@yugabytedb/meko-mcp 2.1.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 (45) hide show
  1. package/README.md +152 -27
  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-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 +1578 -299
  8. package/assets/hooks-handlers/lib/checkpoint-timer.js +444 -81
  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 -34
  12. package/assets/scripts/meko-statusline.sh +41 -1
  13. package/assets/skills/meko-mcp-tools/SKILL.md +72 -125
  14. package/assets/skills/meko-mcp-tools/references/_sections.md +2 -2
  15. package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +12 -13
  16. package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +15 -12
  17. package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +25 -1
  18. package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +19 -77
  19. package/assets/skills/meko-mcp-tools/references/tools-overview.md +8 -7
  20. package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +22 -1
  21. package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +1 -1
  22. package/assets/skills/meko-mcp-tools-desktop/SKILL.md +8 -8
  23. package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +1 -1
  24. package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +1 -1
  25. package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +6 -1
  26. package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +6 -5
  27. package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +4 -4
  28. package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +7 -6
  29. package/assets/skills/meko-select-datapack-desktop/SKILL.md +1 -1
  30. package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +3 -3
  31. package/bin/create-meko-setup.mjs +48 -10
  32. package/lib/capture-status.mjs +67 -0
  33. package/lib/clients/aliases.mjs +5 -0
  34. package/lib/clients/claude-desktop.mjs +120 -5
  35. package/lib/clients/codex.mjs +6 -3
  36. package/lib/clients/index.mjs +2 -0
  37. package/lib/clients/kiro.mjs +705 -0
  38. package/lib/config.mjs +90 -0
  39. package/lib/installer.mjs +1 -0
  40. package/lib/migrate/adapters/codex.mjs +490 -0
  41. package/lib/migrate/id.mjs +28 -3
  42. package/lib/migrate/orchestrator.mjs +34 -7
  43. package/lib/migrate.mjs +4 -2
  44. package/lib/prompt.mjs +16 -1
  45. package/package.json +4 -4
@@ -18,6 +18,7 @@ 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';
21
22
 
22
23
  // ---------------------------------------------------------------------------
23
24
  // Flag definitions
@@ -44,6 +45,10 @@ const options = {
44
45
  help: { type: 'boolean', short: 'h', default: false },
45
46
  version: { type: 'boolean', short: 'v', default: false },
46
47
 
48
+ // --- Capture health (Capture V2 Workstream D) ---
49
+ 'capture-status': { type: 'boolean', default: false },
50
+ json: { type: 'boolean', default: false },
51
+
47
52
  // --- Migrate subcommand ---
48
53
  migrate: { type: 'boolean', default: false },
49
54
  'migrate-status': { type: 'boolean', default: false },
@@ -70,11 +75,11 @@ function readVersion() {
70
75
  return pkg.version;
71
76
  }
72
77
 
73
- const ALL_CLIENTS = ['claude-code', 'claude-desktop', 'cursor', 'codex'];
78
+ const ALL_CLIENTS = ['claude-code', 'claude-desktop', 'cursor', 'codex', 'kiro'];
74
79
 
75
80
  function printHelp() {
76
81
  const text = `
77
- Meko Setup for Claude Clients and Cursor
82
+ Meko Setup for Claude Code, Claude Desktop, Cursor, Codex, and Kiro
78
83
 
79
84
  Install and configure Meko MCP Server in one command.
80
85
 
@@ -100,15 +105,23 @@ Examples:
100
105
  # Install for OpenAI Codex (CLI + Desktop App share the same config):
101
106
  create-meko-setup --client codex --yes
102
107
 
108
+ # Install for Kiro (IDE and kiro-cli share the same config):
109
+ create-meko-setup --client kiro --yes
110
+
103
111
  # Local Meko (docker-compose stack, Claude Code):
104
112
  create-meko-setup --local --yes
105
113
 
106
114
  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.
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.
109
118
  Comma-separated, or "all" to target every supported client (default: claude-code)
110
119
  codex covers BOTH the OpenAI Codex CLI and the Codex Desktop App
111
120
  (they share ~/.codex/config.toml).
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.
112
125
  --url <url> MCP server URL (from cloud.mekodata.ai > Datapacks > Connect)
113
126
  --api-key <key> API key for Cloud Meko authentication
114
127
  --local Use local Meko at http://localhost:8000/mcp
@@ -134,6 +147,14 @@ Options:
134
147
  -h, --help Show this help message
135
148
  -v, --version Show version
136
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
+
137
158
  Migrate existing conversations and memories into Meko:
138
159
  --migrate Start a detached migration of existing Claude Code
139
160
  and Cursor conversations + CLAUDE.md memories.
@@ -267,6 +288,20 @@ async function main() {
267
288
  process.exit(0);
268
289
  }
269
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
+
270
305
  // --check-updates — synchronous probe of the npm registry. Never fails:
271
306
  // network errors produce "status: network error (<message>)" and exit 0.
272
307
  if (flags['check-updates']) {
@@ -442,6 +477,7 @@ async function main() {
442
477
  'claude-desktop': 'Claude Desktop',
443
478
  cursor: 'Cursor',
444
479
  codex: 'OpenAI Codex (CLI + App)',
480
+ kiro: 'Kiro (IDE + kiro-cli)',
445
481
  }[id];
446
482
  return {
447
483
  label: id,
@@ -542,12 +578,14 @@ async function main() {
542
578
  }
543
579
 
544
580
  // 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;
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
+ }
551
589
  }
552
590
 
553
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
  /**
@@ -18,6 +18,101 @@ import {
18
18
  writeInstallerMarker,
19
19
  } from "./common.mjs";
20
20
 
21
+ /**
22
+ * Pinned top-level `mcp-remote` version.
23
+ *
24
+ * Pinning the top-level package (rather than leaving a bare `mcp-remote` that
25
+ * floats onto whatever npm's `latest` tag points to) reduces — but does not
26
+ * eliminate — startup drift: `mcp-remote@0.1.38` still declares transitive
27
+ * ranges like `open@^10.1.0` and `undici@^7.12.0`, and a fresh `npx` cache
28
+ * resolves the newest matching version of each with no lockfile consulted, so
29
+ * a future transitive release can still change startup behavior. The Node
30
+ * floor enforced below is what keeps today's tree runnable: every *currently
31
+ * published* undici 7 release declares `engines.node >= 20.18.1`, so rejecting
32
+ * Node under that floor covers the dependency set that resolves today. It is
33
+ * not a future-proof guarantee — a later in-range 7.x release could raise its
34
+ * own engine floor or introduce another incompatibility, which is exactly the
35
+ * residual drift the paragraph above acknowledges. Bump this pin deliberately
36
+ * after verifying the new release still starts on the supported Node floor.
37
+ */
38
+ export const MCP_REMOTE_VERSION = "0.1.38";
39
+
40
+ /** Pinned npm spec used in the registered command, e.g. `mcp-remote@0.1.38`. */
41
+ export const MCP_REMOTE_PACKAGE = `mcp-remote@${MCP_REMOTE_VERSION}`;
42
+
43
+ /**
44
+ * Minimum Node.js version required for the registered mcp-remote bridge to
45
+ * start. `mcp-remote@0.1.38` depends on `undici@^7.12.0`, and every undici 7
46
+ * release declares `engines.node >= 20.18.1`. npm's engine check is only a
47
+ * warning by default, so nothing stops a below-floor Node from resolving the
48
+ * tree and then crashing the bridge — we hard-fail preflight here instead of
49
+ * writing a config that cannot start. Bump this in lockstep with the pinned
50
+ * `mcp-remote` version above (and the advertised floors in package.json,
51
+ * mcpb/manifest.json, and the docs) after verifying the new dependency tree's
52
+ * engine requirement.
53
+ */
54
+ export const MIN_NODE_VERSION = "20.18.1";
55
+
56
+ /**
57
+ * Structured form of {@link MIN_NODE_VERSION}, parsed once so the preflight can
58
+ * compare major/minor/patch without re-parsing on every call.
59
+ */
60
+ export const MIN_NODE = parseNodeVersion(MIN_NODE_VERSION);
61
+
62
+ /**
63
+ * Parse a `process.version`-style string into its numeric {major, minor, patch}
64
+ * components (e.g. "v20.18.1" -> {major:20, minor:18, patch:1}). A missing
65
+ * minor/patch defaults to 0. Returns null when unparseable.
66
+ *
67
+ * The regex is end-anchored and rejects any trailing characters, including a
68
+ * semver prerelease/build suffix (`-rc.1`, `-nightly`, `+build`). A prerelease
69
+ * like `20.18.1-rc.1` sorts *below* the stable `20.18.1` under semver, so we
70
+ * must not silently discard the suffix and treat it as the stable release —
71
+ * that would let a below-floor prerelease pass the preflight. Returning null
72
+ * here routes such versions through `nodeMeetsFloor`'s not-satisfied path.
73
+ *
74
+ * @param {string} version
75
+ * @returns {{major:number, minor:number, patch:number}|null}
76
+ */
77
+ export function parseNodeVersion(version) {
78
+ const match = /^v?(\d+)(?:\.(\d+))?(?:\.(\d+))?$/.exec(String(version));
79
+ if (!match) return null;
80
+ const major = Number(match[1]);
81
+ const minor = Number(match[2] ?? 0);
82
+ const patch = Number(match[3] ?? 0);
83
+ if (![major, minor, patch].every(Number.isFinite)) return null;
84
+ return { major, minor, patch };
85
+ }
86
+
87
+ /**
88
+ * Does `version` meet the {@link MIN_NODE} floor (>= major.minor.patch)?
89
+ *
90
+ * Three cases:
91
+ * - A clean `X.Y.Z` at/above the floor → true; below → false.
92
+ * - A *version-shaped* string that isn't a clean release — a prerelease
93
+ * (`20.18.1-rc.1`) or trailing garbage (`20.19.0-night,`) — → false. Under
94
+ * semver a prerelease sorts below its release, so it does NOT satisfy
95
+ * `>=20.18.1`; we reject rather than accept an ambiguous runtime.
96
+ * - Input that isn't version-shaped at all → true. We stay lenient on strings
97
+ * we can't read (the same stance the previous major-only check took);
98
+ * `process.version` never produces these, so this only guards odd stubs.
99
+ *
100
+ * @param {string} version
101
+ * @returns {boolean}
102
+ */
103
+ export function nodeMeetsFloor(version) {
104
+ const parsed = parseNodeVersion(version);
105
+ if (parsed === null) {
106
+ // Version-shaped (leading digits, optionally `v`-prefixed) but not a clean
107
+ // X.Y.Z — i.e. it carried a prerelease/build suffix or trailing chars.
108
+ // Treat as not satisfying the floor. Truly non-version input is lenient.
109
+ return !/^v?\d/.test(String(version));
110
+ }
111
+ if (parsed.major !== MIN_NODE.major) return parsed.major > MIN_NODE.major;
112
+ if (parsed.minor !== MIN_NODE.minor) return parsed.minor > MIN_NODE.minor;
113
+ return parsed.patch >= MIN_NODE.patch;
114
+ }
115
+
21
116
  /**
22
117
  * Claude Desktop adapter.
23
118
  *
@@ -31,7 +126,7 @@ import {
31
126
  *
32
127
  * "meko": {
33
128
  * "command": "npx",
34
- * "args": ["-y", "mcp-remote", "<url>", "--transport", "http-only",
129
+ * "args": ["-y", "mcp-remote@<pinned>", "<url>", "--transport", "http-only",
35
130
  * "--header", "User-Agent:meko-mcp-installer/1.0 (...)",
36
131
  * "--header", "Authorization:Bearer ${MEKO_API_KEY}"],
37
132
  * "env": { "MEKO_API_KEY": "<key>" }
@@ -53,6 +148,7 @@ export function createClaudeDesktopAdapter(options = {}) {
53
148
  const assetRootResolver = options.getAssetRoot ?? getAssetRoot;
54
149
  const packageRunner = options.runPackageScript ?? defaultRunPackageScript;
55
150
  const npxProber = options.probeNpx ?? defaultProbeNpx;
151
+ const nodeVersionResolver = options.getNodeVersion ?? (() => process.version);
56
152
 
57
153
  return {
58
154
  id: "claude-desktop",
@@ -61,12 +157,27 @@ export function createClaudeDesktopAdapter(options = {}) {
61
157
  return configPathResolver();
62
158
  },
63
159
  async detectPrerequisites({ log, verbose } = {}) {
160
+ // The registered mcp-remote bridge pulls in undici@^7, whose every
161
+ // release declares engines.node >= 20.18.1; below that floor the bridge
162
+ // crashes at startup and Claude Desktop shows "Server disconnected". A
163
+ // major-only check would wave through Node 20.0.0–20.18.0, so we parse
164
+ // the full version and reject anything below the exact floor here,
165
+ // before writing a config that Claude Desktop cannot start.
166
+ const nodeVersion = nodeVersionResolver();
167
+ if (!nodeMeetsFloor(nodeVersion)) {
168
+ throw new Error(
169
+ `Node >= ${MIN_NODE_VERSION} is required for the mcp-remote bridge that ` +
170
+ `Claude Desktop launches (detected ${nodeVersion}). Older Node ` +
171
+ `versions crash the bridge at startup and Claude Desktop shows ` +
172
+ `"Server disconnected". Upgrade Node.js and re-run the installer.`,
173
+ );
174
+ }
64
175
  const npx = npxProber();
65
176
  if (!npx.found) {
66
177
  throw new Error(
67
178
  "npx (from Node.js) is required so Claude Desktop can launch the " +
68
- "mcp-remote stdio bridge. Install Node.js 18+ (which includes npx) " +
69
- "and re-run the installer.",
179
+ `mcp-remote stdio bridge. Install Node.js ${MIN_NODE_VERSION}+ (which ` +
180
+ "includes npx) and re-run the installer.",
70
181
  );
71
182
  }
72
183
  if (verbose && log?.dim) {
@@ -283,7 +394,7 @@ export function createClaudeDesktopAdapter(options = {}) {
283
394
  export function buildMcpRemoteEntry({ url, apiKey }) {
284
395
  const args = [
285
396
  "-y",
286
- "mcp-remote",
397
+ MCP_REMOTE_PACKAGE,
287
398
  url,
288
399
  "--transport",
289
400
  "http-only",
@@ -309,7 +420,11 @@ export function getMcpRemoteEntryUrl(entry) {
309
420
  }
310
421
  if (typeof entry?.url === "string") return entry.url;
311
422
  if (!Array.isArray(entry?.args)) return undefined;
312
- const remoteIndex = entry.args.indexOf("mcp-remote");
423
+ // Match both the bare `mcp-remote` (legacy entries) and the pinned
424
+ // `mcp-remote@<version>` spec the installer now writes.
425
+ const remoteIndex = entry.args.findIndex(
426
+ (arg) => arg === "mcp-remote" || (typeof arg === "string" && arg.startsWith("mcp-remote@")),
427
+ );
313
428
  const candidate = remoteIndex >= 0 ? entry.args[remoteIndex + 1] : undefined;
314
429
  return typeof candidate === "string" ? candidate : undefined;
315
430
  }
@@ -97,6 +97,7 @@ const MEKO_HOOK_SCRIPTS = [
97
97
  * getAgentsMdPath?: () => string,
98
98
  * getHooksPath?: () => string,
99
99
  * getSkillsRoot?: () => string,
100
+ * resolveSkillSource?: (name: string) => string,
100
101
  * resolveHooksRoot?: () => string,
101
102
  * getHooksInstallRoot?: () => string,
102
103
  * runCommand?: (cmd: string) => string,
@@ -113,6 +114,8 @@ export function createCodexAdapter(options = {}) {
113
114
  const resolveHooksPath = options.getHooksPath ?? getCodexHooksPath;
114
115
  const resolveMekoEnvFilePath =
115
116
  options.getMekoEnvFilePath ?? getCodexMekoEnvFilePath;
117
+ const resolveSkillSourcePath =
118
+ options.resolveSkillSource ?? resolveSkillSource;
116
119
  const resolveHooksRootPath = options.resolveHooksRoot ?? resolveHooksRoot;
117
120
  const resolveHooksInstallRoot =
118
121
  options.getHooksInstallRoot ?? getCodexHooksInstallRoot;
@@ -439,7 +442,7 @@ export function createCodexAdapter(options = {}) {
439
442
 
440
443
  mkdirSync(skillsRoot, { recursive: true });
441
444
  for (const skill of SKILLS) {
442
- const source = resolveSkillSource(skill.name);
445
+ const source = resolveSkillSourcePath(skill.name);
443
446
  const destination = join(skillsRoot, skill.name);
444
447
 
445
448
  if (existsSync(destination)) {
@@ -517,7 +520,7 @@ export function createCodexAdapter(options = {}) {
517
520
  removePath(dest);
518
521
  continue;
519
522
  }
520
- const expectedSource = resolveSkillSource(skill.name);
523
+ const expectedSource = resolveSkillSourcePath(skill.name);
521
524
  if (isOwnSymlink(dest, expectedSource)) removePath(dest);
522
525
  }
523
526
  results.push({
@@ -1314,7 +1317,7 @@ function renderAgentsMdBlock(version, name) {
1314
1317
  `${AGENTS_MD_START} v${version}`,
1315
1318
  "## Meko memory (auto-managed by meko installer)",
1316
1319
  "",
1317
- `You have a persistent memory store via the \`${name}\` MCP server. At the start of every conversation, call \`${toolPrefix}memory_search\` for relevant context. When the user shares facts, preferences, or decisions worth remembering, call \`${toolPrefix}memory_add\`. Skill details: ~/.agents/skills/meko-mcp-tools/SKILL.md`,
1320
+ `You have a persistent memory store via the \`${name}\` MCP server. At the start of every conversation, call \`${toolPrefix}memory_search\` for relevant personal context; use \`${toolPrefix}knowledgebase_search\` when the request concerns shared datapack knowledge. When the user shares facts, preferences, or decisions worth remembering, call \`${toolPrefix}memory_add\`. Skill details: ~/.agents/skills/meko-mcp-tools/SKILL.md`,
1318
1321
  "",
1319
1322
  "Cloud auth requires `MEKO_API_KEY` exported in your shell (or, for the desktop app on macOS, set via `launchctl setenv`).",
1320
1323
  AGENTS_MD_END,
@@ -2,6 +2,7 @@ import { createClaudeCodeAdapter } from "./claude-code.mjs";
2
2
  import { createClaudeDesktopAdapter } from "./claude-desktop.mjs";
3
3
  import { createCodexAdapter } from "./codex.mjs";
4
4
  import { createCursorAdapter } from "./cursor.mjs";
5
+ import { createKiroAdapter } from "./kiro.mjs";
5
6
 
6
7
  /**
7
8
  * @returns {Record<string, object>}
@@ -12,5 +13,6 @@ export function getClientAdapters() {
12
13
  "claude-desktop": createClaudeDesktopAdapter(),
13
14
  cursor: createCursorAdapter(),
14
15
  codex: createCodexAdapter(),
16
+ kiro: createKiroAdapter(),
15
17
  };
16
18
  }