@agent-play/cli 3.0.1 → 3.1.0
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 +63 -2
- package/dist/.root +1 -0
- package/dist/cli.js +538 -188
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# @agent-play/cli
|
|
2
2
|
|
|
3
|
-
Command-line tool for **Agent Play**:
|
|
3
|
+
Command-line tool for **Agent Play**: create a **main developer node** (platform signup), add **agent nodes**, **validate** those identities against the server, and manage agent registrations. The server must use a **Redis**-backed agent repository (`REDIS_URL` on the server).
|
|
4
|
+
|
|
5
|
+
Authentication uses **`x-node-id`** and **`x-node-passw`** on every request **except** main-node creation, which sends hashed passphrase material in the JSON body to **`POST /api/nodes**.
|
|
4
6
|
|
|
5
7
|
## Documentation
|
|
6
8
|
|
|
7
9
|
- **[Repository](https://github.com/wilforlan/agent-play)**
|
|
8
|
-
- **[CLI guide](https://github.com/wilforlan/agent-play/blob/main/docs/cli.md)** —
|
|
10
|
+
- **[CLI guide](https://github.com/wilforlan/agent-play/blob/main/docs/cli.md)** — full **Node setup** and **Node validation** sections
|
|
9
11
|
- **[API reference](https://wilforlan.github.io/agent-play/)** — TypeDoc
|
|
10
12
|
|
|
11
13
|
## Install
|
|
@@ -15,3 +17,62 @@ npm install -g @agent-play/cli
|
|
|
15
17
|
```
|
|
16
18
|
|
|
17
19
|
Binary name: **`agent-play`**.
|
|
20
|
+
|
|
21
|
+
Default server URL: **`http://127.0.0.1:3000`**, or override with **`AGENT_PLAY_SERVER_URL`**.
|
|
22
|
+
|
|
23
|
+
Root key for derivation: **`--root-file`**, **`AGENT_PLAY_ROOT_FILE_PATH`**, or a **`.root`** file under **`~/.agent-play/`** or the current working directory (must match the server’s `.root`).
|
|
24
|
+
|
|
25
|
+
## Node setup
|
|
26
|
+
|
|
27
|
+
1. **Server:** Redis (`REDIS_URL`) and a deployed web UI/API the CLI can reach (`AGENT_PLAY_SERVER_URL`).
|
|
28
|
+
2. **Local `.root`:** Must match the server genesis root key (see resolution order above).
|
|
29
|
+
3. **`create-main-node`** (`bootstrap-node`): prompts for server URL, generates a passphrase, registers **`POST /api/nodes`**, writes **`~/.agent-play/credentials.json`** with **`serverUrl`**, **`nodeId`**, and the human passphrase.
|
|
30
|
+
4. **`create-agent-node`**: derives an agent node under your main node, **`POST /api/nodes/agent-node`**, appends to **`credentials.json` → `agentNodes`**.
|
|
31
|
+
5. **`inspect-node`**, **`list-agent-nodes`**, **`delete-*`**, **`clear-node-credentials`**: inspect or tear down registrations; see **`docs/cli.md`** for the full table.
|
|
32
|
+
|
|
33
|
+
> **@deprecated** **`POST /api/agents`** does not create agent **node** identity. Use **`POST /api/nodes/agent-node`**, then attach runtime data with **`world.addPlayer`**.
|
|
34
|
+
|
|
35
|
+
## Node validation
|
|
36
|
+
|
|
37
|
+
- **`validate-main-node`** — calls **`POST /api/nodes/validate`** for your main node id (uses **`credentials.json`** + **`.root`**).
|
|
38
|
+
- **`validate-agent-node --all`** — validates every id in **`credentials.json` → `agentNodes`** (includes **`mainNodeId`** in the validate body).
|
|
39
|
+
- **`validate-agent-node --agent-node-ids id1,id2`** — same for explicit ids.
|
|
40
|
+
|
|
41
|
+
For Redis-direct checks (ops/CI), use **`node-tools`** script **`scripts/validate-node-derivative.mjs`**; details in **`docs/cli.md`** and **`docs/notes/node-id-v1-migration.md`**.
|
|
42
|
+
|
|
43
|
+
## Commands
|
|
44
|
+
|
|
45
|
+
| Command | Aliases | What it does |
|
|
46
|
+
|--------|---------|----------------|
|
|
47
|
+
| **`create-main-node`** | `bootstrap-node` | Sign up a **main** node: **`POST /api/nodes`** (no node headers), save **`~/.agent-play/credentials.json`**. Optional **`--root-file`**. |
|
|
48
|
+
| **`inspect-node`** | — | **GET /api/nodes** — genesis id, main node, **agent node ids** (`create-agent-node`), and **runtime** agent rows (SDK metadata) if present. |
|
|
49
|
+
| **`create-agent-node`** | `create` | **POST /api/nodes/agent-node** — new agent node under your main node. |
|
|
50
|
+
| **`list-agent-nodes`** | `list` | **GET /api/agents** — lists registered agents. |
|
|
51
|
+
| **`delete-agent-node`** | `delete`, `remove` | **DELETE /api/agents** — optional **`[agent-id]`**; if omitted, prompts. |
|
|
52
|
+
| **`delete-main-node`** | — | **DELETE /api/nodes** — confirm by typing main node id; cascades. |
|
|
53
|
+
| **`validate-main-node`** | — | **POST /api/nodes/validate** for main node id. |
|
|
54
|
+
| **`validate-agent-node`** | — | **`--all`** or **`--agent-node-ids id1,id2,...`** — validate agent node ids. |
|
|
55
|
+
| **`clear-node-credentials`** | — | Removes **`~/.agent-play/credentials.json`**. |
|
|
56
|
+
|
|
57
|
+
## Genesis and main node
|
|
58
|
+
|
|
59
|
+
Every **main node id** is derived from passphrase material and the platform **root key** (the **genesis** identity). **`inspect-node`** and **`create-main-node`** output should agree with **`.root`** when both sides use the same key.
|
|
60
|
+
|
|
61
|
+
Node kinds: **`root` → `main` → `agent`**. Root has no passphrase; main and agent persist hashed material server-side.
|
|
62
|
+
|
|
63
|
+
## Usage examples
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npx agent-play create-main-node
|
|
67
|
+
npx agent-play validate-main-node
|
|
68
|
+
npx agent-play inspect-node
|
|
69
|
+
npx agent-play create-agent-node
|
|
70
|
+
npx agent-play validate-agent-node --all
|
|
71
|
+
npx agent-play list-agent-nodes
|
|
72
|
+
npx agent-play delete-agent-node
|
|
73
|
+
npx agent-play delete-agent-node <agent-uuid>
|
|
74
|
+
npx agent-play delete-main-node
|
|
75
|
+
npx agent-play clear-node-credentials
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
For SDK usage after bootstrap, use **`RemotePlayWorld`** and register players with **`mainNodeId`** and **`agentId`** from the CLI output.
|
package/dist/.root
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
87b6637b010478e48a83a8d445041ae4df5d607df7932153cdfee5c601e8e39e
|
package/dist/cli.js
CHANGED
|
@@ -1,134 +1,227 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import {
|
|
4
|
+
import { existsSync } from "fs";
|
|
5
|
+
import { mkdir, unlink, writeFile } from "fs/promises";
|
|
5
6
|
import { homedir } from "os";
|
|
6
|
-
import { join } from "path";
|
|
7
|
+
import { join, resolve } from "path";
|
|
7
8
|
import { createInterface } from "readline/promises";
|
|
8
9
|
import { stdin as input, stdout as output } from "process";
|
|
10
|
+
import {
|
|
11
|
+
createNodeCredentialFromPassw,
|
|
12
|
+
deriveNodeIdFromPassword,
|
|
13
|
+
generateNodePassw,
|
|
14
|
+
hashNodePassword,
|
|
15
|
+
loadAgentPlayCredentialsFileFromPath,
|
|
16
|
+
loadRootKey
|
|
17
|
+
} from "@agent-play/node-tools";
|
|
18
|
+
function nodeAuthHeaders(cred) {
|
|
19
|
+
return {
|
|
20
|
+
"x-node-id": cred.nodeId,
|
|
21
|
+
"x-node-passw": hashNodePassword(cred.passw)
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function parseAgentRows(agentsRaw) {
|
|
25
|
+
if (!Array.isArray(agentsRaw)) {
|
|
26
|
+
return [];
|
|
27
|
+
}
|
|
28
|
+
const agents = [];
|
|
29
|
+
for (const a of agentsRaw) {
|
|
30
|
+
if (typeof a !== "object" || a === null) continue;
|
|
31
|
+
const o = a;
|
|
32
|
+
if (typeof o.agentId === "string" && typeof o.name === "string") {
|
|
33
|
+
agents.push({ agentId: o.agentId, name: o.name });
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return agents;
|
|
37
|
+
}
|
|
9
38
|
function credentialsPath() {
|
|
10
39
|
return join(homedir(), ".agent-play", "credentials.json");
|
|
11
40
|
}
|
|
12
41
|
async function loadCredentials() {
|
|
13
|
-
|
|
14
|
-
const raw = await readFile(credentialsPath(), "utf8");
|
|
15
|
-
const json = JSON.parse(raw);
|
|
16
|
-
if (typeof json !== "object" || json === null) return null;
|
|
17
|
-
const o = json;
|
|
18
|
-
if (typeof o.serverUrl !== "string" || typeof o.token !== "string") {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
return { serverUrl: o.serverUrl.replace(/\/$/, ""), token: o.token };
|
|
22
|
-
} catch {
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
42
|
+
return loadAgentPlayCredentialsFileFromPath(credentialsPath());
|
|
25
43
|
}
|
|
26
44
|
async function saveCredentials(c) {
|
|
27
45
|
const dir = join(homedir(), ".agent-play");
|
|
28
46
|
await mkdir(dir, { recursive: true });
|
|
29
47
|
await writeFile(
|
|
30
48
|
credentialsPath(),
|
|
31
|
-
JSON.stringify(
|
|
49
|
+
JSON.stringify(c, null, 2),
|
|
32
50
|
"utf8"
|
|
33
51
|
);
|
|
34
52
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if (email.length === 0) {
|
|
45
|
-
rl.close();
|
|
46
|
-
console.error("Email is required.");
|
|
47
|
-
process.exitCode = 1;
|
|
48
|
-
return;
|
|
53
|
+
var BOOTSTRAP_ENVIRONMENTS = [
|
|
54
|
+
{ id: "local-server", url: "http://127.0.0.1:3000" },
|
|
55
|
+
{ id: "test-server", url: "https://test-agent-play.com" },
|
|
56
|
+
{ id: "main-server", url: "https://agent-play.com" }
|
|
57
|
+
];
|
|
58
|
+
function parseBootstrapEnvironmentAnswer(raw) {
|
|
59
|
+
const t = raw.trim().toLowerCase();
|
|
60
|
+
if (t === "" || t === "1") {
|
|
61
|
+
return BOOTSTRAP_ENVIRONMENTS[0].url;
|
|
49
62
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
headers: { "content-type": "application/json" },
|
|
53
|
-
body: JSON.stringify({ email })
|
|
54
|
-
});
|
|
55
|
-
const lookupText = await lookupRes.text();
|
|
56
|
-
if (!lookupRes.ok) {
|
|
57
|
-
rl.close();
|
|
58
|
-
console.error(`Lookup failed (${lookupRes.status}): ${lookupText}`);
|
|
59
|
-
process.exitCode = 1;
|
|
60
|
-
return;
|
|
63
|
+
if (t === "2") {
|
|
64
|
+
return BOOTSTRAP_ENVIRONMENTS[1].url;
|
|
61
65
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
lookupJson = JSON.parse(lookupText);
|
|
65
|
-
} catch {
|
|
66
|
-
rl.close();
|
|
67
|
-
console.error("Invalid JSON from server.");
|
|
68
|
-
process.exitCode = 1;
|
|
69
|
-
return;
|
|
66
|
+
if (t === "3") {
|
|
67
|
+
return BOOTSTRAP_ENVIRONMENTS[2].url;
|
|
70
68
|
}
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const password = (await rl.question("Password: ")).trim();
|
|
75
|
-
rl.close();
|
|
76
|
-
const loginRes = await fetch(`${serverUrl}/api/auth/login`, {
|
|
77
|
-
method: "POST",
|
|
78
|
-
headers: { "content-type": "application/json" },
|
|
79
|
-
body: JSON.stringify({ email, password })
|
|
80
|
-
});
|
|
81
|
-
const loginText = await loginRes.text();
|
|
82
|
-
if (!loginRes.ok) {
|
|
83
|
-
console.error(`Login failed (${loginRes.status}): ${loginText}`);
|
|
84
|
-
process.exitCode = 1;
|
|
85
|
-
return;
|
|
69
|
+
for (const e of BOOTSTRAP_ENVIRONMENTS) {
|
|
70
|
+
if (t === e.id) {
|
|
71
|
+
return e.url;
|
|
86
72
|
}
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
73
|
+
}
|
|
74
|
+
if (t === "local") {
|
|
75
|
+
return BOOTSTRAP_ENVIRONMENTS[0].url;
|
|
76
|
+
}
|
|
77
|
+
if (t === "test") {
|
|
78
|
+
return BOOTSTRAP_ENVIRONMENTS[1].url;
|
|
79
|
+
}
|
|
80
|
+
if (t === "main") {
|
|
81
|
+
return BOOTSTRAP_ENVIRONMENTS[2].url;
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
async function promptBootstrapEnvironment(rl) {
|
|
86
|
+
const lines = [
|
|
87
|
+
"Choose environment (sets server URL):",
|
|
88
|
+
` 1) ${BOOTSTRAP_ENVIRONMENTS[0].id} \u2192 ${BOOTSTRAP_ENVIRONMENTS[0].url}`,
|
|
89
|
+
` 2) ${BOOTSTRAP_ENVIRONMENTS[1].id} \u2192 ${BOOTSTRAP_ENVIRONMENTS[1].url}`,
|
|
90
|
+
` 3) ${BOOTSTRAP_ENVIRONMENTS[2].id} \u2192 ${BOOTSTRAP_ENVIRONMENTS[2].url}`,
|
|
91
|
+
"Enter 1\u20133, or local-server / test-server / main-server [1]: "
|
|
92
|
+
].join("\n");
|
|
93
|
+
for (; ; ) {
|
|
94
|
+
const answer = await rl.question(lines);
|
|
95
|
+
const url = parseBootstrapEnvironmentAnswer(answer);
|
|
96
|
+
if (url !== null) {
|
|
97
|
+
return url.replace(/\/$/, "");
|
|
92
98
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
console.log(
|
|
100
|
+
"Invalid choice. Enter 1, 2, or 3, or one of: local-server, test-server, main-server."
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function parseBootstrapNodeArgs(argv) {
|
|
105
|
+
const out = {};
|
|
106
|
+
for (let i = 0; i < argv.length; i++) {
|
|
107
|
+
const a = argv[i];
|
|
108
|
+
if (a === "--root-file" && typeof argv[i + 1] === "string") {
|
|
109
|
+
out.rootFilePath = argv[++i];
|
|
102
110
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
}
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
function parseValidateAgentNodeArgs(argv) {
|
|
115
|
+
let wantsAll = false;
|
|
116
|
+
let ids = [];
|
|
117
|
+
for (let i = 0; i < argv.length; i++) {
|
|
118
|
+
const a = argv[i];
|
|
119
|
+
if (a === "--all") {
|
|
120
|
+
wantsAll = true;
|
|
121
|
+
continue;
|
|
114
122
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
123
|
+
if (a === "--agent-node-ids" && typeof argv[i + 1] === "string") {
|
|
124
|
+
const raw = argv[++i].trim();
|
|
125
|
+
ids = raw.split(",").map((x) => x.trim()).filter((x) => x.length > 0);
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
if (wantsAll) {
|
|
131
|
+
return { mode: "all" };
|
|
132
|
+
}
|
|
133
|
+
if (ids.length > 0) {
|
|
134
|
+
return { mode: "ids", agentNodeIds: ids };
|
|
135
|
+
}
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
function resolveAgentPlayRootPath(options) {
|
|
139
|
+
if (typeof options.rootFilePath === "string" && options.rootFilePath.trim().length > 0) {
|
|
140
|
+
return resolve(options.rootFilePath.trim());
|
|
141
|
+
}
|
|
142
|
+
const fromEnv = process.env.AGENT_PLAY_ROOT_FILE_PATH;
|
|
143
|
+
if (typeof fromEnv === "string" && fromEnv.trim().length > 0) {
|
|
144
|
+
return resolve(fromEnv.trim());
|
|
145
|
+
}
|
|
146
|
+
const homeRoot = join(homedir(), ".agent-play", ".root");
|
|
147
|
+
if (existsSync(homeRoot)) {
|
|
148
|
+
return homeRoot;
|
|
149
|
+
}
|
|
150
|
+
const cwdRoot = resolve(process.cwd(), ".root");
|
|
151
|
+
if (existsSync(cwdRoot)) {
|
|
152
|
+
return cwdRoot;
|
|
153
|
+
}
|
|
154
|
+
throw new Error(
|
|
155
|
+
"Agent Play root key not found. Pass --root-file <path>, set AGENT_PLAY_ROOT_FILE_PATH, or place .root in ~/.agent-play/ or the project directory."
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
async function registerNodeOnServer(serverUrl, passw, expectedNodeId) {
|
|
159
|
+
const res = await fetch(`${serverUrl}/api/nodes`, {
|
|
160
|
+
method: "POST",
|
|
161
|
+
headers: { "content-type": "application/json" },
|
|
162
|
+
body: JSON.stringify({ kind: "main", passw })
|
|
163
|
+
});
|
|
164
|
+
const text = await res.text();
|
|
165
|
+
if (res.status === 409) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
if (!res.ok) {
|
|
169
|
+
let msg = text;
|
|
170
|
+
try {
|
|
171
|
+
const err = JSON.parse(text);
|
|
172
|
+
if (typeof err.error === "string") {
|
|
173
|
+
msg = err.error;
|
|
174
|
+
}
|
|
175
|
+
} catch {
|
|
120
176
|
}
|
|
121
|
-
|
|
177
|
+
throw new Error(
|
|
178
|
+
`Node registration failed (${String(res.status)}): ${msg}`
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
const json = JSON.parse(text);
|
|
182
|
+
if (typeof json.nodeId !== "string") {
|
|
183
|
+
throw new Error("Invalid response from server.");
|
|
184
|
+
}
|
|
185
|
+
if (json.nodeId !== expectedNodeId) {
|
|
186
|
+
console.log("json", json);
|
|
187
|
+
console.log("expectedNodeId", expectedNodeId);
|
|
188
|
+
throw new Error(
|
|
189
|
+
"Server node id does not match local derivation; check root file and server configuration."
|
|
190
|
+
);
|
|
122
191
|
}
|
|
123
|
-
await saveCredentials({ serverUrl, token });
|
|
124
|
-
console.log(`Signed in. Credentials saved to ${credentialsPath()}`);
|
|
125
192
|
}
|
|
126
|
-
async function
|
|
193
|
+
async function cmdBootstrapNode(argv) {
|
|
194
|
+
const opts = parseBootstrapNodeArgs(argv);
|
|
195
|
+
const rl = createInterface({ input, output });
|
|
196
|
+
const serverUrl = await promptBootstrapEnvironment(rl);
|
|
197
|
+
rl.close();
|
|
198
|
+
console.log(`Using server: ${serverUrl}`);
|
|
199
|
+
const rootPath = resolveAgentPlayRootPath(opts);
|
|
200
|
+
const rootKey = loadRootKey(rootPath);
|
|
201
|
+
const dir = join(homedir(), ".agent-play");
|
|
202
|
+
await mkdir(dir, { recursive: true });
|
|
203
|
+
const generatedPassw = generateNodePassw();
|
|
204
|
+
const hashedPassw = hashNodePassword(generatedPassw);
|
|
205
|
+
const credential = createNodeCredentialFromPassw({ passw: hashedPassw, rootKey });
|
|
206
|
+
await registerNodeOnServer(serverUrl, hashedPassw, credential.nodeId);
|
|
207
|
+
await saveCredentials({
|
|
208
|
+
serverUrl,
|
|
209
|
+
nodeId: credential.nodeId,
|
|
210
|
+
passw: generatedPassw
|
|
211
|
+
});
|
|
212
|
+
console.log(
|
|
213
|
+
`genesisNodeId (platform root key from .root; all main nodes derive under this): ${rootKey}`
|
|
214
|
+
);
|
|
215
|
+
console.log(`mainNodeId (your developer node): ${credential.nodeId}`);
|
|
216
|
+
console.log(`passw: ${generatedPassw}`);
|
|
217
|
+
console.log("Keep this material safe. Losing it means losing access.");
|
|
218
|
+
}
|
|
219
|
+
async function cmdClearNodeCredentials() {
|
|
127
220
|
try {
|
|
128
221
|
await unlink(credentialsPath());
|
|
129
|
-
console.log("
|
|
222
|
+
console.log("Credentials removed.");
|
|
130
223
|
} catch {
|
|
131
|
-
console.log("No saved
|
|
224
|
+
console.log("No saved credentials.");
|
|
132
225
|
}
|
|
133
226
|
}
|
|
134
227
|
function printAgentPlayIntegrationGuide() {
|
|
@@ -136,7 +229,7 @@ function printAgentPlayIntegrationGuide() {
|
|
|
136
229
|
console.log("How your agent appears on the play world");
|
|
137
230
|
console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
|
|
138
231
|
console.log(
|
|
139
|
-
" \u2022
|
|
232
|
+
" \u2022 Use ~/.agent-play/credentials.json + .root with RemotePlayWorld({ nodeCredentials })."
|
|
140
233
|
);
|
|
141
234
|
console.log(
|
|
142
235
|
" \u2022 LangChain: use langchainRegistration(agent) and pass agent.toolNames to addPlayer."
|
|
@@ -148,22 +241,38 @@ function printAgentPlayIntegrationGuide() {
|
|
|
148
241
|
" \u2022 Structures on the map are derived from those tool names \u2014 keep them aligned with your real tools."
|
|
149
242
|
);
|
|
150
243
|
console.log(
|
|
151
|
-
" \u2022 RemotePlayWorld({
|
|
244
|
+
" \u2022 RemotePlayWorld({ nodeCredentials: { rootKey, passw } }) and addAgent({ nodeId, ... })."
|
|
152
245
|
);
|
|
153
246
|
console.log("");
|
|
154
247
|
}
|
|
155
|
-
async function
|
|
248
|
+
async function cmdCreateAgentNode() {
|
|
156
249
|
const cred = await loadCredentials();
|
|
157
250
|
if (cred === null) {
|
|
158
|
-
console.error(
|
|
251
|
+
console.error(
|
|
252
|
+
"Run `agent-play create-main-node` (or `bootstrap-node`) first."
|
|
253
|
+
);
|
|
159
254
|
process.exitCode = 1;
|
|
160
255
|
return;
|
|
161
256
|
}
|
|
162
|
-
const
|
|
257
|
+
const rootKey = loadRootKey(resolveAgentPlayRootPath({}));
|
|
258
|
+
const agentPassw = generateNodePassw();
|
|
259
|
+
const hashedAgentPassw = hashNodePassword(agentPassw);
|
|
260
|
+
const agentNodeId = deriveNodeIdFromPassword({
|
|
261
|
+
password: hashedAgentPassw,
|
|
262
|
+
rootKey
|
|
263
|
+
});
|
|
264
|
+
const res = await fetch(`${cred.serverUrl}/api/nodes/agent-node`, {
|
|
163
265
|
method: "POST",
|
|
164
266
|
headers: {
|
|
165
|
-
|
|
166
|
-
|
|
267
|
+
"content-type": "application/json",
|
|
268
|
+
...nodeAuthHeaders(cred)
|
|
269
|
+
},
|
|
270
|
+
body: JSON.stringify({
|
|
271
|
+
kind: "agent",
|
|
272
|
+
parentNodeId: cred.nodeId,
|
|
273
|
+
agentNodeId,
|
|
274
|
+
agentNodePassw: hashedAgentPassw
|
|
275
|
+
})
|
|
167
276
|
});
|
|
168
277
|
const text = await res.text();
|
|
169
278
|
if (!res.ok) {
|
|
@@ -173,65 +282,55 @@ async function cmdCreateKey() {
|
|
|
173
282
|
if (typeof err.error === "string") msg = err.error;
|
|
174
283
|
} catch {
|
|
175
284
|
}
|
|
176
|
-
console.error(`
|
|
285
|
+
console.error(`Create failed (${res.status}): ${msg}`);
|
|
177
286
|
process.exitCode = 1;
|
|
178
287
|
return;
|
|
179
288
|
}
|
|
180
289
|
const json = JSON.parse(text);
|
|
181
|
-
if (typeof json.
|
|
290
|
+
if (typeof json.agentId !== "string") {
|
|
182
291
|
console.error("Invalid response from server.");
|
|
183
292
|
process.exitCode = 1;
|
|
184
293
|
return;
|
|
185
294
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
async function cmdViewKeys() {
|
|
191
|
-
const cred = await loadCredentials();
|
|
192
|
-
if (cred === null) {
|
|
193
|
-
console.error("Run `agent-play login` first.");
|
|
295
|
+
if (json.agentId !== agentNodeId) {
|
|
296
|
+
console.error(
|
|
297
|
+
"Server returned a different agent node id than the locally derived one."
|
|
298
|
+
);
|
|
194
299
|
process.exitCode = 1;
|
|
195
300
|
return;
|
|
196
301
|
}
|
|
197
|
-
const
|
|
198
|
-
|
|
302
|
+
const nextAgentNodes = [
|
|
303
|
+
...(cred.agentNodes ?? []).filter((n) => n.nodeId !== agentNodeId),
|
|
304
|
+
{
|
|
305
|
+
nodeId: agentNodeId,
|
|
306
|
+
passw: agentPassw,
|
|
307
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
308
|
+
}
|
|
309
|
+
];
|
|
310
|
+
await saveCredentials({
|
|
311
|
+
...cred,
|
|
312
|
+
agentNodes: nextAgentNodes
|
|
199
313
|
});
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
const when = typeof json.createdAt === "string" ? json.createdAt : "unknown time";
|
|
209
|
-
console.log(`Account API key: active (created ${when}).`);
|
|
210
|
-
console.log(
|
|
211
|
-
"The secret value cannot be shown again. Use the key you saved when you ran `agent-play create-key`."
|
|
212
|
-
);
|
|
213
|
-
} else {
|
|
214
|
-
console.log("No API key for this account.");
|
|
215
|
-
console.log("Run `agent-play create-key` to generate one (shown once).");
|
|
216
|
-
}
|
|
314
|
+
printAgentPlayIntegrationGuide();
|
|
315
|
+
console.log(`Created agent node id: ${json.agentId}`);
|
|
316
|
+
console.log(`Agent node passw: ${agentPassw}`);
|
|
317
|
+
console.log(
|
|
318
|
+
`Saved agent node credentials to ${credentialsPath()} (agentNodes).`
|
|
319
|
+
);
|
|
320
|
+
console.log("Keep this material safe. Losing it means losing access.");
|
|
321
|
+
console.log("");
|
|
217
322
|
}
|
|
218
|
-
async function
|
|
323
|
+
async function cmdInspectNode() {
|
|
219
324
|
const cred = await loadCredentials();
|
|
220
325
|
if (cred === null) {
|
|
221
|
-
console.error(
|
|
326
|
+
console.error(
|
|
327
|
+
"Run `agent-play create-main-node` (or `bootstrap-node`) first."
|
|
328
|
+
);
|
|
222
329
|
process.exitCode = 1;
|
|
223
330
|
return;
|
|
224
331
|
}
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
rl.close();
|
|
228
|
-
const res = await fetch(`${cred.serverUrl}/api/agents`, {
|
|
229
|
-
method: "POST",
|
|
230
|
-
headers: {
|
|
231
|
-
"content-type": "application/json",
|
|
232
|
-
authorization: `Bearer ${cred.token}`
|
|
233
|
-
},
|
|
234
|
-
body: JSON.stringify({ name })
|
|
332
|
+
const res = await fetch(`${cred.serverUrl}/api/nodes`, {
|
|
333
|
+
headers: nodeAuthHeaders(cred)
|
|
235
334
|
});
|
|
236
335
|
const text = await res.text();
|
|
237
336
|
if (!res.ok) {
|
|
@@ -241,29 +340,71 @@ async function cmdCreate() {
|
|
|
241
340
|
if (typeof err.error === "string") msg = err.error;
|
|
242
341
|
} catch {
|
|
243
342
|
}
|
|
244
|
-
console.error(`
|
|
343
|
+
console.error(`Inspect failed (${res.status}): ${msg}`);
|
|
245
344
|
process.exitCode = 1;
|
|
246
345
|
return;
|
|
247
346
|
}
|
|
248
347
|
const json = JSON.parse(text);
|
|
249
|
-
if (typeof json.
|
|
250
|
-
console.error("Invalid response
|
|
348
|
+
if (typeof json.genesisNodeId !== "string") {
|
|
349
|
+
console.error("Invalid inspect response.");
|
|
251
350
|
process.exitCode = 1;
|
|
252
351
|
return;
|
|
253
352
|
}
|
|
254
|
-
|
|
255
|
-
|
|
353
|
+
const main2 = json.mainNode;
|
|
354
|
+
if (typeof main2 !== "object" || main2 === null) {
|
|
355
|
+
console.error("Invalid inspect response.");
|
|
356
|
+
process.exitCode = 1;
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const mn = main2;
|
|
360
|
+
if (typeof mn.nodeId !== "string" || typeof mn.createdAt !== "string") {
|
|
361
|
+
console.error("Invalid inspect response.");
|
|
362
|
+
process.exitCode = 1;
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const agentNodeIdsFromMain = Array.isArray(mn.agentNodeIds) ? mn.agentNodeIds.filter((x) => typeof x === "string") : [];
|
|
366
|
+
const runtimeAgents = parseAgentRows(json.agentNodes);
|
|
367
|
+
console.log("Platform genesis node id (from server .root / root key):");
|
|
368
|
+
console.log(` ${json.genesisNodeId}`);
|
|
369
|
+
console.log("");
|
|
370
|
+
console.log("Your main developer node:");
|
|
371
|
+
console.log(` nodeId: ${mn.nodeId}`);
|
|
372
|
+
console.log(` createdAt: ${mn.createdAt}`);
|
|
373
|
+
console.log("");
|
|
374
|
+
console.log(
|
|
375
|
+
`Agent node identities (create-agent-node) (${String(agentNodeIdsFromMain.length)}):`
|
|
376
|
+
);
|
|
377
|
+
if (agentNodeIdsFromMain.length === 0) {
|
|
378
|
+
console.log(" (none)");
|
|
379
|
+
} else {
|
|
380
|
+
agentNodeIdsFromMain.forEach((id, i) => {
|
|
381
|
+
console.log(` ${String(i + 1)}. ${id}`);
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
console.log("");
|
|
385
|
+
console.log(
|
|
386
|
+
`Runtime agents \u2014 SDK metadata (${String(runtimeAgents.length)}):`
|
|
387
|
+
);
|
|
388
|
+
if (runtimeAgents.length === 0) {
|
|
389
|
+
console.log(" (none)");
|
|
390
|
+
} else {
|
|
391
|
+
runtimeAgents.forEach((a, i) => {
|
|
392
|
+
console.log(` ${String(i + 1)}. ${a.agentId} \u2014 ${a.name}`);
|
|
393
|
+
});
|
|
394
|
+
}
|
|
256
395
|
console.log("");
|
|
257
396
|
}
|
|
258
|
-
async function
|
|
397
|
+
async function cmdListAgentNodes() {
|
|
259
398
|
const cred = await loadCredentials();
|
|
260
399
|
if (cred === null) {
|
|
261
|
-
console.error(
|
|
400
|
+
console.error(
|
|
401
|
+
"Run `agent-play create-main-node` (or `bootstrap-node`) first."
|
|
402
|
+
);
|
|
262
403
|
process.exitCode = 1;
|
|
263
404
|
return;
|
|
264
405
|
}
|
|
265
406
|
const listRes = await fetch(`${cred.serverUrl}/api/agents`, {
|
|
266
|
-
headers:
|
|
407
|
+
headers: nodeAuthHeaders(cred)
|
|
267
408
|
});
|
|
268
409
|
const listText = await listRes.text();
|
|
269
410
|
if (!listRes.ok) {
|
|
@@ -272,30 +413,48 @@ async function cmdDelete() {
|
|
|
272
413
|
return;
|
|
273
414
|
}
|
|
274
415
|
const listJson = JSON.parse(listText);
|
|
275
|
-
const
|
|
276
|
-
if (!Array.isArray(agentsRaw)) {
|
|
277
|
-
console.error("Invalid list response.");
|
|
278
|
-
process.exitCode = 1;
|
|
279
|
-
return;
|
|
280
|
-
}
|
|
281
|
-
const agents = [];
|
|
282
|
-
for (const a of agentsRaw) {
|
|
283
|
-
if (typeof a !== "object" || a === null) continue;
|
|
284
|
-
const o = a;
|
|
285
|
-
if (typeof o.agentId === "string" && typeof o.name === "string") {
|
|
286
|
-
agents.push({ agentId: o.agentId, name: o.name });
|
|
287
|
-
}
|
|
288
|
-
}
|
|
416
|
+
const agents = parseAgentRows(listJson.agents);
|
|
289
417
|
if (agents.length === 0) {
|
|
290
|
-
console.log("No
|
|
418
|
+
console.log("No agent nodes.");
|
|
291
419
|
return;
|
|
292
420
|
}
|
|
293
421
|
agents.forEach((a, i) => {
|
|
294
|
-
console.log(`${i + 1}. ${a.agentId} (${a.name})`);
|
|
422
|
+
console.log(`${String(i + 1)}. ${a.agentId} (${a.name})`);
|
|
295
423
|
});
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
424
|
+
}
|
|
425
|
+
async function cmdDeleteAgentNode(argv) {
|
|
426
|
+
const cred = await loadCredentials();
|
|
427
|
+
if (cred === null) {
|
|
428
|
+
console.error(
|
|
429
|
+
"Run `agent-play create-main-node` (or `bootstrap-node`) first."
|
|
430
|
+
);
|
|
431
|
+
process.exitCode = 1;
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
let pick = argv[0]?.trim() ?? "";
|
|
435
|
+
if (pick.length === 0) {
|
|
436
|
+
const listRes = await fetch(`${cred.serverUrl}/api/agents`, {
|
|
437
|
+
headers: nodeAuthHeaders(cred)
|
|
438
|
+
});
|
|
439
|
+
const listText = await listRes.text();
|
|
440
|
+
if (!listRes.ok) {
|
|
441
|
+
console.error(`List failed (${listRes.status}): ${listText}`);
|
|
442
|
+
process.exitCode = 1;
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
const listJson = JSON.parse(listText);
|
|
446
|
+
const agents = parseAgentRows(listJson.agents);
|
|
447
|
+
if (agents.length === 0) {
|
|
448
|
+
console.log("No agents.");
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
agents.forEach((a, i) => {
|
|
452
|
+
console.log(`${i + 1}. ${a.agentId} (${a.name})`);
|
|
453
|
+
});
|
|
454
|
+
const rl = createInterface({ input, output });
|
|
455
|
+
pick = (await rl.question("Agent id to delete (empty = cancel): ")).trim();
|
|
456
|
+
rl.close();
|
|
457
|
+
}
|
|
299
458
|
if (pick.length === 0) {
|
|
300
459
|
console.log("Cancelled.");
|
|
301
460
|
return;
|
|
@@ -304,7 +463,7 @@ async function cmdDelete() {
|
|
|
304
463
|
`${cred.serverUrl}/api/agents?id=${encodeURIComponent(pick)}`,
|
|
305
464
|
{
|
|
306
465
|
method: "DELETE",
|
|
307
|
-
headers:
|
|
466
|
+
headers: nodeAuthHeaders(cred)
|
|
308
467
|
}
|
|
309
468
|
);
|
|
310
469
|
const delText = await delRes.text();
|
|
@@ -316,34 +475,225 @@ async function cmdDelete() {
|
|
|
316
475
|
const delJson = JSON.parse(delText);
|
|
317
476
|
console.log(delJson.ok === true ? "Deleted." : "Not found.");
|
|
318
477
|
}
|
|
478
|
+
async function cmdDeleteMainNode() {
|
|
479
|
+
const cred = await loadCredentials();
|
|
480
|
+
if (cred === null) {
|
|
481
|
+
console.error(
|
|
482
|
+
"Run `agent-play create-main-node` (or `bootstrap-node`) first."
|
|
483
|
+
);
|
|
484
|
+
process.exitCode = 1;
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
console.error("");
|
|
488
|
+
console.error("WARNING: You are about to delete your main developer node.");
|
|
489
|
+
console.error(
|
|
490
|
+
"The server will remove this node and cascade-delete every registered"
|
|
491
|
+
);
|
|
492
|
+
console.error(
|
|
493
|
+
"agent node (SDK agent registration) that belongs to it. This cannot be undone."
|
|
494
|
+
);
|
|
495
|
+
console.error(
|
|
496
|
+
"You will need a new passphrase and secret file to join the platform again."
|
|
497
|
+
);
|
|
498
|
+
console.error("");
|
|
499
|
+
const rl = createInterface({ input, output });
|
|
500
|
+
const typed = (await rl.question(
|
|
501
|
+
`Type your main node id exactly to confirm (${cred.nodeId}): `
|
|
502
|
+
)).trim();
|
|
503
|
+
rl.close();
|
|
504
|
+
if (typed !== cred.nodeId) {
|
|
505
|
+
console.log("Confirmation did not match. Cancelled.");
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
const res = await fetch(`${cred.serverUrl}/api/nodes`, {
|
|
509
|
+
method: "DELETE",
|
|
510
|
+
headers: {
|
|
511
|
+
"content-type": "application/json",
|
|
512
|
+
...nodeAuthHeaders(cred)
|
|
513
|
+
},
|
|
514
|
+
body: JSON.stringify({ confirmNodeId: cred.nodeId })
|
|
515
|
+
});
|
|
516
|
+
const text = await res.text();
|
|
517
|
+
if (!res.ok) {
|
|
518
|
+
let msg = text;
|
|
519
|
+
try {
|
|
520
|
+
const err = JSON.parse(text);
|
|
521
|
+
if (typeof err.error === "string") msg = err.error;
|
|
522
|
+
} catch {
|
|
523
|
+
}
|
|
524
|
+
console.error(`Delete main node failed (${res.status}): ${msg}`);
|
|
525
|
+
process.exitCode = 1;
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
const json = JSON.parse(text);
|
|
529
|
+
if (json.ok !== true) {
|
|
530
|
+
console.error("Unexpected response from server.");
|
|
531
|
+
process.exitCode = 1;
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
const n = typeof json.deletedAgentCount === "number" ? json.deletedAgentCount : 0;
|
|
535
|
+
console.log(
|
|
536
|
+
`Main node removed. Cascaded agent nodes deleted: ${String(n)}.`
|
|
537
|
+
);
|
|
538
|
+
console.log("Run `agent-play clear-node-credentials` to forget local creds.");
|
|
539
|
+
}
|
|
540
|
+
async function validateNodeIdentityOnServer(options) {
|
|
541
|
+
const res = await fetch(`${options.cred.serverUrl}/api/nodes/validate`, {
|
|
542
|
+
method: "POST",
|
|
543
|
+
headers: {
|
|
544
|
+
"content-type": "application/json",
|
|
545
|
+
...nodeAuthHeaders(options.cred)
|
|
546
|
+
},
|
|
547
|
+
body: JSON.stringify({
|
|
548
|
+
nodeId: options.nodeId,
|
|
549
|
+
rootKey: options.rootKey,
|
|
550
|
+
mainNodeId: options.mainNodeId
|
|
551
|
+
})
|
|
552
|
+
});
|
|
553
|
+
const text = await res.text();
|
|
554
|
+
let json;
|
|
555
|
+
try {
|
|
556
|
+
json = JSON.parse(text);
|
|
557
|
+
} catch {
|
|
558
|
+
throw new Error(`Validate failed (${String(res.status)}): ${text}`);
|
|
559
|
+
}
|
|
560
|
+
if (typeof json !== "object" || json === null) {
|
|
561
|
+
throw new Error(`Validate failed (${String(res.status)}): invalid response`);
|
|
562
|
+
}
|
|
563
|
+
const obj = json;
|
|
564
|
+
if (typeof obj.ok !== "boolean") {
|
|
565
|
+
const err = typeof obj.error === "string" ? obj.error : text;
|
|
566
|
+
throw new Error(`Validate failed (${String(res.status)}): ${err}`);
|
|
567
|
+
}
|
|
568
|
+
return {
|
|
569
|
+
ok: obj.ok,
|
|
570
|
+
reason: typeof obj.reason === "string" ? obj.reason : void 0,
|
|
571
|
+
nodeKind: typeof obj.nodeKind === "string" ? obj.nodeKind : void 0
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
async function cmdValidateMainNode() {
|
|
575
|
+
const cred = await loadCredentials();
|
|
576
|
+
if (cred === null) {
|
|
577
|
+
console.error(
|
|
578
|
+
"Run `agent-play create-main-node` (or `bootstrap-node`) first."
|
|
579
|
+
);
|
|
580
|
+
process.exitCode = 1;
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
const rootKey = loadRootKey(resolveAgentPlayRootPath({}));
|
|
584
|
+
const result = await validateNodeIdentityOnServer({
|
|
585
|
+
cred,
|
|
586
|
+
rootKey,
|
|
587
|
+
nodeId: cred.nodeId
|
|
588
|
+
});
|
|
589
|
+
if (!result.ok) {
|
|
590
|
+
console.error(
|
|
591
|
+
`Main node validation failed: ${result.reason ?? "unknown reason"}`
|
|
592
|
+
);
|
|
593
|
+
process.exitCode = 1;
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
console.log(`Main node validation passed: ${cred.nodeId}`);
|
|
597
|
+
}
|
|
598
|
+
async function cmdValidateAgentNode(argv) {
|
|
599
|
+
const cred = await loadCredentials();
|
|
600
|
+
if (cred === null) {
|
|
601
|
+
console.error(
|
|
602
|
+
"Run `agent-play create-main-node` (or `bootstrap-node`) first."
|
|
603
|
+
);
|
|
604
|
+
process.exitCode = 1;
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
const opts = parseValidateAgentNodeArgs(argv);
|
|
608
|
+
if (opts === null) {
|
|
609
|
+
console.error(
|
|
610
|
+
"Usage: agent-play validate-agent-node --all | --agent-node-ids <id1,id2,...>"
|
|
611
|
+
);
|
|
612
|
+
process.exitCode = 1;
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
const rootKey = loadRootKey(resolveAgentPlayRootPath({}));
|
|
616
|
+
const targetIds = opts.mode === "all" ? (cred.agentNodes ?? []).map((n) => n.nodeId) : opts.agentNodeIds;
|
|
617
|
+
const dedupedIds = Array.from(new Set(targetIds.filter((id) => id.length > 0)));
|
|
618
|
+
if (dedupedIds.length === 0) {
|
|
619
|
+
console.log("No agent node ids to validate.");
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
let failures = 0;
|
|
623
|
+
for (const nodeId of dedupedIds) {
|
|
624
|
+
const result = await validateNodeIdentityOnServer({
|
|
625
|
+
cred,
|
|
626
|
+
rootKey,
|
|
627
|
+
nodeId,
|
|
628
|
+
mainNodeId: cred.nodeId
|
|
629
|
+
});
|
|
630
|
+
if (!result.ok) {
|
|
631
|
+
failures += 1;
|
|
632
|
+
console.error(
|
|
633
|
+
`FAIL ${nodeId}: ${result.reason ?? "unknown reason"}`
|
|
634
|
+
);
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
console.log(`PASS ${nodeId}`);
|
|
638
|
+
}
|
|
639
|
+
if (failures > 0) {
|
|
640
|
+
process.exitCode = 1;
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
console.log(`Validated ${String(dedupedIds.length)} agent node(s) successfully.`);
|
|
644
|
+
}
|
|
319
645
|
async function main() {
|
|
320
646
|
const cmd = process.argv[2];
|
|
321
|
-
if (cmd === "
|
|
322
|
-
await
|
|
647
|
+
if (cmd === "bootstrap-node" || cmd === "create-main-node") {
|
|
648
|
+
await cmdBootstrapNode(process.argv.slice(3));
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
if (cmd === "clear-node-credentials") {
|
|
652
|
+
await cmdClearNodeCredentials();
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
if (cmd === "inspect-node") {
|
|
656
|
+
await cmdInspectNode();
|
|
657
|
+
return;
|
|
658
|
+
}
|
|
659
|
+
if (cmd === "create-agent-node" || cmd === "create") {
|
|
660
|
+
await cmdCreateAgentNode();
|
|
323
661
|
return;
|
|
324
662
|
}
|
|
325
|
-
if (cmd === "
|
|
326
|
-
await
|
|
663
|
+
if (cmd === "list-agent-nodes" || cmd === "list") {
|
|
664
|
+
await cmdListAgentNodes();
|
|
327
665
|
return;
|
|
328
666
|
}
|
|
329
|
-
if (cmd === "
|
|
330
|
-
await
|
|
667
|
+
if (cmd === "delete-agent-node" || cmd === "delete" || cmd === "remove") {
|
|
668
|
+
await cmdDeleteAgentNode(process.argv.slice(3));
|
|
331
669
|
return;
|
|
332
670
|
}
|
|
333
|
-
if (cmd === "
|
|
334
|
-
await
|
|
671
|
+
if (cmd === "delete-main-node") {
|
|
672
|
+
await cmdDeleteMainNode();
|
|
335
673
|
return;
|
|
336
674
|
}
|
|
337
|
-
if (cmd === "
|
|
338
|
-
await
|
|
675
|
+
if (cmd === "validate-main-node") {
|
|
676
|
+
await cmdValidateMainNode();
|
|
339
677
|
return;
|
|
340
678
|
}
|
|
341
|
-
if (cmd === "
|
|
342
|
-
await
|
|
679
|
+
if (cmd === "validate-agent-node") {
|
|
680
|
+
await cmdValidateAgentNode(process.argv.slice(3));
|
|
343
681
|
return;
|
|
344
682
|
}
|
|
345
683
|
console.error(
|
|
346
|
-
|
|
684
|
+
[
|
|
685
|
+
"Usage:",
|
|
686
|
+
" agent-play create-main-node | bootstrap-node [--root-file <path>]",
|
|
687
|
+
" agent-play inspect-node",
|
|
688
|
+
" agent-play create-agent-node | create",
|
|
689
|
+
" agent-play list-agent-nodes | list",
|
|
690
|
+
" agent-play delete-agent-node | delete [agent-id]",
|
|
691
|
+
" agent-play delete-main-node",
|
|
692
|
+
" agent-play validate-main-node",
|
|
693
|
+
" agent-play validate-agent-node --all",
|
|
694
|
+
" agent-play validate-agent-node --agent-node-ids <id1,id2,...>",
|
|
695
|
+
" agent-play clear-node-credentials"
|
|
696
|
+
].join("\n")
|
|
347
697
|
);
|
|
348
698
|
process.exitCode = 1;
|
|
349
699
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-play/cli",
|
|
3
|
-
"version": "3.0
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"description": "Command-line tool for Agent Play: login, API keys, and agent registration against the web UI.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"type": "module",
|
|
@@ -20,9 +20,11 @@
|
|
|
20
20
|
"access": "public"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
23
|
-
"build": "tsup src/cli.ts --format esm --platform node --target node20 --out-dir dist --clean"
|
|
23
|
+
"build": "tsup src/cli.ts --format esm --platform node --target node20 --out-dir dist --clean --external @agent-play/node-tools && node ../../scripts/copy-root-file.mjs cli"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@agent-play/node-tools": "1.0.0"
|
|
24
27
|
},
|
|
25
|
-
"dependencies": {},
|
|
26
28
|
"devDependencies": {
|
|
27
29
|
"@types/node": "^22.10.0",
|
|
28
30
|
"tsup": "^8.5.1",
|