@entelligentsia/forgecli 1.0.21 → 1.0.36
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/CHANGELOG.md +346 -0
- package/README.md +2 -0
- package/dist/CHANGELOG-forge-plugin.md +281 -0
- package/dist/bin/argv.d.ts +2 -2
- package/dist/bin/argv.js +25 -0
- package/dist/bin/argv.js.map +1 -1
- package/dist/bin/forge.js +12 -0
- package/dist/bin/forge.js.map +1 -1
- package/dist/bin/init.d.ts +23 -0
- package/dist/bin/init.js +123 -0
- package/dist/bin/init.js.map +1 -0
- package/dist/bin/uninstall.d.ts +20 -0
- package/dist/bin/uninstall.js +141 -0
- package/dist/bin/uninstall.js.map +1 -0
- package/dist/extensions/forgecli/claude-bootstrap/bootstrap.d.ts +40 -0
- package/dist/extensions/forgecli/claude-bootstrap/bootstrap.js +593 -0
- package/dist/extensions/forgecli/claude-bootstrap/bootstrap.js.map +1 -0
- package/dist/extensions/forgecli/claude-bootstrap/settings-merge.d.ts +46 -0
- package/dist/extensions/forgecli/claude-bootstrap/settings-merge.js +245 -0
- package/dist/extensions/forgecli/claude-bootstrap/settings-merge.js.map +1 -0
- package/dist/extensions/forgecli/claude-bootstrap/uninstall.d.ts +23 -0
- package/dist/extensions/forgecli/claude-bootstrap/uninstall.js +215 -0
- package/dist/extensions/forgecli/claude-bootstrap/uninstall.js.map +1 -0
- package/dist/extensions/forgecli/dashboard/component.js +10 -7
- package/dist/extensions/forgecli/dashboard/component.js.map +1 -1
- package/dist/extensions/forgecli/forge-tools.d.ts +1 -0
- package/dist/extensions/forgecli/forge-tools.js +73 -0
- package/dist/extensions/forgecli/forge-tools.js.map +1 -1
- package/dist/extensions/forgecli/lib/forge-root.d.ts +5 -0
- package/dist/extensions/forgecli/lib/forge-root.js +14 -1
- package/dist/extensions/forgecli/lib/forge-root.js.map +1 -1
- package/dist/extensions/forgecli/orchestrators/bug/bug-body.d.ts +1 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-body.js +65 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-body.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-id.d.ts +23 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-id.js +140 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-id.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-phase-dispatch.d.ts +54 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-phase-dispatch.js +349 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-phase-dispatch.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-phases.d.ts +8 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-phases.js +60 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-phases.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-state.d.ts +14 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-state.js +100 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-state.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-triage-routing.d.ts +72 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-triage-routing.js +204 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-triage-routing.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-verdict-loop.d.ts +38 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-verdict-loop.js +166 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-verdict-loop.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-verdict.d.ts +3 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-verdict.js +55 -0
- package/dist/extensions/forgecli/orchestrators/bug/bug-verdict.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/bug/run-bug-command.d.ts +7 -0
- package/dist/extensions/forgecli/orchestrators/bug/run-bug-command.js +293 -0
- package/dist/extensions/forgecli/orchestrators/bug/run-bug-command.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/bug/run-bug-pipeline.d.ts +2 -0
- package/dist/extensions/forgecli/orchestrators/bug/run-bug-pipeline.js +501 -0
- package/dist/extensions/forgecli/orchestrators/bug/run-bug-pipeline.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/bug/run-bug-types.d.ts +41 -0
- package/dist/extensions/forgecli/orchestrators/bug/run-bug-types.js +5 -0
- package/dist/extensions/forgecli/orchestrators/bug/run-bug-types.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/common/orchestrator-entry.d.ts +43 -0
- package/dist/extensions/forgecli/orchestrators/common/orchestrator-entry.js +85 -0
- package/dist/extensions/forgecli/orchestrators/common/orchestrator-entry.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/common/orchestrator-misc.d.ts +8 -0
- package/dist/extensions/forgecli/orchestrators/common/orchestrator-misc.js +37 -0
- package/dist/extensions/forgecli/orchestrators/common/orchestrator-misc.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/common/orchestrator-notify.d.ts +28 -0
- package/dist/extensions/forgecli/orchestrators/common/orchestrator-notify.js +45 -0
- package/dist/extensions/forgecli/orchestrators/common/orchestrator-notify.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/common/orchestrator-transcript-session.d.ts +26 -0
- package/dist/extensions/forgecli/orchestrators/common/orchestrator-transcript-session.js +75 -0
- package/dist/extensions/forgecli/orchestrators/common/orchestrator-transcript-session.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/common/summary-recovery.d.ts +24 -0
- package/dist/extensions/forgecli/orchestrators/common/summary-recovery.js +37 -0
- package/dist/extensions/forgecli/orchestrators/common/summary-recovery.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/fix-bug.d.ts +9 -92
- package/dist/extensions/forgecli/orchestrators/fix-bug.js +23 -1695
- package/dist/extensions/forgecli/orchestrators/fix-bug.js.map +1 -1
- package/dist/extensions/forgecli/orchestrators/run-sprint.d.ts +3 -12
- package/dist/extensions/forgecli/orchestrators/run-sprint.js +97 -270
- package/dist/extensions/forgecli/orchestrators/run-sprint.js.map +1 -1
- package/dist/extensions/forgecli/orchestrators/run-task.d.ts +10 -214
- package/dist/extensions/forgecli/orchestrators/run-task.js +31 -1481
- package/dist/extensions/forgecli/orchestrators/run-task.js.map +1 -1
- package/dist/extensions/forgecli/orchestrators/sprint/sprint-ceremony.d.ts +33 -0
- package/dist/extensions/forgecli/orchestrators/sprint/sprint-ceremony.js +135 -0
- package/dist/extensions/forgecli/orchestrators/sprint/sprint-ceremony.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/sprint/sprint-state.d.ts +18 -0
- package/dist/extensions/forgecli/orchestrators/sprint/sprint-state.js +55 -0
- package/dist/extensions/forgecli/orchestrators/sprint/sprint-state.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/task/run-task-command.d.ts +9 -0
- package/dist/extensions/forgecli/orchestrators/task/run-task-command.js +174 -0
- package/dist/extensions/forgecli/orchestrators/task/run-task-command.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/task/run-task-pipeline.d.ts +2 -0
- package/dist/extensions/forgecli/orchestrators/task/run-task-pipeline.js +494 -0
- package/dist/extensions/forgecli/orchestrators/task/run-task-pipeline.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/task/run-task-types.d.ts +62 -0
- package/dist/extensions/forgecli/orchestrators/task/run-task-types.js +5 -0
- package/dist/extensions/forgecli/orchestrators/task/run-task-types.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/task/task-body.d.ts +4 -0
- package/dist/extensions/forgecli/orchestrators/task/task-body.js +48 -0
- package/dist/extensions/forgecli/orchestrators/task/task-body.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/task/task-events.d.ts +63 -0
- package/dist/extensions/forgecli/orchestrators/task/task-events.js +185 -0
- package/dist/extensions/forgecli/orchestrators/task/task-events.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/task/task-gates.d.ts +34 -0
- package/dist/extensions/forgecli/orchestrators/task/task-gates.js +78 -0
- package/dist/extensions/forgecli/orchestrators/task/task-gates.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/task/task-phase-dispatch.d.ts +42 -0
- package/dist/extensions/forgecli/orchestrators/task/task-phase-dispatch.js +370 -0
- package/dist/extensions/forgecli/orchestrators/task/task-phase-dispatch.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/task/task-phases.d.ts +14 -0
- package/dist/extensions/forgecli/orchestrators/task/task-phases.js +26 -0
- package/dist/extensions/forgecli/orchestrators/task/task-phases.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/task/task-record.d.ts +9 -0
- package/dist/extensions/forgecli/orchestrators/task/task-record.js +58 -0
- package/dist/extensions/forgecli/orchestrators/task/task-record.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/task/task-state.d.ts +14 -0
- package/dist/extensions/forgecli/orchestrators/task/task-state.js +35 -0
- package/dist/extensions/forgecli/orchestrators/task/task-state.js.map +1 -0
- package/dist/extensions/forgecli/orchestrators/task/task-verdict-loop.d.ts +36 -0
- package/dist/extensions/forgecli/orchestrators/task/task-verdict-loop.js +152 -0
- package/dist/extensions/forgecli/orchestrators/task/task-verdict-loop.js.map +1 -0
- package/dist/extensions/forgecli/update/forge-update-command.js +10 -7
- package/dist/extensions/forgecli/update/forge-update-command.js.map +1 -1
- package/dist/forge-payload/.base-pack/commands/approve.md +2 -2
- package/dist/forge-payload/.base-pack/commands/check-agent.md +2 -2
- package/dist/forge-payload/.base-pack/commands/collate.md +2 -2
- package/dist/forge-payload/.base-pack/commands/commit.md +2 -2
- package/dist/forge-payload/.base-pack/commands/enhance.md +2 -2
- package/dist/forge-payload/.base-pack/commands/fix-bug.md +2 -2
- package/dist/forge-payload/.base-pack/commands/implement.md +2 -2
- package/dist/forge-payload/.base-pack/commands/init.md +278 -0
- package/dist/forge-payload/.base-pack/commands/new-sprint.md +2 -2
- package/dist/forge-payload/.base-pack/commands/plan-sprint.md +2 -2
- package/dist/forge-payload/.base-pack/commands/plan.md +2 -2
- package/dist/forge-payload/.base-pack/commands/retro.md +2 -2
- package/dist/forge-payload/.base-pack/commands/review-code.md +2 -2
- package/dist/forge-payload/.base-pack/commands/review-plan.md +2 -2
- package/dist/forge-payload/.base-pack/commands/run-sprint.md +2 -2
- package/dist/forge-payload/.base-pack/commands/run-task.md +2 -2
- package/dist/forge-payload/.base-pack/commands/validate.md +2 -2
- package/dist/forge-payload/.base-pack/workflows/_fragments/event-emission-schema.md +4 -0
- package/dist/forge-payload/.base-pack/workflows/_fragments/event-vocabulary.md +88 -0
- package/dist/forge-payload/.base-pack/workflows/collator_agent.md +5 -6
- package/dist/forge-payload/.base-pack/workflows/commit_task.md +41 -38
- package/dist/forge-payload/.base-pack/workflows/implement_plan.md +3 -3
- package/dist/forge-payload/.base-pack/workflows/migrate_structural.md +1 -1
- package/dist/forge-payload/.base-pack/workflows-js/wfl-fix-bug.js +42 -6
- package/dist/forge-payload/.base-pack/workflows-js/wfl-init.js +449 -0
- package/dist/forge-payload/.base-pack/workflows-js/wfl-run-task.js +32 -1
- package/dist/forge-payload/.claude-plugin/plugin.json +1 -1
- package/dist/forge-payload/.schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/.schemas/event.schema.json +8 -3
- package/dist/forge-payload/.schemas/migrations.json +141 -0
- package/dist/forge-payload/commands/add-pipeline.md +1 -1
- package/dist/forge-payload/commands/add-task.md +3 -3
- package/dist/forge-payload/commands/ask.md +1 -1
- package/dist/forge-payload/commands/check-agent.md +1 -1
- package/dist/forge-payload/commands/config.md +1 -1
- package/dist/forge-payload/commands/health.md +1 -1
- package/dist/forge-payload/commands/init.md +62 -7
- package/dist/forge-payload/commands/rebuild.md +3 -3
- package/dist/forge-payload/commands/remove.md +1 -1
- package/dist/forge-payload/commands/repair.md +1 -1
- package/dist/forge-payload/commands/report-bug.md +1 -1
- package/dist/forge-payload/commands/status.md +1 -1
- package/dist/forge-payload/commands/update.md +3 -3
- package/dist/forge-payload/hooks/lib/common.cjs +228 -0
- package/dist/forge-payload/hooks/lib/plugin-detection.cjs +106 -0
- package/dist/forge-payload/hooks/lib/update-msg.cjs +23 -0
- package/dist/forge-payload/hooks/lib/update-url.cjs +46 -0
- package/dist/forge-payload/hooks/lib/write-registry.js +53 -0
- package/dist/forge-payload/init/discovery/discover-database.md +32 -0
- package/dist/forge-payload/init/discovery/discover-processes.md +31 -0
- package/dist/forge-payload/init/discovery/discover-routing.md +31 -0
- package/dist/forge-payload/init/discovery/discover-stack.md +33 -0
- package/dist/forge-payload/init/discovery/discover-testing.md +34 -0
- package/dist/forge-payload/init/generation/generate-commands.md +171 -0
- package/dist/forge-payload/init/generation/generate-kb-doc.md +60 -0
- package/dist/forge-payload/init/generation/generate-knowledge-base.md +56 -0
- package/dist/forge-payload/init/generation/generate-persona.md +73 -0
- package/dist/forge-payload/init/generation/generate-personas.md +54 -0
- package/dist/forge-payload/init/generation/generate-skill.md +66 -0
- package/dist/forge-payload/init/generation/generate-skills.md +36 -0
- package/dist/forge-payload/init/generation/generate-template.md +60 -0
- package/dist/forge-payload/init/generation/generate-templates.md +39 -0
- package/dist/forge-payload/init/generation/generate-tools.md +133 -0
- package/dist/forge-payload/init/generation/generate-workflows.md +78 -0
- package/dist/forge-payload/init/phases/phase-1-collect.md +10 -2
- package/dist/forge-payload/init/phases/phase-3-materialize.md +1 -1
- package/dist/forge-payload/init/phases/phase-4-register.md +8 -0
- package/dist/forge-payload/init/workflow-gen-plan.json +17 -0
- package/dist/forge-payload/integrity.json +16 -16
- package/dist/forge-payload/meta/store-schema/event.schema.md +7 -0
- package/dist/forge-payload/meta/workflows/_fragments/event-emission-schema.md +4 -0
- package/dist/forge-payload/meta/workflows/_fragments/event-vocabulary.md +88 -0
- package/dist/forge-payload/meta/workflows/meta-collate.md +5 -6
- package/dist/forge-payload/meta/workflows/meta-commit.md +46 -43
- package/dist/forge-payload/meta/workflows/meta-fix-bug.md +7 -2
- package/dist/forge-payload/meta/workflows/meta-implement.md +3 -3
- package/dist/forge-payload/meta/workflows/meta-migrate.md +1 -1
- package/dist/forge-payload/meta/workflows/meta-orchestrate.md +4 -1
- package/dist/forge-payload/schemas/enum-catalog.json +2 -2
- package/dist/forge-payload/schemas/event.schema.json +8 -3
- package/dist/forge-payload/schemas/structure-manifest.json +5 -12
- package/dist/forge-payload/tools/commit-task.cjs +218 -0
- package/dist/forge-payload/tools/forge-preflight.cjs +268 -0
- package/dist/forge-payload/tools/lib/paths.cjs +12 -11
- package/dist/forge-payload/tools/lib/pricing.cjs +31 -11
- package/dist/forge-payload/tools/query-logger.cjs +34 -0
- package/dist/forge-payload/tools/store-cli.cjs +6 -1
- package/dist/forge-payload/tools/substitute-placeholders.cjs +5 -6
- package/package.json +2 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bug-phases.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/orchestrators/bug/bug-phases.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,+EAA+E;AAC/E,6EAA6E;AAI7E,+EAA+E;AAC/E,EAAE;AACF,6EAA6E;AAC7E,wEAAwE;AACxE,mDAAmD;AAEnD,uEAAuE;AACvE,uEAAuE;AAEvE,MAAM,CAAC,MAAM,UAAU,GAAsB;IAC5C,8EAA8E;IAC9E,sEAAsE;IACtE,uEAAuE;IACvE,0EAA0E;IAC1E,kEAAkE;IAClE,uEAAuE;IACvE,2BAA2B;IAC3B,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;IACvG,EAAE,IAAI,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;IAC3G,EAAE,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE;IACjH,EAAE,IAAI,EAAE,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;IACjH,EAAE,IAAI,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE;IACjH,EAAE,IAAI,EAAE,SAAS,EAAE,YAAY,EAAE,mBAAmB,EAAE,WAAW,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE;IAClH,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;CAC3G,CAAC;AAEF,8EAA8E;AAC9E,4EAA4E;AAC5E,+EAA+E;AAC/E,oEAAoE;AACpE,MAAM,CAAC,MAAM,eAAe,GAAmD;IAC9E,MAAM,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE;IACpD,UAAU,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE;IACxD,aAAa,EAAE,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,mBAAmB,EAAE;IACvE,SAAS,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,iBAAiB,EAAE;IAC/D,aAAa,EAAE,EAAE,IAAI,EAAE,wBAAwB,EAAE,IAAI,EAAE,wBAAwB,EAAE;IACjF,OAAO,EAAE,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,wBAAwB,EAAE;IACjE,MAAM,EAAE,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,mBAAmB,EAAE;CAC5D,CAAC;AAEF,8EAA8E;AAC9E,wDAAwD;AACxD,sEAAsE;AACtE,+DAA+D;AAE/D,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAEtD,wEAAwE;AACxE,oEAAoE;AACpE,qEAAqE;AACrE,0EAA0E;AAC1E,yEAAyE;AACzE,wEAAwE;AACxE,wEAAwE;AACxE,iEAAiE;AACjE,MAAM,UAAU,qBAAqB,CAAC,MAA0B;IAC/D,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,CAAC,SAAS,EAAE,aAAa,CAAC,CAAC;IAC7D,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,CAAC,aAAa,CAAC,CAAC;IACjD,OAAO,EAAE,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface RunBugState {
|
|
2
|
+
bugId: string;
|
|
3
|
+
phaseIndex: number;
|
|
4
|
+
iterationCounts: Record<string, number>;
|
|
5
|
+
halted: boolean;
|
|
6
|
+
/** Set on cancellation so the resume prompt says "cancelled" vs "halted". */
|
|
7
|
+
status?: "cancelled" | "halted" | "running";
|
|
8
|
+
lastError?: string;
|
|
9
|
+
savedAt: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function readBugState(cwd: string, bugId: string, sessionId?: string): RunBugState | null;
|
|
12
|
+
export declare function writeBugState(cwd: string, state: RunBugState): void;
|
|
13
|
+
export declare function deleteBugState(cwd: string, bugId: string): void;
|
|
14
|
+
export declare function isBugStateStale(state: RunBugState): boolean;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// bug-state.ts — bug-pipeline state persistence (RunBugState + the cache-file
|
|
2
|
+
// read/write/delete/stale helpers). Extracted VERBATIM from fix-bug.ts
|
|
3
|
+
// (FORGE-S31 file-size refactor); no logic changes.
|
|
4
|
+
import * as fs from "node:fs";
|
|
5
|
+
import * as path from "node:path";
|
|
6
|
+
import { validateId } from "../common/orchestrator-misc.js";
|
|
7
|
+
function bugStateFilePath(cwd, bugId, sessionId) {
|
|
8
|
+
if (!validateId(bugId)) {
|
|
9
|
+
throw new Error(`Invalid bugId for state file path: ${bugId}`);
|
|
10
|
+
}
|
|
11
|
+
const suffix = sessionId ?? process.env.FORGE_SESSION_ID ?? `${process.pid}`;
|
|
12
|
+
return path.join(cwd, ".forge", "cache", `fix-bug-state-${bugId}-${suffix}.json`);
|
|
13
|
+
}
|
|
14
|
+
export function readBugState(cwd, bugId, sessionId) {
|
|
15
|
+
// If a specific session ID is given, read that file directly.
|
|
16
|
+
if (sessionId || process.env.FORGE_SESSION_ID) {
|
|
17
|
+
const fp = bugStateFilePath(cwd, bugId, sessionId);
|
|
18
|
+
try {
|
|
19
|
+
if (!fs.existsSync(fp))
|
|
20
|
+
return null;
|
|
21
|
+
const raw = fs.readFileSync(fp, "utf8");
|
|
22
|
+
return JSON.parse(raw);
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// No specific session — glob for the most recent matching state file.
|
|
29
|
+
// Single-writer assumption: normally only one session per bug.
|
|
30
|
+
const cacheDir = path.join(cwd, ".forge", "cache");
|
|
31
|
+
const prefix = `fix-bug-state-${bugId}-`;
|
|
32
|
+
let bestFile = null;
|
|
33
|
+
let bestMtime = 0;
|
|
34
|
+
try {
|
|
35
|
+
const entries = fs.readdirSync(cacheDir);
|
|
36
|
+
for (const entry of entries) {
|
|
37
|
+
if (!entry.startsWith(prefix) || !entry.endsWith(".json"))
|
|
38
|
+
continue;
|
|
39
|
+
const fp = path.join(cacheDir, entry);
|
|
40
|
+
try {
|
|
41
|
+
const st = fs.statSync(fp);
|
|
42
|
+
if (st.mtimeMs > bestMtime) {
|
|
43
|
+
bestMtime = st.mtimeMs;
|
|
44
|
+
bestFile = fp;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch { }
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
if (!bestFile)
|
|
54
|
+
return null;
|
|
55
|
+
try {
|
|
56
|
+
const raw = fs.readFileSync(bestFile, "utf8");
|
|
57
|
+
return JSON.parse(raw);
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export function writeBugState(cwd, state) {
|
|
64
|
+
// Guard: never write state for PENDING bugIds — wait for real bugId capture.
|
|
65
|
+
if (state.bugId.startsWith("PENDING-"))
|
|
66
|
+
return;
|
|
67
|
+
const fp = bugStateFilePath(cwd, state.bugId);
|
|
68
|
+
const dir = path.dirname(fp);
|
|
69
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
70
|
+
fs.writeFileSync(fp, JSON.stringify(state, null, 2), "utf8");
|
|
71
|
+
}
|
|
72
|
+
export function deleteBugState(cwd, bugId) {
|
|
73
|
+
// Clean up all state files for this bug (all sessions)
|
|
74
|
+
const cacheDir = path.join(cwd, ".forge", "cache");
|
|
75
|
+
const statePrefix = `fix-bug-state-${bugId}-`;
|
|
76
|
+
const debugPrefix = `fix-bug-debug-${bugId}`;
|
|
77
|
+
try {
|
|
78
|
+
const entries = fs.readdirSync(cacheDir);
|
|
79
|
+
for (const entry of entries) {
|
|
80
|
+
if ((entry.startsWith(statePrefix) && entry.endsWith(".json")) || entry.startsWith(debugPrefix)) {
|
|
81
|
+
try {
|
|
82
|
+
fs.unlinkSync(path.join(cacheDir, entry));
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
/* non-fatal */
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// non-fatal
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export function isBugStateStale(state) {
|
|
95
|
+
const savedAt = new Date(state.savedAt).getTime();
|
|
96
|
+
const ageMs = Date.now() - savedAt;
|
|
97
|
+
const sevenDaysMs = 7 * 24 * 60 * 60 * 1000;
|
|
98
|
+
return ageMs > sevenDaysMs;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=bug-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bug-state.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/orchestrators/bug/bug-state.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { PhaseDescriptor } from "../run-task.js";
|
|
3
|
+
import type { BugRecord } from "./bug-id.js";
|
|
4
|
+
import type { RunBugPipelineResult } from "./run-bug-types.js";
|
|
5
|
+
export interface MaybeSkipParams {
|
|
6
|
+
phase: PhaseDescriptor;
|
|
7
|
+
bugId: string;
|
|
8
|
+
cwd: string;
|
|
9
|
+
ctx: ExtensionCommandContext;
|
|
10
|
+
storeCli: string;
|
|
11
|
+
/** Bug record read at the top of §6a (same read the caller already did). */
|
|
12
|
+
bugNow: BugRecord | null;
|
|
13
|
+
summaryKeyByRole: Record<string, string | null>;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* §6a — decide whether the current phase should be skipped because the bug is
|
|
17
|
+
* already in a done state. When skipping, writes a synthetic summary so
|
|
18
|
+
* downstream `after <phase>` verdict checks succeed. Returns true when the
|
|
19
|
+
* caller should `currentPhaseIndex++; continue;`.
|
|
20
|
+
*/
|
|
21
|
+
export declare function maybeSkipPhase(p: MaybeSkipParams): boolean;
|
|
22
|
+
export interface CaptureTriageBugIdParams {
|
|
23
|
+
bugId: string;
|
|
24
|
+
cwd: string;
|
|
25
|
+
ctx: ExtensionCommandContext;
|
|
26
|
+
storeCli: string;
|
|
27
|
+
currentPhaseIndex: number;
|
|
28
|
+
iterationCounts: Record<string, number>;
|
|
29
|
+
debugLogDisabled: boolean;
|
|
30
|
+
toolExecutionEvents: Array<{
|
|
31
|
+
toolName?: string;
|
|
32
|
+
result?: unknown;
|
|
33
|
+
}>;
|
|
34
|
+
}
|
|
35
|
+
export type CaptureTriageBugIdOutcome = {
|
|
36
|
+
kind: "return";
|
|
37
|
+
result: RunBugPipelineResult;
|
|
38
|
+
} | {
|
|
39
|
+
kind: "ok";
|
|
40
|
+
bugId: string;
|
|
41
|
+
debugLogPath: string | null;
|
|
42
|
+
writeDebug: (rec: Record<string, unknown>) => void;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Post-triage bugId capture: for new bugs the triage subagent creates the bug
|
|
46
|
+
* record via store-cli; capture the real id by scanning tool_execution_end
|
|
47
|
+
* events, with a list-and-filter fallback. On success re-initializes the debug
|
|
48
|
+
* log under the real id and returns the updated locals. Preserves the PENDING-
|
|
49
|
+
* nuance: the orchestrator transcript writer keeps the PENDING entityId — this
|
|
50
|
+
* only updates the loop's local bugId.
|
|
51
|
+
*/
|
|
52
|
+
export declare function captureTriageBugId(p: CaptureTriageBugIdParams, writeDebug: (rec: Record<string, unknown>) => void, debugLogPath: string | null): CaptureTriageBugIdOutcome;
|
|
53
|
+
export interface RouteAfterTriageParams {
|
|
54
|
+
bugId: string;
|
|
55
|
+
cwd: string;
|
|
56
|
+
ctx: ExtensionCommandContext;
|
|
57
|
+
storeCli: string;
|
|
58
|
+
currentPhaseIndex: number;
|
|
59
|
+
}
|
|
60
|
+
export type RouteAfterTriageOutcome = {
|
|
61
|
+
kind: "jump";
|
|
62
|
+
toIndex: number;
|
|
63
|
+
} | {
|
|
64
|
+
kind: "advance";
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* §6c — orchestrator-owned post-triage status transitions, then the Path A/B
|
|
68
|
+
* branch read from bug.summaries.triage.route. Path A skips plan-fix +
|
|
69
|
+
* review-plan (jumps to implement); Path B / missing / any other value advances
|
|
70
|
+
* normally.
|
|
71
|
+
*/
|
|
72
|
+
export declare function routeAfterTriage(p: RouteAfterTriageParams): RouteAfterTriageOutcome;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
// bug-triage-routing.ts — bug-specific control flow extracted VERBATIM from
|
|
2
|
+
// fix-bug.ts's phase loop (FORGE-S31 file-size refactor). Two self-contained
|
|
3
|
+
// blocks, each a pure-ish helper the pipeline switches on:
|
|
4
|
+
//
|
|
5
|
+
// 1. maybeSkipPhase — the state-aware phase-skip heuristic (§6a): skip a
|
|
6
|
+
// non-review phase whose output is already reflected in the bug status,
|
|
7
|
+
// writing a synthetic summary so downstream predecessor-verdict checks pass.
|
|
8
|
+
// 2. captureTriageBugId — post-triage bugId capture (§ bugId capture): read the
|
|
9
|
+
// real FORGE-BUG-NNN from triage events, fall back to a list-and-filter,
|
|
10
|
+
// then re-initialize the debug log under the real id. Preserves the
|
|
11
|
+
// PENDING- nuance exactly — the transcript writer keeps the PENDING entityId.
|
|
12
|
+
// 3. routeAfterTriage — the orchestrator-owned post-triage status transitions
|
|
13
|
+
// (§6c) followed by the Path A/B branch read from bug.summaries.triage.route.
|
|
14
|
+
// The source-introspection contract test scans the `postTriageTransitions`
|
|
15
|
+
// wiring here.
|
|
16
|
+
//
|
|
17
|
+
// No logic changes; the inline `continue` / `return` paths are surfaced as small
|
|
18
|
+
// discriminated results.
|
|
19
|
+
import { spawnSync } from "node:child_process";
|
|
20
|
+
import * as fs from "node:fs";
|
|
21
|
+
import * as path from "node:path";
|
|
22
|
+
import { loadGovernorProjectConfig } from "../../governor-config.js";
|
|
23
|
+
import { BUG_PHASES, postTriageTransitions } from "./bug-phases.js";
|
|
24
|
+
import { extractBugIdFromEvents, readBugRecord } from "./bug-id.js";
|
|
25
|
+
// ── 6a. Phase skip (state-aware, defense-in-depth) ─────────────
|
|
26
|
+
// Belt-and-suspenders alongside the explicit summaries.triage.route
|
|
27
|
+
// branch (handled in routeAfterTriage below). Some subagents in some
|
|
28
|
+
// runtimes still go end-to-end during triage instead of just triaging
|
|
29
|
+
// — rather than roll back the work they did, skip non-review phases
|
|
30
|
+
// whose output is already reflected in the bug status. Review phases
|
|
31
|
+
// are never skipped — they are quality gates that must always run.
|
|
32
|
+
//
|
|
33
|
+
// Post-v0.44.0: terminal status is `fixed` only. `approved` and
|
|
34
|
+
// `verified` are no longer valid bug status values; references removed.
|
|
35
|
+
const PHASE_SKIP_STATES = {
|
|
36
|
+
"plan-fix": new Set(["fixed"]),
|
|
37
|
+
implement: new Set(["fixed"]),
|
|
38
|
+
commit: new Set(["fixed"]), // commit writes the terminal status; skip if already there
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* §6a — decide whether the current phase should be skipped because the bug is
|
|
42
|
+
* already in a done state. When skipping, writes a synthetic summary so
|
|
43
|
+
* downstream `after <phase>` verdict checks succeed. Returns true when the
|
|
44
|
+
* caller should `currentPhaseIndex++; continue;`.
|
|
45
|
+
*/
|
|
46
|
+
export function maybeSkipPhase(p) {
|
|
47
|
+
const { phase, bugId, cwd, ctx, storeCli, bugNow, summaryKeyByRole } = p;
|
|
48
|
+
const skipStates = PHASE_SKIP_STATES[phase.role];
|
|
49
|
+
if (!(skipStates && bugNow?.status && skipStates.has(bugNow.status) && !phase.isReview)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
ctx.ui.notify(`⊘ forge:fix-bug — skipping ${phase.role}: bug ${bugId} is already '${bugNow.status}' (work already done).`, "info");
|
|
53
|
+
// Write a synthetic "approved" summary so downstream `after` predecessor
|
|
54
|
+
// verdict checks find a verdict and don't block review phases.
|
|
55
|
+
const summaryKey = summaryKeyByRole[phase.role];
|
|
56
|
+
if (summaryKey) {
|
|
57
|
+
const synthSummary = {
|
|
58
|
+
objective: `Phase ${phase.role} skipped — bug already ${bugNow.status}`,
|
|
59
|
+
findings: ["Subagent completed fix during triage (Path A); phase output implicitly satisfied."],
|
|
60
|
+
// Non-review phases should have verdict "n/a" — the phase
|
|
61
|
+
// didn't produce a gate verdict. This matches the `after
|
|
62
|
+
// <phase> = n/a` preflight gate contract. Review phases
|
|
63
|
+
// use "approved" since they are gate phases.
|
|
64
|
+
verdict: phase.isReview ? "approved" : "n/a",
|
|
65
|
+
written_at: new Date().toISOString(),
|
|
66
|
+
};
|
|
67
|
+
const synthFile = path.join(cwd, ".forge", "cache", `synthetic-summary-${bugId}-${summaryKey}.json`);
|
|
68
|
+
fs.writeFileSync(synthFile, JSON.stringify(synthSummary, null, 2), "utf8");
|
|
69
|
+
const synthResult = spawnSync("node", [storeCli, "set-bug-summary", bugId, summaryKey, synthFile], {
|
|
70
|
+
cwd,
|
|
71
|
+
encoding: "utf8",
|
|
72
|
+
});
|
|
73
|
+
if (synthResult.status !== 0) {
|
|
74
|
+
ctx.ui.notify(`⚠ forge:fix-bug — synthetic summary write failed for ${phase.role}: ${String(synthResult.stderr).trim()}`, "warning");
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
fs.unlinkSync(synthFile);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
/* non-fatal */
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Post-triage bugId capture: for new bugs the triage subagent creates the bug
|
|
87
|
+
* record via store-cli; capture the real id by scanning tool_execution_end
|
|
88
|
+
* events, with a list-and-filter fallback. On success re-initializes the debug
|
|
89
|
+
* log under the real id and returns the updated locals. Preserves the PENDING-
|
|
90
|
+
* nuance: the orchestrator transcript writer keeps the PENDING entityId — this
|
|
91
|
+
* only updates the loop's local bugId.
|
|
92
|
+
*/
|
|
93
|
+
export function captureTriageBugId(p, writeDebug, debugLogPath) {
|
|
94
|
+
const { cwd, ctx, storeCli, currentPhaseIndex, iterationCounts, debugLogDisabled, toolExecutionEvents } = p;
|
|
95
|
+
let bugId = p.bugId;
|
|
96
|
+
const capturedBugId = extractBugIdFromEvents(toolExecutionEvents, loadGovernorProjectConfig(cwd).prefix);
|
|
97
|
+
if (capturedBugId) {
|
|
98
|
+
ctx.ui.notify(`forge:fix-bug — captured bug ID: ${capturedBugId}`, "info");
|
|
99
|
+
bugId = capturedBugId;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// Fallback: list bugs and find the most recent one created after pipeline start.
|
|
103
|
+
const listResult = spawnSync("node", [storeCli, "list", "bug", "--json"], { cwd, encoding: "utf8" });
|
|
104
|
+
if (listResult.status === 0 && listResult.stdout) {
|
|
105
|
+
try {
|
|
106
|
+
const bugs = JSON.parse(listResult.stdout);
|
|
107
|
+
if (Array.isArray(bugs)) {
|
|
108
|
+
// Find most recent bug whose reportedAt is after the pipeline start
|
|
109
|
+
const pipelineStartIso = new Date(parseInt(bugId.replace("PENDING-", ""))).toISOString();
|
|
110
|
+
const recent = bugs
|
|
111
|
+
.filter((b) => b.reportedAt && b.reportedAt >= pipelineStartIso)
|
|
112
|
+
.sort((a, b) => String(b.reportedAt).localeCompare(String(a.reportedAt)))[0];
|
|
113
|
+
if (recent &&
|
|
114
|
+
recent.bugId &&
|
|
115
|
+
typeof recent.bugId === "string" &&
|
|
116
|
+
recent.bugId.startsWith("FORGE-BUG-")) {
|
|
117
|
+
bugId = recent.bugId;
|
|
118
|
+
ctx.ui.notify(`forge:fix-bug — captured bug ID via store fallback: ${bugId}`, "info");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
/* parse failure — fall through to assertion */
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Defensive guard: if bugId is still PENDING after triage, pipeline cannot proceed.
|
|
128
|
+
if (bugId.startsWith("PENDING-")) {
|
|
129
|
+
ctx.ui.notify("× forge:fix-bug — failed to capture real bug ID after triage. Cannot proceed with PENDING placeholder.", "error");
|
|
130
|
+
return {
|
|
131
|
+
kind: "return",
|
|
132
|
+
result: {
|
|
133
|
+
status: "failed",
|
|
134
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
135
|
+
iterationCounts,
|
|
136
|
+
lastError: "bugId still PENDING after triage",
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
// Re-initialize debug log now that real bugId is available.
|
|
141
|
+
if (!debugLogDisabled) {
|
|
142
|
+
debugLogPath = path.join(cwd, ".forge", "cache", `fix-bug-debug-${bugId}.jsonl`);
|
|
143
|
+
const capturedPath = debugLogPath;
|
|
144
|
+
writeDebug = (rec) => {
|
|
145
|
+
try {
|
|
146
|
+
fs.mkdirSync(path.dirname(capturedPath), { recursive: true });
|
|
147
|
+
try {
|
|
148
|
+
const st = fs.statSync(capturedPath);
|
|
149
|
+
if (st.size > 10 * 1024 * 1024) {
|
|
150
|
+
const all = fs.readFileSync(capturedPath, "utf8");
|
|
151
|
+
const lines = all.split("\n");
|
|
152
|
+
const keep = Math.floor(lines.length * 0.8);
|
|
153
|
+
fs.writeFileSync(capturedPath, lines.slice(-keep).join("\n"), "utf8");
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
/* file may not exist yet */
|
|
158
|
+
}
|
|
159
|
+
fs.appendFileSync(capturedPath, `${JSON.stringify({ ts: new Date().toISOString(), phase: "triage", ...rec })}\n`, "utf8");
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
// non-fatal
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
writeDebug({ kind: "bugid_captured", bugId });
|
|
166
|
+
}
|
|
167
|
+
return { kind: "ok", bugId, debugLogPath, writeDebug };
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* §6c — orchestrator-owned post-triage status transitions, then the Path A/B
|
|
171
|
+
* branch read from bug.summaries.triage.route. Path A skips plan-fix +
|
|
172
|
+
* review-plan (jumps to implement); Path B / missing / any other value advances
|
|
173
|
+
* normally.
|
|
174
|
+
*/
|
|
175
|
+
export function routeAfterTriage(p) {
|
|
176
|
+
const { bugId, cwd, ctx, storeCli, currentPhaseIndex } = p;
|
|
177
|
+
const bugAfterTriage = readBugRecord(bugId, storeCli, cwd);
|
|
178
|
+
// Orchestrator-owned post-triage transitions (meta-fix-bug.md
|
|
179
|
+
// step 2). Two sequential writes through store-cli (the FSM
|
|
180
|
+
// authority); failure warns but does not halt — the commit
|
|
181
|
+
// phase's status guard is the backstop.
|
|
182
|
+
for (const target of postTriageTransitions(bugAfterTriage?.status)) {
|
|
183
|
+
const upd = spawnSync("node", [storeCli, "update-status", "bug", bugId, "status", target], {
|
|
184
|
+
cwd,
|
|
185
|
+
encoding: "utf8",
|
|
186
|
+
});
|
|
187
|
+
if (upd.status !== 0) {
|
|
188
|
+
ctx.ui.notify(`⚠ forge:fix-bug — post-triage transition to '${target}' failed: ${(upd.stderr ?? "").toString().trim()}`, "warning");
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const triageSummary = bugAfterTriage?.summaries?.triage;
|
|
193
|
+
const route = triageSummary?.route;
|
|
194
|
+
if (route === "A") {
|
|
195
|
+
const skipUntilIndex = BUG_PHASES.findIndex((ph) => ph.role === "implement");
|
|
196
|
+
if (skipUntilIndex > currentPhaseIndex + 1) {
|
|
197
|
+
ctx.ui.notify(`⊘ forge:fix-bug — Path A selected by triage; skipping plan-fix and review-plan.`, "info");
|
|
198
|
+
return { kind: "jump", toIndex: skipUntilIndex };
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// route === "B", missing, or any other value → fall through to standard advance
|
|
202
|
+
return { kind: "advance" };
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=bug-triage-routing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bug-triage-routing.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/orchestrators/bug/bug-triage-routing.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ExtensionCommandContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { MergedConfig } from "../../config/config-layer.js";
|
|
3
|
+
import type { OrchestratorTranscriptWriter } from "../../subagent/orchestrator-transcript.js";
|
|
4
|
+
import { type PhaseDescriptor } from "../run-task.js";
|
|
5
|
+
import type { RunBugPipelineResult } from "./run-bug-types.js";
|
|
6
|
+
export type BugVerdictLoopOutcome = {
|
|
7
|
+
kind: "advance";
|
|
8
|
+
} | {
|
|
9
|
+
kind: "loopback";
|
|
10
|
+
toIndex: number;
|
|
11
|
+
} | {
|
|
12
|
+
kind: "return";
|
|
13
|
+
result: RunBugPipelineResult;
|
|
14
|
+
};
|
|
15
|
+
export interface BugVerdictLoopParams {
|
|
16
|
+
phase: PhaseDescriptor;
|
|
17
|
+
bugId: string;
|
|
18
|
+
storeCli: string;
|
|
19
|
+
cwd: string;
|
|
20
|
+
forgeRoot: string;
|
|
21
|
+
iterationCounts: Record<string, number>;
|
|
22
|
+
currentPhaseIndex: number;
|
|
23
|
+
modelRoutingConfig: MergedConfig;
|
|
24
|
+
ctx: ExtensionCommandContext;
|
|
25
|
+
orchTranscript: OrchestratorTranscriptWriter;
|
|
26
|
+
/** Per-role phase-summary key map (BUG_SUMMARY_KEY_BY_ROLE). */
|
|
27
|
+
summaryKeyByRole: Record<string, string | null>;
|
|
28
|
+
/** Closure that finalizes this dispatch's OrchestratorTree node. */
|
|
29
|
+
finishPhaseNode: (status: "completed" | "failed" | "escalated") => void;
|
|
30
|
+
/** Per-phase completion-recovery guard (forge-engineering#41) — roles that
|
|
31
|
+
* already consumed their one set-bug-summary recovery attempt this run. */
|
|
32
|
+
recoveredPhases: Set<string>;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Evaluate the review-phase verdict and decide the loop's next move.
|
|
36
|
+
* Mirrors the inline block that previously lived in runBugPipelineInner.
|
|
37
|
+
*/
|
|
38
|
+
export declare function handleBugReviewVerdict(p: BugVerdictLoopParams): BugVerdictLoopOutcome;
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
// bug-verdict-loop.ts — review-phase verdict + revision/loopback handling for
|
|
2
|
+
// the fix-bug pipeline. Extracted VERBATIM from fix-bug.ts's phase loop
|
|
3
|
+
// (FORGE-S31 file-size refactor) as a pure decision function: it performs the
|
|
4
|
+
// same store reads, ctx.ui notifications, state writes, transcript records,
|
|
5
|
+
// tree-node finalization, status-reset transition, and halt-advisor dispatch the
|
|
6
|
+
// inline block did, and returns a small discriminated result the caller's loop
|
|
7
|
+
// switches on.
|
|
8
|
+
//
|
|
9
|
+
// Behavior-preserving: no logic changes. The only structural change is that the
|
|
10
|
+
// inline `return {...}` paths now return `{ kind: "return"; result }`, the
|
|
11
|
+
// `continue` path returns `{ kind: "loopback"; toIndex }`, and the fall-through
|
|
12
|
+
// (approved) path returns `{ kind: "advance" }`.
|
|
13
|
+
import { spawnSync } from "node:child_process";
|
|
14
|
+
import { resolveAdvisorModel, runHaltAdvisor } from "../halt-advisor.js";
|
|
15
|
+
import { recoverPhaseSummary } from "../common/summary-recovery.js";
|
|
16
|
+
import { findPredecessorIndex } from "../run-task.js";
|
|
17
|
+
import { BUG_PHASES } from "./bug-phases.js";
|
|
18
|
+
import { readBugRecord } from "./bug-id.js";
|
|
19
|
+
import { writeBugState } from "./bug-state.js";
|
|
20
|
+
import { readBugVerdict } from "./bug-verdict.js";
|
|
21
|
+
/**
|
|
22
|
+
* Evaluate the review-phase verdict and decide the loop's next move.
|
|
23
|
+
* Mirrors the inline block that previously lived in runBugPipelineInner.
|
|
24
|
+
*/
|
|
25
|
+
export function handleBugReviewVerdict(p) {
|
|
26
|
+
const { phase, bugId, storeCli, cwd, forgeRoot, iterationCounts, currentPhaseIndex, modelRoutingConfig, ctx } = p;
|
|
27
|
+
const { orchTranscript, finishPhaseNode, summaryKeyByRole, recoveredPhases } = p;
|
|
28
|
+
// Re-read bug record for latest status after subagent ran
|
|
29
|
+
const updatedBugRecord = readBugRecord(bugId, storeCli, cwd);
|
|
30
|
+
let verdict = readBugVerdict(updatedBugRecord, phase.role, summaryKeyByRole);
|
|
31
|
+
// Completion recovery (forge-engineering#41): a clean stop with no verdict in
|
|
32
|
+
// the store is most often the subagent writing the {PHASE}-SUMMARY.json
|
|
33
|
+
// sidecar but eliding the set-bug-summary that registers it. Register the
|
|
34
|
+
// sidecar ourselves (once per phase), then re-read. Phases whose verdict comes
|
|
35
|
+
// from bug.status (e.g. commit → summaryKey null) are not recoverable this way.
|
|
36
|
+
if (verdict === "missing") {
|
|
37
|
+
const summaryKey = summaryKeyByRole[phase.role];
|
|
38
|
+
if (summaryKey && !recoveredPhases.has(phase.role)) {
|
|
39
|
+
recoveredPhases.add(phase.role);
|
|
40
|
+
const rec = recoverPhaseSummary({
|
|
41
|
+
storeCli,
|
|
42
|
+
entityId: bugId,
|
|
43
|
+
summaryKey,
|
|
44
|
+
cwd,
|
|
45
|
+
summaryVerb: "set-bug-summary",
|
|
46
|
+
});
|
|
47
|
+
if (rec.ok) {
|
|
48
|
+
const recheck = readBugVerdict(readBugRecord(bugId, storeCli, cwd), phase.role, summaryKeyByRole);
|
|
49
|
+
if (recheck !== "missing") {
|
|
50
|
+
ctx.ui.notify(`⟳ forge:fix-bug — ${phase.role}: subagent skipped set-bug-summary; orchestrator registered ` +
|
|
51
|
+
`the '${summaryKey}' sidecar and the verdict is now present.`, "info");
|
|
52
|
+
verdict = recheck;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (verdict === "missing") {
|
|
58
|
+
ctx.ui.notify(`× forge:fix-bug — verdict missing for phase ${phase.role} after subagent completed. Halting for advisory.`, "error");
|
|
59
|
+
finishPhaseNode("failed");
|
|
60
|
+
writeBugState(cwd, {
|
|
61
|
+
bugId,
|
|
62
|
+
phaseIndex: currentPhaseIndex,
|
|
63
|
+
iterationCounts,
|
|
64
|
+
halted: true,
|
|
65
|
+
lastError: `verdict missing for ${phase.role}`,
|
|
66
|
+
savedAt: new Date().toISOString(),
|
|
67
|
+
});
|
|
68
|
+
// A missing verdict IS a postflight-outputs failure: the canonical
|
|
69
|
+
// phase summary the subagent must write (e.g. summaries.code_review,
|
|
70
|
+
// linked via set-bug-summary) was never recorded, so there is no
|
|
71
|
+
// verdict to route on. Route it through the halt-recovery advisor
|
|
72
|
+
// (FORGE-S26-T18) — the same hand-off the preflight/postflight gate
|
|
73
|
+
// failures use — instead of a bare escalation. Best-effort, non-fatal.
|
|
74
|
+
const advisorModel = resolveAdvisorModel(modelRoutingConfig, ctx.model);
|
|
75
|
+
void runHaltAdvisor({
|
|
76
|
+
gateFailure: {
|
|
77
|
+
phase: phase.role,
|
|
78
|
+
reasonCode: "verdict-missing",
|
|
79
|
+
detail: `Phase '${phase.role}' completed but no verdict was found in the store. ` +
|
|
80
|
+
"The canonical phase summary was not written, so the orchestrator has no verdict to route on.",
|
|
81
|
+
remediation: "Re-run the phase and ensure the subagent's forge_store set-bug-summary call " +
|
|
82
|
+
'uses args:["<bugId>", "<phaseKey>"] with the literal phase key as args[1] ' +
|
|
83
|
+
"(e.g. code_review), and that the call exits zero before the subagent returns.",
|
|
84
|
+
},
|
|
85
|
+
advisorModel,
|
|
86
|
+
taskId: bugId,
|
|
87
|
+
cwd,
|
|
88
|
+
ctx: { ui: ctx.ui },
|
|
89
|
+
forgeRoot,
|
|
90
|
+
});
|
|
91
|
+
return {
|
|
92
|
+
kind: "return",
|
|
93
|
+
result: {
|
|
94
|
+
status: "halted",
|
|
95
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
96
|
+
iterationCounts,
|
|
97
|
+
lastError: `verdict missing for ${phase.role}`,
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
if (verdict === "revision") {
|
|
102
|
+
iterationCounts[phase.role] = (iterationCounts[phase.role] ?? 0) + 1;
|
|
103
|
+
if (iterationCounts[phase.role] >= phase.maxIterations) {
|
|
104
|
+
ctx.ui.notify(`× forge:fix-bug — revision cap reached for phase ${phase.role} ` +
|
|
105
|
+
`(${iterationCounts[phase.role]}/${phase.maxIterations} iterations). Escalating.`, "error");
|
|
106
|
+
finishPhaseNode("escalated");
|
|
107
|
+
writeBugState(cwd, {
|
|
108
|
+
bugId,
|
|
109
|
+
phaseIndex: currentPhaseIndex,
|
|
110
|
+
iterationCounts,
|
|
111
|
+
halted: true,
|
|
112
|
+
lastError: `revision cap reached for ${phase.role}`,
|
|
113
|
+
savedAt: new Date().toISOString(),
|
|
114
|
+
});
|
|
115
|
+
return {
|
|
116
|
+
kind: "return",
|
|
117
|
+
result: {
|
|
118
|
+
status: "escalated",
|
|
119
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
120
|
+
iterationCounts,
|
|
121
|
+
lastError: `revision cap reached for ${phase.role}`,
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// Transition bug back to in-progress before re-dispatching implement.
|
|
126
|
+
// This is required for review-code → implement and approve → implement loops.
|
|
127
|
+
const currentBugStatus = updatedBugRecord?.status;
|
|
128
|
+
if (currentBugStatus === "fixed" || currentBugStatus === "approved") {
|
|
129
|
+
const transitionResult = spawnSync("node", [storeCli, "update-status", "bug", bugId, "status", "in-progress"], { cwd, encoding: "utf8" });
|
|
130
|
+
if (transitionResult.status !== 0) {
|
|
131
|
+
ctx.ui.notify(`⚠ forge:fix-bug — failed to transition bug ${bugId} from ${currentBugStatus} to in-progress: ${transitionResult.stderr ?? "unknown"}`, "warning");
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
ctx.ui.notify(`⟳ forge:fix-bug — transitioned bug ${bugId}: ${currentBugStatus} → in-progress`, "info");
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// The review subagent itself finished cleanly — `revision`
|
|
138
|
+
// is its verdict, not a failure — so its node closes as
|
|
139
|
+
// completed before the predecessor re-dispatches under a
|
|
140
|
+
// fresh node ID.
|
|
141
|
+
finishPhaseNode("completed");
|
|
142
|
+
const predIndex = findPredecessorIndex(BUG_PHASES, currentPhaseIndex);
|
|
143
|
+
ctx.ui.notify(`⟳ forge:fix-bug — ${phase.role} returned revision; looping to ${BUG_PHASES[predIndex]?.role ?? predIndex} ` +
|
|
144
|
+
`(attempt ${iterationCounts[phase.role]}/${phase.maxIterations})`, "info");
|
|
145
|
+
orchTranscript.record({
|
|
146
|
+
kind: "phase-loopback",
|
|
147
|
+
ts: new Date().toISOString(),
|
|
148
|
+
fromPhase: phase.role,
|
|
149
|
+
toPhase: BUG_PHASES[predIndex]?.role ?? String(predIndex),
|
|
150
|
+
fromPhaseIndex: currentPhaseIndex,
|
|
151
|
+
toPhaseIndex: predIndex,
|
|
152
|
+
reason: `${phase.role} returned revision (attempt ${iterationCounts[phase.role]}/${phase.maxIterations})`,
|
|
153
|
+
});
|
|
154
|
+
writeBugState(cwd, {
|
|
155
|
+
bugId,
|
|
156
|
+
phaseIndex: predIndex,
|
|
157
|
+
iterationCounts,
|
|
158
|
+
halted: false,
|
|
159
|
+
savedAt: new Date().toISOString(),
|
|
160
|
+
});
|
|
161
|
+
return { kind: "loopback", toIndex: predIndex };
|
|
162
|
+
}
|
|
163
|
+
// verdict === "approved": fall through to advance
|
|
164
|
+
return { kind: "advance" };
|
|
165
|
+
}
|
|
166
|
+
//# sourceMappingURL=bug-verdict-loop.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bug-verdict-loop.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/orchestrators/bug/bug-verdict-loop.ts"],"names":[],"mappings":"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"}
|