@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
|
@@ -17,6 +17,7 @@ import { seedFor } from "./id.mjs";
|
|
|
17
17
|
import { resolveDestinationDatapack } from "./datapack.mjs";
|
|
18
18
|
import * as claudeCodeAdapter from "./adapters/claude-code.mjs";
|
|
19
19
|
import * as cursorAdapter from "./adapters/cursor.mjs";
|
|
20
|
+
import * as codexAdapter from "./adapters/codex.mjs";
|
|
20
21
|
import * as memoryMdAdapter from "./adapters/memory-md.mjs";
|
|
21
22
|
|
|
22
23
|
/**
|
|
@@ -46,7 +47,9 @@ import * as memoryMdAdapter from "./adapters/memory-md.mjs";
|
|
|
46
47
|
* @returns {Promise<{ok: boolean, summary: object, counts: object}>}
|
|
47
48
|
*/
|
|
48
49
|
export async function runMigration(opts) {
|
|
49
|
-
|
|
50
|
+
// A planning pass is intentionally read-only. In particular, don't create
|
|
51
|
+
// a run directory that `--migrate-status` can mistake for an active run.
|
|
52
|
+
if (!opts.dryRun) fs.mkdirSync(opts.runDir, { recursive: true });
|
|
50
53
|
|
|
51
54
|
const log = opts.dryRun
|
|
52
55
|
? nullLogger()
|
|
@@ -55,6 +58,7 @@ export async function runMigration(opts) {
|
|
|
55
58
|
const prog = progress.initial(opts.runId, opts.scope);
|
|
56
59
|
const progressPath = path.join(opts.runDir, "progress.json");
|
|
57
60
|
const writeProgress = () => {
|
|
61
|
+
if (opts.dryRun) return;
|
|
58
62
|
try { progress.write(progressPath, prog); } catch { /* best effort */ }
|
|
59
63
|
};
|
|
60
64
|
|
|
@@ -91,19 +95,26 @@ export async function runMigration(opts) {
|
|
|
91
95
|
projectCwd: opts.projectCwd,
|
|
92
96
|
home: opts.home,
|
|
93
97
|
});
|
|
98
|
+
const codexSessions = codexAdapter.listSessions({
|
|
99
|
+
scope: opts.scope,
|
|
100
|
+
projectCwd: opts.projectCwd,
|
|
101
|
+
home: opts.home,
|
|
102
|
+
});
|
|
94
103
|
const memoryItems = await memoryMdAdapter.enumerateMemoryItems({
|
|
95
104
|
scope: opts.scope,
|
|
96
105
|
projectCwd: opts.projectCwd,
|
|
97
106
|
home: opts.home,
|
|
98
107
|
});
|
|
99
108
|
|
|
100
|
-
prog.counts.sessionsPlanned =
|
|
109
|
+
prog.counts.sessionsPlanned =
|
|
110
|
+
claudeSessions.length + cursorSessions.length + codexSessions.length;
|
|
101
111
|
writeProgress();
|
|
102
112
|
|
|
103
113
|
log.info("plan", {
|
|
104
114
|
scope: opts.scope,
|
|
105
115
|
claudeSessions: claudeSessions.length,
|
|
106
116
|
cursorSessions: cursorSessions.length,
|
|
117
|
+
codexSessions: codexSessions.length,
|
|
107
118
|
memoryItems: memoryItems.length,
|
|
108
119
|
dryRun: !!opts.dryRun,
|
|
109
120
|
noExtract: !!opts.noExtract,
|
|
@@ -122,7 +133,12 @@ export async function runMigration(opts) {
|
|
|
122
133
|
const parsed = cursorAdapter.parseSession(ref.path);
|
|
123
134
|
pairedTurns += parsed.exchanges.length;
|
|
124
135
|
}
|
|
125
|
-
const
|
|
136
|
+
for (const ref of codexSessions) {
|
|
137
|
+
const parsed = codexAdapter.parseSession(ref.path);
|
|
138
|
+
pairedTurns += parsed.exchanges.length;
|
|
139
|
+
}
|
|
140
|
+
const plannedConversationCreates =
|
|
141
|
+
claudeSessions.length + cursorSessions.length + codexSessions.length
|
|
126
142
|
+ (memoryItems.length > 0 ? countDistinctMemoryAgents(memoryItems) : 0);
|
|
127
143
|
const plannedConversationAddMessage = pairedTurns;
|
|
128
144
|
const plannedMemoryAddExtract = opts.noExtract ? 0 : pairedTurns;
|
|
@@ -132,6 +148,7 @@ export async function runMigration(opts) {
|
|
|
132
148
|
scope: opts.scope,
|
|
133
149
|
claudeSessions: claudeSessions.length,
|
|
134
150
|
cursorSessions: cursorSessions.length,
|
|
151
|
+
codexSessions: codexSessions.length,
|
|
135
152
|
memoryItems: memoryItems.length,
|
|
136
153
|
pairedTurns,
|
|
137
154
|
plannedCalls: {
|
|
@@ -218,7 +235,15 @@ export async function runMigration(opts) {
|
|
|
218
235
|
const withDp = (args) => (datapackId ? { ...args, datapack_id: datapackId } : args);
|
|
219
236
|
|
|
220
237
|
// -- Conversations --
|
|
221
|
-
|
|
238
|
+
// Tag each ref with its source so the parse dispatch below is explicit.
|
|
239
|
+
// Claude Code and Codex both store rollouts as `.jsonl`, so an
|
|
240
|
+
// extension check alone can't tell them apart.
|
|
241
|
+
const taggedSessions = [
|
|
242
|
+
...claudeSessions.map((ref) => ({ ref, source: "claude-code" })),
|
|
243
|
+
...cursorSessions.map((ref) => ({ ref, source: "cursor" })),
|
|
244
|
+
...codexSessions.map((ref) => ({ ref, source: "codex" })),
|
|
245
|
+
];
|
|
246
|
+
for (const { ref, source } of taggedSessions) {
|
|
222
247
|
let existing = state.getSession(st, ref.agentId, ref.sessionUuid);
|
|
223
248
|
if (existing?.status === "done" && !opts.force) {
|
|
224
249
|
log.info("session_skip_done", { agentId: ref.agentId, sessionUuid: ref.sessionUuid });
|
|
@@ -243,9 +268,11 @@ export async function runMigration(opts) {
|
|
|
243
268
|
prog.currentSession = ref.sessionUuid;
|
|
244
269
|
writeProgress();
|
|
245
270
|
|
|
246
|
-
const parsed =
|
|
271
|
+
const parsed = source === "claude-code"
|
|
247
272
|
? await claudeCodeAdapter.parseSession(ref.path)
|
|
248
|
-
:
|
|
273
|
+
: source === "codex"
|
|
274
|
+
? codexAdapter.parseSession(ref.path)
|
|
275
|
+
: cursorAdapter.parseSession(ref.path);
|
|
249
276
|
|
|
250
277
|
if (parsed.partial) {
|
|
251
278
|
log.warn("session_partial", { path: ref.path });
|
|
@@ -260,7 +287,7 @@ export async function runMigration(opts) {
|
|
|
260
287
|
session_id: ref.sessionUuid,
|
|
261
288
|
title: (parsed.firstUserText || ref.sessionUuid).slice(0, 120),
|
|
262
289
|
metadata: JSON.stringify({
|
|
263
|
-
source
|
|
290
|
+
source,
|
|
264
291
|
cwd: ref.cwd || null,
|
|
265
292
|
gitBranch: ref.slug ? (parsed.gitBranch || null) : null,
|
|
266
293
|
startedAt: parsed.startedAt || null,
|
package/lib/migrate.mjs
CHANGED
|
@@ -212,10 +212,10 @@ export async function startMigration(opts) {
|
|
|
212
212
|
// don't move when the state key changes.
|
|
213
213
|
const urlDatapackKey = datapackKeyFromUrl(opts.url);
|
|
214
214
|
let P = paths({ datapackKey: urlDatapackKey });
|
|
215
|
-
fs.mkdirSync(P.root, { recursive: true });
|
|
216
215
|
|
|
217
216
|
// Dry-run is a local-only planning pass: no HTTP, no lock, no fork.
|
|
218
|
-
// Don't gate it on URL/apiKey
|
|
217
|
+
// Don't gate it on URL/apiKey, and don't create the migration root: a
|
|
218
|
+
// planning pass must not appear as a phantom active run in --migrate-status.
|
|
219
219
|
if (opts.dryRun) {
|
|
220
220
|
const runId = generateRunId();
|
|
221
221
|
const runDir = P.runDir(runId);
|
|
@@ -260,6 +260,8 @@ export async function startMigration(opts) {
|
|
|
260
260
|
};
|
|
261
261
|
}
|
|
262
262
|
|
|
263
|
+
fs.mkdirSync(P.root, { recursive: true });
|
|
264
|
+
|
|
263
265
|
// Real run — now URL/apiKey are required (dry-run branch already returned).
|
|
264
266
|
if (!opts.url) {
|
|
265
267
|
return { ok: false, message: "--url (or MEKO_MCP_URL) is required for --migrate." };
|
package/lib/prompt.mjs
CHANGED
|
@@ -37,6 +37,21 @@ function question(query) {
|
|
|
37
37
|
});
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Apply terminal erase bytes that survive readline's muted-output path.
|
|
42
|
+
* Some PTYs leave DEL/BS in the answer when readline is attached to a
|
|
43
|
+
* non-TTY Writable, even with terminal mode enabled. Treat them exactly as
|
|
44
|
+
* interactive backspace so a corrected secret never persists control bytes.
|
|
45
|
+
*/
|
|
46
|
+
function applyEraseCharacters(value) {
|
|
47
|
+
const chars = [];
|
|
48
|
+
for (const char of value) {
|
|
49
|
+
if (char === "\x7f" || char === "\b") chars.pop();
|
|
50
|
+
else chars.push(char);
|
|
51
|
+
}
|
|
52
|
+
return chars.join("");
|
|
53
|
+
}
|
|
54
|
+
|
|
40
55
|
// ---------------------------------------------------------------------------
|
|
41
56
|
// askChoice
|
|
42
57
|
// ---------------------------------------------------------------------------
|
|
@@ -218,7 +233,7 @@ export async function askSecret(questionText) {
|
|
|
218
233
|
|
|
219
234
|
secretRL.question("", (answer) => {
|
|
220
235
|
finish();
|
|
221
|
-
resolve(answer);
|
|
236
|
+
resolve(applyEraseCharacters(answer));
|
|
222
237
|
});
|
|
223
238
|
});
|
|
224
239
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yugabytedb/meko-mcp",
|
|
3
|
-
"version": "2.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.2.0",
|
|
4
|
+
"description": "Installer for Meko across Claude, Cursor, Codex, and Kiro clients",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"create-meko-setup": "bin/create-meko-setup.mjs",
|
|
@@ -18,14 +18,14 @@
|
|
|
18
18
|
"prepack": "node scripts/bundle-assets.mjs",
|
|
19
19
|
"postpack": "node scripts/bundle-assets.mjs --clean",
|
|
20
20
|
"bundle-assets": "node scripts/bundle-assets.mjs",
|
|
21
|
-
"test": "node --test \"test/*.mjs\"",
|
|
21
|
+
"test": "node --test \"test/*.mjs\" && node --test \"test/serial/*.mjs\"",
|
|
22
22
|
"smoke": "./scripts/prepublish-smoke.sh",
|
|
23
23
|
"test:unit": "node --test test/config.test.mjs test/validate.test.mjs test/clients.test.mjs",
|
|
24
24
|
"test:integration": "RUN_INSTALLER_INTEGRATION=1 node --test test/installer.test.mjs",
|
|
25
25
|
"test:integration:cloud": "RUN_INSTALLER_INTEGRATION=1 node --test test/installer.test.mjs"
|
|
26
26
|
},
|
|
27
27
|
"engines": {
|
|
28
|
-
"node": ">=18.
|
|
28
|
+
"node": ">=20.18.1"
|
|
29
29
|
},
|
|
30
30
|
"keywords": [
|
|
31
31
|
"meko",
|