@integrity-labs/agt-cli 0.28.762 → 0.28.764

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.
Files changed (24) hide show
  1. package/dist/bin/agt.js +5 -5
  2. package/dist/{chunk-L4KDOGHB.js → chunk-23KTLVYX.js} +15 -1
  3. package/dist/{chunk-L4KDOGHB.js.map → chunk-23KTLVYX.js.map} +1 -1
  4. package/dist/{chunk-EU6RSU5V.js → chunk-LVBINNTQ.js} +157 -40
  5. package/dist/chunk-LVBINNTQ.js.map +1 -0
  6. package/dist/{chunk-BTED7TYA.js → chunk-SMY25FCN.js} +70 -27
  7. package/dist/{chunk-BTED7TYA.js.map → chunk-SMY25FCN.js.map} +1 -1
  8. package/dist/{claude-pair-runtime-5CKIB2IM.js → claude-pair-runtime-U6WDTNK3.js} +2 -2
  9. package/dist/lib/manager-worker.js +65 -65
  10. package/dist/lib/manager-worker.js.map +1 -1
  11. package/dist/mcp/direct-chat-channel.js +14 -0
  12. package/dist/mcp/index.js +14 -0
  13. package/dist/mcp/origami.js +14 -0
  14. package/dist/mcp/slack-channel.js +14 -0
  15. package/dist/mcp/telegram-channel.js +14 -0
  16. package/dist/{persistent-session-VS44QKVB.js → persistent-session-3OBDKYWF.js} +3 -3
  17. package/dist/{responsiveness-probe-CNSUJALX.js → responsiveness-probe-ULIAXSCT.js} +3 -3
  18. package/dist/{session-auth-dead-3AK3MDNT.js → session-auth-dead-67XFJWMA.js} +2 -2
  19. package/package.json +1 -1
  20. package/dist/chunk-EU6RSU5V.js.map +0 -1
  21. /package/dist/{claude-pair-runtime-5CKIB2IM.js.map → claude-pair-runtime-U6WDTNK3.js.map} +0 -0
  22. /package/dist/{persistent-session-VS44QKVB.js.map → persistent-session-3OBDKYWF.js.map} +0 -0
  23. /package/dist/{responsiveness-probe-CNSUJALX.js.map → responsiveness-probe-ULIAXSCT.js.map} +0 -0
  24. /package/dist/{session-auth-dead-3AK3MDNT.js.map → session-auth-dead-67XFJWMA.js.map} +0 -0
@@ -18,13 +18,122 @@ import {
18
18
  rotateDailySession,
19
19
  sessionFileExists,
20
20
  todayLocalIso
21
- } from "./chunk-L4KDOGHB.js";
21
+ } from "./chunk-23KTLVYX.js";
22
22
  import {
23
23
  reapOrphanChannelMcps
24
24
  } from "./chunk-XWVM4KPK.js";
25
25
 
26
26
  // src/lib/persistent-session.ts
27
- import { spawn as spawn2, execSync as execSync2, execFileSync as execFileSync3 } from "child_process";
27
+ import { spawn as spawn2, execSync as execSync2, execFileSync as execFileSync4 } from "child_process";
28
+
29
+ // src/lib/bounded-exec.ts
30
+ import { execFileSync } from "child_process";
31
+ var TIMEOUT_EXIT_DEADLINE = 124;
32
+ var TIMEOUT_EXIT_KILLED = 137;
33
+ var TIMEOUT_EXIT_CANNOT_RUN = 126;
34
+ var TIMEOUT_EXIT_NOT_FOUND = 127;
35
+ var DEFAULT_KILL_AFTER_MS = 2e3;
36
+ var MIN_DURATION_MS = 1;
37
+ var timeoutBinaryProbe = null;
38
+ var warnedNoTimeoutBinary = false;
39
+ var warnedInvalidDuration = false;
40
+ function hasTimeoutBinary(exec) {
41
+ if (timeoutBinaryProbe !== null) return timeoutBinaryProbe;
42
+ try {
43
+ exec("timeout", ["--version"], { timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] });
44
+ timeoutBinaryProbe = true;
45
+ } catch {
46
+ timeoutBinaryProbe = false;
47
+ }
48
+ return timeoutBinaryProbe;
49
+ }
50
+ function toTimeoutArg(ms) {
51
+ return `${(ms / 1e3).toFixed(3)}s`;
52
+ }
53
+ function invalidDuration(name, ms) {
54
+ if (Number.isFinite(ms) && ms >= MIN_DURATION_MS) return null;
55
+ return `[bounded-exec] refusing to run: ${name}=${String(ms)} is not a usable deadline (needs a finite value >= ${MIN_DURATION_MS}ms). A zero or sub-millisecond duration DISABLES the deadline or the SIGKILL escalation, which would leave this call unbounded while reporting that it was bounded (ENG-9781).`;
56
+ }
57
+ function hardBoundedExecFile(file, args, opts) {
58
+ const exec = opts.exec ?? execFileSync;
59
+ const killAfterMs = opts.killAfterMs ?? DEFAULT_KILL_AFTER_MS;
60
+ const log2 = opts.log;
61
+ const badDuration = invalidDuration("timeoutMs", opts.timeoutMs) ?? invalidDuration("killAfterMs", killAfterMs);
62
+ if (badDuration) {
63
+ if (!warnedInvalidDuration) {
64
+ warnedInvalidDuration = true;
65
+ (log2 ?? ((m) => console.warn(m)))(badDuration);
66
+ }
67
+ return { kind: "failed", status: null, message: badDuration, bounded: false };
68
+ }
69
+ const available = opts.timeoutBinaryAvailable ? opts.timeoutBinaryAvailable() : hasTimeoutBinary(exec);
70
+ if (!available && !warnedNoTimeoutBinary) {
71
+ warnedNoTimeoutBinary = true;
72
+ (log2 ?? ((m) => console.warn(m)))(
73
+ `[bounded-exec] coreutils 'timeout' not found \u2014 subprocess calls on the manager's critical path are running UNBOUNDED. A wedged '${file}' can block the event loop for every agent on this host (ENG-9781).`
74
+ );
75
+ }
76
+ const nodeTimeoutMs = available ? opts.timeoutMs + killAfterMs + 5e3 : opts.timeoutMs;
77
+ const execFile = available ? "timeout" : file;
78
+ const execArgs = available ? [
79
+ "--signal=TERM",
80
+ `--kill-after=${toTimeoutArg(killAfterMs)}`,
81
+ toTimeoutArg(opts.timeoutMs),
82
+ file,
83
+ ...args
84
+ ] : [...args];
85
+ const now = opts.now ?? (() => performance.now());
86
+ const startedAt = now();
87
+ try {
88
+ const stdout = exec(execFile, execArgs, {
89
+ encoding: "utf-8",
90
+ timeout: nodeTimeoutMs,
91
+ maxBuffer: opts.maxBuffer,
92
+ // stderr is CAPTURED rather than discarded: it is the only place the
93
+ // command says why it failed, and a reaper that logs "docker exec failed"
94
+ // with no reason is the kind of line that costs an hour at 3am.
95
+ stdio: ["ignore", "pipe", "pipe"]
96
+ });
97
+ return { kind: "ok", stdout: String(stdout ?? ""), bounded: available };
98
+ } catch (err) {
99
+ const e = err;
100
+ const status = e?.status ?? null;
101
+ const elapsedMs = now() - startedAt;
102
+ if (available && status === TIMEOUT_EXIT_KILLED) {
103
+ return { kind: "timed-out", bounded: true };
104
+ }
105
+ if (available && status === TIMEOUT_EXIT_DEADLINE && elapsedMs >= opts.timeoutMs) {
106
+ return { kind: "timed-out", bounded: true };
107
+ }
108
+ if (e?.code === "ETIMEDOUT" || e?.signal === "SIGTERM" || e?.signal === "SIGKILL") {
109
+ return { kind: "timed-out", bounded: available };
110
+ }
111
+ const stderr = String(e?.stderr ?? "").trim();
112
+ if (available && (status === TIMEOUT_EXIT_CANNOT_RUN || status === TIMEOUT_EXIT_NOT_FOUND) && /^timeout:/m.test(stderr)) {
113
+ return {
114
+ kind: "failed",
115
+ status: null,
116
+ message: `timeout could not run '${file}' (wrapper exit ${status}): ${stderr}`,
117
+ bounded: true,
118
+ notFound: status === TIMEOUT_EXIT_NOT_FOUND
119
+ };
120
+ }
121
+ const base = e?.message ?? String(err);
122
+ return {
123
+ kind: "failed",
124
+ status,
125
+ message: stderr ? `${base}: ${stderr}` : base,
126
+ bounded: available,
127
+ notFound: e?.code === "ENOENT"
128
+ };
129
+ }
130
+ }
131
+ function hardBoundedCapture(file, args, opts) {
132
+ const r = hardBoundedExecFile(file, args, opts);
133
+ return r.kind === "ok" ? r.stdout : null;
134
+ }
135
+
136
+ // src/lib/persistent-session.ts
28
137
  import { join as join6, dirname as dirname5 } from "path";
29
138
  import { homedir as homedir5, platform, userInfo as userInfo2 } from "os";
30
139
  import { existsSync as existsSync5, readFileSync as readFileSync6, readdirSync as readdirSync2, writeFileSync as writeFileSync4, appendFileSync as appendFileSync2, mkdirSync as mkdirSync5, chmodSync as chmodSync3, copyFileSync, rmSync as rmSync3, lstatSync as lstatSync3, realpathSync as realpathSync2, renameSync as renameSync2, statSync } from "fs";
@@ -2501,7 +2610,7 @@ function readAgentIntegrationsEnv(codeName, dir) {
2501
2610
  import { randomUUID } from "crypto";
2502
2611
 
2503
2612
  // ../../packages/core/dist/runtime/session-probe.js
2504
- import { execFileSync } from "child_process";
2613
+ import { execFileSync as execFileSync2 } from "child_process";
2505
2614
  function escapePgrepRegex(value) {
2506
2615
  return value.replace(/[.[\]{}()*+?^$|\\]/g, "\\$&");
2507
2616
  }
@@ -2509,7 +2618,7 @@ function probeClaudeProcessInTmux(tmuxSession) {
2509
2618
  const escapedSession = escapePgrepRegex(tmuxSession);
2510
2619
  const pattern = `(^|[[:space:]])--name ${escapedSession}([[:space:]]|$)`;
2511
2620
  try {
2512
- const out = execFileSync("pgrep", ["-f", "--", pattern], {
2621
+ const out = execFileSync2("pgrep", ["-f", "--", pattern], {
2513
2622
  encoding: "utf-8",
2514
2623
  timeout: 3e3
2515
2624
  }).trim();
@@ -2616,7 +2725,7 @@ function describeError(err) {
2616
2725
  }
2617
2726
 
2618
2727
  // src/lib/claude-dialogs.ts
2619
- import { execFileSync as execFileSync2 } from "child_process";
2728
+ import { execFileSync as execFileSync3 } from "child_process";
2620
2729
  function isLoginPickerVisible(screen) {
2621
2730
  return screen.includes("Select login method") || screen.includes("Claude account with subscription") && screen.includes("Anthropic Console account");
2622
2731
  }
@@ -2857,7 +2966,7 @@ async function sendDialogKeys(tmuxSession, action) {
2857
2966
  if (i > 0 && action.interKeyDelayMs > 0) {
2858
2967
  await new Promise((r) => setTimeout(r, action.interKeyDelayMs));
2859
2968
  }
2860
- execFileSync2("tmux", ["send-keys", "-t", tmuxSession, action.keys[i]], {
2969
+ execFileSync3("tmux", ["send-keys", "-t", tmuxSession, action.keys[i]], {
2861
2970
  stdio: "ignore"
2862
2971
  });
2863
2972
  }
@@ -3365,20 +3474,20 @@ function isolationMode(codeName) {
3365
3474
  var dockerReadinessCache = null;
3366
3475
  var isolationDegradationLogged = false;
3367
3476
  function probeDockerRuntime(image) {
3368
- try {
3369
- execFileSync3("docker", ["info"], { stdio: "ignore", timeout: 15e3 });
3370
- } catch (err) {
3371
- const code = err?.code;
3477
+ const info = hardBoundedExecFile("docker", ["info"], { timeoutMs: 15e3 });
3478
+ if (info.kind !== "ok") {
3372
3479
  return {
3373
3480
  ok: false,
3374
- reason: code === "ENOENT" ? "docker-not-installed" : "docker-daemon-unavailable"
3481
+ // A wedged daemon and a missing binary are different operational
3482
+ // problems with different fixes, and the readiness reason is what an
3483
+ // operator reads. `notFound` carries the distinction across the wrapper
3484
+ // (unwrapped ENOENT vs `timeout` exiting 127) so neither is mistaken for
3485
+ // the other.
3486
+ reason: info.kind === "failed" && info.notFound ? "docker-not-installed" : "docker-daemon-unavailable"
3375
3487
  };
3376
3488
  }
3377
- try {
3378
- execFileSync3("docker", ["image", "inspect", image], { stdio: "ignore", timeout: 15e3 });
3379
- } catch {
3380
- return { ok: false, reason: `image-missing:${image}` };
3381
- }
3489
+ const img = hardBoundedExecFile("docker", ["image", "inspect", image], { timeoutMs: 15e3 });
3490
+ if (img.kind !== "ok") return { ok: false, reason: `image-missing:${image}` };
3382
3491
  return { ok: true };
3383
3492
  }
3384
3493
  function dockerRuntimeReadiness() {
@@ -3456,7 +3565,7 @@ function isNoSuchContainer(err) {
3456
3565
  }
3457
3566
  function reloadEgressSidecar(codeName) {
3458
3567
  try {
3459
- execFileSync3("docker", ["kill", "--signal=HUP", `agt-squid-${codeName}`], {
3568
+ execFileSync4("docker", ["kill", "--signal=HUP", `agt-squid-${codeName}`], {
3460
3569
  stdio: "pipe",
3461
3570
  timeout: EGRESS_DOCKER_TIMEOUT_MS
3462
3571
  });
@@ -3468,7 +3577,7 @@ function reloadEgressSidecar(codeName) {
3468
3577
  }
3469
3578
  function restartEgressSidecar(codeName) {
3470
3579
  try {
3471
- execFileSync3("docker", ["restart", `agt-squid-${codeName}`], {
3580
+ execFileSync4("docker", ["restart", `agt-squid-${codeName}`], {
3472
3581
  stdio: "pipe",
3473
3582
  timeout: EGRESS_DOCKER_TIMEOUT_MS
3474
3583
  });
@@ -4379,7 +4488,7 @@ async function waitForPromptReady(tmuxSession) {
4379
4488
  const deadline = Date.now() + 1e4;
4380
4489
  while (Date.now() < deadline) {
4381
4490
  try {
4382
- const screen = execFileSync3(
4491
+ const screen = execFileSync4(
4383
4492
  "tmux",
4384
4493
  ["capture-pane", "-t", tmuxSession, "-p"],
4385
4494
  { encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
@@ -4398,11 +4507,11 @@ function sleepBlockingMs(ms) {
4398
4507
  }
4399
4508
  function defaultArmSender(tmuxSession, command) {
4400
4509
  try {
4401
- execFileSync3("tmux", ["send-keys", "-t", tmuxSession, "-l", command], {
4510
+ execFileSync4("tmux", ["send-keys", "-t", tmuxSession, "-l", command], {
4402
4511
  stdio: ["ignore", "ignore", "pipe"]
4403
4512
  });
4404
4513
  sleepBlockingMs(SEND_KEYS_ENTER_DELAY_MS);
4405
- execFileSync3("tmux", ["send-keys", "-t", tmuxSession, "Enter"], {
4514
+ execFileSync4("tmux", ["send-keys", "-t", tmuxSession, "Enter"], {
4406
4515
  stdio: ["ignore", "ignore", "pipe"]
4407
4516
  });
4408
4517
  return true;
@@ -4413,7 +4522,7 @@ function defaultArmSender(tmuxSession, command) {
4413
4522
  var armSender = defaultArmSender;
4414
4523
  function defaultPaneCapture(tmuxSession) {
4415
4524
  try {
4416
- return execFileSync3("tmux", ["capture-pane", "-t", tmuxSession, "-p"], {
4525
+ return execFileSync4("tmux", ["capture-pane", "-t", tmuxSession, "-p"], {
4417
4526
  encoding: "utf-8",
4418
4527
  stdio: ["ignore", "pipe", "ignore"],
4419
4528
  timeout: 2e3
@@ -4428,7 +4537,7 @@ var defaultHygieneKeySender = async (tmuxSession, keys, interKeyDelayMs) => {
4428
4537
  if (i > 0 && interKeyDelayMs > 0) {
4429
4538
  await new Promise((r) => setTimeout(r, interKeyDelayMs));
4430
4539
  }
4431
- execFileSync3("tmux", ["send-keys", "-t", tmuxSession, keys[i]], {
4540
+ execFileSync4("tmux", ["send-keys", "-t", tmuxSession, keys[i]], {
4432
4541
  stdio: "ignore"
4433
4542
  });
4434
4543
  }
@@ -4437,7 +4546,7 @@ var hygieneKeySender = defaultHygieneKeySender;
4437
4546
  var SESSION_CREATED_TIMEOUT_MS = 3e3;
4438
4547
  function defaultSessionCreatedProbe(tmuxSession) {
4439
4548
  try {
4440
- const created = execFileSync3("tmux", ["display", "-p", "-t", tmuxSession, "#{session_created}"], {
4549
+ const created = execFileSync4("tmux", ["display", "-p", "-t", tmuxSession, "#{session_created}"], {
4441
4550
  encoding: "utf-8",
4442
4551
  timeout: SESSION_CREATED_TIMEOUT_MS
4443
4552
  }).trim();
@@ -4564,7 +4673,7 @@ function stopPersistentSession(codeName, log2) {
4564
4673
  log2(`[persistent-session] Stopping session for '${codeName}'`);
4565
4674
  session.status = "stopped";
4566
4675
  try {
4567
- execFileSync3("tmux", ["kill-session", "-t", `agt-${codeName}`], { stdio: ["ignore", "ignore", "pipe"] });
4676
+ execFileSync4("tmux", ["kill-session", "-t", `agt-${codeName}`], { stdio: ["ignore", "ignore", "pipe"] });
4568
4677
  } catch (err) {
4569
4678
  const stderr = (err.stderr ?? "").toString().trim();
4570
4679
  const alreadyGone = /can't find session|no server running/i.test(stderr);
@@ -4589,17 +4698,23 @@ var pendingZombieDetections = /* @__PURE__ */ new Map();
4589
4698
  function isClaudeProcessAliveInTmux(tmuxSession) {
4590
4699
  const codeName = tmuxSession.replace(/^agt-/, "");
4591
4700
  if (effectiveIsolationMode(codeName) === "docker") {
4592
- try {
4593
- const out = execFileSync3("docker", ["exec", `agt-${codeName}`, "pgrep", "-f", "claude"], {
4594
- encoding: "utf-8",
4595
- timeout: 8e3
4596
- }).trim();
4597
- return out.length > 0;
4598
- } catch (err) {
4599
- const e = err;
4600
- if (e?.status === 1 || e?.status === 125 || e?.status === 126) return false;
4601
- return true;
4701
+ const r = hardBoundedExecFile(
4702
+ "docker",
4703
+ ["exec", `agt-${codeName}`, "pgrep", "-f", "claude"],
4704
+ // No logger threaded through this helper, and it is not worth widening
4705
+ // its signature for one line: bounded-exec falls back to `console.warn`
4706
+ // when a call site passes none, so the one-shot "unbounded" warning fires
4707
+ // from whichever call is first whether or not that call carries a logger.
4708
+ // It did NOT before ENG-9781's review — the latch was consumed without
4709
+ // emitting — and this comment asserted the outcome it wanted rather than
4710
+ // the one the code produced.
4711
+ { timeoutMs: 8e3 }
4712
+ );
4713
+ if (r.kind === "ok") return r.stdout.trim().length > 0;
4714
+ if (r.kind === "failed" && (r.status === 1 || r.status === 125 || r.status === 126)) {
4715
+ return false;
4602
4716
  }
4717
+ return true;
4603
4718
  }
4604
4719
  return probeClaudeProcessInTmux(tmuxSession) === "alive";
4605
4720
  }
@@ -4657,7 +4772,7 @@ function isSessionHealthy(codeName) {
4657
4772
  if (!claudeAlive) {
4658
4773
  const paneTail = readPaneLogTail(codeName);
4659
4774
  try {
4660
- execFileSync3("tmux", ["kill-session", "-t", tmuxSession], { stdio: "ignore" });
4775
+ execFileSync4("tmux", ["kill-session", "-t", tmuxSession], { stdio: "ignore" });
4661
4776
  } catch {
4662
4777
  }
4663
4778
  session.status = "crashed";
@@ -4753,13 +4868,13 @@ function collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, sp
4753
4868
  let launchArgs = null;
4754
4869
  let channelStatus = null;
4755
4870
  try {
4756
- execFileSync3("tmux", ["has-session", "-t", tmuxSession], { stdio: "ignore" });
4871
+ execFileSync4("tmux", ["has-session", "-t", tmuxSession], { stdio: "ignore" });
4757
4872
  tmuxAlive = true;
4758
4873
  } catch {
4759
4874
  }
4760
4875
  if (tmuxAlive) {
4761
4876
  try {
4762
- screenCapture = execFileSync3("tmux", ["capture-pane", "-t", tmuxSession, "-p", "-S", "-30"], {
4877
+ screenCapture = execFileSync4("tmux", ["capture-pane", "-t", tmuxSession, "-p", "-S", "-30"], {
4763
4878
  encoding: "utf-8",
4764
4879
  timeout: 3e3
4765
4880
  }).trim();
@@ -4767,7 +4882,7 @@ function collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, sp
4767
4882
  }
4768
4883
  }
4769
4884
  try {
4770
- const psOutput = execFileSync3("ps", ["aux"], { encoding: "utf-8", timeout: 3e3 });
4885
+ const psOutput = execFileSync4("ps", ["aux"], { encoding: "utf-8", timeout: 3e3 });
4771
4886
  const line2 = psOutput.split("\n").find((l) => l.includes(`agt-${codeName}`) && !l.includes("grep"));
4772
4887
  if (line2) {
4773
4888
  const match = line2.match(/claude\s+.*/);
@@ -4858,6 +4973,8 @@ export {
4858
4973
  toOpencodeModel,
4859
4974
  mergeOpencodeConfigArtifact,
4860
4975
  readChannelServerEnv,
4976
+ hardBoundedExecFile,
4977
+ hardBoundedCapture,
4861
4978
  LATE_BOUND_VARS,
4862
4979
  expandTemplateVars,
4863
4980
  parseEnvIntegrations,
@@ -4934,4 +5051,4 @@ export {
4934
5051
  stopAllSessionsAndWait,
4935
5052
  getProjectDir
4936
5053
  };
4937
- //# sourceMappingURL=chunk-EU6RSU5V.js.map
5054
+ //# sourceMappingURL=chunk-LVBINNTQ.js.map