@kici-dev/orchestrator 0.1.9 → 0.1.10

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.
@@ -15,6 +15,19 @@ import type { ScalerStateStore, ScalerStateRecovery } from './scaler-state-store
15
15
  * combined with the scaler's `defaults.resources`, applying the request<->limit
16
16
  * mirroring rule. Caps aggregate `requests`; backends use `limits`.
17
17
  */
18
+ /**
19
+ * Resolve the orchestrator WebSocket URL a scaler-spawned agent should dial.
20
+ *
21
+ * 1. Per-scaler `orchestratorUrl` (scalers.yaml) wins — required for container
22
+ * agents (host.docker.internal / LAN IP) and Firecracker VMs (bridge gateway
23
+ * IP), which cannot reach the orchestrator over the host's loopback.
24
+ * 2. `KICI_ORCHESTRATOR_URL` env override.
25
+ * 3. Default `ws://127.0.0.1:<orchestrator-port>/ws` — for local (bare-metal)
26
+ * agents that share the host. The port is the orchestrator's own bind port
27
+ * (`KICI_PORT`, default 4000), NOT the agent's 8080 default; pointing local
28
+ * agents at 8080 leaves them unable to reach the orchestrator.
29
+ */
30
+ export declare function resolveScalerOrchestratorUrl(configUrl: string | undefined, envUrl: string | undefined, port: string | number | undefined): string;
18
31
  export interface ResolvedResources {
19
32
  requests: {
20
33
  cpus: number;
package/dist/server.js CHANGED
@@ -3,7 +3,7 @@ import { dirname as __cjs_dirname } from "node:path";
3
3
  __cjs_dirname(__cjs_fileURLToPath(import.meta.url));
4
4
  import "node:module";
5
5
  import { BaseColdStore, RingBuffer, createDb, createHealthRoutes, createLogger, createMeter, createMetricsRoutes, createPool, createS3Client, encodeKeySegment, enrichRequestContext, formatDuration, getPrometheusExporter, getReconnectDelay, getRequestContext, guardStartup, initTelemetry, requestContext, serializeError, setServiceName, setupGracefulShutdown, sha256, toErrorMessage, validateRequiredTools } from "@kici-dev/shared";
6
- import { ALLOWED_SYSTEM_VARS, AccessLogAction, AccessLogOutcome, AccessLogSource, AccessLogTargetType, ActorType, CheckRunConclusion, EVENT_LOG_PAYLOAD_CHUNK_BYTES, EventLogPayloadStreamError, EventLogSource, EventLogStatus, ExecutionJobStatus, ExecutionRunStatus, ExecutionStepStatus, KICI_AGENT_ENV_PREFIX, KNOWN_ROLES, MIN_PROTOCOL_VERSION, ORCH_CAPABILITIES, OrchRole, PROTOCOL_VERSION, PayloadOmittedReason, RegisterableTriggerType, SCHEMA_VERSION, ScalerBackendType, SourceSubtype, TERMINAL_JOB_STATES, TERMINAL_RUN_STATES, WEBHOOK_RELAY_MAX_BODY_BYTES, WS_CLOSE_AGENT_AUTH_FAILED, WS_CLOSE_AUTH_TIMEOUT, WS_CLOSE_GOING_AWAY, WS_CLOSE_HEARTBEAT_TIMEOUT, WS_CLOSE_INVALID_MESSAGE, WS_CLOSE_PROTOCOL_ERROR, WS_CLOSE_RUN_NOT_FOUND, WS_CLOSE_UNAUTHORIZED, WS_MAX_PAYLOAD_BYTES, WsRateLimiter, accessLogWarmSqlCase, agentAuthRequestSchema, agentToOrchestratorMessageSchema, agentTypeLabel, createWorkflowDecision, dashboardRunDetailApiResponseSchema, dashboardStepLogsApiResponseSchema, deriveOsArchLabels, flattenActor, getAccessLogColdDays, getSecretAuditLogColdDays, isLockDynamicJobFn, isLockInlineValue, isLockStaticJob, joinRequestSchema, logPullPlatformToOrchSchema, matchAllWorkflows, matchScopePattern, minAccessLogWarmDays, minSecretAuditLogWarmDays, observeSubscribeSchema, peerAuthRequestSchema, peerFromPeerMessageSchema, peerHelloResponseSchema, peerHelloSchema, platformToOrchestratorMessageSchema, resolveRoleLabels, resolveSecretsForEnvironment, scalerLabel, secretAuditLogWarmSqlCase, shouldRecordAccess, shouldRecordSecretResolve, stringifyActor, stripScopePrefix, testEventSchema } from "@kici-dev/engine";
6
+ import { ALLOWED_SYSTEM_VARS, AccessLogAction, AccessLogOutcome, AccessLogSource, AccessLogTargetType, ActorType, CheckRunConclusion, EVENT_LOG_PAYLOAD_CHUNK_BYTES, EventLogPayloadStreamError, EventLogSource, EventLogStatus, ExecutionJobStatus, ExecutionRunStatus, ExecutionStepStatus, KICI_AGENT_ENV_PREFIX, KNOWN_ROLES, MIN_PROTOCOL_VERSION, ORCH_CAPABILITIES, OrchRole, PROTOCOL_VERSION, PayloadOmittedReason, RegisterableTriggerType, SCHEMA_VERSION, ScalerBackendType, SourceSubtype, TERMINAL_JOB_STATES, TERMINAL_RUN_STATES, WEBHOOK_RELAY_MAX_BODY_BYTES, WS_CLOSE_AGENT_AUTH_FAILED, WS_CLOSE_AUTH_TIMEOUT, WS_CLOSE_GOING_AWAY, WS_CLOSE_HEARTBEAT_TIMEOUT, WS_CLOSE_INVALID_MESSAGE, WS_CLOSE_PROTOCOL_ERROR, WS_CLOSE_RUN_NOT_FOUND, WS_CLOSE_UNAUTHORIZED, WS_MAX_PAYLOAD_BYTES, WsRateLimiter, accessLogWarmSqlCase, agentAuthRequestSchema, agentToOrchestratorMessageSchema, agentTypeLabel, createWorkflowDecision, dashboardRunDetailApiResponseSchema, dashboardStepLogsApiResponseSchema, deriveOsArchLabels, flattenActor, getAccessLogColdDays, getSecretAuditLogColdDays, isLockDynamicJobFn, isLockInlineValue, isLockStaticJob, isSelfReportedLabel, joinRequestSchema, logPullPlatformToOrchSchema, matchAllWorkflows, matchScopePattern, minAccessLogWarmDays, minSecretAuditLogWarmDays, observeSubscribeSchema, peerAuthRequestSchema, peerFromPeerMessageSchema, peerHelloResponseSchema, peerHelloSchema, platformToOrchestratorMessageSchema, resolveRoleLabels, resolveSecretsForEnvironment, scalerAgentLabels, scalerLabel, secretAuditLogWarmSqlCase, shouldRecordAccess, shouldRecordSecretResolve, stringifyActor, stripScopePrefix, testEventSchema } from "@kici-dev/engine";
7
7
  import { verifySignature } from "@kici-dev/engine/webhook/signature";
8
8
  import { X509Certificate, createCipheriv, createDecipheriv, createHmac, createPrivateKey, createPublicKey, diffieHellman, generateKeyPairSync, hkdfSync, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
9
9
  import os, { cpus, freemem, homedir, hostname, release, tmpdir, totalmem, uptime, userInfo, version } from "node:os";
@@ -15151,7 +15151,7 @@ var init_peer_client = __esmMin((() => {
15151
15151
  init_peer_crypto();
15152
15152
  init_peer_credentials();
15153
15153
  logger$73 = createLogger({ prefix: "peer-client" });
15154
- SOFTWARE_VERSION$1 = "0.1.9";
15154
+ SOFTWARE_VERSION$1 = "0.1.10";
15155
15155
  PeerClient$1 = class {
15156
15156
  ws = null;
15157
15157
  _state = "disconnected";
@@ -16614,7 +16614,7 @@ var init_peer_handler = __esmMin((() => {
16614
16614
  init_peer_crypto();
16615
16615
  init_join_token();
16616
16616
  logger$72 = createLogger({ prefix: "peer-handler" });
16617
- SOFTWARE_VERSION = "0.1.9";
16617
+ SOFTWARE_VERSION = "0.1.10";
16618
16618
  RATE_LIMIT_MAX = 5;
16619
16619
  RATE_LIMIT_WINDOW_MS = 6e4;
16620
16620
  }));
@@ -24774,13 +24774,25 @@ var init_check_run_reporter = __esmMin((() => {
24774
24774
  * returns `false` after closing the WS on the first violation, in which
24775
24775
  * case the caller MUST stop processing.
24776
24776
  */
24777
+ /**
24778
+ * WebSocket close reasons are capped at 123 UTF-8 bytes (RFC 6455 §5.5.1).
24779
+ * A reason longer than that makes `ws.close()` throw a RangeError, which —
24780
+ * thrown from an async message handler — surfaces as an unhandled rejection
24781
+ * and skips the close entirely. Truncate on a byte boundary and drop any
24782
+ * trailing partial multi-byte char.
24783
+ */
24784
+ function truncateCloseReason(reason) {
24785
+ const bytes = Buffer.from(reason, "utf-8");
24786
+ if (bytes.length <= 123) return reason;
24787
+ return bytes.subarray(0, 123).toString("utf-8").replace(/�+$/, "");
24788
+ }
24777
24789
  function enforceRegisterAuthGates(authState, payload, ws, agentIdToTokenId) {
24778
24790
  if (authState === void 0) return true;
24779
24791
  const { tokenId, tokenLabels, tokenAgentType, tokenCreatedBy } = authState;
24780
24792
  const { agentId, labels } = payload;
24781
24793
  if (tokenLabels !== void 0 && tokenLabels !== null) {
24782
24794
  const allowedSet = new Set(tokenLabels);
24783
- const elevated = labels.filter((l) => !allowedSet.has(l));
24795
+ const elevated = labels.filter((l) => !allowedSet.has(l) && !isSelfReportedLabel(l));
24784
24796
  if (elevated.length > 0) {
24785
24797
  logger$59.warn("Agent register-time label-scope violation: wire labels exceed token-bound set", {
24786
24798
  agentId,
@@ -24788,7 +24800,7 @@ function enforceRegisterAuthGates(authState, payload, ws, agentIdToTokenId) {
24788
24800
  wireLabels: labels,
24789
24801
  elevated
24790
24802
  });
24791
- ws.close(WS_CLOSE_AGENT_AUTH_FAILED, `Agent labels exceed token-bound scope: ${elevated.join(",")}`);
24803
+ ws.close(WS_CLOSE_AGENT_AUTH_FAILED, truncateCloseReason(`Agent labels exceed token-bound scope: ${elevated.join(",")}`));
24792
24804
  return false;
24793
24805
  }
24794
24806
  }
@@ -24798,7 +24810,7 @@ function enforceRegisterAuthGates(authState, payload, ws, agentIdToTokenId) {
24798
24810
  tokenCreatedBy,
24799
24811
  tokenId
24800
24812
  });
24801
- ws.close(WS_CLOSE_AGENT_AUTH_FAILED, `Ephemeral token bound to a different agentId: expected ${tokenCreatedBy}, got ${agentId}`);
24813
+ ws.close(WS_CLOSE_AGENT_AUTH_FAILED, truncateCloseReason(`Ephemeral token bound to a different agentId: expected ${tokenCreatedBy}, got ${agentId}`));
24802
24814
  return false;
24803
24815
  }
24804
24816
  if (tokenId !== void 0) {
@@ -34104,15 +34116,15 @@ var init_admin_config = __esmMin((() => {
34104
34116
  function createHealthRoutes$1(deps = {}) {
34105
34117
  return createHealthRoutes({
34106
34118
  livenessInfo: () => ({
34107
- version: "0.1.9",
34108
- buildDate: "2026-05-26T16:38:18.222Z",
34109
- buildCommit: "54278bfb2",
34110
- sdkVersion: "0.1.9",
34111
- sdkBundleHash: "675aafe4de03e677785ef2794d8f34951b14e2bd1e6f0ea825953d6c2abfe128",
34112
- sharedVersion: "0.1.9",
34119
+ version: "0.1.10",
34120
+ buildDate: "2026-05-26T17:19:08.888Z",
34121
+ buildCommit: "6bf528b56",
34122
+ sdkVersion: "0.1.10",
34123
+ sdkBundleHash: "unknown",
34124
+ sharedVersion: "0.1.10",
34113
34125
  sharedBundleHash: "36a23a454fd75ec35f258d39f254543ec0451c6b543fe3618ce427e6e6369aae",
34114
- engineVersion: "0.1.9",
34115
- engineBundleHash: "b704538612ec796a5668765bd55e0eaeaf1bad8a2afa508f9e20ad7b9eb61d21"
34126
+ engineVersion: "0.1.10",
34127
+ engineBundleHash: "dff25bbd7602e853cec6e6e985c6c956ad773e245830273cd52950fff958d4bb"
34116
34128
  }),
34117
34129
  readinessCheck: deps.db ? async () => {
34118
34130
  const checks = {};
@@ -34146,7 +34158,7 @@ function createCapabilitiesRoutes() {
34146
34158
  const app = new Hono();
34147
34159
  app.get("/api/v1/capabilities", (c) => {
34148
34160
  const manifest = {
34149
- orchestratorVersion: "0.1.9",
34161
+ orchestratorVersion: "0.1.10",
34150
34162
  protocolVersion: PROTOCOL_VERSION,
34151
34163
  minProtocolVersion: MIN_PROTOCOL_VERSION
34152
34164
  };
@@ -36583,17 +36595,13 @@ var init_container_backend = __esmMin((() => {
36583
36595
  const stripped = key.slice(KICI_AGENT_ENV_PREFIX.length);
36584
36596
  if (stripped.length > 0) agentEnvForwarded.push(`${stripped}=${value}`);
36585
36597
  }
36598
+ const fullLabels = scalerAgentLabels(labelSet, this.type, this.name, this.roles);
36586
36599
  let agentToken;
36587
- if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId, labelSet, this.tokenTtlMs);
36600
+ if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId, fullLabels, this.tokenTtlMs);
36588
36601
  const env = [
36589
36602
  `KICI_ORCHESTRATOR_URL=${orchestratorUrl}`,
36590
36603
  `KICI_AGENT_ID=${agentId}`,
36591
- `KICI_LABELS=${[
36592
- ...labelSet,
36593
- `kici:agent:${this.type}`,
36594
- `kici:scaler:${this.name}`,
36595
- ...resolveRoleLabels(this.roles)
36596
- ].join(",")}`,
36604
+ `KICI_LABELS=${fullLabels.join(",")}`,
36597
36605
  `KICI_SCALER_MANAGED=1`,
36598
36606
  `KICI_EXECUTION_MODE=bare-metal`,
36599
36607
  ...agentToken ? [`KICI_AGENT_TOKEN=${agentToken}`] : [],
@@ -36889,15 +36897,11 @@ var init_bare_metal_backend = __esmMin((() => {
36889
36897
  const strippedKey = key.slice(KICI_AGENT_ENV_PREFIX.length);
36890
36898
  if (strippedKey.length > 0) env[strippedKey] = value;
36891
36899
  }
36892
- if (this.tokenStore) env.KICI_AGENT_TOKEN = await this.tokenStore.createEphemeral(agentId, labelSet, this.tokenTtlMs);
36900
+ const fullLabels = scalerAgentLabels(labelSet, this.type, this.name, this.roles);
36901
+ if (this.tokenStore) env.KICI_AGENT_TOKEN = await this.tokenStore.createEphemeral(agentId, fullLabels, this.tokenTtlMs);
36893
36902
  env.KICI_ORCHESTRATOR_URL = orchestratorUrl;
36894
36903
  env.KICI_AGENT_ID = agentId;
36895
- env.KICI_LABELS = [
36896
- ...labelSet,
36897
- `kici:agent:${this.type}`,
36898
- `kici:scaler:${this.name}`,
36899
- ...resolveRoleLabels(this.roles)
36900
- ].join(",");
36904
+ env.KICI_LABELS = fullLabels.join(",");
36901
36905
  env.KICI_SCALER_MANAGED = "1";
36902
36906
  env.KICI_EXECUTION_MODE = "bare-metal";
36903
36907
  env.KICI_PORT = "0";
@@ -37647,18 +37651,14 @@ var init_firecracker_backend = __esmMin((() => {
37647
37651
  if (chmodLoosenInterval) clearInterval(chmodLoosenInterval);
37648
37652
  }
37649
37653
  if (!ready) throw new Error(`Firecracker API socket not ready within 5s for agent ${agentId}`);
37654
+ const fullLabels = scalerAgentLabels(labelSet, this.type, this.name, this.roles);
37650
37655
  let agentToken;
37651
- if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId, labelSet, this.tokenTtlMs);
37656
+ if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId, fullLabels, this.tokenTtlMs);
37652
37657
  const acceptedEnv = this.buildForwardedEnv(matchedLabelSet, agentId);
37653
37658
  await api.putMmds({ latest: { "meta-data": {
37654
37659
  "kici-orchestrator-url": orchestratorUrl,
37655
37660
  "kici-agent-id": agentId,
37656
- "kici-labels": [
37657
- ...labelSet,
37658
- `kici:agent:${this.type}`,
37659
- `kici:scaler:${this.name}`,
37660
- ...resolveRoleLabels(this.roles)
37661
- ].join(","),
37661
+ "kici-labels": fullLabels.join(","),
37662
37662
  "kici-scaler-managed": "1",
37663
37663
  "kici-gateway-ip": this.gateway,
37664
37664
  ...agentToken ? { "kici-agent-token": agentToken } : {},
@@ -38735,6 +38735,29 @@ var init_machine_ledger = __esmMin((() => {
38735
38735
  * and manages the agent lifecycle from spawn to destroy.
38736
38736
  */
38737
38737
  /**
38738
+ * Resolved per-job resource amounts (cpus + bytes) for both `requests` and
38739
+ * `limits`. The scaler manager produces this from the job's declared resources
38740
+ * combined with the scaler's `defaults.resources`, applying the request<->limit
38741
+ * mirroring rule. Caps aggregate `requests`; backends use `limits`.
38742
+ */
38743
+ /**
38744
+ * Resolve the orchestrator WebSocket URL a scaler-spawned agent should dial.
38745
+ *
38746
+ * 1. Per-scaler `orchestratorUrl` (scalers.yaml) wins — required for container
38747
+ * agents (host.docker.internal / LAN IP) and Firecracker VMs (bridge gateway
38748
+ * IP), which cannot reach the orchestrator over the host's loopback.
38749
+ * 2. `KICI_ORCHESTRATOR_URL` env override.
38750
+ * 3. Default `ws://127.0.0.1:<orchestrator-port>/ws` — for local (bare-metal)
38751
+ * agents that share the host. The port is the orchestrator's own bind port
38752
+ * (`KICI_PORT`, default 4000), NOT the agent's 8080 default; pointing local
38753
+ * agents at 8080 leaves them unable to reach the orchestrator.
38754
+ */
38755
+ function resolveScalerOrchestratorUrl(configUrl, envUrl, port) {
38756
+ if (configUrl) return configUrl;
38757
+ if (envUrl) return envUrl;
38758
+ return `ws://127.0.0.1:${port ?? "4000"}/ws`;
38759
+ }
38760
+ /**
38738
38761
  * Apply the request<->limit mirroring rule: if only one side is set, copy it
38739
38762
  * to the other; if neither is set, return undefined; if both are set, leave them.
38740
38763
  *
@@ -39646,9 +39669,7 @@ var init_manager = __esmMin((() => {
39646
39669
  });
39647
39670
  }
39648
39671
  getOrchestratorUrl(backendName) {
39649
- const configUrl = this.scalerUrls.get(backendName);
39650
- if (configUrl) return configUrl;
39651
- return process.env.KICI_ORCHESTRATOR_URL ?? "ws://localhost:8080/ws";
39672
+ return resolveScalerOrchestratorUrl(this.scalerUrls.get(backendName), process.env.KICI_ORCHESTRATOR_URL, process.env.KICI_PORT);
39652
39673
  }
39653
39674
  /**
39654
39675
  * Create a per-agent event emitter closure to pass to backend.spawn().
@@ -50298,14 +50319,14 @@ var init_worker_core = __esmMin((() => {
50298
50319
  init_agent_handler();
50299
50320
  init_worker_status();
50300
50321
  init_agent_heartbeat();
50301
- ORCHESTRATOR_VERSION$1 = "0.1.9";
50302
- WORKER_BUILD_COMMIT = "54278bfb2";
50303
- WORKER_SDK_VERSION = "0.1.9";
50304
- WORKER_SDK_BUNDLE_HASH = "675aafe4de03e677785ef2794d8f34951b14e2bd1e6f0ea825953d6c2abfe128";
50305
- WORKER_SHARED_VERSION = "0.1.9";
50322
+ ORCHESTRATOR_VERSION$1 = "0.1.10";
50323
+ WORKER_BUILD_COMMIT = "6bf528b56";
50324
+ WORKER_SDK_VERSION = "0.1.10";
50325
+ WORKER_SDK_BUNDLE_HASH = "unknown";
50326
+ WORKER_SHARED_VERSION = "0.1.10";
50306
50327
  WORKER_SHARED_BUNDLE_HASH = "36a23a454fd75ec35f258d39f254543ec0451c6b543fe3618ce427e6e6369aae";
50307
- WORKER_ENGINE_VERSION = "0.1.9";
50308
- WORKER_ENGINE_BUNDLE_HASH = "b704538612ec796a5668765bd55e0eaeaf1bad8a2afa508f9e20ad7b9eb61d21";
50328
+ WORKER_ENGINE_VERSION = "0.1.10";
50329
+ WORKER_ENGINE_BUNDLE_HASH = "dff25bbd7602e853cec6e6e985c6c956ad773e245830273cd52950fff958d4bb";
50309
50330
  logger$1 = createLogger({ prefix: "worker" });
50310
50331
  DRAIN_TIMEOUT_MS = 3e5;
50311
50332
  }));
@@ -50326,14 +50347,14 @@ var init_worker_core = __esmMin((() => {
50326
50347
  * Graceful shutdown in reverse order:
50327
50348
  * Platform client -> agent WS -> heartbeat -> HTTP -> DB
50328
50349
  */
50329
- const ORCHESTRATOR_VERSION = "0.1.9";
50330
- const BUILD_COMMIT = "54278bfb2";
50331
- const SDK_VERSION = "0.1.9";
50332
- const SDK_BUNDLE_HASH = "675aafe4de03e677785ef2794d8f34951b14e2bd1e6f0ea825953d6c2abfe128";
50333
- const SHARED_VERSION = "0.1.9";
50350
+ const ORCHESTRATOR_VERSION = "0.1.10";
50351
+ const BUILD_COMMIT = "6bf528b56";
50352
+ const SDK_VERSION = "0.1.10";
50353
+ const SDK_BUNDLE_HASH = "unknown";
50354
+ const SHARED_VERSION = "0.1.10";
50334
50355
  const SHARED_BUNDLE_HASH = "36a23a454fd75ec35f258d39f254543ec0451c6b543fe3618ce427e6e6369aae";
50335
- const ENGINE_VERSION = "0.1.9";
50336
- const ENGINE_BUNDLE_HASH = "b704538612ec796a5668765bd55e0eaeaf1bad8a2afa508f9e20ad7b9eb61d21";
50356
+ const ENGINE_VERSION = "0.1.10";
50357
+ const ENGINE_BUNDLE_HASH = "dff25bbd7602e853cec6e6e985c6c956ad773e245830273cd52950fff958d4bb";
50337
50358
  const otelSdk = initTelemetry({
50338
50359
  serviceName: "kici-orchestrator",
50339
50360
  otlpEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT
@@ -9,7 +9,7 @@ import { z } from "zod";
9
9
  import { LOGGER_ENV_VARS, defineEnv, validateUnknownKiciVars } from "@kici-dev/shared/env";
10
10
  import WebSocket from "ws";
11
11
  import { chmodSync, closeSync, createReadStream, createWriteStream, mkdirSync, mkdtempSync, openSync, promises, readFileSync, rmSync, statSync, unlinkSync, unwatchFile, watchFile, writeFileSync } from "node:fs";
12
- import { ALLOWED_SYSTEM_VARS, AccessLogAction, AccessLogOutcome, AccessLogSource, AccessLogTargetType, ActorType, CheckRunConclusion, EventLogSource, EventLogStatus, ExecutionJobStatus, ExecutionRunStatus, ExecutionStepStatus, KICI_AGENT_ENV_PREFIX, KNOWN_ROLES, MIN_PROTOCOL_VERSION, PROTOCOL_VERSION, PayloadOmittedReason, RegisterableTriggerType, SCHEMA_VERSION, ScalerBackendType, SourceSubtype, TERMINAL_JOB_STATES, TERMINAL_RUN_STATES, WS_CLOSE_AGENT_AUTH_FAILED, WS_CLOSE_AUTH_TIMEOUT, WS_CLOSE_GOING_AWAY, WS_CLOSE_HEARTBEAT_TIMEOUT, WS_CLOSE_INVALID_MESSAGE, WS_CLOSE_PROTOCOL_ERROR, WS_CLOSE_RUN_NOT_FOUND, WS_CLOSE_UNAUTHORIZED, WS_MAX_PAYLOAD_BYTES, WsRateLimiter, accessLogWarmSqlCase, agentAuthRequestSchema, agentToOrchestratorMessageSchema, agentTypeLabel, createWorkflowDecision, deriveOsArchLabels, flattenActor, getAccessLogColdDays, getSecretAuditLogColdDays, isLockDynamicJobFn, isLockInlineValue, isLockStaticJob, matchAllWorkflows, minAccessLogWarmDays, minSecretAuditLogWarmDays, observeSubscribeSchema, peerAuthRequestSchema, peerFromPeerMessageSchema, peerHelloResponseSchema, peerHelloSchema, resolveRoleLabels, scalerLabel, secretAuditLogWarmSqlCase, shouldRecordAccess, shouldRecordSecretResolve, testEventSchema } from "@kici-dev/engine";
12
+ import { ALLOWED_SYSTEM_VARS, AccessLogAction, AccessLogOutcome, AccessLogSource, AccessLogTargetType, ActorType, CheckRunConclusion, EventLogSource, EventLogStatus, ExecutionJobStatus, ExecutionRunStatus, ExecutionStepStatus, KICI_AGENT_ENV_PREFIX, KNOWN_ROLES, MIN_PROTOCOL_VERSION, PROTOCOL_VERSION, PayloadOmittedReason, RegisterableTriggerType, SCHEMA_VERSION, ScalerBackendType, SourceSubtype, TERMINAL_JOB_STATES, TERMINAL_RUN_STATES, WS_CLOSE_AGENT_AUTH_FAILED, WS_CLOSE_AUTH_TIMEOUT, WS_CLOSE_GOING_AWAY, WS_CLOSE_HEARTBEAT_TIMEOUT, WS_CLOSE_INVALID_MESSAGE, WS_CLOSE_PROTOCOL_ERROR, WS_CLOSE_RUN_NOT_FOUND, WS_CLOSE_UNAUTHORIZED, WS_MAX_PAYLOAD_BYTES, WsRateLimiter, accessLogWarmSqlCase, agentAuthRequestSchema, agentToOrchestratorMessageSchema, agentTypeLabel, createWorkflowDecision, deriveOsArchLabels, flattenActor, getAccessLogColdDays, getSecretAuditLogColdDays, isLockDynamicJobFn, isLockInlineValue, isLockStaticJob, isSelfReportedLabel, matchAllWorkflows, minAccessLogWarmDays, minSecretAuditLogWarmDays, observeSubscribeSchema, peerAuthRequestSchema, peerFromPeerMessageSchema, peerHelloResponseSchema, peerHelloSchema, resolveRoleLabels, scalerAgentLabels, scalerLabel, secretAuditLogWarmSqlCase, shouldRecordAccess, shouldRecordSecretResolve, testEventSchema } from "@kici-dev/engine";
13
13
  import { access, appendFile, chmod, constants, copyFile, link, mkdir, mkdtemp, open, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
14
14
  import { dirname, join, relative, resolve } from "node:path";
15
15
  import { sql } from "kysely";
@@ -1040,7 +1040,7 @@ var init_peer_client = __esmMin((() => {
1040
1040
  init_peer_crypto();
1041
1041
  init_peer_credentials();
1042
1042
  logger$85 = createLogger({ prefix: "peer-client" });
1043
- SOFTWARE_VERSION$1 = "0.1.9";
1043
+ SOFTWARE_VERSION$1 = "0.1.10";
1044
1044
  PeerClient$1 = class {
1045
1045
  ws = null;
1046
1046
  _state = "disconnected";
@@ -2503,7 +2503,7 @@ var init_peer_handler = __esmMin((() => {
2503
2503
  init_peer_crypto();
2504
2504
  init_join_token();
2505
2505
  logger$84 = createLogger({ prefix: "peer-handler" });
2506
- SOFTWARE_VERSION = "0.1.9";
2506
+ SOFTWARE_VERSION = "0.1.10";
2507
2507
  RATE_LIMIT_MAX = 5;
2508
2508
  RATE_LIMIT_WINDOW_MS = 6e4;
2509
2509
  }));
@@ -10900,13 +10900,25 @@ var init_check_run_reporter = __esmMin((() => {
10900
10900
  * returns `false` after closing the WS on the first violation, in which
10901
10901
  * case the caller MUST stop processing.
10902
10902
  */
10903
+ /**
10904
+ * WebSocket close reasons are capped at 123 UTF-8 bytes (RFC 6455 §5.5.1).
10905
+ * A reason longer than that makes `ws.close()` throw a RangeError, which —
10906
+ * thrown from an async message handler — surfaces as an unhandled rejection
10907
+ * and skips the close entirely. Truncate on a byte boundary and drop any
10908
+ * trailing partial multi-byte char.
10909
+ */
10910
+ function truncateCloseReason(reason) {
10911
+ const bytes = Buffer.from(reason, "utf-8");
10912
+ if (bytes.length <= 123) return reason;
10913
+ return bytes.subarray(0, 123).toString("utf-8").replace(/�+$/, "");
10914
+ }
10903
10915
  function enforceRegisterAuthGates(authState, payload, ws, agentIdToTokenId) {
10904
10916
  if (authState === void 0) return true;
10905
10917
  const { tokenId, tokenLabels, tokenAgentType, tokenCreatedBy } = authState;
10906
10918
  const { agentId, labels } = payload;
10907
10919
  if (tokenLabels !== void 0 && tokenLabels !== null) {
10908
10920
  const allowedSet = new Set(tokenLabels);
10909
- const elevated = labels.filter((l) => !allowedSet.has(l));
10921
+ const elevated = labels.filter((l) => !allowedSet.has(l) && !isSelfReportedLabel(l));
10910
10922
  if (elevated.length > 0) {
10911
10923
  logger$69.warn("Agent register-time label-scope violation: wire labels exceed token-bound set", {
10912
10924
  agentId,
@@ -10914,7 +10926,7 @@ function enforceRegisterAuthGates(authState, payload, ws, agentIdToTokenId) {
10914
10926
  wireLabels: labels,
10915
10927
  elevated
10916
10928
  });
10917
- ws.close(WS_CLOSE_AGENT_AUTH_FAILED, `Agent labels exceed token-bound scope: ${elevated.join(",")}`);
10929
+ ws.close(WS_CLOSE_AGENT_AUTH_FAILED, truncateCloseReason(`Agent labels exceed token-bound scope: ${elevated.join(",")}`));
10918
10930
  return false;
10919
10931
  }
10920
10932
  }
@@ -10924,7 +10936,7 @@ function enforceRegisterAuthGates(authState, payload, ws, agentIdToTokenId) {
10924
10936
  tokenCreatedBy,
10925
10937
  tokenId
10926
10938
  });
10927
- ws.close(WS_CLOSE_AGENT_AUTH_FAILED, `Ephemeral token bound to a different agentId: expected ${tokenCreatedBy}, got ${agentId}`);
10939
+ ws.close(WS_CLOSE_AGENT_AUTH_FAILED, truncateCloseReason(`Ephemeral token bound to a different agentId: expected ${tokenCreatedBy}, got ${agentId}`));
10928
10940
  return false;
10929
10941
  }
10930
10942
  if (tokenId !== void 0) {
@@ -21591,15 +21603,15 @@ var init_admin_config = __esmMin((() => {
21591
21603
  function createHealthRoutes$1(deps = {}) {
21592
21604
  return createHealthRoutes({
21593
21605
  livenessInfo: () => ({
21594
- version: "0.1.9",
21595
- buildDate: "2026-05-26T16:38:18.222Z",
21596
- buildCommit: "54278bfb2",
21597
- sdkVersion: "0.1.9",
21598
- sdkBundleHash: "675aafe4de03e677785ef2794d8f34951b14e2bd1e6f0ea825953d6c2abfe128",
21599
- sharedVersion: "0.1.9",
21606
+ version: "0.1.10",
21607
+ buildDate: "2026-05-26T17:19:08.888Z",
21608
+ buildCommit: "6bf528b56",
21609
+ sdkVersion: "0.1.10",
21610
+ sdkBundleHash: "unknown",
21611
+ sharedVersion: "0.1.10",
21600
21612
  sharedBundleHash: "36a23a454fd75ec35f258d39f254543ec0451c6b543fe3618ce427e6e6369aae",
21601
- engineVersion: "0.1.9",
21602
- engineBundleHash: "b704538612ec796a5668765bd55e0eaeaf1bad8a2afa508f9e20ad7b9eb61d21"
21613
+ engineVersion: "0.1.10",
21614
+ engineBundleHash: "dff25bbd7602e853cec6e6e985c6c956ad773e245830273cd52950fff958d4bb"
21603
21615
  }),
21604
21616
  readinessCheck: deps.db ? async () => {
21605
21617
  const checks = {};
@@ -21633,7 +21645,7 @@ function createCapabilitiesRoutes() {
21633
21645
  const app = new Hono();
21634
21646
  app.get("/api/v1/capabilities", (c) => {
21635
21647
  const manifest = {
21636
- orchestratorVersion: "0.1.9",
21648
+ orchestratorVersion: "0.1.10",
21637
21649
  protocolVersion: PROTOCOL_VERSION,
21638
21650
  minProtocolVersion: MIN_PROTOCOL_VERSION
21639
21651
  };
@@ -28926,17 +28938,13 @@ var init_container_backend = __esmMin((() => {
28926
28938
  const stripped = key.slice(KICI_AGENT_ENV_PREFIX.length);
28927
28939
  if (stripped.length > 0) agentEnvForwarded.push(`${stripped}=${value}`);
28928
28940
  }
28941
+ const fullLabels = scalerAgentLabels(labelSet, this.type, this.name, this.roles);
28929
28942
  let agentToken;
28930
- if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId, labelSet, this.tokenTtlMs);
28943
+ if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId, fullLabels, this.tokenTtlMs);
28931
28944
  const env = [
28932
28945
  `KICI_ORCHESTRATOR_URL=${orchestratorUrl}`,
28933
28946
  `KICI_AGENT_ID=${agentId}`,
28934
- `KICI_LABELS=${[
28935
- ...labelSet,
28936
- `kici:agent:${this.type}`,
28937
- `kici:scaler:${this.name}`,
28938
- ...resolveRoleLabels(this.roles)
28939
- ].join(",")}`,
28947
+ `KICI_LABELS=${fullLabels.join(",")}`,
28940
28948
  `KICI_SCALER_MANAGED=1`,
28941
28949
  `KICI_EXECUTION_MODE=bare-metal`,
28942
28950
  ...agentToken ? [`KICI_AGENT_TOKEN=${agentToken}`] : [],
@@ -29232,15 +29240,11 @@ var init_bare_metal_backend = __esmMin((() => {
29232
29240
  const strippedKey = key.slice(KICI_AGENT_ENV_PREFIX.length);
29233
29241
  if (strippedKey.length > 0) env[strippedKey] = value;
29234
29242
  }
29235
- if (this.tokenStore) env.KICI_AGENT_TOKEN = await this.tokenStore.createEphemeral(agentId, labelSet, this.tokenTtlMs);
29243
+ const fullLabels = scalerAgentLabels(labelSet, this.type, this.name, this.roles);
29244
+ if (this.tokenStore) env.KICI_AGENT_TOKEN = await this.tokenStore.createEphemeral(agentId, fullLabels, this.tokenTtlMs);
29236
29245
  env.KICI_ORCHESTRATOR_URL = orchestratorUrl;
29237
29246
  env.KICI_AGENT_ID = agentId;
29238
- env.KICI_LABELS = [
29239
- ...labelSet,
29240
- `kici:agent:${this.type}`,
29241
- `kici:scaler:${this.name}`,
29242
- ...resolveRoleLabels(this.roles)
29243
- ].join(",");
29247
+ env.KICI_LABELS = fullLabels.join(",");
29244
29248
  env.KICI_SCALER_MANAGED = "1";
29245
29249
  env.KICI_EXECUTION_MODE = "bare-metal";
29246
29250
  env.KICI_PORT = "0";
@@ -29990,18 +29994,14 @@ var init_firecracker_backend = __esmMin((() => {
29990
29994
  if (chmodLoosenInterval) clearInterval(chmodLoosenInterval);
29991
29995
  }
29992
29996
  if (!ready) throw new Error(`Firecracker API socket not ready within 5s for agent ${agentId}`);
29997
+ const fullLabels = scalerAgentLabels(labelSet, this.type, this.name, this.roles);
29993
29998
  let agentToken;
29994
- if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId, labelSet, this.tokenTtlMs);
29999
+ if (this.tokenStore) agentToken = await this.tokenStore.createEphemeral(agentId, fullLabels, this.tokenTtlMs);
29995
30000
  const acceptedEnv = this.buildForwardedEnv(matchedLabelSet, agentId);
29996
30001
  await api.putMmds({ latest: { "meta-data": {
29997
30002
  "kici-orchestrator-url": orchestratorUrl,
29998
30003
  "kici-agent-id": agentId,
29999
- "kici-labels": [
30000
- ...labelSet,
30001
- `kici:agent:${this.type}`,
30002
- `kici:scaler:${this.name}`,
30003
- ...resolveRoleLabels(this.roles)
30004
- ].join(","),
30004
+ "kici-labels": fullLabels.join(","),
30005
30005
  "kici-scaler-managed": "1",
30006
30006
  "kici-gateway-ip": this.gateway,
30007
30007
  ...agentToken ? { "kici-agent-token": agentToken } : {},
@@ -31078,6 +31078,29 @@ var init_machine_ledger = __esmMin((() => {
31078
31078
  * and manages the agent lifecycle from spawn to destroy.
31079
31079
  */
31080
31080
  /**
31081
+ * Resolved per-job resource amounts (cpus + bytes) for both `requests` and
31082
+ * `limits`. The scaler manager produces this from the job's declared resources
31083
+ * combined with the scaler's `defaults.resources`, applying the request<->limit
31084
+ * mirroring rule. Caps aggregate `requests`; backends use `limits`.
31085
+ */
31086
+ /**
31087
+ * Resolve the orchestrator WebSocket URL a scaler-spawned agent should dial.
31088
+ *
31089
+ * 1. Per-scaler `orchestratorUrl` (scalers.yaml) wins — required for container
31090
+ * agents (host.docker.internal / LAN IP) and Firecracker VMs (bridge gateway
31091
+ * IP), which cannot reach the orchestrator over the host's loopback.
31092
+ * 2. `KICI_ORCHESTRATOR_URL` env override.
31093
+ * 3. Default `ws://127.0.0.1:<orchestrator-port>/ws` — for local (bare-metal)
31094
+ * agents that share the host. The port is the orchestrator's own bind port
31095
+ * (`KICI_PORT`, default 4000), NOT the agent's 8080 default; pointing local
31096
+ * agents at 8080 leaves them unable to reach the orchestrator.
31097
+ */
31098
+ function resolveScalerOrchestratorUrl(configUrl, envUrl, port) {
31099
+ if (configUrl) return configUrl;
31100
+ if (envUrl) return envUrl;
31101
+ return `ws://127.0.0.1:${port ?? "4000"}/ws`;
31102
+ }
31103
+ /**
31081
31104
  * Apply the request<->limit mirroring rule: if only one side is set, copy it
31082
31105
  * to the other; if neither is set, return undefined; if both are set, leave them.
31083
31106
  *
@@ -31989,9 +32012,7 @@ var init_manager = __esmMin((() => {
31989
32012
  });
31990
32013
  }
31991
32014
  getOrchestratorUrl(backendName) {
31992
- const configUrl = this.scalerUrls.get(backendName);
31993
- if (configUrl) return configUrl;
31994
- return process.env.KICI_ORCHESTRATOR_URL ?? "ws://localhost:8080/ws";
32015
+ return resolveScalerOrchestratorUrl(this.scalerUrls.get(backendName), process.env.KICI_ORCHESTRATOR_URL, process.env.KICI_PORT);
31995
32016
  }
31996
32017
  /**
31997
32018
  * Create a per-agent event emitter closure to pass to backend.spawn().
@@ -43777,14 +43798,14 @@ var init_worker_core = __esmMin((() => {
43777
43798
  init_agent_handler();
43778
43799
  init_worker_status();
43779
43800
  init_agent_heartbeat();
43780
- ORCHESTRATOR_VERSION$1 = "0.1.9";
43781
- WORKER_BUILD_COMMIT = "54278bfb2";
43782
- WORKER_SDK_VERSION = "0.1.9";
43783
- WORKER_SDK_BUNDLE_HASH = "675aafe4de03e677785ef2794d8f34951b14e2bd1e6f0ea825953d6c2abfe128";
43784
- WORKER_SHARED_VERSION = "0.1.9";
43801
+ ORCHESTRATOR_VERSION$1 = "0.1.10";
43802
+ WORKER_BUILD_COMMIT = "6bf528b56";
43803
+ WORKER_SDK_VERSION = "0.1.10";
43804
+ WORKER_SDK_BUNDLE_HASH = "unknown";
43805
+ WORKER_SHARED_VERSION = "0.1.10";
43785
43806
  WORKER_SHARED_BUNDLE_HASH = "36a23a454fd75ec35f258d39f254543ec0451c6b543fe3618ce427e6e6369aae";
43786
- WORKER_ENGINE_VERSION = "0.1.9";
43787
- WORKER_ENGINE_BUNDLE_HASH = "b704538612ec796a5668765bd55e0eaeaf1bad8a2afa508f9e20ad7b9eb61d21";
43807
+ WORKER_ENGINE_VERSION = "0.1.10";
43808
+ WORKER_ENGINE_BUNDLE_HASH = "dff25bbd7602e853cec6e6e985c6c956ad773e245830273cd52950fff958d4bb";
43788
43809
  logger$1 = createLogger({ prefix: "worker" });
43789
43810
  DRAIN_TIMEOUT_MS = 3e5;
43790
43811
  }));
@@ -43808,14 +43829,14 @@ var init_worker_core = __esmMin((() => {
43808
43829
  * Graceful shutdown:
43809
43830
  * agent WS -> heartbeat -> HTTP -> DB
43810
43831
  */
43811
- const ORCHESTRATOR_VERSION = "0.1.9";
43812
- const BUILD_COMMIT = "54278bfb2";
43813
- const SDK_VERSION = "0.1.9";
43814
- const SDK_BUNDLE_HASH = "675aafe4de03e677785ef2794d8f34951b14e2bd1e6f0ea825953d6c2abfe128";
43815
- const SHARED_VERSION = "0.1.9";
43832
+ const ORCHESTRATOR_VERSION = "0.1.10";
43833
+ const BUILD_COMMIT = "6bf528b56";
43834
+ const SDK_VERSION = "0.1.10";
43835
+ const SDK_BUNDLE_HASH = "unknown";
43836
+ const SHARED_VERSION = "0.1.10";
43816
43837
  const SHARED_BUNDLE_HASH = "36a23a454fd75ec35f258d39f254543ec0451c6b543fe3618ce427e6e6369aae";
43817
- const ENGINE_VERSION = "0.1.9";
43818
- const ENGINE_BUNDLE_HASH = "b704538612ec796a5668765bd55e0eaeaf1bad8a2afa508f9e20ad7b9eb61d21";
43838
+ const ENGINE_VERSION = "0.1.10";
43839
+ const ENGINE_BUNDLE_HASH = "dff25bbd7602e853cec6e6e985c6c956ad773e245830273cd52950fff958d4bb";
43819
43840
  const otelSdk = initTelemetry({
43820
43841
  serviceName: "kici-orchestrator",
43821
43842
  otlpEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT
@@ -29,6 +29,39 @@ import type { PendingDynamicTracker } from '../cache/pending-dynamics.js';
29
29
  import type { CacheStorage } from '../storage/types.js';
30
30
  import type { AgentMetricsAggregator } from '../metrics/agent-metrics-aggregator.js';
31
31
  import type { AgentApiRegistry } from './agent-api-registry.js';
32
+ /**
33
+ * Run the three token-bound authorization gates against a wire-supplied
34
+ * `agent.register` payload. The gates are identical at first register
35
+ * (Phase 2 / `pendingRegistration`) and on every subsequent re-register
36
+ * arriving on the same registered WS — every code path that mutates the
37
+ * registry's `agentId → entry` mapping for an authenticated WS MUST run
38
+ * them, otherwise the §5.3 / §5.1 invariants only hold for the very first
39
+ * register and a re-register can silently overwrite the authority.
40
+ *
41
+ * Gates:
42
+ * 1. Token-scope subset — wire labels MUST be a subset of
43
+ * `agent_tokens.labels` when that set is non-null. Closes the WS with
44
+ * `WS_CLOSE_AGENT_AUTH_FAILED` listing the elevated labels.
45
+ * 2. Ephemeral identity-binding — for `agent_type === 'ephemeral'`,
46
+ * wire `agentId` MUST equal `tokenCreatedBy` (the scaler-spawned
47
+ * agentId the token was issued for). Closes the WS with
48
+ * `WS_CLOSE_AGENT_AUTH_FAILED`.
49
+ * 3. Static-token agentId-collision — a different `tokenId` must not
50
+ * already claim the wire `agentId`. Closes the WS with
51
+ * `WS_CLOSE_INVALID_MESSAGE`.
52
+ *
53
+ * Returns `true` when every gate passed and the caller may proceed;
54
+ * returns `false` after closing the WS on the first violation, in which
55
+ * case the caller MUST stop processing.
56
+ */
57
+ /**
58
+ * WebSocket close reasons are capped at 123 UTF-8 bytes (RFC 6455 §5.5.1).
59
+ * A reason longer than that makes `ws.close()` throw a RangeError, which —
60
+ * thrown from an async message handler — surfaces as an unhandled rejection
61
+ * and skips the close entirely. Truncate on a byte boundary and drop any
62
+ * trailing partial multi-byte char.
63
+ */
64
+ export declare function truncateCloseReason(reason: string): string;
32
65
  export interface AgentWsHandlerDeps {
33
66
  registry: AgentRegistry;
34
67
  dispatcher: Dispatcher;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kici-dev/orchestrator",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "Customer-deployable orchestrator for the KiCI CI/CD stack. Receives webhook events (direct or via Platform relay), matches triggers against the lock file, and dispatches jobs to connected agents.",
5
5
  "keywords": [
6
6
  "kici",
@@ -82,8 +82,8 @@
82
82
  "ws": "^8.20.0",
83
83
  "yaml": "^2.8.3",
84
84
  "zod": "^4.3.6",
85
- "@kici-dev/engine": "0.1.9",
86
- "@kici-dev/shared": "0.1.9"
85
+ "@kici-dev/shared": "0.1.10",
86
+ "@kici-dev/engine": "0.1.10"
87
87
  },
88
88
  "kici": {
89
89
  "metrics": {
package/sbom.spdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "spdxVersion": "SPDX-2.3",
3
3
  "dataLicense": "CC0-1.0",
4
4
  "SPDXID": "SPDXRef-DOCUMENT",
5
- "name": "@kici-dev/orchestrator@0.1.9",
6
- "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Forchestrator/0.1.9/ba441a14-82fe-4153-ab6c-224a79dfea78",
5
+ "name": "@kici-dev/orchestrator@0.1.10",
6
+ "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Forchestrator/0.1.10/1e7943f5-2300-4aee-b905-0121c011771c",
7
7
  "creationInfo": {
8
- "created": "2026-05-26T16:49:21Z",
8
+ "created": "2026-05-26T17:26:36Z",
9
9
  "creators": [
10
10
  "Tool: kici-sbom-generator"
11
11
  ]
@@ -1477,9 +1477,9 @@
1477
1477
  "homepage": "https://ericsmekens.github.io/jsep/tree/master/packages/regex#readme"
1478
1478
  },
1479
1479
  {
1480
- "SPDXID": "SPDXRef-Package--kici-dev-engine-0.1.9",
1480
+ "SPDXID": "SPDXRef-Package--kici-dev-engine-0.1.10",
1481
1481
  "name": "@kici-dev/engine",
1482
- "versionInfo": "0.1.9",
1482
+ "versionInfo": "0.1.10",
1483
1483
  "downloadLocation": "NOASSERTION",
1484
1484
  "filesAnalyzed": false,
1485
1485
  "licenseConcluded": "NOASSERTION",
@@ -1490,7 +1490,7 @@
1490
1490
  {
1491
1491
  "referenceCategory": "PACKAGE-MANAGER",
1492
1492
  "referenceType": "purl",
1493
- "referenceLocator": "pkg:npm/%40kici-dev/engine@0.1.9"
1493
+ "referenceLocator": "pkg:npm/%40kici-dev/engine@0.1.10"
1494
1494
  }
1495
1495
  ],
1496
1496
  "description": "Shared business logic for the KiCI CI/CD stack: protocol, triggers, state machine, and provider interfaces used by the Platform relay, orchestrator, and compiler.",
@@ -1499,7 +1499,7 @@
1499
1499
  {
1500
1500
  "SPDXID": "SPDXRef-RootPackage",
1501
1501
  "name": "@kici-dev/orchestrator",
1502
- "versionInfo": "0.1.9",
1502
+ "versionInfo": "0.1.10",
1503
1503
  "downloadLocation": "NOASSERTION",
1504
1504
  "filesAnalyzed": false,
1505
1505
  "licenseConcluded": "NOASSERTION",
@@ -1510,16 +1510,16 @@
1510
1510
  {
1511
1511
  "referenceCategory": "PACKAGE-MANAGER",
1512
1512
  "referenceType": "purl",
1513
- "referenceLocator": "pkg:npm/%40kici-dev/orchestrator@0.1.9"
1513
+ "referenceLocator": "pkg:npm/%40kici-dev/orchestrator@0.1.10"
1514
1514
  }
1515
1515
  ],
1516
1516
  "description": "Customer-deployable orchestrator for the KiCI CI/CD stack. Receives webhook events (direct or via Platform relay), matches triggers against the lock file, and dispatches jobs to connected agents.",
1517
1517
  "homepage": "https://kici.dev"
1518
1518
  },
1519
1519
  {
1520
- "SPDXID": "SPDXRef-Package--kici-dev-shared-0.1.9",
1520
+ "SPDXID": "SPDXRef-Package--kici-dev-shared-0.1.10",
1521
1521
  "name": "@kici-dev/shared",
1522
- "versionInfo": "0.1.9",
1522
+ "versionInfo": "0.1.10",
1523
1523
  "downloadLocation": "NOASSERTION",
1524
1524
  "filesAnalyzed": false,
1525
1525
  "licenseConcluded": "NOASSERTION",
@@ -1530,7 +1530,7 @@
1530
1530
  {
1531
1531
  "referenceCategory": "PACKAGE-MANAGER",
1532
1532
  "referenceType": "purl",
1533
- "referenceLocator": "pkg:npm/%40kici-dev/shared@0.1.9"
1533
+ "referenceLocator": "pkg:npm/%40kici-dev/shared@0.1.10"
1534
1534
  }
1535
1535
  ],
1536
1536
  "description": "Shared utilities for the KiCI CI/CD stack — logging, zx setup, crypto, telemetry, health and metrics routes. No business logic.",
@@ -10682,17 +10682,17 @@
10682
10682
  "relationshipType": "DEPENDS_ON"
10683
10683
  },
10684
10684
  {
10685
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.9",
10685
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.10",
10686
10686
  "relatedSpdxElement": "SPDXRef-Package-jsonpath-plus-10.4.0",
10687
10687
  "relationshipType": "DEPENDS_ON"
10688
10688
  },
10689
10689
  {
10690
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.9",
10690
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.10",
10691
10691
  "relatedSpdxElement": "SPDXRef-Package-picomatch-4.0.4",
10692
10692
  "relationshipType": "DEPENDS_ON"
10693
10693
  },
10694
10694
  {
10695
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.9",
10695
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.10",
10696
10696
  "relatedSpdxElement": "SPDXRef-Package-zod-4.3.6",
10697
10697
  "relationshipType": "DEPENDS_ON"
10698
10698
  },
@@ -10728,12 +10728,12 @@
10728
10728
  },
10729
10729
  {
10730
10730
  "spdxElementId": "SPDXRef-RootPackage",
10731
- "relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.9",
10731
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.10",
10732
10732
  "relationshipType": "DEPENDS_ON"
10733
10733
  },
10734
10734
  {
10735
10735
  "spdxElementId": "SPDXRef-RootPackage",
10736
- "relatedSpdxElement": "SPDXRef-Package--kici-dev-shared-0.1.9",
10736
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-shared-0.1.10",
10737
10737
  "relationshipType": "DEPENDS_ON"
10738
10738
  },
10739
10739
  {
@@ -10837,102 +10837,102 @@
10837
10837
  "relationshipType": "DEPENDS_ON"
10838
10838
  },
10839
10839
  {
10840
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10840
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10841
10841
  "relatedSpdxElement": "SPDXRef-Package--aws-sdk-client-s3-3.1038.0",
10842
10842
  "relationshipType": "DEPENDS_ON"
10843
10843
  },
10844
10844
  {
10845
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10845
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10846
10846
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-api-1.9.1",
10847
10847
  "relationshipType": "DEPENDS_ON"
10848
10848
  },
10849
10849
  {
10850
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10850
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10851
10851
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-exporter-metrics-otlp-http-0.217.0",
10852
10852
  "relationshipType": "DEPENDS_ON"
10853
10853
  },
10854
10854
  {
10855
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10855
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10856
10856
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-exporter-prometheus-0.217.0",
10857
10857
  "relationshipType": "DEPENDS_ON"
10858
10858
  },
10859
10859
  {
10860
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10860
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10861
10861
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-exporter-trace-otlp-http-0.217.0",
10862
10862
  "relationshipType": "DEPENDS_ON"
10863
10863
  },
10864
10864
  {
10865
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10865
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10866
10866
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-instrumentation-runtime-node-0.28.0",
10867
10867
  "relationshipType": "DEPENDS_ON"
10868
10868
  },
10869
10869
  {
10870
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10870
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10871
10871
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-resources-2.7.0",
10872
10872
  "relationshipType": "DEPENDS_ON"
10873
10873
  },
10874
10874
  {
10875
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10875
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10876
10876
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-sdk-node-0.217.0",
10877
10877
  "relationshipType": "DEPENDS_ON"
10878
10878
  },
10879
10879
  {
10880
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10880
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10881
10881
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-semantic-conventions-1.40.0",
10882
10882
  "relationshipType": "DEPENDS_ON"
10883
10883
  },
10884
10884
  {
10885
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10885
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10886
10886
  "relatedSpdxElement": "SPDXRef-Package-diff-7.0.0",
10887
10887
  "relationshipType": "DEPENDS_ON"
10888
10888
  },
10889
10889
  {
10890
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10890
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10891
10891
  "relatedSpdxElement": "SPDXRef-Package-hono-4.12.18",
10892
10892
  "relationshipType": "DEPENDS_ON"
10893
10893
  },
10894
10894
  {
10895
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10895
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10896
10896
  "relatedSpdxElement": "SPDXRef-Package-kysely-0.29.0",
10897
10897
  "relationshipType": "DEPENDS_ON"
10898
10898
  },
10899
10899
  {
10900
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10900
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10901
10901
  "relatedSpdxElement": "SPDXRef-Package-oxc-transform-0.128.0",
10902
10902
  "relationshipType": "DEPENDS_ON"
10903
10903
  },
10904
10904
  {
10905
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10905
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10906
10906
  "relatedSpdxElement": "SPDXRef-Package-pg-8.20.0",
10907
10907
  "relationshipType": "DEPENDS_ON"
10908
10908
  },
10909
10909
  {
10910
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10910
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10911
10911
  "relatedSpdxElement": "SPDXRef-Package-picocolors-1.1.1",
10912
10912
  "relationshipType": "DEPENDS_ON"
10913
10913
  },
10914
10914
  {
10915
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10915
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10916
10916
  "relatedSpdxElement": "SPDXRef-Package-winston-daily-rotate-file-5.0.0",
10917
10917
  "relationshipType": "DEPENDS_ON"
10918
10918
  },
10919
10919
  {
10920
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10920
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10921
10921
  "relatedSpdxElement": "SPDXRef-Package-winston-3.19.0",
10922
10922
  "relationshipType": "DEPENDS_ON"
10923
10923
  },
10924
10924
  {
10925
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10925
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10926
10926
  "relatedSpdxElement": "SPDXRef-Package-yaml-2.8.3",
10927
10927
  "relationshipType": "DEPENDS_ON"
10928
10928
  },
10929
10929
  {
10930
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10930
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10931
10931
  "relatedSpdxElement": "SPDXRef-Package-zod-4.3.6",
10932
10932
  "relationshipType": "DEPENDS_ON"
10933
10933
  },
10934
10934
  {
10935
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.9",
10935
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.10",
10936
10936
  "relatedSpdxElement": "SPDXRef-Package-zx-8.8.5",
10937
10937
  "relationshipType": "DEPENDS_ON"
10938
10938
  },