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+[^:]*)
|
|
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 -->
|