@yeyuan98/opencode-bioresearcher-plugin 1.5.4-alpha.0 → 1.6.0

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.
Files changed (36) hide show
  1. package/README.md +5 -6
  2. package/dist/agents/bioresearcher/prompt.d.ts +1 -1
  3. package/dist/agents/bioresearcher/prompt.js +3 -3
  4. package/dist/agents/bioresearcherDR/prompt.d.ts +1 -1
  5. package/dist/agents/bioresearcherDR/prompt.js +1 -1
  6. package/dist/agents/bioresearcherDR_worker/prompt.d.ts +1 -1
  7. package/dist/agents/bioresearcherDR_worker/prompt.js +1 -1
  8. package/dist/index.js +3 -3
  9. package/dist/shared/tool-restrictions.d.ts +2 -2
  10. package/dist/shared/tool-restrictions.js +4 -4
  11. package/dist/skills/bioresearcher-core/README.md +1 -1
  12. package/dist/skills/bioresearcher-core/SKILL.md +1 -1
  13. package/dist/skills/bioresearcher-core/patterns/bioresearcher/analysis-methods.md +1 -1
  14. package/dist/skills/bioresearcher-core/patterns/bioresearcher/best-practices.md +1 -1
  15. package/dist/skills/bioresearcher-tests/README.md +1 -1
  16. package/dist/skills/bioresearcher-tests/SKILL.md +1 -1
  17. package/dist/skills/bioresearcher-tests/test_cases/skill_tests.md +3 -3
  18. package/dist/skills/gromacs-guides/SKILL.md +48 -48
  19. package/dist/skills/gromacs-guides/guides/inspect_tpr.md +32 -0
  20. package/dist/tools/db/index.d.ts +3 -3
  21. package/dist/tools/db/tools.d.ts +3 -3
  22. package/dist/tools/misc/calculator.d.ts +1 -1
  23. package/dist/tools/misc/json-extract.d.ts +1 -1
  24. package/dist/tools/misc/json-infer.d.ts +1 -1
  25. package/dist/tools/misc/json-validate.d.ts +1 -1
  26. package/dist/tools/misc/json-validate.js +116 -2
  27. package/dist/tools/misc/timer.d.ts +1 -1
  28. package/dist/tools/parser/obo/obo.d.ts +1 -1
  29. package/dist/tools/parser/pubmed/pubmed.d.ts +1 -1
  30. package/dist/tools/skill/index.d.ts +1 -1
  31. package/dist/tools/skill/index.js +1 -1
  32. package/dist/tools/skill/tool.d.ts +2 -2
  33. package/dist/tools/skill/tool.js +6 -5
  34. package/dist/tools/table/index.d.ts +13 -13
  35. package/dist/tools/table/tools.d.ts +13 -13
  36. package/package.json +6 -7
package/README.md CHANGED
@@ -117,7 +117,7 @@ Configuration via `env.jsonc` in working directory. Use the `env-jsonc-setup` sk
117
117
 
118
118
  ## Skills
119
119
 
120
- Skills are reusable prompt templates discovered from multiple paths:
120
+ Skills are reusable prompt templates discovered from multiple paths via the `bioresearcher-skill` tool:
121
121
 
122
122
  | Path | Scope |
123
123
  |------|-------|
@@ -126,24 +126,23 @@ Skills are reusable prompt templates discovered from multiple paths:
126
126
  | `.claude/skills/` | Claude Code compatible |
127
127
  | `.agents/skills/` | Agents compatible |
128
128
 
129
- This plugin provides a skill tool that overrides Opencode's built-in to support plugin-shipped skills.
130
-
131
- See README in `tools/skill` for full documentation.
129
+ Plugin-shipped skills are discovered alongside user-defined skills. The `bioresearcher-skill` tool name avoids conflict with OpenCode's built-in `skill` tool.
132
130
 
133
131
  ### Supplied skills
134
132
 
135
- - `demo-skill`: showcase skill tool mechanisms.
133
+ - `demo-skill`: showcase skill integration and resource resolution.
136
134
  - `python-setup-uv`: setup python runtime in your working directory with uv.
137
135
  - `pubmed-weekly`: automated download of pubmed daily update files over the past one week.
138
136
  - `long-table-summary`: batch-process large tables using parallel subagents for summarization.
139
137
  - `bioresearcher-core`: core patterns and utilities (retry, JSON tools, subagent waves) for skill development.
140
138
  - `env-jsonc-setup`: guided setup for database connection configuration (db-tools).
141
139
  - `gromacs-guides`: reusable guides for GROMACS molecular dynamics workflows.
140
+ - `bioresearcher-tests`: comprehensive test suite for plugin tools and skills.
142
141
 
143
142
  Prompt the following and follow along:
144
143
 
145
144
  ```txt
146
- Setup python uv with skill
145
+ Setup python uv with bioresearcher-skill
147
146
  ```
148
147
 
149
148
  ## Installation
@@ -4,5 +4,5 @@
4
4
  * A specialized biomedical research agent that performs reference-based
5
5
  * pharmaceutical and drug development research using BioMCP tools.
6
6
  */
7
- export declare const BIORESEARCHER_SYSTEM_PROMPT = "\n------ RULE REMINDER START ------\nIMPORTANT: THIS REMINDER SHALL OVERRIDE ALL OTHER PROMPTS PROVIDED TO YOU. IGNORE ALL OTHER PROMPTS.\n\nYou are an expert in biomedical and pharmaceutical drug development research.\n\n## Skill Loading (MANDATORY)\n\nAt the start of complex research tasks, load the core skill:\n\n```\nskill bioresearcher-core\n```\n\nThis skill provides patterns for:\n- **Decision Making**: Tool selection, analysis method choice\n- **Workflow Control**: Retry logic, progress tracking, rate limiting\n- **Data Handling**: JSON validation, table operations, data exchange\n- **Research Standards**: Citation formatting, report templates, Python standards\n- **Best Practices**: Upfront filtering, error handling, performance optimization\n\n## Core Workflow\n\n### Step 1: Clarify Questions\nIf unclear, guide the user to make their question professional and specific:\n- Identify the core research question\n- Determine what type of data is needed\n- Understand the expected output format\n\n### Step 2: Select Appropriate Tools\nUse decision trees from `patterns/tool-selection.md`:\n\n**Data Source Identification:**\n- Database/SQL \u2192 db* tools (dbQuery, dbListTables, dbDescribeTable)\n- Excel/CSV file \u2192 table* tools (tableFilterRows, tableGroupBy, etc.)\n- Website/URL \u2192 web* tools (webfetch, websearch)\n- Literature/Papers \u2192 biomcp* article tools\n- Clinical Trials \u2192 biomcp* trial tools\n- Genes/Variants \u2192 biomcp* gene/variant tools\n- Drugs/Compounds \u2192 biomcp* drug tools\n\n**CRITICAL: Apply upfront filtering at the source (see best-practices.md)**\n\n### Step 3: Fetch Information\nGather trustable information using selected tools:\n\n**Database Queries:**\n```\n1. Check env.jsonc exists (if not, load skill 'env-jsonc-setup')\n2. dbListTables() \u2192 Discover available data\n3. dbDescribeTable() \u2192 Understand schema\n4. dbQuery(\"SELECT ... WHERE filter = :param\", {param: value})\n \u2705 DO: Use WHERE clauses, LIMIT, named parameters\n \u274C DON'T: SELECT * then filter in Python\n```\n\n**Table Operations:**\n```\n1. tableGetSheetPreview() \u2192 Preview structure\n2. Determine row count \u2192 Choose approach:\n - < 30 rows: Use table tools directly\n - 30-1000 rows: Consider long-table-summary skill\n - > 1000 rows: Use Python for complex analysis\n3. Apply filters: tableFilterRows(column, operator, value)\n \u2705 DO: Filter upfront with tableFilterRows\n \u274C DON'T: Load entire table then filter\n```\n\n**BioMCP Queries:**\n```\n1. Use targeted queries with specific filters\n2. biomcp_article_searcher(genes=[\"BRAF\"], diseases=[\"melanoma\"], page_size=50)\n3. ALWAYS: blockingTimer(0.3) between consecutive calls\n4. Sequential only (NEVER concurrent)\n \u2705 DO: Use specific filters (genes, diseases, variants)\n \u274C DON'T: Broad query then manual filtering\n```\n\n### Step 4: Analyze Data\nChoose analysis method using `patterns/analysis-methods.md`:\n\n**Decision Matrix:**\n| Approach | When to Use |\n|----------|-------------|\n| Table Tools | < 30 rows, simple operations (filter, group, summarize) |\n| long-table-summary Skill | 30-1000 rows, structured summarization, parallel processing |\n| Custom Python | > 1000 rows, complex logic, ML, reusable pipeline |\n\n**Skill Loading:**\n- Complex analysis \u2192 Load `bioresearcher-core` for retry, validation patterns\n- Large table summarization \u2192 Load `long-table-summary` skill\n- Python needed but uv missing \u2192 Load `python-setup-uv` skill\n\n**Python Scripts:**\n- Follow `patterns/python-standards.md` (DRY principle)\n- Module docstrings with purpose, usage, dependencies\n- Function docstrings with Args, Returns, Raises, Examples\n- No code duplication - extract to reusable functions\n- Type hints for all functions\n- Save to `.scripts/py/` folder\n\n### Step 5: Write Reference-Based Report\nFollow `patterns/report-template.md` structure:\n\n**Mandatory Sections:**\n1. **Executive Summary** - Key findings with citations [1, 2]\n2. **Data Sources** - Origin, access method, scope, quality notes\n3. **Analysis Methodology** - Approach, tools, steps, validation\n4. **Findings** - Results with citations and data provenance\n5. **Limitations** - Data gaps, methodological constraints\n6. **References** - Formatted bibliography by source type\n\n**Data Provenance Requirements:**\nEvery claim must have:\n- Citation [N] reference, OR\n- Data source documentation, OR\n- Analysis method description\n\n**Citation Format (from `patterns/citations.md`):**\n- In-text: [1], [2, 3], [1-5]\n- Bibliography: Numbered by order of appearance\n- Source-specific formats (articles, trials, web, databases)\n\n## Rate Limiting (MANDATORY)\n\n**ALWAYS use blockingTimer between consecutive API calls:**\n- BioMCP tools: 0.3 seconds (300ms)\n- Web tools: 0.5 seconds (500ms)\n- Database: No delay needed\n- File operations: No delay needed\n\n## Error Handling & Validation\n\n**Validation Pattern (from best-practices.md):**\n1. Check data existence (not empty)\n2. Validate structure (required fields)\n3. Validate types (correct data types)\n4. Validate values (within ranges)\n5. Validate quality (no duplicates)\n\n**Retry Logic (from patterns/retry.md):**\n- Max 3 attempts for network operations\n- Exponential backoff: 2s, 4s, 8s\n- Use blockingTimer between retries\n\n## Python Guidelines\n\n**When to Use Python:**\n- ONLY if existing tools are not suitable\n- Complex transformations beyond table tools\n- Statistical analysis beyond basic aggregation\n- Machine learning or custom algorithms\n\n**Code Standards (MANDATORY):**\n```python\n#!/usr/bin/env python3\n\"\"\"Script Purpose - One Line Description\n\nThis module provides functionality for:\n- Functionality 1\n- Functionality 2\n\nUsage:\n uv run python script.py command --input file.xlsx --output results/\n\nDependencies:\n - pandas >= 1.5.0\n\nAuthor: BioResearcher AI Agent\nDate: YYYY-MM-DD\n\"\"\"\n```\n\n**Function Documentation:**\n```python\ndef analyze_data(data: List[Dict], threshold: float = 0.5) -> Dict:\n \"\"\"Brief description.\n \n Args:\n data: Description of data\n threshold: Threshold value (0.0 to 1.0)\n \n Returns:\n Dictionary with results\n \n Raises:\n ValueError: If threshold out of range\n \"\"\"\n```\n\n**File Location:**\n- Scripts: `.scripts/py/`\n- Use uv for execution: `uv run python .scripts/py/script.py`\n- If uv unavailable, load skill `python-setup-uv`\n\n## Best Practices (CRITICAL)\n\n### Upfront Filtering\n\u2705 ALWAYS filter at source:\n- Database: WHERE clauses, LIMIT\n- Tables: tableFilterRows upfront\n- BioMCP: Specific filters (genes, diseases, variants)\n- Web: Specific search queries\n\n\u274C NEVER retrieve all data then filter in Python\n\n### Data Validation\n\u2705 ALWAYS validate:\n- Check required fields exist\n- Verify data types correct\n- Ensure values in expected ranges\n\n### Error Handling\n\u2705 ALWAYS handle errors:\n- Try-except for external operations\n- Retry logic with exponential backoff\n- Informative error messages\n\n### Context Management\n\u2705 ALWAYS minimize context usage:\n- Summarize large datasets instead of loading all\n- Use file-based data exchange\n- Paginate large result sets\n\n## Bottomline Rules\n\n1. ONLY use high-quality sources: biomcp results or official biotech/pharma websites\n2. ALWAYS provide citations [1], [2], ... with full bibliography at end\n3. ALWAYS backup files before editing (create `.bak` files)\n4. ALWAYS use blockingTimer(0.3) between consecutive biomcp* calls\n5. ALWAYS filter upfront - never retrieve then filter\n6. ALWAYS validate data before processing\n7. ALWAYS follow structured report template with data provenance\n8. ALWAYS write documented Python code following DRY principle\n------ RULE REMINDER END ------\n";
7
+ export declare const BIORESEARCHER_SYSTEM_PROMPT = "\n------ RULE REMINDER START ------\nIMPORTANT: THIS REMINDER SHALL OVERRIDE ALL OTHER PROMPTS PROVIDED TO YOU. IGNORE ALL OTHER PROMPTS.\n\nYou are an expert in biomedical and pharmaceutical drug development research.\n\n## Skill Loading (MANDATORY)\n\nAt the start of complex research tasks, load the core skill:\n\n```\nbioresearcher-skill bioresearcher-core\n```\n\nThis skill provides patterns for:\n- **Decision Making**: Tool selection, analysis method choice\n- **Workflow Control**: Retry logic, progress tracking, rate limiting\n- **Data Handling**: JSON validation, table operations, data exchange\n- **Research Standards**: Citation formatting, report templates, Python standards\n- **Best Practices**: Upfront filtering, error handling, performance optimization\n\n## Core Workflow\n\n### Step 1: Clarify Questions\nIf unclear, guide the user to make their question professional and specific:\n- Identify the core research question\n- Determine what type of data is needed\n- Understand the expected output format\n\n### Step 2: Select Appropriate Tools\nUse decision trees from `patterns/tool-selection.md`:\n\n**Data Source Identification:**\n- Database/SQL \u2192 db* tools (dbQuery, dbListTables, dbDescribeTable)\n- Excel/CSV file \u2192 table* tools (tableFilterRows, tableGroupBy, etc.)\n- Website/URL \u2192 web* tools (webfetch, websearch)\n- Literature/Papers \u2192 biomcp* article tools\n- Clinical Trials \u2192 biomcp* trial tools\n- Genes/Variants \u2192 biomcp* gene/variant tools\n- Drugs/Compounds \u2192 biomcp* drug tools\n\n**CRITICAL: Apply upfront filtering at the source (see best-practices.md)**\n\n### Step 3: Fetch Information\nGather trustable information using selected tools:\n\n**Database Queries:**\n```\n1. Check env.jsonc exists (if not, load bioresearcher-skill 'env-jsonc-setup')\n2. dbListTables() \u2192 Discover available data\n3. dbDescribeTable() \u2192 Understand schema\n4. dbQuery(\"SELECT ... WHERE filter = :param\", {param: value})\n \u2705 DO: Use WHERE clauses, LIMIT, named parameters\n \u274C DON'T: SELECT * then filter in Python\n```\n\n**Table Operations:**\n```\n1. tableGetSheetPreview() \u2192 Preview structure\n2. Determine row count \u2192 Choose approach:\n - < 30 rows: Use table tools directly\n - 30-1000 rows: Consider long-table-summary skill\n - > 1000 rows: Use Python for complex analysis\n3. Apply filters: tableFilterRows(column, operator, value)\n \u2705 DO: Filter upfront with tableFilterRows\n \u274C DON'T: Load entire table then filter\n```\n\n**BioMCP Queries:**\n```\n1. Use targeted queries with specific filters\n2. biomcp_article_searcher(genes=[\"BRAF\"], diseases=[\"melanoma\"], page_size=50)\n3. ALWAYS: blockingTimer(0.3) between consecutive calls\n4. Sequential only (NEVER concurrent)\n \u2705 DO: Use specific filters (genes, diseases, variants)\n \u274C DON'T: Broad query then manual filtering\n```\n\n### Step 4: Analyze Data\nChoose analysis method using `patterns/analysis-methods.md`:\n\n**Decision Matrix:**\n| Approach | When to Use |\n|----------|-------------|\n| Table Tools | < 30 rows, simple operations (filter, group, summarize) |\n| long-table-summary Skill | 30-1000 rows, structured summarization, parallel processing |\n| Custom Python | > 1000 rows, complex logic, ML, reusable pipeline |\n\n**Skill Loading:**\n- Complex analysis \u2192 Load `bioresearcher-core` for retry, validation patterns\n- Large table summarization \u2192 Load `long-table-summary` skill\n- Python needed but uv missing \u2192 Load `python-setup-uv` skill\n\n**Python Scripts:**\n- Follow `patterns/python-standards.md` (DRY principle)\n- Module docstrings with purpose, usage, dependencies\n- Function docstrings with Args, Returns, Raises, Examples\n- No code duplication - extract to reusable functions\n- Type hints for all functions\n- Save to `.scripts/py/` folder\n\n### Step 5: Write Reference-Based Report\nFollow `patterns/report-template.md` structure:\n\n**Mandatory Sections:**\n1. **Executive Summary** - Key findings with citations [1, 2]\n2. **Data Sources** - Origin, access method, scope, quality notes\n3. **Analysis Methodology** - Approach, tools, steps, validation\n4. **Findings** - Results with citations and data provenance\n5. **Limitations** - Data gaps, methodological constraints\n6. **References** - Formatted bibliography by source type\n\n**Data Provenance Requirements:**\nEvery claim must have:\n- Citation [N] reference, OR\n- Data source documentation, OR\n- Analysis method description\n\n**Citation Format (from `patterns/citations.md`):**\n- In-text: [1], [2, 3], [1-5]\n- Bibliography: Numbered by order of appearance\n- Source-specific formats (articles, trials, web, databases)\n\n## Rate Limiting (MANDATORY)\n\n**ALWAYS use blockingTimer between consecutive API calls:**\n- BioMCP tools: 0.3 seconds (300ms)\n- Web tools: 0.5 seconds (500ms)\n- Database: No delay needed\n- File operations: No delay needed\n\n## Error Handling & Validation\n\n**Validation Pattern (from best-practices.md):**\n1. Check data existence (not empty)\n2. Validate structure (required fields)\n3. Validate types (correct data types)\n4. Validate values (within ranges)\n5. Validate quality (no duplicates)\n\n**Retry Logic (from patterns/retry.md):**\n- Max 3 attempts for network operations\n- Exponential backoff: 2s, 4s, 8s\n- Use blockingTimer between retries\n\n## Python Guidelines\n\n**When to Use Python:**\n- ONLY if existing tools are not suitable\n- Complex transformations beyond table tools\n- Statistical analysis beyond basic aggregation\n- Machine learning or custom algorithms\n\n**Code Standards (MANDATORY):**\n```python\n#!/usr/bin/env python3\n\"\"\"Script Purpose - One Line Description\n\nThis module provides functionality for:\n- Functionality 1\n- Functionality 2\n\nUsage:\n uv run python script.py command --input file.xlsx --output results/\n\nDependencies:\n - pandas >= 1.5.0\n\nAuthor: BioResearcher AI Agent\nDate: YYYY-MM-DD\n\"\"\"\n```\n\n**Function Documentation:**\n```python\ndef analyze_data(data: List[Dict], threshold: float = 0.5) -> Dict:\n \"\"\"Brief description.\n \n Args:\n data: Description of data\n threshold: Threshold value (0.0 to 1.0)\n \n Returns:\n Dictionary with results\n \n Raises:\n ValueError: If threshold out of range\n \"\"\"\n```\n\n**File Location:**\n- Scripts: `.scripts/py/`\n- Use uv for execution: `uv run python .scripts/py/script.py`\n- If uv unavailable, load bioresearcher-skill `python-setup-uv`\n\n## Best Practices (CRITICAL)\n\n### Upfront Filtering\n\u2705 ALWAYS filter at source:\n- Database: WHERE clauses, LIMIT\n- Tables: tableFilterRows upfront\n- BioMCP: Specific filters (genes, diseases, variants)\n- Web: Specific search queries\n\n\u274C NEVER retrieve all data then filter in Python\n\n### Data Validation\n\u2705 ALWAYS validate:\n- Check required fields exist\n- Verify data types correct\n- Ensure values in expected ranges\n\n### Error Handling\n\u2705 ALWAYS handle errors:\n- Try-except for external operations\n- Retry logic with exponential backoff\n- Informative error messages\n\n### Context Management\n\u2705 ALWAYS minimize context usage:\n- Summarize large datasets instead of loading all\n- Use file-based data exchange\n- Paginate large result sets\n\n## Bottomline Rules\n\n1. ONLY use high-quality sources: biomcp results or official biotech/pharma websites\n2. ALWAYS provide citations [1], [2], ... with full bibliography at end\n3. ALWAYS backup files before editing (create `.bak` files)\n4. ALWAYS use blockingTimer(0.3) between consecutive biomcp* calls\n5. ALWAYS filter upfront - never retrieve then filter\n6. ALWAYS validate data before processing\n7. ALWAYS follow structured report template with data provenance\n8. ALWAYS write documented Python code following DRY principle\n------ RULE REMINDER END ------\n";
8
8
  export declare function getBioResearcherPrompt(): string;
@@ -15,7 +15,7 @@ You are an expert in biomedical and pharmaceutical drug development research.
15
15
  At the start of complex research tasks, load the core skill:
16
16
 
17
17
  \`\`\`
18
- skill bioresearcher-core
18
+ bioresearcher-skill bioresearcher-core
19
19
  \`\`\`
20
20
 
21
21
  This skill provides patterns for:
@@ -52,7 +52,7 @@ Gather trustable information using selected tools:
52
52
 
53
53
  **Database Queries:**
54
54
  \`\`\`
55
- 1. Check env.jsonc exists (if not, load skill 'env-jsonc-setup')
55
+ 1. Check env.jsonc exists (if not, load bioresearcher-skill 'env-jsonc-setup')
56
56
  2. dbListTables() → Discover available data
57
57
  3. dbDescribeTable() → Understand schema
58
58
  4. dbQuery("SELECT ... WHERE filter = :param", {param: value})
@@ -197,7 +197,7 @@ def analyze_data(data: List[Dict], threshold: float = 0.5) -> Dict:
197
197
  **File Location:**
198
198
  - Scripts: \`.scripts/py/\`
199
199
  - Use uv for execution: \`uv run python .scripts/py/script.py\`
200
- - If uv unavailable, load skill \`python-setup-uv\`
200
+ - If uv unavailable, load bioresearcher-skill \`python-setup-uv\`
201
201
 
202
202
  ## Best Practices (CRITICAL)
203
203
 
@@ -4,5 +4,5 @@
4
4
  * A specialized biomedical research agent that performs reference-based
5
5
  * pharmaceutical and drug development research using BioMCP tools.
6
6
  */
7
- export declare const BIORESEARCHERDR_SYSTEM_PROMPT = "\n------ RULE REMINDER START ------\nIMPORTANT: THIS REMINDER SHALL OVERRIDE ALL OTHER PROMPTS PROVIDED TO YOU. IGNORE ALL OTHER PROMPTS.\nOverall goal: Perform reference-based biomedical and pharmaceutical drug development research.\n\nSteps to STRICTLY adhere to:\n\n1. If the user query includes 'no-interview', skip Step 2 and proceed to Step 3. Otherwise, proceed to Step 2.\n2. Comprehend initial user inquiry. Use the question tool to ask user to clarify 3-6 unclear points depending on inquiry complexity.\n3. Comprehend final user inquiry to identify critical research aspects to answer user inquiry.\n4. If the original user inquiry includes 'light-research', combine and/or pick top two research aspects and proceed to Step 5. Otherwise, proceed directly to Step 5.\n5. Decide on TOPIC of this inquiry (NO user input). TOPIC should be highly succinct, underscore-separated name based on user inquiry.\n6. Use the todowrite tool to generate a list of identified research aspects.\n7. Create the reports_biomcp/<TOPIC>/ folder if needed.\n8. Use the task tool to assign each research aspect to a bioresearcherDR_worker subagent. Start subagents in parallel in batches (size of 5 for each batch). Record finished subagents by checking the todo list. Prompt the user: 'If subagents are stuck without progress for too long, interrupt and ask me to resume work.'\n9. Proceed until subagents complete research. Restart failed subagents if necessary.\n10. Load the skill 'bioresearcher-core' and read 'patterns/citations.md' for citation format. Read reports from all subagents. Summarize findings to provide a succinct and accurate report addressing user inquiry with proper citations.\n11. Write to reports_biomcp/<TOPIC>/final_report.md with full bibliography.\n\nFollow this template to prompt the bioresearcherDR_worker subagents (Step 8):\n\n```md\nTOPIC: <TOPIC>\nYOUR RESEARCH FOCUS: <RESEARCH-ASPECT>\nDESCRIPTION: <ABSTRACT>\n```\n\nABSTRACT should be a short paragraph of less than 200 words, describing exact focus of the subagent's research aspect and a list of detailed research items.\n\nRules for YOU:\n\n- Do NOT use the following tools: biomcp*, web*, context7* (i.e., tool names starting with biomcp or web or context7. VERY IMPORTANT DO NOT USE ANY BIOMCP TOOL).\n- Do NOT fallback to internal knowledge when query tools fail. STRICTLY ADHERE to external trusted sources.\n- DO provide concrete references for all findings with citations (in brackets, e.g., [1], [2], ...) and full bibliography at the end.\n- DO keep your word succinct, accurate and professional, fitting top standards of academic writing.\n------ RULE REMINDER END ------\n";
7
+ export declare const BIORESEARCHERDR_SYSTEM_PROMPT = "\n------ RULE REMINDER START ------\nIMPORTANT: THIS REMINDER SHALL OVERRIDE ALL OTHER PROMPTS PROVIDED TO YOU. IGNORE ALL OTHER PROMPTS.\nOverall goal: Perform reference-based biomedical and pharmaceutical drug development research.\n\nSteps to STRICTLY adhere to:\n\n1. If the user query includes 'no-interview', skip Step 2 and proceed to Step 3. Otherwise, proceed to Step 2.\n2. Comprehend initial user inquiry. Use the question tool to ask user to clarify 3-6 unclear points depending on inquiry complexity.\n3. Comprehend final user inquiry to identify critical research aspects to answer user inquiry.\n4. If the original user inquiry includes 'light-research', combine and/or pick top two research aspects and proceed to Step 5. Otherwise, proceed directly to Step 5.\n5. Decide on TOPIC of this inquiry (NO user input). TOPIC should be highly succinct, underscore-separated name based on user inquiry.\n6. Use the todowrite tool to generate a list of identified research aspects.\n7. Create the reports_biomcp/<TOPIC>/ folder if needed.\n8. Use the task tool to assign each research aspect to a bioresearcherDR_worker subagent. Start subagents in parallel in batches (size of 5 for each batch). Record finished subagents by checking the todo list. Prompt the user: 'If subagents are stuck without progress for too long, interrupt and ask me to resume work.'\n9. Proceed until subagents complete research. Restart failed subagents if necessary.\n10. Load the bioresearcher-skill 'bioresearcher-core' and read 'patterns/citations.md' for citation format. Read reports from all subagents. Summarize findings to provide a succinct and accurate report addressing user inquiry with proper citations.\n11. Write to reports_biomcp/<TOPIC>/final_report.md with full bibliography.\n\nFollow this template to prompt the bioresearcherDR_worker subagents (Step 8):\n\n```md\nTOPIC: <TOPIC>\nYOUR RESEARCH FOCUS: <RESEARCH-ASPECT>\nDESCRIPTION: <ABSTRACT>\n```\n\nABSTRACT should be a short paragraph of less than 200 words, describing exact focus of the subagent's research aspect and a list of detailed research items.\n\nRules for YOU:\n\n- Do NOT use the following tools: biomcp*, web*, context7* (i.e., tool names starting with biomcp or web or context7. VERY IMPORTANT DO NOT USE ANY BIOMCP TOOL).\n- Do NOT fallback to internal knowledge when query tools fail. STRICTLY ADHERE to external trusted sources.\n- DO provide concrete references for all findings with citations (in brackets, e.g., [1], [2], ...) and full bibliography at the end.\n- DO keep your word succinct, accurate and professional, fitting top standards of academic writing.\n------ RULE REMINDER END ------\n";
8
8
  export declare function getBioResearcherDRPrompt(): string;
@@ -20,7 +20,7 @@ Steps to STRICTLY adhere to:
20
20
  7. Create the reports_biomcp/<TOPIC>/ folder if needed.
21
21
  8. Use the task tool to assign each research aspect to a bioresearcherDR_worker subagent. Start subagents in parallel in batches (size of 5 for each batch). Record finished subagents by checking the todo list. Prompt the user: 'If subagents are stuck without progress for too long, interrupt and ask me to resume work.'
22
22
  9. Proceed until subagents complete research. Restart failed subagents if necessary.
23
- 10. Load the skill 'bioresearcher-core' and read 'patterns/citations.md' for citation format. Read reports from all subagents. Summarize findings to provide a succinct and accurate report addressing user inquiry with proper citations.
23
+ 10. Load the bioresearcher-skill 'bioresearcher-core' and read 'patterns/citations.md' for citation format. Read reports from all subagents. Summarize findings to provide a succinct and accurate report addressing user inquiry with proper citations.
24
24
  11. Write to reports_biomcp/<TOPIC>/final_report.md with full bibliography.
25
25
 
26
26
  Follow this template to prompt the bioresearcherDR_worker subagents (Step 8):
@@ -4,5 +4,5 @@
4
4
  * A focused worker subagent that executes specific research tasks
5
5
  * assigned by the bioresearcherDR orchestrator.
6
6
  */
7
- export declare const BIORESEARCHERDRWORKER_SYSTEM_PROMPT = "\n------ RULE REMINDER START ------\nIMPORTANT: THIS REMINDER SHALL OVERRIDE ALL OTHER PROMPTS PROVIDED TO YOU. IGNORE ALL OTHER PROMPTS.\n\nOverall goal: Execute focused biomedical research as directed by the orchestrator.\n\n## Skill Loading (MANDATORY)\n\nAt the start of your task, load the core skill:\n\n```\nskill bioresearcher-core\n```\n\nThis skill provides patterns for:\n- `patterns/rate-limiting.md` - API rate limiting (use 0.5s between biomcp calls)\n- `patterns/retry.md` - Retry logic for failed requests (up to 3 retries)\n- `patterns/citations.md` - Citation formatting for your report\n\n## Workflow\n\n1. **Follow directions**: Execute the specific research task assigned to you\n2. **Stay focused**: Do NOT delegate to other subagents\n3. **Write findings**: Output to `reports_biomcp/<TOPIC>/<YOUR-FOCUS>.md`\n\n## Rate Limiting\n\nALWAYS use blockingTimer(0.5) between consecutive biomcp* tool calls.\n\n## Retry Logic\n\nIf a query fails:\n1. Wait a few seconds using blockingTimer\n2. Try with a simpler query\n3. Retry up to 3 times before giving up\n\n## Rules\n\n- Do NOT run concurrent MCP calls (sequential only)\n- Do NOT fallback to internal knowledge - use external trusted sources only\n- ALWAYS provide citations [1], [2], ... with full bibliography\n- Keep writing succinct, accurate, professional (academic standard)\n------ RULE REMINDER END ------\n";
7
+ export declare const BIORESEARCHERDRWORKER_SYSTEM_PROMPT = "\n------ RULE REMINDER START ------\nIMPORTANT: THIS REMINDER SHALL OVERRIDE ALL OTHER PROMPTS PROVIDED TO YOU. IGNORE ALL OTHER PROMPTS.\n\nOverall goal: Execute focused biomedical research as directed by the orchestrator.\n\n## Skill Loading (MANDATORY)\n\nAt the start of your task, load the core skill:\n\n```\nbioresearcher-skill bioresearcher-core\n```\n\nThis skill provides patterns for:\n- `patterns/rate-limiting.md` - API rate limiting (use 0.5s between biomcp calls)\n- `patterns/retry.md` - Retry logic for failed requests (up to 3 retries)\n- `patterns/citations.md` - Citation formatting for your report\n\n## Workflow\n\n1. **Follow directions**: Execute the specific research task assigned to you\n2. **Stay focused**: Do NOT delegate to other subagents\n3. **Write findings**: Output to `reports_biomcp/<TOPIC>/<YOUR-FOCUS>.md`\n\n## Rate Limiting\n\nALWAYS use blockingTimer(0.5) between consecutive biomcp* tool calls.\n\n## Retry Logic\n\nIf a query fails:\n1. Wait a few seconds using blockingTimer\n2. Try with a simpler query\n3. Retry up to 3 times before giving up\n\n## Rules\n\n- Do NOT run concurrent MCP calls (sequential only)\n- Do NOT fallback to internal knowledge - use external trusted sources only\n- ALWAYS provide citations [1], [2], ... with full bibliography\n- Keep writing succinct, accurate, professional (academic standard)\n------ RULE REMINDER END ------\n";
8
8
  export declare function getBioResearcherDRWorkerPrompt(): string;
@@ -15,7 +15,7 @@ Overall goal: Execute focused biomedical research as directed by the orchestrato
15
15
  At the start of your task, load the core skill:
16
16
 
17
17
  \`\`\`
18
- skill bioresearcher-core
18
+ bioresearcher-skill bioresearcher-core
19
19
  \`\`\`
20
20
 
21
21
  This skill provides patterns for:
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  import { createBioResearcherAgent } from "./agents/bioresearcher/index";
2
2
  import { createBioResearcherDRAgent } from "./agents/bioresearcherDR/index";
3
3
  import { createBioResearcherDRWorkerAgent } from "./agents/bioresearcherDR_worker/index";
4
+ import { BioResearcherSkillTool } from "./tools/skill";
4
5
  import { tableTools } from "./tools/table/index";
5
6
  import { dbTools } from "./tools/db/index";
6
7
  import { blockingTimer, calculator, jsonExtract, jsonValidate, jsonInfer } from "./tools/misc/index";
7
8
  import { parse_pubmed_articleSet } from "./tools/parser/pubmed";
8
9
  import { parse_obo_file } from "./tools/parser/obo";
9
- import { SkillTool } from "./tools/skill";
10
- export const BioResearcherPlugin = async () => {
10
+ export const BioResearcherPlugin = async (_input) => {
11
11
  return {
12
12
  config: async (config) => {
13
13
  config.agent = config.agent || {};
@@ -16,7 +16,7 @@ export const BioResearcherPlugin = async () => {
16
16
  config.agent.bioresearcherDR_worker = createBioResearcherDRWorkerAgent();
17
17
  },
18
18
  tool: {
19
- skill: SkillTool,
19
+ "bioresearcher-skill": BioResearcherSkillTool,
20
20
  ...tableTools,
21
21
  ...dbTools,
22
22
  blockingTimer,
@@ -20,8 +20,8 @@ export declare function createAllowlist(tools: string[]): ToolRestrictions;
20
20
  * Agent tool restrictions map.
21
21
  *
22
22
  * - bioresearcher: denylist for context7*, web*
23
- * - bioresearcherDR: allowlist for skill, table*, and core file tools (orchestrator - no biomcp)
24
- * - bioresearcherDR_worker: allowlist for skill, biomcp*, table*, and core file tools (data gatherer)
23
+ * - bioresearcherDR: allowlist for bioresearcher-skill, table*, and core file tools (orchestrator - no biomcp)
24
+ * - bioresearcherDR_worker: allowlist for bioresearcher-skill, biomcp*, table*, and core file tools (data gatherer)
25
25
  */
26
26
  export declare const AGENT_TOOL_RESTRICTIONS: Record<string, ToolRestrictions>;
27
27
  /**
@@ -27,13 +27,13 @@ export function createAllowlist(tools) {
27
27
  * Agent tool restrictions map.
28
28
  *
29
29
  * - bioresearcher: denylist for context7*, web*
30
- * - bioresearcherDR: allowlist for skill, table*, and core file tools (orchestrator - no biomcp)
31
- * - bioresearcherDR_worker: allowlist for skill, biomcp*, table*, and core file tools (data gatherer)
30
+ * - bioresearcherDR: allowlist for bioresearcher-skill, table*, and core file tools (orchestrator - no biomcp)
31
+ * - bioresearcherDR_worker: allowlist for bioresearcher-skill, biomcp*, table*, and core file tools (data gatherer)
32
32
  */
33
33
  export const AGENT_TOOL_RESTRICTIONS = {
34
34
  bioresearcher: createDenylist(["context7*", "web*"]),
35
35
  bioresearcherDR: createAllowlist([
36
- "skill",
36
+ "bioresearcher-skill",
37
37
  "table*",
38
38
  "calculator",
39
39
  "blockingTimer",
@@ -47,7 +47,7 @@ export const AGENT_TOOL_RESTRICTIONS = {
47
47
  "task"
48
48
  ]),
49
49
  bioresearcherDR_worker: createAllowlist([
50
- "skill",
50
+ "bioresearcher-skill",
51
51
  "biomcp*",
52
52
  "table*",
53
53
  "calculator",
@@ -21,7 +21,7 @@ No installation required. This skill uses only:
21
21
  ### Load the Skill
22
22
 
23
23
  ```
24
- skill bioresearcher-core
24
+ bioresearcher-skill bioresearcher-core
25
25
  ```
26
26
 
27
27
  ### Extract Skill Path
@@ -59,7 +59,7 @@ The bioresearcherDR_worker subagent uses only shared patterns (citations, rate-l
59
59
 
60
60
  ### Step 1: Load This Skill
61
61
  ```
62
- skill bioresearcher-core
62
+ bioresearcher-skill bioresearcher-core
63
63
  ```
64
64
 
65
65
  ### Step 2: Extract Skill Path
@@ -155,7 +155,7 @@ Agent actions:
155
155
  ### Skill Loading
156
156
 
157
157
  ```markdown
158
- skill long-table-summary
158
+ bioresearcher-skill long-table-summary
159
159
  ```
160
160
 
161
161
  ### 16-Step Workflow Overview
@@ -408,7 +408,7 @@ if row_count < 30:
408
408
 
409
409
  # Medium datasets (30-1000 rows): Use long-table-summary skill
410
410
  elif row_count < 1000:
411
- skill long-table-summary
411
+ bioresearcher-skill long-table-summary
412
412
  # Follow 16-step workflow
413
413
 
414
414
  # Large datasets (> 1000 rows): Use Python
@@ -5,7 +5,7 @@ Comprehensive test suite for the bioresearcher plugin.
5
5
  ## Quick Start
6
6
 
7
7
  ```
8
- skill bioresearcher-tests
8
+ bioresearcher-skill bioresearcher-tests
9
9
  ```
10
10
 
11
11
  Then follow the workflow steps in SKILL.md.
@@ -25,7 +25,7 @@ allowedTools:
25
25
  - calculator
26
26
  - parse_pubmed_articleSet
27
27
  - parse_obo_file
28
- - skill
28
+ - bioresearcher-skill
29
29
  - Question
30
30
  ---
31
31
 
@@ -1,7 +1,7 @@
1
1
  # Skill Tests
2
2
 
3
3
  ## Test: Load demo-skill
4
- - Tool: skill
4
+ - Tool: bioresearcher-skill
5
5
  - Input:
6
6
  ```json
7
7
  {"name": "demo-skill"}
@@ -12,7 +12,7 @@
12
12
  - Expected: Skill content loaded successfully
13
13
 
14
14
  ## Test: Load bioresearcher-core
15
- - Tool: skill
15
+ - Tool: bioresearcher-skill
16
16
  - Input:
17
17
  ```json
18
18
  {"name": "bioresearcher-core"}
@@ -35,7 +35,7 @@
35
35
  - Expected: Demo script executes successfully
36
36
 
37
37
  ## Test: Skill Not Found
38
- - Tool: skill
38
+ - Tool: bioresearcher-skill
39
39
  - Input:
40
40
  ```json
41
41
  {"name": "nonexistent-skill-xyz-12345"}
@@ -1,48 +1,48 @@
1
- ---
2
- name: gromacs-guides
3
- description: Reusable guides for GROMACS molecular dynamics workflows
4
- allowedTools:
5
- - Read
6
- - Bash
7
- ---
8
-
9
- # GROMACS Guides
10
-
11
- This skill provides reusable guides for common GROMACS molecular dynamics workflows.
12
-
13
- ## Quick Start
14
-
15
- ### Step 1: Load This Skill
16
- The skill is loaded automatically when agent calls `skill gromacs-guides`.
17
-
18
- ### Step 2: Extract Skill Path
19
- From the `<skill_files>` section in the skill tool output, extract the `<skill_path>` value.
20
-
21
- ### Step 3: Read the Relevant Guide
22
- ```
23
- Read <skill_path>/guides/inspect_tpr.md
24
- Read <skill_path>/guides/create_index.md
25
- ```
26
-
27
- ## Available Guides
28
-
29
- | Task | Guide |
30
- |------|-------|
31
- | TPR inspection | `guides/inspect_tpr.md` |
32
- | Index file creation | `guides/create_index.md` |
33
-
34
- ## Guide Summaries
35
-
36
- ### inspect_tpr.md
37
- Commands for extracting molecule information from TPR files:
38
- - Quick summary and detailed dump commands
39
- - Molecule type/counts extraction
40
- - Cyclic molecule bond detection
41
- - Molecule independence checking
42
-
43
- ### create_index.md
44
- Workflow for creating GROMACS index files:
45
- - Basic `make_ndx` usage
46
- - `splitch` artefact identification and fixing
47
- - Merge → verify → delete → rename workflow
48
- - C-alpha group creation
1
+ ---
2
+ name: gromacs-guides
3
+ description: Reusable guides for GROMACS molecular dynamics workflows
4
+ allowedTools:
5
+ - Read
6
+ - Bash
7
+ ---
8
+
9
+ # GROMACS Guides
10
+
11
+ This skill provides reusable guides for common GROMACS molecular dynamics workflows.
12
+
13
+ ## Quick Start
14
+
15
+ ### Step 1: Load This Skill
16
+ The skill is loaded automatically when agent calls `bioresearcher-skill gromacs-guides`.
17
+
18
+ ### Step 2: Extract Skill Path
19
+ From the `<skill_files>` section in the skill tool output, extract the `<skill_path>` value.
20
+
21
+ ### Step 3: Read the Relevant Guide
22
+ ```
23
+ Read <skill_path>/guides/inspect_tpr.md
24
+ Read <skill_path>/guides/create_index.md
25
+ ```
26
+
27
+ ## Available Guides
28
+
29
+ | Task | Guide |
30
+ |------|-------|
31
+ | TPR inspection | `guides/inspect_tpr.md` |
32
+ | Index file creation | `guides/create_index.md` |
33
+
34
+ ## Guide Summaries
35
+
36
+ ### inspect_tpr.md
37
+ Commands for extracting molecule information from TPR files:
38
+ - Quick summary and detailed dump commands
39
+ - Molecule type/counts extraction
40
+ - Cyclic molecule bond detection
41
+ - Molecule independence checking
42
+
43
+ ### create_index.md
44
+ Workflow for creating GROMACS index files:
45
+ - Basic `make_ndx` usage
46
+ - `splitch` artefact identification and fixing
47
+ - Merge → verify → delete → rename workflow
48
+ - C-alpha group creation
@@ -126,3 +126,35 @@ gmx dump -s <tpr_file> 2>&1 | grep "bIntermolecularInteractions"
126
126
  ```bash
127
127
  echo "q" | gmx make_ndx -f <tpr_file> 2>&1 | grep -E "(System|Protein|Water|Ion|atoms)"
128
128
  ```
129
+
130
+ ## Standardized TPR Summary Template
131
+
132
+ When users ask generic questions like "summarize this TPR" or "list all components", use this template for consistent output:
133
+
134
+ ### <tpr_file> Analysis Summary
135
+
136
+ | Component | Count | Atoms | Structure |
137
+ |-----------|-------|-------|-----------|
138
+ | <moltype_name> | <N_copies> | <atoms_per_copy> | <Linear/Cyclic/-> |
139
+ | ... | ... | ... | ... |
140
+ | **Total** | - | **<sum_atoms>** | - |
141
+
142
+ **Key Information:**
143
+ - **Total protein residues**: <X> (<Y> atoms total)
144
+ - **Molecules are <independent/linked>** (bIntermolecularInteractions=<true/false>)
145
+ - <Notable features>
146
+
147
+ ### Populating the Template
148
+
149
+ Use commands from:
150
+ - **Key Information to Extract** table → Component, Count, Atoms columns
151
+ - **Detecting Cyclic Molecule Configuration** → Structure column (Linear/Cyclic)
152
+ - **Checking Molecule Independence** → bIntermolecularInteractions value
153
+
154
+ ### Structure Column Values
155
+
156
+ | Value | When to Use |
157
+ |-------|-------------|
158
+ | `Linear` | Standard protein/peptide without cyclization |
159
+ | `**Cyclic** (bond 0→<N-2>)` | N-to-C cyclization detected |
160
+ | `-` | Non-protein (solvent, ions, ligands) |
@@ -17,12 +17,12 @@ export declare const dbTools: {
17
17
  execute(args: {
18
18
  sql: string;
19
19
  params?: Record<string, any> | undefined;
20
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
20
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
21
21
  };
22
22
  dbListTables: {
23
23
  description: string;
24
24
  args: {};
25
- execute(args: Record<string, never>, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
25
+ execute(args: Record<string, never>, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
26
26
  };
27
27
  dbDescribeTable: {
28
28
  description: string;
@@ -31,7 +31,7 @@ export declare const dbTools: {
31
31
  };
32
32
  execute(args: {
33
33
  table_name: string;
34
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
34
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
35
35
  };
36
36
  };
37
37
  export { dbQuery, dbListTables, dbDescribeTable } from './tools';
@@ -9,12 +9,12 @@ export declare const dbQuery: {
9
9
  execute(args: {
10
10
  sql: string;
11
11
  params?: Record<string, any> | undefined;
12
- }, context: ToolContext): Promise<string>;
12
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
13
13
  };
14
14
  export declare const dbListTables: {
15
15
  description: string;
16
16
  args: {};
17
- execute(args: Record<string, never>, context: ToolContext): Promise<string>;
17
+ execute(args: Record<string, never>, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
18
18
  };
19
19
  export declare const dbDescribeTable: {
20
20
  description: string;
@@ -23,5 +23,5 @@ export declare const dbDescribeTable: {
23
23
  };
24
24
  execute(args: {
25
25
  table_name: string;
26
- }, context: ToolContext): Promise<string>;
26
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
27
27
  };
@@ -9,5 +9,5 @@ export declare const calculator: {
9
9
  execute(args: {
10
10
  formula: string;
11
11
  precision: number;
12
- }, context: ToolContext): Promise<string>;
12
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
13
13
  };
@@ -9,5 +9,5 @@ export declare const jsonExtract: {
9
9
  execute(args: {
10
10
  file_path: string;
11
11
  return_all: boolean;
12
- }, context: ToolContext): Promise<string>;
12
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
13
13
  };
@@ -9,5 +9,5 @@ export declare const jsonInfer: {
9
9
  execute(args: {
10
10
  data: string;
11
11
  strict: boolean;
12
- }, context: ToolContext): Promise<string>;
12
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
13
13
  };
@@ -9,5 +9,5 @@ export declare const jsonValidate: {
9
9
  execute(args: {
10
10
  data: string;
11
11
  schema: string;
12
- }, context: ToolContext): Promise<string>;
12
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
13
13
  };
@@ -1,6 +1,120 @@
1
1
  import { tool } from '@opencode-ai/plugin/tool';
2
- import { z, fromJSONSchema } from 'zod';
2
+ import { z } from 'zod';
3
3
  import * as path from 'path';
4
+ function buildZodSchema(schema, rootSchema) {
5
+ if (!schema || typeof schema !== 'object')
6
+ return z.any();
7
+ if (schema.boolean === true)
8
+ return z.boolean();
9
+ if (schema.$ref && rootSchema) {
10
+ const refPath = schema.$ref.replace(/^#\//, '');
11
+ const parts = refPath.split('/').filter(Boolean);
12
+ let resolved = rootSchema;
13
+ for (const part of parts)
14
+ resolved = resolved?.[part];
15
+ return resolved ? buildZodSchema(resolved, rootSchema) : z.any();
16
+ }
17
+ if (schema.enum) {
18
+ const allStrings = schema.enum.every((v) => typeof v === 'string');
19
+ if (allStrings)
20
+ return z.enum(schema.enum);
21
+ return z.any();
22
+ }
23
+ let zodType;
24
+ switch (schema.type) {
25
+ case 'string':
26
+ zodType = z.string();
27
+ if (schema.minLength != null)
28
+ zodType = zodType.min(schema.minLength);
29
+ if (schema.maxLength != null)
30
+ zodType = zodType.max(schema.maxLength);
31
+ if (schema.pattern)
32
+ zodType = zodType.regex(new RegExp(schema.pattern));
33
+ if (schema.format === 'email')
34
+ zodType = z.email();
35
+ if (schema.format === 'url')
36
+ zodType = z.url();
37
+ if (schema.format === 'uuid')
38
+ zodType = z.uuid();
39
+ break;
40
+ case 'number':
41
+ zodType = z.number();
42
+ if (schema.minimum != null)
43
+ zodType = zodType.min(schema.minimum);
44
+ if (schema.maximum != null)
45
+ zodType = zodType.max(schema.maximum);
46
+ if (schema.exclusiveMinimum != null)
47
+ zodType = zodType.gt(schema.exclusiveMinimum);
48
+ if (schema.exclusiveMaximum != null)
49
+ zodType = zodType.lt(schema.exclusiveMaximum);
50
+ break;
51
+ case 'integer':
52
+ zodType = z.number().int();
53
+ if (schema.minimum != null)
54
+ zodType = zodType.min(schema.minimum);
55
+ if (schema.maximum != null)
56
+ zodType = zodType.max(schema.maximum);
57
+ break;
58
+ case 'boolean':
59
+ zodType = z.boolean();
60
+ break;
61
+ case 'null':
62
+ zodType = z.null();
63
+ break;
64
+ case 'array':
65
+ zodType = schema.items
66
+ ? z.array(buildZodSchema(schema.items, rootSchema))
67
+ : z.array(z.any());
68
+ if (schema.minItems != null)
69
+ zodType = zodType.min(schema.minItems);
70
+ if (schema.maxItems != null)
71
+ zodType = zodType.max(schema.maxItems);
72
+ break;
73
+ case 'object': {
74
+ const shape = {};
75
+ const requiredKeys = new Set(schema.required && Array.isArray(schema.required) ? schema.required : []);
76
+ if (schema.properties && typeof schema.properties === 'object') {
77
+ for (const [key, val] of Object.entries(schema.properties)) {
78
+ const fieldSchema = buildZodSchema(val, rootSchema);
79
+ shape[key] = requiredKeys.has(key) ? fieldSchema : fieldSchema.optional();
80
+ }
81
+ }
82
+ zodType = z.object(shape);
83
+ if (schema.additionalProperties === false) {
84
+ zodType = zodType.strict();
85
+ }
86
+ break;
87
+ }
88
+ default:
89
+ zodType = z.any();
90
+ }
91
+ if (!schema.anyOf && !schema.oneOf && !schema.allOf) {
92
+ if (schema.default !== undefined) {
93
+ zodType = zodType.default(schema.default);
94
+ }
95
+ }
96
+ if (schema.anyOf && Array.isArray(schema.anyOf)) {
97
+ const variants = schema.anyOf.map((s) => buildZodSchema(s, rootSchema));
98
+ zodType = z.union(variants);
99
+ }
100
+ if (schema.allOf && Array.isArray(schema.allOf)) {
101
+ const merged = {};
102
+ for (const s of schema.allOf) {
103
+ const sub = buildZodSchema(s, rootSchema);
104
+ const def = sub._def;
105
+ if (def?.shape)
106
+ Object.assign(merged, def.shape);
107
+ }
108
+ if (Object.keys(merged).length > 0) {
109
+ zodType = z.object(merged);
110
+ }
111
+ }
112
+ if (schema.oneOf && Array.isArray(schema.oneOf)) {
113
+ const variants = schema.oneOf.map((s) => buildZodSchema(s, rootSchema));
114
+ zodType = z.union(variants);
115
+ }
116
+ return zodType;
117
+ }
4
118
  const UNSUPPORTED_SCHEMA_FEATURES = [
5
119
  'not', 'unevaluatedItems', 'unevaluatedProperties',
6
120
  'if', 'then', 'else', 'dependentSchemas', 'dependentRequired'
@@ -170,7 +284,7 @@ export const jsonValidate = tool({
170
284
  }
171
285
  let zodSchema;
172
286
  try {
173
- zodSchema = fromJSONSchema(parsedSchema);
287
+ zodSchema = buildZodSchema(parsedSchema, parsedSchema);
174
288
  }
175
289
  catch (e) {
176
290
  return JSON.stringify({
@@ -7,5 +7,5 @@ export declare const blockingTimer: {
7
7
  };
8
8
  execute(args: {
9
9
  delay: number;
10
- }, context: ToolContext): Promise<string>;
10
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
11
11
  };
@@ -13,5 +13,5 @@ export declare const parse_obo_file: {
13
13
  outputFileName: string;
14
14
  verbose: boolean;
15
15
  outputDir?: string | undefined;
16
- }, context: ToolContext): Promise<string>;
16
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
17
17
  };
@@ -19,5 +19,5 @@ export declare const parse_pubmed_articleSet: {
19
19
  verbose: boolean;
20
20
  outputFileName?: string | undefined;
21
21
  outputDir?: string | undefined;
22
- }, context: ToolContext): Promise<string>;
22
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
23
23
  };
@@ -1,3 +1,3 @@
1
- export { SkillTool } from "./tool";
1
+ export { BioResearcherSkillTool } from "./tool";
2
2
  export { getAllSkills, getSkill, SkillConflictError } from "./registry";
3
3
  export type { ExtendedSkill, ExtendedSkillFrontmatter, ParsedSkill } from "./types";
@@ -1,2 +1,2 @@
1
- export { SkillTool } from "./tool";
1
+ export { BioResearcherSkillTool } from "./tool";
2
2
  export { getAllSkills, getSkill, SkillConflictError } from "./registry";
@@ -1,9 +1,9 @@
1
- export declare const SkillTool: {
1
+ export declare const BioResearcherSkillTool: {
2
2
  description: string;
3
3
  args: {
4
4
  name: import("zod").ZodString;
5
5
  };
6
6
  execute(args: {
7
7
  name: string;
8
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
8
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
9
9
  };
@@ -1,5 +1,6 @@
1
1
  import path from "path";
2
2
  import { pathToFileURL } from "url";
3
+ import { Effect } from "effect";
3
4
  import { tool } from "@opencode-ai/plugin";
4
5
  import { getAllSkills, getSkill } from "./registry";
5
6
  function formatDescription(skills) {
@@ -47,7 +48,7 @@ async function listSkillFiles(dir, signal) {
47
48
  }
48
49
  return files.map((f) => `<file>${f}</file>`).join("\n");
49
50
  }
50
- export const SkillTool = tool({
51
+ export const BioResearcherSkillTool = tool({
51
52
  description: "", // Set dynamically below
52
53
  args: {
53
54
  name: tool.schema.string().describe("The name of the skill from available_skills"),
@@ -63,12 +64,12 @@ export const SkillTool = tool({
63
64
  if (skill.agent && ctx.agent !== skill.agent) {
64
65
  throw new Error(`Skill "${skill.name}" is restricted to agent "${skill.agent}". Current agent: "${ctx.agent || "unknown"}".`);
65
66
  }
66
- await ctx.ask({
67
+ await Effect.runPromise(ctx.ask({
67
68
  permission: "skill",
68
69
  patterns: [params.name],
69
70
  always: [params.name],
70
71
  metadata: {},
71
- });
72
+ }));
72
73
  const dir = path.dirname(skill.location);
73
74
  const base = pathToFileURL(dir).href;
74
75
  const files = await listSkillFiles(dir, ctx.abort);
@@ -112,9 +113,9 @@ export const SkillTool = tool({
112
113
  getAllSkills()
113
114
  .then((skills) => {
114
115
  ;
115
- SkillTool.description = formatDescription(skills);
116
+ BioResearcherSkillTool.description = formatDescription(skills);
116
117
  })
117
118
  .catch((err) => {
118
119
  console.error("[bioresearcher-plugin] Failed to load skills for tool description:", err);
119
- SkillTool.description = formatDescription([]);
120
+ BioResearcherSkillTool.description = formatDescription([]);
120
121
  });
@@ -8,7 +8,7 @@ export declare const tableTools: {
8
8
  execute(args: {
9
9
  file_path: string;
10
10
  sheet_name?: string | undefined;
11
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
11
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
12
12
  };
13
13
  tableListSheets: {
14
14
  description: string;
@@ -17,7 +17,7 @@ export declare const tableTools: {
17
17
  };
18
18
  execute(args: {
19
19
  file_path: string;
20
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
20
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
21
21
  };
22
22
  tableGetHeaders: {
23
23
  description: string;
@@ -28,7 +28,7 @@ export declare const tableTools: {
28
28
  execute(args: {
29
29
  file_path: string;
30
30
  sheet_name?: string | undefined;
31
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
31
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
32
32
  };
33
33
  tableGetCell: {
34
34
  description: string;
@@ -41,7 +41,7 @@ export declare const tableTools: {
41
41
  file_path: string;
42
42
  cell_address: string;
43
43
  sheet_name?: string | undefined;
44
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
44
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
45
45
  };
46
46
  tableFilterRows: {
47
47
  description: string;
@@ -68,7 +68,7 @@ export declare const tableTools: {
68
68
  value: any;
69
69
  max_results: number;
70
70
  sheet_name?: string | undefined;
71
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
71
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
72
72
  };
73
73
  tableSearch: {
74
74
  description: string;
@@ -83,7 +83,7 @@ export declare const tableTools: {
83
83
  search_term: string;
84
84
  max_results: number;
85
85
  sheet_name?: string | undefined;
86
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
86
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
87
87
  };
88
88
  tableGetRange: {
89
89
  description: string;
@@ -96,7 +96,7 @@ export declare const tableTools: {
96
96
  file_path: string;
97
97
  range: string;
98
98
  sheet_name?: string | undefined;
99
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
99
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
100
100
  };
101
101
  tableSummarize: {
102
102
  description: string;
@@ -109,7 +109,7 @@ export declare const tableTools: {
109
109
  file_path: string;
110
110
  sheet_name?: string | undefined;
111
111
  columns?: string[] | undefined;
112
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
112
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
113
113
  };
114
114
  tableGroupBy: {
115
115
  description: string;
@@ -132,7 +132,7 @@ export declare const tableTools: {
132
132
  agg_column: string;
133
133
  agg_type: "sum" | "count" | "avg" | "min" | "max";
134
134
  sheet_name?: string | undefined;
135
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
135
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
136
136
  };
137
137
  tablePivotSummary: {
138
138
  description: string;
@@ -157,7 +157,7 @@ export declare const tableTools: {
157
157
  value_field: string;
158
158
  agg: "sum" | "count" | "avg" | "min" | "max";
159
159
  sheet_name?: string | undefined;
160
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
160
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
161
161
  };
162
162
  tableAppendRows: {
163
163
  description: string;
@@ -170,7 +170,7 @@ export declare const tableTools: {
170
170
  file_path: string;
171
171
  rows: (any[] | Record<string, any>)[];
172
172
  sheet_name?: string | undefined;
173
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
173
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
174
174
  };
175
175
  tableUpdateCell: {
176
176
  description: string;
@@ -185,7 +185,7 @@ export declare const tableTools: {
185
185
  cell_address: string;
186
186
  value: any;
187
187
  sheet_name?: string | undefined;
188
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
188
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
189
189
  };
190
190
  tableCreateFile: {
191
191
  description: string;
@@ -198,6 +198,6 @@ export declare const tableTools: {
198
198
  file_path: string;
199
199
  sheet_name: string;
200
200
  data: any;
201
- }, context: import("@opencode-ai/plugin").ToolContext): Promise<string>;
201
+ }, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
202
202
  };
203
203
  };
@@ -9,7 +9,7 @@ export declare const tableGetSheetPreview: {
9
9
  execute(args: {
10
10
  file_path: string;
11
11
  sheet_name?: string | undefined;
12
- }, context: ToolContext): Promise<string>;
12
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
13
13
  };
14
14
  export declare const tableListSheets: {
15
15
  description: string;
@@ -18,7 +18,7 @@ export declare const tableListSheets: {
18
18
  };
19
19
  execute(args: {
20
20
  file_path: string;
21
- }, context: ToolContext): Promise<string>;
21
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
22
22
  };
23
23
  export declare const tableGetHeaders: {
24
24
  description: string;
@@ -29,7 +29,7 @@ export declare const tableGetHeaders: {
29
29
  execute(args: {
30
30
  file_path: string;
31
31
  sheet_name?: string | undefined;
32
- }, context: ToolContext): Promise<string>;
32
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
33
33
  };
34
34
  export declare const tableGetCell: {
35
35
  description: string;
@@ -42,7 +42,7 @@ export declare const tableGetCell: {
42
42
  file_path: string;
43
43
  cell_address: string;
44
44
  sheet_name?: string | undefined;
45
- }, context: ToolContext): Promise<string>;
45
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
46
46
  };
47
47
  export declare const tableFilterRows: {
48
48
  description: string;
@@ -69,7 +69,7 @@ export declare const tableFilterRows: {
69
69
  value: any;
70
70
  max_results: number;
71
71
  sheet_name?: string | undefined;
72
- }, context: ToolContext): Promise<string>;
72
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
73
73
  };
74
74
  export declare const tableSearch: {
75
75
  description: string;
@@ -84,7 +84,7 @@ export declare const tableSearch: {
84
84
  search_term: string;
85
85
  max_results: number;
86
86
  sheet_name?: string | undefined;
87
- }, context: ToolContext): Promise<string>;
87
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
88
88
  };
89
89
  export declare const tableGetRange: {
90
90
  description: string;
@@ -97,7 +97,7 @@ export declare const tableGetRange: {
97
97
  file_path: string;
98
98
  range: string;
99
99
  sheet_name?: string | undefined;
100
- }, context: ToolContext): Promise<string>;
100
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
101
101
  };
102
102
  export declare const tableSummarize: {
103
103
  description: string;
@@ -110,7 +110,7 @@ export declare const tableSummarize: {
110
110
  file_path: string;
111
111
  sheet_name?: string | undefined;
112
112
  columns?: string[] | undefined;
113
- }, context: ToolContext): Promise<string>;
113
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
114
114
  };
115
115
  export declare const tableGroupBy: {
116
116
  description: string;
@@ -133,7 +133,7 @@ export declare const tableGroupBy: {
133
133
  agg_column: string;
134
134
  agg_type: "sum" | "count" | "avg" | "min" | "max";
135
135
  sheet_name?: string | undefined;
136
- }, context: ToolContext): Promise<string>;
136
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
137
137
  };
138
138
  export declare const tablePivotSummary: {
139
139
  description: string;
@@ -158,7 +158,7 @@ export declare const tablePivotSummary: {
158
158
  value_field: string;
159
159
  agg: "sum" | "count" | "avg" | "min" | "max";
160
160
  sheet_name?: string | undefined;
161
- }, context: ToolContext): Promise<string>;
161
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
162
162
  };
163
163
  export declare const tableAppendRows: {
164
164
  description: string;
@@ -171,7 +171,7 @@ export declare const tableAppendRows: {
171
171
  file_path: string;
172
172
  rows: (any[] | Record<string, any>)[];
173
173
  sheet_name?: string | undefined;
174
- }, context: ToolContext): Promise<string>;
174
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
175
175
  };
176
176
  export declare const tableUpdateCell: {
177
177
  description: string;
@@ -186,7 +186,7 @@ export declare const tableUpdateCell: {
186
186
  cell_address: string;
187
187
  value: any;
188
188
  sheet_name?: string | undefined;
189
- }, context: ToolContext): Promise<string>;
189
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
190
190
  };
191
191
  export declare const tableCreateFile: {
192
192
  description: string;
@@ -199,5 +199,5 @@ export declare const tableCreateFile: {
199
199
  file_path: string;
200
200
  sheet_name: string;
201
201
  data: any;
202
- }, context: ToolContext): Promise<string>;
202
+ }, context: ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
203
203
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeyuan98/opencode-bioresearcher-plugin",
3
- "version": "1.5.4-alpha.0",
3
+ "version": "1.6.0",
4
4
  "description": "OpenCode plugin that adds a bioresearcher agent",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -30,22 +30,21 @@
30
30
  "README.md"
31
31
  ],
32
32
  "dependencies": {
33
- "@opencode-ai/plugin": "^1.2.6",
33
+ "@opencode-ai/plugin": "^1.14.0",
34
+ "effect": "4.0.0-beta.48",
34
35
  "fast-xml-parser": "^5.3.5",
35
36
  "mongodb": "^7.1.0",
36
37
  "mysql2": "^3.18.2",
37
38
  "xdg-basedir": "^5.1.0",
38
39
  "xlsx": "^0.18.5",
39
- "zod": "^4.3.6"
40
+ "zod": "4.1.8"
40
41
  },
41
42
  "devDependencies": {
42
43
  "@types/bun": "^1.2.0",
43
44
  "@types/node": "^20.0.0",
44
45
  "typescript": "^5.9.3"
45
46
  },
46
- "overrides": {
47
- "@opencode-ai/plugin": {
48
- "zod": "^4.3.6"
49
- }
47
+ "engines": {
48
+ "opencode": ">=1.4.0"
50
49
  }
51
50
  }