@kici-dev/shared 0.1.15 → 0.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/dist/cold-store/bucket.js +1 -1
  2. package/dist/cold-store/chunk-encoder.js +1 -1
  3. package/dist/cold-store/chunk-id.js +1 -1
  4. package/dist/cold-store/cold-store.js +1 -1
  5. package/dist/cold-store/config.js +1 -1
  6. package/dist/cold-store/index.js +1 -1
  7. package/dist/cold-store/key.js +1 -1
  8. package/dist/cold-store/lru.js +1 -1
  9. package/dist/cold-store/manifest.js +1 -1
  10. package/dist/cold-store/metrics.js +1 -1
  11. package/dist/cold-store/table-adapter.js +1 -1
  12. package/dist/cold-store/types.js +1 -1
  13. package/dist/db-admin.d.ts +11 -6
  14. package/dist/db-admin.js +10 -8
  15. package/dist/db-collation.js +1 -1
  16. package/dist/db.js +1 -1
  17. package/dist/diagnostics/bundle-archive.d.ts +28 -0
  18. package/dist/diagnostics/bundle-archive.js +141 -0
  19. package/dist/diagnostics/bundle-archive.test.d.ts +2 -0
  20. package/dist/diagnostics/bundle-chunks.d.ts +46 -0
  21. package/dist/diagnostics/bundle-chunks.js +111 -0
  22. package/dist/diagnostics/bundle-chunks.test.d.ts +2 -0
  23. package/dist/env/allowlist.d.ts +5 -1
  24. package/dist/env/allowlist.js +7 -3
  25. package/dist/env/define-env.js +1 -1
  26. package/dist/env/index.js +1 -1
  27. package/dist/env/logger-env.js +1 -1
  28. package/dist/graceful-shutdown.js +1 -1
  29. package/dist/idempotency-env-diff.js +1 -1
  30. package/dist/idempotency-files.js +1 -1
  31. package/dist/idempotency-yaml-diff.js +1 -1
  32. package/dist/idempotency.js +1 -1
  33. package/dist/index.d.ts +2 -0
  34. package/dist/index.js +4 -2
  35. package/dist/package-manager-types.js +1 -1
  36. package/dist/package-manager.js +1 -1
  37. package/dist/reconnect-delay.js +1 -1
  38. package/dist/ring-buffer.js +1 -1
  39. package/dist/routes/health.js +1 -1
  40. package/dist/routes/metrics.js +1 -1
  41. package/dist/s3-client.js +1 -1
  42. package/dist/telemetry/index.js +1 -1
  43. package/dist/telemetry/init.js +1 -1
  44. package/dist/telemetry/metrics.js +1 -1
  45. package/dist/tool-check.js +1 -1
  46. package/dist/ts-loader-hook.js +1 -1
  47. package/package.json +4 -2
  48. package/sbom.spdx.json +2338 -510
  49. /package/dist/{chunk-gOLHoazu.js → chunk-BTugEXQM.js} +0 -0
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  //#region src/cold-store/bucket.ts
3
3
  /**
4
4
  * Map a `ColdRetention` to a stable S3 prefix segment. Rounds
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { sha256 } from "@kici-dev/core";
3
3
  import { gzipSync } from "node:zlib";
4
4
  //#region src/cold-store/chunk-encoder.ts
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { sha256 } from "@kici-dev/core";
3
3
  //#region src/cold-store/chunk-id.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { createS3Client } from "../s3-client.js";
3
3
  import { chunkObjectKey, encodeKeySegment, tablePrefix, tenantDayPrefix } from "./key.js";
4
4
  import { coldDaysToBucket, isLongerColdRetention } from "./bucket.js";
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  //#region src/cold-store/config.ts
3
3
  /**
4
4
  * Reasonable defaults — matches the design doc's section 5 table.
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { chunkObjectKey, encodeKeySegment, tablePrefix, tenantDayBucketPrefix, tenantDayPrefix } from "./key.js";
3
3
  import { COLD_BUCKET_NAMES, coldDaysToBucket, isLongerColdRetention } from "./bucket.js";
4
4
  import { computeChunkId } from "./chunk-id.js";
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  //#region src/cold-store/key.ts
3
3
  /**
4
4
  * Key helpers for S3 object layouts.
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  //#region src/cold-store/lru.ts
3
3
  var ChunkLru = class {
4
4
  maxBytes;
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  //#region src/cold-store/manifest.ts
3
3
  /**
4
4
  * Required fields shared by v1 and v2 manifests. Order is the on-disk
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { createMeter } from "../telemetry/metrics.js";
3
3
  //#region src/cold-store/metrics.ts
4
4
  let _meter;
@@ -1,2 +1,2 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  export {};
@@ -1,2 +1,2 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  export {};
@@ -553,8 +553,8 @@ export interface EmitKiciEventOpts {
553
553
  * e2e helpers to simulate what `agent ctx.emit()` does from inside a step
554
554
  * execution — but without needing an actual running step. Returns the event id.
555
555
  *
556
- * Fixed `chain_depth=0` and `expires_at=NOW() + 1h` match emitInternalEvent()
557
- * in e2e/helpers/internal-webhook.ts, which this helper supersedes.
556
+ * Fixed `chain_depth=0` and `expires_at=NOW() + 1h` match emitLocalEvent()
557
+ * in e2e/helpers/local-webhook.ts, which this helper supersedes.
558
558
  */
559
559
  export declare function emitKiciEventDirect(databaseUrl: string, opts: EmitKiciEventOpts): Promise<{
560
560
  eventId: string;
@@ -567,18 +567,23 @@ export interface SeedGenericWebhookSourceOpts {
567
567
  /** Pre-computed routing key (caller uses `generic:${orgId}:${name}`) */
568
568
  routingKey: string;
569
569
  verificationMethod?: string;
570
- /** 'generic' (Stripe-shaped) or 'internal' (github-shaped via InternalWebhookNormalizer) */
571
- providerType?: 'generic' | 'internal';
570
+ /** 'generic' (Stripe-shaped) or 'local' (github-shaped via LocalWebhookNormalizer,
571
+ * a git repo present on the agent filesystem cloned via file://). */
572
+ providerType?: 'generic' | 'local';
573
+ /** For `providerType='local'`: the per-source `{ repoBasePath, cloneUrlBase? }`
574
+ * stored in `git_config`. The orchestrator reads `repoBasePath` from this row
575
+ * at registration time to build the local provider bundle. */
576
+ gitConfig?: Record<string, unknown>;
572
577
  }
573
578
  /**
574
- * Upsert a row into `generic_webhook_sources` for internal E2E tests. Uses
579
+ * Upsert a row into `generic_webhook_sources`. Uses
575
580
  * `ON CONFLICT (routing_key) DO UPDATE` so warm-start mode (where the source
576
581
  * may already exist from a prior run) is idempotent.
577
582
  *
578
583
  * IMPORTANT: callers must invoke this BEFORE the orchestrator starts, because
579
584
  * GenericSourceManager caches sources at boot and does not reload them later.
580
585
  * This helper supersedes seedGenericWebhookSource() in
581
- * e2e/helpers/internal-webhook.ts.
586
+ * e2e/helpers/local-webhook.ts.
582
587
  */
583
588
  export declare function seedGenericWebhookSourceDirect(databaseUrl: string, opts: SeedGenericWebhookSourceOpts): Promise<void>;
584
589
  /**
package/dist/db-admin.js CHANGED
@@ -1,4 +1,4 @@
1
- import "./chunk-gOLHoazu.js";
1
+ import "./chunk-BTugEXQM.js";
2
2
  import { createPool } from "./db.js";
3
3
  import { createHash } from "node:crypto";
4
4
  import pg from "pg";
@@ -992,8 +992,8 @@ async function resetRaftStateDirect(databaseUrl) {
992
992
  * e2e helpers to simulate what `agent ctx.emit()` does from inside a step
993
993
  * execution — but without needing an actual running step. Returns the event id.
994
994
  *
995
- * Fixed `chain_depth=0` and `expires_at=NOW() + 1h` match emitInternalEvent()
996
- * in e2e/helpers/internal-webhook.ts, which this helper supersedes.
995
+ * Fixed `chain_depth=0` and `expires_at=NOW() + 1h` match emitLocalEvent()
996
+ * in e2e/helpers/local-webhook.ts, which this helper supersedes.
997
997
  */
998
998
  async function emitKiciEventDirect(databaseUrl, opts) {
999
999
  const pool = createPool(databaseUrl);
@@ -1016,14 +1016,14 @@ async function emitKiciEventDirect(databaseUrl, opts) {
1016
1016
  }
1017
1017
  }
1018
1018
  /**
1019
- * Upsert a row into `generic_webhook_sources` for internal E2E tests. Uses
1019
+ * Upsert a row into `generic_webhook_sources`. Uses
1020
1020
  * `ON CONFLICT (routing_key) DO UPDATE` so warm-start mode (where the source
1021
1021
  * may already exist from a prior run) is idempotent.
1022
1022
  *
1023
1023
  * IMPORTANT: callers must invoke this BEFORE the orchestrator starts, because
1024
1024
  * GenericSourceManager caches sources at boot and does not reload them later.
1025
1025
  * This helper supersedes seedGenericWebhookSource() in
1026
- * e2e/helpers/internal-webhook.ts.
1026
+ * e2e/helpers/local-webhook.ts.
1027
1027
  */
1028
1028
  async function seedGenericWebhookSourceDirect(databaseUrl, opts) {
1029
1029
  const pool = createPool(databaseUrl);
@@ -1033,14 +1033,15 @@ async function seedGenericWebhookSourceDirect(databaseUrl, opts) {
1033
1033
  verification_method, verification_config,
1034
1034
  event_type_header, dedup_window_seconds,
1035
1035
  max_payload_bytes, rate_limit_rpm, enabled,
1036
- provider_type
1037
- ) VALUES ($1, $2, $3, $4, $5, '{}', 'x-event-type', 300, 10485760, 600, true, $6)
1036
+ provider_type, git_config
1037
+ ) VALUES ($1, $2, $3, $4, $5, '{}', 'x-event-type', 300, 10485760, 600, true, $6, $7::jsonb)
1038
1038
  ON CONFLICT (routing_key) DO UPDATE SET
1039
1039
  customer_id = EXCLUDED.customer_id,
1040
1040
  name = EXCLUDED.name,
1041
1041
  verification_method = EXCLUDED.verification_method,
1042
1042
  verification_config = EXCLUDED.verification_config,
1043
1043
  provider_type = EXCLUDED.provider_type,
1044
+ git_config = EXCLUDED.git_config,
1044
1045
  enabled = true,
1045
1046
  deleted_at = NULL,
1046
1047
  updated_at = NOW()`, [
@@ -1049,7 +1050,8 @@ async function seedGenericWebhookSourceDirect(databaseUrl, opts) {
1049
1050
  opts.name,
1050
1051
  opts.routingKey,
1051
1052
  opts.verificationMethod ?? "none",
1052
- opts.providerType ?? "generic"
1053
+ opts.providerType ?? "generic",
1054
+ opts.gitConfig ? JSON.stringify(opts.gitConfig) : null
1053
1055
  ]);
1054
1056
  } finally {
1055
1057
  await pool.end();
@@ -1,4 +1,4 @@
1
- import "./chunk-gOLHoazu.js";
1
+ import "./chunk-BTugEXQM.js";
2
2
  import pg from "pg";
3
3
  //#region src/db-collation.ts
4
4
  /**
package/dist/db.js CHANGED
@@ -1,4 +1,4 @@
1
- import "./chunk-gOLHoazu.js";
1
+ import "./chunk-BTugEXQM.js";
2
2
  import pg from "pg";
3
3
  import { Kysely, PostgresDialect } from "kysely";
4
4
  import { createLogger } from "@kici-dev/core";
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Shared debug-bundle archive primitives.
3
+ *
4
+ * Allowlist config redaction and windowed log-file archiving, used by the
5
+ * orchestrator's in-process bundle writer, the kici-admin CLI's local bundle,
6
+ * and the agent's fleet mini-bundle assembler. Keeping one copy means a node
7
+ * cannot drift from the redaction posture of its peers.
8
+ */
9
+ import type archiver from 'archiver';
10
+ /** Maximum total log bytes to include in bundle (50MB). */
11
+ export declare const MAX_LOG_BYTES: number;
12
+ /**
13
+ * Redact config values using allowlist approach.
14
+ * Only known-safe fields are preserved; everything else becomes "****".
15
+ */
16
+ export declare function redactConfig(obj: unknown, parentKey?: string): unknown;
17
+ /**
18
+ * Add log files from logDir to the archive, respecting MAX_LOG_BYTES cap
19
+ * and the logWindow time filter. Matches any `*.log` file in the directory,
20
+ * so the per-instance filename pattern produced by
21
+ * `buildLogFilename()` is picked up without additional configuration.
22
+ *
23
+ * Exported for reuse by the `kici-admin debug-bundle` CLI command, which
24
+ * runs outside the orchestrator process but still needs to include the
25
+ * same log files in its locally-assembled bundle.
26
+ */
27
+ export declare function addLogsToArchive(archive: archiver.Archiver, logDir: string, logWindowHours: number): Promise<void>;
28
+ //# sourceMappingURL=bundle-archive.d.ts.map
@@ -0,0 +1,141 @@
1
+ import "../chunk-BTugEXQM.js";
2
+ import * as fs from "node:fs";
3
+ import * as path from "node:path";
4
+ //#region src/diagnostics/bundle-archive.ts
5
+ /**
6
+ * Shared debug-bundle archive primitives.
7
+ *
8
+ * Allowlist config redaction and windowed log-file archiving, used by the
9
+ * orchestrator's in-process bundle writer, the kici-admin CLI's local bundle,
10
+ * and the agent's fleet mini-bundle assembler. Keeping one copy means a node
11
+ * cannot drift from the redaction posture of its peers.
12
+ */
13
+ /** Maximum total log bytes to include in bundle (50MB). */
14
+ const MAX_LOG_BYTES = 50 * 1024 * 1024;
15
+ /**
16
+ * Config field names that are safe to include unredacted.
17
+ * Everything else gets replaced with "****".
18
+ */
19
+ const SAFE_CONFIG_KEYS = new Set([
20
+ "mode",
21
+ "host",
22
+ "port",
23
+ "logLevel",
24
+ "region",
25
+ "environment",
26
+ "name",
27
+ "label",
28
+ "labels",
29
+ "enabled",
30
+ "disabled",
31
+ "timeout",
32
+ "interval",
33
+ "maxRetries",
34
+ "retries",
35
+ "workers",
36
+ "concurrency",
37
+ "maxConcurrency",
38
+ "batchSize",
39
+ "bufferSize",
40
+ "warmPool",
41
+ "cooldown",
42
+ "type",
43
+ "provider",
44
+ "scaler",
45
+ "driver",
46
+ "backend",
47
+ "protocol",
48
+ "scheme",
49
+ "path",
50
+ "basePath",
51
+ "metricsPath",
52
+ "healthPath",
53
+ "logFormat",
54
+ "logFile",
55
+ "logDir",
56
+ "dataDir",
57
+ "version",
58
+ "debug",
59
+ "verbose",
60
+ "quiet",
61
+ "tls",
62
+ "cors",
63
+ "rateLimiting",
64
+ "maxConnections",
65
+ "poolSize",
66
+ "minPool",
67
+ "maxPool",
68
+ "idleTimeout",
69
+ "connectTimeout",
70
+ "requestTimeout",
71
+ "shutdownTimeout",
72
+ "gracefulShutdown"
73
+ ]);
74
+ /**
75
+ * Redact config values using allowlist approach.
76
+ * Only known-safe fields are preserved; everything else becomes "****".
77
+ */
78
+ function redactConfig(obj, parentKey) {
79
+ if (obj === null || obj === void 0) return obj;
80
+ if (Array.isArray(obj)) return obj.map((item) => redactConfig(item, parentKey));
81
+ if (typeof obj === "object") {
82
+ const result = {};
83
+ for (const [key, value] of Object.entries(obj)) result[key] = redactConfig(value, key);
84
+ return result;
85
+ }
86
+ if (typeof obj === "string" && parentKey && !SAFE_CONFIG_KEYS.has(parentKey)) return "****";
87
+ if (typeof obj === "number" || typeof obj === "boolean") return obj;
88
+ if (typeof obj === "string" && parentKey && SAFE_CONFIG_KEYS.has(parentKey)) return obj;
89
+ if (typeof obj === "string") return "****";
90
+ return obj;
91
+ }
92
+ /**
93
+ * Add log files from logDir to the archive, respecting MAX_LOG_BYTES cap
94
+ * and the logWindow time filter. Matches any `*.log` file in the directory,
95
+ * so the per-instance filename pattern produced by
96
+ * `buildLogFilename()` is picked up without additional configuration.
97
+ *
98
+ * Exported for reuse by the `kici-admin debug-bundle` CLI command, which
99
+ * runs outside the orchestrator process but still needs to include the
100
+ * same log files in its locally-assembled bundle.
101
+ */
102
+ async function addLogsToArchive(archive, logDir, logWindowHours) {
103
+ const cutoff = Date.now() - logWindowHours * 60 * 60 * 1e3;
104
+ const entries = fs.readdirSync(logDir).filter((f) => {
105
+ if (!f.endsWith(".log")) return false;
106
+ return fs.statSync(path.join(logDir, f)).mtimeMs >= cutoff;
107
+ });
108
+ entries.sort((a, b) => {
109
+ const aStat = fs.statSync(path.join(logDir, a));
110
+ return fs.statSync(path.join(logDir, b)).mtimeMs - aStat.mtimeMs;
111
+ });
112
+ let totalBytes = 0;
113
+ let totalLines = 0;
114
+ let errors = 0;
115
+ let warnings = 0;
116
+ for (const entry of entries) {
117
+ const filePath = path.join(logDir, entry);
118
+ const stat = fs.statSync(filePath);
119
+ if (totalBytes + stat.size > 52428800) break;
120
+ const content = fs.readFileSync(filePath, "utf-8");
121
+ archive.append(content, { name: `logs/${entry}` });
122
+ totalBytes += stat.size;
123
+ const lines = content.split("\n");
124
+ totalLines += lines.length;
125
+ for (const line of lines) {
126
+ if (/\berror\b/i.test(line)) errors++;
127
+ if (/\bwarn(ing)?\b/i.test(line)) warnings++;
128
+ }
129
+ }
130
+ const summary = {
131
+ totalLines,
132
+ errors,
133
+ warnings,
134
+ totalBytes
135
+ };
136
+ archive.append(JSON.stringify(summary, null, 2), { name: "logs/summary.json" });
137
+ }
138
+ //#endregion
139
+ export { MAX_LOG_BYTES, addLogsToArchive, redactConfig };
140
+
141
+ //# sourceMappingURL=bundle-archive.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bundle-archive.test.d.ts.map
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Channel-agnostic chunked transfer for fleet bundle ZIPs.
3
+ *
4
+ * The WS frame cap (WS_MAX_PAYLOAD_BYTES = 25 MiB) forbids shipping a whole
5
+ * bundle in one frame, so a bundle Buffer is split into ordered base64 frames
6
+ * (~85 KiB raw each, matching the webhook-relay frame size) and reassembled by
7
+ * the receiver. Used on both the orchestrator-agent and peer channels.
8
+ */
9
+ /** Raw bytes per chunk before base64 (matches webhook-relay's ~85 KiB frames). */
10
+ export declare const FLEET_CHUNK_BYTES: number;
11
+ export interface BundleChunkFrame {
12
+ seq: number;
13
+ dataB64: string;
14
+ isLast: boolean;
15
+ }
16
+ /** Split a Buffer into ordered base64 frames. An empty buffer yields one final frame. */
17
+ export declare function chunkBuffer(buf: Buffer, chunkBytes?: number): BundleChunkFrame[];
18
+ /**
19
+ * Correlation core for any "send a request, await a chunked response" channel.
20
+ *
21
+ * Key-agnostic so both the orchestrator-agent channel (keyed by requestId) and
22
+ * the peer channel (keyed by messageId) share one implementation. Pending
23
+ * requests reject on timeout, on an error frame, or on disconnect. No
24
+ * orchestrator-initiated request/response primitive existed before fleet
25
+ * collection; this is it.
26
+ */
27
+ export declare class ChunkRequestWaiter {
28
+ private pending;
29
+ /** Register a pending request `id` that rejects after `timeoutMs`. */
30
+ add(id: string, timeoutMs: number): Promise<Buffer>;
31
+ /** Accumulate a chunk; resolves the pending request on the final frame. */
32
+ onChunk(id: string, seq: number, dataB64: string, isLast: boolean): void;
33
+ /** Reject the pending request `id` with `message`. */
34
+ onError(id: string, message: string): void;
35
+ /** Reject every pending request — used when the underlying connection drops. */
36
+ rejectAll(reason: string): void;
37
+ }
38
+ /** Reassembles ordered frames into a Buffer. Throws on gaps/reordering. */
39
+ export declare class BundleChunkAssembler {
40
+ private parts;
41
+ private next;
42
+ private done;
43
+ /** Returns the assembled Buffer on the final frame, otherwise undefined. */
44
+ accept(seq: number, dataB64: string, isLast: boolean): Buffer | undefined;
45
+ }
46
+ //# sourceMappingURL=bundle-chunks.d.ts.map
@@ -0,0 +1,111 @@
1
+ import "../chunk-BTugEXQM.js";
2
+ //#region src/diagnostics/bundle-chunks.ts
3
+ /**
4
+ * Channel-agnostic chunked transfer for fleet bundle ZIPs.
5
+ *
6
+ * The WS frame cap (WS_MAX_PAYLOAD_BYTES = 25 MiB) forbids shipping a whole
7
+ * bundle in one frame, so a bundle Buffer is split into ordered base64 frames
8
+ * (~85 KiB raw each, matching the webhook-relay frame size) and reassembled by
9
+ * the receiver. Used on both the orchestrator-agent and peer channels.
10
+ */
11
+ /** Raw bytes per chunk before base64 (matches webhook-relay's ~85 KiB frames). */
12
+ const FLEET_CHUNK_BYTES = 85 * 1024;
13
+ /** Split a Buffer into ordered base64 frames. An empty buffer yields one final frame. */
14
+ function chunkBuffer(buf, chunkBytes = FLEET_CHUNK_BYTES) {
15
+ const frames = [];
16
+ if (buf.length === 0) return [{
17
+ seq: 0,
18
+ dataB64: "",
19
+ isLast: true
20
+ }];
21
+ for (let offset = 0, seq = 0; offset < buf.length; offset += chunkBytes, seq++) {
22
+ const slice = buf.subarray(offset, Math.min(offset + chunkBytes, buf.length));
23
+ frames.push({
24
+ seq,
25
+ dataB64: slice.toString("base64"),
26
+ isLast: offset + chunkBytes >= buf.length
27
+ });
28
+ }
29
+ return frames;
30
+ }
31
+ /**
32
+ * Correlation core for any "send a request, await a chunked response" channel.
33
+ *
34
+ * Key-agnostic so both the orchestrator-agent channel (keyed by requestId) and
35
+ * the peer channel (keyed by messageId) share one implementation. Pending
36
+ * requests reject on timeout, on an error frame, or on disconnect. No
37
+ * orchestrator-initiated request/response primitive existed before fleet
38
+ * collection; this is it.
39
+ */
40
+ var ChunkRequestWaiter = class {
41
+ pending = /* @__PURE__ */ new Map();
42
+ /** Register a pending request `id` that rejects after `timeoutMs`. */
43
+ add(id, timeoutMs) {
44
+ return new Promise((resolve, reject) => {
45
+ const timer = setTimeout(() => {
46
+ this.pending.delete(id);
47
+ reject(/* @__PURE__ */ new Error(`chunk request ${id} timed out after ${timeoutMs}ms`));
48
+ }, timeoutMs);
49
+ this.pending.set(id, {
50
+ asm: new BundleChunkAssembler(),
51
+ resolve,
52
+ reject,
53
+ timer
54
+ });
55
+ });
56
+ }
57
+ /** Accumulate a chunk; resolves the pending request on the final frame. */
58
+ onChunk(id, seq, dataB64, isLast) {
59
+ const p = this.pending.get(id);
60
+ if (!p) return;
61
+ try {
62
+ const done = p.asm.accept(seq, dataB64, isLast);
63
+ if (done) {
64
+ clearTimeout(p.timer);
65
+ this.pending.delete(id);
66
+ p.resolve(done);
67
+ }
68
+ } catch (err) {
69
+ clearTimeout(p.timer);
70
+ this.pending.delete(id);
71
+ p.reject(err instanceof Error ? err : new Error(String(err)));
72
+ }
73
+ }
74
+ /** Reject the pending request `id` with `message`. */
75
+ onError(id, message) {
76
+ const p = this.pending.get(id);
77
+ if (!p) return;
78
+ clearTimeout(p.timer);
79
+ this.pending.delete(id);
80
+ p.reject(new Error(message));
81
+ }
82
+ /** Reject every pending request — used when the underlying connection drops. */
83
+ rejectAll(reason) {
84
+ for (const [, p] of this.pending) {
85
+ clearTimeout(p.timer);
86
+ p.reject(new Error(reason));
87
+ }
88
+ this.pending.clear();
89
+ }
90
+ };
91
+ /** Reassembles ordered frames into a Buffer. Throws on gaps/reordering. */
92
+ var BundleChunkAssembler = class {
93
+ parts = [];
94
+ next = 0;
95
+ done = false;
96
+ /** Returns the assembled Buffer on the final frame, otherwise undefined. */
97
+ accept(seq, dataB64, isLast) {
98
+ if (this.done) throw new Error("bundle chunk received after final frame");
99
+ if (seq !== this.next) throw new Error(`out-of-order bundle chunk: expected ${this.next}, got ${seq}`);
100
+ this.next++;
101
+ this.parts.push(Buffer.from(dataB64, "base64"));
102
+ if (isLast) {
103
+ this.done = true;
104
+ return Buffer.concat(this.parts);
105
+ }
106
+ }
107
+ };
108
+ //#endregion
109
+ export { BundleChunkAssembler, ChunkRequestWaiter, FLEET_CHUNK_BYTES, chunkBuffer };
110
+
111
+ //# sourceMappingURL=bundle-chunks.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=bundle-chunks.test.d.ts.map
@@ -39,7 +39,8 @@
39
39
  * - `KICI_*` — every project-internal env var.
40
40
  * - OS basics — NODE_ENV, HOME, PATH, TZ, LANG, TMPDIR,
41
41
  * USER, USERNAME, SHELL, COMSPEC, PWD, OLDPWD,
42
- * HOSTNAME.
42
+ * HOSTNAME, PROCESSOR_ARCHITECTURE (Windows arch
43
+ * hint the agent reads to pick the mise zip).
43
44
  * - Terminal / display — COLUMNS, LINES, TERM, COLORTERM, DISPLAY,
44
45
  * WAYLAND_DISPLAY, LOCALAPPDATA.
45
46
  * - XDG basedir spec — XDG_*.
@@ -48,6 +49,9 @@
48
49
  * GITHUB_PATH, GITHUB_STEP_SUMMARY, GITLAB_CI.
49
50
  * - Cloud / SDK names — AWS_*, REDIS_*, OTEL_*, STRIPE_*, DOCKER_*,
50
51
  * CONTAINER_HOST.
52
+ * - git tooling — GIT_* (git's own env-var family, e.g.
53
+ * GIT_CONFIG_GLOBAL / GIT_SSH_COMMAND, that KiCI
54
+ * sets to drive cloned / overlay workspaces).
51
55
  * - Postgres libpq — PGHOST, PGPORT, PGUSER, PGPASSWORD,
52
56
  * PGDATABASE, PGSERVICEFILE, PGSSLMODE.
53
57
  * - Forgejo dev server — FORGEJO_URL, FORGEJO_CONTAINER (read by the
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  //#region src/env/allowlist.ts
3
3
  /**
4
4
  * Source of truth for the env-var allowlist.
@@ -41,7 +41,8 @@ import "../chunk-gOLHoazu.js";
41
41
  * - `KICI_*` — every project-internal env var.
42
42
  * - OS basics — NODE_ENV, HOME, PATH, TZ, LANG, TMPDIR,
43
43
  * USER, USERNAME, SHELL, COMSPEC, PWD, OLDPWD,
44
- * HOSTNAME.
44
+ * HOSTNAME, PROCESSOR_ARCHITECTURE (Windows arch
45
+ * hint the agent reads to pick the mise zip).
45
46
  * - Terminal / display — COLUMNS, LINES, TERM, COLORTERM, DISPLAY,
46
47
  * WAYLAND_DISPLAY, LOCALAPPDATA.
47
48
  * - XDG basedir spec — XDG_*.
@@ -50,6 +51,9 @@ import "../chunk-gOLHoazu.js";
50
51
  * GITHUB_PATH, GITHUB_STEP_SUMMARY, GITLAB_CI.
51
52
  * - Cloud / SDK names — AWS_*, REDIS_*, OTEL_*, STRIPE_*, DOCKER_*,
52
53
  * CONTAINER_HOST.
54
+ * - git tooling — GIT_* (git's own env-var family, e.g.
55
+ * GIT_CONFIG_GLOBAL / GIT_SSH_COMMAND, that KiCI
56
+ * sets to drive cloned / overlay workspaces).
53
57
  * - Postgres libpq — PGHOST, PGPORT, PGUSER, PGPASSWORD,
54
58
  * PGDATABASE, PGSERVICEFILE, PGSSLMODE.
55
59
  * - Forgejo dev server — FORGEJO_URL, FORGEJO_CONTAINER (read by the
@@ -70,7 +74,7 @@ import "../chunk-gOLHoazu.js";
70
74
  * the dev proxy), HEADED (Playwright convention
71
75
  * for `--headed` runs).
72
76
  */
73
- const OS_SDK_ALLOWLIST_REGEX = /^(KICI_.*|NODE_ENV|HOME|PATH|TZ|LANG|TMPDIR|USER|USERNAME|SHELL|COMSPEC|PWD|OLDPWD|HOSTNAME|COLUMNS|LINES|TERM|COLORTERM|DISPLAY|WAYLAND_DISPLAY|LOCALAPPDATA|XDG_CACHE_HOME|XDG_CONFIG_HOME|XDG_DATA_HOME|XDG_RUNTIME_DIR|XDG_STATE_HOME|INIT_CWD|npm_.*|SSH_.*|CI|GITHUB_ACTIONS|GITHUB_ENV|GITHUB_OUTPUT|GITHUB_PATH|GITHUB_STEP_SUMMARY|GITLAB_CI|AWS_.*|REDIS_.*|OTEL_.*|STRIPE_.*|DOCKER_.*|CONTAINER_HOST|container|PGHOST|PGPORT|PGUSER|PGPASSWORD|PGDATABASE|PGSERVICEFILE|PGSSLMODE|FORGEJO_URL|FORGEJO_CONTAINER|KEYCLOAK_.*|VITE_.*|PLAYWRIGHT|HEADED)$/;
77
+ const OS_SDK_ALLOWLIST_REGEX = /^(KICI_.*|NODE_ENV|HOME|PATH|TZ|LANG|TMPDIR|USER|USERNAME|SHELL|COMSPEC|PWD|OLDPWD|HOSTNAME|PROCESSOR_ARCHITECTURE|COLUMNS|LINES|TERM|COLORTERM|DISPLAY|WAYLAND_DISPLAY|LOCALAPPDATA|XDG_CACHE_HOME|XDG_CONFIG_HOME|XDG_DATA_HOME|XDG_RUNTIME_DIR|XDG_STATE_HOME|INIT_CWD|npm_.*|SSH_.*|CI|GITHUB_ACTIONS|GITHUB_ENV|GITHUB_OUTPUT|GITHUB_PATH|GITHUB_STEP_SUMMARY|GITLAB_CI|AWS_.*|REDIS_.*|OTEL_.*|STRIPE_.*|DOCKER_.*|GIT_.*|CONTAINER_HOST|container|PGHOST|PGPORT|PGUSER|PGPASSWORD|PGDATABASE|PGSERVICEFILE|PGSSLMODE|FORGEJO_URL|FORGEJO_CONTAINER|KEYCLOAK_.*|VITE_.*|PLAYWRIGHT|HEADED)$/;
74
78
  /**
75
79
  * Returns true when `name` is allowed under the KiCI env-var convention:
76
80
  * it matches the OS/SDK allowlist regex (which includes the `KICI_*`
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  //#region src/env/define-env.ts
3
3
  /** Read an env value following the alias precedence (first non-undefined wins). */
4
4
  function readEnv(envMap, env) {
package/dist/env/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { RESERVED_NON_SCHEMA_KICI_PREFIXES, RESERVED_NON_SCHEMA_KICI_VARS, defineEnv, validateUnknownKiciVars } from "./define-env.js";
3
3
  import { LOGGER_ENV_FIELD_SPECS, LOGGER_ENV_VARS, LoggerEnvSchema } from "./logger-env.js";
4
4
  export { LOGGER_ENV_FIELD_SPECS, LOGGER_ENV_VARS, LoggerEnvSchema, RESERVED_NON_SCHEMA_KICI_PREFIXES, RESERVED_NON_SCHEMA_KICI_VARS, defineEnv, validateUnknownKiciVars };
@@ -1,4 +1,4 @@
1
- import "../chunk-gOLHoazu.js";
1
+ import "../chunk-BTugEXQM.js";
2
2
  import { z } from "zod";
3
3
  //#region src/env/logger-env.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import "./chunk-gOLHoazu.js";
1
+ import "./chunk-BTugEXQM.js";
2
2
  import { toErrorMessage } from "@kici-dev/core";
3
3
  //#region src/graceful-shutdown.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import "./chunk-gOLHoazu.js";
1
+ import "./chunk-BTugEXQM.js";
2
2
  //#region src/idempotency-env-diff.ts
3
3
  /**
4
4
  * Env-file semantic diff for the idempotent-step preview path.
@@ -1,4 +1,4 @@
1
- import "./chunk-gOLHoazu.js";
1
+ import "./chunk-BTugEXQM.js";
2
2
  import { diffEnvFiles, renderEnvDiff } from "./idempotency-env-diff.js";
3
3
  import { createTwoFilesPatch } from "diff";
4
4
  //#region src/idempotency-files.ts
@@ -1,4 +1,4 @@
1
- import "./chunk-gOLHoazu.js";
1
+ import "./chunk-BTugEXQM.js";
2
2
  import { setYamlDiffRenderer } from "./idempotency-files.js";
3
3
  import { parse } from "yaml";
4
4
  //#region src/idempotency-yaml-diff.ts
@@ -1,3 +1,3 @@
1
- import "./chunk-gOLHoazu.js";
1
+ import "./chunk-BTugEXQM.js";
2
2
  export * from "@kici-dev/core/idempotency";
3
3
  export {};