sumulige-claude 1.5.1 β†’ 1.6.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 (223) hide show
  1. package/.claude/hooks/hook-registry.json +0 -15
  2. package/.claude/rules/coding-style.md +18 -7
  3. package/.claude/rules/hooks.md +15 -4
  4. package/.claude/rules/performance.md +15 -5
  5. package/.claude/rules/security.md +140 -4
  6. package/.claude/rules/testing.md +138 -9
  7. package/.claude/rules/web-design-standard.md +16 -5
  8. package/.claude/skills/algorithmic-art/metadata.yaml +28 -0
  9. package/.claude/skills/api-tester/SKILL.md +61 -0
  10. package/.claude/skills/api-tester/examples/basic.md +3 -0
  11. package/.claude/skills/api-tester/metadata.yaml +30 -0
  12. package/.claude/skills/api-tester/templates/default.md +3 -0
  13. package/.claude/skills/brand-guidelines/metadata.yaml +26 -0
  14. package/.claude/skills/canvas-design/metadata.yaml +27 -0
  15. package/.claude/skills/code-reviewer-123/SKILL.md +61 -0
  16. package/.claude/skills/code-reviewer-123/examples/basic.md +3 -0
  17. package/.claude/skills/code-reviewer-123/metadata.yaml +30 -0
  18. package/.claude/skills/code-reviewer-123/templates/default.md +3 -0
  19. package/.claude/skills/doc-coauthoring/metadata.yaml +27 -0
  20. package/.claude/skills/docx/metadata.yaml +30 -0
  21. package/.claude/skills/frontend-design/metadata.yaml +28 -0
  22. package/.claude/skills/internal-comms/metadata.yaml +28 -0
  23. package/.claude/skills/mcp-builder/metadata.yaml +26 -0
  24. package/.claude/skills/my-skill/SKILL.md +61 -0
  25. package/.claude/skills/my-skill/examples/basic.md +3 -0
  26. package/.claude/skills/my-skill/metadata.yaml +30 -0
  27. package/.claude/skills/my-skill/templates/default.md +3 -0
  28. package/.claude/skills/pdf/metadata.yaml +29 -0
  29. package/.claude/skills/pptx/metadata.yaml +29 -0
  30. package/.claude/skills/react-best-practices/metadata.yaml +26 -0
  31. package/.claude/skills/react-node-practices/SKILL.md +409 -0
  32. package/.claude/skills/react-node-practices/metadata.yaml +56 -0
  33. package/.claude/skills/skill-creator/metadata.yaml +25 -0
  34. package/.claude/skills/slack-gif-creator/metadata.yaml +28 -0
  35. package/.claude/skills/test-skill-name/SKILL.md +61 -0
  36. package/.claude/skills/test-skill-name/examples/basic.md +3 -0
  37. package/.claude/skills/test-skill-name/metadata.yaml +30 -0
  38. package/.claude/skills/test-skill-name/templates/default.md +3 -0
  39. package/.claude/skills/test-workflow/metadata.yaml +32 -0
  40. package/.claude/skills/theme-factory/metadata.yaml +26 -0
  41. package/.claude/skills/threejs-fundamentals/metadata.yaml +27 -0
  42. package/.claude/skills/web-artifacts-builder/metadata.yaml +30 -0
  43. package/.claude/skills/web-design-guidelines/metadata.yaml +26 -0
  44. package/.claude/skills/webapp-testing/metadata.yaml +26 -0
  45. package/.claude/skills/xlsx/metadata.yaml +29 -0
  46. package/LICENSE +21 -0
  47. package/README.md +280 -529
  48. package/cli.js +19 -3
  49. package/package.json +29 -3
  50. package/template/.codex/README.md +69 -0
  51. package/template/.codex/config.toml +56 -0
  52. package/template/AGENTS.md +94 -0
  53. package/.claude/.kickoff-hint.txt +0 -52
  54. package/.claude/.sumulige-claude-version +0 -1
  55. package/.claude/.version +0 -1
  56. package/.claude/AGENTS.md +0 -42
  57. package/.claude/ANCHORS.md +0 -40
  58. package/.claude/CLAUDE.md +0 -138
  59. package/.claude/MEMORY.md +0 -69
  60. package/.claude/PROJECT_LOG.md +0 -101
  61. package/.claude/THINKING_CHAIN_GUIDE.md +0 -287
  62. package/.claude/USAGE.md +0 -175
  63. package/.claude/boris-optimizations.md +0 -167
  64. package/.claude/handoffs/INDEX.md +0 -21
  65. package/.claude/handoffs/LATEST.md +0 -76
  66. package/.claude/handoffs/handoff_2026-01-22T13-07-04-757Z.md +0 -76
  67. package/.claude/quality-gate.json +0 -82
  68. package/.claude/rag/skill-index.json +0 -135
  69. package/.claude/settings.json +0 -99
  70. package/.claude/settings.local.json +0 -175
  71. package/.claude/templates/PROJECT_KICKOFF.md +0 -89
  72. package/.claude/templates/PROJECT_PROPOSAL.md +0 -227
  73. package/.claude/templates/TASK_PLAN.md +0 -121
  74. package/.claude/templates/hooks/README.md +0 -302
  75. package/.claude/templates/hooks/hook.sh.template +0 -94
  76. package/.claude/templates/hooks/user-prompt-submit.cjs.template +0 -116
  77. package/.claude/templates/hooks/user-response-submit.cjs.template +0 -94
  78. package/.claude/templates/hooks/validate.js +0 -173
  79. package/.claude/templates/tasks/develop.md +0 -69
  80. package/.claude/templates/tasks/research.md +0 -64
  81. package/.claude/templates/tasks/test.md +0 -96
  82. package/.claude/thinking-routes/.last-sync +0 -1
  83. package/.claude/thinking-routes/QUICKREF.md +0 -98
  84. package/.claude/workflow/document-scanner.js +0 -426
  85. package/.claude/workflow/knowledge-engine.js +0 -941
  86. package/.claude/workflow/notebooklm/browser.js +0 -1028
  87. package/.claude/workflow/phases/phase1-research.js +0 -578
  88. package/.claude/workflow/phases/phase1-research.ts +0 -465
  89. package/.claude/workflow/phases/phase2-approve.js +0 -722
  90. package/.claude/workflow/phases/phase3-plan.js +0 -1200
  91. package/.claude/workflow/phases/phase4-develop.js +0 -894
  92. package/.claude/workflow/search-cache.js +0 -230
  93. package/.claude/workflow/templates/approval.md +0 -315
  94. package/.claude/workflow/templates/development.md +0 -377
  95. package/.claude/workflow/templates/planning.md +0 -328
  96. package/.claude/workflow/templates/research.md +0 -250
  97. package/.claude/workflow/types.js +0 -37
  98. package/.claude/workflow/web-search.js +0 -278
  99. package/.claude-plugin/marketplace.json +0 -71
  100. package/.github/workflows/sync-skills.yml +0 -74
  101. package/.versionrc +0 -25
  102. package/AGENTS.md +0 -580
  103. package/CHANGELOG.md +0 -481
  104. package/CLAUDE-template.md +0 -114
  105. package/DEV_TOOLS_GUIDE.md +0 -190
  106. package/PROJECT_STRUCTURE.md +0 -266
  107. package/Q&A.md +0 -325
  108. package/config/defaults.json +0 -34
  109. package/config/official-skills.json +0 -183
  110. package/config/quality-gate.json +0 -67
  111. package/config/skill-categories.json +0 -40
  112. package/config/version-manifest.json +0 -85
  113. package/demos/power-3d-scatter.html +0 -683
  114. package/development/cache/web-search/search_1193d605f8eb364651fc2f2041b58a31.json +0 -36
  115. package/development/cache/web-search/search_3798bf06960edc125f744a1abb5b72c5.json +0 -36
  116. package/development/cache/web-search/search_37c7d4843a53f0d83f1122a6f908a2a3.json +0 -36
  117. package/development/cache/web-search/search_44166fa0153709ee168485a22aa0ab40.json +0 -36
  118. package/development/cache/web-search/search_4deaebb1f77e86a8ca066dc5a49c59fd.json +0 -36
  119. package/development/cache/web-search/search_94da91789466070a7f545612e73c7372.json +0 -36
  120. package/development/cache/web-search/search_dd5de8491b8b803a3cb01339cd210fb0.json +0 -36
  121. package/development/knowledge-base/.index.clean.json +0 -1
  122. package/development/knowledge-base/.index.json +0 -486
  123. package/development/knowledge-base/test-best-practices.md +0 -29
  124. package/development/projects/proj_mkh1pazz_ixmt1/phase1/feasibility-report.md +0 -160
  125. package/development/projects/proj_mkh4jvnb_z7rwf/phase1/feasibility-report.md +0 -160
  126. package/development/projects/proj_mkh4jxkd_ewz5a/phase1/feasibility-report.md +0 -160
  127. package/development/projects/proj_mkh4k84n_ni73k/phase1/feasibility-report.md +0 -160
  128. package/development/projects/proj_mkh4wfyd_u9w88/phase1/feasibility-report.md +0 -160
  129. package/development/projects/proj_mkh4wsbo_iahvf/development/projects/proj_mkh4xbpg_4na5w/phase1/feasibility-report.md +0 -160
  130. package/development/projects/proj_mkh4wsbo_iahvf/phase1/feasibility-report.md +0 -160
  131. package/development/projects/proj_mkh4xulg_1ka8x/phase1/feasibility-report.md +0 -160
  132. package/development/projects/proj_mkh4xwhj_gch8j/phase1/feasibility-report.md +0 -160
  133. package/development/projects/proj_mkh4y2qk_9lm8z/phase1/feasibility-report.md +0 -160
  134. package/development/projects/proj_mkh4y2qk_9lm8z/phase2/requirements.md +0 -226
  135. package/development/projects/proj_mkh4y2qk_9lm8z/phase3/PRD.md +0 -345
  136. package/development/projects/proj_mkh4y2qk_9lm8z/phase3/TASK_PLAN.md +0 -284
  137. package/development/projects/proj_mkh4y2qk_9lm8z/phase3/prototype/README.md +0 -14
  138. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/DEVELOPMENT_LOG.md +0 -35
  139. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/TASKS.md +0 -34
  140. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/.env.example +0 -5
  141. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/README.md +0 -60
  142. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/package.json +0 -25
  143. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/src/index.js +0 -70
  144. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/src/routes/index.js +0 -48
  145. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/tests/health.test.js +0 -20
  146. package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/tests/jest.config.js +0 -21
  147. package/development/projects/proj_mkh7veqg_3lypc/phase1/feasibility-report.md +0 -160
  148. package/development/projects/proj_mkh7veqg_3lypc/phase2/requirements.md +0 -226
  149. package/development/projects/proj_mkh7veqg_3lypc/phase3/PRD.md +0 -345
  150. package/development/projects/proj_mkh7veqg_3lypc/phase3/TASK_PLAN.md +0 -284
  151. package/development/projects/proj_mkh7veqg_3lypc/phase3/prototype/README.md +0 -14
  152. package/development/projects/proj_mkh8k8fo_rmqn5/phase1/feasibility-report.md +0 -160
  153. package/development/projects/proj_mkh8xyhy_1vshq/phase1/feasibility-report.md +0 -178
  154. package/development/projects/proj_mkh8zddd_dhamf/phase1/feasibility-report.md +0 -377
  155. package/development/projects/proj_mkh8zddd_dhamf/phase2/requirements.md +0 -442
  156. package/development/projects/proj_mkh8zddd_dhamf/phase3/api-design.md +0 -800
  157. package/development/projects/proj_mkh8zddd_dhamf/phase3/architecture.md +0 -625
  158. package/development/projects/proj_mkh8zddd_dhamf/phase3/data-model.md +0 -830
  159. package/development/projects/proj_mkh8zddd_dhamf/phase3/risks.md +0 -957
  160. package/development/projects/proj_mkh8zddd_dhamf/phase3/wbs.md +0 -381
  161. package/development/todos/.state.json +0 -19
  162. package/development/todos/INDEX.md +0 -63
  163. package/development/todos/active/_README.md +0 -49
  164. package/development/todos/archived/_README.md +0 -11
  165. package/development/todos/backlog/_README.md +0 -11
  166. package/development/todos/backlog/mcp-integration.md +0 -35
  167. package/development/todos/completed/_README.md +0 -11
  168. package/development/todos/completed/boris-optimizations.md +0 -39
  169. package/development/todos/completed/develop/local-knowledge-index.md +0 -85
  170. package/development/todos/completed/develop/todo-system.md +0 -47
  171. package/development/todos/completed/develop/web-search-integration.md +0 -83
  172. package/development/todos/completed/test/phase1-e2e-test.md +0 -103
  173. package/docs/DEVELOPMENT.md +0 -461
  174. package/docs/MARKETPLACE.md +0 -352
  175. package/docs/RELEASE.md +0 -93
  176. package/jest.config.js +0 -63
  177. package/lib/commands.js +0 -3588
  178. package/lib/config-manager.js +0 -441
  179. package/lib/config-schema.js +0 -408
  180. package/lib/config-validator.js +0 -330
  181. package/lib/config.js +0 -122
  182. package/lib/errors.js +0 -305
  183. package/lib/incremental-sync.js +0 -274
  184. package/lib/marketplace.js +0 -487
  185. package/lib/migrations.js +0 -154
  186. package/lib/permission-audit.js +0 -255
  187. package/lib/quality-gate.js +0 -431
  188. package/lib/quality-rules.js +0 -373
  189. package/lib/utils.js +0 -150
  190. package/lib/version-check.js +0 -169
  191. package/lib/version-manifest.js +0 -171
  192. package/project-paradigm.md +0 -313
  193. package/prompts/how-to-find.md +0 -163
  194. package/prompts/linus-architect.md +0 -71
  195. package/prompts/software-architect.md +0 -173
  196. package/prompts/web-designer.md +0 -249
  197. package/scripts/fix-hooks.mjs +0 -97
  198. package/scripts/sync-external.mjs +0 -298
  199. package/scripts/sync-to-home.sh +0 -108
  200. package/scripts/update-registry.mjs +0 -325
  201. package/sources.yaml +0 -83
  202. package/tests/README.md +0 -263
  203. package/tests/commands.test.js +0 -1086
  204. package/tests/config-manager.test.js +0 -677
  205. package/tests/config-schema.test.js +0 -425
  206. package/tests/config-validator.test.js +0 -436
  207. package/tests/config.test.js +0 -100
  208. package/tests/errors.test.js +0 -477
  209. package/tests/manual/phase1-e2e.sh +0 -389
  210. package/tests/manual/phase2-test-cases.md +0 -311
  211. package/tests/manual/phase3-test-cases.md +0 -309
  212. package/tests/manual/phase4-test-cases.md +0 -414
  213. package/tests/manual/test-cases.md +0 -417
  214. package/tests/marketplace.test.js +0 -420
  215. package/tests/migrations.test.js +0 -187
  216. package/tests/quality-gate.test.js +0 -679
  217. package/tests/quality-rules.test.js +0 -619
  218. package/tests/sync-external.test.js +0 -214
  219. package/tests/update-registry.test.js +0 -251
  220. package/tests/utils.test.js +0 -171
  221. package/tests/version-check.test.js +0 -75
  222. package/tests/web-search.test.js +0 -392
  223. package/thinkinglens-silent.md +0 -138
@@ -1,373 +0,0 @@
1
- /**
2
- * Quality Rules Registry
3
- *
4
- * Pluggable rule system for code quality checks.
5
- * Rules can be defined in-code or loaded from config files (YAML/JSON).
6
- *
7
- * @module lib/quality-rules
8
- */
9
-
10
- const fs = require('fs');
11
- const path = require('path');
12
-
13
- /**
14
- * Rule Registry
15
- * Manages quality check rules
16
- */
17
- class RuleRegistry {
18
- constructor() {
19
- this.rules = new Map();
20
- this._registerBuiltInRules();
21
- }
22
-
23
- /**
24
- * Register a rule
25
- * @param {string} id - Rule identifier
26
- * @param {Object} definition - Rule definition
27
- */
28
- register(id, definition) {
29
- const rule = {
30
- id,
31
- name: definition.name || id,
32
- description: definition.description || '',
33
- severity: definition.severity || 'warn',
34
- enabled: definition.enabled !== false,
35
- check: definition.check,
36
- fix: definition.fix || null,
37
- config: definition.config || {}
38
- };
39
- this.rules.set(id, rule);
40
- return rule;
41
- }
42
-
43
- /**
44
- * Get rule by ID
45
- * @param {string} id - Rule identifier
46
- * @returns {Object|null} Rule object
47
- */
48
- get(id) {
49
- return this.rules.get(id) || null;
50
- }
51
-
52
- /**
53
- * Check if rule exists
54
- * @param {string} id - Rule identifier
55
- * @returns {boolean}
56
- */
57
- has(id) {
58
- return this.rules.has(id);
59
- }
60
-
61
- /**
62
- * Get all rules, optionally filtered
63
- * @param {Object} filter - Filter options
64
- * @returns {Array} Array of rules
65
- */
66
- getAll(filter = {}) {
67
- let rules = Array.from(this.rules.values());
68
-
69
- if (filter.severity) {
70
- rules = rules.filter(r => r.severity === filter.severity);
71
- }
72
- if (filter.enabled !== undefined) {
73
- rules = rules.filter(r => r.enabled === filter.enabled);
74
- }
75
- if (filter.category) {
76
- rules = rules.filter(r => r.category === filter.category);
77
- }
78
-
79
- return rules;
80
- }
81
-
82
- /**
83
- * Enable/disable a rule
84
- * @param {string} id - Rule identifier
85
- * @param {boolean} enabled - Enable state
86
- */
87
- setEnabled(id, enabled) {
88
- const rule = this.rules.get(id);
89
- if (rule) {
90
- rule.enabled = enabled;
91
- }
92
- }
93
-
94
- /**
95
- * Update rule configuration
96
- * @param {string} id - Rule identifier
97
- * @param {Object} config - New configuration
98
- */
99
- updateConfig(id, config) {
100
- const rule = this.rules.get(id);
101
- if (rule) {
102
- rule.config = { ...rule.config, ...config };
103
- }
104
- }
105
-
106
- /**
107
- * Load rules from config file
108
- * @param {string} filePath - Path to rules config file
109
- */
110
- loadFromFile(filePath) {
111
- if (!fs.existsSync(filePath)) {
112
- return;
113
- }
114
-
115
- const content = fs.readFileSync(filePath, 'utf-8');
116
- let config;
117
-
118
- if (filePath.endsWith('.yaml') || filePath.endsWith('.yml')) {
119
- // Try to load YAML parser
120
- try {
121
- const yaml = require('yaml');
122
- config = yaml.parse(content);
123
- } catch {
124
- console.warn(`YAML parser not available, skipping ${filePath}`);
125
- return;
126
- }
127
- } else {
128
- config = JSON.parse(content);
129
- }
130
-
131
- // Register rules from config
132
- for (const ruleDef of config.rules || []) {
133
- if (ruleDef.id) {
134
- const existing = this.rules.get(ruleDef.id);
135
- if (existing) {
136
- // Update existing rule
137
- Object.assign(existing, ruleDef);
138
- } else {
139
- // Register new rule with function check
140
- this.register(ruleDef.id, ruleDef);
141
- }
142
- }
143
- }
144
- }
145
-
146
- /**
147
- * Register built-in rules
148
- */
149
- _registerBuiltInRules() {
150
- // File size rule
151
- this.register('file-size-limit', {
152
- name: 'File Size Limit',
153
- description: 'Ensure files do not exceed size limit',
154
- category: 'size',
155
- severity: 'warn',
156
- enabled: true,
157
- config: { maxSize: 800 * 1024 }, // 800KB
158
- check: (file, config) => {
159
- const stats = fs.statSync(file);
160
- const maxSize = config.maxSize || 800 * 1024;
161
- if (stats.size > maxSize) {
162
- return {
163
- pass: false,
164
- message: `File size (${(stats.size / 1024).toFixed(0)}KB) exceeds limit (${(maxSize / 1024).toFixed(0)}KB)`,
165
- fix: 'Consider splitting the file or removing unused code'
166
- };
167
- }
168
- return { pass: true };
169
- }
170
- });
171
-
172
- // Line count rule
173
- this.register('line-count-limit', {
174
- name: 'Line Count Limit',
175
- description: 'Ensure files do not exceed line count limit',
176
- category: 'size',
177
- severity: 'error',
178
- enabled: true,
179
- config: { maxLines: 800 },
180
- check: (file, config) => {
181
- const content = fs.readFileSync(file, 'utf-8');
182
- const lines = content.split('\n').length;
183
- const maxLines = config.maxLines || 800;
184
- if (lines > maxLines) {
185
- return {
186
- pass: false,
187
- message: `File (${lines} lines) exceeds line limit (${maxLines})`,
188
- fix: 'Consider splitting into smaller modules'
189
- };
190
- }
191
- return { pass: true };
192
- }
193
- });
194
-
195
- // Console.log detection rule
196
- this.register('no-console-logs', {
197
- name: 'No Console Logs',
198
- description: 'Detect console.log statements in production code',
199
- category: 'code-style',
200
- severity: 'warn',
201
- enabled: false,
202
- check: (file) => {
203
- const ext = path.extname(file);
204
- if (!['.js', '.jsx', '.ts', '.tsx', '.cjs', '.mjs'].includes(ext)) {
205
- return { pass: true, skip: true };
206
- }
207
- const content = fs.readFileSync(file, 'utf-8');
208
- // Match console.log/debug/info/warn but not console.error
209
- const matches = content.matchAll(/console\.(log|debug|info|warn)\(/g);
210
- const count = [...matches].length;
211
- if (count > 0) {
212
- return {
213
- pass: false,
214
- message: `Found ${count} console statement(s)`,
215
- fix: 'Remove or replace with proper logging library'
216
- };
217
- }
218
- return { pass: true };
219
- }
220
- });
221
-
222
- // TODO comments rule
223
- this.register('todo-comments', {
224
- name: 'TODO Comments Check',
225
- description: 'Track TODO/FIXME comments in code',
226
- category: 'documentation',
227
- severity: 'info',
228
- enabled: true,
229
- check: (file) => {
230
- const ext = path.extname(file);
231
- if (!['.js', '.jsx', '.ts', '.tsx', '.cjs', '.mjs', '.py', '.go'].includes(ext)) {
232
- return { pass: true, skip: true };
233
- }
234
- const content = fs.readFileSync(file, 'utf-8');
235
- const todoRegex = /(?:TODO|FIXME|XXX|HACK|NOTE):?\s*(.+)/gi;
236
- const todos = [...content.matchAll(todoRegex)];
237
- if (todos.length > 0) {
238
- return {
239
- pass: true, // Just informational
240
- message: `${todos.length} TODO comment(s) found`,
241
- details: todos.map(m => m[1].trim())
242
- };
243
- }
244
- return { pass: true };
245
- }
246
- });
247
-
248
- // Directory depth rule
249
- this.register('directory-depth', {
250
- name: 'Directory Depth Limit',
251
- description: 'Ensure directory structure is not too deep',
252
- category: 'structure',
253
- severity: 'warn',
254
- enabled: true,
255
- config: { maxDepth: 6 },
256
- check: (file, config) => {
257
- const maxDepth = config.maxDepth || 6;
258
- const depth = file.split(path.sep).length;
259
- if (depth > maxDepth) {
260
- return {
261
- pass: false,
262
- message: `Directory depth (${depth}) exceeds limit (${maxDepth})`,
263
- fix: 'Consider flattening the directory structure'
264
- };
265
- }
266
- return { pass: true };
267
- }
268
- });
269
-
270
- // Empty file rule
271
- this.register('no-empty-files', {
272
- name: 'No Empty Files',
273
- description: 'Detect empty or near-empty files',
274
- category: 'quality',
275
- severity: 'warn',
276
- enabled: true,
277
- config: { minLines: 3 },
278
- check: (file, config) => {
279
- const content = fs.readFileSync(file, 'utf-8');
280
- const lines = content.trim().split('\n').filter(l => l.trim());
281
- const minLines = config.minLines || 3;
282
- if (lines.length < minLines) {
283
- return {
284
- pass: false,
285
- message: `File has only ${lines.length} line(s)`,
286
- fix: 'Add content or remove the file'
287
- };
288
- }
289
- return { pass: true };
290
- }
291
- });
292
-
293
- // Trailing whitespace rule
294
- this.register('no-trailing-whitespace', {
295
- name: 'No Trailing Whitespace',
296
- description: 'Detect trailing whitespace on lines',
297
- category: 'code-style',
298
- severity: 'warn',
299
- enabled: true,
300
- check: (file) => {
301
- const ext = path.extname(file);
302
- if (!['.js', '.jsx', '.ts', '.tsx', '.cjs', '.mjs', '.py', '.md', '.txt'].includes(ext)) {
303
- return { pass: true, skip: true };
304
- }
305
- const content = fs.readFileSync(file, 'utf-8');
306
- const lines = content.split('\n');
307
- const trailing = [];
308
- lines.forEach((line, i) => {
309
- if (line !== line.trimEnd()) {
310
- trailing.push(i + 1);
311
- }
312
- });
313
- if (trailing.length > 0) {
314
- return {
315
- pass: false,
316
- message: `Trailing whitespace on ${trailing.length} line(s)`,
317
- fix: 'Run code formatter to fix',
318
- autoFix: true
319
- };
320
- }
321
- return { pass: true };
322
- }
323
- });
324
-
325
- // Large function rule (basic)
326
- this.register('function-length', {
327
- name: 'Function Length Limit',
328
- description: 'Functions should not exceed line limit',
329
- category: 'complexity',
330
- severity: 'warn',
331
- enabled: false,
332
- config: { maxLines: 50 },
333
- check: (file, config) => {
334
- const ext = path.extname(file);
335
- if (!['.js', '.jsx', '.ts', '.tsx', '.cjs', '.mjs'].includes(ext)) {
336
- return { pass: true, skip: true };
337
- }
338
- const content = fs.readFileSync(file, 'utf-8');
339
- const maxLines = config.maxLines || 50;
340
-
341
- // Simple function block detection
342
- const functionPattern = /(?:function\s+\w+|const\s+\w+\s*=\s*(?:async\s*)?(?:\([^)]*\)\s*=>|\([^)]*\)\s*{))[\s\S]*?\n([\s\S]{30,})\n/g;
343
- const matches = [...content.matchAll(functionPattern)];
344
-
345
- if (matches.length > 0) {
346
- return {
347
- pass: false,
348
- message: `Found ${matches.length} function(s) exceeding ${maxLines} lines`,
349
- fix: 'Break large functions into smaller ones'
350
- };
351
- }
352
- return { pass: true };
353
- }
354
- });
355
- }
356
- }
357
-
358
- // Global registry instance
359
- const globalRegistry = new RuleRegistry();
360
-
361
- module.exports = {
362
- RuleRegistry,
363
- registry: globalRegistry,
364
-
365
- // Convenience functions using global registry
366
- register: (id, def) => globalRegistry.register(id, def),
367
- get: (id) => globalRegistry.get(id),
368
- has: (id) => globalRegistry.has(id),
369
- getAll: (filter) => globalRegistry.getAll(filter),
370
- setEnabled: (id, enabled) => globalRegistry.setEnabled(id, enabled),
371
- updateConfig: (id, config) => globalRegistry.updateConfig(id, config),
372
- loadFromFile: (path) => globalRegistry.loadFromFile(path)
373
- };
package/lib/utils.js DELETED
@@ -1,150 +0,0 @@
1
- /**
2
- * Utils - Common utility functions
3
- *
4
- * Extracted from cli.js to eliminate code duplication
5
- */
6
-
7
- const fs = require('fs');
8
- const path = require('path');
9
-
10
- /**
11
- * Copy mode for template deployment
12
- */
13
- const CopyMode = {
14
- SAFE: 'safe', // Skip existing files (no overwrite, no backup)
15
- BACKUP: 'backup', // Backup then overwrite (default)
16
- FORCE: 'force' // Overwrite without backup
17
- };
18
-
19
- /**
20
- * Recursively copy directory contents with backup support
21
- * @param {string} src - Source directory
22
- * @param {string} dest - Destination directory
23
- * @param {boolean|string} mode - Copy mode: true/false (legacy) or CopyMode enum
24
- * @param {string} backupDir - Backup directory path
25
- * @returns {object} Copy result { copied, skipped, backedup }
26
- */
27
- exports.copyRecursive = function(src, dest, mode = CopyMode.BACKUP, backupDir = null) {
28
- if (!fs.existsSync(src)) return { copied: 0, skipped: 0, backedup: 0 };
29
-
30
- // Legacy support: convert boolean to CopyMode
31
- if (typeof mode === 'boolean') {
32
- mode = mode ? CopyMode.FORCE : CopyMode.SAFE;
33
- }
34
-
35
- if (!fs.existsSync(dest)) {
36
- fs.mkdirSync(dest, { recursive: true });
37
- }
38
-
39
- const result = { copied: 0, skipped: 0, backedup: 0 };
40
- const entries = fs.readdirSync(src, { withFileTypes: true });
41
-
42
- for (const entry of entries) {
43
- const srcPath = path.join(src, entry.name);
44
- const destPath = path.join(dest, entry.name);
45
-
46
- if (entry.isDirectory()) {
47
- const subResult = exports.copyRecursive(
48
- srcPath,
49
- destPath,
50
- mode,
51
- backupDir ? path.join(backupDir, entry.name) : null
52
- );
53
- result.copied += subResult.copied;
54
- result.skipped += subResult.skipped;
55
- result.backedup += subResult.backedup;
56
- } else {
57
- const action = copyFile(srcPath, destPath, mode, backupDir);
58
- result[action.type === 'copied' ? 'copied' : action.type]++;
59
- if (action.type === 'backedup') {
60
- result.copied++;
61
- result.backedup++;
62
- }
63
- }
64
- }
65
- return result;
66
- };
67
-
68
- /**
69
- * Copy a single file with backup support
70
- * @param {string} srcPath - Source file path
71
- * @param {string} destPath - Destination file path
72
- * @param {string} mode - Copy mode
73
- * @param {string} backupDir - Backup directory path
74
- * @returns {object} Action result { type, backupPath }
75
- */
76
- function copyFile(srcPath, destPath, mode, backupDir) {
77
- // File doesn't exist - just copy
78
- if (!fs.existsSync(destPath)) {
79
- fs.copyFileSync(srcPath, destPath);
80
- setExecutablePermission(destPath);
81
- return { type: 'copied' };
82
- }
83
-
84
- // File exists - handle based on mode
85
- switch (mode) {
86
- case CopyMode.SAFE:
87
- // Skip existing files
88
- return { type: 'skipped' };
89
-
90
- case CopyMode.FORCE:
91
- // Overwrite without backup
92
- fs.copyFileSync(srcPath, destPath);
93
- setExecutablePermission(destPath);
94
- return { type: 'copied' };
95
-
96
- case CopyMode.BACKUP:
97
- default:
98
- // Backup then overwrite
99
- if (backupDir) {
100
- const timestamp = new Date().toISOString().replace(/[:.]/g, '-').split('T')[0];
101
- const backupFileName = path.basename(destPath) + '.' + timestamp + '.bak';
102
- const backupPath = path.join(backupDir, backupFileName);
103
-
104
- fs.mkdirSync(backupDir, { recursive: true });
105
- fs.copyFileSync(destPath, backupPath);
106
- setExecutablePermission(backupPath);
107
-
108
- fs.copyFileSync(srcPath, destPath);
109
- setExecutablePermission(destPath);
110
- return { type: 'backedup', backupPath };
111
- } else {
112
- // No backup dir, just overwrite
113
- fs.copyFileSync(srcPath, destPath);
114
- setExecutablePermission(destPath);
115
- return { type: 'copied' };
116
- }
117
- }
118
- }
119
-
120
- /**
121
- * Set executable permission for script files
122
- * @param {string} filePath - File path
123
- */
124
- function setExecutablePermission(filePath) {
125
- if (filePath.endsWith('.sh') || filePath.endsWith('.cjs')) {
126
- fs.chmodSync(filePath, 0o755);
127
- }
128
- }
129
-
130
- /**
131
- * Ensure a directory exists
132
- * @param {string} dir - Directory path
133
- */
134
- exports.ensureDir = function(dir) {
135
- if (!fs.existsSync(dir)) {
136
- fs.mkdirSync(dir, { recursive: true });
137
- }
138
- };
139
-
140
- /**
141
- * Convert string to Title Case
142
- * @param {string} str - Input string
143
- * @returns {string} Title cased string
144
- */
145
- exports.toTitleCase = function(str) {
146
- return str.replace(/\b\w/g, char => char.toUpperCase());
147
- };
148
-
149
- // Export CopyMode for use in other modules
150
- exports.CopyMode = CopyMode;
@@ -1,169 +0,0 @@
1
- /**
2
- * Version Check - Check for updates from npm registry
3
- *
4
- * Implements lazy checking with local caching to minimize
5
- * network requests and performance impact.
6
- */
7
-
8
- const fs = require('fs');
9
- const path = require('path');
10
- const https = require('https');
11
-
12
- const CONFIG_DIR = path.join(process.env.HOME, '.claude');
13
- const CHECK_FILE = path.join(CONFIG_DIR, '.last-update-check');
14
- const ONE_DAY = 24 * 60 * 60 * 1000;
15
-
16
- // Current version from package.json
17
- const CURRENT_VERSION = require('../package.json').version;
18
- const PACKAGE_NAME = 'sumulige-claude';
19
-
20
- /**
21
- * Get timestamp of last update check
22
- * @returns {number} Timestamp of last check, or 0 if never checked
23
- */
24
- function getLastCheckTime() {
25
- try {
26
- const content = fs.readFileSync(CHECK_FILE, 'utf-8');
27
- return parseInt(content, 10) || 0;
28
- } catch {
29
- return 0;
30
- }
31
- }
32
-
33
- /**
34
- * Save timestamp of current update check
35
- * @param {number} timestamp - Timestamp to save
36
- */
37
- function saveLastCheckTime(timestamp = Date.now()) {
38
- try {
39
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
40
- fs.writeFileSync(CHECK_FILE, timestamp.toString());
41
- } catch {
42
- // Ignore errors
43
- }
44
- }
45
-
46
- /**
47
- * Fetch latest version from npm registry
48
- * @returns {Promise<string|null>} Latest version or null if failed
49
- */
50
- function fetchLatestVersion() {
51
- return new Promise((resolve) => {
52
- const options = {
53
- hostname: 'registry.npmjs.org',
54
- path: `/${PACKAGE_NAME}`,
55
- timeout: 5000, // 5 second timeout
56
- headers: {
57
- 'User-Agent': `${PACKAGE_NAME}/${CURRENT_VERSION}`
58
- }
59
- };
60
-
61
- const req = https.get(options, (res) => {
62
- let data = '';
63
- res.on('data', chunk => data += chunk);
64
- res.on('end', () => {
65
- try {
66
- const pkg = JSON.parse(data);
67
- resolve(pkg['dist-tags']?.latest || null);
68
- } catch {
69
- resolve(null);
70
- }
71
- });
72
- });
73
-
74
- req.on('error', () => resolve(null));
75
- req.on('timeout', () => {
76
- req.destroy();
77
- resolve(null);
78
- });
79
- req.setTimeout(5000);
80
- });
81
- }
82
-
83
- /**
84
- * Check for updates (with caching)
85
- * @param {Object} options - Check options
86
- * @param {boolean} options.force - Force check even if within cache period
87
- * @param {boolean} options.silent - Don't print messages
88
- * @returns {Promise<Object>} Check result { current, latest, updateAvailable }
89
- */
90
- async function checkUpdate(options = {}) {
91
- const { force = false, silent = false } = options;
92
- const now = Date.now();
93
- const lastCheck = getLastCheckTime();
94
- const shouldCheck = force || (now - lastCheck > ONE_DAY);
95
-
96
- if (!shouldCheck) {
97
- return {
98
- current: CURRENT_VERSION,
99
- latest: null,
100
- updateAvailable: false,
101
- cached: true
102
- };
103
- }
104
-
105
- const latest = await fetchLatestVersion();
106
- saveLastCheckTime(now);
107
-
108
- // Only show update if remote version is NEWER than current
109
- const updateAvailable = latest && compareVersions(latest, CURRENT_VERSION) > 0;
110
- const result = {
111
- current: CURRENT_VERSION,
112
- latest,
113
- updateAvailable,
114
- cached: false
115
- };
116
-
117
- if (!silent && updateAvailable) {
118
- console.log('');
119
- console.log(`πŸ’‘ ζ–°η‰ˆζœ¬ v${latest} 可用 (当前: v${CURRENT_VERSION})`);
120
- console.log(` 运葌: npm update -g ${PACKAGE_NAME}`);
121
- console.log('');
122
- }
123
-
124
- return result;
125
- }
126
-
127
- /**
128
- * Get current version
129
- * @returns {string} Current version
130
- */
131
- function getCurrentVersion() {
132
- return CURRENT_VERSION;
133
- }
134
-
135
- /**
136
- * Parse version string to comparable array
137
- * @param {string} version - Version string (e.g., "1.2.3")
138
- * @returns {number[]} Comparable array [major, minor, patch]
139
- */
140
- function parseVersion(version) {
141
- return version.split('.').map(Number).filter(n => !isNaN(n));
142
- }
143
-
144
- /**
145
- * Compare two versions
146
- * @param {string} v1 - First version
147
- * @param {string} v2 - Second version
148
- * @returns {number} -1 if v1 < v2, 0 if equal, 1 if v1 > v2
149
- */
150
- function compareVersions(v1, v2) {
151
- const parts1 = parseVersion(v1);
152
- const parts2 = parseVersion(v2);
153
- const maxLen = Math.max(parts1.length, parts2.length);
154
-
155
- for (let i = 0; i < maxLen; i++) {
156
- const p1 = parts1[i] || 0;
157
- const p2 = parts2[i] || 0;
158
- if (p1 < p2) return -1;
159
- if (p1 > p2) return 1;
160
- }
161
- return 0;
162
- }
163
-
164
- exports.checkUpdate = checkUpdate;
165
- exports.getCurrentVersion = getCurrentVersion;
166
- exports.compareVersions = compareVersions;
167
- exports.getLastCheckTime = getLastCheckTime;
168
- exports.saveLastCheckTime = saveLastCheckTime;
169
- exports.CURRENT_VERSION = CURRENT_VERSION;