substrate-ai 0.20.138 → 0.20.139

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.
@@ -1,11 +1,11 @@
1
- import { BMAD_BASELINE_TOKENS_FULL, FileKvStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, validateStoryKey } from "./health-2Kfa00-H.js";
1
+ import { BMAD_BASELINE_TOKENS_FULL, FileKvStore, STOP_AFTER_VALID_PHASES, STORY_KEY_PATTERN, VALID_PHASES, __commonJS, __require, __toESM, buildPipelineStatusOutput, createDatabaseAdapter, formatOutput, formatPipelineSummary, formatTokenTelemetry, inspectProcessTree, parseDbTimestampAsUtc, validateStoryKey } from "./health-BXVyiLiL.js";
2
2
  import { createLogger } from "./logger-KeHncl-f.js";
3
3
  import { TypedEventBusImpl, createEventBus, createTuiApp, isTuiCapable, printNonTtyWarning, sleep } from "./helpers-CElYrONe.js";
4
- import { ADVISORY_NOTES, CODEX_SANDBOX_BLOCK_HINT, Categorizer, ConsumerAnalyzer, DEFAULT_GLOBAL_SETTINGS, DispatcherImpl, DoltClient, ESCALATION_DIAGNOSIS, EXPERIMENT_RESULT, EfficiencyScorer, IngestionServer, LogTurnAnalyzer, OPERATIONAL_FINDING, Recommender, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, STORY_METRICS, STORY_OUTCOME, SubstrateConfigSchema, TEST_EXPANSION_FINDING, TEST_PLAN, TelemetryNormalizer, TelemetryPipeline, TurnAnalyzer, addTokenUsage, aggregateTokenUsageForRun, aggregateTokenUsageForStory, callLLM, classifyVersionGap, createConfigSystem, createDatabaseAdapter$1, createDecision, createPipelineRun, createRequirement, createStderrLogger, detectCodexSandboxBlock, detectInterfaceChanges, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunMetrics, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, listRequirements, loadModelRoutingConfig, registerArtifact, swallowDebug, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-DnvGvKLu.js";
5
- import { FindingsInjector, RunManifest, RuntimeProbeListSchema, applyConfigToGraph, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, parseRuntimeProbes, renderFindings, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery } from "./manifest-read-DJFbGhSd.js";
4
+ import { ADVISORY_NOTES, CODEX_SANDBOX_BLOCK_HINT, Categorizer, ConsumerAnalyzer, DEFAULT_GLOBAL_SETTINGS, DispatcherImpl, DoltClient, ESCALATION_DIAGNOSIS, EXPERIMENT_RESULT, EfficiencyScorer, IngestionServer, LogTurnAnalyzer, OPERATIONAL_FINDING, Recommender, RoutingRecommender, RoutingResolver, RoutingTelemetry, RoutingTokenAccumulator, RoutingTuner, STORY_METRICS, STORY_OUTCOME, SubstrateConfigSchema, TEST_EXPANSION_FINDING, TEST_PLAN, TelemetryNormalizer, TelemetryPipeline, TurnAnalyzer, addTokenUsage, aggregateTokenUsageForRun, aggregateTokenUsageForStory, callLLM, classifyVersionGap, createConfigSystem, createDatabaseAdapter$1, createDecision, createPipelineRun, createRequirement, createStderrLogger, detectCodexSandboxBlock, detectInterfaceChanges, getArtifactByTypeForRun, getArtifactsByRun, getDecisionsByCategory, getDecisionsByPhase, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getRunMetrics, getRunningPipelineRuns, getStoryMetricsForRun, getTokenUsageSummary, initSchema, listRequirements, loadModelRoutingConfig, registerArtifact, swallowDebug, updatePipelineRun, updatePipelineRunConfig, upsertDecision, writeRunMetrics, writeStoryMetrics } from "./dist-BWCudDcl.js";
5
+ import { FindingsInjector, RunManifest, RuntimeProbeListSchema, applyConfigToGraph, createDefaultVerificationPipeline, createGraphOrchestrator, createSdlcCodeReviewHandler, createSdlcCreateStoryHandler, createSdlcDevStoryHandler, createSdlcPhaseHandler, detectsEventDrivenAC, detectsStateIntegratingAC, extractTargetFilesFromStoryContent, parseRuntimeProbes, renderFindings, resolveGraphPath, resolveMainRepoRoot, runAcTraceabilityCheck, runStaleVerificationRecovery } from "./manifest-read-IvpNQ6Yy.js";
6
6
  import { WorkGraphRepository, detectCycles } from "./work-graph-repository-DZyJv5pV.js";
7
7
  import { deriveExitCode, routeDecision } from "./decision-router-DblHY8se.js";
8
- import { runInteractivePrompt } from "./interactive-prompt-B91mG5v4.js";
8
+ import { runInteractivePrompt } from "./interactive-prompt-BypNgFHL.js";
9
9
  import { runRecoveryEngine } from "./recovery-engine-BKGBeBnW.js";
10
10
  import { basename, dirname, extname, join } from "path";
11
11
  import { access, readFile, readdir, stat } from "fs/promises";
@@ -7549,6 +7549,104 @@ async function commitDevStoryOutput(storyKey, storyTitle, filesModified, working
7549
7549
  };
7550
7550
  }
7551
7551
  /**
7552
+ * Commit the worktree's dirty state as a recovery checkpoint (H0.1, field
7553
+ * finding #17): on every failure path the story branch — not the worktree's
7554
+ * working tree — must be the durable copy of the agent's work. Before this,
7555
+ * a verification-failed or escalated story left its only copy as uncommitted
7556
+ * files, and any `git worktree remove --force` (operator cleanup, orphan
7557
+ * sweep) destroyed it permanently.
7558
+ *
7559
+ * Semantics differ from `commitDevStoryOutput` deliberately:
7560
+ * - Stages EVERYTHING dirty (`git add -A`; .gitignore still applies) — a
7561
+ * checkpoint must not guess which files matter.
7562
+ * - Bypasses hooks (`--no-verify`): this is a recovery snapshot, not a
7563
+ * deliverable. Deliverable `feat(story-…)` commits keep hooks; wip
7564
+ * checkpoints never merge on their own — `reconcile-from-disk` and the
7565
+ * operator decide what to do with them.
7566
+ * - Message prefix `wip(story-<key>):` so tooling can tell checkpoints from
7567
+ * deliverables (reconcile-from-disk greps both, prefers feat).
7568
+ *
7569
+ * Never throws; all failure modes return a structured status.
7570
+ */
7571
+ async function checkpointStoryWorktree(storyKey, reason, workingDir) {
7572
+ if (!existsSync(workingDir)) return { status: "no-changes" };
7573
+ try {
7574
+ execSync("git add -A", {
7575
+ cwd: workingDir,
7576
+ stdio: [
7577
+ "ignore",
7578
+ "pipe",
7579
+ "pipe"
7580
+ ],
7581
+ timeout: 3e4
7582
+ });
7583
+ } catch (err) {
7584
+ const stderr = err instanceof Error && "stderr" in err ? String(err.stderr ?? err.message) : err instanceof Error ? err.message : String(err);
7585
+ return {
7586
+ status: "failed",
7587
+ stderr: `git add -A failed: ${stderr}`
7588
+ };
7589
+ }
7590
+ const cachedCheck = spawn("git", [
7591
+ "diff",
7592
+ "--cached",
7593
+ "--quiet"
7594
+ ], {
7595
+ cwd: workingDir,
7596
+ stdio: [
7597
+ "ignore",
7598
+ "pipe",
7599
+ "pipe"
7600
+ ]
7601
+ });
7602
+ const cachedStatus = await new Promise((res) => {
7603
+ cachedCheck.on("close", (code) => res(code ?? 0));
7604
+ cachedCheck.on("error", () => res(0));
7605
+ });
7606
+ if (cachedStatus === 0) return { status: "no-changes" };
7607
+ const cleanReason = (reason.split("\n")[0] ?? "checkpoint").split("").filter((ch) => ch.charCodeAt(0) >= 32).join("").slice(0, 100);
7608
+ const message = `wip(story-${storyKey}): ${cleanReason}`;
7609
+ try {
7610
+ execSync(`git commit --no-verify -m ${JSON.stringify(message)}`, {
7611
+ cwd: workingDir,
7612
+ stdio: [
7613
+ "ignore",
7614
+ "pipe",
7615
+ "pipe"
7616
+ ],
7617
+ timeout: 6e4
7618
+ });
7619
+ } catch (err) {
7620
+ const stderr = err instanceof Error && "stderr" in err ? String(err.stderr ?? err.message) : err instanceof Error ? err.message : String(err);
7621
+ return {
7622
+ status: "failed",
7623
+ stderr: `git commit --no-verify failed: ${stderr}`
7624
+ };
7625
+ }
7626
+ let sha = "";
7627
+ try {
7628
+ sha = execSync("git rev-parse HEAD", {
7629
+ cwd: workingDir,
7630
+ encoding: "utf-8",
7631
+ stdio: [
7632
+ "ignore",
7633
+ "pipe",
7634
+ "pipe"
7635
+ ],
7636
+ timeout: 5e3
7637
+ }).trim();
7638
+ } catch {}
7639
+ logger$20.info({
7640
+ storyKey,
7641
+ sha,
7642
+ reason: cleanReason
7643
+ }, "checkpointStoryWorktree: committed recovery checkpoint");
7644
+ return {
7645
+ status: "committed",
7646
+ sha
7647
+ };
7648
+ }
7649
+ /**
7552
7650
  * Check whether the repo at `cwd` has at least one commit (HEAD resolves).
7553
7651
  * Returns false for fresh repos with no commits, avoiding `fatal: bad revision 'HEAD'`.
7554
7652
  * Synchronous (execSync) to keep it simple — this is a fast local check.
@@ -12562,6 +12660,48 @@ var CostGovernanceChecker = class {
12562
12660
  }
12563
12661
  };
12564
12662
 
12663
+ //#endregion
12664
+ //#region src/modules/implementation-orchestrator/dispatch-telemetry-aggregation.ts
12665
+ /**
12666
+ * Aggregates turn counts and token usage across an array of dispatch records.
12667
+ *
12668
+ * Returns an object with `total_turns` and/or `total_tokens` populated only
12669
+ * when at least one record carries the corresponding telemetry:
12670
+ * - If NO record has `turns` data → `total_turns` is absent.
12671
+ * - If NO record has `tokens` data → `total_tokens` is absent.
12672
+ * - If SOME records have turns/tokens and some don't, the available data is
12673
+ * summed; records without the field do not contribute zero.
12674
+ *
12675
+ * Absence MUST NOT be treated as zero by consumers — use `?? null` at call
12676
+ * sites per the `PerStoryState.total_turns` / `total_tokens` semantics.
12677
+ *
12678
+ * @param dispatchRecords - Array of per-dispatch records for one story.
12679
+ * Pass `_storyAgents.get(storyKey) ?? []` from the orchestrator. In the
12680
+ * current implementation those records don't carry token/turn data, so
12681
+ * the result is `{}` — this is the documented known gap.
12682
+ * @returns Partial telemetry aggregate: `{}` when no data, populated when present.
12683
+ */
12684
+ function aggregateStoryDispatchTelemetry(dispatchRecords) {
12685
+ if (dispatchRecords.length === 0) return {};
12686
+ let turnsSum;
12687
+ let tokensInput;
12688
+ let tokensOutput;
12689
+ for (const record of dispatchRecords) {
12690
+ if (record.turns !== void 0) turnsSum = (turnsSum ?? 0) + record.turns;
12691
+ if (record.tokens !== void 0) {
12692
+ tokensInput = (tokensInput ?? 0) + record.tokens.input;
12693
+ tokensOutput = (tokensOutput ?? 0) + record.tokens.output;
12694
+ }
12695
+ }
12696
+ const result = {};
12697
+ if (turnsSum !== void 0) result.total_turns = turnsSum;
12698
+ if (tokensInput !== void 0 && tokensOutput !== void 0) result.total_tokens = {
12699
+ input: tokensInput,
12700
+ output: tokensOutput
12701
+ };
12702
+ return result;
12703
+ }
12704
+
12565
12705
  //#endregion
12566
12706
  //#region src/modules/work-graph/epic-ingester.ts
12567
12707
  var EpicIngester = class {
@@ -13545,6 +13685,7 @@ function createImplementationOrchestrator(deps) {
13545
13685
  const _phaseEndMs = new Map();
13546
13686
  const _storyDispatches = new Map();
13547
13687
  const _storyAgents = new Map();
13688
+ const _storyWorktrees = new Map();
13548
13689
  const _storyRetryCount = new Map();
13549
13690
  let _completedDispatches = 0;
13550
13691
  let _maxConcurrentActual = 0;
@@ -13860,6 +14001,23 @@ function createImplementationOrchestrator(deps) {
13860
14001
  * diagnosis to the decision store (Story 22-3).
13861
14002
  */
13862
14003
  async function emitEscalation(payload) {
14004
+ const escalationWorktree = _storyWorktrees.get(payload.storyKey);
14005
+ if (escalationWorktree !== void 0) {
14006
+ const cp = await checkpointStoryWorktree(payload.storyKey, `escalation: ${payload.escalationReason ?? payload.lastVerdict}`, escalationWorktree);
14007
+ if (cp.status === "committed") {
14008
+ logger$27.info({
14009
+ storyKey: payload.storyKey,
14010
+ sha: cp.sha
14011
+ }, "escalation checkpoint: uncommitted worktree state preserved on story branch");
14012
+ if (runManifest !== null && cp.sha) runManifest.patchStoryState(payload.storyKey, { checkpoint_sha: cp.sha }).catch((err) => logger$27.warn({
14013
+ err,
14014
+ storyKey: payload.storyKey
14015
+ }, "patchStoryState(checkpoint_sha, escalation) failed — pipeline continues"));
14016
+ } else if (cp.status === "failed") logger$27.warn({
14017
+ storyKey: payload.storyKey,
14018
+ stderr: cp.stderr.slice(0, 500)
14019
+ }, "escalation checkpoint failed — worktree state remains uncommitted (inspect before any cleanup)");
14020
+ }
13863
14021
  const diagnosis = generateEscalationDiagnosis(payload.issues, payload.reviewCycles, payload.lastVerdict);
13864
14022
  eventBus.emit("orchestrator:story-escalated", {
13865
14023
  ...payload,
@@ -14173,6 +14331,7 @@ function createImplementationOrchestrator(deps) {
14173
14331
  if (!noWorktree && _worktreeManager !== void 0 && projectRoot !== void 0) {
14174
14332
  const wt = await _worktreeManager.createWorktree(storyKey);
14175
14333
  effectiveProjectRoot = wt.worktreePath;
14334
+ _storyWorktrees.set(storyKey, wt.worktreePath);
14176
14335
  }
14177
14336
  let _capturedStoryTitle;
14178
14337
  await waitIfPaused();
@@ -14902,6 +15061,10 @@ function createImplementationOrchestrator(deps) {
14902
15061
  ]
14903
15062
  }).trim();
14904
15063
  } catch {}
15064
+ if (baselineHeadSha !== void 0 && runManifest !== null) runManifest.patchStoryState(storyKey, { baseline_sha: baselineHeadSha }).catch((err) => logger$27.warn({
15065
+ err,
15066
+ storyKey
15067
+ }, "patchStoryState(baseline_sha) failed — pipeline continues"));
14905
15068
  try {
14906
15069
  let storyContentForAnalysis = "";
14907
15070
  try {
@@ -15360,6 +15523,49 @@ function createImplementationOrchestrator(deps) {
15360
15523
  }
15361
15524
  }
15362
15525
  }
15526
+ let _devOutputCommitHookFailure;
15527
+ const _commitFirstEligible = !noWorktree && _worktreeManager !== void 0 && effectiveProjectRoot !== void 0 && effectiveProjectRoot !== projectRoot;
15528
+ if (_commitFirstEligible && effectiveProjectRoot !== void 0) {
15529
+ const dirtyNow = await getGitChangedFiles(effectiveProjectRoot);
15530
+ if (dirtyNow.length > 0) if (devStoryWasSuccess) {
15531
+ const earlyCommit = await commitDevStoryOutput(storyKey, _capturedStoryTitle, dirtyNow, effectiveProjectRoot);
15532
+ if (earlyCommit.status === "committed") {
15533
+ logger$27.info({
15534
+ storyKey,
15535
+ sha: earlyCommit.sha,
15536
+ fileCount: earlyCommit.filesStaged.length
15537
+ }, "commit-first: dev-story output committed to story branch");
15538
+ if (runManifest !== null && earlyCommit.sha) runManifest.patchStoryState(storyKey, { commit_sha: earlyCommit.sha }).catch((err) => logger$27.warn({
15539
+ err,
15540
+ storyKey
15541
+ }, "patchStoryState(commit_sha, commit-first) failed — pipeline continues"));
15542
+ } else if (earlyCommit.status === "failed") {
15543
+ _devOutputCommitHookFailure = earlyCommit.stderr;
15544
+ const cp = await checkpointStoryWorktree(storyKey, "dev-story output (deliverable commit rejected by hooks)", effectiveProjectRoot);
15545
+ logger$27.warn({
15546
+ storyKey,
15547
+ checkpoint: cp.status,
15548
+ hookStderr: earlyCommit.stderr.slice(0, 500)
15549
+ }, "commit-first: hooks rejected feat commit — work preserved as wip checkpoint");
15550
+ if (cp.status === "committed" && runManifest !== null && cp.sha) runManifest.patchStoryState(storyKey, { checkpoint_sha: cp.sha }).catch((err) => logger$27.warn({
15551
+ err,
15552
+ storyKey
15553
+ }, "patchStoryState(checkpoint_sha) failed — pipeline continues"));
15554
+ }
15555
+ } else {
15556
+ const cp = await checkpointStoryWorktree(storyKey, "dev-story partial output", effectiveProjectRoot);
15557
+ if (cp.status === "committed") {
15558
+ logger$27.info({
15559
+ storyKey,
15560
+ sha: cp.sha
15561
+ }, "commit-first: partial dev-story output checkpointed");
15562
+ if (runManifest !== null && cp.sha) runManifest.patchStoryState(storyKey, { checkpoint_sha: cp.sha }).catch((err) => logger$27.warn({
15563
+ err,
15564
+ storyKey
15565
+ }, "patchStoryState(checkpoint_sha) failed — pipeline continues"));
15566
+ }
15567
+ }
15568
+ }
15363
15569
  endPhase(storyKey, "dev-story", devStoryModel);
15364
15570
  let _buildPassed = false;
15365
15571
  {
@@ -15871,6 +16077,19 @@ function createImplementationOrchestrator(deps) {
15871
16077
  }
15872
16078
  }
15873
16079
  if (!shouldFallThroughToComplete) {
16080
+ if (effectiveProjectRoot !== void 0 && effectiveProjectRoot !== projectRoot) {
16081
+ const cp = await checkpointStoryWorktree(storyKey, `verification-failed: ${verificationFailReason ?? "tier-a-fail"}`, effectiveProjectRoot);
16082
+ if (cp.status === "committed") {
16083
+ logger$27.info({
16084
+ storyKey,
16085
+ sha: cp.sha
16086
+ }, "verification-failed checkpoint: uncommitted worktree state preserved on story branch");
16087
+ if (runManifest !== null && cp.sha) runManifest.patchStoryState(storyKey, { checkpoint_sha: cp.sha }).catch((err) => logger$27.warn({
16088
+ err,
16089
+ storyKey
16090
+ }, "patchStoryState(checkpoint_sha, verification-failed) failed — pipeline continues"));
16091
+ }
16092
+ }
15874
16093
  updateStory(storyKey, {
15875
16094
  phase: "VERIFICATION_FAILED",
15876
16095
  completedAt: new Date().toISOString()
@@ -15915,6 +16134,242 @@ function createImplementationOrchestrator(deps) {
15915
16134
  await persistState();
15916
16135
  return "completed";
15917
16136
  }
16137
+ async function finalizeStory(completedReviewCycles) {
16138
+ if (!noWorktree && _worktreeManager !== void 0 && _orchestratorStartBranch !== void 0 && projectRoot !== void 0) {
16139
+ const branchName = `${BRANCH_PREFIX}${storyKey}`;
16140
+ if (effectiveProjectRoot !== void 0) {
16141
+ const dirty = await getGitChangedFiles(effectiveProjectRoot);
16142
+ const commitResult = await commitDevStoryOutput(storyKey, _capturedStoryTitle, dirty, effectiveProjectRoot);
16143
+ if (commitResult.status === "no-changes") {
16144
+ if (_devOutputCommitHookFailure !== void 0) {
16145
+ logger$27.error({
16146
+ storyKey,
16147
+ stderr: _devOutputCommitHookFailure
16148
+ }, "deliverable commit was rejected by hooks at dev-story end and was never resolved — escalating");
16149
+ updateStory(storyKey, {
16150
+ phase: "ESCALATED",
16151
+ error: "dev-story-commit-failed",
16152
+ completedAt: new Date().toISOString()
16153
+ });
16154
+ await emitEscalation({
16155
+ storyKey,
16156
+ lastVerdict: "dev-story-commit-failed",
16157
+ reviewCycles: completedReviewCycles,
16158
+ issues: [`substrate auto-commit was rejected by pre-commit hooks at dev-story end and the rejection was never resolved: ${_devOutputCommitHookFailure}`, "The work IS preserved as a wip(story-…) checkpoint on the story branch (hooks bypassed) — it was deliberately not merged."]
16159
+ });
16160
+ await persistState();
16161
+ return "terminal";
16162
+ }
16163
+ let branchAdvancedSinceBaseline = false;
16164
+ if (baselineHeadSha) try {
16165
+ const headNow = execSync("git rev-parse HEAD", {
16166
+ cwd: effectiveProjectRoot,
16167
+ encoding: "utf-8",
16168
+ stdio: [
16169
+ "ignore",
16170
+ "pipe",
16171
+ "pipe"
16172
+ ],
16173
+ timeout: 5e3
16174
+ }).trim();
16175
+ branchAdvancedSinceBaseline = headNow !== baselineHeadSha;
16176
+ } catch {}
16177
+ if (!branchAdvancedSinceBaseline) {
16178
+ logger$27.warn({
16179
+ storyKey,
16180
+ reason: commitResult.reason
16181
+ }, "dev-story produced no committable changes — escalating instead of running merge-to-main on an unchanged branch");
16182
+ updateStory(storyKey, {
16183
+ phase: "ESCALATED",
16184
+ error: `dev-story-no-commit: ${commitResult.reason}`,
16185
+ completedAt: new Date().toISOString()
16186
+ });
16187
+ await emitEscalation({
16188
+ storyKey,
16189
+ lastVerdict: "dev-story-no-commit",
16190
+ reviewCycles: completedReviewCycles,
16191
+ issues: [`dev-story phase reached SHIP_IT but produced no committable changes (reason: ${commitResult.reason})`]
16192
+ });
16193
+ await persistState();
16194
+ return "terminal";
16195
+ }
16196
+ logger$27.info({ storyKey }, "working tree clean at finalize but branch already advanced (commit-first) — proceeding to merge");
16197
+ }
16198
+ if (commitResult.status === "failed") {
16199
+ logger$27.error({
16200
+ storyKey,
16201
+ stderr: commitResult.stderr
16202
+ }, "substrate auto-commit failed — escalating story");
16203
+ updateStory(storyKey, {
16204
+ phase: "ESCALATED",
16205
+ error: "dev-story-commit-failed",
16206
+ completedAt: new Date().toISOString()
16207
+ });
16208
+ await emitEscalation({
16209
+ storyKey,
16210
+ lastVerdict: "dev-story-commit-failed",
16211
+ reviewCycles: completedReviewCycles,
16212
+ issues: [`substrate auto-commit failed: ${commitResult.stderr}`]
16213
+ });
16214
+ await persistState();
16215
+ return "terminal";
16216
+ }
16217
+ let finalizeCommitSha;
16218
+ if (commitResult.status === "committed") {
16219
+ finalizeCommitSha = commitResult.sha || void 0;
16220
+ logger$27.info({
16221
+ storyKey,
16222
+ sha: commitResult.sha,
16223
+ fileCount: commitResult.filesStaged.length
16224
+ }, "substrate auto-committed dev-story output before merge-to-main");
16225
+ } else try {
16226
+ finalizeCommitSha = execSync("git rev-parse HEAD", {
16227
+ cwd: effectiveProjectRoot,
16228
+ encoding: "utf-8",
16229
+ stdio: [
16230
+ "ignore",
16231
+ "pipe",
16232
+ "pipe"
16233
+ ],
16234
+ timeout: 5e3
16235
+ }).trim();
16236
+ } catch {}
16237
+ if (runManifest !== null && finalizeCommitSha) {
16238
+ const statePatch = { commit_sha: finalizeCommitSha };
16239
+ if (storyFilePath !== void 0) try {
16240
+ Object.assign(statePatch, captureReconstructionInput(storyFilePath, storyKey, runManifest.baseDir, runManifest.runId, effectiveProjectRoot));
16241
+ } catch (inputErr) {
16242
+ logger$27.warn({
16243
+ err: inputErr,
16244
+ storyKey
16245
+ }, "reconstruction phase-input capture failed — pipeline continues (commit_sha still recorded)");
16246
+ }
16247
+ try {
16248
+ const dispatchTelemetry = aggregateStoryDispatchTelemetry(_storyAgents.get(storyKey) ?? []);
16249
+ if (dispatchTelemetry.total_turns !== void 0) statePatch.total_turns = dispatchTelemetry.total_turns;
16250
+ if (dispatchTelemetry.total_tokens !== void 0) statePatch.total_tokens = dispatchTelemetry.total_tokens;
16251
+ } catch (telemetryErr) {
16252
+ logger$27.warn({
16253
+ err: telemetryErr,
16254
+ storyKey
16255
+ }, "aggregateStoryDispatchTelemetry failed — pipeline continues (commit_sha still recorded)");
16256
+ }
16257
+ runManifest.patchStoryState(storyKey, statePatch).catch((err) => logger$27.warn({
16258
+ err,
16259
+ storyKey
16260
+ }, "patchStoryState(commit_sha/phase-input/telemetry) failed — pipeline continues"));
16261
+ }
16262
+ }
16263
+ try {
16264
+ const branchSha = execSync(`git rev-parse ${branchName}`, {
16265
+ cwd: effectiveProjectRoot ?? projectRoot,
16266
+ encoding: "utf-8",
16267
+ stdio: [
16268
+ "ignore",
16269
+ "pipe",
16270
+ "pipe"
16271
+ ],
16272
+ timeout: 5e3
16273
+ }).trim();
16274
+ const startSha = execSync(`git rev-parse ${_orchestratorStartBranch}`, {
16275
+ cwd: projectRoot,
16276
+ encoding: "utf-8",
16277
+ stdio: [
16278
+ "ignore",
16279
+ "pipe",
16280
+ "pipe"
16281
+ ],
16282
+ timeout: 5e3
16283
+ }).trim();
16284
+ if (branchSha === startSha) {
16285
+ logger$27.warn({
16286
+ storyKey,
16287
+ branchSha,
16288
+ startSha,
16289
+ branchName
16290
+ }, "merge-to-main gate: branch did not advance from start commit — escalating instead of running a no-op merge");
16291
+ updateStory(storyKey, {
16292
+ phase: "ESCALATED",
16293
+ error: "dev-story-no-commit",
16294
+ completedAt: new Date().toISOString()
16295
+ });
16296
+ await emitEscalation({
16297
+ storyKey,
16298
+ lastVerdict: "dev-story-no-commit",
16299
+ reviewCycles: completedReviewCycles,
16300
+ issues: [`branch ${branchName} did not advance past start commit ${startSha} — merge-to-main would be a no-op`]
16301
+ });
16302
+ await persistState();
16303
+ return "terminal";
16304
+ }
16305
+ } catch (gateErr) {
16306
+ logger$27.warn({
16307
+ storyKey,
16308
+ err: gateErr instanceof Error ? gateErr.message : String(gateErr)
16309
+ }, "merge-to-main pre-flight verification failed — proceeding with merge phase");
16310
+ }
16311
+ logger$27.info({
16312
+ storyKey,
16313
+ branchName,
16314
+ startBranch: _orchestratorStartBranch
16315
+ }, "Invoking merge-to-main phase");
16316
+ let mergeResult;
16317
+ try {
16318
+ mergeResult = await enqueueMerge({
16319
+ storyKey,
16320
+ branchName,
16321
+ startBranch: _orchestratorStartBranch,
16322
+ worktreeManager: _worktreeManager,
16323
+ eventBus,
16324
+ projectRoot
16325
+ });
16326
+ } catch (mergeErr) {
16327
+ const errMsg = mergeErr instanceof Error ? mergeErr.message : String(mergeErr);
16328
+ logger$27.error({
16329
+ storyKey,
16330
+ err: mergeErr
16331
+ }, "merge-to-main phase threw unexpectedly — escalating story");
16332
+ updateStory(storyKey, {
16333
+ phase: "ESCALATED",
16334
+ error: `merge-to-main-error: ${errMsg}`,
16335
+ completedAt: new Date().toISOString()
16336
+ });
16337
+ await emitEscalation({
16338
+ storyKey,
16339
+ lastVerdict: "merge-to-main-error",
16340
+ reviewCycles: completedReviewCycles,
16341
+ issues: [`merge-to-main phase threw: ${errMsg}`]
16342
+ });
16343
+ await persistState();
16344
+ return "terminal";
16345
+ }
16346
+ if (!mergeResult.success) {
16347
+ logger$27.warn({
16348
+ storyKey,
16349
+ branchName,
16350
+ conflictingFiles: mergeResult.conflictingFiles
16351
+ }, "merge-to-main conflict — escalating story with merge-conflict-detected");
16352
+ updateStory(storyKey, {
16353
+ phase: "ESCALATED",
16354
+ error: "merge-conflict-detected",
16355
+ completedAt: new Date().toISOString()
16356
+ });
16357
+ await emitEscalation({
16358
+ storyKey,
16359
+ lastVerdict: "merge-conflict-detected",
16360
+ reviewCycles: completedReviewCycles,
16361
+ issues: [`merge conflict in ${mergeResult.conflictingFiles?.length ?? 0} file(s): ${(mergeResult.conflictingFiles ?? []).join(", ")}`]
16362
+ });
16363
+ await persistState();
16364
+ return "terminal";
16365
+ }
16366
+ logger$27.info({
16367
+ storyKey,
16368
+ branchName
16369
+ }, "merge-to-main phase completed successfully");
16370
+ }
16371
+ return "finalized";
16372
+ }
15918
16373
  while (keepReviewing) {
15919
16374
  await waitIfPaused();
15920
16375
  if (_state !== "RUNNING") return;
@@ -16169,6 +16624,13 @@ function createImplementationOrchestrator(deps) {
16169
16624
  } catch {}
16170
16625
  updateStory(storyKey, { lastVerdict: verdict });
16171
16626
  await persistState();
16627
+ if (runManifest !== null) {
16628
+ const persistedVerdict = reviewResult.agentVerdict ?? verdict;
16629
+ runManifest.patchStoryState(storyKey, { verdict: persistedVerdict }).catch((err) => logger$27.warn({
16630
+ err,
16631
+ storyKey
16632
+ }, "patchStoryState(verdict) failed — pipeline continues"));
16633
+ }
16172
16634
  {
16173
16635
  const totalTokens = reviewResult.tokenUsage ? reviewResult.tokenUsage.input + reviewResult.tokenUsage.output : 0;
16174
16636
  const totalTokensK = totalTokens > 0 ? `${Math.round(totalTokens / 1e3)}K` : "0";
@@ -16309,178 +16771,8 @@ function createImplementationOrchestrator(deps) {
16309
16771
  error: expansionErr instanceof Error ? expansionErr.message : String(expansionErr)
16310
16772
  }, "Test expansion failed — story verdict unchanged");
16311
16773
  }
16312
- if (!noWorktree && _worktreeManager !== void 0 && _orchestratorStartBranch !== void 0 && projectRoot !== void 0) {
16313
- const branchName = `${BRANCH_PREFIX}${storyKey}`;
16314
- if (effectiveProjectRoot !== void 0) {
16315
- const dirty = await getGitChangedFiles(effectiveProjectRoot);
16316
- const commitResult = await commitDevStoryOutput(storyKey, _capturedStoryTitle, dirty, effectiveProjectRoot);
16317
- if (commitResult.status === "no-changes") {
16318
- logger$27.warn({
16319
- storyKey,
16320
- reason: commitResult.reason
16321
- }, "dev-story produced no committable changes — escalating instead of running merge-to-main on an unchanged branch");
16322
- updateStory(storyKey, {
16323
- phase: "ESCALATED",
16324
- error: `dev-story-no-commit: ${commitResult.reason}`,
16325
- completedAt: new Date().toISOString()
16326
- });
16327
- await emitEscalation({
16328
- storyKey,
16329
- lastVerdict: "dev-story-no-commit",
16330
- reviewCycles: completedReviewCycles,
16331
- issues: [`dev-story phase reached SHIP_IT but produced no committable changes (reason: ${commitResult.reason})`]
16332
- });
16333
- await persistState();
16334
- return;
16335
- }
16336
- if (commitResult.status === "failed") {
16337
- logger$27.error({
16338
- storyKey,
16339
- stderr: commitResult.stderr
16340
- }, "substrate auto-commit failed — escalating story");
16341
- updateStory(storyKey, {
16342
- phase: "ESCALATED",
16343
- error: "dev-story-commit-failed",
16344
- completedAt: new Date().toISOString()
16345
- });
16346
- await emitEscalation({
16347
- storyKey,
16348
- lastVerdict: "dev-story-commit-failed",
16349
- reviewCycles: completedReviewCycles,
16350
- issues: [`substrate auto-commit failed: ${commitResult.stderr}`]
16351
- });
16352
- await persistState();
16353
- return;
16354
- }
16355
- logger$27.info({
16356
- storyKey,
16357
- sha: commitResult.sha,
16358
- fileCount: commitResult.filesStaged.length
16359
- }, "substrate auto-committed dev-story output before merge-to-main");
16360
- if (runManifest !== null && commitResult.sha) {
16361
- const statePatch = { commit_sha: commitResult.sha };
16362
- if (storyFilePath !== void 0) try {
16363
- Object.assign(statePatch, captureReconstructionInput(storyFilePath, storyKey, runManifest.baseDir, runManifest.runId, effectiveProjectRoot));
16364
- } catch (inputErr) {
16365
- logger$27.warn({
16366
- err: inputErr,
16367
- storyKey
16368
- }, "reconstruction phase-input capture failed — pipeline continues (commit_sha still recorded)");
16369
- }
16370
- runManifest.patchStoryState(storyKey, statePatch).catch((err) => logger$27.warn({
16371
- err,
16372
- storyKey
16373
- }, "patchStoryState(commit_sha/phase-input) failed — pipeline continues"));
16374
- }
16375
- }
16376
- try {
16377
- const branchSha = execSync(`git rev-parse ${branchName}`, {
16378
- cwd: effectiveProjectRoot ?? projectRoot,
16379
- encoding: "utf-8",
16380
- stdio: [
16381
- "ignore",
16382
- "pipe",
16383
- "pipe"
16384
- ],
16385
- timeout: 5e3
16386
- }).trim();
16387
- const startSha = execSync(`git rev-parse ${_orchestratorStartBranch}`, {
16388
- cwd: projectRoot,
16389
- encoding: "utf-8",
16390
- stdio: [
16391
- "ignore",
16392
- "pipe",
16393
- "pipe"
16394
- ],
16395
- timeout: 5e3
16396
- }).trim();
16397
- if (branchSha === startSha) {
16398
- logger$27.warn({
16399
- storyKey,
16400
- branchSha,
16401
- startSha,
16402
- branchName
16403
- }, "merge-to-main gate: branch did not advance from start commit — escalating instead of running a no-op merge");
16404
- updateStory(storyKey, {
16405
- phase: "ESCALATED",
16406
- error: "dev-story-no-commit",
16407
- completedAt: new Date().toISOString()
16408
- });
16409
- await emitEscalation({
16410
- storyKey,
16411
- lastVerdict: "dev-story-no-commit",
16412
- reviewCycles: completedReviewCycles,
16413
- issues: [`branch ${branchName} did not advance past start commit ${startSha} — merge-to-main would be a no-op`]
16414
- });
16415
- await persistState();
16416
- return;
16417
- }
16418
- } catch (gateErr) {
16419
- logger$27.warn({
16420
- storyKey,
16421
- err: gateErr instanceof Error ? gateErr.message : String(gateErr)
16422
- }, "merge-to-main pre-flight verification failed — proceeding with merge phase");
16423
- }
16424
- logger$27.info({
16425
- storyKey,
16426
- branchName,
16427
- startBranch: _orchestratorStartBranch
16428
- }, "Invoking merge-to-main phase");
16429
- let mergeResult;
16430
- try {
16431
- mergeResult = await enqueueMerge({
16432
- storyKey,
16433
- branchName,
16434
- startBranch: _orchestratorStartBranch,
16435
- worktreeManager: _worktreeManager,
16436
- eventBus,
16437
- projectRoot
16438
- });
16439
- } catch (mergeErr) {
16440
- const errMsg = mergeErr instanceof Error ? mergeErr.message : String(mergeErr);
16441
- logger$27.error({
16442
- storyKey,
16443
- err: mergeErr
16444
- }, "merge-to-main phase threw unexpectedly — escalating story");
16445
- updateStory(storyKey, {
16446
- phase: "ESCALATED",
16447
- error: `merge-to-main-error: ${errMsg}`,
16448
- completedAt: new Date().toISOString()
16449
- });
16450
- await emitEscalation({
16451
- storyKey,
16452
- lastVerdict: "merge-to-main-error",
16453
- reviewCycles: completedReviewCycles,
16454
- issues: [`merge-to-main phase threw: ${errMsg}`]
16455
- });
16456
- await persistState();
16457
- return;
16458
- }
16459
- if (!mergeResult.success) {
16460
- logger$27.warn({
16461
- storyKey,
16462
- branchName,
16463
- conflictingFiles: mergeResult.conflictingFiles
16464
- }, "merge-to-main conflict — escalating story with merge-conflict-detected");
16465
- updateStory(storyKey, {
16466
- phase: "ESCALATED",
16467
- error: "merge-conflict-detected",
16468
- completedAt: new Date().toISOString()
16469
- });
16470
- await emitEscalation({
16471
- storyKey,
16472
- lastVerdict: "merge-conflict-detected",
16473
- reviewCycles: completedReviewCycles,
16474
- issues: [`merge conflict in ${mergeResult.conflictingFiles?.length ?? 0} file(s): ${(mergeResult.conflictingFiles ?? []).join(", ")}`]
16475
- });
16476
- await persistState();
16477
- return;
16478
- }
16479
- logger$27.info({
16480
- storyKey,
16481
- branchName
16482
- }, "merge-to-main phase completed successfully");
16483
- }
16774
+ const finalizeOutcome = await finalizeStory(completedReviewCycles);
16775
+ if (finalizeOutcome === "terminal") return;
16484
16776
  keepReviewing = false;
16485
16777
  return;
16486
16778
  }
@@ -16607,6 +16899,7 @@ function createImplementationOrchestrator(deps) {
16607
16899
  }
16608
16900
  });
16609
16901
  if (outcome === "verification-failed") return;
16902
+ if (await finalizeStory(finalReviewCycles) === "terminal") return;
16610
16903
  keepReviewing = false;
16611
16904
  return;
16612
16905
  }
@@ -16816,6 +17109,7 @@ function createImplementationOrchestrator(deps) {
16816
17109
  }
16817
17110
  });
16818
17111
  if (outcome === "verification-failed") return;
17112
+ if (await finalizeStory(finalReviewCycles) === "terminal") return;
16819
17113
  keepReviewing = false;
16820
17114
  return;
16821
17115
  }
@@ -47442,7 +47736,7 @@ async function runFullPipeline(options) {
47442
47736
  */
47443
47737
  async function emitPreDispatchVersionAdvisory(currentVersion) {
47444
47738
  if (process.env["SUBSTRATE_NO_UPDATE_CHECK"] === "1") return;
47445
- const { createVersionManager } = await import("./version-manager-impl-C7ZhqLX3.js");
47739
+ const { createVersionManager } = await import("./version-manager-impl-CfzcfFwo.js");
47446
47740
  const vm = createVersionManager();
47447
47741
  const result = await vm.checkForUpdates(true);
47448
47742
  const gap = classifyVersionGap(currentVersion, result.latestVersion);
@@ -47539,4 +47833,4 @@ function registerRunCommand(program, version = "0.0.0", projectRoot = process.cw
47539
47833
 
47540
47834
  //#endregion
47541
47835
  export { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR$1 as GLOBSTAR, GitClient, GrammarLoader, Minimatch$1 as Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createGitWorktreeManager, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape$1 as escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, normalizeGraphSummaryToStatus, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runRunAction, runSolutioningPhase, unescape$1 as unescape, validateStopAfterFromConflict, wireNdjsonEmitter };
47542
- //# sourceMappingURL=run-Dbwlb4Md.js.map
47836
+ //# sourceMappingURL=run-eaZG_3rN.js.map