@telorun/kernel 0.5.0 → 0.6.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/controllers/module/import-controller.js +2 -2
- package/dist/controllers/module/import-controller.js.map +1 -1
- package/dist/evaluation-context.js +1 -1
- package/dist/evaluation-context.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/kernel.d.ts +13 -15
- package/dist/kernel.d.ts.map +1 -1
- package/dist/kernel.js +25 -37
- package/dist/kernel.js.map +1 -1
- package/dist/{manifest-adapters/local-file-adapter.d.ts → manifest-sources/local-file-source.d.ts} +3 -3
- package/dist/manifest-sources/local-file-source.d.ts.map +1 -0
- package/dist/{manifest-adapters/local-file-adapter.js → manifest-sources/local-file-source.js} +2 -2
- package/dist/manifest-sources/local-file-source.js.map +1 -0
- package/dist/manifest-sources/memory-source.d.ts +23 -0
- package/dist/manifest-sources/memory-source.d.ts.map +1 -0
- package/dist/manifest-sources/memory-source.js +83 -0
- package/dist/manifest-sources/memory-source.js.map +1 -0
- package/dist/module-context.d.ts +6 -2
- package/dist/module-context.d.ts.map +1 -1
- package/dist/module-context.js +13 -1
- package/dist/module-context.js.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +0 -1
- package/dist/registry.js.map +1 -1
- package/dist/resource-context.d.ts +0 -6
- package/dist/resource-context.d.ts.map +1 -1
- package/dist/resource-context.js +2 -27
- package/dist/resource-context.js.map +1 -1
- package/package.json +16 -5
- package/src/controllers/module/import-controller.ts +2 -2
- package/src/evaluation-context.ts +1 -1
- package/src/index.ts +2 -1
- package/src/kernel.ts +45 -56
- package/src/{manifest-adapters/local-file-adapter.ts → manifest-sources/local-file-source.ts} +2 -2
- package/src/manifest-sources/memory-source.ts +104 -0
- package/src/module-context.ts +14 -2
- package/src/registry.ts +0 -1
- package/src/resource-context.ts +3 -35
- package/dist/manifest-adapters/local-file-adapter.d.ts.map +0 -1
- package/dist/manifest-adapters/local-file-adapter.js.map +0 -1
- package/dist/manifest-adapters/manifest-adapter.d.ts +0 -35
- package/dist/manifest-adapters/manifest-adapter.d.ts.map +0 -1
- package/dist/manifest-adapters/manifest-adapter.js +0 -2
- package/dist/manifest-adapters/manifest-adapter.js.map +0 -1
- package/src/manifest-adapters/manifest-adapter.ts +0 -35
package/src/kernel.ts
CHANGED
|
@@ -1,28 +1,32 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AnalysisRegistry,
|
|
3
|
+
isModuleKind,
|
|
4
|
+
Loader,
|
|
5
|
+
StaticAnalyzer,
|
|
6
|
+
type ManifestSource,
|
|
7
|
+
} from "@telorun/analyzer";
|
|
2
8
|
import {
|
|
3
9
|
ControllerContext,
|
|
4
10
|
ControllerPolicy,
|
|
5
11
|
Kernel as IKernel,
|
|
6
|
-
|
|
12
|
+
isCompiledValue,
|
|
7
13
|
ResourceContext,
|
|
8
14
|
ResourceDefinition,
|
|
9
15
|
ResourceInstance,
|
|
10
16
|
ResourceManifest,
|
|
11
17
|
RuntimeError,
|
|
12
18
|
RuntimeEvent,
|
|
13
|
-
isCompiledValue,
|
|
14
19
|
type EvaluationContext as IEvaluationContext,
|
|
15
20
|
type ModuleContext as IModuleContext,
|
|
21
|
+
type LoadOptions,
|
|
16
22
|
type ParsedArgs,
|
|
17
23
|
} from "@telorun/sdk";
|
|
18
24
|
import { createHash } from "node:crypto";
|
|
19
|
-
import { ModuleContext } from "./module-context.js";
|
|
20
|
-
import * as path from "path";
|
|
21
25
|
import { parseArgs } from "util";
|
|
22
26
|
import { ControllerRegistry } from "./controller-registry.js";
|
|
23
27
|
import { EventStream } from "./event-stream.js";
|
|
24
28
|
import { EventBus } from "./events.js";
|
|
25
|
-
import {
|
|
29
|
+
import { ModuleContext } from "./module-context.js";
|
|
26
30
|
import { ResourceContextImpl } from "./resource-context.js";
|
|
27
31
|
import { policyFingerprint } from "./runtime-registry.js";
|
|
28
32
|
import { SchemaValidator } from "./schema-validator.js";
|
|
@@ -31,22 +35,31 @@ import { SchemaValidator } from "./schema-validator.js";
|
|
|
31
35
|
* ModuleContext and returns its controller policy (or undefined). Used to
|
|
32
36
|
* pick the right cache entry when a kind has been loaded under multiple
|
|
33
37
|
* runtime selections. */
|
|
34
|
-
function
|
|
38
|
+
function findEnclosingModule(ctx: IEvaluationContext): ModuleContext | undefined {
|
|
35
39
|
let cur: IEvaluationContext | undefined = ctx;
|
|
36
40
|
while (cur) {
|
|
37
|
-
if (cur instanceof ModuleContext) return cur
|
|
41
|
+
if (cur instanceof ModuleContext) return cur;
|
|
38
42
|
cur = cur.parent;
|
|
39
43
|
}
|
|
40
44
|
return undefined;
|
|
41
45
|
}
|
|
42
46
|
|
|
47
|
+
function findEnclosingPolicy(ctx: IEvaluationContext): ControllerPolicy | undefined {
|
|
48
|
+
return findEnclosingModule(ctx)?.getControllerPolicy();
|
|
49
|
+
}
|
|
50
|
+
|
|
43
51
|
export interface KernelOptions {
|
|
44
52
|
stdin?: NodeJS.ReadableStream;
|
|
45
53
|
stdout?: NodeJS.WritableStream;
|
|
46
54
|
stderr?: NodeJS.WritableStream;
|
|
47
55
|
env?: Record<string, string | undefined>;
|
|
48
56
|
argv?: string[];
|
|
49
|
-
/**
|
|
57
|
+
/** Manifest sources the kernel uses to resolve URLs passed to `load()`.
|
|
58
|
+
* Required: pass an explicit list (`[]` is allowed but means every URL
|
|
59
|
+
* fails to dispatch). Order matters — later entries take priority over
|
|
60
|
+
* earlier ones (sources are unshifted onto the dispatch chain). */
|
|
61
|
+
sources: ManifestSource[];
|
|
62
|
+
/** Base URL for the registry source. When unset, the `RegistrySource`
|
|
50
63
|
* default applies. Callers (e.g. the CLI) are responsible for resolving
|
|
51
64
|
* `TELO_REGISTRY_URL` or any other env-based fallback before passing. */
|
|
52
65
|
registryUrl?: string;
|
|
@@ -82,7 +95,7 @@ export class Kernel implements IKernel {
|
|
|
82
95
|
readonly argv: string[];
|
|
83
96
|
readonly registryUrl: string | undefined;
|
|
84
97
|
|
|
85
|
-
constructor(options: KernelOptions
|
|
98
|
+
constructor(options: KernelOptions) {
|
|
86
99
|
this.stdin = options.stdin ?? process.stdin;
|
|
87
100
|
this.stdout = options.stdout ?? process.stdout;
|
|
88
101
|
this.stderr = options.stderr ?? process.stderr;
|
|
@@ -90,7 +103,9 @@ export class Kernel implements IKernel {
|
|
|
90
103
|
this.argv = options.argv ?? [];
|
|
91
104
|
this.registryUrl = options.registryUrl;
|
|
92
105
|
this.loader = new Loader({ registryUrl: this.registryUrl, celHandlers });
|
|
93
|
-
|
|
106
|
+
for (const source of options.sources) {
|
|
107
|
+
this.loader.register(source);
|
|
108
|
+
}
|
|
94
109
|
this.setupEventStreaming();
|
|
95
110
|
}
|
|
96
111
|
|
|
@@ -116,24 +131,6 @@ export class Kernel implements IKernel {
|
|
|
116
131
|
this.registry.registerDefinition(definition);
|
|
117
132
|
}
|
|
118
133
|
|
|
119
|
-
getModuleContext(_moduleName: string): ModuleContext {
|
|
120
|
-
return this.rootContext;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
resolveModuleAlias(_declaringModule: string, alias: string): string | undefined {
|
|
124
|
-
return this.rootContext.importAliases.get(alias);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
registerModuleImport(
|
|
128
|
-
_declaringModule: string,
|
|
129
|
-
alias: string,
|
|
130
|
-
targetModule: string,
|
|
131
|
-
kinds: string[],
|
|
132
|
-
): void {
|
|
133
|
-
this.rootContext.registerImport(alias, targetModule, kinds);
|
|
134
|
-
this.registry.registerImport(alias, targetModule, kinds);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
134
|
loadModule(url: string, options?: LoadOptions): Promise<ResourceManifest[]> {
|
|
138
135
|
return this.loader.loadModule(url, options);
|
|
139
136
|
}
|
|
@@ -182,11 +179,12 @@ export class Kernel implements IKernel {
|
|
|
182
179
|
}
|
|
183
180
|
|
|
184
181
|
/**
|
|
185
|
-
* Load
|
|
182
|
+
* Load a manifest by URL. The URL is dispatched through the registered
|
|
183
|
+
* `ManifestSource` chain (file://, http://, pkg:, memory://, …); URL-shape
|
|
184
|
+
* normalization is each source's responsibility.
|
|
186
185
|
*/
|
|
187
|
-
async
|
|
188
|
-
const
|
|
189
|
-
const sourceUrl = await this.loader.resolveEntryPoint(resolvedUrl);
|
|
186
|
+
async load(url: string): Promise<void> {
|
|
187
|
+
const sourceUrl = await this.loader.resolveEntryPoint(url);
|
|
190
188
|
this.rootContext = new ModuleContext(
|
|
191
189
|
sourceUrl,
|
|
192
190
|
{},
|
|
@@ -270,16 +268,6 @@ export class Kernel implements IKernel {
|
|
|
270
268
|
}
|
|
271
269
|
}
|
|
272
270
|
|
|
273
|
-
/**
|
|
274
|
-
* Phase 1: Load - Ingest files from directory and load runtime config
|
|
275
|
-
* @deprecated Use loadFromConfig instead
|
|
276
|
-
*/
|
|
277
|
-
async loadDirectory(dirPath: string): Promise<void> {
|
|
278
|
-
const configYamlPath = path.join(dirPath, DEFAULT_MANIFEST_FILENAME);
|
|
279
|
-
|
|
280
|
-
await this.loadFromConfig(configYamlPath);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
271
|
/**
|
|
284
272
|
* Phase 2: Start - Initialize resources
|
|
285
273
|
*/
|
|
@@ -407,10 +395,6 @@ export class Kernel implements IKernel {
|
|
|
407
395
|
return {
|
|
408
396
|
on: (event: string, handler: (event: RuntimeEvent) => void | Promise<void>) =>
|
|
409
397
|
this.eventBus.on(event, handler),
|
|
410
|
-
once: (event: string, handler: (event: RuntimeEvent) => void | Promise<void>) =>
|
|
411
|
-
this.eventBus.once(event, handler),
|
|
412
|
-
off: (event: string, handler: (event: RuntimeEvent) => void | Promise<void>) =>
|
|
413
|
-
this.eventBus.off(event, handler),
|
|
414
398
|
emit: (event: string, payload?: any) => {
|
|
415
399
|
const namespaced = event.includes(".") ? event : `${kind}.${event}`;
|
|
416
400
|
void this.eventBus.emit(namespaced, payload);
|
|
@@ -497,9 +481,11 @@ export class Kernel implements IKernel {
|
|
|
497
481
|
): Promise<{ instance: ResourceInstance; ctx: ResourceContext } | null> {
|
|
498
482
|
const kind = resource.kind;
|
|
499
483
|
|
|
500
|
-
// Resolve the alias-prefixed kind to its real fully-qualified kind
|
|
501
|
-
//
|
|
502
|
-
|
|
484
|
+
// Resolve the alias-prefixed kind to its real fully-qualified kind against the
|
|
485
|
+
// declaring module's own scope. resolveKind() walks up the parent chain so root
|
|
486
|
+
// built-ins (like `Telo`) remain visible from inside imported libraries; sibling
|
|
487
|
+
// modules stay isolated because they're not in the chain.
|
|
488
|
+
const resolvedKind = (findEnclosingModule(evalContext) ?? this.rootContext).resolveKind(kind);
|
|
503
489
|
|
|
504
490
|
const fingerprint = policyFingerprint(findEnclosingPolicy(evalContext));
|
|
505
491
|
const controller = this.controllers.getControllerOrUndefined(resolvedKind, fingerprint);
|
|
@@ -663,7 +649,11 @@ function resolveSchemaRef(
|
|
|
663
649
|
schema: Record<string, unknown>,
|
|
664
650
|
root: Record<string, unknown>,
|
|
665
651
|
): Record<string, unknown> {
|
|
666
|
-
if (
|
|
652
|
+
if (
|
|
653
|
+
schema.$ref &&
|
|
654
|
+
typeof schema.$ref === "string" &&
|
|
655
|
+
(schema.$ref as string).startsWith("#/$defs/")
|
|
656
|
+
) {
|
|
667
657
|
const defName = (schema.$ref as string).slice("#/$defs/".length);
|
|
668
658
|
const defs = root.$defs as Record<string, Record<string, unknown>> | undefined;
|
|
669
659
|
const resolved = defs?.[defName];
|
|
@@ -681,7 +671,9 @@ function collectSchemaProperties(
|
|
|
681
671
|
};
|
|
682
672
|
for (const sub of (schema.oneOf ?? schema.anyOf ?? []) as Record<string, unknown>[]) {
|
|
683
673
|
if (sub && typeof sub === "object" && sub.properties) {
|
|
684
|
-
for (const [k, v] of Object.entries(
|
|
674
|
+
for (const [k, v] of Object.entries(
|
|
675
|
+
sub.properties as Record<string, Record<string, unknown>>,
|
|
676
|
+
)) {
|
|
685
677
|
if (!(k in props)) props[k] = v;
|
|
686
678
|
}
|
|
687
679
|
}
|
|
@@ -702,10 +694,7 @@ function stripCompiledValues(
|
|
|
702
694
|
|
|
703
695
|
if (isCompiledValue(v)) return placeholderForSchema(resolved);
|
|
704
696
|
if (Array.isArray(v)) {
|
|
705
|
-
const itemSchema = resolveSchemaRef(
|
|
706
|
-
(resolved.items ?? {}) as Record<string, unknown>,
|
|
707
|
-
root,
|
|
708
|
-
);
|
|
697
|
+
const itemSchema = resolveSchemaRef((resolved.items ?? {}) as Record<string, unknown>, root);
|
|
709
698
|
return v.map((item) => stripCompiledValues(item, itemSchema, root));
|
|
710
699
|
}
|
|
711
700
|
if (v !== null && typeof v === "object") {
|
package/src/{manifest-adapters/local-file-adapter.ts → manifest-sources/local-file-source.ts}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_MANIFEST_FILENAME, type
|
|
1
|
+
import { DEFAULT_MANIFEST_FILENAME, type ManifestSource } from "@telorun/analyzer";
|
|
2
2
|
import * as fs from "fs/promises";
|
|
3
3
|
import * as path from "path";
|
|
4
4
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
@@ -12,7 +12,7 @@ function toFileUrl(filePath: string): string {
|
|
|
12
12
|
return pathToFileURL(filePath).href;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
export class
|
|
15
|
+
export class LocalFileSource implements ManifestSource {
|
|
16
16
|
supports(pathOrUrl: string): boolean {
|
|
17
17
|
return (
|
|
18
18
|
pathOrUrl.startsWith("file://") ||
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { DEFAULT_MANIFEST_FILENAME, type ManifestSource } from "@telorun/analyzer";
|
|
2
|
+
import { posix } from "node:path";
|
|
3
|
+
import { stringify as yamlStringify } from "yaml";
|
|
4
|
+
|
|
5
|
+
const SCHEME = "memory://";
|
|
6
|
+
|
|
7
|
+
function stripScheme(url: string): string {
|
|
8
|
+
return url.startsWith(SCHEME) ? url.slice(SCHEME.length) : url;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function isAbsoluteUrl(s: string): boolean {
|
|
12
|
+
return /^[a-zA-Z][a-zA-Z0-9+\-.]*:/.test(s);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** In-memory `ManifestSource` for embedders and tests. Register manifest text
|
|
16
|
+
* (or parsed-manifest object arrays) under bare module names; the source
|
|
17
|
+
* canonicalizes module entry points as `<name>/telo.yaml`, mirroring disk's
|
|
18
|
+
* "module is a directory containing telo.yaml" convention so relative imports
|
|
19
|
+
* (`./sub`, `../sibling`) work transparently with POSIX path resolution. */
|
|
20
|
+
export class MemorySource implements ManifestSource {
|
|
21
|
+
private readonly entries = new Map<string, string>();
|
|
22
|
+
|
|
23
|
+
/** Register a manifest source. `name` is a bare module name (`"app"`,
|
|
24
|
+
* `"lib"`, or hierarchical `"auth/login"`) or a partial-file path with a
|
|
25
|
+
* `.yaml`/`.yml` extension. Bare names are stored under `<name>/telo.yaml`;
|
|
26
|
+
* extension-bearing names are stored literally. Object-array `content` is
|
|
27
|
+
* serialized via `yaml.stringify` so the loader downstream is identical to
|
|
28
|
+
* the YAML-text path. */
|
|
29
|
+
set(name: string, content: string | unknown[]): void {
|
|
30
|
+
if (!name) {
|
|
31
|
+
throw new Error("MemorySource.set: name must be non-empty");
|
|
32
|
+
}
|
|
33
|
+
if (name.startsWith("/")) {
|
|
34
|
+
throw new Error(
|
|
35
|
+
`MemorySource.set: name '${name}' must not start with '/' — memory:// has no absolute root`,
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
if (isAbsoluteUrl(name)) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
`MemorySource.set: name '${name}' must be a bare key, not a URL with a scheme`,
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
const normalized = posix.normalize(name);
|
|
44
|
+
if (normalized.startsWith("..") || normalized === "." || normalized === "..") {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`MemorySource.set: name '${name}' contains '..' segments that escape the namespace`,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const text = typeof content === "string"
|
|
51
|
+
? content
|
|
52
|
+
: content
|
|
53
|
+
.filter((doc) => doc !== null && doc !== undefined)
|
|
54
|
+
.map((doc) => yamlStringify(doc))
|
|
55
|
+
.join("---\n");
|
|
56
|
+
|
|
57
|
+
const hasYamlExt = normalized.endsWith(".yaml") || normalized.endsWith(".yml");
|
|
58
|
+
const key = hasYamlExt ? normalized : `${normalized}/${DEFAULT_MANIFEST_FILENAME}`;
|
|
59
|
+
this.entries.set(key, text);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
supports(url: string): boolean {
|
|
63
|
+
return url.startsWith(SCHEME);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async read(url: string): Promise<{ text: string; source: string }> {
|
|
67
|
+
const key = stripScheme(url);
|
|
68
|
+
// Direct hit (literal-extension files, or already-canonicalized telo.yaml URLs).
|
|
69
|
+
const direct = this.entries.get(key);
|
|
70
|
+
if (direct !== undefined) {
|
|
71
|
+
return { text: direct, source: `${SCHEME}${key}` };
|
|
72
|
+
}
|
|
73
|
+
// Directory-style fall-through: bare module name → <name>/telo.yaml.
|
|
74
|
+
const fallback = `${key}/${DEFAULT_MANIFEST_FILENAME}`;
|
|
75
|
+
const fallbackText = this.entries.get(fallback);
|
|
76
|
+
if (fallbackText !== undefined) {
|
|
77
|
+
return { text: fallbackText, source: `${SCHEME}${fallback}` };
|
|
78
|
+
}
|
|
79
|
+
throw new Error(
|
|
80
|
+
`MemorySource: no entry for '${url}'. Tried keys '${key}' and '${fallback}'.`,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
resolveRelative(base: string, relative: string): string {
|
|
85
|
+
if (isAbsoluteUrl(relative)) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
`MemorySource.resolveRelative: relative '${relative}' is an absolute URL — pass it directly, not through resolveRelative`,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
if (relative.startsWith("/")) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`MemorySource.resolveRelative: 'memory://' has no absolute root; use a full 'memory://<name>' URL instead of '${relative}'`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
const baseKey = stripScheme(base);
|
|
96
|
+
const joined = posix.normalize(posix.join(posix.dirname(baseKey), relative));
|
|
97
|
+
if (joined === ".." || joined.startsWith("../")) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`MemorySource.resolveRelative: relative '${relative}' escapes the memory:// namespace from base '${base}'`,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
return `${SCHEME}${joined}`;
|
|
103
|
+
}
|
|
104
|
+
}
|
package/src/module-context.ts
CHANGED
|
@@ -54,7 +54,7 @@ export class ModuleContext extends EvaluationContext implements IModuleContext {
|
|
|
54
54
|
private _resources: Record<string, unknown>;
|
|
55
55
|
|
|
56
56
|
/** Maps import alias → real module name for kind resolution. */
|
|
57
|
-
readonly importAliases = new Map<string, string>();
|
|
57
|
+
private readonly importAliases = new Map<string, string>();
|
|
58
58
|
|
|
59
59
|
/** Maps import alias → allowed kind names. Absent entry = unrestricted (e.g. Kernel). */
|
|
60
60
|
private readonly importedKinds = new Map<string, Set<string>>();
|
|
@@ -139,6 +139,10 @@ export class ModuleContext extends EvaluationContext implements IModuleContext {
|
|
|
139
139
|
}
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
hasImport(alias: string): boolean {
|
|
143
|
+
return this.importAliases.has(alias);
|
|
144
|
+
}
|
|
145
|
+
|
|
142
146
|
getInstance(name: string): unknown {
|
|
143
147
|
const entry = this.resourceInstances.get(name);
|
|
144
148
|
if (!entry) {
|
|
@@ -163,7 +167,10 @@ export class ModuleContext extends EvaluationContext implements IModuleContext {
|
|
|
163
167
|
/**
|
|
164
168
|
* Resolve a fully-qualified kind like "Http.Server" to its real kind "http-server.Server".
|
|
165
169
|
* Splits on the first dot, looks up the prefix in importAliases, validates against
|
|
166
|
-
* importedKinds (if set), and reconstructs the resolved kind.
|
|
170
|
+
* importedKinds (if set), and reconstructs the resolved kind. When the alias is not
|
|
171
|
+
* present locally, walks up the lifecycle parent chain so children inherit ancestors'
|
|
172
|
+
* imports (notably the root's `Telo` built-in). Sibling modules — being absent from the
|
|
173
|
+
* chain — remain isolated.
|
|
167
174
|
* Throws with a clear message if the alias is unknown or the kind is not exported.
|
|
168
175
|
*/
|
|
169
176
|
resolveKind(kind: string): string {
|
|
@@ -175,6 +182,11 @@ export class ModuleContext extends EvaluationContext implements IModuleContext {
|
|
|
175
182
|
const suffix = kind.slice(dot + 1);
|
|
176
183
|
const realModule = this.importAliases.get(prefix);
|
|
177
184
|
if (!realModule) {
|
|
185
|
+
let cur = this.parent;
|
|
186
|
+
while (cur) {
|
|
187
|
+
if (cur instanceof ModuleContext) return cur.resolveKind(kind);
|
|
188
|
+
cur = cur.parent;
|
|
189
|
+
}
|
|
178
190
|
const known = [...this.importAliases.keys()].join(", ") || "(none)";
|
|
179
191
|
throw new Error(
|
|
180
192
|
`Kind '${kind}': no module imported with alias '${prefix}'. Known aliases: ${known}`,
|
package/src/registry.ts
CHANGED
|
@@ -15,7 +15,6 @@ export class ManifestRegistry {
|
|
|
15
15
|
register(resource: RuntimeResource): void {
|
|
16
16
|
const { kind, metadata } = resource;
|
|
17
17
|
const { name } = metadata;
|
|
18
|
-
console.log("Registering resource:", kind, name);
|
|
19
18
|
if (!this.resources.has(kind)) {
|
|
20
19
|
this.resources.set(kind, new Map());
|
|
21
20
|
}
|
package/src/resource-context.ts
CHANGED
|
@@ -13,9 +13,9 @@ import {
|
|
|
13
13
|
type ParsedArgs,
|
|
14
14
|
type TypeRule,
|
|
15
15
|
} from "@telorun/sdk";
|
|
16
|
-
import { EvaluationContext } from "./evaluation-context.js";
|
|
17
16
|
import AjvModule from "ajv";
|
|
18
17
|
import addFormats from "ajv-formats";
|
|
18
|
+
import { EvaluationContext } from "./evaluation-context.js";
|
|
19
19
|
import { Kernel } from "./kernel.js";
|
|
20
20
|
import { formatAjvErrors } from "./manifest-schemas.js";
|
|
21
21
|
import { policyFingerprint } from "./runtime-registry.js";
|
|
@@ -219,8 +219,7 @@ export class ResourceContextImpl implements ResourceContext {
|
|
|
219
219
|
const hasInlineProperties = Object.keys(resource).some(
|
|
220
220
|
(k) => k !== "kind" && k !== "name" && k !== "metadata",
|
|
221
221
|
);
|
|
222
|
-
const hasExplicitName =
|
|
223
|
-
resource.name !== undefined || resource.metadata?.name !== undefined;
|
|
222
|
+
const hasExplicitName = resource.name !== undefined || resource.metadata?.name !== undefined;
|
|
224
223
|
const shouldRegister =
|
|
225
224
|
(hasInlineProperties || (!hasExplicitName && resourceName !== undefined)) &&
|
|
226
225
|
!this.moduleContext.hasManifest(name);
|
|
@@ -239,20 +238,6 @@ export class ResourceContextImpl implements ResourceContext {
|
|
|
239
238
|
return { kind, name };
|
|
240
239
|
}
|
|
241
240
|
|
|
242
|
-
teardownResource(kind: string, name: string): Promise<void> {
|
|
243
|
-
throw new Error("Method teardownResource not implemented.");
|
|
244
|
-
// const parts = kind.split(".");
|
|
245
|
-
// if (parts.length > 2) {
|
|
246
|
-
// return this.kernel.teardownResource(parts[0], parts.slice(1).join("."), name);
|
|
247
|
-
// }
|
|
248
|
-
// return this.kernel.teardownResource(this.metadata.module, kind, name);
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
getResources(kind: string): RuntimeResource[] {
|
|
252
|
-
throw new Error("Method teardownResource not implemented.");
|
|
253
|
-
// return this.kernel.getResourcesByKind(kind);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
241
|
getResourcesByName(_kind: string, name: string): RuntimeResource | null {
|
|
257
242
|
const entry = this.moduleContext.resourceInstances.get(name);
|
|
258
243
|
return (entry?.resource ?? null) as RuntimeResource | null;
|
|
@@ -279,14 +264,6 @@ export class ResourceContextImpl implements ResourceContext {
|
|
|
279
264
|
this.kernel.on(event, handler);
|
|
280
265
|
}
|
|
281
266
|
|
|
282
|
-
once(event: string, handler: (payload?: any) => void | Promise<void>): void {
|
|
283
|
-
throw new Error("Method once not implemented.");
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
off(event: string, handler: (payload?: any) => void | Promise<void>): void {
|
|
287
|
-
throw new Error("Method off not implemented.");
|
|
288
|
-
}
|
|
289
|
-
|
|
290
267
|
async emit(event: string, payload?: any) {
|
|
291
268
|
await this.kernel.emitRuntimeEvent(`${this.metadata.name}.${event}`, payload);
|
|
292
269
|
}
|
|
@@ -308,16 +285,7 @@ export class ResourceContextImpl implements ResourceContext {
|
|
|
308
285
|
}
|
|
309
286
|
|
|
310
287
|
registerModuleImport(alias: string, targetModule: string, kinds: string[]): void {
|
|
311
|
-
|
|
312
|
-
this.kernel.registerModuleImport(declaringModule ?? "", alias, targetModule, kinds);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
resolveModuleAlias(declaringModule: string, alias: string): string | undefined {
|
|
316
|
-
return this.kernel.resolveModuleAlias(declaringModule, alias);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
getModuleContext(moduleName: string): ModuleContext {
|
|
320
|
-
return this.kernel.getModuleContext(moduleName);
|
|
288
|
+
this.moduleContext.registerImport(alias, targetModule, kinds);
|
|
321
289
|
}
|
|
322
290
|
|
|
323
291
|
/**
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"local-file-adapter.d.ts","sourceRoot":"","sources":["../../src/manifest-adapters/local-file-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAcpF,qBAAa,gBAAiB,YAAW,eAAe;IACtD,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAU9B,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAQlE,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IASnD,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAMjD,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAgB/D,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;YAqB/C,kBAAkB;IAchC,OAAO,CAAC,UAAU;CAGnB"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"local-file-adapter.js","sourceRoot":"","sources":["../../src/manifest-adapters/local-file-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
export interface ManifestSourceData {
|
|
2
|
-
/** Raw YAML text */
|
|
3
|
-
text: string;
|
|
4
|
-
/** Parsed YAML documents (result of yaml.loadAll) */
|
|
5
|
-
documents: any[];
|
|
6
|
-
/** Stored as metadata.source (file path or URL) */
|
|
7
|
-
source: string;
|
|
8
|
-
/** Base directory for resolving relative controller entrypoints */
|
|
9
|
-
baseDir: string;
|
|
10
|
-
/** URI prefix — full resource URI is `${uriBase}#${kind}.${name}` */
|
|
11
|
-
uriBase: string;
|
|
12
|
-
}
|
|
13
|
-
export interface ManifestAdapter {
|
|
14
|
-
/** Returns true if this adapter can handle the given path/URL */
|
|
15
|
-
supports(pathOrUrl: string): boolean;
|
|
16
|
-
/**
|
|
17
|
-
* Read a single manifest entry point.
|
|
18
|
-
* - File path or URL → read that file/URL.
|
|
19
|
-
* - Directory path → find and read `telo.yaml` within it.
|
|
20
|
-
*/
|
|
21
|
-
read(pathOrUrl: string): Promise<ManifestSourceData>;
|
|
22
|
-
/**
|
|
23
|
-
* Read all manifest files reachable from the given path/URL.
|
|
24
|
-
* Used for module imports.
|
|
25
|
-
* - Directory path → recursive walk, one entry per .yaml/.yml file found.
|
|
26
|
-
* - File path or URL → single-item array.
|
|
27
|
-
*/
|
|
28
|
-
readAll(pathOrUrl: string): Promise<ManifestSourceData[]>;
|
|
29
|
-
/**
|
|
30
|
-
* Resolve a potentially relative path/URL against a base directory/URL.
|
|
31
|
-
* For absolute inputs the base is ignored.
|
|
32
|
-
*/
|
|
33
|
-
resolveRelative(base: string, relative: string): string;
|
|
34
|
-
}
|
|
35
|
-
//# sourceMappingURL=manifest-adapter.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"manifest-adapter.d.ts","sourceRoot":"","sources":["../../src/manifest-adapters/manifest-adapter.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,qDAAqD;IACrD,SAAS,EAAE,GAAG,EAAE,CAAC;IACjB,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC;IACrC;;;;OAIG;IACH,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACrD;;;;;OAKG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAAC;IAC1D;;;OAGG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;CACzD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"manifest-adapter.js","sourceRoot":"","sources":["../../src/manifest-adapters/manifest-adapter.ts"],"names":[],"mappings":""}
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
export interface ManifestSourceData {
|
|
2
|
-
/** Raw YAML text */
|
|
3
|
-
text: string;
|
|
4
|
-
/** Parsed YAML documents (result of yaml.loadAll) */
|
|
5
|
-
documents: any[];
|
|
6
|
-
/** Stored as metadata.source (file path or URL) */
|
|
7
|
-
source: string;
|
|
8
|
-
/** Base directory for resolving relative controller entrypoints */
|
|
9
|
-
baseDir: string;
|
|
10
|
-
/** URI prefix — full resource URI is `${uriBase}#${kind}.${name}` */
|
|
11
|
-
uriBase: string;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export interface ManifestAdapter {
|
|
15
|
-
/** Returns true if this adapter can handle the given path/URL */
|
|
16
|
-
supports(pathOrUrl: string): boolean;
|
|
17
|
-
/**
|
|
18
|
-
* Read a single manifest entry point.
|
|
19
|
-
* - File path or URL → read that file/URL.
|
|
20
|
-
* - Directory path → find and read `telo.yaml` within it.
|
|
21
|
-
*/
|
|
22
|
-
read(pathOrUrl: string): Promise<ManifestSourceData>;
|
|
23
|
-
/**
|
|
24
|
-
* Read all manifest files reachable from the given path/URL.
|
|
25
|
-
* Used for module imports.
|
|
26
|
-
* - Directory path → recursive walk, one entry per .yaml/.yml file found.
|
|
27
|
-
* - File path or URL → single-item array.
|
|
28
|
-
*/
|
|
29
|
-
readAll(pathOrUrl: string): Promise<ManifestSourceData[]>;
|
|
30
|
-
/**
|
|
31
|
-
* Resolve a potentially relative path/URL against a base directory/URL.
|
|
32
|
-
* For absolute inputs the base is ignored.
|
|
33
|
-
*/
|
|
34
|
-
resolveRelative(base: string, relative: string): string;
|
|
35
|
-
}
|