@hiai-gg/hiai-opencode 0.1.3 → 0.1.4

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 (51) hide show
  1. package/.env.example +14 -18
  2. package/AGENTS.md +75 -23
  3. package/ARCHITECTURE.md +11 -14
  4. package/LICENSE.md +1 -0
  5. package/README.md +177 -94
  6. package/assets/cli/hiai-opencode.mjs +276 -0
  7. package/assets/mcp/playwright.mjs +7 -0
  8. package/config/hiai-opencode.schema.json +113 -1
  9. package/dist/config/defaults.d.ts +0 -3
  10. package/dist/config/index.d.ts +0 -1
  11. package/dist/config/platform-schema.d.ts +70 -0
  12. package/dist/config/schema/agent-overrides.d.ts +256 -0
  13. package/dist/config/schema/categories.d.ts +2 -2
  14. package/dist/config/schema/commands.d.ts +1 -0
  15. package/dist/config/schema/index.d.ts +2 -0
  16. package/dist/config/schema/oh-my-opencode-config.d.ts +267 -0
  17. package/dist/config/schema/skill-discovery.d.ts +11 -0
  18. package/dist/config/types.d.ts +12 -1
  19. package/dist/features/builtin-commands/templates/mcp-status.d.ts +1 -0
  20. package/dist/features/builtin-commands/types.d.ts +1 -1
  21. package/dist/features/opencode-skill-loader/loader.d.ts +2 -0
  22. package/dist/index.js +692 -541
  23. package/dist/plugin/skill-discovery-config.d.ts +4 -0
  24. package/dist/shared/startup-diagnostics.d.ts +6 -0
  25. package/hiai-opencode.json +191 -35
  26. package/package.json +4 -1
  27. package/src/agents/AGENTS.md +3 -4
  28. package/src/config/defaults.ts +60 -81
  29. package/src/config/index.ts +0 -1
  30. package/src/config/platform-schema.ts +17 -2
  31. package/src/config/schema/agent-overrides.ts +2 -0
  32. package/src/config/schema/commands.ts +1 -0
  33. package/src/config/schema/fast-apply.ts +4 -4
  34. package/src/config/schema/index.ts +2 -0
  35. package/src/config/schema/oh-my-opencode-config.ts +3 -0
  36. package/src/config/schema/skill-discovery.ts +25 -0
  37. package/src/config/types.ts +16 -0
  38. package/src/features/builtin-commands/commands.ts +7 -0
  39. package/src/features/builtin-commands/templates/mcp-status.ts +36 -0
  40. package/src/features/builtin-commands/types.ts +1 -1
  41. package/src/features/builtin-skills/skills/playwright.ts +24 -2
  42. package/src/features/opencode-skill-loader/loader.ts +11 -0
  43. package/src/index.ts +14 -13
  44. package/src/plugin/hooks/create-tool-guard-hooks.ts +1 -1
  45. package/src/plugin/skill-context.ts +31 -13
  46. package/src/plugin/skill-discovery-config.ts +32 -0
  47. package/src/plugin-handlers/agent-config-handler.ts +20 -13
  48. package/src/plugin-handlers/command-config-handler.ts +22 -12
  49. package/src/shared/migration/agent-names.ts +5 -5
  50. package/src/shared/startup-diagnostics.ts +77 -0
  51. 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
- - `OPENROUTER_API_KEY` if you use the default model presets
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
- Recommended native OpenCode install:
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 DCP plugin:
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
- Manual config alternative:
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,87 @@ Manual config alternative:
94
96
  }
95
97
  ```
96
98
 
97
- Then start OpenCode:
99
+ The packaged minimal OpenCode example lives in [config/opencode.json](config/opencode.json).
98
100
 
99
- ```bash
100
- opencode
101
- ```
101
+ ### 2. Create project config
102
102
 
103
- Direct npm install is only needed for development or inspection:
103
+ Create a project-level config file at `hiai-opencode.json` in the project root or at `.opencode/hiai-opencode.json`.
104
104
 
105
- ```bash
106
- npm install @hiai-gg/hiai-opencode
107
- ```
108
-
109
- For local development:
105
+ Bash:
110
106
 
111
107
  ```bash
112
- git clone https://github.com/HiAi-gg/hiai-opencode.git
113
- cd hiai-opencode
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
- ## Register The Plugin In OpenCode
119
-
120
- Use the OpenCode plugin CLI:
112
+ PowerShell:
121
113
 
122
- ```bash
123
- opencode plugin @hiai-gg/hiai-opencode@latest --global
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 also want Dynamic Context Pruning, install its separate plugin next:
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 service block below and adjust it later.
133
120
 
134
121
  ```json
135
122
  {
136
- "$schema": "https://opencode.ai/config.json",
137
- "plugin": ["@hiai-gg/hiai-opencode"]
123
+ "mcp": {
124
+ "playwright": { "enabled": true },
125
+ "sequential-thinking": { "enabled": true },
126
+ "firecrawl": { "enabled": true },
127
+ "mempalace": { "enabled": true },
128
+ "rag": { "enabled": false },
129
+ "stitch": { "enabled": false },
130
+ "context7": { "enabled": true }
131
+ }
138
132
  }
139
133
  ```
140
134
 
141
- The packaged minimal example lives in [config/opencode.json](config/opencode.json).
135
+ 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
136
 
143
- The richer example config lives in [hiai-opencode.json](hiai-opencode.json).
137
+ ### 3. Connect models and add service keys
144
138
 
145
- 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.
139
+ Model provider credentials belong to OpenCode Connect, not to `hiai-opencode`.
140
+ This plugin only writes model IDs such as `openrouter/anthropic/claude-3.5-sonnet` into agent and category config.
146
141
 
147
- ## Quick Start
142
+ 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
143
 
149
144
  ```bash
150
- git clone https://github.com/HiAi-gg/hiai-opencode.git
151
- cd hiai-opencode
152
- bun install
153
- bun run build
145
+ export FIRECRAWL_API_KEY=...
146
+ export STITCH_AI_API_KEY=...
147
+ export CONTEXT7_API_KEY=...
154
148
  ```
155
149
 
156
- Register the plugin in OpenCode:
157
-
158
- ```bash
159
- opencode plugin @hiai-gg/hiai-opencode@latest --global
160
- ```
150
+ See [Environment Variables And Keys](#environment-variables-and-keys) for the full list.
161
151
 
162
- Optional:
152
+ ### 4. Start and verify
163
153
 
164
154
  ```bash
165
- opencode plugin @tarquinen/opencode-dcp@latest --global
155
+ opencode
156
+ hiai-opencode mcp-status
157
+ opencode debug config
158
+ opencode mcp list --print-logs --log-level INFO
166
159
  ```
167
160
 
168
- Manual equivalent:
161
+ `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
162
 
170
- ```json
171
- {
172
- "$schema": "https://opencode.ai/config.json",
173
- "plugin": ["@hiai-gg/hiai-opencode"]
174
- }
175
- ```
163
+ `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
164
 
177
- Project-level service config goes in `hiai-opencode.json` at the project root or under `.opencode/`:
165
+ ## Development Install
178
166
 
179
- ```json
180
- {
181
- "mcp": {
182
- "playwright": { "enabled": true },
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
- }
167
+ Direct npm install is only needed for development or inspection:
168
+
169
+ ```bash
170
+ npm install @hiai-gg/hiai-opencode
191
171
  ```
192
172
 
193
- Then verify:
173
+ Local development:
194
174
 
195
175
  ```bash
196
- opencode debug config
197
- opencode mcp list --print-logs --log-level INFO
176
+ git clone https://github.com/HiAi-gg/hiai-opencode.git
177
+ cd hiai-opencode
178
+ bun install
179
+ bun run build
198
180
  ```
199
181
 
200
182
  ## Post-Install Bootstrap Prompt
@@ -210,6 +192,8 @@ Check that @hiai-gg/hiai-opencode is registered. If Dynamic Context Pruning is r
210
192
 
211
193
  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
194
 
195
+ 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.
196
+
213
197
  Enable only services that can run on this machine:
214
198
  - playwright: requires node/npx; optionally set HIAI_PLAYWRIGHT_INSTALL_BROWSERS=1 before first run if browser binaries are needed.
215
199
  - sequential-thinking: requires node/npx.
@@ -232,21 +216,17 @@ If a dependency is missing, install only user-level or project-local dependencie
232
216
 
233
217
  ### Models
234
218
 
235
- Model presets and role guidance:
219
+ Canonical runtime defaults for agents, categories, MCP, LSP, and model IDs:
236
220
 
237
- - [src/config/models.ts](src/config/models.ts)
221
+ - [hiai-opencode.json](hiai-opencode.json)
238
222
 
239
- Runtime defaults for agents, categories, MCP, LSP:
223
+ Runtime loader for the bundled canonical config:
240
224
 
241
225
  - [src/config/defaults.ts](src/config/defaults.ts)
242
226
 
243
- User-facing example config:
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`.
227
+ If you want to change which model a specific agent or category uses by default, edit `hiai-opencode.json`.
248
228
 
249
- If you want to change the shared preset values like `fast`, `mid`, `high`, `vision`, or `reasoning`, edit `src/config/models.ts`.
229
+ Use fully qualified model IDs. Do not introduce local aliases like `hiai-fast`, `sonnet`, `fast`, or `high`.
250
230
 
251
231
  ### Prompting
252
232
 
@@ -281,6 +261,24 @@ Skill materialization logic:
281
261
 
282
262
  - [src/features/builtin-skills/materialize.ts](src/features/builtin-skills/materialize.ts)
283
263
 
264
+ Skill discovery defaults:
265
+
266
+ ```json
267
+ {
268
+ "skill_discovery": {
269
+ "config_sources": true,
270
+ "project_opencode": true,
271
+ "global_opencode": false,
272
+ "project_claude": false,
273
+ "global_claude": false,
274
+ "project_agents": false,
275
+ "global_agents": false
276
+ }
277
+ }
278
+ ```
279
+
280
+ 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.
281
+
284
282
  ### MCP
285
283
 
286
284
  Default MCP registry:
@@ -304,21 +302,23 @@ LSP defaults are defined in:
304
302
 
305
303
  ## Environment Variables And Keys
306
304
 
307
- Important keys:
305
+ 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.
306
+
307
+ Important service variables:
308
308
 
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
309
  - `STITCH_AI_API_KEY`
317
310
  - `FIRECRAWL_API_KEY`
318
311
  - `CONTEXT7_API_KEY`
312
+ - `GOOGLE_SEARCH_API_KEY`
319
313
  - `OLLAMA_BASE_URL`
320
314
  - `OLLAMA_MODEL`
321
315
  - `MEMPALACE_PYTHON`
316
+ - `MEMPALACE_PALACE_PATH`
317
+ - `OPENCODE_RAG_URL`
318
+ - `HIAI_PLAYWRIGHT_INSTALL_BROWSERS`
319
+ - `HIAI_MCP_AUTO_INSTALL`
320
+
321
+ 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
322
 
323
323
  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
324
 
@@ -350,19 +350,40 @@ The source of truth for default MCP wiring is `src/mcp/registry.ts`. Change that
350
350
  - `sequential-thinking`: launches `@modelcontextprotocol/server-sequential-thinking` through the helper npm runner.
351
351
  - `firecrawl`: launches `firecrawl-mcp` through the helper npm runner and requires `FIRECRAWL_API_KEY`.
352
352
 
353
- ### Needs upstream runtime or extra setup
353
+ ### Playwright On Minimal Linux Hosts
354
354
 
355
- - `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.
356
- - `rag`: requires your own running endpoint
355
+ `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
356
 
358
- ### Additional OpenCode Plugin
357
+ Playwright has two dependency layers:
359
358
 
360
- `opencode-dcp` is a separate OpenCode plugin, not an MCP server:
359
+ - Browser binary: install with `HIAI_PLAYWRIGHT_INSTALL_BROWSERS=1` before OpenCode starts, or run `npx playwright install chromium`.
360
+ - 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
361
 
362
- ```bash
363
- opencode plugin @tarquinen/opencode-dcp@latest --global
362
+ If sudo is not available:
363
+
364
+ - Use an already installed system browser by editing the Playwright command in `.opencode/hiai-opencode.json`, for example:
365
+
366
+ ```json
367
+ {
368
+ "mcp": {
369
+ "playwright": {
370
+ "enabled": true,
371
+ "command": ["node", "{pluginRoot}/assets/mcp/playwright.mjs", "--browser", "chrome"],
372
+ "timeout": 600000
373
+ }
374
+ }
375
+ }
364
376
  ```
365
377
 
378
+ - Try `--browser msedge` if Edge is installed.
379
+ - Use a remote/CDP browser or the `agent-browser`/`playwright-cli` skill path if those tools are installed.
380
+ - Use `curl` only as a degraded HTTP check. It does not replace browser interaction, screenshots, auth flows, or client-side app verification.
381
+
382
+ ### Needs upstream runtime or extra setup
383
+
384
+ - `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.
385
+ - `rag`: requires your own running endpoint
386
+
366
387
  ### Important Windows note
367
388
 
368
389
  On some Windows/OpenCode environments, local MCP process spawning can fail with `EPERM` for `cmd` or `node`. If you see that:
@@ -372,6 +393,68 @@ On some Windows/OpenCode environments, local MCP process spawning can fail with
372
393
 
373
394
  This most often affects `sequential-thinking` and `mempalace`, and sometimes local `npx`-backed tools.
374
395
 
396
+ ## Diagnostics
397
+
398
+ The plugin now emits startup warnings for common misconfiguration, including:
399
+
400
+ - `.opencode/opencode.json` containing `plugin: ["list"]`
401
+ - enabled MCP integrations with missing required env vars such as `FIRECRAWL_API_KEY` or `STITCH_AI_API_KEY`
402
+
403
+ Available CLI:
404
+
405
+ ```bash
406
+ hiai-opencode mcp-status
407
+ ```
408
+
409
+ Inside OpenCode, use the slash command:
410
+
411
+ ```text
412
+ /mcp-status
413
+ ```
414
+
415
+ Example output:
416
+
417
+ ```text
418
+ MCP Servers:
419
+ ✅ playwright - backend ok
420
+ ⚠️ rag - enabled, http://localhost:9002/tools/search not reachable
421
+ ✅ firecrawl - backend ok
422
+ ❌ mempalace - python not found
423
+ ⚠️ stitch - enabled, API key missing (STITCH_AI_API_KEY)
424
+ ```
425
+
426
+ Planned follow-up commands:
427
+
428
+ - `hiai-opencode doctor`: report config location, MCP status, missing keys, and local dependency checks.
429
+ - `hiai-opencode export-mcp`: generate a standard `.mcp.json` for hosts that do not expose plugin-provided MCP servers through `opencode mcp list`.
430
+
431
+ Until those commands ship, use:
432
+
433
+ ```bash
434
+ opencode debug config
435
+ opencode mcp list --print-logs --log-level INFO
436
+ ```
437
+
438
+ ## Core Components And Upstream Projects
439
+
440
+ `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.
441
+
442
+ | Component | Upstream | Notes |
443
+ |---|---|---|
444
+ | OpenCode host/runtime | [anomalyco/opencode](https://github.com/anomalyco/opencode) | plugin host and runtime target |
445
+ | Core orchestration influences | [code-yeongyu/oh-my-openagent](https://github.com/code-yeongyu/oh-my-openagent) | architectural influence |
446
+ | Planning / workflow influences | [obra/superpowers](https://github.com/obra/superpowers) | planning, review, and debugging ideas |
447
+ | Specialist / platform influences | [vtemian/micode](https://github.com/vtemian/micode) | platform-style specialist behavior |
448
+ | Agent skill ecosystem | [addyosmani/agent-skills](https://github.com/addyosmani/agent-skills) | tactical workflow skill ideas |
449
+ | Optional external plugin | [Opencode-DCP/opencode-dynamic-context-pruning](https://github.com/Opencode-DCP/opencode-dynamic-context-pruning) | installed separately |
450
+ | MemPalace | [MemPalace/mempalace](https://github.com/MemPalace/mempalace) | external MCP/runtime |
451
+ | Playwright MCP | [microsoft/playwright-mcp](https://github.com/microsoft/playwright-mcp) | external MCP |
452
+ | Sequential Thinking | [modelcontextprotocol/servers](https://github.com/modelcontextprotocol/servers) | external MCP |
453
+ | Firecrawl MCP | [firecrawl-ai/firecrawl-mcp-server](https://github.com/firecrawl-ai/firecrawl-mcp-server) | external MCP |
454
+ | Context7 MCP | [upstash/context7-mcp](https://github.com/upstash/context7-mcp) | external MCP |
455
+ | Websearch cited | [ghoulr/opencode-websearch-cited](https://github.com/ghoulr/opencode-websearch-cited) | search integration influence |
456
+ | bun-pty / PTY ecosystem | [shekohex/opencode-pty](https://github.com/shekohex/opencode-pty) | PTY/runtime integration influence |
457
+
375
458
  ## Build And Publish
376
459
 
377
460
  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
+ })
@@ -42,6 +42,13 @@ if (shouldInstallBrowsers()) {
42
42
  const result = runNpx(["-y", "playwright@latest", "install", "chromium"])
43
43
  if (result.status !== 0) {
44
44
  console.error("[hiai-opencode] playwright browser install failed")
45
+ console.error("[hiai-opencode] Try: npx playwright install chromium")
46
+ }
47
+
48
+ if (process.platform === "linux") {
49
+ console.error("[hiai-opencode] Playwright Chromium may also need Linux system libraries.")
50
+ console.error("[hiai-opencode] If browser launch fails with libnspr4/libnss3/libgtk errors, run: sudo npx playwright install-deps chromium")
51
+ console.error("[hiai-opencode] Without sudo, use an existing browser by adding args in hiai-opencode.json, e.g. --browser chrome")
45
52
  }
46
53
  }
47
54