substrate-ai 0.2.29 → 0.2.31

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.
@@ -0,0 +1,8 @@
1
+ import { registerRunCommand, runRunAction } from "./run-BxXwD2xY.js";
2
+ import "./logger-D2fS2ccL.js";
3
+ import "./config-migrator-DSi8KhQC.js";
4
+ import "./helpers-RL22dYtn.js";
5
+ import "./decisions-Dq4cAA2L.js";
6
+ import "./operational-Bovj4fS-.js";
7
+
8
+ export { runRunAction };
@@ -1,4 +1,5 @@
1
- import "./version-manager-impl-CtzNu7YZ.js";
2
- import { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand } from "./upgrade-CJ0JFQ2c.js";
1
+ import "./config-migrator-DSi8KhQC.js";
2
+ import "./version-manager-impl-CizNmmLT.js";
3
+ import { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand } from "./upgrade-Cvwtnwl4.js";
3
4
 
4
5
  export { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand };
@@ -1,4 +1,4 @@
1
- import { createVersionManager } from "./version-manager-impl-CtzNu7YZ.js";
1
+ import { createVersionManager } from "./version-manager-impl-CizNmmLT.js";
2
2
  import { execSync, spawn } from "child_process";
3
3
  import * as readline from "readline";
4
4
 
@@ -123,4 +123,4 @@ function registerUpgradeCommand(program) {
123
123
 
124
124
  //#endregion
125
125
  export { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand };
126
- //# sourceMappingURL=upgrade-CJ0JFQ2c.js.map
126
+ //# sourceMappingURL=upgrade-Cvwtnwl4.js.map
@@ -1,252 +1,13 @@
1
+ import { SUPPORTED_CONFIG_FORMAT_VERSIONS, SUPPORTED_TASK_GRAPH_VERSIONS, defaultConfigMigrator } from "./config-migrator-DSi8KhQC.js";
1
2
  import { createRequire } from "module";
2
3
  import { fileURLToPath } from "url";
3
4
  import path, { dirname, resolve } from "path";
4
5
  import { mkdirSync, readFileSync, writeFileSync } from "fs";
5
- import { z } from "zod";
6
6
  import os from "os";
7
7
  import * as semver$1 from "semver";
8
8
  import * as semver from "semver";
9
9
  import https from "https";
10
10
 
11
- //#region src/modules/config/config-schema.ts
12
- /** Subscription routing modes */
13
- const SubscriptionRoutingSchema = z.enum([
14
- "auto",
15
- "subscription",
16
- "api",
17
- "disabled"
18
- ]);
19
- /** Rate limit configuration for a provider */
20
- const RateLimitSchema = z.object({
21
- tokens: z.number().int().positive(),
22
- window_seconds: z.number().int().positive()
23
- }).strict();
24
- /** Per-provider configuration */
25
- const ProviderConfigSchema = z.object({
26
- enabled: z.boolean(),
27
- cli_path: z.string().optional(),
28
- subscription_routing: SubscriptionRoutingSchema,
29
- max_concurrent: z.number().int().min(1).max(32),
30
- rate_limit: RateLimitSchema.optional(),
31
- api_key_env: z.string().optional(),
32
- api_billing: z.boolean()
33
- }).strict();
34
- /** Map of all known providers */
35
- const ProvidersSchema = z.object({
36
- claude: ProviderConfigSchema.optional(),
37
- codex: ProviderConfigSchema.optional(),
38
- gemini: ProviderConfigSchema.optional()
39
- }).strict();
40
- const LogLevelSchema = z.enum([
41
- "trace",
42
- "debug",
43
- "info",
44
- "warn",
45
- "error",
46
- "fatal"
47
- ]);
48
- const GlobalSettingsSchema = z.object({
49
- log_level: LogLevelSchema,
50
- max_concurrent_tasks: z.number().int().min(1).max(64),
51
- budget_cap_tokens: z.number().int().min(0),
52
- budget_cap_usd: z.number().min(0),
53
- workspace_dir: z.string().optional(),
54
- update_check: z.boolean().optional()
55
- }).strict();
56
- const CostTrackerConfigSchema = z.object({
57
- enabled: z.boolean(),
58
- token_rates_provider: z.enum(["builtin", "custom"]),
59
- track_planning_costs: z.boolean(),
60
- savings_reporting: z.boolean()
61
- }).strict();
62
- const BudgetConfigSchema = z.object({
63
- default_task_budget_usd: z.number().min(0),
64
- default_session_budget_usd: z.number().min(0),
65
- planning_costs_count_against_budget: z.boolean(),
66
- warning_threshold_percent: z.number().min(0).max(100)
67
- }).strict();
68
- const RoutingRuleSchema = z.object({
69
- task_type: z.string(),
70
- preferred_provider: z.string(),
71
- fallback_providers: z.array(z.string())
72
- }).strict();
73
- const RoutingPolicySchema = z.object({
74
- default_provider: z.string(),
75
- rules: z.array(RoutingRuleSchema)
76
- }).strict();
77
- /**
78
- * Per-workflow token ceiling overrides.
79
- * Keys match the workflow type names used in prompts and events.
80
- * Values must be positive integers.
81
- */
82
- const TokenCeilingsSchema = z.object({
83
- "create-story": z.number().int().positive("create-story token ceiling must be a positive integer").optional(),
84
- "dev-story": z.number().int().positive("dev-story token ceiling must be a positive integer").optional(),
85
- "code-review": z.number().int().positive("code-review token ceiling must be a positive integer").optional(),
86
- "test-plan": z.number().int().positive("test-plan token ceiling must be a positive integer").optional(),
87
- "test-expansion": z.number().int().positive("test-expansion token ceiling must be a positive integer").optional()
88
- });
89
- /** Current supported config format version */
90
- const CURRENT_CONFIG_FORMAT_VERSION = "1";
91
- /** Current supported task graph version */
92
- const CURRENT_TASK_GRAPH_VERSION = "1";
93
- /** All config format versions this toolkit can read and validate */
94
- const SUPPORTED_CONFIG_FORMAT_VERSIONS = ["1"];
95
- /** All task graph format versions this toolkit can read and validate */
96
- const SUPPORTED_TASK_GRAPH_VERSIONS = ["1"];
97
- const SubstrateConfigSchema = z.object({
98
- config_format_version: z.enum(["1"]),
99
- task_graph_version: z.enum(["1"]).optional(),
100
- global: GlobalSettingsSchema,
101
- providers: ProvidersSchema,
102
- cost_tracker: CostTrackerConfigSchema.optional(),
103
- budget: BudgetConfigSchema.optional(),
104
- token_ceilings: TokenCeilingsSchema.optional()
105
- }).strict();
106
- const PartialProviderConfigSchema = ProviderConfigSchema.partial();
107
- const PartialGlobalSettingsSchema = GlobalSettingsSchema.partial();
108
- const PartialSubstrateConfigSchema = z.object({
109
- config_format_version: z.enum(["1"]).optional(),
110
- task_graph_version: z.enum(["1"]).optional(),
111
- global: PartialGlobalSettingsSchema.optional(),
112
- providers: z.object({
113
- claude: PartialProviderConfigSchema.optional(),
114
- codex: PartialProviderConfigSchema.optional(),
115
- gemini: PartialProviderConfigSchema.optional()
116
- }).partial().optional(),
117
- cost_tracker: CostTrackerConfigSchema.partial().optional(),
118
- budget: BudgetConfigSchema.partial().optional(),
119
- token_ceilings: TokenCeilingsSchema.optional()
120
- }).strict();
121
-
122
- //#endregion
123
- //#region src/modules/config/config-migrator.ts
124
- /**
125
- * ConfigMigrator manages a registry of migration functions and applies them
126
- * sequentially to upgrade config documents from one format version to another.
127
- */
128
- var ConfigMigrator = class {
129
- migrations = new Map();
130
- /**
131
- * Register a migration function for the given version key.
132
- *
133
- * @param key - Migration key in format "N->M" (e.g. "1->2")
134
- * @param fn - Migration function that receives the raw config and returns the migrated config
135
- */
136
- register(key, fn) {
137
- this.migrations.set(key, fn);
138
- }
139
- /**
140
- * Check whether a sequential migration path exists from fromVersion to toVersion.
141
- *
142
- * @param fromVersion - Starting version string
143
- * @param toVersion - Target version string
144
- * @returns true if every step in the path is registered
145
- */
146
- canMigrate(fromVersion, toVersion) {
147
- if (fromVersion === toVersion) return true;
148
- const from = parseInt(fromVersion, 10);
149
- const to = parseInt(toVersion, 10);
150
- if (isNaN(from) || isNaN(to) || from >= to) return false;
151
- for (let v = from; v < to; v++) {
152
- const key = `${String(v)}->${String(v + 1)}`;
153
- if (!this.migrations.has(key)) return false;
154
- }
155
- return true;
156
- }
157
- /**
158
- * Apply sequential migrations from fromVersion to toVersion.
159
- *
160
- * If fromVersion === toVersion, returns a no-op success result.
161
- * If any intermediate migration is missing, returns success:false.
162
- *
163
- * When filePath is provided and migration is needed, a backup is written to
164
- * `${filePath}.bak.v${fromVersion}` before any transformations are applied.
165
- *
166
- * @param config - Raw config object to migrate
167
- * @param fromVersion - Starting format version string
168
- * @param toVersion - Target format version string
169
- * @param filePath - Optional path to the source config file for backup creation
170
- * @returns Object containing the (possibly migrated) config and a MigrationResult
171
- */
172
- migrate(config, fromVersion, toVersion, filePath) {
173
- if (fromVersion === toVersion) return {
174
- config,
175
- result: {
176
- success: true,
177
- fromVersion,
178
- toVersion,
179
- migratedKeys: [],
180
- manualStepsRequired: [],
181
- backupPath: null
182
- }
183
- };
184
- const from = parseInt(fromVersion, 10);
185
- const to = parseInt(toVersion, 10);
186
- if (isNaN(from) || isNaN(to) || from >= to) return {
187
- config,
188
- result: {
189
- success: false,
190
- fromVersion,
191
- toVersion,
192
- migratedKeys: [],
193
- manualStepsRequired: [`Cannot migrate from version "${fromVersion}" to "${toVersion}": invalid version range.`],
194
- backupPath: null
195
- }
196
- };
197
- for (let v = from; v < to; v++) {
198
- const key = `${String(v)}->${String(v + 1)}`;
199
- if (!this.migrations.has(key)) return {
200
- config,
201
- result: {
202
- success: false,
203
- fromVersion,
204
- toVersion,
205
- migratedKeys: [],
206
- manualStepsRequired: [`Missing migration step: "${key}". Cannot automatically migrate from version "${fromVersion}" to "${toVersion}". Please upgrade the toolkit: npm install -g substrate@latest`],
207
- backupPath: null
208
- }
209
- };
210
- }
211
- let backupPath = null;
212
- if (filePath !== void 0) {
213
- backupPath = `${filePath}.bak.v${fromVersion}`;
214
- const originalContent = readFileSync(filePath, "utf-8");
215
- writeFileSync(backupPath, originalContent, "utf-8");
216
- }
217
- let current = config;
218
- const migratedKeys = [];
219
- for (let v = from; v < to; v++) {
220
- const key = `${String(v)}->${String(v + 1)}`;
221
- const fn = this.migrations.get(key);
222
- const before = JSON.stringify(current);
223
- current = fn(current);
224
- const after = JSON.stringify(current);
225
- if (current !== null && typeof current === "object" && !Array.isArray(current)) {
226
- const beforeObj = JSON.parse(before);
227
- const afterObj = JSON.parse(after);
228
- for (const k of Object.keys(afterObj)) if (JSON.stringify(afterObj[k]) !== JSON.stringify(beforeObj[k])) {
229
- if (!migratedKeys.includes(k)) migratedKeys.push(k);
230
- }
231
- }
232
- }
233
- return {
234
- config: current,
235
- result: {
236
- success: true,
237
- fromVersion,
238
- toVersion,
239
- migratedKeys,
240
- manualStepsRequired: [],
241
- backupPath
242
- }
243
- };
244
- }
245
- };
246
- /** Singleton instance for use throughout the toolkit */
247
- const defaultConfigMigrator = new ConfigMigrator();
248
-
249
- //#endregion
250
11
  //#region src/modules/version-manager/update-checker.ts
251
12
  /**
252
13
  * Thrown when an update check fails due to network error, timeout, or bad response.
@@ -607,5 +368,5 @@ function createVersionManager(deps = {}) {
607
368
  }
608
369
 
609
370
  //#endregion
610
- export { CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, PartialSubstrateConfigSchema, SUPPORTED_CONFIG_FORMAT_VERSIONS, SubstrateConfigSchema, VersionManagerImpl, createVersionManager, defaultConfigMigrator };
611
- //# sourceMappingURL=version-manager-impl-CtzNu7YZ.js.map
371
+ export { VersionManagerImpl, createVersionManager };
372
+ //# sourceMappingURL=version-manager-impl-CizNmmLT.js.map
@@ -0,0 +1,4 @@
1
+ import "./config-migrator-DSi8KhQC.js";
2
+ import { VersionManagerImpl, createVersionManager } from "./version-manager-impl-CizNmmLT.js";
3
+
4
+ export { createVersionManager };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "substrate-ai",
3
- "version": "0.2.29",
3
+ "version": "0.2.31",
4
4
  "description": "Substrate — multi-agent orchestration daemon for AI coding agents",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -221,6 +221,8 @@ prompts:
221
221
  refine-artifact: prompts/refine-artifact.md
222
222
  # Readiness check prompt (Story 16-6)
223
223
  readiness-check: prompts/readiness-check.md
224
+ # Test plan prompt (Story 25-7)
225
+ test-plan: prompts/test-plan.md
224
226
 
225
227
  constraints:
226
228
  create-story: constraints/create-story.yaml
@@ -100,6 +100,11 @@ ac_checklist:
100
100
  **IMPORTANT**: `ac_checklist` must contain one entry for every AC found in the story. If the story has no parseable ACs (e.g. a refactoring story), `ac_checklist` may be an empty array.
101
101
 
102
102
  **Verdict rules:**
103
- - `SHIP_IT` — zero blocker/major issues (minor issues acceptable)
104
- - `NEEDS_MINOR_FIXES` — minor issues only, or 1-2 major with no blockers
103
+ - `SHIP_IT` — zero issues of any kind
104
+ - `LGTM_WITH_NOTES` — zero correctness/logic/security issues; only advisory or style observations that do not need to be fixed before shipping. Use this when you have optional suggestions but the code is production-ready as-is. Include your suggestions in the `notes` field.
105
+ - `NEEDS_MINOR_FIXES` — one or more minor issues that should be fixed, or 1-2 major issues with no blockers
105
106
  - `NEEDS_MAJOR_REWORK` — any blocker issue, or 3+ major issues
107
+
108
+ **LGTM_WITH_NOTES vs NEEDS_MINOR_FIXES:**
109
+ - Use `LGTM_WITH_NOTES` when: all findings are purely advisory (naming preferences, optional refactors, docs suggestions) and the code ships safely without any changes
110
+ - Use `NEEDS_MINOR_FIXES` when: any finding represents a real gap that should be corrected before the story is considered done (missing error handling, incomplete AC coverage, confusing logic)
@@ -35,6 +35,26 @@ Using the context above, write a complete, implementation-ready story file for s
35
35
  - Status must be: `ready-for-dev`
36
36
  - Dev Agent Record section must be present but left blank (to be filled by dev agent)
37
37
 
38
+ ## Interface Contracts Guidance
39
+
40
+ **Identify cross-story dependencies** when the story creates or consumes shared schemas, interfaces, or message contracts.
41
+
42
+ If the story exports (creates) or imports (consumes from another story) any TypeScript interfaces, Zod schemas, message queue contracts, or API types that are shared across module boundaries, add an `## Interface Contracts` section to the story file.
43
+
44
+ Use this exact format for each item:
45
+
46
+ ```markdown
47
+ ## Interface Contracts
48
+
49
+ - **Export**: SchemaName @ src/path/to/file.ts (queue: some-queue-name)
50
+ - **Import**: SchemaName @ src/path/to/file.ts (from story 25-X)
51
+ ```
52
+
53
+ - `Export` = this story creates/defines the schema that other stories will consume
54
+ - `Import` = this story consumes a schema defined by another story
55
+ - The transport annotation `(queue: ...)` or `(api: ...)` or `(from story X-Y)` is optional but recommended when applicable
56
+ - **The `## Interface Contracts` section is optional** — omit it entirely if the story has no cross-story schema dependencies
57
+
38
58
  ## Scope Cap Guidance
39
59
 
40
60
  **Aim for 6-7 acceptance criteria and 7-8 tasks per story.**
@@ -2,24 +2,30 @@
2
2
 
3
3
  ## Mission
4
4
 
5
- Analyze the story's Acceptance Criteria and tasks. Produce a concrete test plan listing the test files to create, the test categories to cover (unit/integration/e2e), and a brief note on AC coverage.
5
+ Analyze the story's Acceptance Criteria and tasks. Produce a concrete test plan listing the test files to create, the test categories to cover (unit/integration/e2e), and comprehensive coverage notes that include: which ACs each test covers, dependencies to mock, and error conditions to assert.
6
6
 
7
7
  ## Story Content
8
8
 
9
9
  {{story_content}}
10
10
 
11
+ ## Architecture Constraints
12
+
13
+ {{architecture_constraints}}
14
+
11
15
  ## Instructions
12
16
 
13
17
  1. Read the Acceptance Criteria (AC1, AC2, etc.) and Tasks in the story above.
14
18
  2. Identify the source files that will need tests (from Dev Notes, Key File Paths, and Tasks).
15
19
  3. For each AC, determine which test file and test function will validate it.
16
- 4. Produce a concise test plan one or two test files is typical for small stories.
20
+ 4. Identify all external dependencies (modules, services, fs, db) that must be mocked or stubbed.
21
+ 5. Identify error conditions and edge cases that must be asserted (not just the happy path).
22
+ 6. Produce a concise test plan — one or two test files is typical for small stories.
17
23
 
18
24
  **Rules:**
19
25
  - List only test files that will be NEW (not existing ones you'd extend unless necessary).
20
26
  - Use the project's test path convention: `src/modules/<module>/__tests__/<file>.test.ts`
21
27
  - Test categories: `unit` for isolated function tests, `integration` for multi-module tests, `e2e` for full pipeline tests.
22
- - Keep `coverage_notes` brief one sentence per AC is sufficient.
28
+ - `coverage_notes` must include: (a) which test file covers each AC, (b) dependencies to mock (e.g., `vi.mock('node:fs/promises')`), and (c) error conditions to assert (e.g., missing file, schema validation failure, timeout).
23
29
 
24
30
  ## Output Contract
25
31
 
@@ -31,7 +37,7 @@ test_files:
31
37
  test_categories:
32
38
  - unit
33
39
  - integration
34
- coverage_notes: "AC1 covered by foo.test.ts describe('runFoo'). AC2 covered by..."
40
+ coverage_notes: "AC1: foo.test.ts describe('runFoo') covers the happy path. AC2: same file covers error path (rejects on ENOENT). Mocks needed: vi.mock('node:fs/promises'), vi.mock('../db.js'). Error conditions: file not found returns failed result, schema parse error returns failed with details, timeout triggers fallback."
35
41
 
36
42
  If you cannot produce a plan (e.g., story content is missing or unreadable), emit:
37
43
 
@@ -1,7 +0,0 @@
1
- import { registerRunCommand, runRunAction } from "./run-IeDyGCak.js";
2
- import "./logger-D2fS2ccL.js";
3
- import "./helpers-DljGJnFF.js";
4
- import "./decisions-Dq4cAA2L.js";
5
- import "./operational-CnMlvWqc.js";
6
-
7
- export { runRunAction };
@@ -1,3 +0,0 @@
1
- import { VersionManagerImpl, createVersionManager } from "./version-manager-impl-CtzNu7YZ.js";
2
-
3
- export { createVersionManager };