popeye-cli 2.2.0 → 2.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/gemini.d.ts +14 -0
- package/dist/adapters/gemini.d.ts.map +1 -1
- package/dist/adapters/gemini.js +41 -6
- package/dist/adapters/gemini.js.map +1 -1
- package/dist/adapters/grok.d.ts +14 -0
- package/dist/adapters/grok.d.ts.map +1 -1
- package/dist/adapters/grok.js +42 -6
- package/dist/adapters/grok.js.map +1 -1
- package/dist/adapters/openai.d.ts +10 -0
- package/dist/adapters/openai.d.ts.map +1 -1
- package/dist/adapters/openai.js +44 -5
- package/dist/adapters/openai.js.map +1 -1
- package/dist/cli/commands/create.js +1 -1
- package/dist/cli/commands/create.js.map +1 -1
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +324 -20
- package/dist/cli/interactive.js.map +1 -1
- package/dist/generators/all.d.ts.map +1 -1
- package/dist/generators/all.js +3 -2
- package/dist/generators/all.js.map +1 -1
- package/dist/generators/doc-parser.d.ts +21 -6
- package/dist/generators/doc-parser.d.ts.map +1 -1
- package/dist/generators/doc-parser.js +55 -4
- package/dist/generators/doc-parser.js.map +1 -1
- package/dist/generators/templates/fullstack.js +1 -1
- package/dist/generators/templates/website-components.js +1 -1
- package/dist/generators/templates/website-components.js.map +1 -1
- package/dist/generators/templates/website-config.d.ts +4 -1
- package/dist/generators/templates/website-config.d.ts.map +1 -1
- package/dist/generators/templates/website-config.js +17 -11
- package/dist/generators/templates/website-config.js.map +1 -1
- package/dist/generators/templates/website-conversion.js +1 -1
- package/dist/generators/templates/website-conversion.js.map +1 -1
- package/dist/generators/templates/website-landing.js +1 -1
- package/dist/generators/templates/website-landing.js.map +1 -1
- package/dist/generators/templates/website-layout.d.ts +36 -4
- package/dist/generators/templates/website-layout.d.ts.map +1 -1
- package/dist/generators/templates/website-layout.js +466 -23
- package/dist/generators/templates/website-layout.js.map +1 -1
- package/dist/generators/templates/website-pricing.js +1 -1
- package/dist/generators/templates/website-pricing.js.map +1 -1
- package/dist/generators/templates/website-sections.js +1 -1
- package/dist/generators/templates/website-sections.js.map +1 -1
- package/dist/generators/templates/website-seo.d.ts.map +1 -1
- package/dist/generators/templates/website-seo.js +4 -1
- package/dist/generators/templates/website-seo.js.map +1 -1
- package/dist/generators/templates/website.d.ts +1 -1
- package/dist/generators/templates/website.d.ts.map +1 -1
- package/dist/generators/templates/website.js +1 -1
- package/dist/generators/templates/website.js.map +1 -1
- package/dist/generators/website-content-ai.d.ts +52 -0
- package/dist/generators/website-content-ai.d.ts.map +1 -0
- package/dist/generators/website-content-ai.js +141 -0
- package/dist/generators/website-content-ai.js.map +1 -0
- package/dist/generators/website-content-scanner.d.ts +1 -1
- package/dist/generators/website-content-scanner.d.ts.map +1 -1
- package/dist/generators/website-content-scanner.js +98 -1
- package/dist/generators/website-content-scanner.js.map +1 -1
- package/dist/generators/website-context.d.ts +34 -1
- package/dist/generators/website-context.d.ts.map +1 -1
- package/dist/generators/website-context.js +131 -9
- package/dist/generators/website-context.js.map +1 -1
- package/dist/generators/website-debug.d.ts +12 -0
- package/dist/generators/website-debug.d.ts.map +1 -1
- package/dist/generators/website-debug.js +16 -0
- package/dist/generators/website-debug.js.map +1 -1
- package/dist/generators/website.d.ts.map +1 -1
- package/dist/generators/website.js +26 -4
- package/dist/generators/website.js.map +1 -1
- package/dist/pipeline/auto-recovery.d.ts +56 -0
- package/dist/pipeline/auto-recovery.d.ts.map +1 -0
- package/dist/pipeline/auto-recovery.js +185 -0
- package/dist/pipeline/auto-recovery.js.map +1 -0
- package/dist/pipeline/change-request.d.ts +39 -0
- package/dist/pipeline/change-request.d.ts.map +1 -1
- package/dist/pipeline/change-request.js +40 -1
- package/dist/pipeline/change-request.js.map +1 -1
- package/dist/pipeline/check-runner.d.ts +30 -1
- package/dist/pipeline/check-runner.d.ts.map +1 -1
- package/dist/pipeline/check-runner.js +122 -1
- package/dist/pipeline/check-runner.js.map +1 -1
- package/dist/pipeline/command-resolver.d.ts.map +1 -1
- package/dist/pipeline/command-resolver.js +33 -2
- package/dist/pipeline/command-resolver.js.map +1 -1
- package/dist/pipeline/consensus/arbitrator-query.d.ts +22 -0
- package/dist/pipeline/consensus/arbitrator-query.d.ts.map +1 -0
- package/dist/pipeline/consensus/arbitrator-query.js +70 -0
- package/dist/pipeline/consensus/arbitrator-query.js.map +1 -0
- package/dist/pipeline/consensus/consensus-runner.d.ts +131 -7
- package/dist/pipeline/consensus/consensus-runner.d.ts.map +1 -1
- package/dist/pipeline/consensus/consensus-runner.js +809 -35
- package/dist/pipeline/consensus/consensus-runner.js.map +1 -1
- package/dist/pipeline/cr-lifecycle.d.ts +42 -0
- package/dist/pipeline/cr-lifecycle.d.ts.map +1 -0
- package/dist/pipeline/cr-lifecycle.js +89 -0
- package/dist/pipeline/cr-lifecycle.js.map +1 -0
- package/dist/pipeline/gate-engine.d.ts +1 -0
- package/dist/pipeline/gate-engine.d.ts.map +1 -1
- package/dist/pipeline/gate-engine.js +26 -7
- package/dist/pipeline/gate-engine.js.map +1 -1
- package/dist/pipeline/orchestrator.d.ts +1 -1
- package/dist/pipeline/orchestrator.d.ts.map +1 -1
- package/dist/pipeline/orchestrator.js +306 -16
- package/dist/pipeline/orchestrator.js.map +1 -1
- package/dist/pipeline/packets/consensus-packet-builder.d.ts +15 -4
- package/dist/pipeline/packets/consensus-packet-builder.d.ts.map +1 -1
- package/dist/pipeline/packets/consensus-packet-builder.js +29 -17
- package/dist/pipeline/packets/consensus-packet-builder.js.map +1 -1
- package/dist/pipeline/phases/architecture.d.ts.map +1 -1
- package/dist/pipeline/phases/architecture.js +5 -3
- package/dist/pipeline/phases/architecture.js.map +1 -1
- package/dist/pipeline/phases/audit.d.ts.map +1 -1
- package/dist/pipeline/phases/audit.js +5 -3
- package/dist/pipeline/phases/audit.js.map +1 -1
- package/dist/pipeline/phases/consensus-architecture.d.ts.map +1 -1
- package/dist/pipeline/phases/consensus-architecture.js +10 -1
- package/dist/pipeline/phases/consensus-architecture.js.map +1 -1
- package/dist/pipeline/phases/consensus-master-plan.d.ts.map +1 -1
- package/dist/pipeline/phases/consensus-master-plan.js +10 -3
- package/dist/pipeline/phases/consensus-master-plan.js.map +1 -1
- package/dist/pipeline/phases/consensus-role-plans.d.ts.map +1 -1
- package/dist/pipeline/phases/consensus-role-plans.js +10 -1
- package/dist/pipeline/phases/consensus-role-plans.js.map +1 -1
- package/dist/pipeline/phases/done.d.ts.map +1 -1
- package/dist/pipeline/phases/done.js +9 -4
- package/dist/pipeline/phases/done.js.map +1 -1
- package/dist/pipeline/phases/intake.d.ts.map +1 -1
- package/dist/pipeline/phases/intake.js +7 -3
- package/dist/pipeline/phases/intake.js.map +1 -1
- package/dist/pipeline/phases/phase-context.d.ts +2 -0
- package/dist/pipeline/phases/phase-context.d.ts.map +1 -1
- package/dist/pipeline/phases/phase-context.js +3 -1
- package/dist/pipeline/phases/phase-context.js.map +1 -1
- package/dist/pipeline/phases/production-gate.d.ts.map +1 -1
- package/dist/pipeline/phases/production-gate.js +28 -3
- package/dist/pipeline/phases/production-gate.js.map +1 -1
- package/dist/pipeline/phases/qa-validation.d.ts.map +1 -1
- package/dist/pipeline/phases/qa-validation.js +38 -5
- package/dist/pipeline/phases/qa-validation.js.map +1 -1
- package/dist/pipeline/phases/recovery-loop.d.ts +2 -0
- package/dist/pipeline/phases/recovery-loop.d.ts.map +1 -1
- package/dist/pipeline/phases/recovery-loop.js +200 -6
- package/dist/pipeline/phases/recovery-loop.js.map +1 -1
- package/dist/pipeline/phases/review.d.ts.map +1 -1
- package/dist/pipeline/phases/review.js +58 -28
- package/dist/pipeline/phases/review.js.map +1 -1
- package/dist/pipeline/phases/role-planning.d.ts.map +1 -1
- package/dist/pipeline/phases/role-planning.js +18 -2
- package/dist/pipeline/phases/role-planning.js.map +1 -1
- package/dist/pipeline/phases/stuck.d.ts.map +1 -1
- package/dist/pipeline/phases/stuck.js +10 -0
- package/dist/pipeline/phases/stuck.js.map +1 -1
- package/dist/pipeline/repo-snapshot.d.ts.map +1 -1
- package/dist/pipeline/repo-snapshot.js +3 -0
- package/dist/pipeline/repo-snapshot.js.map +1 -1
- package/dist/pipeline/role-execution-adapter.d.ts +2 -1
- package/dist/pipeline/role-execution-adapter.d.ts.map +1 -1
- package/dist/pipeline/role-execution-adapter.js +22 -7
- package/dist/pipeline/role-execution-adapter.js.map +1 -1
- package/dist/pipeline/skill-loader.d.ts +19 -0
- package/dist/pipeline/skill-loader.d.ts.map +1 -1
- package/dist/pipeline/skill-loader.js +22 -0
- package/dist/pipeline/skill-loader.js.map +1 -1
- package/dist/pipeline/skills/coverage-gate.d.ts +44 -0
- package/dist/pipeline/skills/coverage-gate.d.ts.map +1 -0
- package/dist/pipeline/skills/coverage-gate.js +143 -0
- package/dist/pipeline/skills/coverage-gate.js.map +1 -0
- package/dist/pipeline/skills/usage-registry.d.ts +48 -0
- package/dist/pipeline/skills/usage-registry.d.ts.map +1 -0
- package/dist/pipeline/skills/usage-registry.js +55 -0
- package/dist/pipeline/skills/usage-registry.js.map +1 -0
- package/dist/pipeline/strategy-context.d.ts +20 -0
- package/dist/pipeline/strategy-context.d.ts.map +1 -0
- package/dist/pipeline/strategy-context.js +55 -0
- package/dist/pipeline/strategy-context.js.map +1 -0
- package/dist/pipeline/type-defs/artifacts.d.ts +25 -5
- package/dist/pipeline/type-defs/artifacts.d.ts.map +1 -1
- package/dist/pipeline/type-defs/artifacts.js +4 -0
- package/dist/pipeline/type-defs/artifacts.js.map +1 -1
- package/dist/pipeline/type-defs/audit.d.ts +25 -13
- package/dist/pipeline/type-defs/audit.d.ts.map +1 -1
- package/dist/pipeline/type-defs/checks.d.ts +18 -8
- package/dist/pipeline/type-defs/checks.d.ts.map +1 -1
- package/dist/pipeline/type-defs/checks.js +4 -0
- package/dist/pipeline/type-defs/checks.js.map +1 -1
- package/dist/pipeline/type-defs/packets.d.ts +104 -18
- package/dist/pipeline/type-defs/packets.d.ts.map +1 -1
- package/dist/pipeline/type-defs/packets.js +17 -1
- package/dist/pipeline/type-defs/packets.js.map +1 -1
- package/dist/pipeline/type-defs/state.d.ts +160 -16
- package/dist/pipeline/type-defs/state.d.ts.map +1 -1
- package/dist/pipeline/type-defs/state.js +26 -1
- package/dist/pipeline/type-defs/state.js.map +1 -1
- package/dist/shared/text-utils.d.ts +23 -0
- package/dist/shared/text-utils.d.ts.map +1 -0
- package/dist/shared/text-utils.js +66 -0
- package/dist/shared/text-utils.js.map +1 -0
- package/dist/shared/website-strategy-format.d.ts +18 -0
- package/dist/shared/website-strategy-format.d.ts.map +1 -0
- package/dist/shared/website-strategy-format.js +47 -0
- package/dist/shared/website-strategy-format.js.map +1 -0
- package/dist/state/index.d.ts +2 -0
- package/dist/state/index.d.ts.map +1 -1
- package/dist/state/index.js +57 -8
- package/dist/state/index.js.map +1 -1
- package/dist/types/consensus.d.ts +1 -0
- package/dist/types/consensus.d.ts.map +1 -1
- package/dist/types/consensus.js.map +1 -1
- package/dist/types/website-strategy.d.ts +1 -1
- package/dist/types/workflow.d.ts +447 -0
- package/dist/types/workflow.d.ts.map +1 -1
- package/dist/types/workflow.js +3 -0
- package/dist/types/workflow.js.map +1 -1
- package/dist/upgrade/handlers.d.ts.map +1 -1
- package/dist/upgrade/handlers.js +6 -3
- package/dist/upgrade/handlers.js.map +1 -1
- package/dist/workflow/consensus.d.ts.map +1 -1
- package/dist/workflow/consensus.js +1 -0
- package/dist/workflow/consensus.js.map +1 -1
- package/dist/workflow/website-strategy.d.ts.map +1 -1
- package/dist/workflow/website-strategy.js +2 -29
- package/dist/workflow/website-strategy.js.map +1 -1
- package/dist/workflow/website-updater.d.ts.map +1 -1
- package/dist/workflow/website-updater.js +3 -2
- package/dist/workflow/website-updater.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/gemini.ts +51 -6
- package/src/adapters/grok.ts +51 -6
- package/src/adapters/openai.ts +53 -5
- package/src/cli/commands/create.ts +1 -1
- package/src/cli/interactive.ts +333 -19
- package/src/generators/all.ts +3 -2
- package/src/generators/doc-parser.ts +75 -15
- package/src/generators/templates/fullstack.ts +1 -1
- package/src/generators/templates/website-components.ts +1 -1
- package/src/generators/templates/website-config.ts +23 -11
- package/src/generators/templates/website-conversion.ts +1 -1
- package/src/generators/templates/website-landing.ts +1 -1
- package/src/generators/templates/website-layout.ts +491 -23
- package/src/generators/templates/website-pricing.ts +1 -1
- package/src/generators/templates/website-sections.ts +1 -1
- package/src/generators/templates/website-seo.ts +4 -1
- package/src/generators/templates/website.ts +3 -0
- package/src/generators/website-content-ai.ts +186 -0
- package/src/generators/website-content-scanner.ts +113 -1
- package/src/generators/website-context.ts +151 -12
- package/src/generators/website-debug.ts +26 -0
- package/src/generators/website.ts +28 -3
- package/src/pipeline/auto-recovery.ts +283 -0
- package/src/pipeline/change-request.ts +63 -1
- package/src/pipeline/check-runner.ts +141 -2
- package/src/pipeline/command-resolver.ts +34 -2
- package/src/pipeline/consensus/arbitrator-query.ts +101 -0
- package/src/pipeline/consensus/consensus-runner.ts +1099 -42
- package/src/pipeline/cr-lifecycle.ts +103 -0
- package/src/pipeline/gate-engine.ts +35 -7
- package/src/pipeline/orchestrator.ts +361 -16
- package/src/pipeline/packets/consensus-packet-builder.ts +44 -18
- package/src/pipeline/phases/architecture.ts +6 -3
- package/src/pipeline/phases/audit.ts +6 -3
- package/src/pipeline/phases/consensus-architecture.ts +10 -1
- package/src/pipeline/phases/consensus-master-plan.ts +10 -3
- package/src/pipeline/phases/consensus-role-plans.ts +10 -1
- package/src/pipeline/phases/done.ts +15 -4
- package/src/pipeline/phases/intake.ts +7 -3
- package/src/pipeline/phases/phase-context.ts +6 -1
- package/src/pipeline/phases/production-gate.ts +41 -3
- package/src/pipeline/phases/qa-validation.ts +51 -5
- package/src/pipeline/phases/recovery-loop.ts +229 -7
- package/src/pipeline/phases/review.ts +73 -30
- package/src/pipeline/phases/role-planning.ts +21 -2
- package/src/pipeline/phases/stuck.ts +10 -0
- package/src/pipeline/repo-snapshot.ts +3 -0
- package/src/pipeline/role-execution-adapter.ts +30 -4
- package/src/pipeline/skill-loader.ts +33 -0
- package/src/pipeline/skills/coverage-gate.ts +199 -0
- package/src/pipeline/skills/usage-registry.ts +87 -0
- package/src/pipeline/strategy-context.ts +60 -0
- package/src/pipeline/type-defs/artifacts.ts +4 -0
- package/src/pipeline/type-defs/checks.ts +4 -0
- package/src/pipeline/type-defs/packets.ts +18 -1
- package/src/pipeline/type-defs/state.ts +26 -1
- package/src/shared/text-utils.ts +70 -0
- package/src/shared/website-strategy-format.ts +56 -0
- package/src/state/index.ts +60 -8
- package/src/types/consensus.ts +1 -0
- package/src/types/workflow.ts +6 -0
- package/src/upgrade/handlers.ts +9 -3
- package/src/workflow/consensus.ts +1 -0
- package/src/workflow/website-strategy.ts +2 -36
- package/src/workflow/website-updater.ts +4 -2
- package/tests/adapters/gemini.test.ts +165 -0
- package/tests/adapters/grok.test.ts +137 -0
- package/tests/adapters/openai.test.ts +128 -0
- package/tests/generators/doc-parser.test.ts +88 -9
- package/tests/generators/quality-gate.test.ts +19 -3
- package/tests/generators/website-components.test.ts +34 -0
- package/tests/generators/website-content-ai.test.ts +308 -0
- package/tests/generators/website-content-scanner.test.ts +86 -0
- package/tests/generators/website-context.test.ts +3 -2
- package/tests/integration/smokestack-scaffold.test.ts +385 -0
- package/tests/pipeline/auto-recovery.test.ts +337 -0
- package/tests/pipeline/change-request.test.ts +70 -0
- package/tests/pipeline/command-resolver.test.ts +42 -0
- package/tests/pipeline/consensus/arbitrator-query.test.ts +107 -0
- package/tests/pipeline/consensus-runner.test.ts +1333 -10
- package/tests/pipeline/consensus-scoring.test.ts +602 -18
- package/tests/pipeline/gate-engine.test.ts +34 -0
- package/tests/pipeline/install-check.test.ts +261 -0
- package/tests/pipeline/orchestrator.test.ts +1506 -15
- package/tests/pipeline/packets/builders.test.ts +29 -6
- package/tests/pipeline/phases/role-planning.strategy.test.ts +204 -0
- package/tests/pipeline/pipeline-persistence.test.ts +230 -0
- package/tests/pipeline/recovery-loop-guidance.test.ts +280 -0
- package/tests/pipeline/role-execution-adapter.test.ts +88 -0
- package/tests/pipeline/skills/coverage-gate.test.ts +370 -0
- package/tests/pipeline/skills/usage-registry.test.ts +114 -0
- package/tests/pipeline/strategy-context.test.ts +148 -0
- package/tests/shared/text-utils.test.ts +155 -0
- package/tests/state/progress-analysis.test.ts +375 -0
- package/tests/upgrade/handlers.test.ts +33 -2
- package/tests/workflow/consensus.test.ts +6 -0
- package/tsconfig.json +1 -1
package/src/state/index.ts
CHANGED
|
@@ -578,6 +578,10 @@ export interface ProjectProgressAnalysis {
|
|
|
578
578
|
statusMismatch: boolean; // true if status='complete' but work is incomplete
|
|
579
579
|
planMismatch: boolean; // true if plan file has more tasks than state
|
|
580
580
|
|
|
581
|
+
// Pipeline state (when applicable)
|
|
582
|
+
pipelinePhase?: string; // Current pipeline phase (e.g. 'DONE', 'STUCK', 'IMPLEMENTATION')
|
|
583
|
+
pipelineTerminal: boolean; // true if pipeline is in DONE or STUCK state
|
|
584
|
+
|
|
581
585
|
// Milestone breakdown (from state)
|
|
582
586
|
totalMilestones: number;
|
|
583
587
|
completedMilestones: number;
|
|
@@ -780,14 +784,42 @@ export async function analyzeProjectProgress(projectDir: string): Promise<Projec
|
|
|
780
784
|
: 0;
|
|
781
785
|
|
|
782
786
|
// Determine if actually complete - must match plan if plan has more tasks
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
+
// v2.4.6: When no milestones/tasks exist in state but project was explicitly
|
|
788
|
+
// marked complete (status='complete' + phase='complete'), trust the status.
|
|
789
|
+
// completeProject() only sets both to 'complete' after build verification passes.
|
|
790
|
+
const noTrackingData = totalMilestones === 0 && totalTasks === 0;
|
|
791
|
+
const explicitlyCompleted = state.status === 'complete' && state.phase === 'complete';
|
|
792
|
+
|
|
793
|
+
// Pipeline state detection — pipeline truth overrides milestone truth.
|
|
794
|
+
// RECOVERY_LOOP is treated as stuck-like: the pipeline was interrupted mid-recovery
|
|
795
|
+
// and will just re-fail without new guidance.
|
|
796
|
+
const pipelinePhase = state.pipeline?.pipelinePhase;
|
|
797
|
+
const pipelineStuckLike = pipelinePhase === 'STUCK' || pipelinePhase === 'RECOVERY_LOOP';
|
|
798
|
+
const pipelineTerminal = pipelinePhase === 'DONE' || pipelineStuckLike;
|
|
799
|
+
const pipelineDone = pipelinePhase === 'DONE';
|
|
800
|
+
|
|
801
|
+
let isActuallyComplete: boolean;
|
|
802
|
+
if (noTrackingData && pipelinePhase) {
|
|
803
|
+
// Pipeline project: pipeline state is the source of truth.
|
|
804
|
+
// DONE = complete, STUCK = not complete.
|
|
805
|
+
// planMismatch is irrelevant — pipeline projects don't track milestones.
|
|
806
|
+
isActuallyComplete = pipelineDone;
|
|
807
|
+
} else if (noTrackingData) {
|
|
808
|
+
// Legacy project with no tracking: trust explicit completion only
|
|
809
|
+
isActuallyComplete = explicitlyCompleted && !planMismatch;
|
|
810
|
+
} else {
|
|
811
|
+
// Standard milestone-based: all milestones + tasks must be complete
|
|
812
|
+
isActuallyComplete = totalMilestones > 0 &&
|
|
813
|
+
completedMilestones === totalMilestones &&
|
|
814
|
+
completedTasks === totalTasks &&
|
|
815
|
+
!planMismatch; // Can't be complete if plan has more tasks
|
|
816
|
+
}
|
|
787
817
|
|
|
788
|
-
// Check for status mismatch
|
|
818
|
+
// Check for status mismatch.
|
|
819
|
+
// Pipeline terminal states are handled separately — not "mismatches".
|
|
789
820
|
const statusMismatch = (state.status === 'complete' || state.phase === 'complete') &&
|
|
790
|
-
(!isActuallyComplete || planMismatch)
|
|
821
|
+
(!isActuallyComplete || planMismatch) &&
|
|
822
|
+
!pipelineTerminal;
|
|
791
823
|
|
|
792
824
|
// Find next items to work on
|
|
793
825
|
let nextMilestone: { id: string; name: string } | undefined;
|
|
@@ -836,6 +868,15 @@ export async function analyzeProjectProgress(projectDir: string): Promise<Projec
|
|
|
836
868
|
if (planMismatch) {
|
|
837
869
|
progressSummary = `PLAN MISMATCH: State has ${completedTasks}/${totalTasks} tasks but plan has ${planTaskCount} tasks. ` +
|
|
838
870
|
`Only ${percentComplete}% of plan completed.`;
|
|
871
|
+
} else if (isActuallyComplete && pipelineDone && noTrackingData) {
|
|
872
|
+
progressSummary = 'Project completed via pipeline';
|
|
873
|
+
} else if (isActuallyComplete && noTrackingData) {
|
|
874
|
+
progressSummary = 'Project completed (no milestone tracking data)';
|
|
875
|
+
} else if (pipelineStuckLike) {
|
|
876
|
+
const failedAt = state.pipeline?.failedPhase ?? 'unknown';
|
|
877
|
+
const recoveryCount = state.pipeline?.recoveryCount ?? 0;
|
|
878
|
+
const label = pipelinePhase === 'RECOVERY_LOOP' ? 'PIPELINE STUCK (in recovery)' : 'PIPELINE STUCK';
|
|
879
|
+
progressSummary = `${label}: Failed at ${failedAt} after ${recoveryCount} recovery attempts`;
|
|
839
880
|
} else if (isActuallyComplete) {
|
|
840
881
|
progressSummary = `All ${totalTasks} tasks complete across ${totalMilestones} milestones`;
|
|
841
882
|
} else if (statusMismatch) {
|
|
@@ -848,6 +889,8 @@ export async function analyzeProjectProgress(projectDir: string): Promise<Projec
|
|
|
848
889
|
isActuallyComplete,
|
|
849
890
|
statusMismatch,
|
|
850
891
|
planMismatch,
|
|
892
|
+
pipelinePhase,
|
|
893
|
+
pipelineTerminal,
|
|
851
894
|
totalMilestones,
|
|
852
895
|
completedMilestones,
|
|
853
896
|
inProgressMilestones,
|
|
@@ -927,6 +970,15 @@ export async function verifyProjectCompletion(projectDir: string): Promise<{
|
|
|
927
970
|
* @returns Updated state
|
|
928
971
|
*/
|
|
929
972
|
export async function resetIncompleteProject(projectDir: string): Promise<ProjectState> {
|
|
973
|
+
const current = await loadProject(projectDir);
|
|
974
|
+
|
|
975
|
+
// Pipeline projects should not be reset via legacy path —
|
|
976
|
+
// legacy reset changes phase/status but not pipeline.pipelinePhase,
|
|
977
|
+
// creating inconsistent state. Pipeline resume handles its own recovery.
|
|
978
|
+
if (current.pipeline?.pipelinePhase) {
|
|
979
|
+
return current;
|
|
980
|
+
}
|
|
981
|
+
|
|
930
982
|
const verification = await verifyProjectCompletion(projectDir);
|
|
931
983
|
|
|
932
984
|
if (verification.isComplete) {
|
|
@@ -955,8 +1007,8 @@ export async function resetIncompleteProject(projectDir: string): Promise<Projec
|
|
|
955
1007
|
}
|
|
956
1008
|
|
|
957
1009
|
// Reset any failed tasks to pending for retry
|
|
958
|
-
const
|
|
959
|
-
const updatedMilestones =
|
|
1010
|
+
const latestState = await loadProject(projectDir);
|
|
1011
|
+
const updatedMilestones = latestState.milestones.map(m => ({
|
|
960
1012
|
...m,
|
|
961
1013
|
// Reset milestone status if it was incorrectly marked complete
|
|
962
1014
|
status: m.tasks.every(t => t.status === 'complete')
|
package/src/types/consensus.ts
CHANGED
package/src/types/workflow.ts
CHANGED
|
@@ -11,6 +11,8 @@ import type { TestPlanOutput } from './tester.js';
|
|
|
11
11
|
import { TestPlanOutputSchema, TestVerdictSchema } from './tester.js';
|
|
12
12
|
import type { DbConfig } from './database.js';
|
|
13
13
|
import { DbConfigSchema } from './database.js';
|
|
14
|
+
import { PipelineStateSchema } from '../pipeline/types.js';
|
|
15
|
+
import type { PipelineState } from '../pipeline/types.js';
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Workflow phases
|
|
@@ -244,6 +246,8 @@ export interface ProjectState {
|
|
|
244
246
|
auditLastRunAt?: string;
|
|
245
247
|
/** Unique identifier for the audit run */
|
|
246
248
|
auditRunId?: string;
|
|
249
|
+
/** Pipeline execution state — persisted for resume across sessions (v2.4.5) */
|
|
250
|
+
pipeline?: PipelineState;
|
|
247
251
|
}
|
|
248
252
|
|
|
249
253
|
/**
|
|
@@ -271,6 +275,7 @@ export const ProjectStateSchema = z.object({
|
|
|
271
275
|
analysis: z.string(),
|
|
272
276
|
strengths: z.array(z.string()),
|
|
273
277
|
concerns: z.array(z.string()),
|
|
278
|
+
blockingIssues: z.array(z.string()).default([]),
|
|
274
279
|
recommendations: z.array(z.string()),
|
|
275
280
|
approved: z.boolean(),
|
|
276
281
|
rawResponse: z.string(),
|
|
@@ -296,6 +301,7 @@ export const ProjectStateSchema = z.object({
|
|
|
296
301
|
auditRecoveryInProgress: z.boolean().optional(),
|
|
297
302
|
auditLastRunAt: z.string().optional(),
|
|
298
303
|
auditRunId: z.string().optional(),
|
|
304
|
+
pipeline: PipelineStateSchema.optional(),
|
|
299
305
|
});
|
|
300
306
|
|
|
301
307
|
/**
|
package/src/upgrade/handlers.ts
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
generateRootDockerCompose,
|
|
22
22
|
} from '../generators/templates/fullstack.js';
|
|
23
23
|
import { loadState, saveState } from '../state/persistence.js';
|
|
24
|
-
import { buildWebsiteContext, resolveBrandAssets, validateWebsiteContext } from '../generators/website-context.js';
|
|
24
|
+
import { buildWebsiteContext, resolveBrandAssets, validateWebsiteContext, extractDocPathsFromText } from '../generators/website-context.js';
|
|
25
25
|
import type { WebsiteContentContext } from '../generators/website-context.js';
|
|
26
26
|
import { resolveWorkspaceRoot } from '../generators/workspace-root.js';
|
|
27
27
|
import { loadWebsiteStrategy } from '../workflow/website-strategy.js';
|
|
@@ -61,11 +61,17 @@ export async function buildUpgradeContentContext(
|
|
|
61
61
|
projectName: string,
|
|
62
62
|
): Promise<{ context?: WebsiteContentContext; warning?: string }> {
|
|
63
63
|
try {
|
|
64
|
+
// Load state once for idea text + brand context
|
|
65
|
+
const state = await loadState(projectDir);
|
|
66
|
+
|
|
64
67
|
// Build context from user docs (scans projectDir + parent via getScanDirectories)
|
|
65
|
-
|
|
68
|
+
// Extract extra doc paths from state idea text if available
|
|
69
|
+
const extraDocPaths = state?.idea ? extractDocPathsFromText(state.idea) : [];
|
|
70
|
+
const context = await buildWebsiteContext(
|
|
71
|
+
projectDir, projectName, state?.specification ?? state?.idea, extraDocPaths,
|
|
72
|
+
);
|
|
66
73
|
|
|
67
74
|
// Apply brand context from state if available
|
|
68
|
-
const state = await loadState(projectDir);
|
|
69
75
|
if (state?.brandContext?.primaryColor) {
|
|
70
76
|
context.brand = { ...context.brand, primaryColor: state.brandContext.primaryColor };
|
|
71
77
|
}
|
|
@@ -1176,6 +1176,7 @@ export async function runOptimizedConsensusProcess(
|
|
|
1176
1176
|
score: combinedScore,
|
|
1177
1177
|
analysis: combinedAnalysis,
|
|
1178
1178
|
concerns: allConcerns,
|
|
1179
|
+
blockingIssues: [],
|
|
1179
1180
|
recommendations: allRecommendations,
|
|
1180
1181
|
approved: combinedScore >= threshold,
|
|
1181
1182
|
strengths: [],
|
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
BrandAssetsContract,
|
|
14
14
|
} from '../types/website-strategy.js';
|
|
15
15
|
import { WebsiteStrategySchema } from '../types/website-strategy.js';
|
|
16
|
+
import { formatWebsiteStrategy } from '../shared/website-strategy-format.js';
|
|
16
17
|
import { createClient } from '../adapters/openai.js';
|
|
17
18
|
|
|
18
19
|
/** File name for persisted strategy */
|
|
@@ -187,42 +188,7 @@ Respond with ONLY valid JSON, no markdown code fences or explanation.`;
|
|
|
187
188
|
export function formatStrategyForPlanContext(
|
|
188
189
|
strategy: WebsiteStrategyDocument
|
|
189
190
|
): string {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
lines.push(`### Target Customer`);
|
|
193
|
-
lines.push(`- Persona: ${strategy.icp.primaryPersona}`);
|
|
194
|
-
lines.push(`- Pain points: ${strategy.icp.painPoints.join(', ')}`);
|
|
195
|
-
lines.push('');
|
|
196
|
-
|
|
197
|
-
lines.push(`### Positioning`);
|
|
198
|
-
lines.push(`- Category: ${strategy.positioning.category}`);
|
|
199
|
-
lines.push(`- Value proposition: ${strategy.positioning.valueProposition}`);
|
|
200
|
-
lines.push(`- Differentiators: ${strategy.positioning.differentiators.join(', ')}`);
|
|
201
|
-
lines.push('');
|
|
202
|
-
|
|
203
|
-
lines.push(`### Messaging`);
|
|
204
|
-
lines.push(`- Headline: ${strategy.messaging.headline}`);
|
|
205
|
-
lines.push(`- Subheadline: ${strategy.messaging.subheadline}`);
|
|
206
|
-
lines.push('');
|
|
207
|
-
|
|
208
|
-
lines.push(`### SEO Keywords`);
|
|
209
|
-
lines.push(`- Primary: ${strategy.seoStrategy.primaryKeywords.join(', ')}`);
|
|
210
|
-
lines.push(`- Secondary: ${strategy.seoStrategy.secondaryKeywords.join(', ')}`);
|
|
211
|
-
lines.push('');
|
|
212
|
-
|
|
213
|
-
lines.push(`### Site Architecture`);
|
|
214
|
-
for (const page of strategy.siteArchitecture.pages) {
|
|
215
|
-
lines.push(`- ${page.path} (${page.pageType}): ${page.purpose}`);
|
|
216
|
-
}
|
|
217
|
-
lines.push('');
|
|
218
|
-
|
|
219
|
-
lines.push(`### Conversion Strategy`);
|
|
220
|
-
lines.push(`- Primary CTA: "${strategy.conversionStrategy.primaryCta.text}" -> ${strategy.conversionStrategy.primaryCta.href}`);
|
|
221
|
-
lines.push(`- Secondary CTA: "${strategy.conversionStrategy.secondaryCta.text}" -> ${strategy.conversionStrategy.secondaryCta.href}`);
|
|
222
|
-
lines.push(`- Trust signals: ${strategy.conversionStrategy.trustSignals.join(', ')}`);
|
|
223
|
-
lines.push(`- Lead capture: ${strategy.conversionStrategy.leadCapture}`);
|
|
224
|
-
|
|
225
|
-
return lines.join('\n');
|
|
191
|
+
return formatWebsiteStrategy(strategy);
|
|
226
192
|
}
|
|
227
193
|
|
|
228
194
|
/**
|
|
@@ -9,7 +9,7 @@ import path from 'node:path';
|
|
|
9
9
|
import type { ProjectState } from '../types/workflow.js';
|
|
10
10
|
import type { OutputLanguage } from '../types/project.js';
|
|
11
11
|
import { isWorkspace } from '../types/project.js';
|
|
12
|
-
import { buildWebsiteContext, resolveBrandAssets, validateWebsiteContext } from '../generators/website-context.js';
|
|
12
|
+
import { buildWebsiteContext, resolveBrandAssets, validateWebsiteContext, extractDocPathsFromText } from '../generators/website-context.js';
|
|
13
13
|
import { resolveWorkspaceRoot } from '../generators/workspace-root.js';
|
|
14
14
|
import { generateWebsiteLandingPage } from '../generators/templates/website-landing.js';
|
|
15
15
|
import { generateWebsitePricingPage } from '../generators/templates/website-pricing.js';
|
|
@@ -52,10 +52,12 @@ export async function updateWebsiteContent(
|
|
|
52
52
|
|
|
53
53
|
// Build content context from user docs and specification
|
|
54
54
|
const parentDir = path.dirname(projectDir);
|
|
55
|
+
const extraDocPaths = state.idea ? extractDocPathsFromText(state.idea) : [];
|
|
55
56
|
const context = await buildWebsiteContext(
|
|
56
57
|
parentDir,
|
|
57
58
|
state.name,
|
|
58
|
-
state.specification
|
|
59
|
+
state.specification,
|
|
60
|
+
extraDocPaths,
|
|
59
61
|
);
|
|
60
62
|
|
|
61
63
|
// Apply brand context from state if available
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Gemini adapter - parseConsensusResponse
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
import { parseConsensusResponse } from '../../src/adapters/gemini.js';
|
|
7
|
+
|
|
8
|
+
describe('Gemini parseConsensusResponse', () => {
|
|
9
|
+
it('should parse a complete response with blocking issues', () => {
|
|
10
|
+
const response = `
|
|
11
|
+
ANALYSIS:
|
|
12
|
+
Well-structured plan with clear goals.
|
|
13
|
+
|
|
14
|
+
STRENGTHS:
|
|
15
|
+
- Good module separation
|
|
16
|
+
- Clear API design
|
|
17
|
+
|
|
18
|
+
CONCERNS:
|
|
19
|
+
- Consider adding rate limiting
|
|
20
|
+
|
|
21
|
+
BLOCKING_ISSUES:
|
|
22
|
+
- Missing authentication middleware
|
|
23
|
+
- No input validation strategy
|
|
24
|
+
|
|
25
|
+
RECOMMENDATIONS:
|
|
26
|
+
- Add rate limiting middleware
|
|
27
|
+
|
|
28
|
+
CONSENSUS: 72%
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
const result = parseConsensusResponse(response);
|
|
32
|
+
|
|
33
|
+
expect(result.score).toBe(72);
|
|
34
|
+
expect(result.approved).toBe(false);
|
|
35
|
+
expect(result.concerns).toEqual(['Consider adding rate limiting']);
|
|
36
|
+
expect(result.blockingIssues).toEqual([
|
|
37
|
+
'Missing authentication middleware',
|
|
38
|
+
'No input validation strategy',
|
|
39
|
+
]);
|
|
40
|
+
expect(result.recommendations).toEqual(['Add rate limiting middleware']);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should return empty blocking issues when "None"', () => {
|
|
44
|
+
const response = `
|
|
45
|
+
ANALYSIS:
|
|
46
|
+
Excellent plan.
|
|
47
|
+
|
|
48
|
+
STRENGTHS:
|
|
49
|
+
- Comprehensive coverage
|
|
50
|
+
|
|
51
|
+
CONCERNS:
|
|
52
|
+
- Minor naming inconsistencies
|
|
53
|
+
|
|
54
|
+
BLOCKING_ISSUES:
|
|
55
|
+
- None
|
|
56
|
+
|
|
57
|
+
RECOMMENDATIONS:
|
|
58
|
+
- Standardize naming conventions
|
|
59
|
+
|
|
60
|
+
CONSENSUS: 96%
|
|
61
|
+
`;
|
|
62
|
+
|
|
63
|
+
const result = parseConsensusResponse(response);
|
|
64
|
+
|
|
65
|
+
expect(result.score).toBe(96);
|
|
66
|
+
expect(result.approved).toBe(true);
|
|
67
|
+
expect(result.blockingIssues).toEqual([]);
|
|
68
|
+
expect(result.concerns).toHaveLength(1);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should handle missing BLOCKING_ISSUES section (backward compat)', () => {
|
|
72
|
+
const response = `
|
|
73
|
+
ANALYSIS:
|
|
74
|
+
Good plan overall.
|
|
75
|
+
|
|
76
|
+
STRENGTHS:
|
|
77
|
+
- Solid architecture design
|
|
78
|
+
|
|
79
|
+
CONCERNS:
|
|
80
|
+
- Some performance issue to watch
|
|
81
|
+
|
|
82
|
+
RECOMMENDATIONS:
|
|
83
|
+
- Optimize database queries
|
|
84
|
+
|
|
85
|
+
CONSENSUS: 88%
|
|
86
|
+
`;
|
|
87
|
+
|
|
88
|
+
const result = parseConsensusResponse(response);
|
|
89
|
+
|
|
90
|
+
expect(result.blockingIssues).toEqual([]);
|
|
91
|
+
expect(result.score).toBe(88);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should filter none-variant blocking issues like "No blocking issues found"', () => {
|
|
95
|
+
const response = `
|
|
96
|
+
ANALYSIS:
|
|
97
|
+
Good plan with solid foundation.
|
|
98
|
+
|
|
99
|
+
STRENGTHS:
|
|
100
|
+
- Clean design
|
|
101
|
+
|
|
102
|
+
CONCERNS:
|
|
103
|
+
- Minor performance concern
|
|
104
|
+
|
|
105
|
+
BLOCKING_ISSUES:
|
|
106
|
+
- No blocking issues found
|
|
107
|
+
|
|
108
|
+
RECOMMENDATIONS:
|
|
109
|
+
- Optimize queries
|
|
110
|
+
|
|
111
|
+
CONSENSUS: 91%
|
|
112
|
+
`;
|
|
113
|
+
const result = parseConsensusResponse(response);
|
|
114
|
+
expect(result.blockingIssues).toEqual([]);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should filter "None identified" from blocking issues', () => {
|
|
118
|
+
const response = `
|
|
119
|
+
ANALYSIS:
|
|
120
|
+
Thorough review complete.
|
|
121
|
+
|
|
122
|
+
STRENGTHS:
|
|
123
|
+
- Well-structured code
|
|
124
|
+
|
|
125
|
+
CONCERNS:
|
|
126
|
+
- Could use more tests
|
|
127
|
+
|
|
128
|
+
BLOCKING_ISSUES:
|
|
129
|
+
- None identified
|
|
130
|
+
|
|
131
|
+
RECOMMENDATIONS:
|
|
132
|
+
- Add integration tests
|
|
133
|
+
|
|
134
|
+
CONSENSUS: 89%
|
|
135
|
+
`;
|
|
136
|
+
const result = parseConsensusResponse(response);
|
|
137
|
+
expect(result.blockingIssues).toEqual([]);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should handle ALL-CAPS format for blocking issues', () => {
|
|
141
|
+
const response = `
|
|
142
|
+
ANALYSIS:
|
|
143
|
+
Detailed review of the plan.
|
|
144
|
+
|
|
145
|
+
STRENGTHS:
|
|
146
|
+
- Good structure
|
|
147
|
+
|
|
148
|
+
CONCERNS:
|
|
149
|
+
- Minor issue noted
|
|
150
|
+
|
|
151
|
+
BLOCKING_ISSUES:
|
|
152
|
+
- Critical security flaw
|
|
153
|
+
|
|
154
|
+
RECOMMENDATIONS:
|
|
155
|
+
- Fix security
|
|
156
|
+
|
|
157
|
+
CONSENSUS: 60%
|
|
158
|
+
`;
|
|
159
|
+
|
|
160
|
+
const result = parseConsensusResponse(response);
|
|
161
|
+
|
|
162
|
+
expect(result.blockingIssues).toEqual(['Critical security flaw']);
|
|
163
|
+
expect(result.recommendations).toEqual(['Fix security']);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Grok adapter - parseConsensusResponse
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, it, expect } from 'vitest';
|
|
6
|
+
import { parseConsensusResponse } from '../../src/adapters/grok.js';
|
|
7
|
+
|
|
8
|
+
describe('Grok parseConsensusResponse', () => {
|
|
9
|
+
it('should parse a complete response with blocking issues', () => {
|
|
10
|
+
const response = `
|
|
11
|
+
ANALYSIS:
|
|
12
|
+
Solid plan with room for improvement.
|
|
13
|
+
|
|
14
|
+
STRENGTHS:
|
|
15
|
+
- Clean API design
|
|
16
|
+
- Good test coverage plan
|
|
17
|
+
|
|
18
|
+
CONCERNS:
|
|
19
|
+
- Consider adding monitoring
|
|
20
|
+
|
|
21
|
+
BLOCKING_ISSUES:
|
|
22
|
+
- Missing database migration strategy
|
|
23
|
+
- No rollback plan defined
|
|
24
|
+
|
|
25
|
+
RECOMMENDATIONS:
|
|
26
|
+
- Add observability layer
|
|
27
|
+
|
|
28
|
+
CONSENSUS: 70%
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
const result = parseConsensusResponse(response);
|
|
32
|
+
|
|
33
|
+
expect(result.score).toBe(70);
|
|
34
|
+
expect(result.approved).toBe(false);
|
|
35
|
+
expect(result.concerns).toEqual(['Consider adding monitoring']);
|
|
36
|
+
expect(result.blockingIssues).toEqual([
|
|
37
|
+
'Missing database migration strategy',
|
|
38
|
+
'No rollback plan defined',
|
|
39
|
+
]);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should return empty blocking issues when "None"', () => {
|
|
43
|
+
const response = `
|
|
44
|
+
ANALYSIS:
|
|
45
|
+
Great plan.
|
|
46
|
+
|
|
47
|
+
STRENGTHS:
|
|
48
|
+
- Well-structured
|
|
49
|
+
|
|
50
|
+
CONCERNS:
|
|
51
|
+
- Minor style inconsistencies
|
|
52
|
+
|
|
53
|
+
BLOCKING_ISSUES:
|
|
54
|
+
- None
|
|
55
|
+
|
|
56
|
+
RECOMMENDATIONS:
|
|
57
|
+
- Apply consistent formatting
|
|
58
|
+
|
|
59
|
+
CONSENSUS: 95%
|
|
60
|
+
`;
|
|
61
|
+
|
|
62
|
+
const result = parseConsensusResponse(response);
|
|
63
|
+
|
|
64
|
+
expect(result.score).toBe(95);
|
|
65
|
+
expect(result.approved).toBe(true);
|
|
66
|
+
expect(result.blockingIssues).toEqual([]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('should filter none-variant blocking issues like "No blocking issues found"', () => {
|
|
70
|
+
const response = `
|
|
71
|
+
ANALYSIS:
|
|
72
|
+
Solid implementation plan.
|
|
73
|
+
|
|
74
|
+
STRENGTHS:
|
|
75
|
+
- Good architecture
|
|
76
|
+
|
|
77
|
+
CONCERNS:
|
|
78
|
+
- Consider monitoring
|
|
79
|
+
|
|
80
|
+
BLOCKING_ISSUES:
|
|
81
|
+
- No blocking issues found
|
|
82
|
+
|
|
83
|
+
RECOMMENDATIONS:
|
|
84
|
+
- Add monitoring
|
|
85
|
+
|
|
86
|
+
CONSENSUS: 93%
|
|
87
|
+
`;
|
|
88
|
+
const result = parseConsensusResponse(response);
|
|
89
|
+
expect(result.blockingIssues).toEqual([]);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should filter "None identified" from blocking issues', () => {
|
|
93
|
+
const response = `
|
|
94
|
+
ANALYSIS:
|
|
95
|
+
Well-considered approach.
|
|
96
|
+
|
|
97
|
+
STRENGTHS:
|
|
98
|
+
- Comprehensive coverage
|
|
99
|
+
|
|
100
|
+
CONCERNS:
|
|
101
|
+
- Minor style issues
|
|
102
|
+
|
|
103
|
+
BLOCKING_ISSUES:
|
|
104
|
+
- None identified
|
|
105
|
+
|
|
106
|
+
RECOMMENDATIONS:
|
|
107
|
+
- Standardize formatting
|
|
108
|
+
|
|
109
|
+
CONSENSUS: 91%
|
|
110
|
+
`;
|
|
111
|
+
const result = parseConsensusResponse(response);
|
|
112
|
+
expect(result.blockingIssues).toEqual([]);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should handle missing BLOCKING_ISSUES section (backward compat)', () => {
|
|
116
|
+
const response = `
|
|
117
|
+
ANALYSIS:
|
|
118
|
+
Reasonable plan.
|
|
119
|
+
|
|
120
|
+
STRENGTHS:
|
|
121
|
+
- Good overall approach
|
|
122
|
+
|
|
123
|
+
CONCERNS:
|
|
124
|
+
- Needs more detail
|
|
125
|
+
|
|
126
|
+
RECOMMENDATIONS:
|
|
127
|
+
- Expand on implementation details
|
|
128
|
+
|
|
129
|
+
CONSENSUS: 82%
|
|
130
|
+
`;
|
|
131
|
+
|
|
132
|
+
const result = parseConsensusResponse(response);
|
|
133
|
+
|
|
134
|
+
expect(result.blockingIssues).toEqual([]);
|
|
135
|
+
expect(result.score).toBe(82);
|
|
136
|
+
});
|
|
137
|
+
});
|