@integrity-labs/agt-cli 0.28.540 → 0.28.542

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.
@@ -42,7 +42,7 @@ import {
42
42
  resolveConnectivityProbe,
43
43
  worseConnectivityOutcome,
44
44
  wrapScheduledTaskPrompt
45
- } from "./chunk-N6HD5UG4.js";
45
+ } from "./chunk-F63RM2RQ.js";
46
46
  import {
47
47
  parsePsRows
48
48
  } from "./chunk-XWVM4KPK.js";
@@ -5549,7 +5549,7 @@ function exchangeFailureKind(err) {
5549
5549
  }
5550
5550
 
5551
5551
  // src/lib/api-client.ts
5552
- var agtCliVersion = true ? "0.28.540" : "dev";
5552
+ var agtCliVersion = true ? "0.28.542" : "dev";
5553
5553
  var lastConfigHash = null;
5554
5554
  function setConfigHash(hash) {
5555
5555
  lastConfigHash = hash && hash.length > 0 ? hash : null;
@@ -8861,4 +8861,4 @@ export {
8861
8861
  managerInstallSystemUnitCommand,
8862
8862
  managerUninstallSystemUnitCommand
8863
8863
  };
8864
- //# sourceMappingURL=chunk-AGAGAM4W.js.map
8864
+ //# sourceMappingURL=chunk-GVYAIEFA.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-D47WOTHA.js");
103
+ const { resolveClaudeBinary } = await import("./persistent-session-7GPDXRPK.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-FHNWMTUH.js.map
376
+ //# sourceMappingURL=claude-pair-runtime-2UU67Q2T.js.map
@@ -53,7 +53,7 @@ import {
53
53
  safeWriteJsonAtomic,
54
54
  setConfigHash,
55
55
  tripClass
56
- } from "../chunk-AGAGAM4W.js";
56
+ } from "../chunk-GVYAIEFA.js";
57
57
  import {
58
58
  getProjectDir as getProjectDir2,
59
59
  getReadyTasks,
@@ -66,6 +66,7 @@ import {
66
66
  AnchorSessionClient,
67
67
  CLAUDE_MD_MAX_CHARS,
68
68
  CONVERSATION_FAILURE_CATEGORIES,
69
+ ChildProcessError,
69
70
  DEFAULT_FRAMEWORK,
70
71
  DEFAULT_NEIGHBOURHOOD_MS,
71
72
  FLAGS_SCHEMA_VERSION,
@@ -180,7 +181,7 @@ import {
180
181
  toOpencodeModel,
181
182
  transcriptActivityAgeSeconds,
182
183
  writeEgressAllowlist
183
- } from "../chunk-N6HD5UG4.js";
184
+ } from "../chunk-F63RM2RQ.js";
184
185
  import {
185
186
  reapOrphanChannelMcps
186
187
  } from "../chunk-XWVM4KPK.js";
@@ -4498,6 +4499,73 @@ async function applyClaudeAuthToEnv(childEnv, label) {
4498
4499
  }
4499
4500
  }
4500
4501
 
4502
+ // src/lib/claude-runtime-auth-probe.ts
4503
+ var RUNTIME_AUTH_SENTINEL = "AGTAUTHOK";
4504
+ var RUNTIME_AUTH_PROBE_PROMPT = `Reply with exactly this and nothing else: ${RUNTIME_AUTH_SENTINEL}`;
4505
+ var AUTH_REFUSAL_MARKERS = [
4506
+ "failed to authenticate",
4507
+ "oauth session expired",
4508
+ "could not be refreshed",
4509
+ "invalid api key",
4510
+ "authentication_error",
4511
+ "please run /login",
4512
+ "please run `claude /login`"
4513
+ ];
4514
+ function safeDetail(raw) {
4515
+ return raw.replace(/\bsk-[a-zA-Z0-9-]+/g, "sk-<redacted>").replace(/\b(Bearer|token|refreshToken|accessToken)\s*[:=]?\s*\S+/gi, "$1 <redacted>").replace(/\s+/g, " ").trim().slice(0, 200);
4516
+ }
4517
+ function classifyRuntimeAuthProbe(input) {
4518
+ const { exitCode, stdout, stderr, timedOut } = input;
4519
+ const combined = `${stdout}
4520
+ ${stderr}`;
4521
+ const haystack = combined.toLowerCase();
4522
+ if (timedOut) {
4523
+ return { verdict: "inconclusive", detail: "probe timed out" };
4524
+ }
4525
+ const marker = AUTH_REFUSAL_MARKERS.find((m) => haystack.includes(m));
4526
+ if (marker) {
4527
+ return {
4528
+ verdict: "not-authenticated",
4529
+ detail: safeDetail(combined) || `matched: ${marker}`
4530
+ };
4531
+ }
4532
+ if (exitCode === 0 && stdout.includes(RUNTIME_AUTH_SENTINEL)) {
4533
+ return { verdict: "authenticated", detail: "sentinel returned" };
4534
+ }
4535
+ if (exitCode === 0) {
4536
+ return { verdict: "inconclusive", detail: "exit 0 but sentinel absent" };
4537
+ }
4538
+ return {
4539
+ verdict: "inconclusive",
4540
+ detail: safeDetail(`exit ${exitCode ?? "null"}: ${combined}`)
4541
+ };
4542
+ }
4543
+ function foldRuntimeAuthVerdict(input) {
4544
+ const { verdict, previous, consecutiveFailures, requiredConsecutiveFailures } = input;
4545
+ if (verdict === "authenticated") {
4546
+ return { reported: true, consecutiveFailures: 0 };
4547
+ }
4548
+ if (verdict === "not-authenticated") {
4549
+ const next = consecutiveFailures + 1;
4550
+ return {
4551
+ reported: next >= requiredConsecutiveFailures ? false : previous,
4552
+ consecutiveFailures: next
4553
+ };
4554
+ }
4555
+ return { reported: previous, consecutiveFailures };
4556
+ }
4557
+ function heartbeatRuntimeAuthReport(probeVerdict) {
4558
+ return probeVerdict ?? void 0;
4559
+ }
4560
+ function heartbeatRuntimeAuthFields(probeVerdict) {
4561
+ const reported = heartbeatRuntimeAuthReport(probeVerdict);
4562
+ if (reported === void 0) return {};
4563
+ return {
4564
+ agent_runtime_authenticated: reported,
4565
+ agent_runtime_auth_observed: true
4566
+ };
4567
+ }
4568
+
4501
4569
  // src/lib/manager/kanban/parsers.ts
4502
4570
  import { existsSync as existsSync8, readFileSync as readFileSync15 } from "fs";
4503
4571
  import { join as join20 } from "path";
@@ -10369,7 +10437,7 @@ var agentRestartTimezoneInputs = /* @__PURE__ */ new Map();
10369
10437
  var lastVersionCheckAt = 0;
10370
10438
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
10371
10439
  var lastResponsivenessProbeAt = 0;
10372
- var agtCliVersion = true ? "0.28.540" : "dev";
10440
+ var agtCliVersion = true ? "0.28.542" : "dev";
10373
10441
  function resolveBrewPath(execFileSync2) {
10374
10442
  try {
10375
10443
  const out = execFileSync2("which", ["brew"], { timeout: 5e3 }).toString().trim();
@@ -11240,6 +11308,99 @@ function isOlderSemverTuple(local, remote) {
11240
11308
  }
11241
11309
  return false;
11242
11310
  }
11311
+ var RUNTIME_AUTH_PROBE_INTERVAL_MS = 15 * 60 * 1e3;
11312
+ var RUNTIME_AUTH_PROBE_TIMEOUT_MS = 6e4;
11313
+ var RUNTIME_AUTH_PROBE_FAILURES_TO_CONDEMN = 2;
11314
+ var lastRuntimeAuthProbeAt = 0;
11315
+ var runtimeAuthProbeInFlight = false;
11316
+ var runtimeAuthConsecutiveFailures = 0;
11317
+ var runtimeAuthProbeVerdict = null;
11318
+ function effectiveRuntimeAuthenticated() {
11319
+ return runtimeAuthProbeVerdict ?? agentRuntimeAuthenticated;
11320
+ }
11321
+ async function maybeProbeClaudeRuntimeAuth() {
11322
+ if (runtimeAuthProbeInFlight) return;
11323
+ if (Date.now() - lastRuntimeAuthProbeAt < RUNTIME_AUTH_PROBE_INTERVAL_MS) return;
11324
+ const { execFileSync: execFileSync2 } = await import("child_process");
11325
+ if (!claudeBinaryInstalled(execFileSync2)) return;
11326
+ runtimeAuthProbeInFlight = true;
11327
+ lastRuntimeAuthProbeAt = Date.now();
11328
+ try {
11329
+ const before = effectiveRuntimeAuthenticated();
11330
+ const result = await runClaudeRuntimeAuthProbe();
11331
+ const folded = foldRuntimeAuthVerdict({
11332
+ verdict: result.verdict,
11333
+ previous: before,
11334
+ consecutiveFailures: runtimeAuthConsecutiveFailures,
11335
+ requiredConsecutiveFailures: RUNTIME_AUTH_PROBE_FAILURES_TO_CONDEMN
11336
+ });
11337
+ runtimeAuthConsecutiveFailures = folded.consecutiveFailures;
11338
+ if (result.verdict === "authenticated" || folded.reported !== before) {
11339
+ runtimeAuthProbeVerdict = folded.reported;
11340
+ }
11341
+ if (folded.reported !== before) {
11342
+ log(
11343
+ `[runtime-auth-probe] reported authentication ${before} -> ${folded.reported} (verdict=${result.verdict}, consecutiveFailures=${folded.consecutiveFailures}): ${result.detail}`
11344
+ );
11345
+ } else if (result.verdict !== "authenticated") {
11346
+ log(
11347
+ `[runtime-auth-probe] verdict=${result.verdict} (consecutiveFailures=${runtimeAuthConsecutiveFailures}): ${result.detail}`
11348
+ );
11349
+ }
11350
+ } catch (err) {
11351
+ log(`[runtime-auth-probe] probe error (treated as inconclusive): ${err.message}`);
11352
+ } finally {
11353
+ runtimeAuthProbeInFlight = false;
11354
+ }
11355
+ }
11356
+ async function runClaudeRuntimeAuthProbe() {
11357
+ const childEnv = { ...process.env };
11358
+ await applyClaudeAuthToEnv(childEnv, "runtime-auth-probe");
11359
+ const emptyMcp = ensureEvalEmptyMcpConfig();
11360
+ const args = [
11361
+ "-p",
11362
+ RUNTIME_AUTH_PROBE_PROMPT,
11363
+ "--model",
11364
+ process.env["AGT_CONV_EVAL_CLAUDE_MODEL"]?.trim() || DEFAULT_CLAUDE_EVAL_MODEL,
11365
+ // feature-gate-allow: model tunable, not a gate
11366
+ "--output-format",
11367
+ "text",
11368
+ // Same isolation as conversation-eval: no project config, no MCP, no tools.
11369
+ // The probe must exercise AUTH and nothing else.
11370
+ "--mcp-config",
11371
+ emptyMcp,
11372
+ "--strict-mcp-config",
11373
+ "--permission-mode",
11374
+ "auto",
11375
+ "--allowedTools",
11376
+ ""
11377
+ ];
11378
+ try {
11379
+ const { stdout, stderr } = await execFilePromiseLong(resolveClaudeBinary(), args, {
11380
+ cwd: homedir12(),
11381
+ timeout: RUNTIME_AUTH_PROBE_TIMEOUT_MS,
11382
+ stdin: "ignore",
11383
+ env: childEnv,
11384
+ onSpawn: (pid) => registerClaudeSpawn({ pid, started_at: Date.now(), kind: "conv-eval" }),
11385
+ onExit: (pid) => unregisterClaudeSpawn(pid)
11386
+ });
11387
+ return classifyRuntimeAuthProbe({ exitCode: 0, stdout, stderr });
11388
+ } catch (err) {
11389
+ if (err instanceof ChildProcessError) {
11390
+ return classifyRuntimeAuthProbe({
11391
+ exitCode: err.code,
11392
+ stdout: err.stdout,
11393
+ stderr: err.stderr
11394
+ });
11395
+ }
11396
+ return classifyRuntimeAuthProbe({
11397
+ exitCode: null,
11398
+ stdout: "",
11399
+ stderr: err.message,
11400
+ timedOut: true
11401
+ });
11402
+ }
11403
+ }
11243
11404
  async function checkClaudeAuth() {
11244
11405
  try {
11245
11406
  const report = await detectClaudeAuth();
@@ -11580,7 +11741,7 @@ function flushRestartedAgentDiagnostics(hostId, codeNames) {
11580
11741
  if (codeNames.length === 0) return;
11581
11742
  void (async () => {
11582
11743
  try {
11583
- const { collectDiagnostics } = await import("../persistent-session-D47WOTHA.js");
11744
+ const { collectDiagnostics } = await import("../persistent-session-7GPDXRPK.js");
11584
11745
  await api.post("/host/heartbeat", {
11585
11746
  host_id: hostId,
11586
11747
  agent_diagnostics: collectDiagnostics(codeNames, quarantineEntriesFor, claudeMdSizeFor)
@@ -11666,6 +11827,7 @@ async function pollCycle() {
11666
11827
  checkAndUpdateCli().catch((err) => log(`[self-update] Check failed: ${err.message}`));
11667
11828
  }
11668
11829
  maybeUpgradeClaudeCode().catch((err) => log(`[claude-code-upgrade] Check failed: ${err.message}`));
11830
+ maybeProbeClaudeRuntimeAuth().catch((err) => log(`[runtime-auth-probe] Check failed: ${err.message}`));
11669
11831
  try {
11670
11832
  registeredAgentsCache.clear();
11671
11833
  const hostId = await getHostId();
@@ -11687,7 +11849,7 @@ async function pollCycle() {
11687
11849
  }
11688
11850
  try {
11689
11851
  const { detectHostSecurity } = await import("../host-security-6PDFG7F5.js");
11690
- const { collectDiagnostics } = await import("../persistent-session-D47WOTHA.js");
11852
+ const { collectDiagnostics } = await import("../persistent-session-7GPDXRPK.js");
11691
11853
  const diagCodeNames = [...agentState.persistentSessionAgents];
11692
11854
  const agentDiagnostics = diagCodeNames.length > 0 ? collectDiagnostics(diagCodeNames, quarantineEntriesFor, claudeMdSizeFor) : void 0;
11693
11855
  let tailscaleHostname;
@@ -11733,7 +11895,14 @@ async function pollCycle() {
11733
11895
  framework_version: cachedFrameworkVersion ?? void 0,
11734
11896
  agt_version: agtCliVersion,
11735
11897
  host_security: detectHostSecurity() ?? void 0,
11736
- agent_runtime_authenticated: agentRuntimeAuthenticated,
11898
+ // ENG-8623: the probe's verdict, or the field is OMITTED. The column is
11899
+ // named for a runtime observation and the API now stamps a freshness
11900
+ // timestamp beside it, so a file-derived value here would manufacture an
11901
+ // observation nobody made. Spread as ONE unit: the boolean and its
11902
+ // provenance marker must never diverge, so they are produced together
11903
+ // rather than as two fields a future edit could separate. See
11904
+ // `heartbeatRuntimeAuthFields`.
11905
+ ...heartbeatRuntimeAuthFields(runtimeAuthProbeVerdict),
11737
11906
  agent_diagnostics: agentDiagnostics,
11738
11907
  hostname: tailscaleHostname,
11739
11908
  os_username: osUsername,
@@ -11803,7 +11972,7 @@ async function pollCycle() {
11803
11972
  collectPanelessActivityProbes,
11804
11973
  getResponsivenessIntervalMs,
11805
11974
  occupancyQualificationClassifications
11806
- } = await import("../responsiveness-probe-HZUQTMSG.js");
11975
+ } = await import("../responsiveness-probe-P52CE6K7.js");
11807
11976
  const probeIntervalMs = getResponsivenessIntervalMs();
11808
11977
  if (now - lastResponsivenessProbeAt > probeIntervalMs) {
11809
11978
  const probeCodeNames = [...agentState.persistentSessionAgents];
@@ -11894,7 +12063,7 @@ async function pollCycle() {
11894
12063
  collectResponsivenessProbes,
11895
12064
  livePendingInboundOldestAgeSeconds,
11896
12065
  parkPendingInbound
11897
- } = await import("../responsiveness-probe-HZUQTMSG.js");
12066
+ } = await import("../responsiveness-probe-P52CE6K7.js");
11898
12067
  const { getProjectDir: wedgeProjectDir } = await import("../scheduler-engine-NDP36U7O.js");
11899
12068
  const wedgeNow = /* @__PURE__ */ new Date();
11900
12069
  const liveAgents = agentState.persistentSessionAgents;
@@ -15424,7 +15593,7 @@ async function handleRestartDoorbell(agentId, requestedAt, restartReason) {
15424
15593
  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}`));
15425
15594
  void (async () => {
15426
15595
  try {
15427
- const { collectDiagnostics } = await import("../persistent-session-D47WOTHA.js");
15596
+ const { collectDiagnostics } = await import("../persistent-session-7GPDXRPK.js");
15428
15597
  await api.post("/host/heartbeat", {
15429
15598
  host_id: hostId,
15430
15599
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor)
@@ -15474,7 +15643,7 @@ async function respawnAgentAfterMcpStop(codeName, reason) {
15474
15643
  }
15475
15644
  try {
15476
15645
  const hostId = await getHostId();
15477
- const { collectDiagnostics } = await import("../persistent-session-D47WOTHA.js");
15646
+ const { collectDiagnostics } = await import("../persistent-session-7GPDXRPK.js");
15478
15647
  await api.post("/host/heartbeat", {
15479
15648
  host_id: hostId,
15480
15649
  agent_diagnostics: collectDiagnostics([codeName], quarantineEntriesFor, claudeMdSizeFor)
@@ -15998,7 +16167,7 @@ async function processClaudePairSessions(agents) {
15998
16167
  killPairSession,
15999
16168
  pairTmuxSession,
16000
16169
  finalizeClaudePairOnboarding
16001
- } = await import("../claude-pair-runtime-FHNWMTUH.js");
16170
+ } = await import("../claude-pair-runtime-2UU67Q2T.js");
16002
16171
  for (const pairId of pendingResp.cancelled_pair_ids ?? []) {
16003
16172
  log(`[claude-pair] sweeping orphan tmux session for pair ${pairId.slice(0, 8)}`);
16004
16173
  const killed = await killPairSession(pairTmuxSession(pairId));
@@ -16942,6 +17111,7 @@ export {
16942
17111
  isPrereleaseVersion,
16943
17112
  markAgentForFreshMemorySync,
16944
17113
  maybeInjectKanbanCheck,
17114
+ maybeProbeClaudeRuntimeAuth,
16945
17115
  maybeUpgradeClaudeCode,
16946
17116
  refreshSkillsIndexInClaudeMd,
16947
17117
  reorderRestartedFirst,