habit-hooks 0.1.0-beta.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 (192) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +233 -0
  3. package/dist/baseline/commands.d.ts +12 -0
  4. package/dist/baseline/commands.js +131 -0
  5. package/dist/baseline/commands.js.map +1 -0
  6. package/dist/baseline/file-hash.d.ts +2 -0
  7. package/dist/baseline/file-hash.js +25 -0
  8. package/dist/baseline/file-hash.js.map +1 -0
  9. package/dist/baseline/filter.d.ts +8 -0
  10. package/dist/baseline/filter.js +31 -0
  11. package/dist/baseline/filter.js.map +1 -0
  12. package/dist/baseline/store.d.ts +18 -0
  13. package/dist/baseline/store.js +106 -0
  14. package/dist/baseline/store.js.map +1 -0
  15. package/dist/checks/comment-check.d.ts +3 -0
  16. package/dist/checks/comment-check.js +83 -0
  17. package/dist/checks/comment-check.js.map +1 -0
  18. package/dist/checks/eslint-wrap.d.ts +2 -0
  19. package/dist/checks/eslint-wrap.js +104 -0
  20. package/dist/checks/eslint-wrap.js.map +1 -0
  21. package/dist/checks/jscpd-wrap.d.ts +6 -0
  22. package/dist/checks/jscpd-wrap.js +158 -0
  23. package/dist/checks/jscpd-wrap.js.map +1 -0
  24. package/dist/checks/knip-resolve.d.ts +4 -0
  25. package/dist/checks/knip-resolve.js +49 -0
  26. package/dist/checks/knip-resolve.js.map +1 -0
  27. package/dist/checks/knip-schema.d.ts +32 -0
  28. package/dist/checks/knip-schema.js +24 -0
  29. package/dist/checks/knip-schema.js.map +1 -0
  30. package/dist/checks/knip-wrap.d.ts +4 -0
  31. package/dist/checks/knip-wrap.js +127 -0
  32. package/dist/checks/knip-wrap.js.map +1 -0
  33. package/dist/cli/baseline-commands.d.ts +2 -0
  34. package/dist/cli/baseline-commands.js +61 -0
  35. package/dist/cli/baseline-commands.js.map +1 -0
  36. package/dist/cli/emit.d.ts +7 -0
  37. package/dist/cli/emit.js +8 -0
  38. package/dist/cli/emit.js.map +1 -0
  39. package/dist/cli/init/detect.d.ts +8 -0
  40. package/dist/cli/init/detect.js +20 -0
  41. package/dist/cli/init/detect.js.map +1 -0
  42. package/dist/cli/init/git-hook.d.ts +6 -0
  43. package/dist/cli/init/git-hook.js +48 -0
  44. package/dist/cli/init/git-hook.js.map +1 -0
  45. package/dist/cli/init/install-commands.d.ts +6 -0
  46. package/dist/cli/init/install-commands.js +55 -0
  47. package/dist/cli/init/install-commands.js.map +1 -0
  48. package/dist/cli/init/package-scripts.d.ts +6 -0
  49. package/dist/cli/init/package-scripts.js +55 -0
  50. package/dist/cli/init/package-scripts.js.map +1 -0
  51. package/dist/cli/init/prompts.d.ts +9 -0
  52. package/dist/cli/init/prompts.js +33 -0
  53. package/dist/cli/init/prompts.js.map +1 -0
  54. package/dist/cli/init/reporters.d.ts +11 -0
  55. package/dist/cli/init/reporters.js +40 -0
  56. package/dist/cli/init/reporters.js.map +1 -0
  57. package/dist/cli/init/run.d.ts +12 -0
  58. package/dist/cli/init/run.js +159 -0
  59. package/dist/cli/init/run.js.map +1 -0
  60. package/dist/cli/init/scaffold-baseline.d.ts +4 -0
  61. package/dist/cli/init/scaffold-baseline.js +11 -0
  62. package/dist/cli/init/scaffold-baseline.js.map +1 -0
  63. package/dist/cli/init/scaffold-config.d.ts +13 -0
  64. package/dist/cli/init/scaffold-config.js +42 -0
  65. package/dist/cli/init/scaffold-config.js.map +1 -0
  66. package/dist/cli/init/scaffold-eslint-config.d.ts +2 -0
  67. package/dist/cli/init/scaffold-eslint-config.js +12 -0
  68. package/dist/cli/init/scaffold-eslint-config.js.map +1 -0
  69. package/dist/cli/init/scaffold-jscpd-config.d.ts +2 -0
  70. package/dist/cli/init/scaffold-jscpd-config.js +12 -0
  71. package/dist/cli/init/scaffold-jscpd-config.js.map +1 -0
  72. package/dist/cli/init/scaffold-knip-config.d.ts +2 -0
  73. package/dist/cli/init/scaffold-knip-config.js +12 -0
  74. package/dist/cli/init/scaffold-knip-config.js.map +1 -0
  75. package/dist/cli/init/skill.d.ts +7 -0
  76. package/dist/cli/init/skill.js +36 -0
  77. package/dist/cli/init/skill.js.map +1 -0
  78. package/dist/cli/init/snippet.d.ts +1 -0
  79. package/dist/cli/init/snippet.js +18 -0
  80. package/dist/cli/init/snippet.js.map +1 -0
  81. package/dist/cli/init/templates/eslint-config.d.ts +2 -0
  82. package/dist/cli/init/templates/eslint-config.js +35 -0
  83. package/dist/cli/init/templates/eslint-config.js.map +1 -0
  84. package/dist/cli/init/templates/jscpd-config.d.ts +2 -0
  85. package/dist/cli/init/templates/jscpd-config.js +9 -0
  86. package/dist/cli/init/templates/jscpd-config.js.map +1 -0
  87. package/dist/cli/init/templates/knip-config.d.ts +2 -0
  88. package/dist/cli/init/templates/knip-config.js +8 -0
  89. package/dist/cli/init/templates/knip-config.js.map +1 -0
  90. package/dist/cli/init-command.d.ts +2 -0
  91. package/dist/cli/init-command.js +33 -0
  92. package/dist/cli/init-command.js.map +1 -0
  93. package/dist/cli.d.ts +2 -0
  94. package/dist/cli.js +101 -0
  95. package/dist/cli.js.map +1 -0
  96. package/dist/config/defaults.d.ts +4 -0
  97. package/dist/config/defaults.js +172 -0
  98. package/dist/config/defaults.js.map +1 -0
  99. package/dist/config/jiti-loader.d.ts +1 -0
  100. package/dist/config/jiti-loader.js +13 -0
  101. package/dist/config/jiti-loader.js.map +1 -0
  102. package/dist/config/load.d.ts +8 -0
  103. package/dist/config/load.js +53 -0
  104. package/dist/config/load.js.map +1 -0
  105. package/dist/config/merge.d.ts +3 -0
  106. package/dist/config/merge.js +90 -0
  107. package/dist/config/merge.js.map +1 -0
  108. package/dist/config/schema.d.ts +32 -0
  109. package/dist/config/schema.js +4 -0
  110. package/dist/config/schema.js.map +1 -0
  111. package/dist/config/validate.d.ts +2 -0
  112. package/dist/config/validate.js +128 -0
  113. package/dist/config/validate.js.map +1 -0
  114. package/dist/detect/package-json.d.ts +1 -0
  115. package/dist/detect/package-json.js +15 -0
  116. package/dist/detect/package-json.js.map +1 -0
  117. package/dist/detect/tool.d.ts +10 -0
  118. package/dist/detect/tool.js +73 -0
  119. package/dist/detect/tool.js.map +1 -0
  120. package/dist/eslint-runner.d.ts +7 -0
  121. package/dist/eslint-runner.js +34 -0
  122. package/dist/eslint-runner.js.map +1 -0
  123. package/dist/git/exec.d.ts +8 -0
  124. package/dist/git/exec.js +48 -0
  125. package/dist/git/exec.js.map +1 -0
  126. package/dist/git/resolve-scope.d.ts +15 -0
  127. package/dist/git/resolve-scope.js +89 -0
  128. package/dist/git/resolve-scope.js.map +1 -0
  129. package/dist/git/scope.d.ts +7 -0
  130. package/dist/git/scope.js +58 -0
  131. package/dist/git/scope.js.map +1 -0
  132. package/dist/index.d.ts +1 -0
  133. package/dist/index.js +2 -0
  134. package/dist/index.js.map +1 -0
  135. package/dist/prompts/loader.d.ts +6 -0
  136. package/dist/prompts/loader.js +27 -0
  137. package/dist/prompts/loader.js.map +1 -0
  138. package/dist/prompts/packaged-dir.d.ts +1 -0
  139. package/dist/prompts/packaged-dir.js +10 -0
  140. package/dist/prompts/packaged-dir.js.map +1 -0
  141. package/dist/prompts/registry.d.ts +3 -0
  142. package/dist/prompts/registry.js +68 -0
  143. package/dist/prompts/registry.js.map +1 -0
  144. package/dist/reporter.d.ts +7 -0
  145. package/dist/reporter.js +114 -0
  146. package/dist/reporter.js.map +1 -0
  147. package/dist/rules/registry.d.ts +3 -0
  148. package/dist/rules/registry.js +37 -0
  149. package/dist/rules/registry.js.map +1 -0
  150. package/dist/runner.d.ts +15 -0
  151. package/dist/runner.js +151 -0
  152. package/dist/runner.js.map +1 -0
  153. package/dist/types.d.ts +41 -0
  154. package/dist/types.js +2 -0
  155. package/dist/types.js.map +1 -0
  156. package/dist/wrap/notices.d.ts +13 -0
  157. package/dist/wrap/notices.js +29 -0
  158. package/dist/wrap/notices.js.map +1 -0
  159. package/dist/wrap/resolve.d.ts +5 -0
  160. package/dist/wrap/resolve.js +9 -0
  161. package/dist/wrap/resolve.js.map +1 -0
  162. package/dist/wrap/run.d.ts +15 -0
  163. package/dist/wrap/run.js +26 -0
  164. package/dist/wrap/run.js.map +1 -0
  165. package/dist/wrap/shell.d.ts +14 -0
  166. package/dist/wrap/shell.js +44 -0
  167. package/dist/wrap/shell.js.map +1 -0
  168. package/package.json +46 -0
  169. package/src/prompts/comment-non-essential.md +7 -0
  170. package/src/prompts/eslint-boundaries-dependencies.md +9 -0
  171. package/src/prompts/eslint-complexity.md +9 -0
  172. package/src/prompts/eslint-eqeqeq.md +3 -0
  173. package/src/prompts/eslint-fatal.md +7 -0
  174. package/src/prompts/eslint-max-lines-per-function.md +9 -0
  175. package/src/prompts/eslint-max-lines.md +9 -0
  176. package/src/prompts/eslint-max-params.md +9 -0
  177. package/src/prompts/eslint-no-duplicate-imports.md +1 -0
  178. package/src/prompts/eslint-no-unused-vars.md +3 -0
  179. package/src/prompts/eslint-no-var.md +1 -0
  180. package/src/prompts/eslint-no-warning-comments.md +3 -0
  181. package/src/prompts/eslint-prefer-const.md +3 -0
  182. package/src/prompts/eslint-typescript-eslint-no-explicit-any.md +3 -0
  183. package/src/prompts/eslint-typescript-eslint-no-inferrable-types.md +3 -0
  184. package/src/prompts/eslint-typescript-eslint-no-non-null-assertion.md +3 -0
  185. package/src/prompts/jscpd-duplication.md +9 -0
  186. package/src/prompts/knip-classMembers.md +7 -0
  187. package/src/prompts/knip-dependencies.md +9 -0
  188. package/src/prompts/knip-exports.md +9 -0
  189. package/src/prompts/knip-files.md +9 -0
  190. package/src/prompts/knip-types.md +9 -0
  191. package/src/prompts/uncoached.md +3 -0
  192. package/src/skills/habit-hooks-review/SKILL.md +108 -0
@@ -0,0 +1,172 @@
1
+ const tier1Rules = [
2
+ {
3
+ id: 'eslint:max-lines-per-function',
4
+ source: 'eslint',
5
+ sourceRuleId: 'max-lines-per-function',
6
+ severity: 'enforced',
7
+ changedFilesOnly: true,
8
+ title: 'Oversized function',
9
+ description: 'Functions over 12 lines tend to bundle multiple responsibilities.',
10
+ },
11
+ {
12
+ id: 'eslint:max-params',
13
+ source: 'eslint',
14
+ sourceRuleId: 'max-params',
15
+ severity: 'enforced',
16
+ changedFilesOnly: false,
17
+ title: 'Too many parameters',
18
+ description: 'Functions with many parameters violate single responsibility.',
19
+ },
20
+ {
21
+ id: 'eslint:complexity',
22
+ source: 'eslint',
23
+ sourceRuleId: 'complexity',
24
+ severity: 'enforced',
25
+ changedFilesOnly: true,
26
+ title: 'High cyclomatic complexity',
27
+ description: 'Complex functions are harder to understand, test, and maintain.',
28
+ },
29
+ {
30
+ id: 'eslint:max-lines',
31
+ source: 'eslint',
32
+ sourceRuleId: 'max-lines',
33
+ severity: 'enforced',
34
+ changedFilesOnly: true,
35
+ title: 'Oversized file',
36
+ description: 'Files over 200 lines are extremely difficult to maintain.',
37
+ },
38
+ ];
39
+ const tier2Rules = [
40
+ {
41
+ id: 'eslint:no-unused-vars',
42
+ source: 'eslint',
43
+ sourceRuleId: 'no-unused-vars',
44
+ severity: 'enforced',
45
+ changedFilesOnly: false,
46
+ title: 'Unused variable',
47
+ description: 'Unused bindings are dead weight; remove them or rename with a leading underscore if intentional.',
48
+ },
49
+ {
50
+ id: 'eslint:eqeqeq',
51
+ source: 'eslint',
52
+ sourceRuleId: 'eqeqeq',
53
+ severity: 'enforced',
54
+ changedFilesOnly: false,
55
+ title: 'Loose equality',
56
+ description: 'Use === / !== to avoid silent coercion bugs.',
57
+ },
58
+ {
59
+ id: 'eslint:no-var',
60
+ source: 'eslint',
61
+ sourceRuleId: 'no-var',
62
+ severity: 'enforced',
63
+ changedFilesOnly: false,
64
+ title: 'var declaration',
65
+ description: 'Use let or const; var hoists in surprising ways.',
66
+ },
67
+ {
68
+ id: 'eslint:prefer-const',
69
+ source: 'eslint',
70
+ sourceRuleId: 'prefer-const',
71
+ severity: 'enforced',
72
+ changedFilesOnly: false,
73
+ title: 'Reassignable binding never reassigned',
74
+ description: 'A let that is never reassigned should be const.',
75
+ },
76
+ {
77
+ id: 'eslint:no-duplicate-imports',
78
+ source: 'eslint',
79
+ sourceRuleId: 'no-duplicate-imports',
80
+ severity: 'enforced',
81
+ changedFilesOnly: false,
82
+ title: 'Duplicate import',
83
+ description: 'Merge multiple imports from the same module into a single statement.',
84
+ },
85
+ {
86
+ id: 'eslint:no-warning-comments',
87
+ source: 'eslint',
88
+ sourceRuleId: 'no-warning-comments',
89
+ severity: 'suggested',
90
+ changedFilesOnly: false,
91
+ title: 'Warning comment',
92
+ description: 'TODO / FIXME / XXX / HACK markers are unfinished work in the codebase.',
93
+ },
94
+ ];
95
+ const tier3Rules = [
96
+ {
97
+ id: 'eslint:@typescript-eslint/no-explicit-any',
98
+ source: 'eslint',
99
+ sourceRuleId: '@typescript-eslint/no-explicit-any',
100
+ severity: 'suggested',
101
+ changedFilesOnly: true,
102
+ title: 'Explicit any',
103
+ description: 'any disables the type checker; prefer a precise type or unknown plus a narrow.',
104
+ },
105
+ {
106
+ id: 'eslint:@typescript-eslint/no-non-null-assertion',
107
+ source: 'eslint',
108
+ sourceRuleId: '@typescript-eslint/no-non-null-assertion',
109
+ severity: 'suggested',
110
+ changedFilesOnly: true,
111
+ title: 'Non-null assertion',
112
+ description: 'The ! operator silences the type system; prove the value is present with a check.',
113
+ },
114
+ {
115
+ id: 'eslint:@typescript-eslint/no-inferrable-types',
116
+ source: 'eslint',
117
+ sourceRuleId: '@typescript-eslint/no-inferrable-types',
118
+ severity: 'enforced',
119
+ changedFilesOnly: false,
120
+ title: 'Redundant type annotation',
121
+ description: 'TypeScript infers obvious types; drop the annotation when it adds no information.',
122
+ },
123
+ ];
124
+ const customRules = [
125
+ {
126
+ id: 'comment:non-essential',
127
+ source: 'custom',
128
+ severity: 'suggested',
129
+ changedFilesOnly: true,
130
+ title: 'Comment found',
131
+ description: 'Comments indicate code that is not self-documenting.',
132
+ },
133
+ ];
134
+ const jscpdRules = [
135
+ {
136
+ id: 'jscpd:duplication',
137
+ source: 'jscpd',
138
+ severity: 'suggested',
139
+ changedFilesOnly: true,
140
+ title: 'Duplicated code',
141
+ description: 'Repeated blocks usually want a shared abstraction, not a copy-paste.',
142
+ },
143
+ ];
144
+ const knipRules = [
145
+ {
146
+ id: 'knip:classMembers',
147
+ source: 'knip',
148
+ severity: 'enforced',
149
+ changedFilesOnly: false,
150
+ title: 'Unused class member',
151
+ description: 'Class methods or properties not referenced anywhere are dead weight.',
152
+ },
153
+ ];
154
+ export const defaultRules = [
155
+ ...tier1Rules,
156
+ ...tier2Rules,
157
+ ...tier3Rules,
158
+ ...customRules,
159
+ ...jscpdRules,
160
+ ...knipRules,
161
+ ];
162
+ const TEST_FILE_EXCLUDE = ['**/*.test.ts', '**/*.spec.ts', 'tests/**'];
163
+ const CONFIG_FILE_EXCLUDE = ['habit-hooks.config.*'];
164
+ export const defaultConfig = {
165
+ rules: {
166
+ 'eslint:max-lines-per-function': { exclude: TEST_FILE_EXCLUDE },
167
+ 'eslint:max-lines': { exclude: TEST_FILE_EXCLUDE },
168
+ 'jscpd:duplication': { exclude: TEST_FILE_EXCLUDE },
169
+ 'comment:non-essential': { exclude: CONFIG_FILE_EXCLUDE },
170
+ },
171
+ };
172
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function loadTsModule(absolutePath: string): Promise<unknown>;
@@ -0,0 +1,13 @@
1
+ import { createJiti } from 'jiti';
2
+ let cached = null;
3
+ function getJiti() {
4
+ if (cached)
5
+ return cached;
6
+ cached = createJiti(import.meta.url, { interopDefault: true });
7
+ return cached;
8
+ }
9
+ export async function loadTsModule(absolutePath) {
10
+ const jiti = getJiti();
11
+ return jiti.import(absolutePath, { default: true });
12
+ }
13
+ //# sourceMappingURL=jiti-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jiti-loader.js","sourceRoot":"","sources":["../../src/config/jiti-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAa,MAAM,MAAM,CAAC;AAE7C,IAAI,MAAM,GAAgB,IAAI,CAAC;AAE/B,SAAS,OAAO;IACd,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/D,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,YAAoB;IACrD,MAAM,IAAI,GAAG,OAAO,EAAE,CAAC;IACvB,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;AACtD,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { HabitHooksConfig } from './schema.js';
2
+ interface LoadedConfig {
3
+ config: HabitHooksConfig;
4
+ sourcePath: string | null;
5
+ }
6
+ export declare function loadConfig(cwd: string): Promise<LoadedConfig>;
7
+ export declare function loadConfigFromPath(path: string): Promise<LoadedConfig>;
8
+ export {};
@@ -0,0 +1,53 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ import { pathToFileURL } from 'node:url';
4
+ import { validateConfig } from './validate.js';
5
+ import { loadTsModule } from './jiti-loader.js';
6
+ const CONFIG_FILENAMES = [
7
+ 'habit-hooks.config.ts',
8
+ 'habit-hooks.config.mjs',
9
+ 'habit-hooks.config.js',
10
+ 'habit-hooks.config.json',
11
+ ];
12
+ function findConfigFile(cwd) {
13
+ for (const name of CONFIG_FILENAMES) {
14
+ const candidate = join(cwd, name);
15
+ if (existsSync(candidate))
16
+ return candidate;
17
+ }
18
+ return null;
19
+ }
20
+ function unwrapDefault(mod) {
21
+ if (mod && typeof mod === 'object' && 'default' in mod) {
22
+ return mod.default;
23
+ }
24
+ return mod;
25
+ }
26
+ async function readConfigFile(path) {
27
+ if (path.endsWith('.json')) {
28
+ return JSON.parse(readFileSync(path, 'utf8'));
29
+ }
30
+ if (path.endsWith('.ts')) {
31
+ return loadTsModule(path);
32
+ }
33
+ const mod = (await import(pathToFileURL(path).href));
34
+ return unwrapDefault(mod);
35
+ }
36
+ export async function loadConfig(cwd) {
37
+ const sourcePath = findConfigFile(cwd);
38
+ if (sourcePath === null) {
39
+ return { config: {}, sourcePath: null };
40
+ }
41
+ const raw = await readConfigFile(sourcePath);
42
+ const config = validateConfig(raw);
43
+ return { config, sourcePath };
44
+ }
45
+ export async function loadConfigFromPath(path) {
46
+ if (!existsSync(path)) {
47
+ throw new Error(`Config file not found: ${path}`);
48
+ }
49
+ const raw = await readConfigFile(path);
50
+ const config = validateConfig(raw);
51
+ return { config, sourcePath: path };
52
+ }
53
+ //# sourceMappingURL=load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,MAAM,gBAAgB,GAAG;IACvB,uBAAuB;IACvB,wBAAwB;IACxB,uBAAuB;IACvB,yBAAyB;CAC1B,CAAC;AAOF,SAAS,cAAc,CAAC,GAAW;IACjC,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAClC,IAAI,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO,SAAS,CAAC;IAC9C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,aAAa,CAAC,GAAY;IACjC,IAAI,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,SAAS,IAAI,GAAG,EAAE,CAAC;QACvD,OAAQ,GAA4B,CAAC,OAAO,CAAC;IAC/C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,IAAY;IACxC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IACD,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAY,CAAC;IAChE,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,MAAM,UAAU,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;QACxB,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAC1C,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,UAAU,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACnC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAY;IACnD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,EAAE,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IACnC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;AACtC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Rule } from '../types.js';
2
+ import { type HabitHooksConfig } from './schema.js';
3
+ export declare function mergeRules(defaultRules: Rule[], ...overrideSources: (HabitHooksConfig['rules'] | undefined)[]): Rule[];
@@ -0,0 +1,90 @@
1
+ import { isRuleDefinition, } from './schema.js';
2
+ function pickDefined(source) {
3
+ const result = {};
4
+ for (const key of Object.keys(source)) {
5
+ if (source[key] !== undefined)
6
+ result[key] = source[key];
7
+ }
8
+ return result;
9
+ }
10
+ function stripMetaFields(override) {
11
+ const { disabled, ...rest } = override;
12
+ void disabled;
13
+ return rest;
14
+ }
15
+ function applyOverride(base, override) {
16
+ return { ...base, ...pickDefined(stripMetaFields(override)) };
17
+ }
18
+ function pickRuleCore(def) {
19
+ return {
20
+ source: def.source,
21
+ sourceRuleId: def.sourceRuleId,
22
+ severity: def.severity ?? 'suggested',
23
+ changedFilesOnly: def.changedFilesOnly ?? false,
24
+ };
25
+ }
26
+ function pickRuleDisplay(id, def) {
27
+ return {
28
+ title: def.title ?? id,
29
+ description: def.description ?? '',
30
+ include: def.include,
31
+ exclude: def.exclude,
32
+ };
33
+ }
34
+ function buildCustomRule(id, def) {
35
+ return { id, ...pickRuleCore(def), ...pickRuleDisplay(id, def) };
36
+ }
37
+ function mergeEntry(existing, entry) {
38
+ if (!existing || isRuleDefinition(existing) || isRuleDefinition(entry))
39
+ return entry;
40
+ return { ...existing, ...entry };
41
+ }
42
+ function mergeOverrideMaps(sources) {
43
+ const merged = new Map();
44
+ for (const source of sources) {
45
+ if (!source)
46
+ continue;
47
+ for (const [id, entry] of Object.entries(source)) {
48
+ merged.set(id, mergeEntry(merged.get(id), entry));
49
+ }
50
+ }
51
+ return merged;
52
+ }
53
+ function resolveDefaultRule(rule, entry) {
54
+ if (entry === undefined)
55
+ return rule;
56
+ if (isRuleDefinition(entry))
57
+ return buildCustomRule(rule.id, entry);
58
+ if (entry.disabled === true)
59
+ return null;
60
+ return applyOverride(rule, entry);
61
+ }
62
+ function resolveNewRule(id, entry) {
63
+ if (!isRuleDefinition(entry)) {
64
+ throw new Error(`Invalid habit-hooks config: rules.${id} is not a built-in rule and is missing 'source'`);
65
+ }
66
+ if (entry.disabled === true)
67
+ return null;
68
+ return buildCustomRule(id, entry);
69
+ }
70
+ function applyDefaults(defaultRules, entries, seen) {
71
+ return defaultRules.flatMap((rule) => {
72
+ seen.add(rule.id);
73
+ const resolved = resolveDefaultRule(rule, entries.get(rule.id));
74
+ return resolved ? [resolved] : [];
75
+ });
76
+ }
77
+ function collectNewRules(entries, seen) {
78
+ return [...entries].flatMap(([id, entry]) => {
79
+ if (seen.has(id))
80
+ return [];
81
+ const resolved = resolveNewRule(id, entry);
82
+ return resolved ? [resolved] : [];
83
+ });
84
+ }
85
+ export function mergeRules(defaultRules, ...overrideSources) {
86
+ const entries = mergeOverrideMaps(overrideSources);
87
+ const seen = new Set();
88
+ return [...applyDefaults(defaultRules, entries, seen), ...collectNewRules(entries, seen)];
89
+ }
90
+ //# sourceMappingURL=merge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/config/merge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import type { RuleSource, Severity } from '../types.js';
2
+ export interface RuleOverride {
3
+ severity?: Severity;
4
+ changedFilesOnly?: boolean;
5
+ title?: string;
6
+ description?: string;
7
+ disabled?: boolean;
8
+ include?: string[];
9
+ exclude?: string[];
10
+ }
11
+ export interface RuleDefinition extends RuleOverride {
12
+ id: string;
13
+ source: RuleSource;
14
+ sourceRuleId?: string;
15
+ }
16
+ export interface ScopeConfig {
17
+ onlyChangedFiles?: boolean;
18
+ autoBranchOffMain?: boolean;
19
+ branchBase?: string;
20
+ mainBranch?: string;
21
+ }
22
+ export interface CommentCheckConfig {
23
+ maxSingleLineChars?: number;
24
+ maxBlockChars?: number;
25
+ }
26
+ export interface HabitHooksConfig {
27
+ prompts?: string;
28
+ rules?: Record<string, RuleOverride | RuleDefinition>;
29
+ scope?: ScopeConfig;
30
+ commentCheck?: CommentCheckConfig;
31
+ }
32
+ export declare function isRuleDefinition(entry: RuleOverride | RuleDefinition): entry is RuleDefinition;
@@ -0,0 +1,4 @@
1
+ export function isRuleDefinition(entry) {
2
+ return 'source' in entry && typeof entry.source === 'string';
3
+ }
4
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAqCA,MAAM,UAAU,gBAAgB,CAC9B,KAAoC;IAEpC,OAAO,QAAQ,IAAI,KAAK,IAAI,OAAQ,KAAwB,CAAC,MAAM,KAAK,QAAQ,CAAC;AACnF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { HabitHooksConfig } from './schema.js';
2
+ export declare function validateConfig(value: unknown): HabitHooksConfig;
@@ -0,0 +1,128 @@
1
+ const SEVERITIES = ['enforced', 'suggested'];
2
+ const SOURCES = ['eslint', 'jscpd', 'custom'];
3
+ function isPlainObject(value) {
4
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
5
+ }
6
+ function isStringArray(value) {
7
+ return Array.isArray(value) && value.every((entry) => typeof entry === 'string');
8
+ }
9
+ function fail(path, expected) {
10
+ throw new Error(`Invalid habit-hooks config: ${path} must be ${expected}`);
11
+ }
12
+ function validateOptionalString(value, path) {
13
+ if (value === undefined)
14
+ return;
15
+ if (typeof value !== 'string')
16
+ fail(path, 'a string');
17
+ }
18
+ function validateOptionalBoolean(value, path) {
19
+ if (value === undefined)
20
+ return;
21
+ if (typeof value !== 'boolean')
22
+ fail(path, 'a boolean');
23
+ }
24
+ function validateOptionalStringArray(value, path) {
25
+ if (value === undefined)
26
+ return;
27
+ if (!isStringArray(value))
28
+ fail(path, 'an array of strings');
29
+ }
30
+ function validateSeverity(value, path) {
31
+ if (value === undefined)
32
+ return;
33
+ if (typeof value !== 'string' || !SEVERITIES.includes(value)) {
34
+ fail(path, `'enforced' or 'suggested'`);
35
+ }
36
+ }
37
+ function validateSource(value, path) {
38
+ if (typeof value !== 'string' || !SOURCES.includes(value)) {
39
+ fail(path, `one of 'eslint', 'jscpd', 'custom'`);
40
+ }
41
+ }
42
+ function validateRuleOverrideFields(entry, base) {
43
+ validateSeverity(entry.severity, `${base}.severity`);
44
+ validateOptionalBoolean(entry.changedFilesOnly, `${base}.changedFilesOnly`);
45
+ validateOptionalString(entry.title, `${base}.title`);
46
+ validateOptionalString(entry.description, `${base}.description`);
47
+ validateOptionalBoolean(entry.disabled, `${base}.disabled`);
48
+ validateOptionalStringArray(entry.include, `${base}.include`);
49
+ validateOptionalStringArray(entry.exclude, `${base}.exclude`);
50
+ }
51
+ function validateRuleDefinitionFields(entry, base) {
52
+ if (typeof entry.id !== 'string')
53
+ fail(`${base}.id`, 'a string');
54
+ validateSource(entry.source, `${base}.source`);
55
+ validateOptionalString(entry.sourceRuleId, `${base}.sourceRuleId`);
56
+ }
57
+ function validateRuleEntry(value, base) {
58
+ if (!isPlainObject(value))
59
+ fail(base, 'an object');
60
+ const entry = value;
61
+ validateRuleOverrideFields(entry, base);
62
+ if ('source' in entry) {
63
+ validateRuleDefinitionFields(entry, base);
64
+ }
65
+ return entry;
66
+ }
67
+ function validateRules(value) {
68
+ if (value === undefined)
69
+ return undefined;
70
+ if (!isPlainObject(value))
71
+ fail('rules', 'an object keyed by rule id');
72
+ const result = {};
73
+ for (const [key, entry] of Object.entries(value)) {
74
+ result[key] = validateRuleEntry(entry, `rules.${key}`);
75
+ }
76
+ return result;
77
+ }
78
+ function validateScope(value) {
79
+ if (value === undefined)
80
+ return undefined;
81
+ if (!isPlainObject(value))
82
+ fail('scope', 'an object');
83
+ validateOptionalBoolean(value.onlyChangedFiles, 'scope.onlyChangedFiles');
84
+ validateOptionalBoolean(value.autoBranchOffMain, 'scope.autoBranchOffMain');
85
+ validateOptionalString(value.branchBase, 'scope.branchBase');
86
+ validateOptionalString(value.mainBranch, 'scope.mainBranch');
87
+ return value;
88
+ }
89
+ function validatePositiveInteger(value, path) {
90
+ if (value === undefined)
91
+ return;
92
+ if (typeof value !== 'number' || !Number.isInteger(value) || value <= 0) {
93
+ fail(path, 'a positive integer');
94
+ }
95
+ }
96
+ function validateCommentCheck(value) {
97
+ if (value === undefined)
98
+ return undefined;
99
+ if (!isPlainObject(value))
100
+ fail('commentCheck', 'an object');
101
+ validatePositiveInteger(value.maxSingleLineChars, 'commentCheck.maxSingleLineChars');
102
+ validatePositiveInteger(value.maxBlockChars, 'commentCheck.maxBlockChars');
103
+ return value;
104
+ }
105
+ function assembleConfig(parts) {
106
+ const config = {};
107
+ if (parts.prompts !== undefined)
108
+ config.prompts = parts.prompts;
109
+ if (parts.rules !== undefined)
110
+ config.rules = parts.rules;
111
+ if (parts.scope !== undefined)
112
+ config.scope = parts.scope;
113
+ if (parts.commentCheck !== undefined)
114
+ config.commentCheck = parts.commentCheck;
115
+ return config;
116
+ }
117
+ export function validateConfig(value) {
118
+ if (!isPlainObject(value))
119
+ fail('config', 'an object');
120
+ validateOptionalString(value.prompts, 'prompts');
121
+ return assembleConfig({
122
+ prompts: typeof value.prompts === 'string' ? value.prompts : undefined,
123
+ rules: validateRules(value.rules),
124
+ scope: validateScope(value.scope),
125
+ commentCheck: validateCommentCheck(value.commentCheck),
126
+ });
127
+ }
128
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/config/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function hasPackageJsonKey(cwd: string, key: string): boolean;
@@ -0,0 +1,15 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ export function hasPackageJsonKey(cwd, key) {
4
+ const path = join(cwd, 'package.json');
5
+ if (!existsSync(path))
6
+ return false;
7
+ try {
8
+ const pkg = JSON.parse(readFileSync(path, 'utf8'));
9
+ return pkg[key] !== undefined;
10
+ }
11
+ catch {
12
+ return false;
13
+ }
14
+ }
15
+ //# sourceMappingURL=package-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package-json.js","sourceRoot":"","sources":["../../src/detect/package-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,GAAW;IACxD,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IACvC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAA4B,CAAC;QAC9E,OAAO,GAAG,CAAC,GAAG,CAAC,KAAK,SAAS,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,10 @@
1
+ export type ToolName = 'eslint' | 'knip' | 'jscpd';
2
+ interface ToolDetection {
3
+ available: true;
4
+ binPath: string;
5
+ configPath: string | null;
6
+ }
7
+ export declare const TOOL_CONFIG_FILENAMES: Record<ToolName, readonly string[]>;
8
+ export declare const TOOL_PACKAGE_JSON_KEYS: Record<ToolName, string>;
9
+ export declare function detectTool(cwd: string, name: string): ToolDetection | null;
10
+ export {};