@yugabytedb/meko-mcp 2.0.0 → 2.2.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 (65) hide show
  1. package/README.md +183 -33
  2. package/assets/hooks-handlers/codex-session-end.sh +13 -0
  3. package/assets/hooks-handlers/cursor-session-start.sh +19 -1
  4. package/assets/hooks-handlers/lib/capture-notices.js +321 -0
  5. package/assets/hooks-handlers/lib/capture-state.js +2079 -0
  6. package/assets/hooks-handlers/lib/capture-status-cli.js +82 -0
  7. package/assets/hooks-handlers/lib/capture.js +1653 -225
  8. package/assets/hooks-handlers/lib/checkpoint-timer.js +455 -50
  9. package/assets/hooks-handlers/lib/kiro-handler.js +738 -0
  10. package/assets/hooks-handlers/lib/terminal-handoff.js +418 -0
  11. package/assets/hooks-handlers/session-end.sh +3 -24
  12. package/assets/hooks-handlers/session-start.sh +8 -1
  13. package/assets/hooks-handlers/test_checkpoint_timer.sh +162 -0
  14. package/assets/scripts/meko-statusline.sh +41 -1
  15. package/assets/scripts/package-desktop-skill.sh +32 -1
  16. package/assets/skills/meko-mcp-tools/SKILL.md +90 -137
  17. package/assets/skills/meko-mcp-tools/references/_sections.md +3 -5
  18. package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +31 -28
  19. package/assets/skills/meko-mcp-tools/references/tools-conversation-dedup.md +5 -7
  20. package/assets/skills/meko-mcp-tools/references/tools-conversation-reasoning.md +50 -0
  21. package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +69 -49
  22. package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +6 -6
  23. package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +29 -5
  24. package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +29 -92
  25. package/assets/skills/meko-mcp-tools/references/tools-overview.md +42 -40
  26. package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +1 -2
  27. package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +18 -11
  28. package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +10 -9
  29. package/assets/skills/meko-mcp-tools-desktop/SKILL.md +51 -44
  30. package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +6 -6
  31. package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +2 -2
  32. package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +34 -25
  33. package/assets/skills/meko-mcp-tools-desktop/references/tools-conversation-reasoning.md +50 -0
  34. package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +63 -37
  35. package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +4 -4
  36. package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +19 -22
  37. package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +42 -40
  38. package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +1 -2
  39. package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +3 -17
  40. package/assets/skills/meko-select-datapack-desktop/SKILL.md +31 -21
  41. package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +8 -8
  42. package/assets/skills/meko-select-datapack-desktop/references/role-display-future.md +41 -0
  43. package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +1 -1
  44. package/bin/create-meko-setup.mjs +93 -16
  45. package/lib/capture-status.mjs +67 -0
  46. package/lib/clients/aliases.mjs +5 -0
  47. package/lib/clients/claude-code.mjs +8 -4
  48. package/lib/clients/claude-desktop.mjs +133 -4
  49. package/lib/clients/codex.mjs +29 -11
  50. package/lib/clients/common.mjs +2 -0
  51. package/lib/clients/cursor.mjs +7 -2
  52. package/lib/clients/index.mjs +2 -0
  53. package/lib/clients/kiro.mjs +705 -0
  54. package/lib/config.mjs +90 -0
  55. package/lib/detect.mjs +7 -2
  56. package/lib/installer.mjs +1 -0
  57. package/lib/migrate/adapters/codex.mjs +490 -0
  58. package/lib/migrate/id.mjs +28 -3
  59. package/lib/migrate/orchestrator.mjs +34 -7
  60. package/lib/migrate.mjs +4 -2
  61. package/lib/prompt.mjs +17 -2
  62. package/lib/url-selection.mjs +55 -0
  63. package/package.json +4 -4
  64. package/assets/skills/meko-mcp-tools/references/tools-scope-permissions.md +0 -71
  65. package/assets/skills/meko-mcp-tools-desktop/references/tools-scope-permissions.md +0 -71
@@ -3,15 +3,15 @@ name: meko-select-datapack-desktop
3
3
  description: >-
4
4
  Lists the user's Meko datapacks, shows authorization, supports search and
5
5
  pagination, and pins one as the active datapack on Claude Desktop. Triggers
6
- when the user says things like "switch datapack", "use datapack <name>",
7
- "list my datapacks", "which datapack am I on", "pin <name>", or any request
6
+ when the user says things like "switch datapack", "use the Acme datapack",
7
+ "list my datapacks", "which datapack am I on", "pin Acme", or any request
8
8
  to change or inspect the active datapack. Persistence is via memory_add
9
9
  (Desktop has no SessionStart hook), so the pin survives across sessions
10
10
  until the user clears it.
11
11
  license: MIT
12
12
  metadata:
13
13
  author: Meko
14
- version: "1.1.0"
14
+ version: "1.2.1"
15
15
  tags: meko, datapack, selection, project, claude-desktop, desktop
16
16
  ---
17
17
 
@@ -42,10 +42,10 @@ Trigger immediately on any of these signals:
42
42
 
43
43
  ## On every Meko-touching turn (not just when this skill triggers)
44
44
 
45
- Before issuing a Meko MCP write tool call (memory_add, db_run_write_query, conversation_add_message, etc.), if you don't already know the active pin from this turn's earlier work:
45
+ Before issuing a Meko MCP write tool call (memory_add, conversation_add_message, artifact_put, etc.), if you don't already know the active pin from this turn's earlier work:
46
46
 
47
47
  ```
48
- memory_search(scope="read",
48
+ memory_search(
49
49
  query="meko_active_datapack",
50
50
  agent_id="claude_desktop",
51
51
  conversation_id="<this conversation's id>",
@@ -61,7 +61,7 @@ This is once per turn, not once per call. Cache within the turn.
61
61
  ### 1. List
62
62
 
63
63
  Use a **temporary** conversation for browsing only. Call
64
- `conversation_create(scope="write", agent_id="claude_desktop", title="Claude
64
+ `conversation_create(agent_id="claude_desktop", title="Claude
65
65
  Desktop datapack selection")` and use its returned ID for the read-only
66
66
  `datapack_list` below and for the pin `memory_add`/`memory_update` in step 4.
67
67
 
@@ -72,13 +72,20 @@ must flow through a *new* conversation created in the selected datapack — see
72
72
  step 5.
73
73
 
74
74
  ```
75
- datapack_list(scope="read", conversation_id="<this conversation's id>")
75
+ datapack_list(conversation_id="<this conversation's id>")
76
76
  ```
77
77
 
78
78
  The response is an array; the fields you'll use are `datapack_id`,
79
- `datapack_name`, `created_at`, and `account_id`.
79
+ `datapack_name`, `created_at`, `account_id`, and `grant`.
80
80
 
81
- If the response has zero entries, tell the user: *"You don't have any datapacks yet. Run `datapack_create(scope='admin', name='<name>')` to make one, or visit the Meko Cloud console."* Stop here.
81
+ `grant` is the caller's actual authorization on the datapack — one of
82
+ `"owner"`, `"maintainer"`, `"contributor"`, `"viewer"`. Display it verbatim in
83
+ the Role column. Do not hardcode "Owner", do not invent or normalize the value
84
+ (render `"maintainer"` as `maintainer`, not `Maintainer`). The deployed
85
+ response is the source of truth — see `references/role-display-future.md` for
86
+ the taxonomy.
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.
82
89
 
83
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).
84
91
 
@@ -89,19 +96,22 @@ For 2+ datapacks, render a numbered table. **Page size 10.** Default sort: `crea
89
96
  ```
90
97
  Your datapacks (showing 1-10 of 14):
91
98
 
92
- # Name Role Created Status Active?
93
- 1 meko-local-setup Owner 2026-04-30 ready ← (pinned)
94
- 2 meko_default_datapack Owner 2026-04-30 ready
95
- 3 prod-research Owner 2026-04-12 ready
99
+ # Name Role Created Status Active?
100
+ 1 meko-local-setup owner 2026-04-30 ready ← (pinned)
101
+ 2 meko_default_datapack owner 2026-04-30 ready
102
+ 3 team-onboarding maintainer 2026-04-08 ready
103
+ 4 q2-roadmap viewer 2026-03-22 ready
96
104
  …
97
105
 
98
106
  Reply with: a number (1-10) to pin · a substring to search · `next` / `prev` to page
99
107
  · `clear` to unset · `cancel` to leave the current pin alone
100
-
101
- Note: Role is hardcoded to "Owner" today. Shared / Viewer / Contributor /
102
- Maintainer roles are pending upstream backend work — see references/role-display-future.md.
103
108
  ```
104
109
 
110
+ The **Role** column shows each datapack's `grant` value verbatim (`owner`,
111
+ `maintainer`, `contributor`, `viewer`). Never hardcode "Owner" — shared
112
+ datapacks legitimately carry other grants, and misreporting them (e.g. showing
113
+ a `maintainer` grant as "Owner") misleads the user about their own access.
114
+
105
115
  Mark the currently-pinned row with `← (pinned)` based on the `memory_search` result (if any).
106
116
 
107
117
  ### 3. Parse the user's reply
@@ -118,7 +128,7 @@ Mark the currently-pinned row with `← (pinned)` based on the `memory_search`
118
128
  **On first pin (no existing pin memory):**
119
129
 
120
130
  ```
121
- memory_add(scope="write",
131
+ memory_add(
122
132
  text="meko_active_datapack=<uuid> name=<name> selected_at=<iso8601>",
123
133
  agent_id="claude_desktop",
124
134
  conversation_id="<this conversation's id>",
@@ -130,7 +140,7 @@ Verify the write with `memory_search` (the standard Meko verify-after-write rule
130
140
  **On switch (existing pin memory found):**
131
141
 
132
142
  ```
133
- memory_update(scope="write",
143
+ memory_update(
134
144
  memory_id="<existing pin id>",
135
145
  text="meko_active_datapack=<new uuid> name=<new name> selected_at=<iso8601>",
136
146
  agent_id="claude_desktop",
@@ -142,7 +152,7 @@ Always update — never `memory_add` a second pin. Two pin memories will produce
142
152
  **On clear:**
143
153
 
144
154
  ```
145
- memory_delete_by_id(scope="write",
155
+ memory_delete_by_id(
146
156
  memory_id="<existing pin id>",
147
157
  agent_id="claude_desktop",
148
158
  conversation_id="<this conversation's id>")
@@ -153,7 +163,7 @@ If `memory_search` returned no pin, there's nothing to delete — print *"No pin
153
163
  **Conversation transition after a clear (same rule as a switch).** The pin memory is now gone, but the session's current conversation still physically lives in the datapack that was pinned when it was created — a conversation cannot move to the default. You must pick exactly one of these; do not mix them:
154
164
 
155
165
  - **Option A — keep capturing to the current conversation this session.** It stays in its original (now-unpinned) datapack, so you must keep passing that **same old `datapack_id`** on its `conversation_add_message` calls — do NOT switch it to the default (that would fail). The clear only affects *new* sessions. Disclose: *"Pin cleared. This chat keeps saving to `<old datapack name>`; new chats will use the default datapack."*
156
- - **Option B — start default-datapack capture immediately.** Create a **new** conversation with no `datapack_id` (`conversation_create(scope="write", agent_id="claude_desktop")`) and post all subsequent turns there. Stop posting to the old conversation. Disclose: *"Pin cleared. Started a new chat context saving to the default datapack."*
166
+ - **Option B — start default-datapack capture immediately.** Create a **new** conversation with no `datapack_id` (`conversation_create(agent_id="claude_desktop")`) and post all subsequent turns there. Stop posting to the old conversation. Disclose: *"Pin cleared. Started a new chat context saving to the default datapack."*
157
167
 
158
168
  Default to Option A (least disruptive) unless the user wants the switch to take effect right now. Either way, never send `datapack_id=default` to the pre-existing pinned conversation.
159
169
 
@@ -173,7 +183,7 @@ right `datapack_id` flows through automatically.
173
183
  **Then start a fresh conversation for capture in the selected datapack.** The
174
184
  temporary selection conversation from step 1 belongs to the datapack that was
175
185
  active when it was created and cannot be moved. For subsequent capture this
176
- session, call `conversation_create(scope="write", agent_id="claude_desktop",
186
+ session, call `conversation_create(agent_id="claude_desktop",
177
187
  datapack_id="<the newly pinned uuid>", title="<topic>")` and post turns
178
188
  (`conversation_add_message`) to *that* conversation with the same
179
189
  `datapack_id`. Do not keep posting to the selection conversation — doing so
@@ -11,12 +11,12 @@ Concrete transcripts of the four flows the skill supports on Claude Desktop.
11
11
  > memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)
12
12
  [empty]
13
13
 
14
- > datapack_list(scope="read")
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.
18
18
 
19
- > memory_add(scope="write",
19
+ > memory_add(
20
20
  text="meko_active_datapack=8b1c…f4a2 name=prod-research selected_at=2026-05-25T18:42:00Z",
21
21
  agent_id="claude_desktop",
22
22
  conversation_id="<conv-id>",
@@ -44,12 +44,12 @@ datapack_id flows through automatically.
44
44
  > memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)
45
45
  [returns id=mem_abc123, text="meko_active_datapack=8b1c…f4a2 name=prod-research …"]
46
46
 
47
- > datapack_list(scope="read")
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.
51
51
 
52
- > memory_update(scope="write",
52
+ > memory_update(
53
53
  memory_id="mem_abc123",
54
54
  text="meko_active_datapack=4c2e…a991 name=q2-roadmap-deck selected_at=2026-05-25T19:05:00Z",
55
55
  agent_id="claude_desktop",
@@ -69,12 +69,12 @@ The `memory_update` is critical here — using `memory_add` again would create a
69
69
  > memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)
70
70
  [empty]
71
71
 
72
- > datapack_list(scope="read")
72
+ > datapack_list(conversation_id="<conv-id>")
73
73
  [1 entry returned]
74
74
 
75
75
  Only one datapack: `meko-local-setup`. Auto-selecting.
76
76
 
77
- > memory_add(scope="write",
77
+ > memory_add(
78
78
  text="meko_active_datapack=a17d…cc91 name=meko-local-setup selected_at=…",
79
79
  agent_id="claude_desktop",
80
80
  conversation_id="<conv-id>",
@@ -93,7 +93,7 @@ Pinned datapack `meko-local-setup` (`a17d…cc91`). Run this skill again with
93
93
  > memory_search(query="meko_active_datapack", agent_id="claude_desktop", limit=1)
94
94
  [returns id=mem_abc123]
95
95
 
96
- > memory_delete_by_id(scope="write",
96
+ > memory_delete_by_id(
97
97
  memory_id="mem_abc123",
98
98
  agent_id="claude_desktop",
99
99
  conversation_id="<conv-id>")
@@ -114,7 +114,7 @@ This isn't a user-triggered flow — it's the per-turn lookup the skill teaches
114
114
 
115
115
  # Extract UUID after "meko_active_datapack=" → 8b1c…f4a2
116
116
 
117
- > memory_add(scope="write", text="…", datapack_id="8b1c…f4a2",
117
+ > memory_add(text="…", datapack_id="8b1c…f4a2",
118
118
  agent_id="claude_desktop", conversation_id="<conv-id>")
119
119
  ```
120
120
 
@@ -0,0 +1,41 @@
1
+ # Role display — current state
2
+
3
+ ## Today: render `grant` verbatim
4
+
5
+ The deployed Meko `GET /datapacks` response includes a `grant` field on every datapack. Possible values (per maintainer guidance, 2026-05-26):
6
+
7
+ - `"owner"` — datapacks the caller created.
8
+ - `"maintainer"` — write access to a shared datapack including memories AND collective learnings/knowledge.
9
+ - `"contributor"` — write access to a shared datapack: can generate own memories. (Cannot promote / publish collective learnings — that's the maintainer's job.)
10
+ - `"viewer"` — read-only on a shared datapack.
11
+
12
+ Use the field directly in the **Role** column:
13
+
14
+ ```
15
+ # Name Role Created Active?
16
+ 1 prod-research owner 2026-04-12 ← (pinned)
17
+ 2 team-onboarding contributor 2026-04-08
18
+ 3 q2-roadmap viewer 2026-03-22
19
+ ```
20
+
21
+ Do not invent values, do not normalize the casing, do not display `"Owner"` if the field says `"owner"`. The deployed schema is the source of truth.
22
+
23
+ Note that the upstream Go source (the `Datapack` struct in `api_server/internal/models/models.go` of the `meko` API-server repo) does NOT declare `grant` — the deployed server enriches the response beyond what the public Go code lists. Don't rely on the public struct for the wire schema; trust the actual response.
24
+
25
+ ## Other fields the live response includes
26
+
27
+ Beyond the columns the skill renders by default, `datapack_list` returns counts that may be useful in some flows:
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.
32
+
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.
34
+
35
+ ## Sharing UI vs API state
36
+
37
+ The Cloud console "Share <datapack>" page (`meko_ui/src/features/datapacks/pages/DatapackSharePage.tsx`) shows interactive controls with "Coming Soon" overlays on a few specific actions (e.g. invite-by-email link sharing, transfer-ownership). Those overlays mean *those specific UI affordances* aren't shipped — NOT that the underlying `grant`/sharing model is absent. Contributor/maintainer/viewer grants are functional in the data layer today; only the user-facing self-serve invite flow is gated.
38
+
39
+ ## Why the skill ships without Mine / Shared / All filter tabs
40
+
41
+ The tagged pin memory (re-read via `memory_search` before each Meko write) delivers the user's actual ask ("don't make me remember a UUID"). Filter tabs are useful when the response is genuinely mixed-grant; for users with only owner-grant rows they're decorative. We add tabs when there's evidence users with mixed-grant responses want them.
@@ -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(scope="admin", name="<your-datapack-name>")
43
+ datapack_create(name="<your-datapack-name>")
44
44
 
45
45
  Or visit the Meko Cloud console (Datapacks → New datapack).
46
46
  ```
@@ -7,12 +7,18 @@ import { dirname, join } from 'node:path';
7
7
 
8
8
  import { install, uninstall } from '../lib/installer.mjs';
9
9
  import { askChoice, askMultiChoice, askText, askSecret, askYesNo, close as closePrompts } from '../lib/prompt.mjs';
10
- import { banner, error, dim, info } from '../lib/logger.mjs';
11
- import { isPackagedInstall, selfInvocation } from '../lib/clients/common.mjs';
10
+ import { banner, error, dim, info, warn } from '../lib/logger.mjs';
11
+ import {
12
+ isPackagedInstall,
13
+ MEKO_PRODUCTION_CONSOLE_URL,
14
+ selfInvocation,
15
+ } from '../lib/clients/common.mjs';
12
16
  import { getClientAdapters } from '../lib/clients/index.mjs';
17
+ import { resolveSuggestedMcpUrl } from '../lib/url-selection.mjs';
13
18
  import { parseClientList } from '../lib/clients/aliases.mjs';
14
19
  import { startMigration, runChildMigration, readStatus, stopMigration } from '../lib/migrate.mjs';
15
20
  import { checkLatest } from '../lib/version-check.mjs';
21
+ import { runCaptureStatus } from '../lib/capture-status.mjs';
16
22
 
17
23
  // ---------------------------------------------------------------------------
18
24
  // Flag definitions
@@ -39,6 +45,10 @@ const options = {
39
45
  help: { type: 'boolean', short: 'h', default: false },
40
46
  version: { type: 'boolean', short: 'v', default: false },
41
47
 
48
+ // --- Capture health (Capture V2 Workstream D) ---
49
+ 'capture-status': { type: 'boolean', default: false },
50
+ json: { type: 'boolean', default: false },
51
+
42
52
  // --- Migrate subcommand ---
43
53
  migrate: { type: 'boolean', default: false },
44
54
  'migrate-status': { type: 'boolean', default: false },
@@ -65,11 +75,11 @@ function readVersion() {
65
75
  return pkg.version;
66
76
  }
67
77
 
68
- const ALL_CLIENTS = ['claude-code', 'claude-desktop', 'cursor', 'codex'];
78
+ const ALL_CLIENTS = ['claude-code', 'claude-desktop', 'cursor', 'codex', 'kiro'];
69
79
 
70
80
  function printHelp() {
71
81
  const text = `
72
- Meko Setup for Claude Clients and Cursor
82
+ Meko Setup for Claude Code, Claude Desktop, Cursor, Codex, and Kiro
73
83
 
74
84
  Install and configure Meko MCP Server in one command.
75
85
 
@@ -81,7 +91,7 @@ Examples:
81
91
  create-meko-setup
82
92
 
83
93
  # Cloud Meko for Claude Code (non-interactive):
84
- create-meko-setup --url https://your-mcp.mekodev.com/mcp --api-key "$MEKO_API_KEY" --yes
94
+ create-meko-setup --url https://mcp.mekodata.ai/mcp --api-key "$MEKO_API_KEY" --yes
85
95
 
86
96
  # Local Meko with Cursor config:
87
97
  create-meko-setup --client cursor --local --scope project --yes
@@ -95,16 +105,24 @@ Examples:
95
105
  # Install for OpenAI Codex (CLI + Desktop App share the same config):
96
106
  create-meko-setup --client codex --yes
97
107
 
108
+ # Install for Kiro (IDE and kiro-cli share the same config):
109
+ create-meko-setup --client kiro --yes
110
+
98
111
  # Local Meko (docker-compose stack, Claude Code):
99
112
  create-meko-setup --local --yes
100
113
 
101
114
  Options:
102
- --client <list> Target clients: one or more of claude-code, claude-desktop, cursor, codex.
103
- "claude" is accepted as an alias for claude-code.
115
+ --client <list> Target clients: one or more of claude-code, claude-desktop, cursor, codex, kiro.
116
+ "claude" is accepted as an alias for claude-code;
117
+ "kiro-cli" and "kiro-ide" for kiro.
104
118
  Comma-separated, or "all" to target every supported client (default: claude-code)
105
119
  codex covers BOTH the OpenAI Codex CLI and the Codex Desktop App
106
120
  (they share ~/.codex/config.toml).
107
- --url <url> MCP server URL (from app.mekodev.com > Datapacks > Connect)
121
+ kiro covers BOTH the Kiro IDE and kiro-cli. It installs
122
+ inline CLI 2.x and standalone CLI 3.x/IDE capture hooks;
123
+ untrusted IDE workspaces and non-managed CLI agents fall
124
+ back to agent-driven persistence.
125
+ --url <url> MCP server URL (from cloud.mekodata.ai > Datapacks > Connect)
108
126
  --api-key <key> API key for Cloud Meko authentication
109
127
  --local Use local Meko at http://localhost:8000/mcp
110
128
  --scope <scope> Config scope: user or project (default: user)
@@ -129,6 +147,14 @@ Options:
129
147
  -h, --help Show this help message
130
148
  -v, --version Show version
131
149
 
150
+ Capture health (durable outbox / recovery):
151
+ --capture-status Report aggregate conversation-capture health from
152
+ ~/.claude/meko-capture (or MEKO_WATERMARK_DIR).
153
+ Exit 0 = healthy|catching_up, 2 = degraded_retrying,
154
+ 3 = blocked_action_required.
155
+ --json With --capture-status, print machine-readable JSON
156
+ matching the capture-health cache shape.
157
+
132
158
  Migrate existing conversations and memories into Meko:
133
159
  --migrate Start a detached migration of existing Claude Code
134
160
  and Cursor conversations + CLAUDE.md memories.
@@ -262,6 +288,20 @@ async function main() {
262
288
  process.exit(0);
263
289
  }
264
290
 
291
+ // --capture-status — aggregate outbox health (Capture V2). Combine with
292
+ // --json for machine-readable output. Exit codes: 0 healthy|catching_up,
293
+ // 2 degraded_retrying, 3 blocked_action_required.
294
+ if (flags['capture-status']) {
295
+ const out = runCaptureStatus({ json: Boolean(flags.json) });
296
+ if (out.stdout) process.stdout.write(out.stdout);
297
+ if (out.stderr) process.stderr.write(out.stderr);
298
+ process.exit(out.code);
299
+ }
300
+ if (flags.json) {
301
+ error('--json requires --capture-status');
302
+ process.exit(1);
303
+ }
304
+
265
305
  // --check-updates — synchronous probe of the npm registry. Never fails:
266
306
  // network errors produce "status: network error (<message>)" and exit 0.
267
307
  if (flags['check-updates']) {
@@ -437,6 +477,7 @@ async function main() {
437
477
  'claude-desktop': 'Claude Desktop',
438
478
  cursor: 'Cursor',
439
479
  codex: 'OpenAI Codex (CLI + App)',
480
+ kiro: 'Kiro (IDE + kiro-cli)',
440
481
  }[id];
441
482
  return {
442
483
  label: id,
@@ -465,6 +506,28 @@ async function main() {
465
506
  }
466
507
  }
467
508
 
509
+ let suggestedUrl = null;
510
+ if (!url && !flags.local) {
511
+ suggestedUrl = resolveSuggestedMcpUrl({
512
+ adapters: getClientAdapters(),
513
+ clients,
514
+ name: flags.name,
515
+ scope: flags.scope,
516
+ projectRoot,
517
+ });
518
+ if (flags.yes) {
519
+ if (suggestedUrl.source === 'conflict') {
520
+ const conflicts = suggestedUrl.existingUrls.map((existingUrl) => `\n - ${existingUrl}`).join('');
521
+ error(
522
+ `Selected clients have different existing Meko URLs:${conflicts}\n` +
523
+ 'Pass --url explicitly to choose which endpoint to install.',
524
+ );
525
+ process.exit(1);
526
+ }
527
+ url = suggestedUrl.url;
528
+ }
529
+ }
530
+
468
531
  // Interactive mode: URL not provided and not auto-accepting defaults
469
532
  if (!url && !flags.yes) {
470
533
  banner('Meko Setup');
@@ -475,7 +538,7 @@ async function main() {
475
538
  // When only Cloud is available, skip the prompt entirely — asking to
476
539
  // pick between one option is pointless UX.
477
540
  const connectionOptions = [
478
- { label: 'Cloud Meko', description: 'Hosted at mekodev.com (requires URL + API key)' },
541
+ { label: 'Cloud Meko', description: 'Hosted at mekodata.ai (requires an API key)' },
479
542
  ];
480
543
  if (!isPackagedInstall()) {
481
544
  connectionOptions.push({
@@ -490,7 +553,19 @@ async function main() {
490
553
 
491
554
  if (connectionType === 'Cloud Meko') {
492
555
  // Step 2 — MCP URL
493
- url = await askText('MCP server URL (from app.mekodev.com > Datapacks > Connect):');
556
+ if (suggestedUrl?.source === 'existing') {
557
+ dim(`Using the existing Meko endpoint as the default: ${suggestedUrl.url}`);
558
+ } else if (suggestedUrl?.source === 'conflict') {
559
+ const conflicts = suggestedUrl.existingUrls.map((existingUrl) => `\n - ${existingUrl}`).join('');
560
+ warn(
561
+ `Selected clients use different Meko endpoints:${conflicts}\n` +
562
+ 'Enter the endpoint to use for this install.',
563
+ );
564
+ }
565
+ url = await askText(
566
+ `MCP server URL (from ${MEKO_PRODUCTION_CONSOLE_URL} > Datapacks > Connect):`,
567
+ suggestedUrl?.url ?? undefined,
568
+ );
494
569
 
495
570
  // Step 3 — API key. Normalize: terminal paste can drag in trailing
496
571
  // whitespace/CR or accidental surrounding quotes, all of which would
@@ -503,12 +578,14 @@ async function main() {
503
578
  }
504
579
 
505
580
  // Step 4 — skills
506
- const installSkills = await askYesNo(
507
- 'Install Meko agent skills plugin? (behavioral guides for MCP tools)',
508
- true,
509
- );
510
- if (!installSkills) {
511
- skipSkills = true;
581
+ if (!skipSkills) {
582
+ const installSkills = await askYesNo(
583
+ 'Install Meko agent skills plugin? (behavioral guides for MCP tools)',
584
+ true,
585
+ );
586
+ if (!installSkills) {
587
+ skipSkills = true;
588
+ }
512
589
  }
513
590
 
514
591
  // Step 5 — statusline (Claude Code only). --no-statusline / --statusline
@@ -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
  /**
@@ -288,13 +288,17 @@ export function createClaudeCodeAdapter(options = {}) {
288
288
  // leaving the marketplace.json missing. Full clone is small
289
289
  // (~few MB, mostly markdown) and is the only way that reliably
290
290
  // succeeds today.
291
- // Marketplace source is normally the upstream GitHub repo. A dev/e2e
291
+ // Marketplace source is normally the public generated skills repo. Use
292
+ // an explicit HTTPS URL: GitHub's owner/repo shorthand makes Claude Code
293
+ // clone over SSH, which fails for users without GitHub SSH credentials.
294
+ // A dev/e2e
292
295
  // override lets a test install the plugin from a LOCAL working-tree
293
296
  // checkout (a directory path) so unreleased skill changes can be
294
- // exercised end-to-end before they land on `yugabyte/meko-mcp-server`.
295
- // Default is unchanged; only set MEKO_PLUGIN_MARKETPLACE_SOURCE in tests.
297
+ // exercised end-to-end before they are published to `yugabyte/meko-skills`.
298
+ // Only set MEKO_PLUGIN_MARKETPLACE_SOURCE in tests.
296
299
  const marketplaceSource =
297
- process.env.MEKO_PLUGIN_MARKETPLACE_SOURCE || "yugabyte/meko-mcp-server";
300
+ process.env.MEKO_PLUGIN_MARKETPLACE_SOURCE
301
+ || "https://github.com/yugabyte/meko-skills.git";
298
302
  const marketplaceCmd =
299
303
  `claude plugin marketplace add ${shellQuote(marketplaceSource)} --scope ${shellQuote(scope)}`;
300
304
  // `claude plugin list` dropped --scope in CLI 2.1.x; it prints all