@integrity-labs/agt-cli 0.28.734 → 0.28.735

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 CHANGED
@@ -41,7 +41,7 @@ import {
41
41
  success,
42
42
  table,
43
43
  warn
44
- } from "../chunk-RLOZVCRY.js";
44
+ } from "../chunk-AZZ7MLBE.js";
45
45
  import {
46
46
  getProjectDir,
47
47
  isSessionResumeDisabled,
@@ -5467,7 +5467,7 @@ import { execFileSync, execSync } from "child_process";
5467
5467
  import { existsSync as existsSync11, realpathSync as realpathSync2 } from "fs";
5468
5468
  import chalk18 from "chalk";
5469
5469
  import ora16 from "ora";
5470
- var cliVersion = true ? "0.28.734" : "dev";
5470
+ var cliVersion = true ? "0.28.735" : "dev";
5471
5471
  async function fetchLatestVersion() {
5472
5472
  const host2 = getHost();
5473
5473
  if (!host2) return null;
@@ -6654,7 +6654,7 @@ function handleError(err) {
6654
6654
  }
6655
6655
 
6656
6656
  // src/bin/agt.ts
6657
- var cliVersion2 = true ? "0.28.734" : "dev";
6657
+ var cliVersion2 = true ? "0.28.735" : "dev";
6658
6658
  var program = new Command();
6659
6659
  program.name("agt").description("Augmented CLI \u2014 agent provisioning and management").version(cliVersion2).option("--json", "Emit machine-readable JSON output (suppress spinners and colors)").option("--skip-update-check", "Skip the automatic update check on startup");
6660
6660
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -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.735" : "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-AZZ7MLBE.js.map
@@ -57,7 +57,7 @@ import {
57
57
  safeWriteJsonAtomic,
58
58
  setConfigHash,
59
59
  tripClass
60
- } from "../chunk-RLOZVCRY.js";
60
+ } from "../chunk-AZZ7MLBE.js";
61
61
  import {
62
62
  getProjectDir as getProjectDir2,
63
63
  getReadyTasks,
@@ -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";
@@ -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.735" : "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;
@@ -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
  },
@@ -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)}`),
@@ -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) {