@yeyuan98/opencode-bioresearcher-plugin 1.3.1 → 1.4.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.
Files changed (36) hide show
  1. package/README.md +14 -0
  2. package/dist/index.js +4 -1
  3. package/dist/misc-tools/index.d.ts +3 -0
  4. package/dist/misc-tools/index.js +3 -0
  5. package/dist/misc-tools/json-extract.d.ts +13 -0
  6. package/dist/misc-tools/json-extract.js +394 -0
  7. package/dist/misc-tools/json-infer.d.ts +13 -0
  8. package/dist/misc-tools/json-infer.js +199 -0
  9. package/dist/misc-tools/json-tools.d.ts +33 -0
  10. package/dist/misc-tools/json-tools.js +187 -0
  11. package/dist/misc-tools/json-validate.d.ts +13 -0
  12. package/dist/misc-tools/json-validate.js +228 -0
  13. package/dist/skills/bioresearcher-core/README.md +210 -0
  14. package/dist/skills/bioresearcher-core/SKILL.md +128 -0
  15. package/dist/skills/bioresearcher-core/examples/contexts.json +29 -0
  16. package/dist/skills/bioresearcher-core/examples/data-exchange-example.md +303 -0
  17. package/dist/skills/bioresearcher-core/examples/template.md +49 -0
  18. package/dist/skills/bioresearcher-core/patterns/calculator.md +215 -0
  19. package/dist/skills/bioresearcher-core/patterns/data-exchange.md +406 -0
  20. package/dist/skills/bioresearcher-core/patterns/json-tools.md +263 -0
  21. package/dist/skills/bioresearcher-core/patterns/progress.md +127 -0
  22. package/dist/skills/bioresearcher-core/patterns/retry.md +110 -0
  23. package/dist/skills/bioresearcher-core/patterns/shell-commands.md +79 -0
  24. package/dist/skills/bioresearcher-core/patterns/subagent-waves.md +186 -0
  25. package/dist/skills/bioresearcher-core/patterns/table-tools.md +260 -0
  26. package/dist/skills/bioresearcher-core/patterns/user-confirmation.md +187 -0
  27. package/dist/skills/bioresearcher-core/python/template.md +273 -0
  28. package/dist/skills/bioresearcher-core/python/template.py +323 -0
  29. package/dist/skills/long-table-summary/SKILL.md +374 -0
  30. package/dist/skills/long-table-summary/__init__.py +3 -0
  31. package/dist/skills/long-table-summary/combine_outputs.py +345 -0
  32. package/dist/skills/long-table-summary/pyproject.toml +11 -0
  33. package/dist/skills/pubmed-weekly/SKILL.md +329 -329
  34. package/dist/skills/pubmed-weekly/pubmed_weekly.py +411 -411
  35. package/dist/skills/pubmed-weekly/pyproject.toml +8 -8
  36. package/package.json +7 -2
@@ -0,0 +1,186 @@
1
+ # Subagent Waves Pattern
2
+
3
+ Process multiple items with parallel subagents organized in waves.
4
+
5
+ ## Overview
6
+
7
+ Use this pattern when you need to process many items in parallel while controlling concurrency.
8
+
9
+ ## Requirements
10
+
11
+ > **CRITICAL:** This pattern requires the `Task` tool to be available in your environment.
12
+ >
13
+ > - If the Task tool is not available, **subagent waves are not possible**
14
+ > - Alternative: Process items sequentially or use external batch processing
15
+ > - Check tool availability before implementing this pattern
16
+ >
17
+ > To verify Task tool availability, check your environment's tool list.
18
+
19
+ ## Pattern Algorithm
20
+
21
+ ```
22
+ 1. Calculate total items and wave_size
23
+ 2. Group items into waves of wave_size items each
24
+ 3. For each wave:
25
+ a. Launch wave_size subagents in parallel via Task tool
26
+ b. Wait for all subagents to complete
27
+ c. Track progress (use progress pattern)
28
+ d. Validate outputs using jsonExtract + jsonValidate
29
+ e. Collect validated outputs
30
+ 4. Handle failed items (use retry pattern)
31
+ 5. Combine all outputs using jsonExtract or table tools
32
+ ```
33
+
34
+ ## Parameters
35
+
36
+ | Parameter | Default | Description |
37
+ |-----------|---------|-------------|
38
+ | `wave_size` | 3 | Number of parallel subagents per wave |
39
+ | `subagent_type` | "general" | Type of subagent to launch |
40
+
41
+ ## Key Principles
42
+
43
+ 1. **File-based prompts**: Subagents read prompt files, not inline prompts
44
+ 2. **File-based outputs**: Subagents write to output files as JSON
45
+ 3. **Schema validation**: Every output validated before processing
46
+ 4. **Wave coordination**: Wait for entire wave before starting next
47
+ 5. **Progress tracking**: Report after each wave completes
48
+
49
+ ## Tool: Task
50
+
51
+ ```
52
+ task(
53
+ subagent_type: string,
54
+ description: string,
55
+ prompt: string
56
+ )
57
+ ```
58
+
59
+ ## Example: Launch Wave of 3 Subagents
60
+
61
+ ```typescript
62
+ // Wave 1 - Launch 3 subagents in parallel
63
+ task(
64
+ subagent_type="general",
65
+ description="Process batch 001",
66
+ prompt="Read your prompt from ./.work/batch001.md and perform the task described there exactly as written."
67
+ )
68
+ task(
69
+ subagent_type="general",
70
+ description="Process batch 002",
71
+ prompt="Read your prompt from ./.work/batch002.md and perform the task described there exactly as written."
72
+ )
73
+ task(
74
+ subagent_type="general",
75
+ description="Process batch 003",
76
+ prompt="Read your prompt from ./.work/batch003.md and perform the task described there exactly as written."
77
+ )
78
+ // Wait for all 3 to complete before Wave 2
79
+ ```
80
+
81
+ ## Example: Full Wave Processing Workflow
82
+
83
+ ```
84
+ # Configuration
85
+ total_items = 12
86
+ wave_size = 3
87
+ total_waves = ceil(total_items / wave_size) # 4 waves
88
+
89
+ # Create prompt files first (using template.py)
90
+ uv run python <skill_path>/python/template.py generate-batches \
91
+ --template template.md \
92
+ --contexts contexts.json \
93
+ --output-dir ./prompts
94
+
95
+ # Process in waves
96
+ for wave_num in range(1, total_waves + 1):
97
+ # Launch wave
98
+ start_idx = (wave_num - 1) * wave_size + 1
99
+ end_idx = min(wave_num * wave_size, total_items)
100
+
101
+ for batch_num in range(start_idx, end_idx + 1):
102
+ task(
103
+ subagent_type="general",
104
+ description=f"Process batch {batch_num:03d}",
105
+ prompt=f"Read your prompt from ./prompts/batch{batch_num:03d}.md and perform the task."
106
+ )
107
+
108
+ # Wait for wave completion
109
+ # (Task tool handles this - next task call waits)
110
+
111
+ # Report progress
112
+ completed = end_idx
113
+ percent = calculator(formula=f"({completed} / {total_items}) * 100")
114
+ report(f"Progress: {completed}/{total_items} batches ({percent}%)")
115
+ ```
116
+
117
+ ## Output Validation
118
+
119
+ After each wave, validate outputs:
120
+
121
+ ```
122
+ # For each output file
123
+ result = jsonExtract(file_path="./outputs/batch001.md")
124
+ if not result.success:
125
+ log_error("Failed to extract JSON from batch001.md")
126
+ continue
127
+
128
+ # Validate against schema
129
+ validation = jsonValidate(
130
+ data=json.dumps(result.data),
131
+ schema=expected_schema
132
+ )
133
+ if not validation.valid:
134
+ log_error(f"Schema validation failed for batch001.md: {validation.errors}")
135
+ continue
136
+
137
+ # Collect valid output
138
+ valid_outputs.append(result.data)
139
+ ```
140
+
141
+ ## Handling Failed Batches
142
+
143
+ After all waves complete:
144
+
145
+ ```
146
+ # Check for missing outputs
147
+ expected_files = [f"batch{i:03d}.md" for i in range(1, total_items + 1)]
148
+ missing = [f for f in expected_files if not exists(f"./outputs/{f}")]
149
+
150
+ if missing:
151
+ # Use retry pattern
152
+ for batch_file in missing:
153
+ retry_subagent(batch_file, max_attempts=3, delay=2)
154
+ ```
155
+
156
+ ## Combining Outputs
157
+
158
+ For small batches (<10 files), use table tools:
159
+
160
+ ```
161
+ # Extract all JSON
162
+ all_data = []
163
+ for file in output_files:
164
+ result = jsonExtract(file_path=file)
165
+ if result.success:
166
+ all_data.extend(result.data["summaries"])
167
+
168
+ # Create combined Excel
169
+ tableCreateFile(
170
+ file_path="./combined.xlsx",
171
+ sheet_name="Results",
172
+ data=all_data
173
+ )
174
+ ```
175
+
176
+ For large batches (>10 files), use Python script for efficiency.
177
+
178
+ ## Best Practices
179
+
180
+ 1. **Verify Task tool availability** before implementing this pattern
181
+ 2. **Keep wave_size reasonable**: 3-5 subagents per wave
182
+ 3. **Use descriptive descriptions**: "Process batch 001" not "Batch 1"
183
+ 4. **Always use file-based prompts**: Never inline large prompts
184
+ 5. **Validate every output**: Don't skip schema validation
185
+ 6. **Report progress after waves**: Not during individual completions
186
+ 7. **Have fallback plan**: If Task tool unavailable, use sequential processing
@@ -0,0 +1,260 @@
1
+ # Table Tools Pattern
2
+
3
+ Guide for combining subagent outputs using table tools.
4
+
5
+ ## Overview
6
+
7
+ Table tools can be used to combine JSON outputs into Excel/CSV files without Python scripts for small batches.
8
+
9
+ ## When to Use Table Tools vs Python
10
+
11
+ | Scenario | Use Table Tools | Use Python Script |
12
+ |----------|-----------------|-------------------|
13
+ | Files to combine | <10 files | >=10 files |
14
+ | Data size | Small (<1000 rows total) | Large (>1000 rows) |
15
+ | Complexity | Simple merge | Complex transformations |
16
+ | Performance | Acceptable overhead | Need efficiency |
17
+
18
+ ## Tool: tableCreateFile
19
+
20
+ Create a new Excel/CSV file from data.
21
+
22
+ ### Signature
23
+ ```
24
+ tableCreateFile(
25
+ file_path: string,
26
+ sheet_name: string = "Sheet1",
27
+ data: array // Array of arrays OR array of objects
28
+ )
29
+ ```
30
+
31
+ ### Return Format
32
+ ```json
33
+ {
34
+ "success": true,
35
+ "file_path": "./output.xlsx",
36
+ "sheet_name": "Sheet1",
37
+ "rows_created": 100,
38
+ "message": "Successfully created Excel file with 100 rows"
39
+ }
40
+ ```
41
+
42
+ ### Examples
43
+
44
+ ```
45
+ # Create from array of objects
46
+ tableCreateFile(
47
+ file_path="./output.xlsx",
48
+ sheet_name="Results",
49
+ data=[
50
+ {"row_number": 1, "name": "Alice", "score": 95},
51
+ {"row_number": 2, "name": "Bob", "score": 87}
52
+ ]
53
+ )
54
+
55
+ # Create from array of arrays
56
+ tableCreateFile(
57
+ file_path="./output.csv",
58
+ sheet_name="Sheet1",
59
+ data=[
60
+ ["row_number", "name", "score"],
61
+ [1, "Alice", 95],
62
+ [2, "Bob", 87]
63
+ ]
64
+ )
65
+ ```
66
+
67
+ ## Tool: tableAppendRows
68
+
69
+ Append rows to an existing table file.
70
+
71
+ ### Signature
72
+ ```
73
+ tableAppendRows(
74
+ file_path: string,
75
+ sheet_name: string?, // Optional, uses first sheet
76
+ rows: array // Array of arrays OR array of objects
77
+ )
78
+ ```
79
+
80
+ ### Return Format
81
+ ```json
82
+ {
83
+ "success": true,
84
+ "file_path": "./output.xlsx",
85
+ "sheet_name": "Sheet1",
86
+ "rows_appended": 50,
87
+ "message": "Successfully appended 50 rows"
88
+ }
89
+ ```
90
+
91
+ ### Examples
92
+
93
+ **RECOMMENDED: Append using array-of-arrays format (no header duplication):**
94
+ ```
95
+ tableAppendRows(
96
+ file_path="./output.xlsx",
97
+ rows=[
98
+ [3, "Charlie", 92],
99
+ [4, "Diana", 88]
100
+ ]
101
+ )
102
+ ```
103
+
104
+ **Alternative: Append using objects (may duplicate headers):**
105
+ ```
106
+ tableAppendRows(
107
+ file_path="./output.xlsx",
108
+ rows=[
109
+ {"row_number": 3, "name": "Charlie", "score": 92}
110
+ ]
111
+ )
112
+ ```
113
+
114
+ > **Note:** When appending object-format data, some implementations may insert a duplicate header row. For reliable results, use array-of-arrays format for append operations.
115
+
116
+ ## Combining JSON Outputs Workflow
117
+
118
+ ### Step 1: Extract All JSON
119
+
120
+ ```
121
+ # Extract JSON from each output file
122
+ all_rows = []
123
+
124
+ for batch_num in range(1, num_batches + 1):
125
+ file_path = f"./outputs/batch{batch_num:03d}.md"
126
+ result = jsonExtract(file_path=file_path)
127
+
128
+ if result.success:
129
+ # Assuming data has "summaries" array
130
+ summaries = result.data.get("summaries", [])
131
+ all_rows.extend(summaries)
132
+ else:
133
+ log_error(f"Failed to extract from {file_path}")
134
+ ```
135
+
136
+ ### Step 2: Create Combined File
137
+
138
+ ```
139
+ # Create Excel file with all rows
140
+ tableCreateFile(
141
+ file_path="./combined_summary.xlsx",
142
+ sheet_name="Summary",
143
+ data=all_rows
144
+ )
145
+ ```
146
+
147
+ ### Step 3: Append Additional Data (Optional)
148
+
149
+ ```
150
+ # If processing in chunks, append to existing file using array format
151
+ # First, get headers from the created file
152
+ headers = list(all_rows[0].keys()) if all_rows else []
153
+
154
+ for chunk in chunks:
155
+ rows = extract_rows(chunk)
156
+ # Convert to arrays to avoid header duplication
157
+ rows_as_arrays = [[item.get(h) for h in headers] for item in rows]
158
+ tableAppendRows(
159
+ file_path="./combined_summary.xlsx",
160
+ rows=rows_as_arrays
161
+ )
162
+ ```
163
+
164
+ ## Complete Example: Combining Batch Outputs
165
+
166
+ ```
167
+ # Configuration
168
+ output_dir = "./outputs"
169
+ num_batches = 9
170
+ combined_file = "./combined_summary.xlsx"
171
+
172
+ # Collect all rows
173
+ all_rows = []
174
+ failed_batches = []
175
+
176
+ for batch_num in range(1, num_batches + 1):
177
+ file_path = f"{output_dir}/batch{batch_num:03d}.md"
178
+
179
+ # Extract JSON
180
+ result = jsonExtract(file_path=file_path)
181
+
182
+ if not result.success:
183
+ failed_batches.append(batch_num)
184
+ continue
185
+
186
+ # Get summaries from batch output
187
+ summaries = result.data.get("summaries", [])
188
+ all_rows.extend(summaries)
189
+
190
+ # Report failures
191
+ if failed_batches:
192
+ log_error(f"Failed batches: {failed_batches}")
193
+
194
+ # Sort by row_number
195
+ all_rows.sort(key=lambda x: x.get("row_number", 0))
196
+
197
+ # Create combined Excel
198
+ result = tableCreateFile(
199
+ file_path=combined_file,
200
+ sheet_name="Combined",
201
+ data=all_rows
202
+ )
203
+
204
+ # Report result
205
+ report(f"Created {combined_file} with {result.rows_created} rows")
206
+ ```
207
+
208
+ ## Incremental Append Strategy
209
+
210
+ For large datasets, append incrementally using array-of-arrays format:
211
+
212
+ ```
213
+ # Get column headers from first batch
214
+ first_batch = jsonExtract(file_path="./outputs/batch001.md")
215
+ headers = ["row_number", "field1", "field2"] # Define your headers
216
+
217
+ # Create file with first batch (using objects for auto-headers)
218
+ tableCreateFile(
219
+ file_path="./combined.xlsx",
220
+ sheet_name="Data",
221
+ data=first_batch.data.get("summaries", [])
222
+ )
223
+
224
+ # Get header order for array format
225
+ headers = list(first_batch.data.get("summaries", [{}])[0].keys())
226
+
227
+ # Append remaining batches using array format
228
+ for batch_num in range(2, num_batches + 1):
229
+ file_path = f"./outputs/batch{batch_num:03d}.md"
230
+ result = jsonExtract(file_path=file_path)
231
+
232
+ if result.success:
233
+ # Convert objects to arrays to avoid header duplication
234
+ rows_as_arrays = [
235
+ [item.get(h) for h in headers]
236
+ for item in result.data.get("summaries", [])
237
+ ]
238
+ tableAppendRows(
239
+ file_path="./combined.xlsx",
240
+ rows=rows_as_arrays
241
+ )
242
+ ```
243
+
244
+ ## Supported File Formats
245
+
246
+ | Format | Extension | Notes |
247
+ |--------|-----------|-------|
248
+ | Excel | .xlsx | Recommended |
249
+ | Excel (Legacy) | .xls | Limited support |
250
+ | ODS | .ods | OpenDocument Spreadsheet |
251
+ | CSV | .csv | Text-based, no sheets |
252
+
253
+ ## Best Practices
254
+
255
+ 1. **Sort before writing**: Sort rows by key field before creating file
256
+ 2. **Handle failures gracefully**: Log failed extractions, continue with others
257
+ 3. **Use object format for creation**: Array of objects auto-generates headers
258
+ 4. **Use array format for appends**: Prefer array-of-arrays when using tableAppendRows to avoid potential header duplication
259
+ 5. **Check row counts**: Verify expected vs actual row counts
260
+ 6. **For large batches**: Use Python script for better performance
@@ -0,0 +1,187 @@
1
+ # User Confirmation Pattern
2
+
3
+ Request user confirmation before destructive or significant operations.
4
+
5
+ ## Overview
6
+
7
+ Use this pattern before operations that:
8
+ - Delete or modify files
9
+ - Make network requests
10
+ - Incur costs (API calls, cloud resources)
11
+ - Take significant time
12
+ - Cannot be easily undone
13
+
14
+ ## Tool: question
15
+
16
+ > **Note:** The tool is invoked as `question` (lowercase). Some documentation may reference `Question` (capitalized) but both refer to the same tool.
17
+
18
+ ```
19
+ question(questions: [{
20
+ header: string, // Short label (max 30 chars)
21
+ question: string, // Complete question
22
+ options: [{
23
+ label: string, // Display text (1-5 words)
24
+ description: string // Explanation of choice
25
+ }],
26
+ multiple: boolean // Allow multiple selections (default: false)
27
+ }])
28
+ ```
29
+
30
+ ## Example: Before Destructive Operation
31
+
32
+ ```
33
+ question(questions=[{
34
+ "header": "Delete files",
35
+ "question": "This will delete 15 files in ./temp/. Continue?",
36
+ "options": [
37
+ {"label": "Yes, delete", "description": "Permanently delete all 15 files"},
38
+ {"label": "No, cancel", "description": "Keep files and stop this operation"}
39
+ ]
40
+ }])
41
+ ```
42
+
43
+ ## Example: Continue After Failures
44
+
45
+ ```
46
+ question(questions=[{
47
+ "header": "Retry failed",
48
+ "question": "3 batches failed after all retry attempts. How would you like to proceed?",
49
+ "options": [
50
+ {"label": "Continue", "description": "Skip failed batches and continue with remaining"},
51
+ {"label": "Retry now", "description": "Try failed batches one more time"},
52
+ {"label": "Abort", "description": "Stop the entire workflow"}
53
+ ]
54
+ }])
55
+ ```
56
+
57
+ ## Example: Configuration Choice
58
+
59
+ ```
60
+ question(questions=[{
61
+ "header": "Batch size",
62
+ "question": "How many rows should each batch contain?",
63
+ "options": [
64
+ {"label": "30 rows (Recommended)", "description": "Balanced for most use cases"},
65
+ {"label": "50 rows", "description": "Fewer batches, larger context per subagent"},
66
+ {"label": "10 rows", "description": "More batches, smaller context per subagent"}
67
+ ]
68
+ }])
69
+ ```
70
+
71
+ ## Example: Multiple Selection
72
+
73
+ ```
74
+ question(questions=[{
75
+ "header": "Select sheets",
76
+ "question": "Which sheets should be processed?",
77
+ "options": [
78
+ {"label": "Sheet1", "description": "Main data sheet (1000 rows)"},
79
+ {"label": "Sheet2", "description": "Secondary data (500 rows)"},
80
+ {"label": "Summary", "description": "Pre-computed summaries (50 rows)"}
81
+ ],
82
+ "multiple": true
83
+ }])
84
+ ```
85
+
86
+ ## When to Ask for Confirmation
87
+
88
+ | Operation Type | Confirmation Needed |
89
+ |---------------|---------------------|
90
+ | Read file | No |
91
+ | Write new file | No |
92
+ | Overwrite existing file | Yes |
93
+ | Delete file | Yes |
94
+ | Delete directory | Yes |
95
+ | API call (free) | No |
96
+ | API call (paid) | Yes |
97
+ | Long operation (>5 min) | Yes |
98
+ | Network upload | Yes |
99
+ | Network download | No (usually) |
100
+
101
+ ## Response Handling
102
+
103
+ The question tool returns selected option labels as an array:
104
+
105
+ ```
106
+ # Single selection
107
+ response = question(...)
108
+ if response[0] == "Yes, delete":
109
+ proceed_with_deletion()
110
+ else:
111
+ cancel_operation()
112
+
113
+ # Multiple selection
114
+ response = question(..., multiple=true)
115
+ selected_sheets = response # ["Sheet1", "Sheet2"]
116
+ ```
117
+
118
+ ## Example: Conditional Logic Flow
119
+
120
+ ```
121
+ # Ask for confirmation
122
+ response = question(questions=[{
123
+ "header": "Overwrite",
124
+ "question": "File 'output.xlsx' already exists. Overwrite?",
125
+ "options": [
126
+ {"label": "Overwrite", "description": "Replace existing file"},
127
+ {"label": "Append", "description": "Add to existing file"},
128
+ {"label": "Cancel", "description": "Don't modify the file"}
129
+ ]
130
+ }])
131
+
132
+ # Handle response
133
+ if response[0] == "Overwrite":
134
+ write_file(mode="write")
135
+ elif response[0] == "Append":
136
+ write_file(mode="append")
137
+ else:
138
+ report("Operation cancelled by user")
139
+ ```
140
+
141
+ ## Best Practices
142
+
143
+ 1. **Clear header**: Max 30 chars, summarize the decision
144
+ 2. **Descriptive question**: Explain what will happen
145
+ 3. **Helpful options**: Include descriptions that guide the user
146
+ 4. **Recommended option**: Mark with "(Recommended)" in label
147
+ 5. **Safe default**: Put safer option first
148
+ 6. **Cancel option**: Always include a way to abort
149
+
150
+ ## Timeout and No-Response Handling
151
+
152
+ When users don't respond to confirmation prompts, implement a default behavior:
153
+
154
+ ### Default After Timeout
155
+
156
+ ```python
157
+ # If no response after reasonable time, default to safe option
158
+ # Most patterns should default to "cancel" for safety
159
+
160
+ if no_response_after(timeout=60):
161
+ log("No user response, defaulting to cancel")
162
+ cancel_operation()
163
+ ```
164
+
165
+ ### Integration with Retry Pattern
166
+
167
+ For critical operations requiring user input:
168
+ 1. Ask for confirmation
169
+ 2. If no response, wait and retry with `blockingTimer`
170
+ 3. After N attempts, use safe default or abort
171
+
172
+ ```python
173
+ attempts = 0
174
+ max_attempts = 3
175
+ while attempts < max_attempts:
176
+ response = question(...)
177
+ if response:
178
+ handle_response(response)
179
+ break
180
+ attempts += 1
181
+ if attempts < max_attempts:
182
+ blockingTimer(delay=10) # Wait before re-prompting
183
+
184
+ # Default to safe option if no response
185
+ if attempts >= max_attempts:
186
+ cancel_operation()
187
+ ```