@integrity-labs/agt-cli 0.28.281 → 0.28.283

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.
@@ -18,7 +18,7 @@ import {
18
18
  resolveConnectivityProbe,
19
19
  worseConnectivityOutcome,
20
20
  wrapScheduledTaskPrompt
21
- } from "./chunk-C4QMCOAN.js";
21
+ } from "./chunk-CUQUOIPW.js";
22
22
  import {
23
23
  parsePsRows
24
24
  } from "./chunk-XWVM4KPK.js";
@@ -5882,7 +5882,7 @@ function requireHost() {
5882
5882
  }
5883
5883
 
5884
5884
  // src/lib/api-client.ts
5885
- var agtCliVersion = true ? "0.28.281" : "dev";
5885
+ var agtCliVersion = true ? "0.28.283" : "dev";
5886
5886
  var lastConfigHash = null;
5887
5887
  function setConfigHash(hash) {
5888
5888
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -8162,4 +8162,4 @@ export {
8162
8162
  managerInstallSystemUnitCommand,
8163
8163
  managerUninstallSystemUnitCommand
8164
8164
  };
8165
- //# sourceMappingURL=chunk-QVAOI4TB.js.map
8165
+ //# sourceMappingURL=chunk-DDQKILX6.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-7H3IYXXP.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-WRL7JV3G.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-JOYTDNXZ.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-ERIXG5MQ.js.map
@@ -38,7 +38,7 @@ import {
38
38
  requireHost,
39
39
  safeWriteJsonAtomic,
40
40
  setConfigHash
41
- } from "../chunk-QVAOI4TB.js";
41
+ } from "../chunk-DDQKILX6.js";
42
42
  import {
43
43
  getProjectDir as getProjectDir2,
44
44
  getReadyTasks,
@@ -125,7 +125,7 @@ import {
125
125
  takeZombieDetection,
126
126
  transcriptActivityAgeSeconds,
127
127
  writeEgressAllowlist
128
- } from "../chunk-C4QMCOAN.js";
128
+ } from "../chunk-CUQUOIPW.js";
129
129
  import {
130
130
  reapOrphanChannelMcps
131
131
  } from "../chunk-XWVM4KPK.js";
@@ -186,6 +186,29 @@ function managedMcpStructureHash(entries) {
186
186
  const basis = entries.slice().sort((a, b) => a.serverId.localeCompare(b.serverId)).map((e) => `${e.serverId}|${Object.keys(e.headers ?? {}).sort().join(",")}`).join("\n");
187
187
  return createHash("sha256").update(basis).digest("hex").slice(0, 16);
188
188
  }
189
+ function managedMcpStructureHashFromFile(mcpConfig, isManagedKey) {
190
+ if (!mcpConfig || typeof mcpConfig !== "object") return null;
191
+ const servers = mcpConfig.mcpServers;
192
+ if (!servers || typeof servers !== "object") return managedMcpStructureHash([]);
193
+ const entries = [];
194
+ for (const [key, value] of Object.entries(servers)) {
195
+ if (!isManagedKey(key)) continue;
196
+ const headers = value && typeof value === "object" && value.headers && typeof value.headers === "object" ? value.headers : void 0;
197
+ entries.push({ serverId: key, headers });
198
+ }
199
+ return managedMcpStructureHash(entries);
200
+ }
201
+ function decideManagedMcpRestart(input) {
202
+ const { prevStructureHash, structureHash, launchStructureHash, sessionHealthy, flapping } = input;
203
+ if (prevStructureHash === void 0) return { kind: "skip-first-convergence" };
204
+ if (structureHash === prevStructureHash) return { kind: "skip-no-change" };
205
+ if (!sessionHealthy) return { kind: "skip-unhealthy" };
206
+ if (flapping) return { kind: "skip-flapping" };
207
+ if (launchStructureHash != null && launchStructureHash === structureHash) {
208
+ return { kind: "suppress-already-live" };
209
+ }
210
+ return { kind: "restart" };
211
+ }
189
212
  function channelSecretValueHash(envEntries, channelSecretKeys) {
190
213
  if (!envEntries) return null;
191
214
  const basis = channelSecretKeys.slice().sort().filter((k) => Object.prototype.hasOwnProperty.call(envEntries, k)).map((k) => `${k}=${envEntries[k]}`).join("\n");
@@ -6343,6 +6366,7 @@ function scheduleSessionRestart(codeName, delayMs, reason, breakerReason = "hot-
6343
6366
  stopPersistentSession(codeName, log);
6344
6367
  markRestartStopped(codeName, log);
6345
6368
  runningMcpHashes.delete(codeName);
6369
+ sessionLaunchManagedStructure.delete(codeName);
6346
6370
  recordRestartForBreaker(codeName, breakerReason);
6347
6371
  log(`[hot-reload] Session stopped for '${codeName}' \u2014 will respawn with ${reason}`);
6348
6372
  const bindsNewMcp = restartReasonBindsNewMcp(breakerReason);
@@ -6521,6 +6545,7 @@ function isHostBusyForForcedUpdate() {
6521
6545
  var runningMcpHashes = /* @__PURE__ */ new Map();
6522
6546
  var runningMcpServerKeys = /* @__PURE__ */ new Map();
6523
6547
  var runningChannelSecretHashes = /* @__PURE__ */ new Map();
6548
+ var sessionLaunchManagedStructure = /* @__PURE__ */ new Map();
6524
6549
  function projectMcpHash(_codeName, projectDir) {
6525
6550
  try {
6526
6551
  const raw = readFileSync15(join17(projectDir, ".mcp.json"), "utf-8");
@@ -6540,6 +6565,28 @@ function projectMcpKeys(_codeName, projectDir) {
6540
6565
  return null;
6541
6566
  }
6542
6567
  }
6568
+ function seedSessionLaunchBaselines(codeName, projectDir) {
6569
+ const hash = projectMcpHash(codeName, projectDir);
6570
+ const keys = projectMcpKeys(codeName, projectDir);
6571
+ if (hash) runningMcpHashes.set(codeName, hash);
6572
+ else runningMcpHashes.delete(codeName);
6573
+ if (keys) runningMcpServerKeys.set(codeName, keys);
6574
+ else runningMcpServerKeys.delete(codeName);
6575
+ let launchStructure = null;
6576
+ try {
6577
+ const raw = readFileSync15(join17(projectDir, ".mcp.json"), "utf-8");
6578
+ launchStructure = managedMcpStructureHashFromFile(
6579
+ JSON.parse(raw),
6580
+ isManagedMcpServerKey
6581
+ );
6582
+ } catch {
6583
+ }
6584
+ if (launchStructure !== null) {
6585
+ sessionLaunchManagedStructure.set(codeName, launchStructure);
6586
+ } else {
6587
+ sessionLaunchManagedStructure.delete(codeName);
6588
+ }
6589
+ }
6543
6590
  async function runAgentConnectivityProbes(agent, integrations, projectDir) {
6544
6591
  if (integrations.length === 0) return;
6545
6592
  const probeEnv = buildProbeEnv(projectDir);
@@ -6665,6 +6712,7 @@ function stopPersistentSessionAndForgetMcpBaseline(codeName, breakerReason, gate
6665
6712
  runningMcpHashes.delete(codeName);
6666
6713
  runningMcpServerKeys.delete(codeName);
6667
6714
  runningChannelSecretHashes.delete(codeName);
6715
+ sessionLaunchManagedStructure.delete(codeName);
6668
6716
  closeInjectedRunIfOpen(codeName, "cancelled", `session stopped (${breakerReason ?? "deprovision"})`);
6669
6717
  closeScheduledRunsForCode(codeName, "cancelled", `session stopped (${breakerReason ?? "deprovision"})`);
6670
6718
  if (breakerReason) {
@@ -6838,7 +6886,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
6838
6886
  var lastVersionCheckAt = 0;
6839
6887
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6840
6888
  var lastResponsivenessProbeAt = 0;
6841
- var agtCliVersion = true ? "0.28.281" : "dev";
6889
+ var agtCliVersion = true ? "0.28.283" : "dev";
6842
6890
  function resolveBrewPath(execFileSync2) {
6843
6891
  try {
6844
6892
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -7688,7 +7736,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
7688
7736
  if (codeNames.length === 0) return;
7689
7737
  void (async () => {
7690
7738
  try {
7691
- const { collectDiagnostics } = await import("../persistent-session-7H3IYXXP.js");
7739
+ const { collectDiagnostics } = await import("../persistent-session-WRL7JV3G.js");
7692
7740
  await api.post("/host/heartbeat", {
7693
7741
  host_id: hostId,
7694
7742
  agent_diagnostics: collectDiagnostics(codeNames)
@@ -7786,7 +7834,7 @@ async function pollCycle() {
7786
7834
  }
7787
7835
  try {
7788
7836
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
7789
- const { collectDiagnostics } = await import("../persistent-session-7H3IYXXP.js");
7837
+ const { collectDiagnostics } = await import("../persistent-session-WRL7JV3G.js");
7790
7838
  const diagCodeNames = [...agentState.persistentSessionAgents];
7791
7839
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
7792
7840
  let tailscaleHostname;
@@ -7934,7 +7982,7 @@ async function pollCycle() {
7934
7982
  const {
7935
7983
  collectResponsivenessProbes,
7936
7984
  getResponsivenessIntervalMs
7937
- } = await import("../responsiveness-probe-PFJM4QMQ.js");
7985
+ } = await import("../responsiveness-probe-LSRBQ5OJ.js");
7938
7986
  const probeIntervalMs = getResponsivenessIntervalMs();
7939
7987
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
7940
7988
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -7966,7 +8014,7 @@ async function pollCycle() {
7966
8014
  collectResponsivenessProbes,
7967
8015
  livePendingInboundOldestAgeSeconds,
7968
8016
  parkPendingInbound
7969
- } = await import("../responsiveness-probe-PFJM4QMQ.js");
8017
+ } = await import("../responsiveness-probe-LSRBQ5OJ.js");
7970
8018
  const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
7971
8019
  const wedgeNow = /* @__PURE__ */ new Date();
7972
8020
  const liveAgents = agentState.persistentSessionAgents;
@@ -9608,12 +9656,19 @@ async function processAgent(agent, agentStates) {
9608
9656
  }
9609
9657
  agentState.knownManagedMcpHashes.set(agent.agent_id, mcpHash);
9610
9658
  agentState.knownManagedMcpStructure.set(agent.agent_id, structureHash);
9611
- if (prevStructureHash !== void 0 && structureHash !== prevStructureHash && fwForMcp === "claude-code" && isSessionHealthy(agent.code_name) && // ENG-6123: hold the restart + inject-notice while the managed-MCP
9612
- // membership is oscillating. The .mcp.json above was still written
9613
- // (the file converges to the live set); we only withhold the
9614
- // opus-facing notice + the session reload — the two per-flip burns.
9615
- // When the set settles, the next structural change restarts once.
9616
- !mcpFlap.flapping) {
9659
+ const mcpRestartDecision = fwForMcp === "claude-code" && prevStructureHash !== void 0 && structureHash !== prevStructureHash ? decideManagedMcpRestart({
9660
+ prevStructureHash,
9661
+ structureHash,
9662
+ launchStructureHash: sessionLaunchManagedStructure.get(agent.code_name),
9663
+ sessionHealthy: isSessionHealthy(agent.code_name),
9664
+ flapping: mcpFlap.flapping
9665
+ }) : null;
9666
+ if (mcpRestartDecision?.kind === "suppress-already-live") {
9667
+ log(
9668
+ `[hot-reload] Restart suppressed for '${agent.code_name}': the managed MCP structure change is already live in the running session (launched with it) - no respawn needed (ENG-7576)`
9669
+ );
9670
+ }
9671
+ if (mcpRestartDecision?.kind === "restart") {
9617
9672
  const mcpNames = agentToolkits.map((tk) => tk.toolkit_name).join(", ") || "none (all removed)";
9618
9673
  log(`[hot-reload] MCP servers changed for '${agent.code_name}': ${mcpNames} \u2014 restarting session`);
9619
9674
  const restartNotice = agentToolkits.length > 0 ? `New MCP tool servers have been configured: ${mcpNames}. Note: MCP servers require a session restart to connect. Your manager will restart your session shortly.` : "Managed MCP tool servers were removed. Your manager will restart your session shortly so the session drops those tools.";
@@ -10614,11 +10669,16 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash11("sha256")
10614
10669
  // unless an operator env override is already present (which keeps precedence).
10615
10670
  slackReplyBindingMode: hostFlagStore().getString("slack-reply-binding"),
10616
10671
  blockTurnEndAllMarkers: hostFlagStore().getBoolean("block-turn-end-all-markers"),
10672
+ // ENG-7493 (ADR-0044): materialize kanban-waiting-status into the spawn env
10673
+ // (AGT_KANBAN_WAITING_ENABLED) so the stdio kanban MCP exposes the `waiting`
10674
+ // option. Host-grained (HostFlagStore); the per-org API gate is authoritative.
10675
+ kanbanWaitingEnabled: hostFlagStore().getBoolean("kanban-waiting-status"),
10617
10676
  egressAllowlist,
10618
10677
  log
10619
10678
  });
10620
10679
  agentState.persistentSessionAgents.add(codeName);
10621
10680
  claudeAuthTupleBySession.set(codeName, currentAuthTuple);
10681
+ seedSessionLaunchBaselines(codeName, projectDir);
10622
10682
  return {
10623
10683
  decision: "spawn",
10624
10684
  spawnAttempted: true,
@@ -10874,7 +10934,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
10874
10934
  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}`));
10875
10935
  void (async () => {
10876
10936
  try {
10877
- const { collectDiagnostics } = await import("../persistent-session-7H3IYXXP.js");
10937
+ const { collectDiagnostics } = await import("../persistent-session-WRL7JV3G.js");
10878
10938
  await api.post("/host/heartbeat", {
10879
10939
  host_id: hostId,
10880
10940
  agent_diagnostics: collectDiagnostics([codeName])
@@ -10924,7 +10984,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
10924
10984
  }
10925
10985
  try {
10926
10986
  const hostId = await getHostId();
10927
- const { collectDiagnostics } = await import("../persistent-session-7H3IYXXP.js");
10987
+ const { collectDiagnostics } = await import("../persistent-session-WRL7JV3G.js");
10928
10988
  await api.post("/host/heartbeat", {
10929
10989
  host_id: hostId,
10930
10990
  agent_diagnostics: collectDiagnostics([codeName])
@@ -11328,7 +11388,7 @@ async function processClaudePairSessions(agents) {
11328
11388
  killPairSession,
11329
11389
  pairTmuxSession,
11330
11390
  finalizeClaudePairOnboarding
11331
- } = await import("../claude-pair-runtime-JOYTDNXZ.js");
11391
+ } = await import("../claude-pair-runtime-ERIXG5MQ.js");
11332
11392
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
11333
11393
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
11334
11394
  const killed = await killPairSession(pairTmuxSession(pairId));