@savvy-web/silk-effects 0.6.1 → 1.0.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.
Files changed (155) hide show
  1. package/README.md +48 -17
  2. package/_virtual/_rolldown/runtime.js +18 -0
  3. package/changesets/api/categories.js +247 -0
  4. package/changesets/api/changelog.js +134 -0
  5. package/changesets/api/dependency-table.js +163 -0
  6. package/changesets/api/linter.js +168 -0
  7. package/changesets/api/transformer.js +140 -0
  8. package/changesets/categories/index.js +299 -0
  9. package/changesets/categories/types.js +66 -0
  10. package/changesets/changelog/formatting.js +119 -0
  11. package/changesets/changelog/getDependencyReleaseLine.js +114 -0
  12. package/changesets/changelog/getReleaseLine.js +122 -0
  13. package/changesets/changelog/index.js +99 -0
  14. package/changesets/constants.js +43 -0
  15. package/changesets/errors.js +305 -0
  16. package/changesets/index.js +146 -0
  17. package/changesets/markdownlint/index.js +29 -0
  18. package/changesets/markdownlint/rules/content-structure.js +98 -0
  19. package/changesets/markdownlint/rules/dependency-table-format.js +170 -0
  20. package/changesets/markdownlint/rules/heading-hierarchy.js +61 -0
  21. package/changesets/markdownlint/rules/required-sections.js +54 -0
  22. package/changesets/markdownlint/rules/uncategorized-content.js +54 -0
  23. package/changesets/markdownlint/rules/utils.js +30 -0
  24. package/changesets/remark/plugins/aggregate-dependency-tables.js +47 -0
  25. package/changesets/remark/plugins/contributor-footnotes.js +123 -0
  26. package/changesets/remark/plugins/deduplicate-items.js +30 -0
  27. package/changesets/remark/plugins/issue-link-refs.js +58 -0
  28. package/changesets/remark/plugins/merge-sections.js +43 -0
  29. package/changesets/remark/plugins/normalize-format.js +47 -0
  30. package/changesets/remark/plugins/reorder-sections.js +34 -0
  31. package/changesets/remark/presets.js +119 -0
  32. package/changesets/remark/rules/content-structure.js +22 -0
  33. package/changesets/remark/rules/dependency-table-format.js +40 -0
  34. package/changesets/remark/rules/heading-hierarchy.js +19 -0
  35. package/changesets/remark/rules/required-sections.js +17 -0
  36. package/changesets/remark/rules/uncategorized-content.js +31 -0
  37. package/changesets/schemas/changeset.js +146 -0
  38. package/changesets/schemas/dependency-table.js +189 -0
  39. package/changesets/schemas/git.js +69 -0
  40. package/changesets/schemas/github.js +175 -0
  41. package/changesets/schemas/options.js +182 -0
  42. package/changesets/schemas/package-scope.js +128 -0
  43. package/changesets/schemas/primitives.js +72 -0
  44. package/changesets/schemas/version-files.js +151 -0
  45. package/changesets/services/branch-analyzer.js +278 -0
  46. package/changesets/services/changelog.js +50 -0
  47. package/changesets/services/config-inspector.js +390 -0
  48. package/changesets/services/github.js +178 -0
  49. package/changesets/services/markdown.js +106 -0
  50. package/changesets/services/workspace-snapshot.js +182 -0
  51. package/changesets/utils/commit-parser.js +80 -0
  52. package/changesets/utils/dep-diff.js +77 -0
  53. package/changesets/utils/dependency-table.js +347 -0
  54. package/changesets/utils/issue-refs.js +101 -0
  55. package/changesets/utils/jsonpath.js +175 -0
  56. package/changesets/utils/logger.js +50 -0
  57. package/changesets/utils/markdown-link.js +57 -0
  58. package/changesets/utils/publishability.js +39 -0
  59. package/changesets/utils/remark-pipeline.js +79 -0
  60. package/changesets/utils/section-parser.js +94 -0
  61. package/changesets/utils/strip-frontmatter.js +46 -0
  62. package/changesets/utils/version-blocks.js +108 -0
  63. package/changesets/utils/version-files.js +336 -0
  64. package/changesets/utils/worktree-snapshot.js +142 -0
  65. package/changesets/vendor/github-info.js +55 -0
  66. package/commitlint/config/factory.js +69 -0
  67. package/commitlint/config/plugins.js +227 -0
  68. package/commitlint/config/rules.js +155 -0
  69. package/commitlint/config/schema.js +46 -0
  70. package/commitlint/detection/dco.js +53 -0
  71. package/commitlint/detection/scopes.js +45 -0
  72. package/commitlint/formatter/format.js +85 -0
  73. package/commitlint/formatter/messages.js +79 -0
  74. package/commitlint/hook/diagnostics/branch.js +36 -0
  75. package/commitlint/hook/diagnostics/cache.js +37 -0
  76. package/commitlint/hook/diagnostics/commitlint-config.js +36 -0
  77. package/commitlint/hook/diagnostics/open-issues.js +56 -0
  78. package/commitlint/hook/diagnostics/package-manager.js +51 -0
  79. package/commitlint/hook/diagnostics/signing.js +107 -0
  80. package/commitlint/hook/envelope.js +46 -0
  81. package/commitlint/hook/output.js +45 -0
  82. package/commitlint/hook/parse-bash-command.js +105 -0
  83. package/commitlint/hook/rules/closes-trailer.js +31 -0
  84. package/commitlint/hook/rules/forbidden-content.js +32 -0
  85. package/commitlint/hook/rules/plan-leakage.js +36 -0
  86. package/commitlint/hook/rules/signing-flag-conflict.js +25 -0
  87. package/commitlint/hook/rules/soft-wrap.js +37 -0
  88. package/commitlint/hook/rules/types.js +14 -0
  89. package/commitlint/hook/rules/verbosity.js +31 -0
  90. package/commitlint/hook/silence-logger.js +39 -0
  91. package/commitlint/index.js +146 -0
  92. package/commitlint/prompt/config.js +91 -0
  93. package/commitlint/prompt/emojis.js +74 -0
  94. package/commitlint/prompt/prompter.js +135 -0
  95. package/commitlint/static.js +73 -0
  96. package/errors/BiomeSyncError.js +21 -0
  97. package/errors/ChangesetConfigError.js +20 -0
  98. package/errors/ConfigNotFoundError.js +21 -0
  99. package/errors/SectionParseError.js +16 -0
  100. package/errors/SectionValidationError.js +16 -0
  101. package/errors/SectionWriteError.js +16 -0
  102. package/errors/TagFormatError.js +20 -0
  103. package/errors/ToolNotFoundError.js +11 -0
  104. package/errors/ToolResolutionError.js +11 -0
  105. package/errors/ToolVersionMismatchError.js +11 -0
  106. package/errors/VersioningDetectionError.js +20 -0
  107. package/errors/WorkspaceAnalysisError.js +21 -0
  108. package/index.d.ts +9743 -8380
  109. package/index.js +36 -6657
  110. package/lint/Handler.js +39 -0
  111. package/lint/cli/sections.js +65 -0
  112. package/lint/cli/templates/markdownlint.gen.js +183 -0
  113. package/lint/config/Preset.js +152 -0
  114. package/lint/config/createConfig.js +89 -0
  115. package/lint/handlers/Biome.js +179 -0
  116. package/lint/handlers/Markdown.js +139 -0
  117. package/lint/handlers/PackageJson.js +130 -0
  118. package/lint/handlers/PnpmWorkspace.js +141 -0
  119. package/lint/handlers/ShellScripts.js +58 -0
  120. package/lint/handlers/TypeScript.js +134 -0
  121. package/lint/handlers/Yaml.js +167 -0
  122. package/lint/index.js +52 -0
  123. package/lint/utils/Command.js +285 -0
  124. package/lint/utils/Filter.js +100 -0
  125. package/lint/utils/Workspace.js +86 -0
  126. package/package.json +52 -63
  127. package/schemas/CommentStyle.js +16 -0
  128. package/schemas/ResolvedTool.js +63 -0
  129. package/schemas/SavvySections.js +113 -0
  130. package/schemas/SectionBlock.js +70 -0
  131. package/schemas/SectionDefinition.js +121 -0
  132. package/schemas/SectionResults.js +12 -0
  133. package/schemas/TagStrategySchemas.js +18 -0
  134. package/schemas/ToolDefinition.js +39 -0
  135. package/schemas/ToolResults.js +14 -0
  136. package/schemas/VersioningSchemas.js +95 -0
  137. package/schemas/WorkspaceAnalysisSchemas.js +190 -0
  138. package/services/BiomeSchemaSync.js +133 -0
  139. package/services/ChangesetConfig.js +78 -0
  140. package/services/ChangesetConfigReader.js +106 -0
  141. package/services/ConfigDiscovery.js +71 -0
  142. package/services/ManagedSection.js +288 -0
  143. package/services/SilkPublishability.js +193 -0
  144. package/services/SilkWorkspaceAnalyzer.js +213 -0
  145. package/services/TagStrategy.js +54 -0
  146. package/services/ToolDiscovery.js +229 -0
  147. package/services/VersioningStrategy.js +67 -0
  148. package/tsdoc-metadata.json +11 -11
  149. package/turbo/digest.js +127 -0
  150. package/turbo/errors.js +48 -0
  151. package/turbo/index.js +32 -0
  152. package/turbo/schemas/DryRun.js +57 -0
  153. package/turbo/schemas/results.js +61 -0
  154. package/turbo/services/TurboInspector.js +100 -0
  155. package/utils/ToolCommand.js +40 -0
package/package.json CHANGED
@@ -1,65 +1,54 @@
1
1
  {
2
- "name": "@savvy-web/silk-effects",
3
- "version": "0.6.1",
4
- "private": false,
5
- "description": "Shared Effect library for Silk Suite conventions",
6
- "homepage": "https://github.com/savvy-web/systems/tree/main/packages/silk-effects",
7
- "bugs": {
8
- "url": "https://github.com/savvy-web/systems/issues"
9
- },
10
- "repository": {
11
- "type": "git",
12
- "url": "git+https://github.com/savvy-web/systems.git",
13
- "directory": "packages/silk-effects"
14
- },
15
- "license": "MIT",
16
- "author": {
17
- "name": "C. Spencer Beggs",
18
- "email": "spencer@savvyweb.systems",
19
- "url": "https://savvyweb.systems"
20
- },
21
- "sideEffects": false,
22
- "type": "module",
23
- "exports": {
24
- ".": {
25
- "types": "./index.d.ts",
26
- "import": "./index.js"
27
- }
28
- },
29
- "dependencies": {
30
- "@changesets/get-github-info": "^0.8.0",
31
- "jsonc-effect": "^0.2.1",
32
- "mdast-util-heading-range": "^4.0.0",
33
- "mdast-util-to-string": "^4.0.0",
34
- "prettier": "^3.8.3",
35
- "remark-gfm": "^4.0.1",
36
- "remark-parse": "^11.0.0",
37
- "remark-stringify": "^11.0.0",
38
- "semver-effect": "^0.2.1",
39
- "shell-quote": "^1.8.4",
40
- "sort-package-json": "^3.6.1",
41
- "tinyglobby": "^0.2.16",
42
- "unified": "^11.0.5",
43
- "unified-lint-rule": "^3.0.1",
44
- "unist-util-visit": "^5.1.0",
45
- "workspaces-effect": "^1.1.0",
46
- "yaml": "^2.9.0",
47
- "yaml-effect": "^0.6.0",
48
- "yaml-lint": "^1.7.0"
49
- },
50
- "peerDependencies": {
51
- "@effect/platform": ">=0.96.0",
52
- "effect": ">=3.21.0"
53
- },
54
- "files": [
55
- "!silk-effects.api.json",
56
- "!tsconfig.json",
57
- "!tsdoc.json",
58
- "LICENSE",
59
- "README.md",
60
- "index.d.ts",
61
- "index.js",
62
- "package.json",
63
- "tsdoc-metadata.json"
64
- ]
2
+ "name": "@savvy-web/silk-effects",
3
+ "version": "1.0.1",
4
+ "private": false,
5
+ "description": "Shared Effect library for Silk Suite conventions",
6
+ "homepage": "https://github.com/savvy-web/systems/tree/main/packages/silk-effects",
7
+ "bugs": {
8
+ "url": "https://github.com/savvy-web/systems/issues"
9
+ },
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/savvy-web/systems.git",
13
+ "directory": "packages/silk-effects"
14
+ },
15
+ "license": "MIT",
16
+ "author": {
17
+ "name": "C. Spencer Beggs",
18
+ "email": "spencer@savvyweb.systems",
19
+ "url": "https://savvyweb.systems"
20
+ },
21
+ "sideEffects": false,
22
+ "type": "module",
23
+ "exports": {
24
+ ".": {
25
+ "types": "./index.d.ts",
26
+ "import": "./index.js"
27
+ }
28
+ },
29
+ "dependencies": {
30
+ "@changesets/get-github-info": "^0.8.0",
31
+ "jsonc-effect": "^0.2.1",
32
+ "mdast-util-heading-range": "^4.0.0",
33
+ "mdast-util-to-string": "^4.0.0",
34
+ "prettier": "^3.8.3",
35
+ "remark-gfm": "^4.0.1",
36
+ "remark-parse": "^11.0.0",
37
+ "remark-stringify": "^11.0.0",
38
+ "semver-effect": "^0.2.1",
39
+ "shell-quote": "^1.8.4",
40
+ "sort-package-json": "^4.0.0",
41
+ "tinyglobby": "^0.2.16",
42
+ "unified": "^11.0.5",
43
+ "unified-lint-rule": "^3.0.1",
44
+ "unist-util-visit": "^5.1.0",
45
+ "workspaces-effect": "^1.2.0",
46
+ "yaml": "^2.9.0",
47
+ "yaml-effect": "^0.6.0",
48
+ "yaml-lint": "^1.7.0"
49
+ },
50
+ "peerDependencies": {
51
+ "@effect/platform": ">=0.96.0",
52
+ "effect": ">=3.21.0"
53
+ }
65
54
  }
@@ -0,0 +1,16 @@
1
+ import { Schema } from "effect";
2
+
3
+ //#region src/schemas/CommentStyle.ts
4
+ /**
5
+ * Comment syntax used to write managed section markers.
6
+ *
7
+ * @remarks
8
+ * - `"#"` — shell/YAML style, suitable for hook scripts and `.env` files.
9
+ * - `"//"` — C-style, suitable for JavaScript/TypeScript files.
10
+ *
11
+ * @since 0.1.0
12
+ */
13
+ const CommentStyle = Schema.Literal("#", "//");
14
+
15
+ //#endregion
16
+ export { CommentStyle };
@@ -0,0 +1,63 @@
1
+ import { ToolCommand } from "../utils/ToolCommand.js";
2
+ import { ToolSource } from "./ToolResults.js";
3
+ import { Equal, Hash, Schema } from "effect";
4
+ import { Command } from "@effect/platform";
5
+
6
+ //#region src/schemas/ResolvedTool.ts
7
+ const PackageManager = Schema.Literal("npm", "pnpm", "yarn", "bun");
8
+ /**
9
+ * Result of resolving a {@link ToolDefinition}.
10
+ *
11
+ * Provides {@link exec} and {@link dlx} to build commands for the resolved tool.
12
+ *
13
+ * @since 0.2.0
14
+ */
15
+ var ResolvedTool = class ResolvedTool extends Schema.TaggedClass()("ResolvedTool", {
16
+ name: Schema.String,
17
+ source: ToolSource,
18
+ version: Schema.OptionFromSelf(Schema.String),
19
+ globalVersion: Schema.OptionFromSelf(Schema.String),
20
+ localVersion: Schema.OptionFromSelf(Schema.String),
21
+ packageManager: PackageManager,
22
+ mismatch: Schema.Boolean
23
+ }) {
24
+ get isGlobal() {
25
+ return this.source === "global";
26
+ }
27
+ get isLocal() {
28
+ return this.source === "local";
29
+ }
30
+ get hasVersionMismatch() {
31
+ return this.mismatch;
32
+ }
33
+ exec(...args) {
34
+ if (this.source === "global") return new ToolCommand(Command.make(this.name, ...args));
35
+ switch (this.packageManager) {
36
+ case "pnpm": return new ToolCommand(Command.make("pnpm", "exec", this.name, ...args));
37
+ case "npm": return new ToolCommand(Command.make("npx", "--no", "--", this.name, ...args));
38
+ case "yarn": return new ToolCommand(Command.make("yarn", "exec", this.name, ...args));
39
+ case "bun": return new ToolCommand(Command.make("bun", "x", "--no-install", this.name, ...args));
40
+ }
41
+ }
42
+ dlx(...args) {
43
+ switch (this.packageManager) {
44
+ case "pnpm": return new ToolCommand(Command.make("pnpm", "dlx", this.name, ...args));
45
+ case "npm": return new ToolCommand(Command.make("npx", this.name, ...args));
46
+ case "yarn": return new ToolCommand(Command.make("yarn", "dlx", this.name, ...args));
47
+ case "bun": return new ToolCommand(Command.make("bun", "x", this.name, ...args));
48
+ }
49
+ }
50
+ [Equal.symbol](that) {
51
+ if (!(that instanceof ResolvedTool)) return false;
52
+ return this.name === that.name && this.source === that.source && Equal.equals(this.version, that.version);
53
+ }
54
+ [Hash.symbol]() {
55
+ let h = Hash.hash(this.name);
56
+ h = Hash.combine(h)(Hash.hash(this.source));
57
+ h = Hash.combine(h)(Hash.hash(this.version));
58
+ return Hash.cached(this)(h);
59
+ }
60
+ };
61
+
62
+ //#endregion
63
+ export { ResolvedTool };
@@ -0,0 +1,113 @@
1
+ import { ShellSectionDefinition } from "./SectionDefinition.js";
2
+
3
+ //#region src/schemas/SavvySections.ts
4
+ /**
5
+ * Section identity for the shared package-manager preamble.
6
+ *
7
+ * `toolName` is `"savvy-base"`; pair with {@link savvyBasePreamble} to build the block:
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * const block = SavvyBaseSection.block(savvyBasePreamble());
12
+ * ```
13
+ *
14
+ * @since 0.5.0
15
+ */
16
+ const SavvyBaseSection = ShellSectionDefinition.make({ toolName: "savvy-base" });
17
+ /**
18
+ * Section identity for the shared repo-hygiene block.
19
+ *
20
+ * `toolName` is `"savvy-hooks"`; pair with {@link savvyHooksHygiene}.
21
+ *
22
+ * @since 0.5.0
23
+ */
24
+ const SavvyHooksSection = ShellSectionDefinition.make({ toolName: "savvy-hooks" });
25
+ /**
26
+ * Package-manager detection preamble shared across Silk Suite hook files.
27
+ *
28
+ * @remarks
29
+ * Side-effect-free definitions meant to run unconditionally — no markers, no outer CI
30
+ * guard. Defines `ROOT`, the `in_ci` predicate, `PM` (via `detect_pm`), and `pm_exec`.
31
+ * `pm_exec` uses local/exec semantics for every package manager and `bun x` (space form),
32
+ * which works regardless of how bun was installed (the `bunx` shim is not always on PATH).
33
+ *
34
+ * @returns The preamble shell, with no surrounding markers or trailing newline.
35
+ *
36
+ * @since 0.5.0
37
+ */
38
+ function savvyBasePreamble() {
39
+ return `ROOT=$(git rev-parse --show-toplevel)
40
+
41
+ in_ci() { [ -n "$CI" ] || [ -n "$GITHUB_ACTIONS" ]; }
42
+
43
+ detect_pm() {
44
+ if [ -f "$ROOT/package.json" ]; then
45
+ pm=$(jq -r '.packageManager // empty' "$ROOT/package.json" 2>/dev/null | cut -d'@' -f1)
46
+ if [ -n "$pm" ]; then echo "$pm"; return; fi
47
+ fi
48
+ if [ -f "$ROOT/pnpm-lock.yaml" ]; then echo "pnpm"
49
+ elif [ -f "$ROOT/yarn.lock" ]; then echo "yarn"
50
+ elif [ -f "$ROOT/bun.lock" ]; then echo "bun"
51
+ else echo "npm"; fi
52
+ }
53
+ PM=$(detect_pm)
54
+
55
+ pm_exec() {
56
+ case "$PM" in
57
+ pnpm) pnpm exec "$@" ;;
58
+ yarn) yarn exec "$@" ;;
59
+ bun) bun x "$@" ;;
60
+ *) npx --no -- "$@" ;;
61
+ esac
62
+ }`;
63
+ }
64
+ /**
65
+ * Repo-hygiene block shared across Silk Suite hook files.
66
+ *
67
+ * @remarks
68
+ * Self-guarded against CI and needs no package manager: disables Git's `core.fileMode`
69
+ * tracking and marks tracked shell scripts executable.
70
+ *
71
+ * @returns The hygiene shell, with no surrounding markers or trailing newline.
72
+ *
73
+ * @since 0.5.0
74
+ */
75
+ function savvyHooksHygiene() {
76
+ return `if ! { [ -n "$CI" ] || [ -n "$GITHUB_ACTIONS" ]; }; then
77
+ git config core.fileMode false
78
+ git ls-files -z '*.sh' | xargs -0 chmod +x 2>/dev/null || true
79
+ fi`;
80
+ }
81
+ /**
82
+ * Build a consumer's one-line tool section so every consumer calls the shared base
83
+ * helpers identically.
84
+ *
85
+ * @remarks
86
+ * The returned block's content is exactly `in_ci || pm_exec <command>` with `command`
87
+ * appended verbatim — it is not parsed, quoted, or interpolated, so shell tokens like
88
+ * `$ROOT` and `$1` survive into the generated literal.
89
+ *
90
+ * **Precondition:** a {@link SavvyBaseSection} block must precede this section in the same
91
+ * hook file so `in_ci` and `pm_exec` are defined. Consumers guarantee this by passing both
92
+ * to {@link ManagedSection.syncMany | ManagedSection.syncMany} in order:
93
+ *
94
+ * @example
95
+ * ```ts
96
+ * yield* ManagedSection.syncMany(".husky/commit-msg", [
97
+ * SavvyBaseSection.block(savvyBasePreamble()),
98
+ * savvyToolSection("savvy-commit", 'commitlint --config "$ROOT/lib/configs/commitlint.config.ts" --edit "$1"'),
99
+ * ]);
100
+ * ```
101
+ *
102
+ * @param toolName - Section identity; also drives the marker names (uppercased).
103
+ * @param command - The command passed verbatim to `pm_exec`, run only outside CI.
104
+ * @returns A shell {@link SectionBlock} (`commentStyle: "#"`) for `toolName`.
105
+ *
106
+ * @since 0.5.0
107
+ */
108
+ function savvyToolSection(toolName, command) {
109
+ return ShellSectionDefinition.make({ toolName }).block(`in_ci || pm_exec ${command}`);
110
+ }
111
+
112
+ //#endregion
113
+ export { SavvyBaseSection, SavvyHooksSection, savvyBasePreamble, savvyHooksHygiene, savvyToolSection };
@@ -0,0 +1,70 @@
1
+ import { CommentStyle } from "./CommentStyle.js";
2
+ import { SectionDiff } from "./SectionResults.js";
3
+ import { Equal, Function, Hash, Schema } from "effect";
4
+
5
+ //#region src/schemas/SectionBlock.ts
6
+ /**
7
+ * The content between managed section markers.
8
+ *
9
+ * {@link Equal} compares normalized content only (trimmed, whitespace-collapsed).
10
+ * Use {@link SectionBlock.diff | diff} to compute line-level differences.
11
+ *
12
+ * @since 0.2.0
13
+ */
14
+ var SectionBlock = class SectionBlock extends Schema.TaggedClass()("SectionBlock", {
15
+ toolName: Schema.String,
16
+ commentStyle: CommentStyle,
17
+ content: Schema.String
18
+ }) {
19
+ static diff = Function.dual(2, (self, that) => self.diff(that));
20
+ static prepend = Function.dual(2, (self, lines) => self.prepend(lines));
21
+ static append = Function.dual(2, (self, lines) => self.append(lines));
22
+ get text() {
23
+ return this.content;
24
+ }
25
+ get normalized() {
26
+ return this.content.trim().replace(/\s+/g, " ");
27
+ }
28
+ get rendered() {
29
+ const begin = `${this.commentStyle} --- BEGIN ${this.toolName.toUpperCase()} MANAGED SECTION ---`;
30
+ const end = `${this.commentStyle} --- END ${this.toolName.toUpperCase()} MANAGED SECTION ---`;
31
+ return `${begin}\n${this.content}\n${end}`;
32
+ }
33
+ prepend(lines) {
34
+ return SectionBlock.make({
35
+ toolName: this.toolName,
36
+ commentStyle: this.commentStyle,
37
+ content: `${lines}\n${this.content}`
38
+ });
39
+ }
40
+ append(lines) {
41
+ return SectionBlock.make({
42
+ toolName: this.toolName,
43
+ commentStyle: this.commentStyle,
44
+ content: `${this.content}\n${lines}`
45
+ });
46
+ }
47
+ diff(that) {
48
+ if (this.normalized === that.normalized) return SectionDiff.Unchanged();
49
+ const selfLines = this.content.trim().split("\n");
50
+ const thatLines = that.content.trim().split("\n");
51
+ const selfSet = new Set(selfLines);
52
+ const thatSet = new Set(thatLines);
53
+ const removed = selfLines.filter((line) => !thatSet.has(line));
54
+ const added = thatLines.filter((line) => !selfSet.has(line));
55
+ return SectionDiff.Changed({
56
+ added,
57
+ removed
58
+ });
59
+ }
60
+ [Equal.symbol](that) {
61
+ if (!(that instanceof SectionBlock)) return false;
62
+ return this.normalized === that.normalized;
63
+ }
64
+ [Hash.symbol]() {
65
+ return Hash.cached(this)(Hash.hash(this.normalized));
66
+ }
67
+ };
68
+
69
+ //#endregion
70
+ export { SectionBlock };
@@ -0,0 +1,121 @@
1
+ import { SectionValidationError } from "../errors/SectionValidationError.js";
2
+ import { CommentStyle } from "./CommentStyle.js";
3
+ import { SectionDiff } from "./SectionResults.js";
4
+ import { SectionBlock } from "./SectionBlock.js";
5
+ import { Effect, Equal, Function, Hash, Schema } from "effect";
6
+
7
+ //#region src/schemas/SectionDefinition.ts
8
+ /**
9
+ * Identity envelope for a managed section type.
10
+ *
11
+ * {@link Equal} compares on `toolName` + `commentStyle`.
12
+ * Use {@link SectionDefinition.block | block()} to create a {@link SectionBlock},
13
+ * or {@link SectionDefinition.generate | generate()} for a typed factory.
14
+ *
15
+ * @since 0.2.0
16
+ */
17
+ var SectionDefinition = class SectionDefinition extends Schema.TaggedClass()("SectionDefinition", {
18
+ toolName: Schema.String,
19
+ commentStyle: Schema.optionalWith(CommentStyle, { default: () => "#" })
20
+ }) {
21
+ _validate;
22
+ static generate = Function.dual(2, (self, fn) => {
23
+ return (config) => self.block(fn(config));
24
+ });
25
+ static generateEffect = Function.dual(2, (self, fn) => {
26
+ return (config) => Effect.flatMap(fn(config), (content) => {
27
+ try {
28
+ return Effect.succeed(self.block(content));
29
+ } catch (e) {
30
+ return Effect.fail(e);
31
+ }
32
+ });
33
+ });
34
+ static withValidation = Function.dual(2, (self, fn) => {
35
+ const copy = SectionDefinition.make({
36
+ toolName: self.toolName,
37
+ commentStyle: self.commentStyle
38
+ });
39
+ copy._validate = fn;
40
+ return copy;
41
+ });
42
+ static diff = Function.dual(2, (self, that) => self.diff(that));
43
+ block(content) {
44
+ const block = SectionBlock.make({
45
+ toolName: this.toolName,
46
+ commentStyle: this.commentStyle,
47
+ content
48
+ });
49
+ if (this._validate && !this._validate(block)) throw new SectionValidationError({
50
+ toolName: this.toolName,
51
+ reason: "Content failed validation"
52
+ });
53
+ return block;
54
+ }
55
+ generate(fn) {
56
+ return (config) => this.block(fn(config));
57
+ }
58
+ generateEffect(fn) {
59
+ return (config) => Effect.flatMap(fn(config), (content) => {
60
+ try {
61
+ return Effect.succeed(this.block(content));
62
+ } catch (e) {
63
+ return Effect.fail(e);
64
+ }
65
+ });
66
+ }
67
+ diff(that) {
68
+ if (Equal.equals(this, that)) return SectionDiff.Unchanged();
69
+ return SectionDiff.Changed({
70
+ added: [that.toolName !== this.toolName ? `toolName: ${that.toolName}` : "", that.commentStyle !== this.commentStyle ? `commentStyle: ${that.commentStyle}` : ""].filter(Boolean),
71
+ removed: [that.toolName !== this.toolName ? `toolName: ${this.toolName}` : "", that.commentStyle !== this.commentStyle ? `commentStyle: ${this.commentStyle}` : ""].filter(Boolean)
72
+ });
73
+ }
74
+ get beginMarker() {
75
+ return `${this.commentStyle} --- BEGIN ${this.toolName.toUpperCase()} MANAGED SECTION ---`;
76
+ }
77
+ get endMarker() {
78
+ return `${this.commentStyle} --- END ${this.toolName.toUpperCase()} MANAGED SECTION ---`;
79
+ }
80
+ [Equal.symbol](that) {
81
+ if (!(that instanceof SectionDefinition)) return false;
82
+ return this.toolName === that.toolName && this.commentStyle === that.commentStyle;
83
+ }
84
+ [Hash.symbol]() {
85
+ return Hash.cached(this)(Hash.combine(Hash.hash(this.toolName))(Hash.hash(this.commentStyle)));
86
+ }
87
+ };
88
+ /**
89
+ * Convenience section definition for shell hooks.
90
+ *
91
+ * `commentStyle` is always `"#"` — only `toolName` is required.
92
+ *
93
+ * @since 0.2.0
94
+ */
95
+ var ShellSectionDefinition = class extends Schema.TaggedClass()("ShellSectionDefinition", { toolName: Schema.String }) {
96
+ get commentStyle() {
97
+ return "#";
98
+ }
99
+ block(content) {
100
+ return SectionBlock.make({
101
+ toolName: this.toolName,
102
+ commentStyle: "#",
103
+ content
104
+ });
105
+ }
106
+ generate(fn) {
107
+ return (config) => this.block(fn(config));
108
+ }
109
+ generateEffect(fn) {
110
+ return (config) => Effect.map(fn(config), (content) => this.block(content));
111
+ }
112
+ get beginMarker() {
113
+ return `# --- BEGIN ${this.toolName.toUpperCase()} MANAGED SECTION ---`;
114
+ }
115
+ get endMarker() {
116
+ return `# --- END ${this.toolName.toUpperCase()} MANAGED SECTION ---`;
117
+ }
118
+ };
119
+
120
+ //#endregion
121
+ export { SectionDefinition, ShellSectionDefinition };
@@ -0,0 +1,12 @@
1
+ import { Data } from "effect";
2
+
3
+ //#region src/schemas/SectionResults.ts
4
+ /** @since 0.2.0 */
5
+ const SectionDiff = Data.taggedEnum();
6
+ /** @since 0.2.0 */
7
+ const SyncResult = Data.taggedEnum();
8
+ /** @since 0.2.0 */
9
+ const CheckResult = Data.taggedEnum();
10
+
11
+ //#endregion
12
+ export { CheckResult, SectionDiff, SyncResult };
@@ -0,0 +1,18 @@
1
+ import { Schema } from "effect";
2
+
3
+ //#region src/schemas/TagStrategySchemas.ts
4
+ /**
5
+ * Git tag naming strategy for a workspace.
6
+ *
7
+ * @remarks
8
+ * - `"single"` — one shared tag for the entire release (e.g. `1.2.3`).
9
+ * - `"scoped"` — a per-package tag that includes the package name (e.g. `@my-org/pkg@1.2.3`).
10
+ *
11
+ * Determined by {@link TagStrategy.determine} based on the {@link VersioningStrategyResult}.
12
+ *
13
+ * @since 0.1.0
14
+ */
15
+ const TagStrategyType = Schema.Literal("single", "scoped");
16
+
17
+ //#endregion
18
+ export { TagStrategyType };
@@ -0,0 +1,39 @@
1
+ import { ResolutionPolicy, SourceRequirement, VersionExtractor } from "./ToolResults.js";
2
+ import { Equal, Hash, Schema } from "effect";
3
+
4
+ //#region src/schemas/ToolDefinition.ts
5
+ const NameSchema = Schema.Struct({ name: Schema.String });
6
+ /**
7
+ * Declares a CLI tool's identity and resolution constraints.
8
+ *
9
+ * {@link Equal} compares on `name` only (identity).
10
+ *
11
+ * @since 0.2.0
12
+ */
13
+ var ToolDefinition = class ToolDefinition {
14
+ _tag = "ToolDefinition";
15
+ name;
16
+ versionExtractor;
17
+ policy;
18
+ source;
19
+ constructor(name, versionExtractor, policy, source) {
20
+ this.name = name;
21
+ this.versionExtractor = versionExtractor;
22
+ this.policy = policy;
23
+ this.source = source;
24
+ }
25
+ static make(options) {
26
+ Schema.decodeUnknownSync(NameSchema)({ name: options.name });
27
+ return new ToolDefinition(options.name, options.versionExtractor ?? VersionExtractor.Flag({ flag: "--version" }), options.policy ?? ResolutionPolicy.Report(), options.source ?? SourceRequirement.Any());
28
+ }
29
+ [Equal.symbol](that) {
30
+ if (!(that instanceof ToolDefinition)) return false;
31
+ return this.name === that.name;
32
+ }
33
+ [Hash.symbol]() {
34
+ return Hash.cached(this)(Hash.hash(this.name));
35
+ }
36
+ };
37
+
38
+ //#endregion
39
+ export { ToolDefinition };
@@ -0,0 +1,14 @@
1
+ import { Data, Schema } from "effect";
2
+
3
+ //#region src/schemas/ToolResults.ts
4
+ /** Where a tool was resolved from. @since 0.2.0 */
5
+ const ToolSource = Schema.Literal("global", "local");
6
+ /** @since 0.2.0 */
7
+ const VersionExtractor = Data.taggedEnum();
8
+ /** @since 0.2.0 */
9
+ const ResolutionPolicy = Data.taggedEnum();
10
+ /** @since 0.2.0 */
11
+ const SourceRequirement = Data.taggedEnum();
12
+
13
+ //#endregion
14
+ export { ResolutionPolicy, SourceRequirement, ToolSource, VersionExtractor };