@integrity-labs/agt-cli 0.28.734 → 0.28.736

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.
@@ -13,7 +13,7 @@ import {
13
13
  parseEnvFileEntries,
14
14
  parseEnvIntegrations,
15
15
  shellQuote
16
- } from "./chunk-5CF4DRXA.js";
16
+ } from "./chunk-6J6G4HOG.js";
17
17
  import {
18
18
  BIND_FAILURE_QUARANTINE_THRESHOLD,
19
19
  INTEGRATIONS_SECTION_END,
@@ -6427,7 +6427,7 @@ function exchangeFailureKind(err) {
6427
6427
  }
6428
6428
 
6429
6429
  // src/lib/api-client.ts
6430
- var agtCliVersion = true ? "0.28.734" : "dev";
6430
+ var agtCliVersion = true ? "0.28.736" : "dev";
6431
6431
  var lastConfigHash = null;
6432
6432
  function setConfigHash(hash) {
6433
6433
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -10473,4 +10473,4 @@ export {
10473
10473
  managerInstallSystemUnitCommand,
10474
10474
  managerUninstallSystemUnitCommand
10475
10475
  };
10476
- //# sourceMappingURL=chunk-RLOZVCRY.js.map
10476
+ //# sourceMappingURL=chunk-F5UORP7D.js.map
@@ -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-4KGDH66U.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-GJMGXFF2.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-AWLXOAV6.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-R2F4HRID.js.map
@@ -57,7 +57,7 @@ import {
57
57
  safeWriteJsonAtomic,
58
58
  setConfigHash,
59
59
  tripClass
60
- } from "../chunk-RLOZVCRY.js";
60
+ } from "../chunk-F5UORP7D.js";
61
61
  import {
62
62
  getProjectDir as getProjectDir2,
63
63
  getReadyTasks,
@@ -118,7 +118,7 @@ import {
118
118
  takeZombieDetection,
119
119
  toOpencodeModel,
120
120
  writeEgressAllowlist
121
- } from "../chunk-5CF4DRXA.js";
121
+ } from "../chunk-6J6G4HOG.js";
122
122
  import {
123
123
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
124
124
  AnchorSessionClient,
@@ -5584,6 +5584,48 @@ var REFRESH_MANIFEST_FLAGS = {
5584
5584
  integration_skills_manifest: true
5585
5585
  };
5586
5586
 
5587
+ // src/lib/fetch-cadence.ts
5588
+ function createFetchGate(ttlMs) {
5589
+ const lastFetchedAt = /* @__PURE__ */ new Map();
5590
+ const forceCount = /* @__PURE__ */ new Map();
5591
+ const consumedForceCount = /* @__PURE__ */ new Map();
5592
+ let generation = 0;
5593
+ const fetchedAtGeneration = /* @__PURE__ */ new Map();
5594
+ const pendingForces = (key) => (forceCount.get(key) ?? 0) > (consumedForceCount.get(key) ?? 0);
5595
+ return {
5596
+ shouldFetch(key, now = Date.now()) {
5597
+ if (pendingForces(key)) return true;
5598
+ if ((fetchedAtGeneration.get(key) ?? -1) < generation) return true;
5599
+ const last = lastFetchedAt.get(key);
5600
+ if (last === void 0) return true;
5601
+ return now - last >= ttlMs;
5602
+ },
5603
+ beginFetch(key) {
5604
+ return { forceCount: forceCount.get(key) ?? 0, generation };
5605
+ },
5606
+ markFetched(key, token, now = Date.now()) {
5607
+ lastFetchedAt.set(key, now);
5608
+ fetchedAtGeneration.set(key, token.generation);
5609
+ consumedForceCount.set(key, token.forceCount);
5610
+ },
5611
+ forceNext(key) {
5612
+ forceCount.set(key, (forceCount.get(key) ?? 0) + 1);
5613
+ },
5614
+ forceAll() {
5615
+ generation += 1;
5616
+ },
5617
+ forget(key) {
5618
+ lastFetchedAt.delete(key);
5619
+ fetchedAtGeneration.delete(key);
5620
+ forceCount.delete(key);
5621
+ consumedForceCount.delete(key);
5622
+ },
5623
+ size() {
5624
+ return lastFetchedAt.size;
5625
+ }
5626
+ };
5627
+ }
5628
+
5587
5629
  // src/lib/channel-hash-cache.ts
5588
5630
  import { existsSync as existsSync8, readFileSync as readFileSync19, writeFileSync as writeFileSync10 } from "fs";
5589
5631
  import { join as join25 } from "path";
@@ -12359,7 +12401,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
12359
12401
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
12360
12402
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
12361
12403
  async function channelInboundActivityAgeSecondsFor(codeName) {
12362
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-HNUYLIFJ.js");
12404
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-34ECZDWQ.js");
12363
12405
  const newest = newestPendingInboundActivityMtimeMs(dirname10(paneLogPath(codeName)));
12364
12406
  if (newest === null) return null;
12365
12407
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -12972,6 +13014,9 @@ function resolveAgentFramework(codeName) {
12972
13014
  function clearAgentCaches(agentId, codeName) {
12973
13015
  const channelCacheMutated = clearAgentState(agentId, codeName);
12974
13016
  agentChannelTokens.delete(codeName);
13017
+ lastRefreshPayload.delete(agentId);
13018
+ refreshFetchGate.forget(agentId);
13019
+ memoriesFetchGate.forget(agentId);
12975
13020
  forgetRealtimeRebindState(agentId);
12976
13021
  forgetChannelSyncState(agentId);
12977
13022
  sharedBusyBuckets.reset(codeName);
@@ -13007,7 +13052,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
13007
13052
  var lastVersionCheckAt = 0;
13008
13053
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
13009
13054
  var lastResponsivenessProbeAt = 0;
13010
- var agtCliVersion = true ? "0.28.734" : "dev";
13055
+ var agtCliVersion = true ? "0.28.736" : "dev";
13011
13056
  function resolveBrewPath(execFileSync3) {
13012
13057
  try {
13013
13058
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -14517,6 +14562,16 @@ ${SKILLS_INDEX_END}`;
14517
14562
  );
14518
14563
  }
14519
14564
  }
14565
+ var DESIRED_STATE_FETCH_TTL_MS = 6e4;
14566
+ var refreshFetchGate = createFetchGate(DESIRED_STATE_FETCH_TTL_MS);
14567
+ var lastRefreshPayload = /* @__PURE__ */ new Map();
14568
+ var memoriesFetchGate = createFetchGate(DESIRED_STATE_FETCH_TTL_MS);
14569
+ var pollCycleFetches = 0;
14570
+ var pollCycleFetchSkips = 0;
14571
+ function forceRefreshFetch() {
14572
+ refreshFetchGate.forceAll();
14573
+ memoriesFetchGate.forceAll();
14574
+ }
14520
14575
  var consecutivePollFailures = 0;
14521
14576
  function reorderRestartedFirst(agents, restartedIds) {
14522
14577
  if (restartedIds.size === 0) return agents;
@@ -14534,7 +14589,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
14534
14589
  if (codeNames.length === 0) return;
14535
14590
  void (async () => {
14536
14591
  try {
14537
- const { collectDiagnostics } = await import("../persistent-session-4KGDH66U.js");
14592
+ const { collectDiagnostics } = await import("../persistent-session-GJMGXFF2.js");
14538
14593
  await api.post("/host/heartbeat", {
14539
14594
  host_id: hostId,
14540
14595
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -14675,7 +14730,7 @@ async function pollCycleInner() {
14675
14730
  }
14676
14731
  try {
14677
14732
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
14678
- const { collectDiagnostics } = await import("../persistent-session-4KGDH66U.js");
14733
+ const { collectDiagnostics } = await import("../persistent-session-GJMGXFF2.js");
14679
14734
  const diagCodeNames = [...agentState.persistentSessionAgents];
14680
14735
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor) : void 0;
14681
14736
  let tailscaleHostname;
@@ -14844,7 +14899,7 @@ async function pollCycleInner() {
14844
14899
  collectPanelessActivityProbes,
14845
14900
  getResponsivenessIntervalMs,
14846
14901
  occupancyQualificationClassifications
14847
- } = await import("../responsiveness-probe-HNUYLIFJ.js");
14902
+ } = await import("../responsiveness-probe-34ECZDWQ.js");
14848
14903
  const probeIntervalMs = getResponsivenessIntervalMs();
14849
14904
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
14850
14905
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -14954,7 +15009,7 @@ async function pollCycleInner() {
14954
15009
  collectResponsivenessProbes,
14955
15010
  livePendingInboundOldestAgeSeconds,
14956
15011
  parkPendingInbound
14957
- } = await import("../responsiveness-probe-HNUYLIFJ.js");
15012
+ } = await import("../responsiveness-probe-34ECZDWQ.js");
14958
15013
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
14959
15014
  const wedgeNow = /* @__PURE__ */ new Date();
14960
15015
  const liveAgents = agentState.persistentSessionAgents;
@@ -15270,6 +15325,9 @@ async function pollCycleInner() {
15270
15325
  const processOrder = fastRespawn ? reorderRestartedFirst(agents, new Set(restartAcks.keys())) : agents;
15271
15326
  const managedToolkits = createManagedToolkitReader(agents.map((a) => a.agent_id));
15272
15327
  managedPruneLedger = createManagedPruneLedger();
15328
+ const cycleStartedAt = Date.now();
15329
+ pollCycleFetches = 0;
15330
+ pollCycleFetchSkips = 0;
15273
15331
  for (const agent of processOrder) {
15274
15332
  if (restartInFlight.has(agent.agent_id)) {
15275
15333
  const existing = state8.agents.find((a) => a.agentId === agent.agent_id);
@@ -15308,6 +15366,9 @@ async function pollCycleInner() {
15308
15366
  promptBindProbeAttempts.set(agent.code_name, PROMPT_BIND_PROBE_ATTEMPTS);
15309
15367
  }
15310
15368
  }
15369
+ log(
15370
+ `[poll-cycle] agents=${processOrder.length} refresh_fetched=${pollCycleFetches} refresh_skipped=${pollCycleFetchSkips} duration_ms=${Date.now() - cycleStartedAt}`
15371
+ );
15311
15372
  void maybeReportActivityCache({ api, log });
15312
15373
  const crossAgentPrune = managedPruneLedger.summarize();
15313
15374
  if (crossAgentPrune) log(crossAgentPrune);
@@ -15826,6 +15887,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
15826
15887
  if (previousStatus && previousStatus !== agent.status) {
15827
15888
  log(`Agent '${agent.code_name}' status changed: ${previousStatus} \u2192 ${agent.status}`);
15828
15889
  agentState.knownVersions.delete(agent.agent_id);
15890
+ refreshFetchGate.forceNext(agent.agent_id);
15829
15891
  if (previousStatus === "paused" && agent.status === "active" && restartBreaker.isTripped(agent.code_name)) {
15830
15892
  restartBreaker.clear(agent.code_name);
15831
15893
  reportedTrips.delete(agent.code_name);
@@ -15865,85 +15927,95 @@ async function processAgent(agent, agentStates, managedToolkits) {
15865
15927
  }
15866
15928
  agentState.knownStatuses.set(agent.agent_id, agent.status);
15867
15929
  let refreshData;
15868
- try {
15869
- refreshData = await api.post("/host/refresh", {
15870
- agent_id: agent.agent_id,
15871
- // ENG-9585: ask for hashes instead of bodies on all three lanes. The
15872
- // rationale for each flag, and for their staying three flags rather than
15873
- // one, now lives with the constant — so that a new `/host/refresh` caller
15874
- // inherits it instead of having to rediscover it. The manifest is
15875
- // normalised back into `refreshData.knowledge` immediately below.
15876
- ...REFRESH_MANIFEST_FLAGS
15877
- });
15878
- if (refreshData.knowledge_manifest) {
15879
- const resolved = await resolveKnowledgeFromManifest({
15880
- manifest: refreshData.knowledge_manifest,
15881
- cacheDir: join40(config.configDir, "_knowledge"),
15882
- delivery: refreshData.agent?.knowledge_delivery ?? "both",
15883
- fetchContents: async (hashes) => {
15884
- const res = await api.post(
15885
- "/host/knowledge/contents",
15886
- { agent_id: agent.agent_id, hashes }
15887
- );
15888
- return res.contents ?? [];
15889
- },
15890
- log
15891
- });
15892
- refreshData.knowledge = resolved;
15893
- }
15894
- if (refreshData.global_skills_manifest || refreshData.shared_skills_manifest) {
15895
- const resolvedSkills = await resolveSkillsFromManifest({
15896
- globals: refreshData.global_skills_manifest ?? [],
15897
- shared: refreshData.shared_skills_manifest ?? [],
15898
- cacheDir: join40(config.configDir, "_skills"),
15899
- fetchContents: async (hashes) => {
15900
- const res = await api.post(
15901
- "/host/skills/contents",
15902
- { agent_id: agent.agent_id, hashes }
15903
- );
15904
- return res.contents ?? [];
15905
- },
15906
- log
15907
- });
15908
- if (resolvedSkills) {
15909
- refreshData.global_skills = resolvedSkills.globals;
15910
- refreshData.shared_skills = resolvedSkills.shared;
15911
- }
15912
- }
15913
- if (refreshData.integration_skills_manifest) {
15914
- const resolvedIntegrationSkills = await resolveIntegrationSkillsFromManifest({
15915
- manifest: refreshData.integration_skills_manifest,
15916
- cacheDir: join40(config.configDir, "_skills"),
15917
- fetchContents: async (hashes) => {
15918
- const res = await api.post(
15919
- "/host/skills/contents",
15920
- { agent_id: agent.agent_id, hashes }
15921
- );
15922
- return res.contents ?? [];
15923
- },
15924
- log
15930
+ const cachedRefresh = lastRefreshPayload.get(agent.agent_id);
15931
+ const refreshToken = refreshFetchGate.beginFetch(agent.agent_id);
15932
+ if (cachedRefresh !== void 0 && !refreshFetchGate.shouldFetch(agent.agent_id)) {
15933
+ refreshData = cachedRefresh;
15934
+ pollCycleFetchSkips += 1;
15935
+ } else {
15936
+ try {
15937
+ refreshData = await api.post("/host/refresh", {
15938
+ agent_id: agent.agent_id,
15939
+ // ENG-9585: ask for hashes instead of bodies on all three lanes. The
15940
+ // rationale for each flag, and for their staying three flags rather than
15941
+ // one, now lives with the constant — so that a new `/host/refresh` caller
15942
+ // inherits it instead of having to rediscover it. The manifest is
15943
+ // normalised back into `refreshData.knowledge` immediately below.
15944
+ ...REFRESH_MANIFEST_FLAGS
15925
15945
  });
15926
- if (resolvedIntegrationSkills) {
15927
- refreshData.integration_skills = resolvedIntegrationSkills;
15946
+ if (refreshData.knowledge_manifest) {
15947
+ const resolved = await resolveKnowledgeFromManifest({
15948
+ manifest: refreshData.knowledge_manifest,
15949
+ cacheDir: join40(config.configDir, "_knowledge"),
15950
+ delivery: refreshData.agent?.knowledge_delivery ?? "both",
15951
+ fetchContents: async (hashes) => {
15952
+ const res = await api.post(
15953
+ "/host/knowledge/contents",
15954
+ { agent_id: agent.agent_id, hashes }
15955
+ );
15956
+ return res.contents ?? [];
15957
+ },
15958
+ log
15959
+ });
15960
+ refreshData.knowledge = resolved;
15961
+ }
15962
+ if (refreshData.global_skills_manifest || refreshData.shared_skills_manifest) {
15963
+ const resolvedSkills = await resolveSkillsFromManifest({
15964
+ globals: refreshData.global_skills_manifest ?? [],
15965
+ shared: refreshData.shared_skills_manifest ?? [],
15966
+ cacheDir: join40(config.configDir, "_skills"),
15967
+ fetchContents: async (hashes) => {
15968
+ const res = await api.post(
15969
+ "/host/skills/contents",
15970
+ { agent_id: agent.agent_id, hashes }
15971
+ );
15972
+ return res.contents ?? [];
15973
+ },
15974
+ log
15975
+ });
15976
+ if (resolvedSkills) {
15977
+ refreshData.global_skills = resolvedSkills.globals;
15978
+ refreshData.shared_skills = resolvedSkills.shared;
15979
+ }
15928
15980
  }
15981
+ if (refreshData.integration_skills_manifest) {
15982
+ const resolvedIntegrationSkills = await resolveIntegrationSkillsFromManifest({
15983
+ manifest: refreshData.integration_skills_manifest,
15984
+ cacheDir: join40(config.configDir, "_skills"),
15985
+ fetchContents: async (hashes) => {
15986
+ const res = await api.post(
15987
+ "/host/skills/contents",
15988
+ { agent_id: agent.agent_id, hashes }
15989
+ );
15990
+ return res.contents ?? [];
15991
+ },
15992
+ log
15993
+ });
15994
+ if (resolvedIntegrationSkills) {
15995
+ refreshData.integration_skills = resolvedIntegrationSkills;
15996
+ }
15997
+ }
15998
+ } catch (err) {
15999
+ log(`Refresh failed for '${agent.code_name}': ${err.message}`);
16000
+ const existing = state8.agents.find((a) => a.agentId === agent.agent_id);
16001
+ agentStates.push(existing ?? {
16002
+ agentId: agent.agent_id,
16003
+ codeName: agent.code_name,
16004
+ status: agent.status,
16005
+ charterVersion: "",
16006
+ toolsVersion: "",
16007
+ secretsHash: null,
16008
+ lastRefreshAt: null,
16009
+ lastProvisionAt: null,
16010
+ lastDriftCheckAt: null,
16011
+ lastSecretsProvisionAt: null,
16012
+ acpSessions: []
16013
+ });
16014
+ return;
15929
16015
  }
15930
- } catch (err) {
15931
- log(`Refresh failed for '${agent.code_name}': ${err.message}`);
15932
- const existing = state8.agents.find((a) => a.agentId === agent.agent_id);
15933
- agentStates.push(existing ?? {
15934
- agentId: agent.agent_id,
15935
- codeName: agent.code_name,
15936
- status: agent.status,
15937
- charterVersion: "",
15938
- toolsVersion: "",
15939
- secretsHash: null,
15940
- lastRefreshAt: null,
15941
- lastProvisionAt: null,
15942
- lastDriftCheckAt: null,
15943
- lastSecretsProvisionAt: null,
15944
- acpSessions: []
15945
- });
15946
- return;
16016
+ lastRefreshPayload.set(agent.agent_id, refreshData);
16017
+ refreshFetchGate.markFetched(agent.agent_id, refreshToken);
16018
+ pollCycleFetches += 1;
15947
16019
  }
15948
16020
  if (!getAlertSlackWebhook() && refreshData.team?.settings) {
15949
16021
  const webhook = refreshData.team.settings["alert_slack_webhook"];
@@ -16813,8 +16885,8 @@ async function processAgent(agent, agentStates, managedToolkits) {
16813
16885
  for (const integration of integrations) {
16814
16886
  if (integration.auth_type !== "oauth2") continue;
16815
16887
  const expiresAt = integration.credentials?.token_expires_at;
16816
- const refreshToken = integration.credentials?.refresh_token;
16817
- if (!expiresAt || !refreshToken) continue;
16888
+ const refreshToken2 = integration.credentials?.refresh_token;
16889
+ if (!expiresAt || !refreshToken2) continue;
16818
16890
  const msRemaining = new Date(expiresAt).getTime() - Date.now();
16819
16891
  if (msRemaining > 10 * 60 * 1e3) continue;
16820
16892
  try {
@@ -17460,7 +17532,14 @@ async function processAgent(agent, agentStates, managedToolkits) {
17460
17532
  }
17461
17533
  const fetchTickBoard = createTickBoardFetcher(async () => {
17462
17534
  const boardData = await api.post("/host/my-kanban", {
17463
- agent_id: agent.agent_id
17535
+ agent_id: agent.agent_id,
17536
+ // ENG-9585: this is the ONLY caller that polls (every ~10s, per agent),
17537
+ // and it reads exactly `BoardItem`. `description` and `notes` are 57.8%
17538
+ // of the payload and are read here by nothing — but the `kanban_list` MCP
17539
+ // tool and `agt kanban` DO read them, so the route cannot simply drop
17540
+ // them. Asking for the lean shape is this caller saying what it needs;
17541
+ // every other caller keeps the full payload by default.
17542
+ detail: "board"
17464
17543
  });
17465
17544
  return (boardData.items ?? []).map(sanitizeBoardItem);
17466
17545
  });
@@ -18945,6 +19024,7 @@ function ensureRealtimeDriftStarted(agentStates) {
18945
19024
  const agent = agentStates.find((a) => a.agentId === doc.agent_id);
18946
19025
  if (agent) {
18947
19026
  agentState.knownVersions.delete(doc.agent_id);
19027
+ refreshFetchGate.forceNext(doc.agent_id);
18948
19028
  log(`[realtime] Drift invalidated for '${agent.codeName}' \u2014 will re-provision next cycle`);
18949
19029
  }
18950
19030
  },
@@ -19021,7 +19101,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
19021
19101
  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}`));
19022
19102
  void (async () => {
19023
19103
  try {
19024
- const { collectDiagnostics } = await import("../persistent-session-4KGDH66U.js");
19104
+ const { collectDiagnostics } = await import("../persistent-session-GJMGXFF2.js");
19025
19105
  await api.post("/host/heartbeat", {
19026
19106
  host_id: hostId,
19027
19107
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -19067,7 +19147,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
19067
19147
  }
19068
19148
  try {
19069
19149
  const hostId = await getHostId();
19070
- const { collectDiagnostics } = await import("../persistent-session-4KGDH66U.js");
19150
+ const { collectDiagnostics } = await import("../persistent-session-GJMGXFF2.js");
19071
19151
  await api.post("/host/heartbeat", {
19072
19152
  host_id: hostId,
19073
19153
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -19108,6 +19188,8 @@ function ensureRealtimeAssignStarted(agentStates) {
19108
19188
  );
19109
19189
  },
19110
19190
  onAssign: (payload) => {
19191
+ refreshFetchGate.forceNext(payload.agent_id);
19192
+ memoriesFetchGate.forceNext(payload.agent_id);
19111
19193
  log(`[realtime] Agent ${payload.agent_id} assigned \u2014 will pick up next cycle`);
19112
19194
  markAgentForFreshMemorySync(payload.agent_id);
19113
19195
  },
@@ -19323,6 +19405,7 @@ function triggerEarlyPoll(reason) {
19323
19405
  pollTimer = null;
19324
19406
  }
19325
19407
  log(`[realtime] Triggering early poll: ${reason}`);
19408
+ forceRefreshFetch();
19326
19409
  pollTimer = setTimeout(() => {
19327
19410
  void pollCycleAndReschedule(pollCycle, {
19328
19411
  onError: (err) => log(`[poll-loop] early-poll cycle rejected: ${err?.message ?? String(err)}`),
@@ -19699,7 +19782,7 @@ async function processClaudePairSessions(agents) {
19699
19782
  killPairSession,
19700
19783
  pairTmuxSession,
19701
19784
  finalizeClaudePairOnboarding
19702
- } = await import("../claude-pair-runtime-AWLXOAV6.js");
19785
+ } = await import("../claude-pair-runtime-R2F4HRID.js");
19703
19786
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
19704
19787
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
19705
19788
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -20203,10 +20286,15 @@ async function downloadMemories(agent, memoryDir, log2, { force, configDir }) {
20203
20286
  const localListHash = createHash19("sha256").update(localFiles.join(",")).digest("hex").slice(0, 16);
20204
20287
  const prevLocalHash = lastLocalFileHash.get(agent.agent_id);
20205
20288
  const prevDownload = lastDownloadHash.get(agent.agent_id);
20289
+ const memoriesToken = memoriesFetchGate.beginFetch(agent.agent_id);
20290
+ if (!force && !memoriesFetchGate.shouldFetch(agent.agent_id)) {
20291
+ return { status: "deferred", tombstones: null, truncated: false };
20292
+ }
20206
20293
  try {
20207
20294
  const dbMemories = await api.post("/host/memories", {
20208
20295
  agent_id: agent.agent_id
20209
20296
  });
20297
+ memoriesFetchGate.markFetched(agent.agent_id, memoriesToken);
20210
20298
  const tombstones = Array.isArray(dbMemories.tombstones) ? dbMemories.tombstones : null;
20211
20299
  const responseHash = createHash19("sha256").update(JSON.stringify({ m: dbMemories.memories ?? [], t: tombstones })).digest("hex").slice(0, 16);
20212
20300
  if (!force && prevDownload && prevLocalHash === localListHash && lastDownloadHash.get(agent.agent_id) === responseHash) {