agentradar-cli 0.1.2 → 0.1.4
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/README.md +4 -2
- package/dist/index.js +11 -1
- package/dist/runner.js +17 -0
- package/dist/setup.js +57 -2
- package/dist/vendor-runner/feeder.mjs +603 -0
- package/dist/vendor-runner/pane-live.sh +27 -0
- package/dist/vendor-runner/session-frame.mjs +119 -0
- package/dist/vendor-runner/supervisor/supervise-agent.sh +362 -0
- package/dist/vendor-runner/terminal-bridge.mjs +467 -0
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -6,10 +6,12 @@ From the agent's project folder:
|
|
|
6
6
|
|
|
7
7
|
```sh
|
|
8
8
|
npx -y agentradar-cli setup
|
|
9
|
+
# Use the exact runner ID printed by setup:
|
|
10
|
+
npx -y agentradar-cli runner start <runner-id>
|
|
9
11
|
npx -y agentradar-cli skill install
|
|
10
12
|
```
|
|
11
13
|
|
|
12
|
-
The setup command prints a short approval code. Approve that code in the AgentRadar vendor portal; the CLI then receives the AgentRadar bearer in the polling response body and writes the MCP entry
|
|
14
|
+
The setup command prints a short approval code. Approve that code in the AgentRadar vendor portal; the CLI then receives the AgentRadar bearer in the polling response body and writes the project MCP entry plus the supported runner's private config under `~/.agentradar`, with secret-bearing files mode `0600`. It prints the paths and the exact runner start command. It never prints the bearer or puts it in a URL, command argument, or repository file. The supervisor stages credentials into private runtime files, scrubs its child environment, and gives Claude Code only the strict AgentRadar MCP config.
|
|
13
15
|
|
|
14
16
|
Claude Code asks you to trust the folder on first launch. `setup` does not pre-accept that for you, and the onboarding lines above deliberately do not: the `hasTrustDialogAccepted` flag trusts everything already in the directory — existing hooks, `.claude/settings.json`, skills — not just the MCP entry setup added. Dismiss the prompt yourself.
|
|
15
17
|
|
|
@@ -17,4 +19,4 @@ There is a `--trust` flag for unattended runners, where a launch prompt would ha
|
|
|
17
19
|
|
|
18
20
|
The skill command installs only the package-bundled `agentradar-vendor` markdown skill at `.claude/skills/agentradar-vendor/SKILL.md` in the current project. It does not fetch or require access to the private AgentRadar repository.
|
|
19
21
|
|
|
20
|
-
Claude authentication stays separate:
|
|
22
|
+
Claude authentication stays separate. Preferred: use interactive `/login` with the vendor's claude.ai account. A `CLAUDE_CODE_OAUTH_TOKEN` may be stored in the private runner env file when non-interactive Claude authentication is required; the supervisor stages it into a mode-`0600` runtime file before launch. `ANTHROPIC_API_KEY` is prohibited and the supervisor refuses to start when it is set.
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { installVendorSkill } from "./skill-install.js";
|
|
3
|
+
import { startVendorRunner } from "./runner.js";
|
|
3
4
|
import { setupVendorAgent } from "./setup.js";
|
|
4
5
|
async function main() {
|
|
5
6
|
const args = process.argv.slice(2);
|
|
@@ -11,11 +12,20 @@ async function main() {
|
|
|
11
12
|
await setupVendorAgent({ trust: true });
|
|
12
13
|
return;
|
|
13
14
|
}
|
|
15
|
+
if (args.length === 2 && args[0] === "runner" && args[1] === "start") {
|
|
16
|
+
console.error("Usage: agentradar runner start <runner-id>");
|
|
17
|
+
process.exitCode = 1;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (args.length === 3 && args[0] === "runner" && args[1] === "start") {
|
|
21
|
+
process.exitCode = await startVendorRunner(args[2]);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
14
24
|
if (args.length === 2 && args[0] === "skill" && args[1] === "install") {
|
|
15
25
|
await installVendorSkill();
|
|
16
26
|
return;
|
|
17
27
|
}
|
|
18
|
-
console.error("Usage: agentradar setup [--trust] | agentradar skill install");
|
|
28
|
+
console.error("Usage: agentradar setup [--trust] | agentradar runner start <runner-id> | agentradar skill install");
|
|
19
29
|
process.exitCode = 1;
|
|
20
30
|
}
|
|
21
31
|
main().catch((error) => {
|
package/dist/runner.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
export async function startVendorRunner(runnerId, home = homedir()) {
|
|
6
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/.test(runnerId)) {
|
|
7
|
+
throw new Error("Invalid runner ID");
|
|
8
|
+
}
|
|
9
|
+
const envPath = join(home, ".agentradar", "agents", `${runnerId}.env`);
|
|
10
|
+
const supervisor = join(dirname(fileURLToPath(import.meta.url)), "vendor-runner", "supervisor", "supervise-agent.sh");
|
|
11
|
+
return new Promise((resolve, reject) => {
|
|
12
|
+
const child = spawn("bash", [supervisor, envPath], { stdio: "inherit", env: process.env });
|
|
13
|
+
child.once("error", reject);
|
|
14
|
+
child.once("exit", (code, signal) => resolve(code ?? (signal ? 1 : 0)));
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=runner.js.map
|
package/dist/setup.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { lstat, readFile, realpath, rename,
|
|
1
|
+
import { chmod, lstat, mkdir, readFile, realpath, rename, writeFile } from "node:fs/promises";
|
|
2
2
|
import { basename, join, resolve } from "node:path";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import * as tls from "node:tls";
|
|
@@ -109,6 +109,58 @@ async function installProjectMcp(configPath, cwd, installation, trust) {
|
|
|
109
109
|
await chmod(configPath, 0o600);
|
|
110
110
|
return projectPath;
|
|
111
111
|
}
|
|
112
|
+
function shellValue(value) {
|
|
113
|
+
return `'${value.replaceAll("'", "'\\''")}'`;
|
|
114
|
+
}
|
|
115
|
+
async function writePrivateFile(path, contents) {
|
|
116
|
+
try {
|
|
117
|
+
if ((await lstat(path)).isSymbolicLink())
|
|
118
|
+
throw new Error(`Refusing to replace a symlinked ${path}`);
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
if (error.code !== "ENOENT")
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
const tempPath = `${path}.${process.pid}.tmp`;
|
|
125
|
+
await writeFile(tempPath, contents, { mode: 0o600 });
|
|
126
|
+
await rename(tempPath, path);
|
|
127
|
+
await chmod(path, 0o600);
|
|
128
|
+
}
|
|
129
|
+
async function installRunner(home, projectPath, approved) {
|
|
130
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/.test(approved.runnerId)) {
|
|
131
|
+
throw new Error("AgentRadar returned an invalid runner ID");
|
|
132
|
+
}
|
|
133
|
+
const endpoint = new URL(approved.installation.mcpEndpoint);
|
|
134
|
+
if (endpoint.protocol !== "https:" || !/^ar_[A-Za-z0-9_-]+$/.test(approved.installation.bearer)) {
|
|
135
|
+
throw new Error("AgentRadar returned an invalid setup payload");
|
|
136
|
+
}
|
|
137
|
+
const agentDir = join(home, ".agentradar", "agents");
|
|
138
|
+
const configDir = join(home, ".agentradar", "config", approved.runnerId);
|
|
139
|
+
await mkdir(agentDir, { recursive: true, mode: 0o700 });
|
|
140
|
+
await mkdir(configDir, { recursive: true, mode: 0o700 });
|
|
141
|
+
await chmod(agentDir, 0o700);
|
|
142
|
+
await chmod(configDir, 0o700);
|
|
143
|
+
const mcpConfig = join(configDir, "awp-only.json");
|
|
144
|
+
const envPath = join(agentDir, `${approved.runnerId}.env`);
|
|
145
|
+
await writePrivateFile(mcpConfig, `${JSON.stringify({
|
|
146
|
+
mcpServers: {
|
|
147
|
+
agentradar: {
|
|
148
|
+
type: "http",
|
|
149
|
+
url: endpoint.toString(),
|
|
150
|
+
headers: { Authorization: `Bearer ${approved.installation.bearer}` },
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
}, null, 2)}\n`);
|
|
154
|
+
await writePrivateFile(envPath, [
|
|
155
|
+
`AGENT_NAME=${shellValue(approved.runnerId)}`,
|
|
156
|
+
`AR_BASE=${shellValue(projectPath)}`,
|
|
157
|
+
`AWP_MCP_URL=${shellValue(endpoint.toString())}`,
|
|
158
|
+
`AWP_BEARER=${shellValue(approved.installation.bearer)}`,
|
|
159
|
+
`MCP_CONFIG=${shellValue(mcpConfig)}`,
|
|
160
|
+
"",
|
|
161
|
+
].join("\n"));
|
|
162
|
+
return envPath;
|
|
163
|
+
}
|
|
112
164
|
export async function setupVendorAgent(deps = {}) {
|
|
113
165
|
if (!deps.fetch && tls.getCACertificates && tls.setDefaultCACertificates) {
|
|
114
166
|
tls.setDefaultCACertificates([...tls.getCACertificates("default"), ...tls.getCACertificates("system")]);
|
|
@@ -144,13 +196,16 @@ export async function setupVendorAgent(deps = {}) {
|
|
|
144
196
|
const configPath = claudeConfigPath(home);
|
|
145
197
|
const trust = deps.trust === true;
|
|
146
198
|
const projectPath = await installProjectMcp(configPath, cwd, approved.installation, trust);
|
|
199
|
+
const runnerEnv = await installRunner(home, projectPath, approved);
|
|
147
200
|
// Print the path, not just "installed". D3 was a silent write to the wrong file under a
|
|
148
201
|
// relocated CLAUDE_CONFIG_DIR; naming the target turns that class of failure into a glance.
|
|
149
202
|
log(`AgentRadar MCP installed for this project → ${configPath}`);
|
|
150
203
|
log(trust
|
|
151
204
|
? `--trust: pre-accepted the trust dialog for ${projectPath}. Claude Code will run this folder's existing hooks and settings without asking.`
|
|
152
205
|
: `Claude Code will ask you to trust ${projectPath} on first launch — approve it there. Not pre-accepted, because that would trust everything already in the folder, not just this MCP. Re-run with --trust for unattended onboarding.`);
|
|
153
|
-
log(
|
|
206
|
+
log(`Runner installed → ${runnerEnv}`);
|
|
207
|
+
log(`Start it with: agentradar runner start ${approved.runnerId}`);
|
|
208
|
+
log("Claude Code will use your existing /login session. ANTHROPIC_API_KEY is prohibited; a securely stored CLAUDE_CODE_OAUTH_TOKEN is also supported.");
|
|
154
209
|
return;
|
|
155
210
|
}
|
|
156
211
|
throw new Error("AgentRadar setup code expired; run setup again");
|