substrate-ai 0.20.84 → 0.20.86

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli/index.js CHANGED
@@ -3,7 +3,7 @@ import { FileStateStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipel
3
3
  import { createLogger } from "../logger-KeHncl-f.js";
4
4
  import { createEventBus } from "../helpers-CElYrONe.js";
5
5
  import { AdapterRegistry, BudgetConfigSchema, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, ConfigError, CostTrackerConfigSchema, DEFAULT_CONFIG, DoltClient, DoltNotInstalled, GlobalSettingsSchema, InMemoryDatabaseAdapter, IngestionServer, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProvidersSchema, RoutingRecommender, STORY_METRICS, TelemetryConfigSchema, addTokenUsage, aggregateTokenUsageForRun, checkDoltInstalled, compareRunMetrics, createAmendmentRun, createConfigSystem, createDecision, createDoltClient, createPipelineRun, getActiveDecisions, getAllCostEntriesFiltered, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRunMetrics, loadParentRunDecisions, supersedeDecision, swallowDebug, tagRunAsBaseline, updatePipelineRun } from "../dist-DCBSXUiX.js";
6
- import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createGitWorktreeManager, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-DsiQdegK.js";
6
+ import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createGitWorktreeManager, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-DtkAIssJ.js";
7
7
  import "../adapter-registry-DIcrxjH8.js";
8
8
  import { RunManifest, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, parseRuntimeProbes, readCurrentRunId, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck } from "../manifest-read-Boipz5aP.js";
9
9
  import "../errors-D7xD-utp.js";
@@ -8436,7 +8436,7 @@ async function runSupervisorAction(options, deps = {}) {
8436
8436
  await initSchema(expAdapter);
8437
8437
  const { runRunAction: runPipeline } = await import(
8438
8438
  /* @vite-ignore */
8439
- "../run-C3XJLgze.js"
8439
+ "../run-DmnPDKr3.js"
8440
8440
  );
8441
8441
  const runStoryFn = async (opts) => {
8442
8442
  const exitCode = await runPipeline({
@@ -2,7 +2,7 @@ import "./health-CuKzY0Fn.js";
2
2
  import "./logger-KeHncl-f.js";
3
3
  import "./helpers-CElYrONe.js";
4
4
  import "./dist-DCBSXUiX.js";
5
- import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-DsiQdegK.js";
5
+ import { normalizeGraphSummaryToStatus, registerRunCommand, resolveMaxReviewCycles, resolveProbeAuthorStateIntegrating, runRunAction, wireNdjsonEmitter } from "./run-DtkAIssJ.js";
6
6
  import "./manifest-read-Boipz5aP.js";
7
7
  import "./routing-DFxoKHDt.js";
8
8
  import "./work-graph-repository-DZyJv5pV.js";
@@ -17,7 +17,7 @@ import { exec, execFile, execFileSync, execSync, spawn } from "node:child_proces
17
17
  import * as path$5 from "node:path";
18
18
  import * as path$4 from "node:path";
19
19
  import * as path$2 from "node:path";
20
- import path, { basename as basename$1, dirname as dirname$1, extname as extname$1, isAbsolute, join as join$1, posix, resolve as resolve$1, win32 } from "node:path";
20
+ import path, { basename as basename$1, dirname as dirname$1, extname as extname$1, isAbsolute, join as join$1, posix, relative, resolve as resolve$1, win32 } from "node:path";
21
21
  import { tmpdir } from "node:os";
22
22
  import { createHash, randomUUID } from "node:crypto";
23
23
  import { z } from "zod";
@@ -6542,7 +6542,7 @@ async function runCreateStory(deps, params) {
6542
6542
  };
6543
6543
  }
6544
6544
  const implementationDecisions = await getImplementationDecisions(deps, pipelineRunId);
6545
- const epicShardContent = getEpicShard(implementationDecisions, epicId, deps.projectRoot, storyKey);
6545
+ const epicShardContent = getEpicShard(implementationDecisions, epicId, deps.parentProjectRoot ?? deps.projectRoot, storyKey);
6546
6546
  let effectiveSourceAcHash = source_ac_hash;
6547
6547
  if (epicShardContent.length > 0) {
6548
6548
  const storySection = extractStorySection(epicShardContent, storyKey);
@@ -7053,7 +7053,7 @@ function getEpicShard(decisions, epicId, projectRoot, storyKey) {
7053
7053
  }, "Story section absent in decisions-store shard — attempting file-based fallback before returning stale shard");
7054
7054
  }
7055
7055
  if (projectRoot) {
7056
- const fallback = readEpicShardFromFile(projectRoot, epicId);
7056
+ const fallback = readEpicShardFromFile(projectRoot, epicId, storyKey);
7057
7057
  if (fallback) {
7058
7058
  logger$21.info({ epicId }, "Using file-based fallback for epic shard");
7059
7059
  if (storyKey) {
@@ -7129,8 +7129,9 @@ async function getArchConstraints$3(deps) {
7129
7129
  }, "Architecture constraints summarized to fit create-story budget");
7130
7130
  return summarized.slice(0, ARCH_CONSTRAINT_MAX_CHARS);
7131
7131
  }
7132
- if (deps.projectRoot) {
7133
- const fallback = readArchConstraintsFromFile(deps.projectRoot);
7132
+ const archRoot = deps.parentProjectRoot ?? deps.projectRoot;
7133
+ if (archRoot) {
7134
+ const fallback = readArchConstraintsFromFile(archRoot);
7134
7135
  if (fallback) {
7135
7136
  logger$21.info("Using file-based fallback for architecture constraints (decisions table empty)");
7136
7137
  return fallback.length > ARCH_CONSTRAINT_MAX_CHARS ? fallback.slice(0, ARCH_CONSTRAINT_MAX_CHARS) + "\n\n[truncated for token budget]" : fallback;
@@ -7158,7 +7159,7 @@ async function getArchConstraints$3(deps) {
7158
7159
  *
7159
7160
  * Returns the matched section content, or empty string if no path matches.
7160
7161
  */
7161
- function readEpicShardFromFile(projectRoot, epicId) {
7162
+ function readEpicShardFromFile(projectRoot, epicId, storyKey) {
7162
7163
  try {
7163
7164
  const candidates = [join$1(projectRoot, "_bmad-output", "planning-artifacts", "epics.md"), join$1(projectRoot, "_bmad-output", "epics.md")];
7164
7165
  const epicsPath = candidates.find((p) => existsSync(p));
@@ -7184,7 +7185,15 @@ function readEpicShardFromFile(projectRoot, epicId) {
7184
7185
  const perEpicPattern = new RegExp(`^epic-${epicNum}-.*\\.md$`);
7185
7186
  const matches = entries.filter((e) => perEpicPattern.test(e)).sort();
7186
7187
  if (matches.length > 0) {
7187
- const perEpicPath = join$1(planningDir, matches[0]);
7188
+ let chosenIdx = 0;
7189
+ if (storyKey !== void 0 && matches.length > 1) for (let i = 0; i < matches.length; i++) {
7190
+ const candidateContent = readFileSync(join$1(planningDir, matches[i]), "utf-8");
7191
+ if (extractStorySection(candidateContent, storyKey) !== null) {
7192
+ chosenIdx = i;
7193
+ break;
7194
+ }
7195
+ }
7196
+ const perEpicPath = join$1(planningDir, matches[chosenIdx]);
7188
7197
  const content = readFileSync(perEpicPath, "utf-8");
7189
7198
  return content.trim();
7190
7199
  }
@@ -7266,6 +7275,137 @@ async function isValidStoryFile(filePath) {
7266
7275
  //#region src/modules/compiled-workflows/git-helpers.ts
7267
7276
  const logger$20 = createLogger("compiled-workflows:git-helpers");
7268
7277
  /**
7278
+ * Commit the agent's working-tree output for a dev-story dispatch.
7279
+ *
7280
+ * Path E Bug #5 (post-v0.20.85): substrate's per-story worktree flow assumed
7281
+ * the dispatched agent would run `git commit` itself. Empirical audit across
7282
+ * substrate + 4 consumer projects (strata, agent-mesh, boardgame-sandbox,
7283
+ * lucky-numbers) found 1 `feat(story-X-Y)` commit total in 2 months — agents
7284
+ * don't reliably commit. Path E's merge-to-main has been a silent no-op
7285
+ * since v0.20.79 because the branch never advanced past the orchestrator's
7286
+ * start commit. Result: pipelines reported succeeded, work was lost on
7287
+ * worktree cleanup.
7288
+ *
7289
+ * Fix: substrate commits programmatically before merge-to-main fires. The
7290
+ * commit captures every uncommitted file under the worktree that isn't
7291
+ * `.gitignored` (git add respects ignore rules) and isn't outside the
7292
+ * worktree boundary (absolute paths to /tmp/... are filtered out so they
7293
+ * don't trip 'fatal: outside repository'). Pre-commit hooks are NOT
7294
+ * bypassed — they exist in the operator's repo for a reason and should
7295
+ * gate substrate-generated commits too. A hook failure surfaces as a
7296
+ * dev-story-no-commit escalation with the hook output as evidence.
7297
+ *
7298
+ * @param storyKey Story key (e.g. "10-2") for the canonical commit-msg pattern
7299
+ * @param storyTitle Title from create-story result (or fallback string)
7300
+ * @param filesModified Files the agent declared (or recovered via git-status fallback)
7301
+ * @param workingDir The worktree path (or projectRoot when --no-worktree)
7302
+ * @returns Structured result for the orchestrator to inspect
7303
+ */
7304
+ async function commitDevStoryOutput(storyKey, storyTitle, filesModified, workingDir) {
7305
+ const insideWorktree = [];
7306
+ for (const p of filesModified) {
7307
+ const abs = isAbsolute(p) ? p : resolve$1(workingDir, p);
7308
+ const rel = relative(workingDir, abs);
7309
+ if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
7310
+ logger$20.debug({
7311
+ path: p,
7312
+ abs,
7313
+ workingDir
7314
+ }, "commitDevStoryOutput: filtered out path outside worktree");
7315
+ continue;
7316
+ }
7317
+ insideWorktree.push(rel);
7318
+ }
7319
+ if (insideWorktree.length === 0) return {
7320
+ status: "no-changes",
7321
+ reason: "no-files-inside-worktree"
7322
+ };
7323
+ try {
7324
+ execSync(`git add ${insideWorktree.map((p) => JSON.stringify(p)).join(" ")}`, {
7325
+ cwd: workingDir,
7326
+ stdio: [
7327
+ "ignore",
7328
+ "pipe",
7329
+ "pipe"
7330
+ ],
7331
+ timeout: 3e4
7332
+ });
7333
+ } catch (err) {
7334
+ const stderr = err instanceof Error && "stderr" in err ? String(err.stderr ?? err.message) : err instanceof Error ? err.message : String(err);
7335
+ return {
7336
+ status: "failed",
7337
+ stderr: `git add failed: ${stderr}`
7338
+ };
7339
+ }
7340
+ const cachedCheck = spawn("git", [
7341
+ "diff",
7342
+ "--cached",
7343
+ "--quiet"
7344
+ ], {
7345
+ cwd: workingDir,
7346
+ stdio: [
7347
+ "ignore",
7348
+ "pipe",
7349
+ "pipe"
7350
+ ]
7351
+ });
7352
+ const cachedStatus = await new Promise((res) => {
7353
+ cachedCheck.on("close", (code) => res(code ?? 0));
7354
+ cachedCheck.on("error", () => res(0));
7355
+ });
7356
+ if (cachedStatus === 0) return {
7357
+ status: "no-changes",
7358
+ reason: "staging-produced-no-diff"
7359
+ };
7360
+ const title = storyTitle ?? "implementation";
7361
+ const message = `feat(story-${storyKey}): ${title}`;
7362
+ try {
7363
+ execSync(`git commit -m ${JSON.stringify(message)}`, {
7364
+ cwd: workingDir,
7365
+ stdio: [
7366
+ "ignore",
7367
+ "pipe",
7368
+ "pipe"
7369
+ ],
7370
+ timeout: 12e4
7371
+ });
7372
+ } catch (err) {
7373
+ const stderr = err instanceof Error && "stderr" in err ? String(err.stderr ?? err.message) : err instanceof Error ? err.message : String(err);
7374
+ return {
7375
+ status: "failed",
7376
+ stderr: `git commit failed: ${stderr}`
7377
+ };
7378
+ }
7379
+ let sha = "";
7380
+ try {
7381
+ sha = execSync("git rev-parse HEAD", {
7382
+ cwd: workingDir,
7383
+ encoding: "utf-8",
7384
+ stdio: [
7385
+ "ignore",
7386
+ "pipe",
7387
+ "pipe"
7388
+ ],
7389
+ timeout: 5e3
7390
+ }).trim();
7391
+ } catch (err) {
7392
+ logger$20.warn({
7393
+ storyKey,
7394
+ err
7395
+ }, "commitDevStoryOutput: commit succeeded but rev-parse HEAD failed");
7396
+ }
7397
+ logger$20.info({
7398
+ storyKey,
7399
+ sha,
7400
+ fileCount: insideWorktree.length
7401
+ }, "commitDevStoryOutput: committed dev-story output");
7402
+ return {
7403
+ status: "committed",
7404
+ sha,
7405
+ filesStaged: insideWorktree
7406
+ };
7407
+ }
7408
+ /**
7269
7409
  * Check whether the repo at `cwd` has at least one commit (HEAD resolves).
7270
7410
  * Returns false for fresh repos with no commits, avoiding `fatal: bad revision 'HEAD'`.
7271
7411
  * Synchronous (execSync) to keep it simple — this is a fast local check.
@@ -13986,6 +14126,7 @@ function createImplementationOrchestrator(deps) {
13986
14126
  const wt = await _worktreeManager.createWorktree(storyKey);
13987
14127
  effectiveProjectRoot = wt.worktreePath;
13988
14128
  }
14129
+ let _capturedStoryTitle;
13989
14130
  await waitIfPaused();
13990
14131
  if (_state !== "RUNNING") return;
13991
14132
  stateStore?.branchForStory(storyKey).catch((err) => logger$27.warn({
@@ -14107,6 +14248,7 @@ function createImplementationOrchestrator(deps) {
14107
14248
  contextCompiler,
14108
14249
  dispatcher,
14109
14250
  projectRoot: effectiveProjectRoot,
14251
+ parentProjectRoot: projectRoot,
14110
14252
  tokenCeilings,
14111
14253
  otlpEndpoint: _otlpEndpoint,
14112
14254
  agentId
@@ -14281,6 +14423,7 @@ function createImplementationOrchestrator(deps) {
14281
14423
  }
14282
14424
  }
14283
14425
  storyFilePath = createResult.story_file;
14426
+ _capturedStoryTitle = createResult.story_title;
14284
14427
  if (createResult.story_title) try {
14285
14428
  const epicId = storyKey.split("-")[0] ?? storyKey;
14286
14429
  const implDecisions = await getDecisionsByPhase(db, "implementation");
@@ -14535,6 +14678,7 @@ function createImplementationOrchestrator(deps) {
14535
14678
  contextCompiler,
14536
14679
  dispatcher,
14537
14680
  projectRoot: effectiveProjectRoot,
14681
+ parentProjectRoot: projectRoot,
14538
14682
  tokenCeilings,
14539
14683
  otlpEndpoint: _otlpEndpoint,
14540
14684
  agentId
@@ -14591,6 +14735,7 @@ function createImplementationOrchestrator(deps) {
14591
14735
  contextCompiler,
14592
14736
  dispatcher,
14593
14737
  projectRoot: effectiveProjectRoot,
14738
+ parentProjectRoot: projectRoot,
14594
14739
  tokenCeilings,
14595
14740
  otlpEndpoint: _otlpEndpoint,
14596
14741
  agentId
@@ -14726,6 +14871,7 @@ function createImplementationOrchestrator(deps) {
14726
14871
  contextCompiler,
14727
14872
  dispatcher,
14728
14873
  projectRoot: effectiveProjectRoot,
14874
+ parentProjectRoot: projectRoot,
14729
14875
  tokenCeilings,
14730
14876
  otlpEndpoint: _otlpEndpoint,
14731
14877
  repoMapInjector,
@@ -14810,6 +14956,7 @@ function createImplementationOrchestrator(deps) {
14810
14956
  contextCompiler,
14811
14957
  dispatcher,
14812
14958
  projectRoot: effectiveProjectRoot,
14959
+ parentProjectRoot: projectRoot,
14813
14960
  tokenCeilings,
14814
14961
  otlpEndpoint: _otlpEndpoint,
14815
14962
  repoMapInjector,
@@ -15490,6 +15637,7 @@ function createImplementationOrchestrator(deps) {
15490
15637
  contextCompiler,
15491
15638
  dispatcher,
15492
15639
  projectRoot: effectiveProjectRoot,
15640
+ parentProjectRoot: projectRoot,
15493
15641
  tokenCeilings,
15494
15642
  otlpEndpoint: _otlpEndpoint,
15495
15643
  repoMapInjector,
@@ -15701,6 +15849,7 @@ function createImplementationOrchestrator(deps) {
15701
15849
  contextCompiler,
15702
15850
  dispatcher,
15703
15851
  projectRoot: effectiveProjectRoot,
15852
+ parentProjectRoot: projectRoot,
15704
15853
  tokenCeilings,
15705
15854
  otlpEndpoint: _otlpEndpoint,
15706
15855
  repoMapInjector,
@@ -15748,6 +15897,7 @@ function createImplementationOrchestrator(deps) {
15748
15897
  contextCompiler,
15749
15898
  dispatcher,
15750
15899
  projectRoot: effectiveProjectRoot,
15900
+ parentProjectRoot: projectRoot,
15751
15901
  tokenCeilings,
15752
15902
  otlpEndpoint: _otlpEndpoint,
15753
15903
  repoMapInjector,
@@ -15997,6 +16147,7 @@ function createImplementationOrchestrator(deps) {
15997
16147
  contextCompiler,
15998
16148
  dispatcher,
15999
16149
  projectRoot: effectiveProjectRoot,
16150
+ parentProjectRoot: projectRoot,
16000
16151
  tokenCeilings,
16001
16152
  otlpEndpoint: _otlpEndpoint,
16002
16153
  agentId
@@ -16027,6 +16178,101 @@ function createImplementationOrchestrator(deps) {
16027
16178
  }
16028
16179
  if (!noWorktree && _worktreeManager !== void 0 && _orchestratorStartBranch !== void 0 && projectRoot !== void 0) {
16029
16180
  const branchName = `${BRANCH_PREFIX}${storyKey}`;
16181
+ if (effectiveProjectRoot !== void 0) {
16182
+ const dirty = await getGitChangedFiles(effectiveProjectRoot);
16183
+ const commitResult = await commitDevStoryOutput(storyKey, _capturedStoryTitle, dirty, effectiveProjectRoot);
16184
+ if (commitResult.status === "no-changes") {
16185
+ logger$27.warn({
16186
+ storyKey,
16187
+ reason: commitResult.reason
16188
+ }, "dev-story produced no committable changes — escalating instead of running merge-to-main on an unchanged branch");
16189
+ updateStory(storyKey, {
16190
+ phase: "ESCALATED",
16191
+ error: `dev-story-no-commit: ${commitResult.reason}`,
16192
+ completedAt: new Date().toISOString()
16193
+ });
16194
+ await emitEscalation({
16195
+ storyKey,
16196
+ lastVerdict: "dev-story-no-commit",
16197
+ reviewCycles: completedReviewCycles,
16198
+ issues: [`dev-story phase completed with verdict ${reviewVerdict} but produced no committable changes (reason: ${commitResult.reason})`]
16199
+ });
16200
+ await persistState();
16201
+ return;
16202
+ }
16203
+ if (commitResult.status === "failed") {
16204
+ logger$27.error({
16205
+ storyKey,
16206
+ stderr: commitResult.stderr
16207
+ }, "substrate auto-commit failed — escalating story");
16208
+ updateStory(storyKey, {
16209
+ phase: "ESCALATED",
16210
+ error: "dev-story-commit-failed",
16211
+ completedAt: new Date().toISOString()
16212
+ });
16213
+ await emitEscalation({
16214
+ storyKey,
16215
+ lastVerdict: "dev-story-commit-failed",
16216
+ reviewCycles: completedReviewCycles,
16217
+ issues: [`substrate auto-commit failed: ${commitResult.stderr}`]
16218
+ });
16219
+ await persistState();
16220
+ return;
16221
+ }
16222
+ logger$27.info({
16223
+ storyKey,
16224
+ sha: commitResult.sha,
16225
+ fileCount: commitResult.filesStaged.length
16226
+ }, "substrate auto-committed dev-story output before merge-to-main");
16227
+ }
16228
+ try {
16229
+ const branchSha = execSync(`git rev-parse ${branchName}`, {
16230
+ cwd: effectiveProjectRoot ?? projectRoot,
16231
+ encoding: "utf-8",
16232
+ stdio: [
16233
+ "ignore",
16234
+ "pipe",
16235
+ "pipe"
16236
+ ],
16237
+ timeout: 5e3
16238
+ }).trim();
16239
+ const startSha = execSync(`git rev-parse ${_orchestratorStartBranch}`, {
16240
+ cwd: projectRoot,
16241
+ encoding: "utf-8",
16242
+ stdio: [
16243
+ "ignore",
16244
+ "pipe",
16245
+ "pipe"
16246
+ ],
16247
+ timeout: 5e3
16248
+ }).trim();
16249
+ if (branchSha === startSha) {
16250
+ logger$27.warn({
16251
+ storyKey,
16252
+ branchSha,
16253
+ startSha,
16254
+ branchName
16255
+ }, "merge-to-main gate: branch did not advance from start commit — escalating instead of running a no-op merge");
16256
+ updateStory(storyKey, {
16257
+ phase: "ESCALATED",
16258
+ error: "dev-story-no-commit",
16259
+ completedAt: new Date().toISOString()
16260
+ });
16261
+ await emitEscalation({
16262
+ storyKey,
16263
+ lastVerdict: "dev-story-no-commit",
16264
+ reviewCycles: completedReviewCycles,
16265
+ issues: [`branch ${branchName} did not advance past start commit ${startSha} — merge-to-main would be a no-op`]
16266
+ });
16267
+ await persistState();
16268
+ return;
16269
+ }
16270
+ } catch (gateErr) {
16271
+ logger$27.warn({
16272
+ storyKey,
16273
+ err: gateErr instanceof Error ? gateErr.message : String(gateErr)
16274
+ }, "merge-to-main pre-flight verification failed — proceeding with merge phase");
16275
+ }
16030
16276
  logger$27.info({
16031
16277
  storyKey,
16032
16278
  branchName,
@@ -47136,4 +47382,4 @@ function registerRunCommand(program, version = "0.0.0", projectRoot = process.cw
47136
47382
 
47137
47383
  //#endregion
47138
47384
  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 };
47139
- //# sourceMappingURL=run-DsiQdegK.js.map
47385
+ //# sourceMappingURL=run-DtkAIssJ.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.20.84",
3
+ "version": "0.20.86",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",