agentradar-cli 0.3.15 → 0.3.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.
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
2
3
  import { createRequire } from "node:module";
3
4
  import { homedir } from "node:os";
5
+ import { resolve } from "node:path";
4
6
  import { installVendorSkill } from "./skill-install.js";
5
7
  import { startChannel } from "./channel.js";
6
8
  import { runRestartSelftest, startVendorRunner } from "./runner.js";
@@ -19,6 +21,11 @@ export const runArgs = (raw) => raw[0] !== "run" ? raw
19
21
  : raw[1] === "join" ? raw.slice(1)
20
22
  : /^https?:\/\//.test(raw[1] ?? "") ? ["join", ...raw.slice(1)]
21
23
  : ["call", ...raw.slice(1)];
24
+ // The join link carries the secret that claims the agent's key, and ps shows argv to every user on the machine:
25
+ // `--link-file <path>` or `-` (stdin) keeps it off. `again` is how the CLI's own "run it again" lines name it.
26
+ export const joinLink = (urls, linkFile, stdin = () => readFileSync(0, "utf8")) => linkFile ? { link: readFileSync(linkFile, "utf8").trim(), again: `--link-file ${resolve(linkFile)}` }
27
+ : urls[0] === "-" ? { link: stdin().trim(), again: "-" }
28
+ : { link: urls[0], again: undefined };
22
29
  const USAGE = [
23
30
  "Usage: agentradar <noun> [<sub-noun>] <verb> [--<flag> <value> | --<flag>-file <path> ...] [--dry-run] [--json] [--runner <id>]",
24
31
  " Every agent command comes from the server. agentradar --help lists the groups (as $AR_CLI_RUNNER_ID),",
@@ -30,7 +37,7 @@ const USAGE = [
30
37
  " The runner is $AR_CLI_RUNNER_ID, or --runner <id>. --dry-run prints the exact call and sends nothing.",
31
38
  " Exit codes: 0 done; 1 refused or unreachable (the reason is on stderr); 2 the command was wrong.",
32
39
  "Local commands:",
33
- " agentradar join <join-link> [--name <n>] [--model <m>] [--runtime claude|codex|other] [--trust] [--attach-tmux <pane> | --attach-current] [--session <id>] [--no-service | --service]",
40
+ " agentradar join <join-link> | --link-file <path> | - (link on stdin) [--name <n>] [--model <m>] [--runtime claude|codex|other] [--trust] [--attach-tmux <pane> | --attach-current] [--session <id>] [--no-service | --service]",
34
41
  " agentradar join cancel <join-link|request-id>",
35
42
  " agentradar setup [--trust] [--harness claude|codex]",
36
43
  " agentradar leave <runner-id>",
@@ -131,13 +138,13 @@ async function main() {
131
138
  const named = {};
132
139
  const urls = [];
133
140
  for (let i = 1; i < args.length; i++) {
134
- if (["--name", "--model", "--attach-tmux", "--session", "--runtime"].includes(args[i]))
141
+ if (["--name", "--model", "--attach-tmux", "--session", "--runtime", "--link-file"].includes(args[i]))
135
142
  named[args[i].slice(2)] = args[++i] ?? "-";
136
143
  else if (!["--trust", "--attach-current", "--allow-bypass", "--revoke-bypass", "--feeder", "--service", "--no-service"].includes(args[i]))
137
144
  urls.push(args[i]);
138
145
  }
139
- if (urls.length !== 1 || [urls[0], ...Object.values(named)].some((value) => value.startsWith("-")) || (named["attach-tmux"] && args.includes("--attach-current")) || (args.includes("--service") && args.includes("--no-service"))) {
140
- console.error("Usage: agentradar join <join-link> [--name <your name>] [--model <your model id>] [--runtime <claude|codex|other>] [--trust] [--attach-tmux <session[:window.pane]> | --attach-current (Codex and other CLIs)] [--session <claude session id>] [--revoke-bypass] [--no-service | --service]");
146
+ if (urls.length !== (named["link-file"] ? 0 : 1) || [...urls.filter((url) => url !== "-"), ...Object.values(named)].some((value) => value.startsWith("-")) || (named["attach-tmux"] && args.includes("--attach-current")) || (args.includes("--service") && args.includes("--no-service"))) {
147
+ console.error("Usage: agentradar join <join-link> | --link-file <path> | - (the link on stdin) [--name <your name>] [--model <your model id>] [--runtime <claude|codex|other>] [--trust] [--attach-tmux <session[:window.pane]> | --attach-current (Codex and other CLIs)] [--session <claude session id>] [--revoke-bypass] [--no-service | --service]");
141
148
  process.exitCode = 1;
142
149
  return;
143
150
  }
@@ -148,7 +155,9 @@ async function main() {
148
155
  process.exitCode = 1;
149
156
  return;
150
157
  }
151
- process.exitCode = await joinOrganisation(urls[0], {
158
+ const { link, again } = joinLink(urls, named["link-file"]);
159
+ process.exitCode = await joinOrganisation(link, {
160
+ again,
152
161
  harness: runtime.harness, trust: args.includes("--trust"), agentName: named.name, model: named.model, session: named.session,
153
162
  attach: args.includes("--attach-current") ? "current" : named["attach-tmux"],
154
163
  revokeBypass: args.includes("--revoke-bypass"), feeder: args.includes("--feeder"), service: args.includes("--service"),
package/dist/setup.js CHANGED
@@ -904,7 +904,7 @@ export async function joinOrganisation(enrolmentUrl, deps = {}) {
904
904
  await saved?.();
905
905
  log(`Runner installed → ${runnerEnv}`);
906
906
  if (bypass)
907
- log(bypassOnNotice(enrolmentUrl));
907
+ log(bypassOnNotice(deps.again ?? enrolmentUrl));
908
908
  // Best effort: a failed first sync never stops the join; the service's feeder syncs them again.
909
909
  await syncJoinedSkills(runnerId, { home, fetch: fetchImpl, log }).catch((error) => {
910
910
  log(`Your AgentRadar skills are not installed yet (${String(error?.message ?? error).split("\n")[0]}); the runner installs them once it is running.`);
@@ -1069,7 +1069,7 @@ You can restart now or after the approval: until then the channel waits. You do
1069
1069
  const approvedBypass = now.bypassPermissions === true;
1070
1070
  const bypass = localBypass(approvedBypass, false);
1071
1071
  if (bypass)
1072
- log(bypassOnNotice(enrolmentUrl));
1072
+ log(bypassOnNotice(deps.again ?? enrolmentUrl));
1073
1073
  return connected(runnerId, projectPath, approvedBypass, bypass);
1074
1074
  }
1075
1075
  if (poll > 1 && (poll - 1) % 3 === 0)
@@ -1084,7 +1084,7 @@ You can restart now or after the approval: until then the channel waits. You do
1084
1084
  }
1085
1085
  for (let poll = 1;; poll++) {
1086
1086
  if (poll > (deps.polls ?? Infinity)) {
1087
- log(`Still waiting for approval. Run this same command again: agentradar run ${enrolmentUrl}`);
1087
+ log(`Still waiting for approval. Run this same command again: agentradar run ${deps.again ? `join ${deps.again}` : enrolmentUrl}`);
1088
1088
  return 0;
1089
1089
  }
1090
1090
  let response;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentradar-cli",
3
- "version": "0.3.15",
3
+ "version": "0.3.16",
4
4
  "engines": {
5
5
  "node": ">=20"
6
6
  },