substrate-ai 0.3.0 → 0.3.1

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,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { DEFAULT_CONFIG, DEFAULT_ROUTING_POLICY, DatabaseWrapper, DoltNotInstalled, FileStateStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, checkDoltInstalled, createConfigSystem, createContextCompiler, createDispatcher, createDoltClient, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStateStore, createStopAfterGate, findPackageRoot, formatOutput, formatPhaseCompletionSummary, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, initializeDolt, parseDbTimestampAsUtc, registerHealthCommand, registerRunCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveStoryKeys, runAnalysisPhase, runMigrations, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-DO9n3cwy.js";
2
+ import { DEFAULT_CONFIG, DEFAULT_ROUTING_POLICY, DatabaseWrapper, DoltNotInstalled, FileStateStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, checkDoltInstalled, createConfigSystem, createContextCompiler, createDispatcher, createDoltClient, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStateStore, createStopAfterGate, findPackageRoot, formatOutput, formatPhaseCompletionSummary, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, initializeDolt, parseDbTimestampAsUtc, registerHealthCommand, registerRunCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveStoryKeys, runAnalysisPhase, runMigrations, runPlanningPhase, runSolutioningPhase, validateStopAfterFromConflict } from "../run-DNURadtJ.js";
3
3
  import { createLogger } from "../logger-D2fS2ccL.js";
4
4
  import { AdapterRegistry } from "../adapter-registry-PsWhP_1Q.js";
5
5
  import { CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, PartialSubstrateConfigSchema } from "../config-migrator-DSi8KhQC.js";
@@ -681,7 +681,7 @@ async function runInitAction(options) {
681
681
  process.stderr.write(`✗ Dolt initialization failed: ${msg}\n`);
682
682
  return INIT_EXIT_ERROR;
683
683
  }
684
- logger$16.warn("Dolt auto-init failed (non-blocking)", { error: msg });
684
+ logger$16.warn({ error: msg }, "Dolt auto-init failed (non-blocking)");
685
685
  }
686
686
  }
687
687
  else logger$16.debug("Dolt step was skipped (--no-dolt)");
@@ -1362,7 +1362,7 @@ async function runStatusAction(options) {
1362
1362
  if (stateStore) try {
1363
1363
  storeStories = await stateStore.queryStories({});
1364
1364
  } catch (err) {
1365
- logger$13.debug("StateStore query failed, continuing without store data", { err });
1365
+ logger$13.debug({ err }, "StateStore query failed, continuing without store data");
1366
1366
  }
1367
1367
  if (outputFormat === "json") {
1368
1368
  const statusOutput = buildPipelineStatusOutput(run, tokenSummary, decisionsCount, storiesCount);
@@ -2664,7 +2664,7 @@ async function runSupervisorAction(options, deps = {}) {
2664
2664
  const expDb = expDbWrapper.db;
2665
2665
  const { runRunAction: runPipeline } = await import(
2666
2666
  /* @vite-ignore */
2667
- "../run-DP932Mmn.js"
2667
+ "../run-D6WEx9l2.js"
2668
2668
  );
2669
2669
  const runStoryFn = async (opts) => {
2670
2670
  const exitCode = await runPipeline({
@@ -3291,8 +3291,12 @@ function registerMigrateCommand(program) {
3291
3291
  }
3292
3292
  const result = await migrateDataToDolt(client, snapshot.storyMetrics, false);
3293
3293
  if (result.metricsWritten > 0) try {
3294
- await client.exec("add .");
3295
- await client.exec("commit -m \"Migrate historical data from SQLite\"");
3294
+ await client.execArgs(["add", "."]);
3295
+ await client.execArgs([
3296
+ "commit",
3297
+ "-m",
3298
+ "Migrate historical data from SQLite"
3299
+ ]);
3296
3300
  } catch (execErr) {
3297
3301
  const msg = execErr instanceof Error ? execErr.message : String(execErr);
3298
3302
  process.stderr.write(`Warning: Dolt commit failed (non-fatal): ${msg}\n`);
package/dist/index.d.ts CHANGED
@@ -1227,6 +1227,11 @@ interface OrchestratorEvents {
1227
1227
  modifiedInterfaces: string[];
1228
1228
  potentiallyAffectedTests: string[];
1229
1229
  };
1230
+ /** Dolt merge conflict detected when merging a story branch into main */
1231
+ 'pipeline:state-conflict': {
1232
+ storyKey: string;
1233
+ conflict: unknown;
1234
+ };
1230
1235
  /** Per-story metrics snapshot emitted when a story reaches a terminal state (Story 24-4) */
1231
1236
  'story:metrics': {
1232
1237
  storyKey: string;
@@ -1,4 +1,4 @@
1
- import { registerRunCommand, runRunAction } from "./run-DO9n3cwy.js";
1
+ import { registerRunCommand, runRunAction } from "./run-DNURadtJ.js";
2
2
  import "./logger-D2fS2ccL.js";
3
3
  import "./config-migrator-DSi8KhQC.js";
4
4
  import "./helpers-RL22dYtn.js";
@@ -7766,7 +7766,8 @@ var DoltStateStore = class DoltStateStore {
7766
7766
  const entries = [];
7767
7767
  for (const row of rows) {
7768
7768
  const hash = String(row.commit_hash ?? "");
7769
- const timestamp = row.date instanceof Date ? row.date.toISOString() : String(row.date ?? "");
7769
+ const dateVal = row.date;
7770
+ const timestamp = dateVal instanceof Date ? dateVal.toISOString() : String(dateVal ?? "");
7770
7771
  const message = String(row.message ?? "");
7771
7772
  const author = row.committer ? String(row.committer) : void 0;
7772
7773
  const storyKeyMatch = /story\/([0-9]+-[0-9]+)/i.exec(message);
@@ -9241,7 +9242,7 @@ function createImplementationOrchestrator(deps) {
9241
9242
  storyKey
9242
9243
  }, "mergeStory failed");
9243
9244
  });
9244
- else if (updates.phase === "ESCALATED" || updates.phase === "FAILED") stateStore?.rollbackStory(storyKey).catch((err) => logger$24.warn({
9245
+ else if (updates.phase === "ESCALATED") stateStore?.rollbackStory(storyKey).catch((err) => logger$24.warn({
9245
9246
  err,
9246
9247
  storyKey
9247
9248
  }, "rollbackStory failed — branch may persist"));
@@ -10733,7 +10734,11 @@ function resolveStoryKeys(db, projectRoot, opts) {
10733
10734
  const allContent = shardRows.map((r) => r.value).join("\n");
10734
10735
  if (allContent.length > 0) keys = parseStoryKeysFromEpics(allContent);
10735
10736
  } catch {}
10736
- if (keys.length === 0) keys = discoverPendingStoryKeys(projectRoot);
10737
+ if (keys.length === 0) keys = discoverPendingStoryKeys(projectRoot, opts?.epicNumber);
10738
+ if (opts?.epicNumber !== void 0 && keys.length > 0) {
10739
+ const prefix = `${opts.epicNumber}-`;
10740
+ keys = keys.filter((k) => k.startsWith(prefix));
10741
+ }
10737
10742
  if (opts?.filterCompleted === true && keys.length > 0) {
10738
10743
  const completedKeys = getCompletedStoryKeys(db);
10739
10744
  keys = keys.filter((k) => !completedKeys.has(k));
@@ -10781,21 +10786,33 @@ function parseStoryKeysFromEpics(content) {
10781
10786
  * @param projectRoot - Absolute path to the project root directory
10782
10787
  * @returns Sorted array of pending story keys in "N-M" format
10783
10788
  */
10784
- function discoverPendingStoryKeys(projectRoot) {
10789
+ function discoverPendingStoryKeys(projectRoot, epicNumber) {
10785
10790
  let allKeys = [];
10786
- const epicsPath = findEpicsFile(projectRoot);
10787
- if (epicsPath !== void 0) try {
10788
- const content = readFileSync$1(epicsPath, "utf-8");
10789
- allKeys = parseStoryKeysFromEpics(content);
10790
- } catch {}
10791
- if (allKeys.length === 0) {
10791
+ if (epicNumber !== void 0) {
10792
10792
  const epicFiles = findEpicFiles(projectRoot);
10793
- for (const epicFile of epicFiles) try {
10793
+ const targetPattern = new RegExp(`^epic-${epicNumber}[^0-9]`);
10794
+ const matched = epicFiles.filter((f) => targetPattern.test(f.split("/").pop()));
10795
+ for (const epicFile of matched) try {
10794
10796
  const content = readFileSync$1(epicFile, "utf-8");
10795
10797
  const keys = parseStoryKeysFromEpics(content);
10796
10798
  allKeys.push(...keys);
10797
10799
  } catch {}
10798
10800
  allKeys = sortStoryKeys([...new Set(allKeys)]);
10801
+ } else {
10802
+ const epicsPath = findEpicsFile(projectRoot);
10803
+ if (epicsPath !== void 0) try {
10804
+ const content = readFileSync$1(epicsPath, "utf-8");
10805
+ allKeys = parseStoryKeysFromEpics(content);
10806
+ } catch {}
10807
+ if (allKeys.length === 0) {
10808
+ const epicFiles = findEpicFiles(projectRoot);
10809
+ for (const epicFile of epicFiles) try {
10810
+ const content = readFileSync$1(epicFile, "utf-8");
10811
+ const keys = parseStoryKeysFromEpics(content);
10812
+ allKeys.push(...keys);
10813
+ } catch {}
10814
+ allKeys = sortStoryKeys([...new Set(allKeys)]);
10815
+ }
10799
10816
  }
10800
10817
  if (allKeys.length === 0) return [];
10801
10818
  const existingKeys = collectExistingStoryKeys(projectRoot);
@@ -14884,7 +14901,7 @@ function mapInternalPhaseToEventPhase(internalPhase) {
14884
14901
  }
14885
14902
  }
14886
14903
  async function runRunAction(options) {
14887
- const { pack: packName, from: startPhase, stopAfter, concept: conceptArg, conceptFile, stories: storiesArg, concurrency, outputFormat, projectRoot, events: eventsFlag, verbose: verboseFlag, tui: tuiFlag, skipUx, research: researchFlag, skipResearch: skipResearchFlag, skipPreflight, registry: injectedRegistry } = options;
14904
+ const { pack: packName, from: startPhase, stopAfter, concept: conceptArg, conceptFile, stories: storiesArg, concurrency, outputFormat, projectRoot, events: eventsFlag, verbose: verboseFlag, tui: tuiFlag, skipUx, research: researchFlag, skipResearch: skipResearchFlag, skipPreflight, epic: epicNumber, registry: injectedRegistry } = options;
14888
14905
  if (startPhase !== void 0 && !VALID_PHASES.includes(startPhase)) {
14889
14906
  const errorMsg = `Invalid phase '${startPhase}'. Valid phases: ${VALID_PHASES.join(", ")}`;
14890
14907
  if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, errorMsg) + "\n");
@@ -15008,6 +15025,7 @@ async function runRunAction(options) {
15008
15025
  ...researchFlag === true ? { research: true } : {},
15009
15026
  ...skipResearchFlag === true ? { skipResearch: true } : {},
15010
15027
  ...skipPreflight === true ? { skipPreflight: true } : {},
15028
+ ...epicNumber !== void 0 ? { epic: epicNumber } : {},
15011
15029
  ...injectedRegistry !== void 0 ? { registry: injectedRegistry } : {}
15012
15030
  });
15013
15031
  let storyKeys = [...parsedStoryKeys];
@@ -15056,8 +15074,11 @@ async function runRunAction(options) {
15056
15074
  storyKeys = storyKeys.filter((k) => !completedStoryKeys.has(k));
15057
15075
  }
15058
15076
  if (storyKeys.length === 0) {
15059
- storyKeys = discoverPendingStoryKeys(projectRoot);
15060
- if (storyKeys.length > 0) process.stdout.write(`Discovered ${storyKeys.length} pending stories from epics.md: ${storyKeys.join(", ")}\n`);
15077
+ storyKeys = discoverPendingStoryKeys(projectRoot, epicNumber);
15078
+ if (storyKeys.length > 0) {
15079
+ const scopeLabel = epicNumber !== void 0 ? `epic ${epicNumber}` : "epics.md";
15080
+ process.stdout.write(`Discovered ${storyKeys.length} pending stories from ${scopeLabel}: ${storyKeys.join(", ")}\n`);
15081
+ }
15061
15082
  }
15062
15083
  if (storyKeys.length === 0) {
15063
15084
  if (outputFormat === "human") process.stdout.write("No pending stories found in decision store.\n");
@@ -15755,7 +15776,10 @@ async function runFullPipeline(options) {
15755
15776
  process.stdout.write(` [ESCALATED] ${payload.storyKey}: ${payload.lastVerdict}\n`);
15756
15777
  });
15757
15778
  }
15758
- const storyKeys = resolveStoryKeys(db, projectRoot, { explicit: explicitStories });
15779
+ const storyKeys = resolveStoryKeys(db, projectRoot, {
15780
+ explicit: explicitStories,
15781
+ epicNumber: options.epic
15782
+ });
15759
15783
  if (storyKeys.length === 0 && outputFormat === "human") process.stdout.write("[IMPLEMENTATION] No stories found. Run solutioning first or pass --stories.\n");
15760
15784
  if (outputFormat === "human") process.stdout.write(`[IMPLEMENTATION] Starting ${storyKeys.length} stories with concurrency=${concurrency}\n`);
15761
15785
  await orchestrator.run(storyKeys);
@@ -15819,7 +15843,7 @@ async function runFullPipeline(options) {
15819
15843
  }
15820
15844
  }
15821
15845
  function registerRunCommand(program, _version = "0.0.0", projectRoot = process.cwd(), registry) {
15822
- program.command("run").description("Run the autonomous pipeline (use --from to start from a specific phase)").option("--pack <name>", "Methodology pack name", "bmad").option("--from <phase>", "Start from this phase: analysis, planning, solutioning, implementation").option("--stop-after <phase>", "Stop pipeline after this phase completes").option("--concept <text>", "Inline concept text (required when --from analysis)").option("--concept-file <path>", "Path to a file containing the concept text").option("--stories <keys>", "Comma-separated story keys (e.g., 10-1,10-2)").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").option("--events", "Emit structured NDJSON events on stdout for programmatic consumption").option("--verbose", "Show detailed pino log output").option("--help-agent", "Print a machine-optimized prompt fragment for AI agents and exit").option("--tui", "Show TUI dashboard").option("--skip-ux", "Skip the UX design phase even if enabled in the pack manifest").option("--research", "Enable the research phase even if not set in the pack manifest").option("--skip-research", "Skip the research phase even if enabled in the pack manifest").option("--skip-preflight", "Skip the pre-flight build check (escape hatch for known-broken projects)").action(async (opts) => {
15846
+ program.command("run").description("Run the autonomous pipeline (use --from to start from a specific phase)").option("--pack <name>", "Methodology pack name", "bmad").option("--from <phase>", "Start from this phase: analysis, planning, solutioning, implementation").option("--stop-after <phase>", "Stop pipeline after this phase completes").option("--concept <text>", "Inline concept text (required when --from analysis)").option("--concept-file <path>", "Path to a file containing the concept text").option("--stories <keys>", "Comma-separated story keys (e.g., 10-1,10-2)").option("--epic <n>", "Scope story discovery to a single epic number (e.g., 27)", (v) => parseInt(v, 10)).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").option("--events", "Emit structured NDJSON events on stdout for programmatic consumption").option("--verbose", "Show detailed pino log output").option("--help-agent", "Print a machine-optimized prompt fragment for AI agents and exit").option("--tui", "Show TUI dashboard").option("--skip-ux", "Skip the UX design phase even if enabled in the pack manifest").option("--research", "Enable the research phase even if not set in the pack manifest").option("--skip-research", "Skip the research phase even if enabled in the pack manifest").option("--skip-preflight", "Skip the pre-flight build check (escape hatch for known-broken projects)").action(async (opts) => {
15823
15847
  if (opts.helpAgent) {
15824
15848
  process.exitCode = await runHelpAgent();
15825
15849
  return;
@@ -15843,6 +15867,7 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
15843
15867
  concept: opts.concept,
15844
15868
  conceptFile: opts.conceptFile,
15845
15869
  stories: opts.stories,
15870
+ epic: opts.epic,
15846
15871
  concurrency: opts.concurrency,
15847
15872
  outputFormat,
15848
15873
  projectRoot: opts.projectRoot,
@@ -15861,4 +15886,4 @@ function registerRunCommand(program, _version = "0.0.0", projectRoot = process.c
15861
15886
 
15862
15887
  //#endregion
15863
15888
  export { DEFAULT_CONFIG, DEFAULT_ROUTING_POLICY, DatabaseWrapper, DoltNotInstalled, FileStateStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, checkDoltInstalled, createConfigSystem, createContextCompiler, createDispatcher, createDoltClient, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStateStore, createStopAfterGate, findPackageRoot, formatOutput, formatPhaseCompletionSummary, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, initializeDolt, parseDbTimestampAsUtc, registerHealthCommand, registerRunCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveStoryKeys, runAnalysisPhase, runMigrations, runPlanningPhase, runRunAction, runSolutioningPhase, validateStopAfterFromConflict };
15864
- //# sourceMappingURL=run-DO9n3cwy.js.map
15889
+ //# sourceMappingURL=run-DNURadtJ.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",