@telorun/analyzer 0.47.0 → 0.49.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.
- package/dist/analysis-registry.d.ts +22 -11
- package/dist/analysis-registry.d.ts.map +1 -1
- package/dist/analysis-registry.js +36 -39
- package/dist/analyzer.d.ts +38 -1
- package/dist/analyzer.d.ts.map +1 -1
- package/dist/analyzer.js +121 -83
- package/dist/artifact-layer-index.d.ts +55 -0
- package/dist/artifact-layer-index.d.ts.map +1 -0
- package/dist/artifact-layer-index.js +116 -0
- package/dist/artifact-selector.d.ts +81 -0
- package/dist/artifact-selector.d.ts.map +1 -0
- package/dist/artifact-selector.js +122 -0
- package/dist/builtins.d.ts.map +1 -1
- package/dist/builtins.js +130 -20
- package/dist/extends-resolution.d.ts +41 -0
- package/dist/extends-resolution.d.ts.map +1 -1
- package/dist/extends-resolution.js +68 -0
- package/dist/index.d.ts +9 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- package/dist/invocation-contract.d.ts +100 -0
- package/dist/invocation-contract.d.ts.map +1 -0
- package/dist/invocation-contract.js +208 -0
- package/dist/schema-compat.d.ts +12 -4
- package/dist/schema-compat.d.ts.map +1 -1
- package/dist/schema-compat.js +185 -9
- package/dist/validate-base-mapping.js +11 -1
- package/dist/validate-cel-context.d.ts +0 -6
- package/dist/validate-cel-context.d.ts.map +1 -1
- package/dist/validate-cel-context.js +51 -4
- package/dist/validate-invocation-contract.d.ts +30 -0
- package/dist/validate-invocation-contract.d.ts.map +1 -0
- package/dist/validate-invocation-contract.js +394 -0
- package/dist/validate-module-artifact.d.ts +27 -0
- package/dist/validate-module-artifact.d.ts.map +1 -0
- package/dist/validate-module-artifact.js +131 -0
- package/dist/validate-step-inputs.d.ts +24 -0
- package/dist/validate-step-inputs.d.ts.map +1 -0
- package/dist/validate-step-inputs.js +87 -0
- package/dist/validate-throws-coverage.d.ts +1 -1
- package/dist/validate-throws-coverage.d.ts.map +1 -1
- package/dist/validate-throws-coverage.js +9 -1
- package/package.json +2 -2
- package/src/analysis-registry.ts +44 -34
- package/src/analyzer.ts +177 -100
- package/src/artifact-layer-index.ts +162 -0
- package/src/artifact-selector.ts +171 -0
- package/src/builtins.ts +135 -20
- package/src/extends-resolution.ts +86 -0
- package/src/index.ts +38 -1
- package/src/invocation-contract.ts +275 -0
- package/src/schema-compat.ts +191 -8
- package/src/validate-base-mapping.ts +14 -1
- package/src/validate-cel-context.ts +49 -4
- package/src/validate-invocation-contract.ts +450 -0
- package/src/validate-module-artifact.ts +141 -0
- package/src/validate-step-inputs.ts +117 -0
- package/src/validate-throws-coverage.ts +12 -2
|
@@ -62,20 +62,25 @@ export declare class AnalysisRegistry {
|
|
|
62
62
|
* unresolvable. */
|
|
63
63
|
capabilityForRef(xTeloRef: string): string | undefined;
|
|
64
64
|
/** Resolves the JSON Schema for a kind's `invoke()` inputs, for editor hosts
|
|
65
|
-
* that render a typed inputs form.
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
65
|
+
* that render a typed inputs form. A thin wrapper over the shared contract
|
|
66
|
+
* resolver, so the form an editor renders is the contract `telo check` and the
|
|
67
|
+
* kernel enforce — nearest declaration along `extends`, replacing rather than
|
|
68
|
+
* merging. A bare named type reference is left unresolved (returns undefined,
|
|
69
|
+
* no manifests are in scope here) so the caller can fall back to a freeform
|
|
70
|
+
* map. Undefined when the kind declares no input contract. */
|
|
71
71
|
inputTypeForKind(kind: string): Record<string, unknown> | undefined;
|
|
72
|
-
/** Resolves the JSON Schema for a kind's `invoke()` / `
|
|
72
|
+
/** Resolves the JSON Schema for a kind's `invoke()` / `provide()` output, for
|
|
73
73
|
* editor hosts that render a typed output signature. Mirrors
|
|
74
|
-
* {@link inputTypeForKind}
|
|
75
|
-
*
|
|
76
|
-
* raw-schema forms; a bare named type reference is left unresolved. Undefined
|
|
77
|
-
* when the kind declares no output contract. */
|
|
74
|
+
* {@link inputTypeForKind}. Undefined when the kind declares no output
|
|
75
|
+
* contract. */
|
|
78
76
|
outputTypeForKind(kind: string): Record<string, unknown> | undefined;
|
|
77
|
+
private contractForKind;
|
|
78
|
+
/** A resolver that re-scopes at every hop of an `extends` chain: each kind is
|
|
79
|
+
* resolved in the module that DECLARED the definition it was read off, since
|
|
80
|
+
* `extends` aliases are lexical. `resolveParent` always passes that definition
|
|
81
|
+
* as `from`, so one resolver serves a chain of any depth crossing any number
|
|
82
|
+
* of modules. */
|
|
83
|
+
private scopedDefResolver;
|
|
79
84
|
private capabilitiesForRefs;
|
|
80
85
|
/**
|
|
81
86
|
* Walks a manifest's annotation sites (refs, scopes, schema-from, CEL) via
|
|
@@ -96,6 +101,12 @@ export declare class AnalysisRegistry {
|
|
|
96
101
|
*/
|
|
97
102
|
builtinDefinitions(): ResourceDefinition[];
|
|
98
103
|
resolveDefinition(kind: string): ResourceDefinition | undefined;
|
|
104
|
+
/** Resolve a kind in a named module's scope. The entry point for walking an
|
|
105
|
+
* `extends` chain from outside it (the kernel's contract binding): aliases are
|
|
106
|
+
* lexical, so each hop must resolve in the module that declared the definition
|
|
107
|
+
* the kind was read off. Falls back to the global table when the module is
|
|
108
|
+
* unknown or is a root. */
|
|
109
|
+
resolveDefinitionIn(kind: string, module?: string): ResourceDefinition | undefined;
|
|
99
110
|
/** A resolver scoped to `def`'s OWN module, for resolving that definition's
|
|
100
111
|
* `extends` target.
|
|
101
112
|
*
|
|
@@ -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;AAKzE,OAAO,EAAqC,KAAK,eAAe,EAAE,MAAM,uBAAuB,CAAC;
|
|
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;AAIhG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;wDAEwD;AACxD,MAAM,WAAW,YAAY;IAC3B;0CACsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,OAAO,EAAE,OAAO,CAAC;IACjB,sFAAsF;IACtF,IAAI,EAAE,MAAM,EAAE,CAAC;IACf;;;8EAG0E;IAC1E,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;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;;+EAE2E;IAC3E,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI;IAI9E,wFAAwF;IACxF,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAIzD,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,oBAAoB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,YAAY,EAAE;IAoBhE;;;;;;wBAMoB;IACpB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAQtD;;;;;;mEAM+D;IAC/D,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;IAInE;;;oBAGgB;IAChB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS;IAIpE,OAAO,CAAC,eAAe;IAYvB;;;;sBAIkB;IAClB,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,mBAAmB;IAS3B;;;;;;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,CAAC;QAAC,kBAAkB,CAAC,EAAE,OAAO,CAAA;KAAE,GACzF,IAAI;IAQP;;;;OAIG;IACH,kBAAkB,IAAI,kBAAkB,EAAE;IAI1C,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAM/D;;;;gCAI4B;IAC5B,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,kBAAkB,GAAG,SAAS;IAMlF;;;;;;;;yCAQqC;IACrC,qBAAqB,CAAC,GAAG,EAAE;QACzB,QAAQ,CAAC,EAAE;YAAE,MAAM,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;KAChC,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,kBAAkB,GAAG,SAAS;IASpD;;qFAEiF;IACjF,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE;IAUzC,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;;;;;;;;iDAQ6C;IAC7C,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS;IAqB9D;;;;;gEAK4D;IAC5D,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS;IAiB7D,qFAAqF;IACrF,QAAQ,IAAI,eAAe;CAG5B"}
|
|
@@ -3,8 +3,8 @@ import { KERNEL_BUILTINS } from "./builtins.js";
|
|
|
3
3
|
import { DefinitionRegistry } from "./definition-registry.js";
|
|
4
4
|
import { computeSuggestKind, computeValidUserFacingKinds } from "./kind-suggest.js";
|
|
5
5
|
import { visitManifest as runVisitManifest } from "./manifest-visitor.js";
|
|
6
|
+
import { resolveContract } from "./invocation-contract.js";
|
|
6
7
|
import { isRefEntry, isScopeEntry } from "./reference-field-map.js";
|
|
7
|
-
import { resolveTypeFieldToSchema } from "./validate-cel-context.js";
|
|
8
8
|
/**
|
|
9
9
|
* Accumulates type and alias knowledge for a running kernel or analysis session.
|
|
10
10
|
* Wraps AliasResolver and DefinitionRegistry into a single domain-level interface
|
|
@@ -96,51 +96,38 @@ export class AnalysisRegistry {
|
|
|
96
96
|
return def.capability ?? kind;
|
|
97
97
|
}
|
|
98
98
|
/** Resolves the JSON Schema for a kind's `invoke()` inputs, for editor hosts
|
|
99
|
-
* that render a typed inputs form.
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
*
|
|
104
|
-
*
|
|
99
|
+
* that render a typed inputs form. A thin wrapper over the shared contract
|
|
100
|
+
* resolver, so the form an editor renders is the contract `telo check` and the
|
|
101
|
+
* kernel enforce — nearest declaration along `extends`, replacing rather than
|
|
102
|
+
* merging. A bare named type reference is left unresolved (returns undefined,
|
|
103
|
+
* no manifests are in scope here) so the caller can fall back to a freeform
|
|
104
|
+
* map. Undefined when the kind declares no input contract. */
|
|
105
105
|
inputTypeForKind(kind) {
|
|
106
|
-
|
|
107
|
-
if (!def)
|
|
108
|
-
return undefined;
|
|
109
|
-
const own = resolveTypeFieldToSchema(def.inputType, []);
|
|
110
|
-
if (own)
|
|
111
|
-
return own;
|
|
112
|
-
if (def.extends) {
|
|
113
|
-
const abstractDef = this.resolveDefinition(def.extends);
|
|
114
|
-
if (abstractDef) {
|
|
115
|
-
const inherited = resolveTypeFieldToSchema(abstractDef.inputType, []);
|
|
116
|
-
if (inherited)
|
|
117
|
-
return inherited;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return undefined;
|
|
106
|
+
return this.contractForKind(kind, "inputType");
|
|
121
107
|
}
|
|
122
|
-
/** Resolves the JSON Schema for a kind's `invoke()` / `
|
|
108
|
+
/** Resolves the JSON Schema for a kind's `invoke()` / `provide()` output, for
|
|
123
109
|
* editor hosts that render a typed output signature. Mirrors
|
|
124
|
-
* {@link inputTypeForKind}
|
|
125
|
-
*
|
|
126
|
-
* raw-schema forms; a bare named type reference is left unresolved. Undefined
|
|
127
|
-
* when the kind declares no output contract. */
|
|
110
|
+
* {@link inputTypeForKind}. Undefined when the kind declares no output
|
|
111
|
+
* contract. */
|
|
128
112
|
outputTypeForKind(kind) {
|
|
113
|
+
return this.contractForKind(kind, "outputType");
|
|
114
|
+
}
|
|
115
|
+
contractForKind(kind, direction) {
|
|
129
116
|
const def = this.resolveDefinition(kind);
|
|
130
117
|
if (!def)
|
|
131
118
|
return undefined;
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
return
|
|
119
|
+
return resolveContract(direction, undefined, def, {
|
|
120
|
+
resolveDefinition: this.scopedDefResolver(),
|
|
121
|
+
typeManifestsFor: () => [],
|
|
122
|
+
})?.schema;
|
|
123
|
+
}
|
|
124
|
+
/** A resolver that re-scopes at every hop of an `extends` chain: each kind is
|
|
125
|
+
* resolved in the module that DECLARED the definition it was read off, since
|
|
126
|
+
* `extends` aliases are lexical. `resolveParent` always passes that definition
|
|
127
|
+
* as `from`, so one resolver serves a chain of any depth crossing any number
|
|
128
|
+
* of modules. */
|
|
129
|
+
scopedDefResolver() {
|
|
130
|
+
return (kind, from) => this.resolveDefinitionIn(kind, from?.metadata?.module);
|
|
144
131
|
}
|
|
145
132
|
capabilitiesForRefs(refs) {
|
|
146
133
|
const out = [];
|
|
@@ -178,6 +165,16 @@ export class AnalysisRegistry {
|
|
|
178
165
|
const resolved = ctx.aliases?.resolveKind(kind);
|
|
179
166
|
return ctx.definitions?.resolve(kind) ?? (resolved ? ctx.definitions?.resolve(resolved) : undefined);
|
|
180
167
|
}
|
|
168
|
+
/** Resolve a kind in a named module's scope. The entry point for walking an
|
|
169
|
+
* `extends` chain from outside it (the kernel's contract binding): aliases are
|
|
170
|
+
* lexical, so each hop must resolve in the module that declared the definition
|
|
171
|
+
* the kind was read off. Falls back to the global table when the module is
|
|
172
|
+
* unknown or is a root. */
|
|
173
|
+
resolveDefinitionIn(kind, module) {
|
|
174
|
+
const scope = (module ? this.aliasesByModule.get(module) : undefined) ?? this.aliases;
|
|
175
|
+
const canonical = scope.resolveKind(kind);
|
|
176
|
+
return this.defs.resolve(kind) ?? (canonical ? this.defs.resolve(canonical) : undefined);
|
|
177
|
+
}
|
|
181
178
|
/** A resolver scoped to `def`'s OWN module, for resolving that definition's
|
|
182
179
|
* `extends` target.
|
|
183
180
|
*
|
package/dist/analyzer.d.ts
CHANGED
|
@@ -1,7 +1,44 @@
|
|
|
1
|
-
import type { ResourceManifest } from "@telorun/sdk";
|
|
1
|
+
import type { ResourceDefinition, ResourceManifest } from "@telorun/sdk";
|
|
2
|
+
import { AliasResolver, type ModuleScopes } from "./alias-resolver.js";
|
|
2
3
|
import { AnalysisRegistry } from "./analysis-registry.js";
|
|
3
4
|
import { type CelHandlers } from "./cel-environment.js";
|
|
5
|
+
import { DefinitionRegistry } from "./definition-registry.js";
|
|
6
|
+
import { type ContractScope } from "./invocation-contract.js";
|
|
4
7
|
import { type AnalysisDiagnostic, type AnalysisOptions } from "./types.js";
|
|
8
|
+
/** The {@link ContractScope} the analyzer resolves invocation contracts in: kinds
|
|
9
|
+
* resolve in the module that declared the definition they were read off (so an
|
|
10
|
+
* `extends` chain crossing module boundaries re-scopes at every hop), and named
|
|
11
|
+
* `telo#Type` references resolve against the flattened manifest list. `resolveIn`
|
|
12
|
+
* is the top-level entry point, where the kind was written by the READING
|
|
13
|
+
* module and there is no declaring definition yet. */
|
|
14
|
+
export declare function analyzerContractScope(defs: DefinitionRegistry, aliases: AliasResolver, scopes: ModuleScopes, allManifests: Record<string, any>[]): ContractScope & {
|
|
15
|
+
resolveIn(kind: string, module?: string): ResourceDefinition | undefined;
|
|
16
|
+
};
|
|
17
|
+
/** True when an issue reports a property that is absent — its path points at a
|
|
18
|
+
* node the manifest does not contain. */
|
|
19
|
+
export declare const missingRequired: (issue: {
|
|
20
|
+
message: string;
|
|
21
|
+
}) => boolean;
|
|
22
|
+
/** The path minus its last segment: the node that should have contained the
|
|
23
|
+
* missing property. Empty for a top-level miss, which anchors on the map. */
|
|
24
|
+
export declare function containerOf(path: string): string;
|
|
25
|
+
/** Resolve a local `$ref` (only `#/$defs/<name>` form) against the root schema.
|
|
26
|
+
* Non-refs and unresolved refs pass through unchanged. */
|
|
27
|
+
export declare function resolveLocalRef(schema: Record<string, any> | undefined, root: Record<string, any>): Record<string, any> | undefined;
|
|
28
|
+
/** Gather property schemas from a (possibly variant-bearing) object schema:
|
|
29
|
+
* top-level `properties` plus every `oneOf` / `anyOf` / `allOf` branch. */
|
|
30
|
+
export declare function gatherPropertySchemas(schema: Record<string, any>): Array<[string, Record<string, any>]>;
|
|
31
|
+
/**
|
|
32
|
+
* Generic, role-driven walk over an `x-telo-step-context` step array. Calls
|
|
33
|
+
* `visit(step, stepPath)` for every step — top-level and nested through the
|
|
34
|
+
* `x-telo-topology-role` forms (`branch`, `branch-list`, `case-map`). This is
|
|
35
|
+
* the single definition of how steps nest, shared by `buildStepContextSchema`
|
|
36
|
+
* (which types `steps.<name>.result`) and `validateStepInvokeReferences` (which
|
|
37
|
+
* checks invoke refs), so the topology contract lives in one place — adding a
|
|
38
|
+
* role or nesting form updates both consumers at once. No resource kind is
|
|
39
|
+
* hardcoded; recursion is driven entirely by the schema annotations.
|
|
40
|
+
*/
|
|
41
|
+
export declare function walkStepArray(steps: unknown[], stepItemSchema: Record<string, any> | undefined, rootSchema: Record<string, any>, basePath: string, visit: (step: Record<string, any>, stepPath: string) => void): void;
|
|
5
42
|
export interface StaticAnalyzerOptions {
|
|
6
43
|
celHandlers?: CelHandlers;
|
|
7
44
|
}
|
package/dist/analyzer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../src/analyzer.ts"],"names":[],"mappings":"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"}
|
package/dist/analyzer.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { canonicalTypeSchemaId, OBSERVED_STATE_KEY } from "@telorun/sdk";
|
|
2
2
|
import { defaultRegistry, isRefSentinel, isTaggedSentinel } from "@telorun/templating";
|
|
3
|
-
import { AliasResolver, scopeResolverForModule } from "./alias-resolver.js";
|
|
3
|
+
import { AliasResolver, moduleScopedDefResolver, scopeResolverForModule, } from "./alias-resolver.js";
|
|
4
4
|
import { buildCelEnvironment, buildImportInputCelEnvironment, buildTypedCelEnvironment, } from "./cel-environment.js";
|
|
5
5
|
import { DefinitionRegistry } from "./definition-registry.js";
|
|
6
6
|
import { effectiveAuthorSchema } from "./extends-resolution.js";
|
|
7
|
+
import { PERMISSIVE_CONTRACT, resolveContract, } from "./invocation-contract.js";
|
|
7
8
|
import { buildDependencyGraph, formatCycle } from "./dependency-graph.js";
|
|
8
9
|
import { buildKernelGlobalsSchema, mergeKernelGlobalsIntoContext } from "./kernel-globals.js";
|
|
9
10
|
import { buildObservedStateIndex, buildObservedStateResourcesSchema, collectRunReachableNames, observedStateRead, validateObservedStateDeclarations, } from "./validate-observed-state.js";
|
|
@@ -20,11 +21,14 @@ import { rewriteSyntheticOrigins } from "./rewrite-synthetic-origins.js";
|
|
|
20
21
|
import { celTypeSatisfiesJsonSchema, substituteCelFields, validateAgainstSchema, } from "./schema-compat.js";
|
|
21
22
|
import { collectValueSchemaIssues } from "./validate-value-schema.js";
|
|
22
23
|
import { DiagnosticSeverity } from "./types.js";
|
|
23
|
-
import { extractAccessChains, extractCelRegionScopes, extractContextsFromSchema, getManifestItem, pathMatchesScope, resolveContextAnnotations,
|
|
24
|
+
import { extractAccessChains, extractCelRegionScopes, extractContextsFromSchema, getManifestItem, pathMatchesScope, resolveContextAnnotations, } from "./validate-cel-context.js";
|
|
24
25
|
import { buildEvalPaths, evalPathsCover } from "./eval-paths.js";
|
|
25
26
|
import { validateExtends } from "./validate-extends.js";
|
|
26
27
|
import { validateLogging } from "./validate-logging.js";
|
|
28
|
+
import { validateModuleArtifact } from "./validate-module-artifact.js";
|
|
27
29
|
import { validateBaseMapping } from "./validate-base-mapping.js";
|
|
30
|
+
import { validateInvocationContract } from "./validate-invocation-contract.js";
|
|
31
|
+
import { collectStepInputIssues } from "./validate-step-inputs.js";
|
|
28
32
|
import { validateNestedInlineResources } from "./validate-nested-inline.js";
|
|
29
33
|
import { validateProviderCoherence } from "./validate-provider-coherence.js";
|
|
30
34
|
import { validateReferences } from "./validate-references.js";
|
|
@@ -74,17 +78,19 @@ function resolveSelfOrAlias(value, ownModule, scopeResolver) {
|
|
|
74
78
|
}
|
|
75
79
|
return scopeResolver.resolveKind(value);
|
|
76
80
|
}
|
|
77
|
-
/**
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
/** The {@link ContractScope} the analyzer resolves invocation contracts in: kinds
|
|
82
|
+
* resolve in the module that declared the definition they were read off (so an
|
|
83
|
+
* `extends` chain crossing module boundaries re-scopes at every hop), and named
|
|
84
|
+
* `telo#Type` references resolve against the flattened manifest list. `resolveIn`
|
|
85
|
+
* is the top-level entry point, where the kind was written by the READING
|
|
86
|
+
* module and there is no declaring definition yet. */
|
|
87
|
+
export function analyzerContractScope(defs, aliases, scopes, allManifests) {
|
|
88
|
+
const resolve = moduleScopedDefResolver(defs, aliases, scopes);
|
|
89
|
+
return {
|
|
90
|
+
resolveDefinition: resolve,
|
|
91
|
+
resolveIn: resolve.in,
|
|
92
|
+
typeManifestsFor: () => allManifests,
|
|
93
|
+
};
|
|
88
94
|
}
|
|
89
95
|
const SOURCE = "telo-analyzer";
|
|
90
96
|
/** Build a closed JSON Schema for the `self` CEL variable available inside a
|
|
@@ -118,50 +124,66 @@ function buildSelfSchema(definition, defs, aliases) {
|
|
|
118
124
|
};
|
|
119
125
|
}
|
|
120
126
|
/** Build the JSON Schema for the `inputs` CEL variable available inside an
|
|
121
|
-
* invocable template body
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
-
*
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
const own = resolveTypeFieldToSchema(definition.inputType, allManifests);
|
|
130
|
-
if (own)
|
|
131
|
-
return own;
|
|
132
|
-
const ext = definition.extends;
|
|
133
|
-
if (typeof ext === "string" && ext.length > 0) {
|
|
134
|
-
const canonical = aliases.resolveKind(ext) ?? ext;
|
|
135
|
-
const abstractDef = defs.resolve(canonical);
|
|
136
|
-
if (abstractDef) {
|
|
137
|
-
const inherited = resolveTypeFieldToSchema(abstractDef.inputType, allManifests);
|
|
138
|
-
if (inherited)
|
|
139
|
-
return inherited;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
return undefined;
|
|
127
|
+
* invocable template body — the shared contract resolver applied to the
|
|
128
|
+
* definition itself, so a body is typed against the exact signature callers are
|
|
129
|
+
* checked against and dispatch enforces. Walks the whole `extends` chain rather
|
|
130
|
+
* than one hop, so a definition two levels below the declaration still gets
|
|
131
|
+
* typed inputs. Undefined when nothing in the chain declares a contract —
|
|
132
|
+
* the caller signals opaque `map<string, dyn>` upstream. */
|
|
133
|
+
function lookupTemplateInputsSchema(definition, defs, aliases, allManifests, scopes) {
|
|
134
|
+
return resolveContract("inputType", undefined, definition, analyzerContractScope(defs, aliases, scopes, allManifests))?.schema;
|
|
143
135
|
}
|
|
144
136
|
/** Returns a "resolver-facing" view of the manifest where the fields used as
|
|
145
137
|
* navigation roots by Telo.Definition's `x-telo-context-from-root` annotations
|
|
146
138
|
* have been pre-augmented:
|
|
147
139
|
* - `schema` → augmented `self` schema (synthetic `name`/`kind`/metadata).
|
|
148
|
-
* - `inputType` → resolved
|
|
149
|
-
*
|
|
140
|
+
* - `inputType` → resolved through the shared contract resolver, so
|
|
141
|
+
* `x-telo-context-from-root: inputType` substitutes the
|
|
142
|
+
* real signature. Without it the annotation would replace
|
|
143
|
+
* the node verbatim with the inline `{kind, schema}` wrapper
|
|
144
|
+
* the standard library writes everywhere, typing `inputs` as
|
|
145
|
+
* `{kind, schema}` instead of the declared properties.
|
|
150
146
|
*
|
|
151
147
|
* For non-definition manifests the original object is returned. */
|
|
152
|
-
function manifestRootForResolver(m, defs, aliases, allManifests) {
|
|
148
|
+
function manifestRootForResolver(m, defs, aliases, allManifests, scopes) {
|
|
153
149
|
if (m.kind !== "Telo.Definition")
|
|
154
150
|
return m;
|
|
155
|
-
const inputs = lookupTemplateInputsSchema(m, defs, aliases, allManifests);
|
|
151
|
+
const inputs = lookupTemplateInputsSchema(m, defs, aliases, allManifests, scopes);
|
|
156
152
|
return {
|
|
157
153
|
...m,
|
|
158
154
|
schema: buildSelfSchema(m, defs, aliases),
|
|
159
155
|
...(inputs ? { inputType: inputs } : {}),
|
|
160
156
|
};
|
|
161
157
|
}
|
|
158
|
+
/** True when an issue reports a property that is absent — its path points at a
|
|
159
|
+
* node the manifest does not contain. */
|
|
160
|
+
export const missingRequired = (issue) => /is missing required property/.test(issue.message);
|
|
161
|
+
/** The path minus its last segment: the node that should have contained the
|
|
162
|
+
* missing property. Empty for a top-level miss, which anchors on the map. */
|
|
163
|
+
export function containerOf(path) {
|
|
164
|
+
const dot = path.lastIndexOf(".");
|
|
165
|
+
return dot === -1 ? "" : path.slice(0, dot);
|
|
166
|
+
}
|
|
167
|
+
/** How to name the owner of a resolved contract in a diagnostic. When the
|
|
168
|
+
* contract came from the definition's direct parent, echo the author's own
|
|
169
|
+
* spelling (`extends: Mcp.SessionProvider`) — that is the text they can find in
|
|
170
|
+
* their file. A contract inherited from further up the chain isn't written
|
|
171
|
+
* anywhere in this file, so the canonical `module.Kind` is what locates it. */
|
|
172
|
+
function contractOwnerLabel(definition, contract) {
|
|
173
|
+
const declaredBy = contract.declaredBy;
|
|
174
|
+
if (!declaredBy || declaredBy === definition) {
|
|
175
|
+
return String(definition.metadata?.name ?? definition.kind);
|
|
176
|
+
}
|
|
177
|
+
const parentSpelling = definition.extends;
|
|
178
|
+
const canonical = `${declaredBy.metadata.module}.${declaredBy.metadata.name}`;
|
|
179
|
+
if (typeof parentSpelling === "string" && parentSpelling.endsWith(`.${declaredBy.metadata.name}`)) {
|
|
180
|
+
return parentSpelling;
|
|
181
|
+
}
|
|
182
|
+
return canonical;
|
|
183
|
+
}
|
|
162
184
|
/** Resolve a local `$ref` (only `#/$defs/<name>` form) against the root schema.
|
|
163
185
|
* Non-refs and unresolved refs pass through unchanged. */
|
|
164
|
-
function resolveLocalRef(schema, root) {
|
|
186
|
+
export function resolveLocalRef(schema, root) {
|
|
165
187
|
if (!schema)
|
|
166
188
|
return undefined;
|
|
167
189
|
const ref = schema.$ref;
|
|
@@ -175,7 +197,7 @@ function resolveLocalRef(schema, root) {
|
|
|
175
197
|
}
|
|
176
198
|
/** Gather property schemas from a (possibly variant-bearing) object schema:
|
|
177
199
|
* top-level `properties` plus every `oneOf` / `anyOf` / `allOf` branch. */
|
|
178
|
-
function gatherPropertySchemas(schema) {
|
|
200
|
+
export function gatherPropertySchemas(schema) {
|
|
179
201
|
const out = [];
|
|
180
202
|
if (schema.properties && typeof schema.properties === "object") {
|
|
181
203
|
for (const [k, v] of Object.entries(schema.properties)) {
|
|
@@ -206,7 +228,7 @@ function gatherPropertySchemas(schema) {
|
|
|
206
228
|
* role or nesting form updates both consumers at once. No resource kind is
|
|
207
229
|
* hardcoded; recursion is driven entirely by the schema annotations.
|
|
208
230
|
*/
|
|
209
|
-
function walkStepArray(steps, stepItemSchema, rootSchema, basePath, visit) {
|
|
231
|
+
export function walkStepArray(steps, stepItemSchema, rootSchema, basePath, visit) {
|
|
210
232
|
const dispatchRole = (data, role, itemsSchema, path) => {
|
|
211
233
|
if (role === "branch" && Array.isArray(data)) {
|
|
212
234
|
walkStepArray(data, stepItemSchema, rootSchema, path, visit);
|
|
@@ -251,20 +273,18 @@ function walkStepArray(steps, stepItemSchema, rootSchema, basePath, visit) {
|
|
|
251
273
|
}
|
|
252
274
|
/**
|
|
253
275
|
* Build a `steps` context schema from `x-telo-step-context` annotation.
|
|
254
|
-
* Walks each step in the manifest array, resolves the invoked resource's
|
|
255
|
-
* and builds `steps.<name>.result` context entries.
|
|
276
|
+
* Walks each step in the manifest array, resolves the invoked resource's output
|
|
277
|
+
* contract, and builds `steps.<name>.result` context entries.
|
|
256
278
|
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
-
*
|
|
260
|
-
*
|
|
261
|
-
*
|
|
262
|
-
* 3. Permissive `{type: object, additionalProperties: true}` if neither
|
|
263
|
-
* yields a schema.
|
|
279
|
+
* Resolution is the shared {@link resolveContract} — the invoked resource
|
|
280
|
+
* manifest's own declaration, then the kind's, resolved to the nearest
|
|
281
|
+
* declaration along `extends`, then permissive. Sharing it with the kernel is
|
|
282
|
+
* what stops `telo check` from typing `steps.X.result` against one contract
|
|
283
|
+
* while dispatch validates against another.
|
|
264
284
|
*
|
|
265
|
-
*
|
|
266
|
-
* govern step-result chain validation — without it, the validator falls
|
|
267
|
-
* to permissive and the stream-opacity rule never fires.
|
|
285
|
+
* The kind layer is what makes `x-telo-stream` properties on definitions
|
|
286
|
+
* actually govern step-result chain validation — without it, the validator falls
|
|
287
|
+
* back to permissive and the stream-opacity rule never fires.
|
|
268
288
|
*
|
|
269
289
|
* Recursion into nested step arrays is annotation-driven via
|
|
270
290
|
* `x-telo-topology-role`. The analyzer recognises three role values:
|
|
@@ -275,10 +295,12 @@ function walkStepArray(steps, stepItemSchema, rootSchema, basePath, visit) {
|
|
|
275
295
|
* No specific Run.Sequence field name is hardcoded; any kind that uses
|
|
276
296
|
* `x-telo-step-context` and tags its branch fields with these roles works.
|
|
277
297
|
*/
|
|
278
|
-
function buildStepContextSchema(manifest, defSchema, allManifests, defs, aliases) {
|
|
298
|
+
function buildStepContextSchema(manifest, defSchema, allManifests, defs, aliases, scopes) {
|
|
279
299
|
const props = defSchema.properties;
|
|
280
300
|
if (!props)
|
|
281
301
|
return undefined;
|
|
302
|
+
const contractScope = analyzerContractScope(defs, aliases, scopes, allManifests);
|
|
303
|
+
const readingModule = manifest.metadata?.module;
|
|
282
304
|
for (const [fieldName, fieldSchema] of Object.entries(props)) {
|
|
283
305
|
const stepCtx = fieldSchema["x-telo-step-context"];
|
|
284
306
|
if (!stepCtx)
|
|
@@ -301,28 +323,22 @@ function buildStepContextSchema(manifest, defSchema, allManifests, defs, aliases
|
|
|
301
323
|
// or unknown step references slip through chain validation.
|
|
302
324
|
if (typeof name !== "string" || !invoke || typeof invoke !== "object")
|
|
303
325
|
return;
|
|
304
|
-
let outputSchema;
|
|
305
326
|
const invokedKind = invoke.kind;
|
|
306
327
|
const invokedName = invoke.name;
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
// Fallback: pull outputType from the kind's Telo.Definition. The
|
|
318
|
-
// resource manifest typically doesn't carry outputType; the def does.
|
|
319
|
-
if (!outputSchema && invokedKind) {
|
|
320
|
-
outputSchema = lookupDefinitionTypeField(invokedKind, outputTypeField, defs, aliases, allManifests);
|
|
321
|
-
}
|
|
328
|
+
// A named `!ref` carries the target's own manifest (which may narrow the
|
|
329
|
+
// contract for this one instance); an inline `{ kind, ... }` step IS the
|
|
330
|
+
// manifest. Either way the kind layer resolves through `extends`.
|
|
331
|
+
const invokedManifest = invokedName
|
|
332
|
+
? allManifests.find((m) => m.metadata?.name === invokedName && (!invokedKind || m.kind === invokedKind))
|
|
333
|
+
: invoke;
|
|
334
|
+
const invokedDef = invokedKind
|
|
335
|
+
? contractScope.resolveIn(invokedKind, readingModule)
|
|
336
|
+
: undefined;
|
|
337
|
+
const outputSchema = resolveContract(outputTypeField, invokedManifest, invokedDef, contractScope)?.schema;
|
|
322
338
|
stepProperties[name] = {
|
|
323
339
|
type: "object",
|
|
324
340
|
properties: {
|
|
325
|
-
result: outputSchema ??
|
|
341
|
+
result: outputSchema ?? PERMISSIVE_CONTRACT,
|
|
326
342
|
},
|
|
327
343
|
};
|
|
328
344
|
});
|
|
@@ -1015,6 +1031,11 @@ export class StaticAnalyzer {
|
|
|
1015
1031
|
// §14.1 / §10.3: redaction paths and `on_full: block` are statically
|
|
1016
1032
|
// detectable, so they fail `telo check` rather than only at boot.
|
|
1017
1033
|
diagnostics.push(...validateLogging(allManifests, defs, aliases, aliasesByModule));
|
|
1034
|
+
// Module-artifact surface: bundled-controller selector qualifiers and the
|
|
1035
|
+
// published `layers:` index. Every case is decidable from the manifest and
|
|
1036
|
+
// would otherwise fail on a consumer's machine — or, for a mistyped platform
|
|
1037
|
+
// axis, silently offer one platform's binary to every host.
|
|
1038
|
+
diagnostics.push(...validateModuleArtifact(allManifests));
|
|
1018
1039
|
}
|
|
1019
1040
|
resolveSchemaTypeRefs(allManifests, aliases, aliasesByModule);
|
|
1020
1041
|
// Trusted-input fast path: when the caller has already attested that
|
|
@@ -1312,6 +1333,7 @@ export class StaticAnalyzer {
|
|
|
1312
1333
|
// the abstract this definition `extends`. CEL fields inside the templated
|
|
1313
1334
|
// values are replaced with type-appropriate placeholders before AJV runs —
|
|
1314
1335
|
// same pattern as the per-resource schema validation above.
|
|
1336
|
+
const contractScope = analyzerContractScope(defs, aliases, { aliasesByModule, rootModules }, allManifests);
|
|
1315
1337
|
for (const m of allManifests) {
|
|
1316
1338
|
if (m.kind !== "Telo.Definition")
|
|
1317
1339
|
continue;
|
|
@@ -1354,25 +1376,23 @@ export class StaticAnalyzer {
|
|
|
1354
1376
|
// values passed to the dispatch target's invoke(). Validate against the
|
|
1355
1377
|
// target's declared `inputType` when both sides have one.
|
|
1356
1378
|
if (dispatchKind && md.inputs && typeof md.inputs === "object") {
|
|
1357
|
-
const targetSchema =
|
|
1379
|
+
const targetSchema = resolveContract("inputType", undefined, contractScope.resolveIn(dispatchKind, md.metadata?.module), contractScope)?.schema;
|
|
1358
1380
|
if (targetSchema) {
|
|
1359
1381
|
emitTargetMismatch(dispatchKind, targetSchema, md.inputs, "inputs");
|
|
1360
1382
|
}
|
|
1361
1383
|
}
|
|
1362
|
-
// Top-level `result:` is a post-call mapping that must satisfy
|
|
1363
|
-
//
|
|
1384
|
+
// Top-level `result:` is a post-call mapping that must satisfy THIS
|
|
1385
|
+
// definition's output contract — its own `outputType` when it declares
|
|
1386
|
+
// one, otherwise the nearest ancestor's. It's a sibling of whichever
|
|
1364
1387
|
// dispatch entry-point declared a kind-typed target (`provide:` or
|
|
1365
1388
|
// `invoke:`). The target's outputType lives on the dispatcher's `kind`
|
|
1366
1389
|
// and is what `result` is typed against *inside* CEL — separate role.
|
|
1367
1390
|
const hasDispatchObject = (provide && typeof provide === "object" && !Array.isArray(provide)) ||
|
|
1368
1391
|
(invoke && typeof invoke === "object" && !Array.isArray(invoke));
|
|
1369
1392
|
if (hasDispatchObject && md.result && typeof md.result === "object") {
|
|
1370
|
-
const
|
|
1371
|
-
if (
|
|
1372
|
-
|
|
1373
|
-
if (abstractSchema) {
|
|
1374
|
-
emitTargetMismatch(extendsValue, abstractSchema, md.result, "result");
|
|
1375
|
-
}
|
|
1393
|
+
const contract = resolveContract("outputType", undefined, md, contractScope);
|
|
1394
|
+
if (contract) {
|
|
1395
|
+
emitTargetMismatch(contractOwnerLabel(md, contract), contract.schema, md.result, "result");
|
|
1376
1396
|
}
|
|
1377
1397
|
}
|
|
1378
1398
|
}
|
|
@@ -1404,8 +1424,25 @@ export class StaticAnalyzer {
|
|
|
1404
1424
|
const m = e.source;
|
|
1405
1425
|
celInvocationContext = m.metadata?.xTeloInvocationContext;
|
|
1406
1426
|
celStepContextSchema = e.definition?.schema
|
|
1407
|
-
? buildStepContextSchema(m, e.definition.schema, allManifests, defs, aliases)
|
|
1427
|
+
? buildStepContextSchema(m, e.definition.schema, allManifests, defs, aliases, { aliasesByModule, rootModules })
|
|
1408
1428
|
: undefined;
|
|
1429
|
+
if (e.definition?.schema) {
|
|
1430
|
+
const stepName = m.metadata?.name;
|
|
1431
|
+
const stepFile = m.metadata?.source;
|
|
1432
|
+
for (const issue of collectStepInputIssues(m, e.definition.schema, allManifests, defs, aliases, { aliasesByModule, rootModules })) {
|
|
1433
|
+
diagnostics.push({
|
|
1434
|
+
severity: DiagnosticSeverity.Error,
|
|
1435
|
+
code: "CONTRACT_INPUTS_MISMATCH",
|
|
1436
|
+
source: SOURCE,
|
|
1437
|
+
message: `${m.kind}/${stepName}: inputs at '${issue.path}' do not satisfy ${issue.targetLabel}'s declared inputType: ${issue.message}`,
|
|
1438
|
+
data: {
|
|
1439
|
+
resource: { kind: m.kind, name: stepName ?? "" },
|
|
1440
|
+
filePath: stepFile,
|
|
1441
|
+
path: issue.path,
|
|
1442
|
+
},
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1409
1446
|
celErrorScopes = collectErrorContextScopes(e.definition?.schema);
|
|
1410
1447
|
// The non-eval-field check only applies to runtime resource instances:
|
|
1411
1448
|
// structural / templating kinds (capability `Telo.Template`, or no
|
|
@@ -1521,7 +1558,7 @@ export class StaticAnalyzer {
|
|
|
1521
1558
|
const manifestItem = matchedScope
|
|
1522
1559
|
? getManifestItem(path, matchedScope, m)
|
|
1523
1560
|
: m;
|
|
1524
|
-
const rootForResolver = manifestRootForResolver(m, defs, aliases, allManifests);
|
|
1561
|
+
const rootForResolver = manifestRootForResolver(m, defs, aliases, allManifests, { aliasesByModule, rootModules });
|
|
1525
1562
|
const resolvedContext = resolveContextAnnotations(matchedContext, manifestItem, {
|
|
1526
1563
|
manifestRoot: rootForResolver,
|
|
1527
1564
|
defs,
|
|
@@ -1619,6 +1656,7 @@ export class StaticAnalyzer {
|
|
|
1619
1656
|
// Validate `extends` fields and flag legacy `capability: <UserAbstract>` overload.
|
|
1620
1657
|
diagnostics.push(...validateExtends(allManifests, defs, aliases));
|
|
1621
1658
|
diagnostics.push(...validateBaseMapping(allManifests, defs, aliases));
|
|
1659
|
+
diagnostics.push(...validateInvocationContract(allManifests, defs, aliases, aliasesByModule));
|
|
1622
1660
|
// Validate provider coherence rules for `provide:` template-target definitions.
|
|
1623
1661
|
diagnostics.push(...validateProviderCoherence(allManifests, defs, aliases));
|
|
1624
1662
|
// Validate throws: declarations and catches: coverage (rules 1, 2, 4, 7)
|