substrate-ai 0.1.0

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/index.js ADDED
@@ -0,0 +1,465 @@
1
+ import { AdapterRegistry, AdtError, BudgetExceededError, ClaudeCodeAdapter, CodexCLIAdapter, ConfigError, ConfigIncompatibleFormatError, GeminiCLIAdapter, GitError, RecoveryError, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError, childLogger, computeChangedKeys, createConfigWatcher, createDatabaseService, createEventBus, createGitWorktreeManager, createLogger, createMonitorAgent, createMonitorDatabase, createRoutingEngine, createTaskGraphEngine, createWorkerPoolManager, logger } from "./config-watcher-P5CR4cZ0.js";
2
+ import "./config-schema-C9tTMcm1.js";
3
+ import { join } from "node:path";
4
+ import { randomUUID } from "crypto";
5
+
6
+ //#region src/utils/helpers.ts
7
+ /**
8
+ * Sleep for a given number of milliseconds
9
+ * @param ms - Milliseconds to sleep
10
+ */
11
+ function sleep(ms) {
12
+ return new Promise((resolve$1) => setTimeout(resolve$1, ms));
13
+ }
14
+ /**
15
+ * Assert that a value is defined (not null or undefined)
16
+ * @param value - Value to check
17
+ * @param message - Error message if undefined
18
+ */
19
+ function assertDefined(value, message) {
20
+ if (value === null || value === void 0) throw new Error(message);
21
+ }
22
+ /**
23
+ * Format a duration in milliseconds to a human-readable string
24
+ * @param ms - Duration in milliseconds
25
+ */
26
+ function formatDuration(ms) {
27
+ if (ms < 1e3) return `${String(ms)}ms`;
28
+ if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
29
+ if (ms < 36e5) {
30
+ const minutes$1 = Math.floor(ms / 6e4);
31
+ const seconds = Math.floor(ms % 6e4 / 1e3);
32
+ return `${String(minutes$1)}m ${String(seconds)}s`;
33
+ }
34
+ const hours = Math.floor(ms / 36e5);
35
+ const minutes = Math.floor(ms % 36e5 / 6e4);
36
+ return `${String(hours)}h ${String(minutes)}m`;
37
+ }
38
+ /**
39
+ * Generate a unique identifier using crypto.randomUUID()
40
+ * @param prefix - Optional prefix for the ID
41
+ */
42
+ function generateId(prefix = "") {
43
+ const uuid = randomUUID();
44
+ return prefix ? `${prefix}-${uuid}` : uuid;
45
+ }
46
+ /**
47
+ * Deep clone an object using structuredClone.
48
+ * Supports most built-in types (Date, Map, Set, ArrayBuffer, etc.)
49
+ * but does NOT support functions, DOM nodes, or symbols as keys.
50
+ * @param obj - Object to clone
51
+ */
52
+ function deepClone(obj) {
53
+ return structuredClone(obj);
54
+ }
55
+ /**
56
+ * Check if a value is a plain object (not an array, Date, or other special object)
57
+ * @param value - Value to check
58
+ */
59
+ function isPlainObject(value) {
60
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
61
+ const proto = Object.getPrototypeOf(value);
62
+ return proto === Object.prototype || proto === null;
63
+ }
64
+ /**
65
+ * Retry an async operation with exponential backoff
66
+ * @param fn - Async function to retry
67
+ * @param maxRetries - Maximum number of retries
68
+ * @param baseDelayMs - Base delay in milliseconds (doubles each retry)
69
+ */
70
+ async function withRetry(fn, maxRetries = 3, baseDelayMs = 100) {
71
+ let lastError;
72
+ for (let attempt = 0; attempt <= maxRetries; attempt++) try {
73
+ return await fn();
74
+ } catch (error) {
75
+ lastError = error instanceof Error ? error : new Error(String(error));
76
+ if (attempt < maxRetries) await sleep(baseDelayMs * Math.pow(2, attempt));
77
+ }
78
+ throw lastError ?? new Error("Operation failed after retries");
79
+ }
80
+
81
+ //#endregion
82
+ //#region src/core/di.ts
83
+ /**
84
+ * Simple service registry — stores named service instances for DI resolution.
85
+ *
86
+ * Services are registered by name and can be retrieved by name or iterated
87
+ * in registration order for lifecycle management.
88
+ *
89
+ * @example
90
+ * const registry = new ServiceRegistry()
91
+ * registry.register('taskGraph', taskGraphEngine)
92
+ * registry.register('workerManager', workerManager)
93
+ *
94
+ * // Initialize all services
95
+ * await registry.initializeAll()
96
+ *
97
+ * // Shutdown all services in reverse order
98
+ * await registry.shutdownAll()
99
+ */
100
+ var ServiceRegistry = class {
101
+ _services = new Map();
102
+ _order = [];
103
+ /**
104
+ * Register a named service. Registration order is preserved for lifecycle calls.
105
+ * @throws {Error} if a service with the same name is already registered.
106
+ */
107
+ register(name, service) {
108
+ if (this._services.has(name)) throw new Error(`Service "${name}" is already registered`);
109
+ this._services.set(name, service);
110
+ this._order.push(name);
111
+ }
112
+ /**
113
+ * Retrieve a registered service by name.
114
+ * @throws {Error} if no service with the given name is registered.
115
+ */
116
+ get(name) {
117
+ const service = this._services.get(name);
118
+ if (service === void 0) throw new Error(`Service "${name}" is not registered`);
119
+ return service;
120
+ }
121
+ /**
122
+ * Returns true if a service with the given name is registered.
123
+ */
124
+ has(name) {
125
+ return this._services.has(name);
126
+ }
127
+ /**
128
+ * Initialize all registered services in registration order.
129
+ * Fails fast on the first error — later services may depend on
130
+ * already-initialized ones, so continuing after a failure is unsafe.
131
+ * @throws the first initialization error encountered.
132
+ */
133
+ async initializeAll() {
134
+ for (const name of this._order) {
135
+ const service = this._services.get(name);
136
+ if (service !== void 0) await service.initialize();
137
+ }
138
+ }
139
+ /**
140
+ * Shut down all registered services in reverse registration order.
141
+ * Errors are collected and re-thrown as an AggregateError after all services
142
+ * have had a chance to shut down.
143
+ */
144
+ async shutdownAll() {
145
+ const errors = [];
146
+ const reversed = [...this._order].reverse();
147
+ for (const name of reversed) {
148
+ const service = this._services.get(name);
149
+ if (service !== void 0) try {
150
+ await service.shutdown();
151
+ } catch (err) {
152
+ errors.push(err instanceof Error ? err : new Error(String(err)));
153
+ }
154
+ }
155
+ if (errors.length > 0) throw new AggregateError(errors, `Shutdown errors in ${errors.length} service(s)`);
156
+ }
157
+ /** Return names of all registered services in registration order */
158
+ get serviceNames() {
159
+ return [...this._order];
160
+ }
161
+ };
162
+
163
+ //#endregion
164
+ //#region src/modules/budget/budget-tracker.ts
165
+ const logger$3 = createLogger("budget");
166
+ var BudgetTrackerImpl = class {
167
+ _eventBus;
168
+ constructor(eventBus) {
169
+ this._eventBus = eventBus;
170
+ }
171
+ async initialize() {
172
+ logger$3.info("BudgetTracker.initialize() — stub");
173
+ this._eventBus.on("budget:warning", ({ taskId, currentSpend, limit }) => {
174
+ logger$3.warn({
175
+ taskId,
176
+ currentSpend,
177
+ limit
178
+ }, "budget:warning");
179
+ });
180
+ this._eventBus.on("budget:exceeded", ({ taskId, spend, limit }) => {
181
+ logger$3.error({
182
+ taskId,
183
+ spend,
184
+ limit
185
+ }, "budget:exceeded");
186
+ });
187
+ this._eventBus.on("task:complete", ({ taskId, result }) => {
188
+ logger$3.debug({
189
+ taskId,
190
+ costUsd: result.costUsd
191
+ }, "task:complete — accumulate cost");
192
+ });
193
+ this._eventBus.on("task:progress", ({ taskId, tokensUsed }) => {
194
+ logger$3.debug({
195
+ taskId,
196
+ tokensUsed
197
+ }, "task:progress — update token usage");
198
+ });
199
+ }
200
+ async shutdown() {
201
+ logger$3.info("BudgetTracker.shutdown() — stub");
202
+ }
203
+ };
204
+ function createBudgetTracker(options) {
205
+ return new BudgetTrackerImpl(options.eventBus);
206
+ }
207
+
208
+ //#endregion
209
+ //#region src/modules/git/git-manager.ts
210
+ const logger$2 = createLogger("git");
211
+ var GitManagerImpl = class {
212
+ _eventBus;
213
+ repoRoot;
214
+ constructor(eventBus, repoRoot) {
215
+ this._eventBus = eventBus;
216
+ this.repoRoot = repoRoot;
217
+ }
218
+ async initialize() {
219
+ logger$2.info({ repoRoot: this.repoRoot }, "GitManager.initialize() — stub");
220
+ this._eventBus.on("worktree:created", ({ taskId, worktreePath, branchName }) => {
221
+ logger$2.debug({
222
+ taskId,
223
+ worktreePath,
224
+ branchName
225
+ }, "worktree:created");
226
+ });
227
+ this._eventBus.on("worktree:merged", ({ taskId, branch }) => {
228
+ logger$2.debug({
229
+ taskId,
230
+ branch
231
+ }, "worktree:merged");
232
+ });
233
+ this._eventBus.on("worktree:conflict", ({ taskId, conflictingFiles }) => {
234
+ logger$2.warn({
235
+ taskId,
236
+ conflictingFiles
237
+ }, "worktree:conflict");
238
+ });
239
+ this._eventBus.on("worktree:removed", ({ taskId, branchName }) => {
240
+ logger$2.debug({
241
+ taskId,
242
+ branchName
243
+ }, "worktree:removed");
244
+ });
245
+ }
246
+ async shutdown() {
247
+ logger$2.info("GitManager.shutdown() — stub");
248
+ }
249
+ };
250
+ function createGitManager(options) {
251
+ return new GitManagerImpl(options.eventBus, options.repoRoot);
252
+ }
253
+
254
+ //#endregion
255
+ //#region src/core/orchestrator-impl.ts
256
+ const logger$1 = createLogger("orchestrator");
257
+ /** Internal symbol used to expose lifecycle hooks to the factory only */
258
+ const INTERNAL = Symbol("OrchestratorImpl.internal");
259
+ var OrchestratorImpl = class {
260
+ eventBus;
261
+ _registry;
262
+ _ready = false;
263
+ _shutdown = false;
264
+ _shutdownHandlersRegistered = false;
265
+ _configWatcher = null;
266
+ constructor(eventBus, registry) {
267
+ this.eventBus = eventBus;
268
+ this._registry = registry;
269
+ }
270
+ get isReady() {
271
+ return this._ready;
272
+ }
273
+ async shutdown() {
274
+ if (this._shutdown) return;
275
+ this._shutdown = true;
276
+ logger$1.info("Orchestrator shutdown initiated");
277
+ this.eventBus.emit("orchestrator:shutdown", { reason: "shutdown() called" });
278
+ if (this._configWatcher !== null) {
279
+ this._configWatcher.stop();
280
+ this._configWatcher = null;
281
+ }
282
+ try {
283
+ await this._registry.shutdownAll();
284
+ } catch (err) {
285
+ logger$1.error({ err }, "Error during orchestrator shutdown");
286
+ }
287
+ logger$1.info("Orchestrator shutdown complete");
288
+ }
289
+ _markReady() {
290
+ this._ready = true;
291
+ }
292
+ _sigtermHandler = null;
293
+ _sigintHandler = null;
294
+ _registerShutdownHandlers() {
295
+ if (this._shutdownHandlersRegistered) return;
296
+ this._shutdownHandlersRegistered = true;
297
+ const makeHandler = (signal) => () => {
298
+ logger$1.info({ signal }, "Received signal — initiating graceful shutdown");
299
+ this.shutdown().then(() => {
300
+ process.exit(0);
301
+ }).catch((err) => {
302
+ logger$1.error({ err }, "Error during signal-triggered shutdown");
303
+ process.exit(1);
304
+ });
305
+ };
306
+ this._sigtermHandler = makeHandler("SIGTERM");
307
+ this._sigintHandler = makeHandler("SIGINT");
308
+ process.once("SIGTERM", this._sigtermHandler);
309
+ process.once("SIGINT", this._sigintHandler);
310
+ }
311
+ _removeShutdownHandlers() {
312
+ if (this._sigtermHandler !== null) {
313
+ process.removeListener("SIGTERM", this._sigtermHandler);
314
+ this._sigtermHandler = null;
315
+ }
316
+ if (this._sigintHandler !== null) {
317
+ process.removeListener("SIGINT", this._sigintHandler);
318
+ this._sigintHandler = null;
319
+ }
320
+ }
321
+ /**
322
+ * Internal accessor used exclusively by the createOrchestrator factory.
323
+ * Do not call outside of this module.
324
+ * @internal
325
+ */
326
+ [INTERNAL]() {
327
+ return {
328
+ markReady: () => this._markReady(),
329
+ registerShutdownHandlers: () => this._registerShutdownHandlers(),
330
+ removeShutdownHandlers: () => this._removeShutdownHandlers(),
331
+ setConfigWatcher: (watcher) => {
332
+ this._configWatcher = watcher;
333
+ }
334
+ };
335
+ }
336
+ };
337
+ /**
338
+ * Initialize the orchestrator with all modules wired via dependency injection.
339
+ *
340
+ * Steps performed:
341
+ * 1. Create the TypedEventBus
342
+ * 2. Create the SQLite database service
343
+ * 3. Instantiate all modules (TaskGraphEngine, RoutingEngine, WorkerManager,
344
+ * BudgetTracker, GitManager) with constructor injection
345
+ * 4. Register all modules in the ServiceRegistry
346
+ * 5. Call initialize() on all services in registration order
347
+ * 6. Register SIGTERM/SIGINT graceful shutdown handlers
348
+ * 7. Emit orchestrator:ready
349
+ *
350
+ * @param config - Orchestrator configuration
351
+ * @returns Initialized Orchestrator instance
352
+ */
353
+ async function createOrchestrator(config) {
354
+ logger$1.info({ databasePath: config.databasePath }, "Initializing orchestrator");
355
+ const eventBus = createEventBus();
356
+ const databaseService = createDatabaseService(config.databasePath);
357
+ const taskGraphEngine = createTaskGraphEngine({
358
+ eventBus,
359
+ databaseService
360
+ });
361
+ const adapterRegistry = new AdapterRegistry();
362
+ const routingEngine = createRoutingEngine({
363
+ eventBus,
364
+ adapterRegistry
365
+ });
366
+ const budgetTracker = createBudgetTracker({ eventBus });
367
+ const gitManager = createGitManager({
368
+ eventBus,
369
+ repoRoot: config.projectRoot
370
+ });
371
+ const gitWorktreeManager = createGitWorktreeManager({
372
+ eventBus,
373
+ projectRoot: config.projectRoot,
374
+ db: databaseService
375
+ });
376
+ const workerPoolManager = createWorkerPoolManager({
377
+ eventBus,
378
+ adapterRegistry,
379
+ engine: taskGraphEngine,
380
+ db: databaseService,
381
+ gitWorktreeManager
382
+ });
383
+ const monitorDbPath = config.monitor?.databasePath ?? ":memory:";
384
+ const monitorDatabase = createMonitorDatabase(monitorDbPath);
385
+ const monitorAgent = createMonitorAgent({
386
+ eventBus,
387
+ monitorDb: monitorDatabase,
388
+ config: {
389
+ retentionDays: config.monitor?.retentionDays ?? 90,
390
+ customTaxonomy: config.monitor?.customTaxonomy,
391
+ use_recommendations: config.monitor?.use_recommendations ?? false,
392
+ recommendation_threshold_percentage: config.monitor?.recommendation_threshold_percentage,
393
+ min_sample_size: config.monitor?.min_sample_size,
394
+ recommendation_history_days: config.monitor?.recommendation_history_days
395
+ }
396
+ });
397
+ const registry = new ServiceRegistry();
398
+ registry.register("database", databaseService);
399
+ registry.register("taskGraph", taskGraphEngine);
400
+ registry.register("routingEngine", routingEngine);
401
+ registry.register("gitWorktreeManager", gitWorktreeManager);
402
+ registry.register("workerPoolManager", workerPoolManager);
403
+ registry.register("budgetTracker", budgetTracker);
404
+ registry.register("gitManager", gitManager);
405
+ registry.register("monitorAgent", monitorAgent);
406
+ const orchestrator = new OrchestratorImpl(eventBus, registry);
407
+ const internal = orchestrator[INTERNAL]();
408
+ try {
409
+ await registry.initializeAll();
410
+ } catch (err) {
411
+ logger$1.error({ err }, "Service initialization failed — cleaning up");
412
+ internal.removeShutdownHandlers();
413
+ try {
414
+ await registry.shutdownAll();
415
+ } catch (shutdownErr) {
416
+ logger$1.error({ err: shutdownErr }, "Error during cleanup after failed initialization");
417
+ }
418
+ throw err;
419
+ }
420
+ internal.registerShutdownHandlers();
421
+ const enableConfigHotReload = config.enableConfigHotReload ?? true;
422
+ if (enableConfigHotReload) {
423
+ const configFilePath = config.configPath ?? join(config.projectRoot, "substrate.config.yaml");
424
+ let currentConfig = null;
425
+ const configWatcher = createConfigWatcher({
426
+ configPath: configFilePath,
427
+ onReload: (newConfig) => {
428
+ const previousConfig = currentConfig;
429
+ if (previousConfig === null) {
430
+ currentConfig = newConfig;
431
+ return;
432
+ }
433
+ const changedKeys = computeChangedKeys(previousConfig, newConfig);
434
+ currentConfig = newConfig;
435
+ const n = changedKeys.length;
436
+ logger$1.info({
437
+ changedKeys,
438
+ configPath: configFilePath
439
+ }, `Config reloaded: ${n} setting(s) changed`);
440
+ eventBus.emit("config:reloaded", {
441
+ path: configFilePath,
442
+ previousConfig,
443
+ newConfig,
444
+ changedKeys
445
+ });
446
+ },
447
+ onError: (err) => {
448
+ logger$1.error({
449
+ err,
450
+ configPath: configFilePath
451
+ }, `Config reload failed: ${err.message}. Continuing with previous config.`);
452
+ }
453
+ });
454
+ configWatcher.start();
455
+ internal.setConfigWatcher(configWatcher);
456
+ }
457
+ internal.markReady();
458
+ eventBus.emit("orchestrator:ready", {});
459
+ logger$1.info("Orchestrator ready");
460
+ return orchestrator;
461
+ }
462
+
463
+ //#endregion
464
+ export { AdapterRegistry, AdtError, BudgetExceededError, ClaudeCodeAdapter, CodexCLIAdapter, ConfigError, ConfigIncompatibleFormatError, GeminiCLIAdapter, GitError, RecoveryError, ServiceRegistry, TaskConfigError, TaskGraphCycleError, TaskGraphError, TaskGraphIncompatibleFormatError, WorkerError, WorkerNotFoundError, assertDefined, childLogger, createEventBus, createLogger, createOrchestrator, deepClone, formatDuration, generateId, isPlainObject, logger, sleep, withRetry };
465
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,5 @@
1
+ import "./config-schema-C9tTMcm1.js";
2
+ import "./version-manager-impl-DbHmed-I.js";
3
+ import { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand } from "./upgrade-BBPbOHol.js";
4
+
5
+ export { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand };
@@ -0,0 +1,126 @@
1
+ import { createVersionManager } from "./version-manager-impl-DbHmed-I.js";
2
+ import { execSync, spawn } from "child_process";
3
+ import * as readline from "readline";
4
+
5
+ //#region src/cli/commands/upgrade.ts
6
+ /**
7
+ * Detect whether substrate is installed globally.
8
+ */
9
+ function isGlobalInstall() {
10
+ try {
11
+ execSync("npm list -g substrate --depth=0", { stdio: "ignore" });
12
+ return true;
13
+ } catch {
14
+ return false;
15
+ }
16
+ }
17
+ function printVersionTable(currentVersion, latestVersion, isBreaking, changelog) {
18
+ console.log("\nSubstrate update available:");
19
+ console.log(` Current version : v${currentVersion}`);
20
+ console.log(` Latest version : v${latestVersion}`);
21
+ console.log(` Breaking changes: ${isBreaking ? "Yes (major version bump)" : "No"}`);
22
+ console.log(` Changelog : ${changelog}`);
23
+ console.log();
24
+ }
25
+ async function promptConfirm(question) {
26
+ const rl = readline.createInterface({
27
+ input: process.stdin,
28
+ output: process.stdout
29
+ });
30
+ return new Promise((resolve) => {
31
+ rl.question(question, (answer) => {
32
+ rl.close();
33
+ resolve(answer.toLowerCase() === "y");
34
+ });
35
+ });
36
+ }
37
+ async function runNpmInstall(version, global, spawnFn = spawn) {
38
+ const args = global ? [
39
+ "install",
40
+ "-g",
41
+ `substrate@${version}`
42
+ ] : ["install", `substrate@${version}`];
43
+ return new Promise((resolve, reject) => {
44
+ const child = spawnFn("npm", args, { stdio: "inherit" });
45
+ child.on("close", (code) => {
46
+ if (code === 0) resolve();
47
+ else reject(new Error(`npm install exited with code ${String(code)}`));
48
+ });
49
+ child.on("error", (err) => {
50
+ reject(new Error(`Failed to spawn npm: ${err.message}`));
51
+ });
52
+ });
53
+ }
54
+ /**
55
+ * Execute the upgrade command logic.
56
+ * Exported for testability.
57
+ */
58
+ async function runUpgradeCommand(options) {
59
+ const versionManager = options.versionManager ?? createVersionManager();
60
+ const promptFn = options.promptFn ?? promptConfirm;
61
+ const spawnFn = options.spawnFn ?? spawn;
62
+ if (options.check) {
63
+ let result$1;
64
+ try {
65
+ result$1 = await versionManager.checkForUpdates(true);
66
+ } catch {
67
+ process.stderr.write("Warning: Could not reach npm registry to check for updates. Continuing anyway.\n");
68
+ return;
69
+ }
70
+ if (!result$1.updateAvailable) {
71
+ console.log(`substrate is up to date (v${result$1.currentVersion})`);
72
+ return;
73
+ }
74
+ printVersionTable(result$1.currentVersion, result$1.latestVersion, result$1.isBreaking, result$1.changelog);
75
+ return;
76
+ }
77
+ let result;
78
+ try {
79
+ result = await versionManager.checkForUpdates();
80
+ } catch {
81
+ process.stderr.write("Warning: Could not reach npm registry to check for updates. Continuing anyway.\n");
82
+ return;
83
+ }
84
+ if (!result.updateAvailable) {
85
+ console.log(`substrate is up to date (v${result.currentVersion})`);
86
+ return;
87
+ }
88
+ const preview = versionManager.getUpgradePreview(result.latestVersion);
89
+ printVersionTable(result.currentVersion, result.latestVersion, result.isBreaking, result.changelog);
90
+ if (preview.breakingChanges.length > 0) {
91
+ console.log("Breaking changes:");
92
+ for (const change of preview.breakingChanges) console.log(` - ${change}`);
93
+ console.log();
94
+ }
95
+ if (preview.migrationSteps.length > 0) {
96
+ console.log("Migration steps:");
97
+ for (const step of preview.migrationSteps) console.log(` - ${step}`);
98
+ console.log();
99
+ }
100
+ if (!options.yes) {
101
+ const confirmed = await promptFn(`Upgrade substrate from v${result.currentVersion} to v${result.latestVersion}? (y/N) `);
102
+ if (!confirmed) {
103
+ console.log("Upgrade aborted.");
104
+ return;
105
+ }
106
+ }
107
+ const global = isGlobalInstall();
108
+ console.log(`Running: npm install ${global ? "-g " : ""}substrate@${result.latestVersion}`);
109
+ try {
110
+ await runNpmInstall(result.latestVersion, global, spawnFn);
111
+ console.log(`\nSuccessfully upgraded to v${result.latestVersion}`);
112
+ } catch (err) {
113
+ const message = err instanceof Error ? err.message : String(err);
114
+ process.stderr.write(`Upgrade failed: ${message}\n`);
115
+ process.exitCode = 1;
116
+ }
117
+ }
118
+ function registerUpgradeCommand(program) {
119
+ program.command("upgrade").description("Check for updates and upgrade substrate to the latest version").option("--check", "Check for updates without upgrading").option("-y, --yes", "Skip confirmation prompt (non-interactive upgrade)").action(async (options) => {
120
+ await runUpgradeCommand(options);
121
+ });
122
+ }
123
+
124
+ //#endregion
125
+ export { isGlobalInstall, registerUpgradeCommand, runUpgradeCommand };
126
+ //# sourceMappingURL=upgrade-BBPbOHol.js.map
@@ -0,0 +1,4 @@
1
+ import "./config-schema-C9tTMcm1.js";
2
+ import { VersionManagerImpl, createVersionManager } from "./version-manager-impl-DbHmed-I.js";
3
+
4
+ export { createVersionManager };