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
|
@@ -1,436 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Config Validator 模块单元测试
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const os = require('os');
|
|
8
|
-
|
|
9
|
-
describe('Config Validator Module', () => {
|
|
10
|
-
const {
|
|
11
|
-
ConfigValidator,
|
|
12
|
-
defaultValidator,
|
|
13
|
-
validate,
|
|
14
|
-
validateFile,
|
|
15
|
-
validateOrThrow,
|
|
16
|
-
isAJVAvailable
|
|
17
|
-
} = require('../lib/config-validator');
|
|
18
|
-
|
|
19
|
-
const { ConfigError } = require('../lib/errors');
|
|
20
|
-
|
|
21
|
-
// Temporary directory for test files
|
|
22
|
-
const tempDir = path.join(os.tmpdir(), 'smc-validator-test-' + Date.now());
|
|
23
|
-
const validConfigFile = path.join(tempDir, 'valid-config.json');
|
|
24
|
-
const invalidConfigFile = path.join(tempDir, 'invalid-config.json');
|
|
25
|
-
const malformedJsonFile = path.join(tempDir, 'malformed.json');
|
|
26
|
-
const settingsFile = path.join(tempDir, 'settings.json');
|
|
27
|
-
const qualityGateFile = path.join(tempDir, 'quality-gate.json');
|
|
28
|
-
|
|
29
|
-
beforeAll(() => {
|
|
30
|
-
fs.mkdirSync(tempDir, { recursive: true });
|
|
31
|
-
|
|
32
|
-
// Create valid config file
|
|
33
|
-
fs.writeFileSync(validConfigFile, JSON.stringify({
|
|
34
|
-
version: '1.0.7',
|
|
35
|
-
model: 'claude-opus-4.5',
|
|
36
|
-
agents: {
|
|
37
|
-
conductor: { role: 'coordination' }
|
|
38
|
-
},
|
|
39
|
-
skills: []
|
|
40
|
-
}));
|
|
41
|
-
|
|
42
|
-
// Create invalid config file
|
|
43
|
-
fs.writeFileSync(invalidConfigFile, JSON.stringify({
|
|
44
|
-
model: 'test'
|
|
45
|
-
// Missing required 'version' field
|
|
46
|
-
}));
|
|
47
|
-
|
|
48
|
-
// Create malformed JSON file
|
|
49
|
-
fs.writeFileSync(malformedJsonFile, '{ "version": "1.0.0", }');
|
|
50
|
-
|
|
51
|
-
// Create settings file
|
|
52
|
-
fs.writeFileSync(settingsFile, JSON.stringify({
|
|
53
|
-
updateCheck: true,
|
|
54
|
-
syncInterval: 24
|
|
55
|
-
}));
|
|
56
|
-
|
|
57
|
-
// Create quality-gate file
|
|
58
|
-
fs.writeFileSync(qualityGateFile, JSON.stringify({
|
|
59
|
-
enabled: true,
|
|
60
|
-
severity: 'warn',
|
|
61
|
-
rules: []
|
|
62
|
-
}));
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
afterAll(() => {
|
|
66
|
-
if (fs.existsSync(tempDir)) {
|
|
67
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
describe('isAJVAvailable', () => {
|
|
72
|
-
it('should return boolean indicating AJV availability', () => {
|
|
73
|
-
expect(typeof isAJVAvailable()).toBe('boolean');
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
describe('ConfigValidator', () => {
|
|
78
|
-
let validator;
|
|
79
|
-
|
|
80
|
-
beforeEach(() => {
|
|
81
|
-
validator = new ConfigValidator();
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
describe('constructor', () => {
|
|
85
|
-
it('should create validator with default options', () => {
|
|
86
|
-
expect(validator.strict).toBe(true);
|
|
87
|
-
expect(validator.allErrors).toBe(true);
|
|
88
|
-
expect(validator.coerceTypes).toBe(true);
|
|
89
|
-
expect(validator.useDefaults).toBe(false);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
it('should accept custom options', () => {
|
|
93
|
-
const customValidator = new ConfigValidator({
|
|
94
|
-
strict: false,
|
|
95
|
-
allErrors: false,
|
|
96
|
-
coerceTypes: false,
|
|
97
|
-
useDefaults: true
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
expect(customValidator.strict).toBe(false);
|
|
101
|
-
expect(customValidator.allErrors).toBe(false);
|
|
102
|
-
expect(customValidator.coerceTypes).toBe(false);
|
|
103
|
-
expect(customValidator.useDefaults).toBe(true);
|
|
104
|
-
});
|
|
105
|
-
|
|
106
|
-
it('should initialize AJV if available', () => {
|
|
107
|
-
if (isAJVAvailable()) {
|
|
108
|
-
expect(validator.ajv).toBeDefined();
|
|
109
|
-
expect(typeof validator.configValidate).toBe('function');
|
|
110
|
-
expect(typeof validator.settingsValidate).toBe('function');
|
|
111
|
-
expect(typeof validator.qualityGateValidate).toBe('function');
|
|
112
|
-
} else {
|
|
113
|
-
expect(validator.ajv).toBeNull();
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
describe('validate', () => {
|
|
119
|
-
describe('with valid config', () => {
|
|
120
|
-
it('should validate valid config object', () => {
|
|
121
|
-
const validConfig = {
|
|
122
|
-
version: '1.0.7',
|
|
123
|
-
model: 'claude-opus-4.5',
|
|
124
|
-
agents: {},
|
|
125
|
-
skills: []
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
const result = validator.validate(validConfig, 'config');
|
|
129
|
-
|
|
130
|
-
expect(result.valid).toBe(true);
|
|
131
|
-
expect(result.errors).toEqual([]);
|
|
132
|
-
expect(result.warnings).toEqual([]);
|
|
133
|
-
expect(result.fixes).toEqual([]);
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('should validate settings object', () => {
|
|
137
|
-
const settings = {
|
|
138
|
-
updateCheck: true,
|
|
139
|
-
syncInterval: 24
|
|
140
|
-
};
|
|
141
|
-
|
|
142
|
-
const result = validator.validate(settings, 'settings');
|
|
143
|
-
|
|
144
|
-
expect(result.valid).toBe(true);
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
it('should validate quality-gate object', () => {
|
|
148
|
-
const qualityGate = {
|
|
149
|
-
enabled: true,
|
|
150
|
-
severity: 'warn',
|
|
151
|
-
rules: []
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
const result = validator.validate(qualityGate, 'quality-gate');
|
|
155
|
-
|
|
156
|
-
expect(result.valid).toBe(true);
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
describe('with invalid config', () => {
|
|
161
|
-
it('should return errors for invalid config', () => {
|
|
162
|
-
const invalidConfig = {
|
|
163
|
-
model: 'test'
|
|
164
|
-
// Missing version
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
const result = validator.validate(invalidConfig, 'config');
|
|
168
|
-
|
|
169
|
-
expect(result.valid).toBe(false);
|
|
170
|
-
expect(result.errors.length).toBeGreaterThan(0);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
it('should handle unknown schema name', () => {
|
|
174
|
-
const result = validator.validate({ test: 'value' }, 'unknown-schema');
|
|
175
|
-
|
|
176
|
-
expect(result.valid).toBe(false);
|
|
177
|
-
expect(result.errors[0].path).toBe('schema');
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('should separate errors from warnings', () => {
|
|
181
|
-
// This test depends on AJV's error categorization
|
|
182
|
-
const result = validator.validate({}, 'config');
|
|
183
|
-
|
|
184
|
-
if (!isAJVAvailable()) {
|
|
185
|
-
// Basic validation
|
|
186
|
-
expect(result.valid).toBe(false);
|
|
187
|
-
expect(result.errors.length).toBeGreaterThan(0);
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
it('should include fix suggestions', () => {
|
|
192
|
-
const result = validator.validate({}, 'config');
|
|
193
|
-
|
|
194
|
-
if (result.errors.length > 0) {
|
|
195
|
-
expect(result.fixes.length).toBeGreaterThan(0);
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
describe('without AJV (fallback)', () => {
|
|
201
|
-
it('should do basic validation when AJV not available', () => {
|
|
202
|
-
// This is tested implicitly when AJV is not installed
|
|
203
|
-
const result = validator.validate({ version: '1.0.0' }, 'config');
|
|
204
|
-
|
|
205
|
-
expect(result).toBeDefined();
|
|
206
|
-
expect(typeof result.valid).toBe('boolean');
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it('should require config to be object', () => {
|
|
210
|
-
const result = validator.validate(null, 'config');
|
|
211
|
-
|
|
212
|
-
expect(result.valid).toBe(false);
|
|
213
|
-
expect(result.errors[0].message).toContain('object');
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('should validate version format', () => {
|
|
217
|
-
const result = validator.validate({ version: 'invalid' }, 'config');
|
|
218
|
-
|
|
219
|
-
expect(result.valid).toBe(false);
|
|
220
|
-
if (result.errors.length > 0) {
|
|
221
|
-
expect(result.errors.some(e => e.path === 'version')).toBe(true);
|
|
222
|
-
}
|
|
223
|
-
});
|
|
224
|
-
});
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
describe('validateFile', () => {
|
|
228
|
-
it('should validate valid config file', () => {
|
|
229
|
-
const result = validator.validateFile(validConfigFile);
|
|
230
|
-
|
|
231
|
-
expect(result.valid).toBe(true);
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
it('should handle non-existent file', () => {
|
|
235
|
-
const result = validator.validateFile('/does/not/exist.json');
|
|
236
|
-
|
|
237
|
-
expect(result.valid).toBe(false);
|
|
238
|
-
expect(result.errors[0].message).toContain('not found');
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
it('should handle malformed JSON', () => {
|
|
242
|
-
const result = validator.validateFile(malformedJsonFile);
|
|
243
|
-
|
|
244
|
-
expect(result.valid).toBe(false);
|
|
245
|
-
expect(result.errors[0].message).toContain('JSON');
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
it('should provide fix suggestion for JSON errors', () => {
|
|
249
|
-
const result = validator.validateFile(malformedJsonFile);
|
|
250
|
-
|
|
251
|
-
// Should have errors for malformed JSON
|
|
252
|
-
expect(result.valid).toBe(false);
|
|
253
|
-
expect(result.errors.length).toBeGreaterThan(0);
|
|
254
|
-
// Fix suggestions may or may not be present depending on error type
|
|
255
|
-
expect(result.errors[0].message).toContain('JSON');
|
|
256
|
-
});
|
|
257
|
-
|
|
258
|
-
it('should auto-detect schema from filename', () => {
|
|
259
|
-
// For config.json
|
|
260
|
-
const configResult = validator.validateFile(validConfigFile);
|
|
261
|
-
expect(configResult).toBeDefined();
|
|
262
|
-
|
|
263
|
-
// For settings.json
|
|
264
|
-
const settingsResult = validator.validateFile(settingsFile);
|
|
265
|
-
expect(settingsResult).toBeDefined();
|
|
266
|
-
|
|
267
|
-
// For quality-gate.json
|
|
268
|
-
const gateResult = validator.validateFile(qualityGateFile);
|
|
269
|
-
expect(gateResult).toBeDefined();
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
it('should accept explicit schema name', () => {
|
|
273
|
-
const result = validator.validateFile(validConfigFile, 'config');
|
|
274
|
-
|
|
275
|
-
expect(result).toBeDefined();
|
|
276
|
-
expect(typeof result.valid).toBe('boolean');
|
|
277
|
-
});
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
describe('validateOrThrow', () => {
|
|
281
|
-
it('should return config when valid', () => {
|
|
282
|
-
const validConfig = {
|
|
283
|
-
version: '1.0.7',
|
|
284
|
-
model: 'claude-opus-4.5',
|
|
285
|
-
agents: {},
|
|
286
|
-
skills: []
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
const result = validator.validateOrThrow(validConfig, 'config');
|
|
290
|
-
|
|
291
|
-
expect(result).toEqual(validConfig);
|
|
292
|
-
});
|
|
293
|
-
|
|
294
|
-
it('should throw ConfigError when invalid', () => {
|
|
295
|
-
const invalidConfig = { model: 'test' };
|
|
296
|
-
|
|
297
|
-
expect(() => {
|
|
298
|
-
validator.validateOrThrow(invalidConfig, 'config');
|
|
299
|
-
}).toThrow(ConfigError);
|
|
300
|
-
});
|
|
301
|
-
|
|
302
|
-
it('should include error details in thrown error', () => {
|
|
303
|
-
const invalidConfig = {};
|
|
304
|
-
|
|
305
|
-
try {
|
|
306
|
-
validator.validateOrThrow(invalidConfig, 'config');
|
|
307
|
-
fail('Should have thrown');
|
|
308
|
-
} catch (e) {
|
|
309
|
-
expect(e instanceof ConfigError).toBe(true);
|
|
310
|
-
expect(e.errors).toBeDefined();
|
|
311
|
-
expect(e.fixes).toBeDefined();
|
|
312
|
-
}
|
|
313
|
-
});
|
|
314
|
-
});
|
|
315
|
-
});
|
|
316
|
-
|
|
317
|
-
describe('defaultValidator', () => {
|
|
318
|
-
it('should export a default validator instance', () => {
|
|
319
|
-
expect(defaultValidator).toBeDefined();
|
|
320
|
-
expect(defaultValidator instanceof ConfigValidator).toBe(true);
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
it('should have default options', () => {
|
|
324
|
-
expect(defaultValidator.strict).toBe(true);
|
|
325
|
-
});
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
describe('Convenience Functions', () => {
|
|
329
|
-
describe('validate', () => {
|
|
330
|
-
it('should use default validator', () => {
|
|
331
|
-
const result = validate({
|
|
332
|
-
version: '1.0.7',
|
|
333
|
-
model: 'claude-opus-4.5',
|
|
334
|
-
agents: {},
|
|
335
|
-
skills: []
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
expect(result).toBeDefined();
|
|
339
|
-
});
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
describe('validateFile', () => {
|
|
343
|
-
it('should use default validator', () => {
|
|
344
|
-
const result = validateFile(validConfigFile);
|
|
345
|
-
|
|
346
|
-
expect(result).toBeDefined();
|
|
347
|
-
});
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
describe('validateOrThrow', () => {
|
|
351
|
-
it('should use default validator', () => {
|
|
352
|
-
const result = validateOrThrow({
|
|
353
|
-
version: '1.0.7',
|
|
354
|
-
model: 'claude-opus-4.5',
|
|
355
|
-
agents: {},
|
|
356
|
-
skills: []
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
expect(result).toBeDefined();
|
|
360
|
-
});
|
|
361
|
-
});
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
describe('Edge Cases', () => {
|
|
365
|
-
it('should handle empty config', () => {
|
|
366
|
-
const validator = new ConfigValidator();
|
|
367
|
-
const result = validator.validate({}, 'config');
|
|
368
|
-
|
|
369
|
-
expect(result).toBeDefined();
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
it('should handle null config', () => {
|
|
373
|
-
const validator = new ConfigValidator();
|
|
374
|
-
const result = validator.validate(null, 'config');
|
|
375
|
-
|
|
376
|
-
expect(result.valid).toBe(false);
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
it('should handle array config', () => {
|
|
380
|
-
const validator = new ConfigValidator();
|
|
381
|
-
const result = validator.validate([], 'config');
|
|
382
|
-
|
|
383
|
-
expect(result.valid).toBe(false);
|
|
384
|
-
});
|
|
385
|
-
|
|
386
|
-
it('should handle config with extra properties', () => {
|
|
387
|
-
const validator = new ConfigValidator();
|
|
388
|
-
const result = validator.validate({
|
|
389
|
-
version: '1.0.7',
|
|
390
|
-
extraProperty: 'should not error'
|
|
391
|
-
}, 'config');
|
|
392
|
-
|
|
393
|
-
// Extra properties should not cause validation failure (removeAdditional: false)
|
|
394
|
-
expect(result.valid).toBeDefined();
|
|
395
|
-
});
|
|
396
|
-
});
|
|
397
|
-
|
|
398
|
-
describe('Schema Auto-detection', () => {
|
|
399
|
-
it('should detect config schema from config.json', () => {
|
|
400
|
-
const result = validateFile(validConfigFile);
|
|
401
|
-
|
|
402
|
-
// Should not throw and should return a result
|
|
403
|
-
expect(result).toBeDefined();
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
it('should detect settings schema from settings.json', () => {
|
|
407
|
-
const result = validateFile(settingsFile);
|
|
408
|
-
|
|
409
|
-
expect(result).toBeDefined();
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
it('should detect settings schema from settings.local.json', () => {
|
|
413
|
-
const localSettingsFile = path.join(tempDir, 'settings.local.json');
|
|
414
|
-
fs.writeFileSync(localSettingsFile, JSON.stringify({ updateCheck: false }));
|
|
415
|
-
|
|
416
|
-
const result = validateFile(localSettingsFile);
|
|
417
|
-
|
|
418
|
-
expect(result).toBeDefined();
|
|
419
|
-
});
|
|
420
|
-
|
|
421
|
-
it('should detect quality-gate schema from quality-gate.json', () => {
|
|
422
|
-
const result = validateFile(qualityGateFile);
|
|
423
|
-
|
|
424
|
-
expect(result).toBeDefined();
|
|
425
|
-
});
|
|
426
|
-
|
|
427
|
-
it('should default to config schema for unknown filenames', () => {
|
|
428
|
-
const unknownFile = path.join(tempDir, 'unknown.json');
|
|
429
|
-
fs.writeFileSync(unknownFile, JSON.stringify({ version: '1.0.0' }));
|
|
430
|
-
|
|
431
|
-
const result = validateFile(unknownFile);
|
|
432
|
-
|
|
433
|
-
expect(result).toBeDefined();
|
|
434
|
-
});
|
|
435
|
-
});
|
|
436
|
-
});
|
package/tests/config.test.js
DELETED
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Config 模块单元测试
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
const fs = require('fs');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const os = require('os');
|
|
8
|
-
|
|
9
|
-
describe('Config Module', () => {
|
|
10
|
-
const config = require('../lib/config');
|
|
11
|
-
|
|
12
|
-
describe('loadConfig', () => {
|
|
13
|
-
it('should return default config when no user config exists', () => {
|
|
14
|
-
// 使用真实的 CONFIG_DIR 但临时移除 config.json
|
|
15
|
-
const realConfigFile = config.CONFIG_FILE;
|
|
16
|
-
const tempBackup = realConfigFile + '.backup-test';
|
|
17
|
-
|
|
18
|
-
// 备份现有配置(如果存在)
|
|
19
|
-
if (fs.existsSync(realConfigFile)) {
|
|
20
|
-
fs.renameSync(realConfigFile, tempBackup);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
try {
|
|
24
|
-
const result = config.loadConfig();
|
|
25
|
-
|
|
26
|
-
expect(result).toBeDefined();
|
|
27
|
-
expect(result).toHaveProperty('version');
|
|
28
|
-
expect(result).toHaveProperty('agents');
|
|
29
|
-
expect(result).toHaveProperty('skills');
|
|
30
|
-
} finally {
|
|
31
|
-
// 恢复原配置
|
|
32
|
-
if (fs.existsSync(tempBackup)) {
|
|
33
|
-
fs.renameSync(tempBackup, realConfigFile);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('should return DEFAULTS constant', () => {
|
|
39
|
-
expect(config.DEFAULTS).toBeDefined();
|
|
40
|
-
expect(typeof config.DEFAULTS).toBe('object');
|
|
41
|
-
});
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
describe('saveConfig & ensureDir', () => {
|
|
45
|
-
const tempDir = path.join(os.tmpdir(), 'smc-test-' + Date.now());
|
|
46
|
-
const tempFile = path.join(tempDir, 'test-config.json');
|
|
47
|
-
|
|
48
|
-
afterAll(() => {
|
|
49
|
-
// 清理
|
|
50
|
-
if (fs.existsSync(tempDir)) {
|
|
51
|
-
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('should create directory and save config', () => {
|
|
56
|
-
const testConfig = {
|
|
57
|
-
version: '1.0.0',
|
|
58
|
-
test: 'value'
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
// 直接调用 ensureDir
|
|
62
|
-
config.ensureDir(tempDir);
|
|
63
|
-
expect(fs.existsSync(tempDir)).toBe(true);
|
|
64
|
-
|
|
65
|
-
// 手动保存文件
|
|
66
|
-
fs.writeFileSync(tempFile, JSON.stringify(testConfig, null, 2));
|
|
67
|
-
expect(fs.existsSync(tempFile)).toBe(true);
|
|
68
|
-
|
|
69
|
-
const saved = JSON.parse(fs.readFileSync(tempFile, 'utf-8'));
|
|
70
|
-
expect(saved).toEqual(testConfig);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it('should not error when directory exists', () => {
|
|
74
|
-
expect(() => config.ensureDir(tempDir)).not.toThrow();
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
describe('deepMerge (internal behavior)', () => {
|
|
79
|
-
it('should have loadConfig and saveConfig functions', () => {
|
|
80
|
-
expect(typeof config.loadConfig).toBe('function');
|
|
81
|
-
expect(typeof config.saveConfig).toBe('function');
|
|
82
|
-
expect(typeof config.ensureDir).toBe('function');
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
describe('exports', () => {
|
|
87
|
-
it('should export required constants', () => {
|
|
88
|
-
expect(config.CONFIG_DIR).toBeDefined();
|
|
89
|
-
expect(config.CONFIG_FILE).toBeDefined();
|
|
90
|
-
expect(config.DEFAULTS).toBeDefined();
|
|
91
|
-
expect(config.SKILLS_DIR).toBeDefined();
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it('should have correct paths', () => {
|
|
95
|
-
expect(config.CONFIG_DIR).toContain('.claude');
|
|
96
|
-
expect(config.CONFIG_FILE).toContain('config.json');
|
|
97
|
-
expect(config.SKILLS_DIR).toContain('skills');
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
});
|