@kici-dev/agent 0.1.26 → 0.1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/config.d.ts CHANGED
@@ -30,6 +30,8 @@ declare const configSchema: z.ZodObject<{
30
30
  drop: "drop";
31
31
  }>>;
32
32
  sandbox: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<boolean, string>>;
33
+ trustedEnv: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<boolean, string>>;
34
+ inPlace: z.ZodPipe<z.ZodDefault<z.ZodString>, z.ZodTransform<boolean, string>>;
33
35
  sandboxNetwork: z.ZodDefault<z.ZodEnum<{
34
36
  isolated: "isolated";
35
37
  host: "host";
@@ -71,6 +73,8 @@ export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
71
73
  jobHeartbeatIntervalMs: number;
72
74
  backpressureMode: "pause" | "drop";
73
75
  sandbox: boolean;
76
+ trustedEnv: boolean;
77
+ inPlace: boolean;
74
78
  sandboxNetwork: "isolated" | "host";
75
79
  scalerManaged: boolean;
76
80
  scalerIdleTimeoutMs: number;
@@ -102,6 +106,8 @@ export declare const envDef: import("@kici-dev/shared/env").DefineEnvResult<{
102
106
  * - KICI_JOB_HEARTBEAT_INTERVAL_MS (default: 60000)
103
107
  * - KICI_BACKPRESSURE_MODE (default: pause, options: pause | drop)
104
108
  * - KICI_SANDBOX (default: false) — enable bubblewrap (bwrap) namespace isolation for bare-metal execution
109
+ * - KICI_TRUSTED_ENV (default: false) — trusted fleet-agent profile: pass the ambient host env (minus the agent's own KiCI identity secrets) through to steps
110
+ * - KICI_IN_PLACE (default: false) — in-place no-clone profile: for a file:// source, use the real repo path as workDir and skip the clone (the routed deploy:stg profile)
105
111
  * - KICI_SANDBOX_NETWORK (default: isolated, options: isolated | host) — when sandbox=true, controls bwrap network namespace
106
112
  * - KICI_SCALER_MANAGED (set to "1" by the orchestrator's auto-scaler — agent self-shuts down on idle)
107
113
  * - KICI_SCALER_IDLE_TIMEOUT (ms, default 5000) — how long a scaler-managed agent waits before shutdown after going idle
@@ -5,8 +5,8 @@ import { type MatrixValues } from '@kici-dev/engine';
5
5
  * Only fields that were flagged as dynamic and successfully resolved are set.
6
6
  */
7
7
  export interface InitResult {
8
- /** Resolved bound-environment names, in merge order (one per `environments` element). */
9
- environmentNames?: string[];
8
+ /** Resolved bound-context names, in merge order (one per `contexts` element). */
9
+ contextNames?: string[];
10
10
  env?: Record<string, string>;
11
11
  concurrencyGroup?: string;
12
12
  /**
@@ -16,7 +16,7 @@ export interface InitResult {
16
16
  matrixValues?: MatrixValues[];
17
17
  }
18
18
  /**
19
- * Evaluate dynamic fields (environment, env, concurrencyGroup) on a job.
19
+ * Evaluate dynamic fields (context, env, concurrencyGroup) on a job.
20
20
  *
21
21
  * Only fields with their corresponding flag set to true AND whose property
22
22
  * on the job is a function will be evaluated. All evaluations happen in a
@@ -33,7 +33,7 @@ export interface InitResult {
33
33
  * @param timeoutMs - Timeout per dynamic function call (default 60_000ms)
34
34
  */
35
35
  export declare function evaluateDynamicFields(workflow: Workflow, jobName: string, event: Record<string, unknown>, flags: {
36
- dynamicEnvironment: boolean;
36
+ dynamicContext: boolean;
37
37
  dynamicEnv: boolean;
38
38
  dynamicConcurrencyGroup: boolean;
39
39
  dynamicMatrix?: boolean;
@@ -122,6 +122,23 @@ export declare function buildEvalNeedsContext(config: {
122
122
  declaredNeeds?: readonly unknown[];
123
123
  upstreamSnapshot?: import('@kici-dev/engine').UpstreamSnapshot;
124
124
  }): ReturnType<typeof buildNeedsContext> | undefined;
125
+ /**
126
+ * Resolve a job's workDir and its cleanup.
127
+ *
128
+ * - Default: a fresh `mkdtemp` the agent clones into and removes after the job.
129
+ * - **In-place profile** (`inPlace` config + a `file://` source): the source's
130
+ * real repo path used directly as the workDir, with **no clone** and **no
131
+ * removal**. This is the routed `deploy:stg` profile — the operator runs their
132
+ * own already-built working tree (module-relative `MONOREPO_ROOT`,
133
+ * `node_modules`, `dist` all present). Gated to `file://` so a
134
+ * Platform-connected agent (https sources) can never be pushed onto a tree,
135
+ * and read only from agent config (never a dispatch/wire value).
136
+ */
137
+ export declare function resolveJobWorkDir(inPlace: boolean, repoUrl: string | undefined): Promise<{
138
+ workDir: string;
139
+ cleanup: () => Promise<void>;
140
+ inPlace: boolean;
141
+ }>;
125
142
  /**
126
143
  * Top-level job execution orchestrator for the agent.
127
144
  *
@@ -9,8 +9,8 @@
9
9
  * 1. Allowed system vars from process.env
10
10
  * 2. Sandbox defaults (FORCE_COLOR=1, etc.)
11
11
  * 3. KICI_* system vars (orchestrator-generated, from userEnv)
12
- * 4. Org-level environment vars (from orchestrator via environmentVars)
13
- * 5. Source-level environment overrides (merged into environmentVars by orchestrator)
12
+ * 4. Org-level environment vars (from orchestrator via contextVars)
13
+ * 5. Source-level environment overrides (merged into contextVars by orchestrator)
14
14
  * 6. Job env (from lock file env field, evaluated by orchestrator)
15
15
  * 7. setEnv() calls (runtime -- applied at step execution, not here)
16
16
  */
@@ -32,12 +32,21 @@
32
32
  * PLATFORM_TOKEN, WEBHOOK_SECRET, etc.) are never included because they
33
33
  * are not in the allowlist.
34
34
  *
35
+ * The `trustedEnv` option (default false) selects the trusted fleet-agent
36
+ * profile: Layer 1 passes the ambient host env through instead of restricting
37
+ * to `ALLOWED_SYSTEM_VARS`, minus the agent's own KiCI identity/operational
38
+ * secrets (the whole `KICI_*` namespace + a small non-`KICI_` infra denylist).
39
+ * It is read ONLY from agent config (`KICI_TRUSTED_ENV`), never from a dispatch
40
+ * payload, so a workflow cannot request it. With it OFF the output is
41
+ * byte-identical to the allowlist-only behavior.
42
+ *
35
43
  * @param userEnv - Environment variables from workflow config and orchestrator
36
44
  * @param options - Optional extended options for environment layers
37
45
  * @returns A new Record with only safe environment variables
38
46
  */
39
47
  export declare function buildSanitizedEnv(userEnv: Record<string, string>, options?: {
40
- environmentVars?: Record<string, string>;
48
+ contextVars?: Record<string, string>;
41
49
  jobEnv?: Record<string, string>;
50
+ trustedEnv?: boolean;
42
51
  }): Record<string, string>;
43
52
  //# sourceMappingURL=env-sanitizer.d.ts.map
@@ -508,10 +508,10 @@ export interface JobExecutionRequest {
508
508
  orchestratorPrivateKey?: string;
509
509
  /** Base64-encoded X25519 public key for the run (for encrypting secret outputs). */
510
510
  runPublicKey?: string;
511
- /** Deployment environment name (resolved by orchestrator). */
512
- environment?: string;
511
+ /** Resolved context name (resolved by orchestrator). */
512
+ context?: string;
513
513
  /** Environment variables from orchestrator (org-level + source overrides, layers 4-5). */
514
- environmentVars?: Record<string, string>;
514
+ contextVars?: Record<string, string>;
515
515
  /** Job env from lock file env field (layer 6, evaluated by orchestrator). */
516
516
  jobEnv?: Record<string, string>;
517
517
  /** Whether this is a global workflow (dual-clone: workflow repo + source repo). */
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Shared factory for the zx `log` callback that streams a subprocess's
3
+ * stdout/stderr into the captured/streamed run log, line by line, via `emit`.
4
+ *
5
+ * zx does NOT write child stdout/stderr to `process.stdout`; it pipes the
6
+ * child stdio to an internal VoidStream and surfaces each chunk through the
7
+ * shell's `log` callback as `{ kind: 'stdout' | 'stderr', data, verbose }`.
8
+ * The `verbose` flag is zx's per-invocation quiet/verbose decision:
9
+ *
10
+ * - stdout entries: `verbose = !piped && (snapshot.verbose && !snapshot.quiet)`
11
+ * - stderr entries: `verbose = !snapshot.quiet`
12
+ *
13
+ * so a step that opts into `$({ quiet: true })` (e.g. a `sops -d` decrypt of a
14
+ * credential) produces `verbose: false` entries. This factory HONORS that flag
15
+ * — it skips `verbose: false` entries — which is what makes `{ quiet: true }`
16
+ * actually suppress sensitive output from the run log. Without the gate, a
17
+ * decrypted-secret line leaks into the persisted/streamed log (zx's own default
18
+ * log function gates on the same flag: `if (!entry.verbose) return`).
19
+ *
20
+ * IMPORTANT: the shell that installs this callback MUST be constructed with
21
+ * `verbose: true`. With `verbose: true` zx flags ordinary (non-quiet)
22
+ * subprocess output `verbose: true` (captured) and a `{ quiet: true }` call
23
+ * `verbose: false` (suppressed). A `verbose: false` base would flag ordinary
24
+ * output `verbose: false` too, and this gate would then drop every line.
25
+ *
26
+ * The returned callback owns a per-shell line buffer, so partial chunks are
27
+ * coalesced into whole lines before `emit` is called.
28
+ */
29
+ export declare function makeStreamingZxLog(emit: (line: string) => void): (entry: unknown) => void;
30
+ //# sourceMappingURL=streaming-zx-log.d.ts.map
package/dist/index.js CHANGED
@@ -86,6 +86,8 @@ const envDef = defineEnv({
86
86
  jobHeartbeatIntervalMs: z.coerce.number().default(6e4),
87
87
  backpressureMode: z.enum(["pause", "drop"]).default("pause"),
88
88
  sandbox: z.string().default("false").transform((s) => s === "true"),
89
+ trustedEnv: z.string().default("false").transform((s) => s === "true"),
90
+ inPlace: z.string().default("false").transform((s) => s === "true"),
89
91
  sandboxNetwork: z.enum(["isolated", "host"]).default("isolated"),
90
92
  scalerManaged: z.string().optional().transform((s) => s === "1"),
91
93
  scalerIdleTimeoutMs: z.coerce.number().default(5e3),
@@ -112,6 +114,8 @@ const envDef = defineEnv({
112
114
  jobHeartbeatIntervalMs: "KICI_JOB_HEARTBEAT_INTERVAL_MS",
113
115
  backpressureMode: "KICI_BACKPRESSURE_MODE",
114
116
  sandbox: "KICI_SANDBOX",
117
+ trustedEnv: "KICI_TRUSTED_ENV",
118
+ inPlace: "KICI_IN_PLACE",
115
119
  sandboxNetwork: "KICI_SANDBOX_NETWORK",
116
120
  scalerManaged: "KICI_SCALER_MANAGED",
117
121
  scalerIdleTimeoutMs: "KICI_SCALER_IDLE_TIMEOUT",
@@ -140,6 +144,8 @@ const envDef = defineEnv({
140
144
  * - KICI_JOB_HEARTBEAT_INTERVAL_MS (default: 60000)
141
145
  * - KICI_BACKPRESSURE_MODE (default: pause, options: pause | drop)
142
146
  * - KICI_SANDBOX (default: false) — enable bubblewrap (bwrap) namespace isolation for bare-metal execution
147
+ * - KICI_TRUSTED_ENV (default: false) — trusted fleet-agent profile: pass the ambient host env (minus the agent's own KiCI identity secrets) through to steps
148
+ * - KICI_IN_PLACE (default: false) — in-place no-clone profile: for a file:// source, use the real repo path as workDir and skip the clone (the routed deploy:stg profile)
143
149
  * - KICI_SANDBOX_NETWORK (default: isolated, options: isolated | host) — when sandbox=true, controls bwrap network namespace
144
150
  * - KICI_SCALER_MANAGED (set to "1" by the orchestrator's auto-scaler — agent self-shuts down on idle)
145
151
  * - KICI_SCALER_IDLE_TIMEOUT (ms, default 5000) — how long a scaler-managed agent waits before shutdown after going idle
package/dist/server.js CHANGED
@@ -12,7 +12,7 @@ import winston from "winston";
12
12
  import { RingBuffer, addLogsToArchive, chunkBuffer, createHealthRoutes, createLogger, createMeter, createMetricsRoutes, deriveSharedSecret, getPrometheusExporter, getReconnectDelay, getRequestContext, guardStartup, initTelemetry, logger, normalizeLineEndings, redactConfig, requestContext, setServiceName, setupGracefulShutdown, sha256, sha256File, toErrorMessage, validateRequiredTools } from "@kici-dev/shared";
13
13
  import { z } from "zod";
14
14
  import { LOGGER_ENV_VARS, defineEnv, validateUnknownKiciVars } from "@kici-dev/shared/env";
15
- import { ALLOWED_SYSTEM_VARS, CacheRunEventType, CacheStepType, ExecutionJobStatus, ExecutionStepStatus, InitFailureCategory, KNOWN_ROLES, PROTOCOL_VERSION, SANDBOX_DEFAULT_VARS, WS_CLOSE_AGENT_AUTH_FAILED, WS_MAX_PAYLOAD_BYTES, applyIncludeExclude, deriveOsArchLabels, expandMatrix, heartbeatSchema, hostLabel, mergeAutoLabels, orchestratorToAgentMessageSchema, parseHostPropertyAssignments, resolveRoleLabels, resolveWhenToRunOn, validateNoReservedLabels } from "@kici-dev/engine";
15
+ import { ALLOWED_SYSTEM_VARS, CacheRunEventType, CacheStepType, ExecutionJobStatus, ExecutionStepStatus, InitFailureCategory, KNOWN_ROLES, PROTOCOL_VERSION, SANDBOX_DEFAULT_VARS, WS_CLOSE_AGENT_AUTH_FAILED, WS_MAX_PAYLOAD_BYTES, applyIncludeExclude, buildTrustedPassthroughEnv, deriveOsArchLabels, expandMatrix, heartbeatSchema, hostLabel, mergeAutoLabels, orchestratorToAgentMessageSchema, parseHostPropertyAssignments, resolveRoleLabels, resolveWhenToRunOn, validateNoReservedLabels } from "@kici-dev/engine";
16
16
  import { execFile, execFileSync, execSync, fork, spawn } from "node:child_process";
17
17
  import WebSocket from "ws";
18
18
  import * as fs$1 from "node:fs";
@@ -102,6 +102,8 @@ const envDef = defineEnv({
102
102
  jobHeartbeatIntervalMs: z.coerce.number().default(6e4),
103
103
  backpressureMode: z.enum(["pause", "drop"]).default("pause"),
104
104
  sandbox: z.string().default("false").transform((s) => s === "true"),
105
+ trustedEnv: z.string().default("false").transform((s) => s === "true"),
106
+ inPlace: z.string().default("false").transform((s) => s === "true"),
105
107
  sandboxNetwork: z.enum(["isolated", "host"]).default("isolated"),
106
108
  scalerManaged: z.string().optional().transform((s) => s === "1"),
107
109
  scalerIdleTimeoutMs: z.coerce.number().default(5e3),
@@ -128,6 +130,8 @@ const envDef = defineEnv({
128
130
  jobHeartbeatIntervalMs: "KICI_JOB_HEARTBEAT_INTERVAL_MS",
129
131
  backpressureMode: "KICI_BACKPRESSURE_MODE",
130
132
  sandbox: "KICI_SANDBOX",
133
+ trustedEnv: "KICI_TRUSTED_ENV",
134
+ inPlace: "KICI_IN_PLACE",
131
135
  sandboxNetwork: "KICI_SANDBOX_NETWORK",
132
136
  scalerManaged: "KICI_SCALER_MANAGED",
133
137
  scalerIdleTimeoutMs: "KICI_SCALER_IDLE_TIMEOUT",
@@ -156,6 +160,8 @@ const envDef = defineEnv({
156
160
  * - KICI_JOB_HEARTBEAT_INTERVAL_MS (default: 60000)
157
161
  * - KICI_BACKPRESSURE_MODE (default: pause, options: pause | drop)
158
162
  * - KICI_SANDBOX (default: false) — enable bubblewrap (bwrap) namespace isolation for bare-metal execution
163
+ * - KICI_TRUSTED_ENV (default: false) — trusted fleet-agent profile: pass the ambient host env (minus the agent's own KiCI identity secrets) through to steps
164
+ * - KICI_IN_PLACE (default: false) — in-place no-clone profile: for a file:// source, use the real repo path as workDir and skip the clone (the routed deploy:stg profile)
159
165
  * - KICI_SANDBOX_NETWORK (default: isolated, options: isolated | host) — when sandbox=true, controls bwrap network namespace
160
166
  * - KICI_SCALER_MANAGED (set to "1" by the orchestrator's auto-scaler — agent self-shuts down on idle)
161
167
  * - KICI_SCALER_IDLE_TIMEOUT (ms, default 5000) — how long a scaler-managed agent waits before shutdown after going idle
@@ -1342,14 +1348,14 @@ var init_console_capture = __esmMin((() => {
1342
1348
  init_console_capture();
1343
1349
  function safe(name, fallback = "unknown") {
1344
1350
  switch (name) {
1345
- case "version": return "0.1.26";
1346
- case "buildCommit": return "85120b08f";
1347
- case "sdkVersion": return "0.1.26";
1351
+ case "version": return "0.1.27";
1352
+ case "buildCommit": return "f0747470b";
1353
+ case "sdkVersion": return "0.1.27";
1348
1354
  case "sdkBundleHash": return "e06bd1acf349ba365bdb357f3d865e0cbb4ad4604a0270b707a681a4f440954e";
1349
- case "sharedVersion": return "0.1.26";
1350
- case "sharedBundleHash": return "2394db0d8560b2cebf220c0e2d8993c75083aaf70a5917c35099b24feb3a22ba";
1351
- case "engineVersion": return "0.1.26";
1352
- case "engineBundleHash": return "c3320e812b8593d692f3fbf5eafe83507270028f7a1174c607881105dd702654";
1355
+ case "sharedVersion": return "0.1.27";
1356
+ case "sharedBundleHash": return "f8e1f0117cf41fca5a74377633e2ec89e54ce4eda47d9f476cdb83336f1ed962";
1357
+ case "engineVersion": return "0.1.27";
1358
+ case "engineBundleHash": return "ce675fb4790406ed2a938f8f1783db37b283cffd7d8fc1eb12a878e0bfb919b3";
1353
1359
  default: return fallback;
1354
1360
  }
1355
1361
  }
@@ -2112,7 +2118,7 @@ async function extractStepsFromDynamicJob(workflow, dynamicIndex, jobName, event
2112
2118
  }
2113
2119
  var AGENT_SDK_VERSION, AGENT_SDK_BUNDLE_HASH, hookRegistered;
2114
2120
  var init_workflow_loader = __esmMin((() => {
2115
- AGENT_SDK_VERSION = "0.1.26";
2121
+ AGENT_SDK_VERSION = "0.1.27";
2116
2122
  AGENT_SDK_BUNDLE_HASH = "e06bd1acf349ba365bdb357f3d865e0cbb4ad4604a0270b707a681a4f440954e";
2117
2123
  hookRegistered = false;
2118
2124
  }));
@@ -2539,7 +2545,7 @@ function findJobByName(workflow, jobName) {
2539
2545
  throw new Error(`Job '${jobName}' not found in workflow '${workflow.name}'`);
2540
2546
  }
2541
2547
  /**
2542
- * Evaluate dynamic fields (environment, env, concurrencyGroup) on a job.
2548
+ * Evaluate dynamic fields (context, env, concurrencyGroup) on a job.
2543
2549
  *
2544
2550
  * Only fields with their corresponding flag set to true AND whose property
2545
2551
  * on the job is a function will be evaluated. All evaluations happen in a
@@ -2580,15 +2586,15 @@ async function evaluateDynamicFields(workflow, jobName, event, flags, timeoutMs
2580
2586
  if (job.include || job.exclude) combos = applyIncludeExclude(combos, job.include, job.exclude);
2581
2587
  result.matrixValues = combos;
2582
2588
  }
2583
- if (flags.dynamicEnvironment) {
2584
- const envRefs = job.environments ?? (job.environment !== void 0 ? [job.environment] : void 0);
2589
+ if (flags.dynamicContext) {
2590
+ const envRefs = job.contexts ?? (job.context !== void 0 ? [job.context] : void 0);
2585
2591
  if (envRefs && envRefs.length > 0) {
2586
2592
  const names = [];
2587
2593
  for (const ref of envRefs) if (typeof ref === "function") {
2588
- const value = await withTimeout(() => ref(event), timeoutMs, `dynamicEnvironment for job '${jobName}'`);
2594
+ const value = await withTimeout(() => ref(event), timeoutMs, `dynamicContext for job '${jobName}'`);
2589
2595
  if (value !== void 0 && value !== null) names.push(value);
2590
2596
  } else if (typeof ref === "string") names.push(ref);
2591
- if (names.length > 0) result.environmentNames = names;
2597
+ if (names.length > 0) result.contextNames = names;
2592
2598
  }
2593
2599
  }
2594
2600
  if (flags.dynamicEnv && typeof job.env === "function") {
@@ -2889,6 +2895,50 @@ var init_api_intercept = __esmMin((() => {
2889
2895
  PRE_BOOT_SEND = "kici.preBootSend";
2890
2896
  }));
2891
2897
  //#endregion
2898
+ //#region src/execution/streaming-zx-log.ts
2899
+ /**
2900
+ * Shared factory for the zx `log` callback that streams a subprocess's
2901
+ * stdout/stderr into the captured/streamed run log, line by line, via `emit`.
2902
+ *
2903
+ * zx does NOT write child stdout/stderr to `process.stdout`; it pipes the
2904
+ * child stdio to an internal VoidStream and surfaces each chunk through the
2905
+ * shell's `log` callback as `{ kind: 'stdout' | 'stderr', data, verbose }`.
2906
+ * The `verbose` flag is zx's per-invocation quiet/verbose decision:
2907
+ *
2908
+ * - stdout entries: `verbose = !piped && (snapshot.verbose && !snapshot.quiet)`
2909
+ * - stderr entries: `verbose = !snapshot.quiet`
2910
+ *
2911
+ * so a step that opts into `$({ quiet: true })` (e.g. a `sops -d` decrypt of a
2912
+ * credential) produces `verbose: false` entries. This factory HONORS that flag
2913
+ * — it skips `verbose: false` entries — which is what makes `{ quiet: true }`
2914
+ * actually suppress sensitive output from the run log. Without the gate, a
2915
+ * decrypted-secret line leaks into the persisted/streamed log (zx's own default
2916
+ * log function gates on the same flag: `if (!entry.verbose) return`).
2917
+ *
2918
+ * IMPORTANT: the shell that installs this callback MUST be constructed with
2919
+ * `verbose: true`. With `verbose: true` zx flags ordinary (non-quiet)
2920
+ * subprocess output `verbose: true` (captured) and a `{ quiet: true }` call
2921
+ * `verbose: false` (suppressed). A `verbose: false` base would flag ordinary
2922
+ * output `verbose: false` too, and this gate would then drop every line.
2923
+ *
2924
+ * The returned callback owns a per-shell line buffer, so partial chunks are
2925
+ * coalesced into whole lines before `emit` is called.
2926
+ */
2927
+ function makeStreamingZxLog(emit) {
2928
+ let lineBuf = "";
2929
+ return (entry) => {
2930
+ const e = entry;
2931
+ if (e.kind !== "stdout" && e.kind !== "stderr") return;
2932
+ if (!e.verbose) return;
2933
+ const text = typeof e.data === "string" ? e.data : String(e.data ?? "");
2934
+ lineBuf += text;
2935
+ const lines = lineBuf.split("\n");
2936
+ lineBuf = lines.pop();
2937
+ for (const line of lines) if (line) emit(line);
2938
+ };
2939
+ }
2940
+ var init_streaming_zx_log = __esmMin((() => {}));
2941
+ //#endregion
2892
2942
  //#region src/execution/dynamic-job-serializer.ts
2893
2943
  /**
2894
2944
  * Convert an array of SDK Job objects into LockJob format for the orchestrator.
@@ -2912,8 +2962,8 @@ async function serializeJobsToLock(jobs, ctx, staticNames, allowedGroups) {
2912
2962
  }
2913
2963
  async function serializeJob(job, generatedNames, ctx, staticNames, allowedGroups) {
2914
2964
  const { include: runsOn, exclude: excludeLabels } = normalizeRunsOnToMatchers(job.runsOn, `generated job '${job.name}' runsOn`);
2915
- const envRefs = job.environments ?? (job.environment !== void 0 ? [job.environment] : void 0);
2916
- let resolvedEnvironments;
2965
+ const envRefs = job.contexts ?? (job.context !== void 0 ? [job.context] : void 0);
2966
+ let resolvedContexts;
2917
2967
  if (envRefs !== void 0 && envRefs.length > 0) {
2918
2968
  const resolved = [];
2919
2969
  for (const ref of envRefs) if (typeof ref === "function") {
@@ -2926,7 +2976,7 @@ async function serializeJob(job, generatedNames, ctx, staticNames, allowedGroups
2926
2976
  value: ref,
2927
2977
  dynamic: false
2928
2978
  });
2929
- if (resolved.length > 0) resolvedEnvironments = resolved;
2979
+ if (resolved.length > 0) resolvedContexts = resolved;
2930
2980
  }
2931
2981
  let resolvedEnv;
2932
2982
  if (typeof job.env === "function") {
@@ -2953,7 +3003,7 @@ async function serializeJob(job, generatedNames, ctx, staticNames, allowedGroups
2953
3003
  ...job.include ? { include: job.include } : {},
2954
3004
  ...job.exclude ? { exclude: job.exclude } : {},
2955
3005
  ...job.description ? { description: job.description } : {},
2956
- ...resolvedEnvironments !== void 0 ? { environments: resolvedEnvironments } : {},
3006
+ ...resolvedContexts !== void 0 ? { contexts: resolvedContexts } : {},
2957
3007
  ...resolvedEnv !== void 0 ? { env: resolvedEnv } : {},
2958
3008
  ...resolvedConcurrencyGroup !== void 0 ? { concurrencyGroup: resolvedConcurrencyGroup } : {}
2959
3009
  };
@@ -4471,8 +4521,8 @@ var init_dep_packer = __esmMin((() => {
4471
4521
  * 1. Allowed system vars from process.env
4472
4522
  * 2. Sandbox defaults (FORCE_COLOR=1, etc.)
4473
4523
  * 3. KICI_* system vars (orchestrator-generated, from userEnv)
4474
- * 4. Org-level environment vars (from orchestrator via environmentVars)
4475
- * 5. Source-level environment overrides (merged into environmentVars by orchestrator)
4524
+ * 4. Org-level environment vars (from orchestrator via contextVars)
4525
+ * 5. Source-level environment overrides (merged into contextVars by orchestrator)
4476
4526
  * 6. Job env (from lock file env field, evaluated by orchestrator)
4477
4527
  * 7. setEnv() calls (runtime -- applied at step execution, not here)
4478
4528
  */
@@ -4494,19 +4544,28 @@ var init_dep_packer = __esmMin((() => {
4494
4544
  * PLATFORM_TOKEN, WEBHOOK_SECRET, etc.) are never included because they
4495
4545
  * are not in the allowlist.
4496
4546
  *
4547
+ * The `trustedEnv` option (default false) selects the trusted fleet-agent
4548
+ * profile: Layer 1 passes the ambient host env through instead of restricting
4549
+ * to `ALLOWED_SYSTEM_VARS`, minus the agent's own KiCI identity/operational
4550
+ * secrets (the whole `KICI_*` namespace + a small non-`KICI_` infra denylist).
4551
+ * It is read ONLY from agent config (`KICI_TRUSTED_ENV`), never from a dispatch
4552
+ * payload, so a workflow cannot request it. With it OFF the output is
4553
+ * byte-identical to the allowlist-only behavior.
4554
+ *
4497
4555
  * @param userEnv - Environment variables from workflow config and orchestrator
4498
4556
  * @param options - Optional extended options for environment layers
4499
4557
  * @returns A new Record with only safe environment variables
4500
4558
  */
4501
4559
  function buildSanitizedEnv(userEnv, options) {
4502
4560
  const sanitized = {};
4503
- for (const key of ALLOWED_SYSTEM_VARS) {
4561
+ if (options?.trustedEnv) Object.assign(sanitized, buildTrustedPassthroughEnv(process.env));
4562
+ else for (const key of ALLOWED_SYSTEM_VARS) {
4504
4563
  const value = process.env[key];
4505
4564
  if (value !== void 0) sanitized[key] = value;
4506
4565
  }
4507
4566
  Object.assign(sanitized, SANDBOX_DEFAULT_VARS);
4508
4567
  Object.assign(sanitized, userEnv);
4509
- if (options?.environmentVars) Object.assign(sanitized, options.environmentVars);
4568
+ if (options?.contextVars) Object.assign(sanitized, options.contextVars);
4510
4569
  if (options?.jobEnv) Object.assign(sanitized, options.jobEnv);
4511
4570
  return sanitized;
4512
4571
  }
@@ -4639,8 +4698,8 @@ function buildRequest(dispatch, workDir) {
4639
4698
  cliPublicKey: jobConfig.cliPublicKey,
4640
4699
  orchestratorPrivateKey: jobConfig.orchestratorPrivateKey,
4641
4700
  runPublicKey: dispatch.runPublicKey,
4642
- environment: jobConfig.environment,
4643
- environmentVars: jobConfig.environmentVars,
4701
+ context: jobConfig.context,
4702
+ contextVars: jobConfig.contextVars,
4644
4703
  jobEnv: jobConfig.jobEnv,
4645
4704
  isGlobalWorkflow: jobConfig.isGlobalWorkflow,
4646
4705
  workflowRepoUrl: jobConfig.workflowRepoUrl,
@@ -5855,7 +5914,8 @@ var init_sandbox = __esmMin((() => {
5855
5914
  //#region src/execution/job-runner.ts
5856
5915
  var job_runner_exports = /* @__PURE__ */ __exportAll({
5857
5916
  JobRunner: () => JobRunner$1,
5858
- buildEvalNeedsContext: () => buildEvalNeedsContext
5917
+ buildEvalNeedsContext: () => buildEvalNeedsContext,
5918
+ resolveJobWorkDir: () => resolveJobWorkDir
5859
5919
  });
5860
5920
  /**
5861
5921
  * Check if a file exists at the given path.
@@ -5912,6 +5972,36 @@ function buildEvalNeedsContext(config) {
5912
5972
  if (!config.resultAware || !config.upstreamSnapshot) return void 0;
5913
5973
  return buildNeedsContext(config.upstreamSnapshot, config.declaredNeeds ?? []);
5914
5974
  }
5975
+ /**
5976
+ * Resolve a job's workDir and its cleanup.
5977
+ *
5978
+ * - Default: a fresh `mkdtemp` the agent clones into and removes after the job.
5979
+ * - **In-place profile** (`inPlace` config + a `file://` source): the source's
5980
+ * real repo path used directly as the workDir, with **no clone** and **no
5981
+ * removal**. This is the routed `deploy:stg` profile — the operator runs their
5982
+ * own already-built working tree (module-relative `MONOREPO_ROOT`,
5983
+ * `node_modules`, `dist` all present). Gated to `file://` so a
5984
+ * Platform-connected agent (https sources) can never be pushed onto a tree,
5985
+ * and read only from agent config (never a dispatch/wire value).
5986
+ */
5987
+ async function resolveJobWorkDir(inPlace, repoUrl) {
5988
+ if (inPlace && repoUrl && repoUrl.startsWith("file://")) return {
5989
+ workDir: fileURLToPath(repoUrl),
5990
+ cleanup: async () => {},
5991
+ inPlace: true
5992
+ };
5993
+ const workDir = await fsPromises.mkdtemp(join(tmpdir(), "kici-"));
5994
+ return {
5995
+ workDir,
5996
+ cleanup: async () => {
5997
+ await fsPromises.rm(workDir, {
5998
+ recursive: true,
5999
+ force: true
6000
+ }).catch(() => {});
6001
+ },
6002
+ inPlace: false
6003
+ };
6004
+ }
5915
6005
  var logger$2, JobRunner$1;
5916
6006
  var init_job_runner = __esmMin((() => {
5917
6007
  init_git_clone();
@@ -5922,6 +6012,7 @@ var init_job_runner = __esmMin((() => {
5922
6012
  init_api_intercept();
5923
6013
  init_ensure_init_runner();
5924
6014
  init_timeout_util();
6015
+ init_streaming_zx_log();
5925
6016
  init_dynamic_job_serializer();
5926
6017
  init_log_streamer();
5927
6018
  init_overlay_applier();
@@ -5978,14 +6069,12 @@ var init_job_runner = __esmMin((() => {
5978
6069
  async execute(dispatch) {
5979
6070
  const { runId: _runId, jobId, jobConfig: _jobConfig } = dispatch;
5980
6071
  const abortController = new AbortController();
5981
- const workDir = await fsPromises.mkdtemp(join(tmpdir(), "kici-"));
6072
+ const { workDir, cleanup, inPlace } = await resolveJobWorkDir(this.config.inPlace, dispatch.repoUrl);
6073
+ if (inPlace) dispatch.jobConfig.checkout = false;
5982
6074
  const completionPromise = this.runJob(dispatch, workDir, abortController).finally(async () => {
5983
6075
  this.activeJobs.delete(jobId);
5984
6076
  this.activeSandbox = null;
5985
- await fsPromises.rm(workDir, {
5986
- recursive: true,
5987
- force: true
5988
- }).catch(() => {});
6077
+ await cleanup();
5989
6078
  });
5990
6079
  this.activeJobs.set(jobId, {
5991
6080
  abortController,
@@ -6111,8 +6200,9 @@ var init_job_runner = __esmMin((() => {
6111
6200
  const runnerPath = resolveRunnerPath();
6112
6201
  const typedConfig = jobConfig;
6113
6202
  const sanitizedEnv = buildSanitizedEnv(typedConfig.env ?? {}, {
6114
- environmentVars: typedConfig.environmentVars ?? void 0,
6115
- jobEnv: typedConfig.jobEnv ?? void 0
6203
+ contextVars: typedConfig.contextVars ?? void 0,
6204
+ jobEnv: typedConfig.jobEnv ?? void 0,
6205
+ trustedEnv: this.config.trustedEnv
6116
6206
  });
6117
6207
  logger$2.info("Creating execution sandbox", {
6118
6208
  executionMode,
@@ -6583,9 +6673,9 @@ var init_job_runner = __esmMin((() => {
6583
6673
  const initResult = await runCaptured(initSink, async () => {
6584
6674
  const { module } = await loadWorkflowSource(workDir, config.source, config.contentHash, config.resolvedHashFiles);
6585
6675
  const workflow = extractWorkflow(module, config.workflowName);
6586
- initLog(`Evaluating dynamic fields for job '${config.targetJobName}' (env=${config.dynamicEnv} environment=${config.dynamicEnvironment} concurrencyGroup=${config.dynamicConcurrencyGroup} matrix=${config.dynamicMatrix ?? false})`);
6676
+ initLog(`Evaluating dynamic fields for job '${config.targetJobName}' (env=${config.dynamicEnv} context=${config.dynamicContext} concurrencyGroup=${config.dynamicConcurrencyGroup} matrix=${config.dynamicMatrix ?? false})`);
6587
6677
  return evaluateDynamicFields(workflow, config.targetJobName, config.event, {
6588
- dynamicEnvironment: config.dynamicEnvironment,
6678
+ dynamicContext: config.dynamicContext,
6589
6679
  dynamicEnv: config.dynamicEnv,
6590
6680
  dynamicConcurrencyGroup: config.dynamicConcurrencyGroup,
6591
6681
  dynamicMatrix: config.dynamicMatrix ?? false
@@ -6593,7 +6683,7 @@ var init_job_runner = __esmMin((() => {
6593
6683
  });
6594
6684
  logger$2.info("Init job completed successfully", {
6595
6685
  jobId,
6596
- hasEnvironment: initResult.environmentNames !== void 0,
6686
+ hasContext: initResult.contextNames !== void 0,
6597
6687
  hasEnv: initResult.env !== void 0,
6598
6688
  hasConcurrencyGroup: initResult.concurrencyGroup !== void 0
6599
6689
  });
@@ -6688,20 +6778,12 @@ var init_job_runner = __esmMin((() => {
6688
6778
  });
6689
6779
  }
6690
6780
  const { $: zx$ } = await import("zx");
6691
- let zxLineBuf = "";
6692
6781
  const scopedDollar = zx$({
6693
6782
  cwd: workDir,
6694
6783
  env: { ...process.env },
6695
- verbose: false,
6784
+ verbose: true,
6696
6785
  quiet: false,
6697
- log: ((entry) => {
6698
- if (entry.kind !== "stdout" && entry.kind !== "stderr") return;
6699
- const text = typeof entry.data === "string" ? entry.data : String(entry.data ?? "");
6700
- zxLineBuf += text;
6701
- const lines = zxLineBuf.split("\n");
6702
- zxLineBuf = lines.pop();
6703
- for (const line of lines) if (line) evalStreamer.addLine(line);
6704
- })
6786
+ log: makeStreamingZxLog((line) => evalStreamer.addLine(line))
6705
6787
  });
6706
6788
  const evalSink = { addLine: (line) => evalStreamer.addLine(line) };
6707
6789
  const dynamicJobLogger = {
@@ -6944,14 +7026,14 @@ var init_job_runner = __esmMin((() => {
6944
7026
  */
6945
7027
  init_console_capture();
6946
7028
  init_npm_resolver();
6947
- const AGENT_VERSION = "0.1.26";
6948
- const BUILD_COMMIT = "85120b08f";
6949
- const SDK_VERSION = "0.1.26";
7029
+ const AGENT_VERSION = "0.1.27";
7030
+ const BUILD_COMMIT = "f0747470b";
7031
+ const SDK_VERSION = "0.1.27";
6950
7032
  const SDK_BUNDLE_HASH = "e06bd1acf349ba365bdb357f3d865e0cbb4ad4604a0270b707a681a4f440954e";
6951
- const SHARED_VERSION = "0.1.26";
6952
- const SHARED_BUNDLE_HASH = "2394db0d8560b2cebf220c0e2d8993c75083aaf70a5917c35099b24feb3a22ba";
6953
- const ENGINE_VERSION = "0.1.26";
6954
- const ENGINE_BUNDLE_HASH = "c3320e812b8593d692f3fbf5eafe83507270028f7a1174c607881105dd702654";
7033
+ const SHARED_VERSION = "0.1.27";
7034
+ const SHARED_BUNDLE_HASH = "f8e1f0117cf41fca5a74377633e2ec89e54ce4eda47d9f476cdb83336f1ed962";
7035
+ const ENGINE_VERSION = "0.1.27";
7036
+ const ENGINE_BUNDLE_HASH = "ce675fb4790406ed2a938f8f1783db37b283cffd7d8fc1eb12a878e0bfb919b3";
6955
7037
  initTelemetry({
6956
7038
  serviceName: "kici-agent",
6957
7039
  otlpEndpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT
@@ -48,6 +48,49 @@ var __exportAll = (all, no_symbols) => {
48
48
  return target;
49
49
  };
50
50
  //#endregion
51
+ //#region src/execution/streaming-zx-log.ts
52
+ /**
53
+ * Shared factory for the zx `log` callback that streams a subprocess's
54
+ * stdout/stderr into the captured/streamed run log, line by line, via `emit`.
55
+ *
56
+ * zx does NOT write child stdout/stderr to `process.stdout`; it pipes the
57
+ * child stdio to an internal VoidStream and surfaces each chunk through the
58
+ * shell's `log` callback as `{ kind: 'stdout' | 'stderr', data, verbose }`.
59
+ * The `verbose` flag is zx's per-invocation quiet/verbose decision:
60
+ *
61
+ * - stdout entries: `verbose = !piped && (snapshot.verbose && !snapshot.quiet)`
62
+ * - stderr entries: `verbose = !snapshot.quiet`
63
+ *
64
+ * so a step that opts into `$({ quiet: true })` (e.g. a `sops -d` decrypt of a
65
+ * credential) produces `verbose: false` entries. This factory HONORS that flag
66
+ * — it skips `verbose: false` entries — which is what makes `{ quiet: true }`
67
+ * actually suppress sensitive output from the run log. Without the gate, a
68
+ * decrypted-secret line leaks into the persisted/streamed log (zx's own default
69
+ * log function gates on the same flag: `if (!entry.verbose) return`).
70
+ *
71
+ * IMPORTANT: the shell that installs this callback MUST be constructed with
72
+ * `verbose: true`. With `verbose: true` zx flags ordinary (non-quiet)
73
+ * subprocess output `verbose: true` (captured) and a `{ quiet: true }` call
74
+ * `verbose: false` (suppressed). A `verbose: false` base would flag ordinary
75
+ * output `verbose: false` too, and this gate would then drop every line.
76
+ *
77
+ * The returned callback owns a per-shell line buffer, so partial chunks are
78
+ * coalesced into whole lines before `emit` is called.
79
+ */
80
+ function makeStreamingZxLog(emit) {
81
+ let lineBuf = "";
82
+ return (entry) => {
83
+ const e = entry;
84
+ if (e.kind !== "stdout" && e.kind !== "stderr") return;
85
+ if (!e.verbose) return;
86
+ const text = typeof e.data === "string" ? e.data : String(e.data ?? "");
87
+ lineBuf += text;
88
+ const lines = lineBuf.split("\n");
89
+ lineBuf = lines.pop();
90
+ for (const line of lines) if (line) emit(line);
91
+ };
92
+ }
93
+ //#endregion
51
94
  //#region src/provenance/statement-builder.ts
52
95
  /**
53
96
  * Build a SLSA v1.0 in-toto provenance statement from the server-truth identity
@@ -3493,7 +3536,7 @@ function logSubprocessStreams(e, tokens) {
3493
3536
  * no Rolldown step at runtime. `@kici-dev/sdk` and host-repo deps resolve via
3494
3537
  * Node's normal ESM lookup against `.kici/node_modules/`.
3495
3538
  */
3496
- const AGENT_SDK_VERSION = "0.1.26";
3539
+ const AGENT_SDK_VERSION = "0.1.27";
3497
3540
  const AGENT_SDK_BUNDLE_HASH = "e06bd1acf349ba365bdb357f3d865e0cbb4ad4604a0270b707a681a4f440954e";
3498
3541
  /**
3499
3542
  * Register the `@kici-dev/core/ts-loader-hook` oxc-transform ESM loader hook so
@@ -3856,7 +3899,7 @@ async function applyOverlay(config) {
3856
3899
  */
3857
3900
  init_download();
3858
3901
  init_dep_restore();
3859
- const AGENT_VERSION = "0.1.26";
3902
+ const AGENT_VERSION = "0.1.27";
3860
3903
  process.on("uncaughtException", (err) => {
3861
3904
  process.stderr.write(`[workflow-runner] UNCAUGHT EXCEPTION: ${err.message}\n`);
3862
3905
  if (err.stack) process.stderr.write(`[workflow-runner] Stack: ${err.stack}\n`);
@@ -4716,10 +4759,16 @@ function createSecretMasker(request) {
4716
4759
  *
4717
4760
  * Intercept zx subprocess output via the log callback: zx does NOT write child
4718
4761
  * stdout/stderr to process.stdout — it pipes to an internal VoidStream and only
4719
- * calls $.log() with { kind: 'stdout'|'stderr' }. With verbose=false the default
4720
- * log function skips stdout entirely, and with quiet=false it writes stderr to
4721
- * process.stderr. We override the log function to capture both kinds directly
4722
- * and send them as masked IPC log.line messages tagged with `stepIndex`.
4762
+ * calls $.log() with { kind: 'stdout'|'stderr', verbose }. We override the log
4763
+ * function (`makeStreamingZxLog`) to capture both kinds and send them as masked
4764
+ * IPC log.line messages tagged with `stepIndex`.
4765
+ *
4766
+ * The shell is built with `verbose: true` so ordinary subprocess output is
4767
+ * flagged `verbose: true` (captured) while a step that opts into
4768
+ * `$({ quiet: true })` — e.g. a `sops -d` credential decrypt — is flagged
4769
+ * `verbose: false` and dropped by `makeStreamingZxLog`. That gate is what keeps
4770
+ * a decrypted secret out of the streamed run log; a `verbose: false` base would
4771
+ * flag ordinary output `verbose: false` too and drop every line.
4723
4772
  *
4724
4773
  * IMPORTANT: The log function must be passed in the zx$() config, not set on the
4725
4774
  * returned function. zx$() returns a plain function (not the proxy $), so setting
@@ -4727,26 +4776,16 @@ function createSecretMasker(request) {
4727
4776
  * AsyncLocalStorage store that zx uses for ProcessPromise snapshots.
4728
4777
  */
4729
4778
  function buildSandboxShell(cwd, stepIndex, maskedSendFn) {
4730
- let zxLineBuf = "";
4731
4779
  return $({
4732
4780
  cwd,
4733
4781
  env: { ...process.env },
4734
- verbose: false,
4782
+ verbose: true,
4735
4783
  quiet: false,
4736
- log: ((entry) => {
4737
- if (entry.kind === "stdout" || entry.kind === "stderr") {
4738
- const text = typeof entry.data === "string" ? entry.data : String(entry.data ?? "");
4739
- zxLineBuf += text;
4740
- const lines = zxLineBuf.split("\n");
4741
- zxLineBuf = lines.pop();
4742
- for (const line of lines) if (line) maskedSendFn({
4743
- type: "log.line",
4744
- stepIndex,
4745
- line
4746
- });
4747
- return;
4748
- }
4749
- })
4784
+ log: makeStreamingZxLog((line) => maskedSendFn({
4785
+ type: "log.line",
4786
+ stepIndex,
4787
+ line
4788
+ }))
4750
4789
  });
4751
4790
  }
4752
4791
  /**
@@ -4800,7 +4839,7 @@ function createSandboxStepContext(workDir, stepIndex, stepName, request, maskedS
4800
4839
  runsOn: request.runsOn
4801
4840
  },
4802
4841
  isTestRun: request.isTestRun ?? false,
4803
- environment: request.environment,
4842
+ context: request.context,
4804
4843
  cache: createCacheApi(workDir, buildCacheTransport()),
4805
4844
  emit: async (eventName, payload, options) => {
4806
4845
  const reqId = randomUUID();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kici-dev/agent",
3
- "version": "0.1.26",
3
+ "version": "0.1.27",
4
4
  "description": "Customer-deployable agent for the KiCI CI/CD stack. Connects to an orchestrator, clones the workflow repo, executes steps, and streams logs back.",
5
5
  "keywords": [
6
6
  "ci",
@@ -64,10 +64,10 @@
64
64
  "yaml": "^2.9.0",
65
65
  "zod": "^4.4.3",
66
66
  "zx": "^8.8.5",
67
- "@kici-dev/core": "0.1.26",
68
- "@kici-dev/engine": "0.1.26",
69
- "@kici-dev/sdk": "0.1.26",
70
- "@kici-dev/shared": "0.1.26"
67
+ "@kici-dev/core": "0.1.27",
68
+ "@kici-dev/engine": "0.1.27",
69
+ "@kici-dev/sdk": "0.1.27",
70
+ "@kici-dev/shared": "0.1.27"
71
71
  },
72
72
  "kici": {
73
73
  "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/agent@0.1.26",
6
- "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fagent/0.1.26/6219ec2d-01e6-4f85-a26d-146376e963ac",
5
+ "name": "@kici-dev/agent@0.1.27",
6
+ "documentNamespace": "https://kici.dev/sbom/%40kici-dev%2Fagent/0.1.27/4c241955-12c0-4d95-a7dc-c6bb021cf653",
7
7
  "creationInfo": {
8
- "created": "2026-07-06T04:30:08Z",
8
+ "created": "2026-07-10T06:04:29Z",
9
9
  "creators": [
10
10
  "Tool: kici-sbom-generator"
11
11
  ]
@@ -816,7 +816,7 @@
816
816
  {
817
817
  "SPDXID": "SPDXRef-RootPackage",
818
818
  "name": "@kici-dev/agent",
819
- "versionInfo": "0.1.26",
819
+ "versionInfo": "0.1.27",
820
820
  "downloadLocation": "NOASSERTION",
821
821
  "filesAnalyzed": false,
822
822
  "licenseConcluded": "NOASSERTION",
@@ -827,16 +827,16 @@
827
827
  {
828
828
  "referenceCategory": "PACKAGE-MANAGER",
829
829
  "referenceType": "purl",
830
- "referenceLocator": "pkg:npm/%40kici-dev/agent@0.1.26"
830
+ "referenceLocator": "pkg:npm/%40kici-dev/agent@0.1.27"
831
831
  }
832
832
  ],
833
833
  "description": "Customer-deployable agent for the KiCI CI/CD stack. Connects to an orchestrator, clones the workflow repo, executes steps, and streams logs back.",
834
834
  "homepage": "https://kici.dev"
835
835
  },
836
836
  {
837
- "SPDXID": "SPDXRef-Package--kici-dev-core-0.1.26",
837
+ "SPDXID": "SPDXRef-Package--kici-dev-core-0.1.27",
838
838
  "name": "@kici-dev/core",
839
- "versionInfo": "0.1.26",
839
+ "versionInfo": "0.1.27",
840
840
  "downloadLocation": "NOASSERTION",
841
841
  "filesAnalyzed": false,
842
842
  "licenseConcluded": "NOASSERTION",
@@ -847,16 +847,16 @@
847
847
  {
848
848
  "referenceCategory": "PACKAGE-MANAGER",
849
849
  "referenceType": "purl",
850
- "referenceLocator": "pkg:npm/%40kici-dev/core@0.1.26"
850
+ "referenceLocator": "pkg:npm/%40kici-dev/core@0.1.27"
851
851
  }
852
852
  ],
853
853
  "description": "Light shared utilities for the KiCI stack (logging, errors, formatting, crypto, zx init, the TypeScript ESM loader hook). No server-side dependencies.",
854
854
  "homepage": "https://kici.dev"
855
855
  },
856
856
  {
857
- "SPDXID": "SPDXRef-Package--kici-dev-engine-0.1.26",
857
+ "SPDXID": "SPDXRef-Package--kici-dev-engine-0.1.27",
858
858
  "name": "@kici-dev/engine",
859
- "versionInfo": "0.1.26",
859
+ "versionInfo": "0.1.27",
860
860
  "downloadLocation": "NOASSERTION",
861
861
  "filesAnalyzed": false,
862
862
  "licenseConcluded": "NOASSERTION",
@@ -867,16 +867,16 @@
867
867
  {
868
868
  "referenceCategory": "PACKAGE-MANAGER",
869
869
  "referenceType": "purl",
870
- "referenceLocator": "pkg:npm/%40kici-dev/engine@0.1.26"
870
+ "referenceLocator": "pkg:npm/%40kici-dev/engine@0.1.27"
871
871
  }
872
872
  ],
873
873
  "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.",
874
874
  "homepage": "https://kici.dev"
875
875
  },
876
876
  {
877
- "SPDXID": "SPDXRef-Package--kici-dev-sdk-0.1.26",
877
+ "SPDXID": "SPDXRef-Package--kici-dev-sdk-0.1.27",
878
878
  "name": "@kici-dev/sdk",
879
- "versionInfo": "0.1.26",
879
+ "versionInfo": "0.1.27",
880
880
  "downloadLocation": "NOASSERTION",
881
881
  "filesAnalyzed": false,
882
882
  "licenseConcluded": "NOASSERTION",
@@ -887,16 +887,16 @@
887
887
  {
888
888
  "referenceCategory": "PACKAGE-MANAGER",
889
889
  "referenceType": "purl",
890
- "referenceLocator": "pkg:npm/%40kici-dev/sdk@0.1.26"
890
+ "referenceLocator": "pkg:npm/%40kici-dev/sdk@0.1.27"
891
891
  }
892
892
  ],
893
893
  "description": "TypeScript SDK for defining KiCI workflows. Import into `.kici/workflows/*.ts` to declare workflows, jobs, steps, triggers, rules, and matrix configurations.",
894
894
  "homepage": "https://kici.dev"
895
895
  },
896
896
  {
897
- "SPDXID": "SPDXRef-Package--kici-dev-shared-0.1.26",
897
+ "SPDXID": "SPDXRef-Package--kici-dev-shared-0.1.27",
898
898
  "name": "@kici-dev/shared",
899
- "versionInfo": "0.1.26",
899
+ "versionInfo": "0.1.27",
900
900
  "downloadLocation": "NOASSERTION",
901
901
  "filesAnalyzed": false,
902
902
  "licenseConcluded": "NOASSERTION",
@@ -907,7 +907,7 @@
907
907
  {
908
908
  "referenceCategory": "PACKAGE-MANAGER",
909
909
  "referenceType": "purl",
910
- "referenceLocator": "pkg:npm/%40kici-dev/shared@0.1.26"
910
+ "referenceLocator": "pkg:npm/%40kici-dev/shared@0.1.27"
911
911
  }
912
912
  ],
913
913
  "description": "Shared utilities for the KiCI CI/CD stack — logging, zx setup, crypto, telemetry, health and metrics routes. No business logic.",
@@ -6209,22 +6209,22 @@
6209
6209
  },
6210
6210
  {
6211
6211
  "spdxElementId": "SPDXRef-RootPackage",
6212
- "relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.26",
6212
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.27",
6213
6213
  "relationshipType": "DEPENDS_ON"
6214
6214
  },
6215
6215
  {
6216
6216
  "spdxElementId": "SPDXRef-RootPackage",
6217
- "relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.26",
6217
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.27",
6218
6218
  "relationshipType": "DEPENDS_ON"
6219
6219
  },
6220
6220
  {
6221
6221
  "spdxElementId": "SPDXRef-RootPackage",
6222
- "relatedSpdxElement": "SPDXRef-Package--kici-dev-sdk-0.1.26",
6222
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-sdk-0.1.27",
6223
6223
  "relationshipType": "DEPENDS_ON"
6224
6224
  },
6225
6225
  {
6226
6226
  "spdxElementId": "SPDXRef-RootPackage",
6227
- "relatedSpdxElement": "SPDXRef-Package--kici-dev-shared-0.1.26",
6227
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-shared-0.1.27",
6228
6228
  "relationshipType": "DEPENDS_ON"
6229
6229
  },
6230
6230
  {
@@ -6278,192 +6278,192 @@
6278
6278
  "relationshipType": "DEPENDS_ON"
6279
6279
  },
6280
6280
  {
6281
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.26",
6281
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.27",
6282
6282
  "relatedSpdxElement": "SPDXRef-Package-oxc-transform-0.135.0",
6283
6283
  "relationshipType": "DEPENDS_ON"
6284
6284
  },
6285
6285
  {
6286
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.26",
6286
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.27",
6287
6287
  "relatedSpdxElement": "SPDXRef-Package-picocolors-1.1.1",
6288
6288
  "relationshipType": "DEPENDS_ON"
6289
6289
  },
6290
6290
  {
6291
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.26",
6291
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.27",
6292
6292
  "relatedSpdxElement": "SPDXRef-Package-winston-daily-rotate-file-5.0.0",
6293
6293
  "relationshipType": "DEPENDS_ON"
6294
6294
  },
6295
6295
  {
6296
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.26",
6296
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.27",
6297
6297
  "relatedSpdxElement": "SPDXRef-Package-winston-3.19.0",
6298
6298
  "relationshipType": "DEPENDS_ON"
6299
6299
  },
6300
6300
  {
6301
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.26",
6301
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.27",
6302
6302
  "relatedSpdxElement": "SPDXRef-Package-zod-4.4.3",
6303
6303
  "relationshipType": "DEPENDS_ON"
6304
6304
  },
6305
6305
  {
6306
- "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.26",
6306
+ "spdxElementId": "SPDXRef-Package--kici-dev-core-0.1.27",
6307
6307
  "relatedSpdxElement": "SPDXRef-Package-zx-8.8.5",
6308
6308
  "relationshipType": "DEPENDS_ON"
6309
6309
  },
6310
6310
  {
6311
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.26",
6311
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.27",
6312
6312
  "relatedSpdxElement": "SPDXRef-Package-jose-6.2.3",
6313
6313
  "relationshipType": "DEPENDS_ON"
6314
6314
  },
6315
6315
  {
6316
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.26",
6316
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.27",
6317
6317
  "relatedSpdxElement": "SPDXRef-Package-jsonpath-plus-10.4.0",
6318
6318
  "relationshipType": "DEPENDS_ON"
6319
6319
  },
6320
6320
  {
6321
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.26",
6321
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.27",
6322
6322
  "relatedSpdxElement": "SPDXRef-Package-picomatch-4.0.4",
6323
6323
  "relationshipType": "DEPENDS_ON"
6324
6324
  },
6325
6325
  {
6326
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.26",
6326
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.27",
6327
6327
  "relatedSpdxElement": "SPDXRef-Package-safe-regex-2.1.1",
6328
6328
  "relationshipType": "DEPENDS_ON"
6329
6329
  },
6330
6330
  {
6331
- "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.26",
6331
+ "spdxElementId": "SPDXRef-Package--kici-dev-engine-0.1.27",
6332
6332
  "relatedSpdxElement": "SPDXRef-Package-zod-4.4.3",
6333
6333
  "relationshipType": "DEPENDS_ON"
6334
6334
  },
6335
6335
  {
6336
- "spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.26",
6337
- "relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.26",
6336
+ "spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.27",
6337
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.27",
6338
6338
  "relationshipType": "DEPENDS_ON"
6339
6339
  },
6340
6340
  {
6341
- "spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.26",
6342
- "relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.26",
6341
+ "spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.27",
6342
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-engine-0.1.27",
6343
6343
  "relationshipType": "DEPENDS_ON"
6344
6344
  },
6345
6345
  {
6346
- "spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.26",
6346
+ "spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.27",
6347
6347
  "relatedSpdxElement": "SPDXRef-Package-micromatch-4.0.8",
6348
6348
  "relationshipType": "DEPENDS_ON"
6349
6349
  },
6350
6350
  {
6351
- "spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.26",
6351
+ "spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.27",
6352
6352
  "relatedSpdxElement": "SPDXRef-Package-zod-4.4.3",
6353
6353
  "relationshipType": "DEPENDS_ON"
6354
6354
  },
6355
6355
  {
6356
- "spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.26",
6356
+ "spdxElementId": "SPDXRef-Package--kici-dev-sdk-0.1.27",
6357
6357
  "relatedSpdxElement": "SPDXRef-Package-zx-8.8.5",
6358
6358
  "relationshipType": "DEPENDS_ON"
6359
6359
  },
6360
6360
  {
6361
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6361
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6362
6362
  "relatedSpdxElement": "SPDXRef-Package--aws-sdk-client-s3-3.1064.0",
6363
6363
  "relationshipType": "DEPENDS_ON"
6364
6364
  },
6365
6365
  {
6366
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6367
- "relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.26",
6366
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6367
+ "relatedSpdxElement": "SPDXRef-Package--kici-dev-core-0.1.27",
6368
6368
  "relationshipType": "DEPENDS_ON"
6369
6369
  },
6370
6370
  {
6371
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6371
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6372
6372
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-api-1.9.1",
6373
6373
  "relationshipType": "DEPENDS_ON"
6374
6374
  },
6375
6375
  {
6376
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6376
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6377
6377
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-exporter-metrics-otlp-http-0.218.0",
6378
6378
  "relationshipType": "DEPENDS_ON"
6379
6379
  },
6380
6380
  {
6381
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6381
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6382
6382
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-exporter-prometheus-0.218.0",
6383
6383
  "relationshipType": "DEPENDS_ON"
6384
6384
  },
6385
6385
  {
6386
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6386
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6387
6387
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-exporter-trace-otlp-http-0.218.0",
6388
6388
  "relationshipType": "DEPENDS_ON"
6389
6389
  },
6390
6390
  {
6391
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6391
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6392
6392
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-instrumentation-runtime-node-0.31.0",
6393
6393
  "relationshipType": "DEPENDS_ON"
6394
6394
  },
6395
6395
  {
6396
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6396
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6397
6397
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-resources-2.7.1",
6398
6398
  "relationshipType": "DEPENDS_ON"
6399
6399
  },
6400
6400
  {
6401
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6401
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6402
6402
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-sdk-node-0.218.0",
6403
6403
  "relationshipType": "DEPENDS_ON"
6404
6404
  },
6405
6405
  {
6406
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6406
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6407
6407
  "relatedSpdxElement": "SPDXRef-Package--opentelemetry-semantic-conventions-1.41.1",
6408
6408
  "relationshipType": "DEPENDS_ON"
6409
6409
  },
6410
6410
  {
6411
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6411
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6412
6412
  "relatedSpdxElement": "SPDXRef-Package-archiver-8.0.0",
6413
6413
  "relationshipType": "DEPENDS_ON"
6414
6414
  },
6415
6415
  {
6416
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6416
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6417
6417
  "relatedSpdxElement": "SPDXRef-Package-diff-9.0.0",
6418
6418
  "relationshipType": "DEPENDS_ON"
6419
6419
  },
6420
6420
  {
6421
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6421
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6422
6422
  "relatedSpdxElement": "SPDXRef-Package-hono-4.12.25",
6423
6423
  "relationshipType": "DEPENDS_ON"
6424
6424
  },
6425
6425
  {
6426
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6426
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6427
6427
  "relatedSpdxElement": "SPDXRef-Package-kysely-0.29.2",
6428
6428
  "relationshipType": "DEPENDS_ON"
6429
6429
  },
6430
6430
  {
6431
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6431
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6432
6432
  "relatedSpdxElement": "SPDXRef-Package-oxc-transform-0.135.0",
6433
6433
  "relationshipType": "DEPENDS_ON"
6434
6434
  },
6435
6435
  {
6436
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6436
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6437
6437
  "relatedSpdxElement": "SPDXRef-Package-pg-8.21.0",
6438
6438
  "relationshipType": "DEPENDS_ON"
6439
6439
  },
6440
6440
  {
6441
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6441
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6442
6442
  "relatedSpdxElement": "SPDXRef-Package-picocolors-1.1.1",
6443
6443
  "relationshipType": "DEPENDS_ON"
6444
6444
  },
6445
6445
  {
6446
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6446
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6447
6447
  "relatedSpdxElement": "SPDXRef-Package-winston-daily-rotate-file-5.0.0",
6448
6448
  "relationshipType": "DEPENDS_ON"
6449
6449
  },
6450
6450
  {
6451
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6451
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6452
6452
  "relatedSpdxElement": "SPDXRef-Package-winston-3.19.0",
6453
6453
  "relationshipType": "DEPENDS_ON"
6454
6454
  },
6455
6455
  {
6456
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6456
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6457
6457
  "relatedSpdxElement": "SPDXRef-Package-yaml-2.9.0",
6458
6458
  "relationshipType": "DEPENDS_ON"
6459
6459
  },
6460
6460
  {
6461
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6461
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6462
6462
  "relatedSpdxElement": "SPDXRef-Package-zod-4.4.3",
6463
6463
  "relationshipType": "DEPENDS_ON"
6464
6464
  },
6465
6465
  {
6466
- "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.26",
6466
+ "spdxElementId": "SPDXRef-Package--kici-dev-shared-0.1.27",
6467
6467
  "relatedSpdxElement": "SPDXRef-Package-zx-8.8.5",
6468
6468
  "relationshipType": "DEPENDS_ON"
6469
6469
  },