@consiliency/agent-board-cli 1.9.0 → 1.11.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 +123 -1
- package/dist/cli.js +968 -32
- package/dist/enroll_runtime.d.ts +67 -1
- package/dist/enroll_runtime.js +259 -1
- package/package.json +2 -2
package/dist/cli.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Command } from "commander";
|
|
2
|
-
import { type EnrollKeystore, type EnrollmentIntent, type PendingEnrollmentStore, type OAuthFetchLike, type FetchLike, type AgentJoinDeployment, type AgentJoinInstructions, type DeviceAuthorizationPrompt } from "@consiliency/agent-board-client";
|
|
2
|
+
import { type EnrollKeystore, type EnrollmentIntent, type FleetOnboardingIntent, type PendingEnrollmentStore, type OAuthFetchLike, type FetchLike, type AgentJoinDeployment, type AgentJoinInstructions, type DeviceAuthorizationPrompt } from "@consiliency/agent-board-client";
|
|
3
|
+
import { DevicePendingEnrollmentStore } from "./enroll_runtime.js";
|
|
3
4
|
type JsonObject = Record<string, unknown>;
|
|
4
5
|
export interface CliIo {
|
|
5
6
|
writeStdout(message: string): void;
|
|
@@ -38,6 +39,20 @@ interface ClientLike {
|
|
|
38
39
|
grantBoardRole(input: JsonObject): Promise<unknown>;
|
|
39
40
|
setBoardRoleGate(input: JsonObject): Promise<unknown>;
|
|
40
41
|
createInviteLink(input: JsonObject): Promise<unknown>;
|
|
42
|
+
createFleetOnboardingInvite?(input: {
|
|
43
|
+
boardId: string;
|
|
44
|
+
machineId: string;
|
|
45
|
+
harnessKind: string;
|
|
46
|
+
harnessLabel: string;
|
|
47
|
+
repoSlug: string;
|
|
48
|
+
repoFingerprint: string;
|
|
49
|
+
repoScopeRole: "worker" | "reviewer";
|
|
50
|
+
agentRole: "phase_worker" | "reviewer";
|
|
51
|
+
expectedAgentHandle: string;
|
|
52
|
+
maxUses?: number;
|
|
53
|
+
expiresAt?: string;
|
|
54
|
+
createdByAgentId?: string;
|
|
55
|
+
}): Promise<unknown>;
|
|
41
56
|
createInviteLinkWithInstructions(input: JsonObject, deployment: AgentJoinDeployment, board?: {
|
|
42
57
|
boardSlug?: string;
|
|
43
58
|
boardName?: string;
|
|
@@ -145,10 +160,37 @@ export interface EnrollmentCommandRunner {
|
|
|
145
160
|
requestedBoardScopes?: string[];
|
|
146
161
|
onDeviceAuthorization: (prompt: DeviceAuthorizationPrompt) => void | Promise<void>;
|
|
147
162
|
}): Promise<unknown>;
|
|
163
|
+
deviceBegin?(input: {
|
|
164
|
+
/** Optional caller-generated ID used to bind a companion non-secret continuation first. */
|
|
165
|
+
enrollmentId?: string;
|
|
166
|
+
slug: string;
|
|
167
|
+
intent: EnrollmentIntent;
|
|
168
|
+
agentKind?: string;
|
|
169
|
+
requestedScopes?: string[];
|
|
170
|
+
requestedBoardScopes?: string[];
|
|
171
|
+
}): Promise<{
|
|
172
|
+
enrollmentId: string;
|
|
173
|
+
prompt: DeviceAuthorizationPrompt;
|
|
174
|
+
}>;
|
|
175
|
+
deviceComplete?(input: {
|
|
176
|
+
enrollmentId: string;
|
|
177
|
+
expectedFleet?: {
|
|
178
|
+
intent: Omit<FleetOnboardingIntent, "inviteCode">;
|
|
179
|
+
keyReference: string;
|
|
180
|
+
slug: string;
|
|
181
|
+
};
|
|
182
|
+
/** Keep the secret continuation for a caller that must finish local materialization first. */
|
|
183
|
+
deletePending?: boolean;
|
|
184
|
+
}): Promise<unknown>;
|
|
185
|
+
deviceDeletePending?(input: {
|
|
186
|
+
enrollmentId: string;
|
|
187
|
+
}): Promise<void>;
|
|
148
188
|
}
|
|
149
189
|
export interface DefaultEnrollmentRunnerDeps {
|
|
150
190
|
/** Pending store bridging begin→complete. Default: FilePendingEnrollmentStore(env). */
|
|
151
191
|
store?: PendingEnrollmentStore;
|
|
192
|
+
/** Device-code state bridging deviceBegin→deviceComplete across CLI processes. */
|
|
193
|
+
deviceStore?: DevicePendingEnrollmentStore;
|
|
152
194
|
/** OAuth/enroll fetch. Default: nodeFetchAdapter over globalThis.fetch. */
|
|
153
195
|
fetch?: OAuthFetchLike;
|
|
154
196
|
/** Board-native fetch for the post-enroll SessionClient. Default: nodeFetchAdapter. */
|
|
@@ -179,6 +221,86 @@ export interface DefaultEnrollmentRunnerDeps {
|
|
|
179
221
|
};
|
|
180
222
|
}
|
|
181
223
|
export declare function defaultEnrollmentRunner(env?: NodeJS.ProcessEnv, deps?: DefaultEnrollmentRunnerDeps): EnrollmentCommandRunner;
|
|
224
|
+
/**
|
|
225
|
+
* How each field of a `FleetOnboardingIntent` is turned from an argv string into the value
|
|
226
|
+
* that goes on the wire and into the template (Consiliency/message-board#254).
|
|
227
|
+
*
|
|
228
|
+
* This map exists because the previous shape — nine literal `.trim()` calls repeated at two
|
|
229
|
+
* call sites — is the completeness failure CLAUDE.md rule 1 targets: #254 itself enumerated
|
|
230
|
+
* six of the nine, and got one of the six wrong. The map is TOTAL over the intent's string
|
|
231
|
+
* fields by construction, so a field added to `FleetOnboardingIntent` does not compile until
|
|
232
|
+
* someone dispositions it, and both call sites read their verb from here rather than
|
|
233
|
+
* restating it.
|
|
234
|
+
*
|
|
235
|
+
* Three dispositions, because there are three real behaviours and collapsing them is what
|
|
236
|
+
* hid the defect:
|
|
237
|
+
*
|
|
238
|
+
* - `gated` — the library REFUSES a prohibited character in this value rather than
|
|
239
|
+
* rewriting it, because the value is carried byte-exact into a template that runs on
|
|
240
|
+
* ANOTHER machine. A bare `.trim()` here deleted an edge-placed member of the refuse
|
|
241
|
+
* classes before `required()` could see it, so the library's raw-operand ordering (#215)
|
|
242
|
+
* was unreachable from the CLI. The verb is the library's own, imported.
|
|
243
|
+
* - `normalized` — the value is NOT carried verbatim: it is folded, or it is pinned by
|
|
244
|
+
* equality against a value derived from folded atoms. Trimming is right here, and
|
|
245
|
+
* removing it would regress an ordinary trailing space into a hard failure for no
|
|
246
|
+
* byte-exactness gain. Each one's claim is asserted positively in `cli.test.ts`, on the
|
|
247
|
+
* intent the runner RECEIVES — `expectedAgentHandle` and `inviteCode` are copied verbatim
|
|
248
|
+
* into the /enroll body, so "the output is clean" would not be evidence about them.
|
|
249
|
+
* - `vocabulary` — a closed set. A poisoned value cannot match a member, so it is refused
|
|
250
|
+
* by the existing pair check rather than by a presentation class.
|
|
251
|
+
*
|
|
252
|
+
* Each entry also states what a PROHIBITED character in that field does to the /enroll
|
|
253
|
+
* request — `wire`, which is the property `cli.test.ts` measures. It is stated per field
|
|
254
|
+
* rather than as one blanket claim because the blanket claim is false: an invite code is a
|
|
255
|
+
* bearer secret the server matches, so the refuse class is not policed on it.
|
|
256
|
+
*
|
|
257
|
+
* `verbatim` means exactly that — THE REFUSE CLASS IS NOT POLICED ON THIS FIELD — and not
|
|
258
|
+
* "untouched". Edges are still trimmed here as on every field (AC-6), so a prohibited
|
|
259
|
+
* character placed at an edge is erased and only an INTERIOR one survives to the wire. The
|
|
260
|
+
* label is worth stating precisely because the looser reading ("it travels as the operator
|
|
261
|
+
* typed it") stood in this comment and in three places in the plan, and was false at the
|
|
262
|
+
* edges in all four. `cli.test.ts` asserts the arm per PLACEMENT, which is the form that
|
|
263
|
+
* cannot be read two ways.
|
|
264
|
+
*
|
|
265
|
+
* Asserting a field's real arm is what makes an exemption evidence instead of prose.
|
|
266
|
+
*/
|
|
267
|
+
type FleetTupleDisposition = {
|
|
268
|
+
readonly kind: "gated";
|
|
269
|
+
readonly flag: string;
|
|
270
|
+
readonly label: string;
|
|
271
|
+
readonly wire: "refused";
|
|
272
|
+
} | {
|
|
273
|
+
readonly kind: "normalized";
|
|
274
|
+
readonly flag: string;
|
|
275
|
+
readonly why: string;
|
|
276
|
+
readonly wire: "clean" | "verbatim";
|
|
277
|
+
readonly normalize: (value: string) => string;
|
|
278
|
+
} | {
|
|
279
|
+
readonly kind: "vocabulary";
|
|
280
|
+
readonly flag?: string;
|
|
281
|
+
readonly why: string;
|
|
282
|
+
readonly wire: "refused";
|
|
283
|
+
};
|
|
284
|
+
/**
|
|
285
|
+
* The string-valued keys of `T` — the operator the totality claim above rests on, and the
|
|
286
|
+
* reason it is named and exported rather than written inline.
|
|
287
|
+
*
|
|
288
|
+
* `NonNullable` is load-bearing. `-?` strips optionality from the PRODUCED property, but
|
|
289
|
+
* the conditional tests the original indexed access, and for `field?: string` that is
|
|
290
|
+
* `string | undefined`, which does not extend `string`. Written without `NonNullable` this
|
|
291
|
+
* operator answers `never` for every optional member — so an optional string field added to
|
|
292
|
+
* the intent would vanish from the disposition map, from the census, and from the wire
|
|
293
|
+
* matrix, WITHOUT a compile error. Fail-open, and invisible until someone adds such a field.
|
|
294
|
+
*
|
|
295
|
+
* Latent rather than live today (`FleetOnboardingIntent` has no optional string members),
|
|
296
|
+
* which is exactly why it is pinned by a type-level probe in `cli.test.ts` — a guard whose
|
|
297
|
+
* failure mode is silence has to be tested against a shape that would trigger it.
|
|
298
|
+
*/
|
|
299
|
+
export type StringFieldsOf<T> = {
|
|
300
|
+
[K in keyof T]-?: NonNullable<T[K]> extends string ? K : never;
|
|
301
|
+
}[keyof T];
|
|
302
|
+
type FleetTupleField = StringFieldsOf<FleetOnboardingIntent>;
|
|
303
|
+
export declare const FLEET_TUPLE_DISPOSITION: Readonly<Record<FleetTupleField, FleetTupleDisposition>>;
|
|
182
304
|
export declare function createProgram(client: ClientLike, io: CliIo, enrollment?: EnrollmentCommandRunner): Command;
|
|
183
305
|
export declare function runCli(argv: string[], io?: CliIo, client?: ClientLike, enrollment?: EnrollmentCommandRunner): Promise<void>;
|
|
184
306
|
export {};
|