@schoolai/shipyard 3.32.0 → 3.33.0-rc.20260923.1
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/capability-detector-worker.js +8 -8
- package/dist/{chunk-PVN4AJAH.js → chunk-3PJULQHI.js} +2 -2
- package/dist/{chunk-NFVZCZPA.js → chunk-4WJOA7HF.js} +2 -2
- package/dist/{chunk-RBXWUYDC.js → chunk-DQQOVPVK.js} +2 -2
- package/dist/{chunk-ZDJEJI62.js → chunk-ELZLWLTO.js} +2 -2
- package/dist/{chunk-42SK2S4V.js → chunk-FYT3ETTP.js} +2 -2
- package/dist/{chunk-SGFCXJJJ.js → chunk-JYAI3JHY.js} +2 -2
- package/dist/{chunk-7IS6KGWY.js → chunk-M6XAVFHJ.js} +3 -3
- package/dist/{chunk-FARMJBC7.js → chunk-MV7VSD2T.js} +2 -2
- package/dist/{chunk-FARMJBC7.js.map → chunk-MV7VSD2T.js.map} +1 -1
- package/dist/{chunk-RR6V6SNM.js → chunk-VHPNDDB5.js} +100 -17
- package/dist/chunk-VHPNDDB5.js.map +1 -0
- package/dist/{chunk-5TF227G7.js → chunk-WKJAGQU7.js} +3 -3
- package/dist/{chunk-UIBOKFSG.js → chunk-XPOXRIHH.js} +9 -47
- package/dist/chunk-XPOXRIHH.js.map +1 -0
- package/dist/{chunk-MAA2DPW5.js → chunk-ZXYFMJAS.js} +3 -3
- package/dist/cursor-runner.js +3 -3
- package/dist/electron-utility.js +2 -2
- package/dist/{git-repo-M634UEX7.js → git-repo-K45YAY55.js} +3 -3
- package/dist/index.js +4 -4
- package/dist/{login-6YTDDUP4.js → login-SOAGMUHR.js} +3 -3
- package/dist/{mcp-servers-LTYMM2F2.js → mcp-servers-GHDSX3UE.js} +3 -3
- package/dist/{plan-backfill-52OBXJRO.js → plan-backfill-W4FLMVC6.js} +5 -5
- package/dist/{serve-JVTSDF4E.js → serve-SDRQ7JYB.js} +120 -83
- package/dist/{serve-JVTSDF4E.js.map → serve-SDRQ7JYB.js.map} +1 -1
- package/dist/{skills-BX2NZKPN.js → skills-RO2BW4XO.js} +3 -3
- package/dist/{start-TYBSF7PZ.js → start-DHYV7OQM.js} +6 -6
- package/package.json +2 -3
- package/dist/chunk-RR6V6SNM.js.map +0 -1
- package/dist/chunk-UIBOKFSG.js.map +0 -1
- /package/dist/{chunk-PVN4AJAH.js.map → chunk-3PJULQHI.js.map} +0 -0
- /package/dist/{chunk-NFVZCZPA.js.map → chunk-4WJOA7HF.js.map} +0 -0
- /package/dist/{chunk-RBXWUYDC.js.map → chunk-DQQOVPVK.js.map} +0 -0
- /package/dist/{chunk-ZDJEJI62.js.map → chunk-ELZLWLTO.js.map} +0 -0
- /package/dist/{chunk-42SK2S4V.js.map → chunk-FYT3ETTP.js.map} +0 -0
- /package/dist/{chunk-SGFCXJJJ.js.map → chunk-JYAI3JHY.js.map} +0 -0
- /package/dist/{chunk-7IS6KGWY.js.map → chunk-M6XAVFHJ.js.map} +0 -0
- /package/dist/{chunk-5TF227G7.js.map → chunk-WKJAGQU7.js.map} +0 -0
- /package/dist/{chunk-MAA2DPW5.js.map → chunk-ZXYFMJAS.js.map} +0 -0
- /package/dist/{git-repo-M634UEX7.js.map → git-repo-K45YAY55.js.map} +0 -0
- /package/dist/{login-6YTDDUP4.js.map → login-SOAGMUHR.js.map} +0 -0
- /package/dist/{mcp-servers-LTYMM2F2.js.map → mcp-servers-GHDSX3UE.js.map} +0 -0
- /package/dist/{plan-backfill-52OBXJRO.js.map → plan-backfill-W4FLMVC6.js.map} +0 -0
- /package/dist/{skills-BX2NZKPN.js.map → skills-RO2BW4XO.js.map} +0 -0
- /package/dist/{start-TYBSF7PZ.js.map → start-DHYV7OQM.js.map} +0 -0
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/shared/fs-utils.ts
|
|
4
4
|
import { randomUUID } from "crypto";
|
|
5
5
|
import { existsSync } from "fs";
|
|
6
|
-
import { mkdir, readFile, rename, unlink, writeFile } from "fs/promises";
|
|
6
|
+
import { link, mkdir, readFile, rename, stat, unlink, writeFile } from "fs/promises";
|
|
7
7
|
import { dirname, join, parse } from "path";
|
|
8
8
|
function isEnoent(err) {
|
|
9
9
|
return typeof err === "object" && err !== null && "code" in err && err.code === "ENOENT";
|
|
@@ -26,8 +26,9 @@ var LOCK_ACQUIRE_TIMEOUT_MS = 5e3;
|
|
|
26
26
|
var LOCK_STALE_MS = 3e4;
|
|
27
27
|
var LOCK_BACKOFF_BASE_MS = 5;
|
|
28
28
|
var LOCK_BACKOFF_CAP_MS = 50;
|
|
29
|
+
var UNPARSEABLE_LOCK_GRACE_MS = 5e3;
|
|
29
30
|
function isLockStale(lock, nowMs, staleMs, isProcessAlive) {
|
|
30
|
-
if (nowMs - lock.startedAt > staleMs) return true;
|
|
31
|
+
if (nowMs - (lock.refreshedAt ?? lock.startedAt) > staleMs) return true;
|
|
31
32
|
if (!isProcessAlive(lock.pid)) return true;
|
|
32
33
|
return false;
|
|
33
34
|
}
|
|
@@ -55,21 +56,92 @@ async function acquireFileLock(lockPath, owner, settings) {
|
|
|
55
56
|
const deadline = settings.now() + settings.timeoutMs;
|
|
56
57
|
let attempt = 0;
|
|
57
58
|
while (true) {
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
if (await tryCreateLock(lockPath, owner)) return;
|
|
60
|
+
const stole = await tryStealStaleLock(
|
|
61
|
+
lockPath,
|
|
62
|
+
settings.now(),
|
|
63
|
+
settings.staleMs,
|
|
64
|
+
settings.isProcessAlive
|
|
65
|
+
);
|
|
66
|
+
if (settings.now() >= deadline) {
|
|
67
|
+
throw new Error(
|
|
68
|
+
`withFileLock: timed out acquiring ${lockPath} after ${settings.timeoutMs}ms`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
if (stole) continue;
|
|
72
|
+
attempt += 1;
|
|
73
|
+
await settings.sleep(backoffDelay(attempt));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
async function tryAcquireHeldFileLock(lockPath, options) {
|
|
77
|
+
const now = options.now ?? Date.now;
|
|
78
|
+
const isProcessAlive = options.isProcessAlive ?? defaultIsProcessAlive;
|
|
79
|
+
const startedAt = now();
|
|
80
|
+
const owner = {
|
|
81
|
+
pid: process.pid,
|
|
82
|
+
startedAt,
|
|
83
|
+
refreshedAt: startedAt,
|
|
84
|
+
id: randomUUID()
|
|
85
|
+
};
|
|
86
|
+
await mkdir(dirname(lockPath), { recursive: true });
|
|
87
|
+
if (!await tryCreateLock(lockPath, owner)) {
|
|
88
|
+
if (!await tryStealStaleLock(lockPath, now(), options.staleMs, isProcessAlive)) return null;
|
|
89
|
+
if (!await tryCreateLock(lockPath, owner)) return null;
|
|
90
|
+
}
|
|
91
|
+
let compromised = null;
|
|
92
|
+
let released = false;
|
|
93
|
+
const refresh = async () => {
|
|
94
|
+
const current = await readLockRecord(lockPath);
|
|
95
|
+
if (current?.id !== owner.id) {
|
|
96
|
+
compromised = new Error(
|
|
97
|
+
`Held lock compromised: ${lockPath} is no longer owned by this process`
|
|
98
|
+
);
|
|
99
|
+
clearInterval(timer);
|
|
60
100
|
return;
|
|
61
|
-
} catch (err) {
|
|
62
|
-
if (!isEexist(err)) throw err;
|
|
63
|
-
if (await tryStealStaleLock(lockPath, settings.now(), settings.staleMs, settings.isProcessAlive))
|
|
64
|
-
continue;
|
|
65
|
-
if (settings.now() >= deadline) {
|
|
66
|
-
throw new Error(
|
|
67
|
-
`withFileLock: timed out acquiring ${lockPath} after ${settings.timeoutMs}ms`
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
attempt += 1;
|
|
71
|
-
await settings.sleep(backoffDelay(attempt));
|
|
72
101
|
}
|
|
102
|
+
await atomicWriteFile(lockPath, JSON.stringify({ ...owner, refreshedAt: now() }), {
|
|
103
|
+
mode: 384
|
|
104
|
+
});
|
|
105
|
+
};
|
|
106
|
+
const timer = setInterval(() => {
|
|
107
|
+
if (released || compromised) return;
|
|
108
|
+
refresh().catch((err) => {
|
|
109
|
+
compromised = err instanceof Error ? err : new Error(String(err));
|
|
110
|
+
clearInterval(timer);
|
|
111
|
+
});
|
|
112
|
+
}, options.refreshMs);
|
|
113
|
+
timer.unref();
|
|
114
|
+
return {
|
|
115
|
+
assertHealthy() {
|
|
116
|
+
if (compromised) throw compromised;
|
|
117
|
+
},
|
|
118
|
+
async release() {
|
|
119
|
+
if (released) return;
|
|
120
|
+
released = true;
|
|
121
|
+
clearInterval(timer);
|
|
122
|
+
await releaseLockIfOwner(lockPath, owner);
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
async function tryCreateLock(lockPath, owner) {
|
|
127
|
+
const tmpPath = `${lockPath}.${process.pid}.${owner.id}.tmp`;
|
|
128
|
+
await writeFile(tmpPath, JSON.stringify(owner), { mode: 384 });
|
|
129
|
+
try {
|
|
130
|
+
await link(tmpPath, lockPath);
|
|
131
|
+
return true;
|
|
132
|
+
} catch (err) {
|
|
133
|
+
if (isEexist(err)) return false;
|
|
134
|
+
throw err;
|
|
135
|
+
} finally {
|
|
136
|
+
await unlinkIfExists(tmpPath);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function readLockRecord(lockPath) {
|
|
140
|
+
try {
|
|
141
|
+
return parseLockRecord(await readFile(lockPath, "utf-8"));
|
|
142
|
+
} catch (err) {
|
|
143
|
+
if (isEnoent(err)) return null;
|
|
144
|
+
throw err;
|
|
73
145
|
}
|
|
74
146
|
}
|
|
75
147
|
function defaultSleep(ms) {
|
|
@@ -98,8 +170,9 @@ function parseLockRecord(raw) {
|
|
|
98
170
|
const pid = Reflect.get(value, "pid");
|
|
99
171
|
const startedAt = Reflect.get(value, "startedAt");
|
|
100
172
|
const id = Reflect.get(value, "id");
|
|
173
|
+
const refreshedAt = Reflect.get(value, "refreshedAt");
|
|
101
174
|
if (typeof pid === "number" && typeof startedAt === "number" && typeof id === "string") {
|
|
102
|
-
return { pid, startedAt, id };
|
|
175
|
+
return typeof refreshedAt === "number" ? { pid, startedAt, id, refreshedAt } : { pid, startedAt, id };
|
|
103
176
|
}
|
|
104
177
|
return null;
|
|
105
178
|
}
|
|
@@ -112,6 +185,7 @@ async function tryStealStaleLock(lockPath, nowMs, staleMs, isProcessAlive) {
|
|
|
112
185
|
return false;
|
|
113
186
|
}
|
|
114
187
|
if (!existing) {
|
|
188
|
+
if (!await isOlderThan(lockPath, nowMs, UNPARSEABLE_LOCK_GRACE_MS)) return false;
|
|
115
189
|
await unlinkIfExists(lockPath);
|
|
116
190
|
return true;
|
|
117
191
|
}
|
|
@@ -119,6 +193,14 @@ async function tryStealStaleLock(lockPath, nowMs, staleMs, isProcessAlive) {
|
|
|
119
193
|
await unlinkMatching(lockPath, existing);
|
|
120
194
|
return true;
|
|
121
195
|
}
|
|
196
|
+
async function isOlderThan(path, nowMs, ageMs) {
|
|
197
|
+
try {
|
|
198
|
+
return nowMs - (await stat(path)).mtimeMs > ageMs;
|
|
199
|
+
} catch (err) {
|
|
200
|
+
if (isEnoent(err)) return true;
|
|
201
|
+
throw err;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
122
204
|
async function unlinkMatching(lockPath, expected) {
|
|
123
205
|
try {
|
|
124
206
|
const current = parseLockRecord(await readFile(lockPath, "utf-8"));
|
|
@@ -168,6 +250,7 @@ export {
|
|
|
168
250
|
isCorruptionError,
|
|
169
251
|
atomicWriteFile,
|
|
170
252
|
withFileLock,
|
|
253
|
+
tryAcquireHeldFileLock,
|
|
171
254
|
findProjectRoot
|
|
172
255
|
};
|
|
173
|
-
//# sourceMappingURL=chunk-
|
|
256
|
+
//# sourceMappingURL=chunk-VHPNDDB5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/fs-utils.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\nimport { existsSync } from 'node:fs';\nimport { link, mkdir, readFile, rename, stat, unlink, writeFile } from 'node:fs/promises';\nimport { dirname, join, parse } from 'node:path';\n\nexport function isEnoent(err: unknown): boolean {\n return typeof err === 'object' && err !== null && 'code' in err && err.code === 'ENOENT';\n}\n\nexport function isEexist(err: unknown): boolean {\n return typeof err === 'object' && err !== null && 'code' in err && err.code === 'EEXIST';\n}\n\n/**\n * Detect JSON parse errors or Zod validation failures that indicate\n * a corrupt store file. Shared across all file-backed stores.\n */\nexport function isCorruptionError(err: unknown): boolean {\n if (err instanceof SyntaxError) return true;\n if (typeof err === 'object' && err !== null && 'name' in err && err.name === 'ZodError')\n return true;\n return false;\n}\n\n/**\n * Write `contents` to `filePath` atomically by writing to a unique tmp\n * path, then `rename`-ing into place.\n *\n * The tmp path includes `pid` + `randomUUID()` so concurrent writers\n * (different daemon processes, parallel test workers) cannot truncate\n * each other's in-flight tmp file. A shared `${filePath}.tmp` is unsafe:\n * if writer A's `open(w)` truncates a tmp that writer B already wrote\n * but hasn't yet renamed, the next `rename(tmp, filePath)` slides a\n * partial 0-byte (or `{`) into the canonical path — exactly the\n * corruption we observed in `rate-limits.json`.\n *\n * `rename` within one filesystem is atomic per POSIX, so a reader either\n * sees the prior canonical file or the fully-written new one. fsync is\n * intentionally NOT called — power-loss durability is not the failure\n * mode we're fixing, and forcing fsync on every store write would slow\n * the daemon meaningfully without addressing the actual race.\n *\n * Pass `mode` to set permissions on the tmp file (used by credentials-\n * vault to preserve `0o600`). Callers are responsible for `mkdir`-ing\n * the parent dir.\n */\nexport async function atomicWriteFile(\n filePath: string,\n contents: string,\n options?: { mode?: number }\n): Promise<void> {\n const tmpPath = `${filePath}.${process.pid}.${randomUUID()}.tmp`;\n await writeFile(tmpPath, contents, { encoding: 'utf-8', mode: options?.mode });\n await rename(tmpPath, filePath);\n}\n\ninterface LockRecord {\n pid: number;\n startedAt: number;\n /** Held locks (`tryAcquireHeldFileLock`) rewrite this periodically; staleness is judged from it. */\n refreshedAt?: number;\n /**\n * Unique per acquisition — guards against a pid+startedAt collision (17\n * daemons can start within the same millisecond) unlinking a live peer's lock.\n */\n id: string;\n}\n\nexport interface WithFileLockOptions {\n /** Max time to wait to acquire before throwing. Default 5000ms. */\n timeoutMs?: number;\n /** Age past which a held lock is considered abandoned. Default 5000ms. */\n staleMs?: number;\n /** Injected in tests; defaults to `Date.now`. */\n now?: () => number;\n /** Injected in tests; defaults to a `process.kill(pid, 0)` liveness probe. */\n isProcessAlive?: (pid: number) => boolean;\n /** Injected in tests; defaults to a real `setTimeout` delay. */\n sleep?: (ms: number) => Promise<void>;\n}\n\nconst LOCK_ACQUIRE_TIMEOUT_MS = 5_000;\n/**\n * Stale-takeover age must be well ABOVE the acquire timeout so a live holder\n * whose critical section runs longer than a waiter's timeout is never declared\n * stale and stolen (which would run two `fn`s concurrently). A crashed holder\n * is still reclaimed immediately via the PID-liveness check; this age is only\n * the backstop for PID reuse.\n */\nconst LOCK_STALE_MS = 30_000;\nconst LOCK_BACKOFF_BASE_MS = 5;\nconst LOCK_BACKOFF_CAP_MS = 50;\nconst UNPARSEABLE_LOCK_GRACE_MS = 5_000;\n\n/**\n * Pure predicate: is an existing lock safe to steal? Stale when the owner PID\n * is no longer alive, or it has been held longer than `staleMs` (a backstop\n * against a crashed owner whose PID was later reused). Mirrors\n * `self-update-lock.ts:isStaleLock`; duplicated here because `fs-utils` is a\n * lower layer and must not import from `services/` (that would be a cycle).\n */\nexport function isLockStale(\n lock: { pid: number; startedAt: number; refreshedAt?: number },\n nowMs: number,\n staleMs: number,\n isProcessAlive: (pid: number) => boolean\n): boolean {\n if (nowMs - (lock.refreshedAt ?? lock.startedAt) > staleMs) return true;\n if (!isProcessAlive(lock.pid)) return true;\n return false;\n}\n\n/**\n * Run `fn` while holding a cross-process advisory lock at `lockPath`.\n *\n * Cross-process safe via an atomic `link` create (see `tryCreateLock`) —\n * exactly one process wins; losers inspect the existing lock and either wait (live owner) or\n * steal it (stale owner). Throws if the lock cannot be acquired within\n * `timeoutMs`: callers MUST treat a throw as \"did not run\". For credential /\n * record writes, failing the write (and retrying later) is strictly safer than\n * proceeding unlocked and clobbering another daemon's concurrent write.\n *\n * The lock is released in a `finally`, and only if we still own it — guarding\n * against unlinking a successor's lock when our `fn` overran `staleMs` and a\n * peer stole the lock mid-flight.\n */\nexport async function withFileLock<T>(\n lockPath: string,\n fn: () => Promise<T>,\n options?: WithFileLockOptions\n): Promise<T> {\n const settings = resolveLockSettings(options);\n const owner: LockRecord = { pid: process.pid, startedAt: settings.now(), id: randomUUID() };\n\n await mkdir(dirname(lockPath), { recursive: true });\n await acquireFileLock(lockPath, owner, settings);\n\n try {\n return await fn();\n } finally {\n await releaseLockIfOwner(lockPath, owner);\n }\n}\n\ninterface LockSettings {\n timeoutMs: number;\n staleMs: number;\n now: () => number;\n isProcessAlive: (pid: number) => boolean;\n sleep: (ms: number) => Promise<void>;\n}\n\nfunction resolveLockSettings(options?: WithFileLockOptions): LockSettings {\n return {\n timeoutMs: options?.timeoutMs ?? LOCK_ACQUIRE_TIMEOUT_MS,\n staleMs: options?.staleMs ?? LOCK_STALE_MS,\n now: options?.now ?? Date.now,\n isProcessAlive: options?.isProcessAlive ?? defaultIsProcessAlive,\n sleep: options?.sleep ?? defaultSleep,\n };\n}\n\n/**\n * Throw rather than return on timeout: a write that cannot take the lock must\n * NOT silently proceed unlocked, which would reintroduce the whole-file clobber.\n */\nasync function acquireFileLock(\n lockPath: string,\n owner: LockRecord,\n settings: LockSettings\n): Promise<void> {\n const deadline = settings.now() + settings.timeoutMs;\n let attempt = 0;\n\n while (true) {\n if (await tryCreateLock(lockPath, owner)) return;\n const stole = await tryStealStaleLock(\n lockPath,\n settings.now(),\n settings.staleMs,\n settings.isProcessAlive\n );\n /**\n * Deadline before the steal-retry: a path whose create keeps failing\n * EEXIST while every read says ENOENT (e.g. a dangling symlink) used to\n * `continue` here forever — a no-sleep, no-timeout event-loop spin.\n */\n if (settings.now() >= deadline) {\n throw new Error(\n `withFileLock: timed out acquiring ${lockPath} after ${settings.timeoutMs}ms`\n );\n }\n if (stole) continue;\n attempt += 1;\n await settings.sleep(backoffDelay(attempt));\n }\n}\n\nexport interface HeldFileLock {\n /** Throws once another process has taken the lock over (e.g. we stalled past `staleMs`). */\n assertHealthy(): void;\n release(): Promise<void>;\n}\n\nexport interface HeldFileLockOptions {\n /** A held lock not refreshed for this long (or whose owner PID is dead) may be stolen. */\n staleMs: number;\n /** How often the owner rewrites `refreshedAt`. Must be well under `staleMs`. */\n refreshMs: number;\n now?: () => number;\n isProcessAlive?: (pid: number) => boolean;\n}\n\n/**\n * Try once to take a long-held cross-process lock (held for minutes to\n * hours, unlike `withFileLock`'s short critical sections). Returns null when a\n * live, fresh owner holds it. The owner refreshes the record every\n * `refreshMs`; a crashed owner is reclaimable immediately (dead PID) or after\n * `staleMs` without refresh (PID reuse backstop).\n *\n * Replaces `proper-lockfile`, whose `signal-exit` dependency installs a\n * SIGTRAP listener: libuv then catches V8's OOM trap instruction, returns to\n * it, and the daemon spins at 99% CPU forever instead of crashing (the Sept\n * 2026 overnight \"wedges\").\n */\nexport async function tryAcquireHeldFileLock(\n lockPath: string,\n options: HeldFileLockOptions\n): Promise<HeldFileLock | null> {\n const now = options.now ?? Date.now;\n const isProcessAlive = options.isProcessAlive ?? defaultIsProcessAlive;\n const startedAt = now();\n const owner: LockRecord = {\n pid: process.pid,\n startedAt,\n refreshedAt: startedAt,\n id: randomUUID(),\n };\n\n await mkdir(dirname(lockPath), { recursive: true });\n if (!(await tryCreateLock(lockPath, owner))) {\n if (!(await tryStealStaleLock(lockPath, now(), options.staleMs, isProcessAlive))) return null;\n if (!(await tryCreateLock(lockPath, owner))) return null;\n }\n\n let compromised: Error | null = null;\n let released = false;\n const refresh = async () => {\n const current = await readLockRecord(lockPath);\n if (current?.id !== owner.id) {\n compromised = new Error(\n `Held lock compromised: ${lockPath} is no longer owned by this process`\n );\n clearInterval(timer);\n return;\n }\n await atomicWriteFile(lockPath, JSON.stringify({ ...owner, refreshedAt: now() }), {\n mode: 0o600,\n });\n };\n const timer = setInterval(() => {\n if (released || compromised) return;\n refresh().catch((err: unknown) => {\n compromised = err instanceof Error ? err : new Error(String(err));\n clearInterval(timer);\n });\n }, options.refreshMs);\n timer.unref();\n\n return {\n assertHealthy() {\n if (compromised) throw compromised;\n },\n async release() {\n if (released) return;\n released = true;\n clearInterval(timer);\n await releaseLockIfOwner(lockPath, owner);\n },\n };\n}\n\n/**\n * Create the lock with its content already in place: write a private temp\n * file, then hard-link it into place (`link` fails EEXIST atomically, like\n * O_EXCL). `writeFile(…, { flag: 'wx' })` instead creates the file BEFORE its\n * bytes land, so a waiter could read '' mid-create, treat it as corrupt, and\n * steal a live lock — two holders at once.\n */\nasync function tryCreateLock(lockPath: string, owner: LockRecord): Promise<boolean> {\n const tmpPath = `${lockPath}.${process.pid}.${owner.id}.tmp`;\n await writeFile(tmpPath, JSON.stringify(owner), { mode: 0o600 });\n try {\n await link(tmpPath, lockPath);\n return true;\n } catch (err) {\n if (isEexist(err)) return false;\n throw err;\n } finally {\n await unlinkIfExists(tmpPath);\n }\n}\n\nasync function readLockRecord(lockPath: string): Promise<LockRecord | null> {\n try {\n return parseLockRecord(await readFile(lockPath, 'utf-8'));\n } catch (err) {\n if (isEnoent(err)) return null;\n throw err;\n }\n}\n\nfunction defaultSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction defaultIsProcessAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (err) {\n /** EPERM => the process exists but we lack permission to signal it. */\n return typeof err === 'object' && err !== null && 'code' in err && err.code === 'EPERM';\n }\n}\n\nfunction backoffDelay(attempt: number): number {\n const base = Math.min(LOCK_BACKOFF_BASE_MS * 2 ** (attempt - 1), LOCK_BACKOFF_CAP_MS);\n return base + Math.random() * LOCK_BACKOFF_BASE_MS;\n}\n\nfunction parseLockRecord(raw: string): LockRecord | null {\n let value: unknown;\n try {\n value = JSON.parse(raw);\n } catch {\n return null;\n }\n if (typeof value !== 'object' || value === null) return null;\n const pid = Reflect.get(value, 'pid');\n const startedAt = Reflect.get(value, 'startedAt');\n const id = Reflect.get(value, 'id');\n const refreshedAt = Reflect.get(value, 'refreshedAt');\n if (typeof pid === 'number' && typeof startedAt === 'number' && typeof id === 'string') {\n return typeof refreshedAt === 'number'\n ? { pid, startedAt, id, refreshedAt }\n : { pid, startedAt, id };\n }\n return null;\n}\n\nasync function tryStealStaleLock(\n lockPath: string,\n nowMs: number,\n staleMs: number,\n isProcessAlive: (pid: number) => boolean\n): Promise<boolean> {\n let existing: LockRecord | null;\n try {\n existing = parseLockRecord(await readFile(lockPath, 'utf-8'));\n } catch (err) {\n if (isEnoent(err)) return true;\n return false;\n }\n if (!existing) {\n /**\n * Unparseable: either corrupt (reclaim) or a pre-upgrade peer mid-create\n * via `writeFile(wx)` (still being written — never steal). Only a lock\n * that has sat unparseable past the grace window is treated as corrupt.\n */\n if (!(await isOlderThan(lockPath, nowMs, UNPARSEABLE_LOCK_GRACE_MS))) return false;\n await unlinkIfExists(lockPath);\n return true;\n }\n if (!isLockStale(existing, nowMs, staleMs, isProcessAlive)) return false;\n await unlinkMatching(lockPath, existing);\n return true;\n}\n\nasync function isOlderThan(path: string, nowMs: number, ageMs: number): Promise<boolean> {\n try {\n return nowMs - (await stat(path)).mtimeMs > ageMs;\n } catch (err) {\n if (isEnoent(err)) return true;\n throw err;\n }\n}\n\nasync function unlinkMatching(lockPath: string, expected: LockRecord): Promise<void> {\n try {\n const current = parseLockRecord(await readFile(lockPath, 'utf-8'));\n if (current && current.id !== expected.id) {\n return;\n }\n } catch (err) {\n if (isEnoent(err)) return;\n }\n await unlinkIfExists(lockPath);\n}\n\nasync function releaseLockIfOwner(lockPath: string, owner: LockRecord): Promise<void> {\n try {\n const current = parseLockRecord(await readFile(lockPath, 'utf-8'));\n if (current && current.id !== owner.id) {\n return;\n }\n } catch (err) {\n if (isEnoent(err)) return;\n }\n await unlinkIfExists(lockPath);\n}\n\nasync function unlinkIfExists(path: string): Promise<void> {\n try {\n await unlink(path);\n } catch (err) {\n if (!isEnoent(err)) throw err;\n }\n}\n\n/**\n * Walk up the directory tree from `startDir` to find the project root.\n *\n * Looks for `.git` (directory or file — worktrees use a `.git` file) or\n * `pnpm-workspace.yaml` as root markers.\n *\n * Returns a discriminated result so callers can distinguish \"marker found\"\n * (genuinely scoped, even if the marker is in startDir itself) from\n * \"no marker anywhere\" (genuinely unscoped). The bare-string return shape\n * conflated these, since both cases produced `startDir` — breaking the\n * unscoped detection in `serve.ts` whenever the daemon was launched from\n * a project's own root directory.\n *\n * In dev: `startDir` is typically `apps/daemon/` (pnpm runs from package dir),\n * so this walks up to find the monorepo root. In prod install: `startDir` is\n * the user's project directory where the daemon is launched, and `.git` is\n * found immediately. Called once at daemon startup — the result is used as\n * the workspace root for file-io, LSP, and file watching.\n */\nexport function findProjectRoot(startDir: string): { root: string; foundMarker: boolean } {\n let dir = startDir;\n while (true) {\n if (existsSync(join(dir, 'pnpm-workspace.yaml')) || existsSync(join(dir, '.git'))) {\n return { root: dir, foundMarker: true };\n }\n const parent = dirname(dir);\n if (parent === dir || parent === parse(dir).root) {\n return { root: startDir, foundMarker: false };\n }\n dir = parent;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-4T2OQAVL.js";
|
|
5
5
|
import {
|
|
6
6
|
isEnoent
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-VHPNDDB5.js";
|
|
8
8
|
import {
|
|
9
9
|
logger
|
|
10
10
|
} from "./chunk-FIE2FRIW.js";
|
|
@@ -261,7 +261,7 @@ async function refreshRepoPathsInBackground(log) {
|
|
|
261
261
|
const startGen = cacheGeneration;
|
|
262
262
|
const start = Date.now();
|
|
263
263
|
try {
|
|
264
|
-
const { findGitRepos: findGitRepos2, discoverWorktrees: discoverWorktrees2 } = await import("./git-repo-
|
|
264
|
+
const { findGitRepos: findGitRepos2, discoverWorktrees: discoverWorktrees2 } = await import("./git-repo-K45YAY55.js");
|
|
265
265
|
const { homedir: homedir2 } = await import("os");
|
|
266
266
|
const repos = await findGitRepos2(homedir2());
|
|
267
267
|
const worktrees = await discoverWorktrees2(repos);
|
|
@@ -796,4 +796,4 @@ export {
|
|
|
796
796
|
discoverWorktrees,
|
|
797
797
|
_testing
|
|
798
798
|
};
|
|
799
|
-
//# sourceMappingURL=chunk-
|
|
799
|
+
//# sourceMappingURL=chunk-WKJAGQU7.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
detectSkills
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ELZLWLTO.js";
|
|
5
5
|
import {
|
|
6
6
|
AUTH_STATUS_TIMEOUT_MS,
|
|
7
7
|
BUFFER_OVERFLOW_MSG,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
run,
|
|
14
14
|
runWithTimeout,
|
|
15
15
|
truncateDiff
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-WKJAGQU7.js";
|
|
17
17
|
import {
|
|
18
18
|
gitExecSafe
|
|
19
19
|
} from "./chunk-4T2OQAVL.js";
|
|
@@ -23,10 +23,10 @@ import {
|
|
|
23
23
|
CURSOR_RUNTIME_ID,
|
|
24
24
|
DEVIN_RUNTIME_ID,
|
|
25
25
|
detectMCPServers
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-FYT3ETTP.js";
|
|
27
27
|
import {
|
|
28
28
|
isEnoent
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-VHPNDDB5.js";
|
|
30
30
|
import {
|
|
31
31
|
createOneShotPool
|
|
32
32
|
} from "./chunk-ZFKJAYAN.js";
|
|
@@ -39,7 +39,7 @@ import {
|
|
|
39
39
|
formatTaskFeedback,
|
|
40
40
|
toRecord,
|
|
41
41
|
toSdkContent
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-3PJULQHI.js";
|
|
43
43
|
import {
|
|
44
44
|
AGENT_IDS,
|
|
45
45
|
AGENT_SYSTEM_CLAUDE_CODE,
|
|
@@ -55,7 +55,7 @@ import {
|
|
|
55
55
|
claudeDisplayPricing,
|
|
56
56
|
inflateToolResultContent,
|
|
57
57
|
isImageMimeType
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-DQQOVPVK.js";
|
|
59
59
|
import {
|
|
60
60
|
AnthropicAuthStatusSchema,
|
|
61
61
|
CodexAuthStatusSchema,
|
|
@@ -63,7 +63,7 @@ import {
|
|
|
63
63
|
DevinAuthStatusSchema,
|
|
64
64
|
PermissionModeSchema,
|
|
65
65
|
TESTED_CODEX_VERSION
|
|
66
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-MV7VSD2T.js";
|
|
67
67
|
import {
|
|
68
68
|
logger
|
|
69
69
|
} from "./chunk-FIE2FRIW.js";
|
|
@@ -3219,7 +3219,7 @@ function displayCostFor(modelId) {
|
|
|
3219
3219
|
return {
|
|
3220
3220
|
costInputUsd: seed.inputUsdPerMtok,
|
|
3221
3221
|
costOutputUsd: seed.outputUsdPerMtok,
|
|
3222
|
-
pricingNote: `API-equivalent rates, not subscription charges. Cached input: ${seed.cachedInputUsdPerMtok}/M. Prompts above 272K: 2\xD7 input/cache, 1.5\xD7 output
|
|
3222
|
+
pricingNote: `API-equivalent rates, not subscription charges. Cached input: ${seed.cachedInputUsdPerMtok}/M. Prompts above 272K: 2\xD7 input/cache, 1.5\xD7 output.`
|
|
3223
3223
|
};
|
|
3224
3224
|
}
|
|
3225
3225
|
var CODEX_MODEL_CATALOG = withCapabilityTiers([
|
|
@@ -3280,25 +3280,6 @@ var CODEX_MODEL_CATALOG = withCapabilityTiers([
|
|
|
3280
3280
|
vision: true
|
|
3281
3281
|
}
|
|
3282
3282
|
},
|
|
3283
|
-
{
|
|
3284
|
-
id: "gpt-5.6-sol",
|
|
3285
|
-
nativeName: "gpt-5.6-sol",
|
|
3286
|
-
displayName: "GPT-5.6 Sol",
|
|
3287
|
-
description: "Reliable agentic workhorse for everyday tasks.",
|
|
3288
|
-
contextWindow: 272e3,
|
|
3289
|
-
supportedEfforts: ["low", "medium", "high", "xhigh", "max", "ultra"],
|
|
3290
|
-
defaultEffort: "low",
|
|
3291
|
-
pricing: pricingFor("gpt-5.6-sol"),
|
|
3292
|
-
tagline: "Reliable coding, research and everyday work",
|
|
3293
|
-
speedTier: "standard",
|
|
3294
|
-
...displayCostFor("gpt-5.6-sol"),
|
|
3295
|
-
capabilities: {
|
|
3296
|
-
reasoning: true,
|
|
3297
|
-
adaptiveThinking: false,
|
|
3298
|
-
webSearch: false,
|
|
3299
|
-
vision: true
|
|
3300
|
-
}
|
|
3301
|
-
},
|
|
3302
3283
|
{
|
|
3303
3284
|
id: "gpt-5.6-terra",
|
|
3304
3285
|
nativeName: "gpt-5.6-terra",
|
|
@@ -3317,25 +3298,6 @@ var CODEX_MODEL_CATALOG = withCapabilityTiers([
|
|
|
3317
3298
|
webSearch: false,
|
|
3318
3299
|
vision: true
|
|
3319
3300
|
}
|
|
3320
|
-
},
|
|
3321
|
-
{
|
|
3322
|
-
id: "gpt-5.6-luna",
|
|
3323
|
-
nativeName: "gpt-5.6-luna",
|
|
3324
|
-
displayName: "GPT-5.6 Luna",
|
|
3325
|
-
description: "Fast and affordable agentic coding model.",
|
|
3326
|
-
contextWindow: 272e3,
|
|
3327
|
-
supportedEfforts: ["low", "medium", "high", "xhigh", "max"],
|
|
3328
|
-
defaultEffort: "medium",
|
|
3329
|
-
pricing: pricingFor("gpt-5.6-luna"),
|
|
3330
|
-
tagline: "Fast, affordable OpenAI Codex",
|
|
3331
|
-
speedTier: "fast",
|
|
3332
|
-
...displayCostFor("gpt-5.6-luna"),
|
|
3333
|
-
capabilities: {
|
|
3334
|
-
reasoning: true,
|
|
3335
|
-
adaptiveThinking: false,
|
|
3336
|
-
webSearch: false,
|
|
3337
|
-
vision: true
|
|
3338
|
-
}
|
|
3339
3301
|
}
|
|
3340
3302
|
]);
|
|
3341
3303
|
|
|
@@ -8933,4 +8895,4 @@ export {
|
|
|
8933
8895
|
refreshInstalledAgents,
|
|
8934
8896
|
refreshCodexAuthSlice
|
|
8935
8897
|
};
|
|
8936
|
-
//# sourceMappingURL=chunk-
|
|
8898
|
+
//# sourceMappingURL=chunk-XPOXRIHH.js.map
|