@telorun/cli 0.70.0 → 0.71.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/cli.js +11 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/cel.d.ts.map +1 -1
- package/dist/commands/cel.js +26 -11
- 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 +40 -24
- 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 +23 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +65 -36
- 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 +1 -1
package/dist/logger.d.ts
CHANGED
|
@@ -1,11 +1,33 @@
|
|
|
1
1
|
import type { AnalysisDiagnostic, LoadedGraph } from "@telorun/analyzer";
|
|
2
2
|
import { type RuntimeDiagnostic } from "@telorun/kernel";
|
|
3
|
+
/** One diagnostic as `-o json` reports it. The shape is the machine contract
|
|
4
|
+
* that replaces parsing the prose form: `code` is what a caller branches on,
|
|
5
|
+
* and the location is pre-resolved because deriving it needs the loaded graph,
|
|
6
|
+
* which the consumer does not have. */
|
|
7
|
+
export interface JsonDiagnostic {
|
|
8
|
+
file: string;
|
|
9
|
+
line: number;
|
|
10
|
+
column: number;
|
|
11
|
+
severity: "error" | "warning";
|
|
12
|
+
code?: string;
|
|
13
|
+
message: string;
|
|
14
|
+
}
|
|
15
|
+
/** The logger's colouring delegates to `Output`'s per-stream palettes.
|
|
16
|
+
*
|
|
17
|
+
* Its methods paint text destined for STDOUT; `log.err` is the same palette
|
|
18
|
+
* bound to stderr. Which one a caller wants is decided by where it writes, not
|
|
19
|
+
* by the process — `formatDiagnostics` writes to stderr and `check`'s summary
|
|
20
|
+
* to stdout, and one shared decision was wrong for whichever stream was
|
|
21
|
+
* redirected. Under `-o json` both palettes are plain, so structured output
|
|
22
|
+
* cannot carry escapes. */
|
|
3
23
|
export declare function createLogger(verbose: boolean): {
|
|
4
24
|
info: (...args: any[]) => void;
|
|
5
25
|
ok: (text: string) => string;
|
|
6
26
|
warn: (text: string) => string;
|
|
7
27
|
error: (text: string) => string;
|
|
8
28
|
dim: (text: string) => string;
|
|
29
|
+
/** Palette for text written to stderr. */
|
|
30
|
+
err: import("./output.js").Palette;
|
|
9
31
|
verbose: boolean;
|
|
10
32
|
};
|
|
11
33
|
export type Logger = ReturnType<typeof createLogger>;
|
|
@@ -27,5 +49,6 @@ export declare function formatDiagnostics(diagnostics: RuntimeDiagnostic[], log:
|
|
|
27
49
|
export declare function formatAnalysisDiagnostics(diagnostics: AnalysisDiagnostic[], graph: LoadedGraph, log: Logger, entryPath: string): {
|
|
28
50
|
errorCount: number;
|
|
29
51
|
warnCount: number;
|
|
52
|
+
diagnostics: JsonDiagnostic[];
|
|
30
53
|
};
|
|
31
54
|
//# sourceMappingURL=logger.d.ts.map
|
package/dist/logger.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGzE,OAAO,
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGzE,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,iBAAiB,CAAC;AAwDzB;;;wCAGwC;AACxC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;4BAO4B;AAC5B,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO;oBAGzB,GAAG,EAAE;eAGV,MAAM;iBACJ,MAAM;kBACL,MAAM;gBACR,MAAM;IAClB,0CAA0C;;;EAI7C;AAED,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AAErD;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,iBAAiB,EAAE,EAChC,GAAG,EAAE,MAAM,EACX,WAAW,EAAE,MAAM,EACnB,KAAK,CAAC,EAAE,WAAW,GAClB,IAAI,CAuEN;AAED;;yBAEyB;AACzB,wBAAgB,yBAAyB,CACvC,WAAW,EAAE,kBAAkB,EAAE,EACjC,KAAK,EAAE,WAAW,EAClB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAChB;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,cAAc,EAAE,CAAA;CAAE,CAmC1E"}
|
package/dist/logger.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { DiagnosticSeverity } from "@telorun/analyzer";
|
|
2
2
|
import { findPositions, resolveRange } from "@telorun/ide-support";
|
|
3
|
-
import {
|
|
3
|
+
import { describeBlockedGroup, groupBlockedResources, } from "@telorun/kernel";
|
|
4
4
|
import * as path from "path";
|
|
5
5
|
import { fileURLToPath } from "url";
|
|
6
|
+
import { output } from "./output.js";
|
|
6
7
|
/** Render a manifest source for display: a local `file://` URL (how the loader
|
|
7
8
|
* canonicalizes on-disk manifests) becomes a CWD-relative path, a real remote
|
|
8
9
|
* URL (`http(s)://`) is kept absolute, and a bare path is made relative. */
|
|
@@ -26,7 +27,7 @@ function displaySourcePath(raw) {
|
|
|
26
27
|
* Undefined when nothing located it — a diagnostic whose resource is synthetic
|
|
27
28
|
* and whose file matches no graph source. A pointer to line 1 would be worse
|
|
28
29
|
* than none: it sends the reader somewhere the error is not. */
|
|
29
|
-
function
|
|
30
|
+
function resolveLocationParts(graph, d, fallbackSource) {
|
|
30
31
|
const located = findPositions(graph, d.data);
|
|
31
32
|
if (!located && !d.range)
|
|
32
33
|
return undefined;
|
|
@@ -34,28 +35,38 @@ function resolveLocation(graph, d, fallbackSource) {
|
|
|
34
35
|
positionIndex: located?.positionIndex,
|
|
35
36
|
sourceLine: located?.sourceLine,
|
|
36
37
|
});
|
|
37
|
-
|
|
38
|
+
// 1-based for display; the analyzer's own range is 0-based.
|
|
39
|
+
return {
|
|
40
|
+
file: displaySourcePath(located?.file ?? fallbackSource),
|
|
41
|
+
line: range.start.line + 1,
|
|
42
|
+
column: range.start.character + 1,
|
|
43
|
+
};
|
|
38
44
|
}
|
|
45
|
+
function resolveLocation(graph, d, fallbackSource) {
|
|
46
|
+
const parts = resolveLocationParts(graph, d, fallbackSource);
|
|
47
|
+
return parts && `${parts.file}:${parts.line}:${parts.column}`;
|
|
48
|
+
}
|
|
49
|
+
/** The logger's colouring delegates to `Output`'s per-stream palettes.
|
|
50
|
+
*
|
|
51
|
+
* Its methods paint text destined for STDOUT; `log.err` is the same palette
|
|
52
|
+
* bound to stderr. Which one a caller wants is decided by where it writes, not
|
|
53
|
+
* by the process — `formatDiagnostics` writes to stderr and `check`'s summary
|
|
54
|
+
* to stdout, and one shared decision was wrong for whichever stream was
|
|
55
|
+
* redirected. Under `-o json` both palettes are plain, so structured output
|
|
56
|
+
* cannot carry escapes. */
|
|
39
57
|
export function createLogger(verbose) {
|
|
40
|
-
|
|
41
|
-
// order exactly, shared with the `pretty` log encoding rather than
|
|
42
|
-
// reimplemented here. Notably this adds `NO_COLOR` support, which the CLI
|
|
43
|
-
// previously ignored, and stops treating a bare `FORCE_COLOR=0` as "on" —
|
|
44
|
-
// both behavior changes, both required by the spec.
|
|
45
|
-
//
|
|
46
|
-
// The decision is made against stdout, which is where this logger writes.
|
|
47
|
-
const useColor = decideColor({
|
|
48
|
-
setting: "auto",
|
|
49
|
-
env: process.env,
|
|
50
|
-
isTTY: Boolean(process.stdout.isTTY),
|
|
51
|
-
});
|
|
52
|
-
const wrap = (code, text) => (useColor ? `\x1b[${code}m${text}\x1b[0m` : text);
|
|
58
|
+
const out = output();
|
|
53
59
|
return {
|
|
54
|
-
info: (...args) =>
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
info: (...args) => {
|
|
61
|
+
if (!out.isJson)
|
|
62
|
+
out.line(args.map((a) => String(a)).join(" "));
|
|
63
|
+
},
|
|
64
|
+
ok: (text) => out.stdout.ok(text),
|
|
65
|
+
warn: (text) => out.stdout.warn(text),
|
|
66
|
+
error: (text) => out.stdout.error(text),
|
|
67
|
+
dim: (text) => out.stdout.dim(text),
|
|
68
|
+
/** Palette for text written to stderr. */
|
|
69
|
+
err: out.stderr,
|
|
59
70
|
verbose,
|
|
60
71
|
};
|
|
61
72
|
}
|
|
@@ -74,12 +85,16 @@ export function formatDiagnostics(diagnostics, log, displayPath, graph) {
|
|
|
74
85
|
// Column the `error`/`warning` label occupies, so a collapsed group line sits
|
|
75
86
|
// under the resource names it summarizes rather than under the label.
|
|
76
87
|
const NAME_COLUMN = " ".repeat(" error ".length);
|
|
88
|
+
const out = output();
|
|
89
|
+
// This renderer writes to stderr throughout, so it paints with the stderr
|
|
90
|
+
// palette — the stdout one may be coloured when stderr is redirected.
|
|
91
|
+
const paint = log.err;
|
|
77
92
|
const render = (entries, indent) => {
|
|
78
93
|
for (const d of entries) {
|
|
79
94
|
const skip = d.derived && !log.verbose;
|
|
80
95
|
if (!skip) {
|
|
81
|
-
const severityLabel = d.severity === "warning" ?
|
|
82
|
-
const code = d.code ? ` ${
|
|
96
|
+
const severityLabel = d.severity === "warning" ? paint.warn("warning") : paint.error("error");
|
|
97
|
+
const code = d.code ? ` ${paint.dim(d.code)}` : "";
|
|
83
98
|
// A static failure that nothing could locate falls through to the
|
|
84
99
|
// resource / bare-path branches below, which at least name what failed.
|
|
85
100
|
const location = d.origin && graph
|
|
@@ -91,28 +106,28 @@ export function formatDiagnostics(diagnostics, log, displayPath, graph) {
|
|
|
91
106
|
if (!d.details)
|
|
92
107
|
return;
|
|
93
108
|
for (const line of d.details.split("\n")) {
|
|
94
|
-
|
|
109
|
+
out.errLine(`${detailIndent}${paint.dim(line)}`);
|
|
95
110
|
}
|
|
96
111
|
};
|
|
97
112
|
if (location) {
|
|
98
113
|
// Static-analysis failure — the position names the exact spot, so it
|
|
99
114
|
// renders exactly as `telo check` does. Repeating the resource here
|
|
100
115
|
// would duplicate it: an analyzer message already names its own.
|
|
101
|
-
|
|
116
|
+
out.errLine(`${indent}${location} ${severityLabel} ${d.message}${code}`);
|
|
102
117
|
printDetails(`${indent} `);
|
|
103
118
|
}
|
|
104
119
|
else if (d.resource) {
|
|
105
120
|
// Runtime diagnostic — the failure is pinned to a resource, so the
|
|
106
121
|
// entry manifest path adds no information. Show kind + name + message
|
|
107
122
|
// and any structured details indented below.
|
|
108
|
-
const who = `${d.kind ? `${
|
|
109
|
-
|
|
123
|
+
const who = `${d.kind ? `${paint.dim(d.kind)} ` : ""}${d.resource}`;
|
|
124
|
+
out.errLine(`${indent} ${severityLabel} ${who}: ${d.message}${code}`);
|
|
110
125
|
printDetails(`${indent}${NAME_COLUMN} `);
|
|
111
126
|
}
|
|
112
127
|
else {
|
|
113
128
|
// Non-resource diagnostic (e.g. loader/parse failure) — keep the file
|
|
114
129
|
// path since it is the only location cue we have.
|
|
115
|
-
|
|
130
|
+
out.errLine(`${indent}${displayPath} ${severityLabel} ${d.message}${code}`);
|
|
116
131
|
printDetails(`${indent} `);
|
|
117
132
|
}
|
|
118
133
|
}
|
|
@@ -124,7 +139,7 @@ export function formatDiagnostics(diagnostics, log, displayPath, graph) {
|
|
|
124
139
|
}
|
|
125
140
|
if (!log.verbose) {
|
|
126
141
|
for (const [blockedBy, names] of groupBlockedResources(entries)) {
|
|
127
|
-
|
|
142
|
+
out.errLine(`${indent}${NAME_COLUMN}${paint.dim(describeBlockedGroup(blockedBy, names))}`);
|
|
128
143
|
}
|
|
129
144
|
}
|
|
130
145
|
};
|
|
@@ -136,20 +151,34 @@ export function formatDiagnostics(diagnostics, log, displayPath, graph) {
|
|
|
136
151
|
export function formatAnalysisDiagnostics(diagnostics, graph, log, entryPath) {
|
|
137
152
|
let errorCount = 0;
|
|
138
153
|
let warnCount = 0;
|
|
154
|
+
const out = output();
|
|
155
|
+
const collected = [];
|
|
139
156
|
for (const d of diagnostics) {
|
|
140
157
|
// `check` prints one line per diagnostic and has no resource-named form to
|
|
141
158
|
// fall back to, so an unlocatable one still leads with the entry manifest.
|
|
142
|
-
const
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
:
|
|
159
|
+
const parts = resolveLocationParts(graph, d, entryPath) ?? {
|
|
160
|
+
file: displaySourcePath(entryPath),
|
|
161
|
+
line: 1,
|
|
162
|
+
column: 1,
|
|
163
|
+
};
|
|
164
|
+
const isError = (d.severity ?? DiagnosticSeverity.Warning) <= DiagnosticSeverity.Error;
|
|
165
|
+
const severityLabel = isError ? log.error("error") : log.warn("warning");
|
|
146
166
|
const code = d.code ? ` ${log.dim(String(d.code))}` : "";
|
|
147
|
-
|
|
148
|
-
|
|
167
|
+
// Silent under `-o json`: the structured payload carries the same
|
|
168
|
+
// diagnostics with their location resolved, so printing here too would
|
|
169
|
+
// interleave prose into a document a consumer parses.
|
|
170
|
+
out.line(`${parts.file}:${parts.line}:${parts.column} ${severityLabel} ${d.message}${code}`);
|
|
171
|
+
collected.push({
|
|
172
|
+
...parts,
|
|
173
|
+
severity: isError ? "error" : "warning",
|
|
174
|
+
...(d.code === undefined ? {} : { code: String(d.code) }),
|
|
175
|
+
message: d.message,
|
|
176
|
+
});
|
|
177
|
+
if (isError)
|
|
149
178
|
errorCount++;
|
|
150
179
|
else
|
|
151
180
|
warnCount++;
|
|
152
181
|
}
|
|
153
|
-
return { errorCount, warnCount };
|
|
182
|
+
return { errorCount, warnCount, diagnostics: collected };
|
|
154
183
|
}
|
|
155
184
|
//# sourceMappingURL=logger.js.map
|
package/dist/logger.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
package/dist/output.d.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/** Output encodings the CLI can produce. `yaml` is deliberately absent: the flag
|
|
2
|
+
* is an enum precisely so it can gain a value later without a second flag. */
|
|
3
|
+
export type OutputFormat = "text" | "json";
|
|
4
|
+
export declare const OUTPUT_FORMATS: OutputFormat[];
|
|
5
|
+
/** A colour palette bound to ONE stream.
|
|
6
|
+
*
|
|
7
|
+
* Colour is a property of the descriptor being written to, not of the process:
|
|
8
|
+
* `telo check 2>/dev/null` leaves stdout a TTY and stderr not, and a single
|
|
9
|
+
* process-wide decision is wrong for one of them either way. The CLI used to
|
|
10
|
+
* decide once from `process.stdout.isTTY` while `formatDiagnostics` wrote to
|
|
11
|
+
* stderr, so redirecting one stream and not the other produced escapes where
|
|
12
|
+
* they could not be rendered — the leak this splits apart. */
|
|
13
|
+
export interface Palette {
|
|
14
|
+
ok(text: string): string;
|
|
15
|
+
warn(text: string): string;
|
|
16
|
+
error(text: string): string;
|
|
17
|
+
dim(text: string): string;
|
|
18
|
+
}
|
|
19
|
+
/** The minimum of a writable stream this needs. Narrow on purpose: a test hands
|
|
20
|
+
* in a recording pair, so `Output` never reads process globals. */
|
|
21
|
+
export interface OutputStream {
|
|
22
|
+
isTTY?: boolean;
|
|
23
|
+
write(chunk: string): unknown;
|
|
24
|
+
}
|
|
25
|
+
export interface OutputOptions {
|
|
26
|
+
format: OutputFormat;
|
|
27
|
+
stdout?: OutputStream;
|
|
28
|
+
stderr?: OutputStream;
|
|
29
|
+
env?: NodeJS.ProcessEnv;
|
|
30
|
+
}
|
|
31
|
+
/** The single seam every CLI-owned write goes through.
|
|
32
|
+
*
|
|
33
|
+
* The stream split is the whole contract:
|
|
34
|
+
*
|
|
35
|
+
* - **stdout is the machine surface.** Under `-o json` it carries the payload
|
|
36
|
+
* and nothing else, so a consumer parses it whole.
|
|
37
|
+
* - **stderr is the human surface, in BOTH formats.** Prose keeps flowing under
|
|
38
|
+
* `-o json` — the convention npm, cargo and kubectl follow — because the
|
|
39
|
+
* alternative is silence: a command that reports a failure reason through
|
|
40
|
+
* prose would otherwise have it swallowed, leaving `{"ok":false}` with no
|
|
41
|
+
* cause. Suppressing stderr was error swallowing, which Telo forbids.
|
|
42
|
+
*
|
|
43
|
+
* `telo run` is exempt from `-o json` entirely; see `emit`. */
|
|
44
|
+
export declare class Output {
|
|
45
|
+
readonly format: OutputFormat;
|
|
46
|
+
readonly stdout: Palette;
|
|
47
|
+
readonly stderr: Palette;
|
|
48
|
+
private readonly outStream;
|
|
49
|
+
private readonly errStream;
|
|
50
|
+
constructor(options: OutputOptions);
|
|
51
|
+
get isJson(): boolean;
|
|
52
|
+
/** Human-readable line on stdout. Suppressed under `-o json`, where stdout is
|
|
53
|
+
* reserved for the payload. */
|
|
54
|
+
line(text?: string): void;
|
|
55
|
+
/** Human-readable line on stderr. Written in BOTH formats — stderr is not the
|
|
56
|
+
* machine contract, and silencing it loses the reason a command failed. */
|
|
57
|
+
errLine(text?: string): void;
|
|
58
|
+
/** Emit a command's structured RESULT ENVELOPE. A no-op in text mode.
|
|
59
|
+
*
|
|
60
|
+
* Every command that owns its stdout calls this exactly once, including when
|
|
61
|
+
* it has nothing interesting to report — a consumer cannot distinguish
|
|
62
|
+
* "nothing to say" from "this command ignores the flag", so a bare envelope
|
|
63
|
+
* is the difference between a contract and a guess.
|
|
64
|
+
*
|
|
65
|
+
* `telo run` is the ONE exemption, and it is a property of the command rather
|
|
66
|
+
* than an oversight: the kernel runs in-process and the app's own output goes
|
|
67
|
+
* to these same descriptors (`teeStdio` copies, it does not redirect), so
|
|
68
|
+
* NEITHER stream is the CLI's to claim. An envelope written after arbitrary
|
|
69
|
+
* app output is unparseable, which is the exact failure `-o json` exists to
|
|
70
|
+
* remove. The machine surface for a run already exists and is `--debug`,
|
|
71
|
+
* whose wire protocol is framed per event precisely because it shares a
|
|
72
|
+
* stream. */
|
|
73
|
+
emit(payload: unknown): void;
|
|
74
|
+
/** Write a bare DOCUMENT to stdout, in either format.
|
|
75
|
+
*
|
|
76
|
+
* For the commands whose structured form is the document itself rather than a
|
|
77
|
+
* result report — `cel`, `search`, `module versions|manifest|digest|resources|kinds`.
|
|
78
|
+
* Unconditional because their per-command `--json` flag predates `-o` and
|
|
79
|
+
* must keep working under the default `text` format. One serializer with
|
|
80
|
+
* `emit`, so the CLI has a single JSON encoding rather than three. */
|
|
81
|
+
document(payload: unknown): void;
|
|
82
|
+
/** Write verbatim content to stdout, unconditionally and with no framing.
|
|
83
|
+
*
|
|
84
|
+
* For the one case that is neither prose nor a JSON payload: `telo module
|
|
85
|
+
* manifest` printing a module's `telo.yaml` bytes, which ARE the output. It
|
|
86
|
+
* bypasses format handling because the bytes are the answer in every format
|
|
87
|
+
* — the `--json` path wraps them in a document instead and never reaches
|
|
88
|
+
* here. */
|
|
89
|
+
raw(content: string): void;
|
|
90
|
+
}
|
|
91
|
+
export declare function configureOutput(format: OutputFormat): void;
|
|
92
|
+
/** Swap the ambient instance, returning a restore function.
|
|
93
|
+
*
|
|
94
|
+
* For tests of code that reaches the seam through the accessor rather than
|
|
95
|
+
* through a parameter — they hand in an `Output` over recording streams instead
|
|
96
|
+
* of spying on `process.stderr.write`. */
|
|
97
|
+
export declare function installOutput(replacement: Output): () => void;
|
|
98
|
+
export declare function output(): Output;
|
|
99
|
+
/** yargs has already rejected anything outside `choices` by the time a handler
|
|
100
|
+
* runs, so an unrecognized value here means the enum grew and this function was
|
|
101
|
+
* not updated. Throwing is the point: silently degrading `-o yaml` to text is
|
|
102
|
+
* the worst failure a format flag can have. */
|
|
103
|
+
export declare function parseOutputFormat(value: unknown): OutputFormat;
|
|
104
|
+
/** Free-function forms of the seam, for the many call sites that only need to
|
|
105
|
+
* write a line and would otherwise each bind a local. They read the singleton
|
|
106
|
+
* per call, so they observe the configured format no matter when they run. */
|
|
107
|
+
export declare const outLine: (text?: string) => void;
|
|
108
|
+
export declare const outErrLine: (text?: string) => void;
|
|
109
|
+
export declare const outEmit: (payload: unknown) => void;
|
|
110
|
+
export declare const outDocument: (payload: unknown) => void;
|
|
111
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAEA;+EAC+E;AAC/E,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,CAAC;AAE3C,eAAO,MAAM,cAAc,EAAE,YAAY,EAAqB,CAAC;AAE/D;;;;;;;+DAO+D;AAC/D,MAAM,WAAW,OAAO;IACtB,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3B;AAiBD;oEACoE;AACpE,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,YAAY,CAAC;IACrB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AAED;;;;;;;;;;;;gEAYgE;AAChE,qBAAa,MAAM;IACjB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAe;gBAE7B,OAAO,EAAE,aAAa;IAkBlC,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED;oCACgC;IAChC,IAAI,CAAC,IAAI,SAAK,GAAG,IAAI;IAIrB;gFAC4E;IAC5E,OAAO,CAAC,IAAI,SAAK,GAAG,IAAI;IAIxB;;;;;;;;;;;;;;kBAcc;IACd,IAAI,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI5B;;;;;;2EAMuE;IACvE,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAIhC;;;;;;gBAMY;IACZ,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;CAG3B;AAWD,wBAAgB,eAAe,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAE1D;AAED;;;;2CAI2C;AAC3C,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,IAAI,CAM7D;AAED,wBAAgB,MAAM,IAAI,MAAM,CAE/B;AAED;;;gDAGgD;AAChD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAK9D;AAED;;+EAE+E;AAC/E,eAAO,MAAM,OAAO,GAAI,aAAS,KAAG,IAA0B,CAAC;AAC/D,eAAO,MAAM,UAAU,GAAI,aAAS,KAAG,IAA6B,CAAC;AACrE,eAAO,MAAM,OAAO,GAAI,SAAS,OAAO,KAAG,IAA6B,CAAC;AACzE,eAAO,MAAM,WAAW,GAAI,SAAS,OAAO,KAAG,IAAiC,CAAC"}
|
package/dist/output.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { decideColor } from "@telorun/kernel";
|
|
2
|
+
export const OUTPUT_FORMATS = ["text", "json"];
|
|
3
|
+
const PLAIN = {
|
|
4
|
+
ok: (t) => t,
|
|
5
|
+
warn: (t) => t,
|
|
6
|
+
error: (t) => t,
|
|
7
|
+
dim: (t) => t,
|
|
8
|
+
};
|
|
9
|
+
function paletteFor(isTTY, env) {
|
|
10
|
+
// Follows `kernel/specs/logging.md` §11.2 precedence, shared with the `pretty`
|
|
11
|
+
// log encoding rather than reimplemented.
|
|
12
|
+
if (!decideColor({ setting: "auto", env, isTTY }))
|
|
13
|
+
return PLAIN;
|
|
14
|
+
const wrap = (code) => (text) => `\x1b[${code}m${text}\x1b[0m`;
|
|
15
|
+
return { ok: wrap("32"), warn: wrap("33"), error: wrap("31"), dim: wrap("2") };
|
|
16
|
+
}
|
|
17
|
+
/** The single seam every CLI-owned write goes through.
|
|
18
|
+
*
|
|
19
|
+
* The stream split is the whole contract:
|
|
20
|
+
*
|
|
21
|
+
* - **stdout is the machine surface.** Under `-o json` it carries the payload
|
|
22
|
+
* and nothing else, so a consumer parses it whole.
|
|
23
|
+
* - **stderr is the human surface, in BOTH formats.** Prose keeps flowing under
|
|
24
|
+
* `-o json` — the convention npm, cargo and kubectl follow — because the
|
|
25
|
+
* alternative is silence: a command that reports a failure reason through
|
|
26
|
+
* prose would otherwise have it swallowed, leaving `{"ok":false}` with no
|
|
27
|
+
* cause. Suppressing stderr was error swallowing, which Telo forbids.
|
|
28
|
+
*
|
|
29
|
+
* `telo run` is exempt from `-o json` entirely; see `emit`. */
|
|
30
|
+
export class Output {
|
|
31
|
+
format;
|
|
32
|
+
stdout;
|
|
33
|
+
stderr;
|
|
34
|
+
outStream;
|
|
35
|
+
errStream;
|
|
36
|
+
constructor(options) {
|
|
37
|
+
const { format, stdout = process.stdout, stderr = process.stderr, env = process.env, } = options;
|
|
38
|
+
this.format = format;
|
|
39
|
+
this.outStream = stdout;
|
|
40
|
+
this.errStream = stderr;
|
|
41
|
+
// Structured output must never carry escapes: a consumer parses it, and no
|
|
42
|
+
// terminal renders it. Deciding this here rather than at each call site is
|
|
43
|
+
// what makes "JSON is always clean" true by construction. stderr keeps its
|
|
44
|
+
// colour under `-o json` because it stays the human surface.
|
|
45
|
+
this.stdout = format === "text" ? paletteFor(Boolean(stdout.isTTY), env) : PLAIN;
|
|
46
|
+
this.stderr = paletteFor(Boolean(stderr.isTTY), env);
|
|
47
|
+
}
|
|
48
|
+
get isJson() {
|
|
49
|
+
return this.format === "json";
|
|
50
|
+
}
|
|
51
|
+
/** Human-readable line on stdout. Suppressed under `-o json`, where stdout is
|
|
52
|
+
* reserved for the payload. */
|
|
53
|
+
line(text = "") {
|
|
54
|
+
if (this.format === "text")
|
|
55
|
+
this.outStream.write(`${text}\n`);
|
|
56
|
+
}
|
|
57
|
+
/** Human-readable line on stderr. Written in BOTH formats — stderr is not the
|
|
58
|
+
* machine contract, and silencing it loses the reason a command failed. */
|
|
59
|
+
errLine(text = "") {
|
|
60
|
+
this.errStream.write(`${text}\n`);
|
|
61
|
+
}
|
|
62
|
+
/** Emit a command's structured RESULT ENVELOPE. A no-op in text mode.
|
|
63
|
+
*
|
|
64
|
+
* Every command that owns its stdout calls this exactly once, including when
|
|
65
|
+
* it has nothing interesting to report — a consumer cannot distinguish
|
|
66
|
+
* "nothing to say" from "this command ignores the flag", so a bare envelope
|
|
67
|
+
* is the difference between a contract and a guess.
|
|
68
|
+
*
|
|
69
|
+
* `telo run` is the ONE exemption, and it is a property of the command rather
|
|
70
|
+
* than an oversight: the kernel runs in-process and the app's own output goes
|
|
71
|
+
* to these same descriptors (`teeStdio` copies, it does not redirect), so
|
|
72
|
+
* NEITHER stream is the CLI's to claim. An envelope written after arbitrary
|
|
73
|
+
* app output is unparseable, which is the exact failure `-o json` exists to
|
|
74
|
+
* remove. The machine surface for a run already exists and is `--debug`,
|
|
75
|
+
* whose wire protocol is framed per event precisely because it shares a
|
|
76
|
+
* stream. */
|
|
77
|
+
emit(payload) {
|
|
78
|
+
if (this.format === "json")
|
|
79
|
+
this.outStream.write(serialize(payload));
|
|
80
|
+
}
|
|
81
|
+
/** Write a bare DOCUMENT to stdout, in either format.
|
|
82
|
+
*
|
|
83
|
+
* For the commands whose structured form is the document itself rather than a
|
|
84
|
+
* result report — `cel`, `search`, `module versions|manifest|digest|resources|kinds`.
|
|
85
|
+
* Unconditional because their per-command `--json` flag predates `-o` and
|
|
86
|
+
* must keep working under the default `text` format. One serializer with
|
|
87
|
+
* `emit`, so the CLI has a single JSON encoding rather than three. */
|
|
88
|
+
document(payload) {
|
|
89
|
+
this.outStream.write(serialize(payload));
|
|
90
|
+
}
|
|
91
|
+
/** Write verbatim content to stdout, unconditionally and with no framing.
|
|
92
|
+
*
|
|
93
|
+
* For the one case that is neither prose nor a JSON payload: `telo module
|
|
94
|
+
* manifest` printing a module's `telo.yaml` bytes, which ARE the output. It
|
|
95
|
+
* bypasses format handling because the bytes are the answer in every format
|
|
96
|
+
* — the `--json` path wraps them in a document instead and never reaches
|
|
97
|
+
* here. */
|
|
98
|
+
raw(content) {
|
|
99
|
+
this.outStream.write(content);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function serialize(payload) {
|
|
103
|
+
return `${JSON.stringify(payload, null, 2)}\n`;
|
|
104
|
+
}
|
|
105
|
+
/** Configured once from argv by a yargs middleware, before any handler runs, so
|
|
106
|
+
* call sites far from the handler reach the same decision without threading it
|
|
107
|
+
* through every signature. Tests construct an `Output` directly instead. */
|
|
108
|
+
let current = new Output({ format: "text" });
|
|
109
|
+
export function configureOutput(format) {
|
|
110
|
+
current = new Output({ format });
|
|
111
|
+
}
|
|
112
|
+
/** Swap the ambient instance, returning a restore function.
|
|
113
|
+
*
|
|
114
|
+
* For tests of code that reaches the seam through the accessor rather than
|
|
115
|
+
* through a parameter — they hand in an `Output` over recording streams instead
|
|
116
|
+
* of spying on `process.stderr.write`. */
|
|
117
|
+
export function installOutput(replacement) {
|
|
118
|
+
const previous = current;
|
|
119
|
+
current = replacement;
|
|
120
|
+
return () => {
|
|
121
|
+
current = previous;
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
export function output() {
|
|
125
|
+
return current;
|
|
126
|
+
}
|
|
127
|
+
/** yargs has already rejected anything outside `choices` by the time a handler
|
|
128
|
+
* runs, so an unrecognized value here means the enum grew and this function was
|
|
129
|
+
* not updated. Throwing is the point: silently degrading `-o yaml` to text is
|
|
130
|
+
* the worst failure a format flag can have. */
|
|
131
|
+
export function parseOutputFormat(value) {
|
|
132
|
+
if (OUTPUT_FORMATS.includes(value))
|
|
133
|
+
return value;
|
|
134
|
+
throw new Error(`Unsupported --output format '${String(value)}'. Expected one of: ${OUTPUT_FORMATS.join(", ")}.`);
|
|
135
|
+
}
|
|
136
|
+
/** Free-function forms of the seam, for the many call sites that only need to
|
|
137
|
+
* write a line and would otherwise each bind a local. They read the singleton
|
|
138
|
+
* per call, so they observe the configured format no matter when they run. */
|
|
139
|
+
export const outLine = (text = "") => current.line(text);
|
|
140
|
+
export const outErrLine = (text = "") => current.errLine(text);
|
|
141
|
+
export const outEmit = (payload) => current.emit(payload);
|
|
142
|
+
export const outDocument = (payload) => current.document(payload);
|
|
143
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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"}
|