@yugabytedb/meko-mcp 2.1.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 (70) hide show
  1. package/README.md +233 -40
  2. package/assets/hooks-handlers/codex-session-end.sh +4 -69
  3. package/assets/hooks-handlers/cursor-session-start.sh +19 -1
  4. package/assets/hooks-handlers/lib/capture-cleanup-cli.js +1473 -0
  5. package/assets/hooks-handlers/lib/capture-notices.js +438 -0
  6. package/assets/hooks-handlers/lib/capture-state.js +2173 -0
  7. package/assets/hooks-handlers/lib/capture-status-cli.js +86 -0
  8. package/assets/hooks-handlers/lib/capture.js +2782 -403
  9. package/assets/hooks-handlers/lib/checkpoint-timer.js +485 -81
  10. package/assets/hooks-handlers/lib/journal-bridge.js +218 -0
  11. package/assets/hooks-handlers/lib/kiro-handler.js +760 -0
  12. package/assets/hooks-handlers/lib/opencode-handler.js +620 -0
  13. package/assets/hooks-handlers/lib/opencode-normalizer.js +145 -0
  14. package/assets/hooks-handlers/lib/terminal-handoff.js +427 -0
  15. package/assets/hooks-handlers/session-end.sh +3 -34
  16. package/assets/opencode-plugin/meko.js +213 -0
  17. package/assets/scripts/meko-statusline.sh +123 -16
  18. package/assets/skills/meko-mcp-tools/SKILL.md +116 -126
  19. package/assets/skills/meko-mcp-tools/references/_sections.md +3 -3
  20. package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +25 -18
  21. package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +99 -24
  22. package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +1 -1
  23. package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +53 -6
  24. package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +25 -79
  25. package/assets/skills/meko-mcp-tools/references/tools-overview.md +37 -26
  26. package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +14 -8
  27. package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +66 -1
  28. package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +7 -40
  29. package/assets/skills/meko-mcp-tools-desktop/SKILL.md +56 -20
  30. package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +1 -1
  31. package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +1 -1
  32. package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +15 -8
  33. package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +99 -36
  34. package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +22 -5
  35. package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +18 -14
  36. package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +39 -28
  37. package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +14 -8
  38. package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +67 -1
  39. package/assets/skills/meko-select-datapack-desktop/SKILL.md +4 -4
  40. package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +8 -8
  41. package/assets/skills/meko-select-datapack-desktop/references/role-display-future.md +7 -5
  42. package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +4 -4
  43. package/bin/create-meko-setup.mjs +113 -12
  44. package/lib/capture-cleanup.mjs +63 -0
  45. package/lib/capture-status.mjs +67 -0
  46. package/lib/clients/aliases.mjs +5 -0
  47. package/lib/clients/claude-code.mjs +1 -0
  48. package/lib/clients/claude-desktop.mjs +120 -5
  49. package/lib/clients/codex.mjs +85 -37
  50. package/lib/clients/common.mjs +7 -0
  51. package/lib/clients/index.mjs +4 -0
  52. package/lib/clients/kiro.mjs +705 -0
  53. package/lib/clients/opencode.mjs +532 -0
  54. package/lib/config.mjs +158 -1
  55. package/lib/installer.mjs +18 -1
  56. package/lib/migrate/adapters/claude-code.mjs +11 -2
  57. package/lib/migrate/adapters/codex.mjs +497 -0
  58. package/lib/migrate/adapters/memory-md.mjs +27 -8
  59. package/lib/migrate/adapters/opencode.mjs +148 -0
  60. package/lib/migrate/claude-parser.mjs +153 -9
  61. package/lib/migrate/id.mjs +217 -10
  62. package/lib/migrate/mcp-client.mjs +25 -1
  63. package/lib/migrate/opencode-normalizer.mjs +132 -0
  64. package/lib/migrate/orchestrator.mjs +299 -56
  65. package/lib/migrate/progress.mjs +239 -5
  66. package/lib/migrate/registry.mjs +72 -0
  67. package/lib/migrate.mjs +100 -10
  68. package/lib/prompt.mjs +16 -1
  69. package/package.json +4 -4
  70. package/scripts/bundle-assets.mjs +4 -0
@@ -1,6 +1,7 @@
1
1
  # Knowledge Base / RAG workflow
2
2
 
3
- `knowledgebase_search` is the only KB tool exposed via MCP. Index
3
+ MCP exposes two KB tools: `knowledgebase_search` (retrieval) and
4
+ `knowledgebase_delete_document` (remove ONE uploaded file). Index
4
5
  creation and ingestion happen out of band — through the **Meko UI**
5
6
  (`cloud.mekodata.ai`).
6
7
 
@@ -8,9 +9,10 @@ creation and ingestion happen out of band — through the **Meko UI**
8
9
 
9
10
  | Situation | Use this | Why |
10
11
  |---|---|---|
11
- | Search an existing KB | `knowledgebase_search` | The one KB tool exposed via MCP |
12
+ | Search an existing KB | `knowledgebase_search` | Retrieval over the indexed chunks |
12
13
  | Add documents to a KB | **Meko UI** — Datapack → Actions → **Add Knowledge** | File-upload dialog (PDF/TXT/MD/JSON/MP4, 5 MB each, 10/batch). No MCP equivalent |
13
- | Anything else (list / delete / rename / re-index) | **UI** | No MCP tools for KB lifecycle |
14
+ | Delete ONE uploaded file | `knowledgebase_delete_document` | Destructive; `document_id` from search hits; confirm with the user first |
15
+ | Anything else (list / rename / re-index / source lifecycle) | **UI** | No MCP tools for the rest of KB lifecycle |
14
16
 
15
17
  ## knowledgebase_search — the one you'll actually call
16
18
 
@@ -23,7 +25,7 @@ knowledgebase_search(
23
25
  limit=10)
24
26
  ```
25
27
 
26
- Required: `query`, `agent_id`, `conversation_id`, `datapack_id`.
28
+ Required: `query`, `conversation_id`, `datapack_id`.
27
29
  Unlike the memory tools, `datapack_id` has no default here — you must
28
30
  pass it explicitly. `agent_id` is **ignored for filtering** on this
29
31
  tool (KB results are team-shared on the datapack), but you still pass
@@ -37,10 +39,12 @@ Populated KB:
37
39
  {
38
40
  "results": [
39
41
  {
40
- "content": "<chunk text>",
41
- "similarity": 0.87,
42
- "source_uri": "<original source URI>",
43
- "document_name": "<file key>",
42
+ "id": "<chunk id>",
43
+ "chunk_text": "<chunk text>",
44
+ "document_id": "<KB document id; pass to knowledgebase_delete_document>",
45
+ "metadata_filters": {},
46
+ "distance": 0.31,
47
+ "match_type": "semantic" | "keyword" | "hybrid",
44
48
  ...
45
49
  },
46
50
  ...
@@ -49,6 +53,8 @@ Populated KB:
49
53
  }
50
54
  ```
51
55
 
56
+ Lower `distance` is closer. Promoted memories appear as hits whose `metadata_filters.source` is `"memory"`. Hits carry no filename, so show the user the `document_id` and chunk text when they need to identify a file.
57
+
52
58
  Empty or nonexistent KB: `{"results": [], "count": 0}` (no error,
53
59
  just an empty array).
54
60
 
@@ -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` requires the creating agent's exact value.
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.0"
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 on the server** — the next Meko MCP call will fail with a not-found error. Re-run the skill to pick a new one or `clear` the stale pin.
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,10 +8,10 @@ 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
- > datapack_list()
14
+ > datapack_list(conversation_id="<conv-id>")
15
15
  [14 entries returned, filtering by "prod-research"]
16
16
 
17
17
  One match: `prod-research`. Pinning.
@@ -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,10 +41,10 @@ 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
- > datapack_list()
47
+ > datapack_list(conversation_id="<conv-id>")
48
48
  [14 entries returned, filtering by "q2-roadmap-deck"]
49
49
 
50
50
  One match: `q2-roadmap-deck`. Switching pin.
@@ -66,10 +66,10 @@ 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
- > datapack_list()
72
+ > datapack_list(conversation_id="<conv-id>")
73
73
  [1 entry returned]
74
74
 
75
75
  Only one datapack: `meko-local-setup`. Auto-selecting.
@@ -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
- Beyond the columns the skill renders by default, `datapack_list` returns counts that may be useful in some flows:
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` — total memories the caller has under this datapack (per `(user_id, agent_id)` scoping).
30
- - `knowledge_count` — knowledge-base entries on the datapack.
31
- - `learnings_count` — promoted-to-shared memories on the datapack.
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
- These aren't in the spec column set. Don't add them silently. If the user asks for counts, render them on request — and read the numbers from the live response, never invent them.
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 "not found" when used
21
+ ## Symptom: A pinned datapack returns `datapack_access_denied` when used
22
22
 
23
- The pin became stale — the datapack was deleted in another client. Tell the user:
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 on the server.
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
  ```
@@ -18,6 +18,8 @@ import { resolveSuggestedMcpUrl } from '../lib/url-selection.mjs';
18
18
  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
+ import { runCaptureStatus } from '../lib/capture-status.mjs';
22
+ import { captureCleanupArgs, runCaptureCleanup } from '../lib/capture-cleanup.mjs';
21
23
 
22
24
  // ---------------------------------------------------------------------------
23
25
  // Flag definitions
@@ -44,6 +46,15 @@ const options = {
44
46
  help: { type: 'boolean', short: 'h', default: false },
45
47
  version: { type: 'boolean', short: 'v', default: false },
46
48
 
49
+ // --- Capture health (Capture V2 Workstream D) ---
50
+ 'capture-status': { type: 'boolean', default: false },
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' },
57
+
47
58
  // --- Migrate subcommand ---
48
59
  migrate: { type: 'boolean', default: false },
49
60
  'migrate-status': { type: 'boolean', default: false },
@@ -70,11 +81,11 @@ function readVersion() {
70
81
  return pkg.version;
71
82
  }
72
83
 
73
- const ALL_CLIENTS = ['claude-code', 'claude-desktop', 'cursor', 'codex'];
84
+ const ALL_CLIENTS = ['claude-code', 'claude-desktop', 'cursor', 'codex', 'kiro', 'opencode'];
74
85
 
75
86
  function printHelp() {
76
87
  const text = `
77
- Meko Setup for Claude Clients and Cursor
88
+ Meko Setup for Claude Code, Claude Desktop, Cursor, Codex, Kiro, and OpenCode
78
89
 
79
90
  Install and configure Meko MCP Server in one command.
80
91
 
@@ -100,15 +111,25 @@ Examples:
100
111
  # Install for OpenAI Codex (CLI + Desktop App share the same config):
101
112
  create-meko-setup --client codex --yes
102
113
 
114
+ # Install for Kiro (IDE and kiro-cli share the same config):
115
+ create-meko-setup --client kiro --yes
116
+
117
+ create-meko-setup --client opencode --scope user --yes
118
+
103
119
  # Local Meko (docker-compose stack, Claude Code):
104
120
  create-meko-setup --local --yes
105
121
 
106
122
  Options:
107
- --client <list> Target clients: one or more of claude-code, claude-desktop, cursor, codex.
108
- "claude" is accepted as an alias for claude-code.
123
+ --client <list> Target clients: one or more of claude-code, claude-desktop, cursor, codex, kiro, opencode.
124
+ "claude" is accepted as an alias for claude-code;
125
+ "kiro-cli" and "kiro-ide" for kiro.
109
126
  Comma-separated, or "all" to target every supported client (default: claude-code)
110
127
  codex covers BOTH the OpenAI Codex CLI and the Codex Desktop App
111
128
  (they share ~/.codex/config.toml).
129
+ kiro covers BOTH the Kiro IDE and kiro-cli. It installs
130
+ inline CLI 2.x and standalone CLI 3.x/IDE capture hooks;
131
+ untrusted IDE workspaces and non-managed CLI agents fall
132
+ back to agent-driven persistence.
112
133
  --url <url> MCP server URL (from cloud.mekodata.ai > Datapacks > Connect)
113
134
  --api-key <key> API key for Cloud Meko authentication
114
135
  --local Use local Meko at http://localhost:8000/mcp
@@ -134,6 +155,34 @@ Options:
134
155
  -h, --help Show this help message
135
156
  -v, --version Show version
136
157
 
158
+ Capture health (durable outbox / recovery):
159
+ --capture-status Report aggregate conversation-capture health from
160
+ ~/.claude/meko-capture (or MEKO_WATERMARK_DIR).
161
+ Exit 0 = healthy|catching_up, 2 = degraded_retrying,
162
+ 3 = blocked_action_required.
163
+ --json With --capture-status, print machine-readable JSON
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).
185
+
137
186
  Migrate existing conversations and memories into Meko:
138
187
  --migrate Start a detached migration of existing Claude Code
139
188
  and Cursor conversations + CLAUDE.md memories.
@@ -251,7 +300,22 @@ function parseRate(raw) {
251
300
  // ---------------------------------------------------------------------------
252
301
 
253
302
  async function main() {
254
- const { values: flags } = parseArgs({ options, strict: true });
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
+ }
255
319
  const projectRoot = process.cwd();
256
320
 
257
321
  // --help
@@ -267,6 +331,29 @@ async function main() {
267
331
  process.exit(0);
268
332
  }
269
333
 
334
+ // --capture-status — aggregate outbox health (Capture V2). Combine with
335
+ // --json for machine-readable output. Exit codes: 0 healthy|catching_up,
336
+ // 2 degraded_retrying, 3 blocked_action_required.
337
+ if (flags['capture-status']) {
338
+ const out = runCaptureStatus({ json: Boolean(flags.json) });
339
+ if (out.stdout) process.stdout.write(out.stdout);
340
+ if (out.stderr) process.stderr.write(out.stderr);
341
+ process.exit(out.code);
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
+ }
352
+ if (flags.json) {
353
+ error('--json requires --capture-status or --capture-cleanup');
354
+ process.exit(1);
355
+ }
356
+
270
357
  // --check-updates — synchronous probe of the npm registry. Never fails:
271
358
  // network errors produce "status: network error (<message>)" and exit 0.
272
359
  if (flags['check-updates']) {
@@ -442,6 +529,8 @@ async function main() {
442
529
  'claude-desktop': 'Claude Desktop',
443
530
  cursor: 'Cursor',
444
531
  codex: 'OpenAI Codex (CLI + App)',
532
+ kiro: 'Kiro (IDE + kiro-cli)',
533
+ opencode: 'OpenCode CLI/TUI',
445
534
  }[id];
446
535
  return {
447
536
  label: id,
@@ -542,12 +631,14 @@ async function main() {
542
631
  }
543
632
 
544
633
  // Step 4 — skills
545
- const installSkills = await askYesNo(
546
- 'Install Meko agent skills plugin? (behavioral guides for MCP tools)',
547
- true,
548
- );
549
- if (!installSkills) {
550
- skipSkills = true;
634
+ if (!skipSkills) {
635
+ const installSkills = await askYesNo(
636
+ 'Install Meko agent skills plugin? (behavioral guides for MCP tools)',
637
+ true,
638
+ );
639
+ if (!installSkills) {
640
+ skipSkills = true;
641
+ }
551
642
  }
552
643
 
553
644
  // Step 5 — statusline (Claude Code only). --no-statusline / --statusline
@@ -722,15 +813,23 @@ async function maybeOfferMigration({ url, apiKey, scope, projectRoot, datapack }
722
813
  dryRun: true,
723
814
  datapack: datapack ?? null,
724
815
  });
816
+ if (dry && dry.ok === false) {
817
+ dim(`Skipped migration offer: ${dry.message || "dry run failed"}`);
818
+ return;
819
+ }
725
820
  const s = dry?.message?.match(/Claude Code sessions: *(\d+)/);
726
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+)/);
727
824
  const m = dry?.message?.match(/Memory items \(MD\): *(\d+)/);
728
825
  const counts = {
729
826
  claude: s ? Number(s[1]) : 0,
730
827
  cursor: c ? Number(c[1]) : 0,
828
+ codex: x ? Number(x[1]) : 0,
829
+ opencode: o ? Number(o[1]) : 0,
731
830
  memory: m ? Number(m[1]) : 0,
732
831
  };
733
- const total = counts.claude + counts.cursor + counts.memory;
832
+ const total = counts.claude + counts.cursor + counts.codex + counts.opencode + counts.memory;
734
833
  if (total === 0) return;
735
834
 
736
835
  console.log('');
@@ -738,6 +837,8 @@ async function maybeOfferMigration({ url, apiKey, scope, projectRoot, datapack }
738
837
  `Found existing data to migrate: ` +
739
838
  `${counts.claude} Claude Code sessions, ` +
740
839
  `${counts.cursor} Cursor sessions, ` +
840
+ `${counts.codex} Codex sessions, ` +
841
+ `${counts.opencode} OpenCode sessions, ` +
741
842
  `${counts.memory} memory items.`,
742
843
  );
743
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
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * capture-status.mjs — Installer helper that invokes capture-status-cli.js.
3
+ *
4
+ * Resolves the CLI next to bundled/source hooks (same root as capture.js).
5
+ */
6
+
7
+ import { spawnSync } from "node:child_process";
8
+ import { existsSync } from "node:fs";
9
+ import { dirname, join, resolve } from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+
12
+ import { resolveHooksRoot } from "./clients/common.mjs";
13
+
14
+ /**
15
+ * Absolute path to capture-status-cli.js under the active asset root.
16
+ * @returns {string}
17
+ */
18
+ export function resolveCaptureStatusCli() {
19
+ // Prefer the stable source-tree path in a checkout. Bundle tests create and
20
+ // remove installer/assets concurrently, so probing that transient directory
21
+ // first can race between existsSync and spawnSync. Published packages do not
22
+ // contain the repository skills tree and therefore fall back to assets.
23
+ const here = dirname(fileURLToPath(import.meta.url));
24
+ const sourceCli = resolve(
25
+ here,
26
+ "..",
27
+ "..",
28
+ "skills",
29
+ "hooks-handlers",
30
+ "lib",
31
+ "capture-status-cli.js",
32
+ );
33
+ if (existsSync(sourceCli)) return sourceCli;
34
+ return join(resolveHooksRoot(), "lib", "capture-status-cli.js");
35
+ }
36
+
37
+ /**
38
+ * Run the capture-status CLI and return its result.
39
+ *
40
+ * @param {{ json?: boolean, env?: NodeJS.ProcessEnv }} [opts]
41
+ * @returns {{ code: number, stdout: string, stderr: string, cliPath: string }}
42
+ */
43
+ export function runCaptureStatus(opts = {}) {
44
+ const cliPath = resolveCaptureStatusCli();
45
+ if (!existsSync(cliPath)) {
46
+ return {
47
+ code: 1,
48
+ stdout: "",
49
+ stderr: `capture-status CLI not found at ${cliPath}`,
50
+ cliPath,
51
+ };
52
+ }
53
+ const args = [cliPath];
54
+ if (opts.json) args.push("--json");
55
+ const result = spawnSync(process.execPath, args, {
56
+ encoding: "utf8",
57
+ env: opts.env ? { ...process.env, ...opts.env } : process.env,
58
+ });
59
+ const code =
60
+ typeof result.status === "number" && result.status >= 0 ? result.status : 1;
61
+ return {
62
+ code,
63
+ stdout: result.stdout || "",
64
+ stderr: result.stderr || "",
65
+ cliPath,
66
+ };
67
+ }
@@ -3,6 +3,11 @@
3
3
  // import it without booting the bin entry point.
4
4
  export const CLIENT_ALIASES = Object.freeze({
5
5
  claude: "claude-code",
6
+ // The Kiro IDE and `kiro-cli` share one adapter: same mcp.json paths, same
7
+ // skills directories. Users reach for whichever name matches the surface
8
+ // they're installing for, so both resolve to the single `kiro` adapter.
9
+ "kiro-cli": "kiro",
10
+ "kiro-ide": "kiro",
6
11
  });
7
12
 
8
13
  /**
@@ -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",