@integrity-labs/agt-cli 0.28.693 → 0.28.695

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.
Files changed (24) hide show
  1. package/dist/bin/agt.js +5 -5
  2. package/dist/{chunk-HAOMTMPE.js → chunk-A2W4K7IH.js} +4 -4
  3. package/dist/{chunk-4ARKV2GJ.js → chunk-OUERGATQ.js} +2 -2
  4. package/dist/{chunk-BV2ZQRFB.js → chunk-XB2RCS5S.js} +254 -79
  5. package/dist/chunk-XB2RCS5S.js.map +1 -0
  6. package/dist/{claude-pair-runtime-Q5OIAZWC.js → claude-pair-runtime-MRA4KSDR.js} +2 -2
  7. package/dist/lib/manager-worker.js +271 -144
  8. package/dist/lib/manager-worker.js.map +1 -1
  9. package/dist/mcp/direct-chat-channel.js +113 -78
  10. package/dist/mcp/index.js +48 -3
  11. package/dist/mcp/origami.js +48 -3
  12. package/dist/mcp/slack-channel.js +113 -78
  13. package/dist/mcp/telegram-channel.js +113 -78
  14. package/dist/{persistent-session-PPBLGH2J.js → persistent-session-PEY2TMJI.js} +3 -3
  15. package/dist/{responsiveness-probe-H3UBUTW7.js → responsiveness-probe-VJP2AHNR.js} +3 -3
  16. package/dist/{session-auth-dead-K3XQNN5A.js → session-auth-dead-QCZ2EOVS.js} +2 -2
  17. package/package.json +1 -1
  18. package/dist/chunk-BV2ZQRFB.js.map +0 -1
  19. /package/dist/{chunk-HAOMTMPE.js.map → chunk-A2W4K7IH.js.map} +0 -0
  20. /package/dist/{chunk-4ARKV2GJ.js.map → chunk-OUERGATQ.js.map} +0 -0
  21. /package/dist/{claude-pair-runtime-Q5OIAZWC.js.map → claude-pair-runtime-MRA4KSDR.js.map} +0 -0
  22. /package/dist/{persistent-session-PPBLGH2J.js.map → persistent-session-PEY2TMJI.js.map} +0 -0
  23. /package/dist/{responsiveness-probe-H3UBUTW7.js.map → responsiveness-probe-VJP2AHNR.js.map} +0 -0
  24. /package/dist/{session-auth-dead-K3XQNN5A.js.map → session-auth-dead-QCZ2EOVS.js.map} +0 -0
@@ -54,7 +54,7 @@ import {
54
54
  safeWriteJsonAtomic,
55
55
  setConfigHash,
56
56
  tripClass
57
- } from "../chunk-HAOMTMPE.js";
57
+ } from "../chunk-A2W4K7IH.js";
58
58
  import {
59
59
  getProjectDir as getProjectDir2,
60
60
  getReadyTasks,
@@ -112,7 +112,7 @@ import {
112
112
  takeZombieDetection,
113
113
  toOpencodeModel,
114
114
  writeEgressAllowlist
115
- } from "../chunk-4ARKV2GJ.js";
115
+ } from "../chunk-OUERGATQ.js";
116
116
  import {
117
117
  ACCOUNT_ENFORCEMENT_MARKER_FILENAME,
118
118
  AnchorSessionClient,
@@ -136,6 +136,7 @@ import {
136
136
  appendDmFooter,
137
137
  attributeTranscriptUsageByRun,
138
138
  buildFailureCategoryPromptLines,
139
+ buildHostUsageReading,
139
140
  buildScheduledTaskContextBlocks,
140
141
  classifyActor,
141
142
  classifyCursorAdvance,
@@ -181,6 +182,7 @@ import {
181
182
  parseDeliveryTarget,
182
183
  parseTranscriptUsage,
183
184
  parseUsageBanner,
185
+ parseUsageReport,
184
186
  peekCurrentSession,
185
187
  pickNewerClassification,
186
188
  remoteMcpServerKey,
@@ -190,10 +192,11 @@ import {
190
192
  resolveDmTarget,
191
193
  serializeAccountEnforcementMarker,
192
194
  sessionTranscriptDir,
195
+ stabiliseResetInstant,
193
196
  subagentActivityAgeSeconds,
194
197
  sumTranscriptUsageInWindow,
195
198
  transcriptActivityAgeSeconds
196
- } from "../chunk-BV2ZQRFB.js";
199
+ } from "../chunk-XB2RCS5S.js";
197
200
  import {
198
201
  reapOrphanChannelMcps
199
202
  } from "../chunk-XWVM4KPK.js";
@@ -2504,6 +2507,89 @@ async function maybeReportUsageBanner(args) {
2504
2507
  }
2505
2508
  }
2506
2509
 
2510
+ // src/lib/host-usage-poller.ts
2511
+ var HOST_USAGE_POLL_INTERVAL_MS = 15 * 60 * 1e3;
2512
+ var HOST_USAGE_POLL_TIMEOUT_MS = 6e4;
2513
+ var USAGE_COMMAND_ARGS = ["-p", "/usage", "--output-format", "json"];
2514
+ var state2 = {
2515
+ lastPolledAt: 0,
2516
+ inFlight: false,
2517
+ lastWeekResetsAt: null,
2518
+ lastSessionResetsAt: null
2519
+ };
2520
+ function extractUsageText(stdout) {
2521
+ try {
2522
+ const parsed = JSON.parse(stdout);
2523
+ if (!parsed || typeof parsed !== "object") return null;
2524
+ const envelope = parsed;
2525
+ if (envelope.is_error === true) return null;
2526
+ return typeof envelope.result === "string" ? envelope.result : null;
2527
+ } catch {
2528
+ return null;
2529
+ }
2530
+ }
2531
+ async function maybePollHostUsage(deps) {
2532
+ const { api: api2, runUsageCommand, authMode, cliVersion, log: log2 } = deps;
2533
+ const now = deps.now ?? /* @__PURE__ */ new Date();
2534
+ const nowMs = now.getTime();
2535
+ if (state2.inFlight) return;
2536
+ if (nowMs - state2.lastPolledAt < HOST_USAGE_POLL_INTERVAL_MS) return;
2537
+ state2.inFlight = true;
2538
+ try {
2539
+ let reading;
2540
+ try {
2541
+ const { stdout, failed } = await runUsageCommand();
2542
+ const text = failed ? null : extractUsageText(stdout);
2543
+ reading = buildHostUsageReading({
2544
+ report: text === null ? null : parseUsageReport(text, now),
2545
+ readAt: now,
2546
+ cliVersion,
2547
+ authMode,
2548
+ pollFailed: failed
2549
+ });
2550
+ } catch (err) {
2551
+ log2(`[host-usage] /usage poll failed: ${err.message}`);
2552
+ reading = buildHostUsageReading({
2553
+ report: null,
2554
+ readAt: now,
2555
+ cliVersion,
2556
+ authMode,
2557
+ pollFailed: true
2558
+ });
2559
+ }
2560
+ const weekResetsAt = stabiliseResetInstant(state2.lastWeekResetsAt, reading.weekResetsAt);
2561
+ const sessionResetsAt = stabiliseResetInstant(
2562
+ state2.lastSessionResetsAt,
2563
+ reading.sessionResetsAt
2564
+ );
2565
+ await api2.post("/host/usage-readings", {
2566
+ state: reading.state,
2567
+ week_pct: reading.weekPct,
2568
+ week_resets_at: weekResetsAt ? weekResetsAt.toISOString() : null,
2569
+ session_pct: reading.sessionPct,
2570
+ session_resets_at: sessionResetsAt ? sessionResetsAt.toISOString() : null,
2571
+ read_at: reading.readAt.toISOString(),
2572
+ cli_version: reading.cliVersion,
2573
+ source: reading.source,
2574
+ unknown_reason: reading.unknownReason
2575
+ });
2576
+ state2.lastWeekResetsAt = weekResetsAt;
2577
+ state2.lastSessionResetsAt = sessionResetsAt;
2578
+ if (reading.state === "ok") {
2579
+ log2(
2580
+ `[host-usage] week ${reading.weekPct}%` + (weekResetsAt ? ` (resets ${weekResetsAt.toISOString()})` : "") + `, session ${reading.sessionPct}%`
2581
+ );
2582
+ } else if (reading.state === "unknown") {
2583
+ log2(`[host-usage] reading unknown: ${reading.unknownReason}`);
2584
+ }
2585
+ } catch (err) {
2586
+ log2(`[host-usage] post failed: ${err.message}`);
2587
+ } finally {
2588
+ state2.lastPolledAt = nowMs;
2589
+ state2.inFlight = false;
2590
+ }
2591
+ }
2592
+
2507
2593
  // src/lib/claude-account-fingerprint.ts
2508
2594
  import { createHash as createHash6 } from "crypto";
2509
2595
  import { readFile as readFile3, readdir as readdir3 } from "fs/promises";
@@ -2785,12 +2871,12 @@ import { join as join13 } from "path";
2785
2871
  var MIN_CHECK_INTERVAL_MS2 = 6e4;
2786
2872
  var TRANSCRIPT_MTIME_WINDOW_MS = 2 * 24 * 60 * 60 * 1e3;
2787
2873
  var MAX_ENTRIES_PER_POST = 200;
2788
- var state2 = /* @__PURE__ */ new Map();
2874
+ var state3 = /* @__PURE__ */ new Map();
2789
2875
  async function maybeReportTokenUsage(args) {
2790
2876
  const { api: api2, codeName, agentId, log: log2 } = args;
2791
2877
  const now = args.now ?? /* @__PURE__ */ new Date();
2792
2878
  const nowMs = now.getTime();
2793
- const existing = state2.get(codeName);
2879
+ const existing = state3.get(codeName);
2794
2880
  if (existing && nowMs - existing.lastCheckedAt < MIN_CHECK_INTERVAL_MS2) {
2795
2881
  return;
2796
2882
  }
@@ -2801,7 +2887,7 @@ async function maybeReportTokenUsage(args) {
2801
2887
  try {
2802
2888
  dirEntries = readdirSync(dir);
2803
2889
  } catch {
2804
- state2.set(codeName, next);
2890
+ state3.set(codeName, next);
2805
2891
  return;
2806
2892
  }
2807
2893
  const pending2 = [];
@@ -2866,7 +2952,7 @@ async function maybeReportTokenUsage(args) {
2866
2952
  }
2867
2953
  }
2868
2954
  if (pending2.length === 0) {
2869
- state2.set(codeName, next);
2955
+ state3.set(codeName, next);
2870
2956
  return;
2871
2957
  }
2872
2958
  let reported = 0;
@@ -2903,7 +2989,7 @@ async function maybeReportTokenUsage(args) {
2903
2989
  if (reported > 0) {
2904
2990
  log2(`[token-usage] reported ${reported} entr${reported === 1 ? "y" : "ies"} for '${codeName}'`);
2905
2991
  }
2906
- state2.set(codeName, next);
2992
+ state3.set(codeName, next);
2907
2993
  }
2908
2994
 
2909
2995
  // src/lib/workflow-run-reconciler.ts
@@ -3183,7 +3269,7 @@ function selectEvalBackend(opts) {
3183
3269
  }
3184
3270
  };
3185
3271
  }
3186
- var state3 = /* @__PURE__ */ new Map();
3272
+ var state4 = /* @__PURE__ */ new Map();
3187
3273
  function channelRefTokens(channelRef) {
3188
3274
  return channelRef.split(":").slice(1).filter((p) => p && p !== "dm");
3189
3275
  }
@@ -3359,11 +3445,11 @@ async function maybeEvaluateConversations(args) {
3359
3445
  const { api: api2, backend, codeName, agentId, log: log2 } = args;
3360
3446
  const now = args.now ?? /* @__PURE__ */ new Date();
3361
3447
  const nowMs = now.getTime();
3362
- const existing = state3.get(codeName);
3448
+ const existing = state4.get(codeName);
3363
3449
  if (existing && nowMs - existing.lastCheckedAt < MIN_CHECK_INTERVAL_MS4) {
3364
3450
  return;
3365
3451
  }
3366
- state3.set(codeName, { lastCheckedAt: nowMs });
3452
+ state4.set(codeName, { lastCheckedAt: nowMs });
3367
3453
  let pending2;
3368
3454
  try {
3369
3455
  const resp = await api2.get(
@@ -3644,7 +3730,7 @@ function scrubSensitive(text) {
3644
3730
  for (const re of SECRET_PATTERNS) out = out.replace(re, "[redacted]");
3645
3731
  return out;
3646
3732
  }
3647
- var state4 = /* @__PURE__ */ new Map();
3733
+ var state5 = /* @__PURE__ */ new Map();
3648
3734
  function buildExtractionPrompt(channel, transcript) {
3649
3735
  return `You are extracting durable, reusable memories from one completed ${channel} conversation between an AI agent and an end-user. A good memory is a stable preference, fact, correction, or recurring work context that will help the agent in FUTURE conversations \u2014 not a one-off task detail or pleasantry.
3650
3736
 
@@ -3698,11 +3784,11 @@ async function maybeExtractMemories(args) {
3698
3784
  const { api: api2, backend, codeName, agentId, log: log2 } = args;
3699
3785
  const now = args.now ?? /* @__PURE__ */ new Date();
3700
3786
  const nowMs = now.getTime();
3701
- const existing = state4.get(codeName);
3787
+ const existing = state5.get(codeName);
3702
3788
  if (existing && nowMs - existing.lastCheckedAt < MIN_CHECK_INTERVAL_MS5) {
3703
3789
  return;
3704
3790
  }
3705
- state4.set(codeName, { lastCheckedAt: nowMs });
3791
+ state5.set(codeName, { lastCheckedAt: nowMs });
3706
3792
  let pending2;
3707
3793
  try {
3708
3794
  const resp = await api2.get(
@@ -4699,7 +4785,7 @@ async function reportCoverage(args, cursors, touched, log2) {
4699
4785
  // src/lib/tool-call-audit.ts
4700
4786
  var MIN_CHECK_INTERVAL_MS6 = 10 * 6e4;
4701
4787
  var ENTITLEMENT_RECHECK_MS = 30 * 6e4;
4702
- var state5 = /* @__PURE__ */ new Map();
4788
+ var state6 = /* @__PURE__ */ new Map();
4703
4789
  function entitlementLatch(entry, nowMs) {
4704
4790
  if (!entry?.notEntitledAt) return false;
4705
4791
  return !hasElapsed(entry.notEntitledAt, nowMs, ENTITLEMENT_RECHECK_MS);
@@ -4714,13 +4800,13 @@ async function maybeScanToolCalls(args) {
4714
4800
  const nowFn = args.now ?? Date.now;
4715
4801
  const nowMs = nowFn();
4716
4802
  try {
4717
- const existing = state5.get(codeName);
4803
+ const existing = state6.get(codeName);
4718
4804
  if (existing && !hasElapsed(existing.lastCheckedAt, nowMs, MIN_CHECK_INTERVAL_MS6)) return;
4719
4805
  if (entitlementLatch(existing, nowMs)) {
4720
- state5.set(codeName, { lastCheckedAt: nowMs, notEntitledAt: existing?.notEntitledAt ?? null });
4806
+ state6.set(codeName, { lastCheckedAt: nowMs, notEntitledAt: existing?.notEntitledAt ?? null });
4721
4807
  return;
4722
4808
  }
4723
- state5.set(codeName, { lastCheckedAt: nowMs, notEntitledAt: existing?.notEntitledAt ?? null });
4809
+ state6.set(codeName, { lastCheckedAt: nowMs, notEntitledAt: existing?.notEntitledAt ?? null });
4724
4810
  const loggingMode = readAgentLoggingMode(codeName, args.homeDir);
4725
4811
  const hashOnly = loggingModeWithholdsTargets(loggingMode);
4726
4812
  if (loggingMode.mode === null) {
@@ -4752,9 +4838,9 @@ async function maybeScanToolCalls(args) {
4752
4838
  ...args.cursorPath === void 0 ? {} : { cursorPath: args.cursorPath }
4753
4839
  });
4754
4840
  if (summary.notEntitled) {
4755
- state5.set(codeName, { lastCheckedAt: nowMs, notEntitledAt: nowMs });
4841
+ state6.set(codeName, { lastCheckedAt: nowMs, notEntitledAt: nowMs });
4756
4842
  } else if (summary.callsIngested > 0) {
4757
- state5.set(codeName, { lastCheckedAt: nowMs, notEntitledAt: null });
4843
+ state6.set(codeName, { lastCheckedAt: nowMs, notEntitledAt: null });
4758
4844
  }
4759
4845
  } catch (err) {
4760
4846
  log2(`[tool-call-audit] ${codeName}: scan failed: ${err.message}`);
@@ -4768,7 +4854,7 @@ import { join as join21 } from "path";
4768
4854
  var MIN_CHECK_INTERVAL_MS7 = 6e4;
4769
4855
  var STATS_CACHE_PATH = join21(homedir12(), ".claude", "stats-cache.json");
4770
4856
  var ISO_DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
4771
- var state6 = { lastObservedDate: null, lastCheckedAt: 0 };
4857
+ var state7 = { lastObservedDate: null, lastCheckedAt: 0 };
4772
4858
  function selectNewDailyRows(raw, lastObservedDate) {
4773
4859
  let parsed;
4774
4860
  try {
@@ -4807,8 +4893,8 @@ async function maybeReportActivityCache(args) {
4807
4893
  const { api: api2, log: log2 } = args;
4808
4894
  const now = args.now ?? /* @__PURE__ */ new Date();
4809
4895
  const nowMs = now.getTime();
4810
- if (nowMs - state6.lastCheckedAt < MIN_CHECK_INTERVAL_MS7) return;
4811
- state6.lastCheckedAt = nowMs;
4896
+ if (nowMs - state7.lastCheckedAt < MIN_CHECK_INTERVAL_MS7) return;
4897
+ state7.lastCheckedAt = nowMs;
4812
4898
  if (!existsSync5(STATS_CACHE_PATH)) {
4813
4899
  return;
4814
4900
  }
@@ -4819,12 +4905,12 @@ async function maybeReportActivityCache(args) {
4819
4905
  log2(`[activity-cache] readFileSync failed: ${err.message}`);
4820
4906
  return;
4821
4907
  }
4822
- const rows = selectNewDailyRows(raw, state6.lastObservedDate);
4908
+ const rows = selectNewDailyRows(raw, state7.lastObservedDate);
4823
4909
  if (rows.length === 0) return;
4824
4910
  for (const row of rows) {
4825
4911
  try {
4826
4912
  await api2.post("/host/activity-observations", row);
4827
- state6.lastObservedDate = row.date;
4913
+ state7.lastObservedDate = row.date;
4828
4914
  } catch (err) {
4829
4915
  log2(
4830
4916
  `[activity-cache] POST /host/activity-observations failed for date=${row.date}: ${err.message}`
@@ -6010,21 +6096,21 @@ function nudgeIntervalForCount(nudgeCount, fullCadenceMs, maxCadenceMs) {
6010
6096
  const exponent = Math.max(0, Math.min(nudgeCount - 1, 8));
6011
6097
  return Math.min(fullCadenceMs * 3 ** exponent, Math.max(maxCadenceMs, fullCadenceMs));
6012
6098
  }
6013
- function shouldNudgeUnchangedBoard(signature, state8, now, fullCadenceMs, maxCadenceMs = fullCadenceMs) {
6014
- if (!state8) return true;
6015
- if (state8.signature !== signature) return true;
6016
- return now - state8.nudgedAt >= nudgeIntervalForCount(state8.nudgeCount ?? 1, fullCadenceMs, maxCadenceMs);
6099
+ function shouldNudgeUnchangedBoard(signature, state9, now, fullCadenceMs, maxCadenceMs = fullCadenceMs) {
6100
+ if (!state9) return true;
6101
+ if (state9.signature !== signature) return true;
6102
+ return now - state9.nudgedAt >= nudgeIntervalForCount(state9.nudgeCount ?? 1, fullCadenceMs, maxCadenceMs);
6017
6103
  }
6018
6104
  function failureRetryIntervalForCount(failureCount, baseMs, maxMs) {
6019
6105
  const exponent = Math.max(0, Math.min(failureCount - 1, 8));
6020
6106
  return Math.min(baseMs * 3 ** exponent, Math.max(maxMs, baseMs));
6021
6107
  }
6022
6108
  var KANBAN_NOTICE_BREAKER_THRESHOLD = 5;
6023
- function shouldAttemptNoticeEnqueue(state8, now, baseMs, maxMs, breakerThreshold = KANBAN_NOTICE_BREAKER_THRESHOLD) {
6024
- const failures = state8?.failureCount ?? 0;
6109
+ function shouldAttemptNoticeEnqueue(state9, now, baseMs, maxMs, breakerThreshold = KANBAN_NOTICE_BREAKER_THRESHOLD) {
6110
+ const failures = state9?.failureCount ?? 0;
6025
6111
  if (failures <= 0) return { attempt: true, breakerOpen: false };
6026
6112
  const breakerOpen = failures >= breakerThreshold;
6027
- const failedAt = state8?.failedAt;
6113
+ const failedAt = state9?.failedAt;
6028
6114
  const due = failedAt === void 0 || failedAt > now || now - failedAt >= failureRetryIntervalForCount(failures, baseMs, maxMs);
6029
6115
  return { attempt: due, breakerOpen };
6030
6116
  }
@@ -6314,7 +6400,7 @@ function loadKanbanNudgeState(target, configDir) {
6314
6400
  function saveKanbanNudgeState(source, configDir) {
6315
6401
  const path = getKanbanNudgeStateFile(configDir);
6316
6402
  const agents = {};
6317
- for (const [codeName, state8] of source) agents[codeName] = state8;
6403
+ for (const [codeName, state9] of source) agents[codeName] = state9;
6318
6404
  try {
6319
6405
  writeFileSync9(path, JSON.stringify({ version: KANBAN_NUDGE_STATE_VERSION, agents }, null, 2));
6320
6406
  } catch {
@@ -7154,8 +7240,8 @@ async function runScheduledCardDelivery(codeName, agentId, cardId, completedBy,
7154
7240
  markScheduledCardDeliveryComplete(cardId);
7155
7241
  return "terminal";
7156
7242
  }
7157
- const state8 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
7158
- const task = state8.tasks[card.source_ref];
7243
+ const state9 = claudeSchedulerStates.get(codeName) ?? loadSchedulerState(codeName);
7244
+ const task = state9.tasks[card.source_ref];
7159
7245
  if (!task) {
7160
7246
  log(`[scheduled-kanban] delivery: no scheduler task for source_ref=${card.source_ref} on '${codeName}' \u2014 skipping`);
7161
7247
  markScheduledCardDeliveryComplete(cardId);
@@ -7607,16 +7693,16 @@ async function syncAndCheckClaudeScheduler(agent, tasks, boardItems, refreshData
7607
7693
  const prevHash = agentState.knownTasksHashes.get(agent.agent_id);
7608
7694
  if (combinedHash !== prevHash) {
7609
7695
  const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
7610
- const state9 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
7611
- claudeSchedulerStates.set(codeName, state9);
7696
+ const state10 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
7697
+ claudeSchedulerStates.set(codeName, state10);
7612
7698
  agentState.knownTasksHashes.set(agent.agent_id, combinedHash);
7613
7699
  log(`[claude-scheduler] Tasks synced for '${codeName}' (${taskInputs.length} task(s))`);
7614
7700
  }
7615
7701
  if (!claudeSchedulerStates.has(codeName)) {
7616
7702
  claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
7617
7703
  }
7618
- const state8 = claudeSchedulerStates.get(codeName);
7619
- const ready = getReadyTasks(state8, inFlightClaudeTasks);
7704
+ const state9 = claudeSchedulerStates.get(codeName);
7705
+ const ready = getReadyTasks(state9, inFlightClaudeTasks);
7620
7706
  if (ready.length === 0) return;
7621
7707
  const limitedUntil = readUsageCapUntil({ codeName, projectDir: getProjectDir(codeName) });
7622
7708
  if (limitedUntil) {
@@ -7759,17 +7845,17 @@ function candidateTranscriptPaths(dir) {
7759
7845
  return { paths, complete };
7760
7846
  }
7761
7847
  function foldToolCallBrackets(codeName, eventsByPath, nowMs) {
7762
- const state8 = brackets.get(codeName) ?? {
7848
+ const state9 = brackets.get(codeName) ?? {
7763
7849
  open: /* @__PURE__ */ new Map(),
7764
7850
  closed: []
7765
7851
  };
7766
7852
  const nextOpen = /* @__PURE__ */ new Map();
7767
7853
  const openOut = [];
7768
- const paths = /* @__PURE__ */ new Set([...state8.open.keys(), ...eventsByPath.keys()]);
7854
+ const paths = /* @__PURE__ */ new Set([...state9.open.keys(), ...eventsByPath.keys()]);
7769
7855
  for (const path of paths) {
7770
- const carried = state8.open.get(path) ?? [];
7856
+ const carried = state9.open.get(path) ?? [];
7771
7857
  const paired = pairToolCallBrackets(eventsByPath.get(path) ?? [], carried);
7772
- state8.closed.push(...paired.brackets);
7858
+ state9.closed.push(...paired.brackets);
7773
7859
  const live = paired.open.filter((c) => nowMs - c.startMs <= MAX_BRACKET_DEFERRAL_MS);
7774
7860
  if (live.length > 0) {
7775
7861
  nextOpen.set(path, live);
@@ -7779,7 +7865,7 @@ function foldToolCallBrackets(codeName, eventsByPath, nowMs) {
7779
7865
  const keepFrom = nowMs - GATE_MAX_BUCKET_AGE_MS;
7780
7866
  const seen = /* @__PURE__ */ new Set();
7781
7867
  const closed = [];
7782
- for (const b of state8.closed) {
7868
+ for (const b of state9.closed) {
7783
7869
  if (b.endMs < keepFrom) continue;
7784
7870
  const key = `${b.id}\0${b.startMs}\0${b.endMs}`;
7785
7871
  if (seen.has(key)) continue;
@@ -8053,8 +8139,8 @@ function countDefunct(cgroupDir, readText) {
8053
8139
  if (stat2 == null) continue;
8054
8140
  const close = stat2.lastIndexOf(")");
8055
8141
  if (close < 0) continue;
8056
- const state8 = stat2.slice(close + 1).trim().charAt(0);
8057
- if (state8 === "Z") defunct += 1;
8142
+ const state9 = stat2.slice(close + 1).trim().charAt(0);
8143
+ if (state9 === "Z") defunct += 1;
8058
8144
  }
8059
8145
  return defunct;
8060
8146
  }
@@ -9225,16 +9311,16 @@ async function syncAndCheckOpencodeScheduler(agent, tasks, refreshData) {
9225
9311
  const tasksHash = createHash15("sha256").update(JSON.stringify(tasks)).digest("hex").slice(0, 16);
9226
9312
  if (knownOpencodeTaskHashes.get(agent.agent_id) !== tasksHash) {
9227
9313
  const taskInputs = tasks.map((t) => buildSchedulerTaskInput(t));
9228
- const state9 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
9229
- opencodeSchedulerStates.set(codeName, state9);
9314
+ const state10 = syncTasksToScheduler(codeName, agent.agent_id, taskInputs);
9315
+ opencodeSchedulerStates.set(codeName, state10);
9230
9316
  knownOpencodeTaskHashes.set(agent.agent_id, tasksHash);
9231
9317
  log(`[opencode-scheduler] tasks synced for '${codeName}' (${taskInputs.length} task(s))`);
9232
9318
  }
9233
9319
  if (!opencodeSchedulerStates.has(codeName)) {
9234
9320
  opencodeSchedulerStates.set(codeName, loadSchedulerState(codeName));
9235
9321
  }
9236
- const state8 = opencodeSchedulerStates.get(codeName);
9237
- const ready = getReadyTasks(state8, inFlightOpencodeTasks);
9322
+ const state9 = opencodeSchedulerStates.get(codeName);
9323
+ const ready = getReadyTasks(state9, inFlightOpencodeTasks);
9238
9324
  if (ready.length === 0) return;
9239
9325
  if (!isOpencodeSessionHealthy(codeName)) {
9240
9326
  log(`[opencode-scheduler] '${codeName}' has ${ready.length} due task(s) but no healthy serve yet - deferring`);
@@ -10109,10 +10195,10 @@ function recordWedgeForCards(states, inProgressCardIds, nowMs, config2) {
10109
10195
  function pruneCardStates(states, liveInProgressCardIds, nowMs, config2) {
10110
10196
  const live = liveInProgressCardIds instanceof Set ? liveInProgressCardIds : new Set(liveInProgressCardIds);
10111
10197
  const next = /* @__PURE__ */ new Map();
10112
- for (const [id, state8] of states) {
10198
+ for (const [id, state9] of states) {
10113
10199
  if (!live.has(id)) continue;
10114
- if (nowMs - state8.lastWedgeAtMs > config2.cooldownMs) continue;
10115
- next.set(id, state8);
10200
+ if (nowMs - state9.lastWedgeAtMs > config2.cooldownMs) continue;
10201
+ next.set(id, state9);
10116
10202
  }
10117
10203
  return next;
10118
10204
  }
@@ -11053,8 +11139,8 @@ var KNOWN_SAFE_TAIL_SIGNATURES = /* @__PURE__ */ new Set(["session_id_in_use"]);
11053
11139
  function shouldSkipRevokedCleanup(previousKnownStatus) {
11054
11140
  return previousKnownStatus === "revoked";
11055
11141
  }
11056
- function hasRevokedResiduals(state8) {
11057
- return state8.gatewayRunning || state8.portAllocated || state8.provisionDirExists;
11142
+ function hasRevokedResiduals(state9) {
11143
+ return state9.gatewayRunning || state9.portAllocated || state9.provisionDirExists;
11058
11144
  }
11059
11145
  var pendingSessionRestarts = /* @__PURE__ */ new Map();
11060
11146
  var lastRestartWasExternal = /* @__PURE__ */ new Map();
@@ -11256,12 +11342,12 @@ function maybeClearStaleTrip(agent) {
11256
11342
  const marker = getAutoResumeMarker(codeName);
11257
11343
  const isSelfResume = marker !== void 0 && Date.now() - marker.autoResumedAt < AUTO_RESUME_SELF_WINDOW_MS;
11258
11344
  if (!isSelfResume) deleteAutoResumeMarker(codeName);
11259
- state7 = {
11260
- ...state7,
11345
+ state8 = {
11346
+ ...state8,
11261
11347
  circuitBreakerTrips: restartBreaker.serialize(),
11262
11348
  circuitBreakerAutoResumes: Object.fromEntries(autoResumeMarkers.entries())
11263
11349
  };
11264
- send({ type: "state-update", state: state7 });
11350
+ send({ type: "state-update", state: state8 });
11265
11351
  }
11266
11352
  var autoResumeMarkers = /* @__PURE__ */ new Map();
11267
11353
  function autoResumeMarkerKey(codeName) {
@@ -11354,12 +11440,12 @@ function maybeAutoResume(agent) {
11354
11440
  restartBreaker.clear(codeName);
11355
11441
  reportedTrips.delete(codeName);
11356
11442
  dependencyRecoveryLedger.clear(codeName);
11357
- state7 = {
11358
- ...state7,
11443
+ state8 = {
11444
+ ...state8,
11359
11445
  circuitBreakerTrips: restartBreaker.serialize(),
11360
11446
  circuitBreakerAutoResumes: Object.fromEntries(autoResumeMarkers.entries())
11361
11447
  };
11362
- send({ type: "state-update", state: state7 });
11448
+ send({ type: "state-update", state: state8 });
11363
11449
  log(`[auto-resume] agent=${codeName} resumed \u2014 re-trip within backoff window will stay paused (ENG-6088)`);
11364
11450
  } else {
11365
11451
  autoResumeStandDowns.add(`${codeName}:${trippedAt}`);
@@ -11468,12 +11554,12 @@ async function maybeResumeReconcile(agent) {
11468
11554
  restartBreaker.clear(codeName);
11469
11555
  reportedTrips.delete(codeName);
11470
11556
  dependencyRecoveryLedger.clear(codeName);
11471
- state7 = {
11472
- ...state7,
11557
+ state8 = {
11558
+ ...state8,
11473
11559
  circuitBreakerTrips: restartBreaker.serialize(),
11474
11560
  circuitBreakerAutoResumes: Object.fromEntries(autoResumeMarkers.entries())
11475
11561
  };
11476
- send({ type: "state-update", state: state7 });
11562
+ send({ type: "state-update", state: state8 });
11477
11563
  log(`[resume-reconciler] agent=${codeName} resumed \u2014 a re-trip within the backoff window will latch unstable (ENG-6383)`);
11478
11564
  } else {
11479
11565
  autoResumeStandDowns.add(standDownKey);
@@ -11754,7 +11840,7 @@ var pendingDayRolloverReset = /* @__PURE__ */ new Set();
11754
11840
  var dayRolloverInboundHold = /* @__PURE__ */ new Map();
11755
11841
  var INBOUND_HOLD_EPISODE_GAP_MS = 12e4;
11756
11842
  async function channelInboundActivityAgeSecondsFor(codeName) {
11757
- const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-H3UBUTW7.js");
11843
+ const { newestPendingInboundActivityMtimeMs } = await import("../responsiveness-probe-VJP2AHNR.js");
11758
11844
  const newest = newestPendingInboundActivityMtimeMs(dirname10(paneLogPath(codeName)));
11759
11845
  if (newest === null) return null;
11760
11846
  return Math.max(0, Math.floor((Date.now() - newest) / 1e3));
@@ -11903,7 +11989,7 @@ function restartGateFor(codeName, reason) {
11903
11989
  }
11904
11990
  function isHostBusyForForcedUpdate(opts) {
11905
11991
  const now = /* @__PURE__ */ new Date();
11906
- for (const agent of state7.agents) {
11992
+ for (const agent of state8.agents) {
11907
11993
  const decision = decideRestartGate({
11908
11994
  window: null,
11909
11995
  paneLogAgeSeconds: paneLogAgeSecondsFor(agent.codeName),
@@ -11936,7 +12022,7 @@ function runPendingForcedUpdate() {
11936
12022
  relaxed
11937
12023
  } = decidePendingForcedUpdate({
11938
12024
  requestedAt: requestedUpdateAt,
11939
- lastProcessedAt: state7.lastUpdateRequestProcessedAt ?? null,
12025
+ lastProcessedAt: state8.lastUpdateRequestProcessedAt ?? null,
11940
12026
  deferStreak: forcedUpdateDeferStreak,
11941
12027
  nowMs: Date.now(),
11942
12028
  isHostBusy: (isRelaxed) => isHostBusyForForcedUpdate({ relaxed: isRelaxed })
@@ -11970,7 +12056,7 @@ function runPendingForcedUpdate() {
11970
12056
  log(
11971
12057
  forcedUpdate === "consume-deadline" ? `[self-update] WARN "Update CLI now" requested at ${requestedUpdateAt} has been pending ${describePendingFor(pendingForMs)} and the host still reads busy \u2014 running the window-bypassing self-update anyway (ENG-8449 hard deadline). A live turn may be interrupted; the operator asked for this update explicitly.` : `[self-update] "Update CLI now" requested at ${requestedUpdateAt} \u2014 running window-bypassing self-update now (host idle${relaxed ? ", relaxed gate" : ""}).`
11972
12058
  );
11973
- const prevProcessedAt = state7.lastUpdateRequestProcessedAt ?? null;
12059
+ const prevProcessedAt = state8.lastUpdateRequestProcessedAt ?? null;
11974
12060
  void checkAndUpdateCli({ force: true }).then((outcome) => {
11975
12061
  if (!shouldConsumeForcedUpdate(outcome)) {
11976
12062
  log(
@@ -11981,11 +12067,11 @@ function runPendingForcedUpdate() {
11981
12067
  log(
11982
12068
  outcome === "updated" ? `[self-update] "Update CLI now" completed \u2014 upgrade installed; manager restart scheduled.` : `[self-update] "Update CLI now" completed \u2014 host was already on the latest in-channel build; nothing to install.`
11983
12069
  );
11984
- state7.lastUpdateRequestProcessedAt = requestedUpdateAt;
12070
+ state8.lastUpdateRequestProcessedAt = requestedUpdateAt;
11985
12071
  try {
11986
- atomicWriteFileSync(getStateFile(), JSON.stringify(state7, null, 2));
12072
+ atomicWriteFileSync(getStateFile(), JSON.stringify(state8, null, 2));
11987
12073
  } catch (err) {
11988
- state7.lastUpdateRequestProcessedAt = prevProcessedAt;
12074
+ state8.lastUpdateRequestProcessedAt = prevProcessedAt;
11989
12075
  log(
11990
12076
  `[self-update] failed to persist update-request ack; retrying next poll: ${err.message}`
11991
12077
  );
@@ -12345,7 +12431,7 @@ var STALE_TASK_THRESHOLD_MS = (() => {
12345
12431
  })();
12346
12432
  var taskDisplayInfo = /* @__PURE__ */ new Map();
12347
12433
  var activeChannels = /* @__PURE__ */ new Map();
12348
- var state7 = {
12434
+ var state8 = {
12349
12435
  pid: process.pid,
12350
12436
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
12351
12437
  lastPollAt: null,
@@ -12402,7 +12488,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
12402
12488
  var lastVersionCheckAt = 0;
12403
12489
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
12404
12490
  var lastResponsivenessProbeAt = 0;
12405
- var agtCliVersion = true ? "0.28.693" : "dev";
12491
+ var agtCliVersion = true ? "0.28.695" : "dev";
12406
12492
  function resolveBrewPath(execFileSync3) {
12407
12493
  try {
12408
12494
  const out = execFileSync3("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -13391,6 +13477,46 @@ async function runClaudeRuntimeAuthProbe() {
13391
13477
  });
13392
13478
  }
13393
13479
  }
13480
+ async function runHostUsageCommand() {
13481
+ try {
13482
+ const childEnv = { ...process.env };
13483
+ await applyClaudeAuthToEnv(childEnv, "host-usage-poll");
13484
+ const emptyMcp = ensureEvalEmptyMcpConfig();
13485
+ const args = [
13486
+ ...USAGE_COMMAND_ARGS,
13487
+ "--mcp-config",
13488
+ emptyMcp,
13489
+ "--strict-mcp-config",
13490
+ "--permission-mode",
13491
+ "auto",
13492
+ "--allowedTools",
13493
+ ""
13494
+ ];
13495
+ const { stdout } = await execFilePromiseLong(resolveClaudeBinary(), args, {
13496
+ cwd: homedir17(),
13497
+ timeout: HOST_USAGE_POLL_TIMEOUT_MS,
13498
+ stdin: "ignore",
13499
+ env: childEnv,
13500
+ onSpawn: (pid) => registerClaudeSpawn({ pid, started_at: Date.now(), kind: "conv-eval" }),
13501
+ onExit: (pid) => unregisterClaudeSpawn(pid)
13502
+ });
13503
+ return { stdout, failed: false };
13504
+ } catch (err) {
13505
+ if (err instanceof ChildProcessError) return { stdout: err.stdout ?? "", failed: true };
13506
+ return { stdout: "", failed: true };
13507
+ }
13508
+ }
13509
+ async function maybePollHostUsageFromCycle() {
13510
+ const { execFileSync: execFileSync3 } = await import("child_process");
13511
+ if (!claudeBinaryInstalled(execFileSync3)) return;
13512
+ await maybePollHostUsage({
13513
+ api,
13514
+ runUsageCommand: runHostUsageCommand,
13515
+ authMode: getCachedClaudeAuthMode(),
13516
+ cliVersion: cachedFrameworkVersion,
13517
+ log
13518
+ });
13519
+ }
13394
13520
  async function checkClaudeAuth() {
13395
13521
  try {
13396
13522
  const report = await detectClaudeAuth();
@@ -13561,21 +13687,21 @@ function recordChannelSyncFailure(failures, agentId, reason, now) {
13561
13687
  failures.set(agentId, next);
13562
13688
  return next;
13563
13689
  }
13564
- function shouldLogChannelSyncFailure(state8) {
13565
- if (state8.attempts === 1) return true;
13566
- if (state8.attempts <= CHANNEL_SYNC_FREE_ATTEMPTS) return false;
13567
- return state8.attempts > state8.loggedAtAttempt;
13690
+ function shouldLogChannelSyncFailure(state9) {
13691
+ if (state9.attempts === 1) return true;
13692
+ if (state9.attempts <= CHANNEL_SYNC_FREE_ATTEMPTS) return false;
13693
+ return state9.attempts > state9.loggedAtAttempt;
13568
13694
  }
13569
13695
  function stuckChannelSyncs(failures, now, thresholdMs = CHANNEL_SYNC_STUCK_AFTER_MS) {
13570
13696
  const out = [];
13571
- for (const [agentId, state8] of failures) {
13572
- const stuckForMs = now - state8.since;
13697
+ for (const [agentId, state9] of failures) {
13698
+ const stuckForMs = now - state9.since;
13573
13699
  if (stuckForMs < thresholdMs) continue;
13574
13700
  out.push({
13575
13701
  agent_id: agentId,
13576
- attempts: state8.attempts,
13702
+ attempts: state9.attempts,
13577
13703
  stuck_for_seconds: Math.floor(stuckForMs / 1e3),
13578
- reason: state8.lastReason
13704
+ reason: state9.lastReason
13579
13705
  });
13580
13706
  }
13581
13707
  out.sort((a, b) => b.stuck_for_seconds - a.stuck_for_seconds);
@@ -13863,7 +13989,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
13863
13989
  if (codeNames.length === 0) return;
13864
13990
  void (async () => {
13865
13991
  try {
13866
- const { collectDiagnostics } = await import("../persistent-session-PPBLGH2J.js");
13992
+ const { collectDiagnostics } = await import("../persistent-session-PEY2TMJI.js");
13867
13993
  await api.post("/host/heartbeat", {
13868
13994
  host_id: hostId,
13869
13995
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -13959,6 +14085,7 @@ async function pollCycleInner() {
13959
14085
  }
13960
14086
  maybeUpgradeClaudeCode().catch((err) => log(`[claude-code-upgrade] Check failed: ${err.message}`));
13961
14087
  maybeProbeClaudeRuntimeAuth().catch((err) => log(`[runtime-auth-probe] Check failed: ${err.message}`));
14088
+ maybePollHostUsageFromCycle().catch((err) => log(`[host-usage] Check failed: ${err.message}`));
13962
14089
  try {
13963
14090
  registeredAgentsCache.clear();
13964
14091
  const hostId = await getHostId();
@@ -13969,7 +14096,7 @@ async function pollCycleInner() {
13969
14096
  const now = Date.now();
13970
14097
  if (now - lastVersionCheckAt > VERSION_CHECK_INTERVAL_MS) {
13971
14098
  try {
13972
- const firstAgent = state7.agents[0];
14099
+ const firstAgent = state8.agents[0];
13973
14100
  const versionAdapter = firstAgent ? resolveAgentFramework(firstAgent.codeName) : getFramework(DEFAULT_FRAMEWORK);
13974
14101
  if (versionAdapter.getVersion) {
13975
14102
  cachedFrameworkVersion = await versionAdapter.getVersion();
@@ -13980,7 +14107,7 @@ async function pollCycleInner() {
13980
14107
  }
13981
14108
  try {
13982
14109
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
13983
- const { collectDiagnostics } = await import("../persistent-session-PPBLGH2J.js");
14110
+ const { collectDiagnostics } = await import("../persistent-session-PEY2TMJI.js");
13984
14111
  const diagCodeNames = [...agentState.persistentSessionAgents];
13985
14112
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor) : void 0;
13986
14113
  let tailscaleHostname;
@@ -14013,7 +14140,7 @@ async function pollCycleInner() {
14013
14140
  const errId = createHash17("sha256").update(errText).digest("hex").slice(0, 12);
14014
14141
  log(`Claude auth detection failed (error_id=${errId})`);
14015
14142
  }
14016
- const hostHasClaudeCode = state7.agents.some(
14143
+ const hostHasClaudeCode = state8.agents.some(
14017
14144
  (a) => agentFrameworkCache.get(a.codeName) === "claude-code"
14018
14145
  );
14019
14146
  if (hostHasClaudeCode) {
@@ -14092,7 +14219,7 @@ async function pollCycleInner() {
14092
14219
  // ENG-6692: ack the last consumed "Update CLI now" timestamp so the API
14093
14220
  // clears hosts.update_requested_at. Echoes our persisted dedup marker;
14094
14221
  // null until we've ever consumed one.
14095
- update_request_processed_at: state7.lastUpdateRequestProcessedAt ?? null
14222
+ update_request_processed_at: state8.lastUpdateRequestProcessedAt ?? null
14096
14223
  });
14097
14224
  if (hbResp?.maintenance_window) {
14098
14225
  cachedMaintenanceWindow = hbResp.maintenance_window;
@@ -14132,7 +14259,7 @@ async function pollCycleInner() {
14132
14259
  collectPanelessActivityProbes,
14133
14260
  getResponsivenessIntervalMs,
14134
14261
  occupancyQualificationClassifications
14135
- } = await import("../responsiveness-probe-H3UBUTW7.js");
14262
+ } = await import("../responsiveness-probe-VJP2AHNR.js");
14136
14263
  const probeIntervalMs = getResponsivenessIntervalMs();
14137
14264
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
14138
14265
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -14242,7 +14369,7 @@ async function pollCycleInner() {
14242
14369
  collectResponsivenessProbes,
14243
14370
  livePendingInboundOldestAgeSeconds,
14244
14371
  parkPendingInbound
14245
- } = await import("../responsiveness-probe-H3UBUTW7.js");
14372
+ } = await import("../responsiveness-probe-VJP2AHNR.js");
14246
14373
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
14247
14374
  const wedgeNow = /* @__PURE__ */ new Date();
14248
14375
  const liveAgents = agentState.persistentSessionAgents;
@@ -14398,7 +14525,7 @@ async function pollCycleInner() {
14398
14525
  }
14399
14526
  try {
14400
14527
  const { scrapeMcpFailedBannerCount } = await import("../pane-mcp-banner-scraper-JA437JIB.js");
14401
- const { probeSessionAuth } = await import("../session-auth-dead-K3XQNN5A.js");
14528
+ const { probeSessionAuth } = await import("../session-auth-dead-QCZ2EOVS.js");
14402
14529
  const observations = [];
14403
14530
  const pendingCacheCommits = [];
14404
14531
  const modelApiErrorReportingOn = hostFlagStore().getBoolean("model-api-error-reporting");
@@ -14479,7 +14606,7 @@ async function pollCycleInner() {
14479
14606
  const requested = agent.restart_requested_at ?? null;
14480
14607
  if (!requested) continue;
14481
14608
  if (restartInFlight.has(agent.agent_id)) continue;
14482
- const prev = state7.agents.find((a) => a.agentId === agent.agent_id);
14609
+ const prev = state8.agents.find((a) => a.agentId === agent.agent_id);
14483
14610
  const lastProcessed = prev?.lastRestartProcessedAt ?? null;
14484
14611
  const alreadyServiced = lastProcessed != null && Date.parse(lastProcessed) >= Date.parse(requested);
14485
14612
  if (!alreadyServiced) {
@@ -14560,7 +14687,7 @@ async function pollCycleInner() {
14560
14687
  managedPruneLedger = createManagedPruneLedger();
14561
14688
  for (const agent of processOrder) {
14562
14689
  if (restartInFlight.has(agent.agent_id)) {
14563
- const existing = state7.agents.find((a) => a.agentId === agent.agent_id);
14690
+ const existing = state8.agents.find((a) => a.agentId === agent.agent_id);
14564
14691
  if (existing) {
14565
14692
  agentStates.push(existing);
14566
14693
  continue;
@@ -14570,7 +14697,7 @@ async function pollCycleInner() {
14570
14697
  await processAgent(agent, agentStates, managedToolkits);
14571
14698
  } catch (err) {
14572
14699
  log(`Error processing agent '${agent.code_name}': ${err.message}`);
14573
- const existing = state7.agents.find((a) => a.agentId === agent.agent_id);
14700
+ const existing = state8.agents.find((a) => a.agentId === agent.agent_id);
14574
14701
  if (existing) {
14575
14702
  agentStates.push(existing);
14576
14703
  } else {
@@ -14601,12 +14728,12 @@ async function pollCycleInner() {
14601
14728
  if (crossAgentPrune) log(crossAgentPrune);
14602
14729
  const restartAckStateChanged = applyRestartAcks({
14603
14730
  agentStates,
14604
- priorAgents: state7.agents,
14731
+ priorAgents: state8.agents,
14605
14732
  restartAcks
14606
14733
  });
14607
14734
  if (restartAckStateChanged) {
14608
14735
  try {
14609
- const ackedState = { ...state7, agents: agentStates };
14736
+ const ackedState = { ...state8, agents: agentStates };
14610
14737
  atomicWriteFileSync(getStateFile(), JSON.stringify(ackedState, null, 2));
14611
14738
  } catch (err) {
14612
14739
  log(`[restart] failed to persist ack immediately: ${err.message}`);
@@ -14628,7 +14755,7 @@ async function pollCycleInner() {
14628
14755
  } catch {
14629
14756
  }
14630
14757
  const currentIds = new Set(agents.map((a) => a.agent_id));
14631
- for (const prev of state7.agents) {
14758
+ for (const prev of state8.agents) {
14632
14759
  if (!currentIds.has(prev.agentId)) {
14633
14760
  log(`Agent '${prev.codeName}' removed from host (deleted or unassigned)`);
14634
14761
  const adapter = resolveAgentFramework(prev.codeName);
@@ -14790,10 +14917,10 @@ async function pollCycleInner() {
14790
14917
  }
14791
14918
  } catch {
14792
14919
  }
14793
- state7 = {
14794
- ...state7,
14920
+ state8 = {
14921
+ ...state8,
14795
14922
  lastPollAt: (/* @__PURE__ */ new Date()).toISOString(),
14796
- pollCount: state7.pollCount + 1,
14923
+ pollCount: state8.pollCount + 1,
14797
14924
  agents: agentStates,
14798
14925
  // ENG-5441: serialise trip state on every poll so manager restarts
14799
14926
  // never silently clear a tripped breaker. Cheap — only tripped
@@ -14807,9 +14934,9 @@ async function pollCycleInner() {
14807
14934
  consecutivePollFailures = 0;
14808
14935
  }
14809
14936
  verifyPendingRestarts(Date.now());
14810
- send({ type: "state-update", state: state7 });
14937
+ send({ type: "state-update", state: state8 });
14811
14938
  } catch (err) {
14812
- state7.errorCount++;
14939
+ state8.errorCount++;
14813
14940
  const message = err.message;
14814
14941
  log(`Poll error: ${message}`);
14815
14942
  send({ type: "error", message });
@@ -15105,11 +15232,11 @@ async function processAgent(agent, agentStates, managedToolkits) {
15105
15232
  const marker = getAutoResumeMarker(agent.code_name);
15106
15233
  const isSelfResume = marker !== void 0 && Date.now() - marker.autoResumedAt < AUTO_RESUME_SELF_WINDOW_MS;
15107
15234
  if (!isSelfResume && deleteAutoResumeMarker(agent.code_name)) {
15108
- state7 = {
15109
- ...state7,
15235
+ state8 = {
15236
+ ...state8,
15110
15237
  circuitBreakerAutoResumes: Object.fromEntries(autoResumeMarkers.entries())
15111
15238
  };
15112
- send({ type: "state-update", state: state7 });
15239
+ send({ type: "state-update", state: state8 });
15113
15240
  log(`[auto-resume] Cleared auto-resume marker for '${agent.code_name}' on operator resume \u2014 credit re-armed (ENG-6088)`);
15114
15241
  }
15115
15242
  }
@@ -15140,7 +15267,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
15140
15267
  });
15141
15268
  } catch (err) {
15142
15269
  log(`Refresh failed for '${agent.code_name}': ${err.message}`);
15143
- const existing = state7.agents.find((a) => a.agentId === agent.agent_id);
15270
+ const existing = state8.agents.find((a) => a.agentId === agent.agent_id);
15144
15271
  agentStates.push(existing ?? {
15145
15272
  agentId: agent.agent_id,
15146
15273
  codeName: agent.code_name,
@@ -15204,7 +15331,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
15204
15331
  const charterVersion = refreshData.charter.version;
15205
15332
  const toolsVersion = refreshData.tools.version;
15206
15333
  const known = agentState.knownVersions.get(agent.agent_id);
15207
- let lastProvisionAt = state7.agents.find((a) => a.agentId === agent.agent_id)?.lastProvisionAt ?? null;
15334
+ let lastProvisionAt = state8.agents.find((a) => a.agentId === agent.agent_id)?.lastProvisionAt ?? null;
15208
15335
  const quarantinedChannels = channelQuarantineStore().getQuarantinedKeys(agent.code_name);
15209
15336
  const currentChannelIds = setWithout(
15210
15337
  launchableChannelIds(refreshData.channel_configs),
@@ -15659,18 +15786,18 @@ async function processAgent(agent, agentStates, managedToolkits) {
15659
15786
  agentState.knownChannels.set(agent.agent_id, currentChannelIds);
15660
15787
  }
15661
15788
  } else {
15662
- const state8 = recordChannelSyncFailure(
15789
+ const state9 = recordChannelSyncFailure(
15663
15790
  channelSyncFailures,
15664
15791
  agent.agent_id,
15665
15792
  channelConfigFailureReason || "reason not recorded",
15666
15793
  Date.now()
15667
15794
  );
15668
- if (shouldLogChannelSyncFailure(state8)) {
15669
- state8.loggedAtAttempt = state8.attempts;
15670
- const stuckForSeconds = Math.floor((Date.now() - state8.since) / 1e3);
15671
- const waitMs = channelSyncBackoffMs(state8.attempts);
15795
+ if (shouldLogChannelSyncFailure(state9)) {
15796
+ state9.loggedAtAttempt = state9.attempts;
15797
+ const stuckForSeconds = Math.floor((Date.now() - state9.since) / 1e3);
15798
+ const waitMs = channelSyncBackoffMs(state9.attempts);
15672
15799
  log(
15673
- `[channels] Credential sync did not converge for '${agent.code_name}' \u2014 attempt ${state8.attempts}, stuck ${stuckForSeconds}s, next retry in ${Math.round(waitMs / 1e3)}s. Cause: ${state8.lastReason}. Diff left live (ENG-9252).`
15800
+ `[channels] Credential sync did not converge for '${agent.code_name}' \u2014 attempt ${state9.attempts}, stuck ${stuckForSeconds}s, next retry in ${Math.round(waitMs / 1e3)}s. Cause: ${state9.lastReason}. Diff left live (ENG-9252).`
15674
15801
  );
15675
15802
  }
15676
15803
  }
@@ -15970,7 +16097,7 @@ async function processAgent(agent, agentStates, managedToolkits) {
15970
16097
  log(`Failed to provision direct-chat channel for '${agent.code_name}': ${err.message}`);
15971
16098
  }
15972
16099
  }
15973
- let lastSecretsProvisionAt = state7.agents.find((a) => a.agentId === agent.agent_id)?.lastSecretsProvisionAt ?? null;
16100
+ let lastSecretsProvisionAt = state8.agents.find((a) => a.agentId === agent.agent_id)?.lastSecretsProvisionAt ?? null;
15974
16101
  let secretsHash = agentState.knownSecretsHashes.get(agent.agent_id) ?? null;
15975
16102
  try {
15976
16103
  const secretsData = await api.post("/host/secrets", { agent_id: agent.agent_id });
@@ -17854,9 +17981,9 @@ ${truncateForLog(ctx.tail)}` : `; pane_tail_hash=sha256:${createHash17("sha256")
17854
17981
  } else if (!claudeSchedulerStates.has(codeName)) {
17855
17982
  claudeSchedulerStates.set(codeName, loadSchedulerState(codeName));
17856
17983
  }
17857
- const state8 = claudeSchedulerStates.get(codeName);
17858
- if (state8) {
17859
- const ready = getReadyTasks(state8, inFlightClaudeTasks);
17984
+ const state9 = claudeSchedulerStates.get(codeName);
17985
+ if (state9) {
17986
+ const ready = getReadyTasks(state9, inFlightClaudeTasks);
17860
17987
  if (ready.length > 0) {
17861
17988
  log(`[persistent-session] ${ready.length} ready task(s) for '${codeName}': ${ready.map((t) => `${t.name}(next=${t.nextFireAt ? new Date(t.nextFireAt).toISOString() : "null"})`).join(", ")}`);
17862
17989
  }
@@ -17950,19 +18077,19 @@ function recordRealtimeRebindFailure(failures, agentId, status, now) {
17950
18077
  return next;
17951
18078
  }
17952
18079
  function realtimeRebindDue(failures, now) {
17953
- for (const state8 of failures.values()) if (now >= state8.nextAttemptAt) return true;
18080
+ for (const state9 of failures.values()) if (now >= state9.nextAttemptAt) return true;
17954
18081
  return false;
17955
18082
  }
17956
18083
  function stuckRealtimeRebinds(failures, now, thresholdMs = REALTIME_REBIND_STUCK_AFTER_MS) {
17957
18084
  const out = [];
17958
- for (const [agentId, state8] of failures) {
17959
- const stuckForMs = now - state8.since;
18085
+ for (const [agentId, state9] of failures) {
18086
+ const stuckForMs = now - state9.since;
17960
18087
  if (stuckForMs < thresholdMs) continue;
17961
18088
  out.push({
17962
18089
  agent_id: agentId,
17963
- attempts: state8.attempts,
18090
+ attempts: state9.attempts,
17964
18091
  stuck_for_seconds: Math.floor(stuckForMs / 1e3),
17965
- status: state8.lastStatus
18092
+ status: state9.lastStatus
17966
18093
  });
17967
18094
  }
17968
18095
  out.sort((a, b) => b.stuck_for_seconds - a.stuck_for_seconds);
@@ -17985,8 +18112,8 @@ function pruneRealtimeRebindState(failures, liveAgentIds) {
17985
18112
  function holdRealtimeRebindInFlight(failures, agentIds, now, graceMs = REALTIME_REBIND_IN_FLIGHT_GRACE_MS) {
17986
18113
  const until = now + graceMs;
17987
18114
  for (const agentId of agentIds) {
17988
- const state8 = failures.get(agentId);
17989
- if (state8) state8.nextAttemptAt = Math.max(state8.nextAttemptAt, until);
18115
+ const state9 = failures.get(agentId);
18116
+ if (state9) state9.nextAttemptAt = Math.max(state9.nextAttemptAt, until);
17990
18117
  }
17991
18118
  }
17992
18119
  var realtimeAssignStarted = false;
@@ -18107,7 +18234,7 @@ function restartReasonStampsTiming(reason) {
18107
18234
  return reason === "integration-change";
18108
18235
  }
18109
18236
  async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
18110
- const prev = state7.agents.find((a) => a.agentId === agentId);
18237
+ const prev = state8.agents.find((a) => a.agentId === agentId);
18111
18238
  const codeName = prev?.codeName;
18112
18239
  if (!codeName) return;
18113
18240
  const lastProcessed = prev?.lastRestartProcessedAt ?? null;
@@ -18158,7 +18285,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
18158
18285
  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}`));
18159
18286
  void (async () => {
18160
18287
  try {
18161
- const { collectDiagnostics } = await import("../persistent-session-PPBLGH2J.js");
18288
+ const { collectDiagnostics } = await import("../persistent-session-PEY2TMJI.js");
18162
18289
  await api.post("/host/heartbeat", {
18163
18290
  host_id: hostId,
18164
18291
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -18169,7 +18296,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
18169
18296
  })();
18170
18297
  prev.lastRestartProcessedAt = requestedAt;
18171
18298
  try {
18172
- atomicWriteFileSync(getStateFile(), JSON.stringify(state7, null, 2));
18299
+ atomicWriteFileSync(getStateFile(), JSON.stringify(state8, null, 2));
18173
18300
  } catch (err) {
18174
18301
  log(`[restart-lane] failed to persist ack for '${codeName}': ${err.message}`);
18175
18302
  }
@@ -18179,7 +18306,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
18179
18306
  }
18180
18307
  }
18181
18308
  async function respawnAgentAfterMcpStop(codeName, reason) {
18182
- const prev = state7.agents.find((a) => a.codeName === codeName);
18309
+ const prev = state8.agents.find((a) => a.codeName === codeName);
18183
18310
  if (!prev) return;
18184
18311
  const agentId = prev.agentId;
18185
18312
  if (restartInFlight.has(agentId)) return;
@@ -18209,7 +18336,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
18209
18336
  }
18210
18337
  try {
18211
18338
  const hostId = await getHostId();
18212
- const { collectDiagnostics } = await import("../persistent-session-PPBLGH2J.js");
18339
+ const { collectDiagnostics } = await import("../persistent-session-PEY2TMJI.js");
18213
18340
  await api.post("/host/heartbeat", {
18214
18341
  host_id: hostId,
18215
18342
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor, spawnOutcomeForDiagnostics, pidPressureFor)
@@ -18430,18 +18557,18 @@ function ensureRealtimeIntegrationContextStarted(agentStates) {
18430
18557
  );
18431
18558
  },
18432
18559
  onSubscriptionLost: (agentId, status) => {
18433
- const state8 = recordRealtimeRebindFailure(
18560
+ const state9 = recordRealtimeRebindFailure(
18434
18561
  realtimeRebindFailures,
18435
18562
  agentId,
18436
18563
  status,
18437
18564
  Date.now()
18438
18565
  );
18439
- const waitMs = realtimeRebindBackoffMs(state8.attempts);
18440
- if (state8.attempts === 1 || state8.attempts > state8.loggedAtAttempt) {
18441
- state8.loggedAtAttempt = state8.attempts;
18442
- const stuckForSeconds = Math.floor((Date.now() - state8.since) / 1e3);
18566
+ const waitMs = realtimeRebindBackoffMs(state9.attempts);
18567
+ if (state9.attempts === 1 || state9.attempts > state9.loggedAtAttempt) {
18568
+ state9.loggedAtAttempt = state9.attempts;
18569
+ const stuckForSeconds = Math.floor((Date.now() - state9.since) / 1e3);
18443
18570
  log(
18444
- `[realtime] Token rotation subscription lost for agent ${agentId} (${status}) \u2014 attempt ${state8.attempts}, stuck ${stuckForSeconds}s, next rebind in ${Math.round(waitMs / 1e3)}s (ENG-9265)`
18571
+ `[realtime] Token rotation subscription lost for agent ${agentId} (${status}) \u2014 attempt ${state9.attempts}, stuck ${stuckForSeconds}s, next rebind in ${Math.round(waitMs / 1e3)}s (ENG-9265)`
18445
18572
  );
18446
18573
  }
18447
18574
  if (waitMs === 0) subscribedIntegrationContextAgentIds = /* @__PURE__ */ new Set();
@@ -18657,10 +18784,10 @@ function getKanbanNudgeState(codeName) {
18657
18784
  function loadKanbanNudgeStateFromDisk() {
18658
18785
  loadKanbanNudgeState(kanbanNudgeStateByCode, channelHashCacheDir());
18659
18786
  }
18660
- function setKanbanNudgeState(codeName, state8) {
18787
+ function setKanbanNudgeState(codeName, state9) {
18661
18788
  const key = kanbanNudgeStateKey(codeName);
18662
18789
  if (key !== codeName) kanbanNudgeStateByCode.delete(codeName);
18663
- kanbanNudgeStateByCode.set(key, state8);
18790
+ kanbanNudgeStateByCode.set(key, state9);
18664
18791
  saveKanbanNudgeState(kanbanNudgeStateByCode, channelHashCacheDir());
18665
18792
  }
18666
18793
  function clearKanbanNudgeState(codeName) {
@@ -18841,7 +18968,7 @@ async function processClaudePairSessions(agents) {
18841
18968
  killPairSession,
18842
18969
  pairTmuxSession,
18843
18970
  finalizeClaudePairOnboarding
18844
- } = await import("../claude-pair-runtime-Q5OIAZWC.js");
18971
+ } = await import("../claude-pair-runtime-MRA4KSDR.js");
18845
18972
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
18846
18973
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
18847
18974
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -19479,7 +19606,7 @@ async function driveArtifactStreaming() {
19479
19606
  }
19480
19607
  async function driveArtifactStreamingInner() {
19481
19608
  const liveIds = /* @__PURE__ */ new Set();
19482
- for (const agent of state7.agents) {
19609
+ for (const agent of state8.agents) {
19483
19610
  if (!agent.agentId || !agent.codeName || agent.status !== "active") continue;
19484
19611
  liveIds.add(agent.agentId);
19485
19612
  let scanner = artifactScanners.get(agent.agentId);
@@ -19512,7 +19639,7 @@ async function postLivenessHeartbeat() {
19512
19639
  await api.post("/host/heartbeat", {
19513
19640
  host_id: hostId,
19514
19641
  agt_version: agtCliVersion,
19515
- last_poll_at: state7.lastPollAt ?? void 0,
19642
+ last_poll_at: state8.lastPollAt ?? void 0,
19516
19643
  // The delay actually in force, so the monitor compares against reality
19517
19644
  // rather than a constant — a manager riding out an API outage under the
19518
19645
  // ENG-5041 backoff must not be paged as stopped.
@@ -19689,8 +19816,8 @@ function startManager(opts) {
19689
19816
  const raw = readFileSync29(stateFile, "utf-8");
19690
19817
  const parsed = JSON.parse(raw);
19691
19818
  if (Array.isArray(parsed.agents)) {
19692
- state7.agents = parsed.agents;
19693
- log(`[startup] rehydrated ${state7.agents.length} agent state(s) from ${stateFile}`);
19819
+ state8.agents = parsed.agents;
19820
+ log(`[startup] rehydrated ${state8.agents.length} agent state(s) from ${stateFile}`);
19694
19821
  }
19695
19822
  if (parsed.circuitBreakerTrips && typeof parsed.circuitBreakerTrips === "object") {
19696
19823
  restartBreaker.hydrate(parsed.circuitBreakerTrips);
@@ -19703,9 +19830,9 @@ function startManager(opts) {
19703
19830
  if (n > 0) log(`[startup] rehydrated ${n} auto-resume marker(s) (ENG-6088)`);
19704
19831
  }
19705
19832
  if (typeof parsed.lastUpdateRequestProcessedAt === "string" || parsed.lastUpdateRequestProcessedAt === null) {
19706
- state7.lastUpdateRequestProcessedAt = parsed.lastUpdateRequestProcessedAt;
19707
- if (state7.lastUpdateRequestProcessedAt) {
19708
- log(`[startup] rehydrated update-request ack at ${state7.lastUpdateRequestProcessedAt} (ENG-6692)`);
19833
+ state8.lastUpdateRequestProcessedAt = parsed.lastUpdateRequestProcessedAt;
19834
+ if (state8.lastUpdateRequestProcessedAt) {
19835
+ log(`[startup] rehydrated update-request ack at ${state8.lastUpdateRequestProcessedAt} (ENG-6692)`);
19709
19836
  }
19710
19837
  }
19711
19838
  }
@@ -19725,7 +19852,7 @@ function startManager(opts) {
19725
19852
  }
19726
19853
  try {
19727
19854
  refreshSlackRestartContextHints(
19728
- state7.agents.map((a) => a.codeName),
19855
+ state8.agents.map((a) => a.codeName),
19729
19856
  { log }
19730
19857
  );
19731
19858
  } catch (err) {