sumulige-claude 1.1.0 → 1.1.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/pre-commit.cjs +86 -0
- package/.claude/hooks/pre-push.cjs +103 -0
- package/.claude/quality-gate.json +61 -0
- package/.claude/settings.local.json +4 -1
- package/AGENTS.md +416 -177
- package/Q&A.md +230 -213
- package/README.md +256 -230
- package/cli.js +28 -0
- package/config/quality-gate.json +61 -0
- package/docs/DEVELOPMENT.md +329 -291
- package/lib/commands.js +208 -0
- package/lib/config-manager.js +441 -0
- package/lib/config-schema.js +408 -0
- package/lib/config-validator.js +330 -0
- package/lib/config.js +52 -1
- package/lib/errors.js +305 -0
- package/lib/quality-gate.js +431 -0
- package/lib/quality-rules.js +373 -0
- package/package.json +5 -1
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Pre-commit Quality Gate
|
|
4
|
+
*
|
|
5
|
+
* Runs quality checks before committing.
|
|
6
|
+
* Fails the commit if critical or error issues are found.
|
|
7
|
+
*
|
|
8
|
+
* Install: ln -s ../../.claude/hooks/pre-commit.cjs .git/hooks/pre-commit
|
|
9
|
+
* Or use: smc hooks install
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { execSync } = require('child_process');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
|
|
16
|
+
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
17
|
+
|
|
18
|
+
async function main() {
|
|
19
|
+
// Check if quality gate is enabled
|
|
20
|
+
const configPath = path.join(projectDir, '.claude', 'quality-gate.json');
|
|
21
|
+
let config = { enabled: true, gates: { preCommit: true } };
|
|
22
|
+
|
|
23
|
+
if (fs.existsSync(configPath)) {
|
|
24
|
+
try {
|
|
25
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
26
|
+
} catch {}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!config.enabled || !config.gates?.preCommit) {
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Get staged files
|
|
34
|
+
let stagedFiles = [];
|
|
35
|
+
try {
|
|
36
|
+
const output = execSync('git diff --cached --name-only --diff-filter=ACM', {
|
|
37
|
+
encoding: 'utf-8',
|
|
38
|
+
stdio: 'pipe'
|
|
39
|
+
});
|
|
40
|
+
stagedFiles = output.trim().split('\n').filter(Boolean);
|
|
41
|
+
} catch {
|
|
42
|
+
// Not in git repo or no staged files
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (stagedFiles.length === 0) {
|
|
47
|
+
process.exit(0);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Filter to checkable files
|
|
51
|
+
const checkable = stagedFiles.filter(f => {
|
|
52
|
+
const ext = path.extname(f);
|
|
53
|
+
return ['.js', '.ts', '.jsx', '.tsx', '.cjs', '.mjs', '.json', '.md'].includes(ext);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (checkable.length === 0) {
|
|
57
|
+
process.exit(0);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
console.log(`Running pre-commit quality checks on ${checkable.length} file(s)...`);
|
|
61
|
+
|
|
62
|
+
// Run quality gate
|
|
63
|
+
const { QualityGate } = require(path.join(__dirname, '..', '..', 'lib', 'quality-gate.js'));
|
|
64
|
+
const gate = new QualityGate({
|
|
65
|
+
projectDir,
|
|
66
|
+
config
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const result = await gate.check({
|
|
70
|
+
files: checkable.map(f => path.join(projectDir, f)),
|
|
71
|
+
severity: 'error' // Block on errors and critical only
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (!result.passed) {
|
|
75
|
+
console.error('\nPre-commit quality gate failed.');
|
|
76
|
+
console.error('Fix issues or use --no-verify to bypass (not recommended).\n');
|
|
77
|
+
process.exit(1);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
console.log('Pre-commit quality checks passed.\n');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
main().catch(err => {
|
|
84
|
+
console.error('Pre-commit hook error:', err.message);
|
|
85
|
+
process.exit(1);
|
|
86
|
+
});
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Pre-push Quality Gate
|
|
4
|
+
*
|
|
5
|
+
* Runs full quality checks before pushing.
|
|
6
|
+
* More comprehensive than pre-commit.
|
|
7
|
+
*
|
|
8
|
+
* Install: ln -s ../../.claude/hooks/pre-push.cjs .git/hooks/pre-push
|
|
9
|
+
* Or use: smc hooks install
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const { execSync } = require('child_process');
|
|
13
|
+
const path = require('path');
|
|
14
|
+
const fs = require('fs');
|
|
15
|
+
|
|
16
|
+
const projectDir = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
17
|
+
|
|
18
|
+
async function main() {
|
|
19
|
+
// Check if quality gate is enabled
|
|
20
|
+
const configPath = path.join(projectDir, '.claude', 'quality-gate.json');
|
|
21
|
+
let config = { enabled: true, gates: { prePush: true } };
|
|
22
|
+
|
|
23
|
+
if (fs.existsSync(configPath)) {
|
|
24
|
+
try {
|
|
25
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
|
|
26
|
+
} catch {}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (!config.enabled || !config.gates?.prePush) {
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
console.log('Running pre-push quality checks...\n');
|
|
34
|
+
|
|
35
|
+
// Get all files that will be pushed
|
|
36
|
+
let filesToCheck = [];
|
|
37
|
+
try {
|
|
38
|
+
// Get files changed since last push
|
|
39
|
+
const upstream = execSync('git rev-parse --abbrev-ref --symbolic-full-name @{u}', {
|
|
40
|
+
encoding: 'utf-8',
|
|
41
|
+
stdio: 'pipe'
|
|
42
|
+
}).trim() || 'origin/main';
|
|
43
|
+
|
|
44
|
+
const output = execSync(`git diff --name-only ${upstream}...HEAD`, {
|
|
45
|
+
encoding: 'utf-8',
|
|
46
|
+
stdio: 'pipe'
|
|
47
|
+
});
|
|
48
|
+
filesToCheck = output.trim().split('\n').filter(Boolean);
|
|
49
|
+
} catch {
|
|
50
|
+
// No upstream or other git error - check staged files only
|
|
51
|
+
try {
|
|
52
|
+
const output = execSync('git diff --cached --name-only --diff-filter=ACM', {
|
|
53
|
+
encoding: 'utf-8',
|
|
54
|
+
stdio: 'pipe'
|
|
55
|
+
});
|
|
56
|
+
filesToCheck = output.trim().split('\n').filter(Boolean);
|
|
57
|
+
} catch {
|
|
58
|
+
// Not in git repo
|
|
59
|
+
process.exit(0);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (filesToCheck.length === 0) {
|
|
64
|
+
process.exit(0);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Filter to checkable files
|
|
68
|
+
const checkable = filesToCheck.filter(f => {
|
|
69
|
+
const ext = path.extname(f);
|
|
70
|
+
return ['.js', '.ts', '.jsx', '.tsx', '.cjs', '.mjs', '.json', '.md'].includes(ext);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (checkable.length === 0) {
|
|
74
|
+
process.exit(0);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.log(`Checking ${checkable.length} changed file(s)...\n`);
|
|
78
|
+
|
|
79
|
+
// Run quality gate
|
|
80
|
+
const { QualityGate } = require(path.join(__dirname, '..', '..', 'lib', 'quality-gate.js'));
|
|
81
|
+
const gate = new QualityGate({
|
|
82
|
+
projectDir,
|
|
83
|
+
config
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const result = await gate.check({
|
|
87
|
+
files: checkable.map(f => path.join(projectDir, f)),
|
|
88
|
+
severity: 'warn' // Block on warnings too for push
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (!result.passed) {
|
|
92
|
+
console.error('\nPush blocked by quality gate.');
|
|
93
|
+
console.error('Fix issues or use --no-verify to bypass (not recommended).\n');
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
console.log('All quality checks passed. Proceeding with push.\n');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
main().catch(err => {
|
|
101
|
+
console.error('Pre-push hook error:', err.message);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"enabled": true,
|
|
3
|
+
"severity": "warn",
|
|
4
|
+
"rules": [
|
|
5
|
+
{
|
|
6
|
+
"id": "line-count-limit",
|
|
7
|
+
"enabled": true,
|
|
8
|
+
"severity": "error",
|
|
9
|
+
"config": {
|
|
10
|
+
"maxLines": 800
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"id": "file-size-limit",
|
|
15
|
+
"enabled": true,
|
|
16
|
+
"severity": "warn",
|
|
17
|
+
"config": {
|
|
18
|
+
"maxSize": 819200
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"id": "no-empty-files",
|
|
23
|
+
"enabled": true,
|
|
24
|
+
"severity": "warn"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"id": "no-trailing-whitespace",
|
|
28
|
+
"enabled": true,
|
|
29
|
+
"severity": "warn"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "todo-comments",
|
|
33
|
+
"enabled": true,
|
|
34
|
+
"severity": "info"
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"id": "directory-depth",
|
|
38
|
+
"enabled": false,
|
|
39
|
+
"severity": "warn"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"id": "no-console-logs",
|
|
43
|
+
"enabled": false,
|
|
44
|
+
"severity": "warn"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"id": "function-length",
|
|
48
|
+
"enabled": false,
|
|
49
|
+
"severity": "warn"
|
|
50
|
+
}
|
|
51
|
+
],
|
|
52
|
+
"gates": {
|
|
53
|
+
"preCommit": true,
|
|
54
|
+
"prePush": true,
|
|
55
|
+
"onToolUse": false
|
|
56
|
+
},
|
|
57
|
+
"reporting": {
|
|
58
|
+
"format": "console",
|
|
59
|
+
"outputFile": null
|
|
60
|
+
}
|
|
61
|
+
}
|