@adhdev/daemon-core 0.9.80 → 0.9.81
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/git/git-status.d.ts +4 -0
- package/dist/git/git-types.d.ts +18 -0
- package/dist/index.js +262 -192
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +262 -192
- package/dist/index.mjs.map +1 -1
- package/dist/repo-mesh-types.d.ts +15 -0
- package/package.json +1 -1
- package/src/commands/router.ts +17 -1
- package/src/git/git-status.ts +63 -1
- package/src/git/git-types.ts +19 -0
- package/src/repo-mesh-types.ts +15 -0
package/dist/index.mjs
CHANGED
|
@@ -44,6 +44,211 @@ var init_repo_mesh_types = __esm({
|
|
|
44
44
|
}
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
+
// src/git/git-executor.ts
|
|
48
|
+
var git_executor_exports = {};
|
|
49
|
+
__export(git_executor_exports, {
|
|
50
|
+
GitCommandError: () => GitCommandError,
|
|
51
|
+
isPathInside: () => isPathInside,
|
|
52
|
+
normalizeGitOutput: () => normalizeGitOutput,
|
|
53
|
+
resolveGitRepository: () => resolveGitRepository,
|
|
54
|
+
runGit: () => runGit
|
|
55
|
+
});
|
|
56
|
+
import { execFile } from "child_process";
|
|
57
|
+
import { constants } from "fs";
|
|
58
|
+
import { access, realpath, stat } from "fs/promises";
|
|
59
|
+
import * as path from "path";
|
|
60
|
+
import { promisify } from "util";
|
|
61
|
+
async function resolveGitRepository(workspace, options = {}) {
|
|
62
|
+
const normalizedWorkspace = await validateWorkspace(workspace);
|
|
63
|
+
const result = await execGitRaw(normalizedWorkspace, ["rev-parse", "--show-toplevel"], options, {
|
|
64
|
+
mapNotGitRepo: true
|
|
65
|
+
});
|
|
66
|
+
const repoRoot = path.resolve(result.stdout.trim());
|
|
67
|
+
if (!repoRoot) {
|
|
68
|
+
throw new GitCommandError("not_git_repo", "Git did not return a repository root", {
|
|
69
|
+
stdout: result.stdout,
|
|
70
|
+
stderr: result.stderr,
|
|
71
|
+
argv: ["rev-parse", "--show-toplevel"],
|
|
72
|
+
cwd: normalizedWorkspace
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
workspace: normalizedWorkspace,
|
|
77
|
+
repoRoot,
|
|
78
|
+
isGitRepo: true
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
async function runGit(repoOrWorkspace, argv, options = {}) {
|
|
82
|
+
validateGitArgv(argv);
|
|
83
|
+
const repo = typeof repoOrWorkspace === "string" ? await resolveGitRepository(repoOrWorkspace, options) : repoOrWorkspace;
|
|
84
|
+
if (!repo.repoRoot || !repo.isGitRepo) {
|
|
85
|
+
throw new GitCommandError("not_git_repo", "Workspace is not a Git repository", {
|
|
86
|
+
argv,
|
|
87
|
+
cwd: repo.workspace
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
const cwd = options.cwd ? await validateWorkspace(options.cwd) : await validateWorkspace(repo.workspace);
|
|
91
|
+
const canonicalRepoRoot = await realpath(repo.repoRoot);
|
|
92
|
+
const canonicalCwd = await realpath(cwd);
|
|
93
|
+
if (!isPathInside(canonicalRepoRoot, canonicalCwd)) {
|
|
94
|
+
throw new GitCommandError("path_outside_repo", "Git cwd is outside the repository root", {
|
|
95
|
+
argv,
|
|
96
|
+
cwd
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
return execGitRaw(cwd, argv, options);
|
|
100
|
+
}
|
|
101
|
+
function normalizeGitOutput(value) {
|
|
102
|
+
if (typeof value === "string") return value.replace(/\r\n/g, "\n");
|
|
103
|
+
if (Buffer.isBuffer(value)) return value.toString("utf8").replace(/\r\n/g, "\n");
|
|
104
|
+
if (value == null) return "";
|
|
105
|
+
return String(value).replace(/\r\n/g, "\n");
|
|
106
|
+
}
|
|
107
|
+
function isPathInside(parent, child) {
|
|
108
|
+
const relative3 = path.relative(path.resolve(parent), path.resolve(child));
|
|
109
|
+
return relative3 === "" || !relative3.startsWith("..") && !path.isAbsolute(relative3);
|
|
110
|
+
}
|
|
111
|
+
async function validateWorkspace(workspace) {
|
|
112
|
+
if (typeof workspace !== "string" || workspace.length === 0 || workspace.includes("\0")) {
|
|
113
|
+
throw new GitCommandError("invalid_args", "Workspace must be a non-empty path");
|
|
114
|
+
}
|
|
115
|
+
if (!path.isAbsolute(workspace)) {
|
|
116
|
+
throw new GitCommandError("invalid_args", "Workspace must be an absolute path", { cwd: workspace });
|
|
117
|
+
}
|
|
118
|
+
const normalizedWorkspace = path.resolve(workspace);
|
|
119
|
+
try {
|
|
120
|
+
const info = await stat(normalizedWorkspace);
|
|
121
|
+
if (!info.isDirectory()) {
|
|
122
|
+
throw new GitCommandError("invalid_args", "Workspace must be an existing directory", {
|
|
123
|
+
cwd: normalizedWorkspace
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
await access(normalizedWorkspace, constants.R_OK);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
if (error instanceof GitCommandError) throw error;
|
|
129
|
+
throw new GitCommandError("invalid_args", "Workspace must be an existing directory", {
|
|
130
|
+
cwd: normalizedWorkspace,
|
|
131
|
+
cause: error
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return normalizedWorkspace;
|
|
135
|
+
}
|
|
136
|
+
function validateGitArgv(argv) {
|
|
137
|
+
if (!Array.isArray(argv) || argv.length === 0) {
|
|
138
|
+
throw new GitCommandError("invalid_args", "Git argv must be a non-empty string array", { argv });
|
|
139
|
+
}
|
|
140
|
+
for (const arg of argv) {
|
|
141
|
+
if (typeof arg !== "string" || arg.length === 0 || arg.includes("\0")) {
|
|
142
|
+
throw new GitCommandError("invalid_args", "Git argv contains an invalid argument", { argv });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (argv.includes("-C") || argv.some((arg) => arg.startsWith("--git-dir") || arg.startsWith("--work-tree"))) {
|
|
146
|
+
throw new GitCommandError("invalid_args", "Git argv contains unsafe repository override arguments", {
|
|
147
|
+
argv
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
async function execGitRaw(cwd, argv, options, behavior = {}) {
|
|
152
|
+
validateGitArgv(argv);
|
|
153
|
+
try {
|
|
154
|
+
const result = await execFileAsync("git", [...argv], {
|
|
155
|
+
cwd,
|
|
156
|
+
encoding: "utf8",
|
|
157
|
+
timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
158
|
+
maxBuffer: options.maxBuffer ?? DEFAULT_MAX_BUFFER,
|
|
159
|
+
windowsHide: true
|
|
160
|
+
});
|
|
161
|
+
return {
|
|
162
|
+
stdout: normalizeGitOutput(result.stdout),
|
|
163
|
+
stderr: normalizeGitOutput(result.stderr)
|
|
164
|
+
};
|
|
165
|
+
} catch (error) {
|
|
166
|
+
throw mapExecError(error, cwd, argv, behavior);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
function mapExecError(error, cwd, argv, behavior) {
|
|
170
|
+
const execError = error;
|
|
171
|
+
const stdout = normalizeGitOutput(execError.stdout);
|
|
172
|
+
const stderr = normalizeGitOutput(execError.stderr);
|
|
173
|
+
const code = execError.code;
|
|
174
|
+
const signal = execError.signal;
|
|
175
|
+
const message = [stderr.trim(), execError.message].filter(Boolean).join("\n");
|
|
176
|
+
if (code === "ENOENT") {
|
|
177
|
+
return new GitCommandError("git_not_installed", "Git executable was not found", {
|
|
178
|
+
stdout,
|
|
179
|
+
stderr,
|
|
180
|
+
exitCode: code,
|
|
181
|
+
signal,
|
|
182
|
+
argv,
|
|
183
|
+
cwd,
|
|
184
|
+
cause: error
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
if (execError.killed || /timed out/i.test(execError.message)) {
|
|
188
|
+
return new GitCommandError("timeout", "Git command timed out", {
|
|
189
|
+
stdout,
|
|
190
|
+
stderr,
|
|
191
|
+
exitCode: code,
|
|
192
|
+
signal,
|
|
193
|
+
argv,
|
|
194
|
+
cwd,
|
|
195
|
+
cause: error
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
if (behavior.mapNotGitRepo && /not a git repository/i.test(stderr + "\n" + execError.message)) {
|
|
199
|
+
return new GitCommandError("not_git_repo", "Workspace is not a Git repository", {
|
|
200
|
+
stdout,
|
|
201
|
+
stderr,
|
|
202
|
+
exitCode: code,
|
|
203
|
+
signal,
|
|
204
|
+
argv,
|
|
205
|
+
cwd,
|
|
206
|
+
cause: error
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
return new GitCommandError("git_command_failed", message || "Git command failed", {
|
|
210
|
+
stdout,
|
|
211
|
+
stderr,
|
|
212
|
+
exitCode: code,
|
|
213
|
+
signal,
|
|
214
|
+
argv,
|
|
215
|
+
cwd,
|
|
216
|
+
cause: error
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
var execFileAsync, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_BUFFER, GitCommandError;
|
|
220
|
+
var init_git_executor = __esm({
|
|
221
|
+
"src/git/git-executor.ts"() {
|
|
222
|
+
"use strict";
|
|
223
|
+
execFileAsync = promisify(execFile);
|
|
224
|
+
DEFAULT_TIMEOUT_MS = 5e3;
|
|
225
|
+
DEFAULT_MAX_BUFFER = 1024 * 1024;
|
|
226
|
+
GitCommandError = class extends Error {
|
|
227
|
+
reason;
|
|
228
|
+
stdout;
|
|
229
|
+
stderr;
|
|
230
|
+
exitCode;
|
|
231
|
+
signal;
|
|
232
|
+
argv;
|
|
233
|
+
cwd;
|
|
234
|
+
constructor(reason, message, details = {}) {
|
|
235
|
+
super(message);
|
|
236
|
+
if (details.cause !== void 0) {
|
|
237
|
+
this.cause = details.cause;
|
|
238
|
+
}
|
|
239
|
+
this.name = "GitCommandError";
|
|
240
|
+
this.reason = reason;
|
|
241
|
+
this.stdout = normalizeGitOutput(details.stdout);
|
|
242
|
+
this.stderr = normalizeGitOutput(details.stderr);
|
|
243
|
+
this.exitCode = details.exitCode;
|
|
244
|
+
this.signal = details.signal;
|
|
245
|
+
this.argv = details.argv ? [...details.argv] : void 0;
|
|
246
|
+
this.cwd = details.cwd;
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
|
|
47
252
|
// src/git/git-worktree.ts
|
|
48
253
|
var git_worktree_exports = {};
|
|
49
254
|
__export(git_worktree_exports, {
|
|
@@ -5461,206 +5666,24 @@ ${lastSnapshot}`;
|
|
|
5461
5666
|
// src/index.ts
|
|
5462
5667
|
init_repo_mesh_types();
|
|
5463
5668
|
|
|
5464
|
-
// src/git/
|
|
5465
|
-
|
|
5466
|
-
import { constants } from "fs";
|
|
5467
|
-
import { access, realpath, stat } from "fs/promises";
|
|
5468
|
-
import * as path from "path";
|
|
5469
|
-
import { promisify } from "util";
|
|
5470
|
-
var execFileAsync = promisify(execFile);
|
|
5471
|
-
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
5472
|
-
var DEFAULT_MAX_BUFFER = 1024 * 1024;
|
|
5473
|
-
var GitCommandError = class extends Error {
|
|
5474
|
-
reason;
|
|
5475
|
-
stdout;
|
|
5476
|
-
stderr;
|
|
5477
|
-
exitCode;
|
|
5478
|
-
signal;
|
|
5479
|
-
argv;
|
|
5480
|
-
cwd;
|
|
5481
|
-
constructor(reason, message, details = {}) {
|
|
5482
|
-
super(message);
|
|
5483
|
-
if (details.cause !== void 0) {
|
|
5484
|
-
this.cause = details.cause;
|
|
5485
|
-
}
|
|
5486
|
-
this.name = "GitCommandError";
|
|
5487
|
-
this.reason = reason;
|
|
5488
|
-
this.stdout = normalizeGitOutput(details.stdout);
|
|
5489
|
-
this.stderr = normalizeGitOutput(details.stderr);
|
|
5490
|
-
this.exitCode = details.exitCode;
|
|
5491
|
-
this.signal = details.signal;
|
|
5492
|
-
this.argv = details.argv ? [...details.argv] : void 0;
|
|
5493
|
-
this.cwd = details.cwd;
|
|
5494
|
-
}
|
|
5495
|
-
};
|
|
5496
|
-
async function resolveGitRepository(workspace, options = {}) {
|
|
5497
|
-
const normalizedWorkspace = await validateWorkspace(workspace);
|
|
5498
|
-
const result = await execGitRaw(normalizedWorkspace, ["rev-parse", "--show-toplevel"], options, {
|
|
5499
|
-
mapNotGitRepo: true
|
|
5500
|
-
});
|
|
5501
|
-
const repoRoot = path.resolve(result.stdout.trim());
|
|
5502
|
-
if (!repoRoot) {
|
|
5503
|
-
throw new GitCommandError("not_git_repo", "Git did not return a repository root", {
|
|
5504
|
-
stdout: result.stdout,
|
|
5505
|
-
stderr: result.stderr,
|
|
5506
|
-
argv: ["rev-parse", "--show-toplevel"],
|
|
5507
|
-
cwd: normalizedWorkspace
|
|
5508
|
-
});
|
|
5509
|
-
}
|
|
5510
|
-
return {
|
|
5511
|
-
workspace: normalizedWorkspace,
|
|
5512
|
-
repoRoot,
|
|
5513
|
-
isGitRepo: true
|
|
5514
|
-
};
|
|
5515
|
-
}
|
|
5516
|
-
async function runGit(repoOrWorkspace, argv, options = {}) {
|
|
5517
|
-
validateGitArgv(argv);
|
|
5518
|
-
const repo = typeof repoOrWorkspace === "string" ? await resolveGitRepository(repoOrWorkspace, options) : repoOrWorkspace;
|
|
5519
|
-
if (!repo.repoRoot || !repo.isGitRepo) {
|
|
5520
|
-
throw new GitCommandError("not_git_repo", "Workspace is not a Git repository", {
|
|
5521
|
-
argv,
|
|
5522
|
-
cwd: repo.workspace
|
|
5523
|
-
});
|
|
5524
|
-
}
|
|
5525
|
-
const cwd = options.cwd ? await validateWorkspace(options.cwd) : await validateWorkspace(repo.workspace);
|
|
5526
|
-
const canonicalRepoRoot = await realpath(repo.repoRoot);
|
|
5527
|
-
const canonicalCwd = await realpath(cwd);
|
|
5528
|
-
if (!isPathInside(canonicalRepoRoot, canonicalCwd)) {
|
|
5529
|
-
throw new GitCommandError("path_outside_repo", "Git cwd is outside the repository root", {
|
|
5530
|
-
argv,
|
|
5531
|
-
cwd
|
|
5532
|
-
});
|
|
5533
|
-
}
|
|
5534
|
-
return execGitRaw(cwd, argv, options);
|
|
5535
|
-
}
|
|
5536
|
-
function normalizeGitOutput(value) {
|
|
5537
|
-
if (typeof value === "string") return value.replace(/\r\n/g, "\n");
|
|
5538
|
-
if (Buffer.isBuffer(value)) return value.toString("utf8").replace(/\r\n/g, "\n");
|
|
5539
|
-
if (value == null) return "";
|
|
5540
|
-
return String(value).replace(/\r\n/g, "\n");
|
|
5541
|
-
}
|
|
5542
|
-
function isPathInside(parent, child) {
|
|
5543
|
-
const relative3 = path.relative(path.resolve(parent), path.resolve(child));
|
|
5544
|
-
return relative3 === "" || !relative3.startsWith("..") && !path.isAbsolute(relative3);
|
|
5545
|
-
}
|
|
5546
|
-
async function validateWorkspace(workspace) {
|
|
5547
|
-
if (typeof workspace !== "string" || workspace.length === 0 || workspace.includes("\0")) {
|
|
5548
|
-
throw new GitCommandError("invalid_args", "Workspace must be a non-empty path");
|
|
5549
|
-
}
|
|
5550
|
-
if (!path.isAbsolute(workspace)) {
|
|
5551
|
-
throw new GitCommandError("invalid_args", "Workspace must be an absolute path", { cwd: workspace });
|
|
5552
|
-
}
|
|
5553
|
-
const normalizedWorkspace = path.resolve(workspace);
|
|
5554
|
-
try {
|
|
5555
|
-
const info = await stat(normalizedWorkspace);
|
|
5556
|
-
if (!info.isDirectory()) {
|
|
5557
|
-
throw new GitCommandError("invalid_args", "Workspace must be an existing directory", {
|
|
5558
|
-
cwd: normalizedWorkspace
|
|
5559
|
-
});
|
|
5560
|
-
}
|
|
5561
|
-
await access(normalizedWorkspace, constants.R_OK);
|
|
5562
|
-
} catch (error) {
|
|
5563
|
-
if (error instanceof GitCommandError) throw error;
|
|
5564
|
-
throw new GitCommandError("invalid_args", "Workspace must be an existing directory", {
|
|
5565
|
-
cwd: normalizedWorkspace,
|
|
5566
|
-
cause: error
|
|
5567
|
-
});
|
|
5568
|
-
}
|
|
5569
|
-
return normalizedWorkspace;
|
|
5570
|
-
}
|
|
5571
|
-
function validateGitArgv(argv) {
|
|
5572
|
-
if (!Array.isArray(argv) || argv.length === 0) {
|
|
5573
|
-
throw new GitCommandError("invalid_args", "Git argv must be a non-empty string array", { argv });
|
|
5574
|
-
}
|
|
5575
|
-
for (const arg of argv) {
|
|
5576
|
-
if (typeof arg !== "string" || arg.length === 0 || arg.includes("\0")) {
|
|
5577
|
-
throw new GitCommandError("invalid_args", "Git argv contains an invalid argument", { argv });
|
|
5578
|
-
}
|
|
5579
|
-
}
|
|
5580
|
-
if (argv.includes("-C") || argv.some((arg) => arg.startsWith("--git-dir") || arg.startsWith("--work-tree"))) {
|
|
5581
|
-
throw new GitCommandError("invalid_args", "Git argv contains unsafe repository override arguments", {
|
|
5582
|
-
argv
|
|
5583
|
-
});
|
|
5584
|
-
}
|
|
5585
|
-
}
|
|
5586
|
-
async function execGitRaw(cwd, argv, options, behavior = {}) {
|
|
5587
|
-
validateGitArgv(argv);
|
|
5588
|
-
try {
|
|
5589
|
-
const result = await execFileAsync("git", [...argv], {
|
|
5590
|
-
cwd,
|
|
5591
|
-
encoding: "utf8",
|
|
5592
|
-
timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
5593
|
-
maxBuffer: options.maxBuffer ?? DEFAULT_MAX_BUFFER,
|
|
5594
|
-
windowsHide: true
|
|
5595
|
-
});
|
|
5596
|
-
return {
|
|
5597
|
-
stdout: normalizeGitOutput(result.stdout),
|
|
5598
|
-
stderr: normalizeGitOutput(result.stderr)
|
|
5599
|
-
};
|
|
5600
|
-
} catch (error) {
|
|
5601
|
-
throw mapExecError(error, cwd, argv, behavior);
|
|
5602
|
-
}
|
|
5603
|
-
}
|
|
5604
|
-
function mapExecError(error, cwd, argv, behavior) {
|
|
5605
|
-
const execError = error;
|
|
5606
|
-
const stdout = normalizeGitOutput(execError.stdout);
|
|
5607
|
-
const stderr = normalizeGitOutput(execError.stderr);
|
|
5608
|
-
const code = execError.code;
|
|
5609
|
-
const signal = execError.signal;
|
|
5610
|
-
const message = [stderr.trim(), execError.message].filter(Boolean).join("\n");
|
|
5611
|
-
if (code === "ENOENT") {
|
|
5612
|
-
return new GitCommandError("git_not_installed", "Git executable was not found", {
|
|
5613
|
-
stdout,
|
|
5614
|
-
stderr,
|
|
5615
|
-
exitCode: code,
|
|
5616
|
-
signal,
|
|
5617
|
-
argv,
|
|
5618
|
-
cwd,
|
|
5619
|
-
cause: error
|
|
5620
|
-
});
|
|
5621
|
-
}
|
|
5622
|
-
if (execError.killed || /timed out/i.test(execError.message)) {
|
|
5623
|
-
return new GitCommandError("timeout", "Git command timed out", {
|
|
5624
|
-
stdout,
|
|
5625
|
-
stderr,
|
|
5626
|
-
exitCode: code,
|
|
5627
|
-
signal,
|
|
5628
|
-
argv,
|
|
5629
|
-
cwd,
|
|
5630
|
-
cause: error
|
|
5631
|
-
});
|
|
5632
|
-
}
|
|
5633
|
-
if (behavior.mapNotGitRepo && /not a git repository/i.test(stderr + "\n" + execError.message)) {
|
|
5634
|
-
return new GitCommandError("not_git_repo", "Workspace is not a Git repository", {
|
|
5635
|
-
stdout,
|
|
5636
|
-
stderr,
|
|
5637
|
-
exitCode: code,
|
|
5638
|
-
signal,
|
|
5639
|
-
argv,
|
|
5640
|
-
cwd,
|
|
5641
|
-
cause: error
|
|
5642
|
-
});
|
|
5643
|
-
}
|
|
5644
|
-
return new GitCommandError("git_command_failed", message || "Git command failed", {
|
|
5645
|
-
stdout,
|
|
5646
|
-
stderr,
|
|
5647
|
-
exitCode: code,
|
|
5648
|
-
signal,
|
|
5649
|
-
argv,
|
|
5650
|
-
cwd,
|
|
5651
|
-
cause: error
|
|
5652
|
-
});
|
|
5653
|
-
}
|
|
5669
|
+
// src/git/index.ts
|
|
5670
|
+
init_git_executor();
|
|
5654
5671
|
|
|
5655
5672
|
// src/git/git-status.ts
|
|
5673
|
+
init_git_executor();
|
|
5656
5674
|
async function getGitRepoStatus(workspace, options = {}) {
|
|
5657
5675
|
const lastCheckedAt = Date.now();
|
|
5676
|
+
const includeSubmodules = options.includeSubmodules !== false;
|
|
5658
5677
|
try {
|
|
5659
5678
|
const repo = await resolveGitRepository(workspace, options);
|
|
5660
5679
|
const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
|
|
5661
5680
|
const parsed = parsePorcelainV2Status(statusOutput.stdout);
|
|
5662
5681
|
const head = await readHead(repo, options);
|
|
5663
5682
|
const stashCount = await readStashCount(repo, options);
|
|
5683
|
+
let submodules;
|
|
5684
|
+
if (includeSubmodules) {
|
|
5685
|
+
submodules = await getSubmoduleStatuses(repo, options);
|
|
5686
|
+
}
|
|
5664
5687
|
return {
|
|
5665
5688
|
workspace: repo.workspace,
|
|
5666
5689
|
repoRoot: repo.repoRoot,
|
|
@@ -5679,7 +5702,8 @@ async function getGitRepoStatus(workspace, options = {}) {
|
|
|
5679
5702
|
hasConflicts: parsed.conflictFiles.length > 0,
|
|
5680
5703
|
conflictFiles: parsed.conflictFiles,
|
|
5681
5704
|
stashCount,
|
|
5682
|
-
lastCheckedAt
|
|
5705
|
+
lastCheckedAt,
|
|
5706
|
+
submodules
|
|
5683
5707
|
};
|
|
5684
5708
|
} catch (error) {
|
|
5685
5709
|
if (error instanceof GitCommandError) {
|
|
@@ -5801,8 +5825,40 @@ function emptyStatus(workspace, lastCheckedAt, error) {
|
|
|
5801
5825
|
reason: error.reason
|
|
5802
5826
|
};
|
|
5803
5827
|
}
|
|
5828
|
+
async function getSubmoduleStatuses(repo, options) {
|
|
5829
|
+
if (!repo.repoRoot) return [];
|
|
5830
|
+
try {
|
|
5831
|
+
const result = await runGit(repo, ["submodule", "status", "--recursive"], options);
|
|
5832
|
+
return parseSubmoduleStatusOutput(result.stdout, repo.repoRoot, options.submoduleIgnorePaths);
|
|
5833
|
+
} catch {
|
|
5834
|
+
return [];
|
|
5835
|
+
}
|
|
5836
|
+
}
|
|
5837
|
+
function parseSubmoduleStatusOutput(output, repoRoot, ignorePaths) {
|
|
5838
|
+
const submodules = [];
|
|
5839
|
+
const ignoreSet = new Set(ignorePaths || []);
|
|
5840
|
+
for (const line of output.split("\n")) {
|
|
5841
|
+
if (!line.trim()) continue;
|
|
5842
|
+
const match = line.match(/^([\-+\s])([0-9a-f]{40})\s+(\S+)(?:\s+\(([^)]+)\))?/);
|
|
5843
|
+
if (!match) continue;
|
|
5844
|
+
const prefix = match[1];
|
|
5845
|
+
const commit = match[2];
|
|
5846
|
+
const path28 = match[3];
|
|
5847
|
+
if (ignoreSet.has(path28)) continue;
|
|
5848
|
+
submodules.push({
|
|
5849
|
+
path: path28,
|
|
5850
|
+
commit,
|
|
5851
|
+
repoPath: repoRoot + "/" + path28,
|
|
5852
|
+
dirty: prefix === "+",
|
|
5853
|
+
outOfSync: prefix === "-",
|
|
5854
|
+
lastCheckedAt: Date.now()
|
|
5855
|
+
});
|
|
5856
|
+
}
|
|
5857
|
+
return submodules;
|
|
5858
|
+
}
|
|
5804
5859
|
|
|
5805
5860
|
// src/git/git-diff.ts
|
|
5861
|
+
init_git_executor();
|
|
5806
5862
|
import { readFile, realpath as realpath2 } from "fs/promises";
|
|
5807
5863
|
import * as path2 from "path";
|
|
5808
5864
|
var DEFAULT_MAX_FILES = 200;
|
|
@@ -6333,6 +6389,7 @@ function createGitWorkspaceMonitor(options = {}) {
|
|
|
6333
6389
|
|
|
6334
6390
|
// src/git/git-commands.ts
|
|
6335
6391
|
import * as path3 from "path";
|
|
6392
|
+
init_git_executor();
|
|
6336
6393
|
var GIT_COMMAND_NAMES = /* @__PURE__ */ new Set([
|
|
6337
6394
|
"git_status",
|
|
6338
6395
|
"git_diff_summary",
|
|
@@ -25376,12 +25433,25 @@ var DaemonCommandRouter = class {
|
|
|
25376
25433
|
});
|
|
25377
25434
|
if (!node) return { success: false, error: "Failed to register worktree node" };
|
|
25378
25435
|
}
|
|
25436
|
+
const initSubmodules = sourceNode.policy?.initSubmodulesOnClone !== false;
|
|
25437
|
+
if (initSubmodules) {
|
|
25438
|
+
try {
|
|
25439
|
+
const { runGit: runGit2 } = await Promise.resolve().then(() => (init_git_executor(), git_executor_exports));
|
|
25440
|
+
await runGit2(
|
|
25441
|
+
{ workspace: result.worktreePath, repoRoot: result.worktreePath, isGitRepo: true },
|
|
25442
|
+
["submodule", "update", "--init", "--recursive"],
|
|
25443
|
+
{ timeoutMs: 12e4 }
|
|
25444
|
+
);
|
|
25445
|
+
} catch (subErr) {
|
|
25446
|
+
console.warn("[mesh] Submodule init failed for worktree:", subErr.message);
|
|
25447
|
+
}
|
|
25448
|
+
}
|
|
25379
25449
|
try {
|
|
25380
25450
|
const { appendLedgerEntry: appendLedgerEntry2 } = await Promise.resolve().then(() => (init_mesh_ledger(), mesh_ledger_exports));
|
|
25381
25451
|
appendLedgerEntry2(meshId, {
|
|
25382
25452
|
kind: "node_cloned",
|
|
25383
25453
|
nodeId: node.id,
|
|
25384
|
-
payload: { sourceNodeId, branch: result.branch, worktreePath: result.worktreePath }
|
|
25454
|
+
payload: { sourceNodeId, branch: result.branch, worktreePath: result.worktreePath, submodulesInitialized: initSubmodules }
|
|
25385
25455
|
});
|
|
25386
25456
|
} catch {
|
|
25387
25457
|
}
|