substrate-ai 0.1.10 → 0.1.12

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/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="https://github.com/user-attachments/assets/622dd577-2814-4657-bb28-112ed272486d" alt="Substrate — Autonomous Software Development Pipeline" />
2
+ <img src="https://raw.githubusercontent.com/johnplanow/substrate/main/assets/substrate-header.png" alt="Substrate — Autonomous Software Development Pipeline" />
3
3
  </p>
4
4
 
5
5
  # Substrate
package/dist/cli/index.js CHANGED
@@ -8,7 +8,7 @@ import { fileURLToPath } from "url";
8
8
  import { dirname, extname, isAbsolute, join, relative, resolve } from "path";
9
9
  import { access, mkdir, readFile, readdir, stat, writeFile } from "fs/promises";
10
10
  import { execFile } from "child_process";
11
- import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
11
+ import { cpSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, unlinkSync, writeFileSync } from "fs";
12
12
  import yaml, { dump, load } from "js-yaml";
13
13
  import { z } from "zod";
14
14
  import { fileURLToPath as fileURLToPath$1 } from "node:url";
@@ -323,9 +323,9 @@ const DEFAULT_CONFIG = {
323
323
 
324
324
  //#endregion
325
325
  //#region src/cli/commands/templates.ts
326
- const __filename = fileURLToPath$1(import.meta.url);
327
- const __dirname = dirname$1(__filename);
328
- const TEMPLATES_DIR = join$1(__dirname, "..", "templates");
326
+ const __filename$1 = fileURLToPath$1(import.meta.url);
327
+ const __dirname$1 = dirname$1(__filename$1);
328
+ const TEMPLATES_DIR = join$1(__dirname$1, "..", "templates");
329
329
  /**
330
330
  * Get the absolute path to a template YAML file.
331
331
  *
@@ -12114,6 +12114,15 @@ Analyze thoroughly and return ONLY the JSON array with no additional text.`;
12114
12114
 
12115
12115
  //#endregion
12116
12116
  //#region src/cli/commands/auto.ts
12117
+ const __filename = fileURLToPath$1(import.meta.url);
12118
+ const __dirname = dirname(__filename);
12119
+ /**
12120
+ * Absolute path to the Substrate package root.
12121
+ *
12122
+ * In source: src/cli/commands/ → 3 levels up = repo root
12123
+ * Post-build: dist/cli/commands/ → 3 levels up = dist parent = package root
12124
+ */
12125
+ const PACKAGE_ROOT = join(__dirname, "..", "..", "..");
12117
12126
  const logger$3 = createLogger("auto-cmd");
12118
12127
  /** BMAD baseline token total for full pipeline comparison (analysis+planning+solutioning+implementation) */
12119
12128
  const BMAD_BASELINE_TOKENS_FULL = 56800;
@@ -12313,18 +12322,41 @@ function formatPipelineSummary(run, tokenSummary, decisionsCount, storiesCount,
12313
12322
  return lines.join("\n");
12314
12323
  }
12315
12324
  async function runAutoInit(options) {
12316
- const { pack: packName, projectRoot, outputFormat } = options;
12325
+ const { pack: packName, projectRoot, outputFormat, force = false } = options;
12317
12326
  const packPath = join(projectRoot, "packs", packName);
12318
12327
  const dbRoot = await resolveMainRepoRoot(projectRoot);
12319
12328
  const dbDir = join(dbRoot, ".substrate");
12320
12329
  const dbPath = join(dbDir, "substrate.db");
12321
12330
  try {
12331
+ const localManifest = join(packPath, "manifest.yaml");
12332
+ let scaffolded = false;
12333
+ if (!existsSync(localManifest) || force) {
12334
+ const bundledPackPath = join(PACKAGE_ROOT, "packs", packName);
12335
+ if (!existsSync(join(bundledPackPath, "manifest.yaml"))) {
12336
+ const errorMsg = `Pack '${packName}' not found locally or in bundled packs. Try reinstalling Substrate.`;
12337
+ if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, errorMsg) + "\n");
12338
+ else process.stderr.write(`Error: ${errorMsg}\n`);
12339
+ return 1;
12340
+ }
12341
+ if (force && existsSync(localManifest)) {
12342
+ logger$3.info({ pack: packName }, "Replacing existing pack with bundled version");
12343
+ process.stderr.write(`Warning: Replacing existing pack '${packName}' with bundled version\n`);
12344
+ }
12345
+ mkdirSync(dirname(packPath), { recursive: true });
12346
+ cpSync(bundledPackPath, packPath, { recursive: true });
12347
+ logger$3.info({
12348
+ pack: packName,
12349
+ dest: packPath
12350
+ }, "Scaffolded methodology pack");
12351
+ process.stdout.write(`Scaffolding methodology pack '${packName}' into packs/${packName}/\n`);
12352
+ scaffolded = true;
12353
+ }
12322
12354
  const packLoader = createPackLoader();
12323
12355
  try {
12324
12356
  await packLoader.load(packPath);
12325
12357
  } catch (err) {
12326
12358
  const msg = err instanceof Error ? err.message : String(err);
12327
- const errorMsg = `Methodology pack '${packName}' not found. Run 'substrate auto init' first.\n${msg}`;
12359
+ const errorMsg = `Methodology pack '${packName}' not found. Check that packs/${packName}/manifest.yaml exists or try reinstalling Substrate.\n${msg}`;
12328
12360
  if (outputFormat === "json") process.stdout.write(formatOutput(null, "json", false, errorMsg) + "\n");
12329
12361
  else process.stderr.write(`Error: ${errorMsg}\n`);
12330
12362
  return 1;
@@ -12337,7 +12369,8 @@ async function runAutoInit(options) {
12337
12369
  const successMsg = `Pack '${packName}' and database initialized successfully at ${dbPath}`;
12338
12370
  if (outputFormat === "json") process.stdout.write(formatOutput({
12339
12371
  pack: packName,
12340
- dbPath
12372
+ dbPath,
12373
+ scaffolded
12341
12374
  }, "json", true) + "\n");
12342
12375
  else process.stdout.write(`${successMsg}\n`);
12343
12376
  return 0;
@@ -13479,12 +13512,13 @@ async function runAmendCommand(options) {
13479
13512
  */
13480
13513
  function registerAutoCommand(program, _version = "0.0.0", projectRoot = process.cwd()) {
13481
13514
  const auto = program.command("auto").description("Autonomous implementation pipeline");
13482
- auto.command("init").description("Initialize a methodology pack and decision store for autonomous pipeline").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) => {
13515
+ auto.command("init").description("Initialize a methodology pack and decision store for autonomous pipeline").option("--pack <name>", "Methodology pack name", "bmad").option("--project-root <path>", "Project root directory", projectRoot).option("--force", "Overwrite existing local pack with bundled version").option("--output-format <format>", "Output format: human (default) or json", "human").action(async (opts) => {
13483
13516
  const outputFormat = opts.outputFormat === "json" ? "json" : "human";
13484
13517
  const exitCode = await runAutoInit({
13485
13518
  pack: opts.pack,
13486
13519
  projectRoot: opts.projectRoot,
13487
- outputFormat
13520
+ outputFormat,
13521
+ force: opts.force ?? false
13488
13522
  });
13489
13523
  process.exitCode = exitCode;
13490
13524
  });
@@ -14566,12 +14600,12 @@ const logger = createLogger("cli");
14566
14600
  /** Resolve the package.json path relative to this file */
14567
14601
  async function getPackageVersion() {
14568
14602
  try {
14569
- const __filename$1 = fileURLToPath(import.meta.url);
14570
- const __dirname$1 = dirname(__filename$1);
14603
+ const __filename$2 = fileURLToPath(import.meta.url);
14604
+ const __dirname$2 = dirname(__filename$2);
14571
14605
  const paths = [
14572
- resolve(__dirname$1, "../../package.json"),
14573
- resolve(__dirname$1, "../package.json"),
14574
- resolve(__dirname$1, "../../../package.json")
14606
+ resolve(__dirname$2, "../../package.json"),
14607
+ resolve(__dirname$2, "../package.json"),
14608
+ resolve(__dirname$2, "../../../package.json")
14575
14609
  ];
14576
14610
  for (const pkgPath of paths) try {
14577
14611
  const content = await readFile(pkgPath, "utf-8");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.1.10",
3
+ "version": "0.1.12",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -23,7 +23,6 @@
23
23
  "bin": {
24
24
  "substrate": "./dist/cli/index.js"
25
25
  },
26
- "readme": "README.npm.md",
27
26
  "main": "./dist/index.js",
28
27
  "exports": {
29
28
  ".": {
@@ -41,12 +40,11 @@
41
40
  "dist/**/*.json",
42
41
  "dist/cli/templates",
43
42
  "packs",
44
- "README.md",
45
- "README.npm.md"
43
+ "README.md"
46
44
  ],
47
45
  "scripts": {
48
46
  "build": "tsdown",
49
- "postbuild": "cp -r src/cli/templates dist/cli/templates && sed 's|assets/substrate-header.png|https://github.com/user-attachments/assets/622dd577-2814-4657-bb28-112ed272486d|' README.md > README.npm.md",
47
+ "postbuild": "cp -r src/cli/templates dist/cli/templates",
50
48
  "dev": "tsx watch src/cli/index.ts",
51
49
  "test": "vitest run --coverage",
52
50
  "test:watch": "vitest",
package/README.npm.md DELETED
@@ -1,206 +0,0 @@
1
- <p align="center">
2
- <img src="https://github.com/user-attachments/assets/622dd577-2814-4657-bb28-112ed272486d" alt="Substrate — Autonomous Software Development Pipeline" />
3
- </p>
4
-
5
- # Substrate
6
-
7
- Autonomous software development pipeline powered by multi-agent orchestration. Substrate takes a project idea from concept through analysis, planning, architecture, implementation, and code review — coordinating CLI-based AI agents (Claude Code, Codex, Gemini CLI) to do the work.
8
-
9
- Substrate follows a modular monolith pattern running as a single Node.js process. The orchestrator never calls LLMs directly — all intelligent work is delegated to CLI agents running as child processes in isolated git worktrees. The autonomous pipeline compiles BMAD methodology workflows into token-efficient agent dispatches.
10
-
11
- ## Prerequisites
12
-
13
- - **Node.js** 22.0.0 or later
14
- - **git** 2.20 or later
15
- - At least one supported AI CLI agent installed:
16
- - [Claude Code](https://docs.anthropic.com/en/docs/claude-code) (`claude`)
17
- - [Codex CLI](https://github.com/openai/codex) (`codex`)
18
- - Gemini CLI (`gemini`)
19
-
20
- ## Installation
21
-
22
- Install as a project dependency:
23
-
24
- ```bash
25
- npm install substrate-ai
26
- ```
27
-
28
- Or install globally:
29
-
30
- ```bash
31
- npm install -g substrate-ai
32
- ```
33
-
34
- Verify the installation:
35
-
36
- ```bash
37
- npx substrate --version # project install
38
- substrate --version # global install
39
- ```
40
-
41
- > Examples below use `[npx] substrate` — include `npx` for project installs, omit for global.
42
-
43
- ## Quick Start
44
-
45
- ### Autonomous Pipeline (recommended)
46
-
47
- Got an idea? Substrate can take it from concept to working code.
48
-
49
- 1. **Brainstorm** — explore your idea with a multi-persona AI session:
50
-
51
- ```bash
52
- [npx] substrate brainstorm
53
- ```
54
-
55
- 2. **Initialize the pipeline** — set up the methodology pack and decision store:
56
-
57
- ```bash
58
- [npx] substrate auto init
59
- ```
60
-
61
- 3. **Run the full pipeline** — analysis, planning, solutioning, and implementation:
62
-
63
- ```bash
64
- [npx] substrate auto run
65
- ```
66
-
67
- Substrate walks through the entire software development lifecycle autonomously:
68
- - **Analysis** — generates a product brief from your brainstorm
69
- - **Planning** — creates a PRD with requirements
70
- - **Solutioning** — produces architecture, epics, and stories
71
- - **Implementation** — dispatches agents to build, test, and code-review each story
72
-
73
- You can start from any phase or resume an interrupted run:
74
-
75
- ```bash
76
- [npx] substrate auto run --from solutioning # Skip to a specific phase
77
- [npx] substrate auto resume # Pick up where you left off
78
- [npx] substrate auto status # Check pipeline progress
79
- ```
80
-
81
- ### Pick Up an Existing BMAD Project
82
-
83
- Already have a project with BMAD artifacts (vanilla BMAD or the Beads-based ai-toolkit)? Substrate can pick up the remaining implementation work. It reads one directory — `_bmad-output/` — and doesn't care which tool created it.
84
-
85
- **What Substrate needs from your project:**
86
-
87
- | File | Required? | Purpose |
88
- |------|-----------|---------|
89
- | `_bmad-output/planning-artifacts/epics.md` | Yes | Parsed into per-epic context shards |
90
- | `_bmad-output/planning-artifacts/architecture.md` | Yes | Tech stack and constraints for agents |
91
- | `_bmad-output/implementation-artifacts/*.md` | Optional | Existing story files — Substrate skips create-story for any it finds |
92
- | `package.json` | Optional | Test framework detection |
93
-
94
- **Three commands:**
95
-
96
- ```bash
97
- npm install substrate-ai
98
- [npx] substrate auto init # Seeds context from _bmad-output/
99
- [npx] substrate auto run --stories 5-3,5-4,6-1 # Only the unfinished story keys
100
- ```
101
-
102
- For each story, Substrate runs: **create-story** (skipped if story file exists) → **dev-story** (implement) → **code-review** (adversarial review). Non-conflicting stories run in parallel automatically.
103
-
104
- Substrate does not read `sprint-status.yaml` or `.beads/` — you decide what's left by choosing which story keys to pass.
105
-
106
- ## Supported Agents
107
-
108
- | Agent ID | CLI Tool | Billing |
109
- |----------|----------|---------|
110
- | `claude-code` | Claude Code | Subscription (Max) or API key |
111
- | `codex` | Codex CLI | Subscription (ChatGPT Plus/Pro) or API key |
112
- | `gemini` | Gemini CLI | Subscription or API key |
113
-
114
- ## Commands
115
-
116
- ### Pipeline
117
-
118
- | Command | Description |
119
- |---------|-------------|
120
- | `substrate brainstorm` | Interactive multi-persona ideation session |
121
- | `substrate auto init` | Initialize methodology pack for autonomous pipeline |
122
- | `substrate auto run` | Run the full pipeline (analysis → implement) |
123
- | `substrate auto run --from <phase>` | Start from a specific phase |
124
- | `substrate auto resume` | Resume an interrupted pipeline run |
125
- | `substrate auto status` | Show pipeline run status |
126
-
127
- ### Monitoring
128
-
129
- | Command | Description |
130
- |---------|-------------|
131
- | `substrate monitor status` | View task metrics and agent performance |
132
- | `substrate monitor report` | Generate a detailed performance report |
133
- | `substrate cost-report` | View cost and token usage summary |
134
-
135
- ### Setup
136
-
137
- | Command | Description |
138
- |---------|-------------|
139
- | `substrate init` | Initialize project configuration |
140
- | `substrate --help` | Show all available commands |
141
-
142
- ## Configuration
143
-
144
- Substrate reads configuration from `.substrate/config.yaml` in your project root. Run `[npx] substrate init` to generate a default config.
145
-
146
- ## Development
147
-
148
- ```bash
149
- # Clone and install
150
- git clone https://github.com/johnplanow/substrate.git
151
- cd substrate
152
- npm install
153
-
154
- # Build
155
- npm run build
156
-
157
- # Run tests
158
- npm test
159
-
160
- # Development mode (watch)
161
- npm run dev
162
-
163
- # Type check
164
- npm run typecheck
165
-
166
- # Lint
167
- npm run lint
168
- ```
169
-
170
- ## Manual Task Graphs
171
-
172
- For fine-grained control, you can define exactly what agents should do in a YAML task graph:
173
-
174
- ```yaml
175
- version: "1"
176
- session:
177
- name: "my-tasks"
178
- tasks:
179
- write-tests:
180
- name: "Write unit tests"
181
- prompt: |
182
- Look at the src/utils/ directory.
183
- Write comprehensive unit tests for all exported functions.
184
- type: testing
185
- agent: claude-code
186
- update-docs:
187
- name: "Update README"
188
- prompt: |
189
- Read the README.md and verify it accurately describes
190
- the project. Fix any inaccuracies.
191
- type: docs
192
- agent: codex
193
- depends_on:
194
- - write-tests
195
- ```
196
-
197
- ```bash
198
- [npx] substrate start --graph tasks.yaml # Execute the graph
199
- [npx] substrate plan --graph tasks.yaml # Preview without running
200
- ```
201
-
202
- Tasks without dependencies run in parallel. Each agent gets its own isolated git worktree.
203
-
204
- ## License
205
-
206
- MIT