@yugabytedb/meko-mcp 2.2.0 → 2.3.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 (63) hide show
  1. package/README.md +106 -38
  2. package/assets/hooks-handlers/lib/capture-cleanup-cli.js +1473 -0
  3. package/assets/hooks-handlers/lib/capture-notices.js +131 -14
  4. package/assets/hooks-handlers/lib/capture-state.js +95 -1
  5. package/assets/hooks-handlers/lib/capture-status-cli.js +6 -2
  6. package/assets/hooks-handlers/lib/capture.js +1237 -137
  7. package/assets/hooks-handlers/lib/checkpoint-timer.js +51 -10
  8. package/assets/hooks-handlers/lib/journal-bridge.js +218 -0
  9. package/assets/hooks-handlers/lib/kiro-handler.js +26 -4
  10. package/assets/hooks-handlers/lib/opencode-handler.js +620 -0
  11. package/assets/hooks-handlers/lib/opencode-normalizer.js +145 -0
  12. package/assets/hooks-handlers/lib/terminal-handoff.js +10 -1
  13. package/assets/opencode-plugin/meko.js +213 -0
  14. package/assets/scripts/meko-statusline.sh +85 -18
  15. package/assets/skills/meko-mcp-tools/SKILL.md +57 -14
  16. package/assets/skills/meko-mcp-tools/references/_sections.md +2 -2
  17. package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +15 -7
  18. package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +86 -14
  19. package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +1 -1
  20. package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +29 -6
  21. package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +8 -4
  22. package/assets/skills/meko-mcp-tools/references/tools-overview.md +32 -22
  23. package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +14 -8
  24. package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +45 -1
  25. package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +6 -39
  26. package/assets/skills/meko-mcp-tools-desktop/SKILL.md +54 -18
  27. package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +1 -1
  28. package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +1 -1
  29. package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +8 -6
  30. package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +95 -33
  31. package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +22 -5
  32. package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +14 -10
  33. package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +35 -25
  34. package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +14 -8
  35. package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +67 -1
  36. package/assets/skills/meko-select-datapack-desktop/SKILL.md +4 -4
  37. package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +5 -5
  38. package/assets/skills/meko-select-datapack-desktop/references/role-display-future.md +7 -5
  39. package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +4 -4
  40. package/bin/create-meko-setup.mjs +70 -7
  41. package/lib/capture-cleanup.mjs +63 -0
  42. package/lib/clients/claude-code.mjs +1 -0
  43. package/lib/clients/codex.mjs +80 -35
  44. package/lib/clients/common.mjs +7 -0
  45. package/lib/clients/index.mjs +2 -0
  46. package/lib/clients/kiro.mjs +5 -5
  47. package/lib/clients/opencode.mjs +532 -0
  48. package/lib/config.mjs +68 -1
  49. package/lib/installer.mjs +18 -2
  50. package/lib/migrate/adapters/claude-code.mjs +11 -2
  51. package/lib/migrate/adapters/codex.mjs +9 -2
  52. package/lib/migrate/adapters/memory-md.mjs +27 -8
  53. package/lib/migrate/adapters/opencode.mjs +148 -0
  54. package/lib/migrate/claude-parser.mjs +153 -9
  55. package/lib/migrate/id.mjs +195 -13
  56. package/lib/migrate/mcp-client.mjs +25 -1
  57. package/lib/migrate/opencode-normalizer.mjs +132 -0
  58. package/lib/migrate/orchestrator.mjs +293 -77
  59. package/lib/migrate/progress.mjs +239 -5
  60. package/lib/migrate/registry.mjs +72 -0
  61. package/lib/migrate.mjs +96 -8
  62. package/package.json +1 -1
  63. package/scripts/bundle-assets.mjs +4 -0
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Meko Setup Installer
2
2
 
3
- A zero-dependency Node.js CLI that configures [Meko MCP Server](https://mekodata.netlify.app/) for Claude Code, Claude Desktop, Cursor, OpenAI Codex (CLI + Desktop App), and Kiro (IDE + CLI) in one command. It registers MCP server settings, configures hook/runtime environment where supported, installs skills support, and validates the setup.
3
+ A zero-dependency Node.js CLI that configures [Meko MCP Server](https://mekodata.netlify.app/) for Claude Code, Claude Desktop, Cursor, OpenAI Codex, Kiro, and OpenCode in one command. It registers MCP server settings, configures hook/runtime environment where supported, installs skills support, and validates the setup.
4
4
 
5
5
  Reduces manual setup to a single command.
6
6
 
@@ -17,8 +17,8 @@ Cloud Meko also accepts a browser **OAuth** flow, but that path is out of scope
17
17
  here: you turn it on inside a client's own UI, and it uses no API key. Don't
18
18
  configure both against the same client — see [Two authentication
19
19
  modes](../README.md#two-authentication-modes--pick-one-dont-mix-them) for the
20
- comparison and the failure modes, including why OAuth isn't currently usable from
21
- clients that register a loopback callback.
20
+ comparison and the failure modes, including why OAuth with a loopback callback
21
+ still fails against the DEV environment.
22
22
 
23
23
  **Note:** The server accepts the key only as `Authorization: Bearer …` on the
24
24
  wire. An `API_KEY` or `MEKO_API_KEY` environment variable does nothing unless
@@ -62,6 +62,16 @@ npx @yugabytedb/meko-mcp --local --yes
62
62
  npx @yugabytedb/meko-mcp --client cursor --local --scope project --yes
63
63
  ```
64
64
 
65
+ **OpenCode CLI/TUI 1.18.x install:**
66
+
67
+ ```bash
68
+ npx @yugabytedb/meko-mcp --client opencode --scope user --yes
69
+ # Project-scoped plugin, runtime, and skill:
70
+ npx @yugabytedb/meko-mcp --client opencode --scope project --yes
71
+ ```
72
+
73
+ Restart OpenCode after either install.
74
+
65
75
  **Claude Desktop install:**
66
76
 
67
77
  Claude Desktop has two install paths — pick based on whether you want the agent skill (the behavioral guide that teaches the agent *when* to call Meko tools — how to capture turns via per-turn `conversation_add_message` posting so the server can extract memories, and when the narrow explicit `memory_add` cases apply):
@@ -120,7 +130,7 @@ Re-run the installer to refresh the bundles when skill content updates; you'll n
120
130
  # Target two clients in one run:
121
131
  npx @yugabytedb/meko-mcp --client claude-code,claude-desktop --local --yes
122
132
 
123
- # Target every supported client (claude-code, claude-desktop, cursor, codex, kiro):
133
+ # Target every supported client:
124
134
  npx @yugabytedb/meko-mcp --client all --local --yes
125
135
  ```
126
136
 
@@ -173,7 +183,7 @@ The canary used to do a `memory_add` → `memory_get_by_id` → `memory_delete_b
173
183
  - MCP config: `~/.codex/config.toml` (TOML; `[mcp_servers.<name>]` block).
174
184
  - Skills path: `~/.agents/skills/meko-mcp-tools/` (the shared agent-skills convention).
175
185
  - System prompt: `~/.codex/AGENTS.md` (a Meko-managed sentinel block is upserted; user content outside the fence is preserved).
176
- - **Cloud auth (MCP server)**: Codex's TOML stores `bearer_token_env_var = "MEKO_API_KEY"` rather than the key itself. You must export `MEKO_API_KEY` in your shell before launching Codex. The installer offers (interactively, never with `--yes`) to append the export line to your shell rc (`~/.zshrc` / `~/.bashrc` / `~/.config/fish/config.fish`). On macOS, when the desktop app is detected and an API key is supplied, the installer runs `launchctl setenv MEKO_API_KEY ...` so Codex.app launched from Finder/Dock can authenticate in the current login session.
186
+ - **Cloud auth (MCP server)**: Codex's TOML stores `bearer_token_env_var = "MEKO_API_KEY"` rather than the key itself. You must export `MEKO_API_KEY` in your shell before launching Codex. The installer offers (interactively, never with `--yes`) to append the export line to your shell rc (`~/.zshrc` / `~/.bashrc` / `~/.config/fish/config.fish`). On macOS, when an API key is supplied, the installer offers to run `launchctl setenv MEKO_API_KEY ...` (default Yes) so GUI-launched Codex - the desktop app from Finder/Dock, or the CLI from Spotlight/Alfred/`open` - can authenticate in the current login session. The prompt calls out that `launchctl setenv` writes into the login-session env inherited by every subsequently GUI-launched process (visible via `launchctl getenv`, `ps e` on descendants, and crash reports); decline the offer if that exposure is not acceptable for the host and rely on shell rc instead.
177
187
  - **Cloud WAF User-Agent** (cloud installs only): Cloud Meko sits behind a WAF that returns an HTML `403 Forbidden` for any HTTP request with no `User-Agent`. Codex's native MCP client sends none by default, so its `initialize` handshake would 403 and the `meko` server would fail to start with `MCP client for 'meko' failed to start ... HTTP 403`. `codex mcp add` exposes no header flag, so the installer writes a per-server header into `~/.codex/config.toml`:
178
188
  ```toml
179
189
  [mcp_servers.meko]
@@ -191,6 +201,24 @@ The canary used to do a `memory_add` → `memory_get_by_id` → `memory_delete_b
191
201
  - Managed CLI 2.x agent: `~/.kiro/agents/meko-default.json` or `.kiro/agents/meko-default.json`, with inline `agentSpawn`, `userPromptSubmit`, and `stop` hooks. The installer preserves the previous `chat.defaultAgent` before selecting it.
192
202
  - Stable capture runtime: `~/.kiro/hooks/meko-hooks/hooks-handlers/` or the project equivalent. `kiro-hook-env.json` stores the endpoint and optional API key at mode 0600.
193
203
  - Steering file: `~/.kiro/steering/meko.md` or `.kiro/steering/meko.md`. It follows hook capture when the session-start marker is present and falls back to agent-driven persistence only when hooks are disabled, untrusted, or a different CLI 2.x agent is selected. See [Kiro notes](#kiro-notes).
204
+ - **OpenCode CLI/TUI 1.18.x**
205
+ - User plugin: `$OPENCODE_CONFIG_DIR/plugins/meko.js` when set, otherwise `~/.config/opencode/plugins/meko.js`; project plugin: `<project>/.opencode/plugins/meko.js`.
206
+ - Stable runtime and private environment: `$OPENCODE_CONFIG_DIR/meko/` when set, otherwise `~/.config/opencode/meko/`, or `<project>/.opencode/meko/`. `opencode-hook-env.json` is mode 0600 and contains the MCP URL, API key, server name, User-Agent, hook client, stable Node executable, and watermark dir. Automatic capture uses the server-default datapack in this release. `--datapack` applies only to `--migrate`. OpenCode does not read `pin-<slug>.json` (no SessionStart, and `meko-select-datapack` is not installed).
207
+ - Skill: `$OPENCODE_CONFIG_DIR/skills/meko-mcp-tools/` when set, otherwise `~/.config/opencode/skills/meko-mcp-tools/`, or `<project>/.opencode/skills/meko-mcp-tools/`.
208
+ - The plugin mutates OpenCode's resolved configuration at runtime with a native remote MCP entry (`type: remote`, `enabled: true`, `oauth: false`). It does **not** edit `opencode.json` or `opencode.jsonc`; validation runs `opencode debug config` and verifies the resolved entry.
209
+ - Restart OpenCode after install. Reinstall upgrades installer-owned assets while preserving durable capture state and user-owned collisions.
210
+
211
+ ### OpenCode CLI / TUI 1.18.x
212
+
213
+ OpenCode **1.18.x only** is supported in this release; 1.18.22 is the initial canary baseline. The installer rejects older releases and future minor/major versions until they are explicitly certified because OpenCode's plugin and MCP configuration APIs are evolving.
214
+
215
+ The installer-owned plugin listens to OpenCode's public `event({event})` hook. On `session.idle` and `session.error`, it fetches `session.get({path:{id}})` and `session.messages({path:{id}})`, strips the snapshot to visible text plus stable IDs/timestamps, and hands it to Capture v2. Duplicate completed turns are skipped by OpenCode message IDs. A `session.error` snapshot does not rewrite a completed turn and does not append a synthetic `u1:interrupted` user id. A failed handoff leaves a staged snapshot under the durable capture root for startup replay; structurally invalid snapshots are quarantined.
216
+
217
+ **Capture boundary:** one visible user message plus the first visible assistant message before the next user message becomes one Meko turn. Later assistant messages in the same turn are dropped. Multiple visible text parts on that first assistant retain order. Tool calls/results, reasoning, files, attachments, steps, snapshots, patches, text explicitly marked ignored or synthetic, and binary content are excluded. OpenCode compaction-summary exclusion is not certified because the 1.18.22 export shape has not been frozen in a real fixture. Active incomplete turns remain pending until a later snapshot completes them, a later user turn interrupts them, or the 30-minute settle deadline expires (every Capture v2 timer that shares the capture root uses that default; `MEKO_OPENCODE_SETTLE_MS` is a same-process test override). `session.error` holds a partial assistant as a tentative observation until OpenCode rewrites that assistant in place on idle, a later user turn interrupts, or that deadline expires. A later distinct user turn interrupts the prior pending user. Ownership is `opencode:<repo>`, derived at capture from the session directory (the plugin does not inject `agent_id`). Health is visible through `create-meko-setup --capture-status`.
218
+
219
+ **Migration:** `create-meko-setup --migrate` invokes only supported public CLI commands (`opencode session list --format json` and `opencode export <sessionID>`); it never reads OpenCode's SQLite database or internal storage. User scope is a cwd-backed superset that includes the active project. OpenCode 1.18.x lists root sessions only, so child sessions are not migrated. An unsupported OpenCode version is skipped without blocking Claude Code, Cursor, or Codex migration. The current durable root-session view is migrated, not a historical event log.
220
+
221
+ **Not supported yet:** OpenCode Desktop certification, V2 preview APIs/configuration, pre-1.18 or post-1.18 versions, GitHub agent/headless server/remote workspace/shared-session migration, parent-child tree reconstruction, tool/reasoning/file/attachment capture, and incremental streaming capture.
194
222
 
195
223
  ## CLI Reference
196
224
 
@@ -201,7 +229,7 @@ Usage:
201
229
 
202
230
  | Flag | Description | Default |
203
231
  |------|-------------|---------|
204
- | `--client <list>` | Target client(s): one or more of `claude-code`, `claude-desktop`, `cursor`, `codex`, `kiro`. Comma-separated, or `all`. `codex` covers both the OpenAI Codex CLI and the Codex Desktop App (they share `~/.codex/config.toml`); `kiro` covers both the Kiro IDE and `kiro-cli` (they share `~/.kiro/settings/mcp.json`). Aliases: `claude` → `claude-code`, `kiro-cli` / `kiro-ide` → `kiro`. | `claude-code` |
232
+ | `--client <list>` | Target client(s): one or more of `claude-code`, `claude-desktop`, `cursor`, `codex`, `kiro`, `opencode`. Comma-separated, or `all`. `codex` covers both the OpenAI Codex CLI and the Codex Desktop App (they share `~/.codex/config.toml`); `kiro` covers both the Kiro IDE and `kiro-cli` (they share `~/.kiro/settings/mcp.json`). OpenCode is version-gated to CLI/TUI 1.18.x. Aliases: `claude` → `claude-code`, `kiro-cli` / `kiro-ide` → `kiro`. | `claude-code` |
205
233
  | `--url <url>` | MCP server URL (from cloud.mekodata.ai > Datapacks > Connect) | Shared existing endpoint, otherwise production; conflicts prompt or require `--url` under `--yes` |
206
234
  | `--api-key <key>` | API key for Cloud Meko authentication. If a Cloud `--url` is supplied without this flag, the installer falls back to `$MEKO_API_KEY`, then to an interactive prompt on a TTY. Only fails hard when running under `--yes` or with no TTY attached. | _(interactive prompt or `$MEKO_API_KEY` env)_ |
207
235
  | `--local` | Use local Meko at `http://localhost:8000/mcp` (no API key needed) | `false` |
@@ -223,13 +251,18 @@ Capture health flags (durable outbox / recovery — Capture V2):
223
251
  | Flag | Description | Default |
224
252
  |------|-------------|---------|
225
253
  | `--capture-status` | Report aggregate conversation-capture health from `~/.claude/meko-capture` (or `MEKO_WATERMARK_DIR`). Exit `0` = healthy\|catching_up, `2` = degraded_retrying, `3` = blocked_action_required. | `false` |
226
- | `--json` | With `--capture-status`, print machine-readable JSON matching the capture-health cache shape. | `false` |
254
+ | `--json` | With `--capture-status`, print machine-readable JSON matching the capture-health cache shape. Also accepted by `--capture-cleanup`. | `false` |
255
+ | `--capture-cleanup <action>` | Inspect and clean up stuck capture on this machine. Actions: `status`, `stop`, `resume`, `drain`, `discard`, `repair`. See [Clean up stuck capture](../OPERATIONS.md#clean-up-stuck-capture). Exit `0` = done, `1` = error, `2` = partly done. | |
256
+ | `--session <id>` | With `--capture-cleanup`, act on one session. Repeatable; a unique prefix of the ID is enough. A bare ID after the action works too: `--capture-cleanup drain c0acdeb2`. | |
257
+ | `--all` | With `--capture-cleanup`, act on every session. `drain` and `discard` need `--session` or `--all`. | `false` |
258
+ | `--max-exchanges <n>` | With `--capture-cleanup drain`, stop after sending this many exchanges in total. | `200` |
259
+ | `--pace-ms <n>` | With `--capture-cleanup drain`, wait this long between batches. | `1000` |
227
260
 
228
261
  Migrate subcommand flags (see [Migrate Existing Data](#migrate-existing-data) below for details):
229
262
 
230
263
  | Flag | Description | Default |
231
264
  |------|-------------|---------|
232
- | `--migrate` | Start a detached migration of existing Claude Code + Cursor conversations and `CLAUDE.md` memories into Meko. | `false` |
265
+ | `--migrate` | Start a detached migration of existing Claude Code, Cursor, Codex, and OpenCode sessions plus `CLAUDE.md` memories into Meko. | `false` |
233
266
  | `--with-migrate` | With `--yes`, kick off `--migrate` at the end of a successful install without prompting. CI-friendly. | `false` |
234
267
  | `--migrate-status` | Print the status of the latest (or `--run-id`-specified) migration run. | `false` |
235
268
  | `--migrate-stop` | Stop the running migration (SIGTERM, then SIGKILL after 2s). | `false` |
@@ -246,8 +279,9 @@ After installing Meko, `--migrate` seeds your new datapack with the conversation
246
279
 
247
280
  | Source | Location | Becomes |
248
281
  |---|---|---|
249
- | Claude Code transcripts | `~/.claude/projects/<slug>/<uuid>.jsonl` | One Meko conversation (one Langfuse trace) per session; one paired user↔assistant turn per message pair. |
282
+ | Claude Code transcripts | `~/.claude/projects/<slug>/<uuid>.jsonl` | One Meko conversation (one Langfuse trace) per session; one paired user↔assistant turn per message pair. Skill bodies and task notifications join the `reasoning` of the turn they belong to, and a typed `/skill args` becomes that turn's input, as in live capture. |
250
283
  | Cursor transcripts | `~/.cursor/projects/<name>/agent-transcripts/<uuid>/*.jsonl` | Same — one conversation per session, one paired turn per user↔assistant round. |
284
+ | OpenCode sessions | Public CLI: `opencode session list --format json`, then `opencode export <sessionID>` | One Meko conversation per root session with directory metadata; visible text only. |
251
285
  | User-scope CLAUDE.md | `~/.claude/CLAUDE.md` | One memory per top-level `# ` section (`agent_id = "meko_agent"` — the cross-project common bucket — with `metadata.scope = "user"`). |
252
286
  | Project-scope CLAUDE.md | `<projectCwd>/.claude/CLAUDE.md` | One memory per top-level `# ` section (`agent_id = "claude_code:<repo-basename>"`, `metadata.scope = "project"`, `metadata.cwd = <project path>`). |
253
287
  | Indexed project memories | `~/.claude/projects/<slug>/memory/*.md` | One memory per file (`agent_id = "claude_code:<repo-basename>"`); YAML frontmatter (`name`, `description`, `type`) is preserved in metadata. |
@@ -256,12 +290,14 @@ Project `cwd` is derived by reading the `cwd` field from a real session file in
256
290
 
257
291
  ### What the migrator writes (MCP calls)
258
292
 
259
- Per migrated Claude Code / Cursor session:
293
+ Per migrated Claude Code / Cursor / Codex session:
260
294
 
261
- 1. **`conversation_create`** — once per session. Captures `cwd`, `gitBranch`, `startedAt`, and source agent (`claude-code` or `cursor`) in metadata. Returns the `conversation_id` used for subsequent calls.
295
+ 1. **`conversation_create`** — once per session. Captures `cwd`, `startedAt`, and source agent (`claude-code`, `cursor`, or `codex`) in metadata. Returns the `conversation_id` used for subsequent calls. `gitBranch` is set only for Claude Code (its refs have a slug). Cursor and Codex send null.
262
296
  2. **`conversation_add_message`** — once per paired user↔assistant turn. Carries `input`, `output`, and `reasoning` (thinking blocks + tool-use/tool-result summaries), plus a deterministic `seed` for server-side dedup. Fire-and-forget; Meko batches to Langfuse.
263
297
  3. **`memory_add(messages=[{role,content},...])`** — once per paired turn. This invokes Meko's server-side Mem0 extractor (the same pipeline the demo chatbot uses at `chatbot.py:177-178`) so the migrator seeds structured memories, not just raw transcripts. Skipped entirely under `--no-extract`.
264
298
 
299
+ Per migrated OpenCode session: the same three calls, with two differences. `gitBranch` is always null because OpenCode refs have no slug. The adapter sets `reasoning` to `""`, and the orchestrator omits the field (`reasoning || undefined`), so the MCP call has no `reasoning` key.
300
+
265
301
  Per CLAUDE.md / memory directory discovered:
266
302
 
267
303
  4. **`conversation_create`** — one umbrella "memory-migration" conversation per agent (reused for all MD items under that agent, to satisfy Meko's `memory_add` requirement that memories be associated with a conversation).
@@ -273,6 +309,8 @@ So a real run exercises **both** the Langfuse observability surface (1 + 2) and
273
309
  Dry run:
274
310
  Claude Code sessions: 94
275
311
  Cursor sessions: 10
312
+ Codex sessions: 3
313
+ OpenCode sessions: 4
276
314
  Paired user↔asst turns: 887
277
315
  Memory items (MD): 14
278
316
  Planned MCP calls:
@@ -291,7 +329,7 @@ The Meko MCP server does **not** currently auto-extract memories on `conversatio
291
329
 
292
330
  ### Scope
293
331
 
294
- - `--scope user` (default) — every Claude Code and Cursor project on the machine, plus `~/.claude/CLAUDE.md`, plus every per-project `.claude/CLAUDE.md` and indexed `memory/*.md` directory.
332
+ - `--scope user` (default) — every supported local session found by the registered migration adapters, plus `~/.claude/CLAUDE.md`, plus every per-project `.claude/CLAUDE.md` and indexed `memory/*.md` directory.
295
333
  - `--scope project` — only sessions whose `cwd` equals `process.cwd()`, plus that one project's `.claude/CLAUDE.md` and memory directory.
296
334
 
297
335
  ### Running
@@ -322,32 +360,36 @@ create-meko-setup --migrate --scope user --no-extract
322
360
 
323
361
  ```
324
362
  run-id: 20260429-000912-74dbe6
325
- status: running (pending → running → done | failed | stopped)
363
+ status: running (running → succeeded | failed | cancelled; crashed is inferred)
326
364
  scope: user
327
365
  started: 2026-04-29T00:09:12.673Z
328
366
  finished: (in progress)
329
- current: agent / a2f6a1d6-... (agent_id / source-session-uuid)
367
+ heartbeat: 2026-04-29T00:14:02.118Z (refreshed while running; staleness implies crashed)
368
+ current: agent / a2f6a1d6-... / 7c1e0b44-... (<agent-id> / <source-session> / <message-id>)
330
369
  sessions: 76 / 111 (processed / discovered)
331
370
  messages: 674
332
371
  memory pairs: 674 (memory_add from Mem0 extractor)
333
372
  memory (MD): 0 (memory_add from CLAUDE.md / memory files)
334
373
  warnings: 0 (non-fatal; run continues)
335
374
  memory errs: 0 (failed memory_add calls; re-run with --force to retry)
375
+ auth skipped: 0 (calls dropped on a mid-run 401/403; re-run to retry them)
336
376
  ```
337
377
 
338
378
  | Field | Meaning |
339
379
  |---|---|
340
380
  | `run-id` | Unique ID; also the directory name under `~/.meko/migrate/<run-id>/`. |
341
- | `status` | Terminal states are `done`, `failed`, `stopped`. A `running` row that hasn't advanced in >30 s may indicate the daemon died — check `~/.meko/migrate/<run-id>/stdout.log`. |
381
+ | `status` | `running` while the daemon is alive; `succeeded`, `failed`, or `cancelled` once it ends. A fifth value, `crashed`, is not stored: the status command reports it for a run whose daemon is gone (dead PID, or a heartbeat older than 30 s), which is what a `kill -9`, an OOM kill, or a reboot looks like. On `failed`, an `error:` line carries the reason. |
342
382
  | `scope` | Matches the `--scope` flag used at start (`user` or `project`). |
343
- | `started` / `finished` | UTC timestamps. `finished` shows `(in progress)` until a terminal state is reached. |
344
- | `current` | Which source item is being replayed — `<adapter>:<source-session>` (adapter = `claude-code` / `cursor` / `memory-md`). Becomes stale on `done`/`failed`/`stopped`. |
383
+ | `started` / `finished` | UTC timestamps. `finished` shows `(in progress)` until a terminal state is reached, or `(never, daemon died)` for a crashed run. |
384
+ | `heartbeat` | Last time the daemon touched `progress.json`. Refreshed every 10 s while running. |
385
+ | `current` | Which source item is being replayed: `<agent-id> / <source-session-uuid> / <source-message-uuid>`, where `<agent-id>` is the owner such as `opencode:<repo>` or `claude_code:<repo>`. Becomes `-` once the run reaches a terminal state. |
345
386
  | `sessions` | Conversation sessions processed / discovered across all adapters. Climbs during the run. |
346
387
  | `messages` | Total messages replayed so far via `conversation_add_message`. |
347
388
  | `memory pairs` | `memory_add` calls made via the Mem0 extractor path (messages-style input). Usually close to `messages` when the extractor is enabled. |
348
389
  | `memory (MD)` | `memory_add` calls from `CLAUDE.md` / memory-file sources (plain-text input). |
349
390
  | `warnings` | Non-fatal issues (skipped item, partial parse). Run keeps going. |
350
391
  | `memory errs` | `memory_add` calls that failed. Non-zero means the memory extractor couldn't reach the server or rejected the payload — check the per-run log. Re-run with `--force` to retry only the failed items. |
392
+ | `auth skipped` | Calls dropped because the server returned 401/403 partway through the run, typically an expired token. The session that hit the 401/403 stops at that turn and is marked failed, and the run moves on to the next session. Each dropped call is recorded in `log.ndjson` as `message_skipped_auth`. Refresh the credential and re-run without `--force`: the run resumes each failed session from its last delivered turn. |
351
393
 
352
394
  ### Behavior around install
353
395
 
@@ -357,37 +399,39 @@ memory errs: 0 (failed memory_add calls; re-run with --force to
357
399
 
358
400
  ### Idempotency, resume, and state
359
401
 
360
- - Per-run logs: `~/.meko/migrate/<run-id>/log.ndjson` (one JSON object per line). `tail -f | jq .` is a reasonable debug loop.
402
+ - Per-run logs: `~/.meko/migrate/<run-id>/log.ndjson` (one JSON object per line). `tail -f | jq .` is a reasonable debug loop. This is the file the start banner points at, and the only one with run diagnostics in it.
403
+ - `~/.meko/migrate/<run-id>/stdout.log` is the daemon's redirected stdout/stderr. It is normally empty, because every diagnostic goes through the NDJSON logger instead. Non-empty means output escaped the logger: a stack trace from before it opened, or a native crash.
361
404
  - Per-run progress snapshot: `~/.meko/migrate/<run-id>/progress.json` (what `--migrate-status` reads).
362
405
  - Durable state: `~/.meko/migrate/state/<datapack-key>.json` tracks per-session checkpoints (`conversationId`, `messagesSent`, `lastUuid`, `status`) and per-memory content hashes, **scoped per destination datapack**. A re-run skips sessions marked `done` and memories whose body hash is unchanged. A partial session resumes from `lastUuid + 1`.
363
406
  - **Per-datapack scoping**: the datapack key is the UUID segment of the MCP URL (`https://<uuid>.mcp.mekodev.com/mcp` → `<uuid>`), or a stable 16-char sha256 prefix for non-UUID URLs (e.g. `http://localhost:8000/mcp`). Switching datapacks produces completely independent state — migrating into a fresh datapack never falsely treats sessions as already-done just because an earlier run populated a different one. `--migrate-status` prints the `datapack:` key of the latest run so you can tell at a glance which state it belongs to.
364
407
  - Back-compat for the legacy layout: migrations created before this change wrote to a single `~/.meko/migrate/state.json`. On the first run after upgrading, if `state/` is empty and `state.json` exists, the installer asks (or, under `--yes` / CI, silently accepts) "treat the legacy state as belonging to the current datapack" and copies `state.json` → `state/<current-key>.json`. The legacy file is kept on disk in case you roll back the installer.
365
408
  - Server-side dedup: `conversation_add_message` gets a deterministic `seed = sha256(agentId + ":" + sessionUuid + ":" + messageUuid)` so partial-run overlap doesn't create duplicate messages.
366
409
  - `--force` wipes the **current datapack's** resume state and re-issues every MCP call for it. Other datapacks' state files are untouched. If you only want to re-migrate into a new datapack, just point `--url` at the new one — no `--force` needed.
410
+ - `--force` doesn't remove messages that an older installer stored and this version no longer produces. Installers before 2.3.0 stored each Claude Code task notification as its own message, with the notification as input. 2.3.0 folds the notification and its reply into the turn it belongs to. After `--force`, that turn is sent again with the reply, but the old notification message stays, so the reply can appear twice. To get a clean copy, migrate into a new datapack instead.
367
411
 
368
412
  ### What does NOT get migrated (v1)
369
413
 
370
414
  - Slash-command skills, hooks, and `.claude/settings.json` — those remain in Claude Code's own config; Meko has no equivalent tool.
371
415
  - Knowledge-base documents — KB ingestion is UI-only (Datapack → Actions → Add Knowledge); not exposed via MCP.
372
- - Transcripts from other coding agents (Aider, Continue.dev, Windsurf, Codex). Claude Code + Cursor only.
416
+ - Transcripts from unregistered coding agents (for example Aider, Continue.dev, or Windsurf).
373
417
  - `user_id` is left null on every call (the server fills it from the API key). Multi-user routing is a follow-up.
374
418
 
375
419
  ## Client Compatibility Matrix
376
420
 
377
- | Capability | Claude Code | Claude Desktop | Cursor | Codex (CLI + App) | Kiro (IDE + `kiro-cli`) |
378
- |---|---|---|---|---|---|
379
- | One-command install | Yes | Yes | Yes | Yes | Yes |
380
- | MCP server registration | via `claude mcp add` | via `claude_desktop_config.json` merge using `mcp-remote` stdio bridge | via `.cursor/mcp.json` merge | via `codex mcp add` (CLI) or direct TOML write (App-only) | via `~/.kiro/settings/mcp.json` merge (native remote MCP) |
381
- | Backup before config write | `.bak` on `~/.claude/settings.json` | `.bak` on `claude_desktop_config.json` | No `.bak` — additive JSON writes preserve unrelated MCP servers, hooks, and settings | `.bak` on `~/.codex/config.toml` and `~/.codex/AGENTS.md` | No `.bak` — the write is an additive merge that preserves other `mcpServers` entries |
382
- | Automatic conversation capture | Yes (hooks) | **No** — see [issue #8](https://github.com/amiramm/meko-mcp-server/issues/8) | Yes (native hooks; first SessionStart may pause briefly while creating the Meko conversation) | Yes (hooks) — `SessionStart` / `PreCompact` / `SessionEnd` written to `~/.codex/hooks.json`; the AGENTS.md block provides fallback instructions when hooks are unavailable | Yes — inline CLI 2.x plus standalone CLI 3.x/IDE hooks share Capture v2 |
383
- | Automatic memory persistence | Yes (hooks + skill) | Skill only (proactive `memory_add`) | Yes (hooks + skill) | Hooks + skill; AGENTS.md fallback when hooks are unavailable | Hooks + skill; conditional steering fallback when the hook marker is absent |
384
- | Skill install | Plugin marketplace (automatic) | `.skill` bundle auto-built, user drags into app | Copy into `.cursor/skills` | Copy into `~/.agents/skills/meko-mcp-tools/` | Copy into `~/.kiro/skills/` (native Agent Skills format) |
385
- | Uninstall | Full automatic | MCP entry removed; skill must be removed manually from app | MCP + hooks + skills cleaned up | MCP entry, skill dir, and AGENTS.md block all cleaned up | MCP entry plus installer-owned hooks, managed agent, private env, skills, and steering; pending outbox data is preserved |
386
- | `agent_id` used by skill | `claude_code:<repo>` per project (via SessionStart hook); cross-project facts go to `meko_agent` | `claude_desktop` | `cursor:<repo>` per project (via Cursor hook); cross-project facts go to `meko_agent` | `codex:<repo>` per project (via SessionStart hook); cross-project facts go to `meko_agent` | `kiro:<repo>` per project via hook capture; cross-project facts go to `meko_agent` |
387
- | Transport | HTTP only | HTTP (or stdio via hand-edited config) | HTTP only | HTTP (Codex's `bearer_token_env_var` model) | HTTP only |
388
- | Auth model | inline `Authorization: Bearer ...` header | inline header via `mcp-remote` | inline header | MCP server: env-var name reference (`MEKO_API_KEY` exported in shell or via `launchctl setenv`). Hooks: key written to `~/.codex/meko-env.sh` at mode 0600; each hook command sources the file before bash (no env block in Codex's hooks schema; see [Security](#security)). | inline `Authorization: Bearer ...` header (never `mcp-remote` — see note below) |
389
- | Project scope | Yes (`--scope project`) | No | Yes (`--scope project`) | No (warns and degrades to user scope) | Yes (`--scope project`) |
390
- | Deferred to a follow-up | — | `.mcpb` Desktop Extension packaging — see [issue #7](https://github.com/amiramm/meko-mcp-server/issues/7) | — | — | Tool-call/hidden-reasoning capture (not exposed by Kiro hook events) |
421
+ | Capability | Claude Code | Claude Desktop | Cursor | Codex (CLI + App) | Kiro (IDE + `kiro-cli`) | OpenCode CLI/TUI 1.18.x |
422
+ |---|---|---|---|---|---|---|
423
+ | One-command install | Yes | Yes | Yes | Yes | Yes | Yes |
424
+ | MCP server registration | via `claude mcp add` | via `claude_desktop_config.json` merge using `mcp-remote` stdio bridge | via `.cursor/mcp.json` merge | via `codex mcp add` (CLI) or direct TOML write (App-only) | via `~/.kiro/settings/mcp.json` merge (native remote MCP) | Installer-owned plugin overlay; source config untouched |
425
+ | Backup before config write | `.bak` on `~/.claude/settings.json` | `.bak` on `claude_desktop_config.json` | No `.bak` — additive JSON writes preserve unrelated MCP servers, hooks, and settings | `.bak` on `~/.codex/config.toml` and `~/.codex/AGENTS.md` | No `.bak` — the write is an additive merge that preserves other `mcpServers` entries | No source-config write; plugin overlay is copied then renamed into place; runtime tree uses installStableTree |
426
+ | Automatic conversation capture | Yes (hooks) | **No** — see [issue #8](https://github.com/amiramm/meko-mcp-server/issues/8) | Yes (native hooks; first SessionStart may pause briefly while creating the Meko conversation) | Yes (hooks) — `SessionStart` / `PreCompact` / `SessionEnd` written to `~/.codex/hooks.json`; the AGENTS.md block provides fallback instructions when hooks are unavailable | Yes — inline CLI 2.x plus standalone CLI 3.x/IDE hooks share Capture v2 | Yes (`session.idle` / `session.error`, Capture v2; error is an observation, not an immediate interrupt) |
427
+ | Automatic memory persistence | Yes (hooks + skill) | Skill only (proactive `memory_add`) | Yes (hooks + skill) | Hooks + skill; AGENTS.md fallback when hooks are unavailable | Hooks + skill; conditional steering fallback when the hook marker is absent | Yes (capture + skill) |
428
+ | Skill install | Plugin marketplace (automatic) | `.skill` bundle auto-built, user drags into app | Copy into `.cursor/skills` | Copy into `~/.agents/skills/meko-mcp-tools/` | Copy into `~/.kiro/skills/` (native Agent Skills format) | Copy into scoped OpenCode `skills/` |
429
+ | Uninstall | Full automatic | MCP entry removed; skill must be removed manually from app | MCP + hooks + skills cleaned up | MCP entry, skill dir, and AGENTS.md block all cleaned up | MCP entry plus installer-owned hooks, managed agent, private env, skills, and steering; pending outbox data is preserved | Owned plugin/runtime/skill removed; env stays watermark-only; snapshots, journals, outboxes, and capture-root quarantine stay; #307-era invalid files stay in meko/snapshots/quarantine |
430
+ | `agent_id` used by skill | `claude_code:<repo>` per project (via SessionStart hook); cross-project facts go to `meko_agent` | `claude_desktop` | `cursor:<repo>` per project (via Cursor hook); cross-project facts go to `meko_agent` | `codex:<repo>` per project (via SessionStart hook); cross-project facts go to `meko_agent` | `kiro:<repo>` per project via hook capture; cross-project facts go to `meko_agent` | `opencode:<repo>` per project, derived at capture from the session directory (the plugin does not inject `agent_id`); cross-project facts go to `meko_agent` |
431
+ | Transport | HTTP only | HTTP (or stdio via hand-edited config) | HTTP only | HTTP (Codex's `bearer_token_env_var` model) | HTTP only | Native remote HTTP MCP |
432
+ | Auth model | inline `Authorization: Bearer ...` header | inline header via `mcp-remote` | inline header | MCP server: env-var name reference (`MEKO_API_KEY` exported in shell or via `launchctl setenv`). Hooks: key written to `~/.codex/meko-env.sh` at mode 0600; each hook command sources the file before bash (no env block in Codex's hooks schema; see [Security](#security)). | inline `Authorization: Bearer ...` header (never `mcp-remote` — see note below) | Authorization header supplied by the plugin from a mode-0600 private env file |
433
+ | Project scope | Yes (`--scope project`) | No | Yes (`--scope project`) | No (warns and degrades to user scope) | Yes (`--scope project`) | Yes (`--scope project`) |
434
+ | Deferred to a follow-up | — | `.mcpb` Desktop Extension packaging — see [issue #7](https://github.com/amiramm/meko-mcp-server/issues/7) | — | — | Tool-call/hidden-reasoning capture (not exposed by Kiro hook events) | Desktop/V2/headless certification; richer capture surfaces |
391
435
 
392
436
  Cursor previously had a hybrid hook mode that also wrote Claude-compatible hooks into `~/.claude/settings.json`. If you used that mode and now see duplicate `claude_code:*` Meko instructions in Cursor, remove the old Meko hook entries from `~/.claude/settings.json` unless you still use them for Claude Code.
393
437
 
@@ -397,7 +441,10 @@ Cursor previously had a hybrid hook mode that also wrote Claude-compatible hooks
397
441
 
398
442
  **Never use the `mcp-remote` bridge with Kiro.** Kiro speaks remote MCP natively, so the installer registers `{ url, headers }` directly.
399
443
 
400
- What is measured, against `https://mcp.mekodata.ai`:
444
+ What was measured against `https://mcp.mekodata.ai` before 2026-09-24. Production
445
+ now accepts loopback redirects on `/register`, `/authorize`, and `/token`; DEV
446
+ (`mcp.mekodev.com`) still refuses them. The `mcp-remote` findings below still
447
+ apply, because an API key behind the bridge is never sent.
401
448
 
402
449
  - `mcp-remote@0.1.38` reads no auth env var (its only `process.env` reference is `MCP_REMOTE_CONFIG_DIR`), so `MEKO_API_KEY` is never sent; headers come only from `--header`. It therefore connects unauthenticated and begins OAuth.
403
450
  - Run directly, it fails at `registerClient` — the DCR POST — with `HTTP 403: Invalid OAuth error response … Raw body: <html>403 Forbidden</html>`. Its source builds `redirect_uri` as `http://${host}:${callbackPort}${callbackPath}`, defaulting to `localhost` and `/oauth/callback`.
@@ -461,6 +508,8 @@ The installer auto-detects cloud vs local based on the URL: any URL containing `
461
508
  - **Kiro (IDE + `kiro-cli`)**
462
509
  - API key header — stored in `~/.kiro/settings/mcp.json` (or `.kiro/settings/mcp.json` for project scope) under `mcpServers.<name>.headers.Authorization`. The adapter forces the file to **mode 0600** on registration and removal rewrites.
463
510
  - Hook runtime — the endpoint and optional API key are also stored in `kiro-hook-env.json` at **mode 0600** so inline and standalone hooks can authenticate without putting the key in their command strings.
511
+ - **OpenCode**
512
+ - The plugin reads the API key from `$OPENCODE_CONFIG_DIR/meko/opencode-hook-env.json` when set, otherwise `~/.config/opencode/meko/opencode-hook-env.json` (user scope), or `.opencode/meko/opencode-hook-env.json` (project scope). The installer writes this file at **mode 0600** and never places the key in process arguments. Sanitized staged snapshots and Capture v2 journal/outbox files are also private; successfully handed-off snapshots are deleted, transient failures remain retryable, and malformed snapshots move to quarantine.
464
513
 
465
514
  **How credentials are protected:**
466
515
 
@@ -505,6 +554,7 @@ Re-running the installer is idempotent but not inert. A re-run:
505
554
  - Rewrites the Cursor skill directory and hooks config if `--client cursor` is targeted.
506
555
  - Auto-updates the skills plugin if it's already installed (via `claude plugin update meko-agent-skills@meko-agent-skills`), otherwise installs it. See "Updating the skills plugin" below.
507
556
  - Rebuilds the Claude Desktop `.skill` bundle if `--client claude-desktop` is targeted. You must re-drag the rebuilt bundle into Claude Desktop to pick up the new skill content.
557
+ - Replaces installer-owned OpenCode plugin/runtime/skill assets if `--client opencode` is targeted; restart OpenCode to load them. User-owned collisions are refused rather than overwritten.
508
558
 
509
559
  ### Updating the skills plugin (Claude Code)
510
560
 
@@ -607,6 +657,21 @@ Logs worth collecting before filing a bug:
607
657
  - **Claude Code MCP log** (macOS) — `ls -lt ~/Library/Caches/claude-cli-nodejs/*/mcp-logs-meko/ 2>/dev/null` — most recent `*.txt` shows the registration attempt and any stderr from the spawned process.
608
658
  - **Current config snippet** — `grep -A 20 '"meko"' ~/.claude.json` — confirms what state Claude Code was in when the install was attempted.
609
659
 
660
+ ### OpenCode is unsupported or does not load Meko
661
+
662
+ OpenCode integration is gated to **1.18.x**. Check the exact binary that the installer sees:
663
+
664
+ ```bash
665
+ which opencode
666
+ opencode --version
667
+ ```
668
+
669
+ If the version is outside 1.18.x, upgrade or install a certified 1.18.x release before rerunning the installer. If the version is supported but installer validation does not report the remote `mcp.<name>` overlay (`mcp.meko` for the default name), confirm the selected scope and `--name`, check for a user-owned collision at the plugin path, rerun the installer, and restart OpenCode. User scope uses `$OPENCODE_CONFIG_DIR/plugins/meko.js` when the variable is set and `~/.config/opencode/plugins/meko.js` otherwise; project scope uses `.opencode/plugins/meko.js`. Do not print or share `opencode debug config`; its resolved headers may contain the API key.
670
+
671
+ For capture failures, run `create-meko-setup --capture-status --json`. The plugin captures only on `session.idle` or `session.error`, so an actively streaming turn is expected to remain pending. Retained staged snapshots indicate a retryable handoff failure and are replayed at startup; files moved to quarantine were invalid and require inspection. Uninstall leaves staged snapshots in the durable capture root. Do not delete Capture v2 journal/outbox data while diagnosing.
672
+
673
+ For migration failures, run `opencode session list --format json` and `opencode export <sessionID>` directly. One malformed export is isolated to that session. A malformed list records an OpenCode source warning while the other migration sources continue; dry-run output prints the warning.
674
+
610
675
  ### Connection refused
611
676
 
612
677
  ```
@@ -660,10 +725,10 @@ Three known causes:
660
725
  - **No `User-Agent` header.** The WAF refuses any request without one. Add
661
726
  `User-Agent: meko-mcp-installer/1.0`. The installer always does; hand-written
662
727
  configs and some native MCP clients don't.
663
- - **An OAuth callback on a loopback address.** The WAF refuses any `redirect_uri`
664
- pointing at an internal host, so dynamic client registration fails for any
665
- client that registers such a callback, including IDEs. Use API-key auth
666
- instead. Tracked in
728
+ - **An OAuth callback on a loopback address (DEV only).** The DEV WAF refuses
729
+ any `redirect_uri` pointing at an internal host, so dynamic client
730
+ registration fails there for any client that registers such a callback,
731
+ including IDEs. Production accepts these callbacks as of 2026-09-24. Tracked in
667
732
  [#277](https://github.com/yugabyte/meko-mcp-server/issues/277).
668
733
  - **Message text that looks like a path.** Capture writes containing `../` or
669
734
  absolute paths can trip a traversal rule. Tracked in
@@ -772,6 +837,8 @@ This reverses installer-managed changes for the selected client:
772
837
 
773
838
  Each step is safe if the component was already removed -- the uninstaller logs a warning and continues.
774
839
 
840
+ For OpenCode, uninstall removes installer-owned plugin, runtime, and skill assets. The private env stays with only `MEKO_WATERMARK_DIR` (API key stripped) so reinstall resumes the same capture root. Staged snapshots, journals, outboxes, and watermarks stay in the durable capture root. Quarantine of snapshots staged there lives next to those files. Invalid files from a leftover `#307` `meko/snapshots` tree stay in `meko/snapshots/quarantine`. Uninstall does not edit `opencode.json` / `opencode.jsonc` or remove user-owned collisions. There is no installer purge command. Do not delete the capture root: it is shared with Claude Code, Cursor, Codex, and Kiro, and also stores datapack pins. Do not delete OpenCode subdirectories on their own: each session also has a `<sessionId>.watermark.json` in that shared root, and it still points at the journal.
841
+
775
842
  ### Claude Desktop: which artifact, and why the UI can't remove it
776
843
 
777
844
  Claude Desktop can be connected to Meko in two different ways, and they are removed differently:
@@ -806,6 +873,7 @@ node installer/bin/create-meko-setup.mjs --uninstall --verbose
806
873
  | M11 | Invoke from repo root | `cd <repo> && node installer/bin/create-meko-setup.mjs --client cursor --local --scope user --dry-run --yes` | Dry-run succeeds; no path-resolution errors |
807
874
  | M12 | Invoke from `installer/` | `cd <repo>/installer && node bin/create-meko-setup.mjs --client cursor --local --scope user --dry-run --yes` | Dry-run succeeds (note: `--scope project` gives different `.cursor/...` paths because project scope uses cwd — pick a fixed cwd or `--scope user` to compare byte-for-byte) |
808
875
  | M13 | Clone-free via npm pack | `cd installer && npm pack` → `npm install -g ./yugabytedb-meko-mcp-*.tgz` → from a directory with **no repo clone**, run `create-meko-setup --client cursor --local --scope project --dry-run` | Succeeds; asset paths resolve under the globally-installed `node_modules/@yugabytedb/meko-mcp/assets/...` |
876
+ | M14 | OpenCode Tier-2 canary | Follow the OpenCode checklist in [`RELEASING.md`](../RELEASING.md#opencode-tier-2-canary) on certified 1.18.x | Packaged user/project install, tools visibility, automatic capture/recovery, migration, and uninstall all pass |
809
877
 
810
878
  ## Development
811
879