substrate-ai 0.2.28 → 0.2.30

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,244 @@
1
+ import { readFileSync, writeFileSync } from "fs";
2
+ import { z } from "zod";
3
+
4
+ //#region src/modules/config/config-schema.ts
5
+ /** Subscription routing modes */
6
+ const SubscriptionRoutingSchema = z.enum([
7
+ "auto",
8
+ "subscription",
9
+ "api",
10
+ "disabled"
11
+ ]);
12
+ /** Rate limit configuration for a provider */
13
+ const RateLimitSchema = z.object({
14
+ tokens: z.number().int().positive(),
15
+ window_seconds: z.number().int().positive()
16
+ }).strict();
17
+ /** Per-provider configuration */
18
+ const ProviderConfigSchema = z.object({
19
+ enabled: z.boolean(),
20
+ cli_path: z.string().optional(),
21
+ subscription_routing: SubscriptionRoutingSchema,
22
+ max_concurrent: z.number().int().min(1).max(32),
23
+ rate_limit: RateLimitSchema.optional(),
24
+ api_key_env: z.string().optional(),
25
+ api_billing: z.boolean()
26
+ }).strict();
27
+ /** Map of all known providers */
28
+ const ProvidersSchema = z.object({
29
+ claude: ProviderConfigSchema.optional(),
30
+ codex: ProviderConfigSchema.optional(),
31
+ gemini: ProviderConfigSchema.optional()
32
+ }).strict();
33
+ const LogLevelSchema = z.enum([
34
+ "trace",
35
+ "debug",
36
+ "info",
37
+ "warn",
38
+ "error",
39
+ "fatal"
40
+ ]);
41
+ const GlobalSettingsSchema = z.object({
42
+ log_level: LogLevelSchema,
43
+ max_concurrent_tasks: z.number().int().min(1).max(64),
44
+ budget_cap_tokens: z.number().int().min(0),
45
+ budget_cap_usd: z.number().min(0),
46
+ workspace_dir: z.string().optional(),
47
+ update_check: z.boolean().optional()
48
+ }).strict();
49
+ const CostTrackerConfigSchema = z.object({
50
+ enabled: z.boolean(),
51
+ token_rates_provider: z.enum(["builtin", "custom"]),
52
+ track_planning_costs: z.boolean(),
53
+ savings_reporting: z.boolean()
54
+ }).strict();
55
+ const BudgetConfigSchema = z.object({
56
+ default_task_budget_usd: z.number().min(0),
57
+ default_session_budget_usd: z.number().min(0),
58
+ planning_costs_count_against_budget: z.boolean(),
59
+ warning_threshold_percent: z.number().min(0).max(100)
60
+ }).strict();
61
+ const RoutingRuleSchema = z.object({
62
+ task_type: z.string(),
63
+ preferred_provider: z.string(),
64
+ fallback_providers: z.array(z.string())
65
+ }).strict();
66
+ const RoutingPolicySchema = z.object({
67
+ default_provider: z.string(),
68
+ rules: z.array(RoutingRuleSchema)
69
+ }).strict();
70
+ /**
71
+ * Per-workflow token ceiling overrides.
72
+ * Keys match the workflow type names used in prompts and events.
73
+ * Values must be positive integers.
74
+ */
75
+ const TokenCeilingsSchema = z.object({
76
+ "create-story": z.number().int().positive("create-story token ceiling must be a positive integer").optional(),
77
+ "dev-story": z.number().int().positive("dev-story token ceiling must be a positive integer").optional(),
78
+ "code-review": z.number().int().positive("code-review token ceiling must be a positive integer").optional(),
79
+ "test-plan": z.number().int().positive("test-plan token ceiling must be a positive integer").optional(),
80
+ "test-expansion": z.number().int().positive("test-expansion token ceiling must be a positive integer").optional()
81
+ });
82
+ /** Current supported config format version */
83
+ const CURRENT_CONFIG_FORMAT_VERSION = "1";
84
+ /** Current supported task graph version */
85
+ const CURRENT_TASK_GRAPH_VERSION = "1";
86
+ /** All config format versions this toolkit can read and validate */
87
+ const SUPPORTED_CONFIG_FORMAT_VERSIONS = ["1"];
88
+ /** All task graph format versions this toolkit can read and validate */
89
+ const SUPPORTED_TASK_GRAPH_VERSIONS = ["1"];
90
+ const SubstrateConfigSchema = z.object({
91
+ config_format_version: z.enum(["1"]),
92
+ task_graph_version: z.enum(["1"]).optional(),
93
+ global: GlobalSettingsSchema,
94
+ providers: ProvidersSchema,
95
+ cost_tracker: CostTrackerConfigSchema.optional(),
96
+ budget: BudgetConfigSchema.optional(),
97
+ token_ceilings: TokenCeilingsSchema.optional()
98
+ }).strict();
99
+ const PartialProviderConfigSchema = ProviderConfigSchema.partial();
100
+ const PartialGlobalSettingsSchema = GlobalSettingsSchema.partial();
101
+ const PartialSubstrateConfigSchema = z.object({
102
+ config_format_version: z.enum(["1"]).optional(),
103
+ task_graph_version: z.enum(["1"]).optional(),
104
+ global: PartialGlobalSettingsSchema.optional(),
105
+ providers: z.object({
106
+ claude: PartialProviderConfigSchema.optional(),
107
+ codex: PartialProviderConfigSchema.optional(),
108
+ gemini: PartialProviderConfigSchema.optional()
109
+ }).partial().optional(),
110
+ cost_tracker: CostTrackerConfigSchema.partial().optional(),
111
+ budget: BudgetConfigSchema.partial().optional(),
112
+ token_ceilings: TokenCeilingsSchema.optional()
113
+ }).strict();
114
+
115
+ //#endregion
116
+ //#region src/modules/config/config-migrator.ts
117
+ /**
118
+ * ConfigMigrator manages a registry of migration functions and applies them
119
+ * sequentially to upgrade config documents from one format version to another.
120
+ */
121
+ var ConfigMigrator = class {
122
+ migrations = new Map();
123
+ /**
124
+ * Register a migration function for the given version key.
125
+ *
126
+ * @param key - Migration key in format "N->M" (e.g. "1->2")
127
+ * @param fn - Migration function that receives the raw config and returns the migrated config
128
+ */
129
+ register(key, fn) {
130
+ this.migrations.set(key, fn);
131
+ }
132
+ /**
133
+ * Check whether a sequential migration path exists from fromVersion to toVersion.
134
+ *
135
+ * @param fromVersion - Starting version string
136
+ * @param toVersion - Target version string
137
+ * @returns true if every step in the path is registered
138
+ */
139
+ canMigrate(fromVersion, toVersion) {
140
+ if (fromVersion === toVersion) return true;
141
+ const from = parseInt(fromVersion, 10);
142
+ const to = parseInt(toVersion, 10);
143
+ if (isNaN(from) || isNaN(to) || from >= to) return false;
144
+ for (let v = from; v < to; v++) {
145
+ const key = `${String(v)}->${String(v + 1)}`;
146
+ if (!this.migrations.has(key)) return false;
147
+ }
148
+ return true;
149
+ }
150
+ /**
151
+ * Apply sequential migrations from fromVersion to toVersion.
152
+ *
153
+ * If fromVersion === toVersion, returns a no-op success result.
154
+ * If any intermediate migration is missing, returns success:false.
155
+ *
156
+ * When filePath is provided and migration is needed, a backup is written to
157
+ * `${filePath}.bak.v${fromVersion}` before any transformations are applied.
158
+ *
159
+ * @param config - Raw config object to migrate
160
+ * @param fromVersion - Starting format version string
161
+ * @param toVersion - Target format version string
162
+ * @param filePath - Optional path to the source config file for backup creation
163
+ * @returns Object containing the (possibly migrated) config and a MigrationResult
164
+ */
165
+ migrate(config, fromVersion, toVersion, filePath) {
166
+ if (fromVersion === toVersion) return {
167
+ config,
168
+ result: {
169
+ success: true,
170
+ fromVersion,
171
+ toVersion,
172
+ migratedKeys: [],
173
+ manualStepsRequired: [],
174
+ backupPath: null
175
+ }
176
+ };
177
+ const from = parseInt(fromVersion, 10);
178
+ const to = parseInt(toVersion, 10);
179
+ if (isNaN(from) || isNaN(to) || from >= to) return {
180
+ config,
181
+ result: {
182
+ success: false,
183
+ fromVersion,
184
+ toVersion,
185
+ migratedKeys: [],
186
+ manualStepsRequired: [`Cannot migrate from version "${fromVersion}" to "${toVersion}": invalid version range.`],
187
+ backupPath: null
188
+ }
189
+ };
190
+ for (let v = from; v < to; v++) {
191
+ const key = `${String(v)}->${String(v + 1)}`;
192
+ if (!this.migrations.has(key)) return {
193
+ config,
194
+ result: {
195
+ success: false,
196
+ fromVersion,
197
+ toVersion,
198
+ migratedKeys: [],
199
+ manualStepsRequired: [`Missing migration step: "${key}". Cannot automatically migrate from version "${fromVersion}" to "${toVersion}". Please upgrade the toolkit: npm install -g substrate@latest`],
200
+ backupPath: null
201
+ }
202
+ };
203
+ }
204
+ let backupPath = null;
205
+ if (filePath !== void 0) {
206
+ backupPath = `${filePath}.bak.v${fromVersion}`;
207
+ const originalContent = readFileSync(filePath, "utf-8");
208
+ writeFileSync(backupPath, originalContent, "utf-8");
209
+ }
210
+ let current = config;
211
+ const migratedKeys = [];
212
+ for (let v = from; v < to; v++) {
213
+ const key = `${String(v)}->${String(v + 1)}`;
214
+ const fn = this.migrations.get(key);
215
+ const before = JSON.stringify(current);
216
+ current = fn(current);
217
+ const after = JSON.stringify(current);
218
+ if (current !== null && typeof current === "object" && !Array.isArray(current)) {
219
+ const beforeObj = JSON.parse(before);
220
+ const afterObj = JSON.parse(after);
221
+ for (const k of Object.keys(afterObj)) if (JSON.stringify(afterObj[k]) !== JSON.stringify(beforeObj[k])) {
222
+ if (!migratedKeys.includes(k)) migratedKeys.push(k);
223
+ }
224
+ }
225
+ }
226
+ return {
227
+ config: current,
228
+ result: {
229
+ success: true,
230
+ fromVersion,
231
+ toVersion,
232
+ migratedKeys,
233
+ manualStepsRequired: [],
234
+ backupPath
235
+ }
236
+ };
237
+ }
238
+ };
239
+ /** Singleton instance for use throughout the toolkit */
240
+ const defaultConfigMigrator = new ConfigMigrator();
241
+
242
+ //#endregion
243
+ export { CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, PartialSubstrateConfigSchema, SUPPORTED_CONFIG_FORMAT_VERSIONS, SUPPORTED_TASK_GRAPH_VERSIONS, SubstrateConfigSchema, defaultConfigMigrator };
244
+ //# sourceMappingURL=config-migrator-DSi8KhQC.js.map
@@ -500,4 +500,4 @@ function createExperimenter(config, deps) {
500
500
 
501
501
  //#endregion
502
502
  export { createExperimenter };
503
- //# sourceMappingURL=experimenter-bc40oi8p.js.map
503
+ //# sourceMappingURL=experimenter-f_Y1rreV.js.map
@@ -2,6 +2,115 @@ import * as readline from "node:readline";
2
2
  import { EventEmitter } from "node:events";
3
3
  import { randomUUID } from "crypto";
4
4
 
5
+ //#region src/core/errors.ts
6
+ /**
7
+ * Error definitions for Substrate
8
+ * Provides structured error hierarchy for all toolkit operations
9
+ */
10
+ /** Base error class for all Substrate errors */
11
+ var AdtError = class AdtError extends Error {
12
+ code;
13
+ context;
14
+ constructor(message, code, context = {}) {
15
+ super(message);
16
+ this.name = "AdtError";
17
+ this.code = code;
18
+ this.context = context;
19
+ if (Error.captureStackTrace) Error.captureStackTrace(this, AdtError);
20
+ }
21
+ toJSON() {
22
+ return {
23
+ name: this.name,
24
+ message: this.message,
25
+ code: this.code,
26
+ context: this.context,
27
+ stack: this.stack
28
+ };
29
+ }
30
+ };
31
+ /** Error thrown when task configuration is invalid */
32
+ var TaskConfigError = class extends AdtError {
33
+ constructor(message, context = {}) {
34
+ super(message, "TASK_CONFIG_ERROR", context);
35
+ this.name = "TaskConfigError";
36
+ }
37
+ };
38
+ /** Error thrown when a worker/agent operation fails */
39
+ var WorkerError = class extends AdtError {
40
+ constructor(message, context = {}) {
41
+ super(message, "WORKER_ERROR", context);
42
+ this.name = "WorkerError";
43
+ }
44
+ };
45
+ /** Error thrown when a worker/agent cannot be found */
46
+ var WorkerNotFoundError = class extends AdtError {
47
+ constructor(agentId) {
48
+ super(`Worker agent not found: ${agentId}`, "WORKER_NOT_FOUND", { agentId });
49
+ this.name = "WorkerNotFoundError";
50
+ }
51
+ };
52
+ /** Error thrown when a task graph is invalid */
53
+ var TaskGraphError = class extends AdtError {
54
+ constructor(message, context = {}) {
55
+ super(message, "TASK_GRAPH_ERROR", context);
56
+ this.name = "TaskGraphError";
57
+ }
58
+ };
59
+ /** Error thrown when a task graph has cycles (deadlock) */
60
+ var TaskGraphCycleError = class extends TaskGraphError {
61
+ constructor(cycle) {
62
+ super(`Circular dependency detected in task graph: ${cycle.join(" -> ")}`, { cycle });
63
+ this.name = "TaskGraphCycleError";
64
+ }
65
+ };
66
+ /** Error thrown when a budget limit is exceeded */
67
+ var BudgetExceededError = class extends AdtError {
68
+ constructor(limit, current, context = {}) {
69
+ super(`Budget cap exceeded: current=${String(current)}, limit=${String(limit)}`, "BUDGET_EXCEEDED", {
70
+ limit,
71
+ current,
72
+ ...context
73
+ });
74
+ this.name = "BudgetExceededError";
75
+ }
76
+ };
77
+ /** Error thrown when git operations fail */
78
+ var GitError = class extends AdtError {
79
+ constructor(message, context = {}) {
80
+ super(message, "GIT_ERROR", context);
81
+ this.name = "GitError";
82
+ }
83
+ };
84
+ /** Error thrown when configuration is invalid or missing */
85
+ var ConfigError = class extends AdtError {
86
+ constructor(message, context = {}) {
87
+ super(message, "CONFIG_ERROR", context);
88
+ this.name = "ConfigError";
89
+ }
90
+ };
91
+ /** Error thrown when state recovery fails */
92
+ var RecoveryError = class extends AdtError {
93
+ constructor(message, context = {}) {
94
+ super(message, "RECOVERY_ERROR", context);
95
+ this.name = "RecoveryError";
96
+ }
97
+ };
98
+ /** Error thrown when a config file uses an incompatible format version */
99
+ var ConfigIncompatibleFormatError = class extends AdtError {
100
+ constructor(message, context = {}) {
101
+ super(message, "CONFIG_INCOMPATIBLE_FORMAT", context);
102
+ this.name = "ConfigIncompatibleFormatError";
103
+ }
104
+ };
105
+ /** Error thrown when a task graph file uses an incompatible format version */
106
+ var TaskGraphIncompatibleFormatError = class extends AdtError {
107
+ constructor(message, context = {}) {
108
+ super(message, "TASK_GRAPH_INCOMPATIBLE_FORMAT", context);
109
+ this.name = "TaskGraphIncompatibleFormatError";
110
+ }
111
+ };
112
+
113
+ //#endregion
5
114
  //#region src/tui/ansi.ts
6
115
  /**
7
116
  * ANSI escape code helpers for TUI rendering.
@@ -807,5 +916,5 @@ async function withRetry(fn, maxRetries = 3, baseDelayMs = 100) {
807
916
  }
808
917
 
809
918
  //#endregion
810
- export { assertDefined, createEventBus, createTuiApp, deepClone, formatDuration, generateId, isPlainObject, isTuiCapable, printNonTtyWarning, sleep, withRetry };
811
- //# sourceMappingURL=helpers-DljGJnFF.js.map
919
+ export { AdtError, BudgetExceededError, ConfigError, ConfigIncompatibleFormatError, GitError, RecoveryError, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError, assertDefined, createEventBus, createTuiApp, deepClone, formatDuration, generateId, isPlainObject, isTuiCapable, printNonTtyWarning, sleep, withRetry };
920
+ //# sourceMappingURL=helpers-RL22dYtn.js.map
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { childLogger, createLogger, logger } from "./logger-D2fS2ccL.js";
2
- import { AdapterRegistry, AdtError, BudgetExceededError, ClaudeCodeAdapter, CodexCLIAdapter, ConfigError, ConfigIncompatibleFormatError, GeminiCLIAdapter, GitError, RecoveryError, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError } from "./errors-CswS7Mzg.js";
3
- import { assertDefined, createEventBus, createTuiApp, deepClone, formatDuration, generateId, isPlainObject, isTuiCapable, printNonTtyWarning, sleep, withRetry } from "./helpers-DljGJnFF.js";
2
+ import { AdapterRegistry, ClaudeCodeAdapter, CodexCLIAdapter, GeminiCLIAdapter } from "./adapter-registry-PsWhP_1Q.js";
3
+ import { AdtError, BudgetExceededError, ConfigError, ConfigIncompatibleFormatError, GitError, RecoveryError, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError, assertDefined, createEventBus, createTuiApp, deepClone, formatDuration, generateId, isPlainObject, isTuiCapable, printNonTtyWarning, sleep, withRetry } from "./helpers-RL22dYtn.js";
4
4
 
5
5
  //#region src/core/di.ts
6
6
  /**