@xultrax-web/agent-memory-mcp 0.8.1 → 0.9.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 +52 -3
- package/dist/index.js +283 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -200,6 +200,9 @@ Custom path:
|
|
|
200
200
|
| `verify_memory` | Re-evaluate a memory's claims. Extracts URLs/dates/file refs, flags stale-date signals, returns type-specific verification heuristics. Pairs with the `audit_stale` prompt. |
|
|
201
201
|
| `find_backlinks` | List memories that link to the given memory via `[[wiki-link]]` syntax in their bodies. Useful for "what references this" views. |
|
|
202
202
|
| `find_related` | Surface memories related to one by combining outbound links, inbound backlinks, shared tags, type match, and content similarity. Navigates the memory graph by association. |
|
|
203
|
+
| `sync_status` | Report git-sync state: remote URL, branch, uncommitted local files, ahead/behind origin. |
|
|
204
|
+
| `sync_push` | Commit local memory changes + push to the configured git remote. Auto-timestamps the commit message if none given. |
|
|
205
|
+
| `sync_pull` | Fast-forward pull from the git remote. Refuses to pull if local changes are uncommitted. |
|
|
203
206
|
|
|
204
207
|
### Prompts
|
|
205
208
|
|
|
@@ -265,8 +268,44 @@ agent-memory save my-mem --type project --description "X" --content "Body" --tag
|
|
|
265
268
|
agent-memory list --tags "production" # filter by tag (intersection)
|
|
266
269
|
agent-memory backlinks deploy-process # memories that link to deploy-process
|
|
267
270
|
agent-memory related deploy-process # ranked discovery: links + tags + similarity
|
|
271
|
+
agent-memory sync init git@github.com:you/agent-memory.git # multi-machine setup (one-time)
|
|
272
|
+
agent-memory sync push # commit + push local changes
|
|
273
|
+
agent-memory sync pull # fast-forward from remote
|
|
274
|
+
agent-memory sync status # local + ahead/behind state
|
|
268
275
|
```
|
|
269
276
|
|
|
277
|
+
### Multi-machine memory (git sync)
|
|
278
|
+
|
|
279
|
+
The killer feature for file-based memory: every dev machine has git, and markdown merges cleanly. `agent-memory sync` turns `.agent-memory/` into a git repo pointed at a (private) remote, and your memories follow you across desktop/laptop/server.
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
# One-time setup
|
|
283
|
+
agent-memory sync init git@github.com:you/agent-memory.git
|
|
284
|
+
|
|
285
|
+
# End of the day on desktop
|
|
286
|
+
agent-memory sync push
|
|
287
|
+
|
|
288
|
+
# Pick up your laptop before bed
|
|
289
|
+
agent-memory sync pull
|
|
290
|
+
|
|
291
|
+
# Save a new memory while reading in bed
|
|
292
|
+
agent-memory save bedtime-thought --type project --description "..." --content "..."
|
|
293
|
+
agent-memory sync push
|
|
294
|
+
|
|
295
|
+
# Next morning at desktop
|
|
296
|
+
agent-memory sync pull # picks up the bedtime memory
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
What's NOT synced (per-machine state, kept local):
|
|
300
|
+
|
|
301
|
+
- `.lock` — per-process file lock
|
|
302
|
+
- `.events.jsonl` — per-machine audit trail
|
|
303
|
+
- `.trash/` — soft-delete staging
|
|
304
|
+
|
|
305
|
+
What IS synced: every memory file, the `MEMORY.md` index, and any `.gitignore` you add.
|
|
306
|
+
|
|
307
|
+
Commits use the identity `agent-memory <agent-memory@local>` by default — set `GIT_AUTHOR_EMAIL` / `GIT_COMMITTER_EMAIL` in your environment if you want per-machine attribution.
|
|
308
|
+
|
|
270
309
|
### Audit log + structured logging
|
|
271
310
|
|
|
272
311
|
Every mutation appends one JSON line to `.agent-memory/.events.jsonl`:
|
|
@@ -379,11 +418,21 @@ This server is built to be used daily, not to demo well once.
|
|
|
379
418
|
- **`find_backlinks`** tool + `agent-memory backlinks <name>` CLI — "what links to this".
|
|
380
419
|
- **`find_related`** tool + `agent-memory related <name>` CLI — combines outbound + inbound links, shared tags, type match, and content similarity into a ranked discovery view.
|
|
381
420
|
|
|
382
|
-
**
|
|
421
|
+
**Shipped in v0.9 · the moat — multi-machine memory via git:**
|
|
422
|
+
|
|
423
|
+
- **`agent-memory sync init <remote-url>`** — convert `.agent-memory/` into a git repo, push to remote.
|
|
424
|
+
- **`agent-memory sync push`** — auto-commit local changes + push.
|
|
425
|
+
- **`agent-memory sync pull`** — fast-forward from remote.
|
|
426
|
+
- **`agent-memory sync status`** — local state + commits ahead/behind origin.
|
|
427
|
+
- **`agent-memory sync log`** — history of cross-machine memory changes.
|
|
428
|
+
- **`sync_status` / `sync_push` / `sync_pull` MCP tools** — the LLM can do this too.
|
|
429
|
+
- Per-machine state (`.lock`, `.events.jsonl`, `.trash/`) auto-excluded from sync.
|
|
430
|
+
- Default commit identity injected (`agent-memory@local`) so machines without `git config --global user.email` work without setup.
|
|
431
|
+
|
|
432
|
+
**Landing in v0.10+:**
|
|
383
433
|
|
|
384
|
-
- Folder support (`.agent-memory/work/`, `.agent-memory/personal/`)
|
|
385
434
|
- TUI / web UI for browsing + editing memories in a clean interface
|
|
386
|
-
-
|
|
435
|
+
- Folder support (`.agent-memory/work/`, `.agent-memory/personal/`)
|
|
387
436
|
- Memory packs for shareable curated bundles
|
|
388
437
|
|
|
389
438
|
---
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
26
26
|
import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
27
27
|
import Fuse from "fuse.js";
|
|
28
28
|
import matter from "gray-matter";
|
|
29
|
+
import { spawnSync } from "node:child_process";
|
|
29
30
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync, } from "node:fs";
|
|
30
31
|
import { homedir } from "node:os";
|
|
31
32
|
import { join, resolve } from "node:path";
|
|
@@ -913,6 +914,218 @@ function toolFindRelated(args) {
|
|
|
913
914
|
return lines.join("\n");
|
|
914
915
|
}
|
|
915
916
|
// -------------------------------------------------------------
|
|
917
|
+
// Git sync · multi-machine memory via git remote
|
|
918
|
+
// -------------------------------------------------------------
|
|
919
|
+
//
|
|
920
|
+
// The killer feature for file-based memory: every dev machine has git,
|
|
921
|
+
// and markdown files merge cleanly. Convert .agent-memory/ into a git
|
|
922
|
+
// repo, point it at a (private) GitHub repo, and `sync push` / `sync
|
|
923
|
+
// pull` becomes the multi-machine story.
|
|
924
|
+
//
|
|
925
|
+
// Usage flow:
|
|
926
|
+
// agent-memory sync init git@github.com:you/agent-memory.git
|
|
927
|
+
// ... save some memories ...
|
|
928
|
+
// agent-memory sync push # commit + push
|
|
929
|
+
// # later, on another machine:
|
|
930
|
+
// agent-memory sync pull # pull updates
|
|
931
|
+
// agent-memory sync status # ahead/behind/clean
|
|
932
|
+
//
|
|
933
|
+
// Files we EXCLUDE from sync (per-machine state):
|
|
934
|
+
// .lock · proper-lockfile per-process lock
|
|
935
|
+
// .events.jsonl · per-machine audit log
|
|
936
|
+
// .trash/ · per-machine soft-delete staging
|
|
937
|
+
const SYNC_GITIGNORE = "# Per-machine state · do not sync across devices\n" +
|
|
938
|
+
".lock\n" +
|
|
939
|
+
".events.jsonl\n" +
|
|
940
|
+
".trash/\n";
|
|
941
|
+
function git(args) {
|
|
942
|
+
// Inject a default commit identity so machines without `git config
|
|
943
|
+
// --global user.email` can still sync. Env vars are git's highest-
|
|
944
|
+
// precedence identity source, so they override any later config —
|
|
945
|
+
// fine for automated memory-sync where per-commit attribution
|
|
946
|
+
// doesn't matter. Honors operator overrides if set in the environment.
|
|
947
|
+
const result = spawnSync("git", args, {
|
|
948
|
+
cwd: MEMORY_DIR,
|
|
949
|
+
encoding: "utf8",
|
|
950
|
+
env: {
|
|
951
|
+
...process.env,
|
|
952
|
+
GIT_AUTHOR_NAME: process.env.GIT_AUTHOR_NAME ?? "agent-memory",
|
|
953
|
+
GIT_AUTHOR_EMAIL: process.env.GIT_AUTHOR_EMAIL ?? "agent-memory@local",
|
|
954
|
+
GIT_COMMITTER_NAME: process.env.GIT_COMMITTER_NAME ?? "agent-memory",
|
|
955
|
+
GIT_COMMITTER_EMAIL: process.env.GIT_COMMITTER_EMAIL ?? "agent-memory@local",
|
|
956
|
+
},
|
|
957
|
+
});
|
|
958
|
+
return {
|
|
959
|
+
stdout: (result.stdout ?? "").trim(),
|
|
960
|
+
stderr: (result.stderr ?? "").trim(),
|
|
961
|
+
exitCode: result.status ?? -1,
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
function isGitRepo() {
|
|
965
|
+
return existsSync(join(MEMORY_DIR, ".git"));
|
|
966
|
+
}
|
|
967
|
+
function requireRepo() {
|
|
968
|
+
if (!isGitRepo()) {
|
|
969
|
+
throw new Error(`${MEMORY_DIR} is not a git repo. Run 'agent-memory sync init <remote-url>' first.`);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
function toolSyncInit(args) {
|
|
973
|
+
const remoteUrl = String(args.remote ?? args.url ?? "").trim();
|
|
974
|
+
if (!remoteUrl) {
|
|
975
|
+
throw new Error("Usage: agent-memory sync init <remote-url>\nExample: agent-memory sync init git@github.com:you/agent-memory.git");
|
|
976
|
+
}
|
|
977
|
+
ensureStorage();
|
|
978
|
+
if (isGitRepo()) {
|
|
979
|
+
return `${MEMORY_DIR} is already a git repo. Use 'sync push' or 'sync pull'.`;
|
|
980
|
+
}
|
|
981
|
+
const init = git(["init", "-b", "main"]);
|
|
982
|
+
if (init.exitCode !== 0)
|
|
983
|
+
throw new Error(`git init failed: ${init.stderr}`);
|
|
984
|
+
writeFileSync(join(MEMORY_DIR, ".gitignore"), SYNC_GITIGNORE, "utf8");
|
|
985
|
+
const addRemote = git(["remote", "add", "origin", remoteUrl]);
|
|
986
|
+
if (addRemote.exitCode !== 0)
|
|
987
|
+
throw new Error(`git remote add failed: ${addRemote.stderr}`);
|
|
988
|
+
const add = git(["add", "-A"]);
|
|
989
|
+
if (add.exitCode !== 0)
|
|
990
|
+
throw new Error(`git add failed: ${add.stderr}`);
|
|
991
|
+
const commit = git(["commit", "-m", "agent-memory · initial sync"]);
|
|
992
|
+
// commit can fail if there's nothing to commit (empty store) — that's OK
|
|
993
|
+
if (commit.exitCode !== 0 && !commit.stderr.includes("nothing to commit")) {
|
|
994
|
+
log("warn", "initial commit had no changes", { stderr: commit.stderr });
|
|
995
|
+
}
|
|
996
|
+
const push = git(["push", "-u", "origin", "main"]);
|
|
997
|
+
logEvent("sync_init", { remote: remoteUrl, pushed: push.exitCode === 0 });
|
|
998
|
+
const lines = [
|
|
999
|
+
c(ANSI.green, "✓ initialized memory sync"),
|
|
1000
|
+
` storage : ${MEMORY_DIR}`,
|
|
1001
|
+
` remote : ${remoteUrl}`,
|
|
1002
|
+
` branch : main`,
|
|
1003
|
+
];
|
|
1004
|
+
if (push.exitCode !== 0) {
|
|
1005
|
+
lines.push("");
|
|
1006
|
+
lines.push(c(ANSI.yellow, "Initial push failed (remote may not exist yet):"));
|
|
1007
|
+
lines.push(` ${push.stderr.split("\n")[0]}`);
|
|
1008
|
+
lines.push("");
|
|
1009
|
+
lines.push("Create the empty remote on GitHub (or your git host), then run:");
|
|
1010
|
+
lines.push(" agent-memory sync push");
|
|
1011
|
+
}
|
|
1012
|
+
else {
|
|
1013
|
+
lines.push("");
|
|
1014
|
+
lines.push("Future commands: 'sync push' / 'sync pull' / 'sync status' / 'sync log'");
|
|
1015
|
+
}
|
|
1016
|
+
return lines.join("\n");
|
|
1017
|
+
}
|
|
1018
|
+
function toolSyncStatus(_args) {
|
|
1019
|
+
if (!isGitRepo()) {
|
|
1020
|
+
return `${MEMORY_DIR} is not a git repo. Use 'sync init <remote-url>' to set it up.`;
|
|
1021
|
+
}
|
|
1022
|
+
const remote = git(["remote", "get-url", "origin"]);
|
|
1023
|
+
const branch = git(["branch", "--show-current"]);
|
|
1024
|
+
const fetch = git(["fetch", "origin", "--quiet"]);
|
|
1025
|
+
const offline = fetch.exitCode !== 0;
|
|
1026
|
+
const status = git(["status", "--porcelain"]);
|
|
1027
|
+
const localChanges = status.stdout.split("\n").filter(Boolean).length;
|
|
1028
|
+
const lines = [];
|
|
1029
|
+
lines.push(c(ANSI.bold, "agent-memory sync · status"));
|
|
1030
|
+
lines.push(` storage : ${MEMORY_DIR}`);
|
|
1031
|
+
lines.push(` remote : ${remote.stdout || c(ANSI.yellow, "(none configured)")}`);
|
|
1032
|
+
lines.push(` branch : ${branch.stdout || "(unknown)"}`);
|
|
1033
|
+
if (offline) {
|
|
1034
|
+
lines.push(` fetch : ${c(ANSI.yellow, "offline — couldn't reach remote")}`);
|
|
1035
|
+
}
|
|
1036
|
+
lines.push("");
|
|
1037
|
+
lines.push(c(ANSI.bold, "local state:"));
|
|
1038
|
+
if (localChanges === 0) {
|
|
1039
|
+
lines.push(` ${c(ANSI.green, "✓ clean")} — no uncommitted changes`);
|
|
1040
|
+
}
|
|
1041
|
+
else {
|
|
1042
|
+
lines.push(` ${c(ANSI.yellow, `${localChanges} file(s) uncommitted`)} — run 'sync push' to commit + send`);
|
|
1043
|
+
}
|
|
1044
|
+
if (!offline && branch.stdout) {
|
|
1045
|
+
const ahead = git(["rev-list", "--count", `origin/${branch.stdout}..HEAD`]);
|
|
1046
|
+
const behind = git(["rev-list", "--count", `HEAD..origin/${branch.stdout}`]);
|
|
1047
|
+
const aheadN = Number(ahead.stdout || "0");
|
|
1048
|
+
const behindN = Number(behind.stdout || "0");
|
|
1049
|
+
lines.push("");
|
|
1050
|
+
lines.push(c(ANSI.bold, "vs origin:"));
|
|
1051
|
+
if (aheadN === 0 && behindN === 0) {
|
|
1052
|
+
lines.push(` ${c(ANSI.green, "✓ in sync")}`);
|
|
1053
|
+
}
|
|
1054
|
+
else {
|
|
1055
|
+
if (aheadN > 0)
|
|
1056
|
+
lines.push(` ${c(ANSI.cyan, `↑ ${aheadN} commit(s) ahead`)} — run 'sync push'`);
|
|
1057
|
+
if (behindN > 0)
|
|
1058
|
+
lines.push(` ${c(ANSI.cyan, `↓ ${behindN} commit(s) behind`)} — run 'sync pull'`);
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
return lines.join("\n");
|
|
1062
|
+
}
|
|
1063
|
+
function toolSyncPush(args) {
|
|
1064
|
+
requireRepo();
|
|
1065
|
+
const message = args.message
|
|
1066
|
+
? String(args.message)
|
|
1067
|
+
: `agent-memory · sync ${new Date().toISOString().slice(0, 19).replace("T", " ")}Z`;
|
|
1068
|
+
const add = git(["add", "-A"]);
|
|
1069
|
+
if (add.exitCode !== 0)
|
|
1070
|
+
throw new Error(`git add failed: ${add.stderr}`);
|
|
1071
|
+
const status = git(["status", "--porcelain"]);
|
|
1072
|
+
const hadChanges = status.stdout.length > 0;
|
|
1073
|
+
if (hadChanges) {
|
|
1074
|
+
const commit = git(["commit", "-m", message]);
|
|
1075
|
+
if (commit.exitCode !== 0)
|
|
1076
|
+
throw new Error(`commit failed: ${commit.stderr}`);
|
|
1077
|
+
}
|
|
1078
|
+
const push = git(["push"]);
|
|
1079
|
+
if (push.exitCode !== 0)
|
|
1080
|
+
throw new Error(`push failed: ${push.stderr}`);
|
|
1081
|
+
logEvent("sync_push", { hadChanges, commitMessage: hadChanges ? message : null });
|
|
1082
|
+
return hadChanges
|
|
1083
|
+
? c(ANSI.green, `✓ committed local changes + pushed to remote\n message: ${message}`)
|
|
1084
|
+
: c(ANSI.green, `✓ nothing new locally; pushed any unpushed commits`);
|
|
1085
|
+
}
|
|
1086
|
+
function toolSyncPull(_args) {
|
|
1087
|
+
requireRepo();
|
|
1088
|
+
const status = git(["status", "--porcelain"]);
|
|
1089
|
+
if (status.stdout) {
|
|
1090
|
+
return (c(ANSI.yellow, "Local changes uncommitted.") +
|
|
1091
|
+
"\nRun 'agent-memory sync push' first to commit them, then pull.");
|
|
1092
|
+
}
|
|
1093
|
+
const pull = git(["pull", "--ff-only"]);
|
|
1094
|
+
if (pull.exitCode !== 0) {
|
|
1095
|
+
return (c(ANSI.red, "✗ pull failed:") +
|
|
1096
|
+
`\n ${pull.stderr.split("\n").slice(0, 3).join("\n ")}\n\n` +
|
|
1097
|
+
`Likely diverged history (commits on both sides). Resolve manually:\n` +
|
|
1098
|
+
` cd ${MEMORY_DIR}\n` +
|
|
1099
|
+
` git pull # do the merge by hand`);
|
|
1100
|
+
}
|
|
1101
|
+
logEvent("sync_pull", { output: pull.stdout.split("\n")[0] });
|
|
1102
|
+
return c(ANSI.green, "✓ pulled from remote") + (pull.stdout ? `\n${pull.stdout}` : "");
|
|
1103
|
+
}
|
|
1104
|
+
function toolSyncLog(args) {
|
|
1105
|
+
if (!isGitRepo())
|
|
1106
|
+
return `${MEMORY_DIR} is not a git repo.`;
|
|
1107
|
+
const limit = args.limit ? Number(args.limit) : 20;
|
|
1108
|
+
const log = git(["log", `--max-count=${limit}`, "--pretty=format:%h %ci %s", "--no-decorate"]);
|
|
1109
|
+
if (log.exitCode !== 0)
|
|
1110
|
+
return `git log failed: ${log.stderr}`;
|
|
1111
|
+
if (!log.stdout)
|
|
1112
|
+
return "No sync history yet.";
|
|
1113
|
+
const lines = [];
|
|
1114
|
+
lines.push(c(ANSI.bold, `Recent sync history (last ${limit}):`));
|
|
1115
|
+
lines.push("");
|
|
1116
|
+
for (const line of log.stdout.split("\n")) {
|
|
1117
|
+
// Format: <short-sha> <iso-date> <subject>
|
|
1118
|
+
const m = line.match(/^(\S+)\s+(\S+\s+\S+\s+\S+)\s+(.*)$/);
|
|
1119
|
+
if (m) {
|
|
1120
|
+
lines.push(` ${c(ANSI.cyan, m[1])} ${c(ANSI.dim, m[2])} ${m[3]}`);
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1123
|
+
lines.push(` ${line}`);
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
return lines.join("\n");
|
|
1127
|
+
}
|
|
1128
|
+
// -------------------------------------------------------------
|
|
916
1129
|
// Stats · operator dashboard
|
|
917
1130
|
// -------------------------------------------------------------
|
|
918
1131
|
function toolStats(_args) {
|
|
@@ -1022,7 +1235,7 @@ function actionColor(action) {
|
|
|
1022
1235
|
// -------------------------------------------------------------
|
|
1023
1236
|
// Server wiring
|
|
1024
1237
|
// -------------------------------------------------------------
|
|
1025
|
-
const server = new Server({ name: "agent-memory", version: "0.
|
|
1238
|
+
const server = new Server({ name: "agent-memory", version: "0.9.0" }, { capabilities: { tools: {}, resources: {}, prompts: {} } });
|
|
1026
1239
|
// -------------------------------------------------------------
|
|
1027
1240
|
// Resource URI scheme
|
|
1028
1241
|
// -------------------------------------------------------------
|
|
@@ -1434,6 +1647,29 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
|
1434
1647
|
required: ["name"],
|
|
1435
1648
|
},
|
|
1436
1649
|
},
|
|
1650
|
+
{
|
|
1651
|
+
name: "sync_status",
|
|
1652
|
+
description: "Report the git-sync state of the memory store: remote URL, branch, local uncommitted files, commits ahead/behind origin. Use this before opening a new session to know if you have stale memories from another machine.",
|
|
1653
|
+
inputSchema: { type: "object", properties: {} },
|
|
1654
|
+
},
|
|
1655
|
+
{
|
|
1656
|
+
name: "sync_push",
|
|
1657
|
+
description: "Commit any local memory changes and push to the configured git remote. Auto-generates a timestamped commit message if none provided. Use at the end of a session to make memories available on your other machines.",
|
|
1658
|
+
inputSchema: {
|
|
1659
|
+
type: "object",
|
|
1660
|
+
properties: {
|
|
1661
|
+
message: {
|
|
1662
|
+
type: "string",
|
|
1663
|
+
description: "Optional commit message. Defaults to a timestamp.",
|
|
1664
|
+
},
|
|
1665
|
+
},
|
|
1666
|
+
},
|
|
1667
|
+
},
|
|
1668
|
+
{
|
|
1669
|
+
name: "sync_pull",
|
|
1670
|
+
description: "Pull memory updates from the configured git remote (fast-forward only). Run at the start of a session to get memories saved on other machines. Refuses to pull if there are uncommitted local changes.",
|
|
1671
|
+
inputSchema: { type: "object", properties: {} },
|
|
1672
|
+
},
|
|
1437
1673
|
],
|
|
1438
1674
|
}));
|
|
1439
1675
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
@@ -1480,6 +1716,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
1480
1716
|
case "find_related":
|
|
1481
1717
|
result = toolFindRelated(args);
|
|
1482
1718
|
break;
|
|
1719
|
+
case "sync_status":
|
|
1720
|
+
result = toolSyncStatus(args);
|
|
1721
|
+
break;
|
|
1722
|
+
case "sync_push":
|
|
1723
|
+
result = toolSyncPush(args);
|
|
1724
|
+
break;
|
|
1725
|
+
case "sync_pull":
|
|
1726
|
+
result = toolSyncPull(args);
|
|
1727
|
+
break;
|
|
1483
1728
|
default:
|
|
1484
1729
|
throw new Error(`Unknown tool: ${name}`);
|
|
1485
1730
|
}
|
|
@@ -1515,6 +1760,7 @@ const CLI_COMMANDS = new Set([
|
|
|
1515
1760
|
"verify",
|
|
1516
1761
|
"backlinks",
|
|
1517
1762
|
"related",
|
|
1763
|
+
"sync",
|
|
1518
1764
|
"import-claude-code",
|
|
1519
1765
|
"help",
|
|
1520
1766
|
"--help",
|
|
@@ -1670,6 +1916,36 @@ async function cliMain(command, rest) {
|
|
|
1670
1916
|
}) + "\n");
|
|
1671
1917
|
return 0;
|
|
1672
1918
|
}
|
|
1919
|
+
case "sync": {
|
|
1920
|
+
const sub = positional[0];
|
|
1921
|
+
if (!sub) {
|
|
1922
|
+
throw new Error("Usage: agent-memory sync <init|push|pull|status|log>\n" +
|
|
1923
|
+
" init <remote-url> set up a new memory-sync repo\n" +
|
|
1924
|
+
" push [--message X] commit + push local changes\n" +
|
|
1925
|
+
" pull fast-forward pull from remote\n" +
|
|
1926
|
+
" status show local + remote state\n" +
|
|
1927
|
+
" log [--limit N] recent sync commit history");
|
|
1928
|
+
}
|
|
1929
|
+
switch (sub) {
|
|
1930
|
+
case "init":
|
|
1931
|
+
process.stdout.write(toolSyncInit({ remote: positional[1] }) + "\n");
|
|
1932
|
+
return 0;
|
|
1933
|
+
case "push":
|
|
1934
|
+
process.stdout.write(toolSyncPush({ message: flags.message }) + "\n");
|
|
1935
|
+
return 0;
|
|
1936
|
+
case "pull":
|
|
1937
|
+
process.stdout.write(toolSyncPull({}) + "\n");
|
|
1938
|
+
return 0;
|
|
1939
|
+
case "status":
|
|
1940
|
+
process.stdout.write(toolSyncStatus({}) + "\n");
|
|
1941
|
+
return 0;
|
|
1942
|
+
case "log":
|
|
1943
|
+
process.stdout.write(toolSyncLog({ limit: flags.limit ? Number(flags.limit) : undefined }) + "\n");
|
|
1944
|
+
return 0;
|
|
1945
|
+
default:
|
|
1946
|
+
throw new Error(`Unknown sync subcommand: ${sub}. Try 'sync' for help.`);
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1673
1949
|
case "log": {
|
|
1674
1950
|
process.stdout.write(toolLogEvents({
|
|
1675
1951
|
tail: flags.tail ? Number(flags.tail) : undefined,
|
|
@@ -1728,6 +2004,12 @@ COMMANDS
|
|
|
1728
2004
|
backlinks <name> List memories that link to <name> via [[wiki-links]].
|
|
1729
2005
|
related <name> [--max N] Surface related memories via outbound + inbound links,
|
|
1730
2006
|
shared tags, type match, content similarity.
|
|
2007
|
+
sync <init|push|pull|status|log> Multi-machine memory via git remote.
|
|
2008
|
+
sync init <remote-url> Initialize .agent-memory/ as a git repo + push.
|
|
2009
|
+
sync push [--message X] Commit local changes + push to remote.
|
|
2010
|
+
sync pull Fast-forward pull from remote.
|
|
2011
|
+
sync status Show local + ahead/behind state.
|
|
2012
|
+
sync log [--limit N] Recent sync commit history.
|
|
1731
2013
|
import-claude-code [--source <path>] [--project <pat>] [--overwrite] [--dry-run]
|
|
1732
2014
|
Walk ~/.claude/projects/*/memory/ and
|
|
1733
2015
|
import each memory into the current store.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xultrax-web/agent-memory-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"mcpName": "io.github.xultrax-web/agent-memory-mcp",
|
|
5
5
|
"description": "Markdown memory for AI agents. Plain files you can read, edit, grep, and commit. The only MCP memory server that isn't a database.",
|
|
6
6
|
"type": "module",
|