@integrity-labs/agt-cli 0.28.576 → 0.28.578

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.
@@ -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-2ESCLFCK.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-URCLTP7E.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-4C5YXND6.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-LSFDNBRR.js.map
@@ -53,7 +53,7 @@ import {
53
53
  safeWriteJsonAtomic,
54
54
  setConfigHash,
55
55
  tripClass
56
- } from "../chunk-P2LAQMRN.js";
56
+ } from "../chunk-5YFIIWS2.js";
57
57
  import {
58
58
  getProjectDir as getProjectDir2,
59
59
  getReadyTasks,
@@ -182,7 +182,7 @@ import {
182
182
  toOpencodeModel,
183
183
  transcriptActivityAgeSeconds,
184
184
  writeEgressAllowlist
185
- } from "../chunk-E3KBX3UW.js";
185
+ } from "../chunk-L24SX6LH.js";
186
186
  import {
187
187
  reapOrphanChannelMcps
188
188
  } from "../chunk-XWVM4KPK.js";
@@ -11596,7 +11596,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
11596
11596
  var lastVersionCheckAt = 0;
11597
11597
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
11598
11598
  var lastResponsivenessProbeAt = 0;
11599
- var agtCliVersion = true ? "0.28.576" : "dev";
11599
+ var agtCliVersion = true ? "0.28.578" : "dev";
11600
11600
  function resolveBrewPath(execFileSync2) {
11601
11601
  try {
11602
11602
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -12903,7 +12903,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
12903
12903
  if (codeNames.length === 0) return;
12904
12904
  void (async () => {
12905
12905
  try {
12906
- const { collectDiagnostics } = await import("../persistent-session-2ESCLFCK.js");
12906
+ const { collectDiagnostics } = await import("../persistent-session-URCLTP7E.js");
12907
12907
  await api.post("/host/heartbeat", {
12908
12908
  host_id: hostId,
12909
12909
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics)
@@ -13011,7 +13011,7 @@ async function pollCycle() {
13011
13011
  }
13012
13012
  try {
13013
13013
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
13014
- const { collectDiagnostics } = await import("../persistent-session-2ESCLFCK.js");
13014
+ const { collectDiagnostics } = await import("../persistent-session-URCLTP7E.js");
13015
13015
  const diagCodeNames = [...agentState.persistentSessionAgents];
13016
13016
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics) : void 0;
13017
13017
  let tailscaleHostname;
@@ -13134,7 +13134,7 @@ async function pollCycle() {
13134
13134
  collectPanelessActivityProbes,
13135
13135
  getResponsivenessIntervalMs,
13136
13136
  occupancyQualificationClassifications
13137
- } = await import("../responsiveness-probe-YCUDUCAS.js");
13137
+ } = await import("../responsiveness-probe-RZIE5CVC.js");
13138
13138
  const probeIntervalMs = getResponsivenessIntervalMs();
13139
13139
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
13140
13140
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -13225,7 +13225,7 @@ async function pollCycle() {
13225
13225
  collectResponsivenessProbes,
13226
13226
  livePendingInboundOldestAgeSeconds,
13227
13227
  parkPendingInbound
13228
- } = await import("../responsiveness-probe-YCUDUCAS.js");
13228
+ } = await import("../responsiveness-probe-RZIE5CVC.js");
13229
13229
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
13230
13230
  const wedgeNow = /* @__PURE__ */ new Date();
13231
13231
  const liveAgents = agentState.persistentSessionAgents;
@@ -16795,7 +16795,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
16795
16795
  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}`));
16796
16796
  void (async () => {
16797
16797
  try {
16798
- const { collectDiagnostics } = await import("../persistent-session-2ESCLFCK.js");
16798
+ const { collectDiagnostics } = await import("../persistent-session-URCLTP7E.js");
16799
16799
  await api.post("/host/heartbeat", {
16800
16800
  host_id: hostId,
16801
16801
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics)
@@ -16846,7 +16846,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
16846
16846
  }
16847
16847
  try {
16848
16848
  const hostId = await getHostId();
16849
- const { collectDiagnostics } = await import("../persistent-session-2ESCLFCK.js");
16849
+ const { collectDiagnostics } = await import("../persistent-session-URCLTP7E.js");
16850
16850
  await api.post("/host/heartbeat", {
16851
16851
  host_id: hostId,
16852
16852
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics)
@@ -17424,7 +17424,7 @@ async function processClaudePairSessions(agents) {
17424
17424
  killPairSession,
17425
17425
  pairTmuxSession,
17426
17426
  finalizeClaudePairOnboarding
17427
- } = await import("../claude-pair-runtime-4C5YXND6.js");
17427
+ } = await import("../claude-pair-runtime-LSFDNBRR.js");
17428
17428
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
17429
17429
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
17430
17430
  const killed = await killPairSession(pairTmuxSession(pairId));
package/dist/mcp/index.js CHANGED
@@ -6802,6 +6802,15 @@ var require_dist = __commonJS({
6802
6802
 
6803
6803
  // src/index.ts
6804
6804
  import { mkdtemp, writeFile } from "fs/promises";
6805
+ import {
6806
+ closeSync,
6807
+ constants as fsConstants,
6808
+ fstatSync,
6809
+ lstatSync,
6810
+ openSync,
6811
+ readSync,
6812
+ realpathSync
6813
+ } from "fs";
6805
6814
 
6806
6815
  // src/kanban-add-result.ts
6807
6816
  function kanbanAddResultText(data, submittedTitle, status) {
@@ -6818,8 +6827,134 @@ ${first.duplicate_hint}` : added;
6818
6827
  }
6819
6828
 
6820
6829
  // src/index.ts
6821
- import { tmpdir } from "os";
6822
- import { basename, join as join3 } from "path";
6830
+ import { homedir as homedir3, tmpdir } from "os";
6831
+ import { basename, isAbsolute, join as join3, resolve as pathResolve, sep } from "path";
6832
+
6833
+ // src/skill-body-path.ts
6834
+ var SKILL_BODY_PATH_TOOLS = /* @__PURE__ */ new Set(["skill_create", "skill_update"]);
6835
+ var SKILL_BODY_PATH_MAX_BYTES = 512 * 1024;
6836
+ function allowedSkillBodyRoots(agentDir, path) {
6837
+ return [path.join(agentDir, "project"), path.join(agentDir, "scratch")];
6838
+ }
6839
+ function assertNoSymlinkComponents(target, roots, path, fs) {
6840
+ const root = roots.find((r) => isContained(target, r, path.sep));
6841
+ if (!root) return "resolved outside the allowed roots";
6842
+ const rest = target.slice(root.length).split(path.sep).filter(Boolean);
6843
+ let current = root;
6844
+ for (const segment of rest) {
6845
+ current = path.join(current, segment);
6846
+ try {
6847
+ if (fs.lstatSync(current).isSymbolicLink()) {
6848
+ return `'${current}' is a symlink, so the path changed after it was resolved`;
6849
+ }
6850
+ } catch {
6851
+ return `'${current}' could not be inspected`;
6852
+ }
6853
+ }
6854
+ return null;
6855
+ }
6856
+ function isContained(candidate, root, sep2) {
6857
+ if (candidate === root) return true;
6858
+ const rootWithSep = root.endsWith(sep2) ? root : root + sep2;
6859
+ return candidate.startsWith(rootWithSep);
6860
+ }
6861
+ function resolveSkillBodyPath(toolName, args, opts) {
6862
+ if (!SKILL_BODY_PATH_TOOLS.has(toolName)) return { ok: true, args };
6863
+ const raw = args["body_path"];
6864
+ if (raw === void 0 || raw === null) return { ok: true, args };
6865
+ if (typeof raw !== "string" || raw.trim() === "") {
6866
+ return { ok: false, error: "body_path must be a non-empty string." };
6867
+ }
6868
+ if (typeof args["body"] === "string") {
6869
+ return {
6870
+ ok: false,
6871
+ error: "Pass either body or body_path, not both \u2014 they are two ways to say the same thing and I will not guess which one you meant."
6872
+ };
6873
+ }
6874
+ const { agentDir, path, fs } = opts;
6875
+ const maxBytes = opts.maxBytes ?? SKILL_BODY_PATH_MAX_BYTES;
6876
+ const roots = allowedSkillBodyRoots(agentDir, path);
6877
+ const absolute = path.isAbsolute(raw) ? path.resolve(raw) : path.resolve(path.join(agentDir, "project"), raw);
6878
+ if (!roots.some((r) => isContained(absolute, r, path.sep))) {
6879
+ return {
6880
+ ok: false,
6881
+ error: `body_path must be inside your own project or scratch directory. Got '${raw}'. Allowed: ${roots.join(", ")}`
6882
+ };
6883
+ }
6884
+ let real;
6885
+ try {
6886
+ real = fs.realpathSync(absolute);
6887
+ } catch {
6888
+ return { ok: false, error: `body_path does not exist or is unreadable: '${raw}'` };
6889
+ }
6890
+ if (!roots.some((r) => isContained(real, r, path.sep))) {
6891
+ return {
6892
+ ok: false,
6893
+ error: `body_path resolves outside your own directories (symlink?). '${raw}' \u2192 '${real}'. Allowed: ${roots.join(", ")}`
6894
+ };
6895
+ }
6896
+ const walkError = assertNoSymlinkComponents(real, roots, path, fs);
6897
+ if (walkError) return { ok: false, error: `body_path: ${walkError}` };
6898
+ let vetted = null;
6899
+ try {
6900
+ vetted = fs.lstatSync(real);
6901
+ } catch {
6902
+ return { ok: false, error: `body_path vanished before it could be read: '${raw}'` };
6903
+ }
6904
+ let fd;
6905
+ try {
6906
+ fd = fs.openSync(real, opts.openFlags);
6907
+ } catch (err) {
6908
+ const msg = err.message;
6909
+ return {
6910
+ ok: false,
6911
+ error: `body_path could not be opened (it may have been replaced mid-check): '${raw}' \u2014 ${msg}`
6912
+ };
6913
+ }
6914
+ try {
6915
+ let stat;
6916
+ try {
6917
+ stat = fs.fstatSync(fd);
6918
+ } catch {
6919
+ return { ok: false, error: `body_path could not be inspected: '${raw}'` };
6920
+ }
6921
+ if (!stat.isFile()) {
6922
+ return { ok: false, error: `body_path is not a regular file: '${raw}'` };
6923
+ }
6924
+ if (stat.ino !== void 0 && vetted.ino !== void 0) {
6925
+ if (stat.ino !== vetted.ino || stat.dev !== vetted.dev) {
6926
+ return {
6927
+ ok: false,
6928
+ error: `body_path changed identity between the check and the open (it was replaced): '${raw}'`
6929
+ };
6930
+ }
6931
+ }
6932
+ if (stat.size > maxBytes) {
6933
+ return {
6934
+ ok: false,
6935
+ error: `body_path is ${stat.size} bytes, over the ${maxBytes}-byte limit for a skill body.`
6936
+ };
6937
+ }
6938
+ let bytes;
6939
+ try {
6940
+ bytes = fs.readFdSync(fd, maxBytes);
6941
+ } catch (err) {
6942
+ return { ok: false, error: `body_path could not be read: ${err.message}` };
6943
+ }
6944
+ if (bytes.byteLength > maxBytes) {
6945
+ return { ok: false, error: `body_path grew past the ${maxBytes}-byte limit while being read.` };
6946
+ }
6947
+ const body = fs.decodeUtf8(bytes);
6948
+ const next = { ...args, body };
6949
+ delete next["body_path"];
6950
+ return { ok: true, args: next };
6951
+ } finally {
6952
+ try {
6953
+ fs.closeSync(fd);
6954
+ } catch {
6955
+ }
6956
+ }
6957
+ }
6823
6958
 
6824
6959
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
6825
6960
  var external_exports = {};
@@ -24345,16 +24480,72 @@ async function discoverApiTools() {
24345
24480
  return [];
24346
24481
  }
24347
24482
  }
24483
+ function canonicalAgentDir(dir) {
24484
+ try {
24485
+ return realpathSync(dir);
24486
+ } catch {
24487
+ return dir;
24488
+ }
24489
+ }
24348
24490
  async function forwardToolCall(toolName, args) {
24349
24491
  if (!AGT_AGENT_ID) {
24350
24492
  throw new Error("Cannot forward tool call: AGT_AGENT_ID is not set");
24351
24493
  }
24494
+ let outgoing = args;
24495
+ if (SKILL_BODY_PATH_TOOLS.has(toolName) && args["body_path"] !== void 0) {
24496
+ if (!AGT_AGENT_CODE_NAME) {
24497
+ throw new Error("Cannot resolve body_path: AGT_AGENT_CODE_NAME is not set");
24498
+ }
24499
+ const resolved = resolveSkillBodyPath(toolName, args, {
24500
+ // ADR-0049 / ENG-7891: the per-agent host dir is agent_id-keyed and the
24501
+ // codename path is only a compatibility SYMLINK. That is not a style
24502
+ // point here, it is a correctness one: the containment check below
24503
+ // realpath-resolves the caller's path, which resolves THROUGH the symlink
24504
+ // to the agent_id-keyed tree - so a codename-based root would fail
24505
+ // containment for every legitimate file and refuse them all. Resolve the
24506
+ // root to its canonical form so both sides of the comparison are real
24507
+ // paths. Falls back to the unresolved join if the dir is missing, which
24508
+ // then simply refuses (there is nothing to read anyway).
24509
+ agentDir: canonicalAgentDir(join3(homedir3(), ".augmented", AGT_AGENT_CODE_NAME)),
24510
+ // agent-dir-allow: immediately realpath-resolved to the ADR-0049 agent_id-keyed dir before use as a containment root
24511
+ path: { isAbsolute, resolve: pathResolve, join: join3, sep },
24512
+ // O_NOFOLLOW is the whole point of opening by flags: the path is already
24513
+ // symlink-resolved, so a symlink at the final component means it was
24514
+ // swapped after the check, and this turns that into an ELOOP.
24515
+ openFlags: fsConstants.O_RDONLY | fsConstants.O_NOFOLLOW,
24516
+ fs: {
24517
+ realpathSync,
24518
+ openSync,
24519
+ fstatSync,
24520
+ closeSync,
24521
+ // Bounded read straight off the descriptor: at most maxBytes + 1 bytes,
24522
+ // so an oversize file is detected rather than buffered whole.
24523
+ lstatSync,
24524
+ // Raw bytes, decoded only after the byte-length check — see
24525
+ // readFdSync's docblock in skill-body-path.ts.
24526
+ readFdSync: (fd, maxBytes) => {
24527
+ const buf = Buffer.alloc(maxBytes + 1);
24528
+ let read = 0;
24529
+ for (; ; ) {
24530
+ const n = readSync(fd, buf, read, buf.length - read, null);
24531
+ if (n <= 0) break;
24532
+ read += n;
24533
+ if (read >= buf.length) break;
24534
+ }
24535
+ return buf.subarray(0, read);
24536
+ },
24537
+ decodeUtf8: (bytes) => Buffer.from(bytes).toString("utf8")
24538
+ }
24539
+ });
24540
+ if (!resolved.ok) throw new Error(resolved.error);
24541
+ outgoing = resolved.args;
24542
+ }
24352
24543
  return apiPost(
24353
24544
  "/host/mcp/tools/call",
24354
24545
  {
24355
24546
  agent_id: AGT_AGENT_ID,
24356
24547
  name: toolName,
24357
- arguments: args,
24548
+ arguments: outgoing,
24358
24549
  run_id: AGT_RUN_ID ?? null
24359
24550
  },
24360
24551
  false,
@@ -41,7 +41,7 @@ import {
41
41
  writeDirectChatSessionState,
42
42
  writeEgressAllowlist,
43
43
  writePersistentClaudeWrapper
44
- } from "./chunk-E3KBX3UW.js";
44
+ } from "./chunk-L24SX6LH.js";
45
45
  import "./chunk-XWVM4KPK.js";
46
46
  export {
47
47
  EGRESS_BASELINE_DOMAINS,
@@ -87,4 +87,4 @@ export {
87
87
  writeEgressAllowlist,
88
88
  writePersistentClaudeWrapper
89
89
  };
90
- //# sourceMappingURL=persistent-session-2ESCLFCK.js.map
90
+ //# sourceMappingURL=persistent-session-URCLTP7E.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  paneLogPath
3
- } from "./chunk-E3KBX3UW.js";
3
+ } from "./chunk-L24SX6LH.js";
4
4
  import "./chunk-XWVM4KPK.js";
5
5
 
6
6
  // src/lib/responsiveness-probe.ts
@@ -689,4 +689,4 @@ export {
689
689
  readAndResetSlackReplyBindingClassifications,
690
690
  readAndResetSlackReplyTargetClassifications
691
691
  };
692
- //# sourceMappingURL=responsiveness-probe-YCUDUCAS.js.map
692
+ //# sourceMappingURL=responsiveness-probe-RZIE5CVC.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@integrity-labs/agt-cli",
3
- "version": "0.28.576",
3
+ "version": "0.28.578",
4
4
  "description": "Augmented Team CLI — agent provisioning and management",
5
5
  "type": "module",
6
6
  "engines": {