substrate-ai 0.20.78 → 0.20.80

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
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import { FileStateStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion } from "../health-EyALt_76.js";
2
+ import { FileStateStore, SUBSTRATE_OWNED_SETTINGS_KEYS, VALID_PHASES, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion } from "../health-CuKzY0Fn.js";
3
3
  import { createLogger } from "../logger-KeHncl-f.js";
4
4
  import { createEventBus } from "../helpers-CElYrONe.js";
5
5
  import { AdapterRegistry, BudgetConfigSchema, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, ConfigError, CostTrackerConfigSchema, DEFAULT_CONFIG, DoltClient, DoltNotInstalled, GlobalSettingsSchema, InMemoryDatabaseAdapter, IngestionServer, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProvidersSchema, RoutingRecommender, STORY_METRICS, TelemetryConfigSchema, addTokenUsage, aggregateTokenUsageForRun, checkDoltInstalled, compareRunMetrics, createAmendmentRun, createConfigSystem, createDecision, createDoltClient, createPipelineRun, getActiveDecisions, getAllCostEntriesFiltered, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRunMetrics, loadParentRunDecisions, supersedeDecision, swallowDebug, tagRunAsBaseline, updatePipelineRun } from "../dist-DCBSXUiX.js";
6
- import "../adapter-registry-DXLMTmfD.js";
7
- import { RunManifest, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, parseRuntimeProbes, readCurrentRunId, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck } from "../manifest-read-DP4lBymM.js";
8
- import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-5R5ZPgSw.js";
6
+ import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createGitWorktreeManager, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-Bhe2gX2V.js";
7
+ import "../adapter-registry-DIcrxjH8.js";
8
+ import { RunManifest, SupervisorLock, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, parseRuntimeProbes, readCurrentRunId, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics, runAcTraceabilityCheck } from "../manifest-read-Boipz5aP.js";
9
9
  import "../errors-D7xD-utp.js";
10
10
  import "../routing-DFxoKHDt.js";
11
11
  import { WorkGraphRepository } from "../work-graph-repository-DZyJv5pV.js";
12
12
  import "../decisions-CzSIEeGP.js";
13
13
  import "../decision-router-DblHY8se.js";
14
- import "../interactive-prompt-DqvUvzPv.js";
14
+ import "../interactive-prompt-CsvMelhG.js";
15
15
  import "../recovery-engine-BKGBeBnW.js";
16
16
  import "../version-manager-impl-qFBiO4Eh.js";
17
17
  import { registerUpgradeCommand } from "../upgrade-BMnmwTu6.js";
@@ -23,15 +23,13 @@ import { EventEmitter } from "node:events";
23
23
  import yaml from "js-yaml";
24
24
  import * as actualFS from "node:fs";
25
25
  import { existsSync, promises, readFileSync, writeFileSync } from "node:fs";
26
- import { execFile, spawn, spawnSync } from "node:child_process";
27
- import * as path$3 from "node:path";
28
- import * as path$2 from "node:path";
26
+ import { execFile, spawnSync } from "node:child_process";
29
27
  import * as path$1 from "node:path";
30
28
  import { basename as basename$1, join as join$1, posix, relative, resolve as resolve$1, win32 } from "node:path";
31
29
  import { randomUUID } from "node:crypto";
32
30
  import { z } from "zod";
33
31
  import * as fs from "node:fs/promises";
34
- import { access as access$1, lstat, readFile as readFile$1, readdir as readdir$1, readlink, realpath } from "node:fs/promises";
32
+ import { lstat, readFile as readFile$1, readdir as readdir$1, readlink, realpath } from "node:fs/promises";
35
33
  import { appendFileSync, chmodSync, cpSync, existsSync as existsSync$1, lstatSync, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdir as readdir$2, readdirSync as readdirSync$1, readlinkSync, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync as statSync$1, unlinkSync as unlinkSync$1, writeFileSync as writeFileSync$1 } from "fs";
36
34
  import { homedir } from "os";
37
35
  import { createRequire } from "node:module";
@@ -41,605 +39,6 @@ import { createInterface } from "node:readline";
41
39
  import { randomUUID as randomUUID$1 } from "crypto";
42
40
  import { createInterface as createInterface$1 } from "readline";
43
41
 
44
- //#region packages/core/dist/git/git-utils.js
45
- const MIN_GIT_MAJOR = 2;
46
- const MIN_GIT_MINOR = 20;
47
- /**
48
- * Spawn a git subprocess with the given args.
49
- *
50
- * @param args - Arguments to pass to git (e.g., ['worktree', 'add', ...])
51
- * @param options - Optional spawn options (cwd, env)
52
- * @returns - Object with stdout, stderr, and exit code
53
- */
54
- function spawnGit(args, options) {
55
- return new Promise((resolve$2) => {
56
- const proc = spawn("git", args, {
57
- cwd: options?.cwd,
58
- env: options?.env ?? process.env,
59
- stdio: [
60
- "ignore",
61
- "pipe",
62
- "pipe"
63
- ]
64
- });
65
- let stdout = "";
66
- let stderr = "";
67
- proc.stdout?.on("data", (chunk) => {
68
- stdout += chunk.toString();
69
- });
70
- proc.stderr?.on("data", (chunk) => {
71
- stderr += chunk.toString();
72
- });
73
- proc.on("close", (code) => {
74
- resolve$2({
75
- stdout: stdout.trim(),
76
- stderr: stderr.trim(),
77
- code: code ?? 1
78
- });
79
- });
80
- proc.on("error", (err) => {
81
- resolve$2({
82
- stdout: "",
83
- stderr: err.message,
84
- code: 1
85
- });
86
- });
87
- });
88
- }
89
- /**
90
- * Get the installed git version string.
91
- *
92
- * @returns Version string like "2.42.0"
93
- * @throws Error if git is not installed or version cannot be parsed
94
- */
95
- async function getGitVersion() {
96
- const result = await spawnGit(["--version"]);
97
- if (result.code !== 0) throw new Error(`git --version failed: ${result.stderr}`);
98
- const match = /git version\s+(\d+\.\d+(?:\.\d+)?)/.exec(result.stdout);
99
- if (match === null || match[1] === void 0) throw new Error(`Unable to parse git version from output: "${result.stdout}"`);
100
- return match[1];
101
- }
102
- /**
103
- * Parse a git version string into major/minor/patch components.
104
- *
105
- * @param versionString - Version string like "2.42.0" or "2.20"
106
- * @returns - Parsed version components
107
- */
108
- function parseGitVersion(versionString) {
109
- const parts = versionString.split(".").map(Number);
110
- return {
111
- major: parts[0] ?? 0,
112
- minor: parts[1] ?? 0,
113
- patch: parts[2] ?? 0
114
- };
115
- }
116
- /**
117
- * Check if the given git version string is >= 2.20.0.
118
- *
119
- * @param version - Version string like "2.42.0"
120
- * @returns - true if version >= 2.20.0
121
- */
122
- function isGitVersionSupported(version) {
123
- const { major, minor } = parseGitVersion(version);
124
- if (major > MIN_GIT_MAJOR) return true;
125
- if (major === MIN_GIT_MAJOR && minor >= MIN_GIT_MINOR) return true;
126
- return false;
127
- }
128
- /**
129
- * Verify that git is installed and version >= 2.20.
130
- *
131
- * @throws Error with clear message if git is not installed or too old
132
- */
133
- async function verifyGitVersion() {
134
- let version;
135
- try {
136
- version = await getGitVersion();
137
- } catch (err) {
138
- throw new Error(`git is not installed or could not be executed. Please install git 2.20 or newer. Details: ${String(err)}`);
139
- }
140
- if (!isGitVersionSupported(version)) {
141
- const { major, minor, patch } = parseGitVersion(version);
142
- throw new Error(`Git version ${major}.${minor}.${patch} is too old. Substrate requires git 2.20 or newer. Please upgrade git: https://git-scm.com/downloads`);
143
- }
144
- }
145
- /**
146
- * Create a git worktree and its associated branch.
147
- *
148
- * Uses a single `git worktree add {worktreePath} -b {branchName} {baseBranch}`
149
- * command to create the worktree with a new branch in one step.
150
- *
151
- * @param projectRoot - Absolute path to the git repository root
152
- * @param taskId - Task identifier (used in path derivation)
153
- * @param branchName - Branch name to create (e.g., "substrate/task-abc123")
154
- * @param baseBranch - Branch to base the worktree on (e.g., "main")
155
- * @returns - Object with the worktreePath
156
- * @throws - Error if git command fails
157
- */
158
- async function createWorktree(projectRoot, taskId, branchName, baseBranch) {
159
- const worktreePath = path$3.join(projectRoot, ".substrate-worktrees", taskId);
160
- const addResult = await spawnGit([
161
- "worktree",
162
- "add",
163
- worktreePath,
164
- "-b",
165
- branchName,
166
- baseBranch
167
- ], { cwd: projectRoot });
168
- if (addResult.code !== 0) throw new Error(`git worktree add failed for task "${taskId}": ${addResult.stderr || addResult.stdout}`);
169
- return { worktreePath };
170
- }
171
- /**
172
- * Remove a git worktree by path.
173
- *
174
- * Uses `git worktree remove --force` to handle unclean worktrees.
175
- *
176
- * @param worktreePath - Absolute path to the worktree directory
177
- * @param projectRoot - Absolute path to the git repository root
178
- * @throws - Error if git command fails
179
- */
180
- async function removeWorktree(worktreePath, projectRoot) {
181
- const spawnOpts = {};
182
- if (projectRoot !== void 0) spawnOpts.cwd = projectRoot;
183
- const result = await spawnGit([
184
- "worktree",
185
- "remove",
186
- "--force",
187
- worktreePath
188
- ], spawnOpts);
189
- if (result.code !== 0) throw new Error(`git worktree remove failed for "${worktreePath}": ${result.stderr || result.stdout}`);
190
- }
191
- /**
192
- * Delete a git branch using `git branch -D`.
193
- *
194
- * @param branchName - Branch name to delete (e.g., "substrate/task-abc123")
195
- * @param projectRoot - Absolute path to the git repository root
196
- * @returns - true if branch was successfully deleted, false otherwise
197
- */
198
- async function removeBranch(branchName, projectRoot) {
199
- const spawnOpts = {};
200
- if (projectRoot !== void 0) spawnOpts.cwd = projectRoot;
201
- const result = await spawnGit([
202
- "branch",
203
- "-D",
204
- branchName
205
- ], spawnOpts);
206
- if (result.code !== 0) return false;
207
- return true;
208
- }
209
- /**
210
- * Scan the worktrees base directory and return paths of all found worktree directories.
211
- *
212
- * @param projectRoot - Absolute path to the git repository root
213
- * @param baseDirectory - Relative directory name for worktrees (default: '.substrate-worktrees')
214
- * @returns - Array of absolute worktree directory paths
215
- */
216
- async function getOrphanedWorktrees(projectRoot, baseDirectory = ".substrate-worktrees") {
217
- const worktreesDir = path$3.join(projectRoot, baseDirectory);
218
- try {
219
- await access$1(worktreesDir);
220
- } catch {
221
- return [];
222
- }
223
- let entries;
224
- try {
225
- entries = await readdir$1(worktreesDir, { withFileTypes: true });
226
- } catch {
227
- return [];
228
- }
229
- return entries.filter((entry) => entry.isDirectory()).map((entry) => path$3.join(worktreesDir, entry.name));
230
- }
231
- /**
232
- * Simulate a merge using git merge --no-commit --no-ff without committing.
233
- *
234
- * This runs in the target branch's working directory (the project root or
235
- * worktree path). The simulation must be aborted after checking conflicts
236
- * via abortMerge().
237
- *
238
- * @param branchName - The source branch to simulate merging
239
- * @param cwd - Working directory (must be on the target branch)
240
- * @returns - true if merge would be clean, false if there are conflicts
241
- */
242
- async function simulateMerge(branchName, cwd) {
243
- const result = await spawnGit([
244
- "merge",
245
- "--no-commit",
246
- "--no-ff",
247
- branchName
248
- ], { cwd });
249
- if (result.code === 0) return true;
250
- return false;
251
- }
252
- /**
253
- * Abort a merge in progress using git merge --abort.
254
- *
255
- * Should be called after simulateMerge() to clean up the merge state,
256
- * regardless of whether conflicts were found.
257
- *
258
- * @param cwd - Working directory (same as used for simulateMerge)
259
- */
260
- async function abortMerge(cwd) {
261
- await spawnGit(["merge", "--abort"], { cwd });
262
- }
263
- /**
264
- * Get a list of files with conflicts during a merge.
265
- *
266
- * Must be called while a merge is in progress (after simulateMerge() and
267
- * before abortMerge()).
268
- *
269
- * @param cwd - Working directory of the repository
270
- * @returns - Array of conflicting file paths
271
- */
272
- async function getConflictingFiles(cwd) {
273
- const result = await spawnGit([
274
- "diff",
275
- "--name-only",
276
- "--diff-filter=U"
277
- ], { cwd });
278
- if (result.code !== 0) return [];
279
- if (result.stdout.trim() === "") return [];
280
- return result.stdout.trim().split("\n").filter((f) => f.trim().length > 0);
281
- }
282
- /**
283
- * Perform an actual merge using git merge --no-ff.
284
- *
285
- * Should only be called after detectConflicts() confirms there are no conflicts.
286
- * Creates a merge commit even if fast-forward is possible (--no-ff ensures history).
287
- *
288
- * @param branchName - The source branch to merge
289
- * @param cwd - Working directory (must be on the target branch)
290
- * @returns - true if merge succeeded, false otherwise
291
- */
292
- async function performMerge(branchName, cwd) {
293
- const result = await spawnGit([
294
- "merge",
295
- "--no-ff",
296
- branchName
297
- ], { cwd });
298
- if (result.code !== 0) return false;
299
- return true;
300
- }
301
- /**
302
- * Get a list of files changed in the most recent merge.
303
- *
304
- * Uses git diff --name-only HEAD~1..HEAD to find files in the merge commit.
305
- * Falls back to empty array if commit history is insufficient.
306
- *
307
- * @param cwd - Working directory of the repository
308
- * @returns - Array of file paths that were merged
309
- */
310
- async function getMergedFiles(cwd) {
311
- const result = await spawnGit([
312
- "diff",
313
- "--name-only",
314
- "HEAD~1..HEAD"
315
- ], { cwd });
316
- if (result.code !== 0) {
317
- const altResult = await spawnGit([
318
- "show",
319
- "--name-only",
320
- "--format=",
321
- "HEAD"
322
- ], { cwd });
323
- if (altResult.code !== 0) return [];
324
- return altResult.stdout.trim().split("\n").filter((f) => f.trim().length > 0);
325
- }
326
- if (result.stdout.trim() === "") return [];
327
- return result.stdout.trim().split("\n").filter((f) => f.trim().length > 0);
328
- }
329
-
330
- //#endregion
331
- //#region packages/core/dist/git/git-worktree-manager-impl.js
332
- const BRANCH_PREFIX = "substrate/task-";
333
- const DEFAULT_WORKTREE_BASE = ".substrate-worktrees";
334
- var GitWorktreeManagerImpl = class {
335
- _eventBus;
336
- _projectRoot;
337
- _baseDirectory;
338
- _db;
339
- _logger;
340
- /** Bound listener references for cleanup in shutdown() */
341
- _onTaskReady;
342
- _onTaskComplete;
343
- _onTaskFailed;
344
- constructor(eventBus, projectRoot, baseDirectory = DEFAULT_WORKTREE_BASE, db = null, logger$19) {
345
- this._eventBus = eventBus;
346
- this._projectRoot = projectRoot;
347
- this._baseDirectory = baseDirectory;
348
- this._db = db;
349
- this._logger = logger$19 ?? console;
350
- this._onTaskReady = ({ taskId }) => {
351
- this._handleTaskReady(taskId).catch((err) => {
352
- this._logger.error({
353
- taskId,
354
- err
355
- }, "Unhandled error in _handleTaskReady");
356
- });
357
- };
358
- this._onTaskComplete = ({ taskId }) => {
359
- this._handleTaskDone(taskId);
360
- };
361
- this._onTaskFailed = ({ taskId }) => {
362
- this._handleTaskDone(taskId);
363
- };
364
- }
365
- async initialize() {
366
- this._logger.info({ projectRoot: this._projectRoot }, "GitWorktreeManager.initialize()");
367
- await this.verifyGitVersion();
368
- const cleaned = await this.cleanupAllWorktrees();
369
- if (cleaned > 0) this._logger.info({ cleaned }, "Recovered orphaned worktrees on startup");
370
- this._eventBus.on("task:ready", this._onTaskReady);
371
- this._eventBus.on("task:complete", this._onTaskComplete);
372
- this._eventBus.on("task:failed", this._onTaskFailed);
373
- this._logger.info("GitWorktreeManager initialized");
374
- }
375
- async shutdown() {
376
- this._logger.info("GitWorktreeManager.shutdown()");
377
- this._eventBus.off("task:ready", this._onTaskReady);
378
- this._eventBus.off("task:complete", this._onTaskComplete);
379
- this._eventBus.off("task:failed", this._onTaskFailed);
380
- await this.cleanupAllWorktrees();
381
- this._logger.info("GitWorktreeManager shutdown complete");
382
- }
383
- async _handleTaskReady(taskId) {
384
- this._logger.debug({ taskId }, "task:ready — creating worktree");
385
- try {
386
- await this.createWorktree(taskId);
387
- } catch (err) {
388
- this._logger.error({
389
- taskId,
390
- err
391
- }, "Failed to create worktree for task");
392
- }
393
- }
394
- async _handleTaskDone(taskId) {
395
- this._logger.debug({ taskId }, "task done — cleaning up worktree");
396
- try {
397
- await this.cleanupWorktree(taskId);
398
- } catch (err) {
399
- this._logger.warn({
400
- taskId,
401
- err
402
- }, "Failed to cleanup worktree for task");
403
- }
404
- }
405
- async createWorktree(taskId, baseBranch = "main") {
406
- if (!taskId || taskId.trim().length === 0) throw new Error("createWorktree: taskId must be a non-empty string");
407
- const branchName = BRANCH_PREFIX + taskId;
408
- const worktreePath = this.getWorktreePath(taskId);
409
- this._logger.debug({
410
- taskId,
411
- branchName,
412
- worktreePath,
413
- baseBranch
414
- }, "createWorktree");
415
- await createWorktree(this._projectRoot, taskId, branchName, baseBranch);
416
- const createdAt = new Date();
417
- this._eventBus.emit("worktree:created", {
418
- taskId,
419
- branchName,
420
- worktreePath,
421
- createdAt
422
- });
423
- const info = {
424
- taskId,
425
- branchName,
426
- worktreePath,
427
- createdAt
428
- };
429
- this._logger.info({
430
- taskId,
431
- branchName,
432
- worktreePath
433
- }, "Worktree created");
434
- return info;
435
- }
436
- async cleanupWorktree(taskId) {
437
- const branchName = BRANCH_PREFIX + taskId;
438
- const worktreePath = this.getWorktreePath(taskId);
439
- this._logger.debug({
440
- taskId,
441
- branchName,
442
- worktreePath
443
- }, "cleanupWorktree");
444
- let worktreeExists = false;
445
- try {
446
- await access$1(worktreePath);
447
- worktreeExists = true;
448
- } catch {
449
- this._logger.debug({
450
- taskId,
451
- worktreePath
452
- }, "cleanupWorktree: worktree does not exist, skipping removal");
453
- }
454
- if (worktreeExists) try {
455
- await removeWorktree(worktreePath, this._projectRoot);
456
- } catch (err) {
457
- this._logger.warn({
458
- taskId,
459
- worktreePath,
460
- err
461
- }, "removeWorktree failed during cleanup");
462
- }
463
- try {
464
- await removeBranch(branchName, this._projectRoot);
465
- } catch (err) {
466
- this._logger.warn({
467
- taskId,
468
- branchName,
469
- err
470
- }, "removeBranch failed during cleanup");
471
- }
472
- this._eventBus.emit("worktree:removed", {
473
- taskId,
474
- branchName
475
- });
476
- this._logger.info({
477
- taskId,
478
- branchName
479
- }, "Worktree cleaned up");
480
- }
481
- async cleanupAllWorktrees() {
482
- this._logger.debug({ projectRoot: this._projectRoot }, "cleanupAllWorktrees");
483
- const orphanedPaths = await getOrphanedWorktrees(this._projectRoot, this._baseDirectory);
484
- let cleaned = 0;
485
- for (const worktreePath of orphanedPaths) {
486
- const taskId = path$2.basename(worktreePath);
487
- let worktreeRemoved = false;
488
- try {
489
- await removeWorktree(worktreePath, this._projectRoot);
490
- worktreeRemoved = true;
491
- this._logger.debug({
492
- taskId,
493
- worktreePath
494
- }, "cleanupAllWorktrees: removed orphaned worktree");
495
- } catch (err) {
496
- this._logger.warn({
497
- taskId,
498
- worktreePath,
499
- err
500
- }, "cleanupAllWorktrees: failed to remove worktree");
501
- }
502
- const branchName = BRANCH_PREFIX + taskId;
503
- try {
504
- const branchRemoved = await removeBranch(branchName, this._projectRoot);
505
- if (branchRemoved) this._logger.debug({
506
- taskId,
507
- branchName
508
- }, "cleanupAllWorktrees: removed orphaned branch");
509
- } catch (err) {
510
- this._logger.warn({
511
- taskId,
512
- branchName,
513
- err
514
- }, "cleanupAllWorktrees: failed to remove branch");
515
- }
516
- if (worktreeRemoved) cleaned++;
517
- }
518
- if (cleaned > 0) this._logger.info({ cleaned }, "cleanupAllWorktrees: recovered orphaned worktrees");
519
- return cleaned;
520
- }
521
- async detectConflicts(taskId, targetBranch = "main") {
522
- if (!taskId || taskId.trim().length === 0) throw new Error("detectConflicts: taskId must be a non-empty string");
523
- const branchName = BRANCH_PREFIX + taskId;
524
- const worktreePath = this.getWorktreePath(taskId);
525
- this._logger.debug({
526
- taskId,
527
- branchName,
528
- targetBranch
529
- }, "detectConflicts");
530
- try {
531
- await access$1(worktreePath);
532
- } catch {
533
- throw new Error(`detectConflicts: Worktree for task "${taskId}" not found at "${worktreePath}". The worktree may have already been cleaned up.`);
534
- }
535
- const mergeClean = await simulateMerge(branchName, this._projectRoot);
536
- let conflictingFiles = [];
537
- try {
538
- if (!mergeClean) conflictingFiles = await getConflictingFiles(this._projectRoot);
539
- } finally {
540
- await abortMerge(this._projectRoot);
541
- }
542
- const report = {
543
- hasConflicts: !mergeClean || conflictingFiles.length > 0,
544
- conflictingFiles,
545
- taskId,
546
- targetBranch
547
- };
548
- if (report.hasConflicts) this._eventBus.emit("worktree:conflict", {
549
- taskId,
550
- branch: branchName,
551
- conflictingFiles: report.conflictingFiles
552
- });
553
- this._logger.info({
554
- taskId,
555
- hasConflicts: report.hasConflicts,
556
- conflictCount: conflictingFiles.length
557
- }, "Conflict detection complete");
558
- return report;
559
- }
560
- async mergeWorktree(taskId, targetBranch = "main") {
561
- if (!taskId || taskId.trim().length === 0) throw new Error("mergeWorktree: taskId must be a non-empty string");
562
- const branchName = BRANCH_PREFIX + taskId;
563
- this._logger.debug({
564
- taskId,
565
- branchName,
566
- targetBranch
567
- }, "mergeWorktree");
568
- const conflictReport = await this.detectConflicts(taskId, targetBranch);
569
- if (conflictReport.hasConflicts) {
570
- this._logger.info({
571
- taskId,
572
- conflictCount: conflictReport.conflictingFiles.length
573
- }, "Merge skipped due to conflicts");
574
- return {
575
- success: false,
576
- mergedFiles: [],
577
- conflicts: conflictReport
578
- };
579
- }
580
- const mergeSuccess = await performMerge(branchName, this._projectRoot);
581
- if (!mergeSuccess) throw new Error(`mergeWorktree: git merge --no-ff failed for task "${taskId}" branch "${branchName}"`);
582
- const mergedFiles = await getMergedFiles(this._projectRoot);
583
- this._eventBus.emit("worktree:merged", {
584
- taskId,
585
- branch: branchName,
586
- mergedFiles
587
- });
588
- const result = {
589
- success: true,
590
- mergedFiles
591
- };
592
- this._logger.info({
593
- taskId,
594
- branchName,
595
- mergedFileCount: mergedFiles.length
596
- }, "Worktree merged successfully");
597
- return result;
598
- }
599
- async listWorktrees() {
600
- this._logger.debug({
601
- projectRoot: this._projectRoot,
602
- baseDirectory: this._baseDirectory
603
- }, "listWorktrees");
604
- const worktreePaths = await getOrphanedWorktrees(this._projectRoot, this._baseDirectory);
605
- const results = [];
606
- for (const worktreePath of worktreePaths) {
607
- const taskId = path$2.basename(worktreePath);
608
- const branchName = BRANCH_PREFIX + taskId;
609
- let createdAt;
610
- try {
611
- const { stat: stat$2 } = await import("node:fs/promises");
612
- const stats = await stat$2(worktreePath);
613
- createdAt = stats.birthtime ?? stats.ctime;
614
- } catch {
615
- createdAt = new Date();
616
- }
617
- results.push({
618
- taskId,
619
- branchName,
620
- worktreePath,
621
- createdAt
622
- });
623
- }
624
- this._logger.debug({ count: results.length }, "listWorktrees: found worktrees");
625
- return results;
626
- }
627
- getWorktreePath(taskId) {
628
- return path$2.join(this._projectRoot, this._baseDirectory, taskId);
629
- }
630
- async verifyGitVersion() {
631
- try {
632
- await verifyGitVersion();
633
- } catch (err) {
634
- throw new Error(`GitWorktreeManager: git version check failed: ${String(err)}`);
635
- }
636
- }
637
- };
638
- function createGitWorktreeManager(options) {
639
- return new GitWorktreeManagerImpl(options.eventBus, options.projectRoot, options.baseDirectory, options.db ?? null, options.logger);
640
- }
641
-
642
- //#endregion
643
42
  //#region packages/core/dist/monitor/recommendation-engine.js
644
43
  /**
645
44
  * RecommendationEngine — generates routing recommendations from performance aggregates.
@@ -2533,9 +1932,9 @@ async function promptSubscriptionRouting(providerName, nonInteractive) {
2533
1932
  });
2534
1933
  });
2535
1934
  }
2536
- async function directoryExists(path$4) {
1935
+ async function directoryExists(path$2) {
2537
1936
  try {
2538
- await access(path$4);
1937
+ await access(path$2);
2539
1938
  return true;
2540
1939
  } catch {
2541
1940
  return false;
@@ -4487,10 +3886,10 @@ var PathBase = class {
4487
3886
  /**
4488
3887
  * Get the Path object referenced by the string path, resolved from this Path
4489
3888
  */
4490
- resolve(path$4) {
4491
- if (!path$4) return this;
4492
- const rootPath = this.getRootString(path$4);
4493
- const dir = path$4.substring(rootPath.length);
3889
+ resolve(path$2) {
3890
+ if (!path$2) return this;
3891
+ const rootPath = this.getRootString(path$2);
3892
+ const dir = path$2.substring(rootPath.length);
4494
3893
  const dirParts = dir.split(this.splitSep);
4495
3894
  const result = rootPath ? this.getRoot(rootPath).#resolveParts(dirParts) : this.#resolveParts(dirParts);
4496
3895
  return result;
@@ -5145,8 +4544,8 @@ var PathWin32 = class PathWin32 extends PathBase {
5145
4544
  /**
5146
4545
  * @internal
5147
4546
  */
5148
- getRootString(path$4) {
5149
- return win32.parse(path$4).root;
4547
+ getRootString(path$2) {
4548
+ return win32.parse(path$2).root;
5150
4549
  }
5151
4550
  /**
5152
4551
  * @internal
@@ -5191,8 +4590,8 @@ var PathPosix = class PathPosix extends PathBase {
5191
4590
  /**
5192
4591
  * @internal
5193
4592
  */
5194
- getRootString(path$4) {
5195
- return path$4.startsWith("/") ? "/" : "";
4593
+ getRootString(path$2) {
4594
+ return path$2.startsWith("/") ? "/" : "";
5196
4595
  }
5197
4596
  /**
5198
4597
  * @internal
@@ -5285,9 +4684,9 @@ var PathScurryBase = class {
5285
4684
  /**
5286
4685
  * Get the depth of a provided path, string, or the cwd
5287
4686
  */
5288
- depth(path$4 = this.cwd) {
5289
- if (typeof path$4 === "string") path$4 = this.cwd.resolve(path$4);
5290
- return path$4.depth();
4687
+ depth(path$2 = this.cwd) {
4688
+ if (typeof path$2 === "string") path$2 = this.cwd.resolve(path$2);
4689
+ return path$2.depth();
5291
4690
  }
5292
4691
  /**
5293
4692
  * Return the cache of child entries. Exposed so subclasses can create
@@ -5668,9 +5067,9 @@ var PathScurryBase = class {
5668
5067
  process$1();
5669
5068
  return results;
5670
5069
  }
5671
- chdir(path$4 = this.cwd) {
5070
+ chdir(path$2 = this.cwd) {
5672
5071
  const oldCwd = this.cwd;
5673
- this.cwd = typeof path$4 === "string" ? this.cwd.resolve(path$4) : path$4;
5072
+ this.cwd = typeof path$2 === "string" ? this.cwd.resolve(path$2) : path$2;
5674
5073
  this.cwd[setAsCwd](oldCwd);
5675
5074
  }
5676
5075
  };
@@ -6054,8 +5453,8 @@ var MatchRecord = class {
6054
5453
  this.store.set(target, current === void 0 ? n : n & current);
6055
5454
  }
6056
5455
  entries() {
6057
- return [...this.store.entries()].map(([path$4, n]) => [
6058
- path$4,
5456
+ return [...this.store.entries()].map(([path$2, n]) => [
5457
+ path$2,
6059
5458
  !!(n & 2),
6060
5459
  !!(n & 1)
6061
5460
  ]);
@@ -6231,9 +5630,9 @@ var GlobUtil = class {
6231
5630
  signal;
6232
5631
  maxDepth;
6233
5632
  includeChildMatches;
6234
- constructor(patterns, path$4, opts) {
5633
+ constructor(patterns, path$2, opts) {
6235
5634
  this.patterns = patterns;
6236
- this.path = path$4;
5635
+ this.path = path$2;
6237
5636
  this.opts = opts;
6238
5637
  this.#sep = !opts.posix && opts.platform === "win32" ? "\\" : "/";
6239
5638
  this.includeChildMatches = opts.includeChildMatches !== false;
@@ -6254,11 +5653,11 @@ var GlobUtil = class {
6254
5653
  });
6255
5654
  }
6256
5655
  }
6257
- #ignored(path$4) {
6258
- return this.seen.has(path$4) || !!this.#ignore?.ignored?.(path$4);
5656
+ #ignored(path$2) {
5657
+ return this.seen.has(path$2) || !!this.#ignore?.ignored?.(path$2);
6259
5658
  }
6260
- #childrenIgnored(path$4) {
6261
- return !!this.#ignore?.childrenIgnored?.(path$4);
5659
+ #childrenIgnored(path$2) {
5660
+ return !!this.#ignore?.childrenIgnored?.(path$2);
6262
5661
  }
6263
5662
  pause() {
6264
5663
  this.paused = true;
@@ -6440,8 +5839,8 @@ var GlobUtil = class {
6440
5839
  };
6441
5840
  var GlobWalker = class extends GlobUtil {
6442
5841
  matches = new Set();
6443
- constructor(patterns, path$4, opts) {
6444
- super(patterns, path$4, opts);
5842
+ constructor(patterns, path$2, opts) {
5843
+ super(patterns, path$2, opts);
6445
5844
  }
6446
5845
  matchEmit(e) {
6447
5846
  this.matches.add(e);
@@ -6468,8 +5867,8 @@ var GlobWalker = class extends GlobUtil {
6468
5867
  };
6469
5868
  var GlobStream = class extends GlobUtil {
6470
5869
  results;
6471
- constructor(patterns, path$4, opts) {
6472
- super(patterns, path$4, opts);
5870
+ constructor(patterns, path$2, opts) {
5871
+ super(patterns, path$2, opts);
6473
5872
  this.results = new Minipass({
6474
5873
  signal: this.signal,
6475
5874
  objectMode: true
@@ -7491,7 +6890,7 @@ async function runStatusAction(options) {
7491
6890
  logger$15.debug({ err }, "Work graph query failed, continuing without work graph data");
7492
6891
  }
7493
6892
  if (run === void 0) {
7494
- const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-CUPkzJ8b.js");
6893
+ const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-D_2Tesme.js");
7495
6894
  const substrateDirPath = join(projectRoot, ".substrate");
7496
6895
  const processInfo = inspectProcessTree$1({
7497
6896
  projectRoot,
@@ -8456,7 +7855,7 @@ function defaultSupervisorDeps() {
8456
7855
  if (cached === null) {
8457
7856
  const { AdapterRegistry: AR } = await import(
8458
7857
  /* @vite-ignore */
8459
- "../adapter-registry-B42bBpfj.js"
7858
+ "../adapter-registry-BgfwxcSY.js"
8460
7859
  );
8461
7860
  cached = new AR();
8462
7861
  await cached.discoverAndRegister();
@@ -9037,7 +8436,7 @@ async function runSupervisorAction(options, deps = {}) {
9037
8436
  await initSchema(expAdapter);
9038
8437
  const { runRunAction: runPipeline } = await import(
9039
8438
  /* @vite-ignore */
9040
- "../run-E6tr8jf3.js"
8439
+ "../run-L26TdXRR.js"
9041
8440
  );
9042
8441
  const runStoryFn = async (opts) => {
9043
8442
  const exitCode = await runPipeline({
@@ -13246,9 +12645,9 @@ function detectWorkingTreeChanges(targetFiles, projectRoot) {
13246
12645
  const modifiedPaths = [];
13247
12646
  const lines = result.stdout.split("\n").filter((l) => l.trim().length > 0);
13248
12647
  for (const line of lines) {
13249
- const path$4 = line.length > 3 ? line.slice(3).trim() : line.trim();
13250
- for (const tf of targetFiles) if (path$4 === tf || path$4.endsWith(`/${tf}`) || tf.endsWith(`/${path$4}`) || path$4.endsWith(tf) || tf.endsWith(path$4)) {
13251
- modifiedPaths.push(path$4);
12648
+ const path$2 = line.length > 3 ? line.slice(3).trim() : line.trim();
12649
+ for (const tf of targetFiles) if (path$2 === tf || path$2.endsWith(`/${tf}`) || tf.endsWith(`/${path$2}`) || path$2.endsWith(tf) || tf.endsWith(path$2)) {
12650
+ modifiedPaths.push(path$2);
13252
12651
  break;
13253
12652
  }
13254
12653
  }