@entelligentsia/forgecli 0.19.0 → 0.20.3
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 +90 -0
- package/dist/bin/config.js +9 -9
- package/dist/bin/config.js.map +1 -1
- package/dist/bin/forge.js +3 -3
- package/dist/bin/forge.js.map +1 -1
- package/dist/bin/update-cli.js +2 -1
- package/dist/bin/update-cli.js.map +1 -1
- package/dist/extensions/forgecli/add-pipeline.js.map +1 -1
- package/dist/extensions/forgecli/add-task.js.map +1 -1
- package/dist/extensions/forgecli/approve.d.ts +2 -2
- package/dist/extensions/forgecli/approve.js +2 -2
- package/dist/extensions/forgecli/approve.js.map +1 -1
- package/dist/extensions/forgecli/ask-user-tool.js.map +1 -1
- package/dist/extensions/forgecli/audience-gate.js.map +1 -1
- package/dist/extensions/forgecli/calibrate.d.ts +1 -1
- package/dist/extensions/forgecli/calibrate.js +8 -10
- package/dist/extensions/forgecli/calibrate.js.map +1 -1
- package/dist/extensions/forgecli/collate.d.ts +2 -2
- package/dist/extensions/forgecli/collate.js +2 -2
- package/dist/extensions/forgecli/collate.js.map +1 -1
- package/dist/extensions/forgecli/commit.d.ts +2 -2
- package/dist/extensions/forgecli/commit.js +2 -2
- package/dist/extensions/forgecli/commit.js.map +1 -1
- package/dist/extensions/forgecli/config-command.js.map +1 -1
- package/dist/extensions/forgecli/config-layer.js +4 -2
- package/dist/extensions/forgecli/config-layer.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/component.d.ts +1 -1
- package/dist/extensions/forgecli/config-tui/component.js +25 -21
- package/dist/extensions/forgecli/config-tui/component.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/handler.js +2 -6
- package/dist/extensions/forgecli/config-tui/handler.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/keys.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/plugin-config-reader.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/screens/advanced-menu.d.ts +2 -2
- package/dist/extensions/forgecli/config-tui/screens/advanced-menu.js +10 -8
- package/dist/extensions/forgecli/config-tui/screens/advanced-menu.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/screens/confirm-quit.d.ts +2 -2
- package/dist/extensions/forgecli/config-tui/screens/confirm-quit.js +2 -5
- package/dist/extensions/forgecli/config-tui/screens/confirm-quit.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/screens/override-editor.d.ts +2 -2
- package/dist/extensions/forgecli/config-tui/screens/override-editor.js +15 -11
- package/dist/extensions/forgecli/config-tui/screens/override-editor.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/screens/overrides-list-phases.d.ts +2 -2
- package/dist/extensions/forgecli/config-tui/screens/overrides-list-phases.js +15 -11
- package/dist/extensions/forgecli/config-tui/screens/overrides-list-phases.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/screens/overrides-list.d.ts +2 -2
- package/dist/extensions/forgecli/config-tui/screens/overrides-list.js +7 -4
- package/dist/extensions/forgecli/config-tui/screens/overrides-list.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/screens/persona-editor.d.ts +2 -2
- package/dist/extensions/forgecli/config-tui/screens/persona-editor.js +6 -12
- package/dist/extensions/forgecli/config-tui/screens/persona-editor.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/screens/persona-picker.d.ts +2 -2
- package/dist/extensions/forgecli/config-tui/screens/persona-picker.js +3 -6
- package/dist/extensions/forgecli/config-tui/screens/persona-picker.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/screens/personas-list.d.ts +2 -2
- package/dist/extensions/forgecli/config-tui/screens/personas-list.js +2 -2
- package/dist/extensions/forgecli/config-tui/screens/personas-list.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/screens/shared.d.ts +1 -1
- package/dist/extensions/forgecli/config-tui/screens/shared.js +4 -5
- package/dist/extensions/forgecli/config-tui/screens/shared.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/screens/show-resolved.d.ts +2 -2
- package/dist/extensions/forgecli/config-tui/screens/show-resolved.js +9 -11
- package/dist/extensions/forgecli/config-tui/screens/show-resolved.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/screens/tier-menu.d.ts +2 -2
- package/dist/extensions/forgecli/config-tui/screens/tier-menu.js +2 -2
- package/dist/extensions/forgecli/config-tui/screens/tier-menu.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/screens/tier-picker.d.ts +2 -2
- package/dist/extensions/forgecli/config-tui/screens/tier-picker.js +12 -3
- package/dist/extensions/forgecli/config-tui/screens/tier-picker.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/screens/types.d.ts +1 -1
- package/dist/extensions/forgecli/config-tui/screens.d.ts +10 -10
- package/dist/extensions/forgecli/config-tui/screens.js +16 -16
- package/dist/extensions/forgecli/config-tui/screens.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/state/buffer.d.ts +2 -2
- package/dist/extensions/forgecli/config-tui/state/buffer.js +1 -2
- package/dist/extensions/forgecli/config-tui/state/buffer.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/state/constants.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/state/index.d.ts +3 -3
- package/dist/extensions/forgecli/config-tui/state/index.js +2 -2
- package/dist/extensions/forgecli/config-tui/state/index.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/state/init.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/state/reducer.js +2 -4
- package/dist/extensions/forgecli/config-tui/state/reducer.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/state/selectors.d.ts +1 -1
- package/dist/extensions/forgecli/config-tui/state/selectors.js +7 -6
- package/dist/extensions/forgecli/config-tui/state/selectors.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/state.d.ts +3 -3
- package/dist/extensions/forgecli/config-tui/state.js +2 -2
- package/dist/extensions/forgecli/config-tui/state.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/theme.js +1 -1
- package/dist/extensions/forgecli/config-tui/theme.js.map +1 -1
- package/dist/extensions/forgecli/config-tui/tier-meta.js.map +1 -1
- package/dist/extensions/forgecli/config-writer.js +4 -2
- package/dist/extensions/forgecli/config-writer.js.map +1 -1
- package/dist/extensions/forgecli/enhance.d.ts +2 -2
- package/dist/extensions/forgecli/enhance.js +3 -3
- package/dist/extensions/forgecli/enhance.js.map +1 -1
- package/dist/extensions/forgecli/fix-bug.d.ts +1 -1
- package/dist/extensions/forgecli/fix-bug.js +148 -58
- package/dist/extensions/forgecli/fix-bug.js.map +1 -1
- package/dist/extensions/forgecli/forge-artifact-tool.d.ts +8 -1
- package/dist/extensions/forgecli/forge-artifact-tool.js +85 -15
- package/dist/extensions/forgecli/forge-artifact-tool.js.map +1 -1
- package/dist/extensions/forgecli/forge-commands.js.map +1 -1
- package/dist/extensions/forgecli/forge-header.d.ts +1 -1
- package/dist/extensions/forgecli/forge-header.js +1 -1
- package/dist/extensions/forgecli/forge-header.js.map +1 -1
- package/dist/extensions/forgecli/forge-init/phase-descriptors.js +14 -5
- package/dist/extensions/forgecli/forge-init/phase-descriptors.js.map +1 -1
- package/dist/extensions/forgecli/forge-init/phase4-register.js +20 -1
- package/dist/extensions/forgecli/forge-init/phase4-register.js.map +1 -1
- package/dist/extensions/forgecli/forge-init.js +5 -7
- package/dist/extensions/forgecli/forge-init.js.map +1 -1
- package/dist/extensions/forgecli/forge-subagent.d.ts +1 -1
- package/dist/extensions/forgecli/forge-subagent.js +4 -2
- package/dist/extensions/forgecli/forge-subagent.js.map +1 -1
- package/dist/extensions/forgecli/forge-tools.js +10 -4
- package/dist/extensions/forgecli/forge-tools.js.map +1 -1
- package/dist/extensions/forgecli/forge-update-command.d.ts +32 -11
- package/dist/extensions/forgecli/forge-update-command.js +207 -155
- package/dist/extensions/forgecli/forge-update-command.js.map +1 -1
- package/dist/extensions/forgecli/friction-emit.js +3 -5
- package/dist/extensions/forgecli/friction-emit.js.map +1 -1
- package/dist/extensions/forgecli/health-check.js +10 -6
- package/dist/extensions/forgecli/health-check.js.map +1 -1
- package/dist/extensions/forgecli/hook-dispatcher.js +2 -2
- package/dist/extensions/forgecli/hook-dispatcher.js.map +1 -1
- package/dist/extensions/forgecli/hooks/check-update.js.map +1 -1
- package/dist/extensions/forgecli/hooks/forge-permissions.js.map +1 -1
- package/dist/extensions/forgecli/hooks/post-init-hook.js +1 -1
- package/dist/extensions/forgecli/hooks/post-init-hook.js.map +1 -1
- package/dist/extensions/forgecli/hooks/post-sprint-hook.js +1 -1
- package/dist/extensions/forgecli/hooks/post-sprint-hook.js.map +1 -1
- package/dist/extensions/forgecli/hooks/write-guard.js +5 -3
- package/dist/extensions/forgecli/hooks/write-guard.js.map +1 -1
- package/dist/extensions/forgecli/implement.d.ts +2 -2
- package/dist/extensions/forgecli/implement.js +2 -2
- package/dist/extensions/forgecli/implement.js.map +1 -1
- package/dist/extensions/forgecli/index.js +47 -41
- package/dist/extensions/forgecli/index.js.map +1 -1
- package/dist/extensions/forgecli/input-router.js +4 -1
- package/dist/extensions/forgecli/input-router.js.map +1 -1
- package/dist/extensions/forgecli/lib/catalog-helpers.js +2 -1
- package/dist/extensions/forgecli/lib/catalog-helpers.js.map +1 -1
- package/dist/extensions/forgecli/lib/catalog-loader.js.map +1 -1
- package/dist/extensions/forgecli/lib/catalog-types.js +1 -6
- package/dist/extensions/forgecli/lib/catalog-types.js.map +1 -1
- package/dist/extensions/forgecli/lib/exec-helpers.js +1 -1
- package/dist/extensions/forgecli/lib/exec-helpers.js.map +1 -1
- package/dist/extensions/forgecli/lib/forge-config.js.map +1 -1
- package/dist/extensions/forgecli/lib/orchestrator-preflight.js.map +1 -1
- package/dist/extensions/forgecli/lib/parsers.js.map +1 -1
- package/dist/extensions/forgecli/lib/spawn-store-cli.js +17 -7
- package/dist/extensions/forgecli/lib/spawn-store-cli.js.map +1 -1
- package/dist/extensions/forgecli/materialize.js.map +1 -1
- package/dist/extensions/forgecli/migrate.js +1 -1
- package/dist/extensions/forgecli/migrate.js.map +1 -1
- package/dist/extensions/forgecli/migration-engine.js +3 -6
- package/dist/extensions/forgecli/migration-engine.js.map +1 -1
- package/dist/extensions/forgecli/model-resolver.js.map +1 -1
- package/dist/extensions/forgecli/model-validator.js.map +1 -1
- package/dist/extensions/forgecli/parsers/persona-skill-loader.js +1 -1
- package/dist/extensions/forgecli/parsers/workflow-loader.js +2 -6
- package/dist/extensions/forgecli/parsers/workflow-loader.js.map +1 -1
- package/dist/extensions/forgecli/paths/migrator.js +2 -7
- package/dist/extensions/forgecli/paths/migrator.js.map +1 -1
- package/dist/extensions/forgecli/plan.d.ts +2 -2
- package/dist/extensions/forgecli/plan.js +2 -2
- package/dist/extensions/forgecli/plan.js.map +1 -1
- package/dist/extensions/forgecli/quiz-agent.js.map +1 -1
- package/dist/extensions/forgecli/read-command.js +1 -1
- package/dist/extensions/forgecli/read-command.js.map +1 -1
- package/dist/extensions/forgecli/regenerate.js +1 -3
- package/dist/extensions/forgecli/regenerate.js.map +1 -1
- package/dist/extensions/forgecli/remove-command.js.map +1 -1
- package/dist/extensions/forgecli/report-bug.js +2 -2
- package/dist/extensions/forgecli/report-bug.js.map +1 -1
- package/dist/extensions/forgecli/retrospective.js +2 -2
- package/dist/extensions/forgecli/retrospective.js.map +1 -1
- package/dist/extensions/forgecli/review-code.d.ts +2 -2
- package/dist/extensions/forgecli/review-code.js +2 -2
- package/dist/extensions/forgecli/review-code.js.map +1 -1
- package/dist/extensions/forgecli/review-plan.d.ts +2 -2
- package/dist/extensions/forgecli/review-plan.js +2 -2
- package/dist/extensions/forgecli/review-plan.js.map +1 -1
- package/dist/extensions/forgecli/review-server.js +3 -5
- package/dist/extensions/forgecli/review-server.js.map +1 -1
- package/dist/extensions/forgecli/run-sprint.d.ts +1 -1
- package/dist/extensions/forgecli/run-sprint.js +27 -21
- package/dist/extensions/forgecli/run-sprint.js.map +1 -1
- package/dist/extensions/forgecli/run-task.js +102 -42
- package/dist/extensions/forgecli/run-task.js.map +1 -1
- package/dist/extensions/forgecli/session-registry.js.map +1 -1
- package/dist/extensions/forgecli/skill-curator-subagent.js +4 -8
- package/dist/extensions/forgecli/skill-curator-subagent.js.map +1 -1
- package/dist/extensions/forgecli/skill-retriever.js +1 -1
- package/dist/extensions/forgecli/skill-retriever.js.map +1 -1
- package/dist/extensions/forgecli/skill-usage-tracker.js +1 -1
- package/dist/extensions/forgecli/skill-usage-tracker.js.map +1 -1
- package/dist/extensions/forgecli/status-command.js.map +1 -1
- package/dist/extensions/forgecli/store-error-remediation.js +16 -8
- package/dist/extensions/forgecli/store-error-remediation.js.map +1 -1
- package/dist/extensions/forgecli/store-query.js.map +1 -1
- package/dist/extensions/forgecli/store-repair.js.map +1 -1
- package/dist/extensions/forgecli/store-resolver.js +1 -1
- package/dist/extensions/forgecli/store-resolver.js.map +1 -1
- package/dist/extensions/forgecli/store-validator.js +1 -1
- package/dist/extensions/forgecli/store-validator.js.map +1 -1
- package/dist/extensions/forgecli/subagent/agents.js +1 -1
- package/dist/extensions/forgecli/subagent/agents.js.map +1 -1
- package/dist/extensions/forgecli/subagent/index.js +1 -1
- package/dist/extensions/forgecli/subagent/index.js.map +1 -1
- package/dist/extensions/forgecli/test-orchestrate.js +1 -1
- package/dist/extensions/forgecli/test-orchestrate.js.map +1 -1
- package/dist/extensions/forgecli/thread-switcher.js +8 -18
- package/dist/extensions/forgecli/thread-switcher.js.map +1 -1
- package/dist/extensions/forgecli/transition-guard.js +1 -1
- package/dist/extensions/forgecli/transition-guard.js.map +1 -1
- package/dist/extensions/forgecli/update-tools.js +1 -2
- package/dist/extensions/forgecli/update-tools.js.map +1 -1
- package/dist/extensions/forgecli/validate.d.ts +2 -2
- package/dist/extensions/forgecli/validate.js +2 -2
- package/dist/extensions/forgecli/validate.js.map +1 -1
- package/dist/extensions/forgecli/viewport-events.js +2 -2
- package/dist/extensions/forgecli/viewport-events.js.map +1 -1
- package/dist/extensions/forgecli/wf-engine/engine.d.ts +1 -1
- package/dist/extensions/forgecli/wf-engine/engine.js +51 -31
- package/dist/extensions/forgecli/wf-engine/engine.js.map +1 -1
- package/dist/extensions/forgecli/wf-engine/event-parser.js.map +1 -1
- package/dist/extensions/forgecli/wf-engine/id-gen.js +4 -1
- package/dist/extensions/forgecli/wf-engine/id-gen.js.map +1 -1
- package/dist/extensions/forgecli/wf-engine/loader.js +7 -7
- package/dist/extensions/forgecli/wf-engine/loader.js.map +1 -1
- package/dist/extensions/forgecli/wf-engine/predicate.js +14 -7
- package/dist/extensions/forgecli/wf-engine/predicate.js.map +1 -1
- package/dist/extensions/forgecli/wf-engine/prompt-compiler.js.map +1 -1
- package/dist/extensions/forgecli/wf-engine/register.js +1 -1
- package/dist/extensions/forgecli/wf-engine/register.js.map +1 -1
- package/dist/extensions/forgecli/wf-engine/remit-check.js +3 -3
- package/dist/extensions/forgecli/wf-engine/remit-check.js.map +1 -1
- package/dist/extensions/forgecli/wf-engine/state-store.js +7 -3
- package/dist/extensions/forgecli/wf-engine/state-store.js.map +1 -1
- package/dist/extensions/forgecli/wf-engine/worker.js +3 -3
- package/dist/extensions/forgecli/wf-engine/worker.js.map +1 -1
- package/dist/extensions/forgecli/whats-new-widget.js +8 -6
- package/dist/extensions/forgecli/whats-new-widget.js.map +1 -1
- package/dist/extensions/forgecli/whats-new.js +1 -2
- package/dist/extensions/forgecli/whats-new.js.map +1 -1
- package/dist/forge-payload/commands/update.md +23 -1
- package/dist/forge-payload/schemas/_defs/phaseSummary.schema.json +18 -0
- package/dist/forge-payload/schemas/bug.schema.json +40 -0
- package/dist/forge-payload/schemas/collation-state.schema.json +16 -0
- package/dist/forge-payload/schemas/config.schema.json +215 -0
- package/dist/forge-payload/schemas/enum-catalog.json +71 -0
- package/dist/forge-payload/schemas/event-sidecar.schema.json +22 -0
- package/dist/forge-payload/schemas/event.schema.json +184 -0
- package/dist/forge-payload/schemas/feature.schema.json +22 -0
- package/dist/forge-payload/schemas/progress-entry.schema.json +16 -0
- package/dist/forge-payload/schemas/project-context.schema.json +167 -0
- package/dist/forge-payload/schemas/project-overlay.schema.json +25 -0
- package/dist/forge-payload/schemas/proposal.schema.json +40 -0
- package/dist/forge-payload/schemas/sprint.schema.json +27 -0
- package/dist/forge-payload/schemas/structure-versions.schema.json +57 -0
- package/dist/forge-payload/schemas/task.schema.json +43 -0
- package/dist/forge-payload/schemas/transitions/bug.json +31 -0
- package/dist/forge-payload/schemas/transitions/sprint.json +46 -0
- package/dist/forge-payload/schemas/transitions/task.json +109 -0
- package/dist/forge-payload/tools/manage-config.cjs +120 -2
- package/package.json +3 -3
|
@@ -36,29 +36,29 @@
|
|
|
36
36
|
// Reference: lib/orchestrator-preflight.ts (N-H-H, FORGE-S25-T17).
|
|
37
37
|
//
|
|
38
38
|
// N-H-E tag: see inline comment at the materialization skip (~line 707 / checkMaterialization).
|
|
39
|
+
import { spawnSync } from "node:child_process";
|
|
39
40
|
import * as fs from "node:fs";
|
|
40
41
|
import * as path from "node:path";
|
|
41
42
|
import { fileURLToPath } from "node:url";
|
|
42
|
-
import {
|
|
43
|
+
import { assertAudience, CallerContextStore } from "./audience-gate.js";
|
|
43
44
|
// ModelRegistry/AuthStorage no longer instantiated here — use ctx.modelRegistry
|
|
44
45
|
// so extension-registered providers (registered against the live session) are
|
|
45
46
|
// visible to validateModelConfig. Creating a fresh registry here would miss
|
|
46
47
|
// them and produce spurious MODEL_UNAVAILABLE warnings (FORGE-BUG-001).
|
|
47
48
|
import { loadLayeredConfig } from "./config-layer.js";
|
|
48
|
-
import { resolveModelForPhase } from "./model-resolver.js";
|
|
49
|
-
import { runOrchestratorPreflight } from "./lib/orchestrator-preflight.js";
|
|
50
|
-
import { assertAudience, CallerContextStore } from "./audience-gate.js";
|
|
51
|
-
import { resolveToCanonicalId, resolveToolDir } from "./store-resolver.js";
|
|
52
|
-
import { checkMaterialization } from "./lib/manifest-checker.js";
|
|
53
|
-
import { readPersonaDir as readPersonaDirBug, readPipelineNames as readPipelineNamesBug } from "./lib/catalog-helpers.js";
|
|
54
49
|
import { loadForgePersona, runForgeSubagent } from "./forge-subagent.js";
|
|
55
50
|
import { getSubagentTools } from "./forge-tools.js";
|
|
51
|
+
import { readPersonaDir as readPersonaDirBug, readPipelineNames as readPipelineNamesBug, } from "./lib/catalog-helpers.js";
|
|
56
52
|
import { discoverForgeConfigCached } from "./lib/forge-config.js";
|
|
53
|
+
import { checkMaterialization } from "./lib/manifest-checker.js";
|
|
54
|
+
import { runOrchestratorPreflight } from "./lib/orchestrator-preflight.js";
|
|
55
|
+
import { resolveModelForPhase } from "./model-resolver.js";
|
|
57
56
|
import { loadWorkflow } from "./parsers/workflow-loader.js";
|
|
57
|
+
import { buildPhaseEvent, drainFrictionFile, emitEvent, findPredecessorIndex, formatLocalTime, isNonInteractive, judgementFromSummary, runPreflightGate, validateId, } from "./run-task.js";
|
|
58
58
|
import { getSessionRegistry } from "./session-registry.js";
|
|
59
|
+
import { resolveToCanonicalId, resolveToolDir } from "./store-resolver.js";
|
|
59
60
|
import { attachViewportObserver } from "./viewport-events.js";
|
|
60
61
|
import { fmtPhaseSummary } from "./viewport-renderer.js";
|
|
61
|
-
import { validateId, isNonInteractive, formatLocalTime, emitEvent, findPredecessorIndex, runPreflightGate, buildPhaseEvent, drainFrictionFile, judgementFromSummary, } from "./run-task.js";
|
|
62
62
|
// ── Bug phase descriptor table ──────────────────────────────────────────────
|
|
63
63
|
//
|
|
64
64
|
// Decoded from .forge/workflows/fix_bug.md and the task prompt's BUG_PHASES.
|
|
@@ -79,25 +79,25 @@ export const BUG_PHASES = [
|
|
|
79
79
|
// Phases mapped to null use update-status bug instead of set-bug-summary
|
|
80
80
|
// for verdict tracking (Option B).
|
|
81
81
|
export const BUG_SUMMARY_KEY_BY_ROLE = {
|
|
82
|
-
|
|
82
|
+
triage: "triage",
|
|
83
83
|
"plan-fix": "plan",
|
|
84
84
|
"review-plan": "review_plan",
|
|
85
|
-
|
|
85
|
+
implement: "implementation",
|
|
86
86
|
"review-code": "code_review",
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
approve: "approve", // read from bug.summaries.approve (set-bug-summary)
|
|
88
|
+
commit: null, // commit transitions bug.status → fixed (terminal), no summaries entry
|
|
89
89
|
};
|
|
90
90
|
// Bug-event type tokens — explicit mapping per review finding #3.
|
|
91
91
|
// Non-review phases always emit the pass token. Review phases select
|
|
92
92
|
// pass or fail based on ec.judgement.verdict.
|
|
93
93
|
export const BUG_TYPE_TOKENS = {
|
|
94
|
-
|
|
94
|
+
triage: { pass: "bug-triaged", fail: "bug-triaged" },
|
|
95
95
|
"plan-fix": { pass: "fix-planned", fail: "fix-planned" },
|
|
96
96
|
"review-plan": { pass: "fix-review-passed", fail: "fix-review-failed" },
|
|
97
|
-
|
|
97
|
+
implement: { pass: "fix-implemented", fail: "fix-implemented" },
|
|
98
98
|
"review-code": { pass: "fix-code-review-passed", fail: "fix-code-review-failed" },
|
|
99
|
-
|
|
100
|
-
|
|
99
|
+
approve: { pass: "fix-approved", fail: "fix-revision-requested" },
|
|
100
|
+
commit: { pass: "bug-committed", fail: "bug-commit-failed" },
|
|
101
101
|
};
|
|
102
102
|
// ── Bug FSM transitions ────────────────────────────────────────────────────
|
|
103
103
|
// Mirrors store-cli BUG_TRANSITIONS. Terminal: `fixed`.
|
|
@@ -144,9 +144,7 @@ export function readBugState(cwd, bugId, sessionId) {
|
|
|
144
144
|
bestFile = fp;
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
|
-
catch {
|
|
148
|
-
continue;
|
|
149
|
-
}
|
|
147
|
+
catch { }
|
|
150
148
|
}
|
|
151
149
|
}
|
|
152
150
|
catch {
|
|
@@ -183,7 +181,9 @@ export function deleteBugState(cwd, bugId) {
|
|
|
183
181
|
try {
|
|
184
182
|
fs.unlinkSync(path.join(cacheDir, entry));
|
|
185
183
|
}
|
|
186
|
-
catch {
|
|
184
|
+
catch {
|
|
185
|
+
/* non-fatal */
|
|
186
|
+
}
|
|
187
187
|
}
|
|
188
188
|
}
|
|
189
189
|
}
|
|
@@ -228,7 +228,9 @@ export function assignNextBugId(storeCli, cwd) {
|
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
230
|
}
|
|
231
|
-
catch {
|
|
231
|
+
catch {
|
|
232
|
+
/* empty store — start from 1 */
|
|
233
|
+
}
|
|
232
234
|
}
|
|
233
235
|
const next = maxNum + 1;
|
|
234
236
|
return `FORGE-BUG-${String(next).padStart(3, "0")}`;
|
|
@@ -322,13 +324,13 @@ export function composeBugBody(subWorkflowMd, bugId, phaseRole, bugStatusBeforeP
|
|
|
322
324
|
` node "$FORGE_ROOT/tools/store-cli.cjs" set-bug-summary ${bugId} approve <APPROVE-SUMMARY.json>`,
|
|
323
325
|
` The summary's "verdict" field MUST be "approved" or "revision". The downstream commit gate reads this, not bug.status.`,
|
|
324
326
|
`- Commit phase: on successful git commit, run \`node "$FORGE_ROOT/tools/store-cli.cjs" update-status bug ${bugId} status fixed\` (terminal).`,
|
|
325
|
-
`- Do NOT write
|
|
326
|
-
`- Do NOT reference task-specific status values (e.g.,
|
|
327
|
+
`- Do NOT write "approved" or "verified" to bug.status — those values were removed from the schema in forge v0.44.0.`,
|
|
328
|
+
`- Do NOT reference task-specific status values (e.g., "committed") or task entity kind.`,
|
|
327
329
|
"- CRITICAL: All `set-summary` calls must use `set-bug-summary` (not `set-summary`).",
|
|
328
330
|
` e.g. node "$FORGE_ROOT/tools/store-cli.cjs" set-bug-summary ${bugId} review_plan <jsonFile>`,
|
|
329
331
|
`- Preflight gate: use \`--bug\` flag (not \`--task\`). e.g. node "$FORGE_ROOT/tools/preflight-gate.cjs" --phase review-plan --bug ${bugId}`,
|
|
330
332
|
"- Skip re-running preflight-gate — the orchestrator already checked it. Proceed directly to the review.",
|
|
331
|
-
|
|
333
|
+
'Any workflow text that says "task" should be read as "bug" for this context.',
|
|
332
334
|
];
|
|
333
335
|
// Phase-specific reinforcement when the orchestrator can name the current status.
|
|
334
336
|
if (phaseRole === "approve" && bugStatusBeforePhase) {
|
|
@@ -338,7 +340,7 @@ export function composeBugBody(subWorkflowMd, bugId, phaseRole, bugStatusBeforeP
|
|
|
338
340
|
entityKindLines.push(`- Commit phase: after the git commit lands, transition bug.status from '${bugStatusBeforePhase}' to 'fixed'.`);
|
|
339
341
|
}
|
|
340
342
|
if (phaseRole === "triage") {
|
|
341
|
-
entityKindLines.push(
|
|
343
|
+
entityKindLines.push('- Triage phase: in addition to writing TRIAGE.md and TRIAGE-SUMMARY.json, the summary MUST include a `route` field set to `"A"` or `"B"`.', " Path A (short-circuit): severity == minor AND single-file fix ≤ ~20 lines AND no schema/API/migration AND regression test obvious from repro.", " Path B (default): everything else. When in doubt, choose B.", " The orchestrator reads bug.summaries.triage.route to select the downstream phase list.");
|
|
342
344
|
}
|
|
343
345
|
return [
|
|
344
346
|
`Read the workflow below and follow it. Bug ID: ${bugId}.`,
|
|
@@ -414,14 +416,14 @@ export function extractBugIdFromEvents(events) {
|
|
|
414
416
|
const STATUS_KEY = "forge:fix-bug";
|
|
415
417
|
const MESSAGE_KEY = "forge:fix-bug:message";
|
|
416
418
|
export async function runBugPipeline(opts) {
|
|
417
|
-
const { bugId: initialBugId, originalArg, isNewBug, cwd, ctx, forgeRoot, storeCli, preflightGate, registry, resumeFromState } = opts;
|
|
419
|
+
const { bugId: initialBugId, originalArg, isNewBug, cwd, ctx, forgeRoot, storeCli, preflightGate, registry, resumeFromState, } = opts;
|
|
418
420
|
// Mutable bugId — for new bugs, pre-assign a real FORGE-BUG-NNN ID
|
|
419
421
|
// before triage so the subagent never needs to create or discover one.
|
|
420
422
|
// This replaces the fragile PENDING→capture pattern where the subagent was
|
|
421
423
|
// expected to create the bug record and we'd fish the ID from events.
|
|
422
424
|
let bugId = initialBugId;
|
|
423
425
|
let currentPhaseIndex = resumeFromState?.phaseIndex ?? 0;
|
|
424
|
-
|
|
426
|
+
const iterationCounts = resumeFromState?.iterationCounts ?? {};
|
|
425
427
|
let lastModel;
|
|
426
428
|
let lastProvider;
|
|
427
429
|
// ── Per-persona model routing (Plan 16) ─────────────────────────────────
|
|
@@ -436,7 +438,12 @@ export async function runBugPipeline(opts) {
|
|
|
436
438
|
for (const e of layeredConfigErrors) {
|
|
437
439
|
ctx.ui.notify(`× forge:fix-bug — forge-cli config schema error: ${e}`, "error");
|
|
438
440
|
}
|
|
439
|
-
return {
|
|
441
|
+
return {
|
|
442
|
+
status: "failed",
|
|
443
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
444
|
+
iterationCounts,
|
|
445
|
+
lastError: `forge-cli config schema errors: ${layeredConfigErrors.join("; ")}`,
|
|
446
|
+
};
|
|
440
447
|
}
|
|
441
448
|
// Pre-flight validation — same shape as run-task / run-sprint.
|
|
442
449
|
// FORGE-S25-T17: delegated to lib/orchestrator-preflight.ts (H-13).
|
|
@@ -484,7 +491,12 @@ export async function runBugPipeline(opts) {
|
|
|
484
491
|
const phase = BUG_PHASES[currentPhaseIndex];
|
|
485
492
|
if (!phase) {
|
|
486
493
|
ctx.ui.notify(`× forge:fix-bug — invalid phase index ${currentPhaseIndex}`, "error");
|
|
487
|
-
return {
|
|
494
|
+
return {
|
|
495
|
+
status: "failed",
|
|
496
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
497
|
+
iterationCounts,
|
|
498
|
+
lastError: `invalid phase index ${currentPhaseIndex}`,
|
|
499
|
+
};
|
|
488
500
|
}
|
|
489
501
|
ctx.ui.setStatus?.(STATUS_KEY, `fix-bug ${bugId}: phase ${currentPhaseIndex + 1}/${BUG_PHASES.length} (${phase.role})`);
|
|
490
502
|
ctx.ui.notify(`→ ${bugId}: ${phase.role} (phase ${currentPhaseIndex + 1}/${BUG_PHASES.length})`, "info");
|
|
@@ -508,7 +520,12 @@ export async function runBugPipeline(opts) {
|
|
|
508
520
|
lastError: `sub-workflow read failed: ${e.message ?? "unknown"}`,
|
|
509
521
|
savedAt: new Date().toISOString(),
|
|
510
522
|
});
|
|
511
|
-
return {
|
|
523
|
+
return {
|
|
524
|
+
status: "failed",
|
|
525
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
526
|
+
iterationCounts,
|
|
527
|
+
lastError: `sub-workflow read failed: ${e.message ?? "unknown"}`,
|
|
528
|
+
};
|
|
512
529
|
}
|
|
513
530
|
// ── 6a. Phase skip (state-aware, defense-in-depth) ─────────────
|
|
514
531
|
// Belt-and-suspenders alongside the explicit summaries.triage.route
|
|
@@ -523,8 +540,8 @@ export async function runBugPipeline(opts) {
|
|
|
523
540
|
// removed.
|
|
524
541
|
const PHASE_SKIP_STATES = {
|
|
525
542
|
"plan-fix": new Set(["fixed"]),
|
|
526
|
-
|
|
527
|
-
|
|
543
|
+
implement: new Set(["fixed"]),
|
|
544
|
+
commit: new Set(["fixed"]), // commit writes the terminal status; skip if already there
|
|
528
545
|
};
|
|
529
546
|
const bugNow = readBugRecord(bugId, storeCli, cwd);
|
|
530
547
|
const skipStates = PHASE_SKIP_STATES[phase.role];
|
|
@@ -546,14 +563,19 @@ export async function runBugPipeline(opts) {
|
|
|
546
563
|
};
|
|
547
564
|
const synthFile = path.join(cwd, ".forge", "cache", `synthetic-summary-${bugId}-${summaryKey}.json`);
|
|
548
565
|
fs.writeFileSync(synthFile, JSON.stringify(synthSummary, null, 2), "utf8");
|
|
549
|
-
const synthResult = spawnSync("node", [storeCli, "set-bug-summary", bugId, summaryKey, synthFile], {
|
|
566
|
+
const synthResult = spawnSync("node", [storeCli, "set-bug-summary", bugId, summaryKey, synthFile], {
|
|
567
|
+
cwd,
|
|
568
|
+
encoding: "utf8",
|
|
569
|
+
});
|
|
550
570
|
if (synthResult.status !== 0) {
|
|
551
571
|
ctx.ui.notify(`⚠ forge:fix-bug — synthetic summary write failed for ${phase.role}: ${String(synthResult.stderr).trim()}`, "warning");
|
|
552
572
|
}
|
|
553
573
|
try {
|
|
554
574
|
fs.unlinkSync(synthFile);
|
|
555
575
|
}
|
|
556
|
-
catch {
|
|
576
|
+
catch {
|
|
577
|
+
/* non-fatal */
|
|
578
|
+
}
|
|
557
579
|
}
|
|
558
580
|
currentPhaseIndex++;
|
|
559
581
|
continue;
|
|
@@ -583,7 +605,12 @@ export async function runBugPipeline(opts) {
|
|
|
583
605
|
lastError: `preflight gate exit 1 for ${phase.role}`,
|
|
584
606
|
savedAt: new Date().toISOString(),
|
|
585
607
|
});
|
|
586
|
-
return {
|
|
608
|
+
return {
|
|
609
|
+
status: "halted",
|
|
610
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
611
|
+
iterationCounts,
|
|
612
|
+
lastError: `preflight gate exit 1 for ${phase.role}`,
|
|
613
|
+
};
|
|
587
614
|
}
|
|
588
615
|
if (preflightResult === "escalate") {
|
|
589
616
|
ctx.ui.notify(`× forge:fix-bug — preflight gate escalated for phase ${phase.role} (exit 2); manual intervention required.`, "error");
|
|
@@ -595,7 +622,12 @@ export async function runBugPipeline(opts) {
|
|
|
595
622
|
lastError: `preflight gate exit 2 (escalate) for ${phase.role}`,
|
|
596
623
|
savedAt: new Date().toISOString(),
|
|
597
624
|
});
|
|
598
|
-
return {
|
|
625
|
+
return {
|
|
626
|
+
status: "escalated",
|
|
627
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
628
|
+
iterationCounts,
|
|
629
|
+
lastError: `preflight gate exit 2 (escalate) for ${phase.role}`,
|
|
630
|
+
};
|
|
599
631
|
}
|
|
600
632
|
}
|
|
601
633
|
// ── 6. Materialization-marker check ───────────────────────────
|
|
@@ -611,7 +643,12 @@ export async function runBugPipeline(opts) {
|
|
|
611
643
|
for (const marker of markerCheck.missing) {
|
|
612
644
|
ctx.ui.notify(`× workflow regression: ${marker} not found in ${subWorkflowPath}`, "error");
|
|
613
645
|
}
|
|
614
|
-
return {
|
|
646
|
+
return {
|
|
647
|
+
status: "failed",
|
|
648
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
649
|
+
iterationCounts,
|
|
650
|
+
lastError: `materialization markers missing: ${markerCheck.missing.join(", ")}`,
|
|
651
|
+
};
|
|
615
652
|
}
|
|
616
653
|
}
|
|
617
654
|
// ── 5. Audience check ─────────────────────────────────────────
|
|
@@ -620,7 +657,8 @@ export async function runBugPipeline(opts) {
|
|
|
620
657
|
// Skip the audience gate for the monolithic fix_bug.md; only check the
|
|
621
658
|
// true sub-workflows (review_plan, review_code, architect_approve, commit_task)
|
|
622
659
|
// which the subagent does run directly.
|
|
623
|
-
const audienceOk = phase.workflowFile === "fix_bug" ||
|
|
660
|
+
const audienceOk = phase.workflowFile === "fix_bug" ||
|
|
661
|
+
CallerContextStore.asSubagent(() => assertAudience({ workflowName: phase.workflowFile, audience: subWorkflowAudience }, ctx));
|
|
624
662
|
if (!audienceOk) {
|
|
625
663
|
writeBugState(cwd, {
|
|
626
664
|
bugId,
|
|
@@ -630,7 +668,12 @@ export async function runBugPipeline(opts) {
|
|
|
630
668
|
lastError: `audience check failed for ${phase.workflowFile}`,
|
|
631
669
|
savedAt: new Date().toISOString(),
|
|
632
670
|
});
|
|
633
|
-
return {
|
|
671
|
+
return {
|
|
672
|
+
status: "failed",
|
|
673
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
674
|
+
iterationCounts,
|
|
675
|
+
lastError: `audience check failed for ${phase.workflowFile}`,
|
|
676
|
+
};
|
|
634
677
|
}
|
|
635
678
|
// ── Persona load ──────────────────────────────────────────────
|
|
636
679
|
let persona;
|
|
@@ -649,7 +692,12 @@ export async function runBugPipeline(opts) {
|
|
|
649
692
|
lastError: `persona load failed: ${e.message ?? "unknown"}`,
|
|
650
693
|
savedAt: new Date().toISOString(),
|
|
651
694
|
});
|
|
652
|
-
return {
|
|
695
|
+
return {
|
|
696
|
+
status: "failed",
|
|
697
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
698
|
+
iterationCounts,
|
|
699
|
+
lastError: `persona load failed: ${e.message ?? "unknown"}`,
|
|
700
|
+
};
|
|
653
701
|
}
|
|
654
702
|
// ── Read bug record for current status ────────────────────────
|
|
655
703
|
// Skip for PENDING bugIds (bug doesn't exist yet).
|
|
@@ -691,7 +739,9 @@ export async function runBugPipeline(opts) {
|
|
|
691
739
|
fs.writeFileSync(debugLogPath, lines.slice(-keep).join("\n"), "utf8");
|
|
692
740
|
}
|
|
693
741
|
}
|
|
694
|
-
catch {
|
|
742
|
+
catch {
|
|
743
|
+
/* file may not exist yet */
|
|
744
|
+
}
|
|
695
745
|
fs.appendFileSync(debugLogPath, `${JSON.stringify({ ts: new Date().toISOString(), phase: phase.role, ...rec })}\n`, "utf8");
|
|
696
746
|
}
|
|
697
747
|
catch {
|
|
@@ -759,7 +809,9 @@ export async function runBugPipeline(opts) {
|
|
|
759
809
|
// Keeps every phase of this bug-fix pipeline in a single cache
|
|
760
810
|
// namespace so the system-prompt + persona prefix stays warm
|
|
761
811
|
// across the ~10-minute phases.
|
|
762
|
-
cacheSessionId: typeof bugRecordBefore?.sprintId === "string"
|
|
812
|
+
cacheSessionId: typeof bugRecordBefore?.sprintId === "string"
|
|
813
|
+
? `forge:${bugRecordBefore.sprintId}`
|
|
814
|
+
: `forge:bug:${bugId}`,
|
|
763
815
|
onEvent: onSubagentEvent,
|
|
764
816
|
requestedModel: modelResolution.model,
|
|
765
817
|
modelRegistry: ctx.modelRegistry,
|
|
@@ -778,7 +830,12 @@ export async function runBugPipeline(opts) {
|
|
|
778
830
|
lastError: `runForgeSubagent threw: ${e.message ?? "unknown"}`,
|
|
779
831
|
savedAt: new Date().toISOString(),
|
|
780
832
|
});
|
|
781
|
-
return {
|
|
833
|
+
return {
|
|
834
|
+
status: "failed",
|
|
835
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
836
|
+
iterationCounts,
|
|
837
|
+
lastError: `runForgeSubagent threw: ${e.message ?? "unknown"}`,
|
|
838
|
+
};
|
|
782
839
|
}
|
|
783
840
|
// ── Post-subagent abort detection ─────────────────────────────────
|
|
784
841
|
if (result.stopReason === "aborted" || opts.signal?.aborted) {
|
|
@@ -810,7 +867,12 @@ export async function runBugPipeline(opts) {
|
|
|
810
867
|
lastError: result.errorMessage ?? result.stopReason ?? "subagent exit non-zero",
|
|
811
868
|
savedAt: new Date().toISOString(),
|
|
812
869
|
});
|
|
813
|
-
return {
|
|
870
|
+
return {
|
|
871
|
+
status: "failed",
|
|
872
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
873
|
+
iterationCounts,
|
|
874
|
+
lastError: result.errorMessage ?? result.stopReason ?? "subagent exit non-zero",
|
|
875
|
+
};
|
|
814
876
|
}
|
|
815
877
|
// Capture model/provider from subagent result.
|
|
816
878
|
if (result.model)
|
|
@@ -838,19 +900,29 @@ export async function runBugPipeline(opts) {
|
|
|
838
900
|
const recent = bugs
|
|
839
901
|
.filter((b) => b.reportedAt && b.reportedAt >= pipelineStartIso)
|
|
840
902
|
.sort((a, b) => String(b.reportedAt).localeCompare(String(a.reportedAt)))[0];
|
|
841
|
-
if (recent &&
|
|
903
|
+
if (recent &&
|
|
904
|
+
recent.bugId &&
|
|
905
|
+
typeof recent.bugId === "string" &&
|
|
906
|
+
recent.bugId.startsWith("FORGE-BUG-")) {
|
|
842
907
|
bugId = recent.bugId;
|
|
843
908
|
ctx.ui.notify(`forge:fix-bug — captured bug ID via store fallback: ${bugId}`, "info");
|
|
844
909
|
}
|
|
845
910
|
}
|
|
846
911
|
}
|
|
847
|
-
catch {
|
|
912
|
+
catch {
|
|
913
|
+
/* parse failure — fall through to assertion */
|
|
914
|
+
}
|
|
848
915
|
}
|
|
849
916
|
}
|
|
850
917
|
// Defensive guard: if bugId is still PENDING after triage, pipeline cannot proceed.
|
|
851
918
|
if (bugId.startsWith("PENDING-")) {
|
|
852
919
|
ctx.ui.notify("× forge:fix-bug — failed to capture real bug ID after triage. Cannot proceed with PENDING placeholder.", "error");
|
|
853
|
-
return {
|
|
920
|
+
return {
|
|
921
|
+
status: "failed",
|
|
922
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
923
|
+
iterationCounts,
|
|
924
|
+
lastError: "bugId still PENDING after triage",
|
|
925
|
+
};
|
|
854
926
|
}
|
|
855
927
|
// Re-initialize debug log now that real bugId is available.
|
|
856
928
|
if (!debugLogDisabled) {
|
|
@@ -868,7 +940,9 @@ export async function runBugPipeline(opts) {
|
|
|
868
940
|
fs.writeFileSync(debugLogPath, lines.slice(-keep).join("\n"), "utf8");
|
|
869
941
|
}
|
|
870
942
|
}
|
|
871
|
-
catch {
|
|
943
|
+
catch {
|
|
944
|
+
/* file may not exist yet */
|
|
945
|
+
}
|
|
872
946
|
fs.appendFileSync(debugLogPath, `${JSON.stringify({ ts: new Date().toISOString(), phase: phase.role, ...rec })}\n`, "utf8");
|
|
873
947
|
}
|
|
874
948
|
catch {
|
|
@@ -981,7 +1055,12 @@ export async function runBugPipeline(opts) {
|
|
|
981
1055
|
lastError: `verdict missing for ${phase.role}`,
|
|
982
1056
|
savedAt: new Date().toISOString(),
|
|
983
1057
|
});
|
|
984
|
-
return {
|
|
1058
|
+
return {
|
|
1059
|
+
status: "failed",
|
|
1060
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
1061
|
+
iterationCounts,
|
|
1062
|
+
lastError: `verdict missing for ${phase.role}`,
|
|
1063
|
+
};
|
|
985
1064
|
}
|
|
986
1065
|
if (verdict === "revision") {
|
|
987
1066
|
iterationCounts[phase.role] = (iterationCounts[phase.role] ?? 0) + 1;
|
|
@@ -996,7 +1075,12 @@ export async function runBugPipeline(opts) {
|
|
|
996
1075
|
lastError: `revision cap reached for ${phase.role}`,
|
|
997
1076
|
savedAt: new Date().toISOString(),
|
|
998
1077
|
});
|
|
999
|
-
return {
|
|
1078
|
+
return {
|
|
1079
|
+
status: "escalated",
|
|
1080
|
+
lastPhaseIndex: currentPhaseIndex,
|
|
1081
|
+
iterationCounts,
|
|
1082
|
+
lastError: `revision cap reached for ${phase.role}`,
|
|
1083
|
+
};
|
|
1000
1084
|
}
|
|
1001
1085
|
// Transition bug back to in-progress before re-dispatching implement.
|
|
1002
1086
|
// This is required for review-code → implement and approve → implement loops.
|
|
@@ -1065,7 +1149,13 @@ export async function runBugPipeline(opts) {
|
|
|
1065
1149
|
}
|
|
1066
1150
|
// ── All phases complete ───────────────────────────────────────────
|
|
1067
1151
|
deleteBugState(cwd, bugId);
|
|
1068
|
-
return {
|
|
1152
|
+
return {
|
|
1153
|
+
status: "completed",
|
|
1154
|
+
lastPhaseIndex: BUG_PHASES.length - 1,
|
|
1155
|
+
iterationCounts,
|
|
1156
|
+
model: lastModel,
|
|
1157
|
+
provider: lastProvider,
|
|
1158
|
+
};
|
|
1069
1159
|
}
|
|
1070
1160
|
export function registerFixBug(pi, options = {}) {
|
|
1071
1161
|
pi.registerCommand("forge:fix-bug", {
|
|
@@ -1097,8 +1187,7 @@ export function registerFixBug(pi, options = {}) {
|
|
|
1097
1187
|
let isNewBug = false;
|
|
1098
1188
|
// Check if arg looks like it could be a bug ID (prefixed or unprefixed).
|
|
1099
1189
|
// Covers: FORGE-BUG-042, BUG-042, B042.
|
|
1100
|
-
const looksLikeBugId = /^(?:[A-Z0-9]+-)?(?:BUG-?\d+|B\d+)$/i.test(rawArg) ||
|
|
1101
|
-
/^BUG-\d+$/i.test(rawArg);
|
|
1190
|
+
const looksLikeBugId = /^(?:[A-Z0-9]+-)?(?:BUG-?\d+|B\d+)$/i.test(rawArg) || /^BUG-\d+$/i.test(rawArg);
|
|
1102
1191
|
if (/^FORGE-BUG-\d+$/.test(rawArg)) {
|
|
1103
1192
|
// Canonical bug ID — verify it exists
|
|
1104
1193
|
bugId = rawArg;
|
|
@@ -1119,7 +1208,10 @@ export function registerFixBug(pi, options = {}) {
|
|
|
1119
1208
|
// Unprefixed bug ID — resolve through the store cascade.
|
|
1120
1209
|
// Issue #20: unprefixed entity IDs silently poisoned substitutions.
|
|
1121
1210
|
const toolDir = resolveToolDir(forgeRoot);
|
|
1122
|
-
const resolvedBugId = await resolveToCanonicalId(rawArg, toolDir, cwd, "bug", {
|
|
1211
|
+
const resolvedBugId = await resolveToCanonicalId(rawArg, toolDir, cwd, "bug", {
|
|
1212
|
+
ctx,
|
|
1213
|
+
commandLabel: "forge:fix-bug",
|
|
1214
|
+
});
|
|
1123
1215
|
if (!resolvedBugId) {
|
|
1124
1216
|
// Error already emitted by resolver
|
|
1125
1217
|
ctx.ui.setStatus?.(STATUS_KEY, undefined);
|
|
@@ -1189,9 +1281,7 @@ export function registerFixBug(pi, options = {}) {
|
|
|
1189
1281
|
// (explicit failure), halted=false (cancelled/interrupted), and
|
|
1190
1282
|
// any state with existing.status set.
|
|
1191
1283
|
const stateStatus = existing.status ?? (existing.halted ? "halted" : "interrupted");
|
|
1192
|
-
const statusLabel = stateStatus === "cancelled" ? "cancelled"
|
|
1193
|
-
: stateStatus === "halted" ? "halted"
|
|
1194
|
-
: "interrupted";
|
|
1284
|
+
const statusLabel = stateStatus === "cancelled" ? "cancelled" : stateStatus === "halted" ? "halted" : "interrupted";
|
|
1195
1285
|
const phaseRole = BUG_PHASES[existing.phaseIndex]?.role ?? existing.phaseIndex;
|
|
1196
1286
|
if (!isNonInteractive()) {
|
|
1197
1287
|
const resume = await ctx.ui.confirm(`Resume ${bugId}?`, `Cached state — phase ${existing.phaseIndex} (${phaseRole}), ${statusLabel}, ` +
|
|
@@ -1247,7 +1337,7 @@ export function registerFixBug(pi, options = {}) {
|
|
|
1247
1337
|
// needs the real ID before startSession is called.
|
|
1248
1338
|
if (isNewBug && bugId.startsWith("PENDING-")) {
|
|
1249
1339
|
const realBugId = assignNextBugId(storeCli, cwd);
|
|
1250
|
-
const title =
|
|
1340
|
+
const title = rawArg && !rawArg.startsWith("@") ? rawArg.slice(0, 120) : "New bug (pending triage)";
|
|
1251
1341
|
if (preCreateBug(realBugId, title, storeCli, cwd)) {
|
|
1252
1342
|
ctx.ui.notify(`forge:fix-bug — pre-assigned bug ID: ${realBugId}`, "info");
|
|
1253
1343
|
bugId = realBugId;
|