@yugabytedb/meko-mcp 1.1.0 → 1.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 +68 -19
- package/assets/hooks-handlers/before-submit-prompt.sh +44 -0
- package/assets/hooks-handlers/cursor-session-start.sh +42 -0
- package/assets/hooks-handlers/lib/capture.js +291 -40
- package/assets/scripts/package-desktop-skill.sh +36 -0
- package/assets/skills/meko-mcp-tools/references/tools-overview.md +1 -1
- package/assets/skills/meko-mcp-tools-desktop/SKILL.md +251 -0
- package/assets/skills/meko-mcp-tools-desktop/desktop/README.md +150 -0
- package/assets/skills/meko-mcp-tools-desktop/references/_sections.md +24 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-agent-id-conventions.md +99 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-cookbook.md +406 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-known-limitations.md +69 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-memory-vs-conversation.md +217 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-overview.md +112 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-rag-workflow.md +134 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-scope-permissions.md +75 -0
- package/assets/skills/meko-mcp-tools-desktop/references/tools-troubleshooting.md +155 -0
- package/bin/create-meko-setup.mjs +4 -4
- package/lib/clients/claude-desktop.mjs +11 -8
- package/lib/clients/codex.mjs +236 -4
- package/lib/clients/common.mjs +81 -0
- package/lib/clients/cursor.mjs +47 -10
- package/lib/config.mjs +26 -0
- package/lib/installer.mjs +2 -2
- package/package.json +1 -1
- package/scripts/bundle-assets.mjs +8 -0
package/lib/clients/cursor.mjs
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
} from "../config.mjs";
|
|
18
18
|
import {
|
|
19
19
|
getInstallerVersion,
|
|
20
|
+
isDanglingSymlink,
|
|
20
21
|
markerIsStale,
|
|
21
22
|
readInstallerMarker,
|
|
22
23
|
resolveHooksRoot,
|
|
@@ -29,7 +30,8 @@ import {
|
|
|
29
30
|
const SKILLS = [{ name: "meko-mcp-tools" }];
|
|
30
31
|
|
|
31
32
|
const HOOKS = [
|
|
32
|
-
{ event: "sessionStart", script: "session-start.sh", timeout: 15000 },
|
|
33
|
+
{ event: "sessionStart", script: "cursor-session-start.sh", timeout: 15000 },
|
|
34
|
+
{ event: "beforeSubmitPrompt", script: "before-submit-prompt.sh", matcher: "UserPromptSubmit", timeout: 2000 },
|
|
33
35
|
{ event: "preCompact", script: "pre-compact.sh" },
|
|
34
36
|
{ event: "sessionEnd", script: "session-end.sh", timeout: 30000 },
|
|
35
37
|
];
|
|
@@ -101,21 +103,21 @@ export function createCursorAdapter(customPaths = {}) {
|
|
|
101
103
|
writeJsonFile(mcpPath, cfg);
|
|
102
104
|
},
|
|
103
105
|
setHookEnvironment({ url, apiKey, dryRun, log, scope, projectRoot, cursorHookMode }) {
|
|
104
|
-
const mode = cursorHookMode || "
|
|
106
|
+
const mode = cursorHookMode || "native";
|
|
105
107
|
if (dryRun) {
|
|
106
|
-
if (mode === "native"
|
|
108
|
+
if (mode === "native") {
|
|
107
109
|
log.dim(` Would configure Cursor hooks at ${paths.getHooksPath(scope, projectRoot)}`);
|
|
108
110
|
}
|
|
109
|
-
if (mode === "claude-compat"
|
|
111
|
+
if (mode === "claude-compat") {
|
|
110
112
|
log.dim(` Would configure Claude-compatible hooks at ${paths.getClaudeCompatSettingsPath(scope, projectRoot)}`);
|
|
111
113
|
}
|
|
112
114
|
return;
|
|
113
115
|
}
|
|
114
116
|
|
|
115
|
-
if (mode === "native"
|
|
117
|
+
if (mode === "native") {
|
|
116
118
|
installNativeCursorHooks({ scope, projectRoot, url, apiKey, paths });
|
|
117
119
|
}
|
|
118
|
-
if (mode === "claude-compat"
|
|
120
|
+
if (mode === "claude-compat") {
|
|
119
121
|
installClaudeCompatHooks({ scope, projectRoot, url, apiKey, paths });
|
|
120
122
|
}
|
|
121
123
|
},
|
|
@@ -159,6 +161,15 @@ export function createCursorAdapter(customPaths = {}) {
|
|
|
159
161
|
// Same version already deployed — nothing to do.
|
|
160
162
|
continue;
|
|
161
163
|
}
|
|
164
|
+
} else if (isDanglingSymlink(destination)) {
|
|
165
|
+
// Stale symlink left behind by an earlier install whose target
|
|
166
|
+
// (e.g. a deleted worktree) no longer exists. existsSync is false
|
|
167
|
+
// for these, so the branch above misses them. Clear it so the
|
|
168
|
+
// fresh-install path below can replace it cleanly.
|
|
169
|
+
log.dim?.(
|
|
170
|
+
` Replacing dangling symlink at ${destination} (target missing).`,
|
|
171
|
+
);
|
|
172
|
+
removePath(destination);
|
|
162
173
|
}
|
|
163
174
|
|
|
164
175
|
const strategy = symlinkOrCopy(source, destination);
|
|
@@ -186,7 +197,7 @@ export function createCursorAdapter(customPaths = {}) {
|
|
|
186
197
|
uninstallCursorHooks({
|
|
187
198
|
scope,
|
|
188
199
|
projectRoot,
|
|
189
|
-
mode: cursorHookMode || "
|
|
200
|
+
mode: cursorHookMode || "native",
|
|
190
201
|
paths,
|
|
191
202
|
});
|
|
192
203
|
results.push({ key: "hooks", ok: true, message: "Cursor hook configuration cleaned up." });
|
|
@@ -243,10 +254,12 @@ function installNativeCursorHooks({ scope, projectRoot, url, apiKey, paths }) {
|
|
|
243
254
|
}
|
|
244
255
|
|
|
245
256
|
const handlersRoot = resolveHooksRoot();
|
|
257
|
+
pruneNativeCursorMekoHooks(cfg.hooks);
|
|
246
258
|
for (const hook of HOOKS) {
|
|
247
259
|
const scriptPath = join(handlersRoot, hook.script);
|
|
248
260
|
const entry = { command: buildScriptCommand({ scriptPath }) };
|
|
249
261
|
if (hook.timeout) entry.timeout = hook.timeout;
|
|
262
|
+
if (hook.matcher) entry.matcher = hook.matcher;
|
|
250
263
|
upsertHookEntry(cfg.hooks, hook.event, entry);
|
|
251
264
|
}
|
|
252
265
|
|
|
@@ -305,6 +318,30 @@ function upsertHookEntry(hooksObj, event, entry) {
|
|
|
305
318
|
if (!exists) hooksObj[event].push(entry);
|
|
306
319
|
}
|
|
307
320
|
|
|
321
|
+
function pruneNativeCursorMekoHooks(hooksObj) {
|
|
322
|
+
if (!hooksObj || typeof hooksObj !== "object") return;
|
|
323
|
+
for (const event of Object.keys(hooksObj)) {
|
|
324
|
+
if (!Array.isArray(hooksObj[event])) continue;
|
|
325
|
+
hooksObj[event] = hooksObj[event].filter((item) => {
|
|
326
|
+
if (!item?.command) return true;
|
|
327
|
+
return !isMekoHookCommand(item.command);
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function isMekoHookCommand(command) {
|
|
333
|
+
if (typeof command !== "string") return false;
|
|
334
|
+
if (!command.includes("hooks-handlers/")) return false;
|
|
335
|
+
return [
|
|
336
|
+
"session-start.sh",
|
|
337
|
+
"cursor-session-start.sh",
|
|
338
|
+
"before-submit-prompt.sh",
|
|
339
|
+
"pre-compact.sh",
|
|
340
|
+
"session-end.sh",
|
|
341
|
+
"post-tool-context.sh",
|
|
342
|
+
].some((script) => command.includes(script));
|
|
343
|
+
}
|
|
344
|
+
|
|
308
345
|
function upsertClaudeCompatHook(hooksObj, event, entry) {
|
|
309
346
|
if (!Array.isArray(hooksObj[event])) hooksObj[event] = [];
|
|
310
347
|
let bucket = hooksObj[event].find((item) => Array.isArray(item.hooks));
|
|
@@ -318,10 +355,10 @@ function upsertClaudeCompatHook(hooksObj, event, entry) {
|
|
|
318
355
|
|
|
319
356
|
function uninstallCursorHooks({ scope, projectRoot, mode, paths }) {
|
|
320
357
|
const handlersRoot = resolveHooksRoot();
|
|
321
|
-
const scripts = ["session-start.sh", "pre-compact.sh", "session-end.sh"]
|
|
358
|
+
const scripts = ["session-start.sh", "cursor-session-start.sh", "before-submit-prompt.sh", "pre-compact.sh", "session-end.sh"]
|
|
322
359
|
.map((name) => join(handlersRoot, name));
|
|
323
360
|
|
|
324
|
-
if (mode === "native"
|
|
361
|
+
if (mode === "native") {
|
|
325
362
|
const hooksPath = paths.getHooksPath(scope, projectRoot);
|
|
326
363
|
const cfg = readJsonFile(hooksPath);
|
|
327
364
|
if (cfg?.hooks && typeof cfg.hooks === "object") {
|
|
@@ -336,7 +373,7 @@ function uninstallCursorHooks({ scope, projectRoot, mode, paths }) {
|
|
|
336
373
|
}
|
|
337
374
|
}
|
|
338
375
|
|
|
339
|
-
if (mode === "claude-compat"
|
|
376
|
+
if (mode === "claude-compat") {
|
|
340
377
|
// NOTE: we deliberately do NOT strip env.MEKO_MCP_URL / env.MEKO_API_KEY here.
|
|
341
378
|
// On scope=user, this file is the same ~/.claude/settings.json the Claude Code
|
|
342
379
|
// adapter owns; the Claude Code uninstall (claude-code.mjs removeKeys call) is
|
package/lib/config.mjs
CHANGED
|
@@ -117,6 +117,32 @@ export function getCodexAgentsMdPath() {
|
|
|
117
117
|
return join(codexHome, "AGENTS.md");
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
+
/**
|
|
121
|
+
* Return path to Codex's user-level hooks config.
|
|
122
|
+
* @returns {string}
|
|
123
|
+
*/
|
|
124
|
+
export function getCodexHooksPath() {
|
|
125
|
+
const codexHome = process.env.CODEX_HOME || join(homedir(), ".codex");
|
|
126
|
+
return join(codexHome, "hooks.json");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Return path to the Meko env file the Codex hooks source on launch.
|
|
131
|
+
* Lives next to hooks.json under $CODEX_HOME (default ~/.codex/) and is
|
|
132
|
+
* written at mode 0600. Used because Codex's hooks.json schema has no
|
|
133
|
+
* `env` block, and inlining the API key into each hook's `command`
|
|
134
|
+
* field would expose it via `ps -ef` while the hook runs.
|
|
135
|
+
*
|
|
136
|
+
* The hook command becomes `. ~/.codex/meko-env.sh && bash /path/to/hook.sh`,
|
|
137
|
+
* so the secret never appears in process arguments.
|
|
138
|
+
*
|
|
139
|
+
* @returns {string}
|
|
140
|
+
*/
|
|
141
|
+
export function getCodexMekoEnvFilePath() {
|
|
142
|
+
const codexHome = process.env.CODEX_HOME || join(homedir(), ".codex");
|
|
143
|
+
return join(codexHome, "meko-env.sh");
|
|
144
|
+
}
|
|
145
|
+
|
|
120
146
|
/**
|
|
121
147
|
* Return path to the shared agent-skills directory used by Codex
|
|
122
148
|
* (and other agent runtimes that follow the convention).
|
package/lib/installer.mjs
CHANGED
|
@@ -37,7 +37,7 @@ export async function install(options) {
|
|
|
37
37
|
verbose = false,
|
|
38
38
|
yes = false,
|
|
39
39
|
projectRoot = process.cwd(),
|
|
40
|
-
cursorHookMode = "
|
|
40
|
+
cursorHookMode = "native",
|
|
41
41
|
} = options;
|
|
42
42
|
|
|
43
43
|
const adapters = getClientAdapters();
|
|
@@ -225,7 +225,7 @@ export async function uninstall(options = {}) {
|
|
|
225
225
|
scope = "user",
|
|
226
226
|
verbose = false,
|
|
227
227
|
projectRoot = process.cwd(),
|
|
228
|
-
cursorHookMode = "
|
|
228
|
+
cursorHookMode = "native",
|
|
229
229
|
} = options;
|
|
230
230
|
|
|
231
231
|
const adapters = getClientAdapters();
|
package/package.json
CHANGED
|
@@ -18,10 +18,18 @@ const PAYLOAD = [
|
|
|
18
18
|
from: join(repoRoot, "skills", "skills", "meko-mcp-tools"),
|
|
19
19
|
to: join(assetsDir, "skills", "meko-mcp-tools"),
|
|
20
20
|
},
|
|
21
|
+
{
|
|
22
|
+
from: join(repoRoot, "skills", "skills", "meko-mcp-tools-desktop"),
|
|
23
|
+
to: join(assetsDir, "skills", "meko-mcp-tools-desktop"),
|
|
24
|
+
},
|
|
21
25
|
{
|
|
22
26
|
from: join(repoRoot, "skills", "hooks-handlers"),
|
|
23
27
|
to: join(assetsDir, "hooks-handlers"),
|
|
24
28
|
},
|
|
29
|
+
{
|
|
30
|
+
from: join(repoRoot, "skills", "scripts", "package-desktop-skill.sh"),
|
|
31
|
+
to: join(assetsDir, "scripts", "package-desktop-skill.sh"),
|
|
32
|
+
},
|
|
25
33
|
];
|
|
26
34
|
|
|
27
35
|
const cleaning = process.argv.includes("--clean");
|