@integrity-labs/agt-cli 0.28.725 → 0.28.727

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-CEC5KESY.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-LP7JOGZ5.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-XWPOUQMP.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-42GBPDC7.js.map
@@ -57,7 +57,7 @@ import {
57
57
  safeWriteJsonAtomic,
58
58
  setConfigHash,
59
59
  tripClass
60
- } from "../chunk-MHB3SEYC.js";
60
+ } from "../chunk-65RGJKFR.js";
61
61
  import {
62
62
  getProjectDir as getProjectDir2,
63
63
  getReadyTasks,
@@ -90,8 +90,11 @@ import {
90
90
  isolationMode,
91
91
  log,
92
92
  mergeOpencodeConfigArtifact,
93
+ modelPolicyAuthComponent,
94
+ modelPolicyEgressDomains,
93
95
  paneLogPath,
94
96
  parseEnvIntegrations,
97
+ parseModelPolicy,
95
98
  prepareForRespawn,
96
99
  readChannelServerEnv,
97
100
  readDirectChatSessionState,
@@ -115,7 +118,7 @@ import {
115
118
  takeZombieDetection,
116
119
  toOpencodeModel,
117
120
  writeEgressAllowlist
118
- } from "../chunk-ATJU3SDV.js";
121
+ } from "../chunk-ZCTFF4PA.js";
119
122
  import {
120
123
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
121
124
  AnchorSessionClient,
@@ -2880,21 +2883,29 @@ var COMPONENT_ORDER = [
2880
2883
  "auth_mode",
2881
2884
  "anthropic_api_key_fingerprint",
2882
2885
  "claude_account_fingerprint",
2883
- "openrouter_fingerprint"
2886
+ "openrouter_fingerprint",
2887
+ // ENG-9483 slice 2: `<policyId>@<revision>` from modelPolicyAuthComponent.
2888
+ // Non-secret: a uuid the operator chose plus an integer they can see in the UI.
2889
+ "model_policy"
2884
2890
  ];
2891
+ var POLICY_TUPLE_SEPARATOR = "|policy=";
2885
2892
  function parseAuthTuple(tuple) {
2886
- const raw = typeof tuple === "string" ? tuple : "";
2893
+ const full = typeof tuple === "string" ? tuple : "";
2894
+ const sepAt = full.lastIndexOf(POLICY_TUPLE_SEPARATOR);
2895
+ const raw = sepAt === -1 ? full : full.slice(0, sepAt);
2896
+ const policy = sepAt === -1 ? null : full.slice(sepAt + POLICY_TUPLE_SEPARATOR.length) || ABSENT2;
2897
+ const withPolicy = (r) => policy === null ? r : { ...r, model_policy: policy };
2887
2898
  if (raw.startsWith("openrouter:")) {
2888
- return {
2899
+ return withPolicy({
2889
2900
  auth_mode: "openrouter",
2890
2901
  openrouter_fingerprint: raw.slice("openrouter:".length) || ABSENT2
2891
- };
2902
+ });
2892
2903
  }
2893
2904
  const parts = raw.split(":");
2894
2905
  if (parts.length < 2) {
2895
- return { auth_mode: raw || ABSENT2 };
2906
+ return withPolicy({ auth_mode: raw || ABSENT2 });
2896
2907
  }
2897
- return {
2908
+ return withPolicy({
2898
2909
  auth_mode: parts[0] || ABSENT2,
2899
2910
  anthropic_api_key_fingerprint: parts[1] || ABSENT2,
2900
2911
  // Omitted from the string when there is no signed-in account fingerprint
@@ -2902,7 +2913,19 @@ function parseAuthTuple(tuple) {
2902
2913
  // Recorded as the ABSENT sentinel so "account appeared" / "account
2903
2914
  // disappeared" is itself visible as a change.
2904
2915
  claude_account_fingerprint: parts[2] || ABSENT2
2905
- };
2916
+ });
2917
+ }
2918
+ function buildAuthTuple(input) {
2919
+ const {
2920
+ openRouterCredential,
2921
+ claudeAuthMode,
2922
+ anthropicApiKeyFingerprint,
2923
+ claudeAccountFingerprint,
2924
+ modelPolicyComponent
2925
+ } = input;
2926
+ const suffix = modelPolicyComponent ? `${POLICY_TUPLE_SEPARATOR}${modelPolicyComponent}` : "";
2927
+ if (openRouterCredential) return `openrouter:${openRouterCredential}${suffix}`;
2928
+ return `${claudeAuthMode}:${anthropicApiKeyFingerprint ?? ABSENT2}${claudeAccountFingerprint ? `:${claudeAccountFingerprint}` : ""}${suffix}`;
2906
2929
  }
2907
2930
  function diffAuthTuples(recorded, current) {
2908
2931
  const before = parseAuthTuple(recorded);
@@ -5480,6 +5503,28 @@ async function resolveIntegrationSkillsFromManifest(args) {
5480
5503
  return out;
5481
5504
  }
5482
5505
 
5506
+ // src/lib/kanban-board-fetch.ts
5507
+ function createTickBoardFetcher(fetchBoard) {
5508
+ let resolved = null;
5509
+ let inflight = null;
5510
+ return () => {
5511
+ if (resolved) return Promise.resolve(resolved.value);
5512
+ if (inflight) return inflight;
5513
+ inflight = fetchBoard().then(
5514
+ (value) => {
5515
+ resolved = { value };
5516
+ inflight = null;
5517
+ return value;
5518
+ },
5519
+ (err) => {
5520
+ inflight = null;
5521
+ throw err;
5522
+ }
5523
+ );
5524
+ return inflight;
5525
+ };
5526
+ }
5527
+
5483
5528
  // src/lib/channel-hash-cache.ts
5484
5529
  import { existsSync as existsSync8, readFileSync as readFileSync19, writeFileSync as writeFileSync10 } from "fs";
5485
5530
  import { join as join25 } from "path";
@@ -12243,7 +12288,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
12243
12288
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
12244
12289
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
12245
12290
  async function channelInboundActivityAgeSecondsFor(codeName) {
12246
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-J3VB4U4W.js");
12291
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-TTHNHBBS.js");
12247
12292
  const newest = newestPendingInboundActivityMtimeMs(dirname10(paneLogPath(codeName)));
12248
12293
  if (newest === null) return null;
12249
12294
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -12891,7 +12936,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
12891
12936
  var lastVersionCheckAt = 0;
12892
12937
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
12893
12938
  var lastResponsivenessProbeAt = 0;
12894
- var agtCliVersion = true ? "0.28.725" : "dev";
12939
+ var agtCliVersion = true ? "0.28.727" : "dev";
12895
12940
  function resolveBrewPath(execFileSync3) {
12896
12941
  try {
12897
12942
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -14418,7 +14463,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
14418
14463
  if (codeNames.length === 0) return;
14419
14464
  void (async () => {
14420
14465
  try {
14421
- const { collectDiagnostics } = await import("../persistent-session-CEC5KESY.js");
14466
+ const { collectDiagnostics } = await import("../persistent-session-LP7JOGZ5.js");
14422
14467
  await api.post("/host/heartbeat", {
14423
14468
  host_id: hostId,
14424
14469
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -14536,7 +14581,7 @@ async function pollCycleInner() {
14536
14581
  }
14537
14582
  try {
14538
14583
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
14539
- const { collectDiagnostics } = await import("../persistent-session-CEC5KESY.js");
14584
+ const { collectDiagnostics } = await import("../persistent-session-LP7JOGZ5.js");
14540
14585
  const diagCodeNames = [...agentState.persistentSessionAgents];
14541
14586
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor) : void 0;
14542
14587
  let tailscaleHostname;
@@ -14705,7 +14750,7 @@ async function pollCycleInner() {
14705
14750
  collectPanelessActivityProbes,
14706
14751
  getResponsivenessIntervalMs,
14707
14752
  occupancyQualificationClassifications
14708
- } = await import("../responsiveness-probe-J3VB4U4W.js");
14753
+ } = await import("../responsiveness-probe-TTHNHBBS.js");
14709
14754
  const probeIntervalMs = getResponsivenessIntervalMs();
14710
14755
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
14711
14756
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -14815,7 +14860,7 @@ async function pollCycleInner() {
14815
14860
  collectResponsivenessProbes,
14816
14861
  livePendingInboundOldestAgeSeconds,
14817
14862
  parkPendingInbound
14818
- } = await import("../responsiveness-probe-J3VB4U4W.js");
14863
+ } = await import("../responsiveness-probe-TTHNHBBS.js");
14819
14864
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
14820
14865
  const wedgeNow = /* @__PURE__ */ new Date();
14821
14866
  const liveAgents = agentState.persistentSessionAgents;
@@ -17329,13 +17374,18 @@ async function processAgent(agent, agentStates, managedToolkits) {
17329
17374
  }
17330
17375
  }
17331
17376
  }
17377
+ const fetchTickBoard = createTickBoardFetcher(async () => {
17378
+ const boardData = await api.post("/host/my-kanban", {
17379
+ agent_id: agent.agent_id
17380
+ });
17381
+ return (boardData.items ?? []).map(sanitizeBoardItem);
17382
+ });
17332
17383
  let boardItems = [];
17333
17384
  let boardItemsStale = false;
17334
17385
  const hasBoardTemplates = tasks.some((t) => BOARD_INJECT_TEMPLATES.has(t.template_id));
17335
17386
  if (hasBoardTemplates) {
17336
17387
  try {
17337
- const boardData = await api.post("/host/my-kanban", { agent_id: agent.agent_id });
17338
- boardItems = (boardData.items ?? []).map(sanitizeBoardItem);
17388
+ boardItems = await fetchTickBoard();
17339
17389
  kanbanBoardCache.set(agent.code_name, boardItems);
17340
17390
  } catch {
17341
17391
  boardItems = kanbanBoardCache.get(agent.code_name) ?? [];
@@ -17350,11 +17400,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
17350
17400
  let hybridBoardStale = boardItemsStale;
17351
17401
  if (!hybridBoard) {
17352
17402
  try {
17353
- const boardData = await api.post(
17354
- "/host/my-kanban",
17355
- { agent_id: agent.agent_id }
17356
- );
17357
- hybridBoard = (boardData.items ?? []).map(sanitizeBoardItem);
17403
+ hybridBoard = await fetchTickBoard();
17358
17404
  kanbanBoardCache.set(agent.code_name, hybridBoard);
17359
17405
  } catch {
17360
17406
  hybridBoard = kanbanBoardCache.get(agent.code_name) ?? [];
@@ -17762,8 +17808,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
17762
17808
  const agentId = agentState.codeNameToAgentId.get(agent.code_name);
17763
17809
  if (agentId) {
17764
17810
  try {
17765
- const boardData = await api.post("/host/my-kanban", { agent_id: agentId });
17766
- const freshBoard = (boardData.items ?? []).map(sanitizeBoardItem);
17811
+ const freshBoard = await fetchTickBoard();
17767
17812
  const freshDoneIds = new Set(freshBoard.filter((b) => b.status === "done" || b.status === "failed").map((b) => b.id));
17768
17813
  const previousDoneIds = notifyBoardCache.get(agent.code_name);
17769
17814
  notifyBoardCache.set(agent.code_name, freshDoneIds);
@@ -18000,9 +18045,10 @@ var persistentSessionStuckTracker = new PersistentSessionStuckTracker();
18000
18045
  var claudeAuthTupleBySession = /* @__PURE__ */ new Map();
18001
18046
  var opencodeCredentialFingerprintBySession = /* @__PURE__ */ new Map();
18002
18047
  var egressAllowlistBySession = /* @__PURE__ */ new Map();
18003
- function deriveEgressAllowlist(toolsRaw) {
18048
+ function deriveEgressAllowlist(toolsRaw, policy) {
18004
18049
  return buildEgressAllowlist(
18005
- toolsRaw ? extractFrontmatter(toolsRaw).frontmatter : null
18050
+ toolsRaw ? extractFrontmatter(toolsRaw).frontmatter : null,
18051
+ modelPolicyEgressDomains(policy)
18006
18052
  );
18007
18053
  }
18008
18054
  var egressAllowlistEqual = (a, b) => a.length === b.length && a.every((d, i) => d === b[i]);
@@ -18145,6 +18191,9 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
18145
18191
  smallFastModel: openRouterRaw.small_fast_model ?? null,
18146
18192
  fingerprint: openRouterRaw.fingerprint ?? null
18147
18193
  } : null;
18194
+ const modelPolicy = parseModelPolicy(
18195
+ refreshData.model_policy
18196
+ );
18148
18197
  let claudeAuthMode;
18149
18198
  let anthropicApiKey;
18150
18199
  let anthropicApiKeyFingerprint;
@@ -18246,7 +18295,13 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
18246
18295
  let dayRolloverForced = false;
18247
18296
  const claudeAccountFingerprint = !openRouterForAgent && claudeAuthMode === "subscription" ? await getClaudeAccountFingerprint() : null;
18248
18297
  noteClaudeAccountChange(codeName, claudeAccountFingerprint, log);
18249
- const currentAuthTuple = openRouterForAgent ? `openrouter:${openRouterForAgent.fingerprint ?? openRouterForAgent.model}` : `${claudeAuthMode}:${anthropicApiKeyFingerprint ?? "none"}${claudeAccountFingerprint ? `:${claudeAccountFingerprint}` : ""}`;
18298
+ const currentAuthTuple = buildAuthTuple({
18299
+ openRouterCredential: openRouterForAgent ? openRouterForAgent.fingerprint ?? openRouterForAgent.model : null,
18300
+ claudeAuthMode,
18301
+ anthropicApiKeyFingerprint,
18302
+ claudeAccountFingerprint,
18303
+ modelPolicyComponent: modelPolicyAuthComponent(modelPolicy)
18304
+ });
18250
18305
  const recordedAuthTuple = claudeAuthTupleBySession.get(codeName);
18251
18306
  if (recordedAuthTuple && recordedAuthTuple !== currentAuthTuple && isSessionHealthy(codeName)) {
18252
18307
  const authTupleDiff = diffAuthTuples(recordedAuthTuple, currentAuthTuple);
@@ -18413,7 +18468,8 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash19("sha256")
18413
18468
  trackSessionRun(codeName, sessionRunResult.run_id);
18414
18469
  const spawnPrimaryModel = resolveModelChain(refreshData).primary ?? refreshData.agent?.["primary_model"] ?? null;
18415
18470
  const egressAllowlist = deriveEgressAllowlist(
18416
- refreshData.tools?.raw_content
18471
+ refreshData.tools?.raw_content,
18472
+ modelPolicy
18417
18473
  );
18418
18474
  egressAllowlistBySession.set(codeName, egressAllowlist);
18419
18475
  let perAgentApiKey = null;
@@ -18466,6 +18522,17 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash19("sha256")
18466
18522
  model: openRouterForAgent.model,
18467
18523
  smallFastModel: openRouterForAgent.smallFastModel
18468
18524
  } : null,
18525
+ // ENG-9483 slice 2 (ADR-0074). The SHAPE reaches the launcher; the
18526
+ // credential does not. `modelPolicyGatewayToken` is deliberately absent
18527
+ // (⇒ null) rather than wired to some plausible existing secret: slice 1's
18528
+ // resolver never selects `model_policy_bindings.credential`, and ENG-9481's
18529
+ // stored-key-vs-pass-through answer decides whether the credential is a
18530
+ // `gateway_token` (needing ANTHROPIC_CUSTOM_HEADERS, an at-rest secret this
18531
+ // tree does not have) or a plain `api_key` (which does not). Until then a
18532
+ // gateway binding resolves to `blocked` and the agent keeps its existing
18533
+ // auth — see resolveBindingCredential, the one function that changes when
18534
+ // that question is answered.
18535
+ modelPolicy,
18469
18536
  runId: sessionRunResult.run_id,
18470
18537
  agentTimezone,
18471
18538
  // ENG-6476: materialize the host-side reply-routing flags into the agent
@@ -18520,7 +18587,8 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash19("sha256")
18520
18587
  resetRestartCount(codeName);
18521
18588
  if (egressMode(codeName) === "allowlist") {
18522
18589
  const allowlist = deriveEgressAllowlist(
18523
- refreshData.tools?.raw_content
18590
+ refreshData.tools?.raw_content,
18591
+ modelPolicy
18524
18592
  );
18525
18593
  const prev = egressAllowlistBySession.get(codeName);
18526
18594
  if (!prev || !egressAllowlistEqual(prev, allowlist)) {
@@ -18863,7 +18931,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
18863
18931
  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}`));
18864
18932
  void (async () => {
18865
18933
  try {
18866
- const { collectDiagnostics } = await import("../persistent-session-CEC5KESY.js");
18934
+ const { collectDiagnostics } = await import("../persistent-session-LP7JOGZ5.js");
18867
18935
  await api.post("/host/heartbeat", {
18868
18936
  host_id: hostId,
18869
18937
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -18914,7 +18982,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
18914
18982
  }
18915
18983
  try {
18916
18984
  const hostId = await getHostId();
18917
- const { collectDiagnostics } = await import("../persistent-session-CEC5KESY.js");
18985
+ const { collectDiagnostics } = await import("../persistent-session-LP7JOGZ5.js");
18918
18986
  await api.post("/host/heartbeat", {
18919
18987
  host_id: hostId,
18920
18988
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -19546,7 +19614,7 @@ async function processClaudePairSessions(agents) {
19546
19614
  killPairSession,
19547
19615
  pairTmuxSession,
19548
19616
  finalizeClaudePairOnboarding
19549
- } = await import("../claude-pair-runtime-XWPOUQMP.js");
19617
+ } = await import("../claude-pair-runtime-42GBPDC7.js");
19550
19618
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
19551
19619
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
19552
19620
  const killed = await killPairSession(pairTmuxSession(pairId));