myagentmemory 0.4.12 → 0.4.14
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 +118 -49
- package/dist/cli-spec.d.ts +25 -0
- package/dist/cli-spec.js +211 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +435 -71
- package/dist/completions.d.ts +13 -0
- package/dist/completions.js +429 -0
- package/dist/core.d.ts +22 -1
- package/dist/core.js +299 -62
- package/dist/hooks.d.ts +42 -0
- package/dist/hooks.js +444 -0
- package/dist/plugin-bootstrap.d.ts +190 -0
- package/dist/plugin-bootstrap.js +628 -0
- package/dist/plugin-host.d.ts +136 -0
- package/dist/plugin-host.js +98 -0
- package/dist/plugin-runtime.d.ts +21 -0
- package/dist/plugin-runtime.js +208 -0
- package/dist/plugin-service.d.ts +45 -0
- package/dist/plugin-service.js +395 -0
- package/docs/official-plugin-bootstrap.md +335 -0
- package/package.json +62 -11
- package/scripts/install-skills.sh +4 -1
- package/scripts/postinstall.cjs +23 -4
- package/src/cli-spec.ts +236 -0
- package/src/cli.ts +455 -82
- package/src/completions.ts +501 -0
- package/src/core.ts +314 -62
- package/src/hooks.ts +485 -0
- package/src/plugin-bootstrap.ts +931 -0
- package/src/plugin-host.ts +255 -0
- package/src/plugin-runtime.ts +296 -0
- package/src/plugin-service.ts +451 -0
- package/dist/agent-memory +0 -0
package/dist/cli.js
CHANGED
|
@@ -12,14 +12,32 @@
|
|
|
12
12
|
* search — Search via qmd
|
|
13
13
|
* init — Create dirs, detect qmd, setup collection
|
|
14
14
|
* status — Show config, qmd status, file counts
|
|
15
|
+
* completion — Install or print shell completion
|
|
16
|
+
* install-hooks — Install managed session-start hooks
|
|
17
|
+
* uninstall-hooks — Remove managed session-start hooks
|
|
18
|
+
* plugin — Discover and bootstrap optional official plugins
|
|
15
19
|
*
|
|
16
20
|
* Global flags:
|
|
17
21
|
* --dir <path> Override memory directory
|
|
18
22
|
* --json Machine-readable JSON output
|
|
19
23
|
*/
|
|
24
|
+
import { spawn } from "node:child_process";
|
|
20
25
|
import * as fs from "node:fs";
|
|
21
|
-
import {
|
|
22
|
-
|
|
26
|
+
import { detectCompletionShell, generateCompletion, installCompletion } from "./completions.js";
|
|
27
|
+
import { _setBaseDir, buildMemoryContext, checkCollection, dailyPath, detectQmd, distilMemories, ensureDirs, ensureQmdAvailableForSync, ensureQmdAvailableForUpdate, getCollectionName, getDailyDir, getMemoryDir, getMemoryFile, getQmdEmbedMode, getQmdHealth, getQmdResultPath, getQmdResultText, getScratchpadFile, getTopicsDir, installSkills, memoryWrite, nowTimestamp, parseScratchpad, probeEmbeddings, readFileSafe, redactSecrets, runQmdEmbedDetached, runQmdSearch, runQmdSync, runQmdUpdateNow, scheduleQmdUpdate, searchRelevantMemories, serializeScratchpad, setupQmdCollection, slugifyTopic, todayStr, topicPath, uninstallSkills, } from "./core.js";
|
|
28
|
+
import { detectHookAgents, installHooks, uninstallHooks } from "./hooks.js";
|
|
29
|
+
import { createDefaultPluginBootstrap, PluginBootstrapFailure, } from "./plugin-bootstrap.js";
|
|
30
|
+
import { InstalledPluginRuntimeV1 } from "./plugin-runtime.js";
|
|
31
|
+
function readPackageVersion() {
|
|
32
|
+
try {
|
|
33
|
+
const packageJson = JSON.parse(fs.readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
|
|
34
|
+
return typeof packageJson.version === "string" ? packageJson.version : "dev";
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return "dev";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const VERSION = typeof __VERSION__ !== "undefined" ? __VERSION__ : readPackageVersion();
|
|
23
41
|
function parseArgs(argv) {
|
|
24
42
|
const flags = {};
|
|
25
43
|
const positional = [];
|
|
@@ -77,14 +95,125 @@ function exitError(message, json) {
|
|
|
77
95
|
}
|
|
78
96
|
process.exit(1);
|
|
79
97
|
}
|
|
98
|
+
function openExternalUrl(url) {
|
|
99
|
+
let parsed;
|
|
100
|
+
try {
|
|
101
|
+
parsed = new URL(url);
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
if (parsed.protocol !== "https:")
|
|
107
|
+
return false;
|
|
108
|
+
try {
|
|
109
|
+
const child = process.platform === "darwin"
|
|
110
|
+
? spawn("open", [parsed.toString()], { detached: true, stdio: "ignore" })
|
|
111
|
+
: process.platform === "win32"
|
|
112
|
+
? spawn("explorer.exe", [parsed.toString()], { detached: true, stdio: "ignore" })
|
|
113
|
+
: spawn("xdg-open", [parsed.toString()], { detached: true, stdio: "ignore" });
|
|
114
|
+
child.unref();
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function printProOverview(installed) {
|
|
122
|
+
console.log("");
|
|
123
|
+
console.log("AgentMemory Pro includes:");
|
|
124
|
+
console.log(" Session Intelligence Recall decisions and context across Pi, Codex, and Claude Code sessions.");
|
|
125
|
+
console.log(" Guided Learning Turn repeated corrections into reviewable, reversible memory.");
|
|
126
|
+
console.log(" Local Web Console Inspect memories, activity, health, and settings in your browser.");
|
|
127
|
+
console.log("");
|
|
128
|
+
console.log("Your session content stays on this device.");
|
|
129
|
+
console.log("");
|
|
130
|
+
if (installed) {
|
|
131
|
+
console.log("Try it:");
|
|
132
|
+
console.log(' agent-memory recall "what did we decide about authentication?"');
|
|
133
|
+
console.log(" agent-memory learn");
|
|
134
|
+
console.log(" agent-memory web");
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
console.log("Start your Pro beta:");
|
|
138
|
+
console.log(" agent-memory plugin install");
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function printPluginResult(result, json, allowBrowser) {
|
|
142
|
+
if (json) {
|
|
143
|
+
output(result, true);
|
|
144
|
+
}
|
|
145
|
+
else if (result.command === "plugin.list" && result.plugins) {
|
|
146
|
+
for (const plugin of result.plugins) {
|
|
147
|
+
const state = plugin.available ? "available" : plugin.installed ? plugin.entitlement : "not installed";
|
|
148
|
+
console.log(`${plugin.name}: ${state}`);
|
|
149
|
+
}
|
|
150
|
+
printProOverview(Boolean(result.bundle));
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
const version = result.bundle?.version ? ` ${result.bundle.version}` : "";
|
|
154
|
+
let showOverview = false;
|
|
155
|
+
switch (result.result) {
|
|
156
|
+
case "installed":
|
|
157
|
+
console.log(`AgentMemory Pro${version} installed.`);
|
|
158
|
+
showOverview = true;
|
|
159
|
+
break;
|
|
160
|
+
case "upgraded":
|
|
161
|
+
console.log(`AgentMemory Pro upgraded to${version}.`);
|
|
162
|
+
showOverview = true;
|
|
163
|
+
break;
|
|
164
|
+
case "current":
|
|
165
|
+
console.log(result.bundle
|
|
166
|
+
? `AgentMemory Pro${version} is installed and ready.`
|
|
167
|
+
: "AgentMemory Pro is not installed.");
|
|
168
|
+
showOverview = Boolean(result.bundle);
|
|
169
|
+
break;
|
|
170
|
+
case "update_available":
|
|
171
|
+
console.log(`AgentMemory Pro${version} has an update available.`);
|
|
172
|
+
break;
|
|
173
|
+
case "uninstalled":
|
|
174
|
+
console.log("AgentMemory Pro executable components were removed. Memory and billing state were preserved.");
|
|
175
|
+
break;
|
|
176
|
+
case "not_installed":
|
|
177
|
+
console.log("AgentMemory Pro is not installed.");
|
|
178
|
+
console.log("Run: agent-memory plugin install");
|
|
179
|
+
break;
|
|
180
|
+
case "auth_required":
|
|
181
|
+
console.log("Run this command in an interactive terminal to enter an email and activate temporary access.");
|
|
182
|
+
break;
|
|
183
|
+
case "renewal_required":
|
|
184
|
+
console.log("Renew AgentMemory Pro to continue using paid capabilities.");
|
|
185
|
+
break;
|
|
186
|
+
default:
|
|
187
|
+
console.log(result.error?.message ?? "AgentMemory Pro is currently unavailable.");
|
|
188
|
+
}
|
|
189
|
+
if (showOverview)
|
|
190
|
+
printProOverview(true);
|
|
191
|
+
}
|
|
192
|
+
if (result.nextAction) {
|
|
193
|
+
if (allowBrowser && openExternalUrl(result.nextAction.url)) {
|
|
194
|
+
if (!json)
|
|
195
|
+
console.log("Opened the AgentMemory account website.");
|
|
196
|
+
}
|
|
197
|
+
else if (!json) {
|
|
198
|
+
console.log(`Open: ${result.nextAction.url}`);
|
|
199
|
+
}
|
|
200
|
+
if (!json && result.nextAction.userCode)
|
|
201
|
+
console.log(`Code: ${result.nextAction.userCode}`);
|
|
202
|
+
}
|
|
203
|
+
if (!result.ok)
|
|
204
|
+
process.exitCode = 1;
|
|
205
|
+
}
|
|
80
206
|
// ---------------------------------------------------------------------------
|
|
81
207
|
// Commands
|
|
82
208
|
// ---------------------------------------------------------------------------
|
|
83
209
|
async function cmdContext(flags) {
|
|
84
210
|
const json = hasFlag(flags, "json");
|
|
85
211
|
const noSearch = hasFlag(flags, "no-search");
|
|
212
|
+
const query = getFlag(flags, "query") ?? "";
|
|
86
213
|
ensureDirs();
|
|
87
|
-
|
|
214
|
+
if (!noSearch && query)
|
|
215
|
+
await ensureQmdAvailableForSync();
|
|
216
|
+
const searchResults = noSearch ? "" : await searchRelevantMemories(query);
|
|
88
217
|
const context = buildMemoryContext(searchResults);
|
|
89
218
|
if (json) {
|
|
90
219
|
output({ context, directory: getMemoryDir() }, true);
|
|
@@ -102,68 +231,28 @@ async function cmdWrite(flags) {
|
|
|
102
231
|
const mode = getFlag(flags, "mode") ?? "append";
|
|
103
232
|
const topic = getFlag(flags, "topic");
|
|
104
233
|
const date = getFlag(flags, "date");
|
|
234
|
+
const sourceUri = getFlag(flags, "source-uri");
|
|
105
235
|
if (!["long_term", "daily", "topic"].includes(target)) {
|
|
106
236
|
exitError("--target must be 'long_term', 'daily', or 'topic' (default: daily)", json);
|
|
107
237
|
}
|
|
238
|
+
if (!["append", "overwrite"].includes(mode)) {
|
|
239
|
+
exitError("--mode must be 'append' or 'overwrite'", json);
|
|
240
|
+
}
|
|
108
241
|
if (!content) {
|
|
109
242
|
exitError("--content is required", json);
|
|
110
243
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
? { ok: true, path: filePath, target, mode: "append", timestamp: ts }
|
|
124
|
-
: `Appended to daily log: ${filePath}`, json);
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
if (target === "topic") {
|
|
128
|
-
if (!topic) {
|
|
129
|
-
exitError("--topic is required when --target is 'topic'", json);
|
|
130
|
-
}
|
|
131
|
-
const slug = slugifyTopic(topic);
|
|
132
|
-
if (!slug) {
|
|
133
|
-
exitError("--topic must include at least one letter or number", json);
|
|
134
|
-
}
|
|
135
|
-
const filePath = topicPath(slug);
|
|
136
|
-
const existing = readFileSafe(filePath) ?? "";
|
|
137
|
-
const linkDate = date?.trim() || todayStr();
|
|
138
|
-
const header = `# Topic: ${topic}\n\n<!-- created: ${ts} [${sid}] -->\n`;
|
|
139
|
-
const separator = existing.trim() ? "\n\n" : "";
|
|
140
|
-
const base = existing.trim() ? existing : header.trimEnd();
|
|
141
|
-
const stamped = `<!-- ${ts} [${sid}] -->\n${content.trim()}\nDaily: [[${linkDate}]]`;
|
|
142
|
-
fs.writeFileSync(filePath, `${base}${separator}${stamped}`, "utf-8");
|
|
143
|
-
await ensureQmdAvailableForUpdate();
|
|
144
|
-
scheduleQmdUpdate();
|
|
145
|
-
output(json
|
|
146
|
-
? { ok: true, path: filePath, target, mode: "append", timestamp: ts, topic, slug, date: linkDate }
|
|
147
|
-
: `Appended to topic: ${filePath}`, json);
|
|
148
|
-
return;
|
|
149
|
-
}
|
|
150
|
-
// long_term
|
|
151
|
-
const memFile = getMemoryFile();
|
|
152
|
-
const existing = readFileSafe(memFile) ?? "";
|
|
153
|
-
if (mode === "overwrite") {
|
|
154
|
-
const stamped = `<!-- last updated: ${ts} [${sid}] -->\n${content}`;
|
|
155
|
-
fs.writeFileSync(memFile, stamped, "utf-8");
|
|
156
|
-
}
|
|
157
|
-
else {
|
|
158
|
-
const separator = existing.trim() ? "\n\n" : "";
|
|
159
|
-
const stamped = `<!-- ${ts} [${sid}] -->\n${content}`;
|
|
160
|
-
fs.writeFileSync(memFile, existing + separator + stamped, "utf-8");
|
|
161
|
-
}
|
|
162
|
-
await ensureQmdAvailableForUpdate();
|
|
163
|
-
scheduleQmdUpdate();
|
|
164
|
-
output(json
|
|
165
|
-
? { ok: true, path: memFile, target, mode, timestamp: ts }
|
|
166
|
-
: `${mode === "overwrite" ? "Overwrote" : "Appended to"} MEMORY.md`, json);
|
|
244
|
+
const result = await memoryWrite({
|
|
245
|
+
target: target,
|
|
246
|
+
content,
|
|
247
|
+
mode: mode,
|
|
248
|
+
sessionId: "cli",
|
|
249
|
+
topic,
|
|
250
|
+
date,
|
|
251
|
+
sourceUri,
|
|
252
|
+
});
|
|
253
|
+
if (result.isError)
|
|
254
|
+
exitError(result.text.replace(/^Error:\s*/, ""), json);
|
|
255
|
+
output(json ? { ok: true, ...result.details } : result.text.split("\n\n", 1)[0], json);
|
|
167
256
|
}
|
|
168
257
|
async function cmdRead(flags) {
|
|
169
258
|
const json = hasFlag(flags, "json");
|
|
@@ -270,7 +359,11 @@ async function cmdScratchpad(flags, positional) {
|
|
|
270
359
|
ensureDirs();
|
|
271
360
|
const spFile = getScratchpadFile();
|
|
272
361
|
const existing = readFileSafe(spFile) ?? "";
|
|
273
|
-
let items = parseScratchpad(existing)
|
|
362
|
+
let items = parseScratchpad(existing).map((item) => ({
|
|
363
|
+
...item,
|
|
364
|
+
text: redactSecrets(item.text).content,
|
|
365
|
+
meta: redactSecrets(item.meta).content,
|
|
366
|
+
}));
|
|
274
367
|
if (action === "list") {
|
|
275
368
|
if (items.length === 0) {
|
|
276
369
|
output(json ? { items: [], count: 0, open: 0 } : "Scratchpad is empty.", json);
|
|
@@ -292,11 +385,12 @@ async function cmdScratchpad(flags, positional) {
|
|
|
292
385
|
if (!text)
|
|
293
386
|
exitError("--text is required for add", json);
|
|
294
387
|
const ts = nowTimestamp();
|
|
295
|
-
|
|
388
|
+
const safeText = redactSecrets(text).content;
|
|
389
|
+
items.push({ done: false, text: safeText, meta: `<!-- ${ts} [cli] -->` });
|
|
296
390
|
fs.writeFileSync(spFile, serializeScratchpad(items), "utf-8");
|
|
297
391
|
await ensureQmdAvailableForUpdate();
|
|
298
392
|
scheduleQmdUpdate();
|
|
299
|
-
output(json ? { ok: true, action, text } : `Added: - [ ] ${
|
|
393
|
+
output(json ? { ok: true, action, text: safeText } : `Added: - [ ] ${safeText}`, json);
|
|
300
394
|
return;
|
|
301
395
|
}
|
|
302
396
|
if (action === "done" || action === "undo") {
|
|
@@ -446,6 +540,84 @@ function cmdInstallSkills(flags) {
|
|
|
446
540
|
}
|
|
447
541
|
}
|
|
448
542
|
}
|
|
543
|
+
async function promptYesNo(question, defaultYes) {
|
|
544
|
+
const readline = await import("node:readline/promises");
|
|
545
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stderr });
|
|
546
|
+
try {
|
|
547
|
+
const answer = (await rl.question(`${question} ${defaultYes ? "[Y/n]" : "[y/N]"} `)).trim().toLowerCase();
|
|
548
|
+
if (!answer)
|
|
549
|
+
return defaultYes;
|
|
550
|
+
return answer === "y" || answer === "yes";
|
|
551
|
+
}
|
|
552
|
+
finally {
|
|
553
|
+
rl.close();
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
async function cmdInstallHooks(flags) {
|
|
557
|
+
const json = hasFlag(flags, "json");
|
|
558
|
+
const requested = getFlag(flags, "only");
|
|
559
|
+
const requestedKeys = requested ? new Set(requested.split(",").map((value) => value.trim())) : null;
|
|
560
|
+
const { homeDir, targets } = detectHookAgents();
|
|
561
|
+
if (!homeDir)
|
|
562
|
+
exitError("Home directory not found.", json);
|
|
563
|
+
const eligible = targets.filter((target) => target.supported && target.detected && (!requestedKeys || requestedKeys.has(target.key)));
|
|
564
|
+
const selected = new Set();
|
|
565
|
+
const applyAll = hasFlag(flags, "yes") || hasFlag(flags, "all") || !process.stdin.isTTY;
|
|
566
|
+
for (const target of eligible) {
|
|
567
|
+
if (applyAll || (await promptYesNo(`Install SessionStart hook for ${target.label}?`, true)))
|
|
568
|
+
selected.add(target.key);
|
|
569
|
+
}
|
|
570
|
+
const report = installHooks(selected);
|
|
571
|
+
if (!report.ok)
|
|
572
|
+
exitError(report.error ?? "install failed", json);
|
|
573
|
+
if (json)
|
|
574
|
+
return output(report, true);
|
|
575
|
+
if (!report.results.length)
|
|
576
|
+
return output("No eligible agents. Nothing to install.", false);
|
|
577
|
+
for (const result of report.results) {
|
|
578
|
+
console.log(result.installed
|
|
579
|
+
? `Installed ${result.label} hook: ${result.path}`
|
|
580
|
+
: `Skipped ${result.label} (${result.reason ?? "unknown"})`);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
function cmdUninstallHooks(flags) {
|
|
584
|
+
const json = hasFlag(flags, "json");
|
|
585
|
+
const only = getFlag(flags, "only");
|
|
586
|
+
const agents = only ? new Set(only.split(",").map((value) => value.trim())) : undefined;
|
|
587
|
+
const report = uninstallHooks(agents);
|
|
588
|
+
if (!report.ok)
|
|
589
|
+
exitError(report.error ?? "uninstall failed", json);
|
|
590
|
+
if (json) {
|
|
591
|
+
output(report, true);
|
|
592
|
+
return;
|
|
593
|
+
}
|
|
594
|
+
for (const result of report.results) {
|
|
595
|
+
console.log(result.installed
|
|
596
|
+
? `Uninstalled ${result.label}: ${result.path}`
|
|
597
|
+
: `Skipped ${result.label} (${result.reason ?? "unknown"})`);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
function cmdCompletion(flags, positional) {
|
|
601
|
+
const requestedShell = positional[0];
|
|
602
|
+
const shells = ["bash", "zsh", "fish", "powershell"];
|
|
603
|
+
if (requestedShell && !shells.includes(requestedShell))
|
|
604
|
+
exitError(`Unsupported shell '${requestedShell}'. Choose bash, zsh, fish, or powershell.`, hasFlag(flags, "json"));
|
|
605
|
+
const shell = requestedShell ?? detectCompletionShell();
|
|
606
|
+
if (!shell)
|
|
607
|
+
exitError("Could not detect your shell. Specify bash, zsh, fish, or powershell.", hasFlag(flags, "json"));
|
|
608
|
+
if (hasFlag(flags, "stdout")) {
|
|
609
|
+
process.stdout.write(generateCompletion(shell));
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
const result = installCompletion(shell);
|
|
613
|
+
if (hasFlag(flags, "json")) {
|
|
614
|
+
output(result, true);
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
console.log(`Installed ${shell} completion: ${result.completionPath}`);
|
|
618
|
+
if (result.profilePath)
|
|
619
|
+
console.log(`${result.profileUpdated ? "Configured" : "Already configured"}: ${result.profilePath}`);
|
|
620
|
+
}
|
|
449
621
|
async function cmdSync(flags) {
|
|
450
622
|
const json = hasFlag(flags, "json");
|
|
451
623
|
ensureDirs();
|
|
@@ -532,6 +704,19 @@ async function cmdInit(flags) {
|
|
|
532
704
|
console.log(` qmd not found — search features unavailable.`);
|
|
533
705
|
console.log(` Install: bun install -g https://github.com/tobi/qmd`);
|
|
534
706
|
}
|
|
707
|
+
if (process.stdout.isTTY) {
|
|
708
|
+
try {
|
|
709
|
+
const plugin = await createDefaultPluginBootstrap(VERSION).list();
|
|
710
|
+
if (plugin.result === "not_installed") {
|
|
711
|
+
console.log("");
|
|
712
|
+
console.log("Optional: AgentMemory Pro adds session recall and a local Web Console.");
|
|
713
|
+
console.log("Run: agent-memory plugin install");
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
catch {
|
|
717
|
+
// Commercial discovery must never make core initialization fail.
|
|
718
|
+
}
|
|
719
|
+
}
|
|
535
720
|
}
|
|
536
721
|
}
|
|
537
722
|
async function cmdStatus(flags) {
|
|
@@ -561,14 +746,37 @@ async function cmdStatus(flags) {
|
|
|
561
746
|
const qmdFound = await detectQmd();
|
|
562
747
|
let hasCollection = false;
|
|
563
748
|
let health = null;
|
|
749
|
+
let embeddings = "n/a";
|
|
564
750
|
if (qmdFound) {
|
|
565
751
|
hasCollection = await checkCollection();
|
|
566
752
|
if (hasCollection) {
|
|
567
753
|
await ensureQmdAvailableForSync();
|
|
568
754
|
health = await getQmdHealth();
|
|
755
|
+
// A live semantic probe confirms embeddings are actually usable, but
|
|
756
|
+
// it costs a real qmd query (and a possible model load), so it's
|
|
757
|
+
// opt-in — the cheap pending-embed count below covers the common case.
|
|
758
|
+
if (hasFlag(flags, "probe")) {
|
|
759
|
+
embeddings = await probeEmbeddings();
|
|
760
|
+
}
|
|
569
761
|
}
|
|
570
762
|
}
|
|
571
763
|
const embedMode = getQmdEmbedMode();
|
|
764
|
+
let officialPlugin = {
|
|
765
|
+
installed: false,
|
|
766
|
+
result: "unavailable",
|
|
767
|
+
entitlement: "missing",
|
|
768
|
+
};
|
|
769
|
+
try {
|
|
770
|
+
const plugin = await createDefaultPluginBootstrap(VERSION).status();
|
|
771
|
+
officialPlugin = {
|
|
772
|
+
installed: Boolean(plugin.bundle),
|
|
773
|
+
result: plugin.result,
|
|
774
|
+
entitlement: plugin.entitlement.state,
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
catch {
|
|
778
|
+
// Commercial status must never make core status fail.
|
|
779
|
+
}
|
|
572
780
|
if (json) {
|
|
573
781
|
output({
|
|
574
782
|
directory: dir,
|
|
@@ -588,8 +796,10 @@ async function cmdStatus(flags) {
|
|
|
588
796
|
available: qmdFound,
|
|
589
797
|
collection: hasCollection ? getCollectionName() : null,
|
|
590
798
|
health,
|
|
799
|
+
embeddings,
|
|
591
800
|
},
|
|
592
801
|
embedMode,
|
|
802
|
+
officialPlugin,
|
|
593
803
|
}, true);
|
|
594
804
|
}
|
|
595
805
|
else {
|
|
@@ -617,6 +827,14 @@ async function cmdStatus(flags) {
|
|
|
617
827
|
console.log(`qmd: available`);
|
|
618
828
|
console.log(`Collection '${getCollectionName()}': ${hasCollection ? "configured" : "not configured — run: agent-memory init"}`);
|
|
619
829
|
console.log(`Embed mode: ${embedMode}`);
|
|
830
|
+
if (hasCollection && embeddings !== "n/a") {
|
|
831
|
+
const embLabel = embeddings === "ready"
|
|
832
|
+
? "ready"
|
|
833
|
+
: embeddings === "missing"
|
|
834
|
+
? "missing — run: agent-memory sync"
|
|
835
|
+
: "unknown (could not verify within probe timeout)";
|
|
836
|
+
console.log(`Embeddings (semantic/deep search): ${embLabel}`);
|
|
837
|
+
}
|
|
620
838
|
if (health) {
|
|
621
839
|
if (health.totalFiles !== null)
|
|
622
840
|
console.log(`Files indexed: ${health.totalFiles}`);
|
|
@@ -633,6 +851,11 @@ async function cmdStatus(flags) {
|
|
|
633
851
|
else {
|
|
634
852
|
console.log("qmd: not installed");
|
|
635
853
|
}
|
|
854
|
+
if (!officialPlugin.installed) {
|
|
855
|
+
console.log("");
|
|
856
|
+
console.log("Optional official plugins: not installed");
|
|
857
|
+
console.log(" run: agent-memory plugin install");
|
|
858
|
+
}
|
|
636
859
|
}
|
|
637
860
|
}
|
|
638
861
|
async function cmdDistil(flags) {
|
|
@@ -658,6 +881,100 @@ async function cmdDistil(flags) {
|
|
|
658
881
|
}
|
|
659
882
|
}
|
|
660
883
|
}
|
|
884
|
+
function printPluginUsage() {
|
|
885
|
+
console.log(`agent-memory plugin — optional official plugins
|
|
886
|
+
|
|
887
|
+
Usage:
|
|
888
|
+
agent-memory plugin [list]
|
|
889
|
+
agent-memory plugin status
|
|
890
|
+
agent-memory plugin install [--channel stable] [--no-browser]
|
|
891
|
+
agent-memory plugin update [--channel stable]
|
|
892
|
+
agent-memory plugin uninstall --yes
|
|
893
|
+
agent-memory plugin manage [--no-browser]
|
|
894
|
+
|
|
895
|
+
The public core remains fully usable without AgentMemory Pro. Interactive install
|
|
896
|
+
opens a loopback website for temporary email activation and unlimited local use.
|
|
897
|
+
Authentication and payment will be added later.`);
|
|
898
|
+
}
|
|
899
|
+
function pluginCommandFailure(command, error) {
|
|
900
|
+
return {
|
|
901
|
+
schemaVersion: 1,
|
|
902
|
+
command: `plugin.${command}`,
|
|
903
|
+
ok: false,
|
|
904
|
+
result: "unavailable",
|
|
905
|
+
bundle: null,
|
|
906
|
+
entitlement: {
|
|
907
|
+
plan: null,
|
|
908
|
+
state: "missing",
|
|
909
|
+
features: [],
|
|
910
|
+
capabilities: {},
|
|
911
|
+
},
|
|
912
|
+
nextAction: null,
|
|
913
|
+
error: {
|
|
914
|
+
code: error instanceof PluginBootstrapFailure ? error.code : "plugin_command_failed",
|
|
915
|
+
message: error instanceof Error ? error.message : String(error),
|
|
916
|
+
...(error instanceof PluginBootstrapFailure && error.retryable ? { retryable: true } : {}),
|
|
917
|
+
},
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
async function cmdPlugin(flags, positional) {
|
|
921
|
+
const json = hasFlag(flags, "json");
|
|
922
|
+
const subcommand = positional[0] ?? "list";
|
|
923
|
+
if (subcommand === "help" || hasFlag(flags, "help")) {
|
|
924
|
+
printPluginUsage();
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const channel = getFlag(flags, "channel") ?? "stable";
|
|
928
|
+
if (channel !== "stable") {
|
|
929
|
+
printPluginResult(pluginCommandFailure(subcommand, new PluginBootstrapFailure("channel_invalid", "--channel supports only 'stable'")), json, false);
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
const allowBrowser = !json && !hasFlag(flags, "no-browser") && Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
933
|
+
const manager = createDefaultPluginBootstrap(VERSION);
|
|
934
|
+
let result;
|
|
935
|
+
try {
|
|
936
|
+
switch (subcommand) {
|
|
937
|
+
case "list":
|
|
938
|
+
result = await manager.list();
|
|
939
|
+
break;
|
|
940
|
+
case "status":
|
|
941
|
+
result = await manager.status(channel);
|
|
942
|
+
break;
|
|
943
|
+
case "install":
|
|
944
|
+
result = await manager.install({ channel, allowAuthentication: allowBrowser });
|
|
945
|
+
break;
|
|
946
|
+
case "update":
|
|
947
|
+
result = await manager.update({ channel, allowAuthentication: false });
|
|
948
|
+
break;
|
|
949
|
+
case "uninstall":
|
|
950
|
+
if (!hasFlag(flags, "yes")) {
|
|
951
|
+
const status = await manager.status(channel);
|
|
952
|
+
result = {
|
|
953
|
+
...status,
|
|
954
|
+
command: "plugin.uninstall",
|
|
955
|
+
ok: false,
|
|
956
|
+
result: "unavailable",
|
|
957
|
+
error: {
|
|
958
|
+
code: "confirmation_required",
|
|
959
|
+
message: "Re-run with --yes to remove AgentMemory Pro executable components",
|
|
960
|
+
},
|
|
961
|
+
};
|
|
962
|
+
break;
|
|
963
|
+
}
|
|
964
|
+
result = await manager.uninstall();
|
|
965
|
+
break;
|
|
966
|
+
case "manage":
|
|
967
|
+
result = await manager.manage();
|
|
968
|
+
break;
|
|
969
|
+
default:
|
|
970
|
+
result = pluginCommandFailure(subcommand, new PluginBootstrapFailure("unknown_plugin_command", `Unknown plugin command: ${subcommand}. Available bootstrap commands: list, status, install, update, uninstall, manage.`));
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
catch (error) {
|
|
974
|
+
result = pluginCommandFailure(subcommand, error);
|
|
975
|
+
}
|
|
976
|
+
printPluginResult(result, json, allowBrowser && (subcommand === "install" || subcommand === "manage"));
|
|
977
|
+
}
|
|
661
978
|
// ---------------------------------------------------------------------------
|
|
662
979
|
// Usage
|
|
663
980
|
// ---------------------------------------------------------------------------
|
|
@@ -671,15 +988,19 @@ Commands:
|
|
|
671
988
|
version Show binary version
|
|
672
989
|
install-skills Install (or --uninstall) bundled skills
|
|
673
990
|
uninstall-skills Uninstall bundled skills
|
|
674
|
-
context Build
|
|
675
|
-
write Write to memory files (default: daily)
|
|
991
|
+
context Build context; optionally retrieve memories with --query
|
|
992
|
+
write Write to memory files (default: daily; optional --source-uri)
|
|
676
993
|
read Read memory files
|
|
677
994
|
scratchpad Manage checklist items
|
|
678
995
|
search Search across memory files (requires qmd)
|
|
679
996
|
distil Generate compact MEMORY.md index from daily logs + topics
|
|
680
997
|
sync Re-index and embed all files (requires qmd)
|
|
681
998
|
init Initialize memory directory and qmd collection
|
|
682
|
-
status Show configuration and status
|
|
999
|
+
status Show configuration and status (--probe for a live embeddings check)
|
|
1000
|
+
completion Install or print shell completion
|
|
1001
|
+
install-hooks Install managed SessionStart hooks
|
|
1002
|
+
uninstall-hooks Remove only managed SessionStart hooks
|
|
1003
|
+
plugin Discover, install, update, or remove optional official plugins
|
|
683
1004
|
|
|
684
1005
|
Global flags:
|
|
685
1006
|
--dir <path> Override memory directory
|
|
@@ -688,7 +1009,7 @@ Global flags:
|
|
|
688
1009
|
Examples:
|
|
689
1010
|
agent-memory init
|
|
690
1011
|
agent-memory write --content "Fixed auth bug in login flow"
|
|
691
|
-
agent-memory write --target long_term --content "User prefers dark mode"
|
|
1012
|
+
agent-memory write --target long_term --content "User prefers dark mode" --source-uri "session://agent/turn/12"
|
|
692
1013
|
agent-memory write --target topic --topic "auth" --content "Rolled JWT refresh to edge"
|
|
693
1014
|
agent-memory read --target long_term
|
|
694
1015
|
agent-memory read --target daily --date 2026-02-15
|
|
@@ -700,9 +1021,13 @@ Examples:
|
|
|
700
1021
|
agent-memory scratchpad done --text "PR #42"
|
|
701
1022
|
agent-memory search --query "database choice" --mode keyword
|
|
702
1023
|
agent-memory distil --dry-run
|
|
703
|
-
agent-memory context --
|
|
1024
|
+
agent-memory context --query "database choice"
|
|
704
1025
|
agent-memory sync
|
|
705
|
-
agent-memory status --json
|
|
1026
|
+
agent-memory status --json
|
|
1027
|
+
agent-memory completion zsh
|
|
1028
|
+
agent-memory install-hooks --yes
|
|
1029
|
+
agent-memory plugin status
|
|
1030
|
+
agent-memory plugin install`);
|
|
706
1031
|
}
|
|
707
1032
|
// ---------------------------------------------------------------------------
|
|
708
1033
|
// Main
|
|
@@ -719,7 +1044,7 @@ async function main() {
|
|
|
719
1044
|
output(json ? { version: VERSION } : VERSION, json);
|
|
720
1045
|
return;
|
|
721
1046
|
}
|
|
722
|
-
if (!command || command === "help" || hasFlag(flags, "help")) {
|
|
1047
|
+
if (!command || command === "help" || (hasFlag(flags, "help") && command !== "plugin")) {
|
|
723
1048
|
printUsage();
|
|
724
1049
|
return;
|
|
725
1050
|
}
|
|
@@ -758,8 +1083,47 @@ async function main() {
|
|
|
758
1083
|
case "status":
|
|
759
1084
|
await cmdStatus(flags);
|
|
760
1085
|
break;
|
|
761
|
-
|
|
762
|
-
|
|
1086
|
+
case "completion":
|
|
1087
|
+
cmdCompletion(flags, positional);
|
|
1088
|
+
break;
|
|
1089
|
+
case "install-hooks":
|
|
1090
|
+
await cmdInstallHooks(flags);
|
|
1091
|
+
break;
|
|
1092
|
+
case "uninstall-hooks":
|
|
1093
|
+
cmdUninstallHooks(flags);
|
|
1094
|
+
break;
|
|
1095
|
+
case "hook": {
|
|
1096
|
+
if (positional[0] !== "session-start")
|
|
1097
|
+
exitError("hook requires 'session-start'", json);
|
|
1098
|
+
const agent = getFlag(flags, "agent");
|
|
1099
|
+
if (!agent)
|
|
1100
|
+
exitError("hook session-start requires --agent", json);
|
|
1101
|
+
await cmdContext({ "no-search": true });
|
|
1102
|
+
break;
|
|
1103
|
+
}
|
|
1104
|
+
case "plugin":
|
|
1105
|
+
await cmdPlugin(flags, positional);
|
|
1106
|
+
break;
|
|
1107
|
+
default: {
|
|
1108
|
+
const controller = new AbortController();
|
|
1109
|
+
const abort = () => controller.abort();
|
|
1110
|
+
process.once("SIGINT", abort);
|
|
1111
|
+
try {
|
|
1112
|
+
const result = await new InstalledPluginRuntimeV1({ coreVersion: VERSION }).run(command, {
|
|
1113
|
+
args: positional,
|
|
1114
|
+
flags,
|
|
1115
|
+
signal: controller.signal,
|
|
1116
|
+
});
|
|
1117
|
+
if (!result)
|
|
1118
|
+
exitError(`Unknown command: ${command}. Run 'agent-memory help' for usage.`, json);
|
|
1119
|
+
if (!result.ok)
|
|
1120
|
+
exitError(result.error?.message ?? `Plugin command ${command} failed`, json);
|
|
1121
|
+
output(result.data ?? { ok: true }, json);
|
|
1122
|
+
}
|
|
1123
|
+
finally {
|
|
1124
|
+
process.removeListener("SIGINT", abort);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
763
1127
|
}
|
|
764
1128
|
}
|
|
765
1129
|
main().catch((err) => {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type CompletionShell = "bash" | "zsh" | "fish" | "powershell";
|
|
2
|
+
export interface CompletionInstallResult {
|
|
3
|
+
shell: CompletionShell;
|
|
4
|
+
completionPath: string;
|
|
5
|
+
profilePath?: string;
|
|
6
|
+
profileUpdated: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function generateCompletion(shell: CompletionShell): string;
|
|
9
|
+
export declare function detectCompletionShell(environment?: Record<string, string | undefined>, platform?: NodeJS.Platform): CompletionShell | null;
|
|
10
|
+
export declare function installCompletion(shell: CompletionShell, options?: {
|
|
11
|
+
homeDir?: string;
|
|
12
|
+
platform?: NodeJS.Platform;
|
|
13
|
+
}): CompletionInstallResult;
|