@chemx/starter-kit 26.9.25-943 → 26.9.26-253
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/prompts.js +1 -1
- package/cli/commands/cmd-router.js +20 -2
- package/cli/commands-schema.js +65 -6
- package/cli/generator-help.js +26 -6
- package/cli/generator-jig-cli.js +67 -0
- package/cli/generator-jig.js +479 -0
- package/cli/generator-jig.spec.js +148 -0
- package/cli/generator.js +15 -2
- package/cli/index.js +4 -1
- package/cli/installer-templates.js +8 -3
- package/cli/mcp/manifests.js +22 -4
- package/cli/mcp/tools-generate.js +22 -2
- package/cli/mcp/tools-read.js +50 -8
- package/cli/mcp/tools-verify.js +2 -0
- package/cli/mcp/tools.js +52 -3
- package/cli/project-detector.js +105 -2
- package/cli/reader-cli.js +146 -0
- package/cli/reader-logic.js +392 -0
- package/cli/reader-logic.spec.js +160 -0
- package/cli/reader.js +78 -171
- package/cli/search-commands-graph.js +125 -1
- package/cli/search-commands.js +7 -1
- package/cli/search-db.js +2 -0
- package/cli/search-queries-graph.js +294 -0
- package/cli/search-queries.js +6 -1
- package/cli/search.js +28 -30
- package/cli/team/team-memory.js +30 -7
- package/cli/team/team-memory.spec.js +24 -0
- package/cli/tesseract.spec.js +2 -2
- package/cli/trace.spec.js +92 -0
- package/cli/verify-helpers.js +46 -3
- package/cli/verify-lint.js +224 -0
- package/cli/verify-lint.spec.js +44 -0
- package/cli/verify.js +8 -1
- package/cli/verify.spec.js +17 -0
- package/package.json +1 -1
- package/scripts/pre-commit.sh +8 -3
package/cli/reader.js
CHANGED
|
@@ -4,63 +4,27 @@ import { parse } from '@babel/parser';
|
|
|
4
4
|
import traverseModule from '@babel/traverse';
|
|
5
5
|
import { ANSI } from './theme.js';
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
*/
|
|
27
|
-
export const compactCode = (code) => {
|
|
28
|
-
return code
|
|
29
|
-
.split('\n')
|
|
30
|
-
.map((line) => line.trimEnd())
|
|
31
|
-
.filter((line, idx, arr) => {
|
|
32
|
-
const isCurrentEmpty = line.trim() === '';
|
|
33
|
-
const isPrevEmpty = idx > 0 && arr[idx - 1].trim() === '';
|
|
34
|
-
return !(isCurrentEmpty && isPrevEmpty);
|
|
35
|
-
})
|
|
36
|
-
.join('\n');
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const resolveDeclarationKind = (declaration) => {
|
|
40
|
-
const init = declaration.init;
|
|
41
|
-
if (!init) return 'const';
|
|
42
|
-
|
|
43
|
-
if (init.type === 'ArrowFunctionExpression' || init.type === 'FunctionExpression') {
|
|
44
|
-
return 'function';
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
if (init.type !== 'CallExpression') {
|
|
48
|
-
return 'const';
|
|
49
|
-
}
|
|
7
|
+
import {
|
|
8
|
+
stripCodeComments,
|
|
9
|
+
compactCode,
|
|
10
|
+
resolveDeclarationKind,
|
|
11
|
+
summarizeTemplate,
|
|
12
|
+
extractTemplateContent,
|
|
13
|
+
generateAstLogicSkeleton
|
|
14
|
+
} from './reader-logic.js';
|
|
15
|
+
import { runReaderCli } from './reader-cli.js';
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
stripCodeComments,
|
|
19
|
+
compactCode,
|
|
20
|
+
resolveDeclarationKind,
|
|
21
|
+
summarizeTemplate,
|
|
22
|
+
extractTemplateContent,
|
|
23
|
+
generateAstLogicSkeleton
|
|
24
|
+
} from './reader-logic.js';
|
|
25
|
+
export { runReaderCli } from './reader-cli.js';
|
|
50
26
|
|
|
51
|
-
|
|
52
|
-
if (calleeName === 'computed') {
|
|
53
|
-
return 'computed';
|
|
54
|
-
}
|
|
55
|
-
if (calleeName === 'ref') {
|
|
56
|
-
return 'ref';
|
|
57
|
-
}
|
|
58
|
-
if (calleeName && calleeName.startsWith('use')) {
|
|
59
|
-
return 'hook';
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
return 'const';
|
|
63
|
-
};
|
|
27
|
+
const traverse = traverseModule.default || traverseModule;
|
|
64
28
|
|
|
65
29
|
/**
|
|
66
30
|
* Extracts an AST structural outline of a file (types, exports, props, signatures).
|
|
@@ -215,6 +179,22 @@ export const extractSymbolBlock = (code, symbol) => {
|
|
|
215
179
|
};
|
|
216
180
|
};
|
|
217
181
|
|
|
182
|
+
/**
|
|
183
|
+
* Appends a compacted logic skeleton after an outline block.
|
|
184
|
+
* Composable overlay: enriches outline without replacing it.
|
|
185
|
+
*
|
|
186
|
+
* @param {string} rawContent Full file source.
|
|
187
|
+
* @param {string} filePath File path (for template detection).
|
|
188
|
+
* @param {object} options Reader options forwarded to skeleton generator.
|
|
189
|
+
* @returns {{ text: string, tokensEst: number }} Enriched section text and token estimate.
|
|
190
|
+
*/
|
|
191
|
+
const enrichOutline = (rawContent, filePath, options) => {
|
|
192
|
+
const skeleton = generateAstLogicSkeleton(rawContent, filePath, options);
|
|
193
|
+
const compacted = compactCode(skeleton);
|
|
194
|
+
const text = `\n// --- Logic Skeleton ---\n${compacted}`;
|
|
195
|
+
return { text, tokensEst: Math.round(text.length / 3.8) };
|
|
196
|
+
};
|
|
197
|
+
|
|
218
198
|
/**
|
|
219
199
|
* Primary token-optimized file reader.
|
|
220
200
|
*
|
|
@@ -249,14 +229,52 @@ export const readTokenOptimized = (targetPath, options = {}) => {
|
|
|
249
229
|
const rawLines = rawContent.split('\n');
|
|
250
230
|
const totalLines = rawLines.length;
|
|
251
231
|
|
|
232
|
+
if (options.template) {
|
|
233
|
+
const templateText = extractTemplateContent(rawContent, targetPath);
|
|
234
|
+
return {
|
|
235
|
+
file: targetPath,
|
|
236
|
+
totalLines,
|
|
237
|
+
mode: 'template',
|
|
238
|
+
tokensEst: Math.round(templateText.length / 3.8),
|
|
239
|
+
content: templateText,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (options.logic) {
|
|
244
|
+
let logicSource = rawContent;
|
|
245
|
+
if (options.symbol) {
|
|
246
|
+
const block = extractSymbolBlock(rawContent, options.symbol);
|
|
247
|
+
if (!block) {
|
|
248
|
+
throw new Error(`Symbol "${options.symbol}" not found in ${targetPath}`);
|
|
249
|
+
}
|
|
250
|
+
logicSource = block.code;
|
|
251
|
+
}
|
|
252
|
+
let logicText = generateAstLogicSkeleton(logicSource, targetPath, options);
|
|
253
|
+
if (options.compact !== false) {
|
|
254
|
+
logicText = compactCode(logicText);
|
|
255
|
+
}
|
|
256
|
+
return {
|
|
257
|
+
file: targetPath,
|
|
258
|
+
totalLines,
|
|
259
|
+
mode: 'logic',
|
|
260
|
+
symbol: options.symbol || null,
|
|
261
|
+
lineCount: logicText.split('\n').length,
|
|
262
|
+
tokensEst: Math.round(logicText.length / 3.8),
|
|
263
|
+
content: logicText,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
252
267
|
if (options.outline) {
|
|
253
268
|
const outlineText = generateAstOutline(rawContent, targetPath);
|
|
269
|
+
const enriched = options.enrich ? enrichOutline(rawContent, targetPath, options) : null;
|
|
254
270
|
return {
|
|
255
271
|
file: targetPath,
|
|
256
272
|
totalLines,
|
|
257
273
|
mode: 'outline',
|
|
258
274
|
tokensEst: Math.round(outlineText.length / 3.8),
|
|
275
|
+
tokensEnriched: enriched ? enriched.tokensEst : 0,
|
|
259
276
|
content: outlineText,
|
|
277
|
+
enriched: enriched ? enriched.text : null,
|
|
260
278
|
};
|
|
261
279
|
}
|
|
262
280
|
|
|
@@ -290,12 +308,15 @@ export const readTokenOptimized = (targetPath, options = {}) => {
|
|
|
290
308
|
`// To read a specific block, request symbol: chemx({ action: 'read', params: { path: '${rawPath}', symbol: '<name>' } })`,
|
|
291
309
|
`// Or specify a line range: chemx({ action: 'read', params: { path: '${rawPath}', startLine: 1, endLine: 50 } })\n`
|
|
292
310
|
].join('\n');
|
|
311
|
+
const enriched = options.enrich ? enrichOutline(rawContent, rawPath, options) : null;
|
|
293
312
|
return {
|
|
294
313
|
file: rawPath,
|
|
295
314
|
totalLines,
|
|
296
315
|
mode: 'auto-outline',
|
|
297
316
|
tokensEst: Math.round((outlineText.length + notice.length) / 3.8),
|
|
298
|
-
|
|
317
|
+
tokensEnriched: enriched ? enriched.tokensEst : 0,
|
|
318
|
+
content: notice + outlineText,
|
|
319
|
+
enriched: enriched ? enriched.text : null,
|
|
299
320
|
};
|
|
300
321
|
}
|
|
301
322
|
|
|
@@ -345,117 +366,3 @@ export const readTokenOptimized = (targetPath, options = {}) => {
|
|
|
345
366
|
content: processedContent,
|
|
346
367
|
};
|
|
347
368
|
};
|
|
348
|
-
|
|
349
|
-
/**
|
|
350
|
-
* CLI command runner for chemx read / chemx view.
|
|
351
|
-
*
|
|
352
|
-
* @param {string[]} args CLI arguments.
|
|
353
|
-
* @param {boolean} isCli Whether invoked directly from CLI.
|
|
354
|
-
*/
|
|
355
|
-
export const runReaderCli = (args, isCli = false) => {
|
|
356
|
-
if (args.includes('--help') || args.includes('-h') || args.includes('help')) {
|
|
357
|
-
const isJson = args.includes('--json');
|
|
358
|
-
if (isJson) {
|
|
359
|
-
process.stdout.write(JSON.stringify({ help: true, success: true }) + '\n');
|
|
360
|
-
} else {
|
|
361
|
-
process.stdout.write([
|
|
362
|
-
`${ANSI.BOLD}USAGE${ANSI.RESET}`,
|
|
363
|
-
` chemx read <file> [options]`,
|
|
364
|
-
'',
|
|
365
|
-
`${ANSI.BOLD}OPTIONS${ANSI.RESET}`,
|
|
366
|
-
` --outline AST structure outline only (80%+ token savings)`,
|
|
367
|
-
` --symbol=<name> Extract specific function/hook/interface declaration`,
|
|
368
|
-
` --start=<N> Start line number (1-indexed)`,
|
|
369
|
-
` --end=<N> End line number (1-indexed)`,
|
|
370
|
-
` --strip-comments Remove comments to minimize tokens`,
|
|
371
|
-
` --compact Collapse empty whitespace lines`,
|
|
372
|
-
` --json Output result as minified JSON`,
|
|
373
|
-
` -h, --help Show this help message`,
|
|
374
|
-
''
|
|
375
|
-
].join('\n'));
|
|
376
|
-
}
|
|
377
|
-
if (isCli) process.exit(0);
|
|
378
|
-
return { help: true, success: true };
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
const nonFlagArgs = args.filter((a) => !a.startsWith('-'));
|
|
382
|
-
let filePath = nonFlagArgs[0];
|
|
383
|
-
|
|
384
|
-
if (!filePath) {
|
|
385
|
-
process.stderr.write(`${ANSI.RED}✕ Missing file path. Usage: chemx r <file[:start-end]> [-o] [-s name]${ANSI.RESET}\n`);
|
|
386
|
-
if (isCli) process.exit(1);
|
|
387
|
-
return null;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
let startLine;
|
|
391
|
-
let endLine;
|
|
392
|
-
|
|
393
|
-
const colonMatch = filePath.match(/^([^:]+):(\d+)(?:[-:](\d+))?$/);
|
|
394
|
-
if (colonMatch) {
|
|
395
|
-
filePath = colonMatch[1];
|
|
396
|
-
startLine = parseInt(colonMatch[2], 10);
|
|
397
|
-
if (colonMatch[3]) endLine = parseInt(colonMatch[3], 10);
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
const isJson = args.includes('--json') || args.includes('-j');
|
|
401
|
-
const isOutline = args.includes('--outline') || args.includes('-o');
|
|
402
|
-
const isCompact = args.includes('--compact') || args.includes('-c');
|
|
403
|
-
const isStripComments = args.includes('--strip-comments') || args.includes('--no-comments') || args.includes('-sc');
|
|
404
|
-
|
|
405
|
-
let symbol = null;
|
|
406
|
-
const symEqFlag = args.find((a) => a.startsWith('--symbol=') || a.startsWith('-sym='));
|
|
407
|
-
if (symEqFlag) {
|
|
408
|
-
symbol = symEqFlag.split('=')[1];
|
|
409
|
-
} else {
|
|
410
|
-
const sIndex = args.findIndex((a) => a === '-s' || a === '--symbol');
|
|
411
|
-
if (sIndex !== -1 && args[sIndex + 1] && !args[sIndex + 1].startsWith('-')) {
|
|
412
|
-
symbol = args[sIndex + 1];
|
|
413
|
-
} else {
|
|
414
|
-
const sFlag = args.find((a) => a.startsWith('-s='));
|
|
415
|
-
if (sFlag) {
|
|
416
|
-
const val = sFlag.split('=')[1];
|
|
417
|
-
if (/^\d+$/.test(val)) {
|
|
418
|
-
if (startLine === undefined) startLine = parseInt(val, 10);
|
|
419
|
-
} else {
|
|
420
|
-
symbol = val;
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
if (startLine === undefined) {
|
|
427
|
-
const startFlag = args.find((a) => a.startsWith('--start='));
|
|
428
|
-
if (startFlag) startLine = parseInt(startFlag.split('=')[1], 10);
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
if (endLine === undefined) {
|
|
432
|
-
const endFlag = args.find((a) => a.startsWith('--end=') || a.startsWith('-e='));
|
|
433
|
-
if (endFlag) endLine = parseInt(endFlag.split('=')[1], 10);
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
try {
|
|
437
|
-
const res = readTokenOptimized(filePath, {
|
|
438
|
-
outline: isOutline,
|
|
439
|
-
compact: isCompact,
|
|
440
|
-
stripComments: isStripComments,
|
|
441
|
-
symbol,
|
|
442
|
-
startLine,
|
|
443
|
-
endLine,
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
if (isJson) {
|
|
447
|
-
process.stdout.write(JSON.stringify(res, null, 2) + '\n');
|
|
448
|
-
} else {
|
|
449
|
-
process.stdout.write(`${ANSI.BOLD}${ANSI.CYAN}--- ${res.file} (${res.lineCount || res.totalLines} lines, ~${res.tokensEst} tokens) ---${ANSI.RESET}\n`);
|
|
450
|
-
process.stdout.write(res.content + '\n');
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
if (isCli) process.exit(0);
|
|
454
|
-
return res;
|
|
455
|
-
} catch (err) {
|
|
456
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
457
|
-
process.stderr.write(`${ANSI.RED}✕ ${msg}${ANSI.RESET}\n`);
|
|
458
|
-
if (isCli) process.exit(1);
|
|
459
|
-
return null;
|
|
460
|
-
}
|
|
461
|
-
};
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { ANSI } from './theme.js';
|
|
2
2
|
import { toColumnar } from './columnar.js';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
calculateBlastRadius,
|
|
5
|
+
calculateCallTrace,
|
|
6
|
+
calculateBacktrace,
|
|
7
|
+
openIndexDb
|
|
8
|
+
} from './search-db.js';
|
|
4
9
|
|
|
5
10
|
export const handleBlastRadiusCommand = (db, target, { isJson = false, isCli = true, isColumnar = false, maxDepth = 5 } = {}) => {
|
|
6
11
|
const result = calculateBlastRadius(db, target, { maxDepth });
|
|
@@ -80,3 +85,122 @@ export const handleBlastRadiusCommand = (db, target, { isJson = false, isCli = t
|
|
|
80
85
|
if (isCli) process.exit(0);
|
|
81
86
|
return result;
|
|
82
87
|
};
|
|
88
|
+
|
|
89
|
+
const renderCalleeTreeLines = (callees, indent = ' ') => {
|
|
90
|
+
const lines = [];
|
|
91
|
+
callees.forEach((c, idx) => {
|
|
92
|
+
const isLast = idx === callees.length - 1;
|
|
93
|
+
const branch = isLast ? '└── ' : '├── ';
|
|
94
|
+
const subIndent = isLast ? ' ' : '│ ';
|
|
95
|
+
const tag = c.isExternal ? `${ANSI.DIM}[external]${ANSI.RESET}` : `${ANSI.GOLD}[${c.tier}]${ANSI.RESET}`;
|
|
96
|
+
const loc = c.file ? ` ${ANSI.DIM}(${c.file}${c.line ? `:${c.line}` : ''})${ANSI.RESET}` : '';
|
|
97
|
+
lines.push(`${indent}${branch}${ANSI.BOLD}${c.symbol}${ANSI.RESET} ${tag}${loc}`);
|
|
98
|
+
if (c.callees && c.callees.length > 0) {
|
|
99
|
+
lines.push(...renderCalleeTreeLines(c.callees, `${indent}${subIndent}`));
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
return lines;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
export const handleCallTraceCommand = (db, target, { isJson = false, isCli = true, maxDepth = 3 } = {}) => {
|
|
106
|
+
const result = calculateCallTrace(db, target, { maxDepth });
|
|
107
|
+
|
|
108
|
+
if (isJson) {
|
|
109
|
+
process.stdout.write(JSON.stringify(result) + '\n');
|
|
110
|
+
if (isCli) process.exit(0);
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
process.stdout.write(`\n${ANSI.BOLD}${ANSI.CYAN}Forward Call Trace:${ANSI.RESET} ${ANSI.BOLD}${result.target}${ANSI.RESET}\n`);
|
|
115
|
+
if (result.filePath) {
|
|
116
|
+
process.stdout.write(` ${ANSI.DIM}Defined in:${ANSI.RESET} ${result.filePath}:${result.startLine} ${ANSI.DIM}[${result.tier}]${ANSI.RESET}\n`);
|
|
117
|
+
}
|
|
118
|
+
process.stdout.write(` ${ANSI.MINT}Callee Summary:${ANSI.RESET} ${result.totalCallees} downstream calls mapped across ${result.depth} hops\n`);
|
|
119
|
+
|
|
120
|
+
if (result.callees.length === 0) {
|
|
121
|
+
process.stdout.write(` ${ANSI.DIM}No downstream calls or external invocations detected.${ANSI.RESET}\n\n`);
|
|
122
|
+
if (isCli) process.exit(0);
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const treeLines = renderCalleeTreeLines(result.callees, ' ');
|
|
127
|
+
process.stdout.write(treeLines.join('\n') + '\n\n');
|
|
128
|
+
|
|
129
|
+
if (isCli) process.exit(0);
|
|
130
|
+
return result;
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
export const handleBacktraceCommand = (db, target, { isJson = false, isCli = true, maxDepth = 5 } = {}) => {
|
|
134
|
+
const result = calculateBacktrace(db, target, { maxDepth });
|
|
135
|
+
|
|
136
|
+
if (isJson) {
|
|
137
|
+
process.stdout.write(JSON.stringify(result) + '\n');
|
|
138
|
+
if (isCli) process.exit(0);
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
process.stdout.write(`\n${ANSI.BOLD}${ANSI.CYAN}Backtrace Causal Path:${ANSI.RESET} ${ANSI.BOLD}${result.target}${ANSI.RESET}\n`);
|
|
143
|
+
if (result.seedPath) {
|
|
144
|
+
process.stdout.write(` ${ANSI.DIM}Resolved Target:${ANSI.RESET} ${result.seedPath}\n`);
|
|
145
|
+
}
|
|
146
|
+
process.stdout.write(` ${ANSI.MINT}Caller Summary:${ANSI.RESET} ${result.totalCallers} upstream callers across ${result.depth} causal hops\n`);
|
|
147
|
+
|
|
148
|
+
if (result.totalCallers === 0) {
|
|
149
|
+
process.stdout.write(` ${ANSI.DIM}No upstream callers found in project imports.${ANSI.RESET}\n\n`);
|
|
150
|
+
if (isCli) process.exit(0);
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (result.chains.length > 0) {
|
|
155
|
+
process.stdout.write(` ${ANSI.GOLD}Causal Chains (${result.chains.length}):${ANSI.RESET}\n`);
|
|
156
|
+
result.chains.slice(0, 10).forEach((chain, idx) => {
|
|
157
|
+
process.stdout.write(` ${ANSI.DIM}${idx + 1}.${ANSI.RESET} ${chain}\n`);
|
|
158
|
+
});
|
|
159
|
+
if (result.chains.length > 10) {
|
|
160
|
+
process.stdout.write(` ${ANSI.DIM}...and ${result.chains.length - 10} more causal chain(s)${ANSI.RESET}\n`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (result.rootCallers && result.rootCallers.length > 0) {
|
|
165
|
+
process.stdout.write(` ${ANSI.PURPLE}Root Entry Points (${result.rootCallers.length}):${ANSI.RESET}\n`);
|
|
166
|
+
result.rootCallers.forEach((r) => {
|
|
167
|
+
process.stdout.write(` ${ANSI.BOLD}${r.path}${ANSI.RESET} ${ANSI.DIM}[${r.tier}] (depth ${r.depth})${ANSI.RESET}\n`);
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
process.stdout.write('\n');
|
|
172
|
+
if (isCli) process.exit(0);
|
|
173
|
+
return result;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export const runTraceCli = async (args = [], isCli = true) => {
|
|
177
|
+
const nonFlagArgs = args.filter((a) => !a.startsWith('-'));
|
|
178
|
+
const target = nonFlagArgs[0];
|
|
179
|
+
if (!target) {
|
|
180
|
+
process.stderr.write(`${ANSI.RED}✕ Missing symbol or file target. Usage: chemx trace <symbol> [--max-depth=N] [--json]${ANSI.RESET}\n`);
|
|
181
|
+
if (isCli) process.exit(1);
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
const isJson = args.includes('--json') || args.includes('-j');
|
|
185
|
+
const maxDepthFlag = args.find((a) => a.startsWith('--max-depth=') || a.startsWith('-d='));
|
|
186
|
+
const maxDepth = maxDepthFlag ? parseInt(maxDepthFlag.split('=')[1], 10) : 3;
|
|
187
|
+
|
|
188
|
+
const db = openIndexDb(process.cwd());
|
|
189
|
+
return handleCallTraceCommand(db, target, { isJson, isCli, maxDepth });
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
export const runBacktraceCli = async (args = [], isCli = true) => {
|
|
193
|
+
const nonFlagArgs = args.filter((a) => !a.startsWith('-'));
|
|
194
|
+
const target = nonFlagArgs[0];
|
|
195
|
+
if (!target) {
|
|
196
|
+
process.stderr.write(`${ANSI.RED}✕ Missing symbol or file target. Usage: chemx backtrace <symbol> [--max-depth=N] [--json]${ANSI.RESET}\n`);
|
|
197
|
+
if (isCli) process.exit(1);
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
const isJson = args.includes('--json') || args.includes('-j');
|
|
201
|
+
const maxDepthFlag = args.find((a) => a.startsWith('--max-depth=') || a.startsWith('-d='));
|
|
202
|
+
const maxDepth = maxDepthFlag ? parseInt(maxDepthFlag.split('=')[1], 10) : 5;
|
|
203
|
+
|
|
204
|
+
const db = openIndexDb(process.cwd());
|
|
205
|
+
return handleBacktraceCommand(db, target, { isJson, isCli, maxDepth });
|
|
206
|
+
};
|
package/cli/search-commands.js
CHANGED
|
@@ -384,7 +384,13 @@ export const handleCheckCommand = (targetFile, { isJson = false, isCli = true }
|
|
|
384
384
|
return payload;
|
|
385
385
|
};
|
|
386
386
|
|
|
387
|
-
export {
|
|
387
|
+
export {
|
|
388
|
+
handleBlastRadiusCommand,
|
|
389
|
+
handleCallTraceCommand,
|
|
390
|
+
handleBacktraceCommand,
|
|
391
|
+
runTraceCli,
|
|
392
|
+
runBacktraceCli
|
|
393
|
+
} from './search-commands-graph.js';
|
|
388
394
|
export { handleSemanticCommand, handleHybridCommand } from './search-commands-semantic.js';
|
|
389
395
|
|
|
390
396
|
|