substrate-ai 0.2.10 → 0.2.13

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
@@ -2,7 +2,7 @@
2
2
  import { createLogger, deepMask } from "../logger-C6n1g8uP.js";
3
3
  import { AdapterRegistry, createEventBus } from "../event-bus-J-bw-pkp.js";
4
4
  import { CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, PartialSubstrateConfigSchema, SUPPORTED_CONFIG_FORMAT_VERSIONS, SubstrateConfigSchema, defaultConfigMigrator } from "../version-manager-impl-BpVx2DkY.js";
5
- import { DatabaseWrapper, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createContextCompiler, createDispatcher, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, findPackageRoot, formatOutput, formatPhaseCompletionSummary, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getSubstrateDefaultSettings, parseDbTimestampAsUtc, registerRunCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, runAnalysisPhase, runMigrations, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-XqzHIF6m.js";
5
+ import { DatabaseWrapper, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createContextCompiler, createDispatcher, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, findPackageRoot, formatOutput, formatPhaseCompletionSummary, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getSubstrateDefaultSettings, parseDbTimestampAsUtc, registerRunCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, runAnalysisPhase, runMigrations, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-CoP8UQU3.js";
6
6
  import { ConfigError, ConfigIncompatibleFormatError } from "../errors-BPqtzQ4U.js";
7
7
  import { addTokenUsage, createDecision, getDecisionsByPhaseForRun, getLatestRun, getPipelineRunById, getTokenUsageSummary, listRequirements, updatePipelineRun } from "../decisions-DNYByk0U.js";
8
8
  import { aggregateTokenUsageForRun, compareRunMetrics, getBaselineRunMetrics, getRunMetrics, getStoryMetricsForRun, incrementRunRestarts, listRunMetrics, tagRunAsBaseline } from "../metrics-BSg8VIHd.js";
@@ -2414,16 +2414,24 @@ const DEFAULT_STALL_THRESHOLD_SECONDS = 600;
2414
2414
  * - `node dist/cli/index.js run` (npm run substrate:dev)
2415
2415
  * - `npx substrate run`
2416
2416
  * - any node process whose command contains `run` with `--events` or `--stories`
2417
+ *
2418
+ * When `projectRoot` is provided, additionally checks that the command line
2419
+ * contains that path (via `--project-root` flag or as part of the binary/CWD path).
2420
+ * This ensures multi-project environments match the correct orchestrator.
2417
2421
  */
2418
- function isOrchestratorProcessLine(line) {
2422
+ function isOrchestratorProcessLine(line, projectRoot) {
2419
2423
  if (line.includes("grep")) return false;
2420
- if (line.includes("substrate run")) return true;
2421
- if (line.includes("substrate-ai run")) return true;
2422
- if (line.includes("index.js run")) return true;
2423
- if (line.includes("node") && /\srun(\s|$)/.test(line) && (line.includes("--events") || line.includes("--stories"))) return true;
2424
- return false;
2425
- }
2426
- function inspectProcessTree(execFileSyncOverride) {
2424
+ let isOrchestrator = false;
2425
+ if (line.includes("substrate run")) isOrchestrator = true;
2426
+ else if (line.includes("substrate-ai run")) isOrchestrator = true;
2427
+ else if (line.includes("index.js run")) isOrchestrator = true;
2428
+ else if (line.includes("node") && /\srun(\s|$)/.test(line) && (line.includes("--events") || line.includes("--stories"))) isOrchestrator = true;
2429
+ if (!isOrchestrator) return false;
2430
+ if (projectRoot !== void 0) return line.includes(projectRoot);
2431
+ return true;
2432
+ }
2433
+ function inspectProcessTree(opts) {
2434
+ const { projectRoot, execFileSync: execFileSyncOverride } = opts ?? {};
2427
2435
  const result = {
2428
2436
  orchestrator_pid: null,
2429
2437
  child_pids: [],
@@ -2443,7 +2451,7 @@ function inspectProcessTree(execFileSyncOverride) {
2443
2451
  });
2444
2452
  }
2445
2453
  const lines = psOutput.split("\n");
2446
- for (const line of lines) if (isOrchestratorProcessLine(line)) {
2454
+ for (const line of lines) if (isOrchestratorProcessLine(line, projectRoot)) {
2447
2455
  const match = line.trim().match(/^(\d+)/);
2448
2456
  if (match) {
2449
2457
  result.orchestrator_pid = parseInt(match[1], 10);
@@ -2466,6 +2474,58 @@ function inspectProcessTree(execFileSyncOverride) {
2466
2474
  return result;
2467
2475
  }
2468
2476
  /**
2477
+ * Collect all descendant PIDs of the given root PIDs by walking the process
2478
+ * tree recursively. This ensures that grandchildren of the orchestrator
2479
+ * (e.g. node subprocesses spawned by `claude -p`) are also killed during
2480
+ * stall recovery, leaving no orphan processes.
2481
+ *
2482
+ * Returns only the descendants — the root PIDs themselves are NOT included.
2483
+ */
2484
+ function getAllDescendantPids(rootPids, execFileSyncOverride) {
2485
+ if (rootPids.length === 0) return [];
2486
+ try {
2487
+ let psOutput;
2488
+ if (execFileSyncOverride !== void 0) psOutput = execFileSyncOverride("ps", ["-eo", "pid,ppid"], {
2489
+ encoding: "utf-8",
2490
+ timeout: 5e3
2491
+ });
2492
+ else {
2493
+ const { execFileSync } = __require("node:child_process");
2494
+ psOutput = execFileSync("ps", ["-eo", "pid,ppid"], {
2495
+ encoding: "utf-8",
2496
+ timeout: 5e3
2497
+ });
2498
+ }
2499
+ const childrenOf = new Map();
2500
+ for (const line of psOutput.split("\n")) {
2501
+ const parts = line.trim().split(/\s+/);
2502
+ if (parts.length >= 2) {
2503
+ const pid = parseInt(parts[0], 10);
2504
+ const ppid = parseInt(parts[1], 10);
2505
+ if (!isNaN(pid) && !isNaN(ppid) && pid > 0) {
2506
+ if (!childrenOf.has(ppid)) childrenOf.set(ppid, []);
2507
+ childrenOf.get(ppid).push(pid);
2508
+ }
2509
+ }
2510
+ }
2511
+ const descendants = [];
2512
+ const seen = new Set(rootPids);
2513
+ const queue = [...rootPids];
2514
+ while (queue.length > 0) {
2515
+ const current = queue.shift();
2516
+ const children = childrenOf.get(current) ?? [];
2517
+ for (const child of children) if (!seen.has(child)) {
2518
+ seen.add(child);
2519
+ descendants.push(child);
2520
+ queue.push(child);
2521
+ }
2522
+ }
2523
+ return descendants;
2524
+ } catch {
2525
+ return [];
2526
+ }
2527
+ }
2528
+ /**
2469
2529
  * Fetch pipeline health data as a structured object without any stdout side-effects.
2470
2530
  * Used by runSupervisorAction to poll health without formatting overhead.
2471
2531
  *
@@ -2524,10 +2584,11 @@ async function getAutoHealthData(options) {
2524
2584
  }
2525
2585
  }
2526
2586
  } catch {}
2527
- const processInfo = inspectProcessTree();
2587
+ const processInfo = inspectProcessTree({ projectRoot });
2528
2588
  let verdict = "NO_PIPELINE_RUNNING";
2529
2589
  if (run.status === "running") if (processInfo.orchestrator_pid === null && active === 0 && completed > 0) verdict = "NO_PIPELINE_RUNNING";
2530
2590
  else if (processInfo.zombies.length > 0) verdict = "STALLED";
2591
+ else if (processInfo.orchestrator_pid !== null && processInfo.child_pids.length > 0 && stalenessSeconds > DEFAULT_STALL_THRESHOLD_SECONDS) verdict = "HEALTHY";
2531
2592
  else if (stalenessSeconds > DEFAULT_STALL_THRESHOLD_SECONDS) verdict = "STALLED";
2532
2593
  else if (processInfo.orchestrator_pid !== null && processInfo.child_pids.length === 0 && active > 0) verdict = "STALLED";
2533
2594
  else verdict = "HEALTHY";
@@ -2660,6 +2721,7 @@ function defaultSupervisorDeps() {
2660
2721
  };
2661
2722
  }
2662
2723
  },
2724
+ getAllDescendants: (rootPids) => getAllDescendantPids(rootPids),
2663
2725
  runAnalysis: async (runId, projectRoot) => {
2664
2726
  const dbPath = join(projectRoot, ".substrate", "substrate.db");
2665
2727
  if (!existsSync(dbPath)) return;
@@ -2701,7 +2763,7 @@ function defaultSupervisorDeps() {
2701
2763
  */
2702
2764
  async function runSupervisorAction(options, deps = {}) {
2703
2765
  const { pollInterval, stallThreshold, maxRestarts, outputFormat, projectRoot, runId, pack, experiment, maxExperiments } = options;
2704
- const { getHealth, killPid, resumePipeline, sleep, incrementRestarts, runAnalysis, getTokenSnapshot } = {
2766
+ const { getHealth, killPid, resumePipeline, sleep, incrementRestarts, runAnalysis, getTokenSnapshot, getAllDescendants } = {
2705
2767
  ...defaultSupervisorDeps(),
2706
2768
  ...deps
2707
2769
  };
@@ -2833,7 +2895,7 @@ async function runSupervisorAction(options, deps = {}) {
2833
2895
  const expDb = expDbWrapper.db;
2834
2896
  const { runRunAction: runPipeline } = await import(
2835
2897
  /* @vite-ignore */
2836
- "../run-CDdKFwfI.js"
2898
+ "../run-B9IglY4m.js"
2837
2899
  );
2838
2900
  const runStoryFn = async (opts) => {
2839
2901
  const exitCode = await runPipeline({
@@ -2899,7 +2961,10 @@ async function runSupervisorAction(options, deps = {}) {
2899
2961
  return failed.length > 0 || escalated.length > 0 ? 1 : 0;
2900
2962
  }
2901
2963
  if (health.staleness_seconds >= stallThreshold) {
2902
- const pids = [...health.process.orchestrator_pid !== null ? [health.process.orchestrator_pid] : [], ...health.process.child_pids];
2964
+ const directPids = [...health.process.orchestrator_pid !== null ? [health.process.orchestrator_pid] : [], ...health.process.child_pids];
2965
+ const descendantPids = getAllDescendants(directPids);
2966
+ const directPidSet = new Set(directPids);
2967
+ const pids = [...directPids, ...descendantPids.filter((p) => !directPidSet.has(p))];
2903
2968
  emitEvent({
2904
2969
  type: "supervisor:kill",
2905
2970
  run_id: health.run_id,
@@ -2973,6 +3038,7 @@ async function runSupervisorAction(options, deps = {}) {
2973
3038
  function registerSupervisorCommand(program, _version = "0.0.0", projectRoot = process.cwd()) {
2974
3039
  program.command("supervisor").description("Monitor a pipeline run and automatically recover from stalls").option("--poll-interval <seconds>", "Health poll interval in seconds", (v) => parseInt(v, 10), 60).option("--stall-threshold <seconds>", "Staleness in seconds before killing a stalled pipeline", (v) => parseInt(v, 10), 600).option("--max-restarts <n>", "Maximum automatic restarts before aborting", (v) => parseInt(v, 10), 3).option("--run-id <id>", "Pipeline run ID to monitor (defaults to latest)").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").option("--experiment", "After post-run analysis, enter experiment mode: create branches, apply modifications, run single-story experiments, and report verdicts (Story 17-4)", false).option("--max-experiments <n>", "Maximum number of experiments to run per analysis cycle (default: 2, Story 17-4 AC6)", (v) => parseInt(v, 10), 2).action(async (opts) => {
2975
3040
  const outputFormat = opts.outputFormat === "json" ? "json" : "human";
3041
+ if (opts.stallThreshold < 120) console.warn(`Warning: --stall-threshold ${opts.stallThreshold}s is below 120s. Agent steps typically take 45-90s. This may cause false stall detections and wasted restarts.`);
2976
3042
  const exitCode = await runSupervisorAction({
2977
3043
  pollInterval: opts.pollInterval,
2978
3044
  stallThreshold: opts.stallThreshold,
package/dist/index.d.ts CHANGED
@@ -1025,6 +1025,8 @@ interface OrchestratorEvents {
1025
1025
  storyKey: string;
1026
1026
  phase: string;
1027
1027
  elapsedMs: number;
1028
+ /** PID of the stalled child process, or null if not tracked */
1029
+ childPid: number | null;
1028
1030
  };
1029
1031
  /** Readiness check has completed — emitted for all verdicts (READY, NEEDS_WORK, NOT_READY) */
1030
1032
  'solutioning:readiness-check': {
@@ -1,6 +1,6 @@
1
1
  import "./logger-C6n1g8uP.js";
2
2
  import "./event-bus-J-bw-pkp.js";
3
- import { registerRunCommand, runRunAction } from "./run-XqzHIF6m.js";
3
+ import { registerRunCommand, runRunAction } from "./run-CoP8UQU3.js";
4
4
  import "./decisions-DNYByk0U.js";
5
5
  import "./metrics-BSg8VIHd.js";
6
6
 
@@ -1202,6 +1202,15 @@ function buildPipelineStatusOutput(run, tokenSummary, decisionsCount, storiesCou
1202
1202
  totalOutput += row.total_output_tokens;
1203
1203
  totalCost += row.total_cost_usd;
1204
1204
  }
1205
+ let activeDispatches = 0;
1206
+ try {
1207
+ if (run.token_usage_json) {
1208
+ const state = JSON.parse(run.token_usage_json);
1209
+ if (state.stories) {
1210
+ for (const s of Object.values(state.stories)) if (s.phase !== "PENDING" && s.phase !== "COMPLETE" && s.phase !== "ESCALATED") activeDispatches++;
1211
+ }
1212
+ }
1213
+ } catch {}
1205
1214
  return {
1206
1215
  run_id: run.id,
1207
1216
  current_phase: currentPhase,
@@ -1214,7 +1223,9 @@ function buildPipelineStatusOutput(run, tokenSummary, decisionsCount, storiesCou
1214
1223
  decisions_count: decisionsCount,
1215
1224
  stories_count: storiesCount,
1216
1225
  last_activity: run.updated_at,
1217
- staleness_seconds: Math.round((Date.now() - parseDbTimestampAsUtc(run.updated_at).getTime()) / 1e3)
1226
+ staleness_seconds: Math.round((Date.now() - parseDbTimestampAsUtc(run.updated_at).getTime()) / 1e3),
1227
+ last_event_ts: run.updated_at,
1228
+ active_dispatches: activeDispatches
1218
1229
  };
1219
1230
  }
1220
1231
  /**
@@ -2215,10 +2226,14 @@ Options:
2215
2226
  - \`--stories <keys>\` — Comma-separated story keys to process (e.g., \`7-1,7-2\`)
2216
2227
  - \`--verbose\` — Enable verbose logging output
2217
2228
  - \`--pack <name>\` — Methodology pack name (default: bmad)
2218
- - \`--from <phase>\` — Start from this phase: analysis, planning, solutioning, implementation
2229
+ - \`--from <phase>\` — Start from this phase: research, analysis, planning, solutioning, implementation
2219
2230
  - \`--stop-after <phase>\` — Stop pipeline after this phase completes
2220
2231
  - \`--concurrency <n>\` — Maximum parallel conflict groups (default: 3)
2221
2232
  - \`--output-format <format>\` — Output format: human (default) or json
2233
+ - \`--concept <text>\` — Inline concept text (required when --from analysis)
2234
+ - \`--research\` — Enable the research phase even if not set in the pack config
2235
+ - \`--skip-research\` — Skip the research phase even if enabled in the pack config
2236
+ - \`--skip-ux\` — Skip the UX design phase even if enabled in the pack config
2222
2237
  - \`--help-agent\` — Print this agent instruction fragment and exit
2223
2238
 
2224
2239
  Examples:
@@ -2285,12 +2300,51 @@ Options:
2285
2300
  - \`--analysis <run-id>\` — Read and output the analysis report with optimization recommendations for a specific run
2286
2301
  - \`--output-format <format>\` — Output format: human (default) or json
2287
2302
 
2303
+ ### substrate export
2304
+ Export decision store contents as human-readable markdown files.
2305
+
2306
+ \`\`\`
2307
+ substrate export [options]
2308
+ \`\`\`
2309
+
2310
+ Options:
2311
+ - \`--run-id <id>\` — Pipeline run ID to export (defaults to latest run)
2312
+ - \`--output-dir <path>\` — Directory to write exported files to (default: _bmad-output/planning-artifacts/)
2313
+ - \`--output-format <format>\` — Output format: human (default) or json
2314
+
2288
2315
  ### substrate health
2289
2316
  Check pipeline health, stall detection, and process status.
2290
2317
 
2291
2318
  \`\`\`
2292
2319
  substrate health [--output-format json]
2293
2320
  \`\`\`
2321
+
2322
+ ### substrate cost
2323
+ Show cost breakdown for the current session.
2324
+
2325
+ \`\`\`
2326
+ substrate cost [--output-format json]
2327
+ \`\`\`
2328
+
2329
+ ### substrate amend
2330
+ Run an amendment pipeline against a completed run.
2331
+
2332
+ \`\`\`
2333
+ substrate amend [options]
2334
+ \`\`\`
2335
+
2336
+ ### substrate brainstorm
2337
+ Interactive multi-persona brainstorm session with Pragmatic Engineer, Product Thinker, and Devil's Advocate.
2338
+
2339
+ \`\`\`
2340
+ substrate brainstorm [options]
2341
+ \`\`\`
2342
+
2343
+ Session commands: \`!wrap\` (save & exit), \`!quit\` (exit without saving), \`!help\`
2344
+
2345
+ ## Environment Variables
2346
+
2347
+ - \`SUBSTRATE_MEMORY_THRESHOLD_MB\` — Override the free-memory threshold (in MB) for agent dispatch. Default: 512. On macOS, the conservative memory detection may report low availability even when ample RAM exists. Lower this (e.g., 256) if pipelines stall due to memory pressure false positives.
2294
2348
  `;
2295
2349
  }
2296
2350
  /**
@@ -2842,7 +2896,14 @@ const logger$12 = createLogger("agent-dispatch");
2842
2896
  const SHUTDOWN_GRACE_MS = 1e4;
2843
2897
  const SHUTDOWN_MAX_WAIT_MS = 3e4;
2844
2898
  const CHARS_PER_TOKEN = 4;
2845
- const MIN_FREE_MEMORY_BYTES = 512 * 1024 * 1024;
2899
+ const MIN_FREE_MEMORY_BYTES = (() => {
2900
+ const envMB = process.env.SUBSTRATE_MEMORY_THRESHOLD_MB;
2901
+ if (envMB) {
2902
+ const parsed = parseInt(envMB, 10);
2903
+ if (!isNaN(parsed) && parsed >= 0) return parsed * 1024 * 1024;
2904
+ }
2905
+ return 512 * 1024 * 1024;
2906
+ })();
2846
2907
  const MEMORY_PRESSURE_POLL_MS = 1e4;
2847
2908
  /**
2848
2909
  * Get available system memory in bytes, accounting for platform differences.
@@ -5309,6 +5370,7 @@ function createImplementationOrchestrator(deps) {
5309
5370
  let _heartbeatTimer = null;
5310
5371
  const HEARTBEAT_INTERVAL_MS = 3e4;
5311
5372
  const WATCHDOG_TIMEOUT_MS = 6e5;
5373
+ const _stalledStories = new Set();
5312
5374
  const _phaseStartMs = new Map();
5313
5375
  const _phaseEndMs = new Map();
5314
5376
  const _storyDispatches = new Map();
@@ -5404,6 +5466,7 @@ function createImplementationOrchestrator(deps) {
5404
5466
  }
5405
5467
  function recordProgress() {
5406
5468
  _lastProgressTs = Date.now();
5469
+ _stalledStories.clear();
5407
5470
  }
5408
5471
  function startHeartbeat() {
5409
5472
  if (_heartbeatTimer !== null) return;
@@ -5415,7 +5478,8 @@ function createImplementationOrchestrator(deps) {
5415
5478
  for (const s of _stories.values()) if (s.phase === "COMPLETE" || s.phase === "ESCALATED") completed++;
5416
5479
  else if (s.phase === "PENDING") queued++;
5417
5480
  else active++;
5418
- eventBus.emit("orchestrator:heartbeat", {
5481
+ const timeSinceProgress = Date.now() - _lastProgressTs;
5482
+ if (timeSinceProgress >= HEARTBEAT_INTERVAL_MS) eventBus.emit("orchestrator:heartbeat", {
5419
5483
  runId: config.pipelineRunId ?? "",
5420
5484
  activeDispatches: active,
5421
5485
  completedDispatches: completed,
@@ -5424,6 +5488,8 @@ function createImplementationOrchestrator(deps) {
5424
5488
  const elapsed = Date.now() - _lastProgressTs;
5425
5489
  if (elapsed >= WATCHDOG_TIMEOUT_MS) {
5426
5490
  for (const [key, s] of _stories) if (s.phase !== "PENDING" && s.phase !== "COMPLETE" && s.phase !== "ESCALATED") {
5491
+ if (_stalledStories.has(key)) continue;
5492
+ _stalledStories.add(key);
5427
5493
  logger$16.warn({
5428
5494
  storyKey: key,
5429
5495
  phase: s.phase,
@@ -5433,7 +5499,8 @@ function createImplementationOrchestrator(deps) {
5433
5499
  runId: config.pipelineRunId ?? "",
5434
5500
  storyKey: key,
5435
5501
  phase: s.phase,
5436
- elapsedMs: elapsed
5502
+ elapsedMs: elapsed,
5503
+ childPid: null
5437
5504
  });
5438
5505
  }
5439
5506
  }
@@ -6194,7 +6261,7 @@ function createImplementationOrchestrator(deps) {
6194
6261
  });
6195
6262
  persistState();
6196
6263
  recordProgress();
6197
- startHeartbeat();
6264
+ if (config.enableHeartbeat) startHeartbeat();
6198
6265
  if (projectRoot !== void 0) {
6199
6266
  const seedResult = seedMethodologyContext(db, projectRoot);
6200
6267
  if (seedResult.decisionsCreated > 0) logger$16.info({
@@ -10647,7 +10714,8 @@ async function runRunAction(options) {
10647
10714
  run_id: payload.runId,
10648
10715
  story_key: payload.storyKey,
10649
10716
  phase: payload.phase,
10650
- elapsed_ms: payload.elapsedMs
10717
+ elapsed_ms: payload.elapsedMs,
10718
+ child_pid: payload.childPid
10651
10719
  });
10652
10720
  });
10653
10721
  }
@@ -10660,7 +10728,8 @@ async function runRunAction(options) {
10660
10728
  config: {
10661
10729
  maxConcurrency: concurrency,
10662
10730
  maxReviewCycles: 2,
10663
- pipelineRunId: pipelineRun.id
10731
+ pipelineRunId: pipelineRun.id,
10732
+ enableHeartbeat: eventsFlag === true
10664
10733
  },
10665
10734
  projectRoot
10666
10735
  });
@@ -11103,4 +11172,4 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
11103
11172
 
11104
11173
  //#endregion
11105
11174
  export { DatabaseWrapper, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createContextCompiler, createDispatcher, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, findPackageRoot, formatOutput, formatPhaseCompletionSummary, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getSubstrateDefaultSettings, parseDbTimestampAsUtc, registerRunCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, runAnalysisPhase, runMigrations, runPlanningPhase, runRunAction, runSolutioningPhase, validateStopAfterFromConflict };
11106
- //# sourceMappingURL=run-XqzHIF6m.js.map
11175
+ //# sourceMappingURL=run-CoP8UQU3.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.2.10",
3
+ "version": "0.2.13",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",