github-router 0.3.240 → 0.3.241
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/browser-bridge/index.js +357 -369
- package/dist/browser-ext/background.js +2 -2
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/browser-ext/snapshot-cdp.js +1 -1
- package/dist/engine-DL15-epb.js +2 -0
- package/dist/lib/tree-sitter-pool/worker.js +36 -31
- package/dist/lifecycle-0rXrwjWk.js +2 -0
- package/dist/{lifecycle-Cuuj40CW.js → lifecycle-CUf1UDrH.js} +37 -17
- package/dist/lifecycle-CUf1UDrH.js.map +1 -0
- package/dist/{lifecycle-C-9_vhyM.js → lifecycle-DHZsVN8j.js} +39 -16
- package/dist/lifecycle-DHZsVN8j.js.map +1 -0
- package/dist/lifecycle-hzPwXc3I.js +2 -0
- package/dist/main.js +840 -408
- package/dist/main.js.map +1 -1
- package/dist/{paths-Srxs-aR-.js → paths-BjTMI_xK.js} +155 -54
- package/dist/{paths-Srxs-aR-.js.map → paths-BjTMI_xK.js.map} +1 -1
- package/dist/paths-D3XgmTcQ.js +2 -0
- package/dist/{peer-mcp-personas-CDja7arT.js → peer-mcp-personas-r_UmLBkJ.js} +1850 -1206
- package/dist/peer-mcp-personas-r_UmLBkJ.js.map +1 -0
- package/package.json +21 -21
- package/dist/engine-5VxiBAdY.js +0 -6
- package/dist/lifecycle-C-9_vhyM.js.map +0 -1
- package/dist/lifecycle-Cuuj40CW.js.map +0 -1
- package/dist/lifecycle-DF2ygqz8.js +0 -4
- package/dist/lifecycle-wIIt0wGo.js +0 -4
- package/dist/paths-C75DZ_Y3.js +0 -3
- package/dist/peer-mcp-personas-CDja7arT.js.map +0 -1
|
@@ -2,63 +2,164 @@ import consola from "consola";
|
|
|
2
2
|
import { randomBytes } from "node:crypto";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import os from "node:os";
|
|
5
|
-
import
|
|
6
|
-
|
|
5
|
+
import path from "node:path";
|
|
7
6
|
//#region src/lib/paths.ts
|
|
8
7
|
function appDir() {
|
|
9
|
-
return
|
|
8
|
+
return path.join(os.homedir(), ".local", "share", "github-router");
|
|
10
9
|
}
|
|
11
10
|
const PATHS = {
|
|
12
11
|
get APP_DIR() {
|
|
13
12
|
return appDir();
|
|
14
13
|
},
|
|
15
14
|
get GITHUB_TOKEN_PATH() {
|
|
16
|
-
return
|
|
15
|
+
return path.join(appDir(), "github_token");
|
|
17
16
|
},
|
|
17
|
+
/**
|
|
18
|
+
* Second, WRITE-capable GitHub token for the first-mate
|
|
19
|
+
* agent-orchestration surface (`--agents`), stored apart from
|
|
20
|
+
* `github_token` (the Copilot App token). Minted by
|
|
21
|
+
* `setupGitHubAgentToken()` via a device-flow login against the GitHub
|
|
22
|
+
* CLI OAuth client. Mode 0o600.
|
|
23
|
+
*/
|
|
18
24
|
get GITHUB_AGENT_TOKEN_PATH() {
|
|
19
|
-
return
|
|
25
|
+
return path.join(appDir(), "github_agent_token");
|
|
20
26
|
},
|
|
27
|
+
/**
|
|
28
|
+
* Root of the durable first-mate fleet registry (`--agents`): the
|
|
29
|
+
* global `missions.json` mission index + per-repo `<owner>__<repo>.json`
|
|
30
|
+
* unit ledgers + the decisions/approvals ledger. Cross-launch and
|
|
31
|
+
* OUTSIDE the per-launch CLAUDE_CONFIG_DIR mirror (which is swept each
|
|
32
|
+
* launch) — the first mate must survive proxy restarts / context
|
|
33
|
+
* clears. Modeled on the worker-agent lifecycle ledger.
|
|
34
|
+
*/
|
|
21
35
|
get FIRST_MATE_DIR() {
|
|
22
|
-
return process.env.GH_ROUTER_FIRST_MATE_DIR ??
|
|
36
|
+
return process.env.GH_ROUTER_FIRST_MATE_DIR ?? path.join(appDir(), "first-mate");
|
|
23
37
|
},
|
|
24
38
|
get ERROR_LOG_PATH() {
|
|
25
|
-
return
|
|
39
|
+
return path.join(appDir(), "error.log");
|
|
26
40
|
},
|
|
41
|
+
/**
|
|
42
|
+
* Durable, router-owned directory for worker OVERFLOW artifacts. Two
|
|
43
|
+
* kinds land here, both kept OUT of the MCP result relay so they don't
|
|
44
|
+
* overflow Claude Code's 25k-token cap:
|
|
45
|
+
* - `<pid>-<8hex>.patch` — a `worker_implement`/`worker_test` worktree
|
|
46
|
+
* diff larger than `PREVIEW_CAP` (worker-agent/worktree.ts): the FULL
|
|
47
|
+
* `git diff --binary --full-index` patch, written BEFORE the worktree
|
|
48
|
+
* is removed so the (possibly binary) change stays `git apply`-able.
|
|
49
|
+
* - `<pid>-<8hex>.txt` — any worker result over the relay byte cap
|
|
50
|
+
* (worker-agent/relay-cap.ts `relaySafeText`): the full result text,
|
|
51
|
+
* with a bounded preview + this path returned in its place.
|
|
52
|
+
* `sweepAgedWorkerDiffs()` reaps entries older than 7 days on each write.
|
|
53
|
+
* Cross-launch cache (like TOOLBELT_BIN_DIR) — deliberately OUTSIDE the
|
|
54
|
+
* per-launch CLAUDE_CONFIG_DIR mirror and OUTSIDE the user's repo.
|
|
55
|
+
*/
|
|
27
56
|
get WORKER_DIFFS_DIR() {
|
|
28
|
-
return
|
|
57
|
+
return path.join(appDir(), "worker-diffs");
|
|
29
58
|
},
|
|
59
|
+
/**
|
|
60
|
+
* Isolated CODEX_HOME for the spawned Codex CLI. Masks any cached
|
|
61
|
+
* ChatGPT subscription login (openai/codex#2733 — cached login can
|
|
62
|
+
* override OPENAI_API_KEY) so the proxy's dummy key is authoritative.
|
|
63
|
+
*/
|
|
30
64
|
get CODEX_HOME() {
|
|
31
|
-
return
|
|
65
|
+
return path.join(appDir(), "codex-isolated");
|
|
32
66
|
},
|
|
67
|
+
/**
|
|
68
|
+
* Router-owned install + data dir for CloudCLI (the `serve` browser control
|
|
69
|
+
* plane). Holds the pinned local `npm install` (node_modules/), an isolated
|
|
70
|
+
* `auth.db` (so we never collide with a user's standalone CloudCLI DB), and
|
|
71
|
+
* the persisted `.serve-secret.json` login. See docs/serve-control-plane.md.
|
|
72
|
+
*/
|
|
33
73
|
get CLOUDCLI_HOME() {
|
|
34
|
-
return
|
|
74
|
+
return path.join(appDir(), "cloudcli");
|
|
35
75
|
},
|
|
76
|
+
/**
|
|
77
|
+
* Runtime tempfiles for the per-launch peer-MCP wiring (the
|
|
78
|
+
* `--mcp-config` JSON and `--agents` JSON written before spawning
|
|
79
|
+
* Claude Code). Mode 0o700 to match the security review's mandate;
|
|
80
|
+
* cleaned on shutdown via the per-launch `cleanup()`, plus a
|
|
81
|
+
* boot-time sweep of stale files (dead PIDs, >24h old).
|
|
82
|
+
*/
|
|
36
83
|
get CLAUDE_RUNTIME_DIR() {
|
|
37
|
-
return
|
|
84
|
+
return path.join(appDir(), "runtime");
|
|
38
85
|
},
|
|
86
|
+
/**
|
|
87
|
+
* Router-owned CLAUDE_CONFIG_DIR. The spawned Claude Code (and any
|
|
88
|
+
* teammates it spawns via the agent-teams primitive) reads its
|
|
89
|
+
* config — including `.credentials.json` — from this dir. We
|
|
90
|
+
* snapshot-copy the user's `~/.claude/` here at startup (excluding
|
|
91
|
+
* `.credentials.json` and volatile state), then write our own
|
|
92
|
+
* synthetic Console OAuth credential. The teammate-spawn allowlist
|
|
93
|
+
* propagates `CLAUDE_CONFIG_DIR` to children, so teammates find the
|
|
94
|
+
* synthetic credential and authenticate instead of falling into the
|
|
95
|
+
* "Not logged in · Run /login" gate that would otherwise leave
|
|
96
|
+
* them mute. See `ensureClaudeConfigMirror` below.
|
|
97
|
+
*
|
|
98
|
+
* Per-launch dir: `<appDir>/claude-config/<pid>-<8 hex>`. Two
|
|
99
|
+
* concurrent `github-router claude` launches each get their own
|
|
100
|
+
* isolated mirror, so per-launch state (synthetic credential,
|
|
101
|
+
* snapshot copy of `~/.claude/`, future per-launch `.claude.json`
|
|
102
|
+
* mutation with the peer-MCP entry) cannot cross-talk. The
|
|
103
|
+
* per-launch suffix is cached on first access (see
|
|
104
|
+
* `claudeConfigDirSuffix()`) so all callers within a single proxy
|
|
105
|
+
* lifetime see the same value. Boot-time `sweepStaleClaudeConfigMirrors`
|
|
106
|
+
* reaps mirrors from crashed prior PIDs.
|
|
107
|
+
*/
|
|
39
108
|
get CLAUDE_CONFIG_DIR() {
|
|
40
|
-
return
|
|
109
|
+
return path.join(appDir(), "claude-config", claudeConfigDirSuffix());
|
|
41
110
|
},
|
|
111
|
+
/**
|
|
112
|
+
* Durable router-owned `bin/` for the LLM toolbelt — curated CLI
|
|
113
|
+
* tools (rg/fd/jq/sd/sg/yq) materialized here and prepended to the
|
|
114
|
+
* spawned agent's PATH. Intentionally OUTSIDE the per-launch
|
|
115
|
+
* CLAUDE_CONFIG_DIR mirror (which is swept per launch): the toolbelt
|
|
116
|
+
* is a cross-launch cache, like `last-update-check`.
|
|
117
|
+
*/
|
|
42
118
|
get TOOLBELT_BIN_DIR() {
|
|
43
|
-
return
|
|
119
|
+
return path.join(appDir(), "bin");
|
|
44
120
|
},
|
|
121
|
+
/**
|
|
122
|
+
* Root of the github-router-managed ColBERT semantic-search sidecar
|
|
123
|
+
* (the `--semantic-search` opt-in). Everything heavy that the
|
|
124
|
+
* `colgrep` child needs is provisioned, SHA-verified, and stored here
|
|
125
|
+
* by the router — never in the user's repo, never in colgrep's own
|
|
126
|
+
* global `%APPDATA%\colgrep` / `~/.config/colgrep`. Cross-launch cache
|
|
127
|
+
* (like TOOLBELT_BIN_DIR), deliberately OUTSIDE the per-launch
|
|
128
|
+
* CLAUDE_CONFIG_DIR mirror.
|
|
129
|
+
*
|
|
130
|
+
* Layout (see docs/research/colbert-sidecar-design.md §4):
|
|
131
|
+
* colbert/
|
|
132
|
+
* bin/colgrep[.exe] # provisioned binary
|
|
133
|
+
* models/LateOn-Code-edge/<rev>/ # 5 model files
|
|
134
|
+
* onnxruntime/1.23.0/cpu/<libname> # ORT dylib (ORT_DYLIB_PATH)
|
|
135
|
+
* indices/ # === COLGREP_DATA_DIR ===
|
|
136
|
+
* <project>-<xxh3(path|model)>/ # colgrep-owned per-(path,model)
|
|
137
|
+
* .gh-router-meta/<hash>.json # router-owned sidecar metadata
|
|
138
|
+
*/
|
|
45
139
|
get COLBERT_DIR() {
|
|
46
|
-
return
|
|
140
|
+
return path.join(appDir(), "colbert");
|
|
47
141
|
},
|
|
48
142
|
get COLBERT_BIN_DIR() {
|
|
49
|
-
return
|
|
143
|
+
return path.join(appDir(), "colbert", "bin");
|
|
50
144
|
},
|
|
51
145
|
get COLBERT_MODELS_DIR() {
|
|
52
|
-
return
|
|
146
|
+
return path.join(appDir(), "colbert", "models");
|
|
53
147
|
},
|
|
54
148
|
get COLBERT_ORT_DIR() {
|
|
55
|
-
return
|
|
149
|
+
return path.join(appDir(), "colbert", "onnxruntime");
|
|
56
150
|
},
|
|
151
|
+
/**
|
|
152
|
+
* Value passed to colgrep as `COLGREP_DATA_DIR`. colgrep keys the
|
|
153
|
+
* physical index dir by `xxh3(canonical_project_path | model)` under
|
|
154
|
+
* here, so every distinct workspace gets its own index dir for free.
|
|
155
|
+
* The router-owned freshness sidecar lives at
|
|
156
|
+
* `<COLBERT_INDICES_DIR>/.gh-router-meta/<hash>.json`.
|
|
157
|
+
*/
|
|
57
158
|
get COLBERT_INDICES_DIR() {
|
|
58
|
-
return
|
|
159
|
+
return path.join(appDir(), "colbert", "indices");
|
|
59
160
|
},
|
|
60
161
|
get COLBERT_META_DIR() {
|
|
61
|
-
return
|
|
162
|
+
return path.join(appDir(), "colbert", "indices", ".gh-router-meta");
|
|
62
163
|
}
|
|
63
164
|
};
|
|
64
165
|
/**
|
|
@@ -97,10 +198,10 @@ function claudeConfigDirSuffix() {
|
|
|
97
198
|
* refusal lives at the consuming helper.
|
|
98
199
|
*/
|
|
99
200
|
function isUnderClaudeConfigMirror(target) {
|
|
100
|
-
const resolvedRoot =
|
|
101
|
-
const resolvedTarget =
|
|
201
|
+
const resolvedRoot = path.resolve(PATHS.CLAUDE_CONFIG_DIR);
|
|
202
|
+
const resolvedTarget = path.resolve(target);
|
|
102
203
|
if (resolvedTarget === resolvedRoot) return true;
|
|
103
|
-
return resolvedTarget.startsWith(resolvedRoot +
|
|
204
|
+
return resolvedTarget.startsWith(resolvedRoot + path.sep);
|
|
104
205
|
}
|
|
105
206
|
async function ensurePaths() {
|
|
106
207
|
await fs.mkdir(PATHS.APP_DIR, { recursive: true });
|
|
@@ -120,17 +221,17 @@ async function ensurePaths() {
|
|
|
120
221
|
consola.debug("Peer-agent .md sweep skipped:", err);
|
|
121
222
|
});
|
|
122
223
|
await (async () => {
|
|
123
|
-
await (await import("./lifecycle-
|
|
224
|
+
await (await import("./lifecycle-hzPwXc3I.js")).sweepStaleWorktreesAtBoot();
|
|
124
225
|
})().catch((err) => {
|
|
125
226
|
consola.debug("Worker worktree boot sweep skipped:", err);
|
|
126
227
|
});
|
|
127
228
|
await (async () => {
|
|
128
|
-
await (await import("./lifecycle-
|
|
229
|
+
await (await import("./lifecycle-0rXrwjWk.js")).sweepStaleColbertMetaAtBoot();
|
|
129
230
|
})().catch((err) => {
|
|
130
231
|
consola.debug("ColBERT meta boot sweep skipped:", err);
|
|
131
232
|
});
|
|
132
233
|
}
|
|
133
|
-
const CLAUDE_HOME_POLICY = new Map([
|
|
234
|
+
const CLAUDE_HOME_POLICY = /* @__PURE__ */ new Map([
|
|
134
235
|
[".credentials.json", "ISOLATED"],
|
|
135
236
|
[".credentials.json.lock", "ISOLATED"],
|
|
136
237
|
[".oauth_refresh.lock", "ISOLATED"],
|
|
@@ -300,7 +401,7 @@ const SYNTHETIC_CLAUDE_JSON_FIELDS = {
|
|
|
300
401
|
*/
|
|
301
402
|
async function ensureClaudeConfigMirror(opts = {}) {
|
|
302
403
|
const realHome = opts.realHome ?? os.homedir();
|
|
303
|
-
const sourceDir =
|
|
404
|
+
const sourceDir = path.join(realHome, ".claude");
|
|
304
405
|
const targetDir = PATHS.CLAUDE_CONFIG_DIR;
|
|
305
406
|
await fs.mkdir(targetDir, {
|
|
306
407
|
recursive: true,
|
|
@@ -314,11 +415,11 @@ async function ensureClaudeConfigMirror(opts = {}) {
|
|
|
314
415
|
if (err.code !== "ENOENT") consola.debug(`ensureClaudeConfigMirror: cannot stat ${sourceDir}:`, err);
|
|
315
416
|
}
|
|
316
417
|
if (sourceExists) await mirrorDirRecursive(sourceDir, targetDir, "");
|
|
317
|
-
await fs.mkdir(
|
|
418
|
+
await fs.mkdir(path.join(targetDir, "agents"), { recursive: true });
|
|
318
419
|
for (const name of SHARED_TOPLEVEL_NAMES) await ensureSharedSymlink(name, sourceDir, targetDir).catch((err) => {
|
|
319
420
|
consola.debug(`ensureClaudeConfigMirror: SHARED symlink for ${name} skipped:`, err);
|
|
320
421
|
});
|
|
321
|
-
const credentialsPath =
|
|
422
|
+
const credentialsPath = path.join(targetDir, ".credentials.json");
|
|
322
423
|
const desiredJson = JSON.stringify(SYNTHETIC_CREDENTIAL, null, 2);
|
|
323
424
|
let needsWrite = true;
|
|
324
425
|
try {
|
|
@@ -345,7 +446,7 @@ async function ensureClaudeConfigMirror(opts = {}) {
|
|
|
345
446
|
await chmodIfPossible(credentialsPath, 384);
|
|
346
447
|
await injectSyntheticClaudeJsonFields(targetDir, sourceDir, realHome);
|
|
347
448
|
await assertOnboardingGateInjected(targetDir);
|
|
348
|
-
const markerPath =
|
|
449
|
+
const markerPath = path.join(targetDir, MANAGED_MARKER_FILENAME);
|
|
349
450
|
let markerExists = false;
|
|
350
451
|
try {
|
|
351
452
|
const markerStat = await fs.lstat(markerPath);
|
|
@@ -437,7 +538,7 @@ async function ensureClaudeConfigMirror(opts = {}) {
|
|
|
437
538
|
* degradation path is converted to a fail-loud launch error.
|
|
438
539
|
*/
|
|
439
540
|
async function injectSyntheticClaudeJsonFields(targetDir, sourceDir, realHome) {
|
|
440
|
-
const claudeJsonPath =
|
|
541
|
+
const claudeJsonPath = path.join(targetDir, ".claude.json");
|
|
441
542
|
let mirrorIsRegularFile = false;
|
|
442
543
|
try {
|
|
443
544
|
const mirrorStat = await fs.lstat(claudeJsonPath);
|
|
@@ -454,8 +555,8 @@ async function injectSyntheticClaudeJsonFields(targetDir, sourceDir, realHome) {
|
|
|
454
555
|
}
|
|
455
556
|
let existing = {};
|
|
456
557
|
let selectedSource = null;
|
|
457
|
-
const homeLevelClaudeJson =
|
|
458
|
-
const subdirClaudeJson =
|
|
558
|
+
const homeLevelClaudeJson = path.join(realHome, ".claude.json");
|
|
559
|
+
const subdirClaudeJson = path.join(sourceDir, ".claude.json");
|
|
459
560
|
const sourceCandidates = [
|
|
460
561
|
homeLevelClaudeJson,
|
|
461
562
|
mirrorIsRegularFile ? claudeJsonPath : null,
|
|
@@ -464,9 +565,9 @@ async function injectSyntheticClaudeJsonFields(targetDir, sourceDir, realHome) {
|
|
|
464
565
|
for (const sourceCandidate of sourceCandidates) {
|
|
465
566
|
if (sourceCandidate === null) continue;
|
|
466
567
|
try {
|
|
467
|
-
const stat
|
|
468
|
-
if (stat
|
|
469
|
-
consola.warn(`ensureClaudeConfigMirror: ${sourceCandidate} is ${stat
|
|
568
|
+
const stat = await fs.stat(sourceCandidate);
|
|
569
|
+
if (stat.size > MAX_CLAUDE_JSON_BYTES) {
|
|
570
|
+
consola.warn(`ensureClaudeConfigMirror: ${sourceCandidate} is ${stat.size} bytes (> ${MAX_CLAUDE_JSON_BYTES} cap); skipping this source to avoid OOM. Inspect for accidental log/state accumulation.`);
|
|
470
571
|
continue;
|
|
471
572
|
}
|
|
472
573
|
const parsed = parseExistingClaudeJson(await fs.readFile(sourceCandidate, "utf8"), sourceCandidate);
|
|
@@ -521,7 +622,7 @@ async function injectSyntheticClaudeJsonFields(targetDir, sourceDir, realHome) {
|
|
|
521
622
|
* blocks the event loop and risks OOM. 50 MiB is comfortably above
|
|
522
623
|
* any legitimate Claude Code state and well below typical RSS budgets.
|
|
523
624
|
*/
|
|
524
|
-
const MAX_CLAUDE_JSON_BYTES =
|
|
625
|
+
const MAX_CLAUDE_JSON_BYTES = 52428800;
|
|
525
626
|
/**
|
|
526
627
|
* Structural check for `oauthAccount`: must be a non-null, non-array
|
|
527
628
|
* object whose `accountUuid` AND `organizationUuid` are non-empty
|
|
@@ -579,19 +680,19 @@ function parseExistingClaudeJson(raw, contextPath) {
|
|
|
579
680
|
* upward by hand.
|
|
580
681
|
*/
|
|
581
682
|
async function assertOnboardingGateInjected(targetDir) {
|
|
582
|
-
const claudeJsonPath =
|
|
683
|
+
const claudeJsonPath = path.join(targetDir, ".claude.json");
|
|
583
684
|
let lst;
|
|
584
685
|
try {
|
|
585
686
|
lst = await fs.lstat(claudeJsonPath);
|
|
586
687
|
} catch (err) {
|
|
587
|
-
throw new Error(`ensureClaudeConfigMirror: postcondition failed — cannot lstat ${claudeJsonPath} after injection (synthetic onboarding-skip fields are required to prevent Claude Code's first-launch wizard, which would defeat the synthetic credential): ${err.message}
|
|
688
|
+
throw new Error(`ensureClaudeConfigMirror: postcondition failed — cannot lstat ${claudeJsonPath} after injection (synthetic onboarding-skip fields are required to prevent Claude Code's first-launch wizard, which would defeat the synthetic credential): ${err.message}`, { cause: err });
|
|
588
689
|
}
|
|
589
690
|
if (!lst.isFile()) throw new Error(`ensureClaudeConfigMirror: postcondition failed — ${claudeJsonPath} exists but is not a regular file (mode=${lst.mode.toString(8)}). Check the preceding warn-level log lines for the underlying cause; without a regular file holding the gate fields, Claude Code's first-launch wizard fires and defeats the synthetic credential.`);
|
|
590
691
|
let raw;
|
|
591
692
|
try {
|
|
592
693
|
raw = await fs.readFile(claudeJsonPath, "utf8");
|
|
593
694
|
} catch (err) {
|
|
594
|
-
throw new Error(`ensureClaudeConfigMirror: postcondition failed — cannot read ${claudeJsonPath} after injection: ${err.message}
|
|
695
|
+
throw new Error(`ensureClaudeConfigMirror: postcondition failed — cannot read ${claudeJsonPath} after injection: ${err.message}`, { cause: err });
|
|
595
696
|
}
|
|
596
697
|
let parsed;
|
|
597
698
|
try {
|
|
@@ -599,7 +700,7 @@ async function assertOnboardingGateInjected(targetDir) {
|
|
|
599
700
|
if (!json || typeof json !== "object" || Array.isArray(json)) throw new Error(`parsed to non-object (typeof=${typeof json})`);
|
|
600
701
|
parsed = json;
|
|
601
702
|
} catch (err) {
|
|
602
|
-
throw new Error(`ensureClaudeConfigMirror: postcondition failed — ${claudeJsonPath} is not a valid JSON object after injection: ${err.message}
|
|
703
|
+
throw new Error(`ensureClaudeConfigMirror: postcondition failed — ${claudeJsonPath} is not a valid JSON object after injection: ${err.message}`, { cause: err });
|
|
603
704
|
}
|
|
604
705
|
if (parsed.hasCompletedOnboarding !== true || parsed.bypassPermissionsModeAccepted !== true) throw new Error(`ensureClaudeConfigMirror: postcondition failed — ${claudeJsonPath} is missing required gate fields after injection (hasCompletedOnboarding=${String(parsed.hasCompletedOnboarding)}, bypassPermissionsModeAccepted=${String(parsed.bypassPermissionsModeAccepted)}). Check the preceding warn-level log lines for the underlying cause; without these fields Claude Code's first-launch wizard fires and defeats the synthetic credential.`);
|
|
605
706
|
if (!isUsableOauthAccount(parsed.oauthAccount)) throw new Error(`ensureClaudeConfigMirror: postcondition failed — ${claudeJsonPath} has invalid oauthAccount after injection (got ${JSON.stringify(parsed.oauthAccount)}). The synthetic identity blob is required so Claude Code's identity-vs-token cross-checks don't trigger a re-login that defeats the synthetic credential.`);
|
|
@@ -617,7 +718,7 @@ async function assertOnboardingGateInjected(targetDir) {
|
|
|
617
718
|
* - Files copy only if source mtime > target mtime (idempotent).
|
|
618
719
|
*/
|
|
619
720
|
async function mirrorDirRecursive(sourceDir, targetDir, relPath) {
|
|
620
|
-
const sourcePath =
|
|
721
|
+
const sourcePath = path.join(sourceDir, relPath);
|
|
621
722
|
let entries;
|
|
622
723
|
try {
|
|
623
724
|
entries = await fs.readdir(sourcePath);
|
|
@@ -631,10 +732,10 @@ async function mirrorDirRecursive(sourceDir, targetDir, relPath) {
|
|
|
631
732
|
const policy = policyFor(name);
|
|
632
733
|
if (policy === "ISOLATED" || policy === "SHARED") continue;
|
|
633
734
|
}
|
|
634
|
-
const childRel = relPath === "" ? name :
|
|
735
|
+
const childRel = relPath === "" ? name : path.join(relPath, name);
|
|
635
736
|
if (relPath === "agents" && PEER_AGENT_MD_FILENAME.test(name)) continue;
|
|
636
|
-
const childSource =
|
|
637
|
-
const childTarget =
|
|
737
|
+
const childSource = path.join(sourceDir, childRel);
|
|
738
|
+
const childTarget = path.join(targetDir, childRel);
|
|
638
739
|
let stats;
|
|
639
740
|
try {
|
|
640
741
|
stats = await fs.lstat(childSource);
|
|
@@ -698,8 +799,8 @@ async function mirrorDirRecursive(sourceDir, targetDir, relPath) {
|
|
|
698
799
|
* Claude Code's writes through the symlink don't fail with ENOENT.
|
|
699
800
|
*/
|
|
700
801
|
async function ensureSharedSymlink(name, sourceDir, mirrorDir) {
|
|
701
|
-
const sourcePath =
|
|
702
|
-
const mirrorPath =
|
|
802
|
+
const sourcePath = path.join(sourceDir, name);
|
|
803
|
+
const mirrorPath = path.join(mirrorDir, name);
|
|
703
804
|
try {
|
|
704
805
|
await fs.mkdir(sourcePath, { recursive: true });
|
|
705
806
|
} catch (err) {
|
|
@@ -797,7 +898,7 @@ async function writeArtifactCredsToMirror(insecureTLS, env = process.env) {
|
|
|
797
898
|
const token = env.AIORDIE_TOKEN;
|
|
798
899
|
const sessionId = env.AIORDIE_SESSION_ID;
|
|
799
900
|
if (!baseUrl || !token || !sessionId) return;
|
|
800
|
-
const target =
|
|
901
|
+
const target = path.join(PATHS.CLAUDE_CONFIG_DIR, ".aiordie-artifact.json");
|
|
801
902
|
const tempPath = `${target}.${process.pid}.tmp`;
|
|
802
903
|
const body = JSON.stringify({
|
|
803
904
|
baseUrl,
|
|
@@ -848,7 +949,7 @@ async function sweepStaleRuntimeFiles() {
|
|
|
848
949
|
const match = /^peer-(?:mcp|agents)-(\d+)(?:-[0-9a-f]+)?\.json$/.exec(name);
|
|
849
950
|
if (!match) continue;
|
|
850
951
|
const pid = Number.parseInt(match[1], 10);
|
|
851
|
-
const filePath =
|
|
952
|
+
const filePath = path.join(dir, name);
|
|
852
953
|
if (isPidAlive(pid)) continue;
|
|
853
954
|
await fs.unlink(filePath).catch(() => {});
|
|
854
955
|
}
|
|
@@ -899,7 +1000,7 @@ function isPidAlive(pid) {
|
|
|
899
1000
|
* `mirrorDirRecursive`, which skips them so they never register.
|
|
900
1001
|
*/
|
|
901
1002
|
async function sweepStalePeerAgentMdFiles() {
|
|
902
|
-
const dir =
|
|
1003
|
+
const dir = path.join(PATHS.CLAUDE_CONFIG_DIR, "agents");
|
|
903
1004
|
let entries;
|
|
904
1005
|
try {
|
|
905
1006
|
entries = await fs.readdir(dir);
|
|
@@ -911,7 +1012,7 @@ async function sweepStalePeerAgentMdFiles() {
|
|
|
911
1012
|
const match = PEER_AGENT_MD_FILENAME.exec(name);
|
|
912
1013
|
if (!match) continue;
|
|
913
1014
|
if (isPidAlive(Number.parseInt(match[1], 10))) continue;
|
|
914
|
-
await fs.unlink(
|
|
1015
|
+
await fs.unlink(path.join(dir, name)).catch(() => {});
|
|
915
1016
|
}
|
|
916
1017
|
}
|
|
917
1018
|
/**
|
|
@@ -965,7 +1066,7 @@ const CLAUDE_CONFIG_MIRROR_DIR = /^(\d+)-[0-9a-f]{8}$/;
|
|
|
965
1066
|
* Tolerates missing parent dir (first-ever launch, or user wiped it).
|
|
966
1067
|
*/
|
|
967
1068
|
async function sweepStaleClaudeConfigMirrors() {
|
|
968
|
-
const parent =
|
|
1069
|
+
const parent = path.join(appDir(), "claude-config");
|
|
969
1070
|
let entries;
|
|
970
1071
|
try {
|
|
971
1072
|
entries = await fs.readdir(parent);
|
|
@@ -977,7 +1078,7 @@ async function sweepStaleClaudeConfigMirrors() {
|
|
|
977
1078
|
const match = CLAUDE_CONFIG_MIRROR_DIR.exec(name);
|
|
978
1079
|
if (!match) continue;
|
|
979
1080
|
if (isPidAlive(Number.parseInt(match[1], 10))) continue;
|
|
980
|
-
await fs.rm(
|
|
1081
|
+
await fs.rm(path.join(parent, name), {
|
|
981
1082
|
recursive: true,
|
|
982
1083
|
force: true
|
|
983
1084
|
}).catch((err) => {
|
|
@@ -1006,7 +1107,7 @@ async function removeOwnClaudeConfigMirror() {
|
|
|
1006
1107
|
consola.debug(`removeOwnClaudeConfigMirror: rm ${dir} skipped:`, err);
|
|
1007
1108
|
});
|
|
1008
1109
|
}
|
|
1009
|
-
|
|
1010
1110
|
//#endregion
|
|
1011
1111
|
export { isUnderClaudeConfigMirror as a, sweepStalePeerAgentMdFiles as c, writeRuntimeFileSecure as d, ensurePaths as i, sweepStaleRuntimeFiles as l, PEER_AGENT_MD_FILENAME as n, removeOwnClaudeConfigMirror as o, ensureClaudeConfigMirror as r, sweepStaleClaudeConfigMirrors as s, PATHS as t, writeArtifactCredsToMirror as u };
|
|
1012
|
-
|
|
1112
|
+
|
|
1113
|
+
//# sourceMappingURL=paths-BjTMI_xK.js.map
|