@effected/cli 0.25.0 → 0.27.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/README.md +5 -208
- package/bin/effected.js +7 -0
- package/commands/root.js +14 -0
- package/commands/schema/LiveProgress.js +114 -0
- package/commands/schema/build.js +9 -0
- package/commands/schema/check.js +12 -0
- package/commands/schema/errors.js +121 -0
- package/commands/schema/execute.js +141 -0
- package/commands/schema/flags.js +24 -0
- package/commands/schema/index.js +14 -0
- package/commands/schema/validate.js +58 -0
- package/index.d.ts +85 -3906
- package/index.js +4 -26
- package/main.d.ts +51 -0
- package/main.js +61 -0
- package/package.json +18 -50
- package/render/DiffDoc.js +51 -0
- package/tsdoc-metadata.json +1 -1
- package/version.js +11 -0
- package/Cancelled.js +0 -43
- package/CliAudience.js +0 -177
- package/CliColor.js +0 -59
- package/CliEnv.js +0 -101
- package/CliExit.js +0 -64
- package/CliFailure.js +0 -287
- package/CliFormat.js +0 -124
- package/CliInteractive.js +0 -94
- package/CliLinks.js +0 -153
- package/CliLog.js +0 -367
- package/CliLogger.js +0 -91
- package/CliMessage.js +0 -79
- package/CliPrompt.js +0 -110
- package/CliRuntime.js +0 -254
- package/CliTest.js +0 -206
- package/CliTheme.js +0 -142
- package/ConfigIssueRenderer.js +0 -63
- package/Doc.js +0 -548
- package/Fmt.js +0 -335
- package/GithubAnnotation.js +0 -39
- package/Glyphs.js +0 -82
- package/NotInteractive.js +0 -41
- package/Render.js +0 -280
- package/SchemaIssueRenderer.js +0 -47
- package/Status.js +0 -165
- package/TestTerminal.js +0 -101
- package/Token.js +0 -68
- package/internal/ExitRequested.js +0 -21
- package/internal/HelpRouting.js +0 -35
- package/internal/ansi.js +0 -229
- package/internal/autoFormat.js +0 -33
- package/internal/canPrompt.js +0 -14
- package/internal/counts.js +0 -83
- package/internal/diagnostics.js +0 -31
- package/internal/displayPath.js +0 -46
- package/internal/displayWidth.js +0 -42
- package/internal/failureTarget.js +0 -195
- package/internal/fallbackAnswer.js +0 -17
- package/internal/fileSink.js +0 -61
- package/internal/format.js +0 -175
- package/internal/inspect.js +0 -40
- package/internal/isExitCode.js +0 -11
- package/internal/layout.js +0 -249
- package/internal/linkScheme.js +0 -29
- package/internal/linkTarget.js +0 -49
- package/internal/logSafety.js +0 -45
- package/internal/renderAnsi.js +0 -51
- package/internal/renderDoc.js +0 -322
- package/internal/renderGithubLog.js +0 -59
- package/internal/renderMarkdown.js +0 -367
- package/internal/renderPlain.js +0 -49
- package/internal/scanAudience.js +0 -105
- package/internal/splitFrame.js +0 -55
- package/internal/terminalCapabilities.js +0 -23
- package/internal/wizardGate.js +0 -17
- package/testing.d.ts +0 -246
- package/testing.js +0 -4
- package/ui/CliUi.js +0 -507
- package/ui/CliUiDetached.js +0 -36
- package/ui/CliUiLive.js +0 -436
- package/ui/CliUiRouteStream.js +0 -72
- package/ui/Confirm.js +0 -244
- package/ui/DocView.js +0 -76
- package/ui/KeyHelp.js +0 -61
- package/ui/KeyTable.js +0 -198
- package/ui/MultiSelect.js +0 -259
- package/ui/Select.js +0 -229
- package/ui/Tabs.js +0 -201
- package/ui/TextInput.js +0 -289
- package/ui/Toggle.js +0 -31
- package/ui/UiKey.js +0 -48
- package/ui/UiProvider.js +0 -62
- package/ui/UiStreams.js +0 -17
- package/ui/UiTheme.js +0 -147
- package/ui/Viewport.js +0 -203
- package/ui/internal/ErrorBoundary.js +0 -29
- package/ui/internal/Holder.js +0 -73
- package/ui/internal/ScreenContext.js +0 -51
- package/ui/internal/UiProviders.js +0 -38
- package/ui/internal/ink.js +0 -121
- package/ui/internal/inkChalk.js +0 -47
- package/ui/internal/inkConsole.js +0 -150
- package/ui/internal/lazyView.js +0 -73
- package/ui/internal/lineRouter.js +0 -70
- package/ui/internal/lineText.js +0 -18
- package/ui/internal/mountPermit.js +0 -15
- package/ui/internal/processStreams.js +0 -18
- package/ui/internal/renderOptions.js +0 -12
- package/ui/testing/CliUiTest.js +0 -792
- package/ui/testing/fakeStreams.js +0 -104
- package/ui/testing/terminalModel.js +0 -67
- package/ui-testing-serializer.d.ts +0 -12
- package/ui-testing-serializer.js +0 -32
- package/ui-testing.d.ts +0 -558
- package/ui-testing.js +0 -3
- package/ui.d.ts +0 -1990
- package/ui.js +0 -17
package/index.js
CHANGED
|
@@ -1,27 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { CliLinks } from "./CliLinks.js";
|
|
5
|
-
import { Glyphs } from "./Glyphs.js";
|
|
6
|
-
import { Token } from "./Token.js";
|
|
7
|
-
import { CliTheme } from "./CliTheme.js";
|
|
8
|
-
import { Render } from "./Render.js";
|
|
9
|
-
import { Doc } from "./Doc.js";
|
|
10
|
-
import { NotInteractive } from "./NotInteractive.js";
|
|
11
|
-
import { Status } from "./Status.js";
|
|
12
|
-
import { CliDoc, CliFailure } from "./CliFailure.js";
|
|
13
|
-
import { CliAudience } from "./CliAudience.js";
|
|
14
|
-
import { CliColor } from "./CliColor.js";
|
|
15
|
-
import { CliPrompt } from "./CliPrompt.js";
|
|
16
|
-
import { CliEnv } from "./CliEnv.js";
|
|
17
|
-
import { CliExit } from "./CliExit.js";
|
|
18
|
-
import { CliFormat } from "./CliFormat.js";
|
|
19
|
-
import { CliLogger } from "./CliLogger.js";
|
|
20
|
-
import { CliLog } from "./CliLog.js";
|
|
21
|
-
import { CliMessage } from "./CliMessage.js";
|
|
22
|
-
import { CliRuntime } from "./CliRuntime.js";
|
|
23
|
-
import { ConfigIssueRenderer } from "./ConfigIssueRenderer.js";
|
|
24
|
-
import { GithubAnnotation } from "./GithubAnnotation.js";
|
|
25
|
-
import { SchemaIssueRenderer } from "./SchemaIssueRenderer.js";
|
|
1
|
+
import { makeRootCommand } from "./commands/root.js";
|
|
2
|
+
import { CatalogMergeError, DriftError, GateError, NoConfigError, StaleError, ValidationFailedError } from "./commands/schema/errors.js";
|
|
3
|
+
import { CLI_VERSION } from "./version.js";
|
|
26
4
|
|
|
27
|
-
export {
|
|
5
|
+
export { CLI_VERSION, CatalogMergeError, DriftError, GateError, NoConfigError, StaleError, ValidationFailedError, makeRootCommand };
|
package/main.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Distribution } from "@effected/kit";
|
|
2
|
+
import { Layer } from "effect";
|
|
3
|
+
import { SchemaRunDeps } from "@effected/engine/schema";
|
|
4
|
+
import "@effected/env";
|
|
5
|
+
/**
|
|
6
|
+
* What `effected schema` is given by the process boundary, and the test seams: the engine's dependencies, less the
|
|
7
|
+
* progress callback the command supplies itself. `main` reads `cwd`, and nothing else reads the process.
|
|
8
|
+
*
|
|
9
|
+
* @public
|
|
10
|
+
*/
|
|
11
|
+
type SchemaCommandDeps = Omit<SchemaRunDeps, "onProgress">;
|
|
12
|
+
/**
|
|
13
|
+
* Options a carrier's bin shim passes to {@link main}. `distribution` names
|
|
14
|
+
* the package the `effected` bin was installed through; omitted for a direct
|
|
15
|
+
* install of `@effected/cli`.
|
|
16
|
+
*
|
|
17
|
+
* @public
|
|
18
|
+
*/
|
|
19
|
+
export interface MainOptions {
|
|
20
|
+
readonly distribution?: Distribution;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* How `CliRuntime.main` runs the command: exit `3` for a typed error that carries no code of its own, the infrastructure
|
|
24
|
+
* tier, and this module as the program's own, so the failure report's span trail keeps the command's spans when it is
|
|
25
|
+
* installed under `node_modules/@effected/` and leaves out the kit's.
|
|
26
|
+
*
|
|
27
|
+
* @public
|
|
28
|
+
*/
|
|
29
|
+
export declare const mainOptions: {
|
|
30
|
+
readonly exitCode: 3;
|
|
31
|
+
readonly env: {
|
|
32
|
+
readonly appModule: string;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* The `effected` program under `CliRuntime.main`, over `platform`: what
|
|
37
|
+
* {@link main} runs with the Node services, and what a test runs over a test
|
|
38
|
+
* environment.
|
|
39
|
+
*
|
|
40
|
+
* @public
|
|
41
|
+
*/
|
|
42
|
+
export declare const run: <RP, EP>(options: MainOptions, deps: SchemaCommandDeps, platform: Layer.Layer<RP, EP>) => import("effect/Effect").Effect<void, Error, Exclude<import("effect/process/ChildProcessSpawner").ChildProcessSpawner, RP> | Exclude<import("effect/FileSystem").FileSystem, RP> | Exclude<import("effect/Path").Path, RP> | Exclude<import("effect/Stdio").Stdio, RP> | Exclude<import("effect/Stdio").Stdio, RP> | Exclude<import("effect/Terminal").Terminal, RP>>;
|
|
43
|
+
/**
|
|
44
|
+
* Run the `effected` command. Owns the process: installs the runtime teardown
|
|
45
|
+
* and sets the exit code.
|
|
46
|
+
*
|
|
47
|
+
* @public
|
|
48
|
+
*/
|
|
49
|
+
export declare const main: (options?: MainOptions) => void;
|
|
50
|
+
export type { SchemaCommandDeps };
|
|
51
|
+
//# sourceMappingURL=main.d.ts.map
|
package/main.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { makeRootCommand } from "./commands/root.js";
|
|
2
|
+
import { CLI_VERSION } from "./version.js";
|
|
3
|
+
import { CliAudience, CliLogger, CliRuntime } from "@effected/cli-kit";
|
|
4
|
+
import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
|
|
5
|
+
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
6
|
+
|
|
7
|
+
// src/main.ts
|
|
8
|
+
/**
|
|
9
|
+
* The assembled `effected` program.
|
|
10
|
+
*
|
|
11
|
+
* @packageDocumentation
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* `effected --version` prints `effected <version>`; a carrier's
|
|
15
|
+
* ` via <name> <version>` is appended by `CliRuntime.main`'s `distribution`
|
|
16
|
+
* option, not here.
|
|
17
|
+
*/
|
|
18
|
+
const versionFormatter = { formatVersion: (name, version) => `${name} ${version}` };
|
|
19
|
+
/**
|
|
20
|
+
* How `CliRuntime.main` runs the command: exit `3` for a typed error that carries no code of its own, the infrastructure
|
|
21
|
+
* tier, and this module as the program's own, so the failure report's span trail keeps the command's spans when it is
|
|
22
|
+
* installed under `node_modules/@effected/` and leaves out the kit's.
|
|
23
|
+
*
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
const mainOptions = {
|
|
27
|
+
exitCode: 3,
|
|
28
|
+
env: { appModule: import.meta.url }
|
|
29
|
+
};
|
|
30
|
+
/** stdout is the report and nothing else, so every log level goes to stderr. */
|
|
31
|
+
const logger = CliLogger.layer({ stderrFrom: "All" });
|
|
32
|
+
/**
|
|
33
|
+
* The `effected` program under `CliRuntime.main`, over `platform`: what
|
|
34
|
+
* {@link main} runs with the Node services, and what a test runs over a test
|
|
35
|
+
* environment.
|
|
36
|
+
*
|
|
37
|
+
* @public
|
|
38
|
+
*/
|
|
39
|
+
const run = (options, deps, platform) => CliRuntime.main(CliAudience.run(makeRootCommand(deps), { version: CLI_VERSION }), {
|
|
40
|
+
platform,
|
|
41
|
+
logger,
|
|
42
|
+
distribution: options.distribution ?? null,
|
|
43
|
+
exitCode: mainOptions.exitCode,
|
|
44
|
+
helpOnUsageError: "stderr",
|
|
45
|
+
env: {
|
|
46
|
+
...mainOptions.env,
|
|
47
|
+
formatter: versionFormatter,
|
|
48
|
+
helpFlags: { inheritedFlags: "summary" }
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
/**
|
|
52
|
+
* Run the `effected` command. Owns the process: installs the runtime teardown
|
|
53
|
+
* and sets the exit code.
|
|
54
|
+
*
|
|
55
|
+
* @public
|
|
56
|
+
*/
|
|
57
|
+
const main = (options = {}) => {
|
|
58
|
+
NodeRuntime.runMain(run(options, { cwd: process.cwd() }, NodeServices.layer));
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export { main, mainOptions, run };
|
package/package.json
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effected/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "The
|
|
5
|
+
"description": "The effected command: the tool's command tree on the kit's front-end runtime",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"effect",
|
|
8
8
|
"cli",
|
|
9
|
-
"
|
|
10
|
-
"terminal",
|
|
11
|
-
"ink",
|
|
12
|
-
"tui"
|
|
9
|
+
"effected"
|
|
13
10
|
],
|
|
14
11
|
"homepage": "https://github.com/spencerbeggs/effected/tree/main/packages/cli#readme",
|
|
15
12
|
"bugs": {
|
|
@@ -34,57 +31,28 @@
|
|
|
34
31
|
"import": "./index.js",
|
|
35
32
|
"default": "./index.js"
|
|
36
33
|
},
|
|
37
|
-
"./
|
|
38
|
-
"types": "./
|
|
39
|
-
"import": "./
|
|
40
|
-
"default": "./
|
|
41
|
-
},
|
|
42
|
-
"./ui": {
|
|
43
|
-
"types": "./ui.d.ts",
|
|
44
|
-
"import": "./ui.js",
|
|
45
|
-
"default": "./ui.js"
|
|
46
|
-
},
|
|
47
|
-
"./ui/testing": {
|
|
48
|
-
"types": "./ui-testing.d.ts",
|
|
49
|
-
"import": "./ui-testing.js",
|
|
50
|
-
"default": "./ui-testing.js"
|
|
51
|
-
},
|
|
52
|
-
"./ui/testing/serializer": {
|
|
53
|
-
"types": "./ui-testing-serializer.d.ts",
|
|
54
|
-
"import": "./ui-testing-serializer.js",
|
|
55
|
-
"default": "./ui-testing-serializer.js"
|
|
34
|
+
"./main": {
|
|
35
|
+
"types": "./main.d.ts",
|
|
36
|
+
"import": "./main.js",
|
|
37
|
+
"default": "./main.js"
|
|
56
38
|
},
|
|
57
39
|
"./package.json": "./package.json"
|
|
58
40
|
},
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"@effected/engine": "^0.11.0",
|
|
62
|
-
"@effected/github-commands": "^0.8.0"
|
|
41
|
+
"bin": {
|
|
42
|
+
"effected": "bin/effected.js"
|
|
63
43
|
},
|
|
64
|
-
"
|
|
65
|
-
"@
|
|
66
|
-
"@effected/
|
|
67
|
-
"@effected/
|
|
68
|
-
"@effected/
|
|
69
|
-
"@
|
|
70
|
-
"
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@effect/platform-node": "~4.1.2",
|
|
46
|
+
"@effected/cli-kit": "^0.27.0",
|
|
47
|
+
"@effected/engine": "0.13.0",
|
|
48
|
+
"@effected/env": "^0.11.0",
|
|
49
|
+
"@effected/glob": "^0.19.0",
|
|
50
|
+
"@effected/kit": "^0.13.0",
|
|
51
|
+
"@effected/walker": "^0.25.1",
|
|
52
|
+
"effect": "~4.1.2",
|
|
71
53
|
"ink": "^8.0.0",
|
|
72
54
|
"react": "^19.3.0"
|
|
73
55
|
},
|
|
74
|
-
"peerDependenciesMeta": {
|
|
75
|
-
"@effected/config-file": {
|
|
76
|
-
"optional": true
|
|
77
|
-
},
|
|
78
|
-
"@types/react": {
|
|
79
|
-
"optional": true
|
|
80
|
-
},
|
|
81
|
-
"ink": {
|
|
82
|
-
"optional": true
|
|
83
|
-
},
|
|
84
|
-
"react": {
|
|
85
|
-
"optional": true
|
|
86
|
-
}
|
|
87
|
-
},
|
|
88
56
|
"engines": {
|
|
89
57
|
"node": ">=24.11.0"
|
|
90
58
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { Doc } from "@effected/cli-kit";
|
|
2
|
+
|
|
3
|
+
// src/render/DiffDoc.ts
|
|
4
|
+
/**
|
|
5
|
+
* How many diff rows `DiffDoc.render` shows per schema before it cuts the rest with a "… N more lines" tail: a
|
|
6
|
+
* screenful of context that keeps a many-schema report readable.
|
|
7
|
+
*
|
|
8
|
+
* @public
|
|
9
|
+
*/
|
|
10
|
+
const DEFAULT_MAX_DIFF_LINES = 40;
|
|
11
|
+
const expandTabs = (text) => text.replaceAll(" ", " ");
|
|
12
|
+
/**
|
|
13
|
+
* A schema's line diff as a `Doc`, in git's shape: an `@@ path @@` header, context lines as they are, removes in the
|
|
14
|
+
* `error` token and adds in the `success` token.
|
|
15
|
+
*
|
|
16
|
+
* @remarks
|
|
17
|
+
* Each tab in a line's text is expanded to two spaces, so a tab-indented document keeps its shape. Every line's text
|
|
18
|
+
* goes into the document as a `Doc.text` run, which is data: the renderers remove escape and control characters from it
|
|
19
|
+
* and never read it as markup, so a diff of untrusted text cannot repaint the terminal.
|
|
20
|
+
* A document with more than one hunk separates them with a muted `@@ -a,b +c,d @@` range row. The cap counts every
|
|
21
|
+
* row after the header (diff lines, range rows and `` markers) and the tail names exactly
|
|
22
|
+
* how many were cut. Nothing here loads Ink or React.
|
|
23
|
+
*
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
var DiffDoc = class {
|
|
27
|
+
constructor() {}
|
|
28
|
+
/**
|
|
29
|
+
* @param path - the schema file the diff is for, shown in the header
|
|
30
|
+
* @param diff - the diff
|
|
31
|
+
* @param options - `maxLines`, the cap on shown rows
|
|
32
|
+
*/
|
|
33
|
+
static render(path, diff, options) {
|
|
34
|
+
const cap = Math.max(0, Math.floor(options?.maxLines ?? 40));
|
|
35
|
+
const rows = [];
|
|
36
|
+
diff.hunks.forEach((hunk) => {
|
|
37
|
+
if (diff.hunks.length > 1) rows.push(Doc.text(`@@ -${hunk.oldStart},${hunk.oldLines} +${hunk.newStart},${hunk.newLines} @@`, "muted"));
|
|
38
|
+
for (const line of hunk.lines) {
|
|
39
|
+
const text = expandTabs(line.text);
|
|
40
|
+
rows.push(line.kind === "add" ? Doc.text(`+${text}`, "success") : line.kind === "remove" ? Doc.text(`-${text}`, "error") : Doc.text(` ${text}`));
|
|
41
|
+
if (line.noNewline === true) rows.push(Doc.text("\", "muted"));
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
const hidden = rows.length - cap;
|
|
45
|
+
const shown = hidden > 0 ? rows.slice(0, cap) : rows;
|
|
46
|
+
if (hidden > 0) shown.push(Doc.text(`… ${hidden} more ${hidden === 1 ? "line" : "lines"}`, "muted"));
|
|
47
|
+
return Doc.lines([Doc.text(`@@ ${path} @@`, "accent"), ...shown], { wrap: false });
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export { DiffDoc };
|
package/tsdoc-metadata.json
CHANGED
package/version.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/version.ts
|
|
2
|
+
/**
|
|
3
|
+
* The `effected` command's version. The bundler replaces the exact expression
|
|
4
|
+
* `process.env.__PACKAGE_VERSION__` with the package version at build time, so
|
|
5
|
+
* it must stay spelled this way.
|
|
6
|
+
*
|
|
7
|
+
* @public
|
|
8
|
+
*/
|
|
9
|
+
const CLI_VERSION = "0.27.0";
|
|
10
|
+
|
|
11
|
+
export { CLI_VERSION };
|
package/Cancelled.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { Runtime, Schema } from "effect";
|
|
2
|
-
|
|
3
|
-
// src/Cancelled.ts
|
|
4
|
-
/**
|
|
5
|
-
* A person backed out of an interactive prompt: they pressed escape, or the
|
|
6
|
-
* prompt was interrupted.
|
|
7
|
-
*
|
|
8
|
-
* @remarks
|
|
9
|
-
* Exits `130`, the conventional status for a run ended by the user, through
|
|
10
|
-
* core's own `Runtime.errorExitCode` marker, so `CliRuntime.reportFailures`
|
|
11
|
-
* keeps it. Its default rendering is one line, `cancelled; nothing written`,
|
|
12
|
-
* because nothing has been written by the time a prompt is cancelled and a
|
|
13
|
-
* stack trace would only alarm. A consumer `render` still overrides the line, and can hand off to it: the line is
|
|
14
|
-
* the error's `message`, so `error.message` and `String(error)` carry it.
|
|
15
|
-
*
|
|
16
|
-
* @public
|
|
17
|
-
*/
|
|
18
|
-
var Cancelled = class extends Schema.TaggedError()("Cancelled", { reason: Schema.Literals(["escape", "interrupt"]) }) {
|
|
19
|
-
/**
|
|
20
|
-
* The one line, `cancelled; nothing written`.
|
|
21
|
-
*
|
|
22
|
-
* @remarks
|
|
23
|
-
* A prototype getter, not a field, so it is not part of the encoded form, equality or a JSON dump. Assigning to
|
|
24
|
-
* it is ignored: a library that rewrites `error.message` (to prefix a context, say) must not make this error throw,
|
|
25
|
-
* which a getter-only property does in strict mode. The line is fixed.
|
|
26
|
-
*/
|
|
27
|
-
get message() {
|
|
28
|
-
return "cancelled; nothing written";
|
|
29
|
-
}
|
|
30
|
-
set message(_value) {}
|
|
31
|
-
/**
|
|
32
|
-
* The process exit code: `130`.
|
|
33
|
-
*
|
|
34
|
-
* @remarks
|
|
35
|
-
* A prototype getter rather than an own field, so a JSON or logger dump of the error does not carry the
|
|
36
|
-
* runtime marker.
|
|
37
|
-
*/
|
|
38
|
-
get [Runtime.errorExitCode]() {
|
|
39
|
-
return 130;
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
export { Cancelled };
|
package/CliAudience.js
DELETED
|
@@ -1,177 +0,0 @@
|
|
|
1
|
-
import { canPrompt } from "./internal/canPrompt.js";
|
|
2
|
-
import { CliInteractive } from "./CliInteractive.js";
|
|
3
|
-
import { refreshFailureTarget } from "./internal/failureTarget.js";
|
|
4
|
-
import { scanAudience, tallyAudience } from "./internal/scanAudience.js";
|
|
5
|
-
import { WizardDropped } from "./internal/wizardGate.js";
|
|
6
|
-
import { Effect, Option, Stdio } from "effect";
|
|
7
|
-
import { Audience, TerminalEnv } from "@effected/env";
|
|
8
|
-
import { CliConfig, CliError, Command, Flag, GlobalFlag } from "effect/cli";
|
|
9
|
-
|
|
10
|
-
// src/CliAudience.ts
|
|
11
|
-
const KINDS = [
|
|
12
|
-
"human",
|
|
13
|
-
"agent",
|
|
14
|
-
"ci"
|
|
15
|
-
];
|
|
16
|
-
/**
|
|
17
|
-
* Whether the run may prompt once a flag has named the audience.
|
|
18
|
-
*
|
|
19
|
-
* Only a `human` audience prompts, and only with a terminal on both standard input and standard output and a `TERM`
|
|
20
|
-
* that is not `dumb` (`canPrompt`, the decision `CliInteractive.layer` makes). With the
|
|
21
|
-
* terminal facts in the environment (`TerminalEnv`) that is decided from them, not from the ambient value, so a
|
|
22
|
-
* flag can WIDEN: `--human` under a detected agent on real terminals prompts, and in a pipe it still cannot. With no
|
|
23
|
-
* `TerminalEnv` there is nothing to decide from and the flag only narrows.
|
|
24
|
-
*/
|
|
25
|
-
const interactiveWhenFlagged = (kind, current) => Effect.flatMap(Effect.serviceOption(TerminalEnv), (terminal) => {
|
|
26
|
-
if (kind !== "human") return Effect.succeed(false);
|
|
27
|
-
return Option.isSome(terminal) ? canPrompt(terminal.value) : Effect.succeed(current);
|
|
28
|
-
});
|
|
29
|
-
const CONFLICT = "Give at most one of --audience, --human, --agent, --ci (once).";
|
|
30
|
-
/** Resolve the four flags into the audience to provide, failing when more than one occurrence was given. */
|
|
31
|
-
const resolve = (input) => {
|
|
32
|
-
const { given: named, conflict } = tallyAudience(input);
|
|
33
|
-
if (conflict) return Effect.fail(new CliError.UserError({
|
|
34
|
-
cause: /* @__PURE__ */ new Error(CONFLICT),
|
|
35
|
-
userMessage: CONFLICT
|
|
36
|
-
}));
|
|
37
|
-
const [kind] = named;
|
|
38
|
-
return kind === void 0 ? Audience : Effect.succeed({
|
|
39
|
-
kind,
|
|
40
|
-
source: "flag"
|
|
41
|
-
});
|
|
42
|
-
};
|
|
43
|
-
/**
|
|
44
|
-
* The audience flags of a CLI: `--audience <human|agent|ci>` and the shorthands `--human`, `--agent`, `--ci`,
|
|
45
|
-
* resolved into `@effected/env`'s `Audience`.
|
|
46
|
-
*
|
|
47
|
-
* @remarks
|
|
48
|
-
* The one wiring: share the flags on the root command and hand the root to {@link CliAudience.run} (or
|
|
49
|
-
* {@link CliAudience.runWith}), which resolves the flags from argv before core parses and applies
|
|
50
|
-
* {@link CliAudience.provide} itself:
|
|
51
|
-
*
|
|
52
|
-
* ```ts
|
|
53
|
-
* const root = Command.make("tool").pipe(
|
|
54
|
-
* Command.withSharedFlags(CliAudience.flags()),
|
|
55
|
-
* Command.withSubcommands([verify]),
|
|
56
|
-
* )
|
|
57
|
-
* NodeRuntime.runMain(
|
|
58
|
-
* CliRuntime.main(CliAudience.run(root, { version }), { platform: NodeServices.layer, env: {} }),
|
|
59
|
-
* )
|
|
60
|
-
* ```
|
|
61
|
-
*
|
|
62
|
-
* Core lists a shared flag in the help of every subcommand, not only at the root: that is upstream (Effect-TS/effect
|
|
63
|
-
* issue 8642), and `flags({ hidden: true })` is the way to keep them out of help altogether.
|
|
64
|
-
*
|
|
65
|
-
* A root that forgot `Command.withSharedFlags(CliAudience.flags())` does not compile. Giving more than one
|
|
66
|
-
* occurrence across the four flags is a usage error even when they agree; a boolean set to false (`--no-agent`,
|
|
67
|
-
* `--agent=false`) counts as not given. A bad `--audience` value is core's own parse error. Both exit `64` under
|
|
68
|
-
* `CliRuntime.main`. A conflicting audience together with `--help` exits `0` and prints help, because core handles
|
|
69
|
-
* its action flags before the resolver runs.
|
|
70
|
-
*
|
|
71
|
-
* A flag decides `CliInteractive` from the audience it names and the terminal facts: `--human` is interactive when
|
|
72
|
-
* `TerminalEnv` says there is a terminal on stdin and on stdout, even where the environment detected an agent, so a
|
|
73
|
-
* person running the tool inside an agent can ask for the human experience; in a pipe it still cannot prompt. A
|
|
74
|
-
* non-human flag (`--agent`, `--ci`, `--audience agent|ci`) turns it off and drops `--wizard`, and switches
|
|
75
|
-
* diagnostics to NDJSON, for the whole run including the parse step where a fallback prompt fires. Without
|
|
76
|
-
* `TerminalEnv` in the environment a flag only narrows. `--wizard` follows the decision: a run a flag makes
|
|
77
|
-
* interactive gets it back where the environment's gate had dropped it, and only there: a consumer's own `builtIns`
|
|
78
|
-
* without it stay without it.
|
|
79
|
-
* {@link CliAudience.provide} on its own, the path for a bare `Command.run`, acts only on the subcommand handler,
|
|
80
|
-
* because core parses the root flags into a local context before any of it is visible.
|
|
81
|
-
*
|
|
82
|
-
* @public
|
|
83
|
-
*/
|
|
84
|
-
var CliAudience = class CliAudience {
|
|
85
|
-
constructor() {}
|
|
86
|
-
/**
|
|
87
|
-
* The four flags, for `Command.withSharedFlags` on the root command.
|
|
88
|
-
*
|
|
89
|
-
* @remarks
|
|
90
|
-
* Each is repeatable, so every occurrence is counted; a boolean given as `false` (`--agent=false`,
|
|
91
|
-
* `--no-agent`) is not an occurrence. Core lists shared flags in every command's help; pass
|
|
92
|
-
* `hidden` to remove them from all of them.
|
|
93
|
-
*/
|
|
94
|
-
static flags = (options) => {
|
|
95
|
-
const hide = options?.hidden === true;
|
|
96
|
-
const maybeHide = (flag) => hide ? Flag.withHidden(flag) : flag;
|
|
97
|
-
return {
|
|
98
|
-
audience: maybeHide(Flag.Literals("audience", KINDS).pipe(Flag.atLeast(0), Flag.withDescription("Who the output is for"))),
|
|
99
|
-
human: maybeHide(Flag.Boolean("human").pipe(Flag.atLeast(0), Flag.withDescription("Shorthand for --audience human"))),
|
|
100
|
-
agent: maybeHide(Flag.Boolean("agent").pipe(Flag.atLeast(0), Flag.withDescription("Shorthand for --audience agent"))),
|
|
101
|
-
ci: maybeHide(Flag.Boolean("ci").pipe(Flag.atLeast(0), Flag.withDescription("Shorthand for --audience ci")))
|
|
102
|
-
};
|
|
103
|
-
};
|
|
104
|
-
/**
|
|
105
|
-
* Resolve the flags before every subcommand handler and re-provide `Audience`.
|
|
106
|
-
*
|
|
107
|
-
* @remarks
|
|
108
|
-
* `CliAudience.run` and `runWith` apply this themselves, so a program run through them never needs it. Use it
|
|
109
|
-
* directly only with a bare `Command.run`, which leaves a fallback prompt blind to the flags (see the class
|
|
110
|
-
* remarks).
|
|
111
|
-
*
|
|
112
|
-
* A failure report is written outside the run, where the flag is not in force, so only `runWith` and `run` carry
|
|
113
|
-
* the flag's audience to it; with this on its own the report follows the environment's audience.
|
|
114
|
-
*
|
|
115
|
-
* Pipe it onto the composite root, after `withSubcommands`, since a parent's handler does not run when a
|
|
116
|
-
* subcommand is selected. With exactly one flag the audience is `{ kind, source: "flag" }`; with none the
|
|
117
|
-
* ambient `Audience` is read and provided back unchanged, so `Audience` stays in the requirement a handler
|
|
118
|
-
* reading it already has, and is added to a program whose handlers do not read it.
|
|
119
|
-
*/
|
|
120
|
-
static provide = (command) => Command.provideEffect(command, Audience, (input) => resolve(input)).pipe(Command.provideEffect(CliInteractive, (input) => Effect.gen(function* () {
|
|
121
|
-
const current = yield* CliInteractive;
|
|
122
|
-
const [flagged] = tallyAudience(input).given;
|
|
123
|
-
return flagged === void 0 ? current : yield* interactiveWhenFlagged(flagged, current);
|
|
124
|
-
})));
|
|
125
|
-
/**
|
|
126
|
-
* Run a command the way `Command.runWith` does, with the audience flag resolved BEFORE core parses.
|
|
127
|
-
*
|
|
128
|
-
* @remarks
|
|
129
|
-
* It scans `argv` for the four audience flags first, then runs core around a provided `Audience` (when exactly
|
|
130
|
-
* one is given: `{ kind, source: "flag" }`) and a `CliInteractive` decided from it: `--human` is interactive when
|
|
131
|
-
* `TerminalEnv` reports a terminal on stdin and stdout and `TERM` is not `dumb` (it can turn prompting on under a detected agent), a
|
|
132
|
-
* non-human flag or a conflict makes it false. A fallback prompt fires while core parses, earlier than
|
|
133
|
-
* anything `CliAudience.provide` can reach, so `--agent init` on a terminal would otherwise still prompt. No
|
|
134
|
-
* flag leaves the ambient values untouched. A conflict still gets core's own usage error, exit `64`, from
|
|
135
|
-
* `CliAudience.provide`'s resolver.
|
|
136
|
-
*
|
|
137
|
-
* @param command - the composite root, with the flags shared and `CliAudience.provide` piped on
|
|
138
|
-
* @param config - the same `version` and `renderErrors` as core's
|
|
139
|
-
*/
|
|
140
|
-
static runWith = (command, config) => {
|
|
141
|
-
const core = Command.runWith(CliAudience.provide(command), config);
|
|
142
|
-
return (argv) => {
|
|
143
|
-
const run = core(argv);
|
|
144
|
-
const { given, conflict } = scanAudience(argv);
|
|
145
|
-
const [kind] = given;
|
|
146
|
-
if (kind === void 0) return run;
|
|
147
|
-
const withAudience = conflict ? run : Effect.provideService(run, Audience, {
|
|
148
|
-
kind,
|
|
149
|
-
source: "flag"
|
|
150
|
-
});
|
|
151
|
-
return Effect.gen(function* () {
|
|
152
|
-
const current = yield* CliInteractive;
|
|
153
|
-
const ambient = yield* CliConfig.CliConfig;
|
|
154
|
-
if (!conflict) yield* refreshFailureTarget({
|
|
155
|
-
kind,
|
|
156
|
-
source: "flag"
|
|
157
|
-
});
|
|
158
|
-
const interactive = !conflict && (yield* interactiveWhenFlagged(kind, current));
|
|
159
|
-
const decided = Effect.provideService(withAudience, CliInteractive, interactive);
|
|
160
|
-
const hasWizard = ambient.builtIns.includes(GlobalFlag.Wizard);
|
|
161
|
-
if (!(interactive && !hasWizard && (yield* WizardDropped) === ambient) && !(!interactive && hasWizard)) return yield* decided;
|
|
162
|
-
const builtIns = interactive ? [...ambient.builtIns, GlobalFlag.Wizard] : ambient.builtIns.filter((flag) => flag !== GlobalFlag.Wizard);
|
|
163
|
-
return yield* Effect.provideService(decided, CliConfig.CliConfig, CliConfig.make({ builtIns }));
|
|
164
|
-
});
|
|
165
|
-
};
|
|
166
|
-
};
|
|
167
|
-
/**
|
|
168
|
-
* `Command.run` with the audience flag resolved before parsing: reads `Stdio.args` and calls
|
|
169
|
-
* {@link CliAudience.runWith}.
|
|
170
|
-
*
|
|
171
|
-
* @param command - the composite root
|
|
172
|
-
* @param config - the same `version` and `renderErrors` as core's
|
|
173
|
-
*/
|
|
174
|
-
static run = (command, config) => Stdio.Stdio.use(({ args }) => Effect.flatMap(args, (argv) => CliAudience.runWith(command, config)(argv)));
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
export { CliAudience };
|
package/CliColor.js
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { Effect, Layer } from "effect";
|
|
2
|
-
import { TerminalEnv } from "@effected/env";
|
|
3
|
-
import { CliOutput } from "effect/cli";
|
|
4
|
-
|
|
5
|
-
// src/CliColor.ts
|
|
6
|
-
/**
|
|
7
|
-
* Whether a CLI's output should carry ANSI colour, decided once and shared by
|
|
8
|
-
* everything that renders — help text, error output, and any rendered result.
|
|
9
|
-
*
|
|
10
|
-
* @remarks
|
|
11
|
-
* The decision is `@effected/env`'s `TerminalEnv.colorLevel("stdout")`, which
|
|
12
|
-
* follows Node's `getColorDepth` precedence: `FORCE_COLOR` first (`0` or an
|
|
13
|
-
* unrecognised value forces colour off; an empty value, `1` or `true` force basic colour, `2` 256 colours and
|
|
14
|
-
* `3` truecolor, even without a terminal), then a non-empty `NO_COLOR` or `NODE_DISABLE_COLORS` and
|
|
15
|
-
* `TERM=dumb`, then the TTY gate. `FORCE_COLOR` therefore beats `NO_COLOR`.
|
|
16
|
-
* The environment
|
|
17
|
-
* is read through the ambient `ConfigProvider`, never `process`, so a test
|
|
18
|
-
* swaps it with `Effect.provideService(ConfigProvider.ConfigProvider, ...)`;
|
|
19
|
-
* an ambient `TerminalEnv`, such as `TerminalEnv.layerTest`, answers instead
|
|
20
|
-
* when one is provided.
|
|
21
|
-
*
|
|
22
|
-
* @public
|
|
23
|
-
*/
|
|
24
|
-
var CliColor = class CliColor {
|
|
25
|
-
constructor() {}
|
|
26
|
-
/**
|
|
27
|
-
* The decision, for passing to a pure renderer as a plain boolean.
|
|
28
|
-
*
|
|
29
|
-
* @public
|
|
30
|
-
*/
|
|
31
|
-
static enabled = TerminalEnv.colorLevel("stdout").pipe(Effect.map((level) => level !== "none"));
|
|
32
|
-
/**
|
|
33
|
-
* Core's default `CliOutput.Formatter`, coloured by the same decision as
|
|
34
|
-
* {@link CliColor.enabled}, so help text, parse errors and rendered
|
|
35
|
-
* output never disagree on whether colour is on.
|
|
36
|
-
*
|
|
37
|
-
* @remarks
|
|
38
|
-
* `overrides` replaces individual methods of the default formatter — for
|
|
39
|
-
* example `formatVersion`, to append a "via `<carrier>`" line without
|
|
40
|
-
* losing the other defaults. Each call mints a fresh layer; bind the
|
|
41
|
-
* result to a `const` or the decision is re-read every time it is
|
|
42
|
-
* provided.
|
|
43
|
-
*
|
|
44
|
-
* The `never` in its output does not mean it installs nothing.
|
|
45
|
-
* `CliOutput.Formatter` is a `Context.Reference`, whose key type is
|
|
46
|
-
* `never`, so this layer sets the formatter reference rather than
|
|
47
|
-
* providing a service. Every command it is provided to renders with the
|
|
48
|
-
* formatter it sets, and without it they fall back to core's default
|
|
49
|
-
* formatter.
|
|
50
|
-
*
|
|
51
|
-
* @public
|
|
52
|
-
*/
|
|
53
|
-
static formatterLayer = (overrides = {}) => Layer.unwrap(Effect.map(CliColor.enabled, (colors) => CliOutput.layer({
|
|
54
|
-
...CliOutput.defaultFormatter({ colors }),
|
|
55
|
-
...overrides
|
|
56
|
-
})));
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export { CliColor };
|