@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,370 @@
|
|
|
1
|
+
// task-phase-dispatch.ts — per-phase subagent dispatch for the run-task
|
|
2
|
+
// pipeline: persona load → task-body compose → model resolution → viewport
|
|
3
|
+
// observer attach → context-governor injection → runForgeSubagent (IL10) →
|
|
4
|
+
// post-subagent abort / halt-on-failure detection. Extracted VERBATIM from
|
|
5
|
+
// run-task.ts's phase loop (FORGE-S31 file-size refactor) with no logic
|
|
6
|
+
// changes — the inline `return {...}` paths now return `{ kind: "return";
|
|
7
|
+
// result }`, and the success path returns `{ kind: "ok"; ... }` carrying the
|
|
8
|
+
// live locals the loop needs (subagent result, finishPhaseNode closure,
|
|
9
|
+
// observer, phaseStart, writeDebug).
|
|
10
|
+
//
|
|
11
|
+
// IL10 — ALL LLM dispatch goes through runForgeSubagent (NO sendKickoff here).
|
|
12
|
+
import * as fs from "node:fs";
|
|
13
|
+
import * as path from "node:path";
|
|
14
|
+
import { CallerContextStore } from "../../audience-gate.js";
|
|
15
|
+
import { buildGovernorFactory } from "../../context-governor.js";
|
|
16
|
+
import { buildForgeCompactionFactory } from "../../context-governor-compaction.js";
|
|
17
|
+
import { loadForgePersona, runForgeSubagent } from "../../forge-subagent.js";
|
|
18
|
+
import { getSubagentTools } from "../../forge-tools.js";
|
|
19
|
+
import { resolveModelForPhase } from "../../config/model-resolver.js";
|
|
20
|
+
import { getOrchestratorTree } from "../../orchestrator-tree.js";
|
|
21
|
+
import { attachViewportObserver } from "../../viewport/events.js";
|
|
22
|
+
import { composeTaskBody, buildSummariesBlock } from "./task-body.js";
|
|
23
|
+
import { emitIncompletePhaseEvent } from "./task-events.js";
|
|
24
|
+
import { PHASES } from "./task-phases.js";
|
|
25
|
+
import { readTaskRecord } from "./task-record.js";
|
|
26
|
+
import { writeState } from "./task-state.js";
|
|
27
|
+
const STATUS_KEY = "forge:run-task";
|
|
28
|
+
const MESSAGE_KEY = "forge:run-task:message";
|
|
29
|
+
/**
|
|
30
|
+
* Run a single phase's subagent dispatch and classify the immediate outcome
|
|
31
|
+
* (persona-load failure, subagent throw, cancellation, or non-zero exit) into
|
|
32
|
+
* a discriminated result. On success returns `kind: "ok"` with the live locals
|
|
33
|
+
* the caller's loop needs for verdict/postflight handling and advance.
|
|
34
|
+
*/
|
|
35
|
+
export async function dispatchPhase(p) {
|
|
36
|
+
const { opts, phase, taskId, cwd, ctx, storeCli, currentPhaseIndex, iterationCounts, dispatchCounts, modelRoutingConfig, registry, cacheSessionId, taskRecordAtStart, } = p;
|
|
37
|
+
const tree = getOrchestratorTree();
|
|
38
|
+
// ── Persona load ──────────────────────────────────────────────
|
|
39
|
+
let persona;
|
|
40
|
+
try {
|
|
41
|
+
persona = loadForgePersona(phase.personaNoun, cwd);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
const e = err;
|
|
45
|
+
ctx.ui.notify(`× forge:run-task — persona '${phase.personaNoun}' not found for phase ${phase.role}: ${e.message ?? "unknown"}. ` +
|
|
46
|
+
"Run /forge:regenerate to materialize persona files.", "error");
|
|
47
|
+
writeState(cwd, {
|
|
48
|
+
taskId,
|
|
49
|
+
phaseIndex: currentPhaseIndex,
|
|
50
|
+
iterationCounts,
|
|
51
|
+
halted: true,
|
|
52
|
+
lastError: `persona load failed: ${e.message ?? "unknown"}`,
|
|
53
|
+
savedAt: new Date().toISOString(),
|
|
54
|
+
});
|
|
55
|
+
return {
|
|
56
|
+
kind: "return",
|
|
57
|
+
result: {
|
|
58
|
+
status: "failed",
|
|
59
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
60
|
+
iterationCounts,
|
|
61
|
+
lastError: `persona load failed: ${e.message ?? "unknown"}`,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// ── 4. Dispatch via runForgeSubagent (IL10) ───────────────────
|
|
66
|
+
// NEVER sendKickoff here — that would reproduce issue #30 (same-context inline = no fork).
|
|
67
|
+
// Read fresh task record to carry forward prior phase summaries (forge-cli#19).
|
|
68
|
+
const taskRecordForSummaries = currentPhaseIndex > 0 ? readTaskRecord(taskId, storeCli, cwd) : null;
|
|
69
|
+
const summariesBlock = buildSummariesBlock(taskRecordForSummaries?.summaries);
|
|
70
|
+
const taskBody = composeTaskBody(p.subWorkflowMd, taskId, summariesBlock || undefined);
|
|
71
|
+
// Log whether carry-forward summaries were injected (forge-cli#19).
|
|
72
|
+
if (summariesBlock) {
|
|
73
|
+
const debugCarryPath = path.join(cwd, ".forge", "cache", `run-task-debug-${taskId}.jsonl`);
|
|
74
|
+
try {
|
|
75
|
+
fs.mkdirSync(path.dirname(debugCarryPath), { recursive: true });
|
|
76
|
+
fs.appendFileSync(debugCarryPath, `${JSON.stringify({ ts: new Date().toISOString(), phase: phase.role, kind: "carry_forward_injected", summariesLength: summariesBlock.length, summariesBlock })}\n`, "utf8");
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
/* best-effort debug log */
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Resolve per-phase model from layered config (Plan 16 Slice 2).
|
|
83
|
+
// Pipeline name "default" matches the Forge plugin's shipped pipeline.
|
|
84
|
+
// When config is absent or cascade bottoms out, resolves to inherit
|
|
85
|
+
// (model: undefined) — setModel is skipped and pi's current model is used.
|
|
86
|
+
const modelResolution = resolveModelForPhase("default", phase.role, phase.personaNoun, modelRoutingConfig);
|
|
87
|
+
const dispatchModelLabel = modelResolution.model
|
|
88
|
+
? `${modelResolution.model.provider}:${modelResolution.model.model}`
|
|
89
|
+
: "inherit";
|
|
90
|
+
ctx.ui.notify(` dispatch: persona=${phase.personaNoun} · model=${dispatchModelLabel} [${modelResolution.source}]`, "info");
|
|
91
|
+
const phaseStart = Date.now();
|
|
92
|
+
// Stabilization debug log — every subagent event appended as JSONL.
|
|
93
|
+
const debugLogPath = path.join(cwd, ".forge", "cache", `run-task-debug-${taskId}.jsonl`);
|
|
94
|
+
const writeDebug = (rec) => {
|
|
95
|
+
try {
|
|
96
|
+
fs.mkdirSync(path.dirname(debugLogPath), { recursive: true });
|
|
97
|
+
fs.appendFileSync(debugLogPath, `${JSON.stringify({ ts: new Date().toISOString(), phase: phase.role, ...rec })}\n`, "utf8");
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// non-fatal; debug log is best-effort
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
writeDebug({ kind: "phase_start", phaseIndex: currentPhaseIndex });
|
|
104
|
+
writeDebug({
|
|
105
|
+
kind: "requested_model",
|
|
106
|
+
requested: modelResolution.model ?? null,
|
|
107
|
+
source: modelResolution.source,
|
|
108
|
+
persona: phase.personaNoun,
|
|
109
|
+
});
|
|
110
|
+
registry.startPhase(taskId, phase.role, currentPhaseIndex);
|
|
111
|
+
// Bridge: register phase in OrchestratorTree. Node identity is
|
|
112
|
+
// per-dispatch (see dispatchCounts above) — never reuse an ID for a
|
|
113
|
+
// re-dispatched role.
|
|
114
|
+
const iteration = (dispatchCounts[phase.role] = (dispatchCounts[phase.role] ?? 0) + 1);
|
|
115
|
+
const phaseNodeId = `${taskId}:${phase.role}:${iteration}`;
|
|
116
|
+
tree.startNode(phaseNodeId, {
|
|
117
|
+
parentId: taskId,
|
|
118
|
+
label: `${phase.role}:${iteration}`,
|
|
119
|
+
kind: "leaf",
|
|
120
|
+
// Full body — display clamping/expansion is the view's decision
|
|
121
|
+
// (the tree applies only a storage cap).
|
|
122
|
+
promptPreview: taskBody,
|
|
123
|
+
});
|
|
124
|
+
// Capture the first stream-observed model on turn_end (IL10 visibility).
|
|
125
|
+
// If pi auto-substitutes or setModel silently no-ops, this line will diverge
|
|
126
|
+
// from requested_model — exactly the diagnostic signal we want.
|
|
127
|
+
let modelObservedLogged = false;
|
|
128
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
129
|
+
const wrappedOnEvent = (event) => {
|
|
130
|
+
if (!modelObservedLogged && event?.type === "turn_end" && typeof event?.message?.model === "string") {
|
|
131
|
+
modelObservedLogged = true;
|
|
132
|
+
writeDebug({
|
|
133
|
+
kind: "model_observed",
|
|
134
|
+
provider: event.message.provider ?? null,
|
|
135
|
+
model: event.message.model,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
observer.onEvent(event);
|
|
139
|
+
};
|
|
140
|
+
const refreshStatus = () => {
|
|
141
|
+
if (process.env.FORGE_VERBOSE !== "1")
|
|
142
|
+
return;
|
|
143
|
+
const elapsed = Math.floor((Date.now() - phaseStart) / 1000);
|
|
144
|
+
const tail = observer.state.lastTool ? ` · ${observer.state.lastTool}` : "";
|
|
145
|
+
ctx.ui.setStatus?.(STATUS_KEY, `run-task ${taskId}: ${phase.role} · t${observer.state.turn} · tools ${observer.state.toolCount}${observer.state.errCount ? ` · err ${observer.state.errCount}` : ""} · ${elapsed}s${tail}`);
|
|
146
|
+
};
|
|
147
|
+
const observer = attachViewportObserver({
|
|
148
|
+
registry,
|
|
149
|
+
sessionId: taskId,
|
|
150
|
+
phaseRole: phase.role,
|
|
151
|
+
nodeId: phaseNodeId,
|
|
152
|
+
beginHeader: `─── phase ${currentPhaseIndex + 1}/${PHASES.length} ${phase.role} begin · ${taskId} ───`,
|
|
153
|
+
writeDebug,
|
|
154
|
+
notify: (msg, level) => ctx.ui.notify(msg, level),
|
|
155
|
+
setStatusVerbose: process.env.FORGE_VERBOSE === "1" ? (k, v) => ctx.ui.setStatus?.(k, v) : undefined,
|
|
156
|
+
verboseKeys: { messageKey: MESSAGE_KEY },
|
|
157
|
+
afterEach: refreshStatus,
|
|
158
|
+
});
|
|
159
|
+
// ── Context governor injection (completes FORGE-S30-T07) ──────
|
|
160
|
+
// Per-phase factories built HERE because only the pipeline knows the
|
|
161
|
+
// `${personaNoun}/${role}` phase key — pi never sets persona/phase on
|
|
162
|
+
// ExtensionContext, and the parent session's registerHookDispatcher
|
|
163
|
+
// governor never sees subagent tool traffic (dormant-governor defect,
|
|
164
|
+
// CART-S02-T03 benchmark). Flag-gated: FORGE_CTX_GOVERNOR=1.
|
|
165
|
+
// buildGovernorFactory — Mechanisms A/B/C/D in the subagent
|
|
166
|
+
// buildForgeCompactionFactory — Mechanism E with warm-tier path opts
|
|
167
|
+
// (previously injected from index.ts with NO opts → warm-tier dead)
|
|
168
|
+
const phaseKey = `${phase.personaNoun}/${phase.role}`;
|
|
169
|
+
// Sprint ID from the task record's sprint FK (the store owns that
|
|
170
|
+
// relationship); the taskId-shape regex is only a fallback for records
|
|
171
|
+
// missing the FK (FORGE-BUG-043 PR 2).
|
|
172
|
+
const sprintIdForSummaries = taskRecordAtStart?.sprintId ?? /^(.*)-T\d+$/.exec(taskId)?.[1];
|
|
173
|
+
const governorFactories = process.env.FORGE_CTX_GOVERNOR === "1"
|
|
174
|
+
? [
|
|
175
|
+
buildGovernorFactory({ phaseKey, cwd }),
|
|
176
|
+
buildForgeCompactionFactory({
|
|
177
|
+
cwd,
|
|
178
|
+
phaseKey,
|
|
179
|
+
entityId: taskId,
|
|
180
|
+
sprintId: sprintIdForSummaries,
|
|
181
|
+
}),
|
|
182
|
+
]
|
|
183
|
+
: [];
|
|
184
|
+
const phaseExtensionFactories = [...(opts.extensionFactories ?? []), ...governorFactories];
|
|
185
|
+
let result;
|
|
186
|
+
try {
|
|
187
|
+
// FORGE-BUG-040: wrap the runForgeSubagent dispatch in the phase
|
|
188
|
+
// caller context (parity with fix-bug.ts) so the phase-ownership
|
|
189
|
+
// guard can verify tool calls from the subagent. Single setter
|
|
190
|
+
// of phase context for the task pipeline.
|
|
191
|
+
result = await CallerContextStore.asSubagent(phase.role, () => runForgeSubagent({
|
|
192
|
+
persona,
|
|
193
|
+
task: taskBody,
|
|
194
|
+
cwd,
|
|
195
|
+
exportTag: `${taskId}__${phase.role}`,
|
|
196
|
+
tailLog: observer.state.tailLog,
|
|
197
|
+
cacheSessionId,
|
|
198
|
+
streamFn: opts.streamFnFactory?.({
|
|
199
|
+
kind: "task-phase",
|
|
200
|
+
persona: persona.name,
|
|
201
|
+
phase: phase.role,
|
|
202
|
+
taskId,
|
|
203
|
+
}),
|
|
204
|
+
onEvent: wrappedOnEvent,
|
|
205
|
+
requestedModel: modelResolution.model,
|
|
206
|
+
modelRegistry: ctx.modelRegistry,
|
|
207
|
+
signal: opts.signal,
|
|
208
|
+
customTools: opts.forgeToolDefs ? getSubagentTools(opts.forgeToolDefs, persona.name) : undefined,
|
|
209
|
+
extensionFactories: phaseExtensionFactories.length > 0 ? phaseExtensionFactories : undefined,
|
|
210
|
+
}));
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
const e = err;
|
|
214
|
+
ctx.ui.notify(`× forge:run-task — runForgeSubagent threw for phase ${phase.role}: ${e.message ?? "unknown"}`, "error");
|
|
215
|
+
tree.completeNode(phaseNodeId, "failed");
|
|
216
|
+
writeState(cwd, {
|
|
217
|
+
taskId,
|
|
218
|
+
phaseIndex: currentPhaseIndex,
|
|
219
|
+
iterationCounts,
|
|
220
|
+
halted: true,
|
|
221
|
+
lastError: `runForgeSubagent threw: ${e.message ?? "unknown"}`,
|
|
222
|
+
savedAt: new Date().toISOString(),
|
|
223
|
+
});
|
|
224
|
+
return {
|
|
225
|
+
kind: "return",
|
|
226
|
+
result: {
|
|
227
|
+
status: "failed",
|
|
228
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
229
|
+
iterationCounts,
|
|
230
|
+
lastError: `runForgeSubagent threw: ${e.message ?? "unknown"}`,
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
// Close this dispatch's tree node with final usage/model — MUST be
|
|
235
|
+
// called on every exit path below (failure, halt, escalation,
|
|
236
|
+
// loopback, advance). A node left `running` keeps a live spinner in
|
|
237
|
+
// the dashboard forever AND absorbs the next same-role dispatch's
|
|
238
|
+
// telemetry via the observer's legacy role-prefix scan.
|
|
239
|
+
const finishPhaseNode = (status) => {
|
|
240
|
+
tree.setNodeUsage(phaseNodeId, {
|
|
241
|
+
input: result.usage.input,
|
|
242
|
+
output: result.usage.output,
|
|
243
|
+
cacheRead: result.usage.cacheRead,
|
|
244
|
+
});
|
|
245
|
+
if (result.model)
|
|
246
|
+
tree.setNodeModel(phaseNodeId, result.model, result.provider ?? "");
|
|
247
|
+
tree.completeNode(phaseNodeId, status);
|
|
248
|
+
};
|
|
249
|
+
// ── Post-subagent abort detection ─────────────────────────────────
|
|
250
|
+
// If the abort signal fired during the subagent run, treat it as
|
|
251
|
+
// cancellation regardless of the exit code (subagent may have been
|
|
252
|
+
// mid-turn when aborted — exitCode could be 0 or 1).
|
|
253
|
+
// This check MUST come before halt-on-failure so that
|
|
254
|
+
// stopReason="aborted" + exitCode=1 is classified as cancellation,
|
|
255
|
+
// not a phase failure.
|
|
256
|
+
if (result.stopReason === "aborted" || opts.signal?.aborted) {
|
|
257
|
+
ctx.ui.notify(`⊘ forge:run-task — ${taskId} phase ${phase.role} cancelled.`, "info");
|
|
258
|
+
registry.completePhase(taskId, phase.role, "cancelled");
|
|
259
|
+
tree.completeNode(phaseNodeId, "cancelled");
|
|
260
|
+
registry.confirmCancelled(taskId);
|
|
261
|
+
// Bug B: account the billed tokens of this aborted attempt before returning.
|
|
262
|
+
{
|
|
263
|
+
const abortSprintId = readTaskRecord(taskId, storeCli, cwd)?.sprintId;
|
|
264
|
+
if (abortSprintId) {
|
|
265
|
+
emitIncompletePhaseEvent({
|
|
266
|
+
emitCtx: {
|
|
267
|
+
entityType: "task",
|
|
268
|
+
taskId,
|
|
269
|
+
sprintId: abortSprintId,
|
|
270
|
+
phase,
|
|
271
|
+
iteration: (iterationCounts[phase.role] ?? 0) + 1,
|
|
272
|
+
startMs: phaseStart,
|
|
273
|
+
endMs: Date.now(),
|
|
274
|
+
model: result.model ?? "unknown",
|
|
275
|
+
provider: result.provider ?? "unknown",
|
|
276
|
+
usage: {
|
|
277
|
+
input: result.usage.input,
|
|
278
|
+
output: result.usage.output,
|
|
279
|
+
cacheRead: result.usage.cacheRead,
|
|
280
|
+
cacheWrite: result.usage.cacheWrite,
|
|
281
|
+
},
|
|
282
|
+
judgement: undefined,
|
|
283
|
+
storeCli,
|
|
284
|
+
cwd,
|
|
285
|
+
},
|
|
286
|
+
outcome: "aborted",
|
|
287
|
+
notes: result.errorMessage ?? result.stopReason ?? undefined,
|
|
288
|
+
onDebug: writeDebug,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
writeDebug({ kind: "incomplete_emit_skipped", reason: "no-sprintId", outcome: "aborted" });
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// ADR-S21-01: preserve state file so cancelled runs are resumable
|
|
296
|
+
writeState(cwd, {
|
|
297
|
+
taskId,
|
|
298
|
+
phaseIndex: currentPhaseIndex,
|
|
299
|
+
iterationCounts,
|
|
300
|
+
halted: false,
|
|
301
|
+
status: "cancelled",
|
|
302
|
+
lastError: undefined,
|
|
303
|
+
savedAt: new Date().toISOString(),
|
|
304
|
+
});
|
|
305
|
+
return {
|
|
306
|
+
kind: "return",
|
|
307
|
+
result: { status: "cancelled", lastPhaseIndex: currentPhaseIndex, iterationCounts },
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
// ── Halt-on-failure ───────────────────────────────────────────
|
|
311
|
+
if (result.exitCode !== 0) {
|
|
312
|
+
ctx.ui.notify(`× forge:run-task — phase ${phase.role} failed (exit ${result.exitCode})` +
|
|
313
|
+
(result.errorMessage ? `: ${result.errorMessage}` : "") +
|
|
314
|
+
(result.stopReason ? ` [${result.stopReason}]` : ""), "error");
|
|
315
|
+
finishPhaseNode("failed");
|
|
316
|
+
// Bug B: account the billed tokens of this failed attempt before returning.
|
|
317
|
+
{
|
|
318
|
+
const failSprintId = readTaskRecord(taskId, storeCli, cwd)?.sprintId;
|
|
319
|
+
if (failSprintId) {
|
|
320
|
+
emitIncompletePhaseEvent({
|
|
321
|
+
emitCtx: {
|
|
322
|
+
entityType: "task",
|
|
323
|
+
taskId,
|
|
324
|
+
sprintId: failSprintId,
|
|
325
|
+
phase,
|
|
326
|
+
iteration: (iterationCounts[phase.role] ?? 0) + 1,
|
|
327
|
+
startMs: phaseStart,
|
|
328
|
+
endMs: Date.now(),
|
|
329
|
+
model: result.model ?? "unknown",
|
|
330
|
+
provider: result.provider ?? "unknown",
|
|
331
|
+
usage: {
|
|
332
|
+
input: result.usage.input,
|
|
333
|
+
output: result.usage.output,
|
|
334
|
+
cacheRead: result.usage.cacheRead,
|
|
335
|
+
cacheWrite: result.usage.cacheWrite,
|
|
336
|
+
},
|
|
337
|
+
judgement: undefined,
|
|
338
|
+
storeCli,
|
|
339
|
+
cwd,
|
|
340
|
+
},
|
|
341
|
+
outcome: "failed",
|
|
342
|
+
notes: result.errorMessage ?? result.stopReason ?? undefined,
|
|
343
|
+
onDebug: writeDebug,
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
else {
|
|
347
|
+
writeDebug({ kind: "incomplete_emit_skipped", reason: "no-sprintId", outcome: "failed" });
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
writeState(cwd, {
|
|
351
|
+
taskId,
|
|
352
|
+
phaseIndex: currentPhaseIndex,
|
|
353
|
+
iterationCounts,
|
|
354
|
+
halted: true,
|
|
355
|
+
lastError: result.errorMessage ?? result.stopReason ?? "subagent exit non-zero",
|
|
356
|
+
savedAt: new Date().toISOString(),
|
|
357
|
+
});
|
|
358
|
+
return {
|
|
359
|
+
kind: "return",
|
|
360
|
+
result: {
|
|
361
|
+
status: "failed",
|
|
362
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
363
|
+
iterationCounts,
|
|
364
|
+
lastError: result.errorMessage ?? result.stopReason ?? "subagent exit non-zero",
|
|
365
|
+
},
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
return { kind: "ok", result, finishPhaseNode, observer, phaseStart, writeDebug };
|
|
369
|
+
}
|
|
370
|
+
//# sourceMappingURL=task-phase-dispatch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-phase-dispatch.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/orchestrators/task/task-phase-dispatch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface PhaseDescriptor {
|
|
2
|
+
/** Workflow role name (also used as key for summaries and iteration tracking). */
|
|
3
|
+
role: string;
|
|
4
|
+
/** Filename under .forge/workflows/ (without extension). */
|
|
5
|
+
workflowFile: string;
|
|
6
|
+
/** Persona noun passed to loadForgePersona. */
|
|
7
|
+
personaNoun: string;
|
|
8
|
+
/** When true: read summaries.<role>.verdict after dispatch. */
|
|
9
|
+
isReview: boolean;
|
|
10
|
+
/** Max revision iterations before escalation. */
|
|
11
|
+
maxIterations: number;
|
|
12
|
+
}
|
|
13
|
+
export declare const PHASES: PhaseDescriptor[];
|
|
14
|
+
export declare const SUMMARY_KEY_BY_ROLE: Record<string, string | null>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// task-phases.ts — phase descriptor table for the /forge:run-task pipeline.
|
|
2
|
+
// Extracted from run-task.ts (no logic changes). run-task.ts re-exports these.
|
|
3
|
+
export const PHASES = [
|
|
4
|
+
{ role: "plan", workflowFile: "plan_task", personaNoun: "engineer", isReview: false, maxIterations: 1 },
|
|
5
|
+
{ role: "review-plan", workflowFile: "review_plan", personaNoun: "supervisor", isReview: true, maxIterations: 3 },
|
|
6
|
+
{ role: "implement", workflowFile: "implement_plan", personaNoun: "engineer", isReview: false, maxIterations: 1 },
|
|
7
|
+
{ role: "review-code", workflowFile: "review_code", personaNoun: "supervisor", isReview: true, maxIterations: 3 },
|
|
8
|
+
{ role: "validate", workflowFile: "validate_task", personaNoun: "qa-engineer", isReview: true, maxIterations: 3 },
|
|
9
|
+
{ role: "approve", workflowFile: "architect_approve", personaNoun: "architect", isReview: true, maxIterations: 3 },
|
|
10
|
+
{ role: "writeback", workflowFile: "collator_agent", personaNoun: "collator", isReview: false, maxIterations: 1 },
|
|
11
|
+
{ role: "commit", workflowFile: "commit_task", personaNoun: "engineer", isReview: false, maxIterations: 1 },
|
|
12
|
+
];
|
|
13
|
+
// Map phase.role → canonical summary key written by base-pack workflows
|
|
14
|
+
// (see forge/forge/tools/store-cli.cjs VALID_SUMMARY_PHASES). Phases whose
|
|
15
|
+
// workflows do not write a summaries entry (e.g. approve, which transitions
|
|
16
|
+
// task.status=approved instead) map to null and are verdict-checked via
|
|
17
|
+
// task status rather than the summaries map.
|
|
18
|
+
export const SUMMARY_KEY_BY_ROLE = {
|
|
19
|
+
plan: "plan",
|
|
20
|
+
"review-plan": "review_plan",
|
|
21
|
+
implement: "implementation",
|
|
22
|
+
"review-code": "code_review",
|
|
23
|
+
validate: "validation",
|
|
24
|
+
approve: null,
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=task-phases.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-phases.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/orchestrators/task/task-phases.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,+EAA+E;AAoB/E,MAAM,CAAC,MAAM,MAAM,GAAsB;IACxC,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;IACvG,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,UAAU,EAAE,YAAY,EAAE,eAAe,EAAE,WAAW,EAAE,aAAa,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,WAAW,EAAE,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;IACjH,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE;CAC3G,CAAC;AAEF,wEAAwE;AACxE,2EAA2E;AAC3E,4EAA4E;AAC5E,wEAAwE;AACxE,6CAA6C;AAC7C,MAAM,CAAC,MAAM,mBAAmB,GAAkC;IACjE,IAAI,EAAE,MAAM;IACZ,aAAa,EAAE,aAAa;IAC5B,SAAS,EAAE,gBAAgB;IAC3B,aAAa,EAAE,aAAa;IAC5B,QAAQ,EAAE,YAAY;IACtB,OAAO,EAAE,IAAI;CACb,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
type Verdict = "approved" | "revision" | "n/a" | "missing";
|
|
2
|
+
export declare function readVerdict(taskId: string, phaseRole: string, storeCli: string, cwd: string): Verdict;
|
|
3
|
+
export interface TaskRecord {
|
|
4
|
+
sprintId?: string;
|
|
5
|
+
status?: string;
|
|
6
|
+
summaries?: Record<string, unknown>;
|
|
7
|
+
}
|
|
8
|
+
export declare function readTaskRecord(taskId: string, storeCli: string, cwd: string): TaskRecord | null;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// task-record.ts — store-cli verdict + task-record reads for the run-task
|
|
2
|
+
// pipeline. Extracted from run-task.ts (no logic changes). run-task.ts
|
|
3
|
+
// re-exports these.
|
|
4
|
+
import { spawnSync } from "node:child_process";
|
|
5
|
+
import { SUMMARY_KEY_BY_ROLE } from "./task-phases.js";
|
|
6
|
+
export function readVerdict(taskId, phaseRole, storeCli, cwd) {
|
|
7
|
+
const result = spawnSync("node", [storeCli, "read", "task", taskId], { cwd, encoding: "utf8" });
|
|
8
|
+
if (result.status !== 0)
|
|
9
|
+
return "missing";
|
|
10
|
+
try {
|
|
11
|
+
const raw = typeof result.stdout === "string" ? result.stdout : String(result.stdout);
|
|
12
|
+
const record = JSON.parse(raw);
|
|
13
|
+
// Phases like `approve` do not write a summaries entry; they
|
|
14
|
+
// transition task.status to "approved" instead. For those, the
|
|
15
|
+
// verdict source is task.status.
|
|
16
|
+
const summaryKey = SUMMARY_KEY_BY_ROLE[phaseRole];
|
|
17
|
+
if (summaryKey === null) {
|
|
18
|
+
return record.status === "approved" ? "approved" : "missing";
|
|
19
|
+
}
|
|
20
|
+
// Verdict lookup with three fallbacks:
|
|
21
|
+
// 1. Canonical mapped summary key (e.g. "code_review" for review-code).
|
|
22
|
+
// 2. Underscore-swapped phase role ("review_code") — legacy/defensive.
|
|
23
|
+
// 3. Raw hyphenated phase role ("review-code") — defensive only.
|
|
24
|
+
const summaries = record.summaries ?? {};
|
|
25
|
+
const underscoreKey = phaseRole.replace(/-/g, "_");
|
|
26
|
+
const candidates = [summaryKey ?? "", underscoreKey, phaseRole].filter(Boolean);
|
|
27
|
+
let verdict;
|
|
28
|
+
for (const k of candidates) {
|
|
29
|
+
if (summaries[k]?.verdict) {
|
|
30
|
+
verdict = summaries[k].verdict;
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (!verdict)
|
|
35
|
+
return "missing";
|
|
36
|
+
if (verdict === "approved")
|
|
37
|
+
return "approved";
|
|
38
|
+
if (verdict === "revision")
|
|
39
|
+
return "revision";
|
|
40
|
+
return "missing";
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return "missing";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
export function readTaskRecord(taskId, storeCli, cwd) {
|
|
47
|
+
const result = spawnSync("node", [storeCli, "read", "task", taskId], { cwd, encoding: "utf8" });
|
|
48
|
+
if (result.status !== 0)
|
|
49
|
+
return null;
|
|
50
|
+
try {
|
|
51
|
+
const raw = typeof result.stdout === "string" ? result.stdout : String(result.stdout);
|
|
52
|
+
return JSON.parse(raw);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=task-record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-record.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/orchestrators/task/task-record.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,uEAAuE;AACvE,oBAAoB;AAEpB,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAMvD,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,SAAiB,EAAE,QAAgB,EAAE,GAAW;IAC3F,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAChG,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC1C,IAAI,CAAC;QACJ,MAAM,GAAG,GAAW,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9F,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAG5B,CAAC;QAEF,6DAA6D;QAC7D,+DAA+D;QAC/D,iCAAiC;QACjC,MAAM,UAAU,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAClD,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;YACzB,OAAO,MAAM,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9D,CAAC;QAED,uCAAuC;QACvC,0EAA0E;QAC1E,yEAAyE;QACzE,mEAAmE;QACnE,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;QACzC,MAAM,aAAa,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACnD,MAAM,UAAU,GAAG,CAAC,UAAU,IAAI,EAAE,EAAE,aAAa,EAAE,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAChF,IAAI,OAA2B,CAAC;QAChC,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;YAC5B,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;gBAC3B,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;gBAC/B,MAAM;YACP,CAAC;QACF,CAAC;QACD,IAAI,CAAC,OAAO;YAAE,OAAO,SAAS,CAAC;QAC/B,IAAI,OAAO,KAAK,UAAU;YAAE,OAAO,UAAU,CAAC;QAC9C,IAAI,OAAO,KAAK,UAAU;YAAE,OAAO,UAAU,CAAC;QAC9C,OAAO,SAAS,CAAC;IAClB,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAUD,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,QAAgB,EAAE,GAAW;IAC3E,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IAChG,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACrC,IAAI,CAAC;QACJ,MAAM,GAAG,GAAW,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9F,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAe,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC;IACb,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface RunTaskState {
|
|
2
|
+
taskId: string;
|
|
3
|
+
phaseIndex: number;
|
|
4
|
+
iterationCounts: Record<string, number>;
|
|
5
|
+
halted: boolean;
|
|
6
|
+
/** Set on cancellation so the resume prompt can say "cancelled" vs "halted". */
|
|
7
|
+
status?: "cancelled" | "halted" | "running";
|
|
8
|
+
lastError?: string;
|
|
9
|
+
savedAt: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function readState(cwd: string, taskId: string): RunTaskState | null;
|
|
12
|
+
export declare function writeState(cwd: string, state: RunTaskState): void;
|
|
13
|
+
export declare function deleteState(cwd: string, taskId: string): void;
|
|
14
|
+
export declare function isStateStale(state: RunTaskState): boolean;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// task-state.ts — run-task state persistence. Extracted from run-task.ts
|
|
2
|
+
// (no logic changes). run-task.ts re-exports these; run-sprint.ts imports
|
|
3
|
+
// readState as readTaskState from the barrel.
|
|
4
|
+
import * as fs from "node:fs";
|
|
5
|
+
import { isStateStale as isJsonStateStale, readJsonState, taskStateFilePath, writeJsonState, } from "../../lib/state-helpers.js";
|
|
6
|
+
import { validateId } from "../common/orchestrator-misc.js";
|
|
7
|
+
// FORGE-S25-T16 (N-H-B): state helpers delegate to lib/state-helpers.ts.
|
|
8
|
+
// Public API (readState, writeState, deleteState, isStateStale) is preserved —
|
|
9
|
+
// run-sprint.ts imports readState as readTaskState from this file.
|
|
10
|
+
function stateFilePath(cwd, taskId) {
|
|
11
|
+
if (!validateId(taskId)) {
|
|
12
|
+
throw new Error(`Invalid taskId for state file path: ${taskId}`);
|
|
13
|
+
}
|
|
14
|
+
return taskStateFilePath(cwd, taskId);
|
|
15
|
+
}
|
|
16
|
+
export function readState(cwd, taskId) {
|
|
17
|
+
return readJsonState(stateFilePath(cwd, taskId));
|
|
18
|
+
}
|
|
19
|
+
export function writeState(cwd, state) {
|
|
20
|
+
writeJsonState(stateFilePath(cwd, state.taskId), state);
|
|
21
|
+
}
|
|
22
|
+
export function deleteState(cwd, taskId) {
|
|
23
|
+
const fp = stateFilePath(cwd, taskId);
|
|
24
|
+
try {
|
|
25
|
+
if (fs.existsSync(fp))
|
|
26
|
+
fs.unlinkSync(fp);
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
// non-fatal
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function isStateStale(state) {
|
|
33
|
+
return isJsonStateStale(state.savedAt);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=task-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task-state.js","sourceRoot":"","sources":["../../../../../src/extensions/forgecli/orchestrators/task/task-state.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,0EAA0E;AAC1E,8CAA8C;AAE9C,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAE9B,OAAO,EACN,YAAY,IAAI,gBAAgB,EAChC,aAAa,EACb,iBAAiB,EACjB,cAAc,GACd,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAe5D,yEAAyE;AACzE,+EAA+E;AAC/E,mEAAmE;AAEnE,SAAS,aAAa,CAAC,GAAW,EAAE,MAAc;IACjD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,uCAAuC,MAAM,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,iBAAiB,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,MAAc;IACpD,OAAO,aAAa,CAAe,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,KAAmB;IAC1D,cAAc,CAAC,aAAa,CAAC,GAAG,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,MAAc;IACtD,MAAM,EAAE,GAAG,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACtC,IAAI,CAAC;QACJ,IAAI,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC;YAAE,EAAE,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACR,YAAY;IACb,CAAC;AACF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAmB;IAC/C,OAAO,gBAAgB,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
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 "./task-phases.js";
|
|
5
|
+
import type { RunTaskPipelineResult } from "./run-task-types.js";
|
|
6
|
+
export type VerdictLoopOutcome = {
|
|
7
|
+
kind: "advance";
|
|
8
|
+
} | {
|
|
9
|
+
kind: "loopback";
|
|
10
|
+
toIndex: number;
|
|
11
|
+
} | {
|
|
12
|
+
kind: "return";
|
|
13
|
+
result: RunTaskPipelineResult;
|
|
14
|
+
};
|
|
15
|
+
export interface VerdictLoopParams {
|
|
16
|
+
phase: PhaseDescriptor;
|
|
17
|
+
taskId: 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
|
+
/** Closure that finalizes this dispatch's OrchestratorTree node. */
|
|
27
|
+
finishPhaseNode: (status: "completed" | "failed" | "escalated") => void;
|
|
28
|
+
/** Per-phase completion-recovery guard (forge-engineering#41) — roles that
|
|
29
|
+
* already consumed their one set-summary recovery attempt this run. */
|
|
30
|
+
recoveredPhases: Set<string>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Evaluate the review-phase verdict and decide the loop's next move.
|
|
34
|
+
* Mirrors the inline block that previously lived in runTaskPipelineInner.
|
|
35
|
+
*/
|
|
36
|
+
export declare function handleReviewVerdict(p: VerdictLoopParams): VerdictLoopOutcome;
|