@tablation/crew 0.116.0 → 0.117.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/cli.js CHANGED
@@ -125,19 +125,20 @@ function excludeFile(worktree) {
125
125
  return void 0;
126
126
  }
127
127
  }
128
+ function excludeFromGit(worktree, entry) {
129
+ const ex = excludeFile(worktree);
130
+ if (!ex) return;
131
+ mkdirSync(dirname(ex), { recursive: true });
132
+ const have = existsSync2(ex) ? readFileSync(ex, "utf8") : "";
133
+ if (have.split("\n").some((l) => l.trim() === entry)) return;
134
+ appendFileSync(ex, `${have === "" || have.endsWith("\n") ? "" : "\n"}${entry}
135
+ `);
136
+ }
128
137
  function prepareDropFile(worktree) {
129
138
  const file = pointedAtFile(worktree);
130
139
  mkdirSync(dirname(file), { recursive: true });
131
140
  if (!existsSync2(file)) writeFileSync(file, "");
132
- const ex = excludeFile(worktree);
133
- if (ex) {
134
- mkdirSync(dirname(ex), { recursive: true });
135
- const have = existsSync2(ex) ? readFileSync(ex, "utf8") : "";
136
- if (!have.split("\n").some((l) => l.trim() === `${POINTED_AT_DIR}/`)) {
137
- appendFileSync(ex, `${have === "" || have.endsWith("\n") ? "" : "\n"}${POINTED_AT_DIR}/
138
- `);
139
- }
140
- }
141
+ excludeFromGit(worktree, `${POINTED_AT_DIR}/`);
141
142
  return file;
142
143
  }
143
144
  function parseLine(raw) {
@@ -180,15 +181,160 @@ function dropFileMtime(worktree) {
180
181
  }
181
182
  }
182
183
 
184
+ // src/intel-register.ts
185
+ import { execFileSync as execFileSync2 } from "child_process";
186
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
187
+ import { dirname as dirname2, join as join2 } from "path";
188
+
189
+ // src/intel.ts
190
+ var INTEL_MINIMUM_TOOLS = [
191
+ "find symbols by name",
192
+ "references to a symbol",
193
+ "a symbol's definition",
194
+ "a file's symbol outline"
195
+ ];
196
+ var INTEL_SERVER_NAME = "code";
197
+ var lastUrl = (output) => {
198
+ const last = output.split("\n").map((l) => l.trim()).filter(Boolean).pop();
199
+ return last && /^https?:\/\/\S+$/i.test(last) ? last : void 0;
200
+ };
201
+ var oneLine = (s) => s.replace(/\s+/g, " ").trim().slice(0, 200);
202
+ async function rpcResult(res) {
203
+ const text2 = await res.text();
204
+ const body = (res.headers.get("content-type") ?? "").includes("text/event-stream") ? text2.split("\n").find((l) => l.startsWith("data:"))?.slice(5).trim() ?? "" : text2;
205
+ const msg = JSON.parse(body);
206
+ if (msg.error) throw new Error(msg.error.message ?? "MCP error");
207
+ return msg.result;
208
+ }
209
+ async function initializeAndList(url, f, signal) {
210
+ const headers = { "content-type": "application/json", accept: "application/json, text/event-stream" };
211
+ const init = await f(url, {
212
+ method: "POST",
213
+ headers,
214
+ signal,
215
+ body: JSON.stringify({
216
+ jsonrpc: "2.0",
217
+ id: 1,
218
+ method: "initialize",
219
+ params: { protocolVersion: "2025-03-26", capabilities: {}, clientInfo: { name: "crew", version: "0" } }
220
+ })
221
+ });
222
+ if (!init.ok) throw new Error(`initialize answered ${init.status}`);
223
+ await rpcResult(init);
224
+ const session = init.headers.get("mcp-session-id");
225
+ const sessionHeaders = session ? { ...headers, "mcp-session-id": session } : headers;
226
+ await f(url, { method: "POST", headers: sessionHeaders, signal, body: JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" }) }).then((r) => r.body?.cancel()).catch(() => {
227
+ });
228
+ const list = await f(url, { method: "POST", headers: sessionHeaders, signal, body: JSON.stringify({ jsonrpc: "2.0", id: 2, method: "tools/list" }) });
229
+ if (!list.ok) throw new Error(`tools/list answered ${list.status}`);
230
+ const result = await rpcResult(list);
231
+ return (result?.tools ?? []).map((t) => String(t.name)).filter(Boolean);
232
+ }
233
+ async function probeIntel(deps, env, startupSeconds) {
234
+ let ran;
235
+ try {
236
+ ran = await deps.runHook(env);
237
+ } catch (e) {
238
+ return { state: "failed", reason: `the intel hook could not run: ${oneLine(e.message)}` };
239
+ }
240
+ if (!ran) return { state: "absent" };
241
+ if (ran.code !== 0) return { state: "failed", reason: `the intel hook exited ${ran.code}${ran.output.trim() ? `: ${oneLine(ran.output.trim().split("\n").pop() ?? "")}` : ""}` };
242
+ const url = lastUrl(ran.output);
243
+ if (!url) return { state: "failed", reason: "the intel hook printed no URL as its last line" };
244
+ const f = deps.fetch ?? fetch;
245
+ const sleep = deps.sleep ?? ((ms3) => new Promise((r) => setTimeout(r, ms3)));
246
+ const now = deps.now ?? Date.now;
247
+ const deadline = now() + startupSeconds * 1e3;
248
+ let last = "no answer";
249
+ for (; ; ) {
250
+ try {
251
+ const tools = await initializeAndList(url, f, AbortSignal.timeout(Math.max(1, deadline - now())));
252
+ return { state: "ready", url, tools };
253
+ } catch (e) {
254
+ last = oneLine(e.message);
255
+ }
256
+ if (now() >= deadline) break;
257
+ await sleep(500);
258
+ }
259
+ return { state: "failed", reason: `${url} did not answer an MCP initialize within ${startupSeconds}s (${last})` };
260
+ }
261
+ function codeToolsParagraph(outcome, server = INTEL_SERVER_NAME) {
262
+ if (outcome.state === "absent") return "No symbol service is available for this repository.";
263
+ if (outcome.state === "failed") return `The symbol service did not start (${outcome.reason}), so none is available for this run.`;
264
+ return [
265
+ `The \`${server}\` MCP server serves this repository's symbols from its language server. It offers at least: ${INTEL_MINIMUM_TOOLS.join("; ")}.`,
266
+ `Tools it advertised: ${outcome.tools.length ? outcome.tools.map((t) => `\`${t}\``).join(", ") : "(none listed)"}.`
267
+ ].join(" ");
268
+ }
269
+
270
+ // src/intel-register.ts
271
+ function mergeJsonServer(existing, entry, server) {
272
+ let doc = {};
273
+ if (existing !== void 0 && existing.trim() !== "") {
274
+ const parsed = JSON.parse(existing);
275
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("is not a JSON object");
276
+ doc = parsed;
277
+ }
278
+ const servers = doc.mcpServers;
279
+ if (servers !== void 0 && (!servers || typeof servers !== "object" || Array.isArray(servers))) throw new Error("has an mcpServers that is not an object");
280
+ doc.mcpServers = { ...servers, [server]: entry };
281
+ return `${JSON.stringify(doc, null, 2)}
282
+ `;
283
+ }
284
+ function mergeTomlServer(existing, url, server) {
285
+ const table2 = `[mcp_servers.${server}]
286
+ url = ${JSON.stringify(url)}
287
+ `;
288
+ const text2 = existing ?? "";
289
+ const lines2 = text2.split("\n");
290
+ const start = lines2.findIndex((l) => l.trim() === `[mcp_servers.${server}]`);
291
+ if (start < 0) return text2 === "" ? table2 : `${text2}${text2.endsWith("\n") ? "" : "\n"}
292
+ ${table2}`;
293
+ let end = lines2.findIndex((l, i) => i > start && /^\s*\[/.test(l));
294
+ if (end < 0) end = lines2.length;
295
+ const keepTail = lines2.slice(end);
296
+ return [...lines2.slice(0, start), ...table2.trimEnd().split("\n"), ...keepTail.length && keepTail[0] !== "" ? [""] : [], ...keepTail].join("\n");
297
+ }
298
+ function tracked(worktree, rel) {
299
+ try {
300
+ execFileSync2("git", ["ls-files", "--error-unmatch", "--", rel], { cwd: worktree, stdio: "ignore" });
301
+ return true;
302
+ } catch {
303
+ return false;
304
+ }
305
+ }
306
+ function registerCodeServer(worktree, url, server = INTEL_SERVER_NAME) {
307
+ const out = { written: [], skipped: [] };
308
+ const plans = [
309
+ [".mcp.json", (old) => mergeJsonServer(old, { type: "http", url }, server)],
310
+ [".codex/config.toml", (old) => mergeTomlServer(old, url, server)],
311
+ [".gemini/settings.json", (old) => mergeJsonServer(old, { httpUrl: url }, server)]
312
+ ];
313
+ for (const [rel, merge] of plans) {
314
+ const file = join2(worktree, rel);
315
+ try {
316
+ const next = merge(existsSync3(file) ? readFileSync2(file, "utf8") : void 0);
317
+ mkdirSync2(dirname2(file), { recursive: true });
318
+ writeFileSync2(file, next);
319
+ if (tracked(worktree, rel)) execFileSync2("git", ["update-index", "--skip-worktree", "--", rel], { cwd: worktree, stdio: "ignore" });
320
+ else excludeFromGit(worktree, rel);
321
+ out.written.push(rel);
322
+ } catch (e) {
323
+ out.skipped.push(`${rel} left alone: ${e.message}`);
324
+ }
325
+ }
326
+ return out;
327
+ }
328
+
183
329
  // src/periscope-state.ts
184
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, rmSync, writeFileSync as writeFileSync2 } from "fs";
330
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync, readFileSync as readFileSync3, rmSync, writeFileSync as writeFileSync3 } from "fs";
185
331
  import { connect } from "net";
186
- import { join as join2 } from "path";
187
- var dirOf = (stateDir) => join2(stateDir, "periscopes");
188
- var fileOf = (stateDir, ticketRecordId) => join2(dirOf(stateDir), `${ticketRecordId}.json`);
332
+ import { join as join3 } from "path";
333
+ var dirOf = (stateDir) => join3(stateDir, "periscopes");
334
+ var fileOf = (stateDir, ticketRecordId) => join3(dirOf(stateDir), `${ticketRecordId}.json`);
189
335
  function writePeriscopeSidecar(stateDir, sc) {
190
- mkdirSync2(dirOf(stateDir), { recursive: true });
191
- writeFileSync2(fileOf(stateDir, sc.ticketRecordId), `${JSON.stringify(sc, null, 2)}
336
+ mkdirSync3(dirOf(stateDir), { recursive: true });
337
+ writeFileSync3(fileOf(stateDir, sc.ticketRecordId), `${JSON.stringify(sc, null, 2)}
192
338
  `);
193
339
  }
194
340
  function removePeriscopeSidecar(stateDir, ticketRecordId) {
@@ -196,12 +342,12 @@ function removePeriscopeSidecar(stateDir, ticketRecordId) {
196
342
  }
197
343
  function readPeriscopeSidecars(stateDir) {
198
344
  const dir = dirOf(stateDir);
199
- if (!existsSync3(dir)) return [];
345
+ if (!existsSync4(dir)) return [];
200
346
  const out = [];
201
347
  for (const name of readdirSync(dir)) {
202
348
  if (!name.endsWith(".json")) continue;
203
349
  try {
204
- const sc = JSON.parse(readFileSync2(join2(dir, name), "utf8"));
350
+ const sc = JSON.parse(readFileSync3(join3(dir, name), "utf8"));
205
351
  if (sc && typeof sc.ticketRecordId === "string" && typeof sc.url === "string") out.push(sc);
206
352
  } catch {
207
353
  }
@@ -319,23 +465,23 @@ function shellInitScript(shell) {
319
465
  }
320
466
 
321
467
  // src/config.ts
322
- import { readFileSync as readFileSync12, existsSync as existsSync11 } from "fs";
323
- import { resolve as resolve2, dirname as dirname5, isAbsolute as isAbsolute2, join as join13, basename as basename4 } from "path";
468
+ import { readFileSync as readFileSync13, existsSync as existsSync12 } from "fs";
469
+ import { resolve as resolve2, dirname as dirname6, isAbsolute as isAbsolute2, join as join14, basename as basename4 } from "path";
324
470
  import { homedir as homedir6, tmpdir } from "os";
325
471
  import { parse as parse2 } from "yaml";
326
472
 
327
473
  // src/events.ts
328
474
  import {
329
475
  appendFileSync as appendFileSync2,
330
- mkdirSync as mkdirSync3,
331
- existsSync as existsSync4,
476
+ mkdirSync as mkdirSync4,
477
+ existsSync as existsSync5,
332
478
  statSync as statSync2,
333
479
  renameSync,
334
480
  openSync,
335
481
  closeSync,
336
482
  rmSync as rmSync2
337
483
  } from "fs";
338
- import { join as join3, dirname as dirname2 } from "path";
484
+ import { join as join4, dirname as dirname3 } from "path";
339
485
  function render(e) {
340
486
  const scope = e.role ? `${e.step}[${e.role}]` : e.step;
341
487
  const ticket = e.ticket ? ` ${e.ticket}` : "";
@@ -347,7 +493,7 @@ var ROTATED_EVENTS_RE = /^events\.\d{8}T\d{6}Z(?:-\d+)?\.jsonl$/;
347
493
  var ROTATE_LOCK_STALE_MS = 6e4;
348
494
  function rotateEventsFile(file, maxBytes, now = /* @__PURE__ */ new Date()) {
349
495
  try {
350
- if (!existsSync4(file) || statSync2(file).size <= maxBytes) return void 0;
496
+ if (!existsSync5(file) || statSync2(file).size <= maxBytes) return void 0;
351
497
  } catch {
352
498
  return void 0;
353
499
  }
@@ -367,8 +513,8 @@ function rotateEventsFile(file, maxBytes, now = /* @__PURE__ */ new Date()) {
367
513
  try {
368
514
  if (statSync2(file).size <= maxBytes) return void 0;
369
515
  const stamp = now.toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "Z");
370
- let dest = join3(dirname2(file), `events.${stamp}.jsonl`);
371
- for (let n = 1; existsSync4(dest); n++) dest = join3(dirname2(file), `events.${stamp}-${n}.jsonl`);
516
+ let dest = join4(dirname3(file), `events.${stamp}.jsonl`);
517
+ for (let n = 1; existsSync5(dest); n++) dest = join4(dirname3(file), `events.${stamp}-${n}.jsonl`);
372
518
  renameSync(file, dest);
373
519
  return dest;
374
520
  } finally {
@@ -391,7 +537,7 @@ var Emitter = class _Emitter {
391
537
  for (const f of [opts.eventFile, opts.logFile]) {
392
538
  if (!f) continue;
393
539
  try {
394
- mkdirSync3(dirname2(f), { recursive: true });
540
+ mkdirSync4(dirname3(f), { recursive: true });
395
541
  } catch {
396
542
  }
397
543
  }
@@ -467,18 +613,18 @@ var Emitter = class _Emitter {
467
613
  }
468
614
  }
469
615
  };
470
- var eventFileFor = (stateDir) => join3(stateDir, "events.jsonl");
616
+ var eventFileFor = (stateDir) => join4(stateDir, "events.jsonl");
471
617
 
472
618
  // src/pair-install.ts
473
- import { existsSync as existsSync7, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
619
+ import { existsSync as existsSync8, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "fs";
474
620
  import { spawnSync as spawnSync3 } from "child_process";
475
621
  import { homedir as homedir5 } from "os";
476
- import { join as join9 } from "path";
622
+ import { join as join10 } from "path";
477
623
 
478
624
  // src/adapters/claude.ts
479
- import { readFileSync as readFileSync7 } from "fs";
625
+ import { readFileSync as readFileSync8 } from "fs";
480
626
  import { homedir as homedir3 } from "os";
481
- import { join as join7 } from "path";
627
+ import { join as join8 } from "path";
482
628
 
483
629
  // src/stream.ts
484
630
  function toolTarget(name, input) {
@@ -537,19 +683,19 @@ function extractResult(line) {
537
683
 
538
684
  // src/claude-mcp.ts
539
685
  import { spawnSync } from "child_process";
540
- import { readFileSync as readFileSync5 } from "fs";
686
+ import { readFileSync as readFileSync6 } from "fs";
541
687
  import { homedir } from "os";
542
- import { join as join5 } from "path";
688
+ import { join as join6 } from "path";
543
689
 
544
690
  // src/mcp-registrations.ts
545
691
  import { createHash } from "crypto";
546
- import { mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
547
- import { join as join4 } from "path";
548
- var fileFor = (stateDir) => join4(stateDir, "mcp-registrations.json");
692
+ import { mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
693
+ import { join as join5 } from "path";
694
+ var fileFor = (stateDir) => join5(stateDir, "mcp-registrations.json");
549
695
  var keyFingerprint = (key) => createHash("sha256").update(key).digest("hex").slice(0, 8);
550
696
  function readMcpRegistrations(stateDir) {
551
697
  try {
552
- const j = JSON.parse(readFileSync4(fileFor(stateDir), "utf8"));
698
+ const j = JSON.parse(readFileSync5(fileFor(stateDir), "utf8"));
553
699
  return Array.isArray(j) ? j : [];
554
700
  } catch {
555
701
  return [];
@@ -557,8 +703,8 @@ function readMcpRegistrations(stateDir) {
557
703
  }
558
704
  function recordMcpRegistration(stateDir, r, now = /* @__PURE__ */ new Date()) {
559
705
  const rest = readMcpRegistrations(stateDir).filter((x) => !(x.harness === r.harness && x.scope === r.scope && x.name === r.name));
560
- mkdirSync4(stateDir, { recursive: true });
561
- writeFileSync3(fileFor(stateDir), `${JSON.stringify([...rest, { ...r, at: now.toISOString() }], null, 2)}
706
+ mkdirSync5(stateDir, { recursive: true });
707
+ writeFileSync4(fileFor(stateDir), `${JSON.stringify([...rest, { ...r, at: now.toISOString() }], null, 2)}
562
708
  `, { mode: 384 });
563
709
  }
564
710
  function findMcpRegistration(stateDir, r) {
@@ -581,7 +727,7 @@ function runClaude(bin, args) {
581
727
  }
582
728
  function userScopeEntry(home) {
583
729
  try {
584
- const j = JSON.parse(readFileSync5(join5(home, ".claude.json"), "utf8"));
730
+ const j = JSON.parse(readFileSync6(join6(home, ".claude.json"), "utf8"));
585
731
  return j.mcpServers?.[MCP_SERVER_NAME];
586
732
  } catch {
587
733
  return void 0;
@@ -665,8 +811,8 @@ function removeClaudeMcp(o) {
665
811
  }
666
812
 
667
813
  // src/launcher.ts
668
- import { basename, join as join6 } from "path";
669
- import { existsSync as existsSync5, readFileSync as readFileSync6, readdirSync as readdirSync2 } from "fs";
814
+ import { basename, join as join7 } from "path";
815
+ import { existsSync as existsSync6, readFileSync as readFileSync7, readdirSync as readdirSync2 } from "fs";
670
816
  import { homedir as homedir2 } from "os";
671
817
  function isOriLauncher(spec) {
672
818
  return !!spec.launcher && basename(spec.launcher) === "ori";
@@ -675,7 +821,7 @@ function isOmlxLauncher(spec) {
675
821
  return !!spec.launcher && basename(spec.launcher) === "omlx";
676
822
  }
677
823
  function defaultOmlxBin(home = homedir2()) {
678
- return join6(home, ".omlx", "bin", "omlx");
824
+ return join7(home, ".omlx", "bin", "omlx");
679
825
  }
680
826
  function launcherExecutable(spec, home) {
681
827
  if (!spec.launcher) return void 0;
@@ -728,8 +874,8 @@ function omlxModelPresent(model, dirs) {
728
874
  });
729
875
  }
730
876
  function readOmlxSettings(home = homedir2()) {
731
- const p = join6(home, ".omlx", "settings.json");
732
- return existsSync5(p) ? parseOmlxSettings(readFileSync6(p, "utf8")) : void 0;
877
+ const p = join7(home, ".omlx", "settings.json");
878
+ return existsSync6(p) ? parseOmlxSettings(readFileSync7(p, "utf8")) : void 0;
733
879
  }
734
880
 
735
881
  // src/capability.ts
@@ -793,7 +939,7 @@ function describeClaudeAuth(spec, env = process.env, home = homedir3()) {
793
939
  if (spec.auth === "workspace") return `workspace${spec.inference ? ` (${new URL(spec.inference.baseUrl).host})` : " (endpoint resolved per route at run time)"}`;
794
940
  let fromSettings;
795
941
  try {
796
- const parsed = JSON.parse(readFileSync7(join7(home, ".claude", "settings.json"), "utf8"));
942
+ const parsed = JSON.parse(readFileSync8(join8(home, ".claude", "settings.json"), "utf8"));
797
943
  const e = parsed.env ?? {};
798
944
  const on = (k) => e[k] !== void 0 && e[k] !== "" && e[k] !== "0";
799
945
  if (on("CLAUDE_CODE_USE_VERTEX")) fromSettings = "vertex from ~/.claude/settings.json";
@@ -897,12 +1043,12 @@ var claudeAdapter = {
897
1043
  // src/adapters/codex.ts
898
1044
  import { spawnSync as spawnSync2 } from "child_process";
899
1045
  import { homedir as homedir4 } from "os";
900
- import { join as join8 } from "path";
901
- import { rmSync as rmSync4, writeFileSync as writeFileSync5 } from "fs";
1046
+ import { join as join9 } from "path";
1047
+ import { rmSync as rmSync4, writeFileSync as writeFileSync6 } from "fs";
902
1048
 
903
1049
  // src/pair-files.ts
904
- import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync4, rmSync as rmSync3 } from "fs";
905
- import { dirname as dirname3 } from "path";
1050
+ import { existsSync as existsSync7, mkdirSync as mkdirSync6, readFileSync as readFileSync9, writeFileSync as writeFileSync5, rmSync as rmSync3 } from "fs";
1051
+ import { dirname as dirname4 } from "path";
906
1052
  var PAIR_BLOCK_START = "<!-- crew:pair start -->";
907
1053
  var PAIR_BLOCK_END = "<!-- crew:pair end -->";
908
1054
  var PAIR_KEY_VAR = "CREW_API_KEY";
@@ -942,11 +1088,11 @@ function removePairBlock(text2) {
942
1088
  return text2.replace(new RegExp(`\\n*${BLOCK_RE.source}`), "\n").replace(/^\n+/, "").replace(/\n{3,}/g, "\n\n");
943
1089
  }
944
1090
  function readIfExists(path) {
945
- return existsSync6(path) ? readFileSync8(path, "utf8") : void 0;
1091
+ return existsSync7(path) ? readFileSync9(path, "utf8") : void 0;
946
1092
  }
947
1093
  function writeFileMkdir(path, text2) {
948
- mkdirSync5(dirname3(path), { recursive: true });
949
- writeFileSync4(path, text2);
1094
+ mkdirSync6(dirname4(path), { recursive: true });
1095
+ writeFileSync5(path, text2);
950
1096
  }
951
1097
  function installBlockFile(path, harness, dryRun) {
952
1098
  const before = readIfExists(path) ?? "";
@@ -962,7 +1108,7 @@ function removeBlockFile(path, dryRun) {
962
1108
  if (dryRun) return true;
963
1109
  const after = removePairBlock(before);
964
1110
  if (after.trim() === "") rmSync3(path);
965
- else writeFileSync4(path, after);
1111
+ else writeFileSync5(path, after);
966
1112
  return true;
967
1113
  }
968
1114
  function blockVerdict(path, harness) {
@@ -1089,8 +1235,8 @@ function codexTable(url) {
1089
1235
  return [`[mcp_servers.${SERVER}]`, `url = ${tomlString(url)}`, `bearer_token_env_var = ${tomlString(PAIR_KEY_VAR)}`];
1090
1236
  }
1091
1237
  var codexPaths = (home) => ({
1092
- instructions: join8(home, ".codex", "AGENTS.md"),
1093
- config: join8(home, ".codex", "config.toml")
1238
+ instructions: join9(home, ".codex", "AGENTS.md"),
1239
+ config: join9(home, ".codex", "config.toml")
1094
1240
  });
1095
1241
  function codexMcpState(config, url) {
1096
1242
  const lines2 = config.split("\n");
@@ -1141,7 +1287,7 @@ var codexPair = {
1141
1287
  if (hadMcp && !o.dryRun) {
1142
1288
  const after = removeTomlTable(config, `mcp_servers.${SERVER}`);
1143
1289
  if (after === "") rmSync4(p.config);
1144
- else writeFileSync5(p.config, after);
1290
+ else writeFileSync6(p.config, after);
1145
1291
  }
1146
1292
  const what = hadBlock && hadMcp ? `the Pair block and ${SERVER} server` : hadBlock ? "the Pair block" : `the ${SERVER} server`;
1147
1293
  return hadBlock || hadMcp ? `pair(codex): ${o.dryRun ? "(dry run) would remove" : "removed"} ${what}${kept}` : `pair(codex): nothing to remove${kept}`;
@@ -1237,8 +1383,8 @@ var codexAdapter = {
1237
1383
 
1238
1384
  // src/pair-install.ts
1239
1385
  var geminiPaths = (home) => ({
1240
- instructions: join9(home, ".gemini", "GEMINI.md"),
1241
- config: join9(home, ".gemini", "settings.json")
1386
+ instructions: join10(home, ".gemini", "GEMINI.md"),
1387
+ config: join10(home, ".gemini", "settings.json")
1242
1388
  });
1243
1389
  function readGeminiSettings(path) {
1244
1390
  const text2 = readIfExists(path);
@@ -1326,7 +1472,7 @@ var geminiPair = {
1326
1472
  if (Object.keys(rest).length > 0) next.mcpServers = rest;
1327
1473
  else delete next.mcpServers;
1328
1474
  if (Object.keys(next).length === 0) rmSync5(p.config);
1329
- else writeFileSync6(p.config, `${JSON.stringify(next, null, 2)}
1475
+ else writeFileSync7(p.config, `${JSON.stringify(next, null, 2)}
1330
1476
  `);
1331
1477
  }
1332
1478
  const what = hadBlock && hadMcp ? `the Pair block and ${SERVER} server` : hadBlock ? "the Pair block" : `the ${SERVER} server`;
@@ -1337,9 +1483,9 @@ var VSCODE_FLAVOURS = ["Code", "Code - Insiders"];
1337
1483
  function vscodeUserDirs(o) {
1338
1484
  const home = o.home ?? homedir5();
1339
1485
  const platform2 = o.platform ?? process.platform;
1340
- const root = platform2 === "darwin" ? join9(home, "Library", "Application Support") : platform2 === "win32" ? process.env.APPDATA ?? join9(home, "AppData", "Roaming") : join9(home, ".config");
1341
- const all = VSCODE_FLAVOURS.map((f) => join9(root, f, "User"));
1342
- const present = all.filter((d) => existsSync7(d));
1486
+ const root = platform2 === "darwin" ? join10(home, "Library", "Application Support") : platform2 === "win32" ? process.env.APPDATA ?? join10(home, "AppData", "Roaming") : join10(home, ".config");
1487
+ const all = VSCODE_FLAVOURS.map((f) => join10(root, f, "User"));
1488
+ const present = all.filter((d) => existsSync8(d));
1343
1489
  return present.length > 0 ? present : [all[0]];
1344
1490
  }
1345
1491
  var COPILOT_FRONTMATTER = '---\napplyTo: "**"\n---\n\n';
@@ -1377,7 +1523,7 @@ function removeCopilotInstructions(path, dryRun) {
1377
1523
  if (dryRun) return true;
1378
1524
  const after = removePairBlock(before);
1379
1525
  if (after.trim() === "" || after.trim() === COPILOT_FRONTMATTER.trim()) rmSync5(path);
1380
- else writeFileSync6(path, after);
1526
+ else writeFileSync7(path, after);
1381
1527
  return true;
1382
1528
  }
1383
1529
  var copilotPair = {
@@ -1386,8 +1532,8 @@ var copilotPair = {
1386
1532
  installPair(o) {
1387
1533
  const lines2 = [];
1388
1534
  for (const dir of vscodeUserDirs(o)) {
1389
- const mcpPath = join9(dir, "mcp.json");
1390
- const instrPath = join9(dir, "prompts", "crew-pair.instructions.md");
1535
+ const mcpPath = join10(dir, "mcp.json");
1536
+ const instrPath = join10(dir, "prompts", "crew-pair.instructions.md");
1391
1537
  const settings = readVscodeMcp(mcpPath);
1392
1538
  if (!settings) {
1393
1539
  lines2.push(`pair(copilot): ${mcpPath} is not a plain JSON object (comments are not supported) \u2014 fix it by hand; nothing was written there`);
@@ -1415,8 +1561,8 @@ var copilotPair = {
1415
1561
  },
1416
1562
  verifyPair(o) {
1417
1563
  const verdicts = vscodeUserDirs(o).map((dir) => {
1418
- const instrPath = join9(dir, "prompts", "crew-pair.instructions.md");
1419
- const mcpPath = join9(dir, "mcp.json");
1564
+ const instrPath = join10(dir, "prompts", "crew-pair.instructions.md");
1565
+ const mcpPath = join10(dir, "mcp.json");
1420
1566
  const b = blockVerdict(instrPath, "copilot");
1421
1567
  if (!b.ok) return b;
1422
1568
  const settings = readVscodeMcp(mcpPath);
@@ -1431,8 +1577,8 @@ var copilotPair = {
1431
1577
  removePair(o) {
1432
1578
  const lines2 = [];
1433
1579
  for (const dir of vscodeUserDirs(o)) {
1434
- const mcpPath = join9(dir, "mcp.json");
1435
- const hadBlock = removeCopilotInstructions(join9(dir, "prompts", "crew-pair.instructions.md"), o.dryRun);
1580
+ const mcpPath = join10(dir, "mcp.json");
1581
+ const hadBlock = removeCopilotInstructions(join10(dir, "prompts", "crew-pair.instructions.md"), o.dryRun);
1436
1582
  const settings = readVscodeMcp(mcpPath);
1437
1583
  const st = settings ? copilotMcpState(settings, o.url) : { state: "missing" };
1438
1584
  const hadMcp = st.state === "registered";
@@ -1443,7 +1589,7 @@ var copilotPair = {
1443
1589
  if (Object.keys(rest).length > 0) next.servers = rest;
1444
1590
  else delete next.servers;
1445
1591
  if (Object.keys(next).length === 0) rmSync5(mcpPath);
1446
- else writeFileSync6(mcpPath, `${JSON.stringify(next, null, 2)}
1592
+ else writeFileSync7(mcpPath, `${JSON.stringify(next, null, 2)}
1447
1593
  `);
1448
1594
  }
1449
1595
  const what = hadBlock && hadMcp ? `the Pair instructions and ${SERVER} server` : hadBlock ? "the Pair instructions" : `the ${SERVER} server`;
@@ -1692,9 +1838,9 @@ function resolveSeat(ship, route2, role, persona = {}, repo) {
1692
1838
  }
1693
1839
 
1694
1840
  // src/forges.ts
1695
- import { execFileSync as execFileSync2 } from "child_process";
1696
- import { chmodSync, existsSync as existsSync8, mkdirSync as mkdirSync6, readFileSync as readFileSync9, rmSync as rmSync6, statSync as statSync3, writeFileSync as writeFileSync7 } from "fs";
1697
- import { dirname as dirname4, join as join10 } from "path";
1841
+ import { execFileSync as execFileSync3 } from "child_process";
1842
+ import { chmodSync, existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync10, rmSync as rmSync6, statSync as statSync3, writeFileSync as writeFileSync8 } from "fs";
1843
+ import { dirname as dirname5, join as join11 } from "path";
1698
1844
  var ForgeError = class extends Error {
1699
1845
  };
1700
1846
  var DEFAULT_FORGE_USERNAME = "x-access-token";
@@ -1722,7 +1868,7 @@ function forgeDescriptorFor(host) {
1722
1868
  }
1723
1869
  var DEFAULT_KEYCHAIN_SERVICE = "crew-forge";
1724
1870
  function defaultTokenFilePath(stateDir, host) {
1725
- return join10(stateDir, "forges", `${host.replace(/[^a-z0-9.-]/gi, "_")}.token`);
1871
+ return join11(stateDir, "forges", `${host.replace(/[^a-z0-9.-]/gi, "_")}.token`);
1726
1872
  }
1727
1873
  var envSource = {
1728
1874
  read: (s, c) => c.env[s.var]?.trim() || null,
@@ -1731,19 +1877,19 @@ var envSource = {
1731
1877
  var fileSource = {
1732
1878
  read(s, c) {
1733
1879
  const path = s.path ?? defaultTokenFilePath(c.stateDir, c.host);
1734
- if (!existsSync8(path)) return null;
1880
+ if (!existsSync9(path)) return null;
1735
1881
  const mode = statSync3(path).mode & 511;
1736
1882
  if (mode & 63) {
1737
1883
  throw new ForgeError(
1738
1884
  `${path} is mode ${mode.toString(8).padStart(3, "0")}; a forge token file must be owner-only (chmod 600 ${path})`
1739
1885
  );
1740
1886
  }
1741
- return readFileSync9(path, "utf8").trim() || null;
1887
+ return readFileSync10(path, "utf8").trim() || null;
1742
1888
  },
1743
1889
  write(s, token, c) {
1744
1890
  const path = s.path ?? defaultTokenFilePath(c.stateDir, c.host);
1745
- mkdirSync6(dirname4(path), { recursive: true, mode: 448 });
1746
- writeFileSync7(path, `${token}
1891
+ mkdirSync7(dirname5(path), { recursive: true, mode: 448 });
1892
+ writeFileSync8(path, `${token}
1747
1893
  `, { mode: 384 });
1748
1894
  chmodSync(path, 384);
1749
1895
  },
@@ -1757,13 +1903,13 @@ var keychainSource = {
1757
1903
  read(s, c) {
1758
1904
  try {
1759
1905
  if (process.platform === "darwin") {
1760
- return execFileSync2(
1906
+ return execFileSync3(
1761
1907
  "security",
1762
1908
  ["find-generic-password", "-s", keychainService(s), "-a", c.host, "-w"],
1763
1909
  { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }
1764
1910
  ).trim() || null;
1765
1911
  }
1766
- return execFileSync2(
1912
+ return execFileSync3(
1767
1913
  "secret-tool",
1768
1914
  ["lookup", "service", keychainService(s), "account", c.host],
1769
1915
  { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }
@@ -1776,13 +1922,13 @@ var keychainSource = {
1776
1922
  try {
1777
1923
  if (process.platform === "darwin") {
1778
1924
  const q2 = (v) => `"${v.replace(/(["\\])/g, "\\$1")}"`;
1779
- execFileSync2("security", ["-i"], {
1925
+ execFileSync3("security", ["-i"], {
1780
1926
  input: `add-generic-password -U -s ${q2(keychainService(s))} -a ${q2(c.host)} -w ${q2(token)}
1781
1927
  `,
1782
1928
  stdio: ["pipe", "ignore", "pipe"]
1783
1929
  });
1784
1930
  } else {
1785
- execFileSync2(
1931
+ execFileSync3(
1786
1932
  "secret-tool",
1787
1933
  ["store", "--label", `crew ${c.host}`, "service", keychainService(s), "account", c.host],
1788
1934
  { input: token, stdio: ["pipe", "ignore", "pipe"] }
@@ -1795,9 +1941,9 @@ var keychainSource = {
1795
1941
  erase(s, c) {
1796
1942
  try {
1797
1943
  if (process.platform === "darwin") {
1798
- execFileSync2("security", ["delete-generic-password", "-s", keychainService(s), "-a", c.host], { stdio: "ignore" });
1944
+ execFileSync3("security", ["delete-generic-password", "-s", keychainService(s), "-a", c.host], { stdio: "ignore" });
1799
1945
  } else {
1800
- execFileSync2("secret-tool", ["clear", "service", keychainService(s), "account", c.host], { stdio: "ignore" });
1946
+ execFileSync3("secret-tool", ["clear", "service", keychainService(s), "account", c.host], { stdio: "ignore" });
1801
1947
  }
1802
1948
  } catch {
1803
1949
  }
@@ -1877,10 +2023,10 @@ function answerCredential(action, input, forges, stateDir, env = process.env) {
1877
2023
  password=${token}
1878
2024
  `;
1879
2025
  }
1880
- var missesPath = (stateDir) => join10(stateDir, "forge-misses.json");
2026
+ var missesPath = (stateDir) => join11(stateDir, "forge-misses.json");
1881
2027
  function readForgeMisses(stateDir) {
1882
2028
  try {
1883
- const raw = JSON.parse(readFileSync9(missesPath(stateDir), "utf8"));
2029
+ const raw = JSON.parse(readFileSync10(missesPath(stateDir), "utf8"));
1884
2030
  return Object.entries(raw).filter(([, t]) => typeof t === "string").map(([host, lastMissAt]) => ({ host, lastMissAt })).sort((a, b) => a.host.localeCompare(b.host));
1885
2031
  } catch {
1886
2032
  return [];
@@ -1895,8 +2041,8 @@ function noteForgeMiss(stateDir, host, at) {
1895
2041
  if (!(bare in cur)) return;
1896
2042
  delete cur[bare];
1897
2043
  } else cur[bare] = at;
1898
- mkdirSync6(stateDir, { recursive: true });
1899
- writeFileSync7(missesPath(stateDir), JSON.stringify(cur), { mode: 384 });
2044
+ mkdirSync7(stateDir, { recursive: true });
2045
+ writeFileSync8(missesPath(stateDir), JSON.stringify(cur), { mode: 384 });
1900
2046
  } catch {
1901
2047
  }
1902
2048
  }
@@ -1998,8 +2144,8 @@ import { hostFromUrl } from "@tablation/client";
1998
2144
 
1999
2145
  // src/secret-store.ts
2000
2146
  import { createHash as createHash2 } from "crypto";
2001
- import { accessSync, constants, existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync10, renameSync as renameSync2, rmSync as rmSync7, statSync as statSync4, writeFileSync as writeFileSync8, chmodSync as chmodSync2 } from "fs";
2002
- import { join as join11 } from "path";
2147
+ import { accessSync, constants, existsSync as existsSync10, mkdirSync as mkdirSync8, readFileSync as readFileSync11, renameSync as renameSync2, rmSync as rmSync7, statSync as statSync4, writeFileSync as writeFileSync9, chmodSync as chmodSync2 } from "fs";
2148
+ import { join as join12 } from "path";
2003
2149
  import { getSessionStore as getOsSessionStore } from "@tablation/client";
2004
2150
  var SECRET_STORE_MODES = ["auto", "os", "file"];
2005
2151
  function isSecretStoreMode(v) {
@@ -2010,7 +2156,7 @@ function configureSecretStore(c) {
2010
2156
  configured = c;
2011
2157
  }
2012
2158
  function keysDir(stateDir) {
2013
- return join11(stateDir, "keys");
2159
+ return join12(stateDir, "keys");
2014
2160
  }
2015
2161
  function entryName(host, slug2) {
2016
2162
  return `${createHash2("sha256").update(`${host}\0${slug2}`).digest("hex")}.json`;
@@ -2021,34 +2167,34 @@ var FileSessionStore = class {
2021
2167
  this.dir = dir;
2022
2168
  }
2023
2169
  ensureDir() {
2024
- mkdirSync7(this.dir, { recursive: true, mode: 448 });
2170
+ mkdirSync8(this.dir, { recursive: true, mode: 448 });
2025
2171
  if ((statSync4(this.dir).mode & 63) !== 0) chmodSync2(this.dir, 448);
2026
2172
  }
2027
2173
  async get(host, slug2) {
2028
- const file = join11(this.dir, entryName(host, slug2));
2029
- if (!existsSync9(this.dir)) return void 0;
2174
+ const file = join12(this.dir, entryName(host, slug2));
2175
+ if (!existsSync10(this.dir)) return void 0;
2030
2176
  accessSync(this.dir, constants.R_OK | constants.X_OK);
2031
- if (!existsSync9(file)) return void 0;
2032
- return JSON.parse(readFileSync10(file, "utf8"));
2177
+ if (!existsSync10(file)) return void 0;
2178
+ return JSON.parse(readFileSync11(file, "utf8"));
2033
2179
  }
2034
2180
  async set(host, slug2, session) {
2035
2181
  this.ensureDir();
2036
- const file = join11(this.dir, entryName(host, slug2));
2182
+ const file = join12(this.dir, entryName(host, slug2));
2037
2183
  const tmp = `${file}.${process.pid}.tmp`;
2038
- writeFileSync8(tmp, JSON.stringify(session), { mode: 384 });
2184
+ writeFileSync9(tmp, JSON.stringify(session), { mode: 384 });
2039
2185
  renameSync2(tmp, file);
2040
2186
  }
2041
2187
  async clear(host, slug2) {
2042
- if (!existsSync9(this.dir)) return;
2043
- rmSync7(join11(this.dir, entryName(host, slug2)), { force: true });
2188
+ if (!existsSync10(this.dir)) return;
2189
+ rmSync7(join12(this.dir, entryName(host, slug2)), { force: true });
2044
2190
  }
2045
2191
  /** Whether a key could be written here right now, without leaving anything behind. */
2046
2192
  writable() {
2047
2193
  try {
2048
2194
  this.ensureDir();
2049
2195
  accessSync(this.dir, constants.R_OK | constants.W_OK | constants.X_OK);
2050
- const probe = join11(this.dir, `.probe.${process.pid}`);
2051
- writeFileSync8(probe, "", { mode: 384 });
2196
+ const probe = join12(this.dir, `.probe.${process.pid}`);
2197
+ writeFileSync9(probe, "", { mode: 384 });
2052
2198
  rmSync7(probe, { force: true });
2053
2199
  return { ok: true };
2054
2200
  } catch (e) {
@@ -2099,11 +2245,11 @@ function osStoreReachable(env = process.env, platform2 = process.platform, hasBi
2099
2245
  if (platform2 !== "linux") return true;
2100
2246
  if (!hasBinary("secret-tool")) return false;
2101
2247
  if (env.DBUS_SESSION_BUS_ADDRESS) return true;
2102
- return !!env.XDG_RUNTIME_DIR && existsSync9(join11(env.XDG_RUNTIME_DIR, "bus"));
2248
+ return !!env.XDG_RUNTIME_DIR && existsSync10(join12(env.XDG_RUNTIME_DIR, "bus"));
2103
2249
  }
2104
2250
  function onPath(name) {
2105
2251
  for (const dir of (process.env.PATH ?? "").split(":")) {
2106
- if (dir && existsSync9(join11(dir, name))) return true;
2252
+ if (dir && existsSync10(join12(dir, name))) return true;
2107
2253
  }
2108
2254
  return false;
2109
2255
  }
@@ -2170,8 +2316,8 @@ function explain(ship, required) {
2170
2316
  }
2171
2317
 
2172
2318
  // src/repo-config.ts
2173
- import { readFileSync as readFileSync11, existsSync as existsSync10 } from "fs";
2174
- import { join as join12, basename as basename3 } from "path";
2319
+ import { readFileSync as readFileSync12, existsSync as existsSync11 } from "fs";
2320
+ import { join as join13, basename as basename3 } from "path";
2175
2321
  import { parse } from "yaml";
2176
2322
 
2177
2323
  // src/sandbox-policy.ts
@@ -2382,6 +2528,7 @@ var HOOK_NAMES = [
2382
2528
  "isolate",
2383
2529
  "handoff",
2384
2530
  "preview",
2531
+ "intel",
2385
2532
  "map",
2386
2533
  "ci_status",
2387
2534
  "version",
@@ -2453,8 +2600,8 @@ var MODES = ["local", "integrate", "ci_manual", "ci_auto", "external"];
2453
2600
  var PROVIDERS = ["github", "buildkite", "other", "none"];
2454
2601
  function findRepoConfig(dir) {
2455
2602
  for (const name of REPO_CONFIG_FILENAMES) {
2456
- const p = join12(dir, name);
2457
- if (existsSync10(p)) return p;
2603
+ const p = join13(dir, name);
2604
+ if (existsSync11(p)) return p;
2458
2605
  }
2459
2606
  return null;
2460
2607
  }
@@ -2734,7 +2881,7 @@ function parseRepoConfig(text2, file) {
2734
2881
  function loadRepoConfig(dir) {
2735
2882
  const file = findRepoConfig(dir);
2736
2883
  if (!file) return null;
2737
- return parseRepoConfig(readFileSync11(file, "utf8"), file);
2884
+ return parseRepoConfig(readFileSync12(file, "utf8"), file);
2738
2885
  }
2739
2886
  function hookLabel(cfg, hook2) {
2740
2887
  return cfg.labels[hook2] ?? cfg.hooks[hook2] ?? hook2;
@@ -3015,6 +3162,7 @@ var ConfigError = class extends Error {
3015
3162
  };
3016
3163
  var DEFAULT_MAX_PERISCOPES = 3;
3017
3164
  var DEFAULT_PERISCOPE_IDLE_MINUTES = 120;
3165
+ var DEFAULT_INTEL_STARTUP_SECONDS = 20;
3018
3166
  var DEFAULT_MAP_TOKEN_BUDGET = 1e3;
3019
3167
  function parseCloneScheme(v) {
3020
3168
  if (v === void 0 || v === null || v === "") return void 0;
@@ -3108,6 +3256,7 @@ var SHIP_KEYS = /* @__PURE__ */ new Set([
3108
3256
  "previewHost",
3109
3257
  "maxPeriscopes",
3110
3258
  "periscopeIdleMinutes",
3259
+ "intelStartupSeconds",
3111
3260
  "mapTokenBudget",
3112
3261
  "secretStore",
3113
3262
  "env",
@@ -3261,11 +3410,11 @@ function expand(p, base) {
3261
3410
  return isAbsolute2(out) ? out : resolve2(base, out);
3262
3411
  }
3263
3412
  function resolvePromptsDir(promptSet, crewHome, base) {
3264
- if (!promptSet) return join13(crewHome, "prompts", "default");
3413
+ if (!promptSet) return join14(crewHome, "prompts", "default");
3265
3414
  if (promptSet.includes("/") || promptSet.startsWith(".") || promptSet.startsWith("~")) {
3266
3415
  return expand(promptSet, base);
3267
3416
  }
3268
- return join13(crewHome, "prompts", promptSet);
3417
+ return join14(crewHome, "prompts", promptSet);
3269
3418
  }
3270
3419
  var Missing = class {
3271
3420
  paths = [];
@@ -3289,7 +3438,7 @@ var Missing = class {
3289
3438
  };
3290
3439
  function crewVersion(crewHome) {
3291
3440
  try {
3292
- const pkg = JSON.parse(readFileSync12(join13(crewHome, "package.json"), "utf8"));
3441
+ const pkg = JSON.parse(readFileSync13(join14(crewHome, "package.json"), "utf8"));
3293
3442
  return pkg.version ?? "0.0.0";
3294
3443
  } catch {
3295
3444
  return "0.0.0";
@@ -3299,26 +3448,26 @@ function configSearchPath(crewHome) {
3299
3448
  if (process.env.CREW_CONFIG) return [resolve2(process.env.CREW_CONFIG)];
3300
3449
  const xdg = process.env.XDG_CONFIG_HOME;
3301
3450
  return [
3302
- ...xdg ? [join13(xdg, "crew", "crew.yaml")] : [],
3303
- join13(homedir6(), ".config", "crew", "crew.yaml"),
3451
+ ...xdg ? [join14(xdg, "crew", "crew.yaml")] : [],
3452
+ join14(homedir6(), ".config", "crew", "crew.yaml"),
3304
3453
  resolve2(crewHome, "crew.yaml")
3305
3454
  ];
3306
3455
  }
3307
3456
  function findConfigFile(crewHome) {
3308
3457
  const candidates2 = configSearchPath(crewHome);
3309
- return candidates2.find((c) => existsSync11(c)) ?? candidates2[candidates2.length - 1];
3458
+ return candidates2.find((c) => existsSync12(c)) ?? candidates2[candidates2.length - 1];
3310
3459
  }
3311
- var defaultConfigPath = () => join13(process.env.XDG_CONFIG_HOME ?? join13(homedir6(), ".config"), "crew", "crew.yaml");
3460
+ var defaultConfigPath = () => join14(process.env.XDG_CONFIG_HOME ?? join14(homedir6(), ".config"), "crew", "crew.yaml");
3312
3461
  function routeSlug(route2) {
3313
3462
  return route2.replace(/\//g, "-");
3314
3463
  }
3315
3464
  function resolvedPathFor(stateDir, route2) {
3316
3465
  const [workspace, project] = splitRoute(route2);
3317
- return join13(stateDir, "resolved", workspace, `${project}.json`);
3466
+ return join14(stateDir, "resolved", workspace, `${project}.json`);
3318
3467
  }
3319
3468
  function apiKeyPathFor(stateDir, route2) {
3320
3469
  const [workspace, project] = splitRoute(route2);
3321
- return join13(stateDir, "keys", workspace, `${project}.env`);
3470
+ return join14(stateDir, "keys", workspace, `${project}.env`);
3322
3471
  }
3323
3472
  function splitRoute(route2) {
3324
3473
  const parts = route2.split("/");
@@ -3329,9 +3478,9 @@ function splitRoute(route2) {
3329
3478
  }
3330
3479
  function readResolvedFile(stateDir, route2) {
3331
3480
  const path = resolvedPathFor(stateDir, route2);
3332
- if (!existsSync11(path)) return void 0;
3481
+ if (!existsSync12(path)) return void 0;
3333
3482
  try {
3334
- return JSON.parse(readFileSync12(path, "utf8"));
3483
+ return JSON.parse(readFileSync13(path, "utf8"));
3335
3484
  } catch (e) {
3336
3485
  throw new ConfigError(`${path}: not valid JSON \u2014 ${e.message}`);
3337
3486
  }
@@ -3392,23 +3541,23 @@ function parseResolved(raw, m, where) {
3392
3541
  }
3393
3542
  function loadConfig(crewHome, configFile, opts = {}) {
3394
3543
  const file = configFile ?? findConfigFile(crewHome);
3395
- if (opts.text === void 0 && !existsSync11(file)) {
3544
+ if (opts.text === void 0 && !existsSync12(file)) {
3396
3545
  throw new ConfigError(
3397
3546
  `no config found. Looked in:
3398
3547
  ` + configSearchPath(crewHome).map((c) => ` - ${c}`).join("\n") + `
3399
3548
 
3400
3549
  Create the first of those:
3401
- mkdir -p ${dirname5(defaultConfigPath())} && cp ${join13(crewHome, "crew.example.yaml")} ${defaultConfigPath()}`
3550
+ mkdir -p ${dirname6(defaultConfigPath())} && cp ${join14(crewHome, "crew.example.yaml")} ${defaultConfigPath()}`
3402
3551
  );
3403
3552
  }
3404
3553
  let raw;
3405
3554
  try {
3406
- raw = parse2(opts.text ?? readFileSync12(file, "utf8"));
3555
+ raw = parse2(opts.text ?? readFileSync13(file, "utf8"));
3407
3556
  } catch (e) {
3408
3557
  throw new ConfigError(`${file}: not valid YAML \u2014 ${e.message}`);
3409
3558
  }
3410
3559
  if (!raw || typeof raw !== "object") throw new ConfigError(`${file} is empty or not a mapping`);
3411
- const base = dirname5(file);
3560
+ const base = dirname6(file);
3412
3561
  const missing = new Missing();
3413
3562
  rejectUnknownKeys(raw, /* @__PURE__ */ new Set(["ship", "routes"]), "top-level", file);
3414
3563
  const shipRaw = raw.ship ?? {};
@@ -3457,6 +3606,10 @@ Create the first of those:
3457
3606
  if (!Number.isInteger(periscopeIdleMinutes) || periscopeIdleMinutes < 1) {
3458
3607
  missing.add(`ship.periscopeIdleMinutes must be a positive integer (got "${shipRaw.periscopeIdleMinutes}")`);
3459
3608
  }
3609
+ const intelStartupSeconds = shipRaw.intelStartupSeconds === void 0 ? DEFAULT_INTEL_STARTUP_SECONDS : Number(shipRaw.intelStartupSeconds);
3610
+ if (!Number.isInteger(intelStartupSeconds) || intelStartupSeconds < 1) {
3611
+ missing.add(`ship.intelStartupSeconds must be a positive integer (got "${shipRaw.intelStartupSeconds}")`);
3612
+ }
3460
3613
  const mapTokenBudget = shipRaw.mapTokenBudget === void 0 ? DEFAULT_MAP_TOKEN_BUDGET : Number(shipRaw.mapTokenBudget);
3461
3614
  if (!Number.isInteger(mapTokenBudget) || mapTokenBudget < 1) {
3462
3615
  missing.add(`ship.mapTokenBudget must be a positive integer (got "${shipRaw.mapTokenBudget}")`);
@@ -3526,7 +3679,7 @@ Create the first of those:
3526
3679
  useNvm: shipRaw.useNvm !== false,
3527
3680
  nvmSh: shipRaw.nvmSh,
3528
3681
  stateDir,
3529
- logFile: expand(shipRaw.logFile ?? join13(tmpdir(), "crew.log"), base),
3682
+ logFile: expand(shipRaw.logFile ?? join14(tmpdir(), "crew.log"), base),
3530
3683
  userAgent: shipRaw.userAgent ?? `Mozilla/5.0 CrewAgent/${crewVersion(crewHome)}`,
3531
3684
  maxConcurrentAgents,
3532
3685
  maxConcurrentAgentsSet,
@@ -3544,6 +3697,7 @@ Create the first of those:
3544
3697
  previewHost: shipRaw.previewHost ? String(shipRaw.previewHost).trim() || void 0 : void 0,
3545
3698
  maxPeriscopes,
3546
3699
  periscopeIdleMinutes,
3700
+ intelStartupSeconds,
3547
3701
  mapTokenBudget,
3548
3702
  secretStore,
3549
3703
  env: parseShipEnv(shipRaw.env)
@@ -3707,7 +3861,7 @@ function parseOneRoute(c, where, file, base, stateDir, raw, missing, crewHome, t
3707
3861
  const hasRepos = Object.keys(repoDirs).length > 0;
3708
3862
  const reposBasePath = expand(String(c?.reposBasePath ?? raw.ship?.reposBasePath ?? DEFAULT_REPOS_BASE_PATH), base);
3709
3863
  const dirIsCloneBase = !c?.dir && !hasRepos && !Array.isArray(c?.repos);
3710
- const dir = c?.dir ? expand(String(c.dir), base) : hasRepos ? Object.values(repoDirs)[0] : dirIsCloneBase ? join13(reposBasePath, splitRoute(route2)[0]) : "";
3864
+ const dir = c?.dir ? expand(String(c.dir), base) : hasRepos ? Object.values(repoDirs)[0] : dirIsCloneBase ? join14(reposBasePath, splitRoute(route2)[0]) : "";
3711
3865
  const weight = c?.weight === void 0 ? void 0 : Number(c.weight);
3712
3866
  if (weight !== void 0 && !(Number.isFinite(weight) && weight > 0)) {
3713
3867
  missing.add(`${where}.weight must be a positive number (got "${c?.weight}")`);
@@ -3770,7 +3924,7 @@ function locateDir(cfg, dir, commonDirOf) {
3770
3924
  const direct = find(target);
3771
3925
  if (direct) return direct;
3772
3926
  const common = commonDirOf?.(target);
3773
- return common ? find(dirname5(resolve2(target, common))) : void 0;
3927
+ return common ? find(dirname6(resolve2(target, common))) : void 0;
3774
3928
  }
3775
3929
  function findRoute(cfg, route2) {
3776
3930
  if (!route2) {
@@ -3805,8 +3959,8 @@ function repoIdForName(r, name) {
3805
3959
  }
3806
3960
  function resolveApiKey(r) {
3807
3961
  if (r.apiKey) return r.apiKey;
3808
- if (r.apiKeyFile && r.apiKeyVar && existsSync11(r.apiKeyFile)) {
3809
- for (const line of readFileSync12(r.apiKeyFile, "utf8").split("\n")) {
3962
+ if (r.apiKeyFile && r.apiKeyVar && existsSync12(r.apiKeyFile)) {
3963
+ for (const line of readFileSync13(r.apiKeyFile, "utf8").split("\n")) {
3810
3964
  const m = line.match(new RegExp(`^${r.apiKeyVar}=(.*)$`));
3811
3965
  if (m) return (m[1] ?? "").trim().replace(/^["']|["']$/g, "");
3812
3966
  }
@@ -3819,9 +3973,9 @@ function resolveApiKey(r) {
3819
3973
  }
3820
3974
  function credentialSource(r) {
3821
3975
  if (r.apiKey) return KEYCHAIN_ELIGIBLE_ROUTES.has(r) ? "keychain" : "inline";
3822
- if (r.apiKeyFile && r.apiKeyVar && existsSync11(r.apiKeyFile)) {
3976
+ if (r.apiKeyFile && r.apiKeyVar && existsSync12(r.apiKeyFile)) {
3823
3977
  const re = new RegExp(`^${r.apiKeyVar}=`);
3824
- if (readFileSync12(r.apiKeyFile, "utf8").split("\n").some((l) => re.test(l))) return "apiKeyFile";
3978
+ if (readFileSync13(r.apiKeyFile, "utf8").split("\n").some((l) => re.test(l))) return "apiKeyFile";
3825
3979
  }
3826
3980
  return process.env.CREW_API_KEY?.trim() ? "CREW_API_KEY" : "none";
3827
3981
  }
@@ -3877,7 +4031,7 @@ function configuredMembers(rt) {
3877
4031
  return out;
3878
4032
  }
3879
4033
  function defaultRepoDir(basePath, workspace, repoName) {
3880
- return join13(basePath, workspace, repoName);
4034
+ return join14(basePath, workspace, repoName);
3881
4035
  }
3882
4036
  function reposOf(r) {
3883
4037
  const named = Object.entries(r.repos);
@@ -3916,10 +4070,10 @@ function passengerRepoTargets(r) {
3916
4070
  return reposOf(r).filter((t) => r.repoOverrides[t.name]?.hostPassengers !== false);
3917
4071
  }
3918
4072
  function passengerCheckoutDir(basePath, workspace, repoName) {
3919
- return join13(basePath, workspace, ".passenger-checkouts", repoName);
4073
+ return join14(basePath, workspace, ".passenger-checkouts", repoName);
3920
4074
  }
3921
4075
  function passengerMirrorArea(ship) {
3922
- return ship.runner === "sandbox" ? join13(ship.stateDir, "passenger-sources") : void 0;
4076
+ return ship.runner === "sandbox" ? join14(ship.stateDir, "passenger-sources") : void 0;
3923
4077
  }
3924
4078
  function passengerCheckoutTargets(r, mirrorArea) {
3925
4079
  if (!r.hostPassengers) return [];
@@ -3930,7 +4084,7 @@ function passengerCheckoutTargets(r, mirrorArea) {
3930
4084
  const forgeHost = t.forgeHost ?? (id ? r.resolved?.repoForgeHosts?.[id] : void 0);
3931
4085
  return {
3932
4086
  name: t.name,
3933
- dir: mirrorArea ? join13(mirrorArea, workspace, t.name) : passengerCheckoutDir(r.reposBasePath, workspace, t.name),
4087
+ dir: mirrorArea ? join14(mirrorArea, workspace, t.name) : passengerCheckoutDir(r.reposBasePath, workspace, t.name),
3934
4088
  remote: t.remote ?? (id ? remotes[id] : void 0),
3935
4089
  ...forgeHost ? { forgeHost } : {}
3936
4090
  };
@@ -4212,9 +4366,9 @@ function recoveredFailureHeadlines(o, route2) {
4212
4366
  }
4213
4367
 
4214
4368
  // src/install.ts
4215
- import { dirname as dirname6, join as join14, extname } from "path";
4369
+ import { dirname as dirname7, join as join15, extname } from "path";
4216
4370
  import { homedir as homedir7, userInfo } from "os";
4217
- import { accessSync as accessSync2, constants as constants2, existsSync as existsSync12, mkdirSync as mkdirSync8, readdirSync as readdirSync3, readFileSync as readFileSync13, statSync as statSync5, writeFileSync as writeFileSync9, unlinkSync, realpathSync } from "fs";
4371
+ import { accessSync as accessSync2, constants as constants2, existsSync as existsSync13, mkdirSync as mkdirSync9, readdirSync as readdirSync3, readFileSync as readFileSync14, statSync as statSync5, writeFileSync as writeFileSync10, unlinkSync, realpathSync } from "fs";
4218
4372
  import { spawnSync as spawnSync4 } from "child_process";
4219
4373
  import { createHash as createHash3 } from "crypto";
4220
4374
 
@@ -4226,7 +4380,7 @@ function isCompiledBinary(moduleUrl) {
4226
4380
  // src/install.ts
4227
4381
  function crewInvocation(crewHome) {
4228
4382
  if (isCompiledBinary(import.meta.url)) return [process.execPath];
4229
- return [process.execPath, join14(crewHome, "bin", "crew")];
4383
+ return [process.execPath, join15(crewHome, "bin", "crew")];
4230
4384
  }
4231
4385
  var INTERVAL_SECONDS = 120;
4232
4386
  function labelFor(crewHome, job) {
@@ -4257,14 +4411,14 @@ function schedulerLogFor(crewLog, job) {
4257
4411
  return `${stem}.${suffix}${ext || ".log"}`;
4258
4412
  }
4259
4413
  function pathFor(ship) {
4260
- const nodeBinDir = dirname6(process.execPath);
4414
+ const nodeBinDir = dirname7(process.execPath);
4261
4415
  const parts = [nodeBinDir];
4262
4416
  if (ship.extraPath) parts.push(ship.extraPath);
4263
4417
  parts.push("/usr/bin", "/bin", "/usr/sbin", "/sbin");
4264
4418
  return parts.join(":");
4265
4419
  }
4266
4420
  function findOnPath(bin, searchPath) {
4267
- const candidates2 = bin.includes("/") ? [bin] : searchPath.split(":").filter(Boolean).map((dir) => join14(dir, bin));
4421
+ const candidates2 = bin.includes("/") ? [bin] : searchPath.split(":").filter(Boolean).map((dir) => join15(dir, bin));
4268
4422
  for (const candidate of candidates2) {
4269
4423
  try {
4270
4424
  accessSync2(candidate, constants2.X_OK);
@@ -4274,12 +4428,12 @@ function findOnPath(bin, searchPath) {
4274
4428
  }
4275
4429
  return void 0;
4276
4430
  }
4277
- var COMMON_DOCKER_DIRS = ["/usr/local/bin", "/opt/homebrew/bin", join14(homedir7(), ".docker", "bin")].join(":");
4431
+ var COMMON_DOCKER_DIRS = ["/usr/local/bin", "/opt/homebrew/bin", join15(homedir7(), ".docker", "bin")].join(":");
4278
4432
  function dockerPathProblem(ship, shellPath = process.env.PATH ?? "") {
4279
4433
  const schedulerPath = pathFor(ship);
4280
4434
  if (findOnPath("docker", schedulerPath)) return void 0;
4281
4435
  const inShell = findOnPath("docker", shellPath);
4282
- return inShell ? `\`docker\` is not on the scheduler PATH (${schedulerPath}) but is at ${inShell} in your shell; add ${dirname6(inShell)} to ship.extraPath in crew.yaml and run \`crew install\`` : `\`docker\` is not on the scheduler PATH (${schedulerPath}) or your shell PATH; install Docker, then add its directory to ship.extraPath in crew.yaml and run \`crew install\``;
4436
+ return inShell ? `\`docker\` is not on the scheduler PATH (${schedulerPath}) but is at ${inShell} in your shell; add ${dirname7(inShell)} to ship.extraPath in crew.yaml and run \`crew install\`` : `\`docker\` is not on the scheduler PATH (${schedulerPath}) or your shell PATH; install Docker, then add its directory to ship.extraPath in crew.yaml and run \`crew install\``;
4283
4437
  }
4284
4438
  var USER_INSTALL = { root: false, user: "" };
4285
4439
  function installContext(env = process.env) {
@@ -4289,7 +4443,7 @@ function installContext(env = process.env) {
4289
4443
  }
4290
4444
  var SYSTEM_UNIT_DIR = "/etc/systemd/system";
4291
4445
  function systemUnitPathFor(label, suffix = "service") {
4292
- return join14(SYSTEM_UNIT_DIR, `${label}.${suffix}`);
4446
+ return join15(SYSTEM_UNIT_DIR, `${label}.${suffix}`);
4293
4447
  }
4294
4448
  function unitEnvironment(ship) {
4295
4449
  return [["PATH", pathFor(ship)], ...Object.entries(ship.env ?? {})];
@@ -4310,7 +4464,7 @@ function xmlEscape(s) {
4310
4464
  }
4311
4465
  function planLaunchd(ship, crewHome, job) {
4312
4466
  const label = labelFor(crewHome, job);
4313
- const unitPath = join14(homedir7(), "Library", "LaunchAgents", `${label}.plist`);
4467
+ const unitPath = join15(homedir7(), "Library", "LaunchAgents", `${label}.plist`);
4314
4468
  const crewLog = ship.logFile;
4315
4469
  const schedulerLog = schedulerLogFor(crewLog, job);
4316
4470
  const persistent = job === "run";
@@ -4364,7 +4518,7 @@ ${scheduleKeys}
4364
4518
  }
4365
4519
  function planSystemd(ship, crewHome, job, ctx) {
4366
4520
  const label = labelFor(crewHome, job);
4367
- const unitDir = ctx.root ? SYSTEM_UNIT_DIR : join14(homedir7(), ".config", "systemd", "user");
4521
+ const unitDir = ctx.root ? SYSTEM_UNIT_DIR : join15(homedir7(), ".config", "systemd", "user");
4368
4522
  const ctl = ctx.root ? ["systemctl"] : ["systemctl", "--user"];
4369
4523
  const userLine = ctx.root && ctx.user && ctx.user !== "root" ? `User=${ctx.user}
4370
4524
  ` : "";
@@ -4373,7 +4527,7 @@ function planSystemd(ship, crewHome, job, ctx) {
4373
4527
  lingerCommand: ["loginctl", "enable-linger", ctx.user],
4374
4528
  lingerHint: `the daemon will stop when ${ctx.user} logs out; run \`sudo loginctl enable-linger ${ctx.user}\` once, or run \`crew install\` as root for a system unit`
4375
4529
  };
4376
- const servicePath = join14(unitDir, `${label}.service`);
4530
+ const servicePath = join15(unitDir, `${label}.service`);
4377
4531
  const crewLog = ship.logFile;
4378
4532
  const schedulerLog = schedulerLogFor(crewLog, job);
4379
4533
  const description = job === "release" ? "Tablation crew \u2014 release" : job === "passengers" ? "Tablation crew \u2014 Host Passengers sync" : "Tablation crew \u2014 persistent supervisor loop";
@@ -4414,7 +4568,7 @@ WantedBy=${wantedBy}
4414
4568
  ...linger
4415
4569
  };
4416
4570
  }
4417
- const timerPath = join14(unitDir, `${label}.timer`);
4571
+ const timerPath = join15(unitDir, `${label}.timer`);
4418
4572
  const service = `# Written by \`crew install\` \u2014 re-run it rather than hand-editing this file.
4419
4573
  [Unit]
4420
4574
  Description=${description}
@@ -4489,7 +4643,7 @@ function planInstall(ship, crewHome, hostShip, hasSystemd, job = "run", ctx = US
4489
4643
  function planUninstall(ship, crewHome, hostShip, hasSystemd, job = "run") {
4490
4644
  const label = labelFor(crewHome, job);
4491
4645
  if (hostShip === "macos") {
4492
- const unitPath = join14(homedir7(), "Library", "LaunchAgents", `${label}.plist`);
4646
+ const unitPath = join15(homedir7(), "Library", "LaunchAgents", `${label}.plist`);
4493
4647
  return {
4494
4648
  mechanism: "launchd",
4495
4649
  unitPaths: [unitPath],
@@ -4499,20 +4653,20 @@ function planUninstall(ship, crewHome, hostShip, hasSystemd, job = "run") {
4499
4653
  };
4500
4654
  }
4501
4655
  if (hostShip === "linux" && hasSystemd) {
4502
- const system = existsSync12(systemUnitPathFor(label));
4503
- const unitDir = system ? SYSTEM_UNIT_DIR : join14(homedir7(), ".config", "systemd", "user");
4656
+ const system = existsSync13(systemUnitPathFor(label));
4657
+ const unitDir = system ? SYSTEM_UNIT_DIR : join15(homedir7(), ".config", "systemd", "user");
4504
4658
  const ctl = system ? ["systemctl"] : ["systemctl", "--user"];
4505
4659
  if (job === "run") {
4506
4660
  return {
4507
4661
  mechanism: "systemd",
4508
- unitPaths: [join14(unitDir, `${label}.service`)],
4662
+ unitPaths: [join15(unitDir, `${label}.service`)],
4509
4663
  crontabLine: null,
4510
4664
  unloadCommands: [[...ctl, "disable", "--now", `${label}.service`]]
4511
4665
  };
4512
4666
  }
4513
4667
  return {
4514
4668
  mechanism: "systemd",
4515
- unitPaths: [join14(unitDir, `${label}.service`), join14(unitDir, `${label}.timer`)],
4669
+ unitPaths: [join15(unitDir, `${label}.service`), join15(unitDir, `${label}.timer`)],
4516
4670
  crontabLine: null,
4517
4671
  unloadCommands: [[...ctl, "disable", "--now", `${label}.timer`]]
4518
4672
  };
@@ -4530,7 +4684,7 @@ function planUninstall(ship, crewHome, hostShip, hasSystemd, job = "run") {
4530
4684
  function planDaemonControl(crewHome, hostShip, hasSystemd) {
4531
4685
  const label = labelFor(crewHome, "run");
4532
4686
  if (hostShip === "macos") {
4533
- const unitPath = join14(homedir7(), "Library", "LaunchAgents", `${label}.plist`);
4687
+ const unitPath = join15(homedir7(), "Library", "LaunchAgents", `${label}.plist`);
4534
4688
  return {
4535
4689
  mechanism: "launchd",
4536
4690
  startCommand: ["launchctl", "load", unitPath],
@@ -4540,7 +4694,7 @@ function planDaemonControl(crewHome, hostShip, hasSystemd) {
4540
4694
  }
4541
4695
  if (hostShip === "linux" && hasSystemd) {
4542
4696
  const unit = `${label}.service`;
4543
- const ctl = existsSync12(systemUnitPathFor(label)) ? ["systemctl"] : ["systemctl", "--user"];
4697
+ const ctl = existsSync13(systemUnitPathFor(label)) ? ["systemctl"] : ["systemctl", "--user"];
4544
4698
  return {
4545
4699
  mechanism: "systemd",
4546
4700
  startCommand: [...ctl, "start", unit],
@@ -4572,10 +4726,10 @@ async function applyInstall(plan, crewHome, dryRun, log) {
4572
4726
  log.emit(`would write ${path}`);
4573
4727
  continue;
4574
4728
  }
4575
- const before = existsSync12(path) ? readFileSync13(path, "utf8") : null;
4729
+ const before = existsSync13(path) ? readFileSync14(path, "utf8") : null;
4576
4730
  if (before !== plan.unitContent[path]) changed2 = true;
4577
- mkdirSync8(dirname6(path), { recursive: true });
4578
- writeFileSync9(path, plan.unitContent[path]);
4731
+ mkdirSync9(dirname7(path), { recursive: true });
4732
+ writeFileSync10(path, plan.unitContent[path]);
4579
4733
  log.emit(`wrote ${path}`);
4580
4734
  }
4581
4735
  if (plan.crontabLine) {
@@ -4639,7 +4793,7 @@ async function applyUninstall(plan, crewHome, dryRun, log) {
4639
4793
  }
4640
4794
  }
4641
4795
  for (const path of plan.unitPaths) {
4642
- if (!existsSync12(path)) continue;
4796
+ if (!existsSync13(path)) continue;
4643
4797
  if (dryRun) {
4644
4798
  log.emit(`would remove ${path}`);
4645
4799
  continue;
@@ -4658,7 +4812,7 @@ async function applyUninstall(plan, crewHome, dryRun, log) {
4658
4812
  }
4659
4813
  var CREW_LAUNCHD_PREFIX = "com.tablation.crew";
4660
4814
  function launchAgentsDir() {
4661
- return join14(homedir7(), "Library", "LaunchAgents");
4815
+ return join15(homedir7(), "Library", "LaunchAgents");
4662
4816
  }
4663
4817
  function xmlUnescape(s) {
4664
4818
  return s.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&");
@@ -4675,25 +4829,25 @@ function loadedCrewLabels() {
4675
4829
  return [...parseLaunchctlList(list.stdout ?? "").keys()].filter((l) => l.startsWith(CREW_LAUNCHD_PREFIX));
4676
4830
  }
4677
4831
  function listLaunchdUnits(dir = launchAgentsDir(), loaded = []) {
4678
- const files = existsSync12(dir) ? readdirSync3(dir) : [];
4832
+ const files = existsSync13(dir) ? readdirSync3(dir) : [];
4679
4833
  const units = files.filter((f) => f.startsWith(CREW_LAUNCHD_PREFIX) && f.endsWith(".plist")).sort().map((f) => {
4680
- const plistPath = join14(dir, f);
4834
+ const plistPath = join15(dir, f);
4681
4835
  let program = null;
4682
4836
  try {
4683
- program = programFromPlist(readFileSync13(plistPath, "utf8"));
4837
+ program = programFromPlist(readFileSync14(plistPath, "utf8"));
4684
4838
  } catch {
4685
4839
  }
4686
4840
  return {
4687
4841
  label: f.slice(0, -".plist".length),
4688
4842
  plistPath,
4689
4843
  program,
4690
- programExists: program !== null && existsSync12(program)
4844
+ programExists: program !== null && existsSync13(program)
4691
4845
  };
4692
4846
  });
4693
4847
  const seen = new Set(units.map((u) => u.label));
4694
4848
  for (const label of [...loaded].sort()) {
4695
4849
  if (!label.startsWith(CREW_LAUNCHD_PREFIX) || seen.has(label)) continue;
4696
- units.push({ label, plistPath: join14(dir, `${label}.plist`), program: null, programExists: false, orphan: true });
4850
+ units.push({ label, plistPath: join15(dir, `${label}.plist`), program: null, programExists: false, orphan: true });
4697
4851
  }
4698
4852
  return units;
4699
4853
  }
@@ -4706,9 +4860,9 @@ function removeLaunchdUnit(unit, dryRun, log) {
4706
4860
  log.emit(`would unload and remove ${unit.label}`);
4707
4861
  return;
4708
4862
  }
4709
- if (existsSync12(unit.plistPath)) spawnSync4("launchctl", ["unload", unit.plistPath], { encoding: "utf8" });
4863
+ if (existsSync13(unit.plistPath)) spawnSync4("launchctl", ["unload", unit.plistPath], { encoding: "utf8" });
4710
4864
  spawnSync4("launchctl", ["remove", unit.label], { encoding: "utf8" });
4711
- if (existsSync12(unit.plistPath)) unlinkSync(unit.plistPath);
4865
+ if (existsSync13(unit.plistPath)) unlinkSync(unit.plistPath);
4712
4866
  log.emit(`removed ${unit.label} (${unit.plistPath})`);
4713
4867
  }
4714
4868
  function clearForeignLaunchdUnits(crewHome, replace, dryRun, log, dir, loaded) {
@@ -4786,24 +4940,24 @@ function detectSystemd() {
4786
4940
  }
4787
4941
 
4788
4942
  // src/ship-attention.ts
4789
- import { existsSync as existsSync14, statfsSync } from "fs";
4943
+ import { existsSync as existsSync15, statfsSync } from "fs";
4790
4944
 
4791
4945
  // src/git.ts
4792
- import { execFileSync as execFileSync3 } from "child_process";
4946
+ import { execFileSync as execFileSync4 } from "child_process";
4793
4947
  import {
4794
- existsSync as existsSync13,
4795
- mkdirSync as mkdirSync9,
4948
+ existsSync as existsSync14,
4949
+ mkdirSync as mkdirSync10,
4796
4950
  openSync as openSync2,
4797
4951
  closeSync as closeSync2,
4798
4952
  writeSync,
4799
4953
  statSync as statSync6,
4800
4954
  unlinkSync as unlinkSync2,
4801
- readFileSync as readFileSync14,
4802
- writeFileSync as writeFileSync10,
4955
+ readFileSync as readFileSync15,
4956
+ writeFileSync as writeFileSync11,
4803
4957
  readdirSync as readdirSync4,
4804
4958
  rmSync as rmSync8
4805
4959
  } from "fs";
4806
- import { dirname as dirname7, basename as basename5, join as join15 } from "path";
4960
+ import { dirname as dirname8, basename as basename5, join as join16 } from "path";
4807
4961
  var GitError = class extends Error {
4808
4962
  };
4809
4963
  function streamText(x) {
@@ -4811,7 +4965,7 @@ function streamText(x) {
4811
4965
  }
4812
4966
  function gitRaw(cwd, args) {
4813
4967
  try {
4814
- return execFileSync3("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
4968
+ return execFileSync4("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
4815
4969
  } catch (e) {
4816
4970
  const err3 = e;
4817
4971
  const why = [err3.stderr, err3.stdout].map(streamText).filter(Boolean).join(" / ");
@@ -4820,7 +4974,7 @@ function gitRaw(cwd, args) {
4820
4974
  }
4821
4975
  function git(cwd, args) {
4822
4976
  try {
4823
- return execFileSync3("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
4977
+ return execFileSync4("git", args, { cwd, encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] }).trim();
4824
4978
  } catch (e) {
4825
4979
  const err3 = e;
4826
4980
  const why = [err3.stderr, err3.stdout].map(streamText).filter(Boolean).join(" / ");
@@ -4991,9 +5145,9 @@ function keyCommitsInRange(cwd, key, range) {
4991
5145
  }
4992
5146
  function patchIdOf(cwd, from, to) {
4993
5147
  try {
4994
- const diff = execFileSync3("git", ["diff", from, to], { cwd, encoding: "utf8", maxBuffer: 256 * 1024 * 1024 });
5148
+ const diff = execFileSync4("git", ["diff", from, to], { cwd, encoding: "utf8", maxBuffer: 256 * 1024 * 1024 });
4995
5149
  if (!diff) return null;
4996
- const out = execFileSync3("git", ["patch-id", "--stable"], { cwd, encoding: "utf8", input: diff });
5150
+ const out = execFileSync4("git", ["patch-id", "--stable"], { cwd, encoding: "utf8", input: diff });
4997
5151
  return out.split(" ")[0]?.trim() || null;
4998
5152
  } catch {
4999
5153
  return null;
@@ -5183,7 +5337,7 @@ function recoverStrandedReleaseCheckouts(cwd) {
5183
5337
  if (line.startsWith("worktree ")) path = line.slice("worktree ".length);
5184
5338
  else if (line.startsWith("branch refs/heads/crew/release-") && path) {
5185
5339
  gitOk(cwd, ["worktree", "remove", "--force", path]);
5186
- const root = dirname7(path);
5340
+ const root = dirname8(path);
5187
5341
  if (basename5(root).startsWith("crew-release-")) rmSync8(root, { recursive: true, force: true });
5188
5342
  }
5189
5343
  }
@@ -5201,11 +5355,11 @@ function sweepStaleReleaseRoots(tmp, now = Date.now(), maxAgeMs = 60 * 60 * 1e3)
5201
5355
  }
5202
5356
  for (const name of names) {
5203
5357
  if (!name.startsWith("crew-release-")) continue;
5204
- const root = join15(tmp, name);
5358
+ const root = join16(tmp, name);
5205
5359
  try {
5206
5360
  const st = statSync6(root);
5207
5361
  if (!st.isDirectory() || now - st.mtimeMs < maxAgeMs) continue;
5208
- if (existsSync13(join15(root, "checkout"))) continue;
5362
+ if (existsSync14(join16(root, "checkout"))) continue;
5209
5363
  rmSync8(root, { recursive: true, force: true });
5210
5364
  removed.push(name);
5211
5365
  } catch {
@@ -5257,16 +5411,16 @@ function originUrlOf(dir, remoteName) {
5257
5411
  }
5258
5412
  }
5259
5413
  function ensureRepoCheckout(dir, remote, opts = {}) {
5260
- if (existsSync13(`${dir}/.git`)) return false;
5414
+ if (existsSync14(`${dir}/.git`)) return false;
5261
5415
  if (!remote) {
5262
5416
  throw new GitError(
5263
5417
  `${dir} does not exist and this repo has no discovered remote to clone from \u2014 re-run \`crew connect\`, or check out the repository yourself and point \`repos:\` at it`
5264
5418
  );
5265
5419
  }
5266
- mkdirSync9(dirname7(dir), { recursive: true });
5420
+ mkdirSync10(dirname8(dir), { recursive: true });
5267
5421
  const url = cloneUrlFor(remote, opts);
5268
5422
  try {
5269
- execFileSync3("git", ["clone", url, dir], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
5423
+ execFileSync4("git", ["clone", url, dir], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"] });
5270
5424
  } catch (e) {
5271
5425
  const err3 = e;
5272
5426
  const why = [err3.stderr, err3.stdout].map(streamText).filter(Boolean).join(" / ");
@@ -5288,7 +5442,7 @@ function sleepSync(ms3) {
5288
5442
  }
5289
5443
  function acquireCheckoutLock(dir, timeoutMs = 3e4) {
5290
5444
  const lockPath = checkoutLockPath(dir);
5291
- mkdirSync9(dirname7(lockPath), { recursive: true });
5445
+ mkdirSync10(dirname8(lockPath), { recursive: true });
5292
5446
  const deadline = Date.now() + timeoutMs;
5293
5447
  for (; ; ) {
5294
5448
  try {
@@ -5325,17 +5479,17 @@ function acquireCheckoutLock(dir, timeoutMs = 3e4) {
5325
5479
  function syncPassengerCheckout(dir, githubRemote, gitRemoteName, base, clone = {}) {
5326
5480
  const release = acquireCheckoutLock(dir);
5327
5481
  try {
5328
- if (!existsSync13(`${dir}/.git`) && githubRemote) {
5482
+ if (!existsSync14(`${dir}/.git`) && githubRemote) {
5329
5483
  const url = cloneUrlFor(githubRemote, clone);
5330
5484
  const marker = cloneFailureMarker(dir);
5331
- if (existsSync13(marker) && readFileSync14(marker, "utf8").split("\n")[0] === url) {
5332
- return { action: "clone-failed", detail: readFileSync14(marker, "utf8").split("\n").slice(1).join("\n"), repeat: true };
5485
+ if (existsSync14(marker) && readFileSync15(marker, "utf8").split("\n")[0] === url) {
5486
+ return { action: "clone-failed", detail: readFileSync15(marker, "utf8").split("\n").slice(1).join("\n"), repeat: true };
5333
5487
  }
5334
5488
  try {
5335
5489
  ensureRepoCheckout(dir, githubRemote, clone);
5336
5490
  } catch (e) {
5337
5491
  if (!(e instanceof GitError)) throw e;
5338
- writeFileSync10(marker, `${url}
5492
+ writeFileSync11(marker, `${url}
5339
5493
  ${e.message}`);
5340
5494
  return { action: "clone-failed", detail: e.message, repeat: false };
5341
5495
  }
@@ -5561,7 +5715,7 @@ function noteHeldWorktree(state, h, nowMs = Date.now()) {
5561
5715
  function reconcileHeldWorktrees(state, repo, log, stillRefused) {
5562
5716
  for (const i of state.shipAttention().previous()) {
5563
5717
  if (i.kind !== "worktree_held" || !i.held || i.held.repo !== repo) continue;
5564
- const gone = !existsSync14(i.held.path);
5718
+ const gone = !existsSync15(i.held.path);
5565
5719
  if (!gone && !(stillRefused && !stillRefused.has(i.held.path))) continue;
5566
5720
  clearShipAttention(state, i.key);
5567
5721
  log.emit(
@@ -5679,6 +5833,18 @@ function repoFindings(o) {
5679
5833
  remedy: "add the directory holding it to ship.extraPath in crew.yaml"
5680
5834
  });
5681
5835
  }
5836
+ if (o.intelSyntax) {
5837
+ if (o.intelSyntax.status === "error") {
5838
+ problems.push({
5839
+ severity: "attention",
5840
+ kind: "intel_hook_syntax",
5841
+ ...at,
5842
+ hook: "intel",
5843
+ message: `${o.route}/${o.repo}: the intel hook fails its syntax check, so no symbol service will start: ${(o.intelSyntax.message ?? "").split("\n")[0]}`,
5844
+ remedy: "fix hooks.intel in the repository's .crew.yaml (`crew repos check` prints the full error)"
5845
+ });
5846
+ } else passed++;
5847
+ }
5682
5848
  return { problems, passed };
5683
5849
  }
5684
5850
  function attentionProblems(items, already) {
@@ -5689,13 +5855,13 @@ function attentionProblems(items, already) {
5689
5855
  // src/sandbox-image.ts
5690
5856
  import { createHash as createHash6 } from "crypto";
5691
5857
  import { spawn as spawn4 } from "child_process";
5692
- import { execFileSync as execFileSync7 } from "child_process";
5693
- import { mkdirSync as mkdirSync15, readFileSync as readFileSync22, renameSync as renameSync3, writeFileSync as writeFileSync16, rmSync as rmSync13 } from "fs";
5694
- import { dirname as dirname11, join as join27 } from "path";
5858
+ import { execFileSync as execFileSync8 } from "child_process";
5859
+ import { mkdirSync as mkdirSync16, readFileSync as readFileSync23, renameSync as renameSync3, writeFileSync as writeFileSync17, rmSync as rmSync13 } from "fs";
5860
+ import { dirname as dirname12, join as join28 } from "path";
5695
5861
  import { tmpdir as tmpdir3 } from "os";
5696
5862
 
5697
5863
  // src/passenger-containers.ts
5698
- import { execFileSync as execFileSync6 } from "child_process";
5864
+ import { execFileSync as execFileSync7 } from "child_process";
5699
5865
  import { createHash as createHash5 } from "crypto";
5700
5866
 
5701
5867
  // src/sandbox-cache.ts
@@ -5704,32 +5870,32 @@ import { promisify as promisify2 } from "util";
5704
5870
 
5705
5871
  // src/deprovision-host.ts
5706
5872
  import { spawnSync as spawnSync6 } from "child_process";
5707
- import { existsSync as existsSync25, readdirSync as readdirSync11 } from "fs";
5873
+ import { existsSync as existsSync26, readdirSync as readdirSync11 } from "fs";
5708
5874
 
5709
5875
  // src/interrupted.ts
5710
- import { existsSync as existsSync23, readdirSync as readdirSync9, readFileSync as readFileSync21 } from "fs";
5711
- import { join as join25 } from "path";
5876
+ import { existsSync as existsSync24, readdirSync as readdirSync9, readFileSync as readFileSync22 } from "fs";
5877
+ import { join as join26 } from "path";
5712
5878
 
5713
5879
  // src/agent.ts
5714
5880
  import { spawnSync as spawnSync5 } from "child_process";
5715
- import { readFileSync as readFileSync20, existsSync as existsSync22, statSync as statSync8, mkdirSync as mkdirSync14, writeFileSync as writeFileSync15, createWriteStream, openSync as openSync3, closeSync as closeSync3, readSync } from "fs";
5881
+ import { readFileSync as readFileSync21, existsSync as existsSync23, statSync as statSync8, mkdirSync as mkdirSync15, writeFileSync as writeFileSync16, createWriteStream, openSync as openSync3, closeSync as closeSync3, readSync } from "fs";
5716
5882
  import { StringDecoder } from "string_decoder";
5717
5883
  import { finished } from "stream/promises";
5718
- import { join as join24, dirname as dirname10, basename as basename9 } from "path";
5884
+ import { join as join25, dirname as dirname11, basename as basename9 } from "path";
5719
5885
  import { createHash as createHash4 } from "crypto";
5720
5886
 
5721
5887
  // src/state.ts
5722
- import { readFileSync as readFileSync15, writeFileSync as writeFileSync11, existsSync as existsSync15, mkdirSync as mkdirSync10, rmSync as rmSync9, statSync as statSync7, readdirSync as readdirSync5 } from "fs";
5723
- import { join as join16 } from "path";
5888
+ import { readFileSync as readFileSync16, writeFileSync as writeFileSync12, existsSync as existsSync16, mkdirSync as mkdirSync11, rmSync as rmSync9, statSync as statSync7, readdirSync as readdirSync5 } from "fs";
5889
+ import { join as join17 } from "path";
5724
5890
  var EPOCH = "1970-01-01T00:00:00.000Z";
5725
5891
  var State = class _State {
5726
5892
  dir;
5727
5893
  constructor(dir) {
5728
5894
  this.dir = dir;
5729
- mkdirSync10(dir, { recursive: true });
5895
+ mkdirSync11(dir, { recursive: true });
5730
5896
  }
5731
5897
  path(...parts) {
5732
- return join16(this.dir, ...parts);
5898
+ return join17(this.dir, ...parts);
5733
5899
  }
5734
5900
  /**
5735
5901
  * The timestamp every "new since last poll" check is measured against.
@@ -5740,14 +5906,14 @@ var State = class _State {
5740
5906
  */
5741
5907
  watermark() {
5742
5908
  try {
5743
- const v = readFileSync15(this.path(".poll-watermark"), "utf8").trim();
5909
+ const v = readFileSync16(this.path(".poll-watermark"), "utf8").trim();
5744
5910
  return v || EPOCH;
5745
5911
  } catch {
5746
5912
  return EPOCH;
5747
5913
  }
5748
5914
  }
5749
5915
  setWatermark(at) {
5750
- writeFileSync11(this.path(".poll-watermark"), `${at}
5916
+ writeFileSync12(this.path(".poll-watermark"), `${at}
5751
5917
  `);
5752
5918
  }
5753
5919
  /**
@@ -5765,16 +5931,16 @@ var State = class _State {
5765
5931
  }
5766
5932
  /** Whole-crew pause, and the per-role sentinels one level down. */
5767
5933
  isPaused() {
5768
- return existsSync15(this.path(".crew-paused"));
5934
+ return existsSync16(this.path(".crew-paused"));
5769
5935
  }
5770
5936
  isRolePaused(role) {
5771
- return existsSync15(this.path(`.role-paused-${role}`));
5937
+ return existsSync16(this.path(`.role-paused-${role}`));
5772
5938
  }
5773
5939
  pausedRoles(roles) {
5774
5940
  return new Set(roles.filter((r) => this.isRolePaused(r)));
5775
5941
  }
5776
5942
  pause(role) {
5777
- writeFileSync11(role ? this.path(`.role-paused-${role}`) : this.path(".crew-paused"), "");
5943
+ writeFileSync12(role ? this.path(`.role-paused-${role}`) : this.path(".crew-paused"), "");
5778
5944
  }
5779
5945
  resume(role) {
5780
5946
  rmSync9(role ? this.path(`.role-paused-${role}`) : this.path(".crew-paused"), { force: true });
@@ -5785,10 +5951,10 @@ var State = class _State {
5785
5951
  * while agents keep working.
5786
5952
  */
5787
5953
  isReleasePaused() {
5788
- return existsSync15(this.path(".release-paused"));
5954
+ return existsSync16(this.path(".release-paused"));
5789
5955
  }
5790
5956
  setReleasePaused(paused) {
5791
- if (paused) writeFileSync11(this.path(".release-paused"), "");
5957
+ if (paused) writeFileSync12(this.path(".release-paused"), "");
5792
5958
  else rmSync9(this.path(".release-paused"), { force: true });
5793
5959
  }
5794
5960
  /**
@@ -5826,7 +5992,7 @@ var State = class _State {
5826
5992
  const name = _State.safe(rawName);
5827
5993
  const file = this.path(`.${name}.lock`);
5828
5994
  try {
5829
- const existing = Number.parseInt(readFileSync15(file, "utf8").trim(), 10);
5995
+ const existing = Number.parseInt(readFileSync16(file, "utf8").trim(), 10);
5830
5996
  if (Number.isFinite(existing) && existing > 0) {
5831
5997
  try {
5832
5998
  process.kill(existing, 0);
@@ -5836,7 +6002,7 @@ var State = class _State {
5836
6002
  }
5837
6003
  } catch {
5838
6004
  }
5839
- writeFileSync11(file, `${process.pid}
6005
+ writeFileSync12(file, `${process.pid}
5840
6006
  `);
5841
6007
  return {
5842
6008
  ok: true,
@@ -5864,7 +6030,7 @@ var State = class _State {
5864
6030
  if (!/^\.release-.+\.lock$/.test(n)) continue;
5865
6031
  let pid = 0;
5866
6032
  try {
5867
- pid = Number.parseInt(readFileSync15(this.path(n), "utf8").trim(), 10);
6033
+ pid = Number.parseInt(readFileSync16(this.path(n), "utf8").trim(), 10);
5868
6034
  } catch {
5869
6035
  continue;
5870
6036
  }
@@ -5950,7 +6116,7 @@ var State = class _State {
5950
6116
  ticketInFlight(recordId) {
5951
6117
  const file = this.path(`.${_State.safe(`crew-ticket-${recordId}`)}.lock`);
5952
6118
  try {
5953
- const pid = Number.parseInt(readFileSync15(file, "utf8").trim(), 10);
6119
+ const pid = Number.parseInt(readFileSync16(file, "utf8").trim(), 10);
5954
6120
  if (!Number.isFinite(pid) || pid <= 0) return false;
5955
6121
  process.kill(pid, 0);
5956
6122
  return true;
@@ -5984,7 +6150,7 @@ var State = class _State {
5984
6150
  const heldReported = `.release-held-${suffix}`;
5985
6151
  const read = (f) => {
5986
6152
  try {
5987
- return readFileSync15(this.path(f), "utf8").trim() || null;
6153
+ return readFileSync16(this.path(f), "utf8").trim() || null;
5988
6154
  } catch {
5989
6155
  return null;
5990
6156
  }
@@ -5993,7 +6159,7 @@ var State = class _State {
5993
6159
  blockedCount: () => Number.parseInt(read(blocked) ?? "", 10) || 0,
5994
6160
  noteBlocked: () => {
5995
6161
  const n = (Number.parseInt(read(blocked) ?? "", 10) || 0) + 1;
5996
- writeFileSync11(this.path(blocked), `${n}
6162
+ writeFileSync12(this.path(blocked), `${n}
5997
6163
  `);
5998
6164
  return n;
5999
6165
  },
@@ -6010,7 +6176,7 @@ var State = class _State {
6010
6176
  */
6011
6177
  deployFailedSha: () => read(failed),
6012
6178
  noteDeployFailed: (sha) => {
6013
- writeFileSync11(this.path(failed), `${sha}
6179
+ writeFileSync12(this.path(failed), `${sha}
6014
6180
  `);
6015
6181
  },
6016
6182
  clearDeployFailed: () => {
@@ -6024,7 +6190,7 @@ var State = class _State {
6024
6190
  noteTestGateFailed: (sha) => {
6025
6191
  const [prev, n] = (read(gateFailed) ?? "").split(" ");
6026
6192
  const next = prev === sha ? (Number.parseInt(n ?? "", 10) || 0) + 1 : 1;
6027
- writeFileSync11(this.path(gateFailed), `${sha} ${next}
6193
+ writeFileSync12(this.path(gateFailed), `${sha} ${next}
6028
6194
  `);
6029
6195
  return next;
6030
6196
  },
@@ -6034,13 +6200,13 @@ var State = class _State {
6034
6200
  /** Whether the board was already told about this head's red gate. */
6035
6201
  heldReported: () => {
6036
6202
  try {
6037
- return readFileSync15(this.path(heldReported), "utf8").replace(/\n$/, "") || null;
6203
+ return readFileSync16(this.path(heldReported), "utf8").replace(/\n$/, "") || null;
6038
6204
  } catch {
6039
6205
  return null;
6040
6206
  }
6041
6207
  },
6042
6208
  noteHeldReported: (signature) => {
6043
- writeFileSync11(this.path(heldReported), `${signature}
6209
+ writeFileSync12(this.path(heldReported), `${signature}
6044
6210
  `);
6045
6211
  },
6046
6212
  clearHeldReported: () => {
@@ -6048,7 +6214,7 @@ var State = class _State {
6048
6214
  },
6049
6215
  testGateReported: (sha) => read(gateReported) === sha,
6050
6216
  noteTestGateReported: (sha) => {
6051
- writeFileSync11(this.path(gateReported), `${sha}
6217
+ writeFileSync12(this.path(gateReported), `${sha}
6052
6218
  `);
6053
6219
  }
6054
6220
  };
@@ -6071,7 +6237,7 @@ var State = class _State {
6071
6237
  const ticketStreakFile = `.fairness-ticket-streak-${suffix}`;
6072
6238
  const read = (f) => {
6073
6239
  try {
6074
- return readFileSync15(this.path(f), "utf8").trim() || null;
6240
+ return readFileSync16(this.path(f), "utf8").trim() || null;
6075
6241
  } catch {
6076
6242
  return null;
6077
6243
  }
@@ -6104,18 +6270,18 @@ var State = class _State {
6104
6270
  clear2();
6105
6271
  return;
6106
6272
  }
6107
- writeFileSync11(this.path(streakFile), `${this.readInt(streakFile) + 1}
6273
+ writeFileSync12(this.path(streakFile), `${this.readInt(streakFile) + 1}
6108
6274
  `);
6109
6275
  const prior = read(ticketFile);
6110
6276
  if (topTicket && topTicket === prior) {
6111
- writeFileSync11(this.path(ticketStreakFile), `${this.readInt(ticketStreakFile) + 1}
6277
+ writeFileSync12(this.path(ticketStreakFile), `${this.readInt(ticketStreakFile) + 1}
6112
6278
  `);
6113
6279
  } else if (topTicket) {
6114
- writeFileSync11(this.path(ticketFile), `${topTicket}
6280
+ writeFileSync12(this.path(ticketFile), `${topTicket}
6115
6281
  `);
6116
- writeFileSync11(this.path(sinceFile), `${(/* @__PURE__ */ new Date()).toISOString()}
6282
+ writeFileSync12(this.path(sinceFile), `${(/* @__PURE__ */ new Date()).toISOString()}
6117
6283
  `);
6118
- writeFileSync11(this.path(ticketStreakFile), "1\n");
6284
+ writeFileSync12(this.path(ticketStreakFile), "1\n");
6119
6285
  }
6120
6286
  }
6121
6287
  };
@@ -6136,14 +6302,14 @@ var State = class _State {
6136
6302
  return {
6137
6303
  previous: () => {
6138
6304
  try {
6139
- const parsed = JSON.parse(readFileSync15(this.path(file), "utf8"));
6305
+ const parsed = JSON.parse(readFileSync16(this.path(file), "utf8"));
6140
6306
  return parsed && typeof parsed === "object" ? parsed : {};
6141
6307
  } catch {
6142
6308
  return {};
6143
6309
  }
6144
6310
  },
6145
6311
  persist: (next) => {
6146
- writeFileSync11(this.path(file), JSON.stringify(next));
6312
+ writeFileSync12(this.path(file), JSON.stringify(next));
6147
6313
  }
6148
6314
  };
6149
6315
  }
@@ -6159,14 +6325,14 @@ var State = class _State {
6159
6325
  return {
6160
6326
  previous: () => {
6161
6327
  try {
6162
- const parsed = JSON.parse(readFileSync15(this.path(file), "utf8"));
6328
+ const parsed = JSON.parse(readFileSync16(this.path(file), "utf8"));
6163
6329
  return Array.isArray(parsed) ? parsed.filter((x) => typeof x === "string") : [];
6164
6330
  } catch {
6165
6331
  return [];
6166
6332
  }
6167
6333
  },
6168
6334
  persist: (next) => {
6169
- writeFileSync11(this.path(file), JSON.stringify(next));
6335
+ writeFileSync12(this.path(file), JSON.stringify(next));
6170
6336
  }
6171
6337
  };
6172
6338
  }
@@ -6180,14 +6346,14 @@ var State = class _State {
6180
6346
  return {
6181
6347
  previous: () => {
6182
6348
  try {
6183
- const parsed = JSON.parse(readFileSync15(this.path(file), "utf8"));
6349
+ const parsed = JSON.parse(readFileSync16(this.path(file), "utf8"));
6184
6350
  return Array.isArray(parsed) ? parsed : [];
6185
6351
  } catch {
6186
6352
  return [];
6187
6353
  }
6188
6354
  },
6189
6355
  persist: (next) => {
6190
- writeFileSync11(this.path(file), JSON.stringify(next));
6356
+ writeFileSync12(this.path(file), JSON.stringify(next));
6191
6357
  }
6192
6358
  };
6193
6359
  }
@@ -6200,7 +6366,7 @@ var State = class _State {
6200
6366
  const file = ".release-last-run";
6201
6367
  return {
6202
6368
  touch: () => {
6203
- writeFileSync11(this.path(file), (/* @__PURE__ */ new Date()).toISOString());
6369
+ writeFileSync12(this.path(file), (/* @__PURE__ */ new Date()).toISOString());
6204
6370
  },
6205
6371
  at: () => {
6206
6372
  try {
@@ -6213,7 +6379,7 @@ var State = class _State {
6213
6379
  }
6214
6380
  readInt(file) {
6215
6381
  try {
6216
- return Number.parseInt(readFileSync15(this.path(file), "utf8").trim(), 10) || 0;
6382
+ return Number.parseInt(readFileSync16(this.path(file), "utf8").trim(), 10) || 0;
6217
6383
  } catch {
6218
6384
  return 0;
6219
6385
  }
@@ -6292,6 +6458,7 @@ var HOOK_PURPOSE = [
6292
6458
  ["ports", "this worktree's port assignments; prints KEY=value overrides to export"],
6293
6459
  ["handoff", "leave the operator able to open what you built; put its output in your progress comment"],
6294
6460
  ["preview", "start this worktree's dev server for a viewer, bound to CREW_PREVIEW_HOST, detached; its last stdout line is the URL"],
6461
+ ["intel", "start this worktree's symbol service, loopback only, detached; its last stdout line is the URL of an MCP endpoint"],
6295
6462
  ["map", 'prints an outline of the repository; the crew places it under "Repository map" below'],
6296
6463
  ["test", "run the suite"],
6297
6464
  ["build", "build it"],
@@ -6766,8 +6933,8 @@ var PERISCOPE_COLUMNS = [
6766
6933
  ];
6767
6934
 
6768
6935
  // src/agent-log.ts
6769
- import { existsSync as existsSync16, mkdirSync as mkdirSync11, readdirSync as readdirSync6, readFileSync as readFileSync16, rmSync as rmSync10, writeFileSync as writeFileSync12 } from "fs";
6770
- import { join as join17 } from "path";
6936
+ import { existsSync as existsSync17, mkdirSync as mkdirSync12, readdirSync as readdirSync6, readFileSync as readFileSync17, rmSync as rmSync10, writeFileSync as writeFileSync13 } from "fs";
6937
+ import { join as join18 } from "path";
6771
6938
 
6772
6939
  // src/pending-backoff.ts
6773
6940
  var sleepBackoff = (attempts) => Math.min(6e4 * 2 ** Math.max(0, attempts - 1), 30 * 6e4);
@@ -6939,20 +7106,20 @@ async function addRunToTicket(target, t, recordId, run3) {
6939
7106
  };
6940
7107
  }
6941
7108
  }
6942
- var queueDir = (stateDir) => join17(stateDir, "pending-agent-logs");
7109
+ var queueDir = (stateDir) => join18(stateDir, "pending-agent-logs");
6943
7110
  function queueAgentRun(stateDir, name, q2) {
6944
- mkdirSync11(queueDir(stateDir), { recursive: true });
6945
- writeFileSync12(join17(queueDir(stateDir), `${name}.json`), JSON.stringify(q2));
7111
+ mkdirSync12(queueDir(stateDir), { recursive: true });
7112
+ writeFileSync13(join18(queueDir(stateDir), `${name}.json`), JSON.stringify(q2));
6946
7113
  }
6947
7114
  async function replayQueuedAgentRuns(stateDir, route2, keyFor, log, now = /* @__PURE__ */ new Date()) {
6948
7115
  const dir = queueDir(stateDir);
6949
- if (!existsSync16(dir)) return 0;
7116
+ if (!existsSync17(dir)) return 0;
6950
7117
  let sent = 0;
6951
7118
  for (const f of readdirSync6(dir).filter((n) => n.endsWith(".json")).sort()) {
6952
- const path = join17(dir, f);
7119
+ const path = join18(dir, f);
6953
7120
  let q2;
6954
7121
  try {
6955
- q2 = JSON.parse(readFileSync16(path, "utf8"));
7122
+ q2 = JSON.parse(readFileSync17(path, "utf8"));
6956
7123
  } catch {
6957
7124
  continue;
6958
7125
  }
@@ -6981,7 +7148,7 @@ async function replayQueuedAgentRuns(stateDir, route2, keyFor, log, now = /* @__
6981
7148
  continue;
6982
7149
  }
6983
7150
  const attempts = q2.attempts + 1;
6984
- writeFileSync12(path, JSON.stringify({
7151
+ writeFileSync13(path, JSON.stringify({
6985
7152
  ...q2,
6986
7153
  attempts,
6987
7154
  warned: true,
@@ -6992,20 +7159,20 @@ async function replayQueuedAgentRuns(stateDir, route2, keyFor, log, now = /* @__
6992
7159
  }
6993
7160
  return sent;
6994
7161
  }
6995
- var countersDir = (stateDir) => join17(stateDir, "pending-ticket-counters");
7162
+ var countersDir = (stateDir) => join18(stateDir, "pending-ticket-counters");
6996
7163
  function queueTicketCounters(stateDir, name, q2) {
6997
- mkdirSync11(countersDir(stateDir), { recursive: true });
6998
- writeFileSync12(join17(countersDir(stateDir), `${name}.json`), JSON.stringify(q2));
7164
+ mkdirSync12(countersDir(stateDir), { recursive: true });
7165
+ writeFileSync13(join18(countersDir(stateDir), `${name}.json`), JSON.stringify(q2));
6999
7166
  }
7000
7167
  async function replayQueuedTicketCounters(stateDir, route2, keyFor, log, now = /* @__PURE__ */ new Date()) {
7001
7168
  const dir = countersDir(stateDir);
7002
- if (!existsSync16(dir)) return 0;
7169
+ if (!existsSync17(dir)) return 0;
7003
7170
  let sent = 0;
7004
7171
  for (const f of readdirSync6(dir).filter((n) => n.endsWith(".json")).sort()) {
7005
- const path = join17(dir, f);
7172
+ const path = join18(dir, f);
7006
7173
  let q2;
7007
7174
  try {
7008
- q2 = JSON.parse(readFileSync16(path, "utf8"));
7175
+ q2 = JSON.parse(readFileSync17(path, "utf8"));
7009
7176
  } catch {
7010
7177
  continue;
7011
7178
  }
@@ -7024,7 +7191,7 @@ async function replayQueuedTicketCounters(stateDir, route2, keyFor, log, now = /
7024
7191
  continue;
7025
7192
  }
7026
7193
  const attempts = q2.attempts + 1;
7027
- writeFileSync12(path, JSON.stringify({
7194
+ writeFileSync13(path, JSON.stringify({
7028
7195
  ...q2,
7029
7196
  attempts,
7030
7197
  warned: true,
@@ -7227,8 +7394,8 @@ var HandoffTranscriptTracker = class {
7227
7394
  };
7228
7395
 
7229
7396
  // src/pending-handoff.ts
7230
- import { existsSync as existsSync19, mkdirSync as mkdirSync12, readdirSync as readdirSync7, readFileSync as readFileSync17, rmSync as rmSync11, writeFileSync as writeFileSync13 } from "fs";
7231
- import { join as join20 } from "path";
7397
+ import { existsSync as existsSync20, mkdirSync as mkdirSync13, readdirSync as readdirSync7, readFileSync as readFileSync18, rmSync as rmSync11, writeFileSync as writeFileSync14 } from "fs";
7398
+ import { join as join21 } from "path";
7232
7399
 
7233
7400
  // src/ticket-branch.ts
7234
7401
  import { basename as basename7 } from "path";
@@ -8394,16 +8561,16 @@ function holdWarnings(tickets, ships, contract, humanHolds, now = Date.now()) {
8394
8561
  }
8395
8562
 
8396
8563
  // src/run-worktree.ts
8397
- import { existsSync as existsSync18 } from "fs";
8398
- import { dirname as dirname8, join as join19 } from "path";
8564
+ import { existsSync as existsSync19 } from "fs";
8565
+ import { dirname as dirname9, join as join20 } from "path";
8399
8566
 
8400
8567
  // src/ports.ts
8401
- import { execFileSync as execFileSync4 } from "child_process";
8402
- import { existsSync as existsSync17 } from "fs";
8403
- import { join as join18 } from "path";
8568
+ import { execFileSync as execFileSync5 } from "child_process";
8569
+ import { existsSync as existsSync18 } from "fs";
8570
+ import { join as join19 } from "path";
8404
8571
  var run = (cmd, args) => {
8405
8572
  try {
8406
- return execFileSync4(cmd, args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
8573
+ return execFileSync5(cmd, args, { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] });
8407
8574
  } catch {
8408
8575
  return "";
8409
8576
  }
@@ -8445,7 +8612,7 @@ function ticketForPort(port, s = DEFAULT_PORTS) {
8445
8612
  }
8446
8613
  function worktreeExists(parent, prefix, n) {
8447
8614
  for (const name of [`${prefix}${n}`, `${prefix}${String(n).padStart(3, "0")}`]) {
8448
- if (existsSync17(join18(parent, name, ".git"))) return true;
8615
+ if (existsSync18(join19(parent, name, ".git"))) return true;
8449
8616
  }
8450
8617
  return false;
8451
8618
  }
@@ -8528,7 +8695,7 @@ function planRunWorktree(dir, cfg, t, role, opts = {}) {
8528
8695
  const existing = worktreeForNumber(dir, num);
8529
8696
  const located = locateBranchForTicket(dir, cfg, t, role);
8530
8697
  const baseRef = hasRemote ? `${remote}/${base}` : base;
8531
- if (existing && !existing.prunable && existsSync18(existing.path)) {
8698
+ if (existing && !existing.prunable && existsSync19(existing.path)) {
8532
8699
  const branch = existing.branch;
8533
8700
  if (status(existing.path).length > 0) {
8534
8701
  return { action: opts.resumeInterrupted ? "resume-dirty" : "leave-dirty", path: existing.path, branch };
@@ -8544,7 +8711,7 @@ function planRunWorktree(dir, cfg, t, role, opts = {}) {
8544
8711
  if (countCommits(existing.path, `${baseRef}..HEAD`) > 0) return { action: "leave-unpushed", path: existing.path, branch };
8545
8712
  return { action: "recut", path: existing.path, branch, base: baseRef };
8546
8713
  }
8547
- const path = join19(dirname8(dir), worktreeForTicket(dir, cfg, t, role));
8714
+ const path = join20(dirname9(dir), worktreeForTicket(dir, cfg, t, role));
8548
8715
  if (located?.where === "remote" || located && hasRemote && remoteBranchExists(dir, remote, located.branch)) {
8549
8716
  return { action: "cut-remote", path, branch: located.branch };
8550
8717
  }
@@ -8598,7 +8765,7 @@ function dropEmptyRunBranch(dir, cfg, branch) {
8598
8765
  if (remoteConfigured(dir, remote) && remoteBranchExists(dir, remote, branch)) return false;
8599
8766
  if (countCommits(dir, `${baseRef}..${branch}`) !== 0) return false;
8600
8767
  const wt = worktrees(dir).find((w) => w.branch === branch && !w.prunable && w.path !== dir);
8601
- if (wt && existsSync18(wt.path)) {
8768
+ if (wt && existsSync19(wt.path)) {
8602
8769
  if (status(wt.path).length > 0) return false;
8603
8770
  if (gitOk(dir, ["worktree", "remove", wt.path]) === null) return false;
8604
8771
  }
@@ -8606,7 +8773,7 @@ function dropEmptyRunBranch(dir, cfg, branch) {
8606
8773
  }
8607
8774
  async function finishRunWorktree(dir, cfg, branch) {
8608
8775
  const wt = worktrees(dir).find((w) => w.branch === branch && !w.prunable && w.path !== dir);
8609
- if (!wt || !existsSync18(wt.path)) return { kind: "none" };
8776
+ if (!wt || !existsSync19(wt.path)) return { kind: "none" };
8610
8777
  if (cfg.hooks.handoff) return { kind: "kept-handoff", path: wt.path };
8611
8778
  if (status(wt.path).length > 0) return { kind: "kept-dirty", path: wt.path };
8612
8779
  if (remoteConfigured(dir, cfg.branch.remote) && worktreeHoldsUnpushed(wt.path, cfg.branch.remote)) {
@@ -8618,7 +8785,7 @@ async function finishRunWorktree(dir, cfg, branch) {
8618
8785
  if (pids.length) await killGently(pids);
8619
8786
  }
8620
8787
  gitOk(dir, ["worktree", "remove", wt.path]);
8621
- return existsSync18(wt.path) ? { kind: "kept-dirty", path: wt.path } : { kind: "removed", path: wt.path };
8788
+ return existsSync19(wt.path) ? { kind: "kept-dirty", path: wt.path } : { kind: "removed", path: wt.path };
8622
8789
  }
8623
8790
 
8624
8791
  // src/handoff-guard.ts
@@ -9001,20 +9168,20 @@ async function guardRunStrays(route2, ship, tracker, role, workingId, since2, lo
9001
9168
 
9002
9169
  // src/pending-handoff.ts
9003
9170
  var PENDING_MAX_AGE_MS = 48 * 36e5;
9004
- var pendingDirFor = (stateDir) => join20(stateDir, "pending-handoffs");
9005
- var stateDirOfStream = (streamPath) => join20(streamPath, "..", "..");
9171
+ var pendingDirFor = (stateDir) => join21(stateDir, "pending-handoffs");
9172
+ var stateDirOfStream = (streamPath) => join21(streamPath, "..", "..");
9006
9173
  function writePendingHandoff(stateDir, rec) {
9007
9174
  const dir = pendingDirFor(stateDir);
9008
- mkdirSync12(dir, { recursive: true });
9009
- writeFileSync13(join20(dir, `${rec.ticketRecordId}.json`), JSON.stringify(rec, null, 2));
9175
+ mkdirSync13(dir, { recursive: true });
9176
+ writeFileSync14(join21(dir, `${rec.ticketRecordId}.json`), JSON.stringify(rec, null, 2));
9010
9177
  }
9011
9178
  function listPendingHandoffs(stateDir, route2) {
9012
9179
  const dir = pendingDirFor(stateDir);
9013
- if (!existsSync19(dir)) return [];
9180
+ if (!existsSync20(dir)) return [];
9014
9181
  const out = [];
9015
9182
  for (const f of readdirSync7(dir).filter((n) => n.endsWith(".json")).sort()) {
9016
9183
  try {
9017
- const rec = JSON.parse(readFileSync17(join20(dir, f), "utf8"));
9184
+ const rec = JSON.parse(readFileSync18(join21(dir, f), "utf8"));
9018
9185
  if (rec.version === 1 && rec.ticketRecordId && (!route2 || rec.route === route2)) out.push(rec);
9019
9186
  } catch {
9020
9187
  }
@@ -9022,7 +9189,7 @@ function listPendingHandoffs(stateDir, route2) {
9022
9189
  return out;
9023
9190
  }
9024
9191
  function removePendingHandoff(stateDir, ticketRecordId) {
9025
- rmSync11(join20(pendingDirFor(stateDir), `${ticketRecordId}.json`), { force: true });
9192
+ rmSync11(join21(pendingDirFor(stateDir), `${ticketRecordId}.json`), { force: true });
9026
9193
  }
9027
9194
  function pendingHandoffFor(stateDir, ticketRecordId) {
9028
9195
  return listPendingHandoffs(stateDir).find((r) => r.ticketRecordId === ticketRecordId);
@@ -9132,8 +9299,8 @@ function expandSkillMarkers(text2, lookup2, opts = {}) {
9132
9299
  }
9133
9300
 
9134
9301
  // src/skills.ts
9135
- import { readFileSync as readFileSync19, readdirSync as readdirSync8, existsSync as existsSync21 } from "fs";
9136
- import { join as join22 } from "path";
9302
+ import { readFileSync as readFileSync20, readdirSync as readdirSync8, existsSync as existsSync22 } from "fs";
9303
+ import { join as join23 } from "path";
9137
9304
  import { parse as parseYaml } from "yaml";
9138
9305
  import { TablationClient as TablationClient3, StaleWriteError as StaleWriteError3, TablationApiError as TablationApiError2 } from "@tablation/client";
9139
9306
 
@@ -9149,8 +9316,8 @@ ${additions}`;
9149
9316
  }
9150
9317
 
9151
9318
  // src/agents.ts
9152
- import { readFileSync as readFileSync18, existsSync as existsSync20 } from "fs";
9153
- import { join as join21 } from "path";
9319
+ import { readFileSync as readFileSync19, existsSync as existsSync21 } from "fs";
9320
+ import { join as join22 } from "path";
9154
9321
  import { TablationClient as TablationClient2, StaleWriteError as StaleWriteError2, TablationApiError } from "@tablation/client";
9155
9322
  var PERSONA_NAME = {
9156
9323
  dev: "Developer",
@@ -9164,12 +9331,12 @@ var CREW_AGENT_COLUMN = "agent_id";
9164
9331
  var AgentsSyncError = class extends Error {
9165
9332
  };
9166
9333
  function personaDefaultPrompt(promptsDir, role) {
9167
- const briefPath = join21(promptsDir, "personas", `lane-${role}.md`);
9168
- if (!existsSync20(briefPath)) throw new AgentsSyncError(`no brief at ${briefPath}`);
9169
- if (SELF_CONTAINED_ROLES.has(role)) return readFileSync18(briefPath, "utf8");
9170
- const commonPath = join21(promptsDir, "personas", "common.md");
9171
- if (!existsSync20(commonPath)) return readFileSync18(briefPath, "utf8");
9172
- return `${readFileSync18(commonPath, "utf8")}${readFileSync18(briefPath, "utf8")}`;
9334
+ const briefPath = join22(promptsDir, "personas", `lane-${role}.md`);
9335
+ if (!existsSync21(briefPath)) throw new AgentsSyncError(`no brief at ${briefPath}`);
9336
+ if (SELF_CONTAINED_ROLES.has(role)) return readFileSync19(briefPath, "utf8");
9337
+ const commonPath = join22(promptsDir, "personas", "common.md");
9338
+ if (!existsSync21(commonPath)) return readFileSync19(briefPath, "utf8");
9339
+ return `${readFileSync19(commonPath, "utf8")}${readFileSync19(briefPath, "utf8")}`;
9173
9340
  }
9174
9341
  async function resolveAgentId(route2, role, opts) {
9175
9342
  const cached = route2.resolved?.agentPersonas?.[role]?.agentId;
@@ -9616,7 +9783,7 @@ function describeCrewLink(o) {
9616
9783
  var SkillSyncError = class extends Error {
9617
9784
  };
9618
9785
  function parseSkillFile(path) {
9619
- const text2 = readFileSync19(path, "utf8");
9786
+ const text2 = readFileSync20(path, "utf8");
9620
9787
  const match = /^---\n([\s\S]*?)\n---\n([\s\S]*)$/.exec(text2);
9621
9788
  if (!match) throw new SkillSyncError(`${path}: missing YAML frontmatter (expected a leading --- block)`);
9622
9789
  const frontmatter = match[1];
@@ -9629,9 +9796,9 @@ function parseSkillFile(path) {
9629
9796
  return { name: meta.name, description: meta.description, prompt: body, file: path };
9630
9797
  }
9631
9798
  function listLocalSkills(promptsDir) {
9632
- const dir = join22(promptsDir, "skills");
9633
- if (!existsSync21(dir)) return [];
9634
- return readdirSync8(dir).filter((f) => f.endsWith(".md")).map((f) => parseSkillFile(join22(dir, f)));
9799
+ const dir = join23(promptsDir, "skills");
9800
+ if (!existsSync22(dir)) return [];
9801
+ return readdirSync8(dir).filter((f) => f.endsWith(".md")).map((f) => parseSkillFile(join23(dir, f)));
9635
9802
  }
9636
9803
  async function syncSkills(route2, opts) {
9637
9804
  if (!route2.resolved) {
@@ -9815,10 +9982,10 @@ function skillMarkerWarnings(promptsDir, personaPrompts) {
9815
9982
  }
9816
9983
 
9817
9984
  // src/runner.ts
9818
- import { spawn as spawn2, execFile, execFileSync as execFileSync5 } from "child_process";
9819
- import { mkdtempSync, mkdirSync as mkdirSync13, writeFileSync as writeFileSync14, rmSync as rmSync12 } from "fs";
9985
+ import { spawn as spawn2, execFile, execFileSync as execFileSync6 } from "child_process";
9986
+ import { mkdtempSync, mkdirSync as mkdirSync14, writeFileSync as writeFileSync15, rmSync as rmSync12 } from "fs";
9820
9987
  import { tmpdir as tmpdir2 } from "os";
9821
- import { basename as basename8, dirname as dirname9, join as join23 } from "path";
9988
+ import { basename as basename8, dirname as dirname10, join as join24 } from "path";
9822
9989
  import { promisify } from "util";
9823
9990
 
9824
9991
  // src/run-limit.ts
@@ -9947,8 +10114,8 @@ var SandboxRunner = class {
9947
10114
  throw new Error(`cannot generate the sandbox policy: ${e.message}`);
9948
10115
  }
9949
10116
  policyFile = policyPathFor(plan.streamPath);
9950
- mkdirSync13(dirname9(policyFile), { recursive: true });
9951
- writeFileSync14(policyFile, generated.yaml, { mode: 384 });
10117
+ mkdirSync14(dirname10(policyFile), { recursive: true });
10118
+ writeFileSync15(policyFile, generated.yaml, { mode: 384 });
9952
10119
  }
9953
10120
  const create2 = ["sandbox", "create", "--name", name, "--detach"];
9954
10121
  if (policyFile) create2.push("--policy", policyFile);
@@ -9991,10 +10158,10 @@ var SandboxRunner = class {
9991
10158
  const harness = cfg.agentBin ?? basename8(plan.bin);
9992
10159
  const viaUpload = Buffer.byteLength(plan.prompt) > SANDBOX_STDIN_LIMIT;
9993
10160
  if (viaUpload) {
9994
- const tmp = mkdtempSync(join23(tmpdir2(), "crew-prompt-"));
10161
+ const tmp = mkdtempSync(join24(tmpdir2(), "crew-prompt-"));
9995
10162
  try {
9996
- const file = join23(tmp, "prompt.txt");
9997
- writeFileSync14(file, plan.prompt, { mode: 384 });
10163
+ const file = join24(tmp, "prompt.txt");
10164
+ writeFileSync15(file, plan.prompt, { mode: 384 });
9998
10165
  await this.os(["sandbox", "upload", name, file, SANDBOX_PROMPT_PATH]);
9999
10166
  } finally {
10000
10167
  rmSync12(tmp, { recursive: true, force: true });
@@ -10060,7 +10227,7 @@ function describeExecError(e) {
10060
10227
  }
10061
10228
  function gitOrigin(cwd) {
10062
10229
  try {
10063
- return execFileSync5("git", ["-C", cwd, "remote", "get-url", "origin"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
10230
+ return execFileSync6("git", ["-C", cwd, "remote", "get-url", "origin"], { encoding: "utf8", stdio: ["ignore", "pipe", "ignore"] }).trim();
10064
10231
  } catch {
10065
10232
  return null;
10066
10233
  }
@@ -10071,7 +10238,7 @@ function runnerFor(kind, sandbox) {
10071
10238
  function runnerOfSidecar(sc) {
10072
10239
  return sc.runner === "sandbox" ? new SandboxRunner(sc.sandboxBin ? { bin: sc.sandboxBin } : {}) : new HostRunner();
10073
10240
  }
10074
- function checkSandboxRunner(cfg = {}, run3 = (b, a) => execFileSync5(b, a, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 15e3 })) {
10241
+ function checkSandboxRunner(cfg = {}, run3 = (b, a) => execFileSync6(b, a, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: 15e3 })) {
10075
10242
  const bin = cfg.bin ?? DEFAULT_SANDBOX_CONFIG.bin;
10076
10243
  let version;
10077
10244
  try {
@@ -10138,7 +10305,7 @@ var ALLOWANCE_REFUSAL_MARKER = "AI_ALLOWANCE_EXCEEDED";
10138
10305
  function streamShowsAllowanceRefusal(streamPath) {
10139
10306
  let raw;
10140
10307
  try {
10141
- raw = readFileSync20(streamPath, "utf8");
10308
+ raw = readFileSync21(streamPath, "utf8");
10142
10309
  } catch {
10143
10310
  return false;
10144
10311
  }
@@ -10161,26 +10328,26 @@ function streamShowsAllowanceRefusal(streamPath) {
10161
10328
  }
10162
10329
  return false;
10163
10330
  }
10164
- var digestPathFor = (stateDir, routeLabel, role, runId) => join24(stateDir, `digest-${routeLabel}-${role}${runId ? `-${runId}` : ""}.md`);
10331
+ var digestPathFor = (stateDir, routeLabel, role, runId) => join25(stateDir, `digest-${routeLabel}-${role}${runId ? `-${runId}` : ""}.md`);
10165
10332
  function planAgentRun(o) {
10166
- const briefPath = join24(o.route.promptsDir, "personas", `lane-${o.role}.md`);
10167
- if (!existsSync22(briefPath)) {
10333
+ const briefPath = join25(o.route.promptsDir, "personas", `lane-${o.role}.md`);
10334
+ if (!existsSync23(briefPath)) {
10168
10335
  throw new AgentError(`no brief at ${briefPath} \u2014 refusing to run an unscoped session`);
10169
10336
  }
10170
- const commonPath = join24(o.route.promptsDir, "personas", "common.md");
10171
- const usesCommon = !SELF_CONTAINED_ROLES.has(o.role) && existsSync22(commonPath);
10337
+ const commonPath = join25(o.route.promptsDir, "personas", "common.md");
10338
+ const usesCommon = !SELF_CONTAINED_ROLES.has(o.role) && existsSync23(commonPath);
10172
10339
  const now = o.now ?? (() => Date.now());
10173
10340
  const routeLabel = routeSlug(o.route.route);
10174
10341
  const ownDigest = o.runId ? digestPathFor(o.stateDir, routeLabel, o.role, o.runId) : void 0;
10175
- const digestPath2 = ownDigest && existsSync22(ownDigest) ? ownDigest : digestPathFor(o.stateDir, routeLabel, o.role);
10342
+ const digestPath2 = ownDigest && existsSync23(ownDigest) ? ownDigest : digestPathFor(o.stateDir, routeLabel, o.role);
10176
10343
  let digest;
10177
10344
  let ageSeconds;
10178
- if (existsSync22(digestPath2)) {
10345
+ if (existsSync23(digestPath2)) {
10179
10346
  ageSeconds = Math.floor((now() - statSync8(digestPath2).mtimeMs) / 1e3);
10180
- if (ageSeconds <= DIGEST_MAX_AGE_SECONDS) digest = readFileSync20(digestPath2, "utf8");
10347
+ if (ageSeconds <= DIGEST_MAX_AGE_SECONDS) digest = readFileSync21(digestPath2, "utf8");
10181
10348
  }
10182
- const common = usesCommon ? readFileSync20(commonPath, "utf8") : "";
10183
- const brief = readFileSync20(briefPath, "utf8");
10349
+ const common = usesCommon ? readFileSync21(commonPath, "utf8") : "";
10350
+ const brief = readFileSync21(briefPath, "utf8");
10184
10351
  const effectiveCommon = o.divergedPrompt ? "" : common;
10185
10352
  const effectiveBrief = appendAdditions(o.divergedPrompt ?? brief, o.personaAdditions);
10186
10353
  const localSkills = new Map(listLocalSkills(o.route.promptsDir).map((s) => [s.name, s.prompt]));
@@ -10203,7 +10370,7 @@ function planAgentRun(o) {
10203
10370
  digest
10204
10371
  });
10205
10372
  const promptSha = createHash4("sha256").update(expanded.text).digest("hex");
10206
- const streamsDir = join24(o.stateDir, "streams");
10373
+ const streamsDir = join25(o.stateDir, "streams");
10207
10374
  const base = `${routeLabel}-${o.role}-${o.cycle}${o.runId ? `-${o.runId}` : ""}`;
10208
10375
  const seat = resolveSeat(o.ship, o.route, o.role, o.agentPersona ?? (o.agentModel ? { model: o.agentModel } : {}), o.repo);
10209
10376
  const { model } = seat;
@@ -10293,8 +10460,8 @@ function planAgentRun(o) {
10293
10460
  digestAttached: digest !== void 0,
10294
10461
  digestAgeSeconds: ageSeconds,
10295
10462
  model,
10296
- streamPath: join24(streamsDir, `${base}.jsonl`),
10297
- eventsPath: join24(streamsDir, `${base}.events.jsonl`),
10463
+ streamPath: join25(streamsDir, `${base}.jsonl`),
10464
+ eventsPath: join25(streamsDir, `${base}.events.jsonl`),
10298
10465
  ticket: o.ticket,
10299
10466
  ticketRecordId: o.ticketRecordId ?? null,
10300
10467
  repo: o.repo ?? null,
@@ -10325,7 +10492,7 @@ function describePlan(p) {
10325
10492
  var pidPathFor = (streamPath) => `${streamPath}.pid`;
10326
10493
  function readRunSidecar(streamPath) {
10327
10494
  try {
10328
- const sc = JSON.parse(readFileSync20(pidPathFor(streamPath), "utf8"));
10495
+ const sc = JSON.parse(readFileSync21(pidPathFor(streamPath), "utf8"));
10329
10496
  return typeof sc.pid === "number" && typeof sc.spawnedAt === "string" && typeof sc.role === "string" ? sc : null;
10330
10497
  } catch {
10331
10498
  return null;
@@ -10372,7 +10539,7 @@ async function killForDeadline(kill, pid, emit, role, ticket, spawnedAt, limitMi
10372
10539
  var withoutKey = ({ apiKey: _apiKey, ...rest }) => rest;
10373
10540
  function openSink(path) {
10374
10541
  try {
10375
- mkdirSync14(dirname10(path), { recursive: true });
10542
+ mkdirSync15(dirname11(path), { recursive: true });
10376
10543
  return createWriteStream(path, { flags: "a" });
10377
10544
  } catch {
10378
10545
  return void 0;
@@ -10554,7 +10721,7 @@ var RunObserver = class {
10554
10721
  };
10555
10722
  function writeRunMeta(id, startedAt, liveTicket, extra) {
10556
10723
  try {
10557
- writeFileSync15(`${id.streamPath}.meta.json`, JSON.stringify({
10724
+ writeFileSync16(`${id.streamPath}.meta.json`, JSON.stringify({
10558
10725
  route: id.route,
10559
10726
  role: id.role,
10560
10727
  hint: id.ticket,
@@ -10714,7 +10881,7 @@ function spawnAgent(plan, emit, hintMoved) {
10714
10881
  const id = identityOf(plan, adapter.harness);
10715
10882
  let streamFd;
10716
10883
  try {
10717
- mkdirSync14(dirname10(plan.streamPath), { recursive: true });
10884
+ mkdirSync15(dirname11(plan.streamPath), { recursive: true });
10718
10885
  streamFd = openSync3(plan.streamPath, "a");
10719
10886
  } catch (e) {
10720
10887
  void endSink(eventsSink);
@@ -10772,7 +10939,7 @@ function spawnAgent(plan, emit, hintMoved) {
10772
10939
  promptSha: plan.promptSha
10773
10940
  };
10774
10941
  try {
10775
- writeFileSync15(pidPathFor(plan.streamPath), JSON.stringify(sidecar));
10942
+ writeFileSync16(pidPathFor(plan.streamPath), JSON.stringify(sidecar));
10776
10943
  } catch {
10777
10944
  }
10778
10945
  }
@@ -10886,21 +11053,21 @@ var pidAlive = (pid) => {
10886
11053
  };
10887
11054
  function runFinished(streamPath) {
10888
11055
  const path = `${streamPath}.meta.json`;
10889
- if (!existsSync23(path)) return false;
11056
+ if (!existsSync24(path)) return false;
10890
11057
  try {
10891
- return JSON.parse(readFileSync21(path, "utf8")).running !== true;
11058
+ return JSON.parse(readFileSync22(path, "utf8")).running !== true;
10892
11059
  } catch {
10893
11060
  return true;
10894
11061
  }
10895
11062
  }
10896
11063
  function orphanedStreams(o) {
10897
- const dir = join25(o.stateDir, "streams");
10898
- if (!existsSync23(dir)) return [];
11064
+ const dir = join26(o.stateDir, "streams");
11065
+ if (!existsSync24(dir)) return [];
10899
11066
  const ownerAlive = o.isOwnerAlive ?? pidAlive;
10900
11067
  const out = [];
10901
11068
  for (const name of readdirSync9(dir)) {
10902
11069
  if (!name.endsWith(".jsonl") || name.endsWith(".events.jsonl")) continue;
10903
- const streamPath = join25(dir, name);
11070
+ const streamPath = join26(dir, name);
10904
11071
  if (runFinished(streamPath)) continue;
10905
11072
  const sidecar = readRunSidecar(streamPath);
10906
11073
  if (!sidecar || sidecar.route !== o.routeLabel) continue;
@@ -10953,15 +11120,15 @@ async function reconcileRuns(o) {
10953
11120
  }
10954
11121
 
10955
11122
  // src/live-runs.ts
10956
- import { existsSync as existsSync24, readdirSync as readdirSync10, statSync as statSync9 } from "fs";
10957
- import { join as join26 } from "path";
11123
+ import { existsSync as existsSync25, readdirSync as readdirSync10, statSync as statSync9 } from "fs";
11124
+ import { join as join27 } from "path";
10958
11125
  function liveRuns(stateDir, isAlive = runIsAlive) {
10959
- const dir = join26(stateDir, "streams");
10960
- if (!existsSync24(dir)) return [];
11126
+ const dir = join27(stateDir, "streams");
11127
+ if (!existsSync25(dir)) return [];
10961
11128
  const out = [];
10962
11129
  for (const name of readdirSync10(dir)) {
10963
11130
  if (!name.endsWith(".jsonl") || name.endsWith(".events.jsonl")) continue;
10964
- const streamPath = join26(dir, name);
11131
+ const streamPath = join27(dir, name);
10965
11132
  if (runFinished(streamPath)) continue;
10966
11133
  const sidecar = readRunSidecar(streamPath);
10967
11134
  if (!sidecar || !isAlive(sidecar)) continue;
@@ -10971,12 +11138,12 @@ function liveRuns(stateDir, isAlive = runIsAlive) {
10971
11138
  }
10972
11139
  function runActivity(stateDir, isAlive = runIsAlive) {
10973
11140
  const activeRuns = liveRuns(stateDir, isAlive).length;
10974
- const dir = join26(stateDir, "streams");
11141
+ const dir = join27(stateDir, "streams");
10975
11142
  let newest = 0;
10976
- if (existsSync24(dir)) {
11143
+ if (existsSync25(dir)) {
10977
11144
  for (const name of readdirSync10(dir)) {
10978
11145
  if (!name.endsWith(".jsonl") || name.endsWith(".events.jsonl")) continue;
10979
- const streamPath = join26(dir, name);
11146
+ const streamPath = join27(dir, name);
10980
11147
  if (!runFinished(streamPath)) continue;
10981
11148
  try {
10982
11149
  newest = Math.max(newest, statSync9(`${streamPath}.meta.json`).mtimeMs);
@@ -11347,7 +11514,7 @@ function realDeprovisionDeps(cfg, emit, crewHome, getStore) {
11347
11514
  if (host === "windows") return [];
11348
11515
  const ctx = installContext();
11349
11516
  const systemd = detectSystemd();
11350
- return ["run", "release", "passengers"].flatMap((job) => planInstall(cfg.ship, crewHome, host, systemd, job, ctx).unitPaths).filter((p) => existsSync25(p));
11517
+ return ["run", "release", "passengers"].flatMap((job) => planInstall(cfg.ship, crewHome, host, systemd, job, ctx).unitPaths).filter((p) => existsSync26(p));
11351
11518
  };
11352
11519
  return {
11353
11520
  liveRuns: () => liveRuns(stateDir).map((r) => ({ role: r.role, route: r.route, pid: r.pid, ticketRecordId: r.ticketRecordId ?? void 0, streamPath: r.streamPath })),
@@ -11408,7 +11575,7 @@ function realDeprovisionDeps(cfg, emit, crewHome, getStore) {
11408
11575
  },
11409
11576
  remaining() {
11410
11577
  const left = [];
11411
- if (existsSync25(cfg.configFile)) left.push(`config ${cfg.configFile}`);
11578
+ if (existsSync26(cfg.configFile)) left.push(`config ${cfg.configFile}`);
11412
11579
  for (const h of forgeHosts()) if (hasForgeToken(cfg.ship.forges, h, stateDir)) left.push(`forge token for ${h}`);
11413
11580
  try {
11414
11581
  for (const k of readdirSync11(keysDir(stateDir))) left.push(`seat key ${k}`);
@@ -11683,7 +11850,7 @@ function makeCachePass(o) {
11683
11850
  // src/passenger-containers.ts
11684
11851
  var realExec2 = (cmd, args, opts) => {
11685
11852
  try {
11686
- return execFileSync6(cmd, args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: opts?.timeoutMs });
11853
+ return execFileSync7(cmd, args, { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], timeout: opts?.timeoutMs });
11687
11854
  } catch (e) {
11688
11855
  const err3 = e;
11689
11856
  const why = [err3.stderr, err3.stdout].map((x) => (x ?? "").trim()).filter(Boolean).join(" / ");
@@ -11963,7 +12130,7 @@ var WARM_MAX_BYTES = 64 * 1024 * 1024;
11963
12130
  var globToRegExp = (glob) => new RegExp(`^${glob.split("*").map((p) => p.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join("[^/]*")}$`);
11964
12131
  function readWarmFiles(dir, ref, patterns) {
11965
12132
  if (patterns.length === 0) return {};
11966
- const git2 = (args) => execFileSync7("git", ["-C", dir, ...args], { encoding: "utf8", maxBuffer: WARM_MAX_BYTES, stdio: ["ignore", "pipe", "pipe"] });
12133
+ const git2 = (args) => execFileSync8("git", ["-C", dir, ...args], { encoding: "utf8", maxBuffer: WARM_MAX_BYTES, stdio: ["ignore", "pipe", "pipe"] });
11967
12134
  const all = git2(["ls-tree", "-r", "--name-only", ref]).split("\n").filter(Boolean);
11968
12135
  const res = patterns.map(globToRegExp);
11969
12136
  const out = {};
@@ -12016,19 +12183,19 @@ function planSandbox(repo, decl, warm = {}) {
12016
12183
  const layer = repoLayer(repo, decl, crew, warm);
12017
12184
  return { repo, tag: layer.tag, claude: SANDBOX_CLAUDE_VERSION, layers: [base, crew, layer] };
12018
12185
  }
12019
- var sandboxStatePath = (stateDir) => join27(stateDir, "sandbox-images.json");
12186
+ var sandboxStatePath = (stateDir) => join28(stateDir, "sandbox-images.json");
12020
12187
  function readSandboxState(stateDir) {
12021
12188
  try {
12022
- const v = JSON.parse(readFileSync22(sandboxStatePath(stateDir), "utf8"));
12189
+ const v = JSON.parse(readFileSync23(sandboxStatePath(stateDir), "utf8"));
12023
12190
  return v && typeof v === "object" && !Array.isArray(v) ? v : {};
12024
12191
  } catch {
12025
12192
  return {};
12026
12193
  }
12027
12194
  }
12028
12195
  function writeSandboxState(stateDir, state) {
12029
- mkdirSync15(stateDir, { recursive: true });
12196
+ mkdirSync16(stateDir, { recursive: true });
12030
12197
  const file = sandboxStatePath(stateDir);
12031
- writeFileSync16(`${file}.tmp`, `${JSON.stringify(state, null, 2)}
12198
+ writeFileSync17(`${file}.tmp`, `${JSON.stringify(state, null, 2)}
12032
12199
  `);
12033
12200
  renameSync3(`${file}.tmp`, file);
12034
12201
  }
@@ -12048,7 +12215,7 @@ var spawnBuildRunner = (engine = "docker") => (args, logPath) => new Promise((re
12048
12215
  child.stdout.on("data", (d) => chunks.push(d));
12049
12216
  child.stderr.on("data", (d) => chunks.push(d));
12050
12217
  const done = (code, extra = "") => {
12051
- writeFileSync16(logPath, `$ ${engine} ${args.join(" ")}
12218
+ writeFileSync17(logPath, `$ ${engine} ${args.join(" ")}
12052
12219
  ${Buffer.concat(chunks).toString("utf8")}${extra}`, { flag: "a" });
12053
12220
  resolve8(code);
12054
12221
  };
@@ -12070,7 +12237,7 @@ var engineRemoveImage = (engine = "docker", exec = realExec2) => (tag) => {
12070
12237
  } catch {
12071
12238
  }
12072
12239
  };
12073
- var sandboxLogDir = (stateDir) => join27(stateDir, "sandbox-logs");
12240
+ var sandboxLogDir = (stateDir) => join28(stateDir, "sandbox-logs");
12074
12241
  async function buildSandboxImage(plan, deps) {
12075
12242
  const now = deps.now ?? (() => /* @__PURE__ */ new Date());
12076
12243
  const state = readSandboxState(deps.stateDir);
@@ -12079,20 +12246,20 @@ async function buildSandboxImage(plan, deps) {
12079
12246
  return { kind: "reused", tag: plan.tag };
12080
12247
  }
12081
12248
  const logDir = sandboxLogDir(deps.stateDir);
12082
- mkdirSync15(logDir, { recursive: true });
12083
- const logPath = join27(logDir, `${slug(plan.repo)}-${now().toISOString().replace(/[:.]/g, "-")}.log`);
12249
+ mkdirSync16(logDir, { recursive: true });
12250
+ const logPath = join28(logDir, `${slug(plan.repo)}-${now().toISOString().replace(/[:.]/g, "-")}.log`);
12084
12251
  const builtLayers = [];
12085
12252
  for (const layer of plan.layers) {
12086
12253
  if (deps.hasImage(layer.tag)) continue;
12087
- const ctx = join27(tmpdir3(), `crew-sandbox-${hash([layer.tag, process.pid, Date.now()])}`);
12088
- mkdirSync15(ctx, { recursive: true });
12254
+ const ctx = join28(tmpdir3(), `crew-sandbox-${hash([layer.tag, process.pid, Date.now()])}`);
12255
+ mkdirSync16(ctx, { recursive: true });
12089
12256
  try {
12090
- writeFileSync16(join27(ctx, "Dockerfile"), layer.dockerfile);
12257
+ writeFileSync17(join28(ctx, "Dockerfile"), layer.dockerfile);
12091
12258
  for (const [name, content] of Object.entries(layer.files)) {
12092
- mkdirSync15(dirname11(join27(ctx, name)), { recursive: true });
12093
- writeFileSync16(join27(ctx, name), content);
12259
+ mkdirSync16(dirname12(join28(ctx, name)), { recursive: true });
12260
+ writeFileSync17(join28(ctx, name), content);
12094
12261
  }
12095
- const code = await deps.run(["build", "--tag", layer.tag, "--file", join27(ctx, "Dockerfile"), ctx], logPath);
12262
+ const code = await deps.run(["build", "--tag", layer.tag, "--file", join28(ctx, "Dockerfile"), ctx], logPath);
12096
12263
  if (code !== 0) {
12097
12264
  state[plan.repo] = { ...entry, failure: { tag: plan.tag, at: now().toISOString(), logPath } };
12098
12265
  writeSandboxState(deps.stateDir, state);
@@ -12145,10 +12312,10 @@ async function sandboxBuildTick(repos, deps, force = false) {
12145
12312
  }
12146
12313
 
12147
12314
  // src/doctor-checks.ts
12148
- import { execFileSync as execFileSync8 } from "child_process";
12315
+ import { execFileSync as execFileSync9 } from "child_process";
12149
12316
  var PROBE_BRANCH = "crew-probe-branch";
12150
12317
  var realGit = (cwd, args, env) => {
12151
- execFileSync8("git", args, { cwd, env, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
12318
+ execFileSync9("git", args, { cwd, env, stdio: ["ignore", "pipe", "pipe"], timeout: 3e4 });
12152
12319
  };
12153
12320
  function isSshRemote(url) {
12154
12321
  return /^ssh:\/\//.test(url) || /^[\w.-]+@[\w.-]+:/.test(url);
@@ -12281,9 +12448,9 @@ function managedRuntimeWarnings(kind, ship) {
12281
12448
 
12282
12449
  // src/selftest.ts
12283
12450
  import { spawn as spawn5 } from "child_process";
12284
- import { existsSync as existsSync26, mkdirSync as mkdirSync16, mkdtempSync as mkdtempSync2, readFileSync as readFileSync23, rmSync as rmSync14, writeFileSync as writeFileSync17 } from "fs";
12451
+ import { existsSync as existsSync27, mkdirSync as mkdirSync17, mkdtempSync as mkdtempSync2, readFileSync as readFileSync24, rmSync as rmSync14, writeFileSync as writeFileSync18 } from "fs";
12285
12452
  import { tmpdir as tmpdir4 } from "os";
12286
- import { join as join28 } from "path";
12453
+ import { join as join29 } from "path";
12287
12454
  var SELFTEST_TIMEOUT_MS = 12e4;
12288
12455
  var KEY_VAR = "CREW_API_KEY";
12289
12456
  var SELFTEST_PROMPT = "This is a read-only connectivity check. Use the tracker MCP tool to read this workspace (the workspaces find-one tool, using the workspace id below) and reply with the workspace's name alone, on one line. Do not write anything, do not create files, and do not use any other tool.\n\nWorkspace id: ";
@@ -12444,7 +12611,7 @@ async function runSelftest(i, deps = realDeps) {
12444
12611
  ...adapter.runEnv(spec),
12445
12612
  [KEY_VAR]: i.apiKey
12446
12613
  };
12447
- const cwd = mkdtempSync2(join28(tmpdir4(), "crew-selftest-"));
12614
+ const cwd = mkdtempSync2(join29(tmpdir4(), "crew-selftest-"));
12448
12615
  try {
12449
12616
  const run3 = await deps.run({
12450
12617
  bin: invocation.bin,
@@ -12477,11 +12644,11 @@ function formatResult(r) {
12477
12644
  const secs = `${(r.ms / 1e3).toFixed(1)}s`;
12478
12645
  return r.ok ? `${r.toolchain}: PASS ${r.detail} (${secs}${tok})` : `${r.toolchain}: FAIL ${r.failure} \u2014 ${r.detail} (${secs})`;
12479
12646
  }
12480
- var fileFor2 = (stateDir) => join28(stateDir, "selftest.json");
12647
+ var fileFor2 = (stateDir) => join29(stateDir, "selftest.json");
12481
12648
  function readSelftest(stateDir) {
12482
12649
  try {
12483
12650
  const p = fileFor2(stateDir);
12484
- return existsSync26(p) ? JSON.parse(readFileSync23(p, "utf8")) : {};
12651
+ return existsSync27(p) ? JSON.parse(readFileSync24(p, "utf8")) : {};
12485
12652
  } catch {
12486
12653
  return {};
12487
12654
  }
@@ -12489,8 +12656,8 @@ function readSelftest(stateDir) {
12489
12656
  function recordSelftest(stateDir, results) {
12490
12657
  const all = readSelftest(stateDir);
12491
12658
  for (const r of results) all[r.toolchain] = r;
12492
- mkdirSync16(stateDir, { recursive: true });
12493
- writeFileSync17(fileFor2(stateDir), `${JSON.stringify(all, null, 2)}
12659
+ mkdirSync17(stateDir, { recursive: true });
12660
+ writeFileSync18(fileFor2(stateDir), `${JSON.stringify(all, null, 2)}
12494
12661
  `);
12495
12662
  }
12496
12663
  function doctorSelftestLines(stored, toolchains) {
@@ -12502,7 +12669,7 @@ function doctorSelftestLines(stored, toolchains) {
12502
12669
  }
12503
12670
 
12504
12671
  // src/cli.ts
12505
- import { resolve as resolve7, dirname as dirname29, join as join50, basename as basename16 } from "path";
12672
+ import { resolve as resolve7, dirname as dirname30, join as join51, basename as basename16 } from "path";
12506
12673
  import { fileURLToPath } from "url";
12507
12674
  import { hostname as hostname4, homedir as homedir11 } from "os";
12508
12675
  import { spawnSync as spawnSync10 } from "child_process";
@@ -12699,14 +12866,14 @@ function rosterMarkdown(roster, meId) {
12699
12866
  }
12700
12867
 
12701
12868
  // src/connect-resume.ts
12702
- import { mkdirSync as mkdirSync17, readFileSync as readFileSync24, rmSync as rmSync15, writeFileSync as writeFileSync18 } from "fs";
12703
- import { dirname as dirname12, join as join29 } from "path";
12869
+ import { mkdirSync as mkdirSync18, readFileSync as readFileSync25, rmSync as rmSync15, writeFileSync as writeFileSync19 } from "fs";
12870
+ import { dirname as dirname13, join as join30 } from "path";
12704
12871
  function lastSessionFile(stateDir) {
12705
- return join29(stateDir, "connect-session.json");
12872
+ return join30(stateDir, "connect-session.json");
12706
12873
  }
12707
12874
  function readPointers(stateDir) {
12708
12875
  try {
12709
- const parsed = JSON.parse(readFileSync24(lastSessionFile(stateDir), "utf8"));
12876
+ const parsed = JSON.parse(readFileSync25(lastSessionFile(stateDir), "utf8"));
12710
12877
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return {};
12711
12878
  const out = {};
12712
12879
  for (const [host, v] of Object.entries(parsed)) {
@@ -12720,8 +12887,8 @@ function readPointers(stateDir) {
12720
12887
  }
12721
12888
  function writePointers(stateDir, pointers) {
12722
12889
  const file = lastSessionFile(stateDir);
12723
- mkdirSync17(dirname12(file), { recursive: true });
12724
- writeFileSync18(file, `${JSON.stringify(pointers, null, 2)}
12890
+ mkdirSync18(dirname13(file), { recursive: true });
12891
+ writeFileSync19(file, `${JSON.stringify(pointers, null, 2)}
12725
12892
  `, { mode: 384 });
12726
12893
  }
12727
12894
  function rememberSession(stateDir, host, workspaceSlug) {
@@ -12806,15 +12973,15 @@ async function signOutSessions(o) {
12806
12973
  }
12807
12974
 
12808
12975
  // src/reset.ts
12809
- import { existsSync as existsSync27, mkdirSync as mkdirSync18, readFileSync as readFileSync25, readdirSync as readdirSync12, rmSync as rmSync16, statSync as statSync10, writeFileSync as writeFileSync19 } from "fs";
12810
- import { dirname as dirname13, join as join30 } from "path";
12976
+ import { existsSync as existsSync28, mkdirSync as mkdirSync19, readFileSync as readFileSync26, readdirSync as readdirSync12, rmSync as rmSync16, statSync as statSync10, writeFileSync as writeFileSync20 } from "fs";
12977
+ import { dirname as dirname14, join as join31 } from "path";
12811
12978
  import { hostFromUrl as hostFromUrl3 } from "@tablation/client";
12812
12979
  function clonedCheckoutsFile(stateDir) {
12813
- return join30(stateDir, "cloned-checkouts.json");
12980
+ return join31(stateDir, "cloned-checkouts.json");
12814
12981
  }
12815
12982
  function readClonedCheckouts(stateDir) {
12816
12983
  try {
12817
- const parsed = JSON.parse(readFileSync25(clonedCheckoutsFile(stateDir), "utf8"));
12984
+ const parsed = JSON.parse(readFileSync26(clonedCheckoutsFile(stateDir), "utf8"));
12818
12985
  return Array.isArray(parsed) ? parsed.filter((d) => typeof d === "string") : [];
12819
12986
  } catch {
12820
12987
  return [];
@@ -12824,8 +12991,8 @@ function recordClonedCheckout(stateDir, dir) {
12824
12991
  const known = readClonedCheckouts(stateDir);
12825
12992
  if (known.includes(dir)) return;
12826
12993
  const file = clonedCheckoutsFile(stateDir);
12827
- mkdirSync18(dirname13(file), { recursive: true });
12828
- writeFileSync19(file, `${JSON.stringify([...known, dir], null, 2)}
12994
+ mkdirSync19(dirname14(file), { recursive: true });
12995
+ writeFileSync20(file, `${JSON.stringify([...known, dir], null, 2)}
12829
12996
  `);
12830
12997
  }
12831
12998
  var mark = (dryRun) => dryRun ? "would-remove" : "removed";
@@ -12879,7 +13046,7 @@ async function runReset(o, fx) {
12879
13046
  }
12880
13047
  if (o.beforeState) steps.push(...await o.beforeState());
12881
13048
  steps.push(...o.wipeState ? wipeStateDir(o.stateDir, o.dryRun) : removeState(o.stateDir, o.dryRun));
12882
- if (existsSync27(o.configFile)) {
13049
+ if (existsSync28(o.configFile)) {
12883
13050
  if (!o.dryRun) rmSync16(o.configFile, { force: true });
12884
13051
  steps.push({ step: "config", target: o.configFile, action: mark(o.dryRun) });
12885
13052
  } else {
@@ -12888,7 +13055,7 @@ async function runReset(o, fx) {
12888
13055
  return steps;
12889
13056
  }
12890
13057
  function removeCheckout(dir, dryRun, fx) {
12891
- if (!existsSync27(dir)) return { step: "checkout", target: dir, action: "absent", detail: "already gone" };
13058
+ if (!existsSync28(dir)) return { step: "checkout", target: dir, action: "absent", detail: "already gone" };
12892
13059
  const { dirty, linkedWorktrees } = fx.inspectCheckout(dir);
12893
13060
  if (dirty.length) {
12894
13061
  return { step: "checkout", target: dir, action: "kept", detail: `has uncommitted changes (${dirty.length} path${dirty.length === 1 ? "" : "s"}: ${dirty.slice(0, 5).join(", ")}${dirty.length > 5 ? ", \u2026" : ""})` };
@@ -12901,15 +13068,15 @@ function removeCheckout(dir, dryRun, fx) {
12901
13068
  }
12902
13069
  function removeState(stateDir, dryRun) {
12903
13070
  const out = [];
12904
- const targets = [join30(stateDir, "resolved"), join30(stateDir, "keys"), clonedCheckoutsFile(stateDir), join30(stateDir, "connect-session.json"), join30(stateDir, "reload-requested"), join30(stateDir, "daemon.started")];
13071
+ const targets = [join31(stateDir, "resolved"), join31(stateDir, "keys"), clonedCheckoutsFile(stateDir), join31(stateDir, "connect-session.json"), join31(stateDir, "reload-requested"), join31(stateDir, "daemon.started")];
12905
13072
  try {
12906
13073
  for (const name of readdirSync12(stateDir)) {
12907
- if (name.startsWith(".") && statSync10(join30(stateDir, name)).isFile()) targets.push(join30(stateDir, name));
13074
+ if (name.startsWith(".") && statSync10(join31(stateDir, name)).isFile()) targets.push(join31(stateDir, name));
12908
13075
  }
12909
13076
  } catch {
12910
13077
  }
12911
13078
  for (const t of targets) {
12912
- if (!existsSync27(t)) continue;
13079
+ if (!existsSync28(t)) continue;
12913
13080
  if (!dryRun) rmSync16(t, { recursive: true, force: true });
12914
13081
  out.push({ step: "state", target: t, action: mark(dryRun) });
12915
13082
  }
@@ -12924,7 +13091,7 @@ function wipeStateDir(stateDir, dryRun) {
12924
13091
  return [{ step: "state", target: stateDir, action: "absent", detail: "no state directory" }];
12925
13092
  }
12926
13093
  if (!names.length) return [{ step: "state", target: stateDir, action: "absent", detail: "already empty" }];
12927
- if (!dryRun) for (const n of names) rmSync16(join30(stateDir, n), { recursive: true, force: true });
13094
+ if (!dryRun) for (const n of names) rmSync16(join31(stateDir, n), { recursive: true, force: true });
12928
13095
  return [{ step: "state", target: stateDir, action: mark(dryRun), detail: `${names.length} entr${names.length === 1 ? "y" : "ies"}` }];
12929
13096
  }
12930
13097
  function describeResetStep(s) {
@@ -13005,9 +13172,9 @@ async function runDeprovision(o, fx, deps) {
13005
13172
  }
13006
13173
 
13007
13174
  // src/pool-member.ts
13008
- import { mkdirSync as mkdirSync19, readFileSync as readFileSync26, renameSync as renameSync4, writeFileSync as writeFileSync20 } from "fs";
13175
+ import { mkdirSync as mkdirSync20, readFileSync as readFileSync27, renameSync as renameSync4, writeFileSync as writeFileSync21 } from "fs";
13009
13176
  import { homedir as homedir8 } from "os";
13010
- import { dirname as dirname14, join as join31 } from "path";
13177
+ import { dirname as dirname15, join as join32 } from "path";
13011
13178
  var POOL_EXIT = { ok: 0, failed: 1, credential: 2 };
13012
13179
  function backoffMs(attempt) {
13013
13180
  return Math.min(6e4, 5e3 * 2 ** Math.max(0, attempt));
@@ -13238,22 +13405,22 @@ async function runPoolMember(deps) {
13238
13405
  }
13239
13406
  }
13240
13407
  function defaultMemberDir(env = process.env) {
13241
- return env.CREW_POOL_DIR ?? join31(env.XDG_STATE_HOME ?? join31(homedir8(), ".local", "state"), "crew-pool-member");
13408
+ return env.CREW_POOL_DIR ?? join32(env.XDG_STATE_HOME ?? join32(homedir8(), ".local", "state"), "crew-pool-member");
13242
13409
  }
13243
13410
  function fileMemberStore(dir) {
13244
- const file = join31(dir, "member.json");
13411
+ const file = join32(dir, "member.json");
13245
13412
  return {
13246
13413
  read() {
13247
13414
  try {
13248
- return JSON.parse(readFileSync26(file, "utf8"));
13415
+ return JSON.parse(readFileSync27(file, "utf8"));
13249
13416
  } catch {
13250
13417
  return {};
13251
13418
  }
13252
13419
  },
13253
13420
  write(f) {
13254
- mkdirSync19(dirname14(file), { recursive: true, mode: 448 });
13421
+ mkdirSync20(dirname15(file), { recursive: true, mode: 448 });
13255
13422
  const tmp = `${file}.tmp`;
13256
- writeFileSync20(tmp, `${JSON.stringify(f)}
13423
+ writeFileSync21(tmp, `${JSON.stringify(f)}
13257
13424
  `, { mode: 384 });
13258
13425
  renameSync4(tmp, file);
13259
13426
  }
@@ -13305,30 +13472,30 @@ function hostArchitecture(arch = process.arch) {
13305
13472
 
13306
13473
  // src/pool-member-host.ts
13307
13474
  import "child_process";
13308
- import { existsSync as existsSync31 } from "fs";
13475
+ import { existsSync as existsSync32 } from "fs";
13309
13476
  import { hostname as hostname3 } from "os";
13310
13477
 
13311
13478
  // src/machine-id.ts
13312
- import { execFileSync as execFileSync9 } from "child_process";
13479
+ import { execFileSync as execFileSync10 } from "child_process";
13313
13480
  import { createHash as createHash7 } from "crypto";
13314
- import { existsSync as existsSync28, mkdirSync as mkdirSync20, readFileSync as readFileSync27, writeFileSync as writeFileSync21 } from "fs";
13315
- import { dirname as dirname15, join as join32 } from "path";
13481
+ import { existsSync as existsSync29, mkdirSync as mkdirSync21, readFileSync as readFileSync28, writeFileSync as writeFileSync22 } from "fs";
13482
+ import { dirname as dirname16, join as join33 } from "path";
13316
13483
  function machineIdPathFor(stateDir) {
13317
- return join32(stateDir, "machine-id");
13484
+ return join33(stateDir, "machine-id");
13318
13485
  }
13319
13486
  var sha256 = (s) => createHash7("sha256").update(s).digest("hex");
13320
13487
  function readRawMachineId(platform2 = process.platform) {
13321
13488
  try {
13322
13489
  if (platform2 === "darwin") {
13323
- const out = execFileSync9("ioreg", ["-rd1", "-c", "IOPlatformExpertDevice"], {
13490
+ const out = execFileSync10("ioreg", ["-rd1", "-c", "IOPlatformExpertDevice"], {
13324
13491
  encoding: "utf8",
13325
13492
  stdio: ["ignore", "pipe", "ignore"]
13326
13493
  });
13327
13494
  return /"IOPlatformUUID"\s*=\s*"([^"]+)"/.exec(out)?.[1];
13328
13495
  }
13329
13496
  for (const p of ["/etc/machine-id", "/var/lib/dbus/machine-id"]) {
13330
- if (existsSync28(p)) {
13331
- const id = readFileSync27(p, "utf8").trim();
13497
+ if (existsSync29(p)) {
13498
+ const id = readFileSync28(p, "utf8").trim();
13332
13499
  if (id) return id;
13333
13500
  }
13334
13501
  }
@@ -13339,15 +13506,15 @@ function readRawMachineId(platform2 = process.platform) {
13339
13506
  function ensureMachineId(stateDir, opts = {}) {
13340
13507
  if (opts.override?.trim()) return sha256(opts.override.trim());
13341
13508
  const path = machineIdPathFor(stateDir);
13342
- if (existsSync28(path)) {
13343
- const cached = readFileSync27(path, "utf8").trim();
13509
+ if (existsSync29(path)) {
13510
+ const cached = readFileSync28(path, "utf8").trim();
13344
13511
  if (/^[0-9a-f]{64}$/.test(cached)) return cached;
13345
13512
  }
13346
13513
  const raw = (opts.read ?? readRawMachineId)();
13347
13514
  if (!raw) return void 0;
13348
13515
  const hashed = sha256(raw);
13349
- mkdirSync20(dirname15(path), { recursive: true });
13350
- writeFileSync21(path, `${hashed}
13516
+ mkdirSync21(dirname16(path), { recursive: true });
13517
+ writeFileSync22(path, `${hashed}
13351
13518
  `, { mode: 384 });
13352
13519
  return hashed;
13353
13520
  }
@@ -13360,7 +13527,7 @@ function matchShipRows(ships, shipName2, machineId) {
13360
13527
 
13361
13528
  // src/provision.ts
13362
13529
  import { spawnSync as spawnSync7 } from "child_process";
13363
- import { existsSync as existsSync29, readFileSync as readFileSync28, writeFileSync as writeFileSync22 } from "fs";
13530
+ import { existsSync as existsSync30, readFileSync as readFileSync29, writeFileSync as writeFileSync23 } from "fs";
13364
13531
  import { hostname as hostname2 } from "os";
13365
13532
  import { parseDocument as parseDocument3, isMap as isMap2, isScalar } from "yaml";
13366
13533
 
@@ -13369,7 +13536,7 @@ import { parseDocument as parseDocument2 } from "yaml";
13369
13536
 
13370
13537
  // src/repos-cmd.ts
13371
13538
  import { homedir as homedir9 } from "os";
13372
- import { basename as basename10, join as join33, resolve as resolve4 } from "path";
13539
+ import { basename as basename10, join as join34, resolve as resolve4 } from "path";
13373
13540
  import { isMap, isSeq, parseDocument, stringify as stringify2 } from "yaml";
13374
13541
  var ReposError = class extends Error {
13375
13542
  };
@@ -13647,7 +13814,7 @@ function planRepoClone(i) {
13647
13814
  }
13648
13815
  const ship = doc.get("ship", true);
13649
13816
  const basePath = String(m.get("reposBasePath") ?? (isMap(ship) ? ship.get("reposBasePath") : void 0) ?? "~/Crew");
13650
- const target = i.dir ? expandDir(i.dir, i.base) : join33(expandDir(basePath, i.base), i.route.split("/")[0], name);
13817
+ const target = i.dir ? expandDir(i.dir, i.base) : join34(expandDir(basePath, i.base), i.route.split("/")[0], name);
13651
13818
  const add = planRepoAdd({ text: i.text, base: i.base, route: i.route, path: target, origin: remote, resolved: i.resolved, name, isCheckout: i.isCheckout });
13652
13819
  const forgeHost = i.resolved?.repoForgeHosts?.[id];
13653
13820
  return { ...add, remote, target, ...forgeHost ? { forgeHost } : {} };
@@ -13954,7 +14121,7 @@ function realProvisionDeps(crewHome) {
13954
14121
  };
13955
14122
  const configFile = () => {
13956
14123
  const f = findConfigFile(crewHome);
13957
- return existsSync29(f) ? f : null;
14124
+ return existsSync30(f) ? f : null;
13958
14125
  };
13959
14126
  return {
13960
14127
  crew: spawnCrew,
@@ -13962,13 +14129,13 @@ function realProvisionDeps(crewHome) {
13962
14129
  enableRoute(route2) {
13963
14130
  const file = configFile();
13964
14131
  if (!file) return false;
13965
- const text2 = readFileSync28(file, "utf8");
14132
+ const text2 = readFileSync29(file, "utf8");
13966
14133
  const doc = parseDocument3(text2);
13967
14134
  const routes = doc.get("routes");
13968
14135
  const entry = routes?.items?.find((r) => r.get("route") === route2);
13969
14136
  if (!entry) throw new Error(`route ${route2} is not in ${file}`);
13970
14137
  if (entry.get("enabled") === true) return false;
13971
- writeFileSync22(file, planEnable(text2, route2));
14138
+ writeFileSync23(file, planEnable(text2, route2));
13972
14139
  return true;
13973
14140
  },
13974
14141
  installState() {
@@ -13988,14 +14155,14 @@ function realProvisionDeps(crewHome) {
13988
14155
  continue;
13989
14156
  }
13990
14157
  for (const p of plan.unitPaths) {
13991
- if (!existsSync29(p) || readFileSync28(p, "utf8") !== plan.unitContent[p]) unitsStale = true;
14158
+ if (!existsSync30(p) || readFileSync29(p, "utf8") !== plan.unitContent[p]) unitsStale = true;
13992
14159
  }
13993
14160
  }
13994
14161
  const label = labelFor(crewHome, "run");
13995
14162
  let running = false;
13996
14163
  let lingering = true;
13997
14164
  if (mechanism === "systemd") {
13998
- const system = ctx.root || existsSync29(systemUnitPathFor(label));
14165
+ const system = ctx.root || existsSync30(systemUnitPathFor(label));
13999
14166
  const ctl = system ? ["systemctl"] : ["systemctl", "--user"];
14000
14167
  running = spawnSync7(ctl[0], [...ctl.slice(1), "is-active", "--quiet", `${label}.service`]).status === 0;
14001
14168
  if (!system) {
@@ -14012,18 +14179,18 @@ function realProvisionDeps(crewHome) {
14012
14179
  setShipSetting(key, value2) {
14013
14180
  const file = configFile();
14014
14181
  if (!file) return false;
14015
- const doc = parseDocument3(readFileSync28(file, "utf8"));
14182
+ const doc = parseDocument3(readFileSync29(file, "utf8"));
14016
14183
  if (doc.getIn(["ship", key]) === value2) return false;
14017
14184
  doc.setIn(["ship", key], value2);
14018
- writeFileSync22(file, doc.toString());
14185
+ writeFileSync23(file, doc.toString());
14019
14186
  return true;
14020
14187
  },
14021
14188
  applyManagedDefaults() {
14022
14189
  const file = configFile();
14023
14190
  if (!file) return [];
14024
- const doc = parseDocument3(readFileSync28(file, "utf8"));
14191
+ const doc = parseDocument3(readFileSync29(file, "utf8"));
14025
14192
  const wrote = applyManagedDefaultsToDoc(doc);
14026
- if (wrote.length) writeFileSync22(file, doc.toString());
14193
+ if (wrote.length) writeFileSync23(file, doc.toString());
14027
14194
  return wrote;
14028
14195
  },
14029
14196
  storedToken(host) {
@@ -14040,9 +14207,9 @@ host=${host}
14040
14207
 
14041
14208
  // src/tunnel.ts
14042
14209
  import { spawn as spawn6 } from "child_process";
14043
- import { existsSync as existsSync30, mkdirSync as mkdirSync21, readFileSync as readFileSync29, writeFileSync as writeFileSync23, unlinkSync as unlinkSync3, readdirSync as readdirSync13 } from "fs";
14210
+ import { existsSync as existsSync31, mkdirSync as mkdirSync22, readFileSync as readFileSync30, writeFileSync as writeFileSync24, unlinkSync as unlinkSync3, readdirSync as readdirSync13 } from "fs";
14044
14211
  import { randomInt } from "crypto";
14045
- import { join as join34 } from "path";
14212
+ import { join as join35 } from "path";
14046
14213
  var DEFAULT_SPAWN_OPTIONS = { stdio: "ignore", detached: true };
14047
14214
  var defaultSpawn = (cmd, args) => spawn6(cmd, args, DEFAULT_SPAWN_OPTIONS);
14048
14215
  var SLUG_ALPHABET = "abcdefghijklmnopqrstuvwxyz0123456789";
@@ -14114,21 +14281,21 @@ function startTunnel(opts) {
14114
14281
  };
14115
14282
  }
14116
14283
  function tunnelStatePath(stateDir, workspaceId) {
14117
- return join34(stateDir, "passengers", `${workspaceId}.json`);
14284
+ return join35(stateDir, "passengers", `${workspaceId}.json`);
14118
14285
  }
14119
14286
  function readPersistedTunnel(stateDir, workspaceId) {
14120
14287
  const path = tunnelStatePath(stateDir, workspaceId);
14121
- if (!existsSync30(path)) return void 0;
14288
+ if (!existsSync31(path)) return void 0;
14122
14289
  try {
14123
- return JSON.parse(readFileSync29(path, "utf8"));
14290
+ return JSON.parse(readFileSync30(path, "utf8"));
14124
14291
  } catch {
14125
14292
  return void 0;
14126
14293
  }
14127
14294
  }
14128
14295
  function writePersistedTunnel(stateDir, state) {
14129
14296
  const path = tunnelStatePath(stateDir, state.workspaceId);
14130
- mkdirSync21(join34(stateDir, "passengers"), { recursive: true });
14131
- writeFileSync23(path, `${JSON.stringify(state, null, 2)}
14297
+ mkdirSync22(join35(stateDir, "passengers"), { recursive: true });
14298
+ writeFileSync24(path, `${JSON.stringify(state, null, 2)}
14132
14299
  `);
14133
14300
  }
14134
14301
  function updatePersistedTunnel(stateDir, workspaceId, patch2) {
@@ -14230,8 +14397,8 @@ function syncPassengerTunnels(plans, relayHost, relayPort, privateKeyPath, state
14230
14397
  }
14231
14398
  }
14232
14399
  function readAllPersistedWorkspaceIds(stateDir) {
14233
- const dir = join34(stateDir, "passengers");
14234
- if (!existsSync30(dir)) return [];
14400
+ const dir = join35(stateDir, "passengers");
14401
+ if (!existsSync31(dir)) return [];
14235
14402
  return readdirSync13(dir).filter((f) => f.endsWith(".json") && !f.endsWith("-sync.json")).map((f) => f.slice(0, -".json".length));
14236
14403
  }
14237
14404
 
@@ -14256,7 +14423,7 @@ function realPoolMemberDeps(o) {
14256
14423
  crewVersion: crewVersion(o.crewHome),
14257
14424
  hostname: hostname3()
14258
14425
  },
14259
- hasShipConfig: () => existsSync31(findConfigFile(o.crewHome)),
14426
+ hasShipConfig: () => existsSync32(findConfigFile(o.crewHome)),
14260
14427
  async provision(lease, instanceClass, shipKind) {
14261
14428
  const hosts = lease.forges.map((f) => f.host.toLowerCase());
14262
14429
  const lines2 = [];
@@ -15132,8 +15299,8 @@ ${waiting.map((t) => `| ${displayKey2(t)} | ${t.status} | ${blockers(t, i)} |`).
15132
15299
  }
15133
15300
 
15134
15301
  // src/poll.ts
15135
- import { writeFileSync as writeFileSync24 } from "fs";
15136
- import { join as join35 } from "path";
15302
+ import { writeFileSync as writeFileSync25 } from "fs";
15303
+ import { join as join36 } from "path";
15137
15304
 
15138
15305
  // src/stalled.ts
15139
15306
  var STALLED_AFTER_CYCLES = 30;
@@ -15440,7 +15607,7 @@ async function decideCycle(o) {
15440
15607
  }
15441
15608
  return decision;
15442
15609
  }
15443
- var digestPath = (stateDir, route2, role, runId) => join35(stateDir, `digest-${route2}-${role}${runId ? `-${runId}` : ""}.md`);
15610
+ var digestPath = (stateDir, route2, role, runId) => join36(stateDir, `digest-${route2}-${role}${runId ? `-${runId}` : ""}.md`);
15444
15611
  function otherRunsRemoved(tickets, own) {
15445
15612
  if (!own) return tickets;
15446
15613
  return tickets.filter((t) => t.id === own.ticket.id || !own.inFlight(t.id));
@@ -15518,7 +15685,7 @@ function writeDigest(o, d, role, stateDir, runId, own) {
15518
15685
 
15519
15686
  ${body}` : body;
15520
15687
  const path = digestPath(stateDir, routeSlug(o.route.route), role, runId);
15521
- writeFileSync24(path, text2);
15688
+ writeFileSync25(path, text2);
15522
15689
  o.emit.emit(`queue digest written for ${role} (${Buffer.byteLength(text2)} bytes)`, {
15523
15690
  data: { role, bytes: Buffer.byteLength(text2) }
15524
15691
  });
@@ -15626,8 +15793,8 @@ async function resolveOne(tracker, t, seat, approvedStatus, buildingStatus, affi
15626
15793
  }
15627
15794
 
15628
15795
  // src/repo-refresh.ts
15629
- import { existsSync as existsSync32, mkdirSync as mkdirSync22, readFileSync as readFileSync30, writeFileSync as writeFileSync25 } from "fs";
15630
- import { dirname as dirname17 } from "path";
15796
+ import { existsSync as existsSync33, mkdirSync as mkdirSync23, readFileSync as readFileSync31, writeFileSync as writeFileSync26 } from "fs";
15797
+ import { dirname as dirname18 } from "path";
15631
15798
  var REFRESH_COOLDOWN_MS = 2 * 6e4;
15632
15799
  var UNSERVABLE_PASSES_BEFORE_ATTENTION = 3;
15633
15800
  var lastAsked = /* @__PURE__ */ new Map();
@@ -15656,11 +15823,11 @@ function applyRepoRows(resolved, rows) {
15656
15823
  }
15657
15824
  function persistRepoRows(stateDir, routeName, rows) {
15658
15825
  const path = resolvedPathFor(stateDir, routeName);
15659
- if (!existsSync32(path)) return;
15660
- const raw = JSON.parse(readFileSync30(path, "utf8"));
15826
+ if (!existsSync33(path)) return;
15827
+ const raw = JSON.parse(readFileSync31(path, "utf8"));
15661
15828
  applyRepoRows(raw, rows);
15662
- mkdirSync22(dirname17(path), { recursive: true });
15663
- writeFileSync25(path, `${JSON.stringify(raw, null, 2)}
15829
+ mkdirSync23(dirname18(path), { recursive: true });
15830
+ writeFileSync26(path, `${JSON.stringify(raw, null, 2)}
15664
15831
  `);
15665
15832
  }
15666
15833
  async function refreshUnknownRepos(o) {
@@ -16110,13 +16277,13 @@ Ship ${shipName2} found: ${problem}. The release refuses to squash a ref nobody
16110
16277
  var localRefSkipReported = (ticket, problem, events) => events.some((e) => e.record_id === ticket.id && e.event_type === "local_ref_skip" && (e.message ?? "").includes(problem));
16111
16278
 
16112
16279
  // src/connect-wizard.ts
16113
- import { delimiter, dirname as dirname18, join as join36 } from "path";
16114
- import { accessSync as accessSync3, constants as constants3, existsSync as existsSync33, mkdirSync as mkdirSync23, writeFileSync as writeFileSync26 } from "fs";
16280
+ import { delimiter, dirname as dirname19, join as join37 } from "path";
16281
+ import { accessSync as accessSync3, constants as constants3, existsSync as existsSync34, mkdirSync as mkdirSync24, writeFileSync as writeFileSync27 } from "fs";
16115
16282
  import { stringify as stringify3 } from "yaml";
16116
16283
  var HOST_PASSENGERS_DOCS_URL = "https://crew.tablation.dev/host-passengers";
16117
16284
  function shouldRunWizard(opts) {
16118
16285
  if (!opts.isTTY) return false;
16119
- const exists = opts.configExists ?? existsSync33;
16286
+ const exists = opts.configExists ?? existsSync34;
16120
16287
  return !configSearchPath(opts.crewHome).some((p) => exists(p));
16121
16288
  }
16122
16289
  function firstRunConfigPath() {
@@ -16133,7 +16300,7 @@ function defaultIsExecutable(p) {
16133
16300
  function findOnPath2(name, pathEnv, isExecutable = defaultIsExecutable) {
16134
16301
  for (const dir of pathEnv.split(delimiter)) {
16135
16302
  if (!dir) continue;
16136
- const candidate = join36(dir, name);
16303
+ const candidate = join37(dir, name);
16137
16304
  if (isExecutable(candidate)) return candidate;
16138
16305
  }
16139
16306
  return void 0;
@@ -16159,9 +16326,9 @@ async function runWizard(p, env) {
16159
16326
  if (entered && isExec(entered)) agentBin = entered;
16160
16327
  else p.say(entered ? `${entered} is not an executable file.` : "A path is required.");
16161
16328
  }
16162
- const nodeDir = dirname18(env.nodePath);
16329
+ const nodeDir = dirname19(env.nodePath);
16163
16330
  const pnpmPath = findOnPath2("pnpm", env.pathEnv, isExec);
16164
- const baseDirs = [nodeDir, pnpmPath ? dirname18(pnpmPath) : void 0];
16331
+ const baseDirs = [nodeDir, pnpmPath ? dirname19(pnpmPath) : void 0];
16165
16332
  p.say(
16166
16333
  `
16167
16334
  Host Passengers lets this machine run the agent sessions that other people's
@@ -16172,7 +16339,7 @@ Tablation workspaces ask for, in a container. More: ${HOST_PASSENGERS_DOCS_URL}`
16172
16339
  p.say("Docker is not available here, so nothing will be hosted until it is. Your answer is recorded anyway.");
16173
16340
  }
16174
16341
  const dockerPath = hostPassengers ? findOnPath2("docker", env.pathEnv, isExec) : void 0;
16175
- const extraPath = deriveExtraPath([...baseDirs, dockerPath ? dirname18(dockerPath) : void 0]);
16342
+ const extraPath = deriveExtraPath([...baseDirs, dockerPath ? dirname19(dockerPath) : void 0]);
16176
16343
  if (extraPath) {
16177
16344
  p.say(`Hooks will get ${extraPath} on their PATH (where node, pnpm${dockerPath ? " and docker" : ""} live).`);
16178
16345
  }
@@ -16194,9 +16361,9 @@ routes:
16194
16361
  ${routeBlock}`;
16195
16362
  }
16196
16363
  function writeNewConfig(path, text2) {
16197
- mkdirSync23(dirname18(path), { recursive: true });
16364
+ mkdirSync24(dirname19(path), { recursive: true });
16198
16365
  try {
16199
- writeFileSync26(path, text2, { mode: 384, flag: "wx" });
16366
+ writeFileSync27(path, text2, { mode: 384, flag: "wx" });
16200
16367
  return true;
16201
16368
  } catch (e) {
16202
16369
  if (e.code === "EEXIST") return false;
@@ -16230,7 +16397,7 @@ Wrote ${o.configPath}.
16230
16397
  // src/connect-json.ts
16231
16398
  import { accessSync as accessSync4, constants as constants4 } from "fs";
16232
16399
  import { homedir as homedir10 } from "os";
16233
- import { dirname as dirname19, join as join37 } from "path";
16400
+ import { dirname as dirname20, join as join38 } from "path";
16234
16401
  import { delimiter as delimiter2 } from "path";
16235
16402
  var CHOICE_EXIT_CODE = 3;
16236
16403
  function createEmitter(json2, write) {
@@ -16269,12 +16436,12 @@ function agentBinSearchDirs(home, pathEnv, extraPath) {
16269
16436
  const dirs = [
16270
16437
  ...pathEnv.split(delimiter2),
16271
16438
  ...(extraPath ?? "").split(delimiter2),
16272
- join37(home, ".local/bin"),
16273
- join37(home, ".claude/local"),
16439
+ join38(home, ".local/bin"),
16440
+ join38(home, ".claude/local"),
16274
16441
  "/opt/homebrew/bin",
16275
16442
  "/usr/local/bin",
16276
- join37(home, ".npm-global/bin"),
16277
- join37(home, ".volta/bin")
16443
+ join38(home, ".npm-global/bin"),
16444
+ join38(home, ".volta/bin")
16278
16445
  ];
16279
16446
  return [...new Set(dirs.filter(Boolean))];
16280
16447
  }
@@ -16296,7 +16463,7 @@ function flagWizardAnswers(f, env) {
16296
16463
  const agentBin = f.agentBin ?? found?.bin;
16297
16464
  const pnpmPath = findOnPath2("pnpm", env.pathEnv, isExec);
16298
16465
  const dockerPath = f.hostPassengers ? findOnPath2("docker", env.pathEnv, isExec) : void 0;
16299
- const extraPath = f.extraPath ?? deriveExtraPath([dirname19(env.nodePath), pnpmPath ? dirname19(pnpmPath) : void 0, dockerPath ? dirname19(dockerPath) : void 0]);
16466
+ const extraPath = f.extraPath ?? deriveExtraPath([dirname20(env.nodePath), pnpmPath ? dirname20(pnpmPath) : void 0, dockerPath ? dirname20(dockerPath) : void 0]);
16300
16467
  return {
16301
16468
  answers: {
16302
16469
  name: f.shipName?.trim() || env.hostname,
@@ -16310,8 +16477,8 @@ function flagWizardAnswers(f, env) {
16310
16477
  }
16311
16478
 
16312
16479
  // src/release-run.ts
16313
- import { readFileSync as readFileSync31, writeFileSync as writeFileSync27, existsSync as existsSync34, copyFileSync, mkdirSync as mkdirSync24, mkdtempSync as mkdtempSync3, rmSync as rmSync17 } from "fs";
16314
- import { dirname as dirname20, join as join38 } from "path";
16480
+ import { readFileSync as readFileSync32, writeFileSync as writeFileSync28, existsSync as existsSync35, copyFileSync, mkdirSync as mkdirSync25, mkdtempSync as mkdtempSync3, rmSync as rmSync17 } from "fs";
16481
+ import { dirname as dirname21, join as join39 } from "path";
16315
16482
  import { tmpdir as tmpdir5 } from "os";
16316
16483
 
16317
16484
  // src/release.ts
@@ -17052,13 +17219,13 @@ async function bump(o, size) {
17052
17219
  }
17053
17220
  return printed;
17054
17221
  }
17055
- const files = o.repo.release.versionFiles.map((f) => join38(o.cwd, f));
17222
+ const files = o.repo.release.versionFiles.map((f) => join39(o.cwd, f));
17056
17223
  const first = files[0];
17057
- if (!existsSync34(first)) {
17224
+ if (!existsSync35(first)) {
17058
17225
  o.emit.error(`no ${o.repo.release.versionFiles[0]} to read a version from`);
17059
17226
  return null;
17060
17227
  }
17061
- const current = JSON.parse(readFileSync31(first, "utf8")).version;
17228
+ const current = JSON.parse(readFileSync32(first, "utf8")).version;
17062
17229
  if (!current) {
17063
17230
  o.emit.error(`no version field in ${o.repo.release.versionFiles[0]}`);
17064
17231
  return null;
@@ -17071,27 +17238,27 @@ async function bump(o, size) {
17071
17238
  return version;
17072
17239
  }
17073
17240
  for (const f of files) {
17074
- const src = readFileSync31(f, "utf8");
17241
+ const src = readFileSync32(f, "utf8");
17075
17242
  const out = src.replace(/("version"\s*:\s*")[^"]*(")/, `$1${version}$2`);
17076
17243
  if (out === src) {
17077
17244
  o.emit.error(`no version field in ${f}`);
17078
17245
  return null;
17079
17246
  }
17080
- writeFileSync27(f, out);
17247
+ writeFileSync28(f, out);
17081
17248
  }
17082
17249
  return version;
17083
17250
  }
17084
17251
  function writeChangelog(o, version, entries) {
17085
17252
  const file = o.repo.release.changelog;
17086
17253
  if (!file || entries.length === 0) return;
17087
- const path = join38(o.cwd, file);
17254
+ const path = join39(o.cwd, file);
17088
17255
  const section = renderChangelogSection(version, (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), entries);
17089
17256
  if (o.dryRun) {
17090
17257
  o.emit.emit(`would prepend ${entries.length} entr(ies) to ${file}`);
17091
17258
  return;
17092
17259
  }
17093
- const existing = existsSync34(path) ? readFileSync31(path, "utf8") : "# Changelog\n";
17094
- writeFileSync27(path, insertChangelogSection(existing, section));
17260
+ const existing = existsSync35(path) ? readFileSync32(path, "utf8") : "# Changelog\n";
17261
+ writeFileSync28(path, insertChangelogSection(existing, section));
17095
17262
  }
17096
17263
  async function confirm(o, expected) {
17097
17264
  if (!o.repo.hooks.released) return void 0;
@@ -17184,8 +17351,8 @@ function closeReleaseCheckout(cwd, root, dir, branch, run3 = gitOk) {
17184
17351
  function openReleaseCheckout(o) {
17185
17352
  const { remote, base } = o.repo.branch;
17186
17353
  const branch = `crew/release-${Date.now()}`;
17187
- const root = mkdtempSync3(join38(tmpdir5(), "crew-release-"));
17188
- const dir = join38(root, "checkout");
17354
+ const root = mkdtempSync3(join39(tmpdir5(), "crew-release-"));
17355
+ const dir = join39(root, "checkout");
17189
17356
  o.emit.emit(`release checkout: ${dir}`, { step: "release" });
17190
17357
  const close = () => closeReleaseCheckout(o.cwd, root, dir, branch);
17191
17358
  try {
@@ -17195,10 +17362,10 @@ function openReleaseCheckout(o) {
17195
17362
  throw e;
17196
17363
  }
17197
17364
  for (const f of o.repo.worktrees.copy) {
17198
- const src = join38(o.cwd, f);
17199
- if (!existsSync34(src)) continue;
17200
- mkdirSync24(dirname20(join38(dir, f)), { recursive: true });
17201
- copyFileSync(src, join38(dir, f));
17365
+ const src = join39(o.cwd, f);
17366
+ if (!existsSync35(src)) continue;
17367
+ mkdirSync25(dirname21(join39(dir, f)), { recursive: true });
17368
+ copyFileSync(src, join39(dir, f));
17202
17369
  }
17203
17370
  return { dir, branch, close };
17204
17371
  }
@@ -18220,7 +18387,7 @@ function missingReleaserWarning(repo, release, ships, now = Date.now()) {
18220
18387
  }
18221
18388
 
18222
18389
  // src/watch.ts
18223
- import { watch as watchFile, existsSync as existsSync35, statSync as statSync11, openSync as openSync4, readSync as readSync2, closeSync as closeSync4 } from "fs";
18390
+ import { watch as watchFile, existsSync as existsSync36, statSync as statSync11, openSync as openSync4, readSync as readSync2, closeSync as closeSync4 } from "fs";
18224
18391
  var E = "\x1B[";
18225
18392
  var dim = (s) => `${E}2m${s}${E}0m`;
18226
18393
  var bold = (s) => `${E}1m${s}${E}0m`;
@@ -18321,7 +18488,7 @@ function renderHeaders(states, now = Date.now()) {
18321
18488
  return states.map((s) => renderHeader(s, now)).join("");
18322
18489
  }
18323
18490
  function readFrom(file, from) {
18324
- if (!existsSync35(file)) return { events: [], offset: from };
18491
+ if (!existsSync36(file)) return { events: [], offset: from };
18325
18492
  const size = statSync11(file).size;
18326
18493
  if (size < from) return readFrom(file, 0);
18327
18494
  if (size === from) return { events: [], offset: from };
@@ -18564,8 +18731,8 @@ function nextRoles(decision, ran) {
18564
18731
  }
18565
18732
 
18566
18733
  // src/ship-name.ts
18567
- import { existsSync as existsSync36, mkdirSync as mkdirSync25, readFileSync as readFileSync32, renameSync as renameSync5, writeFileSync as writeFileSync28 } from "fs";
18568
- import { dirname as dirname21 } from "path";
18734
+ import { existsSync as existsSync37, mkdirSync as mkdirSync26, readFileSync as readFileSync33, renameSync as renameSync5, writeFileSync as writeFileSync29 } from "fs";
18735
+ import { dirname as dirname22 } from "path";
18569
18736
  import { parseDocument as parseDocument5 } from "yaml";
18570
18737
  var ShipNameError = class extends Error {
18571
18738
  };
@@ -18626,34 +18793,34 @@ async function syncRouteName(i) {
18626
18793
  return { status: "ok", ...base, action, name: i.local };
18627
18794
  }
18628
18795
  function readSyncedName(resolvedFile) {
18629
- if (!existsSync36(resolvedFile)) return void 0;
18796
+ if (!existsSync37(resolvedFile)) return void 0;
18630
18797
  try {
18631
- const v = JSON.parse(readFileSync32(resolvedFile, "utf8")).shipName;
18798
+ const v = JSON.parse(readFileSync33(resolvedFile, "utf8")).shipName;
18632
18799
  return typeof v === "string" ? v : void 0;
18633
18800
  } catch {
18634
18801
  return void 0;
18635
18802
  }
18636
18803
  }
18637
18804
  function writeSyncedName(resolvedFile, name) {
18638
- if (!existsSync36(resolvedFile)) return;
18805
+ if (!existsSync37(resolvedFile)) return;
18639
18806
  let raw;
18640
18807
  try {
18641
- raw = JSON.parse(readFileSync32(resolvedFile, "utf8"));
18808
+ raw = JSON.parse(readFileSync33(resolvedFile, "utf8"));
18642
18809
  } catch {
18643
18810
  return;
18644
18811
  }
18645
18812
  if (raw.shipName === name) return;
18646
18813
  raw.shipName = name;
18647
- mkdirSync25(dirname21(resolvedFile), { recursive: true });
18814
+ mkdirSync26(dirname22(resolvedFile), { recursive: true });
18648
18815
  const tmp = `${resolvedFile}.tmp${process.pid}`;
18649
- writeFileSync28(tmp, `${JSON.stringify(raw, null, 2)}
18816
+ writeFileSync29(tmp, `${JSON.stringify(raw, null, 2)}
18650
18817
  `);
18651
18818
  renameSync5(tmp, resolvedFile);
18652
18819
  }
18653
18820
  async function reconcileShipName(i) {
18654
18821
  let local = i.ship.name;
18655
18822
  try {
18656
- local = shipNameOfYaml(readFileSync32(i.configFile, "utf8")) ?? local;
18823
+ local = shipNameOfYaml(readFileSync33(i.configFile, "utf8")) ?? local;
18657
18824
  } catch {
18658
18825
  }
18659
18826
  const resolvedFile = resolvedPathFor(i.stateDir, i.route);
@@ -18677,8 +18844,8 @@ async function reconcileShipName(i) {
18677
18844
  }
18678
18845
  if (result.status !== "ok") return result;
18679
18846
  if (result.action === "adopt" || result.action === "row-wins") {
18680
- const text2 = readFileSync32(i.configFile, "utf8");
18681
- writeFileSync28(i.configFile, setShipNameInYaml(text2, result.name));
18847
+ const text2 = readFileSync33(i.configFile, "utf8");
18848
+ writeFileSync29(i.configFile, setShipNameInYaml(text2, result.name));
18682
18849
  i.ship.name = result.name;
18683
18850
  if (result.action === "row-wins") {
18684
18851
  i.emit?.warn(
@@ -19337,8 +19504,8 @@ function describeCapability(i) {
19337
19504
  }
19338
19505
 
19339
19506
  // src/agents-sync-run.ts
19340
- import { existsSync as existsSync37, mkdirSync as mkdirSync26, readFileSync as readFileSync33, writeFileSync as writeFileSync29 } from "fs";
19341
- import { dirname as dirname22 } from "path";
19507
+ import { existsSync as existsSync38, mkdirSync as mkdirSync27, readFileSync as readFileSync34, writeFileSync as writeFileSync30 } from "fs";
19508
+ import { dirname as dirname23 } from "path";
19342
19509
  async function runAgentsSync(target, o) {
19343
19510
  const dryRun = o.dryRun ?? false;
19344
19511
  const force = o.force ?? false;
@@ -19371,12 +19538,12 @@ async function runAgentsSync(target, o) {
19371
19538
  for (const s of skillResult?.outcomes ?? []) o.say(describeSkillSyncOutcome(s));
19372
19539
  if (!dryRun) {
19373
19540
  const resolvedPath = resolvedPathFor(o.stateDir, target.route);
19374
- const raw = existsSync37(resolvedPath) ? JSON.parse(readFileSync33(resolvedPath, "utf8")) : {};
19541
+ const raw = existsSync38(resolvedPath) ? JSON.parse(readFileSync34(resolvedPath, "utf8")) : {};
19375
19542
  raw.agentPersonas = personaResult.agentPersonas;
19376
19543
  if (skillResult) raw.agentSkills = skillResult.agentSkills;
19377
19544
  if (personaResult.releaseAgentId) raw.releaseAgentId = personaResult.releaseAgentId;
19378
- mkdirSync26(dirname22(resolvedPath), { recursive: true });
19379
- writeFileSync29(resolvedPath, `${JSON.stringify(raw, null, 2)}
19545
+ mkdirSync27(dirname23(resolvedPath), { recursive: true });
19546
+ writeFileSync30(resolvedPath, `${JSON.stringify(raw, null, 2)}
19380
19547
  `);
19381
19548
  if (target.resolved) {
19382
19549
  target.resolved.agentPersonas = personaResult.agentPersonas;
@@ -19480,7 +19647,7 @@ async function showLogEntry(route2, entryId, opts = {}) {
19480
19647
 
19481
19648
  // src/repos-check.ts
19482
19649
  import { spawnSync as spawnSync9 } from "child_process";
19483
- import { readFileSync as readFileSync34 } from "fs";
19650
+ import { readFileSync as readFileSync35 } from "fs";
19484
19651
  import { basename as basename11 } from "path";
19485
19652
  var POSIX_SHELL = /^(?:ba|z|da|k|a|mk)?sh$|^fish$/;
19486
19653
  function checkHookSyntax(script, shell) {
@@ -19521,7 +19688,7 @@ function checkRepoSpec(dir, opts = {}) {
19521
19688
  }
19522
19689
  let parsed;
19523
19690
  try {
19524
- parsed = parseRepoConfig(readFileSync34(file, "utf8"), file);
19691
+ parsed = parseRepoConfig(readFileSync35(file, "utf8"), file);
19525
19692
  } catch (e) {
19526
19693
  if (!(e instanceof RepoConfigError)) throw e;
19527
19694
  return { ...empty, file, error: e.message, exitCode: 1 };
@@ -19800,7 +19967,7 @@ function existingRepoConfig(f) {
19800
19967
  }
19801
19968
 
19802
19969
  // src/repos-hooks-agent.ts
19803
- import { spawn as spawn7, execFileSync as execFileSync10 } from "child_process";
19970
+ import { spawn as spawn7, execFileSync as execFileSync11 } from "child_process";
19804
19971
  import { realpathSync as realpathSync2 } from "fs";
19805
19972
  import { isAbsolute as isAbsolute3, relative } from "path";
19806
19973
  var AgentSuggestError = class extends Error {
@@ -19903,7 +20070,7 @@ function classifyFailure(o) {
19903
20070
  }
19904
20071
  function porcelain(dir) {
19905
20072
  try {
19906
- return execFileSync10("git", ["status", "--porcelain", "--untracked-files=all"], { cwd: dir, encoding: "utf8" });
20073
+ return execFileSync11("git", ["status", "--porcelain", "--untracked-files=all"], { cwd: dir, encoding: "utf8" });
19907
20074
  } catch {
19908
20075
  return void 0;
19909
20076
  }
@@ -19972,7 +20139,7 @@ ${run3.err}` });
19972
20139
  }
19973
20140
 
19974
20141
  // src/sample-ticket.ts
19975
- import { basename as basename12, dirname as dirname23, join as join39 } from "path";
20142
+ import { basename as basename12, dirname as dirname24, join as join40 } from "path";
19976
20143
  var SAMPLE_REPO = "crew-sample";
19977
20144
  var SAMPLE_REMOTE = `local/${SAMPLE_REPO}`;
19978
20145
  var SAMPLE_MARKER = "sample: true";
@@ -19995,8 +20162,8 @@ has something safe to work on: its test and build hooks always pass, it has no
19995
20162
  remote, and \`crew sample-ticket --remove\` deletes it.
19996
20163
  `;
19997
20164
  function sampleDir(existing, reposBase, workspace) {
19998
- if (existing.length > 0) return join39(dirname23(existing[0]), SAMPLE_REPO);
19999
- return join39(reposBase, workspace, SAMPLE_REPO);
20165
+ if (existing.length > 0) return join40(dirname24(existing[0]), SAMPLE_REPO);
20166
+ return join40(reposBase, workspace, SAMPLE_REPO);
20000
20167
  }
20001
20168
  var SAMPLE_TITLE = "Sample: add a documented `greet` function with a test";
20002
20169
  function sampleDescription() {
@@ -20040,8 +20207,8 @@ function planSampleTicket(i) {
20040
20207
  }
20041
20208
 
20042
20209
  // src/worktree-sweep.ts
20043
- import { existsSync as existsSync38, readFileSync as readFileSync35, readdirSync as readdirSync14 } from "fs";
20044
- import { basename as basename13, dirname as dirname24, join as join40, resolve as resolve5 } from "path";
20210
+ import { existsSync as existsSync39, readFileSync as readFileSync36, readdirSync as readdirSync14 } from "fs";
20211
+ import { basename as basename13, dirname as dirname25, join as join41, resolve as resolve5 } from "path";
20045
20212
  function planWorktreeSweep(target, tickets, contract) {
20046
20213
  const terminal = new Set(contract.statuses.resolved.filter((s) => s !== contract.statuses.verified));
20047
20214
  const verified = contract.statuses.verified;
@@ -20105,7 +20272,7 @@ function worktreeTicketNumbers(target) {
20105
20272
  return [...nums];
20106
20273
  }
20107
20274
  function siblingWorktreeDirs(target) {
20108
- const parent = dirname24(target.dir.replace(/[/\\]+$/, ""));
20275
+ const parent = dirname25(target.dir.replace(/[/\\]+$/, ""));
20109
20276
  const stem = `${basename13(target.dir.replace(/[/\\]+$/, ""))}-`;
20110
20277
  const registered = new Set(worktrees(target.dir).map((w) => resolve5(w.path)));
20111
20278
  let names;
@@ -20118,7 +20285,7 @@ function siblingWorktreeDirs(target) {
20118
20285
  for (const name of names) {
20119
20286
  if (!name.startsWith(stem)) continue;
20120
20287
  const m = DIR_NUMBER_SUFFIXED.exec(name);
20121
- const path = join40(parent, name);
20288
+ const path = join41(parent, name);
20122
20289
  if (m && !registered.has(resolve5(path))) out.push({ path, number: m[1] });
20123
20290
  }
20124
20291
  return out;
@@ -20153,7 +20320,7 @@ async function applyWorktreeSweep(cwd, actions, dryRun, log, remote = "origin",
20153
20320
  let removed = 0;
20154
20321
  let keptBranches = 0;
20155
20322
  for (const a of actions) {
20156
- if (!dryRun && base && !a.keepBranch && existsSync38(a.path) && isHandBackMerge(a.path, base)) {
20323
+ if (!dryRun && base && !a.keepBranch && existsSync39(a.path) && isHandBackMerge(a.path, base)) {
20157
20324
  if (gitOk(a.path, ["merge", "--abort"]) !== null) {
20158
20325
  log.emit(
20159
20326
  `abandoned the hand-back merge of ${base} in ${a.path}: ${a.ticket.issue_id} deployed without it`,
@@ -20161,7 +20328,7 @@ async function applyWorktreeSweep(cwd, actions, dryRun, log, remote = "origin",
20161
20328
  );
20162
20329
  }
20163
20330
  }
20164
- if (!dryRun && existsSync38(a.path)) {
20331
+ if (!dryRun && existsSync39(a.path)) {
20165
20332
  let dirty = false;
20166
20333
  try {
20167
20334
  dirty = status(a.path).length > 0;
@@ -20172,7 +20339,7 @@ async function applyWorktreeSweep(cwd, actions, dryRun, log, remote = "origin",
20172
20339
  continue;
20173
20340
  }
20174
20341
  }
20175
- if (!dryRun && a.requirePushed && a.branch && existsSync38(a.path) && remoteConfigured(cwd, remote) && worktreeHoldsUnpushed(a.path, remote)) {
20342
+ if (!dryRun && a.requirePushed && a.branch && existsSync39(a.path) && remoteConfigured(cwd, remote) && worktreeHoldsUnpushed(a.path, remote)) {
20176
20343
  refuse(a, "unpushed commits", `${a.branch} has commits that are not on ${remote}`);
20177
20344
  continue;
20178
20345
  }
@@ -20221,7 +20388,7 @@ function isHandBackMerge(path, base) {
20221
20388
  if (!msgPath) return false;
20222
20389
  let first;
20223
20390
  try {
20224
- first = readFileSync35(resolve5(path, msgPath), "utf8").split("\n")[0] ?? "";
20391
+ first = readFileSync36(resolve5(path, msgPath), "utf8").split("\n")[0] ?? "";
20225
20392
  } catch {
20226
20393
  return false;
20227
20394
  }
@@ -20326,14 +20493,14 @@ function applyRemoteBranchCleanup(cwd, remote, branches2, dryRun, log) {
20326
20493
  }
20327
20494
 
20328
20495
  // src/stream-sweep.ts
20329
- import { existsSync as existsSync39, readdirSync as readdirSync15, rmSync as rmSync18, statSync as statSync12 } from "fs";
20330
- import { join as join41 } from "path";
20496
+ import { existsSync as existsSync40, readdirSync as readdirSync15, rmSync as rmSync18, statSync as statSync12 } from "fs";
20497
+ import { join as join42 } from "path";
20331
20498
  var DAY_MS2 = 24 * 60 * 60 * 1e3;
20332
20499
  function planStreamSweep(stateDir, retentionDays, now = Date.now()) {
20333
- const dir = join41(stateDir, "streams");
20334
- if (!existsSync39(dir)) return [];
20500
+ const dir = join42(stateDir, "streams");
20501
+ if (!existsSync40(dir)) return [];
20335
20502
  const cutoff = now - retentionDays * DAY_MS2;
20336
- return readdirSync15(dir).map((name) => join41(dir, name)).filter((path) => {
20503
+ return readdirSync15(dir).map((name) => join42(dir, name)).filter((path) => {
20337
20504
  try {
20338
20505
  return statSync12(path).mtimeMs < cutoff;
20339
20506
  } catch {
@@ -20359,9 +20526,9 @@ function applyStreamSweep(paths, dryRun, log) {
20359
20526
  return removed;
20360
20527
  }
20361
20528
  function planEventsSweep(stateDir, retentionDays, now = Date.now()) {
20362
- if (!existsSync39(stateDir)) return [];
20529
+ if (!existsSync40(stateDir)) return [];
20363
20530
  const cutoff = now - retentionDays * DAY_MS2;
20364
- return readdirSync15(stateDir).filter((name) => ROTATED_EVENTS_RE.test(name)).map((name) => join41(stateDir, name)).filter((path) => {
20531
+ return readdirSync15(stateDir).filter((name) => ROTATED_EVENTS_RE.test(name)).map((name) => join42(stateDir, name)).filter((path) => {
20365
20532
  try {
20366
20533
  return statSync12(path).mtimeMs < cutoff;
20367
20534
  } catch {
@@ -20371,12 +20538,12 @@ function planEventsSweep(stateDir, retentionDays, now = Date.now()) {
20371
20538
  }
20372
20539
 
20373
20540
  // src/cli.ts
20374
- import { realpathSync as realpathSync3, readFileSync as readFileSync41, existsSync as existsSync46, mkdirSync as mkdirSync33, writeFileSync as writeFileSync34, rmSync as rmSync23, unlinkSync as unlinkSync5, copyFileSync as copyFileSync2, renameSync as renameSync6, statSync as statSync16, readdirSync as readdirSync20 } from "fs";
20541
+ import { realpathSync as realpathSync3, readFileSync as readFileSync42, existsSync as existsSync47, mkdirSync as mkdirSync34, writeFileSync as writeFileSync35, rmSync as rmSync23, unlinkSync as unlinkSync5, copyFileSync as copyFileSync2, renameSync as renameSync6, statSync as statSync16, readdirSync as readdirSync20 } from "fs";
20375
20542
  import { createInterface } from "readline/promises";
20376
20543
 
20377
20544
  // src/periscope-cmd.ts
20378
- import { existsSync as existsSync40, mkdirSync as mkdirSync27, readFileSync as readFileSync36, rmSync as rmSync19, writeFileSync as writeFileSync30 } from "fs";
20379
- import { join as join42 } from "path";
20545
+ import { existsSync as existsSync41, mkdirSync as mkdirSync28, readFileSync as readFileSync37, rmSync as rmSync19, writeFileSync as writeFileSync31 } from "fs";
20546
+ import { join as join43 } from "path";
20380
20547
  var PeriscopeError = class extends Error {
20381
20548
  };
20382
20549
  var LivePeriscopeError = class extends PeriscopeError {
@@ -20386,28 +20553,29 @@ var LivePeriscopeError = class extends PeriscopeError {
20386
20553
  this.data = { refused: "live_periscope_exists", ...live };
20387
20554
  }
20388
20555
  };
20389
- var priorDir = (stateDir) => join42(stateDir, "periscope-priors");
20390
- var priorPath = (stateDir, ticketRecordId) => join42(priorDir(stateDir), `${ticketRecordId}.json`);
20556
+ var priorDir = (stateDir) => join43(stateDir, "periscope-priors");
20557
+ var priorPath = (stateDir, ticketRecordId) => join43(priorDir(stateDir), `${ticketRecordId}.json`);
20391
20558
  function removePeriscopePrior(stateDir, ticketRecordId) {
20392
20559
  rmSync19(priorPath(stateDir, ticketRecordId), { force: true });
20393
20560
  }
20394
20561
  function writePeriscopePrior(stateDir, ticketRecordId, prior) {
20395
20562
  try {
20396
- mkdirSync27(priorDir(stateDir), { recursive: true });
20397
- writeFileSync30(priorPath(stateDir, ticketRecordId), JSON.stringify(prior));
20563
+ mkdirSync28(priorDir(stateDir), { recursive: true });
20564
+ writeFileSync31(priorPath(stateDir, ticketRecordId), JSON.stringify(prior));
20398
20565
  } catch {
20399
20566
  }
20400
20567
  }
20401
20568
  function readPeriscopePrior(stateDir, ticketRecordId) {
20402
20569
  try {
20403
20570
  const p = priorPath(stateDir, ticketRecordId);
20404
- return existsSync40(p) ? JSON.parse(readFileSync36(p, "utf8")) : void 0;
20571
+ return existsSync41(p) ? JSON.parse(readFileSync37(p, "utf8")) : void 0;
20405
20572
  } catch {
20406
20573
  return void 0;
20407
20574
  }
20408
20575
  }
20409
20576
  var DEFAULT_MAX_PERISCOPES2 = 3;
20410
20577
  var DEFAULT_PERISCOPE_IDLE_MINUTES2 = 120;
20578
+ var DEFAULT_INTEL_STARTUP_SECONDS2 = 20;
20411
20579
  function parsePeriscopeUpArgs(positional2, flags) {
20412
20580
  const usage2 = "usage: crew periscope up [[route] REPO] [--topic TEXT | --issue NNN] [--isolate] [--host HOST] [--assignee CREW_ROW_ID] [--requested-by ID] [--no-open] [--json]";
20413
20581
  const rest = positional2.slice(2);
@@ -20475,12 +20643,15 @@ function openerFor(platform2) {
20475
20643
  return platform2 === "darwin" ? "open" : platform2 === "linux" ? "xdg-open" : void 0;
20476
20644
  }
20477
20645
  function upOutput(res, terminal) {
20478
- return terminal ? `${res.ticket}
20646
+ const block = terminal ? `${res.ticket}
20479
20647
  ${res.url}
20480
20648
  ${res.worktree}
20481
20649
  ` : `${res.ticket}
20482
20650
  ${res.worktree}
20483
20651
  ${res.url}
20652
+ `;
20653
+ return `${block}
20654
+ ${res.codeTools}
20484
20655
  `;
20485
20656
  }
20486
20657
  function shouldOpen(f) {
@@ -20577,6 +20748,23 @@ ${tail(preview?.output ?? "")}`);
20577
20748
  if (!url) return abandon(`preview printed no URL as its last line
20578
20749
  ${tail(preview.output)}`);
20579
20750
  d.say("preview", `preview at ${url}`, { url });
20751
+ const intel = await probeIntel(
20752
+ { runHook: (e) => d.runHook("intel", wt.path, e) },
20753
+ env,
20754
+ d.intelStartupSeconds ?? DEFAULT_INTEL_STARTUP_SECONDS2
20755
+ );
20756
+ if (intel.state === "ready") d.say("intel", `symbol service at ${intel.url} (${intel.tools.length} tools)`, { intelUrl: intel.url, intelTools: intel.tools });
20757
+ else if (intel.state === "failed") d.say("warning", `symbol service not started: ${intel.reason}`);
20758
+ let codeOutcome = intel;
20759
+ if (intel.state === "ready" && d.registerCode) {
20760
+ try {
20761
+ for (const why of d.registerCode(wt.path, intel.url).skipped) d.say("warning", why);
20762
+ } catch (e) {
20763
+ codeOutcome = { state: "failed", reason: `registering it failed: ${e.message}` };
20764
+ d.say("warning", `symbol service not registered: ${e.message}`);
20765
+ }
20766
+ }
20767
+ const codeTools = codeToolsParagraph(codeOutcome);
20580
20768
  const now = d.now();
20581
20769
  let row;
20582
20770
  try {
@@ -20608,6 +20796,7 @@ ${tail(preview.output)}`);
20608
20796
  host: d.host,
20609
20797
  state: "live",
20610
20798
  isolated: args.isolate,
20799
+ ...intel.state === "ready" ? { intelUrl: intel.url, intelTools: intel.tools } : {},
20611
20800
  startedAt: now.toISOString(),
20612
20801
  lastActivityAt: now.toISOString(),
20613
20802
  expiresAt: new Date(now.getTime() + d.caps.idleMinutes * 6e4).toISOString()
@@ -20625,6 +20814,7 @@ ${tail(preview.output)}`);
20625
20814
  branch: wt.branch,
20626
20815
  url,
20627
20816
  periscopeRecordId: row.id,
20817
+ codeTools,
20628
20818
  ...prior ? { existing: true, priorStatus: prior.status } : {}
20629
20819
  };
20630
20820
  }
@@ -20804,9 +20994,9 @@ ${tail2(preview.output)}`);
20804
20994
  }
20805
20995
 
20806
20996
  // src/periscope-idle.ts
20807
- import { execFileSync as execFileSync11 } from "child_process";
20997
+ import { execFileSync as execFileSync12 } from "child_process";
20808
20998
  import { statSync as statSync13 } from "fs";
20809
- import { join as join43 } from "path";
20999
+ import { join as join44 } from "path";
20810
21000
  var MAX_SCANNED_FILES = 2e4;
20811
21001
  function newestWorktreeMtime(root) {
20812
21002
  const a = newestTrackedMtime(root);
@@ -20816,7 +21006,7 @@ function newestWorktreeMtime(root) {
20816
21006
  function newestTrackedMtime(root) {
20817
21007
  let listing;
20818
21008
  try {
20819
- listing = execFileSync11("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
21009
+ listing = execFileSync12("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
20820
21010
  cwd: root,
20821
21011
  encoding: "utf8",
20822
21012
  stdio: ["ignore", "pipe", "ignore"],
@@ -20831,7 +21021,7 @@ function newestTrackedMtime(root) {
20831
21021
  if (!rel) continue;
20832
21022
  if (++scanned > MAX_SCANNED_FILES) break;
20833
21023
  try {
20834
- const m = statSync13(join43(root, rel)).mtimeMs;
21024
+ const m = statSync13(join44(root, rel)).mtimeMs;
20835
21025
  if (newest === null || m > newest) newest = m;
20836
21026
  } catch {
20837
21027
  }
@@ -20906,21 +21096,21 @@ async function runPeriscopeIdlePass(d) {
20906
21096
  import { dirname as dirOf2, resolve as resolvePath } from "path";
20907
21097
 
20908
21098
  // src/ssh-keys.ts
20909
- import { execFileSync as execFileSync12 } from "child_process";
20910
- import { existsSync as existsSync41, mkdirSync as mkdirSync28, readFileSync as readFileSync37, chmodSync as chmodSync3 } from "fs";
20911
- import { dirname as dirname25, join as join44 } from "path";
21099
+ import { execFileSync as execFileSync13 } from "child_process";
21100
+ import { existsSync as existsSync42, mkdirSync as mkdirSync29, readFileSync as readFileSync38, chmodSync as chmodSync3 } from "fs";
21101
+ import { dirname as dirname26, join as join45 } from "path";
20912
21102
  var SshKeyError = class extends Error {
20913
21103
  };
20914
21104
  function shipSshKeyPathFor(stateDir) {
20915
- return join44(stateDir, "ssh", "id_ed25519");
21105
+ return join45(stateDir, "ssh", "id_ed25519");
20916
21106
  }
20917
21107
  function ensureShipSshKeypair(stateDir) {
20918
21108
  const privateKeyPath = shipSshKeyPathFor(stateDir);
20919
21109
  const publicKeyPath = `${privateKeyPath}.pub`;
20920
- if (!existsSync41(privateKeyPath)) {
20921
- mkdirSync28(dirname25(privateKeyPath), { recursive: true });
21110
+ if (!existsSync42(privateKeyPath)) {
21111
+ mkdirSync29(dirname26(privateKeyPath), { recursive: true });
20922
21112
  try {
20923
- execFileSync12("ssh-keygen", [
21113
+ execFileSync13("ssh-keygen", [
20924
21114
  "-t",
20925
21115
  "ed25519",
20926
21116
  "-N",
@@ -20938,15 +21128,15 @@ function ensureShipSshKeypair(stateDir) {
20938
21128
  }
20939
21129
  chmodSync3(privateKeyPath, 384);
20940
21130
  }
20941
- if (!existsSync41(publicKeyPath)) {
21131
+ if (!existsSync42(publicKeyPath)) {
20942
21132
  throw new SshKeyError(`${privateKeyPath} exists but ${publicKeyPath} does not \u2014 regenerate or restore it`);
20943
21133
  }
20944
- const publicKey = readFileSync37(publicKeyPath, "utf8").trim();
21134
+ const publicKey = readFileSync38(publicKeyPath, "utf8").trim();
20945
21135
  return { privateKeyPath, publicKeyPath, publicKey };
20946
21136
  }
20947
21137
  function sshKeygenAvailable() {
20948
21138
  try {
20949
- execFileSync12("ssh-keygen", ["-V"], { stdio: ["ignore", "ignore", "ignore"] });
21139
+ execFileSync13("ssh-keygen", ["-V"], { stdio: ["ignore", "ignore", "ignore"] });
20950
21140
  return true;
20951
21141
  } catch (e) {
20952
21142
  return e.code !== "ENOENT";
@@ -21105,12 +21295,12 @@ async function unregisterEndpoint(workspaceId, info, d) {
21105
21295
  import { createServer as createHttpServer } from "http";
21106
21296
  import { spawn as spawn8 } from "child_process";
21107
21297
  import { randomBytes } from "crypto";
21108
- import { existsSync as existsSync42, mkdirSync as mkdirSync30, readFileSync as readFileSync38, writeFileSync as writeFileSync31, unlinkSync as unlinkSync4, readdirSync as readdirSync16 } from "fs";
21109
- import { join as join45 } from "path";
21298
+ import { existsSync as existsSync43, mkdirSync as mkdirSync31, readFileSync as readFileSync39, writeFileSync as writeFileSync32, unlinkSync as unlinkSync4, readdirSync as readdirSync16 } from "fs";
21299
+ import { join as join46 } from "path";
21110
21300
 
21111
21301
  // src/passenger-mirror.ts
21112
- import { mkdirSync as mkdirSync29 } from "fs";
21113
- import { dirname as dirname26 } from "path";
21302
+ import { mkdirSync as mkdirSync30 } from "fs";
21303
+ import { dirname as dirname27 } from "path";
21114
21304
  function mirrorRepoOf(spec) {
21115
21305
  const fromOrigin = spec.originUrl ? parseRemote(spec.originUrl) : null;
21116
21306
  if (fromOrigin) return fromOrigin;
@@ -21128,9 +21318,9 @@ async function materializeMirrorCheckouts(specs, cacheFor = (s) => new SandboxCa
21128
21318
  continue;
21129
21319
  }
21130
21320
  try {
21131
- const parent = dirname26(spec.dir);
21132
- mkdirSync29(parent, { recursive: true });
21133
- mkdirSync29(spec.dir, { recursive: true });
21321
+ const parent = dirname27(spec.dir);
21322
+ mkdirSync30(parent, { recursive: true });
21323
+ mkdirSync30(spec.dir, { recursive: true });
21134
21324
  const r = await cacheFor(spec).materialize(repo, spec.base, parent, spec.name);
21135
21325
  out.push({ ...base, action: r.changed ? "updated" : "unchanged", detail: r.tip });
21136
21326
  } catch (e) {
@@ -21236,21 +21426,21 @@ var defaultSpawn2 = (cmd, args, env) => {
21236
21426
  return child;
21237
21427
  };
21238
21428
  function syncDaemonStatePath(stateDir, workspaceId) {
21239
- return join45(stateDir, "passengers", `${workspaceId}-sync.json`);
21429
+ return join46(stateDir, "passengers", `${workspaceId}-sync.json`);
21240
21430
  }
21241
21431
  function readPersistedSyncDaemon(stateDir, workspaceId) {
21242
21432
  const path = syncDaemonStatePath(stateDir, workspaceId);
21243
- if (!existsSync42(path)) return void 0;
21433
+ if (!existsSync43(path)) return void 0;
21244
21434
  try {
21245
- return JSON.parse(readFileSync38(path, "utf8"));
21435
+ return JSON.parse(readFileSync39(path, "utf8"));
21246
21436
  } catch {
21247
21437
  return void 0;
21248
21438
  }
21249
21439
  }
21250
21440
  function writePersistedSyncDaemon(stateDir, state) {
21251
21441
  const path = syncDaemonStatePath(stateDir, state.workspaceId);
21252
- mkdirSync30(join45(stateDir, "passengers"), { recursive: true });
21253
- writeFileSync31(path, `${JSON.stringify(state, null, 2)}
21442
+ mkdirSync31(join46(stateDir, "passengers"), { recursive: true });
21443
+ writeFileSync32(path, `${JSON.stringify(state, null, 2)}
21254
21444
  `);
21255
21445
  }
21256
21446
  function removePersistedSyncDaemon(stateDir, workspaceId) {
@@ -21270,8 +21460,8 @@ function waitForExit(pid, alive, timeoutMs = 5e3) {
21270
21460
  }
21271
21461
  }
21272
21462
  function readAllPersistedSyncWorkspaceIds(stateDir) {
21273
- const dir = join45(stateDir, "passengers");
21274
- if (!existsSync42(dir)) return [];
21463
+ const dir = join46(stateDir, "passengers");
21464
+ if (!existsSync43(dir)) return [];
21275
21465
  const suffix = "-sync.json";
21276
21466
  return readdirSync16(dir).filter((f) => f.endsWith(suffix)).map((f) => f.slice(0, -suffix.length));
21277
21467
  }
@@ -21359,8 +21549,8 @@ function describeCause(err3) {
21359
21549
  }
21360
21550
 
21361
21551
  // src/daemon.ts
21362
- import { existsSync as existsSync43, mkdirSync as mkdirSync31, readFileSync as readFileSync39, readdirSync as readdirSync17, rmSync as rmSync20, statSync as statSync14, writeFileSync as writeFileSync32 } from "fs";
21363
- import { join as join46 } from "path";
21552
+ import { existsSync as existsSync44, mkdirSync as mkdirSync32, readFileSync as readFileSync40, readdirSync as readdirSync17, rmSync as rmSync20, statSync as statSync14, writeFileSync as writeFileSync33 } from "fs";
21553
+ import { join as join47 } from "path";
21364
21554
  import { randomBytes as randomBytes2 } from "crypto";
21365
21555
  var DEFAULT_FLOOR_MS = 5e3;
21366
21556
  var DEFAULT_CEILING_MS = INTERVAL_SECONDS * 1e3;
@@ -21448,7 +21638,7 @@ function latestMtime(path) {
21448
21638
  if (!stat2.isDirectory()) return 0;
21449
21639
  let latest = stat2.mtimeMs;
21450
21640
  for (const entry of readdirSync17(path, { withFileTypes: true })) {
21451
- latest = Math.max(latest, latestMtime(join46(path, entry.name)));
21641
+ latest = Math.max(latest, latestMtime(join47(path, entry.name)));
21452
21642
  }
21453
21643
  return latest;
21454
21644
  }
@@ -21457,10 +21647,10 @@ function computeTreeSignature(paths) {
21457
21647
  }
21458
21648
  function makeStaleChecker(paths, opts = {}) {
21459
21649
  const initial = computeTreeSignature(paths);
21460
- return () => computeTreeSignature(paths) !== initial || opts.reloadSentinel !== void 0 && existsSync43(opts.reloadSentinel);
21650
+ return () => computeTreeSignature(paths) !== initial || opts.reloadSentinel !== void 0 && existsSync44(opts.reloadSentinel);
21461
21651
  }
21462
21652
  function reloadSentinelFor(stateDir) {
21463
- return join46(stateDir, "reload-requested");
21653
+ return join47(stateDir, "reload-requested");
21464
21654
  }
21465
21655
  function readReloadRequestedAt(stateDir) {
21466
21656
  try {
@@ -21470,17 +21660,17 @@ function readReloadRequestedAt(stateDir) {
21470
21660
  }
21471
21661
  }
21472
21662
  function daemonStampFor(stateDir) {
21473
- return join46(stateDir, "daemon.started");
21663
+ return join47(stateDir, "daemon.started");
21474
21664
  }
21475
21665
  function noteDaemonStarted(stateDir, now = Date.now()) {
21476
- mkdirSync31(stateDir, { recursive: true });
21666
+ mkdirSync32(stateDir, { recursive: true });
21477
21667
  rmSync20(reloadSentinelFor(stateDir), { force: true });
21478
- writeFileSync32(daemonStampFor(stateDir), `${JSON.stringify({ pid: process.pid, startedAt: now })}
21668
+ writeFileSync33(daemonStampFor(stateDir), `${JSON.stringify({ pid: process.pid, startedAt: now })}
21479
21669
  `);
21480
21670
  }
21481
21671
  function readDaemonStarted(stateDir) {
21482
21672
  try {
21483
- const v = JSON.parse(readFileSync39(daemonStampFor(stateDir), "utf8")).startedAt;
21673
+ const v = JSON.parse(readFileSync40(daemonStampFor(stateDir), "utf8")).startedAt;
21484
21674
  return typeof v === "number" ? v : null;
21485
21675
  } catch {
21486
21676
  return null;
@@ -22046,7 +22236,7 @@ import { createHash as createHash10 } from "crypto";
22046
22236
  import {
22047
22237
  chmodSync as chmodSync4,
22048
22238
  closeSync as closeSync5,
22049
- existsSync as existsSync44,
22239
+ existsSync as existsSync45,
22050
22240
  fstatSync,
22051
22241
  openSync as openSync5,
22052
22242
  readSync as readSync3,
@@ -22057,7 +22247,7 @@ import {
22057
22247
  } from "fs";
22058
22248
  import { createConnection } from "net";
22059
22249
  import { createServer } from "http";
22060
- import { basename as basename14, dirname as dirname27, join as join47 } from "path";
22250
+ import { basename as basename14, dirname as dirname28, join as join48 } from "path";
22061
22251
  import { execFile as execFile3, spawn as spawn10 } from "child_process";
22062
22252
 
22063
22253
  // src/periscope-control.ts
@@ -22286,7 +22476,7 @@ function runCrew(args, onLine, timeoutMs = 20 * 6e4) {
22286
22476
  // src/control-api.ts
22287
22477
  var PAUSABLE = ["dev", "design", "qa"];
22288
22478
  var CONTROL_SOCKET_NAME = "control.sock";
22289
- var controlSocketFor = (stateDir) => join47(stateDir, CONTROL_SOCKET_NAME);
22479
+ var controlSocketFor = (stateDir) => join48(stateDir, CONTROL_SOCKET_NAME);
22290
22480
  var MAX_SOCKET_PATH = 100;
22291
22481
  var MAX_TAIL_BYTES = 1024 * 1024;
22292
22482
  var MAX_WAIT_SECONDS = 30;
@@ -22373,7 +22563,7 @@ function candidates(live, rotated) {
22373
22563
  const out = [live];
22374
22564
  if (!rotated) return out;
22375
22565
  try {
22376
- for (const n of readdirSync18(dirname27(live))) if (ROTATED_EVENTS_RE.test(n)) out.push(join47(dirname27(live), n));
22566
+ for (const n of readdirSync18(dirname28(live))) if (ROTATED_EVENTS_RE.test(n)) out.push(join48(dirname28(live), n));
22377
22567
  } catch {
22378
22568
  }
22379
22569
  return out;
@@ -22417,7 +22607,7 @@ function lastLines2(path, n) {
22417
22607
  }
22418
22608
  function readTail(live, opts) {
22419
22609
  const max = opts.maxBytes ?? MAX_TAIL_BYTES;
22420
- if (!existsSync44(live)) {
22610
+ if (!existsSync45(live)) {
22421
22611
  return { lines: [], cursor: opts.after ?? encodeCursor({ dev: 0, ino: 0, off: 0 }), reset: false };
22422
22612
  }
22423
22613
  const cur = opts.after ? decodeCursor(opts.after) : null;
@@ -22533,7 +22723,7 @@ async function tailReply(path, q2, rotated, abort) {
22533
22723
  const deadline = Date.now() + Math.min(wait, MAX_WAIT_SECONDS) * 1e3;
22534
22724
  let r = readTail(path, { after, tail: tail3, rotated });
22535
22725
  while (after && !r.lines.length && !r.reset && Date.now() < deadline && !abort.aborted) {
22536
- await waitForChange(dirname27(path), deadline - Date.now(), abort);
22726
+ await waitForChange(dirname28(path), deadline - Date.now(), abort);
22537
22727
  r = readTail(path, { after: r.cursor, rotated });
22538
22728
  }
22539
22729
  return reply2(200, r);
@@ -22573,8 +22763,8 @@ async function route(deps, method, url, req, abort) {
22573
22763
  if (p.startsWith("/streams/") && get2) {
22574
22764
  const run3 = decodeURIComponent(p.slice("/streams/".length));
22575
22765
  if (!RUN_NAME_RE.test(run3) || run3.includes("..") || /\.(pid|meta\.json|events\.jsonl)$/.test(run3)) return err2(400, "not a run name");
22576
- const file = join47(deps.stateDir, "streams", run3.endsWith(".jsonl") ? run3 : `${run3}.jsonl`);
22577
- if (!existsSync44(file)) return err2(404, "no such run");
22766
+ const file = join48(deps.stateDir, "streams", run3.endsWith(".jsonl") ? run3 : `${run3}.jsonl`);
22767
+ if (!existsSync45(file)) return err2(404, "no such run");
22578
22768
  return tailReply(file, url.searchParams, false, abort);
22579
22769
  }
22580
22770
  if ((p === "/pause" || p === "/resume") && post3) {
@@ -22618,7 +22808,7 @@ function send(res, r) {
22618
22808
  res.end(body);
22619
22809
  }
22620
22810
  async function socketIsStale(path) {
22621
- if (!existsSync44(path)) return false;
22811
+ if (!existsSync45(path)) return false;
22622
22812
  return new Promise((resolve8) => {
22623
22813
  const c = createConnection(path);
22624
22814
  c.once("connect", () => {
@@ -22637,7 +22827,7 @@ async function startControlServer(deps) {
22637
22827
  return null;
22638
22828
  }
22639
22829
  if (await socketIsStale(path)) rmSync21(path, { force: true });
22640
- else if (existsSync44(path)) {
22830
+ else if (existsSync45(path)) {
22641
22831
  log(`control API not started: ${path} is in use by another process`);
22642
22832
  return null;
22643
22833
  }
@@ -22723,31 +22913,31 @@ function crewJson(args, timeoutMs = 6e4) {
22723
22913
 
22724
22914
  // src/periscope-mcp.ts
22725
22915
  import { lstat, mkdir, readdir, readFile, readlink, realpath, rm, stat, writeFile } from "fs/promises";
22726
- import { basename as basename15, dirname as dirname28, isAbsolute as isAbsolute4, join as join49, relative as relative2, resolve as resolve6, sep } from "path";
22916
+ import { basename as basename15, dirname as dirname29, isAbsolute as isAbsolute4, join as join50, relative as relative2, resolve as resolve6, sep } from "path";
22727
22917
  import { z } from "zod";
22728
22918
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
22729
22919
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
22730
22920
 
22731
22921
  // src/periscope-endpoints.ts
22732
22922
  import { randomBytes as randomBytes3 } from "crypto";
22733
- import { chmodSync as chmodSync5, existsSync as existsSync45, mkdirSync as mkdirSync32, readdirSync as readdirSync19, readFileSync as readFileSync40, rmSync as rmSync22, writeFileSync as writeFileSync33 } from "fs";
22734
- import { join as join48 } from "path";
22735
- var secretDir = (stateDir) => join48(stateDir, "periscope-mcp");
22736
- var secretFile = (stateDir, id) => join48(secretDir(stateDir), `${id}.json`);
22737
- var endpointDir = (stateDir) => join48(stateDir, "periscope-endpoints");
22738
- var endpointFile = (stateDir, id) => join48(endpointDir(stateDir), `${id}.json`);
22923
+ import { chmodSync as chmodSync5, existsSync as existsSync46, mkdirSync as mkdirSync33, readdirSync as readdirSync19, readFileSync as readFileSync41, rmSync as rmSync22, writeFileSync as writeFileSync34 } from "fs";
22924
+ import { join as join49 } from "path";
22925
+ var secretDir = (stateDir) => join49(stateDir, "periscope-mcp");
22926
+ var secretFile = (stateDir, id) => join49(secretDir(stateDir), `${id}.json`);
22927
+ var endpointDir = (stateDir) => join49(stateDir, "periscope-endpoints");
22928
+ var endpointFile = (stateDir, id) => join49(endpointDir(stateDir), `${id}.json`);
22739
22929
  function mintPeriscopeSecret(stateDir, ticketRecordId) {
22740
- mkdirSync32(secretDir(stateDir), { recursive: true, mode: 448 });
22930
+ mkdirSync33(secretDir(stateDir), { recursive: true, mode: 448 });
22741
22931
  const secret = randomBytes3(32).toString("base64url");
22742
22932
  const file = secretFile(stateDir, ticketRecordId);
22743
- writeFileSync33(file, `${JSON.stringify({ secret })}
22933
+ writeFileSync34(file, `${JSON.stringify({ secret })}
22744
22934
  `, { mode: 384 });
22745
22935
  chmodSync5(file, 384);
22746
22936
  return secret;
22747
22937
  }
22748
22938
  function readPeriscopeSecret(stateDir, ticketRecordId) {
22749
22939
  try {
22750
- const v = JSON.parse(readFileSync40(secretFile(stateDir, ticketRecordId), "utf8"));
22940
+ const v = JSON.parse(readFileSync41(secretFile(stateDir, ticketRecordId), "utf8"));
22751
22941
  return typeof v.secret === "string" && v.secret ? v.secret : void 0;
22752
22942
  } catch {
22753
22943
  return void 0;
@@ -22758,14 +22948,14 @@ function removePeriscopeSecret(stateDir, ticketRecordId) {
22758
22948
  }
22759
22949
  function readPeriscopeEndpoint(stateDir, ticketRecordId) {
22760
22950
  try {
22761
- return JSON.parse(readFileSync40(endpointFile(stateDir, ticketRecordId), "utf8"));
22951
+ return JSON.parse(readFileSync41(endpointFile(stateDir, ticketRecordId), "utf8"));
22762
22952
  } catch {
22763
22953
  return void 0;
22764
22954
  }
22765
22955
  }
22766
22956
  function writePeriscopeEndpoint(stateDir, rec) {
22767
- mkdirSync32(endpointDir(stateDir), { recursive: true });
22768
- writeFileSync33(endpointFile(stateDir, rec.ticketRecordId), `${JSON.stringify(rec, null, 2)}
22957
+ mkdirSync33(endpointDir(stateDir), { recursive: true });
22958
+ writeFileSync34(endpointFile(stateDir, rec.ticketRecordId), `${JSON.stringify(rec, null, 2)}
22769
22959
  `);
22770
22960
  }
22771
22961
  function removePeriscopeEndpointRecord(stateDir, ticketRecordId) {
@@ -22773,7 +22963,7 @@ function removePeriscopeEndpointRecord(stateDir, ticketRecordId) {
22773
22963
  }
22774
22964
  function listPeriscopeEndpoints(stateDir) {
22775
22965
  const dir = endpointDir(stateDir);
22776
- if (!existsSync45(dir)) return [];
22966
+ if (!existsSync46(dir)) return [];
22777
22967
  const out = [];
22778
22968
  for (const name of readdirSync19(dir)) {
22779
22969
  if (!name.endsWith(".json")) continue;
@@ -22861,10 +23051,10 @@ async function realAncestor(p) {
22861
23051
  }
22862
23052
  if (isLink) {
22863
23053
  if (++hops > 40) throw new PathRefusal(`too many symbolic links resolving ${p}`);
22864
- cur = resolve6(dirname28(cur), await readlink(cur));
23054
+ cur = resolve6(dirname29(cur), await readlink(cur));
22865
23055
  continue;
22866
23056
  }
22867
- const parent = dirname28(cur);
23057
+ const parent = dirname29(cur);
22868
23058
  if (parent === cur) throw new PathRefusal(`cannot resolve ${p}`);
22869
23059
  tail3.push(basename15(cur));
22870
23060
  cur = parent;
@@ -22876,13 +23066,13 @@ async function resolveInWorktree(root, requested) {
22876
23066
  let abs;
22877
23067
  if (isAbsolute4(requested)) {
22878
23068
  abs = resolve6(requested);
22879
- if (isInside(root, abs)) abs = join49(realRoot, relative2(root, abs));
23069
+ if (isInside(root, abs)) abs = join50(realRoot, relative2(root, abs));
22880
23070
  } else {
22881
23071
  abs = resolve6(realRoot, requested);
22882
23072
  }
22883
23073
  if (!isInside(realRoot, abs)) throw new PathRefusal(`${requested} is outside this periscope's worktree`);
22884
23074
  const { real, rest } = await realAncestor(abs);
22885
- const final = rest ? join49(real, rest) : real;
23075
+ const final = rest ? join50(real, rest) : real;
22886
23076
  if (!isInside(realRoot, final)) throw new PathRefusal(`${requested} is outside this periscope's worktree`);
22887
23077
  if (relative2(realRoot, final).split(sep).includes(".git")) throw new PathRefusal(".git is not reachable from a periscope");
22888
23078
  return final;
@@ -22950,7 +23140,7 @@ function createPeriscopeMcpServer(d, sc) {
22950
23140
  const entries = (await readdir(abs, { withFileTypes: true })).filter((e) => e.name !== ".git");
22951
23141
  const lines2 = await Promise.all(entries.map(async (e) => {
22952
23142
  if (e.isDirectory()) return `[DIR] ${e.name}`;
22953
- const size = (await lstat(join49(abs, e.name))).size;
23143
+ const size = (await lstat(join50(abs, e.name))).size;
22954
23144
  return `[FILE] ${e.name} (${size} bytes)`;
22955
23145
  }));
22956
23146
  return text(lines2.join("\n") || "(empty)");
@@ -22975,7 +23165,7 @@ function createPeriscopeMcpServer(d, sc) {
22975
23165
  if (Buffer.byteLength(content) > MAX_WRITE_BYTES) return text(`content exceeds ${MAX_WRITE_BYTES} bytes`, true);
22976
23166
  const abs = await inTree(path);
22977
23167
  if (abs === await realpath(root)) return text("path must name a file", true);
22978
- await mkdir(dirname28(abs), { recursive: true });
23168
+ await mkdir(dirname29(abs), { recursive: true });
22979
23169
  await inTree(path);
22980
23170
  await writeFile(abs, content);
22981
23171
  return text(`Wrote ${Buffer.byteLength(content)} bytes to ${await rel(abs)}`);
@@ -23015,8 +23205,8 @@ function createPeriscopeMcpServer(d, sc) {
23015
23205
  inputSchema: { path: z.string() },
23016
23206
  annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false }
23017
23207
  }, async ({ path }) => {
23018
- const parent = await inTree(dirname28(path) === "" ? "." : dirname28(path));
23019
- const abs = join49(parent, basename15(path));
23208
+ const parent = await inTree(dirname29(path) === "" ? "." : dirname29(path));
23209
+ const abs = join50(parent, basename15(path));
23020
23210
  if (basename15(path) === ".git" || abs === parent) return text("path must name a file", true);
23021
23211
  const st = await lstat(abs).catch(() => void 0);
23022
23212
  if (!st) return text(`${path} does not exist`, true);
@@ -23137,7 +23327,7 @@ function findPeriscope(sidecars, segment) {
23137
23327
  }
23138
23328
 
23139
23329
  // src/cli.ts
23140
- var CREW_HOME = isCompiledBinary(import.meta.url) ? dirname29(process.execPath) : resolve7(dirname29(fileURLToPath(import.meta.url)), "..");
23330
+ var CREW_HOME = isCompiledBinary(import.meta.url) ? dirname30(process.execPath) : resolve7(dirname30(fileURLToPath(import.meta.url)), "..");
23141
23331
  var RELEASE_LOCK_TTL_MS = 20 * 60 * 1e3;
23142
23332
  var CYCLE_SECONDS2 = 120;
23143
23333
  var STALE_CYCLES = 3;
@@ -23505,7 +23695,7 @@ if (command === "provision") {
23505
23695
  process.exit(outcome.code);
23506
23696
  }
23507
23697
  if (command === "pool-member") {
23508
- const pool = poolConfigFrom(argv, process.env, () => readFileSync41(0, "utf8"));
23698
+ const pool = poolConfigFrom(argv, process.env, () => readFileSync42(0, "utf8"));
23509
23699
  if (typeof pool === "string") {
23510
23700
  process.stderr.write(`crew pool-member: ${pool}
23511
23701
  `);
@@ -23733,7 +23923,7 @@ if (command === "passenger-sync-daemon") {
23733
23923
  } else {
23734
23924
  const toleratesNoRoutes = command === "credential" || command === "forge" || command === "repos" || command === "ship" || command === "disconnect" && flag("reset") || command === "deprovision" || command === "connect" && flag("sign-out");
23735
23925
  const configless = command === "connect" && flag("sign-out") || command === "disconnect" && flag("reset") || command === "deprovision";
23736
- if (configless && !existsSync46(findConfigFile(CREW_HOME))) {
23926
+ if (configless && !existsSync47(findConfigFile(CREW_HOME))) {
23737
23927
  cfg = loadConfig(CREW_HOME, firstRunConfigPath(), { text: "ship: {}\n", allowNoRoutes: true });
23738
23928
  } else {
23739
23929
  cfg = loadConfig(CREW_HOME, void 0, toleratesNoRoutes ? { allowNoRoutes: true } : {});
@@ -23748,7 +23938,7 @@ if (command === "passenger-sync-daemon") {
23748
23938
  throw e;
23749
23939
  }
23750
23940
  if (command === "credential") {
23751
- const r = runCredential(positional[1], readFileSync41(0, "utf8"), cfg.ship.forges, cfg.ship.stateDir);
23941
+ const r = runCredential(positional[1], readFileSync42(0, "utf8"), cfg.ship.forges, cfg.ship.stateDir);
23752
23942
  process.stdout.write(r.out);
23753
23943
  process.stderr.write(r.err);
23754
23944
  process.exit(r.code);
@@ -23760,9 +23950,9 @@ if (command === "passenger-sync-daemon") {
23760
23950
  forges: cfg.ship.forges,
23761
23951
  stateDir: cfg.ship.stateDir,
23762
23952
  configFile: cfg.configFile,
23763
- readFile: (p) => readFileSync41(p, "utf8"),
23764
- writeFile: (p, t) => writeFileSync34(p, t),
23765
- stdin: () => readFileSync41(0, "utf8"),
23953
+ readFile: (p) => readFileSync42(p, "utf8"),
23954
+ writeFile: (p, t) => writeFileSync35(p, t),
23955
+ stdin: () => readFileSync42(0, "utf8"),
23766
23956
  env: process.env
23767
23957
  }
23768
23958
  );
@@ -24055,8 +24245,8 @@ if (command === "passenger-sync-daemon") {
24055
24245
  }
24056
24246
  if (host === "linux" && hasSystemd) {
24057
24247
  const label = labelFor(CREW_HOME, "run");
24058
- const staleTimer = join50(homedir11(), ".config", "systemd", "user", `${label}.timer`);
24059
- if (existsSync46(staleTimer)) {
24248
+ const staleTimer = join51(homedir11(), ".config", "systemd", "user", `${label}.timer`);
24249
+ if (existsSync47(staleTimer)) {
24060
24250
  process.stdout.write(
24061
24251
  `removing stale run timer from before the persistent-service cutover: ${staleTimer}${dryRun ? " (dry run)" : ""}
24062
24252
  `
@@ -24083,7 +24273,7 @@ if (command === "passenger-sync-daemon") {
24083
24273
  const tracker = new Tracker(c, cfg.ship);
24084
24274
  problems.push(...validateContract(tracker.contract).map((p) => `contract: ${p}`));
24085
24275
  for (const r of await resolvedRepos(c)) {
24086
- if (!existsSync46(r.dir)) problems.push(`repo ${r.name}: ${r.dir} is missing on disk`);
24276
+ if (!existsSync47(r.dir)) problems.push(`repo ${r.name}: ${r.dir} is missing on disk`);
24087
24277
  if (!satisfies(host, r.config.platform)) problems.push(`repo ${r.name}: requires ${r.config.platform}, this host is ${host}`);
24088
24278
  readiness.push(...validateEffective(r.config).map((p) => `repo ${r.name}: ${p}`));
24089
24279
  }
@@ -24110,7 +24300,7 @@ if (command === "passenger-sync-daemon") {
24110
24300
  }
24111
24301
  async function doctorFix(o) {
24112
24302
  const routes = await Promise.all(routesInScope(cfg.routes, named).map((c) => gatherHealth({ route: c.route, enabled: c.enabled, hasRepos: reposOf(c).length > 0 }, () => routeProblems(c))));
24113
- const unitExists = (p) => existsSync46(p);
24303
+ const unitExists = (p) => existsSync47(p);
24114
24304
  const crontab = o.host === "linux" ? spawnSync10("crontab", ["-l"], { encoding: "utf8" }).stdout ?? "" : "";
24115
24305
  const schedulerAbsent = o.host !== "windows" ? !schedulerInstalled(planInstall(cfg.ship, CREW_HOME, o.host, detectSystemd(), "run", installContext()), unitExists, crontab) : true;
24116
24306
  const plan = planFix({ routes, schedulerAbsent, host: o.host });
@@ -24127,7 +24317,7 @@ if (command === "passenger-sync-daemon") {
24127
24317
  for (const a of plan.actions) {
24128
24318
  if (a.kind === "enable") {
24129
24319
  if (prompter && !await prompter.confirm(`Route ${a.route} passes every check \u2014 set enabled: true in ${cfg.configFile}?`, false)) continue;
24130
- writeFileSync34(cfg.configFile, planEnable(readFileSync41(cfg.configFile, "utf8"), a.route));
24320
+ writeFileSync35(cfg.configFile, planEnable(readFileSync42(cfg.configFile, "utf8"), a.route));
24131
24321
  enabledSound.add(a.route);
24132
24322
  changed2.push(`enabled route ${a.route} in ${cfg.configFile}`);
24133
24323
  } else {
@@ -25266,7 +25456,7 @@ ${cu.tail.trimEnd()}
25266
25456
  process.exit(1);
25267
25457
  }
25268
25458
  requireArmed("run the daemon loop");
25269
- const watchPaths = isCompiledBinary(import.meta.url) ? [process.execPath] : [join50(CREW_HOME, "src"), join50(CREW_HOME, "dist"), join50(CREW_HOME, "bin")];
25459
+ const watchPaths = isCompiledBinary(import.meta.url) ? [process.execPath] : [join51(CREW_HOME, "src"), join51(CREW_HOME, "dist"), join51(CREW_HOME, "bin")];
25270
25460
  const configPaths = daemonConfigPaths(cfg);
25271
25461
  watchPaths.push(...configPaths);
25272
25462
  noteDaemonStarted(cfg.ship.stateDir);
@@ -25571,10 +25761,10 @@ ${cu.tail.trimEnd()}
25571
25761
  `);
25572
25762
  if (!dryRun) {
25573
25763
  const resolvedPath = resolvedPathFor(cfg.ship.stateDir, target.route);
25574
- const raw = existsSync46(resolvedPath) ? JSON.parse(readFileSync41(resolvedPath, "utf8")) : {};
25764
+ const raw = existsSync47(resolvedPath) ? JSON.parse(readFileSync42(resolvedPath, "utf8")) : {};
25575
25765
  raw.agentSkills = result.agentSkills;
25576
- mkdirSync33(dirOf2(resolvedPath), { recursive: true });
25577
- writeFileSync34(resolvedPath, `${JSON.stringify(raw, null, 2)}
25766
+ mkdirSync34(dirOf2(resolvedPath), { recursive: true });
25767
+ writeFileSync35(resolvedPath, `${JSON.stringify(raw, null, 2)}
25578
25768
  `);
25579
25769
  }
25580
25770
  if (result.outcomes.some((o) => o.action === "diverged")) process.exitCode = 1;
@@ -25597,7 +25787,7 @@ ${cu.tail.trimEnd()}
25597
25787
  throw e;
25598
25788
  }
25599
25789
  const oldName = cfg.ship.name;
25600
- writeFileSync34(cfg.configFile, setShipNameInYaml(readFileSync41(cfg.configFile, "utf8"), newName));
25790
+ writeFileSync35(cfg.configFile, setShipNameInYaml(readFileSync42(cfg.configFile, "utf8"), newName));
25601
25791
  cfg.ship.name = newName;
25602
25792
  let renameMachineId;
25603
25793
  try {
@@ -25644,14 +25834,14 @@ ${cu.tail.trimEnd()}
25644
25834
  process.exit(2);
25645
25835
  };
25646
25836
  if (sub !== "add" && sub !== "list" && sub !== "clone" && sub !== "hooks" && sub !== "check") usage2();
25647
- const configText = readFileSync41(cfg.configFile, "utf8");
25837
+ const configText = readFileSync42(cfg.configFile, "utf8");
25648
25838
  if (sub === "check") {
25649
25839
  try {
25650
25840
  const routeArg = value("route") ?? positional[2];
25651
25841
  const found = cfg.routes.find((r) => r.route === routeArg);
25652
25842
  if (!found) throw new ReposError(`no route "${routeArg}" in the config (have: ${cfg.routes.map((r) => r.route).join(", ") || "none"})`);
25653
25843
  const named2 = value("route") ? void 0 : positional[3];
25654
- const dir = named2 ? repoDirOf(configText, dirname29(cfg.configFile), found.route, named2) : resolvePath(positional[value("route") ? 2 : 3] ?? ".");
25844
+ const dir = named2 ? repoDirOf(configText, dirname30(cfg.configFile), found.route, named2) : resolvePath(positional[value("route") ? 2 : 3] ?? ".");
25655
25845
  const target = reposOf(found).find((t) => resolvePath(t.dir) === dir || t.name === named2);
25656
25846
  const o = target ? found.repoOverrides[target.name] : void 0;
25657
25847
  runReposCheck(dir, {
@@ -25674,9 +25864,9 @@ ${cu.tail.trimEnd()}
25674
25864
  if (sub === "hooks") {
25675
25865
  try {
25676
25866
  const a = parseHooksArgs(positional.slice(2), routeNamesOf(configText));
25677
- const dir = repoDirOf(configText, dirname29(cfg.configFile), a.route, a.name);
25678
- if (!existsSync46(dir)) throw new ReposError(`${dir} does not exist on disk`);
25679
- const files = { exists: (r) => existsSync46(resolvePath(dir, r)), list: (r) => {
25867
+ const dir = repoDirOf(configText, dirname30(cfg.configFile), a.route, a.name);
25868
+ if (!existsSync47(dir)) throw new ReposError(`${dir} does not exist on disk`);
25869
+ const files = { exists: (r) => existsSync47(resolvePath(dir, r)), list: (r) => {
25680
25870
  try {
25681
25871
  return readdirSync20(resolvePath(dir, r));
25682
25872
  } catch {
@@ -25684,7 +25874,7 @@ ${cu.tail.trimEnd()}
25684
25874
  }
25685
25875
  }, read: (r) => {
25686
25876
  try {
25687
- return readFileSync41(resolvePath(dir, r), "utf8");
25877
+ return readFileSync42(resolvePath(dir, r), "utf8");
25688
25878
  } catch {
25689
25879
  return void 0;
25690
25880
  }
@@ -25726,19 +25916,19 @@ ${cu.tail.trimEnd()}
25726
25916
  let cleared;
25727
25917
  if (clear2) {
25728
25918
  const plan = clearRouteHooks(configText, a.route, a.name);
25729
- if (plan.removed.length > 0) writeFileSync34(cfg.configFile, plan.text);
25919
+ if (plan.removed.length > 0) writeFileSync35(cfg.configFile, plan.text);
25730
25920
  cleared = { file: cfg.configFile, removed: plan.removed };
25731
25921
  }
25732
25922
  if (write && suggestion.source === null && recipeIds.length === 0 && hookSpecs.length === 0) throw new ReposError(`nothing to write: ${suggestion.notes[0]}`);
25733
25923
  if (write === "route") {
25734
25924
  const plan = planRouteHooks(configText, a.route, a.name, picked.hooks, { replace: flag("replace") });
25735
- writeFileSync34(cfg.configFile, plan.text);
25925
+ writeFileSync35(cfg.configFile, plan.text);
25736
25926
  written = { target: "route", file: cfg.configFile, hooks: plan.written, kept: plan.kept, replaced: plan.replaced };
25737
25927
  } else if (write === "repo") {
25738
25928
  const have = existingRepoConfig(files);
25739
25929
  if (have) throw new ReposError(`${resolvePath(dir, have)} already exists; not overwriting it`);
25740
25930
  const file = resolvePath(dir, ".crew.yaml");
25741
- writeFileSync34(file, starterRepoConfig(picked.hooks, picked.release), { flag: "wx" });
25931
+ writeFileSync35(file, starterRepoConfig(picked.hooks, picked.release), { flag: "wx" });
25742
25932
  written = { target: "repo", file, hooks: Object.keys(picked.hooks), kept: [], replaced: [] };
25743
25933
  }
25744
25934
  if (flag("json")) {
@@ -25794,7 +25984,7 @@ ${cu.tail.trimEnd()}
25794
25984
  if (sub === "list" && !routeName) usage2();
25795
25985
  if (sub === "add") {
25796
25986
  try {
25797
- const a = parseAddArgs(positional.slice(2), routeNamesOf(configText), (p) => existsSync46(resolvePath(p.replace(/^~(?=\/|$)/, homedir11()))));
25987
+ const a = parseAddArgs(positional.slice(2), routeNamesOf(configText), (p) => existsSync47(resolvePath(p.replace(/^~(?=\/|$)/, homedir11()))));
25798
25988
  routeName = a.route;
25799
25989
  addPath = a.path;
25800
25990
  addName = a.name;
@@ -25824,7 +26014,7 @@ ${cu.tail.trimEnd()}
25824
26014
  const resolvedFile = resolvedPathFor(cfg.ship.stateDir, routeName);
25825
26015
  if (sub === "list" || sub === "add") {
25826
26016
  const liveRoute = cfg.routes.find((r) => r.route === routeName);
25827
- if (liveRoute?.resolved?.reposModelId && existsSync46(resolvedFile) && !dryRun) {
26017
+ if (liveRoute?.resolved?.reposModelId && existsSync47(resolvedFile) && !dryRun) {
25828
26018
  try {
25829
26019
  await hydrateApiKeys([liveRoute]);
25830
26020
  persistRepoRows(cfg.ship.stateDir, liveRoute.route, await new Tracker(liveRoute, cfg.ship).repoRowsForMap());
@@ -25833,16 +26023,16 @@ ${cu.tail.trimEnd()}
25833
26023
  }
25834
26024
  }
25835
26025
  let resolvedRemotes;
25836
- if (existsSync46(resolvedFile)) {
26026
+ if (existsSync47(resolvedFile)) {
25837
26027
  try {
25838
- resolvedRemotes = JSON.parse(readFileSync41(resolvedFile, "utf8"));
26028
+ resolvedRemotes = JSON.parse(readFileSync42(resolvedFile, "utf8"));
25839
26029
  } catch {
25840
26030
  }
25841
26031
  }
25842
26032
  const originOf = (dir) => gitOk(dir, ["remote", "get-url", "origin"]) ?? void 0;
25843
26033
  const text2 = configText;
25844
- const base = dirname29(cfg.configFile);
25845
- const isCheckout = (d) => existsSync46(`${d}/.git`);
26034
+ const base = dirname30(cfg.configFile);
26035
+ const isCheckout = (d) => existsSync47(`${d}/.git`);
25846
26036
  try {
25847
26037
  if (sub === "list") {
25848
26038
  if (flag("json")) {
@@ -25852,11 +26042,11 @@ ${cu.tail.trimEnd()}
25852
26042
  base,
25853
26043
  resolved: resolvedRemotes,
25854
26044
  originOf,
25855
- exists: (d) => existsSync46(d),
26045
+ exists: (d) => existsSync47(d),
25856
26046
  isCheckout,
25857
26047
  repoHasHooks: (d) => REPO_CONFIG_FILENAMES.some((f) => {
25858
26048
  try {
25859
- return Object.keys(parseRepoConfig(readFileSync41(resolvePath(d, f), "utf8"), f).hooks).length > 0;
26049
+ return Object.keys(parseRepoConfig(readFileSync42(resolvePath(d, f), "utf8"), f).hooks).length > 0;
25860
26050
  } catch {
25861
26051
  return false;
25862
26052
  }
@@ -25873,7 +26063,7 @@ ${cu.tail.trimEnd()}
25873
26063
  for (const r of repos) {
25874
26064
  const origin2 = originOf(r.dir);
25875
26065
  const row = matchRepoName(origin2, resolvedRemotes);
25876
- const note = !existsSync46(r.dir) ? "missing on disk" : row ? `Repos row: ${row}` : `no Repos row matches ${normalizeRemote(origin2) ?? "this checkout (no origin remote)"}`;
26066
+ const note = !existsSync47(r.dir) ? "missing on disk" : row ? `Repos row: ${row}` : `no Repos row matches ${normalizeRemote(origin2) ?? "this checkout (no origin remote)"}`;
25877
26067
  process.stdout.write(`${r.name} ${r.dir} ${note}
25878
26068
  `);
25879
26069
  }
@@ -25885,9 +26075,9 @@ ${cu.tail.trimEnd()}
25885
26075
  ` : `${human}
25886
26076
  `);
25887
26077
  const plan2 = planRepoClone({ text: text2, base, route: routeName, name: addName, resolved: resolvedRemotes, dir: value("dir"), isCheckout });
25888
- if (existsSync46(plan2.target) && (existsSync46(`${plan2.target}/.git`) || readdirSync20(plan2.target).length > 0)) {
26078
+ if (existsSync47(plan2.target) && (existsSync47(`${plan2.target}/.git`) || readdirSync20(plan2.target).length > 0)) {
25889
26079
  throw new ReposError(
25890
- existsSync46(`${plan2.target}/.git`) ? `${plan2.target} is already a checkout \u2014 attach it with \`crew repos add ${routeName} ${plan2.name} ${plan2.target}\`` : `${plan2.target} exists and is not empty \u2014 pass --dir to clone somewhere else`
26080
+ existsSync47(`${plan2.target}/.git`) ? `${plan2.target} is already a checkout \u2014 attach it with \`crew repos add ${routeName} ${plan2.name} ${plan2.target}\`` : `${plan2.target} exists and is not empty \u2014 pass --dir to clone somewhere else`
25891
26081
  );
25892
26082
  }
25893
26083
  if (dryRun) {
@@ -25905,14 +26095,14 @@ ${cu.tail.trimEnd()}
25905
26095
  throw new ReposError(`${e.message}${authHint}
25906
26096
  crew.yaml was not changed`);
25907
26097
  }
25908
- writeFileSync34(cfg.configFile, plan2.text);
26098
+ writeFileSync35(cfg.configFile, plan2.text);
25909
26099
  if (plan2.droppedDir) process.stderr.write(`crew repos: dropped dir: ${plan2.droppedDir} from route ${routeName} \u2014 it is not a checkout (the clone base); checkouts now live under repos:
25910
26100
  `);
25911
26101
  say("attached", { route: routeName, name: plan2.name, dir: plan2.target, mode: plan2.mode }, `cloned and attached ${plan2.target} to ${routeName} as ${plan2.mode === "dir" ? "dir" : `repos.${plan2.name}`} in ${cfg.configFile}`);
25912
26102
  break;
25913
26103
  }
25914
26104
  const target = resolvePath(addPath.replace(/^~(?=\/|$)/, homedir11()));
25915
- const top = existsSync46(target) ? gitOk(target, ["rev-parse", "--show-toplevel"]) : null;
26105
+ const top = existsSync47(target) ? gitOk(target, ["rev-parse", "--show-toplevel"]) : null;
25916
26106
  if (!top) throw new ReposError(`${target} is not a git checkout`);
25917
26107
  const origin = originOf(top);
25918
26108
  const plan = planRepoAdd({
@@ -25964,15 +26154,15 @@ ${cu.tail.trimEnd()}
25964
26154
  const created = await rowTracker.createRepoRow(rowPayload);
25965
26155
  process.stdout.write(`created Repos row ${String(rowPayload.name)} (${String(rowPayload.remote)}) ${created.id}
25966
26156
  `);
25967
- if (existsSync46(resolvedFile)) {
25968
- const raw = JSON.parse(readFileSync41(resolvedFile, "utf8"));
26157
+ if (existsSync47(resolvedFile)) {
26158
+ const raw = JSON.parse(readFileSync42(resolvedFile, "utf8"));
25969
26159
  raw.repoNames = { ...raw.repoNames, [created.id]: String(rowPayload.name) };
25970
26160
  raw.repoRemotes = { ...raw.repoRemotes, [created.id]: String(rowPayload.remote) };
25971
- writeFileSync34(resolvedFile, `${JSON.stringify(raw, null, 2)}
26161
+ writeFileSync35(resolvedFile, `${JSON.stringify(raw, null, 2)}
25972
26162
  `);
25973
26163
  }
25974
26164
  }
25975
- writeFileSync34(cfg.configFile, plan.text);
26165
+ writeFileSync35(cfg.configFile, plan.text);
25976
26166
  process.stdout.write(`added ${top} to ${routeName} as ${plan.mode === "dir" ? "dir" : `repos.${plan.name}`} in ${cfg.configFile}
25977
26167
  `);
25978
26168
  } catch (e) {
@@ -26341,7 +26531,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
26341
26531
  process.exit(2);
26342
26532
  }
26343
26533
  if (found.shipNameAdopted && !dryRun) {
26344
- writeFileSync34(cfg.configFile, setShipNameInYaml(readFileSync41(cfg.configFile, "utf8"), found.shipNameAdopted));
26534
+ writeFileSync35(cfg.configFile, setShipNameInYaml(readFileSync42(cfg.configFile, "utf8"), found.shipNameAdopted));
26345
26535
  cfg.ship.name = found.shipNameAdopted;
26346
26536
  }
26347
26537
  if (found.shipRow) {
@@ -26384,10 +26574,10 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
26384
26574
  }
26385
26575
  }
26386
26576
  let previous;
26387
- const hadPreviousFile = existsSync46(resolvedPath);
26577
+ const hadPreviousFile = existsSync47(resolvedPath);
26388
26578
  if (hadPreviousFile) {
26389
26579
  try {
26390
- previous = JSON.parse(readFileSync41(resolvedPath, "utf8"));
26580
+ previous = JSON.parse(readFileSync42(resolvedPath, "utf8"));
26391
26581
  } catch {
26392
26582
  }
26393
26583
  }
@@ -26517,10 +26707,10 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
26517
26707
  process.stderr.write(`(dry run) would write resolved ids to ${resolvedPath}
26518
26708
  `);
26519
26709
  } else {
26520
- mkdirSync33(dirname29(resolvedPath), { recursive: true });
26710
+ mkdirSync34(dirname30(resolvedPath), { recursive: true });
26521
26711
  if (hadPreviousFile) copyFileSync2(resolvedPath, `${resolvedPath}.bak`);
26522
26712
  const tmpPath = `${resolvedPath}.tmp${process.pid}`;
26523
- writeFileSync34(tmpPath, `${JSON.stringify(resolved, null, 2)}
26713
+ writeFileSync35(tmpPath, `${JSON.stringify(resolved, null, 2)}
26524
26714
  `);
26525
26715
  renameSync6(tmpPath, resolvedPath);
26526
26716
  process.stderr.write(`Resolved ids written to ${resolvedPath}
@@ -26566,8 +26756,8 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
26566
26756
  process.stderr.write(`(dry run) would write the minted API key to ${apiKeyFile}
26567
26757
  `);
26568
26758
  } else {
26569
- mkdirSync33(dirname29(apiKeyFile), { recursive: true });
26570
- writeFileSync34(apiKeyFile, `${apiKeyVar}=${apiKey}
26759
+ mkdirSync34(dirname30(apiKeyFile), { recursive: true });
26760
+ writeFileSync35(apiKeyFile, `${apiKeyVar}=${apiKey}
26571
26761
  `, { mode: 384 });
26572
26762
  process.stderr.write(`API key written to ${apiKeyFile}
26573
26763
  `);
@@ -27442,7 +27632,7 @@ Signed in as ${result.identity.email} \u2014 minted an API key in workspace "${r
27442
27632
  const shellR = hit && resolveShell(hit.repo.config.shell ?? cfg.ship.shell);
27443
27633
  const resumed = await runPeriscopeResume({
27444
27634
  find: async () => hit && { row: hit.row, tag: hit.tag },
27445
- worktreeExists: (p) => existsSync46(p),
27635
+ worktreeExists: (p) => existsSync47(p),
27446
27636
  prepareDropFile,
27447
27637
  caps: periscopeCaps(cfg.ship),
27448
27638
  runHook: async (name, cwd, env) => {
@@ -27537,10 +27727,10 @@ ${where.join("\n")}`);
27537
27727
  },
27538
27728
  prepare: async (path) => {
27539
27729
  for (const f of repoP.config.worktrees.copy) {
27540
- const src = join50(repoP.dir, f);
27541
- if (!existsSync46(src)) continue;
27542
- mkdirSync33(dirOf2(join50(path, f)), { recursive: true });
27543
- copyFileSync2(src, join50(path, f));
27730
+ const src = join51(repoP.dir, f);
27731
+ if (!existsSync47(src)) continue;
27732
+ mkdirSync34(dirOf2(join51(path, f)), { recursive: true });
27733
+ copyFileSync2(src, join51(path, f));
27544
27734
  }
27545
27735
  const setup = repoP.config.hooks.setup;
27546
27736
  return setup ? runScript(setup, { cwd: path, shell: shellP, onLine: (l) => {
@@ -27549,10 +27739,11 @@ ${where.join("\n")}`);
27549
27739
  },
27550
27740
  runHook: async (name, cwd, env) => {
27551
27741
  const script = repoP.config.hooks[name];
27552
- return script ? runScript(script, { cwd, env, shell: shellP, timeoutMs: name === "preview" ? 18e4 : void 0 }) : null;
27742
+ return script ? runScript(script, { cwd, env, shell: shellP, timeoutMs: name === "preview" ? 18e4 : name === "intel" ? 6e4 : void 0 }) : null;
27553
27743
  },
27554
27744
  createRow: (fields) => trackerP.createPeriscope(fields),
27555
27745
  prepareDropFile,
27746
+ registerCode: registerCodeServer,
27556
27747
  recordLocal: (sc) => {
27557
27748
  writePeriscopeSidecar(cfg.ship.stateDir, { ...sc, route: routeP.route });
27558
27749
  if (flag("serve-mcp")) mintPeriscopeSecret(cfg.ship.stateDir, sc.ticketRecordId);
@@ -27612,6 +27803,7 @@ ${where.join("\n")}`);
27612
27803
  },
27613
27804
  now: () => /* @__PURE__ */ new Date(),
27614
27805
  host: a.host ?? "localhost",
27806
+ intelStartupSeconds: cfg.ship.intelStartupSeconds,
27615
27807
  say
27616
27808
  };
27617
27809
  if (dryRun) {
@@ -27695,7 +27887,7 @@ ${where.join("\n")}`);
27695
27887
  }
27696
27888
  case "sync": {
27697
27889
  emit.enter("worktree");
27698
- let tracked = 0;
27890
+ let tracked2 = 0;
27699
27891
  let acted = 0;
27700
27892
  let baseChecked = 0;
27701
27893
  let baseActed = 0;
@@ -27733,7 +27925,7 @@ ${where.join("\n")}`);
27733
27925
  }
27734
27926
  if (!s2.upstream) continue;
27735
27927
  if (w.branch !== r.config.branch.base && s2.upstream === `${r.config.branch.remote}/${r.config.branch.base}`) continue;
27736
- tracked++;
27928
+ tracked2++;
27737
27929
  if (s2.canFastForward) {
27738
27930
  acted++;
27739
27931
  if (dryRun) emit.emit(`would fast-forward ${w.branch}: ${s2.detail}`);
@@ -27746,8 +27938,8 @@ ${where.join("\n")}`);
27746
27938
  }
27747
27939
  if (baseUnsafe > 0) process.exitCode = 1;
27748
27940
  if (baseChecked > 0 && baseActed === 0) emit.emit(`${baseChecked} base branch(es) checked, all level with the remote`);
27749
- if (tracked === 0) emit.emit("no worktree tracks a remote branch \u2014 nothing to sync");
27750
- else if (acted === 0) emit.emit(`${tracked} worktree(s) tracking a remote, all level with it`);
27941
+ if (tracked2 === 0) emit.emit("no worktree tracks a remote branch \u2014 nothing to sync");
27942
+ else if (acted === 0) emit.emit(`${tracked2} worktree(s) tracking a remote, all level with it`);
27751
27943
  break;
27752
27944
  }
27753
27945
  case "pause":
@@ -27836,7 +28028,7 @@ ${where.join("\n")}`);
27836
28028
  };
27837
28029
  const droppedRoutes = [];
27838
28030
  try {
27839
- const rawCfg = parseYaml2(readFileSync41(cfg.configFile, "utf8"));
28031
+ const rawCfg = parseYaml2(readFileSync42(cfg.configFile, "utf8"));
27840
28032
  for (const r of rawCfg?.routes ?? []) {
27841
28033
  if (typeof r?.route !== "string" || cfg.routes.some((x) => x.route === r.route)) continue;
27842
28034
  try {
@@ -27889,8 +28081,8 @@ ${where.join("\n")}`);
27889
28081
  process.stdout.write("crew reload: no daemon unit is running \u2014 nothing to reload (the next run reads crew.yaml fresh)\n");
27890
28082
  break;
27891
28083
  }
27892
- mkdirSync33(cfg.ship.stateDir, { recursive: true });
27893
- writeFileSync34(sentinel, `${(/* @__PURE__ */ new Date()).toISOString()}
28084
+ mkdirSync34(cfg.ship.stateDir, { recursive: true });
28085
+ writeFileSync35(sentinel, `${(/* @__PURE__ */ new Date()).toISOString()}
27894
28086
  `);
27895
28087
  process.stdout.write(
27896
28088
  "crew reload: requested \u2014 the daemon relaunches with the new config once its running agents end (it starts no new work meanwhile); if it is busy, `crew reload --now` forces the relaunch and interrupts them\n"
@@ -27955,7 +28147,7 @@ ${where.join("\n")}`);
27955
28147
  }
27956
28148
  case "log": {
27957
28149
  try {
27958
- const text2 = readFileSync41(cfg.ship.logFile, "utf8").split("\n");
28150
+ const text2 = readFileSync42(cfg.ship.logFile, "utf8").split("\n");
27959
28151
  process.stdout.write(`${text2.slice(-(Number(value("tail")) || 40)).join("\n")}
27960
28152
  `);
27961
28153
  } catch {
@@ -27978,8 +28170,8 @@ ${where.join("\n")}`);
27978
28170
  };
27979
28171
  if (!route2.resolved) fail(`route ${route2.route} is not connected \u2014 run \`crew connect\` first`);
27980
28172
  const tracker = new Tracker(route2, cfg.ship);
27981
- const configText = readFileSync41(cfg.configFile, "utf8");
27982
- const cfgBase = dirname29(cfg.configFile);
28173
+ const configText = readFileSync42(cfg.configFile, "utf8");
28174
+ const cfgBase = dirname30(cfg.configFile);
27983
28175
  const configured2 = configuredRepos(configText, route2.route, cfgBase);
27984
28176
  const dir = configured2.find((r) => r.name === SAMPLE_REPO)?.dir ?? sampleDir(configured2.map((r) => r.dir), route2.reposBasePath, route2.route.split("/")[0]);
27985
28177
  const resolvedFile = resolvedPathFor(cfg.ship.stateDir, route2.route);
@@ -28007,7 +28199,7 @@ ${where.join("\n")}`);
28007
28199
  }
28008
28200
  if (configured2.some((r) => r.dir === dir)) {
28009
28201
  try {
28010
- writeFileSync34(cfg.configFile, planRepoRemove(configText, cfgBase, route2.route, dir).text);
28202
+ writeFileSync35(cfg.configFile, planRepoRemove(configText, cfgBase, route2.route, dir).text);
28011
28203
  } catch (e) {
28012
28204
  if (e instanceof ReposError) fail(e.message);
28013
28205
  throw e;
@@ -28015,29 +28207,29 @@ ${where.join("\n")}`);
28015
28207
  }
28016
28208
  if (row) {
28017
28209
  await tracker.deleteRepoRow(row.id);
28018
- if (existsSync46(resolvedFile)) {
28019
- const raw = JSON.parse(readFileSync41(resolvedFile, "utf8"));
28210
+ if (existsSync47(resolvedFile)) {
28211
+ const raw = JSON.parse(readFileSync42(resolvedFile, "utf8"));
28020
28212
  if (raw.repoNames) delete raw.repoNames[row.id];
28021
28213
  if (raw.repoRemotes) delete raw.repoRemotes[row.id];
28022
- writeFileSync34(resolvedFile, `${JSON.stringify(raw, null, 2)}
28214
+ writeFileSync35(resolvedFile, `${JSON.stringify(raw, null, 2)}
28023
28215
  `);
28024
28216
  }
28025
28217
  }
28026
- if (existsSync46(join50(dir, ".git")) && basename16(dir) === SAMPLE_REPO) rmSync23(dir, { recursive: true, force: true });
28218
+ if (existsSync47(join51(dir, ".git")) && basename16(dir) === SAMPLE_REPO) rmSync23(dir, { recursive: true, force: true });
28027
28219
  say("removed", { dir, closed }, `removed the sample repo${closed.length ? `, closed ${closed.join(", ")}` : ""}`);
28028
28220
  break;
28029
28221
  }
28030
28222
  const projectId = route2.resolved.areaId ?? resolveRepoProject(await tracker.projectRows(), value("project"));
28031
- const fresh = !existsSync46(join50(dir, ".git"));
28032
- if (existsSync46(dir) && fresh && readdirSync20(dir).length > 0) fail(`${dir} exists and is not a git checkout \u2014 move it aside`);
28223
+ const fresh = !existsSync47(join51(dir, ".git"));
28224
+ if (existsSync47(dir) && fresh && readdirSync20(dir).length > 0) fail(`${dir} exists and is not a git checkout \u2014 move it aside`);
28033
28225
  if (dryRun) {
28034
28226
  say("dry-run", { dir, newCheckout: fresh, repoRow: row?.id ?? null }, `would ${fresh ? "create" : "reuse"} ${dir}${row ? "" : ", create the Repos row"}, and file one ${tracker.contract.statuses.approved} ticket`);
28035
28227
  break;
28036
28228
  }
28037
28229
  if (fresh) {
28038
- mkdirSync33(dir, { recursive: true });
28039
- writeFileSync34(join50(dir, "README.md"), SAMPLE_README);
28040
- writeFileSync34(join50(dir, ".crew.yaml"), SAMPLE_CREW_YAML);
28230
+ mkdirSync34(dir, { recursive: true });
28231
+ writeFileSync35(join51(dir, "README.md"), SAMPLE_README);
28232
+ writeFileSync35(join51(dir, ".crew.yaml"), SAMPLE_CREW_YAML);
28041
28233
  const g = (...a) => {
28042
28234
  const r = spawnSync10("git", a, { cwd: dir, encoding: "utf8" });
28043
28235
  if (r.status !== 0) fail(`git ${a[0]} failed in ${dir}: ${(r.stderr || r.stdout).trim()}`);
@@ -28055,17 +28247,17 @@ ${where.join("\n")}`);
28055
28247
  spec: { platform: "unix", releaseMode: "integrate", ciProvider: "none" }
28056
28248
  });
28057
28249
  repoId = (await tracker.createRepoRow(payload)).id;
28058
- if (existsSync46(resolvedFile)) {
28059
- const raw = JSON.parse(readFileSync41(resolvedFile, "utf8"));
28250
+ if (existsSync47(resolvedFile)) {
28251
+ const raw = JSON.parse(readFileSync42(resolvedFile, "utf8"));
28060
28252
  raw.repoNames = { ...raw.repoNames, [repoId]: SAMPLE_REPO };
28061
28253
  raw.repoRemotes = { ...raw.repoRemotes, [repoId]: SAMPLE_REMOTE };
28062
- writeFileSync34(resolvedFile, `${JSON.stringify(raw, null, 2)}
28254
+ writeFileSync35(resolvedFile, `${JSON.stringify(raw, null, 2)}
28063
28255
  `);
28064
28256
  }
28065
28257
  }
28066
28258
  if (!configured2.some((r) => r.dir === dir)) {
28067
28259
  try {
28068
- writeFileSync34(cfg.configFile, planRepoAdd({ text: configText, base: cfgBase, route: route2.route, path: dir, name: SAMPLE_REPO }).text);
28260
+ writeFileSync35(cfg.configFile, planRepoAdd({ text: configText, base: cfgBase, route: route2.route, path: dir, name: SAMPLE_REPO }).text);
28069
28261
  } catch (e) {
28070
28262
  if (e instanceof ReposError) fail(e.message);
28071
28263
  throw e;
@@ -28411,7 +28603,7 @@ watermark: ${state.watermark()}
28411
28603
  }
28412
28604
  for (const r of repos) {
28413
28605
  const remote = r.config.branch.remote;
28414
- if (existsSync46(r.dir)) {
28606
+ if (existsSync47(r.dir)) {
28415
28607
  pushAuth.push({
28416
28608
  route: c.route,
28417
28609
  repo: r.name,
@@ -28449,7 +28641,8 @@ watermark: ${state.watermark()}
28449
28641
  notes: validateEffective(r.config),
28450
28642
  base: doctorBaseReport(r, r.config.branch.base, baseHealth),
28451
28643
  hooks: r.config.hooks,
28452
- onPath: (cmd) => !!findOnPath(cmd, doctorSchedulerPath)
28644
+ onPath: (cmd) => !!findOnPath(cmd, doctorSchedulerPath),
28645
+ intelSyntax: r.config.hooks.intel ? checkHookSyntax(r.config.hooks.intel, r.config.shell) : void 0
28453
28646
  });
28454
28647
  problems.push(...f.problems);
28455
28648
  passed += f.passed;
@@ -28500,7 +28693,7 @@ routes: ${cfg.routes.map((c) => c.route).join(", ")}
28500
28693
  }
28501
28694
  try {
28502
28695
  const evFile = eventFileFor(cfg.ship.stateDir);
28503
- const evSize = existsSync46(evFile) ? statSync16(evFile).size : 0;
28696
+ const evSize = existsSync47(evFile) ? statSync16(evFile).size : 0;
28504
28697
  process.stdout.write(
28505
28698
  evSize > cfg.ship.eventsRotateBytes * 4 ? `events log: WARN ${evFile} is ${Math.round(evSize / 1048576)} MB (> 4x eventsRotateBytes); run \`crew reap\` to rotate it
28506
28699
  ` : "events log: ok\n"
@@ -28511,7 +28704,7 @@ routes: ${cfg.routes.map((c) => c.route).join(", ")}
28511
28704
  const unitPlan = planInstall(cfg.ship, CREW_HOME, host, detectSystemd(), "run", installContext());
28512
28705
  const abandons = unitAbandonsAgents(unitPlan, (p) => {
28513
28706
  try {
28514
- return readFileSync41(p, "utf8");
28707
+ return readFileSync42(p, "utf8");
28515
28708
  } catch {
28516
28709
  return null;
28517
28710
  }