@savvy-web/cli 2.1.7 → 2.1.9

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
@@ -6,9 +6,11 @@ import { initCommand } from "../commands/init.js";
6
6
  import { lintCommand } from "../commands/lint/index.js";
7
7
  import { reposCommand } from "../commands/repos/index.js";
8
8
  import { NodeRuntime, NodeServices } from "@effect/platform-node";
9
+ import { ToolDiscovery } from "@effected/commands";
9
10
  import { Git } from "@effected/git";
10
- import { PackageManagerDetector, WorkspaceDiscovery, WorkspaceRoot } from "@effected/workspaces";
11
- import { BiomeSchemaSyncLive, ChangesetConfigReaderLive, Changesets, ConfigDiscoveryLive, ManagedSectionLive, Repos, SilkPublishabilityDetectorLive, ToolDiscoveryLive, VersioningStrategyLive } from "@savvy-web/silk-effects";
11
+ import { ManagedSection } from "@effected/templates";
12
+ import { PackageManagerDetector, WorkspaceDiscovery, WorkspaceRoot, Workspaces } from "@effected/workspaces";
13
+ import { BiomeSchemaSyncLive, ChangesetConfigReaderLive, Changesets, ConfigDiscoveryLive, Repos, SilkPublishabilityDetectorLive } from "@savvy-web/silk-effects";
12
14
  import { Effect, Layer } from "effect";
13
15
  import { Command } from "effect/unstable/cli";
14
16
 
@@ -37,8 +39,14 @@ import { Command } from "effect/unstable/cli";
37
39
  * `WorkspaceRoot` from `process.cwd()` lazily on first use, so the CLI's
38
40
  * startup cwd is the discovery root).
39
41
  * - Flat silk-effects services — `ChangesetConfigReaderLive`,
40
- * `SilkPublishabilityDetectorLive`, `ManagedSectionLive`, `BiomeSchemaSyncLive`,
41
- * `ConfigDiscoveryLive`, `ToolDiscoveryLive`, and `VersioningStrategyLive`.
42
+ * `SilkPublishabilityDetectorLive`, `ManagedSection.layer` (from
43
+ * `@effected/templates`), `BiomeSchemaSyncLive`,
44
+ * and `ConfigDiscoveryLive`. Tool resolution is the kit's
45
+ * `ToolDiscovery.layer` over `ChildProcessSpawner` plus a `LocalExec`, which
46
+ * `Workspaces.localExecLayer()` supplies from the detected package manager.
47
+ * Versioning classification
48
+ * is a pure `@effected/workspaces` value operation over `WorkspaceDiscovery`
49
+ * and the silk `PublishabilityDetector`, so it needs no layer of its own.
42
50
  * - Changesets-namespace services — `Changesets.ConfigInspectorLive`,
43
51
  * `Changesets.ReleasePlannerLive`, and `Changesets.BranchAnalyzerLive`
44
52
  * sharing a single `ConfigInspector` via `provideMerge`. `DepsRegen` is NOT
@@ -68,7 +76,7 @@ const rootCommand = Command.make("savvy").pipe(Command.withSubcommands([
68
76
  * CLI application: reads argv from the Stdio service provided by NodeServices.
69
77
  * (v4's `Command.run` takes only `version` — the name comes from the root command.)
70
78
  */
71
- const cli = Command.run(rootCommand, { version: "2.1.7" });
79
+ const cli = Command.run(rootCommand, { version: "2.1.9" });
72
80
  /**
73
81
  * Shared workspace services from `@effected/workspaces`, wired as a
74
82
  * self-contained unit and built ONCE (layers memoize by reference).
@@ -86,13 +94,13 @@ const WorkspaceLive = Layer.mergeAll(WorkspaceRootLive, PackageManagerDetector.l
86
94
  */
87
95
  const GitLive = Git.layer;
88
96
  /**
89
- * Base layer membership: silk-effects leaf services (`ManagedSection`,
90
- * `BiomeSchemaSync`, `ConfigDiscovery`, `SilkPublishabilityDetector`) that
91
- * depend only on the platform, plus the changeset base layers
97
+ * Base layer membership: the kit's `ManagedSection` plus the silk-effects leaf
98
+ * services (`BiomeSchemaSync`, `ConfigDiscovery`, `SilkPublishabilityDetector`)
99
+ * that depend only on the platform, plus the changeset base layers
92
100
  * (`WorkspaceLive`, `ChangesetConfigReader`, `GitLive`) that `AppLive`'s
93
101
  * upper services build upon.
94
102
  */
95
- const BaseLive = Layer.mergeAll(WorkspaceLive, GitLive, ChangesetConfigReaderLive, ManagedSectionLive, BiomeSchemaSyncLive, ConfigDiscoveryLive, SilkPublishabilityDetectorLive);
103
+ const BaseLive = Layer.mergeAll(WorkspaceLive, GitLive, ChangesetConfigReaderLive, ManagedSection.layer, BiomeSchemaSyncLive, ConfigDiscoveryLive, SilkPublishabilityDetectorLive);
96
104
  /**
97
105
  * `ConfigInspectorLive` is built once via {@link Layer.provideMerge}: the merge
98
106
  * feeds that single `ConfigInspector` instance into `ReleasePlannerLive` and
@@ -108,7 +116,16 @@ const InspectorAndAnalyzerLive = Changesets.BranchAnalyzerLive.pipe(Layer.provid
108
116
  * flow up to `NodeServices.layer`.
109
117
  */
110
118
  const ReposGroupLive = Repos.ReposManagerLive.pipe(Layer.provide(Repos.ReposConfigStoreLive), Layer.provide(GitLive));
111
- const AppLive = Layer.mergeAll(ToolDiscoveryLive, VersioningStrategyLive, InspectorAndAnalyzerLive, ReposGroupLive).pipe(Layer.provideMerge(BaseLive), Layer.provideMerge(NodeServices.layer));
119
+ /**
120
+ * `ToolDiscovery` from `@effected/commands`, wired to this workspace. Its
121
+ * `LocalExec` contract — the argv prefix that runs a project-local binary — is
122
+ * implemented by `Workspaces.localExecLayer()`, which reads the detected package
123
+ * manager and the resolved workspace root. Both are already in `WorkspaceLive`,
124
+ * and the layer is bound to a `const` so the single reference memoizes.
125
+ */
126
+ const LocalExecLive = Workspaces.localExecLayer();
127
+ const ToolDiscoveryGroupLive = ToolDiscovery.layer.pipe(Layer.provide(LocalExecLive), Layer.provide(WorkspaceLive));
128
+ const AppLive = Layer.mergeAll(ToolDiscoveryGroupLive, InspectorAndAnalyzerLive, ReposGroupLive).pipe(Layer.provideMerge(BaseLive), Layer.provideMerge(NodeServices.layer));
112
129
  /**
113
130
  * Bootstrap and run the `savvy` CLI application.
114
131
  *
@@ -1,15 +1,11 @@
1
1
  import { HUSKY_HOOK_PATH, POST_CHECKOUT_HOOK_PATH, POST_COMMIT_HOOK_PATH, POST_MERGE_HOOK_PATH } from "./constants.js";
2
2
  import { SECTION_DEF, savvyCommitBlock } from "./init.js";
3
- import { WorkspaceDiscovery } from "@effected/workspaces";
4
- import { CheckResult, Commitlint, ManagedSection, SavvyBaseSection, SavvyHooksSection, VersioningStrategy, savvyBasePreamble, savvyHooksHygiene } from "@savvy-web/silk-effects";
5
- import { Effect, FileSystem } from "effect";
3
+ import { CheckOutcome, ManagedSection } from "@effected/templates";
4
+ import { VersioningStrategy } from "@effected/workspaces";
5
+ import { ChangesetConfigReader, Commitlint, SavvyBaseSection, SavvyHooksSection, savvyBasePreamble, savvyHooksHygiene } from "@savvy-web/silk-effects";
6
+ import { Effect, FileSystem, Option } from "effect";
6
7
 
7
8
  //#region src/commands/commit/check.ts
8
- /**
9
- * Check command - validate current commitlint setup.
10
- *
11
- * @internal
12
- */
13
9
  /** Unicode cross symbol. */
14
10
  const CROSS_MARK = "✗";
15
11
  /** Unicode bullet symbol. */
@@ -70,16 +66,23 @@ function extractConfigPathFromManaged(managedContent) {
70
66
  return match ? match[1] : null;
71
67
  }
72
68
  /**
73
- * Detect the release format using silk-effects versioning service.
69
+ * Detect the release format from the workspace's versioning strategy.
70
+ *
71
+ * @remarks
72
+ * `VersioningStrategy.detect` (from `@effected/workspaces`) enumerates the
73
+ * workspace and asks the ambient `PublishabilityDetector` which packages
74
+ * publish — the CLI provides silk's own detector, so the "private plus
75
+ * publishConfig.access is publishable" convention is applied by that layer
76
+ * rather than by a filter written here. Fixed groups are a changesets concept,
77
+ * so they are read from the changeset config and handed in as a plain argument.
74
78
  *
75
79
  * @returns Effect yielding the release format string
76
80
  */
77
81
  const detectReleaseFormat = Effect.gen(function* () {
78
- const versioning = yield* VersioningStrategy;
79
- const discovery = yield* WorkspaceDiscovery;
80
- const publishableNames = (yield* Effect.catch(discovery.listPackages(), () => Effect.succeed([]))).filter((pkg) => !pkg.private || pkg.publishConfig?.access !== void 0).map((pkg) => pkg.name);
81
- const result = yield* Effect.catch(versioning.detect(publishableNames, process.cwd()), () => Effect.succeed({ type: "single" }));
82
- return STRATEGY_TO_FORMAT[result.type] ?? "semver";
82
+ const configReader = yield* ChangesetConfigReader;
83
+ const fixedGroups = (yield* Effect.catch(configReader.read(process.cwd()), () => Effect.succeed(null)))?.fixed ?? [];
84
+ const strategy = yield* Effect.catch(VersioningStrategy.detect({ fixedGroups }), () => Effect.succeed(VersioningStrategy.classify({ packages: [] })));
85
+ return STRATEGY_TO_FORMAT[strategy.type] ?? "semver";
83
86
  });
84
87
  /**
85
88
  * Run the check validation pipeline.
@@ -104,9 +107,9 @@ function runCommitCheck() {
104
107
  else yield* Effect.log(`${CROSS_MARK} No husky commit-msg hook found`);
105
108
  let sectionsHealthy = true;
106
109
  if (hasHuskyHook) {
107
- const baseStatus = yield* ms.check(HUSKY_HOOK_PATH, SavvyBaseSection.block(savvyBasePreamble()));
108
- if (CheckResult.$is("Found")(baseStatus) && baseStatus.isUpToDate) yield* Effect.log(`${"✓"} Base section: up-to-date`);
109
- else if (CheckResult.$is("Found")(baseStatus)) {
110
+ const baseStatus = yield* ms.check(HUSKY_HOOK_PATH, SavvyBaseSection.section(savvyBasePreamble()));
111
+ if (CheckOutcome.$is("UpToDate")(baseStatus)) yield* Effect.log(`${"✓"} Base section: up-to-date`);
112
+ else if (CheckOutcome.$is("Drifted")(baseStatus)) {
110
113
  sectionsHealthy = false;
111
114
  yield* Effect.log(`${"⚠"} Base section: outdated (run 'savvy init' to update)`);
112
115
  } else {
@@ -114,11 +117,11 @@ function runCommitCheck() {
114
117
  yield* Effect.log(`${BULLET} Base section: not found (run 'savvy init' to add)`);
115
118
  }
116
119
  const block = yield* ms.read(HUSKY_HOOK_PATH, SECTION_DEF);
117
- if (block) {
118
- const configPath = extractConfigPathFromManaged(block.content);
120
+ if (Option.isSome(block)) {
121
+ const configPath = extractConfigPathFromManaged(block.value.content);
119
122
  if (configPath) {
120
123
  const status = yield* ms.check(HUSKY_HOOK_PATH, savvyCommitBlock(configPath));
121
- if (CheckResult.$is("Found")(status) && status.isUpToDate) yield* Effect.log(`${"✓"} Commit section: up-to-date`);
124
+ if (CheckOutcome.$is("UpToDate")(status)) yield* Effect.log(`${"✓"} Commit section: up-to-date`);
122
125
  else {
123
126
  sectionsHealthy = false;
124
127
  yield* Effect.log(`${"⚠"} Commit section: outdated (run 'savvy init' to update)`);
@@ -142,9 +145,9 @@ function runCommitCheck() {
142
145
  yield* Effect.log(`${BULLET} Hygiene hook: ${hookPath} not found (run 'savvy init' to add)`);
143
146
  continue;
144
147
  }
145
- const hygieneStatus = yield* ms.check(hookPath, SavvyHooksSection.block(savvyHooksHygiene()));
146
- if (CheckResult.$is("Found")(hygieneStatus) && hygieneStatus.isUpToDate) yield* Effect.log(`${"✓"} Hygiene hook: ${hookPath}`);
147
- else if (CheckResult.$is("Found")(hygieneStatus)) {
148
+ const hygieneStatus = yield* ms.check(hookPath, SavvyHooksSection.section(savvyHooksHygiene()));
149
+ if (CheckOutcome.$is("UpToDate")(hygieneStatus)) yield* Effect.log(`${"✓"} Hygiene hook: ${hookPath}`);
150
+ else if (CheckOutcome.$is("Drifted")(hygieneStatus)) {
148
151
  sectionsHealthy = false;
149
152
  yield* Effect.log(`${"⚠"} Hygiene hook: ${hookPath} outdated (run 'savvy init' to update)`);
150
153
  } else {
@@ -1,5 +1,6 @@
1
1
  import { HUSKY_HOOK_PATH, POST_CHECKOUT_HOOK_PATH, POST_COMMIT_HOOK_PATH, POST_MERGE_HOOK_PATH } from "./constants.js";
2
- import { ManagedSection, SavvyBaseSection, SavvyHooksSection, SectionDefinition, savvyBasePreamble, savvyHooksHygiene, savvyToolSection } from "@savvy-web/silk-effects";
2
+ import { CommentStyle, ManagedSection, SectionId } from "@effected/templates";
3
+ import { SavvyBaseSection, SavvyHooksSection, savvyBasePreamble, savvyHooksHygiene, savvyToolSection } from "@savvy-web/silk-effects";
3
4
  import { Effect, FileSystem } from "effect";
4
5
  import { dirname } from "node:path";
5
6
  import { chmod } from "node:fs/promises";
@@ -13,7 +14,10 @@ import { chmod } from "node:fs/promises";
13
14
  /** Executable file permission mode. */
14
15
  const EXECUTABLE_MODE = 493;
15
16
  /** Section definition for the savvy-commit tool section (identity for read/check/remove). */
16
- const SECTION_DEF = SectionDefinition.make({ toolName: "savvy-commit" });
17
+ const SECTION_DEF = SectionId.make({
18
+ key: "SAVVY-COMMIT",
19
+ commentStyle: CommentStyle.hash
20
+ });
17
21
  /** Header written when creating a fresh commit-msg hook. */
18
22
  const COMMIT_MSG_HEADER = "#!/usr/bin/env sh\n# Commit-msg hook with savvy managed sections\n# Custom hooks can go above, below, or between the managed sections\n\n";
19
23
  /** Header written when creating a fresh hygiene hook (post-checkout / post-merge / post-commit). */
@@ -78,7 +82,7 @@ function runCommitInit(opts) {
78
82
  yield* fs.makeDirectory(".husky", { recursive: true });
79
83
  if (force) yield* fs.writeFileString(HUSKY_HOOK_PATH, COMMIT_MSG_HEADER);
80
84
  else yield* ensureHookFile(HUSKY_HOOK_PATH, COMMIT_MSG_HEADER);
81
- const commitResults = yield* ms.syncMany(HUSKY_HOOK_PATH, [SavvyBaseSection.block(savvyBasePreamble()), savvyCommitBlock(config)]);
85
+ const commitResults = yield* ms.syncAll(HUSKY_HOOK_PATH, [SavvyBaseSection.section(savvyBasePreamble()), savvyCommitBlock(config)]);
82
86
  yield* makeExecutable(HUSKY_HOOK_PATH);
83
87
  yield* Effect.log(`${"✓"} ${force ? "Replaced" : "Synced"} ${HUSKY_HOOK_PATH} (${commitResults.map((r) => r._tag).join(", ")})`);
84
88
  for (const hookPath of [
@@ -87,7 +91,7 @@ function runCommitInit(opts) {
87
91
  POST_COMMIT_HOOK_PATH
88
92
  ]) {
89
93
  yield* ensureHookFile(hookPath, HYGIENE_HEADER);
90
- yield* ms.sync(hookPath, SavvyHooksSection.block(savvyHooksHygiene()));
94
+ yield* ms.sync(hookPath, SavvyHooksSection.section(savvyHooksHygiene()));
91
95
  yield* makeExecutable(hookPath);
92
96
  yield* Effect.log(`${"✓"} Synced ${hookPath}`);
93
97
  }
@@ -1,6 +1,8 @@
1
1
  import { BIOME_VERSION } from "./biome-version.js";
2
- import { CheckResult, ConfigDiscovery, Lint, ManagedSection, SavvyBaseSection, SavvyHooksSection, ToolDefinition, ToolDiscovery, savvyBasePreamble, savvyHooksHygiene } from "@savvy-web/silk-effects";
3
- import { Effect, FileSystem } from "effect";
2
+ import { Tool, ToolDiscovery } from "@effected/commands";
3
+ import { CheckOutcome, ManagedSection } from "@effected/templates";
4
+ import { ConfigDiscovery, Lint, SavvyBaseSection, SavvyHooksSection, savvyBasePreamble, savvyHooksHygiene } from "@savvy-web/silk-effects";
5
+ import { Effect, FileSystem, Option } from "effect";
4
6
  import { Jsonc } from "@effected/jsonc";
5
7
  import { isDeepStrictEqual } from "node:util";
6
8
 
@@ -156,23 +158,26 @@ function runLintCheck(opts) {
156
158
  let lintStatusLabel = "missing";
157
159
  let detectedConfigPath = null;
158
160
  if (hasHuskyHook) {
159
- const baseResult = yield* ms.check(Lint.HUSKY_HOOK_PATH, SavvyBaseSection.block(savvyBasePreamble()));
160
- if (CheckResult.$is("Found")(baseResult)) {
161
- baseStatusLabel = baseResult.isUpToDate ? "up-to-date" : "outdated";
162
- if (!baseResult.isUpToDate) sectionsHealthy = false;
163
- } else sectionsHealthy = false;
161
+ const baseResult = yield* ms.check(Lint.HUSKY_HOOK_PATH, SavvyBaseSection.section(savvyBasePreamble()));
162
+ if (CheckOutcome.$is("Absent")(baseResult)) sectionsHealthy = false;
163
+ else {
164
+ const upToDate = CheckOutcome.$is("UpToDate")(baseResult);
165
+ baseStatusLabel = upToDate ? "up-to-date" : "outdated";
166
+ if (!upToDate) sectionsHealthy = false;
167
+ }
164
168
  const existing = yield* ms.read(Lint.HUSKY_HOOK_PATH, Lint.SavvyLintSectionDef);
165
- if (existing) {
166
- const configPath = extractConfigPathFromManaged(existing.content);
169
+ if (Option.isSome(existing)) {
170
+ const configPath = extractConfigPathFromManaged(existing.value.content);
167
171
  detectedConfigPath = configPath;
168
172
  if (configPath) {
169
173
  const lintResult = yield* ms.check(Lint.HUSKY_HOOK_PATH, Lint.savvyLintBlock(configPath));
170
- if (CheckResult.$is("Found")(lintResult)) {
171
- lintStatusLabel = lintResult.isUpToDate ? "up-to-date" : "outdated";
172
- if (!lintResult.isUpToDate) sectionsHealthy = false;
173
- } else {
174
+ if (CheckOutcome.$is("Absent")(lintResult)) {
174
175
  lintStatusLabel = "outdated";
175
176
  sectionsHealthy = false;
177
+ } else {
178
+ const upToDate = CheckOutcome.$is("UpToDate")(lintResult);
179
+ lintStatusLabel = upToDate ? "up-to-date" : "outdated";
180
+ if (!upToDate) sectionsHealthy = false;
176
181
  }
177
182
  } else {
178
183
  lintStatusLabel = "outdated";
@@ -200,9 +205,9 @@ function runLintCheck(opts) {
200
205
  });
201
206
  continue;
202
207
  }
203
- const hygieneResult = yield* ms.check(hookPath, SavvyHooksSection.block(savvyHooksHygiene()));
204
- const found = CheckResult.$is("Found")(hygieneResult);
205
- const isUpToDate = CheckResult.$is("Found")(hygieneResult) && hygieneResult.isUpToDate;
208
+ const hygieneResult = yield* ms.check(hookPath, SavvyHooksSection.section(savvyHooksHygiene()));
209
+ const found = !CheckOutcome.$is("Absent")(hygieneResult);
210
+ const isUpToDate = CheckOutcome.$is("UpToDate")(hygieneResult);
206
211
  shellHookStatuses.push({
207
212
  path: hookPath,
208
213
  found,
@@ -255,13 +260,13 @@ function runLintCheck(opts) {
255
260
  else if (status.isUpToDate) yield* Effect.log(`${CHECK_MARK} ${status.path}: up-to-date`);
256
261
  else yield* Effect.log(`${WARNING} ${status.path}: outdated (run 'savvy init' to update)`);
257
262
  yield* Effect.log("\nTool availability:");
258
- const biomeAvailable = yield* td.isAvailable(ToolDefinition.make({ name: "biome" }));
263
+ const biomeAvailable = yield* td.isAvailable(Tool.named("biome"));
259
264
  const biomeConfig = yield* findConfig(discovery, ["biome.jsonc", "biome.json"]);
260
265
  if (biomeAvailable) {
261
266
  const configInfo = biomeConfig ? ` (config: ${biomeConfig})` : "";
262
267
  yield* Effect.log(` ${CHECK_MARK} Biome${configInfo}`);
263
268
  } else yield* Effect.log(` ${BULLET} Biome: not installed`);
264
- const markdownAvailable = yield* td.isAvailable(ToolDefinition.make({ name: "markdownlint-cli2" }));
269
+ const markdownAvailable = yield* td.isAvailable(Tool.named("markdownlint-cli2"));
265
270
  const markdownConfig = yield* findConfig(discovery, [
266
271
  ".markdownlint-cli2.jsonc",
267
272
  ".markdownlint-cli2.json",
@@ -275,8 +280,8 @@ function runLintCheck(opts) {
275
280
  const configInfo = markdownConfig ? ` (config: ${markdownConfig})` : "";
276
281
  yield* Effect.log(` ${CHECK_MARK} markdownlint-cli2${configInfo}`);
277
282
  } else yield* Effect.log(` ${BULLET} markdownlint-cli2: not installed`);
278
- const tsgoAvailable = yield* td.isAvailable(ToolDefinition.make({ name: "tsgo" }));
279
- const tscAvailable = yield* td.isAvailable(ToolDefinition.make({ name: "tsc" }));
283
+ const tsgoAvailable = yield* td.isAvailable(Tool.named("tsgo"));
284
+ const tscAvailable = yield* td.isAvailable(Tool.named("tsc"));
280
285
  if (tsgoAvailable) yield* Effect.log(` ${CHECK_MARK} TypeScript (tsgo)`);
281
286
  else if (tscAvailable) yield* Effect.log(` ${CHECK_MARK} TypeScript (tsc)`);
282
287
  else yield* Effect.log(` ${BULLET} TypeScript: not installed`);
@@ -1,5 +1,6 @@
1
1
  import { BIOME_VERSION } from "./biome-version.js";
2
- import { BiomeSchemaSync, Lint, ManagedSection, SavvyBaseSection, SavvyHooksSection, savvyBasePreamble, savvyHooksHygiene } from "@savvy-web/silk-effects";
2
+ import { ManagedSection } from "@effected/templates";
3
+ import { BiomeSchemaSync, Lint, SavvyBaseSection, SavvyHooksSection, savvyBasePreamble, savvyHooksHygiene } from "@savvy-web/silk-effects";
3
4
  import { Effect, FileSystem } from "effect";
4
5
  import { dirname } from "node:path";
5
6
  import { Jsonc, JsoncEdit, JsoncModifier } from "@effected/jsonc";
@@ -161,7 +162,7 @@ function runLintInit(opts) {
161
162
  yield* fs.makeDirectory(".husky", { recursive: true });
162
163
  if (force) yield* fs.writeFileString(Lint.HUSKY_HOOK_PATH, PRE_COMMIT_HEADER);
163
164
  else yield* ensureHookFile(Lint.HUSKY_HOOK_PATH, PRE_COMMIT_HEADER);
164
- const preCommitResults = yield* ms.syncMany(Lint.HUSKY_HOOK_PATH, [SavvyBaseSection.block(savvyBasePreamble()), Lint.savvyLintBlock(config)]);
165
+ const preCommitResults = yield* ms.syncAll(Lint.HUSKY_HOOK_PATH, [SavvyBaseSection.section(savvyBasePreamble()), Lint.savvyLintBlock(config)]);
165
166
  yield* makeExecutable(Lint.HUSKY_HOOK_PATH);
166
167
  yield* Effect.log(`${CHECK_MARK} ${force ? "Replaced" : "Synced"} ${Lint.HUSKY_HOOK_PATH} (${preCommitResults.map((r) => r._tag).join(", ")})`);
167
168
  if (presetIncludesShellScripts(preset)) for (const hookPath of [
@@ -171,7 +172,7 @@ function runLintInit(opts) {
171
172
  ]) {
172
173
  yield* ensureHookFile(hookPath, HYGIENE_HEADER);
173
174
  yield* ms.remove(hookPath, Lint.LegacySavvyLintHygieneDef);
174
- yield* ms.sync(hookPath, SavvyHooksSection.block(savvyHooksHygiene()));
175
+ yield* ms.sync(hookPath, SavvyHooksSection.section(savvyHooksHygiene()));
175
176
  yield* makeExecutable(hookPath);
176
177
  yield* Effect.log(`${CHECK_MARK} Synced ${hookPath}`);
177
178
  }
package/index.d.ts CHANGED
@@ -1,10 +1,12 @@
1
- import { BiomeSchemaSync, Changesets, ConfigDiscovery, ManagedSection, Repos, SectionParseError, SectionWriteError, ToolDiscovery, VersioningStrategy } from "@savvy-web/silk-effects";
1
+ import { BiomeSchemaSync, ChangesetConfigReader, Changesets, ConfigDiscovery, Repos } from "@savvy-web/silk-effects";
2
2
  import { Cause, Effect, FileSystem, Path } from "effect";
3
3
  import { Command } from "effect/unstable/cli";
4
4
  import { ChildProcessSpawner } from "effect/unstable/process";
5
5
  import { Git } from "@effected/git";
6
- import { WorkspaceDiscovery, WorkspaceRoot } from "@effected/workspaces";
6
+ import { PublishabilityDetector, WorkspaceDiscovery, WorkspaceRoot } from "@effected/workspaces";
7
+ import { ManagedSection, SectionFileError, SectionParseError, SectionRenderError } from "@effected/templates";
7
8
  import { PlatformError } from "effect/PlatformError";
9
+ import { ToolDiscovery } from "@effected/commands";
8
10
  import { JsoncParseError } from "@effected/jsonc";
9
11
  //#region src/cli/index.d.ts
10
12
  /**
@@ -31,8 +33,14 @@ import { JsoncParseError } from "@effected/jsonc";
31
33
  * `WorkspaceRoot` from `process.cwd()` lazily on first use, so the CLI's
32
34
  * startup cwd is the discovery root).
33
35
  * - Flat silk-effects services — `ChangesetConfigReaderLive`,
34
- * `SilkPublishabilityDetectorLive`, `ManagedSectionLive`, `BiomeSchemaSyncLive`,
35
- * `ConfigDiscoveryLive`, `ToolDiscoveryLive`, and `VersioningStrategyLive`.
36
+ * `SilkPublishabilityDetectorLive`, `ManagedSection.layer` (from
37
+ * `@effected/templates`), `BiomeSchemaSyncLive`,
38
+ * and `ConfigDiscoveryLive`. Tool resolution is the kit's
39
+ * `ToolDiscovery.layer` over `ChildProcessSpawner` plus a `LocalExec`, which
40
+ * `Workspaces.localExecLayer()` supplies from the detected package manager.
41
+ * Versioning classification
42
+ * is a pure `@effected/workspaces` value operation over `WorkspaceDiscovery`
43
+ * and the silk `PublishabilityDetector`, so it needs no layer of its own.
36
44
  * - Changesets-namespace services — `Changesets.ConfigInspectorLive`,
37
45
  * `Changesets.ReleasePlannerLive`, and `Changesets.BranchAnalyzerLive`
38
46
  * sharing a single `ConfigInspector` via `provideMerge`. `DepsRegen` is NOT
@@ -139,7 +147,7 @@ declare function runCheck<EChangeset, RChangeset, ECommit, RCommit, ELint, RLint
139
147
  declare const checkCommand: Command.Command<"check", {
140
148
  readonly changesetDir: string;
141
149
  readonly quiet: boolean;
142
- }, {}, Error | import("@effected/jsonc").JsoncParseError | import("effect/PlatformError").PlatformError | import("@savvy-web/silk-effects").SectionParseError, import("@savvy-web/silk-effects").ConfigDiscovery | import("effect/FileSystem").FileSystem | import("@savvy-web/silk-effects").ManagedSection | import("@savvy-web/silk-effects").ToolDiscovery | import("@savvy-web/silk-effects").VersioningStrategy | import("@effected/workspaces").WorkspaceDiscovery>;
150
+ }, {}, Error | import("@effected/jsonc").JsoncParseError | import("effect/PlatformError").PlatformError | import("@effected/templates").SectionFileError | import("@effected/templates").SectionParseError, import("@savvy-web/silk-effects").ChangesetConfigReader | import("@savvy-web/silk-effects").ConfigDiscovery | import("effect/FileSystem").FileSystem | import("@effected/templates").ManagedSection | import("@effected/workspaces").PublishabilityDetector | import("@effected/commands").ToolDiscovery | import("@effected/workspaces").WorkspaceDiscovery>;
143
151
  //#endregion
144
152
  //#region src/commands/commit/check.d.ts
145
153
  /**
@@ -152,7 +160,7 @@ declare const checkCommand: Command.Command<"check", {
152
160
  *
153
161
  * @internal
154
162
  */
155
- declare function runCommitCheck(): Effect.Effect<void, SectionParseError | PlatformError, ManagedSection | FileSystem.FileSystem | VersioningStrategy | WorkspaceDiscovery>;
163
+ declare function runCommitCheck(): Effect.Effect<void, SectionParseError | SectionFileError | PlatformError, ManagedSection | FileSystem.FileSystem | ChangesetConfigReader | PublishabilityDetector | WorkspaceDiscovery>;
156
164
  //#endregion
157
165
  //#region src/commands/commit/init.d.ts
158
166
  /**
@@ -169,7 +177,7 @@ declare function runCommitCheck(): Effect.Effect<void, SectionParseError | Platf
169
177
  declare function runCommitInit(opts: {
170
178
  force: boolean;
171
179
  config: string;
172
- }): Effect.Effect<void, Error | SectionWriteError | PlatformError, ManagedSection | FileSystem.FileSystem>;
180
+ }): Effect.Effect<void, Error | SectionParseError | SectionRenderError | SectionFileError | PlatformError, ManagedSection | FileSystem.FileSystem>;
173
181
  //#endregion
174
182
  //#region src/commands/commit/index.d.ts
175
183
  /**
@@ -211,7 +219,7 @@ declare const initCommand: Command.Command<"init", {
211
219
  readonly commitConfig: string;
212
220
  readonly lintConfig: string;
213
221
  readonly lintPreset: "minimal" | "silk" | "standard";
214
- }, {}, Error | import("effect/PlatformError").PlatformError | import("@savvy-web/silk-effects").SectionWriteError, import("@savvy-web/silk-effects").BiomeSchemaSync | import("effect/FileSystem").FileSystem | import("@effected/git").Git | import("@savvy-web/silk-effects").ManagedSection | import("@effected/workspaces").WorkspaceRoot>;
222
+ }, {}, Error | import("effect/PlatformError").PlatformError | import("@effected/templates").SectionFileError | import("@effected/templates").SectionParseError | import("@effected/templates").SectionRenderError, import("@savvy-web/silk-effects").BiomeSchemaSync | import("effect/FileSystem").FileSystem | import("@effected/git").Git | import("@effected/templates").ManagedSection | import("@effected/workspaces").WorkspaceRoot>;
215
223
  //#endregion
216
224
  //#region src/commands/lint/check.d.ts
217
225
  /**
@@ -227,7 +235,7 @@ declare const initCommand: Command.Command<"init", {
227
235
  */
228
236
  declare function runLintCheck(opts: {
229
237
  quiet: boolean;
230
- }): Effect.Effect<void, JsoncParseError | SectionParseError | PlatformError, ManagedSection | FileSystem.FileSystem | ToolDiscovery | ConfigDiscovery>;
238
+ }): Effect.Effect<void, JsoncParseError | SectionParseError | SectionFileError | PlatformError, ManagedSection | FileSystem.FileSystem | ToolDiscovery | ConfigDiscovery>;
231
239
  //#endregion
232
240
  //#region src/commands/lint/init.d.ts
233
241
  /**
@@ -245,7 +253,7 @@ declare function runLintInit(opts: {
245
253
  force: boolean;
246
254
  config: string;
247
255
  preset: "minimal" | "standard" | "silk";
248
- }): Effect.Effect<void, Error | SectionWriteError | PlatformError, ManagedSection | FileSystem.FileSystem | BiomeSchemaSync>;
256
+ }): Effect.Effect<void, Error | SectionParseError | SectionRenderError | SectionFileError | PlatformError, ManagedSection | FileSystem.FileSystem | BiomeSchemaSync>;
249
257
  //#endregion
250
258
  //#region src/commands/lint/index.d.ts
251
259
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@savvy-web/cli",
3
- "version": "2.1.7",
3
+ "version": "2.1.9",
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",
@@ -32,11 +32,13 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@effect/platform-node": "4.0.0-beta.101",
35
- "@effected/git": "^0.4.2",
35
+ "@effected/commands": "^0.1.0",
36
+ "@effected/git": "^0.5.0",
36
37
  "@effected/jsonc": "^0.5.1",
37
- "@effected/workspaces": "^0.7.0",
38
- "@effected/yaml": "^0.5.1",
39
- "@savvy-web/silk-effects": "4.2.5",
38
+ "@effected/templates": "^0.1.0",
39
+ "@effected/workspaces": "^0.9.0",
40
+ "@effected/yaml": "^0.6.0",
41
+ "@savvy-web/silk-effects": "5.0.0",
40
42
  "effect": "4.0.0-beta.101"
41
43
  }
42
44
  }