@kici-dev/orchestrator 0.14.2 → 0.15.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.
Files changed (49) hide show
  1. package/dist/__test-helpers__/peer-mutual-auth.d.ts +42 -0
  2. package/dist/agent/host-roster.d.ts +100 -37
  3. package/dist/app.d.ts +4 -2
  4. package/dist/cli/commands/host.d.ts +3 -0
  5. package/dist/cli/commands/source-manifest.d.ts +3 -3
  6. package/dist/cli/commands/source.d.ts +23 -0
  7. package/dist/cli/join.d.ts +2 -2
  8. package/dist/cli/kici-admin.d.ts +5 -0
  9. package/dist/cli/local-github-ingress-url.d.ts +6 -0
  10. package/dist/cli/root-option-routing.d.ts +46 -0
  11. package/dist/cli/webhook-url-notes.d.ts +15 -0
  12. package/dist/cli.js +1429 -885
  13. package/dist/cluster/coordinator-credential.d.ts +21 -0
  14. package/dist/cluster/index.d.ts +4 -4
  15. package/dist/cluster/join-client.d.ts +23 -21
  16. package/dist/cluster/join-handler.d.ts +24 -16
  17. package/dist/cluster/join-protocol-v2.d.ts +84 -0
  18. package/dist/cluster/join-token.d.ts +78 -56
  19. package/dist/cluster/peer-auth-coordinator.d.ts +16 -2
  20. package/dist/cluster/peer-client.d.ts +72 -4
  21. package/dist/cluster/peer-crypto.d.ts +60 -3
  22. package/dist/cluster/peer-discovery.d.ts +67 -0
  23. package/dist/cluster/peer-handler.d.ts +17 -5
  24. package/dist/cluster/peer-registry.d.ts +15 -1
  25. package/dist/config/schema.d.ts +14 -0
  26. package/dist/config/types.d.ts +4 -0
  27. package/dist/config.d.ts +9 -0
  28. package/dist/db/migrations/157_host_roster_identity_source.d.ts +21 -0
  29. package/dist/db/types.d.ts +16 -2
  30. package/dist/github-app-name-refresher/github-app-name-refresher.d.ts +25 -13
  31. package/dist/index.d.ts +1 -1
  32. package/dist/index.js +225 -81
  33. package/dist/providers/github/manifest.d.ts +58 -7
  34. package/dist/routes/admin-sources.d.ts +26 -23
  35. package/dist/routes/admin.d.ts +14 -17
  36. package/dist/routes/cluster-join.d.ts +13 -0
  37. package/dist/routes/github-webhook.d.ts +13 -11
  38. package/dist/scaler/bare-metal-backend.d.ts +42 -1
  39. package/dist/scaler/types.d.ts +7 -5
  40. package/dist/server.js +9040 -7631
  41. package/dist/sources/source-manager.d.ts +0 -24
  42. package/dist/sources/webhook-url-resolvers.d.ts +60 -0
  43. package/dist/standalone.js +9944 -8818
  44. package/dist/ws/dashboard-fleet-handler.d.ts +4 -3
  45. package/dist/ws/dashboard-fleet-write-handler.d.ts +7 -1
  46. package/dist/ws/platform-client.d.ts +18 -6
  47. package/installer-image-digests.json +3 -3
  48. package/package.json +4 -4
  49. package/sbom.spdx.json +53 -53
@@ -0,0 +1,42 @@
1
+ export declare function refTranscriptHash(serverPub: Buffer, serverNonce: Buffer, authSchemes: readonly string[], clientPub: Buffer): Buffer;
2
+ export declare function refClientProof(o: {
3
+ psk: Buffer;
4
+ th: Buffer;
5
+ mode: string;
6
+ instanceId: string;
7
+ role: string;
8
+ protocolVersion: number;
9
+ tokenRouting: string;
10
+ }): Buffer;
11
+ export declare function refServerProof(o: {
12
+ psk: Buffer;
13
+ th: Buffer;
14
+ clientProof: Buffer;
15
+ serverInstanceId: string;
16
+ grantedRole: string;
17
+ sessionCredential: string | null;
18
+ }): Buffer;
19
+ export declare function refAppKey(o: {
20
+ handshakeKey: Buffer;
21
+ psk: Buffer;
22
+ th: Buffer;
23
+ clientProof: Buffer;
24
+ serverProof: Buffer;
25
+ }): Buffer;
26
+ /** A join token in the production format, with its routing segment and stored hash. */
27
+ export declare function makeTestJoinToken(routing: {
28
+ orgId: string;
29
+ routingKey: string;
30
+ expiry: number;
31
+ role: 'coordinator' | 'worker';
32
+ }): {
33
+ token: string;
34
+ routingB64: string;
35
+ secretHex: string;
36
+ tokenHash: string;
37
+ };
38
+ /** The PSK a credential-mode peer proves with: the bytes of sha256(credential). */
39
+ export declare function credentialPsk(credential: string): Buffer;
40
+ /** The PSK a token-mode peer proves with: the bytes of the stored token hash. */
41
+ export declare function tokenPsk(tokenHash: string): Buffer;
42
+ //# sourceMappingURL=peer-mutual-auth.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import { type Kysely } from 'kysely';
2
- import { type CanonicalLabel, type HostInventoryEntry, type InventorySelector, type LabelMatcher } from '@kici-dev/engine';
3
- import type { Database, HostRosterRow } from '../db/types.js';
2
+ import { type CanonicalLabel, type FleetHostEntry, FleetHostWriteRefusal, type HostInventoryEntry, type InventorySelector, type LabelMatcher } from '@kici-dev/engine';
3
+ import { type Database, type HostRosterRow } from '../db/types.js';
4
4
  /** Typed host-vars bag carried by roster rows (`string | number | boolean`). */
5
5
  export type HostProperties = Record<string, string | number | boolean>;
6
6
  /**
@@ -10,15 +10,60 @@ export type HostProperties = Record<string, string | number | boolean>;
10
10
  */
11
11
  export declare const STAGED_AGENT_VERSION_KEY = "kici:staged-agent-version";
12
12
  /**
13
- * Drop every orchestrator-reserved `kici:`-namespaced key from an
14
- * agent-reported host-property bag. Agent-reported properties win the roster
15
- * shallow-merge, so without this an agent could FORGE reserved keys the
16
- * orchestrator trusts — the staged-version convergence gate and the
17
- * root-executed restart commands both read `kici:` keys. Only orchestrator
18
- * writes (`recordStagedVersion`) and operator declares (`declareStatic`) set
19
- * this namespace; a registering agent never may.
13
+ * True when a host label or property key is in the orchestrator-reserved
14
+ * `kici:` namespace. Trimmed and case-insensitive, matching how labels fold on
15
+ * read (`canonicalizeLabel`).
16
+ */
17
+ export declare function isReservedHostKey(key: string): boolean;
18
+ /**
19
+ * Drop every reserved `kici:` key from an agent-reported host-property bag.
20
+ * Agent-reported properties win the roster shallow-merge, and the staged-version
21
+ * convergence gate and the restart commands the re-stage runs over SSH both
22
+ * read `kici:` keys, so a registering agent must never set them. Reserved keys
23
+ * come only from orchestrator code (`recordStagedVersion`) and a local
24
+ * `kici-admin host declare`.
20
25
  */
21
26
  export declare function stripReservedProperties(props: HostProperties): HostProperties;
27
+ /** Who is writing a static host declaration or removal. */
28
+ export declare enum HostWriteAuthority {
29
+ /** A local `kici-admin` declare or remove. */
30
+ operator = "operator",
31
+ /** A Platform-relayed dashboard write. The default. */
32
+ platform = "platform"
33
+ }
34
+ /** A host write refused because of the writer's authority. */
35
+ export declare class HostWriteRefusedError extends Error {
36
+ readonly code: FleetHostWriteRefusal;
37
+ readonly detail: string;
38
+ constructor(code: FleetHostWriteRefusal, detail: string, message: string);
39
+ }
40
+ /** A Platform write named a reserved `kici:` label or property key. */
41
+ export declare class ReservedHostKeyError extends HostWriteRefusedError {
42
+ readonly keys: string[];
43
+ constructor(keys: string[]);
44
+ }
45
+ /** A Platform declare named a host that already exists. */
46
+ export declare class HostExistsError extends HostWriteRefusedError {
47
+ constructor(agentId: string);
48
+ }
49
+ /** A Platform remove named a host an agent or operator confirmed. */
50
+ export declare class HostConfirmedError extends HostWriteRefusedError {
51
+ constructor(agentId: string);
52
+ }
53
+ /** Input of {@link HostRosterStore.declareStatic}. */
54
+ export interface DeclareStaticInput {
55
+ agentId: string;
56
+ labels?: string[];
57
+ hostname?: string;
58
+ properties?: HostProperties;
59
+ address?: string;
60
+ sshUser?: string;
61
+ sshPort?: number;
62
+ sshKeySecret?: string;
63
+ s3Reachable?: boolean;
64
+ /** Who is writing. Omitted ⇒ `platform`, the most restricted. */
65
+ authority?: HostWriteAuthority;
66
+ }
22
67
  /**
23
68
  * Pre-agent reach metadata for a declared host — how to SSH to it for bootstrap
24
69
  * bring-up before it has a KiCI agent. All fields nullable: a host with no reach
@@ -144,31 +189,33 @@ export declare class HostRosterStore {
144
189
  /** Coarse heartbeat stamp — same owner-guard as markDisconnected. */
145
190
  stampLastSeen(agentId: string, instanceId: string): Promise<void>;
146
191
  /**
147
- * Operator pre-declare of a static host. A re-declare of an existing agent_id
148
- * converges the operator-owned columns (labels, hostname, reach,
149
- * host_properties) to the newly-declared values while preserving the
150
- * agent-reported liveness/identity columns (connected_instance_id, last_seen,
151
- * platform, arch, lifecycle_class, token_id, reboot_pending_until). The
152
- * optional reach fields (`address`/`sshUser`/`sshPort`/`sshKeySecret`) carry
153
- * how to SSH to the host for bootstrap bring-up. Each operator field is
154
- * preserve-on-omit: an omitted field keeps the existing column value.
155
- *
156
- * Returns `{ created: true }` when the declare inserted a new row,
157
- * `{ created: false }` when it converged an existing one.
192
+ * Declare a static host. Under `operator` authority (a local `kici-admin`),
193
+ * it inserts or converges the row; under `platform` authority (a dashboard
194
+ * write, the default) it only creates a new, unconfirmed row. Returns
195
+ * `{ created: true }` when the declare inserted the row.
158
196
  */
159
- declareStatic(input: {
160
- agentId: string;
161
- labels?: string[];
162
- hostname?: string;
163
- properties?: HostProperties;
164
- address?: string;
165
- sshUser?: string;
166
- sshPort?: number;
167
- sshKeySecret?: string;
168
- s3Reachable?: boolean;
169
- }): Promise<{
197
+ declareStatic(input: DeclareStaticInput): Promise<{
170
198
  created: boolean;
171
199
  }>;
200
+ /**
201
+ * A Platform declare: create a new `platform` row, never touch an existing
202
+ * one. Reserved `kici:` labels or properties refuse the whole write before
203
+ * any SQL, and the insert-or-nothing statement leaves no check-then-write race.
204
+ */
205
+ private createPlaceholder;
206
+ /**
207
+ * An operator declare. A re-declare converges the operator-owned columns
208
+ * (labels, hostname, reach, host_properties) and preserves the agent-reported
209
+ * liveness and identity columns (connected_instance_id, last_seen, platform,
210
+ * arch, lifecycle_class, token_id, reboot_pending_until). Each operator field
211
+ * is preserve-on-omit, and properties shallow-merge — except on a row a
212
+ * dashboard declare created: there the operator's values replace labels,
213
+ * hostname and properties outright, so no Platform-chosen value survives the
214
+ * confirmation, and the row becomes `operator`. An `agent` row stays `agent`.
215
+ * PostgreSQL evaluates every SET expression against the existing row, so each
216
+ * CASE reads the source before this statement changes it.
217
+ */
218
+ private declareAsOperator;
172
219
  /**
173
220
  * Read a host's pre-agent reach metadata. Returns null when the host is not
174
221
  * in the roster; a host declared without reach fields reads back with nulls.
@@ -181,12 +228,14 @@ export declare class HostRosterStore {
181
228
  * reserved key so the convergence gate can compare it against the target
182
229
  * INDEPENDENTLY of the agent's own self-reported bundle version (two payloads
183
230
  * can carry the same self-report but different staged keys). Shallow-merged, so
184
- * it survives agent re-register (the agent never reports this reserved key).
231
+ * it survives an agent re-register (the agent's reserved keys are stripped).
185
232
  */
186
233
  recordStagedVersion(agentId: string, version: string): Promise<void>;
187
234
  /** Read a host's recorded staged agent-payload version, or null when never staged. */
188
235
  getStagedVersion(agentId: string): Promise<string | null>;
189
236
  listAll(): Promise<HostRosterRow[]>;
237
+ /** Every confirmed roster row (agent- or operator-set identity), by agent id. */
238
+ private listConfirmed;
190
239
  /**
191
240
  * Resolve EVERY roster host matching a label predicate (OR-of-AND include
192
241
  * groups, minus exclude labels), tagged with its derived status. Returns
@@ -232,22 +281,36 @@ export declare class HostRosterStore {
232
281
  * Query the roster as canonical {@link HostInventoryEntry} records. With a
233
282
  * selector, reuses `findMatching`'s label filtering (server-side, glob/regex);
234
283
  * property filtering is done client-side in the workflow. Omit the selector ⇒
235
- * every host.
284
+ * every host. Unconfirmed rows a dashboard declare created are omitted.
236
285
  */
237
286
  queryInventory(selector: InventorySelector | undefined, graceMs: number): Promise<HostInventoryEntry[]>;
238
- /** Single-host inventory lookup; null when the agent is not in the roster. */
287
+ /** Single-host inventory lookup; null when the agent is absent or unconfirmed. */
239
288
  getInventory(agentId: string, graceMs: number): Promise<HostInventoryEntry | null>;
289
+ /** A roster row as the dashboard sees it: the inventory entry plus `confirmed`. */
290
+ toFleetEntry(row: HostRosterRow, graceMs: number): FleetHostEntry;
291
+ /** Every roster host for the dashboard, unconfirmed placeholders included. */
292
+ listFleetHosts(graceMs: number): Promise<FleetHostEntry[]>;
293
+ /** One roster host for the dashboard, or null when the agent id has no row. */
294
+ getFleetHost(agentId: string, graceMs: number): Promise<FleetHostEntry | null>;
240
295
  /**
241
296
  * Count `static` (declared) hosts whose derived status is `unreachable` —
242
297
  * the "declared-but-absent" alarm population. Reuses the single-source
243
298
  * {@link deriveHostStatus} so the count never diverges from what
244
299
  * `kici-admin host list` shows. A not-currently-connected static host reads
245
300
  * `unreachable` regardless of grace (only the connected-but-stale case
246
- * depends on `graceMs`).
301
+ * depends on `graceMs`). An unconfirmed dashboard-created row never raises
302
+ * the alarm.
247
303
  */
248
304
  countStaticUnreachable(graceMs: number): Promise<number>;
249
- /** Remove a host from the roster by agent id. Returns rows deleted. */
250
- removeStatic(agentId: string): Promise<number>;
305
+ /**
306
+ * Remove a host from the roster by agent id. Returns rows deleted (0 when no
307
+ * row matches). Under `platform` authority (the default) only an unconfirmed
308
+ * row a dashboard declare created is removed; a confirmed row throws
309
+ * {@link HostConfirmedError}.
310
+ */
311
+ removeStatic(agentId: string, opts?: {
312
+ authority?: HostWriteAuthority;
313
+ }): Promise<number>;
251
314
  /** Delete ephemeral rows whose last_seen is older than ttl. Returns count. */
252
315
  reapEphemeralPastTtl(ttlMs: number): Promise<number>;
253
316
  /**
package/dist/app.d.ts CHANGED
@@ -278,6 +278,8 @@ export interface AppDependencies {
278
278
  * pre-flight (before any App exists). Passed into the admin source routes.
279
279
  */
280
280
  resolveGithubWebhookUrl?: AdminRouteDeps['resolveGithubWebhookUrl'];
281
+ /** Builds the direct-ingress URL for `source list`. Passed into the admin source routes. */
282
+ resolveSourceIngressUrl?: AdminRouteDeps['resolveSourceIngressUrl'];
281
283
  /** Config admin API route dependencies. Optional -- mounted when config management is available. */
282
284
  configRouteDeps?: ConfigRouteDeps;
283
285
  /** Event router for internal event delivery. Optional -- if not set, event routing is inactive. */
@@ -367,8 +369,8 @@ export interface AppDependencies {
367
369
  sendToPeer: (targetInstanceId: string, msg: PeerToPeerMessage) => boolean;
368
370
  getConnectionCount: () => number;
369
371
  };
370
- /** Optional join handler for direct peer join requests. */
371
- onJoinRequest?: (msg: import('@kici-dev/engine').JoinRequest) => Promise<import('@kici-dev/engine').JoinResponse>;
372
+ /** Optional join handler for direct peer join requests; answers any join.request frame. */
373
+ onJoinRequest?: (raw: unknown) => Promise<import('@kici-dev/engine').JoinResponse>;
372
374
  /** Optional callback when agent inventory changes (connect/disconnect). Triggers peer heartbeat broadcast. */
373
375
  onAgentInventoryChanged?: () => void;
374
376
  /** Run coordinator for multi-orch claim/reroute. Optional -- if not set, jobs dispatch locally. */
@@ -4,9 +4,12 @@
4
4
  * host list List all roster hosts with derived status
5
5
  * host get Show one roster host
6
6
  * host declare Pre-declare a static host before its agent connects
7
+ * host remove Remove a host from the roster
7
8
  *
8
9
  * Reads/writes the orchestrator DB directly (via withDb), so this lives in
9
10
  * kici-admin — never in the public `kici` or the Platform `kici-platform-admin`.
11
+ * Writes run as the operator: they may set reserved `kici:` labels and
12
+ * properties, change any host, and confirm a host the dashboard created.
10
13
  */
11
14
  import type { Command } from 'commander';
12
15
  export declare function registerHostCommands(program: Command): void;
@@ -19,9 +19,9 @@ export interface ManifestSetupOptions {
19
19
  githubOrg?: string;
20
20
  /**
21
21
  * Self-hosted webhook URL override. When set, it is baked verbatim into the
22
- * App manifest's `hook_attributes.url` and the platform-mode webhook-URL
23
- * resolution is skipped — so the flow works even where the auto-resolved KiCI
24
- * platform URL is unavailable. KiCI adds no ingress at this URL; the operator
22
+ * App manifest's `hook_attributes.url` instead of the URL the orchestrator
23
+ * resolves for its mode — so the flow works even where that URL is
24
+ * unavailable. KiCI adds no ingress at this URL; the operator
25
25
  * owns delivery. Advanced/self-hosted only.
26
26
  */
27
27
  webhookUrl?: string;
@@ -21,6 +21,28 @@
21
21
  */
22
22
  import type { Command } from 'commander';
23
23
  import type { AdminApiClient } from '../api-client.js';
24
+ /** Structural row a listed generic/local source exposes for text rendering.
25
+ * Both the HTTP `GenericSourceResponse` and the DB `GenericWebhookSource`
26
+ * satisfy it, so `renderSourceListText` renders either transport's output. */
27
+ interface ListableGenericRow {
28
+ id: string;
29
+ name: string;
30
+ routing_key: string;
31
+ enabled: boolean;
32
+ deleted_at?: unknown;
33
+ }
34
+ /** Render the human-readable `source list` output shared by the HTTP and the
35
+ * direct-DB branches. `hasOrg` mirrors whether `--org` was passed (generic
36
+ * sources are only listed for a specific org). `opts.directDb` marks a direct
37
+ * DB read, which has no ingress URLs to print. */
38
+ export declare function renderSourceListText(githubSources: Array<{
39
+ routingKey: string;
40
+ name: string;
41
+ provider: string;
42
+ ingressUrl?: string | null;
43
+ }>, genericSources: ListableGenericRow[], hasOrg: boolean, opts: {
44
+ directDb: boolean;
45
+ }): void;
24
46
  /** Error shown when both the private key and the webhook secret ask for stdin. */
25
47
  export declare const BOTH_STDIN_ERROR = "cannot read both the private key and the webhook secret from stdin \u2014 use @file or --from-env for one of them";
26
48
  /**
@@ -34,4 +56,5 @@ export declare function resolveWebhookSecret(opts: {
34
56
  privateKeyFromStdin: boolean;
35
57
  }, readStdin?: () => Promise<string>): Promise<string | undefined>;
36
58
  export declare function registerSourceCommands(program: Command, getClient: () => AdminApiClient): void;
59
+ export {};
37
60
  //# sourceMappingURL=source.d.ts.map
@@ -2,8 +2,8 @@
2
2
  * `kici-admin join` command.
3
3
  *
4
4
  * Bootstraps a new orchestrator by connecting to an existing cluster via
5
- * Platform relay or direct peer, receiving an encrypted config bundle, and
6
- * writing an env file the orchestrator boots from.
5
+ * Platform relay or direct peer, receiving the configuration bundle sealed to
6
+ * this host, and writing an env file the orchestrator boots from.
7
7
  *
8
8
  * Usage:
9
9
  * kici-admin join --token kici_join_v1.xxx.yyy --platform wss://api.kici.dev/ws --api-key KEY
@@ -8,6 +8,11 @@
8
8
  * Global options:
9
9
  * --url / -u Orchestrator URL (env: KICI_ADMIN_URL, default: http://localhost:8080)
10
10
  * --token / -t Admin API token (env: KICI_ADMIN_TOKEN, required)
11
+ * -V / --cli-version / --version Print the CLI version (--version only before a command)
12
+ *
13
+ * A command that declares its own option under one of these flags (for
14
+ * example `orchestrator upgrade --url`) owns that flag after its name; see
15
+ * `root-option-routing.ts`.
11
16
  */
12
17
  import { Command } from 'commander';
13
18
  /**
@@ -5,4 +5,10 @@
5
5
  * KICI_WEBHOOK_PUBLIC_URL" note instead of a fabricated URL).
6
6
  */
7
7
  export declare function buildLocalGithubIngressUrl(webhookPublicUrl: string | undefined, orgId: string, sourceId: string): string | null;
8
+ /**
9
+ * Build the orchestrator's OWN org-scoped GitHub App ingress URL
10
+ * (`<base>/webhook/<orgId>/github`), served by the org-scoped direct route.
11
+ * Null when no public base is configured.
12
+ */
13
+ export declare function buildLocalGithubAppIngressUrl(webhookPublicUrl: string | undefined, orgId: string): string | null;
8
14
  //# sourceMappingURL=local-github-ingress-url.d.ts.map
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Decide which command each root-option token in a kici-admin argv belongs to.
3
+ *
4
+ * Commander matches a program option anywhere in argv: the root's own
5
+ * `parseOptions` consumes `-u, --url`, `-t, --token` and `-V, --cli-version`
6
+ * even after a command name. That lets an operator put a global option after
7
+ * the command (`kici-admin runs list -u <url>`), but on its own it would also
8
+ * take an option away from any command that declares one with the same flag,
9
+ * such as `orchestrator upgrade --url <archive-url>` or
10
+ * `join --token <join-token>`.
11
+ *
12
+ * {@link routeRootArgs} prepares the argv for the root's `parseOptions`:
13
+ *
14
+ * - A flag that the command being run declares, and that also names a root
15
+ * option, belongs to that command when it comes after the command's name. It
16
+ * is hidden from the root behind an opaque stand-in token, which the root
17
+ * classifies as an unknown option and so hands on to the subcommand; the
18
+ * stand-ins are mapped back to the original tokens before the subcommand
19
+ * parses them.
20
+ * - `--version` before the first command name is the root's version flag. The
21
+ * root cannot register `--version` itself (`orchestrator upgrade` and
22
+ * `agent upgrade` own `--version <version>`), so it is rewritten to the
23
+ * registered `--cli-version`. After a command name it is left alone.
24
+ *
25
+ * - The value of a command option, when it is shaped like an option (`-uP4ss`,
26
+ * `--url`), is hidden from the root the same way, so the root does not read
27
+ * it as one of its own flags.
28
+ *
29
+ * Every other token reaches the root unchanged, so a root option after a
30
+ * command that does not declare that flag still sets the global option.
31
+ */
32
+ import type { Command } from 'commander';
33
+ /** The flag the root registers its version option under. */
34
+ export declare const ROOT_VERSION_FLAG = "--cli-version";
35
+ /** The root's argv, routed, and the map from each stand-in back to its token. */
36
+ export interface RoutedRootArgs {
37
+ readonly args: string[];
38
+ /** Map a token from the root's parse result back to the original token. */
39
+ readonly restore: (token: string) => string;
40
+ }
41
+ /**
42
+ * Route a kici-admin argv (the user arguments, without `node` and the script)
43
+ * for the root command's `parseOptions`. See the module comment.
44
+ */
45
+ export declare function routeRootArgs(root: Command, args: readonly string[]): RoutedRootArgs;
46
+ //# sourceMappingURL=root-option-routing.d.ts.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * The text the CLI prints when the orchestrator returns no webhook URL. Shared
3
+ * by `kici-admin source add` and the manifest setup flow, so each
4
+ * `WebhookUrlNote` reads the same in both.
5
+ */
6
+ import { WebhookUrlNote } from '../sources/webhook-url-resolvers.js';
7
+ /**
8
+ * Short reason shown in `(unavailable — <reason>)` when no webhook URL could be
9
+ * resolved. Takes a plain string too, because an orchestrator of another
10
+ * version can send a note this CLI does not know.
11
+ */
12
+ export declare function webhookNoteReason(note: WebhookUrlNote | string | undefined): string;
13
+ /** Actionable next-step hint paired with {@link webhookNoteReason}. */
14
+ export declare function webhookNoteHint(note: WebhookUrlNote | string | undefined): string;
15
+ //# sourceMappingURL=webhook-url-notes.d.ts.map