aicomputer 0.1.7 → 0.1.8

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 (2) hide show
  1. package/dist/index.js +75 -40
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1537,7 +1537,7 @@ var CLAUDE_OAUTH_REDIRECT_URL = process.env.CLAUDE_OAUTH_REDIRECT_URL ?? "https:
1537
1537
  var CLAUDE_OAUTH_SCOPES = (process.env.CLAUDE_OAUTH_SCOPES ?? "user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload").split(/\s+/).filter(Boolean);
1538
1538
  var readyPollIntervalMs = 2e3;
1539
1539
  var readyPollTimeoutMs = 18e4;
1540
- var claudeAuthCommand = new Command4("claude-auth").alias("claude-login").description("Authenticate Claude Code on a computer").option("--machine <id-or-handle>", "Use a specific computer").option("--keep-helper", "Keep a temporary helper machine if one is created").option("--skip-cross-check", "Skip verification on a second shared machine").action(async (options) => {
1540
+ var claudeAuthCommand = new Command4("claude-auth").alias("claude-login").description("Authenticate Claude Code on a computer").option("--machine <id-or-handle>", "Use a specific computer").option("--keep-helper", "Keep a temporary helper machine if one is created").option("--skip-cross-check", "Skip verification on a second shared machine").option("--verbose", "Show step-by-step auth diagnostics").action(async (options) => {
1541
1541
  const todos = createTodoList();
1542
1542
  let target = null;
1543
1543
  let helperCreated = false;
@@ -1573,19 +1573,22 @@ var claudeAuthCommand = new Command4("claude-auth").alias("claude-login").descri
1573
1573
  sharedInstall ? `installed Claude login on shared home via ${target.handle}` : `installed Claude login on ${target.handle}`
1574
1574
  );
1575
1575
  activeTodoID = "verify-primary";
1576
- await verifyStoredAuth(sshTarget);
1577
- markTodo(
1576
+ const primaryVerification = await verifyStoredAuth(sshTarget);
1577
+ markVerificationTodo(
1578
1578
  todos,
1579
1579
  "verify-primary",
1580
- "done",
1580
+ primaryVerification,
1581
1581
  `${target.handle} fresh login shell sees Claude auth`
1582
1582
  );
1583
1583
  activeTodoID = "verify-shared";
1584
- const sharedCheck = await verifySecondaryMachine(
1584
+ const sharedCheck = primaryVerification.status === "verified" ? await verifySecondaryMachine(
1585
1585
  target.id,
1586
1586
  sharedInstall,
1587
1587
  Boolean(options.skipCrossCheck)
1588
- );
1588
+ ) : {
1589
+ status: "skipped",
1590
+ reason: "primary verification was inconclusive"
1591
+ };
1589
1592
  if (sharedCheck.status === "verified") {
1590
1593
  markTodo(
1591
1594
  todos,
@@ -1623,7 +1626,9 @@ var claudeAuthCommand = new Command4("claude-auth").alias("claude-login").descri
1623
1626
  } else {
1624
1627
  markTodo(todos, "cleanup", "skipped", "no helper created");
1625
1628
  }
1626
- printTodoList(todos);
1629
+ if (options.verbose) {
1630
+ printTodoList(todos);
1631
+ }
1627
1632
  }
1628
1633
  if (failureMessage) {
1629
1634
  console.error(chalk5.red(`
@@ -1631,7 +1636,9 @@ ${failureMessage}`));
1631
1636
  process.exit(1);
1632
1637
  }
1633
1638
  if (target) {
1634
- console.log(chalk5.green(`Claude is ready on ${chalk5.bold(target.handle)}.`));
1639
+ console.log(
1640
+ chalk5.green(`Claude login installed on ${chalk5.bold(target.handle)}.`)
1641
+ );
1635
1642
  console.log();
1636
1643
  }
1637
1644
  });
@@ -1654,6 +1661,13 @@ function markTodo(items, id, state, detail) {
1654
1661
  item.state = state;
1655
1662
  item.detail = detail;
1656
1663
  }
1664
+ function markVerificationTodo(items, id, result, successDetail) {
1665
+ if (result.status === "verified") {
1666
+ markTodo(items, id, "done", successDetail);
1667
+ return;
1668
+ }
1669
+ markTodo(items, id, "skipped", result.detail);
1670
+ }
1657
1671
  function printTodoList(items) {
1658
1672
  console.log();
1659
1673
  console.log(chalk5.dim("TODO"));
@@ -1889,7 +1903,7 @@ async function installClaudeAuth(target, oauth) {
1889
1903
  const spinner = ora3(`Installing Claude auth on ${chalk5.bold(target.handle)}...`).start();
1890
1904
  try {
1891
1905
  const installScript = buildInstallScript(oauth.refreshToken, oauth.scope);
1892
- const result = await runRemoteBash(target, ["-s"], installScript);
1906
+ const result = await runRemoteCommand(target, ["bash", "-s"], installScript);
1893
1907
  if (result.stdout.trim()) {
1894
1908
  spinner.succeed(`Installed Claude auth on ${chalk5.bold(target.handle)}`);
1895
1909
  return;
@@ -1922,32 +1936,53 @@ function buildInstallScript(refreshToken, scopes) {
1922
1936
  ].join("\n");
1923
1937
  }
1924
1938
  async function verifyStoredAuth(target) {
1925
- const command = freshShellCommand("claude auth status --json");
1926
- const result = await runRemoteBash(target, ["-lc", command]);
1927
- const payload = parseStatusOutput(result.stdout);
1928
- if (!payload.loggedIn) {
1929
- throw new Error(`Claude auth is not visible on ${target.handle}`);
1939
+ try {
1940
+ const result = await runRemoteCommand(target, [
1941
+ "bash",
1942
+ "--noprofile",
1943
+ "--norc",
1944
+ "-lc",
1945
+ "claude auth status --json 2>/dev/null || claude auth status"
1946
+ ]);
1947
+ const payload = parseStatusOutput(result.stdout, result.stderr);
1948
+ if (payload.loggedIn) {
1949
+ return { status: "verified", detail: "verified" };
1950
+ }
1951
+ return {
1952
+ status: "failed",
1953
+ detail: payload.detail ? `verification failed: ${payload.detail}` : "verification failed"
1954
+ };
1955
+ } catch (error) {
1956
+ return {
1957
+ status: "inconclusive",
1958
+ detail: error instanceof Error ? error.message : "verification command did not complete cleanly"
1959
+ };
1930
1960
  }
1931
1961
  }
1932
- function freshShellCommand(inner) {
1933
- return [
1934
- "env -i",
1935
- 'HOME="$HOME"',
1936
- 'USER="${USER:-node}"',
1937
- 'SHELL="/bin/bash"',
1938
- 'PATH="$HOME/.local/bin:/usr/local/bin:/usr/bin:/bin"',
1939
- "bash -lc",
1940
- shellQuote(inner)
1941
- ].join(" ");
1942
- }
1943
- function parseStatusOutput(stdout) {
1944
- const start = stdout.indexOf("{");
1945
- const end = stdout.lastIndexOf("}");
1962
+ function parseStatusOutput(stdout, stderr) {
1963
+ const combined = [stdout, stderr].map((value) => value.trim()).filter(Boolean).join("\n");
1964
+ const start = combined.indexOf("{");
1965
+ const end = combined.lastIndexOf("}");
1946
1966
  if (start === -1 || end === -1 || end <= start) {
1947
- throw new Error("could not parse claude auth status output");
1967
+ const normalized = combined.toLowerCase();
1968
+ if (normalized.includes("logged in")) {
1969
+ return { loggedIn: true };
1970
+ }
1971
+ if (normalized.includes("not logged in") || normalized.includes("logged out")) {
1972
+ return { loggedIn: false, detail: firstStatusLine(combined) };
1973
+ }
1974
+ throw new Error(
1975
+ combined ? `could not verify Claude auth from status output: ${firstStatusLine(combined)}` : "could not verify Claude auth from empty status output"
1976
+ );
1948
1977
  }
1949
- const parsed = JSON.parse(stdout.slice(start, end + 1));
1950
- return { loggedIn: parsed.loggedIn === true };
1978
+ const parsed = JSON.parse(combined.slice(start, end + 1));
1979
+ return {
1980
+ loggedIn: parsed.loggedIn === true,
1981
+ detail: parsed.loggedIn === true ? void 0 : parsed.error
1982
+ };
1983
+ }
1984
+ function firstStatusLine(value) {
1985
+ return value.split(/\r?\n/).map((line) => line.trim()).find(Boolean) ?? "unknown output";
1951
1986
  }
1952
1987
  async function verifySecondaryMachine(primaryComputerID, sharedInstall, skip) {
1953
1988
  if (!sharedInstall) {
@@ -1968,10 +2003,13 @@ async function verifySecondaryMachine(primaryComputerID, sharedInstall, skip) {
1968
2003
  };
1969
2004
  }
1970
2005
  const sshTarget = await resolveSSHTarget(secondary);
1971
- await verifyStoredAuth(sshTarget);
2006
+ const verification = await verifyStoredAuth(sshTarget);
2007
+ if (verification.status !== "verified") {
2008
+ return { status: "skipped", reason: verification.detail };
2009
+ }
1972
2010
  return { status: "verified", handle: secondary.handle };
1973
2011
  }
1974
- async function runRemoteBash(target, bashArgs, script) {
2012
+ async function runRemoteCommand(target, remoteArgs, script) {
1975
2013
  const args = [
1976
2014
  "-T",
1977
2015
  "-i",
@@ -1979,8 +2017,7 @@ async function runRemoteBash(target, bashArgs, script) {
1979
2017
  "-p",
1980
2018
  String(target.port),
1981
2019
  `${target.user}@${target.host}`,
1982
- "bash",
1983
- ...bashArgs
2020
+ ...remoteArgs
1984
2021
  ];
1985
2022
  return new Promise((resolve, reject) => {
1986
2023
  const child = spawn2("ssh", args, {
@@ -2010,9 +2047,6 @@ async function runRemoteBash(target, bashArgs, script) {
2010
2047
  }
2011
2048
  });
2012
2049
  }
2013
- function shellQuote(value) {
2014
- return `'${value.replace(/'/g, `'\\''`)}'`;
2015
- }
2016
2050
  function base64url(buffer) {
2017
2051
  return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
2018
2052
  }
@@ -2582,7 +2616,8 @@ _computer() {
2582
2616
  _arguments \\
2583
2617
  '--machine[Use a specific computer]:computer:_computer_handles' \\
2584
2618
  '--keep-helper[Keep a temporary helper machine]' \\
2585
- '--skip-cross-check[Skip second-machine verification]'
2619
+ '--skip-cross-check[Skip second-machine verification]' \\
2620
+ '--verbose[Show step-by-step auth diagnostics]'
2586
2621
  ;;
2587
2622
  create)
2588
2623
  _arguments \\
@@ -2749,7 +2784,7 @@ var BASH_SCRIPT = `_computer() {
2749
2784
  COMPREPLY=($(compgen -W "--json" -- "$cur"))
2750
2785
  ;;
2751
2786
  claude-auth|claude-login)
2752
- COMPREPLY=($(compgen -W "--machine --keep-helper --skip-cross-check" -- "$cur"))
2787
+ COMPREPLY=($(compgen -W "--machine --keep-helper --skip-cross-check --verbose" -- "$cur"))
2753
2788
  ;;
2754
2789
  create)
2755
2790
  COMPREPLY=($(compgen -W "--name --tier --interactive --runtime-family --source-kind --image-family --image-ref --use-platform-default --primary-port --primary-path --healthcheck-type --healthcheck-value --ssh-enabled --ssh-disabled --vnc-enabled --vnc-disabled" -- "$cur"))
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aicomputer",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Computer CLI - manage your Agent Computer fleet from the terminal",
5
5
  "homepage": "https://agentcomputer.ai",
6
6
  "repository": {