@consiliency/agent-board-cli 1.16.0 → 1.20.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/dist/cli.d.ts +1 -0
- package/dist/cli.js +97 -82
- package/dist/enroll_runtime.d.ts +2 -1
- package/dist/enroll_runtime.js +2 -1
- package/package.json +2 -2
package/dist/cli.d.ts
CHANGED
|
@@ -79,6 +79,7 @@ interface ClientLike {
|
|
|
79
79
|
agentDashboard(input: JsonObject): Promise<unknown>;
|
|
80
80
|
agentInbox(input: JsonObject): Promise<unknown>;
|
|
81
81
|
agentInboxCounts(input: JsonObject): Promise<unknown>;
|
|
82
|
+
wakeRecovery(input: JsonObject): Promise<unknown>;
|
|
82
83
|
boardDirectory(input: JsonObject): Promise<unknown>;
|
|
83
84
|
boardMemberships(input: JsonObject): Promise<unknown>;
|
|
84
85
|
boardFeed(input: JsonObject): Promise<unknown>;
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Command, Option } from "commander";
|
|
|
2
2
|
import { createHash, randomUUID } from "node:crypto";
|
|
3
3
|
import { homedir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
|
-
import { createAgentBoardClient, toOperationFailure, beginEnrollment, completeEnrollment, beginDeviceEnrollment, completeDeviceEnrollment, runEnrollment, runDeviceEnrollment, resolveEnrollmentDescriptor, EnrollmentDescriptorError, EnrollmentCommandError, resolveEnrollEndpoint, resolveEnrollSessionUrl, resolveEnrollPublishableKey, resolveJoinDeployment, buildFleetHarnessTemplate, finalizeFleetHarnessTemplate, normalizePublishableKeyFieldReference, normalizeFleetTupleValue, normalizeKeyReference, enrollCommitMarker, assertPresentationSafe, FLEET_TEMPLATE_FAILURE_MESSAGE, PROHIBITED_PRESENTATION_REMOVE_CLASS, buildAgentJoinInstructions, nodeFetchAdapter, buildEnrollKeystore, } from "@consiliency/agent-board-client";
|
|
5
|
+
import { createAgentBoardClient, toOperationFailure, beginEnrollment, completeEnrollment, beginDeviceEnrollment, completeDeviceEnrollment, runEnrollment, runDeviceEnrollment, resolveEnrollmentDescriptor, EnrollmentDescriptorError, EnrollmentCommandError, resolveEnrollEndpoint, resolveEnrollSessionUrl, resolveEnrollPublishableKey, resolveJoinDeployment, buildFleetHarnessTemplate, finalizeFleetHarnessTemplate, normalizePublishableKeyFieldReference, normalizeFleetTupleValue, normalizeKeyReference, enrollCommitMarker, assertPresentationSafe, FLEET_TEMPLATE_FAILURE_MESSAGE, PROHIBITED_PRESENTATION_REMOVE_CLASS, buildAgentJoinInstructions, nodeFetchAdapter, buildEnrollKeystore, AUTHORED_CAUSE_CODES, codeProvenance, markAuthoredCode, } from "@consiliency/agent-board-client";
|
|
6
6
|
import { DevicePendingEnrollmentStore, FilePendingEnrollmentStore, FleetDeviceContinuationStore, makeBrowserOpener, prepareFleetRuntimeOutput, publishFinalizedFleetTemplate, } from "./enroll_runtime.js";
|
|
7
7
|
function isRuntimeStatus(value) {
|
|
8
8
|
return Boolean(value && typeof value === "object" && "runtime" in value);
|
|
@@ -29,6 +29,7 @@ class FleetSafeMessageError extends Error {
|
|
|
29
29
|
super(message);
|
|
30
30
|
this.code = code;
|
|
31
31
|
this.name = "FleetSafeMessageError";
|
|
32
|
+
markAuthoredCode(this);
|
|
32
33
|
}
|
|
33
34
|
}
|
|
34
35
|
/**
|
|
@@ -70,17 +71,21 @@ class FleetPreflightError extends FleetSafeMessageError {
|
|
|
70
71
|
* blanket redaction is for.
|
|
71
72
|
*/
|
|
72
73
|
class FleetPostCommitError extends FleetSafeMessageError {
|
|
73
|
-
constructor(committedFacts, cause) {
|
|
74
|
+
constructor(committedFacts, origin, cause) {
|
|
74
75
|
// Only the ids that survived. Region-1 facts are deliberately sparse — that region
|
|
75
76
|
// renders what this process KNEW rather than what the response echoed — so a fixed
|
|
76
77
|
// four-field list would print `agentId=,` and read as data while carrying none.
|
|
77
|
-
const committed = renderIds(committedFacts
|
|
78
|
+
const committed = renderIds(committedFacts, origin)
|
|
79
|
+
|| (origin === "receipt"
|
|
80
|
+
? "(the receipt carried no id we could verify)"
|
|
81
|
+
: "(this enrollment named nothing to verify against)");
|
|
78
82
|
const detail = cause instanceof FleetSafeMessageError
|
|
79
83
|
? cause.message
|
|
80
84
|
: `detail withheld (a raw local failure can carry key descriptors)${namedCauseCode(cause)}`;
|
|
81
85
|
super("fleet_onboarding_committed_local_finalization_failed", "fleet enrollment COMMITTED on the server; only local finalization failed. "
|
|
82
86
|
+ "Do NOT treat this as a failed enrollment and do NOT re-run it — the bounded invite use is spent. "
|
|
83
|
-
+
|
|
87
|
+
+ `${origin === "receipt" ? "Committed" : "Verify against the values you passed as"}: ${committed}. `
|
|
88
|
+
+ `Local finalization failure: ${detail}`);
|
|
84
89
|
this.cause = cause;
|
|
85
90
|
}
|
|
86
91
|
}
|
|
@@ -140,29 +145,34 @@ function throughPresentationGate(action) {
|
|
|
140
145
|
}
|
|
141
146
|
}
|
|
142
147
|
/**
|
|
143
|
-
*
|
|
144
|
-
*
|
|
148
|
+
* The one-word cause discriminator, restored on a PROVENANCE gate (#403) after #402
|
|
149
|
+
* withdrew it. #402's two shape gates both rested on a claim about what a credential can
|
|
150
|
+
* look like (a snake_case alphabet, then a 42-character cap) and a fleet invite code or a
|
|
151
|
+
* short OAuth `device_code` fits either. There is no third shape bound, so this gate asks
|
|
152
|
+
* a different question: did WE write this value?
|
|
145
153
|
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
154
|
+
* Property (plan §2.1): returns ` [code <cause.code>]` iff `cause.code` is a string equal
|
|
155
|
+
* to a member of AUTHORED_CAUSE_CODES — the set derived by
|
|
156
|
+
* `scripts/derive-authored-cause-codes.mjs` from every literal this repository assigns to
|
|
157
|
+
* an error `code` — AND the instance carries the authored value-bound brand for that exact
|
|
158
|
+
* value (`codeProvenance(cause) === "authored"`, see code_provenance.ts). Both halves are
|
|
159
|
+
* needed: the set alone would print a server body that happens to equal a member; the
|
|
160
|
+
* brand alone would print a value the brand was never bound to. A foreign value therefore
|
|
161
|
+
* reaches the operator only if it is already a published member of the set (it carries no
|
|
162
|
+
* foreign byte) AND arrived through an instance that was branded authored for it (R6-1:
|
|
163
|
+
* an equal-value overwrite of an authored code is one bit of equality, not a leak).
|
|
153
164
|
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
* THE COST, stated because it is real: a post-commit or commit-unknown message no longer
|
|
159
|
-
* carries `[code <cause>]`, so an operator debugging one of those loses the one-word
|
|
160
|
-
* discriminator. Everything else in both messages is unchanged, and both still name the
|
|
161
|
-
* state and the action. Restoring it needs a bound that holds for EVERY credential able to
|
|
162
|
-
* reach here, not one derived from a single issuer.
|
|
165
|
+
* Every other input returns "": a non-object, a non-string `code`, a non-member, an
|
|
166
|
+
* unbranded instance, a `"foreign"`-branded instance, or an instance whose `code` was
|
|
167
|
+
* written after it was branded.
|
|
163
168
|
*/
|
|
164
|
-
function namedCauseCode(
|
|
165
|
-
|
|
169
|
+
function namedCauseCode(cause) {
|
|
170
|
+
if (cause === null || typeof cause !== "object")
|
|
171
|
+
return "";
|
|
172
|
+
const { code } = cause;
|
|
173
|
+
if (typeof code !== "string" || !AUTHORED_CAUSE_CODES.has(code))
|
|
174
|
+
return "";
|
|
175
|
+
return codeProvenance(cause) === "authored" ? ` [code ${code}]` : "";
|
|
166
176
|
}
|
|
167
177
|
function committedFactsFromOutcome(outcome) {
|
|
168
178
|
return {
|
|
@@ -227,7 +237,7 @@ async function afterFleetCommit(outcome, action) {
|
|
|
227
237
|
return await action();
|
|
228
238
|
}
|
|
229
239
|
catch (error) {
|
|
230
|
-
throw error instanceof FleetPostCommitError ? error : new FleetPostCommitError(committedFactsFromOutcome(outcome), error);
|
|
240
|
+
throw error instanceof FleetPostCommitError ? error : new FleetPostCommitError(committedFactsFromOutcome(outcome), "receipt", error);
|
|
231
241
|
}
|
|
232
242
|
}
|
|
233
243
|
/**
|
|
@@ -235,60 +245,42 @@ async function afterFleetCommit(outcome, action) {
|
|
|
235
245
|
* agentHandle=,`) is the shape both messages exist to avoid printing: it reads as
|
|
236
246
|
* evidence while carrying none.
|
|
237
247
|
*/
|
|
238
|
-
function renderIds(facts) {
|
|
239
|
-
//
|
|
240
|
-
//
|
|
241
|
-
// `committedFactsFromOutcome` below (straight from the outcome, never normalized) —
|
|
242
|
-
// and the type carries a stated invariant that a non-id-shaped value is not rendered.
|
|
243
|
-
// A per-producer gate makes that invariant a thing each new producer must remember;
|
|
244
|
-
// gating the render makes it hold for producers that do not exist yet. Without it a
|
|
245
|
-
// poisoned `agent_id` in an otherwise contract-valid receipt reaches stdout verbatim,
|
|
246
|
-
// newlines and all.
|
|
247
|
-
const printable = (value) => /^[A-Za-z0-9._:@/+=-]{1,128}$/.test(value);
|
|
248
|
-
// `agentId` gets a TYPED gate, not the generic one, and the asymmetry is deliberate.
|
|
249
|
-
//
|
|
250
|
-
// Of the four fields, three are already tied to something this process sent: the
|
|
251
|
-
// receipt check requires `board_id`/`machine_id`/`agent_handle` to EQUAL the
|
|
252
|
-
// authorized tuple, so a contract-valid receipt cannot carry a surprise there — the
|
|
253
|
-
// validation does what region 1 achieves by construction. `agent_id` is the one field
|
|
254
|
-
// the contract constrains only as non-empty, so it is the one place a receipt can
|
|
255
|
-
// carry an arbitrary server-chosen string into an operator's terminal, including a
|
|
256
|
-
// value we ourselves sent (the invite code) echoed back.
|
|
257
|
-
//
|
|
258
|
-
// The schema declares it: `agents.id uuid primary key`. So a non-UUID `agent_id` is
|
|
259
|
-
// off-contract, and rendering it as an agent id would be rendering something this
|
|
260
|
-
// field cannot legitimately be. This is a type check derived from the contract, not a
|
|
261
|
-
// guess at what "looks like an id".
|
|
262
|
-
//
|
|
263
|
-
// Residual, stated rather than implied: an on-path attacker who can forge a
|
|
264
|
-
// contract-valid receipt can also supply a well-formed UUID. No client-side check
|
|
265
|
-
// closes that; it needs a signature over the response.
|
|
266
|
-
const isUuid = (value) => /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(value);
|
|
267
|
-
// THREE typed gates now, not one (Consiliency/message-board#402). `boardId` and
|
|
268
|
-
// `machineId` are OPERATOR-SUPPLIED on the indeterminate path — `localFacts` takes them
|
|
269
|
-
// from the intent, deliberately, so the message reports what the enrollment ASKED FOR —
|
|
270
|
-
// and the generic `printable` alphabet is a superset of base64url, which is what
|
|
271
|
-
// `create_invite_link` mints. A bounded invite code pasted into `--board-id` was therefore
|
|
272
|
-
// echoed here, on a path that needs no injected runner: an off-contract server answer is
|
|
273
|
-
// all it takes.
|
|
248
|
+
function renderIds(facts, origin) {
|
|
249
|
+
// FACTS ARE RENDERED BY WHERE THEY CAME FROM, NEVER BY WHAT THEY LOOK LIKE
|
|
250
|
+
// (Consiliency/message-board#404).
|
|
274
251
|
//
|
|
275
|
-
//
|
|
276
|
-
//
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
//
|
|
252
|
+
// This function used to hold three shape gates — a permissive `printable` alphabet and
|
|
253
|
+
// a UUID test — and both were the wrong instrument twice over. A shape gate on the
|
|
254
|
+
// INTENT arm bounds an echo of the operator's own argument instead of removing it: the
|
|
255
|
+
// alphabet is a superset of base64url, so a bounded invite code pasted into `--board-id`
|
|
256
|
+
// passed it, and `<host>-<code>` passed the handle's. A shape gate on the RECEIPT arm is
|
|
257
|
+
// a second, weaker copy of the `exact` check the value already passed, and it HID a
|
|
258
|
+
// legitimate id whose shape the schema does not actually pin.
|
|
280
259
|
//
|
|
281
|
-
//
|
|
282
|
-
//
|
|
283
|
-
//
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
["
|
|
288
|
-
["
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
260
|
+
// So there is no predicate here at all, and none can be reintroduced without failing
|
|
261
|
+
// B1a (a value hidden on the intent arm whatever its shape) or B2 (a value shown on the
|
|
262
|
+
// receipt arm whatever its shape).
|
|
263
|
+
const present = [
|
|
264
|
+
["agentId", facts.agentId],
|
|
265
|
+
["agentHandle", facts.agentHandle],
|
|
266
|
+
["boardId", facts.boardId],
|
|
267
|
+
["machineId", facts.machineId],
|
|
268
|
+
].filter(([, value]) => value !== "");
|
|
269
|
+
if (origin === "receipt") {
|
|
270
|
+
// The server's own answer, after `exact` required it to equal the authorized tuple —
|
|
271
|
+
// the same strings the success path prints in full.
|
|
272
|
+
return present.map(([key, value]) => `${key}=${value}`).join(", ");
|
|
273
|
+
}
|
|
274
|
+
// The operator's own arguments. The value is theirs already; what the message has to
|
|
275
|
+
// carry is WHICH enrollment and WHAT to verify against, and the flag names carry that.
|
|
276
|
+
// `agentId` and `keyId` are `""` on this arm by construction (`enroll.ts` localFacts),
|
|
277
|
+
// so they contribute nothing and are not in the map.
|
|
278
|
+
const FLAG_OF_INTENT_FACT = {
|
|
279
|
+
agentHandle: "--expected-agent-handle",
|
|
280
|
+
boardId: "--board-id",
|
|
281
|
+
machineId: "--machine-id",
|
|
282
|
+
};
|
|
283
|
+
return present.map(([key]) => FLAG_OF_INTENT_FACT[key]).filter((flag) => flag !== undefined).join(", ");
|
|
292
284
|
}
|
|
293
285
|
/**
|
|
294
286
|
* Raised when the server's answer was OFF-CONTRACT, so whether it committed is unknown.
|
|
@@ -303,9 +295,11 @@ class FleetIndeterminateError extends FleetSafeMessageError {
|
|
|
303
295
|
// Only the ids that actually survived. An all-empty list (`agentId=, agentHandle=`)
|
|
304
296
|
// is the shape this state exists to stop printing — it reads as data while carrying
|
|
305
297
|
// none, and on the off-contract path there is frequently nothing to show.
|
|
306
|
-
const rendered = renderIds(marker.facts);
|
|
298
|
+
const rendered = renderIds(marker.facts, marker.origin);
|
|
307
299
|
const observed = rendered
|
|
308
|
-
?
|
|
300
|
+
? (marker.origin === "receipt"
|
|
301
|
+
? ` Ids from the server's answer, to verify against: ${rendered}.`
|
|
302
|
+
: ` Verify against the values you passed as: ${rendered}.`)
|
|
309
303
|
: " Nothing about this enrollment could be corroborated, so there is no id here to verify against.";
|
|
310
304
|
super("fleet_onboarding_commit_indeterminate",
|
|
311
305
|
// Covers both shapes: an off-contract status (201/202/204), and a 200 that carried
|
|
@@ -340,7 +334,7 @@ async function throughFleetCommit(call) {
|
|
|
340
334
|
throw error;
|
|
341
335
|
throw marker.state === "indeterminate"
|
|
342
336
|
? new FleetIndeterminateError(marker, error)
|
|
343
|
-
: new FleetPostCommitError(marker.facts, error);
|
|
337
|
+
: new FleetPostCommitError(marker.facts, marker.origin, error);
|
|
344
338
|
}
|
|
345
339
|
}
|
|
346
340
|
/**
|
|
@@ -1512,6 +1506,27 @@ function addReadCommands(program, client, io) {
|
|
|
1512
1506
|
recipientAgentId: options.recipientAgentId,
|
|
1513
1507
|
limit: options.limit,
|
|
1514
1508
|
})));
|
|
1509
|
+
// WAKETIER0 (plans/WAKE-MULTIHARNESS-ROADMAP.md Phase 1). The terminal binding of
|
|
1510
|
+
// the universal baseline. `wake-recovery` is the primary name and `agent-wake-recovery`
|
|
1511
|
+
// the view-shaped alias, matching `agent-inbox`/`inbox` in the other direction: the
|
|
1512
|
+
// join text an agent is handed spells the short form, so that is the one that must
|
|
1513
|
+
// not drift.
|
|
1514
|
+
//
|
|
1515
|
+
// NO `--recipient-agent-id` OPTION, and its absence is the property (see the MCP
|
|
1516
|
+
// registration): the view self-scopes to current_agent_id() in SQL, so a
|
|
1517
|
+
// caller-supplied recipient could only ever contradict the session. Offering the
|
|
1518
|
+
// flag would invite an operator to "check another agent's" recovery set and get
|
|
1519
|
+
// their own rows back, silently.
|
|
1520
|
+
program
|
|
1521
|
+
.command("wake-recovery")
|
|
1522
|
+
.alias("agent-wake-recovery")
|
|
1523
|
+
.description("your OWN unhandled inbox items (Tier 0: a per-turn check, not a wake)")
|
|
1524
|
+
.option("--board-id <boardId>")
|
|
1525
|
+
.addOption(numberOption("--limit <limit>", "row limit"))
|
|
1526
|
+
.action((options) => runHandler(io, "agent_board.v_agent_wake_recovery", () => client.wakeRecovery({
|
|
1527
|
+
boardId: options.boardId,
|
|
1528
|
+
limit: options.limit,
|
|
1529
|
+
})));
|
|
1515
1530
|
program
|
|
1516
1531
|
.command("board-directory")
|
|
1517
1532
|
.option("--board-id <boardId>")
|
|
@@ -2395,7 +2410,7 @@ function addEnrollCommands(program, io, enrollment) {
|
|
|
2395
2410
|
// The non-fleet half of what `requiredOption` used to do. The fleet half is the
|
|
2396
2411
|
// collector's; this arm keeps its own guard because `enrollmentIntentFromCli`
|
|
2397
2412
|
// returns before the collector when `--fleet-onboarding` is absent.
|
|
2398
|
-
if (!options.fleetOnboarding && !options.slug
|
|
2413
|
+
if (!options.fleetOnboarding && !String(options.slug ?? "").trim()) {
|
|
2399
2414
|
throw new FleetPreflightError("enroll_run_slug_required", "enroll run requires --slug");
|
|
2400
2415
|
}
|
|
2401
2416
|
// ORDER IS THE CONTRACT on this path (#254). The intent is built and the whole
|
|
@@ -2587,7 +2602,7 @@ function addEnrollCommands(program, io, enrollment) {
|
|
|
2587
2602
|
// this file writes. Only the NAME of each comparison crosses; no operand does,
|
|
2588
2603
|
// because two of the five are a key reference and a whole template.
|
|
2589
2604
|
const divergent = [
|
|
2590
|
-
["--slug", options.slug.trim() !== pending.agentSlug],
|
|
2605
|
+
["--slug", String(options.slug ?? "").trim() !== pending.agentSlug],
|
|
2591
2606
|
["--runtime-output", options.runtimeOutput !== continuation.runtimeOutput],
|
|
2592
2607
|
["the keystore key reference", continuation.keyReference !== pending.keyReference],
|
|
2593
2608
|
["--publishable-key-field-reference", continuation.publishableKeyFieldReference !== pending.publishableKeyFieldReference],
|
package/dist/enroll_runtime.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { EnrollmentOutcome, FinalizedFleetHarnessTemplate, PendingFleetHarnessTemplate } from "@consiliency/agent-board-client";
|
|
2
|
+
import { type AuthoredCauseCode } from "@consiliency/agent-board-client";
|
|
2
3
|
import { type EnrollmentIntent, type PendingEnrollment, type PendingEnrollmentStore } from "@consiliency/agent-board-client";
|
|
3
4
|
export declare class EnrollRuntimeError extends Error {
|
|
4
5
|
code: string;
|
|
5
|
-
constructor(code:
|
|
6
|
+
constructor(code: AuthoredCauseCode, message: string);
|
|
6
7
|
}
|
|
7
8
|
/** Versioned, non-secret continuation for an interrupted fleet device flow. */
|
|
8
9
|
export interface FleetDeviceContinuation {
|
package/dist/enroll_runtime.js
CHANGED
|
@@ -8,7 +8,7 @@ import { constants as FS } from "node:fs";
|
|
|
8
8
|
import * as fs from "node:fs/promises";
|
|
9
9
|
import { homedir } from "node:os";
|
|
10
10
|
import { dirname, join } from "node:path";
|
|
11
|
-
import { validateFinalizedFleetHarnessTemplate } from "@consiliency/agent-board-client";
|
|
11
|
+
import { validateFinalizedFleetHarnessTemplate, markAuthoredCode } from "@consiliency/agent-board-client";
|
|
12
12
|
import { resolveEnrollmentDescriptor, } from "@consiliency/agent-board-client";
|
|
13
13
|
export class EnrollRuntimeError extends Error {
|
|
14
14
|
code;
|
|
@@ -16,6 +16,7 @@ export class EnrollRuntimeError extends Error {
|
|
|
16
16
|
super(message);
|
|
17
17
|
this.name = "EnrollRuntimeError";
|
|
18
18
|
this.code = code;
|
|
19
|
+
markAuthoredCode(this);
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
22
|
export class FleetDeviceContinuationStore {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@consiliency/agent-board-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.20.0",
|
|
4
4
|
"repository": "https://github.com/Consiliency/message-board.git",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"registry": "https://registry.npmjs.org"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@consiliency/agent-board-client": "1.
|
|
34
|
+
"@consiliency/agent-board-client": "1.30.0",
|
|
35
35
|
"commander": "^14.0.1"
|
|
36
36
|
},
|
|
37
37
|
"license": "Apache-2.0"
|