@kici-dev/orchestrator 0.14.2 → 0.16.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 (176) hide show
  1. package/dist/__test-helpers__/peer-mutual-auth.d.ts +42 -0
  2. package/dist/__test-helpers__/scratch-db.d.ts +16 -0
  3. package/dist/agent/host-roster.d.ts +100 -37
  4. package/dist/agent/registry.d.ts +1 -8
  5. package/dist/app-on-error.d.ts +1 -1
  6. package/dist/app.d.ts +4 -2
  7. package/dist/artifacts/artifact-store.d.ts +0 -2
  8. package/dist/audit/access-log.d.ts +1 -1
  9. package/dist/cache/source-cache.d.ts +1 -1
  10. package/dist/cache/user-cache.d.ts +0 -28
  11. package/dist/cli/api-client.d.ts +27 -1
  12. package/dist/cli/commands/access-log.d.ts +1 -1
  13. package/dist/cli/commands/cold-store-impl.d.ts +7 -84
  14. package/dist/cli/commands/db.d.ts +1 -0
  15. package/dist/cli/commands/host.d.ts +3 -0
  16. package/dist/cli/commands/orchestrator-service/status.d.ts +2 -0
  17. package/dist/cli/commands/org.d.ts +12 -0
  18. package/dist/cli/commands/scaler.d.ts +14 -0
  19. package/dist/cli/commands/secret.d.ts +1 -45
  20. package/dist/cli/commands/service-health.d.ts +21 -13
  21. package/dist/cli/commands/shared/cli-action.d.ts +17 -0
  22. package/dist/cli/commands/shared/db.d.ts +5 -5
  23. package/dist/cli/commands/shared/org-id.d.ts +5 -0
  24. package/dist/cli/commands/shared/service-verbs.d.ts +19 -0
  25. package/dist/cli/commands/shared/table.d.ts +3 -0
  26. package/dist/cli/commands/shared/unbound-context-warning.d.ts +2 -22
  27. package/dist/cli/commands/source-manifest.d.ts +3 -3
  28. package/dist/cli/commands/source.d.ts +23 -0
  29. package/dist/cli/commands/trust-policy.d.ts +7 -31
  30. package/dist/cli/join.d.ts +2 -2
  31. package/dist/cli/kici-admin.d.ts +6 -1
  32. package/dist/cli/local-github-ingress-url.d.ts +6 -0
  33. package/dist/cli/root-option-routing.d.ts +46 -0
  34. package/dist/cli/webhook-url-notes.d.ts +15 -0
  35. package/dist/cli.js +10667 -8461
  36. package/dist/cluster/coordinator-credential.d.ts +21 -0
  37. package/dist/cluster/coordinator.d.ts +2 -2
  38. package/dist/cluster/index.d.ts +4 -4
  39. package/dist/cluster/join-client.d.ts +23 -21
  40. package/dist/cluster/join-handler.d.ts +24 -16
  41. package/dist/cluster/join-protocol-v2.d.ts +84 -0
  42. package/dist/cluster/join-token.d.ts +78 -56
  43. package/dist/cluster/peer-auth-coordinator.d.ts +16 -2
  44. package/dist/cluster/peer-client.d.ts +99 -5
  45. package/dist/cluster/peer-crypto.d.ts +60 -3
  46. package/dist/cluster/peer-discovery.d.ts +67 -0
  47. package/dist/cluster/peer-forget.d.ts +4 -9
  48. package/dist/cluster/peer-handler.d.ts +28 -6
  49. package/dist/cluster/peer-registry.d.ts +15 -1
  50. package/dist/cluster/peer-request-waiters.d.ts +26 -0
  51. package/dist/cluster/scaler-orphans-peer.d.ts +4 -9
  52. package/dist/cluster/scaler-reload-fanout.d.ts +29 -0
  53. package/dist/cluster/scaler-reload-peer.d.ts +16 -0
  54. package/dist/cluster/worker-cluster-settings.d.ts +1 -0
  55. package/dist/cold-store/load-access-log-range.d.ts +3 -3
  56. package/dist/cold-store/tables/access-log.d.ts +4 -12
  57. package/dist/cold-store/tables/event-log.d.ts +8 -19
  58. package/dist/cold-store/tables/execution-jobs.d.ts +7 -24
  59. package/dist/cold-store/tables/execution-runs.d.ts +6 -20
  60. package/dist/cold-store/tables/execution-steps.d.ts +8 -26
  61. package/dist/cold-store/tables/secret-audit-log.d.ts +4 -11
  62. package/dist/config/env-overlay.d.ts +3 -8
  63. package/dist/config/reload.d.ts +9 -2
  64. package/dist/config/schema.d.ts +16 -2
  65. package/dist/config/types.d.ts +6 -2
  66. package/dist/config.d.ts +22 -17
  67. package/dist/contexts/held-runs.d.ts +3 -6
  68. package/dist/dashboard/cursor.d.ts +12 -0
  69. package/dist/dashboard/handler.d.ts +5 -12
  70. package/dist/db/deferred-index-build.d.ts +42 -0
  71. package/dist/db/deferred-indexes.d.ts +3 -37
  72. package/dist/db/migrations/100_held_runs_hold_type_vocabulary.d.ts +3 -5
  73. package/dist/db/migrations/157_host_roster_identity_source.d.ts +21 -0
  74. package/dist/db/migrations/158_normalize_legacy_values.d.ts +4 -0
  75. package/dist/db/repos/org-ids-repo.d.ts +87 -0
  76. package/dist/db/schema-snapshot.generated.d.ts +3 -0
  77. package/dist/db/types.d.ts +21 -24
  78. package/dist/fault-injection-types.d.ts +0 -6
  79. package/dist/git/dispatch-git-auth.d.ts +6 -12
  80. package/dist/github-app-name-refresher/github-app-name-refresher.d.ts +25 -13
  81. package/dist/helpers/json.d.ts +3 -0
  82. package/dist/index.d.ts +1 -1
  83. package/dist/index.js +357 -216
  84. package/dist/metrics/prometheus.d.ts +0 -5
  85. package/dist/oidc/id-token-claims.d.ts +1 -1
  86. package/dist/oidc/resolve-signer.d.ts +2 -4
  87. package/dist/orchestrator-core.d.ts +10 -3
  88. package/dist/pipeline/global-eval-round.d.ts +2 -26
  89. package/dist/pipeline/install-secrets-resolver.d.ts +0 -3
  90. package/dist/pipeline/manual-schedule.d.ts +1 -7
  91. package/dist/provenance/dispatch-context.d.ts +5 -7
  92. package/dist/provenance/pending-attestations-repo.d.ts +1 -1
  93. package/dist/provenance/trust-root.d.ts +4 -5
  94. package/dist/provenance/verify-deferred-capture.d.ts +3 -3
  95. package/dist/provider-registry.d.ts +13 -40
  96. package/dist/providers/github/manifest.d.ts +58 -7
  97. package/dist/providers/universal-git/ssh-auth.d.ts +0 -5
  98. package/dist/reporting/check-run-reporter.d.ts +8 -21
  99. package/dist/reporting/check-run-summary.d.ts +2 -2
  100. package/dist/reporting/execution-tracker.d.ts +1 -1
  101. package/dist/reporting/log-chunk-sink.d.ts +1 -1
  102. package/dist/reporting/run-summary-fields.d.ts +25 -0
  103. package/dist/reporting/s3-log-storage.d.ts +2 -2
  104. package/dist/routes/admin-access-log.d.ts +2 -9
  105. package/dist/routes/admin-backends.d.ts +2 -9
  106. package/dist/routes/admin-cluster-name.d.ts +2 -8
  107. package/dist/routes/admin-cluster-settings.d.ts +2 -8
  108. package/dist/routes/admin-config.d.ts +0 -3
  109. package/dist/routes/admin-contexts.d.ts +3 -11
  110. package/dist/routes/admin-db.d.ts +2 -9
  111. package/dist/routes/admin-env.d.ts +33 -0
  112. package/dist/routes/admin-event-dlq.d.ts +2 -9
  113. package/dist/routes/admin-event-inspect.d.ts +2 -9
  114. package/dist/routes/admin-event-log.d.ts +2 -9
  115. package/dist/routes/admin-events.d.ts +3 -13
  116. package/dist/routes/admin-held-runs.d.ts +2 -8
  117. package/dist/routes/admin-list-limit.d.ts +3 -0
  118. package/dist/routes/admin-maintenance.d.ts +2 -9
  119. package/dist/routes/admin-orchestrator-drain.d.ts +2 -9
  120. package/dist/routes/admin-org-settings.d.ts +2 -8
  121. package/dist/routes/admin-orgs.d.ts +27 -0
  122. package/dist/routes/admin-peer-forget.d.ts +2 -9
  123. package/dist/routes/admin-queue-execution.d.ts +3 -10
  124. package/dist/routes/admin-registrations.d.ts +3 -14
  125. package/dist/routes/admin-runs.d.ts +3 -14
  126. package/dist/routes/admin-scaler-orphans.d.ts +2 -9
  127. package/dist/routes/admin-scaler-reload.d.ts +41 -0
  128. package/dist/routes/admin-scheduled-jobs.d.ts +2 -9
  129. package/dist/routes/admin-signing-keys.d.ts +2 -9
  130. package/dist/routes/admin-sources.d.ts +28 -32
  131. package/dist/routes/admin-trust-policy.d.ts +2 -8
  132. package/dist/routes/admin.d.ts +29 -30
  133. package/dist/routes/cluster-join.d.ts +13 -0
  134. package/dist/routes/github-webhook.d.ts +13 -11
  135. package/dist/scaler/bare-metal-backend.d.ts +42 -1
  136. package/dist/scaler/config.d.ts +12 -84
  137. package/dist/scaler/file-reload.d.ts +48 -0
  138. package/dist/scaler/manager.d.ts +47 -33
  139. package/dist/scaler/scaler-state-store.d.ts +5 -0
  140. package/dist/scaler/types.d.ts +8 -9
  141. package/dist/secrets/job-secret-gate.d.ts +2 -5
  142. package/dist/secrets/secret-resolver.d.ts +2 -4
  143. package/dist/security/trust-policy-gate.d.ts +0 -4
  144. package/dist/server.d.ts +6 -17
  145. package/dist/server.js +10933 -10836
  146. package/dist/sources/source-manager.d.ts +0 -24
  147. package/dist/sources/webhook-url-resolvers.d.ts +60 -0
  148. package/dist/standalone.js +10457 -10060
  149. package/dist/worker/reroute-dispatch.d.ts +1 -0
  150. package/dist/worker/reroute-spawn-control.d.ts +1 -3
  151. package/dist/worker-core.d.ts +9 -2
  152. package/dist/ws/agent-handler.d.ts +3 -3
  153. package/dist/ws/dashboard-access.d.ts +57 -0
  154. package/dist/ws/dashboard-backends-handler.d.ts +1 -6
  155. package/dist/ws/dashboard-context-handler.d.ts +10 -15
  156. package/dist/ws/dashboard-fleet-handler.d.ts +4 -3
  157. package/dist/ws/dashboard-fleet-write-handler.d.ts +6 -5
  158. package/dist/ws/dashboard-global-workflows-handler.d.ts +1 -6
  159. package/dist/ws/dashboard-registrations-handler.d.ts +1 -7
  160. package/dist/ws/platform-client.d.ts +94 -327
  161. package/installer-image-digests.json +3 -3
  162. package/package.json +4 -4
  163. package/sbom.spdx.json +53 -53
  164. package/dist/cache/legacy-prefixes.d.ts +0 -19
  165. package/dist/cli/commands/agent-service/logs.d.ts +0 -14
  166. package/dist/cli/commands/agent-service/restart.d.ts +0 -12
  167. package/dist/cli/commands/agent-service/start.d.ts +0 -12
  168. package/dist/cli/commands/agent-service/stop.d.ts +0 -12
  169. package/dist/cli/commands/agent-service/uninstall.d.ts +0 -13
  170. package/dist/cli/commands/cache.d.ts +0 -51
  171. package/dist/cli/commands/orchestrator-service/logs.d.ts +0 -14
  172. package/dist/cli/commands/orchestrator-service/restart.d.ts +0 -12
  173. package/dist/cli/commands/orchestrator-service/start.d.ts +0 -12
  174. package/dist/cli/commands/orchestrator-service/stop.d.ts +0 -12
  175. package/dist/cli/commands/orchestrator-service/uninstall.d.ts +0 -13
  176. package/dist/git/inherited-secret.d.ts +0 -29
@@ -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
@@ -0,0 +1,16 @@
1
+ /** Throwaway PostgreSQL databases for DB-gated tests, dropped by `cleanup`. */
2
+ import pg from 'pg';
3
+ import { Kysely } from 'kysely';
4
+ export interface ScratchDb {
5
+ url: string;
6
+ pool: pg.Pool;
7
+ db: Kysely<any>;
8
+ }
9
+ /** Creates databases on `adminUrl`; `cleanup` drops every one of them. */
10
+ export declare function scratchDbFactory(adminUrl: string): {
11
+ freshDb: (tag: string) => Promise<ScratchDb>;
12
+ cleanup: () => Promise<void>;
13
+ };
14
+ /** The applied migration names, sorted. */
15
+ export declare function ledgerNames(db: Kysely<any>): Promise<string[]>;
16
+ //# sourceMappingURL=scratch-db.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
  /**
@@ -9,7 +9,7 @@
9
9
  * No persistence needed -- agents re-register on reconnect.
10
10
  */
11
11
  import { type CanonicalLabel, type LabelMatcher } from '@kici-dev/engine';
12
- import type { AgentCapabilities, WsLike } from '@kici-dev/engine';
12
+ import type { WsLike } from '@kici-dev/engine';
13
13
  /**
14
14
  * The longest a busy rejection holds an agent out of routing when no evidence
15
15
  * of a free slot lifts the hold first: an `agent.status` capacity report, or a
@@ -108,11 +108,6 @@ export interface AgentEntry {
108
108
  registeredAt: number;
109
109
  /** Self-reported agent version (e.g. "0.0.1"). Null if not reported. */
110
110
  version: string | null;
111
- /**
112
- * Optional behaviours the agent advertised on `agent.register`. Null for an
113
- * agent that advertised none, which is read as supporting none.
114
- */
115
- capabilities: AgentCapabilities | null;
116
111
  /**
117
112
  * The `agent_tokens.id` row used to authenticate this connection, or
118
113
  * `null` when auth mode is `none`. Indexed by `tokenIdIndex` so a
@@ -180,8 +175,6 @@ interface AgentMetadata {
180
175
  * any operator-declared properties). Undefined ⇒ the agent reported none.
181
176
  */
182
177
  properties?: Record<string, string | number | boolean>;
183
- /** Optional behaviours the agent advertised on `agent.register`. */
184
- capabilities?: AgentCapabilities;
185
178
  }
186
179
  /**
187
180
  * Subset of `HostRosterStore` the registry reconciles into. Optional — when no
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Without one, Hono answers an unhandled throw with a bare, unstructured 500:
5
5
  * no JSON body, no route context, and nothing written to our own logs. Every
6
- * admin router already catches inside its handlers (routes/admin-errors.ts),
6
+ * admin sub-app answers its own errors through its own onError (routes/admin-env.ts),
7
7
  * and the auth path catches inside its middleware (routes/admin-auth.ts) -- this
8
8
  * covers whatever neither does.
9
9
  *
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. */
@@ -207,8 +207,6 @@ export declare class ArtifactStore {
207
207
  runId: string;
208
208
  name: string;
209
209
  }): Promise<ArtifactDownloadResult>;
210
- /** ISO string for a row's created_at (Date or already-string). */
211
- private createdAtIso;
212
210
  /** Load a run's non-expired artifact rows, newest first, given the org TTL. */
213
211
  private loadRunRows;
214
212
  /**
@@ -105,7 +105,7 @@ export declare class AccessLogWriter {
105
105
  * synthetic `__orchestrator__` tenant is scanned (matches the
106
106
  * NULL-org_id rows the orchestrator itself emits via
107
107
  * `cold-store-archive` / `cold-store-purge`). The CLI exposes this as
108
- * `kici-admin access-log show <id> --org-id <orgId>`.
108
+ * `kici-admin access-log show <id> --org <orgId>`.
109
109
  *
110
110
  * Best-effort contract: a cold-store error logs a warn line and
111
111
  * returns null, matching `loadAccessLogRange` and
@@ -32,7 +32,7 @@
32
32
  * defect this layout closes — so serving it would serve the bug. For a v6 lock
33
33
  * the fallback is unreachable anyway, since the schema bump moves every hash.
34
34
  * Old objects are orphaned. The cache TTL is enforced lazily on access, so
35
- * nothing here removes them; `kici-admin cache purge-legacy` does.
35
+ * nothing here removes them.
36
36
  */
37
37
  import type { CacheStorage } from '../storage/types.js';
38
38
  /**
@@ -24,26 +24,6 @@ export interface UserCacheOrgLimits {
24
24
  }
25
25
  /** Resolves the per-org cache limits for an org id (e.g. an `org_settings` read). */
26
26
  export type UserCacheOrgLimitsReader = (orgId: string) => Promise<UserCacheOrgLimits>;
27
- /**
28
- * Stem prefix of an in-flight upload, `.tmp-<uuid>.tar.gz`: the presigned PUT
29
- * target a save lands on before commit copies it to its final key. Shared with
30
- * the retired-layout classifier so both agree on what an upload looks like.
31
- */
32
- export declare const TEMP_UPLOAD_STEM = ".tmp-";
33
- /**
34
- * Sanitize a path segment so a key can never escape its org/repo/scope
35
- * namespace. Beyond stripping disallowed characters, a segment consisting
36
- * only of dots (`.`, `..`, …) is replaced wholesale: such a segment is a
37
- * dot-segment that HTTP/S3 path canonicalization collapses (`a/./b` → `a/b`,
38
- * `a/../b` → `b`), which both corrupts the namespace and breaks the SigV4
39
- * signature on a pre-signed PUT/GET. Repo identifiers like `.` (the internal
40
- * provider's repo id) hit exactly this case, so the all-dots guard keeps the
41
- * object key canonical and the namespace boundary intact.
42
- *
43
- * Exported so an operator tool that addresses an org's prefix from a raw org id
44
- * (`kici-admin cache purge-legacy --org`) lands on the segment the writer used.
45
- */
46
- export declare function sanitizeSegment(s: string): string;
47
27
  /** Identifies the org + repo + write scope a cache operation targets. */
48
28
  export interface UserCacheRef {
49
29
  org: string;
@@ -65,14 +45,6 @@ export interface UserCacheBeginSaveResult {
65
45
  uploadUrl?: string;
66
46
  tempKey?: string;
67
47
  }
68
- /**
69
- * The object key a committed save under `key` lands on for this ref. This is
70
- * the writer's own path — `beginSave` and `commitSave` address the entry
71
- * through it — so anything that must recognise a current-layout key (the
72
- * legacy-layout classifier tests) takes it from here rather than restating
73
- * the format.
74
- */
75
- export declare function userCacheEntryKey(ref: UserCacheRef, key: string): string;
76
48
  export declare class UserCache {
77
49
  private readonly storage;
78
50
  /** Cluster-wide default quota (the `KICI_USER_CACHE_QUOTA_BYTES` value). */
@@ -5,7 +5,7 @@
5
5
  * All methods are thin wrappers around fetch() that handle JSON serialization,
6
6
  * error formatting, and URL construction.
7
7
  */
8
- import type { PeerForgetOutcome, ScalerLiveVm, ScalerVmStopResult } from '@kici-dev/engine';
8
+ import type { PeerForgetOutcome, ScalerLiveVm, ScalerReloadAnswer, ScalerReloadInstanceResult, ScalerVmStopResult } from '@kici-dev/engine';
9
9
  /** `POST /api/v1/admin/peers/forget`: one result per coordinator, this one first. */
10
10
  export interface PeerForgetResponseBody {
11
11
  instanceId: string;
@@ -18,6 +18,11 @@ export interface PeerForgetResponseBody {
18
18
  acknowledgementRequired?: boolean;
19
19
  error?: string;
20
20
  }
21
+ /** The answer of `POST /api/v1/admin/scaler/reload`: one result per orchestrator, this one first. */
22
+ export interface ScalerReloadResponseBody {
23
+ scope: 'cluster' | 'single';
24
+ results: ScalerReloadInstanceResult[];
25
+ }
21
26
  /** The node a scaler orphans request answered for. */
22
27
  export interface ScalerOrphansNode {
23
28
  instanceId: string;
@@ -138,7 +143,11 @@ export declare function firstCauseMessage(err: unknown): string;
138
143
  * opening a connection.
139
144
  */
140
145
  export declare function isTransportFailure(err: unknown): boolean;
146
+ /** The admin API address kici-admin dials when neither --url nor KICI_ADMIN_URL is set. */
147
+ export declare const DEFAULT_ADMIN_URL = "http://localhost:4000";
141
148
  export declare function fetchAdminApi(url: string, init: RequestInit, baseUrl: string): Promise<Response>;
149
+ /** Build a `?a=1&b=2` query string, skipping undefined, null and empty-string values. */
150
+ export declare function toQuery(params: Record<string, string | number | boolean | undefined | null>): string;
142
151
  export declare class AdminApiClient {
143
152
  private readonly baseUrl;
144
153
  private readonly token;
@@ -409,6 +418,7 @@ export declare class AdminApiClient {
409
418
  success: boolean;
410
419
  version?: number;
411
420
  errors?: string[];
421
+ scaler?: ScalerReloadAnswer;
412
422
  }>;
413
423
  /** Flip the coordinator drain flag on ('drain') or off ('resume'). */
414
424
  drain(action: 'drain' | 'resume'): Promise<{
@@ -432,6 +442,22 @@ export declare class AdminApiClient {
432
442
  timeoutMs?: number;
433
443
  acknowledgeBackstop?: boolean;
434
444
  }): Promise<PeerForgetResponseBody>;
445
+ /**
446
+ * POST `body` and parse the answer whatever its status, for a route that
447
+ * reports per-instance results on a non-2xx status too. An unparseable body
448
+ * reads as `{}`.
449
+ */
450
+ private postForBody;
451
+ /**
452
+ * Reload the scaler config on this orchestrator and, unless `single`, on every
453
+ * peer it is connected to. A response where an instance refused its file or
454
+ * was not reached (422) is returned like a success, so the caller can show
455
+ * every instance; a 404 means the orchestrator predates the route.
456
+ */
457
+ scalerReload(body: {
458
+ single?: boolean;
459
+ timeoutMs?: number;
460
+ }): Promise<ScalerReloadResponseBody>;
435
461
  /** List the live Firecracker VMs on this coordinator, or on the `target` peer. */
436
462
  listScalerOrphans(opts?: {
437
463
  target?: string;
@@ -10,7 +10,7 @@
10
10
  * access-log show Show a single entry by id
11
11
  *
12
12
  * Filter flags for `list`:
13
- * --org-id -> ?orgId=
13
+ * --org -> ?orgId=
14
14
  * --actor-type -> ?actorType=
15
15
  * --actor-id -> ?actorId=
16
16
  * --action -> ?action=
@@ -1,101 +1,24 @@
1
- export declare function archiveNow(opts: {
2
- databaseUrl: string;
1
+ export declare const archiveNow: (opts: import("@kici-dev/shared").ColdStoreAdminStoreOpts & {
3
2
  table: string;
4
- instanceId?: string;
5
- }): Promise<void>;
6
- export declare function dryRunArchive(opts: {
7
- databaseUrl: string;
3
+ }) => Promise<void>, dryRunArchive: (opts: import("@kici-dev/shared").ColdStoreAdminStoreOpts & {
8
4
  table: string;
9
5
  tenant?: string;
10
6
  from?: string;
11
7
  to?: string;
12
- instanceId?: string;
13
- }): Promise<void>;
14
- export interface ChunkListing {
15
- chunkId: string;
16
- tenantId: string;
17
- partitionDate: string;
18
- dataKey: string | null;
19
- manifestKey: string | null;
20
- }
21
- export declare function listChunks(opts: {
22
- databaseUrl: string;
8
+ }) => Promise<void>, listChunks: (opts: import("@kici-dev/shared").ColdStoreAdminStoreOpts & {
23
9
  table: string;
24
10
  tenant?: string;
25
11
  missingData?: boolean;
26
12
  missingManifest?: boolean;
27
13
  from?: string;
28
14
  to?: string;
29
- instanceId?: string;
30
- }): Promise<void>;
31
- export declare function verifyChunk(opts: {
32
- databaseUrl: string;
33
- chunkId: string;
34
- table: string;
35
- tenant: string;
36
- partitionDate: string;
37
- instanceId?: string;
38
- }): Promise<'match' | 'mismatch'>;
39
- export declare function replayChunk(opts: {
40
- databaseUrl: string;
41
- chunkId: string;
42
- table: string;
43
- tenant: string;
44
- partitionDate: string;
45
- instanceId?: string;
46
- }): Promise<void>;
47
- /**
48
- * Promote a chunk's rows back into the orchestrator PG.
49
- * Mirrors the Platform-side `replayIntoPg`. Adapter must implement
50
- * `replayInsert` — currently only `execution_runs`.
51
- */
52
- export declare function replayIntoPg(opts: {
53
- databaseUrl: string;
54
- chunkId: string;
55
- table: string;
56
- tenant: string;
57
- partitionDate: string;
58
- instanceId?: string;
59
- }): Promise<void>;
60
- export declare function reconcile(opts: {
61
- databaseUrl: string;
15
+ }) => Promise<void>, verifyChunk: (opts: import("@kici-dev/shared").ColdStoreAdminChunkOpts) => Promise<"match" | "mismatch">, replayChunk: (opts: import("@kici-dev/shared").ColdStoreAdminChunkOpts) => Promise<void>, replayIntoPg: (opts: import("@kici-dev/shared").ColdStoreAdminChunkOpts) => Promise<void>, reconcile: (opts: import("@kici-dev/shared").ColdStoreAdminStoreOpts & {
62
16
  table: string;
63
17
  tenant?: string;
64
18
  confirmCleanup?: boolean;
65
- instanceId?: string;
66
- }): Promise<void>;
67
- /**
68
- * List chunks past their cold-retention horizon. Read-only;
69
- * no S3 or PG mutation. Emits one JSON line per row so the output is
70
- * easy to pipe through `jq` / `column -t` / etc.
71
- */
72
- export declare function listPurgeable(opts: {
73
- databaseUrl: string;
74
- table?: string;
75
- bucket?: string;
76
- limit?: number;
77
- instanceId?: string;
78
- }): Promise<void>;
79
- /**
80
- * Delete S3 objects + clean up PG bookkeeping for chunks
81
- * past their cold-retention horizon. Defaults to dry-run; pass
82
- * `--apply` to actually delete.
83
- */
84
- export declare function purgeNow(opts: {
85
- databaseUrl: string;
86
- table?: string;
87
- bucket?: string;
88
- limit?: number;
19
+ }) => Promise<void>, listPurgeable: (opts: import("@kici-dev/shared").ColdStoreAdminPurgeOpts) => Promise<void>, purgeNow: (opts: import("@kici-dev/shared").ColdStoreAdminPurgeOpts & {
89
20
  apply?: boolean;
90
- instanceId?: string;
91
- }): Promise<void>;
92
- export declare function peekChunk(opts: {
93
- databaseUrl: string;
94
- chunkId: string;
95
- table: string;
96
- tenant: string;
97
- partitionDate: string;
21
+ }) => Promise<void>, peekChunk: (opts: import("@kici-dev/shared").ColdStoreAdminChunkOpts & {
98
22
  limit: number;
99
- instanceId?: string;
100
- }): Promise<void>;
23
+ }) => Promise<void>;
101
24
  //# sourceMappingURL=cold-store-impl.d.ts.map
@@ -7,6 +7,7 @@
7
7
  * db create-role CREATE ROLE LOGIN [CREATEDB] (direct DB)
8
8
  * db create-readonly-user Read-only role + GRANT SELECT (direct DB)
9
9
  * db check-schema Compare bundled migrations vs live schema (direct DB)
10
+ * db schema-diff Compare the live schema with the release snapshot (direct DB)
10
11
  * db collation-check Check pg_database.datcollversion vs running libc (direct DB)
11
12
  * db reindex REINDEX DATABASE CONCURRENTLY (direct DB)
12
13
  * db refresh-collation-version ALTER DATABASE REFRESH COLLATION VERSION (direct DB)
@@ -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;
@@ -4,6 +4,8 @@
4
4
  * Shows OS-level service status (state, PID, uptime) and queries the
5
5
  * running orchestrator's `/health` and `/ready` endpoints for its version,
6
6
  * build fingerprint, uptime and readiness (database reachable, boot finished).
7
+ * With an admin token (`--token` / KICI_ADMIN_TOKEN) it also asks the
8
+ * instance's admin API which org the Platform attached it to.
7
9
  *
8
10
  * Target resolution goes through resolveInstanceTarget — the same priority chain
9
11
  * every lifecycle command uses (--instance-dir > --name > CWD manifest >
@@ -0,0 +1,12 @@
1
+ /**
2
+ * `kici-admin org list` — every org id this orchestrator holds data for.
3
+ *
4
+ * Reads `GET /api/v1/admin/org-ids` by default. With `--database-url` (or
5
+ * KICI_DATABASE_URL) it runs the same query against the orchestrator database
6
+ * directly; that mode cannot see the live Platform connection, so it lists no
7
+ * `platform` source and says so.
8
+ */
9
+ import type { Command } from 'commander';
10
+ import type { AdminApiClient } from '../api-client.js';
11
+ export declare function registerOrgCommands(program: Command, getClient: () => AdminApiClient): void;
12
+ //# sourceMappingURL=org.d.ts.map
@@ -5,6 +5,9 @@
5
5
  * orchestrator does not track and, with --stop, stop
6
6
  * them. Goes through the admin HTTP API; `--target`
7
7
  * reaches a worker through the coordinator.
8
+ * scaler reload Re-read the scaler config on this orchestrator and
9
+ * every peer it is connected to (admin HTTP API);
10
+ * each one applies its file completely or not at all.
8
11
  * scaler reap-orphans Free leaked Firecracker/container resources WITHOUT a
9
12
  * running orchestrator (recovery for a wedged node whose
10
13
  * data disk is full).
@@ -49,6 +52,17 @@ export declare function formatAge(seconds: number): string;
49
52
  * @returns the process exit code
50
53
  */
51
54
  export declare function runScalerOrphans(client: OrphansClient, opts: ScalerOrphansOptions, io: ScalerOrphansIo): Promise<number>;
55
+ export interface ScalerReloadOptions {
56
+ single: boolean;
57
+ timeout: string;
58
+ json: boolean;
59
+ }
60
+ /**
61
+ * `scaler reload`: reload the scaler config and print one block per instance.
62
+ * Resolves the exit code: 1 when any instance refused its file or was not
63
+ * reached, else 0. A bad `--timeout` throws before any request.
64
+ */
65
+ export declare function runScalerReload(client: Pick<AdminApiClient, 'scalerReload'>, opts: ScalerReloadOptions, out: (line: string) => void): Promise<number>;
52
66
  export declare function registerScalerCommands(program: Command, getClient: () => AdminApiClient): void;
53
67
  export {};
54
68
  //# sourceMappingURL=scaler.d.ts.map