@integrity-labs/agt-cli 0.28.680 → 0.28.682

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.
@@ -55,7 +55,7 @@ import {
55
55
  setConfigHash,
56
56
  setSecretFileTmpfsBacking,
57
57
  tripClass
58
- } from "../chunk-4JTDWOBW.js";
58
+ } from "../chunk-RQ2IJTLD.js";
59
59
  import {
60
60
  getProjectDir as getProjectDir2,
61
61
  getReadyTasks,
@@ -2388,6 +2388,8 @@ function scopeToCurrentPaneEpoch(tail) {
2388
2388
  }
2389
2389
  var MIN_CHECK_INTERVAL_MS = 6e4;
2390
2390
  var PANE_TAIL_LINES_FOR_BANNER = 5e3;
2391
+ var REAFFIRM_INTERVAL_MS = 15 * 6e4;
2392
+ var ABSENCE_CONFIRMATIONS = 30;
2391
2393
  var state = /* @__PURE__ */ new Map();
2392
2394
  async function maybeReportUsageBanner(args) {
2393
2395
  const { api: api2, codeName, agentId, log: log2 } = args;
@@ -2408,21 +2410,61 @@ async function maybeReportUsageBanner(args) {
2408
2410
  lastPct: existing?.lastPct ?? null,
2409
2411
  lastWeekResetsAt: existing?.lastWeekResetsAt ?? null,
2410
2412
  lastLimitScope: existing?.lastLimitScope ?? null,
2411
- lastCheckedAt: nowMs
2413
+ lastCheckedAt: nowMs,
2414
+ lastPostedAt: existing?.lastPostedAt ?? null,
2415
+ consecutiveAbsences: existing?.consecutiveAbsences ?? 0
2412
2416
  };
2413
- if (!tail) {
2414
- state.set(codeName, next);
2415
- return;
2416
- }
2417
- const epochText = scopeToCurrentPaneEpoch(tail);
2418
- const observation = parseUsageBanner(epochText, now);
2417
+ const observation = tail ? parseUsageBanner(scopeToCurrentPaneEpoch(tail), now) : null;
2419
2418
  if (!observation) {
2419
+ if (!existing || existing.lastPct === null) {
2420
+ state.set(codeName, next);
2421
+ return;
2422
+ }
2423
+ next.consecutiveAbsences = (existing.consecutiveAbsences ?? 0) + 1;
2424
+ if (next.consecutiveAbsences < ABSENCE_CONFIRMATIONS) {
2425
+ state.set(codeName, next);
2426
+ return;
2427
+ }
2428
+ try {
2429
+ await api2.post("/host/usage-observations", {
2430
+ agent_id: agentId,
2431
+ // A cleared banner is not "0% used" - we do not know the number, we
2432
+ // know the CAP is gone. 0 is the only value the route accepts that the
2433
+ // server will classify below any threshold, and `source` below is what
2434
+ // makes the row self-describing rather than a fabricated measurement.
2435
+ observed_pct: 0,
2436
+ // Carry the last known window so the row stays coherent with the one it
2437
+ // supersedes. The server short-circuits on `source` before it reasons
2438
+ // about this instant, so it is provenance, not an input to the decision.
2439
+ week_resets_at: existing.lastWeekResetsAt ?? now.toISOString(),
2440
+ reset_precision: "unknown",
2441
+ limit_scope: existing.lastLimitScope ?? "unknown",
2442
+ // ENG-8631: the server keys its `banner_cleared` recovery off exactly
2443
+ // this string. `source` is a free-form text column, so this needs no
2444
+ // migration and an older API simply stores it and behaves as before.
2445
+ source: "pane_log_cleared"
2446
+ });
2447
+ log2(
2448
+ `[usage-banner] '${codeName}': cap banner absent for ${next.consecutiveAbsences} consecutive checks; posted a clearing observation`
2449
+ );
2450
+ next.lastPct = null;
2451
+ next.lastWeekResetsAt = null;
2452
+ next.lastLimitScope = null;
2453
+ next.consecutiveAbsences = 0;
2454
+ next.lastPostedAt = nowMs;
2455
+ } catch (err) {
2456
+ log2(
2457
+ `[usage-banner] clearing POST failed for '${codeName}': ${err.message}`
2458
+ );
2459
+ }
2420
2460
  state.set(codeName, next);
2421
2461
  return;
2422
2462
  }
2423
- const observedAtIso = next.lastWeekResetsAt;
2463
+ next.consecutiveAbsences = 0;
2424
2464
  const weekResetsAtIso = observation.weekResetsAt.toISOString();
2425
- if (existing && existing.lastPct === observation.pct && observedAtIso === weekResetsAtIso && existing.lastLimitScope === observation.limitScope) {
2465
+ const unchanged = existing !== void 0 && existing.lastPct === observation.pct && existing.lastWeekResetsAt === weekResetsAtIso && existing.lastLimitScope === observation.limitScope;
2466
+ const dueToReaffirm = next.lastPostedAt === null || nowMs - next.lastPostedAt >= REAFFIRM_INTERVAL_MS;
2467
+ if (unchanged && !dueToReaffirm) {
2426
2468
  state.set(codeName, next);
2427
2469
  return;
2428
2470
  }
@@ -2455,6 +2497,7 @@ async function maybeReportUsageBanner(args) {
2455
2497
  next.lastPct = observation.pct;
2456
2498
  next.lastWeekResetsAt = weekResetsAtIso;
2457
2499
  next.lastLimitScope = observation.limitScope;
2500
+ next.lastPostedAt = nowMs;
2458
2501
  state.set(codeName, next);
2459
2502
  } catch (err) {
2460
2503
  log2(`[usage-banner] POST /host/usage-observations failed for '${codeName}': ${err.message}`);
@@ -12360,7 +12403,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
12360
12403
  var lastVersionCheckAt = 0;
12361
12404
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
12362
12405
  var lastResponsivenessProbeAt = 0;
12363
- var agtCliVersion = true ? "0.28.680" : "dev";
12406
+ var agtCliVersion = true ? "0.28.682" : "dev";
12364
12407
  function resolveBrewPath(execFileSync3) {
12365
12408
  try {
12366
12409
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();