sessionpipe 0.11.0 → 0.12.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/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // sessionpipe 0.11.0 · Apache-2.0 · https://sessionpipe.org
2
+ // sessionpipe 0.12.0 · Apache-2.0 · https://sessionpipe.org
3
3
  var __defProp = Object.defineProperty;
4
4
  var __export = (target2, all) => {
5
5
  for (var name in all)
@@ -12,7 +12,7 @@ import {
12
12
  existsSync as existsSync20,
13
13
  mkdtempSync,
14
14
  readdirSync as readdirSync8,
15
- readFileSync as readFileSync20,
15
+ readFileSync as readFileSync21,
16
16
  realpathSync as realpathSync9,
17
17
  rmSync as rmSync3,
18
18
  statSync as statSync12,
@@ -662,13 +662,7 @@ var claudeCode = {
662
662
  );
663
663
  break;
664
664
  case "Stop":
665
- events.push(
666
- ev("turn.ended", {
667
- turn_id,
668
- reason: "stop",
669
- background: Array.isArray(s.background_tasks) ? s.background_tasks.length : void 0
670
- })
671
- );
665
+ events.push(ev("turn.ended", { turn_id, reason: "stop", background: backgroundCount(s.background_tasks) }));
672
666
  break;
673
667
  case "StopFailure":
674
668
  events.push(
@@ -691,7 +685,8 @@ var claudeCode = {
691
685
  events.push(
692
686
  ev("subagent.ended", {
693
687
  agent_id: String(s.agent_id ?? ""),
694
- agent_type: typeof s.agent_type === "string" ? s.agent_type : void 0
688
+ agent_type: typeof s.agent_type === "string" ? s.agent_type : void 0,
689
+ background: backgroundCount(s.background_tasks, String(s.agent_id ?? ""))
695
690
  })
696
691
  );
697
692
  break;
@@ -766,6 +761,15 @@ var claudeCode = {
766
761
  return rows2;
767
762
  }
768
763
  };
764
+ var WAITER_RE = /(?:^|[\s"'`/\\])sessionpipe(?:\.\w+)?["']?\s+wait(?:\s|$)/;
765
+ function backgroundCount(tasks, ending) {
766
+ if (!Array.isArray(tasks)) return void 0;
767
+ return tasks.filter((t) => {
768
+ const task = t;
769
+ if (ending !== void 0 && task?.id === ending) return false;
770
+ return !(typeof task?.command === "string" && WAITER_RE.test(task.command));
771
+ }).length;
772
+ }
769
773
  var LINE_REFRESH_S = 60;
770
774
  function statusLine(file, want, cmd) {
771
775
  const f = readJsonFile(file);
@@ -1646,7 +1650,7 @@ import path7 from "node:path";
1646
1650
 
1647
1651
  // ../core/src/adapters/headless.ts
1648
1652
  import { spawn } from "node:child_process";
1649
- import { accessSync, constants, statSync as statSync3 } from "node:fs";
1653
+ import { accessSync, constants, readFileSync as readFileSync4, statSync as statSync3 } from "node:fs";
1650
1654
  import path6 from "node:path";
1651
1655
  var JOB_TIMEOUT_MS = 30 * 6e4;
1652
1656
  var OUT_CAP = 1024 * 1024;
@@ -1668,6 +1672,32 @@ function findBinary(o) {
1668
1672
  for (const d of o.dirs) for (const n of o.names) if (isExe(path6.join(d, n))) return path6.join(d, n);
1669
1673
  return null;
1670
1674
  }
1675
+ function shimTarget(shim) {
1676
+ let text = "";
1677
+ try {
1678
+ text = readFileSync4(shim, "utf8");
1679
+ } catch {
1680
+ return null;
1681
+ }
1682
+ const m = /"%(?:~dp0|dp0%)\\([^"]+)"\s+%\*/.exec(text);
1683
+ if (!m) return null;
1684
+ const target2 = path6.resolve(path6.dirname(shim), m[1].split("\\").join(path6.sep));
1685
+ try {
1686
+ return statSync3(target2).isFile() ? target2 : null;
1687
+ } catch {
1688
+ return null;
1689
+ }
1690
+ }
1691
+ function spawnable(bin, args2) {
1692
+ if (!/\.(cmd|bat)$/i.test(bin)) return { file: bin, args: args2 };
1693
+ const target2 = shimTarget(bin);
1694
+ return target2 ? { file: process.execPath, args: [target2, ...args2] } : null;
1695
+ }
1696
+ var shimNote = (bin) => `${path6.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`;
1697
+ function probe(bin, args2) {
1698
+ const s = spawnable(bin, args2);
1699
+ return s ? { ...s, shell: false } : { file: [`"${bin}"`, ...args2].join(" "), args: [], shell: true };
1700
+ }
1671
1701
  function jobEnv(env = process.env) {
1672
1702
  return { ...env, SESSIONPIPE_CONTROL_JOB: "1" };
1673
1703
  }
@@ -1680,8 +1710,13 @@ function runHeadless(bin, args2, o) {
1680
1710
  let timedOut = false;
1681
1711
  let settled = false;
1682
1712
  let child;
1713
+ const c = spawnable(bin, args2);
1714
+ if (!c) {
1715
+ resolve({ error: shimNote(bin) });
1716
+ return;
1717
+ }
1683
1718
  try {
1684
- child = spawn(bin, args2, {
1719
+ child = spawn(c.file, c.args, {
1685
1720
  cwd: o.cwd,
1686
1721
  env: o.env,
1687
1722
  stdio: ["ignore", "pipe", "pipe"],
@@ -1881,8 +1916,10 @@ function startAcp(o) {
1881
1916
  });
1882
1917
  const label = o.label;
1883
1918
  let child;
1919
+ const c = spawnable(o.bin, o.args);
1920
+ if (!c) return Promise.resolve({ failed: `couldn't start ${label}: ${shimNote(o.bin)}` });
1884
1921
  try {
1885
- child = spawn2(o.bin, o.args, {
1922
+ child = spawn2(c.file, c.args, {
1886
1923
  cwd: o.cwd,
1887
1924
  env: jobEnv(o.env),
1888
1925
  stdio: ["pipe", "pipe", "pipe"],
@@ -1943,15 +1980,15 @@ function startAcp(o) {
1943
1980
  return;
1944
1981
  }
1945
1982
  if (kind !== "agent_message_chunk" || !turn) return;
1946
- const c = obj(u.content);
1947
- if (c?.type !== "text" || !str(c.text)) return;
1983
+ const c2 = obj(u.content);
1984
+ if (c2?.type !== "text" || !str(c2.text)) return;
1948
1985
  const mid = str(u.messageId) || null;
1949
1986
  if (turn.message !== void 0 && mid !== turn.message && turn.text.trim())
1950
1987
  turn.text = `${turn.text.trimEnd()}
1951
1988
 
1952
1989
  `;
1953
1990
  turn.message = mid;
1954
- turn.text += str(c.text);
1991
+ turn.text += str(c2.text);
1955
1992
  o.onText?.(turn.text);
1956
1993
  };
1957
1994
  const onRequest = (id, method, params) => {
@@ -2147,7 +2184,7 @@ import {
2147
2184
  existsSync as existsSync3,
2148
2185
  mkdirSync as mkdirSync2,
2149
2186
  readdirSync as readdirSync3,
2150
- readFileSync as readFileSync4,
2187
+ readFileSync as readFileSync5,
2151
2188
  realpathSync,
2152
2189
  statSync as statSync4,
2153
2190
  unlinkSync as unlinkSync2,
@@ -2276,7 +2313,7 @@ var antigravity = {
2276
2313
  readTranscript(file, fromLine) {
2277
2314
  let text = "";
2278
2315
  try {
2279
- text = readFileSync4(file, "utf8");
2316
+ text = readFileSync5(file, "utf8");
2280
2317
  } catch {
2281
2318
  return { turns: [], line: fromLine };
2282
2319
  }
@@ -2355,7 +2392,7 @@ function agProjects(dir) {
2355
2392
  if (!ID_RE2.test(id)) continue;
2356
2393
  let j;
2357
2394
  try {
2358
- j = JSON.parse(readFileSync4(path8.join(dir, n), "utf8"));
2395
+ j = JSON.parse(readFileSync5(path8.join(dir, n), "utf8"));
2359
2396
  } catch {
2360
2397
  continue;
2361
2398
  }
@@ -2392,7 +2429,7 @@ function antigravityRemoteUrl(transcript, opts) {
2392
2429
  for (const d of dirs) {
2393
2430
  try {
2394
2431
  const m = /installation_uuid:\s*"([0-9a-f-]{36})"/i.exec(
2395
- readFileSync4(path8.join(d, "antigravity_state.pbtxt"), "utf8")
2432
+ readFileSync5(path8.join(d, "antigravity_state.pbtxt"), "utf8")
2396
2433
  );
2397
2434
  if (!m) continue;
2398
2435
  const base = `https://antigravity.google.com/r/${m[1]}-v2`;
@@ -2596,7 +2633,7 @@ __export(claude_code_control_exports, {
2596
2633
  sessionFolder: () => sessionFolder
2597
2634
  });
2598
2635
  import { execFile, execFileSync as execFileSync3 } from "node:child_process";
2599
- import { closeSync as closeSync2, openSync as openSync2, readdirSync as readdirSync4, readFileSync as readFileSync5, readSync as readSync2, statSync as statSync5 } from "node:fs";
2636
+ import { closeSync as closeSync2, openSync as openSync2, readdirSync as readdirSync4, readFileSync as readFileSync6, readSync as readSync2, statSync as statSync5 } from "node:fs";
2600
2637
  import os5 from "node:os";
2601
2638
  import path10 from "node:path";
2602
2639
 
@@ -3268,11 +3305,12 @@ function parseAuthStatus(stdout) {
3268
3305
  }
3269
3306
  }
3270
3307
  function claudeLogin2(bin, configDir, env = process.env) {
3308
+ const c = probe(bin, ["auth", "status", "--json"]);
3271
3309
  return new Promise((resolve) => {
3272
3310
  execFile(
3273
- bin,
3274
- ["auth", "status", "--json"],
3275
- { encoding: "utf8", timeout: 2e4, env: claudeEnv(configDir, env), maxBuffer: 256 * 1024 },
3311
+ c.file,
3312
+ c.args,
3313
+ { encoding: "utf8", timeout: 2e4, env: claudeEnv(configDir, env), maxBuffer: 256 * 1024, shell: c.shell },
3276
3314
  // `auth status` may exit non-zero when signed out; its JSON still says so.
3277
3315
  (_err, stdout) => resolve(parseAuthStatus(stdout))
3278
3316
  );
@@ -3292,13 +3330,15 @@ function loginHint(configDir, platform = process.platform) {
3292
3330
  }
3293
3331
  function detectCaps(bin) {
3294
3332
  let help2 = "";
3333
+ const c = probe(bin, ["--help"]);
3295
3334
  try {
3296
- help2 = execFileSync3(bin, ["--help"], {
3335
+ help2 = execFileSync3(c.file, c.args, {
3297
3336
  encoding: "utf8",
3298
3337
  timeout: 3e4,
3299
3338
  env: claudeEnv(),
3300
3339
  stdio: ["ignore", "pipe", "pipe"],
3301
- maxBuffer: 4 * 1024 * 1024
3340
+ maxBuffer: 4 * 1024 * 1024,
3341
+ shell: c.shell
3302
3342
  });
3303
3343
  } catch (e) {
3304
3344
  help2 = String(e?.stdout || "");
@@ -3405,7 +3445,7 @@ function liveProcess(session, configDir) {
3405
3445
  }
3406
3446
  for (const n of names) {
3407
3447
  try {
3408
- const j = JSON.parse(readFileSync5(path10.join(configDir, "sessions", n), "utf8"));
3448
+ const j = JSON.parse(readFileSync6(path10.join(configDir, "sessions", n), "utf8"));
3409
3449
  if (String(j.sessionId) !== session) continue;
3410
3450
  if (pidAlive(Number(j.pid ?? n.slice(0, -5)))) return true;
3411
3451
  } catch {
@@ -3453,7 +3493,7 @@ function parseResult(stdout) {
3453
3493
  var isUuid = (s) => typeof s === "string" && UUID_RE3.test(s);
3454
3494
 
3455
3495
  // ../core/src/adapters/codex.ts
3456
- import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "node:fs";
3496
+ import { existsSync as existsSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "node:fs";
3457
3497
  import path11 from "node:path";
3458
3498
 
3459
3499
  // ../core/src/adapters/codex-config.ts
@@ -3610,7 +3650,7 @@ function installNotify(cmd, env) {
3610
3650
  const file = configFile2(env);
3611
3651
  let text = "";
3612
3652
  try {
3613
- text = readFileSync6(file, "utf8");
3653
+ text = readFileSync7(file, "utf8");
3614
3654
  } catch {
3615
3655
  }
3616
3656
  const argv = cmd([NAME3, "notify"]).argv;
@@ -3656,7 +3696,7 @@ function uninstallNotify(env) {
3656
3696
  const file = configFile2(env);
3657
3697
  let text;
3658
3698
  try {
3659
- text = readFileSync6(file, "utf8");
3699
+ text = readFileSync7(file, "utf8");
3660
3700
  } catch {
3661
3701
  return { file, changed: false };
3662
3702
  }
@@ -3728,7 +3768,7 @@ var codex = {
3728
3768
  ];
3729
3769
  let text = "";
3730
3770
  try {
3731
- text = readFileSync6(configFile2(env), "utf8");
3771
+ text = readFileSync7(configFile2(env), "utf8");
3732
3772
  } catch {
3733
3773
  }
3734
3774
  const n = readNotify(text);
@@ -3855,7 +3895,7 @@ var codex = {
3855
3895
  readTranscript(file, fromLine) {
3856
3896
  let text = "";
3857
3897
  try {
3858
- text = readFileSync6(file, "utf8");
3898
+ text = readFileSync7(file, "utf8");
3859
3899
  } catch {
3860
3900
  return { turns: [], line: fromLine };
3861
3901
  }
@@ -3972,7 +4012,7 @@ __export(codex_control_exports, {
3972
4012
  reading: () => reading2
3973
4013
  });
3974
4014
  import { execFile as execFile2 } from "node:child_process";
3975
- import { readFileSync as readFileSync7 } from "node:fs";
4015
+ import { readFileSync as readFileSync8 } from "node:fs";
3976
4016
  import os6 from "node:os";
3977
4017
  import path12 from "node:path";
3978
4018
  var LABEL2 = "Codex";
@@ -4018,7 +4058,7 @@ function codexArgs(o) {
4018
4058
  function codexModels(env = process.env, home = os6.homedir()) {
4019
4059
  try {
4020
4060
  const file = path12.join(env.CODEX_HOME || path12.join(home, ".codex"), "models_cache.json");
4021
- const j = JSON.parse(readFileSync7(file, "utf8"));
4061
+ const j = JSON.parse(readFileSync8(file, "utf8"));
4022
4062
  if (!Array.isArray(j.models)) return [];
4023
4063
  const out2 = [];
4024
4064
  for (const m of j.models)
@@ -4034,11 +4074,12 @@ var codexEnv = (env = process.env) => jobEnv(env);
4034
4074
  var LOGIN_HINT = "Codex isn't signed in on this machine: run `codex login --device-auth` there.";
4035
4075
  function codexLogin(bin, env = process.env) {
4036
4076
  if (env.CODEX_API_KEY) return Promise.resolve({ loggedIn: true, method: "api key" });
4077
+ const c = probe(bin, ["login", "status"]);
4037
4078
  return new Promise((resolve) => {
4038
4079
  execFile2(
4039
- bin,
4040
- ["login", "status"],
4041
- { encoding: "utf8", timeout: 2e4, env: codexEnv(env), maxBuffer: 256 * 1024 },
4080
+ c.file,
4081
+ c.args,
4082
+ { encoding: "utf8", timeout: 2e4, env: codexEnv(env), maxBuffer: 256 * 1024, shell: c.shell },
4042
4083
  (err) => {
4043
4084
  if (!err) return resolve({ loggedIn: true });
4044
4085
  const code = err.code;
@@ -4543,7 +4584,7 @@ function devinAccount(env = process.env) {
4543
4584
 
4544
4585
  // ../core/src/adapters/gemini-cli.ts
4545
4586
  import { execFileSync as execFileSync5 } from "node:child_process";
4546
- import { existsSync as existsSync7, readFileSync as readFileSync8 } from "node:fs";
4587
+ import { existsSync as existsSync7, readFileSync as readFileSync9 } from "node:fs";
4547
4588
  import path14 from "node:path";
4548
4589
  var NAME5 = "gemini-cli";
4549
4590
  var GEMINI_EVENTS = [
@@ -4565,14 +4606,14 @@ function geminiVersion(platform = process.platform, env = process.env) {
4565
4606
  const win = platform === "win32";
4566
4607
  const bin = win ? findBinary({ names: ["gemini.exe", "gemini.cmd"], dirs: [path14.dirname(process.execPath)], env }) : "gemini";
4567
4608
  if (!bin) throw new Error("no gemini on PATH");
4568
- const o = {
4609
+ const c = probe(bin, ["--version"]);
4610
+ return execFileSync5(c.file, c.args, {
4569
4611
  encoding: "utf8",
4570
4612
  timeout: 4e3,
4571
4613
  stdio: ["ignore", "pipe", "ignore"],
4572
- env
4573
- };
4574
- const out2 = /\.cmd$/i.test(bin) ? execFileSync5(`"${bin}" --version`, { ...o, shell: true }) : execFileSync5(bin, ["--version"], o);
4575
- return out2.trim();
4614
+ env,
4615
+ shell: c.shell
4616
+ }).trim();
4576
4617
  }
4577
4618
  function geminiHooksActive(settingsFile) {
4578
4619
  const tools = readJson(settingsFile).tools;
@@ -4697,7 +4738,7 @@ var geminiCli = {
4697
4738
  readTranscript(file, fromLine) {
4698
4739
  let text = "";
4699
4740
  try {
4700
- text = readFileSync8(file, "utf8");
4741
+ text = readFileSync9(file, "utf8");
4701
4742
  } catch {
4702
4743
  return { turns: [], line: fromLine };
4703
4744
  }
@@ -4746,12 +4787,12 @@ function drivableHarnesses(env = process.env) {
4746
4787
  }
4747
4788
 
4748
4789
  // ../core/src/config.ts
4749
- import { chmodSync, existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync9, writeFileSync as writeFileSync5 } from "node:fs";
4790
+ import { chmodSync, existsSync as existsSync8, mkdirSync as mkdirSync4, readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "node:fs";
4750
4791
  import path15 from "node:path";
4751
4792
  var DEFAULT_CONFIG = { sinks: [], harnesses: {}, update_check: true, keep_days: 30 };
4752
4793
  function readConfig(file = configFile()) {
4753
4794
  try {
4754
- const j = JSON.parse(readFileSync9(file, "utf8"));
4795
+ const j = JSON.parse(readFileSync10(file, "utf8"));
4755
4796
  return {
4756
4797
  ...DEFAULT_CONFIG,
4757
4798
  ...j,
@@ -4851,7 +4892,7 @@ import {
4851
4892
  mkdirSync as mkdirSync5,
4852
4893
  openSync as openSync3,
4853
4894
  readdirSync as readdirSync6,
4854
- readFileSync as readFileSync10,
4895
+ readFileSync as readFileSync11,
4855
4896
  readSync as readSync3,
4856
4897
  renameSync,
4857
4898
  statSync as statSync6,
@@ -4881,7 +4922,7 @@ var Outbox = class {
4881
4922
  const f = this.seqFile(ref);
4882
4923
  let n = -1;
4883
4924
  try {
4884
- const t = readFileSync10(f, "utf8").trim();
4925
+ const t = readFileSync11(f, "utf8").trim();
4885
4926
  if (/^\d+$/.test(t)) n = Number(t);
4886
4927
  } catch {
4887
4928
  }
@@ -4893,7 +4934,7 @@ var Outbox = class {
4893
4934
  lastSeqInFile(ref) {
4894
4935
  const f = this.file(ref);
4895
4936
  if (!existsSync9(f)) return -1;
4896
- const lines = readFileSync10(f, "utf8").trim().split("\n");
4937
+ const lines = readFileSync11(f, "utf8").trim().split("\n");
4897
4938
  for (let i = lines.length - 1; i >= 0; i--) {
4898
4939
  try {
4899
4940
  const j = JSON.parse(lines[i]);
@@ -5016,7 +5057,7 @@ var Cursors = class {
5016
5057
  }
5017
5058
  read() {
5018
5059
  try {
5019
- return JSON.parse(readFileSync10(this.file(), "utf8"));
5060
+ return JSON.parse(readFileSync11(this.file(), "utf8"));
5020
5061
  } catch {
5021
5062
  return {};
5022
5063
  }
@@ -5040,7 +5081,7 @@ function takeNamedLock(root, name, staleMs = 5 * 6e4) {
5040
5081
  mkdirSync5(dir, { recursive: true, mode: 448 });
5041
5082
  const f = path16.join(dir, `${name}.lock`);
5042
5083
  try {
5043
- if (Date.now() - statSync6(f).mtimeMs > staleMs || !processAlive(Number(readFileSync10(f, "utf8")))) unlinkSync3(f);
5084
+ if (Date.now() - statSync6(f).mtimeMs > staleMs || !processAlive(Number(readFileSync11(f, "utf8")))) unlinkSync3(f);
5044
5085
  else return null;
5045
5086
  } catch {
5046
5087
  }
@@ -5466,7 +5507,7 @@ function connectTier(flag2, current) {
5466
5507
  }
5467
5508
 
5468
5509
  // src/control/autoupdate.ts
5469
- import { readFileSync as readFileSync16 } from "node:fs";
5510
+ import { readFileSync as readFileSync17 } from "node:fs";
5470
5511
  import path26 from "node:path";
5471
5512
 
5472
5513
  // src/update.ts
@@ -5476,12 +5517,12 @@ import path25 from "node:path";
5476
5517
 
5477
5518
  // src/runtime.ts
5478
5519
  import { execFileSync as execFileSync6 } from "node:child_process";
5479
- import { readFileSync as readFileSync15, realpathSync as realpathSync2 } from "node:fs";
5520
+ import { readFileSync as readFileSync16, realpathSync as realpathSync2 } from "node:fs";
5480
5521
  import os10 from "node:os";
5481
5522
  import path24 from "node:path";
5482
5523
 
5483
5524
  // src/launcher.ts
5484
- import { accessSync as accessSync2, chmodSync as chmodSync2, constants as constants2, mkdirSync as mkdirSync7, readFileSync as readFileSync11, renameSync as renameSync2, rmSync, writeFileSync as writeFileSync7 } from "node:fs";
5525
+ import { accessSync as accessSync2, chmodSync as chmodSync2, constants as constants2, mkdirSync as mkdirSync7, readFileSync as readFileSync12, renameSync as renameSync2, rmSync, writeFileSync as writeFileSync7 } from "node:fs";
5485
5526
  import os7 from "node:os";
5486
5527
  import path19 from "node:path";
5487
5528
  var LAUNCHER = "sessionpipe-hook";
@@ -5505,7 +5546,7 @@ exec "$n" ${sq(hook)} "$@"
5505
5546
  }
5506
5547
  function writeIfChanged(file, body, mode) {
5507
5548
  try {
5508
- const cur = readFileSync11(file);
5549
+ const cur = readFileSync12(file);
5509
5550
  if (cur.equals(Buffer.isBuffer(body) ? body : Buffer.from(body))) {
5510
5551
  chmodSync2(file, mode);
5511
5552
  return false;
@@ -5523,7 +5564,7 @@ function installLauncher(o) {
5523
5564
  mkdirSync7(dir, { recursive: true, mode: 493 });
5524
5565
  let changed = false;
5525
5566
  for (const f of COPIED)
5526
- changed = writeIfChanged(path19.join(dir, f), readFileSync11(path19.join(o.distDir, f)), 420) || changed;
5567
+ changed = writeIfChanged(path19.join(dir, f), readFileSync12(path19.join(o.distDir, f)), 420) || changed;
5527
5568
  const launcher = path19.join(dir, LAUNCHER);
5528
5569
  changed = writeIfChanged(launcher, launcherScript(o.node, path19.join(dir, "hook.js"), o.version), 493) || changed;
5529
5570
  return { launcher, changed };
@@ -5535,7 +5576,7 @@ function launcherState(version, env = process.env) {
5535
5576
  const file = launcherPath(env);
5536
5577
  let text = "";
5537
5578
  try {
5538
- text = readFileSync11(file, "utf8");
5579
+ text = readFileSync12(file, "utf8");
5539
5580
  } catch {
5540
5581
  return {
5541
5582
  file,
@@ -5580,7 +5621,7 @@ import {
5580
5621
  existsSync as existsSync11,
5581
5622
  mkdirSync as mkdirSync10,
5582
5623
  readdirSync as readdirSync7,
5583
- readFileSync as readFileSync14,
5624
+ readFileSync as readFileSync15,
5584
5625
  renameSync as renameSync5,
5585
5626
  statSync as statSync7,
5586
5627
  unlinkSync as unlinkSync4,
@@ -5590,7 +5631,7 @@ import os9 from "node:os";
5590
5631
  import path23 from "node:path";
5591
5632
 
5592
5633
  // src/control/aliases.ts
5593
- import { chmodSync as chmodSync4, mkdirSync as mkdirSync9, readFileSync as readFileSync13, renameSync as renameSync4, writeFileSync as writeFileSync9 } from "node:fs";
5634
+ import { chmodSync as chmodSync4, mkdirSync as mkdirSync9, readFileSync as readFileSync14, renameSync as renameSync4, writeFileSync as writeFileSync9 } from "node:fs";
5594
5635
  import path21 from "node:path";
5595
5636
 
5596
5637
  // src/control/store.ts
@@ -5602,7 +5643,7 @@ import {
5602
5643
  fsyncSync,
5603
5644
  mkdirSync as mkdirSync8,
5604
5645
  openSync as openSync4,
5605
- readFileSync as readFileSync12,
5646
+ readFileSync as readFileSync13,
5606
5647
  renameSync as renameSync3,
5607
5648
  writeFileSync as writeFileSync8
5608
5649
  } from "node:fs";
@@ -5652,7 +5693,7 @@ function secretDel(store, account, run = defaultRunner) {
5652
5693
  if (store === "keychain") run("security", ["delete-generic-password", "-s", SERVICE2, "-a", account]);
5653
5694
  else run("secret-tool", ["clear", "service", SERVICE2, "account", account]);
5654
5695
  }
5655
- function probe(store, run = defaultRunner) {
5696
+ function probe2(store, run = defaultRunner) {
5656
5697
  const account = `probe:${randomBytes3(6).toString("hex")}`;
5657
5698
  const ok = secretSet(store, account, randomBytes3(12).toString("base64url"), run);
5658
5699
  secretDel(store, account, run);
@@ -5662,7 +5703,7 @@ function bestStore(env = process.env, platform = process.platform, run = default
5662
5703
  const want = env.SESSIONPIPE_SECRETS;
5663
5704
  if (want === "file") return "file";
5664
5705
  const candidates = want === "keychain" || want === "secret-service" ? [want] : platform === "darwin" ? ["keychain"] : platform === "linux" && env.DBUS_SESSION_BUS_ADDRESS && (env.DISPLAY || env.WAYLAND_DISPLAY) ? ["secret-service"] : [];
5665
- for (const s of candidates) if (probe(s, run)) return s;
5706
+ for (const s of candidates) if (probe2(s, run)) return s;
5666
5707
  return "file";
5667
5708
  }
5668
5709
  var storeLabel = (s) => s === "keychain" ? "the macOS Keychain" : s === "secret-service" ? "the Secret Service keyring" : "a 0600 file";
@@ -5739,7 +5780,7 @@ function writePrivate(file, value) {
5739
5780
  }
5740
5781
  function readControl(env = process.env, run = defaultRunner) {
5741
5782
  try {
5742
- const j = JSON.parse(readFileSync12(controlFile(env), "utf8"));
5783
+ const j = JSON.parse(readFileSync13(controlFile(env), "utf8"));
5743
5784
  if (!j || !Array.isArray(j.receivers)) return null;
5744
5785
  return {
5745
5786
  name: j.name || "machine",
@@ -5756,7 +5797,7 @@ function readControl(env = process.env, run = defaultRunner) {
5756
5797
  }
5757
5798
  function pairedCount(env = process.env) {
5758
5799
  try {
5759
- const j = JSON.parse(readFileSync12(controlFile(env), "utf8"));
5800
+ const j = JSON.parse(readFileSync13(controlFile(env), "utf8"));
5760
5801
  return Array.isArray(j.receivers) ? j.receivers.length : 0;
5761
5802
  } catch {
5762
5803
  return 0;
@@ -5806,7 +5847,7 @@ var NonceStore = class {
5806
5847
  this.now = now;
5807
5848
  let raw = "";
5808
5849
  try {
5809
- raw = readFileSync12(file, "utf8");
5850
+ raw = readFileSync13(file, "utf8");
5810
5851
  } catch {
5811
5852
  }
5812
5853
  const cut2 = this.now() - NONCE_TTL_MS;
@@ -5869,7 +5910,7 @@ var AckOutbox = class {
5869
5910
  file;
5870
5911
  all() {
5871
5912
  try {
5872
- return readFileSync12(this.file, "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l));
5913
+ return readFileSync13(this.file, "utf8").split("\n").filter(Boolean).map((l) => JSON.parse(l));
5873
5914
  } catch {
5874
5915
  return [];
5875
5916
  }
@@ -5889,7 +5930,7 @@ var AckOutbox = class {
5889
5930
  };
5890
5931
  function readState(file) {
5891
5932
  try {
5892
- const j = JSON.parse(readFileSync12(file, "utf8"));
5933
+ const j = JSON.parse(readFileSync13(file, "utf8"));
5893
5934
  const started = {};
5894
5935
  if (j.started && typeof j.started === "object")
5895
5936
  for (const [k, v] of Object.entries(j.started)) {
@@ -5907,7 +5948,7 @@ var writeState = (file, s) => writePrivate(file, s);
5907
5948
  var aliasFile = (controlDir) => path21.join(controlDir, "aliases.json");
5908
5949
  function readAliases(file) {
5909
5950
  try {
5910
- const j = JSON.parse(readFileSync13(file, "utf8"));
5951
+ const j = JSON.parse(readFileSync14(file, "utf8"));
5911
5952
  if (!j || typeof j !== "object" || Array.isArray(j)) return {};
5912
5953
  const out2 = {};
5913
5954
  for (const [k, v] of Object.entries(j)) {
@@ -6087,7 +6128,7 @@ async function tellDaemon(state2, job, session, cwd, transcript) {
6087
6128
  300
6088
6129
  );
6089
6130
  }
6090
- var VERSION = true ? "0.11.0" : "0.0.0";
6131
+ var VERSION = true ? "0.12.0" : "0.0.0";
6091
6132
  function enqueueJob(state2, job) {
6092
6133
  const jobs = jobsDir(state2);
6093
6134
  mkdirSync10(jobs, { recursive: true, mode: 448 });
@@ -6120,7 +6161,7 @@ function factsState(state2) {
6120
6161
  return {
6121
6162
  get(h, s) {
6122
6163
  try {
6123
- return JSON.parse(readFileSync14(file(h, s), "utf8"));
6164
+ return JSON.parse(readFileSync15(file(h, s), "utf8"));
6124
6165
  } catch {
6125
6166
  return {};
6126
6167
  }
@@ -6422,7 +6463,7 @@ var BACKOFF_MS = [2e3, 1e4, 6e4, 5 * 6e4, 30 * 6e4];
6422
6463
  var backoffFile = (state2, sink2) => path23.join(state2, "backoff", `${safeId(sink2)}.json`);
6423
6464
  function readBackoff(state2, sink2) {
6424
6465
  try {
6425
- const b = JSON.parse(readFileSync14(backoffFile(state2, sink2), "utf8"));
6466
+ const b = JSON.parse(readFileSync15(backoffFile(state2, sink2), "utf8"));
6426
6467
  return typeof b.until === "number" ? b : null;
6427
6468
  } catch {
6428
6469
  return null;
@@ -6628,7 +6669,7 @@ function assertSetupVersion(allowDowngrade, target2) {
6628
6669
  );
6629
6670
  let installed;
6630
6671
  try {
6631
- installed = JSON.parse(readFileSync15(pkg, "utf8")).version;
6672
+ installed = JSON.parse(readFileSync16(pkg, "utf8")).version;
6632
6673
  } catch {
6633
6674
  }
6634
6675
  if (typeof installed === "string") check(installed, pkg);
@@ -6861,7 +6902,7 @@ var UNIT = "sessionpipe-control.service";
6861
6902
  var updateFile = (env = process.env) => path26.join(controlState(env), "update.json");
6862
6903
  function readUpdate(file) {
6863
6904
  try {
6864
- const j = JSON.parse(readFileSync16(file, "utf8"));
6905
+ const j = JSON.parse(readFileSync17(file, "utf8"));
6865
6906
  return j && typeof j === "object" ? j : {};
6866
6907
  } catch {
6867
6908
  return {};
@@ -6924,7 +6965,7 @@ function restartVia(o) {
6924
6965
  if (o.platform === "linux") {
6925
6966
  let cg = "";
6926
6967
  try {
6927
- cg = (o.cgroup ?? (() => readFileSync16("/proc/self/cgroup", "utf8")))();
6968
+ cg = (o.cgroup ?? (() => readFileSync17("/proc/self/cgroup", "utf8")))();
6928
6969
  } catch {
6929
6970
  }
6930
6971
  const inUnit = cg.split("\n").some((l) => l.endsWith(`/${UNIT}`) || l.includes(`/${UNIT}/`));
@@ -7266,7 +7307,7 @@ import {
7266
7307
  existsSync as existsSync13,
7267
7308
  lstatSync,
7268
7309
  mkdirSync as mkdirSync11,
7269
- readFileSync as readFileSync17,
7310
+ readFileSync as readFileSync18,
7270
7311
  realpathSync as realpathSync4,
7271
7312
  statSync as statSync8,
7272
7313
  unlinkSync as unlinkSync5,
@@ -7295,7 +7336,7 @@ var anySet = (env) => POOL_ENV_KEYS.some((k) => env[k] !== void 0);
7295
7336
  function readJsonFile2(file) {
7296
7337
  let raw;
7297
7338
  try {
7298
- raw = readFileSync17(file, "utf8");
7339
+ raw = readFileSync18(file, "utf8");
7299
7340
  } catch {
7300
7341
  return { ok: true, existed: false, value: {}, shape: { indent: " ", eol: "\n", finalNewline: true }, raw: "" };
7301
7342
  }
@@ -7410,7 +7451,7 @@ function uninstallPoolEnv(dirs, o) {
7410
7451
  const original = o.keep ? kept(o.keep, file) : null;
7411
7452
  let text = formatJson2(settings2, f.shape);
7412
7453
  if (original && existsSync13(original)) {
7413
- const raw = readFileSync17(original, "utf8");
7454
+ const raw = readFileSync18(original, "utf8");
7414
7455
  try {
7415
7456
  if (JSON.stringify(JSON.parse(raw)) === JSON.stringify(settings2)) text = raw;
7416
7457
  } catch {
@@ -7922,7 +7963,7 @@ function startPoolServer(deps) {
7922
7963
  }
7923
7964
 
7924
7965
  // src/pool/store.ts
7925
- import { existsSync as existsSync14, readFileSync as readFileSync18 } from "node:fs";
7966
+ import { existsSync as existsSync14, readFileSync as readFileSync19 } from "node:fs";
7926
7967
  import path28 from "node:path";
7927
7968
  var poolFile = (env = process.env) => path28.join(path28.dirname(configFile(env)), "pool.json");
7928
7969
  var poolSecretsFile = (env = process.env) => path28.join(path28.dirname(configFile(env)), "pool.secrets.json");
@@ -7931,7 +7972,7 @@ var EMPTY = { on: false, port: 0, accounts: [] };
7931
7972
  var UUID_RE5 = /^[0-9a-f-]{8,64}$/i;
7932
7973
  function readJson2(file) {
7933
7974
  try {
7934
- const j = JSON.parse(readFileSync18(file, "utf8"));
7975
+ const j = JSON.parse(readFileSync19(file, "utf8"));
7935
7976
  return j && typeof j === "object" && !Array.isArray(j) ? j : null;
7936
7977
  } catch {
7937
7978
  return null;
@@ -8033,7 +8074,7 @@ var PoolSecrets = class {
8033
8074
  return { value: typeof v === "string" && v ? v : null, unreadable: false };
8034
8075
  }
8035
8076
  const value = secretGet(where, name, this.run);
8036
- return { value, unreadable: value === null && !probe(where, this.run) };
8077
+ return { value, unreadable: value === null && !probe2(where, this.run) };
8037
8078
  }
8038
8079
  /** False when the store refused (then nothing was written anywhere). */
8039
8080
  set(cfg, name, value) {
@@ -8575,7 +8616,7 @@ function openPool(deps) {
8575
8616
  }
8576
8617
 
8577
8618
  // src/control/daemon.ts
8578
- import { chmodSync as chmodSync6, existsSync as existsSync17, mkdirSync as mkdirSync13, readFileSync as readFileSync19, realpathSync as realpathSync6, statSync as statSync10, unlinkSync as unlinkSync6 } from "node:fs";
8619
+ import { chmodSync as chmodSync6, existsSync as existsSync17, mkdirSync as mkdirSync13, readFileSync as readFileSync20, realpathSync as realpathSync6, statSync as statSync10, unlinkSync as unlinkSync6 } from "node:fs";
8579
8620
  import net3 from "node:net";
8580
8621
  import path31 from "node:path";
8581
8622
 
@@ -8979,7 +9020,7 @@ function startNamed(cmd) {
8979
9020
  return null;
8980
9021
  }
8981
9022
  }
8982
- var VERSION2 = true ? "0.11.0" : "0.0.0";
9023
+ var VERSION2 = true ? "0.12.0" : "0.0.0";
8983
9024
  var MAX_REPLY = 2e4;
8984
9025
  var HELLO_EVERY_MS = 10 * 6e4;
8985
9026
  var TURN_FALLBACK_MS = 30 * 6e4;
@@ -9841,7 +9882,7 @@ ${IN_PLACE_ANSWER}`, id: p.msgId });
9841
9882
  factsCwd(harness, id) {
9842
9883
  try {
9843
9884
  const f = path31.join(path31.dirname(this.dir), "facts", safeId(harness), `${safeId(id)}.json`);
9844
- const cwd = JSON.parse(readFileSync19(f, "utf8")).cwd;
9885
+ const cwd = JSON.parse(readFileSync20(f, "utf8")).cwd;
9845
9886
  return typeof cwd === "string" && path31.isAbsolute(cwd) ? cwd : void 0;
9846
9887
  } catch {
9847
9888
  return void 0;
@@ -10927,7 +10968,7 @@ function uninstallService(o) {
10927
10968
  }
10928
10969
 
10929
10970
  // src/control/pair.ts
10930
- var VERSION3 = true ? "0.11.0" : "0.0.0";
10971
+ var VERSION3 = true ? "0.12.0" : "0.0.0";
10931
10972
  var RENEW_FOR_MS = 60 * 6e4;
10932
10973
  async function json(r) {
10933
10974
  try {
@@ -12772,7 +12813,7 @@ function hookWall(runs = 8) {
12772
12813
  }
12773
12814
  function timing() {
12774
12815
  try {
12775
- const lines = readFileSync20(path36.join(state, "timing.jsonl"), "utf8").trim().split("\n").slice(-100);
12816
+ const lines = readFileSync21(path36.join(state, "timing.jsonl"), "utf8").trim().split("\n").slice(-100);
12776
12817
  const ms2 = lines.map((l) => JSON.parse(l).ms).filter((x) => x >= 0).sort((a, b) => a - b);
12777
12818
  if (!ms2.length) return null;
12778
12819
  const q = (p) => Math.round(
@@ -13019,7 +13060,7 @@ async function tail() {
13019
13060
  async function workerFromArgv() {
13020
13061
  const f = args[1];
13021
13062
  if (!f) return;
13022
- const job = JSON.parse(readFileSync20(f, "utf8"));
13063
+ const job = JSON.parse(readFileSync21(f, "utf8"));
13023
13064
  try {
13024
13065
  unlinkSync8(f);
13025
13066
  } catch {