@chem-x/starter-kit 26.9.21-227 → 26.9.21-34
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/cli/audit/autofix.js +2 -17
- package/cli/audit.js +0 -3
- package/cli/commands/cmd-audit.js +3 -43
- package/cli/commands/cmd-router.js +1 -13
- package/cli/generator-templates/archetypes/index.js +4 -34
- package/cli/generator-templates/controller.js +1 -1
- package/cli/generator-templates/react.js +1 -1
- package/cli/generator-templates/svelte.js +1 -1
- package/cli/generator-templates/types.js +2 -2
- package/cli/generator-templates/vue.js +1 -1
- package/cli/generator-templates.js +0 -1
- package/cli/generator-templates.spec.js +0 -5
- package/cli/generator.js +7 -94
- package/cli/index.js +2 -5
- package/cli/mcp/antigravity.js +2 -3
- package/cli/mcp/manifests.js +1 -1
- package/cli/mcp/tools-search.js +1 -7
- package/cli/mcp/tools.js +0 -23
- package/cli/mutators.js +23 -10
- package/cli/project-detector.js +0 -47
- package/cli/ui-e2e-verification.spec.js +1 -3
- package/cli/ui-filetree.spec.js +5 -5
- package/cli/ui-html.js +34 -26
- package/cli/ui-kanban.spec.js +12 -12
- package/cli/ui-styles.js +81 -195
- package/cli/ui-vbulletin.spec.js +13 -12
- package/cli/ui.spec.js +4 -6
- package/package.json +1 -1
- package/cli/audit/clone-detector.js +0 -64
- package/cli/audit/clone-detector.spec.js +0 -46
- package/cli/audit/reporter-clones.js +0 -33
- package/cli/audit/reporter-hotspot-graph.js +0 -34
- package/cli/audit-stages.spec.js +0 -30
- package/cli/exploder.js +0 -258
- package/cli/exploder.spec.js +0 -99
- package/cli/generator-compact.spec.js +0 -104
- package/cli/generator-templates/archetypes/minimal-archetypes.js +0 -131
- package/cli/generator-templates/archetypes/vector-matcher.js +0 -50
- package/cli/generator-templates/archetypes/vector-matcher.spec.js +0 -25
- package/cli/generator-templates/compact.js +0 -130
- package/cli/search-queries-hotspot-graph.js +0 -65
- package/cli/search-queries-hotspot-graph.spec.js +0 -66
- package/cli/search-queries-similar.js +0 -84
- package/cli/search-queries-similar.spec.js +0 -43
- package/cli/trend.js +0 -84
- package/cli/trend.spec.js +0 -51
- package/cli/ui-index.html +0 -659
package/cli/audit/autofix.js
CHANGED
|
@@ -63,9 +63,7 @@ export const autofixContent = (content, options = {}) => {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
// 3. AI lazy placeholder comment removal
|
|
66
|
-
|
|
67
|
-
const isLazyTruncationEligible = !shouldDropLine && shouldFix('AI_SLOP_LAZY_PLACEHOLDER');
|
|
68
|
-
if (isLazyTruncationEligible && hasLazyTruncation) {
|
|
66
|
+
if (!shouldDropLine && shouldFix('AI_SLOP_LAZY_PLACEHOLDER') && TRUNCATION_REGEX.test(line)) {
|
|
69
67
|
fixes.push({
|
|
70
68
|
line: lineNumber,
|
|
71
69
|
rule: 'AI_SLOP_LAZY_PLACEHOLDER',
|
|
@@ -74,9 +72,7 @@ export const autofixContent = (content, options = {}) => {
|
|
|
74
72
|
shouldDropLine = true;
|
|
75
73
|
}
|
|
76
74
|
|
|
77
|
-
|
|
78
|
-
const isEmDashEligible = !shouldDropLine && shouldFix('TYPOGRAPHY_EM_DASH');
|
|
79
|
-
if (isEmDashEligible && hasEmDash) {
|
|
75
|
+
if (!shouldDropLine && shouldFix('TYPOGRAPHY_EM_DASH') && line.includes('\u2014')) {
|
|
80
76
|
line = line.replace(/\u2014/g, '-');
|
|
81
77
|
fixes.push({
|
|
82
78
|
line: lineNumber,
|
|
@@ -85,17 +81,6 @@ export const autofixContent = (content, options = {}) => {
|
|
|
85
81
|
});
|
|
86
82
|
}
|
|
87
83
|
|
|
88
|
-
const hasTimeoutMacro = /setTimeout\([^,]+,\s*0\)/.test(line);
|
|
89
|
-
const isTimeoutEligible = !shouldDropLine && shouldFix('MACRO_TASK_OVER_MICRO_TASK');
|
|
90
|
-
if (isTimeoutEligible && hasTimeoutMacro) {
|
|
91
|
-
line = line.replace(/setTimeout\(([^,]+),\s*0\)/g, 'queueMicrotask($1)');
|
|
92
|
-
fixes.push({
|
|
93
|
-
line: lineNumber,
|
|
94
|
-
rule: 'MACRO_TASK_OVER_MICRO_TASK',
|
|
95
|
-
action: 'Replaced setTimeout(fn, 0) with queueMicrotask(fn)'
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
|
|
99
84
|
if (!shouldDropLine) {
|
|
100
85
|
resultLines.push(line);
|
|
101
86
|
}
|
package/cli/audit.js
CHANGED
|
@@ -226,11 +226,8 @@ export const runAudit = (targetDir = 'src', options = {}) => {
|
|
|
226
226
|
const patterns = patternRegistry.resolveHarmonizationCandidates(hotspots);
|
|
227
227
|
const roadmap = buildRemediationRoadmap({ hotspots, violations, patterns });
|
|
228
228
|
|
|
229
|
-
const stage = options.stage || (options.relax ? 'draft' : 'strict');
|
|
230
|
-
|
|
231
229
|
const report = {
|
|
232
230
|
targetDir,
|
|
233
|
-
stage,
|
|
234
231
|
options,
|
|
235
232
|
scannedFiles,
|
|
236
233
|
totalViolations: violations.length,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* cmd-audit.js
|
|
2
|
+
* cmd-audit.js — Audit command orchestrator.
|
|
3
3
|
* Single responsibility: run the full AST audit pipeline given CLI args.
|
|
4
4
|
* Extracted from cli/index.js per Directive 1.A (Monolith Decomposition).
|
|
5
5
|
*/
|
|
@@ -47,19 +47,6 @@ export const runAudit = async (customDir, isCli, rawArgs, loadProjectConfig) =>
|
|
|
47
47
|
const isPromptOnFail = rawArgs.includes('--prompt-on-fail');
|
|
48
48
|
const isCopyPrompt = rawArgs.includes('--copy-prompt');
|
|
49
49
|
|
|
50
|
-
const stageFlag = rawArgs.find((arg) => arg.startsWith('--stage='));
|
|
51
|
-
let stage = 'strict';
|
|
52
|
-
if (stageFlag) {
|
|
53
|
-
stage = stageFlag.split('=')[1];
|
|
54
|
-
} else if (rawArgs.includes('--relax') || rawArgs.includes('--draft')) {
|
|
55
|
-
stage = 'draft';
|
|
56
|
-
} else if (isStrict) {
|
|
57
|
-
stage = 'strict';
|
|
58
|
-
} else if (projectConfig.stage) {
|
|
59
|
-
stage = projectConfig.stage;
|
|
60
|
-
}
|
|
61
|
-
const isDraft = stage === 'draft';
|
|
62
|
-
|
|
63
50
|
const dirFlag = rawArgs.find((arg) => arg.startsWith('--dir='));
|
|
64
51
|
const outputFlag = rawArgs.find((arg) => arg.startsWith('--output=') || arg.startsWith('-o='));
|
|
65
52
|
const outputFile = outputFlag ? outputFlag.split('=')[1] : null;
|
|
@@ -101,7 +88,7 @@ export const runAudit = async (customDir, isCli, rawArgs, loadProjectConfig) =>
|
|
|
101
88
|
fileList = preflight.fileList;
|
|
102
89
|
}
|
|
103
90
|
|
|
104
|
-
const auditOptions = { outputFile, model, costPerMillion, fast: isFast, fileList
|
|
91
|
+
const auditOptions = { outputFile, model, costPerMillion, fast: isFast, fileList };
|
|
105
92
|
const report = executeAstAudit(targetDir, auditOptions);
|
|
106
93
|
saveAuditSnapshot(report);
|
|
107
94
|
const syncRes = syncSearchIndex(targetDir, process.cwd());
|
|
@@ -115,35 +102,9 @@ export const runAudit = async (customDir, isCli, rawArgs, loadProjectConfig) =>
|
|
|
115
102
|
process.stdout.write(`\x1b[32m✔\x1b[0m Auto-triage generated ${createdTasks.length} team task(s) from audit violations.\n`);
|
|
116
103
|
}
|
|
117
104
|
}
|
|
118
|
-
if (rawArgs.includes('--clones')) {
|
|
119
|
-
const { detectSemanticClones } = await import('../audit/clone-detector.js');
|
|
120
|
-
const { formatCloneReport } = await import('../audit/reporter-clones.js');
|
|
121
|
-
const cloneThresholdArg = rawArgs.find((a) => a.startsWith('--clone-threshold='));
|
|
122
|
-
const threshold = cloneThresholdArg ? parseFloat(cloneThresholdArg.split('=')[1]) : 0.85;
|
|
123
|
-
const clones = detectSemanticClones(syncRes.db, { threshold });
|
|
124
|
-
if (isJson) {
|
|
125
|
-
report.clones = clones;
|
|
126
|
-
} else {
|
|
127
|
-
process.stdout.write(formatCloneReport(clones));
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
if (rawArgs.includes('--hotspot-graph')) {
|
|
131
|
-
const { calculateCascadingHotspotGraph } = await import('../search-queries-hotspot-graph.js');
|
|
132
|
-
const { formatHotspotGraphReport } = await import('../audit/reporter-hotspot-graph.js');
|
|
133
|
-
const limitArg = rawArgs.find((a) => a.startsWith('--limit='));
|
|
134
|
-
const limit = limitArg ? parseInt(limitArg.split('=')[1], 10) : 10;
|
|
135
|
-
const graph = calculateCascadingHotspotGraph(syncRes.db, { limit });
|
|
136
|
-
if (isJson) {
|
|
137
|
-
report.hotspotGraph = graph;
|
|
138
|
-
} else {
|
|
139
|
-
process.stdout.write(formatHotspotGraphReport(graph));
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
105
|
}
|
|
143
106
|
|
|
144
107
|
// Stage 1: Atomic failure predicates
|
|
145
|
-
const isCriticalViolation = (v) => v.severity === 'CRITICAL';
|
|
146
|
-
const hasCritical = report.violations.some(isCriticalViolation);
|
|
147
108
|
const isSevereViolation = (v) => v.severity === 'CRITICAL' || v.severity === 'HIGH';
|
|
148
109
|
const hasCriticalOrHigh = report.violations.some(isSevereViolation);
|
|
149
110
|
const hasViolations = report.violations.length > 0;
|
|
@@ -155,8 +116,7 @@ export const runAudit = async (customDir, isCli, rawArgs, loadProjectConfig) =>
|
|
|
155
116
|
const isDefaultFail = !hasThreshold && !isStrict && hasCriticalOrHigh;
|
|
156
117
|
|
|
157
118
|
// Stage 2: Unified failure decision
|
|
158
|
-
const
|
|
159
|
-
const hasFailingViolations = isDraft ? hasCritical : hasStandardFailure;
|
|
119
|
+
const hasFailingViolations = evaluateAuditFailure([isStrictFail, isDefaultFail, isGradeFail, isScoreFail]);
|
|
160
120
|
|
|
161
121
|
if (isJson) {
|
|
162
122
|
process.stdout.write(JSON.stringify(report, null, 2) + '\n');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* cmd-router.js
|
|
2
|
+
* cmd-router.js — CLI command dispatch table.
|
|
3
3
|
* Single responsibility: map first-arg tokens to their lazy-loaded command handlers.
|
|
4
4
|
* Extracted from cli/index.js per Directive 1.A (Monolith Decomposition).
|
|
5
5
|
*/
|
|
@@ -67,12 +67,6 @@ export const dispatchCommand = async (firstArg, rawArgs, runAudit, getPackageVer
|
|
|
67
67
|
await runAudit(posDir, true);
|
|
68
68
|
break;
|
|
69
69
|
}
|
|
70
|
-
case 'trend':
|
|
71
|
-
case 'trends': {
|
|
72
|
-
const { runTrend } = await import('../trend.js');
|
|
73
|
-
runTrend(rawArgs.slice(1), process.cwd());
|
|
74
|
-
break;
|
|
75
|
-
}
|
|
76
70
|
case 'init': {
|
|
77
71
|
const { runInit } = await import('../scaffold.js');
|
|
78
72
|
await runInit(rawArgs[1] || 'src/chemical-x', rawArgs, runAudit);
|
|
@@ -113,12 +107,6 @@ export const dispatchCommand = async (firstArg, rawArgs, runAudit, getPackageVer
|
|
|
113
107
|
await runMutatorCli(rawArgs, true);
|
|
114
108
|
break;
|
|
115
109
|
}
|
|
116
|
-
case 'explode':
|
|
117
|
-
case 'unpack': {
|
|
118
|
-
const { runExplodeCli } = await import('../exploder.js');
|
|
119
|
-
await runExplodeCli(rawArgs.slice(1), true);
|
|
120
|
-
break;
|
|
121
|
-
}
|
|
122
110
|
case 'add': {
|
|
123
111
|
if (['prop', 'state', 'action'].includes(rawArgs[1])) {
|
|
124
112
|
const { runMutatorCli } = await import('../mutators.js');
|
|
@@ -7,10 +7,6 @@ import { INPUT_ARCHETYPES } from './input-archetypes.js';
|
|
|
7
7
|
import { LAYOUT_ARCHETYPES } from './layout-archetypes.js';
|
|
8
8
|
import { DOMAIN_ARCHETYPES } from './domain-archetypes.js';
|
|
9
9
|
import { STATUS_ARCHETYPES } from './status-archetypes.js';
|
|
10
|
-
import { MINIMAL_ARCHETYPES } from './minimal-archetypes.js';
|
|
11
|
-
import { matchArchetypeByVector } from './vector-matcher.js';
|
|
12
|
-
|
|
13
|
-
export { matchArchetypeByVector };
|
|
14
10
|
|
|
15
11
|
export const ALL_ARCHETYPES = [
|
|
16
12
|
...COLLECTION_ARCHETYPES,
|
|
@@ -20,24 +16,7 @@ export const ALL_ARCHETYPES = [
|
|
|
20
16
|
...STATUS_ARCHETYPES
|
|
21
17
|
];
|
|
22
18
|
|
|
23
|
-
export const
|
|
24
|
-
...MINIMAL_ARCHETYPES,
|
|
25
|
-
...ALL_ARCHETYPES
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
const isPartialMatch = (token, kw) => {
|
|
29
|
-
const isMinLength = token.length >= 3;
|
|
30
|
-
const isAffixMatch = token.startsWith(kw) || kw.startsWith(token);
|
|
31
|
-
return isMinLength && isAffixMatch;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
export const resolveArchetype = (slug = '', description = '', explicitTemplate = '') => {
|
|
35
|
-
if (explicitTemplate) {
|
|
36
|
-
const templateNorm = String(explicitTemplate).toLowerCase().trim();
|
|
37
|
-
const exactMatch = EXTENDED_ARCHETYPES.find((a) => a.id === templateNorm || a.keywords.includes(templateNorm));
|
|
38
|
-
if (exactMatch) return exactMatch;
|
|
39
|
-
}
|
|
40
|
-
|
|
19
|
+
export const resolveArchetype = (slug = '', description = '') => {
|
|
41
20
|
const normalized = String(slug).toLowerCase().replace(/^(m-|a-|o-|t-|v-|use-)/, '');
|
|
42
21
|
const slugTokens = normalized.split(/[-_]/).filter(Boolean);
|
|
43
22
|
const descTokens = String(description)
|
|
@@ -61,7 +40,7 @@ export const resolveArchetype = (slug = '', description = '', explicitTemplate =
|
|
|
61
40
|
for (const kw of archetype.keywords) {
|
|
62
41
|
if (token === kw) {
|
|
63
42
|
score += 12;
|
|
64
|
-
} else if (
|
|
43
|
+
} else if (token.length >= 3 && (token.startsWith(kw) || kw.startsWith(token))) {
|
|
65
44
|
score += 8;
|
|
66
45
|
}
|
|
67
46
|
}
|
|
@@ -74,7 +53,7 @@ export const resolveArchetype = (slug = '', description = '', explicitTemplate =
|
|
|
74
53
|
for (const kw of archetype.keywords) {
|
|
75
54
|
if (token === kw) {
|
|
76
55
|
score += 7;
|
|
77
|
-
} else if (
|
|
56
|
+
} else if (token.length >= 3 && (token.startsWith(kw) || kw.startsWith(token))) {
|
|
78
57
|
score += 4;
|
|
79
58
|
}
|
|
80
59
|
}
|
|
@@ -86,19 +65,10 @@ export const resolveArchetype = (slug = '', description = '', explicitTemplate =
|
|
|
86
65
|
}
|
|
87
66
|
}
|
|
88
67
|
|
|
89
|
-
|
|
90
|
-
if (hasKeywordWinner) {
|
|
68
|
+
if (bestArchetype && highestScore > 0) {
|
|
91
69
|
return bestArchetype;
|
|
92
70
|
}
|
|
93
71
|
|
|
94
|
-
const hasDescription = Boolean(description && String(description).trim());
|
|
95
|
-
if (hasDescription) {
|
|
96
|
-
const vectorMatch = matchArchetypeByVector(description, 0.3);
|
|
97
|
-
if (vectorMatch) {
|
|
98
|
-
return vectorMatch.archetype;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
72
|
// Fallback to State Boundary (Archetype #22 in LAYOUT_ARCHETYPES)
|
|
103
73
|
return LAYOUT_ARCHETYPES.find((a) => a.id === 'state-boundary') || ALL_ARCHETYPES[0];
|
|
104
74
|
};
|
|
@@ -3,7 +3,7 @@ import { convertReactControllerToVue, convertReactControllerToSvelte } from './c
|
|
|
3
3
|
|
|
4
4
|
export const buildController = (name, pascalName, options = {}) => {
|
|
5
5
|
const fw = options.framework ? options.framework.toLowerCase() : 'react';
|
|
6
|
-
const archetype = resolveArchetype(name, options.description || options.desc
|
|
6
|
+
const archetype = resolveArchetype(name, options.description || options.desc);
|
|
7
7
|
|
|
8
8
|
if (archetype && typeof archetype.buildController === 'function') {
|
|
9
9
|
const rawReactController = archetype.buildController(name, pascalName);
|
|
@@ -3,7 +3,7 @@ import { resolveArchetype } from './archetypes/index.js';
|
|
|
3
3
|
export const buildReactComponent = (name, pascalName, options = {}) => {
|
|
4
4
|
const atomsPackage = options.atomsPackage || null;
|
|
5
5
|
const hasController = options.hasController !== false;
|
|
6
|
-
const archetype = resolveArchetype(name, options.description || options.desc
|
|
6
|
+
const archetype = resolveArchetype(name, options.description || options.desc);
|
|
7
7
|
|
|
8
8
|
const atomImport = atomsPackage ? `import { AtomButton } from '${atomsPackage}';\n` : '';
|
|
9
9
|
const controllerImport = hasController
|
|
@@ -3,7 +3,7 @@ import { resolveArchetype } from './archetypes/index.js';
|
|
|
3
3
|
export const buildSvelteComponent = (name, pascalName, options = {}) => {
|
|
4
4
|
const atomsPackage = options.atomsPackage || null;
|
|
5
5
|
const hasController = options.hasController !== false;
|
|
6
|
-
const archetype = resolveArchetype(name, options.description || options.desc
|
|
6
|
+
const archetype = resolveArchetype(name, options.description || options.desc);
|
|
7
7
|
const atomImport = atomsPackage ? `import { AtomButton } from '${atomsPackage}';\n` : '';
|
|
8
8
|
|
|
9
9
|
const controllerImport = hasController
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { resolveArchetype } from './archetypes/index.js';
|
|
2
2
|
|
|
3
3
|
export const buildPropsType = (name, pascalName, options = {}) => {
|
|
4
|
-
const archetype = resolveArchetype(name, options.description || options.desc
|
|
4
|
+
const archetype = resolveArchetype(name, options.description || options.desc);
|
|
5
5
|
if (archetype && typeof archetype.buildProps === 'function') {
|
|
6
6
|
const rawProps = archetype.buildProps(name, pascalName);
|
|
7
7
|
if (!rawProps.includes(`${pascalName}Emits`)) {
|
|
@@ -28,7 +28,7 @@ export interface ${pascalName}Emits {
|
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
export const buildStateType = (name, pascalName, options = {}) => {
|
|
31
|
-
const archetype = resolveArchetype(name, options.description || options.desc
|
|
31
|
+
const archetype = resolveArchetype(name, options.description || options.desc);
|
|
32
32
|
if (archetype && typeof archetype.buildState === 'function') {
|
|
33
33
|
return archetype.buildState(name, pascalName);
|
|
34
34
|
}
|
|
@@ -3,7 +3,7 @@ import { resolveArchetype } from './archetypes/index.js';
|
|
|
3
3
|
export const buildVueComponent = (name, pascalName, options = {}) => {
|
|
4
4
|
const atomsPackage = options.atomsPackage || null;
|
|
5
5
|
const hasController = options.hasController !== false;
|
|
6
|
-
const archetype = resolveArchetype(name, options.description || options.desc
|
|
6
|
+
const archetype = resolveArchetype(name, options.description || options.desc);
|
|
7
7
|
|
|
8
8
|
const controllerImport = hasController
|
|
9
9
|
? `import { use${pascalName}Controller } from './${name}.controller';\n`
|
|
@@ -180,8 +180,3 @@ test('archetypes: resolveArchetype matches from description keywords', () => {
|
|
|
180
180
|
const cart = resolveArchetype('m-box', 'shopping cart checkout billing payment');
|
|
181
181
|
assert.equal(cart.id, 'cart-billing');
|
|
182
182
|
});
|
|
183
|
-
|
|
184
|
-
test('archetypes: resolveArchetype matches from semantic vector embeddings on unknown slugs', () => {
|
|
185
|
-
const chat = resolveArchetype('m-quantum-nexus', 'live chat messages conversation thread');
|
|
186
|
-
assert.equal(chat.id, 'chat-messaging');
|
|
187
|
-
});
|
package/cli/generator.js
CHANGED
|
@@ -5,7 +5,6 @@ import { checkOrPromptEvaluation } from './license.js';
|
|
|
5
5
|
import {
|
|
6
6
|
toPascalCase,
|
|
7
7
|
toCamelCase,
|
|
8
|
-
resolveArchetype,
|
|
9
8
|
buildReactComponent,
|
|
10
9
|
buildVueComponent,
|
|
11
10
|
buildSvelteComponent,
|
|
@@ -26,10 +25,9 @@ import {
|
|
|
26
25
|
buildSvelteView,
|
|
27
26
|
buildViewParamsType,
|
|
28
27
|
buildViewIndex,
|
|
29
|
-
buildViewSpec
|
|
30
|
-
buildCompactCapsule
|
|
28
|
+
buildViewSpec
|
|
31
29
|
} from './generator-templates.js';
|
|
32
|
-
import { detectFramework, resolveFramework, detectTierBaseDir, detectInstalledFamily, detectTestRunner
|
|
30
|
+
import { detectFramework, resolveFramework, detectTierBaseDir, detectInstalledFamily, detectTestRunner } from './project-detector.js';
|
|
33
31
|
|
|
34
32
|
const TIERS = [
|
|
35
33
|
{ prefix: 'm-', tier: 'molecule', label: '1. m- Molecule (Self-contained feature block < 100 lines - Recommended)' },
|
|
@@ -84,20 +82,11 @@ export const createCapsuleFiles = ({
|
|
|
84
82
|
cwd = process.cwd(),
|
|
85
83
|
desc = '',
|
|
86
84
|
description = '',
|
|
87
|
-
template = null,
|
|
88
|
-
templateArg = null,
|
|
89
|
-
css = null,
|
|
90
|
-
compact = false,
|
|
91
|
-
flat = false,
|
|
92
85
|
dryRun = false
|
|
93
86
|
}) => {
|
|
94
87
|
const capsuleDesc = desc || description || '';
|
|
95
88
|
const cleanName = (name || 'user-avatar').trim().toLowerCase();
|
|
96
89
|
const selectedTier = resolveSelectedTier(tier, cleanName);
|
|
97
|
-
const explicitTemplate = template || templateArg || null;
|
|
98
|
-
const isCompact = Boolean(compact || flat);
|
|
99
|
-
const styling = detectStylingStack(cwd);
|
|
100
|
-
const wantsNoScss = css === 'none' || css === 'tailwind' || (styling.hasTailwind && css !== 'scss');
|
|
101
90
|
|
|
102
91
|
const resolvedFrameworkId = resolveFramework({ frameworkArg: framework, cwd });
|
|
103
92
|
const selectedFramework = FRAMEWORKS.find(
|
|
@@ -123,56 +112,6 @@ export const createCapsuleFiles = ({
|
|
|
123
112
|
const detectedDir = detectTierBaseDir(selectedTier.tier, cwd);
|
|
124
113
|
const parentDir = targetParent || detectedDir;
|
|
125
114
|
const resolvedParent = path.resolve(cwd, parentDir || '.');
|
|
126
|
-
|
|
127
|
-
const isHookOrView = selectedTier.tier === 'hook' || selectedTier.tier === 'view';
|
|
128
|
-
const canUseCompact = isCompact && !isHookOrView;
|
|
129
|
-
if (canUseCompact) {
|
|
130
|
-
const compFile = `${capsuleName}.${selectedFramework.ext}`;
|
|
131
|
-
const targetFilePath = path.resolve(resolvedParent, compFile);
|
|
132
|
-
|
|
133
|
-
if (!dryRun && fs.existsSync(targetFilePath)) {
|
|
134
|
-
throw new Error(`File ${compFile} already exists at ${targetFilePath}.`);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const archetype = resolveArchetype(capsuleName, capsuleDesc, explicitTemplate);
|
|
138
|
-
const installedFamily = detectInstalledFamily(cwd);
|
|
139
|
-
const compactContent = buildCompactCapsule({
|
|
140
|
-
capsuleName,
|
|
141
|
-
pascalName,
|
|
142
|
-
framework: selectedFramework.id,
|
|
143
|
-
archetype,
|
|
144
|
-
atomsPackage: installedFamily.atomsPackage
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
const filesCreated = [compFile];
|
|
148
|
-
const previews = [{ file: compFile, lines: compactContent.split('\n').length }];
|
|
149
|
-
|
|
150
|
-
if (!dryRun) {
|
|
151
|
-
if (!fs.existsSync(resolvedParent)) {
|
|
152
|
-
fs.mkdirSync(resolvedParent, { recursive: true });
|
|
153
|
-
}
|
|
154
|
-
fs.writeFileSync(targetFilePath, compactContent, 'utf-8');
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
const relTargetDir = path.relative(cwd, targetFilePath);
|
|
158
|
-
|
|
159
|
-
return {
|
|
160
|
-
success: true,
|
|
161
|
-
compact: true,
|
|
162
|
-
dryRun: Boolean(dryRun),
|
|
163
|
-
capsuleName,
|
|
164
|
-
pascalName,
|
|
165
|
-
framework: selectedFramework.id,
|
|
166
|
-
tier: selectedTier.tier,
|
|
167
|
-
targetDir: targetFilePath,
|
|
168
|
-
relativeDir: relTargetDir,
|
|
169
|
-
directory: relTargetDir,
|
|
170
|
-
files: filesCreated,
|
|
171
|
-
filesCreated,
|
|
172
|
-
previews
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
|
|
176
115
|
const targetDir = path.resolve(resolvedParent, capsuleName);
|
|
177
116
|
const runner = detectTestRunner(targetDir || cwd);
|
|
178
117
|
|
|
@@ -231,26 +170,24 @@ export const createCapsuleFiles = ({
|
|
|
231
170
|
atomsPackage: installedFamily.atomsPackage,
|
|
232
171
|
hasController,
|
|
233
172
|
description: capsuleDesc,
|
|
234
|
-
framework: selectedFramework.id
|
|
235
|
-
template: explicitTemplate
|
|
173
|
+
framework: selectedFramework.id
|
|
236
174
|
};
|
|
237
175
|
|
|
238
176
|
recordFile(compFile, path.join(targetDir, compFile), selectedFramework.compBuilder(capsuleName, pascalName, templateOpts));
|
|
239
177
|
recordFile('index.ts', path.join(targetDir, 'index.ts'), buildIndex(capsuleName, pascalName, selectedFramework.ext, hasController));
|
|
240
178
|
recordFile(specFile, path.join(targetDir, specFile), buildComponentSpec(capsuleName, pascalName, hasController, runner));
|
|
241
179
|
|
|
242
|
-
|
|
243
|
-
recordFile('types/
|
|
244
|
-
recordFile('types/state.d.ts', path.join(typesDir, 'state.d.ts'), buildStateType(capsuleName, pascalName, domainOpts));
|
|
180
|
+
recordFile('types/props.d.ts', path.join(typesDir, 'props.d.ts'), buildPropsType(capsuleName, pascalName, { description: capsuleDesc, framework: selectedFramework.id }));
|
|
181
|
+
recordFile('types/state.d.ts', path.join(typesDir, 'state.d.ts'), buildStateType(capsuleName, pascalName, { description: capsuleDesc, framework: selectedFramework.id }));
|
|
245
182
|
recordFile('types/index.ts', path.join(typesDir, 'index.ts'), buildTypesIndex(['props', 'state']));
|
|
246
183
|
recordFile('types.d.ts', path.join(targetDir, 'types.d.ts'), "export * from './types/index';\n");
|
|
247
184
|
|
|
248
185
|
if (hasController) {
|
|
249
186
|
const controllerFile = `${capsuleName}.controller.ts`;
|
|
250
|
-
recordFile(controllerFile, path.join(targetDir, controllerFile), buildController(capsuleName, pascalName,
|
|
187
|
+
recordFile(controllerFile, path.join(targetDir, controllerFile), buildController(capsuleName, pascalName, { description: capsuleDesc, framework: selectedFramework.id }));
|
|
251
188
|
}
|
|
252
189
|
|
|
253
|
-
if (!isLean
|
|
190
|
+
if (!isLean) {
|
|
254
191
|
const scssFile = `_${capsuleName}.scss`;
|
|
255
192
|
recordFile(scssFile, path.join(targetDir, scssFile), buildScss(capsuleName));
|
|
256
193
|
}
|
|
@@ -357,27 +294,6 @@ export const runGenerateWizard = async (rawArgs = []) => {
|
|
|
357
294
|
.replace(/^--(desc|description|prompt)=/, '');
|
|
358
295
|
const isDryRun = rawArgs.includes('--dry-run') || rawArgs.includes('-n');
|
|
359
296
|
|
|
360
|
-
const isBareOrMinimal = rawArgs.includes('--bare') || rawArgs.includes('--minimal');
|
|
361
|
-
const templateFlagMatch = (rawArgs.find((a) => a.startsWith('--template=')) || '').split('=')[1];
|
|
362
|
-
let templateArg = templateFlagMatch || null;
|
|
363
|
-
if (!templateArg && isBareOrMinimal) {
|
|
364
|
-
templateArg = 'minimal';
|
|
365
|
-
} else if (!templateArg && rawArgs.includes('--controls')) {
|
|
366
|
-
templateArg = 'controls';
|
|
367
|
-
} else if (!templateArg && rawArgs.includes('--canvas')) {
|
|
368
|
-
templateArg = 'canvas';
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
const cssFlagMatch = (rawArgs.find((a) => a.startsWith('--css=')) || '').split('=')[1];
|
|
372
|
-
let cssArg = cssFlagMatch || null;
|
|
373
|
-
if (!cssArg && rawArgs.includes('--no-scss')) {
|
|
374
|
-
cssArg = 'none';
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
const hasCompactFlag = rawArgs.includes('--compact');
|
|
378
|
-
const hasFlatFlag = rawArgs.includes('--flat');
|
|
379
|
-
const isCompact = hasCompactFlag || hasFlatFlag;
|
|
380
|
-
|
|
381
297
|
if (!rawName && !isYes) {
|
|
382
298
|
rawName = useGum
|
|
383
299
|
? gumInput('Capsule feature name (e.g. user-avatar, spark-kpi, auth-status):', 'user-avatar')
|
|
@@ -455,9 +371,6 @@ export const runGenerateWizard = async (rawArgs = []) => {
|
|
|
455
371
|
isLean,
|
|
456
372
|
cwd: process.cwd(),
|
|
457
373
|
desc: descArg,
|
|
458
|
-
template: templateArg,
|
|
459
|
-
css: cssArg,
|
|
460
|
-
compact: isCompact,
|
|
461
374
|
dryRun: isDryRun
|
|
462
375
|
});
|
|
463
376
|
} catch (err) {
|
package/cli/index.js
CHANGED
|
@@ -67,12 +67,11 @@ export const patchFile = async (...a) => (await import('./patcher.js')).pa
|
|
|
67
67
|
export const runWriterCli = async (...a) => (await import('./patcher.js')).runWriterCli(...a);
|
|
68
68
|
export const writeFile = async (...a) => (await import('./patcher.js')).writeFile(...a);
|
|
69
69
|
export const runTeamCli = async (...a) => (await import('./team/index.js')).runTeamCli(...a);
|
|
70
|
-
export const runTrend = async (...a) => (await import('./trend.js')).runTrend(...a);
|
|
71
70
|
export const runPillarsWizard = async (...a) => (await import('./pillars-wizard.js')).runPillarsWizard(...a);
|
|
72
71
|
export { handleError, withErrorCatcher, publishIssue };
|
|
73
72
|
|
|
74
73
|
// ---------------------------------------------------------------------------
|
|
75
|
-
// Allowed commands guard (exits early before any heavy import)
|
|
74
|
+
// Allowed commands guard (exits early — before any heavy import)
|
|
76
75
|
// ---------------------------------------------------------------------------
|
|
77
76
|
|
|
78
77
|
export const ALLOWED_COMMANDS = new Set([
|
|
@@ -81,9 +80,7 @@ export const ALLOWED_COMMANDS = new Set([
|
|
|
81
80
|
'patch', 'edit',
|
|
82
81
|
'write',
|
|
83
82
|
'generate', 'g', 'gen', 'capsule', 'add',
|
|
84
|
-
'explode', 'unpack',
|
|
85
83
|
'audit',
|
|
86
|
-
'trend', 'trends',
|
|
87
84
|
'verify', 'check:all',
|
|
88
85
|
'team', 'swarm', 'feed',
|
|
89
86
|
'pillars', 'rules', 'config:pillars',
|
|
@@ -103,7 +100,7 @@ export const ALLOWED_COMMANDS = new Set([
|
|
|
103
100
|
]);
|
|
104
101
|
|
|
105
102
|
// ---------------------------------------------------------------------------
|
|
106
|
-
// main
|
|
103
|
+
// main — thin orchestrator; real dispatch lives in cmd-router.js
|
|
107
104
|
// ---------------------------------------------------------------------------
|
|
108
105
|
|
|
109
106
|
const main = async () => {
|
package/cli/mcp/antigravity.js
CHANGED
|
@@ -8,9 +8,8 @@ export const buildMcpInstructions = () => {
|
|
|
8
8
|
'# Chemical X Protocol: Master MCP Gateway Guide (chemical-x / chemx)',
|
|
9
9
|
'',
|
|
10
10
|
'MASTER TOOL: "chemx" (chemical-x / chemx)',
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'Pass the desired operation via the action parameter; see action: \'help\' for the full list.',
|
|
11
|
+
'Recommended gateway tool for all Chemical X operations. Dispatches all sub-operations',
|
|
12
|
+
'through a single tool for token efficiency and single-point authorization.',
|
|
14
13
|
'',
|
|
15
14
|
'1. TESTING, BUILDS & VERIFICATION:',
|
|
16
15
|
' - chemx({ action: "test" }) or chemx({ command: "test" })',
|
package/cli/mcp/manifests.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
export const MASTER_MCP_TOOL = {
|
|
7
7
|
name: 'chemx',
|
|
8
|
-
description:
|
|
8
|
+
description: 'Chemical X Protocol Master Gateway: provides all Chemical X operations (test, build, verify, typecheck, audit, read, patch, write, check, q, team, autofix, generate, patterns, issue) through a single unified tool. Recommended for token efficiency and single-point authorization.',
|
|
9
9
|
inputSchema: {
|
|
10
10
|
type: 'object',
|
|
11
11
|
properties: {
|
package/cli/mcp/tools-search.js
CHANGED
|
@@ -11,7 +11,6 @@ import {
|
|
|
11
11
|
querySemanticIndex,
|
|
12
12
|
queryHybridIndex
|
|
13
13
|
} from '../search-queries.js';
|
|
14
|
-
import { findSimilarSymbols } from '../search-queries-similar.js';
|
|
15
14
|
import { readTokenOptimized } from '../reader.js';
|
|
16
15
|
import { patchFile, writeFile } from '../patcher.js';
|
|
17
16
|
import { toColumnar } from '../columnar.js';
|
|
@@ -186,12 +185,7 @@ export const handleChemxRead = (args = {}, cwd = process.cwd()) => {
|
|
|
186
185
|
const blast = calculateBlastRadius(db, args.symbol || targetPath);
|
|
187
186
|
if (args.symbol) {
|
|
188
187
|
const refs = findSymbolReferences(db, args.symbol);
|
|
189
|
-
|
|
190
|
-
const hasSimilar = similar.length > 0;
|
|
191
|
-
const simSuffix = hasSimilar
|
|
192
|
-
? ` Similar symbols: ${similar.map((s) => `${s.name} (${Math.round(s.similarity * 100)}%)`).join(', ')}.`
|
|
193
|
-
: '';
|
|
194
|
-
connectionCard = `\n// Connections for ${args.symbol}: referenced by ${refs.length} file(s) [${refs.slice(0, 3).map((r) => path.basename(r.importerPath)).join(', ')}]. Blast Radius: ${blast.totalImpactCount} affected file(s) across ${blast.depth} hops (${blast.impactedTests.length} tests).${simSuffix}`;
|
|
188
|
+
connectionCard = `\n// Connections for ${args.symbol}: referenced by ${refs.length} file(s) [${refs.slice(0, 3).map((r) => path.basename(r.importerPath)).join(', ')}]. Blast Radius: ${blast.totalImpactCount} affected file(s) across ${blast.depth} hops (${blast.impactedTests.length} tests).`;
|
|
195
189
|
} else {
|
|
196
190
|
const deps = findFileDependencies(db, targetPath);
|
|
197
191
|
const dependents = findFileDependents(db, targetPath);
|
package/cli/mcp/tools.js
CHANGED
|
@@ -15,8 +15,6 @@ import { runBuildAudit } from '../build.js';
|
|
|
15
15
|
import { runAutofix } from '../audit/autofix.js';
|
|
16
16
|
import { runTypecheckAudit, runTestAudit, runProjectVerify } from '../verify.js';
|
|
17
17
|
import { syncSearchIndex, syncViolationsIndex, recordAuditSnapshot } from '../search.js';
|
|
18
|
-
import { openIndexDb } from '../search-schema.js';
|
|
19
|
-
import { fetchScoreTrends, formatTrendReport, renderSparkline } from '../trend.js';
|
|
20
18
|
import { MCP_TOOLS, ALL_MCP_TOOLS } from './manifests.js';
|
|
21
19
|
import {
|
|
22
20
|
resolveTargetCwd,
|
|
@@ -288,24 +286,6 @@ const handleChemxVerify = async (args = {}, cwd = process.cwd()) => {
|
|
|
288
286
|
});
|
|
289
287
|
};
|
|
290
288
|
|
|
291
|
-
const handleChemxTrend = async (args = {}, cwd = process.cwd()) => {
|
|
292
|
-
const targetCwd = resolveTargetCwd(args.cwd || cwd);
|
|
293
|
-
const db = openIndexDb(targetCwd);
|
|
294
|
-
const limit = args.limit || 10;
|
|
295
|
-
const snapshots = fetchScoreTrends(db, limit);
|
|
296
|
-
if (args.json) {
|
|
297
|
-
const scores = snapshots.map((s) => s.score);
|
|
298
|
-
return {
|
|
299
|
-
count: snapshots.length,
|
|
300
|
-
sparkline: renderSparkline(scores),
|
|
301
|
-
latestScore: snapshots.length ? snapshots[snapshots.length - 1].score : null,
|
|
302
|
-
delta: snapshots.length >= 2 ? snapshots[snapshots.length - 1].score - snapshots[0].score : 0,
|
|
303
|
-
snapshots
|
|
304
|
-
};
|
|
305
|
-
}
|
|
306
|
-
return formatTrendReport(snapshots);
|
|
307
|
-
};
|
|
308
|
-
|
|
309
289
|
const handleChemx = async (args = {}, cwd = process.cwd()) => {
|
|
310
290
|
let action = args.action;
|
|
311
291
|
let params = args.params || {};
|
|
@@ -351,14 +331,11 @@ const handleChemx = async (args = {}, cwd = process.cwd()) => {
|
|
|
351
331
|
} else if (subCmd === 'autofix') {
|
|
352
332
|
action = 'autofix';
|
|
353
333
|
params = { path: parts[1] || 'src', ...params };
|
|
354
|
-
} else if (subCmd === 'trend' || subCmd === 'trends') {
|
|
355
|
-
action = 'trend';
|
|
356
334
|
}
|
|
357
335
|
}
|
|
358
336
|
|
|
359
337
|
const DISPATCHER = {
|
|
360
338
|
audit: handleAudit,
|
|
361
|
-
trend: handleChemxTrend,
|
|
362
339
|
build: handleAuditBuild,
|
|
363
340
|
verify: handleChemxVerify,
|
|
364
341
|
typecheck: handleChemxTypecheck,
|