@telorun/analyzer 0.12.1 → 0.13.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 (45) hide show
  1. package/dist/analysis-registry.d.ts +12 -0
  2. package/dist/analysis-registry.d.ts.map +1 -1
  3. package/dist/analysis-registry.js +15 -0
  4. package/dist/analyzer.d.ts.map +1 -1
  5. package/dist/analyzer.js +64 -84
  6. package/dist/builtins.d.ts.map +1 -1
  7. package/dist/builtins.js +25 -0
  8. package/dist/cel-environment.d.ts +1 -1
  9. package/dist/cel-environment.d.ts.map +1 -1
  10. package/dist/cel-environment.js +40 -2
  11. package/dist/dependency-graph.d.ts.map +1 -1
  12. package/dist/dependency-graph.js +41 -62
  13. package/dist/index.d.ts +2 -0
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +1 -0
  16. package/dist/kernel-globals.d.ts +1 -1
  17. package/dist/kernel-globals.d.ts.map +1 -1
  18. package/dist/kernel-globals.js +19 -1
  19. package/dist/manifest-visitor.d.ts +109 -0
  20. package/dist/manifest-visitor.d.ts.map +1 -0
  21. package/dist/manifest-visitor.js +110 -0
  22. package/dist/schema-compat.d.ts +10 -0
  23. package/dist/schema-compat.d.ts.map +1 -1
  24. package/dist/schema-compat.js +32 -0
  25. package/dist/validate-cel-context.d.ts +14 -0
  26. package/dist/validate-cel-context.d.ts.map +1 -1
  27. package/dist/validate-cel-context.js +38 -0
  28. package/dist/validate-references.d.ts.map +1 -1
  29. package/dist/validate-references.js +117 -160
  30. package/dist/validate-unused-declarations.d.ts +25 -0
  31. package/dist/validate-unused-declarations.d.ts.map +1 -0
  32. package/dist/validate-unused-declarations.js +91 -0
  33. package/package.json +2 -2
  34. package/src/analysis-registry.ts +20 -0
  35. package/src/analyzer.ts +157 -169
  36. package/src/builtins.ts +25 -0
  37. package/src/cel-environment.ts +42 -1
  38. package/src/dependency-graph.ts +37 -52
  39. package/src/index.ts +11 -0
  40. package/src/kernel-globals.ts +22 -1
  41. package/src/manifest-visitor.ts +251 -0
  42. package/src/schema-compat.ts +32 -0
  43. package/src/validate-cel-context.ts +50 -0
  44. package/src/validate-references.ts +168 -211
  45. package/src/validate-unused-declarations.ts +95 -0
@@ -1,4 +1,5 @@
1
1
  import type { ResourceDefinition, ResourceManifest } from "@telorun/sdk";
2
+ import { type ManifestVisitor } from "./manifest-visitor.js";
2
3
  import type { AnalysisContext } from "./types.js";
3
4
  /**
4
5
  * Accumulates type and alias knowledge for a running kernel or analysis session.
@@ -22,6 +23,17 @@ export declare class AnalysisRegistry {
22
23
  * sub-schema (e.g. Server.notFoundHandler.returns[].content[mime].encoder).
23
24
  */
24
25
  iterateFieldEntries(resource: ResourceManifest, onRef: (fieldPath: string) => void, onScope: (fieldPath: string) => void): void;
26
+ /**
27
+ * Walks a manifest's annotation sites (refs, scopes, schema-from, CEL) via
28
+ * the shared manifest visitor, bound to this registry's definitions and
29
+ * aliases. The public seam for hosts (editor overview graph, tooling) that
30
+ * need the same site discovery the analyzer's own passes use, without
31
+ * reaching into the internal DefinitionRegistry.
32
+ */
33
+ visitManifest(resources: ResourceManifest[], visitor: ManifestVisitor, opts?: {
34
+ skipKinds?: ReadonlySet<string>;
35
+ expand?: boolean;
36
+ }): void;
25
37
  /**
26
38
  * Returns the built-in kernel definitions. The underlying DefinitionRegistry already
27
39
  * seeds these on construction; this method exposes them so callers (e.g. the kernel's
@@ -1 +1 @@
1
- {"version":3,"file":"analysis-registry.d.ts","sourceRoot":"","sources":["../src/analysis-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAMzE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;;;GAIG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA4B;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAoC;IAEpE,kBAAkB,CAAC,GAAG,EAAE,kBAAkB,GAAG,IAAI;IAIjD,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAIpE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAIpE,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI7C;;;;;;;OAOG;IACH,mBAAmB,CACjB,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,EAClC,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,GACnC,IAAI;IAkBP;;;;OAIG;IACH,kBAAkB,IAAI,kBAAkB,EAAE;IAI1C,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAM/D,QAAQ,IAAI,MAAM,EAAE;IAIpB;mEAC+D;IAC/D,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE;IAIxC;;;gCAG4B;IAC5B,oBAAoB,IAAI,MAAM,EAAE;IAIhC;wEACoE;IACpE,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIhD;;;;;gEAK4D;IAC5D,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS;IA+B7D,qFAAqF;IACrF,QAAQ,IAAI,eAAe;CAG5B"}
1
+ {"version":3,"file":"analysis-registry.d.ts","sourceRoot":"","sources":["../src/analysis-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAKzE,OAAO,EAAqC,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAEhG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;;;GAIG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA4B;IACjD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAoC;IAEpE,kBAAkB,CAAC,GAAG,EAAE,kBAAkB,GAAG,IAAI;IAIjD,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAIpE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI;IAIpE,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI7C;;;;;;;OAOG;IACH,mBAAmB,CACjB,QAAQ,EAAE,gBAAgB,EAC1B,KAAK,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,EAClC,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,GACnC,IAAI;IAkBP;;;;;;OAMG;IACH,aAAa,CACX,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,EAAE,eAAe,EACxB,IAAI,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GAC3D,IAAI;IAQP;;;;OAIG;IACH,kBAAkB,IAAI,kBAAkB,EAAE;IAI1C,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAM/D,QAAQ,IAAI,MAAM,EAAE;IAIpB;mEAC+D;IAC/D,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,EAAE;IAIxC;;;gCAG4B;IAC5B,oBAAoB,IAAI,MAAM,EAAE;IAIhC;wEACoE;IACpE,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIhD;;;;;gEAK4D;IAC5D,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS;IA+B7D,qFAAqF;IACrF,QAAQ,IAAI,eAAe;CAG5B"}
@@ -2,6 +2,7 @@ import { AliasResolver } from "./alias-resolver.js";
2
2
  import { KERNEL_BUILTINS } from "./builtins.js";
3
3
  import { DefinitionRegistry } from "./definition-registry.js";
4
4
  import { computeSuggestKind, computeValidUserFacingKinds } from "./kind-suggest.js";
5
+ import { visitManifest as runVisitManifest } from "./manifest-visitor.js";
5
6
  import { isRefEntry, isScopeEntry } from "./reference-field-map.js";
6
7
  /**
7
8
  * Accumulates type and alias knowledge for a running kernel or analysis session.
@@ -46,6 +47,20 @@ export class AnalysisRegistry {
46
47
  }
47
48
  }
48
49
  }
50
+ /**
51
+ * Walks a manifest's annotation sites (refs, scopes, schema-from, CEL) via
52
+ * the shared manifest visitor, bound to this registry's definitions and
53
+ * aliases. The public seam for hosts (editor overview graph, tooling) that
54
+ * need the same site discovery the analyzer's own passes use, without
55
+ * reaching into the internal DefinitionRegistry.
56
+ */
57
+ visitManifest(resources, visitor, opts) {
58
+ runVisitManifest(resources, this.defs, visitor, {
59
+ aliases: this.aliases,
60
+ aliasesByModule: this.aliasesByModule,
61
+ ...opts,
62
+ });
63
+ }
49
64
  /**
50
65
  * Returns the built-in kernel definitions. The underlying DefinitionRegistry already
51
66
  * seeds these on construction; this method exposes them so callers (e.g. the kernel's
@@ -1 +1 @@
1
- {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAIzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAgB9B,OAAO,EAAsB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAif/F,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;gBAEzB,OAAO,GAAE,qBAA0B;IAI/C;;;;;;;;;;;;;;OAcG;IACH,OAAO,CACL,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,kBAAkB,EAAE;IAoiBvB,aAAa,CACX,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,kBAAkB,EAAE;IAMvB,SAAS,CAAC,SAAS,EAAE,gBAAgB,EAAE,EAAE,QAAQ,EAAE,gBAAgB,GAAG,gBAAgB,EAAE;IAexF,OAAO,CACL,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,gBAAgB,GACzB;QAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;CAsB5F"}
1
+ {"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAIzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,sBAAsB,CAAC;AAiB9B,OAAO,EAAsB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AA+c/F,MAAM,WAAW,qBAAqB;IACpC,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;gBAEzB,OAAO,GAAE,qBAA0B;IAI/C;;;;;;;;;;;;;;OAcG;IACH,OAAO,CACL,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,kBAAkB,EAAE;IAyjBvB,aAAa,CACX,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,kBAAkB,EAAE;IAMvB,SAAS,CAAC,SAAS,EAAE,gBAAgB,EAAE,EAAE,QAAQ,EAAE,gBAAgB,GAAG,gBAAgB,EAAE;IAexF,OAAO,CACL,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,gBAAgB,GACzB;QAAE,WAAW,EAAE,kBAAkB,EAAE,CAAC;QAAC,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;QAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE;CAsB5F"}
package/dist/analyzer.js CHANGED
@@ -1,10 +1,11 @@
1
- import { defaultRegistry, walkCelExpressions } from "@telorun/templating";
1
+ import { defaultRegistry, isTaggedSentinel } from "@telorun/templating";
2
2
  import { AliasResolver } from "./alias-resolver.js";
3
3
  import { buildCelEnvironment, buildTypedCelEnvironment, } from "./cel-environment.js";
4
4
  import { DefinitionRegistry } from "./definition-registry.js";
5
5
  import { buildDependencyGraph, formatCycle } from "./dependency-graph.js";
6
6
  import { buildKernelGlobalsSchema, mergeKernelGlobalsIntoContext } from "./kernel-globals.js";
7
7
  import { computeSuggestKind } from "./kind-suggest.js";
8
+ import { visitManifest } from "./manifest-visitor.js";
8
9
  import { isModuleKind } from "./module-kinds.js";
9
10
  import { normalizeInlineResources } from "./normalize-inline-resources.js";
10
11
  import { REF_VALIDATION_SKIP_KINDS } from "./system-kinds.js";
@@ -12,11 +13,12 @@ import { resolveRefSentinels } from "./resolve-ref-sentinels.js";
12
13
  import { rewriteSyntheticOrigins } from "./rewrite-synthetic-origins.js";
13
14
  import { celTypeSatisfiesJsonSchema, substituteCelFields, validateAgainstSchema, } from "./schema-compat.js";
14
15
  import { DiagnosticSeverity } from "./types.js";
15
- import { getManifestItem, pathMatchesScope, resolveContextAnnotations, resolveTypeFieldToSchema, } from "./validate-cel-context.js";
16
+ import { extractContextsFromSchema, getManifestItem, pathMatchesScope, resolveContextAnnotations, resolveTypeFieldToSchema, } from "./validate-cel-context.js";
16
17
  import { validateExtends } from "./validate-extends.js";
17
18
  import { validateNestedInlineResources } from "./validate-nested-inline.js";
18
19
  import { validateProviderCoherence } from "./validate-provider-coherence.js";
19
20
  import { validateReferences } from "./validate-references.js";
21
+ import { validateUnusedDeclarations } from "./validate-unused-declarations.js";
20
22
  import { validateThrowsCoverage } from "./validate-throws-coverage.js";
21
23
  const SELF_PREFIX = "Self.";
22
24
  /**
@@ -142,44 +144,6 @@ function manifestRootForResolver(m, defs, aliases, allManifests) {
142
144
  ...(inputs ? { inputType: inputs } : {}),
143
145
  };
144
146
  }
145
- /**
146
- * Walk a JSON Schema tree and collect all `x-telo-context` annotations,
147
- * returning them as `{ scope, schema }` pairs using JSONPath-style scopes —
148
- * the same format the analyzer uses for CEL context validation.
149
- *
150
- * Result is sorted by scope specificity (longer scope first) so that the
151
- * per-expression resolver's first-match-wins logic picks the most-specific
152
- * context. Without this, a broader ancestor scope (e.g. `$.resources[*]`)
153
- * could shadow a narrower descendant scope whose activation differs.
154
- */
155
- function extractContextsFromSchema(schema, path = "$") {
156
- const all = collectContexts(schema, path);
157
- return all.sort((a, b) => b.scope.length - a.scope.length);
158
- }
159
- function collectContexts(schema, path) {
160
- if (!schema || typeof schema !== "object")
161
- return [];
162
- const results = [];
163
- if (schema["x-telo-context"]) {
164
- results.push({ scope: path, schema: schema["x-telo-context"] });
165
- }
166
- if (schema.properties) {
167
- for (const [key, value] of Object.entries(schema.properties)) {
168
- results.push(...collectContexts(value, `${path}.${key}`));
169
- }
170
- }
171
- if (schema.items && typeof schema.items === "object") {
172
- results.push(...collectContexts(schema.items, `${path}[*]`));
173
- }
174
- for (const key of ["oneOf", "anyOf", "allOf"]) {
175
- if (Array.isArray(schema[key])) {
176
- for (const subschema of schema[key]) {
177
- results.push(...collectContexts(subschema, path));
178
- }
179
- }
180
- }
181
- return results;
182
- }
183
147
  /** Resolve a local `$ref` (only `#/$defs/<name>` form) against the root schema.
184
148
  * Non-refs and unresolved refs pass through unchanged. */
185
149
  function resolveLocalRef(schema, root) {
@@ -347,19 +311,30 @@ const CEL_PURE_RE = /^\s*\$\{\{[^}]*\}\}\s*$/;
347
311
  const CEL_EXPR_RE = /\$\{\{\s*([^}]+?)\s*\}\}/;
348
312
  /** Recursively walk `data`+`schema` together, type-checking every pure CEL template
349
313
  * string via `env.check()`. Returns `SchemaIssue[]` for any type mismatches found. */
350
- function collectCelTypeIssues(data, schema, path, definition, manifest, baseTypedEnv, rootEnv) {
314
+ function collectCelTypeIssues(data, schema, path, definition, manifest, baseTypedEnv, rootEnv, rootModuleManifest) {
351
315
  const issues = [];
352
- if (typeof data === "string" && CEL_PURE_RE.test(data)) {
353
- const exprMatch = data.match(CEL_EXPR_RE);
354
- if (exprMatch) {
355
- const expr = exprMatch[1].trim();
316
+ // A pure CEL value type-checks the same regardless of surface form: a
317
+ // `${{ }}` string and a `!cel`-tagged sentinel must behave identically.
318
+ let celExpr;
319
+ if (isTaggedSentinel(data)) {
320
+ // Non-CEL engines (e.g. `!literal`) are analyzed by their own engine pass.
321
+ if (data.engine !== "cel")
322
+ return issues;
323
+ celExpr = data.source;
324
+ }
325
+ else if (typeof data === "string" && CEL_PURE_RE.test(data)) {
326
+ celExpr = data.match(CEL_EXPR_RE)?.[1]?.trim();
327
+ }
328
+ if (celExpr !== undefined) {
329
+ {
330
+ const expr = celExpr;
356
331
  // Merge x-telo-context variables for this path if applicable
357
332
  let typedEnv = baseTypedEnv;
358
333
  if (definition.schema) {
359
334
  for (const ctx of extractContextsFromSchema(definition.schema)) {
360
335
  if (!pathMatchesScope(path, ctx.scope))
361
336
  continue;
362
- typedEnv = buildTypedCelEnvironment(rootEnv, manifest, ctx.schema);
337
+ typedEnv = buildTypedCelEnvironment(rootEnv, manifest, ctx.schema, rootModuleManifest);
363
338
  break;
364
339
  }
365
340
  }
@@ -382,8 +357,9 @@ function collectCelTypeIssues(data, schema, path, definition, manifest, baseType
382
357
  else if (checkResult?.valid && checkResult.type && schema) {
383
358
  const celType = checkResult.type.split("<")[0];
384
359
  if (!celTypeSatisfiesJsonSchema(celType, schema)) {
360
+ const expected = schema["x-telo-type"] ?? schema.type ?? "unknown";
385
361
  issues.push({
386
- message: `CEL returns '${checkResult.type}' but field expects '${schema.type ?? "unknown"}'`,
362
+ message: `CEL returns '${checkResult.type}' but field expects '${expected}'`,
387
363
  path,
388
364
  });
389
365
  }
@@ -394,13 +370,13 @@ function collectCelTypeIssues(data, schema, path, definition, manifest, baseType
394
370
  if (Array.isArray(data)) {
395
371
  const itemSchema = (schema.items ?? {});
396
372
  for (let i = 0; i < data.length; i++) {
397
- issues.push(...collectCelTypeIssues(data[i], itemSchema, `${path}[${i}]`, definition, manifest, baseTypedEnv, rootEnv));
373
+ issues.push(...collectCelTypeIssues(data[i], itemSchema, `${path}[${i}]`, definition, manifest, baseTypedEnv, rootEnv, rootModuleManifest));
398
374
  }
399
375
  }
400
376
  else if (data !== null && typeof data === "object") {
401
377
  const props = (schema.properties ?? {});
402
378
  for (const [k, v] of Object.entries(data)) {
403
- issues.push(...collectCelTypeIssues(v, (props[k] ?? {}), path ? `${path}.${k}` : k, definition, manifest, baseTypedEnv, rootEnv));
379
+ issues.push(...collectCelTypeIssues(v, (props[k] ?? {}), path ? `${path}.${k}` : k, definition, manifest, baseTypedEnv, rootEnv, rootModuleManifest));
404
380
  }
405
381
  }
406
382
  return issues;
@@ -625,6 +601,11 @@ export class StaticAnalyzer {
625
601
  // Build typed kernel globals schema so x-telo-context chain validation
626
602
  // recognises variables, secrets, resources, env automatically
627
603
  const kernelGlobals = buildKernelGlobalsSchema(allManifests);
604
+ // The module doc (Application/Library) carries the Application-only `ports`
605
+ // namespace; threaded into per-resource CEL typing so `${{ ports.X }}`
606
+ // resolves its nominal brand cross-doc.
607
+ const moduleManifest = allManifests.find((mm) => mm.kind === "Telo.Application") ??
608
+ allManifests.find((mm) => mm.kind === "Telo.Library");
628
609
  // Validate each non-definition, non-system resource
629
610
  for (const m of allManifests) {
630
611
  const filePath = m.metadata?.source;
@@ -678,8 +659,8 @@ export class StaticAnalyzer {
678
659
  }
679
660
  : definition.schema;
680
661
  // Phase 1: CEL type checking — walk data+schema together, check env.check() return types
681
- const baseTypedEnv = buildTypedCelEnvironment(this.celEnv, m);
682
- const celIssues = collectCelTypeIssues(m, schema, "", definition, m, baseTypedEnv, this.celEnv);
662
+ const baseTypedEnv = buildTypedCelEnvironment(this.celEnv, m, undefined, moduleManifest);
663
+ const celIssues = collectCelTypeIssues(m, schema, "", definition, m, baseTypedEnv, this.celEnv, moduleManifest);
683
664
  // Phase 2+3: AJV on substituted data — CEL fields replaced with typed placeholders
684
665
  const ajvIssues = validateAgainstSchema(substituteCelFields(m, schema), schema);
685
666
  const issues = [...celIssues, ...ajvIssues];
@@ -791,42 +772,39 @@ export class StaticAnalyzer {
791
772
  }
792
773
  }
793
774
  }
794
- // Validate CEL syntax and context variable access in all manifests
795
- for (const m of allManifests) {
796
- const resource = { kind: m.kind, name: m.metadata?.name };
797
- const filePath = m.metadata?.source;
798
- const resolvedKind = aliases.resolveKind(m.kind);
799
- const mDefinition = defs.resolve(m.kind) ?? (resolvedKind ? defs.resolve(resolvedKind) : undefined);
800
- // Pre-compute step context for manifests with x-telo-step-context
801
- const stepContextSchema = mDefinition?.schema
802
- ? buildStepContextSchema(m, mDefinition.schema, allManifests, defs, aliases)
803
- : undefined;
804
- walkCelExpressions(m, "", (expr, path, engineName) => {
805
- // Resolve the effective context for this expression's path. The
806
- // engine receives a single closed schema and validates member-access
807
- // chains against it; per-path resolution (step context, x-telo-context,
808
- // kernel-globals merge) stays on the analyzer side because it depends
809
- // on analyzer-internal state (definitions, aliases).
810
- const contexts = mDefinition?.schema ? extractContextsFromSchema(mDefinition.schema) : [];
811
- const invocationContext = m.metadata?.xTeloInvocationContext;
812
- let matchedContext;
813
- let matchedScope;
814
- for (const ctx of contexts) {
815
- if (pathMatchesScope(path, ctx.scope)) {
816
- matchedContext = ctx.schema;
817
- matchedScope = ctx.scope;
818
- break;
819
- }
820
- }
821
- if (!matchedContext)
822
- matchedContext = invocationContext;
823
- if (stepContextSchema) {
775
+ // Validate CEL syntax and context variable access in all manifests. The
776
+ // walker discovers every compiled CEL node by scanning the value tree and
777
+ // hands back the `x-telo-context` schema matched at the enclosing path; the
778
+ // per-path resolution (step context, kernel-globals merge, x-telo-context-*
779
+ // annotation resolution) stays here because it depends on analyzer-internal
780
+ // state (definitions, aliases, the typed CEL env).
781
+ // Per-resource state computed at enter and read by that resource's CEL
782
+ // sites. The manifest / resource / filePath come straight off each CelSite's
783
+ // `source` (no need to capture them); only the derived step / invocation
784
+ // context — which require analyzer state to build — are stashed here.
785
+ let celStepContextSchema;
786
+ let celInvocationContext;
787
+ visitManifest(allManifests, defs, {
788
+ onResourceEnter: (e) => {
789
+ const m = e.source;
790
+ celInvocationContext = m.metadata?.xTeloInvocationContext;
791
+ celStepContextSchema = e.definition?.schema
792
+ ? buildStepContextSchema(m, e.definition.schema, allManifests, defs, aliases)
793
+ : undefined;
794
+ },
795
+ onCel: (e) => {
796
+ const m = e.source;
797
+ const resource = { kind: m.kind, name: m.metadata?.name };
798
+ const filePath = m.metadata?.source;
799
+ const { expr, path, engineName, matchedScope } = e;
800
+ let matchedContext = e.contextSchema ?? celInvocationContext;
801
+ if (celStepContextSchema) {
824
802
  const base = matchedContext ?? { type: "object", properties: {}, additionalProperties: true };
825
803
  matchedContext = {
826
804
  ...base,
827
805
  properties: {
828
806
  ...(base.properties ?? {}),
829
- steps: stepContextSchema,
807
+ steps: celStepContextSchema,
830
808
  },
831
809
  };
832
810
  }
@@ -890,8 +868,8 @@ export class StaticAnalyzer {
890
868
  });
891
869
  }
892
870
  }
893
- });
894
- }
871
+ },
872
+ }, { aliases });
895
873
  // Validate resource references (Phase 3)
896
874
  diagnostics.push(...validateReferences(allManifests, { aliases, definitions: defs, aliasesByModule }));
897
875
  // Validate `extends` fields and flag legacy `capability: <UserAbstract>` overload.
@@ -900,6 +878,8 @@ export class StaticAnalyzer {
900
878
  diagnostics.push(...validateProviderCoherence(allManifests, defs, aliases));
901
879
  // Validate throws: declarations and catches: coverage (rules 1, 2, 4, 7)
902
880
  diagnostics.push(...validateThrowsCoverage(allManifests, defs, aliases, this.celEnv));
881
+ // Warn about declared variables / secrets / ports that no CEL references.
882
+ diagnostics.push(...validateUnusedDeclarations(allManifests, this.celEnv));
903
883
  // Reroute diagnostics on synthetic (inline-extracted) resources back to
904
884
  // the chain root so position-index lookups land on the parent doc.
905
885
  return rewriteSyntheticOrigins(diagnostics, allManifests);
@@ -1 +1 @@
1
- {"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,eAAO,MAAM,eAAe,EAAE,kBAAkB,EAiU/C,CAAC"}
1
+ {"version":3,"file":"builtins.d.ts","sourceRoot":"","sources":["../src/builtins.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,eAAO,MAAM,eAAe,EAAE,kBAAkB,EA0V/C,CAAC"}
package/dist/builtins.js CHANGED
@@ -277,6 +277,31 @@ export const KERNEL_BUILTINS = [
277
277
  },
278
278
  },
279
279
  },
280
+ // Inbound ports the Application listens on. A name-keyed map mirroring
281
+ // `variables`: each entry binds a host env var (`env:`) that supplies a
282
+ // port integer (implicitly typed `integer`, 1–65535), with an optional
283
+ // `default:` used when the env var is unset. `protocol:` (default `tcp`)
284
+ // selects the transport — the runner reads this list to know the
285
+ // exposed ports before launch, and the analyzer brands the resolved
286
+ // `ports.<name>` value (tcp → TcpPort, udp → UdpPort) for static wiring
287
+ // checks. Application-only. See kernel/nodejs/src/application-env.ts.
288
+ ports: {
289
+ type: "object",
290
+ additionalProperties: {
291
+ type: "object",
292
+ required: ["env"],
293
+ properties: {
294
+ env: { type: "string" },
295
+ protocol: {
296
+ type: "string",
297
+ enum: ["tcp", "udp"],
298
+ default: "tcp",
299
+ },
300
+ default: { type: "integer", minimum: 1, maximum: 65535 },
301
+ },
302
+ additionalProperties: false,
303
+ },
304
+ },
280
305
  },
281
306
  required: ["metadata"],
282
307
  additionalProperties: false,
@@ -12,5 +12,5 @@ export type { CelHandlers } from "@telorun/templating";
12
12
  *
13
13
  * NOTE: The set of kernel globals registered here must match `KERNEL_GLOBAL_NAMES`
14
14
  * in kernel-globals.ts, which is used for chain-access validation. */
15
- export declare function buildTypedCelEnvironment(baseEnv: Environment, manifest: ResourceManifest, extraContextSchema?: Record<string, any> | null): Environment;
15
+ export declare function buildTypedCelEnvironment(baseEnv: Environment, manifest: ResourceManifest, extraContextSchema?: Record<string, any> | null, rootModuleManifest?: ResourceManifest): Environment;
16
16
  //# sourceMappingURL=cel-environment.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cel-environment.d.ts","sourceRoot":"","sources":["../src/cel-environment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;;;;;;uEASuE;AACvE,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,gBAAgB,EAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,GAC9C,WAAW,CAyCb"}
1
+ {"version":3,"file":"cel-environment.d.ts","sourceRoot":"","sources":["../src/cel-environment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAUrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD;;;;;;;;;uEASuE;AACvE,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,gBAAgB,EAC1B,kBAAkB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,EAI/C,kBAAkB,CAAC,EAAE,gBAAgB,GACpC,WAAW,CAuEb"}
@@ -1,4 +1,10 @@
1
- import { jsonSchemaToCelType } from "./schema-compat.js";
1
+ import { jsonSchemaToCelType, VALUE_BRAND_BASE } from "./schema-compat.js";
2
+ /** Transport protocol on a `ports` entry → the nominal CEL brand its resolved
3
+ * value carries. Mirrors the `protocol` enum in the Application schema. */
4
+ const PORT_PROTOCOL_BRAND = {
5
+ tcp: "TcpPort",
6
+ udp: "UdpPort",
7
+ };
2
8
  export { buildCelEnvironment } from "@telorun/templating";
3
9
  /** Clone `baseEnv` and register typed variable declarations so that
4
10
  * `env.check(expr)` can infer return types for expressions referencing known variables.
@@ -10,9 +16,21 @@ export { buildCelEnvironment } from "@telorun/templating";
10
16
  *
11
17
  * NOTE: The set of kernel globals registered here must match `KERNEL_GLOBAL_NAMES`
12
18
  * in kernel-globals.ts, which is used for chain-access validation. */
13
- export function buildTypedCelEnvironment(baseEnv, manifest, extraContextSchema) {
19
+ export function buildTypedCelEnvironment(baseEnv, manifest, extraContextSchema,
20
+ // The `ports` namespace is Application-only and lives on the module doc, not
21
+ // on the resource being analyzed. When validating a resource, the caller
22
+ // passes the module manifest here so `${{ ports.X }}` types cross-doc.
23
+ rootModuleManifest) {
14
24
  try {
15
25
  const env = baseEnv.clone();
26
+ // Register nominal value brands (TcpPort/UdpPort/…) on the *clone* so the
27
+ // type-checker can distinguish structurally-identical values. The base env
28
+ // (shared with the kernel runtime) is untouched — a branded value flows as
29
+ // a plain integer at runtime, so only static checking needs these. cel-js
30
+ // auto-generates a field-less wrapper class; no runtime constructor needed.
31
+ for (const brand of Object.keys(VALUE_BRAND_BASE)) {
32
+ env.registerType(brand, { fields: {} });
33
+ }
16
34
  // Build typed ObjectSchema from manifest.variables if it looks like a schema map
17
35
  const vars = manifest.variables;
18
36
  if (vars !== null && typeof vars === "object" && !Array.isArray(vars)) {
@@ -31,6 +49,26 @@ export function buildTypedCelEnvironment(baseEnv, manifest, extraContextSchema)
31
49
  else {
32
50
  env.registerVariable("variables", "map");
33
51
  }
52
+ // `ports` namespace: each entry types as the brand its `protocol` selects
53
+ // (tcp → TcpPort, udp → UdpPort), so `${{ ports.http }}` carries a nominal
54
+ // type that consuming fields can check against.
55
+ const portsManifest = (rootModuleManifest ?? manifest).ports;
56
+ if (portsManifest !== null && typeof portsManifest === "object" && !Array.isArray(portsManifest)) {
57
+ const portEntries = Object.entries(portsManifest).filter(([, v]) => v !== null && typeof v === "object" && !Array.isArray(v));
58
+ if (portEntries.length > 0) {
59
+ const schema = {};
60
+ for (const [k, v] of portEntries) {
61
+ schema[k] = PORT_PROTOCOL_BRAND[v.protocol ?? "tcp"] ?? "int";
62
+ }
63
+ env.registerVariable({ name: "ports", schema });
64
+ }
65
+ else {
66
+ env.registerVariable("ports", "map");
67
+ }
68
+ }
69
+ else {
70
+ env.registerVariable("ports", "map");
71
+ }
34
72
  env.registerVariable("secrets", "map");
35
73
  env.registerVariable("resources", "map");
36
74
  env.registerVariable("env", "map");
@@ -1 +1 @@
1
- {"version":3,"file":"dependency-graph.d.ts","sourceRoot":"","sources":["../src/dependency-graph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAInE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B;kDAC8C;IAC9C,KAAK,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACpC;oFACgF;IAChF,KAAK,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;CACrC;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,CAAC,EAAE,aAAa,EACvB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GAC3C,eAAe,CAkHjB;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,MAAM,CAOtE"}
1
+ {"version":3,"file":"dependency-graph.d.ts","sourceRoot":"","sources":["../src/dependency-graph.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAInE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B;kDAC8C;IAC9C,KAAK,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;IACpC;oFACgF;IAChF,KAAK,CAAC,EAAE,aAAa,CAAC,YAAY,CAAC,CAAC;CACrC;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,gBAAgB,EAAE,EAC7B,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,CAAC,EAAE,aAAa,EACvB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GAC3C,eAAe,CAmGjB;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,aAAa,CAAC,YAAY,CAAC,GAAG,MAAM,CAOtE"}
@@ -1,5 +1,5 @@
1
1
  import { isRefSentinel } from "@telorun/templating";
2
- import { isRefEntry, isScopeEntry, resolveFieldValues } from "./reference-field-map.js";
2
+ import { visitManifest } from "./manifest-visitor.js";
3
3
  import { DEPENDENCY_GRAPH_SKIP_KINDS as SYSTEM_KINDS } from "./system-kinds.js";
4
4
  const nodeKey = (kind, name) => `${kind}\0${name}`;
5
5
  /**
@@ -33,68 +33,47 @@ export function buildDependencyGraph(resources, registry, aliases, aliasesByModu
33
33
  const deps = new Map();
34
34
  for (const key of nodes.keys())
35
35
  deps.set(key, new Set());
36
- for (const r of resources) {
37
- if (!r.metadata?.name || !r.kind || SYSTEM_KINDS.has(r.kind))
38
- continue;
39
- const sourceKey = nodeKey(r.kind, r.metadata.name);
40
- // Use the expanded map so refs nested behind x-telo-schema-from contribute
41
- // edges to the DAG. Without these, a parent (e.g. Http.Server) can init
42
- // before its extracted encoder and Phase 5 injection fires against a
43
- // not-yet-created dependency.
44
- const fieldMap = aliases && aliasesByModule
45
- ? registry.expandedFieldMapForResource(r, aliases, aliasesByModule)
46
- : registry.getFieldMapForKind(r.kind, aliases);
47
- if (!fieldMap)
48
- continue;
49
- // Collect names of resources declared inside scope fields — these are initialized
50
- // on-demand at runtime, not at boot, so edges pointing to them are excluded from the DAG.
51
- const scopedNames = new Set();
52
- for (const [scopeFieldPath, entry] of fieldMap) {
53
- if (!isScopeEntry(entry))
54
- continue;
55
- const scopeVal = r[scopeFieldPath];
56
- if (!Array.isArray(scopeVal))
57
- continue;
58
- for (const item of scopeVal) {
59
- const name = item?.metadata?.name;
60
- if (typeof name === "string")
61
- scopedNames.add(name);
36
+ // Names of resources declared inside the *current* resource's scope fields —
37
+ // initialized on-demand at runtime, not at boot, so edges pointing to them
38
+ // are excluded. Scoping is per-source-resource: an edge A → B is dropped only
39
+ // when B is declared inside A's own scope (the visitor's ScopeBoundary fires
40
+ // before that resource's RefSites, so this is set before any edge is added).
41
+ let scopedNames = new Set();
42
+ // Expanded map so refs nested behind x-telo-schema-from contribute edges to
43
+ // the DAG. Without these, a parent (e.g. Http.Server) can init before its
44
+ // extracted encoder and Phase 5 injection fires against a not-yet-created
45
+ // dependency.
46
+ visitManifest(resources, registry, {
47
+ onScope: (e) => {
48
+ scopedNames = e.enclosedNames;
49
+ },
50
+ onRef: (e) => {
51
+ const sourceKey = nodeKey(e.source.kind, e.source.metadata.name);
52
+ const val = e.value;
53
+ // `!ref <name>` sentinel — look up the target's kind from the name
54
+ // (resources are unique by name) so the edge carries the concrete kind,
55
+ // matching the {kind, name} edge shape below.
56
+ if (isRefSentinel(val)) {
57
+ const refName = val.source;
58
+ if (scopedNames.has(refName))
59
+ return;
60
+ const node = nodesByName.get(refName);
61
+ if (node)
62
+ deps.get(sourceKey).add(nodeKey(node.kind, node.name));
63
+ return;
62
64
  }
63
- }
64
- for (const [fieldPath, entry] of fieldMap) {
65
- if (!isRefEntry(entry))
66
- continue;
67
- for (const val of resolveFieldValues(r, fieldPath)) {
68
- if (!val)
69
- continue;
70
- // `!ref <name>` sentinel — look up the target's kind from the
71
- // name (resources are unique by name) so the edge carries the
72
- // concrete kind, matching the {kind, name} edge shape below.
73
- if (isRefSentinel(val)) {
74
- const refName = val.source;
75
- if (scopedNames.has(refName))
76
- continue;
77
- const node = nodesByName.get(refName);
78
- if (node) {
79
- deps.get(sourceKey).add(nodeKey(node.kind, node.name));
80
- }
81
- continue;
82
- }
83
- if (typeof val !== "object")
84
- continue;
85
- const ref = val;
86
- if (!ref.kind || !ref.name)
87
- continue;
88
- // Edges to scoped resources are runtime deps, not boot-time deps — exclude from DAG
89
- if (scopedNames.has(ref.name))
90
- continue;
91
- const targetKey = nodeKey(ref.kind, ref.name);
92
- if (nodes.has(targetKey)) {
93
- deps.get(sourceKey).add(targetKey);
94
- }
95
- }
96
- }
97
- }
65
+ if (typeof val !== "object")
66
+ return;
67
+ const ref = val;
68
+ if (!ref.kind || !ref.name)
69
+ return;
70
+ if (scopedNames.has(ref.name))
71
+ return;
72
+ const targetKey = nodeKey(ref.kind, ref.name);
73
+ if (nodes.has(targetKey))
74
+ deps.get(sourceKey).add(targetKey);
75
+ },
76
+ }, { aliases, aliasesByModule, skipKinds: SYSTEM_KINDS, expand: true });
98
77
  // --- Kahn's topological sort ---
99
78
  // in-degree[X] = number of X's dependencies (size of deps[X])
100
79
  // reverse[dep] = set of nodes that depend on dep (for degree decrement)
package/dist/index.d.ts CHANGED
@@ -2,6 +2,8 @@ export { AnalysisRegistry } from "./analysis-registry.js";
2
2
  export { StaticAnalyzer } from "./analyzer.js";
3
3
  export type { GraphLoadError, ImportEdge, LoadedFile, LoadedGraph, LoadedModule, ParseError, } from "./loaded-types.js";
4
4
  export { flattenForAnalyzer, flattenLoadedModule } from "./flatten-for-analyzer.js";
5
+ export { visitManifest } from "./manifest-visitor.js";
6
+ export type { CelSiteEvent, ManifestVisitor, RefSiteEvent, ResourceEnterEvent, ResourceExitEvent, ScopeBoundaryEvent, SchemaFromSiteEvent, VisitOptions, } from "./manifest-visitor.js";
5
7
  export { Loader } from "./manifest-loader.js";
6
8
  export { isModuleKind, MODULE_KINDS } from "./module-kinds.js";
7
9
  export type { ModuleKind } from "./module-kinds.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EACR,cAAc,EACd,UAAU,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,UAAU,GACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC/D,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EACH,sBAAsB,EACtB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,GACtB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC3E,YAAY,EACR,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,cAAc,EACd,QAAQ,EACR,aAAa,EACb,KAAK,EACR,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EACR,cAAc,EACd,UAAU,EACV,UAAU,EACV,WAAW,EACX,YAAY,EACZ,UAAU,GACb,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACpF,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACtD,YAAY,EACR,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EAClB,mBAAmB,EACnB,YAAY,GACf,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC/D,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AACnF,OAAO,EACH,sBAAsB,EACtB,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,GACtB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,yBAAyB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAC3E,YAAY,EACR,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,cAAc,EACd,QAAQ,EACR,aAAa,EACb,KAAK,EACR,MAAM,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export { AnalysisRegistry } from "./analysis-registry.js";
2
2
  export { StaticAnalyzer } from "./analyzer.js";
3
3
  export { flattenForAnalyzer, flattenLoadedModule } from "./flatten-for-analyzer.js";
4
+ export { visitManifest } from "./manifest-visitor.js";
4
5
  export { Loader } from "./manifest-loader.js";
5
6
  export { isModuleKind, MODULE_KINDS } from "./module-kinds.js";
6
7
  export { parseLoadedFile } from "./parse-loaded-file.js";
@@ -10,7 +10,7 @@ import type { ResourceManifest } from "@telorun/sdk";
10
10
  * There is no `imports` namespace at runtime — import snapshots are stored
11
11
  * under `resources.<alias>`.
12
12
  */
13
- export declare const KERNEL_GLOBAL_NAMES: readonly ["variables", "secrets", "resources", "env"];
13
+ export declare const KERNEL_GLOBAL_NAMES: readonly ["variables", "secrets", "resources", "ports", "env"];
14
14
  /**
15
15
  * Build a typed JSON Schema describing the kernel globals available in the
16
16
  * given manifest set. Used to merge into `x-telo-context` schemas so that
@@ -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;AAGrD;;;;;;;;;;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;AAwBD;;;;;;;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;AAGrD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,mBAAmB,gEAAiE,CAAC;AASlG;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,gBAAgB,EAAE,GAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAkCrB;AA4CD;;;;;;;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"}