@savvy-web/cli 2.1.8 → 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 +27 -10
- package/commands/commit/check.js +26 -23
- package/commands/commit/init.js +8 -4
- package/commands/lint/check.js +25 -20
- package/commands/lint/init.js +4 -3
- package/index.d.ts +18 -10
- package/package.json +5 -3
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 {
|
|
11
|
-
import {
|
|
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`, `
|
|
41
|
-
* `
|
|
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.
|
|
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
|
|
90
|
-
* `BiomeSchemaSync`, `ConfigDiscovery`, `SilkPublishabilityDetector`)
|
|
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,
|
|
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
|
-
|
|
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
|
*
|
package/commands/commit/check.js
CHANGED
|
@@ -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 {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
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
|
|
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
|
|
79
|
-
const
|
|
80
|
-
const
|
|
81
|
-
|
|
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.
|
|
108
|
-
if (
|
|
109
|
-
else if (
|
|
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 (
|
|
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.
|
|
146
|
-
if (
|
|
147
|
-
else if (
|
|
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 {
|
package/commands/commit/init.js
CHANGED
|
@@ -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 {
|
|
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 =
|
|
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.
|
|
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.
|
|
94
|
+
yield* ms.sync(hookPath, SavvyHooksSection.section(savvyHooksHygiene()));
|
|
91
95
|
yield* makeExecutable(hookPath);
|
|
92
96
|
yield* Effect.log(`${"✓"} Synced ${hookPath}`);
|
|
93
97
|
}
|
package/commands/lint/check.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { BIOME_VERSION } from "./biome-version.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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.
|
|
160
|
-
if (
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
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 (
|
|
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.
|
|
204
|
-
const found =
|
|
205
|
-
const 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(
|
|
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(
|
|
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(
|
|
279
|
-
const tscAvailable = yield* td.isAvailable(
|
|
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`);
|
package/commands/lint/init.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BIOME_VERSION } from "./biome-version.js";
|
|
2
|
-
import {
|
|
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.
|
|
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.
|
|
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,
|
|
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`, `
|
|
35
|
-
* `
|
|
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").
|
|
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 |
|
|
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 |
|
|
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("@
|
|
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 |
|
|
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.
|
|
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/commands": "^0.1.0",
|
|
35
36
|
"@effected/git": "^0.5.0",
|
|
36
37
|
"@effected/jsonc": "^0.5.1",
|
|
37
|
-
"@effected/
|
|
38
|
+
"@effected/templates": "^0.1.0",
|
|
39
|
+
"@effected/workspaces": "^0.9.0",
|
|
38
40
|
"@effected/yaml": "^0.6.0",
|
|
39
|
-
"@savvy-web/silk-effects": "
|
|
41
|
+
"@savvy-web/silk-effects": "5.0.0",
|
|
40
42
|
"effect": "4.0.0-beta.101"
|
|
41
43
|
}
|
|
42
44
|
}
|