substrate-ai 0.9.0 → 0.10.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/adapter-registry-DXLMTmfD.js +0 -0
- package/dist/adapter-registry-neBZrkr3.js +4 -0
- package/dist/cli/index.js +5594 -5951
- package/dist/decisions-C0pz9Clx.js +0 -0
- package/dist/{decisions-BDLp3tJB.js → decisions-DQZW0h9X.js} +2 -1
- package/dist/dist-eNB_v7Iy.js +10205 -0
- package/dist/errors-BvyMlvCX.js +74 -0
- package/dist/experimenter-Dos3NsCg.js +3 -0
- package/dist/health-BvYILeQQ.js +6 -0
- package/dist/{health-C-VRJruD.js → health-CiDi90gC.js} +57 -1850
- package/dist/{helpers-CpMs8VZX.js → helpers-DTp3VJ2-.js} +31 -121
- package/dist/index.d.ts +672 -253
- package/dist/index.js +5 -3
- package/dist/{logger-D2fS2ccL.js → logger-KeHncl-f.js} +2 -42
- package/dist/routing-CcBOCuC9.js +0 -0
- package/dist/{routing-CD8bIci_.js → routing-HaYsjEIS.js} +2 -2
- package/dist/{run-ClxNDHbr.js → run-CAUhTR7Y.js} +594 -4249
- package/dist/run-DPZOQOvB.js +9 -0
- package/dist/{upgrade-B1S61VXJ.js → upgrade-DFGrqjGI.js} +3 -3
- package/dist/{upgrade-BK0HrKA6.js → upgrade-DYdYuuJK.js} +3 -3
- package/dist/version-manager-impl-BmOWu8ml.js +0 -0
- package/dist/version-manager-impl-CKv6I1S0.js +4 -0
- package/package.json +2 -2
- package/dist/adapter-registry-D2zdMwVu.js +0 -840
- package/dist/adapter-registry-WAyFydN5.js +0 -4
- package/dist/config-migrator-CtGelIsG.js +0 -250
- package/dist/decisions-DhAA2HG2.js +0 -397
- package/dist/experimenter-D_N_7ZF3.js +0 -503
- package/dist/git-utils-DxPx6erV.js +0 -365
- package/dist/health-DMbNP9bw.js +0 -5
- package/dist/operational-BdcdmDqS.js +0 -374
- package/dist/routing-BVrxrM6v.js +0 -832
- package/dist/run-MAQ3Wuju.js +0 -10
- package/dist/version-manager-impl-BIxOe7gZ.js +0 -372
- package/dist/version-manager-impl-RrWs-CI6.js +0 -4
|
@@ -1,365 +0,0 @@
|
|
|
1
|
-
import { createLogger } from "./logger-D2fS2ccL.js";
|
|
2
|
-
import { spawn } from "node:child_process";
|
|
3
|
-
import * as path from "node:path";
|
|
4
|
-
import { access, readdir } from "node:fs/promises";
|
|
5
|
-
|
|
6
|
-
//#region src/modules/git-worktree/git-utils.ts
|
|
7
|
-
const logger = createLogger("git-utils");
|
|
8
|
-
const MIN_GIT_MAJOR = 2;
|
|
9
|
-
const MIN_GIT_MINOR = 20;
|
|
10
|
-
/**
|
|
11
|
-
* Spawn a git subprocess with the given args.
|
|
12
|
-
*
|
|
13
|
-
* @param args - Arguments to pass to git (e.g., ['worktree', 'add', ...])
|
|
14
|
-
* @param options - Optional spawn options (cwd, env)
|
|
15
|
-
* @returns - Object with stdout, stderr, and exit code
|
|
16
|
-
*/
|
|
17
|
-
function spawnGit(args, options) {
|
|
18
|
-
return new Promise((resolve$1) => {
|
|
19
|
-
logger.debug({
|
|
20
|
-
args,
|
|
21
|
-
cwd: options?.cwd
|
|
22
|
-
}, "spawnGit");
|
|
23
|
-
const proc = spawn("git", args, {
|
|
24
|
-
cwd: options?.cwd,
|
|
25
|
-
env: options?.env ?? process.env,
|
|
26
|
-
stdio: [
|
|
27
|
-
"ignore",
|
|
28
|
-
"pipe",
|
|
29
|
-
"pipe"
|
|
30
|
-
]
|
|
31
|
-
});
|
|
32
|
-
let stdout = "";
|
|
33
|
-
let stderr = "";
|
|
34
|
-
proc.stdout?.on("data", (chunk) => {
|
|
35
|
-
stdout += chunk.toString();
|
|
36
|
-
});
|
|
37
|
-
proc.stderr?.on("data", (chunk) => {
|
|
38
|
-
stderr += chunk.toString();
|
|
39
|
-
});
|
|
40
|
-
proc.on("close", (code) => {
|
|
41
|
-
resolve$1({
|
|
42
|
-
stdout: stdout.trim(),
|
|
43
|
-
stderr: stderr.trim(),
|
|
44
|
-
code: code ?? 1
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
proc.on("error", (err) => {
|
|
48
|
-
resolve$1({
|
|
49
|
-
stdout: "",
|
|
50
|
-
stderr: err.message,
|
|
51
|
-
code: 1
|
|
52
|
-
});
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Get the installed git version string.
|
|
58
|
-
*
|
|
59
|
-
* @returns Version string like "2.42.0"
|
|
60
|
-
* @throws Error if git is not installed or version cannot be parsed
|
|
61
|
-
*/
|
|
62
|
-
async function getGitVersion() {
|
|
63
|
-
const result = await spawnGit(["--version"]);
|
|
64
|
-
if (result.code !== 0) throw new Error(`git --version failed: ${result.stderr}`);
|
|
65
|
-
const match = /git version\s+(\d+\.\d+(?:\.\d+)?)/.exec(result.stdout);
|
|
66
|
-
if (match === null || match[1] === void 0) throw new Error(`Unable to parse git version from output: "${result.stdout}"`);
|
|
67
|
-
return match[1];
|
|
68
|
-
}
|
|
69
|
-
/**
|
|
70
|
-
* Parse a git version string into major/minor/patch components.
|
|
71
|
-
*
|
|
72
|
-
* @param versionString - Version string like "2.42.0" or "2.20"
|
|
73
|
-
* @returns - Parsed version components
|
|
74
|
-
*/
|
|
75
|
-
function parseGitVersion(versionString) {
|
|
76
|
-
const parts = versionString.split(".").map(Number);
|
|
77
|
-
return {
|
|
78
|
-
major: parts[0] ?? 0,
|
|
79
|
-
minor: parts[1] ?? 0,
|
|
80
|
-
patch: parts[2] ?? 0
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Check if the given git version string is >= 2.20.0.
|
|
85
|
-
*
|
|
86
|
-
* @param version - Version string like "2.42.0"
|
|
87
|
-
* @returns - true if version >= 2.20.0
|
|
88
|
-
*/
|
|
89
|
-
function isGitVersionSupported(version) {
|
|
90
|
-
const { major, minor } = parseGitVersion(version);
|
|
91
|
-
if (major > MIN_GIT_MAJOR) return true;
|
|
92
|
-
if (major === MIN_GIT_MAJOR && minor >= MIN_GIT_MINOR) return true;
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Verify that git is installed and version >= 2.20.
|
|
97
|
-
*
|
|
98
|
-
* @throws Error with clear message if git is not installed or too old
|
|
99
|
-
*/
|
|
100
|
-
async function verifyGitVersion() {
|
|
101
|
-
let version;
|
|
102
|
-
try {
|
|
103
|
-
version = await getGitVersion();
|
|
104
|
-
} catch (err) {
|
|
105
|
-
throw new Error(`git is not installed or could not be executed. Please install git 2.20 or newer. Details: ${String(err)}`);
|
|
106
|
-
}
|
|
107
|
-
if (!isGitVersionSupported(version)) {
|
|
108
|
-
const { major, minor, patch } = parseGitVersion(version);
|
|
109
|
-
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`);
|
|
110
|
-
}
|
|
111
|
-
logger.debug({ version }, "git version verified");
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Create a git worktree and its associated branch.
|
|
115
|
-
*
|
|
116
|
-
* Uses a single `git worktree add {worktreePath} -b {branchName} {baseBranch}`
|
|
117
|
-
* command to create the worktree with a new branch in one step.
|
|
118
|
-
*
|
|
119
|
-
* @param projectRoot - Absolute path to the git repository root
|
|
120
|
-
* @param taskId - Task identifier (used in path derivation)
|
|
121
|
-
* @param branchName - Branch name to create (e.g., "substrate/task-abc123")
|
|
122
|
-
* @param baseBranch - Branch to base the worktree on (e.g., "main")
|
|
123
|
-
* @returns - Object with the worktreePath
|
|
124
|
-
* @throws - Error if git command fails
|
|
125
|
-
*/
|
|
126
|
-
async function createWorktree(projectRoot, taskId, branchName, baseBranch) {
|
|
127
|
-
const worktreePath = path.join(projectRoot, ".substrate-worktrees", taskId);
|
|
128
|
-
logger.debug({
|
|
129
|
-
projectRoot,
|
|
130
|
-
taskId,
|
|
131
|
-
branchName,
|
|
132
|
-
baseBranch,
|
|
133
|
-
worktreePath
|
|
134
|
-
}, "createWorktree");
|
|
135
|
-
const addResult = await spawnGit([
|
|
136
|
-
"worktree",
|
|
137
|
-
"add",
|
|
138
|
-
worktreePath,
|
|
139
|
-
"-b",
|
|
140
|
-
branchName,
|
|
141
|
-
baseBranch
|
|
142
|
-
], { cwd: projectRoot });
|
|
143
|
-
if (addResult.code !== 0) throw new Error(`git worktree add failed for task "${taskId}": ${addResult.stderr || addResult.stdout}`);
|
|
144
|
-
logger.info({
|
|
145
|
-
taskId,
|
|
146
|
-
branchName,
|
|
147
|
-
worktreePath
|
|
148
|
-
}, "Worktree created");
|
|
149
|
-
return { worktreePath };
|
|
150
|
-
}
|
|
151
|
-
/**
|
|
152
|
-
* Remove a git worktree by path.
|
|
153
|
-
*
|
|
154
|
-
* Uses `git worktree remove --force` to handle unclean worktrees.
|
|
155
|
-
*
|
|
156
|
-
* @param worktreePath - Absolute path to the worktree directory
|
|
157
|
-
* @param projectRoot - Absolute path to the git repository root
|
|
158
|
-
* @throws - Error if git command fails
|
|
159
|
-
*/
|
|
160
|
-
async function removeWorktree(worktreePath, projectRoot) {
|
|
161
|
-
logger.debug({ worktreePath }, "removeWorktree");
|
|
162
|
-
const spawnOpts = {};
|
|
163
|
-
if (projectRoot !== void 0) spawnOpts.cwd = projectRoot;
|
|
164
|
-
const result = await spawnGit([
|
|
165
|
-
"worktree",
|
|
166
|
-
"remove",
|
|
167
|
-
"--force",
|
|
168
|
-
worktreePath
|
|
169
|
-
], spawnOpts);
|
|
170
|
-
if (result.code !== 0) throw new Error(`git worktree remove failed for "${worktreePath}": ${result.stderr || result.stdout}`);
|
|
171
|
-
logger.debug({ worktreePath }, "Worktree removed");
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Delete a git branch using `git branch -D`.
|
|
175
|
-
*
|
|
176
|
-
* @param branchName - Branch name to delete (e.g., "substrate/task-abc123")
|
|
177
|
-
* @param projectRoot - Absolute path to the git repository root
|
|
178
|
-
* @returns - true if branch was successfully deleted, false otherwise
|
|
179
|
-
*/
|
|
180
|
-
async function removeBranch(branchName, projectRoot) {
|
|
181
|
-
logger.debug({ branchName }, "removeBranch");
|
|
182
|
-
const spawnOpts = {};
|
|
183
|
-
if (projectRoot !== void 0) spawnOpts.cwd = projectRoot;
|
|
184
|
-
const result = await spawnGit([
|
|
185
|
-
"branch",
|
|
186
|
-
"-D",
|
|
187
|
-
branchName
|
|
188
|
-
], spawnOpts);
|
|
189
|
-
if (result.code !== 0) {
|
|
190
|
-
logger.warn({
|
|
191
|
-
branchName,
|
|
192
|
-
stderr: result.stderr
|
|
193
|
-
}, "git branch -D failed (may already be deleted)");
|
|
194
|
-
return false;
|
|
195
|
-
}
|
|
196
|
-
logger.debug({ branchName }, "Branch deleted");
|
|
197
|
-
return true;
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* Scan the worktrees base directory and return paths of all found worktree directories.
|
|
201
|
-
*
|
|
202
|
-
* @param projectRoot - Absolute path to the git repository root
|
|
203
|
-
* @param baseDirectory - Relative directory name for worktrees (default: '.substrate-worktrees')
|
|
204
|
-
* @returns - Array of absolute worktree directory paths
|
|
205
|
-
*/
|
|
206
|
-
async function getOrphanedWorktrees(projectRoot, baseDirectory = ".substrate-worktrees") {
|
|
207
|
-
const worktreesDir = path.join(projectRoot, baseDirectory);
|
|
208
|
-
try {
|
|
209
|
-
await access(worktreesDir);
|
|
210
|
-
} catch {
|
|
211
|
-
return [];
|
|
212
|
-
}
|
|
213
|
-
let entries;
|
|
214
|
-
try {
|
|
215
|
-
entries = await readdir(worktreesDir, { withFileTypes: true });
|
|
216
|
-
} catch (err) {
|
|
217
|
-
logger.warn({
|
|
218
|
-
worktreesDir,
|
|
219
|
-
err
|
|
220
|
-
}, "getOrphanedWorktrees: failed to read directory");
|
|
221
|
-
return [];
|
|
222
|
-
}
|
|
223
|
-
return entries.filter((entry) => entry.isDirectory()).map((entry) => path.join(worktreesDir, entry.name));
|
|
224
|
-
}
|
|
225
|
-
/**
|
|
226
|
-
* Simulate a merge using git merge --no-commit --no-ff without committing.
|
|
227
|
-
*
|
|
228
|
-
* This runs in the target branch's working directory (the project root or
|
|
229
|
-
* worktree path). The simulation must be aborted after checking conflicts
|
|
230
|
-
* via abortMerge().
|
|
231
|
-
*
|
|
232
|
-
* @param branchName - The source branch to simulate merging
|
|
233
|
-
* @param cwd - Working directory (must be on the target branch)
|
|
234
|
-
* @returns - true if merge would be clean, false if there are conflicts
|
|
235
|
-
*/
|
|
236
|
-
async function simulateMerge(branchName, cwd) {
|
|
237
|
-
logger.debug({
|
|
238
|
-
branchName,
|
|
239
|
-
cwd
|
|
240
|
-
}, "simulateMerge");
|
|
241
|
-
const result = await spawnGit([
|
|
242
|
-
"merge",
|
|
243
|
-
"--no-commit",
|
|
244
|
-
"--no-ff",
|
|
245
|
-
branchName
|
|
246
|
-
], { cwd });
|
|
247
|
-
if (result.code === 0) return true;
|
|
248
|
-
return false;
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Abort a merge in progress using git merge --abort.
|
|
252
|
-
*
|
|
253
|
-
* Should be called after simulateMerge() to clean up the merge state,
|
|
254
|
-
* regardless of whether conflicts were found.
|
|
255
|
-
*
|
|
256
|
-
* @param cwd - Working directory (same as used for simulateMerge)
|
|
257
|
-
*/
|
|
258
|
-
async function abortMerge(cwd) {
|
|
259
|
-
logger.debug({ cwd }, "abortMerge");
|
|
260
|
-
const result = await spawnGit(["merge", "--abort"], { cwd });
|
|
261
|
-
if (result.code !== 0) logger.warn({
|
|
262
|
-
cwd,
|
|
263
|
-
stderr: result.stderr
|
|
264
|
-
}, "abortMerge: git merge --abort returned non-zero (may have been nothing to abort)");
|
|
265
|
-
logger.debug({ cwd }, "Merge aborted");
|
|
266
|
-
}
|
|
267
|
-
/**
|
|
268
|
-
* Get a list of files with conflicts during a merge.
|
|
269
|
-
*
|
|
270
|
-
* Must be called while a merge is in progress (after simulateMerge() and
|
|
271
|
-
* before abortMerge()).
|
|
272
|
-
*
|
|
273
|
-
* @param cwd - Working directory of the repository
|
|
274
|
-
* @returns - Array of conflicting file paths
|
|
275
|
-
*/
|
|
276
|
-
async function getConflictingFiles(cwd) {
|
|
277
|
-
logger.debug({ cwd }, "getConflictingFiles");
|
|
278
|
-
const result = await spawnGit([
|
|
279
|
-
"diff",
|
|
280
|
-
"--name-only",
|
|
281
|
-
"--diff-filter=U"
|
|
282
|
-
], { cwd });
|
|
283
|
-
if (result.code !== 0) {
|
|
284
|
-
logger.warn({
|
|
285
|
-
cwd,
|
|
286
|
-
stderr: result.stderr
|
|
287
|
-
}, "getConflictingFiles: git diff returned non-zero");
|
|
288
|
-
return [];
|
|
289
|
-
}
|
|
290
|
-
if (result.stdout.trim() === "") return [];
|
|
291
|
-
return result.stdout.trim().split("\n").filter((f) => f.trim().length > 0);
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Perform an actual merge using git merge --no-ff.
|
|
295
|
-
*
|
|
296
|
-
* Should only be called after detectConflicts() confirms there are no conflicts.
|
|
297
|
-
* Creates a merge commit even if fast-forward is possible (--no-ff ensures history).
|
|
298
|
-
*
|
|
299
|
-
* @param branchName - The source branch to merge
|
|
300
|
-
* @param cwd - Working directory (must be on the target branch)
|
|
301
|
-
* @returns - true if merge succeeded, false otherwise
|
|
302
|
-
*/
|
|
303
|
-
async function performMerge(branchName, cwd) {
|
|
304
|
-
logger.debug({
|
|
305
|
-
branchName,
|
|
306
|
-
cwd
|
|
307
|
-
}, "performMerge");
|
|
308
|
-
const result = await spawnGit([
|
|
309
|
-
"merge",
|
|
310
|
-
"--no-ff",
|
|
311
|
-
branchName
|
|
312
|
-
], { cwd });
|
|
313
|
-
if (result.code !== 0) {
|
|
314
|
-
logger.warn({
|
|
315
|
-
branchName,
|
|
316
|
-
cwd,
|
|
317
|
-
stderr: result.stderr
|
|
318
|
-
}, "performMerge: git merge --no-ff failed");
|
|
319
|
-
return false;
|
|
320
|
-
}
|
|
321
|
-
logger.debug({
|
|
322
|
-
branchName,
|
|
323
|
-
cwd
|
|
324
|
-
}, "Merge completed");
|
|
325
|
-
return true;
|
|
326
|
-
}
|
|
327
|
-
/**
|
|
328
|
-
* Get a list of files changed in the most recent merge.
|
|
329
|
-
*
|
|
330
|
-
* Uses git diff --name-only HEAD~1..HEAD to find files in the merge commit.
|
|
331
|
-
* Falls back to empty array if commit history is insufficient.
|
|
332
|
-
*
|
|
333
|
-
* @param cwd - Working directory of the repository
|
|
334
|
-
* @returns - Array of file paths that were merged
|
|
335
|
-
*/
|
|
336
|
-
async function getMergedFiles(cwd) {
|
|
337
|
-
logger.debug({ cwd }, "getMergedFiles");
|
|
338
|
-
const result = await spawnGit([
|
|
339
|
-
"diff",
|
|
340
|
-
"--name-only",
|
|
341
|
-
"HEAD~1..HEAD"
|
|
342
|
-
], { cwd });
|
|
343
|
-
if (result.code !== 0) {
|
|
344
|
-
const altResult = await spawnGit([
|
|
345
|
-
"show",
|
|
346
|
-
"--name-only",
|
|
347
|
-
"--format=",
|
|
348
|
-
"HEAD"
|
|
349
|
-
], { cwd });
|
|
350
|
-
if (altResult.code !== 0) {
|
|
351
|
-
logger.warn({
|
|
352
|
-
cwd,
|
|
353
|
-
stderr: altResult.stderr
|
|
354
|
-
}, "getMergedFiles: failed to get merged file list");
|
|
355
|
-
return [];
|
|
356
|
-
}
|
|
357
|
-
return altResult.stdout.trim().split("\n").filter((f) => f.trim().length > 0);
|
|
358
|
-
}
|
|
359
|
-
if (result.stdout.trim() === "") return [];
|
|
360
|
-
return result.stdout.trim().split("\n").filter((f) => f.trim().length > 0);
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
//#endregion
|
|
364
|
-
export { abortMerge, createWorktree, getConflictingFiles, getMergedFiles, getOrphanedWorktrees, performMerge, removeBranch, removeWorktree, simulateMerge, spawnGit, verifyGitVersion };
|
|
365
|
-
//# sourceMappingURL=git-utils-DxPx6erV.js.map
|
package/dist/health-DMbNP9bw.js
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { DEFAULT_STALL_THRESHOLD_SECONDS, getAllDescendantPids, getAutoHealthData, inspectProcessTree, isOrchestratorProcessLine, registerHealthCommand, runHealthAction } from "./health-C-VRJruD.js";
|
|
2
|
-
import "./logger-D2fS2ccL.js";
|
|
3
|
-
import "./decisions-DhAA2HG2.js";
|
|
4
|
-
|
|
5
|
-
export { inspectProcessTree };
|