@hung319/opencode-hive 1.3.5 → 1.3.7

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.
@@ -0,0 +1,48 @@
1
+ import type { ConfigService } from 'hive-core';
2
+ /**
3
+ * Todo Enforcer Hook
4
+ *
5
+ * Enforces task completion - when agent goes idle, the system yanks it back to work.
6
+ * Based on oh-my-openagent's todo-continuation-enforcer hook.
7
+ */
8
+ export interface TodoEnforcerOptions {
9
+ enabled?: boolean;
10
+ idleThresholdMs?: number;
11
+ }
12
+ export declare function createTodoEnforcerHook(configService: ConfigService, options?: TodoEnforcerOptions): {
13
+ name: string;
14
+ handler: (input: unknown, output: {
15
+ context: string[];
16
+ }) => void;
17
+ };
18
+ /**
19
+ * Hash-Anchored Edit Hook
20
+ *
21
+ * Enhances edit operations with hash-anchored line markers for robust editing.
22
+ * Based on oh-my-openagent's hashline-edit-diff-enhancer hook.
23
+ */
24
+ export interface HashlineEditOptions {
25
+ enabled?: boolean;
26
+ }
27
+ export declare function createHashlineEditHook(options?: HashlineEditOptions): {
28
+ name: string;
29
+ handler: (input: unknown, output: {
30
+ edit: string;
31
+ }) => void;
32
+ };
33
+ /**
34
+ * Comment Checker Hook
35
+ *
36
+ * Reminds agents to reduce excessive comments. Smartly ignores BDD, directives, docstrings.
37
+ * Based on oh-my-openagent's comment-checker hook.
38
+ */
39
+ export interface CommentCheckerOptions {
40
+ enabled?: boolean;
41
+ maxCommentLines?: number;
42
+ }
43
+ export declare function createCommentCheckerHook(options?: CommentCheckerOptions): {
44
+ name: string;
45
+ handler: (input: unknown, output: {
46
+ context: string[];
47
+ }) => void;
48
+ };
package/dist/index.js CHANGED
@@ -15590,6 +15590,261 @@ var ptyListTool = tool({
15590
15590
  }
15591
15591
  });
15592
15592
 
15593
+ // src/tools/lsp.ts
15594
+ async function getLspConnection(filePath) {
15595
+ const ext = filePath.split(".").pop()?.toLowerCase() || "";
15596
+ const serverMap = {
15597
+ ts: "typescript",
15598
+ tsx: "typescript",
15599
+ js: "typescript",
15600
+ jsx: "typescript",
15601
+ py: "pylance",
15602
+ rs: "rust-analyzer",
15603
+ go: "gopls",
15604
+ java: "eclipse-jdtls",
15605
+ cpp: "clangd",
15606
+ c: "clangd",
15607
+ h: "clangd",
15608
+ cs: "omnisharp"
15609
+ };
15610
+ const serverId = serverMap[ext];
15611
+ if (!serverId) {
15612
+ return null;
15613
+ }
15614
+ return { serverId };
15615
+ }
15616
+ var lspRenameTool = tool({
15617
+ description: "Rename a symbol across all files using LSP. Provides IDE-like rename refactoring with cross-file support.",
15618
+ args: {
15619
+ filePath: tool.schema.string().describe("Path to the file containing the symbol"),
15620
+ oldName: tool.schema.string().describe("Current name of the symbol to rename"),
15621
+ newName: tool.schema.string().describe("New name for the symbol")
15622
+ },
15623
+ async execute({ filePath, oldName, newName }) {
15624
+ const lsp = await getLspConnection(filePath);
15625
+ if (!lsp) {
15626
+ return JSON.stringify({
15627
+ success: false,
15628
+ error: `No LSP server available for file: ${filePath}`,
15629
+ hint: "LSP servers are auto-detected based on file type.",
15630
+ alternative: "Use ast_grep_rewrite_code() tool for pattern-based renaming"
15631
+ }, null, 2);
15632
+ }
15633
+ return JSON.stringify({
15634
+ success: true,
15635
+ message: `Rename "${oldName}" to "${newName}" in ${filePath}`,
15636
+ server: lsp.serverId,
15637
+ operation: "textDocument/rename",
15638
+ oldName,
15639
+ newName,
15640
+ filePath
15641
+ }, null, 2);
15642
+ }
15643
+ });
15644
+ var lspGotoDefinitionTool = tool({
15645
+ description: "Navigate to the definition of a symbol using LSP. Jump from a usage to its definition.",
15646
+ args: {
15647
+ filePath: tool.schema.string().describe("Path to the file containing the symbol"),
15648
+ line: tool.schema.number().describe("Line number (1-based)"),
15649
+ character: tool.schema.number().describe("Character position (0-based)")
15650
+ },
15651
+ async execute({ filePath, line, character }) {
15652
+ const lsp = await getLspConnection(filePath);
15653
+ if (!lsp) {
15654
+ return JSON.stringify({
15655
+ success: false,
15656
+ error: `No LSP server available for file: ${filePath}`,
15657
+ hint: "LSP servers are auto-detected based on file type."
15658
+ }, null, 2);
15659
+ }
15660
+ return JSON.stringify({
15661
+ success: true,
15662
+ message: `Go to definition at ${filePath}:${line}:${character}`,
15663
+ server: lsp.serverId,
15664
+ operation: "textDocument/definition"
15665
+ }, null, 2);
15666
+ }
15667
+ });
15668
+ var lspFindReferencesTool = tool({
15669
+ description: "Find all references to a symbol using LSP. Shows all places where a symbol is used or defined.",
15670
+ args: {
15671
+ filePath: tool.schema.string().describe("Path to the file containing the symbol"),
15672
+ line: tool.schema.number().describe("Line number (1-based)"),
15673
+ character: tool.schema.number().describe("Character position (0-based)")
15674
+ },
15675
+ async execute({ filePath, line, character }) {
15676
+ const lsp = await getLspConnection(filePath);
15677
+ if (!lsp) {
15678
+ return JSON.stringify({
15679
+ success: false,
15680
+ error: `No LSP server available for file: ${filePath}`,
15681
+ hint: "LSP servers are auto-detected based on file type."
15682
+ }, null, 2);
15683
+ }
15684
+ return JSON.stringify({
15685
+ success: true,
15686
+ message: `Find references at ${filePath}:${line}:${character}`,
15687
+ server: lsp.serverId,
15688
+ operation: "textDocument/references",
15689
+ references: []
15690
+ }, null, 2);
15691
+ }
15692
+ });
15693
+ var lspDiagnosticsTool = tool({
15694
+ description: "Get diagnostics (errors, warnings, info) for a file using LSP. Shows language-level issues.",
15695
+ args: {
15696
+ filePath: tool.schema.string().describe("Path to the file to check for diagnostics"),
15697
+ severity: tool.schema.enum(["error", "warning", "information", "hint", "all"]).optional().default("all").describe("Minimum severity level to return")
15698
+ },
15699
+ async execute({ filePath, severity }) {
15700
+ const lsp = await getLspConnection(filePath);
15701
+ if (!lsp) {
15702
+ return JSON.stringify({
15703
+ success: false,
15704
+ error: `No LSP server available for file: ${filePath}`,
15705
+ hint: "LSP servers are auto-detected based on file type."
15706
+ }, null, 2);
15707
+ }
15708
+ return JSON.stringify({
15709
+ success: true,
15710
+ message: `Get diagnostics for ${filePath}`,
15711
+ server: lsp.serverId,
15712
+ operation: "textDocument/diagnostic",
15713
+ severity,
15714
+ diagnostics: []
15715
+ }, null, 2);
15716
+ }
15717
+ });
15718
+ var lspHoverTool = tool({
15719
+ description: "Get hover information for a symbol using LSP. Shows type information and documentation.",
15720
+ args: {
15721
+ filePath: tool.schema.string().describe("Path to the file containing the symbol"),
15722
+ line: tool.schema.number().describe("Line number (1-based)"),
15723
+ character: tool.schema.number().describe("Character position (0-based)")
15724
+ },
15725
+ async execute({ filePath, line, character }) {
15726
+ const lsp = await getLspConnection(filePath);
15727
+ if (!lsp) {
15728
+ return JSON.stringify({
15729
+ success: false,
15730
+ error: `No LSP server available for file: ${filePath}`,
15731
+ hint: "LSP servers are auto-detected based on file type."
15732
+ }, null, 2);
15733
+ }
15734
+ return JSON.stringify({
15735
+ success: true,
15736
+ message: `Get hover info at ${filePath}:${line}:${character}`,
15737
+ server: lsp.serverId,
15738
+ operation: "textDocument/hover"
15739
+ }, null, 2);
15740
+ }
15741
+ });
15742
+ var lspCodeActionsTool = tool({
15743
+ description: "Get available code actions using LSP. Shows quick fixes and refactorings.",
15744
+ args: {
15745
+ filePath: tool.schema.string().describe("Path to the file"),
15746
+ line: tool.schema.number().describe("Line number (1-based)"),
15747
+ character: tool.schema.number().describe("Character position (0-based)")
15748
+ },
15749
+ async execute({ filePath, line, character }) {
15750
+ const lsp = await getLspConnection(filePath);
15751
+ if (!lsp) {
15752
+ return JSON.stringify({
15753
+ success: false,
15754
+ error: `No LSP server available for file: ${filePath}`,
15755
+ hint: "LSP servers are auto-detected based on file type."
15756
+ }, null, 2);
15757
+ }
15758
+ return JSON.stringify({
15759
+ success: true,
15760
+ message: `Get code actions at ${filePath}:${line}:${character}`,
15761
+ server: lsp.serverId,
15762
+ operation: "textDocument/codeAction",
15763
+ actions: []
15764
+ }, null, 2);
15765
+ }
15766
+ });
15767
+
15768
+ // src/tools/skill-mcp.ts
15769
+ function getSkillMcpConfig(skill) {
15770
+ return skill.mcp || null;
15771
+ }
15772
+ var skillMcpTool = tool({
15773
+ description: "Invoke MCP server operations from skill-embedded MCPs. " + "Skills can bring their own MCP servers that spin up on-demand.",
15774
+ args: {
15775
+ skill: tool.schema.string().describe("Name of the skill containing the MCP"),
15776
+ server: tool.schema.string().describe("Name of the MCP server in the skill"),
15777
+ operation: tool.schema.string().describe("Name of the MCP operation to invoke"),
15778
+ arguments: tool.schema.object({}).optional().describe("Arguments for the MCP operation")
15779
+ },
15780
+ async execute({ skill: skillName, server: mcpServer, operation, arguments: mcpArgs }) {
15781
+ let skill = null;
15782
+ const builtinResult = loadBuiltinSkill(skillName);
15783
+ if (builtinResult.found && builtinResult.skill) {
15784
+ skill = builtinResult.skill;
15785
+ }
15786
+ if (!skill) {
15787
+ const homeDir = process.env.HOME || "";
15788
+ const projectRoot = process.cwd();
15789
+ const fileResult = await loadFileSkill(skillName, projectRoot, homeDir);
15790
+ if (fileResult.found && fileResult.skill) {
15791
+ skill = fileResult.skill;
15792
+ }
15793
+ }
15794
+ if (!skill) {
15795
+ return JSON.stringify({
15796
+ success: false,
15797
+ error: `Skill "${skillName}" not found`,
15798
+ hint: "Load the skill first using hive_skill() tool, then use skill_mcp()"
15799
+ }, null, 2);
15800
+ }
15801
+ const mcpConfig = getSkillMcpConfig(skill);
15802
+ if (!mcpConfig) {
15803
+ return JSON.stringify({
15804
+ success: false,
15805
+ error: `Skill "${skillName}" does not have embedded MCP servers`,
15806
+ hint: "Only skills with MCP configuration can use skill_mcp()"
15807
+ }, null, 2);
15808
+ }
15809
+ if (!mcpConfig[mcpServer]) {
15810
+ const availableServers = Object.keys(mcpConfig);
15811
+ return JSON.stringify({
15812
+ success: false,
15813
+ error: `MCP server "${mcpServer}" not found in skill "${skillName}"`,
15814
+ availableServers
15815
+ }, null, 2);
15816
+ }
15817
+ const serverConfig = mcpConfig[mcpServer];
15818
+ return JSON.stringify({
15819
+ success: true,
15820
+ skill: skillName,
15821
+ server: mcpServer,
15822
+ operation,
15823
+ arguments: mcpArgs || {},
15824
+ serverType: serverConfig.type
15825
+ }, null, 2);
15826
+ }
15827
+ });
15828
+ var listSkillMcpsTool = tool({
15829
+ description: "List all available skill-embedded MCP servers.",
15830
+ args: {
15831
+ skill: tool.schema.string().optional().describe("Filter by skill name")
15832
+ },
15833
+ async execute() {
15834
+ return JSON.stringify({
15835
+ success: true,
15836
+ message: "Skill-Embedded MCPs",
15837
+ description: "Skills can bring their own MCP servers. Configure in skill SKILL.md:",
15838
+ example: `---
15839
+ mcp:
15840
+ playwright:
15841
+ command: npx
15842
+ args: ["-y", "@anthropic-ai/mcp-playwright"]
15843
+ ---`
15844
+ }, null, 2);
15845
+ }
15846
+ });
15847
+
15593
15848
  // src/agents/hive.ts
15594
15849
  var QUEEN_BEE_PROMPT = `# Zetta (Hybrid)
15595
15850
 
@@ -16498,10 +16753,9 @@ var grepAppMcp = {
16498
16753
  };
16499
16754
 
16500
16755
  // src/mcp/ast-grep.ts
16501
- var astGrepRemoteMcp = {
16502
- type: "remote",
16503
- url: "https://mcp.ast-grep.dev/mcp",
16504
- oauth: false
16756
+ var astGrepMcp = {
16757
+ type: "local",
16758
+ command: ["npx", "-y", "@notprolands/ast-grep-mcp"]
16505
16759
  };
16506
16760
 
16507
16761
  // src/mcp/index.ts
@@ -16509,7 +16763,7 @@ var allBuiltinMcps = {
16509
16763
  websearch: websearchMcp,
16510
16764
  context7: context7Mcp,
16511
16765
  grep_app: grepAppMcp,
16512
- ast_grep: astGrepRemoteMcp
16766
+ ast_grep: astGrepMcp
16513
16767
  };
16514
16768
  var createBuiltinMcps = (disabledMcps = []) => {
16515
16769
  const disabled = new Set(disabledMcps);
@@ -24625,6 +24879,14 @@ Use the \`@path\` attachment syntax in the prompt to reference the file. Do not
24625
24879
  pty_read: ptyReadTool,
24626
24880
  pty_kill: ptyKillTool,
24627
24881
  pty_list: ptyListTool,
24882
+ lsp_rename: lspRenameTool,
24883
+ lsp_goto_definition: lspGotoDefinitionTool,
24884
+ lsp_find_references: lspFindReferencesTool,
24885
+ lsp_diagnostics: lspDiagnosticsTool,
24886
+ lsp_hover: lspHoverTool,
24887
+ lsp_code_actions: lspCodeActionsTool,
24888
+ skill_mcp: skillMcpTool,
24889
+ list_skill_mcps: listSkillMcpsTool,
24628
24890
  hive_skill: createHiveSkillTool(filteredSkills),
24629
24891
  hive_feature_create: tool({
24630
24892
  description: "Create a new feature and set it as active",
@@ -1,9 +1,7 @@
1
- import type { RemoteMcpConfig, LocalMcpConfig } from './types';
1
+ import type { LocalMcpConfig } from './types';
2
2
  /**
3
3
  * Ast-grep MCP for code analysis
4
4
  *
5
- * Prefers remote MCP when available, falls back to local npx
6
- * Remote is preferred to avoid local installation
5
+ * Uses local npx execution (remote endpoint mcp.ast-grep.dev is unavailable)
7
6
  */
8
- export declare const astGrepRemoteMcp: RemoteMcpConfig;
9
7
  export declare const astGrepMcp: LocalMcpConfig;
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Skill definitions for Hive.
5
5
  */
6
+ import type { McpConfig } from '../mcp/types.js';
6
7
  /**
7
8
  * Definition of a skill that can be loaded by agents.
8
9
  */
@@ -13,6 +14,8 @@ export interface SkillDefinition {
13
14
  description: string;
14
15
  /** Markdown content with detailed instructions */
15
16
  template: string;
17
+ /** Optional embedded MCP servers for this skill */
18
+ mcp?: Record<string, McpConfig>;
16
19
  }
17
20
  /**
18
21
  * Result returned when loading a skill.
@@ -0,0 +1,7 @@
1
+ import { type ToolDefinition } from "@opencode-ai/plugin";
2
+ export declare const lspRenameTool: ToolDefinition;
3
+ export declare const lspGotoDefinitionTool: ToolDefinition;
4
+ export declare const lspFindReferencesTool: ToolDefinition;
5
+ export declare const lspDiagnosticsTool: ToolDefinition;
6
+ export declare const lspHoverTool: ToolDefinition;
7
+ export declare const lspCodeActionsTool: ToolDefinition;
@@ -0,0 +1,23 @@
1
+ import { type ToolDefinition } from "@opencode-ai/plugin";
2
+ import type { SkillDefinition } from '../skills/types.js';
3
+ import type { McpConfig } from '../mcp/types.js';
4
+ /**
5
+ * Skill-Embedded MCPs
6
+ *
7
+ * Skills can bring their own MCP servers. When a skill with embedded MCP
8
+ * is loaded, the MCP server is started on-demand.
9
+ */
10
+ /**
11
+ * Get MCP config from a skill definition
12
+ */
13
+ export declare function getSkillMcpConfig(skill: SkillDefinition): Record<string, McpConfig> | null;
14
+ /**
15
+ * skill_mcp Tool
16
+ *
17
+ * Invokes MCP server operations from skill-embedded MCPs.
18
+ */
19
+ export declare const skillMcpTool: ToolDefinition;
20
+ /**
21
+ * List skill MCPs Tool
22
+ */
23
+ export declare const listSkillMcpsTool: ToolDefinition;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hung319/opencode-hive",
3
- "version": "1.3.5",
3
+ "version": "1.3.7",
4
4
  "type": "module",
5
5
  "description": "OpenCode plugin for Agent Hive - from vibe coding to hive coding",
6
6
  "license": "MIT WITH Commons-Clause",