@integrity-labs/agt-cli 0.10.14 → 0.10.16

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.
@@ -10,7 +10,7 @@ import {
10
10
  provisionStopHook,
11
11
  requireHost,
12
12
  resolveChannels
13
- } from "../chunk-KZ7Y55HJ.js";
13
+ } from "../chunk-XTETZ2D5.js";
14
14
  import {
15
15
  findTaskByTemplate,
16
16
  getProjectDir,
@@ -340,7 +340,7 @@ var GatewayClientPool = class extends EventEmitter {
340
340
  };
341
341
 
342
342
  // src/lib/claude-auth-detect.ts
343
- import { readFile } from "fs/promises";
343
+ import { readFile, readdir } from "fs/promises";
344
344
  import { homedir, platform } from "os";
345
345
  import { join } from "path";
346
346
  import { execFile } from "child_process";
@@ -364,6 +364,18 @@ async function readOauthCredentials() {
364
364
  join(homedir(), ".claude", ".credentials.json"),
365
365
  join(homedir(), ".claude", "credentials.json")
366
366
  ];
367
+ const isLinuxRoot = platform() === "linux" && typeof process.getuid === "function" && process.getuid() === 0;
368
+ if (isLinuxRoot) {
369
+ try {
370
+ const entries = await readdir("/home", { withFileTypes: true });
371
+ for (const entry of entries) {
372
+ if (!entry.isDirectory()) continue;
373
+ candidates.push(join("/home", entry.name, ".claude", ".credentials.json"));
374
+ candidates.push(join("/home", entry.name, ".claude", "credentials.json"));
375
+ }
376
+ } catch {
377
+ }
378
+ }
367
379
  for (const path of candidates) {
368
380
  const parsed = await readJsonSilently(path);
369
381
  if (parsed) {
@@ -781,48 +793,60 @@ function clearAgentCaches(agentId, codeName) {
781
793
  var cachedFrameworkVersion = null;
782
794
  var lastVersionCheckAt = 0;
783
795
  var VERSION_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
796
+ function resolveBrewPath(execFileSync) {
797
+ try {
798
+ const out = execFileSync("which", ["brew"], { timeout: 5e3 }).toString().trim();
799
+ if (out) return out;
800
+ } catch {
801
+ }
802
+ const fallback = "/home/linuxbrew/.linuxbrew/bin/brew";
803
+ if (existsSync(fallback)) return fallback;
804
+ return null;
805
+ }
784
806
  async function ensureFrameworkBinary(frameworkId) {
785
807
  if (frameworkId !== "claude-code") return;
786
808
  if (frameworkBinaryChecked.has(frameworkId)) return;
787
809
  frameworkBinaryChecked.add(frameworkId);
788
810
  const { execFileSync } = await import("child_process");
789
- let brewPath;
790
- try {
791
- brewPath = execFileSync("which", ["brew"], { timeout: 5e3 }).toString().trim();
792
- } catch {
793
- log("Homebrew not found \u2014 cannot auto-install/upgrade Claude Code. Install manually: https://claude.ai/download");
811
+ const brewPath = resolveBrewPath(execFileSync);
812
+ if (!brewPath) {
813
+ log("Homebrew not found (no `brew` on PATH, no /home/linuxbrew/.linuxbrew/bin/brew). Cannot auto-install Claude Code. Install manually: https://claude.ai/download");
794
814
  return;
795
815
  }
796
- let claudeExists = false;
797
- try {
798
- execFileSync("which", ["claude"], { timeout: 5e3 });
799
- claudeExists = true;
800
- } catch {
816
+ log(`Using brew at ${brewPath}`);
817
+ const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
818
+ const runBrew = (args, opts) => {
819
+ if (isRoot) {
820
+ const sudoArgs = ["-u", "ec2-user", "-H", brewPath, ...args];
821
+ return execFileSync("sudo", sudoArgs, { ...opts, stdio: "pipe" }).toString();
822
+ }
823
+ return execFileSync(brewPath, args, { ...opts, stdio: "pipe" }).toString();
824
+ };
825
+ let claudeExists = existsSync("/home/linuxbrew/.linuxbrew/bin/claude");
826
+ if (!claudeExists) {
827
+ try {
828
+ execFileSync("which", ["claude"], { timeout: 5e3 });
829
+ claudeExists = true;
830
+ } catch {
831
+ }
801
832
  }
802
833
  if (!claudeExists) {
803
- log("Claude Code binary not found \u2014 installing via Homebrew...");
834
+ log(`Claude Code binary not found \u2014 installing via Homebrew${isRoot ? " (as ec2-user via sudo)" : ""}...`);
804
835
  try {
805
- execFileSync(brewPath, ["install", "--cask", "claude-code"], {
806
- timeout: 12e4,
807
- stdio: "pipe"
808
- });
836
+ runBrew(["install", "--cask", "claude-code"], { timeout: 12e4 });
809
837
  } catch (err) {
810
838
  log(`Claude Code install failed: ${err.message}`);
811
839
  return;
812
840
  }
813
- try {
814
- execFileSync("which", ["claude"], { timeout: 5e3 });
841
+ if (existsSync("/home/linuxbrew/.linuxbrew/bin/claude")) {
815
842
  log("Claude Code installed successfully");
816
- } catch {
817
- log("Claude Code install completed but binary not found on PATH \u2014 you may need to restart your terminal");
843
+ } else {
844
+ log("Claude Code install completed but binary not found at expected path \u2014 check brew logs");
818
845
  }
819
846
  } else {
820
- log("Checking for Claude Code updates...");
847
+ log(`Checking for Claude Code updates${isRoot ? " (as ec2-user via sudo)" : ""}...`);
821
848
  try {
822
- const output = execFileSync(brewPath, ["upgrade", "--cask", "claude-code"], {
823
- timeout: 12e4,
824
- stdio: "pipe"
825
- }).toString();
849
+ const output = runBrew(["upgrade", "--cask", "claude-code"], { timeout: 12e4 });
826
850
  if (output.includes("already installed") || output.includes("up-to-date")) {
827
851
  log("Claude Code is already up to date");
828
852
  } else {
@@ -837,7 +861,7 @@ async function ensureFrameworkBinary(frameworkId) {
837
861
  }
838
862
  }
839
863
  }
840
- agentRuntimeAuthenticated = checkClaudeAuth(execFileSync);
864
+ agentRuntimeAuthenticated = await checkClaudeAuth();
841
865
  }
842
866
  var UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1e3;
843
867
  async function checkAndUpdateCli() {
@@ -889,28 +913,23 @@ async function checkAndUpdateCli() {
889
913
  } catch {
890
914
  }
891
915
  }
892
- function checkClaudeAuth(execFileSync) {
916
+ async function checkClaudeAuth() {
893
917
  try {
894
- const authOutput = execFileSync("claude", ["auth", "status"], { timeout: 1e4, stdio: "pipe" }).toString().trim();
895
- let loggedIn = null;
896
- try {
897
- const parsed = JSON.parse(authOutput);
898
- if (typeof parsed.loggedIn === "boolean") loggedIn = parsed.loggedIn;
899
- } catch {
900
- const lower = authOutput.toLowerCase();
901
- if (lower.includes("not logged in") || lower.includes("logged out")) loggedIn = false;
902
- else if (lower.includes("logged in")) loggedIn = true;
903
- }
904
- if (loggedIn === false) {
905
- log('\u26A0\uFE0F Claude Code is not authenticated. Run "claude" in a terminal to log in, then restart the manager.');
918
+ const report = await detectClaudeAuth();
919
+ if (!report) {
920
+ log("\u26A0\uFE0F Claude Code is not authenticated. Run `claude /login` (or set `ANTHROPIC_API_KEY`) on the host, then the manager will pick it up on the next cycle.");
906
921
  return false;
907
- } else if (loggedIn === null) {
908
- log('\u26A0\uFE0F Could not determine Claude Code auth state. Run "claude" in a terminal to verify login.');
922
+ }
923
+ if (report.status === "expired") {
924
+ log(`\u26A0\uFE0F Claude Code auth expired (${report.mode}). Re-run \`claude /login\` to refresh.`);
909
925
  return false;
910
926
  }
927
+ if (report.status === "expiring_soon") {
928
+ log(`[auth] Claude Code token expiring soon (expires_at=${report.expires_at}) \u2014 still valid, proceeding`);
929
+ }
911
930
  return true;
912
- } catch {
913
- log('\u26A0\uFE0F Could not check Claude Code auth status. Run "claude" in a terminal to ensure it is logged in.');
931
+ } catch (err) {
932
+ log(`\u26A0\uFE0F Claude Code auth probe failed: ${err.message}`);
914
933
  return false;
915
934
  }
916
935
  }
@@ -2792,8 +2811,7 @@ async function ensurePersistentSession(agent, tasks, boardItems, refreshData) {
2792
2811
  }
2793
2812
  devChannels.push("server:direct-chat");
2794
2813
  if (!agentRuntimeAuthenticated) {
2795
- const { execFileSync } = await import("child_process");
2796
- agentRuntimeAuthenticated = checkClaudeAuth(execFileSync);
2814
+ agentRuntimeAuthenticated = await checkClaudeAuth();
2797
2815
  if (!agentRuntimeAuthenticated) {
2798
2816
  log(`[persistent-session] Skipping '${codeName}' \u2014 Claude Code not authenticated`);
2799
2817
  return;
@@ -4213,8 +4231,27 @@ async function stopPolling() {
4213
4231
  function startManager(opts) {
4214
4232
  config = opts;
4215
4233
  deployMcpAssets();
4234
+ void ensureHostFrameworkBinaries();
4216
4235
  startPolling();
4217
4236
  }
4237
+ async function ensureHostFrameworkBinaries() {
4238
+ const apiKey = getApiKey();
4239
+ if (!apiKey) {
4240
+ log("[framework-install] AGT_API_KEY not set \u2014 skipping host framework binary check");
4241
+ return;
4242
+ }
4243
+ try {
4244
+ const exchange = await exchangeApiKey(apiKey);
4245
+ if (!exchange.framework) {
4246
+ log("[framework-install] host has no framework set \u2014 skipping");
4247
+ return;
4248
+ }
4249
+ log(`[framework-install] host framework = ${exchange.framework}`);
4250
+ await ensureFrameworkBinary(exchange.framework);
4251
+ } catch (err) {
4252
+ log(`[framework-install] failed: ${err.message}`);
4253
+ }
4254
+ }
4218
4255
  function deployMcpAssets() {
4219
4256
  const targetDir = join2(homedir2(), ".augmented", "_mcp");
4220
4257
  mkdirSync(targetDir, { recursive: true });