@integrity-labs/agt-cli 0.28.1127 → 0.28.1128

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.
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  consumerTermsOffKeys,
6
6
  selectRowKeys
7
- } from "./chunk-OCMJ5E6J.js";
7
+ } from "./chunk-B6UYVEMD.js";
8
8
  import {
9
9
  CLAUDE_CONFIG_DIR_ENV,
10
10
  claudeConfigDirFor,
@@ -269,7 +269,7 @@ async function spawnPairSession(session) {
269
269
  return { ok: true };
270
270
  } catch {
271
271
  }
272
- const { resolveClaudeBinary } = await import("./persistent-session-D5O5MMNY.js");
272
+ const { resolveClaudeBinary } = await import("./persistent-session-ICG7OHZM.js");
273
273
  const claudeBin = resolveClaudeBinary();
274
274
  const pairEnv = {
275
275
  ...process.env,
@@ -739,4 +739,4 @@ export {
739
739
  startClaudePair,
740
740
  submitClaudePairCode
741
741
  };
742
- //# sourceMappingURL=claude-pair-runtime-H55GPDDO.js.map
742
+ //# sourceMappingURL=claude-pair-runtime-AFNXHDMT.js.map
@@ -7,6 +7,7 @@ import {
7
7
  DEAD_CHANNEL_MS,
8
8
  FIRST_CONNECT_WINDOW_MS,
9
9
  HostFlagStore,
10
+ RM_POLICY_RELATIVE_PATH,
10
11
  RestartBreaker,
11
12
  SUPERVISOR_RESTART_EXIT_CODE,
12
13
  TunnelWatcher,
@@ -40,6 +41,7 @@ import {
40
41
  getCachedClaudeAuthModeRaw,
41
42
  getHostId,
42
43
  givenUpMcpServerKeys,
44
+ guardrailsForProvision,
43
45
  isIntegrationBucketedReason,
44
46
  isProvisioningReloadReason,
45
47
  isTransientAuthFailure,
@@ -49,6 +51,7 @@ import {
49
51
  markQuarantinedForProbe,
50
52
  migrateAgentDirToIdKeyed,
51
53
  mintAgentKey,
54
+ parseRmPolicy,
52
55
  pinAllowsUrgent,
53
56
  provision,
54
57
  provisionAutoKanbanProgressHook,
@@ -57,6 +60,7 @@ import {
57
60
  provisionLongCommandHook,
58
61
  provisionOrientHook,
59
62
  provisionPreCompactHook,
63
+ provisionRootRmHook,
60
64
  provisionSessionStateHook,
61
65
  provisionStopHook,
62
66
  readEnvNumber,
@@ -70,8 +74,9 @@ import {
70
74
  resolveEffectivePinRaw,
71
75
  safeWriteJsonAtomic,
72
76
  setConfigHash,
77
+ shellGuard,
73
78
  tripClass
74
- } from "../chunk-7W5TLMFG.js";
79
+ } from "../chunk-Q272XYOI.js";
75
80
  import {
76
81
  getProjectDir as getProjectDir2,
77
82
  getReadyTasks,
@@ -158,7 +163,7 @@ import {
158
163
  webFetchBaselineValue,
159
164
  webFetchRestartNeeded,
160
165
  writeEgressAllowlist
161
- } from "../chunk-37PZYGGA.js";
166
+ } from "../chunk-BUCSF5DF.js";
162
167
  import {
163
168
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
164
169
  AnchorSessionClient,
@@ -254,6 +259,7 @@ import {
254
259
  parseUsageReport,
255
260
  peekCurrentSession,
256
261
  pickNewerClassification,
262
+ redactPaneFrame,
257
263
  remoteMcpServerKey,
258
264
  resolveAgentTimezone,
259
265
  resolveAvatarEnvUrl,
@@ -268,11 +274,15 @@ import {
268
274
  subagentActivityAgeSeconds,
269
275
  sumTranscriptUsageInWindow,
270
276
  transcriptActivityAgeSeconds
271
- } from "../chunk-6J7WE4J4.js";
277
+ } from "../chunk-EVYDMDOY.js";
272
278
  import {
273
279
  classifyUnanswerablePane,
274
- paneRemedy
275
- } from "../chunk-OCMJ5E6J.js";
280
+ focusedConfirmDialogBlock,
281
+ isParkedOnToolPermissionPrompt,
282
+ paneRemedy,
283
+ sendDialogKeys,
284
+ simpleTextHash
285
+ } from "../chunk-B6UYVEMD.js";
276
286
  import {
277
287
  reapOrphanChannelMcps
278
288
  } from "../chunk-XWVM4KPK.js";
@@ -314,7 +324,7 @@ function defaultUnique() {
314
324
  // src/lib/manager-worker.ts
315
325
  import { execFileSync as syncExecFile } from "child_process";
316
326
  import { join as join43, dirname as dirname11, delimiter as pathDelimiter } from "path";
317
- import { homedir as homedir17, platform as platform3 } from "os";
327
+ import { homedir as homedir17, hostname, platform as platform3 } from "os";
318
328
  import { fileURLToPath as fileURLToPath2 } from "url";
319
329
 
320
330
  // ../../packages/core/dist/provisioning/channel-policy-env.js
@@ -822,6 +832,237 @@ var AnchorSessionLifecycle = class {
822
832
  }
823
833
  };
824
834
 
835
+ // src/lib/dangerous-rm-backstop.ts
836
+ import { lstatSync } from "fs";
837
+ var BACKSTOP_AFTER_MS = 2 * 6e4;
838
+ var MAX_ANSWERS_PER_PROMPT = 3;
839
+ var DANGEROUS_RM_LINE = /Dangerous rm operation\b/;
840
+ var SEARCH_LINES = 40;
841
+ var STANDARD_ROOT_ENTRIES = /* @__PURE__ */ new Set([
842
+ "vmlinuz",
843
+ "vmlinuz.old",
844
+ "initrd.img",
845
+ "initrd.img.old",
846
+ "swapfile",
847
+ "swap.img",
848
+ ".autorelabel",
849
+ "bin",
850
+ "boot",
851
+ "dev",
852
+ "etc",
853
+ "home",
854
+ "lib",
855
+ "lib32",
856
+ "lib64",
857
+ "libx32",
858
+ "lost+found",
859
+ "media",
860
+ "mnt",
861
+ "opt",
862
+ "proc",
863
+ "root",
864
+ "run",
865
+ "sbin",
866
+ "snap",
867
+ "srv",
868
+ "sys",
869
+ "tmp",
870
+ "usr",
871
+ "var"
872
+ ]);
873
+ function stripBox(line) {
874
+ return line.replace(/^\s*│ ?/, "").replace(/\s*│\s*$/, "");
875
+ }
876
+ function readDangerousRmPrompt(pane) {
877
+ if (!pane || !isParkedOnToolPermissionPrompt(pane)) return null;
878
+ const block = focusedConfirmDialogBlock(pane);
879
+ if (!block) return null;
880
+ const lines = pane.split("\n");
881
+ const footer = lines.lastIndexOf(block[block.length - 1]);
882
+ if (footer < 0) return null;
883
+ let head = -1;
884
+ for (let i = footer; i >= Math.max(0, footer - SEARCH_LINES); i--) {
885
+ if (DANGEROUS_RM_LINE.test(lines[i])) {
886
+ head = i;
887
+ break;
888
+ }
889
+ }
890
+ if (head < 0) return null;
891
+ const reasonParts = [stripBox(lines[head]).replace(/^.*Dangerous rm operation\s*(?:on\s*)?/, "")];
892
+ for (let i = head + 1; i < footer; i++) {
893
+ const t = stripBox(lines[i]).trim();
894
+ if (!t || /^Do you want to proceed\?/.test(t)) break;
895
+ reasonParts.push(t);
896
+ }
897
+ const reason = reasonParts.join(" ").trim();
898
+ let commandLines = null;
899
+ for (let i = head - 1; i >= Math.max(0, head - SEARCH_LINES); i--) {
900
+ if (lines[i].trim() === "Bash command") {
901
+ const cmd = [];
902
+ for (let j = i + 1; j < head; j++) {
903
+ if (!/^\s*│/.test(lines[j])) break;
904
+ cmd.push(stripBox(lines[j]));
905
+ }
906
+ if (cmd.length) commandLines = cmd;
907
+ break;
908
+ }
909
+ }
910
+ const key = simpleTextHash([reason, ...commandLines ?? [], ...block].join("\n"));
911
+ return { reason, commandLines, key };
912
+ }
913
+ function judgeReading(command) {
914
+ const a = shellGuard.analyze(command);
915
+ if (!a.ok || a.heredoc || a.substitution || a.findDelete) return { rule: "unparseable", target: null };
916
+ if (a.rm.length !== 1) return { rule: "not-single-rm", target: null };
917
+ const inv = a.rm[0];
918
+ if (inv.targetsUnknown) return { rule: "unresolved-target", target: null };
919
+ if (inv.recursive) return { rule: "recursive", target: null };
920
+ if (inv.targets.length !== 1) return { rule: "multiple-targets", target: null };
921
+ const t = inv.targets[0];
922
+ if (t.expansion || t.glob || t.tilde) return { rule: "unresolved-target", target: null };
923
+ if (!/^\/[^/]+$/.test(t.text)) return { rule: "not-root-level", target: null };
924
+ if (STANDARD_ROOT_ENTRIES.has(t.text.slice(1))) return { rule: "standard-root-entry", target: t.text };
925
+ return { rule: "single-root-file", target: t.text };
926
+ }
927
+ var MAX_YES_COMMAND_LINES = 6;
928
+ function looksElided(lines) {
929
+ if (lines.length > MAX_YES_COMMAND_LINES) return true;
930
+ return lines.some((l) => /…|\.\.\.\s*$|\+\s*\d+\s+(?:more\s+)?lines?\b/i.test(l));
931
+ }
932
+ function commandReadings(lines) {
933
+ if (lines.length === 1) return [lines[0]];
934
+ return [lines.join(""), lines.join(" "), lines.join("\n")];
935
+ }
936
+ function decideDangerousRm(prompt, policy, opts = {}) {
937
+ const lstat = opts.lstat ?? lstatSync;
938
+ const command = prompt.commandLines ? commandReadings(prompt.commandLines)[0] : null;
939
+ const no = (rule, alert, target2 = null) => ({
940
+ answer: "no",
941
+ rule,
942
+ alert,
943
+ command,
944
+ target: target2
945
+ });
946
+ if (policy === null) return no("policy-unknown", true);
947
+ if (policy.no_delete) return no("no-delete-guardrail", false);
948
+ if (!prompt.commandLines) return no("command-not-visible", true);
949
+ if (looksElided(prompt.commandLines)) return no("command-elided", true);
950
+ const verdicts = commandReadings(prompt.commandLines).map(judgeReading);
951
+ const first = verdicts[0];
952
+ if (first.rule !== "single-root-file") return no(first.rule, true, first.target);
953
+ if (!verdicts.every((v) => v.rule === "single-root-file" && v.target === first.target)) {
954
+ return no("unparseable", true);
955
+ }
956
+ const target = first.target;
957
+ if (!/^critical path:/.test(prompt.reason) || !prompt.reason.endsWith(`: ${target}`)) {
958
+ return no("reason-mismatch", true, target);
959
+ }
960
+ if (opts.isolated) return no("isolated-agent", false, target);
961
+ try {
962
+ if (!lstat(target).isFile()) return no("not-regular-file", true, target);
963
+ } catch {
964
+ return no("not-regular-file", true, target);
965
+ }
966
+ return { answer: "yes", rule: "single-root-file", alert: false, command, target };
967
+ }
968
+ var OPTION_ROW = /^\s*(❯\s*)?(\d)\.\s+(.*?)\s*$/;
969
+ function promptAnswerKeys(pane, answer) {
970
+ const block = focusedConfirmDialogBlock(pane);
971
+ if (!block) return answer === "no" ? ["Escape"] : null;
972
+ let cursor = -1;
973
+ let target = -1;
974
+ for (let i = 0; i < block.length; i++) {
975
+ const m = OPTION_ROW.exec(block[i]);
976
+ if (!m) continue;
977
+ if (m[1]) cursor = i;
978
+ const label = m[3];
979
+ if (target < 0 && (answer === "yes" ? label === "Yes" : /^No\b/.test(label))) target = i;
980
+ }
981
+ if (cursor < 0 || target < 0) return answer === "no" ? ["Escape"] : null;
982
+ const d = target - cursor;
983
+ return [...Array(Math.abs(d)).fill(d > 0 ? "Down" : "Up"), "Enter"];
984
+ }
985
+ var DangerousRmBackstop = class {
986
+ episodes = /* @__PURE__ */ new Map();
987
+ observe(agent, pane, now) {
988
+ const prompt = readDangerousRmPrompt(pane);
989
+ if (!prompt) {
990
+ if (pane) this.episodes.delete(agent);
991
+ return null;
992
+ }
993
+ const ep = this.episodes.get(agent);
994
+ if (!ep || ep.key !== prompt.key) {
995
+ this.episodes.set(agent, {
996
+ key: prompt.key,
997
+ firstSeen: now,
998
+ answeredAt: null,
999
+ answers: 0,
1000
+ inFlight: false,
1001
+ reportedStuck: false,
1002
+ reportedDispatchFailure: false
1003
+ });
1004
+ return null;
1005
+ }
1006
+ if (ep.inFlight) return null;
1007
+ if (ep.answeredAt !== null) {
1008
+ if (now - ep.answeredAt < BACKSTOP_AFTER_MS) return null;
1009
+ if (ep.answers >= MAX_ANSWERS_PER_PROMPT) {
1010
+ if (ep.reportedStuck) return null;
1011
+ ep.reportedStuck = true;
1012
+ return { kind: "still-parked", prompt, sinceAnswerMs: now - ep.answeredAt, answers: ep.answers };
1013
+ }
1014
+ ep.inFlight = true;
1015
+ return { kind: "answer", prompt, waitedMs: now - ep.answeredAt };
1016
+ }
1017
+ if (now - ep.firstSeen < BACKSTOP_AFTER_MS) return null;
1018
+ ep.inFlight = true;
1019
+ return { kind: "answer", prompt, waitedMs: now - ep.firstSeen };
1020
+ }
1021
+ /** The keys for `key` were sent: this prompt is answered. */
1022
+ answered(agent, key, now) {
1023
+ const ep = this.episodes.get(agent);
1024
+ if (!ep || ep.key !== key) return;
1025
+ ep.inFlight = false;
1026
+ ep.answeredAt = now;
1027
+ ep.answers += 1;
1028
+ }
1029
+ /**
1030
+ * Sending failed: release the reservation so a later sweep retries. Returns
1031
+ * true the FIRST time for this prompt, so the caller alerts once rather than
1032
+ * on every ~10s retry.
1033
+ */
1034
+ dispatchFailed(agent, key) {
1035
+ const ep = this.episodes.get(agent);
1036
+ if (!ep || ep.key !== key) return false;
1037
+ ep.inFlight = false;
1038
+ if (ep.reportedDispatchFailure) return false;
1039
+ ep.reportedDispatchFailure = true;
1040
+ return true;
1041
+ }
1042
+ forget(agent) {
1043
+ this.episodes.delete(agent);
1044
+ }
1045
+ };
1046
+ function planAnswer(pane, decision) {
1047
+ const keys = promptAnswerKeys(pane, decision.answer);
1048
+ if (keys) return { decision, keys };
1049
+ return {
1050
+ decision: { ...decision, answer: "no", rule: "yes-row-unreadable", alert: true },
1051
+ keys: promptAnswerKeys(pane, "no") ?? ["Escape"]
1052
+ };
1053
+ }
1054
+ function readRmPolicyText(read) {
1055
+ try {
1056
+ return parseRmPolicy(read());
1057
+ } catch {
1058
+ return null;
1059
+ }
1060
+ }
1061
+ function describeDecision(codeName, host, decision, waitedMs, attempted = false) {
1062
+ const cmd = decision.command === null ? "(command not visible in the pane)" : JSON.stringify(decision.command);
1063
+ return `host ${host}, agent ${codeName}: ${attempted ? "tried to answer" : "answered"} ${decision.answer === "yes" ? "Yes" : "No"} to Claude Code's "Dangerous rm operation" prompt after ${Math.round(waitedMs / 1e3)}s unanswered (rule ${decision.rule}). Command: ${cmd}`;
1064
+ }
1065
+
825
1066
  // src/lib/channel-restart-decision.ts
826
1067
  function launchableChannelIds(channelConfigs) {
827
1068
  if (!channelConfigs) return /* @__PURE__ */ new Set();
@@ -2728,7 +2969,7 @@ function provisionReviewPoster(codeName, sourceDir = resolveBundledReviewAssetDi
2728
2969
  }
2729
2970
 
2730
2971
  // src/lib/id-keyed-migration.ts
2731
- import { existsSync as existsSync3, lstatSync, readlinkSync, renameSync as renameSync2 } from "fs";
2972
+ import { existsSync as existsSync3, lstatSync as lstatSync2, readlinkSync, renameSync as renameSync2 } from "fs";
2732
2973
  import { join as join10 } from "path";
2733
2974
  import { homedir as homedir3 } from "os";
2734
2975
  var ID_KEYED_MIGRATION_FLAG = "id-keyed-layout-migration";
@@ -2775,7 +3016,7 @@ function maybeMigrateAgentToIdKeyedLayout(agent, deps) {
2775
3016
  const newCwd = join10(idPath, "project");
2776
3017
  let codeNameKind;
2777
3018
  try {
2778
- codeNameKind = lstatSync(codeNamePath).isSymbolicLink() ? "symlink" : "realdir";
3019
+ codeNameKind = lstatSync2(codeNamePath).isSymbolicLink() ? "symlink" : "realdir";
2779
3020
  } catch {
2780
3021
  codeNameKind = "absent";
2781
3022
  }
@@ -4117,8 +4358,8 @@ var DEFAULT_LOCAL_EVAL_MODEL = "gemma4:12b";
4117
4358
  var EVAL_TIMEOUT_MS = 12e4;
4118
4359
  async function runLocalEvalChat(prompt, opts) {
4119
4360
  const endpoint = new URL(opts.url);
4120
- const hostname = endpoint.hostname.toLowerCase();
4121
- const isLoopback = hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1" || hostname === "[::1]";
4361
+ const hostname2 = endpoint.hostname.toLowerCase();
4362
+ const isLoopback = hostname2 === "localhost" || hostname2 === "127.0.0.1" || hostname2 === "::1" || hostname2 === "[::1]";
4122
4363
  if (!isLoopback) {
4123
4364
  throw new Error(`local eval url must be loopback-only, got host '${endpoint.hostname}'`);
4124
4365
  }
@@ -7874,7 +8115,7 @@ function resolveModelChain(refreshData) {
7874
8115
  }
7875
8116
 
7876
8117
  // src/lib/manager/claude-auth.ts
7877
- import { chmodSync as chmodSync2, existsSync as existsSync14, lstatSync as lstatSync2, mkdirSync as mkdirSync11, rmSync as rmSync6 } from "fs";
8118
+ import { chmodSync as chmodSync2, existsSync as existsSync14, lstatSync as lstatSync3, mkdirSync as mkdirSync11, rmSync as rmSync6 } from "fs";
7878
8119
  import { join as join34 } from "path";
7879
8120
  import { homedir as homedir13 } from "os";
7880
8121
  async function applyClaudeAuthToEnv(childEnv, label, options = {}) {
@@ -7913,13 +8154,13 @@ function claudeConfigDirForChild(childEnv) {
7913
8154
  }
7914
8155
  function ensurePrivateConfigDir(dir, platform4 = process.platform, chmod = chmodSync2) {
7915
8156
  mkdirSync11(dir, { recursive: true, mode: 448 });
7916
- const st = lstatSync2(dir);
8157
+ const st = lstatSync3(dir);
7917
8158
  if (!st.isDirectory()) {
7918
8159
  throw new Error(`isolated Claude config dir ${dir} is not a real directory (symlink or file); refusing`);
7919
8160
  }
7920
8161
  if (platform4 === "win32") return;
7921
8162
  if ((st.mode & 511) !== 448) chmod(dir, 448);
7922
- const mode = lstatSync2(dir).mode & 511;
8163
+ const mode = lstatSync3(dir).mode & 511;
7923
8164
  if (mode !== 448) {
7924
8165
  throw new Error(`isolated Claude config dir ${dir} could not be made private (mode ${mode.toString(8)}); refusing`);
7925
8166
  }
@@ -13511,6 +13752,64 @@ async function reportReaperEvent(agentId, reaper, action, reason) {
13511
13752
  );
13512
13753
  }
13513
13754
  }
13755
+ var dangerousRmBackstop = new DangerousRmBackstop();
13756
+ async function runDangerousRmBackstop(agentId, codeName, pane) {
13757
+ let action = null;
13758
+ try {
13759
+ action = dangerousRmBackstop.observe(codeName, pane, Date.now());
13760
+ if (!action || pane === null) return;
13761
+ const host = hostname();
13762
+ const scrub = (s) => {
13763
+ const r = redactPaneFrame(s);
13764
+ return r.length > 400 ? `${r.slice(0, 399)}\u2026` : r;
13765
+ };
13766
+ if (action.kind === "still-parked") {
13767
+ const msg = `host ${host}, agent ${codeName}: the same "Dangerous rm operation" prompt is on screen after the backstop answered it ${action.answers} times (last ${Math.round(action.sinceAnswerMs / 1e3)}s ago), so either the keys are not landing or the agent keeps re-running the command; not answering again`;
13768
+ log(`[dangerous-rm-backstop] ${msg}`);
13769
+ void reportReaperEvent(agentId, "dangerous-rm-backstop", "alert", msg);
13770
+ return;
13771
+ }
13772
+ const policy = readRmPolicyText(
13773
+ () => readFileSync34(join43(getFramework("claude-code").getAgentDir(codeName), RM_POLICY_RELATIVE_PATH), "utf-8")
13774
+ );
13775
+ const decision = decideDangerousRm(action.prompt, policy, {
13776
+ isolated: isolationMode(codeName) === "docker"
13777
+ });
13778
+ const shown = { ...decision, command: decision.command === null ? null : scrub(decision.command) };
13779
+ const plan = planAnswer(pane, decision);
13780
+ const final = plan.decision;
13781
+ const line = describeDecision(codeName, host, { ...final, command: shown.command }, action.waitedMs);
13782
+ try {
13783
+ await sendDialogKeys(`agt-${codeName}`, {
13784
+ kind: "dangerous-rm-backstop",
13785
+ keys: plan.keys,
13786
+ interKeyDelayMs: 150,
13787
+ logMessage: `Answered ${final.answer} to a dangerous-rm prompt`
13788
+ });
13789
+ } catch (err) {
13790
+ const first = dangerousRmBackstop.dispatchFailed(codeName, action.prompt.key);
13791
+ const tried = describeDecision(codeName, host, { ...final, command: shown.command }, action.waitedMs, true);
13792
+ log(`[dangerous-rm-backstop] ${tried} - SEND FAILED, will retry: ${err.message}`);
13793
+ if (first) {
13794
+ void reportReaperEvent(
13795
+ agentId,
13796
+ "dangerous-rm-backstop",
13797
+ "alert",
13798
+ `${tried} - the keys could not be sent, so the prompt is still up; retrying`
13799
+ );
13800
+ }
13801
+ return;
13802
+ }
13803
+ dangerousRmBackstop.answered(codeName, action.prompt.key, Date.now());
13804
+ log(
13805
+ `[dangerous-rm-backstop] ${line} (keys ${plan.keys.join(" ")}${policy?.sources.length ? `; guardrails ${policy.sources.join(", ")}` : ""})`
13806
+ );
13807
+ if (final.alert) void reportReaperEvent(agentId, "dangerous-rm-backstop", "alert", line);
13808
+ } catch (err) {
13809
+ if (action?.kind === "answer") dangerousRmBackstop.dispatchFailed(codeName, action.prompt.key);
13810
+ log(`[dangerous-rm-backstop] ${codeName}: failed (suppressed): ${err.message}`);
13811
+ }
13812
+ }
13514
13813
  function recordRestartForBreaker(codeName, reason) {
13515
13814
  if (reason === "managed-mcp-churn" && mcpFlapDampener.flappedWithin(codeName, FLAP_CHANNEL_MANAGED_MCP, FLAP_BREAKER_COOLDOWN_MS)) {
13516
13815
  log(
@@ -14192,7 +14491,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
14192
14491
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
14193
14492
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
14194
14493
  async function channelInboundActivityAgeSecondsFor(codeName) {
14195
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-JJQ3AC5E.js");
14494
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-HRMY4TOT.js");
14196
14495
  const newest = newestPendingInboundActivityMtimeMs(dirname11(paneLogPath(codeName)));
14197
14496
  if (newest === null) return null;
14198
14497
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -14950,7 +15249,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
14950
15249
  var lastVersionCheckAt = 0;
14951
15250
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
14952
15251
  var lastResponsivenessProbeAt = 0;
14953
- var agtCliVersion = true ? "0.28.1127" : "dev";
15252
+ var agtCliVersion = true ? "0.28.1128" : "dev";
14954
15253
  function resolveBrewPath(execFileSync3) {
14955
15254
  try {
14956
15255
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -16580,7 +16879,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
16580
16879
  if (codeNames.length === 0) return;
16581
16880
  void (async () => {
16582
16881
  try {
16583
- const { collectDiagnostics } = await import("../persistent-session-D5O5MMNY.js");
16882
+ const { collectDiagnostics } = await import("../persistent-session-ICG7OHZM.js");
16584
16883
  await api.post("/host/heartbeat", {
16585
16884
  host_id: hostId,
16586
16885
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor)
@@ -16722,7 +17021,7 @@ async function pollCycleInner() {
16722
17021
  }
16723
17022
  try {
16724
17023
  const { detectHostSecurity } = await import("../host-security-KQYYZZVW.js");
16725
- const { collectDiagnostics } = await import("../persistent-session-D5O5MMNY.js");
17024
+ const { collectDiagnostics } = await import("../persistent-session-ICG7OHZM.js");
16726
17025
  const diagCodeNames = [...agentState.persistentSessionAgents];
16727
17026
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor) : void 0;
16728
17027
  let tailscaleHostname;
@@ -16930,7 +17229,7 @@ async function pollCycleInner() {
16930
17229
  collectPanelessActivityProbes,
16931
17230
  getResponsivenessIntervalMs,
16932
17231
  occupancyQualificationClassifications
16933
- } = await import("../responsiveness-probe-JJQ3AC5E.js");
17232
+ } = await import("../responsiveness-probe-HRMY4TOT.js");
16934
17233
  const probeIntervalMs = getResponsivenessIntervalMs();
16935
17234
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
16936
17235
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -17047,7 +17346,7 @@ async function pollCycleInner() {
17047
17346
  collectResponsivenessProbes,
17048
17347
  livePendingInboundOldestAgeSeconds,
17049
17348
  parkPendingInbound
17050
- } = await import("../responsiveness-probe-JJQ3AC5E.js");
17349
+ } = await import("../responsiveness-probe-HRMY4TOT.js");
17051
17350
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-M6AFZWNU.js");
17052
17351
  const wedgeNow = /* @__PURE__ */ new Date();
17053
17352
  const liveAgents = agentState.persistentSessionAgents;
@@ -17333,7 +17632,7 @@ async function pollCycleInner() {
17333
17632
  }
17334
17633
  }
17335
17634
  );
17336
- const { parkPendingInbound } = await import("../responsiveness-probe-JJQ3AC5E.js");
17635
+ const { parkPendingInbound } = await import("../responsiveness-probe-HRMY4TOT.js");
17337
17636
  const { parked, deadLettered } = parkPendingInbound(codeName, new Date(fatalNowMs));
17338
17637
  paneFatalStreak.delete(codeName);
17339
17638
  paneFatalRestarts.set(codeName, [...history, fatalNowMs]);
@@ -17364,7 +17663,7 @@ async function pollCycleInner() {
17364
17663
  TRANSCRIPT_MOUNT_ESCALATION_REFRESH_MS,
17365
17664
  bindSourceEscalations
17366
17665
  } = await import("../transcript-mount-health-OHE6IVJV.js");
17367
- const { transcriptBindSourcesFor, ensureTranscriptBindSources } = await import("../persistent-session-D5O5MMNY.js");
17666
+ const { transcriptBindSourcesFor, ensureTranscriptBindSources } = await import("../persistent-session-ICG7OHZM.js");
17368
17667
  const mountConfig = resolveTranscriptMountConfig();
17369
17668
  const liveAgents = agentState.persistentSessionAgents;
17370
17669
  for (const tracked of [
@@ -17529,7 +17828,7 @@ async function pollCycleInner() {
17529
17828
  }
17530
17829
  try {
17531
17830
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-VR5QGP3J.js");
17532
- const { probeSessionAuth } = await import("../session-auth-dead-WYJJYTQB.js");
17831
+ const { probeSessionAuth } = await import("../session-auth-dead-DCS7IE2F.js");
17533
17832
  const observations = [];
17534
17833
  const pendingCacheCommits = [];
17535
17834
  const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
@@ -17817,16 +18116,19 @@ async function pollCycleInner() {
17817
18116
  omittedNoSession += 1;
17818
18117
  continue;
17819
18118
  }
18119
+ let sweptPane = null;
17820
18120
  const observation = observeBlockedPrompt(agent.code_name, true, (codeName) => {
17821
18121
  try {
17822
- return syncExecFile("tmux", ["capture-pane", "-t", `agt-${codeName}`, "-p"], {
18122
+ sweptPane = syncExecFile("tmux", ["capture-pane", "-t", `agt-${codeName}`, "-p"], {
17823
18123
  stdio: ["ignore", "pipe", "ignore"],
17824
18124
  timeout: 2e3
17825
18125
  }).toString();
18126
+ return sweptPane;
17826
18127
  } catch {
17827
18128
  return null;
17828
18129
  }
17829
18130
  });
18131
+ void runDangerousRmBackstop(agent.agent_id, agent.code_name, sweptPane);
17830
18132
  const { observation: settled, cost } = blockedPromptCost.settle(
17831
18133
  agent.code_name,
17832
18134
  observation
@@ -21591,6 +21893,11 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash20("sha256")
21591
21893
  } catch (err) {
21592
21894
  log(`[persistent-session] Failed to provision long-command hook for '${codeName}': ${err.message}`);
21593
21895
  }
21896
+ try {
21897
+ provisionRootRmHook(codeName);
21898
+ } catch (err) {
21899
+ log(`[persistent-session] Failed to provision root-rm hook for '${codeName}': ${err.message}`);
21900
+ }
21594
21901
  try {
21595
21902
  provisionSessionStateHook(codeName);
21596
21903
  } catch (err) {
@@ -22116,7 +22423,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
22116
22423
  try {
22117
22424
  const freshId = rotateSessionForWedge(codeName);
22118
22425
  consecutiveWedgeCycles.delete(codeName);
22119
- const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-JJQ3AC5E.js");
22426
+ const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-HRMY4TOT.js");
22120
22427
  const { parked, deadLettered } = parkForRestart(codeName, /* @__PURE__ */ new Date());
22121
22428
  const parkNote = parked > 0 ? `, ${parked} inbound parked` : "";
22122
22429
  const deadNote = deadLettered > 0 ? `, ${deadLettered} undeliverable dead-lettered` : "";
@@ -22159,7 +22466,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
22159
22466
  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}`));
22160
22467
  void (async () => {
22161
22468
  try {
22162
- const { collectDiagnostics } = await import("../persistent-session-D5O5MMNY.js");
22469
+ const { collectDiagnostics } = await import("../persistent-session-ICG7OHZM.js");
22163
22470
  await api.post("/host/heartbeat", {
22164
22471
  host_id: hostId,
22165
22472
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor)
@@ -22210,7 +22517,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
22210
22517
  }
22211
22518
  try {
22212
22519
  const hostId = await getHostId();
22213
- const { collectDiagnostics } = await import("../persistent-session-D5O5MMNY.js");
22520
+ const { collectDiagnostics } = await import("../persistent-session-ICG7OHZM.js");
22214
22521
  await api.post("/host/heartbeat", {
22215
22522
  host_id: hostId,
22216
22523
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor, runtimeVersionFor)
@@ -22883,7 +23190,7 @@ async function processClaudePairSessions(agents) {
22883
23190
  // cannot take it for itself — by the time it runs, the write it is looking
22884
23191
  // for may already have happened.
22885
23192
  snapshotPairConfig
22886
- } = await import("../claude-pair-runtime-H55GPDDO.js");
23193
+ } = await import("../claude-pair-runtime-AFNXHDMT.js");
22887
23194
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
22888
23195
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
22889
23196
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -23133,7 +23440,8 @@ function generateArtifacts(agent, refreshData, adapter, renderIntegrationsSectio
23133
23440
  knowledgeDelivery: refreshData.agent.knowledge_delivery ?? "both",
23134
23441
  teamMembers: refreshData.team_members ?? void 0,
23135
23442
  people: refreshData.people ?? void 0,
23136
- guardrails: refreshData.guardrails,
23443
+ // ENG-11513: a failed resolution becomes undefined (unknown), not [] (none).
23444
+ guardrails: guardrailsForProvision(refreshData.guardrails, refreshData.guardrails_resolved),
23137
23445
  // ENG-9862: standing rules (ENG-9789), threaded exactly like guardrails so
23138
23446
  // the claude-code adapter can render them into CLAUDE.md. Absent on an
23139
23447
  // older API renders nothing, which is the documented fail-direction.