@integrity-labs/agt-cli 0.28.1127 → 0.28.1129
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.
- package/dist/bin/agt.js +6 -6
- package/dist/{chunk-37PZYGGA.js → chunk-23GMWGOP.js} +3 -3
- package/dist/{chunk-7W5TLMFG.js → chunk-2YWHPXY7.js} +941 -378
- package/dist/chunk-2YWHPXY7.js.map +1 -0
- package/dist/{chunk-OCMJ5E6J.js → chunk-B6UYVEMD.js} +2 -1
- package/dist/chunk-B6UYVEMD.js.map +1 -0
- package/dist/{chunk-6J7WE4J4.js → chunk-JFABPA3Z.js} +44 -25
- package/dist/chunk-JFABPA3Z.js.map +1 -0
- package/dist/{claude-pair-runtime-H55GPDDO.js → claude-pair-runtime-LDJXKNWF.js} +3 -3
- package/dist/lib/manager-worker.js +336 -28
- package/dist/lib/manager-worker.js.map +1 -1
- package/dist/mcp/direct-chat-channel.js +237 -237
- package/dist/mcp/index.js +237 -237
- package/dist/mcp/origami.js +237 -237
- package/dist/mcp/slack-channel.js +243 -243
- package/dist/mcp/telegram-channel.js +237 -237
- package/dist/{persistent-session-D5O5MMNY.js → persistent-session-QSE66QYT.js} +4 -4
- package/dist/{responsiveness-probe-JJQ3AC5E.js → responsiveness-probe-NC4A3FCR.js} +4 -4
- package/dist/{session-auth-dead-WYJJYTQB.js → session-auth-dead-23ERZN4N.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-6J7WE4J4.js.map +0 -1
- package/dist/chunk-7W5TLMFG.js.map +0 -1
- package/dist/chunk-OCMJ5E6J.js.map +0 -1
- /package/dist/{chunk-37PZYGGA.js.map → chunk-23GMWGOP.js.map} +0 -0
- /package/dist/{claude-pair-runtime-H55GPDDO.js.map → claude-pair-runtime-LDJXKNWF.js.map} +0 -0
- /package/dist/{persistent-session-D5O5MMNY.js.map → persistent-session-QSE66QYT.js.map} +0 -0
- /package/dist/{responsiveness-probe-JJQ3AC5E.js.map → responsiveness-probe-NC4A3FCR.js.map} +0 -0
- /package/dist/{session-auth-dead-WYJJYTQB.js.map → session-auth-dead-23ERZN4N.js.map} +0 -0
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
consumerTermsOffKeys,
|
|
6
6
|
selectRowKeys
|
|
7
|
-
} from "./chunk-
|
|
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-
|
|
272
|
+
const { resolveClaudeBinary } = await import("./persistent-session-QSE66QYT.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-
|
|
742
|
+
//# sourceMappingURL=claude-pair-runtime-LDJXKNWF.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-
|
|
79
|
+
} from "../chunk-2YWHPXY7.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-
|
|
166
|
+
} from "../chunk-23GMWGOP.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-
|
|
277
|
+
} from "../chunk-JFABPA3Z.js";
|
|
272
278
|
import {
|
|
273
279
|
classifyUnanswerablePane,
|
|
274
|
-
|
|
275
|
-
|
|
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 =
|
|
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
|
|
4121
|
-
const isLoopback =
|
|
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
|
|
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 =
|
|
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 =
|
|
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-
|
|
14494
|
+
const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-NC4A3FCR.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.
|
|
15252
|
+
var agtCliVersion = true ? "0.28.1129" : "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-
|
|
16882
|
+
const { collectDiagnostics } = await import("../persistent-session-QSE66QYT.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-
|
|
17024
|
+
const { collectDiagnostics } = await import("../persistent-session-QSE66QYT.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-
|
|
17232
|
+
} = await import("../responsiveness-probe-NC4A3FCR.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-
|
|
17349
|
+
} = await import("../responsiveness-probe-NC4A3FCR.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-
|
|
17635
|
+
const { parkPendingInbound } = await import("../responsiveness-probe-NC4A3FCR.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-
|
|
17666
|
+
const { transcriptBindSourcesFor, ensureTranscriptBindSources } = await import("../persistent-session-QSE66QYT.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-
|
|
17831
|
+
const { probeSessionAuth } = await import("../session-auth-dead-23ERZN4N.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
|
-
|
|
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-
|
|
22426
|
+
const { parkPendingInbound: parkForRestart } = await import("../responsiveness-probe-NC4A3FCR.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-
|
|
22469
|
+
const { collectDiagnostics } = await import("../persistent-session-QSE66QYT.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-
|
|
22520
|
+
const { collectDiagnostics } = await import("../persistent-session-QSE66QYT.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-
|
|
23193
|
+
} = await import("../claude-pair-runtime-LDJXKNWF.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
|
-
|
|
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.
|