@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.
- package/README.md +106 -38
- package/assets/hooks-handlers/lib/capture-cleanup-cli.js +1473 -0
- package/assets/hooks-handlers/lib/capture-notices.js +131 -14
- package/assets/hooks-handlers/lib/capture-state.js +95 -1
- package/assets/hooks-handlers/lib/capture-status-cli.js +6 -2
- package/assets/hooks-handlers/lib/capture.js +1237 -137
- package/assets/hooks-handlers/lib/checkpoint-timer.js +51 -10
- package/assets/hooks-handlers/lib/journal-bridge.js +218 -0
- package/assets/hooks-handlers/lib/kiro-handler.js +26 -4
- package/assets/hooks-handlers/lib/opencode-handler.js +620 -0
- package/assets/hooks-handlers/lib/opencode-normalizer.js +145 -0
- package/assets/hooks-handlers/lib/terminal-handoff.js +10 -1
- package/assets/opencode-plugin/meko.js +213 -0
- package/assets/scripts/meko-statusline.sh +85 -18
- package/assets/skills/meko-mcp-tools/SKILL.md +57 -14
- package/assets/skills/meko-mcp-tools/references/_sections.md +2 -2
- package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +15 -7
- package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +86 -14
- package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +1 -1
- package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +29 -6
- package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +8 -4
- package/assets/skills/meko-mcp-tools/references/tools-overview.md +32 -22
- package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +14 -8
- package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +45 -1
- package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +6 -39
- package/assets/skills/meko-mcp-tools-desktop/SKILL.md +54 -18
- package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +1 -1
- package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +1 -1
- package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +8 -6
- package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +95 -33
- package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +22 -5
- package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +14 -10
- package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +35 -25
- package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +14 -8
- package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +67 -1
- package/assets/skills/meko-select-datapack-desktop/SKILL.md +4 -4
- package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +5 -5
- package/assets/skills/meko-select-datapack-desktop/references/role-display-future.md +7 -5
- package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +4 -4
- package/bin/create-meko-setup.mjs +70 -7
- package/lib/capture-cleanup.mjs +63 -0
- package/lib/clients/claude-code.mjs +1 -0
- package/lib/clients/codex.mjs +80 -35
- package/lib/clients/common.mjs +7 -0
- package/lib/clients/index.mjs +2 -0
- package/lib/clients/kiro.mjs +5 -5
- package/lib/clients/opencode.mjs +532 -0
- package/lib/config.mjs +68 -1
- package/lib/installer.mjs +18 -2
- package/lib/migrate/adapters/claude-code.mjs +11 -2
- package/lib/migrate/adapters/codex.mjs +9 -2
- package/lib/migrate/adapters/memory-md.mjs +27 -8
- package/lib/migrate/adapters/opencode.mjs +148 -0
- package/lib/migrate/claude-parser.mjs +153 -9
- package/lib/migrate/id.mjs +195 -13
- package/lib/migrate/mcp-client.mjs +25 -1
- package/lib/migrate/opencode-normalizer.mjs +132 -0
- package/lib/migrate/orchestrator.mjs +293 -77
- package/lib/migrate/progress.mjs +239 -5
- package/lib/migrate/registry.mjs +72 -0
- package/lib/migrate.mjs +96 -8
- package/package.json +1 -1
- package/scripts/bundle-assets.mjs +4 -0
|
@@ -7,7 +7,7 @@ These patterns are extracted from real agent sessions. Follow them to avoid wast
|
|
|
7
7
|
1. **Never retry the identical failed call more than once.** If it fails twice with the same error, it's not transient — diagnose the cause.
|
|
8
8
|
2. **Distinguish transient vs persistent failures.** "Connection already closed" is transient (retry once). "Permission denied" is persistent (stop, don't retry).
|
|
9
9
|
3. **Don't guess parameters sequentially.** If a tool fails with one parameter format, don't try 4 variations. Check this skill's docs for the correct format first.
|
|
10
|
-
4. **Use your session's `agent_id` consistently on writes.** For Claude Desktop the default is `claude_desktop`; use `meko_agent` when writing cross-project facts. Other clients use `<client>:<repo-basename>` (e.g. `claude_code:meko-mcp-server`). Memory reads and `conversation_list` span all of this user's agents regardless of the value passed; `conversation_get`
|
|
10
|
+
4. **Use your session's `agent_id` consistently on writes.** For Claude Desktop the default is `claude_desktop`; use `meko_agent` when writing cross-project facts. Other clients use `<client>:<repo-basename>` (e.g. `claude_code:meko-mcp-server`). Memory reads and `conversation_list` span all of this user's agents regardless of the value passed; the conversation calls (`conversation_get`, `conversation_add_message`, `conversation_update`, `conversation_delete`) require the creating agent's exact value.
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -26,6 +26,72 @@ These patterns are extracted from real agent sessions. Follow them to avoid wast
|
|
|
26
26
|
|
|
27
27
|
---
|
|
28
28
|
|
|
29
|
+
## Connection errors: `[Errno 111] Connection refused`
|
|
30
|
+
|
|
31
|
+
**Affects:** any tool, intermittently. Reports show `memory_add`, `conversation_create`, `memory_search`, and `context_search` failing this way while identical calls succeed minutes later.
|
|
32
|
+
|
|
33
|
+
**What it means:** the request reached no listening server, usually a server instance that was restarting or scaling. It is not a timeout and not a rejected argument.
|
|
34
|
+
|
|
35
|
+
**What to do:** wait a few seconds and retry once. Retry `conversation_add_message` only with a `seed`, and never retry `conversation_create` (see the table below). If the retry also fails, report the failure. For a write, tell the user it was not saved; don't let a failed write pass silently.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## `memory_search` hangs or times out
|
|
40
|
+
|
|
41
|
+
`memory_search` can stall for minutes under backend load while other tools respond. Don't raise the client timeout; that only makes the stall longer. Retry once. If it stalls again, report that the search failed, and if the user needs an answer now, try `context_search` or `memory_get_by_id` for a known id. `memory_get_all` only returns a recent window, so it can't replace a search.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Quota errors that look like auth errors
|
|
46
|
+
|
|
47
|
+
`free_tier_limit_reached` can arrive with HTTP 403, and automatic capture that hits a cap shows up as capture failing with 403. Read the error code, not the status. A quota error means the account reached a lifetime cap (see `tools-known-limitations.md`). Don't rotate keys or reinstall. Tell the user which tool hit the cap and that upgrading the plan lifts it.
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Datapack and ownership errors
|
|
52
|
+
|
|
53
|
+
| Error | Meaning | What to do |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| `datapack_access_denied` | The `datapack_id` isn't a UUID, or it isn't owned by or shared with your account. The access check also fails closed on a transient server database error. | Retry once. If it repeats, stop; don't switch to another datapack. If the id came from a pin, ask the user to re-pin with the select-datapack skill. |
|
|
56
|
+
| `datapack_id_required` | The call couldn't resolve a datapack. Conversation reads and writes (including `conversation_list`), `datapack_describe`, and `knowledgebase_delete_document` return it. | Pass the pinned `datapack_id`. Don't drop the parameter to make the call pass. |
|
|
57
|
+
| `not_found` from `memory_get_by_id`, `memory_update`, or `memory_delete_by_id` | The memory doesn't exist **or** belongs to another account. The server returns the same error for both on purpose. | Check the id came from a search in this datapack. |
|
|
58
|
+
| `memory_is_promoted` | The memory was promoted to shared knowledge and is read-only through MCP. | Point the user at the Cloud UI Learnings tab. |
|
|
59
|
+
| `invalid_run_id` | `memory_delete_all` got a `run_id` that isn't a conversation id. | Pass the conversation UUID, or omit `run_id`. |
|
|
60
|
+
| `embedder_error` from `knowledgebase_search` | The server couldn't resolve the embedding setup for this datapack's index. | Report it; retrying won't help. |
|
|
61
|
+
| `invalid_force_source` from `context_search` | `force_source` isn't `auto`, `memory`, `knowledge_base`, or `conversation`. | Omit `force_source`. |
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## Conversation writes fail right after `conversation_create`
|
|
66
|
+
|
|
67
|
+
`conversation_add_message` has intermittently returned `not_found`, or `agent_id_mismatch` naming agent `'None'`, seconds after `conversation_create` returned that id. It shows up most with several parallel subagents writing to one conversation. Retry once with the same `seed` after a few seconds. If it still fails, don't create a new conversation for the same work: save the durable findings with `memory_add` and tell the user the transcript is incomplete.
|
|
68
|
+
|
|
69
|
+
On a long conversation that has worked before, `not_found` can instead mean the trace grew too large to load. See `tools-known-limitations.md`.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## "No Meko account found for cognito identity ..." on every call
|
|
74
|
+
|
|
75
|
+
Every Meko tool fails with this error while the connection itself looks fine. Two users hit it for the same reason: Claude Desktop had both the Meko URL connector (Settings > Connectors, which signs in through the browser) and the API-key install from `npx @yugabytedb/meko-mcp --client claude-desktop`, and Desktop used the connector's identity. The word "provisioned" in the error points at a backend account problem, but the fix is on the client:
|
|
76
|
+
|
|
77
|
+
1. Ask the user for the full list under Settings > Connectors, not just `claude_desktop_config.json`.
|
|
78
|
+
2. Have them remove the Meko URL connector and keep only the API-key install. Use the full API key from the downloaded file.
|
|
79
|
+
3. Quit Claude Desktop completely (Cmd+Q) and reopen it.
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## "Server disconnected" with `SyntaxError ... node:fs/promises ... 'constants'`
|
|
84
|
+
|
|
85
|
+
The MCP bridge started under an old Node.js version. `npx` picked up a Node older than 20 from the user's `PATH` (often through `nvm`). Have the user make Node 20 or later the default, for example `nvm alias default 20`, then fully quit and reopen Claude Desktop. Current installer releases declare Node 20.18.1 or later as their minimum.
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## You can't run a delete the user asked for
|
|
90
|
+
|
|
91
|
+
Some Claude Desktop deployments refuse Meko delete tools (`memory_delete_by_id`, `memory_delete_all`, `conversation_delete`, `knowledgebase_delete_document`) by policy, even when the datapack owner asks. If that applies to you, say so plainly. Give the user the exact ids with a one-line summary of each and the tool call to run from a client that allows deletes, such as Claude Code. Don't report anything as deleted.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
29
95
|
## agent_id errors
|
|
30
96
|
|
|
31
97
|
On the Cloud multi-tenant schema, `agent_id` is a TEXT column value — not a PostgreSQL identifier — so arbitrary strings are accepted.
|
|
@@ -11,7 +11,7 @@ description: >-
|
|
|
11
11
|
license: MIT
|
|
12
12
|
metadata:
|
|
13
13
|
author: Meko
|
|
14
|
-
version: "1.2.
|
|
14
|
+
version: "1.2.2"
|
|
15
15
|
tags: meko, datapack, selection, project, claude-desktop, desktop
|
|
16
16
|
---
|
|
17
17
|
|
|
@@ -28,7 +28,7 @@ text: "meko_active_datapack=<uuid> name=<name> selected_at=<iso8601>"
|
|
|
28
28
|
metadata: { "type": "active-datapack-pin" }
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
You discover it by calling `memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)` at the start of any turn that's about to make a Meko MCP write. If you find a pin, pass `datapack_id="<uuid>"` to every Meko call that accepts it. If you don't find one, fall back to the server default (omit the parameter).
|
|
31
|
+
You discover it by calling `memory_search(query="meko_active_datapack", agent_id="claude_desktop", conversation_id="<this conversation's id>", limit=1)` (`conversation_id` is required and must be a 32-hex id; before `conversation_create`, pass a freshly generated one, never `""`) at the start of any turn that's about to make a Meko MCP write. If you find a pin, pass `datapack_id="<uuid>"` to every Meko call that accepts it. If you don't find one, fall back to the server default (omit the parameter).
|
|
32
32
|
|
|
33
33
|
## When to invoke this skill
|
|
34
34
|
|
|
@@ -85,7 +85,7 @@ the Role column. Do not hardcode "Owner", do not invent or normalize the value
|
|
|
85
85
|
response is the source of truth — see `references/role-display-future.md` for
|
|
86
86
|
the taxonomy.
|
|
87
87
|
|
|
88
|
-
If the response has zero entries, tell the user: *"You don't have any datapacks yet. Run `datapack_create(name='<name>')` to make one, or visit the Meko Cloud console."* Stop here.
|
|
88
|
+
If the response has zero entries, tell the user: *"You don't have any datapacks yet. Run `datapack_create(name='<name>', conversation_id='<conversation id>')` to make one, or visit the Meko Cloud console."* Stop here.
|
|
89
89
|
|
|
90
90
|
If the response has exactly **one** entry, **auto-select it**. Print: *"Only one datapack: `<name>`. Auto-selecting. Run `meko-select-datapack-desktop` again with `clear` to unset."* Skip the table; jump to step 4 (persist) and step 5 (confirm).
|
|
91
91
|
|
|
@@ -192,7 +192,7 @@ would split capture across the old and new datapacks or fail outright.
|
|
|
192
192
|
## Edge cases
|
|
193
193
|
|
|
194
194
|
- **Multiple pin memories somehow exist** — the user (or a buggy earlier run) created duplicates. Use the most recent (highest `selected_at`); offer to delete the others.
|
|
195
|
-
- **The pinned datapack no longer exists
|
|
195
|
+
- **The pinned datapack no longer exists or was unshared** — the next Meko MCP call that passes it fails with `datapack_access_denied`. Re-run the skill to pick a new one or `clear` the stale pin.
|
|
196
196
|
- **memory_search times out or fails** — fall back to the server default (omit `datapack_id`) and tell the user *"Couldn't read the active-datapack pin. Using server default for this call."* Don't guess a UUID.
|
|
197
197
|
- **User explicitly overrides for a single call** — pass the user's `datapack_id` for that one call. Do NOT update the pin memory.
|
|
198
198
|
|
|
@@ -8,7 +8,7 @@ Concrete transcripts of the four flows the skill supports on Claude Desktop.
|
|
|
8
8
|
|
|
9
9
|
**Skill:**
|
|
10
10
|
```
|
|
11
|
-
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)
|
|
11
|
+
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", conversation_id="<conv-id>", limit=1)
|
|
12
12
|
[empty]
|
|
13
13
|
|
|
14
14
|
> datapack_list(conversation_id="<conv-id>")
|
|
@@ -23,7 +23,7 @@ One match: `prod-research`. Pinning.
|
|
|
23
23
|
metadata='{"type":"active-datapack-pin"}')
|
|
24
24
|
[returns id=mem_abc123]
|
|
25
25
|
|
|
26
|
-
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)
|
|
26
|
+
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", conversation_id="<conv-id>", limit=1)
|
|
27
27
|
[verifies the row exists]
|
|
28
28
|
|
|
29
29
|
Pinned datapack `prod-research` (`8b1c…f4a2`) for Claude Desktop.
|
|
@@ -41,7 +41,7 @@ datapack_id flows through automatically.
|
|
|
41
41
|
|
|
42
42
|
**Skill:**
|
|
43
43
|
```
|
|
44
|
-
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)
|
|
44
|
+
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", conversation_id="<conv-id>", limit=1)
|
|
45
45
|
[returns id=mem_abc123, text="meko_active_datapack=8b1c…f4a2 name=prod-research …"]
|
|
46
46
|
|
|
47
47
|
> datapack_list(conversation_id="<conv-id>")
|
|
@@ -66,7 +66,7 @@ The `memory_update` is critical here — using `memory_add` again would create a
|
|
|
66
66
|
|
|
67
67
|
**Skill:**
|
|
68
68
|
```
|
|
69
|
-
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)
|
|
69
|
+
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", conversation_id="<conv-id>", limit=1)
|
|
70
70
|
[empty]
|
|
71
71
|
|
|
72
72
|
> datapack_list(conversation_id="<conv-id>")
|
|
@@ -90,7 +90,7 @@ Pinned datapack `meko-local-setup` (`a17d…cc91`). Run this skill again with
|
|
|
90
90
|
|
|
91
91
|
**Skill:**
|
|
92
92
|
```
|
|
93
|
-
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)
|
|
93
|
+
> memory_search(query="meko_active_datapack", agent_id="claude_desktop", conversation_id="<conv-id>", limit=1)
|
|
94
94
|
[returns id=mem_abc123]
|
|
95
95
|
|
|
96
96
|
> memory_delete_by_id(
|
|
@@ -24,13 +24,15 @@ Note that the upstream Go source (the `Datapack` struct in `api_server/internal/
|
|
|
24
24
|
|
|
25
25
|
## Other fields the live response includes
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
`datapack_list` doesn't compute counts; its list response carries no count fields. If the user asks for counts, call `datapack_describe(datapack_id=<id>, conversation_id="<conversation id>")` and read them from that response:
|
|
28
28
|
|
|
29
|
-
- `memory_count
|
|
30
|
-
- `
|
|
31
|
-
- `learnings_count
|
|
29
|
+
- `memory_count`: all memories stored in the datapack.
|
|
30
|
+
- `collective_memory_count`: memories promoted to shared knowledge.
|
|
31
|
+
- `learnings_count`: memories awaiting a promotion decision.
|
|
32
|
+
- `knowledge_base_file_count`: uploaded KB documents (`null` if the status endpoint is unreachable).
|
|
33
|
+
- `knowledge_chunk_count`: KB chunks across all documents. `knowledge_count` is a deprecated alias.
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
Don't add counts to the table silently, and never invent the numbers.
|
|
34
36
|
|
|
35
37
|
## Sharing UI vs API state
|
|
36
38
|
|
|
@@ -18,12 +18,12 @@ You (or an earlier run) created duplicates by using `memory_add` instead of `mem
|
|
|
18
18
|
|
|
19
19
|
The cookbook's Flow 2 demonstrates the correct switch path.
|
|
20
20
|
|
|
21
|
-
## Symptom: A pinned datapack returns
|
|
21
|
+
## Symptom: A pinned datapack returns `datapack_access_denied` when used
|
|
22
22
|
|
|
23
|
-
The pin became stale
|
|
23
|
+
The pin became stale: the datapack was deleted, or its share to you was revoked, in another client. The server checks ownership and shares on every call that passes a `datapack_id`, so the call fails with `datapack_access_denied` (older servers returned a not-found error). The check also fails closed on a transient server database error, so retry the call once before treating the pin as stale. Tell the user:
|
|
24
24
|
|
|
25
25
|
```
|
|
26
|
-
The pinned datapack `<name>` (`<id>`) no longer exists
|
|
26
|
+
The pinned datapack `<name>` (`<id>`) no longer exists or is no longer shared with you.
|
|
27
27
|
Run `meko-select-datapack-desktop` to pick a fresh one, or `clear` to unpin.
|
|
28
28
|
```
|
|
29
29
|
|
|
@@ -40,7 +40,7 @@ The user has zero datapacks. Print:
|
|
|
40
40
|
```
|
|
41
41
|
You don't have any datapacks yet. Create one with:
|
|
42
42
|
|
|
43
|
-
datapack_create(name="<your-datapack-name>")
|
|
43
|
+
datapack_create(name="<your-datapack-name>", conversation_id="<conversation id>")
|
|
44
44
|
|
|
45
45
|
Or visit the Meko Cloud console (Datapacks → New datapack).
|
|
46
46
|
```
|
|
@@ -19,6 +19,7 @@ import { parseClientList } from '../lib/clients/aliases.mjs';
|
|
|
19
19
|
import { startMigration, runChildMigration, readStatus, stopMigration } from '../lib/migrate.mjs';
|
|
20
20
|
import { checkLatest } from '../lib/version-check.mjs';
|
|
21
21
|
import { runCaptureStatus } from '../lib/capture-status.mjs';
|
|
22
|
+
import { captureCleanupArgs, runCaptureCleanup } from '../lib/capture-cleanup.mjs';
|
|
22
23
|
|
|
23
24
|
// ---------------------------------------------------------------------------
|
|
24
25
|
// Flag definitions
|
|
@@ -48,6 +49,11 @@ const options = {
|
|
|
48
49
|
// --- Capture health (Capture V2 Workstream D) ---
|
|
49
50
|
'capture-status': { type: 'boolean', default: false },
|
|
50
51
|
json: { type: 'boolean', default: false },
|
|
52
|
+
'capture-cleanup': { type: 'string' },
|
|
53
|
+
session: { type: 'string', multiple: true },
|
|
54
|
+
all: { type: 'boolean', default: false },
|
|
55
|
+
'max-exchanges': { type: 'string' },
|
|
56
|
+
'pace-ms': { type: 'string' },
|
|
51
57
|
|
|
52
58
|
// --- Migrate subcommand ---
|
|
53
59
|
migrate: { type: 'boolean', default: false },
|
|
@@ -75,11 +81,11 @@ function readVersion() {
|
|
|
75
81
|
return pkg.version;
|
|
76
82
|
}
|
|
77
83
|
|
|
78
|
-
const ALL_CLIENTS = ['claude-code', 'claude-desktop', 'cursor', 'codex', 'kiro'];
|
|
84
|
+
const ALL_CLIENTS = ['claude-code', 'claude-desktop', 'cursor', 'codex', 'kiro', 'opencode'];
|
|
79
85
|
|
|
80
86
|
function printHelp() {
|
|
81
87
|
const text = `
|
|
82
|
-
Meko Setup for Claude Code, Claude Desktop, Cursor, Codex, and
|
|
88
|
+
Meko Setup for Claude Code, Claude Desktop, Cursor, Codex, Kiro, and OpenCode
|
|
83
89
|
|
|
84
90
|
Install and configure Meko MCP Server in one command.
|
|
85
91
|
|
|
@@ -108,11 +114,13 @@ Examples:
|
|
|
108
114
|
# Install for Kiro (IDE and kiro-cli share the same config):
|
|
109
115
|
create-meko-setup --client kiro --yes
|
|
110
116
|
|
|
117
|
+
create-meko-setup --client opencode --scope user --yes
|
|
118
|
+
|
|
111
119
|
# Local Meko (docker-compose stack, Claude Code):
|
|
112
120
|
create-meko-setup --local --yes
|
|
113
121
|
|
|
114
122
|
Options:
|
|
115
|
-
--client <list> Target clients: one or more of claude-code, claude-desktop, cursor, codex, kiro.
|
|
123
|
+
--client <list> Target clients: one or more of claude-code, claude-desktop, cursor, codex, kiro, opencode.
|
|
116
124
|
"claude" is accepted as an alias for claude-code;
|
|
117
125
|
"kiro-cli" and "kiro-ide" for kiro.
|
|
118
126
|
Comma-separated, or "all" to target every supported client (default: claude-code)
|
|
@@ -153,7 +161,27 @@ Capture health (durable outbox / recovery):
|
|
|
153
161
|
Exit 0 = healthy|catching_up, 2 = degraded_retrying,
|
|
154
162
|
3 = blocked_action_required.
|
|
155
163
|
--json With --capture-status, print machine-readable JSON
|
|
156
|
-
matching the capture-health cache shape.
|
|
164
|
+
matching the capture-health cache shape. Also
|
|
165
|
+
accepted by --capture-cleanup.
|
|
166
|
+
--capture-cleanup <action>
|
|
167
|
+
Clean up stuck capture on this machine:
|
|
168
|
+
status list sessions with unsent work and the
|
|
169
|
+
background capture processes (read-only)
|
|
170
|
+
stop stop SessionEnd workers and in-flight
|
|
171
|
+
drains, and park all unsent work so no
|
|
172
|
+
hook retries it (nothing is deleted)
|
|
173
|
+
resume unpark and hand back to the hooks
|
|
174
|
+
drain send now, one session at a time; stops
|
|
175
|
+
and re-parks at the first failure
|
|
176
|
+
discard skip a session's unsent exchanges for
|
|
177
|
+
good (needs --yes)
|
|
178
|
+
repair clear stale failure fields and leftover
|
|
179
|
+
PID, lease, and job files
|
|
180
|
+
Options: --session <id> or a bare session ID
|
|
181
|
+
(repeatable, prefix ok),
|
|
182
|
+
--all, --dry-run, --json, --yes,
|
|
183
|
+
--max-exchanges N (drain, default 200),
|
|
184
|
+
--pace-ms N (drain, default 1000).
|
|
157
185
|
|
|
158
186
|
Migrate existing conversations and memories into Meko:
|
|
159
187
|
--migrate Start a detached migration of existing Claude Code
|
|
@@ -272,7 +300,22 @@ function parseRate(raw) {
|
|
|
272
300
|
// ---------------------------------------------------------------------------
|
|
273
301
|
|
|
274
302
|
async function main() {
|
|
275
|
-
const { values: flags } = parseArgs({
|
|
303
|
+
const { values: flags, positionals } = parseArgs({
|
|
304
|
+
options,
|
|
305
|
+
strict: true,
|
|
306
|
+
allowPositionals: true,
|
|
307
|
+
});
|
|
308
|
+
// Only --capture-cleanup takes bare arguments: session IDs, so
|
|
309
|
+
// `--capture-cleanup drain c0acdeb2` works like `--session c0acdeb2`.
|
|
310
|
+
if (positionals.length > 0) {
|
|
311
|
+
if (flags['capture-cleanup'] === undefined) {
|
|
312
|
+
error(
|
|
313
|
+
`Unexpected argument '${positionals[0]}'. This command does not take positional arguments`,
|
|
314
|
+
);
|
|
315
|
+
process.exit(1);
|
|
316
|
+
}
|
|
317
|
+
flags.session = [...(flags.session || []), ...positionals];
|
|
318
|
+
}
|
|
276
319
|
const projectRoot = process.cwd();
|
|
277
320
|
|
|
278
321
|
// --help
|
|
@@ -297,8 +340,17 @@ async function main() {
|
|
|
297
340
|
if (out.stderr) process.stderr.write(out.stderr);
|
|
298
341
|
process.exit(out.code);
|
|
299
342
|
}
|
|
343
|
+
// --capture-cleanup <action>: inspect, stop, park, drain, or discard
|
|
344
|
+
// stuck capture sessions. Exit codes: 0 done, 1 error, 2 partly done.
|
|
345
|
+
if (flags['capture-cleanup'] !== undefined) {
|
|
346
|
+
const out = runCaptureCleanup(
|
|
347
|
+
captureCleanupArgs(flags['capture-cleanup'], flags),
|
|
348
|
+
);
|
|
349
|
+
if (out.error) error(out.error);
|
|
350
|
+
process.exit(out.code);
|
|
351
|
+
}
|
|
300
352
|
if (flags.json) {
|
|
301
|
-
error('--json requires --capture-status');
|
|
353
|
+
error('--json requires --capture-status or --capture-cleanup');
|
|
302
354
|
process.exit(1);
|
|
303
355
|
}
|
|
304
356
|
|
|
@@ -478,6 +530,7 @@ async function main() {
|
|
|
478
530
|
cursor: 'Cursor',
|
|
479
531
|
codex: 'OpenAI Codex (CLI + App)',
|
|
480
532
|
kiro: 'Kiro (IDE + kiro-cli)',
|
|
533
|
+
opencode: 'OpenCode CLI/TUI',
|
|
481
534
|
}[id];
|
|
482
535
|
return {
|
|
483
536
|
label: id,
|
|
@@ -760,15 +813,23 @@ async function maybeOfferMigration({ url, apiKey, scope, projectRoot, datapack }
|
|
|
760
813
|
dryRun: true,
|
|
761
814
|
datapack: datapack ?? null,
|
|
762
815
|
});
|
|
816
|
+
if (dry && dry.ok === false) {
|
|
817
|
+
dim(`Skipped migration offer: ${dry.message || "dry run failed"}`);
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
763
820
|
const s = dry?.message?.match(/Claude Code sessions: *(\d+)/);
|
|
764
821
|
const c = dry?.message?.match(/Cursor sessions: *(\d+)/);
|
|
822
|
+
const x = dry?.message?.match(/Codex sessions: *(\d+)/);
|
|
823
|
+
const o = dry?.message?.match(/OpenCode sessions: *(\d+)/);
|
|
765
824
|
const m = dry?.message?.match(/Memory items \(MD\): *(\d+)/);
|
|
766
825
|
const counts = {
|
|
767
826
|
claude: s ? Number(s[1]) : 0,
|
|
768
827
|
cursor: c ? Number(c[1]) : 0,
|
|
828
|
+
codex: x ? Number(x[1]) : 0,
|
|
829
|
+
opencode: o ? Number(o[1]) : 0,
|
|
769
830
|
memory: m ? Number(m[1]) : 0,
|
|
770
831
|
};
|
|
771
|
-
const total = counts.claude + counts.cursor + counts.memory;
|
|
832
|
+
const total = counts.claude + counts.cursor + counts.codex + counts.opencode + counts.memory;
|
|
772
833
|
if (total === 0) return;
|
|
773
834
|
|
|
774
835
|
console.log('');
|
|
@@ -776,6 +837,8 @@ async function maybeOfferMigration({ url, apiKey, scope, projectRoot, datapack }
|
|
|
776
837
|
`Found existing data to migrate: ` +
|
|
777
838
|
`${counts.claude} Claude Code sessions, ` +
|
|
778
839
|
`${counts.cursor} Cursor sessions, ` +
|
|
840
|
+
`${counts.codex} Codex sessions, ` +
|
|
841
|
+
`${counts.opencode} OpenCode sessions, ` +
|
|
779
842
|
`${counts.memory} memory items.`,
|
|
780
843
|
);
|
|
781
844
|
const proceed = await askYesNo(
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* capture-cleanup.mjs: installer helper that invokes capture-cleanup-cli.js.
|
|
3
|
+
*
|
|
4
|
+
* Resolves the CLI the same way capture-status.mjs does, so a published
|
|
5
|
+
* package runs the bundled copy next to the capture.js it drains with.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { spawnSync } from "node:child_process";
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { dirname, join } from "node:path";
|
|
11
|
+
|
|
12
|
+
import { resolveCaptureStatusCli } from "./capture-status.mjs";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Absolute path to capture-cleanup-cli.js under the active asset root.
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
export function resolveCaptureCleanupCli() {
|
|
19
|
+
return join(dirname(resolveCaptureStatusCli()), "capture-cleanup-cli.js");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Build the CLI argument list from parsed installer flags.
|
|
24
|
+
*
|
|
25
|
+
* @param {string} action
|
|
26
|
+
* @param {{ session?: string[], all?: boolean, 'dry-run'?: boolean,
|
|
27
|
+
* json?: boolean, yes?: boolean, 'max-exchanges'?: string,
|
|
28
|
+
* 'pace-ms'?: string }} flags
|
|
29
|
+
* @returns {string[]}
|
|
30
|
+
*/
|
|
31
|
+
export function captureCleanupArgs(action, flags = {}) {
|
|
32
|
+
const args = [action];
|
|
33
|
+
for (const id of flags.session || []) args.push("--session", id);
|
|
34
|
+
if (flags.all) args.push("--all");
|
|
35
|
+
if (flags["dry-run"]) args.push("--dry-run");
|
|
36
|
+
if (flags.json) args.push("--json");
|
|
37
|
+
if (flags.yes) args.push("--yes");
|
|
38
|
+
if (flags["max-exchanges"] != null) args.push("--max-exchanges", String(flags["max-exchanges"]));
|
|
39
|
+
if (flags["pace-ms"] != null) args.push("--pace-ms", String(flags["pace-ms"]));
|
|
40
|
+
return args;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Run the capture-cleanup CLI with inherited stdio (drain prints progress)
|
|
45
|
+
* and return its exit code.
|
|
46
|
+
*
|
|
47
|
+
* @param {string[]} args
|
|
48
|
+
* @param {{ env?: NodeJS.ProcessEnv }} [opts]
|
|
49
|
+
* @returns {{ code: number, cliPath: string, error?: string }}
|
|
50
|
+
*/
|
|
51
|
+
export function runCaptureCleanup(args, opts = {}) {
|
|
52
|
+
const cliPath = resolveCaptureCleanupCli();
|
|
53
|
+
if (!existsSync(cliPath)) {
|
|
54
|
+
return { code: 1, cliPath, error: `capture-cleanup CLI not found at ${cliPath}` };
|
|
55
|
+
}
|
|
56
|
+
const result = spawnSync(process.execPath, [cliPath, ...args], {
|
|
57
|
+
stdio: "inherit",
|
|
58
|
+
env: opts.env ? { ...process.env, ...opts.env } : process.env,
|
|
59
|
+
});
|
|
60
|
+
const code =
|
|
61
|
+
typeof result.status === "number" && result.status >= 0 ? result.status : 1;
|
|
62
|
+
return { code, cliPath };
|
|
63
|
+
}
|
|
@@ -65,6 +65,7 @@ const MEKO_MARKETPLACE_NAME = "meko-agent-skills";
|
|
|
65
65
|
const MEKO_ALWAYS_AVAILABLE_TOOLS = [
|
|
66
66
|
"mcp__meko__memory_add",
|
|
67
67
|
"mcp__meko__memory_search",
|
|
68
|
+
"mcp__meko__context_search",
|
|
68
69
|
"mcp__meko__memory_get_all",
|
|
69
70
|
"mcp__meko__memory_get_by_id",
|
|
70
71
|
"mcp__meko__memory_update",
|
package/lib/clients/codex.mjs
CHANGED
|
@@ -254,7 +254,7 @@ export function createCodexAdapter(options = {}) {
|
|
|
254
254
|
const next = removeCodexConfigBlock(raw, name);
|
|
255
255
|
if (next !== raw) writeWithBackup(path, next);
|
|
256
256
|
},
|
|
257
|
-
async registerServer({ name, url, apiKey, dryRun, verbose, log, scope
|
|
257
|
+
async registerServer({ name, url, apiKey, dryRun, verbose, log, scope }) {
|
|
258
258
|
const path = settingsPathFor(scope, log);
|
|
259
259
|
const useApiKey = apiKey ? "MEKO_API_KEY" : null;
|
|
260
260
|
const cliCmd = buildCliRegisterCommand(name, url, useApiKey);
|
|
@@ -353,35 +353,6 @@ export function createCodexAdapter(options = {}) {
|
|
|
353
353
|
// Cloud auth UX: env-var-only model. The key is never written to
|
|
354
354
|
// config.toml; the user's runtime env supplies it. Print actionable
|
|
355
355
|
// instructions and (when interactive) offer to wire things up.
|
|
356
|
-
if (apiKey) {
|
|
357
|
-
const platform = surfaces.app?.platform ?? process.platform;
|
|
358
|
-
const hasApp = Boolean(surfaces.app);
|
|
359
|
-
const shellRc = detectShellRc();
|
|
360
|
-
printCloudAuthInstructions({ shellRc, hasApp, platform, log });
|
|
361
|
-
if (!yes) {
|
|
362
|
-
await maybeOfferRcAppend({
|
|
363
|
-
apiKey,
|
|
364
|
-
shellRc,
|
|
365
|
-
promptUser,
|
|
366
|
-
log,
|
|
367
|
-
});
|
|
368
|
-
if (hasApp && platform === "darwin") {
|
|
369
|
-
await maybeOfferLaunchctlSetenv({
|
|
370
|
-
apiKey,
|
|
371
|
-
promptUser,
|
|
372
|
-
runCommand,
|
|
373
|
-
log,
|
|
374
|
-
});
|
|
375
|
-
}
|
|
376
|
-
} else if (hasApp && platform === "darwin") {
|
|
377
|
-
setLaunchctlMekoApiKey({
|
|
378
|
-
apiKey,
|
|
379
|
-
runCommand,
|
|
380
|
-
log,
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
|
|
385
356
|
if (surfaces.app) {
|
|
386
357
|
log.dim?.(" Restart Codex.app to attach the new MCP server.");
|
|
387
358
|
}
|
|
@@ -427,6 +398,61 @@ export function createCodexAdapter(options = {}) {
|
|
|
427
398
|
);
|
|
428
399
|
}
|
|
429
400
|
},
|
|
401
|
+
/**
|
|
402
|
+
* Cloud auth UX: env-var-only model. The key is never written to
|
|
403
|
+
* config.toml, so the user's runtime env must supply it. This is a
|
|
404
|
+
* separate adapter step (not part of registerServer) because an
|
|
405
|
+
* interactive reinstall where the user declines the overwrite prompt
|
|
406
|
+
* skips registration entirely - and the launchd env would otherwise
|
|
407
|
+
* never be refreshed after a key rotation. See
|
|
408
|
+
* yugabyte/meko-mcp-server#337.
|
|
409
|
+
*/
|
|
410
|
+
async syncCloudAuthEnvironment({ apiKey, dryRun, log, yes }) {
|
|
411
|
+
if (!apiKey || dryRun) return;
|
|
412
|
+
const platform = surfaces.app?.platform ?? process.platform;
|
|
413
|
+
const hasApp = Boolean(surfaces.app);
|
|
414
|
+
const shellRc = detectShellRc();
|
|
415
|
+
printCloudAuthInstructions({ shellRc, hasApp, platform, log });
|
|
416
|
+
if (!yes) {
|
|
417
|
+
// Offer launchctl BEFORE rc-append, and isolate the rc-append
|
|
418
|
+
// failure mode. `maybeOfferRcAppend` throws when the shell rc is
|
|
419
|
+
// fish and the API key contains a `'` (fish single-quoting can't
|
|
420
|
+
// escape it). If that threw first, the launchctl offer - the
|
|
421
|
+
// yugabyte/meko-mcp-server#337 fix - would never run.
|
|
422
|
+
//
|
|
423
|
+
// macOS: offer launchctl setenv regardless of whether Codex.app
|
|
424
|
+
// is present. Spotlight- and Alfred-launched Codex CLI reads the
|
|
425
|
+
// launchd env too. Login-session inheritance means every
|
|
426
|
+
// GUI-launched process in this session then sees MEKO_API_KEY
|
|
427
|
+
// (visible via `launchctl getenv`, `ps e` on descendants,
|
|
428
|
+
// crash reports); the prompt copy calls that out so the choice
|
|
429
|
+
// is informed.
|
|
430
|
+
if (platform === "darwin") {
|
|
431
|
+
await maybeOfferLaunchctlSetenv({
|
|
432
|
+
apiKey,
|
|
433
|
+
promptUser,
|
|
434
|
+
runCommand,
|
|
435
|
+
log,
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
try {
|
|
439
|
+
await maybeOfferRcAppend({
|
|
440
|
+
apiKey,
|
|
441
|
+
shellRc,
|
|
442
|
+
promptUser,
|
|
443
|
+
log,
|
|
444
|
+
});
|
|
445
|
+
} catch (err) {
|
|
446
|
+
log?.warn?.(` Skipping shell rc append: ${err.message}`);
|
|
447
|
+
}
|
|
448
|
+
} else if (platform === "darwin") {
|
|
449
|
+
setLaunchctlMekoApiKey({
|
|
450
|
+
apiKey,
|
|
451
|
+
runCommand,
|
|
452
|
+
log,
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
},
|
|
430
456
|
installSkills({ dryRun, log, scope, name }) {
|
|
431
457
|
void scope; // Codex skills are user-scope only.
|
|
432
458
|
const serverName = name ?? "meko";
|
|
@@ -1317,7 +1343,7 @@ function renderAgentsMdBlock(version, name) {
|
|
|
1317
1343
|
`${AGENTS_MD_START} v${version}`,
|
|
1318
1344
|
"## Meko memory (auto-managed by meko installer)",
|
|
1319
1345
|
"",
|
|
1320
|
-
`You have a persistent memory store via the \`${name}\` MCP server. At the start of every conversation, call \`${toolPrefix}
|
|
1346
|
+
`You have a persistent memory store via the \`${name}\` MCP server. At the start of every conversation, call \`${toolPrefix}context_search\` for relevant context: it returns personal memory, shared datapack knowledge, and past conversations in one call. Use \`${toolPrefix}memory_search\` or \`${toolPrefix}knowledgebase_search\` when you need a single source. When the user shares facts, preferences, or decisions worth remembering, call \`${toolPrefix}memory_add\`. Skill details: ~/.agents/skills/meko-mcp-tools/SKILL.md`,
|
|
1321
1347
|
"",
|
|
1322
1348
|
"Cloud auth requires `MEKO_API_KEY` exported in your shell (or, for the desktop app on macOS, set via `launchctl setenv`).",
|
|
1323
1349
|
AGENTS_MD_END,
|
|
@@ -1350,9 +1376,16 @@ function printCloudAuthInstructions({ shellRc, hasApp, platform, log }) {
|
|
|
1350
1376
|
log.dim?.(` fish: set -gx MEKO_API_KEY '<your-meko-api-key>'`);
|
|
1351
1377
|
}
|
|
1352
1378
|
log.dim?.(` Then open a new terminal (or run "exec $SHELL" / "exec fish").`);
|
|
1353
|
-
if (
|
|
1379
|
+
if (platform === "darwin") {
|
|
1380
|
+
// Explain launchd for both Codex.app and CLI-only macOS installs.
|
|
1381
|
+
// GUI-launched Codex (Finder, Dock, Spotlight, Alfred, `open -a`) reads
|
|
1382
|
+
// launchd's env, not the shell rc, so a fresh install or a rotated key
|
|
1383
|
+
// needs `launchctl setenv` to propagate. Shell-launched CLI still
|
|
1384
|
+
// reads its shell rc.
|
|
1354
1385
|
log.warn?.(
|
|
1355
|
-
|
|
1386
|
+
hasApp
|
|
1387
|
+
? "macOS Codex.app launched from Finder/Dock does NOT inherit shell rc - set it via launchctl too:"
|
|
1388
|
+
: "macOS Codex CLI launched from Spotlight/Alfred/`open` does NOT inherit shell rc - set it via launchctl too:",
|
|
1356
1389
|
);
|
|
1357
1390
|
log.dim?.(
|
|
1358
1391
|
` launchctl setenv MEKO_API_KEY '<your-meko-api-key>' # current login session`,
|
|
@@ -1360,6 +1393,9 @@ function printCloudAuthInstructions({ shellRc, hasApp, platform, log }) {
|
|
|
1360
1393
|
log.dim?.(
|
|
1361
1394
|
" (For permanence across reboots, add a ~/Library/LaunchAgents/com.meko.env.plist.)",
|
|
1362
1395
|
);
|
|
1396
|
+
log.warn?.(
|
|
1397
|
+
" launchctl setenv writes to the login session's env, which every subsequently GUI-launched process inherits (visible via `launchctl getenv`, `ps e` on descendants, and crash reports).",
|
|
1398
|
+
);
|
|
1363
1399
|
}
|
|
1364
1400
|
}
|
|
1365
1401
|
|
|
@@ -1443,9 +1479,15 @@ export async function maybeOfferLaunchctlSetenv({
|
|
|
1443
1479
|
runCommand,
|
|
1444
1480
|
log,
|
|
1445
1481
|
}) {
|
|
1482
|
+
// Default to Yes: this is the setting that makes GUI-launched Codex on
|
|
1483
|
+
// macOS see the fresh key. Users who habitually hit Enter at the prompt
|
|
1484
|
+
// otherwise leave launchd empty and Codex authenticates with whatever key
|
|
1485
|
+
// it had at first start. See yugabyte/meko-mcp-server#337. The prompt
|
|
1486
|
+
// names both Codex.app and Spotlight-launched CLI so a user without the
|
|
1487
|
+
// desktop app understands why the offer applies to them.
|
|
1446
1488
|
const accept = await promptUser(
|
|
1447
|
-
"Run `launchctl setenv MEKO_API_KEY ...` so Codex
|
|
1448
|
-
|
|
1489
|
+
"Run `launchctl setenv MEKO_API_KEY ...` so GUI-launched Codex (App, Spotlight, Alfred, `open`) sees the key now? (writes the key into the login session env, inherited by every subsequently GUI-launched process)",
|
|
1490
|
+
true,
|
|
1449
1491
|
);
|
|
1450
1492
|
if (!accept) return { set: false };
|
|
1451
1493
|
return setLaunchctlMekoApiKey({ apiKey, runCommand, log });
|
|
@@ -1463,6 +1505,9 @@ export function setLaunchctlMekoApiKey({ apiKey, runCommand, log }) {
|
|
|
1463
1505
|
try {
|
|
1464
1506
|
runCommand(`launchctl setenv MEKO_API_KEY ${shellQuote(apiKey)}`);
|
|
1465
1507
|
log?.dim?.(" Set MEKO_API_KEY via launchctl (current login session).");
|
|
1508
|
+
log?.warn?.(
|
|
1509
|
+
" Fully quit any running Codex (Cmd-Q, or `pkill -x codex` for the CLI) and relaunch — a process already running will keep its previous MEKO_API_KEY.",
|
|
1510
|
+
);
|
|
1466
1511
|
return { set: true };
|
|
1467
1512
|
} catch (err) {
|
|
1468
1513
|
log?.warn?.(" launchctl setenv failed; run it manually if Codex.app needs cloud auth.");
|
package/lib/clients/common.mjs
CHANGED
|
@@ -88,6 +88,13 @@ export function resolveHooksRoot() {
|
|
|
88
88
|
return join(getAssetRoot(), "hooks-handlers");
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* @returns {string} absolute path to the installer-owned OpenCode plugin source
|
|
93
|
+
*/
|
|
94
|
+
export function resolveOpenCodePluginSource() {
|
|
95
|
+
return join(getAssetRoot(), "opencode-plugin", "meko.js");
|
|
96
|
+
}
|
|
97
|
+
|
|
91
98
|
/**
|
|
92
99
|
* @returns {string} absolute path to the statusline script source.
|
|
93
100
|
* Lives under skills/scripts/ in source, mirrored under assets/scripts/ in
|
package/lib/clients/index.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { createClaudeDesktopAdapter } from "./claude-desktop.mjs";
|
|
|
3
3
|
import { createCodexAdapter } from "./codex.mjs";
|
|
4
4
|
import { createCursorAdapter } from "./cursor.mjs";
|
|
5
5
|
import { createKiroAdapter } from "./kiro.mjs";
|
|
6
|
+
import { createOpenCodeAdapter } from "./opencode.mjs";
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* @returns {Record<string, object>}
|
|
@@ -14,5 +15,6 @@ export function getClientAdapters() {
|
|
|
14
15
|
cursor: createCursorAdapter(),
|
|
15
16
|
codex: createCodexAdapter(),
|
|
16
17
|
kiro: createKiroAdapter(),
|
|
18
|
+
opencode: createOpenCodeAdapter(),
|
|
17
19
|
};
|
|
18
20
|
}
|