@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.
- package/README.md +152 -27
- package/assets/hooks-handlers/codex-session-end.sh +4 -69
- package/assets/hooks-handlers/cursor-session-start.sh +19 -1
- package/assets/hooks-handlers/lib/capture-notices.js +321 -0
- package/assets/hooks-handlers/lib/capture-state.js +2079 -0
- package/assets/hooks-handlers/lib/capture-status-cli.js +82 -0
- package/assets/hooks-handlers/lib/capture.js +1578 -299
- package/assets/hooks-handlers/lib/checkpoint-timer.js +444 -81
- package/assets/hooks-handlers/lib/kiro-handler.js +738 -0
- package/assets/hooks-handlers/lib/terminal-handoff.js +418 -0
- package/assets/hooks-handlers/session-end.sh +3 -34
- package/assets/scripts/meko-statusline.sh +41 -1
- package/assets/skills/meko-mcp-tools/SKILL.md +72 -125
- package/assets/skills/meko-mcp-tools/references/_sections.md +2 -2
- package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +12 -13
- package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +15 -12
- package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +25 -1
- package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +19 -77
- package/assets/skills/meko-mcp-tools/references/tools-overview.md +8 -7
- package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +22 -1
- package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +1 -1
- package/assets/skills/meko-mcp-tools-desktop/SKILL.md +8 -8
- package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +1 -1
- package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +1 -1
- package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +6 -1
- package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +6 -5
- package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +4 -4
- package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +7 -6
- package/assets/skills/meko-select-datapack-desktop/SKILL.md +1 -1
- package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +3 -3
- package/bin/create-meko-setup.mjs +48 -10
- package/lib/capture-status.mjs +67 -0
- package/lib/clients/aliases.mjs +5 -0
- package/lib/clients/claude-desktop.mjs +120 -5
- package/lib/clients/codex.mjs +6 -3
- package/lib/clients/index.mjs +2 -0
- package/lib/clients/kiro.mjs +705 -0
- package/lib/config.mjs +90 -0
- package/lib/installer.mjs +1 -0
- package/lib/migrate/adapters/codex.mjs +490 -0
- package/lib/migrate/id.mjs +28 -3
- package/lib/migrate/orchestrator.mjs +34 -7
- package/lib/migrate.mjs +4 -2
- package/lib/prompt.mjs +16 -1
- 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
|
|
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
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
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
|
+
}
|
package/lib/clients/aliases.mjs
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|
package/lib/clients/codex.mjs
CHANGED
|
@@ -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 =
|
|
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 =
|
|
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,
|
package/lib/clients/index.mjs
CHANGED
|
@@ -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
|
}
|