sessionpipe 0.12.0 → 0.13.0

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/index.js CHANGED
@@ -1,4 +1,9 @@
1
- // sessionpipe 0.12.0 · Apache-2.0 · https://sessionpipe.org
1
+ // sessionpipe 0.13.0 · Apache-2.0 · https://sessionpipe.org
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: true });
6
+ };
2
7
 
3
8
  // src/http-sink.ts
4
9
  import { createHash, createHmac } from "node:crypto";
@@ -100,15 +105,15 @@ import {
100
105
  appendFileSync as appendFileSync3,
101
106
  existsSync as existsSync10,
102
107
  mkdirSync as mkdirSync8,
103
- readdirSync as readdirSync6,
104
- readFileSync as readFileSync10,
108
+ readdirSync as readdirSync7,
109
+ readFileSync as readFileSync11,
105
110
  renameSync as renameSync3,
106
- statSync as statSync6,
111
+ statSync as statSync7,
107
112
  unlinkSync as unlinkSync4,
108
113
  writeFileSync as writeFileSync8
109
114
  } from "node:fs";
110
- import os3 from "node:os";
111
- import path15 from "node:path";
115
+ import os4 from "node:os";
116
+ import path16 from "node:path";
112
117
 
113
118
  // ../core/src/paths.ts
114
119
  import os from "node:os";
@@ -288,7 +293,14 @@ ${m.text}`;
288
293
  continue;
289
294
  }
290
295
  if (cur) turns.push(cur);
291
- cur = { user: m.text, assistant: "", at: m.at, startLine: m.line, endLine: m.line };
296
+ cur = {
297
+ user: m.text,
298
+ assistant: "",
299
+ at: m.at,
300
+ startLine: m.line,
301
+ endLine: m.line,
302
+ ...m.injected ? { injected: true } : {}
303
+ };
292
304
  } else {
293
305
  if (!cur) cur = { user: "", assistant: "", at: m.at, startLine: m.line, endLine: m.line };
294
306
  cur.assistant += (cur.assistant ? "\n\n" : "") + m.text;
@@ -298,10 +310,17 @@ ${m.text}`;
298
310
  if (cur?.assistant) turns.push(cur);
299
311
  const line = cur && !cur.assistant ? cur.startLine : endLine;
300
312
  const out = {
301
- turns: turns.map((t) => ({ user: t.user, assistant: t.assistant, at: t.at, endLine: t.endLine })),
313
+ turns: turns.map((t) => ({
314
+ user: t.user,
315
+ assistant: t.assistant,
316
+ at: t.at,
317
+ endLine: t.endLine,
318
+ ...t.injected ? { injected: true } : {}
319
+ })),
302
320
  line
303
321
  };
304
- if (cur && !cur.assistant && cur.user) out.open = { user: cur.user, at: cur.at };
322
+ if (cur && !cur.assistant && cur.user)
323
+ out.open = { user: cur.user, at: cur.at, ...cur.injected ? { injected: true } : {} };
305
324
  return out;
306
325
  }
307
326
  var isInjected = (text) => /^<[a-z_-]+(?:\s[^>]*)?>/i.test(text) && /<\/[a-z_-]+>\s*$/i.test(text) || /^<!--\s/.test(text) || /^<command-/.test(text);
@@ -324,27 +343,51 @@ var textParts = (c, kinds) => {
324
343
  (b) => b && typeof b === "object" && kinds.includes(b.type ?? "") && typeof b.text === "string"
325
344
  ).map((b) => b.text).join("\n");
326
345
  };
346
+ var SPOKEN = /* @__PURE__ */ new Set(["human", "peer"]);
347
+ var PEER_INTRO = /sent a message[^\n]*:$/;
348
+ var PEER_OUTRO = "\n\nThis came from another ";
349
+ var ENVELOPE = /^<cross-session-message\b[^>]*>\n([\s\S]*)\n<\/cross-session-message>$/;
350
+ function peerAsk(origin, text) {
351
+ const body = origin?.body;
352
+ let t = typeof body === "string" && body.trim() ? body : text;
353
+ if (t !== body) {
354
+ const nl = t.indexOf("\n");
355
+ if (nl > 0 && PEER_INTRO.test(t.slice(0, nl))) t = t.slice(nl + 1);
356
+ const outro = t.indexOf(PEER_OUTRO);
357
+ if (outro > 0) t = t.slice(0, outro);
358
+ }
359
+ return (ENVELOPE.exec(t.trim())?.[1] ?? t).trim();
360
+ }
327
361
  var queuedPrompt = (a) => {
328
362
  if (!a || typeof a !== "object") return "";
329
363
  const q = a;
330
364
  if (q.type !== "queued_command" || (q.commandMode ?? "prompt") !== "prompt") return "";
331
- if (q.origin?.kind && q.origin.kind !== "human") return "";
332
- return textParts(q.prompt, ["text"]).trim();
365
+ const kind = q.origin?.kind ?? "human";
366
+ if (!SPOKEN.has(kind)) return "";
367
+ const text = textParts(q.prompt, ["text"]).trim();
368
+ return kind === "peer" ? peerAsk(q.origin, text) : text;
333
369
  };
370
+ var channelText = (text) => /^<channel\b[^>]*>([\s\S]*)<\/channel>$/.exec(text)?.[1]?.trim() ?? "";
334
371
  function readClaude(lines, from) {
335
372
  const msgs = [];
336
373
  for (let i = from; i < lines.length; i++) {
337
374
  const j = lines[i] ? parse(lines[i]) : null;
338
375
  if (!j || j.isSidechain) continue;
339
376
  const origin = j.origin;
340
- if (j.type === "user" && (j.isMeta || j.isCompactSummary || j.repeatsCompactSummary || origin?.kind && origin.kind !== "human"))
341
- continue;
377
+ const channel = j.type === "user" && origin?.kind === "channel";
378
+ const peer = origin?.kind === "peer";
379
+ if (j.type === "user" && (j.isCompactSummary || j.repeatsCompactSummary)) continue;
380
+ if (j.type === "user" && !channel && !peer && (j.isMeta || origin?.kind && origin.kind !== "human")) continue;
342
381
  const at = Date.parse(String(j.timestamp ?? "")) || Date.now();
343
382
  const c = j.message?.content;
344
- if (j.type === "user") {
345
- const text = textParts(c, ["text"]).trim();
383
+ if (channel) {
384
+ const text = channelText(textParts(c, ["text"]).trim());
385
+ if (text) msgs.push({ role: "user", text, at, line: i, injected: true });
386
+ } else if (j.type === "user") {
387
+ const raw = textParts(c, ["text"]).trim();
388
+ const text = peer ? peerAsk(origin, raw) : raw;
346
389
  if (!text || isInjected(text)) continue;
347
- msgs.push({ role: "user", text, at, line: i });
390
+ msgs.push({ role: "user", text, at, line: i, ...peer ? { injected: true } : {} });
348
391
  } else if (j.type === "assistant" && Array.isArray(c)) {
349
392
  const text = textParts(c, ["text"]).trim();
350
393
  if (text) msgs.push({ role: "assistant", text, at, line: i });
@@ -1258,8 +1301,44 @@ async function claudeAiTitle(bridge, token) {
1258
1301
  }
1259
1302
 
1260
1303
  // ../core/src/adapters/headless.ts
1304
+ import { spawn } from "node:child_process";
1261
1305
  import { accessSync, constants, readFileSync as readFileSync3, statSync as statSync3 } from "node:fs";
1262
1306
  import path5 from "node:path";
1307
+
1308
+ // ../core/src/launched-by.ts
1309
+ var LAUNCHED_BY_ENV = "SESSIONPIPE_LAUNCHED_BY";
1310
+ var DELEGATED_BY_ENV = "SESSIONPIPE_ASKED_BY";
1311
+ var ASK_CHAIN_ENV = "SESSIONPIPE_ASK_CHAIN";
1312
+ var LINEAGE_ENV = [LAUNCHED_BY_ENV, DELEGATED_BY_ENV, ASK_CHAIN_ENV];
1313
+ var SESSION_REF = /^[a-z][a-z0-9-]{0,39}:[A-Za-z0-9._:-]{1,128}$/;
1314
+ function withoutLineage(env) {
1315
+ const e = { ...env };
1316
+ for (const k of LINEAGE_ENV) delete e[k];
1317
+ return e;
1318
+ }
1319
+ function refIn(env, name) {
1320
+ const v = env[name]?.trim();
1321
+ return v && SESSION_REF.test(v) ? v : void 0;
1322
+ }
1323
+ function launchedBy(env) {
1324
+ return refIn(env, LAUNCHED_BY_ENV);
1325
+ }
1326
+ function delegatedBy(env) {
1327
+ return refIn(env, DELEGATED_BY_ENV);
1328
+ }
1329
+ function readHook(adapter, input) {
1330
+ const r = adapter.fromHook(input);
1331
+ if (r && !r.session.parent_id) {
1332
+ const self = `${adapter.name}:${r.session.id}`;
1333
+ const launcher = launchedBy(input.env);
1334
+ if (launcher && launcher !== self) r.session.launched_by = launcher;
1335
+ const asker = delegatedBy(input.env);
1336
+ if (asker && asker !== self) r.session.delegated_by = asker;
1337
+ }
1338
+ return r;
1339
+ }
1340
+
1341
+ // ../core/src/adapters/headless.ts
1263
1342
  var JOB_TIMEOUT_MS = 30 * 6e4;
1264
1343
  var OUT_CAP = 1024 * 1024;
1265
1344
  function isExe(p) {
@@ -1301,10 +1380,116 @@ function spawnable(bin, args) {
1301
1380
  const target = shimTarget(bin);
1302
1381
  return target ? { file: process.execPath, args: [target, ...args] } : null;
1303
1382
  }
1383
+ var shimNote = (bin) => `${path5.basename(bin)} is a launcher script that names no program to run; point the harness's override (SESSIONPIPE_CLAUDE, SESSIONPIPE_CODEX, \u2026) at the program itself`;
1304
1384
  function probe(bin, args) {
1305
1385
  const s = spawnable(bin, args);
1306
1386
  return s ? { ...s, shell: false } : { file: [`"${bin}"`, ...args].join(" "), args: [], shell: true };
1307
1387
  }
1388
+ function runHeadless(bin, args, o) {
1389
+ return new Promise((resolve) => {
1390
+ let out = [];
1391
+ let outLen = 0;
1392
+ let tooBig = false;
1393
+ let errTail = "";
1394
+ let timedOut = false;
1395
+ let settled = false;
1396
+ let child;
1397
+ const c = spawnable(bin, args);
1398
+ if (!c) {
1399
+ resolve({ error: shimNote(bin) });
1400
+ return;
1401
+ }
1402
+ try {
1403
+ child = spawn(c.file, c.args, {
1404
+ cwd: o.cwd,
1405
+ env: o.env,
1406
+ stdio: ["ignore", "pipe", "pipe"],
1407
+ detached: process.platform !== "win32",
1408
+ windowsHide: true
1409
+ });
1410
+ } catch (e) {
1411
+ resolve({ error: e.message });
1412
+ return;
1413
+ }
1414
+ const kill = (sig) => {
1415
+ try {
1416
+ if (process.platform !== "win32" && child.pid) process.kill(-child.pid, sig);
1417
+ else child.kill(sig);
1418
+ } catch {
1419
+ try {
1420
+ child.kill(sig);
1421
+ } catch {
1422
+ }
1423
+ }
1424
+ };
1425
+ const keep = (line) => {
1426
+ if (!o.keep?.(line)) return;
1427
+ out = [Buffer.from(line)];
1428
+ outLen = line.length;
1429
+ };
1430
+ let partial = "";
1431
+ child.stdout?.on("data", (b) => {
1432
+ if (o.onLine) {
1433
+ const chunk = partial + b.toString("utf8");
1434
+ const lines = chunk.split("\n");
1435
+ partial = lines.pop();
1436
+ for (const line of lines) {
1437
+ if (!line.trim()) continue;
1438
+ try {
1439
+ o.onLine(line);
1440
+ } catch {
1441
+ }
1442
+ keep(line);
1443
+ }
1444
+ if (partial.length > OUT_CAP) partial = "";
1445
+ return;
1446
+ }
1447
+ if (tooBig) return;
1448
+ if (outLen + b.length > OUT_CAP) {
1449
+ tooBig = true;
1450
+ out = [];
1451
+ return;
1452
+ }
1453
+ out.push(b);
1454
+ outLen += b.length;
1455
+ });
1456
+ child.stderr?.on("data", (b) => {
1457
+ errTail = (errTail + b.toString("utf8")).slice(-4e3);
1458
+ });
1459
+ const timer = setTimeout(() => {
1460
+ timedOut = true;
1461
+ kill("SIGTERM");
1462
+ setTimeout(() => kill("SIGKILL"), 1e4).unref();
1463
+ }, o.timeoutMs ?? JOB_TIMEOUT_MS);
1464
+ const result = (code, signal) => ({
1465
+ code,
1466
+ signal,
1467
+ stdout: tooBig ? null : Buffer.concat(out).toString("utf8"),
1468
+ tooBig,
1469
+ stderr: errTail,
1470
+ timedOut
1471
+ });
1472
+ const finish = (r) => {
1473
+ if (settled) return;
1474
+ settled = true;
1475
+ clearTimeout(timer);
1476
+ resolve(r);
1477
+ };
1478
+ child.on("error", (e) => finish({ error: e.message }));
1479
+ child.on("exit", (code, signal) => setTimeout(() => finish(result(code, signal)), 2e3).unref());
1480
+ child.on("close", (code, signal) => {
1481
+ if (o.onLine && partial.trim()) {
1482
+ try {
1483
+ o.onLine(partial);
1484
+ } catch {
1485
+ }
1486
+ keep(partial);
1487
+ partial = "";
1488
+ }
1489
+ finish(result(code, signal));
1490
+ });
1491
+ });
1492
+ }
1308
1493
 
1309
1494
  // ../core/src/adapters/antigravity.ts
1310
1495
  import {
@@ -1594,6 +1779,50 @@ function antigravityFacts(file, opts) {
1594
1779
  return out;
1595
1780
  }
1596
1781
 
1782
+ // ../core/src/adapters/claude-code-control.ts
1783
+ var claude_code_control_exports = {};
1784
+ __export(claude_code_control_exports, {
1785
+ CLAUDE_MODES: () => CLAUDE_MODES,
1786
+ JOB_TIMEOUT_MS: () => JOB_TIMEOUT_MS,
1787
+ MODE_RANK: () => MODE_RANK,
1788
+ NO_HOME_SETTINGS: () => NO_HOME_SETTINGS,
1789
+ ceilingLevel: () => ceilingLevel,
1790
+ claudeArgs: () => claudeArgs,
1791
+ claudeEnv: () => claudeEnv,
1792
+ claudeLogin: () => claudeLogin2,
1793
+ cmpVersion: () => cmpVersion,
1794
+ defaultLevel: () => defaultLevel,
1795
+ detectCaps: () => detectCaps,
1796
+ findClaude: () => findClaude,
1797
+ findTranscript: () => findTranscript,
1798
+ findTranscripts: () => findTranscripts,
1799
+ homeSettings: () => homeSettings,
1800
+ hookMode: () => hookMode,
1801
+ isUuid: () => isUuid,
1802
+ liveProcess: () => liveProcess,
1803
+ liveRecord: () => liveRecord,
1804
+ liveRecords: () => liveRecords,
1805
+ loginCommand: () => loginCommand,
1806
+ loginHint: () => loginHint,
1807
+ modeFlags: () => modeFlags,
1808
+ modeRank: () => modeRank,
1809
+ offeredLevels: () => offeredLevels,
1810
+ outputArgs: () => outputArgs,
1811
+ parseAuthStatus: () => parseAuthStatus,
1812
+ parseCaps: () => parseCaps,
1813
+ parseResult: () => parseResult,
1814
+ peerClass: () => peerClass,
1815
+ recentlyWritten: () => recentlyWritten,
1816
+ relaunchMode: () => relaunchMode,
1817
+ resolveHome: () => resolveHome,
1818
+ runClaude: () => runClaude,
1819
+ sessionFolder: () => sessionFolder
1820
+ });
1821
+ import { execFile, execFileSync as execFileSync3 } from "node:child_process";
1822
+ import { closeSync as closeSync2, openSync as openSync2, readdirSync as readdirSync4, readFileSync as readFileSync5, readSync as readSync2, statSync as statSync5 } from "node:fs";
1823
+ import os2 from "node:os";
1824
+ import path7 from "node:path";
1825
+
1597
1826
  // ../core/src/control/verify.ts
1598
1827
  var GRANT_MAX_MS = 24 * 36e5;
1599
1828
  var SKEW_MS = 5 * 6e4;
@@ -1604,10 +1833,10 @@ var MODEL_RE = /^[A-Za-z0-9][A-Za-z0-9._:/@[\]-]*$/;
1604
1833
  var START_PERMISSIONS = ["read", "safe", "edits", "auto"];
1605
1834
  var levelRank = (l) => START_PERMISSIONS.indexOf(l);
1606
1835
  var FIELDS = {
1607
- prompt: ["text", "files"],
1836
+ prompt: ["text", "files", "reply_to"],
1608
1837
  "permission.answer": ["for", "decision"],
1609
1838
  cancel: [],
1610
- start: ["text", "cwd", "files", "permission", "model"],
1839
+ start: ["text", "cwd", "files", "permission", "model", "reply_to"],
1611
1840
  "key.add": ["key", "name"],
1612
1841
  pool: ["pool_action", "pool_account", "pool_order", "pool_code"]
1613
1842
  };
@@ -1615,9 +1844,454 @@ var POOL_FIELDS = FIELDS.pool;
1615
1844
  var enc = new TextEncoder();
1616
1845
  var dec = new TextDecoder();
1617
1846
 
1847
+ // ../core/src/adapters/claude-code-control.ts
1848
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1849
+ var LIVE_WRITE_MS = 9e4;
1850
+ var cmpVersion = (a, b) => {
1851
+ const pa = a.split(".").map(Number);
1852
+ const pb = b.split(".").map(Number);
1853
+ for (let i = 0; i < Math.max(pa.length, pb.length); i++)
1854
+ if ((pa[i] ?? 0) !== (pb[i] ?? 0)) return (pa[i] ?? 0) - (pb[i] ?? 0);
1855
+ return 0;
1856
+ };
1857
+ function findClaude(env = process.env, home = os2.homedir()) {
1858
+ if (env.SESSIONPIPE_CLAUDE && isExe(env.SESSIONPIPE_CLAUDE)) return env.SESSIONPIPE_CLAUDE;
1859
+ const names = process.platform === "win32" ? ["claude.exe", "claude.cmd"] : ["claude"];
1860
+ for (const d of String(env.PATH || "").split(path7.delimiter)) {
1861
+ if (!d || !path7.isAbsolute(d)) continue;
1862
+ for (const n of names) if (isExe(path7.join(d, n))) return path7.join(d, n);
1863
+ }
1864
+ for (const p of [
1865
+ path7.join(home, ".claude", "local", "claude"),
1866
+ path7.join(home, ".local", "bin", "claude"),
1867
+ "/opt/homebrew/bin/claude",
1868
+ "/usr/local/bin/claude"
1869
+ ])
1870
+ if (isExe(p)) return p;
1871
+ const app = path7.join(home, "Library", "Application Support", "Claude", "claude-code");
1872
+ let versions = [];
1873
+ try {
1874
+ versions = readdirSync4(app).filter((n) => /^\d+(\.\d+)*$/.test(n)).sort(cmpVersion).reverse();
1875
+ } catch {
1876
+ }
1877
+ for (const v of versions) {
1878
+ const p = path7.join(app, v, "claude.app", "Contents", "MacOS", "claude");
1879
+ if (isExe(p)) return p;
1880
+ }
1881
+ return null;
1882
+ }
1883
+ function optionBlock(help, flag) {
1884
+ const lines = help.split("\n");
1885
+ const re = new RegExp(`^\\s{0,4}(?:-\\w, )?${flag.replace(/-/g, "\\-")}(?![\\w-])`);
1886
+ const start = lines.findIndex((l) => re.test(l));
1887
+ if (start < 0) return null;
1888
+ const out = [lines[start]];
1889
+ for (let i = start + 1; i < lines.length && lines[i]?.trim() && !/^\s{0,4}-/.test(lines[i]); i++)
1890
+ out.push(lines[i]);
1891
+ return out.join(" ");
1892
+ }
1893
+ function parseCaps(help) {
1894
+ const pm = optionBlock(help, "--permission-mode");
1895
+ const pp = optionBlock(help, "--permission-prompts");
1896
+ return {
1897
+ hasMode: !!pm,
1898
+ modes: pm ? [...pm.matchAll(/"([A-Za-z]+)"/g)].map((m) => m[1]) : [],
1899
+ promptsNone: !!pp && /"none"/.test(pp),
1900
+ fork: !!optionBlock(help, "--fork-session"),
1901
+ stream: !!optionBlock(help, "--include-partial-messages")
1902
+ };
1903
+ }
1904
+ var LEVEL_MODE = {
1905
+ read: "plan",
1906
+ edits: "acceptEdits",
1907
+ auto: "auto"
1908
+ };
1909
+ function modeFlags(level, caps) {
1910
+ if (level === "inherit") return { args: [] };
1911
+ if (caps.unread)
1912
+ return { error: `this machine couldn't read its Claude Code's options (${caps.unread}); try again in a minute` };
1913
+ if (level === "auto" && !caps.modes.includes("auto"))
1914
+ return { error: "this machine is in auto mode, but its Claude Code has no auto permission mode" };
1915
+ if (level !== "safe") {
1916
+ const m = LEVEL_MODE[level];
1917
+ if (!caps.modes.includes(m)) return { error: `this machine's Claude Code has no ${m} permission mode` };
1918
+ return { args: ["--permission-mode", m] };
1919
+ }
1920
+ if (caps.modes.includes("dontAsk")) return { args: ["--permission-mode", "dontAsk"] };
1921
+ const args = [];
1922
+ if (caps.hasMode)
1923
+ args.push(
1924
+ "--permission-mode",
1925
+ caps.modes.includes("manual") && !caps.modes.includes("default") ? "manual" : "default"
1926
+ );
1927
+ if (caps.promptsNone) args.push("--permission-prompts", "none");
1928
+ return { args };
1929
+ }
1930
+ var ceilingLevel = (mode) => mode === "inherit" ? "safe" : mode;
1931
+ function offeredLevels(mode, caps) {
1932
+ if (caps.unread) return [];
1933
+ return START_PERMISSIONS.filter(
1934
+ (l) => levelRank(l) <= levelRank(ceilingLevel(mode)) && (l === "safe" || caps.modes.includes(LEVEL_MODE[l]))
1935
+ );
1936
+ }
1937
+ var defaultLevel = (mode) => mode;
1938
+ function outputArgs(caps) {
1939
+ return caps.stream ? ["--output-format", "stream-json", "--verbose", "--include-partial-messages"] : ["--output-format", "json"];
1940
+ }
1941
+ function claudeArgs(o) {
1942
+ const mf = modeFlags(o.level, o.caps);
1943
+ if ("error" in mf) return mf;
1944
+ const where = o.resume ? ["--resume", o.resume, ...o.fork ? ["--fork-session"] : []] : ["--session-id", o.session];
1945
+ return {
1946
+ args: [
1947
+ "-p",
1948
+ ...outputArgs(o.caps),
1949
+ ...mf.args,
1950
+ ...o.model ? ["--model", o.model] : [],
1951
+ ...o.allowedTools?.length ? [`--allowedTools=${o.allowedTools.join(",")}`] : [],
1952
+ ...where,
1953
+ o.prompt.startsWith("-") ? ` ${o.prompt}` : o.prompt
1954
+ ]
1955
+ };
1956
+ }
1957
+ function claudeEnv(configDir, env = process.env) {
1958
+ const e = withoutLineage(env);
1959
+ for (const k of [
1960
+ "CLAUDECODE",
1961
+ "CLAUDE_CODE_SESSION_ID",
1962
+ "CLAUDE_CODE_HOST_SESSION_ID",
1963
+ "CLAUDE_CODE_ENTRYPOINT",
1964
+ "CLAUDE_CODE_SESSION_ATTENDED",
1965
+ "CLAUDE_CODE_SSE_PORT"
1966
+ ])
1967
+ delete e[k];
1968
+ e.SESSIONPIPE_CONTROL_JOB = "1";
1969
+ if (configDir !== void 0) {
1970
+ if (path7.resolve(configDir) === path7.resolve(os2.homedir(), ".claude")) delete e.CLAUDE_CONFIG_DIR;
1971
+ else e.CLAUDE_CONFIG_DIR = configDir;
1972
+ }
1973
+ return e;
1974
+ }
1975
+ function parseAuthStatus(stdout) {
1976
+ const text = String(stdout || "").trim();
1977
+ const start = text.indexOf("{");
1978
+ if (start < 0) return { loggedIn: null };
1979
+ try {
1980
+ const j = JSON.parse(text.slice(start));
1981
+ if (typeof j.loggedIn !== "boolean") return { loggedIn: null };
1982
+ return {
1983
+ loggedIn: j.loggedIn,
1984
+ ...typeof j.authMethod === "string" ? { method: j.authMethod } : {},
1985
+ ...typeof j.subscriptionType === "string" ? { subscription: j.subscriptionType } : {}
1986
+ };
1987
+ } catch {
1988
+ return { loggedIn: null };
1989
+ }
1990
+ }
1991
+ function claudeLogin2(bin, configDir, env = process.env) {
1992
+ const c = probe(bin, ["auth", "status", "--json"]);
1993
+ return new Promise((resolve) => {
1994
+ execFile(
1995
+ c.file,
1996
+ c.args,
1997
+ { encoding: "utf8", timeout: 2e4, env: claudeEnv(configDir, env), maxBuffer: 256 * 1024, shell: c.shell },
1998
+ // `auth status` may exit non-zero when signed out; its JSON still says so.
1999
+ (_err, stdout) => resolve(parseAuthStatus(stdout))
2000
+ );
2001
+ });
2002
+ }
2003
+ function loginCommand(configDir) {
2004
+ const home = os2.homedir();
2005
+ const isDefault = !configDir || path7.resolve(configDir) === path7.resolve(home, ".claude");
2006
+ return isDefault ? "`claude auth login`" : `\`CLAUDE_CONFIG_DIR=${configDir.replace(home, "~")} claude auth login\``;
2007
+ }
2008
+ function loginHint(configDir, platform = process.platform) {
2009
+ const shown = configDir ? configDir.replace(os2.homedir(), "~") : "~/.claude";
2010
+ const login = loginCommand(configDir);
2011
+ if (platform === "darwin")
2012
+ return `Claude Code (${shown}) isn't signed in as this machine's background service sees it. On a Mac its login lives in the login keychain, which a background service can read only while someone is logged in at the screen: log in at the Mac, or run ${login} there.`;
2013
+ return `Claude Code (${shown}) isn't signed in on this machine: run ${login} there.`;
2014
+ }
2015
+ function detectCaps(bin, timeoutMs = 3e4) {
2016
+ const c = probe(bin, ["--help"]);
2017
+ try {
2018
+ return parseCaps(
2019
+ execFileSync3(c.file, c.args, {
2020
+ encoding: "utf8",
2021
+ timeout: timeoutMs,
2022
+ env: claudeEnv(),
2023
+ stdio: ["ignore", "pipe", "pipe"],
2024
+ maxBuffer: 4 * 1024 * 1024,
2025
+ shell: c.shell
2026
+ })
2027
+ );
2028
+ } catch (e) {
2029
+ const err = e;
2030
+ const caps = parseCaps(String(err?.stdout || ""));
2031
+ if (caps.hasMode) return caps;
2032
+ const why = err?.code === "ETIMEDOUT" ? `timed out after ${timeoutMs / 1e3} s` : "failed";
2033
+ return { ...caps, unread: `\`${path7.basename(bin)} --help\` ${why}` };
2034
+ }
2035
+ }
2036
+ function transcriptIn(session, dir) {
2037
+ let projects = [];
2038
+ try {
2039
+ projects = readdirSync4(path7.join(dir, "projects"), { withFileTypes: true });
2040
+ } catch {
2041
+ return null;
2042
+ }
2043
+ for (const p of projects) {
2044
+ if (!p.isDirectory()) continue;
2045
+ const file = path7.join(dir, "projects", p.name, `${session}.jsonl`);
2046
+ try {
2047
+ if (statSync5(file).isFile()) return { file, configDir: dir, project: p.name };
2048
+ } catch {
2049
+ }
2050
+ }
2051
+ return null;
2052
+ }
2053
+ function findTranscript(session, dirs) {
2054
+ if (!UUID_RE.test(session)) return null;
2055
+ for (const dir of dirs) {
2056
+ const t = transcriptIn(session, dir);
2057
+ if (t) return t;
2058
+ }
2059
+ return null;
2060
+ }
2061
+ function findTranscripts(session, dirs) {
2062
+ if (!UUID_RE.test(session)) return [];
2063
+ const out = [];
2064
+ for (const dir of dirs) {
2065
+ const t = transcriptIn(session, dir);
2066
+ if (t) out.push(t);
2067
+ }
2068
+ return out;
2069
+ }
2070
+ var homeName = (t) => path7.basename(t.configDir);
2071
+ function resolveHome(session, dirs) {
2072
+ const all = findTranscripts(session, dirs);
2073
+ if (!all.length) return null;
2074
+ if (all.length === 1) return { transcript: all[0] };
2075
+ const live = all.filter((t) => liveRecords(session, t.configDir).length > 0);
2076
+ if (live.length === 1) return { transcript: live[0] };
2077
+ return {
2078
+ ambiguous: [...new Set(all.map(homeName))].sort(),
2079
+ live: [...new Set(live.map(homeName))].sort()
2080
+ };
2081
+ }
2082
+ var projectName = (cwd) => cwd.replace(/[^a-zA-Z0-9]/g, "-");
2083
+ function sessionFolder(t, cap2 = 8 * 1024 * 1024) {
2084
+ let first = null;
2085
+ let count = 0;
2086
+ let fd;
2087
+ const look = (line) => {
2088
+ if (line.indexOf('"cwd"') < 0) return null;
2089
+ let j;
2090
+ try {
2091
+ j = JSON.parse(line.toString("utf8"));
2092
+ } catch {
2093
+ return null;
2094
+ }
2095
+ if (!j || typeof j.cwd !== "string" || !path7.isAbsolute(j.cwd)) return null;
2096
+ if (projectName(j.cwd) === t.project) return j.cwd;
2097
+ first ??= j.cwd;
2098
+ count++;
2099
+ return null;
2100
+ };
2101
+ try {
2102
+ fd = openSync2(t.file, "r");
2103
+ const buf = Buffer.alloc(256 * 1024);
2104
+ let pos = 0;
2105
+ let rest = Buffer.alloc(0);
2106
+ let skipping = false;
2107
+ while (pos < cap2 && count < 50) {
2108
+ const n = readSync2(fd, buf, 0, buf.length, pos);
2109
+ if (!n) {
2110
+ if (!skipping && rest.length) {
2111
+ const hit = look(rest);
2112
+ if (hit) return hit;
2113
+ }
2114
+ break;
2115
+ }
2116
+ pos += n;
2117
+ let chunk = rest.length ? Buffer.concat([rest, buf.subarray(0, n)]) : buf.subarray(0, n);
2118
+ let nl = chunk.indexOf(10);
2119
+ while (nl >= 0) {
2120
+ const line = chunk.subarray(0, nl);
2121
+ chunk = chunk.subarray(nl + 1);
2122
+ if (skipping) skipping = false;
2123
+ else {
2124
+ const hit = look(line);
2125
+ if (hit) return hit;
2126
+ }
2127
+ nl = chunk.indexOf(10);
2128
+ }
2129
+ if (chunk.length > 2 * 1024 * 1024) {
2130
+ skipping = true;
2131
+ rest = Buffer.alloc(0);
2132
+ } else rest = skipping ? Buffer.alloc(0) : Buffer.from(chunk);
2133
+ }
2134
+ } catch {
2135
+ } finally {
2136
+ if (fd !== void 0)
2137
+ try {
2138
+ closeSync2(fd);
2139
+ } catch {
2140
+ }
2141
+ }
2142
+ return first;
2143
+ }
2144
+ function pidAlive(pid) {
2145
+ if (!Number.isSafeInteger(pid) || pid <= 1) return false;
2146
+ try {
2147
+ process.kill(pid, 0);
2148
+ return true;
2149
+ } catch (e) {
2150
+ return e.code === "EPERM";
2151
+ }
2152
+ }
2153
+ var registryRow = (file, configDir, j) => {
2154
+ const pid = Number(j.pid ?? path7.basename(file).slice(0, -5));
2155
+ const str = (v) => typeof v === "string" && v ? v : null;
2156
+ let keyFile = null;
2157
+ try {
2158
+ const want = new RegExp(`^${pid}\\.[0-9a-f]{64}\\.key$`);
2159
+ const hit = readdirSync4(path7.dirname(file)).find((n) => want.test(n));
2160
+ if (hit) keyFile = path7.join(path7.dirname(file), hit);
2161
+ } catch {
2162
+ }
2163
+ return {
2164
+ configDir,
2165
+ file,
2166
+ pid,
2167
+ socket: str(j.messagingSocketPath),
2168
+ peerProtocol: typeof j.peerProtocol === "number" ? j.peerProtocol : null,
2169
+ procStart: str(j.procStart),
2170
+ status: str(j.status),
2171
+ kind: str(j.kind),
2172
+ entrypoint: str(j.entrypoint),
2173
+ keyFile
2174
+ };
2175
+ };
2176
+ function liveRecords(session, dirs) {
2177
+ const out = [];
2178
+ for (const dir of typeof dirs === "string" ? [dirs] : dirs) {
2179
+ let names = [];
2180
+ try {
2181
+ names = readdirSync4(path7.join(dir, "sessions")).filter((n) => /^\d+\.json$/.test(n));
2182
+ } catch {
2183
+ continue;
2184
+ }
2185
+ for (const n of names) {
2186
+ const file = path7.join(dir, "sessions", n);
2187
+ let j;
2188
+ try {
2189
+ j = JSON.parse(readFileSync5(file, "utf8"));
2190
+ } catch {
2191
+ continue;
2192
+ }
2193
+ if (String(j.sessionId) !== session) continue;
2194
+ const row = registryRow(file, dir, j);
2195
+ if (pidAlive(row.pid)) out.push(row);
2196
+ }
2197
+ }
2198
+ return out;
2199
+ }
2200
+ function liveRecord(session, dirs) {
2201
+ const all = liveRecords(session, dirs);
2202
+ return all.length === 1 ? all[0] : null;
2203
+ }
2204
+ function liveProcess(session, configDir) {
2205
+ return liveRecords(session, configDir).length > 0;
2206
+ }
2207
+ var MODE_RANK = {
2208
+ plan: 0,
2209
+ default: 1,
2210
+ manual: 1,
2211
+ dontAsk: 1,
2212
+ acceptEdits: 2,
2213
+ auto: 3,
2214
+ bypassPermissions: 4
2215
+ };
2216
+ var CLAUDE_MODES = Object.keys(MODE_RANK);
2217
+ var modeRank = (m) => m && m in MODE_RANK ? MODE_RANK[m] : -1;
2218
+ function hookMode(payload) {
2219
+ if (!payload || typeof payload !== "object") return null;
2220
+ const p = payload;
2221
+ const v = typeof p.permission_mode === "string" ? p.permission_mode : p.permissionMode;
2222
+ return typeof v === "string" && CLAUDE_MODES.includes(v) ? v : null;
2223
+ }
2224
+ function peerClass(mode) {
2225
+ if (mode === "bypassPermissions") return "bypass";
2226
+ if (mode === "default" || mode === "manual" || mode === "dontAsk" || mode === "acceptEdits") return "prompting";
2227
+ return null;
2228
+ }
2229
+ var NO_HOME_SETTINGS = { defaultMode: null, disableAutoMode: false, disableBypass: false };
2230
+ function homeSettings(configDir, home = os2.homedir()) {
2231
+ const file = path7.join(configDir ?? path7.join(home, ".claude"), "settings.json");
2232
+ let j;
2233
+ try {
2234
+ j = JSON.parse(readFileSync5(file, "utf8"));
2235
+ } catch {
2236
+ return { ...NO_HOME_SETTINGS };
2237
+ }
2238
+ if (!j || typeof j !== "object" || Array.isArray(j)) return { ...NO_HOME_SETTINGS };
2239
+ const p = j.permissions && typeof j.permissions === "object" ? j.permissions : {};
2240
+ const off = (k) => j[k] === "disable" || p[k] === "disable";
2241
+ return {
2242
+ defaultMode: typeof p.defaultMode === "string" && CLAUDE_MODES.includes(p.defaultMode) ? p.defaultMode : null,
2243
+ disableAutoMode: off("disableAutoMode"),
2244
+ disableBypass: off("disableBypassPermissionsMode")
2245
+ };
2246
+ }
2247
+ function relaunchMode(recorded, home) {
2248
+ if (recorded === "plan") return recorded;
2249
+ if ((recorded === "dontAsk" || recorded === "acceptEdits") && modeRank(home.defaultMode) >= modeRank(recorded))
2250
+ return recorded;
2251
+ return null;
2252
+ }
2253
+ function recentlyWritten(file, ourLastEnd, now = Date.now()) {
2254
+ let m;
2255
+ try {
2256
+ m = statSync5(file).mtimeMs;
2257
+ } catch {
2258
+ return false;
2259
+ }
2260
+ if (now - m > LIVE_WRITE_MS) return false;
2261
+ return !(ourLastEnd && m <= ourLastEnd + 2e3);
2262
+ }
2263
+ function runClaude(bin, args, o) {
2264
+ return runHeadless(bin, args, { ...o, keep: o.keep ?? ((line) => line.includes('"type":"result"')) });
2265
+ }
2266
+ function parseResult(stdout) {
2267
+ const s = String(stdout || "").trim();
2268
+ if (!s) return null;
2269
+ const pick = (j) => {
2270
+ if (Array.isArray(j)) {
2271
+ for (let i = j.length - 1; i >= 0; i--) if (j[i]?.type === "result") return j[i];
2272
+ return null;
2273
+ }
2274
+ return j && typeof j === "object" ? j : null;
2275
+ };
2276
+ try {
2277
+ return pick(JSON.parse(s));
2278
+ } catch {
2279
+ }
2280
+ const lines = s.split("\n");
2281
+ for (let i = lines.length - 1; i >= 0; i--) {
2282
+ try {
2283
+ const j = pick(JSON.parse(lines[i]));
2284
+ if (j && (j.type === "result" || "result" in j)) return j;
2285
+ } catch {
2286
+ }
2287
+ }
2288
+ return null;
2289
+ }
2290
+ var isUuid = (s) => typeof s === "string" && UUID_RE.test(s);
2291
+
1618
2292
  // ../core/src/adapters/codex.ts
1619
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "node:fs";
1620
- import path7 from "node:path";
2293
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
2294
+ import path8 from "node:path";
1621
2295
 
1622
2296
  // ../core/src/adapters/codex-config.ts
1623
2297
  var NOTIFY_LINE = /^[ \t]*notify[ \t]*=[ \t]*(\[.*\])[ \t]*(?:#.*)?(?=\r?$)/m;
@@ -1763,24 +2437,24 @@ var CODEX_EVENTS = [
1763
2437
  ];
1764
2438
  var OPTS2 = { matcherFor: (e) => /Tool|Permission/.test(e) ? "" : void 0, timeout: 5 };
1765
2439
  var eventsFor2 = (lean) => lean ? CODEX_EVENTS.filter((e) => e !== "PreToolUse") : [...CODEX_EVENTS];
1766
- var codexHome = (env) => env.CODEX_HOME || path7.join(homeDir(), ".codex");
1767
- var hooksFile2 = (env) => path7.join(codexHome(env), "hooks.json");
1768
- var configFile2 = (env) => path7.join(codexHome(env), "config.toml");
1769
- var sessionsDir = (env) => path7.join(codexHome(env), "sessions");
2440
+ var codexHome = (env) => env.CODEX_HOME || path8.join(homeDir(), ".codex");
2441
+ var hooksFile2 = (env) => path8.join(codexHome(env), "hooks.json");
2442
+ var configFile2 = (env) => path8.join(codexHome(env), "config.toml");
2443
+ var sessionsDir = (env) => path8.join(codexHome(env), "sessions");
1770
2444
  var validTool3 = (n) => typeof n === "string" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);
1771
2445
  var endReason2 = (r) => r === "clear" || r === "logout" || r === "exit" ? r : "other";
1772
2446
  function installNotify(cmd, env) {
1773
2447
  const file = configFile2(env);
1774
2448
  let text = "";
1775
2449
  try {
1776
- text = readFileSync5(file, "utf8");
2450
+ text = readFileSync6(file, "utf8");
1777
2451
  } catch {
1778
2452
  }
1779
2453
  const argv = cmd([NAME3, "notify"]).argv;
1780
2454
  const line = `notify = ${JSON.stringify(argv)}`;
1781
2455
  const n = readNotify(text);
1782
2456
  const write = (next) => {
1783
- mkdirSync3(path7.dirname(file), { recursive: true });
2457
+ mkdirSync3(path8.dirname(file), { recursive: true });
1784
2458
  writeFileSync4(file, next);
1785
2459
  };
1786
2460
  if (n && !n.other) {
@@ -1819,7 +2493,7 @@ function uninstallNotify(env) {
1819
2493
  const file = configFile2(env);
1820
2494
  let text;
1821
2495
  try {
1822
- text = readFileSync5(file, "utf8");
2496
+ text = readFileSync6(file, "utf8");
1823
2497
  } catch {
1824
2498
  return { file, changed: false };
1825
2499
  }
@@ -1842,12 +2516,12 @@ function findRollout(threadId, env = process.env) {
1842
2516
  const walk = (dir, depth) => {
1843
2517
  let names = [];
1844
2518
  try {
1845
- names = readdirSync4(dir);
2519
+ names = readdirSync5(dir);
1846
2520
  } catch {
1847
2521
  return;
1848
2522
  }
1849
2523
  for (const n of names.sort().reverse()) {
1850
- const p = path7.join(dir, n);
2524
+ const p = path8.join(dir, n);
1851
2525
  if (n.endsWith(`-${threadId}.jsonl`)) {
1852
2526
  best = p;
1853
2527
  return;
@@ -1891,7 +2565,7 @@ var codex = {
1891
2565
  ];
1892
2566
  let text = "";
1893
2567
  try {
1894
- text = readFileSync5(configFile2(env), "utf8");
2568
+ text = readFileSync6(configFile2(env), "utf8");
1895
2569
  } catch {
1896
2570
  }
1897
2571
  const n = readNotify(text);
@@ -2018,7 +2692,7 @@ var codex = {
2018
2692
  readTranscript(file, fromLine) {
2019
2693
  let text = "";
2020
2694
  try {
2021
- text = readFileSync5(file, "utf8");
2695
+ text = readFileSync6(file, "utf8");
2022
2696
  } catch {
2023
2697
  return { turns: [], line: fromLine };
2024
2698
  }
@@ -2032,7 +2706,7 @@ var codex = {
2032
2706
  backfill(sinceMs, env = process.env) {
2033
2707
  const rows2 = [];
2034
2708
  for (const f of recentFiles(sessionsDir(env), 3, sinceMs, (n) => /^rollout-.*\.jsonl$/.test(n))) {
2035
- const m = /([0-9a-f]{8}-[0-9a-f-]{27,})\.jsonl$/i.exec(path7.basename(f));
2709
+ const m = /([0-9a-f]{8}-[0-9a-f-]{27,})\.jsonl$/i.exec(path8.basename(f));
2036
2710
  if (!m?.[1]) continue;
2037
2711
  if (codexSubagent(rolloutMeta(f))) continue;
2038
2712
  const facts = codexFacts(f);
@@ -2119,10 +2793,10 @@ function codexFacts(file) {
2119
2793
  // ../core/src/adapters/devin.ts
2120
2794
  import { createHash as createHash3 } from "node:crypto";
2121
2795
  import { existsSync as existsSync6, readlinkSync } from "node:fs";
2122
- import path8 from "node:path";
2796
+ import path9 from "node:path";
2123
2797
 
2124
2798
  // ../core/src/readers/sqlite.ts
2125
- import { execFileSync as execFileSync3 } from "node:child_process";
2799
+ import { execFileSync as execFileSync4 } from "node:child_process";
2126
2800
  import { existsSync as existsSync5 } from "node:fs";
2127
2801
  import { createRequire } from "node:module";
2128
2802
  function quiet(fn) {
@@ -2202,7 +2876,7 @@ db.close();
2202
2876
  process.stdout.write(JSON.stringify(out));`;
2203
2877
  function viaChild(file, sql, params, o) {
2204
2878
  try {
2205
- const out = execFileSync3(
2879
+ const out = execFileSync4(
2206
2880
  process.execPath,
2207
2881
  ["--experimental-sqlite", "--no-warnings", "-e", CHILD, file, sql, JSON.stringify(params), String(o.timeoutMs)],
2208
2882
  {
@@ -2246,7 +2920,7 @@ function viaCli(file, sql, params, o) {
2246
2920
  const text = inlineParams(sql, params);
2247
2921
  if (!text) return null;
2248
2922
  try {
2249
- const out = execFileSync3("sqlite3", ["-readonly", "-json", file, text], {
2923
+ const out = execFileSync4("sqlite3", ["-readonly", "-json", file, text], {
2250
2924
  encoding: "utf8",
2251
2925
  timeout: o.timeoutMs + 3e3,
2252
2926
  stdio: ["ignore", "pipe", "ignore"],
@@ -2303,11 +2977,11 @@ function foreignEvent(file) {
2303
2977
  return Object.keys(hooks).find((k) => !ok.includes(k));
2304
2978
  }
2305
2979
  var homeOf = (env) => env.HOME || homeDir();
2306
- var appData = (env) => env.APPDATA || path8.join(homeOf(env), "AppData", "Roaming");
2307
- var devinConfigDir = (env = process.env) => process.platform === "win32" ? path8.join(appData(env), "devin") : path8.join(env.XDG_CONFIG_HOME || path8.join(homeOf(env), ".config"), "devin");
2308
- var configFile3 = (env) => path8.join(devinConfigDir(env), "config.json");
2309
- var devinDataDir = (env = process.env) => process.platform === "win32" ? path8.join(appData(env), "devin", "cli") : path8.join(env.XDG_DATA_HOME || path8.join(homeOf(env), ".local", "share"), "devin", "cli");
2310
- var sessionsDb = (env) => path8.join(devinDataDir(env), "sessions.db");
2980
+ var appData = (env) => env.APPDATA || path9.join(homeOf(env), "AppData", "Roaming");
2981
+ var devinConfigDir = (env = process.env) => process.platform === "win32" ? path9.join(appData(env), "devin") : path9.join(env.XDG_CONFIG_HOME || path9.join(homeOf(env), ".config"), "devin");
2982
+ var configFile3 = (env) => path9.join(devinConfigDir(env), "config.json");
2983
+ var devinDataDir = (env = process.env) => process.platform === "win32" ? path9.join(appData(env), "devin", "cli") : path9.join(env.XDG_DATA_HOME || path9.join(homeOf(env), ".local", "share"), "devin", "cli");
2984
+ var sessionsDb = (env) => path9.join(devinDataDir(env), "sessions.db");
2311
2985
  var SESSION_ID = /^[A-Za-z0-9._:-]{1,128}$/;
2312
2986
  var validTool4 = (n) => typeof n === "string" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);
2313
2987
  var endReason3 = (r) => r === "clear" || r === "logout" || r === "exit" ? r : "other";
@@ -2479,7 +3153,7 @@ var BACKFILL_SQL = `SELECT s.id, ${SESSION_FIELDS} FROM sessions s
2479
3153
  function sessionFacts(row) {
2480
3154
  const out = {};
2481
3155
  if (typeof row.model === "string" && row.model) out.model = row.model;
2482
- if (typeof row.working_directory === "string" && path8.isAbsolute(row.working_directory))
3156
+ if (typeof row.working_directory === "string" && path9.isAbsolute(row.working_directory))
2483
3157
  out.cwd = row.working_directory;
2484
3158
  const started = Number(row.created_at);
2485
3159
  const last = Number(row.last_activity_at);
@@ -2524,8 +3198,8 @@ function readDevinChain(db, session, fromLine) {
2524
3198
  }
2525
3199
  function devinVersion(env = process.env) {
2526
3200
  try {
2527
- const target = readlinkSync(path8.join(devinDataDir(env), "_versions", "current"));
2528
- const name = path8.basename(target);
3201
+ const target = readlinkSync(path9.join(devinDataDir(env), "_versions", "current"));
3202
+ const name = path9.basename(target);
2529
3203
  return /^[0-9][0-9A-Za-z.+-]{0,63}$/.test(name) ? name : void 0;
2530
3204
  } catch {
2531
3205
  return void 0;
@@ -2538,9 +3212,9 @@ function devinAccount(env = process.env) {
2538
3212
  }
2539
3213
 
2540
3214
  // ../core/src/adapters/gemini-cli.ts
2541
- import { execFileSync as execFileSync4 } from "node:child_process";
2542
- import { existsSync as existsSync7, readFileSync as readFileSync6 } from "node:fs";
2543
- import path9 from "node:path";
3215
+ import { execFileSync as execFileSync5 } from "node:child_process";
3216
+ import { existsSync as existsSync7, readFileSync as readFileSync7 } from "node:fs";
3217
+ import path10 from "node:path";
2544
3218
  var NAME5 = "gemini-cli";
2545
3219
  var GEMINI_EVENTS = [
2546
3220
  "SessionStart",
@@ -2553,16 +3227,16 @@ var GEMINI_EVENTS = [
2553
3227
  "SessionEnd"
2554
3228
  ];
2555
3229
  var OPTS4 = { matcherFor: (e) => /Tool/.test(e) ? ".*" : void 0, timeout: 5e3 };
2556
- var geminiDir = (env) => env.GEMINI_CLI_HOME || path9.join(homeDir(), ".gemini");
2557
- var settings = (env) => path9.join(geminiDir(env), "settings.json");
3230
+ var geminiDir = (env) => env.GEMINI_CLI_HOME || path10.join(homeDir(), ".gemini");
3231
+ var settings = (env) => path10.join(geminiDir(env), "settings.json");
2558
3232
  var validTool5 = (n) => typeof n === "string" && /^[A-Za-z0-9_.:-]{1,120}$/.test(n);
2559
3233
  var eventsFor4 = (lean) => lean ? GEMINI_EVENTS.filter((e) => e !== "BeforeTool") : [...GEMINI_EVENTS];
2560
3234
  function geminiVersion(platform = process.platform, env = process.env) {
2561
3235
  const win = platform === "win32";
2562
- const bin = win ? findBinary({ names: ["gemini.exe", "gemini.cmd"], dirs: [path9.dirname(process.execPath)], env }) : "gemini";
3236
+ const bin = win ? findBinary({ names: ["gemini.exe", "gemini.cmd"], dirs: [path10.dirname(process.execPath)], env }) : "gemini";
2563
3237
  if (!bin) throw new Error("no gemini on PATH");
2564
3238
  const c = probe(bin, ["--version"]);
2565
- return execFileSync4(c.file, c.args, {
3239
+ return execFileSync5(c.file, c.args, {
2566
3240
  encoding: "utf8",
2567
3241
  timeout: 4e3,
2568
3242
  stdio: ["ignore", "pipe", "ignore"],
@@ -2595,7 +3269,7 @@ var geminiCli = {
2595
3269
  name: NAME5,
2596
3270
  events: GEMINI_EVENTS,
2597
3271
  // ~/.gemini also belongs to Antigravity; Gemini CLI is here when its settings or its chat logs exist.
2598
- detect: (env = process.env) => existsSync7(settings(env)) || existsSync7(path9.join(geminiDir(env), "tmp")),
3272
+ detect: (env = process.env) => existsSync7(settings(env)) || existsSync7(path10.join(geminiDir(env), "tmp")),
2599
3273
  configFiles: (env = process.env) => [settings(env)],
2600
3274
  install: (cmd, env = process.env, opts = {}) => {
2601
3275
  const r = installClaudeShaped(settings(env), NAME5, eventsFor4(opts.lean), cmd, OPTS4);
@@ -2693,7 +3367,7 @@ var geminiCli = {
2693
3367
  readTranscript(file, fromLine) {
2694
3368
  let text = "";
2695
3369
  try {
2696
- text = readFileSync6(file, "utf8");
3370
+ text = readFileSync7(file, "utf8");
2697
3371
  } catch {
2698
3372
  return { turns: [], line: fromLine };
2699
3373
  }
@@ -2733,12 +3407,12 @@ var ADAPTERS = [claudeCode, codex, geminiCli, antigravity, devin];
2733
3407
  var adapterByName = (name) => ADAPTERS.find((a) => a.name === name);
2734
3408
 
2735
3409
  // ../core/src/config.ts
2736
- import { chmodSync, existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "node:fs";
2737
- import path10 from "node:path";
3410
+ import { chmodSync, existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
3411
+ import path11 from "node:path";
2738
3412
  var DEFAULT_CONFIG = { sinks: [], harnesses: {}, update_check: true, keep_days: 30 };
2739
3413
  function readConfig(file = configFile()) {
2740
3414
  try {
2741
- const j = JSON.parse(readFileSync7(file, "utf8"));
3415
+ const j = JSON.parse(readFileSync8(file, "utf8"));
2742
3416
  return {
2743
3417
  ...DEFAULT_CONFIG,
2744
3418
  ...j,
@@ -2750,7 +3424,7 @@ function readConfig(file = configFile()) {
2750
3424
  }
2751
3425
  }
2752
3426
  function writeConfig(c, file = configFile()) {
2753
- mkdirSync4(path10.dirname(file), { recursive: true, mode: 448 });
3427
+ mkdirSync4(path11.dirname(file), { recursive: true, mode: 448 });
2754
3428
  writeFileSync5(file, `${JSON.stringify(c, null, 2)}
2755
3429
  `, { mode: 384 });
2756
3430
  if (process.platform !== "win32" && existsSync8(file)) {
@@ -2814,38 +3488,22 @@ function makeEvent(a, ctx) {
2814
3488
  };
2815
3489
  }
2816
3490
 
2817
- // ../core/src/launched-by.ts
2818
- var LAUNCHED_BY_ENV = "SESSIONPIPE_LAUNCHED_BY";
2819
- var LAUNCHED_BY = /^[a-z][a-z0-9-]{0,39}:[A-Za-z0-9._:-]{1,128}$/;
2820
- function launchedBy(env) {
2821
- const v = env[LAUNCHED_BY_ENV]?.trim();
2822
- return v && LAUNCHED_BY.test(v) ? v : void 0;
2823
- }
2824
- function readHook(adapter, input) {
2825
- const r = adapter.fromHook(input);
2826
- if (r && !r.session.parent_id) {
2827
- const launcher = launchedBy(input.env);
2828
- if (launcher && launcher !== `${adapter.name}:${r.session.id}`) r.session.launched_by = launcher;
2829
- }
2830
- return r;
2831
- }
2832
-
2833
3491
  // ../core/src/outbox.ts
2834
3492
  import {
2835
3493
  appendFileSync,
2836
- closeSync as closeSync2,
3494
+ closeSync as closeSync3,
2837
3495
  existsSync as existsSync9,
2838
3496
  mkdirSync as mkdirSync5,
2839
- openSync as openSync2,
2840
- readdirSync as readdirSync5,
2841
- readFileSync as readFileSync8,
2842
- readSync as readSync2,
3497
+ openSync as openSync3,
3498
+ readdirSync as readdirSync6,
3499
+ readFileSync as readFileSync9,
3500
+ readSync as readSync3,
2843
3501
  renameSync,
2844
- statSync as statSync5,
3502
+ statSync as statSync6,
2845
3503
  unlinkSync as unlinkSync3,
2846
3504
  writeFileSync as writeFileSync6
2847
3505
  } from "node:fs";
2848
- import path11 from "node:path";
3506
+ import path12 from "node:path";
2849
3507
  var READ_CHUNK = 1024 * 1024;
2850
3508
  var READ_MAX = 8 * 1024 * 1024;
2851
3509
  var Outbox = class {
@@ -2854,13 +3512,13 @@ var Outbox = class {
2854
3512
  }
2855
3513
  root;
2856
3514
  dir(harness) {
2857
- return path11.join(this.root, "outbox", safeId(harness));
3515
+ return path12.join(this.root, "outbox", safeId(harness));
2858
3516
  }
2859
3517
  file(ref) {
2860
- return path11.join(this.dir(ref.harness), `${safeId(ref.session)}.jsonl`);
3518
+ return path12.join(this.dir(ref.harness), `${safeId(ref.session)}.jsonl`);
2861
3519
  }
2862
3520
  seqFile(ref) {
2863
- return path11.join(this.dir(ref.harness), `${safeId(ref.session)}.seq`);
3521
+ return path12.join(this.dir(ref.harness), `${safeId(ref.session)}.seq`);
2864
3522
  }
2865
3523
  /** The next seq for a session, persisted (survives a hibernating machine and a
2866
3524
  * restart; an in-memory counter would restart at 0 and collide). */
@@ -2868,19 +3526,19 @@ var Outbox = class {
2868
3526
  const f = this.seqFile(ref);
2869
3527
  let n = -1;
2870
3528
  try {
2871
- const t = readFileSync8(f, "utf8").trim();
3529
+ const t = readFileSync9(f, "utf8").trim();
2872
3530
  if (/^\d+$/.test(t)) n = Number(t);
2873
3531
  } catch {
2874
3532
  }
2875
3533
  if (n < 0) n = this.lastSeqInFile(ref) + 1;
2876
- mkdirSync5(path11.dirname(f), { recursive: true, mode: 448 });
3534
+ mkdirSync5(path12.dirname(f), { recursive: true, mode: 448 });
2877
3535
  writeFileSync6(f, String(n + 1), { mode: 384 });
2878
3536
  return n;
2879
3537
  }
2880
3538
  lastSeqInFile(ref) {
2881
3539
  const f = this.file(ref);
2882
3540
  if (!existsSync9(f)) return -1;
2883
- const lines = readFileSync8(f, "utf8").trim().split("\n");
3541
+ const lines = readFileSync9(f, "utf8").trim().split("\n");
2884
3542
  for (let i = lines.length - 1; i >= 0; i--) {
2885
3543
  try {
2886
3544
  const j = JSON.parse(lines[i]);
@@ -2899,19 +3557,19 @@ var Outbox = class {
2899
3557
  /** Every session file, newest first. */
2900
3558
  sessions() {
2901
3559
  const out = [];
2902
- const base = path11.join(this.root, "outbox");
3560
+ const base = path12.join(this.root, "outbox");
2903
3561
  if (!existsSync9(base)) return [];
2904
- for (const h of readdirSync5(base)) {
2905
- const d = path11.join(base, h);
3562
+ for (const h of readdirSync6(base)) {
3563
+ const d = path12.join(base, h);
2906
3564
  let names = [];
2907
3565
  try {
2908
- names = readdirSync5(d).filter((n) => n.endsWith(".jsonl"));
3566
+ names = readdirSync6(d).filter((n) => n.endsWith(".jsonl"));
2909
3567
  } catch {
2910
3568
  continue;
2911
3569
  }
2912
3570
  for (const n of names) {
2913
3571
  try {
2914
- out.push({ ref: { harness: h, session: n.slice(0, -6) }, mtime: statSync5(path11.join(d, n)).mtimeMs });
3572
+ out.push({ ref: { harness: h, session: n.slice(0, -6) }, mtime: statSync6(path12.join(d, n)).mtimeMs });
2915
3573
  } catch {
2916
3574
  }
2917
3575
  }
@@ -2927,16 +3585,16 @@ var Outbox = class {
2927
3585
  read(ref, from, maxEvents = 500) {
2928
3586
  const f = this.file(ref);
2929
3587
  if (!existsSync9(f)) return { events: [], offset: from };
2930
- const size = statSync5(f).size;
3588
+ const size = statSync6(f).size;
2931
3589
  if (from >= size) return { events: [], offset: from };
2932
- const fd = openSync2(f, "r");
3590
+ const fd = openSync3(f, "r");
2933
3591
  try {
2934
3592
  const events = [];
2935
3593
  let offset = from;
2936
3594
  let chunk = READ_CHUNK;
2937
3595
  while (events.length < maxEvents && offset < size) {
2938
3596
  const buf = Buffer.alloc(Math.min(size - offset, chunk));
2939
- const n = readSync2(fd, buf, 0, buf.length, offset);
3597
+ const n = readSync3(fd, buf, 0, buf.length, offset);
2940
3598
  const text = buf.subarray(0, n).toString("utf8");
2941
3599
  let pos = 0;
2942
3600
  let used = 0;
@@ -2959,7 +3617,7 @@ var Outbox = class {
2959
3617
  }
2960
3618
  return { events, offset };
2961
3619
  } finally {
2962
- closeSync2(fd);
3620
+ closeSync3(fd);
2963
3621
  }
2964
3622
  }
2965
3623
  /** Files older than `days` are pruned; the cursor files with them. */
@@ -2969,7 +3627,7 @@ var Outbox = class {
2969
3627
  for (const ref of this.sessions()) {
2970
3628
  const f = this.file(ref);
2971
3629
  try {
2972
- if (statSync5(f).mtimeMs < cutoff) {
3630
+ if (statSync6(f).mtimeMs < cutoff) {
2973
3631
  unlinkSync3(f);
2974
3632
  try {
2975
3633
  unlinkSync3(this.seqFile(ref));
@@ -2999,18 +3657,18 @@ var Cursors = class {
2999
3657
  root;
3000
3658
  sink;
3001
3659
  file() {
3002
- return path11.join(this.root, "cursors", `${safeId(this.sink)}.json`);
3660
+ return path12.join(this.root, "cursors", `${safeId(this.sink)}.json`);
3003
3661
  }
3004
3662
  read() {
3005
3663
  try {
3006
- return JSON.parse(readFileSync8(this.file(), "utf8"));
3664
+ return JSON.parse(readFileSync9(this.file(), "utf8"));
3007
3665
  } catch {
3008
3666
  return {};
3009
3667
  }
3010
3668
  }
3011
3669
  write(c) {
3012
3670
  const f = this.file();
3013
- mkdirSync5(path11.dirname(f), { recursive: true, mode: 448 });
3671
+ mkdirSync5(path12.dirname(f), { recursive: true, mode: 448 });
3014
3672
  const tmp = `${f}.${process.pid}.tmp`;
3015
3673
  writeFileSync6(tmp, JSON.stringify(c), { mode: 384 });
3016
3674
  renameSync(tmp, f);
@@ -3023,11 +3681,11 @@ function takeLock(root, ref, staleMs = 5 * 6e4) {
3023
3681
  return takeNamedLock(root, `${safeId(ref.harness)}-${safeId(ref.session)}`, staleMs);
3024
3682
  }
3025
3683
  function takeNamedLock(root, name, staleMs = 5 * 6e4) {
3026
- const dir = path11.join(root, "locks");
3684
+ const dir = path12.join(root, "locks");
3027
3685
  mkdirSync5(dir, { recursive: true, mode: 448 });
3028
- const f = path11.join(dir, `${name}.lock`);
3686
+ const f = path12.join(dir, `${name}.lock`);
3029
3687
  try {
3030
- if (Date.now() - statSync5(f).mtimeMs > staleMs || !processAlive(Number(readFileSync8(f, "utf8")))) unlinkSync3(f);
3688
+ if (Date.now() - statSync6(f).mtimeMs > staleMs || !processAlive(Number(readFileSync9(f, "utf8")))) unlinkSync3(f);
3031
3689
  else return null;
3032
3690
  } catch {
3033
3691
  }
@@ -3265,6 +3923,8 @@ var TYPE_TIER = {
3265
3923
  "subagent.ended": 1,
3266
3924
  "context.compacted": 1,
3267
3925
  "limits.observed": 1,
3926
+ "delegation.started": 0,
3927
+ "delegation.ended": 0,
3268
3928
  native: 3
3269
3929
  };
3270
3930
  var DATA_ALLOW = {
@@ -3275,8 +3935,8 @@ var DATA_ALLOW = {
3275
3935
  "session.forgotten": { 0: [] },
3276
3936
  "turn.started": { 0: ["turn_id", "submitted_by", "injected"], 1: ["prompt_chars"] },
3277
3937
  "turn.ended": { 0: ["turn_id", "reason", "ms", "background"], 1: ["error"] },
3278
- "turn.transcript": { 2: ["turn", "user", "assistant", "at"] },
3279
- "turn.progress": { 2: ["turn", "user", "assistant", "at"] },
3938
+ "turn.transcript": { 2: ["turn", "user", "assistant", "at", "injected"] },
3939
+ "turn.progress": { 2: ["turn", "user", "assistant", "at", "injected"] },
3280
3940
  "tool.started": { 1: ["tool", "call_id", "turn_id", "agent_id"], 3: ["input"] },
3281
3941
  "tool.ended": { 1: ["tool", "call_id", "turn_id", "agent_id", "ms", "ok", "error"], 3: ["input", "output"] },
3282
3942
  "files.changed": { 1: ["paths"] },
@@ -3285,7 +3945,9 @@ var DATA_ALLOW = {
3285
3945
  "subagent.started": { 1: ["agent_id", "agent_type"] },
3286
3946
  "subagent.ended": { 1: ["agent_id", "agent_type"] },
3287
3947
  "context.compacted": { 1: ["trigger"] },
3288
- "limits.observed": { 1: ["windows", "plan", "account_id"] }
3948
+ "limits.observed": { 1: ["windows", "plan", "account_id"] },
3949
+ "delegation.started": { 0: ["ask_id", "via", "harness", "to"], 1: ["text"] },
3950
+ "delegation.ended": { 0: ["ask_id", "to", "ok", "ms", "error", "relayed"], 2: ["reply"] }
3289
3951
  };
3290
3952
  var SESSION_ALLOW = [
3291
3953
  "id",
@@ -3301,7 +3963,8 @@ var SESSION_ALLOW = [
3301
3963
  "account_id",
3302
3964
  "attended",
3303
3965
  "parent_id",
3304
- "launched_by"
3966
+ "launched_by",
3967
+ "delegated_by"
3305
3968
  ];
3306
3969
  var MAX_SIDE = 2e4;
3307
3970
  var MAX_IO = 64 * 1024;
@@ -3340,6 +4003,8 @@ function filterEvent(event, tier, pii, opts = {}) {
3340
4003
  if (data.input !== void 0) data.input = cap(data.input, MAX_IO);
3341
4004
  if (data.output !== void 0) data.output = cap(data.output, MAX_IO);
3342
4005
  if (typeof data.message === "string") data.message = cap(data.message, 200);
4006
+ if (event.type === "delegation.started" && typeof data.text === "string") data.text = cap(data.text, 200);
4007
+ if (event.type === "delegation.ended" && typeof data.reply === "string") data.reply = cap(data.reply, MAX_SIDE);
3343
4008
  const rulesets = [];
3344
4009
  let out = { ...event, tier, session, data, privacy: { rulesets, pii } };
3345
4010
  if (tier > 0) {
@@ -3367,7 +4032,7 @@ function shortId(harness, id) {
3367
4032
 
3368
4033
  // ../core/src/sinks/file.ts
3369
4034
  import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync6 } from "node:fs";
3370
- import path12 from "node:path";
4035
+ import path13 from "node:path";
3371
4036
  var FileSink = class {
3372
4037
  constructor(name, file, tier, pii) {
3373
4038
  this.name = name;
@@ -3381,7 +4046,7 @@ var FileSink = class {
3381
4046
  pii;
3382
4047
  async send(events) {
3383
4048
  try {
3384
- mkdirSync6(path12.dirname(this.file), { recursive: true });
4049
+ mkdirSync6(path13.dirname(this.file), { recursive: true });
3385
4050
  appendFileSync2(this.file, `${events.map((e) => JSON.stringify(e)).join("\n")}
3386
4051
  `);
3387
4052
  return { ok: true, acknowledged: events.length, accepted: events.length, duplicates: 0, rejected: [] };
@@ -3415,8 +4080,8 @@ var StdoutSink = class {
3415
4080
  };
3416
4081
 
3417
4082
  // src/control/aliases.ts
3418
- import { chmodSync as chmodSync2, mkdirSync as mkdirSync7, readFileSync as readFileSync9, renameSync as renameSync2, writeFileSync as writeFileSync7 } from "node:fs";
3419
- import path13 from "node:path";
4083
+ import { chmodSync as chmodSync2, mkdirSync as mkdirSync7, readFileSync as readFileSync10, renameSync as renameSync2, writeFileSync as writeFileSync7 } from "node:fs";
4084
+ import path14 from "node:path";
3420
4085
 
3421
4086
  // src/secrets.ts
3422
4087
  import { spawnSync } from "node:child_process";
@@ -3460,10 +4125,10 @@ function startOptionsOf(v) {
3460
4125
  }
3461
4126
 
3462
4127
  // src/control/aliases.ts
3463
- var aliasFile = (controlDir) => path13.join(controlDir, "aliases.json");
4128
+ var aliasFile = (controlDir) => path14.join(controlDir, "aliases.json");
3464
4129
  function readAliases(file) {
3465
4130
  try {
3466
- const j = JSON.parse(readFileSync9(file, "utf8"));
4131
+ const j = JSON.parse(readFileSync10(file, "utf8"));
3467
4132
  if (!j || typeof j !== "object" || Array.isArray(j)) return {};
3468
4133
  const out = {};
3469
4134
  for (const [k, v] of Object.entries(j)) {
@@ -3484,12 +4149,12 @@ function receiverIdOf(all, harness, id) {
3484
4149
 
3485
4150
  // src/control/local.ts
3486
4151
  import net from "node:net";
3487
- import os2 from "node:os";
3488
- import path14 from "node:path";
4152
+ import os3 from "node:os";
4153
+ import path15 from "node:path";
3489
4154
  function socketPath(state, env = process.env) {
3490
4155
  if (env.SESSIONPIPE_SOCKET) return env.SESSIONPIPE_SOCKET;
3491
- if (process.platform === "win32") return `\\\\.\\pipe\\sessionpipe-control-${os2.userInfo().username}`;
3492
- return path14.join(state, "control.sock");
4156
+ if (process.platform === "win32") return `\\\\.\\pipe\\sessionpipe-control-${os3.userInfo().username}`;
4157
+ return path15.join(state, "control.sock");
3493
4158
  }
3494
4159
  function ask(sock, req, timeoutMs) {
3495
4160
  return new Promise((resolve) => {
@@ -3525,6 +4190,11 @@ function ask(sock, req, timeoutMs) {
3525
4190
  async function tellDaemon(state, job, session, cwd, transcript) {
3526
4191
  const sock = socketPath(state);
3527
4192
  if (process.platform !== "win32" && !existsSync10(sock)) return;
4193
+ let mode = null;
4194
+ try {
4195
+ mode = claude_code_control_exports.hookMode(JSON.parse(job.stdin));
4196
+ } catch {
4197
+ }
3528
4198
  await ask(
3529
4199
  sock,
3530
4200
  {
@@ -3532,7 +4202,8 @@ async function tellDaemon(state, job, session, cwd, transcript) {
3532
4202
  session: `${job.harness}:${session}`,
3533
4203
  event: job.event,
3534
4204
  ...cwd ? { cwd } : {},
3535
- ...transcript ? { transcript } : {}
4205
+ ...transcript ? { transcript } : {},
4206
+ ...mode ? { mode } : {}
3536
4207
  },
3537
4208
  300
3538
4209
  );
@@ -3540,7 +4211,7 @@ async function tellDaemon(state, job, session, cwd, transcript) {
3540
4211
  function enqueueJob(state, job) {
3541
4212
  const jobs = jobsDir(state);
3542
4213
  mkdirSync8(jobs, { recursive: true, mode: 448 });
3543
- const f = path15.join(jobs, `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}.json`);
4214
+ const f = path16.join(jobs, `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}.json`);
3544
4215
  writeFileSync8(f, JSON.stringify(job), { mode: 384 });
3545
4216
  return f;
3546
4217
  }
@@ -3554,9 +4225,9 @@ function releaseJob(claimed) {
3554
4225
  function log(state, line) {
3555
4226
  try {
3556
4227
  mkdirSync8(state, { recursive: true, mode: 448 });
3557
- const f = path15.join(state, "log");
4228
+ const f = path16.join(state, "log");
3558
4229
  try {
3559
- if (statSync6(f).size > 1024 * 1024) renameSync3(f, `${f}.1`);
4230
+ if (statSync7(f).size > 1024 * 1024) renameSync3(f, `${f}.1`);
3560
4231
  } catch {
3561
4232
  }
3562
4233
  appendFileSync3(f, `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
@@ -3565,11 +4236,11 @@ function log(state, line) {
3565
4236
  }
3566
4237
  }
3567
4238
  function factsState(state) {
3568
- const file = (h, s) => path15.join(state, "facts", safeId(h), `${safeId(s)}.json`);
4239
+ const file = (h, s) => path16.join(state, "facts", safeId(h), `${safeId(s)}.json`);
3569
4240
  return {
3570
4241
  get(h, s) {
3571
4242
  try {
3572
- return JSON.parse(readFileSync10(file(h, s), "utf8"));
4243
+ return JSON.parse(readFileSync11(file(h, s), "utf8"));
3573
4244
  } catch {
3574
4245
  return {};
3575
4246
  }
@@ -3578,7 +4249,7 @@ function factsState(state) {
3578
4249
  const cur = this.get(h, s);
3579
4250
  const next = { ...cur, ...patch };
3580
4251
  if (JSON.stringify(next) === JSON.stringify(cur)) return;
3581
- mkdirSync8(path15.dirname(file(h, s)), { recursive: true, mode: 448 });
4252
+ mkdirSync8(path16.dirname(file(h, s)), { recursive: true, mode: 448 });
3582
4253
  writeFileSync8(file(h, s), JSON.stringify(next), { mode: 384 });
3583
4254
  }
3584
4255
  };
@@ -3595,7 +4266,7 @@ function buildSinks(sinks, o = {}) {
3595
4266
  const tier = Math.min(s.tier, s.max_tier ?? 3);
3596
4267
  if (s.url === "stdout") out.push(new StdoutSink(s.name, tier, !!s.pii));
3597
4268
  else if (s.url.startsWith("file:"))
3598
- out.push(new FileSink(s.name, s.url.slice(5).replace(/^~(?=\/|$)/, os3.homedir()), tier, !!s.pii));
4269
+ out.push(new FileSink(s.name, s.url.slice(5).replace(/^~(?=\/|$)/, os4.homedir()), tier, !!s.pii));
3599
4270
  else if (/^https?:\/\//.test(s.url)) out.push(new HttpSink(s, tier));
3600
4271
  }
3601
4272
  return out;
@@ -3603,13 +4274,14 @@ function buildSinks(sinks, o = {}) {
3603
4274
  var PROGRESS_MS = 2e4;
3604
4275
  function openTurn(read, o) {
3605
4276
  const last = read.turns[read.turns.length - 1];
3606
- const fresh = (user, at) => ({
4277
+ const fresh = (user, at, injected) => ({
3607
4278
  turn: o.base + read.turns.length,
3608
4279
  user: user.slice(0, MAX_TURN_SIDE),
3609
4280
  assistant: "",
3610
- at
4281
+ at,
4282
+ ...injected ? { injected: true } : {}
3611
4283
  });
3612
- if (read.open) return fresh(read.open.user, read.open.at);
4284
+ if (read.open) return fresh(read.open.user, read.open.at, read.open.injected);
3613
4285
  const prompt = o.prompt?.trim();
3614
4286
  if (prompt && !isInjected(prompt) && !(last && last.user.includes(prompt.slice(0, 200)))) return fresh(prompt, o.at);
3615
4287
  if (!last) return null;
@@ -3617,6 +4289,7 @@ function openTurn(read, o) {
3617
4289
  turn: o.base + read.turns.length - 1,
3618
4290
  user: last.user.slice(0, MAX_TURN_SIDE),
3619
4291
  assistant: capTail(last.assistant, MAX_TURN_SIDE),
4292
+ ...last.injected ? { injected: true } : {},
3620
4293
  at: last.at
3621
4294
  };
3622
4295
  }
@@ -3624,6 +4297,7 @@ var MAX_TURN_SIDE = 2e4;
3624
4297
  var JOB_OWN_ENV = [
3625
4298
  "CLAUDE_CODE_SESSION_ATTENDED",
3626
4299
  "CLAUDE_CODE_HOST_SESSION_ID",
4300
+ "SESSIONPIPE_ASKED_BY",
3627
4301
  "SESSIONPIPE_CONTROL_JOB",
3628
4302
  "SESSIONPIPE_LAUNCHED_BY"
3629
4303
  ];
@@ -3651,7 +4325,7 @@ async function runJob(job, opts = {}) {
3651
4325
  );
3652
4326
  return { events: [], delivered: {} };
3653
4327
  }
3654
- const id = receiverIdOf(readAliases(aliasFile(path15.join(state, "control"))), job.harness, r.session.id) ?? r.session.id;
4328
+ const id = receiverIdOf(readAliases(aliasFile(path16.join(state, "control"))), job.harness, r.session.id) ?? r.session.id;
3655
4329
  const claudeEnd = job.harness === "claude-code" && r.events.some((e) => e.type === "session.ended");
3656
4330
  if (!claudeEnd) await tellDaemon(state, job, id, r.session.cwd, r.transcript);
3657
4331
  const outbox = new Outbox(state);
@@ -3688,7 +4362,7 @@ async function runJob(job, opts = {}) {
3688
4362
  learned = rest;
3689
4363
  if (harness_version) facts.save(job.harness, id, { harness_version });
3690
4364
  facts.save(job.harness, id, { session: { ...mem.session, ...learned } });
3691
- if (CWD_FROM_HOOKS.has(job.harness) && r.session.cwd && path15.isAbsolute(r.session.cwd))
4365
+ if (CWD_FROM_HOOKS.has(job.harness) && r.session.cwd && path16.isAbsolute(r.session.cwd))
3692
4366
  facts.save(job.harness, id, { cwd: r.session.cwd });
3693
4367
  }
3694
4368
  const known = mem.session ?? {};
@@ -3701,10 +4375,11 @@ async function runJob(job, opts = {}) {
3701
4375
  ...learned.branch ? { branch: learned.branch } : {},
3702
4376
  id,
3703
4377
  seq: 0,
3704
- machine: machineName(cfg, os3.hostname()),
4378
+ machine: machineName(cfg, os4.hostname()),
3705
4379
  ...cwdRaw ? { cwd: tilde(cwdRaw) } : {},
3706
4380
  ...r.session.model ? { model: r.session.model } : {},
3707
- ...r.session.launched_by ? { launched_by: r.session.launched_by } : {}
4381
+ ...r.session.launched_by ? { launched_by: r.session.launched_by } : {},
4382
+ ...r.session.delegated_by ? { delegated_by: r.session.delegated_by } : {}
3708
4383
  };
3709
4384
  const version = facts.get(job.harness, id).harness_version ?? void 0;
3710
4385
  for (const a of r.events) {
@@ -3758,7 +4433,13 @@ async function runJob(job, opts = {}) {
3758
4433
  {
3759
4434
  type: "turn.transcript",
3760
4435
  harnessEvent: job.event,
3761
- data: { turn: turnNo++, user: t.user, assistant: t.assistant, at: new Date(t.at).toISOString() }
4436
+ data: {
4437
+ turn: turnNo++,
4438
+ user: t.user,
4439
+ assistant: t.assistant,
4440
+ at: new Date(t.at).toISOString(),
4441
+ ...t.injected ? { injected: true } : {}
4442
+ }
3762
4443
  },
3763
4444
  {
3764
4445
  harness: { name: job.harness, ...version ? { version } : {} },
@@ -3804,7 +4485,7 @@ async function runJob(job, opts = {}) {
3804
4485
  return { events, delivered };
3805
4486
  }
3806
4487
  async function drain(state, sinkConfigs, outbox, first) {
3807
- const more = path15.join(state, "locks", "flush.more");
4488
+ const more = path16.join(state, "locks", "flush.more");
3808
4489
  let release = takeNamedLock(state, "flush");
3809
4490
  if (!release) {
3810
4491
  try {
@@ -3832,10 +4513,10 @@ async function drain(state, sinkConfigs, outbox, first) {
3832
4513
  }
3833
4514
  }
3834
4515
  var BACKOFF_MS = [2e3, 1e4, 6e4, 5 * 6e4, 30 * 6e4];
3835
- var backoffFile = (state, sink) => path15.join(state, "backoff", `${safeId(sink)}.json`);
4516
+ var backoffFile = (state, sink) => path16.join(state, "backoff", `${safeId(sink)}.json`);
3836
4517
  function readBackoff(state, sink) {
3837
4518
  try {
3838
- const b = JSON.parse(readFileSync10(backoffFile(state, sink), "utf8"));
4519
+ const b = JSON.parse(readFileSync11(backoffFile(state, sink), "utf8"));
3839
4520
  return typeof b.until === "number" ? b : null;
3840
4521
  } catch {
3841
4522
  return null;
@@ -3848,7 +4529,7 @@ function noteFailure(state, sink, res, prev) {
3848
4529
  const b = { until: Date.now() + wait, failures, why: `${res.status ?? ""} ${res.error ?? ""}`.trim() };
3849
4530
  const f = backoffFile(state, sink);
3850
4531
  try {
3851
- mkdirSync8(path15.dirname(f), { recursive: true, mode: 448 });
4532
+ mkdirSync8(path16.dirname(f), { recursive: true, mode: 448 });
3852
4533
  writeFileSync8(f, JSON.stringify(b), { mode: 384 });
3853
4534
  } catch {
3854
4535
  }
@@ -3948,7 +4629,7 @@ async function flush(state, sinkConfigs, outbox, first, o = {}) {
3948
4629
  const { events, offset: next } = outbox.read(ref, offset, room);
3949
4630
  if (!events.length) break;
3950
4631
  for (const e of events) {
3951
- const f = filterEvent(e, sink.tier, sink.pii, { home: os3.homedir() });
4632
+ const f = filterEvent(e, sink.tier, sink.pii, { home: os4.homedir() });
3952
4633
  if (f) batch.push(f);
3953
4634
  }
3954
4635
  offset = next;
@@ -3981,7 +4662,7 @@ function applySinkVerdict(name, res) {
3981
4662
  } catch {
3982
4663
  }
3983
4664
  }
3984
- var jobsDir = (state) => path15.join(state, "jobs");
4665
+ var jobsDir = (state) => path16.join(state, "jobs");
3985
4666
  export {
3986
4667
  HttpSink,
3987
4668
  buildSinks,