@savvy-web/cli 3.3.0 → 3.4.1

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/cli/index.js CHANGED
@@ -12,7 +12,7 @@ import { Git } from "@effected/git";
12
12
  import { PackageManagerDetector, WorkspaceDiscovery, WorkspaceRoot, Workspaces } from "@effected/workspaces";
13
13
  import { ManagedSection } from "@effected/templates";
14
14
  import { ToolDiscovery } from "@effected/commands";
15
- import { NodeServices } from "@effect/platform-node";
15
+ import * as NodeServices from "@effect/platform-node/NodeServices";
16
16
 
17
17
  //#region src/cli/index.ts
18
18
  /**
@@ -1,9 +1,8 @@
1
+ import { Cause } from "effect";
2
+
1
3
  //#region src/internal/failure-line.ts
2
- /**
3
- * How a failure that reaches `CliRuntime.main` reads on stderr.
4
- *
5
- * @packageDocumentation
6
- */
4
+ /** Where a defect report asks to be filed; mirrors `package.json#bugs.url`. */
5
+ const ISSUES_URL = "https://github.com/savvy-web/systems/issues";
7
6
  const HIDDEN = /* @__PURE__ */ new Set([
8
7
  "_tag",
9
8
  "message",
@@ -11,28 +10,50 @@ const HIDDEN = /* @__PURE__ */ new Set([
11
10
  "stack",
12
11
  "cause"
13
12
  ]);
13
+ /** A field value as text; never throws, since a bigint or circular field would make `JSON.stringify` hide the failure. */
14
+ const field = (value) => {
15
+ if (typeof value === "string") return value;
16
+ try {
17
+ return JSON.stringify(value) ?? String(value);
18
+ } catch {
19
+ return String(value);
20
+ }
21
+ };
22
+ /** One line for a typed failure: its own message, else its tag with its fields, else `String`. */
23
+ const describe = (error) => {
24
+ if (error instanceof Error && error.message !== "") return error.message;
25
+ if (typeof error === "object" && error !== null && "_tag" in error) {
26
+ const fields = Object.entries(error).filter(([key]) => !HIDDEN.has(key)).map(([key, value]) => `${key}: ${field(value)}`);
27
+ const tag = String(error._tag);
28
+ return fields.length > 0 ? `${tag}: ${fields.join(", ")}` : tag;
29
+ }
30
+ return String(error);
31
+ };
14
32
  /**
15
33
  * Renders a failure for `CliRuntime.main`'s `render` option.
16
34
  *
17
35
  * @remarks
18
- * The kit's default is `String(error)`, which prints a `Data.TaggedError`
19
- * with no `message` as its bare tag and drops the fields that say what went
20
- * wrong (`CleanError`, with the `reason` lost). This prefers the error's own
21
- * message, then its tag with its fields, then `String`.
36
+ * The kit tells the renderer whether the squashed error is a typed failure
37
+ * or a defect, so nothing here guesses that from the error's shape.
38
+ *
39
+ * - A typed failure is an expected outcome and reads as one line. The kit's
40
+ * default is `String(error)`, which prints a `Data.TaggedError` with no
41
+ * `message` as its bare tag and drops the fields that say what went wrong
42
+ * (`CleanError`, with the `reason` lost), so this prefers the error's own
43
+ * message, then its tag with its fields, then `String`.
44
+ * - A defect — a `die`, a thrown exception — is a bug in savvy. It gets the
45
+ * issue-report treatment: a headline, the whole pretty-printed cause with
46
+ * its stack, and where to report it.
22
47
  *
23
48
  * @internal
24
49
  */
25
50
  var FailureLine = class {
26
51
  constructor() {}
27
- static render = (error) => {
28
- if (error instanceof Error && error.message !== "") return error.message;
29
- if (typeof error === "object" && error !== null && "_tag" in error) {
30
- const fields = Object.entries(error).filter(([key]) => !HIDDEN.has(key)).map(([key, value]) => `${key}: ${typeof value === "string" ? value : JSON.stringify(value)}`);
31
- const tag = String(error._tag);
32
- return fields.length > 0 ? `${tag}: ${fields.join(", ")}` : tag;
33
- }
34
- return String(error);
35
- };
52
+ static render = (error, details) => details.isDefect ? [
53
+ `savvy hit an unexpected error: ${describe(error)}`,
54
+ ...Cause.pretty(details.cause).split("\n"),
55
+ `This is a bug in savvy. Please report it with the output above at ${ISSUES_URL}`
56
+ ] : describe(error);
36
57
  };
37
58
 
38
59
  //#endregion
package/main.js CHANGED
@@ -5,7 +5,7 @@ import { CLI_VERSION } from "./version.js";
5
5
  import { Command } from "effect/unstable/cli";
6
6
  import { CliColor, CliRuntime } from "@effected/cli";
7
7
  import { Effect, Layer, Option } from "effect";
8
- import { NodeRuntime } from "@effect/platform-node";
8
+ import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
9
9
  import { CurrentDistribution } from "@effected/engine";
10
10
 
11
11
  //#region src/main.ts
@@ -18,8 +18,11 @@ import { CurrentDistribution } from "@effected/engine";
18
18
  * `AppLive` stack and the carrier-aware version formatter, and hands the
19
19
  * program to `@effected/cli`'s `CliRuntime.main`, which provides the platform
20
20
  * and the kit-default CLI logger (every log line on stderr), reports failures
21
- * through that logger, applies the `CliExit` code a command set, and exits
22
- * `64` on a usage error.
21
+ * through that logger (a typed failure as one line, a defect as a bug report),
22
+ * applies the `CliExit` code a command set, and exits `64` on a usage error
23
+ * with the help document on stderr, so stdout stays clean for a caller that
24
+ * parses it. The version formatter rides in `platform`, not `program`: help
25
+ * routing only sees a Formatter provided there.
23
26
  * No type casts: the layer graph is validated by the compiler.
24
27
  *
25
28
  * @packageDocumentation
@@ -33,10 +36,12 @@ import { CurrentDistribution } from "@effected/engine";
33
36
  const main = (options = {}) => {
34
37
  const distribution = Option.fromNullishOr(options.distribution);
35
38
  const VersionFormatterLive = CliColor.formatterLayer({ formatVersion: (name, version) => VersionLine.format(name, version, distribution) });
36
- const program = Command.run(rootCommand, { version: CLI_VERSION }).pipe(Effect.provide(Layer.merge(AppLive, VersionFormatterLive)), Effect.provideService(CurrentDistribution, distribution));
39
+ const program = Command.run(rootCommand, { version: CLI_VERSION }).pipe(Effect.provide(AppLive), Effect.provideService(CurrentDistribution, distribution));
40
+ const platform = VersionFormatterLive.pipe(Layer.provideMerge(CliPlatform));
37
41
  NodeRuntime.runMain(CliRuntime.main(program, {
38
- platform: CliPlatform,
39
- render: FailureLine.render
42
+ platform,
43
+ render: FailureLine.render,
44
+ helpOnUsageError: "stderr"
40
45
  }));
41
46
  };
42
47
  /* v8 ignore stop */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@savvy-web/cli",
3
- "version": "3.3.0",
3
+ "version": "3.4.1",
4
4
  "private": false,
5
5
  "description": "The savvy CLI — unified commit, changeset, and lint commands for the Silk Suite",
6
6
  "homepage": "https://github.com/savvy-web/systems/tree/main/packages/cli",
@@ -37,15 +37,15 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@effect/platform-node": "4.0.0-rc.117",
40
- "@effected/cli": "^0.8.0",
40
+ "@effected/cli": "^0.9.0",
41
41
  "@effected/commands": "^0.9.0",
42
42
  "@effected/engine": "^0.1.0",
43
43
  "@effected/git": "^0.17.0",
44
44
  "@effected/jsonc": "^0.13.0",
45
45
  "@effected/templates": "^0.8.0",
46
- "@effected/workspaces": "^0.26.0",
46
+ "@effected/workspaces": "^0.28.0",
47
47
  "@effected/yaml": "^0.17.0",
48
- "@savvy-web/silk-effects": "9.1.3",
48
+ "@savvy-web/silk-effects": "9.2.0",
49
49
  "effect": "4.0.0-rc.117"
50
50
  }
51
51
  }
package/version.js CHANGED
@@ -7,7 +7,7 @@
7
7
  * @packageDocumentation
8
8
  */
9
9
  /** @internal */
10
- const CLI_VERSION = "3.3.0";
10
+ const CLI_VERSION = "3.4.1";
11
11
 
12
12
  //#endregion
13
13
  export { CLI_VERSION };