@hung319/opencode-hive 1.4.4 → 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);
@@ -854,8 +854,8 @@ var init_context_compression = __esm(() => {
854
854
  });
855
855
 
856
856
  // src/index.ts
857
- import * as path11 from "path";
858
- import * as os4 from "os";
857
+ import * as path12 from "path";
858
+ import * as os5 from "os";
859
859
 
860
860
  // ../../node_modules/.bun/zod@4.1.8/node_modules/zod/v4/classic/external.js
861
861
  var exports_external = {};
@@ -16213,50 +16213,333 @@ var ptyListTool = tool({
16213
16213
  }
16214
16214
  });
16215
16215
 
16216
- // src/tools/lsp.ts
16217
- async function getLspConnection(filePath) {
16218
- const ext = filePath.split(".").pop()?.toLowerCase() || "";
16219
- const serverMap = {
16220
- ts: "typescript",
16221
- tsx: "typescript",
16222
- js: "typescript",
16223
- jsx: "typescript",
16224
- py: "pylance",
16225
- rs: "rust-analyzer",
16226
- go: "gopls",
16227
- java: "eclipse-jdtls",
16228
- cpp: "clangd",
16229
- c: "clangd",
16230
- h: "clangd",
16231
- cs: "omnisharp"
16232
- };
16233
- const serverId = serverMap[ext];
16234
- if (!serverId) {
16235
- return null;
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
+ ]
16234
+ },
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
+ ]
16254
+ },
16255
+ rust: {
16256
+ extensions: ["rs"],
16257
+ primary: {
16258
+ command: "rustup",
16259
+ args: ["component", "add", "rust-analyzer"],
16260
+ verifyCommand: "rust-analyzer --version"
16261
+ },
16262
+ alternatives: []
16263
+ },
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
+ };
16236
16492
  }
16237
- return { serverId };
16238
16493
  }
16494
+ var lspManager = new LspManager;
16495
+
16496
+ // src/tools/lsp.ts
16239
16497
  var lspRenameTool = tool({
16240
- description: "Rename a symbol across all files using LSP. Provides IDE-like rename refactoring with cross-file support.",
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
+ \`\`\``,
16241
16514
  args: {
16242
16515
  filePath: tool.schema.string().describe("Path to the file containing the symbol"),
16243
16516
  oldName: tool.schema.string().describe("Current name of the symbol to rename"),
16244
16517
  newName: tool.schema.string().describe("New name for the symbol")
16245
16518
  },
16246
16519
  async execute({ filePath, oldName, newName }) {
16247
- const lsp = await getLspConnection(filePath);
16248
- if (!lsp) {
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) {
16249
16530
  return JSON.stringify({
16250
16531
  success: false,
16251
- error: `No LSP server available for file: ${filePath}`,
16252
- hint: "LSP servers are auto-detected based on file type.",
16253
- alternative: "Use ast_grep_rewrite_code() tool for pattern-based renaming"
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."
16254
16537
  }, null, 2);
16255
16538
  }
16256
16539
  return JSON.stringify({
16257
16540
  success: true,
16258
16541
  message: `Rename "${oldName}" to "${newName}" in ${filePath}`,
16259
- server: lsp.serverId,
16542
+ language: status.language,
16260
16543
  operation: "textDocument/rename",
16261
16544
  oldName,
16262
16545
  newName,
@@ -16265,73 +16548,123 @@ var lspRenameTool = tool({
16265
16548
  }
16266
16549
  });
16267
16550
  var lspGotoDefinitionTool = tool({
16268
- description: "Navigate to the definition of a symbol using LSP. Jump from a usage to its definition.",
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)`,
16269
16562
  args: {
16270
16563
  filePath: tool.schema.string().describe("Path to the file containing the symbol"),
16271
16564
  line: tool.schema.number().describe("Line number (1-based)"),
16272
16565
  character: tool.schema.number().describe("Character position (0-based)")
16273
16566
  },
16274
16567
  async execute({ filePath, line, character }) {
16275
- const lsp = await getLspConnection(filePath);
16276
- if (!lsp) {
16568
+ const lang = getLanguageFromPath(filePath);
16569
+ if (!lang) {
16277
16570
  return JSON.stringify({
16278
16571
  success: false,
16279
- error: `No LSP server available for file: ${filePath}`,
16280
- hint: "LSP servers are auto-detected based on file type."
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)
16281
16582
  }, null, 2);
16282
16583
  }
16283
16584
  return JSON.stringify({
16284
16585
  success: true,
16285
16586
  message: `Go to definition at ${filePath}:${line}:${character}`,
16286
- server: lsp.serverId,
16287
- operation: "textDocument/definition"
16587
+ language: status.language,
16588
+ operation: "textDocument/definition",
16589
+ location: { filePath, line, character }
16288
16590
  }, null, 2);
16289
16591
  }
16290
16592
  });
16291
16593
  var lspFindReferencesTool = tool({
16292
- description: "Find all references to a symbol using LSP. Shows all places where a symbol is used or defined.",
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`,
16293
16600
  args: {
16294
16601
  filePath: tool.schema.string().describe("Path to the file containing the symbol"),
16295
16602
  line: tool.schema.number().describe("Line number (1-based)"),
16296
16603
  character: tool.schema.number().describe("Character position (0-based)")
16297
16604
  },
16298
16605
  async execute({ filePath, line, character }) {
16299
- const lsp = await getLspConnection(filePath);
16300
- if (!lsp) {
16606
+ const lang = getLanguageFromPath(filePath);
16607
+ if (!lang) {
16301
16608
  return JSON.stringify({
16302
16609
  success: false,
16303
- error: `No LSP server available for file: ${filePath}`,
16304
- hint: "LSP servers are auto-detected based on file type."
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)
16305
16620
  }, null, 2);
16306
16621
  }
16307
16622
  return JSON.stringify({
16308
16623
  success: true,
16309
16624
  message: `Find references at ${filePath}:${line}:${character}`,
16310
- server: lsp.serverId,
16625
+ language: status.language,
16311
16626
  operation: "textDocument/references",
16627
+ location: { filePath, line, character },
16312
16628
  references: []
16313
16629
  }, null, 2);
16314
16630
  }
16315
16631
  });
16316
16632
  var lspDiagnosticsTool = tool({
16317
- 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)`,
16318
16643
  args: {
16319
16644
  filePath: tool.schema.string().describe("Path to the file to check for diagnostics"),
16320
16645
  severity: tool.schema.enum(["error", "warning", "information", "hint", "all"]).optional().default("all").describe("Minimum severity level to return")
16321
16646
  },
16322
16647
  async execute({ filePath, severity }) {
16323
- const lsp = await getLspConnection(filePath);
16324
- if (!lsp) {
16648
+ const lang = getLanguageFromPath(filePath);
16649
+ if (!lang) {
16325
16650
  return JSON.stringify({
16326
16651
  success: false,
16327
- error: `No LSP server available for file: ${filePath}`,
16328
- hint: "LSP servers are auto-detected based on file type."
16652
+ error: `Unsupported file type: ${filePath}`
16653
+ }, null, 2);
16654
+ }
16655
+ const status = await lspManager.checkAndInstall(filePath);
16656
+ if (!status.ready) {
16657
+ return JSON.stringify({
16658
+ success: false,
16659
+ language: status.language,
16660
+ error: status.message,
16661
+ alternatives: await getLspStatus(filePath)
16329
16662
  }, null, 2);
16330
16663
  }
16331
16664
  return JSON.stringify({
16332
16665
  success: true,
16333
16666
  message: `Get diagnostics for ${filePath}`,
16334
- server: lsp.serverId,
16667
+ language: status.language,
16335
16668
  operation: "textDocument/diagnostic",
16336
16669
  severity,
16337
16670
  diagnostics: []
@@ -16339,54 +16672,168 @@ var lspDiagnosticsTool = tool({
16339
16672
  }
16340
16673
  });
16341
16674
  var lspHoverTool = tool({
16342
- 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`,
16343
16681
  args: {
16344
16682
  filePath: tool.schema.string().describe("Path to the file containing the symbol"),
16345
16683
  line: tool.schema.number().describe("Line number (1-based)"),
16346
16684
  character: tool.schema.number().describe("Character position (0-based)")
16347
16685
  },
16348
16686
  async execute({ filePath, line, character }) {
16349
- const lsp = await getLspConnection(filePath);
16350
- 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) {
16351
16696
  return JSON.stringify({
16352
16697
  success: false,
16353
- error: `No LSP server available for file: ${filePath}`,
16354
- hint: "LSP servers are auto-detected based on file type."
16698
+ language: status.language,
16699
+ error: status.message,
16700
+ alternatives: await getLspStatus(filePath)
16355
16701
  }, null, 2);
16356
16702
  }
16357
16703
  return JSON.stringify({
16358
16704
  success: true,
16359
16705
  message: `Get hover info at ${filePath}:${line}:${character}`,
16360
- server: lsp.serverId,
16361
- operation: "textDocument/hover"
16706
+ language: status.language,
16707
+ operation: "textDocument/hover",
16708
+ location: { filePath, line, character }
16362
16709
  }, null, 2);
16363
16710
  }
16364
16711
  });
16365
16712
  var lspCodeActionsTool = tool({
16366
- 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`,
16367
16719
  args: {
16368
16720
  filePath: tool.schema.string().describe("Path to the file"),
16369
16721
  line: tool.schema.number().describe("Line number (1-based)"),
16370
16722
  character: tool.schema.number().describe("Character position (0-based)")
16371
16723
  },
16372
16724
  async execute({ filePath, line, character }) {
16373
- const lsp = await getLspConnection(filePath);
16374
- 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) {
16375
16734
  return JSON.stringify({
16376
16735
  success: false,
16377
- error: `No LSP server available for file: ${filePath}`,
16378
- hint: "LSP servers are auto-detected based on file type."
16736
+ language: status.language,
16737
+ error: status.message,
16738
+ alternatives: await getLspStatus(filePath)
16379
16739
  }, null, 2);
16380
16740
  }
16381
16741
  return JSON.stringify({
16382
16742
  success: true,
16383
16743
  message: `Get code actions at ${filePath}:${line}:${character}`,
16384
- server: lsp.serverId,
16744
+ language: status.language,
16385
16745
  operation: "textDocument/codeAction",
16746
+ location: { filePath, line, character },
16386
16747
  actions: []
16387
16748
  }, null, 2);
16388
16749
  }
16389
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
+ });
16390
16837
 
16391
16838
  // src/tools/skill-mcp.ts
16392
16839
  function getSkillMcpConfig(skill) {
@@ -16470,16 +16917,16 @@ mcp:
16470
16917
 
16471
16918
  // src/tools/memory.ts
16472
16919
  import * as fs2 from "fs";
16473
- import * as path2 from "path";
16920
+ import * as path3 from "path";
16474
16921
  import * as os from "os";
16475
16922
  function getGlobalMemoryDir() {
16476
- return path2.join(os.homedir(), ".config", "opencode", "hive", "memory", "global");
16923
+ return path3.join(os.homedir(), ".config", "opencode", "hive", "memory", "global");
16477
16924
  }
16478
16925
  function getProjectMemoryDir(projectRoot) {
16479
- return path2.join(projectRoot, ".hive", "memory", "project");
16926
+ return path3.join(projectRoot, ".hive", "memory", "project");
16480
16927
  }
16481
16928
  function getJournalDir() {
16482
- return path2.join(os.homedir(), ".config", "opencode", "hive", "journal");
16929
+ return path3.join(os.homedir(), ".config", "opencode", "hive", "journal");
16483
16930
  }
16484
16931
  function parseFrontmatter2(content) {
16485
16932
  if (!content.startsWith(`---
@@ -16536,7 +16983,7 @@ ${lines.join(`
16536
16983
  function readMemoryBlock(filePath, scope) {
16537
16984
  const content = fs2.readFileSync(filePath, "utf-8");
16538
16985
  const { frontmatter, body } = parseFrontmatter2(content);
16539
- const label = frontmatter.label || path2.basename(filePath, path2.extname(filePath));
16986
+ const label = frontmatter.label || path3.basename(filePath, path3.extname(filePath));
16540
16987
  const description = frontmatter.description || "Memory block";
16541
16988
  const limit = frontmatter.limit || 5000;
16542
16989
  const readOnly = frontmatter.read_only === true;
@@ -16561,7 +17008,7 @@ function listMemoryBlocks(scope, projectRoot) {
16561
17008
  const blocks = [];
16562
17009
  for (const file2 of fs2.readdirSync(dir)) {
16563
17010
  if (file2.endsWith(".md")) {
16564
- const filePath = path2.join(dir, file2);
17011
+ const filePath = path3.join(dir, file2);
16565
17012
  try {
16566
17013
  blocks.push(readMemoryBlock(filePath, scope));
16567
17014
  } catch {}
@@ -16585,7 +17032,7 @@ async function ensureMemorySeeded(projectRoot) {
16585
17032
  for (const seed of SEED_BLOCKS) {
16586
17033
  const dir = seed.scope === "global" ? getGlobalMemoryDir() : getProjectMemoryDir(projectRoot);
16587
17034
  fs2.mkdirSync(dir, { recursive: true });
16588
- const filePath = path2.join(dir, `${seed.label}.md`);
17035
+ const filePath = path3.join(dir, `${seed.label}.md`);
16589
17036
  if (!fs2.existsSync(filePath)) {
16590
17037
  const content = buildFrontmatter({
16591
17038
  label: seed.label,
@@ -16603,7 +17050,7 @@ function writeJournalEntry(title, body, project, tags = []) {
16603
17050
  fs2.mkdirSync(journalDir, { recursive: true });
16604
17051
  const now = new Date;
16605
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")}`;
16606
- const filePath = path2.join(journalDir, `${id2}.md`);
17053
+ const filePath = path3.join(journalDir, `${id2}.md`);
16607
17054
  const frontmatter = buildFrontmatter({
16608
17055
  title,
16609
17056
  project: project || "",
@@ -16630,7 +17077,7 @@ function searchJournalEntries(query, project, limit = 20) {
16630
17077
  const entries = [];
16631
17078
  const files = fs2.readdirSync(journalDir).filter((f) => f.endsWith(".md")).sort().reverse();
16632
17079
  for (const file2 of files) {
16633
- const filePath = path2.join(journalDir, file2);
17080
+ const filePath = path3.join(journalDir, file2);
16634
17081
  const content = fs2.readFileSync(filePath, "utf-8");
16635
17082
  const { frontmatter, body } = parseFrontmatter2(content);
16636
17083
  const entry = {
@@ -16728,7 +17175,7 @@ var hiveMemorySetTool = tool({
16728
17175
  }
16729
17176
  const dir = scope === "global" ? getGlobalMemoryDir() : getProjectMemoryDir(projectRoot);
16730
17177
  fs2.mkdirSync(dir, { recursive: true });
16731
- const filePath = path2.join(dir, `${label}.md`);
17178
+ const filePath = path3.join(dir, `${label}.md`);
16732
17179
  if (fs2.existsSync(filePath)) {
16733
17180
  const existing = readMemoryBlock(filePath, scope);
16734
17181
  if (existing.readOnly) {
@@ -16766,7 +17213,7 @@ var hiveMemoryReplaceTool = tool({
16766
17213
  async execute({ scope, label, oldText, newText }) {
16767
17214
  const projectRoot = process.cwd();
16768
17215
  const dir = scope === "global" ? getGlobalMemoryDir() : getProjectMemoryDir(projectRoot);
16769
- const filePath = path2.join(dir, `${label}.md`);
17216
+ const filePath = path3.join(dir, `${label}.md`);
16770
17217
  if (!fs2.existsSync(filePath)) {
16771
17218
  return JSON.stringify({
16772
17219
  success: false,
@@ -16890,10 +17337,10 @@ async function buildMemoryInjection(projectRoot) {
16890
17337
  `);
16891
17338
  }
16892
17339
  function getTypedMemoryDir() {
16893
- return path2.join(os.homedir(), ".config", "opencode", "hive", "typed-memory");
17340
+ return path3.join(os.homedir(), ".config", "opencode", "hive", "typed-memory");
16894
17341
  }
16895
17342
  function getDeletionsFile() {
16896
- return path2.join(getTypedMemoryDir(), "deletions.logfmt");
17343
+ return path3.join(getTypedMemoryDir(), "deletions.logfmt");
16897
17344
  }
16898
17345
  function parseTypedMemoryLine(line) {
16899
17346
  const tsMatch = line.match(/ts=([^\s]+)/);
@@ -16949,7 +17396,7 @@ async function getAllTypedMemories() {
16949
17396
  for (const filename of files) {
16950
17397
  if (filename === "deletions.logfmt")
16951
17398
  continue;
16952
- const filepath = path2.join(dir, filename);
17399
+ const filepath = path3.join(dir, filename);
16953
17400
  const text = fs2.readFileSync(filepath, "utf-8");
16954
17401
  lines.push(...text.trim().split(`
16955
17402
  `).filter(Boolean));
@@ -16965,7 +17412,7 @@ async function findTypedMemories(scope, type, query) {
16965
17412
  for (const filename of files) {
16966
17413
  if (filename === "deletions.logfmt")
16967
17414
  continue;
16968
- const filepath = path2.join(dir, filename);
17415
+ const filepath = path3.join(dir, filename);
16969
17416
  const text = fs2.readFileSync(filepath, "utf-8");
16970
17417
  const lines = text.split(`
16971
17418
  `);
@@ -17153,7 +17600,7 @@ var hiveMemoryForgetTool = tool({
17153
17600
 
17154
17601
  // src/tools/agent-booster.ts
17155
17602
  import * as fs3 from "fs";
17156
- import * as path3 from "path";
17603
+ import * as path4 from "path";
17157
17604
  var boosterInstance = null;
17158
17605
  var boosterInitPromise = null;
17159
17606
  async function initBooster() {
@@ -17311,7 +17758,7 @@ var hiveCodeEditTool = tool({
17311
17758
  newContent: tool.schema.string().describe("Replacement text")
17312
17759
  },
17313
17760
  async execute({ path: filePath, oldContent, newContent }) {
17314
- const resolvedPath = path3.isAbsolute(filePath) ? filePath : path3.join(process.cwd(), filePath);
17761
+ const resolvedPath = path4.isAbsolute(filePath) ? filePath : path4.join(process.cwd(), filePath);
17315
17762
  const result = await applyCodeEdit({
17316
17763
  path: resolvedPath,
17317
17764
  oldContent,
@@ -17352,7 +17799,7 @@ const newFunction = () => { ... };
17352
17799
  snippet: tool.schema.string().describe("Code snippet with // ... existing code ... markers")
17353
17800
  },
17354
17801
  async execute({ path: filePath, snippet }) {
17355
- const resolvedPath = path3.isAbsolute(filePath) ? filePath : path3.join(process.cwd(), filePath);
17802
+ const resolvedPath = path4.isAbsolute(filePath) ? filePath : path4.join(process.cwd(), filePath);
17356
17803
  const available = await isBoosterAvailable();
17357
17804
  if (!available) {
17358
17805
  return JSON.stringify({
@@ -17410,7 +17857,7 @@ var hiveBoosterStatusTool = tool({
17410
17857
 
17411
17858
  // src/services/vector-memory.ts
17412
17859
  import * as fs4 from "fs";
17413
- import * as path4 from "path";
17860
+ import * as path5 from "path";
17414
17861
  import * as os2 from "os";
17415
17862
  var memoryInstance = null;
17416
17863
  var memoryInitPromise = null;
@@ -17425,7 +17872,7 @@ async function initMemory(options) {
17425
17872
  memoryInitPromise = (async () => {
17426
17873
  try {
17427
17874
  const memory = (()=>{throw new Error("Cannot require module "+"@sparkleideas/memory");})();
17428
- 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");
17429
17876
  const dimensions = options?.dimensions || 384;
17430
17877
  fs4.mkdirSync(indexPath, { recursive: true });
17431
17878
  if (typeof memory.init === "function") {
@@ -17529,7 +17976,7 @@ async function getMemoryStatus() {
17529
17976
  };
17530
17977
  }
17531
17978
  function getFallbackDir() {
17532
- return path4.join(os2.homedir(), ".config", "opencode", "hive", "vector-memory", "fallback");
17979
+ return path5.join(os2.homedir(), ".config", "opencode", "hive", "vector-memory", "fallback");
17533
17980
  }
17534
17981
  function ensureFallbackDir() {
17535
17982
  const dir = getFallbackDir();
@@ -17550,7 +17997,7 @@ async function addMemoryFallback(content, metadata) {
17550
17997
  createdAt: new Date().toISOString(),
17551
17998
  updatedAt: new Date().toISOString()
17552
17999
  };
17553
- const filePath = path4.join(getFallbackDir(), `${id2}.json`);
18000
+ const filePath = path5.join(getFallbackDir(), `${id2}.json`);
17554
18001
  fs4.writeFileSync(filePath, JSON.stringify(entry, null, 2), "utf-8");
17555
18002
  return { id: id2, success: true, fallback: true };
17556
18003
  }
@@ -17562,7 +18009,7 @@ async function searchMemoriesFallback(query, options) {
17562
18009
  const files = fs4.readdirSync(getFallbackDir()).filter((f) => f.endsWith(".json"));
17563
18010
  for (const file2 of files) {
17564
18011
  try {
17565
- const content = fs4.readFileSync(path4.join(getFallbackDir(), file2), "utf-8");
18012
+ const content = fs4.readFileSync(path5.join(getFallbackDir(), file2), "utf-8");
17566
18013
  const entry = JSON.parse(content);
17567
18014
  if (type && entry.metadata.type !== type)
17568
18015
  continue;
@@ -17597,7 +18044,7 @@ async function searchMemoriesFallback(query, options) {
17597
18044
  };
17598
18045
  }
17599
18046
  async function getMemoryFallback(id2) {
17600
- const filePath = path4.join(getFallbackDir(), `${id2}.json`);
18047
+ const filePath = path5.join(getFallbackDir(), `${id2}.json`);
17601
18048
  if (!fs4.existsSync(filePath)) {
17602
18049
  return null;
17603
18050
  }
@@ -17609,7 +18056,7 @@ async function getMemoryFallback(id2) {
17609
18056
  }
17610
18057
  }
17611
18058
  async function deleteMemoryFallback(id2) {
17612
- const filePath = path4.join(getFallbackDir(), `${id2}.json`);
18059
+ const filePath = path5.join(getFallbackDir(), `${id2}.json`);
17613
18060
  if (!fs4.existsSync(filePath)) {
17614
18061
  return false;
17615
18062
  }
@@ -17626,7 +18073,7 @@ function getFallbackStats() {
17626
18073
  const files = fs4.readdirSync(getFallbackDir()).filter((f) => f.endsWith(".json"));
17627
18074
  for (const file2 of files) {
17628
18075
  try {
17629
- const content = fs4.readFileSync(path4.join(getFallbackDir(), file2), "utf-8");
18076
+ const content = fs4.readFileSync(path5.join(getFallbackDir(), file2), "utf-8");
17630
18077
  const entry = JSON.parse(content);
17631
18078
  stats.total++;
17632
18079
  const type = entry.metadata.type || "unknown";
@@ -18153,7 +18600,7 @@ Choose "usage" to see which imports are actually used (great for refactoring), o
18153
18600
  mode: tool.schema.enum(["usage", "discovery"]).default("usage").describe("Analysis mode"),
18154
18601
  path: tool.schema.string().optional().describe("Directory or file to analyze")
18155
18602
  },
18156
- async execute({ mode, path: path5 }) {
18603
+ async execute({ mode, path: path6 }) {
18157
18604
  await initAstGrep();
18158
18605
  if (!astGrepModule) {
18159
18606
  return JSON.stringify({
@@ -18162,7 +18609,7 @@ Choose "usage" to see which imports are actually used (great for refactoring), o
18162
18609
  }, null, 2);
18163
18610
  }
18164
18611
  try {
18165
- const analyzePath = path5 || process.cwd();
18612
+ const analyzePath = path6 || process.cwd();
18166
18613
  if (!fs5.existsSync(analyzePath)) {
18167
18614
  return JSON.stringify({
18168
18615
  success: false,
@@ -18224,14 +18671,14 @@ Choose "usage" to see which imports are actually used (great for refactoring), o
18224
18671
 
18225
18672
  // src/tools/hive-doctor.ts
18226
18673
  import * as fs6 from "fs";
18227
- import * as path5 from "path";
18674
+ import * as path6 from "path";
18228
18675
  async function checkPackage(packageName) {
18229
18676
  try {
18230
18677
  const packageJsonPath = __require.resolve(`${packageName}/package.json`, {
18231
18678
  paths: [
18232
18679
  process.cwd(),
18233
- path5.join(process.cwd(), "node_modules"),
18234
- path5.join(process.cwd(), "packages/opencode-hive/node_modules")
18680
+ path6.join(process.cwd(), "node_modules"),
18681
+ path6.join(process.cwd(), "packages/opencode-hive/node_modules")
18235
18682
  ]
18236
18683
  });
18237
18684
  if (fs6.existsSync(packageJsonPath)) {
@@ -18244,8 +18691,8 @@ async function checkPackage(packageName) {
18244
18691
  function checkOptimizations() {
18245
18692
  const checks3 = [];
18246
18693
  const configPaths = [
18247
- path5.join(process.env.HOME || "", ".config/opencode/agent_hive.json"),
18248
- path5.join(process.env.HOME || "", ".config/opencode/agent_hive.jsonc")
18694
+ path6.join(process.env.HOME || "", ".config/opencode/agent_hive.json"),
18695
+ path6.join(process.env.HOME || "", ".config/opencode/agent_hive.jsonc")
18249
18696
  ];
18250
18697
  let config2 = null;
18251
18698
  for (const configPath of configPaths) {
@@ -18436,6 +18883,492 @@ var hiveDoctorQuickTool = tool({
18436
18883
  }
18437
18884
  });
18438
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 };
19144
+ } catch {
19145
+ return { installed: false };
19146
+ }
19147
+ }
19148
+ function runAutoCr(args2) {
19149
+ try {
19150
+ const allArgs = [...args2, "--output", "json"];
19151
+ const output = execSync3(`auto-cr-cmd ${allArgs.join(" ")}`, {
19152
+ encoding: "utf-8",
19153
+ maxBuffer: 50 * 1024 * 1024
19154
+ });
19155
+ try {
19156
+ const json2 = JSON.parse(output);
19157
+ return { success: true, output, json: json2 };
19158
+ } catch {
19159
+ return { success: true, output };
19160
+ }
19161
+ } catch (error45) {
19162
+ const stderr = error45.stderr || "";
19163
+ const stdout = error45.stdout || "";
19164
+ const combined = stdout + stderr;
19165
+ try {
19166
+ const json2 = JSON.parse(combined);
19167
+ return { success: true, output: combined, json: json2 };
19168
+ } catch {
19169
+ return { success: false, error: combined || error45.message };
19170
+ }
19171
+ }
19172
+ }
19173
+ var autoCrStatusTool = tool({
19174
+ description: `Check auto-cr-cmd installation status.
19175
+
19176
+ **Returns:**
19177
+ - installed: Whether auto-cr-cmd is available
19178
+ - version: Auto-CR version
19179
+ - ready: Whether it's ready to scan
19180
+
19181
+ **Installation:**
19182
+ \`\`\`bash
19183
+ npm install auto-cr-cmd
19184
+ # or
19185
+ pnpm add auto-cr-cmd
19186
+ \`\`\``,
19187
+ args: {},
19188
+ async execute() {
19189
+ const status = checkAutoCrStatus();
19190
+ if (!status.installed) {
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).
19214
+
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
+ \`\`\``,
19231
+ args: {
19232
+ path: tool.schema.string().optional().default("./src").describe("Directory path to scan"),
19233
+ language: tool.schema.string().optional().default("en").describe("Output language (en or zh)")
19234
+ },
19235
+ async execute({ path: path7, language }) {
19236
+ const status = checkAutoCrStatus();
19237
+ if (!status.installed) {
19238
+ return JSON.stringify({
19239
+ success: false,
19240
+ error: "auto-cr-cmd not installed",
19241
+ hint: "npm install auto-cr-cmd"
19242
+ }, null, 2);
19243
+ }
19244
+ if (!fs7.existsSync(path7)) {
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 || []
19281
+ }, null, 2);
19282
+ }
19283
+ return JSON.stringify({
19284
+ success: true,
19285
+ scanned: path7,
19286
+ rawOutput: result.output
19287
+ }, null, 2);
19288
+ }
19289
+ });
19290
+ var autoCrDiffTool = tool({
19291
+ description: `Scan git diff output for code issues using auto-cr.
19292
+
19293
+ **Use case:** Run in CI to check only changed files.
19294
+
19295
+ **Example:**
19296
+ \`\`\`bash
19297
+ git diff --name-only -z | xargs -0 auto-cr-cmd --stdin --output json
19298
+ \`\`\`
19299
+
19300
+ **Note:** This tool requires git diff output piped via stdin.`,
19301
+ args: {
19302
+ language: tool.schema.string().optional().default("en").describe("Output language (en or zh)")
19303
+ },
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
+ }
19313
+ return JSON.stringify({
19314
+ success: true,
19315
+ message: "Use git diff with auto-cr directly",
19316
+ example: "git diff --name-only -z | xargs -0 npx auto-cr-cmd --stdin --output json"
19317
+ }, null, 2);
19318
+ }
19319
+ });
19320
+ var autoCrRulesTool = tool({
19321
+ description: `List available auto-cr rules and their descriptions.
19322
+
19323
+ **Returns:** All built-in rules with descriptions.`,
19324
+ args: {},
19325
+ async execute() {
19326
+ const rules = [
19327
+ {
19328
+ name: "no-deep-relative-imports",
19329
+ severity: "error",
19330
+ description: "Import paths should not exceed maximum depth",
19331
+ example: "Use path aliases (@shared/utils) instead of ../../../../shared/utils"
19332
+ },
19333
+ {
19334
+ name: "no-circular-dependencies",
19335
+ severity: "warning",
19336
+ description: "Detect circular module dependencies",
19337
+ example: "A imports B, B imports A creates a cycle"
19338
+ },
19339
+ {
19340
+ name: "no-swallowed-errors",
19341
+ severity: "warning",
19342
+ description: "try-catch blocks that swallow errors without rethrowing",
19343
+ example: "catch (e) {} without logging or rethrowing"
19344
+ },
19345
+ {
19346
+ name: "no-catastrophic-regex",
19347
+ severity: "error",
19348
+ description: "Potentially catastrophic regex backtracking",
19349
+ example: "Regex with nested quantifiers that can hang"
19350
+ },
19351
+ {
19352
+ name: "no-deep-clone-in-loop",
19353
+ severity: "warning",
19354
+ description: "Performance: deep clone operations inside loops",
19355
+ example: "for loop calling JSON.parse(JSON.stringify())"
19356
+ },
19357
+ {
19358
+ name: "no-n2-array-lookup",
19359
+ severity: "warning",
19360
+ description: "O(n²) array operations",
19361
+ example: "Nested for loops accessing array elements"
19362
+ }
19363
+ ];
19364
+ return JSON.stringify({
19365
+ success: true,
19366
+ rules,
19367
+ totalRules: rules.length
19368
+ }, null, 2);
19369
+ }
19370
+ });
19371
+
18439
19372
  // src/agents/hive.ts
18440
19373
  var QUEEN_BEE_PROMPT = `# Zetta (Hybrid)
18441
19374
 
@@ -19775,13 +20708,20 @@ var pareSearchMcp = {
19775
20708
  command: ["npx", "-y", "@paretools/search"]
19776
20709
  };
19777
20710
 
20711
+ // src/mcp/veil.ts
20712
+ var veilMcp = {
20713
+ type: "local",
20714
+ command: ["npx", "-y", "@ushiradineth/veil@latest", "mcp", "server"]
20715
+ };
20716
+
19778
20717
  // src/mcp/index.ts
19779
20718
  var allBuiltinMcps = {
19780
20719
  websearch: websearchMcp,
19781
20720
  context7: context7Mcp,
19782
20721
  grep_app: grepAppMcp,
19783
20722
  ast_grep: astGrepMcp,
19784
- pare_search: pareSearchMcp
20723
+ pare_search: pareSearchMcp,
20724
+ veil: veilMcp
19785
20725
  };
19786
20726
  var createBuiltinMcps = (disabledMcps = []) => {
19787
20727
  const disabled = new Set(disabledMcps);
@@ -19790,10 +20730,10 @@ var createBuiltinMcps = (disabledMcps = []) => {
19790
20730
 
19791
20731
  // ../hive-core/dist/index.js
19792
20732
  import { createRequire as createRequire2 } from "node:module";
19793
- import * as path6 from "path";
20733
+ import * as path7 from "path";
19794
20734
  import * as os3 from "os";
19795
20735
  import * as path22 from "path";
19796
- import * as fs7 from "fs";
20736
+ import * as fs8 from "fs";
19797
20737
  import * as path32 from "path";
19798
20738
  import * as fs22 from "fs";
19799
20739
  import * as fs32 from "fs";
@@ -19802,18 +20742,18 @@ import * as fs52 from "fs";
19802
20742
  import * as fs72 from "fs/promises";
19803
20743
  import * as path42 from "path";
19804
20744
  import { Buffer as Buffer2 } from "node:buffer";
19805
- import { spawn } from "child_process";
20745
+ import { spawn as spawn2 } from "child_process";
19806
20746
  import { normalize } from "node:path";
19807
20747
  import { EventEmitter } from "node:events";
19808
- import * as fs8 from "fs";
20748
+ import * as fs82 from "fs";
19809
20749
  import * as path52 from "path";
19810
20750
  import * as fs10 from "fs";
19811
- import * as path7 from "path";
20751
+ import * as path72 from "path";
19812
20752
  import * as fs11 from "fs";
19813
20753
  import * as path8 from "path";
19814
20754
  import { existsSync as existsSync52 } from "fs";
19815
20755
  import { join as join92, sep } from "path";
19816
- import { execSync } from "child_process";
20756
+ import { execSync as execSync4 } from "child_process";
19817
20757
  var __create2 = Object.create;
19818
20758
  var __getProtoOf2 = Object.getPrototypeOf;
19819
20759
  var __defProp2 = Object.defineProperty;
@@ -20665,9 +21605,10 @@ var DEFAULT_HIVE_CONFIG = {
20665
21605
  },
20666
21606
  vectorMemory: {
20667
21607
  enabled: false,
20668
- indexPath: path6.join(os3.homedir(), ".config", "opencode", "hive", "vector-index"),
21608
+ indexPath: path7.join(os3.homedir(), ".config", "opencode", "hive", "vector-index"),
20669
21609
  dimensions: 384
20670
- }
21610
+ },
21611
+ autoInstallDeps: true
20671
21612
  };
20672
21613
  var HIVE_DIR = ".hive";
20673
21614
  var FEATURES_DIR = "features";
@@ -20739,22 +21680,22 @@ function getSubtaskReportPath(projectRoot, featureName, taskFolder, subtaskFolde
20739
21680
  return path22.join(getSubtaskPath(projectRoot, featureName, taskFolder, subtaskFolder), REPORT_FILE);
20740
21681
  }
20741
21682
  function ensureDir(dirPath) {
20742
- if (!fs7.existsSync(dirPath)) {
20743
- fs7.mkdirSync(dirPath, { recursive: true });
21683
+ if (!fs8.existsSync(dirPath)) {
21684
+ fs8.mkdirSync(dirPath, { recursive: true });
20744
21685
  }
20745
21686
  }
20746
21687
  function fileExists(filePath) {
20747
- return fs7.existsSync(filePath);
21688
+ return fs8.existsSync(filePath);
20748
21689
  }
20749
21690
  function readJson(filePath) {
20750
- if (!fs7.existsSync(filePath))
21691
+ if (!fs8.existsSync(filePath))
20751
21692
  return null;
20752
- const content = fs7.readFileSync(filePath, "utf-8");
21693
+ const content = fs8.readFileSync(filePath, "utf-8");
20753
21694
  return JSON.parse(content);
20754
21695
  }
20755
21696
  function writeJson(filePath, data) {
20756
21697
  ensureDir(path22.dirname(filePath));
20757
- fs7.writeFileSync(filePath, JSON.stringify(data, null, 2));
21698
+ fs8.writeFileSync(filePath, JSON.stringify(data, null, 2));
20758
21699
  }
20759
21700
  var DEFAULT_LOCK_OPTIONS = {
20760
21701
  timeout: 5000,
@@ -20766,7 +21707,7 @@ function getLockPath(filePath) {
20766
21707
  }
20767
21708
  function isLockStale(lockPath, staleTTL) {
20768
21709
  try {
20769
- const stat2 = fs7.statSync(lockPath);
21710
+ const stat2 = fs8.statSync(lockPath);
20770
21711
  const age = Date.now() - stat2.mtimeMs;
20771
21712
  return age > staleTTL;
20772
21713
  } catch {
@@ -20786,12 +21727,12 @@ function acquireLockSync(filePath, options = {}) {
20786
21727
  ensureDir(lockDir);
20787
21728
  while (true) {
20788
21729
  try {
20789
- const fd = fs7.openSync(lockPath, fs7.constants.O_CREAT | fs7.constants.O_EXCL | fs7.constants.O_WRONLY);
20790
- fs7.writeSync(fd, lockContent);
20791
- fs7.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);
20792
21733
  return () => {
20793
21734
  try {
20794
- fs7.unlinkSync(lockPath);
21735
+ fs8.unlinkSync(lockPath);
20795
21736
  } catch {}
20796
21737
  };
20797
21738
  } catch (err) {
@@ -20801,7 +21742,7 @@ function acquireLockSync(filePath, options = {}) {
20801
21742
  } else if (error45.code === "EEXIST") {
20802
21743
  if (isLockStale(lockPath, opts.staleLockTTL)) {
20803
21744
  try {
20804
- fs7.unlinkSync(lockPath);
21745
+ fs8.unlinkSync(lockPath);
20805
21746
  continue;
20806
21747
  } catch {}
20807
21748
  }
@@ -20820,11 +21761,11 @@ function writeAtomic(filePath, content) {
20820
21761
  ensureDir(path22.dirname(filePath));
20821
21762
  const tempPath = `${filePath}.tmp.${process.pid}.${Date.now()}`;
20822
21763
  try {
20823
- fs7.writeFileSync(tempPath, content);
20824
- fs7.renameSync(tempPath, filePath);
21764
+ fs8.writeFileSync(tempPath, content);
21765
+ fs8.renameSync(tempPath, filePath);
20825
21766
  } catch (error45) {
20826
21767
  try {
20827
- fs7.unlinkSync(tempPath);
21768
+ fs8.unlinkSync(tempPath);
20828
21769
  } catch {}
20829
21770
  throw error45;
20830
21771
  }
@@ -20859,13 +21800,13 @@ function patchJsonLockedSync(filePath, patch, options = {}) {
20859
21800
  }
20860
21801
  }
20861
21802
  function readText(filePath) {
20862
- if (!fs7.existsSync(filePath))
21803
+ if (!fs8.existsSync(filePath))
20863
21804
  return null;
20864
- return fs7.readFileSync(filePath, "utf-8");
21805
+ return fs8.readFileSync(filePath, "utf-8");
20865
21806
  }
20866
21807
  function writeText(filePath, content) {
20867
21808
  ensureDir(path22.dirname(filePath));
20868
- fs7.writeFileSync(filePath, content);
21809
+ fs8.writeFileSync(filePath, content);
20869
21810
  }
20870
21811
  function detectContext(cwd) {
20871
21812
  const result = {
@@ -22956,7 +23897,7 @@ var init_git_executor_chain = __esm2({
22956
23897
  rejection = reason || rejection;
22957
23898
  }
22958
23899
  });
22959
- const spawned = spawn(command, args2, spawnOptions);
23900
+ const spawned = spawn2(command, args2, spawnOptions);
22960
23901
  spawned.stdout.on("data", onDataReceived(stdOut, "stdOut", logger, outputLogger.step("stdOut")));
22961
23902
  spawned.stderr.on("data", onDataReceived(stdErr, "stdErr", logger, outputLogger.step("stdErr")));
22962
23903
  spawned.on("error", onErrorReceived(stdErr, logger));
@@ -26150,10 +27091,10 @@ class ContextService {
26150
27091
  const contextPath = getContextPath(this.projectRoot, featureName);
26151
27092
  if (!fileExists(contextPath))
26152
27093
  return [];
26153
- 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);
26154
27095
  return files.map((name) => {
26155
27096
  const filePath = path52.join(contextPath, name);
26156
- const stat2 = fs8.statSync(filePath);
27097
+ const stat2 = fs82.statSync(filePath);
26157
27098
  const content = readText(filePath) || "";
26158
27099
  return {
26159
27100
  name: name.replace(/\.md$/, ""),
@@ -26166,7 +27107,7 @@ class ContextService {
26166
27107
  const contextPath = getContextPath(this.projectRoot, featureName);
26167
27108
  const filePath = path52.join(contextPath, this.normalizeFileName(fileName));
26168
27109
  if (fileExists(filePath)) {
26169
- fs8.unlinkSync(filePath);
27110
+ fs82.unlinkSync(filePath);
26170
27111
  return true;
26171
27112
  }
26172
27113
  return false;
@@ -26197,8 +27138,8 @@ ${f.content}`);
26197
27138
  const archiveName = `${timestamp}_${ctx.name}.md`;
26198
27139
  const src = path52.join(contextPath, `${ctx.name}.md`);
26199
27140
  const dest = path52.join(archiveDir, archiveName);
26200
- fs8.copyFileSync(src, dest);
26201
- fs8.unlinkSync(src);
27141
+ fs82.copyFileSync(src, dest);
27142
+ fs82.unlinkSync(src);
26202
27143
  archived.push(ctx.name);
26203
27144
  }
26204
27145
  return { archived, archivePath: archiveDir };
@@ -26226,8 +27167,8 @@ class ConfigService {
26226
27167
  cachedCustomAgentConfigs = null;
26227
27168
  constructor() {
26228
27169
  const homeDir = process.env.HOME || process.env.USERPROFILE || "";
26229
- const configDir = path7.join(homeDir, ".config", "opencode");
26230
- 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");
26231
27172
  }
26232
27173
  getPath() {
26233
27174
  return this.configPath;
@@ -26290,7 +27231,7 @@ class ConfigService {
26290
27231
  ...updates.customAgents
26291
27232
  } : current.customAgents
26292
27233
  };
26293
- const configDir = path7.dirname(this.configPath);
27234
+ const configDir = path72.dirname(this.configPath);
26294
27235
  if (!fs10.existsSync(configDir)) {
26295
27236
  fs10.mkdirSync(configDir, { recursive: true });
26296
27237
  }
@@ -26678,10 +27619,10 @@ class DockerSandboxService {
26678
27619
  static ensureContainer(worktreePath, image) {
26679
27620
  const name = this.containerName(worktreePath);
26680
27621
  try {
26681
- execSync(`docker inspect --format='{{.State.Running}}' ${name}`, { stdio: "pipe" });
27622
+ execSync4(`docker inspect --format='{{.State.Running}}' ${name}`, { stdio: "pipe" });
26682
27623
  return name;
26683
27624
  } catch {
26684
- 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" });
26685
27626
  return name;
26686
27627
  }
26687
27628
  }
@@ -26692,12 +27633,12 @@ class DockerSandboxService {
26692
27633
  static stopContainer(worktreePath) {
26693
27634
  const name = this.containerName(worktreePath);
26694
27635
  try {
26695
- execSync(`docker rm -f ${name}`, { stdio: "ignore" });
27636
+ execSync4(`docker rm -f ${name}`, { stdio: "ignore" });
26696
27637
  } catch {}
26697
27638
  }
26698
27639
  static isDockerAvailable() {
26699
27640
  try {
26700
- execSync("docker info", { stdio: "ignore" });
27641
+ execSync4("docker info", { stdio: "ignore" });
26701
27642
  return true;
26702
27643
  } catch {
26703
27644
  return false;
@@ -27277,6 +28218,183 @@ function buildCompactionPrompt() {
27277
28218
  return COMPACTION_RESUME_PROMPT;
27278
28219
  }
27279
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
+
27280
28398
  // src/index.ts
27281
28399
  function formatSkillsXml(skills) {
27282
28400
  if (skills.length === 0)
@@ -27302,7 +28420,7 @@ async function buildAutoLoadedSkillsContent(agentName, configService, projectRoo
27302
28420
  if (autoLoadSkills.length === 0) {
27303
28421
  return "";
27304
28422
  }
27305
- const homeDir = process.env.HOME || os4.homedir();
28423
+ const homeDir = process.env.HOME || os5.homedir();
27306
28424
  const skillTemplates = [];
27307
28425
  for (const skillId of autoLoadSkills) {
27308
28426
  const builtinSkill = BUILTIN_SKILLS.find((entry) => entry.name === skillId);
@@ -27384,11 +28502,14 @@ var plugin = async (ctx) => {
27384
28502
  const disabledMcps = configService.getDisabledMcps();
27385
28503
  const disabledSkills = configService.getDisabledSkills();
27386
28504
  const builtinMcps = createBuiltinMcps(disabledMcps);
28505
+ if (configService.get().autoInstallDeps !== false) {
28506
+ ensurePluginDeps();
28507
+ }
27387
28508
  const filteredSkills = getFilteredSkills(disabledSkills);
27388
28509
  const effectiveAutoLoadSkills = configService.getAgentConfig("zetta").autoLoadSkills ?? [];
27389
28510
  const worktreeService = new WorktreeService({
27390
28511
  baseDir: directory,
27391
- hiveDir: path11.join(directory, ".hive")
28512
+ hiveDir: path12.join(directory, ".hive")
27392
28513
  });
27393
28514
  const isOmoSlimEnabled = () => {
27394
28515
  return configService.isOmoSlimEnabled();
@@ -27415,7 +28536,7 @@ var plugin = async (ctx) => {
27415
28536
  };
27416
28537
  const checkBlocked = (feature) => {
27417
28538
  const fs12 = __require("fs");
27418
- const blockedPath = path11.join(directory, ".hive", "features", feature, "BLOCKED");
28539
+ const blockedPath = path12.join(directory, ".hive", "features", feature, "BLOCKED");
27419
28540
  if (fs12.existsSync(blockedPath)) {
27420
28541
  const reason = fs12.readFileSync(blockedPath, "utf-8").trim();
27421
28542
  return `⛔ BLOCKED by Beekeeper
@@ -27569,9 +28690,9 @@ To unblock: Remove .hive/features/${feature}/BLOCKED`;
27569
28690
  spec: specContent,
27570
28691
  workerPrompt
27571
28692
  });
27572
- const hiveDir = path11.join(directory, ".hive");
28693
+ const hiveDir = path12.join(directory, ".hive");
27573
28694
  const workerPromptPath = writeWorkerPromptFile(feature, task, workerPrompt, hiveDir);
27574
- const relativePromptPath = normalizePath(path11.relative(directory, workerPromptPath));
28695
+ const relativePromptPath = normalizePath(path12.relative(directory, workerPromptPath));
27575
28696
  const PREVIEW_MAX_LENGTH = 200;
27576
28697
  const workerPromptPreview = workerPrompt.length > PREVIEW_MAX_LENGTH ? workerPrompt.slice(0, PREVIEW_MAX_LENGTH) + "..." : workerPrompt;
27577
28698
  const taskToolPrompt = `Follow instructions in @${relativePromptPath}`;
@@ -27979,7 +29100,7 @@ ${snapshot}
27979
29100
  if (sandboxConfig.mode !== "none") {
27980
29101
  const workdir = output.args?.workdir;
27981
29102
  if (workdir) {
27982
- const hiveWorktreeBase = path11.join(directory, ".hive", ".worktrees");
29103
+ const hiveWorktreeBase = path12.join(directory, ".hive", ".worktrees");
27983
29104
  if (workdir.startsWith(hiveWorktreeBase)) {
27984
29105
  const wrapped = DockerSandboxService.wrapCommand(workdir, finalCommand, sandboxConfig);
27985
29106
  output.args.command = wrapped;
@@ -28030,6 +29151,8 @@ ${snapshot}
28030
29151
  lsp_diagnostics: lspDiagnosticsTool,
28031
29152
  lsp_hover: lspHoverTool,
28032
29153
  lsp_code_actions: lspCodeActionsTool,
29154
+ lsp_status: lspStatusTool,
29155
+ lsp_install: lspInstallTool,
28033
29156
  skill_mcp: skillMcpTool,
28034
29157
  list_skill_mcps: listSkillMcpsTool,
28035
29158
  hive_memory_list: hiveMemoryListTool,
@@ -28054,6 +29177,16 @@ ${snapshot}
28054
29177
  ast_grep_analyze_imports: astGrepAnalyzeImportsTool,
28055
29178
  hive_doctor: hiveDoctorTool,
28056
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,
28057
29190
  hive_skill: createHiveSkillTool(filteredSkills),
28058
29191
  hive_feature_create: tool({
28059
29192
  description: "Create a new feature and set it as active",