@telorun/analyzer 0.11.0 → 0.12.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 (92) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +3 -3
  3. package/dist/adapters/http-adapter.d.ts +10 -0
  4. package/dist/adapters/http-adapter.d.ts.map +1 -0
  5. package/dist/adapters/http-adapter.js +18 -0
  6. package/dist/adapters/node-adapter.d.ts +17 -0
  7. package/dist/adapters/node-adapter.d.ts.map +1 -0
  8. package/dist/adapters/node-adapter.js +71 -0
  9. package/dist/adapters/registry-adapter.d.ts +15 -0
  10. package/dist/adapters/registry-adapter.d.ts.map +1 -0
  11. package/dist/adapters/registry-adapter.js +53 -0
  12. package/dist/analysis-registry.d.ts +7 -0
  13. package/dist/analysis-registry.d.ts.map +1 -1
  14. package/dist/analysis-registry.js +38 -0
  15. package/dist/analyzer.d.ts +15 -0
  16. package/dist/analyzer.d.ts.map +1 -1
  17. package/dist/analyzer.js +114 -10
  18. package/dist/builtins.d.ts.map +1 -1
  19. package/dist/builtins.js +58 -1
  20. package/dist/definition-registry.d.ts.map +1 -1
  21. package/dist/definition-registry.js +16 -0
  22. package/dist/dependency-graph.d.ts.map +1 -1
  23. package/dist/dependency-graph.js +27 -13
  24. package/dist/index.d.ts +2 -0
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +2 -0
  27. package/dist/kernel-globals.d.ts.map +1 -1
  28. package/dist/kernel-globals.js +9 -11
  29. package/dist/manifest-loader.d.ts +23 -1
  30. package/dist/manifest-loader.d.ts.map +1 -1
  31. package/dist/manifest-loader.js +66 -3
  32. package/dist/normalize-inline-resources.d.ts.map +1 -1
  33. package/dist/normalize-inline-resources.js +26 -14
  34. package/dist/position-metadata.d.ts +11 -2
  35. package/dist/position-metadata.d.ts.map +1 -1
  36. package/dist/position-metadata.js +18 -3
  37. package/dist/precompile.d.ts.map +1 -1
  38. package/dist/precompile.js +9 -1
  39. package/dist/reference-field-map.d.ts +21 -4
  40. package/dist/reference-field-map.d.ts.map +1 -1
  41. package/dist/reference-field-map.js +93 -25
  42. package/dist/residual-schema.d.ts +23 -0
  43. package/dist/residual-schema.d.ts.map +1 -0
  44. package/dist/residual-schema.js +45 -0
  45. package/dist/resolve-ref-sentinels.d.ts +27 -0
  46. package/dist/resolve-ref-sentinels.d.ts.map +1 -0
  47. package/dist/resolve-ref-sentinels.js +114 -0
  48. package/dist/rewrite-synthetic-origins.d.ts +10 -0
  49. package/dist/rewrite-synthetic-origins.d.ts.map +1 -0
  50. package/dist/rewrite-synthetic-origins.js +55 -0
  51. package/dist/schema-compat.d.ts +7 -1
  52. package/dist/schema-compat.d.ts.map +1 -1
  53. package/dist/schema-compat.js +19 -2
  54. package/dist/system-kinds.d.ts +25 -0
  55. package/dist/system-kinds.d.ts.map +1 -0
  56. package/dist/system-kinds.js +34 -0
  57. package/dist/types.d.ts +12 -0
  58. package/dist/types.d.ts.map +1 -1
  59. package/dist/validate-cel-context.d.ts +5 -0
  60. package/dist/validate-cel-context.d.ts.map +1 -1
  61. package/dist/validate-cel-context.js +27 -15
  62. package/dist/validate-provider-coherence.d.ts +23 -0
  63. package/dist/validate-provider-coherence.d.ts.map +1 -0
  64. package/dist/validate-provider-coherence.js +148 -0
  65. package/dist/validate-references.d.ts.map +1 -1
  66. package/dist/validate-references.js +141 -36
  67. package/dist/with-synthetic-positions.d.ts +28 -0
  68. package/dist/with-synthetic-positions.d.ts.map +1 -0
  69. package/dist/with-synthetic-positions.js +45 -0
  70. package/package.json +7 -4
  71. package/src/analysis-registry.ts +37 -0
  72. package/src/analyzer.ts +118 -12
  73. package/src/builtins.ts +58 -1
  74. package/src/definition-registry.ts +15 -0
  75. package/src/dependency-graph.ts +27 -14
  76. package/src/index.ts +2 -0
  77. package/src/kernel-globals.ts +9 -11
  78. package/src/manifest-loader.ts +69 -4
  79. package/src/normalize-inline-resources.ts +48 -13
  80. package/src/position-metadata.ts +18 -3
  81. package/src/precompile.ts +8 -1
  82. package/src/reference-field-map.ts +129 -24
  83. package/src/residual-schema.ts +49 -0
  84. package/src/resolve-ref-sentinels.ts +127 -0
  85. package/src/rewrite-synthetic-origins.ts +75 -0
  86. package/src/schema-compat.ts +19 -2
  87. package/src/system-kinds.ts +37 -0
  88. package/src/types.ts +12 -0
  89. package/src/validate-cel-context.ts +28 -15
  90. package/src/validate-provider-coherence.ts +166 -0
  91. package/src/validate-references.ts +138 -35
  92. package/src/with-synthetic-positions.ts +48 -0
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  # SUSTAINABLE USE LICENSE (Fair-code)
2
2
 
3
- Copyright (c) 2026 DiglyAI
3
+ Copyright (c) 2026 CodeNet Sp. z o.o.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to use, copy, modify, and distribute the Software for any purpose—including commercial purposes—subject to the following conditions:
6
6
 
@@ -14,4 +14,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
14
14
 
15
15
  5. DISCLAIMER: The Software is provided "as is", without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the Software or the use or other dealings in the Software.
16
16
 
17
- For commercial licensing, managed hosting exemptions, or enterprise inquiries, please contact DiglyAI.
17
+ For commercial licensing, managed hosting exemptions, or enterprise inquiries, please contact <contact@codenet.pl>.
package/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  <p align="center">
2
- <img src="./assets/telo.png" alt="Telo" width="200" />
2
+ <img src="https://raw.githubusercontent.com/telorun/telo/main/assets/telo.png" alt="Telo" width="200" />
3
3
  </p>
4
4
 
5
5
  <h1 align="center">Telo</h1>
@@ -61,12 +61,12 @@ targets:
61
61
  kind: Telo.Import
62
62
  metadata:
63
63
  name: Http
64
- source: ../modules/http-server
64
+ source: std/http-server@0.4.0
65
65
  ---
66
66
  kind: Telo.Import
67
67
  metadata:
68
68
  name: Sql
69
- source: ../modules/sql
69
+ source: std/sql@0.2.3
70
70
  ---
71
71
  # SQLite database — swap driver/host/database for PostgreSQL with zero YAML changes
72
72
  kind: Sql.Connection
@@ -0,0 +1,10 @@
1
+ import { type ManifestAdapter } from "../types.js";
2
+ export declare class HttpAdapter implements ManifestAdapter {
3
+ supports(url: string): boolean;
4
+ read(url: string): Promise<{
5
+ text: string;
6
+ source: string;
7
+ }>;
8
+ resolveRelative(base: string, relative: string): string;
9
+ }
10
+ //# sourceMappingURL=http-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/http-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAE9E,qBAAa,WAAY,YAAW,eAAe;IACjD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIxB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAWlE,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;CAIxD"}
@@ -0,0 +1,18 @@
1
+ import { DEFAULT_MANIFEST_FILENAME } from "../types.js";
2
+ export class HttpAdapter {
3
+ supports(url) {
4
+ return url.startsWith("http://") || url.startsWith("https://");
5
+ }
6
+ async read(url) {
7
+ const fetchUrl = url.includes(".yaml") ? url : `${url}/${DEFAULT_MANIFEST_FILENAME}`;
8
+ const response = await fetch(fetchUrl);
9
+ if (!response.ok) {
10
+ throw new Error(`Failed to fetch manifest from ${fetchUrl}: ${response.status} ${response.statusText}`);
11
+ }
12
+ return { text: await response.text(), source: fetchUrl };
13
+ }
14
+ resolveRelative(base, relative) {
15
+ const baseDir = base.endsWith("/") ? base : base.slice(0, base.lastIndexOf("/") + 1);
16
+ return new URL(relative, baseDir).href;
17
+ }
18
+ }
@@ -0,0 +1,17 @@
1
+ import { type ManifestAdapter } from "../types.js";
2
+ /** Node.js fs-based ManifestAdapter for local files. Not browser-compatible. */
3
+ export declare class NodeAdapter implements ManifestAdapter {
4
+ private readonly cwd;
5
+ constructor(cwd?: string);
6
+ supports(url: string): boolean;
7
+ read(url: string): Promise<{
8
+ text: string;
9
+ source: string;
10
+ }>;
11
+ resolveRelative(base: string, relative: string): string;
12
+ expandGlob(base: string, patterns: string[]): Promise<string[]>;
13
+ resolveOwnerOf(fileUrl: string): Promise<string | null>;
14
+ }
15
+ /** @deprecated Use `new NodeAdapter(cwd)` instead */
16
+ export declare function createNodeAdapter(cwd?: string): ManifestAdapter;
17
+ //# sourceMappingURL=node-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/node-adapter.ts"],"names":[],"mappings":"AAIA,OAAO,EAA6B,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAM9E,gFAAgF;AAChF,qBAAa,WAAY,YAAW,eAAe;IACrC,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,GAAE,MAAsB;IAExD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAUxB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IASlE,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAKjD,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAc/D,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAoB9D;AAED,qDAAqD;AACrD,wBAAgB,iBAAiB,CAAC,GAAG,GAAE,MAAsB,GAAG,eAAe,CAE9E"}
@@ -0,0 +1,71 @@
1
+ import * as fs from "fs/promises";
2
+ import * as path from "path";
3
+ import { fileURLToPath } from "url";
4
+ import { minimatch } from "minimatch";
5
+ import { DEFAULT_MANIFEST_FILENAME } from "../types.js";
6
+ function toFilePath(url) {
7
+ return url.startsWith("file://") ? fileURLToPath(url) : url;
8
+ }
9
+ /** Node.js fs-based ManifestAdapter for local files. Not browser-compatible. */
10
+ export class NodeAdapter {
11
+ cwd;
12
+ constructor(cwd = process.cwd()) {
13
+ this.cwd = cwd;
14
+ }
15
+ supports(url) {
16
+ return (url.startsWith("file://") ||
17
+ url.startsWith("/") ||
18
+ url.startsWith("./") ||
19
+ url.startsWith("../") ||
20
+ (!url.includes("://") && !url.includes("@")));
21
+ }
22
+ async read(url) {
23
+ const filePath = toFilePath(url);
24
+ const stat = await fs.stat(filePath).catch(() => null);
25
+ const resolvedPath = stat?.isDirectory() ? path.join(filePath, DEFAULT_MANIFEST_FILENAME) : filePath;
26
+ const text = await fs.readFile(resolvedPath, "utf8");
27
+ return { text, source: resolvedPath };
28
+ }
29
+ resolveRelative(base, relative) {
30
+ const baseDir = path.dirname(path.resolve(this.cwd, toFilePath(base)));
31
+ return path.resolve(baseDir, relative);
32
+ }
33
+ async expandGlob(base, patterns) {
34
+ const baseDir = path.dirname(path.resolve(this.cwd, toFilePath(base)));
35
+ const entries = await fs.readdir(baseDir, { recursive: true, encoding: "utf8" });
36
+ const normalizedPatterns = patterns.map((p) => p.replace(/\\/g, "/").replace(/^\.\//, ""));
37
+ const matched = [];
38
+ for (const entry of entries) {
39
+ const normalized = entry.replace(/\\/g, "/");
40
+ if (normalizedPatterns.some((p) => minimatch(normalized, p))) {
41
+ matched.push(path.resolve(baseDir, entry));
42
+ }
43
+ }
44
+ return matched.sort();
45
+ }
46
+ async resolveOwnerOf(fileUrl) {
47
+ const resolved = path.resolve(this.cwd, toFilePath(fileUrl));
48
+ let dir = path.dirname(resolved);
49
+ while (true) {
50
+ const candidate = path.join(dir, DEFAULT_MANIFEST_FILENAME);
51
+ if (candidate !== resolved) {
52
+ try {
53
+ await fs.access(candidate);
54
+ return candidate;
55
+ }
56
+ catch {
57
+ // telo.yaml not found at this level
58
+ }
59
+ }
60
+ const parent = path.dirname(dir);
61
+ if (parent === dir)
62
+ break;
63
+ dir = parent;
64
+ }
65
+ return null;
66
+ }
67
+ }
68
+ /** @deprecated Use `new NodeAdapter(cwd)` instead */
69
+ export function createNodeAdapter(cwd = process.cwd()) {
70
+ return new NodeAdapter(cwd);
71
+ }
@@ -0,0 +1,15 @@
1
+ import { type ManifestAdapter } from "../types.js";
2
+ export declare class RegistryAdapter implements ManifestAdapter {
3
+ private registryUrl;
4
+ constructor(registryUrl?: string);
5
+ supports(url: string): boolean;
6
+ read(moduleRef: string): Promise<{
7
+ text: string;
8
+ source: string;
9
+ }>;
10
+ resolveRelative(base: string, relative: string): string;
11
+ private toRegistryModuleBase;
12
+ private toRegistryUrl;
13
+ private parseModuleRef;
14
+ }
15
+ //# sourceMappingURL=registry-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/registry-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAI9E,qBAAa,eAAgB,YAAW,eAAe;IACzC,OAAO,CAAC,WAAW;gBAAX,WAAW,SAAuB;IAEtD,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAWxB,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAWxE,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAMvD,OAAO,CAAC,oBAAoB;IAM5B,OAAO,CAAC,aAAa;IAIrB,OAAO,CAAC,cAAc;CAmBvB"}
@@ -0,0 +1,53 @@
1
+ import { DEFAULT_MANIFEST_FILENAME } from "../types.js";
2
+ const DEFAULT_REGISTRY_URL = "https://registry.telo.run";
3
+ export class RegistryAdapter {
4
+ registryUrl;
5
+ constructor(registryUrl = DEFAULT_REGISTRY_URL) {
6
+ this.registryUrl = registryUrl;
7
+ }
8
+ supports(url) {
9
+ return (!url.startsWith("http://") &&
10
+ !url.startsWith("https://") &&
11
+ !url.startsWith("/") &&
12
+ !url.startsWith(".") &&
13
+ url.includes("@") &&
14
+ url.includes("/"));
15
+ }
16
+ async read(moduleRef) {
17
+ const fetchUrl = this.toRegistryUrl(moduleRef);
18
+ const response = await fetch(fetchUrl);
19
+ if (!response.ok) {
20
+ throw new Error(`Failed to fetch manifest ${moduleRef}: ${response.status} ${response.statusText}`);
21
+ }
22
+ return { text: await response.text(), source: fetchUrl };
23
+ }
24
+ resolveRelative(base, relative) {
25
+ const baseUrl = this.supports(base) ? this.toRegistryModuleBase(base) : base;
26
+ const baseWithSlash = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
27
+ return new URL(relative, baseWithSlash).href;
28
+ }
29
+ toRegistryModuleBase(moduleRef) {
30
+ const parsed = this.parseModuleRef(moduleRef);
31
+ const normalizedBase = this.registryUrl.replace(/\/+$/, "");
32
+ return `${normalizedBase}/${parsed.modulePath}/${parsed.version}`;
33
+ }
34
+ toRegistryUrl(moduleRef) {
35
+ return `${this.toRegistryModuleBase(moduleRef)}/${DEFAULT_MANIFEST_FILENAME}`;
36
+ }
37
+ parseModuleRef(moduleRef) {
38
+ const atIdx = moduleRef.lastIndexOf("@");
39
+ if (atIdx <= 0 || atIdx === moduleRef.length - 1) {
40
+ throw new Error(`Invalid module reference '${moduleRef}', expected namespace/name@version`);
41
+ }
42
+ const modulePath = moduleRef.slice(0, atIdx);
43
+ if (!modulePath.includes("/")) {
44
+ throw new Error(`Invalid module reference '${moduleRef}', expected namespace/name@version`);
45
+ }
46
+ const rawVersion = moduleRef.slice(atIdx + 1);
47
+ const version = rawVersion.startsWith("v") ? rawVersion.substring(1) : rawVersion;
48
+ if (!version) {
49
+ throw new Error(`Invalid module reference '${moduleRef}', expected namespace/name@version`);
50
+ }
51
+ return { modulePath, version };
52
+ }
53
+ }
@@ -41,6 +41,13 @@ export declare class AnalysisRegistry {
41
41
  /** Returns the closest user-facing kind to `badKind`, or undefined when nothing
42
42
  * is close enough (or multiple candidates tie). Case-sensitive. */
43
43
  suggestKind(badKind: string): string | undefined;
44
+ /** Returns every user-facing (alias-form) kind that satisfies the given
45
+ * `x-telo-ref` constraint string (e.g. `"telo#Invocable"`, `"std/sql#Connection"`).
46
+ * Resolution mirrors `validateReferences.checkKind`: abstract targets expand to
47
+ * the set of definitions extending them; concrete targets yield just themselves.
48
+ * Returns `undefined` when the ref can't be resolved (e.g. unregistered identity),
49
+ * so callers can fall back to the unfiltered kind list. */
50
+ userFacingKindsForRef(xTeloRef: string): string[] | undefined;
44
51
  /** @internal Bridge for StaticAnalyzer — do not use outside the analyzer package. */
45
52
  _context(): AnalysisContext;
46
53
  }
@@ -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,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;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"}
@@ -79,6 +79,44 @@ export class AnalysisRegistry {
79
79
  suggestKind(badKind) {
80
80
  return computeSuggestKind(badKind, this.aliases, this.defs);
81
81
  }
82
+ /** Returns every user-facing (alias-form) kind that satisfies the given
83
+ * `x-telo-ref` constraint string (e.g. `"telo#Invocable"`, `"std/sql#Connection"`).
84
+ * Resolution mirrors `validateReferences.checkKind`: abstract targets expand to
85
+ * the set of definitions extending them; concrete targets yield just themselves.
86
+ * Returns `undefined` when the ref can't be resolved (e.g. unregistered identity),
87
+ * so callers can fall back to the unfiltered kind list. */
88
+ userFacingKindsForRef(xTeloRef) {
89
+ const targetKind = this.defs.resolveRef(xTeloRef);
90
+ if (!targetKind)
91
+ return undefined;
92
+ const targetDef = this.defs.resolve(targetKind);
93
+ if (!targetDef)
94
+ return undefined;
95
+ const canonicalKinds = [];
96
+ if (targetDef.kind === "Telo.Abstract") {
97
+ for (const def of this.defs.getByExtends(targetKind)) {
98
+ const module = def.metadata?.module;
99
+ if (module && def.metadata?.name) {
100
+ canonicalKinds.push(`${module}.${def.metadata.name}`);
101
+ }
102
+ }
103
+ }
104
+ else {
105
+ canonicalKinds.push(targetKind);
106
+ }
107
+ const out = new Set();
108
+ for (const kind of canonicalKinds) {
109
+ const dot = kind.indexOf(".");
110
+ if (dot === -1)
111
+ continue;
112
+ const moduleName = kind.slice(0, dot);
113
+ const typeName = kind.slice(dot + 1);
114
+ for (const alias of this.aliases.aliasesFor(moduleName)) {
115
+ out.add(`${alias}.${typeName}`);
116
+ }
117
+ }
118
+ return Array.from(out);
119
+ }
82
120
  /** @internal Bridge for StaticAnalyzer — do not use outside the analyzer package. */
83
121
  _context() {
84
122
  return { aliases: this.aliases, definitions: this.defs, aliasesByModule: this.aliasesByModule };
@@ -8,6 +8,21 @@ export interface StaticAnalyzerOptions {
8
8
  export declare class StaticAnalyzer {
9
9
  private readonly celEnv;
10
10
  constructor(options?: StaticAnalyzerOptions);
11
+ /**
12
+ * Run static analysis over a flattened manifest list.
13
+ *
14
+ * **Contract**: every non-system manifest (anything outside `Telo.Definition`,
15
+ * `Telo.Abstract`) must carry `metadata.source` (non-empty string) and
16
+ * `metadata.sourceLine` (number). The dedup that backs
17
+ * `DUPLICATE_RESOURCE_NAME` reads those fields to tell a pipeline echo
18
+ * apart from a genuine collision, and downstream diagnostic positioning
19
+ * depends on them too. Real callers stamp positions already (the `Loader`,
20
+ * `flattenForAnalyzer`, the telo-editor's `emitDocsFor`, the VSCode
21
+ * extension). Programmatic callers — tests, ad-hoc scripts — should pass
22
+ * their inputs through `withSyntheticPositions(...)` before calling
23
+ * `analyze()`. A missing position throws a clear error rather than
24
+ * silently producing wrong diagnostics.
25
+ */
11
26
  analyze(manifests: ResourceManifest[], options?: AnalysisOptions, registry?: AnalysisRegistry): AnalysisDiagnostic[];
12
27
  analyzeErrors(manifests: ResourceManifest[], options?: AnalysisOptions, registry?: AnalysisRegistry): AnalysisDiagnostic[];
13
28
  normalize(manifests: ResourceManifest[], registry: AnalysisRegistry): ResourceManifest[];
@@ -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;AAa9B,OAAO,EAAsB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AA8c/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,OAAO,CACL,SAAS,EAAE,gBAAgB,EAAE,EAC7B,OAAO,CAAC,EAAE,eAAe,EACzB,QAAQ,CAAC,EAAE,gBAAgB,GAC1B,kBAAkB,EAAE;IA6avB,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;IAUxF,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;AAgB9B,OAAO,EAAsB,KAAK,kBAAkB,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAgf/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;IA8dvB,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
@@ -7,13 +7,49 @@ import { buildKernelGlobalsSchema, mergeKernelGlobalsIntoContext } from "./kerne
7
7
  import { computeSuggestKind } from "./kind-suggest.js";
8
8
  import { isModuleKind } from "./module-kinds.js";
9
9
  import { normalizeInlineResources } from "./normalize-inline-resources.js";
10
+ import { REF_VALIDATION_SKIP_KINDS } from "./system-kinds.js";
11
+ import { resolveRefSentinels } from "./resolve-ref-sentinels.js";
12
+ import { rewriteSyntheticOrigins } from "./rewrite-synthetic-origins.js";
10
13
  import { celTypeSatisfiesJsonSchema, substituteCelFields, validateAgainstSchema, } from "./schema-compat.js";
11
14
  import { DiagnosticSeverity } from "./types.js";
12
15
  import { getManifestItem, pathMatchesScope, resolveContextAnnotations, resolveTypeFieldToSchema, } from "./validate-cel-context.js";
13
16
  import { validateExtends } from "./validate-extends.js";
17
+ import { validateProviderCoherence } from "./validate-provider-coherence.js";
14
18
  import { validateReferences } from "./validate-references.js";
15
19
  import { validateThrowsCoverage } from "./validate-throws-coverage.js";
16
20
  const SELF_PREFIX = "Self.";
21
+ /**
22
+ * `StaticAnalyzer.analyze()` requires `metadata.source` (non-empty) and
23
+ * `metadata.sourceLine` (number) on every non-system manifest — see the
24
+ * JSDoc on `analyze()`. Production callers stamp these via the `Loader` /
25
+ * `flattenForAnalyzer` / `emitDocsFor` paths; programmatic callers (tests,
26
+ * scripts) should pre-process inputs with `withSyntheticPositions(...)`.
27
+ * Surfacing the violation here turns silent dedup misbehaviour into a
28
+ * loud, actionable error.
29
+ */
30
+ function assertManifestPositions(manifests) {
31
+ for (let i = 0; i < manifests.length; i++) {
32
+ const m = manifests[i];
33
+ if (REF_VALIDATION_SKIP_KINDS.has(m.kind))
34
+ continue;
35
+ const meta = m.metadata;
36
+ const okSource = typeof meta?.source === "string" && meta.source.length > 0;
37
+ const okLine = typeof meta?.sourceLine === "number";
38
+ if (okSource && okLine)
39
+ continue;
40
+ const label = `${m.kind}/${m.metadata?.name ?? "(unnamed)"}`;
41
+ const missing = [
42
+ !okSource ? "metadata.source" : null,
43
+ !okLine ? "metadata.sourceLine" : null,
44
+ ]
45
+ .filter(Boolean)
46
+ .join(" and ");
47
+ throw new Error(`StaticAnalyzer.analyze(): manifest #${i} (${label}) is missing ${missing}. ` +
48
+ `Real callers stamp positions automatically; programmatic callers ` +
49
+ `(tests, ad-hoc scripts) should pass inputs through ` +
50
+ `\`withSyntheticPositions(manifests)\` before calling analyze().`);
51
+ }
52
+ }
17
53
  /** Resolve an alias-prefixed kind value (e.g. `Self.Encoder` or `Ai.Model`)
18
54
  * to its canonical form. `Self.<Name>` resolves to `<ownModule>.<Name>` —
19
55
  * the magic alias for "this library's own module" — and other prefixes
@@ -373,7 +409,23 @@ export class StaticAnalyzer {
373
409
  constructor(options = {}) {
374
410
  this.celEnv = buildCelEnvironment(options.celHandlers);
375
411
  }
412
+ /**
413
+ * Run static analysis over a flattened manifest list.
414
+ *
415
+ * **Contract**: every non-system manifest (anything outside `Telo.Definition`,
416
+ * `Telo.Abstract`) must carry `metadata.source` (non-empty string) and
417
+ * `metadata.sourceLine` (number). The dedup that backs
418
+ * `DUPLICATE_RESOURCE_NAME` reads those fields to tell a pipeline echo
419
+ * apart from a genuine collision, and downstream diagnostic positioning
420
+ * depends on them too. Real callers stamp positions already (the `Loader`,
421
+ * `flattenForAnalyzer`, the telo-editor's `emitDocsFor`, the VSCode
422
+ * extension). Programmatic callers — tests, ad-hoc scripts — should pass
423
+ * their inputs through `withSyntheticPositions(...)` before calling
424
+ * `analyze()`. A missing position throws a clear error rather than
425
+ * silently producing wrong diagnostics.
426
+ */
376
427
  analyze(manifests, options, registry) {
428
+ assertManifestPositions(manifests);
377
429
  const diagnostics = [];
378
430
  // Use pre-seeded registries from the provided AnalysisRegistry, or create fresh ones.
379
431
  // New aliases/definitions found in the manifests are accumulated into the provided instance
@@ -490,6 +542,20 @@ export class StaticAnalyzer {
490
542
  }
491
543
  // Phase 2: extract inline resources from x-telo-ref slots into first-class manifests
492
544
  const allManifests = normalizeInlineResources(manifests, defs, aliases, aliasesByModule);
545
+ // Phase 2.5: resolve `!ref <name>` sentinels at every ref slot to canonical
546
+ // {kind, name} objects so downstream phases (validation, dependency graph,
547
+ // kernel controllers) see a uniform shape. Runs after normalize so both
548
+ // original and inline-extracted manifests have their sentinels resolved.
549
+ resolveRefSentinels(allManifests, defs, aliases, aliasesByModule);
550
+ // Trusted-input fast path: when the caller has already attested that
551
+ // this exact manifest set passes analysis (e.g. via the kernel's
552
+ // hash-stamped `.validated.json` cache), skip the validation walk.
553
+ // Registration of identities / aliases / definitions and inline-resource
554
+ // normalisation have already run above; that's all downstream
555
+ // consumers (prepare, init loop) require.
556
+ if (options?.skipValidation) {
557
+ return diagnostics;
558
+ }
493
559
  // Build a name→manifest map for looking up referenced resources
494
560
  const byName = new Map();
495
561
  for (const m of allManifests) {
@@ -497,6 +563,36 @@ export class StaticAnalyzer {
497
563
  byName.set(m.metadata.name, m);
498
564
  }
499
565
  }
566
+ // Library env: rejection — `env:` on a Library `variables` / `secrets`
567
+ // entry is forbidden. The Library entry schema is otherwise open so that
568
+ // any JSON Schema property schema is valid; this targeted check produces
569
+ // a clear diagnostic instead of a generic "additional property" error.
570
+ for (const m of allManifests) {
571
+ if (m.kind !== "Telo.Library")
572
+ continue;
573
+ const filePath = m.metadata?.source;
574
+ const moduleName = m.metadata?.name;
575
+ const resource = moduleName ? { kind: m.kind, name: moduleName } : undefined;
576
+ for (const block of ["variables", "secrets"]) {
577
+ const entries = m[block];
578
+ if (!entries || typeof entries !== "object" || Array.isArray(entries))
579
+ continue;
580
+ for (const [entryName, entry] of Object.entries(entries)) {
581
+ if (!entry || typeof entry !== "object" || Array.isArray(entry))
582
+ continue;
583
+ if ("env" in entry) {
584
+ diagnostics.push({
585
+ severity: DiagnosticSeverity.Error,
586
+ code: "LIBRARY_ENV_KEY_REJECTED",
587
+ source: SOURCE,
588
+ message: `Telo.Library ${block}/${entryName}: 'env:' is only permitted on Telo.Application entries. ` +
589
+ `Libraries must receive values from importers via the parent manifest's variables / secrets block.`,
590
+ data: { resource, filePath, path: `${block}.${entryName}.env` },
591
+ });
592
+ }
593
+ }
594
+ }
595
+ }
500
596
  // Build typed kernel globals schema so x-telo-context chain validation
501
597
  // recognises variables, secrets, resources, env automatically
502
598
  const kernelGlobals = buildKernelGlobalsSchema(allManifests);
@@ -622,15 +718,14 @@ export class StaticAnalyzer {
622
718
  emitTargetMismatch(dispatchKind, targetSchema, md.inputs, "inputs");
623
719
  }
624
720
  }
625
- // Top-level `result:` (a sibling, only meaningful with `provide:`) is a
626
- // post-call mapping that must satisfy the abstract this definition
627
- // `extends` (`outputType`). The target's outputType lives on `provide.kind`
721
+ // Top-level `result:` is a post-call mapping that must satisfy the abstract
722
+ // this definition `extends` (`outputType`). It's a sibling of whichever
723
+ // dispatch entry-point declared a kind-typed target (`provide:` or
724
+ // `invoke:`). The target's outputType lives on the dispatcher's `kind`
628
725
  // and is what `result` is typed against *inside* CEL — separate role.
629
- if (provide &&
630
- typeof provide === "object" &&
631
- !Array.isArray(provide) &&
632
- md.result &&
633
- typeof md.result === "object") {
726
+ const hasDispatchObject = (provide && typeof provide === "object" && !Array.isArray(provide)) ||
727
+ (invoke && typeof invoke === "object" && !Array.isArray(invoke));
728
+ if (hasDispatchObject && md.result && typeof md.result === "object") {
634
729
  const extendsValue = md.extends;
635
730
  if (typeof extendsValue === "string" && extendsValue.length > 0) {
636
731
  const abstractSchema = lookupDefinitionTypeField(extendsValue, "outputType", defs, aliases, allManifests);
@@ -735,16 +830,25 @@ export class StaticAnalyzer {
735
830
  diagnostics.push(...validateReferences(allManifests, { aliases, definitions: defs, aliasesByModule }));
736
831
  // Validate `extends` fields and flag legacy `capability: <UserAbstract>` overload.
737
832
  diagnostics.push(...validateExtends(allManifests, defs, aliases));
833
+ // Validate provider coherence rules for `provide:` template-target definitions.
834
+ diagnostics.push(...validateProviderCoherence(allManifests, defs, aliases));
738
835
  // Validate throws: declarations and catches: coverage (rules 1, 2, 4, 7)
739
836
  diagnostics.push(...validateThrowsCoverage(allManifests, defs, aliases, this.celEnv));
740
- return diagnostics;
837
+ // Reroute diagnostics on synthetic (inline-extracted) resources back to
838
+ // the chain root so position-index lookups land on the parent doc.
839
+ return rewriteSyntheticOrigins(diagnostics, allManifests);
741
840
  }
742
841
  analyzeErrors(manifests, options, registry) {
743
842
  return this.analyze(manifests, options, registry).filter((d) => d.severity === DiagnosticSeverity.Error);
744
843
  }
745
844
  normalize(manifests, registry) {
746
845
  const ctx = registry._context();
747
- return normalizeInlineResources(manifests, ctx.definitions, ctx.aliases, ctx.aliasesByModule);
846
+ const normalized = normalizeInlineResources(manifests, ctx.definitions, ctx.aliases, ctx.aliasesByModule);
847
+ // Resolve !ref sentinels after normalize so both the original and
848
+ // inline-extracted manifests get their refs canonicalized to
849
+ // {kind, name} for the kernel that consumes this output.
850
+ resolveRefSentinels(normalized, ctx.definitions, ctx.aliases, ctx.aliasesByModule);
851
+ return normalized;
748
852
  }
749
853
  prepare(manifests, registry) {
750
854
  const ctx = registry._context();
@@ -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,EAwQ/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,EAiU/C,CAAC"}
package/dist/builtins.js CHANGED
@@ -147,7 +147,12 @@ export const KERNEL_BUILTINS = [
147
147
  additionalProperties: false,
148
148
  properties: {
149
149
  self: { "x-telo-context-from-root": "schema" },
150
- result: { "x-telo-context-from-ref-kind": "provide/kind#outputType" },
150
+ result: {
151
+ "x-telo-context-from-ref-kind": [
152
+ "provide/kind#outputType",
153
+ "invoke/kind#outputType",
154
+ ],
155
+ },
151
156
  },
152
157
  },
153
158
  },
@@ -213,6 +218,20 @@ export const KERNEL_BUILTINS = [
213
218
  anyOf: [
214
219
  { type: "string", "x-telo-ref": "telo#Runnable" },
215
220
  { type: "string", "x-telo-ref": "telo#Service" },
221
+ // Post-resolution shape that `resolveRefSentinels`
222
+ // substitutes a `!ref <name>` sentinel into. The
223
+ // adjacent `x-telo-ref` constraints govern the kind
224
+ // check; this branch only admits the structural form so
225
+ // AJV doesn't reject a resolved ref.
226
+ {
227
+ type: "object",
228
+ required: ["kind", "name"],
229
+ properties: {
230
+ kind: { type: "string" },
231
+ name: { type: "string" },
232
+ },
233
+ additionalProperties: true,
234
+ },
216
235
  ],
217
236
  },
218
237
  },
@@ -220,6 +239,44 @@ export const KERNEL_BUILTINS = [
220
239
  type: "array",
221
240
  items: { type: "string" },
222
241
  },
242
+ // Application-level environment contract. Each entry layers `env:`
243
+ // (required, names the source env var) and `default:` (optional, used
244
+ // when the env var is unset) on top of an open JSON Schema property
245
+ // schema. `type:` constrains the coercion rule applied to the raw env
246
+ // string (scalars per-type; `object` / `array` via JSON.parse with the
247
+ // matching top-level type). All other JSON Schema keywords are passed
248
+ // through unchanged and applied to the coerced value via the standard
249
+ // schema validator. See kernel/nodejs/src/application-env.ts.
250
+ variables: {
251
+ type: "object",
252
+ additionalProperties: {
253
+ type: "object",
254
+ required: ["env", "type"],
255
+ properties: {
256
+ env: { type: "string" },
257
+ type: {
258
+ type: "string",
259
+ enum: ["string", "integer", "number", "boolean", "object", "array"],
260
+ },
261
+ default: {},
262
+ },
263
+ },
264
+ },
265
+ secrets: {
266
+ type: "object",
267
+ additionalProperties: {
268
+ type: "object",
269
+ required: ["env", "type"],
270
+ properties: {
271
+ env: { type: "string" },
272
+ type: {
273
+ type: "string",
274
+ enum: ["string", "integer", "number", "boolean", "object", "array"],
275
+ },
276
+ default: {},
277
+ },
278
+ },
279
+ },
223
280
  },
224
281
  required: ["metadata"],
225
282
  additionalProperties: false,
@@ -1 +1 @@
1
- {"version":3,"file":"definition-registry.d.ts","sourceRoot":"","sources":["../src/definition-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,0BAA0B,CAAC;AAGlC,+EAA+E;AAC/E,qBAAa,kBAAkB;;IAK7B;;sFAEkF;IAClF,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;IAEzD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAyC;IAC9D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwC;IAClE,mEAAmE;IACnE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA+B;IAC1D;6DACyD;IACzD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IACzD;;0EAEsE;IACtE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA6B;IAEhE,QAAQ,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI;IAiC9C,OAAO,CAAC,aAAa;IASrB;;;yFAGqF;IACrF,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAgB1E;4EACwE;IACxE,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMnE;wFACoF;IACpF,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE;IAWtE,OAAO,CAAC,iBAAiB;IAczB;;;;;;;;4FAQwF;IACxF,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAUhD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAIrD,+FAA+F;IAC/F,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAIxD,gGAAgG;IAChG,kBAAkB,CAChB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,GACvD,iBAAiB,GAAG,SAAS;IAOhC;;;;;;;;qFAQiF;IACjF,2BAA2B,CACzB,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,aAAa,EACtB,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GAC1C,iBAAiB,GAAG,SAAS;IAuBhC,OAAO,CAAC,uBAAuB;IA+B/B;;qEAEiE;IACjE,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAgBxD,KAAK,IAAI,MAAM,EAAE;CAGlB"}
1
+ {"version":3,"file":"definition-registry.d.ts","sourceRoot":"","sources":["../src/definition-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,0BAA0B,CAAC;AAGlC,+EAA+E;AAC/E,qBAAa,kBAAkB;;IAK7B;;sFAEkF;IAClF,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAqB;IAEzD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAyC;IAC9D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAwC;IAClE,mEAAmE;IACnE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA+B;IAC1D;6DACyD;IACzD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA6B;IACzD;;0EAEsE;IACtE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA6B;IAEhE,QAAQ,CAAC,UAAU,EAAE,kBAAkB,GAAG,IAAI;IAiC9C,OAAO,CAAC,aAAa;IASrB;;;yFAGqF;IACrF,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IA+B1E;4EACwE;IACxE,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAMnE;wFACoF;IACpF,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,EAAE;IAWtE,OAAO,CAAC,iBAAiB;IAczB;;;;;;;;4FAQwF;IACxF,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAUhD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAIrD,+FAA+F;IAC/F,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,GAAG,SAAS;IAIxD,gGAAgG;IAChG,kBAAkB,CAChB,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;QAAE,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAA;KAAE,GACvD,iBAAiB,GAAG,SAAS;IAOhC;;;;;;;;qFAQiF;IACjF,2BAA2B,CACzB,QAAQ,EAAE,gBAAgB,EAC1B,OAAO,EAAE,aAAa,EACtB,eAAe,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,GAC1C,iBAAiB,GAAG,SAAS;IAuBhC,OAAO,CAAC,uBAAuB;IA+B/B;;qEAEiE;IACjE,YAAY,CAAC,YAAY,EAAE,MAAM,GAAG,kBAAkB,EAAE;IAgBxD,KAAK,IAAI,MAAM,EAAE;CAGlB"}
@@ -70,6 +70,22 @@ export class DefinitionRegistry {
70
70
  * @param namespace The module's metadata.namespace (e.g. "std"), or null for telo built-ins.
71
71
  * @param moduleName The module's metadata.name (e.g. "pipeline", "http-server"). */
72
72
  registerModuleIdentity(namespace, moduleName) {
73
+ // The "telo" identity is reserved for the Telo built-in module and gets
74
+ // populated automatically when a Telo.Abstract definition registers (see
75
+ // `register` below). A user app / library without a namespace must NOT
76
+ // claim it — silently overwriting the built-in entry breaks every
77
+ // x-telo-ref that resolves through "telo#…". Concretely, the
78
+ // `Http.Api.routes[].handler` slot in the http-server schema carries
79
+ // `x-telo-ref: "telo#Invocable"`. If the entry application is, say,
80
+ // `Telo.Application/HelloApi` (no namespace), this method previously
81
+ // overwrote `"telo" → "Telo"` with `"telo" → "HelloApi"`. The handler's
82
+ // ref then resolved to a nonexistent `HelloApi.Invocable`, the
83
+ // kind-mismatch check inside `validate-references.ts` short-circuited
84
+ // on partial context, and the analyzer reported zero issues for a
85
+ // manifest that explodes at runtime. Skip non-Telo no-namespace modules;
86
+ // they have no x-telo-ref identity to declare anyway.
87
+ if (!namespace && moduleName !== "Telo")
88
+ return;
73
89
  const identity = namespace ? `${namespace}/${moduleName}` : "telo";
74
90
  this.identityMap.set(identity, moduleName);
75
91
  this.reverseIdentityMap.set(moduleName, identity);