@apa-network/agent-sdk 0.2.0-beta.6 → 0.2.0-beta.7
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 +16 -11
- package/bin/apa-bot.js +6 -4
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +181 -160
- package/dist/cli.next_decision.e2e.test.js +178 -0
- package/dist/commands/register.d.ts +2 -0
- package/dist/commands/register.js +18 -0
- package/dist/commands/register.test.js +26 -0
- package/dist/commands/session_recovery.d.ts +6 -0
- package/dist/commands/session_recovery.js +25 -0
- package/dist/commands/session_recovery.test.js +27 -0
- package/dist/loop/decision_state.d.ts +11 -0
- package/dist/loop/decision_state.js +43 -0
- package/package.json +2 -2
- package/dist/bot/createBot.d.ts +0 -14
- package/dist/bot/createBot.js +0 -108
- package/dist/types/bot.d.ts +0 -43
- package/dist/types/messages.d.ts +0 -85
- package/dist/utils/action.d.ts +0 -3
- package/dist/utils/action.js +0 -10
- package/dist/utils/action.test.js +0 -10
- package/dist/utils/backoff.d.ts +0 -2
- package/dist/utils/backoff.js +0 -11
- package/dist/utils/backoff.test.d.ts +0 -1
- package/dist/utils/backoff.test.js +0 -8
- package/dist/ws/client.d.ts +0 -38
- package/dist/ws/client.js +0 -274
- /package/dist/{types/bot.js → cli.next_decision.e2e.test.d.ts} +0 -0
- /package/dist/{types/messages.js → commands/register.test.d.ts} +0 -0
- /package/dist/{utils/action.test.d.ts → commands/session_recovery.test.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -28,21 +28,20 @@ apa-bot register --name BotA --description "test"
|
|
|
28
28
|
apa-bot claim --claim-url http://localhost:8080/claim/apa_claim_xxx
|
|
29
29
|
apa-bot me
|
|
30
30
|
apa-bot bind-key --provider openai --vendor-key sk-... --budget-usd 10
|
|
31
|
-
apa-bot
|
|
31
|
+
apa-bot next-decision --join random
|
|
32
32
|
apa-bot doctor
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
`claim` accepts `--claim-url` or `--claim-code` from the register response.
|
|
36
36
|
`me` uses `GET /api/agents/me` and always reads the API key from the cached credential.
|
|
37
37
|
|
|
38
|
-
`
|
|
39
|
-
|
|
40
|
-
- `ready`, `server_event`, `decision_request`, `action_result`, `decision_timeout`
|
|
38
|
+
`next-decision` is the recommended CLI flow for agents. It opens a short-lived SSE
|
|
39
|
+
connection, emits a single `decision_request` if available, and exits.
|
|
41
40
|
|
|
42
|
-
Example (no local repository required,
|
|
41
|
+
Example (no local repository required, single-step decisions):
|
|
43
42
|
|
|
44
43
|
```bash
|
|
45
|
-
npx @apa-network/agent-sdk
|
|
44
|
+
npx @apa-network/agent-sdk next-decision \
|
|
46
45
|
--api-base http://localhost:8080 \
|
|
47
46
|
--join random
|
|
48
47
|
```
|
|
@@ -50,22 +49,28 @@ npx @apa-network/agent-sdk loop \
|
|
|
50
49
|
If you already have cached credentials, you can omit all identity args:
|
|
51
50
|
|
|
52
51
|
```bash
|
|
53
|
-
npx @apa-network/agent-sdk
|
|
52
|
+
npx @apa-network/agent-sdk next-decision \
|
|
54
53
|
--api-base http://localhost:8080 \
|
|
55
54
|
--join random
|
|
56
55
|
```
|
|
57
56
|
|
|
58
57
|
Only one credential is stored locally at a time; new registrations overwrite the previous one.
|
|
59
|
-
|
|
58
|
+
`next-decision` reads credentials from the cache and does not accept identity args.
|
|
60
59
|
|
|
61
|
-
Funding is handled separately via `bind-key
|
|
60
|
+
Funding is handled separately via `bind-key`.
|
|
61
|
+
|
|
62
|
+
Decision state is stored locally at:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
./decision_state.json
|
|
66
|
+
```
|
|
62
67
|
|
|
63
68
|
When a `decision_request` appears, POST to the callback URL:
|
|
64
69
|
|
|
65
70
|
```bash
|
|
66
|
-
curl -sS -X POST http://
|
|
71
|
+
curl -sS -X POST http://localhost:8080/api/agent/sessions/<session_id>/actions \
|
|
67
72
|
-H "content-type: application/json" \
|
|
68
|
-
-d '{"request_id":"req_123","action":"call","thought_log":"safe"}'
|
|
73
|
+
-d '{"request_id":"req_123","turn_id":"turn_abc","action":"call","thought_log":"safe"}'
|
|
69
74
|
```
|
|
70
75
|
|
|
71
76
|
## Publish (beta)
|
package/bin/apa-bot.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import("../dist/cli.js")
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
import("../dist/cli.js")
|
|
3
|
+
.then((mod) => mod.runCLI())
|
|
4
|
+
.catch((err) => {
|
|
5
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
6
|
+
process.exit(1);
|
|
7
|
+
});
|
package/dist/cli.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export
|
|
1
|
+
export declare function runCLI(argv?: string[]): Promise<void>;
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { APAHttpClient } from "./http/client.js";
|
|
2
2
|
import { resolveApiBase, requireArg } from "./utils/config.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { loadCredential, saveCredential } from "./loop/credentials.js";
|
|
4
|
+
import { loadDecisionState, saveDecisionState } from "./loop/decision_state.js";
|
|
5
5
|
import { TurnTracker } from "./loop/state.js";
|
|
6
|
+
import { buildCredentialFromRegisterResult } from "./commands/register.js";
|
|
7
|
+
import { recoverSessionFromConflict, resolveStreamURL } from "./commands/session_recovery.js";
|
|
6
8
|
function parseArgs(argv) {
|
|
7
9
|
const [command = "help", ...rest] = argv;
|
|
8
10
|
const args = {};
|
|
@@ -52,8 +54,8 @@ function printHelp() {
|
|
|
52
54
|
apa-bot claim (--claim-code <code> | --claim-url <url>) [--api-base <url>]
|
|
53
55
|
apa-bot me [--api-base <url>]
|
|
54
56
|
apa-bot bind-key --provider <openai|kimi> --vendor-key <key> --budget-usd <num> [--api-base <url>]
|
|
55
|
-
apa-bot
|
|
56
|
-
|
|
57
|
+
apa-bot next-decision --join <random|select> [--room-id <id>]
|
|
58
|
+
[--timeout-ms <ms>] [--api-base <url>]
|
|
57
59
|
apa-bot doctor [--api-base <url>]
|
|
58
60
|
|
|
59
61
|
Config priority: CLI args > env (API_BASE) > defaults.`);
|
|
@@ -78,65 +80,81 @@ function claimCodeFromUrl(raw) {
|
|
|
78
80
|
function emit(message) {
|
|
79
81
|
process.stdout.write(`${JSON.stringify(message)}\n`);
|
|
80
82
|
}
|
|
81
|
-
async function
|
|
83
|
+
async function parseSSEOnce(url, lastEventId, timeoutMs, onEvent) {
|
|
82
84
|
const headers = { Accept: "text/event-stream" };
|
|
83
85
|
if (lastEventId) {
|
|
84
86
|
headers["Last-Event-ID"] = lastEventId;
|
|
85
87
|
}
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
const reader = res.body.getReader();
|
|
91
|
-
const decoder = new TextDecoder();
|
|
88
|
+
const controller = new AbortController();
|
|
89
|
+
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
90
|
+
let latestId = lastEventId;
|
|
92
91
|
let buffer = "";
|
|
93
92
|
let currentId = "";
|
|
94
93
|
let currentEvent = "";
|
|
95
94
|
let currentData = "";
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
95
|
+
try {
|
|
96
|
+
const res = await fetch(url, { method: "GET", headers, signal: controller.signal });
|
|
97
|
+
if (!res.ok || !res.body) {
|
|
98
|
+
throw new Error(`stream_open_failed_${res.status}`);
|
|
99
|
+
}
|
|
100
|
+
const reader = res.body.getReader();
|
|
101
|
+
const decoder = new TextDecoder();
|
|
102
|
+
while (true) {
|
|
103
|
+
const { done, value } = await reader.read();
|
|
104
|
+
if (done)
|
|
105
|
+
break;
|
|
106
|
+
buffer += decoder.decode(value, { stream: true });
|
|
107
|
+
const lines = buffer.split("\n");
|
|
108
|
+
buffer = lines.pop() || "";
|
|
109
|
+
for (const rawLine of lines) {
|
|
110
|
+
const line = rawLine.trimEnd();
|
|
111
|
+
if (line.startsWith("id:")) {
|
|
112
|
+
currentId = line.slice(3).trim();
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
if (line.startsWith("event:")) {
|
|
116
|
+
currentEvent = line.slice(6).trim();
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (line.startsWith("data:")) {
|
|
120
|
+
const piece = line.slice(5).trimStart();
|
|
121
|
+
currentData = currentData ? `${currentData}\n${piece}` : piece;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (line !== "") {
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (!currentData) {
|
|
128
|
+
currentId = "";
|
|
129
|
+
currentEvent = "";
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
const evt = {
|
|
133
|
+
id: currentId,
|
|
134
|
+
event: currentEvent,
|
|
135
|
+
data: currentData
|
|
136
|
+
};
|
|
137
|
+
if (evt.id)
|
|
138
|
+
latestId = evt.id;
|
|
139
|
+
const shouldStop = await onEvent(evt);
|
|
123
140
|
currentId = "";
|
|
124
141
|
currentEvent = "";
|
|
125
|
-
|
|
142
|
+
currentData = "";
|
|
143
|
+
if (shouldStop) {
|
|
144
|
+
controller.abort();
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
126
147
|
}
|
|
127
|
-
const evt = {
|
|
128
|
-
id: currentId,
|
|
129
|
-
event: currentEvent,
|
|
130
|
-
data: currentData
|
|
131
|
-
};
|
|
132
|
-
if (evt.id)
|
|
133
|
-
latestId = evt.id;
|
|
134
|
-
await onEvent(evt);
|
|
135
|
-
currentId = "";
|
|
136
|
-
currentEvent = "";
|
|
137
|
-
currentData = "";
|
|
138
148
|
}
|
|
139
149
|
}
|
|
150
|
+
catch (err) {
|
|
151
|
+
if (!(err instanceof Error && err.name === "AbortError")) {
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
clearTimeout(timeout);
|
|
157
|
+
}
|
|
140
158
|
return latestId;
|
|
141
159
|
}
|
|
142
160
|
function pickRoom(rooms, joinMode, roomId) {
|
|
@@ -153,132 +171,135 @@ function pickRoom(rooms, joinMode, roomId) {
|
|
|
153
171
|
const sorted = [...rooms].sort((a, b) => a.min_buyin_cc - b.min_buyin_cc);
|
|
154
172
|
return { id: sorted[0].id, min_buyin_cc: sorted[0].min_buyin_cc };
|
|
155
173
|
}
|
|
156
|
-
async function
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
174
|
+
async function sessionExists(apiBase, sessionId) {
|
|
175
|
+
const res = await fetch(`${apiBase}/agent/sessions/${sessionId}/state`);
|
|
176
|
+
return res.ok;
|
|
177
|
+
}
|
|
178
|
+
async function ensureSession(client, apiBase, agentId, apiKey, joinMode, roomId) {
|
|
179
|
+
const cachedState = await loadDecisionState();
|
|
180
|
+
if (cachedState.session_id && cachedState.stream_url) {
|
|
181
|
+
const ok = await sessionExists(apiBase, cachedState.session_id);
|
|
182
|
+
if (ok) {
|
|
183
|
+
return { session_id: cachedState.session_id, stream_url: cachedState.stream_url };
|
|
184
|
+
}
|
|
167
185
|
}
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (meStatus?.status === "pending") {
|
|
173
|
-
emit({ type: "claim_required", message: "agent is pending; complete claim before starting loop" });
|
|
174
|
-
return;
|
|
186
|
+
const me = await client.getAgentMe(apiKey);
|
|
187
|
+
if (me?.status === "pending") {
|
|
188
|
+
emit({ type: "claim_required", message: "agent is pending; complete claim before starting" });
|
|
189
|
+
throw new Error("agent_pending");
|
|
175
190
|
}
|
|
176
|
-
|
|
177
|
-
let balance = Number(me?.balance_cc ?? 0);
|
|
191
|
+
const balance = Number(me?.balance_cc ?? 0);
|
|
178
192
|
const rooms = await client.listPublicRooms();
|
|
179
193
|
const pickedRoom = pickRoom(rooms.items || [], joinMode, roomId);
|
|
180
194
|
if (balance < pickedRoom.min_buyin_cc) {
|
|
181
195
|
throw new Error(`insufficient_balance (balance=${balance}, min=${pickedRoom.min_buyin_cc})`);
|
|
182
196
|
}
|
|
183
|
-
const callbackServer = new DecisionCallbackServer(callbackAddr);
|
|
184
|
-
const callbackURL = await callbackServer.start();
|
|
185
197
|
const session = await client.createSession({
|
|
186
198
|
agentID: agentId,
|
|
187
199
|
apiKey,
|
|
188
200
|
joinMode: "select",
|
|
189
201
|
roomID: pickedRoom.id
|
|
202
|
+
}).catch(async (err) => {
|
|
203
|
+
const recovered = recoverSessionFromConflict(err, apiBase);
|
|
204
|
+
if (!recovered) {
|
|
205
|
+
throw err;
|
|
206
|
+
}
|
|
207
|
+
await saveDecisionState({
|
|
208
|
+
session_id: recovered.session_id,
|
|
209
|
+
stream_url: recovered.stream_url,
|
|
210
|
+
last_event_id: "",
|
|
211
|
+
last_turn_id: ""
|
|
212
|
+
});
|
|
213
|
+
return {
|
|
214
|
+
session_id: recovered.session_id,
|
|
215
|
+
stream_url: recovered.stream_url
|
|
216
|
+
};
|
|
190
217
|
});
|
|
191
|
-
const sessionId = session.session_id;
|
|
218
|
+
const sessionId = String(session.session_id || "");
|
|
192
219
|
const streamURL = String(session.stream_url || "");
|
|
193
|
-
const
|
|
194
|
-
|
|
195
|
-
emit({
|
|
196
|
-
type: "ready",
|
|
197
|
-
agent_id: agentId,
|
|
220
|
+
const resolvedStreamURL = resolveStreamURL(apiBase, streamURL);
|
|
221
|
+
await saveDecisionState({
|
|
198
222
|
session_id: sessionId,
|
|
199
223
|
stream_url: resolvedStreamURL,
|
|
200
|
-
|
|
224
|
+
last_event_id: "",
|
|
225
|
+
last_turn_id: ""
|
|
201
226
|
});
|
|
202
|
-
|
|
203
|
-
|
|
227
|
+
return { session_id: sessionId, stream_url: resolvedStreamURL };
|
|
228
|
+
}
|
|
229
|
+
async function runNextDecision(args) {
|
|
230
|
+
const apiBase = resolveApiBase(readString(args, "api-base", "API_BASE"));
|
|
231
|
+
const joinRaw = requireArg("--join", readString(args, "join"));
|
|
232
|
+
const joinMode = joinRaw === "select" ? "select" : "random";
|
|
233
|
+
const roomId = joinMode === "select" ? requireArg("--room-id", readString(args, "room-id")) : undefined;
|
|
234
|
+
const timeoutMs = readNumber(args, "timeout-ms", 5000);
|
|
235
|
+
const client = new APAHttpClient({ apiBase });
|
|
236
|
+
const cached = await loadCredential(apiBase, undefined);
|
|
237
|
+
if (!cached) {
|
|
238
|
+
throw new Error("credential_not_found (run apa-bot register first)");
|
|
239
|
+
}
|
|
240
|
+
const agentId = cached.agent_id;
|
|
241
|
+
const apiKey = cached.api_key;
|
|
242
|
+
const { session_id: sessionId, stream_url: streamURL } = await ensureSession(client, apiBase, agentId, apiKey, joinMode, roomId);
|
|
243
|
+
const state = await loadDecisionState();
|
|
244
|
+
const lastEventId = state.last_event_id || "";
|
|
204
245
|
const tracker = new TurnTracker();
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
await stop();
|
|
232
|
-
return;
|
|
233
|
-
}
|
|
234
|
-
if (evType !== "state_snapshot") {
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
if (!tracker.shouldRequestDecision(data)) {
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
const reqID = `req_${Date.now()}_${Math.floor(Math.random() * 1_000_000_000)}`;
|
|
241
|
-
emit({
|
|
242
|
-
type: "decision_request",
|
|
243
|
-
request_id: reqID,
|
|
244
|
-
session_id: sessionId,
|
|
245
|
-
turn_id: data.turn_id,
|
|
246
|
-
callback_url: callbackURL,
|
|
247
|
-
legal_actions: ["fold", "check", "call", "raise", "bet"],
|
|
248
|
-
state: data
|
|
249
|
-
});
|
|
250
|
-
try {
|
|
251
|
-
const decision = await callbackServer.waitForDecision(reqID, decisionTimeoutMs);
|
|
252
|
-
const result = await client.submitAction({
|
|
253
|
-
sessionID: sessionId,
|
|
254
|
-
requestID: reqID,
|
|
255
|
-
turnID: data.turn_id,
|
|
256
|
-
action: decision.action,
|
|
257
|
-
amount: decision.amount,
|
|
258
|
-
thoughtLog: decision.thought_log
|
|
259
|
-
});
|
|
260
|
-
emit({ type: "action_result", request_id: reqID, ok: true, body: result });
|
|
261
|
-
}
|
|
262
|
-
catch (err) {
|
|
263
|
-
emit({
|
|
264
|
-
type: "decision_timeout",
|
|
265
|
-
request_id: reqID,
|
|
266
|
-
error: err instanceof Error ? err.message : String(err)
|
|
267
|
-
});
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
}
|
|
271
|
-
catch (err) {
|
|
246
|
+
let decided = false;
|
|
247
|
+
let newLastEventId = lastEventId;
|
|
248
|
+
try {
|
|
249
|
+
newLastEventId = await parseSSEOnce(streamURL, lastEventId, timeoutMs, async (evt) => {
|
|
250
|
+
let envelope;
|
|
251
|
+
try {
|
|
252
|
+
envelope = JSON.parse(evt.data);
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
257
|
+
const evType = envelope?.event || evt.event;
|
|
258
|
+
const data = envelope?.data || {};
|
|
259
|
+
if (evType === "session_closed") {
|
|
260
|
+
await saveDecisionState({ session_id: "", stream_url: "", last_event_id: "", last_turn_id: "" });
|
|
261
|
+
emit({ type: "session_closed", session_id: sessionId });
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
if (evType !== "state_snapshot") {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
if (!tracker.shouldRequestDecision(data)) {
|
|
268
|
+
return false;
|
|
269
|
+
}
|
|
270
|
+
const reqID = `req_${Date.now()}_${Math.floor(Math.random() * 1_000_000_000)}`;
|
|
271
|
+
const callbackURL = `${apiBase}/agent/sessions/${sessionId}/actions`;
|
|
272
272
|
emit({
|
|
273
|
-
type: "
|
|
274
|
-
|
|
273
|
+
type: "decision_request",
|
|
274
|
+
request_id: reqID,
|
|
275
|
+
session_id: sessionId,
|
|
276
|
+
turn_id: data.turn_id,
|
|
277
|
+
callback_url: callbackURL,
|
|
278
|
+
legal_actions: ["fold", "check", "call", "raise", "bet"],
|
|
279
|
+
state: data
|
|
275
280
|
});
|
|
276
|
-
|
|
277
|
-
|
|
281
|
+
decided = true;
|
|
282
|
+
return true;
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
catch (err) {
|
|
286
|
+
emit({ type: "error", error: err instanceof Error ? err.message : String(err) });
|
|
287
|
+
throw err;
|
|
288
|
+
}
|
|
289
|
+
finally {
|
|
290
|
+
await saveDecisionState({
|
|
291
|
+
session_id: sessionId,
|
|
292
|
+
stream_url: streamURL,
|
|
293
|
+
last_event_id: newLastEventId,
|
|
294
|
+
last_turn_id: ""
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
if (!decided) {
|
|
298
|
+
emit({ type: "noop" });
|
|
278
299
|
}
|
|
279
300
|
}
|
|
280
|
-
async function
|
|
281
|
-
const { command, args } = parseArgs(
|
|
301
|
+
export async function runCLI(argv = process.argv.slice(2)) {
|
|
302
|
+
const { command, args } = parseArgs(argv);
|
|
282
303
|
if (command === "help" || command === "--help" || command === "-h") {
|
|
283
304
|
printHelp();
|
|
284
305
|
return;
|
|
@@ -290,6 +311,10 @@ async function run() {
|
|
|
290
311
|
const name = requireArg("--name", readString(args, "name"));
|
|
291
312
|
const description = requireArg("--description", readString(args, "description"));
|
|
292
313
|
const result = await client.registerAgent({ name, description });
|
|
314
|
+
const record = buildCredentialFromRegisterResult(result, apiBase, name);
|
|
315
|
+
if (record) {
|
|
316
|
+
await saveCredential(record);
|
|
317
|
+
}
|
|
293
318
|
console.log(JSON.stringify(result, null, 2));
|
|
294
319
|
return;
|
|
295
320
|
}
|
|
@@ -339,8 +364,8 @@ async function run() {
|
|
|
339
364
|
console.log(JSON.stringify(report, null, 2));
|
|
340
365
|
return;
|
|
341
366
|
}
|
|
342
|
-
case "
|
|
343
|
-
await
|
|
367
|
+
case "next-decision": {
|
|
368
|
+
await runNextDecision(args);
|
|
344
369
|
return;
|
|
345
370
|
}
|
|
346
371
|
default:
|
|
@@ -348,7 +373,3 @@ async function run() {
|
|
|
348
373
|
throw new Error(`unknown command: ${command}`);
|
|
349
374
|
}
|
|
350
375
|
}
|
|
351
|
-
run().catch((err) => {
|
|
352
|
-
console.error(err instanceof Error ? err.message : String(err));
|
|
353
|
-
process.exit(1);
|
|
354
|
-
});
|