@membank/cli 0.0.2 → 0.0.3
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/dist/index.mjs +164 -61
- package/package.json +3 -3
package/dist/index.mjs
CHANGED
|
@@ -7,6 +7,8 @@ import { dirname, join } from "node:path";
|
|
|
7
7
|
import * as readline from "node:readline";
|
|
8
8
|
import { createInterface } from "node:readline";
|
|
9
9
|
import { homedir, tmpdir } from "node:os";
|
|
10
|
+
import { execFile } from "node:child_process";
|
|
11
|
+
import { promisify } from "node:util";
|
|
10
12
|
import { EventEmitter } from "node:events";
|
|
11
13
|
import { pipeline } from "@huggingface/transformers";
|
|
12
14
|
//#region src/commands/add.ts
|
|
@@ -80,12 +82,12 @@ const MEMORY_TYPES = new Set([
|
|
|
80
82
|
function isValidRecord(r) {
|
|
81
83
|
if (typeof r !== "object" || r === null) return false;
|
|
82
84
|
const rec = r;
|
|
83
|
-
return typeof rec
|
|
85
|
+
return typeof rec.id === "string" && rec.id.length > 0 && typeof rec.content === "string" && typeof rec.type === "string" && MEMORY_TYPES.has(rec.type) && typeof rec.scope === "string" && rec.scope.length > 0;
|
|
84
86
|
}
|
|
85
87
|
function isExportFile(parsed) {
|
|
86
88
|
if (typeof parsed !== "object" || parsed === null) return false;
|
|
87
89
|
const obj = parsed;
|
|
88
|
-
return obj
|
|
90
|
+
return obj.version === 1 && Array.isArray(obj.memories);
|
|
89
91
|
}
|
|
90
92
|
async function importCommand(filePath, db, formatter, prompt) {
|
|
91
93
|
let raw;
|
|
@@ -314,19 +316,50 @@ var PromptHelper = class {
|
|
|
314
316
|
}
|
|
315
317
|
};
|
|
316
318
|
//#endregion
|
|
319
|
+
//#region src/utils/execFileNoThrow.ts
|
|
320
|
+
const execFileAsync = promisify(execFile);
|
|
321
|
+
function resolveCmd(cmd) {
|
|
322
|
+
return process.platform === "win32" ? `${cmd}.cmd` : cmd;
|
|
323
|
+
}
|
|
324
|
+
async function execFileNoThrow(cmd, args) {
|
|
325
|
+
try {
|
|
326
|
+
const { stdout, stderr } = await execFileAsync(resolveCmd(cmd), args, { encoding: "utf8" });
|
|
327
|
+
return {
|
|
328
|
+
stdout: stdout ?? "",
|
|
329
|
+
stderr: stderr ?? "",
|
|
330
|
+
exitCode: 0
|
|
331
|
+
};
|
|
332
|
+
} catch (err) {
|
|
333
|
+
if (err !== null && typeof err === "object" && "code" in err) {
|
|
334
|
+
const e = err;
|
|
335
|
+
if (e.code === "ENOENT") return {
|
|
336
|
+
stdout: "",
|
|
337
|
+
stderr: `Command not found: ${cmd}`,
|
|
338
|
+
exitCode: 127
|
|
339
|
+
};
|
|
340
|
+
return {
|
|
341
|
+
stdout: typeof e.stdout === "string" ? e.stdout : "",
|
|
342
|
+
stderr: typeof e.stderr === "string" ? e.stderr : "",
|
|
343
|
+
exitCode: typeof e.code === "number" ? e.code : 1
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
return {
|
|
347
|
+
stdout: "",
|
|
348
|
+
stderr: err instanceof Error ? err.message : String(err),
|
|
349
|
+
exitCode: 1
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
//#endregion
|
|
317
354
|
//#region src/setup/harness-config-writer.ts
|
|
318
355
|
const defaultPathResolver = {
|
|
319
356
|
home: () => {
|
|
320
|
-
const h = process.env
|
|
357
|
+
const h = process.env.HOME ?? process.env.USERPROFILE;
|
|
321
358
|
if (!h) throw new Error("Cannot determine home directory");
|
|
322
359
|
return h;
|
|
323
360
|
},
|
|
324
361
|
cwd: () => process.cwd()
|
|
325
362
|
};
|
|
326
|
-
const MEMBANK_ENTRY = {
|
|
327
|
-
command: "npx",
|
|
328
|
-
args: ["@membank/cli", "--mcp"]
|
|
329
|
-
};
|
|
330
363
|
function readJson(path) {
|
|
331
364
|
try {
|
|
332
365
|
return JSON.parse(readFileSync(path, "utf8"));
|
|
@@ -343,66 +376,133 @@ function writeJsonAtomic(path, data) {
|
|
|
343
376
|
function hasKey(container, key) {
|
|
344
377
|
return container !== null && typeof container === "object" && key in container;
|
|
345
378
|
}
|
|
379
|
+
function assertCliFound(result, cli) {
|
|
380
|
+
if (result.exitCode === 127) throw new Error(`${cli} CLI not found — install ${cli} first`);
|
|
381
|
+
}
|
|
382
|
+
const MEMBANK_NPX_ARGS = [
|
|
383
|
+
"npx",
|
|
384
|
+
"@membank/cli@latest",
|
|
385
|
+
"--mcp"
|
|
386
|
+
];
|
|
346
387
|
const writers = {
|
|
347
|
-
"claude-code": {
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
388
|
+
"claude-code": { async write(resolver, run, { overwrite = false } = {}) {
|
|
389
|
+
const configured = hasKey(readJson(join(resolver.home(), ".claude.json")).mcpServers, "membank");
|
|
390
|
+
if (configured && !overwrite) return { status: "already-configured" };
|
|
391
|
+
if (configured) {
|
|
392
|
+
const remove = await run("claude", [
|
|
393
|
+
"mcp",
|
|
394
|
+
"remove",
|
|
395
|
+
"--scope",
|
|
396
|
+
"user",
|
|
397
|
+
"membank"
|
|
398
|
+
]);
|
|
399
|
+
assertCliFound(remove, "claude");
|
|
400
|
+
if (remove.exitCode !== 0) throw new Error(`claude mcp remove failed: ${remove.stderr}`);
|
|
401
|
+
}
|
|
402
|
+
const add = await run("claude", [
|
|
403
|
+
"mcp",
|
|
404
|
+
"add",
|
|
405
|
+
"--scope",
|
|
406
|
+
"user",
|
|
407
|
+
"membank",
|
|
408
|
+
"--",
|
|
409
|
+
...MEMBANK_NPX_ARGS
|
|
410
|
+
]);
|
|
411
|
+
assertCliFound(add, "claude");
|
|
412
|
+
if (add.exitCode !== 0) throw new Error(`claude mcp add failed: ${add.stderr || add.stdout}`);
|
|
413
|
+
return { status: "written" };
|
|
414
|
+
} },
|
|
415
|
+
vscode: { async write(resolver, run, { overwrite = false } = {}) {
|
|
416
|
+
const cfgPath = join(resolver.cwd(), ".vscode", "mcp.json");
|
|
417
|
+
const cfg = readJson(cfgPath);
|
|
418
|
+
const configured = hasKey(cfg.servers, "membank");
|
|
419
|
+
if (configured && !overwrite) return { status: "already-configured" };
|
|
420
|
+
if (configured) {
|
|
421
|
+
writeJsonAtomic(cfgPath, {
|
|
422
|
+
...cfg,
|
|
423
|
+
servers: {
|
|
424
|
+
...cfg.servers,
|
|
425
|
+
membank: {
|
|
426
|
+
command: "npx",
|
|
427
|
+
args: ["@membank/cli@latest", "--mcp"]
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
return { status: "written" };
|
|
432
|
+
}
|
|
433
|
+
const payload = JSON.stringify({
|
|
434
|
+
name: "membank",
|
|
435
|
+
command: "npx",
|
|
436
|
+
args: ["@membank/cli@latest", "--mcp"]
|
|
437
|
+
});
|
|
438
|
+
const result = await run("code", [
|
|
439
|
+
"--folder-uri",
|
|
440
|
+
resolver.cwd(),
|
|
441
|
+
"--add-mcp",
|
|
442
|
+
payload
|
|
443
|
+
]);
|
|
444
|
+
assertCliFound(result, "code");
|
|
445
|
+
if (result.exitCode !== 0) throw new Error(`code --add-mcp failed: ${result.stderr || result.stdout}`);
|
|
446
|
+
return { status: "written" };
|
|
447
|
+
} },
|
|
448
|
+
codex: { async write(_resolver, run, { overwrite = false } = {}) {
|
|
449
|
+
const list = await run("codex", ["mcp", "list"]);
|
|
450
|
+
assertCliFound(list, "codex");
|
|
451
|
+
const configured = list.exitCode === 0 && list.stdout.includes("membank");
|
|
452
|
+
if (configured && !overwrite) return { status: "already-configured" };
|
|
453
|
+
if (configured) {
|
|
454
|
+
const remove = await run("codex", [
|
|
455
|
+
"mcp",
|
|
456
|
+
"remove",
|
|
457
|
+
"membank"
|
|
458
|
+
]);
|
|
459
|
+
assertCliFound(remove, "codex");
|
|
460
|
+
if (remove.exitCode !== 0) throw new Error(`codex mcp remove failed: ${remove.stderr}`);
|
|
461
|
+
}
|
|
462
|
+
const add = await run("codex", [
|
|
463
|
+
"mcp",
|
|
464
|
+
"add",
|
|
465
|
+
"membank",
|
|
466
|
+
"--",
|
|
467
|
+
...MEMBANK_NPX_ARGS
|
|
468
|
+
]);
|
|
469
|
+
assertCliFound(add, "codex");
|
|
470
|
+
if (add.exitCode !== 0) throw new Error(`codex mcp add failed: ${add.stderr || add.stdout}`);
|
|
471
|
+
return { status: "written" };
|
|
472
|
+
} },
|
|
473
|
+
opencode: { async write(resolver, _run, { overwrite = false } = {}) {
|
|
474
|
+
const cfgPath = join(resolver.home(), ".config", "opencode", "opencode.json");
|
|
475
|
+
const cfg = readJson(cfgPath);
|
|
476
|
+
if (hasKey(cfg.mcp, "membank") && !overwrite) return { status: "already-configured" };
|
|
477
|
+
writeJsonAtomic(cfgPath, {
|
|
384
478
|
...cfg,
|
|
385
479
|
mcp: {
|
|
386
|
-
...cfg
|
|
387
|
-
membank:
|
|
480
|
+
...cfg.mcp,
|
|
481
|
+
membank: {
|
|
482
|
+
type: "local",
|
|
483
|
+
command: [
|
|
484
|
+
"npx",
|
|
485
|
+
"@membank/cli@latest",
|
|
486
|
+
"--mcp"
|
|
487
|
+
]
|
|
488
|
+
}
|
|
388
489
|
}
|
|
389
|
-
})
|
|
390
|
-
|
|
490
|
+
});
|
|
491
|
+
return { status: "written" };
|
|
492
|
+
} }
|
|
391
493
|
};
|
|
392
494
|
const SUPPORTED_HARNESSES = Object.keys(writers);
|
|
393
495
|
var HarnessConfigWriter = class {
|
|
394
496
|
#resolver;
|
|
395
|
-
|
|
497
|
+
#run;
|
|
498
|
+
constructor(resolver = defaultPathResolver, run = execFileNoThrow) {
|
|
396
499
|
this.#resolver = resolver;
|
|
500
|
+
this.#run = run;
|
|
397
501
|
}
|
|
398
|
-
write(harness, { overwrite = false } = {}) {
|
|
502
|
+
async write(harness, { overwrite = false } = {}) {
|
|
399
503
|
const writer = writers[harness];
|
|
400
504
|
if (!writer) throw new Error(`Unknown harness: ${harness}`);
|
|
401
|
-
|
|
402
|
-
const existing = readJson(path);
|
|
403
|
-
if (!overwrite && writer.isConfigured(existing)) return { status: "already-configured" };
|
|
404
|
-
writeJsonAtomic(path, writer.merge(existing));
|
|
405
|
-
return { status: "written" };
|
|
505
|
+
return writer.write(this.#resolver, this.#run, { overwrite });
|
|
406
506
|
}
|
|
407
507
|
};
|
|
408
508
|
//#endregion
|
|
@@ -481,7 +581,8 @@ function harnessConfigs(resolver) {
|
|
|
481
581
|
return [
|
|
482
582
|
{
|
|
483
583
|
name: "claude-code",
|
|
484
|
-
configPath: join(home, ".claude
|
|
584
|
+
configPath: join(home, ".claude.json"),
|
|
585
|
+
fallbackPaths: [join(home, ".claude", "settings.json")]
|
|
485
586
|
},
|
|
486
587
|
{
|
|
487
588
|
name: "vscode",
|
|
@@ -489,16 +590,18 @@ function harnessConfigs(resolver) {
|
|
|
489
590
|
},
|
|
490
591
|
{
|
|
491
592
|
name: "codex",
|
|
492
|
-
configPath: join(home, ".codex", "config.
|
|
593
|
+
configPath: join(home, ".codex", "config.toml"),
|
|
594
|
+
fallbackPaths: [join(home, ".codex", "config.json")]
|
|
493
595
|
},
|
|
494
596
|
{
|
|
495
597
|
name: "opencode",
|
|
496
|
-
configPath: join(home, ".config", "opencode", "
|
|
598
|
+
configPath: join(home, ".config", "opencode", "opencode.json"),
|
|
599
|
+
fallbackPaths: [join(home, ".config", "opencode", "config.json")]
|
|
497
600
|
}
|
|
498
601
|
];
|
|
499
602
|
}
|
|
500
603
|
function detectHarnesses(resolver = defaultResolver) {
|
|
501
|
-
return harnessConfigs(resolver).filter((h) => existsSync(h.configPath)).map((h) => ({
|
|
604
|
+
return harnessConfigs(resolver).filter((h) => existsSync(h.configPath) || (h.fallbackPaths?.some((p) => existsSync(p)) ?? false)).map((h) => ({
|
|
502
605
|
name: h.name,
|
|
503
606
|
configPath: h.configPath
|
|
504
607
|
}));
|
|
@@ -582,7 +685,7 @@ var SetupOrchestrator = class {
|
|
|
582
685
|
for (const h of detected) {
|
|
583
686
|
let writeResult;
|
|
584
687
|
try {
|
|
585
|
-
writeResult = this.#writer.write(h.name);
|
|
688
|
+
writeResult = await this.#writer.write(h.name);
|
|
586
689
|
} catch (err) {
|
|
587
690
|
const msg = err instanceof Error ? err.message : String(err);
|
|
588
691
|
out(` ✗ ${h.name}: ${msg}`);
|
|
@@ -605,7 +708,7 @@ var SetupOrchestrator = class {
|
|
|
605
708
|
continue;
|
|
606
709
|
}
|
|
607
710
|
try {
|
|
608
|
-
this.#writer.write(h.name, { overwrite: true });
|
|
711
|
+
await this.#writer.write(h.name, { overwrite: true });
|
|
609
712
|
out(` ✓ ${h.name}: written (overwritten)`);
|
|
610
713
|
results.push({
|
|
611
714
|
harness: h.name,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@membank/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"@huggingface/transformers": "^4.2.0",
|
|
18
18
|
"commander": "^14.0.3",
|
|
19
19
|
"ora": "^9.4.0",
|
|
20
|
-
"@membank/core": "0.0.
|
|
21
|
-
"@membank/mcp": "0.0.
|
|
20
|
+
"@membank/core": "0.0.3",
|
|
21
|
+
"@membank/mcp": "0.0.3"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^25.6.0",
|