@kici-dev/engine 0.1.27 → 0.3.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 (148) hide show
  1. package/dist/approval/types.d.ts +8 -1
  2. package/dist/approval/types.js +8 -1
  3. package/dist/artifacts/name.d.ts +60 -0
  4. package/dist/artifacts/name.js +71 -0
  5. package/dist/audit/access-log-policy.d.ts +1 -1
  6. package/dist/audit/access-log-policy.js +8 -0
  7. package/dist/audit/activity.d.ts +12 -12
  8. package/dist/audit/retention-policy.js +16 -0
  9. package/dist/billing/plan-type.d.ts +53 -0
  10. package/dist/billing/plan-type.js +70 -0
  11. package/dist/bundler/rolldown-config.d.ts +3 -3
  12. package/dist/check-mode.d.ts +1 -1
  13. package/dist/context/concurrency-strategy.d.ts +34 -0
  14. package/dist/context/concurrency-strategy.js +35 -0
  15. package/dist/context/held-run-job-id.d.ts +45 -0
  16. package/dist/context/held-run-job-id.js +56 -0
  17. package/dist/context/held-run-status.d.ts +33 -0
  18. package/dist/context/held-run-status.js +37 -0
  19. package/dist/context/hold-expiry.d.ts +20 -0
  20. package/dist/context/hold-expiry.js +25 -0
  21. package/dist/context/hold-reason.d.ts +33 -0
  22. package/dist/context/hold-reason.js +23 -0
  23. package/dist/context/hold-type.d.ts +40 -0
  24. package/dist/context/hold-type.js +61 -0
  25. package/dist/context/index.d.ts +9 -1
  26. package/dist/context/index.js +9 -2
  27. package/dist/context/multi-context.d.ts +3 -3
  28. package/dist/context/scope-name.d.ts +29 -0
  29. package/dist/context/scope-name.js +49 -0
  30. package/dist/context/scope-resolver.d.ts +33 -0
  31. package/dist/context/scope-resolver.js +45 -15
  32. package/dist/context/types.d.ts +8 -5
  33. package/dist/dev-ops/operations.d.ts +8 -0
  34. package/dist/dev-ops/operations.js +36 -19
  35. package/dist/diagnostics/infra-alert.d.ts +71 -0
  36. package/dist/diagnostics/infra-alert.js +60 -0
  37. package/dist/env/environment-allowlist.d.ts +4 -4
  38. package/dist/fanout/materialize.d.ts +16 -0
  39. package/dist/fanout/materialize.js +32 -3
  40. package/dist/index.d.ts +15 -6
  41. package/dist/index.js +34 -19
  42. package/dist/inputs/descriptor.d.ts +9 -9
  43. package/dist/inventory.d.ts +4 -4
  44. package/dist/labels.d.ts +82 -2
  45. package/dist/labels.js +119 -1
  46. package/dist/matrix/expand.d.ts +49 -2
  47. package/dist/matrix/expand.js +102 -13
  48. package/dist/matrix/format.d.ts +6 -1
  49. package/dist/matrix/format.js +6 -1
  50. package/dist/mcp/held-run-resolve.d.ts +7 -10
  51. package/dist/mcp/held-run-resolve.js +33 -7
  52. package/dist/metrics/catalog-policy.js +4 -4
  53. package/dist/metrics/metric-catalog.generated.d.ts +959 -739
  54. package/dist/metrics/metric-catalog.generated.js +284 -20
  55. package/dist/metrics/metric-kind-compat.d.ts +26 -0
  56. package/dist/metrics/metric-kind-compat.js +33 -0
  57. package/dist/protocol/analytics-events.d.ts +6 -6
  58. package/dist/protocol/dashboard-api-errors.d.ts +1 -0
  59. package/dist/protocol/dashboard-api-errors.js +5 -1
  60. package/dist/protocol/dashboard-write-operations.d.ts +143 -86
  61. package/dist/protocol/dashboard-write-operations.js +91 -17
  62. package/dist/protocol/messages/access-log.d.ts +437 -392
  63. package/dist/protocol/messages/access-log.js +11 -2
  64. package/dist/protocol/messages/actor.d.ts +2 -2
  65. package/dist/protocol/messages/agent-dev-ops.d.ts +4 -2
  66. package/dist/protocol/messages/agent-dev-ops.js +2 -5
  67. package/dist/protocol/messages/agent-run-result.d.ts +72 -62
  68. package/dist/protocol/messages/auth.d.ts +35 -23
  69. package/dist/protocol/messages/browser.d.ts +81 -5
  70. package/dist/protocol/messages/browser.js +53 -2
  71. package/dist/protocol/messages/capabilities.d.ts +106 -31
  72. package/dist/protocol/messages/capabilities.js +94 -10
  73. package/dist/protocol/messages/common.d.ts +45 -2
  74. package/dist/protocol/messages/common.js +64 -3
  75. package/dist/protocol/messages/dashboard-sealed-write.d.ts +52 -0
  76. package/dist/protocol/messages/dashboard-sealed-write.js +57 -0
  77. package/dist/protocol/messages/dashboard.d.ts +1026 -498
  78. package/dist/protocol/messages/dashboard.js +208 -31
  79. package/dist/protocol/messages/deployment-identity.d.ts +37 -10
  80. package/dist/protocol/messages/deployment-identity.js +30 -3
  81. package/dist/protocol/messages/event-log.d.ts +5 -5
  82. package/dist/protocol/messages/execution-status.d.ts +189 -53
  83. package/dist/protocol/messages/execution-status.js +108 -40
  84. package/dist/protocol/messages/heartbeat-health.d.ts +83 -0
  85. package/dist/protocol/messages/heartbeat-health.js +87 -0
  86. package/dist/protocol/messages/log-stream.d.ts +18 -0
  87. package/dist/protocol/messages/log-stream.js +19 -0
  88. package/dist/protocol/messages/oidc-mint.d.ts +7 -0
  89. package/dist/protocol/messages/oidc-mint.js +7 -0
  90. package/dist/protocol/messages/orchestrator-agent.d.ts +264 -67
  91. package/dist/protocol/messages/orchestrator-agent.js +170 -5
  92. package/dist/protocol/messages/pat-kind.d.ts +1 -1
  93. package/dist/protocol/messages/peer.d.ts +122 -58
  94. package/dist/protocol/messages/peer.js +37 -2
  95. package/dist/protocol/messages/platform-orchestrator.d.ts +561 -217
  96. package/dist/protocol/messages/platform-orchestrator.js +131 -21
  97. package/dist/protocol/messages/run-events.d.ts +5 -5
  98. package/dist/protocol/messages/scaler-event.d.ts +3 -3
  99. package/dist/protocol/messages/source-registration.d.ts +56 -13
  100. package/dist/protocol/messages/source-registration.js +49 -6
  101. package/dist/protocol/source-origin.d.ts +1 -1
  102. package/dist/provenance/attestation-origin.d.ts +1 -1
  103. package/dist/provenance/schema.d.ts +11 -11
  104. package/dist/provenance/verify.js +2 -1
  105. package/dist/provider/changed-files-fetcher.d.ts +21 -2
  106. package/dist/provider/check-run-conclusion.d.ts +2 -2
  107. package/dist/provider/check-status-poster.d.ts +23 -0
  108. package/dist/provider/index.d.ts +2 -2
  109. package/dist/registration/registerable-trigger-type.d.ts +14 -13
  110. package/dist/registration/registerable-trigger-type.js +1 -0
  111. package/dist/sandbox/capabilities.d.ts +6 -0
  112. package/dist/sandbox/capabilities.js +57 -0
  113. package/dist/scaler/scaler-backend-type.d.ts +1 -1
  114. package/dist/status/presentation.d.ts +89 -0
  115. package/dist/status/presentation.js +163 -0
  116. package/dist/trigger/compiled-matchers.d.ts +13 -0
  117. package/dist/trigger/compiled-matchers.js +44 -0
  118. package/dist/trigger/event-buckets.d.ts +44 -0
  119. package/dist/trigger/event-buckets.js +93 -0
  120. package/dist/trigger/matcher.d.ts +7 -3
  121. package/dist/trigger/matcher.js +53 -15
  122. package/dist/trigger/schedule-key.d.ts +14 -0
  123. package/dist/trigger/schedule-key.js +21 -0
  124. package/dist/trigger/trigger-event-type.d.ts +1 -1
  125. package/dist/trigger/trigger-event-type.js +2 -0
  126. package/dist/trigger/types.d.ts +173 -43
  127. package/dist/trigger/types.js +82 -25
  128. package/dist/webhook/event-types.d.ts +56 -0
  129. package/dist/webhook/event-types.js +59 -0
  130. package/dist/ws/ws-like.d.ts +13 -0
  131. package/package.json +12 -4
  132. package/sbom.spdx.json +10 -10
  133. package/dist/environment/host-match.d.ts +0 -25
  134. package/dist/environment/index.d.ts +0 -6
  135. package/dist/environment/multi-env.d.ts +0 -30
  136. package/dist/environment/scope-resolver.d.ts +0 -46
  137. package/dist/environment/scope-template.d.ts +0 -18
  138. package/dist/environment/types.d.ts +0 -119
  139. package/dist/package-manager.d.ts +0 -20
  140. package/dist/protocol/messages/observe.d.ts +0 -76
  141. package/dist/protocol/messages/saas-orchestrator.d.ts +0 -2179
  142. package/dist/protocol/messages/test-run.d.ts +0 -59
  143. package/dist/state-machine/index.d.ts +0 -2
  144. package/dist/state-machine/index.js +0 -3
  145. package/dist/state-machine/machine.d.ts +0 -34
  146. package/dist/state-machine/machine.js +0 -103
  147. package/dist/state-machine/types.d.ts +0 -34
  148. package/dist/state-machine/types.js +0 -15
@@ -1,6 +1,8 @@
1
1
  import "../../rolldown-runtime-ClRpJifh.js";
2
2
  import { browserJobContextSchema, browserRunEventSchema } from "./run-events.js";
3
3
  import { browserEventLogPayloadChunkSchema } from "./dashboard.js";
4
+ import { LogStream } from "./log-stream.js";
5
+ import { OrchLogPhase } from "./platform-orchestrator.js";
4
6
  import { z } from "zod";
5
7
  //#region src/protocol/messages/browser.ts
6
8
  /**
@@ -38,6 +40,24 @@ const browserLogUnsubscribeSchema = z.object({
38
40
  jobId: z.string(),
39
41
  stepIndex: z.number()
40
42
  });
43
+ /**
44
+ * Browser subscribes to live orchestration/provisioning logs for a job.
45
+ *
46
+ * Keyed by `(runId, jobId)` — no `stepIndex` (orch logs are job-level, not
47
+ * per-step). On subscribe the Platform backfills persisted history via the
48
+ * `dashboard.orch.logs` RPC, then streams live `orch-log.lines`.
49
+ */
50
+ const browserOrchLogSubscribeSchema = z.object({
51
+ type: z.literal("orch-log.subscribe"),
52
+ runId: z.string(),
53
+ jobId: z.string()
54
+ });
55
+ /** Browser unsubscribes from live orchestration/provisioning logs for a job. */
56
+ const browserOrchLogUnsubscribeSchema = z.object({
57
+ type: z.literal("orch-log.unsubscribe"),
58
+ runId: z.string(),
59
+ jobId: z.string()
60
+ });
41
61
  /** Browser subscribes to org-level status updates (run/job/step status changes). */
42
62
  const browserStatusSubscribeSchema = z.object({
43
63
  type: z.literal("status.subscribe"),
@@ -71,6 +91,8 @@ const browserToPlatformMessageSchema = z.discriminatedUnion("type", [
71
91
  browserAuthRefreshSchema,
72
92
  browserLogSubscribeSchema,
73
93
  browserLogUnsubscribeSchema,
94
+ browserOrchLogSubscribeSchema,
95
+ browserOrchLogUnsubscribeSchema,
74
96
  browserStatusSubscribeSchema,
75
97
  browserStatusUnsubscribeSchema,
76
98
  browserEventLogPayloadFetchSchema,
@@ -94,7 +116,35 @@ const browserLogLinesSchema = z.object({
94
116
  stepIndex: z.number(),
95
117
  lines: z.array(z.string()),
96
118
  /** Total line count (cumulative offset so browser knows position). */
97
- lineCount: z.number()
119
+ lineCount: z.number(),
120
+ /**
121
+ * Which stream these lines came from. Absent when the producing orchestrator
122
+ * does not report one; read as `stdout`.
123
+ */
124
+ stream: LogStream.optional()
125
+ });
126
+ /**
127
+ * Platform sends orchestration/provisioning log lines for a subscribed job.
128
+ *
129
+ * Delivered in two forms over the same message:
130
+ * - **Backfill** (on subscribe): `lines` are the persisted JSONL strings from
131
+ * the `dashboard.orch.logs` RPC (each carrying its own `phase`/`ts`), so the
132
+ * top-level `phase`/`ts` are omitted.
133
+ * - **Live** (streamed after backfill): `lines` are raw message strings for a
134
+ * single `phase` at timestamp `ts`.
135
+ *
136
+ * The dashboard normalizes both by attempting to JSON-parse each line and
137
+ * falling back to the envelope `phase`/`ts`, and dedups on `(ts, phase,
138
+ * message)` so an overlap between the backfill snapshot and the first live
139
+ * chunk is not double-appended.
140
+ */
141
+ const browserOrchLogLinesSchema = z.object({
142
+ type: z.literal("orch-log.lines"),
143
+ runId: z.string(),
144
+ jobId: z.string(),
145
+ phase: OrchLogPhase.optional(),
146
+ lines: z.array(z.string()),
147
+ ts: z.number().optional()
98
148
  });
99
149
  /** Platform notifies browser that lines were dropped due to backpressure. */
100
150
  const browserGapSchema = z.object({
@@ -206,6 +256,7 @@ const platformToBrowserMessageSchema = z.discriminatedUnion("type", [
206
256
  browserAuthSuccessSchema,
207
257
  browserAuthFailureSchema,
208
258
  browserLogLinesSchema,
259
+ browserOrchLogLinesSchema,
209
260
  browserGapSchema,
210
261
  browserLogStreamTerminatedSchema,
211
262
  browserRunStatusSchema,
@@ -220,6 +271,6 @@ const platformToBrowserMessageSchema = z.discriminatedUnion("type", [
220
271
  browserEventLogPayloadChunkSchema
221
272
  ]);
222
273
  //#endregion
223
- export { browserAuthFailureSchema, browserAuthRefreshSchema, browserAuthRequestSchema, browserAuthSuccessSchema, browserErrorSchema, browserEventLogPayloadFetchSchema, browserGapSchema, browserJobNewSchema, browserJobStatusSchema, browserLogLinesSchema, browserLogStreamTerminatedReason, browserLogStreamTerminatedSchema, browserLogSubscribeSchema, browserLogUnsubscribeSchema, browserPingSchema, browserPongSchema, browserRunNewSchema, browserRunStatusSchema, browserStatusSubscribeSchema, browserStatusUnsubscribeSchema, browserStepStatusSchema, browserToPlatformMessageSchema, platformToBrowserMessageSchema };
274
+ export { browserAuthFailureSchema, browserAuthRefreshSchema, browserAuthRequestSchema, browserAuthSuccessSchema, browserErrorSchema, browserEventLogPayloadFetchSchema, browserGapSchema, browserJobNewSchema, browserJobStatusSchema, browserLogLinesSchema, browserLogStreamTerminatedReason, browserLogStreamTerminatedSchema, browserLogSubscribeSchema, browserLogUnsubscribeSchema, browserOrchLogLinesSchema, browserOrchLogSubscribeSchema, browserOrchLogUnsubscribeSchema, browserPingSchema, browserPongSchema, browserRunNewSchema, browserRunStatusSchema, browserStatusSubscribeSchema, browserStatusUnsubscribeSchema, browserStepStatusSchema, browserToPlatformMessageSchema, platformToBrowserMessageSchema };
224
275
 
225
276
  //# sourceMappingURL=browser.js.map
@@ -1,16 +1,24 @@
1
1
  /**
2
- * Orchestrator capability negotiation schemas.
2
+ * Capability negotiation schemas — bidirectional.
3
3
  *
4
4
  * Modeled after peerCapabilitiesSchema in peer.ts.
5
- * See CONTEXT.md through for design decisions.
6
5
  *
7
- * Direction: orchestrator Platform only. The Platform is always at the latest version
8
- * (centrally deployed), so Platform capabilities are unnecessary. The Platform checks
9
- * orchestrator capabilities before sending feature-gated messages.
6
+ * Two directions, each advertised as the sending side learns what the other
7
+ * understands:
8
+ * - **orchestrator Platform** (`orchCapabilitiesSchema`, sent in `auth.request`):
9
+ * the Platform pre-flight-checks orchestrator capabilities before sending
10
+ * feature-gated messages (e.g. the dashboard-request manifest).
11
+ * - **Platform → orchestrator** (`platformCapabilitiesSchema`, advertised once
12
+ * after auth): a self-hosted orchestrator can run *ahead* of the hosted
13
+ * Platform, so it pre-flight-checks its own feature-gated sends against what
14
+ * the Platform advertises — surfacing a diagnosable capability gap instead of
15
+ * firing a frame the Platform would drop.
10
16
  *
11
- * Pattern: Each field indicates support for an optional protocol feature.
12
- * Missing fields default to unsupported for backward compatibility.
13
- * Schema uses .passthrough() so newer orchestrators sending unknown flags don't get stripped.
17
+ * Pattern (both directions): each field indicates support for an optional
18
+ * protocol feature. Missing fields default to unsupported for backward
19
+ * compatibility; `.passthrough()` preserves unknown flags from a newer peer.
20
+ * A peer that never advertises at all is treated as "unknown" (optimistic),
21
+ * never as "supports nothing".
14
22
  */
15
23
  import { z } from 'zod';
16
24
  /** Orchestrator role in a cluster topology. */
@@ -28,36 +36,48 @@ export declare const orchCapabilitiesSchema: z.ZodObject<{
28
36
  coordinator: "coordinator";
29
37
  worker: "worker";
30
38
  }>>;
31
- dashboardWrites: z.ZodOptional<z.ZodRecord<z.ZodEnum<{
32
- "secrets.set": "secrets.set";
33
- "secrets.delete": "secrets.delete";
34
- "secrets.scope.create": "secrets.scope.create";
35
- "secrets.scope.rename": "secrets.scope.rename";
36
- "secrets.scope.delete": "secrets.scope.delete";
37
- "variables.set": "variables.set";
38
- "variables.delete": "variables.delete";
39
- "contexts.create": "contexts.create";
40
- "contexts.update": "contexts.update";
41
- "contexts.test_access.set": "contexts.test_access.set";
42
- "contexts.delete": "contexts.delete";
43
- "contexts.bindings.set": "contexts.bindings.set";
44
- "contexts.source_overrides.set": "contexts.source_overrides.set";
45
- "contexts.source_overrides.delete": "contexts.source_overrides.delete";
46
- "held_runs.approve": "held_runs.approve";
47
- "held_runs.reject": "held_runs.reject";
48
- "event_dlq.retry": "event_dlq.retry";
49
- "event_dlq.discard": "event_dlq.discard";
39
+ dashboardWrites: z.ZodOptional<z.ZodPipe<z.ZodRecord<z.ZodEnum<{
50
40
  "attestations.retry": "attestations.retry";
51
- "registration.disable": "registration.disable";
52
- "registration.delete": "registration.delete";
53
- "global_workflows.update": "global_workflows.update";
54
41
  "backends.sync": "backends.sync";
55
42
  "backends.sync_one": "backends.sync_one";
56
43
  "backends.test": "backends.test";
44
+ "contexts.bindings.set": "contexts.bindings.set";
45
+ "contexts.create": "contexts.create";
46
+ "contexts.delete": "contexts.delete";
47
+ "contexts.source_overrides.delete": "contexts.source_overrides.delete";
48
+ "contexts.source_overrides.set": "contexts.source_overrides.set";
49
+ "contexts.test_access.set": "contexts.test_access.set";
50
+ "contexts.update": "contexts.update";
51
+ "event_dlq.discard": "event_dlq.discard";
52
+ "event_dlq.retry": "event_dlq.retry";
57
53
  "fleet.host.declare": "fleet.host.declare";
58
54
  "fleet.host.remove": "fleet.host.remove";
59
- }> & z.core.$partial, z.ZodBoolean>>;
55
+ "global_workflows.update": "global_workflows.update";
56
+ "held_runs.approve": "held_runs.approve";
57
+ "held_runs.reject": "held_runs.reject";
58
+ "registration.delete": "registration.delete";
59
+ "registration.disable": "registration.disable";
60
+ "secrets.delete": "secrets.delete";
61
+ "secrets.scope.create": "secrets.scope.create";
62
+ "secrets.scope.delete": "secrets.scope.delete";
63
+ "secrets.scope.rename": "secrets.scope.rename";
64
+ "secrets.set": "secrets.set";
65
+ "variables.delete": "variables.delete";
66
+ "variables.set": "variables.set";
67
+ }> & z.core.$partial, z.ZodUnion<readonly [z.ZodBoolean, z.ZodEnum<{
68
+ disabled: "disabled";
69
+ encrypted: "encrypted";
70
+ permissive: "permissive";
71
+ }>]>>, z.ZodTransform<Partial<Record<"attestations.retry" | "backends.sync" | "backends.sync_one" | "backends.test" | "contexts.bindings.set" | "contexts.create" | "contexts.delete" | "contexts.source_overrides.delete" | "contexts.source_overrides.set" | "contexts.test_access.set" | "contexts.update" | "event_dlq.discard" | "event_dlq.retry" | "fleet.host.declare" | "fleet.host.remove" | "global_workflows.update" | "held_runs.approve" | "held_runs.reject" | "registration.delete" | "registration.disable" | "secrets.delete" | "secrets.scope.create" | "secrets.scope.delete" | "secrets.scope.rename" | "secrets.set" | "variables.delete" | "variables.set", "disabled" | "encrypted" | "permissive">>, Partial<Record<"attestations.retry" | "backends.sync" | "backends.sync_one" | "backends.test" | "contexts.bindings.set" | "contexts.create" | "contexts.delete" | "contexts.source_overrides.delete" | "contexts.source_overrides.set" | "contexts.test_access.set" | "contexts.update" | "event_dlq.discard" | "event_dlq.retry" | "fleet.host.declare" | "fleet.host.remove" | "global_workflows.update" | "held_runs.approve" | "held_runs.reject" | "registration.delete" | "registration.disable" | "secrets.delete" | "secrets.scope.create" | "secrets.scope.delete" | "secrets.scope.rename" | "secrets.set" | "variables.delete" | "variables.set", "disabled" | "encrypted" | "permissive" | boolean>>>>>;
60
72
  supportedDashboardRequests: z.ZodOptional<z.ZodArray<z.ZodString>>;
73
+ dashboardEncryptionKey: z.ZodOptional<z.ZodObject<{
74
+ kty: z.ZodLiteral<"OKP">;
75
+ crv: z.ZodLiteral<"X25519">;
76
+ x: z.ZodString;
77
+ kid: z.ZodString;
78
+ use: z.ZodOptional<z.ZodLiteral<"enc">>;
79
+ }, z.core.$loose>>;
80
+ dashboardVerifiedIssuer: z.ZodOptional<z.ZodNullable<z.ZodString>>;
61
81
  }, z.core.$loose>;
62
82
  /** Inferred type for orchestrator capabilities. */
63
83
  export type OrchCapabilities = z.infer<typeof orchCapabilitiesSchema>;
@@ -74,4 +94,59 @@ export declare const ORCH_CAPABILITIES: Readonly<{
74
94
  * orchestrator) or the flag is missing/false.
75
95
  */
76
96
  export declare function hasOrchCapability(capabilities: OrchCapabilities | undefined, flag: string): boolean;
97
+ /**
98
+ * Platform-advertised capabilities sent to the orchestrator after auth.
99
+ * Uses .passthrough() so a newer Platform's unknown flags are preserved.
100
+ * Every field is optional and absent = unsupported (same evolution contract as
101
+ * `orchCapabilitiesSchema`).
102
+ */
103
+ export declare const platformCapabilitiesSchema: z.ZodObject<{
104
+ orchMetrics: z.ZodOptional<z.ZodBoolean>;
105
+ oidcMint: z.ZodOptional<z.ZodBoolean>;
106
+ }, z.core.$loose>;
107
+ /** Inferred type for Platform capabilities. */
108
+ export type PlatformCapabilities = z.infer<typeof platformCapabilitiesSchema>;
109
+ /** Default Platform capabilities advertised to the orchestrator after auth. */
110
+ export declare const PLATFORM_CAPABILITIES: Readonly<{
111
+ orchMetrics: true;
112
+ oidcMint: true;
113
+ }>;
114
+ /**
115
+ * Check whether the Platform advertises a specific capability flag.
116
+ *
117
+ * Takes `string` (not `keyof`) because a newer Platform may advertise flags the
118
+ * current orchestrator build doesn't know about. Returns false if capabilities
119
+ * is undefined (nothing advertised yet) or the flag is missing/false.
120
+ *
121
+ * NOTE: "undefined → false" here is the plain reader semantics. A feature-gated
122
+ * SEND that must stay backward-safe against a pre-capability Platform (which
123
+ * never advertises) treats "nothing advertised yet" as optimistic-send — that
124
+ * layer lives in the orchestrator's `sendIfPlatformSupports`, not here.
125
+ */
126
+ export declare function hasPlatformCapability(capabilities: PlatformCapabilities | undefined, flag: string): boolean;
127
+ /**
128
+ * Orchestrator -> Agent capabilities, advertised on `register.ack`. Same
129
+ * evolution contract as the other two directions: every field optional,
130
+ * absent = unsupported, `.passthrough()` preserves a newer orchestrator's
131
+ * unknown flags. Lets the agent learn which optional agent-facing protocol
132
+ * features this orchestrator build supports.
133
+ */
134
+ export declare const orchAgentCapabilitiesSchema: z.ZodObject<{
135
+ artifactCompleteAck: z.ZodOptional<z.ZodBoolean>;
136
+ }, z.core.$loose>;
137
+ /** Inferred type for orchestrator -> agent capabilities. */
138
+ export type OrchAgentCapabilities = z.infer<typeof orchAgentCapabilitiesSchema>;
139
+ /** Default orchestrator -> agent capabilities advertised on register.ack. */
140
+ export declare const ORCH_AGENT_CAPABILITIES: Readonly<{
141
+ artifactCompleteAck: true;
142
+ }>;
143
+ /**
144
+ * Check whether an orchestrator advertises a specific agent-facing capability
145
+ * flag.
146
+ *
147
+ * Takes `string` (not `keyof`) because a newer orchestrator may advertise flags
148
+ * this agent build doesn't know about. Returns false if capabilities is
149
+ * undefined (pre-capability orchestrator) or the flag is missing/false.
150
+ */
151
+ export declare function hasOrchAgentCapability(capabilities: OrchAgentCapabilities | undefined, flag: string): boolean;
77
152
  //# sourceMappingURL=capabilities.d.ts.map
@@ -1,21 +1,30 @@
1
1
  import "../../rolldown-runtime-ClRpJifh.js";
2
2
  import { dashboardWritePolicyMap } from "../dashboard-write-operations.js";
3
+ import { dashboardEncryptionJwkSchema } from "./dashboard-sealed-write.js";
3
4
  import { DASHBOARD_REQUEST_TYPES } from "./dashboard.js";
4
5
  import { z } from "zod";
5
6
  //#region src/protocol/messages/capabilities.ts
6
7
  /**
7
- * Orchestrator capability negotiation schemas.
8
+ * Capability negotiation schemas — bidirectional.
8
9
  *
9
10
  * Modeled after peerCapabilitiesSchema in peer.ts.
10
- * See CONTEXT.md through for design decisions.
11
11
  *
12
- * Direction: orchestrator Platform only. The Platform is always at the latest version
13
- * (centrally deployed), so Platform capabilities are unnecessary. The Platform checks
14
- * orchestrator capabilities before sending feature-gated messages.
12
+ * Two directions, each advertised as the sending side learns what the other
13
+ * understands:
14
+ * - **orchestrator Platform** (`orchCapabilitiesSchema`, sent in `auth.request`):
15
+ * the Platform pre-flight-checks orchestrator capabilities before sending
16
+ * feature-gated messages (e.g. the dashboard-request manifest).
17
+ * - **Platform → orchestrator** (`platformCapabilitiesSchema`, advertised once
18
+ * after auth): a self-hosted orchestrator can run *ahead* of the hosted
19
+ * Platform, so it pre-flight-checks its own feature-gated sends against what
20
+ * the Platform advertises — surfacing a diagnosable capability gap instead of
21
+ * firing a frame the Platform would drop.
15
22
  *
16
- * Pattern: Each field indicates support for an optional protocol feature.
17
- * Missing fields default to unsupported for backward compatibility.
18
- * Schema uses .passthrough() so newer orchestrators sending unknown flags don't get stripped.
23
+ * Pattern (both directions): each field indicates support for an optional
24
+ * protocol feature. Missing fields default to unsupported for backward
25
+ * compatibility; `.passthrough()` preserves unknown flags from a newer peer.
26
+ * A peer that never advertises at all is treated as "unknown" (optimistic),
27
+ * never as "supports nothing".
19
28
  */
20
29
  /** Orchestrator role in a cluster topology. */
21
30
  const OrchRole = z.enum(["coordinator", "worker"]);
@@ -43,7 +52,23 @@ const orchCapabilitiesSchema = z.object({
43
52
  * cannot drift. Absent on pre-capability builds → treated as "unknown",
44
53
  * never as "supports nothing".
45
54
  */
46
- supportedDashboardRequests: z.array(z.string()).optional()
55
+ supportedDashboardRequests: z.array(z.string()).optional(),
56
+ /**
57
+ * The orchestrator's active X25519 dashboard-encryption public key. Feeds
58
+ * the Convenient tier: the key reaches the hosted control plane over the
59
+ * authenticated orchestrator connection, and the dashboard fetches it from
60
+ * there when no verified issuer is configured. Absent on builds without the
61
+ * key (no `KICI_SECRET_KEY`, or not yet provisioned) — the dashboard then
62
+ * fails closed rather than sending plaintext.
63
+ */
64
+ dashboardEncryptionKey: dashboardEncryptionJwkSchema.optional(),
65
+ /**
66
+ * The verified-tier origin the dashboard should fetch the encryption key
67
+ * from directly (bypassing the control plane), from the orchestrator's
68
+ * `dashboard_verified_issuer` cluster setting. Null/absent ⇒ the Verified
69
+ * tier is not offered and the Convenient tier applies.
70
+ */
71
+ dashboardVerifiedIssuer: z.string().nullable().optional()
47
72
  }).passthrough();
48
73
  /** Default orchestrator capabilities sent in auth.request. */
49
74
  const ORCH_CAPABILITIES = Object.freeze({
@@ -60,7 +85,66 @@ const ORCH_CAPABILITIES = Object.freeze({
60
85
  function hasOrchCapability(capabilities, flag) {
61
86
  return capabilities?.[flag] === true;
62
87
  }
88
+ /**
89
+ * Platform-advertised capabilities sent to the orchestrator after auth.
90
+ * Uses .passthrough() so a newer Platform's unknown flags are preserved.
91
+ * Every field is optional and absent = unsupported (same evolution contract as
92
+ * `orchCapabilitiesSchema`).
93
+ */
94
+ const platformCapabilitiesSchema = z.object({
95
+ /** Platform ingests periodic `orch.metrics` telemetry pushes. */
96
+ orchMetrics: z.boolean().optional(),
97
+ /** Platform serves the orchestrator-initiated `oidc.mint.request` RPC. */
98
+ oidcMint: z.boolean().optional()
99
+ }).passthrough();
100
+ /** Default Platform capabilities advertised to the orchestrator after auth. */
101
+ const PLATFORM_CAPABILITIES = Object.freeze({
102
+ orchMetrics: true,
103
+ oidcMint: true
104
+ });
105
+ /**
106
+ * Check whether the Platform advertises a specific capability flag.
107
+ *
108
+ * Takes `string` (not `keyof`) because a newer Platform may advertise flags the
109
+ * current orchestrator build doesn't know about. Returns false if capabilities
110
+ * is undefined (nothing advertised yet) or the flag is missing/false.
111
+ *
112
+ * NOTE: "undefined → false" here is the plain reader semantics. A feature-gated
113
+ * SEND that must stay backward-safe against a pre-capability Platform (which
114
+ * never advertises) treats "nothing advertised yet" as optimistic-send — that
115
+ * layer lives in the orchestrator's `sendIfPlatformSupports`, not here.
116
+ */
117
+ function hasPlatformCapability(capabilities, flag) {
118
+ return capabilities?.[flag] === true;
119
+ }
120
+ /**
121
+ * Orchestrator -> Agent capabilities, advertised on `register.ack`. Same
122
+ * evolution contract as the other two directions: every field optional,
123
+ * absent = unsupported, `.passthrough()` preserves a newer orchestrator's
124
+ * unknown flags. Lets the agent learn which optional agent-facing protocol
125
+ * features this orchestrator build supports.
126
+ */
127
+ const orchAgentCapabilitiesSchema = z.object({
128
+ /**
129
+ * Orchestrator acks `artifacts.upload.complete` (with committed|failed) so
130
+ * the agent can fail the workflow step on a lost commit instead of losing
131
+ * the artifact silently. Absent -> agent stays fire-and-forget.
132
+ */
133
+ artifactCompleteAck: z.boolean().optional() }).passthrough();
134
+ /** Default orchestrator -> agent capabilities advertised on register.ack. */
135
+ const ORCH_AGENT_CAPABILITIES = Object.freeze({ artifactCompleteAck: true });
136
+ /**
137
+ * Check whether an orchestrator advertises a specific agent-facing capability
138
+ * flag.
139
+ *
140
+ * Takes `string` (not `keyof`) because a newer orchestrator may advertise flags
141
+ * this agent build doesn't know about. Returns false if capabilities is
142
+ * undefined (pre-capability orchestrator) or the flag is missing/false.
143
+ */
144
+ function hasOrchAgentCapability(capabilities, flag) {
145
+ return capabilities?.[flag] === true;
146
+ }
63
147
  //#endregion
64
- export { ORCH_CAPABILITIES, OrchRole, hasOrchCapability, orchCapabilitiesSchema };
148
+ export { ORCH_AGENT_CAPABILITIES, ORCH_CAPABILITIES, OrchRole, PLATFORM_CAPABILITIES, hasOrchAgentCapability, hasOrchCapability, hasPlatformCapability, orchAgentCapabilitiesSchema, orchCapabilitiesSchema, platformCapabilitiesSchema };
65
149
 
66
150
  //# sourceMappingURL=capabilities.js.map
@@ -35,12 +35,55 @@ export declare const ackSchema: z.ZodObject<{
35
35
  type: z.ZodLiteral<"ack">;
36
36
  messageId: z.ZodString;
37
37
  }, z.core.$strip>;
38
- /** Negative acknowledgment - message received but could not be processed. */
38
+ /**
39
+ * Negative acknowledgment - message received but could not be processed.
40
+ *
41
+ * Doubles as the version-skew diagnosability signal: when a peer receives a
42
+ * protocol message type it does not understand, it replies with a NACK naming
43
+ * the unsupported `receivedType` instead of silently dropping the frame (which
44
+ * otherwise surfaces only as a downstream proxy timeout). `messageId` correlates
45
+ * the NACK to a request/response frame when the offending frame carried one; a
46
+ * fire-and-forget control frame omits it and `receivedType` is the diagnostic
47
+ * anchor. Both are optional so an uncorrelatable skew frame still yields a valid
48
+ * NACK.
49
+ */
39
50
  export declare const nackSchema: z.ZodObject<{
40
51
  type: z.ZodLiteral<"nack">;
41
- messageId: z.ZodString;
52
+ messageId: z.ZodOptional<z.ZodString>;
53
+ receivedType: z.ZodOptional<z.ZodString>;
42
54
  reason: z.ZodString;
43
55
  }, z.core.$strip>;
56
+ export type Nack = z.infer<typeof nackSchema>;
57
+ /**
58
+ * Message types that are NEVER answered with an unsupported-message NACK when
59
+ * they fail a direction's recognition chain:
60
+ * - `nack` — loop guard: a malformed NACK must not trigger a NACK-of-NACK.
61
+ * - `log.chunk` / `orch-log.chunk` — pure streaming frames. A NACK cannot be
62
+ * correlated to a stream and would only add noise; these stay drop-and-warn.
63
+ */
64
+ export declare const NACK_EXEMPT_MESSAGE_TYPES: ReadonlySet<string>;
65
+ /**
66
+ * Build an unsupported-message NACK for a frame that failed every schema in a
67
+ * direction's recognition chain (version skew: the peer sent a type this build
68
+ * does not understand).
69
+ *
70
+ * Returns `null` — meaning "do not NACK, stay drop-and-warn" — when:
71
+ * - `raw` is not an object carrying a non-empty string `type` (genuinely
72
+ * malformed garbage, not a recognizable-but-unsupported message); OR
73
+ * - the `type` is in `NACK_EXEMPT_MESSAGE_TYPES` (loop guard + streaming); OR
74
+ * - the `type` is in `knownTypes` — a KNOWN message type that failed the
75
+ * direction's recognition chain is malformed (e.g. an oversized field past
76
+ * its length bound), not version skew. The caller must close the connection,
77
+ * never keep it alive with a NACK; only a genuinely-unknown type is a skew
78
+ * signal.
79
+ *
80
+ * `side` names the local peer emitting the NACK (the behind party) for the
81
+ * operator-facing upgrade hint, matching the lock-window "upgrade the
82
+ * orchestrator/Platform" wording. `knownTypes` is the set of message types this
83
+ * build recognizes for the given direction (derived from the schema
84
+ * discriminators by the caller).
85
+ */
86
+ export declare function buildUnsupportedMessageNack(raw: unknown, side: 'orchestrator' | 'platform', knownTypes: ReadonlySet<string>): z.infer<typeof nackSchema> | null;
44
87
  /** Protocol-level error message. */
45
88
  export declare const errorSchema: z.ZodObject<{
46
89
  type: z.ZodLiteral<"error">;
@@ -37,12 +37,73 @@ const ackSchema = z.object({
37
37
  type: z.literal("ack"),
38
38
  messageId: z.string()
39
39
  });
40
- /** Negative acknowledgment - message received but could not be processed. */
40
+ /**
41
+ * Negative acknowledgment - message received but could not be processed.
42
+ *
43
+ * Doubles as the version-skew diagnosability signal: when a peer receives a
44
+ * protocol message type it does not understand, it replies with a NACK naming
45
+ * the unsupported `receivedType` instead of silently dropping the frame (which
46
+ * otherwise surfaces only as a downstream proxy timeout). `messageId` correlates
47
+ * the NACK to a request/response frame when the offending frame carried one; a
48
+ * fire-and-forget control frame omits it and `receivedType` is the diagnostic
49
+ * anchor. Both are optional so an uncorrelatable skew frame still yields a valid
50
+ * NACK.
51
+ */
41
52
  const nackSchema = z.object({
42
53
  type: z.literal("nack"),
43
- messageId: z.string(),
54
+ /** Correlation id echoed from the offending frame, when it carried one. */
55
+ messageId: z.string().optional(),
56
+ /** The unsupported/unrecognized message type that triggered this NACK. */
57
+ receivedType: z.string().optional(),
44
58
  reason: z.string()
45
59
  });
60
+ /**
61
+ * Message types that are NEVER answered with an unsupported-message NACK when
62
+ * they fail a direction's recognition chain:
63
+ * - `nack` — loop guard: a malformed NACK must not trigger a NACK-of-NACK.
64
+ * - `log.chunk` / `orch-log.chunk` — pure streaming frames. A NACK cannot be
65
+ * correlated to a stream and would only add noise; these stay drop-and-warn.
66
+ */
67
+ const NACK_EXEMPT_MESSAGE_TYPES = /* @__PURE__ */ new Set([
68
+ "nack",
69
+ "log.chunk",
70
+ "orch-log.chunk"
71
+ ]);
72
+ /**
73
+ * Build an unsupported-message NACK for a frame that failed every schema in a
74
+ * direction's recognition chain (version skew: the peer sent a type this build
75
+ * does not understand).
76
+ *
77
+ * Returns `null` — meaning "do not NACK, stay drop-and-warn" — when:
78
+ * - `raw` is not an object carrying a non-empty string `type` (genuinely
79
+ * malformed garbage, not a recognizable-but-unsupported message); OR
80
+ * - the `type` is in `NACK_EXEMPT_MESSAGE_TYPES` (loop guard + streaming); OR
81
+ * - the `type` is in `knownTypes` — a KNOWN message type that failed the
82
+ * direction's recognition chain is malformed (e.g. an oversized field past
83
+ * its length bound), not version skew. The caller must close the connection,
84
+ * never keep it alive with a NACK; only a genuinely-unknown type is a skew
85
+ * signal.
86
+ *
87
+ * `side` names the local peer emitting the NACK (the behind party) for the
88
+ * operator-facing upgrade hint, matching the lock-window "upgrade the
89
+ * orchestrator/Platform" wording. `knownTypes` is the set of message types this
90
+ * build recognizes for the given direction (derived from the schema
91
+ * discriminators by the caller).
92
+ */
93
+ function buildUnsupportedMessageNack(raw, side, knownTypes) {
94
+ if (typeof raw !== "object" || raw === null) return null;
95
+ const frame = raw;
96
+ if (typeof frame.type !== "string" || frame.type.length === 0) return null;
97
+ if (NACK_EXEMPT_MESSAGE_TYPES.has(frame.type)) return null;
98
+ if (knownTypes.has(frame.type)) return null;
99
+ const nack = {
100
+ type: "nack",
101
+ receivedType: frame.type,
102
+ reason: `unsupported message type "${frame.type}" — this ${side} does not understand it (protocol version skew); upgrade the ${side}`
103
+ };
104
+ if (typeof frame.messageId === "string" && frame.messageId.length > 0) nack.messageId = frame.messageId;
105
+ return nack;
106
+ }
46
107
  /** Protocol-level error message. */
47
108
  const errorSchema = z.object({
48
109
  type: z.literal("error"),
@@ -50,6 +111,6 @@ const errorSchema = z.object({
50
111
  message: z.string()
51
112
  });
52
113
  //#endregion
53
- export { WS_MAX_PAYLOAD_BYTES, ackSchema, errorSchema, heartbeatSchema, nackSchema };
114
+ export { NACK_EXEMPT_MESSAGE_TYPES, WS_MAX_PAYLOAD_BYTES, ackSchema, buildUnsupportedMessageNack, errorSchema, heartbeatSchema, nackSchema };
54
115
 
55
116
  //# sourceMappingURL=common.js.map
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Wire envelope for a browser-sealed dashboard write.
3
+ *
4
+ * Under the `encrypted` dashboard-write posture the browser seals the plaintext
5
+ * value to the orchestrator's published X25519 encryption key before it leaves
6
+ * the page, so the hosted Platform relays only opaque ciphertext. The envelope
7
+ * is the exact shape the orchestrator's `decryptDashboardSealedWrite` consumes:
8
+ * an ephemeral X25519 public key (base64 DER-SPKI) and the AES-256-GCM output
9
+ * packed as `IV || authTag || ciphertext` (base64), plus the `keyId` (`kid`)
10
+ * naming which published encryption key the browser sealed to.
11
+ *
12
+ * Browser-safe: pure Zod, no node built-ins, so the dashboard SPA imports it
13
+ * directly.
14
+ */
15
+ import { z } from 'zod';
16
+ export declare const dashboardSealedEnvelopeSchema: z.ZodObject<{
17
+ keyId: z.ZodString;
18
+ ephemeralPublicKey: z.ZodString;
19
+ encrypted: z.ZodString;
20
+ }, z.core.$strip>;
21
+ export type DashboardSealedEnvelope = z.infer<typeof dashboardSealedEnvelopeSchema>;
22
+ /**
23
+ * The orchestrator's published X25519 dashboard-encryption public key, as an
24
+ * OKP JWK (`kty:'OKP'`, `crv:'X25519'`, `use:'enc'`, `x` = the raw 32-byte
25
+ * public key base64url-encoded, `kid` = its RFC 7638 thumbprint).
26
+ *
27
+ * `.passthrough()` because a JWK may legitimately carry members a given peer
28
+ * does not know; only the members the seal actually needs are validated.
29
+ */
30
+ export declare const dashboardEncryptionJwkSchema: z.ZodObject<{
31
+ kty: z.ZodLiteral<"OKP">;
32
+ crv: z.ZodLiteral<"X25519">;
33
+ x: z.ZodString;
34
+ kid: z.ZodString;
35
+ use: z.ZodOptional<z.ZodLiteral<"enc">>;
36
+ }, z.core.$loose>;
37
+ export type DashboardEncryptionJwk = z.infer<typeof dashboardEncryptionJwkSchema>;
38
+ /**
39
+ * Structured error codes the orchestrator returns (in a `.set.response`
40
+ * `error` field) when a sealed / plaintext write cannot be honored under the
41
+ * `encrypted` posture. The dashboard renders a fail-closed affordance keyed on
42
+ * these codes — never a silent fallback to plaintext-through-Platform.
43
+ */
44
+ export declare const DashboardSealedWriteError: z.ZodEnum<{
45
+ decryption_failed: "decryption_failed";
46
+ encryption_unavailable: "encryption_unavailable";
47
+ missing_value: "missing_value";
48
+ operation_requires_encryption: "operation_requires_encryption";
49
+ unknown_encryption_key: "unknown_encryption_key";
50
+ }>;
51
+ export type DashboardSealedWriteError = z.infer<typeof DashboardSealedWriteError>;
52
+ //# sourceMappingURL=dashboard-sealed-write.d.ts.map
@@ -0,0 +1,57 @@
1
+ import "../../rolldown-runtime-ClRpJifh.js";
2
+ import { z } from "zod";
3
+ //#region src/protocol/messages/dashboard-sealed-write.ts
4
+ /**
5
+ * Wire envelope for a browser-sealed dashboard write.
6
+ *
7
+ * Under the `encrypted` dashboard-write posture the browser seals the plaintext
8
+ * value to the orchestrator's published X25519 encryption key before it leaves
9
+ * the page, so the hosted Platform relays only opaque ciphertext. The envelope
10
+ * is the exact shape the orchestrator's `decryptDashboardSealedWrite` consumes:
11
+ * an ephemeral X25519 public key (base64 DER-SPKI) and the AES-256-GCM output
12
+ * packed as `IV || authTag || ciphertext` (base64), plus the `keyId` (`kid`)
13
+ * naming which published encryption key the browser sealed to.
14
+ *
15
+ * Browser-safe: pure Zod, no node built-ins, so the dashboard SPA imports it
16
+ * directly.
17
+ */
18
+ const dashboardSealedEnvelopeSchema = z.object({
19
+ /** The `kid` of the orchestrator encryption key the browser sealed to. */
20
+ keyId: z.string().min(1),
21
+ /** Ephemeral X25519 public key, base64-encoded DER-SPKI. */
22
+ ephemeralPublicKey: z.string().min(1),
23
+ /** AES-256-GCM output as base64 `IV(12) || authTag(16) || ciphertext`. */
24
+ encrypted: z.string().min(1)
25
+ });
26
+ /**
27
+ * The orchestrator's published X25519 dashboard-encryption public key, as an
28
+ * OKP JWK (`kty:'OKP'`, `crv:'X25519'`, `use:'enc'`, `x` = the raw 32-byte
29
+ * public key base64url-encoded, `kid` = its RFC 7638 thumbprint).
30
+ *
31
+ * `.passthrough()` because a JWK may legitimately carry members a given peer
32
+ * does not know; only the members the seal actually needs are validated.
33
+ */
34
+ const dashboardEncryptionJwkSchema = z.object({
35
+ kty: z.literal("OKP"),
36
+ crv: z.literal("X25519"),
37
+ x: z.string().min(1),
38
+ kid: z.string().min(1),
39
+ use: z.literal("enc").optional()
40
+ }).passthrough();
41
+ /**
42
+ * Structured error codes the orchestrator returns (in a `.set.response`
43
+ * `error` field) when a sealed / plaintext write cannot be honored under the
44
+ * `encrypted` posture. The dashboard renders a fail-closed affordance keyed on
45
+ * these codes — never a silent fallback to plaintext-through-Platform.
46
+ */
47
+ const DashboardSealedWriteError = z.enum([
48
+ "operation_requires_encryption",
49
+ "unknown_encryption_key",
50
+ "encryption_unavailable",
51
+ "decryption_failed",
52
+ "missing_value"
53
+ ]);
54
+ //#endregion
55
+ export { DashboardSealedWriteError, dashboardEncryptionJwkSchema, dashboardSealedEnvelopeSchema };
56
+
57
+ //# sourceMappingURL=dashboard-sealed-write.js.map