This commit is contained in:
2026-02-17 09:13:23 -08:00
parent 035cc680a7
commit 6f98f6bd7f
25 changed files with 1524 additions and 1607 deletions
+86 -1
View File
@@ -1,5 +1,5 @@
// Completion markers for plan2code-loop
const COMPLETION_MARKERS = ['TASK_COMPLETE', 'TASK_BLOCKED', 'LOOP_COMPLETE'] as const;
const COMPLETION_MARKERS = ['TASK_COMPLETE', 'TASK_BLOCKED', 'LOOP_COMPLETE', 'PREREQ_COMPLETE', 'PREREQ_ASSUMED'] as const;
export type CompletionMarker = (typeof COMPLETION_MARKERS)[number];
@@ -43,6 +43,28 @@ export function checkForCompletion(output: string): CompletionCheckResult {
};
}
// Check for PREREQ_COMPLETE with prereq info
// Format: PREREQ_COMPLETE: P1.1 - Verified Phase 1 complete
const prereqMatch = output.match(/PREREQ_COMPLETE[:\[\s]+([^\]:\-\s]+)[\]:\-\s]+(.+?)(?:\n|$)/i);
if (prereqMatch) {
return {
completed: true,
marker: 'PREREQ_COMPLETE',
taskId: prereqMatch[1],
taskName: prereqMatch[2].trim(),
};
}
// Check for PREREQ_ASSUMED with prereq info
// Format: PREREQ_ASSUMED: P2.1 - Design approval (cannot verify)
const assumedMatch = output.match(/PREREQ_ASSUMED[:\[\s]+([^\]:\-\s]+)[\]:\-\s]+(.+?)(?:\n|$)/i);
if (assumedMatch) {
return {
completed: true,
marker: 'PREREQ_ASSUMED',
taskId: assumedMatch[1],
taskName: assumedMatch[2].trim(),
};
}
// Check for TASK_BLOCKED with task info and reason
// Format: TASK_BLOCKED: 1.1 - Reason why blocked
const blockedWithTaskMatch = output.match(/TASK_BLOCKED[:\[\s]+(\d+\.\d+)[\]:\-\s]+(.+?)(?:\n|$)/i);
@@ -72,3 +94,66 @@ export function checkForCompletion(output: string): CompletionCheckResult {
return { completed: false };
}
/**
* Extract ALL completion markers from output (for phase mode).
* Returns an array of all TASK_COMPLETE/TASK_BLOCKED markers found,
* plus whether LOOP_COMPLETE or PHASE_COMPLETE was present.
*/
export function checkForAllCompletions(output: string): {
tasks: CompletionCheckResult[];
loopComplete: boolean;
phaseComplete: boolean;
} {
const tasks: CompletionCheckResult[] = [];
let loopComplete = false;
let phaseComplete = false;
if (output.includes('LOOP_COMPLETE')) {
loopComplete = true;
}
if (output.includes('PHASE_COMPLETE')) {
phaseComplete = true;
}
// Find all TASK_COMPLETE markers with task info
// Format: TASK_COMPLETE: 1.1 - Task description
const completeRegex = /TASK_COMPLETE[:\[\s]+(\d+\.\d+)[\]:\-\s]+(.+?)(?:\n|$)/gi;
let match: RegExpExecArray | null;
while ((match = completeRegex.exec(output)) !== null) {
tasks.push({
completed: true,
marker: 'TASK_COMPLETE',
taskId: match[1],
taskName: match[2].trim(),
});
}
// Find all TASK_BLOCKED markers with task info
const blockedRegex = /TASK_BLOCKED[:\[\s]+(\d+\.\d+)[\]:\-\s]+(.+?)(?:\n|$)/gi;
while ((match = blockedRegex.exec(output)) !== null) {
tasks.push({
completed: true,
marker: 'TASK_BLOCKED',
taskId: match[1],
reason: match[2].trim(),
});
}
// Find PREREQ_COMPLETE markers
const prereqRegex = /PREREQ_COMPLETE[:\[\s]+([^\]:\-\s]+)[\]:\-\s]+(.+?)(?:\n|$)/gi;
while ((match = prereqRegex.exec(output)) !== null) {
tasks.push({
completed: true,
marker: 'PREREQ_COMPLETE',
taskId: match[1],
taskName: match[2].trim(),
});
}
// Find PREREQ_ASSUMED markers
const assumedRegex = /PREREQ_ASSUMED[:\[\s]+([^\]:\-\s]+)[\]:\-\s]+(.+?)(?:\n|$)/gi;
while ((match = assumedRegex.exec(output)) !== null) {
tasks.push({
completed: true,
marker: 'PREREQ_ASSUMED',
taskId: match[1],
taskName: match[2].trim(),
});
}
return { tasks, loopComplete, phaseComplete };
}
+1 -1
View File
@@ -40,7 +40,7 @@ export async function ensureGitRepo(cwd: string): Promise<boolean> {
/**
* Required entries for the .gitignore file
*/
const REQUIRED_GITIGNORE_ENTRIES = ['specs/', 'specs--completed/', 'nul'];
const REQUIRED_GITIGNORE_ENTRIES = ['specs/', 'specs--completed/', 'nul', 'node_modules/'];
/**
* Ensure .gitignore exists with required entries
+1
View File
@@ -13,5 +13,6 @@ export {
createTaskCommit,
isGitRepo,
ensureGitRepo,
ensureGitignore,
type GitCommitOptions
} from './git.js';