@integrity-labs/agt-cli 0.28.17 → 0.28.19

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
@@ -33,7 +33,7 @@ import {
33
33
  success,
34
34
  table,
35
35
  warn
36
- } from "../chunk-TORLV2SF.js";
36
+ } from "../chunk-MGE73AKK.js";
37
37
  import {
38
38
  CHANNEL_REGISTRY,
39
39
  DEPLOYMENT_TEMPLATES,
@@ -60,7 +60,7 @@ import {
60
60
  renderTemplate,
61
61
  resolveChannels,
62
62
  serializeManifestForSlackCli
63
- } from "../chunk-FW5TXDQC.js";
63
+ } from "../chunk-6UXSC4TR.js";
64
64
 
65
65
  // src/bin/agt.ts
66
66
  import { join as join21 } from "path";
@@ -4773,7 +4773,7 @@ import { execFileSync, execSync } from "child_process";
4773
4773
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4774
4774
  import chalk18 from "chalk";
4775
4775
  import ora16 from "ora";
4776
- var cliVersion = true ? "0.28.17" : "dev";
4776
+ var cliVersion = true ? "0.28.19" : "dev";
4777
4777
  async function fetchLatestVersion() {
4778
4778
  const host2 = getHost();
4779
4779
  if (!host2) return null;
@@ -5696,7 +5696,7 @@ function handleError(err) {
5696
5696
  }
5697
5697
 
5698
5698
  // src/bin/agt.ts
5699
- var cliVersion2 = true ? "0.28.17" : "dev";
5699
+ var cliVersion2 = true ? "0.28.19" : "dev";
5700
5700
  var program = new Command();
5701
5701
  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");
5702
5702
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  claudeModelAlias,
3
3
  isClaudeFastMode
4
- } from "./chunk-FW5TXDQC.js";
4
+ } from "./chunk-6UXSC4TR.js";
5
5
  import {
6
6
  reapOrphanChannelMcps
7
7
  } from "./chunk-XWVM4KPK.js";
@@ -1487,4 +1487,4 @@ export {
1487
1487
  stopAllSessionsAndWait,
1488
1488
  getProjectDir
1489
1489
  };
1490
- //# sourceMappingURL=chunk-F3RMS762.js.map
1490
+ //# sourceMappingURL=chunk-5DIMLYS5.js.map
@@ -5166,4 +5166,4 @@ export {
5166
5166
  coerceEnvValue,
5167
5167
  FLAGS_SCHEMA_VERSION
5168
5168
  };
5169
- //# sourceMappingURL=chunk-FW5TXDQC.js.map
5169
+ //# sourceMappingURL=chunk-6UXSC4TR.js.map
@@ -14,7 +14,7 @@ import {
14
14
  registerFramework,
15
15
  resolveAvatarEnvUrl,
16
16
  wrapScheduledTaskPrompt
17
- } from "./chunk-FW5TXDQC.js";
17
+ } from "./chunk-6UXSC4TR.js";
18
18
 
19
19
  // ../../packages/core/dist/integrations/registry.js
20
20
  var INTEGRATION_REGISTRY = [
@@ -8275,4 +8275,4 @@ export {
8275
8275
  managerInstallSystemUnitCommand,
8276
8276
  managerUninstallSystemUnitCommand
8277
8277
  };
8278
- //# sourceMappingURL=chunk-TORLV2SF.js.map
8278
+ //# sourceMappingURL=chunk-MGE73AKK.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-MIRJWKG7.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-RANQKKKC.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-VQWI5YXW.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-CFUSOOVY.js.map
@@ -22,7 +22,7 @@ import {
22
22
  provisionStopHook,
23
23
  requireHost,
24
24
  safeWriteJsonAtomic
25
- } from "../chunk-TORLV2SF.js";
25
+ } from "../chunk-MGE73AKK.js";
26
26
  import {
27
27
  getProjectDir as getProjectDir2,
28
28
  getReadyTasks,
@@ -64,7 +64,7 @@ import {
64
64
  takeWatchdogGiveUpCount,
65
65
  takeZombieDetection,
66
66
  transcriptActivityAgeSeconds
67
- } from "../chunk-F3RMS762.js";
67
+ } from "../chunk-5DIMLYS5.js";
68
68
  import {
69
69
  FLAGS_SCHEMA_VERSION,
70
70
  KANBAN_CHECK_COMMAND,
@@ -96,7 +96,7 @@ import {
96
96
  sumTranscriptUsageInWindow,
97
97
  worseConnectivityOutcome,
98
98
  wrapScheduledTaskPrompt
99
- } from "../chunk-FW5TXDQC.js";
99
+ } from "../chunk-6UXSC4TR.js";
100
100
  import {
101
101
  parsePsRows,
102
102
  reapOrphanChannelMcps
@@ -434,6 +434,16 @@ function clearPresenceReaperStateForKeys(codeName, keys) {
434
434
  presenceReaperState.delete(stateKey(codeName, key));
435
435
  }
436
436
  }
437
+ function givenUpMcpServerKeys(codeName) {
438
+ const prefix = `${codeName}\0`;
439
+ const out = /* @__PURE__ */ new Set();
440
+ for (const [key, st] of presenceReaperState) {
441
+ if (key.startsWith(prefix) && st.attempts >= MAX_PRESENCE_RESTART_ATTEMPTS) {
442
+ out.add(key.slice(prefix.length));
443
+ }
444
+ }
445
+ return out;
446
+ }
437
447
  function findMissingMcpServers(args) {
438
448
  const { rows, codeName, mcpJson } = args;
439
449
  const servers = mcpJson?.mcpServers ?? {};
@@ -1099,6 +1109,69 @@ function hydrateAutoResumeMarkers(saved) {
1099
1109
  return map;
1100
1110
  }
1101
1111
 
1112
+ // src/lib/resume-reconciler.ts
1113
+ var DEFAULT_MIN_HEALTHY_CYCLES = 2;
1114
+ var DEFAULT_BACKOFF_RESET_MS2 = 864e5;
1115
+ function readResumeReconcilerConfig(env = process.env) {
1116
+ const raw = (env["AGT_RESUME_RECONCILER_ENABLED"] ?? "").trim().toLowerCase();
1117
+ const minCycles = readEnvNumber("AGT_RESUME_MIN_HEALTHY_CYCLES", DEFAULT_MIN_HEALTHY_CYCLES);
1118
+ return {
1119
+ enabled: raw === "1" || raw === "true" || raw === "yes" || raw === "on",
1120
+ // A fractional / <1 override is meaningless for a cycle count — floor to an
1121
+ // integer and demand at least 1, so "healthy" always means "observed at
1122
+ // least once". readEnvNumber already rejects NaN / <=0 to the default.
1123
+ minHealthyCycles: Math.max(1, Math.floor(minCycles)),
1124
+ backoffResetMs: readEnvNumber("AGT_AUTO_RESUME_BACKOFF_RESET_MS", DEFAULT_BACKOFF_RESET_MS2)
1125
+ };
1126
+ }
1127
+ function decideResumeReconcile(opts) {
1128
+ const { trip, marker, health, config: config2, now } = opts;
1129
+ if (!config2.enabled) return { action: "hold", reason: "disabled" };
1130
+ if (!trip) return { action: "hold", reason: "no-trip" };
1131
+ if (marker && now - marker.autoResumedAt < config2.backoffResetMs) {
1132
+ if (trip.trippedAt === marker.trippedAt) {
1133
+ return { action: "hold", reason: "not-healthy-yet" };
1134
+ }
1135
+ return { action: "latch-unstable", trippedAt: trip.trippedAt };
1136
+ }
1137
+ if (!health.dependencyStatusActive) {
1138
+ return { action: "hold", reason: "not-healthy-yet", precondition: "status" };
1139
+ }
1140
+ if (!health.mcpPresent) {
1141
+ return { action: "hold", reason: "not-healthy-yet", precondition: "mcp" };
1142
+ }
1143
+ if (health.connectivityOkCycles < config2.minHealthyCycles) {
1144
+ return {
1145
+ action: "hold",
1146
+ reason: "not-healthy-yet",
1147
+ precondition: "connectivity",
1148
+ cyclesShort: config2.minHealthyCycles - Math.max(0, health.connectivityOkCycles)
1149
+ };
1150
+ }
1151
+ return { action: "resume", healthyCycles: health.connectivityOkCycles };
1152
+ }
1153
+
1154
+ // src/lib/resume-reconciler-inputs.ts
1155
+ function deriveMcpPresent(declaredKeys, givenUpKeys) {
1156
+ if (declaredKeys === null) return false;
1157
+ for (const key of declaredKeys) {
1158
+ if (givenUpKeys.has(key)) return false;
1159
+ }
1160
+ return true;
1161
+ }
1162
+ function parseResumeHealthResponse(raw) {
1163
+ if (!raw || typeof raw !== "object") return null;
1164
+ const r = raw;
1165
+ if (typeof r.dependencyStatusActive !== "boolean") return null;
1166
+ if (typeof r.connectivityOkCycles !== "number" || !Number.isFinite(r.connectivityOkCycles)) {
1167
+ return null;
1168
+ }
1169
+ return {
1170
+ dependencyStatusActive: r.dependencyStatusActive,
1171
+ connectivityOkCycles: r.connectivityOkCycles
1172
+ };
1173
+ }
1174
+
1102
1175
  // src/lib/model-change-respawn.ts
1103
1176
  function shouldRespawnForModelChange(input) {
1104
1177
  const { previousModel, primaryModel, framework, sessionHealthy } = input;
@@ -4741,6 +4814,10 @@ var killPausedCodeNames = /* @__PURE__ */ new Set();
4741
4814
  var BACK_ONLINE_GREETING_GUIDANCE = " When you reconnect, if you tell anyone you are back, start that message with a \u{1F44B} wave emoji and do not use a \u{1F7E2} green-light emoji.";
4742
4815
  function maybeAutoResume(agent) {
4743
4816
  const codeName = agent.code_name;
4817
+ if (readResumeReconcilerConfig().enabled) {
4818
+ void maybeResumeReconcile(agent);
4819
+ return;
4820
+ }
4744
4821
  if (autoResumeInFlight.has(codeName)) return;
4745
4822
  const trip = restartBreaker.getTrip(codeName);
4746
4823
  if (trip && autoResumeStandDowns.has(`${codeName}:${trip.trippedAt}`)) return;
@@ -4792,6 +4869,92 @@ function maybeAutoResume(agent) {
4792
4869
  log(`[auto-resume] agent=${codeName} POST failed (will retry next poll): ${err.message}`);
4793
4870
  });
4794
4871
  }
4872
+ function logResumeReconcileHoldOnce(codeName, trippedAt, reason, detail) {
4873
+ const key = `${codeName}:${trippedAt}`;
4874
+ if (autoResumeLoggedSkips.get(key) !== reason) {
4875
+ autoResumeLoggedSkips.set(key, reason);
4876
+ log(`[resume-reconciler] agent=${codeName} decision=hold reason=${reason}${detail ? ` (${detail})` : ""} (ENG-6383)`);
4877
+ }
4878
+ }
4879
+ async function maybeResumeReconcile(agent) {
4880
+ const codeName = agent.code_name;
4881
+ if (autoResumeInFlight.has(codeName)) return;
4882
+ const trip = restartBreaker.getTrip(codeName);
4883
+ if (!trip) return;
4884
+ const standDownKey = `${codeName}:${trip.trippedAt}`;
4885
+ if (autoResumeStandDowns.has(standDownKey)) return;
4886
+ autoResumeInFlight.add(codeName);
4887
+ try {
4888
+ const config2 = readResumeReconcilerConfig();
4889
+ const trippedAt = trip.trippedAt;
4890
+ let serverHealth = null;
4891
+ try {
4892
+ const raw = await api.get(
4893
+ `/host/circuit-breaker/resume-health?agent_id=${encodeURIComponent(agent.agent_id)}`
4894
+ );
4895
+ serverHealth = parseResumeHealthResponse(raw);
4896
+ } catch (err) {
4897
+ logResumeReconcileHoldOnce(codeName, trippedAt, "health-fetch-failed", err.message.slice(0, 80));
4898
+ return;
4899
+ }
4900
+ if (!serverHealth) {
4901
+ logResumeReconcileHoldOnce(codeName, trippedAt, "health-unparseable");
4902
+ return;
4903
+ }
4904
+ const declaredKeys = projectMcpKeys(codeName, getProjectDir(codeName));
4905
+ const mcpPresent = deriveMcpPresent(declaredKeys, givenUpMcpServerKeys(codeName));
4906
+ const decision = decideResumeReconcile({
4907
+ trip,
4908
+ marker: autoResumeMarkers.get(codeName),
4909
+ health: { ...serverHealth, mcpPresent },
4910
+ config: config2,
4911
+ now: Date.now()
4912
+ });
4913
+ if (decision.action === "hold") {
4914
+ const reason = decision.precondition ? `not-healthy-yet:${decision.precondition}` : decision.reason;
4915
+ const detail = decision.cyclesShort ? `${decision.cyclesShort}-short` : void 0;
4916
+ logResumeReconcileHoldOnce(codeName, trippedAt, reason, detail);
4917
+ return;
4918
+ }
4919
+ if (decision.action === "latch-unstable") {
4920
+ autoResumeStandDowns.add(standDownKey);
4921
+ const key = `${codeName}:${trippedAt}`;
4922
+ if (autoResumeLoggedSkips.get(key) !== "latch-unstable") {
4923
+ autoResumeLoggedSkips.set(key, "latch-unstable");
4924
+ log(
4925
+ `[resume-reconciler] agent=${codeName} decision=latch-unstable \u2014 auto-resumed once then re-tripped within the backoff window; latching to mandatory-manual (NOT resuming; restart counter untouched; agent stays paused with its circuit-breaker alert open) (ENG-6383)`
4926
+ );
4927
+ }
4928
+ return;
4929
+ }
4930
+ log(
4931
+ `[resume-reconciler] agent=${codeName} decision=resume healthyCycles=${decision.healthyCycles} trippedAt=${new Date(trippedAt).toISOString()} (ENG-6383)`
4932
+ );
4933
+ const res = await api.post(
4934
+ "/host/circuit-breaker/auto-resume",
4935
+ { agent_id: agent.agent_id, tripped_at: new Date(trippedAt).toISOString() }
4936
+ );
4937
+ if (res.resumed) {
4938
+ autoResumeMarkers.set(codeName, { trippedAt, autoResumedAt: Date.now() });
4939
+ restartBreaker.clear(codeName);
4940
+ reportedTrips.delete(codeName);
4941
+ state6 = {
4942
+ ...state6,
4943
+ circuitBreakerTrips: restartBreaker.serialize(),
4944
+ circuitBreakerAutoResumes: Object.fromEntries(autoResumeMarkers.entries())
4945
+ };
4946
+ send({ type: "state-update", state: state6 });
4947
+ log(`[resume-reconciler] agent=${codeName} resumed \u2014 a re-trip within the backoff window will latch unstable (ENG-6383)`);
4948
+ } else {
4949
+ autoResumeStandDowns.add(standDownKey);
4950
+ log(`[resume-reconciler] agent=${codeName} not applied (reason=${res.reason ?? "unknown"}) \u2014 standing down for this trip (ENG-6383)`);
4951
+ }
4952
+ } catch (err) {
4953
+ log(`[resume-reconciler] agent=${codeName} reconcile failed (will retry next poll): ${err.message}`);
4954
+ } finally {
4955
+ autoResumeInFlight.delete(codeName);
4956
+ }
4957
+ }
4795
4958
  function scheduleSessionRestart(codeName, delayMs, reason, breakerReason = "hot-reload-mcp") {
4796
4959
  const existing = pendingSessionRestarts.get(codeName);
4797
4960
  if (existing) {
@@ -5266,7 +5429,7 @@ var cachedMaintenanceWindow = null;
5266
5429
  var lastVersionCheckAt = 0;
5267
5430
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
5268
5431
  var lastResponsivenessProbeAt = 0;
5269
- var agtCliVersion = true ? "0.28.17" : "dev";
5432
+ var agtCliVersion = true ? "0.28.19" : "dev";
5270
5433
  function resolveBrewPath(execFileSync4) {
5271
5434
  try {
5272
5435
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -6375,7 +6538,7 @@ async function pollCycle() {
6375
6538
  }
6376
6539
  try {
6377
6540
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
6378
- const { collectDiagnostics } = await import("../persistent-session-MIRJWKG7.js");
6541
+ const { collectDiagnostics } = await import("../persistent-session-RANQKKKC.js");
6379
6542
  const diagCodeNames = [...agentState.persistentSessionAgents];
6380
6543
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames) : void 0;
6381
6544
  let tailscaleHostname;
@@ -6469,7 +6632,7 @@ async function pollCycle() {
6469
6632
  const {
6470
6633
  collectResponsivenessProbes,
6471
6634
  getResponsivenessIntervalMs
6472
- } = await import("../responsiveness-probe-3G7C4AP4.js");
6635
+ } = await import("../responsiveness-probe-KQP6MY5N.js");
6473
6636
  const probeIntervalMs = getResponsivenessIntervalMs();
6474
6637
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
6475
6638
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -6501,7 +6664,7 @@ async function pollCycle() {
6501
6664
  collectResponsivenessProbes,
6502
6665
  livePendingInboundOldestAgeSeconds,
6503
6666
  parkPendingInbound
6504
- } = await import("../responsiveness-probe-3G7C4AP4.js");
6667
+ } = await import("../responsiveness-probe-KQP6MY5N.js");
6505
6668
  const { getProjectDir: wedgeProjectDir } = await import("../claude-scheduler-FATCLHDM.js");
6506
6669
  const wedgeNow = /* @__PURE__ */ new Date();
6507
6670
  const liveAgents = agentState.persistentSessionAgents;
@@ -11092,7 +11255,7 @@ async function processClaudePairSessions(agents) {
11092
11255
  killPairSession,
11093
11256
  pairTmuxSession,
11094
11257
  finalizeClaudePairOnboarding
11095
- } = await import("../claude-pair-runtime-VQWI5YXW.js");
11258
+ } = await import("../claude-pair-runtime-CFUSOOVY.js");
11096
11259
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
11097
11260
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
11098
11261
  const killed = await killPairSession(pairTmuxSession(pairId));