@telorun/cli 0.70.0 → 0.72.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/bundle/partition-layers.d.ts +11 -26
- package/dist/bundle/partition-layers.d.ts.map +1 -1
- package/dist/bundle/partition-layers.js +37 -88
- package/dist/bundle/partition-layers.js.map +1 -1
- package/dist/cli.js +11 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/cel.d.ts +18 -0
- package/dist/commands/cel.d.ts.map +1 -1
- package/dist/commands/cel.js +60 -12
- package/dist/commands/cel.js.map +1 -1
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +43 -8
- package/dist/commands/check.js.map +1 -1
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +27 -17
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/module.d.ts.map +1 -1
- package/dist/commands/module.js +36 -31
- package/dist/commands/module.js.map +1 -1
- package/dist/commands/publish.d.ts.map +1 -1
- package/dist/commands/publish.js +57 -26
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/run.d.ts.map +1 -1
- package/dist/commands/run.js +15 -4
- package/dist/commands/run.js.map +1 -1
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +19 -10
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/upgrade.d.ts.map +1 -1
- package/dist/commands/upgrade.js +35 -21
- package/dist/commands/upgrade.js.map +1 -1
- package/dist/controller-progress.d.ts.map +1 -1
- package/dist/controller-progress.js +0 -0
- package/dist/controller-progress.js.map +1 -1
- package/dist/debug-event-subscriber.d.ts.map +1 -1
- package/dist/debug-event-subscriber.js +2 -1
- package/dist/debug-event-subscriber.js.map +1 -1
- package/dist/logger.d.ts +33 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +73 -37
- package/dist/logger.js.map +1 -1
- package/dist/output.d.ts +111 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +143 -0
- package/dist/output.js.map +1 -0
- package/package.json +6 -6
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ArtifactSelector } from "@telorun/analyzer";
|
|
1
|
+
import { type ArtifactSelector, type ModuleFileClaim } from "@telorun/analyzer";
|
|
2
2
|
import type { PayloadLayer } from "@telorun/kernel";
|
|
3
3
|
/** Manifest-relative POSIX path of a selected file, grouped into the layer it
|
|
4
4
|
* belongs to. Content is read by the caller — this module decides membership
|
|
@@ -16,29 +16,13 @@ export interface Partition {
|
|
|
16
16
|
/** `assets:` patterns that matched nothing — almost always a typo, and invisible
|
|
17
17
|
* in `layers` because an empty layer is dropped. */
|
|
18
18
|
unmatchedAssets: string[];
|
|
19
|
-
/** `siblings=` patterns that matched nothing, with the
|
|
19
|
+
/** `siblings=` patterns that matched nothing, with the claim that declared
|
|
20
20
|
* each one. */
|
|
21
21
|
unmatchedSiblings: Array<{
|
|
22
|
-
|
|
22
|
+
origin: string;
|
|
23
23
|
pattern: string;
|
|
24
24
|
}>;
|
|
25
25
|
}
|
|
26
|
-
interface ControllerClaim {
|
|
27
|
-
selector: ArtifactSelector;
|
|
28
|
-
/** Entry-point path exactly as `path=` names it, manifest-relative. */
|
|
29
|
-
entry: string;
|
|
30
|
-
/** Sibling patterns declared on the same candidate. */
|
|
31
|
-
siblings: string[];
|
|
32
|
-
/** For diagnostics: the PURL this claim came from. */
|
|
33
|
-
purl: string;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Every bundled-controller candidate declared anywhere in the manifest, with its
|
|
37
|
-
* selector and the files it claims. Read from `controllers:` on each doc — the
|
|
38
|
-
* manifest already names each entry point, so the partition is derived rather
|
|
39
|
-
* than declared.
|
|
40
|
-
*/
|
|
41
|
-
export declare function readControllerClaims(manifestText: string): ControllerClaim[];
|
|
42
26
|
/**
|
|
43
27
|
* Partition the selected payload into the layers a module artifact ships.
|
|
44
28
|
*
|
|
@@ -53,13 +37,15 @@ export declare function readControllerClaims(manifestText: string): ControllerCl
|
|
|
53
37
|
* therefore costs bytes, never a module-not-found at runtime. Both declarations
|
|
54
38
|
* are optional and only ever buy laziness.
|
|
55
39
|
*
|
|
56
|
-
* `
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
40
|
+
* `claims` is everything the manifest names — read by `collectModuleFileClaims`,
|
|
41
|
+
* which asks each syntax's own owner (this module recognises neither a PURL nor
|
|
42
|
+
* a YAML tag). `files` are the manifest-relative paths `selectFiles` produced;
|
|
43
|
+
* `assetPatterns` is the author's `assets:` list. A claimed file joins the
|
|
44
|
+
* payload whether or not `files:` selected it — the manifest already names it,
|
|
45
|
+
* so restating it would be pure duplication. Layers with no files are dropped,
|
|
46
|
+
* so a controller-only module publishes exactly one payload layer.
|
|
61
47
|
*/
|
|
62
|
-
export declare function partitionLayers(
|
|
48
|
+
export declare function partitionLayers(claims: readonly ModuleFileClaim[], files: string[], assetPatterns: string[]): Partition;
|
|
63
49
|
/**
|
|
64
50
|
* One line per layer for the publish output, so an author can see that a file they
|
|
65
51
|
* meant as a sidecar or an asset landed in `common` instead.
|
|
@@ -69,5 +55,4 @@ export declare function partitionLayers(manifestText: string, files: string[], a
|
|
|
69
55
|
* silence about the single mistake this output exists to catch.
|
|
70
56
|
*/
|
|
71
57
|
export declare function describePartition(partition: Partition): string[];
|
|
72
|
-
export {};
|
|
73
58
|
//# sourceMappingURL=partition-layers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"partition-layers.d.ts","sourceRoot":"","sources":["../../src/bundle/partition-layers.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"partition-layers.d.ts","sourceRoot":"","sources":["../../src/bundle/partition-layers.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACrB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD;;uDAEuD;AACvD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IAC3B,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;uEAEuE;AACvE,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB;yDACqD;IACrD,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B;oBACgB;IAChB,iBAAiB,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/D;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,SAAS,eAAe,EAAE,EAClC,KAAK,EAAE,MAAM,EAAE,EACf,aAAa,EAAE,MAAM,EAAE,GACtB,SAAS,CA4EX;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,EAAE,CAYhE"}
|
|
@@ -1,67 +1,5 @@
|
|
|
1
|
-
import { describeSelector,
|
|
1
|
+
import { describeSelector, selectorKey, } from "@telorun/analyzer";
|
|
2
2
|
import { selectByPatterns } from "@telorun/glob";
|
|
3
|
-
import { defaultCustomTags } from "@telorun/templating";
|
|
4
|
-
import { PackageURL } from "packageurl-js";
|
|
5
|
-
import { parseAllDocuments } from "yaml";
|
|
6
|
-
/** `pkg:telo/local/<format>?path=…` — the bundled-controller delivery mode.
|
|
7
|
-
* Anything else (`pkg:npm`, `pkg:cargo`) fetches from its own ecosystem and
|
|
8
|
-
* contributes no layer. */
|
|
9
|
-
const BUNDLED_TYPE = "telo";
|
|
10
|
-
const BUNDLED_NAMESPACE = "local";
|
|
11
|
-
/** Qualifier naming extra files that belong in a controller's layer — what an
|
|
12
|
-
* entry point loads but the manifest cannot otherwise see (a `.wasm` beside its
|
|
13
|
-
* glue, a native library opened at runtime). Comma-separated
|
|
14
|
-
* `.gitignore`-style patterns, matched through the one glob engine. Optional:
|
|
15
|
-
* an unclaimed sidecar joins the common layer, which every controller-hosting
|
|
16
|
-
* kernel pulls, so omitting it costs bytes rather than a broken import. */
|
|
17
|
-
const SIBLINGS_QUALIFIER = "siblings";
|
|
18
|
-
/** Normalize a `path=` / sibling value to the manifest-relative POSIX form
|
|
19
|
-
* `selectFiles` returns, so membership is a string comparison. */
|
|
20
|
-
function normalizeRelative(value) {
|
|
21
|
-
return value.replace(/^\.\//, "").replace(/\\/g, "/");
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Every bundled-controller candidate declared anywhere in the manifest, with its
|
|
25
|
-
* selector and the files it claims. Read from `controllers:` on each doc — the
|
|
26
|
-
* manifest already names each entry point, so the partition is derived rather
|
|
27
|
-
* than declared.
|
|
28
|
-
*/
|
|
29
|
-
export function readControllerClaims(manifestText) {
|
|
30
|
-
const claims = [];
|
|
31
|
-
for (const doc of parseAllDocuments(manifestText, { customTags: defaultCustomTags() })) {
|
|
32
|
-
const json = doc.toJSON();
|
|
33
|
-
const candidates = Array.isArray(json?.controllers) ? json.controllers : [];
|
|
34
|
-
for (const candidate of candidates) {
|
|
35
|
-
if (typeof candidate !== "string")
|
|
36
|
-
continue;
|
|
37
|
-
let parsed;
|
|
38
|
-
try {
|
|
39
|
-
parsed = PackageURL.fromString(candidate);
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
// Not a parseable PURL — publish is not the place to reject it; the
|
|
43
|
-
// analyzer and the controller loader both report it with better context.
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
if (parsed.type !== BUNDLED_TYPE || parsed.namespace !== BUNDLED_NAMESPACE)
|
|
47
|
-
continue;
|
|
48
|
-
const entry = parsed.qualifiers?.path;
|
|
49
|
-
if (typeof entry !== "string" || entry === "")
|
|
50
|
-
continue;
|
|
51
|
-
const siblings = String(parsed.qualifiers?.[SIBLINGS_QUALIFIER] ?? "")
|
|
52
|
-
.split(",")
|
|
53
|
-
.map((p) => p.trim())
|
|
54
|
-
.filter((p) => p !== "");
|
|
55
|
-
claims.push({
|
|
56
|
-
selector: selectorFromQualifiers(parsed.name, parsed.qualifiers, `controller "${candidate}"`),
|
|
57
|
-
entry: normalizeRelative(entry),
|
|
58
|
-
siblings,
|
|
59
|
-
purl: candidate,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return claims;
|
|
64
|
-
}
|
|
65
3
|
/**
|
|
66
4
|
* Partition the selected payload into the layers a module artifact ships.
|
|
67
5
|
*
|
|
@@ -76,24 +14,30 @@ export function readControllerClaims(manifestText) {
|
|
|
76
14
|
* therefore costs bytes, never a module-not-found at runtime. Both declarations
|
|
77
15
|
* are optional and only ever buy laziness.
|
|
78
16
|
*
|
|
79
|
-
* `
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
17
|
+
* `claims` is everything the manifest names — read by `collectModuleFileClaims`,
|
|
18
|
+
* which asks each syntax's own owner (this module recognises neither a PURL nor
|
|
19
|
+
* a YAML tag). `files` are the manifest-relative paths `selectFiles` produced;
|
|
20
|
+
* `assetPatterns` is the author's `assets:` list. A claimed file joins the
|
|
21
|
+
* payload whether or not `files:` selected it — the manifest already names it,
|
|
22
|
+
* so restating it would be pure duplication. Layers with no files are dropped,
|
|
23
|
+
* so a controller-only module publishes exactly one payload layer.
|
|
84
24
|
*/
|
|
85
|
-
export function partitionLayers(
|
|
86
|
-
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
|
|
90
|
-
|
|
25
|
+
export function partitionLayers(claims, files, assetPatterns) {
|
|
26
|
+
// Narrowing predicates, so the controller branch reaches `selector` and
|
|
27
|
+
// `siblings` as declared fields rather than through a non-null assertion —
|
|
28
|
+
// the claim type is a discriminated union precisely so this is checked.
|
|
29
|
+
const controllers = claims.filter((claim) => claim.role === "controller");
|
|
30
|
+
const claimedAssets = claims.filter((claim) => claim.role === "assets");
|
|
31
|
+
// A claimed file is part of the payload because the manifest names it, not
|
|
32
|
+
// because `files:` restates it. `files:` keeps its role for everything the
|
|
33
|
+
// manifest cannot otherwise see — static files, sidecars — and a module whose
|
|
34
|
+
// only payload is its controller declares no `files:` at all.
|
|
91
35
|
//
|
|
92
36
|
// Sibling patterns are still matched against `files:` alone: a sibling is a
|
|
93
37
|
// glob over the payload, so a pattern that selects nothing there means the
|
|
94
38
|
// author forgot to include the file, which `unmatchedSiblings` reports.
|
|
95
|
-
const selected = new Set([...files, ...claims.map((claim) => claim.
|
|
96
|
-
const unclaimed = new Set(files);
|
|
39
|
+
const selected = new Set([...files, ...claims.map((claim) => claim.path)]);
|
|
40
|
+
const unclaimed = new Set([...files, ...claimedAssets.map((claim) => claim.path)]);
|
|
97
41
|
// Controller layers first: a file an entry point or sibling claims belongs to
|
|
98
42
|
// that selector, never to assets or common, so the layer a kernel skips is
|
|
99
43
|
// genuinely skippable. A file several candidates claim is copied into each of
|
|
@@ -102,30 +46,35 @@ export function partitionLayers(manifestText, files, assetPatterns) {
|
|
|
102
46
|
// would break the "a declaration never costs correctness" guarantee.
|
|
103
47
|
const bySelector = new Map();
|
|
104
48
|
const unmatchedSiblings = [];
|
|
105
|
-
for (const claim of
|
|
49
|
+
for (const claim of controllers) {
|
|
106
50
|
const key = selectorKey(claim.selector);
|
|
107
51
|
let plan = bySelector.get(key);
|
|
108
52
|
if (!plan) {
|
|
109
53
|
plan = { role: "controller", selector: claim.selector, files: [] };
|
|
110
54
|
bySelector.set(key, plan);
|
|
111
55
|
}
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
for (const pattern of claim.siblings) {
|
|
56
|
+
const patterns = [...claim.siblings];
|
|
57
|
+
const siblings = selectByPatterns([...selected], patterns, { applyDefaultIgnore: false });
|
|
58
|
+
for (const pattern of patterns) {
|
|
116
59
|
if (selectByPatterns([...selected], [pattern], { applyDefaultIgnore: false }).length === 0) {
|
|
117
|
-
unmatchedSiblings.push({
|
|
60
|
+
unmatchedSiblings.push({ origin: claim.origin, pattern });
|
|
118
61
|
}
|
|
119
62
|
}
|
|
120
|
-
for (const file of [claim.
|
|
63
|
+
for (const file of [claim.path, ...siblings]) {
|
|
121
64
|
unclaimed.delete(file);
|
|
122
65
|
if (!plan.files.includes(file))
|
|
123
66
|
plan.files.push(file);
|
|
124
67
|
}
|
|
125
68
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
69
|
+
// A file a tag embeds is an asset by declaration, so it needs no `assets:`
|
|
70
|
+
// pattern to be lazy — the manifest already said what it is. A pattern can
|
|
71
|
+
// still claim more, and a file claimed both ways is one file.
|
|
72
|
+
const assetFiles = [
|
|
73
|
+
...new Set([
|
|
74
|
+
...claimedAssets.map((claim) => claim.path).filter((file) => unclaimed.has(file)),
|
|
75
|
+
...selectByPatterns([...unclaimed], assetPatterns, { applyDefaultIgnore: false }),
|
|
76
|
+
]),
|
|
77
|
+
].sort();
|
|
129
78
|
for (const file of assetFiles)
|
|
130
79
|
unclaimed.delete(file);
|
|
131
80
|
const unmatchedAssets = assetPatterns.filter((pattern) => !pattern.startsWith("!") &&
|
|
@@ -157,8 +106,8 @@ export function describePartition(partition) {
|
|
|
157
106
|
for (const pattern of partition.unmatchedAssets) {
|
|
158
107
|
lines.push(`assets pattern '${pattern}' matched no file`);
|
|
159
108
|
}
|
|
160
|
-
for (const {
|
|
161
|
-
lines.push(`siblings pattern '${pattern}' matched no file (from ${
|
|
109
|
+
for (const { origin, pattern } of partition.unmatchedSiblings) {
|
|
110
|
+
lines.push(`siblings pattern '${pattern}' matched no file (from ${origin})`);
|
|
162
111
|
}
|
|
163
112
|
return lines;
|
|
164
113
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"partition-layers.js","sourceRoot":"","sources":["../../src/bundle/partition-layers.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,
|
|
1
|
+
{"version":3,"file":"partition-layers.js","sourceRoot":"","sources":["../../src/bundle/partition-layers.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import yargs from "yargs";
|
|
3
3
|
import { hideBin } from "yargs/helpers";
|
|
4
|
+
import { OUTPUT_FORMATS, configureOutput, parseOutputFormat } from "./output.js";
|
|
4
5
|
import { celCommand } from "./commands/cel.js";
|
|
5
6
|
import { checkCommand } from "./commands/check.js";
|
|
6
7
|
import { installCommand } from "./commands/install.js";
|
|
@@ -47,6 +48,16 @@ cli
|
|
|
47
48
|
default: true,
|
|
48
49
|
describe: "Persist the analysis/validator cache to disk. Use --no-cache-write for an ephemeral, read-only run (validates in-memory, reads the baked cache but never writes it).",
|
|
49
50
|
})
|
|
51
|
+
.option("output", {
|
|
52
|
+
alias: "o",
|
|
53
|
+
type: "string",
|
|
54
|
+
choices: OUTPUT_FORMATS,
|
|
55
|
+
default: "text",
|
|
56
|
+
describe: "Output format for the CLI's own output. `json` is a machine contract and never carries colour. Note `telo run` streams the app's stdout/stderr through untouched — the app picks its own encoding via its `logging:` block.",
|
|
57
|
+
})
|
|
58
|
+
// Runs before any handler, so a call site deep inside a command reaches the
|
|
59
|
+
// same decision without the format being threaded through every signature.
|
|
60
|
+
.middleware((argv) => configureOutput(parseOutputFormat(argv.output)), true)
|
|
50
61
|
.demandCommand(1, "Please specify a command or path to run")
|
|
51
62
|
.strict()
|
|
52
63
|
.help()
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,IAAI,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;KACnC,UAAU,CAAC,MAAM,CAAC;KAClB,KAAK,CAAC,wBAAwB,CAAC,CAAC;AAEnC,GAAG,GAAG,UAAU,CAAC,GAAG,CAAe,CAAC;AACpC,GAAG,GAAG,YAAY,CAAC,GAAG,CAAe,CAAC;AACtC,GAAG,GAAG,cAAc,CAAC,GAAG,CAAe,CAAC;AACxC,GAAG,GAAG,aAAa,CAAC,GAAG,CAAe,CAAC;AACvC,GAAG,GAAG,cAAc,CAAC,GAAG,CAAe,CAAC;AACxC,GAAG,GAAG,UAAU,CAAC,GAAG,CAAe,CAAC;AACpC,GAAG,GAAG,aAAa,CAAC,GAAG,CAAe,CAAC;AACvC,GAAG,GAAG,cAAc,CAAC,GAAG,CAAe,CAAC;AAExC,GAAG;KACA,MAAM,CAAC,SAAS,EAAE;IACjB,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,wBAAwB;CACnC,CAAC;KACD,MAAM,CAAC,OAAO,EAAE;IACf,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,8BAA8B;CACzC,CAAC;KACD,MAAM,CAAC,kBAAkB,EAAE;IAC1B,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,4BAA4B;CACvC,CAAC;KACD,MAAM,CAAC,OAAO,EAAE;IACf,KAAK,EAAE,GAAG;IACV,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,2CAA2C;CACtD,CAAC;KACD,MAAM,CAAC,aAAa,EAAE;IACrB,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,IAAI;IACb,QAAQ,EACN,sKAAsK;CACzK,CAAC;KACD,aAAa,CAAC,CAAC,EAAE,yCAAyC,CAAC;KAC3D,MAAM,EAAE;KACR,IAAI,EAAE;KACN,OAAO,EAAE;KACT,KAAK,EAAE,CAAC"}
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD,IAAI,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;KACnC,UAAU,CAAC,MAAM,CAAC;KAClB,KAAK,CAAC,wBAAwB,CAAC,CAAC;AAEnC,GAAG,GAAG,UAAU,CAAC,GAAG,CAAe,CAAC;AACpC,GAAG,GAAG,YAAY,CAAC,GAAG,CAAe,CAAC;AACtC,GAAG,GAAG,cAAc,CAAC,GAAG,CAAe,CAAC;AACxC,GAAG,GAAG,aAAa,CAAC,GAAG,CAAe,CAAC;AACvC,GAAG,GAAG,cAAc,CAAC,GAAG,CAAe,CAAC;AACxC,GAAG,GAAG,UAAU,CAAC,GAAG,CAAe,CAAC;AACpC,GAAG,GAAG,aAAa,CAAC,GAAG,CAAe,CAAC;AACvC,GAAG,GAAG,cAAc,CAAC,GAAG,CAAe,CAAC;AAExC,GAAG;KACA,MAAM,CAAC,SAAS,EAAE;IACjB,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,wBAAwB;CACnC,CAAC;KACD,MAAM,CAAC,OAAO,EAAE;IACf,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,8BAA8B;CACzC,CAAC;KACD,MAAM,CAAC,kBAAkB,EAAE;IAC1B,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,4BAA4B;CACvC,CAAC;KACD,MAAM,CAAC,OAAO,EAAE;IACf,KAAK,EAAE,GAAG;IACV,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,KAAK;IACd,QAAQ,EAAE,2CAA2C;CACtD,CAAC;KACD,MAAM,CAAC,aAAa,EAAE;IACrB,IAAI,EAAE,SAAS;IACf,OAAO,EAAE,IAAI;IACb,QAAQ,EACN,sKAAsK;CACzK,CAAC;KACD,MAAM,CAAC,QAAQ,EAAE;IAChB,KAAK,EAAE,GAAG;IACV,IAAI,EAAE,QAAQ;IACd,OAAO,EAAE,cAAc;IACvB,OAAO,EAAE,MAAe;IACxB,QAAQ,EACN,6NAA6N;CAChO,CAAC;IACF,4EAA4E;IAC5E,2EAA2E;KAC1E,UAAU,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,eAAe,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC;KAC3E,aAAa,CAAC,CAAC,EAAE,yCAAyC,CAAC;KAC3D,MAAM,EAAE;KACR,IAAI,EAAE;KACN,OAAO,EAAE;KACT,KAAK,EAAE,CAAC"}
|
package/dist/commands/cel.d.ts
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
import { type CelFunctionInfo } from "@telorun/templating";
|
|
1
2
|
import type { Argv } from "yargs";
|
|
3
|
+
/** A CEL built-in, in the same shape as a catalog entry so one listing covers
|
|
4
|
+
* both halves of what a manifest may call. `receiver` is what the catalog
|
|
5
|
+
* cannot express: a built-in is usually a METHOD, and calling it as a global
|
|
6
|
+
* does not type-check. Leaving them out was the reason an author could read
|
|
7
|
+
* this command end to end and still write `startsWith(key, 'x')`. */
|
|
8
|
+
interface CelBuiltinInfo {
|
|
9
|
+
name: string;
|
|
10
|
+
signature: string;
|
|
11
|
+
category: "builtin";
|
|
12
|
+
receiver: string | null;
|
|
13
|
+
}
|
|
14
|
+
/** The `--json` document: Telo's catalog followed by CEL's built-ins. Exported
|
|
15
|
+
* for tests — the listing is what every new CEL diagnostic points a reader at,
|
|
16
|
+
* so "does it contain the functions those diagnostics are about" is worth
|
|
17
|
+
* asserting without spawning a CLI. */
|
|
18
|
+
export declare function functionListing(): (CelFunctionInfo | CelBuiltinInfo)[];
|
|
2
19
|
export declare function celCommand(yargs: Argv): Argv;
|
|
20
|
+
export {};
|
|
3
21
|
//# sourceMappingURL=cel.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cel.d.ts","sourceRoot":"","sources":["../../src/commands/cel.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cel.d.ts","sourceRoot":"","sources":["../../src/commands/cel.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AAGlC;;;;sEAIsE;AACtE,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,SAAS,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAWD;;;wCAGwC;AACxC,wBAAgB,eAAe,IAAI,CAAC,eAAe,GAAG,cAAc,CAAC,EAAE,CAEtE;AAiGD,wBAAgB,UAAU,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,CAkC5C"}
|
package/dist/commands/cel.js
CHANGED
|
@@ -1,9 +1,31 @@
|
|
|
1
|
-
import { buildCelEnvironment, celFunctionCatalog } from "@telorun/templating";
|
|
1
|
+
import { buildCelEnvironment, celBuiltinFunctions, celFunctionCatalog, } from "@telorun/templating";
|
|
2
2
|
import { enableBigIntJson, nodeCelHandlers } from "@telorun/kernel";
|
|
3
|
+
import { output } from "../output.js";
|
|
4
|
+
function builtins() {
|
|
5
|
+
return celBuiltinFunctions().map((fn) => ({
|
|
6
|
+
name: fn.name,
|
|
7
|
+
signature: fn.signature,
|
|
8
|
+
category: "builtin",
|
|
9
|
+
receiver: fn.receiverType,
|
|
10
|
+
}));
|
|
11
|
+
}
|
|
12
|
+
/** The `--json` document: Telo's catalog followed by CEL's built-ins. Exported
|
|
13
|
+
* for tests — the listing is what every new CEL diagnostic points a reader at,
|
|
14
|
+
* so "does it contain the functions those diagnostics are about" is worth
|
|
15
|
+
* asserting without spawning a CLI. */
|
|
16
|
+
export function functionListing() {
|
|
17
|
+
return [...celFunctionCatalog(), ...builtins()];
|
|
18
|
+
}
|
|
3
19
|
function printFunctions(asJson) {
|
|
4
20
|
const catalog = celFunctionCatalog();
|
|
5
|
-
|
|
6
|
-
|
|
21
|
+
const out = output();
|
|
22
|
+
// `--json` predates the global flag and is an alias for it. The array IS the
|
|
23
|
+
// contract, so it is emitted bare rather than inside an envelope. Built-ins
|
|
24
|
+
// are appended rather than merged into a new shape: a consumer reading
|
|
25
|
+
// `signature` and `name` keeps working, and one reading `category` sees a
|
|
26
|
+
// new value rather than a changed one.
|
|
27
|
+
if (asJson || out.isJson) {
|
|
28
|
+
out.document(functionListing());
|
|
7
29
|
return;
|
|
8
30
|
}
|
|
9
31
|
const byCategory = new Map();
|
|
@@ -13,18 +35,33 @@ function printFunctions(asJson) {
|
|
|
13
35
|
byCategory.set(fn.category, list);
|
|
14
36
|
}
|
|
15
37
|
for (const [category, fns] of byCategory) {
|
|
16
|
-
|
|
38
|
+
out.line(`\n${category}`);
|
|
17
39
|
for (const fn of fns) {
|
|
18
40
|
const tags = [
|
|
19
41
|
fn.hostBacked ? "host" : null,
|
|
20
42
|
fn.deterministic ? null : "non-deterministic",
|
|
21
43
|
].filter(Boolean);
|
|
22
44
|
const suffix = tags.length ? ` [${tags.join(", ")}]` : "";
|
|
23
|
-
|
|
24
|
-
|
|
45
|
+
out.line(` ${fn.signature}${suffix}`);
|
|
46
|
+
out.line(` ${fn.summary}`);
|
|
25
47
|
}
|
|
26
48
|
}
|
|
27
|
-
|
|
49
|
+
// Grouped by receiver, because the grouping IS the information: everything
|
|
50
|
+
// under `on string` must be called on a value, and the globals must not be.
|
|
51
|
+
const byReceiver = new Map();
|
|
52
|
+
for (const fn of builtins()) {
|
|
53
|
+
const key = fn.receiver ?? "";
|
|
54
|
+
const list = byReceiver.get(key) ?? [];
|
|
55
|
+
list.push(fn.signature);
|
|
56
|
+
byReceiver.set(key, list);
|
|
57
|
+
}
|
|
58
|
+
out.line("\nCEL built-ins (provided by CEL itself)");
|
|
59
|
+
for (const [receiver, signatures] of [...byReceiver].sort(([a], [b]) => a.localeCompare(b))) {
|
|
60
|
+
out.line(` ${receiver === "" ? "global functions" : `on ${receiver}`}`);
|
|
61
|
+
for (const signature of signatures.sort())
|
|
62
|
+
out.line(` ${signature}`);
|
|
63
|
+
}
|
|
64
|
+
out.line();
|
|
28
65
|
}
|
|
29
66
|
function evalExpression(expr, contextJson, asJson) {
|
|
30
67
|
// The one command that evaluates CEL without a kernel, so it installs the
|
|
@@ -33,12 +70,17 @@ function evalExpression(expr, contextJson, asJson) {
|
|
|
33
70
|
// it through `boot()`, which is what keeps the CLI and an embedding Node app
|
|
34
71
|
// identical: hosting a kernel is the only thing that installs it.
|
|
35
72
|
enableBigIntJson();
|
|
73
|
+
const out = output();
|
|
36
74
|
let context;
|
|
37
75
|
try {
|
|
38
76
|
context = contextJson ? JSON.parse(contextJson) : {};
|
|
39
77
|
}
|
|
40
78
|
catch (err) {
|
|
41
|
-
|
|
79
|
+
const message = `Invalid --context JSON: ${err instanceof Error ? err.message : String(err)}`;
|
|
80
|
+
// Prose on stderr plus a non-zero exit — never an envelope on stdout.
|
|
81
|
+
// stdout is the document, and an error object there would be
|
|
82
|
+
// indistinguishable from a CEL expression that evaluated to one.
|
|
83
|
+
out.errLine(message);
|
|
42
84
|
process.exit(1);
|
|
43
85
|
}
|
|
44
86
|
// Real Node handlers so host-backed functions (sha256, base64, …) behave
|
|
@@ -49,14 +91,20 @@ function evalExpression(expr, contextJson, asJson) {
|
|
|
49
91
|
result = env.parse(expr)(context);
|
|
50
92
|
}
|
|
51
93
|
catch (err) {
|
|
52
|
-
|
|
94
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
95
|
+
// Prose on stderr plus a non-zero exit — never an envelope on stdout.
|
|
96
|
+
// stdout is the document, and an error object there would be
|
|
97
|
+
// indistinguishable from a CEL expression that evaluated to one.
|
|
98
|
+
out.errLine(message);
|
|
53
99
|
process.exit(1);
|
|
54
100
|
}
|
|
55
|
-
|
|
56
|
-
|
|
101
|
+
// The evaluated value IS the contract — emitted bare, exactly as `--json`
|
|
102
|
+
// already did, so the int64 encoding installed above stays observable.
|
|
103
|
+
if (asJson || out.isJson) {
|
|
104
|
+
out.document(result);
|
|
57
105
|
}
|
|
58
106
|
else {
|
|
59
|
-
|
|
107
|
+
out.line(String(typeof result === "bigint" ? result.toString() : result));
|
|
60
108
|
}
|
|
61
109
|
}
|
|
62
110
|
export function celCommand(yargs) {
|
package/dist/commands/cel.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cel.js","sourceRoot":"","sources":["../../src/commands/cel.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"cel.js","sourceRoot":"","sources":["../../src/commands/cel.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AA+PlC,wBAAsB,KAAK,CAAC,IAAI,EAAE;IAChC,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG,OAAO,CAAC,IAAI,CAAC,CA4EhB;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,IAAI,GAAG,IAAI,CAoB9C"}
|
package/dist/commands/check.js
CHANGED
|
@@ -6,7 +6,8 @@ import { defaultTransportRegistry } from "@telorun/kernel/transports";
|
|
|
6
6
|
import * as fs from "fs/promises";
|
|
7
7
|
import * as path from "path";
|
|
8
8
|
import { pathToFileURL } from "url";
|
|
9
|
-
import { createLogger, formatAnalysisDiagnostics, formatDiagnostics } from "../logger.js";
|
|
9
|
+
import { createLogger, formatAnalysisDiagnostics, formatDiagnostics, } from "../logger.js";
|
|
10
|
+
import { outErrLine, output } from "../output.js";
|
|
10
11
|
import { RecordingCacheSource, readOriginDigests, revalidateMutableOciRefs, writeOriginDigests, } from "../manifest-freshness.js";
|
|
11
12
|
const DEFAULT_REGISTRY_URL = "https://registry.telo.run";
|
|
12
13
|
function cacheTargetFor(entryPath) {
|
|
@@ -70,7 +71,7 @@ async function dropStaleEntry(file, session, log) {
|
|
|
70
71
|
await fs.rm(file, { force: true });
|
|
71
72
|
}
|
|
72
73
|
catch (err) {
|
|
73
|
-
|
|
74
|
+
outErrLine(`${log.err.warn(`[manifest-cache] could not remove stale entry ${file}: ${err instanceof Error ? err.message : String(err)}`)}\n`);
|
|
74
75
|
}
|
|
75
76
|
session.loader.forget(pathToFileURL(file).href);
|
|
76
77
|
for (const recorder of session.recorders) {
|
|
@@ -110,6 +111,7 @@ knownDigests, log) {
|
|
|
110
111
|
return {
|
|
111
112
|
errorCount: 0,
|
|
112
113
|
warnCount: 0,
|
|
114
|
+
diagnostics: [],
|
|
113
115
|
staleFiles: freshness.staleFiles,
|
|
114
116
|
digests: freshness.digests,
|
|
115
117
|
};
|
|
@@ -141,7 +143,7 @@ knownDigests, log) {
|
|
|
141
143
|
await writeOriginDigests(cacheTarget.manifestsDir, digests);
|
|
142
144
|
}
|
|
143
145
|
catch (err) {
|
|
144
|
-
|
|
146
|
+
outErrLine(`${log.err.warn(`[manifest-cache] write failed: ${err instanceof Error ? err.message : String(err)}`)}\n`);
|
|
145
147
|
}
|
|
146
148
|
}
|
|
147
149
|
return { ...counts, staleFiles: [], digests };
|
|
@@ -150,8 +152,25 @@ knownDigests, log) {
|
|
|
150
152
|
const sourceLine = err.sourceLine;
|
|
151
153
|
const displayPath = isUrl ? entryPath : path.relative(process.cwd(), entryPath);
|
|
152
154
|
const loc = sourceLine !== undefined ? `:${sourceLine + 1}` : "";
|
|
153
|
-
|
|
154
|
-
|
|
155
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
156
|
+
formatDiagnostics([{ message }], log, `${displayPath}${loc}`);
|
|
157
|
+
// A load failure is a diagnostic like any other to a `-o json` consumer;
|
|
158
|
+
// dropping it there would make the payload disagree with the exit code.
|
|
159
|
+
return {
|
|
160
|
+
errorCount: 1,
|
|
161
|
+
warnCount: 0,
|
|
162
|
+
diagnostics: [
|
|
163
|
+
{
|
|
164
|
+
file: displayPath,
|
|
165
|
+
line: sourceLine !== undefined ? sourceLine + 1 : 1,
|
|
166
|
+
column: 1,
|
|
167
|
+
severity: "error",
|
|
168
|
+
message,
|
|
169
|
+
},
|
|
170
|
+
],
|
|
171
|
+
staleFiles: [],
|
|
172
|
+
digests: new Map(),
|
|
173
|
+
};
|
|
155
174
|
}
|
|
156
175
|
}
|
|
157
176
|
export async function check(argv) {
|
|
@@ -168,6 +187,7 @@ export async function check(argv) {
|
|
|
168
187
|
const session = openSession([...cacheTargets.values()], registryUrl);
|
|
169
188
|
let totalErrors = 0;
|
|
170
189
|
let totalWarns = 0;
|
|
190
|
+
const allDiagnostics = [];
|
|
171
191
|
for (const p of argv.paths) {
|
|
172
192
|
const cacheTarget = cacheTargetFor(resolveEntryPath(p));
|
|
173
193
|
let outcome = await checkOne(p, registryUrl, session, cacheTarget, cacheWrite, null, log);
|
|
@@ -184,9 +204,11 @@ export async function check(argv) {
|
|
|
184
204
|
}
|
|
185
205
|
totalErrors += outcome.errorCount;
|
|
186
206
|
totalWarns += outcome.warnCount;
|
|
207
|
+
allDiagnostics.push(...outcome.diagnostics);
|
|
187
208
|
}
|
|
209
|
+
const out = output();
|
|
188
210
|
if (totalErrors === 0 && totalWarns === 0) {
|
|
189
|
-
|
|
211
|
+
out.line(log.ok("✓") + " No issues found");
|
|
190
212
|
}
|
|
191
213
|
else {
|
|
192
214
|
const parts = [];
|
|
@@ -194,10 +216,23 @@ export async function check(argv) {
|
|
|
194
216
|
parts.push(log.error(`${totalErrors} error${totalErrors !== 1 ? "s" : ""}`));
|
|
195
217
|
if (totalWarns > 0)
|
|
196
218
|
parts.push(log.warn(`${totalWarns} warning${totalWarns !== 1 ? "s" : ""}`));
|
|
197
|
-
|
|
219
|
+
out.line(`\n${parts.join(", ")}`);
|
|
198
220
|
}
|
|
221
|
+
// Emitted even when clean: an empty `diagnostics` array is the answer, and a
|
|
222
|
+
// consumer must not have to treat "no output" as success.
|
|
223
|
+
out.emit({
|
|
224
|
+
ok: totalErrors === 0,
|
|
225
|
+
errorCount: totalErrors,
|
|
226
|
+
warnCount: totalWarns,
|
|
227
|
+
diagnostics: allDiagnostics,
|
|
228
|
+
});
|
|
229
|
+
// `process.exitCode`, not `process.exit()`: the structured payload was just
|
|
230
|
+
// written, and on a pipe `write` is asynchronous while `exit` does not flush. A
|
|
231
|
+
// large diagnostic set exceeds the 64 KB pipe buffer, and truncated JSON is a
|
|
232
|
+
// parse failure for the one consumer this format exists for. Returning lets
|
|
233
|
+
// the event loop drain.
|
|
199
234
|
if (totalErrors > 0)
|
|
200
|
-
process.
|
|
235
|
+
process.exitCode = 1;
|
|
201
236
|
}
|
|
202
237
|
export function checkCommand(yargs) {
|
|
203
238
|
return yargs.command("check <paths..>", "Check one or more Telo manifests for errors without running them", (y) => y
|