sessionpipe-core 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,4 @@
1
- // sessionpipe-core 0.12.0 · Apache-2.0 · https://sessionpipe.org
1
+ // sessionpipe-core 0.13.0 · Apache-2.0 · https://sessionpipe.org
2
2
  var __defProp = Object.defineProperty;
3
3
  var __export = (target, all) => {
4
4
  for (var name in all)
@@ -211,7 +211,14 @@ ${m.text}`;
211
211
  continue;
212
212
  }
213
213
  if (cur) turns.push(cur);
214
- cur = { user: m.text, assistant: "", at: m.at, startLine: m.line, endLine: m.line };
214
+ cur = {
215
+ user: m.text,
216
+ assistant: "",
217
+ at: m.at,
218
+ startLine: m.line,
219
+ endLine: m.line,
220
+ ...m.injected ? { injected: true } : {}
221
+ };
215
222
  } else {
216
223
  if (!cur) cur = { user: "", assistant: "", at: m.at, startLine: m.line, endLine: m.line };
217
224
  cur.assistant += (cur.assistant ? "\n\n" : "") + m.text;
@@ -221,10 +228,17 @@ ${m.text}`;
221
228
  if (cur?.assistant) turns.push(cur);
222
229
  const line = cur && !cur.assistant ? cur.startLine : endLine;
223
230
  const out = {
224
- turns: turns.map((t) => ({ user: t.user, assistant: t.assistant, at: t.at, endLine: t.endLine })),
231
+ turns: turns.map((t) => ({
232
+ user: t.user,
233
+ assistant: t.assistant,
234
+ at: t.at,
235
+ endLine: t.endLine,
236
+ ...t.injected ? { injected: true } : {}
237
+ })),
225
238
  line
226
239
  };
227
- if (cur && !cur.assistant && cur.user) out.open = { user: cur.user, at: cur.at };
240
+ if (cur && !cur.assistant && cur.user)
241
+ out.open = { user: cur.user, at: cur.at, ...cur.injected ? { injected: true } : {} };
228
242
  return out;
229
243
  }
230
244
  var isInjected = (text) => /^<[a-z_-]+(?:\s[^>]*)?>/i.test(text) && /<\/[a-z_-]+>\s*$/i.test(text) || /^<!--\s/.test(text) || /^<command-/.test(text);
@@ -247,27 +261,51 @@ var textParts = (c, kinds) => {
247
261
  (b) => b && typeof b === "object" && kinds.includes(b.type ?? "") && typeof b.text === "string"
248
262
  ).map((b) => b.text).join("\n");
249
263
  };
264
+ var SPOKEN = /* @__PURE__ */ new Set(["human", "peer"]);
265
+ var PEER_INTRO = /sent a message[^\n]*:$/;
266
+ var PEER_OUTRO = "\n\nThis came from another ";
267
+ var ENVELOPE = /^<cross-session-message\b[^>]*>\n([\s\S]*)\n<\/cross-session-message>$/;
268
+ function peerAsk(origin, text) {
269
+ const body = origin?.body;
270
+ let t = typeof body === "string" && body.trim() ? body : text;
271
+ if (t !== body) {
272
+ const nl = t.indexOf("\n");
273
+ if (nl > 0 && PEER_INTRO.test(t.slice(0, nl))) t = t.slice(nl + 1);
274
+ const outro = t.indexOf(PEER_OUTRO);
275
+ if (outro > 0) t = t.slice(0, outro);
276
+ }
277
+ return (ENVELOPE.exec(t.trim())?.[1] ?? t).trim();
278
+ }
250
279
  var queuedPrompt = (a) => {
251
280
  if (!a || typeof a !== "object") return "";
252
281
  const q = a;
253
282
  if (q.type !== "queued_command" || (q.commandMode ?? "prompt") !== "prompt") return "";
254
- if (q.origin?.kind && q.origin.kind !== "human") return "";
255
- return textParts(q.prompt, ["text"]).trim();
283
+ const kind = q.origin?.kind ?? "human";
284
+ if (!SPOKEN.has(kind)) return "";
285
+ const text = textParts(q.prompt, ["text"]).trim();
286
+ return kind === "peer" ? peerAsk(q.origin, text) : text;
256
287
  };
288
+ var channelText = (text) => /^<channel\b[^>]*>([\s\S]*)<\/channel>$/.exec(text)?.[1]?.trim() ?? "";
257
289
  function readClaude(lines, from) {
258
290
  const msgs = [];
259
291
  for (let i = from; i < lines.length; i++) {
260
292
  const j = lines[i] ? parse(lines[i]) : null;
261
293
  if (!j || j.isSidechain) continue;
262
294
  const origin = j.origin;
263
- if (j.type === "user" && (j.isMeta || j.isCompactSummary || j.repeatsCompactSummary || origin?.kind && origin.kind !== "human"))
264
- continue;
295
+ const channel = j.type === "user" && origin?.kind === "channel";
296
+ const peer = origin?.kind === "peer";
297
+ if (j.type === "user" && (j.isCompactSummary || j.repeatsCompactSummary)) continue;
298
+ if (j.type === "user" && !channel && !peer && (j.isMeta || origin?.kind && origin.kind !== "human")) continue;
265
299
  const at = Date.parse(String(j.timestamp ?? "")) || Date.now();
266
300
  const c = j.message?.content;
267
- if (j.type === "user") {
268
- const text = textParts(c, ["text"]).trim();
301
+ if (channel) {
302
+ const text = channelText(textParts(c, ["text"]).trim());
303
+ if (text) msgs.push({ role: "user", text, at, line: i, injected: true });
304
+ } else if (j.type === "user") {
305
+ const raw = textParts(c, ["text"]).trim();
306
+ const text = peer ? peerAsk(origin, raw) : raw;
269
307
  if (!text || isInjected(text)) continue;
270
- msgs.push({ role: "user", text, at, line: i });
308
+ msgs.push({ role: "user", text, at, line: i, ...peer ? { injected: true } : {} });
271
309
  } else if (j.type === "assistant" && Array.isArray(c)) {
272
310
  const text = textParts(c, ["text"]).trim();
273
311
  if (text) msgs.push({ role: "assistant", text, at, line: i });
@@ -1635,6 +1673,41 @@ import path7 from "node:path";
1635
1673
  import { spawn } from "node:child_process";
1636
1674
  import { accessSync, constants, readFileSync as readFileSync4, statSync as statSync3 } from "node:fs";
1637
1675
  import path6 from "node:path";
1676
+
1677
+ // src/launched-by.ts
1678
+ var LAUNCHED_BY_ENV = "SESSIONPIPE_LAUNCHED_BY";
1679
+ var DELEGATED_BY_ENV = "SESSIONPIPE_ASKED_BY";
1680
+ var ASK_CHAIN_ENV = "SESSIONPIPE_ASK_CHAIN";
1681
+ var LINEAGE_ENV = [LAUNCHED_BY_ENV, DELEGATED_BY_ENV, ASK_CHAIN_ENV];
1682
+ var SESSION_REF = /^[a-z][a-z0-9-]{0,39}:[A-Za-z0-9._:-]{1,128}$/;
1683
+ function withoutLineage(env) {
1684
+ const e = { ...env };
1685
+ for (const k of LINEAGE_ENV) delete e[k];
1686
+ return e;
1687
+ }
1688
+ function refIn(env, name) {
1689
+ const v = env[name]?.trim();
1690
+ return v && SESSION_REF.test(v) ? v : void 0;
1691
+ }
1692
+ function launchedBy(env) {
1693
+ return refIn(env, LAUNCHED_BY_ENV);
1694
+ }
1695
+ function delegatedBy(env) {
1696
+ return refIn(env, DELEGATED_BY_ENV);
1697
+ }
1698
+ function readHook(adapter, input) {
1699
+ const r = adapter.fromHook(input);
1700
+ if (r && !r.session.parent_id) {
1701
+ const self = `${adapter.name}:${r.session.id}`;
1702
+ const launcher = launchedBy(input.env);
1703
+ if (launcher && launcher !== self) r.session.launched_by = launcher;
1704
+ const asker = delegatedBy(input.env);
1705
+ if (asker && asker !== self) r.session.delegated_by = asker;
1706
+ }
1707
+ return r;
1708
+ }
1709
+
1710
+ // src/adapters/headless.ts
1638
1711
  var JOB_TIMEOUT_MS = 30 * 6e4;
1639
1712
  var OUT_CAP = 1024 * 1024;
1640
1713
  function isExe(p) {
@@ -1682,7 +1755,7 @@ function probe(bin, args) {
1682
1755
  return s ? { ...s, shell: false } : { file: [`"${bin}"`, ...args].join(" "), args: [], shell: true };
1683
1756
  }
1684
1757
  function jobEnv(env = process.env) {
1685
- return { ...env, SESSIONPIPE_CONTROL_JOB: "1" };
1758
+ return { ...withoutLineage(env), SESSIONPIPE_CONTROL_JOB: "1" };
1686
1759
  }
1687
1760
  function runHeadless(bin, args, o) {
1688
1761
  return new Promise((resolve) => {
@@ -1904,7 +1977,9 @@ function startAcp(o) {
1904
1977
  try {
1905
1978
  child = spawn2(c.file, c.args, {
1906
1979
  cwd: o.cwd,
1907
- env: jobEnv(o.env),
1980
+ // The caller's env as given (the daemon's is jobEnv's already, with the ask's
1981
+ // lineage on top), marked as a control job.
1982
+ env: { ...o.env, SESSIONPIPE_CONTROL_JOB: "1" },
1908
1983
  stdio: ["pipe", "pipe", "pipe"],
1909
1984
  detached: process.platform !== "win32",
1910
1985
  windowsHide: true
@@ -2591,7 +2666,10 @@ var reading = () => new AgyReading();
2591
2666
  // src/adapters/claude-code-control.ts
2592
2667
  var claude_code_control_exports = {};
2593
2668
  __export(claude_code_control_exports, {
2669
+ CLAUDE_MODES: () => CLAUDE_MODES,
2594
2670
  JOB_TIMEOUT_MS: () => JOB_TIMEOUT_MS,
2671
+ MODE_RANK: () => MODE_RANK,
2672
+ NO_HOME_SETTINGS: () => NO_HOME_SETTINGS,
2595
2673
  ceilingLevel: () => ceilingLevel,
2596
2674
  claudeArgs: () => claudeArgs,
2597
2675
  claudeEnv: () => claudeEnv,
@@ -2601,17 +2679,26 @@ __export(claude_code_control_exports, {
2601
2679
  detectCaps: () => detectCaps,
2602
2680
  findClaude: () => findClaude,
2603
2681
  findTranscript: () => findTranscript,
2682
+ findTranscripts: () => findTranscripts,
2683
+ homeSettings: () => homeSettings,
2684
+ hookMode: () => hookMode,
2604
2685
  isUuid: () => isUuid,
2605
2686
  liveProcess: () => liveProcess,
2687
+ liveRecord: () => liveRecord,
2688
+ liveRecords: () => liveRecords,
2606
2689
  loginCommand: () => loginCommand,
2607
2690
  loginHint: () => loginHint,
2608
2691
  modeFlags: () => modeFlags,
2692
+ modeRank: () => modeRank,
2609
2693
  offeredLevels: () => offeredLevels2,
2610
2694
  outputArgs: () => outputArgs,
2611
2695
  parseAuthStatus: () => parseAuthStatus,
2612
2696
  parseCaps: () => parseCaps,
2613
2697
  parseResult: () => parseResult,
2698
+ peerClass: () => peerClass,
2614
2699
  recentlyWritten: () => recentlyWritten,
2700
+ relaunchMode: () => relaunchMode,
2701
+ resolveHome: () => resolveHome,
2615
2702
  runClaude: () => runClaude,
2616
2703
  sessionFolder: () => sessionFolder
2617
2704
  });
@@ -2630,10 +2717,10 @@ var MODEL_RE = /^[A-Za-z0-9][A-Za-z0-9._:/@[\]-]*$/;
2630
2717
  var START_PERMISSIONS = ["read", "safe", "edits", "auto"];
2631
2718
  var levelRank = (l) => START_PERMISSIONS.indexOf(l);
2632
2719
  var FIELDS = {
2633
- prompt: ["text", "files"],
2720
+ prompt: ["text", "files", "reply_to"],
2634
2721
  "permission.answer": ["for", "decision"],
2635
2722
  cancel: [],
2636
- start: ["text", "cwd", "files", "permission", "model"],
2723
+ start: ["text", "cwd", "files", "permission", "model", "reply_to"],
2637
2724
  "key.add": ["key", "name"],
2638
2725
  pool: ["pool_action", "pool_account", "pool_order", "pool_code"]
2639
2726
  };
@@ -2705,6 +2792,8 @@ var LEVEL_MODE = {
2705
2792
  };
2706
2793
  function modeFlags(level, caps) {
2707
2794
  if (level === "inherit") return { args: [] };
2795
+ if (caps.unread)
2796
+ return { error: `this machine couldn't read its Claude Code's options (${caps.unread}); try again in a minute` };
2708
2797
  if (level === "auto" && !caps.modes.includes("auto"))
2709
2798
  return { error: "this machine is in auto mode, but its Claude Code has no auto permission mode" };
2710
2799
  if (level !== "safe") {
@@ -2724,6 +2813,7 @@ function modeFlags(level, caps) {
2724
2813
  }
2725
2814
  var ceilingLevel = (mode) => mode === "inherit" ? "safe" : mode;
2726
2815
  function offeredLevels2(mode, caps) {
2816
+ if (caps.unread) return [];
2727
2817
  return START_PERMISSIONS.filter(
2728
2818
  (l) => levelRank(l) <= levelRank(ceilingLevel(mode)) && (l === "safe" || caps.modes.includes(LEVEL_MODE[l]))
2729
2819
  );
@@ -2749,7 +2839,7 @@ function claudeArgs(o) {
2749
2839
  };
2750
2840
  }
2751
2841
  function claudeEnv(configDir, env = process.env) {
2752
- const e = { ...env };
2842
+ const e = withoutLineage(env);
2753
2843
  for (const k of [
2754
2844
  "CLAUDECODE",
2755
2845
  "CLAUDE_CODE_SESSION_ID",
@@ -2806,43 +2896,73 @@ function loginHint(configDir, platform = process.platform) {
2806
2896
  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.`;
2807
2897
  return `Claude Code (${shown}) isn't signed in on this machine: run ${login} there.`;
2808
2898
  }
2809
- function detectCaps(bin) {
2810
- let help = "";
2899
+ function detectCaps(bin, timeoutMs = 3e4) {
2811
2900
  const c = probe(bin, ["--help"]);
2812
2901
  try {
2813
- help = execFileSync3(c.file, c.args, {
2814
- encoding: "utf8",
2815
- timeout: 3e4,
2816
- env: claudeEnv(),
2817
- stdio: ["ignore", "pipe", "pipe"],
2818
- maxBuffer: 4 * 1024 * 1024,
2819
- shell: c.shell
2820
- });
2902
+ return parseCaps(
2903
+ execFileSync3(c.file, c.args, {
2904
+ encoding: "utf8",
2905
+ timeout: timeoutMs,
2906
+ env: claudeEnv(),
2907
+ stdio: ["ignore", "pipe", "pipe"],
2908
+ maxBuffer: 4 * 1024 * 1024,
2909
+ shell: c.shell
2910
+ })
2911
+ );
2821
2912
  } catch (e) {
2822
- help = String(e?.stdout || "");
2913
+ const err = e;
2914
+ const caps = parseCaps(String(err?.stdout || ""));
2915
+ if (caps.hasMode) return caps;
2916
+ const why = err?.code === "ETIMEDOUT" ? `timed out after ${timeoutMs / 1e3} s` : "failed";
2917
+ return { ...caps, unread: `\`${path10.basename(bin)} --help\` ${why}` };
2823
2918
  }
2824
- return parseCaps(help);
2825
2919
  }
2826
- function findTranscript(session, dirs) {
2827
- if (!UUID_RE2.test(session)) return null;
2828
- for (const dir of dirs) {
2829
- let projects = [];
2920
+ function transcriptIn(session, dir) {
2921
+ let projects = [];
2922
+ try {
2923
+ projects = readdirSync4(path10.join(dir, "projects"), { withFileTypes: true });
2924
+ } catch {
2925
+ return null;
2926
+ }
2927
+ for (const p of projects) {
2928
+ if (!p.isDirectory()) continue;
2929
+ const file = path10.join(dir, "projects", p.name, `${session}.jsonl`);
2830
2930
  try {
2831
- projects = readdirSync4(path10.join(dir, "projects"), { withFileTypes: true });
2931
+ if (statSync5(file).isFile()) return { file, configDir: dir, project: p.name };
2832
2932
  } catch {
2833
- continue;
2834
- }
2835
- for (const p of projects) {
2836
- if (!p.isDirectory()) continue;
2837
- const file = path10.join(dir, "projects", p.name, `${session}.jsonl`);
2838
- try {
2839
- if (statSync5(file).isFile()) return { file, configDir: dir, project: p.name };
2840
- } catch {
2841
- }
2842
2933
  }
2843
2934
  }
2844
2935
  return null;
2845
2936
  }
2937
+ function findTranscript(session, dirs) {
2938
+ if (!UUID_RE2.test(session)) return null;
2939
+ for (const dir of dirs) {
2940
+ const t = transcriptIn(session, dir);
2941
+ if (t) return t;
2942
+ }
2943
+ return null;
2944
+ }
2945
+ function findTranscripts(session, dirs) {
2946
+ if (!UUID_RE2.test(session)) return [];
2947
+ const out = [];
2948
+ for (const dir of dirs) {
2949
+ const t = transcriptIn(session, dir);
2950
+ if (t) out.push(t);
2951
+ }
2952
+ return out;
2953
+ }
2954
+ var homeName = (t) => path10.basename(t.configDir);
2955
+ function resolveHome(session, dirs) {
2956
+ const all = findTranscripts(session, dirs);
2957
+ if (!all.length) return null;
2958
+ if (all.length === 1) return { transcript: all[0] };
2959
+ const live = all.filter((t) => liveRecords(session, t.configDir).length > 0);
2960
+ if (live.length === 1) return { transcript: live[0] };
2961
+ return {
2962
+ ambiguous: [...new Set(all.map(homeName))].sort(),
2963
+ live: [...new Set(live.map(homeName))].sort()
2964
+ };
2965
+ }
2846
2966
  var projectName = (cwd) => cwd.replace(/[^a-zA-Z0-9]/g, "-");
2847
2967
  function sessionFolder(t, cap2 = 8 * 1024 * 1024) {
2848
2968
  let first = null;
@@ -2914,22 +3034,105 @@ function pidAlive(pid) {
2914
3034
  return e.code === "EPERM";
2915
3035
  }
2916
3036
  }
2917
- function liveProcess(session, configDir) {
2918
- let names = [];
3037
+ var registryRow = (file, configDir, j) => {
3038
+ const pid = Number(j.pid ?? path10.basename(file).slice(0, -5));
3039
+ const str2 = (v) => typeof v === "string" && v ? v : null;
3040
+ let keyFile = null;
2919
3041
  try {
2920
- names = readdirSync4(path10.join(configDir, "sessions")).filter((n) => /^\d+\.json$/.test(n));
3042
+ const want = new RegExp(`^${pid}\\.[0-9a-f]{64}\\.key$`);
3043
+ const hit = readdirSync4(path10.dirname(file)).find((n) => want.test(n));
3044
+ if (hit) keyFile = path10.join(path10.dirname(file), hit);
2921
3045
  } catch {
2922
- return false;
2923
3046
  }
2924
- for (const n of names) {
3047
+ return {
3048
+ configDir,
3049
+ file,
3050
+ pid,
3051
+ socket: str2(j.messagingSocketPath),
3052
+ peerProtocol: typeof j.peerProtocol === "number" ? j.peerProtocol : null,
3053
+ procStart: str2(j.procStart),
3054
+ status: str2(j.status),
3055
+ kind: str2(j.kind),
3056
+ entrypoint: str2(j.entrypoint),
3057
+ keyFile
3058
+ };
3059
+ };
3060
+ function liveRecords(session, dirs) {
3061
+ const out = [];
3062
+ for (const dir of typeof dirs === "string" ? [dirs] : dirs) {
3063
+ let names = [];
2925
3064
  try {
2926
- const j = JSON.parse(readFileSync6(path10.join(configDir, "sessions", n), "utf8"));
2927
- if (String(j.sessionId) !== session) continue;
2928
- if (pidAlive(Number(j.pid ?? n.slice(0, -5)))) return true;
3065
+ names = readdirSync4(path10.join(dir, "sessions")).filter((n) => /^\d+\.json$/.test(n));
2929
3066
  } catch {
3067
+ continue;
3068
+ }
3069
+ for (const n of names) {
3070
+ const file = path10.join(dir, "sessions", n);
3071
+ let j;
3072
+ try {
3073
+ j = JSON.parse(readFileSync6(file, "utf8"));
3074
+ } catch {
3075
+ continue;
3076
+ }
3077
+ if (String(j.sessionId) !== session) continue;
3078
+ const row = registryRow(file, dir, j);
3079
+ if (pidAlive(row.pid)) out.push(row);
2930
3080
  }
2931
3081
  }
2932
- return false;
3082
+ return out;
3083
+ }
3084
+ function liveRecord(session, dirs) {
3085
+ const all = liveRecords(session, dirs);
3086
+ return all.length === 1 ? all[0] : null;
3087
+ }
3088
+ function liveProcess(session, configDir) {
3089
+ return liveRecords(session, configDir).length > 0;
3090
+ }
3091
+ var MODE_RANK = {
3092
+ plan: 0,
3093
+ default: 1,
3094
+ manual: 1,
3095
+ dontAsk: 1,
3096
+ acceptEdits: 2,
3097
+ auto: 3,
3098
+ bypassPermissions: 4
3099
+ };
3100
+ var CLAUDE_MODES = Object.keys(MODE_RANK);
3101
+ var modeRank = (m) => m && m in MODE_RANK ? MODE_RANK[m] : -1;
3102
+ function hookMode(payload) {
3103
+ if (!payload || typeof payload !== "object") return null;
3104
+ const p = payload;
3105
+ const v = typeof p.permission_mode === "string" ? p.permission_mode : p.permissionMode;
3106
+ return typeof v === "string" && CLAUDE_MODES.includes(v) ? v : null;
3107
+ }
3108
+ function peerClass(mode) {
3109
+ if (mode === "bypassPermissions") return "bypass";
3110
+ if (mode === "default" || mode === "manual" || mode === "dontAsk" || mode === "acceptEdits") return "prompting";
3111
+ return null;
3112
+ }
3113
+ var NO_HOME_SETTINGS = { defaultMode: null, disableAutoMode: false, disableBypass: false };
3114
+ function homeSettings(configDir, home = os5.homedir()) {
3115
+ const file = path10.join(configDir ?? path10.join(home, ".claude"), "settings.json");
3116
+ let j;
3117
+ try {
3118
+ j = JSON.parse(readFileSync6(file, "utf8"));
3119
+ } catch {
3120
+ return { ...NO_HOME_SETTINGS };
3121
+ }
3122
+ if (!j || typeof j !== "object" || Array.isArray(j)) return { ...NO_HOME_SETTINGS };
3123
+ const p = j.permissions && typeof j.permissions === "object" ? j.permissions : {};
3124
+ const off = (k) => j[k] === "disable" || p[k] === "disable";
3125
+ return {
3126
+ defaultMode: typeof p.defaultMode === "string" && CLAUDE_MODES.includes(p.defaultMode) ? p.defaultMode : null,
3127
+ disableAutoMode: off("disableAutoMode"),
3128
+ disableBypass: off("disableBypassPermissionsMode")
3129
+ };
3130
+ }
3131
+ function relaunchMode(recorded, home) {
3132
+ if (recorded === "plan") return recorded;
3133
+ if ((recorded === "dontAsk" || recorded === "acceptEdits") && modeRank(home.defaultMode) >= modeRank(recorded))
3134
+ return recorded;
3135
+ return null;
2933
3136
  }
2934
3137
  function recentlyWritten(file, ourLastEnd, now = Date.now()) {
2935
3138
  let m;
@@ -4347,22 +4550,6 @@ function makeEvent(a, ctx) {
4347
4550
  };
4348
4551
  }
4349
4552
 
4350
- // src/launched-by.ts
4351
- var LAUNCHED_BY_ENV = "SESSIONPIPE_LAUNCHED_BY";
4352
- var LAUNCHED_BY = /^[a-z][a-z0-9-]{0,39}:[A-Za-z0-9._:-]{1,128}$/;
4353
- function launchedBy(env) {
4354
- const v = env[LAUNCHED_BY_ENV]?.trim();
4355
- return v && LAUNCHED_BY.test(v) ? v : void 0;
4356
- }
4357
- function readHook(adapter, input) {
4358
- const r = adapter.fromHook(input);
4359
- if (r && !r.session.parent_id) {
4360
- const launcher = launchedBy(input.env);
4361
- if (launcher && launcher !== `${adapter.name}:${r.session.id}`) r.session.launched_by = launcher;
4362
- }
4363
- return r;
4364
- }
4365
-
4366
4553
  // src/outbox.ts
4367
4554
  import {
4368
4555
  appendFileSync,
@@ -4801,6 +4988,8 @@ var TYPE_TIER = {
4801
4988
  "subagent.ended": 1,
4802
4989
  "context.compacted": 1,
4803
4990
  "limits.observed": 1,
4991
+ "delegation.started": 0,
4992
+ "delegation.ended": 0,
4804
4993
  native: 3
4805
4994
  };
4806
4995
  var DATA_ALLOW = {
@@ -4811,8 +5000,8 @@ var DATA_ALLOW = {
4811
5000
  "session.forgotten": { 0: [] },
4812
5001
  "turn.started": { 0: ["turn_id", "submitted_by", "injected"], 1: ["prompt_chars"] },
4813
5002
  "turn.ended": { 0: ["turn_id", "reason", "ms", "background"], 1: ["error"] },
4814
- "turn.transcript": { 2: ["turn", "user", "assistant", "at"] },
4815
- "turn.progress": { 2: ["turn", "user", "assistant", "at"] },
5003
+ "turn.transcript": { 2: ["turn", "user", "assistant", "at", "injected"] },
5004
+ "turn.progress": { 2: ["turn", "user", "assistant", "at", "injected"] },
4816
5005
  "tool.started": { 1: ["tool", "call_id", "turn_id", "agent_id"], 3: ["input"] },
4817
5006
  "tool.ended": { 1: ["tool", "call_id", "turn_id", "agent_id", "ms", "ok", "error"], 3: ["input", "output"] },
4818
5007
  "files.changed": { 1: ["paths"] },
@@ -4821,7 +5010,9 @@ var DATA_ALLOW = {
4821
5010
  "subagent.started": { 1: ["agent_id", "agent_type"] },
4822
5011
  "subagent.ended": { 1: ["agent_id", "agent_type"] },
4823
5012
  "context.compacted": { 1: ["trigger"] },
4824
- "limits.observed": { 1: ["windows", "plan", "account_id"] }
5013
+ "limits.observed": { 1: ["windows", "plan", "account_id"] },
5014
+ "delegation.started": { 0: ["ask_id", "via", "harness", "to"], 1: ["text"] },
5015
+ "delegation.ended": { 0: ["ask_id", "to", "ok", "ms", "error", "relayed"], 2: ["reply"] }
4825
5016
  };
4826
5017
  var SESSION_ALLOW = [
4827
5018
  "id",
@@ -4837,7 +5028,8 @@ var SESSION_ALLOW = [
4837
5028
  "account_id",
4838
5029
  "attended",
4839
5030
  "parent_id",
4840
- "launched_by"
5031
+ "launched_by",
5032
+ "delegated_by"
4841
5033
  ];
4842
5034
  var MAX_SIDE = 2e4;
4843
5035
  var MAX_IO = 64 * 1024;
@@ -4876,6 +5068,8 @@ function filterEvent(event, tier, pii, opts = {}) {
4876
5068
  if (data.input !== void 0) data.input = cap(data.input, MAX_IO);
4877
5069
  if (data.output !== void 0) data.output = cap(data.output, MAX_IO);
4878
5070
  if (typeof data.message === "string") data.message = cap(data.message, 200);
5071
+ if (event.type === "delegation.started" && typeof data.text === "string") data.text = cap(data.text, 200);
5072
+ if (event.type === "delegation.ended" && typeof data.reply === "string") data.reply = cap(data.reply, MAX_SIDE);
4879
5073
  const rulesets = [];
4880
5074
  let out = { ...event, tier, session, data, privacy: { rulesets, pii } };
4881
5075
  if (tier > 0) {
@@ -4955,13 +5149,16 @@ var PROTOCOL_VERSION = 1;
4955
5149
  export {
4956
5150
  ADAPTERS,
4957
5151
  AG_STALE_PRETOOL,
5152
+ ASK_CHAIN_ENV,
4958
5153
  Cursors,
4959
5154
  DEFAULT_CONFIG,
5155
+ DELEGATED_BY_ENV,
4960
5156
  DEVIN_EVENTS,
4961
5157
  FileSink,
4962
5158
  HELLO_HARNESSES_MAX,
4963
5159
  JOB_TIMEOUT_MS,
4964
5160
  LAUNCHED_BY_ENV,
5161
+ LINEAGE_ENV,
4965
5162
  Outbox,
4966
5163
  PROTOCOL_VERSION,
4967
5164
  REDACTED,
@@ -4983,6 +5180,7 @@ export {
4983
5180
  codex,
4984
5181
  codex_control_exports as codexControl,
4985
5182
  configFile,
5183
+ delegatedBy,
4986
5184
  deniedNote,
4987
5185
  devin,
4988
5186
  devinConfigDir,
@@ -5003,6 +5201,7 @@ export {
5003
5201
  makeEvent,
5004
5202
  notClaudeCode,
5005
5203
  pairTurns,
5204
+ peerAsk,
5006
5205
  processAlive,
5007
5206
  readAntigravity,
5008
5207
  readClaude,
@@ -5025,6 +5224,7 @@ export {
5025
5224
  tilde,
5026
5225
  ulid,
5027
5226
  untilde,
5227
+ withoutLineage,
5028
5228
  writeConfig
5029
5229
  };
5030
5230
  //# sourceMappingURL=index.js.map