@integrity-labs/agt-cli 0.28.30 → 0.28.32

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-62PUHAXF.js";
36
+ } from "../chunk-KJVDXL3L.js";
37
37
  import {
38
38
  CHANNEL_REGISTRY,
39
39
  DEPLOYMENT_TEMPLATES,
@@ -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.30" : "dev";
4776
+ var cliVersion = true ? "0.28.32" : "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.30" : "dev";
5699
+ var cliVersion2 = true ? "0.28.32" : "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) => {
@@ -7266,7 +7266,7 @@ function requireHost() {
7266
7266
  }
7267
7267
 
7268
7268
  // src/lib/api-client.ts
7269
- var agtCliVersion = true ? "0.28.30" : "dev";
7269
+ var agtCliVersion = true ? "0.28.32" : "dev";
7270
7270
  var cachedExchange = null;
7271
7271
  var exchangeInFlight = null;
7272
7272
  function invalidateExchange() {
@@ -8317,4 +8317,4 @@ export {
8317
8317
  managerInstallSystemUnitCommand,
8318
8318
  managerUninstallSystemUnitCommand
8319
8319
  };
8320
- //# sourceMappingURL=chunk-62PUHAXF.js.map
8320
+ //# sourceMappingURL=chunk-KJVDXL3L.js.map
@@ -22,7 +22,7 @@ import {
22
22
  provisionStopHook,
23
23
  requireHost,
24
24
  safeWriteJsonAtomic
25
- } from "../chunk-62PUHAXF.js";
25
+ } from "../chunk-KJVDXL3L.js";
26
26
  import {
27
27
  getProjectDir as getProjectDir2,
28
28
  getReadyTasks,
@@ -1303,6 +1303,64 @@ async function runConnectivityProbes(integrations, options = {}) {
1303
1303
  return { reports, due: due.length, probed: batch.length, skipped };
1304
1304
  }
1305
1305
 
1306
+ // src/lib/dependency-recovery-ledger.ts
1307
+ function ledgerKey(kind, label) {
1308
+ return `${kind}:${label}`;
1309
+ }
1310
+ var DependencyRecoveryLedger = class {
1311
+ /** code_name → (`${kind}:${label}` → entry). */
1312
+ byAgent = /* @__PURE__ */ new Map();
1313
+ /**
1314
+ * Fold one connectivity-probe round's verdicts into the ledger. `down`
1315
+ * records (or re-arms) the dependency; `ok` marks an already-recorded one
1316
+ * recovered; anything else is left untouched (non-escalating, so it neither
1317
+ * opens nor closes an incident).
1318
+ */
1319
+ record(codeName, verdicts) {
1320
+ for (const v of verdicts) {
1321
+ if (v.status === "down") {
1322
+ const entries = this.entriesFor(codeName);
1323
+ const key = ledgerKey(v.kind, v.label);
1324
+ const existing = entries.get(key);
1325
+ if (existing) existing.recovered = false;
1326
+ else entries.set(key, { kind: v.kind, label: v.label, recovered: false });
1327
+ } else if (v.status === "ok") {
1328
+ const entry = this.byAgent.get(codeName)?.get(ledgerKey(v.kind, v.label));
1329
+ if (entry) entry.recovered = true;
1330
+ }
1331
+ }
1332
+ }
1333
+ /**
1334
+ * The dependencies that went down and have since read `ok` again — the
1335
+ * close-the-loop set for this agent's auto-resume. Read-only; the caller
1336
+ * {@link clear}s the agent once the resume that consumes this succeeds.
1337
+ */
1338
+ collectRecovered(codeName) {
1339
+ const entries = this.byAgent.get(codeName);
1340
+ if (!entries) return [];
1341
+ const out = [];
1342
+ for (const e of entries.values()) {
1343
+ if (e.recovered) out.push({ kind: e.kind, label: e.label });
1344
+ }
1345
+ return out;
1346
+ }
1347
+ /**
1348
+ * Drop an agent's ledger — call when its trip clears so the next trip diffs
1349
+ * from a clean slate (and unrecovered/deleted deps don't linger forever).
1350
+ */
1351
+ clear(codeName) {
1352
+ this.byAgent.delete(codeName);
1353
+ }
1354
+ entriesFor(codeName) {
1355
+ let entries = this.byAgent.get(codeName);
1356
+ if (!entries) {
1357
+ entries = /* @__PURE__ */ new Map();
1358
+ this.byAgent.set(codeName, entries);
1359
+ }
1360
+ return entries;
1361
+ }
1362
+ };
1363
+
1306
1364
  // src/lib/cli-probe.ts
1307
1365
  import { execFile } from "child_process";
1308
1366
  var DEFAULT_TIMEOUT_MS = 8e3;
@@ -5430,6 +5488,9 @@ var autoResumeInFlight = /* @__PURE__ */ new Set();
5430
5488
  var AUTO_RESUME_SELF_WINDOW_MS = 12e4;
5431
5489
  var autoResumeLoggedSkips = /* @__PURE__ */ new Map();
5432
5490
  var autoResumeStandDowns = /* @__PURE__ */ new Set();
5491
+ var dependencyRecoveryLedger = new DependencyRecoveryLedger();
5492
+ var unstableLatchUnreported = /* @__PURE__ */ new Set();
5493
+ var unstableLatchReportInFlight = /* @__PURE__ */ new Set();
5433
5494
  var killPausedCodeNames = /* @__PURE__ */ new Set();
5434
5495
  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.";
5435
5496
  function maybeAutoResume(agent) {
@@ -5473,6 +5534,7 @@ function maybeAutoResume(agent) {
5473
5534
  autoResumeMarkers.set(codeName, { trippedAt, autoResumedAt: Date.now() });
5474
5535
  restartBreaker.clear(codeName);
5475
5536
  reportedTrips.delete(codeName);
5537
+ dependencyRecoveryLedger.clear(codeName);
5476
5538
  state6 = {
5477
5539
  ...state6,
5478
5540
  circuitBreakerTrips: restartBreaker.serialize(),
@@ -5496,13 +5558,34 @@ function logResumeReconcileHoldOnce(codeName, trippedAt, reason, detail) {
5496
5558
  log(`[resume-reconciler] agent=${codeName} decision=hold reason=${reason}${detail ? ` (${detail})` : ""} (ENG-6383)`);
5497
5559
  }
5498
5560
  }
5561
+ function reportUnstableLatch(agent, trippedAt, standDownKey) {
5562
+ if (unstableLatchReportInFlight.has(standDownKey)) return;
5563
+ unstableLatchReportInFlight.add(standDownKey);
5564
+ void api.post("/host/circuit-breaker/unstable-latch", {
5565
+ agent_id: agent.agent_id,
5566
+ tripped_at: new Date(trippedAt).toISOString()
5567
+ }).then(() => {
5568
+ unstableLatchUnreported.delete(standDownKey);
5569
+ }).catch((err) => {
5570
+ log(
5571
+ `[resume-reconciler] agent=${agent.code_name} unstable-latch report failed (will retry next poll): ${err.message} (ENG-6392)`
5572
+ );
5573
+ }).finally(() => {
5574
+ unstableLatchReportInFlight.delete(standDownKey);
5575
+ });
5576
+ }
5499
5577
  async function maybeResumeReconcile(agent) {
5500
5578
  const codeName = agent.code_name;
5501
5579
  if (autoResumeInFlight.has(codeName)) return;
5502
5580
  const trip = restartBreaker.getTrip(codeName);
5503
5581
  if (!trip) return;
5504
5582
  const standDownKey = `${codeName}:${trip.trippedAt}`;
5505
- if (autoResumeStandDowns.has(standDownKey)) return;
5583
+ if (autoResumeStandDowns.has(standDownKey)) {
5584
+ if (unstableLatchUnreported.has(standDownKey)) {
5585
+ reportUnstableLatch(agent, trip.trippedAt, standDownKey);
5586
+ }
5587
+ return;
5588
+ }
5506
5589
  autoResumeInFlight.add(codeName);
5507
5590
  try {
5508
5591
  const config2 = { ...readResumeReconcilerConfig(), enabled: hostFlagStore().getBoolean("resume-reconciler") };
@@ -5545,19 +5628,27 @@ async function maybeResumeReconcile(agent) {
5545
5628
  `[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)`
5546
5629
  );
5547
5630
  }
5631
+ unstableLatchUnreported.add(standDownKey);
5632
+ reportUnstableLatch(agent, trippedAt, standDownKey);
5548
5633
  return;
5549
5634
  }
5550
5635
  log(
5551
5636
  `[resume-reconciler] agent=${codeName} decision=resume healthyCycles=${decision.healthyCycles} trippedAt=${new Date(trippedAt).toISOString()} (ENG-6383)`
5552
5637
  );
5638
+ const recoveredDependencies = dependencyRecoveryLedger.collectRecovered(codeName);
5553
5639
  const res = await api.post(
5554
5640
  "/host/circuit-breaker/auto-resume",
5555
- { agent_id: agent.agent_id, tripped_at: new Date(trippedAt).toISOString() }
5641
+ {
5642
+ agent_id: agent.agent_id,
5643
+ tripped_at: new Date(trippedAt).toISOString(),
5644
+ ...recoveredDependencies.length > 0 ? { recovered_dependencies: recoveredDependencies } : {}
5645
+ }
5556
5646
  );
5557
5647
  if (res.resumed) {
5558
5648
  autoResumeMarkers.set(codeName, { trippedAt, autoResumedAt: Date.now() });
5559
5649
  restartBreaker.clear(codeName);
5560
5650
  reportedTrips.delete(codeName);
5651
+ dependencyRecoveryLedger.clear(codeName);
5561
5652
  state6 = {
5562
5653
  ...state6,
5563
5654
  circuitBreakerTrips: restartBreaker.serialize(),
@@ -5881,6 +5972,14 @@ async function runAgentConnectivityProbes(agent, integrations, projectDir) {
5881
5972
  agent_id: agent.agent_id,
5882
5973
  results: result.reports
5883
5974
  });
5975
+ const labelById = new Map(integrations.map((i) => [i.id, i.definition_id]));
5976
+ dependencyRecoveryLedger.record(
5977
+ agent.code_name,
5978
+ result.reports.flatMap((r) => {
5979
+ const label = labelById.get(r.integration_id);
5980
+ return label ? [{ kind: "integration", label, status: r.status }] : [];
5981
+ })
5982
+ );
5884
5983
  log(
5885
5984
  `Connectivity probe for '${agent.code_name}': probed=${result.probed} reported=${result.reports.length} due=${result.due}`
5886
5985
  );
@@ -6072,7 +6171,7 @@ var cachedMaintenanceWindow = null;
6072
6171
  var lastVersionCheckAt = 0;
6073
6172
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
6074
6173
  var lastResponsivenessProbeAt = 0;
6075
- var agtCliVersion = true ? "0.28.30" : "dev";
6174
+ var agtCliVersion = true ? "0.28.32" : "dev";
6076
6175
  function resolveBrewPath(execFileSync4) {
6077
6176
  try {
6078
6177
  const out = execFileSync4("which", ["brew"], { timeout: 5e3 }).toString().trim();