@integrity-labs/agt-cli 0.28.416 → 0.28.417

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
@@ -40,7 +40,7 @@ import {
40
40
  success,
41
41
  table,
42
42
  warn
43
- } from "../chunk-73XZ5UZO.js";
43
+ } from "../chunk-NDDVFICX.js";
44
44
  import {
45
45
  AnchorSessionClient,
46
46
  CHANNEL_REGISTRY,
@@ -70,7 +70,7 @@ import {
70
70
  renderTemplate,
71
71
  resolveChannels,
72
72
  serializeManifestForSlackCli
73
- } from "../chunk-QZUKHEMO.js";
73
+ } from "../chunk-I5SDCW2T.js";
74
74
  import "../chunk-XWVM4KPK.js";
75
75
 
76
76
  // src/bin/agt.ts
@@ -4829,7 +4829,7 @@ import { execFileSync, execSync } from "child_process";
4829
4829
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4830
4830
  import chalk18 from "chalk";
4831
4831
  import ora16 from "ora";
4832
- var cliVersion = true ? "0.28.416" : "dev";
4832
+ var cliVersion = true ? "0.28.417" : "dev";
4833
4833
  async function fetchLatestVersion() {
4834
4834
  const host2 = getHost();
4835
4835
  if (!host2) return null;
@@ -6001,7 +6001,7 @@ function handleError(err) {
6001
6001
  }
6002
6002
 
6003
6003
  // src/bin/agt.ts
6004
- var cliVersion2 = true ? "0.28.416" : "dev";
6004
+ var cliVersion2 = true ? "0.28.417" : "dev";
6005
6005
  var program = new Command();
6006
6006
  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");
6007
6007
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -10295,12 +10295,66 @@ var TurnOutcomeTracker = class {
10295
10295
  }
10296
10296
  };
10297
10297
 
10298
+ // src/lib/opencode-activity-tracker.ts
10299
+ var OpencodeActivityTracker = class {
10300
+ state = /* @__PURE__ */ new Map();
10301
+ entry(codeName) {
10302
+ let cur = this.state.get(codeName);
10303
+ if (!cur) {
10304
+ cur = { inFlight: 0, lastActiveAt: null };
10305
+ this.state.set(codeName, cur);
10306
+ }
10307
+ return cur;
10308
+ }
10309
+ /** A turn has been dispatched to the serve. Call BEFORE awaiting it. */
10310
+ beginTurn(codeName) {
10311
+ this.entry(codeName).inFlight += 1;
10312
+ }
10313
+ /**
10314
+ * A dispatched turn has resolved. Call in a `finally`, so a throw cannot
10315
+ * strand the agent permanently "busy" — a leaked in-flight count would pin
10316
+ * the age at 0 forever and bill the agent around the clock.
10317
+ *
10318
+ * `counted` is false for a gate decline: it occupied the agent for the
10319
+ * microseconds the gate took, and nothing more.
10320
+ */
10321
+ endTurn(codeName, counted, now = Date.now()) {
10322
+ const cur = this.entry(codeName);
10323
+ cur.inFlight = Math.max(0, cur.inFlight - 1);
10324
+ if (counted) cur.lastActiveAt = now;
10325
+ }
10326
+ /**
10327
+ * Seconds since this agent was last doing work, or null if it never has been
10328
+ * in this manager generation.
10329
+ *
10330
+ * 0 while any turn is in flight — see the interval rationale above. Null is
10331
+ * "no signal", NOT "idle": the API omits the field entirely so a mixed-version
10332
+ * fleet cannot have a silent old CLI read as a busy agent (or vice versa).
10333
+ */
10334
+ activityAgeSeconds(codeName, now = Date.now()) {
10335
+ const cur = this.state.get(codeName);
10336
+ if (!cur) return null;
10337
+ if (cur.inFlight > 0) return 0;
10338
+ if (cur.lastActiveAt == null) return null;
10339
+ return Math.max(0, Math.floor((now - cur.lastActiveAt) / 1e3));
10340
+ }
10341
+ /**
10342
+ * Drop all state for an agent, so a fresh serve is not born holding the dead
10343
+ * one's in-flight count. Called from the same teardown path that resets turn
10344
+ * health.
10345
+ */
10346
+ reset(codeName) {
10347
+ this.state.delete(codeName);
10348
+ }
10349
+ };
10350
+
10298
10351
  // src/lib/opencode-session.ts
10299
10352
  var OPENCODE_BIN = process.env["AGT_OPENCODE_BIN"]?.trim() || "opencode";
10300
10353
  var OPENCODE_RUN_TIMEOUT_MS = Number(process.env["AGT_OPENCODE_RUN_TIMEOUT_MS"]) || 18e4;
10301
10354
  var sessions = /* @__PURE__ */ new Map();
10302
10355
  var loggers = /* @__PURE__ */ new Map();
10303
10356
  var turnOutcomeTracker = new TurnOutcomeTracker();
10357
+ var activityTracker = new OpencodeActivityTracker();
10304
10358
  var bridges = /* @__PURE__ */ new Map();
10305
10359
  function opencodeTmuxSession(codeName) {
10306
10360
  return `agt-oc-${codeName}`;
@@ -10641,18 +10695,28 @@ async function injectOpencodeMessage(codeName, msg, opts = {}) {
10641
10695
  return { status: "declined", reason: "server_not_running" };
10642
10696
  }
10643
10697
  const bridge = getBridge(codeName, session.port, session.password);
10698
+ activityTracker.beginTurn(codeName);
10699
+ let occupied = true;
10644
10700
  try {
10645
10701
  const result = await bridge.handleInbound(msg, { gate: opts.gate, awaitReply: opts.awaitReply });
10646
10702
  const outcome = result.status === "declined" ? "declined" : result.status === "replied" && result.reply ? "replied" : opts.awaitReply === false ? "admitted" : "no_reply";
10703
+ occupied = outcome !== "declined";
10647
10704
  noteOpencodeTurnOutcome(codeName, outcome, session);
10648
10705
  return result;
10649
10706
  } catch (err) {
10650
10707
  noteOpencodeTurnOutcome(codeName, "failed", session);
10651
10708
  throw err;
10709
+ } finally {
10710
+ if (isLiveOpencodeSession(codeName, session)) {
10711
+ activityTracker.endTurn(codeName, occupied);
10712
+ }
10652
10713
  }
10653
10714
  }
10715
+ function isLiveOpencodeSession(codeName, startedOn) {
10716
+ return sessions.get(codeName) === startedOn && startedOn.status === "running";
10717
+ }
10654
10718
  function noteOpencodeTurnOutcome(codeName, outcome, startedOn) {
10655
- if (sessions.get(codeName) !== startedOn || startedOn.status !== "running") return;
10719
+ if (!isLiveOpencodeSession(codeName, startedOn)) return;
10656
10720
  const { health, shouldWarn, recovered } = turnOutcomeTracker.record(codeName, outcome);
10657
10721
  const log2 = loggers.get(codeName);
10658
10722
  if (!log2) return;
@@ -10748,6 +10812,7 @@ function stopOpencodeSession(codeName, log2) {
10748
10812
  stopTranscriptRefresher(codeName);
10749
10813
  bridges.delete(codeName);
10750
10814
  turnOutcomeTracker.reset(codeName);
10815
+ activityTracker.reset(codeName);
10751
10816
  loggers.delete(codeName);
10752
10817
  const session = sessions.get(codeName);
10753
10818
  if (session) {
@@ -10762,6 +10827,9 @@ function getOpencodeSessionState(codeName) {
10762
10827
  function getOpencodeTurnHealth(codeName) {
10763
10828
  return turnOutcomeTracker.get(codeName);
10764
10829
  }
10830
+ function getOpencodeActivityAgeSeconds(codeName, now = Date.now()) {
10831
+ return activityTracker.activityAgeSeconds(codeName, now);
10832
+ }
10765
10833
  function stripUndefined(env2) {
10766
10834
  const out = {};
10767
10835
  for (const [k, v] of Object.entries(env2)) if (v !== void 0) out[k] = v;
@@ -12558,6 +12626,8 @@ export {
12558
12626
  injectOpencodeMessage,
12559
12627
  stopOpencodeSession,
12560
12628
  getOpencodeSessionState,
12629
+ getOpencodeTurnHealth,
12630
+ getOpencodeActivityAgeSeconds,
12561
12631
  sessionTranscriptDir,
12562
12632
  transcriptActivityAgeSeconds,
12563
12633
  subagentActivityAgeSeconds,
@@ -12606,4 +12676,4 @@ export {
12606
12676
  stopAllSessionsAndWait,
12607
12677
  getProjectDir
12608
12678
  };
12609
- //# sourceMappingURL=chunk-QZUKHEMO.js.map
12679
+ //# sourceMappingURL=chunk-I5SDCW2T.js.map