@integrity-labs/agt-cli 0.28.587 → 0.28.589

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-4BP5X62F.js";
43
+ } from "../chunk-THFO7CK4.js";
44
44
  import {
45
45
  AnchorSessionClient,
46
46
  CHANNEL_REGISTRY,
@@ -71,7 +71,7 @@ import {
71
71
  requiredMcpWildcard,
72
72
  resolveChannels,
73
73
  serializeManifestForSlackCli
74
- } from "../chunk-GMTRKIHI.js";
74
+ } from "../chunk-QDJEEGZB.js";
75
75
  import "../chunk-XWVM4KPK.js";
76
76
 
77
77
  // src/bin/agt.ts
@@ -4908,7 +4908,7 @@ import { execFileSync, execSync } from "child_process";
4908
4908
  import { existsSync as existsSync10, realpathSync as realpathSync2 } from "fs";
4909
4909
  import chalk18 from "chalk";
4910
4910
  import ora16 from "ora";
4911
- var cliVersion = true ? "0.28.587" : "dev";
4911
+ var cliVersion = true ? "0.28.589" : "dev";
4912
4912
  async function fetchLatestVersion() {
4913
4913
  const host2 = getHost();
4914
4914
  if (!host2) return null;
@@ -6088,7 +6088,7 @@ function handleError(err) {
6088
6088
  }
6089
6089
 
6090
6090
  // src/bin/agt.ts
6091
- var cliVersion2 = true ? "0.28.587" : "dev";
6091
+ var cliVersion2 = true ? "0.28.589" : "dev";
6092
6092
  var program = new Command();
6093
6093
  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");
6094
6094
  program.hook("preAction", async (thisCommand, actionCommand) => {
@@ -6448,13 +6448,30 @@ async function timedFetch2(fetchImpl, url, init) {
6448
6448
  clearTimeout(timer);
6449
6449
  }
6450
6450
  }
6451
- function statusForHttp(httpStatus) {
6451
+ function isRateLimited(res) {
6452
+ const retryAfter = res.headers.get("retry-after");
6453
+ if (retryAfter !== null && retryAfter.trim() !== "")
6454
+ return true;
6455
+ const remaining = res.headers.get("x-ratelimit-remaining");
6456
+ if (remaining === null || remaining.trim() === "")
6457
+ return false;
6458
+ return Number(remaining) === 0;
6459
+ }
6460
+ function statusForHttp(httpStatus, opts) {
6461
+ if (httpStatus === 429)
6462
+ return "transient_error";
6463
+ if (httpStatus === 403 && opts?.rateLimited)
6464
+ return "transient_error";
6452
6465
  if (httpStatus === 401 || httpStatus === 403)
6453
6466
  return "down";
6454
6467
  if (httpStatus >= 500)
6455
6468
  return "transient_error";
6456
6469
  return "down";
6457
6470
  }
6471
+ function rateLimitMessage(provider, httpStatus) {
6472
+ const subject = provider ? `${provider} rate limit` : "Rate limited by the provider";
6473
+ return `${subject} (${httpStatus}) \u2014 not a credential failure`;
6474
+ }
6458
6475
  function redactSecret(message, secret) {
6459
6476
  if (typeof secret !== "string" || secret.length < 4)
6460
6477
  return message;
@@ -6475,8 +6492,11 @@ async function probeLinear(creds, fetchImpl) {
6475
6492
  headers: { "Content-Type": "application/json", Authorization: String(key) },
6476
6493
  body: JSON.stringify({ query: "{ viewer { id name email } }" })
6477
6494
  });
6478
- if (!res.ok)
6479
- return { status: statusForHttp(res.status), message: `Linear API returned ${res.status}` };
6495
+ if (!res.ok) {
6496
+ const rateLimited = isRateLimited(res);
6497
+ const message = res.status === 429 || res.status === 403 && rateLimited ? rateLimitMessage("Linear", res.status) : `Linear API returned ${res.status}`;
6498
+ return { status: statusForHttp(res.status, { rateLimited }), message };
6499
+ }
6480
6500
  const body = await res.json();
6481
6501
  if (body.errors?.length)
6482
6502
  return { status: "down", message: body.errors[0]?.message ?? "Unknown Linear error" };
@@ -6495,8 +6515,9 @@ async function probeBearerJson(url, creds, fetchImpl, interpret, extraHeaders) {
6495
6515
  try {
6496
6516
  const res = await timedFetch2(fetchImpl, url, { headers: { Authorization: `Bearer ${token}`, ...extraHeaders } });
6497
6517
  if (!res.ok) {
6498
- const message = res.status === 401 ? "Token expired or revoked \u2014 reconnect required" : `API returned ${res.status}`;
6499
- return { status: statusForHttp(res.status), message };
6518
+ const rateLimited = isRateLimited(res);
6519
+ const message = res.status === 401 ? "Token expired or revoked \u2014 reconnect required" : res.status === 429 || res.status === 403 && rateLimited ? rateLimitMessage(null, res.status) : `API returned ${res.status}`;
6520
+ return { status: statusForHttp(res.status, { rateLimited }), message };
6500
6521
  }
6501
6522
  return interpret(await res.json());
6502
6523
  } catch (err) {
@@ -6514,8 +6535,9 @@ async function probeBuffer(creds, fetchImpl) {
6514
6535
  body: JSON.stringify({ query: "{ account { organizations { id name } } }" })
6515
6536
  });
6516
6537
  if (!res.ok) {
6517
- const message = res.status === 401 ? "Buffer API key expired or revoked \u2014 reconnect required" : `Buffer API returned ${res.status}`;
6518
- return { status: statusForHttp(res.status), message };
6538
+ const rateLimited = isRateLimited(res);
6539
+ const message = res.status === 401 ? "Buffer API key expired or revoked \u2014 reconnect required" : res.status === 429 || res.status === 403 && rateLimited ? rateLimitMessage("Buffer", res.status) : `Buffer API returned ${res.status}`;
6540
+ return { status: statusForHttp(res.status, { rateLimited }), message };
6519
6541
  }
6520
6542
  const body = await res.json();
6521
6543
  if (body.errors?.length)
@@ -6537,10 +6559,7 @@ async function probeVercel(creds, fetchImpl) {
6537
6559
  headers: { Authorization: `Bearer ${token}` }
6538
6560
  });
6539
6561
  if (!res.ok) {
6540
- if (res.status === 429) {
6541
- return { status: "transient_error", message: "Vercel rate limit (429) \u2014 not a credential failure" };
6542
- }
6543
- const message = res.status === 401 || res.status === 403 ? `Vercel rejected the token (${res.status}) \u2014 invalid or revoked API token` : `Vercel API returned ${res.status}`;
6562
+ const message = res.status === 429 ? rateLimitMessage("Vercel", res.status) : res.status === 401 || res.status === 403 ? `Vercel rejected the token (${res.status}) \u2014 invalid or revoked API token` : `Vercel API returned ${res.status}`;
6544
6563
  return { status: statusForHttp(res.status), message };
6545
6564
  }
6546
6565
  const body = await res.json();
@@ -6568,9 +6587,6 @@ async function probeHiggsfield(creds, fetchImpl) {
6568
6587
  headers: { Authorization: `Key ${token}` }
6569
6588
  });
6570
6589
  if (!res.ok) {
6571
- if (res.status === 429) {
6572
- return { status: "transient_error", message: "Higgsfield rate limit (429) \u2014 not a credential failure" };
6573
- }
6574
6590
  const body = await res.text().catch(() => "");
6575
6591
  if (res.status === 403 && /credit/i.test(body)) {
6576
6592
  return {
@@ -6578,7 +6594,7 @@ async function probeHiggsfield(creds, fetchImpl) {
6578
6594
  message: "Higgsfield authenticated, but the account is out of credits \u2014 generation will fail"
6579
6595
  };
6580
6596
  }
6581
- const message = res.status === 401 || res.status === 403 ? `Higgsfield rejected the key pair (${res.status}) \u2014 invalid or revoked API key` : `Higgsfield API returned ${res.status}`;
6597
+ const message = res.status === 429 ? rateLimitMessage("Higgsfield", res.status) : res.status === 401 || res.status === 403 ? `Higgsfield rejected the key pair (${res.status}) \u2014 invalid or revoked API key` : `Higgsfield API returned ${res.status}`;
6582
6598
  return { status: statusForHttp(res.status), message };
6583
6599
  }
6584
6600
  const motions = await res.json();
@@ -14708,6 +14724,32 @@ function buildDockerRunCommand(args) {
14708
14724
  const runCmd = [
14709
14725
  "exec docker run --rm -it",
14710
14726
  `--name agt-${codeName}`,
14727
+ // ENG-8825: run tini as PID 1 so ADOPTED ORPHANS GET REAPED. Without it the
14728
+ // container's PID 1 is the wrapper script, which execs `claude` - and a
14729
+ // process reparented to PID 1 stays a zombie until PID 1 calls wait(),
14730
+ // which claude does not and should not have to. Every subprocess that
14731
+ // outlives its immediate parent therefore leaks a PID for the life of the
14732
+ // container.
14733
+ //
14734
+ // Measured on a real agent (koda, 2026-08-14) after ~4h of ordinary work -
14735
+ // git, gh, vitest, tsc, shell pipelines:
14736
+ //
14737
+ // cgroup pids: 479/512 zombies: 403 live procs: 15
14738
+ //
14739
+ // ~100 zombies/hour, so `--pids-limit` two lines below is reached in about
14740
+ // five hours of active use. The limit is deliberate; the leak just eats it.
14741
+ //
14742
+ // What makes this worth a flag rather than a monitoring item is the DISGUISE.
14743
+ // Past the ceiling every spawn returns EAGAIN, and that surfaces inside
14744
+ // whatever unrelated command ran next: vitest reports "no tests" (reads as a
14745
+ // broken suite), tsc dies silently at exit 137 (reads as an OOM - it was
14746
+ // misdiagnosed as one three times before the PID count was checked), esbuild
14747
+ // fails mid-run. An agent hitting this concludes its own code is wrong.
14748
+ //
14749
+ // Docker's bundled tini. Deliberately NOT an in-process SIGCHLD handler in
14750
+ // the harness: reaping adopted orphans is init's job, and re-implementing it
14751
+ // per-application is how it gets forgotten again next time.
14752
+ "--init",
14711
14753
  `--memory ${memory}`,
14712
14754
  `--cpus ${cpus}`,
14713
14755
  `--pids-limit ${pids}`,
@@ -16042,4 +16084,4 @@ export {
16042
16084
  stopAllSessionsAndWait,
16043
16085
  getProjectDir
16044
16086
  };
16045
- //# sourceMappingURL=chunk-GMTRKIHI.js.map
16087
+ //# sourceMappingURL=chunk-QDJEEGZB.js.map