@telorun/kernel 0.59.0 → 0.61.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 (120) hide show
  1. package/dist/bundle/files-integrity.d.ts +21 -12
  2. package/dist/bundle/files-integrity.d.ts.map +1 -1
  3. package/dist/bundle/files-integrity.js +27 -14
  4. package/dist/bundle/files-integrity.js.map +1 -1
  5. package/dist/bundle/module-artifact.d.ts +134 -0
  6. package/dist/bundle/module-artifact.d.ts.map +1 -0
  7. package/dist/bundle/module-artifact.js +300 -0
  8. package/dist/bundle/module-artifact.js.map +1 -0
  9. package/dist/bundle/module-manifest.d.ts +12 -4
  10. package/dist/bundle/module-manifest.d.ts.map +1 -1
  11. package/dist/bundle/module-manifest.js +8 -4
  12. package/dist/bundle/module-manifest.js.map +1 -1
  13. package/dist/controller-loader.d.ts +3 -2
  14. package/dist/controller-loader.d.ts.map +1 -1
  15. package/dist/controller-loader.js +8 -8
  16. package/dist/controller-loader.js.map +1 -1
  17. package/dist/controller-loaders/bundle-loader.d.ts +8 -6
  18. package/dist/controller-loaders/bundle-loader.d.ts.map +1 -1
  19. package/dist/controller-loaders/bundle-loader.js +52 -13
  20. package/dist/controller-loaders/bundle-loader.js.map +1 -1
  21. package/dist/controller-loaders/npm-loader.d.ts +0 -18
  22. package/dist/controller-loaders/npm-loader.d.ts.map +1 -1
  23. package/dist/controller-loaders/npm-loader.js +3 -190
  24. package/dist/controller-loaders/npm-loader.js.map +1 -1
  25. package/dist/controllers/resource-definition/resource-definition-controller.d.ts.map +1 -1
  26. package/dist/controllers/resource-definition/resource-definition-controller.js +6 -1
  27. package/dist/controllers/resource-definition/resource-definition-controller.js.map +1 -1
  28. package/dist/controllers/resource-definition/resource-inherited-controller.d.ts.map +1 -1
  29. package/dist/controllers/resource-definition/resource-inherited-controller.js +57 -10
  30. package/dist/controllers/resource-definition/resource-inherited-controller.js.map +1 -1
  31. package/dist/controllers/type/json-schema-controller.d.ts +8 -0
  32. package/dist/controllers/type/json-schema-controller.d.ts.map +1 -0
  33. package/dist/controllers/type/json-schema-controller.js +91 -0
  34. package/dist/controllers/type/json-schema-controller.js.map +1 -0
  35. package/dist/directory-lock.d.ts +27 -0
  36. package/dist/directory-lock.d.ts.map +1 -0
  37. package/dist/directory-lock.js +205 -0
  38. package/dist/directory-lock.js.map +1 -0
  39. package/dist/evaluation-context.d.ts +5 -0
  40. package/dist/evaluation-context.d.ts.map +1 -1
  41. package/dist/evaluation-context.js +63 -33
  42. package/dist/evaluation-context.js.map +1 -1
  43. package/dist/index.d.ts +5 -2
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +4 -1
  46. package/dist/index.js.map +1 -1
  47. package/dist/init-failure-diagnostics.d.ts +61 -0
  48. package/dist/init-failure-diagnostics.d.ts.map +1 -0
  49. package/dist/init-failure-diagnostics.js +141 -0
  50. package/dist/init-failure-diagnostics.js.map +1 -0
  51. package/dist/invocation-contract-binding.d.ts +105 -0
  52. package/dist/invocation-contract-binding.d.ts.map +1 -0
  53. package/dist/invocation-contract-binding.js +296 -0
  54. package/dist/invocation-contract-binding.js.map +1 -0
  55. package/dist/kernel.d.ts +49 -0
  56. package/dist/kernel.d.ts.map +1 -1
  57. package/dist/kernel.js +117 -6
  58. package/dist/kernel.js.map +1 -1
  59. package/dist/manifest-sources/local-manifest-cache-source.d.ts +1 -1
  60. package/dist/manifest-sources/local-manifest-cache-source.d.ts.map +1 -1
  61. package/dist/manifest-sources/local-manifest-cache-source.js +1 -1
  62. package/dist/manifest-sources/local-manifest-cache-source.js.map +1 -1
  63. package/dist/module-context.d.ts.map +1 -1
  64. package/dist/module-context.js +21 -0
  65. package/dist/module-context.js.map +1 -1
  66. package/dist/resource-context.d.ts +61 -0
  67. package/dist/resource-context.d.ts.map +1 -1
  68. package/dist/resource-context.js +131 -0
  69. package/dist/resource-context.js.map +1 -1
  70. package/dist/schema-compiled-values.d.ts +9 -1
  71. package/dist/schema-compiled-values.d.ts.map +1 -1
  72. package/dist/schema-compiled-values.js +55 -16
  73. package/dist/schema-compiled-values.js.map +1 -1
  74. package/dist/schema-validator.d.ts.map +1 -1
  75. package/dist/schema-validator.js +15 -1
  76. package/dist/schema-validator.js.map +1 -1
  77. package/dist/transports/oci/oci-client.d.ts +28 -1
  78. package/dist/transports/oci/oci-client.d.ts.map +1 -1
  79. package/dist/transports/oci/oci-client.js +24 -1
  80. package/dist/transports/oci/oci-client.js.map +1 -1
  81. package/dist/transports/oci/oci-transport.d.ts +20 -14
  82. package/dist/transports/oci/oci-transport.d.ts.map +1 -1
  83. package/dist/transports/oci/oci-transport.js +105 -46
  84. package/dist/transports/oci/oci-transport.js.map +1 -1
  85. package/dist/transports/registry-transport.d.ts +7 -2
  86. package/dist/transports/registry-transport.d.ts.map +1 -1
  87. package/dist/transports/registry-transport.js +8 -33
  88. package/dist/transports/registry-transport.js.map +1 -1
  89. package/dist/transports/transport-registry.d.ts +5 -4
  90. package/dist/transports/transport-registry.d.ts.map +1 -1
  91. package/dist/transports/transport-registry.js +4 -4
  92. package/dist/transports/transport-registry.js.map +1 -1
  93. package/dist/transports/transport.d.ts +27 -19
  94. package/dist/transports/transport.d.ts.map +1 -1
  95. package/package.json +3 -3
  96. package/src/bundle/files-integrity.ts +34 -14
  97. package/src/bundle/module-artifact.ts +375 -0
  98. package/src/bundle/module-manifest.ts +22 -6
  99. package/src/controller-loader.ts +9 -4
  100. package/src/controller-loaders/bundle-loader.ts +57 -11
  101. package/src/controller-loaders/npm-loader.ts +3 -209
  102. package/src/controllers/resource-definition/resource-definition-controller.ts +19 -0
  103. package/src/controllers/resource-definition/resource-inherited-controller.ts +69 -10
  104. package/src/controllers/type/json-schema-controller.ts +114 -0
  105. package/src/directory-lock.ts +225 -0
  106. package/src/evaluation-context.ts +81 -32
  107. package/src/index.ts +11 -2
  108. package/src/init-failure-diagnostics.ts +169 -0
  109. package/src/invocation-contract-binding.ts +392 -0
  110. package/src/kernel.ts +149 -6
  111. package/src/manifest-sources/local-manifest-cache-source.ts +1 -1
  112. package/src/module-context.ts +27 -0
  113. package/src/resource-context.ts +138 -0
  114. package/src/schema-compiled-values.ts +55 -15
  115. package/src/schema-validator.ts +15 -1
  116. package/src/transports/oci/oci-client.ts +32 -1
  117. package/src/transports/oci/oci-transport.ts +122 -51
  118. package/src/transports/registry-transport.ts +10 -38
  119. package/src/transports/transport-registry.ts +5 -5
  120. package/src/transports/transport.ts +32 -19
@@ -0,0 +1,205 @@
1
+ import { NOOP_LOGGER } from "@telorun/sdk";
2
+ import * as fs from "fs/promises";
3
+ import * as os from "os";
4
+ import * as path from "path";
5
+ /**
6
+ * The cross-process lock guarding mutation of a shared cache directory.
7
+ *
8
+ * Two consumers hold it for the same reason — several Telo processes (and, in
9
+ * one process, several concurrent resolutions) may decide to populate the same
10
+ * directory at the same moment: `NpmControllerLoader` around its install root,
11
+ * and `ModuleArtifact` around a module's extracted layers. One implementation
12
+ * rather than two, because the reclaim rule below is subtle enough that two
13
+ * copies would drift.
14
+ */
15
+ /**
16
+ * A held lock is refreshed (its mtime bumped) every {@link LOCK_HEARTBEAT_MS}
17
+ * by the holder. Staleness is judged purely by mtime age — a lock older than
18
+ * this means the holder stopped heartbeating (crashed, was killed, or its
19
+ * container vanished), so it is safe to reclaim. This deliberately does NOT
20
+ * probe the recorded PID for liveness: PID identity is meaningless across
21
+ * container restarts and PID namespaces (deterministic PID reuse makes an
22
+ * unrelated process look like the dead holder on the same hostname), which is
23
+ * exactly what deadlocked container boots. The `{pid, host}` in the lock body
24
+ * is diagnostics for humans, never a reclaim signal. Must be comfortably
25
+ * larger than the heartbeat interval so a briefly-descheduled holder (GC
26
+ * pause, busy event loop) is not reclaimed out from under itself.
27
+ */
28
+ const LOCK_STALE_MS = 30000;
29
+ /** How often the holder refreshes the lock mtime while `fn` runs. Well under
30
+ * {@link LOCK_STALE_MS} so several heartbeats are missed before a live holder
31
+ * is ever judged stale. */
32
+ const LOCK_HEARTBEAT_MS = 5000;
33
+ /**
34
+ * Total wall-clock cap for waiting on the lock — enough for a slow first
35
+ * populate on a peer process to finish, short enough that a genuinely
36
+ * deadlocked CI job fails loudly rather than hanging for hours. The retry
37
+ * interval trades wakeup latency vs. wasted polls; 500ms is well below the
38
+ * lock holder's typical hold time.
39
+ */
40
+ const LOCK_WAIT_MAX_MS = 5 * 60000;
41
+ const LOCK_RETRY_MS = 500;
42
+ /** After this long waiting on a lock, emit one line so a slow wait is visible
43
+ * instead of looking like a silent hang. */
44
+ const LOCK_WAIT_NOTICE_MS = 2000;
45
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
46
+ /**
47
+ * In-process serialization ahead of the filesystem lock.
48
+ *
49
+ * Without it, N concurrent callers for the same directory all reach the fs lock,
50
+ * N-1 sit in the retry loop, and each crossing {@link LOCK_WAIT_NOTICE_MS}
51
+ * prints the wait notice — a notice whose whole point is "another *process* is
52
+ * populating this", printed when the holder is us. (`telo install` fanning 52
53
+ * controllers out through one `Promise.allSettled` printed 51 of them.)
54
+ *
55
+ * Queuing here means exactly one caller per process reaches the fs lock, so the
56
+ * notice regains its cross-process meaning and the losers do no I/O at all. The
57
+ * fs lock is untouched and still provides the cross-process guarantee.
58
+ */
59
+ const localQueues = new Map();
60
+ function withLocalQueue(dir, fn) {
61
+ const prev = localQueues.get(dir) ?? Promise.resolve();
62
+ // Run on both settle paths: one failure must not wedge the queue.
63
+ const run = prev.then(fn, fn);
64
+ // The stored tail never rejects — a failure neither poisons followers nor
65
+ // surfaces as an unhandled rejection on the chain copy.
66
+ const tail = run.then(() => { }, () => { });
67
+ localQueues.set(dir, tail);
68
+ // Drop the entry once nothing further is queued, so a long-lived process that
69
+ // touches many directories doesn't retain a promise per directory forever.
70
+ void tail.then(() => {
71
+ if (localQueues.get(dir) === tail)
72
+ localQueues.delete(dir);
73
+ });
74
+ return run;
75
+ }
76
+ /**
77
+ * Acquire the lock for `dir` and run `fn` under it: first the in-process queue
78
+ * above, then the cross-process filesystem lock. `label` names the operation in
79
+ * the wait notice and timeout error (e.g. "controller install", "module layer").
80
+ */
81
+ export async function withDirectoryLock(dir, label, fn, log = NOOP_LOGGER) {
82
+ return withLocalQueue(dir, () => withFileLock(dir, label, fn, log));
83
+ }
84
+ /**
85
+ * Acquire a process-portable lock on `<dir>/.lock` and execute fn while
86
+ * holding it. `fs.open(path, 'wx')` is atomic on POSIX and Windows, so
87
+ * concurrent processes serialize naturally.
88
+ *
89
+ * Liveness is a heartbeat: the holder bumps the lock's mtime every
90
+ * {@link LOCK_HEARTBEAT_MS} while `fn` runs, and a waiter reclaims a lock whose
91
+ * mtime is older than {@link LOCK_STALE_MS} (holder crashed/killed/vanished).
92
+ * mtime age is the *only* reclaim signal — the recorded `{pid, host}` is
93
+ * diagnostics, never probed for liveness, because PID identity is unreliable
94
+ * across container restarts and PID namespaces (the failure that deadlocked
95
+ * container boots). Reclaim is via atomic rename to a unique tombstone so two
96
+ * waiters that both see the lock stale can't both win.
97
+ *
98
+ * The lock guards *writes* into the directory. It does NOT serialize reads of
99
+ * already-populated content — those run lock-free against a stable tree.
100
+ */
101
+ async function withFileLock(dir, label, fn, log) {
102
+ const lockPath = path.join(dir, ".lock");
103
+ await fs.mkdir(dir, { recursive: true });
104
+ const lockBody = JSON.stringify({ pid: process.pid, host: os.hostname(), startedAt: Date.now() });
105
+ let handle = null;
106
+ const waitedSince = Date.now();
107
+ let noticed = false;
108
+ while (true) {
109
+ try {
110
+ handle = await fs.open(lockPath, "wx");
111
+ await handle.writeFile(lockBody);
112
+ break;
113
+ }
114
+ catch (err) {
115
+ if (err?.code !== "EEXIST")
116
+ throw err;
117
+ // Lock exists. Reclaim it only if its heartbeat has gone silent.
118
+ if (await reclaimIfStale(lockPath))
119
+ continue;
120
+ const waited = Date.now() - waitedSince;
121
+ if (waited > LOCK_WAIT_MAX_MS) {
122
+ throw new Error(`[telo] timed out waiting for ${label} lock at ${lockPath} ` +
123
+ `(held >${LOCK_WAIT_MAX_MS / 60000} min with a live heartbeat). ` +
124
+ `Inspect the lock file or remove it manually if no other Telo process is running.`);
125
+ }
126
+ if (!noticed && waited > LOCK_WAIT_NOTICE_MS) {
127
+ noticed = true;
128
+ log.info(`waiting for ${label} lock`, { "telo.lock.path": lockPath });
129
+ }
130
+ await sleep(LOCK_RETRY_MS);
131
+ }
132
+ }
133
+ // Keep the lock fresh while `fn` runs so a slow-but-live operation is never
134
+ // reclaimed. `unref` so the heartbeat can't by itself keep the process alive.
135
+ const heartbeat = setInterval(() => {
136
+ const now = new Date();
137
+ fs.utimes(lockPath, now, now).catch(() => { });
138
+ }, LOCK_HEARTBEAT_MS);
139
+ heartbeat.unref?.();
140
+ try {
141
+ return await fn();
142
+ }
143
+ finally {
144
+ clearInterval(heartbeat);
145
+ // The fd close races nothing important: if it fails, the FD is reaped on
146
+ // process exit. The unlink is the dangerous one — a non-ENOENT failure
147
+ // (permissions, read-only mount) means every subsequent kernel waits
148
+ // LOCK_STALE_MS before reclaiming. Surface it so the cause is visible
149
+ // rather than hiding behind a silent hang.
150
+ await handle.close().catch(() => { });
151
+ try {
152
+ await fs.rm(lockPath, { force: true });
153
+ }
154
+ catch (err) {
155
+ if (err?.code !== "ENOENT") {
156
+ log.warn(`failed to release ${label} lock`, { "telo.lock.path": lockPath }, { error: err });
157
+ }
158
+ }
159
+ }
160
+ }
161
+ /**
162
+ * If the lock at `lockPath` is stale (mtime older than {@link LOCK_STALE_MS}, so
163
+ * its holder stopped heartbeating), atomically claim and remove it and return
164
+ * true; otherwise return false. The claim is a `rename` to a unique tombstone:
165
+ * `rename` is atomic and fails for all but one racer, so two processes that
166
+ * both observe the same stale lock cannot both reclaim it — the loser's rename
167
+ * throws ENOENT (the file is already gone) and it simply retries the open.
168
+ */
169
+ async function reclaimIfStale(lockPath) {
170
+ let stat;
171
+ try {
172
+ stat = await fs.stat(lockPath);
173
+ }
174
+ catch (err) {
175
+ // Race: lock vanished while we inspected it. Retry the open immediately.
176
+ if (err?.code === "ENOENT")
177
+ return true;
178
+ throw err;
179
+ }
180
+ if (Date.now() - stat.mtimeMs < LOCK_STALE_MS)
181
+ return false;
182
+ // Stale — the holder's heartbeat is silent. Claim via atomic rename; only one
183
+ // racer wins, the rest get ENOENT and fall back to retrying the open.
184
+ const tombstone = `${lockPath}.stale.${process.pid}.${stat.mtimeMs}`;
185
+ try {
186
+ await fs.rename(lockPath, tombstone);
187
+ }
188
+ catch (err) {
189
+ if (err?.code === "ENOENT")
190
+ return true; // another waiter reclaimed it first
191
+ throw err;
192
+ }
193
+ await fs.rm(tombstone, { force: true });
194
+ return true;
195
+ }
196
+ /**
197
+ * Internals exposed for the lock's own tests (acquire/release, stale reclaim,
198
+ * heartbeat, in-process queuing). Not part of the kernel's public API.
199
+ */
200
+ export const __testing__ = {
201
+ reclaimIfStale,
202
+ LOCK_STALE_MS,
203
+ LOCK_HEARTBEAT_MS,
204
+ };
205
+ //# sourceMappingURL=directory-lock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"directory-lock.js","sourceRoot":"","sources":["../src/directory-lock.ts"],"names":[],"mappings":"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"}
@@ -59,6 +59,11 @@ export declare class EvaluationContext implements IEvaluationContext {
59
59
  }>;
60
60
  /** Resources queued for initialization on this context node. */
61
61
  private pendingResources;
62
+ /** Per-resource dependency names, captured at create() time — BEFORE Phase-5
63
+ * injection swaps refs for live instances, so the walk sees plain objects and
64
+ * cannot wander into a controller's (possibly cyclic) object graph. Read only
65
+ * when init fails, to attribute each failure to its cause. */
66
+ private readonly resourceDependencies;
62
67
  /**
63
68
  * Optional hook called between create() and init() for each resource.
64
69
  * Set by the kernel to inject live instances into reference fields.
@@ -1 +1 @@
1
- {"version":3,"file":"evaluation-context.d.ts","sourceRoot":"","sources":["../src/evaluation-context.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"evaluation-context.d.ts","sourceRoot":"","sources":["../src/evaluation-context.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ import { formatSpanCounter } from "./logging/span-id.js";
3
3
  import { getRefIdentity, isCompiledValue, isInvokeError, isCancellationError, resourceKey, UNCANCELLABLE_CONTEXT, } from "@telorun/sdk";
4
4
  import { RuntimeError } from "@telorun/sdk";
5
5
  import { evalPathCovers } from "@telorun/analyzer";
6
+ import { classifyInitFailures, renderInitFailureText, summarizeInitFailures, } from "./init-failure-diagnostics.js";
6
7
  import { acceptReportedStatus, buildPublishedProps, diagnoseObservedStateAccess, } from "./observed-state.js";
7
8
  export { resourceKey };
8
9
  /** A pure resolved reference is a `{ kind, name, alias? }` object and nothing
@@ -65,6 +66,15 @@ function collectResourceRefs(resource) {
65
66
  }
66
67
  return [...found.values()];
67
68
  }
69
+ /**
70
+ * Project resource refs onto the names they depend on IN THIS CONTEXT. A local
71
+ * ref is its own name; a cross-module `Alias.name` ref depends on the local
72
+ * `Telo.Import` resource named by the alias, since that is the resource whose
73
+ * failure would strand it. Used to attribute an init failure to its cause.
74
+ */
75
+ function localDependencyNames(refs) {
76
+ return refs.map((r) => (r.alias && r.alias !== "Self" ? r.alias : r.name));
77
+ }
68
78
  /**
69
79
  * Build a resource's resolved properties for the debug stream — its config "after
70
80
  * templating", with `${{ }}` / `!cel` reduced to concrete values. The manifest is
@@ -308,6 +318,11 @@ export class EvaluationContext {
308
318
  this.createdInstances = new Map();
309
319
  /** Resources queued for initialization on this context node. */
310
320
  this.pendingResources = [];
321
+ /** Per-resource dependency names, captured at create() time — BEFORE Phase-5
322
+ * injection swaps refs for live instances, so the walk sees plain objects and
323
+ * cannot wander into a controller's (possibly cyclic) object graph. Read only
324
+ * when init fails, to attribute each failure to its cause. */
325
+ this.resourceDependencies = new Map();
311
326
  /** Cache of compiled walker closures keyed on the manifest subtree they walk.
312
327
  * WeakMap so entries are GC'd if the manifest is reloaded. */
313
328
  this.walkerCache = new WeakMap();
@@ -515,6 +530,8 @@ export class EvaluationContext {
515
530
  errors.delete(name);
516
531
  progress = true;
517
532
  const createdRes = created.resource;
533
+ const refs = collectResourceRefs(createdRes);
534
+ this.resourceDependencies.set(name, localDependencyNames(refs));
518
535
  const payload = {
519
536
  resource: {
520
537
  kind: createdRes.kind,
@@ -523,7 +540,7 @@ export class EvaluationContext {
523
540
  id: this.resourceId(createdRes.kind, createdRes.metadata.name),
524
541
  },
525
542
  ...(this.owner ? { owner: this.owner } : {}),
526
- dependencies: this.qualifyDeps(collectResourceRefs(createdRes)),
543
+ dependencies: this.qualifyDeps(refs),
527
544
  };
528
545
  // `properties` (the resolved config) is a second full config walk plus
529
546
  // a secret scrub. Build it lazily: the EventBus short-circuits when
@@ -553,7 +570,7 @@ export class EvaluationContext {
553
570
  if (this.preInitHook) {
554
571
  this.preInitHook(resource, (n, alias) => alias && alias !== "Self"
555
572
  ? this.resolveImportedInstance(alias, n)
556
- : this.resourceInstances.get(n)?.instance, (n) => this.hasManifest(n) && !this.resourceInstances.has(n));
573
+ : this.resourceInstances.get(n)?.instance, (n) => this.hasManifest(n) && !this.resourceInstances.has(n), this);
557
574
  }
558
575
  if (instance.init)
559
576
  await instance.init(ctx);
@@ -566,6 +583,9 @@ export class EvaluationContext {
566
583
  await this.publishSnapshot(name);
567
584
  this.resourceInstances.set(name, { resource, instance });
568
585
  this.createdInstances.delete(name);
586
+ // Read only on failure, and this one succeeded — drop it rather than
587
+ // holding a dep-name array per resource for the context's lifetime.
588
+ this.resourceDependencies.delete(name);
569
589
  errors.delete(name);
570
590
  progress = true;
571
591
  await this.emit(`${resource.kind}.${resource.metadata.name}.Initialized`, {
@@ -588,36 +608,27 @@ export class EvaluationContext {
588
608
  break;
589
609
  } while (pass <= MAX_PASSES);
590
610
  if (this.pendingResources.length > 0 || this.createdInstances.size > 0) {
591
- const diagnostics = [
592
- ...this.pendingResources.map((r) => {
593
- const info = errors.get(r.metadata.name) ?? { message: "Unknown error" };
594
- return {
595
- resource: r.metadata.name,
596
- kind: r.kind,
597
- message: info.message,
598
- details: info.details,
599
- code: info.code,
600
- };
601
- }),
602
- ...[...this.createdInstances].map(([name, { resource }]) => {
603
- const info = errors.get(name) ?? { message: "Unknown error" };
604
- return {
605
- resource: name,
606
- kind: resource.kind,
607
- message: info.message,
608
- details: info.details,
609
- code: info.code,
610
- };
611
- }),
611
+ const toFailure = (name, kind, deps) => {
612
+ const info = errors.get(name) ?? { message: "Unknown error" };
613
+ return {
614
+ resource: name,
615
+ kind,
616
+ message: info.message,
617
+ details: info.details,
618
+ code: info.code,
619
+ children: info.children,
620
+ deps,
621
+ };
622
+ };
623
+ const failures = [
624
+ // A resource that never got created was never injected either, so its
625
+ // manifest still carries plain `{kind, name}` refs — walk it here rather
626
+ // than relying on the create-time capture it never reached.
627
+ ...this.pendingResources.map((r) => toFailure(r.metadata.name, r.kind, localDependencyNames(collectResourceRefs(r)))),
628
+ ...[...this.createdInstances].map(([name, { resource }]) => toFailure(name, resource.kind, this.resourceDependencies.get(name) ?? [])),
612
629
  ];
613
- const textDetails = diagnostics
614
- .map((d) => {
615
- const head = ` ${d.kind ? `${d.kind} ` : ""}${d.resource}: ${d.message}${d.code ? ` [${d.code}]` : ""}`;
616
- const extra = d.details ? "\n" + d.details.split("\n").map((l) => ` ${l}`).join("\n") : "";
617
- return head + extra;
618
- })
619
- .join("\n");
620
- throw new RuntimeError("ERR_RESOURCE_INITIALIZATION_FAILED", `Unable to process resources:\n${textDetails}`, diagnostics);
630
+ const diagnostics = classifyInitFailures(failures);
631
+ throw new RuntimeError("ERR_RESOURCE_INITIALIZATION_FAILED", `${summarizeInitFailures(diagnostics)}:\n${renderInitFailureText(diagnostics)}`, diagnostics);
621
632
  }
622
633
  this.state = "Initialized";
623
634
  }
@@ -664,7 +675,7 @@ export class EvaluationContext {
664
675
  // Propagate injection hook: extend getInstance to also resolve parent singleton instances.
665
676
  if (parent.preInitHook) {
666
677
  const parentHook = parent.preInitHook;
667
- child.preInitHook = (resource, childGetInstance, childIsPending) => {
678
+ child.preInitHook = (resource, childGetInstance, childIsPending, owner) => {
668
679
  parentHook(resource, (name, alias) => {
669
680
  if (alias && alias !== "Self")
670
681
  return parent.resolveImportedInstance(alias, name);
@@ -685,7 +696,10 @@ export class EvaluationContext {
685
696
  },
686
697
  // Only a scope-local dependency can still be pending — an outer resource
687
698
  // is live by the time a scope opens — so the child's own predicate suffices.
688
- childIsPending);
699
+ childIsPending,
700
+ // Forwarded, not replaced by `child`: a `with:` nested inside a scoped
701
+ // resource must still resolve kinds against the scope it opened in.
702
+ owner);
689
703
  };
690
704
  }
691
705
  try {
@@ -1446,6 +1460,22 @@ function formatErrorForDiagnostic(err) {
1446
1460
  if (!(err instanceof Error)) {
1447
1461
  return { message: String(err) };
1448
1462
  }
1463
+ // A nested context's aggregate (an import initializing its library's
1464
+ // resources) already carries a classified diagnostic list. Keep it structured
1465
+ // instead of letting the cause-chain walk flatten it into this entry's
1466
+ // message: the child's root causes stay distinguishable from the child's own
1467
+ // cascade, and the error count sees the real leaves rather than one import.
1468
+ // The headline is re-derived from the diagnostics, never recovered by parsing
1469
+ // the message the child already rendered from them.
1470
+ if (err instanceof RuntimeError &&
1471
+ err.code === "ERR_RESOURCE_INITIALIZATION_FAILED" &&
1472
+ err.diagnostics?.length) {
1473
+ return {
1474
+ message: summarizeInitFailures(err.diagnostics),
1475
+ code: err.code,
1476
+ children: err.diagnostics,
1477
+ };
1478
+ }
1449
1479
  const detailLines = [];
1450
1480
  const seen = new Set();
1451
1481
  let current = err;