@integrity-labs/agt-cli 0.28.763 → 0.28.765

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 (25) 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-HVOHM3PB.js → chunk-EWH4J63B.js} +86 -28
  5. package/dist/chunk-EWH4J63B.js.map +1 -0
  6. package/dist/{chunk-EU6RSU5V.js → chunk-LVBINNTQ.js} +157 -40
  7. package/dist/chunk-LVBINNTQ.js.map +1 -0
  8. package/dist/{claude-pair-runtime-5CKIB2IM.js → claude-pair-runtime-U6WDTNK3.js} +2 -2
  9. package/dist/lib/manager-worker.js +57 -62
  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/chunk-HVOHM3PB.js.map +0 -1
  22. /package/dist/{claude-pair-runtime-5CKIB2IM.js.map → claude-pair-runtime-U6WDTNK3.js.map} +0 -0
  23. /package/dist/{persistent-session-VS44QKVB.js.map → persistent-session-3OBDKYWF.js.map} +0 -0
  24. /package/dist/{responsiveness-probe-CNSUJALX.js.map → responsiveness-probe-ULIAXSCT.js.map} +0 -0
  25. /package/dist/{session-auth-dead-3AK3MDNT.js.map → session-auth-dead-67XFJWMA.js.map} +0 -0
@@ -7,13 +7,14 @@ import {
7
7
  buildRemoteMcpEntry,
8
8
  expandTemplateVars,
9
9
  getProjectDir,
10
+ hardBoundedExecFile,
10
11
  isolationMode,
11
12
  log,
12
13
  mergeEnvIntegrationsContent,
13
14
  parseEnvFileEntries,
14
15
  parseEnvIntegrations,
15
16
  shellQuote
16
- } from "./chunk-EU6RSU5V.js";
17
+ } from "./chunk-LVBINNTQ.js";
17
18
  import {
18
19
  BIND_FAILURE_QUARANTINE_THRESHOLD,
19
20
  INTEGRATIONS_SECTION_END,
@@ -63,7 +64,7 @@ import {
63
64
  sessionTranscriptDir,
64
65
  worseConnectivityOutcome,
65
66
  wrapScheduledTaskPrompt
66
- } from "./chunk-L4KDOGHB.js";
67
+ } from "./chunk-23KTLVYX.js";
67
68
  import {
68
69
  parsePsRows
69
70
  } from "./chunk-XWVM4KPK.js";
@@ -2551,9 +2552,24 @@ function provisionStopHook(codeName) {
2551
2552
  "# obligation (consume is the explicit handled-without-reply ack, the same",
2552
2553
  "# session-scoped drain the MCP applies), so either counts as answered. session_id",
2553
2554
  "# is unambiguous (one session per marker), so there is no cross-thread class here.",
2555
+ "#",
2556
+ "# ENG-9420: this predicate was the one of four that ENG-8142 missed. It came",
2557
+ "# from ENG-7808 and had been error-blind ever since, so a direct_chat.reply",
2558
+ '# whose tool_result came back is_error:true still satisfied "the agent',
2559
+ '# replied" - the recovery outbox never written, the owed-reply re-prompt',
2560
+ "# suppressed. Direct chat is where scheduled-task results and approval",
2561
+ "# round-trips land, so that is a user asking a question and getting nothing.",
2562
+ "#",
2563
+ "# A FAILED consume is treated the same as a failed reply, deliberately.",
2564
+ '# consume means "handled without replying" and drains the marker; if the',
2565
+ "# drain failed, the marker was not drained and the conversation is not",
2566
+ "# settled. Counting it would suppress the re-prompt for a message that is",
2567
+ "# still genuinely pending. The failure direction of this choice is an extra",
2568
+ "# re-prompt, which the user sees and can ignore; the other direction is a",
2569
+ "# silently dropped message, which nobody sees at all.",
2554
2570
  "replied_this_conv_directchat() {",
2555
2571
  ' local session_id="$1" hit',
2556
- ` hit=$(printf '%s' "$LAST_ASSISTANT" | jq -r --arg sid "$session_id" '(.message.content // .content // []) | (if type=="array" then . else [] end) | (if any(.[]; (type=="object") and (.type=="tool_use") and ((.name|tostring)|test("(^|__)direct_chat[._](reply|consume)$")) and (((.input.session_id // "")|tostring)==$sid)) then "yes" else "no" end)' 2>/dev/null || echo no)`,
2572
+ ` hit=$(printf '%s' "$LAST_ASSISTANT" | jq -r --arg sid "$session_id" --arg errids "$ERRORED_TOOL_IDS" '(($errids // "") | split("\\n") | map(select(length > 0))) as $bad | (.message.content // .content // []) | (if type=="array" then . else [] end) | (if any(.[]; (type=="object") and (.type=="tool_use") and ((.name|tostring)|test("(^|__)direct_chat[._](reply|consume)$")) and ((.id // "") as $tid | ($bad | index($tid)) == null) and (((.input.session_id // "")|tostring)==$sid)) then "yes" else "no" end)' 2>/dev/null || echo no)`,
2557
2573
  ' [ "$hit" = "yes" ]',
2558
2574
  "}",
2559
2575
  "recover_telegram_for() {",
@@ -6436,7 +6452,7 @@ function exchangeFailureKind(err) {
6436
6452
  }
6437
6453
 
6438
6454
  // src/lib/api-client.ts
6439
- var agtCliVersion = true ? "0.28.763" : "dev";
6455
+ var agtCliVersion = true ? "0.28.765" : "dev";
6440
6456
  var lastConfigHash = null;
6441
6457
  function setConfigHash(hash) {
6442
6458
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -7043,6 +7059,12 @@ var HostFlagStore = class {
7043
7059
 
7044
7060
  // src/lib/stale-mcp-reaper.ts
7045
7061
  import { execFileSync } from "child_process";
7062
+ function livenessFromProbe(r, onNoAnswer) {
7063
+ if (r.kind === "ok") return true;
7064
+ if (r.kind === "failed" && r.status !== null) return false;
7065
+ onNoAnswer?.(r.kind === "timed-out" ? "did not answer within its bound" : `could not run: ${r.message}`);
7066
+ return true;
7067
+ }
7046
7068
  var rotationTimestamps = /* @__PURE__ */ new Map();
7047
7069
  var DEFAULT_ROTATION_GRACE_MS = 15e3;
7048
7070
  function rotationKey(codeName, serverKey) {
@@ -7256,19 +7278,30 @@ function findMcpChildrenForAgent(args) {
7256
7278
  function reapStaleMcpChildren(args) {
7257
7279
  const { log: log2, codeName, serverKeys, mcpJson, graceMs = 5e3, isolated = false } = args;
7258
7280
  if (serverKeys.length === 0) return [];
7259
- const runPs = args.runPs ?? (isolated ? () => execFileSync("docker", ["exec", `agt-${codeName}`, "ps", "-eo", "pid,ppid,args"], {
7260
- encoding: "utf-8",
7261
- timeout: 8e3
7262
- }) : () => execFileSync("ps", ["-eo", "pid,ppid,args"], { encoding: "utf-8", timeout: 5e3 }));
7263
- const killProcess = args.killProcess ?? (isolated ? (pid, signal) => {
7264
- try {
7265
- execFileSync(
7281
+ const runPs = args.runPs ?? (isolated ? (
7282
+ // ENG-9781: hard-bounded. See bounded-exec.ts — `execFileSync`'s own
7283
+ // `timeout` is not a bound, and this runs per isolated agent per cycle
7284
+ // on the manager-worker's critical path. Throws on a non-answer so the
7285
+ // caller's existing catch skips the agent rather than acting on an
7286
+ // empty process list.
7287
+ () => {
7288
+ const r = hardBoundedExecFile(
7266
7289
  "docker",
7267
- ["exec", `agt-${codeName}`, "kill", signal === "SIGKILL" ? "-KILL" : "-TERM", String(pid)],
7268
- { timeout: 8e3, stdio: "ignore" }
7290
+ ["exec", `agt-${codeName}`, "ps", "-eo", "pid,ppid,args"],
7291
+ { timeoutMs: 8e3, log: log2 }
7292
+ );
7293
+ if (r.kind === "ok") return r.stdout;
7294
+ throw new Error(
7295
+ r.kind === "timed-out" ? `docker exec ps did not answer within its bound (bounded=${r.bounded})` : `docker exec ps failed (status=${r.status}): ${r.message}`
7269
7296
  );
7270
- } catch {
7271
7297
  }
7298
+ ) : () => execFileSync("ps", ["-eo", "pid,ppid,args"], { encoding: "utf-8", timeout: 5e3 }));
7299
+ const killProcess = args.killProcess ?? (isolated ? (pid, signal) => {
7300
+ hardBoundedExecFile(
7301
+ "docker",
7302
+ ["exec", `agt-${codeName}`, "kill", signal === "SIGKILL" ? "-KILL" : "-TERM", String(pid)],
7303
+ { timeoutMs: 8e3, log: log2 }
7304
+ );
7272
7305
  } : (pid, signal) => {
7273
7306
  try {
7274
7307
  process.kill(pid, signal);
@@ -7276,15 +7309,17 @@ function reapStaleMcpChildren(args) {
7276
7309
  }
7277
7310
  });
7278
7311
  const isAlive = args.isAlive ?? (isolated ? (pid) => {
7279
- try {
7280
- execFileSync("docker", ["exec", `agt-${codeName}`, "kill", "-0", String(pid)], {
7281
- timeout: 8e3,
7282
- stdio: "ignore"
7283
- });
7284
- return true;
7285
- } catch {
7286
- return false;
7287
- }
7312
+ const r = hardBoundedExecFile(
7313
+ "docker",
7314
+ ["exec", `agt-${codeName}`, "kill", "-0", String(pid)],
7315
+ { timeoutMs: 8e3, log: log2 }
7316
+ );
7317
+ return livenessFromProbe(
7318
+ r,
7319
+ (why) => log2(
7320
+ `[stale-mcp-reaper] liveness probe for pid ${pid} in 'agt-${codeName}' ${why} \u2014 treating as ALIVE (no reap) rather than guessing`
7321
+ )
7322
+ );
7288
7323
  } : (pid) => {
7289
7324
  try {
7290
7325
  process.kill(pid, 0);
@@ -7453,10 +7488,33 @@ function reapMissingMcpSessions(args) {
7453
7488
  currentGenerationExternallyStarted = false
7454
7489
  } = args;
7455
7490
  const now = args.now ?? Date.now;
7456
- const runPs = args.runPs ?? (isolated ? () => execFileSync2("docker", ["exec", `agt-${codeName}`, "ps", "-eo", "pid,ppid,args"], {
7457
- encoding: "utf-8",
7458
- timeout: 8e3
7459
- }) : () => execFileSync2("ps", ["-eo", "pid,ppid,args"], { encoding: "utf-8", timeout: 5e3 }));
7491
+ const runPs = args.runPs ?? (isolated ? (
7492
+ // ENG-9781: HARD-bounded, and the distinction is the whole ticket. The
7493
+ // previous `execFileSync(..., { timeout: 8_000 })` bounded nothing —
7494
+ // Node fires SIGTERM at the deadline and then keeps waiting, so a
7495
+ // docker CLI talking to a wedged daemon blocked the manager-worker's
7496
+ // event loop and stopped scheduling for EVERY agent on the host
7497
+ // (33m46s, twice, on 2026-09-01). This call runs once per isolated
7498
+ // agent per poll cycle, so it is the single worst place on the manager
7499
+ // for an unbounded subprocess.
7500
+ //
7501
+ // Throwing on a non-answer is deliberate rather than lazy: the caller
7502
+ // already catches, logs and SKIPS the agent for the cycle, which is
7503
+ // exactly right. A timeout must not become an empty process list —
7504
+ // that reads as "every declared MCP server is missing" and restarts the
7505
+ // session, turning a docker hiccup into a fleet-wide restart storm.
7506
+ () => {
7507
+ const r = hardBoundedExecFile(
7508
+ "docker",
7509
+ ["exec", `agt-${codeName}`, "ps", "-eo", "pid,ppid,args"],
7510
+ { timeoutMs: 8e3, log: log2 }
7511
+ );
7512
+ if (r.kind === "ok") return r.stdout;
7513
+ throw new Error(
7514
+ r.kind === "timed-out" ? `docker exec ps did not answer within its bound (bounded=${r.bounded})` : `docker exec ps failed (status=${r.status}): ${r.message}`
7515
+ );
7516
+ }
7517
+ ) : () => execFileSync2("ps", ["-eo", "pid,ppid,args"], { encoding: "utf-8", timeout: 5e3 }));
7460
7518
  if (!mcpJson?.mcpServers) {
7461
7519
  return { missing: [], restarted: false, reason: "no-mcp-json" };
7462
7520
  }
@@ -10593,4 +10651,4 @@ export {
10593
10651
  managerInstallSystemUnitCommand,
10594
10652
  managerUninstallSystemUnitCommand
10595
10653
  };
10596
- //# sourceMappingURL=chunk-HVOHM3PB.js.map
10654
+ //# sourceMappingURL=chunk-EWH4J63B.js.map