@hung319/opencode-hive 1.5.1 → 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, {
@@ -854,8 +450,8 @@ var init_context_compression = __esm(() => {
854
450
  });
855
451
 
856
452
  // src/index.ts
857
- import * as path12 from "path";
858
- import * as os5 from "os";
453
+ import * as path11 from "path";
454
+ import * as os4 from "os";
859
455
 
860
456
  // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/classic/external.js
861
457
  var exports_external = {};
@@ -18208,485 +17804,52 @@ 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"
18275
- };
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
- };
17840
+ execSync2(`npx -y ${npxCmd} --version`, { stdio: "pipe", timeout: 1e4 });
17841
+ return {
17842
+ ...tool3,
17843
+ installed: true,
17844
+ version: "via npx"
18308
17845
  };
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
- }
18321
- }
18322
- });
18323
- var astGrepTestMatchCodeRuleTool = tool({
18324
- description: `Test a code against an ast-grep YAML rule.
18325
-
18326
- This is useful to test a rule before using it in a project.
18327
-
18328
- **Parameters:**
18329
- - code: The code to test against the rule
18330
- - yaml: The ast-grep YAML rule to test
18331
-
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);
18347
- }
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"
18360
- }
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);
18367
- }
18368
- }
18369
- });
18370
- var astGrepFindCodeTool = tool({
18371
- description: `Find code in a project folder that matches the given ast-grep pattern.
18372
-
18373
- Pattern is good for simple and single-AST node result. For more complex usage, use ast_grep_scan_code.
18374
-
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
18379
-
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) {
18392
- 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"
17846
+ } catch {
17847
+ return {
17848
+ ...tool3,
17849
+ installed: false
18414
17850
  };
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
- });
18442
- }
18443
- });
18444
- return JSON.stringify({
18445
- success: true,
18446
- count: results.length,
18447
- matches: results.slice(0, 50)
18448
- }, null, 2);
18449
- } catch (error45) {
18450
- return JSON.stringify({
18451
- success: false,
18452
- error: error45 instanceof Error ? error45.message : String(error45)
18453
- }, null, 2);
18454
17851
  }
18455
17852
  }
18456
- });
18457
- var astGrepScanCodeTool = tool({
18458
- description: `Analyze TypeScript/JS code for common bugs, performance issues and best practices.
18459
-
18460
- Uses AST-based analysis for precise detection without false positives. Essential for maintaining code quality and preventing runtime errors.
18461
-
18462
- **Detects:**
18463
- - Type safety violations
18464
- - Loose object types
18465
- - Incorrect async patterns
18466
- - Import style issues
18467
- - Common bugs
18468
-
18469
- **Parameters:**
18470
- - project_folder: Optional - path to scan (defaults to current directory)`,
18471
- args: {
18472
- project_folder: tool.schema.string().optional().describe("Path to scan (defaults to current directory)")
18473
- },
18474
- async execute({ project_folder }) {
18475
- await initAstGrep();
18476
- if (!astGrepModule) {
18477
- return JSON.stringify({
18478
- success: false,
18479
- error: "@ast-grep/napi not available",
18480
- hint: "Install @ast-grep/napi or use MCP-based ast_grep"
18481
- }, null, 2);
18482
- }
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) {
18523
- return JSON.stringify({
18524
- success: false,
18525
- error: error45 instanceof Error ? error45.message : String(error45)
18526
- }, null, 2);
18527
- }
18528
- }
18529
- });
18530
- var astGrepRewriteCodeTool = tool({
18531
- description: `Transform and refactor code using AST-based find-and-replace patterns.
18532
-
18533
- Use metavariables ($VAR, $$$VARS) in both pattern and replacement.
18534
-
18535
- **Example:** Find 'console.log($ARG)' and replace with 'logger.info($ARG)'
18536
-
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)`,
18542
- 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")
18547
- },
18548
- async execute({ project_folder, pattern, replacement, language }) {
18549
- await initAstGrep();
18550
- if (!astGrepModule) {
18551
- return JSON.stringify({
18552
- success: false,
18553
- error: "@ast-grep/napi not available",
18554
- hint: "Install @ast-grep/napi or use MCP-based ast_grep"
18555
- }, null, 2);
18556
- }
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) {
18584
- return JSON.stringify({
18585
- success: false,
18586
- error: error45 instanceof Error ? error45.message : String(error45)
18587
- }, null, 2);
18588
- }
18589
- }
18590
- });
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).
18595
-
18596
- **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)`,
18599
- 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")
18602
- },
18603
- async execute({ mode, path: path6 }) {
18604
- await initAstGrep();
18605
- if (!astGrepModule) {
18606
- return JSON.stringify({
18607
- success: false,
18608
- error: "@ast-grep/napi not available"
18609
- }, null, 2);
18610
- }
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) {
18664
- return JSON.stringify({
18665
- success: false,
18666
- error: error45 instanceof Error ? error45.message : String(error45)
18667
- }, null, 2);
18668
- }
18669
- }
18670
- });
18671
-
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
17853
  }
18691
17854
  function checkOptimizations() {
18692
17855
  const checks3 = [];
@@ -18696,9 +17859,9 @@ function checkOptimizations() {
18696
17859
  ];
18697
17860
  let config2 = null;
18698
17861
  for (const configPath of configPaths) {
18699
- if (fs6.existsSync(configPath)) {
17862
+ if (fs5.existsSync(configPath)) {
18700
17863
  try {
18701
- const content = fs6.readFileSync(configPath, "utf-8");
17864
+ const content = fs5.readFileSync(configPath, "utf-8");
18702
17865
  config2 = JSON.parse(content.replace(/\\/g, ""));
18703
17866
  break;
18704
17867
  } catch {}
@@ -18729,26 +17892,30 @@ function checkOptimizations() {
18729
17892
  recommendation: sandboxConfig === "none" ? "Enable Docker sandbox for isolated test environments" : undefined
18730
17893
  });
18731
17894
  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
17895
  const hasPareSearch = !disabledMcps.includes("pare_search");
18739
17896
  checks3.push({
18740
17897
  name: "pareSearch",
18741
17898
  enabled: hasPareSearch,
18742
17899
  recommendation: !hasPareSearch ? "Enable pare_search for structured ripgrep output (65-95% token reduction)" : undefined
18743
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
+ });
18744
17907
  return checks3;
18745
17908
  }
18746
- function generateRecommendations(dependencies, optimizations) {
17909
+ function generateRecommendations(dependencies, cliTools, optimizations) {
18747
17910
  const recommendations = [];
18748
17911
  const missingRequired = dependencies.filter((d) => d.required && !d.installed);
18749
17912
  if (missingRequired.length > 0) {
18750
17913
  recommendations.push(`Missing required packages: ${missingRequired.map((d) => d.name).join(", ")}`);
18751
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
+ }
18752
17919
  const disabledOptimizations = optimizations.filter((o) => !o.enabled && o.recommendation);
18753
17920
  for (const opt of disabledOptimizations) {
18754
17921
  if (opt.recommendation) {
@@ -18756,11 +17923,11 @@ function generateRecommendations(dependencies, optimizations) {
18756
17923
  }
18757
17924
  }
18758
17925
  if (recommendations.length === 0) {
18759
- recommendations.push("System is optimized! No immediate actions needed.");
17926
+ recommendations.push("System is healthy! All checks passed.");
18760
17927
  }
18761
17928
  return recommendations;
18762
17929
  }
18763
- function generateQuickFixes(dependencies, optimizations) {
17930
+ function generateQuickFixes(dependencies, cliTools, optimizations) {
18764
17931
  const fixes = [];
18765
17932
  const missingPackages = dependencies.filter((d) => !d.installed && !d.required);
18766
17933
  for (const pkg of missingPackages) {
@@ -18769,6 +17936,13 @@ function generateQuickFixes(dependencies, optimizations) {
18769
17936
  description: `Install ${pkg.name}`
18770
17937
  });
18771
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
+ }
18772
17946
  if (optimizations.find((o) => o.name === "snip" && !o.enabled)) {
18773
17947
  fixes.push({
18774
17948
  command: 'Add to ~/.config/opencode/agent_hive.json: { "snip": { "enabled": true } }',
@@ -18783,13 +17957,14 @@ function generateQuickFixes(dependencies, optimizations) {
18783
17957
  }
18784
17958
  return fixes;
18785
17959
  }
18786
- function calculateStatus(dependencies, optimizations) {
17960
+ function calculateStatus(dependencies, cliTools, optimizations) {
18787
17961
  const missingRequired = dependencies.filter((d) => d.required && !d.installed);
18788
17962
  if (missingRequired.length > 0) {
18789
17963
  return "issues";
18790
17964
  }
17965
+ const missingTools = cliTools.filter((t) => !t.installed);
18791
17966
  const disabledCount = optimizations.filter((o) => !o.enabled).length;
18792
- if (disabledCount > 2) {
17967
+ if (missingTools.length > 0 || disabledCount > 2) {
18793
17968
  return "warning";
18794
17969
  }
18795
17970
  return "healthy";
@@ -18799,8 +17974,9 @@ var hiveDoctorTool = tool({
18799
17974
 
18800
17975
  **What it checks:**
18801
17976
  1. Dependencies - Optional packages installed and working
18802
- 2. Optimizations - Features enabled in config
18803
- 3. Recommendations - Suggestions for improvements
17977
+ 2. CLI Tools - dora, auto-cr, etc. available via npx
17978
+ 3. Optimizations - Features enabled in config
17979
+ 4. Recommendations - Suggestions for improvements
18804
17980
 
18805
17981
  **Use when:**
18806
17982
  - Setting up Hive for the first time
@@ -18810,27 +17986,55 @@ var hiveDoctorTool = tool({
18810
17986
 
18811
17987
  **Example output:**
18812
17988
  - healthy: All checks pass
18813
- - warning: Some optimizations disabled
17989
+ - warning: Some optimizations disabled or CLI tools missing
18814
17990
  - issues: Missing required packages`,
18815
17991
  args: {},
18816
17992
  async execute() {
18817
17993
  const dependencyChecks = [
18818
17994
  { name: "agent-booster", package: "@sparkleideas/agent-booster", required: false },
18819
17995
  { name: "vector-memory", package: "@sparkleideas/memory", required: false },
18820
- { name: "ast-grep NAPI", package: "@ast-grep/napi", required: false },
18821
17996
  { name: "pare-search", package: "@paretools/search", required: false },
18822
17997
  { name: "context7", package: "@upstash/context7-mcp", required: false },
18823
17998
  { name: "Exa search", package: "exa-mcp-server", required: false }
18824
17999
  ];
18825
- for (const dep of dependencyChecks) {
18826
- const result2 = await checkPackage(dep.package);
18827
- dep.installed = result2.installed;
18828
- dep.version = result2.version;
18000
+ for (const dep of dependencyChecks) {
18001
+ const result2 = await checkPackage(dep.package);
18002
+ dep.installed = result2.installed;
18003
+ dep.version = result2.version;
18004
+ }
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);
18829
18033
  }
18830
18034
  const optimizationChecks = checkOptimizations();
18831
- const recommendations = generateRecommendations(dependencyChecks, optimizationChecks);
18832
- const quickFixes = generateQuickFixes(dependencyChecks, optimizationChecks);
18833
- const status = calculateStatus(dependencyChecks, optimizationChecks);
18035
+ const recommendations = generateRecommendations(dependencyChecks, cliToolChecks, optimizationChecks);
18036
+ const quickFixes = generateQuickFixes(dependencyChecks, cliToolChecks, optimizationChecks);
18037
+ const status = calculateStatus(dependencyChecks, cliToolChecks, optimizationChecks);
18834
18038
  const result = {
18835
18039
  status,
18836
18040
  timestamp: new Date().toISOString(),
@@ -18840,6 +18044,12 @@ var hiveDoctorTool = tool({
18840
18044
  installed: dependencyChecks.filter((d) => d.installed).length,
18841
18045
  packages: dependencyChecks
18842
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
+ },
18843
18053
  optimizations: {
18844
18054
  total: optimizationChecks.length,
18845
18055
  enabled: optimizationChecks.filter((o) => o.enabled).length,
@@ -18857,12 +18067,11 @@ var hiveDoctorQuickTool = tool({
18857
18067
 
18858
18068
  **Returns:**
18859
18069
  - healthy: All systems go
18860
- - warning: Some optimizations disabled
18070
+ - warning: Some CLI tools missing or optimizations disabled
18861
18071
  - issues: Action required`,
18862
18072
  args: {},
18863
18073
  async execute() {
18864
18074
  const keyPackages = [
18865
- "@ast-grep/napi",
18866
18075
  "@sparkleideas/agent-booster",
18867
18076
  "@paretools/search"
18868
18077
  ];
@@ -18878,494 +18087,955 @@ var hiveDoctorQuickTool = tool({
18878
18087
  return JSON.stringify({
18879
18088
  status: healthy ? "healthy" : "warning",
18880
18089
  packages: results,
18881
- runFullCheck: "Use hive_doctor for detailed analysis"
18090
+ runFullCheck: "Use hive_doctor for detailed analysis with CLI tool checks"
18882
18091
  }, null, 2);
18883
18092
  }
18884
18093
  });
18885
18094
 
18886
18095
  // src/tools/dora.ts
18887
- import { execSync as execSync2 } from "child_process";
18096
+ import { execSync as execSync3 } from "child_process";
18888
18097
  function checkDoraStatus() {
18889
18098
  try {
18890
- const output = execSync2("dora --version", { encoding: "utf-8" });
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.
18120
+
18121
+ **Returns:**
18122
+ - installed: Whether dora CLI is available
18123
+ - version: Dora version
18124
+ - indexed: Whether codebase has been indexed
18125
+
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) {
18136
+ return JSON.stringify({
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"
18143
+ }
18144
+ }, null, 2);
18145
+ }
18146
+ if (!status.indexed) {
18147
+ return JSON.stringify({
18148
+ status: "not_indexed",
18149
+ version: status.version,
18150
+ message: "Codebase not indexed",
18151
+ nextStep: "Run: dora init && dora index"
18152
+ }, null, 2);
18153
+ }
18154
+ return JSON.stringify({
18155
+ status: "ready",
18156
+ version: status.version,
18157
+ indexed: true,
18158
+ message: "Dora is ready"
18159
+ }, null, 2);
18160
+ }
18161
+ });
18162
+ var doraSymbolTool = tool({
18163
+ description: `Find symbol definitions using dora (SCIP-based).
18164
+
18165
+ **Parameters:**
18166
+ - name: Symbol name to search for
18167
+ - kind: Filter by symbol kind (function, class, method, etc.)
18168
+
18169
+ **Example:**
18170
+ \`\`\`
18171
+ dora_symbol({ name: "getUserById" })
18172
+ \`\`\`
18173
+
18174
+ **Note:** Requires dora to be installed and indexed.`,
18175
+ args: {
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.)")
18178
+ },
18179
+ async execute({ name, kind }) {
18180
+ const status = checkDoraStatus();
18181
+ if (!status.installed || !status.indexed) {
18182
+ return JSON.stringify({
18183
+ success: false,
18184
+ error: "Dora not ready. Run dora_status first.",
18185
+ hint: "Install and index: dora init && dora index"
18186
+ }, null, 2);
18187
+ }
18188
+ const args2 = ["symbol", name];
18189
+ if (kind) {
18190
+ args2.push("--kind", kind);
18191
+ }
18192
+ const result = runDoraCommand(args2);
18193
+ if (!result.success) {
18194
+ return JSON.stringify({
18195
+ success: false,
18196
+ error: result.error,
18197
+ hint: "Symbol may not exist or not indexed"
18198
+ }, null, 2);
18199
+ }
18200
+ return JSON.stringify({
18201
+ success: true,
18202
+ symbol: name,
18203
+ output: result.output
18204
+ }, null, 2);
18205
+ }
18206
+ });
18207
+ var doraFileTool = tool({
18208
+ description: `Get file dependencies and information using dora.
18209
+
18210
+ **Parameters:**
18211
+ - path: File path to analyze
18212
+
18213
+ **Example:**
18214
+ \`\`\`
18215
+ dora_file({ path: "src/index.ts" })
18216
+ \`\`\`
18217
+
18218
+ **Returns:** File metadata, exports, and dependencies.`,
18219
+ args: {
18220
+ path: tool.schema.string().describe("File path to analyze")
18221
+ },
18222
+ async execute({ path: path7 }) {
18223
+ const status = checkDoraStatus();
18224
+ if (!status.installed || !status.indexed) {
18225
+ return JSON.stringify({
18226
+ success: false,
18227
+ error: "Dora not ready. Run dora_status first."
18228
+ }, null, 2);
18229
+ }
18230
+ const result = runDoraCommand(["file", path7]);
18231
+ if (!result.success) {
18232
+ return JSON.stringify({
18233
+ success: false,
18234
+ error: result.error,
18235
+ hint: "File may not exist or not indexed"
18236
+ }, null, 2);
18237
+ }
18238
+ return JSON.stringify({
18239
+ success: true,
18240
+ path: path7,
18241
+ output: result.output
18242
+ }, null, 2);
18243
+ }
18244
+ });
18245
+ var doraReferencesTool = tool({
18246
+ description: `Find all references to a symbol using dora.
18247
+
18248
+ **Parameters:**
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.`,
18257
+ args: {
18258
+ name: tool.schema.string().describe("Symbol name to find references for")
18259
+ },
18260
+ async execute({ name }) {
18261
+ const status = checkDoraStatus();
18262
+ if (!status.installed || !status.indexed) {
18263
+ return JSON.stringify({
18264
+ success: false,
18265
+ error: "Dora not ready. Run dora_status first."
18266
+ }, null, 2);
18267
+ }
18268
+ const result = runDoraCommand(["references", name]);
18269
+ if (!result.success) {
18270
+ return JSON.stringify({
18271
+ success: false,
18272
+ error: result.error
18273
+ }, null, 2);
18274
+ }
18275
+ return JSON.stringify({
18276
+ success: true,
18277
+ symbol: name,
18278
+ output: result.output
18279
+ }, null, 2);
18280
+ }
18281
+ });
18282
+ var doraCyclesTool = tool({
18283
+ description: `Detect circular dependencies in the codebase using dora.
18284
+
18285
+ **Example:**
18286
+ \`\`\`
18287
+ dora_cycles()
18288
+ \`\`\`
18289
+
18290
+ **Returns:** List of circular dependency paths if found.`,
18291
+ args: {},
18292
+ async execute() {
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);
18299
+ }
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);
18311
+ }
18312
+ });
18313
+ var doraUnusedTool = tool({
18314
+ description: `Find unused/dead code in the codebase using dora.
18315
+
18316
+ **Example:**
18317
+ \`\`\`
18318
+ dora_unused()
18319
+ \`\`\`
18320
+
18321
+ **Returns:** List of symbols with zero references.`,
18322
+ args: {},
18323
+ async execute() {
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);
18337
+ }
18338
+ return JSON.stringify({
18339
+ success: true,
18340
+ unused: result.output
18341
+ }, null, 2);
18342
+ }
18343
+ });
18344
+
18345
+ // src/tools/auto-cr.ts
18346
+ import { execSync as execSync4 } from "child_process";
18347
+ import * as fs6 from "fs";
18348
+ function checkAutoCrStatus() {
18349
+ try {
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
- }
18402
+ message: "auto-cr-cmd not found",
18403
+ installation: "npm install auto-cr-cmd"
18935
18404
  }, null, 2);
18936
18405
  }
18937
- if (!status.indexed) {
18406
+ return JSON.stringify({
18407
+ status: "ready",
18408
+ version: status.version,
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
+ ]
18418
+ }, null, 2);
18419
+ }
18420
+ });
18421
+ var autoCrScanTool = tool({
18422
+ description: `Scan directory for code issues using auto-cr (SWC-based static analysis).
18423
+
18424
+ **Parameters:**
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
18435
+
18436
+ **Example:**
18437
+ \`\`\`
18438
+ auto_cr_scan({ path: "./src" })
18439
+ \`\`\``,
18440
+ args: {
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)")
18443
+ },
18444
+ async execute({ path: path7, language }) {
18445
+ const status = checkAutoCrStatus();
18446
+ if (!status.installed) {
18938
18447
  return JSON.stringify({
18939
- status: "not_indexed",
18940
- version: status.version,
18941
- message: "Codebase not indexed",
18942
- nextStep: "Run: dora init && dora index"
18448
+ success: false,
18449
+ error: "auto-cr-cmd not installed",
18450
+ hint: "npm install auto-cr-cmd"
18451
+ }, null, 2);
18452
+ }
18453
+ if (!fs6.existsSync(path7)) {
18454
+ return JSON.stringify({
18455
+ success: false,
18456
+ error: `Path not found: ${path7}`
18457
+ }, null, 2);
18458
+ }
18459
+ const result = runAutoCr(["--language", language, path7]);
18460
+ if (!result.success && !result.json) {
18461
+ return JSON.stringify({
18462
+ success: false,
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 || []
18943
18490
  }, null, 2);
18944
18491
  }
18945
18492
  return JSON.stringify({
18946
- status: "ready",
18947
- version: status.version,
18948
- indexed: true,
18949
- message: "Dora is ready"
18493
+ success: true,
18494
+ scanned: path7,
18495
+ rawOutput: result.output
18950
18496
  }, null, 2);
18951
18497
  }
18952
18498
  });
18953
- var doraSymbolTool = tool({
18954
- description: `Find symbol definitions using dora (SCIP-based).
18499
+ var autoCrDiffTool = tool({
18500
+ description: `Scan git diff output for code issues using auto-cr.
18501
+
18502
+ **Use case:** Run in CI to check only changed files.
18503
+
18504
+ **Example:**
18505
+ \`\`\`bash
18506
+ git diff --name-only -z | xargs -0 auto-cr-cmd --stdin --output json
18507
+ \`\`\`
18508
+
18509
+ **Note:** This tool requires git diff output piped via stdin.`,
18510
+ args: {
18511
+ language: tool.schema.string().optional().default("en").describe("Output language (en or zh)")
18512
+ },
18513
+ async execute({ language }) {
18514
+ const status = checkAutoCrStatus();
18515
+ if (!status.installed) {
18516
+ return JSON.stringify({
18517
+ success: false,
18518
+ error: "auto-cr-cmd not installed",
18519
+ hint: "npm install auto-cr-cmd"
18520
+ }, null, 2);
18521
+ }
18522
+ return JSON.stringify({
18523
+ success: true,
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"
18526
+ }, null, 2);
18527
+ }
18528
+ });
18529
+ var autoCrRulesTool = tool({
18530
+ description: `List available auto-cr rules and their descriptions.
18531
+
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
+ });
18580
+
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.
18955
18606
 
18956
- **Parameters:**
18957
- - name: Symbol name to search for
18958
- - kind: Filter by symbol kind (function, class, method, etc.)
18607
+ This is useful to discover correct syntax kind and syntax tree structure. Call it when debugging a rule.
18959
18608
 
18960
- **Example:**
18961
- \`\`\`
18962
- dora_symbol({ name: "getUserById" })
18963
- \`\`\`
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)
18964
18613
 
18965
- **Note:** Requires dora to be installed and indexed.`,
18614
+ **Use when:**
18615
+ - Debugging AST patterns
18616
+ - Finding correct syntax kind names
18617
+ - Understanding code structure`,
18966
18618
  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.)")
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")
18969
18622
  },
18970
- async execute({ name, kind }) {
18971
- const status = checkDoraStatus();
18972
- if (!status.installed || !status.indexed) {
18623
+ async execute({ code, language, format }) {
18624
+ await initAstGrep();
18625
+ if (!astGrepModule) {
18973
18626
  return JSON.stringify({
18974
18627
  success: false,
18975
- error: "Dora not ready. Run dora_status first.",
18976
- hint: "Install and index: dora init && dora index"
18628
+ error: "@ast-grep/napi not available",
18629
+ hint: "Install @ast-grep/napi or use MCP-based ast_grep"
18977
18630
  }, null, 2);
18978
18631
  }
18979
- const args2 = ["symbol", name];
18980
- if (kind) {
18981
- args2.push("--kind", kind);
18982
- }
18983
- const result = runDoraCommand(args2);
18984
- 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) {
18985
18686
  return JSON.stringify({
18986
18687
  success: false,
18987
- error: result.error,
18988
- hint: "Symbol may not exist or not indexed"
18688
+ error: error45 instanceof Error ? error45.message : String(error45)
18989
18689
  }, null, 2);
18990
18690
  }
18991
- return JSON.stringify({
18992
- success: true,
18993
- symbol: name,
18994
- output: result.output
18995
- }, null, 2);
18996
18691
  }
18997
18692
  });
18998
- var doraFileTool = tool({
18999
- description: `Get file dependencies and information using dora.
18693
+ var astGrepTestMatchCodeRuleTool = tool({
18694
+ description: `Test a code against an ast-grep YAML rule.
19000
18695
 
19001
- **Parameters:**
19002
- - path: File path to analyze
18696
+ This is useful to test a rule before using it in a project.
19003
18697
 
19004
- **Example:**
19005
- \`\`\`
19006
- dora_file({ path: "src/index.ts" })
19007
- \`\`\`
18698
+ **Parameters:**
18699
+ - code: The code to test against the rule
18700
+ - yaml: The ast-grep YAML rule to test
19008
18701
 
19009
- **Returns:** File metadata, exports, and dependencies.`,
18702
+ **Returns:**
18703
+ - Whether the rule matched
18704
+ - Matched nodes with locations`,
19010
18705
  args: {
19011
- path: tool.schema.string().describe("File path to analyze")
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")
19012
18708
  },
19013
- async execute({ path: path7 }) {
19014
- const status = checkDoraStatus();
19015
- if (!status.installed || !status.indexed) {
18709
+ async execute({ code, yaml }) {
18710
+ await initAstGrep();
18711
+ if (!astGrepModule) {
19016
18712
  return JSON.stringify({
19017
18713
  success: false,
19018
- 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"
19019
18716
  }, null, 2);
19020
18717
  }
19021
- const result = runDoraCommand(["file", path7]);
19022
- if (!result.success) {
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
+ }
18731
+ }, null, 2);
18732
+ } catch (error45) {
19023
18733
  return JSON.stringify({
19024
18734
  success: false,
19025
- error: result.error,
19026
- hint: "File may not exist or not indexed"
18735
+ error: error45 instanceof Error ? error45.message : String(error45)
19027
18736
  }, null, 2);
19028
18737
  }
19029
- return JSON.stringify({
19030
- success: true,
19031
- path: path7,
19032
- output: result.output
19033
- }, null, 2);
19034
18738
  }
19035
18739
  });
19036
- var doraReferencesTool = tool({
19037
- description: `Find all references to a symbol using dora.
18740
+ var astGrepFindCodeTool = tool({
18741
+ description: `Find code in a project folder that matches the given ast-grep pattern.
19038
18742
 
19039
- **Parameters:**
19040
- - name: Symbol name to find references for
18743
+ Pattern is good for simple and single-AST node result. For more complex usage, use ast_grep_scan_code.
19041
18744
 
19042
- **Example:**
19043
- \`\`\`
19044
- dora_references({ name: "UserService" })
19045
- \`\`\`
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
19046
18749
 
19047
- **Note:** Returns all usages across the codebase.`,
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`,
19048
18754
  args: {
19049
- name: tool.schema.string().describe("Symbol name to find references for")
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.)")
19050
18758
  },
19051
- async execute({ name }) {
19052
- const status = checkDoraStatus();
19053
- if (!status.installed || !status.indexed) {
19054
- return JSON.stringify({
19055
- success: false,
19056
- error: "Dora not ready. Run dora_status first."
19057
- }, null, 2);
19058
- }
19059
- const result = runDoraCommand(["references", name]);
19060
- if (!result.success) {
18759
+ async execute({ project_folder, pattern, language }) {
18760
+ await initAstGrep();
18761
+ if (!astGrepModule) {
19061
18762
  return JSON.stringify({
19062
18763
  success: false,
19063
- error: result.error
18764
+ error: "@ast-grep/napi not available",
18765
+ hint: "Install @ast-grep/napi or use MCP-based ast_grep"
19064
18766
  }, null, 2);
19065
18767
  }
19066
- return JSON.stringify({
19067
- success: true,
19068
- symbol: name,
19069
- output: result.output
19070
- }, null, 2);
19071
- }
19072
- });
19073
- var doraCyclesTool = tool({
19074
- description: `Detect circular dependencies in the codebase using dora.
19075
-
19076
- **Example:**
19077
- \`\`\`
19078
- dora_cycles()
19079
- \`\`\`
19080
-
19081
- **Returns:** List of circular dependency paths if found.`,
19082
- args: {},
19083
- async execute() {
19084
- const status = checkDoraStatus();
19085
- if (!status.installed || !status.indexed) {
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
+ });
19086
18814
  return JSON.stringify({
19087
- success: false,
19088
- error: "Dora not ready. Run dora_status first."
18815
+ success: true,
18816
+ count: results.length,
18817
+ matches: results.slice(0, 50)
19089
18818
  }, null, 2);
19090
- }
19091
- const result = runDoraCommand(["cycles"]);
19092
- if (!result.success) {
18819
+ } catch (error45) {
19093
18820
  return JSON.stringify({
19094
18821
  success: false,
19095
- error: result.error
18822
+ error: error45 instanceof Error ? error45.message : String(error45)
19096
18823
  }, null, 2);
19097
18824
  }
19098
- return JSON.stringify({
19099
- success: true,
19100
- cycles: result.output
19101
- }, null, 2);
19102
18825
  }
19103
18826
  });
19104
- var doraUnusedTool = tool({
19105
- description: `Find unused/dead code in the codebase using dora.
18827
+ var astGrepScanCodeTool = tool({
18828
+ description: `Analyze TypeScript/JS code for common bugs, performance issues and best practices.
19106
18829
 
19107
- **Example:**
19108
- \`\`\`
19109
- dora_unused()
19110
- \`\`\`
18830
+ Uses AST-based analysis for precise detection without false positives. Essential for maintaining code quality and preventing runtime errors.
19111
18831
 
19112
- **Returns:** List of symbols with zero references.`,
19113
- args: {},
19114
- async execute() {
19115
- const status = checkDoraStatus();
19116
- if (!status.installed || !status.indexed) {
18832
+ **Detects:**
18833
+ - Type safety violations
18834
+ - Loose object types
18835
+ - Incorrect async patterns
18836
+ - Import style issues
18837
+ - Common bugs
18838
+
18839
+ **Parameters:**
18840
+ - project_folder: Optional - path to scan (defaults to current directory)`,
18841
+ args: {
18842
+ project_folder: tool.schema.string().optional().describe("Path to scan (defaults to current directory)")
18843
+ },
18844
+ async execute({ project_folder }) {
18845
+ await initAstGrep();
18846
+ if (!astGrepModule) {
19117
18847
  return JSON.stringify({
19118
18848
  success: false,
19119
- error: "Dora not ready. Run dora_status first."
18849
+ error: "@ast-grep/napi not available",
18850
+ hint: "Install @ast-grep/napi or use MCP-based ast_grep"
19120
18851
  }, null, 2);
19121
18852
  }
19122
- const result = runDoraCommand(["unused"]);
19123
- if (!result.success) {
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
+ }
19124
18885
  return JSON.stringify({
19125
- success: false,
19126
- error: result.error
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`
19127
18891
  }, 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) {
18892
+ } catch (error45) {
19191
18893
  return JSON.stringify({
19192
- status: "not_installed",
19193
- message: "auto-cr-cmd not found",
19194
- installation: "npm install auto-cr-cmd"
18894
+ success: false,
18895
+ error: error45 instanceof Error ? error45.message : String(error45)
19195
18896
  }, null, 2);
19196
18897
  }
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
18898
  }
19211
18899
  });
19212
- var autoCrScanTool = tool({
19213
- description: `Scan directory for code issues using auto-cr (SWC-based static analysis).
18900
+ var astGrepRewriteCodeTool = tool({
18901
+ description: `Transform and refactor code using AST-based find-and-replace patterns.
19214
18902
 
19215
- **Parameters:**
19216
- - path: Directory path to scan (defaults to ./src)
19217
- - language: Output language (en/zh, defaults to en)
18903
+ Use metavariables ($VAR, $$$VARS) in both pattern and replacement.
19218
18904
 
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
18905
+ **Example:** Find 'console.log($ARG)' and replace with 'logger.info($ARG)'
19226
18906
 
19227
- **Example:**
19228
- \`\`\`
19229
- auto_cr_scan({ path: "./src" })
19230
- \`\`\``,
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)`,
19231
18912
  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)")
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")
19234
18917
  },
19235
- async execute({ path: path7, language }) {
19236
- const status = checkAutoCrStatus();
19237
- if (!status.installed) {
19238
- return JSON.stringify({
19239
- success: false,
19240
- error: "auto-cr-cmd not installed",
19241
- hint: "npm install auto-cr-cmd"
19242
- }, null, 2);
19243
- }
19244
- if (!fs7.existsSync(path7)) {
18918
+ async execute({ project_folder, pattern, replacement, language }) {
18919
+ await initAstGrep();
18920
+ if (!astGrepModule) {
19245
18921
  return JSON.stringify({
19246
18922
  success: false,
19247
- error: `Path not found: ${path7}`
18923
+ error: "@ast-grep/napi not available",
18924
+ hint: "Install @ast-grep/napi or use MCP-based ast_grep"
19248
18925
  }, null, 2);
19249
18926
  }
19250
- const result = runAutoCr(["--language", language, path7]);
19251
- if (!result.success && !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
+ }
19252
18941
  return JSON.stringify({
19253
- success: false,
19254
- error: result.error || "Scan failed"
18942
+ success: true,
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
+ }
19255
18952
  }, null, 2);
19256
- }
19257
- if (result.json) {
19258
- const { summary, files, notifications } = result.json;
18953
+ } catch (error45) {
19259
18954
  return JSON.stringify({
19260
- 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 || []
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;
@@ -21607,8 +21277,7 @@ var DEFAULT_HIVE_CONFIG = {
21607
21277
  enabled: false,
21608
21278
  indexPath: path7.join(os3.homedir(), ".config", "opencode", "hive", "vector-index"),
21609
21279
  dimensions: 384
21610
- },
21611
- autoInstallDeps: true
21280
+ }
21612
21281
  };
21613
21282
  var HIVE_DIR = ".hive";
21614
21283
  var FEATURES_DIR = "features";
@@ -27619,10 +27288,10 @@ class DockerSandboxService {
27619
27288
  static ensureContainer(worktreePath, image) {
27620
27289
  const name = this.containerName(worktreePath);
27621
27290
  try {
27622
- execSync4(`docker inspect --format='{{.State.Running}}' ${name}`, { stdio: "pipe" });
27291
+ execSync5(`docker inspect --format='{{.State.Running}}' ${name}`, { stdio: "pipe" });
27623
27292
  return name;
27624
27293
  } catch {
27625
- 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" });
27626
27295
  return name;
27627
27296
  }
27628
27297
  }
@@ -27633,12 +27302,12 @@ class DockerSandboxService {
27633
27302
  static stopContainer(worktreePath) {
27634
27303
  const name = this.containerName(worktreePath);
27635
27304
  try {
27636
- execSync4(`docker rm -f ${name}`, { stdio: "ignore" });
27305
+ execSync5(`docker rm -f ${name}`, { stdio: "ignore" });
27637
27306
  } catch {}
27638
27307
  }
27639
27308
  static isDockerAvailable() {
27640
27309
  try {
27641
- execSync4("docker info", { stdio: "ignore" });
27310
+ execSync5("docker info", { stdio: "ignore" });
27642
27311
  return true;
27643
27312
  } catch {
27644
27313
  return false;
@@ -28218,183 +27887,6 @@ function buildCompactionPrompt() {
28218
27887
  return COMPACTION_RESUME_PROMPT;
28219
27888
  }
28220
27889
 
28221
- // src/utils/dep-installer.ts
28222
- import { execSync as execSync5 } from "child_process";
28223
- import * as path11 from "path";
28224
- import * as os4 from "os";
28225
- var PLUGIN_TOOLS = [
28226
- {
28227
- name: "btca",
28228
- npmPackage: "btca-cli",
28229
- installCommand: ["npm", "install", "-g", "btca-cli"],
28230
- verifyCommand: "btca --version",
28231
- description: "Bluetooth Classic Audio control",
28232
- required: false
28233
- },
28234
- {
28235
- name: "dora",
28236
- npmPackage: "@butttons/dora",
28237
- installCommand: ["npm", "install", "-g", "@butttons/dora"],
28238
- verifyCommand: "dora --version",
28239
- description: "SCIP-based code navigation",
28240
- required: false
28241
- },
28242
- {
28243
- name: "auto-cr",
28244
- npmPackage: "auto-cr-cmd",
28245
- installCommand: ["npm", "install", "-g", "auto-cr-cmd"],
28246
- verifyCommand: "auto-cr-cmd --version",
28247
- description: "SWC-based automated code review",
28248
- required: false
28249
- },
28250
- {
28251
- name: "scip-typescript",
28252
- npmPackage: "@sourcegraph/scip-typescript",
28253
- installCommand: ["npm", "install", "-g", "@sourcegraph/scip-typescript"],
28254
- verifyCommand: "scip-typescript --version",
28255
- description: "TypeScript SCIP indexer (for dora)",
28256
- required: false
28257
- },
28258
- {
28259
- name: "typescript-language-server",
28260
- npmPackage: "typescript-language-server",
28261
- installCommand: ["npm", "install", "-g", "typescript-language-server", "typescript"],
28262
- verifyCommand: "typescript-language-server --version",
28263
- description: "TypeScript/JavaScript LSP server",
28264
- required: false
28265
- },
28266
- {
28267
- name: "pyright",
28268
- npmPackage: "pyright",
28269
- installCommand: ["pip", "install", "pyright"],
28270
- verifyCommand: "pyright --version",
28271
- description: "Python LSP server",
28272
- required: false
28273
- }
28274
- ];
28275
-
28276
- class DependencyInstaller {
28277
- installDir;
28278
- cache = new Map;
28279
- cacheTimeout = 60000;
28280
- constructor(installDir) {
28281
- this.installDir = installDir || path11.join(os4.homedir(), ".local");
28282
- }
28283
- getBinDir() {
28284
- return path11.join(this.installDir, "bin");
28285
- }
28286
- commandExists(cmd) {
28287
- try {
28288
- execSync5(`which ${cmd}`, { stdio: "ignore" });
28289
- return true;
28290
- } catch {
28291
- return false;
28292
- }
28293
- }
28294
- verifyTool(config2) {
28295
- try {
28296
- execSync5(config2.verifyCommand, { stdio: "ignore", timeout: 5000 });
28297
- return true;
28298
- } catch {
28299
- return false;
28300
- }
28301
- }
28302
- async install(config2) {
28303
- console.log(`[dep-installer] Installing ${config2.name}...`);
28304
- try {
28305
- const [cmd, ...args2] = config2.installCommand;
28306
- const fullCmd = `${cmd} ${args2.join(" ")}`;
28307
- execSync5(fullCmd, {
28308
- stdio: "inherit",
28309
- timeout: 120000,
28310
- env: {
28311
- ...process.env,
28312
- ...cmd === "npm" ? { npm_config_prefix: this.installDir } : {}
28313
- }
28314
- });
28315
- const verified = this.verifyTool(config2);
28316
- if (verified) {
28317
- console.log(`[dep-installer] ✓ ${config2.name} installed successfully`);
28318
- this.cache.set(config2.name, { installed: true, checked: Date.now() });
28319
- return { success: true, output: `${config2.name} installed and verified` };
28320
- } else {
28321
- return { success: false, error: "Installation completed but verification failed" };
28322
- }
28323
- } catch (error45) {
28324
- console.warn(`[dep-installer] ✗ ${config2.name} installation failed: ${error45.message}`);
28325
- return { success: false, error: error45.message };
28326
- }
28327
- }
28328
- isInstalled(toolName) {
28329
- const cached2 = this.cache.get(toolName);
28330
- if (cached2 && Date.now() - cached2.checked < this.cacheTimeout) {
28331
- return cached2.installed;
28332
- }
28333
- const config2 = PLUGIN_TOOLS.find((t) => t.name === toolName);
28334
- if (!config2)
28335
- return false;
28336
- const installed = this.verifyTool(config2);
28337
- this.cache.set(toolName, { installed, checked: Date.now() });
28338
- return installed;
28339
- }
28340
- getStatus() {
28341
- return PLUGIN_TOOLS.map((config2) => ({
28342
- name: config2.name,
28343
- installed: this.isInstalled(config2.name),
28344
- description: config2.description,
28345
- required: config2.required
28346
- }));
28347
- }
28348
- async ensureRequired() {
28349
- const installed = [];
28350
- const missing = [];
28351
- const errors3 = {};
28352
- for (const config2 of PLUGIN_TOOLS) {
28353
- if (config2.required && !this.isInstalled(config2.name)) {
28354
- const result = await this.install(config2);
28355
- if (result.success) {
28356
- installed.push(config2.name);
28357
- } else {
28358
- missing.push(config2.name);
28359
- errors3[config2.name] = result.error || "Installation failed";
28360
- }
28361
- }
28362
- }
28363
- return { installed, missing, errors: errors3 };
28364
- }
28365
- async installAll() {
28366
- const success2 = [];
28367
- const failed = {};
28368
- for (const config2 of PLUGIN_TOOLS) {
28369
- if (!this.isInstalled(config2.name)) {
28370
- const result = await this.install(config2);
28371
- if (result.success) {
28372
- success2.push(config2.name);
28373
- } else {
28374
- failed[config2.name] = result.error || "Installation failed";
28375
- }
28376
- } else {
28377
- success2.push(config2.name);
28378
- }
28379
- }
28380
- return { success: success2, failed };
28381
- }
28382
- async installTool(toolName) {
28383
- const config2 = PLUGIN_TOOLS.find((t) => t.name === toolName);
28384
- if (!config2) {
28385
- return { success: false, error: `Unknown tool: ${toolName}. Available: ${PLUGIN_TOOLS.map((t) => t.name).join(", ")}` };
28386
- }
28387
- if (this.isInstalled(toolName)) {
28388
- return { success: true, output: `${toolName} is already installed` };
28389
- }
28390
- return this.install(config2);
28391
- }
28392
- }
28393
- var dependencyInstaller = new DependencyInstaller;
28394
- async function ensurePluginDeps() {
28395
- dependencyInstaller.ensureRequired().catch(console.error);
28396
- }
28397
-
28398
27890
  // src/index.ts
28399
27891
  function formatSkillsXml(skills) {
28400
27892
  if (skills.length === 0)
@@ -28420,7 +27912,7 @@ async function buildAutoLoadedSkillsContent(agentName, configService, projectRoo
28420
27912
  if (autoLoadSkills.length === 0) {
28421
27913
  return "";
28422
27914
  }
28423
- const homeDir = process.env.HOME || os5.homedir();
27915
+ const homeDir = process.env.HOME || os4.homedir();
28424
27916
  const skillTemplates = [];
28425
27917
  for (const skillId of autoLoadSkills) {
28426
27918
  const builtinSkill = BUILTIN_SKILLS.find((entry) => entry.name === skillId);
@@ -28502,14 +27994,11 @@ var plugin = async (ctx) => {
28502
27994
  const disabledMcps = configService.getDisabledMcps();
28503
27995
  const disabledSkills = configService.getDisabledSkills();
28504
27996
  const builtinMcps = createBuiltinMcps(disabledMcps);
28505
- if (configService.get().autoInstallDeps !== false) {
28506
- ensurePluginDeps();
28507
- }
28508
27997
  const filteredSkills = getFilteredSkills(disabledSkills);
28509
27998
  const effectiveAutoLoadSkills = configService.getAgentConfig("zetta").autoLoadSkills ?? [];
28510
27999
  const worktreeService = new WorktreeService({
28511
28000
  baseDir: directory,
28512
- hiveDir: path12.join(directory, ".hive")
28001
+ hiveDir: path11.join(directory, ".hive")
28513
28002
  });
28514
28003
  const isOmoSlimEnabled = () => {
28515
28004
  return configService.isOmoSlimEnabled();
@@ -28536,7 +28025,7 @@ var plugin = async (ctx) => {
28536
28025
  };
28537
28026
  const checkBlocked = (feature) => {
28538
28027
  const fs12 = __require("fs");
28539
- const blockedPath = path12.join(directory, ".hive", "features", feature, "BLOCKED");
28028
+ const blockedPath = path11.join(directory, ".hive", "features", feature, "BLOCKED");
28540
28029
  if (fs12.existsSync(blockedPath)) {
28541
28030
  const reason = fs12.readFileSync(blockedPath, "utf-8").trim();
28542
28031
  return `⛔ BLOCKED by Beekeeper
@@ -28690,9 +28179,9 @@ To unblock: Remove .hive/features/${feature}/BLOCKED`;
28690
28179
  spec: specContent,
28691
28180
  workerPrompt
28692
28181
  });
28693
- const hiveDir = path12.join(directory, ".hive");
28182
+ const hiveDir = path11.join(directory, ".hive");
28694
28183
  const workerPromptPath = writeWorkerPromptFile(feature, task, workerPrompt, hiveDir);
28695
- const relativePromptPath = normalizePath(path12.relative(directory, workerPromptPath));
28184
+ const relativePromptPath = normalizePath(path11.relative(directory, workerPromptPath));
28696
28185
  const PREVIEW_MAX_LENGTH = 200;
28697
28186
  const workerPromptPreview = workerPrompt.length > PREVIEW_MAX_LENGTH ? workerPrompt.slice(0, PREVIEW_MAX_LENGTH) + "..." : workerPrompt;
28698
28187
  const taskToolPrompt = `Follow instructions in @${relativePromptPath}`;
@@ -29100,7 +28589,7 @@ ${snapshot}
29100
28589
  if (sandboxConfig.mode !== "none") {
29101
28590
  const workdir = output.args?.workdir;
29102
28591
  if (workdir) {
29103
- const hiveWorktreeBase = path12.join(directory, ".hive", ".worktrees");
28592
+ const hiveWorktreeBase = path11.join(directory, ".hive", ".worktrees");
29104
28593
  if (workdir.startsWith(hiveWorktreeBase)) {
29105
28594
  const wrapped = DockerSandboxService.wrapCommand(workdir, finalCommand, sandboxConfig);
29106
28595
  output.args.command = wrapped;
@@ -29169,12 +28658,6 @@ ${snapshot}
29169
28658
  hive_vector_search: hiveVectorSearchTool,
29170
28659
  hive_vector_add: hiveVectorAddTool,
29171
28660
  hive_vector_status: hiveVectorStatusTool,
29172
- ast_grep_dump_syntax_tree: astGrepDumpSyntaxTreeTool,
29173
- ast_grep_test_match_code_rule: astGrepTestMatchCodeRuleTool,
29174
- ast_grep_find_code: astGrepFindCodeTool,
29175
- ast_grep_scan_code: astGrepScanCodeTool,
29176
- ast_grep_rewrite_code: astGrepRewriteCodeTool,
29177
- ast_grep_analyze_imports: astGrepAnalyzeImportsTool,
29178
28661
  hive_doctor: hiveDoctorTool,
29179
28662
  hive_doctor_quick: hiveDoctorQuickTool,
29180
28663
  dora_status: doraStatusTool,
@@ -29187,6 +28670,12 @@ ${snapshot}
29187
28670
  auto_cr_scan: autoCrScanTool,
29188
28671
  auto_cr_diff: autoCrDiffTool,
29189
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,
29190
28679
  hive_skill: createHiveSkillTool(filteredSkills),
29191
28680
  hive_feature_create: tool({
29192
28681
  description: "Create a new feature and set it as active",