@hasna/mementos 0.14.29 → 0.14.30
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 +13 -0
- package/dist/bridge.d.ts +50 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/cli.js +283 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +188 -1
- package/dist/mcp-runtime.d.ts +1 -1
- package/dist/mcp.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -47,3 +47,16 @@ integration snippets. OpenCode and Antigravity receive the same MCP registration
|
|
|
47
47
|
plus host instruction files that tell the agent to use `memory.search`,
|
|
48
48
|
`memory.save`, and `mementos inject` as the hosted fallback path when native
|
|
49
49
|
hooks are unavailable.
|
|
50
|
+
|
|
51
|
+
## Bridge
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
mementos bridge status
|
|
55
|
+
mementos bridge start --agent <name>
|
|
56
|
+
mementos bridge stop
|
|
57
|
+
mementos bridge install
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The bridge is remote-only. It keeps PID/log/service metadata under user config
|
|
61
|
+
paths and heartbeats the hosted agent when `--agent` or `MEMENTOS_AGENT_NAME` is
|
|
62
|
+
set; it does not own a local memory store.
|
package/dist/bridge.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export interface BridgeOptions {
|
|
2
|
+
agentName?: string;
|
|
3
|
+
apiUrl?: string;
|
|
4
|
+
homeDir?: string;
|
|
5
|
+
intervalMs?: number;
|
|
6
|
+
platform?: NodeJS.Platform;
|
|
7
|
+
}
|
|
8
|
+
export interface BridgeStartOptions extends BridgeOptions {
|
|
9
|
+
command?: string[];
|
|
10
|
+
}
|
|
11
|
+
export interface BridgeServiceOptions extends BridgeOptions {
|
|
12
|
+
command?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface BridgePaths {
|
|
15
|
+
baseDir: string;
|
|
16
|
+
logFile: string;
|
|
17
|
+
pidFile: string;
|
|
18
|
+
serviceFile: string;
|
|
19
|
+
}
|
|
20
|
+
export interface BridgeStatus {
|
|
21
|
+
agentName?: string;
|
|
22
|
+
apiUrl: string;
|
|
23
|
+
localDatabase: false;
|
|
24
|
+
logFile: string;
|
|
25
|
+
pid?: number;
|
|
26
|
+
pidFile: string;
|
|
27
|
+
remoteOnly: true;
|
|
28
|
+
running: boolean;
|
|
29
|
+
startedAt?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface BridgeServiceResult {
|
|
32
|
+
path: string;
|
|
33
|
+
remoteOnly: true;
|
|
34
|
+
status: "installed" | "removed" | "absent";
|
|
35
|
+
}
|
|
36
|
+
export declare function buildBridgePaths(homeDir?: string, platform?: NodeJS.Platform): BridgePaths;
|
|
37
|
+
export declare function getBridgeStatus(options?: BridgeOptions): BridgeStatus;
|
|
38
|
+
export declare function startBridge(options?: BridgeStartOptions): BridgeStatus;
|
|
39
|
+
export declare function stopBridge(options?: BridgeOptions): BridgeServiceResult;
|
|
40
|
+
export declare function installBridgeService(options?: BridgeServiceOptions): BridgeServiceResult;
|
|
41
|
+
export declare function uninstallBridgeService(options?: BridgeOptions): BridgeServiceResult;
|
|
42
|
+
export declare function readBridgeLogs(options?: BridgeOptions & {
|
|
43
|
+
lines?: number;
|
|
44
|
+
}): string[];
|
|
45
|
+
export declare function writeBridgePid(options: BridgeOptions & {
|
|
46
|
+
pid: number;
|
|
47
|
+
startedAt: string;
|
|
48
|
+
}): void;
|
|
49
|
+
export declare function clearBridgePid(options?: BridgeOptions): void;
|
|
50
|
+
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../src/bridge.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACvD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,oBAAqB,SAAQ,aAAa;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,KAAK,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,IAAI,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,IAAI,CAAC;IACjB,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;CAC5C;AASD,wBAAgB,gBAAgB,CAAC,OAAO,SAAY,EAAE,QAAQ,GAAE,MAAM,CAAC,QAA2B,GAAG,WAAW,CAU/G;AAED,wBAAgB,eAAe,CAAC,OAAO,GAAE,aAAkB,GAAG,YAAY,CAYzE;AAED,wBAAgB,WAAW,CAAC,OAAO,GAAE,kBAAuB,GAAG,YAAY,CA8B1E;AAED,wBAAgB,UAAU,CAAC,OAAO,GAAE,aAAkB,GAAG,mBAAmB,CAO3E;AAED,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,oBAAyB,GAAG,mBAAmB,CAW5F;AAED,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,aAAkB,GAAG,mBAAmB,CAKvF;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,aAAa,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,EAAE,CAOzF;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAShG;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,aAAkB,GAAG,IAAI,CAEhE"}
|
package/dist/cli.js
CHANGED
|
@@ -573,6 +573,185 @@ function findLocalDatabaseFiles(dir) {
|
|
|
573
573
|
});
|
|
574
574
|
}
|
|
575
575
|
|
|
576
|
+
// src/bridge.ts
|
|
577
|
+
import { spawn } from "child_process";
|
|
578
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, openSync, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
579
|
+
import { homedir as homedir2 } from "os";
|
|
580
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
581
|
+
function buildBridgePaths(homeDir = homedir2(), platform = process.platform) {
|
|
582
|
+
const baseDir = join2(homeDir, ".config", "mementos", "bridge");
|
|
583
|
+
return {
|
|
584
|
+
baseDir,
|
|
585
|
+
logFile: join2(baseDir, "bridge.log"),
|
|
586
|
+
pidFile: join2(baseDir, "bridge.pid.json"),
|
|
587
|
+
serviceFile: platform === "darwin" ? join2(homeDir, "Library", "LaunchAgents", "md.mementos.bridge.plist") : join2(homeDir, ".config", "systemd", "user", "mementos-bridge.service")
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
function getBridgeStatus(options = {}) {
|
|
591
|
+
const paths = buildBridgePaths(options.homeDir, options.platform);
|
|
592
|
+
const pidFile = readBridgePid(paths.pidFile);
|
|
593
|
+
if (pidFile && !isRunning(pidFile.pid)) {
|
|
594
|
+
rmSync2(paths.pidFile, { force: true });
|
|
595
|
+
return baseStatus(paths, options, false);
|
|
596
|
+
}
|
|
597
|
+
return {
|
|
598
|
+
...baseStatus(paths, options, Boolean(pidFile)),
|
|
599
|
+
...pidFile?.agentName ? { agentName: pidFile.agentName } : {},
|
|
600
|
+
...pidFile ? { pid: pidFile.pid, startedAt: pidFile.startedAt } : {}
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
function startBridge(options = {}) {
|
|
604
|
+
const current = getBridgeStatus(options);
|
|
605
|
+
if (current.running)
|
|
606
|
+
return current;
|
|
607
|
+
const paths = buildBridgePaths(options.homeDir, options.platform);
|
|
608
|
+
mkdirSync2(paths.baseDir, { recursive: true });
|
|
609
|
+
const out = openSync(paths.logFile, "a");
|
|
610
|
+
const err = openSync(paths.logFile, "a");
|
|
611
|
+
const command = options.command ?? [process.execPath, process.argv[1] ?? "mementos", "bridge", "run"];
|
|
612
|
+
const child = spawn(command[0] ?? "mementos", command.slice(1), {
|
|
613
|
+
detached: true,
|
|
614
|
+
env: {
|
|
615
|
+
...process.env,
|
|
616
|
+
...options.agentName ? { MEMENTOS_AGENT_NAME: options.agentName } : {},
|
|
617
|
+
...options.apiUrl ? { MEMENTOS_API_URL: options.apiUrl } : {},
|
|
618
|
+
...options.homeDir ? { MEMENTOS_BRIDGE_HOME: options.homeDir } : {},
|
|
619
|
+
...options.intervalMs ? { MEMENTOS_BRIDGE_INTERVAL_MS: String(options.intervalMs) } : {}
|
|
620
|
+
},
|
|
621
|
+
stdio: ["ignore", out, err]
|
|
622
|
+
});
|
|
623
|
+
child.unref();
|
|
624
|
+
writeBridgePid({
|
|
625
|
+
agentName: options.agentName,
|
|
626
|
+
apiUrl: options.apiUrl,
|
|
627
|
+
homeDir: options.homeDir,
|
|
628
|
+
pid: child.pid ?? 0,
|
|
629
|
+
startedAt: new Date().toISOString()
|
|
630
|
+
});
|
|
631
|
+
return getBridgeStatus(options);
|
|
632
|
+
}
|
|
633
|
+
function stopBridge(options = {}) {
|
|
634
|
+
const paths = buildBridgePaths(options.homeDir, options.platform);
|
|
635
|
+
const pidFile = readBridgePid(paths.pidFile);
|
|
636
|
+
if (!pidFile)
|
|
637
|
+
return { path: paths.pidFile, remoteOnly: true, status: "absent" };
|
|
638
|
+
if (isRunning(pidFile.pid))
|
|
639
|
+
process.kill(pidFile.pid, "SIGTERM");
|
|
640
|
+
clearBridgePid(options);
|
|
641
|
+
return { path: paths.pidFile, remoteOnly: true, status: "removed" };
|
|
642
|
+
}
|
|
643
|
+
function installBridgeService(options = {}) {
|
|
644
|
+
const platform = options.platform ?? process.platform;
|
|
645
|
+
const paths = buildBridgePaths(options.homeDir, platform);
|
|
646
|
+
mkdirSync2(dirname2(paths.serviceFile), { recursive: true });
|
|
647
|
+
const command = options.command ?? "mementos bridge run";
|
|
648
|
+
const apiUrl = options.apiUrl ?? "https://mementos.md/api/v1";
|
|
649
|
+
const content = platform === "darwin" ? renderLaunchdService(command, apiUrl, options.agentName) : renderSystemdService(command, apiUrl, options.agentName);
|
|
650
|
+
writeFileSync2(paths.serviceFile, content, { mode: 420 });
|
|
651
|
+
return { path: paths.serviceFile, remoteOnly: true, status: "installed" };
|
|
652
|
+
}
|
|
653
|
+
function uninstallBridgeService(options = {}) {
|
|
654
|
+
const paths = buildBridgePaths(options.homeDir, options.platform);
|
|
655
|
+
if (!existsSync2(paths.serviceFile))
|
|
656
|
+
return { path: paths.serviceFile, remoteOnly: true, status: "absent" };
|
|
657
|
+
rmSync2(paths.serviceFile, { force: true });
|
|
658
|
+
return { path: paths.serviceFile, remoteOnly: true, status: "removed" };
|
|
659
|
+
}
|
|
660
|
+
function readBridgeLogs(options = {}) {
|
|
661
|
+
const paths = buildBridgePaths(options.homeDir, options.platform);
|
|
662
|
+
if (!existsSync2(paths.logFile))
|
|
663
|
+
return [];
|
|
664
|
+
return readFileSync2(paths.logFile, "utf8").split(`
|
|
665
|
+
`).filter(Boolean).slice(-(options.lines ?? 40));
|
|
666
|
+
}
|
|
667
|
+
function writeBridgePid(options) {
|
|
668
|
+
const paths = buildBridgePaths(options.homeDir, options.platform);
|
|
669
|
+
mkdirSync2(paths.baseDir, { recursive: true });
|
|
670
|
+
writeFileSync2(paths.pidFile, `${JSON.stringify({
|
|
671
|
+
...options.agentName ? { agentName: options.agentName } : {},
|
|
672
|
+
...options.apiUrl ? { apiUrl: options.apiUrl } : {},
|
|
673
|
+
pid: options.pid,
|
|
674
|
+
startedAt: options.startedAt
|
|
675
|
+
}, null, 2)}
|
|
676
|
+
`, { mode: 420 });
|
|
677
|
+
}
|
|
678
|
+
function clearBridgePid(options = {}) {
|
|
679
|
+
rmSync2(buildBridgePaths(options.homeDir, options.platform).pidFile, { force: true });
|
|
680
|
+
}
|
|
681
|
+
function baseStatus(paths, options, running) {
|
|
682
|
+
return {
|
|
683
|
+
...options.agentName ? { agentName: options.agentName } : {},
|
|
684
|
+
apiUrl: options.apiUrl ?? "https://mementos.md/api/v1",
|
|
685
|
+
localDatabase: false,
|
|
686
|
+
logFile: paths.logFile,
|
|
687
|
+
pidFile: paths.pidFile,
|
|
688
|
+
remoteOnly: true,
|
|
689
|
+
running
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
function readBridgePid(path) {
|
|
693
|
+
if (!existsSync2(path))
|
|
694
|
+
return;
|
|
695
|
+
try {
|
|
696
|
+
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
697
|
+
return Number.isInteger(parsed.pid) && parsed.pid > 0 ? parsed : undefined;
|
|
698
|
+
} catch {
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
function isRunning(pid) {
|
|
703
|
+
try {
|
|
704
|
+
process.kill(pid, 0);
|
|
705
|
+
return true;
|
|
706
|
+
} catch {
|
|
707
|
+
return false;
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
function renderSystemdService(command, apiUrl, agentName) {
|
|
711
|
+
return `[Unit]
|
|
712
|
+
Description=mementos.md remote bridge
|
|
713
|
+
|
|
714
|
+
[Service]
|
|
715
|
+
Type=simple
|
|
716
|
+
Environment=MEMENTOS_API_URL=${apiUrl}
|
|
717
|
+
${agentName ? `Environment=MEMENTOS_AGENT_NAME=${agentName}
|
|
718
|
+
` : ""}ExecStart=${command}
|
|
719
|
+
Restart=on-failure
|
|
720
|
+
|
|
721
|
+
[Install]
|
|
722
|
+
WantedBy=default.target
|
|
723
|
+
`;
|
|
724
|
+
}
|
|
725
|
+
function renderLaunchdService(command, apiUrl, agentName) {
|
|
726
|
+
const args = command.split(/\s+/).map((part) => ` <string>${escapeXml(part)}</string>`).join(`
|
|
727
|
+
`);
|
|
728
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
729
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
730
|
+
<plist version="1.0">
|
|
731
|
+
<dict>
|
|
732
|
+
<key>Label</key>
|
|
733
|
+
<string>md.mementos.bridge</string>
|
|
734
|
+
<key>ProgramArguments</key>
|
|
735
|
+
<array>
|
|
736
|
+
${args}
|
|
737
|
+
</array>
|
|
738
|
+
<key>EnvironmentVariables</key>
|
|
739
|
+
<dict>
|
|
740
|
+
<key>MEMENTOS_API_URL</key>
|
|
741
|
+
<string>${escapeXml(apiUrl)}</string>
|
|
742
|
+
${agentName ? ` <key>MEMENTOS_AGENT_NAME</key>
|
|
743
|
+
<string>${escapeXml(agentName)}</string>
|
|
744
|
+
` : ""} </dict>
|
|
745
|
+
<key>RunAtLoad</key>
|
|
746
|
+
<true/>
|
|
747
|
+
</dict>
|
|
748
|
+
</plist>
|
|
749
|
+
`;
|
|
750
|
+
}
|
|
751
|
+
function escapeXml(value) {
|
|
752
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
753
|
+
}
|
|
754
|
+
|
|
576
755
|
// src/remote-client.ts
|
|
577
756
|
var DEFAULT_API_URL = "https://mementos.md/api/v1";
|
|
578
757
|
|
|
@@ -753,6 +932,8 @@ async function run(name, args) {
|
|
|
753
932
|
return injectMemory(args);
|
|
754
933
|
case "hook":
|
|
755
934
|
return runHook(args);
|
|
935
|
+
case "bridge":
|
|
936
|
+
return runBridge(args);
|
|
756
937
|
case "billing":
|
|
757
938
|
return runBilling(args);
|
|
758
939
|
case "inbox":
|
|
@@ -778,6 +959,37 @@ async function run(name, args) {
|
|
|
778
959
|
${helpText()}`);
|
|
779
960
|
}
|
|
780
961
|
}
|
|
962
|
+
async function runBridge(args) {
|
|
963
|
+
const subcommand = args[0] ?? "status";
|
|
964
|
+
const options = parseBridgeOptions(args.slice(1));
|
|
965
|
+
const bridgeOptions = {
|
|
966
|
+
agentName: options.agentName ?? process.env.MEMENTOS_AGENT_NAME,
|
|
967
|
+
apiUrl: baseApiUrl().endsWith("/api/v1") ? baseApiUrl() : `${baseApiUrl()}/api/v1`,
|
|
968
|
+
homeDir: options.homeDir ?? process.env.MEMENTOS_BRIDGE_HOME,
|
|
969
|
+
intervalMs: options.intervalMs ?? readPositiveInteger(process.env.MEMENTOS_BRIDGE_INTERVAL_MS)
|
|
970
|
+
};
|
|
971
|
+
switch (subcommand) {
|
|
972
|
+
case "start":
|
|
973
|
+
return startBridge(bridgeOptions);
|
|
974
|
+
case "status":
|
|
975
|
+
return getBridgeStatus(bridgeOptions);
|
|
976
|
+
case "stop":
|
|
977
|
+
return stopBridge(bridgeOptions);
|
|
978
|
+
case "install":
|
|
979
|
+
return installBridgeService({
|
|
980
|
+
...bridgeOptions,
|
|
981
|
+
command: "mementos bridge run"
|
|
982
|
+
});
|
|
983
|
+
case "uninstall":
|
|
984
|
+
return uninstallBridgeService(bridgeOptions);
|
|
985
|
+
case "logs":
|
|
986
|
+
return { lines: readBridgeLogs({ ...bridgeOptions, lines: options.lines }) };
|
|
987
|
+
case "run":
|
|
988
|
+
return runBridgeDaemon(bridgeOptions, Boolean(options.once));
|
|
989
|
+
default:
|
|
990
|
+
throw new Error("usage: mementos bridge <start|status|stop|install|uninstall|logs|run>");
|
|
991
|
+
}
|
|
992
|
+
}
|
|
781
993
|
async function runInbox(args) {
|
|
782
994
|
const subcommand = args[0] ?? "list";
|
|
783
995
|
switch (subcommand) {
|
|
@@ -803,6 +1015,44 @@ async function runInbox(args) {
|
|
|
803
1015
|
throw new Error("usage: mementos inbox <send|list|claim>");
|
|
804
1016
|
}
|
|
805
1017
|
}
|
|
1018
|
+
async function runBridgeDaemon(options, once) {
|
|
1019
|
+
writeBridgePid({
|
|
1020
|
+
agentName: options.agentName,
|
|
1021
|
+
apiUrl: options.apiUrl,
|
|
1022
|
+
homeDir: options.homeDir,
|
|
1023
|
+
pid: process.pid,
|
|
1024
|
+
startedAt: new Date().toISOString()
|
|
1025
|
+
});
|
|
1026
|
+
const cleanup = () => clearBridgePid(options);
|
|
1027
|
+
process.once("SIGINT", () => {
|
|
1028
|
+
cleanup();
|
|
1029
|
+
process.exit(0);
|
|
1030
|
+
});
|
|
1031
|
+
process.once("SIGTERM", () => {
|
|
1032
|
+
cleanup();
|
|
1033
|
+
process.exit(0);
|
|
1034
|
+
});
|
|
1035
|
+
try {
|
|
1036
|
+
const intervalMs = options.intervalMs ?? 30000;
|
|
1037
|
+
do {
|
|
1038
|
+
if (options.agentName) {
|
|
1039
|
+
await client.heartbeatAgent({
|
|
1040
|
+
name: options.agentName,
|
|
1041
|
+
source: "mementos-bridge"
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
if (once)
|
|
1045
|
+
break;
|
|
1046
|
+
await sleep(intervalMs);
|
|
1047
|
+
} while (true);
|
|
1048
|
+
if (once)
|
|
1049
|
+
cleanup();
|
|
1050
|
+
return getBridgeStatus(options);
|
|
1051
|
+
} finally {
|
|
1052
|
+
if (once)
|
|
1053
|
+
cleanup();
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
806
1056
|
async function runBilling(args) {
|
|
807
1057
|
const subcommand = args[0] ?? "status";
|
|
808
1058
|
switch (subcommand) {
|
|
@@ -1017,6 +1267,26 @@ function parseSetupOptions(args) {
|
|
|
1017
1267
|
}
|
|
1018
1268
|
return options;
|
|
1019
1269
|
}
|
|
1270
|
+
function parseBridgeOptions(args) {
|
|
1271
|
+
const options = {};
|
|
1272
|
+
for (let index = 0;index < args.length; index += 1) {
|
|
1273
|
+
const arg = args[index];
|
|
1274
|
+
if (arg === "--agent" || arg === "--agent-name") {
|
|
1275
|
+
options.agentName = args[++index];
|
|
1276
|
+
} else if (arg === "--home") {
|
|
1277
|
+
options.homeDir = args[++index];
|
|
1278
|
+
} else if (arg === "--interval-ms") {
|
|
1279
|
+
options.intervalMs = readPositiveInteger(args[++index]);
|
|
1280
|
+
} else if (arg === "--lines") {
|
|
1281
|
+
options.lines = readPositiveInteger(args[++index]);
|
|
1282
|
+
} else if (arg === "--once") {
|
|
1283
|
+
options.once = true;
|
|
1284
|
+
} else {
|
|
1285
|
+
throw new Error(`Unknown bridge option: ${arg}`);
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
return options;
|
|
1289
|
+
}
|
|
1020
1290
|
function parseInboxOptions(args) {
|
|
1021
1291
|
const options = {};
|
|
1022
1292
|
for (let index = 0;index < args.length; index += 1) {
|
|
@@ -1049,6 +1319,18 @@ function parseHosts(input) {
|
|
|
1049
1319
|
function baseProductUrl() {
|
|
1050
1320
|
return (process.env.MEMENTOS_API_URL ?? DEFAULT_API_URL).replace(/\/api\/v1\/?$/, "").replace(/\/+$/, "");
|
|
1051
1321
|
}
|
|
1322
|
+
function baseApiUrl() {
|
|
1323
|
+
return (process.env.MEMENTOS_API_URL ?? DEFAULT_API_URL).replace(/\/+$/, "");
|
|
1324
|
+
}
|
|
1325
|
+
function readPositiveInteger(input) {
|
|
1326
|
+
if (!input)
|
|
1327
|
+
return;
|
|
1328
|
+
const value = Number(input);
|
|
1329
|
+
return Number.isInteger(value) && value > 0 ? value : undefined;
|
|
1330
|
+
}
|
|
1331
|
+
function sleep(ms) {
|
|
1332
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1333
|
+
}
|
|
1052
1334
|
function readTextPayload(payload) {
|
|
1053
1335
|
if (typeof payload !== "object" || payload === null)
|
|
1054
1336
|
return;
|
|
@@ -1063,6 +1345,7 @@ Usage:
|
|
|
1063
1345
|
mementos setup agents [--dry-run|--verify|--uninstall]
|
|
1064
1346
|
mementos inject <query>
|
|
1065
1347
|
mementos hook <stop|user-prompt-submit|session-start|subagent-start|subagent-stop|pre-tool-use|post-tool-use|notification|setup|doctor>
|
|
1348
|
+
mementos bridge <start|status|stop|install|uninstall|logs|run>
|
|
1066
1349
|
mementos inbox <send|list|claim>
|
|
1067
1350
|
mementos billing <status|credits|buy>
|
|
1068
1351
|
mementos capabilities
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { DEFAULT_API_URL, MementosRemoteClient, MementosRemoteError, createRemoteClientFromEnv, normalizeApiUrl, type RemoteClientConfig, type RemoteRequestOptions, } from "./remote-client";
|
|
2
2
|
export { REMOTE_MCP_TOOLS, callRemoteMcpTool, handleMcpMessage, startMcpStdio, type RemoteMcpTool, } from "./mcp-runtime";
|
|
3
3
|
export { SUPPORTED_AGENT_HOSTS, buildAgentSetupPlan, diagnoseAgentSetup, formatMemoryInjection, installAgentSetup, renderSignupInstructions, type AgentSetupFile, type AgentSetupOptions, type AgentSetupPlan, type AgentSetupDiagnostic, type AgentSetupDiagnosticOptions, type SupportedAgentHost, } from "./agent-setup";
|
|
4
|
+
export { buildBridgePaths, clearBridgePid, getBridgeStatus, installBridgeService, readBridgeLogs, startBridge, stopBridge, uninstallBridgeService, writeBridgePid, type BridgeOptions, type BridgePaths, type BridgeServiceOptions, type BridgeServiceResult, type BridgeStartOptions, type BridgeStatus, } from "./bridge";
|
|
4
5
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,yBAAyB,EACzB,eAAe,EACf,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,KAAK,aAAa,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,wBAAwB,EACxB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,kBAAkB,GACxB,MAAM,eAAe,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,oBAAoB,EACpB,mBAAmB,EACnB,yBAAyB,EACzB,eAAe,EACf,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,GAC1B,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,KAAK,aAAa,GACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,iBAAiB,EACjB,wBAAwB,EACxB,KAAK,cAAc,EACnB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,2BAA2B,EAChC,KAAK,kBAAkB,GACxB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,oBAAoB,EACpB,cAAc,EACd,WAAW,EACX,UAAU,EACV,sBAAsB,EACtB,cAAc,EACd,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,YAAY,GAClB,MAAM,UAAU,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -146,7 +146,7 @@ function readErrorMessage(payload, status) {
|
|
|
146
146
|
}
|
|
147
147
|
// src/mcp-runtime.ts
|
|
148
148
|
import { createInterface } from "readline";
|
|
149
|
-
var MEMENTOS_MCP_VERSION = "0.14.
|
|
149
|
+
var MEMENTOS_MCP_VERSION = "0.14.30";
|
|
150
150
|
var AUTHLESS_SCHEMA = {
|
|
151
151
|
type: "object",
|
|
152
152
|
properties: {},
|
|
@@ -915,16 +915,203 @@ function findLocalDatabaseFiles(dir) {
|
|
|
915
915
|
return localDbPattern.test(entry) ? [path] : [];
|
|
916
916
|
});
|
|
917
917
|
}
|
|
918
|
+
// src/bridge.ts
|
|
919
|
+
import { spawn } from "child_process";
|
|
920
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, openSync, readFileSync as readFileSync2, rmSync as rmSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
921
|
+
import { homedir as homedir2 } from "os";
|
|
922
|
+
import { dirname as dirname2, join as join2 } from "path";
|
|
923
|
+
function buildBridgePaths(homeDir = homedir2(), platform = process.platform) {
|
|
924
|
+
const baseDir = join2(homeDir, ".config", "mementos", "bridge");
|
|
925
|
+
return {
|
|
926
|
+
baseDir,
|
|
927
|
+
logFile: join2(baseDir, "bridge.log"),
|
|
928
|
+
pidFile: join2(baseDir, "bridge.pid.json"),
|
|
929
|
+
serviceFile: platform === "darwin" ? join2(homeDir, "Library", "LaunchAgents", "md.mementos.bridge.plist") : join2(homeDir, ".config", "systemd", "user", "mementos-bridge.service")
|
|
930
|
+
};
|
|
931
|
+
}
|
|
932
|
+
function getBridgeStatus(options = {}) {
|
|
933
|
+
const paths = buildBridgePaths(options.homeDir, options.platform);
|
|
934
|
+
const pidFile = readBridgePid(paths.pidFile);
|
|
935
|
+
if (pidFile && !isRunning(pidFile.pid)) {
|
|
936
|
+
rmSync2(paths.pidFile, { force: true });
|
|
937
|
+
return baseStatus(paths, options, false);
|
|
938
|
+
}
|
|
939
|
+
return {
|
|
940
|
+
...baseStatus(paths, options, Boolean(pidFile)),
|
|
941
|
+
...pidFile?.agentName ? { agentName: pidFile.agentName } : {},
|
|
942
|
+
...pidFile ? { pid: pidFile.pid, startedAt: pidFile.startedAt } : {}
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
function startBridge(options = {}) {
|
|
946
|
+
const current = getBridgeStatus(options);
|
|
947
|
+
if (current.running)
|
|
948
|
+
return current;
|
|
949
|
+
const paths = buildBridgePaths(options.homeDir, options.platform);
|
|
950
|
+
mkdirSync2(paths.baseDir, { recursive: true });
|
|
951
|
+
const out = openSync(paths.logFile, "a");
|
|
952
|
+
const err = openSync(paths.logFile, "a");
|
|
953
|
+
const command = options.command ?? [process.execPath, process.argv[1] ?? "mementos", "bridge", "run"];
|
|
954
|
+
const child = spawn(command[0] ?? "mementos", command.slice(1), {
|
|
955
|
+
detached: true,
|
|
956
|
+
env: {
|
|
957
|
+
...process.env,
|
|
958
|
+
...options.agentName ? { MEMENTOS_AGENT_NAME: options.agentName } : {},
|
|
959
|
+
...options.apiUrl ? { MEMENTOS_API_URL: options.apiUrl } : {},
|
|
960
|
+
...options.homeDir ? { MEMENTOS_BRIDGE_HOME: options.homeDir } : {},
|
|
961
|
+
...options.intervalMs ? { MEMENTOS_BRIDGE_INTERVAL_MS: String(options.intervalMs) } : {}
|
|
962
|
+
},
|
|
963
|
+
stdio: ["ignore", out, err]
|
|
964
|
+
});
|
|
965
|
+
child.unref();
|
|
966
|
+
writeBridgePid({
|
|
967
|
+
agentName: options.agentName,
|
|
968
|
+
apiUrl: options.apiUrl,
|
|
969
|
+
homeDir: options.homeDir,
|
|
970
|
+
pid: child.pid ?? 0,
|
|
971
|
+
startedAt: new Date().toISOString()
|
|
972
|
+
});
|
|
973
|
+
return getBridgeStatus(options);
|
|
974
|
+
}
|
|
975
|
+
function stopBridge(options = {}) {
|
|
976
|
+
const paths = buildBridgePaths(options.homeDir, options.platform);
|
|
977
|
+
const pidFile = readBridgePid(paths.pidFile);
|
|
978
|
+
if (!pidFile)
|
|
979
|
+
return { path: paths.pidFile, remoteOnly: true, status: "absent" };
|
|
980
|
+
if (isRunning(pidFile.pid))
|
|
981
|
+
process.kill(pidFile.pid, "SIGTERM");
|
|
982
|
+
clearBridgePid(options);
|
|
983
|
+
return { path: paths.pidFile, remoteOnly: true, status: "removed" };
|
|
984
|
+
}
|
|
985
|
+
function installBridgeService(options = {}) {
|
|
986
|
+
const platform = options.platform ?? process.platform;
|
|
987
|
+
const paths = buildBridgePaths(options.homeDir, platform);
|
|
988
|
+
mkdirSync2(dirname2(paths.serviceFile), { recursive: true });
|
|
989
|
+
const command = options.command ?? "mementos bridge run";
|
|
990
|
+
const apiUrl = options.apiUrl ?? "https://mementos.md/api/v1";
|
|
991
|
+
const content = platform === "darwin" ? renderLaunchdService(command, apiUrl, options.agentName) : renderSystemdService(command, apiUrl, options.agentName);
|
|
992
|
+
writeFileSync2(paths.serviceFile, content, { mode: 420 });
|
|
993
|
+
return { path: paths.serviceFile, remoteOnly: true, status: "installed" };
|
|
994
|
+
}
|
|
995
|
+
function uninstallBridgeService(options = {}) {
|
|
996
|
+
const paths = buildBridgePaths(options.homeDir, options.platform);
|
|
997
|
+
if (!existsSync2(paths.serviceFile))
|
|
998
|
+
return { path: paths.serviceFile, remoteOnly: true, status: "absent" };
|
|
999
|
+
rmSync2(paths.serviceFile, { force: true });
|
|
1000
|
+
return { path: paths.serviceFile, remoteOnly: true, status: "removed" };
|
|
1001
|
+
}
|
|
1002
|
+
function readBridgeLogs(options = {}) {
|
|
1003
|
+
const paths = buildBridgePaths(options.homeDir, options.platform);
|
|
1004
|
+
if (!existsSync2(paths.logFile))
|
|
1005
|
+
return [];
|
|
1006
|
+
return readFileSync2(paths.logFile, "utf8").split(`
|
|
1007
|
+
`).filter(Boolean).slice(-(options.lines ?? 40));
|
|
1008
|
+
}
|
|
1009
|
+
function writeBridgePid(options) {
|
|
1010
|
+
const paths = buildBridgePaths(options.homeDir, options.platform);
|
|
1011
|
+
mkdirSync2(paths.baseDir, { recursive: true });
|
|
1012
|
+
writeFileSync2(paths.pidFile, `${JSON.stringify({
|
|
1013
|
+
...options.agentName ? { agentName: options.agentName } : {},
|
|
1014
|
+
...options.apiUrl ? { apiUrl: options.apiUrl } : {},
|
|
1015
|
+
pid: options.pid,
|
|
1016
|
+
startedAt: options.startedAt
|
|
1017
|
+
}, null, 2)}
|
|
1018
|
+
`, { mode: 420 });
|
|
1019
|
+
}
|
|
1020
|
+
function clearBridgePid(options = {}) {
|
|
1021
|
+
rmSync2(buildBridgePaths(options.homeDir, options.platform).pidFile, { force: true });
|
|
1022
|
+
}
|
|
1023
|
+
function baseStatus(paths, options, running) {
|
|
1024
|
+
return {
|
|
1025
|
+
...options.agentName ? { agentName: options.agentName } : {},
|
|
1026
|
+
apiUrl: options.apiUrl ?? "https://mementos.md/api/v1",
|
|
1027
|
+
localDatabase: false,
|
|
1028
|
+
logFile: paths.logFile,
|
|
1029
|
+
pidFile: paths.pidFile,
|
|
1030
|
+
remoteOnly: true,
|
|
1031
|
+
running
|
|
1032
|
+
};
|
|
1033
|
+
}
|
|
1034
|
+
function readBridgePid(path) {
|
|
1035
|
+
if (!existsSync2(path))
|
|
1036
|
+
return;
|
|
1037
|
+
try {
|
|
1038
|
+
const parsed = JSON.parse(readFileSync2(path, "utf8"));
|
|
1039
|
+
return Number.isInteger(parsed.pid) && parsed.pid > 0 ? parsed : undefined;
|
|
1040
|
+
} catch {
|
|
1041
|
+
return;
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
function isRunning(pid) {
|
|
1045
|
+
try {
|
|
1046
|
+
process.kill(pid, 0);
|
|
1047
|
+
return true;
|
|
1048
|
+
} catch {
|
|
1049
|
+
return false;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
function renderSystemdService(command, apiUrl, agentName) {
|
|
1053
|
+
return `[Unit]
|
|
1054
|
+
Description=mementos.md remote bridge
|
|
1055
|
+
|
|
1056
|
+
[Service]
|
|
1057
|
+
Type=simple
|
|
1058
|
+
Environment=MEMENTOS_API_URL=${apiUrl}
|
|
1059
|
+
${agentName ? `Environment=MEMENTOS_AGENT_NAME=${agentName}
|
|
1060
|
+
` : ""}ExecStart=${command}
|
|
1061
|
+
Restart=on-failure
|
|
1062
|
+
|
|
1063
|
+
[Install]
|
|
1064
|
+
WantedBy=default.target
|
|
1065
|
+
`;
|
|
1066
|
+
}
|
|
1067
|
+
function renderLaunchdService(command, apiUrl, agentName) {
|
|
1068
|
+
const args = command.split(/\s+/).map((part) => ` <string>${escapeXml(part)}</string>`).join(`
|
|
1069
|
+
`);
|
|
1070
|
+
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
1071
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
1072
|
+
<plist version="1.0">
|
|
1073
|
+
<dict>
|
|
1074
|
+
<key>Label</key>
|
|
1075
|
+
<string>md.mementos.bridge</string>
|
|
1076
|
+
<key>ProgramArguments</key>
|
|
1077
|
+
<array>
|
|
1078
|
+
${args}
|
|
1079
|
+
</array>
|
|
1080
|
+
<key>EnvironmentVariables</key>
|
|
1081
|
+
<dict>
|
|
1082
|
+
<key>MEMENTOS_API_URL</key>
|
|
1083
|
+
<string>${escapeXml(apiUrl)}</string>
|
|
1084
|
+
${agentName ? ` <key>MEMENTOS_AGENT_NAME</key>
|
|
1085
|
+
<string>${escapeXml(agentName)}</string>
|
|
1086
|
+
` : ""} </dict>
|
|
1087
|
+
<key>RunAtLoad</key>
|
|
1088
|
+
<true/>
|
|
1089
|
+
</dict>
|
|
1090
|
+
</plist>
|
|
1091
|
+
`;
|
|
1092
|
+
}
|
|
1093
|
+
function escapeXml(value) {
|
|
1094
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1095
|
+
}
|
|
918
1096
|
export {
|
|
1097
|
+
writeBridgePid,
|
|
1098
|
+
uninstallBridgeService,
|
|
1099
|
+
stopBridge,
|
|
919
1100
|
startMcpStdio,
|
|
1101
|
+
startBridge,
|
|
920
1102
|
renderSignupInstructions,
|
|
1103
|
+
readBridgeLogs,
|
|
921
1104
|
normalizeApiUrl,
|
|
1105
|
+
installBridgeService,
|
|
922
1106
|
installAgentSetup,
|
|
923
1107
|
handleMcpMessage,
|
|
1108
|
+
getBridgeStatus,
|
|
924
1109
|
formatMemoryInjection,
|
|
925
1110
|
diagnoseAgentSetup,
|
|
926
1111
|
createRemoteClientFromEnv,
|
|
1112
|
+
clearBridgePid,
|
|
927
1113
|
callRemoteMcpTool,
|
|
1114
|
+
buildBridgePaths,
|
|
928
1115
|
buildAgentSetupPlan,
|
|
929
1116
|
SUPPORTED_AGENT_HOSTS,
|
|
930
1117
|
REMOTE_MCP_TOOLS,
|
package/dist/mcp-runtime.d.ts
CHANGED
package/dist/mcp.js
CHANGED