@hung319/opencode-hive 1.4.3 → 1.5.1

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
@@ -96,8 +96,8 @@ var require_dist = __commonJS((exports) => {
96
96
  Object.defineProperty(exports, "__esModule", { value: true });
97
97
  exports.AgentBooster = undefined;
98
98
  exports.apply = apply;
99
- var path3 = __importStar(__require("path"));
100
- var wasmPath = path3.join(__dirname, "../wasm/agent_booster_wasm.js");
99
+ var path4 = __importStar(__require("path"));
100
+ var wasmPath = path4.join(__dirname, "../wasm/agent_booster_wasm.js");
101
101
  var AgentBoosterWasm;
102
102
  try {
103
103
  AgentBoosterWasm = __require(wasmPath);
@@ -235,6 +235,410 @@ 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
+
238
642
  // src/utils/context-compression.ts
239
643
  var exports_context_compression = {};
240
644
  __export(exports_context_compression, {
@@ -450,8 +854,8 @@ var init_context_compression = __esm(() => {
450
854
  });
451
855
 
452
856
  // src/index.ts
453
- import * as path9 from "path";
454
- import * as os4 from "os";
857
+ import * as path12 from "path";
858
+ import * as os5 from "os";
455
859
 
456
860
  // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/classic/external.js
457
861
  var exports_external = {};
@@ -15809,125 +16213,458 @@ var ptyListTool = tool({
15809
16213
  }
15810
16214
  });
15811
16215
 
15812
- // src/tools/lsp.ts
15813
- async function getLspConnection(filePath) {
15814
- const ext = filePath.split(".").pop()?.toLowerCase() || "";
15815
- const serverMap = {
15816
- ts: "typescript",
15817
- tsx: "typescript",
15818
- js: "typescript",
15819
- jsx: "typescript",
15820
- py: "pylance",
15821
- rs: "rust-analyzer",
15822
- go: "gopls",
15823
- java: "eclipse-jdtls",
15824
- cpp: "clangd",
15825
- c: "clangd",
15826
- h: "clangd",
15827
- cs: "omnisharp"
15828
- };
15829
- const serverId = serverMap[ext];
15830
- if (!serverId) {
15831
- return null;
15832
- }
15833
- return { serverId };
15834
- }
15835
- var lspRenameTool = tool({
15836
- description: "Rename a symbol across all files using LSP. Provides IDE-like rename refactoring with cross-file support.",
15837
- args: {
15838
- filePath: tool.schema.string().describe("Path to the file containing the symbol"),
15839
- oldName: tool.schema.string().describe("Current name of the symbol to rename"),
15840
- newName: tool.schema.string().describe("New name for the symbol")
16216
+ // src/tools/lsp-manager.ts
16217
+ import { execSync } from "child_process";
16218
+ import * as path2 from "path";
16219
+ var LSP_DATABASE = {
16220
+ typescript: {
16221
+ extensions: ["ts", "tsx", "js", "jsx", "mjs", "cjs"],
16222
+ primary: {
16223
+ command: "npm",
16224
+ args: ["install", "-g", "typescript-language-server", "typescript"],
16225
+ verifyCommand: "typescript-language-server --version"
16226
+ },
16227
+ alternatives: [
16228
+ {
16229
+ command: "npm",
16230
+ args: ["install", "-g", "@volarjs/typescript-language-server"],
16231
+ verifyCommand: "volar-server --version"
16232
+ }
16233
+ ]
15841
16234
  },
15842
- async execute({ filePath, oldName, newName }) {
15843
- const lsp = await getLspConnection(filePath);
15844
- if (!lsp) {
15845
- return JSON.stringify({
15846
- success: false,
15847
- error: `No LSP server available for file: ${filePath}`,
15848
- hint: "LSP servers are auto-detected based on file type.",
15849
- alternative: "Use ast_grep_rewrite_code() tool for pattern-based renaming"
15850
- }, null, 2);
15851
- }
15852
- return JSON.stringify({
15853
- success: true,
15854
- message: `Rename "${oldName}" to "${newName}" in ${filePath}`,
15855
- server: lsp.serverId,
15856
- operation: "textDocument/rename",
15857
- oldName,
15858
- newName,
15859
- filePath
15860
- }, null, 2);
15861
- }
15862
- });
15863
- var lspGotoDefinitionTool = tool({
15864
- description: "Navigate to the definition of a symbol using LSP. Jump from a usage to its definition.",
15865
- args: {
15866
- filePath: tool.schema.string().describe("Path to the file containing the symbol"),
15867
- line: tool.schema.number().describe("Line number (1-based)"),
15868
- character: tool.schema.number().describe("Character position (0-based)")
16235
+ python: {
16236
+ extensions: ["py", "pyw", "pyi"],
16237
+ primary: {
16238
+ command: "pip",
16239
+ args: ["install", "pyright"],
16240
+ verifyCommand: "pyright --version"
16241
+ },
16242
+ alternatives: [
16243
+ {
16244
+ command: "pip",
16245
+ args: ["install", "ruff-lsp"],
16246
+ verifyCommand: "ruff-lsp --version"
16247
+ },
16248
+ {
16249
+ command: "pip",
16250
+ args: ["install", "jedi-language-server"],
16251
+ verifyCommand: "jedi-language-server --version"
16252
+ }
16253
+ ]
15869
16254
  },
15870
- async execute({ filePath, line, character }) {
15871
- const lsp = await getLspConnection(filePath);
15872
- if (!lsp) {
15873
- return JSON.stringify({
15874
- success: false,
15875
- error: `No LSP server available for file: ${filePath}`,
15876
- hint: "LSP servers are auto-detected based on file type."
15877
- }, null, 2);
15878
- }
15879
- return JSON.stringify({
15880
- success: true,
15881
- message: `Go to definition at ${filePath}:${line}:${character}`,
15882
- server: lsp.serverId,
15883
- operation: "textDocument/definition"
15884
- }, null, 2);
15885
- }
15886
- });
15887
- var lspFindReferencesTool = tool({
15888
- description: "Find all references to a symbol using LSP. Shows all places where a symbol is used or defined.",
15889
- args: {
15890
- filePath: tool.schema.string().describe("Path to the file containing the symbol"),
15891
- line: tool.schema.number().describe("Line number (1-based)"),
15892
- character: tool.schema.number().describe("Character position (0-based)")
16255
+ rust: {
16256
+ extensions: ["rs"],
16257
+ primary: {
16258
+ command: "rustup",
16259
+ args: ["component", "add", "rust-analyzer"],
16260
+ verifyCommand: "rust-analyzer --version"
16261
+ },
16262
+ alternatives: []
15893
16263
  },
15894
- async execute({ filePath, line, character }) {
15895
- const lsp = await getLspConnection(filePath);
15896
- if (!lsp) {
15897
- return JSON.stringify({
15898
- success: false,
15899
- error: `No LSP server available for file: ${filePath}`,
15900
- hint: "LSP servers are auto-detected based on file type."
15901
- }, null, 2);
15902
- }
15903
- return JSON.stringify({
15904
- success: true,
15905
- message: `Find references at ${filePath}:${line}:${character}`,
15906
- server: lsp.serverId,
15907
- operation: "textDocument/references",
15908
- references: []
16264
+ go: {
16265
+ extensions: ["go"],
16266
+ primary: {
16267
+ command: "go",
16268
+ args: ["install", "golang.org/x/tools/gopls@latest"],
16269
+ verifyCommand: "gopls version"
16270
+ },
16271
+ alternatives: []
16272
+ },
16273
+ java: {
16274
+ extensions: ["java"],
16275
+ primary: {
16276
+ command: "sdk",
16277
+ args: ["install", "java", "21.0.3-tem"],
16278
+ verifyCommand: "jdtls --version"
16279
+ },
16280
+ alternatives: []
16281
+ },
16282
+ cpp: {
16283
+ extensions: ["cpp", "cc", "cxx", "c", "h", "hpp", "hh"],
16284
+ primary: {
16285
+ command: "apt",
16286
+ args: ["install", "clangd"],
16287
+ verifyCommand: "clangd --version"
16288
+ },
16289
+ alternatives: [
16290
+ {
16291
+ command: "apt",
16292
+ args: ["install", "ccls"],
16293
+ verifyCommand: "ccls --version"
16294
+ }
16295
+ ]
16296
+ },
16297
+ csharp: {
16298
+ extensions: ["cs"],
16299
+ primary: {
16300
+ command: "dotnet",
16301
+ args: ["tool", "install", "--global", "OmniSharp"],
16302
+ verifyCommand: "omniSharp --version"
16303
+ },
16304
+ alternatives: []
16305
+ },
16306
+ ruby: {
16307
+ extensions: ["rb"],
16308
+ primary: {
16309
+ command: "gem",
16310
+ args: ["install", "solargraph"],
16311
+ verifyCommand: "solargraph --version"
16312
+ },
16313
+ alternatives: []
16314
+ },
16315
+ php: {
16316
+ extensions: ["php"],
16317
+ primary: {
16318
+ command: "composer",
16319
+ args: ["global", "require", "phpactor/phpactor"],
16320
+ verifyCommand: "phpactor --version"
16321
+ },
16322
+ alternatives: []
16323
+ },
16324
+ vue: {
16325
+ extensions: ["vue"],
16326
+ primary: {
16327
+ command: "npm",
16328
+ args: ["install", "-g", "volar"],
16329
+ verifyCommand: "volar-server --version"
16330
+ },
16331
+ alternatives: []
16332
+ },
16333
+ svelte: {
16334
+ extensions: ["svelte"],
16335
+ primary: {
16336
+ command: "npm",
16337
+ args: ["install", "-g", "svelte-language-server"],
16338
+ verifyCommand: "svelte-language-server --version"
16339
+ },
16340
+ alternatives: []
16341
+ }
16342
+ };
16343
+ function getLanguageFromPath(filePath) {
16344
+ const ext = path2.extname(filePath).slice(1).toLowerCase();
16345
+ for (const [lang, config2] of Object.entries(LSP_DATABASE)) {
16346
+ if (config2.extensions.includes(ext)) {
16347
+ return lang;
16348
+ }
16349
+ }
16350
+ return null;
16351
+ }
16352
+ async function checkLspServer(config2) {
16353
+ const cmd = config2.verifyCommand || `${config2.command} --version`;
16354
+ try {
16355
+ execSync(cmd, { stdio: "ignore", timeout: 5000 });
16356
+ return true;
16357
+ } catch {
16358
+ return false;
16359
+ }
16360
+ }
16361
+ async function ensureLspInstalled(language) {
16362
+ const config2 = LSP_DATABASE[language];
16363
+ if (!config2) {
16364
+ return {
16365
+ success: false,
16366
+ installed: null,
16367
+ error: `No LSP configuration for language: ${language}`
16368
+ };
16369
+ }
16370
+ if (await checkLspServer(config2.primary)) {
16371
+ return { success: true, installed: config2.primary.command };
16372
+ }
16373
+ try {
16374
+ console.log(`[lsp] Installing ${language} LSP: ${config2.primary.command} ${config2.primary.args.join(" ")}`);
16375
+ execSync(`${config2.primary.command} ${config2.primary.args.join(" ")}`, {
16376
+ stdio: "inherit",
16377
+ timeout: 120000
16378
+ });
16379
+ if (await checkLspServer(config2.primary)) {
16380
+ return { success: true, installed: config2.primary.command };
16381
+ }
16382
+ } catch (error45) {
16383
+ console.warn(`[lsp] Primary installation failed: ${error45.message}`);
16384
+ }
16385
+ for (const alt of config2.alternatives) {
16386
+ try {
16387
+ console.log(`[lsp] Trying alternative: ${alt.command} ${alt.args.join(" ")}`);
16388
+ execSync(`${alt.command} ${alt.args.join(" ")}`, {
16389
+ stdio: "inherit",
16390
+ timeout: 120000
16391
+ });
16392
+ if (await checkLspServer(alt)) {
16393
+ return { success: true, installed: alt.command };
16394
+ }
16395
+ } catch (error45) {
16396
+ console.warn(`[lsp] Alternative installation failed: ${error45.message}`);
16397
+ }
16398
+ }
16399
+ return {
16400
+ success: false,
16401
+ installed: null,
16402
+ error: `Failed to install LSP for ${language}. Tried: ${config2.primary.command} and ${config2.alternatives.map((a) => a.command).join(", ")}`
16403
+ };
16404
+ }
16405
+ async function getLspStatus(filePath) {
16406
+ if (filePath) {
16407
+ const lang = getLanguageFromPath(filePath);
16408
+ if (!lang) {
16409
+ return {
16410
+ language: "unknown",
16411
+ installed: false,
16412
+ primary: null,
16413
+ alternatives: [],
16414
+ canInstall: false
16415
+ };
16416
+ }
16417
+ const config2 = LSP_DATABASE[lang];
16418
+ return {
16419
+ language: lang,
16420
+ installed: await checkLspServer(config2.primary),
16421
+ primary: config2.primary.command,
16422
+ alternatives: config2.alternatives.map((a) => a.command),
16423
+ canInstall: config2.alternatives.length > 0 || true
16424
+ };
16425
+ }
16426
+ const statuses = [];
16427
+ for (const lang of Object.keys(LSP_DATABASE)) {
16428
+ const config2 = LSP_DATABASE[lang];
16429
+ statuses.push({
16430
+ language: lang,
16431
+ installed: await checkLspServer(config2.primary),
16432
+ primary: config2.primary.command,
16433
+ alternatives: config2.alternatives.map((a) => a.command),
16434
+ canInstall: config2.alternatives.length > 0 || true
16435
+ });
16436
+ }
16437
+ return statuses;
16438
+ }
16439
+
16440
+ class LspManager {
16441
+ connections = new Map;
16442
+ async checkAndInstall(filePath) {
16443
+ const lang = getLanguageFromPath(filePath);
16444
+ if (!lang) {
16445
+ return {
16446
+ language: "unknown",
16447
+ ready: false,
16448
+ installed: false,
16449
+ message: `Unsupported file type. LSP not available.`
16450
+ };
16451
+ }
16452
+ const config2 = LSP_DATABASE[lang];
16453
+ if (!config2) {
16454
+ return {
16455
+ language: lang,
16456
+ ready: false,
16457
+ installed: false,
16458
+ message: `No LSP configuration for ${lang}.`
16459
+ };
16460
+ }
16461
+ const isInstalled = await checkLspServer(config2.primary);
16462
+ if (isInstalled) {
16463
+ return {
16464
+ language: lang,
16465
+ ready: true,
16466
+ installed: true,
16467
+ message: `${lang} LSP ready (${config2.primary.command})`
16468
+ };
16469
+ }
16470
+ const result = await ensureLspInstalled(lang);
16471
+ return {
16472
+ language: lang,
16473
+ ready: result.success,
16474
+ installed: result.success,
16475
+ message: result.success ? `${lang} LSP installed successfully` : result.error || "Installation failed"
16476
+ };
16477
+ }
16478
+ getAvailableLanguages() {
16479
+ return Object.keys(LSP_DATABASE);
16480
+ }
16481
+ getLspInfo(filePath) {
16482
+ const lang = getLanguageFromPath(filePath);
16483
+ if (!lang)
16484
+ return null;
16485
+ const config2 = LSP_DATABASE[lang];
16486
+ return {
16487
+ language: lang,
16488
+ extensions: config2.extensions,
16489
+ primaryCommand: config2.primary.command,
16490
+ alternativeCommands: config2.alternatives.map((a) => a.command)
16491
+ };
16492
+ }
16493
+ }
16494
+ var lspManager = new LspManager;
16495
+
16496
+ // src/tools/lsp.ts
16497
+ var lspRenameTool = tool({
16498
+ description: `Rename a symbol across all files using LSP. Provides IDE-like rename refactoring.
16499
+
16500
+ **Features:**
16501
+ - Auto-installs LSP server if missing
16502
+ - Falls back to alternative LSPs automatically
16503
+ - Cross-file rename support
16504
+
16505
+ **Parameters:**
16506
+ - filePath: Path to the file containing the symbol
16507
+ - oldName: Current symbol name to rename
16508
+ - newName: New name for the symbol
16509
+
16510
+ **Example:**
16511
+ \`\`\`
16512
+ lsp_rename({ filePath: "src/utils.ts", oldName: "getUser", newName: "fetchUser" })
16513
+ \`\`\``,
16514
+ args: {
16515
+ filePath: tool.schema.string().describe("Path to the file containing the symbol"),
16516
+ oldName: tool.schema.string().describe("Current name of the symbol to rename"),
16517
+ newName: tool.schema.string().describe("New name for the symbol")
16518
+ },
16519
+ async execute({ filePath, oldName, newName }) {
16520
+ const lang = getLanguageFromPath(filePath);
16521
+ if (!lang) {
16522
+ return JSON.stringify({
16523
+ success: false,
16524
+ error: `Unsupported file type: ${filePath}`,
16525
+ hint: "LSP requires a supported programming language file"
16526
+ }, null, 2);
16527
+ }
16528
+ const status = await lspManager.checkAndInstall(filePath);
16529
+ if (!status.ready) {
16530
+ return JSON.stringify({
16531
+ success: false,
16532
+ language: status.language,
16533
+ error: status.message,
16534
+ autoInstallFailed: true,
16535
+ alternatives: await getLspStatus(filePath),
16536
+ hint: "LSP server not available. Consider using ast_grep_rewrite_code for pattern-based renaming."
16537
+ }, null, 2);
16538
+ }
16539
+ return JSON.stringify({
16540
+ success: true,
16541
+ message: `Rename "${oldName}" to "${newName}" in ${filePath}`,
16542
+ language: status.language,
16543
+ operation: "textDocument/rename",
16544
+ oldName,
16545
+ newName,
16546
+ filePath
16547
+ }, null, 2);
16548
+ }
16549
+ });
16550
+ var lspGotoDefinitionTool = tool({
16551
+ description: `Navigate to the definition of a symbol using LSP.
16552
+
16553
+ **Features:**
16554
+ - Auto-installs LSP server if missing
16555
+ - Jump from usage to definition
16556
+ - Supports all LSP-capable languages
16557
+
16558
+ **Parameters:**
16559
+ - filePath: Path to the file containing the symbol
16560
+ - line: Line number (1-based)
16561
+ - character: Character position (0-based)`,
16562
+ args: {
16563
+ filePath: tool.schema.string().describe("Path to the file containing the symbol"),
16564
+ line: tool.schema.number().describe("Line number (1-based)"),
16565
+ character: tool.schema.number().describe("Character position (0-based)")
16566
+ },
16567
+ async execute({ filePath, line, character }) {
16568
+ const lang = getLanguageFromPath(filePath);
16569
+ if (!lang) {
16570
+ return JSON.stringify({
16571
+ success: false,
16572
+ error: `Unsupported file type: ${filePath}`
16573
+ }, null, 2);
16574
+ }
16575
+ const status = await lspManager.checkAndInstall(filePath);
16576
+ if (!status.ready) {
16577
+ return JSON.stringify({
16578
+ success: false,
16579
+ language: status.language,
16580
+ error: status.message,
16581
+ alternatives: await getLspStatus(filePath)
16582
+ }, null, 2);
16583
+ }
16584
+ return JSON.stringify({
16585
+ success: true,
16586
+ message: `Go to definition at ${filePath}:${line}:${character}`,
16587
+ language: status.language,
16588
+ operation: "textDocument/definition",
16589
+ location: { filePath, line, character }
16590
+ }, null, 2);
16591
+ }
16592
+ });
16593
+ var lspFindReferencesTool = tool({
16594
+ description: `Find all references to a symbol using LSP.
16595
+
16596
+ **Features:**
16597
+ - Auto-installs LSP server if missing
16598
+ - Returns all usages across the codebase
16599
+ - Shows both definitions and references`,
16600
+ args: {
16601
+ filePath: tool.schema.string().describe("Path to the file containing the symbol"),
16602
+ line: tool.schema.number().describe("Line number (1-based)"),
16603
+ character: tool.schema.number().describe("Character position (0-based)")
16604
+ },
16605
+ async execute({ filePath, line, character }) {
16606
+ const lang = getLanguageFromPath(filePath);
16607
+ if (!lang) {
16608
+ return JSON.stringify({
16609
+ success: false,
16610
+ error: `Unsupported file type: ${filePath}`
16611
+ }, null, 2);
16612
+ }
16613
+ const status = await lspManager.checkAndInstall(filePath);
16614
+ if (!status.ready) {
16615
+ return JSON.stringify({
16616
+ success: false,
16617
+ language: status.language,
16618
+ error: status.message,
16619
+ alternatives: await getLspStatus(filePath)
16620
+ }, null, 2);
16621
+ }
16622
+ return JSON.stringify({
16623
+ success: true,
16624
+ message: `Find references at ${filePath}:${line}:${character}`,
16625
+ language: status.language,
16626
+ operation: "textDocument/references",
16627
+ location: { filePath, line, character },
16628
+ references: []
15909
16629
  }, null, 2);
15910
16630
  }
15911
16631
  });
15912
16632
  var lspDiagnosticsTool = tool({
15913
- description: "Get diagnostics (errors, warnings, info) for a file using LSP. Shows language-level issues.",
16633
+ description: `Get diagnostics (errors, warnings, info) for a file using LSP.
16634
+
16635
+ **Features:**
16636
+ - Auto-installs LSP server if missing
16637
+ - Shows language-level issues
16638
+ - Filterable by severity
16639
+
16640
+ **Parameters:**
16641
+ - filePath: Path to the file to check
16642
+ - severity: Minimum severity level (error, warning, info, hint, all)`,
15914
16643
  args: {
15915
16644
  filePath: tool.schema.string().describe("Path to the file to check for diagnostics"),
15916
16645
  severity: tool.schema.enum(["error", "warning", "information", "hint", "all"]).optional().default("all").describe("Minimum severity level to return")
15917
16646
  },
15918
16647
  async execute({ filePath, severity }) {
15919
- const lsp = await getLspConnection(filePath);
15920
- if (!lsp) {
16648
+ const lang = getLanguageFromPath(filePath);
16649
+ if (!lang) {
16650
+ return JSON.stringify({
16651
+ success: false,
16652
+ error: `Unsupported file type: ${filePath}`
16653
+ }, null, 2);
16654
+ }
16655
+ const status = await lspManager.checkAndInstall(filePath);
16656
+ if (!status.ready) {
15921
16657
  return JSON.stringify({
15922
16658
  success: false,
15923
- error: `No LSP server available for file: ${filePath}`,
15924
- hint: "LSP servers are auto-detected based on file type."
16659
+ language: status.language,
16660
+ error: status.message,
16661
+ alternatives: await getLspStatus(filePath)
15925
16662
  }, null, 2);
15926
16663
  }
15927
16664
  return JSON.stringify({
15928
16665
  success: true,
15929
16666
  message: `Get diagnostics for ${filePath}`,
15930
- server: lsp.serverId,
16667
+ language: status.language,
15931
16668
  operation: "textDocument/diagnostic",
15932
16669
  severity,
15933
16670
  diagnostics: []
@@ -15935,54 +16672,168 @@ var lspDiagnosticsTool = tool({
15935
16672
  }
15936
16673
  });
15937
16674
  var lspHoverTool = tool({
15938
- description: "Get hover information for a symbol using LSP. Shows type information and documentation.",
16675
+ description: `Get hover information for a symbol using LSP.
16676
+
16677
+ **Features:**
16678
+ - Auto-installs LSP server if missing
16679
+ - Shows type information and documentation
16680
+ - Quick access to symbol details`,
15939
16681
  args: {
15940
16682
  filePath: tool.schema.string().describe("Path to the file containing the symbol"),
15941
16683
  line: tool.schema.number().describe("Line number (1-based)"),
15942
16684
  character: tool.schema.number().describe("Character position (0-based)")
15943
16685
  },
15944
16686
  async execute({ filePath, line, character }) {
15945
- const lsp = await getLspConnection(filePath);
15946
- if (!lsp) {
16687
+ const lang = getLanguageFromPath(filePath);
16688
+ if (!lang) {
16689
+ return JSON.stringify({
16690
+ success: false,
16691
+ error: `Unsupported file type: ${filePath}`
16692
+ }, null, 2);
16693
+ }
16694
+ const status = await lspManager.checkAndInstall(filePath);
16695
+ if (!status.ready) {
15947
16696
  return JSON.stringify({
15948
16697
  success: false,
15949
- error: `No LSP server available for file: ${filePath}`,
15950
- hint: "LSP servers are auto-detected based on file type."
16698
+ language: status.language,
16699
+ error: status.message,
16700
+ alternatives: await getLspStatus(filePath)
15951
16701
  }, null, 2);
15952
16702
  }
15953
16703
  return JSON.stringify({
15954
16704
  success: true,
15955
16705
  message: `Get hover info at ${filePath}:${line}:${character}`,
15956
- server: lsp.serverId,
15957
- operation: "textDocument/hover"
16706
+ language: status.language,
16707
+ operation: "textDocument/hover",
16708
+ location: { filePath, line, character }
15958
16709
  }, null, 2);
15959
16710
  }
15960
16711
  });
15961
16712
  var lspCodeActionsTool = tool({
15962
- description: "Get available code actions using LSP. Shows quick fixes and refactorings.",
16713
+ description: `Get available code actions using LSP.
16714
+
16715
+ **Features:**
16716
+ - Auto-installs LSP server if missing
16717
+ - Shows quick fixes and refactorings
16718
+ - Suggests code improvements`,
15963
16719
  args: {
15964
16720
  filePath: tool.schema.string().describe("Path to the file"),
15965
16721
  line: tool.schema.number().describe("Line number (1-based)"),
15966
16722
  character: tool.schema.number().describe("Character position (0-based)")
15967
16723
  },
15968
16724
  async execute({ filePath, line, character }) {
15969
- const lsp = await getLspConnection(filePath);
15970
- if (!lsp) {
16725
+ const lang = getLanguageFromPath(filePath);
16726
+ if (!lang) {
16727
+ return JSON.stringify({
16728
+ success: false,
16729
+ error: `Unsupported file type: ${filePath}`
16730
+ }, null, 2);
16731
+ }
16732
+ const status = await lspManager.checkAndInstall(filePath);
16733
+ if (!status.ready) {
15971
16734
  return JSON.stringify({
15972
16735
  success: false,
15973
- error: `No LSP server available for file: ${filePath}`,
15974
- hint: "LSP servers are auto-detected based on file type."
16736
+ language: status.language,
16737
+ error: status.message,
16738
+ alternatives: await getLspStatus(filePath)
15975
16739
  }, null, 2);
15976
16740
  }
15977
16741
  return JSON.stringify({
15978
16742
  success: true,
15979
16743
  message: `Get code actions at ${filePath}:${line}:${character}`,
15980
- server: lsp.serverId,
16744
+ language: status.language,
15981
16745
  operation: "textDocument/codeAction",
16746
+ location: { filePath, line, character },
15982
16747
  actions: []
15983
16748
  }, null, 2);
15984
16749
  }
15985
16750
  });
16751
+ var lspStatusTool = tool({
16752
+ description: `Check LSP server status and install missing servers.
16753
+
16754
+ **Features:**
16755
+ - Shows installed LSP servers
16756
+ - Auto-installs missing servers
16757
+ - Supports multiple LSP servers per language
16758
+
16759
+ **Parameters:**
16760
+ - filePath: Optional file path to check specific language
16761
+ - install: Set to true to auto-install missing servers
16762
+
16763
+ **Example:**
16764
+ \`\`\`
16765
+ lsp_status({ filePath: "src/index.ts" })
16766
+ lsp_status({ install: true })
16767
+ \`\`\``,
16768
+ args: {
16769
+ filePath: tool.schema.string().optional().describe("Optional file path to check specific language"),
16770
+ install: tool.schema.boolean().optional().default(false).describe("Auto-install missing LSP servers")
16771
+ },
16772
+ async execute({ filePath, install }) {
16773
+ if (filePath) {
16774
+ const lang = getLanguageFromPath(filePath);
16775
+ if (!lang) {
16776
+ return JSON.stringify({
16777
+ success: false,
16778
+ error: `Unsupported file type: ${filePath}`,
16779
+ supportedLanguages: lspManager.getAvailableLanguages()
16780
+ }, null, 2);
16781
+ }
16782
+ const status = await lspManager.checkAndInstall(filePath);
16783
+ if (install && !status.ready) {
16784
+ const result = await ensureLspInstalled(lang);
16785
+ return JSON.stringify({
16786
+ ...result,
16787
+ language: lang,
16788
+ installAttempted: true
16789
+ }, null, 2);
16790
+ }
16791
+ return JSON.stringify({
16792
+ success: status.ready,
16793
+ language: status.language,
16794
+ installed: status.installed,
16795
+ ready: status.ready,
16796
+ message: status.message,
16797
+ info: lspManager.getLspInfo(filePath)
16798
+ }, null, 2);
16799
+ }
16800
+ const allStatuses = await getLspStatus();
16801
+ return JSON.stringify({
16802
+ success: true,
16803
+ languages: allStatuses,
16804
+ totalLanguages: allStatuses.length,
16805
+ installedCount: allStatuses.filter((s) => s.installed).length
16806
+ }, null, 2);
16807
+ }
16808
+ });
16809
+ var lspInstallTool = tool({
16810
+ description: `Install LSP server for a specific language.
16811
+
16812
+ **Features:**
16813
+ - Installs primary LSP server
16814
+ - Falls back to alternatives if primary fails
16815
+ - Shows installation progress
16816
+
16817
+ **Parameters:**
16818
+ - language: Language to install LSP for (e.g., "typescript", "python", "rust")
16819
+
16820
+ **Example:**
16821
+ \`\`\`
16822
+ lsp_install({ language: "typescript" })
16823
+ lsp_install({ language: "python" })
16824
+ \`\`\``,
16825
+ args: {
16826
+ language: tool.schema.string().describe("Language to install LSP for")
16827
+ },
16828
+ async execute({ language }) {
16829
+ const result = await ensureLspInstalled(language.toLowerCase());
16830
+ return JSON.stringify({
16831
+ ...result,
16832
+ language,
16833
+ installationMethod: result.success ? "auto" : "failed"
16834
+ }, null, 2);
16835
+ }
16836
+ });
15986
16837
 
15987
16838
  // src/tools/skill-mcp.ts
15988
16839
  function getSkillMcpConfig(skill) {
@@ -16066,16 +16917,16 @@ mcp:
16066
16917
 
16067
16918
  // src/tools/memory.ts
16068
16919
  import * as fs2 from "fs";
16069
- import * as path2 from "path";
16920
+ import * as path3 from "path";
16070
16921
  import * as os from "os";
16071
16922
  function getGlobalMemoryDir() {
16072
- return path2.join(os.homedir(), ".config", "opencode", "hive", "memory", "global");
16923
+ return path3.join(os.homedir(), ".config", "opencode", "hive", "memory", "global");
16073
16924
  }
16074
16925
  function getProjectMemoryDir(projectRoot) {
16075
- return path2.join(projectRoot, ".hive", "memory", "project");
16926
+ return path3.join(projectRoot, ".hive", "memory", "project");
16076
16927
  }
16077
16928
  function getJournalDir() {
16078
- return path2.join(os.homedir(), ".config", "opencode", "hive", "journal");
16929
+ return path3.join(os.homedir(), ".config", "opencode", "hive", "journal");
16079
16930
  }
16080
16931
  function parseFrontmatter2(content) {
16081
16932
  if (!content.startsWith(`---
@@ -16132,7 +16983,7 @@ ${lines.join(`
16132
16983
  function readMemoryBlock(filePath, scope) {
16133
16984
  const content = fs2.readFileSync(filePath, "utf-8");
16134
16985
  const { frontmatter, body } = parseFrontmatter2(content);
16135
- const label = frontmatter.label || path2.basename(filePath, path2.extname(filePath));
16986
+ const label = frontmatter.label || path3.basename(filePath, path3.extname(filePath));
16136
16987
  const description = frontmatter.description || "Memory block";
16137
16988
  const limit = frontmatter.limit || 5000;
16138
16989
  const readOnly = frontmatter.read_only === true;
@@ -16157,7 +17008,7 @@ function listMemoryBlocks(scope, projectRoot) {
16157
17008
  const blocks = [];
16158
17009
  for (const file2 of fs2.readdirSync(dir)) {
16159
17010
  if (file2.endsWith(".md")) {
16160
- const filePath = path2.join(dir, file2);
17011
+ const filePath = path3.join(dir, file2);
16161
17012
  try {
16162
17013
  blocks.push(readMemoryBlock(filePath, scope));
16163
17014
  } catch {}
@@ -16181,7 +17032,7 @@ async function ensureMemorySeeded(projectRoot) {
16181
17032
  for (const seed of SEED_BLOCKS) {
16182
17033
  const dir = seed.scope === "global" ? getGlobalMemoryDir() : getProjectMemoryDir(projectRoot);
16183
17034
  fs2.mkdirSync(dir, { recursive: true });
16184
- const filePath = path2.join(dir, `${seed.label}.md`);
17035
+ const filePath = path3.join(dir, `${seed.label}.md`);
16185
17036
  if (!fs2.existsSync(filePath)) {
16186
17037
  const content = buildFrontmatter({
16187
17038
  label: seed.label,
@@ -16199,7 +17050,7 @@ function writeJournalEntry(title, body, project, tags = []) {
16199
17050
  fs2.mkdirSync(journalDir, { recursive: true });
16200
17051
  const now = new Date;
16201
17052
  const id2 = `${now.getUTCFullYear()}${String(now.getUTCMonth() + 1).padStart(2, "0")}${String(now.getUTCDate()).padStart(2, "0")}-${String(now.getUTCHours()).padStart(2, "0")}${String(now.getUTCMinutes()).padStart(2, "0")}${String(now.getUTCSeconds()).padStart(2, "0")}-${String(now.getUTCMilliseconds()).padStart(3, "0")}`;
16202
- const filePath = path2.join(journalDir, `${id2}.md`);
17053
+ const filePath = path3.join(journalDir, `${id2}.md`);
16203
17054
  const frontmatter = buildFrontmatter({
16204
17055
  title,
16205
17056
  project: project || "",
@@ -16226,7 +17077,7 @@ function searchJournalEntries(query, project, limit = 20) {
16226
17077
  const entries = [];
16227
17078
  const files = fs2.readdirSync(journalDir).filter((f) => f.endsWith(".md")).sort().reverse();
16228
17079
  for (const file2 of files) {
16229
- const filePath = path2.join(journalDir, file2);
17080
+ const filePath = path3.join(journalDir, file2);
16230
17081
  const content = fs2.readFileSync(filePath, "utf-8");
16231
17082
  const { frontmatter, body } = parseFrontmatter2(content);
16232
17083
  const entry = {
@@ -16324,7 +17175,7 @@ var hiveMemorySetTool = tool({
16324
17175
  }
16325
17176
  const dir = scope === "global" ? getGlobalMemoryDir() : getProjectMemoryDir(projectRoot);
16326
17177
  fs2.mkdirSync(dir, { recursive: true });
16327
- const filePath = path2.join(dir, `${label}.md`);
17178
+ const filePath = path3.join(dir, `${label}.md`);
16328
17179
  if (fs2.existsSync(filePath)) {
16329
17180
  const existing = readMemoryBlock(filePath, scope);
16330
17181
  if (existing.readOnly) {
@@ -16362,7 +17213,7 @@ var hiveMemoryReplaceTool = tool({
16362
17213
  async execute({ scope, label, oldText, newText }) {
16363
17214
  const projectRoot = process.cwd();
16364
17215
  const dir = scope === "global" ? getGlobalMemoryDir() : getProjectMemoryDir(projectRoot);
16365
- const filePath = path2.join(dir, `${label}.md`);
17216
+ const filePath = path3.join(dir, `${label}.md`);
16366
17217
  if (!fs2.existsSync(filePath)) {
16367
17218
  return JSON.stringify({
16368
17219
  success: false,
@@ -16486,10 +17337,10 @@ async function buildMemoryInjection(projectRoot) {
16486
17337
  `);
16487
17338
  }
16488
17339
  function getTypedMemoryDir() {
16489
- return path2.join(os.homedir(), ".config", "opencode", "hive", "typed-memory");
17340
+ return path3.join(os.homedir(), ".config", "opencode", "hive", "typed-memory");
16490
17341
  }
16491
17342
  function getDeletionsFile() {
16492
- return path2.join(getTypedMemoryDir(), "deletions.logfmt");
17343
+ return path3.join(getTypedMemoryDir(), "deletions.logfmt");
16493
17344
  }
16494
17345
  function parseTypedMemoryLine(line) {
16495
17346
  const tsMatch = line.match(/ts=([^\s]+)/);
@@ -16545,7 +17396,7 @@ async function getAllTypedMemories() {
16545
17396
  for (const filename of files) {
16546
17397
  if (filename === "deletions.logfmt")
16547
17398
  continue;
16548
- const filepath = path2.join(dir, filename);
17399
+ const filepath = path3.join(dir, filename);
16549
17400
  const text = fs2.readFileSync(filepath, "utf-8");
16550
17401
  lines.push(...text.trim().split(`
16551
17402
  `).filter(Boolean));
@@ -16561,7 +17412,7 @@ async function findTypedMemories(scope, type, query) {
16561
17412
  for (const filename of files) {
16562
17413
  if (filename === "deletions.logfmt")
16563
17414
  continue;
16564
- const filepath = path2.join(dir, filename);
17415
+ const filepath = path3.join(dir, filename);
16565
17416
  const text = fs2.readFileSync(filepath, "utf-8");
16566
17417
  const lines = text.split(`
16567
17418
  `);
@@ -16749,7 +17600,7 @@ var hiveMemoryForgetTool = tool({
16749
17600
 
16750
17601
  // src/tools/agent-booster.ts
16751
17602
  import * as fs3 from "fs";
16752
- import * as path3 from "path";
17603
+ import * as path4 from "path";
16753
17604
  var boosterInstance = null;
16754
17605
  var boosterInitPromise = null;
16755
17606
  async function initBooster() {
@@ -16907,7 +17758,7 @@ var hiveCodeEditTool = tool({
16907
17758
  newContent: tool.schema.string().describe("Replacement text")
16908
17759
  },
16909
17760
  async execute({ path: filePath, oldContent, newContent }) {
16910
- const resolvedPath = path3.isAbsolute(filePath) ? filePath : path3.join(process.cwd(), filePath);
17761
+ const resolvedPath = path4.isAbsolute(filePath) ? filePath : path4.join(process.cwd(), filePath);
16911
17762
  const result = await applyCodeEdit({
16912
17763
  path: resolvedPath,
16913
17764
  oldContent,
@@ -16948,7 +17799,7 @@ const newFunction = () => { ... };
16948
17799
  snippet: tool.schema.string().describe("Code snippet with // ... existing code ... markers")
16949
17800
  },
16950
17801
  async execute({ path: filePath, snippet }) {
16951
- const resolvedPath = path3.isAbsolute(filePath) ? filePath : path3.join(process.cwd(), filePath);
17802
+ const resolvedPath = path4.isAbsolute(filePath) ? filePath : path4.join(process.cwd(), filePath);
16952
17803
  const available = await isBoosterAvailable();
16953
17804
  if (!available) {
16954
17805
  return JSON.stringify({
@@ -17006,7 +17857,7 @@ var hiveBoosterStatusTool = tool({
17006
17857
 
17007
17858
  // src/services/vector-memory.ts
17008
17859
  import * as fs4 from "fs";
17009
- import * as path4 from "path";
17860
+ import * as path5 from "path";
17010
17861
  import * as os2 from "os";
17011
17862
  var memoryInstance = null;
17012
17863
  var memoryInitPromise = null;
@@ -17021,7 +17872,7 @@ async function initMemory(options) {
17021
17872
  memoryInitPromise = (async () => {
17022
17873
  try {
17023
17874
  const memory = (()=>{throw new Error("Cannot require module "+"@sparkleideas/memory");})();
17024
- const indexPath = options?.indexPath || path4.join(os2.homedir(), ".config", "opencode", "hive", "vector-index");
17875
+ const indexPath = options?.indexPath || path5.join(os2.homedir(), ".config", "opencode", "hive", "vector-index");
17025
17876
  const dimensions = options?.dimensions || 384;
17026
17877
  fs4.mkdirSync(indexPath, { recursive: true });
17027
17878
  if (typeof memory.init === "function") {
@@ -17125,7 +17976,7 @@ async function getMemoryStatus() {
17125
17976
  };
17126
17977
  }
17127
17978
  function getFallbackDir() {
17128
- return path4.join(os2.homedir(), ".config", "opencode", "hive", "vector-memory", "fallback");
17979
+ return path5.join(os2.homedir(), ".config", "opencode", "hive", "vector-memory", "fallback");
17129
17980
  }
17130
17981
  function ensureFallbackDir() {
17131
17982
  const dir = getFallbackDir();
@@ -17146,7 +17997,7 @@ async function addMemoryFallback(content, metadata) {
17146
17997
  createdAt: new Date().toISOString(),
17147
17998
  updatedAt: new Date().toISOString()
17148
17999
  };
17149
- const filePath = path4.join(getFallbackDir(), `${id2}.json`);
18000
+ const filePath = path5.join(getFallbackDir(), `${id2}.json`);
17150
18001
  fs4.writeFileSync(filePath, JSON.stringify(entry, null, 2), "utf-8");
17151
18002
  return { id: id2, success: true, fallback: true };
17152
18003
  }
@@ -17158,7 +18009,7 @@ async function searchMemoriesFallback(query, options) {
17158
18009
  const files = fs4.readdirSync(getFallbackDir()).filter((f) => f.endsWith(".json"));
17159
18010
  for (const file2 of files) {
17160
18011
  try {
17161
- const content = fs4.readFileSync(path4.join(getFallbackDir(), file2), "utf-8");
18012
+ const content = fs4.readFileSync(path5.join(getFallbackDir(), file2), "utf-8");
17162
18013
  const entry = JSON.parse(content);
17163
18014
  if (type && entry.metadata.type !== type)
17164
18015
  continue;
@@ -17193,7 +18044,7 @@ async function searchMemoriesFallback(query, options) {
17193
18044
  };
17194
18045
  }
17195
18046
  async function getMemoryFallback(id2) {
17196
- const filePath = path4.join(getFallbackDir(), `${id2}.json`);
18047
+ const filePath = path5.join(getFallbackDir(), `${id2}.json`);
17197
18048
  if (!fs4.existsSync(filePath)) {
17198
18049
  return null;
17199
18050
  }
@@ -17205,154 +18056,1315 @@ async function getMemoryFallback(id2) {
17205
18056
  }
17206
18057
  }
17207
18058
  async function deleteMemoryFallback(id2) {
17208
- const filePath = path4.join(getFallbackDir(), `${id2}.json`);
18059
+ const filePath = path5.join(getFallbackDir(), `${id2}.json`);
17209
18060
  if (!fs4.existsSync(filePath)) {
17210
18061
  return false;
17211
18062
  }
17212
18063
  try {
17213
- fs4.unlinkSync(filePath);
17214
- return true;
18064
+ fs4.unlinkSync(filePath);
18065
+ return true;
18066
+ } catch {
18067
+ return false;
18068
+ }
18069
+ }
18070
+ function getFallbackStats() {
18071
+ ensureFallbackDir();
18072
+ const stats = { total: 0, byType: {} };
18073
+ const files = fs4.readdirSync(getFallbackDir()).filter((f) => f.endsWith(".json"));
18074
+ for (const file2 of files) {
18075
+ try {
18076
+ const content = fs4.readFileSync(path5.join(getFallbackDir(), file2), "utf-8");
18077
+ const entry = JSON.parse(content);
18078
+ stats.total++;
18079
+ const type = entry.metadata.type || "unknown";
18080
+ stats.byType[type] = (stats.byType[type] || 0) + 1;
18081
+ } catch {}
18082
+ }
18083
+ return stats;
18084
+ }
18085
+ var VectorMemoryService = {
18086
+ init: initMemory,
18087
+ add: addMemory,
18088
+ search: searchMemories,
18089
+ get: getMemory,
18090
+ delete: deleteMemory,
18091
+ status: getMemoryStatus
18092
+ };
18093
+
18094
+ // src/tools/vector-memory.ts
18095
+ var hiveVectorSearchTool = tool({
18096
+ description: `Semantic memory search using vector embeddings.
18097
+
18098
+ **Features:**
18099
+ - HNSW indexing for fast similarity search
18100
+ - Semantic matching (finds conceptually similar content)
18101
+ - Filter by type and scope
18102
+ - Fallback to text search if vector unavailable
18103
+
18104
+ **Types:**
18105
+ - decision: Architectural decisions, design choices
18106
+ - learning: Insights, discoveries, patterns found
18107
+ - preference: User preferences, coding style
18108
+ - blocker: Known blockers, workarounds
18109
+ - context: Important context about the project
18110
+ - pattern: Code patterns, recurring solutions`,
18111
+ args: {
18112
+ query: tool.schema.string().describe("Search query (semantic or keyword)"),
18113
+ type: tool.schema.enum(["decision", "learning", "preference", "blocker", "context", "pattern"]).optional().describe("Filter by memory type"),
18114
+ scope: tool.schema.string().optional().describe("Filter by scope (e.g., auth, api, ui)"),
18115
+ limit: tool.schema.number().optional().describe("Maximum results (default: 10)")
18116
+ },
18117
+ async execute({ query, type, scope, limit = 10 }) {
18118
+ const result = await VectorMemoryService.search(query, {
18119
+ limit,
18120
+ type,
18121
+ scope
18122
+ });
18123
+ if (result.results.length === 0) {
18124
+ return JSON.stringify({
18125
+ message: "No matching memories found",
18126
+ query,
18127
+ fallback: result.fallback || false,
18128
+ tips: [
18129
+ "Try different keywords",
18130
+ "Use broader search terms",
18131
+ "Create memories with hive_memory_set first"
18132
+ ]
18133
+ }, null, 2);
18134
+ }
18135
+ return JSON.stringify({
18136
+ total: result.results.length,
18137
+ query,
18138
+ fallback: result.fallback || false,
18139
+ results: result.results.map((r) => ({
18140
+ id: r.id,
18141
+ content: r.content,
18142
+ score: Math.round(r.score * 100) / 100,
18143
+ type: r.metadata.type,
18144
+ scope: r.metadata.scope,
18145
+ tags: r.metadata.tags
18146
+ }))
18147
+ }, null, 2);
18148
+ }
18149
+ });
18150
+ var hiveVectorAddTool = tool({
18151
+ description: `Add a memory with semantic indexing for future search.
18152
+
18153
+ **Metadata:**
18154
+ - type: Categorize the memory
18155
+ - scope: Project area or component
18156
+ - tags: Additional categorization
18157
+
18158
+ **Example:**
18159
+ \`\`\`
18160
+ Content: "Use async/await instead of .then() chains"
18161
+ Type: learning
18162
+ Scope: async-patterns
18163
+ Tags: javascript, promises, best-practice
18164
+ \`\`\``,
18165
+ args: {
18166
+ content: tool.schema.string().describe("Memory content to store"),
18167
+ type: tool.schema.enum(["decision", "learning", "preference", "blocker", "context", "pattern"]).optional().describe("Memory type"),
18168
+ scope: tool.schema.string().optional().describe("Scope (e.g., auth, api, ui)"),
18169
+ tags: tool.schema.array(tool.schema.string()).optional().describe("Tags for categorization")
18170
+ },
18171
+ async execute({ content, type, scope, tags }) {
18172
+ const metadata = {};
18173
+ if (type)
18174
+ metadata.type = type;
18175
+ if (scope)
18176
+ metadata.scope = scope;
18177
+ if (tags)
18178
+ metadata.tags = tags;
18179
+ const result = await VectorMemoryService.add(content, metadata);
18180
+ return JSON.stringify({
18181
+ success: result.success,
18182
+ id: result.id,
18183
+ fallback: result.fallback || false,
18184
+ message: `Memory stored${result.fallback ? " (text search mode)" : " (vector indexed)"}`
18185
+ }, null, 2);
18186
+ }
18187
+ });
18188
+ var hiveVectorStatusTool = tool({
18189
+ description: `Check vector memory status and statistics.
18190
+
18191
+ **Returns:**
18192
+ - available: Whether @sparkleideas/memory is working
18193
+ - type: vector or fallback
18194
+ - stats: Memory counts by type`,
18195
+ args: {},
18196
+ async execute() {
18197
+ const status = await VectorMemoryService.status();
18198
+ return JSON.stringify({
18199
+ status: status.available ? "ready" : "fallback",
18200
+ type: status.type,
18201
+ backend: status.available ? "@sparkleideas/memory (HNSW + Vector)" : "Simple text search",
18202
+ stats: status.stats,
18203
+ tips: status.available ? [] : [
18204
+ "Install @sparkleideas/memory for vector search",
18205
+ "npm install @sparkleideas/memory"
18206
+ ]
18207
+ }, null, 2);
18208
+ }
18209
+ });
18210
+
18211
+ // src/tools/ast-grep-native.ts
18212
+ 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;
18230
+ }
18231
+ })();
18232
+ await astGrepInitPromise;
18233
+ }
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
+ }
18262
+ 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
+ };
18308
+ };
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"
18414
+ };
18415
+ const lang = language ? langMap[language.toLowerCase()] || language : "TypeScript";
18416
+ const Lang = astGrepModule.Lang;
18417
+ if (!Lang[lang]) {
18418
+ return JSON.stringify({
18419
+ success: false,
18420
+ error: `Unsupported language: ${language}`
18421
+ }, null, 2);
18422
+ }
18423
+ const findInFiles = astGrepModule.findInFiles;
18424
+ const results = [];
18425
+ await findInFiles(Lang[lang], {
18426
+ paths: [project_folder],
18427
+ matcher: { rule: { pattern } }
18428
+ }, (err, node) => {
18429
+ if (err) {
18430
+ console.warn("[ast-grep] Search error:", err);
18431
+ return;
18432
+ }
18433
+ if (node) {
18434
+ const text = node.text();
18435
+ const range = node.range();
18436
+ results.push({
18437
+ file: node.filename() || "unknown",
18438
+ line: range ? range.start.index : 0,
18439
+ column: range ? range.start.column : 0,
18440
+ matched: text.slice(0, 100)
18441
+ });
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
+ }
18455
+ }
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
+ }
18691
+ function checkOptimizations() {
18692
+ const checks3 = [];
18693
+ const configPaths = [
18694
+ path6.join(process.env.HOME || "", ".config/opencode/agent_hive.json"),
18695
+ path6.join(process.env.HOME || "", ".config/opencode/agent_hive.jsonc")
18696
+ ];
18697
+ let config2 = null;
18698
+ for (const configPath of configPaths) {
18699
+ if (fs6.existsSync(configPath)) {
18700
+ try {
18701
+ const content = fs6.readFileSync(configPath, "utf-8");
18702
+ config2 = JSON.parse(content.replace(/\\/g, ""));
18703
+ break;
18704
+ } catch {}
18705
+ }
18706
+ }
18707
+ const snipConfig = config2?.snip;
18708
+ checks3.push({
18709
+ name: "snip",
18710
+ enabled: snipConfig?.enabled === true,
18711
+ recommendation: !snipConfig?.enabled ? "Enable snip in config for 60-90% token reduction on shell output" : undefined
18712
+ });
18713
+ const vectorConfig = config2?.vectorMemory;
18714
+ checks3.push({
18715
+ name: "vectorMemory",
18716
+ enabled: vectorConfig?.enabled === true,
18717
+ recommendation: !vectorConfig?.enabled ? "Enable vector memory for semantic search across memories" : undefined
18718
+ });
18719
+ const boosterConfig = config2?.agentBooster;
18720
+ checks3.push({
18721
+ name: "agentBooster",
18722
+ enabled: boosterConfig?.enabled !== false,
18723
+ recommendation: boosterConfig?.enabled === false ? "Enable agent booster for 52x faster code editing" : undefined
18724
+ });
18725
+ const sandboxConfig = config2?.sandbox;
18726
+ checks3.push({
18727
+ name: "sandbox",
18728
+ enabled: sandboxConfig !== "none",
18729
+ recommendation: sandboxConfig === "none" ? "Enable Docker sandbox for isolated test environments" : undefined
18730
+ });
18731
+ const disabledMcps = config2?.disableMcps || [];
18732
+ const hasAstGrep = !disabledMcps.includes("ast_grep");
18733
+ checks3.push({
18734
+ name: "nativeAstGrep",
18735
+ enabled: hasAstGrep,
18736
+ recommendation: !hasAstGrep ? "Enable native ast-grep for fast AST analysis" : undefined
18737
+ });
18738
+ const hasPareSearch = !disabledMcps.includes("pare_search");
18739
+ checks3.push({
18740
+ name: "pareSearch",
18741
+ enabled: hasPareSearch,
18742
+ recommendation: !hasPareSearch ? "Enable pare_search for structured ripgrep output (65-95% token reduction)" : undefined
18743
+ });
18744
+ return checks3;
18745
+ }
18746
+ function generateRecommendations(dependencies, optimizations) {
18747
+ const recommendations = [];
18748
+ const missingRequired = dependencies.filter((d) => d.required && !d.installed);
18749
+ if (missingRequired.length > 0) {
18750
+ recommendations.push(`Missing required packages: ${missingRequired.map((d) => d.name).join(", ")}`);
18751
+ }
18752
+ const disabledOptimizations = optimizations.filter((o) => !o.enabled && o.recommendation);
18753
+ for (const opt of disabledOptimizations) {
18754
+ if (opt.recommendation) {
18755
+ recommendations.push(opt.recommendation);
18756
+ }
18757
+ }
18758
+ if (recommendations.length === 0) {
18759
+ recommendations.push("System is optimized! No immediate actions needed.");
18760
+ }
18761
+ return recommendations;
18762
+ }
18763
+ function generateQuickFixes(dependencies, optimizations) {
18764
+ const fixes = [];
18765
+ const missingPackages = dependencies.filter((d) => !d.installed && !d.required);
18766
+ for (const pkg of missingPackages) {
18767
+ fixes.push({
18768
+ command: `npm install ${pkg.package}`,
18769
+ description: `Install ${pkg.name}`
18770
+ });
18771
+ }
18772
+ if (optimizations.find((o) => o.name === "snip" && !o.enabled)) {
18773
+ fixes.push({
18774
+ command: 'Add to ~/.config/opencode/agent_hive.json: { "snip": { "enabled": true } }',
18775
+ description: "Enable snip for token reduction"
18776
+ });
18777
+ }
18778
+ if (optimizations.find((o) => o.name === "vectorMemory" && !o.enabled)) {
18779
+ fixes.push({
18780
+ command: 'Add to ~/.config/opencode/agent_hive.json: { "vectorMemory": { "enabled": true } }',
18781
+ description: "Enable vector memory for semantic search"
18782
+ });
18783
+ }
18784
+ return fixes;
18785
+ }
18786
+ function calculateStatus(dependencies, optimizations) {
18787
+ const missingRequired = dependencies.filter((d) => d.required && !d.installed);
18788
+ if (missingRequired.length > 0) {
18789
+ return "issues";
18790
+ }
18791
+ const disabledCount = optimizations.filter((o) => !o.enabled).length;
18792
+ if (disabledCount > 2) {
18793
+ return "warning";
18794
+ }
18795
+ return "healthy";
18796
+ }
18797
+ var hiveDoctorTool = tool({
18798
+ description: `Hive Doctor - System health check and optimization advisor.
18799
+
18800
+ **What it checks:**
18801
+ 1. Dependencies - Optional packages installed and working
18802
+ 2. Optimizations - Features enabled in config
18803
+ 3. Recommendations - Suggestions for improvements
18804
+
18805
+ **Use when:**
18806
+ - Setting up Hive for the first time
18807
+ - Troubleshooting issues
18808
+ - Optimizing performance
18809
+ - Checking if new features are available
18810
+
18811
+ **Example output:**
18812
+ - healthy: All checks pass
18813
+ - warning: Some optimizations disabled
18814
+ - issues: Missing required packages`,
18815
+ args: {},
18816
+ async execute() {
18817
+ const dependencyChecks = [
18818
+ { name: "agent-booster", package: "@sparkleideas/agent-booster", required: false },
18819
+ { name: "vector-memory", package: "@sparkleideas/memory", required: false },
18820
+ { name: "ast-grep NAPI", package: "@ast-grep/napi", required: false },
18821
+ { name: "pare-search", package: "@paretools/search", required: false },
18822
+ { name: "context7", package: "@upstash/context7-mcp", required: false },
18823
+ { name: "Exa search", package: "exa-mcp-server", required: false }
18824
+ ];
18825
+ for (const dep of dependencyChecks) {
18826
+ const result2 = await checkPackage(dep.package);
18827
+ dep.installed = result2.installed;
18828
+ dep.version = result2.version;
18829
+ }
18830
+ const optimizationChecks = checkOptimizations();
18831
+ const recommendations = generateRecommendations(dependencyChecks, optimizationChecks);
18832
+ const quickFixes = generateQuickFixes(dependencyChecks, optimizationChecks);
18833
+ const status = calculateStatus(dependencyChecks, optimizationChecks);
18834
+ const result = {
18835
+ status,
18836
+ timestamp: new Date().toISOString(),
18837
+ checks: {
18838
+ dependencies: {
18839
+ total: dependencyChecks.length,
18840
+ installed: dependencyChecks.filter((d) => d.installed).length,
18841
+ packages: dependencyChecks
18842
+ },
18843
+ optimizations: {
18844
+ total: optimizationChecks.length,
18845
+ enabled: optimizationChecks.filter((o) => o.enabled).length,
18846
+ features: optimizationChecks
18847
+ }
18848
+ },
18849
+ recommendations,
18850
+ quickFixes
18851
+ };
18852
+ return JSON.stringify(result, null, 2);
18853
+ }
18854
+ });
18855
+ var hiveDoctorQuickTool = tool({
18856
+ description: `Quick health check - shows status summary only.
18857
+
18858
+ **Returns:**
18859
+ - healthy: All systems go
18860
+ - warning: Some optimizations disabled
18861
+ - issues: Action required`,
18862
+ args: {},
18863
+ async execute() {
18864
+ const keyPackages = [
18865
+ "@ast-grep/napi",
18866
+ "@sparkleideas/agent-booster",
18867
+ "@paretools/search"
18868
+ ];
18869
+ const results = {};
18870
+ let healthy = true;
18871
+ for (const pkg of keyPackages) {
18872
+ const result = await checkPackage(pkg);
18873
+ results[pkg] = result.installed;
18874
+ if (!result.installed) {
18875
+ healthy = false;
18876
+ }
18877
+ }
18878
+ return JSON.stringify({
18879
+ status: healthy ? "healthy" : "warning",
18880
+ packages: results,
18881
+ runFullCheck: "Use hive_doctor for detailed analysis"
18882
+ }, null, 2);
18883
+ }
18884
+ });
18885
+
18886
+ // src/tools/dora.ts
18887
+ import { execSync as execSync2 } from "child_process";
18888
+ function checkDoraStatus() {
18889
+ try {
18890
+ const output = execSync2("dora --version", { encoding: "utf-8" });
18891
+ const version2 = output.trim();
18892
+ const indexExists = __require("fs").existsSync(".dora/dora.db");
18893
+ return { installed: true, version: version2, indexed: indexExists };
18894
+ } catch {
18895
+ return { installed: false, indexed: false };
18896
+ }
18897
+ }
18898
+ function runDoraCommand(args2) {
18899
+ try {
18900
+ const output = execSync2(`dora ${args2.join(" ")}`, {
18901
+ encoding: "utf-8",
18902
+ maxBuffer: 10 * 1024 * 1024
18903
+ });
18904
+ return { success: true, output };
18905
+ } catch (error45) {
18906
+ return { success: false, error: error45.message || "Command failed" };
18907
+ }
18908
+ }
18909
+ var doraStatusTool = tool({
18910
+ description: `Check dora installation status and index state.
18911
+
18912
+ **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\`
18921
+
18922
+ **Note:** Indexing is required once per codebase. After that, dora works instantly.`,
18923
+ args: {},
18924
+ async execute() {
18925
+ const status = checkDoraStatus();
18926
+ if (!status.installed) {
18927
+ return JSON.stringify({
18928
+ status: "not_installed",
18929
+ message: "Dora CLI not found",
18930
+ installation: {
18931
+ step1: "bun install -g @butttons/dora",
18932
+ step2: "npm install -g @sourcegraph/scip-typescript",
18933
+ step3: "dora init && dora index"
18934
+ }
18935
+ }, null, 2);
18936
+ }
18937
+ if (!status.indexed) {
18938
+ return JSON.stringify({
18939
+ status: "not_indexed",
18940
+ version: status.version,
18941
+ message: "Codebase not indexed",
18942
+ nextStep: "Run: dora init && dora index"
18943
+ }, null, 2);
18944
+ }
18945
+ return JSON.stringify({
18946
+ status: "ready",
18947
+ version: status.version,
18948
+ indexed: true,
18949
+ message: "Dora is ready"
18950
+ }, null, 2);
18951
+ }
18952
+ });
18953
+ var doraSymbolTool = tool({
18954
+ description: `Find symbol definitions using dora (SCIP-based).
18955
+
18956
+ **Parameters:**
18957
+ - name: Symbol name to search for
18958
+ - kind: Filter by symbol kind (function, class, method, etc.)
18959
+
18960
+ **Example:**
18961
+ \`\`\`
18962
+ dora_symbol({ name: "getUserById" })
18963
+ \`\`\`
18964
+
18965
+ **Note:** Requires dora to be installed and indexed.`,
18966
+ 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.)")
18969
+ },
18970
+ async execute({ name, kind }) {
18971
+ const status = checkDoraStatus();
18972
+ if (!status.installed || !status.indexed) {
18973
+ return JSON.stringify({
18974
+ success: false,
18975
+ error: "Dora not ready. Run dora_status first.",
18976
+ hint: "Install and index: dora init && dora index"
18977
+ }, null, 2);
18978
+ }
18979
+ const args2 = ["symbol", name];
18980
+ if (kind) {
18981
+ args2.push("--kind", kind);
18982
+ }
18983
+ const result = runDoraCommand(args2);
18984
+ if (!result.success) {
18985
+ return JSON.stringify({
18986
+ success: false,
18987
+ error: result.error,
18988
+ hint: "Symbol may not exist or not indexed"
18989
+ }, null, 2);
18990
+ }
18991
+ return JSON.stringify({
18992
+ success: true,
18993
+ symbol: name,
18994
+ output: result.output
18995
+ }, null, 2);
18996
+ }
18997
+ });
18998
+ var doraFileTool = tool({
18999
+ description: `Get file dependencies and information using dora.
19000
+
19001
+ **Parameters:**
19002
+ - path: File path to analyze
19003
+
19004
+ **Example:**
19005
+ \`\`\`
19006
+ dora_file({ path: "src/index.ts" })
19007
+ \`\`\`
19008
+
19009
+ **Returns:** File metadata, exports, and dependencies.`,
19010
+ args: {
19011
+ path: tool.schema.string().describe("File path to analyze")
19012
+ },
19013
+ async execute({ path: path7 }) {
19014
+ const status = checkDoraStatus();
19015
+ if (!status.installed || !status.indexed) {
19016
+ return JSON.stringify({
19017
+ success: false,
19018
+ error: "Dora not ready. Run dora_status first."
19019
+ }, null, 2);
19020
+ }
19021
+ const result = runDoraCommand(["file", path7]);
19022
+ if (!result.success) {
19023
+ return JSON.stringify({
19024
+ success: false,
19025
+ error: result.error,
19026
+ hint: "File may not exist or not indexed"
19027
+ }, null, 2);
19028
+ }
19029
+ return JSON.stringify({
19030
+ success: true,
19031
+ path: path7,
19032
+ output: result.output
19033
+ }, null, 2);
19034
+ }
19035
+ });
19036
+ var doraReferencesTool = tool({
19037
+ description: `Find all references to a symbol using dora.
19038
+
19039
+ **Parameters:**
19040
+ - name: Symbol name to find references for
19041
+
19042
+ **Example:**
19043
+ \`\`\`
19044
+ dora_references({ name: "UserService" })
19045
+ \`\`\`
19046
+
19047
+ **Note:** Returns all usages across the codebase.`,
19048
+ args: {
19049
+ name: tool.schema.string().describe("Symbol name to find references for")
19050
+ },
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) {
19061
+ return JSON.stringify({
19062
+ success: false,
19063
+ error: result.error
19064
+ }, null, 2);
19065
+ }
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) {
19086
+ return JSON.stringify({
19087
+ success: false,
19088
+ error: "Dora not ready. Run dora_status first."
19089
+ }, null, 2);
19090
+ }
19091
+ const result = runDoraCommand(["cycles"]);
19092
+ if (!result.success) {
19093
+ return JSON.stringify({
19094
+ success: false,
19095
+ error: result.error
19096
+ }, null, 2);
19097
+ }
19098
+ return JSON.stringify({
19099
+ success: true,
19100
+ cycles: result.output
19101
+ }, null, 2);
19102
+ }
19103
+ });
19104
+ var doraUnusedTool = tool({
19105
+ description: `Find unused/dead code in the codebase using dora.
19106
+
19107
+ **Example:**
19108
+ \`\`\`
19109
+ dora_unused()
19110
+ \`\`\`
19111
+
19112
+ **Returns:** List of symbols with zero references.`,
19113
+ args: {},
19114
+ async execute() {
19115
+ const status = checkDoraStatus();
19116
+ if (!status.installed || !status.indexed) {
19117
+ return JSON.stringify({
19118
+ success: false,
19119
+ error: "Dora not ready. Run dora_status first."
19120
+ }, null, 2);
19121
+ }
19122
+ const result = runDoraCommand(["unused"]);
19123
+ if (!result.success) {
19124
+ return JSON.stringify({
19125
+ success: false,
19126
+ error: result.error
19127
+ }, 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 };
17215
19144
  } catch {
17216
- return false;
19145
+ return { installed: false };
17217
19146
  }
17218
19147
  }
17219
- function getFallbackStats() {
17220
- ensureFallbackDir();
17221
- const stats = { total: 0, byType: {} };
17222
- const files = fs4.readdirSync(getFallbackDir()).filter((f) => f.endsWith(".json"));
17223
- for (const file2 of files) {
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
+ });
17224
19155
  try {
17225
- const content = fs4.readFileSync(path4.join(getFallbackDir(), file2), "utf-8");
17226
- const entry = JSON.parse(content);
17227
- stats.total++;
17228
- const type = entry.metadata.type || "unknown";
17229
- stats.byType[type] = (stats.byType[type] || 0) + 1;
17230
- } catch {}
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
+ }
17231
19171
  }
17232
- return stats;
17233
19172
  }
17234
- var VectorMemoryService = {
17235
- init: initMemory,
17236
- add: addMemory,
17237
- search: searchMemories,
17238
- get: getMemory,
17239
- delete: deleteMemory,
17240
- status: getMemoryStatus
17241
- };
19173
+ var autoCrStatusTool = tool({
19174
+ description: `Check auto-cr-cmd installation status.
17242
19175
 
17243
- // src/tools/vector-memory.ts
17244
- var hiveVectorSearchTool = tool({
17245
- description: `Semantic memory search using vector embeddings.
19176
+ **Returns:**
19177
+ - installed: Whether auto-cr-cmd is available
19178
+ - version: Auto-CR version
19179
+ - ready: Whether it's ready to scan
17246
19180
 
17247
- **Features:**
17248
- - HNSW indexing for fast similarity search
17249
- - Semantic matching (finds conceptually similar content)
17250
- - Filter by type and scope
17251
- - Fallback to text search if vector unavailable
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) {
19191
+ return JSON.stringify({
19192
+ status: "not_installed",
19193
+ message: "auto-cr-cmd not found",
19194
+ installation: "npm install auto-cr-cmd"
19195
+ }, null, 2);
19196
+ }
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
+ }
19211
+ });
19212
+ var autoCrScanTool = tool({
19213
+ description: `Scan directory for code issues using auto-cr (SWC-based static analysis).
17252
19214
 
17253
- **Types:**
17254
- - decision: Architectural decisions, design choices
17255
- - learning: Insights, discoveries, patterns found
17256
- - preference: User preferences, coding style
17257
- - blocker: Known blockers, workarounds
17258
- - context: Important context about the project
17259
- - pattern: Code patterns, recurring solutions`,
19215
+ **Parameters:**
19216
+ - path: Directory path to scan (defaults to ./src)
19217
+ - language: Output language (en/zh, defaults to en)
19218
+
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
19226
+
19227
+ **Example:**
19228
+ \`\`\`
19229
+ auto_cr_scan({ path: "./src" })
19230
+ \`\`\``,
17260
19231
  args: {
17261
- query: tool.schema.string().describe("Search query (semantic or keyword)"),
17262
- type: tool.schema.enum(["decision", "learning", "preference", "blocker", "context", "pattern"]).optional().describe("Filter by memory type"),
17263
- scope: tool.schema.string().optional().describe("Filter by scope (e.g., auth, api, ui)"),
17264
- limit: tool.schema.number().optional().describe("Maximum results (default: 10)")
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)")
17265
19234
  },
17266
- async execute({ query, type, scope, limit = 10 }) {
17267
- const result = await VectorMemoryService.search(query, {
17268
- limit,
17269
- type,
17270
- scope
17271
- });
17272
- if (result.results.length === 0) {
19235
+ async execute({ path: path7, language }) {
19236
+ const status = checkAutoCrStatus();
19237
+ if (!status.installed) {
17273
19238
  return JSON.stringify({
17274
- message: "No matching memories found",
17275
- query,
17276
- fallback: result.fallback || false,
17277
- tips: [
17278
- "Try different keywords",
17279
- "Use broader search terms",
17280
- "Create memories with hive_memory_set first"
17281
- ]
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)) {
19245
+ return JSON.stringify({
19246
+ success: false,
19247
+ error: `Path not found: ${path7}`
19248
+ }, null, 2);
19249
+ }
19250
+ const result = runAutoCr(["--language", language, path7]);
19251
+ if (!result.success && !result.json) {
19252
+ return JSON.stringify({
19253
+ success: false,
19254
+ error: result.error || "Scan failed"
19255
+ }, null, 2);
19256
+ }
19257
+ if (result.json) {
19258
+ const { summary, files, notifications } = result.json;
19259
+ 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 || []
17282
19281
  }, null, 2);
17283
19282
  }
17284
19283
  return JSON.stringify({
17285
- total: result.results.length,
17286
- query,
17287
- fallback: result.fallback || false,
17288
- results: result.results.map((r) => ({
17289
- id: r.id,
17290
- content: r.content,
17291
- score: Math.round(r.score * 100) / 100,
17292
- type: r.metadata.type,
17293
- scope: r.metadata.scope,
17294
- tags: r.metadata.tags
17295
- }))
19284
+ success: true,
19285
+ scanned: path7,
19286
+ rawOutput: result.output
17296
19287
  }, null, 2);
17297
19288
  }
17298
19289
  });
17299
- var hiveVectorAddTool = tool({
17300
- description: `Add a memory with semantic indexing for future search.
19290
+ var autoCrDiffTool = tool({
19291
+ description: `Scan git diff output for code issues using auto-cr.
17301
19292
 
17302
- **Metadata:**
17303
- - type: Categorize the memory
17304
- - scope: Project area or component
17305
- - tags: Additional categorization
19293
+ **Use case:** Run in CI to check only changed files.
17306
19294
 
17307
19295
  **Example:**
19296
+ \`\`\`bash
19297
+ git diff --name-only -z | xargs -0 auto-cr-cmd --stdin --output json
17308
19298
  \`\`\`
17309
- Content: "Use async/await instead of .then() chains"
17310
- Type: learning
17311
- Scope: async-patterns
17312
- Tags: javascript, promises, best-practice
17313
- \`\`\``,
19299
+
19300
+ **Note:** This tool requires git diff output piped via stdin.`,
17314
19301
  args: {
17315
- content: tool.schema.string().describe("Memory content to store"),
17316
- type: tool.schema.enum(["decision", "learning", "preference", "blocker", "context", "pattern"]).optional().describe("Memory type"),
17317
- scope: tool.schema.string().optional().describe("Scope (e.g., auth, api, ui)"),
17318
- tags: tool.schema.array(tool.schema.string()).optional().describe("Tags for categorization")
19302
+ language: tool.schema.string().optional().default("en").describe("Output language (en or zh)")
17319
19303
  },
17320
- async execute({ content, type, scope, tags }) {
17321
- const metadata = {};
17322
- if (type)
17323
- metadata.type = type;
17324
- if (scope)
17325
- metadata.scope = scope;
17326
- if (tags)
17327
- metadata.tags = tags;
17328
- const result = await VectorMemoryService.add(content, metadata);
19304
+ async execute({ language }) {
19305
+ const status = checkAutoCrStatus();
19306
+ if (!status.installed) {
19307
+ return JSON.stringify({
19308
+ success: false,
19309
+ error: "auto-cr-cmd not installed",
19310
+ hint: "npm install auto-cr-cmd"
19311
+ }, null, 2);
19312
+ }
17329
19313
  return JSON.stringify({
17330
- success: result.success,
17331
- id: result.id,
17332
- fallback: result.fallback || false,
17333
- message: `Memory stored${result.fallback ? " (text search mode)" : " (vector indexed)"}`
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"
17334
19317
  }, null, 2);
17335
19318
  }
17336
19319
  });
17337
- var hiveVectorStatusTool = tool({
17338
- description: `Check vector memory status and statistics.
19320
+ var autoCrRulesTool = tool({
19321
+ description: `List available auto-cr rules and their descriptions.
17339
19322
 
17340
- **Returns:**
17341
- - available: Whether @sparkleideas/memory is working
17342
- - type: vector or fallback
17343
- - stats: Memory counts by type`,
19323
+ **Returns:** All built-in rules with descriptions.`,
17344
19324
  args: {},
17345
19325
  async execute() {
17346
- const status = await VectorMemoryService.status();
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"
19362
+ }
19363
+ ];
17347
19364
  return JSON.stringify({
17348
- status: status.available ? "ready" : "fallback",
17349
- type: status.type,
17350
- backend: status.available ? "@sparkleideas/memory (HNSW + Vector)" : "Simple text search",
17351
- stats: status.stats,
17352
- tips: status.available ? [] : [
17353
- "Install @sparkleideas/memory for vector search",
17354
- "npm install @sparkleideas/memory"
17355
- ]
19365
+ success: true,
19366
+ rules,
19367
+ totalRules: rules.length
17356
19368
  }, null, 2);
17357
19369
  }
17358
19370
  });
@@ -18690,12 +20702,26 @@ var astGrepMcp = {
18690
20702
  command: ["npx", "-y", "@notprolands/ast-grep-mcp"]
18691
20703
  };
18692
20704
 
20705
+ // src/mcp/pare-search.ts
20706
+ var pareSearchMcp = {
20707
+ type: "local",
20708
+ command: ["npx", "-y", "@paretools/search"]
20709
+ };
20710
+
20711
+ // src/mcp/veil.ts
20712
+ var veilMcp = {
20713
+ type: "local",
20714
+ command: ["npx", "-y", "@ushiradineth/veil@latest", "mcp", "server"]
20715
+ };
20716
+
18693
20717
  // src/mcp/index.ts
18694
20718
  var allBuiltinMcps = {
18695
20719
  websearch: websearchMcp,
18696
20720
  context7: context7Mcp,
18697
20721
  grep_app: grepAppMcp,
18698
- ast_grep: astGrepMcp
20722
+ ast_grep: astGrepMcp,
20723
+ pare_search: pareSearchMcp,
20724
+ veil: veilMcp
18699
20725
  };
18700
20726
  var createBuiltinMcps = (disabledMcps = []) => {
18701
20727
  const disabled = new Set(disabledMcps);
@@ -18704,30 +20730,30 @@ var createBuiltinMcps = (disabledMcps = []) => {
18704
20730
 
18705
20731
  // ../hive-core/dist/index.js
18706
20732
  import { createRequire as createRequire2 } from "node:module";
18707
- import * as path5 from "path";
20733
+ import * as path7 from "path";
18708
20734
  import * as os3 from "os";
18709
20735
  import * as path22 from "path";
18710
- import * as fs5 from "fs";
20736
+ import * as fs8 from "fs";
18711
20737
  import * as path32 from "path";
18712
20738
  import * as fs22 from "fs";
18713
20739
  import * as fs32 from "fs";
18714
20740
  import * as fs42 from "fs";
18715
20741
  import * as fs52 from "fs";
18716
- import * as fs7 from "fs/promises";
20742
+ import * as fs72 from "fs/promises";
18717
20743
  import * as path42 from "path";
18718
20744
  import { Buffer as Buffer2 } from "node:buffer";
18719
- import { spawn } from "child_process";
20745
+ import { spawn as spawn2 } from "child_process";
18720
20746
  import { normalize } from "node:path";
18721
20747
  import { EventEmitter } from "node:events";
18722
- import * as fs8 from "fs";
20748
+ import * as fs82 from "fs";
18723
20749
  import * as path52 from "path";
18724
20750
  import * as fs10 from "fs";
18725
- import * as path7 from "path";
20751
+ import * as path72 from "path";
18726
20752
  import * as fs11 from "fs";
18727
20753
  import * as path8 from "path";
18728
20754
  import { existsSync as existsSync52 } from "fs";
18729
20755
  import { join as join92, sep } from "path";
18730
- import { execSync } from "child_process";
20756
+ import { execSync as execSync4 } from "child_process";
18731
20757
  var __create2 = Object.create;
18732
20758
  var __getProtoOf2 = Object.getPrototypeOf;
18733
20759
  var __defProp2 = Object.defineProperty;
@@ -19579,9 +21605,10 @@ var DEFAULT_HIVE_CONFIG = {
19579
21605
  },
19580
21606
  vectorMemory: {
19581
21607
  enabled: false,
19582
- indexPath: path5.join(os3.homedir(), ".config", "opencode", "hive", "vector-index"),
21608
+ indexPath: path7.join(os3.homedir(), ".config", "opencode", "hive", "vector-index"),
19583
21609
  dimensions: 384
19584
- }
21610
+ },
21611
+ autoInstallDeps: true
19585
21612
  };
19586
21613
  var HIVE_DIR = ".hive";
19587
21614
  var FEATURES_DIR = "features";
@@ -19653,22 +21680,22 @@ function getSubtaskReportPath(projectRoot, featureName, taskFolder, subtaskFolde
19653
21680
  return path22.join(getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder), REPORT_FILE);
19654
21681
  }
19655
21682
  function ensureDir(dirPath) {
19656
- if (!fs5.existsSync(dirPath)) {
19657
- fs5.mkdirSync(dirPath, { recursive: true });
21683
+ if (!fs8.existsSync(dirPath)) {
21684
+ fs8.mkdirSync(dirPath, { recursive: true });
19658
21685
  }
19659
21686
  }
19660
21687
  function fileExists(filePath) {
19661
- return fs5.existsSync(filePath);
21688
+ return fs8.existsSync(filePath);
19662
21689
  }
19663
21690
  function readJson(filePath) {
19664
- if (!fs5.existsSync(filePath))
21691
+ if (!fs8.existsSync(filePath))
19665
21692
  return null;
19666
- const content = fs5.readFileSync(filePath, "utf-8");
21693
+ const content = fs8.readFileSync(filePath, "utf-8");
19667
21694
  return JSON.parse(content);
19668
21695
  }
19669
21696
  function writeJson(filePath, data) {
19670
21697
  ensureDir(path22.dirname(filePath));
19671
- fs5.writeFileSync(filePath, JSON.stringify(data, null, 2));
21698
+ fs8.writeFileSync(filePath, JSON.stringify(data, null, 2));
19672
21699
  }
19673
21700
  var DEFAULT_LOCK_OPTIONS = {
19674
21701
  timeout: 5000,
@@ -19680,7 +21707,7 @@ function getLockPath(filePath) {
19680
21707
  }
19681
21708
  function isLockStale(lockPath, staleTTL) {
19682
21709
  try {
19683
- const stat2 = fs5.statSync(lockPath);
21710
+ const stat2 = fs8.statSync(lockPath);
19684
21711
  const age = Date.now() - stat2.mtimeMs;
19685
21712
  return age > staleTTL;
19686
21713
  } catch {
@@ -19700,12 +21727,12 @@ function acquireLockSync(filePath, options = {}) {
19700
21727
  ensureDir(lockDir);
19701
21728
  while (true) {
19702
21729
  try {
19703
- const fd = fs5.openSync(lockPath, fs5.constants.O_CREAT | fs5.constants.O_EXCL | fs5.constants.O_WRONLY);
19704
- fs5.writeSync(fd, lockContent);
19705
- fs5.closeSync(fd);
21730
+ const fd = fs8.openSync(lockPath, fs8.constants.O_CREAT | fs8.constants.O_EXCL | fs8.constants.O_WRONLY);
21731
+ fs8.writeSync(fd, lockContent);
21732
+ fs8.closeSync(fd);
19706
21733
  return () => {
19707
21734
  try {
19708
- fs5.unlinkSync(lockPath);
21735
+ fs8.unlinkSync(lockPath);
19709
21736
  } catch {}
19710
21737
  };
19711
21738
  } catch (err) {
@@ -19715,7 +21742,7 @@ function acquireLockSync(filePath, options = {}) {
19715
21742
  } else if (error45.code === "EEXIST") {
19716
21743
  if (isLockStale(lockPath, opts.staleLockTTL)) {
19717
21744
  try {
19718
- fs5.unlinkSync(lockPath);
21745
+ fs8.unlinkSync(lockPath);
19719
21746
  continue;
19720
21747
  } catch {}
19721
21748
  }
@@ -19734,11 +21761,11 @@ function writeAtomic(filePath, content) {
19734
21761
  ensureDir(path22.dirname(filePath));
19735
21762
  const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}`;
19736
21763
  try {
19737
- fs5.writeFileSync(tempPath, content);
19738
- fs5.renameSync(tempPath, filePath);
21764
+ fs8.writeFileSync(tempPath, content);
21765
+ fs8.renameSync(tempPath, filePath);
19739
21766
  } catch (error45) {
19740
21767
  try {
19741
- fs5.unlinkSync(tempPath);
21768
+ fs8.unlinkSync(tempPath);
19742
21769
  } catch {}
19743
21770
  throw error45;
19744
21771
  }
@@ -19773,13 +21800,13 @@ function patchJsonLockedSync(filePath, patch, options = {}) {
19773
21800
  }
19774
21801
  }
19775
21802
  function readText(filePath) {
19776
- if (!fs5.existsSync(filePath))
21803
+ if (!fs8.existsSync(filePath))
19777
21804
  return null;
19778
- return fs5.readFileSync(filePath, "utf-8");
21805
+ return fs8.readFileSync(filePath, "utf-8");
19779
21806
  }
19780
21807
  function writeText(filePath, content) {
19781
21808
  ensureDir(path22.dirname(filePath));
19782
- fs5.writeFileSync(filePath, content);
21809
+ fs8.writeFileSync(filePath, content);
19783
21810
  }
19784
21811
  function detectContext(cwd) {
19785
21812
  const result = {
@@ -21870,7 +23897,7 @@ var init_git_executor_chain = __esm2({
21870
23897
  rejection = reason || rejection;
21871
23898
  }
21872
23899
  });
21873
- const spawned = spawn(command, args2, spawnOptions);
23900
+ const spawned = spawn2(command, args2, spawnOptions);
21874
23901
  spawned.stdout.on("data", onDataReceived(stdOut, "stdOut", logger, outputLogger.step("stdOut")));
21875
23902
  spawned.stderr.on("data", onDataReceived(stdErr, "stdErr", logger, outputLogger.step("stdErr")));
21876
23903
  spawned.on("error", onErrorReceived(stdErr, logger));
@@ -24614,7 +26641,7 @@ class WorktreeService {
24614
26641
  const featurePath = path42.join(this.config.hiveDir, "features", feature);
24615
26642
  const tasksPath = path42.join(featurePath, "tasks", step, "status.json");
24616
26643
  try {
24617
- await fs7.access(tasksPath);
26644
+ await fs72.access(tasksPath);
24618
26645
  return tasksPath;
24619
26646
  } catch {}
24620
26647
  return path42.join(featurePath, "execution", step, "status.json");
@@ -24626,7 +26653,7 @@ class WorktreeService {
24626
26653
  const worktreePath = this.getWorktreePath(feature, step);
24627
26654
  const branchName = this.getBranchName(feature, step);
24628
26655
  const git = this.getGit();
24629
- await fs7.mkdir(path42.dirname(worktreePath), { recursive: true });
26656
+ await fs72.mkdir(path42.dirname(worktreePath), { recursive: true });
24630
26657
  const base = baseBranch || (await git.revparse(["HEAD"])).trim();
24631
26658
  const existing = await this.get(feature, step);
24632
26659
  if (existing) {
@@ -24655,7 +26682,7 @@ class WorktreeService {
24655
26682
  const worktreePath = this.getWorktreePath(feature, step);
24656
26683
  const branchName = this.getBranchName(feature, step);
24657
26684
  try {
24658
- await fs7.access(worktreePath);
26685
+ await fs72.access(worktreePath);
24659
26686
  const worktreeGit = this.getGit(worktreePath);
24660
26687
  const commit = (await worktreeGit.revparse(["HEAD"])).trim();
24661
26688
  return {
@@ -24675,7 +26702,7 @@ class WorktreeService {
24675
26702
  let base = baseCommit;
24676
26703
  if (!base) {
24677
26704
  try {
24678
- const status = JSON.parse(await fs7.readFile(statusPath, "utf-8"));
26705
+ const status = JSON.parse(await fs72.readFile(statusPath, "utf-8"));
24679
26706
  base = status.baseCommit;
24680
26707
  } catch {}
24681
26708
  }
@@ -24725,7 +26752,7 @@ class WorktreeService {
24725
26752
  const base = baseBranch || "HEAD~1";
24726
26753
  const worktreeGit = this.getGit(worktreePath);
24727
26754
  const diff = await worktreeGit.diff([`${base}...HEAD`]);
24728
- await fs7.writeFile(patchPath, diff);
26755
+ await fs72.writeFile(patchPath, diff);
24729
26756
  return patchPath;
24730
26757
  }
24731
26758
  async applyDiff(feature, step, baseBranch) {
@@ -24735,13 +26762,13 @@ class WorktreeService {
24735
26762
  }
24736
26763
  const patchPath = path42.join(this.config.hiveDir, ".worktrees", feature, `${step}.patch`);
24737
26764
  try {
24738
- await fs7.writeFile(patchPath, diffContent);
26765
+ await fs72.writeFile(patchPath, diffContent);
24739
26766
  const git = this.getGit();
24740
26767
  await git.applyPatch(patchPath);
24741
- await fs7.unlink(patchPath).catch(() => {});
26768
+ await fs72.unlink(patchPath).catch(() => {});
24742
26769
  return { success: true, filesAffected: filesChanged };
24743
26770
  } catch (error45) {
24744
- await fs7.unlink(patchPath).catch(() => {});
26771
+ await fs72.unlink(patchPath).catch(() => {});
24745
26772
  const err = error45;
24746
26773
  return {
24747
26774
  success: false,
@@ -24757,13 +26784,13 @@ class WorktreeService {
24757
26784
  }
24758
26785
  const patchPath = path42.join(this.config.hiveDir, ".worktrees", feature, `${step}.patch`);
24759
26786
  try {
24760
- await fs7.writeFile(patchPath, diffContent);
26787
+ await fs72.writeFile(patchPath, diffContent);
24761
26788
  const git = this.getGit();
24762
26789
  await git.applyPatch(patchPath, ["-R"]);
24763
- await fs7.unlink(patchPath).catch(() => {});
26790
+ await fs72.unlink(patchPath).catch(() => {});
24764
26791
  return { success: true, filesAffected: filesChanged };
24765
26792
  } catch (error45) {
24766
- await fs7.unlink(patchPath).catch(() => {});
26793
+ await fs72.unlink(patchPath).catch(() => {});
24767
26794
  const err = error45;
24768
26795
  return {
24769
26796
  success: false,
@@ -24782,7 +26809,7 @@ class WorktreeService {
24782
26809
  return [...new Set(files)];
24783
26810
  }
24784
26811
  async revertFromSavedDiff(diffPath) {
24785
- const diffContent = await fs7.readFile(diffPath, "utf-8");
26812
+ const diffContent = await fs72.readFile(diffPath, "utf-8");
24786
26813
  if (!diffContent.trim()) {
24787
26814
  return { success: true, filesAffected: [] };
24788
26815
  }
@@ -24807,7 +26834,7 @@ class WorktreeService {
24807
26834
  try {
24808
26835
  await git.raw(["worktree", "remove", worktreePath, "--force"]);
24809
26836
  } catch {
24810
- await fs7.rm(worktreePath, { recursive: true, force: true });
26837
+ await fs72.rm(worktreePath, { recursive: true, force: true });
24811
26838
  }
24812
26839
  try {
24813
26840
  await git.raw(["worktree", "prune"]);
@@ -24822,13 +26849,13 @@ class WorktreeService {
24822
26849
  const worktreesDir = this.getWorktreesDir();
24823
26850
  const results = [];
24824
26851
  try {
24825
- const features = feature ? [feature] : await fs7.readdir(worktreesDir);
26852
+ const features = feature ? [feature] : await fs72.readdir(worktreesDir);
24826
26853
  for (const feat of features) {
24827
26854
  const featurePath = path42.join(worktreesDir, feat);
24828
- const stat2 = await fs7.stat(featurePath).catch(() => null);
26855
+ const stat2 = await fs72.stat(featurePath).catch(() => null);
24829
26856
  if (!stat2?.isDirectory())
24830
26857
  continue;
24831
- const steps = await fs7.readdir(featurePath).catch(() => []);
26858
+ const steps = await fs72.readdir(featurePath).catch(() => []);
24832
26859
  for (const step of steps) {
24833
26860
  const info = await this.get(feat, step);
24834
26861
  if (info) {
@@ -24846,16 +26873,16 @@ class WorktreeService {
24846
26873
  await git.raw(["worktree", "prune"]);
24847
26874
  } catch {}
24848
26875
  const worktreesDir = this.getWorktreesDir();
24849
- const features = feature ? [feature] : await fs7.readdir(worktreesDir).catch(() => []);
26876
+ const features = feature ? [feature] : await fs72.readdir(worktreesDir).catch(() => []);
24850
26877
  for (const feat of features) {
24851
26878
  const featurePath = path42.join(worktreesDir, feat);
24852
- const stat2 = await fs7.stat(featurePath).catch(() => null);
26879
+ const stat2 = await fs72.stat(featurePath).catch(() => null);
24853
26880
  if (!stat2?.isDirectory())
24854
26881
  continue;
24855
- const steps = await fs7.readdir(featurePath).catch(() => []);
26882
+ const steps = await fs72.readdir(featurePath).catch(() => []);
24856
26883
  for (const step of steps) {
24857
26884
  const worktreePath = path42.join(featurePath, step);
24858
- const stepStat = await fs7.stat(worktreePath).catch(() => null);
26885
+ const stepStat = await fs72.stat(worktreePath).catch(() => null);
24859
26886
  if (!stepStat?.isDirectory())
24860
26887
  continue;
24861
26888
  try {
@@ -24876,13 +26903,13 @@ class WorktreeService {
24876
26903
  }
24877
26904
  const patchPath = path42.join(this.config.hiveDir, ".worktrees", feature, `${step}-check.patch`);
24878
26905
  try {
24879
- await fs7.writeFile(patchPath, diffContent);
26906
+ await fs72.writeFile(patchPath, diffContent);
24880
26907
  const git = this.getGit();
24881
26908
  await git.applyPatch(patchPath, ["--check"]);
24882
- await fs7.unlink(patchPath).catch(() => {});
26909
+ await fs72.unlink(patchPath).catch(() => {});
24883
26910
  return [];
24884
26911
  } catch (error45) {
24885
- await fs7.unlink(patchPath).catch(() => {});
26912
+ await fs72.unlink(patchPath).catch(() => {});
24886
26913
  const err = error45;
24887
26914
  const stderr = err.message || "";
24888
26915
  const conflicts2 = stderr.split(`
@@ -24895,7 +26922,7 @@ class WorktreeService {
24895
26922
  }
24896
26923
  async checkConflictsFromSavedDiff(diffPath, reverse = false) {
24897
26924
  try {
24898
- await fs7.access(diffPath);
26925
+ await fs72.access(diffPath);
24899
26926
  } catch {
24900
26927
  return [];
24901
26928
  }
@@ -24918,7 +26945,7 @@ class WorktreeService {
24918
26945
  async commitChanges(feature, step, message) {
24919
26946
  const worktreePath = this.getWorktreePath(feature, step);
24920
26947
  try {
24921
- await fs7.access(worktreePath);
26948
+ await fs72.access(worktreePath);
24922
26949
  } catch {
24923
26950
  return { committed: false, sha: "", message: "Worktree not found" };
24924
26951
  }
@@ -25064,10 +27091,10 @@ class ContextService {
25064
27091
  const contextPath = getContextPath(this.projectRoot, featureName);
25065
27092
  if (!fileExists(contextPath))
25066
27093
  return [];
25067
- const files = fs8.readdirSync(contextPath, { withFileTypes: true }).filter((f) => f.isFile() && f.name.endsWith(".md")).map((f) => f.name);
27094
+ const files = fs82.readdirSync(contextPath, { withFileTypes: true }).filter((f) => f.isFile() && f.name.endsWith(".md")).map((f) => f.name);
25068
27095
  return files.map((name) => {
25069
27096
  const filePath = path52.join(contextPath, name);
25070
- const stat2 = fs8.statSync(filePath);
27097
+ const stat2 = fs82.statSync(filePath);
25071
27098
  const content = readText(filePath) || "";
25072
27099
  return {
25073
27100
  name: name.replace(/\.md$/, ""),
@@ -25080,7 +27107,7 @@ class ContextService {
25080
27107
  const contextPath = getContextPath(this.projectRoot, featureName);
25081
27108
  const filePath = path52.join(contextPath, this.normalizeFileName(fileName));
25082
27109
  if (fileExists(filePath)) {
25083
- fs8.unlinkSync(filePath);
27110
+ fs82.unlinkSync(filePath);
25084
27111
  return true;
25085
27112
  }
25086
27113
  return false;
@@ -25111,8 +27138,8 @@ ${f.content}`);
25111
27138
  const archiveName = `${timestamp}_${ctx.name}.md`;
25112
27139
  const src = path52.join(contextPath, `${ctx.name}.md`);
25113
27140
  const dest = path52.join(archiveDir, archiveName);
25114
- fs8.copyFileSync(src, dest);
25115
- fs8.unlinkSync(src);
27141
+ fs82.copyFileSync(src, dest);
27142
+ fs82.unlinkSync(src);
25116
27143
  archived.push(ctx.name);
25117
27144
  }
25118
27145
  return { archived, archivePath: archiveDir };
@@ -25140,8 +27167,8 @@ class ConfigService {
25140
27167
  cachedCustomAgentConfigs = null;
25141
27168
  constructor() {
25142
27169
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
25143
- const configDir = path7.join(homeDir, ".config", "opencode");
25144
- this.configPath = path7.join(configDir, "agent_hive.json");
27170
+ const configDir = path72.join(homeDir, ".config", "opencode");
27171
+ this.configPath = path72.join(configDir, "agent_hive.json");
25145
27172
  }
25146
27173
  getPath() {
25147
27174
  return this.configPath;
@@ -25204,7 +27231,7 @@ class ConfigService {
25204
27231
  ...updates.customAgents
25205
27232
  } : current.customAgents
25206
27233
  };
25207
- const configDir = path7.dirname(this.configPath);
27234
+ const configDir = path72.dirname(this.configPath);
25208
27235
  if (!fs10.existsSync(configDir)) {
25209
27236
  fs10.mkdirSync(configDir, { recursive: true });
25210
27237
  }
@@ -25592,10 +27619,10 @@ class DockerSandboxService {
25592
27619
  static ensureContainer(worktreePath, image) {
25593
27620
  const name = this.containerName(worktreePath);
25594
27621
  try {
25595
- execSync(`docker inspect --format='{{.State.Running}}' ${name}`, { stdio: "pipe" });
27622
+ execSync4(`docker inspect --format='{{.State.Running}}' ${name}`, { stdio: "pipe" });
25596
27623
  return name;
25597
27624
  } catch {
25598
- execSync(`docker run -d --name ${name} -v ${worktreePath}:/app -w /app ${image} tail -f /dev/null`, { stdio: "pipe" });
27625
+ execSync4(`docker run -d --name ${name} -v ${worktreePath}:/app -w /app ${image} tail -f /dev/null`, { stdio: "pipe" });
25599
27626
  return name;
25600
27627
  }
25601
27628
  }
@@ -25606,12 +27633,12 @@ class DockerSandboxService {
25606
27633
  static stopContainer(worktreePath) {
25607
27634
  const name = this.containerName(worktreePath);
25608
27635
  try {
25609
- execSync(`docker rm -f ${name}`, { stdio: "ignore" });
27636
+ execSync4(`docker rm -f ${name}`, { stdio: "ignore" });
25610
27637
  } catch {}
25611
27638
  }
25612
27639
  static isDockerAvailable() {
25613
27640
  try {
25614
- execSync("docker info", { stdio: "ignore" });
27641
+ execSync4("docker info", { stdio: "ignore" });
25615
27642
  return true;
25616
27643
  } catch {
25617
27644
  return false;
@@ -26130,15 +28157,15 @@ function applyContextBudget(files, config2 = {}) {
26130
28157
  }
26131
28158
 
26132
28159
  // src/utils/prompt-file.ts
26133
- import * as fs6 from "fs";
26134
- import * as path6 from "path";
28160
+ import * as fs9 from "fs";
28161
+ import * as path9 from "path";
26135
28162
  function writeWorkerPromptFile(feature, task, prompt, hiveDir) {
26136
- const promptDir = path6.join(hiveDir, "features", feature, "tasks", task);
26137
- const promptPath = path6.join(promptDir, "worker-prompt.md");
26138
- if (!fs6.existsSync(promptDir)) {
26139
- fs6.mkdirSync(promptDir, { recursive: true });
28163
+ const promptDir = path9.join(hiveDir, "features", feature, "tasks", task);
28164
+ const promptPath = path9.join(promptDir, "worker-prompt.md");
28165
+ if (!fs9.existsSync(promptDir)) {
28166
+ fs9.mkdirSync(promptDir, { recursive: true });
26140
28167
  }
26141
- fs6.writeFileSync(promptPath, prompt, "utf-8");
28168
+ fs9.writeFileSync(promptPath, prompt, "utf-8");
26142
28169
  return promptPath;
26143
28170
  }
26144
28171
 
@@ -26191,6 +28218,183 @@ function buildCompactionPrompt() {
26191
28218
  return COMPACTION_RESUME_PROMPT;
26192
28219
  }
26193
28220
 
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
+
26194
28398
  // src/index.ts
26195
28399
  function formatSkillsXml(skills) {
26196
28400
  if (skills.length === 0)
@@ -26216,7 +28420,7 @@ async function buildAutoLoadedSkillsContent(agentName, configService, projectRoo
26216
28420
  if (autoLoadSkills.length === 0) {
26217
28421
  return "";
26218
28422
  }
26219
- const homeDir = process.env.HOME || os4.homedir();
28423
+ const homeDir = process.env.HOME || os5.homedir();
26220
28424
  const skillTemplates = [];
26221
28425
  for (const skillId of autoLoadSkills) {
26222
28426
  const builtinSkill = BUILTIN_SKILLS.find((entry) => entry.name === skillId);
@@ -26298,11 +28502,14 @@ var plugin = async (ctx) => {
26298
28502
  const disabledMcps = configService.getDisabledMcps();
26299
28503
  const disabledSkills = configService.getDisabledSkills();
26300
28504
  const builtinMcps = createBuiltinMcps(disabledMcps);
28505
+ if (configService.get().autoInstallDeps !== false) {
28506
+ ensurePluginDeps();
28507
+ }
26301
28508
  const filteredSkills = getFilteredSkills(disabledSkills);
26302
28509
  const effectiveAutoLoadSkills = configService.getAgentConfig("zetta").autoLoadSkills ?? [];
26303
28510
  const worktreeService = new WorktreeService({
26304
28511
  baseDir: directory,
26305
- hiveDir: path9.join(directory, ".hive")
28512
+ hiveDir: path12.join(directory, ".hive")
26306
28513
  });
26307
28514
  const isOmoSlimEnabled = () => {
26308
28515
  return configService.isOmoSlimEnabled();
@@ -26328,10 +28535,10 @@ var plugin = async (ctx) => {
26328
28535
  }
26329
28536
  };
26330
28537
  const checkBlocked = (feature) => {
26331
- const fs9 = __require("fs");
26332
- const blockedPath = path9.join(directory, ".hive", "features", feature, "BLOCKED");
26333
- if (fs9.existsSync(blockedPath)) {
26334
- const reason = fs9.readFileSync(blockedPath, "utf-8").trim();
28538
+ const fs12 = __require("fs");
28539
+ const blockedPath = path12.join(directory, ".hive", "features", feature, "BLOCKED");
28540
+ if (fs12.existsSync(blockedPath)) {
28541
+ const reason = fs12.readFileSync(blockedPath, "utf-8").trim();
26335
28542
  return `⛔ BLOCKED by Beekeeper
26336
28543
 
26337
28544
  ${reason || "(No reason provided)"}
@@ -26483,9 +28690,9 @@ To unblock: Remove .hive/features/${feature}/BLOCKED`;
26483
28690
  spec: specContent,
26484
28691
  workerPrompt
26485
28692
  });
26486
- const hiveDir = path9.join(directory, ".hive");
28693
+ const hiveDir = path12.join(directory, ".hive");
26487
28694
  const workerPromptPath = writeWorkerPromptFile(feature, task, workerPrompt, hiveDir);
26488
- const relativePromptPath = normalizePath(path9.relative(directory, workerPromptPath));
28695
+ const relativePromptPath = normalizePath(path12.relative(directory, workerPromptPath));
26489
28696
  const PREVIEW_MAX_LENGTH = 200;
26490
28697
  const workerPromptPreview = workerPrompt.length > PREVIEW_MAX_LENGTH ? workerPrompt.slice(0, PREVIEW_MAX_LENGTH) + "..." : workerPrompt;
26491
28698
  const taskToolPrompt = `Follow instructions in @${relativePromptPath}`;
@@ -26893,7 +29100,7 @@ ${snapshot}
26893
29100
  if (sandboxConfig.mode !== "none") {
26894
29101
  const workdir = output.args?.workdir;
26895
29102
  if (workdir) {
26896
- const hiveWorktreeBase = path9.join(directory, ".hive", ".worktrees");
29103
+ const hiveWorktreeBase = path12.join(directory, ".hive", ".worktrees");
26897
29104
  if (workdir.startsWith(hiveWorktreeBase)) {
26898
29105
  const wrapped = DockerSandboxService.wrapCommand(workdir, finalCommand, sandboxConfig);
26899
29106
  output.args.command = wrapped;
@@ -26944,6 +29151,8 @@ ${snapshot}
26944
29151
  lsp_diagnostics: lspDiagnosticsTool,
26945
29152
  lsp_hover: lspHoverTool,
26946
29153
  lsp_code_actions: lspCodeActionsTool,
29154
+ lsp_status: lspStatusTool,
29155
+ lsp_install: lspInstallTool,
26947
29156
  skill_mcp: skillMcpTool,
26948
29157
  list_skill_mcps: listSkillMcpsTool,
26949
29158
  hive_memory_list: hiveMemoryListTool,
@@ -26960,6 +29169,24 @@ ${snapshot}
26960
29169
  hive_vector_search: hiveVectorSearchTool,
26961
29170
  hive_vector_add: hiveVectorAddTool,
26962
29171
  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
+ hive_doctor: hiveDoctorTool,
29179
+ hive_doctor_quick: hiveDoctorQuickTool,
29180
+ dora_status: doraStatusTool,
29181
+ dora_symbol: doraSymbolTool,
29182
+ dora_file: doraFileTool,
29183
+ dora_references: doraReferencesTool,
29184
+ dora_cycles: doraCyclesTool,
29185
+ dora_unused: doraUnusedTool,
29186
+ auto_cr_status: autoCrStatusTool,
29187
+ auto_cr_scan: autoCrScanTool,
29188
+ auto_cr_diff: autoCrDiffTool,
29189
+ auto_cr_rules: autoCrRulesTool,
26963
29190
  hive_skill: createHiveSkillTool(filteredSkills),
26964
29191
  hive_feature_create: tool({
26965
29192
  description: "Create a new feature and set it as active",