@hiai-gg/hiai-opencode 0.1.3 → 0.1.5
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/.env.example +14 -18
- package/AGENTS.md +77 -23
- package/ARCHITECTURE.md +15 -17
- package/LICENSE.md +1 -0
- package/README.md +189 -94
- package/assets/cli/hiai-opencode.mjs +276 -0
- package/assets/mcp/playwright.mjs +7 -0
- package/config/hiai-opencode.schema.json +85 -50
- package/dist/config/defaults.d.ts +1 -3
- package/dist/config/index.d.ts +0 -1
- package/dist/config/platform-schema.d.ts +343 -4
- package/dist/config/schema/agent-overrides.d.ts +256 -0
- package/dist/config/schema/categories.d.ts +1 -1
- package/dist/config/schema/commands.d.ts +1 -0
- package/dist/config/schema/index.d.ts +2 -0
- package/dist/config/schema/oh-my-opencode-config.d.ts +267 -0
- package/dist/config/schema/skill-discovery.d.ts +11 -0
- package/dist/config/types.d.ts +33 -3
- package/dist/create-tools.d.ts +2 -0
- package/dist/features/builtin-commands/templates/mcp-status.d.ts +1 -0
- package/dist/features/builtin-commands/types.d.ts +1 -1
- package/dist/features/opencode-skill-loader/loader.d.ts +2 -0
- package/dist/index.js +744 -358
- package/dist/internals/plugins/websearch-cited/index.d.ts +7 -1
- package/dist/mcp/types.d.ts +1 -1
- package/dist/plugin/skill-discovery-config.d.ts +4 -0
- package/dist/plugin/tool-registry.d.ts +2 -0
- package/dist/shared/startup-diagnostics.d.ts +6 -0
- package/dist/tools/skill-mcp/tools.d.ts +2 -0
- package/hiai-opencode.json +55 -33
- package/package.json +4 -1
- package/src/agents/AGENTS.md +3 -4
- package/src/config/defaults.ts +186 -77
- package/src/config/index.ts +0 -1
- package/src/config/loader.test.ts +16 -1
- package/src/config/loader.ts +4 -2
- package/src/config/platform-schema.ts +53 -4
- package/src/config/schema/agent-overrides.ts +2 -0
- package/src/config/schema/commands.ts +1 -0
- package/src/config/schema/fast-apply.ts +4 -4
- package/src/config/schema/index.ts +2 -0
- package/src/config/schema/oh-my-opencode-config.ts +3 -0
- package/src/config/schema/skill-discovery.ts +25 -0
- package/src/config/types.ts +49 -2
- package/src/create-tools.ts +4 -1
- package/src/features/builtin-commands/commands.ts +7 -0
- package/src/features/builtin-commands/templates/mcp-status.ts +36 -0
- package/src/features/builtin-commands/types.ts +1 -1
- package/src/features/builtin-skills/skills/playwright.ts +24 -2
- package/src/features/opencode-skill-loader/loader.ts +11 -0
- package/src/index.ts +53 -14
- package/src/internals/plugins/websearch-cited/index.ts +10 -5
- package/src/lsp/index.ts +1 -0
- package/src/mcp/registry.ts +6 -1
- package/src/plugin/hooks/create-tool-guard-hooks.ts +1 -1
- package/src/plugin/skill-context.ts +31 -13
- package/src/plugin/skill-discovery-config.ts +32 -0
- package/src/plugin/tool-registry.ts +4 -0
- package/src/plugin-handlers/agent-config-handler.ts +20 -13
- package/src/plugin-handlers/command-config-handler.ts +22 -12
- package/src/shared/migration/agent-names.ts +5 -5
- package/src/shared/startup-diagnostics.ts +77 -0
- package/src/tools/skill-mcp/tools.ts +45 -7
- package/src/config/models.ts +0 -32
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ Minimum:
|
|
|
60
60
|
|
|
61
61
|
Usually required:
|
|
62
62
|
|
|
63
|
-
-
|
|
63
|
+
- at least one model provider connected in OpenCode for the model IDs you configure
|
|
64
64
|
|
|
65
65
|
Optional, depending on which services you want:
|
|
66
66
|
|
|
@@ -73,19 +73,21 @@ Optional, depending on which services you want:
|
|
|
73
73
|
|
|
74
74
|
## Install
|
|
75
75
|
|
|
76
|
-
|
|
76
|
+
### 1. Register the OpenCode plugin
|
|
77
77
|
|
|
78
78
|
```bash
|
|
79
79
|
opencode plugin @hiai-gg/hiai-opencode@latest --global
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
Optional
|
|
82
|
+
Optional Dynamic Context Pruning plugin:
|
|
83
83
|
|
|
84
84
|
```bash
|
|
85
85
|
opencode plugin @tarquinen/opencode-dcp@latest --global
|
|
86
86
|
```
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
Do not put MCP server packages such as `firecrawl-mcp`, `@playwright/mcp`, or `@modelcontextprotocol/server-sequential-thinking` into the OpenCode `plugin` array. They are MCP servers, not OpenCode plugins. `hiai-opencode` only provides the OpenCode-side launch wiring for them through its `mcp` config and helper launchers.
|
|
89
|
+
|
|
90
|
+
Manual OpenCode config equivalent:
|
|
89
91
|
|
|
90
92
|
```json
|
|
91
93
|
{
|
|
@@ -94,107 +96,99 @@ Manual config alternative:
|
|
|
94
96
|
}
|
|
95
97
|
```
|
|
96
98
|
|
|
97
|
-
|
|
99
|
+
The packaged minimal OpenCode example lives in [config/opencode.json](config/opencode.json).
|
|
98
100
|
|
|
99
|
-
|
|
100
|
-
opencode
|
|
101
|
-
```
|
|
101
|
+
### 2. Create project config
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
Create a project-level config file at `hiai-opencode.json` in the project root or at `.opencode/hiai-opencode.json`.
|
|
104
104
|
|
|
105
|
-
|
|
106
|
-
npm install @hiai-gg/hiai-opencode
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
For local development:
|
|
105
|
+
Bash:
|
|
110
106
|
|
|
111
107
|
```bash
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
bun install
|
|
115
|
-
bun run build
|
|
108
|
+
mkdir -p .opencode
|
|
109
|
+
cp hiai-opencode.json .opencode/hiai-opencode.json
|
|
116
110
|
```
|
|
117
111
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
Use the OpenCode plugin CLI:
|
|
112
|
+
PowerShell:
|
|
121
113
|
|
|
122
|
-
```
|
|
123
|
-
|
|
114
|
+
```powershell
|
|
115
|
+
New-Item -ItemType Directory -Force .opencode
|
|
116
|
+
Copy-Item .\hiai-opencode.json .\.opencode\hiai-opencode.json
|
|
124
117
|
```
|
|
125
118
|
|
|
126
|
-
If you
|
|
127
|
-
|
|
128
|
-
```bash
|
|
129
|
-
opencode plugin @tarquinen/opencode-dcp@latest --global
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
If you prefer manual config, add the plugin package to your OpenCode config. OpenCode installs npm plugins automatically at startup.
|
|
119
|
+
If you installed only from npm/OpenCode and do not have this repository checked out, create `.opencode/hiai-opencode.json` with the shape below and adjust it later.
|
|
133
120
|
|
|
134
121
|
```json
|
|
135
122
|
{
|
|
136
|
-
"
|
|
137
|
-
|
|
123
|
+
"models": {
|
|
124
|
+
"bob": { "model": "openrouter/anthropic/claude-3.5-opus", "recommended": "xhigh" },
|
|
125
|
+
"coder": { "model": "openrouter/anthropic/claude-3.5-sonnet", "recommended": "high" },
|
|
126
|
+
"strategist": { "model": "openrouter/z-ai/glm-5.1", "recommended": "high" },
|
|
127
|
+
"guard": { "model": "openrouter/openai/gpt-4o", "recommended": "middle" },
|
|
128
|
+
"critic": { "model": "openrouter/qwen/qwen2.5-72b-instruct", "recommended": "high" },
|
|
129
|
+
"designer": { "model": "openrouter/google/gemini-3.1-pro", "recommended": "design" },
|
|
130
|
+
"researcher": { "model": "openrouter/google/gemini-2.0-flash", "recommended": "fast" },
|
|
131
|
+
"manager": { "model": "openrouter/google/gemini-2.0-flash", "recommended": "fast" },
|
|
132
|
+
"brainstormer": { "model": "openrouter/kimi/kimi-latest", "recommended": "writing" },
|
|
133
|
+
"vision": { "model": "openrouter/google/gemini-3.1-pro", "recommended": "vision" }
|
|
134
|
+
},
|
|
135
|
+
"mcp": {
|
|
136
|
+
"playwright": { "enabled": true },
|
|
137
|
+
"sequential-thinking": { "enabled": true },
|
|
138
|
+
"firecrawl": { "enabled": true },
|
|
139
|
+
"mempalace": { "enabled": true },
|
|
140
|
+
"rag": { "enabled": false },
|
|
141
|
+
"stitch": { "enabled": false },
|
|
142
|
+
"context7": { "enabled": true }
|
|
143
|
+
}
|
|
138
144
|
}
|
|
139
145
|
```
|
|
140
146
|
|
|
141
|
-
|
|
147
|
+
By default, skill discovery is deterministic: `hiai-opencode` skills plus project-local `.opencode/skills` only. Global Claude/OpenCode/Agents skill folders are opt-in.
|
|
142
148
|
|
|
143
|
-
|
|
149
|
+
### 3. Connect models and add service keys
|
|
144
150
|
|
|
145
|
-
|
|
151
|
+
Model provider credentials belong to OpenCode Connect, not to `hiai-opencode`.
|
|
152
|
+
This plugin only reads the 10 model IDs in `models`. Internal routing derives hidden agents and task categories from those 10 choices.
|
|
146
153
|
|
|
147
|
-
|
|
154
|
+
Use OpenCode Connect to authorize the providers behind your configured model IDs. Then add only the service keys for MCP or search integrations you actually use:
|
|
148
155
|
|
|
149
156
|
```bash
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
bun run build
|
|
157
|
+
export FIRECRAWL_API_KEY=...
|
|
158
|
+
export STITCH_AI_API_KEY=...
|
|
159
|
+
export CONTEXT7_API_KEY=...
|
|
154
160
|
```
|
|
155
161
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
```bash
|
|
159
|
-
opencode plugin @hiai-gg/hiai-opencode@latest --global
|
|
160
|
-
```
|
|
162
|
+
See [Environment Variables And Keys](#environment-variables-and-keys) for the full list.
|
|
161
163
|
|
|
162
|
-
|
|
164
|
+
### 4. Start and verify
|
|
163
165
|
|
|
164
166
|
```bash
|
|
165
|
-
opencode
|
|
167
|
+
opencode
|
|
168
|
+
hiai-opencode mcp-status
|
|
169
|
+
opencode debug config
|
|
170
|
+
opencode mcp list --print-logs --log-level INFO
|
|
166
171
|
```
|
|
167
172
|
|
|
168
|
-
|
|
173
|
+
`opencode mcp list` may not show plugin-provided MCP servers in every OpenCode version. If that happens, use `opencode debug config` and startup logs as the source of truth.
|
|
169
174
|
|
|
170
|
-
|
|
171
|
-
{
|
|
172
|
-
"$schema": "https://opencode.ai/config.json",
|
|
173
|
-
"plugin": ["@hiai-gg/hiai-opencode"]
|
|
174
|
-
}
|
|
175
|
-
```
|
|
175
|
+
`hiai-opencode mcp-status` is the fastest visibility check. It does not change OpenCode config; it reports config location, enabled MCP services, missing keys, and basic local runtime availability.
|
|
176
176
|
|
|
177
|
-
|
|
177
|
+
## Development Install
|
|
178
178
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
"sequential-thinking": { "enabled": true },
|
|
184
|
-
"firecrawl": { "enabled": true },
|
|
185
|
-
"mempalace": { "enabled": true },
|
|
186
|
-
"rag": { "enabled": false },
|
|
187
|
-
"stitch": { "enabled": false },
|
|
188
|
-
"context7": { "enabled": true }
|
|
189
|
-
}
|
|
190
|
-
}
|
|
179
|
+
Direct npm install is only needed for development or inspection:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
npm install @hiai-gg/hiai-opencode
|
|
191
183
|
```
|
|
192
184
|
|
|
193
|
-
|
|
185
|
+
Local development:
|
|
194
186
|
|
|
195
187
|
```bash
|
|
196
|
-
|
|
197
|
-
|
|
188
|
+
git clone https://github.com/HiAi-gg/hiai-opencode.git
|
|
189
|
+
cd hiai-opencode
|
|
190
|
+
bun install
|
|
191
|
+
bun run build
|
|
198
192
|
```
|
|
199
193
|
|
|
200
194
|
## Post-Install Bootstrap Prompt
|
|
@@ -210,6 +204,8 @@ Check that @hiai-gg/hiai-opencode is registered. If Dynamic Context Pruning is r
|
|
|
210
204
|
|
|
211
205
|
Find or create hiai-opencode.json in the project root or .opencode/. Use its mcp object as the single switchboard for enabling or disabling MCP services.
|
|
212
206
|
|
|
207
|
+
Keep skill discovery deterministic unless I explicitly ask for external skills. Leave global_opencode, project_claude, global_claude, project_agents, and global_agents disabled by default.
|
|
208
|
+
|
|
213
209
|
Enable only services that can run on this machine:
|
|
214
210
|
- playwright: requires node/npx; optionally set HIAI_PLAYWRIGHT_INSTALL_BROWSERS=1 before first run if browser binaries are needed.
|
|
215
211
|
- sequential-thinking: requires node/npx.
|
|
@@ -232,21 +228,17 @@ If a dependency is missing, install only user-level or project-local dependencie
|
|
|
232
228
|
|
|
233
229
|
### Models
|
|
234
230
|
|
|
235
|
-
|
|
231
|
+
Canonical user-facing config for 10 primary agent models, MCP/LSP switches, service auth placeholders, and skill discovery:
|
|
236
232
|
|
|
237
|
-
- [
|
|
233
|
+
- [hiai-opencode.json](hiai-opencode.json)
|
|
238
234
|
|
|
239
|
-
Runtime
|
|
235
|
+
Runtime loader for the bundled canonical config:
|
|
240
236
|
|
|
241
237
|
- [src/config/defaults.ts](src/config/defaults.ts)
|
|
242
238
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
- [hiai-opencode.json](hiai-opencode.json)
|
|
246
|
-
|
|
247
|
-
If you want to change which model a specific agent uses by default, edit `src/config/defaults.ts`.
|
|
239
|
+
If you want to change model selection, edit the 10 entries in `models`. Do not add category-specific model choices unless you are intentionally developing the plugin internals.
|
|
248
240
|
|
|
249
|
-
|
|
241
|
+
Use fully qualified model IDs. Do not introduce local aliases like `hiai-fast`, `sonnet`, `fast`, or `high`.
|
|
250
242
|
|
|
251
243
|
### Prompting
|
|
252
244
|
|
|
@@ -281,6 +273,24 @@ Skill materialization logic:
|
|
|
281
273
|
|
|
282
274
|
- [src/features/builtin-skills/materialize.ts](src/features/builtin-skills/materialize.ts)
|
|
283
275
|
|
|
276
|
+
Skill discovery defaults:
|
|
277
|
+
|
|
278
|
+
```json
|
|
279
|
+
{
|
|
280
|
+
"skill_discovery": {
|
|
281
|
+
"config_sources": true,
|
|
282
|
+
"project_opencode": true,
|
|
283
|
+
"global_opencode": false,
|
|
284
|
+
"project_claude": false,
|
|
285
|
+
"global_claude": false,
|
|
286
|
+
"project_agents": false,
|
|
287
|
+
"global_agents": false
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
This keeps clean installs reproducible and avoids accidentally mixing Codex, Claude, Antigravity, and global OpenCode skill collections. To opt into external skill folders, enable the specific source you want instead of turning everything on.
|
|
293
|
+
|
|
284
294
|
### MCP
|
|
285
295
|
|
|
286
296
|
Default MCP registry:
|
|
@@ -304,21 +314,23 @@ LSP defaults are defined in:
|
|
|
304
314
|
|
|
305
315
|
## Environment Variables And Keys
|
|
306
316
|
|
|
307
|
-
|
|
317
|
+
Model provider keys are handled by OpenCode Connect. Do not add `OPENROUTER_API_KEY`, `OPENAI_API_KEY`, or `ANTHROPIC_API_KEY` to `hiai-opencode` config for normal model usage.
|
|
318
|
+
|
|
319
|
+
Important service variables:
|
|
308
320
|
|
|
309
|
-
- `OPENROUTER_API_KEY`
|
|
310
|
-
- `OPENAI_API_KEY`
|
|
311
|
-
- `ANTHROPIC_API_KEY`
|
|
312
|
-
- `DEEPSEEK_API_KEY`
|
|
313
|
-
- `GLM_API_KEY`
|
|
314
|
-
- `MINIMAX_API_KEY`
|
|
315
|
-
- `QWEN_API_KEY`
|
|
316
321
|
- `STITCH_AI_API_KEY`
|
|
317
322
|
- `FIRECRAWL_API_KEY`
|
|
318
323
|
- `CONTEXT7_API_KEY`
|
|
324
|
+
- `GOOGLE_SEARCH_API_KEY`
|
|
319
325
|
- `OLLAMA_BASE_URL`
|
|
320
326
|
- `OLLAMA_MODEL`
|
|
321
327
|
- `MEMPALACE_PYTHON`
|
|
328
|
+
- `MEMPALACE_PALACE_PATH`
|
|
329
|
+
- `OPENCODE_RAG_URL`
|
|
330
|
+
- `HIAI_PLAYWRIGHT_INSTALL_BROWSERS`
|
|
331
|
+
- `HIAI_MCP_AUTO_INSTALL`
|
|
332
|
+
|
|
333
|
+
Optional headless or non-Connect fallback variables are documented in [.env.example](.env.example), but they are not required for normal OpenCode model auth.
|
|
322
334
|
|
|
323
335
|
Use [.env.example](.env.example) as the reference template. Create a local `.env` in your OpenCode environment or export these variables in your shell before startup.
|
|
324
336
|
|
|
@@ -350,19 +362,40 @@ The source of truth for default MCP wiring is `src/mcp/registry.ts`. Change that
|
|
|
350
362
|
- `sequential-thinking`: launches `@modelcontextprotocol/server-sequential-thinking` through the helper npm runner.
|
|
351
363
|
- `firecrawl`: launches `firecrawl-mcp` through the helper npm runner and requires `FIRECRAWL_API_KEY`.
|
|
352
364
|
|
|
353
|
-
###
|
|
365
|
+
### Playwright On Minimal Linux Hosts
|
|
354
366
|
|
|
355
|
-
- `
|
|
356
|
-
- `rag`: requires your own running endpoint
|
|
367
|
+
`hiai-opencode mcp-status` can confirm that the Playwright MCP launcher is available, but it cannot guarantee that Chromium can start on a minimal Linux image.
|
|
357
368
|
|
|
358
|
-
|
|
369
|
+
Playwright has two dependency layers:
|
|
359
370
|
|
|
360
|
-
|
|
371
|
+
- Browser binary: install with `HIAI_PLAYWRIGHT_INSTALL_BROWSERS=1` before OpenCode starts, or run `npx playwright install chromium`.
|
|
372
|
+
- System libraries: if Chromium errors with missing packages like `libnspr4`, `libnss3`, `libatk-bridge`, or `libgtk-3`, install them with admin rights, usually `sudo npx playwright install-deps chromium`.
|
|
361
373
|
|
|
362
|
-
|
|
363
|
-
|
|
374
|
+
If sudo is not available:
|
|
375
|
+
|
|
376
|
+
- Use an already installed system browser by editing the Playwright command in `.opencode/hiai-opencode.json`, for example:
|
|
377
|
+
|
|
378
|
+
```json
|
|
379
|
+
{
|
|
380
|
+
"mcp": {
|
|
381
|
+
"playwright": {
|
|
382
|
+
"enabled": true,
|
|
383
|
+
"command": ["node", "{pluginRoot}/assets/mcp/playwright.mjs", "--browser", "chrome"],
|
|
384
|
+
"timeout": 600000
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
364
388
|
```
|
|
365
389
|
|
|
390
|
+
- Try `--browser msedge` if Edge is installed.
|
|
391
|
+
- Use a remote/CDP browser or the `agent-browser`/`playwright-cli` skill path if those tools are installed.
|
|
392
|
+
- Use `curl` only as a degraded HTTP check. It does not replace browser interaction, screenshots, auth flows, or client-side app verification.
|
|
393
|
+
|
|
394
|
+
### Needs upstream runtime or extra setup
|
|
395
|
+
|
|
396
|
+
- `mempalace`: prefers `uv`; otherwise uses Python. If `HIAI_MCP_AUTO_INSTALL` is not `0`, `false`, or `no`, the launcher can run `python -m pip install --user mempalace` on first start.
|
|
397
|
+
- `rag`: requires your own running endpoint
|
|
398
|
+
|
|
366
399
|
### Important Windows note
|
|
367
400
|
|
|
368
401
|
On some Windows/OpenCode environments, local MCP process spawning can fail with `EPERM` for `cmd` or `node`. If you see that:
|
|
@@ -372,6 +405,68 @@ On some Windows/OpenCode environments, local MCP process spawning can fail with
|
|
|
372
405
|
|
|
373
406
|
This most often affects `sequential-thinking` and `mempalace`, and sometimes local `npx`-backed tools.
|
|
374
407
|
|
|
408
|
+
## Diagnostics
|
|
409
|
+
|
|
410
|
+
The plugin now emits startup warnings for common misconfiguration, including:
|
|
411
|
+
|
|
412
|
+
- `.opencode/opencode.json` containing `plugin: ["list"]`
|
|
413
|
+
- enabled MCP integrations with missing required env vars such as `FIRECRAWL_API_KEY` or `STITCH_AI_API_KEY`
|
|
414
|
+
|
|
415
|
+
Available CLI:
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
hiai-opencode mcp-status
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
Inside OpenCode, use the slash command:
|
|
422
|
+
|
|
423
|
+
```text
|
|
424
|
+
/mcp-status
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Example output:
|
|
428
|
+
|
|
429
|
+
```text
|
|
430
|
+
MCP Servers:
|
|
431
|
+
✅ playwright - backend ok
|
|
432
|
+
⚠️ rag - enabled, http://localhost:9002/tools/search not reachable
|
|
433
|
+
✅ firecrawl - backend ok
|
|
434
|
+
❌ mempalace - python not found
|
|
435
|
+
⚠️ stitch - enabled, API key missing (STITCH_AI_API_KEY)
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
Planned follow-up commands:
|
|
439
|
+
|
|
440
|
+
- `hiai-opencode doctor`: report config location, MCP status, missing keys, and local dependency checks.
|
|
441
|
+
- `hiai-opencode export-mcp`: generate a standard `.mcp.json` for hosts that do not expose plugin-provided MCP servers through `opencode mcp list`.
|
|
442
|
+
|
|
443
|
+
Until those commands ship, use:
|
|
444
|
+
|
|
445
|
+
```bash
|
|
446
|
+
opencode debug config
|
|
447
|
+
opencode mcp list --print-logs --log-level INFO
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
## Core Components And Upstream Projects
|
|
451
|
+
|
|
452
|
+
`hiai-opencode` wires these projects and ideas into an OpenCode-friendly setup. Upstream projects remain independent; this table is attribution and orientation, not an ownership claim.
|
|
453
|
+
|
|
454
|
+
| Component | Upstream | Notes |
|
|
455
|
+
|---|---|---|
|
|
456
|
+
| OpenCode host/runtime | [anomalyco/opencode](https://github.com/anomalyco/opencode) | plugin host and runtime target |
|
|
457
|
+
| Core orchestration influences | [code-yeongyu/oh-my-openagent](https://github.com/code-yeongyu/oh-my-openagent) | architectural influence |
|
|
458
|
+
| Planning / workflow influences | [obra/superpowers](https://github.com/obra/superpowers) | planning, review, and debugging ideas |
|
|
459
|
+
| Specialist / platform influences | [vtemian/micode](https://github.com/vtemian/micode) | platform-style specialist behavior |
|
|
460
|
+
| Agent skill ecosystem | [addyosmani/agent-skills](https://github.com/addyosmani/agent-skills) | tactical workflow skill ideas |
|
|
461
|
+
| Optional external plugin | [Opencode-DCP/opencode-dynamic-context-pruning](https://github.com/Opencode-DCP/opencode-dynamic-context-pruning) | installed separately |
|
|
462
|
+
| MemPalace | [MemPalace/mempalace](https://github.com/MemPalace/mempalace) | external MCP/runtime |
|
|
463
|
+
| Playwright MCP | [microsoft/playwright-mcp](https://github.com/microsoft/playwright-mcp) | external MCP |
|
|
464
|
+
| Sequential Thinking | [modelcontextprotocol/servers](https://github.com/modelcontextprotocol/servers) | external MCP |
|
|
465
|
+
| Firecrawl MCP | [firecrawl-ai/firecrawl-mcp-server](https://github.com/firecrawl-ai/firecrawl-mcp-server) | external MCP |
|
|
466
|
+
| Context7 MCP | [upstash/context7-mcp](https://github.com/upstash/context7-mcp) | external MCP |
|
|
467
|
+
| Websearch cited | [ghoulr/opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited) | search integration influence |
|
|
468
|
+
| bun-pty / PTY ecosystem | [shekohex/opencode-pty](https://github.com/shekohex/opencode-pty) | PTY/runtime integration influence |
|
|
469
|
+
|
|
375
470
|
## Build And Publish
|
|
376
471
|
|
|
377
472
|
Build:
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawnSync } from "node:child_process"
|
|
4
|
+
import { existsSync, readFileSync } from "node:fs"
|
|
5
|
+
import { dirname, join } from "node:path"
|
|
6
|
+
import { homedir } from "node:os"
|
|
7
|
+
import { parse } from "jsonc-parser"
|
|
8
|
+
|
|
9
|
+
const DEFAULT_RAG_URL = "http://localhost:9002/tools/search"
|
|
10
|
+
|
|
11
|
+
const MCP_REGISTRY = {
|
|
12
|
+
playwright: {
|
|
13
|
+
defaultEnabled: true,
|
|
14
|
+
requiredEnv: [],
|
|
15
|
+
check: checkNodeNpx,
|
|
16
|
+
},
|
|
17
|
+
rag: {
|
|
18
|
+
defaultEnabled: true,
|
|
19
|
+
requiredEnv: [],
|
|
20
|
+
check: checkRag,
|
|
21
|
+
},
|
|
22
|
+
firecrawl: {
|
|
23
|
+
defaultEnabled: true,
|
|
24
|
+
requiredEnv: ["FIRECRAWL_API_KEY"],
|
|
25
|
+
authFallback: "firecrawl",
|
|
26
|
+
check: checkNodeNpx,
|
|
27
|
+
},
|
|
28
|
+
mempalace: {
|
|
29
|
+
defaultEnabled: true,
|
|
30
|
+
requiredEnv: [],
|
|
31
|
+
check: checkMempalace,
|
|
32
|
+
},
|
|
33
|
+
stitch: {
|
|
34
|
+
defaultEnabled: true,
|
|
35
|
+
requiredEnv: ["STITCH_AI_API_KEY"],
|
|
36
|
+
authFallback: "stitch",
|
|
37
|
+
check: checkRemoteKeyOnly,
|
|
38
|
+
},
|
|
39
|
+
context7: {
|
|
40
|
+
defaultEnabled: true,
|
|
41
|
+
requiredEnv: [],
|
|
42
|
+
check: checkRemoteOptionalKey,
|
|
43
|
+
},
|
|
44
|
+
"sequential-thinking": {
|
|
45
|
+
defaultEnabled: true,
|
|
46
|
+
requiredEnv: [],
|
|
47
|
+
check: checkNodeNpx,
|
|
48
|
+
},
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function usage() {
|
|
52
|
+
console.log(`hiai-opencode
|
|
53
|
+
|
|
54
|
+
Usage:
|
|
55
|
+
hiai-opencode mcp-status
|
|
56
|
+
|
|
57
|
+
Commands:
|
|
58
|
+
mcp-status Check hiai-opencode MCP configuration, keys, and local runtimes.
|
|
59
|
+
`)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function resolveEnvTemplate(value) {
|
|
63
|
+
if (typeof value !== "string") return value
|
|
64
|
+
return value.replace(/\{env:([^}]+)\}/g, (_match, expression) => {
|
|
65
|
+
const [name, fallback] = String(expression).split(":-", 2)
|
|
66
|
+
return process.env[name] || fallback || ""
|
|
67
|
+
})
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function candidateConfigPaths() {
|
|
71
|
+
const cwd = process.cwd()
|
|
72
|
+
const paths = [
|
|
73
|
+
join(cwd, "hiai-opencode.json"),
|
|
74
|
+
join(cwd, "hiai-opencode.jsonc"),
|
|
75
|
+
join(cwd, ".opencode", "hiai-opencode.json"),
|
|
76
|
+
join(cwd, ".opencode", "hiai-opencode.jsonc"),
|
|
77
|
+
join(homedir(), ".config", "opencode", "hiai-opencode.json"),
|
|
78
|
+
join(homedir(), ".config", "opencode", "hiai-opencode.jsonc"),
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
if (process.platform === "win32" && process.env.APPDATA) {
|
|
82
|
+
paths.push(join(process.env.APPDATA, "opencode", "hiai-opencode.json"))
|
|
83
|
+
paths.push(join(process.env.APPDATA, "opencode", "hiai-opencode.jsonc"))
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return paths
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function loadConfig() {
|
|
90
|
+
for (const path of candidateConfigPaths()) {
|
|
91
|
+
if (!existsSync(path)) continue
|
|
92
|
+
try {
|
|
93
|
+
return {
|
|
94
|
+
path,
|
|
95
|
+
config: parse(readFileSync(path, "utf-8")) ?? {},
|
|
96
|
+
}
|
|
97
|
+
} catch (error) {
|
|
98
|
+
return {
|
|
99
|
+
path,
|
|
100
|
+
config: {},
|
|
101
|
+
error: error instanceof Error ? error.message : String(error),
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return { path: null, config: {} }
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function hasCommand(command, args = ["--version"]) {
|
|
110
|
+
const result = spawnSync(command, args, {
|
|
111
|
+
stdio: "ignore",
|
|
112
|
+
timeout: 10000,
|
|
113
|
+
shell: process.platform === "win32",
|
|
114
|
+
})
|
|
115
|
+
return result.status === 0
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function hasNode() {
|
|
119
|
+
return hasCommand(process.platform === "win32" ? "node.exe" : "node")
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function hasNpx() {
|
|
123
|
+
return hasCommand(process.platform === "win32" ? "npx.cmd" : "npx")
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function checkNodeNpx() {
|
|
127
|
+
const node = hasNode()
|
|
128
|
+
const npx = hasNpx()
|
|
129
|
+
if (node && npx) return { level: "ok", detail: "backend ok" }
|
|
130
|
+
return {
|
|
131
|
+
level: "error",
|
|
132
|
+
detail: `${node ? "node ok" : "node not found"}, ${npx ? "npx ok" : "npx not found"}`,
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function pythonCandidates() {
|
|
137
|
+
const configured = process.env.MEMPALACE_PYTHON?.trim()
|
|
138
|
+
const candidates = []
|
|
139
|
+
if (configured) candidates.push(configured)
|
|
140
|
+
if (process.platform === "win32") {
|
|
141
|
+
candidates.push("py", "python", "python3")
|
|
142
|
+
} else {
|
|
143
|
+
candidates.push("python3", "python")
|
|
144
|
+
}
|
|
145
|
+
return [...new Set(candidates)]
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function canImportMempalace(command) {
|
|
149
|
+
const args =
|
|
150
|
+
command === "py"
|
|
151
|
+
? ["-3", "-c", "import mempalace.mcp_server"]
|
|
152
|
+
: ["-c", "import mempalace.mcp_server"]
|
|
153
|
+
const result = spawnSync(command, args, {
|
|
154
|
+
stdio: "ignore",
|
|
155
|
+
timeout: 10000,
|
|
156
|
+
shell: process.platform === "win32",
|
|
157
|
+
})
|
|
158
|
+
return result.status === 0
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function checkMempalace() {
|
|
162
|
+
if (hasCommand(process.platform === "win32" ? "uv.exe" : "uv")) {
|
|
163
|
+
return { level: "ok", detail: "uv available" }
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
for (const candidate of pythonCandidates()) {
|
|
167
|
+
if (canImportMempalace(candidate)) {
|
|
168
|
+
return { level: "ok", detail: `${candidate} with mempalace available` }
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const hasPython = pythonCandidates().some((candidate) =>
|
|
173
|
+
hasCommand(candidate, candidate === "py" ? ["-3", "--version"] : ["--version"]),
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
level: "error",
|
|
178
|
+
detail: hasPython ? "mempalace Python package not found" : "python not found",
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async function checkRag(config) {
|
|
183
|
+
const url =
|
|
184
|
+
process.env.OPENCODE_RAG_URL?.trim()
|
|
185
|
+
|| resolveEnvTemplate(config?.mcp?.rag?.environment?.OPENCODE_RAG_URL)
|
|
186
|
+
|| DEFAULT_RAG_URL
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
const controller = new AbortController()
|
|
190
|
+
const timeout = setTimeout(() => controller.abort(), 2500)
|
|
191
|
+
const response = await fetch(url, { method: "GET", signal: controller.signal })
|
|
192
|
+
clearTimeout(timeout)
|
|
193
|
+
|
|
194
|
+
if (response.status < 500) {
|
|
195
|
+
return { level: "ok", detail: `enabled, ${url} reachable` }
|
|
196
|
+
}
|
|
197
|
+
return { level: "warn", detail: `enabled, ${url} returned ${response.status}` }
|
|
198
|
+
} catch {
|
|
199
|
+
return { level: "warn", detail: `enabled, ${url} not reachable` }
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function checkRemoteKeyOnly() {
|
|
204
|
+
return { level: "ok", detail: "remote endpoint configured" }
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function checkRemoteOptionalKey(_config, name) {
|
|
208
|
+
if (name === "context7" && !process.env.CONTEXT7_API_KEY?.trim()) {
|
|
209
|
+
return { level: "ok", detail: "remote endpoint configured, API key optional/missing" }
|
|
210
|
+
}
|
|
211
|
+
return { level: "ok", detail: "remote endpoint configured" }
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function hasEnvOrAuth(config, envName, authKey) {
|
|
215
|
+
if (process.env[envName]?.trim()) return true
|
|
216
|
+
if (authKey && config?.auth?.[authKey]?.trim()) return true
|
|
217
|
+
return false
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
function statusIcon(level) {
|
|
221
|
+
if (level === "ok") return "✅"
|
|
222
|
+
if (level === "warn") return "⚠️ "
|
|
223
|
+
return "❌"
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async function mcpStatus() {
|
|
227
|
+
const { path, config, error } = loadConfig()
|
|
228
|
+
console.log("hiai-opencode mcp-status")
|
|
229
|
+
console.log(`Config: ${path ?? "not found; using defaults"}`)
|
|
230
|
+
if (error) console.log(`Config parse warning: ${error}`)
|
|
231
|
+
console.log("")
|
|
232
|
+
console.log("MCP Servers:")
|
|
233
|
+
|
|
234
|
+
for (const [name, entry] of Object.entries(MCP_REGISTRY)) {
|
|
235
|
+
const userEntry = config?.mcp?.[name]
|
|
236
|
+
const enabled = userEntry?.enabled ?? entry.defaultEnabled
|
|
237
|
+
if (!enabled) {
|
|
238
|
+
console.log(`⚪ ${name.padEnd(20)} - disabled`)
|
|
239
|
+
continue
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const missingEnv = entry.requiredEnv.filter((envName) =>
|
|
243
|
+
!hasEnvOrAuth(config, envName, entry.authFallback),
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
if (missingEnv.length > 0) {
|
|
247
|
+
console.log(`⚠️ ${name.padEnd(20)} - enabled, API key missing (${missingEnv.join(", ")})`)
|
|
248
|
+
continue
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const result = await entry.check(config, name)
|
|
252
|
+
console.log(`${statusIcon(result.level)} ${name.padEnd(20)} - ${result.detail}`)
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
async function main() {
|
|
257
|
+
const command = process.argv[2]
|
|
258
|
+
if (!command || command === "-h" || command === "--help") {
|
|
259
|
+
usage()
|
|
260
|
+
return
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (command === "mcp-status") {
|
|
264
|
+
await mcpStatus()
|
|
265
|
+
return
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
console.error(`Unknown command: ${command}`)
|
|
269
|
+
usage()
|
|
270
|
+
process.exit(1)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
main().catch((error) => {
|
|
274
|
+
console.error(error instanceof Error ? error.message : String(error))
|
|
275
|
+
process.exit(1)
|
|
276
|
+
})
|