@xultrax-web/agent-memory-mcp 0.11.7 → 0.12.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.
Files changed (2) hide show
  1. package/dist/index.js +47 -31
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -615,27 +615,27 @@ export function toolDeleteMemory(args) {
615
615
  const fp = memoryFilePath(name);
616
616
  if (!existsSync(fp))
617
617
  return `Memory "${name}" not found.`;
618
- // v0.11.3 · receipt-gated path. If a receipt is supplied, validate it
619
- // against the current rule set + required caveats. If validation fails,
620
- // refuse the delete with a clear reason. If no receipt is supplied,
621
- // proceed (back-compat) but log so audit can surface the gap. v0.12
622
- // will require receipts unconditionally for destructive ops.
618
+ // v0.12.0 · receipt REQUIRED for delete_memory. The v0.11.x back-compat
619
+ // path (delete without receipt) is removed. Callers MUST first call
620
+ // check_action({action_type: 'deletions'}) to obtain a fresh receipt,
621
+ // then pass it to delete_memory as the `receipt` argument.
623
622
  const receipt = parseReceiptArg(args.receipt);
624
- if (receipt) {
625
- const v = validateReceipt(receipt, {
626
- required_caveats: [{ type: "action_type", value: "deletions" }],
627
- });
628
- if (!v.valid) {
629
- logEvent("delete_denied", { name, reason: v.reason, receipt_id: receipt.id });
630
- throw new Error(`delete_memory refused · receipt invalid (${v.reason}). ` +
631
- `Call check_action({action: 'delete memory ${name}', action_type: 'deletions'}) ` +
632
- `to get a fresh receipt.`);
633
- }
634
- logEvent("delete_approved_via_receipt", { name, receipt_id: receipt.id });
635
- }
636
- else {
637
- logEvent("delete_without_receipt", { name });
623
+ if (!receipt) {
624
+ logEvent("delete_refused_no_receipt", { name });
625
+ throw new Error(`delete_memory refused · receipt required (v0.12.0+). ` +
626
+ `Call check_action({action: 'delete memory ${name}', action_type: 'deletions'}) ` +
627
+ `first, then pass the issued receipt as the 'receipt' argument to delete_memory.`);
628
+ }
629
+ const v = validateReceipt(receipt, {
630
+ required_caveats: [{ type: "action_type", value: "deletions" }],
631
+ });
632
+ if (!v.valid) {
633
+ logEvent("delete_denied", { name, reason: v.reason, receipt_id: receipt.id });
634
+ throw new Error(`delete_memory refused · receipt invalid (${v.reason}). ` +
635
+ `Call check_action({action: 'delete memory ${name}', action_type: 'deletions'}) ` +
636
+ `to get a fresh receipt.`);
638
637
  }
638
+ logEvent("delete_approved_via_receipt", { name, receipt_id: receipt.id });
639
639
  return withLock(() => {
640
640
  ensureTrash();
641
641
  // Trash filename: <unix-ms>-<name>.md so restore can pick the
@@ -644,12 +644,9 @@ export function toolDeleteMemory(args) {
644
644
  const trashPath = join(TRASH_DIR, `${ts}-${name}.md`);
645
645
  renameSync(fp, trashPath);
646
646
  removeIndexEntryUnlocked(name);
647
- logEvent("delete", { name, trash: `${ts}-${name}.md`, gated: !!receipt });
647
+ logEvent("delete", { name, trash: `${ts}-${name}.md`, gated: true });
648
648
  log("debug", "delete_memory", { name });
649
- const gateMsg = receipt
650
- ? ` (gated by receipt ${receipt.id})`
651
- : " (no receipt · v0.11.3 back-compat path)";
652
- return `Moved "${name}" to trash${gateMsg}. Restore with: agent-memory restore ${name}`;
649
+ return `Moved "${name}" to trash (gated by receipt ${receipt.id}). Restore with: agent-memory restore ${name}`;
653
650
  });
654
651
  }
655
652
  function toolRestoreMemory(args) {
@@ -1782,7 +1779,14 @@ function recentDenials() {
1782
1779
  }));
1783
1780
  }
1784
1781
  function recentUnreceiptedDeletes() {
1785
- const records = readEventLog({ tail: AUDIT_EVENT_TAIL, action: "delete_without_receipt" });
1782
+ // v0.11.x emitted "delete_without_receipt" when an unreceipted delete
1783
+ // succeeded. v0.12.0 emits "delete_refused_no_receipt" when refusing.
1784
+ // We surface BOTH event types so an audit run against pre-v0.12 logs
1785
+ // still reports historical unreceipted deletes correctly.
1786
+ const records = [
1787
+ ...readEventLog({ tail: AUDIT_EVENT_TAIL, action: "delete_without_receipt" }),
1788
+ ...readEventLog({ tail: AUDIT_EVENT_TAIL, action: "delete_refused_no_receipt" }),
1789
+ ];
1786
1790
  return records.map((r) => ({
1787
1791
  ts: String(r.ts),
1788
1792
  name: String(r.name ?? ""),
@@ -2188,7 +2192,7 @@ function actionColor(action) {
2188
2192
  // -------------------------------------------------------------
2189
2193
  // Server wiring
2190
2194
  // -------------------------------------------------------------
2191
- const server = new Server({ name: "agent-memory", version: "0.11.7" }, { capabilities: { tools: {}, resources: {}, prompts: {} } });
2195
+ const server = new Server({ name: "agent-memory", version: "0.12.0" }, { capabilities: { tools: {}, resources: {}, prompts: {} } });
2192
2196
  // -------------------------------------------------------------
2193
2197
  // Resource URI scheme
2194
2198
  // -------------------------------------------------------------
@@ -2512,18 +2516,18 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
2512
2516
  {
2513
2517
  name: "delete_memory",
2514
2518
  description: "Move a memory to .trash/ (soft delete). The file is removed from the index but recoverable via restore_memory until you manually empty .trash/. " +
2515
- "v0.11.3+ accepts an optional `receipt` argument · pass a Compliance Receipt from check_action({action_type: 'deletions'}) to gate the delete against the rule store. " +
2519
+ "v0.12.0+ · receipt REQUIRED. Caller MUST first call check_action({action: 'delete memory <name>', action_type: 'deletions'}) to obtain a fresh Compliance Receipt, then pass it to this tool as `receipt`. " +
2516
2520
  "Receipts must carry the caveat {type: 'action_type', value: 'deletions'} or the delete refuses. " +
2517
- "Receipts not supplied are accepted (back-compat) but logged · v0.12 will require them.",
2521
+ "Migration from v0.11.x: previously unreceipted deletes were accepted with a warning · now they throw. Add a check_action call before each delete_memory call.",
2518
2522
  inputSchema: {
2519
2523
  type: "object",
2520
2524
  properties: {
2521
2525
  name: { type: "string", description: "The memory's name slug" },
2522
2526
  receipt: {
2523
- description: "Optional Compliance Receipt (object or JSON string) from check_action. v0.11.3 logs unreceipted deletes but doesn't block them yet.",
2527
+ description: "REQUIRED · Compliance Receipt (object or JSON string) from check_action with action_type=deletions. Without this, the delete is refused.",
2524
2528
  },
2525
2529
  },
2526
- required: ["name"],
2530
+ required: ["name", "receipt"],
2527
2531
  },
2528
2532
  },
2529
2533
  {
@@ -2986,7 +2990,19 @@ async function cliMain(command, rest) {
2986
2990
  const name = positional[0];
2987
2991
  if (!name)
2988
2992
  throw new Error("Usage: agent-memory delete <name>");
2989
- process.stdout.write(toolDeleteMemory({ name }) + "\n");
2993
+ // v0.12.0+ · delete_memory requires a Compliance Receipt. The CLI
2994
+ // is the trusted operator path (a human is running the command,
2995
+ // not an AI agent), so we auto-issue a CLI-scoped receipt rather
2996
+ // than make the operator chain `check-action` then paste JSON.
2997
+ // MCP callers (AI agents) still must go through check_action
2998
+ // explicitly — this short-circuit only fires from the CLI binary.
2999
+ const receipt = issueReceipt({
3000
+ caveats: [
3001
+ { type: "action_type", value: "deletions" },
3002
+ { type: "issued_by", value: "cli" },
3003
+ ],
3004
+ });
3005
+ process.stdout.write(toolDeleteMemory({ name, receipt: JSON.stringify(receipt) }) + "\n");
2990
3006
  return 0;
2991
3007
  }
2992
3008
  case "restore": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xultrax-web/agent-memory-mcp",
3
- "version": "0.11.7",
3
+ "version": "0.12.0",
4
4
  "mcpName": "io.github.xultrax-web/agent-memory-mcp",
5
5
  "description": "Codify how you work. Every AI tool obeys. Markdown rules + cross-tool companion files (AGENTS.md/CLAUDE.md/.cursor/rules/.gemini) + Compliance Receipts for protocol-level enforcement of destructive ops. Reference implementation of CRP 1.0. Works on every MCP client (no Sampling required).",
6
6
  "type": "module",