@kitsy/cnos 1.6.1 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/build/index.cjs +1332 -156
  2. package/dist/build/index.d.cts +1 -1
  3. package/dist/build/index.d.ts +1 -1
  4. package/dist/build/index.js +36 -14
  5. package/dist/{chunk-JYWQFMW5.js → chunk-2DGT7N7E.js} +1 -1
  6. package/dist/{chunk-S7H2UULC.js → chunk-2TL42I6M.js} +1323 -139
  7. package/dist/{chunk-MW4OVAT3.js → chunk-5KIQCYFH.js} +1 -1
  8. package/dist/{chunk-N32UN66E.js → chunk-CV3SLBYZ.js} +8 -8
  9. package/dist/{chunk-XSUP7JKH.js → chunk-GHGJFRDL.js} +6 -2
  10. package/dist/{chunk-BMAD24KC.js → chunk-OA7FQGAG.js} +1 -1
  11. package/dist/{chunk-6FAX2VKQ.js → chunk-PFT56ID2.js} +195 -28
  12. package/dist/{chunk-VGZREX5D.js → chunk-RYIARE4M.js} +1 -1
  13. package/dist/{chunk-UR7CHHNN.js → chunk-TT4NV56Z.js} +3 -2
  14. package/dist/{chunk-UJBQS7CJ.js → chunk-UL63DFLS.js} +1 -1
  15. package/dist/configure/index.cjs +1309 -155
  16. package/dist/configure/index.d.cts +3 -3
  17. package/dist/configure/index.d.ts +3 -3
  18. package/dist/configure/index.js +8 -8
  19. package/dist/{plugin-CKrBlWGI.d.cts → core-BJ8xewez.d.cts} +142 -60
  20. package/dist/{plugin-CKrBlWGI.d.ts → core-BJ8xewez.d.ts} +142 -60
  21. package/dist/{envNaming-B7Mztkcf.d.ts → envNaming-BRyiuPoI.d.ts} +1 -1
  22. package/dist/{envNaming-gMVnPOfe.d.cts → envNaming-rx71gpi0.d.cts} +1 -1
  23. package/dist/index.cjs +1548 -227
  24. package/dist/index.d.cts +1 -1
  25. package/dist/index.d.ts +1 -1
  26. package/dist/index.js +10 -10
  27. package/dist/internal.cjs +831 -122
  28. package/dist/internal.d.cts +56 -3
  29. package/dist/internal.d.ts +56 -3
  30. package/dist/internal.js +30 -3
  31. package/dist/plugin/basic-schema.cjs +49 -23
  32. package/dist/plugin/basic-schema.d.cts +1 -1
  33. package/dist/plugin/basic-schema.d.ts +1 -1
  34. package/dist/plugin/basic-schema.js +2 -2
  35. package/dist/plugin/cli-args.cjs +38 -23
  36. package/dist/plugin/cli-args.d.cts +1 -1
  37. package/dist/plugin/cli-args.d.ts +1 -1
  38. package/dist/plugin/cli-args.js +2 -2
  39. package/dist/plugin/dotenv.cjs +46 -31
  40. package/dist/plugin/dotenv.d.cts +2 -2
  41. package/dist/plugin/dotenv.d.ts +2 -2
  42. package/dist/plugin/dotenv.js +2 -2
  43. package/dist/plugin/env-export.cjs +56 -27
  44. package/dist/plugin/env-export.d.cts +2 -2
  45. package/dist/plugin/env-export.d.ts +2 -2
  46. package/dist/plugin/env-export.js +2 -2
  47. package/dist/plugin/filesystem.cjs +61 -39
  48. package/dist/plugin/filesystem.d.cts +1 -1
  49. package/dist/plugin/filesystem.d.ts +1 -1
  50. package/dist/plugin/filesystem.js +2 -2
  51. package/dist/plugin/process-env.cjs +40 -25
  52. package/dist/plugin/process-env.d.cts +2 -2
  53. package/dist/plugin/process-env.d.ts +2 -2
  54. package/dist/plugin/process-env.js +2 -2
  55. package/dist/runtime/index.cjs +1548 -227
  56. package/dist/runtime/index.d.cts +3 -1
  57. package/dist/runtime/index.d.ts +3 -1
  58. package/dist/runtime/index.js +10 -10
  59. package/dist/toPublicEnv-CCSgdvI9.d.ts +13 -0
  60. package/dist/toPublicEnv-ivRtLjcw.d.cts +13 -0
  61. package/package.json +1 -1
  62. package/dist/toPublicEnv-CmBsy53P.d.cts +0 -7
  63. package/dist/toPublicEnv-q6VwWxXZ.d.ts +0 -7
@@ -34,16 +34,682 @@ var CnosKeyNotFoundError = class extends CnosError {
34
34
  }
35
35
  key;
36
36
  };
37
+ var CnosDerivedExpressionError = class extends CnosError {
38
+ constructor(message, expression) {
39
+ super(expression ? `${message} (${expression})` : message);
40
+ this.expression = expression;
41
+ }
42
+ expression;
43
+ };
44
+ var CnosDerivedCycleError = class extends CnosError {
45
+ constructor(message) {
46
+ super(message);
47
+ }
48
+ };
49
+ var CnosDerivedResolutionError = class extends CnosError {
50
+ constructor(key, message) {
51
+ super(message);
52
+ this.key = key;
53
+ }
54
+ key;
55
+ };
56
+ var CnosRuntimeProviderError = class extends CnosError {
57
+ constructor(message) {
58
+ super(message);
59
+ }
60
+ };
61
+
62
+ // ../core/src/derive/builtins.ts
63
+ function stringify(value) {
64
+ if (value === void 0 || value === null) {
65
+ return "";
66
+ }
67
+ if (typeof value === "string") {
68
+ return value;
69
+ }
70
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
71
+ return String(value);
72
+ }
73
+ return JSON.stringify(value);
74
+ }
75
+ var DERIVE_BUILTINS = {
76
+ concat: (...args) => args.map((value) => stringify(value)).join(""),
77
+ coalesce: (...args) => args.find((value) => value !== void 0 && value !== null),
78
+ when: (condition, whenTrue, whenFalse) => condition ? whenTrue : whenFalse,
79
+ exists: (value) => value !== void 0 && value !== null,
80
+ eq: (left, right) => left === right,
81
+ ne: (left, right) => left !== right
82
+ };
83
+
84
+ // ../core/src/derive/parser.ts
85
+ function isWhitespace(value) {
86
+ return value === " " || value === "\n" || value === "\r" || value === " ";
87
+ }
88
+ function skipWhitespace(state) {
89
+ while (isWhitespace(state.source[state.index])) {
90
+ state.index += 1;
91
+ }
92
+ }
93
+ function isIdentifierStart(value) {
94
+ return typeof value === "string" && /[A-Za-z_]/.test(value);
95
+ }
96
+ function isIdentifierPart(value) {
97
+ return typeof value === "string" && /[A-Za-z0-9_.-]/.test(value);
98
+ }
99
+ function errorAt(state, message) {
100
+ throw new CnosDerivedExpressionError(`${message} at position ${state.index + 1}`, state.source);
101
+ }
102
+ function parseStringLiteral(state) {
103
+ const quote = state.source[state.index];
104
+ if (quote !== "'") {
105
+ errorAt(state, "Expected string literal");
106
+ }
107
+ state.index += 1;
108
+ let value = "";
109
+ while (state.index < state.source.length) {
110
+ const current = state.source[state.index];
111
+ if (current === "\\") {
112
+ const next = state.source[state.index + 1];
113
+ if (next === void 0) {
114
+ errorAt(state, "Unterminated escape sequence");
115
+ }
116
+ value += next;
117
+ state.index += 2;
118
+ continue;
119
+ }
120
+ if (current === "'") {
121
+ state.index += 1;
122
+ return {
123
+ type: "literal",
124
+ value
125
+ };
126
+ }
127
+ value += current;
128
+ state.index += 1;
129
+ }
130
+ errorAt(state, "Unterminated string literal");
131
+ }
132
+ function parseNumberLiteral(state) {
133
+ const start = state.index;
134
+ while (/[0-9]/.test(state.source[state.index] ?? "")) {
135
+ state.index += 1;
136
+ }
137
+ if (state.source[state.index] === ".") {
138
+ state.index += 1;
139
+ while (/[0-9]/.test(state.source[state.index] ?? "")) {
140
+ state.index += 1;
141
+ }
142
+ }
143
+ return {
144
+ type: "literal",
145
+ value: Number(state.source.slice(start, state.index))
146
+ };
147
+ }
148
+ function parseIdentifier(state) {
149
+ if (!isIdentifierStart(state.source[state.index])) {
150
+ errorAt(state, "Expected identifier");
151
+ }
152
+ const start = state.index;
153
+ state.index += 1;
154
+ while (isIdentifierPart(state.source[state.index])) {
155
+ state.index += 1;
156
+ }
157
+ return state.source.slice(start, state.index);
158
+ }
159
+ function parseArguments(state) {
160
+ const args = [];
161
+ skipWhitespace(state);
162
+ if (state.source[state.index] === ")") {
163
+ state.index += 1;
164
+ return args;
165
+ }
166
+ while (state.index < state.source.length) {
167
+ args.push(parseExpressionNode(state));
168
+ skipWhitespace(state);
169
+ const current = state.source[state.index];
170
+ if (current === ",") {
171
+ state.index += 1;
172
+ skipWhitespace(state);
173
+ continue;
174
+ }
175
+ if (current === ")") {
176
+ state.index += 1;
177
+ return args;
178
+ }
179
+ errorAt(state, 'Expected "," or ")"');
180
+ }
181
+ errorAt(state, "Unterminated function call");
182
+ }
183
+ function parseIdentifierOrCall(state) {
184
+ const identifier = parseIdentifier(state);
185
+ skipWhitespace(state);
186
+ if (state.source[state.index] === "(") {
187
+ if (!(identifier in DERIVE_BUILTINS)) {
188
+ throw new CnosDerivedExpressionError(`Unknown derive function: ${identifier}`, state.source);
189
+ }
190
+ state.index += 1;
191
+ return {
192
+ type: "call",
193
+ name: identifier,
194
+ args: parseArguments(state)
195
+ };
196
+ }
197
+ if (identifier === "true" || identifier === "false") {
198
+ return {
199
+ type: "literal",
200
+ value: identifier === "true"
201
+ };
202
+ }
203
+ if (identifier === "null") {
204
+ return {
205
+ type: "literal",
206
+ value: null
207
+ };
208
+ }
209
+ return {
210
+ type: "ref",
211
+ path: identifier
212
+ };
213
+ }
214
+ function parseExpressionNode(state) {
215
+ skipWhitespace(state);
216
+ const current = state.source[state.index];
217
+ if (current === "'") {
218
+ return parseStringLiteral(state);
219
+ }
220
+ if (/[0-9]/.test(current ?? "")) {
221
+ return parseNumberLiteral(state);
222
+ }
223
+ if (isIdentifierStart(current)) {
224
+ return parseIdentifierOrCall(state);
225
+ }
226
+ errorAt(state, "Unexpected token");
227
+ }
228
+ function parseExpression(source) {
229
+ const state = {
230
+ source,
231
+ index: 0
232
+ };
233
+ const ast = parseExpressionNode(state);
234
+ skipWhitespace(state);
235
+ if (state.index !== source.length) {
236
+ errorAt(state, "Unexpected trailing input");
237
+ }
238
+ return ast;
239
+ }
240
+
241
+ // ../core/src/derive/templateParser.ts
242
+ function toLiteral(value) {
243
+ return {
244
+ type: "literal",
245
+ value
246
+ };
247
+ }
248
+ function toRef(path14) {
249
+ return {
250
+ type: "ref",
251
+ path: path14
252
+ };
253
+ }
254
+ function parseTemplate(source) {
255
+ const parts = [];
256
+ let cursor = 0;
257
+ while (cursor < source.length) {
258
+ const start = source.indexOf("${", cursor);
259
+ if (start < 0) {
260
+ if (cursor < source.length) {
261
+ parts.push(toLiteral(source.slice(cursor)));
262
+ }
263
+ break;
264
+ }
265
+ if (start > cursor) {
266
+ parts.push(toLiteral(source.slice(cursor, start)));
267
+ }
268
+ const end = source.indexOf("}", start + 2);
269
+ if (end < 0) {
270
+ throw new CnosDerivedExpressionError(`Invalid derivation template: unclosed \${...} at position ${start + 1}`, source);
271
+ }
272
+ const ref = source.slice(start + 2, end).trim();
273
+ if (!ref) {
274
+ throw new CnosDerivedExpressionError(`Invalid derivation template: empty reference at position ${start + 1}`, source);
275
+ }
276
+ if (!/^[A-Za-z_][A-Za-z0-9_.-]*$/.test(ref)) {
277
+ throw new CnosDerivedExpressionError(`Invalid derivation template reference "${ref}"`, source);
278
+ }
279
+ parts.push(toRef(ref));
280
+ cursor = end + 1;
281
+ }
282
+ if (parts.length === 0) {
283
+ return toLiteral("");
284
+ }
285
+ if (parts.length === 1) {
286
+ return parts[0];
287
+ }
288
+ return {
289
+ type: "call",
290
+ name: "concat",
291
+ args: parts
292
+ };
293
+ }
294
+
295
+ // ../core/src/derive/evaluator.ts
296
+ function isDerivedValue(value) {
297
+ return Boolean(
298
+ value && typeof value === "object" && !Array.isArray(value) && "$derive" in value
299
+ );
300
+ }
301
+ function extractRefs(node, refs = /* @__PURE__ */ new Set()) {
302
+ if (node.type === "ref") {
303
+ refs.add(node.path);
304
+ return refs;
305
+ }
306
+ if (node.type === "call") {
307
+ for (const arg of node.args) {
308
+ extractRefs(arg, refs);
309
+ }
310
+ }
311
+ return refs;
312
+ }
313
+ function parseDerivation(value) {
314
+ const source = typeof value.$derive === "string" ? value.$derive : value.$derive?.expr;
315
+ if (typeof source !== "string") {
316
+ throw new CnosDerivedExpressionError("Derived value requires either a template string or { expr } object");
317
+ }
318
+ const type = typeof value.$derive === "string" ? "template" : "expression";
319
+ const ast = type === "template" ? parseTemplate(source) : parseExpression(source);
320
+ const refs = Array.from(extractRefs(ast)).sort((left, right) => left.localeCompare(right));
321
+ return {
322
+ type,
323
+ raw: source,
324
+ ast,
325
+ refs,
326
+ runtimeRefs: [],
327
+ isRuntimeDependent: false
328
+ };
329
+ }
330
+ function normalizeConcatValue(value) {
331
+ if (value === void 0 || value === null) {
332
+ return "";
333
+ }
334
+ if (typeof value === "string") {
335
+ return value;
336
+ }
337
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
338
+ return String(value);
339
+ }
340
+ return JSON.stringify(value);
341
+ }
342
+ function evaluateNode(node, resolveRef) {
343
+ switch (node.type) {
344
+ case "literal":
345
+ return node.value;
346
+ case "ref":
347
+ return resolveRef(node.path);
348
+ case "call": {
349
+ const args = node.args.map((arg) => evaluateNode(arg, resolveRef));
350
+ switch (node.name) {
351
+ case "concat":
352
+ return args.map((value) => normalizeConcatValue(value)).join("");
353
+ case "coalesce":
354
+ return DERIVE_BUILTINS.coalesce(...args);
355
+ case "when":
356
+ return DERIVE_BUILTINS.when(args[0], args[1], args[2]);
357
+ case "exists":
358
+ return DERIVE_BUILTINS.exists(args[0]);
359
+ case "eq":
360
+ return DERIVE_BUILTINS.eq(args[0], args[1]);
361
+ case "ne":
362
+ return DERIVE_BUILTINS.ne(args[0], args[1]);
363
+ default:
364
+ throw new CnosDerivedExpressionError(`Unknown derive function: ${String(node.name)}`);
365
+ }
366
+ }
367
+ default:
368
+ throw new CnosDerivedExpressionError(`Unsupported derive AST node ${node.type ?? "unknown"}`);
369
+ }
370
+ }
371
+ function evaluateDerivation(options) {
372
+ const missingRefs = /* @__PURE__ */ new Set();
373
+ const value = evaluateNode(options.parsed.ast, (ref) => {
374
+ const resolved = options.resolveRef(ref);
375
+ if (resolved === void 0) {
376
+ missingRefs.add(ref);
377
+ options.onMissing?.(ref);
378
+ }
379
+ return resolved;
380
+ });
381
+ if (missingRefs.size > 0 && options.parsed.ast.type === "ref") {
382
+ throw new CnosDerivedResolutionError(
383
+ options.key,
384
+ `Unable to resolve derived config key ${options.key} because ${Array.from(missingRefs).join(", ")} is missing.`
385
+ );
386
+ }
387
+ return value;
388
+ }
389
+
390
+ // ../core/src/derive/validate.ts
391
+ var FORBIDDEN_TARGET_NAMESPACES = /* @__PURE__ */ new Set(["public", "meta", "secret"]);
392
+ var FORBIDDEN_REF_NAMESPACES = /* @__PURE__ */ new Set(["public", "secret"]);
393
+ function validateDerivedTargetNamespace(manifest, namespace) {
394
+ if (FORBIDDEN_TARGET_NAMESPACES.has(namespace)) {
395
+ throw new CnosManifestError(`Cannot define derived values under namespace "${namespace}".`);
396
+ }
397
+ if (manifest.runtimeNamespaces[namespace]) {
398
+ throw new CnosManifestError(`Cannot define derived values under runtime namespace "${namespace}".`);
399
+ }
400
+ }
401
+ function validateParsedDerivation(manifest, parsed) {
402
+ for (const ref of parsed.refs) {
403
+ const namespace = ref.split(".")[0] ?? "";
404
+ if (FORBIDDEN_REF_NAMESPACES.has(namespace)) {
405
+ throw new CnosDerivedExpressionError(`Derived expressions cannot reference ${namespace}.* keys.`, parsed.raw);
406
+ }
407
+ if (manifest.runtimeNamespaces[namespace]) {
408
+ continue;
409
+ }
410
+ if (!manifest.namespaces[namespace] && namespace !== "value" && namespace !== "meta") {
411
+ throw new CnosDerivedExpressionError(`Unknown derive reference namespace: ${namespace}`, parsed.raw);
412
+ }
413
+ }
414
+ }
415
+ function normalizeDerivedValue(templateOrExpr, expr = false) {
416
+ return expr ? {
417
+ $derive: {
418
+ expr: templateOrExpr
419
+ }
420
+ } : {
421
+ $derive: templateOrExpr
422
+ };
423
+ }
424
+
425
+ // ../core/src/derive/depGraph.ts
426
+ function detectDerivationCycles(dependencyMap) {
427
+ const visiting = /* @__PURE__ */ new Set();
428
+ const visited = /* @__PURE__ */ new Set();
429
+ const stack = [];
430
+ const visit = (key) => {
431
+ if (visited.has(key)) {
432
+ return;
433
+ }
434
+ if (visiting.has(key)) {
435
+ const start = stack.indexOf(key);
436
+ const cycle = [...stack.slice(start), key].join(" -> ");
437
+ throw new CnosDerivedCycleError(`Derivation cycle detected: ${cycle}`);
438
+ }
439
+ visiting.add(key);
440
+ stack.push(key);
441
+ for (const dependency of dependencyMap.get(key) ?? []) {
442
+ visit(dependency);
443
+ }
444
+ stack.pop();
445
+ visiting.delete(key);
446
+ visited.add(key);
447
+ };
448
+ for (const key of dependencyMap.keys()) {
449
+ visit(key);
450
+ }
451
+ }
452
+
453
+ // ../core/src/derive/runtime.ts
454
+ function namespaceForKey(key) {
455
+ return key.split(".")[0] ?? "";
456
+ }
457
+ function dependencyNamespaces(key, entries, memo) {
458
+ if (memo.has(key)) {
459
+ return memo.get(key);
460
+ }
461
+ const entry = entries.get(key);
462
+ if (!entry) {
463
+ memo.set(key, []);
464
+ return [];
465
+ }
466
+ const namespaces = /* @__PURE__ */ new Set();
467
+ for (const ref of entry.parsed.refs) {
468
+ const namespace = namespaceForKey(ref);
469
+ if (!entries.has(ref)) {
470
+ namespaces.add(namespace);
471
+ continue;
472
+ }
473
+ for (const dependencyNamespace of dependencyNamespaces(ref, entries, memo)) {
474
+ namespaces.add(dependencyNamespace);
475
+ }
476
+ }
477
+ const result = Array.from(namespaces).sort((left, right) => left.localeCompare(right));
478
+ memo.set(key, result);
479
+ return result;
480
+ }
481
+ function isRuntimeDependentKey(key, entries, manifest, memo) {
482
+ if (memo.has(key)) {
483
+ return memo.get(key);
484
+ }
485
+ const entry = entries.get(key);
486
+ if (!entry) {
487
+ memo.set(key, false);
488
+ return false;
489
+ }
490
+ for (const ref of entry.parsed.refs) {
491
+ const namespace = namespaceForKey(ref);
492
+ if (manifest.runtimeNamespaces[namespace]) {
493
+ memo.set(key, true);
494
+ return true;
495
+ }
496
+ if (entries.has(ref) && isRuntimeDependentKey(ref, entries, manifest, memo)) {
497
+ memo.set(key, true);
498
+ return true;
499
+ }
500
+ }
501
+ memo.set(key, false);
502
+ return false;
503
+ }
504
+ function prepareEntries(graph, manifest) {
505
+ const entries = /* @__PURE__ */ new Map();
506
+ for (const [key, entry] of graph.entries) {
507
+ if (!isDerivedValue(entry.value)) {
508
+ continue;
509
+ }
510
+ const namespaceDefinition = manifest.namespaces[entry.namespace];
511
+ if (!namespaceDefinition || namespaceDefinition.kind === "data") {
512
+ validateDerivedTargetNamespace(manifest, entry.namespace);
513
+ }
514
+ const parsed = parseDerivation(entry.value);
515
+ validateParsedDerivation(manifest, parsed);
516
+ entries.set(key, {
517
+ key,
518
+ namespace: entry.namespace,
519
+ value: entry.value,
520
+ parsed
521
+ });
522
+ }
523
+ detectDerivationCycles(
524
+ new Map(
525
+ Array.from(entries.values()).map((entry) => [
526
+ entry.key,
527
+ entry.parsed.refs.filter((ref) => entries.has(ref))
528
+ ])
529
+ )
530
+ );
531
+ const runtimeMemo = /* @__PURE__ */ new Map();
532
+ const namespaceMemo = /* @__PURE__ */ new Map();
533
+ for (const entry of entries.values()) {
534
+ entry.parsed.isRuntimeDependent = isRuntimeDependentKey(entry.key, entries, manifest, runtimeMemo);
535
+ entry.parsed.runtimeRefs = entry.parsed.refs.filter((ref) => manifest.runtimeNamespaces[namespaceForKey(ref)]);
536
+ if (entry.parsed.runtimeRefs.length === 0 && entry.parsed.isRuntimeDependent) {
537
+ entry.parsed.runtimeRefs = dependencyNamespaces(entry.key, entries, namespaceMemo).filter((namespace) => manifest.runtimeNamespaces[namespace]).map((namespace) => `${namespace}.*`);
538
+ }
539
+ }
540
+ return entries;
541
+ }
542
+ function createDerivedRuntimeSupport(graph, manifest, runtimeProviders) {
543
+ const entries = prepareEntries(graph, manifest);
544
+ const configCache = /* @__PURE__ */ new Map();
545
+ const runtimeDependencyMemo = /* @__PURE__ */ new Map();
546
+ const support = {};
547
+ Object.assign(support, {
548
+ runtimeProviders,
549
+ read(key, readBase) {
550
+ const namespace = namespaceForKey(key);
551
+ if (runtimeProviders.has(namespace)) {
552
+ const provider = runtimeProviders.get(namespace);
553
+ return provider(key.slice(namespace.length + 1));
554
+ }
555
+ if (entries.has(key)) {
556
+ return readDerived(key, readBase);
557
+ }
558
+ return readBase(key);
559
+ },
560
+ describe(key, readBase) {
561
+ const entry = entries.get(key);
562
+ if (!entry) {
563
+ return void 0;
564
+ }
565
+ const runtimeNamespaces = Array.from(
566
+ new Set(
567
+ entry.parsed.refs.map((ref) => namespaceForKey(ref)).filter((namespace) => manifest.runtimeNamespaces[namespace])
568
+ )
569
+ ).sort((left, right) => left.localeCompare(right));
570
+ return {
571
+ key,
572
+ type: entry.parsed.type,
573
+ expression: entry.parsed.raw,
574
+ dependencies: entry.parsed.refs.map((ref) => {
575
+ const namespace = namespaceForKey(ref);
576
+ return {
577
+ key: ref,
578
+ value: support.read(ref, readBase),
579
+ ...manifest.runtimeNamespaces[namespace] ? {
580
+ runtimeNamespace: namespace
581
+ } : {}
582
+ };
583
+ }),
584
+ runtimeDependent: entry.parsed.isRuntimeDependent,
585
+ runtimeNamespaces,
586
+ ...entry.parsed.isRuntimeDependent ? {
587
+ promotionWarning: "Cannot be promoted to browser/public."
588
+ } : {}
589
+ };
590
+ },
591
+ isDerivedKey(key) {
592
+ return entries.has(key);
593
+ },
594
+ isRuntimeDependentKey(key) {
595
+ if (runtimeDependencyMemo.has(key)) {
596
+ return runtimeDependencyMemo.get(key);
597
+ }
598
+ const value = entries.get(key)?.parsed.isRuntimeDependent ?? false;
599
+ runtimeDependencyMemo.set(key, value);
600
+ return value;
601
+ },
602
+ toConcreteValue(key, readBase, mode) {
603
+ const entry = entries.get(key);
604
+ if (!entry) {
605
+ return support.read(key, readBase);
606
+ }
607
+ if (!entry.parsed.isRuntimeDependent) {
608
+ return support.read(key, readBase);
609
+ }
610
+ if (mode === "server" || mode === "runtime") {
611
+ return support.read(key, readBase);
612
+ }
613
+ for (const ref of entry.parsed.refs) {
614
+ const namespace = namespaceForKey(ref);
615
+ const runtimeNamespace = manifest.runtimeNamespaces[namespace];
616
+ if (!runtimeNamespace) {
617
+ continue;
618
+ }
619
+ if (runtimeNamespace.serverOnly) {
620
+ throw new CnosDerivedResolutionError(
621
+ key,
622
+ `Cannot resolve ${key} for ${mode} output because it depends on runtime namespace ${namespace}.`
623
+ );
624
+ }
625
+ if (!runtimeProviders.has(namespace)) {
626
+ if (mode === "env") {
627
+ return void 0;
628
+ }
629
+ throw new CnosDerivedResolutionError(
630
+ key,
631
+ `Cannot resolve ${key} for ${mode} output because runtime namespace ${namespace} has no registered provider.`
632
+ );
633
+ }
634
+ }
635
+ return support.read(key, readBase);
636
+ },
637
+ toServerFormula(key) {
638
+ const entry = entries.get(key);
639
+ if (!entry || !entry.parsed.isRuntimeDependent) {
640
+ return void 0;
641
+ }
642
+ return {
643
+ expr: entry.parsed.raw,
644
+ deps: entry.parsed.refs.filter((ref) => !manifest.runtimeNamespaces[namespaceForKey(ref)]),
645
+ runtimeRefs: entry.parsed.refs.filter((ref) => manifest.runtimeNamespaces[namespaceForKey(ref)])
646
+ };
647
+ },
648
+ derivedKeys: Array.from(entries.keys()).sort((left, right) => left.localeCompare(right))
649
+ });
650
+ const readDerived = (key, readBase, evaluationStack = /* @__PURE__ */ new Set()) => {
651
+ const entry = entries.get(key);
652
+ if (!entry) {
653
+ return readBase(key);
654
+ }
655
+ if (!entry.parsed.isRuntimeDependent && configCache.has(key)) {
656
+ return configCache.get(key);
657
+ }
658
+ const value = evaluateDerivation({
659
+ key,
660
+ parsed: entry.parsed,
661
+ resolveRef: (ref) => {
662
+ const namespace = namespaceForKey(ref);
663
+ if (runtimeProviders.has(namespace)) {
664
+ const provider = runtimeProviders.get(namespace);
665
+ return provider(ref.slice(namespace.length + 1));
666
+ }
667
+ if (entries.has(ref)) {
668
+ if (evaluationStack.has(ref)) {
669
+ throw new CnosDerivedResolutionError(key, `Unable to resolve derived config key ${key} because of a recursive dependency on ${ref}.`);
670
+ }
671
+ evaluationStack.add(ref);
672
+ const resolved = readDerived(ref, readBase, evaluationStack);
673
+ evaluationStack.delete(ref);
674
+ return resolved;
675
+ }
676
+ return readBase(ref);
677
+ }
678
+ });
679
+ if (!entry.parsed.isRuntimeDependent) {
680
+ configCache.set(key, value);
681
+ }
682
+ return value;
683
+ };
684
+ for (const key of Array.from(entries.keys()).sort((left, right) => left.localeCompare(right))) {
685
+ const entry = entries.get(key);
686
+ if (!entry.parsed.isRuntimeDependent) {
687
+ readDerived(key, (ref) => graph.entries.get(ref)?.value);
688
+ }
689
+ }
690
+ return support;
691
+ }
692
+ function registerRuntimeProvider(manifest, runtimeProviders, namespace, provider) {
693
+ const definition = manifest.runtimeNamespaces[namespace];
694
+ if (!definition) {
695
+ throw new CnosRuntimeProviderError(`Cannot register runtime provider for undeclared namespace "${namespace}".`);
696
+ }
697
+ if (definition.builtIn) {
698
+ throw new CnosRuntimeProviderError(`Cannot override built-in runtime namespace "${namespace}".`);
699
+ }
700
+ runtimeProviders.set(namespace, provider);
701
+ }
37
702
 
38
703
  // ../core/src/runtime/inspect.ts
39
- function inspectValue(graph, key) {
704
+ function inspectValue(graph, key, helpers = {}) {
40
705
  const entry = graph.entries.get(key);
41
706
  if (!entry) {
42
707
  throw new CnosKeyNotFoundError(key);
43
708
  }
709
+ const derived = helpers.describeDerived?.(key);
44
710
  return {
45
711
  key: entry.key,
46
- value: entry.value,
712
+ value: helpers.read ? helpers.read(entry.key) : entry.value,
47
713
  namespace: entry.namespace,
48
714
  profile: graph.profile,
49
715
  profileSource: graph.profileSource,
@@ -64,7 +730,10 @@ function inspectValue(graph, key) {
64
730
  workspaceId: override.workspaceId,
65
731
  value: override.value,
66
732
  ...override.origin ? { origin: override.origin } : {}
67
- }))
733
+ })),
734
+ ...derived ? {
735
+ derived
736
+ } : {}
68
737
  };
69
738
  }
70
739
 
@@ -175,25 +844,312 @@ async function writeKeychain(entry, value) {
175
844
  }
176
845
 
177
846
  // ../core/src/utils/yaml.ts
178
- import { parse, stringify } from "yaml";
847
+ import { parse, stringify as stringify2 } from "yaml";
179
848
  function parseYaml(source) {
180
849
  return parse(source);
181
850
  }
182
851
  function stringifyYaml(value) {
183
- return stringify(value);
852
+ return stringify2(value);
853
+ }
854
+
855
+ // ../core/src/discovery/parseGitUri.ts
856
+ function isGitRootUri(uri) {
857
+ return /^git\+[a-z]+:\/\//i.test(uri);
858
+ }
859
+ function parseGitUri(uri) {
860
+ if (!isGitRootUri(uri)) {
861
+ throw new CnosDiscoveryError(`Unsupported git root URI: ${uri}`);
862
+ }
863
+ const withoutPrefix = uri.slice("git+".length);
864
+ const hashIndex = withoutPrefix.indexOf("#");
865
+ if (hashIndex < 0) {
866
+ throw new CnosDiscoveryError(
867
+ `Git root URI must include a #ref (tag, branch, or commit). Got: ${uri}`
868
+ );
869
+ }
870
+ const cloneUrl = withoutPrefix.slice(0, hashIndex);
871
+ const fragment = withoutPrefix.slice(hashIndex + 1);
872
+ const separatorIndex = fragment.indexOf(":");
873
+ const ref = (separatorIndex >= 0 ? fragment.slice(0, separatorIndex) : fragment).trim();
874
+ const subpath = (separatorIndex >= 0 ? fragment.slice(separatorIndex + 1) : ".cnos").trim() || ".cnos";
875
+ const protocol = cloneUrl.slice(0, cloneUrl.indexOf("://"));
876
+ if (!cloneUrl || !ref) {
877
+ throw new CnosDiscoveryError(
878
+ `Git root URI must include both a clone URL and #ref. Got: ${uri}`
879
+ );
880
+ }
881
+ return {
882
+ uri,
883
+ cloneUrl,
884
+ ref,
885
+ subpath,
886
+ transport: protocol === "https" ? "https" : protocol === "ssh" ? "ssh" : protocol === "file" ? "file" : "custom"
887
+ };
184
888
  }
185
889
 
890
+ // ../core/src/discovery/cache/cacheManager.ts
891
+ var SEMVER_TAG_RE = /^v?\d+\.\d+(?:\.\d+)?(?:[-+][A-Za-z0-9.-]+)?$/;
892
+ var COMMIT_SHA_RE = /^[0-9a-f]{40}$/i;
893
+ function isImmutableGitRef(ref) {
894
+ return SEMVER_TAG_RE.test(ref) || COMMIT_SHA_RE.test(ref);
895
+ }
896
+ function resolveRemoteRootCacheTtlSeconds(mode = "runtime", processEnv = process.env, override) {
897
+ if (typeof override === "number" && Number.isFinite(override) && override >= 0) {
898
+ return override;
899
+ }
900
+ const fromEnv = Number(processEnv.CNOS_CACHE_TTL ?? "");
901
+ if (Number.isFinite(fromEnv) && fromEnv >= 0) {
902
+ return fromEnv;
903
+ }
904
+ switch (mode) {
905
+ case "build":
906
+ return 0;
907
+ case "dev":
908
+ return 30;
909
+ case "runtime":
910
+ default:
911
+ return 300;
912
+ }
913
+ }
914
+ function isRemoteRootCacheFresh(metadata, options) {
915
+ if (!metadata || options.forceRefresh) {
916
+ return false;
917
+ }
918
+ if (metadata.uri !== options.uri || metadata.ref !== options.ref) {
919
+ return false;
920
+ }
921
+ if (metadata.isImmutable) {
922
+ return true;
923
+ }
924
+ const ttlSeconds = resolveRemoteRootCacheTtlSeconds(
925
+ options.mode,
926
+ options.processEnv,
927
+ options.ttlSeconds
928
+ );
929
+ if (ttlSeconds <= 0) {
930
+ return false;
931
+ }
932
+ const cachedAtMs = Date.parse(metadata.cachedAt);
933
+ if (Number.isNaN(cachedAtMs)) {
934
+ return false;
935
+ }
936
+ return Date.now() - cachedAtMs <= ttlSeconds * 1e3;
937
+ }
938
+
939
+ // ../core/src/discovery/cache/cacheMetadata.ts
940
+ import { mkdir, readFile, writeFile } from "fs/promises";
941
+ import path from "path";
942
+ async function readRemoteRootCacheMetadata(metaPath) {
943
+ try {
944
+ const source = await readFile(metaPath, "utf8");
945
+ const parsed = JSON.parse(source);
946
+ if (!parsed || typeof parsed.uri !== "string" || typeof parsed.cloneUrl !== "string" || typeof parsed.ref !== "string" || typeof parsed.subpath !== "string" || typeof parsed.resolvedCommit !== "string" || typeof parsed.cachedAt !== "string" || typeof parsed.isImmutable !== "boolean") {
947
+ return void 0;
948
+ }
949
+ return parsed;
950
+ } catch {
951
+ return void 0;
952
+ }
953
+ }
954
+ async function writeRemoteRootCacheMetadata(metaPath, metadata) {
955
+ await mkdir(path.dirname(metaPath), { recursive: true });
956
+ await writeFile(metaPath, `${JSON.stringify(metadata, null, 2)}
957
+ `, "utf8");
958
+ }
959
+
960
+ // ../core/src/discovery/cache/cachePaths.ts
961
+ import { createHash } from "crypto";
962
+ import os3 from "os";
963
+ import path5 from "path";
964
+
186
965
  // ../core/src/utils/path.ts
187
- import { access as access2 } from "fs/promises";
188
- import os from "os";
966
+ import { access as access3 } from "fs/promises";
967
+ import os2 from "os";
968
+ import path4 from "path";
969
+
970
+ // ../core/src/discovery/findCnosrc.ts
971
+ import { access as access2, readFile as readFile2 } from "fs/promises";
972
+ import path3 from "path";
973
+
974
+ // ../core/src/discovery/resolveRoot.ts
975
+ import { access, mkdir as mkdir2 } from "fs/promises";
189
976
  import path2 from "path";
977
+ import { spawn as spawn2 } from "child_process";
978
+ import os from "os";
979
+ async function pathExists(targetPath) {
980
+ try {
981
+ await access(targetPath);
982
+ return true;
983
+ } catch {
984
+ return false;
985
+ }
986
+ }
987
+ function expandHomePath(targetPath) {
988
+ if (targetPath === "~") {
989
+ return os.homedir();
990
+ }
991
+ if (targetPath.startsWith("~/") || targetPath.startsWith("~\\")) {
992
+ return path2.join(os.homedir(), targetPath.slice(2));
993
+ }
994
+ return targetPath;
995
+ }
996
+ function isLocalRootUri(rootUri) {
997
+ return !isGitRootUri2(rootUri) && !isCnosHostedRootUri(rootUri);
998
+ }
999
+ function isCnosHostedRootUri(rootUri) {
1000
+ return rootUri.startsWith("cnos://");
1001
+ }
1002
+ function isGitRootUri2(rootUri) {
1003
+ return rootUri.startsWith("git+");
1004
+ }
1005
+ async function runGitCommand(args, options = {}) {
1006
+ return new Promise((resolve, reject) => {
1007
+ const child = spawn2("git", args, {
1008
+ cwd: options.cwd,
1009
+ env: options.processEnv ?? process.env,
1010
+ shell: process.platform === "win32",
1011
+ stdio: ["ignore", "pipe", "pipe"]
1012
+ });
1013
+ let stdout = "";
1014
+ let stderr = "";
1015
+ child.stdout.on("data", (chunk) => {
1016
+ stdout += chunk.toString();
1017
+ });
1018
+ child.stderr.on("data", (chunk) => {
1019
+ stderr += chunk.toString();
1020
+ });
1021
+ child.on("error", (error) => {
1022
+ reject(
1023
+ new CnosDiscoveryError(
1024
+ `Failed to run git. Make sure git is installed and available on PATH. ${error.message}`
1025
+ )
1026
+ );
1027
+ });
1028
+ child.on("close", (code) => {
1029
+ if (code === 0) {
1030
+ resolve(stdout.trim());
1031
+ return;
1032
+ }
1033
+ const details = stderr.trim() || stdout.trim();
1034
+ reject(
1035
+ new CnosDiscoveryError(
1036
+ details ? `Git command failed: ${details}` : `Git command failed with exit code ${code ?? 1}`
1037
+ )
1038
+ );
1039
+ });
1040
+ });
1041
+ }
1042
+ async function resolveLocalRoot(rootUri, cnosrcDir) {
1043
+ const candidateRoot = rootUri.startsWith("~") ? expandHomePath(rootUri) : rootUri;
1044
+ const manifestRoot = path2.resolve(cnosrcDir, candidateRoot);
1045
+ const manifestPath = path2.join(manifestRoot, "cnos.yml");
1046
+ if (!await pathExists(manifestPath)) {
1047
+ throw new CnosDiscoveryError(`.cnosrc.yml points to ${manifestRoot} but no cnos.yml found there.`);
1048
+ }
1049
+ return {
1050
+ manifestRoot,
1051
+ resolution: {
1052
+ rootUri,
1053
+ protocol: "local",
1054
+ remote: false,
1055
+ readOnly: false
1056
+ }
1057
+ };
1058
+ }
1059
+ async function ensureGitCheckout(parsed, repoDir, processEnv) {
1060
+ const hasRepo = await pathExists(path2.join(repoDir, ".git"));
1061
+ if (!hasRepo) {
1062
+ await mkdir2(path2.dirname(repoDir), { recursive: true });
1063
+ await runGitCommand(["clone", "--no-checkout", parsed.cloneUrl, repoDir], { processEnv });
1064
+ } else {
1065
+ await runGitCommand(["-C", repoDir, "remote", "set-url", "origin", parsed.cloneUrl], {
1066
+ processEnv
1067
+ });
1068
+ }
1069
+ await runGitCommand(["-C", repoDir, "fetch", "--tags", "--force", "origin"], { processEnv });
1070
+ await runGitCommand(["-C", repoDir, "checkout", "--force", parsed.ref], { processEnv });
1071
+ await runGitCommand(["-C", repoDir, "clean", "-fdx"], { processEnv });
1072
+ }
1073
+ async function resolveGitRoot(rootUri, options = {}) {
1074
+ const processEnv = options.processEnv ?? process.env;
1075
+ const parsed = parseGitUri(rootUri);
1076
+ const cachePaths = resolveRemoteRootCachePaths(rootUri, processEnv);
1077
+ const metadata = await readRemoteRootCacheMetadata(cachePaths.metaPath);
1078
+ const immutable = isImmutableGitRef(parsed.ref);
1079
+ const cacheFresh = isRemoteRootCacheFresh(metadata, {
1080
+ uri: rootUri,
1081
+ ref: parsed.ref,
1082
+ ...options.cacheMode ? { mode: options.cacheMode } : {},
1083
+ processEnv,
1084
+ ...typeof options.cacheTtlSeconds === "number" ? { ttlSeconds: options.cacheTtlSeconds } : {},
1085
+ ...options.forceRefresh ? { forceRefresh: true } : {}
1086
+ });
1087
+ if (!cacheFresh) {
1088
+ try {
1089
+ await ensureGitCheckout(parsed, cachePaths.repoDir, processEnv);
1090
+ } catch (error) {
1091
+ const message = error instanceof Error ? error.message : String(error);
1092
+ const authHint = parsed.transport === "ssh" ? " Check your SSH key and git access." : " Check the URL and your git credential helper or token setup.";
1093
+ throw new CnosDiscoveryError(`Failed to resolve remote git root ${rootUri}. ${message}${authHint}`);
1094
+ }
1095
+ const resolvedCommit = await runGitCommand(["-C", cachePaths.repoDir, "rev-parse", "HEAD"], {
1096
+ processEnv
1097
+ });
1098
+ await writeRemoteRootCacheMetadata(cachePaths.metaPath, {
1099
+ uri: rootUri,
1100
+ cloneUrl: parsed.cloneUrl,
1101
+ ref: parsed.ref,
1102
+ subpath: parsed.subpath,
1103
+ resolvedCommit,
1104
+ cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
1105
+ isImmutable: immutable
1106
+ });
1107
+ }
1108
+ const nextMetadata = metadata && cacheFresh ? metadata : await readRemoteRootCacheMetadata(cachePaths.metaPath);
1109
+ const manifestRoot = path2.join(cachePaths.repoDir, parsed.subpath);
1110
+ if (!await pathExists(path2.join(manifestRoot, "cnos.yml"))) {
1111
+ throw new CnosDiscoveryError(
1112
+ `Git root ${rootUri} resolved to ${manifestRoot} but no cnos.yml was found there. Check the :subpath segment.`
1113
+ );
1114
+ }
1115
+ return {
1116
+ manifestRoot,
1117
+ resolution: {
1118
+ rootUri,
1119
+ protocol: "git",
1120
+ remote: true,
1121
+ readOnly: true,
1122
+ cacheDir: cachePaths.cacheDir,
1123
+ cacheMetaPath: cachePaths.metaPath,
1124
+ ref: parsed.ref,
1125
+ subpath: parsed.subpath,
1126
+ immutable,
1127
+ ...nextMetadata?.resolvedCommit ? { resolvedCommit: nextMetadata.resolvedCommit } : {},
1128
+ ...nextMetadata?.cachedAt ? { cachedAt: nextMetadata.cachedAt } : {}
1129
+ }
1130
+ };
1131
+ }
1132
+ async function resolveRootUri(rootUri, cnosrcDir, options = {}) {
1133
+ if (isLocalRootUri(rootUri)) {
1134
+ return resolveLocalRoot(rootUri, cnosrcDir);
1135
+ }
1136
+ if (isGitRootUri2(rootUri)) {
1137
+ return resolveGitRoot(rootUri, options);
1138
+ }
1139
+ if (isCnosHostedRootUri(rootUri)) {
1140
+ throw new CnosDiscoveryError(
1141
+ `The cnos:// remote root protocol is reserved but not implemented yet. Use git+https:// or git+ssh:// for now.`
1142
+ );
1143
+ }
1144
+ throw new CnosDiscoveryError(
1145
+ `Unknown root protocol: ${rootUri}. Supported root protocols are local paths, git+https://..., and git+ssh://....`
1146
+ );
1147
+ }
190
1148
 
191
1149
  // ../core/src/discovery/findCnosrc.ts
192
- import { access, readFile } from "fs/promises";
193
- import path from "path";
194
1150
  async function exists(targetPath) {
195
1151
  try {
196
- await access(targetPath);
1152
+ await access2(targetPath);
197
1153
  return true;
198
1154
  } catch {
199
1155
  return false;
@@ -214,13 +1170,13 @@ function validateCnosrc(value, filePath) {
214
1170
  };
215
1171
  }
216
1172
  async function findCnosrc(startDir = process.cwd(), maxLevels = 3) {
217
- let current = path.resolve(startDir);
1173
+ let current = path3.resolve(startDir);
218
1174
  for (let depth = 0; depth <= maxLevels; depth += 1) {
219
- const candidate = path.join(current, ".cnosrc.yml");
1175
+ const candidate = path3.join(current, ".cnosrc.yml");
220
1176
  if (await exists(candidate)) {
221
1177
  return candidate;
222
1178
  }
223
- const parent = path.dirname(current);
1179
+ const parent = path3.dirname(current);
224
1180
  if (parent === current) {
225
1181
  break;
226
1182
  }
@@ -228,27 +1184,22 @@ async function findCnosrc(startDir = process.cwd(), maxLevels = 3) {
228
1184
  }
229
1185
  return void 0;
230
1186
  }
231
- async function discoverCnosAnchor(startDir = process.cwd(), maxLevels = 3) {
1187
+ async function discoverCnosAnchor(startDir = process.cwd(), maxLevels = 3, options = {}) {
232
1188
  const anchorPath = await findCnosrc(startDir, maxLevels);
233
1189
  if (!anchorPath) {
234
1190
  throw new CnosDiscoveryError(
235
1191
  "No .cnosrc.yml found. Run cnos init or create .cnosrc.yml in your package root."
236
1192
  );
237
1193
  }
238
- const source = await readFile(anchorPath, "utf8");
1194
+ const source = await readFile2(anchorPath, "utf8");
239
1195
  const parsed = validateCnosrc(parseYaml(source), anchorPath);
240
- const consumerRoot = path.dirname(anchorPath);
241
- const manifestRoot = path.resolve(consumerRoot, parsed.root);
242
- const manifestPath = path.join(manifestRoot, "cnos.yml");
243
- if (!await exists(manifestPath)) {
244
- throw new CnosDiscoveryError(
245
- `.cnosrc.yml points to ${manifestRoot} but no cnos.yml found there.`
246
- );
247
- }
1196
+ const consumerRoot = path3.dirname(anchorPath);
1197
+ const resolvedRoot = await resolveRootUri(parsed.root, consumerRoot, options);
248
1198
  return {
249
1199
  anchorPath,
250
1200
  consumerRoot,
251
- manifestRoot,
1201
+ manifestRoot: resolvedRoot.manifestRoot,
1202
+ rootResolution: resolvedRoot.resolution,
252
1203
  ...parsed.workspace ? { workspace: parsed.workspace } : {}
253
1204
  };
254
1205
  }
@@ -258,21 +1209,21 @@ var PRIMARY_CNOS_DIR = ".cnos";
258
1209
  var LEGACY_CNOS_DIR = "cnos";
259
1210
  async function exists2(filePath) {
260
1211
  try {
261
- await access2(filePath);
1212
+ await access3(filePath);
262
1213
  return true;
263
1214
  } catch {
264
1215
  return false;
265
1216
  }
266
1217
  }
267
1218
  async function resolveCnosRoot(root = process.cwd()) {
268
- const basePath = path2.resolve(root);
1219
+ const basePath = path4.resolve(root);
269
1220
  const candidates = [
270
- path2.join(basePath, PRIMARY_CNOS_DIR),
271
- path2.join(basePath, LEGACY_CNOS_DIR),
1221
+ path4.join(basePath, PRIMARY_CNOS_DIR),
1222
+ path4.join(basePath, LEGACY_CNOS_DIR),
272
1223
  basePath
273
1224
  ];
274
1225
  for (const candidate of candidates) {
275
- if (await exists2(path2.join(candidate, "cnos.yml"))) {
1226
+ if (await exists2(path4.join(candidate, "cnos.yml"))) {
276
1227
  return candidate;
277
1228
  }
278
1229
  }
@@ -282,18 +1233,44 @@ async function resolveCnosRoot(root = process.cwd()) {
282
1233
  }
283
1234
  async function resolveManifestRoot(options = {}) {
284
1235
  if (options.root) {
1236
+ if (options.root.startsWith("git+") || options.root.startsWith("cnos://")) {
1237
+ const consumerRoot2 = path4.resolve(options.cwd ?? process.cwd());
1238
+ const resolvedRoot2 = await resolveRootUri(options.root, consumerRoot2, {
1239
+ ...options.processEnv ? { processEnv: options.processEnv } : {},
1240
+ ...options.cacheMode ? { cacheMode: options.cacheMode } : {},
1241
+ ...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
1242
+ ...options.forceRefresh ? { forceRefresh: true } : {}
1243
+ });
1244
+ return {
1245
+ manifestRoot: resolvedRoot2.manifestRoot,
1246
+ consumerRoot: consumerRoot2,
1247
+ rootResolution: resolvedRoot2.resolution
1248
+ };
1249
+ }
285
1250
  const manifestRoot = await resolveCnosRoot(options.root);
286
- const resolvedRoot = path2.resolve(options.root);
287
- const consumerRoot = path2.basename(manifestRoot) === PRIMARY_CNOS_DIR || path2.basename(manifestRoot) === LEGACY_CNOS_DIR ? path2.dirname(manifestRoot) : resolvedRoot;
1251
+ const resolvedRoot = path4.resolve(options.root);
1252
+ const consumerRoot = path4.basename(manifestRoot) === PRIMARY_CNOS_DIR || path4.basename(manifestRoot) === LEGACY_CNOS_DIR ? path4.dirname(manifestRoot) : resolvedRoot;
288
1253
  return {
289
1254
  manifestRoot,
290
- consumerRoot
1255
+ consumerRoot,
1256
+ rootResolution: {
1257
+ rootUri: manifestRoot,
1258
+ protocol: "local",
1259
+ remote: false,
1260
+ readOnly: false
1261
+ }
291
1262
  };
292
1263
  }
293
- const discovered = await discoverCnosAnchor(options.cwd ?? process.cwd());
1264
+ const discovered = await discoverCnosAnchor(options.cwd ?? process.cwd(), 3, {
1265
+ ...options.processEnv ? { processEnv: options.processEnv } : {},
1266
+ ...options.cacheMode ? { cacheMode: options.cacheMode } : {},
1267
+ ...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
1268
+ ...options.forceRefresh ? { forceRefresh: true } : {}
1269
+ });
294
1270
  return {
295
1271
  manifestRoot: discovered.manifestRoot,
296
1272
  consumerRoot: discovered.consumerRoot,
1273
+ rootResolution: discovered.rootResolution,
297
1274
  anchorPath: discovered.anchorPath,
298
1275
  ...discovered.workspace ? { workspace: discovered.workspace } : {}
299
1276
  };
@@ -304,12 +1281,12 @@ function interpolatePathTemplate(template, tokens) {
304
1281
  template
305
1282
  );
306
1283
  }
307
- function expandHomePath(targetPath) {
1284
+ function expandHomePath2(targetPath) {
308
1285
  if (targetPath === "~") {
309
- return os.homedir();
1286
+ return os2.homedir();
310
1287
  }
311
1288
  if (targetPath.startsWith("~/") || targetPath.startsWith("~\\")) {
312
- return path2.join(os.homedir(), targetPath.slice(2));
1289
+ return path4.join(os2.homedir(), targetPath.slice(2));
313
1290
  }
314
1291
  return targetPath;
315
1292
  }
@@ -327,19 +1304,19 @@ function stripWorkspaceTemplatePrefix(template) {
327
1304
  function resolveWorkspaceScopedPath(workspaceRoot, template, tokens) {
328
1305
  const relativeTemplate = stripWorkspaceTemplatePrefix(template);
329
1306
  const interpolated = interpolatePathTemplate(relativeTemplate, tokens);
330
- return path2.resolve(workspaceRoot, interpolated);
1307
+ return path4.resolve(workspaceRoot, interpolated);
331
1308
  }
332
1309
  function resolveNamespaceDirectory(workspaceRoot, namespace, profile) {
333
1310
  const rootFolder = namespace === "value" ? "values" : namespace === "secret" ? "secrets" : namespace;
334
1311
  if (profile && profile !== "base") {
335
- return path2.resolve(workspaceRoot, "profiles", profile, rootFolder);
1312
+ return path4.resolve(workspaceRoot, "profiles", profile, rootFolder);
336
1313
  }
337
- return path2.resolve(workspaceRoot, rootFolder);
1314
+ return path4.resolve(workspaceRoot, rootFolder);
338
1315
  }
339
1316
  function resolveConfigDocumentPath(workspaceRoot, namespace, configPath, profile) {
340
1317
  const namespaceRoot = resolveNamespaceDirectory(workspaceRoot, namespace, profile);
341
1318
  const fileName = `${configPath.split(".").shift() ?? "app"}.yml`;
342
- return path2.resolve(namespaceRoot, fileName);
1319
+ return path4.resolve(namespaceRoot, fileName);
343
1320
  }
344
1321
  function toPortablePath(targetPath) {
345
1322
  return targetPath.replace(/\\/g, "/");
@@ -354,9 +1331,29 @@ function stripNamespace(key) {
354
1331
  return key.split(".").slice(1).join(".");
355
1332
  }
356
1333
 
1334
+ // ../core/src/discovery/cache/cachePaths.ts
1335
+ function resolveCnosCacheRoot(processEnv = process.env) {
1336
+ return path5.resolve(
1337
+ expandHomePath2(processEnv.CNOS_CACHE_DIR ?? path5.join(os3.homedir(), ".cnos", "cache"))
1338
+ );
1339
+ }
1340
+ function createRemoteRootCacheKey(uri) {
1341
+ return createHash("sha256").update(uri).digest("hex");
1342
+ }
1343
+ function resolveRemoteRootCachePaths(uri, processEnv = process.env) {
1344
+ const cacheRoot = resolveCnosCacheRoot(processEnv);
1345
+ const cacheDir = path5.join(cacheRoot, "roots", createRemoteRootCacheKey(uri));
1346
+ return {
1347
+ cacheRoot,
1348
+ cacheDir,
1349
+ repoDir: path5.join(cacheDir, "repo"),
1350
+ metaPath: path5.join(cacheDir, ".cnos-cache-meta.json")
1351
+ };
1352
+ }
1353
+
357
1354
  // ../core/src/manifest/loadManifest.ts
358
- import { readFile as readFile2 } from "fs/promises";
359
- import path3 from "path";
1355
+ import { readFile as readFile3 } from "fs/promises";
1356
+ import path6 from "path";
360
1357
 
361
1358
  // ../core/src/manifest/normalizeManifest.ts
362
1359
  var DEFAULT_RESOLVE_FROM = ["cli.profile", "env.CNOS_PROFILE", "default"];
@@ -409,6 +1406,13 @@ var DEFAULT_NAMESPACES = {
409
1406
  readonly: true
410
1407
  }
411
1408
  };
1409
+ var DEFAULT_RUNTIME_NAMESPACES = {
1410
+ process: {
1411
+ description: "Live process runtime values.",
1412
+ serverOnly: true,
1413
+ builtIn: true
1414
+ }
1415
+ };
412
1416
  function validateResolveFrom(resolveFrom) {
413
1417
  const validValues = ["cli.profile", "env.CNOS_PROFILE", "default"];
414
1418
  for (const entry of resolveFrom) {
@@ -431,7 +1435,7 @@ function normalizeWorkspaceItems(items) {
431
1435
  }
432
1436
  function normalizeNamespaces(namespaces) {
433
1437
  const normalized = Object.fromEntries(
434
- Object.entries(namespaces ?? {}).map(([namespace, definition]) => [
1438
+ Object.entries(namespaces ?? {}).filter(([namespace]) => namespace !== "runtime").map(([namespace, definition]) => [
435
1439
  namespace,
436
1440
  {
437
1441
  kind: definition.kind ?? "data",
@@ -447,6 +1451,29 @@ function normalizeNamespaces(namespaces) {
447
1451
  ...normalized
448
1452
  };
449
1453
  }
1454
+ function normalizeRuntimeNamespaces(namespaces) {
1455
+ const runtimeEntries = namespaces?.runtime ?? {};
1456
+ const normalized = Object.fromEntries(
1457
+ Object.entries(runtimeEntries).map(([namespace, definition]) => [
1458
+ namespace,
1459
+ {
1460
+ ...definition.description?.trim() ? {
1461
+ description: definition.description.trim()
1462
+ } : {},
1463
+ serverOnly: definition.server_only ?? true
1464
+ }
1465
+ ])
1466
+ );
1467
+ for (const namespace of Object.keys(normalized)) {
1468
+ if (DEFAULT_NAMESPACES[namespace] || namespace === "runtime") {
1469
+ throw new CnosManifestError(`Runtime namespace "${namespace}" conflicts with a built-in or reserved namespace.`);
1470
+ }
1471
+ }
1472
+ return {
1473
+ ...DEFAULT_RUNTIME_NAMESPACES,
1474
+ ...normalized
1475
+ };
1476
+ }
450
1477
  function normalizeVaults(vaults) {
451
1478
  return Object.fromEntries(
452
1479
  Object.entries(vaults ?? {}).map(([name, definition]) => {
@@ -538,6 +1565,7 @@ function normalizeManifest(manifest) {
538
1565
  const defaultProfile = manifest.profiles?.default?.trim() || "base";
539
1566
  const workspaceItems = normalizeWorkspaceItems(manifest.workspaces?.items);
540
1567
  const resolveFrom = validateResolveFrom(manifest.profiles?.resolveFrom ?? DEFAULT_RESOLVE_FROM);
1568
+ const runtimeNamespaces = normalizeRuntimeNamespaces(manifest.namespaces);
541
1569
  const filesystemValues = {
542
1570
  root: "./",
543
1571
  format: "yaml",
@@ -611,6 +1639,7 @@ function normalizeManifest(manifest) {
611
1639
  }
612
1640
  },
613
1641
  namespaces: normalizeNamespaces(manifest.namespaces),
1642
+ runtimeNamespaces,
614
1643
  vaults: normalizeVaults(manifest.vaults),
615
1644
  writePolicy: {
616
1645
  define: {
@@ -629,13 +1658,17 @@ function normalizeManifest(manifest) {
629
1658
  async function loadManifest(options = {}) {
630
1659
  const resolved = await resolveManifestRoot({
631
1660
  ...options.root ? { root: options.root } : {},
632
- ...options.cwd ? { cwd: options.cwd } : {}
1661
+ ...options.cwd ? { cwd: options.cwd } : {},
1662
+ ...options.processEnv ? { processEnv: options.processEnv } : {},
1663
+ ...options.cacheMode ? { cacheMode: options.cacheMode } : {},
1664
+ ...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
1665
+ ...options.forceRefresh ? { forceRefresh: true } : {}
633
1666
  });
634
1667
  const manifestRoot = resolved.manifestRoot;
635
- const manifestPath = path3.join(manifestRoot, "cnos.yml");
1668
+ const manifestPath = path6.join(manifestRoot, "cnos.yml");
636
1669
  let source;
637
1670
  try {
638
- source = await readFile2(manifestPath, "utf8");
1671
+ source = await readFile3(manifestPath, "utf8");
639
1672
  } catch {
640
1673
  throw new CnosManifestError("Unable to read CNOS manifest", manifestPath);
641
1674
  }
@@ -645,10 +1678,11 @@ async function loadManifest(options = {}) {
645
1678
  }
646
1679
  return {
647
1680
  manifestRoot,
648
- repoRoot: path3.dirname(manifestRoot),
1681
+ repoRoot: path6.dirname(manifestRoot),
649
1682
  consumerRoot: resolved.consumerRoot,
650
1683
  ...resolved.anchorPath ? { anchorPath: resolved.anchorPath } : {},
651
1684
  ...resolved.workspace ? { anchoredWorkspace: resolved.workspace } : {},
1685
+ rootResolution: resolved.rootResolution,
652
1686
  manifestPath,
653
1687
  manifest: normalizeManifest(rawManifest),
654
1688
  rawManifest
@@ -704,29 +1738,29 @@ function validateProjectionIssue(manifest, key, target) {
704
1738
  }
705
1739
 
706
1740
  // ../core/src/secrets/sessionStore.ts
707
- import { mkdir, readFile as readFile3, readdir, rm, writeFile } from "fs/promises";
708
- import path4 from "path";
1741
+ import { mkdir as mkdir3, readFile as readFile4, readdir, rm, writeFile as writeFile2 } from "fs/promises";
1742
+ import path7 from "path";
709
1743
  function buildSessionRoot(processEnv = process.env) {
710
- return path4.join(path4.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets")), "sessions");
1744
+ return path7.join(path7.resolve(expandHomePath2(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets")), "sessions");
711
1745
  }
712
1746
  function buildSessionPath(vault, processEnv) {
713
- return path4.join(buildSessionRoot(processEnv), `${vault}.json`);
1747
+ return path7.join(buildSessionRoot(processEnv), `${vault}.json`);
714
1748
  }
715
1749
  async function writeVaultSessionKey(vault, derivedKey, processEnv) {
716
1750
  const filePath = buildSessionPath(vault, processEnv);
717
- await mkdir(path4.dirname(filePath), { recursive: true });
1751
+ await mkdir3(path7.dirname(filePath), { recursive: true });
718
1752
  const document = {
719
1753
  version: 1,
720
1754
  vault,
721
1755
  derivedKey: derivedKey.toString("hex"),
722
1756
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
723
1757
  };
724
- await writeFile(filePath, JSON.stringify(document, null, 2), "utf8");
1758
+ await writeFile2(filePath, JSON.stringify(document, null, 2), "utf8");
725
1759
  return filePath;
726
1760
  }
727
1761
  async function readVaultSessionKey(vault, processEnv) {
728
1762
  try {
729
- const source = await readFile3(buildSessionPath(vault, processEnv), "utf8");
1763
+ const source = await readFile4(buildSessionPath(vault, processEnv), "utf8");
730
1764
  const document = JSON.parse(source);
731
1765
  if (document.version !== 1 || typeof document.derivedKey !== "string") {
732
1766
  return void 0;
@@ -744,15 +1778,15 @@ async function clearAllVaultSessionKeys(processEnv) {
744
1778
  const root = buildSessionRoot(processEnv);
745
1779
  try {
746
1780
  const entries = await readdir(root);
747
- await Promise.all(entries.map((entry) => rm(path4.join(root, entry), { force: true })));
1781
+ await Promise.all(entries.map((entry) => rm(path7.join(root, entry), { force: true })));
748
1782
  } catch {
749
1783
  }
750
1784
  }
751
1785
 
752
1786
  // ../core/src/utils/secretStore.ts
753
1787
  import { createCipheriv, createDecipheriv, pbkdf2Sync, randomBytes } from "crypto";
754
- import { mkdir as mkdir2, readdir as readdir2, readFile as readFile4, rm as rm2, stat, writeFile as writeFile2 } from "fs/promises";
755
- import path5 from "path";
1788
+ import { mkdir as mkdir4, readdir as readdir2, readFile as readFile5, rm as rm2, stat, writeFile as writeFile3 } from "fs/promises";
1789
+ import path8 from "path";
756
1790
  var KEY_LENGTH = 32;
757
1791
  var SALT_LENGTH = 32;
758
1792
  var IV_LENGTH = 12;
@@ -769,7 +1803,7 @@ function isSecretReference(value) {
769
1803
  return isObject(value) && typeof value.provider === "string" && value.provider.trim().length > 0 && typeof value.ref === "string" && value.ref.trim().length > 0 && (value.vault === void 0 && true || typeof value.vault === "string" && value.vault.trim().length > 0) && Object.keys(value).every((key) => ["provider", "ref", "vault"].includes(key));
770
1804
  }
771
1805
  function resolveSecretStoreRoot(processEnv = process.env) {
772
- return path5.resolve(expandHomePath(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
1806
+ return path8.resolve(expandHomePath2(processEnv.CNOS_SECRET_HOME ?? "~/.cnos/secrets"));
773
1807
  }
774
1808
  function normalizeVaultToken(vault = "default") {
775
1809
  return vault.replace(/[^A-Za-z0-9]+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
@@ -804,19 +1838,19 @@ function deriveVaultKey(passphrase, salt, iterations = PBKDF2_ITERATIONS) {
804
1838
  return pbkdf2Sync(passphrase, salt, iterations, KEY_LENGTH, "sha512");
805
1839
  }
806
1840
  function buildMetaPath(storeRoot, vault = "default") {
807
- return path5.join(storeRoot, "vaults", vault, META_FILENAME);
1841
+ return path8.join(storeRoot, "vaults", vault, META_FILENAME);
808
1842
  }
809
1843
  function resolveSecretVaultFile(storeRoot, vault = "default") {
810
1844
  return buildMetaPath(storeRoot, vault);
811
1845
  }
812
1846
  function buildKeystorePath(storeRoot, vault = "default") {
813
- return path5.join(storeRoot, "vaults", vault, KEYSTORE_FILENAME);
1847
+ return path8.join(storeRoot, "vaults", vault, KEYSTORE_FILENAME);
814
1848
  }
815
1849
  function buildLegacyVaultFile(storeRoot, vault = "default") {
816
- return path5.join(storeRoot, "vaults", `${vault}.json`);
1850
+ return path8.join(storeRoot, "vaults", `${vault}.json`);
817
1851
  }
818
1852
  function buildLegacyVaultStoreRoot(storeRoot, vault = "default") {
819
- return path5.join(storeRoot, "vaults", vault, "store");
1853
+ return path8.join(storeRoot, "vaults", vault, "store");
820
1854
  }
821
1855
  function assertVaultMetadata(value, filePath) {
822
1856
  if (!isObject(value)) {
@@ -913,15 +1947,15 @@ function buildInitialPayload() {
913
1947
  async function writeVaultFiles(storeRoot, vault, meta, payload, key) {
914
1948
  const metaPath = buildMetaPath(storeRoot, vault);
915
1949
  const keystorePath = buildKeystorePath(storeRoot, vault);
916
- await mkdir2(path5.dirname(metaPath), { recursive: true });
917
- await writeFile2(metaPath, stringifyYaml(meta), "utf8");
918
- await writeFile2(keystorePath, encryptPayload(payload, key));
1950
+ await mkdir4(path8.dirname(metaPath), { recursive: true });
1951
+ await writeFile3(metaPath, stringifyYaml(meta), "utf8");
1952
+ await writeFile3(keystorePath, encryptPayload(payload, key));
919
1953
  }
920
1954
  async function readVaultMetadata(storeRoot, vault = "default") {
921
1955
  await assertNoLegacyVaultFormat(storeRoot, vault);
922
1956
  const metaPath = buildMetaPath(storeRoot, vault);
923
1957
  try {
924
- const source = await readFile4(metaPath, "utf8");
1958
+ const source = await readFile5(metaPath, "utf8");
925
1959
  return assertVaultMetadata(parseYaml(source), metaPath);
926
1960
  } catch (error) {
927
1961
  if (error.code === "ENOENT") {
@@ -931,11 +1965,11 @@ async function readVaultMetadata(storeRoot, vault = "default") {
931
1965
  }
932
1966
  }
933
1967
  async function listSecretVaults(storeRoot) {
934
- const vaultRoot = path5.join(storeRoot, "vaults");
1968
+ const vaultRoot = path8.join(storeRoot, "vaults");
935
1969
  try {
936
1970
  const entries = await readdir2(vaultRoot, { withFileTypes: true });
937
1971
  const vaults = await Promise.all(
938
- entries.filter((entry) => entry.isDirectory()).map(async (entry) => await exists3(path5.join(vaultRoot, entry.name, META_FILENAME)) ? entry.name : void 0)
1972
+ entries.filter((entry) => entry.isDirectory()).map(async (entry) => await exists3(path8.join(vaultRoot, entry.name, META_FILENAME)) ? entry.name : void 0)
939
1973
  );
940
1974
  return vaults.filter((value) => Boolean(value)).sort((left, right) => left.localeCompare(right));
941
1975
  } catch {
@@ -1024,7 +2058,7 @@ async function loadVaultPayload(storeRoot, vault, auth) {
1024
2058
  if (!key) {
1025
2059
  throw new CnosAuthenticationError(`Vault "${vault}" requires authentication before access.`);
1026
2060
  }
1027
- const buffer = await readFile4(buildKeystorePath(storeRoot, vault));
2061
+ const buffer = await readFile5(buildKeystorePath(storeRoot, vault));
1028
2062
  return {
1029
2063
  meta,
1030
2064
  payload: decryptPayload(buffer, key),
@@ -1097,7 +2131,7 @@ function resolveVaultDefinition(vaults, vault = "default") {
1097
2131
  };
1098
2132
  }
1099
2133
  async function removeLocalVaultFiles(storeRoot, vault = "default") {
1100
- await rm2(path5.join(storeRoot, "vaults", vault), { recursive: true, force: true });
2134
+ await rm2(path8.join(storeRoot, "vaults", vault), { recursive: true, force: true });
1101
2135
  }
1102
2136
 
1103
2137
  // ../core/src/secrets/providers/github.ts
@@ -1156,11 +2190,11 @@ var GithubSecretsVaultProvider = class {
1156
2190
  };
1157
2191
 
1158
2192
  // ../core/src/secrets/auditLog.ts
1159
- import { appendFile, mkdir as mkdir3 } from "fs/promises";
1160
- import path6 from "path";
2193
+ import { appendFile, mkdir as mkdir5 } from "fs/promises";
2194
+ import path9 from "path";
1161
2195
  async function appendAuditEvent(event, processEnv = process.env) {
1162
- const auditFile = processEnv.CNOS_AUDIT_FILE ?? path6.join(resolveSecretStoreRoot(processEnv), "audit", "access.log");
1163
- await mkdir3(path6.dirname(auditFile), { recursive: true });
2196
+ const auditFile = processEnv.CNOS_AUDIT_FILE ?? path9.join(resolveSecretStoreRoot(processEnv), "audit", "access.log");
2197
+ await mkdir5(path9.dirname(auditFile), { recursive: true });
1164
2198
  await appendFile(
1165
2199
  auditFile,
1166
2200
  `${JSON.stringify({
@@ -1387,7 +2421,7 @@ function setNestedValue(target, pathSegments, value) {
1387
2421
  target[head] = nextTarget;
1388
2422
  setNestedValue(nextTarget, tail, value);
1389
2423
  }
1390
- function toNamespaceObject(graph, namespace) {
2424
+ function toNamespaceObject(graph, namespace, readValueForKey = (key) => graph.entries.get(key)?.value) {
1391
2425
  const output = {};
1392
2426
  const resolvedEntries = Array.from(graph.entries.values()).sort(
1393
2427
  (left, right) => left.key.localeCompare(right.key)
@@ -1397,7 +2431,11 @@ function toNamespaceObject(graph, namespace) {
1397
2431
  continue;
1398
2432
  }
1399
2433
  const valuePath = namespace ? stripNamespace(entry.key) : entry.key;
1400
- setNestedValue(output, valuePath.split("."), entry.value);
2434
+ const value = readValueForKey(entry.key);
2435
+ if (value === void 0) {
2436
+ continue;
2437
+ }
2438
+ setNestedValue(output, valuePath.split("."), value);
1401
2439
  }
1402
2440
  return output;
1403
2441
  }
@@ -1407,12 +2445,6 @@ function readValue(graph, key) {
1407
2445
  return graph.entries.get(key)?.value;
1408
2446
  }
1409
2447
 
1410
- // ../core/src/runtime/readOr.ts
1411
- function readOrValue(graph, key, fallback) {
1412
- const value = readValue(graph, key);
1413
- return value === void 0 ? fallback : value;
1414
- }
1415
-
1416
2448
  // ../core/src/runtime/require.ts
1417
2449
  function requireValue(graph, key) {
1418
2450
  const value = readValue(graph, key);
@@ -1422,6 +2454,36 @@ function requireValue(graph, key) {
1422
2454
  return value;
1423
2455
  }
1424
2456
 
2457
+ // ../core/src/runtime/runtimeProviders.ts
2458
+ function createDefaultRuntimeProviders(manifest, processEnv) {
2459
+ const providers = /* @__PURE__ */ new Map();
2460
+ if (manifest.runtimeNamespaces.process) {
2461
+ providers.set("process", (key) => {
2462
+ const segments = key.split(".");
2463
+ if (segments[0] === "env") {
2464
+ return processEnv[segments.slice(1).join(".")];
2465
+ }
2466
+ if (key === "cwd") {
2467
+ return process.cwd();
2468
+ }
2469
+ if (key === "platform") {
2470
+ return process.platform;
2471
+ }
2472
+ if (key === "arch") {
2473
+ return process.arch;
2474
+ }
2475
+ if (key === "pid") {
2476
+ return process.pid;
2477
+ }
2478
+ if (key === "node.version") {
2479
+ return process.version;
2480
+ }
2481
+ return void 0;
2482
+ });
2483
+ }
2484
+ return providers;
2485
+ }
2486
+
1425
2487
  // ../core/src/runtime/toEnv.ts
1426
2488
  function normalizeEnvValue(value) {
1427
2489
  if (value === void 0 || value === null) {
@@ -1435,7 +2497,7 @@ function normalizeEnvValue(value) {
1435
2497
  }
1436
2498
  return JSON.stringify(value);
1437
2499
  }
1438
- function toEnv(graph, manifest, options = {}) {
2500
+ function toEnv(graph, manifest, options = {}, helpers = {}) {
1439
2501
  const includeSecrets = options.includeSecrets ?? true;
1440
2502
  const output = {};
1441
2503
  const mappedEntries = Object.entries(manifest.envMapping.explicit).sort(
@@ -1456,7 +2518,11 @@ function toEnv(graph, manifest, options = {}) {
1456
2518
  if (isSecretReference(entry.value)) {
1457
2519
  continue;
1458
2520
  }
1459
- output[envVar] = normalizeEnvValue(entry.value);
2521
+ const value = helpers.read ? helpers.read(logicalKey) : entry.value;
2522
+ if (value === void 0) {
2523
+ continue;
2524
+ }
2525
+ output[envVar] = normalizeEnvValue(value);
1460
2526
  }
1461
2527
  return output;
1462
2528
  }
@@ -1493,36 +2559,46 @@ function resolvePublicPrefix(manifest, options) {
1493
2559
  }
1494
2560
  return manifest.public.frameworks[options.framework] ?? "";
1495
2561
  }
1496
- function toPublicEnv(graph, manifest, options = {}) {
2562
+ function toPublicEnv(graph, manifest, options = {}, helpers = {}) {
1497
2563
  const prefix = resolvePublicPrefix(manifest, options);
1498
2564
  const output = {};
1499
2565
  const promotions = Array.from(graph.entries.values()).filter((entry) => entry.namespace === "public").sort((left, right) => left.key.localeCompare(right.key));
1500
2566
  for (const resolved of promotions) {
2567
+ if (helpers.isRuntimeDependent?.(resolved.key)) {
2568
+ const value2 = helpers.read?.(resolved.key);
2569
+ if (value2 === void 0) {
2570
+ throw new CnosManifestError(`Cannot build public output for ${resolved.key} because it depends on runtime-only values.`);
2571
+ }
2572
+ }
1501
2573
  const baseEnvVar = fallbackPublicEnvVar(stripNamespace(resolved.key));
1502
2574
  const envVar = prefix && !baseEnvVar.startsWith(prefix) ? `${prefix}${baseEnvVar}` : baseEnvVar;
1503
- output[envVar] = normalizeEnvValue2(resolved.value);
2575
+ const value = helpers.read ? helpers.read(resolved.key) : resolved.value;
2576
+ if (value === void 0) {
2577
+ continue;
2578
+ }
2579
+ output[envVar] = normalizeEnvValue2(value);
1504
2580
  }
1505
2581
  return output;
1506
2582
  }
1507
2583
 
1508
2584
  // ../core/src/runtime/dump.ts
1509
- import { mkdir as mkdir4, writeFile as writeFile3 } from "fs/promises";
1510
- import path7 from "path";
2585
+ import { mkdir as mkdir6, writeFile as writeFile4 } from "fs/promises";
2586
+ import path10 from "path";
1511
2587
  function buildDumpFiles(graph, options = {}) {
1512
- const basePath = options.flatten ? "" : path7.posix.join("workspaces", graph.workspace.workspaceId);
2588
+ const basePath = options.flatten ? "" : path10.posix.join("workspaces", graph.workspace.workspaceId);
1513
2589
  const values = toNamespaceObject(graph, "value");
1514
2590
  const secrets = toNamespaceObject(graph, "secret");
1515
2591
  const files = [];
1516
2592
  if (Object.keys(values).length > 0) {
1517
2593
  files.push({
1518
- path: path7.posix.join(basePath, "values", graph.profile, "app.yml"),
2594
+ path: path10.posix.join(basePath, "values", graph.profile, "app.yml"),
1519
2595
  namespace: "value",
1520
2596
  content: stringifyYaml(values)
1521
2597
  });
1522
2598
  }
1523
2599
  if (Object.keys(secrets).length > 0) {
1524
2600
  files.push({
1525
- path: path7.posix.join(basePath, "secrets", graph.profile, "app.yml"),
2601
+ path: path10.posix.join(basePath, "secrets", graph.profile, "app.yml"),
1526
2602
  namespace: "secret",
1527
2603
  content: stringifyYaml(secrets)
1528
2604
  });
@@ -1538,12 +2614,12 @@ function planDump(graph, options = {}) {
1538
2614
  };
1539
2615
  }
1540
2616
  async function writeDump(graph, options) {
1541
- const root = path7.resolve(options.to);
2617
+ const root = path10.resolve(options.to);
1542
2618
  const plan = planDump(graph, options);
1543
2619
  for (const file of plan.files) {
1544
- const destination = path7.join(root, file.path);
1545
- await mkdir4(path7.dirname(destination), { recursive: true });
1546
- await writeFile3(destination, file.content, "utf8");
2620
+ const destination = path10.join(root, file.path);
2621
+ await mkdir6(path10.dirname(destination), { recursive: true });
2622
+ await writeFile4(destination, file.content, "utf8");
1547
2623
  }
1548
2624
  return {
1549
2625
  ...plan,
@@ -1555,6 +2631,10 @@ async function writeDump(graph, options) {
1555
2631
  function flattenObject(value, prefix = "") {
1556
2632
  return Object.entries(value).reduce((accumulator, [key, nestedValue]) => {
1557
2633
  const nextKey = prefix ? `${prefix}.${key}` : key;
2634
+ if (isDerivedValue(nestedValue) || isSecretReference(nestedValue)) {
2635
+ accumulator[nextKey] = nestedValue;
2636
+ return accumulator;
2637
+ }
1558
2638
  if (nestedValue && typeof nestedValue === "object" && !Array.isArray(nestedValue)) {
1559
2639
  Object.assign(accumulator, flattenObject(nestedValue, nextKey));
1560
2640
  return accumulator;
@@ -1574,11 +2654,11 @@ function normalizeMappingConfig(config = {}) {
1574
2654
  function toScreamingSnakeSegment(segment) {
1575
2655
  return segment.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/[^A-Za-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "").toUpperCase();
1576
2656
  }
1577
- function toScreamingSnake(path11) {
1578
- return path11.split(".").map((segment) => toScreamingSnakeSegment(segment)).filter(Boolean).join("_");
2657
+ function toScreamingSnake(path14) {
2658
+ return path14.split(".").map((segment) => toScreamingSnakeSegment(segment)).filter(Boolean).join("_");
1579
2659
  }
1580
- function fromScreamingSnake(path11) {
1581
- return path11.split("_").map((segment) => segment.trim().toLowerCase()).filter(Boolean).join(".");
2660
+ function fromScreamingSnake(path14) {
2661
+ return path14.split("_").map((segment) => segment.trim().toLowerCase()).filter(Boolean).join(".");
1582
2662
  }
1583
2663
  function logicalKeyToEnvVar(key, config = {}) {
1584
2664
  const normalized = normalizeMappingConfig(config);
@@ -1730,12 +2810,12 @@ function createProvenanceInspector() {
1730
2810
  }
1731
2811
 
1732
2812
  // ../core/src/manifest/loadWorkspaceFile.ts
1733
- import { readFile as readFile5 } from "fs/promises";
1734
- import path8 from "path";
2813
+ import { readFile as readFile6 } from "fs/promises";
2814
+ import path11 from "path";
1735
2815
  async function loadWorkspaceFile(repoRoot) {
1736
- const workspaceFilePath = path8.join(repoRoot, ".cnos-workspace.yml");
2816
+ const workspaceFilePath = path11.join(repoRoot, ".cnos-workspace.yml");
1737
2817
  try {
1738
- const source = await readFile5(workspaceFilePath, "utf8");
2818
+ const source = await readFile6(workspaceFilePath, "utf8");
1739
2819
  const parsed = parseYaml(source);
1740
2820
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1741
2821
  throw new CnosManifestError(".cnos-workspace.yml must be a YAML object", workspaceFilePath);
@@ -1758,11 +2838,11 @@ async function loadWorkspaceFile(repoRoot) {
1758
2838
  }
1759
2839
 
1760
2840
  // ../core/src/profiles/expandProfileChain.ts
1761
- import { access as access3, readFile as readFile6 } from "fs/promises";
1762
- import path9 from "path";
2841
+ import { access as access4, readFile as readFile7 } from "fs/promises";
2842
+ import path12 from "path";
1763
2843
  async function fileExists(targetPath) {
1764
2844
  try {
1765
- await access3(targetPath);
2845
+ await access4(targetPath);
1766
2846
  return true;
1767
2847
  } catch {
1768
2848
  return false;
@@ -1796,11 +2876,11 @@ async function loadProfileDefinition(profileName, options) {
1796
2876
  return normalizeProfileDefinition(profileName, void 0);
1797
2877
  }
1798
2878
  for (const workspaceRoot of [...workspaceRoots].reverse()) {
1799
- const profilePath = path9.join(workspaceRoot.path, "profiles", `${profileName}.yml`);
2879
+ const profilePath = path12.join(workspaceRoot.path, "profiles", `${profileName}.yml`);
1800
2880
  if (!await fileExists(profilePath)) {
1801
2881
  continue;
1802
2882
  }
1803
- const document = await readFile6(profilePath, "utf8");
2883
+ const document = await readFile7(profilePath, "utf8");
1804
2884
  const parsed = parseYaml(document);
1805
2885
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1806
2886
  throw new CnosManifestError("Profile definition must be a YAML object", profilePath);
@@ -1808,7 +2888,7 @@ async function loadProfileDefinition(profileName, options) {
1808
2888
  const definition = normalizeProfileDefinition(
1809
2889
  profileName,
1810
2890
  parsed,
1811
- options.manifestRoot ? toPortablePath(path9.relative(path9.dirname(options.manifestRoot), profilePath)) : toPortablePath(profilePath)
2891
+ options.manifestRoot ? toPortablePath(path12.relative(path12.dirname(options.manifestRoot), profilePath)) : toPortablePath(profilePath)
1812
2892
  );
1813
2893
  if (definition.name !== profileName) {
1814
2894
  throw new CnosManifestError(
@@ -2054,8 +3134,8 @@ function createProfileAwareResolver() {
2054
3134
  }
2055
3135
 
2056
3136
  // ../core/src/workspaces/resolveWorkspaceContext.ts
2057
- import { access as access4 } from "fs/promises";
2058
- import path10 from "path";
3137
+ import { access as access5 } from "fs/promises";
3138
+ import path13 from "path";
2059
3139
 
2060
3140
  // ../core/src/workspaces/expandWorkspaceChain.ts
2061
3141
  function expandWorkspaceChain(workspaceId, items) {
@@ -2094,14 +3174,14 @@ function expandWorkspaceChain(workspaceId, items) {
2094
3174
  // ../core/src/workspaces/resolveWorkspaceContext.ts
2095
3175
  async function exists4(targetPath) {
2096
3176
  try {
2097
- await access4(targetPath);
3177
+ await access5(targetPath);
2098
3178
  return true;
2099
3179
  } catch {
2100
3180
  return false;
2101
3181
  }
2102
3182
  }
2103
3183
  async function resolveLocalWorkspaceRoot(manifestRoot, workspaceId, manifest) {
2104
- const workspaceRoot = path10.join(manifestRoot, "workspaces", workspaceId);
3184
+ const workspaceRoot = path13.join(manifestRoot, "workspaces", workspaceId);
2105
3185
  if (await exists4(workspaceRoot)) {
2106
3186
  return workspaceRoot;
2107
3187
  }
@@ -2109,7 +3189,7 @@ async function resolveLocalWorkspaceRoot(manifestRoot, workspaceId, manifest) {
2109
3189
  ([namespace, definition]) => namespace !== "value" && namespace !== "secret" && definition.kind === "data" && !definition.sensitive
2110
3190
  ).map(([namespace]) => namespace);
2111
3191
  const legacyMarkers = ["values", "secrets", "env", "profiles", ...customDataNamespaceRoots].map(
2112
- (segment) => path10.join(manifestRoot, segment)
3192
+ (segment) => path13.join(manifestRoot, segment)
2113
3193
  );
2114
3194
  if ((await Promise.all(legacyMarkers.map((marker) => exists4(marker)))).some(Boolean)) {
2115
3195
  return manifestRoot;
@@ -2157,26 +3237,26 @@ function resolveGlobalRoot(manifest, workspaceFile, options) {
2157
3237
  }
2158
3238
  if (options.globalRoot) {
2159
3239
  return {
2160
- value: path10.resolve(expandHomePath(options.globalRoot)),
3240
+ value: path13.resolve(expandHomePath2(options.globalRoot)),
2161
3241
  source: "cli"
2162
3242
  };
2163
3243
  }
2164
3244
  if (workspaceFile?.globalRoot) {
2165
3245
  return {
2166
- value: path10.resolve(expandHomePath(workspaceFile.globalRoot)),
3246
+ value: path13.resolve(expandHomePath2(workspaceFile.globalRoot)),
2167
3247
  source: "workspace-file"
2168
3248
  };
2169
3249
  }
2170
3250
  if (manifest.workspaces.global.root) {
2171
3251
  return {
2172
- value: path10.resolve(expandHomePath(manifest.workspaces.global.root)),
3252
+ value: path13.resolve(expandHomePath2(manifest.workspaces.global.root)),
2173
3253
  source: "manifest"
2174
3254
  };
2175
3255
  }
2176
3256
  const cnosHome = options.processEnv?.CNOS_HOME;
2177
3257
  if (cnosHome) {
2178
3258
  return {
2179
- value: path10.resolve(expandHomePath(cnosHome)),
3259
+ value: path13.resolve(expandHomePath2(cnosHome)),
2180
3260
  source: "CNOS_HOME"
2181
3261
  };
2182
3262
  }
@@ -2198,7 +3278,7 @@ async function resolveWorkspaceContext(manifest, options) {
2198
3278
  workspaceRoots.push({
2199
3279
  scope: "global",
2200
3280
  workspaceId: chainWorkspaceId,
2201
- path: path10.join(globalRoot.value, "workspaces", globalWorkspaceId)
3281
+ path: path13.join(globalRoot.value, "workspaces", globalWorkspaceId)
2202
3282
  });
2203
3283
  }
2204
3284
  }
@@ -2321,6 +3401,10 @@ function applySchemaRules(graph, schema) {
2321
3401
  }
2322
3402
  continue;
2323
3403
  }
3404
+ if (isDerivedValue(resolvedEntry.value)) {
3405
+ nextEntries.set(key, resolvedEntry);
3406
+ continue;
3407
+ }
2324
3408
  const coercedValue = coerceValue(resolvedEntry.value, rule);
2325
3409
  const nextResolvedEntry = coercedValue === resolvedEntry.value ? resolvedEntry : {
2326
3410
  ...resolvedEntry,
@@ -2467,7 +3551,7 @@ function resolveSecretEntryValue(key, value, cache) {
2467
3551
  }
2468
3552
 
2469
3553
  // ../core/src/runtime/toServerProjection.ts
2470
- import { createHash } from "crypto";
3554
+ import { createHash as createHash2 } from "crypto";
2471
3555
  function stableSortObject(value) {
2472
3556
  return Object.fromEntries(Object.entries(value).sort(([left], [right]) => left.localeCompare(right)));
2473
3557
  }
@@ -2476,12 +3560,14 @@ function stripValuePrefix(key) {
2476
3560
  }
2477
3561
  function configHash(values) {
2478
3562
  const serialized = JSON.stringify(stableSortObject(values));
2479
- return createHash("sha256").update(serialized).digest("hex");
3563
+ return createHash2("sha256").update(serialized).digest("hex");
2480
3564
  }
2481
- function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
3565
+ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev", helpers = {}) {
2482
3566
  const values = {};
3567
+ const derived = {};
2483
3568
  const secretRefs = {};
2484
3569
  const namespaces = /* @__PURE__ */ new Set();
3570
+ const runtimeNamespaces = /* @__PURE__ */ new Set();
2485
3571
  const publicKeys = Array.from(graph.entries.values()).filter((entry) => entry.namespace === "public").map((entry) => entry.key.slice("public.".length)).sort((left, right) => left.localeCompare(right));
2486
3572
  for (const [key, entry] of graph.entries) {
2487
3573
  if (entry.namespace === "secret" && isSecretReference(entry.value)) {
@@ -2493,12 +3579,33 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
2493
3579
  continue;
2494
3580
  }
2495
3581
  if (entry.namespace === "value") {
2496
- values[stripValuePrefix(key)] = entry.value;
3582
+ if (helpers.isRuntimeDependent?.(key)) {
3583
+ const formula = helpers.toServerFormula?.(key);
3584
+ if (formula) {
3585
+ derived[stripValuePrefix(key)] = formula;
3586
+ for (const ref of formula.runtimeRefs) {
3587
+ runtimeNamespaces.add(ref.split(".")[0] ?? "");
3588
+ }
3589
+ }
3590
+ continue;
3591
+ }
3592
+ const value = helpers.read ? helpers.read(key) : entry.value;
3593
+ values[stripValuePrefix(key)] = value;
2497
3594
  continue;
2498
3595
  }
2499
3596
  const namespaceDefinition = manifest.namespaces[entry.namespace];
2500
3597
  if (namespaceDefinition && namespaceDefinition.kind === "data" && !namespaceDefinition.sensitive && entry.namespace !== "public") {
2501
- values[key] = entry.value;
3598
+ if (helpers.isRuntimeDependent?.(key)) {
3599
+ const formula = helpers.toServerFormula?.(key);
3600
+ if (formula) {
3601
+ derived[key] = formula;
3602
+ for (const ref of formula.runtimeRefs) {
3603
+ runtimeNamespaces.add(ref.split(".")[0] ?? "");
3604
+ }
3605
+ }
3606
+ continue;
3607
+ }
3608
+ values[key] = helpers.read ? helpers.read(key) : entry.value;
2502
3609
  namespaces.add(entry.namespace);
2503
3610
  }
2504
3611
  }
@@ -2509,8 +3616,10 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
2509
3616
  resolvedAt: graph.resolvedAt,
2510
3617
  configHash: configHash(values),
2511
3618
  values: stableSortObject(values),
3619
+ derived: stableSortObject(derived),
2512
3620
  secretRefs: stableSortObject(secretRefs),
2513
3621
  publicKeys,
3622
+ runtimeNamespaces: Array.from(runtimeNamespaces).sort((left, right) => left.localeCompare(right)),
2514
3623
  meta: {
2515
3624
  workspace: graph.workspace.workspaceId,
2516
3625
  profile: graph.profile,
@@ -2522,6 +3631,19 @@ function toServerProjection(graph, manifest, cnosVersion = "0.0.0-dev") {
2522
3631
 
2523
3632
  // ../core/src/orchestrator/runtime.ts
2524
3633
  function createRuntime(manifest, graph, plugins = [], secretCache, processEnv = process.env, cnosVersion = "0.0.0-dev") {
3634
+ const runtimeProviders = createDefaultRuntimeProviders(manifest, processEnv);
3635
+ const derivedSupport = createDerivedRuntimeSupport(graph, manifest, runtimeProviders);
3636
+ function resolveProjectedSourceKey(key) {
3637
+ if (!key.startsWith("public.")) {
3638
+ return key;
3639
+ }
3640
+ const promotedFrom = graph.entries.get(key)?.winner.metadata?.promotedFrom;
3641
+ if (typeof promotedFrom === "string") {
3642
+ return promotedFrom;
3643
+ }
3644
+ const fallback = `value.${key.slice("public.".length)}`;
3645
+ return graph.entries.has(fallback) ? fallback : key;
3646
+ }
2525
3647
  async function refreshSecretEntry(key) {
2526
3648
  const entry = graph.entries.get(key);
2527
3649
  if (!entry || entry.namespace !== "secret" || !isSecretReference(entry.value)) {
@@ -2553,6 +3675,19 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
2553
3675
  }
2554
3676
  }
2555
3677
  function readLogicalKey(key) {
3678
+ const resolved = derivedSupport.read(key, (ref) => {
3679
+ const entry2 = graph.entries.get(ref);
3680
+ if (!entry2) {
3681
+ return void 0;
3682
+ }
3683
+ if (!secretCache) {
3684
+ return entry2.value;
3685
+ }
3686
+ return resolveSecretEntryValue(ref, entry2.value, secretCache);
3687
+ });
3688
+ if (resolved !== void 0 || graph.entries.has(key) || manifest.runtimeNamespaces[key.split(".")[0] ?? ""]) {
3689
+ return resolved;
3690
+ }
2556
3691
  const entry = graph.entries.get(key);
2557
3692
  if (!entry) {
2558
3693
  return void 0;
@@ -2577,34 +3712,64 @@ function createRuntime(manifest, graph, plugins = [], secretCache, processEnv =
2577
3712
  return value;
2578
3713
  },
2579
3714
  readOr(key, fallback) {
2580
- return readOrValue(graph, key, fallback);
3715
+ const value = readLogicalKey(key);
3716
+ return value === void 0 ? fallback : value;
2581
3717
  },
2582
- value(path11) {
2583
- return readLogicalKey(toLogicalKey("value", path11));
3718
+ value(path14) {
3719
+ return readLogicalKey(toLogicalKey("value", path14));
2584
3720
  },
2585
- secret(path11) {
2586
- return readLogicalKey(toLogicalKey("secret", path11));
3721
+ secret(path14) {
3722
+ return readLogicalKey(toLogicalKey("secret", path14));
2587
3723
  },
2588
- meta(path11) {
2589
- return readLogicalKey(toLogicalKey("meta", path11));
3724
+ meta(path14) {
3725
+ return readLogicalKey(toLogicalKey("meta", path14));
2590
3726
  },
2591
3727
  inspect(key) {
2592
- return inspectValue(graph, key);
3728
+ return inspectValue(graph, key, {
3729
+ read: (ref) => readLogicalKey(ref),
3730
+ describeDerived: (ref) => derivedSupport.describe(ref, (candidate) => {
3731
+ const entry = graph.entries.get(candidate);
3732
+ if (!entry) {
3733
+ return void 0;
3734
+ }
3735
+ if (!secretCache) {
3736
+ return entry.value;
3737
+ }
3738
+ return resolveSecretEntryValue(candidate, entry.value, secretCache);
3739
+ })
3740
+ });
2593
3741
  },
2594
3742
  toObject() {
2595
- return toNamespaceObject(graph);
3743
+ return toNamespaceObject(graph, void 0, (key) => readLogicalKey(key));
2596
3744
  },
2597
3745
  toNamespace(namespace) {
2598
- return toNamespaceObject(graph, namespace);
3746
+ return toNamespaceObject(graph, namespace, (key) => readLogicalKey(key));
2599
3747
  },
2600
3748
  toEnv(options) {
2601
- return toEnv(graph, manifest, options);
3749
+ return toEnv(graph, manifest, options, {
3750
+ read: (key) => readLogicalKey(key),
3751
+ isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(key)
3752
+ });
2602
3753
  },
2603
3754
  toPublicEnv(options) {
2604
- return toPublicEnv(graph, manifest, options);
3755
+ return toPublicEnv(graph, manifest, options, {
3756
+ read: (key) => derivedSupport.toConcreteValue(
3757
+ resolveProjectedSourceKey(key),
3758
+ (candidate) => readLogicalKey(candidate),
3759
+ "public"
3760
+ ),
3761
+ isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(resolveProjectedSourceKey(key))
3762
+ });
2605
3763
  },
2606
3764
  toServerProjection() {
2607
- return toServerProjection(graph, manifest, cnosVersion);
3765
+ return toServerProjection(graph, manifest, cnosVersion, {
3766
+ read: (key) => derivedSupport.toConcreteValue(key, (candidate) => readLogicalKey(candidate), "server"),
3767
+ isRuntimeDependent: (key) => derivedSupport.isRuntimeDependentKey(key),
3768
+ toServerFormula: (key) => derivedSupport.toServerFormula(key)
3769
+ });
3770
+ },
3771
+ registerRuntimeProvider(namespace, provider) {
3772
+ registerRuntimeProvider(manifest, runtimeProviders, namespace, provider);
2608
3773
  },
2609
3774
  async refreshSecrets() {
2610
3775
  await refreshAllSecrets();
@@ -2711,7 +3876,11 @@ function appendMetaEntries(graph, cnosVersion) {
2711
3876
  async function createCnos(options = {}) {
2712
3877
  const loadedManifest = await loadManifest({
2713
3878
  ...options.root ? { root: options.root } : {},
2714
- ...options.cwd ? { cwd: options.cwd } : {}
3879
+ ...options.cwd ? { cwd: options.cwd } : {},
3880
+ ...options.processEnv ? { processEnv: options.processEnv } : {},
3881
+ ...options.cacheMode ? { cacheMode: options.cacheMode } : {},
3882
+ ...typeof options.cacheTtlSeconds === "number" ? { cacheTtlSeconds: options.cacheTtlSeconds } : {},
3883
+ ...options.forceRefresh ? { forceRefresh: true } : {}
2715
3884
  });
2716
3885
  for (const key of loadedManifest.manifest.public.promote) {
2717
3886
  ensureProjectionAllowed(loadedManifest.manifest, key, "public");
@@ -2775,12 +3944,27 @@ export {
2775
3944
  CnosManifestError,
2776
3945
  CnosSecurityError,
2777
3946
  CnosAuthenticationError,
3947
+ isDerivedValue,
3948
+ parseDerivation,
3949
+ validateDerivedTargetNamespace,
3950
+ validateParsedDerivation,
3951
+ normalizeDerivedValue,
3952
+ createDerivedRuntimeSupport,
3953
+ registerRuntimeProvider,
2778
3954
  inspectValue,
2779
3955
  createProvenanceInspector,
2780
3956
  readKeychain,
2781
3957
  writeKeychain,
2782
3958
  parseYaml,
2783
3959
  stringifyYaml,
3960
+ parseGitUri,
3961
+ isImmutableGitRef,
3962
+ readRemoteRootCacheMetadata,
3963
+ writeRemoteRootCacheMetadata,
3964
+ resolveCnosCacheRoot,
3965
+ createRemoteRootCacheKey,
3966
+ resolveRemoteRootCachePaths,
3967
+ resolveRootUri,
2784
3968
  resolveManifestRoot,
2785
3969
  resolveWorkspaceScopedPath,
2786
3970
  resolveConfigDocumentPath,
@@ -2818,8 +4002,8 @@ export {
2818
4002
  resolveVaultAuth,
2819
4003
  toNamespaceObject,
2820
4004
  readValue,
2821
- readOrValue,
2822
4005
  requireValue,
4006
+ createDefaultRuntimeProviders,
2823
4007
  toEnv,
2824
4008
  toPublicEnv,
2825
4009
  createCnos,