@yeyuan98/opencode-bioresearcher-plugin 1.4.0 → 1.5.0-alpha.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 (72) hide show
  1. package/README.md +35 -20
  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 +2 -0
  55. package/dist/skills/bioresearcher-core/README.md +210 -210
  56. package/dist/skills/bioresearcher-core/SKILL.md +128 -128
  57. package/dist/skills/bioresearcher-core/examples/contexts.json +29 -29
  58. package/dist/skills/bioresearcher-core/examples/data-exchange-example.md +303 -303
  59. package/dist/skills/bioresearcher-core/examples/template.md +49 -49
  60. package/dist/skills/bioresearcher-core/patterns/calculator.md +215 -215
  61. package/dist/skills/bioresearcher-core/patterns/data-exchange.md +406 -406
  62. package/dist/skills/bioresearcher-core/patterns/json-tools.md +263 -263
  63. package/dist/skills/bioresearcher-core/patterns/progress.md +127 -127
  64. package/dist/skills/bioresearcher-core/patterns/retry.md +110 -110
  65. package/dist/skills/bioresearcher-core/patterns/shell-commands.md +79 -79
  66. package/dist/skills/bioresearcher-core/patterns/subagent-waves.md +186 -186
  67. package/dist/skills/bioresearcher-core/patterns/table-tools.md +260 -260
  68. package/dist/skills/bioresearcher-core/patterns/user-confirmation.md +187 -187
  69. package/dist/skills/bioresearcher-core/python/template.md +273 -273
  70. package/dist/skills/bioresearcher-core/python/template.py +323 -323
  71. package/dist/skills/env-jsonc-setup/SKILL.md +206 -0
  72. package/package.json +3 -1
package/README.md CHANGED
@@ -77,19 +77,33 @@ Download pubmed article data from https://ftp.ncbi.nlm.nih.gov/pubmed/updatefile
77
77
 
78
78
  Reference: [PubMed Download Data](https://pubmed.ncbi.nlm.nih.gov/download/).
79
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
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
+ ### Database Tools
93
+
94
+ Query MySQL and MongoDB databases with read-only access.
95
+
96
+ **Explore your data warehouse without leaving the conversation.**
97
+
98
+ ```text
99
+ List all tables in the database.
100
+ Describe the schema for table users.
101
+ Query orders placed in the last 30 days.
102
+ ```
103
+
104
+ Configuration via `env.jsonc` in working directory. Use the `env-jsonc-setup` skill for guided setup.
105
+
106
+ ## Skills
93
107
 
94
108
  Skills are reusable prompt templates discovered from multiple paths:
95
109
 
@@ -104,13 +118,14 @@ This plugin provides a skill tool that overrides Opencode's built-in to support
104
118
 
105
119
  See [skill-tools/README.md](skill-tools/README.md) for full documentation.
106
120
 
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.
121
+ ### Supplied skills
122
+
123
+ - `demo-skill`: showcase skill tool mechanisms.
124
+ - `python-setup-uv`: setup python runtime in your working directory with uv.
125
+ - `pubmed-weekly`: automated download of pubmed daily update files over the past one week.
126
+ - `long-table-summary`: batch-process large tables using parallel subagents for summarization.
127
+ - `bioresearcher-core`: core patterns and utilities (retry, JSON tools, subagent waves) for skill development.
128
+ - `env-jsonc-setup`: guided setup for database connection configuration (db-tools).
114
129
 
115
130
  Prompt the following and follow along:
116
131
 
@@ -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 {};