substrate-ai 0.19.48 → 0.19.50

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
@@ -1296,23 +1296,15 @@ async function detectNodeBuildTool(dir) {
1296
1296
  const TASK_RUNNER_MARKERS = [
1297
1297
  {
1298
1298
  file: "justfile",
1299
- runner: "just",
1300
- listCommand: ["just", "--list"]
1299
+ runner: "just"
1301
1300
  },
1302
1301
  {
1303
1302
  file: "Justfile",
1304
- runner: "just",
1305
- listCommand: ["just", "--list"]
1303
+ runner: "just"
1306
1304
  },
1307
1305
  {
1308
1306
  file: "Makefile",
1309
- runner: "make",
1310
- listCommand: []
1311
- },
1312
- {
1313
- file: "Taskfile.yml",
1314
- runner: "task",
1315
- listCommand: ["task", "--list"]
1307
+ runner: "make"
1316
1308
  }
1317
1309
  ];
1318
1310
  /** Known build-related target names, in preference order. */
@@ -1339,7 +1331,6 @@ async function detectTaskRunner(dir) {
1339
1331
  if (!await fileExists(path$1.join(dir, marker.file))) continue;
1340
1332
  if (marker.runner === "just") return detectJustTargets(dir, marker.file);
1341
1333
  if (marker.runner === "make") return detectMakeTargets(dir);
1342
- return { runner: "task" };
1343
1334
  }
1344
1335
  return null;
1345
1336
  }
@@ -1359,7 +1350,7 @@ async function detectJustTargets(dir, _filename) {
1359
1350
  } catch {
1360
1351
  try {
1361
1352
  const content = await fs.readFile(path$1.join(dir, _filename), "utf-8");
1362
- const recipes = content.split("\n").map((line) => line.match(/^([a-zA-Z_][\w-]*)(?:\s+[^:]*)?:/)).filter((m) => m !== null).map((m) => m[1]);
1353
+ const recipes = content.split("\n").map((line) => line.match(/^([a-zA-Z_][\w-]*)(?:\s+[^:]*)?:(?!=)/)).filter((m) => m !== null).map((m) => m[1]);
1363
1354
  for (const target of BUILD_TARGETS) if (recipes.includes(target)) {
1364
1355
  result.buildCommand = `just ${target}`;
1365
1356
  break;
@@ -1871,6 +1862,72 @@ async function scaffoldClaudeMd(projectRoot, profile) {
1871
1862
  await writeFile(claudeMdPath, newContent, "utf8");
1872
1863
  logger$15.info({ claudeMdPath }, "Wrote substrate section to CLAUDE.md");
1873
1864
  }
1865
+ async function scaffoldAgentsMd(projectRoot, profile) {
1866
+ const agentsMdPath = join(projectRoot, "AGENTS.md");
1867
+ const pkgRoot = findPackageRoot(__dirname);
1868
+ const templateName = "agents-md-substrate-section.md";
1869
+ let templatePath = join(pkgRoot, "dist", "cli", "templates", templateName);
1870
+ if (!existsSync$1(templatePath)) templatePath = join(pkgRoot, "src", "cli", "templates", templateName);
1871
+ let sectionContent;
1872
+ try {
1873
+ sectionContent = await readFile(templatePath, "utf8");
1874
+ } catch {
1875
+ logger$15.warn({ templatePath }, "AGENTS.md substrate section template not found; skipping");
1876
+ return;
1877
+ }
1878
+ const substrateVersion = readSubstrateVersion(pkgRoot);
1879
+ sectionContent = sectionContent.replace("{{SUBSTRATE_VERSION}}", substrateVersion);
1880
+ if (!sectionContent.endsWith("\n")) sectionContent += "\n";
1881
+ const devNotesSection = buildStackAwareDevNotes(profile ?? null);
1882
+ let existingContent = "";
1883
+ let fileExists$1 = false;
1884
+ try {
1885
+ existingContent = await readFile(agentsMdPath, "utf8");
1886
+ fileExists$1 = true;
1887
+ } catch {}
1888
+ let newContent;
1889
+ if (!fileExists$1) newContent = devNotesSection ? devNotesSection + "\n\n" + sectionContent : sectionContent;
1890
+ else if (existingContent.includes(CLAUDE_MD_START_MARKER)) newContent = existingContent.replace(new RegExp(`${CLAUDE_MD_START_MARKER.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${CLAUDE_MD_END_MARKER.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`), sectionContent.trimEnd());
1891
+ else {
1892
+ const separator = existingContent.endsWith("\n") ? "\n" : "\n\n";
1893
+ newContent = existingContent + separator + sectionContent;
1894
+ }
1895
+ await writeFile(agentsMdPath, newContent, "utf8");
1896
+ logger$15.info({ agentsMdPath }, "Wrote substrate section to AGENTS.md");
1897
+ }
1898
+ async function scaffoldGeminiMd(projectRoot, profile) {
1899
+ const geminiMdPath = join(projectRoot, "GEMINI.md");
1900
+ const pkgRoot = findPackageRoot(__dirname);
1901
+ const templateName = "gemini-md-substrate-section.md";
1902
+ let templatePath = join(pkgRoot, "dist", "cli", "templates", templateName);
1903
+ if (!existsSync$1(templatePath)) templatePath = join(pkgRoot, "src", "cli", "templates", templateName);
1904
+ let sectionContent;
1905
+ try {
1906
+ sectionContent = await readFile(templatePath, "utf8");
1907
+ } catch {
1908
+ logger$15.warn({ templatePath }, "GEMINI.md substrate section template not found; skipping");
1909
+ return;
1910
+ }
1911
+ const substrateVersion = readSubstrateVersion(pkgRoot);
1912
+ sectionContent = sectionContent.replace("{{SUBSTRATE_VERSION}}", substrateVersion);
1913
+ if (!sectionContent.endsWith("\n")) sectionContent += "\n";
1914
+ const devNotesSection = buildStackAwareDevNotes(profile ?? null);
1915
+ let existingContent = "";
1916
+ let fileExists$1 = false;
1917
+ try {
1918
+ existingContent = await readFile(geminiMdPath, "utf8");
1919
+ fileExists$1 = true;
1920
+ } catch {}
1921
+ let newContent;
1922
+ if (!fileExists$1) newContent = devNotesSection ? devNotesSection + "\n\n" + sectionContent : sectionContent;
1923
+ else if (existingContent.includes(CLAUDE_MD_START_MARKER)) newContent = existingContent.replace(new RegExp(`${CLAUDE_MD_START_MARKER.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}[\\s\\S]*?${CLAUDE_MD_END_MARKER.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}`), sectionContent.trimEnd());
1924
+ else {
1925
+ const separator = existingContent.endsWith("\n") ? "\n" : "\n\n";
1926
+ newContent = existingContent + separator + sectionContent;
1927
+ }
1928
+ await writeFile(geminiMdPath, newContent, "utf8");
1929
+ logger$15.info({ geminiMdPath }, "Wrote substrate section to GEMINI.md");
1930
+ }
1874
1931
  async function scaffoldStatuslineScript(projectRoot) {
1875
1932
  const pkgRoot = findPackageRoot(__dirname);
1876
1933
  const templateName = "statusline.sh";
@@ -2450,6 +2507,8 @@ async function runInitAction(options) {
2450
2507
  await initSchema(dbAdapter);
2451
2508
  await dbAdapter.close();
2452
2509
  await scaffoldClaudeMd(projectRoot, detectedProfile);
2510
+ await scaffoldAgentsMd(projectRoot, detectedProfile);
2511
+ await scaffoldGeminiMd(projectRoot, detectedProfile);
2453
2512
  await scaffoldStatuslineScript(projectRoot);
2454
2513
  await scaffoldClaudeSettings(projectRoot);
2455
2514
  await scaffoldClaudeCommands(projectRoot, outputFormat);
@@ -2521,6 +2580,8 @@ async function runInitAction(options) {
2521
2580
  }
2522
2581
  process.stdout.write(` Scaffolded:\n`);
2523
2582
  process.stdout.write(` CLAUDE.md pipeline instructions for Claude Code\n`);
2583
+ process.stdout.write(` AGENTS.md pipeline instructions for Codex CLI\n`);
2584
+ process.stdout.write(` GEMINI.md pipeline instructions for Gemini CLI\n`);
2524
2585
  process.stdout.write(` .claude/commands/ /substrate-run, /substrate-supervisor, /substrate-metrics\n`);
2525
2586
  process.stdout.write(` .substrate/ config, database, routing policy\n`);
2526
2587
  if (doltInitialized) process.stdout.write(`✓ Dolt state store initialized at .substrate/state/\n`);
@@ -0,0 +1,63 @@
1
+ <!-- substrate:start -->
2
+ <!-- substrate:version={{SUBSTRATE_VERSION}} -->
3
+ ## Substrate Pipeline
4
+
5
+ This project uses Substrate for automated implementation pipelines. When asked to implement, build, or run the pipeline, go straight to running substrate. Do not explore the codebase, read source files, or plan the implementation yourself. Substrate orchestrates sub-agents that handle all of that.
6
+
7
+ ### Running the Pipeline
8
+
9
+ Substrate auto-detects which pipeline phase to start from (analysis, planning, solutioning, implementation) and auto-discovers pending stories.
10
+
11
+ ```
12
+ substrate run --events
13
+ ```
14
+
15
+ To target specific stories:
16
+ ```
17
+ substrate run --events --stories 1-1,1-2,1-3
18
+ ```
19
+
20
+ If substrate needs input it can't auto-detect (e.g., a project concept for analysis), it will exit with a clear error message telling you what to provide.
21
+
22
+ Scope warning: Without `--stories`, substrate auto-discovers ALL pending stories across ALL epics and may dispatch 30+ stories at once. For controlled runs, always specify story keys explicitly with `--stories`.
23
+
24
+ Execution rules:
25
+ - Pipeline runs take 5-40 minutes. Use long timeouts.
26
+ - Never pipe substrate output to head, tail, grep, or any command that may close the pipe early.
27
+ - For full event protocol and command reference: `substrate run --help-agent`
28
+
29
+ ### Monitoring
30
+
31
+ Poll status periodically (every 60-90s):
32
+ ```
33
+ substrate status --output-format json
34
+ ```
35
+
36
+ Check process health:
37
+ ```
38
+ substrate health --output-format json
39
+ ```
40
+
41
+ ### After Pipeline Completes
42
+
43
+ 1. Summarize results: X succeeded, Y failed, Z escalated
44
+ 2. Check metrics: `substrate metrics --output-format json`
45
+
46
+ ### Handling Escalations
47
+
48
+ - On story escalation: read the flagged files and issues, propose a fix, ask the user before applying
49
+ - On minor fix verdict (NEEDS_MINOR_FIXES): offer to fix automatically
50
+ - On build verification failure: read the build output, diagnose the error, propose a fix
51
+ - Never re-run a failed story without explicit user confirmation
52
+
53
+ ### Key Commands
54
+
55
+ | Command | Purpose |
56
+ |---|---|
57
+ | `substrate run --events` | Run pipeline with NDJSON event stream |
58
+ | `substrate status --output-format json` | Poll current pipeline state |
59
+ | `substrate health --output-format json` | Check process health |
60
+ | `substrate metrics --output-format json` | View historical run metrics |
61
+ | `substrate resume` | Resume an interrupted pipeline run |
62
+ | `substrate run --help-agent` | Full agent instruction reference |
63
+ <!-- substrate:end -->
@@ -0,0 +1,63 @@
1
+ <!-- substrate:start -->
2
+ <!-- substrate:version={{SUBSTRATE_VERSION}} -->
3
+ ## Substrate Pipeline
4
+
5
+ This project uses Substrate for automated implementation pipelines. When asked to implement, build, or run the pipeline, go straight to running substrate. Do not explore the codebase, read source files, or plan the implementation yourself. Substrate orchestrates sub-agents that handle all of that.
6
+
7
+ ### Running the Pipeline
8
+
9
+ Substrate auto-detects which pipeline phase to start from (analysis, planning, solutioning, implementation) and auto-discovers pending stories.
10
+
11
+ ```
12
+ substrate run --events
13
+ ```
14
+
15
+ To target specific stories:
16
+ ```
17
+ substrate run --events --stories 1-1,1-2,1-3
18
+ ```
19
+
20
+ If substrate needs input it can't auto-detect (e.g., a project concept for analysis), it will exit with a clear error message telling you what to provide.
21
+
22
+ Scope warning: Without `--stories`, substrate auto-discovers ALL pending stories across ALL epics and may dispatch 30+ stories at once. For controlled runs, always specify story keys explicitly with `--stories`.
23
+
24
+ Execution rules:
25
+ - Pipeline runs take 5-40 minutes. Use long timeouts.
26
+ - Never pipe substrate output to head, tail, grep, or any command that may close the pipe early.
27
+ - For full event protocol and command reference: `substrate run --help-agent`
28
+
29
+ ### Monitoring
30
+
31
+ Poll status periodically (every 60-90s):
32
+ ```
33
+ substrate status --output-format json
34
+ ```
35
+
36
+ Check process health:
37
+ ```
38
+ substrate health --output-format json
39
+ ```
40
+
41
+ ### After Pipeline Completes
42
+
43
+ 1. Summarize results: X succeeded, Y failed, Z escalated
44
+ 2. Check metrics: `substrate metrics --output-format json`
45
+
46
+ ### Handling Escalations
47
+
48
+ - On story escalation: read the flagged files and issues, propose a fix, ask the user before applying
49
+ - On minor fix verdict (NEEDS_MINOR_FIXES): offer to fix automatically
50
+ - On build verification failure: read the build output, diagnose the error, propose a fix
51
+ - Never re-run a failed story without explicit user confirmation
52
+
53
+ ### Key Commands
54
+
55
+ | Command | Purpose |
56
+ |---|---|
57
+ | `substrate run --events` | Run pipeline with NDJSON event stream |
58
+ | `substrate status --output-format json` | Poll current pipeline state |
59
+ | `substrate health --output-format json` | Check process health |
60
+ | `substrate metrics --output-format json` | View historical run metrics |
61
+ | `substrate resume` | Resume an interrupted pipeline run |
62
+ | `substrate run --help-agent` | Full agent instruction reference |
63
+ <!-- substrate:end -->
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.19.48",
3
+ "version": "0.19.50",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",