@hung319/opencode-hive 1.5.2 → 1.5.6

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/dist/index.js CHANGED
@@ -235,410 +235,6 @@ var require_dist = __commonJS((exports) => {
235
235
  exports.default = AgentBooster;
236
236
  });
237
237
 
238
- // ../../node_modules/.bun/@ast-grep+napi-linux-x64-musl@0.41.1/node_modules/@ast-grep/napi-linux-x64-musl/ast-grep-napi.linux-x64-musl.node
239
- var require_ast_grep_napi_linux_x64_musl = __commonJS((exports, module) => {
240
- module.exports = __require("./ast-grep-napi.linux-x64-musl-qnd01z8b.node");
241
- });
242
-
243
- // ../../node_modules/.bun/@ast-grep+napi-linux-x64-gnu@0.41.1/node_modules/@ast-grep/napi-linux-x64-gnu/ast-grep-napi.linux-x64-gnu.node
244
- var require_ast_grep_napi_linux_x64_gnu = __commonJS((exports, module) => {
245
- module.exports = __require("./ast-grep-napi.linux-x64-gnu-qdwfscvp.node");
246
- });
247
-
248
- // ../../node_modules/.bun/@ast-grep+napi@0.41.1/node_modules/@ast-grep/napi/index.js
249
- var require_napi = __commonJS((exports, module) => {
250
- var __filename = "/home/runner/work/agent-hive/agent-hive/node_modules/.bun/@ast-grep+napi@0.41.1/node_modules/@ast-grep/napi/index.js";
251
- var { createRequire: createRequire2 } = __require("node:module");
252
- __require = createRequire2(__filename);
253
- var { readFileSync: readFileSync5 } = __require("node:fs");
254
- var nativeBinding = null;
255
- var loadErrors = [];
256
- var isMusl = () => {
257
- let musl = false;
258
- if (process.platform === "linux") {
259
- musl = isMuslFromFilesystem();
260
- if (musl === null) {
261
- musl = isMuslFromReport();
262
- }
263
- if (musl === null) {
264
- musl = isMuslFromChildProcess();
265
- }
266
- }
267
- return musl;
268
- };
269
- var isFileMusl = (f) => f.includes("libc.musl-") || f.includes("ld-musl-");
270
- var isMuslFromFilesystem = () => {
271
- try {
272
- return readFileSync5("/usr/bin/ldd", "utf-8").includes("musl");
273
- } catch {
274
- return null;
275
- }
276
- };
277
- var isMuslFromReport = () => {
278
- let report = null;
279
- if (typeof process.report?.getReport === "function") {
280
- process.report.excludeNetwork = true;
281
- report = process.report.getReport();
282
- }
283
- if (!report) {
284
- return null;
285
- }
286
- if (report.header && report.header.glibcVersionRuntime) {
287
- return false;
288
- }
289
- if (Array.isArray(report.sharedObjects)) {
290
- if (report.sharedObjects.some(isFileMusl)) {
291
- return true;
292
- }
293
- }
294
- return false;
295
- };
296
- var isMuslFromChildProcess = () => {
297
- try {
298
- return __require("child_process").execSync("ldd --version", { encoding: "utf8" }).includes("musl");
299
- } catch (e) {
300
- return false;
301
- }
302
- };
303
- function requireNative() {
304
- if (process.env.NAPI_RS_NATIVE_LIBRARY_PATH) {
305
- try {
306
- nativeBinding = __require(process.env.NAPI_RS_NATIVE_LIBRARY_PATH);
307
- } catch (err) {
308
- loadErrors.push(err);
309
- }
310
- } else if (process.platform === "android") {
311
- if (process.arch === "arm64") {
312
- try {
313
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.android-arm64.node");})();
314
- } catch (e) {
315
- loadErrors.push(e);
316
- }
317
- try {
318
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-android-arm64");})();
319
- } catch (e) {
320
- loadErrors.push(e);
321
- }
322
- } else if (process.arch === "arm") {
323
- try {
324
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.android-arm-eabi.node");})();
325
- } catch (e) {
326
- loadErrors.push(e);
327
- }
328
- try {
329
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-android-arm-eabi");})();
330
- } catch (e) {
331
- loadErrors.push(e);
332
- }
333
- } else {
334
- loadErrors.push(new Error(`Unsupported architecture on Android ${process.arch}`));
335
- }
336
- } else if (process.platform === "win32") {
337
- if (process.arch === "x64") {
338
- try {
339
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.win32-x64-msvc.node");})();
340
- } catch (e) {
341
- loadErrors.push(e);
342
- }
343
- try {
344
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-win32-x64-msvc");})();
345
- } catch (e) {
346
- loadErrors.push(e);
347
- }
348
- } else if (process.arch === "ia32") {
349
- try {
350
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.win32-ia32-msvc.node");})();
351
- } catch (e) {
352
- loadErrors.push(e);
353
- }
354
- try {
355
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-win32-ia32-msvc");})();
356
- } catch (e) {
357
- loadErrors.push(e);
358
- }
359
- } else if (process.arch === "arm64") {
360
- try {
361
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.win32-arm64-msvc.node");})();
362
- } catch (e) {
363
- loadErrors.push(e);
364
- }
365
- try {
366
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-win32-arm64-msvc");})();
367
- } catch (e) {
368
- loadErrors.push(e);
369
- }
370
- } else {
371
- loadErrors.push(new Error(`Unsupported architecture on Windows: ${process.arch}`));
372
- }
373
- } else if (process.platform === "darwin") {
374
- try {
375
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.darwin-universal.node");})();
376
- } catch (e) {
377
- loadErrors.push(e);
378
- }
379
- try {
380
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-darwin-universal");})();
381
- } catch (e) {
382
- loadErrors.push(e);
383
- }
384
- if (process.arch === "x64") {
385
- try {
386
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.darwin-x64.node");})();
387
- } catch (e) {
388
- loadErrors.push(e);
389
- }
390
- try {
391
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-darwin-x64");})();
392
- } catch (e) {
393
- loadErrors.push(e);
394
- }
395
- } else if (process.arch === "arm64") {
396
- try {
397
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.darwin-arm64.node");})();
398
- } catch (e) {
399
- loadErrors.push(e);
400
- }
401
- try {
402
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-darwin-arm64");})();
403
- } catch (e) {
404
- loadErrors.push(e);
405
- }
406
- } else {
407
- loadErrors.push(new Error(`Unsupported architecture on macOS: ${process.arch}`));
408
- }
409
- } else if (process.platform === "freebsd") {
410
- if (process.arch === "x64") {
411
- try {
412
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.freebsd-x64.node");})();
413
- } catch (e) {
414
- loadErrors.push(e);
415
- }
416
- try {
417
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-freebsd-x64");})();
418
- } catch (e) {
419
- loadErrors.push(e);
420
- }
421
- } else if (process.arch === "arm64") {
422
- try {
423
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.freebsd-arm64.node");})();
424
- } catch (e) {
425
- loadErrors.push(e);
426
- }
427
- try {
428
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-freebsd-arm64");})();
429
- } catch (e) {
430
- loadErrors.push(e);
431
- }
432
- } else {
433
- loadErrors.push(new Error(`Unsupported architecture on FreeBSD: ${process.arch}`));
434
- }
435
- } else if (process.platform === "linux") {
436
- if (process.arch === "x64") {
437
- if (isMusl()) {
438
- try {
439
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.linux-x64-musl.node");})();
440
- } catch (e) {
441
- loadErrors.push(e);
442
- }
443
- try {
444
- return require_ast_grep_napi_linux_x64_musl();
445
- } catch (e) {
446
- loadErrors.push(e);
447
- }
448
- } else {
449
- try {
450
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.linux-x64-gnu.node");})();
451
- } catch (e) {
452
- loadErrors.push(e);
453
- }
454
- try {
455
- return require_ast_grep_napi_linux_x64_gnu();
456
- } catch (e) {
457
- loadErrors.push(e);
458
- }
459
- }
460
- } else if (process.arch === "arm64") {
461
- if (isMusl()) {
462
- try {
463
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.linux-arm64-musl.node");})();
464
- } catch (e) {
465
- loadErrors.push(e);
466
- }
467
- try {
468
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-linux-arm64-musl");})();
469
- } catch (e) {
470
- loadErrors.push(e);
471
- }
472
- } else {
473
- try {
474
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.linux-arm64-gnu.node");})();
475
- } catch (e) {
476
- loadErrors.push(e);
477
- }
478
- try {
479
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-linux-arm64-gnu");})();
480
- } catch (e) {
481
- loadErrors.push(e);
482
- }
483
- }
484
- } else if (process.arch === "arm") {
485
- if (isMusl()) {
486
- try {
487
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.linux-arm-musleabihf.node");})();
488
- } catch (e) {
489
- loadErrors.push(e);
490
- }
491
- try {
492
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-linux-arm-musleabihf");})();
493
- } catch (e) {
494
- loadErrors.push(e);
495
- }
496
- } else {
497
- try {
498
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.linux-arm-gnueabihf.node");})();
499
- } catch (e) {
500
- loadErrors.push(e);
501
- }
502
- try {
503
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-linux-arm-gnueabihf");})();
504
- } catch (e) {
505
- loadErrors.push(e);
506
- }
507
- }
508
- } else if (process.arch === "riscv64") {
509
- if (isMusl()) {
510
- try {
511
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.linux-riscv64-musl.node");})();
512
- } catch (e) {
513
- loadErrors.push(e);
514
- }
515
- try {
516
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-linux-riscv64-musl");})();
517
- } catch (e) {
518
- loadErrors.push(e);
519
- }
520
- } else {
521
- try {
522
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.linux-riscv64-gnu.node");})();
523
- } catch (e) {
524
- loadErrors.push(e);
525
- }
526
- try {
527
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-linux-riscv64-gnu");})();
528
- } catch (e) {
529
- loadErrors.push(e);
530
- }
531
- }
532
- } else if (process.arch === "ppc64") {
533
- try {
534
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.linux-ppc64-gnu.node");})();
535
- } catch (e) {
536
- loadErrors.push(e);
537
- }
538
- try {
539
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-linux-ppc64-gnu");})();
540
- } catch (e) {
541
- loadErrors.push(e);
542
- }
543
- } else if (process.arch === "s390x") {
544
- try {
545
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.linux-s390x-gnu.node");})();
546
- } catch (e) {
547
- loadErrors.push(e);
548
- }
549
- try {
550
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-linux-s390x-gnu");})();
551
- } catch (e) {
552
- loadErrors.push(e);
553
- }
554
- } else {
555
- loadErrors.push(new Error(`Unsupported architecture on Linux: ${process.arch}`));
556
- }
557
- } else if (process.platform === "openharmony") {
558
- if (process.arch === "arm64") {
559
- try {
560
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.linux-arm64-ohos.node");})();
561
- } catch (e) {
562
- loadErrors.push(e);
563
- }
564
- try {
565
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-linux-arm64-ohos");})();
566
- } catch (e) {
567
- loadErrors.push(e);
568
- }
569
- } else if (process.arch === "x64") {
570
- try {
571
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.linux-x64-ohos.node");})();
572
- } catch (e) {
573
- loadErrors.push(e);
574
- }
575
- try {
576
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-linux-x64-ohos");})();
577
- } catch (e) {
578
- loadErrors.push(e);
579
- }
580
- } else if (process.arch === "arm") {
581
- try {
582
- return (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.linux-arm-ohos.node");})();
583
- } catch (e) {
584
- loadErrors.push(e);
585
- }
586
- try {
587
- return (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-linux-arm-ohos");})();
588
- } catch (e) {
589
- loadErrors.push(e);
590
- }
591
- } else {
592
- loadErrors.push(new Error(`Unsupported architecture on OpenHarmony: ${process.arch}`));
593
- }
594
- } else {
595
- loadErrors.push(new Error(`Unsupported OS: ${process.platform}, architecture: ${process.arch}`));
596
- }
597
- }
598
- nativeBinding = requireNative();
599
- if (!nativeBinding || process.env.NAPI_RS_FORCE_WASI) {
600
- try {
601
- nativeBinding = (()=>{throw new Error("Cannot require module "+"./ast-grep-napi.wasi.cjs");})();
602
- } catch (err) {
603
- if (process.env.NAPI_RS_FORCE_WASI) {
604
- loadErrors.push(err);
605
- }
606
- }
607
- if (!nativeBinding) {
608
- try {
609
- nativeBinding = (()=>{throw new Error("Cannot require module "+"@ast-grep/napi-wasm32-wasi");})();
610
- } catch (err) {
611
- if (process.env.NAPI_RS_FORCE_WASI) {
612
- loadErrors.push(err);
613
- }
614
- }
615
- }
616
- }
617
- if (!nativeBinding) {
618
- if (loadErrors.length > 0) {
619
- throw new Error(`Cannot find native binding. ` + `npm has a bug related to optional dependencies (https://github.com/npm/cli/issues/4828). ` + "Please try `npm i` again after removing both package-lock.json and node_modules directory.", { cause: loadErrors });
620
- }
621
- throw new Error(`Failed to load native binding`);
622
- }
623
- module.exports = nativeBinding;
624
- module.exports.SgNode = nativeBinding.SgNode;
625
- module.exports.SgRoot = nativeBinding.SgRoot;
626
- module.exports.findInFiles = nativeBinding.findInFiles;
627
- module.exports.kind = nativeBinding.kind;
628
- module.exports.Lang = nativeBinding.Lang;
629
- module.exports.parse = nativeBinding.parse;
630
- module.exports.parseAsync = nativeBinding.parseAsync;
631
- module.exports.parseFiles = nativeBinding.parseFiles;
632
- module.exports.pattern = nativeBinding.pattern;
633
- module.exports.registerDynamicLanguage = nativeBinding.registerDynamicLanguage;
634
- module.exports.css = nativeBinding.css;
635
- module.exports.html = nativeBinding.html;
636
- module.exports.js = nativeBinding.js;
637
- module.exports.jsx = nativeBinding.jsx;
638
- module.exports.ts = nativeBinding.ts;
639
- module.exports.tsx = nativeBinding.tsx;
640
- });
641
-
642
238
  // src/utils/context-compression.ts
643
239
  var exports_context_compression = {};
644
240
  __export(exports_context_compression, {
@@ -18208,1164 +17804,1238 @@ var hiveVectorStatusTool = tool({
18208
17804
  }
18209
17805
  });
18210
17806
 
18211
- // src/tools/ast-grep-native.ts
17807
+ // src/tools/hive-doctor.ts
17808
+ import { execSync as execSync2 } from "child_process";
18212
17809
  import * as fs5 from "fs";
18213
- var astGrepModule = null;
18214
- var astGrepInitPromise = null;
18215
- async function initAstGrep() {
18216
- if (astGrepModule !== null) {
18217
- return;
18218
- }
18219
- if (astGrepInitPromise !== null) {
18220
- await astGrepInitPromise;
18221
- return;
18222
- }
18223
- astGrepInitPromise = (async () => {
18224
- try {
18225
- astGrepModule = await Promise.resolve().then(() => __toESM(require_napi(), 1));
18226
- console.log("[ast-grep] Native NAPI initialized successfully");
18227
- } catch (error45) {
18228
- console.warn("[ast-grep] Failed to load @ast-grep/napi:", error45 instanceof Error ? error45.message : error45);
18229
- astGrepModule = null;
17810
+ import * as path6 from "path";
17811
+ async function checkPackage(packageName) {
17812
+ try {
17813
+ const packageJsonPath = __require.resolve(`${packageName}/package.json`, {
17814
+ paths: [
17815
+ process.cwd(),
17816
+ path6.join(process.cwd(), "node_modules"),
17817
+ path6.join(process.cwd(), "packages/opencode-hive/node_modules")
17818
+ ]
17819
+ });
17820
+ if (fs5.existsSync(packageJsonPath)) {
17821
+ const pkg = JSON.parse(fs5.readFileSync(packageJsonPath, "utf-8"));
17822
+ return { installed: true, version: pkg.version };
18230
17823
  }
18231
- })();
18232
- await astGrepInitPromise;
17824
+ } catch {}
17825
+ return { installed: false };
18233
17826
  }
18234
- var astGrepDumpSyntaxTreeTool = tool({
18235
- description: `Dump code's syntax structure or dump a query's pattern structure.
18236
-
18237
- This is useful to discover correct syntax kind and syntax tree structure. Call it when debugging a rule.
18238
-
18239
- **Parameters:**
18240
- - code: The code you need
18241
- - language: Programming language (typescript, javascript, python, rust, go, java, etc.)
18242
- - format: Output format - 'cst' (concrete syntax tree) or 'pattern' (to inspect rule patterns)
18243
-
18244
- **Use when:**
18245
- - Debugging AST patterns
18246
- - Finding correct syntax kind names
18247
- - Understanding code structure`,
18248
- args: {
18249
- code: tool.schema.string().describe("The code to analyze"),
18250
- language: tool.schema.string().describe("Programming language (typescript, javascript, python, rust, go, java, etc.)"),
18251
- format: tool.schema.enum(["cst", "pattern"]).default("cst").describe("Output format")
18252
- },
18253
- async execute({ code, language, format }) {
18254
- await initAstGrep();
18255
- if (!astGrepModule) {
18256
- return JSON.stringify({
18257
- success: false,
18258
- error: "@ast-grep/napi not available",
18259
- hint: "Install @ast-grep/napi or use MCP-based ast_grep"
18260
- }, null, 2);
18261
- }
17827
+ function checkCliTool(tool3) {
17828
+ try {
17829
+ const result = execSync2(tool3.command, { stdio: "pipe", timeout: 5000 });
17830
+ const output = result.toString().trim();
17831
+ const versionMatch = output.match(/(\d+\.\d+\.\d+)/);
17832
+ return {
17833
+ ...tool3,
17834
+ installed: true,
17835
+ version: versionMatch ? versionMatch[1] : output.slice(0, 50)
17836
+ };
17837
+ } catch {
17838
+ const npxCmd = tool3.command.split(" ")[0];
18262
17839
  try {
18263
- const langMap = {
18264
- typescript: "TypeScript",
18265
- javascript: "JavaScript",
18266
- tsx: "Tsx",
18267
- jsx: "Jsx",
18268
- python: "Python",
18269
- rust: "Rust",
18270
- go: "Go",
18271
- java: "Java",
18272
- c: "C",
18273
- cpp: "Cpp",
18274
- csharp: "CSharp"
17840
+ execSync2(`npx -y ${npxCmd} --version`, { stdio: "pipe", timeout: 1e4 });
17841
+ return {
17842
+ ...tool3,
17843
+ installed: true,
17844
+ version: "via npx"
18275
17845
  };
18276
- const lang = langMap[language.toLowerCase()] || language;
18277
- const Lang = astGrepModule.Lang;
18278
- if (!Lang || !Lang[lang]) {
18279
- return JSON.stringify({
18280
- success: false,
18281
- error: `Unsupported language: ${language}`,
18282
- availableLanguages: Object.keys(langMap)
18283
- }, null, 2);
18284
- }
18285
- if (format === "pattern") {
18286
- return JSON.stringify({
18287
- success: true,
18288
- format: "pattern",
18289
- language,
18290
- example: {
18291
- match: "AwaitExpression",
18292
- kind: "Use kind to match AST node types",
18293
- pattern: "Use pattern for code templates"
18294
- }
18295
- }, null, 2);
18296
- }
18297
- const parse5 = astGrepModule.parse;
18298
- const ast = parse5(Lang[lang], code);
18299
- const root = ast.root();
18300
- const dump = (node, depth = 0) => {
18301
- if (!node)
18302
- return null;
18303
- return {
18304
- kind: node.kind(),
18305
- text: node.text(),
18306
- children: node.children().map((child) => dump(child, depth + 1))
18307
- };
17846
+ } catch {
17847
+ return {
17848
+ ...tool3,
17849
+ installed: false
18308
17850
  };
18309
- return JSON.stringify({
18310
- success: true,
18311
- format: "cst",
18312
- language,
18313
- tree: dump(root)
18314
- }, null, 2);
18315
- } catch (error45) {
18316
- return JSON.stringify({
18317
- success: false,
18318
- error: error45 instanceof Error ? error45.message : String(error45)
18319
- }, null, 2);
18320
17851
  }
18321
17852
  }
18322
- });
18323
- var astGrepTestMatchCodeRuleTool = tool({
18324
- description: `Test a code against an ast-grep YAML rule.
17853
+ }
17854
+ function checkOptimizations() {
17855
+ const checks3 = [];
17856
+ const configPaths = [
17857
+ path6.join(process.env.HOME || "", ".config/opencode/agent_hive.json"),
17858
+ path6.join(process.env.HOME || "", ".config/opencode/agent_hive.jsonc")
17859
+ ];
17860
+ let config2 = null;
17861
+ for (const configPath of configPaths) {
17862
+ if (fs5.existsSync(configPath)) {
17863
+ try {
17864
+ const content = fs5.readFileSync(configPath, "utf-8");
17865
+ config2 = JSON.parse(content.replace(/\\/g, ""));
17866
+ break;
17867
+ } catch {}
17868
+ }
17869
+ }
17870
+ const snipConfig = config2?.snip;
17871
+ checks3.push({
17872
+ name: "snip",
17873
+ enabled: snipConfig?.enabled === true,
17874
+ recommendation: !snipConfig?.enabled ? "Enable snip in config for 60-90% token reduction on shell output" : undefined
17875
+ });
17876
+ const vectorConfig = config2?.vectorMemory;
17877
+ checks3.push({
17878
+ name: "vectorMemory",
17879
+ enabled: vectorConfig?.enabled === true,
17880
+ recommendation: !vectorConfig?.enabled ? "Enable vector memory for semantic search across memories" : undefined
17881
+ });
17882
+ const boosterConfig = config2?.agentBooster;
17883
+ checks3.push({
17884
+ name: "agentBooster",
17885
+ enabled: boosterConfig?.enabled !== false,
17886
+ recommendation: boosterConfig?.enabled === false ? "Enable agent booster for 52x faster code editing" : undefined
17887
+ });
17888
+ const sandboxConfig = config2?.sandbox;
17889
+ checks3.push({
17890
+ name: "sandbox",
17891
+ enabled: sandboxConfig !== "none",
17892
+ recommendation: sandboxConfig === "none" ? "Enable Docker sandbox for isolated test environments" : undefined
17893
+ });
17894
+ const disabledMcps = config2?.disableMcps || [];
17895
+ const hasPareSearch = !disabledMcps.includes("pare_search");
17896
+ checks3.push({
17897
+ name: "pareSearch",
17898
+ enabled: hasPareSearch,
17899
+ recommendation: !hasPareSearch ? "Enable pare_search for structured ripgrep output (65-95% token reduction)" : undefined
17900
+ });
17901
+ const hasVeil = !disabledMcps.includes("veil");
17902
+ checks3.push({
17903
+ name: "veil",
17904
+ enabled: hasVeil,
17905
+ recommendation: !hasVeil ? "Enable veil for code discovery and intelligent retrieval" : undefined
17906
+ });
17907
+ return checks3;
17908
+ }
17909
+ function generateRecommendations(dependencies, cliTools, optimizations) {
17910
+ const recommendations = [];
17911
+ const missingRequired = dependencies.filter((d) => d.required && !d.installed);
17912
+ if (missingRequired.length > 0) {
17913
+ recommendations.push(`Missing required packages: ${missingRequired.map((d) => d.name).join(", ")}`);
17914
+ }
17915
+ const missingCliTools = cliTools.filter((t) => !t.installed);
17916
+ if (missingCliTools.length > 0) {
17917
+ recommendations.push(`⚠️ Missing CLI tools: ${missingCliTools.map((t) => t.name).join(", ")}`, `Install with: ${missingCliTools.map((t) => `npx -y ${t.command}`).join(" | ")}`);
17918
+ }
17919
+ const disabledOptimizations = optimizations.filter((o) => !o.enabled && o.recommendation);
17920
+ for (const opt of disabledOptimizations) {
17921
+ if (opt.recommendation) {
17922
+ recommendations.push(opt.recommendation);
17923
+ }
17924
+ }
17925
+ if (recommendations.length === 0) {
17926
+ recommendations.push("✅ System is healthy! All checks passed.");
17927
+ }
17928
+ return recommendations;
17929
+ }
17930
+ function generateQuickFixes(dependencies, cliTools, optimizations) {
17931
+ const fixes = [];
17932
+ const missingPackages = dependencies.filter((d) => !d.installed && !d.required);
17933
+ for (const pkg of missingPackages) {
17934
+ fixes.push({
17935
+ command: `npm install ${pkg.package}`,
17936
+ description: `Install ${pkg.name}`
17937
+ });
17938
+ }
17939
+ const missingTools = cliTools.filter((t) => !t.installed);
17940
+ for (const tool3 of missingTools) {
17941
+ fixes.push({
17942
+ command: `npx -y ${tool3.command}`,
17943
+ description: `Install ${tool3.name} via npx`
17944
+ });
17945
+ }
17946
+ if (optimizations.find((o) => o.name === "snip" && !o.enabled)) {
17947
+ fixes.push({
17948
+ command: 'Add to ~/.config/opencode/agent_hive.json: { "snip": { "enabled": true } }',
17949
+ description: "Enable snip for token reduction"
17950
+ });
17951
+ }
17952
+ if (optimizations.find((o) => o.name === "vectorMemory" && !o.enabled)) {
17953
+ fixes.push({
17954
+ command: 'Add to ~/.config/opencode/agent_hive.json: { "vectorMemory": { "enabled": true } }',
17955
+ description: "Enable vector memory for semantic search"
17956
+ });
17957
+ }
17958
+ return fixes;
17959
+ }
17960
+ function calculateStatus(dependencies, cliTools, optimizations) {
17961
+ const missingRequired = dependencies.filter((d) => d.required && !d.installed);
17962
+ if (missingRequired.length > 0) {
17963
+ return "issues";
17964
+ }
17965
+ const missingTools = cliTools.filter((t) => !t.installed);
17966
+ const disabledCount = optimizations.filter((o) => !o.enabled).length;
17967
+ if (missingTools.length > 0 || disabledCount > 2) {
17968
+ return "warning";
17969
+ }
17970
+ return "healthy";
17971
+ }
17972
+ var hiveDoctorTool = tool({
17973
+ description: `Hive Doctor - System health check and optimization advisor.
18325
17974
 
18326
- This is useful to test a rule before using it in a project.
17975
+ **What it checks:**
17976
+ 1. Dependencies - Optional packages installed and working
17977
+ 2. CLI Tools - dora, auto-cr, etc. available via npx
17978
+ 3. Optimizations - Features enabled in config
17979
+ 4. Recommendations - Suggestions for improvements
18327
17980
 
18328
- **Parameters:**
18329
- - code: The code to test against the rule
18330
- - yaml: The ast-grep YAML rule to test
17981
+ **Use when:**
17982
+ - Setting up Hive for the first time
17983
+ - Troubleshooting issues
17984
+ - Optimizing performance
17985
+ - Checking if new features are available
18331
17986
 
18332
- **Returns:**
18333
- - Whether the rule matched
18334
- - Matched nodes with locations`,
18335
- args: {
18336
- code: tool.schema.string().describe("The code to test against the rule"),
18337
- yaml: tool.schema.string().describe("The ast-grep YAML rule to search")
18338
- },
18339
- async execute({ code, yaml }) {
18340
- await initAstGrep();
18341
- if (!astGrepModule) {
18342
- return JSON.stringify({
18343
- success: false,
18344
- error: "@ast-grep/napi not available",
18345
- hint: "Install @ast-grep/napi or use MCP-based ast_grep"
18346
- }, null, 2);
17987
+ **Example output:**
17988
+ - healthy: All checks pass
17989
+ - warning: Some optimizations disabled or CLI tools missing
17990
+ - issues: Missing required packages`,
17991
+ args: {},
17992
+ async execute() {
17993
+ const dependencyChecks = [
17994
+ { name: "agent-booster", package: "@sparkleideas/agent-booster", required: false },
17995
+ { name: "vector-memory", package: "@sparkleideas/memory", required: false },
17996
+ { name: "pare-search", package: "@paretools/search", required: false },
17997
+ { name: "context7", package: "@upstash/context7-mcp", required: false },
17998
+ { name: "Exa search", package: "exa-mcp-server", required: false }
17999
+ ];
18000
+ for (const dep of dependencyChecks) {
18001
+ const result2 = await checkPackage(dep.package);
18002
+ dep.installed = result2.installed;
18003
+ dep.version = result2.version;
18347
18004
  }
18348
- try {
18349
- const parse5 = astGrepModule.parse;
18350
- const Lang = astGrepModule.Lang;
18351
- const ast = parse5(Lang.TypeScript, code);
18352
- const root = ast.root();
18353
- return JSON.stringify({
18354
- success: true,
18355
- matched: false,
18356
- note: "YAML rule testing requires @ast-grep/cli. Use ast_grep_find_code for pattern-based search.",
18357
- example: {
18358
- pattern: "console.log($ARG)",
18359
- description: "Match console.log with any argument"
18005
+ const cliToolChecks = [
18006
+ {
18007
+ name: "dora",
18008
+ command: "@butttons/dora",
18009
+ description: "SCIP-based code navigation",
18010
+ installCommand: "npx -y @butttons/dora"
18011
+ },
18012
+ {
18013
+ name: "auto-cr",
18014
+ command: "auto-cr-cmd",
18015
+ description: "SWC-based automated code review",
18016
+ installCommand: "npx -y auto-cr-cmd"
18017
+ },
18018
+ {
18019
+ name: "veil",
18020
+ command: "@ushiradineth/veil",
18021
+ description: "Code discovery and retrieval",
18022
+ installCommand: "npx -y @ushiradineth/veil"
18023
+ },
18024
+ {
18025
+ name: "scip-typescript",
18026
+ command: "@sourcegraph/scip-typescript",
18027
+ description: "TypeScript SCIP indexer (for dora)",
18028
+ installCommand: "npx -y @sourcegraph/scip-typescript"
18029
+ }
18030
+ ];
18031
+ for (const tool3 of cliToolChecks) {
18032
+ checkCliTool(tool3);
18033
+ }
18034
+ const optimizationChecks = checkOptimizations();
18035
+ const recommendations = generateRecommendations(dependencyChecks, cliToolChecks, optimizationChecks);
18036
+ const quickFixes = generateQuickFixes(dependencyChecks, cliToolChecks, optimizationChecks);
18037
+ const status = calculateStatus(dependencyChecks, cliToolChecks, optimizationChecks);
18038
+ const result = {
18039
+ status,
18040
+ timestamp: new Date().toISOString(),
18041
+ checks: {
18042
+ dependencies: {
18043
+ total: dependencyChecks.length,
18044
+ installed: dependencyChecks.filter((d) => d.installed).length,
18045
+ packages: dependencyChecks
18046
+ },
18047
+ cliTools: {
18048
+ total: cliToolChecks.length,
18049
+ available: cliToolChecks.filter((t) => t.installed).length,
18050
+ tools: cliToolChecks,
18051
+ missing: cliToolChecks.filter((t) => !t.installed).map((t) => t.name)
18052
+ },
18053
+ optimizations: {
18054
+ total: optimizationChecks.length,
18055
+ enabled: optimizationChecks.filter((o) => o.enabled).length,
18056
+ features: optimizationChecks
18360
18057
  }
18361
- }, null, 2);
18362
- } catch (error45) {
18363
- return JSON.stringify({
18364
- success: false,
18365
- error: error45 instanceof Error ? error45.message : String(error45)
18366
- }, null, 2);
18058
+ },
18059
+ recommendations,
18060
+ quickFixes
18061
+ };
18062
+ return JSON.stringify(result, null, 2);
18063
+ }
18064
+ });
18065
+ var hiveDoctorQuickTool = tool({
18066
+ description: `Quick health check - shows status summary only.
18067
+
18068
+ **Returns:**
18069
+ - healthy: All systems go
18070
+ - warning: Some CLI tools missing or optimizations disabled
18071
+ - issues: Action required`,
18072
+ args: {},
18073
+ async execute() {
18074
+ const keyPackages = [
18075
+ "@sparkleideas/agent-booster",
18076
+ "@paretools/search"
18077
+ ];
18078
+ const results = {};
18079
+ let healthy = true;
18080
+ for (const pkg of keyPackages) {
18081
+ const result = await checkPackage(pkg);
18082
+ results[pkg] = result.installed;
18083
+ if (!result.installed) {
18084
+ healthy = false;
18085
+ }
18367
18086
  }
18087
+ return JSON.stringify({
18088
+ status: healthy ? "healthy" : "warning",
18089
+ packages: results,
18090
+ runFullCheck: "Use hive_doctor for detailed analysis with CLI tool checks"
18091
+ }, null, 2);
18368
18092
  }
18369
18093
  });
18370
- var astGrepFindCodeTool = tool({
18371
- description: `Find code in a project folder that matches the given ast-grep pattern.
18372
18094
 
18373
- Pattern is good for simple and single-AST node result. For more complex usage, use ast_grep_scan_code.
18095
+ // src/tools/dora.ts
18096
+ import { execSync as execSync3 } from "child_process";
18097
+ function checkDoraStatus() {
18098
+ try {
18099
+ const output = execSync3("dora --version", { encoding: "utf-8" });
18100
+ const version2 = output.trim();
18101
+ const indexExists = __require("fs").existsSync(".dora/dora.db");
18102
+ return { installed: true, version: version2, indexed: indexExists };
18103
+ } catch {
18104
+ return { installed: false, indexed: false };
18105
+ }
18106
+ }
18107
+ function runDoraCommand(args2) {
18108
+ try {
18109
+ const output = execSync3(`dora ${args2.join(" ")}`, {
18110
+ encoding: "utf-8",
18111
+ maxBuffer: 10 * 1024 * 1024
18112
+ });
18113
+ return { success: true, output };
18114
+ } catch (error45) {
18115
+ return { success: false, error: error45.message || "Command failed" };
18116
+ }
18117
+ }
18118
+ var doraStatusTool = tool({
18119
+ description: `Check dora installation status and index state.
18374
18120
 
18375
- **Parameters:**
18376
- - project_folder: The absolute path to the project folder
18377
- - pattern: The ast-grep pattern to search for (e.g., 'console.log($ARG)', '$VAR = $VALUE')
18378
- - language: Optional - programming language filter
18121
+ **Returns:**
18122
+ - installed: Whether dora CLI is available
18123
+ - version: Dora version
18124
+ - indexed: Whether codebase has been indexed
18379
18125
 
18380
- **Pattern Examples:**
18381
- - 'console.log($ARG)' - Match console.log with any argument
18382
- - '$VAR = $VALUE' - Match any assignment
18383
- - 'function $NAME($PARAMS) { $BODY }' - Match function declarations`,
18384
- args: {
18385
- project_folder: tool.schema.string().describe("The absolute path to the project folder"),
18386
- pattern: tool.schema.string().describe("The ast-grep pattern to search for"),
18387
- language: tool.schema.string().optional().describe("Programming language filter (typescript, javascript, python, etc.)")
18388
- },
18389
- async execute({ project_folder, pattern, language }) {
18390
- await initAstGrep();
18391
- if (!astGrepModule) {
18126
+ **Requirements:**
18127
+ - Install dora: \`bun install -g @butttons/dora\`
18128
+ - Install SCIP indexer: \`npm install -g @sourcegraph/scip-typescript\`
18129
+ - Initialize: \`dora init && dora index\`
18130
+
18131
+ **Note:** Indexing is required once per codebase. After that, dora works instantly.`,
18132
+ args: {},
18133
+ async execute() {
18134
+ const status = checkDoraStatus();
18135
+ if (!status.installed) {
18392
18136
  return JSON.stringify({
18393
- success: false,
18394
- error: "@ast-grep/napi not available",
18395
- hint: "Install @ast-grep/napi or use MCP-based ast_grep"
18396
- }, null, 2);
18397
- }
18398
- try {
18399
- if (!fs5.existsSync(project_folder)) {
18400
- return JSON.stringify({
18401
- success: false,
18402
- error: `Path not found: ${project_folder}`
18403
- }, null, 2);
18404
- }
18405
- const langMap = {
18406
- typescript: "TypeScript",
18407
- javascript: "JavaScript",
18408
- tsx: "Tsx",
18409
- jsx: "Jsx",
18410
- python: "Python",
18411
- rust: "Rust",
18412
- go: "Go",
18413
- java: "Java"
18414
- };
18415
- const lang = language ? langMap[language.toLowerCase()] || language : "TypeScript";
18416
- const Lang = astGrepModule.Lang;
18417
- if (!Lang[lang]) {
18418
- return JSON.stringify({
18419
- success: false,
18420
- error: `Unsupported language: ${language}`
18421
- }, null, 2);
18422
- }
18423
- const findInFiles = astGrepModule.findInFiles;
18424
- const results = [];
18425
- await findInFiles(Lang[lang], {
18426
- paths: [project_folder],
18427
- matcher: { rule: { pattern } }
18428
- }, (err, node) => {
18429
- if (err) {
18430
- console.warn("[ast-grep] Search error:", err);
18431
- return;
18432
- }
18433
- if (node) {
18434
- const text = node.text();
18435
- const range = node.range();
18436
- results.push({
18437
- file: node.filename() || "unknown",
18438
- line: range ? range.start.index : 0,
18439
- column: range ? range.start.column : 0,
18440
- matched: text.slice(0, 100)
18441
- });
18137
+ status: "not_installed",
18138
+ message: "Dora CLI not found",
18139
+ installation: {
18140
+ step1: "bun install -g @butttons/dora",
18141
+ step2: "npm install -g @sourcegraph/scip-typescript",
18142
+ step3: "dora init && dora index"
18442
18143
  }
18443
- });
18444
- return JSON.stringify({
18445
- success: true,
18446
- count: results.length,
18447
- matches: results.slice(0, 50)
18448
18144
  }, null, 2);
18449
- } catch (error45) {
18145
+ }
18146
+ if (!status.indexed) {
18450
18147
  return JSON.stringify({
18451
- success: false,
18452
- error: error45 instanceof Error ? error45.message : String(error45)
18148
+ status: "not_indexed",
18149
+ version: status.version,
18150
+ message: "Codebase not indexed",
18151
+ nextStep: "Run: dora init && dora index"
18453
18152
  }, null, 2);
18454
18153
  }
18154
+ return JSON.stringify({
18155
+ status: "ready",
18156
+ version: status.version,
18157
+ indexed: true,
18158
+ message: "Dora is ready"
18159
+ }, null, 2);
18455
18160
  }
18456
18161
  });
18457
- var astGrepScanCodeTool = tool({
18458
- description: `Analyze TypeScript/JS code for common bugs, performance issues and best practices.
18162
+ var doraSymbolTool = tool({
18163
+ description: `Find symbol definitions using dora (SCIP-based).
18459
18164
 
18460
- Uses AST-based analysis for precise detection without false positives. Essential for maintaining code quality and preventing runtime errors.
18165
+ **Parameters:**
18166
+ - name: Symbol name to search for
18167
+ - kind: Filter by symbol kind (function, class, method, etc.)
18461
18168
 
18462
- **Detects:**
18463
- - Type safety violations
18464
- - Loose object types
18465
- - Incorrect async patterns
18466
- - Import style issues
18467
- - Common bugs
18169
+ **Example:**
18170
+ \`\`\`
18171
+ dora_symbol({ name: "getUserById" })
18172
+ \`\`\`
18468
18173
 
18469
- **Parameters:**
18470
- - project_folder: Optional - path to scan (defaults to current directory)`,
18174
+ **Note:** Requires dora to be installed and indexed.`,
18471
18175
  args: {
18472
- project_folder: tool.schema.string().optional().describe("Path to scan (defaults to current directory)")
18176
+ name: tool.schema.string().describe("Symbol name to search for"),
18177
+ kind: tool.schema.string().optional().describe("Filter by symbol kind (function, class, method, etc.)")
18473
18178
  },
18474
- async execute({ project_folder }) {
18475
- await initAstGrep();
18476
- if (!astGrepModule) {
18179
+ async execute({ name, kind }) {
18180
+ const status = checkDoraStatus();
18181
+ if (!status.installed || !status.indexed) {
18477
18182
  return JSON.stringify({
18478
18183
  success: false,
18479
- error: "@ast-grep/napi not available",
18480
- hint: "Install @ast-grep/napi or use MCP-based ast_grep"
18184
+ error: "Dora not ready. Run dora_status first.",
18185
+ hint: "Install and index: dora init && dora index"
18481
18186
  }, null, 2);
18482
18187
  }
18483
- try {
18484
- const scanPath = project_folder || process.cwd();
18485
- if (!fs5.existsSync(scanPath)) {
18486
- return JSON.stringify({
18487
- success: false,
18488
- error: `Path not found: ${scanPath}`
18489
- }, null, 2);
18490
- }
18491
- const bugPatterns = [
18492
- { pattern: "await Promise.all($ARR)", severity: "warning", message: "Check if Promise.all is used correctly with async operations" },
18493
- { pattern: "JSON.parse($STR)", severity: "info", message: "Consider adding try-catch for JSON.parse" },
18494
- { pattern: "$VAR == $VAL", severity: "warning", message: "Use === instead of == for strict equality" }
18495
- ];
18496
- const issues = [];
18497
- const Lang = astGrepModule.Lang;
18498
- const findInFiles = astGrepModule.findInFiles;
18499
- for (const bug of bugPatterns) {
18500
- await findInFiles(Lang.TypeScript, {
18501
- paths: [scanPath],
18502
- matcher: { rule: { pattern: bug.pattern } }
18503
- }, (err, node) => {
18504
- if (err || !node)
18505
- return;
18506
- issues.push({
18507
- file: node.filename() || "unknown",
18508
- line: node.range()?.start.index || 0,
18509
- severity: bug.severity,
18510
- message: bug.message,
18511
- pattern: bug.pattern
18512
- });
18513
- });
18514
- }
18515
- return JSON.stringify({
18516
- success: true,
18517
- scanned: scanPath,
18518
- issuesFound: issues.length,
18519
- issues: issues.slice(0, 20),
18520
- summary: issues.length === 0 ? "No common issues detected" : `Found ${issues.length} potential issues`
18521
- }, null, 2);
18522
- } catch (error45) {
18188
+ const args2 = ["symbol", name];
18189
+ if (kind) {
18190
+ args2.push("--kind", kind);
18191
+ }
18192
+ const result = runDoraCommand(args2);
18193
+ if (!result.success) {
18523
18194
  return JSON.stringify({
18524
18195
  success: false,
18525
- error: error45 instanceof Error ? error45.message : String(error45)
18196
+ error: result.error,
18197
+ hint: "Symbol may not exist or not indexed"
18526
18198
  }, null, 2);
18527
18199
  }
18200
+ return JSON.stringify({
18201
+ success: true,
18202
+ symbol: name,
18203
+ output: result.output
18204
+ }, null, 2);
18528
18205
  }
18529
18206
  });
18530
- var astGrepRewriteCodeTool = tool({
18531
- description: `Transform and refactor code using AST-based find-and-replace patterns.
18207
+ var doraFileTool = tool({
18208
+ description: `Get file dependencies and information using dora.
18532
18209
 
18533
- Use metavariables ($VAR, $$$VARS) in both pattern and replacement.
18210
+ **Parameters:**
18211
+ - path: File path to analyze
18534
18212
 
18535
- **Example:** Find 'console.log($ARG)' and replace with 'logger.info($ARG)'
18213
+ **Example:**
18214
+ \`\`\`
18215
+ dora_file({ path: "src/index.ts" })
18216
+ \`\`\`
18536
18217
 
18537
- **Parameters:**
18538
- - project_folder: Path to the project folder
18539
- - pattern: AST pattern to find
18540
- - replacement: Replacement pattern
18541
- - language: Programming language (defaults to TypeScript)`,
18218
+ **Returns:** File metadata, exports, and dependencies.`,
18542
18219
  args: {
18543
- project_folder: tool.schema.string().describe("Path to the project folder"),
18544
- pattern: tool.schema.string().describe("AST pattern to find"),
18545
- replacement: tool.schema.string().describe("Replacement pattern"),
18546
- language: tool.schema.string().optional().default("TypeScript").describe("Programming language")
18220
+ path: tool.schema.string().describe("File path to analyze")
18547
18221
  },
18548
- async execute({ project_folder, pattern, replacement, language }) {
18549
- await initAstGrep();
18550
- if (!astGrepModule) {
18222
+ async execute({ path: path7 }) {
18223
+ const status = checkDoraStatus();
18224
+ if (!status.installed || !status.indexed) {
18551
18225
  return JSON.stringify({
18552
18226
  success: false,
18553
- error: "@ast-grep/napi not available",
18554
- hint: "Install @ast-grep/napi or use MCP-based ast_grep"
18227
+ error: "Dora not ready. Run dora_status first."
18555
18228
  }, null, 2);
18556
18229
  }
18557
- try {
18558
- if (!fs5.existsSync(project_folder)) {
18559
- return JSON.stringify({
18560
- success: false,
18561
- error: `Path not found: ${project_folder}`
18562
- }, null, 2);
18563
- }
18564
- const Lang = astGrepModule.Lang;
18565
- if (!Lang[language]) {
18566
- return JSON.stringify({
18567
- success: false,
18568
- error: `Unsupported language: ${language}`
18569
- }, null, 2);
18570
- }
18571
- return JSON.stringify({
18572
- success: true,
18573
- operation: "info",
18574
- message: "Full rewrite requires @ast-grep/cli with config file",
18575
- suggestion: "Use ast_grep_find_code to find matches, then hive_code_edit for individual replacements",
18576
- parameters: {
18577
- projectFolder: project_folder,
18578
- pattern,
18579
- replacement,
18580
- language
18581
- }
18582
- }, null, 2);
18583
- } catch (error45) {
18230
+ const result = runDoraCommand(["file", path7]);
18231
+ if (!result.success) {
18584
18232
  return JSON.stringify({
18585
18233
  success: false,
18586
- error: error45 instanceof Error ? error45.message : String(error45)
18234
+ error: result.error,
18235
+ hint: "File may not exist or not indexed"
18587
18236
  }, null, 2);
18588
18237
  }
18238
+ return JSON.stringify({
18239
+ success: true,
18240
+ path: path7,
18241
+ output: result.output
18242
+ }, null, 2);
18589
18243
  }
18590
18244
  });
18591
- var astGrepAnalyzeImportsTool = tool({
18592
- description: `Analyze import statements and dependencies in your codebase.
18593
-
18594
- Choose "usage" to see which imports are actually used (great for refactoring), or "discovery" to explore all imports and identifiers in the code (great for understanding structure).
18245
+ var doraReferencesTool = tool({
18246
+ description: `Find all references to a symbol using dora.
18595
18247
 
18596
18248
  **Parameters:**
18597
- - mode: "usage" (default) shows where imports are used, "discovery" shows all imports
18598
- - path: Specific directory or file to analyze (defaults to current directory)`,
18249
+ - name: Symbol name to find references for
18250
+
18251
+ **Example:**
18252
+ \`\`\`
18253
+ dora_references({ name: "UserService" })
18254
+ \`\`\`
18255
+
18256
+ **Note:** Returns all usages across the codebase.`,
18599
18257
  args: {
18600
- mode: tool.schema.enum(["usage", "discovery"]).default("usage").describe("Analysis mode"),
18601
- path: tool.schema.string().optional().describe("Directory or file to analyze")
18258
+ name: tool.schema.string().describe("Symbol name to find references for")
18602
18259
  },
18603
- async execute({ mode, path: path6 }) {
18604
- await initAstGrep();
18605
- if (!astGrepModule) {
18260
+ async execute({ name }) {
18261
+ const status = checkDoraStatus();
18262
+ if (!status.installed || !status.indexed) {
18606
18263
  return JSON.stringify({
18607
18264
  success: false,
18608
- error: "@ast-grep/napi not available"
18265
+ error: "Dora not ready. Run dora_status first."
18609
18266
  }, null, 2);
18610
18267
  }
18611
- try {
18612
- const analyzePath = path6 || process.cwd();
18613
- if (!fs5.existsSync(analyzePath)) {
18614
- return JSON.stringify({
18615
- success: false,
18616
- error: `Path not found: ${analyzePath}`
18617
- }, null, 2);
18618
- }
18619
- const Lang = astGrepModule.Lang;
18620
- const findInFiles = astGrepModule.findInFiles;
18621
- const imports = {};
18622
- await findInFiles(Lang.TypeScript, {
18623
- paths: [analyzePath],
18624
- matcher: { rule: { kind: "import_statement" } }
18625
- }, (err, node) => {
18626
- if (err || !node)
18627
- return;
18628
- const text = node.text();
18629
- const match = text.match(/from ['"]([^'"]+)['"]/);
18630
- if (match) {
18631
- const module = match[1];
18632
- const file2 = node.filename() || "unknown";
18633
- if (!imports[module]) {
18634
- imports[module] = [];
18635
- }
18636
- if (!imports[module].includes(file2)) {
18637
- imports[module].push(file2);
18638
- }
18639
- }
18640
- });
18641
- if (mode === "usage") {
18642
- return JSON.stringify({
18643
- success: true,
18644
- mode: "usage",
18645
- imports: Object.entries(imports).map(([module, files]) => ({
18646
- module,
18647
- importCount: 1,
18648
- filesCount: files.length
18649
- })),
18650
- note: "Full usage analysis requires @ast-grep/cli"
18651
- }, null, 2);
18652
- }
18653
- return JSON.stringify({
18654
- success: true,
18655
- mode: "discovery",
18656
- totalModules: Object.keys(imports).length,
18657
- imports: Object.entries(imports).map(([module, files]) => ({
18658
- module,
18659
- importCount: files.length,
18660
- files: files.slice(0, 5)
18661
- }))
18662
- }, null, 2);
18663
- } catch (error45) {
18268
+ const result = runDoraCommand(["references", name]);
18269
+ if (!result.success) {
18664
18270
  return JSON.stringify({
18665
18271
  success: false,
18666
- error: error45 instanceof Error ? error45.message : String(error45)
18272
+ error: result.error
18667
18273
  }, null, 2);
18668
18274
  }
18275
+ return JSON.stringify({
18276
+ success: true,
18277
+ symbol: name,
18278
+ output: result.output
18279
+ }, null, 2);
18669
18280
  }
18670
18281
  });
18282
+ var doraCyclesTool = tool({
18283
+ description: `Detect circular dependencies in the codebase using dora.
18671
18284
 
18672
- // src/tools/hive-doctor.ts
18673
- import * as fs6 from "fs";
18674
- import * as path6 from "path";
18675
- async function checkPackage(packageName) {
18676
- try {
18677
- const packageJsonPath = __require.resolve(`${packageName}/package.json`, {
18678
- paths: [
18679
- process.cwd(),
18680
- path6.join(process.cwd(), "node_modules"),
18681
- path6.join(process.cwd(), "packages/opencode-hive/node_modules")
18682
- ]
18683
- });
18684
- if (fs6.existsSync(packageJsonPath)) {
18685
- const pkg = JSON.parse(fs6.readFileSync(packageJsonPath, "utf-8"));
18686
- return { installed: true, version: pkg.version };
18687
- }
18688
- } catch {}
18689
- return { installed: false };
18690
- }
18691
- function checkOptimizations() {
18692
- const checks3 = [];
18693
- const configPaths = [
18694
- path6.join(process.env.HOME || "", ".config/opencode/agent_hive.json"),
18695
- path6.join(process.env.HOME || "", ".config/opencode/agent_hive.jsonc")
18696
- ];
18697
- let config2 = null;
18698
- for (const configPath of configPaths) {
18699
- if (fs6.existsSync(configPath)) {
18700
- try {
18701
- const content = fs6.readFileSync(configPath, "utf-8");
18702
- config2 = JSON.parse(content.replace(/\\/g, ""));
18703
- break;
18704
- } catch {}
18705
- }
18706
- }
18707
- const snipConfig = config2?.snip;
18708
- checks3.push({
18709
- name: "snip",
18710
- enabled: snipConfig?.enabled === true,
18711
- recommendation: !snipConfig?.enabled ? "Enable snip in config for 60-90% token reduction on shell output" : undefined
18712
- });
18713
- const vectorConfig = config2?.vectorMemory;
18714
- checks3.push({
18715
- name: "vectorMemory",
18716
- enabled: vectorConfig?.enabled === true,
18717
- recommendation: !vectorConfig?.enabled ? "Enable vector memory for semantic search across memories" : undefined
18718
- });
18719
- const boosterConfig = config2?.agentBooster;
18720
- checks3.push({
18721
- name: "agentBooster",
18722
- enabled: boosterConfig?.enabled !== false,
18723
- recommendation: boosterConfig?.enabled === false ? "Enable agent booster for 52x faster code editing" : undefined
18724
- });
18725
- const sandboxConfig = config2?.sandbox;
18726
- checks3.push({
18727
- name: "sandbox",
18728
- enabled: sandboxConfig !== "none",
18729
- recommendation: sandboxConfig === "none" ? "Enable Docker sandbox for isolated test environments" : undefined
18730
- });
18731
- const disabledMcps = config2?.disableMcps || [];
18732
- const hasAstGrep = !disabledMcps.includes("ast_grep");
18733
- checks3.push({
18734
- name: "nativeAstGrep",
18735
- enabled: hasAstGrep,
18736
- recommendation: !hasAstGrep ? "Enable native ast-grep for fast AST analysis" : undefined
18737
- });
18738
- const hasPareSearch = !disabledMcps.includes("pare_search");
18739
- checks3.push({
18740
- name: "pareSearch",
18741
- enabled: hasPareSearch,
18742
- recommendation: !hasPareSearch ? "Enable pare_search for structured ripgrep output (65-95% token reduction)" : undefined
18743
- });
18744
- return checks3;
18745
- }
18746
- function generateRecommendations(dependencies, optimizations) {
18747
- const recommendations = [];
18748
- const missingRequired = dependencies.filter((d) => d.required && !d.installed);
18749
- if (missingRequired.length > 0) {
18750
- recommendations.push(`Missing required packages: ${missingRequired.map((d) => d.name).join(", ")}`);
18751
- }
18752
- const disabledOptimizations = optimizations.filter((o) => !o.enabled && o.recommendation);
18753
- for (const opt of disabledOptimizations) {
18754
- if (opt.recommendation) {
18755
- recommendations.push(opt.recommendation);
18756
- }
18757
- }
18758
- if (recommendations.length === 0) {
18759
- recommendations.push("System is optimized! No immediate actions needed.");
18760
- }
18761
- return recommendations;
18762
- }
18763
- function generateQuickFixes(dependencies, optimizations) {
18764
- const fixes = [];
18765
- const missingPackages = dependencies.filter((d) => !d.installed && !d.required);
18766
- for (const pkg of missingPackages) {
18767
- fixes.push({
18768
- command: `npm install ${pkg.package}`,
18769
- description: `Install ${pkg.name}`
18770
- });
18771
- }
18772
- if (optimizations.find((o) => o.name === "snip" && !o.enabled)) {
18773
- fixes.push({
18774
- command: 'Add to ~/.config/opencode/agent_hive.json: { "snip": { "enabled": true } }',
18775
- description: "Enable snip for token reduction"
18776
- });
18777
- }
18778
- if (optimizations.find((o) => o.name === "vectorMemory" && !o.enabled)) {
18779
- fixes.push({
18780
- command: 'Add to ~/.config/opencode/agent_hive.json: { "vectorMemory": { "enabled": true } }',
18781
- description: "Enable vector memory for semantic search"
18782
- });
18783
- }
18784
- return fixes;
18785
- }
18786
- function calculateStatus(dependencies, optimizations) {
18787
- const missingRequired = dependencies.filter((d) => d.required && !d.installed);
18788
- if (missingRequired.length > 0) {
18789
- return "issues";
18790
- }
18791
- const disabledCount = optimizations.filter((o) => !o.enabled).length;
18792
- if (disabledCount > 2) {
18793
- return "warning";
18794
- }
18795
- return "healthy";
18796
- }
18797
- var hiveDoctorTool = tool({
18798
- description: `Hive Doctor - System health check and optimization advisor.
18799
-
18800
- **What it checks:**
18801
- 1. Dependencies - Optional packages installed and working
18802
- 2. Optimizations - Features enabled in config
18803
- 3. Recommendations - Suggestions for improvements
18804
-
18805
- **Use when:**
18806
- - Setting up Hive for the first time
18807
- - Troubleshooting issues
18808
- - Optimizing performance
18809
- - Checking if new features are available
18285
+ **Example:**
18286
+ \`\`\`
18287
+ dora_cycles()
18288
+ \`\`\`
18810
18289
 
18811
- **Example output:**
18812
- - healthy: All checks pass
18813
- - warning: Some optimizations disabled
18814
- - issues: Missing required packages`,
18290
+ **Returns:** List of circular dependency paths if found.`,
18815
18291
  args: {},
18816
18292
  async execute() {
18817
- const dependencyChecks = [
18818
- { name: "agent-booster", package: "@sparkleideas/agent-booster", required: false },
18819
- { name: "vector-memory", package: "@sparkleideas/memory", required: false },
18820
- { name: "ast-grep NAPI", package: "@ast-grep/napi", required: false },
18821
- { name: "pare-search", package: "@paretools/search", required: false },
18822
- { name: "context7", package: "@upstash/context7-mcp", required: false },
18823
- { name: "Exa search", package: "exa-mcp-server", required: false }
18824
- ];
18825
- for (const dep of dependencyChecks) {
18826
- const result2 = await checkPackage(dep.package);
18827
- dep.installed = result2.installed;
18828
- dep.version = result2.version;
18293
+ const status = checkDoraStatus();
18294
+ if (!status.installed || !status.indexed) {
18295
+ return JSON.stringify({
18296
+ success: false,
18297
+ error: "Dora not ready. Run dora_status first."
18298
+ }, null, 2);
18829
18299
  }
18830
- const optimizationChecks = checkOptimizations();
18831
- const recommendations = generateRecommendations(dependencyChecks, optimizationChecks);
18832
- const quickFixes = generateQuickFixes(dependencyChecks, optimizationChecks);
18833
- const status = calculateStatus(dependencyChecks, optimizationChecks);
18834
- const result = {
18835
- status,
18836
- timestamp: new Date().toISOString(),
18837
- checks: {
18838
- dependencies: {
18839
- total: dependencyChecks.length,
18840
- installed: dependencyChecks.filter((d) => d.installed).length,
18841
- packages: dependencyChecks
18842
- },
18843
- optimizations: {
18844
- total: optimizationChecks.length,
18845
- enabled: optimizationChecks.filter((o) => o.enabled).length,
18846
- features: optimizationChecks
18847
- }
18848
- },
18849
- recommendations,
18850
- quickFixes
18851
- };
18852
- return JSON.stringify(result, null, 2);
18300
+ const result = runDoraCommand(["cycles"]);
18301
+ if (!result.success) {
18302
+ return JSON.stringify({
18303
+ success: false,
18304
+ error: result.error
18305
+ }, null, 2);
18306
+ }
18307
+ return JSON.stringify({
18308
+ success: true,
18309
+ cycles: result.output
18310
+ }, null, 2);
18853
18311
  }
18854
18312
  });
18855
- var hiveDoctorQuickTool = tool({
18856
- description: `Quick health check - shows status summary only.
18313
+ var doraUnusedTool = tool({
18314
+ description: `Find unused/dead code in the codebase using dora.
18857
18315
 
18858
- **Returns:**
18859
- - healthy: All systems go
18860
- - warning: Some optimizations disabled
18861
- - issues: Action required`,
18316
+ **Example:**
18317
+ \`\`\`
18318
+ dora_unused()
18319
+ \`\`\`
18320
+
18321
+ **Returns:** List of symbols with zero references.`,
18862
18322
  args: {},
18863
18323
  async execute() {
18864
- const keyPackages = [
18865
- "@ast-grep/napi",
18866
- "@sparkleideas/agent-booster",
18867
- "@paretools/search"
18868
- ];
18869
- const results = {};
18870
- let healthy = true;
18871
- for (const pkg of keyPackages) {
18872
- const result = await checkPackage(pkg);
18873
- results[pkg] = result.installed;
18874
- if (!result.installed) {
18875
- healthy = false;
18876
- }
18324
+ const status = checkDoraStatus();
18325
+ if (!status.installed || !status.indexed) {
18326
+ return JSON.stringify({
18327
+ success: false,
18328
+ error: "Dora not ready. Run dora_status first."
18329
+ }, null, 2);
18330
+ }
18331
+ const result = runDoraCommand(["unused"]);
18332
+ if (!result.success) {
18333
+ return JSON.stringify({
18334
+ success: false,
18335
+ error: result.error
18336
+ }, null, 2);
18877
18337
  }
18878
18338
  return JSON.stringify({
18879
- status: healthy ? "healthy" : "warning",
18880
- packages: results,
18881
- runFullCheck: "Use hive_doctor for detailed analysis"
18339
+ success: true,
18340
+ unused: result.output
18882
18341
  }, null, 2);
18883
18342
  }
18884
18343
  });
18885
18344
 
18886
- // src/tools/dora.ts
18887
- import { execSync as execSync2 } from "child_process";
18888
- function checkDoraStatus() {
18345
+ // src/tools/auto-cr.ts
18346
+ import { execSync as execSync4 } from "child_process";
18347
+ import * as fs6 from "fs";
18348
+ function checkAutoCrStatus() {
18889
18349
  try {
18890
- const output = execSync2("dora --version", { encoding: "utf-8" });
18350
+ const output = execSync4("auto-cr-cmd --version", { encoding: "utf-8" });
18891
18351
  const version2 = output.trim();
18892
- const indexExists = __require("fs").existsSync(".dora/dora.db");
18893
- return { installed: true, version: version2, indexed: indexExists };
18352
+ return { installed: true, version: version2 };
18894
18353
  } catch {
18895
- return { installed: false, indexed: false };
18354
+ return { installed: false };
18896
18355
  }
18897
18356
  }
18898
- function runDoraCommand(args2) {
18357
+ function runAutoCr(args2) {
18899
18358
  try {
18900
- const output = execSync2(`dora ${args2.join(" ")}`, {
18359
+ const allArgs = [...args2, "--output", "json"];
18360
+ const output = execSync4(`auto-cr-cmd ${allArgs.join(" ")}`, {
18901
18361
  encoding: "utf-8",
18902
- maxBuffer: 10 * 1024 * 1024
18362
+ maxBuffer: 50 * 1024 * 1024
18903
18363
  });
18904
- return { success: true, output };
18364
+ try {
18365
+ const json2 = JSON.parse(output);
18366
+ return { success: true, output, json: json2 };
18367
+ } catch {
18368
+ return { success: true, output };
18369
+ }
18905
18370
  } catch (error45) {
18906
- return { success: false, error: error45.message || "Command failed" };
18371
+ const stderr = error45.stderr || "";
18372
+ const stdout = error45.stdout || "";
18373
+ const combined = stdout + stderr;
18374
+ try {
18375
+ const json2 = JSON.parse(combined);
18376
+ return { success: true, output: combined, json: json2 };
18377
+ } catch {
18378
+ return { success: false, error: combined || error45.message };
18379
+ }
18907
18380
  }
18908
18381
  }
18909
- var doraStatusTool = tool({
18910
- description: `Check dora installation status and index state.
18382
+ var autoCrStatusTool = tool({
18383
+ description: `Check auto-cr-cmd installation status.
18911
18384
 
18912
18385
  **Returns:**
18913
- - installed: Whether dora CLI is available
18914
- - version: Dora version
18915
- - indexed: Whether codebase has been indexed
18916
-
18917
- **Requirements:**
18918
- - Install dora: \`bun install -g @butttons/dora\`
18919
- - Install SCIP indexer: \`npm install -g @sourcegraph/scip-typescript\`
18920
- - Initialize: \`dora init && dora index\`
18386
+ - installed: Whether auto-cr-cmd is available
18387
+ - version: Auto-CR version
18388
+ - ready: Whether it's ready to scan
18921
18389
 
18922
- **Note:** Indexing is required once per codebase. After that, dora works instantly.`,
18390
+ **Installation:**
18391
+ \`\`\`bash
18392
+ npm install auto-cr-cmd
18393
+ # or
18394
+ pnpm add auto-cr-cmd
18395
+ \`\`\``,
18923
18396
  args: {},
18924
18397
  async execute() {
18925
- const status = checkDoraStatus();
18398
+ const status = checkAutoCrStatus();
18926
18399
  if (!status.installed) {
18927
18400
  return JSON.stringify({
18928
18401
  status: "not_installed",
18929
- message: "Dora CLI not found",
18930
- installation: {
18931
- step1: "bun install -g @butttons/dora",
18932
- step2: "npm install -g @sourcegraph/scip-typescript",
18933
- step3: "dora init && dora index"
18934
- }
18935
- }, null, 2);
18936
- }
18937
- if (!status.indexed) {
18938
- return JSON.stringify({
18939
- status: "not_indexed",
18940
- version: status.version,
18941
- message: "Codebase not indexed",
18942
- nextStep: "Run: dora init && dora index"
18402
+ message: "auto-cr-cmd not found",
18403
+ installation: "npm install auto-cr-cmd"
18943
18404
  }, null, 2);
18944
18405
  }
18945
18406
  return JSON.stringify({
18946
18407
  status: "ready",
18947
18408
  version: status.version,
18948
- indexed: true,
18949
- message: "Dora is ready"
18409
+ message: "Auto-CR is ready to scan",
18410
+ rules: [
18411
+ "no-deep-relative-imports",
18412
+ "no-circular-dependencies",
18413
+ "no-swallowed-errors",
18414
+ "no-catastrophic-regex",
18415
+ "no-deep-clone-in-loop",
18416
+ "no-n2-array-lookup"
18417
+ ]
18950
18418
  }, null, 2);
18951
18419
  }
18952
18420
  });
18953
- var doraSymbolTool = tool({
18954
- description: `Find symbol definitions using dora (SCIP-based).
18421
+ var autoCrScanTool = tool({
18422
+ description: `Scan directory for code issues using auto-cr (SWC-based static analysis).
18955
18423
 
18956
18424
  **Parameters:**
18957
- - name: Symbol name to search for
18958
- - kind: Filter by symbol kind (function, class, method, etc.)
18425
+ - path: Directory path to scan (defaults to ./src)
18426
+ - language: Output language (en/zh, defaults to en)
18427
+
18428
+ **Rules detected:**
18429
+ - no-deep-relative-imports: Import paths exceeding depth limit
18430
+ - no-circular-dependencies: Circular module dependencies
18431
+ - no-swallowed-errors: try-catch blocks that swallow errors
18432
+ - no-catastrophic-regex: Potentially catastrophic regex patterns
18433
+ - no-deep-clone-in-loop: Performance anti-patterns
18434
+ - no-n2-array-lookup: O(n²) array operations
18959
18435
 
18960
18436
  **Example:**
18961
18437
  \`\`\`
18962
- dora_symbol({ name: "getUserById" })
18963
- \`\`\`
18964
-
18965
- **Note:** Requires dora to be installed and indexed.`,
18438
+ auto_cr_scan({ path: "./src" })
18439
+ \`\`\``,
18966
18440
  args: {
18967
- name: tool.schema.string().describe("Symbol name to search for"),
18968
- kind: tool.schema.string().optional().describe("Filter by symbol kind (function, class, method, etc.)")
18441
+ path: tool.schema.string().optional().default("./src").describe("Directory path to scan"),
18442
+ language: tool.schema.string().optional().default("en").describe("Output language (en or zh)")
18969
18443
  },
18970
- async execute({ name, kind }) {
18971
- const status = checkDoraStatus();
18972
- if (!status.installed || !status.indexed) {
18444
+ async execute({ path: path7, language }) {
18445
+ const status = checkAutoCrStatus();
18446
+ if (!status.installed) {
18973
18447
  return JSON.stringify({
18974
18448
  success: false,
18975
- error: "Dora not ready. Run dora_status first.",
18976
- hint: "Install and index: dora init && dora index"
18449
+ error: "auto-cr-cmd not installed",
18450
+ hint: "npm install auto-cr-cmd"
18977
18451
  }, null, 2);
18978
18452
  }
18979
- const args2 = ["symbol", name];
18980
- if (kind) {
18981
- args2.push("--kind", kind);
18453
+ if (!fs6.existsSync(path7)) {
18454
+ return JSON.stringify({
18455
+ success: false,
18456
+ error: `Path not found: ${path7}`
18457
+ }, null, 2);
18982
18458
  }
18983
- const result = runDoraCommand(args2);
18984
- if (!result.success) {
18459
+ const result = runAutoCr(["--language", language, path7]);
18460
+ if (!result.success && !result.json) {
18985
18461
  return JSON.stringify({
18986
18462
  success: false,
18987
- error: result.error,
18988
- hint: "Symbol may not exist or not indexed"
18463
+ error: result.error || "Scan failed"
18464
+ }, null, 2);
18465
+ }
18466
+ if (result.json) {
18467
+ const { summary, files, notifications } = result.json;
18468
+ return JSON.stringify({
18469
+ success: true,
18470
+ scanned: path7,
18471
+ summary: {
18472
+ filesScanned: summary?.scannedFiles || 0,
18473
+ filesWithErrors: summary?.filesWithErrors || 0,
18474
+ filesWithWarnings: summary?.filesWithWarnings || 0,
18475
+ totalViolations: summary?.violationTotals?.total || 0
18476
+ },
18477
+ files: files?.map((f) => ({
18478
+ path: f.filePath,
18479
+ violations: f.totalViolations,
18480
+ errors: f.severityCounts?.error || 0,
18481
+ warnings: f.severityCounts?.warning || 0,
18482
+ details: f.violations?.map((v) => ({
18483
+ rule: v.ruleName,
18484
+ severity: v.severity,
18485
+ message: v.message,
18486
+ line: v.line
18487
+ }))
18488
+ })),
18489
+ notifications: notifications || []
18989
18490
  }, null, 2);
18990
18491
  }
18991
18492
  return JSON.stringify({
18992
18493
  success: true,
18993
- symbol: name,
18994
- output: result.output
18494
+ scanned: path7,
18495
+ rawOutput: result.output
18995
18496
  }, null, 2);
18996
18497
  }
18997
18498
  });
18998
- var doraFileTool = tool({
18999
- description: `Get file dependencies and information using dora.
18499
+ var autoCrDiffTool = tool({
18500
+ description: `Scan git diff output for code issues using auto-cr.
19000
18501
 
19001
- **Parameters:**
19002
- - path: File path to analyze
18502
+ **Use case:** Run in CI to check only changed files.
19003
18503
 
19004
18504
  **Example:**
19005
- \`\`\`
19006
- dora_file({ path: "src/index.ts" })
18505
+ \`\`\`bash
18506
+ git diff --name-only -z | xargs -0 auto-cr-cmd --stdin --output json
19007
18507
  \`\`\`
19008
18508
 
19009
- **Returns:** File metadata, exports, and dependencies.`,
18509
+ **Note:** This tool requires git diff output piped via stdin.`,
19010
18510
  args: {
19011
- path: tool.schema.string().describe("File path to analyze")
18511
+ language: tool.schema.string().optional().default("en").describe("Output language (en or zh)")
19012
18512
  },
19013
- async execute({ path: path7 }) {
19014
- const status = checkDoraStatus();
19015
- if (!status.installed || !status.indexed) {
19016
- return JSON.stringify({
19017
- success: false,
19018
- error: "Dora not ready. Run dora_status first."
19019
- }, null, 2);
19020
- }
19021
- const result = runDoraCommand(["file", path7]);
19022
- if (!result.success) {
18513
+ async execute({ language }) {
18514
+ const status = checkAutoCrStatus();
18515
+ if (!status.installed) {
19023
18516
  return JSON.stringify({
19024
18517
  success: false,
19025
- error: result.error,
19026
- hint: "File may not exist or not indexed"
18518
+ error: "auto-cr-cmd not installed",
18519
+ hint: "npm install auto-cr-cmd"
19027
18520
  }, null, 2);
19028
18521
  }
19029
18522
  return JSON.stringify({
19030
18523
  success: true,
19031
- path: path7,
19032
- output: result.output
18524
+ message: "Use git diff with auto-cr directly",
18525
+ example: "git diff --name-only -z | xargs -0 npx auto-cr-cmd --stdin --output json"
19033
18526
  }, null, 2);
19034
18527
  }
19035
18528
  });
19036
- var doraReferencesTool = tool({
19037
- description: `Find all references to a symbol using dora.
18529
+ var autoCrRulesTool = tool({
18530
+ description: `List available auto-cr rules and their descriptions.
19038
18531
 
19039
- **Parameters:**
19040
- - name: Symbol name to find references for
18532
+ **Returns:** All built-in rules with descriptions.`,
18533
+ args: {},
18534
+ async execute() {
18535
+ const rules = [
18536
+ {
18537
+ name: "no-deep-relative-imports",
18538
+ severity: "error",
18539
+ description: "Import paths should not exceed maximum depth",
18540
+ example: "Use path aliases (@shared/utils) instead of ../../../../shared/utils"
18541
+ },
18542
+ {
18543
+ name: "no-circular-dependencies",
18544
+ severity: "warning",
18545
+ description: "Detect circular module dependencies",
18546
+ example: "A imports B, B imports A creates a cycle"
18547
+ },
18548
+ {
18549
+ name: "no-swallowed-errors",
18550
+ severity: "warning",
18551
+ description: "try-catch blocks that swallow errors without rethrowing",
18552
+ example: "catch (e) {} without logging or rethrowing"
18553
+ },
18554
+ {
18555
+ name: "no-catastrophic-regex",
18556
+ severity: "error",
18557
+ description: "Potentially catastrophic regex backtracking",
18558
+ example: "Regex with nested quantifiers that can hang"
18559
+ },
18560
+ {
18561
+ name: "no-deep-clone-in-loop",
18562
+ severity: "warning",
18563
+ description: "Performance: deep clone operations inside loops",
18564
+ example: "for loop calling JSON.parse(JSON.stringify())"
18565
+ },
18566
+ {
18567
+ name: "no-n2-array-lookup",
18568
+ severity: "warning",
18569
+ description: "O(n²) array operations",
18570
+ example: "Nested for loops accessing array elements"
18571
+ }
18572
+ ];
18573
+ return JSON.stringify({
18574
+ success: true,
18575
+ rules,
18576
+ totalRules: rules.length
18577
+ }, null, 2);
18578
+ }
18579
+ });
19041
18580
 
19042
- **Example:**
19043
- \`\`\`
19044
- dora_references({ name: "UserService" })
19045
- \`\`\`
18581
+ // src/tools/ast-grep-native.ts
18582
+ import * as fs7 from "fs";
18583
+ var astGrepModule = null;
18584
+ var astGrepInitPromise = null;
18585
+ async function initAstGrep() {
18586
+ if (astGrepModule !== null) {
18587
+ return;
18588
+ }
18589
+ if (astGrepInitPromise !== null) {
18590
+ await astGrepInitPromise;
18591
+ return;
18592
+ }
18593
+ astGrepInitPromise = (async () => {
18594
+ try {
18595
+ astGrepModule = await import("@ast-grep/napi");
18596
+ console.log("[ast-grep] Native NAPI initialized successfully");
18597
+ } catch (error45) {
18598
+ console.warn("[ast-grep] Failed to load @ast-grep/napi:", error45 instanceof Error ? error45.message : error45);
18599
+ astGrepModule = null;
18600
+ }
18601
+ })();
18602
+ await astGrepInitPromise;
18603
+ }
18604
+ var astGrepDumpSyntaxTreeTool = tool({
18605
+ description: `Dump code's syntax structure or dump a query's pattern structure.
19046
18606
 
19047
- **Note:** Returns all usages across the codebase.`,
18607
+ This is useful to discover correct syntax kind and syntax tree structure. Call it when debugging a rule.
18608
+
18609
+ **Parameters:**
18610
+ - code: The code you need
18611
+ - language: Programming language (typescript, javascript, python, rust, go, java, etc.)
18612
+ - format: Output format - 'cst' (concrete syntax tree) or 'pattern' (to inspect rule patterns)
18613
+
18614
+ **Use when:**
18615
+ - Debugging AST patterns
18616
+ - Finding correct syntax kind names
18617
+ - Understanding code structure`,
19048
18618
  args: {
19049
- name: tool.schema.string().describe("Symbol name to find references for")
18619
+ code: tool.schema.string().describe("The code to analyze"),
18620
+ language: tool.schema.string().describe("Programming language (typescript, javascript, python, rust, go, java, etc.)"),
18621
+ format: tool.schema.enum(["cst", "pattern"]).default("cst").describe("Output format")
19050
18622
  },
19051
- async execute({ name }) {
19052
- const status = checkDoraStatus();
19053
- if (!status.installed || !status.indexed) {
18623
+ async execute({ code, language, format }) {
18624
+ await initAstGrep();
18625
+ if (!astGrepModule) {
19054
18626
  return JSON.stringify({
19055
18627
  success: false,
19056
- error: "Dora not ready. Run dora_status first."
18628
+ error: "@ast-grep/napi not available",
18629
+ hint: "Install @ast-grep/napi or use MCP-based ast_grep"
19057
18630
  }, null, 2);
19058
18631
  }
19059
- const result = runDoraCommand(["references", name]);
19060
- if (!result.success) {
18632
+ try {
18633
+ const langMap = {
18634
+ typescript: "TypeScript",
18635
+ javascript: "JavaScript",
18636
+ tsx: "Tsx",
18637
+ jsx: "Jsx",
18638
+ python: "Python",
18639
+ rust: "Rust",
18640
+ go: "Go",
18641
+ java: "Java",
18642
+ c: "C",
18643
+ cpp: "Cpp",
18644
+ csharp: "CSharp"
18645
+ };
18646
+ const lang = langMap[language.toLowerCase()] || language;
18647
+ const Lang = astGrepModule.Lang;
18648
+ if (!Lang || !Lang[lang]) {
18649
+ return JSON.stringify({
18650
+ success: false,
18651
+ error: `Unsupported language: ${language}`,
18652
+ availableLanguages: Object.keys(langMap)
18653
+ }, null, 2);
18654
+ }
18655
+ if (format === "pattern") {
18656
+ return JSON.stringify({
18657
+ success: true,
18658
+ format: "pattern",
18659
+ language,
18660
+ example: {
18661
+ match: "AwaitExpression",
18662
+ kind: "Use kind to match AST node types",
18663
+ pattern: "Use pattern for code templates"
18664
+ }
18665
+ }, null, 2);
18666
+ }
18667
+ const parse5 = astGrepModule.parse;
18668
+ const ast = parse5(Lang[lang], code);
18669
+ const root = ast.root();
18670
+ const dump = (node, depth = 0) => {
18671
+ if (!node)
18672
+ return null;
18673
+ return {
18674
+ kind: node.kind(),
18675
+ text: node.text(),
18676
+ children: node.children().map((child) => dump(child, depth + 1))
18677
+ };
18678
+ };
18679
+ return JSON.stringify({
18680
+ success: true,
18681
+ format: "cst",
18682
+ language,
18683
+ tree: dump(root)
18684
+ }, null, 2);
18685
+ } catch (error45) {
19061
18686
  return JSON.stringify({
19062
18687
  success: false,
19063
- error: result.error
18688
+ error: error45 instanceof Error ? error45.message : String(error45)
19064
18689
  }, null, 2);
19065
18690
  }
19066
- return JSON.stringify({
19067
- success: true,
19068
- symbol: name,
19069
- output: result.output
19070
- }, null, 2);
19071
18691
  }
19072
18692
  });
19073
- var doraCyclesTool = tool({
19074
- description: `Detect circular dependencies in the codebase using dora.
18693
+ var astGrepTestMatchCodeRuleTool = tool({
18694
+ description: `Test a code against an ast-grep YAML rule.
19075
18695
 
19076
- **Example:**
19077
- \`\`\`
19078
- dora_cycles()
19079
- \`\`\`
18696
+ This is useful to test a rule before using it in a project.
19080
18697
 
19081
- **Returns:** List of circular dependency paths if found.`,
19082
- args: {},
19083
- async execute() {
19084
- const status = checkDoraStatus();
19085
- if (!status.installed || !status.indexed) {
18698
+ **Parameters:**
18699
+ - code: The code to test against the rule
18700
+ - yaml: The ast-grep YAML rule to test
18701
+
18702
+ **Returns:**
18703
+ - Whether the rule matched
18704
+ - Matched nodes with locations`,
18705
+ args: {
18706
+ code: tool.schema.string().describe("The code to test against the rule"),
18707
+ yaml: tool.schema.string().describe("The ast-grep YAML rule to search")
18708
+ },
18709
+ async execute({ code, yaml }) {
18710
+ await initAstGrep();
18711
+ if (!astGrepModule) {
19086
18712
  return JSON.stringify({
19087
18713
  success: false,
19088
- error: "Dora not ready. Run dora_status first."
18714
+ error: "@ast-grep/napi not available",
18715
+ hint: "Install @ast-grep/napi or use MCP-based ast_grep"
18716
+ }, null, 2);
18717
+ }
18718
+ try {
18719
+ const parse5 = astGrepModule.parse;
18720
+ const Lang = astGrepModule.Lang;
18721
+ const ast = parse5(Lang.TypeScript, code);
18722
+ const root = ast.root();
18723
+ return JSON.stringify({
18724
+ success: true,
18725
+ matched: false,
18726
+ note: "YAML rule testing requires @ast-grep/cli. Use ast_grep_find_code for pattern-based search.",
18727
+ example: {
18728
+ pattern: "console.log($ARG)",
18729
+ description: "Match console.log with any argument"
18730
+ }
19089
18731
  }, null, 2);
19090
- }
19091
- const result = runDoraCommand(["cycles"]);
19092
- if (!result.success) {
18732
+ } catch (error45) {
19093
18733
  return JSON.stringify({
19094
18734
  success: false,
19095
- error: result.error
18735
+ error: error45 instanceof Error ? error45.message : String(error45)
19096
18736
  }, null, 2);
19097
18737
  }
19098
- return JSON.stringify({
19099
- success: true,
19100
- cycles: result.output
19101
- }, null, 2);
19102
18738
  }
19103
18739
  });
19104
- var doraUnusedTool = tool({
19105
- description: `Find unused/dead code in the codebase using dora.
18740
+ var astGrepFindCodeTool = tool({
18741
+ description: `Find code in a project folder that matches the given ast-grep pattern.
19106
18742
 
19107
- **Example:**
19108
- \`\`\`
19109
- dora_unused()
19110
- \`\`\`
18743
+ Pattern is good for simple and single-AST node result. For more complex usage, use ast_grep_scan_code.
19111
18744
 
19112
- **Returns:** List of symbols with zero references.`,
19113
- args: {},
19114
- async execute() {
19115
- const status = checkDoraStatus();
19116
- if (!status.installed || !status.indexed) {
18745
+ **Parameters:**
18746
+ - project_folder: The absolute path to the project folder
18747
+ - pattern: The ast-grep pattern to search for (e.g., 'console.log($ARG)', '$VAR = $VALUE')
18748
+ - language: Optional - programming language filter
18749
+
18750
+ **Pattern Examples:**
18751
+ - 'console.log($ARG)' - Match console.log with any argument
18752
+ - '$VAR = $VALUE' - Match any assignment
18753
+ - 'function $NAME($PARAMS) { $BODY }' - Match function declarations`,
18754
+ args: {
18755
+ project_folder: tool.schema.string().describe("The absolute path to the project folder"),
18756
+ pattern: tool.schema.string().describe("The ast-grep pattern to search for"),
18757
+ language: tool.schema.string().optional().describe("Programming language filter (typescript, javascript, python, etc.)")
18758
+ },
18759
+ async execute({ project_folder, pattern, language }) {
18760
+ await initAstGrep();
18761
+ if (!astGrepModule) {
19117
18762
  return JSON.stringify({
19118
18763
  success: false,
19119
- error: "Dora not ready. Run dora_status first."
18764
+ error: "@ast-grep/napi not available",
18765
+ hint: "Install @ast-grep/napi or use MCP-based ast_grep"
19120
18766
  }, null, 2);
19121
18767
  }
19122
- const result = runDoraCommand(["unused"]);
19123
- if (!result.success) {
18768
+ try {
18769
+ if (!fs7.existsSync(project_folder)) {
18770
+ return JSON.stringify({
18771
+ success: false,
18772
+ error: `Path not found: ${project_folder}`
18773
+ }, null, 2);
18774
+ }
18775
+ const langMap = {
18776
+ typescript: "TypeScript",
18777
+ javascript: "JavaScript",
18778
+ tsx: "Tsx",
18779
+ jsx: "Jsx",
18780
+ python: "Python",
18781
+ rust: "Rust",
18782
+ go: "Go",
18783
+ java: "Java"
18784
+ };
18785
+ const lang = language ? langMap[language.toLowerCase()] || language : "TypeScript";
18786
+ const Lang = astGrepModule.Lang;
18787
+ if (!Lang[lang]) {
18788
+ return JSON.stringify({
18789
+ success: false,
18790
+ error: `Unsupported language: ${language}`
18791
+ }, null, 2);
18792
+ }
18793
+ const findInFiles = astGrepModule.findInFiles;
18794
+ const results = [];
18795
+ await findInFiles(Lang[lang], {
18796
+ paths: [project_folder],
18797
+ matcher: { rule: { pattern } }
18798
+ }, (err, node) => {
18799
+ if (err) {
18800
+ console.warn("[ast-grep] Search error:", err);
18801
+ return;
18802
+ }
18803
+ if (node) {
18804
+ const text = node.text();
18805
+ const range = node.range();
18806
+ results.push({
18807
+ file: node.filename() || "unknown",
18808
+ line: range ? range.start.index : 0,
18809
+ column: range ? range.start.column : 0,
18810
+ matched: text.slice(0, 100)
18811
+ });
18812
+ }
18813
+ });
19124
18814
  return JSON.stringify({
19125
- success: false,
19126
- error: result.error
18815
+ success: true,
18816
+ count: results.length,
18817
+ matches: results.slice(0, 50)
19127
18818
  }, null, 2);
19128
- }
19129
- return JSON.stringify({
19130
- success: true,
19131
- unused: result.output
19132
- }, null, 2);
19133
- }
19134
- });
19135
-
19136
- // src/tools/auto-cr.ts
19137
- import { execSync as execSync3 } from "child_process";
19138
- import * as fs7 from "fs";
19139
- function checkAutoCrStatus() {
19140
- try {
19141
- const output = execSync3("auto-cr-cmd --version", { encoding: "utf-8" });
19142
- const version2 = output.trim();
19143
- return { installed: true, version: version2 };
19144
- } catch {
19145
- return { installed: false };
19146
- }
19147
- }
19148
- function runAutoCr(args2) {
19149
- try {
19150
- const allArgs = [...args2, "--output", "json"];
19151
- const output = execSync3(`auto-cr-cmd ${allArgs.join(" ")}`, {
19152
- encoding: "utf-8",
19153
- maxBuffer: 50 * 1024 * 1024
19154
- });
19155
- try {
19156
- const json2 = JSON.parse(output);
19157
- return { success: true, output, json: json2 };
19158
- } catch {
19159
- return { success: true, output };
19160
- }
19161
- } catch (error45) {
19162
- const stderr = error45.stderr || "";
19163
- const stdout = error45.stdout || "";
19164
- const combined = stdout + stderr;
19165
- try {
19166
- const json2 = JSON.parse(combined);
19167
- return { success: true, output: combined, json: json2 };
19168
- } catch {
19169
- return { success: false, error: combined || error45.message };
19170
- }
19171
- }
19172
- }
19173
- var autoCrStatusTool = tool({
19174
- description: `Check auto-cr-cmd installation status.
19175
-
19176
- **Returns:**
19177
- - installed: Whether auto-cr-cmd is available
19178
- - version: Auto-CR version
19179
- - ready: Whether it's ready to scan
19180
-
19181
- **Installation:**
19182
- \`\`\`bash
19183
- npm install auto-cr-cmd
19184
- # or
19185
- pnpm add auto-cr-cmd
19186
- \`\`\``,
19187
- args: {},
19188
- async execute() {
19189
- const status = checkAutoCrStatus();
19190
- if (!status.installed) {
18819
+ } catch (error45) {
19191
18820
  return JSON.stringify({
19192
- status: "not_installed",
19193
- message: "auto-cr-cmd not found",
19194
- installation: "npm install auto-cr-cmd"
18821
+ success: false,
18822
+ error: error45 instanceof Error ? error45.message : String(error45)
19195
18823
  }, null, 2);
19196
18824
  }
19197
- return JSON.stringify({
19198
- status: "ready",
19199
- version: status.version,
19200
- message: "Auto-CR is ready to scan",
19201
- rules: [
19202
- "no-deep-relative-imports",
19203
- "no-circular-dependencies",
19204
- "no-swallowed-errors",
19205
- "no-catastrophic-regex",
19206
- "no-deep-clone-in-loop",
19207
- "no-n2-array-lookup"
19208
- ]
19209
- }, null, 2);
19210
18825
  }
19211
18826
  });
19212
- var autoCrScanTool = tool({
19213
- description: `Scan directory for code issues using auto-cr (SWC-based static analysis).
18827
+ var astGrepScanCodeTool = tool({
18828
+ description: `Analyze TypeScript/JS code for common bugs, performance issues and best practices.
19214
18829
 
19215
- **Parameters:**
19216
- - path: Directory path to scan (defaults to ./src)
19217
- - language: Output language (en/zh, defaults to en)
18830
+ Uses AST-based analysis for precise detection without false positives. Essential for maintaining code quality and preventing runtime errors.
19218
18831
 
19219
- **Rules detected:**
19220
- - no-deep-relative-imports: Import paths exceeding depth limit
19221
- - no-circular-dependencies: Circular module dependencies
19222
- - no-swallowed-errors: try-catch blocks that swallow errors
19223
- - no-catastrophic-regex: Potentially catastrophic regex patterns
19224
- - no-deep-clone-in-loop: Performance anti-patterns
19225
- - no-n2-array-lookup: O(n²) array operations
18832
+ **Detects:**
18833
+ - Type safety violations
18834
+ - Loose object types
18835
+ - Incorrect async patterns
18836
+ - Import style issues
18837
+ - Common bugs
19226
18838
 
19227
- **Example:**
19228
- \`\`\`
19229
- auto_cr_scan({ path: "./src" })
19230
- \`\`\``,
18839
+ **Parameters:**
18840
+ - project_folder: Optional - path to scan (defaults to current directory)`,
19231
18841
  args: {
19232
- path: tool.schema.string().optional().default("./src").describe("Directory path to scan"),
19233
- language: tool.schema.string().optional().default("en").describe("Output language (en or zh)")
18842
+ project_folder: tool.schema.string().optional().describe("Path to scan (defaults to current directory)")
19234
18843
  },
19235
- async execute({ path: path7, language }) {
19236
- const status = checkAutoCrStatus();
19237
- if (!status.installed) {
18844
+ async execute({ project_folder }) {
18845
+ await initAstGrep();
18846
+ if (!astGrepModule) {
18847
+ return JSON.stringify({
18848
+ success: false,
18849
+ error: "@ast-grep/napi not available",
18850
+ hint: "Install @ast-grep/napi or use MCP-based ast_grep"
18851
+ }, null, 2);
18852
+ }
18853
+ try {
18854
+ const scanPath = project_folder || process.cwd();
18855
+ if (!fs7.existsSync(scanPath)) {
18856
+ return JSON.stringify({
18857
+ success: false,
18858
+ error: `Path not found: ${scanPath}`
18859
+ }, null, 2);
18860
+ }
18861
+ const bugPatterns = [
18862
+ { pattern: "await Promise.all($ARR)", severity: "warning", message: "Check if Promise.all is used correctly with async operations" },
18863
+ { pattern: "JSON.parse($STR)", severity: "info", message: "Consider adding try-catch for JSON.parse" },
18864
+ { pattern: "$VAR == $VAL", severity: "warning", message: "Use === instead of == for strict equality" }
18865
+ ];
18866
+ const issues = [];
18867
+ const Lang = astGrepModule.Lang;
18868
+ const findInFiles = astGrepModule.findInFiles;
18869
+ for (const bug of bugPatterns) {
18870
+ await findInFiles(Lang.TypeScript, {
18871
+ paths: [scanPath],
18872
+ matcher: { rule: { pattern: bug.pattern } }
18873
+ }, (err, node) => {
18874
+ if (err || !node)
18875
+ return;
18876
+ issues.push({
18877
+ file: node.filename() || "unknown",
18878
+ line: node.range()?.start.index || 0,
18879
+ severity: bug.severity,
18880
+ message: bug.message,
18881
+ pattern: bug.pattern
18882
+ });
18883
+ });
18884
+ }
19238
18885
  return JSON.stringify({
19239
- success: false,
19240
- error: "auto-cr-cmd not installed",
19241
- hint: "npm install auto-cr-cmd"
18886
+ success: true,
18887
+ scanned: scanPath,
18888
+ issuesFound: issues.length,
18889
+ issues: issues.slice(0, 20),
18890
+ summary: issues.length === 0 ? "No common issues detected" : `Found ${issues.length} potential issues`
19242
18891
  }, null, 2);
19243
- }
19244
- if (!fs7.existsSync(path7)) {
18892
+ } catch (error45) {
19245
18893
  return JSON.stringify({
19246
18894
  success: false,
19247
- error: `Path not found: ${path7}`
18895
+ error: error45 instanceof Error ? error45.message : String(error45)
19248
18896
  }, null, 2);
19249
18897
  }
19250
- const result = runAutoCr(["--language", language, path7]);
19251
- if (!result.success && !result.json) {
18898
+ }
18899
+ });
18900
+ var astGrepRewriteCodeTool = tool({
18901
+ description: `Transform and refactor code using AST-based find-and-replace patterns.
18902
+
18903
+ Use metavariables ($VAR, $$$VARS) in both pattern and replacement.
18904
+
18905
+ **Example:** Find 'console.log($ARG)' and replace with 'logger.info($ARG)'
18906
+
18907
+ **Parameters:**
18908
+ - project_folder: Path to the project folder
18909
+ - pattern: AST pattern to find
18910
+ - replacement: Replacement pattern
18911
+ - language: Programming language (defaults to TypeScript)`,
18912
+ args: {
18913
+ project_folder: tool.schema.string().describe("Path to the project folder"),
18914
+ pattern: tool.schema.string().describe("AST pattern to find"),
18915
+ replacement: tool.schema.string().describe("Replacement pattern"),
18916
+ language: tool.schema.string().optional().default("TypeScript").describe("Programming language")
18917
+ },
18918
+ async execute({ project_folder, pattern, replacement, language }) {
18919
+ await initAstGrep();
18920
+ if (!astGrepModule) {
19252
18921
  return JSON.stringify({
19253
18922
  success: false,
19254
- error: result.error || "Scan failed"
18923
+ error: "@ast-grep/napi not available",
18924
+ hint: "Install @ast-grep/napi or use MCP-based ast_grep"
19255
18925
  }, null, 2);
19256
18926
  }
19257
- if (result.json) {
19258
- const { summary, files, notifications } = result.json;
18927
+ try {
18928
+ if (!fs7.existsSync(project_folder)) {
18929
+ return JSON.stringify({
18930
+ success: false,
18931
+ error: `Path not found: ${project_folder}`
18932
+ }, null, 2);
18933
+ }
18934
+ const Lang = astGrepModule.Lang;
18935
+ if (!Lang[language]) {
18936
+ return JSON.stringify({
18937
+ success: false,
18938
+ error: `Unsupported language: ${language}`
18939
+ }, null, 2);
18940
+ }
19259
18941
  return JSON.stringify({
19260
18942
  success: true,
19261
- scanned: path7,
19262
- summary: {
19263
- filesScanned: summary?.scannedFiles || 0,
19264
- filesWithErrors: summary?.filesWithErrors || 0,
19265
- filesWithWarnings: summary?.filesWithWarnings || 0,
19266
- totalViolations: summary?.violationTotals?.total || 0
19267
- },
19268
- files: files?.map((f) => ({
19269
- path: f.filePath,
19270
- violations: f.totalViolations,
19271
- errors: f.severityCounts?.error || 0,
19272
- warnings: f.severityCounts?.warning || 0,
19273
- details: f.violations?.map((v) => ({
19274
- rule: v.ruleName,
19275
- severity: v.severity,
19276
- message: v.message,
19277
- line: v.line
19278
- }))
19279
- })),
19280
- notifications: notifications || []
18943
+ operation: "info",
18944
+ message: "Full rewrite requires @ast-grep/cli with config file",
18945
+ suggestion: "Use ast_grep_find_code to find matches, then hive_code_edit for individual replacements",
18946
+ parameters: {
18947
+ projectFolder: project_folder,
18948
+ pattern,
18949
+ replacement,
18950
+ language
18951
+ }
18952
+ }, null, 2);
18953
+ } catch (error45) {
18954
+ return JSON.stringify({
18955
+ success: false,
18956
+ error: error45 instanceof Error ? error45.message : String(error45)
19281
18957
  }, null, 2);
19282
18958
  }
19283
- return JSON.stringify({
19284
- success: true,
19285
- scanned: path7,
19286
- rawOutput: result.output
19287
- }, null, 2);
19288
18959
  }
19289
18960
  });
19290
- var autoCrDiffTool = tool({
19291
- description: `Scan git diff output for code issues using auto-cr.
19292
-
19293
- **Use case:** Run in CI to check only changed files.
18961
+ var astGrepAnalyzeImportsTool = tool({
18962
+ description: `Analyze import statements and dependencies in your codebase.
19294
18963
 
19295
- **Example:**
19296
- \`\`\`bash
19297
- git diff --name-only -z | xargs -0 auto-cr-cmd --stdin --output json
19298
- \`\`\`
18964
+ Choose "usage" to see which imports are actually used (great for refactoring), or "discovery" to explore all imports and identifiers in the code (great for understanding structure).
19299
18965
 
19300
- **Note:** This tool requires git diff output piped via stdin.`,
18966
+ **Parameters:**
18967
+ - mode: "usage" (default) shows where imports are used, "discovery" shows all imports
18968
+ - path: Specific directory or file to analyze (defaults to current directory)`,
19301
18969
  args: {
19302
- language: tool.schema.string().optional().default("en").describe("Output language (en or zh)")
18970
+ mode: tool.schema.enum(["usage", "discovery"]).default("usage").describe("Analysis mode"),
18971
+ path: tool.schema.string().optional().describe("Directory or file to analyze")
19303
18972
  },
19304
- async execute({ language }) {
19305
- const status = checkAutoCrStatus();
19306
- if (!status.installed) {
18973
+ async execute({ mode, path: path7 }) {
18974
+ await initAstGrep();
18975
+ if (!astGrepModule) {
19307
18976
  return JSON.stringify({
19308
18977
  success: false,
19309
- error: "auto-cr-cmd not installed",
19310
- hint: "npm install auto-cr-cmd"
18978
+ error: "@ast-grep/napi not available"
19311
18979
  }, null, 2);
19312
18980
  }
19313
- return JSON.stringify({
19314
- success: true,
19315
- message: "Use git diff with auto-cr directly",
19316
- example: "git diff --name-only -z | xargs -0 npx auto-cr-cmd --stdin --output json"
19317
- }, null, 2);
19318
- }
19319
- });
19320
- var autoCrRulesTool = tool({
19321
- description: `List available auto-cr rules and their descriptions.
19322
-
19323
- **Returns:** All built-in rules with descriptions.`,
19324
- args: {},
19325
- async execute() {
19326
- const rules = [
19327
- {
19328
- name: "no-deep-relative-imports",
19329
- severity: "error",
19330
- description: "Import paths should not exceed maximum depth",
19331
- example: "Use path aliases (@shared/utils) instead of ../../../../shared/utils"
19332
- },
19333
- {
19334
- name: "no-circular-dependencies",
19335
- severity: "warning",
19336
- description: "Detect circular module dependencies",
19337
- example: "A imports B, B imports A creates a cycle"
19338
- },
19339
- {
19340
- name: "no-swallowed-errors",
19341
- severity: "warning",
19342
- description: "try-catch blocks that swallow errors without rethrowing",
19343
- example: "catch (e) {} without logging or rethrowing"
19344
- },
19345
- {
19346
- name: "no-catastrophic-regex",
19347
- severity: "error",
19348
- description: "Potentially catastrophic regex backtracking",
19349
- example: "Regex with nested quantifiers that can hang"
19350
- },
19351
- {
19352
- name: "no-deep-clone-in-loop",
19353
- severity: "warning",
19354
- description: "Performance: deep clone operations inside loops",
19355
- example: "for loop calling JSON.parse(JSON.stringify())"
19356
- },
19357
- {
19358
- name: "no-n2-array-lookup",
19359
- severity: "warning",
19360
- description: "O(n²) array operations",
19361
- example: "Nested for loops accessing array elements"
18981
+ try {
18982
+ const analyzePath = path7 || process.cwd();
18983
+ if (!fs7.existsSync(analyzePath)) {
18984
+ return JSON.stringify({
18985
+ success: false,
18986
+ error: `Path not found: ${analyzePath}`
18987
+ }, null, 2);
19362
18988
  }
19363
- ];
19364
- return JSON.stringify({
19365
- success: true,
19366
- rules,
19367
- totalRules: rules.length
19368
- }, null, 2);
18989
+ const Lang = astGrepModule.Lang;
18990
+ const findInFiles = astGrepModule.findInFiles;
18991
+ const imports = {};
18992
+ await findInFiles(Lang.TypeScript, {
18993
+ paths: [analyzePath],
18994
+ matcher: { rule: { kind: "import_statement" } }
18995
+ }, (err, node) => {
18996
+ if (err || !node)
18997
+ return;
18998
+ const text = node.text();
18999
+ const match = text.match(/from ['"]([^'"]+)['"]/);
19000
+ if (match) {
19001
+ const module = match[1];
19002
+ const file2 = node.filename() || "unknown";
19003
+ if (!imports[module]) {
19004
+ imports[module] = [];
19005
+ }
19006
+ if (!imports[module].includes(file2)) {
19007
+ imports[module].push(file2);
19008
+ }
19009
+ }
19010
+ });
19011
+ if (mode === "usage") {
19012
+ return JSON.stringify({
19013
+ success: true,
19014
+ mode: "usage",
19015
+ imports: Object.entries(imports).map(([module, files]) => ({
19016
+ module,
19017
+ importCount: 1,
19018
+ filesCount: files.length
19019
+ })),
19020
+ note: "Full usage analysis requires @ast-grep/cli"
19021
+ }, null, 2);
19022
+ }
19023
+ return JSON.stringify({
19024
+ success: true,
19025
+ mode: "discovery",
19026
+ totalModules: Object.keys(imports).length,
19027
+ imports: Object.entries(imports).map(([module, files]) => ({
19028
+ module,
19029
+ importCount: files.length,
19030
+ files: files.slice(0, 5)
19031
+ }))
19032
+ }, null, 2);
19033
+ } catch (error45) {
19034
+ return JSON.stringify({
19035
+ success: false,
19036
+ error: error45 instanceof Error ? error45.message : String(error45)
19037
+ }, null, 2);
19038
+ }
19369
19039
  }
19370
19040
  });
19371
19041
 
@@ -20696,12 +20366,6 @@ var grepAppMcp = {
20696
20366
  oauth: false
20697
20367
  };
20698
20368
 
20699
- // src/mcp/ast-grep.ts
20700
- var astGrepMcp = {
20701
- type: "local",
20702
- command: ["npx", "-y", "@notprolands/ast-grep-mcp"]
20703
- };
20704
-
20705
20369
  // src/mcp/pare-search.ts
20706
20370
  var pareSearchMcp = {
20707
20371
  type: "local",
@@ -20714,14 +20378,20 @@ var veilMcp = {
20714
20378
  command: ["npx", "-y", "@ushiradineth/veil@latest", "mcp", "server"]
20715
20379
  };
20716
20380
 
20381
+ // src/mcp/ast-grep.ts
20382
+ var astGrepMcp = {
20383
+ type: "local",
20384
+ command: ["npx", "-y", "@notprolands/ast-grep-mcp"]
20385
+ };
20386
+
20717
20387
  // src/mcp/index.ts
20718
20388
  var allBuiltinMcps = {
20719
20389
  websearch: websearchMcp,
20720
20390
  context7: context7Mcp,
20721
20391
  grep_app: grepAppMcp,
20722
- ast_grep: astGrepMcp,
20723
20392
  pare_search: pareSearchMcp,
20724
- veil: veilMcp
20393
+ veil: veilMcp,
20394
+ ast_grep: astGrepMcp
20725
20395
  };
20726
20396
  var createBuiltinMcps = (disabledMcps = []) => {
20727
20397
  const disabled = new Set(disabledMcps);
@@ -20753,7 +20423,7 @@ import * as fs11 from "fs";
20753
20423
  import * as path8 from "path";
20754
20424
  import { existsSync as existsSync52 } from "fs";
20755
20425
  import { join as join92, sep } from "path";
20756
- import { execSync as execSync4 } from "child_process";
20426
+ import { execSync as execSync5 } from "child_process";
20757
20427
  var __create2 = Object.create;
20758
20428
  var __getProtoOf2 = Object.getPrototypeOf;
20759
20429
  var __defProp2 = Object.defineProperty;
@@ -27618,10 +27288,10 @@ class DockerSandboxService {
27618
27288
  static ensureContainer(worktreePath, image) {
27619
27289
  const name = this.containerName(worktreePath);
27620
27290
  try {
27621
- execSync4(`docker inspect --format='{{.State.Running}}' ${name}`, { stdio: "pipe" });
27291
+ execSync5(`docker inspect --format='{{.State.Running}}' ${name}`, { stdio: "pipe" });
27622
27292
  return name;
27623
27293
  } catch {
27624
- execSync4(`docker run -d --name ${name} -v ${worktreePath}:/app -w /app ${image} tail -f /dev/null`, { stdio: "pipe" });
27294
+ execSync5(`docker run -d --name ${name} -v ${worktreePath}:/app -w /app ${image} tail -f /dev/null`, { stdio: "pipe" });
27625
27295
  return name;
27626
27296
  }
27627
27297
  }
@@ -27632,12 +27302,12 @@ class DockerSandboxService {
27632
27302
  static stopContainer(worktreePath) {
27633
27303
  const name = this.containerName(worktreePath);
27634
27304
  try {
27635
- execSync4(`docker rm -f ${name}`, { stdio: "ignore" });
27305
+ execSync5(`docker rm -f ${name}`, { stdio: "ignore" });
27636
27306
  } catch {}
27637
27307
  }
27638
27308
  static isDockerAvailable() {
27639
27309
  try {
27640
- execSync4("docker info", { stdio: "ignore" });
27310
+ execSync5("docker info", { stdio: "ignore" });
27641
27311
  return true;
27642
27312
  } catch {
27643
27313
  return false;
@@ -28988,12 +28658,6 @@ ${snapshot}
28988
28658
  hive_vector_search: hiveVectorSearchTool,
28989
28659
  hive_vector_add: hiveVectorAddTool,
28990
28660
  hive_vector_status: hiveVectorStatusTool,
28991
- ast_grep_dump_syntax_tree: astGrepDumpSyntaxTreeTool,
28992
- ast_grep_test_match_code_rule: astGrepTestMatchCodeRuleTool,
28993
- ast_grep_find_code: astGrepFindCodeTool,
28994
- ast_grep_scan_code: astGrepScanCodeTool,
28995
- ast_grep_rewrite_code: astGrepRewriteCodeTool,
28996
- ast_grep_analyze_imports: astGrepAnalyzeImportsTool,
28997
28661
  hive_doctor: hiveDoctorTool,
28998
28662
  hive_doctor_quick: hiveDoctorQuickTool,
28999
28663
  dora_status: doraStatusTool,
@@ -29006,6 +28670,12 @@ ${snapshot}
29006
28670
  auto_cr_scan: autoCrScanTool,
29007
28671
  auto_cr_diff: autoCrDiffTool,
29008
28672
  auto_cr_rules: autoCrRulesTool,
28673
+ ast_grep_dump_syntax_tree: astGrepDumpSyntaxTreeTool,
28674
+ ast_grep_test_match_code_rule: astGrepTestMatchCodeRuleTool,
28675
+ ast_grep_find_code: astGrepFindCodeTool,
28676
+ ast_grep_scan_code: astGrepScanCodeTool,
28677
+ ast_grep_rewrite_code: astGrepRewriteCodeTool,
28678
+ ast_grep_analyze_imports: astGrepAnalyzeImportsTool,
29009
28679
  hive_skill: createHiveSkillTool(filteredSkills),
29010
28680
  hive_feature_create: tool({
29011
28681
  description: "Create a new feature and set it as active",