@telorun/analyzer 0.1.3 → 0.2.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 (65) hide show
  1. package/README.md +3 -3
  2. package/dist/analyzer.d.ts +6 -0
  3. package/dist/analyzer.d.ts.map +1 -1
  4. package/dist/analyzer.js +45 -25
  5. package/dist/builtins.d.ts.map +1 -1
  6. package/dist/builtins.js +56 -24
  7. package/dist/cel-environment.d.ts +12 -5
  8. package/dist/cel-environment.d.ts.map +1 -1
  9. package/dist/cel-environment.js +31 -17
  10. package/dist/definition-registry.d.ts +5 -5
  11. package/dist/definition-registry.d.ts.map +1 -1
  12. package/dist/definition-registry.js +10 -10
  13. package/dist/dependency-graph.d.ts.map +1 -1
  14. package/dist/dependency-graph.js +9 -2
  15. package/dist/index.d.ts +2 -1
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +1 -1
  18. package/dist/kernel-globals.d.ts +6 -2
  19. package/dist/kernel-globals.d.ts.map +1 -1
  20. package/dist/kernel-globals.js +14 -8
  21. package/dist/manifest-loader.d.ts +9 -1
  22. package/dist/manifest-loader.d.ts.map +1 -1
  23. package/dist/manifest-loader.js +165 -11
  24. package/dist/module-kinds.d.ts +4 -0
  25. package/dist/module-kinds.d.ts.map +1 -0
  26. package/dist/module-kinds.js +4 -0
  27. package/dist/normalize-inline-resources.d.ts.map +1 -1
  28. package/dist/normalize-inline-resources.js +6 -1
  29. package/dist/precompile.d.ts +3 -2
  30. package/dist/precompile.d.ts.map +1 -1
  31. package/dist/precompile.js +13 -11
  32. package/dist/reference-field-map.d.ts +1 -1
  33. package/dist/resolve-throws-union.d.ts +30 -0
  34. package/dist/resolve-throws-union.d.ts.map +1 -0
  35. package/dist/resolve-throws-union.js +252 -0
  36. package/dist/types.d.ts +11 -0
  37. package/dist/types.d.ts.map +1 -1
  38. package/dist/validate-cel-context.js +1 -1
  39. package/dist/validate-references.d.ts.map +1 -1
  40. package/dist/validate-references.js +19 -12
  41. package/dist/validate-throws-coverage.d.ts +8 -0
  42. package/dist/validate-throws-coverage.d.ts.map +1 -0
  43. package/dist/validate-throws-coverage.js +461 -0
  44. package/package.json +3 -3
  45. package/src/analyzer.ts +60 -26
  46. package/src/builtins.ts +56 -24
  47. package/src/cel-environment.ts +40 -17
  48. package/src/definition-registry.ts +10 -10
  49. package/src/dependency-graph.ts +9 -2
  50. package/src/index.ts +2 -1
  51. package/src/kernel-globals.ts +19 -10
  52. package/src/manifest-loader.ts +202 -17
  53. package/src/module-kinds.ts +6 -0
  54. package/src/normalize-inline-resources.ts +6 -1
  55. package/src/precompile.ts +14 -11
  56. package/src/reference-field-map.ts +1 -1
  57. package/src/resolve-throws-union.ts +345 -0
  58. package/src/types.ts +13 -0
  59. package/src/validate-cel-context.ts +1 -1
  60. package/src/validate-references.ts +19 -12
  61. package/src/validate-throws-coverage.ts +565 -0
  62. package/dist/adapters/node-adapter.d.ts +0 -15
  63. package/dist/adapters/node-adapter.d.ts.map +0 -1
  64. package/dist/adapters/node-adapter.js +0 -33
  65. package/src/adapters/node-adapter.ts +0 -38
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export { HttpAdapter } from "./adapters/http-adapter.js";
2
- export { createNodeAdapter, NodeAdapter } from "./adapters/node-adapter.js";
3
2
  export { RegistryAdapter } from "./adapters/registry-adapter.js";
4
3
  export { AnalysisRegistry } from "./analysis-registry.js";
5
4
  export { StaticAnalyzer } from "./analyzer.js";
6
5
  export { Loader } from "./manifest-loader.js";
6
+ export { MODULE_KINDS, isModuleKind } from "./module-kinds.js";
7
7
  export { DEFAULT_MANIFEST_FILENAME, DiagnosticSeverity } from "./types.js";
@@ -6,7 +6,7 @@ import type { ResourceManifest } from "@telorun/sdk";
6
6
  * must stay in sync with this list.
7
7
  *
8
8
  * Note: `env` is only available in the root module context. Child modules
9
- * loaded via Kernel.Import do not receive host environment variables.
9
+ * loaded via Telo.Import do not receive host environment variables.
10
10
  * There is no `imports` namespace at runtime — import snapshots are stored
11
11
  * under `resources.<alias>`.
12
12
  */
@@ -17,7 +17,11 @@ export declare const KERNEL_GLOBAL_NAMES: readonly ["variables", "secrets", "res
17
17
  * chain-access validation recognises kernel globals without module authors
18
18
  * having to re-declare them.
19
19
  *
20
- * - `variables` / `secrets`: typed from the `Kernel.Module` declaration
20
+ * - `variables` / `secrets`: typed from the root module doc — prefer
21
+ * Telo.Application when present, otherwise fall back to Telo.Library.
22
+ * Applications are the root whose variables/secrets contract governs CEL
23
+ * in the outer module; Libraries are only relevant when the caller scoped
24
+ * the manifest list to a single library's file.
21
25
  * - `resources`: enumerates all non-system resource names
22
26
  * - `env`: dynamic (runtime env vars, root module only)
23
27
  */
@@ -1 +1 @@
1
- {"version":3,"file":"kernel-globals.d.ts","sourceRoot":"","sources":["../src/kernel-globals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,uDAAwD,CAAC;AAQzF;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,gBAAgB,EAAE,GAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA6BrB;AA2BD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAClC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACjC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CASrB"}
1
+ {"version":3,"file":"kernel-globals.d.ts","sourceRoot":"","sources":["../src/kernel-globals.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,uDAAwD,CAAC;AASzF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,gBAAgB,EAAE,GAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAiCrB;AA2BD;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAC3C,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAClC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GACjC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CASrB"}
@@ -5,15 +5,16 @@
5
5
  * must stay in sync with this list.
6
6
  *
7
7
  * Note: `env` is only available in the root module context. Child modules
8
- * loaded via Kernel.Import do not receive host environment variables.
8
+ * loaded via Telo.Import do not receive host environment variables.
9
9
  * There is no `imports` namespace at runtime — import snapshots are stored
10
10
  * under `resources.<alias>`.
11
11
  */
12
12
  export const KERNEL_GLOBAL_NAMES = ["variables", "secrets", "resources", "env"];
13
13
  const SYSTEM_KINDS = new Set([
14
- "Kernel.Definition",
15
- "Kernel.Module",
16
- "Kernel.Abstract",
14
+ "Telo.Definition",
15
+ "Telo.Application",
16
+ "Telo.Library",
17
+ "Telo.Abstract",
17
18
  ]);
18
19
  /**
19
20
  * Build a typed JSON Schema describing the kernel globals available in the
@@ -21,18 +22,23 @@ const SYSTEM_KINDS = new Set([
21
22
  * chain-access validation recognises kernel globals without module authors
22
23
  * having to re-declare them.
23
24
  *
24
- * - `variables` / `secrets`: typed from the `Kernel.Module` declaration
25
+ * - `variables` / `secrets`: typed from the root module doc — prefer
26
+ * Telo.Application when present, otherwise fall back to Telo.Library.
27
+ * Applications are the root whose variables/secrets contract governs CEL
28
+ * in the outer module; Libraries are only relevant when the caller scoped
29
+ * the manifest list to a single library's file.
25
30
  * - `resources`: enumerates all non-system resource names
26
31
  * - `env`: dynamic (runtime env vars, root module only)
27
32
  */
28
33
  export function buildKernelGlobalsSchema(manifests) {
29
- const moduleManifest = manifests.find((m) => m.kind === "Kernel.Module");
34
+ const moduleManifest = manifests.find((m) => m.kind === "Telo.Application") ??
35
+ manifests.find((m) => m.kind === "Telo.Library");
30
36
  const resourceProps = {};
31
37
  for (const m of manifests) {
32
38
  const name = m.metadata?.name;
33
39
  if (!name || !m.kind)
34
40
  continue;
35
- // Kernel.Import snapshots are stored under resources.<alias> at runtime,
41
+ // Telo.Import snapshots are stored under resources.<alias> at runtime,
36
42
  // so they appear here alongside regular resources.
37
43
  if (!SYSTEM_KINDS.has(m.kind)) {
38
44
  resourceProps[name] = { type: "object", additionalProperties: true };
@@ -52,7 +58,7 @@ export function buildKernelGlobalsSchema(manifests) {
52
58
  },
53
59
  };
54
60
  }
55
- /** Wrap a JSON Schema property map (like `Kernel.Module.variables`) into a
61
+ /** Wrap a JSON Schema property map (like `Telo.Application.variables`) into a
56
62
  * closed object schema suitable for chain-access validation. Falls back to
57
63
  * an open map when the module declares no variables/secrets. */
58
64
  function buildSchemaMapSchema(schemaMap) {
@@ -1,13 +1,21 @@
1
1
  import { type ResourceManifest } from "@telorun/sdk";
2
- import type { LoadOptions, LoaderInitOptions, ManifestAdapter } from "./types.js";
2
+ import { type LoadOptions, type LoaderInitOptions, type ManifestAdapter } from "./types.js";
3
3
  export declare class Loader {
4
4
  private static readonly moduleCache;
5
5
  protected adapters: ManifestAdapter[];
6
+ private readonly celEnv;
6
7
  constructor(extraAdaptersOrOptions?: ManifestAdapter[] | LoaderInitOptions);
7
8
  register(adapter: ManifestAdapter): this;
8
9
  private pick;
9
10
  resolveEntryPoint(url: string): Promise<string>;
10
11
  loadModule(url: string, options?: LoadOptions): Promise<ResourceManifest[]>;
12
+ private resolveIncludes;
13
+ private loadPartialFile;
14
+ loadModuleForFile(fileUrl: string): Promise<{
15
+ ownerUrl: string;
16
+ manifests: ResourceManifest[];
17
+ sourceManifests: Map<string, ResourceManifest[]>;
18
+ } | null>;
11
19
  loadModuleGraph(entryUrl: string, onError?: (url: string, error: Error) => void): Promise<Map<string, ResourceManifest[]>>;
12
20
  loadManifests(entryUrl: string): Promise<ResourceManifest[]>;
13
21
  }
@@ -1 +1 @@
1
- {"version":3,"file":"manifest-loader.d.ts","sourceRoot":"","sources":["../src/manifest-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAKtE,OAAO,KAAK,EACV,WAAW,EACX,iBAAiB,EACjB,eAAe,EAGhB,MAAM,YAAY,CAAC;AAEpB,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAG/B;IAEJ,SAAS,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;gBAE1B,sBAAsB,GAAE,eAAe,EAAE,GAAG,iBAAsB;IAiB9E,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAKxC,OAAO,CAAC,IAAI;IAMN,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK/C,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAgF3E,eAAe,CACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,GAC5C,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAsCrC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAoDnE"}
1
+ {"version":3,"file":"manifest-loader.d.ts","sourceRoot":"","sources":["../src/manifest-loader.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAOtE,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,iBAAiB,EACtB,KAAK,eAAe,EAGrB,MAAM,YAAY,CAAC;AASpB,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAG/B;IAEJ,SAAS,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAC;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;gBAEzB,sBAAsB,GAAE,eAAe,EAAE,GAAG,iBAAsB;IAmB9E,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAKxC,OAAO,CAAC,IAAI;IAMN,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK/C,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;YAqGnE,eAAe;YAoBf,eAAe;IAgEvB,iBAAiB,CACrB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC;QACT,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,gBAAgB,EAAE,CAAC;QAC9B,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;KAClD,GAAG,IAAI,CAAC;IAiCH,eAAe,CACnB,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,GAC5C,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAsCrC,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;CAiEnE"}
@@ -2,10 +2,20 @@ import { isCompiledValue } from "@telorun/sdk";
2
2
  import { isMap, isPair, isScalar, isSeq, parseAllDocuments } from "yaml";
3
3
  import { HttpAdapter } from "./adapters/http-adapter.js";
4
4
  import { RegistryAdapter } from "./adapters/registry-adapter.js";
5
+ import { buildCelEnvironment } from "./cel-environment.js";
6
+ import { isModuleKind } from "./module-kinds.js";
5
7
  import { precompileDoc } from "./precompile.js";
8
+ import { DEFAULT_MANIFEST_FILENAME, } from "./types.js";
9
+ const SYSTEM_KINDS = new Set([
10
+ "Telo.Application",
11
+ "Telo.Library",
12
+ "Telo.Import",
13
+ "Telo.Definition",
14
+ ]);
6
15
  export class Loader {
7
16
  static moduleCache = new Map();
8
17
  adapters;
18
+ celEnv;
9
19
  constructor(extraAdaptersOrOptions = []) {
10
20
  const options = Array.isArray(extraAdaptersOrOptions)
11
21
  ? { extraAdapters: extraAdaptersOrOptions }
@@ -20,6 +30,7 @@ export class Loader {
20
30
  if (options.extraAdapters?.length) {
21
31
  this.adapters.unshift(...options.extraAdapters);
22
32
  }
33
+ this.celEnv = buildCelEnvironment(options.celHandlers);
23
34
  }
24
35
  register(adapter) {
25
36
  this.adapters.unshift(adapter);
@@ -57,7 +68,7 @@ export class Loader {
57
68
  let compiledDocs;
58
69
  if (options?.compile) {
59
70
  try {
60
- const result = precompileDoc(rawDoc);
71
+ const result = precompileDoc(rawDoc, this.celEnv);
61
72
  compiledDocs = Array.isArray(result) ? result : [result];
62
73
  }
63
74
  catch (error) {
@@ -83,15 +94,17 @@ export class Loader {
83
94
  resolved.push({ ...manifest, metadata });
84
95
  }
85
96
  }
86
- const moduleManifests = resolved.filter((m) => m.kind === "Kernel.Module");
97
+ const moduleManifests = resolved.filter((m) => isModuleKind(m.kind));
87
98
  if (moduleManifests.length > 1) {
88
- throw new Error(`File '${source}' contains ${moduleManifests.length} Kernel.Module declarations. Maximum one is allowed.`);
99
+ const kinds = moduleManifests.map((m) => m.kind).join(", ");
100
+ throw new Error(`File '${source}' contains ${moduleManifests.length} module declarations (${kinds}). ` +
101
+ `A file may declare at most one Telo.Application or Telo.Library.`);
89
102
  }
90
103
  const moduleManifest = moduleManifests[0];
91
104
  const moduleName = moduleManifest?.metadata?.name;
92
105
  if (moduleName) {
93
106
  for (const manifest of resolved) {
94
- if (manifest.kind !== "Kernel.Module" && !manifest.metadata?.module) {
107
+ if (!isModuleKind(manifest.kind) && !manifest.metadata?.module) {
95
108
  const pi = manifest.metadata?.positionIndex;
96
109
  manifest.metadata = { ...manifest.metadata, module: moduleName };
97
110
  if (pi) {
@@ -105,9 +118,126 @@ export class Loader {
105
118
  }
106
119
  }
107
120
  }
108
- Loader.moduleCache.set(cacheKey, { text, manifests: resolved });
121
+ // Expand include directives load partial files into the same module scope.
122
+ // Results with includes are NOT cached because partial file content is not
123
+ // tracked in the cache key — the cache would serve stale data if a partial changes.
124
+ let hasIncludes = false;
125
+ if (moduleManifest) {
126
+ const includePatterns = moduleManifest.include;
127
+ if (includePatterns?.length) {
128
+ hasIncludes = true;
129
+ const adapter = this.pick(source);
130
+ const includedFiles = await this.resolveIncludes(source, includePatterns, adapter);
131
+ for (const includedUrl of includedFiles) {
132
+ const partialManifests = await this.loadPartialFile(includedUrl, moduleName, options);
133
+ resolved.push(...partialManifests);
134
+ }
135
+ }
136
+ }
137
+ if (!hasIncludes) {
138
+ Loader.moduleCache.set(cacheKey, { text, manifests: resolved });
139
+ }
109
140
  return cloneManifestArray(resolved);
110
141
  }
142
+ async resolveIncludes(ownerSource, patterns, adapter) {
143
+ const hasGlobs = patterns.some((p) => /[*?{}\[\]]/.test(p));
144
+ if (hasGlobs) {
145
+ if (!adapter.expandGlob) {
146
+ throw new Error(`Include patterns in '${ownerSource}' contain globs but the adapter for this source ` +
147
+ `does not support glob expansion. Use explicit file paths instead of patterns like: ` +
148
+ patterns.filter((p) => /[*?{}\[\]]/.test(p)).join(", "));
149
+ }
150
+ return adapter.expandGlob(ownerSource, patterns);
151
+ }
152
+ // Literal relative paths — deduplicate in case the same file appears under multiple patterns.
153
+ return [...new Set(patterns.map((p) => adapter.resolveRelative(ownerSource, p)))];
154
+ }
155
+ async loadPartialFile(url, ownerModuleName, options) {
156
+ const { text, source } = await this.pick(url).read(url);
157
+ const parsedDocuments = parseAllDocuments(text);
158
+ const rawDocs = parsedDocuments.map((d) => d.toJSON());
159
+ const offsets = documentLineOffsets(text);
160
+ const lineOffsets = buildLineOffsets(text);
161
+ const resolved = [];
162
+ let docIdx = 0;
163
+ for (const rawDoc of rawDocs) {
164
+ const currentDocIdx = docIdx++;
165
+ const sourceLine = offsets[currentDocIdx] ?? 0;
166
+ const positionIndex = buildPositionIndex(parsedDocuments[currentDocIdx], lineOffsets);
167
+ if (rawDoc === null || rawDoc === undefined)
168
+ continue;
169
+ const kind = rawDoc.kind;
170
+ if (kind && SYSTEM_KINDS.has(kind)) {
171
+ throw new Error(`Included file '${source}' contains '${kind}' which is not allowed in partial files. ` +
172
+ `Only the owner telo.yaml may declare ${kind} resources.`);
173
+ }
174
+ let compiledDocs;
175
+ if (options?.compile) {
176
+ try {
177
+ const result = precompileDoc(rawDoc, this.celEnv);
178
+ compiledDocs = Array.isArray(result) ? result : [result];
179
+ }
180
+ catch (error) {
181
+ throw new Error(`Failed to compile manifest in ${source}: ${error instanceof Error ? error.message : String(error)}`);
182
+ }
183
+ }
184
+ else {
185
+ compiledDocs = [rawDoc];
186
+ }
187
+ for (const doc of compiledDocs) {
188
+ if (doc === null || doc === undefined)
189
+ continue;
190
+ const manifest = doc;
191
+ const metadata = {
192
+ ...manifest.metadata,
193
+ source,
194
+ sourceLine,
195
+ ...(ownerModuleName && !manifest.metadata?.module ? { module: ownerModuleName } : {}),
196
+ };
197
+ Object.defineProperty(metadata, "positionIndex", {
198
+ value: positionIndex,
199
+ enumerable: false,
200
+ writable: true,
201
+ configurable: true,
202
+ });
203
+ resolved.push({ ...manifest, metadata });
204
+ }
205
+ }
206
+ return resolved;
207
+ }
208
+ async loadModuleForFile(fileUrl) {
209
+ // Try loading as a regular module first (it might be a telo.yaml itself).
210
+ // Use loadManifests (not loadModule) so imported definitions are included —
211
+ // otherwise the analyzer won't know about kinds from Telo.Import sources.
212
+ try {
213
+ const docs = await this.loadModule(fileUrl);
214
+ const hasModule = docs.some((d) => isModuleKind(d.kind));
215
+ if (hasModule) {
216
+ const { source } = await this.pick(fileUrl).read(fileUrl);
217
+ const manifests = await this.loadManifests(fileUrl);
218
+ return { ownerUrl: source, manifests, sourceManifests: groupBySource(manifests) };
219
+ }
220
+ }
221
+ catch (err) {
222
+ // If the file looks like an owner manifest (named telo.yaml), rethrow —
223
+ // a broken owner shouldn't silently fall through to parent lookup.
224
+ const normalized = fileUrl.replace(/\\/g, "/");
225
+ if (normalized.endsWith(`/${DEFAULT_MANIFEST_FILENAME}`) || normalized === DEFAULT_MANIFEST_FILENAME) {
226
+ throw err;
227
+ }
228
+ // Otherwise fall through to owner lookup — this is likely a partial file
229
+ }
230
+ // Find the owning telo.yaml via parent-directory traversal
231
+ const adapter = this.pick(fileUrl);
232
+ if (!adapter.resolveOwnerOf)
233
+ return null;
234
+ const ownerUrl = await adapter.resolveOwnerOf(fileUrl);
235
+ if (!ownerUrl)
236
+ return null;
237
+ // Load the owner module (which will load included files via include expansion)
238
+ const manifests = await this.loadManifests(ownerUrl);
239
+ return { ownerUrl, manifests, sourceManifests: groupBySource(manifests) };
240
+ }
111
241
  async loadModuleGraph(entryUrl, onError) {
112
242
  const visited = new Set([entryUrl]);
113
243
  const result = new Map();
@@ -116,7 +246,7 @@ export class Loader {
116
246
  const queue = [...entry];
117
247
  while (queue.length > 0) {
118
248
  const m = queue.shift();
119
- if (m.kind !== "Kernel.Import")
249
+ if (m.kind !== "Telo.Import")
120
250
  continue;
121
251
  const importSource = m.source;
122
252
  if (!importSource)
@@ -139,7 +269,7 @@ export class Loader {
139
269
  }
140
270
  result.set(importUrl, imported);
141
271
  for (const im of imported) {
142
- if (im.kind === "Kernel.Import")
272
+ if (im.kind === "Telo.Import")
143
273
  queue.push(im);
144
274
  }
145
275
  }
@@ -152,7 +282,7 @@ export class Loader {
152
282
  const queue = [...entry];
153
283
  while (queue.length > 0) {
154
284
  const m = queue.shift();
155
- if (m.kind !== "Kernel.Import")
285
+ if (m.kind !== "Telo.Import")
156
286
  continue;
157
287
  const importSource = m.source;
158
288
  if (!importSource)
@@ -173,7 +303,18 @@ export class Loader {
173
303
  e.sourceLine = m.metadata?.sourceLine ?? 0;
174
304
  throw e;
175
305
  }
176
- const importedModule = imported.find((im) => im.kind === "Kernel.Module");
306
+ // Import target must be a Telo.Library. Check the Library branch
307
+ // explicitly rather than "anything that's a module kind" so that a
308
+ // future third kind can't silently slip past as a valid import target.
309
+ const importedLibrary = imported.find((im) => im.kind === "Telo.Library");
310
+ const importedApplication = imported.find((im) => im.kind === "Telo.Application");
311
+ if (importedApplication) {
312
+ const e = new Error(`Telo.Import target '${importSource}' is a Telo.Application. ` +
313
+ `Only Telo.Library modules may be imported. Applications are run directly, not imported.`);
314
+ e.sourceLine = m.metadata?.sourceLine ?? 0;
315
+ throw e;
316
+ }
317
+ const importedModule = importedLibrary;
177
318
  if (importedModule?.metadata?.name) {
178
319
  const pi = m.metadata?.positionIndex;
179
320
  m.metadata = {
@@ -191,9 +332,9 @@ export class Loader {
191
332
  }
192
333
  }
193
334
  for (const im of imported) {
194
- if (im.kind === "Kernel.Definition")
335
+ if (im.kind === "Telo.Definition")
195
336
  importedDefs.push(im);
196
- if (im.kind === "Kernel.Import")
337
+ if (im.kind === "Telo.Import")
197
338
  queue.push(im);
198
339
  }
199
340
  }
@@ -224,6 +365,19 @@ function cloneManifestValue(value) {
224
365
  }
225
366
  return value;
226
367
  }
368
+ function groupBySource(manifests) {
369
+ const map = new Map();
370
+ for (const m of manifests) {
371
+ const src = m.metadata?.source ?? "unknown";
372
+ let list = map.get(src);
373
+ if (!list) {
374
+ list = [];
375
+ map.set(src, list);
376
+ }
377
+ list.push(m);
378
+ }
379
+ return map;
380
+ }
227
381
  function documentLineOffsets(text) {
228
382
  const offsets = [0];
229
383
  const lines = text.split("\n");
@@ -0,0 +1,4 @@
1
+ export declare const MODULE_KINDS: readonly ["Telo.Application", "Telo.Library"];
2
+ export type ModuleKind = (typeof MODULE_KINDS)[number];
3
+ export declare function isModuleKind(kind: string | undefined): kind is ModuleKind;
4
+ //# sourceMappingURL=module-kinds.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"module-kinds.d.ts","sourceRoot":"","sources":["../src/module-kinds.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,YAAY,+CAAgD,CAAC;AAC1E,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,YAAY,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,IAAI,UAAU,CAEzE"}
@@ -0,0 +1,4 @@
1
+ export const MODULE_KINDS = ["Telo.Application", "Telo.Library"];
2
+ export function isModuleKind(kind) {
3
+ return kind === "Telo.Application" || kind === "Telo.Library";
4
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"normalize-inline-resources.d.ts","sourceRoot":"","sources":["../src/normalize-inline-resources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AASzD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,CAAC,EAAE,aAAa,GACtB,gBAAgB,EAAE,CAkDpB"}
1
+ {"version":3,"file":"normalize-inline-resources.d.ts","sourceRoot":"","sources":["../src/normalize-inline-resources.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAczD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,CAAC,EAAE,aAAa,GACtB,gBAAgB,EAAE,CAkDpB"}
@@ -1,5 +1,10 @@
1
1
  import { isRefEntry, isScopeEntry, isInlineResource } from "./reference-field-map.js";
2
- const SYSTEM_KINDS = new Set(["Kernel.Definition", "Kernel.Module", "Kernel.Import"]);
2
+ const SYSTEM_KINDS = new Set([
3
+ "Telo.Definition",
4
+ "Telo.Application",
5
+ "Telo.Library",
6
+ "Telo.Import",
7
+ ]);
3
8
  /** Replaces characters outside [a-zA-Z0-9_] with underscores. */
4
9
  function sanitizeName(raw) {
5
10
  return raw.replace(/[^a-zA-Z0-9_]/g, "_");
@@ -1,9 +1,10 @@
1
+ import type { Environment } from "@marcbachmann/cel-js";
1
2
  /**
2
3
  * Walks a raw YAML document and replaces all "${{ expr }}" strings with
3
4
  * CompiledValue wrappers. Throws on CEL syntax errors.
4
5
  * Intended to be called once per document at load time.
5
- * Kernel.Definition documents are returned unchanged — their schema fields
6
+ * Telo.Definition documents are returned unchanged — their schema fields
6
7
  * are static metadata and must not be treated as CEL templates.
7
8
  */
8
- export declare function precompileDoc(doc: unknown): unknown;
9
+ export declare function precompileDoc(doc: unknown, env: Environment): unknown;
9
10
  //# sourceMappingURL=precompile.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"precompile.d.ts","sourceRoot":"","sources":["../src/precompile.ts"],"names":[],"mappings":"AAMA;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAanD"}
1
+ {"version":3,"file":"precompile.d.ts","sourceRoot":"","sources":["../src/precompile.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAKxD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAarE"}
@@ -1,36 +1,36 @@
1
- import { celEnvironment } from "./cel-environment.js";
2
1
  const TEMPLATE_REGEX = /\$\{\{\s*([^}]+?)\s*\}\}/g;
3
2
  const EXACT_TEMPLATE_REGEX = /^\s*\$\{\{\s*([^}]+?)\s*\}\}\s*$/;
4
3
  /**
5
4
  * Walks a raw YAML document and replaces all "${{ expr }}" strings with
6
5
  * CompiledValue wrappers. Throws on CEL syntax errors.
7
6
  * Intended to be called once per document at load time.
8
- * Kernel.Definition documents are returned unchanged — their schema fields
7
+ * Telo.Definition documents are returned unchanged — their schema fields
9
8
  * are static metadata and must not be treated as CEL templates.
10
9
  */
11
- export function precompileDoc(doc) {
10
+ export function precompileDoc(doc, env) {
12
11
  if (typeof doc === "string")
13
- return compileString(doc);
12
+ return compileString(doc, env);
14
13
  if (Array.isArray(doc))
15
- return doc.map(precompileDoc);
14
+ return doc.map((item) => precompileDoc(item, env));
16
15
  // Only recurse into plain objects. Class instances (ResourceInstance, ScopeHandle, etc.)
17
16
  // are returned as-is — their prototype methods must not be lost by object reconstruction.
18
17
  if (doc !== null && typeof doc === "object" && Object.getPrototypeOf(doc) === Object.prototype) {
19
18
  const result = {};
20
19
  for (const [k, v] of Object.entries(doc)) {
21
- result[k] = precompileDoc(v);
20
+ result[k] = precompileDoc(v, env);
22
21
  }
23
22
  return result;
24
23
  }
25
24
  return doc;
26
25
  }
27
- function compileString(s) {
26
+ function compileString(s, env) {
28
27
  if (!s.includes("${{"))
29
28
  return s;
30
29
  const exact = s.match(EXACT_TEMPLATE_REGEX);
31
30
  if (exact) {
32
- const fn = celEnvironment.parse(exact[1].trim());
33
- return { __compiled: true, call: (ctx) => fn(ctx) };
31
+ const expr = exact[1].trim();
32
+ const fn = env.parse(expr);
33
+ return { __compiled: true, source: expr, call: (ctx) => fn(ctx) };
34
34
  }
35
35
  // Interpolated template — collect literal parts + compiled sub-expressions
36
36
  const parts = [];
@@ -38,14 +38,16 @@ function compileString(s) {
38
38
  for (const m of s.matchAll(TEMPLATE_REGEX)) {
39
39
  if (m.index > last)
40
40
  parts.push(s.slice(last, m.index));
41
- const fn = celEnvironment.parse(m[1].trim());
42
- parts.push({ __compiled: true, call: (ctx) => fn(ctx) });
41
+ const expr = m[1].trim();
42
+ const fn = env.parse(expr);
43
+ parts.push({ __compiled: true, source: expr, call: (ctx) => fn(ctx) });
43
44
  last = m.index + m[0].length;
44
45
  }
45
46
  if (last < s.length)
46
47
  parts.push(s.slice(last));
47
48
  return {
48
49
  __compiled: true,
50
+ source: s,
49
51
  call: (ctx) => parts.map((p) => (typeof p === "string" ? p : String(p.call(ctx) ?? ""))).join(""),
50
52
  };
51
53
  }
@@ -1,6 +1,6 @@
1
1
  /** An entry for a field that carries one or more x-telo-ref constraints. */
2
2
  export interface RefFieldEntry {
3
- /** One or more canonical ref strings ("namespace/module#TypeName" or "kernel#TypeName").
3
+ /** One or more canonical ref strings ("namespace/module#TypeName" or "telo#TypeName").
4
4
  * Multiple entries arise from anyOf branches. */
5
5
  refs: string[];
6
6
  /** True when the field path traversed through at least one array (path contains "[]"). */
@@ -0,0 +1,30 @@
1
+ import type { ResourceManifest } from "@telorun/sdk";
2
+ import type { AliasResolver } from "./alias-resolver.js";
3
+ import type { DefinitionRegistry } from "./definition-registry.js";
4
+ export interface ThrowsCodeMeta {
5
+ data?: Record<string, any>;
6
+ }
7
+ export interface ThrowsUnion {
8
+ /** Code → per-code metadata (data schema, etc). Keys are the declared codes. */
9
+ codes: Map<string, ThrowsCodeMeta>;
10
+ /** True when the union cannot be fully resolved statically — e.g. a
11
+ * `passthrough` call site uses a CEL expression the analyzer can't narrow,
12
+ * an unknown kind was encountered, or a cycle short-circuited resolution.
13
+ * Callers must treat unbounded unions as requiring a catch-all entry. */
14
+ unbounded: boolean;
15
+ }
16
+ export interface ResolveCtx {
17
+ allManifests: ResourceManifest[];
18
+ defs: DefinitionRegistry;
19
+ aliases: AliasResolver;
20
+ memo: Map<string, ThrowsUnion>;
21
+ inProgress: Set<string>;
22
+ }
23
+ export declare function createResolveCtx(allManifests: ResourceManifest[], defs: DefinitionRegistry, aliases: AliasResolver): ResolveCtx;
24
+ /** Resolve the effective throw union for a named manifest. The result combines
25
+ * explicit `throws.codes`, `throws.inherit: true` dataflow (step-context
26
+ * traversal with try/catch subtraction), and unbounded markers for
27
+ * unresolvable passthrough call sites. Cycles short-circuit to an empty
28
+ * result so resolution always terminates. */
29
+ export declare function resolveThrowsUnion(manifest: ResourceManifest, ctx: ResolveCtx): ThrowsUnion;
30
+ //# sourceMappingURL=resolve-throws-union.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-throws-union.d.ts","sourceRoot":"","sources":["../src/resolve-throws-union.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,gFAAgF;IAChF,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IACnC;;;8EAG0E;IAC1E,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,IAAI,EAAE,kBAAkB,CAAC;IACzB,OAAO,EAAE,aAAa,CAAC;IACvB,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC/B,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACzB;AAED,wBAAgB,gBAAgB,CAC9B,YAAY,EAAE,gBAAgB,EAAE,EAChC,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,aAAa,GACrB,UAAU,CAQZ;AA+BD;;;;8CAI8C;AAC9C,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,gBAAgB,EAC1B,GAAG,EAAE,UAAU,GACd,WAAW,CA+Cb"}