sumulige-claude 1.5.1 β 1.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/hooks/hook-registry.json +0 -15
- package/.claude/rules/coding-style.md +18 -7
- package/.claude/rules/hooks.md +15 -4
- package/.claude/rules/performance.md +15 -5
- package/.claude/rules/security.md +140 -4
- package/.claude/rules/testing.md +138 -9
- package/.claude/rules/web-design-standard.md +16 -5
- package/.claude/skills/algorithmic-art/metadata.yaml +28 -0
- package/.claude/skills/api-tester/SKILL.md +61 -0
- package/.claude/skills/api-tester/examples/basic.md +3 -0
- package/.claude/skills/api-tester/metadata.yaml +30 -0
- package/.claude/skills/api-tester/templates/default.md +3 -0
- package/.claude/skills/brand-guidelines/metadata.yaml +26 -0
- package/.claude/skills/canvas-design/metadata.yaml +27 -0
- package/.claude/skills/code-reviewer-123/SKILL.md +61 -0
- package/.claude/skills/code-reviewer-123/examples/basic.md +3 -0
- package/.claude/skills/code-reviewer-123/metadata.yaml +30 -0
- package/.claude/skills/code-reviewer-123/templates/default.md +3 -0
- package/.claude/skills/doc-coauthoring/metadata.yaml +27 -0
- package/.claude/skills/docx/metadata.yaml +30 -0
- package/.claude/skills/frontend-design/metadata.yaml +28 -0
- package/.claude/skills/internal-comms/metadata.yaml +28 -0
- package/.claude/skills/mcp-builder/metadata.yaml +26 -0
- package/.claude/skills/my-skill/SKILL.md +61 -0
- package/.claude/skills/my-skill/examples/basic.md +3 -0
- package/.claude/skills/my-skill/metadata.yaml +30 -0
- package/.claude/skills/my-skill/templates/default.md +3 -0
- package/.claude/skills/pdf/metadata.yaml +29 -0
- package/.claude/skills/pptx/metadata.yaml +29 -0
- package/.claude/skills/react-best-practices/metadata.yaml +26 -0
- package/.claude/skills/react-node-practices/SKILL.md +409 -0
- package/.claude/skills/react-node-practices/metadata.yaml +56 -0
- package/.claude/skills/skill-creator/metadata.yaml +25 -0
- package/.claude/skills/slack-gif-creator/metadata.yaml +28 -0
- package/.claude/skills/test-skill-name/SKILL.md +61 -0
- package/.claude/skills/test-skill-name/examples/basic.md +3 -0
- package/.claude/skills/test-skill-name/metadata.yaml +30 -0
- package/.claude/skills/test-skill-name/templates/default.md +3 -0
- package/.claude/skills/test-workflow/metadata.yaml +32 -0
- package/.claude/skills/theme-factory/metadata.yaml +26 -0
- package/.claude/skills/threejs-fundamentals/metadata.yaml +27 -0
- package/.claude/skills/web-artifacts-builder/metadata.yaml +30 -0
- package/.claude/skills/web-design-guidelines/metadata.yaml +26 -0
- package/.claude/skills/webapp-testing/metadata.yaml +26 -0
- package/.claude/skills/xlsx/metadata.yaml +29 -0
- package/LICENSE +21 -0
- package/cli.js +1 -1
- package/package.json +25 -3
- package/.claude/.kickoff-hint.txt +0 -52
- package/.claude/.sumulige-claude-version +0 -1
- package/.claude/.version +0 -1
- package/.claude/AGENTS.md +0 -42
- package/.claude/ANCHORS.md +0 -40
- package/.claude/CLAUDE.md +0 -138
- package/.claude/MEMORY.md +0 -69
- package/.claude/PROJECT_LOG.md +0 -101
- package/.claude/THINKING_CHAIN_GUIDE.md +0 -287
- package/.claude/USAGE.md +0 -175
- package/.claude/boris-optimizations.md +0 -167
- package/.claude/handoffs/INDEX.md +0 -21
- package/.claude/handoffs/LATEST.md +0 -76
- package/.claude/handoffs/handoff_2026-01-22T13-07-04-757Z.md +0 -76
- package/.claude/quality-gate.json +0 -82
- package/.claude/rag/skill-index.json +0 -135
- package/.claude/settings.json +0 -99
- package/.claude/settings.local.json +0 -175
- package/.claude/templates/PROJECT_KICKOFF.md +0 -89
- package/.claude/templates/PROJECT_PROPOSAL.md +0 -227
- package/.claude/templates/TASK_PLAN.md +0 -121
- package/.claude/templates/hooks/README.md +0 -302
- package/.claude/templates/hooks/hook.sh.template +0 -94
- package/.claude/templates/hooks/user-prompt-submit.cjs.template +0 -116
- package/.claude/templates/hooks/user-response-submit.cjs.template +0 -94
- package/.claude/templates/hooks/validate.js +0 -173
- package/.claude/templates/tasks/develop.md +0 -69
- package/.claude/templates/tasks/research.md +0 -64
- package/.claude/templates/tasks/test.md +0 -96
- package/.claude/thinking-routes/.last-sync +0 -1
- package/.claude/thinking-routes/QUICKREF.md +0 -98
- package/.claude/workflow/document-scanner.js +0 -426
- package/.claude/workflow/knowledge-engine.js +0 -941
- package/.claude/workflow/notebooklm/browser.js +0 -1028
- package/.claude/workflow/phases/phase1-research.js +0 -578
- package/.claude/workflow/phases/phase1-research.ts +0 -465
- package/.claude/workflow/phases/phase2-approve.js +0 -722
- package/.claude/workflow/phases/phase3-plan.js +0 -1200
- package/.claude/workflow/phases/phase4-develop.js +0 -894
- package/.claude/workflow/search-cache.js +0 -230
- package/.claude/workflow/templates/approval.md +0 -315
- package/.claude/workflow/templates/development.md +0 -377
- package/.claude/workflow/templates/planning.md +0 -328
- package/.claude/workflow/templates/research.md +0 -250
- package/.claude/workflow/types.js +0 -37
- package/.claude/workflow/web-search.js +0 -278
- package/.claude-plugin/marketplace.json +0 -71
- package/.github/workflows/sync-skills.yml +0 -74
- package/.versionrc +0 -25
- package/AGENTS.md +0 -580
- package/CHANGELOG.md +0 -481
- package/CLAUDE-template.md +0 -114
- package/DEV_TOOLS_GUIDE.md +0 -190
- package/PROJECT_STRUCTURE.md +0 -266
- package/Q&A.md +0 -325
- package/config/defaults.json +0 -34
- package/config/official-skills.json +0 -183
- package/config/quality-gate.json +0 -67
- package/config/skill-categories.json +0 -40
- package/config/version-manifest.json +0 -85
- package/demos/power-3d-scatter.html +0 -683
- package/development/cache/web-search/search_1193d605f8eb364651fc2f2041b58a31.json +0 -36
- package/development/cache/web-search/search_3798bf06960edc125f744a1abb5b72c5.json +0 -36
- package/development/cache/web-search/search_37c7d4843a53f0d83f1122a6f908a2a3.json +0 -36
- package/development/cache/web-search/search_44166fa0153709ee168485a22aa0ab40.json +0 -36
- package/development/cache/web-search/search_4deaebb1f77e86a8ca066dc5a49c59fd.json +0 -36
- package/development/cache/web-search/search_94da91789466070a7f545612e73c7372.json +0 -36
- package/development/cache/web-search/search_dd5de8491b8b803a3cb01339cd210fb0.json +0 -36
- package/development/knowledge-base/.index.clean.json +0 -1
- package/development/knowledge-base/.index.json +0 -486
- package/development/knowledge-base/test-best-practices.md +0 -29
- package/development/projects/proj_mkh1pazz_ixmt1/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4jvnb_z7rwf/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4jxkd_ewz5a/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4k84n_ni73k/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4wfyd_u9w88/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4wsbo_iahvf/development/projects/proj_mkh4xbpg_4na5w/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4wsbo_iahvf/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4xulg_1ka8x/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4xwhj_gch8j/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4y2qk_9lm8z/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh4y2qk_9lm8z/phase2/requirements.md +0 -226
- package/development/projects/proj_mkh4y2qk_9lm8z/phase3/PRD.md +0 -345
- package/development/projects/proj_mkh4y2qk_9lm8z/phase3/TASK_PLAN.md +0 -284
- package/development/projects/proj_mkh4y2qk_9lm8z/phase3/prototype/README.md +0 -14
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/DEVELOPMENT_LOG.md +0 -35
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/TASKS.md +0 -34
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/.env.example +0 -5
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/README.md +0 -60
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/package.json +0 -25
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/src/index.js +0 -70
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/src/routes/index.js +0 -48
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/tests/health.test.js +0 -20
- package/development/projects/proj_mkh4y2qk_9lm8z/phase4/source/tests/jest.config.js +0 -21
- package/development/projects/proj_mkh7veqg_3lypc/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh7veqg_3lypc/phase2/requirements.md +0 -226
- package/development/projects/proj_mkh7veqg_3lypc/phase3/PRD.md +0 -345
- package/development/projects/proj_mkh7veqg_3lypc/phase3/TASK_PLAN.md +0 -284
- package/development/projects/proj_mkh7veqg_3lypc/phase3/prototype/README.md +0 -14
- package/development/projects/proj_mkh8k8fo_rmqn5/phase1/feasibility-report.md +0 -160
- package/development/projects/proj_mkh8xyhy_1vshq/phase1/feasibility-report.md +0 -178
- package/development/projects/proj_mkh8zddd_dhamf/phase1/feasibility-report.md +0 -377
- package/development/projects/proj_mkh8zddd_dhamf/phase2/requirements.md +0 -442
- package/development/projects/proj_mkh8zddd_dhamf/phase3/api-design.md +0 -800
- package/development/projects/proj_mkh8zddd_dhamf/phase3/architecture.md +0 -625
- package/development/projects/proj_mkh8zddd_dhamf/phase3/data-model.md +0 -830
- package/development/projects/proj_mkh8zddd_dhamf/phase3/risks.md +0 -957
- package/development/projects/proj_mkh8zddd_dhamf/phase3/wbs.md +0 -381
- package/development/todos/.state.json +0 -19
- package/development/todos/INDEX.md +0 -63
- package/development/todos/active/_README.md +0 -49
- package/development/todos/archived/_README.md +0 -11
- package/development/todos/backlog/_README.md +0 -11
- package/development/todos/backlog/mcp-integration.md +0 -35
- package/development/todos/completed/_README.md +0 -11
- package/development/todos/completed/boris-optimizations.md +0 -39
- package/development/todos/completed/develop/local-knowledge-index.md +0 -85
- package/development/todos/completed/develop/todo-system.md +0 -47
- package/development/todos/completed/develop/web-search-integration.md +0 -83
- package/development/todos/completed/test/phase1-e2e-test.md +0 -103
- package/docs/DEVELOPMENT.md +0 -461
- package/docs/MARKETPLACE.md +0 -352
- package/docs/RELEASE.md +0 -93
- package/jest.config.js +0 -63
- package/lib/commands.js +0 -3588
- package/lib/config-manager.js +0 -441
- package/lib/config-schema.js +0 -408
- package/lib/config-validator.js +0 -330
- package/lib/config.js +0 -122
- package/lib/errors.js +0 -305
- package/lib/incremental-sync.js +0 -274
- package/lib/marketplace.js +0 -487
- package/lib/migrations.js +0 -154
- package/lib/permission-audit.js +0 -255
- package/lib/quality-gate.js +0 -431
- package/lib/quality-rules.js +0 -373
- package/lib/utils.js +0 -150
- package/lib/version-check.js +0 -169
- package/lib/version-manifest.js +0 -171
- package/project-paradigm.md +0 -313
- package/prompts/how-to-find.md +0 -163
- package/prompts/linus-architect.md +0 -71
- package/prompts/software-architect.md +0 -173
- package/prompts/web-designer.md +0 -249
- package/scripts/fix-hooks.mjs +0 -97
- package/scripts/sync-external.mjs +0 -298
- package/scripts/sync-to-home.sh +0 -108
- package/scripts/update-registry.mjs +0 -325
- package/sources.yaml +0 -83
- package/tests/README.md +0 -263
- package/tests/commands.test.js +0 -1086
- package/tests/config-manager.test.js +0 -677
- package/tests/config-schema.test.js +0 -425
- package/tests/config-validator.test.js +0 -436
- package/tests/config.test.js +0 -100
- package/tests/errors.test.js +0 -477
- package/tests/manual/phase1-e2e.sh +0 -389
- package/tests/manual/phase2-test-cases.md +0 -311
- package/tests/manual/phase3-test-cases.md +0 -309
- package/tests/manual/phase4-test-cases.md +0 -414
- package/tests/manual/test-cases.md +0 -417
- package/tests/marketplace.test.js +0 -420
- package/tests/migrations.test.js +0 -187
- package/tests/quality-gate.test.js +0 -679
- package/tests/quality-rules.test.js +0 -619
- package/tests/sync-external.test.js +0 -214
- package/tests/update-registry.test.js +0 -251
- package/tests/utils.test.js +0 -171
- package/tests/version-check.test.js +0 -75
- package/tests/web-search.test.js +0 -392
- package/thinkinglens-silent.md +0 -138
package/lib/quality-rules.js
DELETED
|
@@ -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;
|
package/lib/version-check.js
DELETED
|
@@ -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;
|