v1.14.0 — add Step 3b review workflow, unify file naming, resilient code references

- Add /plan2code-3b-review: 5-step post-implementation review with adaptive
  scope, 11 dimensions, reference-file architecture, and Plan/Apply/Verify fixes
- Unify workflow/skill file naming to single-dash (drop -- and --- conventions)
- Add Devin platform support and CLAUDE.md MANDATORY FIRST STEP template
- Guide agents to use semantic anchors over line numbers in workflow prompts
- Bump version to 1.14.0
This commit is contained in:
2026-05-23 06:58:20 -07:00
parent 8e0b1a2ab2
commit 5e48e98293
42 changed files with 3431 additions and 2542 deletions
+8 -8
View File
@@ -16,14 +16,14 @@ const ANALYZE_PROMPT_PATH = new URL('../src/prompts/analyze.md', import.meta.url
function readPromptFiles(plan2codeRoot: string): Record<string, string> {
const srcDir = path.join(plan2codeRoot, 'src');
const promptFiles = [
'plan2code-1--plan.md',
'plan2code-1b--revise-plan.md',
'plan2code-2--document.md',
'plan2code-3--implement.md',
'plan2code-4--finalize.md',
'plan2code---init.md',
'plan2code---init-update.md',
'plan2code---quick-task.md',
'plan2code-1-plan.md',
'plan2code-1b-revise-plan.md',
'plan2code-2-document.md',
'plan2code-3-implement.md',
'plan2code-4-finalize.md',
'plan2code-init.md',
'plan2code-init-update.md',
'plan2code-quick-task.md',
];
const contents: Record<string, string> = {};
+4 -4
View File
@@ -69,8 +69,8 @@ function detectPlan2CodeRoot(): string | null {
for (let i = 0; i < 5; i++) {
const srcDir = path.join(dir, 'src');
if (
fs.existsSync(path.join(srcDir, 'plan2code-1--plan.md')) &&
fs.existsSync(path.join(srcDir, 'plan2code-2--document.md'))
fs.existsSync(path.join(srcDir, 'plan2code-1-plan.md')) &&
fs.existsSync(path.join(srcDir, 'plan2code-2-document.md'))
) {
return dir;
}
@@ -764,8 +764,8 @@ export async function runCLI(): Promise<void> {
// Warn if the path doesn't look like a plan2code repo
const hasSrcPrompts =
fs.existsSync(path.join(resolvedPlan2CodeRoot, 'src', 'plan2code-1--plan.md')) &&
fs.existsSync(path.join(resolvedPlan2CodeRoot, 'src', 'plan2code-2--document.md'));
fs.existsSync(path.join(resolvedPlan2CodeRoot, 'src', 'plan2code-1-plan.md')) &&
fs.existsSync(path.join(resolvedPlan2CodeRoot, 'src', 'plan2code-2-document.md'));
if (!hasSrcPrompts) {
console.log(chalk.yellow('⚠ No src/plan2code-*.md prompts found at that path. Hashing and analysis may be limited.'));
}
+8 -8
View File
@@ -99,14 +99,14 @@ function generateRunId(): string {
export function collectPromptVersions(plan2codeRoot: string): PromptVersions {
const srcDir = path.join(plan2codeRoot, 'src');
return {
plan: sha256File(path.join(srcDir, 'plan2code-1--plan.md')),
revise_plan: sha256File(path.join(srcDir, 'plan2code-1b--revise-plan.md')),
document: sha256File(path.join(srcDir, 'plan2code-2--document.md')),
implement: sha256File(path.join(srcDir, 'plan2code-3--implement.md')),
finalize: sha256File(path.join(srcDir, 'plan2code-4--finalize.md')),
init: sha256File(path.join(srcDir, 'plan2code---init.md')),
init_update: sha256File(path.join(srcDir, 'plan2code---init-update.md')),
quick_task: sha256File(path.join(srcDir, 'plan2code---quick-task.md')),
plan: sha256File(path.join(srcDir, 'plan2code-1-plan.md')),
revise_plan: sha256File(path.join(srcDir, 'plan2code-1b-revise-plan.md')),
document: sha256File(path.join(srcDir, 'plan2code-2-document.md')),
implement: sha256File(path.join(srcDir, 'plan2code-3-implement.md')),
finalize: sha256File(path.join(srcDir, 'plan2code-4-finalize.md')),
init: sha256File(path.join(srcDir, 'plan2code-init.md')),
init_update: sha256File(path.join(srcDir, 'plan2code-init-update.md')),
quick_task: sha256File(path.join(srcDir, 'plan2code-quick-task.md')),
};
}
+9 -9
View File
@@ -5,18 +5,18 @@ import type { PromptEdit } from './types.js';
// ── Shared fixtures ───────────────────────────────────────────────────────────
const PROMPT_CONTENTS: Record<string, string> = {
'plan2code-1--plan.md': 'This is the plan prompt content. It has some text here.',
'plan2code-2--document.md': 'Document prompt with repeated text. repeated text. Done.',
'plan2code-3--implement.md': 'Implement prompt content.',
'plan2code-1-plan.md': 'This is the plan prompt content. It has some text here.',
'plan2code-2-document.md': 'Document prompt with repeated text. repeated text. Done.',
'plan2code-3-implement.md': 'Implement prompt content.',
};
function makeEdit(overrides: Partial<PromptEdit> = {}): PromptEdit {
return {
file: 'plan2code-1--plan.md',
file: 'plan2code-1-plan.md',
rationale: 'test rationale',
expected_metric_impact: 'test impact',
char_count_before: PROMPT_CONTENTS['plan2code-1--plan.md'].length,
char_count_after: PROMPT_CONTENTS['plan2code-1--plan.md'].length,
char_count_before: PROMPT_CONTENTS['plan2code-1-plan.md'].length,
char_count_after: PROMPT_CONTENTS['plan2code-1-plan.md'].length,
char_count_delta: 0,
old_text: 'some text',
new_text: 'better text',
@@ -59,10 +59,10 @@ describe('validateEdit', () => {
it('warns when old_text appears multiple times', () => {
const edit = makeEdit({
file: 'plan2code-2--document.md',
file: 'plan2code-2-document.md',
old_text: 'repeated text',
char_count_before: PROMPT_CONTENTS['plan2code-2--document.md'].length,
char_count_after: PROMPT_CONTENTS['plan2code-2--document.md'].length,
char_count_before: PROMPT_CONTENTS['plan2code-2-document.md'].length,
char_count_after: PROMPT_CONTENTS['plan2code-2-document.md'].length,
});
const result = validateEdit(edit, PROMPT_CONTENTS);
expect(result.valid).toBe(true);
+8 -8
View File
@@ -32,14 +32,14 @@ function generateProposalId(): string {
function readPromptFiles(plan2codeRoot: string): Record<string, string> {
const srcDir = path.join(plan2codeRoot, 'src');
const promptFiles = [
'plan2code-1--plan.md',
'plan2code-1b--revise-plan.md',
'plan2code-2--document.md',
'plan2code-3--implement.md',
'plan2code-4--finalize.md',
'plan2code---init.md',
'plan2code---init-update.md',
'plan2code---quick-task.md',
'plan2code-1-plan.md',
'plan2code-1b-revise-plan.md',
'plan2code-2-document.md',
'plan2code-3-implement.md',
'plan2code-4-finalize.md',
'plan2code-init.md',
'plan2code-init-update.md',
'plan2code-quick-task.md',
];
const contents: Record<string, string> = {};
+1 -1
View File
@@ -76,7 +76,7 @@ For each step (14), provide:
Numbered list. For each underperforming metric:
1. **Metric:** [metric name] | **Value:** [actual] | **Target:** [target]
- **File:** [plan2code-X--name.md]
- **File:** [plan2code-X-name.md]
- **Section:** [specific heading or section name]
- **Hypothesis:** [specific gap in the prompt that would explain the metric miss]
- **Confidence:** [High/Medium/Low] — [reason for confidence level]
+1 -1
View File
@@ -67,7 +67,7 @@ Produce EXACTLY the following sections. The JSON block is parsed by machine —
```json
[
{
"file": "plan2code-X--name.md",
"file": "plan2code-X-name.md",
"rationale": "One sentence explaining what this edit fixes",
"expected_metric_impact": "avg_metric_name: expected direction and magnitude",
"char_count_before": 0,
+8 -8
View File
@@ -1,14 +1,14 @@
// All TypeScript interfaces for plan2code-metrics
export interface PromptVersions {
plan: string; // sha256:... plan2code-1--plan.md
revise_plan: string; // plan2code-1b--revise-plan.md
document: string; // plan2code-2--document.md
implement: string; // plan2code-3--implement.md
finalize: string; // plan2code-4--finalize.md
init: string; // plan2code---init.md
init_update: string; // plan2code---init-update.md
quick_task: string; // plan2code---quick-task.md
plan: string; // sha256:... plan2code-1-plan.md
revise_plan: string; // plan2code-1b-revise-plan.md
document: string; // plan2code-2-document.md
implement: string; // plan2code-3-implement.md
finalize: string; // plan2code-4-finalize.md
init: string; // plan2code-init.md
init_update: string; // plan2code-init-update.md
quick_task: string; // plan2code-quick-task.md
}
export interface Step1PlanMetrics {