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.
- package/README.md +110 -49
- package/agents/bioresearcher-dr-worker.md +32 -20
- package/connector-meta.json +6 -5
- package/index.js +146 -61
- package/package.json +4 -2
- package/skill-bundle.json +3 -5
- package/skills/bioresearcher-deep-research/SKILL.md +52 -6
- package/skills/bioresearcher-deep-research/references/analysis-methods.md +15 -0
- package/skills/bioresearcher-deep-research/references/article-literature.md +36 -18
- package/skills/bioresearcher-deep-research/references/cartography.md +190 -0
- package/skills/bioresearcher-deep-research/references/diseases.md +1 -1
- package/skills/bioresearcher-deep-research/references/drugs.md +5 -4
- package/skills/bioresearcher-deep-research/references/functional-genomics.md +7 -3
- package/skills/bioresearcher-deep-research/references/genes.md +5 -3
- package/skills/bioresearcher-deep-research/references/patents.md +9 -3
- package/skills/bioresearcher-deep-research/references/rate-limiting-auth.md +7 -2
- package/skills/bioresearcher-deep-research/references/report-template.md +17 -0
- package/skills/bioresearcher-deep-research/references/tool-selection.md +8 -5
- package/skills/bioresearcher-deep-research/references/utility-config.md +2 -2
- package/skills/bioresearcher-deep-research/references/worker-protocol.md +16 -1
- package/skills/bioresearcher-onboard/SKILL.md +114 -0
- package/skills/bioresearcher-onboard/scripts/bootstrap.ps1 +96 -0
- package/skills/bioresearcher-onboard/scripts/bootstrap.sh +127 -0
- package/skills/bioresearcher-onboard/scripts/onboard.mjs +512 -0
- package/loader.js +0 -3
|
@@ -67,6 +67,23 @@ the source of truth for citations]
|
|
|
67
67
|
[queries that failed after retries, with reasons]
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
+
## Map-first optional sections
|
|
71
|
+
|
|
72
|
+
When the run used empirical cartography (SKILL.md Step 1.5), two OPTIONAL
|
|
73
|
+
sections extend the mandatory structure. Both cite through the normal
|
|
74
|
+
merged-ledger markers - cartography anchors are ordinary ledger records.
|
|
75
|
+
|
|
76
|
+
- **Landscape** (inside Findings, after the selected aspects): one line per
|
|
77
|
+
discovered-but-unselected category, citing its cartography anchors -
|
|
78
|
+
acknowledged, not researched; the report must say so explicitly.
|
|
79
|
+
- **Decision guide by question scenario** (after the findings/evidence
|
|
80
|
+
tables; DEFAULT-ON in map-first mode, skippable only if the user
|
|
81
|
+
declines): one compact table per user-confirmed question scenario -
|
|
82
|
+
scenario | recommended method sequence | tier | caveat - built only from
|
|
83
|
+
ledger-verified sources, with tiers labeled scope-relative.
|
|
84
|
+
- Taxonomy disagreements between the field's own syntheses are reported in
|
|
85
|
+
Analysis Methodology or Findings - never silently resolved.
|
|
86
|
+
|
|
70
87
|
## Citation placement rules
|
|
71
88
|
|
|
72
89
|
- Authored text uses semantic cite-key markers `[@pmid:...]`, groups
|
|
@@ -5,10 +5,11 @@ Route a research question to the correct biomcp tool, then shape the call with
|
|
|
5
5
|
|
|
6
6
|
## Overview
|
|
7
7
|
|
|
8
|
-
biomcp (npm `biomcp`, pinned `biomcp@1.
|
|
9
|
-
environment-gated optional tools (3 database, 4 R analysis, 8 biowasm).
|
|
10
|
-
|
|
11
|
-
domain
|
|
8
|
+
biomcp (npm `biomcp`, pinned `biomcp@1.6`) exposes 58 tools: 43 core plus 15
|
|
9
|
+
environment-gated optional tools (3 database, 4 R analysis, 8 biowasm). The
|
|
10
|
+
1.6 core set adds `journal_metrics` and `preprint_fulltext` to the article
|
|
11
|
+
family. This file routes question types to tools; per-domain parameter
|
|
12
|
+
detail lives in the domain reference files.
|
|
12
13
|
|
|
13
14
|
> In MCP clients that prefix server tools (e.g. opencode with server name
|
|
14
15
|
> 'biomcp'), tools appear as biomcp_article_search etc.
|
|
@@ -20,6 +21,8 @@ QUESTION TYPE
|
|
|
20
21
|
├─ Literature / papers / PubMed
|
|
21
22
|
│ → article_search (query, source?, dateRange?, limit, offset)
|
|
22
23
|
│ → article_get (id: PMID/PMCID/DOI, sections?, citation_mode?)
|
|
24
|
+
│ → preprint_fulltext (bioRxiv/medRxiv preprint DOI, version?) # on-demand full text; license disclosed
|
|
25
|
+
│ → journal_metrics (journal name / NLM abbreviation / ISSN, limit <= 25) # OpenAlex venue quality (2-yr citedness, h-index, i10, OA) before citing
|
|
23
26
|
│ → details: references/article-literature.md
|
|
24
27
|
│
|
|
25
28
|
├─ Clinical trials / NCT IDs
|
|
@@ -131,7 +134,7 @@ Question: "What evidence links BRAF V600E to melanoma drug resistance?"
|
|
|
131
134
|
|---------|-------|-----|
|
|
132
135
|
| `no_such_tool` for a db/analysis tool | feature not enabled, or enabled after server start (tools register at startup only) | set `DB_TYPE`/`ANALYSIS_R`/`ANALYSIS_BIOWASM` in the client env block, restart the client |
|
|
133
136
|
| Tool error mentioning OncoKB token | `variant_oncokb` without `ONCOKB_TOKEN` | get a token (oncokb.org registration) and set it, or skip OncoKB |
|
|
134
|
-
| gene_diseases returns an `_error`
|
|
137
|
+
| gene_diseases returns an `_error` row | BOTH DisGeNET and OpenTargets failed - not merely a missing key | without `DISGENET_API_KEY` the tool silently returns OpenTargets rows (source: "opentargets"); add the key for DisGeNET-grade associations |
|
|
135
138
|
| variant_search returns nothing for "BRAF V600E" as `query` | compound free text is not a variant ID | use `gene="BRAF"`, `hgvsp="V600E"` as separate params (the tool also auto-splits a bare "GENE V600E" query, but explicit params are reliable) |
|
|
136
139
|
| Trial pages repeat or skip | offset paging used on trial_search | use `page_token` cursor paging |
|
|
137
140
|
|
|
@@ -104,13 +104,13 @@ Check a feature's parameters in detail:
|
|
|
104
104
|
| `no_such_tool` after enabling a feature | tools register at server start only | restart the client/session, then verify with `biomcp_configure` `{}` (`running_now`) |
|
|
105
105
|
| set refused: "sensitive" | sensitive key class requires confirmation | re-send identical call with `confirm_sensitive: true` |
|
|
106
106
|
| `cwd_refused` | server cwd is / or $HOME | use the client env block (error carries the translation) |
|
|
107
|
-
| batch_get item row contains `
|
|
107
|
+
| batch_get item row contains `success: false` + `error` | that single ID failed (typo, unknown ID) | fix the ID and re-request just that item; the batch continues and other items succeeded |
|
|
108
108
|
|
|
109
109
|
## Integration notes
|
|
110
110
|
|
|
111
111
|
- Smoke-test sequence for a fresh setup: `biomcp_configure` with `{}` ->
|
|
112
112
|
confirm expected features `running_now` -> one cheap domain call.
|
|
113
|
-
- `doctor` CLI complements this: `npx -y biomcp@1.
|
|
113
|
+
- `doctor` CLI complements this: `npx -y biomcp@1.6 doctor` (exit 0 = clear);
|
|
114
114
|
`--client opencode` emits a paste-ready client entry.
|
|
115
115
|
- Multi-entity literature pulls (e.g. 10 PMIDs from article_search) belong in
|
|
116
116
|
ONE `batch_get` call, not 10 article_get calls.
|
|
@@ -38,6 +38,18 @@ EXECUTION RULE: Do NOT read or inspect evidence-ledger.py or other skill scripts
|
|
|
38
38
|
startup (via `${CLAUDE_PLUGIN_ROOT}`); the orchestrator sends ONLY the
|
|
39
39
|
filled-in template below.
|
|
40
40
|
|
|
41
|
+
## Cartographer workers (map-first mode)
|
|
42
|
+
|
|
43
|
+
Cartography axes use the SAME worker contract (rules 1-9, file protocol,
|
|
44
|
+
completion gate) with two substitutions: the deliverable is a CATEGORY MAP
|
|
45
|
+
(`reports/<TOPIC>/category_map_<axis>.md`: one subsection per anchored
|
|
46
|
+
category - name, one-line description, 1-3 anchor markers, maturity signals,
|
|
47
|
+
surfacing queries - plus a Query Log and Evidence Gaps) instead of an aspect
|
|
48
|
+
report, and the focus name is `cartography_<axis>`. The dispatch prompt
|
|
49
|
+
template, axis archetypes, anti-pinning contract, and anchoring rule live in
|
|
50
|
+
`references/cartography.md`. Tier A workers read that file too when the
|
|
51
|
+
assigned focus starts with `cartography_`.
|
|
52
|
+
|
|
41
53
|
## File protocol
|
|
42
54
|
|
|
43
55
|
- Output files (exactly TWO - together they are the self-contained
|
|
@@ -132,7 +144,10 @@ EXECUTION RULE: Do NOT read or inspect evidence-ledger.py or other skill scripts
|
|
|
132
144
|
`python3 <SKILL_DIR>/scripts/evidence-ledger.py add <file> --stdin`,
|
|
133
145
|
substituting the SKILL_DIR value from your prompt LITERALLY - it is a
|
|
134
146
|
path string, NOT an environment variable (`$SKILL_DIR` in a shell
|
|
135
|
-
resolves to nothing and breaks the call).
|
|
147
|
+
resolves to nothing and breaks the call). Anchor every shell command
|
|
148
|
+
to the workspace root (`cd <workspace root> && python3 <SKILL_DIR>/...`)
|
|
149
|
+
so relative report paths resolve regardless of the shell's starting
|
|
150
|
+
directory. Pass records via a shell heredoc
|
|
136
151
|
or with an array/JSONL file (`add <file> @<batch.json>`):
|
|
137
152
|
```bash
|
|
138
153
|
python3 <SKILL_DIR>/scripts/evidence-ledger.py add reports/<TOPIC>/evidence/<YOUR-FOCUS>.jsonl --stdin << 'EOF'
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bioresearcher-onboard
|
|
3
|
+
description: "Bootstraps a project-local biomcp MCP server runtime in .bioresearcher-runtime/: downloads portable Node.js 22 (if missing), vendors biomcp with fast mirror support (official or npmmirror), configures optional features (R, Biowasm, SQLite), and registers the server in OpenCode, Claude Code, Cursor, ZCode, Pi, CodeBuddy, or WorkBuddy. Use when biomcp is not installed, when biomedical tools are missing, or on requests like setup bioresearcher, install biomcp, or onboard."
|
|
4
|
+
license: Apache-2.0
|
|
5
|
+
compatibility: "Unix-like shells (Linux, macOS) and Windows (PowerShell, cmd.exe); OpenCode, Claude Code, Cursor, ZCode, Pi Coding Agent, CodeBuddy, WorkBuddy"
|
|
6
|
+
metadata:
|
|
7
|
+
version: "1.2.0"
|
|
8
|
+
source: "bioresearcher-skills"
|
|
9
|
+
allowed-tools: Bash Read Write Edit
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# BioMCP Project-Local Onboarding
|
|
13
|
+
|
|
14
|
+
This skill sets up a self-contained, project-local BioMCP runtime in your
|
|
15
|
+
working directory under `.bioresearcher-runtime/`.
|
|
16
|
+
|
|
17
|
+
## What it does
|
|
18
|
+
|
|
19
|
+
- Checks if the host has Node.js >= 22.13. If missing, downloads a pinned,
|
|
20
|
+
cryptographically verified portable Node.js LTS binary into
|
|
21
|
+
`.bioresearcher-runtime/node/` (zero global installation, does not touch `~`
|
|
22
|
+
or `/usr/local`).
|
|
23
|
+
- Auto-detects network conditions (official distribution vs. fast npmmirror in
|
|
24
|
+
mainland China).
|
|
25
|
+
- Installs `biomcp` locally into `.bioresearcher-runtime/node_modules/` with
|
|
26
|
+
sub-100ms startup latency and offline resilience.
|
|
27
|
+
- Configures optional features (R analysis, Biowasm genomics, SQLite database)
|
|
28
|
+
and registers the server in your harness configuration (`opencode.json`
|
|
29
|
+
under the canonical `mcp.servers.biomcp` key, `.mcp.json`, etc.) without
|
|
30
|
+
overwriting existing settings.
|
|
31
|
+
- Verifies the configuration using the built-in diagnostic doctor.
|
|
32
|
+
|
|
33
|
+
## Steps
|
|
34
|
+
|
|
35
|
+
Follow the steps below in order.
|
|
36
|
+
|
|
37
|
+
### Step 1: Run Stage 0 Bootstrap
|
|
38
|
+
|
|
39
|
+
Execute the bootstrap script corresponding to your operating system.
|
|
40
|
+
|
|
41
|
+
**For Unix-like shells (Linux, macOS, Git Bash):**
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
bash skills/bioresearcher-onboard/scripts/bootstrap.sh
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
**For Windows (PowerShell):**
|
|
48
|
+
|
|
49
|
+
```powershell
|
|
50
|
+
powershell -NoProfile -ExecutionPolicy Bypass -File skills\bioresearcher-onboard\scripts\bootstrap.ps1
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
The script automatically:
|
|
54
|
+
1. Reuses your host Node.js if version >= 22.13 is available.
|
|
55
|
+
2. If missing, downloads and verifies the official portable Node.js archive into
|
|
56
|
+
`.bioresearcher-runtime/node/`.
|
|
57
|
+
3. Installs `biomcp@1.6.0` into `.bioresearcher-runtime/node_modules/`.
|
|
58
|
+
4. Updates your harness configuration (`opencode.json` or `.mcp.json`) with
|
|
59
|
+
absolute executable paths.
|
|
60
|
+
|
|
61
|
+
### Step 2: Configure Optional Features (Optional)
|
|
62
|
+
|
|
63
|
+
By default, the core biomedical tools (PubMed/literature, clinical trials,
|
|
64
|
+
genes, variants, drugs, diseases, patents) and built-in SQLite are installed.
|
|
65
|
+
|
|
66
|
+
If the user needs specialized capabilities, pass the corresponding flags to the
|
|
67
|
+
bootstrap script or set environment variables before running:
|
|
68
|
+
|
|
69
|
+
- **R / Bioconductor Analysis** (DESeq2, edgeR, limma; requires ~2 GB RAM):
|
|
70
|
+
Pass `--with-r` to install the `webr@0.6` peer dependency and enable R
|
|
71
|
+
analysis in `.biomcp.json`.
|
|
72
|
+
- **Biowasm Analysis** (SAM/BAM/BED/BCF genomics tools):
|
|
73
|
+
Pass `--with-biowasm` to enable Biowasm in `.biomcp.json`.
|
|
74
|
+
- **Local SQLite Database**:
|
|
75
|
+
Pass `--sqlite-path=<path_to_db>` (e.g. `--sqlite-path=data/research.db`).
|
|
76
|
+
- **Client Override**:
|
|
77
|
+
Pass `--client=opencode`, `--client=claude-code`, `--client=cursor`,
|
|
78
|
+
`--client=zcode`, `--client=pi`, `--client=codebuddy`, or
|
|
79
|
+
`--client=workbuddy` if auto-detection should be overridden.
|
|
80
|
+
|
|
81
|
+
Example with R analysis and SQLite enabled:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
bash skills/bioresearcher-onboard/scripts/bootstrap.sh --with-r --sqlite-path=data/research.db
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Step 3: In-Session Feature Reconfiguration
|
|
88
|
+
|
|
89
|
+
Once BioMCP is registered and running, you do not need to hand-edit
|
|
90
|
+
configuration files. Use the built-in `biomcp_configure` tool to inspect or
|
|
91
|
+
adjust features dynamically:
|
|
92
|
+
|
|
93
|
+
- Inspect feature status:
|
|
94
|
+
`biomcp_configure(action="status")`
|
|
95
|
+
- Enable or disable features:
|
|
96
|
+
`biomcp_configure(action="set", values={"features.analysis_r.enabled": true})`
|
|
97
|
+
- Configure SQLite database:
|
|
98
|
+
`biomcp_configure(action="set", values={"features.database.enabled": true, "features.database.type": "sqlite", "features.database.sqlite_path": "data/research.db"}, confirm_sensitive=true)`
|
|
99
|
+
|
|
100
|
+
### Step 4: Restart the Harness
|
|
101
|
+
|
|
102
|
+
MCP servers are spawned at client startup. Instruct the user to restart their
|
|
103
|
+
agent session or IDE to activate the newly connected BioMCP tools:
|
|
104
|
+
|
|
105
|
+
- **OpenCode**: Restart the session or open a new terminal session.
|
|
106
|
+
- **Claude Code**: Start a new session (`claude`).
|
|
107
|
+
- **Cursor / VS Code**: Reload the window or restart the application.
|
|
108
|
+
- **ZCode**: Reload the workspace or start a new ADE session.
|
|
109
|
+
- **Pi Coding Agent**: Start a new agent session (`pi`).
|
|
110
|
+
- **CodeBuddy**: Reload the window or restart the CLI session.
|
|
111
|
+
- **WorkBuddy**: Restart the application or switch workspace.
|
|
112
|
+
|
|
113
|
+
After restarting, verify connectivity by asking the agent to search for a gene
|
|
114
|
+
or article (e.g., `gene_search(query="BRAF")`).
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Stage 0 Zero-Dependency PowerShell Bootstrap for bioresearcher-onboard (Windows)
|
|
2
|
+
# Checks for existing Node >= 22.13; if missing, downloads pinned portable
|
|
3
|
+
# Node.js LTS into .bioresearcher-runtime\node, verifies SHA256, and hands off
|
|
4
|
+
# execution to onboard.mjs.
|
|
5
|
+
$ErrorActionPreference = "Stop"
|
|
6
|
+
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
7
|
+
$RuntimeRoot = if ($env:BIORESEARCHER_RUNTIME_DIR) { $env:BIORESEARCHER_RUNTIME_DIR } else { Join-Path (Get-Location).Path ".bioresearcher-runtime" }
|
|
8
|
+
$NodeDir = Join-Path $RuntimeRoot "node"
|
|
9
|
+
$NodeExe = Join-Path $NodeDir "node.exe"
|
|
10
|
+
|
|
11
|
+
$NodeVer = "v22.14.0"
|
|
12
|
+
|
|
13
|
+
# 1. Probe if host already satisfies Node >= 22.13
|
|
14
|
+
if (Get-Command node -ErrorAction SilentlyContinue) {
|
|
15
|
+
try {
|
|
16
|
+
$check = node -e "var v=process.versions.node.split('.');process.exit((v[0]>22||(v[0]==22&&v[1]>=13))?0:1)"
|
|
17
|
+
if ($LASTEXITCODE -eq 0) {
|
|
18
|
+
Write-Host "[bioresearcher-onboard] Found host $(node -v) on PATH"
|
|
19
|
+
& node "$ScriptDir\onboard.mjs" @args
|
|
20
|
+
exit $LASTEXITCODE
|
|
21
|
+
}
|
|
22
|
+
} catch {}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
# If already vendored in working directory, reuse directly
|
|
26
|
+
if (Test-Path $NodeExe) {
|
|
27
|
+
$env:PATH = "$NodeDir;$env:PATH"
|
|
28
|
+
& "$NodeExe" "$ScriptDir\onboard.mjs" @args
|
|
29
|
+
exit $LASTEXITCODE
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
Write-Host "[bioresearcher-onboard] Host Node >= 22.13 not found. Bootstrapping portable Node.js $NodeVer into .bioresearcher-runtime\..."
|
|
33
|
+
|
|
34
|
+
# 2. Architecture Detection
|
|
35
|
+
$Arch = if ([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture -eq [System.Runtime.InteropServices.Architecture]::Arm64) {
|
|
36
|
+
"arm64"
|
|
37
|
+
} else {
|
|
38
|
+
"x64"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# 3. Mirror Selection Probe (2-second integer timeout)
|
|
42
|
+
$MirrorBase = "https://nodejs.org/dist/$NodeVer"
|
|
43
|
+
$NpmRegistry = "https://registry.npmjs.org"
|
|
44
|
+
try {
|
|
45
|
+
$req = [System.Net.WebRequest]::Create("https://nodejs.org/dist/")
|
|
46
|
+
$req.Timeout = 2000
|
|
47
|
+
$res = $req.GetResponse()
|
|
48
|
+
$res.Close()
|
|
49
|
+
} catch {
|
|
50
|
+
Write-Host "[bioresearcher-onboard] nodejs.org unreachable; using npmmirror.com fast mirror"
|
|
51
|
+
$MirrorBase = "https://npmmirror.com/mirrors/node/$NodeVer"
|
|
52
|
+
$NpmRegistry = "https://registry.npmmirror.com"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
$File = "node-$NodeVer-win-$Arch.zip"
|
|
56
|
+
$DownloadUrl = "$MirrorBase/$File"
|
|
57
|
+
|
|
58
|
+
$Checksums = @{
|
|
59
|
+
"x64" = "55b639295920b219bb2acbcfa00f90393a2789095b7323f79475c9f34795f217"
|
|
60
|
+
"arm64" = "2d71f5f9b2fffa33baa108c07d74b0d24e0c3dd8f441d567772ae0e3dd4b1a22"
|
|
61
|
+
}
|
|
62
|
+
$ExpectedSha = $Checksums[$Arch]
|
|
63
|
+
|
|
64
|
+
New-Item -ItemType Directory -Force -Path $RuntimeRoot | Out-Null
|
|
65
|
+
$TmpArchive = Join-Path $RuntimeRoot "node.zip"
|
|
66
|
+
|
|
67
|
+
Write-Host "[bioresearcher-onboard] Downloading $File..."
|
|
68
|
+
Invoke-WebRequest -Uri $DownloadUrl -OutFile $TmpArchive -UseBasicParsing
|
|
69
|
+
|
|
70
|
+
# 4. Checksum verification
|
|
71
|
+
$ActualSha = (Get-FileHash -Path $TmpArchive -Algorithm SHA256).Hash.ToLower()
|
|
72
|
+
if ($ActualSha -ne $ExpectedSha) {
|
|
73
|
+
Remove-Item -Force $TmpArchive -ErrorAction SilentlyContinue
|
|
74
|
+
Write-Error "SHA256 checksum verification failed for $File.`nExpected: $ExpectedSha`nActual: $ActualSha"
|
|
75
|
+
exit 1
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# 5. Extract and flatten layout
|
|
79
|
+
$TmpExtract = Join-Path $RuntimeRoot "node-extract-tmp"
|
|
80
|
+
if (Test-Path $TmpExtract) { Remove-Item -Recurse -Force $TmpExtract }
|
|
81
|
+
New-Item -ItemType Directory -Force -Path $TmpExtract | Out-Null
|
|
82
|
+
Expand-Archive -Path $TmpArchive -DestinationPath $TmpExtract -Force
|
|
83
|
+
Remove-Item -Force $TmpArchive
|
|
84
|
+
|
|
85
|
+
New-Item -ItemType Directory -Force -Path $NodeDir | Out-Null
|
|
86
|
+
$ExtractedFolder = Get-ChildItem -Path $TmpExtract | Select-Object -First 1
|
|
87
|
+
Get-ChildItem -Path $ExtractedFolder.FullName | Move-Item -Destination $NodeDir -Force
|
|
88
|
+
Remove-Item -Recurse -Force $TmpExtract
|
|
89
|
+
|
|
90
|
+
Write-Host "[bioresearcher-onboard] Portable Node.js ready: $(& $NodeExe -v)"
|
|
91
|
+
|
|
92
|
+
# 6. Hand off to Stage 1
|
|
93
|
+
$env:PATH = "$NodeDir;$env:PATH"
|
|
94
|
+
$env:NPM_CONFIG_REGISTRY = $NpmRegistry
|
|
95
|
+
& "$NodeExe" "$ScriptDir\onboard.mjs" @args
|
|
96
|
+
exit $LASTEXITCODE
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Stage 0 Zero-Dependency Bootstrap for bioresearcher-onboard.
|
|
3
|
+
# Checks for existing Node >= 22.13; if missing, downloads pinned portable
|
|
4
|
+
# Node.js LTS into .bioresearcher-runtime/node, verifies SHA256, and hands off
|
|
5
|
+
# execution to onboard.mjs.
|
|
6
|
+
set -euo pipefail
|
|
7
|
+
|
|
8
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
9
|
+
RUNTIME_ROOT="${BIORESEARCHER_RUNTIME_DIR:-$PWD/.bioresearcher-runtime}"
|
|
10
|
+
NODE_DIR="$RUNTIME_ROOT/node"
|
|
11
|
+
NODE_BIN="$NODE_DIR/bin/node"
|
|
12
|
+
|
|
13
|
+
NODE_REQ_MAJ=22
|
|
14
|
+
NODE_REQ_MIN=13
|
|
15
|
+
NODE_VER="v22.14.0"
|
|
16
|
+
|
|
17
|
+
# 1. Probe if host already satisfies Node >= 22.13
|
|
18
|
+
if command -v node >/dev/null 2>&1; then
|
|
19
|
+
if node -e "var v=process.versions.node.split('.');process.exit((v[0]>$NODE_REQ_MAJ||(v[0]==$NODE_REQ_MAJ&&v[1]>=$NODE_REQ_MIN))?0:1)" 2>/dev/null; then
|
|
20
|
+
echo "[bioresearcher-onboard] Found host $(node -v) at $(command -v node)"
|
|
21
|
+
exec node "$SCRIPT_DIR/onboard.mjs" "$@"
|
|
22
|
+
fi
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# If already vendored in working directory, reuse directly
|
|
26
|
+
if [ -x "$NODE_BIN" ]; then
|
|
27
|
+
export PATH="$NODE_DIR/bin:$PATH"
|
|
28
|
+
exec "$NODE_BIN" "$SCRIPT_DIR/onboard.mjs" "$@"
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
echo "[bioresearcher-onboard] Host Node >= 22.13 not found. Bootstrapping portable Node.js $NODE_VER into .bioresearcher-runtime/..."
|
|
32
|
+
|
|
33
|
+
# 2. OS and Architecture Detection
|
|
34
|
+
OS_RAW="$(uname -s)"
|
|
35
|
+
case "$OS_RAW" in
|
|
36
|
+
Linux*) OS="linux" ;;
|
|
37
|
+
Darwin*) OS="darwin" ;;
|
|
38
|
+
*) echo "Error: Unsupported operating system $OS_RAW. Windows users should run bootstrap.ps1." >&2; exit 1 ;;
|
|
39
|
+
esac
|
|
40
|
+
|
|
41
|
+
# Linux C library gate
|
|
42
|
+
if [ "$OS" = "linux" ]; then
|
|
43
|
+
if ldd /bin/ls 2>&1 | grep -qi "musl"; then
|
|
44
|
+
echo "Error: Alpine/musl Linux detected. Official Node prebuilts require glibc." >&2
|
|
45
|
+
echo "Please install Node >= 22.13 via your system package manager (e.g. apk add nodejs)." >&2
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
ARCH_RAW="$(uname -m)"
|
|
51
|
+
case "$ARCH_RAW" in
|
|
52
|
+
x86_64|amd64) ARCH="x64" ;;
|
|
53
|
+
arm64|aarch64) ARCH="arm64" ;;
|
|
54
|
+
*) echo "Error: Unsupported CPU architecture $ARCH_RAW." >&2; exit 1 ;;
|
|
55
|
+
esac
|
|
56
|
+
|
|
57
|
+
# macOS Rosetta detection: probe true hardware arch
|
|
58
|
+
if [ "$OS" = "darwin" ]; then
|
|
59
|
+
if [ "$(sysctl -in sysctl.proc_translated 2>/dev/null || echo 0)" = "1" ]; then
|
|
60
|
+
ARCH="arm64"
|
|
61
|
+
fi
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# 3. Mirror Selection Probe (1.2s timeout)
|
|
65
|
+
if curl -s -I --connect-timeout 1.0 --max-time 1.2 "https://nodejs.org/dist/" >/dev/null 2>&1; then
|
|
66
|
+
MIRROR_BASE="https://nodejs.org/dist/${NODE_VER}"
|
|
67
|
+
NPM_REGISTRY="https://registry.npmjs.org"
|
|
68
|
+
else
|
|
69
|
+
echo "[bioresearcher-onboard] nodejs.org unreachable or timed out; using npmmirror.com fast mirror"
|
|
70
|
+
MIRROR_BASE="https://npmmirror.com/mirrors/node/${NODE_VER}"
|
|
71
|
+
NPM_REGISTRY="https://registry.npmmirror.com"
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
FILE="node-${NODE_VER}-${OS}-${ARCH}.tar.gz"
|
|
75
|
+
DOWNLOAD_URL="${MIRROR_BASE}/${FILE}"
|
|
76
|
+
|
|
77
|
+
# Pinned SHA256 checksums from official Node.js SHASUMS256.txt
|
|
78
|
+
case "${OS}-${ARCH}" in
|
|
79
|
+
linux-x64) EXPECTED_SHA="9d942932535988091034dc94cc5f42b6dc8784d6366df3a36c4c9ccb3996f0c2" ;;
|
|
80
|
+
linux-arm64) EXPECTED_SHA="8cf30ff7250f9463b53c18f89c6c606dfda70378215b2c905d0a9a8b08bd45e0" ;;
|
|
81
|
+
darwin-x64) EXPECTED_SHA="6698587713ab565a94a360e091df9f6d91c8fadda6d00f0cf6526e9b40bed250" ;;
|
|
82
|
+
darwin-arm64) EXPECTED_SHA="e9404633bc02a5162c5c573b1e2490f5fb44648345d64a958b17e325729a5e42" ;;
|
|
83
|
+
*) echo "Error: Missing checksum for target ${OS}-${ARCH}." >&2; exit 1 ;;
|
|
84
|
+
esac
|
|
85
|
+
|
|
86
|
+
mkdir -p "$RUNTIME_ROOT"
|
|
87
|
+
TMP_ARCHIVE="$RUNTIME_ROOT/node.tar.gz"
|
|
88
|
+
|
|
89
|
+
echo "[bioresearcher-onboard] Downloading $FILE..."
|
|
90
|
+
curl -f -s -L --retry 2 -o "$TMP_ARCHIVE" "$DOWNLOAD_URL"
|
|
91
|
+
|
|
92
|
+
# 4. Checksum verification
|
|
93
|
+
if command -v sha256sum >/dev/null 2>&1; then
|
|
94
|
+
ACTUAL_SHA="$(sha256sum "$TMP_ARCHIVE" | awk '{print $1}')"
|
|
95
|
+
elif command -v shasum >/dev/null 2>&1; then
|
|
96
|
+
ACTUAL_SHA="$(shasum -a 256 "$TMP_ARCHIVE" | awk '{print $1}')"
|
|
97
|
+
else
|
|
98
|
+
ACTUAL_SHA=""
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
if [ -n "$ACTUAL_SHA" ] && [ "$ACTUAL_SHA" != "$EXPECTED_SHA" ]; then
|
|
102
|
+
echo "Error: SHA256 checksum verification failed for $FILE." >&2
|
|
103
|
+
echo "Expected: $EXPECTED_SHA" >&2
|
|
104
|
+
echo "Actual: $ACTUAL_SHA" >&2
|
|
105
|
+
rm -f "$TMP_ARCHIVE"
|
|
106
|
+
exit 1
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
# 5. Extract and prune
|
|
110
|
+
mkdir -p "$NODE_DIR"
|
|
111
|
+
tar -xzf "$TMP_ARCHIVE" -C "$NODE_DIR" --strip-components=1
|
|
112
|
+
rm -f "$TMP_ARCHIVE"
|
|
113
|
+
|
|
114
|
+
# Remove non-runtime artifacts (saves ~49 MB)
|
|
115
|
+
rm -rf "$NODE_DIR/include" "$NODE_DIR/share" "$NODE_DIR"/*.md "$NODE_DIR"/LICENSE
|
|
116
|
+
|
|
117
|
+
# macOS Gatekeeper quarantine removal
|
|
118
|
+
if [ "$OS" = "darwin" ]; then
|
|
119
|
+
xattr -dr com.apple.quarantine "$NODE_DIR" 2>/dev/null || true
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
echo "[bioresearcher-onboard] Portable Node.js ready: $("$NODE_BIN" -v)"
|
|
123
|
+
|
|
124
|
+
# 6. Hand off to Stage 1
|
|
125
|
+
export PATH="$NODE_DIR/bin:$PATH"
|
|
126
|
+
export NPM_CONFIG_REGISTRY="$NPM_REGISTRY"
|
|
127
|
+
exec "$NODE_BIN" "$SCRIPT_DIR/onboard.mjs" "$@"
|