@integrity-labs/agt-cli 0.28.656 → 0.28.658

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.
@@ -12261,4 +12261,4 @@ export {
12261
12261
  minutesSinceLocalMidnight,
12262
12262
  peekCurrentSession
12263
12263
  };
12264
- //# sourceMappingURL=chunk-XUJIPPKF.js.map
12264
+ //# sourceMappingURL=chunk-RASKCVAA.js.map
@@ -100,7 +100,7 @@ async function spawnPairSession(session) {
100
100
  return { ok: true };
101
101
  } catch {
102
102
  }
103
- const { resolveClaudeBinary } = await import("./persistent-session-2W67OQUH.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-PG7POJ3L.js");
104
104
  const claudeBin = resolveClaudeBinary();
105
105
  const pairEnv = {
106
106
  ...process.env,
@@ -373,4 +373,4 @@ export {
373
373
  startClaudePair,
374
374
  submitClaudePairCode
375
375
  };
376
- //# sourceMappingURL=claude-pair-runtime-3CYAS6UC.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-TRRXWBEM.js.map
@@ -55,7 +55,7 @@ import {
55
55
  safeWriteJsonAtomic,
56
56
  setConfigHash,
57
57
  tripClass
58
- } from "../chunk-XYXXHPG4.js";
58
+ } from "../chunk-QIOFZ6EP.js";
59
59
  import {
60
60
  getProjectDir as getProjectDir2,
61
61
  getReadyTasks,
@@ -111,7 +111,7 @@ import {
111
111
  takeZombieDetection,
112
112
  toOpencodeModel,
113
113
  writeEgressAllowlist
114
- } from "../chunk-OBIOE63G.js";
114
+ } from "../chunk-LAYT5BNW.js";
115
115
  import {
116
116
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
117
117
  AnchorSessionClient,
@@ -192,7 +192,7 @@ import {
192
192
  subagentActivityAgeSeconds,
193
193
  sumTranscriptUsageInWindow,
194
194
  transcriptActivityAgeSeconds
195
- } from "../chunk-XUJIPPKF.js";
195
+ } from "../chunk-RASKCVAA.js";
196
196
  import {
197
197
  reapOrphanChannelMcps
198
198
  } from "../chunk-XWVM4KPK.js";
@@ -11609,7 +11609,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
11609
11609
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
11610
11610
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
11611
11611
  async function channelInboundActivityAgeSecondsFor(codeName) {
11612
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-44G7U6LR.js");
11612
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-HP6SYFOJ.js");
11613
11613
  const newest = newestPendingInboundActivityMtimeMs(dirname10(paneLogPath(codeName)));
11614
11614
  if (newest === null) return null;
11615
11615
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -12252,7 +12252,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
12252
12252
  var lastVersionCheckAt = 0;
12253
12253
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
12254
12254
  var lastResponsivenessProbeAt = 0;
12255
- var agtCliVersion = true ? "0.28.656" : "dev";
12255
+ var agtCliVersion = true ? "0.28.658" : "dev";
12256
12256
  function resolveBrewPath(execFileSync3) {
12257
12257
  try {
12258
12258
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -13562,7 +13562,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
13562
13562
  if (codeNames.length === 0) return;
13563
13563
  void (async () => {
13564
13564
  try {
13565
- const { collectDiagnostics } = await import("../persistent-session-2W67OQUH.js");
13565
+ const { collectDiagnostics } = await import("../persistent-session-PG7POJ3L.js");
13566
13566
  await api.post("/host/heartbeat", {
13567
13567
  host_id: hostId,
13568
13568
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -13678,7 +13678,7 @@ async function pollCycleInner() {
13678
13678
  }
13679
13679
  try {
13680
13680
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
13681
- const { collectDiagnostics } = await import("../persistent-session-2W67OQUH.js");
13681
+ const { collectDiagnostics } = await import("../persistent-session-PG7POJ3L.js");
13682
13682
  const diagCodeNames = [...agentState.persistentSessionAgents];
13683
13683
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor) : void 0;
13684
13684
  let tailscaleHostname;
@@ -13801,7 +13801,7 @@ async function pollCycleInner() {
13801
13801
  collectPanelessActivityProbes,
13802
13802
  getResponsivenessIntervalMs,
13803
13803
  occupancyQualificationClassifications
13804
- } = await import("../responsiveness-probe-44G7U6LR.js");
13804
+ } = await import("../responsiveness-probe-HP6SYFOJ.js");
13805
13805
  const probeIntervalMs = getResponsivenessIntervalMs();
13806
13806
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
13807
13807
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -13911,7 +13911,7 @@ async function pollCycleInner() {
13911
13911
  collectResponsivenessProbes,
13912
13912
  livePendingInboundOldestAgeSeconds,
13913
13913
  parkPendingInbound
13914
- } = await import("../responsiveness-probe-44G7U6LR.js");
13914
+ } = await import("../responsiveness-probe-HP6SYFOJ.js");
13915
13915
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
13916
13916
  const wedgeNow = /* @__PURE__ */ new Date();
13917
13917
  const liveAgents = agentState.persistentSessionAgents;
@@ -14067,7 +14067,7 @@ async function pollCycleInner() {
14067
14067
  }
14068
14068
  try {
14069
14069
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
14070
- const { probeSessionAuth } = await import("../session-auth-dead-TNWKYZIA.js");
14070
+ const { probeSessionAuth } = await import("../session-auth-dead-RIAIWHHV.js");
14071
14071
  const observations = [];
14072
14072
  const pendingCacheCommits = [];
14073
14073
  const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
@@ -17700,7 +17700,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
17700
17700
  void api.post("/host/restart-ack", { host_id: hostId, agent_id: agentId, restart_requested_at: requestedAt }).catch((err) => log(`[restart-lane] ack failed for '${codeName}': ${err.message}`));
17701
17701
  void (async () => {
17702
17702
  try {
17703
- const { collectDiagnostics } = await import("../persistent-session-2W67OQUH.js");
17703
+ const { collectDiagnostics } = await import("../persistent-session-PG7POJ3L.js");
17704
17704
  await api.post("/host/heartbeat", {
17705
17705
  host_id: hostId,
17706
17706
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -17751,7 +17751,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
17751
17751
  }
17752
17752
  try {
17753
17753
  const hostId = await getHostId();
17754
- const { collectDiagnostics } = await import("../persistent-session-2W67OQUH.js");
17754
+ const { collectDiagnostics } = await import("../persistent-session-PG7POJ3L.js");
17755
17755
  await api.post("/host/heartbeat", {
17756
17756
  host_id: hostId,
17757
17757
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -18348,7 +18348,7 @@ async function processClaudePairSessions(agents) {
18348
18348
  killPairSession,
18349
18349
  pairTmuxSession,
18350
18350
  finalizeClaudePairOnboarding
18351
- } = await import("../claude-pair-runtime-3CYAS6UC.js");
18351
+ } = await import("../claude-pair-runtime-TRRXWBEM.js");
18352
18352
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
18353
18353
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
18354
18354
  const killed = await killPairSession(pairTmuxSession(pairId));
package/dist/mcp/index.js CHANGED
@@ -22373,7 +22373,6 @@ import {
22373
22373
  closeSync,
22374
22374
  constants as fsConstants,
22375
22375
  fstatSync,
22376
- lstatSync,
22377
22376
  openSync,
22378
22377
  readSync,
22379
22378
  realpathSync
@@ -22425,22 +22424,66 @@ function hostFilePathArg(toolName) {
22425
22424
  function allowedHostFileRoots(agentDir, path) {
22426
22425
  return [path.join(agentDir, "project"), path.join(agentDir, "scratch")];
22427
22426
  }
22428
- function assertNoSymlinkComponents(target, roots, path, fs) {
22427
+ function openContained(target, roots, opts) {
22428
+ const { path, fs, procFdBase } = opts;
22429
+ if (!procFdBase) {
22430
+ return {
22431
+ ok: false,
22432
+ error: "reading a host path needs descriptor-relative traversal (procfs), which this platform does not provide. Pass the content inline instead."
22433
+ };
22434
+ }
22429
22435
  const root = roots.find((r) => isContained(target, r, path.sep));
22430
- if (!root) return "resolved outside the allowed roots";
22431
- const rest = target.slice(root.length).split(path.sep).filter(Boolean);
22432
- let current = root;
22433
- for (const segment of rest) {
22434
- current = path.join(current, segment);
22435
- try {
22436
- if (fs.lstatSync(current).isSymbolicLink()) {
22437
- return `'${current}' is a symlink, so the path changed after it was resolved`;
22436
+ if (!root) return { ok: false, error: "resolved outside the allowed roots" };
22437
+ const segments = target.slice(root.length).split(path.sep).filter(Boolean);
22438
+ const fileName = segments[segments.length - 1];
22439
+ if (fileName === void 0) {
22440
+ return { ok: false, error: `'${target}' is a directory, not a file` };
22441
+ }
22442
+ for (const segment of segments) {
22443
+ if (segment === "." || segment === "..") {
22444
+ return { ok: false, error: `'${target}' contains a '${segment}' component` };
22445
+ }
22446
+ }
22447
+ const dirNames = segments.slice(0, -1);
22448
+ let dirFd;
22449
+ try {
22450
+ dirFd = fs.openSync(root, opts.dirOpenFlags);
22451
+ } catch (err) {
22452
+ return { ok: false, error: `the allowed root '${root}' could not be opened \u2014 ${err.message}` };
22453
+ }
22454
+ try {
22455
+ for (const name of dirNames) {
22456
+ let nextFd;
22457
+ try {
22458
+ nextFd = fs.openSync(path.join(procFdBase, String(dirFd), name), opts.dirOpenFlags);
22459
+ } catch (err) {
22460
+ return {
22461
+ ok: false,
22462
+ error: `'${name}' could not be entered \u2014 it is a symlink, is not a directory, or was replaced mid-traversal (${err.message})`
22463
+ };
22438
22464
  }
22465
+ try {
22466
+ fs.closeSync(dirFd);
22467
+ } catch {
22468
+ }
22469
+ dirFd = nextFd;
22470
+ }
22471
+ let fd;
22472
+ try {
22473
+ fd = fs.openSync(path.join(procFdBase, String(dirFd), fileName), opts.openFlags);
22474
+ } catch (err) {
22475
+ return {
22476
+ ok: false,
22477
+ error: `'${fileName}' could not be opened (a symlink, or replaced mid-check) \u2014 ${err.message}`
22478
+ };
22479
+ }
22480
+ return { ok: true, fd };
22481
+ } finally {
22482
+ try {
22483
+ fs.closeSync(dirFd);
22439
22484
  } catch {
22440
- return `'${current}' could not be inspected`;
22441
22485
  }
22442
22486
  }
22443
- return null;
22444
22487
  }
22445
22488
  function isContained(candidate, root, sep2) {
22446
22489
  if (candidate === root) return true;
@@ -22483,24 +22526,9 @@ function resolveHostFilePath(toolName, args, opts) {
22483
22526
  error: `${spec.pathArg} resolves outside your own directories (symlink?). '${raw}' \u2192 '${real}'. Allowed: ${roots.join(", ")}`
22484
22527
  };
22485
22528
  }
22486
- const walkError = assertNoSymlinkComponents(real, roots, path, fs);
22487
- if (walkError) return { ok: false, error: `${spec.pathArg}: ${walkError}` };
22488
- let vetted = null;
22489
- try {
22490
- vetted = fs.lstatSync(real);
22491
- } catch {
22492
- return { ok: false, error: `${spec.pathArg} vanished before it could be read: '${raw}'` };
22493
- }
22494
- let fd;
22495
- try {
22496
- fd = fs.openSync(real, opts.openFlags);
22497
- } catch (err) {
22498
- const msg = err.message;
22499
- return {
22500
- ok: false,
22501
- error: `${spec.pathArg} could not be opened (it may have been replaced mid-check): '${raw}' \u2014 ${msg}`
22502
- };
22503
- }
22529
+ const opened = openContained(real, roots, opts);
22530
+ if (!opened.ok) return { ok: false, error: `${spec.pathArg}: ${opened.error} ('${raw}')` };
22531
+ const fd = opened.fd;
22504
22532
  try {
22505
22533
  let stat;
22506
22534
  try {
@@ -22511,14 +22539,6 @@ function resolveHostFilePath(toolName, args, opts) {
22511
22539
  if (!stat.isFile()) {
22512
22540
  return { ok: false, error: `${spec.pathArg} is not a regular file: '${raw}'` };
22513
22541
  }
22514
- if (stat.ino !== void 0 && vetted.ino !== void 0) {
22515
- if (stat.ino !== vetted.ino || stat.dev !== vetted.dev) {
22516
- return {
22517
- ok: false,
22518
- error: `${spec.pathArg} changed identity between the check and the open (it was replaced): '${raw}'`
22519
- };
22520
- }
22521
- }
22522
22542
  if (stat.size > maxBytes) {
22523
22543
  return {
22524
22544
  ok: false,
@@ -45984,16 +46004,37 @@ async function forwardToolCall(toolName, args) {
45984
46004
  // symlink-resolved, so a symlink at the final component means it was
45985
46005
  // swapped after the check, and this turns that into an ELOOP.
45986
46006
  openFlags: fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW,
46007
+ // ENG-9230. Each intermediate DIRECTORY is opened too, so the walk can be
46008
+ // anchored to descriptors rather than pathnames. O_DIRECTORY alongside
46009
+ // O_NOFOLLOW so a component that stopped being a directory is refused by
46010
+ // the kernel rather than noticed later.
46011
+ dirOpenFlags: fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW | fsConstants.O_DIRECTORY,
46012
+ // ENG-9230. Supplied ONLY on Linux, and its absence is load-bearing:
46013
+ // `openContained` refuses outright rather than falling back to the
46014
+ // pathname walk, because that walk is the vulnerability. On a platform
46015
+ // without procfs the host-path shortcut is simply unavailable and the
46016
+ // agent passes the content inline — slower, and safe.
46017
+ //
46018
+ // `process.platform` rather than probing for /proc: a probe would have to
46019
+ // decide what a read failure means, and "cannot tell" would have to fail
46020
+ // closed anyway. Agent hosts are Linux EC2; this is about local dev on
46021
+ // macOS getting an honest refusal instead of a silent downgrade.
46022
+ ...process.platform === "linux" ? { procFdBase: "/proc/self/fd" } : {},
45987
46023
  fs: {
45988
46024
  realpathSync,
45989
46025
  openSync,
45990
46026
  fstatSync,
45991
46027
  closeSync,
45992
46028
  // Bounded read straight off the descriptor: at most maxBytes + 1 bytes,
45993
- // so an oversize file is detected rather than buffered whole.
45994
- lstatSync,
45995
- // Raw bytes, decoded only after the byte-length check — see
45996
- // readFdSync's docblock in host-file-path.ts.
46029
+ // so an oversize file is detected rather than buffered whole. Raw bytes,
46030
+ // decoded only after the byte-length check — see readFdSync's docblock
46031
+ // in host-file-path.ts.
46032
+ //
46033
+ // ENG-9230: `lstatSync` used to be injected here and is deliberately
46034
+ // gone. Every remaining member of this seam takes a DESCRIPTOR except
46035
+ // the two that cannot (realpath, and the single open of the allowed
46036
+ // root); handing the resolver a pathname-based stat back would put the
46037
+ // exploitable primitive within reach of the next change.
45997
46038
  readFdSync: (fd, maxBytes) => {
45998
46039
  const buf = Buffer.alloc(maxBytes + 1);
45999
46040
  let read = 0;
@@ -43,8 +43,8 @@ import {
43
43
  writeDirectChatSessionState,
44
44
  writeEgressAllowlist,
45
45
  writePersistentClaudeWrapper
46
- } from "./chunk-OBIOE63G.js";
47
- import "./chunk-XUJIPPKF.js";
46
+ } from "./chunk-LAYT5BNW.js";
47
+ import "./chunk-RASKCVAA.js";
48
48
  import "./chunk-XWVM4KPK.js";
49
49
  export {
50
50
  EGRESS_BASELINE_DOMAINS,
@@ -92,4 +92,4 @@ export {
92
92
  writeEgressAllowlist,
93
93
  writePersistentClaudeWrapper
94
94
  };
95
- //# sourceMappingURL=persistent-session-2W67OQUH.js.map
95
+ //# sourceMappingURL=persistent-session-PG7POJ3L.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-OBIOE63G.js";
4
- import "./chunk-XUJIPPKF.js";
3
+ } from "./chunk-LAYT5BNW.js";
4
+ import "./chunk-RASKCVAA.js";
5
5
  import "./chunk-XWVM4KPK.js";
6
6
 
7
7
  // src/lib/responsiveness-probe.ts
@@ -727,4 +727,4 @@ export {
727
727
  readAndResetSlackReplyBindingClassifications,
728
728
  readAndResetSlackReplyTargetClassifications
729
729
  };
730
- //# sourceMappingURL=responsiveness-probe-44G7U6LR.js.map
730
+ //# sourceMappingURL=responsiveness-probe-HP6SYFOJ.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  sessionTranscriptDir
3
- } from "./chunk-XUJIPPKF.js";
3
+ } from "./chunk-RASKCVAA.js";
4
4
 
5
5
  // src/lib/session-auth-dead.ts
6
6
  import { closeSync, openSync, readSync, readdirSync, statSync } from "fs";
@@ -203,4 +203,4 @@ export {
203
203
  decideSessionAuthState,
204
204
  probeSessionAuth
205
205
  };
206
- //# sourceMappingURL=session-auth-dead-TNWKYZIA.js.map
206
+ //# sourceMappingURL=session-auth-dead-RIAIWHHV.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.656",
3
+ "version": "0.28.658",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {