@savvy-web/silk-effects 0.6.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -0,0 +1,36 @@
1
+ import { Effect } from "effect";
2
+
3
+ //#region src/commitlint/hook/rules/plan-leakage.ts
4
+ /**
5
+ * plan-leakage rule — advises when commit bodies reference plan files
6
+ * or contain planning-narrative language.
7
+ *
8
+ * @internal
9
+ */
10
+ const PATH_PATTERNS = [/\.claude\/plans\//i, /\.claude\/design\//i];
11
+ const PHRASE_PATTERNS = [
12
+ /\bas decided in the plan\b/i,
13
+ /\bpreviously documented\b/i,
14
+ /\bsee the design doc\b/i,
15
+ /\bper the (plan|design doc|spec)\b/i
16
+ ];
17
+ const planLeakageRule = {
18
+ id: "plan-leakage",
19
+ severity: "advise",
20
+ check: (input) => Effect.sync(() => {
21
+ const matchedPaths = PATH_PATTERNS.filter((re) => re.test(input.message));
22
+ const matchedPhrases = PHRASE_PATTERNS.filter((re) => re.test(input.message));
23
+ if (matchedPaths.length === 0 && matchedPhrases.length === 0) return null;
24
+ const reasons = [];
25
+ if (matchedPaths.length > 0) reasons.push("references planning artifacts (.claude/plans/ or .claude/design/)");
26
+ if (matchedPhrases.length > 0) reasons.push("contains planning-narrative phrasing");
27
+ return {
28
+ ruleId: "plan-leakage",
29
+ severity: "advise",
30
+ message: `Body ${reasons.join(" and ")}. Plan-file paths and "as decided in the plan"-style narrative belong in the PR description, not the commit body. Remove those references and re-run git commit.`
31
+ };
32
+ })
33
+ };
34
+
35
+ //#endregion
36
+ export { planLeakageRule };
@@ -0,0 +1,25 @@
1
+ import { Effect } from "effect";
2
+
3
+ //#region src/commitlint/hook/rules/signing-flag-conflict.ts
4
+ /**
5
+ * signing-flag-conflict rule — denies when the command explicitly opts out
6
+ * of signing while the project is configured to require signing.
7
+ *
8
+ * @internal
9
+ */
10
+ const signingFlagConflictRule = {
11
+ id: "signing-flag-conflict",
12
+ severity: "deny",
13
+ check: (input, ctx) => Effect.sync(() => {
14
+ if (input.flags.sign !== "force-off") return null;
15
+ if (!ctx.autoSignEnabled) return null;
16
+ return {
17
+ ruleId: "signing-flag-conflict",
18
+ severity: "deny",
19
+ message: "Command uses --no-gpg-sign while commit.gpgsign=true is configured. Either remove --no-gpg-sign, or update git config commit.gpgsign first if you intend to leave signing off."
20
+ };
21
+ })
22
+ };
23
+
24
+ //#endregion
25
+ export { signingFlagConflictRule };
@@ -0,0 +1,37 @@
1
+ import { Effect } from "effect";
2
+
3
+ //#region src/commitlint/hook/rules/soft-wrap.ts
4
+ /**
5
+ * soft-wrap rule — advises when a bullet point appears to have an
6
+ * artificial mid-bullet line wrap.
7
+ *
8
+ * Heuristic: a bullet line shorter than 80 chars, immediately followed
9
+ * by an indented continuation line (not a new bullet), suggests the
10
+ * agent wrapped at ~80 chars unnecessarily.
11
+ *
12
+ * @internal
13
+ */
14
+ const BULLET = /^([ \t]*)[-*]\s/;
15
+ const CONTINUATION = /^[ \t]+\S/;
16
+ const softWrapRule = {
17
+ id: "soft-wrap",
18
+ severity: "advise",
19
+ check: (input) => Effect.sync(() => {
20
+ const lines = input.message.split("\n");
21
+ for (let i = 0; i < lines.length - 1; i++) {
22
+ const line = lines[i] ?? "";
23
+ const next = lines[i + 1] ?? "";
24
+ if (!line.match(BULLET)) continue;
25
+ if (line.length >= 80) continue;
26
+ if (CONTINUATION.test(next) && !BULLET.test(next)) return {
27
+ ruleId: "soft-wrap",
28
+ severity: "advise",
29
+ message: "A bullet point appears to have an artificial soft-wrap (a short bullet followed by an indented continuation). The body line limit is 300 chars; one bullet should fit on one line. Reflow the bullet onto a single line."
30
+ };
31
+ }
32
+ return null;
33
+ })
34
+ };
35
+
36
+ //#endregion
37
+ export { softWrapRule };
@@ -0,0 +1,14 @@
1
+ //#region src/commitlint/hook/rules/types.ts
2
+ function partitionHits(hits) {
3
+ const deny = [];
4
+ const advise = [];
5
+ for (const hit of hits) if (hit.severity === "deny") deny.push(hit);
6
+ else advise.push(hit);
7
+ return {
8
+ deny,
9
+ advise
10
+ };
11
+ }
12
+
13
+ //#endregion
14
+ export { partitionHits };
@@ -0,0 +1,31 @@
1
+ import { Effect } from "effect";
2
+
3
+ //#region src/commitlint/hook/rules/verbosity.ts
4
+ /**
5
+ * verbosity rule — advises when the body exceeds line or word thresholds.
6
+ *
7
+ * @internal
8
+ */
9
+ const VERBOSITY_LINE_THRESHOLD = 25;
10
+ const VERBOSITY_WORD_THRESHOLD = 400;
11
+ const verbosityRule = {
12
+ id: "verbosity",
13
+ severity: "advise",
14
+ check: (input) => Effect.sync(() => {
15
+ const body = input.message.split("\n").slice(2).filter((l) => l.length > 0);
16
+ const lineCount = body.length;
17
+ const wordCount = body.join(" ").trim().split(/\s+/).filter(Boolean).length;
18
+ if (lineCount <= 25 && wordCount <= 400) return null;
19
+ const reasons = [];
20
+ if (lineCount > 25) reasons.push(`${lineCount} non-empty body lines`);
21
+ if (wordCount > 400) reasons.push(`${wordCount} words`);
22
+ return {
23
+ ruleId: "verbosity",
24
+ severity: "advise",
25
+ message: `Body has ${reasons.join(" / ")}; the project standard keeps commit bodies under ~${25} lines and ~${400} words. Move detail to the PR description and keep the commit body to the irreducible "what + why".`
26
+ };
27
+ })
28
+ };
29
+
30
+ //#endregion
31
+ export { verbosityRule };
@@ -0,0 +1,39 @@
1
+ import { Layer, LogLevel, Logger } from "effect";
2
+
3
+ //#region src/commitlint/hook/silence-logger.ts
4
+ /**
5
+ * Logger configuration shared by all hook subcommands.
6
+ *
7
+ * @remarks
8
+ * Hook subcommands reserve stdout for the JSON envelope they emit to Claude
9
+ * Code. Effect's default logger writes messages to stdout via `console.log`,
10
+ * which pollutes that contract (e.g., workspaces-effect emits "Workspace root
11
+ * found" on every CLI invocation). This Layer combines two protections:
12
+ *
13
+ * 1. {@link Logger.minimumLogLevel} at `Warning` silences routine Info/Debug
14
+ * traffic so the common case never reaches the logger at all.
15
+ * 2. A default-logger replacement that routes anything which *does* fire to
16
+ * stderr, so even Warning/Error output cannot corrupt the stdout envelope.
17
+ *
18
+ * Only the hook command wrappers provide this Layer, so regular `savvy`
19
+ * commands keep their stdout output intact.
20
+ *
21
+ * @internal
22
+ */
23
+ /**
24
+ * Replacement for the default logger that writes every message to stderr,
25
+ * leaving stdout reserved for the hook's JSON envelope.
26
+ */
27
+ const StderrLogger = Logger.replace(Logger.defaultLogger, Logger.make(({ message }) => {
28
+ process.stderr.write(`${JSON.stringify(message)}\n`);
29
+ }));
30
+ /** Minimum log level layer that suppresses Info and below. */
31
+ const MinLogLevel = Logger.minimumLogLevel(LogLevel.Warning);
32
+ /**
33
+ * Combined hook logger layer: stderr redirect merged with the Warning minimum
34
+ * log level. Provided by hook command wrappers to keep stdout corruption-proof.
35
+ */
36
+ const HookSilencer = Layer.merge(StderrLogger, MinLogLevel);
37
+
38
+ //#endregion
39
+ export { HookSilencer };
@@ -0,0 +1,146 @@
1
+ import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
+ import { detectDCO } from "./detection/dco.js";
3
+ import { COMMIT_TYPES, COMMIT_TYPE_DEFINITIONS, DCO_SIGNOFF_TEXT, TDD_SCOPE_PATTERN, TDD_STATES } from "./config/rules.js";
4
+ import { TYPE_EMOJIS, TYPE_EMOJIS_UNICODE, getTypeEmoji } from "./prompt/emojis.js";
5
+ import { createPromptConfig, createTypeEnum, defaultPromptConfig, emojiPromptConfig } from "./prompt/config.js";
6
+ import { createConfig } from "./config/factory.js";
7
+ import { decodeConfigOptions } from "./config/schema.js";
8
+ import staticConfig from "./static.js";
9
+ import { ERROR_EXPLANATIONS, ERROR_SUGGESTIONS, getExplanation, getSuggestion } from "./formatter/messages.js";
10
+ import { format } from "./formatter/format.js";
11
+ import { prompter } from "./prompt/prompter.js";
12
+ import { detectScopes } from "./detection/scopes.js";
13
+ import { PostToolUseEnvelope, PreToolUseEnvelope, SessionStartEnvelope, UserPromptSubmitEnvelope } from "./hook/envelope.js";
14
+ import { postToolUseAdvise, preToolUseAdvise, preToolUseAllow, preToolUseDeny, preToolUseSilent, sessionStartContext, userPromptSubmitContext } from "./hook/output.js";
15
+ import { parseBashCommand } from "./hook/parse-bash-command.js";
16
+ import { HookSilencer } from "./hook/silence-logger.js";
17
+ import { inferTicketId, readBranchInfo } from "./hook/diagnostics/branch.js";
18
+ import { readCache, writeCache } from "./hook/diagnostics/cache.js";
19
+ import { parseHuskyConfigPath, readCommitlintConfigPath } from "./hook/diagnostics/commitlint-config.js";
20
+ import { ISSUES_CACHE_RELATIVE_PATH, fetchAndCacheOpenIssues, readOpenIssuesFromCache, readOrFetchOpenIssues } from "./hook/diagnostics/open-issues.js";
21
+ import { detectFromLockfiles, detectPackageManager, parsePackageManagerField } from "./hook/diagnostics/package-manager.js";
22
+ import { buildSigningDiagnostic, parseGpgKeyExpiry, readSigningDiagnostic } from "./hook/diagnostics/signing.js";
23
+ import { closesTrailerRule, hasClosingTrailer } from "./hook/rules/closes-trailer.js";
24
+ import { forbiddenContentRule } from "./hook/rules/forbidden-content.js";
25
+ import { planLeakageRule } from "./hook/rules/plan-leakage.js";
26
+ import { signingFlagConflictRule } from "./hook/rules/signing-flag-conflict.js";
27
+ import { softWrapRule } from "./hook/rules/soft-wrap.js";
28
+ import { partitionHits } from "./hook/rules/types.js";
29
+ import { verbosityRule } from "./hook/rules/verbosity.js";
30
+
31
+ //#region src/commitlint/index.ts
32
+ /**
33
+ * Commitlint namespace — commitlint business logic extracted from \@savvy-web/commitlint.
34
+ *
35
+ * @remarks
36
+ * This barrel re-exports the complete commitlint public surface (minus CLI/bin) from
37
+ * the silk-effects package. Downstream consumers import via the Commitlint namespace:
38
+ *
39
+ * ```typescript
40
+ * import { Commitlint } from "@savvy-web/silk-effects";
41
+ * const config = Commitlint.CommitlintConfig.silk();
42
+ * ```
43
+ *
44
+ * @packageDocumentation
45
+ */
46
+ var commitlint_exports = /* @__PURE__ */ __exportAll({
47
+ COMMIT_TYPES: () => COMMIT_TYPES,
48
+ COMMIT_TYPE_DEFINITIONS: () => COMMIT_TYPE_DEFINITIONS,
49
+ CommitlintConfig: () => CommitlintConfig,
50
+ DCO_SIGNOFF_TEXT: () => DCO_SIGNOFF_TEXT,
51
+ DEFAULT_BODY_MAX_LINE_LENGTH: () => 300,
52
+ ERROR_EXPLANATIONS: () => ERROR_EXPLANATIONS,
53
+ ERROR_SUGGESTIONS: () => ERROR_SUGGESTIONS,
54
+ HookSilencer: () => HookSilencer,
55
+ ISSUES_CACHE_RELATIVE_PATH: () => ISSUES_CACHE_RELATIVE_PATH,
56
+ ISSUES_CACHE_TTL_SECONDS: () => 600,
57
+ PostToolUseEnvelope: () => PostToolUseEnvelope,
58
+ PreToolUseEnvelope: () => PreToolUseEnvelope,
59
+ SessionStartEnvelope: () => SessionStartEnvelope,
60
+ TDD_SCOPE_PATTERN: () => TDD_SCOPE_PATTERN,
61
+ TDD_STATES: () => TDD_STATES,
62
+ TYPE_EMOJIS: () => TYPE_EMOJIS,
63
+ TYPE_EMOJIS_UNICODE: () => TYPE_EMOJIS_UNICODE,
64
+ UserPromptSubmitEnvelope: () => UserPromptSubmitEnvelope,
65
+ VERBOSITY_LINE_THRESHOLD: () => 25,
66
+ VERBOSITY_WORD_THRESHOLD: () => 400,
67
+ buildSigningDiagnostic: () => buildSigningDiagnostic,
68
+ closesTrailerRule: () => closesTrailerRule,
69
+ createPromptConfig: () => createPromptConfig,
70
+ createTypeEnum: () => createTypeEnum,
71
+ default: () => CommitlintConfig,
72
+ defaultPromptConfig: () => defaultPromptConfig,
73
+ detectDCO: () => detectDCO,
74
+ detectFromLockfiles: () => detectFromLockfiles,
75
+ detectPackageManager: () => detectPackageManager,
76
+ detectScopes: () => detectScopes,
77
+ emojiPromptConfig: () => emojiPromptConfig,
78
+ fetchAndCacheOpenIssues: () => fetchAndCacheOpenIssues,
79
+ forbiddenContentRule: () => forbiddenContentRule,
80
+ format: () => format,
81
+ getExplanation: () => getExplanation,
82
+ getSuggestion: () => getSuggestion,
83
+ getTypeEmoji: () => getTypeEmoji,
84
+ hasClosingTrailer: () => hasClosingTrailer,
85
+ inferTicketId: () => inferTicketId,
86
+ parseBashCommand: () => parseBashCommand,
87
+ parseGpgKeyExpiry: () => parseGpgKeyExpiry,
88
+ parseHuskyConfigPath: () => parseHuskyConfigPath,
89
+ parsePackageManagerField: () => parsePackageManagerField,
90
+ partitionHits: () => partitionHits,
91
+ planLeakageRule: () => planLeakageRule,
92
+ postToolUseAdvise: () => postToolUseAdvise,
93
+ preToolUseAdvise: () => preToolUseAdvise,
94
+ preToolUseAllow: () => preToolUseAllow,
95
+ preToolUseDeny: () => preToolUseDeny,
96
+ preToolUseSilent: () => preToolUseSilent,
97
+ prompter: () => prompter,
98
+ readBranchInfo: () => readBranchInfo,
99
+ readCache: () => readCache,
100
+ readCommitlintConfigPath: () => readCommitlintConfigPath,
101
+ readOpenIssuesFromCache: () => readOpenIssuesFromCache,
102
+ readOrFetchOpenIssues: () => readOrFetchOpenIssues,
103
+ readSigningDiagnostic: () => readSigningDiagnostic,
104
+ sessionStartContext: () => sessionStartContext,
105
+ signingFlagConflictRule: () => signingFlagConflictRule,
106
+ softWrapRule: () => softWrapRule,
107
+ staticConfig: () => staticConfig,
108
+ userPromptSubmitContext: () => userPromptSubmitContext,
109
+ verbosityRule: () => verbosityRule,
110
+ writeCache: () => writeCache
111
+ });
112
+ /**
113
+ * Dynamic commitlint configuration factory.
114
+ *
115
+ * @remarks
116
+ * Provides static methods for creating commitlint configurations with automatic
117
+ * detection of repository characteristics. The class co-locates configuration
118
+ * creation with schema validation.
119
+ *
120
+ * @public
121
+ *
122
+ * @example
123
+ * ```typescript
124
+ * import { Commitlint } from "@savvy-web/silk-effects";
125
+ *
126
+ * // Auto-detect everything
127
+ * export default Commitlint.CommitlintConfig.silk();
128
+ *
129
+ * // With explicit overrides
130
+ * export default Commitlint.CommitlintConfig.silk({
131
+ * dco: true,
132
+ * scopes: ["api", "cli"],
133
+ * emojis: true,
134
+ * });
135
+ * ```
136
+ */
137
+ var CommitlintConfig = class {
138
+ static silk(options = {}) {
139
+ return createConfig(decodeConfigOptions(options));
140
+ }
141
+ /* v8 ignore next 3 -- private constructor prevents direct instantiation */
142
+ constructor() {}
143
+ };
144
+
145
+ //#endregion
146
+ export { commitlint_exports };
@@ -0,0 +1,91 @@
1
+ import { COMMIT_TYPE_DEFINITIONS } from "../config/rules.js";
2
+ import { TYPE_EMOJIS } from "./emojis.js";
3
+
4
+ //#region src/commitlint/prompt/config.ts
5
+ /**
6
+ * Create type enum configuration for prompts.
7
+ *
8
+ * @remarks
9
+ * Builds the type enum object used by commitizen adapters
10
+ * to display commit type options in the interactive prompt.
11
+ *
12
+ * @param emojis - Whether to include emoji shortcodes
13
+ * @returns Type enum configuration object
14
+ *
15
+ * @public
16
+ */
17
+ function createTypeEnum(emojis) {
18
+ const typeEnum = {};
19
+ for (const def of COMMIT_TYPE_DEFINITIONS) typeEnum[def.type] = {
20
+ description: def.description,
21
+ title: def.title,
22
+ emoji: emojis ? TYPE_EMOJIS[def.type] : ""
23
+ };
24
+ return typeEnum;
25
+ }
26
+ /**
27
+ * Create prompt configuration for commitizen adapters.
28
+ *
29
+ * @remarks
30
+ * Generates a complete prompt configuration object compatible with
31
+ * `@commitlint/cz-commitlint` and included in `CommitlintConfig.silk()` output.
32
+ *
33
+ * @param options - Prompt configuration options
34
+ * @returns Prompt configuration object
35
+ *
36
+ * @public
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * import { createPromptConfig } from "@savvy-web/commitlint/prompt";
41
+ *
42
+ * const promptConfig = createPromptConfig({ emojis: true });
43
+ * ```
44
+ */
45
+ function createPromptConfig(options = {}) {
46
+ const { emojis = false, scopes } = options;
47
+ const scopeQuestion = { description: "What is the scope of this change (e.g., component name):" };
48
+ if (scopes && scopes.length > 0) scopeQuestion.enum = scopes;
49
+ return {
50
+ settings: {
51
+ enableMultipleScopes: true,
52
+ scopeEnumSeparator: ","
53
+ },
54
+ messages: {
55
+ skip: "(press enter to skip)",
56
+ max: "(max %d chars)",
57
+ min: "(min %d chars)",
58
+ emptyWarning: "cannot be empty",
59
+ upperLimitWarning: "over the limit",
60
+ lowerLimitWarning: "below the limit"
61
+ },
62
+ questions: {
63
+ type: {
64
+ description: "Select the type of change you're committing:",
65
+ enum: createTypeEnum(emojis)
66
+ },
67
+ scope: scopeQuestion,
68
+ subject: { description: "Write a short, imperative description of the change:" },
69
+ body: { description: "Provide a longer description of the change (optional):" },
70
+ isBreaking: { description: "Are there any breaking changes?" },
71
+ breakingBody: { description: "Describe the breaking changes:" },
72
+ isIssueAffected: { description: "Does this change affect any open issues?" },
73
+ issuesBody: { description: "Add issue references (e.g., 'fix #123', 'close #456'):" }
74
+ }
75
+ };
76
+ }
77
+ /**
78
+ * Default prompt configuration (no emojis).
79
+ *
80
+ * @public
81
+ */
82
+ const defaultPromptConfig = createPromptConfig();
83
+ /**
84
+ * Prompt configuration with emojis enabled.
85
+ *
86
+ * @public
87
+ */
88
+ const emojiPromptConfig = createPromptConfig({ emojis: true });
89
+
90
+ //#endregion
91
+ export { createPromptConfig, createTypeEnum, defaultPromptConfig, emojiPromptConfig };
@@ -0,0 +1,74 @@
1
+ //#region src/commitlint/prompt/emojis.ts
2
+ /**
3
+ * Emoji shortcode mapping for commit types.
4
+ *
5
+ * @remarks
6
+ * Uses GitHub/GitLab compatible shortcodes (e.g., `:sparkles:`) that
7
+ * render as emojis in Markdown contexts and web UIs.
8
+ *
9
+ * @public
10
+ */
11
+ const TYPE_EMOJIS = {
12
+ ai: ":robot:",
13
+ feat: ":sparkles:",
14
+ fix: ":bug:",
15
+ docs: ":memo:",
16
+ style: ":lipstick:",
17
+ refactor: ":recycle:",
18
+ perf: ":zap:",
19
+ test: ":white_check_mark:",
20
+ tdd: ":test_tube:",
21
+ build: ":package:",
22
+ ci: ":construction_worker:",
23
+ chore: ":wrench:",
24
+ revert: ":rewind:",
25
+ release: ":bookmark:"
26
+ };
27
+ /**
28
+ * Unicode emoji mapping for commit types.
29
+ *
30
+ * @remarks
31
+ * Uses actual Unicode emojis for terminals and contexts that
32
+ * support direct emoji rendering.
33
+ *
34
+ * @public
35
+ */
36
+ const TYPE_EMOJIS_UNICODE = {
37
+ ai: "🤖",
38
+ feat: "✨",
39
+ fix: "🐛",
40
+ docs: "📝",
41
+ style: "💄",
42
+ refactor: "♻️",
43
+ perf: "⚡",
44
+ test: "✅",
45
+ tdd: "🫪",
46
+ build: "📦",
47
+ ci: "👷",
48
+ chore: "🔧",
49
+ revert: "⏪",
50
+ release: "🔖"
51
+ };
52
+ /**
53
+ * Get emoji for a commit type.
54
+ *
55
+ * @param type - Commit type
56
+ * @param unicode - Use Unicode emojis instead of shortcodes
57
+ * @returns Emoji string (shortcode or Unicode)
58
+ *
59
+ * @public
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * import { getTypeEmoji } from "@savvy-web/commitlint/prompt";
64
+ *
65
+ * getTypeEmoji("feat"); // ":sparkles:"
66
+ * getTypeEmoji("feat", true); // "✨"
67
+ * ```
68
+ */
69
+ function getTypeEmoji(type, unicode = false) {
70
+ return unicode ? TYPE_EMOJIS_UNICODE[type] : TYPE_EMOJIS[type];
71
+ }
72
+
73
+ //#endregion
74
+ export { TYPE_EMOJIS, TYPE_EMOJIS_UNICODE, getTypeEmoji };
@@ -0,0 +1,135 @@
1
+ import { COMMIT_TYPE_DEFINITIONS } from "../config/rules.js";
2
+ import { TYPE_EMOJIS_UNICODE } from "./emojis.js";
3
+
4
+ //#region src/commitlint/prompt/prompter.ts
5
+ /** Default prompter options */
6
+ const DEFAULT_OPTIONS = {
7
+ emojis: true,
8
+ scopes: [],
9
+ maxSubjectLength: 100,
10
+ maxBodyLength: 300
11
+ };
12
+ /**
13
+ * Build type choices for the prompt.
14
+ */
15
+ function buildTypeChoices(emojis) {
16
+ return COMMIT_TYPE_DEFINITIONS.map((def) => {
17
+ const emoji = emojis ? TYPE_EMOJIS_UNICODE[def.type] : "";
18
+ return {
19
+ name: `${emoji ? `${emoji} ` : ""}${def.type}: ${def.description}`,
20
+ value: def.type
21
+ };
22
+ });
23
+ }
24
+ /**
25
+ * Build scope choices for the prompt.
26
+ */
27
+ function buildScopeChoices(scopes) {
28
+ return [{
29
+ name: "(none)",
30
+ value: ""
31
+ }, ...scopes.map((scope) => ({
32
+ name: scope,
33
+ value: scope
34
+ }))];
35
+ }
36
+ /**
37
+ * Format the final commit message.
38
+ */
39
+ function formatCommitMessage(answers) {
40
+ const { type, scope, subject, body, isBreaking, breakingBody, isIssueAffected, issues } = answers;
41
+ const parts = [`${type}${scope ? `(${scope})` : ""}${isBreaking ? "!" : ""}: ${subject}`];
42
+ if (body) parts.push("", body);
43
+ if (isBreaking && breakingBody) parts.push("", `BREAKING CHANGE: ${breakingBody}`);
44
+ if (isIssueAffected && issues) parts.push("", issues);
45
+ return parts.join("\n");
46
+ }
47
+ /**
48
+ * Commitizen prompter function.
49
+ *
50
+ * @remarks
51
+ * This is the main entry point for the commitizen adapter.
52
+ * It prompts the user for commit information and calls the
53
+ * commit callback with the formatted message.
54
+ *
55
+ * @param cz - Inquirer instance provided by commitizen
56
+ * @param commit - Callback to execute the commit
57
+ * @param options - Prompter options
58
+ *
59
+ * @public
60
+ */
61
+ function prompter(cz, commit, options = {}) {
62
+ const opts = {
63
+ ...DEFAULT_OPTIONS,
64
+ ...options
65
+ };
66
+ const scopeQuestion = opts.scopes.length > 0 ? {
67
+ type: "list",
68
+ name: "scope",
69
+ message: "Select the scope of this change:",
70
+ choices: buildScopeChoices(opts.scopes)
71
+ } : {
72
+ type: "input",
73
+ name: "scope",
74
+ message: "Scope of this change (press enter to skip):",
75
+ filter: (input) => input.trim().toLowerCase()
76
+ };
77
+ const questions = [
78
+ {
79
+ type: "list",
80
+ name: "type",
81
+ message: "Select the type of change you're committing:",
82
+ choices: buildTypeChoices(opts.emojis)
83
+ },
84
+ scopeQuestion,
85
+ {
86
+ type: "input",
87
+ name: "subject",
88
+ message: `Short description (max ${opts.maxSubjectLength} chars):`,
89
+ validate: (input) => {
90
+ if (!input.trim()) return "Subject is required";
91
+ if (input.length > opts.maxSubjectLength) return `Subject must be ${opts.maxSubjectLength} characters or less (currently ${input.length})`;
92
+ return true;
93
+ },
94
+ filter: (input) => {
95
+ const trimmed = input.trim();
96
+ return trimmed.charAt(0).toLowerCase() + trimmed.slice(1);
97
+ }
98
+ },
99
+ {
100
+ type: "input",
101
+ name: "body",
102
+ message: "Longer description (press enter to skip):"
103
+ },
104
+ {
105
+ type: "confirm",
106
+ name: "isBreaking",
107
+ message: "Are there any breaking changes?",
108
+ default: false
109
+ },
110
+ {
111
+ type: "input",
112
+ name: "breakingBody",
113
+ message: "Describe the breaking changes:",
114
+ when: (answers) => answers.isBreaking === true
115
+ },
116
+ {
117
+ type: "confirm",
118
+ name: "isIssueAffected",
119
+ message: "Does this change affect any open issues?",
120
+ default: false
121
+ },
122
+ {
123
+ type: "input",
124
+ name: "issues",
125
+ message: "Issue references (e.g., 'fix #123', 'closes #456'):",
126
+ when: (answers) => answers.isIssueAffected === true
127
+ }
128
+ ];
129
+ cz.prompt(questions).then((answers) => {
130
+ commit(formatCommitMessage(answers));
131
+ }).catch(() => {});
132
+ }
133
+
134
+ //#endregion
135
+ export { prompter };