opencode-bioresearcher 1.11.1 → 1.13.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 (25) hide show
  1. package/README.md +110 -49
  2. package/agents/bioresearcher-dr-worker.md +32 -20
  3. package/connector-meta.json +6 -5
  4. package/index.js +146 -61
  5. package/package.json +4 -2
  6. package/skill-bundle.json +3 -5
  7. package/skills/bioresearcher-deep-research/SKILL.md +52 -6
  8. package/skills/bioresearcher-deep-research/references/analysis-methods.md +15 -0
  9. package/skills/bioresearcher-deep-research/references/article-literature.md +36 -18
  10. package/skills/bioresearcher-deep-research/references/cartography.md +190 -0
  11. package/skills/bioresearcher-deep-research/references/diseases.md +1 -1
  12. package/skills/bioresearcher-deep-research/references/drugs.md +5 -4
  13. package/skills/bioresearcher-deep-research/references/functional-genomics.md +7 -3
  14. package/skills/bioresearcher-deep-research/references/genes.md +5 -3
  15. package/skills/bioresearcher-deep-research/references/patents.md +9 -3
  16. package/skills/bioresearcher-deep-research/references/rate-limiting-auth.md +7 -2
  17. package/skills/bioresearcher-deep-research/references/report-template.md +17 -0
  18. package/skills/bioresearcher-deep-research/references/tool-selection.md +8 -5
  19. package/skills/bioresearcher-deep-research/references/utility-config.md +2 -2
  20. package/skills/bioresearcher-deep-research/references/worker-protocol.md +16 -1
  21. package/skills/bioresearcher-onboard/SKILL.md +114 -0
  22. package/skills/bioresearcher-onboard/scripts/bootstrap.ps1 +96 -0
  23. package/skills/bioresearcher-onboard/scripts/bootstrap.sh +127 -0
  24. package/skills/bioresearcher-onboard/scripts/onboard.mjs +512 -0
  25. package/loader.js +0 -3
@@ -0,0 +1,512 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Stage 1 Onboarding Engine for bioresearcher-onboard.
4
+ * Installs biomcp@1.6.0 into .bioresearcher-runtime/node_modules, configures
5
+ * optional features via .biomcp.json, non-destructively merges harness
6
+ * configuration files, and runs pre-flight doctor verification.
7
+ */
8
+
9
+ import fs from "node:fs";
10
+ import path from "node:path";
11
+ import process from "node:process";
12
+ import { spawnSync } from "node:child_process";
13
+
14
+ const CWD = process.cwd();
15
+ const RUNTIME_ROOT = process.env.BIORESEARCHER_RUNTIME_DIR || path.resolve(CWD, ".bioresearcher-runtime");
16
+ const CACHE_DIR = path.join(RUNTIME_ROOT, "npm-cache");
17
+ const IS_WIN = process.platform === "win32";
18
+
19
+ // 1. Resolve Node and npm executables
20
+ let nodeBin = process.execPath;
21
+ const vendoredNode = IS_WIN
22
+ ? path.join(RUNTIME_ROOT, "node", "node.exe")
23
+ : path.join(RUNTIME_ROOT, "node", "bin", "node");
24
+
25
+ if (fs.existsSync(vendoredNode)) {
26
+ nodeBin = vendoredNode;
27
+ }
28
+
29
+ let npmBin = IS_WIN
30
+ ? path.join(RUNTIME_ROOT, "node", "npm.cmd")
31
+ : path.join(RUNTIME_ROOT, "node", "bin", "npm");
32
+
33
+ if (!fs.existsSync(npmBin)) {
34
+ npmBin = "npm";
35
+ }
36
+
37
+ // 2. Parse CLI options
38
+ const args = process.argv.slice(2);
39
+ const getArgVal = (prefix) => {
40
+ const match = args.find((a) => a.startsWith(prefix));
41
+ return match ? match.slice(match.indexOf("=") + 1) : null;
42
+ };
43
+
44
+ const options = {
45
+ withR: args.includes("--with-r") || process.env.ONBOARD_R === "1",
46
+ withMysql: args.includes("--with-mysql") || process.env.ONBOARD_MYSQL === "1",
47
+ withBiowasm: args.includes("--with-biowasm") || process.env.ONBOARD_BIOWASM === "1",
48
+ sqlitePath: getArgVal("--sqlite-path=") || process.env.ONBOARD_SQLITE_PATH || null,
49
+ client: getArgVal("--client=") || null,
50
+ registry: getArgVal("--registry=") || process.env.NPM_CONFIG_REGISTRY || "https://registry.npmjs.org",
51
+ nonInteractive: args.includes("--non-interactive") || !process.stdin.isTTY,
52
+ };
53
+
54
+ console.log("[bioresearcher-onboard] Initializing project-local BioMCP runtime...");
55
+
56
+ // 3. Prepare isolated .bioresearcher-runtime directory
57
+ fs.mkdirSync(RUNTIME_ROOT, { recursive: true });
58
+ fs.mkdirSync(CACHE_DIR, { recursive: true });
59
+
60
+ const runtimePkgJson = path.join(RUNTIME_ROOT, "package.json");
61
+ if (!fs.existsSync(runtimePkgJson)) {
62
+ fs.writeFileSync(runtimePkgJson, JSON.stringify({ name: "bioresearcher-runtime", private: true }, null, 2));
63
+ }
64
+
65
+ // 4. Determine packages to install
66
+ const packagesToInstall = ["biomcp@1.6.0"];
67
+ if (options.withR) packagesToInstall.push("webr@0.6");
68
+ if (options.withMysql) packagesToInstall.push("mysql2@3");
69
+
70
+ console.log(`[bioresearcher-onboard] Installing dependencies (${packagesToInstall.join(", ")}) via ${options.registry}...`);
71
+
72
+ const npmEnv = {
73
+ ...process.env,
74
+ npm_config_cache: CACHE_DIR,
75
+ npm_config_userconfig: IS_WIN ? "NUL" : "/dev/null",
76
+ npm_config_audit: "false",
77
+ npm_config_fund: "false",
78
+ npm_config_update_notifier: "false",
79
+ npm_config_registry: options.registry,
80
+ };
81
+
82
+ const installArgs = ["install", "--prefix", RUNTIME_ROOT, "--ignore-scripts", ...packagesToInstall];
83
+ const installRes = spawnSync(npmBin, installArgs, {
84
+ env: npmEnv,
85
+ stdio: "inherit",
86
+ cwd: RUNTIME_ROOT,
87
+ });
88
+
89
+ if (installRes.status !== 0) {
90
+ console.error("[bioresearcher-onboard] Error: Failed to install packages into .bioresearcher-runtime");
91
+ process.exit(installRes.status || 1);
92
+ }
93
+
94
+ // 5. Verify bundle path
95
+ const bundlePath = path.join(RUNTIME_ROOT, "node_modules", "biomcp", "dist", "bundle.js");
96
+ if (!fs.existsSync(bundlePath)) {
97
+ console.error(`[bioresearcher-onboard] Error: BioMCP bundle not found at ${bundlePath}`);
98
+ process.exit(1);
99
+ }
100
+
101
+ // 6. Generate .biomcp.json if optional features are requested
102
+ const featuresConfig = {};
103
+ if (options.withR) {
104
+ featuresConfig.analysis_r = { enabled: true };
105
+ }
106
+ if (options.withBiowasm) {
107
+ featuresConfig.analysis_biowasm = { enabled: true };
108
+ }
109
+ if (options.sqlitePath) {
110
+ featuresConfig.database = {
111
+ enabled: true,
112
+ type: "sqlite",
113
+ sqlite_path: options.sqlitePath,
114
+ };
115
+ } else if (options.withMysql) {
116
+ featuresConfig.database = {
117
+ enabled: true,
118
+ type: "mysql",
119
+ };
120
+ }
121
+
122
+ const biomcpJsonPath = path.resolve(CWD, ".biomcp.json");
123
+ if (Object.keys(featuresConfig).length > 0) {
124
+ let existing = {};
125
+ if (fs.existsSync(biomcpJsonPath)) {
126
+ try {
127
+ existing = JSON.parse(fs.readFileSync(biomcpJsonPath, "utf8"));
128
+ } catch {}
129
+ }
130
+ existing.features = { ...existing.features, ...featuresConfig };
131
+
132
+ // Write atomically with 0o600 permissions
133
+ const tmpPath = `${biomcpJsonPath}.${Date.now()}.tmp`;
134
+ fs.writeFileSync(tmpPath, JSON.stringify(existing, null, 2), { mode: 0o600 });
135
+ fs.renameSync(tmpPath, biomcpJsonPath);
136
+ console.log(`[bioresearcher-onboard] Configured optional features in .biomcp.json`);
137
+ }
138
+
139
+ // 7. Non-destructive deep-merge of client harness configuration files
140
+ // Normalize Windows paths to POSIX forward slashes for valid JSON strings
141
+ const normalizedNodePath = IS_WIN ? nodeBin.replace(/\\/g, "/") : nodeBin;
142
+ const normalizedBundlePath = IS_WIN ? bundlePath.replace(/\\/g, "/") : bundlePath;
143
+
144
+ function stripJsonc(content) {
145
+ let result = "";
146
+ let inString = false;
147
+ let inSingleComment = false;
148
+ let inMultiComment = false;
149
+ let isEscaped = false;
150
+
151
+ for (let i = 0; i < content.length; i++) {
152
+ const ch = content[i];
153
+ const next = content[i + 1];
154
+
155
+ if (inSingleComment) {
156
+ if (ch === "\n") {
157
+ inSingleComment = false;
158
+ result += ch;
159
+ }
160
+ continue;
161
+ }
162
+
163
+ if (inMultiComment) {
164
+ if (ch === "*" && next === "/") {
165
+ inMultiComment = false;
166
+ i++;
167
+ }
168
+ continue;
169
+ }
170
+
171
+ if (inString) {
172
+ result += ch;
173
+ if (isEscaped) {
174
+ isEscaped = false;
175
+ } else if (ch === "\\") {
176
+ isEscaped = true;
177
+ } else if (ch === "\"") {
178
+ inString = false;
179
+ }
180
+ continue;
181
+ }
182
+
183
+ if (ch === "\"") {
184
+ inString = true;
185
+ isEscaped = false;
186
+ result += ch;
187
+ continue;
188
+ }
189
+
190
+ if (ch === "/" && next === "/") {
191
+ inSingleComment = true;
192
+ i++;
193
+ continue;
194
+ }
195
+
196
+ if (ch === "/" && next === "*") {
197
+ inMultiComment = true;
198
+ i++;
199
+ continue;
200
+ }
201
+
202
+ if (ch === ",") {
203
+ let j = i + 1;
204
+ let isTrailing = false;
205
+ let tempInSingle = false;
206
+ let tempInMulti = false;
207
+ while (j < content.length) {
208
+ const cj = content[j];
209
+ const nj = content[j + 1];
210
+ if (tempInSingle) {
211
+ if (cj === "\n") tempInSingle = false;
212
+ j++;
213
+ continue;
214
+ }
215
+ if (tempInMulti) {
216
+ if (cj === "*" && nj === "/") {
217
+ tempInMulti = false;
218
+ j += 2;
219
+ continue;
220
+ }
221
+ j++;
222
+ continue;
223
+ }
224
+ if (cj === "/" && nj === "/") {
225
+ tempInSingle = true;
226
+ j += 2;
227
+ continue;
228
+ }
229
+ if (cj === "/" && nj === "*") {
230
+ tempInMulti = true;
231
+ j += 2;
232
+ continue;
233
+ }
234
+ if (/\s/.test(cj)) {
235
+ j++;
236
+ continue;
237
+ }
238
+ if (cj === "}" || cj === "]") {
239
+ isTrailing = true;
240
+ }
241
+ break;
242
+ }
243
+ if (isTrailing) {
244
+ continue;
245
+ }
246
+ }
247
+
248
+ result += ch;
249
+ }
250
+
251
+ return result.trim();
252
+ }
253
+
254
+ function safeMergeJson(filePath, updater) {
255
+ let data = {};
256
+ let backedUp = false;
257
+ if (fs.existsSync(filePath)) {
258
+ const raw = fs.readFileSync(filePath, "utf8");
259
+ if (raw.trim().length > 0) {
260
+ try {
261
+ data = JSON.parse(stripJsonc(raw));
262
+ } catch (e) {
263
+ console.error(`[bioresearcher-onboard] Error: Failed to parse existing JSONC at ${filePath}: ${e.message}`);
264
+ console.error(`[bioresearcher-onboard] Aborting modification to prevent data loss. Existing file was not modified.`);
265
+ process.exit(1);
266
+ }
267
+ }
268
+ fs.copyFileSync(filePath, `${filePath}.bak`);
269
+ backedUp = true;
270
+ }
271
+
272
+ if (typeof data !== "object" || data === null || Array.isArray(data)) {
273
+ data = {};
274
+ }
275
+
276
+ const updated = updater(data);
277
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
278
+ const tmp = `${filePath}.${Date.now()}.tmp`;
279
+ fs.writeFileSync(tmp, JSON.stringify(updated, null, 2));
280
+ fs.renameSync(tmp, filePath);
281
+ if (backedUp) {
282
+ console.log(`[bioresearcher-onboard] Updated ${path.basename(filePath)} (backup saved to ${path.basename(filePath)}.bak)`);
283
+ } else {
284
+ console.log(`[bioresearcher-onboard] Created ${path.basename(filePath)}`);
285
+ }
286
+ }
287
+
288
+ // Probe harness configs upfront to avoid generating unintended files
289
+ const opencodePath = path.resolve(CWD, "opencode.json");
290
+ const claudePath = path.resolve(CWD, ".mcp.json");
291
+ const cursorDir = path.resolve(CWD, ".cursor");
292
+ const cursorPath = path.join(cursorDir, "mcp.json");
293
+
294
+ const zcodeDir = path.resolve(CWD, ".zcode");
295
+ const zcodePath = path.join(zcodeDir, "config.json");
296
+
297
+ const piDir = path.resolve(CWD, ".pi");
298
+ const piPath = path.join(piDir, "mcp.json");
299
+
300
+ const codebuddyDir = path.resolve(CWD, ".codebuddy");
301
+ const codebuddySettingsPath = path.join(codebuddyDir, "settings.json");
302
+ const codebuddyMdPath = path.resolve(CWD, "CODEBUDDY.md");
303
+
304
+ const workbuddyDir = path.resolve(CWD, ".workbuddy");
305
+ const workbuddyPath = path.join(workbuddyDir, "mcp.json");
306
+ const workbuddyMdPath = path.resolve(CWD, "WORKBUDDY.md");
307
+
308
+ const opencodeExists = fs.existsSync(opencodePath);
309
+ const claudeExists = fs.existsSync(claudePath);
310
+ const cursorExists = fs.existsSync(cursorDir) || fs.existsSync(cursorPath);
311
+ const zcodeExists = fs.existsSync(zcodeDir) || fs.existsSync(zcodePath) || Boolean(process.env.ZCODE_WORKSPACE);
312
+ const piExists = fs.existsSync(piDir) || fs.existsSync(piPath) || Boolean(process.env.PI_CODING_AGENT_DIR);
313
+ const codebuddyExists = fs.existsSync(codebuddyDir) || fs.existsSync(codebuddyMdPath) || Boolean(process.env.CODEBUDDY_CLI);
314
+ const workbuddyExists = fs.existsSync(workbuddyDir) || fs.existsSync(workbuddyPath) || fs.existsSync(workbuddyMdPath);
315
+
316
+ // Normalize client argument with aliases
317
+ const clientArg = (options.client || "").toLowerCase().trim();
318
+ const clientAliases = {
319
+ "claude": "claude-code",
320
+ "code-buddy": "codebuddy",
321
+ "work-buddy": "workbuddy",
322
+ "pi-agent": "pi",
323
+ };
324
+ const resolvedClient = clientAliases[clientArg] || clientArg;
325
+
326
+ const validClients = ["opencode", "claude-code", "cursor", "zcode", "pi", "codebuddy", "workbuddy"];
327
+ if (resolvedClient && !validClients.includes(resolvedClient)) {
328
+ console.error(`[bioresearcher-onboard] Error: Unknown client "${options.client}". Valid options: ${validClients.join(", ")}`);
329
+ process.exit(1);
330
+ }
331
+
332
+ let targetOpencode = resolvedClient === "opencode" || (!resolvedClient && opencodeExists);
333
+ let targetClaude = resolvedClient === "claude-code" || (!resolvedClient && claudeExists && !codebuddyExists);
334
+ let targetCursor = resolvedClient === "cursor" || (!resolvedClient && cursorExists);
335
+ let targetZcode = resolvedClient === "zcode" || (!resolvedClient && zcodeExists);
336
+ let targetPi = resolvedClient === "pi" || (!resolvedClient && piExists);
337
+ let targetCodebuddy = resolvedClient === "codebuddy" || (!resolvedClient && codebuddyExists);
338
+ let targetWorkbuddy = resolvedClient === "workbuddy" || (!resolvedClient && workbuddyExists);
339
+
340
+ // Default to opencode.json if no client specified and no config file exists yet
341
+ const anyDetected = opencodeExists || claudeExists || cursorExists || zcodeExists || piExists || codebuddyExists || workbuddyExists;
342
+ if (!resolvedClient && !anyDetected) {
343
+ targetOpencode = true;
344
+ }
345
+
346
+ // OpenCode: opencode.json (canonical v2 shape mcp.servers.<name>)
347
+ if (targetOpencode) {
348
+ const npxCmd = IS_WIN ? "npx.cmd" : "npx";
349
+ safeMergeJson(opencodePath, (data) => {
350
+ data.$schema = data.$schema || "https://opencode.ai/config.json";
351
+ data.mcp = data.mcp || {};
352
+ data.mcp.servers = data.mcp.servers || {};
353
+ // Migrate legacy flat entry (pre-v2 onboard / old plugin config hook):
354
+ // preserve environment, convert flat timeout N to the triple form.
355
+ const legacy = data.mcp.biomcp;
356
+ if (data.mcp.servers.biomcp === undefined && legacy && typeof legacy === "object" && !Array.isArray(legacy)) {
357
+ const flatTimeout = typeof legacy.timeout === "number" ? legacy.timeout : 120000;
358
+ data.mcp.servers.biomcp = {
359
+ type: "local",
360
+ command: [npxCmd, "-y", "-p", "biomcp@1.6.0", "biomcp"],
361
+ environment: legacy.environment || {},
362
+ timeout: { startup: flatTimeout, catalog: flatTimeout, execution: flatTimeout },
363
+ };
364
+ } else if (data.mcp.servers.biomcp === undefined) {
365
+ data.mcp.servers.biomcp = {
366
+ type: "local",
367
+ command: [npxCmd, "-y", "-p", "biomcp@1.6.0", "biomcp"],
368
+ environment: {},
369
+ timeout: { startup: 120000, catalog: 120000, execution: 120000 },
370
+ };
371
+ }
372
+ // An existing canonical entry is left untouched; drop the migrated flat key.
373
+ if (legacy !== undefined) delete data.mcp.biomcp;
374
+ if (Object.keys(data.mcp).length === 0) delete data.mcp;
375
+ return data;
376
+ });
377
+ }
378
+
379
+ // Claude Code: .mcp.json
380
+ if (targetClaude) {
381
+ safeMergeJson(claudePath, (data) => {
382
+ data.mcpServers = data.mcpServers || {};
383
+ data.mcpServers.biomcp = {
384
+ type: "stdio",
385
+ command: normalizedNodePath,
386
+ args: [normalizedBundlePath],
387
+ env: data.mcpServers.biomcp?.env || {},
388
+ };
389
+ return data;
390
+ });
391
+ }
392
+
393
+ // Cursor: .cursor/mcp.json
394
+ if (targetCursor) {
395
+ safeMergeJson(cursorPath, (data) => {
396
+ data.mcpServers = data.mcpServers || {};
397
+ data.mcpServers.biomcp = {
398
+ command: normalizedNodePath,
399
+ args: [normalizedBundlePath],
400
+ env: data.mcpServers.biomcp?.env || {},
401
+ };
402
+ return data;
403
+ });
404
+ }
405
+
406
+ // ZCode: .zcode/config.json
407
+ if (targetZcode) {
408
+ safeMergeJson(zcodePath, (data) => {
409
+ data.mcp = data.mcp || {};
410
+ data.mcp.servers = data.mcp.servers || {};
411
+ data.mcp.servers.biomcp = {
412
+ command: normalizedNodePath,
413
+ args: [normalizedBundlePath],
414
+ env: data.mcp.servers.biomcp?.env || {},
415
+ enable: true,
416
+ };
417
+ return data;
418
+ });
419
+ }
420
+
421
+ // Pi Coding Agent: .pi/mcp.json
422
+ if (targetPi) {
423
+ safeMergeJson(piPath, (data) => {
424
+ data.mcpServers = data.mcpServers || {};
425
+ data.mcpServers.biomcp = {
426
+ command: normalizedNodePath,
427
+ args: [normalizedBundlePath],
428
+ env: data.mcpServers.biomcp?.env || {},
429
+ };
430
+ return data;
431
+ });
432
+ }
433
+
434
+ // CodeBuddy: .mcp.json + pre-approval in .codebuddy/settings.json
435
+ if (targetCodebuddy) {
436
+ safeMergeJson(claudePath, (data) => {
437
+ data.mcpServers = data.mcpServers || {};
438
+ data.mcpServers.biomcp = {
439
+ type: "stdio",
440
+ command: normalizedNodePath,
441
+ args: [normalizedBundlePath],
442
+ env: data.mcpServers.biomcp?.env || {},
443
+ };
444
+ return data;
445
+ });
446
+
447
+ safeMergeJson(codebuddySettingsPath, (data) => {
448
+ const approved = new Set(data.enabledMcpjsonServers || []);
449
+ approved.add("biomcp");
450
+ data.enabledMcpjsonServers = Array.from(approved);
451
+ return data;
452
+ });
453
+ }
454
+
455
+ // WorkBuddy: .workbuddy/mcp.json
456
+ if (targetWorkbuddy) {
457
+ safeMergeJson(workbuddyPath, (data) => {
458
+ data.mcpServers = data.mcpServers || {};
459
+ data.mcpServers.biomcp = {
460
+ type: "stdio",
461
+ command: normalizedNodePath,
462
+ args: [normalizedBundlePath],
463
+ env: data.mcpServers.biomcp?.env || {},
464
+ };
465
+ return data;
466
+ });
467
+ }
468
+
469
+ // 8. Run pre-flight verification via biomcp doctor --json
470
+ console.log("[bioresearcher-onboard] Running pre-flight verification via biomcp doctor...");
471
+ const cliPath = path.join(RUNTIME_ROOT, "node_modules", "biomcp", "dist", "cli.js");
472
+ const doctorRes = spawnSync(nodeBin, [cliPath, "doctor", "--json"], {
473
+ cwd: CWD,
474
+ encoding: "utf8",
475
+ });
476
+
477
+ if (doctorRes.status === 0) {
478
+ try {
479
+ const report = JSON.parse(doctorRes.stdout);
480
+ console.log(`[bioresearcher-onboard] ✓ Pre-flight check PASSED (schema v${report.schema_version})`);
481
+ console.log(` Node: ${report.node.version} (required ${report.node.required})`);
482
+ console.log(` Install mode: ${report.server_context.install_mode}`);
483
+ for (const f of report.features) {
484
+ console.log(` Feature ${f.id}: ${f.running_after_restart ? "ON after restart" : "off"}`);
485
+ }
486
+ } catch {
487
+ console.log("[bioresearcher-onboard] ✓ Doctor exit code 0");
488
+ }
489
+ } else {
490
+ console.warn("[bioresearcher-onboard] Warning: Doctor reported potential blockers:");
491
+ console.log(doctorRes.stdout || doctorRes.stderr);
492
+ }
493
+
494
+ // 9. Git Hygiene: Ensure .bioresearcher-runtime is gitignored
495
+ const gitignorePath = path.resolve(CWD, ".gitignore");
496
+ let gitignoreContent = "";
497
+ if (fs.existsSync(gitignorePath)) {
498
+ gitignoreContent = fs.readFileSync(gitignorePath, "utf8");
499
+ }
500
+ if (!gitignoreContent.includes(".bioresearcher-runtime")) {
501
+ const newline = gitignoreContent.length > 0 && !gitignoreContent.endsWith("\n") ? "\n" : "";
502
+ fs.appendFileSync(gitignorePath, `${newline}# BioMCP project-local runtime\n.bioresearcher-runtime/\n`);
503
+ console.log("[bioresearcher-onboard] Added .bioresearcher-runtime/ to .gitignore");
504
+ }
505
+
506
+ console.log("\n========================================================");
507
+ console.log("✓ BioMCP runtime bootstrapped successfully!");
508
+ console.log(` Runtime directory: .bioresearcher-runtime/`);
509
+ console.log(` Node.js: ${nodeBin}`);
510
+ console.log(` BioMCP bundle: ${bundlePath}`);
511
+ console.log("\n→ NEXT STEP: Restart your agent/client session to activate biomcp tools.");
512
+ console.log("========================================================\n");
package/loader.js DELETED
@@ -1,3 +0,0 @@
1
- // Root loader for OpenCode shallow plugin auto-discovery (.opencode/plugins/bioresearcher.js).
2
- export { default } from "./bioresearcher/index.js";
3
- export * from "./bioresearcher/index.js";