myagentmemory 0.5.1 → 0.5.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/upgrade.js CHANGED
@@ -1,12 +1,18 @@
1
1
  /**
2
2
  * Upgrade orchestration for the `agent-memory` CLI and its official Pro plugin bundle.
3
3
  *
4
- * Two consumers:
4
+ * Three consumers:
5
5
  * 1. `agent-memory upgrade` — explicit user command; checks and (optionally) installs.
6
- * 2. `agent-memory hook session-start` — passive notice from a 24h-cached record.
6
+ * 2. `agent-memory upgrade --background` — detached, non-interactive; checks, then
7
+ * installs any target whose `readUpgradePolicy()` value is `"auto"` (the default).
8
+ * Spawned by `refreshUpgradeCacheBackground()` from `hook session-start`.
9
+ * 3. `agent-memory hook session-start` — passive notice from a 24h-cached record,
10
+ * including the outcome of the last `--background` auto-install attempt.
7
11
  *
8
12
  * Network calls always have a hard timeout and always fail closed (upgrade is a
9
- * quality-of-life feature; a flaky registry must never break the CLI).
13
+ * quality-of-life feature; a flaky registry must never break the CLI). Same fail-closed
14
+ * contract applies to auto-install: a failed background install is recorded, never
15
+ * retried before the next cache refresh, and never thrown.
10
16
  */
11
17
  import { spawn, spawnSync } from "node:child_process";
12
18
  import * as fs from "node:fs";
@@ -50,6 +56,15 @@ async function fetchLatestFromNpm(fetchImpl = globalThis.fetch) {
50
56
  function upgradeCachePath() {
51
57
  return path.join(getMemoryDir(), "state", "upgrade-check.json");
52
58
  }
59
+ function isValidAutoOutcome(value) {
60
+ if (typeof value !== "object" || value === null)
61
+ return false;
62
+ const candidate = value;
63
+ return (typeof candidate.at === "string" &&
64
+ typeof candidate.ok === "boolean" &&
65
+ (candidate.version === null || typeof candidate.version === "string") &&
66
+ (candidate.error === undefined || typeof candidate.error === "string"));
67
+ }
53
68
  export function readUpgradeCache() {
54
69
  try {
55
70
  const raw = fs.readFileSync(upgradeCachePath(), "utf-8");
@@ -69,6 +84,8 @@ export function readUpgradeCache() {
69
84
  cliLatest: parsed.cliLatest ?? null,
70
85
  pluginCurrent: parsed.pluginCurrent ?? null,
71
86
  pluginLatest: parsed.pluginLatest ?? null,
87
+ cliAuto: isValidAutoOutcome(parsed.cliAuto) ? parsed.cliAuto : undefined,
88
+ pluginAuto: isValidAutoOutcome(parsed.pluginAuto) ? parsed.pluginAuto : undefined,
72
89
  };
73
90
  }
74
91
  catch {
@@ -93,6 +110,60 @@ export function isCacheFresh(record, now = Date.now()) {
93
110
  return false;
94
111
  return now - checked < CACHE_TTL_MS;
95
112
  }
113
+ const UPGRADE_POLICY_FILENAME = "upgrade-policy.json";
114
+ const UPGRADE_POLICY_DEFAULT = { cli: "auto", plugin: "auto" };
115
+ function upgradePolicyPath() {
116
+ return path.join(getMemoryDir(), "state", UPGRADE_POLICY_FILENAME);
117
+ }
118
+ function isPolicyValue(value) {
119
+ return value === "off" || value === "notify" || value === "auto";
120
+ }
121
+ /**
122
+ * Resolve the persisted auto-upgrade policy.
123
+ * Precedence per target: `AGENT_MEMORY_AUTO_UPGRADE_{CLI,PLUGIN}` env var →
124
+ * `<memoryDir>/state/upgrade-policy.json` → default `"auto"`.
125
+ *
126
+ * `existed` tells callers whether the policy file was already on disk —
127
+ * used to fire a one-time "auto-upgrade is on" notice on first read.
128
+ */
129
+ export function readUpgradePolicy() {
130
+ let stored = {};
131
+ let existed = false;
132
+ try {
133
+ const raw = fs.readFileSync(upgradePolicyPath(), "utf-8");
134
+ const parsed = JSON.parse(raw);
135
+ if (isPolicyValue(parsed.cli) || isPolicyValue(parsed.plugin)) {
136
+ stored = parsed;
137
+ existed = true;
138
+ }
139
+ }
140
+ catch { }
141
+ const envCli = process.env.AGENT_MEMORY_AUTO_UPGRADE_CLI;
142
+ const envPlugin = process.env.AGENT_MEMORY_AUTO_UPGRADE_PLUGIN;
143
+ return {
144
+ cli: isPolicyValue(envCli) ? envCli : isPolicyValue(stored.cli) ? stored.cli : UPGRADE_POLICY_DEFAULT.cli,
145
+ plugin: isPolicyValue(envPlugin)
146
+ ? envPlugin
147
+ : isPolicyValue(stored.plugin)
148
+ ? stored.plugin
149
+ : UPGRADE_POLICY_DEFAULT.plugin,
150
+ existed,
151
+ };
152
+ }
153
+ /** Atomically persist the auto-upgrade policy. Merges with whatever is already on disk. */
154
+ export function writeUpgradePolicy(patch) {
155
+ const current = readUpgradePolicy();
156
+ const next = {
157
+ cli: patch.cli ?? current.cli,
158
+ plugin: patch.plugin ?? current.plugin,
159
+ };
160
+ const target = upgradePolicyPath();
161
+ fs.mkdirSync(path.dirname(target), { recursive: true });
162
+ const temporary = `${target}.${process.pid}.tmp`;
163
+ fs.writeFileSync(temporary, `${JSON.stringify(next, null, 2)}\n`, { mode: 0o600 });
164
+ fs.renameSync(temporary, target);
165
+ return next;
166
+ }
96
167
  // ---------------------------------------------------------------------------
97
168
  // Install-method detection
98
169
  // ---------------------------------------------------------------------------
@@ -163,8 +234,10 @@ export function runInstaller(method, opts = {}) {
163
234
  // ---------------------------------------------------------------------------
164
235
  /**
165
236
  * Fire-and-forget: spawn a detached child that runs `agent-memory upgrade
166
- * --check --refresh --quiet` so the next session-start has a fresh cache.
167
- * Never awaits, never throws.
237
+ * --background --refresh --quiet` so the next session-start has a fresh
238
+ * cache. Unlike a plain check, `--background` also installs any target whose
239
+ * policy is `"auto"` (see `readUpgradePolicy`) — this is the one place
240
+ * auto-upgrade actually happens. Never awaits, never throws.
168
241
  */
169
242
  export function refreshUpgradeCacheBackground() {
170
243
  try {
@@ -172,7 +245,7 @@ export function refreshUpgradeCacheBackground() {
172
245
  const script = process.argv[1];
173
246
  if (!binary || !script)
174
247
  return;
175
- const child = spawn(binary, [script, "upgrade", "--check", "--refresh", "--quiet", "--json"], {
248
+ const child = spawn(binary, [script, "upgrade", "--background", "--refresh", "--quiet", "--json"], {
176
249
  detached: true,
177
250
  stdio: "ignore",
178
251
  env: { ...process.env, AGENT_MEMORY_UPGRADE_BACKGROUND: "1" },
@@ -231,13 +304,40 @@ export async function checkForUpgrades(opts) {
231
304
  fromCache,
232
305
  };
233
306
  }
234
- export function formatUpgradeNotice(status) {
307
+ /**
308
+ * `cache` (when passed) lets this distinguish a plain "notify" signal from the
309
+ * outcome of the last `--background` auto-install attempt for that target:
310
+ * - succeeded, but this process is running older code than what's on disk
311
+ * (e.g. a long-running `serve --mcp`) → "auto-upgraded, restart to use it"
312
+ * - failed → surface the error and point at the manual command
313
+ * - succeeded and already caught up (this process's own version matches) → silent
314
+ */
315
+ export function formatUpgradeNotice(status, cache) {
235
316
  const parts = [];
236
- if (status.cli.upgradeAvailable)
317
+ let needsManualRun = false;
318
+ if (cache?.cliAuto && !cache.cliAuto.ok) {
319
+ parts.push(`CLI auto-upgrade failed (${cache.cliAuto.error ?? "unknown error"})`);
320
+ needsManualRun = true;
321
+ }
322
+ else if (cache?.cliAuto?.ok && cache.cliAuto.version && cache.cliAuto.version !== status.cli.current) {
323
+ parts.push(`CLI auto-upgraded → ${cache.cliAuto.version} (restart any long-running agent-memory process to use it)`);
324
+ }
325
+ else if (status.cli.upgradeAvailable) {
237
326
  parts.push(`CLI ${status.cli.current} → ${status.cli.latest ?? "new"}`);
238
- if (status.plugin.upgradeAvailable)
327
+ needsManualRun = true;
328
+ }
329
+ if (cache?.pluginAuto && !cache.pluginAuto.ok) {
330
+ parts.push(`Pro auto-upgrade failed (${cache.pluginAuto.error ?? "unknown error"})`);
331
+ needsManualRun = true;
332
+ }
333
+ else if (cache?.pluginAuto?.ok && cache.pluginAuto.version && cache.pluginAuto.version !== status.plugin.current) {
334
+ parts.push(`Pro auto-upgraded → ${cache.pluginAuto.version}`);
335
+ }
336
+ else if (status.plugin.upgradeAvailable) {
239
337
  parts.push(`Pro ${status.plugin.current ?? "?"} → ${status.plugin.latest ?? "new"}`);
338
+ needsManualRun = true;
339
+ }
240
340
  if (!parts.length)
241
341
  return null;
242
- return `agent-memory: upgrade available (${parts.join(", ")}). Run: agent-memory upgrade`;
342
+ return `agent-memory: ${parts.join("; ")}${needsManualRun ? ". Run: agent-memory upgrade" : ""}`;
243
343
  }
@@ -267,7 +267,7 @@ An install or upgrade must:
267
267
 
268
268
  Failure before activation leaves the previous version active. Failure immediately after activation restores the previous receipt. Concurrent installers do not interleave. The core never invokes package-manager lifecycle scripts or elevates privileges.
269
269
 
270
- Uninstall removes executable versions, the active receipt, contributed skills, and managed hooks. It does not remove `MEMORY.md`, daily logs, topics, scratchpad items, source session logs, plugin-created review data, or billing state. A separate future purge command would require explicit scope and confirmation.
270
+ Uninstall removes executable versions, the active receipt, contributed skills, and managed hooks. It does not remove `MEMORY.md`, daily logs, topics, scratchpad items, source session logs, plugin-created review data, or billing state. The top-level `agent-memory uninstall` command composes this with hook/skill/MCP/completion removal in one step; its explicit `--data` flag additionally deletes the memory directory and the entire plugin install root (bundles, receipts, and the activation credential) once the user opts in and confirms.
271
271
 
272
272
  ## Plugin host API v1
273
273
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myagentmemory",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "agentmemory (agent-memory) is persistent memory for coding agents (Claude Code, OpenAI Codex, Cursor, Agent) with qmd-powered semantic search across daily logs, long-term memory, and scratchpad",
5
5
  "main": "./dist/core.js",
6
6
  "types": "./dist/core.d.ts",
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bash
2
- # Install (or uninstall) agent-memory skills for Claude Code, Codex, Cursor, and Agent CLI.
2
+ # Install (or uninstall) agent-memory skills for Claude Code, Codex, Cursor, Agent CLI, and Qoder.
3
3
  # Usage: bash scripts/install-skills.sh [--uninstall]
4
4
 
5
5
  set -euo pipefail
@@ -63,12 +63,14 @@ SKILL_DIRS=(
63
63
  "$HOME/.codex/skills/agent-memory"
64
64
  "$HOME/.cursor/skills/agent-memory"
65
65
  "$HOME/.agents/skills/agent-memory"
66
+ "$HOME/.qoder/skills/agent-memory"
66
67
  )
67
68
  SKILL_LABELS=(
68
69
  "Claude Code skill"
69
70
  "Codex skill"
70
71
  "Cursor skill"
71
72
  "Agent CLI skill"
73
+ "Qoder skill"
72
74
  )
73
75
 
74
76
  if $UNINSTALL; then
@@ -84,6 +86,7 @@ else
84
86
  install_skill "Codex skill" "$PROJECT_DIR/skills/codex" "$HOME/.codex/skills/agent-memory" "$HOME/.codex" '[ -f "$HOME/.codex/config.toml" ] || command_exists codex'
85
87
  install_skill "Cursor skill" "$PROJECT_DIR/skills/cursor" "$HOME/.cursor/skills/agent-memory" "$HOME/.cursor"
86
88
  install_skill "Agent CLI skill" "$PROJECT_DIR/skills/agent" "$HOME/.agents/skills/agent-memory" "$HOME/.agents"
89
+ install_skill "Qoder skill" "$PROJECT_DIR/skills/qoder" "$HOME/.qoder/skills/agent-memory" "$HOME/.qoder" '[ -f "$HOME/.qoder/settings.json" ] || [ -f "$HOME/.qoder/settings.local.json" ] || command_exists qoder'
87
90
  echo ""
88
91
  echo "Done."
89
92
  fi
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: agent-memory
3
- description: Persistent memory across coding sessions — long-term facts, daily logs, topic notes, scratchpad checklist, and semantic search.
3
+ description: Persistent memory across coding sessions — long-term facts, daily logs, topic notes, scratchpad checklist, and keyword/semantic search, plus recall of past chat sessions. Use whenever the user says "remember", "recall", or asks to look up/search memory.
4
4
  ---
5
5
 
6
6
  # Agent Memory
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: agent-memory
3
- description: Persistent memory across coding sessions — long-term facts, daily logs, topic notes, scratchpad checklist, and semantic search.
3
+ description: Persistent memory across coding sessions — long-term facts, daily logs, topic notes, scratchpad checklist, and keyword/semantic search, plus recall of past chat sessions. Use whenever the user says "remember", "recall", or asks to look up/search memory.
4
4
  allowed-tools: Bash(agent-memory *)
5
5
  ---
6
6
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: agent-memory
3
- description: Persistent memory across coding sessions — long-term facts, daily logs, topic notes, scratchpad checklist, and semantic search.
3
+ description: Persistent memory across coding sessions — long-term facts, daily logs, topic notes, scratchpad checklist, and keyword/semantic search, plus recall of past chat sessions. Use whenever the user says "remember", "recall", or asks to look up/search memory.
4
4
  ---
5
5
 
6
6
  # Agent Memory
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: agent-memory
3
- description: Persistent memory across coding sessions — long-term facts, daily logs, topic notes, scratchpad checklist, and semantic search.
3
+ description: Persistent memory across coding sessions — long-term facts, daily logs, topic notes, scratchpad checklist, and keyword/semantic search, plus recall of past chat sessions. Use whenever the user says "remember", "recall", or asks to look up/search memory.
4
4
  ---
5
5
 
6
6
  # Agent Memory
@@ -0,0 +1,164 @@
1
+ ---
2
+ name: agent-memory
3
+ description: Persistent memory across coding sessions — long-term facts, daily logs, topic notes, scratchpad checklist, and semantic search.
4
+ ---
5
+
6
+ # Agent Memory
7
+
8
+ You have a persistent memory system. Use it **proactively** — don't wait to be asked.
9
+
10
+ ## Current Memory Context
11
+
12
+ Run this to load memory context at session start:
13
+
14
+ ```bash
15
+ agent-memory context --no-search 2>/dev/null
16
+ ```
17
+
18
+ ## Session Lifecycle
19
+
20
+ ### On session start
21
+ 1. Run `agent-memory context` to load memory — especially check **open scratchpad items** (pick up where you left off)
22
+ 2. If the user's task relates to prior work, search for relevant memories:
23
+ ```bash
24
+ agent-memory search --query "<topic>" --mode keyword
25
+ ```
26
+
27
+ ### On session end (after significant work)
28
+ 1. Log what was accomplished in the daily log
29
+ 2. Mark completed scratchpad items as done; add new follow-ups
30
+ 3. Only write to long-term memory if you discovered a **durable fact** that doesn't already exist there
31
+
32
+ ## Where to Write — Decision Guide
33
+
34
+ **Default to daily. Long-term is rare.**
35
+
36
+ | What happened | Write to | Why |
37
+ |---|---|---|
38
+ | Made progress, fixed a bug, investigated something | `daily` | Session-specific — searchable later via qmd |
39
+ | Tracking a topic or event across days | `topic` | Builds a per-topic file with backlinks to daily logs |
40
+ | User said "remember this" about a preference or decision | `long_term` | Durable fact, needs to be in every session's context |
41
+ | Discovered a recurring pattern (3rd time seeing it) | `long_term` | Graduated from daily observations to established fact |
42
+ | Found a gotcha, workaround, or non-obvious behavior | `daily` first | If it keeps coming up, *then* promote to long-term |
43
+ | TODO or follow-up for any task (persistent todo) | `scratchpad` | Persistent, cross-session task tracking |
44
+
45
+ **MEMORY.md is a curated wiki, not a log.** It should stay under ~50 lines of high-signal content. If you're appending to it frequently, you're probably writing to the wrong target.
46
+
47
+ ## Memory Commands
48
+
49
+ ### Write to daily log (default — no --target needed)
50
+
51
+ ```bash
52
+ # Session notes, progress, bugs found, decisions made
53
+ agent-memory write --content "Fixed auth bug in login.ts — token refresh was missing"
54
+ agent-memory write --content "Investigated slow queries — N+1 in getUserOrders, added .include(:orders)"
55
+ ```
56
+
57
+ ### Write to long-term memory (rare, curated)
58
+
59
+ ```bash
60
+ # Only for durable facts that belong in every session's context
61
+ agent-memory write --target long_term --content "Project uses Drizzle ORM with PostgreSQL. Migrations in db/migrations/. #architecture"
62
+
63
+ # Overwrite MEMORY.md entirely (for curation — rewrite, don't append)
64
+ agent-memory write --target long_term --content "..." --mode overwrite
65
+ ```
66
+
67
+ When writing to long-term, prefer **overwrite mode** to curate the whole file rather than blindly appending. Read it first, then rewrite with the new fact incorporated.
68
+
69
+ ### Write to a topic/event file
70
+
71
+ ```bash
72
+ # Event- or theme-based log with backlinks to the daily entry
73
+ agent-memory write --target topic --topic "auth" --content "JWT refresh rolled out to edge #auth"
74
+ ```
75
+
76
+ ### Read
77
+
78
+ ```bash
79
+ agent-memory read --target daily # Today's log
80
+ agent-memory read --target daily --date 2026-02-15 # Specific day
81
+ agent-memory read --target list # All daily log files
82
+ agent-memory read --target topic --topic "auth"
83
+ agent-memory read --target topics # All topic files
84
+ agent-memory read --target long_term # MEMORY.md
85
+ agent-memory read --target scratchpad # Scratchpad checklist
86
+ ```
87
+
88
+ ### Scratchpad (persistent TODOs)
89
+
90
+ ```bash
91
+ agent-memory scratchpad add --text "Review PR #42"
92
+ agent-memory scratchpad list
93
+ agent-memory scratchpad done --text "PR #42" # Matches by substring
94
+ agent-memory scratchpad undo --text "PR #42"
95
+ agent-memory scratchpad clear_done # Remove completed items
96
+ ```
97
+
98
+ ### Search — recall past work
99
+
100
+ Search is how you find things written to daily logs. Use it before duplicating effort.
101
+
102
+ ```bash
103
+ agent-memory search --query "database choice" --mode keyword # Fast keyword
104
+ agent-memory search --query "how we handle auth" --mode semantic # Finds related concepts
105
+ agent-memory search --query "performance" --mode deep --limit 10 # Hybrid + reranking
106
+ ```
107
+
108
+ If qmd is not installed, fall back to reading files directly:
109
+ ```bash
110
+ agent-memory read --target long_term
111
+ agent-memory read --target daily
112
+ ```
113
+
114
+ ### Setup
115
+
116
+ ```bash
117
+ agent-memory init # Create dirs, detect qmd, setup collection
118
+ agent-memory sync # Re-index and embed all files (requires qmd)
119
+ agent-memory status # Show config, file counts, qmd status
120
+ ```
121
+
122
+ ## Writing Good Entries
123
+
124
+ ### Daily log entries
125
+ Describe what you did and what you learned. Include `#tags`.
126
+
127
+ **Recommended tags** (use what fits, invent your own as needed):
128
+ `#architecture` `#auth` `#bugfix` `#database` `#deploy` `#docs` `#ops` `#perf` `#refactor` `#security` `#testing` `#ui`
129
+
130
+ ```bash
131
+ # Good — specific, searchable, tagged
132
+ agent-memory write --content "Refactored auth middleware to use jose instead of jsonwebtoken. Reduced bundle by 40KB. #refactor #auth"
133
+
134
+ # Bad — too vague, no tags
135
+ agent-memory write --content "worked on auth stuff"
136
+ ```
137
+
138
+ ### Long-term entries
139
+ Only facts that should appear in **every** session's context. Use `#tags` and `[[links]]`.
140
+
141
+ ```bash
142
+ # Good — this belongs in every session
143
+ agent-memory write --target long_term --content "Deploy: 'bun run deploy:prod', requires AWS_PROFILE=prod. #ops [[deploy]]"
144
+
145
+ # Bad — this is a daily log entry, not a durable fact
146
+ agent-memory write --target long_term --content "Fixed the deploy script today"
147
+ ```
148
+
149
+ ## Memory Hygiene
150
+
151
+ - **Daily is the default** — when in doubt, write to daily (no `--target` needed)
152
+ - **MEMORY.md is a wiki** — curate it by reading + rewriting, not by appending endlessly
153
+ - **Keep MEMORY.md under ~50 lines** — it's injected into every session, so only high-signal facts belong there
154
+ - **Search before writing long-term** — the fact may already exist in a daily log, searchable via qmd
155
+ - **Promote deliberately** — if a pattern appears in daily logs 3+ times, that's when it earns a spot in MEMORY.md
156
+
157
+ ## Guidelines
158
+
159
+ - When someone says "remember this", decide: is it a durable fact (long-term) or a session note (daily)?
160
+ - Default to daily for almost everything (just `--content "..."` — no `--target` needed)
161
+ - Use `--target long_term` sparingly: architecture, preferences, key commands, hard-won lessons
162
+ - Prefer the scratchpad for any TODOs or follow-ups (persistent, cross-session tracking)
163
+ - Use `#tags` and `[[links]]` in content to improve search recall
164
+ - Use `agent-memory search` to recall past work before starting related tasks
package/src/cli-spec.ts CHANGED
@@ -26,6 +26,7 @@ export const COMMANDS = [
26
26
  "uninstall-skills",
27
27
  "install-hooks",
28
28
  "uninstall-hooks",
29
+ "uninstall",
29
30
  "completion",
30
31
  "pro",
31
32
  "recall",
@@ -61,6 +62,8 @@ export const COMMAND_DESCRIPTIONS: Record<(typeof COMMANDS)[number], string> = {
61
62
  "uninstall-skills": "remove core instructions from detected agents",
62
63
  "install-hooks": "install managed context and memory-write reminder hooks",
63
64
  "uninstall-hooks": "remove only hooks managed by agent-memory",
65
+ uninstall:
66
+ "remove hooks, skills, MCP registrations, completions, and the Pro plugin; add --data to also delete memory data",
64
67
  completion: "install or print Bash, Zsh, Fish, or PowerShell completion",
65
68
  pro: "install, inspect, or upgrade AgentMemory Pro",
66
69
  recall: "recall decisions and context from prior coding sessions with Pro",
@@ -68,7 +71,7 @@ export const COMMAND_DESCRIPTIONS: Record<(typeof COMMANDS)[number], string> = {
68
71
  dashboard: "open the private local Memory Dashboard",
69
72
  plugin: "discover, install, update, or remove optional official plugins",
70
73
  serve: "run as a Model Context Protocol (MCP) server over stdio",
71
- upgrade: "check for and install newer agent-memory CLI and Pro plugin releases",
74
+ upgrade: "check for, and auto-install by default, newer agent-memory CLI and Pro plugin releases",
72
75
  version: "print the installed agent-memory version",
73
76
  help: "show this command overview",
74
77
  };
@@ -113,6 +116,7 @@ export const COMMAND_OPTIONS: Record<string, readonly string[]> = {
113
116
  "uninstall-skills": [],
114
117
  "install-hooks": ["--yes", "--all", "--only", "--mode"],
115
118
  "uninstall-hooks": ["--only"],
119
+ uninstall: ["--data", "--yes"],
116
120
  completion: ["--stdout"],
117
121
  pro: [],
118
122
  recall: [
@@ -129,7 +133,7 @@ export const COMMAND_OPTIONS: Record<string, readonly string[]> = {
129
133
  learn: ["--preview"],
130
134
  dashboard: ["--no-browser"],
131
135
  serve: ["--mcp", "--register", "--only"],
132
- upgrade: ["--check", "--refresh", "--yes", "--quiet", "--cli", "--plugin"],
136
+ upgrade: ["--check", "--refresh", "--yes", "--quiet", "--cli", "--plugin", "--background"],
133
137
  version: [],
134
138
  help: [],
135
139
  };
@@ -294,6 +298,7 @@ export const OPTION_SPECS: Record<string, CliOptionSpec> = {
294
298
  "--agent": { description: "internal SessionStart host key", value: { label: "agent", kind: "value" } },
295
299
  "--token": { description: "internal session-worker lease token", value: { label: "token", kind: "value" } },
296
300
  "--uninstall": { description: "use install-skills compatibility uninstall mode" },
301
+ "--data": { description: "uninstall: also permanently delete the memory directory and plugin state" },
297
302
  "--mcp": { description: "serve as an MCP server over stdio (used by Claude Code)" },
298
303
  "--register": { description: "register the MCP server in detected supported agents and exit" },
299
304
  "--check": { description: "upgrade: report available updates without installing" },
@@ -301,6 +306,10 @@ export const OPTION_SPECS: Record<string, CliOptionSpec> = {
301
306
  "--quiet": { description: "upgrade: suppress non-error output (used by the passive session-start refresh)" },
302
307
  "--cli": { description: "upgrade: limit action to the CLI binary" },
303
308
  "--plugin": { description: "upgrade: limit action to the Pro plugin bundle" },
309
+ "--background": {
310
+ description:
311
+ "upgrade: non-interactive; installs only targets whose policy is 'auto' (see: agent-memory upgrade policy)",
312
+ },
304
313
  };
305
314
 
306
315
  export const SHELL_DESCRIPTIONS: Record<string, string> = {
@@ -339,6 +348,7 @@ const COMMAND_USAGE: Record<string, string> = {
339
348
  "install-hooks":
340
349
  "agent-memory install-hooks [--yes] [--all] [--only claude,codex,cursor] [--mode stable|per-turn] [--json]",
341
350
  "uninstall-hooks": "agent-memory uninstall-hooks [--only claude,codex,cursor] [--json]",
351
+ uninstall: "agent-memory uninstall [--data] [--yes] [--json]",
342
352
  completion: "agent-memory completion [bash|zsh|fish|powershell] [--stdout]",
343
353
  pro: "agent-memory pro <install|status|upgrade> [--channel stable] [--yes]",
344
354
  recall:
@@ -347,7 +357,8 @@ const COMMAND_USAGE: Record<string, string> = {
347
357
  dashboard: "agent-memory dashboard [--no-browser]",
348
358
  plugin:
349
359
  "agent-memory plugin <list|status|install|update|uninstall|manage> [--channel stable] [--yes] [--no-browser]",
350
- upgrade: "agent-memory upgrade [--check] [--yes] [--cli|--plugin] [--refresh] [--json]",
360
+ upgrade:
361
+ "agent-memory upgrade [--check] [--yes] [--cli|--plugin] [--refresh] [--json]\n agent-memory upgrade policy [off|notify|auto] [--cli|--plugin] [--json] (default: auto for both)",
351
362
  version: "agent-memory version",
352
363
  help: "agent-memory help [<command>]",
353
364
  };
@@ -386,6 +397,10 @@ const COMMAND_EXAMPLES: Record<string, string[]> = {
386
397
  status: ["agent-memory status", "agent-memory status --json"],
387
398
  init: ["agent-memory init", "agent-memory init --yes --skip-hooks"],
388
399
  setup: ["agent-memory setup", "agent-memory setup --json"],
400
+ uninstall: [
401
+ "agent-memory uninstall --yes # removes hooks, skills, MCP registrations, completions, Pro plugin",
402
+ "agent-memory uninstall --data --yes # also deletes MEMORY.md, daily logs, scratchpad, topics",
403
+ ],
389
404
  "install-hooks": [
390
405
  "agent-memory install-hooks",
391
406
  "agent-memory install-hooks --yes",
@@ -29,6 +29,14 @@ export interface CompletionInstallResult {
29
29
  profileUpdated: boolean;
30
30
  }
31
31
 
32
+ export interface CompletionUninstallResult {
33
+ shell: CompletionShell;
34
+ completionPath: string;
35
+ removed: boolean;
36
+ profilePath?: string;
37
+ profileUpdated: boolean;
38
+ }
39
+
32
40
  function words(values: readonly string[]): string {
33
41
  return values.join(" ");
34
42
  }
@@ -460,6 +468,27 @@ function ensureProfileBlock(filePath: string, lines: string[]): boolean {
460
468
  return true;
461
469
  }
462
470
 
471
+ /** Reverse of {@link ensureProfileBlock}: strips the marker block, if present, from the given file. */
472
+ function removeProfileBlock(filePath: string): boolean {
473
+ const start = "# >>> agent-memory completion >>>";
474
+ const end = "# <<< agent-memory completion <<<";
475
+ if (!fs.existsSync(filePath)) return false;
476
+ const current = fs.readFileSync(filePath, "utf8");
477
+ const startIndex = current.indexOf(start);
478
+ const endIndex = startIndex === -1 ? -1 : current.indexOf(end, startIndex);
479
+ if (startIndex === -1 || endIndex === -1) return false;
480
+ const updated = (current.slice(0, startIndex) + current.slice(endIndex + end.length)).replace(/\n{3,}/g, "\n\n");
481
+ if (updated === current) return false;
482
+ fs.writeFileSync(filePath, updated, { mode: 0o600 });
483
+ return true;
484
+ }
485
+
486
+ function removeCompletionFile(filePath: string): boolean {
487
+ if (!fs.existsSync(filePath)) return false;
488
+ fs.unlinkSync(filePath);
489
+ return true;
490
+ }
491
+
463
492
  export function installCompletion(
464
493
  shell: CompletionShell,
465
494
  options: { homeDir?: string; platform?: NodeJS.Platform } = {},
@@ -507,3 +536,47 @@ export function installCompletion(
507
536
  ]);
508
537
  return { shell, completionPath, profilePath, profileUpdated };
509
538
  }
539
+
540
+ function uninstallShellCompletion(
541
+ shell: CompletionShell,
542
+ homeDir: string,
543
+ platform: NodeJS.Platform,
544
+ ): CompletionUninstallResult {
545
+ const completionDir = path.join(homeDir, ".config", "agent-memory", "completions");
546
+
547
+ if (shell === "fish") {
548
+ const completionPath = path.join(homeDir, ".config", "fish", "completions", "agent-memory.fish");
549
+ return { shell, completionPath, removed: removeCompletionFile(completionPath), profileUpdated: false };
550
+ }
551
+
552
+ const extension = shell === "powershell" ? "ps1" : shell;
553
+ const completionPath = path.join(completionDir, `agent-memory.${extension}`);
554
+ const removed = removeCompletionFile(completionPath);
555
+
556
+ if (shell === "bash") {
557
+ const profilePath = path.join(homeDir, ".bashrc");
558
+ return { shell, completionPath, removed, profilePath, profileUpdated: removeProfileBlock(profilePath) };
559
+ }
560
+
561
+ if (shell === "zsh") {
562
+ const profilePath = path.join(homeDir, ".zshrc");
563
+ return { shell, completionPath, removed, profilePath, profileUpdated: removeProfileBlock(profilePath) };
564
+ }
565
+
566
+ const profilePath =
567
+ platform === "win32"
568
+ ? path.join(homeDir, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1")
569
+ : path.join(homeDir, ".config", "powershell", "Microsoft.PowerShell_profile.ps1");
570
+ return { shell, completionPath, removed, profilePath, profileUpdated: removeProfileBlock(profilePath) };
571
+ }
572
+
573
+ /** Reverse of {@link installCompletion} across every supported shell. */
574
+ export function uninstallCompletion(
575
+ options: { homeDir?: string; platform?: NodeJS.Platform } = {},
576
+ ): CompletionUninstallResult[] {
577
+ const homeDir = options.homeDir ?? os.homedir();
578
+ const platform = options.platform ?? process.platform;
579
+ return (["bash", "zsh", "fish", "powershell"] as const).map((shell) =>
580
+ uninstallShellCompletion(shell, homeDir, platform),
581
+ );
582
+ }
package/src/core.ts CHANGED
@@ -1063,6 +1063,17 @@ export function installSkills(): InstallSkillsReport {
1063
1063
  destDir: path.join(homeDir, ".cursor", "skills", "agent-memory"),
1064
1064
  homeMarker: path.join(homeDir, ".cursor"),
1065
1065
  },
1066
+ {
1067
+ label: "Qoder skill",
1068
+ srcDir: path.join(skillsDir, "qoder"),
1069
+ destDir: path.join(homeDir, ".qoder", "skills", "agent-memory"),
1070
+ homeMarker: path.join(homeDir, ".qoder"),
1071
+ detectFiles: [
1072
+ path.join(homeDir, ".qoder", "settings.json"),
1073
+ path.join(homeDir, ".qoder", "settings.local.json"),
1074
+ ],
1075
+ detectCommand: "qoder",
1076
+ },
1066
1077
  {
1067
1078
  label: "Agent CLI skill",
1068
1079
  srcDir: path.join(skillsDir, "agent"),