@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.
- package/README.md +233 -40
- 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-cleanup-cli.js +1473 -0
- package/assets/hooks-handlers/lib/capture-notices.js +438 -0
- package/assets/hooks-handlers/lib/capture-state.js +2173 -0
- package/assets/hooks-handlers/lib/capture-status-cli.js +86 -0
- package/assets/hooks-handlers/lib/capture.js +2782 -403
- package/assets/hooks-handlers/lib/checkpoint-timer.js +485 -81
- package/assets/hooks-handlers/lib/journal-bridge.js +218 -0
- package/assets/hooks-handlers/lib/kiro-handler.js +760 -0
- package/assets/hooks-handlers/lib/opencode-handler.js +620 -0
- package/assets/hooks-handlers/lib/opencode-normalizer.js +145 -0
- package/assets/hooks-handlers/lib/terminal-handoff.js +427 -0
- package/assets/hooks-handlers/session-end.sh +3 -34
- package/assets/opencode-plugin/meko.js +213 -0
- package/assets/scripts/meko-statusline.sh +123 -16
- package/assets/skills/meko-mcp-tools/SKILL.md +116 -126
- package/assets/skills/meko-mcp-tools/references/_sections.md +3 -3
- package/assets/skills/meko-mcp-tools/references/tools-agent-id-conventions.md +25 -18
- package/assets/skills/meko-mcp-tools/references/tools-cookbook.md +99 -24
- package/assets/skills/meko-mcp-tools/references/tools-datapack-workflow.md +1 -1
- package/assets/skills/meko-mcp-tools/references/tools-known-limitations.md +53 -6
- package/assets/skills/meko-mcp-tools/references/tools-memory-vs-conversation.md +25 -79
- package/assets/skills/meko-mcp-tools/references/tools-overview.md +37 -26
- package/assets/skills/meko-mcp-tools/references/tools-rag-workflow.md +14 -8
- package/assets/skills/meko-mcp-tools/references/tools-troubleshooting.md +66 -1
- package/assets/skills/meko-mcp-tools/references/tools-user-id-conventions.md +7 -40
- package/assets/skills/meko-mcp-tools-desktop/SKILL.md +56 -20
- 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 +15 -8
- package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +99 -36
- package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +22 -5
- package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +18 -14
- package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +39 -28
- package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +14 -8
- package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +67 -1
- package/assets/skills/meko-select-datapack-desktop/SKILL.md +4 -4
- package/assets/skills/meko-select-datapack-desktop/references/cookbook.md +8 -8
- package/assets/skills/meko-select-datapack-desktop/references/role-display-future.md +7 -5
- package/assets/skills/meko-select-datapack-desktop/references/troubleshooting.md +4 -4
- package/bin/create-meko-setup.mjs +113 -12
- package/lib/capture-cleanup.mjs +63 -0
- package/lib/capture-status.mjs +67 -0
- package/lib/clients/aliases.mjs +5 -0
- package/lib/clients/claude-code.mjs +1 -0
- package/lib/clients/claude-desktop.mjs +120 -5
- package/lib/clients/codex.mjs +85 -37
- package/lib/clients/common.mjs +7 -0
- package/lib/clients/index.mjs +4 -0
- package/lib/clients/kiro.mjs +705 -0
- package/lib/clients/opencode.mjs +532 -0
- package/lib/config.mjs +158 -1
- package/lib/installer.mjs +18 -1
- package/lib/migrate/adapters/claude-code.mjs +11 -2
- package/lib/migrate/adapters/codex.mjs +497 -0
- package/lib/migrate/adapters/memory-md.mjs +27 -8
- package/lib/migrate/adapters/opencode.mjs +148 -0
- package/lib/migrate/claude-parser.mjs +153 -9
- package/lib/migrate/id.mjs +217 -10
- package/lib/migrate/mcp-client.mjs +25 -1
- package/lib/migrate/opencode-normalizer.mjs +132 -0
- package/lib/migrate/orchestrator.mjs +299 -56
- package/lib/migrate/progress.mjs +239 -5
- package/lib/migrate/registry.mjs +72 -0
- package/lib/migrate.mjs +100 -10
- package/lib/prompt.mjs +16 -1
- package/package.json +4 -4
- package/scripts/bundle-assets.mjs +4 -0
|
@@ -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;
|
|
@@ -251,7 +254,7 @@ export function createCodexAdapter(options = {}) {
|
|
|
251
254
|
const next = removeCodexConfigBlock(raw, name);
|
|
252
255
|
if (next !== raw) writeWithBackup(path, next);
|
|
253
256
|
},
|
|
254
|
-
async registerServer({ name, url, apiKey, dryRun, verbose, log, scope
|
|
257
|
+
async registerServer({ name, url, apiKey, dryRun, verbose, log, scope }) {
|
|
255
258
|
const path = settingsPathFor(scope, log);
|
|
256
259
|
const useApiKey = apiKey ? "MEKO_API_KEY" : null;
|
|
257
260
|
const cliCmd = buildCliRegisterCommand(name, url, useApiKey);
|
|
@@ -350,35 +353,6 @@ export function createCodexAdapter(options = {}) {
|
|
|
350
353
|
// Cloud auth UX: env-var-only model. The key is never written to
|
|
351
354
|
// config.toml; the user's runtime env supplies it. Print actionable
|
|
352
355
|
// instructions and (when interactive) offer to wire things up.
|
|
353
|
-
if (apiKey) {
|
|
354
|
-
const platform = surfaces.app?.platform ?? process.platform;
|
|
355
|
-
const hasApp = Boolean(surfaces.app);
|
|
356
|
-
const shellRc = detectShellRc();
|
|
357
|
-
printCloudAuthInstructions({ shellRc, hasApp, platform, log });
|
|
358
|
-
if (!yes) {
|
|
359
|
-
await maybeOfferRcAppend({
|
|
360
|
-
apiKey,
|
|
361
|
-
shellRc,
|
|
362
|
-
promptUser,
|
|
363
|
-
log,
|
|
364
|
-
});
|
|
365
|
-
if (hasApp && platform === "darwin") {
|
|
366
|
-
await maybeOfferLaunchctlSetenv({
|
|
367
|
-
apiKey,
|
|
368
|
-
promptUser,
|
|
369
|
-
runCommand,
|
|
370
|
-
log,
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
} else if (hasApp && platform === "darwin") {
|
|
374
|
-
setLaunchctlMekoApiKey({
|
|
375
|
-
apiKey,
|
|
376
|
-
runCommand,
|
|
377
|
-
log,
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
356
|
if (surfaces.app) {
|
|
383
357
|
log.dim?.(" Restart Codex.app to attach the new MCP server.");
|
|
384
358
|
}
|
|
@@ -424,6 +398,61 @@ export function createCodexAdapter(options = {}) {
|
|
|
424
398
|
);
|
|
425
399
|
}
|
|
426
400
|
},
|
|
401
|
+
/**
|
|
402
|
+
* Cloud auth UX: env-var-only model. The key is never written to
|
|
403
|
+
* config.toml, so the user's runtime env must supply it. This is a
|
|
404
|
+
* separate adapter step (not part of registerServer) because an
|
|
405
|
+
* interactive reinstall where the user declines the overwrite prompt
|
|
406
|
+
* skips registration entirely - and the launchd env would otherwise
|
|
407
|
+
* never be refreshed after a key rotation. See
|
|
408
|
+
* yugabyte/meko-mcp-server#337.
|
|
409
|
+
*/
|
|
410
|
+
async syncCloudAuthEnvironment({ apiKey, dryRun, log, yes }) {
|
|
411
|
+
if (!apiKey || dryRun) return;
|
|
412
|
+
const platform = surfaces.app?.platform ?? process.platform;
|
|
413
|
+
const hasApp = Boolean(surfaces.app);
|
|
414
|
+
const shellRc = detectShellRc();
|
|
415
|
+
printCloudAuthInstructions({ shellRc, hasApp, platform, log });
|
|
416
|
+
if (!yes) {
|
|
417
|
+
// Offer launchctl BEFORE rc-append, and isolate the rc-append
|
|
418
|
+
// failure mode. `maybeOfferRcAppend` throws when the shell rc is
|
|
419
|
+
// fish and the API key contains a `'` (fish single-quoting can't
|
|
420
|
+
// escape it). If that threw first, the launchctl offer - the
|
|
421
|
+
// yugabyte/meko-mcp-server#337 fix - would never run.
|
|
422
|
+
//
|
|
423
|
+
// macOS: offer launchctl setenv regardless of whether Codex.app
|
|
424
|
+
// is present. Spotlight- and Alfred-launched Codex CLI reads the
|
|
425
|
+
// launchd env too. Login-session inheritance means every
|
|
426
|
+
// GUI-launched process in this session then sees MEKO_API_KEY
|
|
427
|
+
// (visible via `launchctl getenv`, `ps e` on descendants,
|
|
428
|
+
// crash reports); the prompt copy calls that out so the choice
|
|
429
|
+
// is informed.
|
|
430
|
+
if (platform === "darwin") {
|
|
431
|
+
await maybeOfferLaunchctlSetenv({
|
|
432
|
+
apiKey,
|
|
433
|
+
promptUser,
|
|
434
|
+
runCommand,
|
|
435
|
+
log,
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
try {
|
|
439
|
+
await maybeOfferRcAppend({
|
|
440
|
+
apiKey,
|
|
441
|
+
shellRc,
|
|
442
|
+
promptUser,
|
|
443
|
+
log,
|
|
444
|
+
});
|
|
445
|
+
} catch (err) {
|
|
446
|
+
log?.warn?.(` Skipping shell rc append: ${err.message}`);
|
|
447
|
+
}
|
|
448
|
+
} else if (platform === "darwin") {
|
|
449
|
+
setLaunchctlMekoApiKey({
|
|
450
|
+
apiKey,
|
|
451
|
+
runCommand,
|
|
452
|
+
log,
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
},
|
|
427
456
|
installSkills({ dryRun, log, scope, name }) {
|
|
428
457
|
void scope; // Codex skills are user-scope only.
|
|
429
458
|
const serverName = name ?? "meko";
|
|
@@ -439,7 +468,7 @@ export function createCodexAdapter(options = {}) {
|
|
|
439
468
|
|
|
440
469
|
mkdirSync(skillsRoot, { recursive: true });
|
|
441
470
|
for (const skill of SKILLS) {
|
|
442
|
-
const source =
|
|
471
|
+
const source = resolveSkillSourcePath(skill.name);
|
|
443
472
|
const destination = join(skillsRoot, skill.name);
|
|
444
473
|
|
|
445
474
|
if (existsSync(destination)) {
|
|
@@ -517,7 +546,7 @@ export function createCodexAdapter(options = {}) {
|
|
|
517
546
|
removePath(dest);
|
|
518
547
|
continue;
|
|
519
548
|
}
|
|
520
|
-
const expectedSource =
|
|
549
|
+
const expectedSource = resolveSkillSourcePath(skill.name);
|
|
521
550
|
if (isOwnSymlink(dest, expectedSource)) removePath(dest);
|
|
522
551
|
}
|
|
523
552
|
results.push({
|
|
@@ -1314,7 +1343,7 @@ function renderAgentsMdBlock(version, name) {
|
|
|
1314
1343
|
`${AGENTS_MD_START} v${version}`,
|
|
1315
1344
|
"## Meko memory (auto-managed by meko installer)",
|
|
1316
1345
|
"",
|
|
1317
|
-
`You have a persistent memory store via the \`${name}\` MCP server. At the start of every conversation, call \`${toolPrefix}
|
|
1346
|
+
`You have a persistent memory store via the \`${name}\` MCP server. At the start of every conversation, call \`${toolPrefix}context_search\` for relevant context: it returns personal memory, shared datapack knowledge, and past conversations in one call. Use \`${toolPrefix}memory_search\` or \`${toolPrefix}knowledgebase_search\` when you need a single source. When the user shares facts, preferences, or decisions worth remembering, call \`${toolPrefix}memory_add\`. Skill details: ~/.agents/skills/meko-mcp-tools/SKILL.md`,
|
|
1318
1347
|
"",
|
|
1319
1348
|
"Cloud auth requires `MEKO_API_KEY` exported in your shell (or, for the desktop app on macOS, set via `launchctl setenv`).",
|
|
1320
1349
|
AGENTS_MD_END,
|
|
@@ -1347,9 +1376,16 @@ function printCloudAuthInstructions({ shellRc, hasApp, platform, log }) {
|
|
|
1347
1376
|
log.dim?.(` fish: set -gx MEKO_API_KEY '<your-meko-api-key>'`);
|
|
1348
1377
|
}
|
|
1349
1378
|
log.dim?.(` Then open a new terminal (or run "exec $SHELL" / "exec fish").`);
|
|
1350
|
-
if (
|
|
1379
|
+
if (platform === "darwin") {
|
|
1380
|
+
// Explain launchd for both Codex.app and CLI-only macOS installs.
|
|
1381
|
+
// GUI-launched Codex (Finder, Dock, Spotlight, Alfred, `open -a`) reads
|
|
1382
|
+
// launchd's env, not the shell rc, so a fresh install or a rotated key
|
|
1383
|
+
// needs `launchctl setenv` to propagate. Shell-launched CLI still
|
|
1384
|
+
// reads its shell rc.
|
|
1351
1385
|
log.warn?.(
|
|
1352
|
-
|
|
1386
|
+
hasApp
|
|
1387
|
+
? "macOS Codex.app launched from Finder/Dock does NOT inherit shell rc - set it via launchctl too:"
|
|
1388
|
+
: "macOS Codex CLI launched from Spotlight/Alfred/`open` does NOT inherit shell rc - set it via launchctl too:",
|
|
1353
1389
|
);
|
|
1354
1390
|
log.dim?.(
|
|
1355
1391
|
` launchctl setenv MEKO_API_KEY '<your-meko-api-key>' # current login session`,
|
|
@@ -1357,6 +1393,9 @@ function printCloudAuthInstructions({ shellRc, hasApp, platform, log }) {
|
|
|
1357
1393
|
log.dim?.(
|
|
1358
1394
|
" (For permanence across reboots, add a ~/Library/LaunchAgents/com.meko.env.plist.)",
|
|
1359
1395
|
);
|
|
1396
|
+
log.warn?.(
|
|
1397
|
+
" launchctl setenv writes to the login session's env, which every subsequently GUI-launched process inherits (visible via `launchctl getenv`, `ps e` on descendants, and crash reports).",
|
|
1398
|
+
);
|
|
1360
1399
|
}
|
|
1361
1400
|
}
|
|
1362
1401
|
|
|
@@ -1440,9 +1479,15 @@ export async function maybeOfferLaunchctlSetenv({
|
|
|
1440
1479
|
runCommand,
|
|
1441
1480
|
log,
|
|
1442
1481
|
}) {
|
|
1482
|
+
// Default to Yes: this is the setting that makes GUI-launched Codex on
|
|
1483
|
+
// macOS see the fresh key. Users who habitually hit Enter at the prompt
|
|
1484
|
+
// otherwise leave launchd empty and Codex authenticates with whatever key
|
|
1485
|
+
// it had at first start. See yugabyte/meko-mcp-server#337. The prompt
|
|
1486
|
+
// names both Codex.app and Spotlight-launched CLI so a user without the
|
|
1487
|
+
// desktop app understands why the offer applies to them.
|
|
1443
1488
|
const accept = await promptUser(
|
|
1444
|
-
"Run `launchctl setenv MEKO_API_KEY ...` so Codex
|
|
1445
|
-
|
|
1489
|
+
"Run `launchctl setenv MEKO_API_KEY ...` so GUI-launched Codex (App, Spotlight, Alfred, `open`) sees the key now? (writes the key into the login session env, inherited by every subsequently GUI-launched process)",
|
|
1490
|
+
true,
|
|
1446
1491
|
);
|
|
1447
1492
|
if (!accept) return { set: false };
|
|
1448
1493
|
return setLaunchctlMekoApiKey({ apiKey, runCommand, log });
|
|
@@ -1460,6 +1505,9 @@ export function setLaunchctlMekoApiKey({ apiKey, runCommand, log }) {
|
|
|
1460
1505
|
try {
|
|
1461
1506
|
runCommand(`launchctl setenv MEKO_API_KEY ${shellQuote(apiKey)}`);
|
|
1462
1507
|
log?.dim?.(" Set MEKO_API_KEY via launchctl (current login session).");
|
|
1508
|
+
log?.warn?.(
|
|
1509
|
+
" Fully quit any running Codex (Cmd-Q, or `pkill -x codex` for the CLI) and relaunch — a process already running will keep its previous MEKO_API_KEY.",
|
|
1510
|
+
);
|
|
1463
1511
|
return { set: true };
|
|
1464
1512
|
} catch (err) {
|
|
1465
1513
|
log?.warn?.(" launchctl setenv failed; run it manually if Codex.app needs cloud auth.");
|
package/lib/clients/common.mjs
CHANGED
|
@@ -88,6 +88,13 @@ export function resolveHooksRoot() {
|
|
|
88
88
|
return join(getAssetRoot(), "hooks-handlers");
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
/**
|
|
92
|
+
* @returns {string} absolute path to the installer-owned OpenCode plugin source
|
|
93
|
+
*/
|
|
94
|
+
export function resolveOpenCodePluginSource() {
|
|
95
|
+
return join(getAssetRoot(), "opencode-plugin", "meko.js");
|
|
96
|
+
}
|
|
97
|
+
|
|
91
98
|
/**
|
|
92
99
|
* @returns {string} absolute path to the statusline script source.
|
|
93
100
|
* Lives under skills/scripts/ in source, mirrored under assets/scripts/ in
|
package/lib/clients/index.mjs
CHANGED
|
@@ -2,6 +2,8 @@ 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";
|
|
6
|
+
import { createOpenCodeAdapter } from "./opencode.mjs";
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* @returns {Record<string, object>}
|
|
@@ -12,5 +14,7 @@ export function getClientAdapters() {
|
|
|
12
14
|
"claude-desktop": createClaudeDesktopAdapter(),
|
|
13
15
|
cursor: createCursorAdapter(),
|
|
14
16
|
codex: createCodexAdapter(),
|
|
17
|
+
kiro: createKiroAdapter(),
|
|
18
|
+
opencode: createOpenCodeAdapter(),
|
|
15
19
|
};
|
|
16
20
|
}
|