@yeyuan98/opencode-bioresearcher-plugin 1.4.1 → 1.5.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 (69) hide show
  1. package/README.md +49 -22
  2. package/dist/db-tools/backends/index.d.ts +11 -0
  3. package/dist/db-tools/backends/index.js +48 -0
  4. package/dist/db-tools/backends/mongodb/backend.d.ts +15 -0
  5. package/dist/db-tools/backends/mongodb/backend.js +76 -0
  6. package/dist/db-tools/backends/mongodb/connection.d.ts +27 -0
  7. package/dist/db-tools/backends/mongodb/connection.js +107 -0
  8. package/dist/db-tools/backends/mongodb/index.d.ts +4 -0
  9. package/dist/db-tools/backends/mongodb/index.js +3 -0
  10. package/dist/db-tools/backends/mongodb/translator.d.ts +30 -0
  11. package/dist/db-tools/backends/mongodb/translator.js +407 -0
  12. package/dist/db-tools/backends/mysql/backend.d.ts +15 -0
  13. package/dist/db-tools/backends/mysql/backend.js +57 -0
  14. package/dist/db-tools/backends/mysql/connection.d.ts +25 -0
  15. package/dist/db-tools/backends/mysql/connection.js +83 -0
  16. package/dist/db-tools/backends/mysql/index.d.ts +3 -0
  17. package/dist/db-tools/backends/mysql/index.js +2 -0
  18. package/dist/db-tools/backends/mysql/translator.d.ts +7 -0
  19. package/dist/db-tools/backends/mysql/translator.js +67 -0
  20. package/dist/db-tools/core/base.d.ts +17 -0
  21. package/dist/db-tools/core/base.js +51 -0
  22. package/dist/db-tools/core/config-loader.d.ts +3 -0
  23. package/dist/db-tools/core/config-loader.js +46 -0
  24. package/dist/db-tools/core/index.d.ts +2 -0
  25. package/dist/db-tools/core/index.js +2 -0
  26. package/dist/db-tools/core/jsonc-parser.d.ts +2 -0
  27. package/dist/db-tools/core/jsonc-parser.js +77 -0
  28. package/dist/db-tools/core/validator.d.ts +16 -0
  29. package/dist/db-tools/core/validator.js +118 -0
  30. package/dist/db-tools/executor.d.ts +13 -0
  31. package/dist/db-tools/executor.js +54 -0
  32. package/dist/db-tools/index.d.ts +51 -0
  33. package/dist/db-tools/index.js +27 -0
  34. package/dist/db-tools/interface/backend.d.ts +24 -0
  35. package/dist/db-tools/interface/backend.js +1 -0
  36. package/dist/db-tools/interface/connection.d.ts +21 -0
  37. package/dist/db-tools/interface/connection.js +11 -0
  38. package/dist/db-tools/interface/index.d.ts +4 -0
  39. package/dist/db-tools/interface/index.js +4 -0
  40. package/dist/db-tools/interface/query.d.ts +60 -0
  41. package/dist/db-tools/interface/query.js +1 -0
  42. package/dist/db-tools/interface/schema.d.ts +22 -0
  43. package/dist/db-tools/interface/schema.js +1 -0
  44. package/dist/db-tools/pool.d.ts +8 -0
  45. package/dist/db-tools/pool.js +49 -0
  46. package/dist/db-tools/tools/index.d.ts +27 -0
  47. package/dist/db-tools/tools/index.js +191 -0
  48. package/dist/db-tools/tools.d.ts +27 -0
  49. package/dist/db-tools/tools.js +111 -0
  50. package/dist/db-tools/types.d.ts +94 -0
  51. package/dist/db-tools/types.js +40 -0
  52. package/dist/db-tools/utils.d.ts +33 -0
  53. package/dist/db-tools/utils.js +94 -0
  54. package/dist/index.js +5 -1
  55. package/dist/parser-tools/obo/index.d.ts +2 -0
  56. package/dist/parser-tools/obo/index.js +2 -0
  57. package/dist/parser-tools/obo/obo.d.ts +17 -0
  58. package/dist/parser-tools/obo/obo.js +216 -0
  59. package/dist/parser-tools/obo/types.d.ts +166 -0
  60. package/dist/parser-tools/obo/types.js +1 -0
  61. package/dist/parser-tools/obo/utils.d.ts +21 -0
  62. package/dist/parser-tools/obo/utils.js +411 -0
  63. package/dist/skills/env-jsonc-setup/SKILL.md +206 -0
  64. package/dist/skills/long-table-summary/SKILL.md +437 -374
  65. package/dist/skills/long-table-summary/combine_outputs.py +5 -14
  66. package/dist/skills/long-table-summary/generate_prompts.py +211 -0
  67. package/dist/skills/long-table-summary/pyproject.toml +8 -11
  68. package/package.json +3 -1
  69. package/dist/skills/long-table-summary/__init__.py +0 -3
package/README.md CHANGED
@@ -75,21 +75,47 @@ Parse PubMed XML files to markdown or Excel format. Supports `.xml` and `.xml.gz
75
75
  Download pubmed article data from https://ftp.ncbi.nlm.nih.gov/pubmed/updatefiles/pubmed26n1340.xml.gz and parse to Excel format.
76
76
  ```
77
77
 
78
- Reference: [PubMed Download Data](https://pubmed.ncbi.nlm.nih.gov/download/).
79
-
80
- ### JSON Tools
81
-
82
- Extract, validate, and infer JSON schemas from data.
83
-
84
- **Robust JSON handling for LLM workflows.**
85
-
86
- ```text
87
- Extract JSON from output.md using jsonExtract tool.
88
- Validate data.json against schema.json using jsonValidate tool.
89
- Infer schema from sample.json using jsonInfer tool.
90
- ```
91
-
92
- ## Skills
78
+ Reference: [PubMed Download Data](https://pubmed.ncbi.nlm.nih.gov/download/).
79
+
80
+ ### OBO Parser
81
+
82
+ Parse OBO (Open Biological and Biomedical Ontology) files to CSV format. Handles Term, Typedef, and Instance frames.
83
+
84
+ **Flatten complex ontologies into analysis-ready tables.**
85
+
86
+ ```text
87
+ Parse go.obo file and convert to CSV using parse_obo_file tool.
88
+ ```
89
+
90
+ Reference: [OBO Format](http://owlcollab.github.io/oboformat/doc/obo-syntax.html).
91
+
92
+ ### JSON Tools
93
+
94
+ Extract, validate, and infer JSON schemas from data.
95
+
96
+ **Robust JSON handling for LLM workflows.**
97
+
98
+ ```text
99
+ Extract JSON from output.md using jsonExtract tool.
100
+ Validate data.json against schema.json using jsonValidate tool.
101
+ Infer schema from sample.json using jsonInfer tool.
102
+ ```
103
+
104
+ ### Database Tools
105
+
106
+ Query MySQL and MongoDB databases with read-only access.
107
+
108
+ **Explore your data warehouse without leaving the conversation.**
109
+
110
+ ```text
111
+ List all tables in the database.
112
+ Describe the schema for table users.
113
+ Query orders placed in the last 30 days.
114
+ ```
115
+
116
+ Configuration via `env.jsonc` in working directory. Use the `env-jsonc-setup` skill for guided setup.
117
+
118
+ ## Skills
93
119
 
94
120
  Skills are reusable prompt templates discovered from multiple paths:
95
121
 
@@ -104,13 +130,14 @@ This plugin provides a skill tool that overrides Opencode's built-in to support
104
130
 
105
131
  See [skill-tools/README.md](skill-tools/README.md) for full documentation.
106
132
 
107
- ### Supplied skills
108
-
109
- - `demo-skill`: showcase skill tool mechanisms.
110
- - `python-setup-uv`: setup python runtime in your working directory with uv.
111
- - `pubmed-weekly`: automated download of pubmed daily update files over the past one week.
112
- - `long-table-summary`: batch-process large tables using parallel subagents for summarization.
113
- - `bioresearcher-core`: core patterns and utilities (retry, JSON tools, subagent waves) for skill development.
133
+ ### Supplied skills
134
+
135
+ - `demo-skill`: showcase skill tool mechanisms.
136
+ - `python-setup-uv`: setup python runtime in your working directory with uv.
137
+ - `pubmed-weekly`: automated download of pubmed daily update files over the past one week.
138
+ - `long-table-summary`: batch-process large tables using parallel subagents for summarization.
139
+ - `bioresearcher-core`: core patterns and utilities (retry, JSON tools, subagent waves) for skill development.
140
+ - `env-jsonc-setup`: guided setup for database connection configuration (db-tools).
114
141
 
115
142
  Prompt the following and follow along:
116
143
 
@@ -0,0 +1,11 @@
1
+ import type { IDatabaseBackend, IConnectionConfig, BackendType } from '../interface';
2
+ type BackendFactory = (config: IConnectionConfig) => IDatabaseBackend;
3
+ export declare function registerBackend(type: BackendType, factory: BackendFactory): void;
4
+ export declare function createBackend(config: IConnectionConfig): IDatabaseBackend;
5
+ export declare function getSupportedTypes(): BackendType[];
6
+ export declare function isBackendSupported(type: string): type is BackendType;
7
+ export declare function getBackend(config?: IConnectionConfig): IDatabaseBackend;
8
+ export declare function initializeBackend(config: IConnectionConfig): Promise<IDatabaseBackend>;
9
+ export declare function closeBackend(): Promise<void>;
10
+ export declare function getDefaultBackend(): IDatabaseBackend | null;
11
+ export {};
@@ -0,0 +1,48 @@
1
+ import { MySQLBackend } from './mysql';
2
+ import { MongoDBBackend } from './mongodb';
3
+ const backendRegistry = new Map();
4
+ export function registerBackend(type, factory) {
5
+ backendRegistry.set(type, factory);
6
+ }
7
+ export function createBackend(config) {
8
+ const factory = backendRegistry.get(config.type);
9
+ if (!factory) {
10
+ throw new Error(`Unsupported backend type: ${config.type}. Supported types: ${getSupportedTypes().join(', ')}`);
11
+ }
12
+ return factory(config);
13
+ }
14
+ export function getSupportedTypes() {
15
+ return Array.from(backendRegistry.keys());
16
+ }
17
+ export function isBackendSupported(type) {
18
+ return backendRegistry.has(type);
19
+ }
20
+ registerBackend('mysql', (config) => new MySQLBackend(config));
21
+ registerBackend('mongodb', (config) => new MongoDBBackend(config));
22
+ let defaultBackend = null;
23
+ export function getBackend(config) {
24
+ if (!config) {
25
+ if (!defaultBackend) {
26
+ throw new Error('No backend initialized. Call initializeBackend() first or provide config.');
27
+ }
28
+ return defaultBackend;
29
+ }
30
+ return createBackend(config);
31
+ }
32
+ export async function initializeBackend(config) {
33
+ if (defaultBackend) {
34
+ await defaultBackend.disconnect();
35
+ }
36
+ defaultBackend = createBackend(config);
37
+ await defaultBackend.connect();
38
+ return defaultBackend;
39
+ }
40
+ export async function closeBackend() {
41
+ if (defaultBackend) {
42
+ await defaultBackend.disconnect();
43
+ defaultBackend = null;
44
+ }
45
+ }
46
+ export function getDefaultBackend() {
47
+ return defaultBackend;
48
+ }
@@ -0,0 +1,15 @@
1
+ import type { IConnectionConfig, IQuery, IQueryResult, ICollectionInfo, IColumnSchema, IConnectionPool } from '../../interface';
2
+ import { BaseBackend } from '../../core/base';
3
+ import { MongoDBConnectionConfig } from './connection';
4
+ export declare class MongoDBBackend extends BaseBackend {
5
+ readonly type = "mongodb";
6
+ readonly config: MongoDBConnectionConfig;
7
+ constructor(config: IConnectionConfig);
8
+ connect(): Promise<void>;
9
+ disconnect(): Promise<void>;
10
+ getPool(): IConnectionPool | null;
11
+ executeQuery(query: IQuery): Promise<IQueryResult>;
12
+ listCollections(): Promise<ICollectionInfo[]>;
13
+ describeCollection(name: string): Promise<IColumnSchema[]>;
14
+ }
15
+ export declare function createMongoDBBackend(config: IConnectionConfig): MongoDBBackend;
@@ -0,0 +1,76 @@
1
+ import { BaseBackend } from '../../core/base';
2
+ import { getDb, closeClient, validateMongoDBConfig, MongoDBConnectionPool, } from './connection';
3
+ import { parseSelectQuery, executeParsedQuery, listMongoDBCollections, describeMongoDBCollection, createFieldInfoFromRow, SQLParseError, } from './translator';
4
+ export class MongoDBBackend extends BaseBackend {
5
+ type = 'mongodb';
6
+ config;
7
+ constructor(config) {
8
+ super();
9
+ this.config = {
10
+ ...config,
11
+ uri: config.options?.uri,
12
+ authSource: config.options?.authSource,
13
+ replicaSet: config.options?.replicaSet,
14
+ };
15
+ }
16
+ async connect() {
17
+ validateMongoDBConfig(this.config);
18
+ await getDb(this.config);
19
+ this._connected = true;
20
+ }
21
+ async disconnect() {
22
+ await closeClient();
23
+ this._connected = false;
24
+ }
25
+ getPool() {
26
+ return new MongoDBConnectionPool(this.config);
27
+ }
28
+ async executeQuery(query) {
29
+ const startTime = Date.now();
30
+ try {
31
+ if (!this._connected) {
32
+ await this.connect();
33
+ }
34
+ const db = await getDb(this.config);
35
+ const parsed = parseSelectQuery(query.sql);
36
+ const collection = db.collection(parsed.collection);
37
+ const rows = await executeParsedQuery(collection, parsed, query.params);
38
+ const fields = createFieldInfoFromRow(rows[0] || {});
39
+ const executionTimeMs = Date.now() - startTime;
40
+ return this.createSuccessResult(rows, fields, executionTimeMs);
41
+ }
42
+ catch (error) {
43
+ const executionTimeMs = Date.now() - startTime;
44
+ if (error instanceof SQLParseError) {
45
+ return {
46
+ success: false,
47
+ error: {
48
+ code: 'SQL_PARSE_ERROR',
49
+ message: error.message,
50
+ hints: [
51
+ 'Check your SQL syntax',
52
+ 'Only SELECT queries are supported',
53
+ 'Supported clauses: WHERE, ORDER BY, LIMIT, OFFSET, GROUP BY, HAVING',
54
+ ],
55
+ },
56
+ metadata: {
57
+ executionTimeMs,
58
+ backend: this.type,
59
+ },
60
+ };
61
+ }
62
+ return this.createErrorResult(error, executionTimeMs);
63
+ }
64
+ }
65
+ async listCollections() {
66
+ const db = await getDb(this.config);
67
+ return listMongoDBCollections(db);
68
+ }
69
+ async describeCollection(name) {
70
+ const db = await getDb(this.config);
71
+ return describeMongoDBCollection(db, name);
72
+ }
73
+ }
74
+ export function createMongoDBBackend(config) {
75
+ return new MongoDBBackend(config);
76
+ }
@@ -0,0 +1,27 @@
1
+ import { MongoClient, MongoClientOptions, Db } from 'mongodb';
2
+ import type { IConnectionConfig, IConnectionPool, IConnection } from '../../interface';
3
+ export interface MongoDBConnectionConfig extends IConnectionConfig {
4
+ uri?: string;
5
+ authSource?: string;
6
+ replicaSet?: string;
7
+ }
8
+ declare let client: MongoClient | null;
9
+ declare let db: Db | null;
10
+ export declare function buildConnectionString(config: MongoDBConnectionConfig): string;
11
+ export declare function createClientOptions(config: MongoDBConnectionConfig): MongoClientOptions;
12
+ export declare function getClient(config: MongoDBConnectionConfig): Promise<MongoClient>;
13
+ export declare function getDb(config: MongoDBConnectionConfig): Promise<Db>;
14
+ export declare function closeClient(): Promise<void>;
15
+ export declare function getClientStatus(): {
16
+ initialized: boolean;
17
+ hasConfig: boolean;
18
+ };
19
+ export declare function validateMongoDBConfig(config: MongoDBConnectionConfig): void;
20
+ export declare class MongoDBConnectionPool implements IConnectionPool {
21
+ private config;
22
+ constructor(config: MongoDBConnectionConfig);
23
+ getConnection(): Promise<IConnection>;
24
+ end(): Promise<void>;
25
+ isHealthy(): boolean;
26
+ }
27
+ export { client as _internalClient, db as _internalDb };
@@ -0,0 +1,107 @@
1
+ import { MongoClient } from 'mongodb';
2
+ let client = null;
3
+ let db = null;
4
+ let currentConfig = null;
5
+ export function buildConnectionString(config) {
6
+ if (config.uri) {
7
+ return config.uri;
8
+ }
9
+ const auth = config.username && config.password
10
+ ? `${encodeURIComponent(config.username)}:${encodeURIComponent(config.password)}@`
11
+ : '';
12
+ const host = config.host || 'localhost';
13
+ const port = config.port || 27017;
14
+ const database = config.database || 'test';
15
+ let uri = `mongodb://${auth}${host}:${port}/${database}`;
16
+ const params = [];
17
+ if (config.authSource)
18
+ params.push(`authSource=${config.authSource}`);
19
+ if (config.replicaSet)
20
+ params.push(`replicaSet=${config.replicaSet}`);
21
+ if (params.length > 0) {
22
+ uri += '?' + params.join('&');
23
+ }
24
+ return uri;
25
+ }
26
+ export function createClientOptions(config) {
27
+ return {
28
+ connectTimeoutMS: config.connectionTimeout || 10000,
29
+ serverSelectionTimeoutMS: config.connectionTimeout || 10000,
30
+ maxPoolSize: 10,
31
+ minPoolSize: 1,
32
+ };
33
+ }
34
+ export async function getClient(config) {
35
+ if (client && currentConfig && isSameConfig(currentConfig, config)) {
36
+ return client;
37
+ }
38
+ if (client) {
39
+ await client.close().catch(err => console.error('[mongodb-backend] Previous client cleanup failed:', err.message));
40
+ }
41
+ const uri = buildConnectionString(config);
42
+ const options = createClientOptions(config);
43
+ client = new MongoClient(uri, options);
44
+ await client.connect();
45
+ db = client.db(config.database);
46
+ currentConfig = config;
47
+ return client;
48
+ }
49
+ export async function getDb(config) {
50
+ if (db && currentConfig && isSameConfig(currentConfig, config)) {
51
+ return db;
52
+ }
53
+ await getClient(config);
54
+ return db;
55
+ }
56
+ function isSameConfig(a, b) {
57
+ if (a.uri && b.uri) {
58
+ return a.uri === b.uri;
59
+ }
60
+ return (a.host === b.host &&
61
+ a.port === b.port &&
62
+ a.username === b.username &&
63
+ a.password === b.password &&
64
+ a.database === b.database);
65
+ }
66
+ export async function closeClient() {
67
+ if (client) {
68
+ await client.close().catch(err => console.error('[mongodb-backend] Client close failed:', err.message));
69
+ client = null;
70
+ db = null;
71
+ currentConfig = null;
72
+ }
73
+ }
74
+ export function getClientStatus() {
75
+ return {
76
+ initialized: client !== null,
77
+ hasConfig: currentConfig !== null,
78
+ };
79
+ }
80
+ export function validateMongoDBConfig(config) {
81
+ if (!config.uri && !config.database) {
82
+ throw new Error(`Missing required MongoDB configuration.\n` +
83
+ `Provide either:\n` +
84
+ ` - MONGODB_URI environment variable (for Atlas or connection strings)\n` +
85
+ ` - DB_DATABASE environment variable (for local MongoDB)`);
86
+ }
87
+ }
88
+ export class MongoDBConnectionPool {
89
+ config;
90
+ constructor(config) {
91
+ this.config = config;
92
+ }
93
+ async getConnection() {
94
+ const client = await getClient(this.config);
95
+ return {
96
+ isConnected: () => true,
97
+ close: async () => { },
98
+ };
99
+ }
100
+ async end() {
101
+ await closeClient();
102
+ }
103
+ isHealthy() {
104
+ return client !== null;
105
+ }
106
+ }
107
+ export { client as _internalClient, db as _internalDb };
@@ -0,0 +1,4 @@
1
+ export { MongoDBBackend, createMongoDBBackend } from './backend';
2
+ export { getDb, closeClient, validateMongoDBConfig } from './connection';
3
+ export type { MongoDBConnectionConfig } from './connection';
4
+ export { parseSelectQuery, SQLParseError } from './translator';
@@ -0,0 +1,3 @@
1
+ export { MongoDBBackend, createMongoDBBackend } from './backend';
2
+ export { getDb, closeClient, validateMongoDBConfig } from './connection';
3
+ export { parseSelectQuery, SQLParseError } from './translator';
@@ -0,0 +1,30 @@
1
+ import type { Document, Collection, SortDirection } from 'mongodb';
2
+ import type { IFieldInfo, IColumnSchema, ICollectionInfo, IRow } from '../../interface';
3
+ type MutableSort = {
4
+ [key: string]: SortDirection;
5
+ };
6
+ export interface ParsedSelectQuery {
7
+ collection: string;
8
+ fields: string[] | null;
9
+ where: Record<string, unknown> | null;
10
+ orderBy: MutableSort | null;
11
+ limit: number | null;
12
+ offset: number | null;
13
+ groupBy: string[] | null;
14
+ having: Record<string, unknown> | null;
15
+ aggregations: AggregationFunction[] | null;
16
+ }
17
+ export interface AggregationFunction {
18
+ type: 'COUNT' | 'SUM' | 'AVG' | 'MIN' | 'MAX';
19
+ field: string;
20
+ alias?: string;
21
+ }
22
+ export declare class SQLParseError extends Error {
23
+ constructor(message: string);
24
+ }
25
+ export declare function parseSelectQuery(sql: string): ParsedSelectQuery;
26
+ export declare function executeParsedQuery<T extends Document>(collection: Collection<T>, parsed: ParsedSelectQuery, params?: Record<string, unknown> | unknown[]): Promise<IRow[]>;
27
+ export declare function listMongoDBCollections(db: import('mongodb').Db): Promise<ICollectionInfo[]>;
28
+ export declare function describeMongoDBCollection(db: import('mongodb').Db, collectionName: string): Promise<IColumnSchema[]>;
29
+ export declare function createFieldInfoFromRow(row: IRow): IFieldInfo[];
30
+ export {};