@effected/cli 0.27.0 → 0.29.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/bin/effected.js CHANGED
@@ -1,7 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import { main } from "../main.js";
3
-
4
2
  // src/bin.ts
3
+ if (import.meta.url.endsWith(".ts")) {
4
+ const { register } = await import([
5
+ "tsx",
6
+ "esm",
7
+ "api"
8
+ ].join("/"));
9
+ register();
10
+ }
11
+ const { main } = await import("../main.js");
5
12
  main();
6
13
 
7
14
  export { };
package/ci.js ADDED
@@ -0,0 +1,16 @@
1
+ import { Option } from "effect";
2
+ import { RuntimeEnv } from "@effected/env";
3
+
4
+ // src/ci.ts
5
+ /**
6
+ * Whether the process runs under CI, by `@effected/env`'s one rule: a known
7
+ * provider's marker, or a truthy `CI` or `CONTINUOUS_INTEGRATION`; `CI=false`
8
+ * is not CI. Its own module so `main` and its test call the same expression,
9
+ * and so `main` never reaches `@effected/engine/build`, which loads the
10
+ * bundler and its toolchain.
11
+ *
12
+ * @internal
13
+ */
14
+ const isCI = (env) => Option.isSome(RuntimeEnv.fromRecord(env).ci);
15
+
16
+ export { isCI };
@@ -0,0 +1,9 @@
1
+ import { execute } from "./execute.js";
2
+ import { buildFlags } from "./flags.js";
3
+ import { Command } from "effect/cli";
4
+
5
+ // src/commands/action/build.ts
6
+ /** `effected action build`: build the GitHub Action in the working directory into its `dist`. */
7
+ const makeBuildCommand = (deps) => Command.make("build", buildFlags, (input) => execute(input, deps)).pipe(Command.withDescription("Build the GitHub Action in the working directory from the [action] table of its effected.toml into dist"));
8
+
9
+ export { makeBuildCommand };
@@ -0,0 +1,54 @@
1
+ import { Schema } from "effect";
2
+
3
+ // src/commands/action/errors.ts
4
+ /**
5
+ * Validation stopped the build or an entry failed. Exit `1`.
6
+ *
7
+ * @public
8
+ */
9
+ var ActionBuildFailedError = class extends Schema.TaggedError()("ActionBuildFailedError", {
10
+ /** How many validation errors there were. */
11
+ errors: Schema.Number,
12
+ /** How many entries failed to bundle or load. */
13
+ failedEntries: Schema.Number
14
+ }) {
15
+ get message() {
16
+ const parts = [...this.errors > 0 ? [`${this.errors} validation error(s)`] : [], ...this.failedEntries > 0 ? [`${this.failedEntries} failed entry(ies)`] : []];
17
+ return parts.length > 0 ? `The action build failed with ${parts.join(" and ")}.` : "The action build failed: warnings are errors in strict mode.";
18
+ }
19
+ };
20
+ /**
21
+ * The build could not start: its `effected.toml` would not load, it has no `[action]` table, or the directory is not a
22
+ * package. Exit `2`: exit `1` means it ran and found a problem.
23
+ *
24
+ * @remarks
25
+ * Carries the engine's message. This command's own type rather than the engine's, because the engine's build entry is
26
+ * loaded only when the command runs.
27
+ *
28
+ * @public
29
+ */
30
+ var ActionConfigError = class extends Schema.TaggedError()("ActionConfigError", { message: Schema.String }) {};
31
+ /**
32
+ * The build could not finish: an entry is missing with validation off, or a file could not be read, cleaned, written or
33
+ * copied. `action init` fails with it too when a write fails after its checks, naming the files already written. Exit
34
+ * `3`, the infrastructure tier.
35
+ *
36
+ * @remarks
37
+ * Carries the engine's message, as {@link ActionConfigError} does.
38
+ *
39
+ * @public
40
+ */
41
+ var ActionRunError = class extends Schema.TaggedError()("ActionRunError", { message: Schema.String }) {};
42
+ /**
43
+ * `action init` could not start: the directory is not a package, the action's name or description was found nowhere
44
+ * or holds a control character, files it would write exist and `--force` was not given, or a path cannot be written
45
+ * over (a symbolic link, the wrong kind of entry), which `--force` never overrides. Exit `2`, and nothing was written.
46
+ *
47
+ * @remarks
48
+ * Carries the engine's message, as {@link ActionConfigError} does.
49
+ *
50
+ * @public
51
+ */
52
+ var ActionInitError = class extends Schema.TaggedError()("ActionInitError", { message: Schema.String }) {};
53
+
54
+ export { ActionBuildFailedError, ActionConfigError, ActionInitError, ActionRunError };
@@ -0,0 +1,44 @@
1
+ import { InitDoc } from "../../render/InitDoc.js";
2
+ import { resolveFormat } from "../schema/execute.js";
3
+ import { ActionInitError, ActionRunError } from "./errors.js";
4
+ import { Console, Effect, Option, Schema } from "effect";
5
+ import { CliRuntime, Doc } from "@effected/cli-kit";
6
+
7
+ // src/commands/action/execute-init.ts
8
+ /**
9
+ * Run one `action init`.
10
+ *
11
+ * @remarks
12
+ * The engine's build entry is imported here, as `action build` imports it, so `effected --version` never loads it.
13
+ */
14
+ const executeInit = Effect.fn("effected.action.init")(function* (input, deps) {
15
+ const format = yield* resolveFormat(input.format);
16
+ const { ActionInit, ActionInitResult } = yield* Effect.promise(() => import("@effected/engine/build"));
17
+ const refused = (error) => Effect.fail(CliRuntime.reported(new ActionInitError({ message: error.message }), 2));
18
+ const stopped = (error) => Effect.fail(CliRuntime.reported(new ActionRunError({ message: error.message }), 3));
19
+ const answer = yield* ActionInit.run({
20
+ ...Option.match(input.name, {
21
+ onNone: () => ({}),
22
+ onSome: (name) => ({ name })
23
+ }),
24
+ ...Option.match(input.description, {
25
+ onNone: () => ({}),
26
+ onSome: (description) => ({ description })
27
+ }),
28
+ force: input.force
29
+ }, { cwd: deps.cwd }).pipe(Effect.catchTags({
30
+ NotAPackageError: refused,
31
+ ActionMetadataMissingError: refused,
32
+ ActionMetadataInvalidError: refused,
33
+ ScaffoldConflictError: refused,
34
+ ScaffoldExistsError: (error) => Effect.fail(CliRuntime.reported(new ActionInitError({ message: `${error.message}: pass --force to replace them` }), 2)),
35
+ ScaffoldWriteError: stopped,
36
+ PlatformError: stopped
37
+ }));
38
+ if (format === "json") {
39
+ yield* Console.log(JSON.stringify(Schema.encodeSync(ActionInitResult)(answer)));
40
+ for (const line of InitDoc.lines(answer)) yield* Effect.logInfo(line);
41
+ } else yield* Doc.print([InitDoc.render(answer)]);
42
+ });
43
+
44
+ export { executeInit };
@@ -0,0 +1,47 @@
1
+ import { ActionDoc } from "../../render/ActionDoc.js";
2
+ import { resolveFormat } from "../schema/execute.js";
3
+ import { ActionBuildFailedError, ActionConfigError, ActionRunError } from "./errors.js";
4
+ import { Console, Effect, Schema } from "effect";
5
+ import { CliRuntime, Doc } from "@effected/cli-kit";
6
+ import { StepSummary } from "@effected/engine/schema";
7
+
8
+ // src/commands/action/execute.ts
9
+ /**
10
+ * Run one `action build`.
11
+ *
12
+ * @remarks
13
+ * The engine's build entry is imported here rather than at the top of the module: it loads the bundler and its
14
+ * toolchain, which `effected --version` and every `effected schema` run have no use for. The report is emitted first and
15
+ * the failure follows, so a run that fails has still said why.
16
+ */
17
+ const execute = Effect.fn("effected.action.execute")(function* (input, deps) {
18
+ const format = yield* resolveFormat(input.format);
19
+ const { ActionRun, ActionRunResult } = yield* Effect.promise(() => import("@effected/engine/build"));
20
+ const refused = (error) => Effect.fail(CliRuntime.reported(new ActionConfigError({ message: error.message }), 2));
21
+ const stopped = (error) => Effect.fail(CliRuntime.reported(new ActionRunError({ message: error.message }), 3));
22
+ const answer = yield* ActionRun.run({
23
+ validate: !input.noValidate,
24
+ persist: !input.noPersist
25
+ }, deps).pipe(Effect.catchTags({
26
+ EffectedConfigError: refused,
27
+ NotAPackageError: refused,
28
+ NotAnActionError: refused,
29
+ BundleFailed: stopped,
30
+ CleanError: stopped,
31
+ WriteError: stopped,
32
+ PersistLocalError: stopped,
33
+ ActionYmlPathError: stopped,
34
+ PlatformError: stopped
35
+ }));
36
+ if (format === "json") {
37
+ yield* Console.log(JSON.stringify(Schema.encodeSync(ActionRunResult)(answer)));
38
+ for (const line of ActionDoc.lines(answer.result)) yield* Effect.logInfo(line);
39
+ } else yield* Doc.print([ActionDoc.render(answer.result)]);
40
+ yield* StepSummary.append(ActionDoc.markdown(answer.result));
41
+ if (answer.verdict === "failed") return yield* Effect.fail(CliRuntime.reported(new ActionBuildFailedError({
42
+ errors: answer.result.validation.errors.length,
43
+ failedEntries: answer.result.build.entries.filter((entry) => !entry.success).length
44
+ }), 1));
45
+ });
46
+
47
+ export { execute };
@@ -0,0 +1,19 @@
1
+ import { formatFlag } from "../schema/flags.js";
2
+ import { Flag } from "effect/cli";
3
+
4
+ // src/commands/action/flags.ts
5
+ /** What `action build` takes. */
6
+ const buildFlags = {
7
+ format: formatFlag,
8
+ noValidate: Flag.Boolean("no-validate").pipe(Flag.withDefault(false), Flag.withDescription("Skip validating the config and action.yml, and the bundle size check")),
9
+ noPersist: Flag.Boolean("no-persist").pipe(Flag.withDefault(false), Flag.withDescription("Skip copying the build to the local action directory"))
10
+ };
11
+ /** What `action init` takes. A name or description left out is read from `package.json`. */
12
+ const initFlags = {
13
+ format: formatFlag,
14
+ name: Flag.String("name").pipe(Flag.optional, Flag.withDescription("The action's display name in action.yml; omitted, package.json's name without its scope")),
15
+ description: Flag.String("description").pipe(Flag.optional, Flag.withDescription("What the action does, for action.yml; omitted, package.json's description")),
16
+ force: Flag.Boolean("force").pipe(Flag.withDefault(false), Flag.withDescription("Replace files that already exist; without it, any existing file stops the run before a write"))
17
+ };
18
+
19
+ export { buildFlags, initFlags };
@@ -0,0 +1,9 @@
1
+ import { makeBuildCommand } from "./build.js";
2
+ import { makeInitCommand } from "./init.js";
3
+ import { Command } from "effect/cli";
4
+
5
+ // src/commands/action/index.ts
6
+ /** `effected action`: the group, closed over the process boundary it runs against. */
7
+ const makeActionCommand = (deps) => Command.make("action", {}).pipe(Command.withDescription("Scaffold or build the GitHub Action in the working directory, from its effected.toml"), Command.withSubcommands([makeBuildCommand(deps), makeInitCommand(deps)]));
8
+
9
+ export { makeActionCommand };
@@ -0,0 +1,9 @@
1
+ import { executeInit } from "./execute-init.js";
2
+ import { initFlags } from "./flags.js";
3
+ import { Command } from "effect/cli";
4
+
5
+ // src/commands/action/init.ts
6
+ /** `effected action init`: scaffold a new GitHub Action in the working directory. */
7
+ const makeInitCommand = (deps) => Command.make("init", initFlags, (input) => executeInit(input, deps)).pipe(Command.withDescription("Scaffold a new GitHub Action in the working directory: the [action] table of effected.toml, action.yml, src/main.ts, src/program.ts and tsconfig.json"));
8
+
9
+ export { makeInitCommand };
@@ -0,0 +1,9 @@
1
+ import { execute } from "./execute.js";
2
+ import { buildFlags } from "./flags.js";
3
+ import { Command } from "effect/cli";
4
+
5
+ // src/commands/package/build.ts
6
+ /** `effected package build`: build the package in the working directory into its `dist/prod`. */
7
+ const makeBuildCommand = (deps) => Command.make("build", buildFlags, (input) => execute(input, deps)).pipe(Command.withDescription("Build the package in the working directory into dist/prod: JS, declarations, the manifest, the API model and any binary"));
8
+
9
+ export { makeBuildCommand };
@@ -0,0 +1,38 @@
1
+ import { Schema } from "effect";
2
+
3
+ // src/commands/package/errors.ts
4
+ /**
5
+ * The build crashed or recorded an error. Exit `1`.
6
+ *
7
+ * @public
8
+ */
9
+ var BuildFailedError = class extends Schema.TaggedError()("BuildFailedError", {
10
+ /** How many errors the build recorded. */
11
+ errors: Schema.Number,
12
+ /** What ended the build, when it did not reach its end. */
13
+ failure: Schema.optionalKey(Schema.String)
14
+ }) {
15
+ get message() {
16
+ const count = `${this.errors} error(s)`;
17
+ return this.failure !== void 0 ? `The build failed with ${count}: ${this.failure}` : `The build recorded ${count}.`;
18
+ }
19
+ };
20
+ /**
21
+ * The build could not run: its `effected.toml` or a plugin would not load, the directory is not a package, or the
22
+ * bundler refused the config before any work. Exit `2`: exit `1` means it ran and found a problem.
23
+ *
24
+ * @remarks
25
+ * Carries the engine's message, which names the file at fault and the key within it. This command's own type rather
26
+ * than the bundler's, because the CLI reaches the bundler only through the engine.
27
+ *
28
+ * @public
29
+ */
30
+ var PackageConfigError = class extends Schema.TaggedError()("PackageConfigError", { message: Schema.String }) {};
31
+ /**
32
+ * A file the build needs could not be read or written. Exit `3`, the infrastructure tier.
33
+ *
34
+ * @public
35
+ */
36
+ var PackageRunError = class extends Schema.TaggedError()("PackageRunError", { message: Schema.String }) {};
37
+
38
+ export { BuildFailedError, PackageConfigError, PackageRunError };
@@ -0,0 +1,52 @@
1
+ import { IssuesDoc } from "../../render/IssuesDoc.js";
2
+ import { resolveFormat } from "../schema/execute.js";
3
+ import { BuildFailedError, PackageConfigError, PackageRunError } from "./errors.js";
4
+ import { Console, Effect, Schema } from "effect";
5
+ import { CliRuntime, Doc } from "@effected/cli-kit";
6
+ import { StepSummary } from "@effected/engine/schema";
7
+ import { Audience } from "@effected/env";
8
+
9
+ // src/commands/package/execute.ts
10
+ /**
11
+ * Run one `package build`.
12
+ *
13
+ * @remarks
14
+ * The engine's build entry is imported here rather than at the top of the module: it loads the bundler and its
15
+ * toolchain, which `effected --version` and every `effected schema` run have no use for. The report is emitted first and
16
+ * the failure follows, so a run that fails has still said why.
17
+ *
18
+ * With `--format json`, stdout holds one document, so CI's annotations go to stderr instead, where the runner reads
19
+ * workflow commands too.
20
+ */
21
+ const execute = Effect.fn("effected.package.execute")(function* (input, deps) {
22
+ const format = yield* resolveFormat(input.format);
23
+ const audience = yield* Audience;
24
+ const { BuildRun, BuildRunResult, renderCiAnnotations } = yield* Effect.promise(() => import("@effected/engine/build"));
25
+ const refused = (error) => Effect.fail(CliRuntime.reported(new PackageConfigError({ message: error.message }), 2));
26
+ const result = yield* BuildRun.run({
27
+ noExe: input.noExe,
28
+ verbose: input.verbose
29
+ }, deps).pipe(Effect.catchTags({
30
+ EffectedConfigError: refused,
31
+ PluginLoadError: refused,
32
+ NotAPackageError: refused,
33
+ ConfigValidationError: refused,
34
+ PlatformError: (error) => Effect.fail(CliRuntime.reported(new PackageRunError({ message: error.message }), 3))
35
+ }));
36
+ const { issues } = result;
37
+ if (format === "json") {
38
+ yield* Console.log(JSON.stringify(Schema.encodeSync(BuildRunResult)(result)));
39
+ for (const line of IssuesDoc.lines(issues)) yield* Effect.logInfo(line);
40
+ } else yield* Doc.print([IssuesDoc.render(issues)]);
41
+ if (audience.kind === "ci") {
42
+ const write = format === "json" ? Console.error : Console.log;
43
+ for (const line of renderCiAnnotations(result.report)) yield* write(line);
44
+ }
45
+ yield* StepSummary.append(IssuesDoc.markdown(issues));
46
+ if (result.verdict === "failed") return yield* Effect.fail(CliRuntime.reported(new BuildFailedError({
47
+ errors: issues.errors.length,
48
+ ...issues.failure !== void 0 ? { failure: issues.failure.message } : {}
49
+ }), 1));
50
+ });
51
+
52
+ export { execute };
@@ -0,0 +1,12 @@
1
+ import { formatFlag } from "../schema/flags.js";
2
+ import { Flag } from "effect/cli";
3
+
4
+ // src/commands/package/flags.ts
5
+ /** What `package build` takes. */
6
+ const buildFlags = {
7
+ format: formatFlag,
8
+ noExe: Flag.Boolean("no-exe").pipe(Flag.withDefault(false), Flag.withDescription("Skip the single-executable compile; the manifest still points at the binary")),
9
+ verbose: Flag.Boolean("verbose").pipe(Flag.withDefault(false), Flag.withDescription("Measure gzip sizes for the report"))
10
+ };
11
+
12
+ export { buildFlags };
@@ -0,0 +1,8 @@
1
+ import { makeBuildCommand } from "./build.js";
2
+ import { Command } from "effect/cli";
3
+
4
+ // src/commands/package/index.ts
5
+ /** `effected package`: the group, closed over the process boundary it runs against. */
6
+ const makePackageCommand = (deps) => Command.make("package", {}).pipe(Command.withDescription("Build the package in the working directory from its effected.toml"), Command.withSubcommands([makeBuildCommand(deps)]));
7
+
8
+ export { makePackageCommand };
package/commands/root.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { makeActionCommand } from "./action/index.js";
2
+ import { makePackageCommand } from "./package/index.js";
1
3
  import { makeSchemaCommand } from "./schema/index.js";
2
4
  import { CliAudience } from "@effected/cli-kit";
3
5
  import { Command } from "effect/cli";
@@ -9,6 +11,10 @@ import { Command } from "effect/cli";
9
11
  *
10
12
  * @public
11
13
  */
12
- const makeRootCommand = (deps) => Command.make("effected", {}).pipe(Command.withDescription("The effected tool: a toolchain for Effect v4 applications."), Command.withSharedFlags(CliAudience.flags()), Command.withSubcommands([makeSchemaCommand(deps)]));
14
+ const makeRootCommand = (deps) => Command.make("effected", {}).pipe(Command.withDescription("The effected tool: a toolchain for Effect v4 applications."), Command.withSharedFlags(CliAudience.flags()), Command.withSubcommands([
15
+ makeSchemaCommand(deps),
16
+ makePackageCommand(deps),
17
+ makeActionCommand(deps)
18
+ ]));
13
19
 
14
20
  export { makeRootCommand };
@@ -1,9 +1,9 @@
1
1
  import { DiffDoc } from "../../render/DiffDoc.js";
2
2
  import { CatalogMergeError, DriftError, GateError, NoConfigError, StaleError } from "./errors.js";
3
+ import { Console, Effect, Option } from "effect";
3
4
  import { CliInteractive, CliRuntime, Doc } from "@effected/cli-kit";
4
5
  import { ConfigLoadError, ConfigLoader, Report, SchemaRun, StepSummary } from "@effected/engine/schema";
5
6
  import { Audience } from "@effected/env";
6
- import { Console, Effect, Option } from "effect";
7
7
 
8
8
  // src/commands/schema/execute.ts
9
9
  /** `--format` as given, else what the audience reads: JSON for an agent, human text for a person and for CI. */
@@ -1,10 +1,10 @@
1
1
  import { ValidationFailedError } from "./errors.js";
2
2
  import { configFailures, resolveFormat, warnVersionMismatch } from "./execute.js";
3
3
  import { configArgument, formatFlag, ignoreVersionMismatchFlag } from "./flags.js";
4
+ import { Console, Effect, Option, Schema } from "effect";
4
5
  import { CliRuntime, Doc } from "@effected/cli-kit";
5
6
  import { Argument, Command, Flag } from "effect/cli";
6
7
  import { SchemaValidate, ValidateReport } from "@effected/engine/schema";
7
- import { Console, Effect, Option, Schema } from "effect";
8
8
 
9
9
  // src/commands/schema/validate.ts
10
10
  const findingLine = (finding) => {
package/index.d.ts CHANGED
@@ -1,7 +1,115 @@
1
+ import { Schema } from "effect";
2
+ import { ActionRunDeps, BuildRunDeps } from "@effected/engine/build";
3
+ import "@effected/env";
1
4
  import "effect/cli";
2
5
  import { SchemaRunDeps } from "@effected/engine/schema";
3
- import "@effected/env";
4
- import { Schema } from "effect";
6
+ declare const ActionBuildFailedError_base: Schema.Class<ActionBuildFailedError, Schema.TaggedStruct<"ActionBuildFailedError", {
7
+ /** How many validation errors there were. */
8
+ readonly errors: Schema.Number;
9
+ /** How many entries failed to bundle or load. */
10
+ readonly failedEntries: Schema.Number;
11
+ }>, import("effect/Cause").YieldableError>;
12
+ /**
13
+ * Validation stopped the build or an entry failed. Exit `1`.
14
+ *
15
+ * @public
16
+ */
17
+ export declare class ActionBuildFailedError extends ActionBuildFailedError_base {
18
+ get message(): string;
19
+ }
20
+ declare const ActionConfigError_base: Schema.Class<ActionConfigError, Schema.TaggedStruct<"ActionConfigError", {
21
+ readonly message: Schema.String;
22
+ }>, import("effect/Cause").YieldableError>;
23
+ /**
24
+ * The build could not start: its `effected.toml` would not load, it has no `[action]` table, or the directory is not a
25
+ * package. Exit `2`: exit `1` means it ran and found a problem.
26
+ *
27
+ * @remarks
28
+ * Carries the engine's message. This command's own type rather than the engine's, because the engine's build entry is
29
+ * loaded only when the command runs.
30
+ *
31
+ * @public
32
+ */
33
+ export declare class ActionConfigError extends ActionConfigError_base {}
34
+ declare const ActionRunError_base: Schema.Class<ActionRunError, Schema.TaggedStruct<"ActionRunError", {
35
+ readonly message: Schema.String;
36
+ }>, import("effect/Cause").YieldableError>;
37
+ /**
38
+ * The build could not finish: an entry is missing with validation off, or a file could not be read, cleaned, written or
39
+ * copied. `action init` fails with it too when a write fails after its checks, naming the files already written. Exit
40
+ * `3`, the infrastructure tier.
41
+ *
42
+ * @remarks
43
+ * Carries the engine's message, as {@link ActionConfigError} does.
44
+ *
45
+ * @public
46
+ */
47
+ export declare class ActionRunError extends ActionRunError_base {}
48
+ declare const ActionInitError_base: Schema.Class<ActionInitError, Schema.TaggedStruct<"ActionInitError", {
49
+ readonly message: Schema.String;
50
+ }>, import("effect/Cause").YieldableError>;
51
+ /**
52
+ * `action init` could not start: the directory is not a package, the action's name or description was found nowhere
53
+ * or holds a control character, files it would write exist and `--force` was not given, or a path cannot be written
54
+ * over (a symbolic link, the wrong kind of entry), which `--force` never overrides. Exit `2`, and nothing was written.
55
+ *
56
+ * @remarks
57
+ * Carries the engine's message, as {@link ActionConfigError} does.
58
+ *
59
+ * @public
60
+ */
61
+ export declare class ActionInitError extends ActionInitError_base {}
62
+ /**
63
+ * What `effected action` is given by the process boundary. `main` reads `cwd` and `ci`, and nothing else reads the
64
+ * process.
65
+ *
66
+ * @public
67
+ */
68
+ type ActionCommandDeps = ActionRunDeps;
69
+ declare const BuildFailedError_base: Schema.Class<BuildFailedError, Schema.TaggedStruct<"BuildFailedError", {
70
+ /** How many errors the build recorded. */
71
+ readonly errors: Schema.Number;
72
+ /** What ended the build, when it did not reach its end. */
73
+ readonly failure: Schema.optionalKey<Schema.String>;
74
+ }>, import("effect/Cause").YieldableError>;
75
+ /**
76
+ * The build crashed or recorded an error. Exit `1`.
77
+ *
78
+ * @public
79
+ */
80
+ export declare class BuildFailedError extends BuildFailedError_base {
81
+ get message(): string;
82
+ }
83
+ declare const PackageConfigError_base: Schema.Class<PackageConfigError, Schema.TaggedStruct<"PackageConfigError", {
84
+ readonly message: Schema.String;
85
+ }>, import("effect/Cause").YieldableError>;
86
+ /**
87
+ * The build could not run: its `effected.toml` or a plugin would not load, the directory is not a package, or the
88
+ * bundler refused the config before any work. Exit `2`: exit `1` means it ran and found a problem.
89
+ *
90
+ * @remarks
91
+ * Carries the engine's message, which names the file at fault and the key within it. This command's own type rather
92
+ * than the bundler's, because the CLI reaches the bundler only through the engine.
93
+ *
94
+ * @public
95
+ */
96
+ export declare class PackageConfigError extends PackageConfigError_base {}
97
+ declare const PackageRunError_base: Schema.Class<PackageRunError, Schema.TaggedStruct<"PackageRunError", {
98
+ readonly message: Schema.String;
99
+ }>, import("effect/Cause").YieldableError>;
100
+ /**
101
+ * A file the build needs could not be read or written. Exit `3`, the infrastructure tier.
102
+ *
103
+ * @public
104
+ */
105
+ export declare class PackageRunError extends PackageRunError_base {}
106
+ /**
107
+ * What `effected package` is given by the process boundary, and the test seams: the engine's dependencies, less the
108
+ * progress callback. `main` reads `cwd` and `ci`, and nothing else reads the process.
109
+ *
110
+ * @public
111
+ */
112
+ type PackageCommandDeps = Omit<BuildRunDeps, "onProgress">;
5
113
  declare const DriftError_base: Schema.Class<DriftError, Schema.TaggedStruct<"DriftError", {
6
114
  readonly drifted: Schema.$Array<Schema.Struct<{
7
115
  readonly $id: Schema.String;
@@ -111,6 +219,12 @@ export declare class NoConfigError extends NoConfigError_base {
111
219
  * @public
112
220
  */
113
221
  type SchemaCommandDeps = Omit<SchemaRunDeps, "onProgress">;
222
+ /**
223
+ * What every command is given by the process boundary, and the test seams.
224
+ *
225
+ * @public
226
+ */
227
+ type CommandDeps = SchemaCommandDeps & PackageCommandDeps & ActionCommandDeps;
114
228
  /**
115
229
  * The `effected` command tree, closed over the process boundary it runs against: `main` hands in the process values, a
116
230
  * test its own. The audience flags are shared on the root so every subcommand accepts them.
@@ -126,5 +240,5 @@ export declare const makeRootCommand: any;
126
240
  * @public
127
241
  */
128
242
  export declare const CLI_VERSION: string;
129
- export type { SchemaCommandDeps };
243
+ export type { ActionCommandDeps, CommandDeps, PackageCommandDeps, SchemaCommandDeps };
130
244
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -1,5 +1,7 @@
1
+ import { ActionBuildFailedError, ActionConfigError, ActionInitError, ActionRunError } from "./commands/action/errors.js";
2
+ import { BuildFailedError, PackageConfigError, PackageRunError } from "./commands/package/errors.js";
1
3
  import { makeRootCommand } from "./commands/root.js";
2
4
  import { CatalogMergeError, DriftError, GateError, NoConfigError, StaleError, ValidationFailedError } from "./commands/schema/errors.js";
3
5
  import { CLI_VERSION } from "./version.js";
4
6
 
5
- export { CLI_VERSION, CatalogMergeError, DriftError, GateError, NoConfigError, StaleError, ValidationFailedError, makeRootCommand };
7
+ export { ActionBuildFailedError, ActionConfigError, ActionInitError, ActionRunError, BuildFailedError, CLI_VERSION, CatalogMergeError, DriftError, GateError, NoConfigError, PackageConfigError, PackageRunError, StaleError, ValidationFailedError, makeRootCommand };
package/main.d.ts CHANGED
@@ -1,7 +1,23 @@
1
1
  import { Distribution } from "@effected/kit";
2
2
  import { Layer } from "effect";
3
- import { SchemaRunDeps } from "@effected/engine/schema";
3
+ import "effect/cli";
4
+ import { ActionRunDeps, BuildRunDeps } from "@effected/engine/build";
4
5
  import "@effected/env";
6
+ import { SchemaRunDeps } from "@effected/engine/schema";
7
+ /**
8
+ * What `effected action` is given by the process boundary. `main` reads `cwd` and `ci`, and nothing else reads the
9
+ * process.
10
+ *
11
+ * @public
12
+ */
13
+ type ActionCommandDeps = ActionRunDeps;
14
+ /**
15
+ * What `effected package` is given by the process boundary, and the test seams: the engine's dependencies, less the
16
+ * progress callback. `main` reads `cwd` and `ci`, and nothing else reads the process.
17
+ *
18
+ * @public
19
+ */
20
+ type PackageCommandDeps = Omit<BuildRunDeps, "onProgress">;
5
21
  /**
6
22
  * What `effected schema` is given by the process boundary, and the test seams: the engine's dependencies, less the
7
23
  * progress callback the command supplies itself. `main` reads `cwd`, and nothing else reads the process.
@@ -9,6 +25,12 @@ import "@effected/env";
9
25
  * @public
10
26
  */
11
27
  type SchemaCommandDeps = Omit<SchemaRunDeps, "onProgress">;
28
+ /**
29
+ * What every command is given by the process boundary, and the test seams.
30
+ *
31
+ * @public
32
+ */
33
+ type CommandDeps = SchemaCommandDeps & PackageCommandDeps & ActionCommandDeps;
12
34
  /**
13
35
  * Options a carrier's bin shim passes to {@link main}. `distribution` names
14
36
  * the package the `effected` bin was installed through; omitted for a direct
@@ -39,7 +61,7 @@ export declare const mainOptions: {
39
61
  *
40
62
  * @public
41
63
  */
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>>;
64
+ export declare const run: <RP, EP>(options: MainOptions, deps: CommandDeps, 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
65
  /**
44
66
  * Run the `effected` command. Owns the process: installs the runtime teardown
45
67
  * and sets the exit code.
@@ -47,5 +69,5 @@ export declare const run: <RP, EP>(options: MainOptions, deps: SchemaCommandDeps
47
69
  * @public
48
70
  */
49
71
  export declare const main: (options?: MainOptions) => void;
50
- export type { SchemaCommandDeps };
72
+ export type { ActionCommandDeps, CommandDeps, PackageCommandDeps, SchemaCommandDeps };
51
73
  //# sourceMappingURL=main.d.ts.map
package/main.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { isCI } from "./ci.js";
1
2
  import { makeRootCommand } from "./commands/root.js";
2
3
  import { CLI_VERSION } from "./version.js";
3
4
  import { CliAudience, CliLogger, CliRuntime } from "@effected/cli-kit";
@@ -55,7 +56,10 @@ const run = (options, deps, platform) => CliRuntime.main(CliAudience.run(makeRoo
55
56
  * @public
56
57
  */
57
58
  const main = (options = {}) => {
58
- NodeRuntime.runMain(run(options, { cwd: process.cwd() }, NodeServices.layer));
59
+ NodeRuntime.runMain(run(options, {
60
+ cwd: process.cwd(),
61
+ ci: isCI(process.env)
62
+ }, NodeServices.layer));
59
63
  };
60
64
 
61
65
  export { main, mainOptions, run };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effected/cli",
3
- "version": "0.27.0",
3
+ "version": "0.29.0",
4
4
  "private": false,
5
5
  "description": "The effected command: the tool's command tree on the kit's front-end runtime",
6
6
  "keywords": [
@@ -43,16 +43,20 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@effect/platform-node": "~4.1.2",
46
- "@effected/cli-kit": "^0.27.0",
47
- "@effected/engine": "0.13.0",
46
+ "@effected/cli-kit": "^0.27.1",
47
+ "@effected/engine": "0.15.0",
48
48
  "@effected/env": "^0.11.0",
49
- "@effected/glob": "^0.19.0",
49
+ "@effected/glob": "^0.20.0",
50
50
  "@effected/kit": "^0.13.0",
51
- "@effected/walker": "^0.25.1",
51
+ "@effected/walker": "^0.26.0",
52
52
  "effect": "~4.1.2",
53
53
  "ink": "^8.0.0",
54
54
  "react": "^19.3.0"
55
55
  },
56
+ "peerDependencies": {
57
+ "@types/node": "^26.6.0",
58
+ "typescript": "7.1.0-beta || 7.1.1-rc || >=7.1.0 <8"
59
+ },
56
60
  "engines": {
57
61
  "node": ">=24.11.0"
58
62
  }
@@ -0,0 +1,66 @@
1
+ import { Doc } from "@effected/cli-kit";
2
+
3
+ // src/render/ActionDoc.ts
4
+ const formatBytes = (bytes) => {
5
+ if (bytes < 1024) return `${bytes} B`;
6
+ return bytes < 1048576 ? `${(bytes / 1024).toFixed(1)} KB` : `${(bytes / 1048576).toFixed(1)} MB`;
7
+ };
8
+ const issueLine = (issue) => `${issue.code}: ${issue.message}`;
9
+ /** One line for an entry, with only the first line of its error: a failed load's message can carry a require stack. */
10
+ const entryLine = (entry) => {
11
+ if (entry.stats === void 0) return `✗ ${(entry.error ?? "failed").split("\n")[0]}`;
12
+ const { entry: name, size, duration, outputPath } = entry.stats;
13
+ return `✓ ${name}: ${formatBytes(size)} (${duration}ms) → ${outputPath}`;
14
+ };
15
+ const summaryOf = ({ build }) => `built ${build.entries.filter((entry) => entry.success).length} entries in ${build.duration}ms`;
16
+ /** A warning as its first line, indented under the entry it belongs to. */
17
+ const warningLines = (entry) => (entry.warnings ?? []).map((warning) => ` ${warning.trim().split("\n")[0]}`);
18
+ /**
19
+ * An action build for a reader: validation's errors, its warnings, a line per entry, then the total.
20
+ *
21
+ * @public
22
+ */
23
+ var ActionDoc = class ActionDoc {
24
+ constructor() {}
25
+ /** The report as plain lines, the total last, for a log. */
26
+ static lines(result) {
27
+ return [
28
+ ...result.validation.errors.map(issueLine),
29
+ ...result.validation.warnings.map(issueLine),
30
+ ...result.build.entries.flatMap((entry) => [entryLine(entry), ...warningLines(entry)]),
31
+ summaryOf(result)
32
+ ];
33
+ }
34
+ /**
35
+ * The report as a `Doc`.
36
+ *
37
+ * @remarks
38
+ * Every line goes in as a `Doc.text` run, which is data: the renderers remove escape and control characters from it,
39
+ * so an error quoting untrusted text cannot repaint the terminal.
40
+ */
41
+ static render(result) {
42
+ const rows = [
43
+ ...result.validation.errors.map((issue) => Doc.text(issueLine(issue), "error")),
44
+ ...result.validation.warnings.map((issue) => Doc.text(issueLine(issue), "warning")),
45
+ ...result.build.entries.flatMap((entry) => [Doc.text(entryLine(entry), entry.success ? "success" : "error"), ...warningLines(entry).map((line) => Doc.text(line, "warning"))]),
46
+ Doc.text(summaryOf(result), result.build.success ? "success" : "error")
47
+ ];
48
+ return Doc.lines(rows, { wrap: false });
49
+ }
50
+ /** The report for a GitHub step summary, in a code block. */
51
+ static markdown(result) {
52
+ const body = ActionDoc.lines(result).join("\n");
53
+ const longest = (body.match(/`+/g) ?? []).reduce((length, run) => Math.max(length, run.length), 2);
54
+ const fence = "`".repeat(longest + 1);
55
+ return [
56
+ "### effected action build",
57
+ "",
58
+ fence,
59
+ body,
60
+ fence,
61
+ ""
62
+ ].join("\n");
63
+ }
64
+ };
65
+
66
+ export { ActionDoc };
@@ -0,0 +1,35 @@
1
+ import { Doc } from "@effected/cli-kit";
2
+
3
+ // src/render/InitDoc.ts
4
+ /** What is left to do, as lines: the packages to add, the module type, and the build. */
5
+ const nextSteps = (result) => [
6
+ ...result.missingDependencies.length > 0 ? [`add dependencies: ${result.missingDependencies.join(" ")}`] : [],
7
+ ...result.missingDevDependencies.length > 0 ? [`add devDependencies: ${result.missingDevDependencies.join(" ")}`] : [],
8
+ ...result.typeModule ? [] : ["set \"type\": \"module\" in package.json"],
9
+ "then run: effected action build"
10
+ ];
11
+ const fileLine = (result, file) => `${result.overwritten.includes(file) ? "replaced" : "wrote"} ${file}`;
12
+ /**
13
+ * An `action init` for a reader: a line per file written, then what is left to do.
14
+ *
15
+ * @public
16
+ */
17
+ var InitDoc = class {
18
+ constructor() {}
19
+ /** The report as plain lines, for a log. */
20
+ static lines(result) {
21
+ return [...result.written.map((file) => fileLine(result, file)), ...nextSteps(result)];
22
+ }
23
+ /**
24
+ * The report as a `Doc`.
25
+ *
26
+ * @remarks
27
+ * Every line goes in as a `Doc.text` run, which is data, so a name echoed back cannot repaint the terminal.
28
+ */
29
+ static render(result) {
30
+ const rows = [...result.written.map((file) => Doc.text(fileLine(result, file), result.overwritten.includes(file) ? "warning" : "success")), ...nextSteps(result).map((line) => Doc.text(line, "muted"))];
31
+ return Doc.lines(rows, { wrap: false });
32
+ }
33
+ };
34
+
35
+ export { InitDoc };
@@ -0,0 +1,73 @@
1
+ import { Doc } from "@effected/cli-kit";
2
+
3
+ // src/render/IssuesDoc.ts
4
+ /** `file:line:col code text`, leaving out whichever parts the diagnostic does not have. */
5
+ const lineOf = (diagnostic) => {
6
+ return [
7
+ ...diagnostic.file === void 0 ? [] : [[
8
+ diagnostic.file,
9
+ diagnostic.line,
10
+ diagnostic.column
11
+ ].filter((part) => part !== void 0).join(":")],
12
+ ...diagnostic.code !== void 0 ? [diagnostic.code] : [],
13
+ diagnostic.text
14
+ ].join(" ");
15
+ };
16
+ const summaryOf = (issues) => `built ${issues.package}: ${issues.errors.length} errors, ${issues.warnings.length} warnings, ${issues.suppressed.length} suppressed`;
17
+ const summaryToken = (issues) => !issues.buildOk || issues.errors.length > 0 ? "error" : issues.warnings.length > 0 ? "warning" : "success";
18
+ const fenceFor = (text) => {
19
+ const longest = (text.match(/`+/g) ?? []).reduce((length, run) => Math.max(length, run.length), 2);
20
+ return "`".repeat(longest + 1);
21
+ };
22
+ /**
23
+ * A build's `issues.json` for a reader: errors, then warnings, then one summary line. Suppressed diagnostics are only
24
+ * counted.
25
+ *
26
+ * @public
27
+ */
28
+ var IssuesDoc = class {
29
+ constructor() {}
30
+ /** The report as plain lines, the summary last, for a log. */
31
+ static lines(issues) {
32
+ return [
33
+ ...issues.errors.map(lineOf),
34
+ ...issues.warnings.map(lineOf),
35
+ summaryOf(issues)
36
+ ];
37
+ }
38
+ /**
39
+ * The report as a `Doc`.
40
+ *
41
+ * @remarks
42
+ * Every line goes in as a `Doc.text` run, which is data: the renderers remove escape and control characters from it,
43
+ * so a diagnostic quoting untrusted text cannot repaint the terminal.
44
+ */
45
+ static render(issues) {
46
+ const rows = [
47
+ ...issues.errors.map((diagnostic) => Doc.text(lineOf(diagnostic), "error")),
48
+ ...issues.warnings.map((diagnostic) => Doc.text(lineOf(diagnostic), "warning")),
49
+ Doc.text(summaryOf(issues), summaryToken(issues))
50
+ ];
51
+ return Doc.lines(rows, { wrap: false });
52
+ }
53
+ /** The report for a GitHub step summary: the failure, when there is one, and the diagnostics in a code block. */
54
+ static markdown(issues) {
55
+ const diagnostics = [...issues.errors, ...issues.warnings].map(lineOf).join("\n");
56
+ const fence = fenceFor(diagnostics);
57
+ return [
58
+ "### effected package build",
59
+ "",
60
+ summaryOf(issues),
61
+ ...issues.failure !== void 0 ? ["", `Failed: ${issues.failure.message}`] : [],
62
+ ...diagnostics !== "" ? [
63
+ "",
64
+ fence,
65
+ diagnostics,
66
+ fence
67
+ ] : [],
68
+ ""
69
+ ].join("\n");
70
+ }
71
+ };
72
+
73
+ export { IssuesDoc };
package/version.js CHANGED
@@ -6,6 +6,6 @@
6
6
  *
7
7
  * @public
8
8
  */
9
- const CLI_VERSION = "0.27.0";
9
+ const CLI_VERSION = "0.29.0";
10
10
 
11
11
  export { CLI_VERSION };