@integrity-labs/agt-cli 0.28.736 → 0.28.738

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.
Files changed (24) hide show
  1. package/dist/bin/agt.js +5 -5
  2. package/dist/{chunk-6J6G4HOG.js → chunk-JDNULCLF.js} +2 -2
  3. package/dist/{chunk-IBBBIE4K.js → chunk-MAXKAS4Q.js} +36 -15
  4. package/dist/chunk-MAXKAS4Q.js.map +1 -0
  5. package/dist/{chunk-F5UORP7D.js → chunk-WTAZ5GOS.js} +4 -4
  6. package/dist/{claude-pair-runtime-R2F4HRID.js → claude-pair-runtime-JUGH4TOW.js} +2 -2
  7. package/dist/lib/manager-worker.js +125 -16
  8. package/dist/lib/manager-worker.js.map +1 -1
  9. package/dist/mcp/direct-chat-channel.js +35 -14
  10. package/dist/mcp/index.js +35 -14
  11. package/dist/mcp/origami.js +35 -14
  12. package/dist/mcp/slack-channel.js +35 -14
  13. package/dist/mcp/telegram-channel.js +35 -14
  14. package/dist/{persistent-session-GJMGXFF2.js → persistent-session-E7TUUVAI.js} +3 -3
  15. package/dist/{responsiveness-probe-34ECZDWQ.js → responsiveness-probe-PXXWLOML.js} +3 -3
  16. package/dist/{session-auth-dead-TK3KNAH4.js → session-auth-dead-HZZJK37X.js} +2 -2
  17. package/package.json +1 -1
  18. package/dist/chunk-IBBBIE4K.js.map +0 -1
  19. /package/dist/{chunk-6J6G4HOG.js.map → chunk-JDNULCLF.js.map} +0 -0
  20. /package/dist/{chunk-F5UORP7D.js.map → chunk-WTAZ5GOS.js.map} +0 -0
  21. /package/dist/{claude-pair-runtime-R2F4HRID.js.map → claude-pair-runtime-JUGH4TOW.js.map} +0 -0
  22. /package/dist/{persistent-session-GJMGXFF2.js.map → persistent-session-E7TUUVAI.js.map} +0 -0
  23. /package/dist/{responsiveness-probe-34ECZDWQ.js.map → responsiveness-probe-PXXWLOML.js.map} +0 -0
  24. /package/dist/{session-auth-dead-TK3KNAH4.js.map → session-auth-dead-HZZJK37X.js.map} +0 -0
@@ -13,7 +13,7 @@ import {
13
13
  parseEnvFileEntries,
14
14
  parseEnvIntegrations,
15
15
  shellQuote
16
- } from "./chunk-6J6G4HOG.js";
16
+ } from "./chunk-JDNULCLF.js";
17
17
  import {
18
18
  BIND_FAILURE_QUARANTINE_THRESHOLD,
19
19
  INTEGRATIONS_SECTION_END,
@@ -62,7 +62,7 @@ import {
62
62
  sessionTranscriptDir,
63
63
  worseConnectivityOutcome,
64
64
  wrapScheduledTaskPrompt
65
- } from "./chunk-IBBBIE4K.js";
65
+ } from "./chunk-MAXKAS4Q.js";
66
66
  import {
67
67
  parsePsRows
68
68
  } from "./chunk-XWVM4KPK.js";
@@ -6427,7 +6427,7 @@ function exchangeFailureKind(err) {
6427
6427
  }
6428
6428
 
6429
6429
  // src/lib/api-client.ts
6430
- var agtCliVersion = true ? "0.28.736" : "dev";
6430
+ var agtCliVersion = true ? "0.28.738" : "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-F5UORP7D.js.map
10476
+ //# sourceMappingURL=chunk-WTAZ5GOS.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-GJMGXFF2.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-E7TUUVAI.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-R2F4HRID.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-JUGH4TOW.js.map
@@ -57,7 +57,7 @@ import {
57
57
  safeWriteJsonAtomic,
58
58
  setConfigHash,
59
59
  tripClass
60
- } from "../chunk-F5UORP7D.js";
60
+ } from "../chunk-WTAZ5GOS.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-6J6G4HOG.js";
121
+ } from "../chunk-JDNULCLF.js";
122
122
  import {
123
123
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
124
124
  AnchorSessionClient,
@@ -203,7 +203,7 @@ import {
203
203
  subagentActivityAgeSeconds,
204
204
  sumTranscriptUsageInWindow,
205
205
  transcriptActivityAgeSeconds
206
- } from "../chunk-IBBBIE4K.js";
206
+ } from "../chunk-MAXKAS4Q.js";
207
207
  import {
208
208
  reapOrphanChannelMcps
209
209
  } from "../chunk-XWVM4KPK.js";
@@ -655,6 +655,35 @@ function resolveChannelLaunchFlags(channelConfigs, quarantinedChannels) {
655
655
  return { devChannels, pluginChannels };
656
656
  }
657
657
 
658
+ // src/lib/channel-sync-precondition.ts
659
+ var CHANNEL_BACKING_INTEGRATION = Object.freeze({
660
+ slack: "slack",
661
+ telegram: "telegram",
662
+ msteams: "msteams",
663
+ whatsapp: "whatsapp",
664
+ discord: "discord"
665
+ });
666
+ function createEffectiveIntegrationObservations() {
667
+ return /* @__PURE__ */ new Map();
668
+ }
669
+ function recordEffectiveIntegrationIds(observations, agentId, definitionIds) {
670
+ observations.set(agentId, new Set(definitionIds));
671
+ }
672
+ function forgetEffectiveIntegrations(observations, agentId) {
673
+ observations.delete(agentId);
674
+ }
675
+ function checkChannelIntegrationPrecondition(observations, agentId, channelId) {
676
+ const definitionId = Object.prototype.hasOwnProperty.call(CHANNEL_BACKING_INTEGRATION, channelId) ? CHANNEL_BACKING_INTEGRATION[channelId] : void 0;
677
+ if (!definitionId) return { status: "unknown" };
678
+ const observed = observations.get(agentId);
679
+ if (!observed) return { status: "unknown" };
680
+ if (observed.has(definitionId)) return { status: "ok" };
681
+ return { status: "integration-missing", definitionId };
682
+ }
683
+ function channelIntegrationMissingReason(channelId, definitionId) {
684
+ return `the '${definitionId}' integration is not installed on this agent in any scope, so ${channelId} credentials cannot converge \u2014 not retrying until it is installed (ENG-9652)`;
685
+ }
686
+
658
687
  // src/lib/sender-policy-restart-decision.ts
659
688
  function decideSenderPolicyRestart(input) {
660
689
  const {
@@ -5568,6 +5597,58 @@ function createTickBoardFetcher(fetchBoard) {
5568
5597
  };
5569
5598
  }
5570
5599
 
5600
+ // src/lib/kanban-board-token.ts
5601
+ var BoardTokenCache = class {
5602
+ entries = /* @__PURE__ */ new Map();
5603
+ /** The token to send as `known_token`, or undefined when we hold no board. */
5604
+ tokenFor(agentId) {
5605
+ return this.entries.get(agentId)?.token;
5606
+ }
5607
+ /**
5608
+ * Resolve a response into rows.
5609
+ *
5610
+ * Returns `null` when the server said `unchanged` but we hold nothing for
5611
+ * this agent — which should be impossible (we only send a token we have) but
5612
+ * is reachable across a teardown/re-add race, and the caller must re-fetch
5613
+ * rather than silently serve an empty board. An empty board is not a harmless
5614
+ * default here: section 12 writes whatever it is handed into `notifyBoardCache`
5615
+ * as this tick's truth, so seeding "nothing is done" over a board that has
5616
+ * done cards makes the NEXT tick report every one of them as newly done — a
5617
+ * burst of false completion notifications to real users.
5618
+ */
5619
+ resolve(agentId, res) {
5620
+ if (res.unchanged === true) {
5621
+ const held = this.entries.get(agentId);
5622
+ if (!held) return null;
5623
+ if (typeof res.board_token === "string" && res.board_token.length > 0) {
5624
+ this.entries.set(agentId, { token: res.board_token, rows: held.rows });
5625
+ }
5626
+ return held.rows;
5627
+ }
5628
+ const rows = res.items ?? [];
5629
+ if (typeof res.board_token === "string" && res.board_token.length > 0) {
5630
+ this.entries.set(agentId, { token: res.board_token, rows });
5631
+ } else {
5632
+ this.entries.delete(agentId);
5633
+ }
5634
+ return rows;
5635
+ }
5636
+ /**
5637
+ * Drop an agent's board. Teardown must call this: a board left behind is
5638
+ * served to the agent if it is later RE-ADDED, which is exactly when its work
5639
+ * is most likely to have moved on. Same argument as ENG-9585's
5640
+ * `lastRefreshPayload` purge, and the same reason it is registered in
5641
+ * `clearAgentCaches` rather than deleted ad hoc at each call site.
5642
+ */
5643
+ forget(agentId) {
5644
+ this.entries.delete(agentId);
5645
+ }
5646
+ /** Test/diagnostic only. */
5647
+ size() {
5648
+ return this.entries.size;
5649
+ }
5650
+ };
5651
+
5571
5652
  // src/lib/refresh-manifest-flags.ts
5572
5653
  var REFRESH_MANIFEST_FLAGS = {
5573
5654
  /** Knowledge as slug + hash instead of inline bodies. */
@@ -12401,7 +12482,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
12401
12482
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
12402
12483
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
12403
12484
  async function channelInboundActivityAgeSecondsFor(codeName) {
12404
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-34ECZDWQ.js");
12485
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-PXXWLOML.js");
12405
12486
  const newest = newestPendingInboundActivityMtimeMs(dirname10(paneLogPath(codeName)));
12406
12487
  if (newest === null) return null;
12407
12488
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -13015,6 +13096,7 @@ function clearAgentCaches(agentId, codeName) {
13015
13096
  const channelCacheMutated = clearAgentState(agentId, codeName);
13016
13097
  agentChannelTokens.delete(codeName);
13017
13098
  lastRefreshPayload.delete(agentId);
13099
+ boardTokenCache.forget(agentId);
13018
13100
  refreshFetchGate.forget(agentId);
13019
13101
  memoriesFetchGate.forget(agentId);
13020
13102
  forgetRealtimeRebindState(agentId);
@@ -13052,7 +13134,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
13052
13134
  var lastVersionCheckAt = 0;
13053
13135
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
13054
13136
  var lastResponsivenessProbeAt = 0;
13055
- var agtCliVersion = true ? "0.28.736" : "dev";
13137
+ var agtCliVersion = true ? "0.28.738" : "dev";
13056
13138
  function resolveBrewPath(execFileSync3) {
13057
13139
  try {
13058
13140
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -14218,6 +14300,7 @@ function saveChannelHashCache2() {
14218
14300
  var channelWriteFailureCounts = /* @__PURE__ */ new Map();
14219
14301
  var CHANNEL_WRITE_FAILURE_ESCALATE_EVERY = 90;
14220
14302
  var channelSyncFailures = /* @__PURE__ */ new Map();
14303
+ var effectiveIntegrationObservations = createEffectiveIntegrationObservations();
14221
14304
  var channelSyncAttemptedSets = /* @__PURE__ */ new Map();
14222
14305
  var channelCredentialVerdicts = /* @__PURE__ */ new Map();
14223
14306
  function sameChannelSet(a, b) {
@@ -14230,6 +14313,7 @@ function forgetChannelSyncState(agentId) {
14230
14313
  channelSyncFailures.delete(agentId);
14231
14314
  channelSyncAttemptedSets.delete(agentId);
14232
14315
  channelCredentialVerdicts.delete(agentId);
14316
+ forgetEffectiveIntegrations(effectiveIntegrationObservations, agentId);
14233
14317
  }
14234
14318
  var CHANNEL_SYNC_FREE_ATTEMPTS = 3;
14235
14319
  var CHANNEL_SYNC_MAX_BACKOFF_MS = 5 * 6e4;
@@ -14589,7 +14673,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
14589
14673
  if (codeNames.length === 0) return;
14590
14674
  void (async () => {
14591
14675
  try {
14592
- const { collectDiagnostics } = await import("../persistent-session-GJMGXFF2.js");
14676
+ const { collectDiagnostics } = await import("../persistent-session-E7TUUVAI.js");
14593
14677
  await api.post("/host/heartbeat", {
14594
14678
  host_id: hostId,
14595
14679
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -14730,7 +14814,7 @@ async function pollCycleInner() {
14730
14814
  }
14731
14815
  try {
14732
14816
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
14733
- const { collectDiagnostics } = await import("../persistent-session-GJMGXFF2.js");
14817
+ const { collectDiagnostics } = await import("../persistent-session-E7TUUVAI.js");
14734
14818
  const diagCodeNames = [...agentState.persistentSessionAgents];
14735
14819
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor) : void 0;
14736
14820
  let tailscaleHostname;
@@ -14899,7 +14983,7 @@ async function pollCycleInner() {
14899
14983
  collectPanelessActivityProbes,
14900
14984
  getResponsivenessIntervalMs,
14901
14985
  occupancyQualificationClassifications
14902
- } = await import("../responsiveness-probe-34ECZDWQ.js");
14986
+ } = await import("../responsiveness-probe-PXXWLOML.js");
14903
14987
  const probeIntervalMs = getResponsivenessIntervalMs();
14904
14988
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
14905
14989
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -15009,7 +15093,7 @@ async function pollCycleInner() {
15009
15093
  collectResponsivenessProbes,
15010
15094
  livePendingInboundOldestAgeSeconds,
15011
15095
  parkPendingInbound
15012
- } = await import("../responsiveness-probe-34ECZDWQ.js");
15096
+ } = await import("../responsiveness-probe-PXXWLOML.js");
15013
15097
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
15014
15098
  const wedgeNow = /* @__PURE__ */ new Date();
15015
15099
  const liveAgents = agentState.persistentSessionAgents;
@@ -15165,7 +15249,7 @@ async function pollCycleInner() {
15165
15249
  }
15166
15250
  try {
15167
15251
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
15168
- const { probeSessionAuth } = await import("../session-auth-dead-TK3KNAH4.js");
15252
+ const { probeSessionAuth } = await import("../session-auth-dead-HZZJK37X.js");
15169
15253
  const observations = [];
15170
15254
  const pendingCacheCommits = [];
15171
15255
  const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
@@ -16448,6 +16532,19 @@ async function processAgent(agent, agentStates, managedToolkits) {
16448
16532
  );
16449
16533
  }
16450
16534
  }
16535
+ const precondition = checkChannelIntegrationPrecondition(
16536
+ effectiveIntegrationObservations,
16537
+ agent.agent_id,
16538
+ channelId
16539
+ );
16540
+ if (precondition.status === "integration-missing") {
16541
+ channelConfigConverged = false;
16542
+ channelConfigFailureReason = channelIntegrationMissingReason(
16543
+ channelId,
16544
+ precondition.definitionId
16545
+ );
16546
+ continue;
16547
+ }
16451
16548
  frameworkAdapter.writeChannelCredentials(
16452
16549
  agent.code_name,
16453
16550
  channelId,
@@ -16878,6 +16975,11 @@ async function processAgent(agent, agentStates, managedToolkits) {
16878
16975
  try {
16879
16976
  const integrationsData = await api.post("/host/agent-integrations", { agent_id: agent.agent_id });
16880
16977
  const integrations = (integrationsData.integrations ?? []).map(withResolvedRemoteMcp);
16978
+ recordEffectiveIntegrationIds(
16979
+ effectiveIntegrationObservations,
16980
+ agent.agent_id,
16981
+ integrations.map((i) => i.definition_id)
16982
+ );
16881
16983
  firstConnectUnsettledByAgent.set(
16882
16984
  agent.code_name,
16883
16985
  computeFirstConnectUnsettled(integrations, Date.now(), BIND_REMEDIATION_FIRST_CONNECT_WINDOW_MS)
@@ -17531,7 +17633,8 @@ async function processAgent(agent, agentStates, managedToolkits) {
17531
17633
  }
17532
17634
  }
17533
17635
  const fetchTickBoard = createTickBoardFetcher(async () => {
17534
- const boardData = await api.post("/host/my-kanban", {
17636
+ const knownToken = boardTokenCache.tokenFor(agent.agent_id);
17637
+ const post = (token) => api.post("/host/my-kanban", {
17535
17638
  agent_id: agent.agent_id,
17536
17639
  // ENG-9585: this is the ONLY caller that polls (every ~10s, per agent),
17537
17640
  // and it reads exactly `BoardItem`. `description` and `notes` are 57.8%
@@ -17539,9 +17642,14 @@ async function processAgent(agent, agentStates, managedToolkits) {
17539
17642
  // tool and `agt kanban` DO read them, so the route cannot simply drop
17540
17643
  // them. Asking for the lean shape is this caller saying what it needs;
17541
17644
  // every other caller keeps the full payload by default.
17542
- detail: "board"
17645
+ detail: "board",
17646
+ ...token ? { known_token: token } : {}
17543
17647
  });
17544
- return (boardData.items ?? []).map(sanitizeBoardItem);
17648
+ let rows = boardTokenCache.resolve(agent.agent_id, await post(knownToken));
17649
+ if (rows === null) {
17650
+ rows = boardTokenCache.resolve(agent.agent_id, await post(void 0)) ?? [];
17651
+ }
17652
+ return rows.map(sanitizeBoardItem);
17545
17653
  });
17546
17654
  let boardItems = [];
17547
17655
  let boardItemsStale = false;
@@ -19101,7 +19209,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
19101
19209
  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}`));
19102
19210
  void (async () => {
19103
19211
  try {
19104
- const { collectDiagnostics } = await import("../persistent-session-GJMGXFF2.js");
19212
+ const { collectDiagnostics } = await import("../persistent-session-E7TUUVAI.js");
19105
19213
  await api.post("/host/heartbeat", {
19106
19214
  host_id: hostId,
19107
19215
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -19147,7 +19255,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
19147
19255
  }
19148
19256
  try {
19149
19257
  const hostId = await getHostId();
19150
- const { collectDiagnostics } = await import("../persistent-session-GJMGXFF2.js");
19258
+ const { collectDiagnostics } = await import("../persistent-session-E7TUUVAI.js");
19151
19259
  await api.post("/host/heartbeat", {
19152
19260
  host_id: hostId,
19153
19261
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor, forwardedToolsFor)
@@ -19764,6 +19872,7 @@ async function maybeInjectKanbanCheck(codeName, agentId, actionableCount, signat
19764
19872
  var lastHarvestAt = /* @__PURE__ */ new Map();
19765
19873
  var HARVEST_INTERVAL_MS = 3 * 60 * 1e3;
19766
19874
  var kanbanBoardCache = /* @__PURE__ */ new Map();
19875
+ var boardTokenCache = new BoardTokenCache();
19767
19876
  var notifyBoardCache = /* @__PURE__ */ new Map();
19768
19877
  var notifiedWaitingHumanIds = /* @__PURE__ */ new Map();
19769
19878
  var spawnedPairIds = /* @__PURE__ */ new Set();
@@ -19782,7 +19891,7 @@ async function processClaudePairSessions(agents) {
19782
19891
  killPairSession,
19783
19892
  pairTmuxSession,
19784
19893
  finalizeClaudePairOnboarding
19785
- } = await import("../claude-pair-runtime-R2F4HRID.js");
19894
+ } = await import("../claude-pair-runtime-JUGH4TOW.js");
19786
19895
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
19787
19896
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
19788
19897
  const killed = await killPairSession(pairTmuxSession(pairId));