@adhdev/daemon-core 0.9.82-rc.302 → 0.9.82-rc.304
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-executor.d.ts +11 -0
- package/dist/git/git-status.d.ts +2 -0
- package/dist/index.js +88 -61
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +88 -61
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/commands/router.ts +23 -3
- package/src/git/git-executor.ts +12 -0
- package/src/git/git-status.ts +71 -13
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import type { GitFailureReason, GitRepoIdentity } from './git-types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Timeout for status-collection git commands (status/log/submodule/stash/fetch).
|
|
4
|
+
* The default 5s is fine for porcelain status, but on Windows the `git` subprocess
|
|
5
|
+
* spawn itself is pathologically slow (measured: `submodule status` ~3.5s, cold
|
|
6
|
+
* `log -1` ~4.2s) and overlaps with refreshUpstream fetches — a single command
|
|
7
|
+
* routinely exceeds 5s, which previously collapsed the whole status to all-null and
|
|
8
|
+
* dropped the node from the mesh graph. Give the collection path a much larger
|
|
9
|
+
* budget so a slow-but-healthy repo never reads as "not a git repo". Windows gets a
|
|
10
|
+
* larger budget than POSIX because the spawn cost is OS-specific, not repo-specific.
|
|
11
|
+
*/
|
|
12
|
+
export declare const GIT_STATUS_TIMEOUT_MS: number;
|
|
2
13
|
export interface GitExecutorOptions {
|
|
3
14
|
timeoutMs?: number;
|
|
4
15
|
maxBuffer?: number;
|
package/dist/git/git-status.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { GitRepoStatus } from './git-types.js';
|
|
2
2
|
import { type DaemonBuildInfo } from '../build-info.js';
|
|
3
|
+
/** Test seam: clear the last-known-good status cache between cases. */
|
|
4
|
+
export declare function __resetGitStatusCacheForTests(): void;
|
|
3
5
|
export interface GitStatusOptions {
|
|
4
6
|
timeoutMs?: number;
|
|
5
7
|
/** When true, include submodule status in the result. Defaults to true. */
|
package/dist/index.js
CHANGED
|
@@ -82,6 +82,7 @@ var init_repo_mesh_types = __esm({
|
|
|
82
82
|
// src/git/git-executor.ts
|
|
83
83
|
var git_executor_exports = {};
|
|
84
84
|
__export(git_executor_exports, {
|
|
85
|
+
GIT_STATUS_TIMEOUT_MS: () => GIT_STATUS_TIMEOUT_MS,
|
|
85
86
|
GitCommandError: () => GitCommandError,
|
|
86
87
|
isPathInside: () => isPathInside,
|
|
87
88
|
normalizeGitOutput: () => normalizeGitOutput,
|
|
@@ -246,7 +247,7 @@ function mapExecError(error, cwd, argv, behavior) {
|
|
|
246
247
|
cause: error
|
|
247
248
|
});
|
|
248
249
|
}
|
|
249
|
-
var import_node_child_process, import_node_fs, import_promises, path, import_node_util, execFileAsync, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_BUFFER, GitCommandError;
|
|
250
|
+
var import_node_child_process, import_node_fs, import_promises, path, import_node_util, execFileAsync, DEFAULT_TIMEOUT_MS, DEFAULT_MAX_BUFFER, GIT_STATUS_TIMEOUT_MS, GitCommandError;
|
|
250
251
|
var init_git_executor = __esm({
|
|
251
252
|
"src/git/git-executor.ts"() {
|
|
252
253
|
"use strict";
|
|
@@ -258,6 +259,7 @@ var init_git_executor = __esm({
|
|
|
258
259
|
execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
259
260
|
DEFAULT_TIMEOUT_MS = 5e3;
|
|
260
261
|
DEFAULT_MAX_BUFFER = 1024 * 1024;
|
|
262
|
+
GIT_STATUS_TIMEOUT_MS = process.platform === "win32" ? 3e4 : 2e4;
|
|
261
263
|
GitCommandError = class extends Error {
|
|
262
264
|
reason;
|
|
263
265
|
stdout;
|
|
@@ -293,10 +295,10 @@ function readInjected(value) {
|
|
|
293
295
|
}
|
|
294
296
|
function getDaemonBuildInfo() {
|
|
295
297
|
if (cached) return cached;
|
|
296
|
-
const commit = readInjected(true ? "
|
|
297
|
-
const commitShort = readInjected(true ? "
|
|
298
|
-
const version = readInjected(true ? "0.9.82-rc.
|
|
299
|
-
const builtAt = readInjected(true ? "2026-06-
|
|
298
|
+
const commit = readInjected(true ? "1d8f7eabac25d169c6344185357519db0c0ffd13" : void 0) ?? "unknown";
|
|
299
|
+
const commitShort = readInjected(true ? "1d8f7eab" : void 0) ?? (commit !== "unknown" ? commit.slice(0, 7) : "unknown");
|
|
300
|
+
const version = readInjected(true ? "0.9.82-rc.304" : void 0) ?? readInjected(typeof process !== "undefined" ? process.env?.ADHDEV_PKG_VERSION : void 0) ?? "unknown";
|
|
301
|
+
const builtAt = readInjected(true ? "2026-06-17T05:27:03.554Z" : void 0);
|
|
300
302
|
cached = builtAt ? { commit, commitShort, version, builtAt } : { commit, commitShort, version };
|
|
301
303
|
return cached;
|
|
302
304
|
}
|
|
@@ -308,65 +310,80 @@ var init_build_info = __esm({
|
|
|
308
310
|
});
|
|
309
311
|
|
|
310
312
|
// src/git/git-status.ts
|
|
313
|
+
function isTransientGitFailure(error) {
|
|
314
|
+
return error.reason === "timeout" || error.reason === "git_command_failed";
|
|
315
|
+
}
|
|
311
316
|
async function getGitRepoStatus(workspace, options = {}) {
|
|
312
317
|
const lastCheckedAt = Date.now();
|
|
313
318
|
const includeSubmodules = options.includeSubmodules !== false;
|
|
319
|
+
const effectiveOptions = options.timeoutMs === void 0 ? { ...options, timeoutMs: GIT_STATUS_TIMEOUT_MS } : options;
|
|
314
320
|
try {
|
|
315
|
-
const repo = await resolveGitRepository(workspace,
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
|
|
320
|
-
if (upstreamProbe.upstreamStatus === "fresh") {
|
|
321
|
-
parsed = await readPorcelainStatus(repo, options);
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
const head = await readHead(repo, options);
|
|
325
|
-
const stashCount = await readStashCount(repo, options);
|
|
326
|
-
let submodules;
|
|
327
|
-
if (includeSubmodules) {
|
|
328
|
-
submodules = await getSubmoduleStatuses(repo, options);
|
|
329
|
-
}
|
|
330
|
-
const submoduleDirty = (submodules || []).some((submodule) => submodule.dirty || submodule.outOfSync || !!submodule.error);
|
|
331
|
-
const dirty = parsed.staged + parsed.modified + parsed.untracked + parsed.deleted + parsed.renamed > 0 || parsed.conflictFiles.length > 0 || stashCount > 0 || submoduleDirty;
|
|
332
|
-
const daemonBuildBehind = await detectDaemonBuildBehind(repo, submodules, options);
|
|
333
|
-
return {
|
|
334
|
-
workspace: repo.workspace,
|
|
335
|
-
repoRoot: repo.repoRoot,
|
|
336
|
-
isGitRepo: true,
|
|
337
|
-
branch: parsed.branch,
|
|
338
|
-
headCommit: head.commit,
|
|
339
|
-
headMessage: head.message,
|
|
340
|
-
upstream: parsed.upstream,
|
|
341
|
-
upstreamStatus: parsed.upstream ? upstreamProbe.upstreamStatus : "no_upstream",
|
|
342
|
-
upstreamFetchedAt: upstreamProbe.upstreamFetchedAt,
|
|
343
|
-
upstreamFetchError: upstreamProbe.upstreamFetchError,
|
|
344
|
-
ahead: parsed.ahead,
|
|
345
|
-
behind: parsed.behind,
|
|
346
|
-
staged: parsed.staged,
|
|
347
|
-
modified: parsed.modified,
|
|
348
|
-
untracked: parsed.untracked,
|
|
349
|
-
deleted: parsed.deleted,
|
|
350
|
-
renamed: parsed.renamed,
|
|
351
|
-
dirty,
|
|
352
|
-
hasConflicts: parsed.conflictFiles.length > 0,
|
|
353
|
-
conflictFiles: parsed.conflictFiles,
|
|
354
|
-
stashCount,
|
|
355
|
-
lastCheckedAt,
|
|
356
|
-
submodules,
|
|
357
|
-
...daemonBuildBehind ? { daemonBuildBehind } : {}
|
|
358
|
-
};
|
|
321
|
+
const repo = await resolveGitRepository(workspace, effectiveOptions);
|
|
322
|
+
const status = await collectGitRepoStatus(repo, includeSubmodules, lastCheckedAt, effectiveOptions);
|
|
323
|
+
lastKnownGoodStatus.set(workspace, status);
|
|
324
|
+
return status;
|
|
359
325
|
} catch (error) {
|
|
360
|
-
|
|
361
|
-
|
|
326
|
+
const gitError = error instanceof GitCommandError ? error : new GitCommandError("git_command_failed", "Failed to read Git status", { cause: error });
|
|
327
|
+
if (isTransientGitFailure(gitError)) {
|
|
328
|
+
const cached2 = lastKnownGoodStatus.get(workspace);
|
|
329
|
+
if (cached2) {
|
|
330
|
+
return {
|
|
331
|
+
...cached2,
|
|
332
|
+
lastCheckedAt,
|
|
333
|
+
upstreamStatus: "unavailable",
|
|
334
|
+
error: gitError.stderr || gitError.message,
|
|
335
|
+
reason: gitError.reason
|
|
336
|
+
};
|
|
337
|
+
}
|
|
362
338
|
}
|
|
363
|
-
return emptyStatus(
|
|
364
|
-
workspace,
|
|
365
|
-
lastCheckedAt,
|
|
366
|
-
new GitCommandError("git_command_failed", "Failed to read Git status", { cause: error })
|
|
367
|
-
);
|
|
339
|
+
return emptyStatus(workspace, lastCheckedAt, gitError);
|
|
368
340
|
}
|
|
369
341
|
}
|
|
342
|
+
async function collectGitRepoStatus(repo, includeSubmodules, lastCheckedAt, options) {
|
|
343
|
+
let parsed = await readPorcelainStatus(repo, options);
|
|
344
|
+
let upstreamProbe = getInitialUpstreamProbe(parsed);
|
|
345
|
+
if (options.refreshUpstream) {
|
|
346
|
+
upstreamProbe = await refreshTrackedUpstream(repo, parsed, options);
|
|
347
|
+
if (upstreamProbe.upstreamStatus === "fresh") {
|
|
348
|
+
parsed = await readPorcelainStatus(repo, options);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
const head = await readHead(repo, options);
|
|
352
|
+
const stashCount = await readStashCount(repo, options);
|
|
353
|
+
let submodules;
|
|
354
|
+
if (includeSubmodules) {
|
|
355
|
+
submodules = await getSubmoduleStatuses(repo, options);
|
|
356
|
+
}
|
|
357
|
+
const submoduleDirty = (submodules || []).some((submodule) => submodule.dirty || submodule.outOfSync || !!submodule.error);
|
|
358
|
+
const dirty = parsed.staged + parsed.modified + parsed.untracked + parsed.deleted + parsed.renamed > 0 || parsed.conflictFiles.length > 0 || stashCount > 0 || submoduleDirty;
|
|
359
|
+
const daemonBuildBehind = await detectDaemonBuildBehind(repo, submodules, options);
|
|
360
|
+
return {
|
|
361
|
+
workspace: repo.workspace,
|
|
362
|
+
repoRoot: repo.repoRoot,
|
|
363
|
+
isGitRepo: true,
|
|
364
|
+
branch: parsed.branch,
|
|
365
|
+
headCommit: head.commit,
|
|
366
|
+
headMessage: head.message,
|
|
367
|
+
upstream: parsed.upstream,
|
|
368
|
+
upstreamStatus: parsed.upstream ? upstreamProbe.upstreamStatus : "no_upstream",
|
|
369
|
+
upstreamFetchedAt: upstreamProbe.upstreamFetchedAt,
|
|
370
|
+
upstreamFetchError: upstreamProbe.upstreamFetchError,
|
|
371
|
+
ahead: parsed.ahead,
|
|
372
|
+
behind: parsed.behind,
|
|
373
|
+
staged: parsed.staged,
|
|
374
|
+
modified: parsed.modified,
|
|
375
|
+
untracked: parsed.untracked,
|
|
376
|
+
deleted: parsed.deleted,
|
|
377
|
+
renamed: parsed.renamed,
|
|
378
|
+
dirty,
|
|
379
|
+
hasConflicts: parsed.conflictFiles.length > 0,
|
|
380
|
+
conflictFiles: parsed.conflictFiles,
|
|
381
|
+
stashCount,
|
|
382
|
+
lastCheckedAt,
|
|
383
|
+
submodules,
|
|
384
|
+
...daemonBuildBehind ? { daemonBuildBehind } : {}
|
|
385
|
+
};
|
|
386
|
+
}
|
|
370
387
|
function isNonRuntimeRootFile(file) {
|
|
371
388
|
const base = file.slice(file.lastIndexOf("/") + 1);
|
|
372
389
|
if (/^\.(?:verify|marker|converge|ff-verify|patch-equiv|live-verify)\b/i.test(base)) return true;
|
|
@@ -607,7 +624,7 @@ function emptyStatus(workspace, lastCheckedAt, error) {
|
|
|
607
624
|
async function getSubmoduleStatuses(repo, options) {
|
|
608
625
|
if (!repo.repoRoot) return [];
|
|
609
626
|
try {
|
|
610
|
-
const result = await runGit(repo, ["submodule", "status"
|
|
627
|
+
const result = await runGit(repo, ["submodule", "status"], options);
|
|
611
628
|
const submodules = parseSubmoduleStatusOutput(result.stdout, repo.repoRoot, options.submoduleIgnorePaths);
|
|
612
629
|
await Promise.all(submodules.map((submodule) => enrichSubmoduleWorktreeStatus(repo, submodule, options)));
|
|
613
630
|
return submodules;
|
|
@@ -651,12 +668,13 @@ function parseSubmoduleStatusOutput(output, repoRoot, ignorePaths) {
|
|
|
651
668
|
}
|
|
652
669
|
return submodules;
|
|
653
670
|
}
|
|
654
|
-
var DAEMON_RUNTIME_PACKAGES, WEB_ONLY_PACKAGES;
|
|
671
|
+
var lastKnownGoodStatus, DAEMON_RUNTIME_PACKAGES, WEB_ONLY_PACKAGES;
|
|
655
672
|
var init_git_status = __esm({
|
|
656
673
|
"src/git/git-status.ts"() {
|
|
657
674
|
"use strict";
|
|
658
675
|
init_git_executor();
|
|
659
676
|
init_build_info();
|
|
677
|
+
lastKnownGoodStatus = /* @__PURE__ */ new Map();
|
|
660
678
|
DAEMON_RUNTIME_PACKAGES = /* @__PURE__ */ new Set([
|
|
661
679
|
"daemon-core",
|
|
662
680
|
"daemon-standalone",
|
|
@@ -42307,6 +42325,15 @@ function finalizeMeshNodeStatus(args) {
|
|
|
42307
42325
|
const connectionState = readStringValue(readObjectRecord(status.connection).state);
|
|
42308
42326
|
status.launchReady = !!daemonId && (readStringValue(status.machineStatus) === "online" || connectionState === "connected" || isSelfNode);
|
|
42309
42327
|
}
|
|
42328
|
+
function readMeshTimeoutEnvMs(name, defaultMs) {
|
|
42329
|
+
const raw = process.env[name]?.trim();
|
|
42330
|
+
if (!raw) return defaultMs;
|
|
42331
|
+
const parsed = Number.parseInt(raw, 10);
|
|
42332
|
+
if (Number.isFinite(parsed) && parsed >= 1e3 && parsed <= 12e4) return parsed;
|
|
42333
|
+
return defaultMs;
|
|
42334
|
+
}
|
|
42335
|
+
var MESH_DIRECT_PROBE_TIMEOUT_MS = readMeshTimeoutEnvMs("MESH_DIRECT_PROBE_TIMEOUT_MS", 25e3);
|
|
42336
|
+
var MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS = readMeshTimeoutEnvMs("MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS", 25e3);
|
|
42310
42337
|
async function probeRemoteMeshGitStatus(args) {
|
|
42311
42338
|
if (!args.dispatchMeshCommand) return null;
|
|
42312
42339
|
const remoteResult = await Promise.race([
|
|
@@ -42370,7 +42397,7 @@ async function hydrateInlineMeshDirectTruth(args) {
|
|
|
42370
42397
|
dispatchMeshCommand: args.dispatchMeshCommand,
|
|
42371
42398
|
daemonId,
|
|
42372
42399
|
workspace,
|
|
42373
|
-
timeoutMs:
|
|
42400
|
+
timeoutMs: MESH_DIRECT_PROBE_TIMEOUT_MS
|
|
42374
42401
|
});
|
|
42375
42402
|
if (remoteGit) {
|
|
42376
42403
|
recordInlineMeshDirectGitTruth(node, remoteGit, "selected_coordinator_mesh_p2p_git");
|
|
@@ -48340,7 +48367,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
48340
48367
|
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
48341
48368
|
daemonId,
|
|
48342
48369
|
workspace,
|
|
48343
|
-
timeoutMs:
|
|
48370
|
+
timeoutMs: MESH_DIRECT_PROBE_TIMEOUT_MS
|
|
48344
48371
|
});
|
|
48345
48372
|
if (remoteGit) {
|
|
48346
48373
|
status.git = remoteGit;
|
|
@@ -48364,7 +48391,7 @@ ${ptyResult.output.slice(-2e3)}`);
|
|
|
48364
48391
|
dispatchMeshCommand: this.deps.dispatchMeshCommand,
|
|
48365
48392
|
daemonId,
|
|
48366
48393
|
workspace,
|
|
48367
|
-
timeoutMs:
|
|
48394
|
+
timeoutMs: MESH_DIRECT_PROBE_RETRY_TIMEOUT_MS
|
|
48368
48395
|
});
|
|
48369
48396
|
if (remoteGit) {
|
|
48370
48397
|
status.git = remoteGit;
|