@integrity-labs/agt-cli 0.28.318 → 0.28.319

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-VSSEZTY7.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-U5IQYEXX.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-PWVOBBX4.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-55LJJ7DB.js.map
@@ -26,6 +26,7 @@ import {
26
26
  getCachedClaudeAuthMode,
27
27
  getHostId,
28
28
  givenUpMcpServerKeys,
29
+ liveProxyExtraHeaderVars,
29
30
  provision,
30
31
  provisionAutoKanbanProgressHook,
31
32
  provisionChannelProgressHook,
@@ -39,7 +40,7 @@ import {
39
40
  requireHost,
40
41
  safeWriteJsonAtomic,
41
42
  setConfigHash
42
- } from "../chunk-2DIWTRTU.js";
43
+ } from "../chunk-373GH3RH.js";
43
44
  import {
44
45
  getProjectDir as getProjectDir2,
45
46
  getReadyTasks,
@@ -48,6 +49,7 @@ import {
48
49
  syncTasksToScheduler
49
50
  } from "../chunk-I3YS5WFV.js";
50
51
  import {
52
+ AnchorSessionClient,
51
53
  CONVERSATION_FAILURE_CATEGORIES,
52
54
  DEFAULT_FRAMEWORK,
53
55
  FLAGS_SCHEMA_VERSION,
@@ -127,7 +129,7 @@ import {
127
129
  takeZombieDetection,
128
130
  transcriptActivityAgeSeconds,
129
131
  writeEgressAllowlist
130
- } from "../chunk-4DHYHNCV.js";
132
+ } from "../chunk-ISHK77EM.js";
131
133
  import {
132
134
  reapOrphanChannelMcps
133
135
  } from "../chunk-XWVM4KPK.js";
@@ -279,6 +281,95 @@ function withResolvedRemoteMcp(integration) {
279
281
  };
280
282
  }
281
283
 
284
+ // src/lib/anchor-session-lifecycle.ts
285
+ var DEFAULT_ANCHOR_SESSION_MAX_DURATION_MINUTES = 60;
286
+ var DEFAULT_ANCHOR_SESSION_REFRESH_MARGIN_MINUTES = 5;
287
+ var AnchorSessionLifecycle = class {
288
+ store = /* @__PURE__ */ new Map();
289
+ maxDurationMs;
290
+ refreshMarginMs;
291
+ idleTimeoutMinutes;
292
+ createClient;
293
+ constructor(opts = {}) {
294
+ const maxDurationMinutes = opts.maxDurationMinutes ?? DEFAULT_ANCHOR_SESSION_MAX_DURATION_MINUTES;
295
+ this.maxDurationMs = maxDurationMinutes * 6e4;
296
+ this.refreshMarginMs = (opts.refreshMarginMinutes ?? DEFAULT_ANCHOR_SESSION_REFRESH_MARGIN_MINUTES) * 6e4;
297
+ this.idleTimeoutMinutes = opts.idleTimeoutMinutes ?? maxDurationMinutes;
298
+ this.createClient = opts.createClient ?? ((apiKey) => new AnchorSessionClient({ apiKey }));
299
+ }
300
+ /**
301
+ * Return the session id the agent should bind, minting or re-minting as needed.
302
+ * Returns null for the stateless case (no profile / no key / mint failure with
303
+ * no valid fallback) - the manager then leaves `ANCHOR_BROWSER_SESSION_ID`
304
+ * empty. Never throws.
305
+ */
306
+ async ensure(params) {
307
+ const { agentId, now } = params;
308
+ const log2 = params.log ?? (() => {
309
+ });
310
+ const profileName = params.profileName?.trim() || "";
311
+ const apiKey = params.apiKey?.trim() || "";
312
+ const existing = this.store.get(agentId);
313
+ if (!profileName) {
314
+ if (existing) {
315
+ this.endBestEffort(apiKey, existing.sessionId, log2);
316
+ this.store.delete(agentId);
317
+ }
318
+ return null;
319
+ }
320
+ if (!apiKey) {
321
+ if (existing && existing.profileName === profileName && now < existing.expiresAt) {
322
+ return existing.sessionId;
323
+ }
324
+ log2(`[anchor-session] ${agentId}: profile "${profileName}" but no api key - stateless`);
325
+ return null;
326
+ }
327
+ if (existing && existing.profileName === profileName && now < existing.expiresAt - this.refreshMarginMs) {
328
+ return existing.sessionId;
329
+ }
330
+ try {
331
+ const client2 = this.createClient(apiKey);
332
+ const session = await client2.createSession({
333
+ profileName,
334
+ dedicatedStickyIp: true,
335
+ maxDurationMinutes: this.maxDurationMs / 6e4,
336
+ idleTimeoutMinutes: this.idleTimeoutMinutes
337
+ });
338
+ const effectiveMs = Math.min(this.maxDurationMs, this.idleTimeoutMinutes * 6e4);
339
+ this.store.set(agentId, {
340
+ sessionId: session.sessionId,
341
+ profileName,
342
+ expiresAt: now + effectiveMs
343
+ });
344
+ if (existing && existing.sessionId !== session.sessionId) {
345
+ this.endBestEffort(apiKey, existing.sessionId, log2);
346
+ }
347
+ log2(`[anchor-session] ${agentId}: minted session for profile "${profileName}"`);
348
+ return session.sessionId;
349
+ } catch (err) {
350
+ const reason = err instanceof Error ? err.message : String(err);
351
+ if (existing && existing.profileName === profileName && now < existing.expiresAt) {
352
+ log2(`[anchor-session] ${agentId}: re-mint failed (${reason}) - keeping current session`);
353
+ return existing.sessionId;
354
+ }
355
+ log2(`[anchor-session] ${agentId}: mint failed (${reason}) - degrading to stateless`);
356
+ return null;
357
+ }
358
+ }
359
+ /** Forget an agent's session (e.g. on decommission). Best-effort ends it. */
360
+ forget(agentId, apiKey, log2 = () => {
361
+ }) {
362
+ const existing = this.store.get(agentId);
363
+ if (!existing) return;
364
+ this.endBestEffort(apiKey?.trim() || "", existing.sessionId, log2);
365
+ this.store.delete(agentId);
366
+ }
367
+ endBestEffort(apiKey, sessionId, log2) {
368
+ if (!apiKey || !sessionId) return;
369
+ void this.createClient(apiKey).endSession(sessionId).catch((err) => log2(`[anchor-session] failed to end a stale session: ${err.message}`));
370
+ }
371
+ };
372
+
282
373
  // src/lib/channel-restart-decision.ts
283
374
  function launchableChannelIds(channelConfigs) {
284
375
  if (!channelConfigs) return /* @__PURE__ */ new Set();
@@ -6739,6 +6830,7 @@ function isHostBusyForForcedUpdate() {
6739
6830
  return false;
6740
6831
  }
6741
6832
  var runningMcpHashes = /* @__PURE__ */ new Map();
6833
+ var anchorSessionLifecycle = new AnchorSessionLifecycle();
6742
6834
  var runningMcpServerKeys = /* @__PURE__ */ new Map();
6743
6835
  var runningChannelSecretHashes = /* @__PURE__ */ new Map();
6744
6836
  var sessionLaunchManagedStructure = /* @__PURE__ */ new Map();
@@ -7087,7 +7179,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
7087
7179
  var lastVersionCheckAt = 0;
7088
7180
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
7089
7181
  var lastResponsivenessProbeAt = 0;
7090
- var agtCliVersion = true ? "0.28.318" : "dev";
7182
+ var agtCliVersion = true ? "0.28.319" : "dev";
7091
7183
  function resolveBrewPath(execFileSync2) {
7092
7184
  try {
7093
7185
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -7959,7 +8051,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
7959
8051
  if (codeNames.length === 0) return;
7960
8052
  void (async () => {
7961
8053
  try {
7962
- const { collectDiagnostics } = await import("../persistent-session-VSSEZTY7.js");
8054
+ const { collectDiagnostics } = await import("../persistent-session-U5IQYEXX.js");
7963
8055
  await api.post("/host/heartbeat", {
7964
8056
  host_id: hostId,
7965
8057
  agent_diagnostics: collectDiagnostics(codeNames)
@@ -8057,7 +8149,7 @@ async function pollCycle() {
8057
8149
  }
8058
8150
  try {
8059
8151
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
8060
- const { collectDiagnostics } = await import("../persistent-session-VSSEZTY7.js");
8152
+ const { collectDiagnostics } = await import("../persistent-session-U5IQYEXX.js");
8061
8153
  const diagCodeNames = [...agentState.persistentSessionAgents];
8062
8154
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
8063
8155
  let tailscaleHostname;
@@ -8206,7 +8298,7 @@ async function pollCycle() {
8206
8298
  const {
8207
8299
  collectResponsivenessProbes,
8208
8300
  getResponsivenessIntervalMs
8209
- } = await import("../responsiveness-probe-I6YFUKYD.js");
8301
+ } = await import("../responsiveness-probe-YIESMTKL.js");
8210
8302
  const probeIntervalMs = getResponsivenessIntervalMs();
8211
8303
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
8212
8304
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -8238,7 +8330,7 @@ async function pollCycle() {
8238
8330
  collectResponsivenessProbes,
8239
8331
  livePendingInboundOldestAgeSeconds,
8240
8332
  parkPendingInbound
8241
- } = await import("../responsiveness-probe-I6YFUKYD.js");
8333
+ } = await import("../responsiveness-probe-YIESMTKL.js");
8242
8334
  const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
8243
8335
  const wedgeNow = /* @__PURE__ */ new Date();
8244
8336
  const liveAgents = agentState.persistentSessionAgents;
@@ -9722,6 +9814,24 @@ async function processAgent(agent, agentStates) {
9722
9814
  log(`OAuth token refresh failed for '${agent.code_name}/${integration.definition_id}': ${err.message}`);
9723
9815
  }
9724
9816
  }
9817
+ const anchorIntegration = integrations.find((i) => i.definition_id === "anchor-browser");
9818
+ if (anchorIntegration) {
9819
+ const profileName = anchorIntegration.config?.["profile_name"];
9820
+ const apiKey = anchorIntegration.credentials?.["api_key"];
9821
+ const sessionId = await anchorSessionLifecycle.ensure({
9822
+ agentId: agent.agent_id,
9823
+ profileName,
9824
+ apiKey,
9825
+ now: Date.now(),
9826
+ log
9827
+ });
9828
+ const config2 = { ...anchorIntegration.config ?? {} };
9829
+ if (sessionId) config2["session_id"] = sessionId;
9830
+ else delete config2["session_id"];
9831
+ anchorIntegration.config = config2;
9832
+ } else {
9833
+ anchorSessionLifecycle.forget(agent.agent_id, void 0, log);
9834
+ }
9725
9835
  if (hostFlagStore().getBoolean("connectivity-probe")) {
9726
9836
  try {
9727
9837
  const probeProjectDir = join19(homedir10(), ".augmented", agent.code_name, "project");
@@ -9809,7 +9919,8 @@ async function processAgent(agent, agentStates) {
9809
9919
  isolated: isolationMode(agent.code_name) === "docker"
9810
9920
  });
9811
9921
  }
9812
- const respawnVars = envOnlyRespawnVars(changedVars, mcpJsonForReap, CHANNEL_SECRET_ENV_KEYS);
9922
+ const liveProxyVars = liveProxyExtraHeaderVars(mcpJsonForReap);
9923
+ const respawnVars = envOnlyRespawnVars(changedVars, mcpJsonForReap, CHANNEL_SECRET_ENV_KEYS).filter((v) => !liveProxyVars.has(v));
9813
9924
  const envDiff = classifyEnvIntegrationsDiff(preWriteEnv, postWriteEnv);
9814
9925
  const rotatedOnlyVars = new Set(envDiff.rotated);
9815
9926
  const envRespawnReason = respawnVars.length > 0 && respawnVars.every((v) => rotatedOnlyVars.has(v)) ? "credential-rotation" : "hot-reload-mcp";
@@ -11257,7 +11368,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
11257
11368
  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}`));
11258
11369
  void (async () => {
11259
11370
  try {
11260
- const { collectDiagnostics } = await import("../persistent-session-VSSEZTY7.js");
11371
+ const { collectDiagnostics } = await import("../persistent-session-U5IQYEXX.js");
11261
11372
  await api.post("/host/heartbeat", {
11262
11373
  host_id: hostId,
11263
11374
  agent_diagnostics: collectDiagnostics([codeName])
@@ -11307,7 +11418,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
11307
11418
  }
11308
11419
  try {
11309
11420
  const hostId = await getHostId();
11310
- const { collectDiagnostics } = await import("../persistent-session-VSSEZTY7.js");
11421
+ const { collectDiagnostics } = await import("../persistent-session-U5IQYEXX.js");
11311
11422
  await api.post("/host/heartbeat", {
11312
11423
  host_id: hostId,
11313
11424
  agent_diagnostics: collectDiagnostics([codeName])
@@ -11731,7 +11842,7 @@ async function processClaudePairSessions(agents) {
11731
11842
  killPairSession,
11732
11843
  pairTmuxSession,
11733
11844
  finalizeClaudePairOnboarding
11734
- } = await import("../claude-pair-runtime-PWVOBBX4.js");
11845
+ } = await import("../claude-pair-runtime-55LJJ7DB.js");
11735
11846
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
11736
11847
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
11737
11848
  const killed = await killPairSession(pairTmuxSession(pairId));