substrate-ai 0.2.19 → 0.2.21

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
@@ -1,11 +1,11 @@
1
1
  #!/usr/bin/env node
2
- import { DatabaseWrapper, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createContextCompiler, createDispatcher, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, findPackageRoot, formatOutput, formatPhaseCompletionSummary, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, registerHealthCommand, registerRunCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, runAnalysisPhase, runMigrations, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-mFmS2pw6.js";
2
+ import { DatabaseWrapper, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createContextCompiler, createDispatcher, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, findPackageRoot, formatOutput, formatPhaseCompletionSummary, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, registerHealthCommand, registerRunCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, runAnalysisPhase, runMigrations, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-BLIgARum.js";
3
3
  import { createLogger, deepMask } from "../logger-D2fS2ccL.js";
4
4
  import { AdapterRegistry, createEventBus } from "../event-bus-BMxhfxfT.js";
5
5
  import { CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, PartialSubstrateConfigSchema, SUPPORTED_CONFIG_FORMAT_VERSIONS, SubstrateConfigSchema, defaultConfigMigrator } from "../version-manager-impl-CZ6KF1Ds.js";
6
6
  import { ConfigError, ConfigIncompatibleFormatError } from "../errors-BPqtzQ4U.js";
7
- import { addTokenUsage, createDecision, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestRun, getTokenUsageSummary, listRequirements, updatePipelineRun } from "../decisions-Dq4cAA2L.js";
8
- import { EXPERIMENT_RESULT, OPERATIONAL_FINDING, STORY_METRICS, aggregateTokenUsageForRun, compareRunMetrics, getBaselineRunMetrics, getRunMetrics, getStoryMetricsForRun, incrementRunRestarts, listRunMetrics, tagRunAsBaseline } from "../operational-CobuCGbM.js";
7
+ import { addTokenUsage, createDecision, createPipelineRun, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestRun, getTokenUsageSummary, listRequirements, updatePipelineRun } from "../decisions-Dq4cAA2L.js";
8
+ import { ESCALATION_DIAGNOSIS, EXPERIMENT_RESULT, OPERATIONAL_FINDING, STORY_METRICS, aggregateTokenUsageForRun, compareRunMetrics, getBaselineRunMetrics, getRunMetrics, getStoryMetricsForRun, incrementRunRestarts, listRunMetrics, tagRunAsBaseline } from "../operational-CnMlvWqc.js";
9
9
  import { abortMerge, createWorktree, getConflictingFiles, getMergedFiles, getOrphanedWorktrees, performMerge, removeBranch, removeWorktree, simulateMerge, verifyGitVersion } from "../git-utils-CtmrZrHS.js";
10
10
  import { registerUpgradeCommand } from "../upgrade-CjjAx5kD.js";
11
11
  import { Command } from "commander";
@@ -324,7 +324,7 @@ const DEFAULT_CONFIG = {
324
324
 
325
325
  //#endregion
326
326
  //#region src/cli/commands/init.ts
327
- const logger$16 = createLogger("init");
327
+ const logger$17 = createLogger("init");
328
328
  const __dirname = dirname(new URL(import.meta.url).pathname);
329
329
  const INIT_EXIT_SUCCESS = 0;
330
330
  const INIT_EXIT_ERROR = 1;
@@ -345,7 +345,7 @@ async function scaffoldBmadFramework(projectRoot, force, outputFormat) {
345
345
  const version = resolveBmadMethodVersion();
346
346
  if (force && bmadExists) process.stderr.write(`Warning: Replacing existing _bmad/ framework with bmad-method@${version}\n`);
347
347
  process.stdout.write(`Scaffolding BMAD framework from bmad-method@${version}\n`);
348
- logger$16.info({
348
+ logger$17.info({
349
349
  version,
350
350
  dest: bmadDest
351
351
  }, "Scaffolding BMAD framework");
@@ -355,7 +355,7 @@ async function scaffoldBmadFramework(projectRoot, force, outputFormat) {
355
355
  const destDir = join(bmadDest, dir);
356
356
  mkdirSync(destDir, { recursive: true });
357
357
  cpSync(srcDir, destDir, { recursive: true });
358
- logger$16.info({
358
+ logger$17.info({
359
359
  dir,
360
360
  dest: destDir
361
361
  }, "Scaffolded BMAD framework directory");
@@ -374,7 +374,7 @@ async function scaffoldBmadFramework(projectRoot, force, outputFormat) {
374
374
  "document_output_language: English"
375
375
  ].join("\n") + "\n";
376
376
  await writeFile(configFile, configStub, "utf8");
377
- logger$16.info({ configFile }, "Generated _bmad/_config/config.yaml stub");
377
+ logger$17.info({ configFile }, "Generated _bmad/_config/config.yaml stub");
378
378
  }
379
379
  }
380
380
  const CLAUDE_MD_START_MARKER = "<!-- substrate:start -->";
@@ -389,7 +389,7 @@ async function scaffoldClaudeMd(projectRoot) {
389
389
  try {
390
390
  sectionContent = await readFile(templatePath, "utf8");
391
391
  } catch {
392
- logger$16.warn({ templatePath }, "CLAUDE.md substrate section template not found; skipping");
392
+ logger$17.warn({ templatePath }, "CLAUDE.md substrate section template not found; skipping");
393
393
  return;
394
394
  }
395
395
  if (!sectionContent.endsWith("\n")) sectionContent += "\n";
@@ -407,7 +407,7 @@ async function scaffoldClaudeMd(projectRoot) {
407
407
  newContent = existingContent + separator + sectionContent;
408
408
  }
409
409
  await writeFile(claudeMdPath, newContent, "utf8");
410
- logger$16.info({ claudeMdPath }, "Wrote substrate section to CLAUDE.md");
410
+ logger$17.info({ claudeMdPath }, "Wrote substrate section to CLAUDE.md");
411
411
  }
412
412
  async function scaffoldStatuslineScript(projectRoot) {
413
413
  const pkgRoot = findPackageRoot(__dirname);
@@ -418,7 +418,7 @@ async function scaffoldStatuslineScript(projectRoot) {
418
418
  try {
419
419
  content = await readFile(templatePath, "utf8");
420
420
  } catch {
421
- logger$16.warn({ templatePath }, "statusline.sh template not found; skipping");
421
+ logger$17.warn({ templatePath }, "statusline.sh template not found; skipping");
422
422
  return;
423
423
  }
424
424
  const claudeDir = join(projectRoot, ".claude");
@@ -426,7 +426,7 @@ async function scaffoldStatuslineScript(projectRoot) {
426
426
  mkdirSync(claudeDir, { recursive: true });
427
427
  await writeFile(statuslinePath, content, "utf8");
428
428
  chmodSync(statuslinePath, 493);
429
- logger$16.info({ statuslinePath }, "Wrote .claude/statusline.sh");
429
+ logger$17.info({ statuslinePath }, "Wrote .claude/statusline.sh");
430
430
  }
431
431
  async function scaffoldClaudeSettings(projectRoot) {
432
432
  const claudeDir = join(projectRoot, ".claude");
@@ -442,7 +442,7 @@ async function scaffoldClaudeSettings(projectRoot) {
442
442
  if (!merged["$schema"]) merged["$schema"] = "https://json.schemastore.org/claude-code-settings.json";
443
443
  mkdirSync(claudeDir, { recursive: true });
444
444
  await writeFile(settingsPath, JSON.stringify(merged, null, 2) + "\n", "utf8");
445
- logger$16.info({ settingsPath }, "Wrote substrate settings to .claude/settings.json");
445
+ logger$17.info({ settingsPath }, "Wrote substrate settings to .claude/settings.json");
446
446
  }
447
447
  function resolveBmadMethodInstallerLibPath(fromDir = __dirname) {
448
448
  try {
@@ -512,7 +512,7 @@ async function compileBmadAgents(bmadDir) {
512
512
  writeFileSync(mdPath, result.xml, "utf-8");
513
513
  compiled++;
514
514
  } catch (compileErr) {
515
- logger$16.debug({
515
+ logger$17.debug({
516
516
  err: compileErr,
517
517
  file
518
518
  }, "Failed to compile agent YAML");
@@ -533,9 +533,9 @@ async function scaffoldClaudeCommands(projectRoot, outputFormat) {
533
533
  const _require = createRequire(join(__dirname, "synthetic.js"));
534
534
  try {
535
535
  const compiledCount = await compileBmadAgents(bmadDir);
536
- if (compiledCount > 0) logger$16.info({ compiledCount }, "Compiled agent YAML files to MD");
536
+ if (compiledCount > 0) logger$17.info({ compiledCount }, "Compiled agent YAML files to MD");
537
537
  } catch (compileErr) {
538
- logger$16.warn({ err: compileErr }, "Agent compilation failed; agent commands may be incomplete");
538
+ logger$17.warn({ err: compileErr }, "Agent compilation failed; agent commands may be incomplete");
539
539
  }
540
540
  const { AgentCommandGenerator } = _require(join(installerLibPath, "ide", "shared", "agent-command-generator.js"));
541
541
  const { WorkflowCommandGenerator } = _require(join(installerLibPath, "ide", "shared", "workflow-command-generator.js"));
@@ -547,7 +547,7 @@ async function scaffoldClaudeCommands(projectRoot, outputFormat) {
547
547
  const manifestGen = new ManifestGenerator();
548
548
  await manifestGen.generateManifests(bmadDir, allModules, [], { ides: ["claude-code"] });
549
549
  } catch (manifestErr) {
550
- logger$16.warn({ err: manifestErr }, "ManifestGenerator failed; workflow/task commands may be incomplete");
550
+ logger$17.warn({ err: manifestErr }, "ManifestGenerator failed; workflow/task commands may be incomplete");
551
551
  }
552
552
  const commandsDir = join(projectRoot, ".claude", "commands");
553
553
  mkdirSync(commandsDir, { recursive: true });
@@ -563,7 +563,7 @@ async function scaffoldClaudeCommands(projectRoot, outputFormat) {
563
563
  const taskToolCount = await taskToolGen.writeDashArtifacts(commandsDir, taskToolArtifacts);
564
564
  const total = agentCount + workflowCount + taskToolCount;
565
565
  if (outputFormat !== "json") process.stdout.write(`Generated ${String(total)} Claude Code commands (${String(agentCount)} agents, ${String(workflowCount)} workflows, ${String(taskToolCount)} tasks/tools)\n`);
566
- logger$16.info({
566
+ logger$17.info({
567
567
  agentCount,
568
568
  workflowCount,
569
569
  taskToolCount,
@@ -573,7 +573,7 @@ async function scaffoldClaudeCommands(projectRoot, outputFormat) {
573
573
  } catch (err) {
574
574
  const msg = err instanceof Error ? err.message : String(err);
575
575
  if (outputFormat !== "json") process.stderr.write(`Warning: .claude/commands/ generation failed: ${msg}\n`);
576
- logger$16.warn({ err }, "scaffoldClaudeCommands failed; init continues");
576
+ logger$17.warn({ err }, "scaffoldClaudeCommands failed; init continues");
577
577
  }
578
578
  }
579
579
  const PROVIDER_DEFAULTS = DEFAULT_CONFIG.providers;
@@ -647,7 +647,7 @@ async function runInitAction(options) {
647
647
  discoveryReport = await registry.discoverAndRegister();
648
648
  } catch (err) {
649
649
  const message = err instanceof Error ? err.message : String(err);
650
- logger$16.error({ err }, "Adapter discovery failed");
650
+ logger$17.error({ err }, "Adapter discovery failed");
651
651
  if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, `Adapter discovery failed: ${message}`) + "\n");
652
652
  else process.stderr.write(` Error: adapter discovery failed — ${message}\n`);
653
653
  return INIT_EXIT_ERROR;
@@ -696,12 +696,12 @@ async function runInitAction(options) {
696
696
  return INIT_EXIT_ERROR;
697
697
  }
698
698
  if (force && existsSync(localManifest)) {
699
- logger$16.info({ pack: packName }, "Replacing existing pack with bundled version");
699
+ logger$17.info({ pack: packName }, "Replacing existing pack with bundled version");
700
700
  process.stderr.write(`Warning: Replacing existing pack '${packName}' with bundled version\n`);
701
701
  }
702
702
  mkdirSync(dirname(packPath), { recursive: true });
703
703
  cpSync(bundledPackPath, packPath, { recursive: true });
704
- logger$16.info({
704
+ logger$17.info({
705
705
  pack: packName,
706
706
  dest: packPath
707
707
  }, "Scaffolded methodology pack");
@@ -754,7 +754,7 @@ async function runInitAction(options) {
754
754
  const msg = err instanceof Error ? err.message : String(err);
755
755
  if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, msg) + "\n");
756
756
  else process.stderr.write(`Error: ${msg}\n`);
757
- logger$16.error({ err }, "init failed");
757
+ logger$17.error({ err }, "init failed");
758
758
  return INIT_EXIT_ERROR;
759
759
  }
760
760
  }
@@ -800,7 +800,7 @@ function formatUnsupportedVersionError(formatType, version, supported) {
800
800
 
801
801
  //#endregion
802
802
  //#region src/modules/config/config-system-impl.ts
803
- const logger$15 = createLogger("config");
803
+ const logger$16 = createLogger("config");
804
804
  function deepMerge(base, override) {
805
805
  const result = { ...base };
806
806
  for (const [key, val] of Object.entries(override)) if (val !== null && val !== void 0 && typeof val === "object" && !Array.isArray(val) && typeof result[key] === "object" && result[key] !== null && !Array.isArray(result[key])) result[key] = deepMerge(result[key], val);
@@ -845,7 +845,7 @@ function readEnvOverrides() {
845
845
  }
846
846
  const parsed = PartialSubstrateConfigSchema.safeParse(overrides);
847
847
  if (!parsed.success) {
848
- logger$15.warn({ errors: parsed.error.issues }, "Invalid environment variable overrides ignored");
848
+ logger$16.warn({ errors: parsed.error.issues }, "Invalid environment variable overrides ignored");
849
849
  return {};
850
850
  }
851
851
  return parsed.data;
@@ -909,7 +909,7 @@ var ConfigSystemImpl = class {
909
909
  throw new ConfigError(`Configuration validation failed:\n${issues}`, { issues: result.error.issues });
910
910
  }
911
911
  this._config = result.data;
912
- logger$15.debug("Configuration loaded successfully");
912
+ logger$16.debug("Configuration loaded successfully");
913
913
  }
914
914
  getConfig() {
915
915
  if (this._config === null) throw new ConfigError("Configuration has not been loaded. Call load() before getConfig().", {});
@@ -972,7 +972,7 @@ var ConfigSystemImpl = class {
972
972
  if (version !== void 0 && typeof version === "string" && !isVersionSupported(version, SUPPORTED_CONFIG_FORMAT_VERSIONS)) if (defaultConfigMigrator.canMigrate(version, CURRENT_CONFIG_FORMAT_VERSION)) {
973
973
  const migrationOutput = defaultConfigMigrator.migrate(rawObj, version, CURRENT_CONFIG_FORMAT_VERSION, filePath);
974
974
  if (migrationOutput.result.success) {
975
- logger$15.info({
975
+ logger$16.info({
976
976
  from: version,
977
977
  to: CURRENT_CONFIG_FORMAT_VERSION,
978
978
  backup: migrationOutput.result.backupPath
@@ -1015,7 +1015,7 @@ function createConfigSystem(options = {}) {
1015
1015
 
1016
1016
  //#endregion
1017
1017
  //#region src/cli/commands/config.ts
1018
- const logger$14 = createLogger("config-cmd");
1018
+ const logger$15 = createLogger("config-cmd");
1019
1019
  const CONFIG_EXIT_SUCCESS = 0;
1020
1020
  const CONFIG_EXIT_ERROR = 1;
1021
1021
  const CONFIG_EXIT_INVALID = 2;
@@ -1041,7 +1041,7 @@ async function runConfigShow(opts = {}) {
1041
1041
  return CONFIG_EXIT_INVALID;
1042
1042
  }
1043
1043
  const message = err instanceof Error ? err.message : String(err);
1044
- logger$14.error({ err }, "Failed to load configuration");
1044
+ logger$15.error({ err }, "Failed to load configuration");
1045
1045
  process.stderr.write(` Error loading configuration: ${message}\n`);
1046
1046
  return CONFIG_EXIT_ERROR;
1047
1047
  }
@@ -1115,7 +1115,7 @@ async function runConfigExport(opts = {}) {
1115
1115
  return CONFIG_EXIT_INVALID;
1116
1116
  }
1117
1117
  const message = err instanceof Error ? err.message : String(err);
1118
- logger$14.error({ err }, "Failed to load configuration");
1118
+ logger$15.error({ err }, "Failed to load configuration");
1119
1119
  process.stderr.write(`Error loading configuration: ${message}\n`);
1120
1120
  return CONFIG_EXIT_ERROR;
1121
1121
  }
@@ -1269,9 +1269,9 @@ function registerConfigCommand(program, _version) {
1269
1269
 
1270
1270
  //#endregion
1271
1271
  //#region src/cli/commands/resume.ts
1272
- const logger$13 = createLogger("resume-cmd");
1272
+ const logger$14 = createLogger("resume-cmd");
1273
1273
  async function runResumeAction(options) {
1274
- const { runId: specifiedRunId, stopAfter, outputFormat, projectRoot, concurrency, pack: packName } = options;
1274
+ const { runId: specifiedRunId, stopAfter, outputFormat, projectRoot, concurrency, pack: packName, registry } = options;
1275
1275
  if (stopAfter !== void 0 && !VALID_PHASES.includes(stopAfter)) {
1276
1276
  const errorMsg = `Invalid phase: "${stopAfter}". Valid phases: ${VALID_PHASES.join(", ")}`;
1277
1277
  if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, errorMsg) + "\n");
@@ -1345,13 +1345,14 @@ async function runResumeAction(options) {
1345
1345
  concurrency,
1346
1346
  outputFormat,
1347
1347
  existingRunId: runId,
1348
- projectRoot
1348
+ projectRoot,
1349
+ registry
1349
1350
  });
1350
1351
  } catch (err) {
1351
1352
  const msg = err instanceof Error ? err.message : String(err);
1352
1353
  if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, msg) + "\n");
1353
1354
  else process.stderr.write(`Error: ${msg}\n`);
1354
- logger$13.error({ err }, "auto resume failed");
1355
+ logger$14.error({ err }, "auto resume failed");
1355
1356
  return 1;
1356
1357
  } finally {
1357
1358
  try {
@@ -1360,7 +1361,7 @@ async function runResumeAction(options) {
1360
1361
  }
1361
1362
  }
1362
1363
  async function runFullPipelineFromPhase(options) {
1363
- const { packName, packPath, dbDir, dbPath, startPhase, stopAfter, concept, concurrency, outputFormat, existingRunId, projectRoot } = options;
1364
+ const { packName, packPath, dbDir, dbPath, startPhase, stopAfter, concept, concurrency, outputFormat, existingRunId, projectRoot, registry: injectedRegistry } = options;
1364
1365
  if (!existsSync(dbDir)) mkdirSync(dbDir, { recursive: true });
1365
1366
  const dbWrapper = new DatabaseWrapper(dbPath);
1366
1367
  try {
@@ -1380,8 +1381,8 @@ async function runFullPipelineFromPhase(options) {
1380
1381
  }
1381
1382
  const eventBus = createEventBus();
1382
1383
  const contextCompiler = createContextCompiler({ db });
1383
- const adapterRegistry = new AdapterRegistry();
1384
- await adapterRegistry.discoverAndRegister();
1384
+ const adapterRegistry = injectedRegistry ?? new AdapterRegistry();
1385
+ if (injectedRegistry === void 0) await adapterRegistry.discoverAndRegister();
1385
1386
  const dispatcher = createDispatcher({
1386
1387
  eventBus,
1387
1388
  adapterRegistry
@@ -1502,7 +1503,7 @@ async function runFullPipelineFromPhase(options) {
1502
1503
  });
1503
1504
  }
1504
1505
  } catch (err) {
1505
- logger$13.warn({ err }, "Failed to record token usage");
1506
+ logger$14.warn({ err }, "Failed to record token usage");
1506
1507
  }
1507
1508
  });
1508
1509
  const storyDecisions = db.prepare(`SELECT description FROM requirements WHERE pipeline_run_id = ? AND source = 'solutioning-phase'`).all(runId);
@@ -1561,7 +1562,7 @@ async function runFullPipelineFromPhase(options) {
1561
1562
  const msg = err instanceof Error ? err.message : String(err);
1562
1563
  if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, msg) + "\n");
1563
1564
  else process.stderr.write(`Error: ${msg}\n`);
1564
- logger$13.error({ err }, "pipeline from phase failed");
1565
+ logger$14.error({ err }, "pipeline from phase failed");
1565
1566
  return 1;
1566
1567
  } finally {
1567
1568
  try {
@@ -1569,7 +1570,7 @@ async function runFullPipelineFromPhase(options) {
1569
1570
  } catch {}
1570
1571
  }
1571
1572
  }
1572
- function registerResumeCommand(program, _version = "0.0.0", projectRoot = process.cwd()) {
1573
+ function registerResumeCommand(program, _version = "0.0.0", projectRoot = process.cwd(), registry) {
1573
1574
  program.command("resume").description("Resume a previously interrupted pipeline run").option("--run-id <id>", "Pipeline run ID to resume (defaults to latest)").option("--pack <name>", "Methodology pack name", "bmad").option("--stop-after <phase>", "Stop pipeline after this phase completes (overrides saved state)").option("--concurrency <n>", "Maximum parallel conflict groups", (v) => parseInt(v, 10), 3).option("--project-root <path>", "Project root directory", projectRoot).option("--output-format <format>", "Output format: human (default) or json", "human").action(async (opts) => {
1574
1575
  const outputFormat = opts.outputFormat === "json" ? "json" : "human";
1575
1576
  const exitCode = await runResumeAction({
@@ -1578,7 +1579,8 @@ function registerResumeCommand(program, _version = "0.0.0", projectRoot = proces
1578
1579
  outputFormat,
1579
1580
  projectRoot: opts.projectRoot,
1580
1581
  concurrency: opts.concurrency,
1581
- pack: opts.pack
1582
+ pack: opts.pack,
1583
+ registry
1582
1584
  });
1583
1585
  process.exitCode = exitCode;
1584
1586
  });
@@ -1586,7 +1588,7 @@ function registerResumeCommand(program, _version = "0.0.0", projectRoot = proces
1586
1588
 
1587
1589
  //#endregion
1588
1590
  //#region src/cli/commands/status.ts
1589
- const logger$12 = createLogger("status-cmd");
1591
+ const logger$13 = createLogger("status-cmd");
1590
1592
  async function runStatusAction(options) {
1591
1593
  const { outputFormat, runId, projectRoot } = options;
1592
1594
  const dbRoot = await resolveMainRepoRoot(projectRoot);
@@ -1663,7 +1665,7 @@ async function runStatusAction(options) {
1663
1665
  const msg = err instanceof Error ? err.message : String(err);
1664
1666
  if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, msg) + "\n");
1665
1667
  else process.stderr.write(`Error: ${msg}\n`);
1666
- logger$12.error({ err }, "status action failed");
1668
+ logger$13.error({ err }, "status action failed");
1667
1669
  return 1;
1668
1670
  } finally {
1669
1671
  try {
@@ -2087,7 +2089,7 @@ Analyze thoroughly and return ONLY the JSON array with no additional text.`;
2087
2089
 
2088
2090
  //#endregion
2089
2091
  //#region src/cli/commands/amend.ts
2090
- const logger$11 = createLogger("amend-cmd");
2092
+ const logger$12 = createLogger("amend-cmd");
2091
2093
  /**
2092
2094
  * Detect and apply supersessions after a phase completes in an amendment run.
2093
2095
  *
@@ -2118,7 +2120,7 @@ function runPostPhaseSupersessionDetection(db, amendmentRunId, currentPhase, han
2118
2120
  });
2119
2121
  } catch (err) {
2120
2122
  const msg = err instanceof Error ? err.message : String(err);
2121
- logger$11.warn({
2123
+ logger$12.warn({
2122
2124
  err,
2123
2125
  originalId: parentMatch.id,
2124
2126
  supersedingId: newDec.id
@@ -2127,7 +2129,7 @@ function runPostPhaseSupersessionDetection(db, amendmentRunId, currentPhase, han
2127
2129
  }
2128
2130
  }
2129
2131
  async function runAmendAction(options) {
2130
- const { concept: conceptArg, conceptFile, runId: specifiedRunId, stopAfter, from: startPhase, projectRoot, pack: packName } = options;
2132
+ const { concept: conceptArg, conceptFile, runId: specifiedRunId, stopAfter, from: startPhase, projectRoot, pack: packName, registry: injectedRegistry } = options;
2131
2133
  let concept;
2132
2134
  if (conceptFile !== void 0 && conceptFile !== "") try {
2133
2135
  concept = await readFile(conceptFile, "utf-8");
@@ -2214,8 +2216,8 @@ async function runAmendAction(options) {
2214
2216
  }
2215
2217
  const eventBus = createEventBus();
2216
2218
  const contextCompiler = createContextCompiler({ db });
2217
- const adapterRegistry = new AdapterRegistry();
2218
- await adapterRegistry.discoverAndRegister();
2219
+ const adapterRegistry = injectedRegistry ?? new AdapterRegistry();
2220
+ if (injectedRegistry === void 0) await adapterRegistry.discoverAndRegister();
2219
2221
  const dispatcher = createDispatcher({
2220
2222
  eventBus,
2221
2223
  adapterRegistry
@@ -2253,7 +2255,7 @@ async function runAmendAction(options) {
2253
2255
  for (let i = startIdx; i < phaseOrder.length; i++) {
2254
2256
  const currentPhase = phaseOrder[i];
2255
2257
  const amendmentContext = handler.loadContextForPhase(currentPhase);
2256
- logger$11.info({
2258
+ logger$12.info({
2257
2259
  phase: currentPhase,
2258
2260
  amendmentContextLen: amendmentContext.length
2259
2261
  }, "Amendment context loaded for phase");
@@ -2373,7 +2375,7 @@ async function runAmendAction(options) {
2373
2375
  } catch (err) {
2374
2376
  const msg = err instanceof Error ? err.message : String(err);
2375
2377
  process.stderr.write(`Error: ${msg}\n`);
2376
- logger$11.error({ err }, "amend failed");
2378
+ logger$12.error({ err }, "amend failed");
2377
2379
  return 1;
2378
2380
  } finally {
2379
2381
  try {
@@ -2381,7 +2383,7 @@ async function runAmendAction(options) {
2381
2383
  } catch {}
2382
2384
  }
2383
2385
  }
2384
- function registerAmendCommand(program, _version = "0.0.0", projectRoot = process.cwd()) {
2386
+ function registerAmendCommand(program, _version = "0.0.0", projectRoot = process.cwd(), registry) {
2385
2387
  program.command("amend").description("Run an amendment pipeline against a completed run and an existing run").option("--concept <text>", "Amendment concept description (inline)").option("--concept-file <path>", "Path to concept file").option("--run-id <id>", "Parent run ID (defaults to latest completed run)").option("--stop-after <phase>", "Stop pipeline after this phase completes").option("--from <phase>", "Start pipeline from this phase").option("--pack <name>", "Methodology pack name", "bmad").option("--project-root <path>", "Project root directory", projectRoot).option("--output-format <format>", "Output format: human (default) or json", "human").action(async (opts) => {
2386
2388
  const exitCode = await runAmendAction({
2387
2389
  concept: opts.concept,
@@ -2390,7 +2392,8 @@ function registerAmendCommand(program, _version = "0.0.0", projectRoot = process
2390
2392
  stopAfter: opts.stopAfter,
2391
2393
  from: opts.from,
2392
2394
  projectRoot: opts.projectRoot,
2393
- pack: opts.pack
2395
+ pack: opts.pack,
2396
+ registry
2394
2397
  });
2395
2398
  process.exitCode = exitCode;
2396
2399
  });
@@ -2828,7 +2831,7 @@ async function runSupervisorAction(options, deps = {}) {
2828
2831
  try {
2829
2832
  const { createExperimenter } = await import(
2830
2833
  /* @vite-ignore */
2831
- "../experimenter-CHRVkV3d.js"
2834
+ "../experimenter-bc40oi8p.js"
2832
2835
  );
2833
2836
  const { getLatestRun: getLatest } = await import(
2834
2837
  /* @vite-ignore */
@@ -2842,7 +2845,7 @@ async function runSupervisorAction(options, deps = {}) {
2842
2845
  const expDb = expDbWrapper.db;
2843
2846
  const { runRunAction: runPipeline } = await import(
2844
2847
  /* @vite-ignore */
2845
- "../run-CUGB4FQx.js"
2848
+ "../run-gmS6DsGT.js"
2846
2849
  );
2847
2850
  const runStoryFn = async (opts) => {
2848
2851
  const exitCode = await runPipeline({
@@ -3085,7 +3088,7 @@ function registerSupervisorCommand(program, _version = "0.0.0", projectRoot = pr
3085
3088
 
3086
3089
  //#endregion
3087
3090
  //#region src/cli/commands/metrics.ts
3088
- const logger$10 = createLogger("metrics-cmd");
3091
+ const logger$11 = createLogger("metrics-cmd");
3089
3092
  async function runMetricsAction(options) {
3090
3093
  const { outputFormat, projectRoot, limit = 10, compare, tagBaseline, analysis } = options;
3091
3094
  if (analysis !== void 0) {
@@ -3237,7 +3240,7 @@ async function runMetricsAction(options) {
3237
3240
  const msg = err instanceof Error ? err.message : String(err);
3238
3241
  if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, msg) + "\n");
3239
3242
  else process.stderr.write(`Error: ${msg}\n`);
3240
- logger$10.error({ err }, "metrics action failed");
3243
+ logger$11.error({ err }, "metrics action failed");
3241
3244
  return 1;
3242
3245
  } finally {
3243
3246
  try {
@@ -3491,7 +3494,7 @@ function getPlanningCostTotal(db, sessionId) {
3491
3494
  function getLatestSessionId(_db) {
3492
3495
  return null;
3493
3496
  }
3494
- const logger$9 = createLogger("cost-cmd");
3497
+ const logger$10 = createLogger("cost-cmd");
3495
3498
  const COST_EXIT_SUCCESS = 0;
3496
3499
  const COST_EXIT_ERROR = 1;
3497
3500
  /**
@@ -3737,7 +3740,7 @@ async function runCostAction(options) {
3737
3740
  } catch (err) {
3738
3741
  const message = err instanceof Error ? err.message : String(err);
3739
3742
  process.stderr.write(`Error: ${message}\n`);
3740
- logger$9.error({ err }, "runCostAction failed");
3743
+ logger$10.error({ err }, "runCostAction failed");
3741
3744
  return COST_EXIT_ERROR;
3742
3745
  } finally {
3743
3746
  if (wrapper !== null) try {
@@ -3839,7 +3842,7 @@ function applyMonitorSchema(db) {
3839
3842
 
3840
3843
  //#endregion
3841
3844
  //#region src/persistence/monitor-database.ts
3842
- const logger$8 = createLogger("persistence:monitor-db");
3845
+ const logger$9 = createLogger("persistence:monitor-db");
3843
3846
  var MonitorDatabaseImpl = class {
3844
3847
  _db = null;
3845
3848
  _path;
@@ -3850,10 +3853,10 @@ var MonitorDatabaseImpl = class {
3850
3853
  this._open();
3851
3854
  }
3852
3855
  _open() {
3853
- logger$8.info({ path: this._path }, "Opening monitor database");
3856
+ logger$9.info({ path: this._path }, "Opening monitor database");
3854
3857
  this._db = new BetterSqlite3(this._path);
3855
3858
  const walResult = this._db.pragma("journal_mode = WAL");
3856
- if (walResult?.[0]?.journal_mode !== "wal") logger$8.warn({ result: walResult?.[0]?.journal_mode }, "Monitor DB: WAL pragma did not confirm wal mode");
3859
+ if (walResult?.[0]?.journal_mode !== "wal") logger$9.warn({ result: walResult?.[0]?.journal_mode }, "Monitor DB: WAL pragma did not confirm wal mode");
3857
3860
  this._db.pragma("synchronous = NORMAL");
3858
3861
  this._db.pragma("busy_timeout = 5000");
3859
3862
  this._db.pragma("foreign_keys = ON");
@@ -3888,7 +3891,7 @@ var MonitorDatabaseImpl = class {
3888
3891
  total_retries = total_retries + @retries,
3889
3892
  last_updated = @lastUpdated
3890
3893
  `);
3891
- logger$8.info({ path: this._path }, "Monitor database ready");
3894
+ logger$9.info({ path: this._path }, "Monitor database ready");
3892
3895
  }
3893
3896
  _assertOpen() {
3894
3897
  if (this._db === null) throw new Error("MonitorDatabase: connection is closed");
@@ -4037,7 +4040,7 @@ var MonitorDatabaseImpl = class {
4037
4040
  const db = this._assertOpen();
4038
4041
  const cutoff = new Date(Date.now() - retentionDays * 24 * 60 * 60 * 1e3).toISOString();
4039
4042
  const result = db.prepare("DELETE FROM task_metrics WHERE recorded_at < @cutoff").run({ cutoff });
4040
- logger$8.info({
4043
+ logger$9.info({
4041
4044
  cutoff,
4042
4045
  deleted: result.changes
4043
4046
  }, "Pruned old task_metrics rows");
@@ -4076,13 +4079,13 @@ var MonitorDatabaseImpl = class {
4076
4079
  db.exec("ROLLBACK");
4077
4080
  throw err;
4078
4081
  }
4079
- logger$8.info("Rebuilt performance_aggregates from task_metrics");
4082
+ logger$9.info("Rebuilt performance_aggregates from task_metrics");
4080
4083
  }
4081
4084
  resetAllData() {
4082
4085
  const db = this._assertOpen();
4083
4086
  db.exec("DELETE FROM task_metrics");
4084
4087
  db.exec("DELETE FROM performance_aggregates");
4085
- logger$8.info({ path: this._path }, "Monitor data reset — all rows deleted");
4088
+ logger$9.info({ path: this._path }, "Monitor data reset — all rows deleted");
4086
4089
  }
4087
4090
  getTaskMetricsDateRange() {
4088
4091
  const db = this._assertOpen();
@@ -4099,7 +4102,7 @@ var MonitorDatabaseImpl = class {
4099
4102
  if (this._db === null) return;
4100
4103
  this._db.close();
4101
4104
  this._db = null;
4102
- logger$8.info({ path: this._path }, "Monitor database closed");
4105
+ logger$9.info({ path: this._path }, "Monitor database closed");
4103
4106
  }
4104
4107
  /**
4105
4108
  * Access the raw underlying database for testing purposes only.
@@ -4112,7 +4115,7 @@ var MonitorDatabaseImpl = class {
4112
4115
 
4113
4116
  //#endregion
4114
4117
  //#region src/modules/monitor/recommendation-engine.ts
4115
- const logger$7 = createLogger("monitor:recommendations");
4118
+ const logger$8 = createLogger("monitor:recommendations");
4116
4119
  var RecommendationEngine = class {
4117
4120
  _monitorDb;
4118
4121
  _filters;
@@ -4145,7 +4148,7 @@ var RecommendationEngine = class {
4145
4148
  const sinceDate = new Date(Date.now() - this._historyDays * 24 * 60 * 60 * 1e3).toISOString();
4146
4149
  const aggregates = this._monitorDb.getAggregates({ sinceDate });
4147
4150
  if (aggregates.length === 0) {
4148
- logger$7.debug("No performance aggregates found — no recommendations to generate");
4151
+ logger$8.debug("No performance aggregates found — no recommendations to generate");
4149
4152
  return [];
4150
4153
  }
4151
4154
  const byTaskType = new Map();
@@ -4210,7 +4213,7 @@ var RecommendationEngine = class {
4210
4213
  if (confDiff !== 0) return confDiff;
4211
4214
  return b.improvement_percentage - a.improvement_percentage;
4212
4215
  });
4213
- logger$7.debug({ count: recommendations.length }, "Generated routing recommendations");
4216
+ logger$8.debug({ count: recommendations.length }, "Generated routing recommendations");
4214
4217
  return recommendations;
4215
4218
  }
4216
4219
  /**
@@ -4376,7 +4379,7 @@ function generateMonitorReport(monitorDb, options = {}) {
4376
4379
 
4377
4380
  //#endregion
4378
4381
  //#region src/cli/commands/monitor.ts
4379
- const logger$6 = createLogger("monitor-cmd");
4382
+ const logger$7 = createLogger("monitor-cmd");
4380
4383
  const MONITOR_EXIT_SUCCESS = 0;
4381
4384
  const MONITOR_EXIT_ERROR = 1;
4382
4385
  /**
@@ -4579,7 +4582,7 @@ async function runMonitorReportAction(options) {
4579
4582
  } catch (err) {
4580
4583
  const message = err instanceof Error ? err.message : String(err);
4581
4584
  process.stderr.write(`Error: ${message}\n`);
4582
- logger$6.error({ err }, "runMonitorReportAction failed");
4585
+ logger$7.error({ err }, "runMonitorReportAction failed");
4583
4586
  return MONITOR_EXIT_ERROR;
4584
4587
  } finally {
4585
4588
  if (monitorDb !== null) try {
@@ -4641,7 +4644,7 @@ async function runMonitorStatusAction(options) {
4641
4644
  } catch (err) {
4642
4645
  const message = err instanceof Error ? err.message : String(err);
4643
4646
  process.stderr.write(`Error: ${message}\n`);
4644
- logger$6.error({ err }, "runMonitorStatusAction failed");
4647
+ logger$7.error({ err }, "runMonitorStatusAction failed");
4645
4648
  return MONITOR_EXIT_ERROR;
4646
4649
  } finally {
4647
4650
  if (monitorDb !== null) try {
@@ -4676,7 +4679,7 @@ async function runMonitorResetAction(options) {
4676
4679
  } catch (err) {
4677
4680
  const message = err instanceof Error ? err.message : String(err);
4678
4681
  process.stderr.write(`Error: ${message}\n`);
4679
- logger$6.error({ err }, "runMonitorResetAction failed");
4682
+ logger$7.error({ err }, "runMonitorResetAction failed");
4680
4683
  return MONITOR_EXIT_ERROR;
4681
4684
  } finally {
4682
4685
  if (monitorDb !== null) try {
@@ -4724,7 +4727,7 @@ async function runMonitorRecommendationsAction(options) {
4724
4727
  } catch (err) {
4725
4728
  const message = err instanceof Error ? err.message : String(err);
4726
4729
  process.stderr.write(`Error: ${message}\n`);
4727
- logger$6.error({ err }, "runMonitorRecommendationsAction failed");
4730
+ logger$7.error({ err }, "runMonitorRecommendationsAction failed");
4728
4731
  return MONITOR_EXIT_ERROR;
4729
4732
  } finally {
4730
4733
  if (monitorDb !== null) try {
@@ -4802,7 +4805,7 @@ function registerMonitorCommand(program, version = "0.0.0", projectRoot = proces
4802
4805
 
4803
4806
  //#endregion
4804
4807
  //#region src/modules/git-worktree/git-worktree-manager-impl.ts
4805
- const logger$5 = createLogger("git-worktree");
4808
+ const logger$6 = createLogger("git-worktree");
4806
4809
  const BRANCH_PREFIX = "substrate/task-";
4807
4810
  const DEFAULT_WORKTREE_BASE = ".substrate-worktrees";
4808
4811
  var GitWorktreeManagerImpl = class {
@@ -4821,7 +4824,7 @@ var GitWorktreeManagerImpl = class {
4821
4824
  this._db = db;
4822
4825
  this._onTaskReady = ({ taskId }) => {
4823
4826
  this._handleTaskReady(taskId).catch((err) => {
4824
- logger$5.error({
4827
+ logger$6.error({
4825
4828
  taskId,
4826
4829
  err
4827
4830
  }, "Unhandled error in _handleTaskReady");
@@ -4835,40 +4838,40 @@ var GitWorktreeManagerImpl = class {
4835
4838
  };
4836
4839
  }
4837
4840
  async initialize() {
4838
- logger$5.info({ projectRoot: this._projectRoot }, "GitWorktreeManager.initialize()");
4841
+ logger$6.info({ projectRoot: this._projectRoot }, "GitWorktreeManager.initialize()");
4839
4842
  await this.verifyGitVersion();
4840
4843
  const cleaned = await this.cleanupAllWorktrees();
4841
- if (cleaned > 0) logger$5.info({ cleaned }, "Recovered orphaned worktrees on startup");
4844
+ if (cleaned > 0) logger$6.info({ cleaned }, "Recovered orphaned worktrees on startup");
4842
4845
  this._eventBus.on("task:ready", this._onTaskReady);
4843
4846
  this._eventBus.on("task:complete", this._onTaskComplete);
4844
4847
  this._eventBus.on("task:failed", this._onTaskFailed);
4845
- logger$5.info("GitWorktreeManager initialized");
4848
+ logger$6.info("GitWorktreeManager initialized");
4846
4849
  }
4847
4850
  async shutdown() {
4848
- logger$5.info("GitWorktreeManager.shutdown()");
4851
+ logger$6.info("GitWorktreeManager.shutdown()");
4849
4852
  this._eventBus.off("task:ready", this._onTaskReady);
4850
4853
  this._eventBus.off("task:complete", this._onTaskComplete);
4851
4854
  this._eventBus.off("task:failed", this._onTaskFailed);
4852
4855
  await this.cleanupAllWorktrees();
4853
- logger$5.info("GitWorktreeManager shutdown complete");
4856
+ logger$6.info("GitWorktreeManager shutdown complete");
4854
4857
  }
4855
4858
  async _handleTaskReady(taskId) {
4856
- logger$5.debug({ taskId }, "task:ready — creating worktree");
4859
+ logger$6.debug({ taskId }, "task:ready — creating worktree");
4857
4860
  try {
4858
4861
  await this.createWorktree(taskId);
4859
4862
  } catch (err) {
4860
- logger$5.error({
4863
+ logger$6.error({
4861
4864
  taskId,
4862
4865
  err
4863
4866
  }, "Failed to create worktree for task");
4864
4867
  }
4865
4868
  }
4866
4869
  async _handleTaskDone(taskId) {
4867
- logger$5.debug({ taskId }, "task done — cleaning up worktree");
4870
+ logger$6.debug({ taskId }, "task done — cleaning up worktree");
4868
4871
  try {
4869
4872
  await this.cleanupWorktree(taskId);
4870
4873
  } catch (err) {
4871
- logger$5.warn({
4874
+ logger$6.warn({
4872
4875
  taskId,
4873
4876
  err
4874
4877
  }, "Failed to cleanup worktree for task");
@@ -4878,7 +4881,7 @@ var GitWorktreeManagerImpl = class {
4878
4881
  if (!taskId || taskId.trim().length === 0) throw new Error("createWorktree: taskId must be a non-empty string");
4879
4882
  const branchName = BRANCH_PREFIX + taskId;
4880
4883
  const worktreePath = this.getWorktreePath(taskId);
4881
- logger$5.debug({
4884
+ logger$6.debug({
4882
4885
  taskId,
4883
4886
  branchName,
4884
4887
  worktreePath,
@@ -4898,7 +4901,7 @@ var GitWorktreeManagerImpl = class {
4898
4901
  worktreePath,
4899
4902
  createdAt
4900
4903
  };
4901
- logger$5.info({
4904
+ logger$6.info({
4902
4905
  taskId,
4903
4906
  branchName,
4904
4907
  worktreePath
@@ -4908,7 +4911,7 @@ var GitWorktreeManagerImpl = class {
4908
4911
  async cleanupWorktree(taskId) {
4909
4912
  const branchName = BRANCH_PREFIX + taskId;
4910
4913
  const worktreePath = this.getWorktreePath(taskId);
4911
- logger$5.debug({
4914
+ logger$6.debug({
4912
4915
  taskId,
4913
4916
  branchName,
4914
4917
  worktreePath
@@ -4918,7 +4921,7 @@ var GitWorktreeManagerImpl = class {
4918
4921
  await access$1(worktreePath);
4919
4922
  worktreeExists = true;
4920
4923
  } catch {
4921
- logger$5.debug({
4924
+ logger$6.debug({
4922
4925
  taskId,
4923
4926
  worktreePath
4924
4927
  }, "cleanupWorktree: worktree does not exist, skipping removal");
@@ -4926,7 +4929,7 @@ var GitWorktreeManagerImpl = class {
4926
4929
  if (worktreeExists) try {
4927
4930
  await removeWorktree(worktreePath, this._projectRoot);
4928
4931
  } catch (err) {
4929
- logger$5.warn({
4932
+ logger$6.warn({
4930
4933
  taskId,
4931
4934
  worktreePath,
4932
4935
  err
@@ -4935,7 +4938,7 @@ var GitWorktreeManagerImpl = class {
4935
4938
  try {
4936
4939
  await removeBranch(branchName, this._projectRoot);
4937
4940
  } catch (err) {
4938
- logger$5.warn({
4941
+ logger$6.warn({
4939
4942
  taskId,
4940
4943
  branchName,
4941
4944
  err
@@ -4945,13 +4948,13 @@ var GitWorktreeManagerImpl = class {
4945
4948
  taskId,
4946
4949
  branchName
4947
4950
  });
4948
- logger$5.info({
4951
+ logger$6.info({
4949
4952
  taskId,
4950
4953
  branchName
4951
4954
  }, "Worktree cleaned up");
4952
4955
  }
4953
4956
  async cleanupAllWorktrees() {
4954
- logger$5.debug({ projectRoot: this._projectRoot }, "cleanupAllWorktrees");
4957
+ logger$6.debug({ projectRoot: this._projectRoot }, "cleanupAllWorktrees");
4955
4958
  const orphanedPaths = await getOrphanedWorktrees(this._projectRoot, this._baseDirectory);
4956
4959
  let cleaned = 0;
4957
4960
  for (const worktreePath of orphanedPaths) {
@@ -4960,12 +4963,12 @@ var GitWorktreeManagerImpl = class {
4960
4963
  try {
4961
4964
  await removeWorktree(worktreePath, this._projectRoot);
4962
4965
  worktreeRemoved = true;
4963
- logger$5.debug({
4966
+ logger$6.debug({
4964
4967
  taskId,
4965
4968
  worktreePath
4966
4969
  }, "cleanupAllWorktrees: removed orphaned worktree");
4967
4970
  } catch (err) {
4968
- logger$5.warn({
4971
+ logger$6.warn({
4969
4972
  taskId,
4970
4973
  worktreePath,
4971
4974
  err
@@ -4975,12 +4978,12 @@ var GitWorktreeManagerImpl = class {
4975
4978
  let branchRemoved = false;
4976
4979
  try {
4977
4980
  branchRemoved = await removeBranch(branchName, this._projectRoot);
4978
- if (branchRemoved) logger$5.debug({
4981
+ if (branchRemoved) logger$6.debug({
4979
4982
  taskId,
4980
4983
  branchName
4981
4984
  }, "cleanupAllWorktrees: removed orphaned branch");
4982
4985
  } catch (err) {
4983
- logger$5.warn({
4986
+ logger$6.warn({
4984
4987
  taskId,
4985
4988
  branchName,
4986
4989
  err
@@ -4988,14 +4991,14 @@ var GitWorktreeManagerImpl = class {
4988
4991
  }
4989
4992
  if (worktreeRemoved) cleaned++;
4990
4993
  }
4991
- if (cleaned > 0) logger$5.info({ cleaned }, "cleanupAllWorktrees: recovered orphaned worktrees");
4994
+ if (cleaned > 0) logger$6.info({ cleaned }, "cleanupAllWorktrees: recovered orphaned worktrees");
4992
4995
  return cleaned;
4993
4996
  }
4994
4997
  async detectConflicts(taskId, targetBranch = "main") {
4995
4998
  if (!taskId || taskId.trim().length === 0) throw new Error("detectConflicts: taskId must be a non-empty string");
4996
4999
  const branchName = BRANCH_PREFIX + taskId;
4997
5000
  const worktreePath = this.getWorktreePath(taskId);
4998
- logger$5.debug({
5001
+ logger$6.debug({
4999
5002
  taskId,
5000
5003
  branchName,
5001
5004
  targetBranch
@@ -5023,7 +5026,7 @@ var GitWorktreeManagerImpl = class {
5023
5026
  branch: branchName,
5024
5027
  conflictingFiles: report.conflictingFiles
5025
5028
  });
5026
- logger$5.info({
5029
+ logger$6.info({
5027
5030
  taskId,
5028
5031
  hasConflicts: report.hasConflicts,
5029
5032
  conflictCount: conflictingFiles.length
@@ -5033,14 +5036,14 @@ var GitWorktreeManagerImpl = class {
5033
5036
  async mergeWorktree(taskId, targetBranch = "main") {
5034
5037
  if (!taskId || taskId.trim().length === 0) throw new Error("mergeWorktree: taskId must be a non-empty string");
5035
5038
  const branchName = BRANCH_PREFIX + taskId;
5036
- logger$5.debug({
5039
+ logger$6.debug({
5037
5040
  taskId,
5038
5041
  branchName,
5039
5042
  targetBranch
5040
5043
  }, "mergeWorktree");
5041
5044
  const conflictReport = await this.detectConflicts(taskId, targetBranch);
5042
5045
  if (conflictReport.hasConflicts) {
5043
- logger$5.info({
5046
+ logger$6.info({
5044
5047
  taskId,
5045
5048
  conflictCount: conflictReport.conflictingFiles.length
5046
5049
  }, "Merge skipped due to conflicts");
@@ -5062,7 +5065,7 @@ var GitWorktreeManagerImpl = class {
5062
5065
  success: true,
5063
5066
  mergedFiles
5064
5067
  };
5065
- logger$5.info({
5068
+ logger$6.info({
5066
5069
  taskId,
5067
5070
  branchName,
5068
5071
  mergedFileCount: mergedFiles.length
@@ -5070,7 +5073,7 @@ var GitWorktreeManagerImpl = class {
5070
5073
  return result;
5071
5074
  }
5072
5075
  async listWorktrees() {
5073
- logger$5.debug({
5076
+ logger$6.debug({
5074
5077
  projectRoot: this._projectRoot,
5075
5078
  baseDirectory: this._baseDirectory
5076
5079
  }, "listWorktrees");
@@ -5094,7 +5097,7 @@ var GitWorktreeManagerImpl = class {
5094
5097
  createdAt
5095
5098
  });
5096
5099
  }
5097
- logger$5.debug({ count: results.length }, "listWorktrees: found worktrees");
5100
+ logger$6.debug({ count: results.length }, "listWorktrees: found worktrees");
5098
5101
  return results;
5099
5102
  }
5100
5103
  getWorktreePath(taskId) {
@@ -5114,7 +5117,7 @@ function createGitWorktreeManager(options) {
5114
5117
 
5115
5118
  //#endregion
5116
5119
  //#region src/cli/commands/merge.ts
5117
- const logger$4 = createLogger("merge-cmd");
5120
+ const logger$5 = createLogger("merge-cmd");
5118
5121
  const MERGE_EXIT_SUCCESS = 0;
5119
5122
  const MERGE_EXIT_CONFLICT = 1;
5120
5123
  const MERGE_EXIT_ERROR = 2;
@@ -5152,7 +5155,7 @@ async function mergeTask(taskId, targetBranch, projectRoot) {
5152
5155
  projectRoot
5153
5156
  });
5154
5157
  try {
5155
- logger$4.info({
5158
+ logger$5.info({
5156
5159
  taskId,
5157
5160
  targetBranch
5158
5161
  }, "Running conflict detection...");
@@ -5174,7 +5177,7 @@ async function mergeTask(taskId, targetBranch, projectRoot) {
5174
5177
  } catch (err) {
5175
5178
  const message = err instanceof Error ? err.message : String(err);
5176
5179
  console.error(`Error merging task "${taskId}": ${message}`);
5177
- logger$4.error({
5180
+ logger$5.error({
5178
5181
  taskId,
5179
5182
  err
5180
5183
  }, "merge --task failed");
@@ -5228,7 +5231,7 @@ async function mergeAll(targetBranch, projectRoot, taskIds) {
5228
5231
  error: message
5229
5232
  });
5230
5233
  console.log(` Error for task "${taskId}": ${message}`);
5231
- logger$4.error({
5234
+ logger$5.error({
5232
5235
  taskId,
5233
5236
  err
5234
5237
  }, "merge --all: task failed");
@@ -5281,7 +5284,7 @@ function registerMergeCommand(program, projectRoot = process.cwd()) {
5281
5284
 
5282
5285
  //#endregion
5283
5286
  //#region src/cli/commands/worktrees.ts
5284
- const logger$3 = createLogger("worktrees-cmd");
5287
+ const logger$4 = createLogger("worktrees-cmd");
5285
5288
  const WORKTREES_EXIT_SUCCESS = 0;
5286
5289
  const WORKTREES_EXIT_ERROR = 1;
5287
5290
  /** Valid task statuses for filtering */
@@ -5408,7 +5411,7 @@ async function listWorktreesAction(options) {
5408
5411
  try {
5409
5412
  worktreeInfos = await manager.listWorktrees();
5410
5413
  } catch (err) {
5411
- logger$3.error({ err }, "Failed to list worktrees");
5414
+ logger$4.error({ err }, "Failed to list worktrees");
5412
5415
  const message = err instanceof Error ? err.message : String(err);
5413
5416
  process.stderr.write(`Error listing worktrees: ${message}\n`);
5414
5417
  return WORKTREES_EXIT_ERROR;
@@ -5435,7 +5438,7 @@ async function listWorktreesAction(options) {
5435
5438
  } catch (err) {
5436
5439
  const message = err instanceof Error ? err.message : String(err);
5437
5440
  process.stderr.write(`Error: ${message}\n`);
5438
- logger$3.error({ err }, "listWorktreesAction failed");
5441
+ logger$4.error({ err }, "listWorktreesAction failed");
5439
5442
  return WORKTREES_EXIT_ERROR;
5440
5443
  }
5441
5444
  }
@@ -5476,7 +5479,7 @@ function registerWorktreesCommand(program, version = "0.0.0", projectRoot = proc
5476
5479
 
5477
5480
  //#endregion
5478
5481
  //#region src/cli/commands/brainstorm.ts
5479
- const logger$2 = createLogger("brainstorm-cmd");
5482
+ const logger$3 = createLogger("brainstorm-cmd");
5480
5483
  /**
5481
5484
  * Detect whether the project has existing planning artifacts that indicate
5482
5485
  * this is an amendment session (vs. a brand-new project brainstorm).
@@ -5522,13 +5525,13 @@ async function loadAmendmentContextDocuments(projectRoot) {
5522
5525
  try {
5523
5526
  brief = await readFile(briefPath, "utf-8");
5524
5527
  } catch {
5525
- logger$2.warn({ briefPath }, "product-brief.md not found — continuing without brief context");
5528
+ logger$3.warn({ briefPath }, "product-brief.md not found — continuing without brief context");
5526
5529
  process.stderr.write(`Warning: product-brief.md not found at ${briefPath}\n`);
5527
5530
  }
5528
5531
  try {
5529
5532
  prd = await readFile(prdPath, "utf-8");
5530
5533
  } catch {
5531
- logger$2.warn({ prdPath }, "requirements.md not found — continuing without PRD context");
5534
+ logger$3.warn({ prdPath }, "requirements.md not found — continuing without PRD context");
5532
5535
  process.stderr.write(`Warning: requirements.md not found at ${prdPath}\n`);
5533
5536
  }
5534
5537
  return {
@@ -5737,7 +5740,7 @@ async function dispatchToPersonas(userPrompt, context, llmDispatch) {
5737
5740
  }
5738
5741
  ];
5739
5742
  const defaultDispatch = async (prompt, personaName) => {
5740
- logger$2.debug({
5743
+ logger$3.debug({
5741
5744
  personaName,
5742
5745
  promptLength: prompt.length
5743
5746
  }, "Dispatching to persona (stub mode)");
@@ -5754,7 +5757,7 @@ async function dispatchToPersonas(userPrompt, context, llmDispatch) {
5754
5757
  };
5755
5758
  } catch (err) {
5756
5759
  const msg = err instanceof Error ? err.message : String(err);
5757
- logger$2.error({
5760
+ logger$3.error({
5758
5761
  err,
5759
5762
  personaName: persona.name
5760
5763
  }, "Persona dispatch failed");
@@ -5906,7 +5909,7 @@ async function runBrainstormSession(options, llmDispatch, rlInterface) {
5906
5909
  }
5907
5910
  });
5908
5911
  rl.on("error", (err) => {
5909
- logger$2.error({ err }, "readline error");
5912
+ logger$3.error({ err }, "readline error");
5910
5913
  if (!sessionEnded) endSession(false);
5911
5914
  });
5912
5915
  });
@@ -6496,7 +6499,7 @@ function renderReadinessReport(decisions) {
6496
6499
 
6497
6500
  //#endregion
6498
6501
  //#region src/cli/commands/export.ts
6499
- const logger$1 = createLogger("export-cmd");
6502
+ const logger$2 = createLogger("export-cmd");
6500
6503
  /**
6501
6504
  * Execute the export action.
6502
6505
  * Returns an exit code (0 = success, 1 = error).
@@ -6623,7 +6626,7 @@ async function runExportAction(options) {
6623
6626
  const msg = err instanceof Error ? err.message : String(err);
6624
6627
  if (outputFormat === "json") process.stdout.write(JSON.stringify({ error: msg }) + "\n");
6625
6628
  else process.stderr.write(`Error: ${msg}\n`);
6626
- logger$1.error({ err }, "export action failed");
6629
+ logger$2.error({ err }, "export action failed");
6627
6630
  return 1;
6628
6631
  } finally {
6629
6632
  if (dbWrapper !== void 0) try {
@@ -6645,6 +6648,220 @@ function registerExportCommand(program, _version = "0.0.0", projectRoot = proces
6645
6648
  });
6646
6649
  }
6647
6650
 
6651
+ //#endregion
6652
+ //#region src/persistence/queries/retry-escalated.ts
6653
+ /**
6654
+ * Query the decision store for escalation-diagnosis decisions and classify
6655
+ * each story key as retryable or skipped.
6656
+ *
6657
+ * Key format in the DB: `{storyKey}:{runId}`
6658
+ *
6659
+ * - When `runId` is provided, only decisions whose key contains that runId
6660
+ * are considered (AC5 scoping).
6661
+ * - When `runId` is omitted, the runId of the last (most recently created)
6662
+ * escalation-diagnosis decision is used as the default (AC1 defaulting).
6663
+ *
6664
+ * @param db The SQLite database connection
6665
+ * @param runId Optional run ID to scope the query
6666
+ */
6667
+ function getRetryableEscalations(db, runId) {
6668
+ const decisions = getDecisionsByCategory(db, ESCALATION_DIAGNOSIS);
6669
+ const result = {
6670
+ retryable: [],
6671
+ skipped: []
6672
+ };
6673
+ if (decisions.length === 0) return result;
6674
+ const parsed = [];
6675
+ for (const decision of decisions) {
6676
+ const colonIdx = decision.key.indexOf(":");
6677
+ if (colonIdx === -1) continue;
6678
+ const storyKey = decision.key.slice(0, colonIdx);
6679
+ const decisionRunId = decision.key.slice(colonIdx + 1);
6680
+ let diagnosis;
6681
+ try {
6682
+ diagnosis = JSON.parse(decision.value);
6683
+ } catch {
6684
+ continue;
6685
+ }
6686
+ parsed.push({
6687
+ storyKey,
6688
+ decisionRunId,
6689
+ diagnosis
6690
+ });
6691
+ }
6692
+ if (parsed.length === 0) return result;
6693
+ const effectiveRunId = runId ?? parsed[parsed.length - 1].decisionRunId;
6694
+ const lastEntryByKey = new Map();
6695
+ for (const entry of parsed) {
6696
+ if (entry.decisionRunId !== effectiveRunId) continue;
6697
+ lastEntryByKey.set(entry.storyKey, entry);
6698
+ }
6699
+ for (const [storyKey, entry] of lastEntryByKey.entries()) {
6700
+ const { recommendedAction } = entry.diagnosis;
6701
+ if (recommendedAction === "retry-targeted") result.retryable.push(storyKey);
6702
+ else if (recommendedAction === "human-intervention") result.skipped.push({
6703
+ key: storyKey,
6704
+ reason: "needs human review"
6705
+ });
6706
+ else if (recommendedAction === "split-story") result.skipped.push({
6707
+ key: storyKey,
6708
+ reason: "story should be split"
6709
+ });
6710
+ }
6711
+ return result;
6712
+ }
6713
+
6714
+ //#endregion
6715
+ //#region src/cli/commands/retry-escalated.ts
6716
+ const logger$1 = createLogger("retry-escalated-cmd");
6717
+ async function runRetryEscalatedAction(options) {
6718
+ const { runId, dryRun, outputFormat, projectRoot, concurrency, pack: packName, registry: injectedRegistry } = options;
6719
+ const dbRoot = await resolveMainRepoRoot(projectRoot);
6720
+ const dbPath = join(dbRoot, ".substrate", "substrate.db");
6721
+ if (!existsSync(dbPath)) {
6722
+ const errorMsg = `Decision store not initialized. Run 'substrate init' first.`;
6723
+ if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, errorMsg) + "\n");
6724
+ else process.stderr.write(`Error: ${errorMsg}\n`);
6725
+ return 1;
6726
+ }
6727
+ const dbWrapper = new DatabaseWrapper(dbPath);
6728
+ try {
6729
+ dbWrapper.open();
6730
+ runMigrations(dbWrapper.db);
6731
+ const db = dbWrapper.db;
6732
+ const { retryable, skipped } = getRetryableEscalations(db, runId);
6733
+ if (retryable.length === 0) {
6734
+ if (outputFormat === "json") process.stdout.write(formatOutput({
6735
+ retryKeys: [],
6736
+ skippedKeys: skipped
6737
+ }, "json", true) + "\n");
6738
+ else process.stdout.write("No retry-targeted escalations found.\n");
6739
+ return 0;
6740
+ }
6741
+ if (dryRun) {
6742
+ if (outputFormat === "json") process.stdout.write(formatOutput({
6743
+ retryKeys: retryable,
6744
+ skippedKeys: skipped
6745
+ }, "json", true) + "\n");
6746
+ else {
6747
+ const count = retryable.length;
6748
+ process.stdout.write(`Retrying: ${count} ${count === 1 ? "story" : "stories"} — ${retryable.join(", ")}\n`);
6749
+ for (const s of skipped) process.stdout.write(`Skipping: ${s.key} (${s.reason})\n`);
6750
+ }
6751
+ return 0;
6752
+ }
6753
+ const packPath = join(projectRoot, "packs", packName);
6754
+ const packLoader = createPackLoader();
6755
+ let pack;
6756
+ try {
6757
+ pack = await packLoader.load(packPath);
6758
+ } catch (err) {
6759
+ const msg = err instanceof Error ? err.message : String(err);
6760
+ const errorMsg = `Methodology pack '${packName}' not found. Run 'substrate init' first.\n${msg}`;
6761
+ if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, errorMsg) + "\n");
6762
+ else process.stderr.write(`Error: ${errorMsg}\n`);
6763
+ return 1;
6764
+ }
6765
+ if (outputFormat === "human") {
6766
+ const count = retryable.length;
6767
+ process.stdout.write(`Retrying: ${count} ${count === 1 ? "story" : "stories"} — ${retryable.join(", ")}\n`);
6768
+ for (const s of skipped) process.stdout.write(`Skipping: ${s.key} (${s.reason})\n`);
6769
+ }
6770
+ const pipelineRun = createPipelineRun(db, {
6771
+ methodology: pack.manifest.name,
6772
+ start_phase: "implementation",
6773
+ config_json: JSON.stringify({
6774
+ storyKeys: retryable,
6775
+ concurrency,
6776
+ retryRun: true
6777
+ })
6778
+ });
6779
+ const eventBus = createEventBus();
6780
+ const contextCompiler = createContextCompiler({ db });
6781
+ const adapterRegistry = injectedRegistry ?? new AdapterRegistry();
6782
+ if (injectedRegistry === void 0) await adapterRegistry.discoverAndRegister();
6783
+ const dispatcher = createDispatcher({
6784
+ eventBus,
6785
+ adapterRegistry
6786
+ });
6787
+ const orchestrator = createImplementationOrchestrator({
6788
+ db,
6789
+ pack,
6790
+ contextCompiler,
6791
+ dispatcher,
6792
+ eventBus,
6793
+ config: {
6794
+ maxConcurrency: concurrency,
6795
+ maxReviewCycles: 2,
6796
+ pipelineRunId: pipelineRun.id
6797
+ },
6798
+ projectRoot
6799
+ });
6800
+ eventBus.on("orchestrator:story-phase-complete", (payload) => {
6801
+ try {
6802
+ const result = payload.result;
6803
+ if (result?.tokenUsage !== void 0) {
6804
+ const { input, output } = result.tokenUsage;
6805
+ const costUsd = (input * 3 + output * 15) / 1e6;
6806
+ addTokenUsage(db, pipelineRun.id, {
6807
+ phase: payload.phase,
6808
+ agent: "claude-code",
6809
+ input_tokens: input,
6810
+ output_tokens: output,
6811
+ cost_usd: costUsd
6812
+ });
6813
+ }
6814
+ } catch (err) {
6815
+ logger$1.warn({ err }, "Failed to record token usage");
6816
+ }
6817
+ });
6818
+ if (outputFormat === "human") {
6819
+ eventBus.on("orchestrator:story-complete", (payload) => {
6820
+ process.stdout.write(` [COMPLETE] ${payload.storyKey} (${payload.reviewCycles} review cycle(s))\n`);
6821
+ });
6822
+ eventBus.on("orchestrator:story-escalated", (payload) => {
6823
+ process.stdout.write(` [ESCALATED] ${payload.storyKey}: ${payload.lastVerdict}\n`);
6824
+ });
6825
+ }
6826
+ await orchestrator.run(retryable);
6827
+ if (outputFormat === "json") process.stdout.write(formatOutput({
6828
+ retryKeys: retryable,
6829
+ skippedKeys: skipped
6830
+ }, "json", true) + "\n");
6831
+ else process.stdout.write("[RETRY] Complete\n");
6832
+ return 0;
6833
+ } catch (err) {
6834
+ const msg = err instanceof Error ? err.message : String(err);
6835
+ if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, msg) + "\n");
6836
+ else process.stderr.write(`Error: ${msg}\n`);
6837
+ logger$1.error({ err }, "retry-escalated failed");
6838
+ return 1;
6839
+ } finally {
6840
+ try {
6841
+ dbWrapper.close();
6842
+ } catch {}
6843
+ }
6844
+ }
6845
+ function registerRetryEscalatedCommand(program, _version = "0.0.0", projectRoot = process.cwd(), registry) {
6846
+ program.command("retry-escalated").description("Retry escalated stories flagged as retry-targeted by escalation diagnosis").option("--run-id <id>", "Scope to a specific pipeline run ID (defaults to latest run with escalations)").option("--dry-run", "Print retryable and skipped stories without invoking the orchestrator").option("--concurrency <n>", "Maximum parallel story executions", (v) => {
6847
+ const n = parseInt(v, 10);
6848
+ if (isNaN(n) || n < 1) throw new Error(`--concurrency must be a positive integer, got: ${v}`);
6849
+ return n;
6850
+ }, 3).option("--pack <name>", "Methodology pack name", "bmad").option("--project-root <path>", "Project root directory", projectRoot).option("--output-format <format>", "Output format: human (default) or json", "human").action(async (opts) => {
6851
+ const outputFormat = opts.outputFormat === "json" ? "json" : "human";
6852
+ const exitCode = await runRetryEscalatedAction({
6853
+ runId: opts.runId,
6854
+ dryRun: opts.dryRun === true,
6855
+ outputFormat,
6856
+ projectRoot: opts.projectRoot,
6857
+ concurrency: opts.concurrency,
6858
+ pack: opts.pack,
6859
+ registry
6860
+ });
6861
+ process.exitCode = exitCode;
6862
+ });
6863
+ }
6864
+
6648
6865
  //#endregion
6649
6866
  //#region src/cli/index.ts
6650
6867
  process.setMaxListeners(20);
@@ -6680,16 +6897,19 @@ async function createProgram() {
6680
6897
  const version = await getPackageVersion();
6681
6898
  const program = new Command();
6682
6899
  program.name("substrate").description("Substrate - Autonomous implementation pipeline for AI coding agents").version(version, "-v, --version", "Output the current version");
6683
- registerAdaptersCommand(program, version);
6900
+ const registry = new AdapterRegistry();
6901
+ await registry.discoverAndRegister();
6902
+ registerAdaptersCommand(program, version, registry);
6684
6903
  registerInitCommand(program, version);
6685
6904
  registerConfigCommand(program, version);
6686
- registerRunCommand(program, version);
6687
- registerResumeCommand(program, version);
6905
+ registerRunCommand(program, version, process.cwd(), registry);
6906
+ registerResumeCommand(program, version, process.cwd(), registry);
6688
6907
  registerStatusCommand(program, version);
6689
- registerAmendCommand(program, version);
6908
+ registerAmendCommand(program, version, process.cwd(), registry);
6690
6909
  registerHealthCommand(program, version);
6691
6910
  registerSupervisorCommand(program, version);
6692
6911
  registerMetricsCommand(program, version);
6912
+ registerRetryEscalatedCommand(program, version, process.cwd(), registry);
6693
6913
  registerCostCommand(program, version);
6694
6914
  registerMonitorCommand(program, version);
6695
6915
  registerMergeCommand(program);