myagentmemory 0.5.2 → 0.5.4
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 +10 -7
- package/dist/cli-spec.d.ts +1 -1
- package/dist/cli-spec.js +16 -4
- package/dist/cli.js +466 -65
- package/dist/completions.d.ts +12 -0
- package/dist/completions.js +51 -0
- package/dist/core.js +11 -0
- package/dist/hooks.d.ts +15 -1
- package/dist/hooks.js +190 -5
- package/dist/mcp-server.d.ts +2 -0
- package/dist/mcp-server.js +15 -0
- package/dist/plugin-host.d.ts +7 -1
- package/dist/plugin-runtime.d.ts +2 -0
- package/dist/plugin-runtime.js +13 -1
- package/dist/plugin-service.d.ts +1 -5
- package/dist/plugin-service.js +16 -64
- package/dist/upgrade.d.ts +60 -7
- package/dist/upgrade.js +146 -15
- package/docs/official-plugin-bootstrap.md +3 -4
- package/package.json +1 -2
- package/scripts/install-skills.sh +4 -1
- package/skills/agent/SKILL.md +1 -1
- package/skills/claude-code/SKILL.md +1 -1
- package/skills/codex/SKILL.md +1 -1
- package/skills/cursor/SKILL.md +1 -1
- package/skills/qoder/SKILL.md +164 -0
- package/src/cli-spec.ts +19 -4
- package/src/completions.ts +73 -0
- package/src/core.ts +11 -0
- package/src/hooks.ts +199 -6
- package/src/plugin-host.ts +7 -1
package/dist/plugin-service.js
CHANGED
|
@@ -139,8 +139,8 @@ function activationPage(action, error) {
|
|
|
139
139
|
<p class="terminal-note" id="terminal-note">Your terminal will finish setup after activation.</p>
|
|
140
140
|
<details>
|
|
141
141
|
<summary>What’s shared during activation</summary>
|
|
142
|
-
<p>Your email identifies your free daily allowance. The CLI also sends core and bundle versions, platform, architecture, and release channel. The service stores
|
|
143
|
-
<p class="never-sent"><strong>
|
|
142
|
+
<p>Your email identifies your free daily allowance. The CLI also sends core and bundle versions, platform, architecture, and release channel. The service stores bounded activation metadata. Activation records expire after 365 days without use.</p>
|
|
143
|
+
<p class="never-sent"><strong>Not included in AgentMemory's application payload:</strong> memory, session content, queries, repository paths, raw agent session identifiers, IP addresses, or user-agent strings.</p>
|
|
144
144
|
</details>
|
|
145
145
|
</section>
|
|
146
146
|
</main>
|
|
@@ -394,38 +394,21 @@ export class AgentMemoryServiceBackend {
|
|
|
394
394
|
validatePluginEntitlementStatusV1(value.entitlement);
|
|
395
395
|
if (typeof value.artifactGrant !== "string" || !value.artifactGrant)
|
|
396
396
|
throw new PluginBootstrapFailure("service_response_invalid", "The access response omitted its artifact grant");
|
|
397
|
-
if (typeof value.usageCredential !== "string" || !ACTIVATION_CREDENTIAL.test(value.usageCredential))
|
|
398
|
-
throw new PluginBootstrapFailure("service_response_invalid", "The access response omitted its usage credential");
|
|
399
397
|
const recallQuota = value.entitlement.capabilities.recall?.quota;
|
|
400
398
|
const learningQuota = value.entitlement.capabilities.learning?.quota;
|
|
401
399
|
if (value.entitlement.plan !== "free" ||
|
|
402
400
|
value.entitlement.state !== "active" ||
|
|
403
401
|
value.entitlement.capabilities.recall?.enabled !== true ||
|
|
404
402
|
!recallQuota ||
|
|
405
|
-
recallQuota.limit !== 20 ||
|
|
406
|
-
recallQuota.scope !== "device" ||
|
|
407
|
-
recallQuota.window !== "day" ||
|
|
408
403
|
value.entitlement.capabilities.learning?.enabled !== true ||
|
|
409
404
|
!learningQuota ||
|
|
410
|
-
learningQuota.limit !== 5 ||
|
|
411
|
-
learningQuota.scope !== "device" ||
|
|
412
|
-
learningQuota.window !== "day" ||
|
|
413
405
|
value.entitlement.capabilities["session-index"]?.enabled !== true ||
|
|
414
406
|
value.entitlement.capabilities["session-worker"]?.enabled !== false ||
|
|
415
407
|
value.entitlement.capabilities["web-console"]?.enabled !== true)
|
|
416
408
|
throw new PluginBootstrapFailure("service_response_invalid", "The free preview policy is invalid");
|
|
417
|
-
this.writeActivation(installationId
|
|
409
|
+
this.writeActivation(installationId);
|
|
418
410
|
return { kind: "granted", entitlement: value.entitlement, artifactGrant: value.artifactGrant };
|
|
419
411
|
}
|
|
420
|
-
async reserveSession(operationId) {
|
|
421
|
-
return this.sessionUsage("reserve", operationId);
|
|
422
|
-
}
|
|
423
|
-
async commitSession(operationId) {
|
|
424
|
-
return this.sessionUsage("commit", operationId);
|
|
425
|
-
}
|
|
426
|
-
async releaseSession(operationId) {
|
|
427
|
-
return this.sessionUsage("release", operationId);
|
|
428
|
-
}
|
|
429
412
|
async listReleases(request) {
|
|
430
413
|
const response = await this.request(`${this.apiOrigin}/v1/plugin/releases`, {
|
|
431
414
|
headers: { Authorization: `Bearer ${request.artifactGrant}` },
|
|
@@ -480,28 +463,28 @@ export class AgentMemoryServiceBackend {
|
|
|
480
463
|
if (!stat.isFile() || stat.isSymbolicLink() || (process.platform !== "win32" && (stat.mode & 0o077) !== 0))
|
|
481
464
|
return null;
|
|
482
465
|
const value = JSON.parse(fs.readFileSync(activationPath, "utf-8"));
|
|
483
|
-
if (value.
|
|
484
|
-
typeof value.installationId !== "string" ||
|
|
466
|
+
if (typeof value.installationId !== "string" ||
|
|
485
467
|
!/^am_install_[A-Za-z0-9_-]{32}$/.test(value.installationId) ||
|
|
486
468
|
!Number.isFinite(Date.parse(value.activatedAt)) ||
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
469
|
+
(value.schemaVersion !== 4 &&
|
|
470
|
+
(value.schemaVersion !== 3 ||
|
|
471
|
+
typeof value.usageCredential !== "string" ||
|
|
472
|
+
!ACTIVATION_CREDENTIAL.test(value.usageCredential) ||
|
|
473
|
+
!Number.isSafeInteger(value.dailySessionLimit))))
|
|
491
474
|
return null;
|
|
492
|
-
return
|
|
475
|
+
return {
|
|
476
|
+
schemaVersion: 4,
|
|
477
|
+
installationId: value.installationId,
|
|
478
|
+
activatedAt: value.activatedAt,
|
|
479
|
+
};
|
|
493
480
|
}
|
|
494
481
|
catch {
|
|
495
482
|
return null;
|
|
496
483
|
}
|
|
497
484
|
}
|
|
498
|
-
writeActivation(installationId
|
|
485
|
+
writeActivation(installationId) {
|
|
499
486
|
if (!/^am_install_[A-Za-z0-9_-]{32}$/.test(installationId))
|
|
500
487
|
throw new PluginBootstrapFailure("activation_failed", "The installation identifier is invalid");
|
|
501
|
-
if (!ACTIVATION_CREDENTIAL.test(usageCredential))
|
|
502
|
-
throw new PluginBootstrapFailure("activation_failed", "The activation credential is invalid");
|
|
503
|
-
if (!Number.isSafeInteger(dailySessionLimit) || dailySessionLimit <= 0 || dailySessionLimit > 10_000)
|
|
504
|
-
throw new PluginBootstrapFailure("activation_failed", "The free session allowance is invalid");
|
|
505
488
|
const target = this.activationPath();
|
|
506
489
|
fs.mkdirSync(this.root, { recursive: true, mode: 0o700 });
|
|
507
490
|
const rootStat = fs.lstatSync(this.root);
|
|
@@ -515,43 +498,12 @@ export class AgentMemoryServiceBackend {
|
|
|
515
498
|
throw new PluginBootstrapFailure("activation_path_invalid", "The plugin activation directory is unsafe");
|
|
516
499
|
const temporary = `${target}.tmp-${process.pid}-${randomUUID()}`;
|
|
517
500
|
fs.writeFileSync(temporary, `${JSON.stringify({
|
|
518
|
-
schemaVersion:
|
|
501
|
+
schemaVersion: 4,
|
|
519
502
|
installationId,
|
|
520
503
|
activatedAt: new Date().toISOString(),
|
|
521
|
-
usageCredential,
|
|
522
|
-
dailySessionLimit,
|
|
523
504
|
}, null, 2)}\n`, { mode: 0o600, flag: "wx" });
|
|
524
505
|
fs.renameSync(temporary, target);
|
|
525
506
|
}
|
|
526
|
-
async sessionUsage(action, operationId) {
|
|
527
|
-
const activation = this.readActivation();
|
|
528
|
-
if (!activation)
|
|
529
|
-
throw new PluginBootstrapFailure("auth_required", "Run plugin install to activate AgentMemory");
|
|
530
|
-
const response = await this.request(`${this.apiOrigin}/v1/plugin/sessions/${action}`, {
|
|
531
|
-
method: "POST",
|
|
532
|
-
headers: {
|
|
533
|
-
Authorization: `Bearer ${activation.usageCredential}`,
|
|
534
|
-
"Content-Type": "application/json",
|
|
535
|
-
},
|
|
536
|
-
body: JSON.stringify({ schemaVersion: 1, operationId }),
|
|
537
|
-
});
|
|
538
|
-
const value = (await readJson(response));
|
|
539
|
-
const decision = value.decision;
|
|
540
|
-
if (!decision ||
|
|
541
|
-
typeof decision.allowed !== "boolean" ||
|
|
542
|
-
!["reserved", "committed", "released", "exhausted", "missing"].includes(String(decision.state)) ||
|
|
543
|
-
!Number.isSafeInteger(decision.limit) ||
|
|
544
|
-
Number(decision.limit) <= 0 ||
|
|
545
|
-
!Number.isSafeInteger(decision.used) ||
|
|
546
|
-
Number(decision.used) < 0 ||
|
|
547
|
-
!Number.isSafeInteger(decision.remaining) ||
|
|
548
|
-
Number(decision.remaining) < 0 ||
|
|
549
|
-
typeof decision.resetAt !== "string" ||
|
|
550
|
-
!Number.isFinite(Date.parse(decision.resetAt)) ||
|
|
551
|
-
typeof decision.idempotent !== "boolean")
|
|
552
|
-
throw new PluginBootstrapFailure("service_response_invalid", "The session usage response is invalid");
|
|
553
|
-
return decision;
|
|
554
|
-
}
|
|
555
507
|
async request(url, init = {}) {
|
|
556
508
|
let response;
|
|
557
509
|
try {
|
package/dist/upgrade.d.ts
CHANGED
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Upgrade orchestration for the `agent-memory` CLI and its official Pro plugin bundle.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Three consumers:
|
|
5
5
|
* 1. `agent-memory upgrade` — explicit user command; checks and (optionally) installs.
|
|
6
|
-
* 2. `agent-memory
|
|
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 { type SpawnOptions } from "node:child_process";
|
|
12
|
-
export type InstallManager = "bun" | "npm" | "pnpm" | "yarn" | "unknown";
|
|
18
|
+
export type InstallManager = "bun" | "homebrew" | "npm" | "pnpm" | "yarn" | "unknown";
|
|
13
19
|
export interface InstallMethod {
|
|
14
20
|
manager: InstallManager;
|
|
15
21
|
global: boolean;
|
|
@@ -24,6 +30,17 @@ export interface UpgradeCache {
|
|
|
24
30
|
cliLatest: string | null;
|
|
25
31
|
pluginCurrent: string | null;
|
|
26
32
|
pluginLatest: string | null;
|
|
33
|
+
/** Outcome of the most recent `--background` auto-upgrade attempt, if any. */
|
|
34
|
+
cliAuto?: AutoUpgradeOutcome;
|
|
35
|
+
pluginAuto?: AutoUpgradeOutcome;
|
|
36
|
+
}
|
|
37
|
+
export interface AutoUpgradeOutcome {
|
|
38
|
+
at: string;
|
|
39
|
+
ok: boolean;
|
|
40
|
+
/** Version installed (ok) or the previous/current version (failure). */
|
|
41
|
+
version: string | null;
|
|
42
|
+
/** Failure reason; absent when ok. */
|
|
43
|
+
error?: string;
|
|
27
44
|
}
|
|
28
45
|
export interface UpgradeStatus {
|
|
29
46
|
cli: {
|
|
@@ -42,6 +59,32 @@ export interface UpgradeStatus {
|
|
|
42
59
|
export declare function readUpgradeCache(): UpgradeCache | null;
|
|
43
60
|
export declare function writeUpgradeCache(record: UpgradeCache): void;
|
|
44
61
|
export declare function isCacheFresh(record: UpgradeCache | null, now?: number): boolean;
|
|
62
|
+
export type UpgradePolicyValue = "off" | "notify" | "auto";
|
|
63
|
+
export interface UpgradePolicy {
|
|
64
|
+
cli: UpgradePolicyValue;
|
|
65
|
+
plugin: UpgradePolicyValue;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Resolve the persisted auto-upgrade policy.
|
|
69
|
+
* Precedence per target: `AGENT_MEMORY_AUTO_UPGRADE_{CLI,PLUGIN}` env var →
|
|
70
|
+
* `<memoryDir>/state/upgrade-policy.json` → default `"auto"`.
|
|
71
|
+
*
|
|
72
|
+
* `existed` tells callers whether the policy file was already on disk —
|
|
73
|
+
* used to fire a one-time "auto-upgrade is on" notice on first read.
|
|
74
|
+
*/
|
|
75
|
+
export declare function readUpgradePolicy(): UpgradePolicy & {
|
|
76
|
+
existed: boolean;
|
|
77
|
+
};
|
|
78
|
+
/** Atomically persist the auto-upgrade policy. Merges with whatever is already on disk. */
|
|
79
|
+
export declare function writeUpgradePolicy(patch: Partial<UpgradePolicy>): UpgradePolicy;
|
|
80
|
+
export declare function resolveSelfLaunch(input: {
|
|
81
|
+
execPath: string;
|
|
82
|
+
scriptCandidate: string | undefined;
|
|
83
|
+
fileExists: (candidate: string) => boolean;
|
|
84
|
+
}): {
|
|
85
|
+
command: string;
|
|
86
|
+
args: string[];
|
|
87
|
+
};
|
|
45
88
|
/**
|
|
46
89
|
* Best-effort detection of how `myagentmemory` was installed. Path signatures
|
|
47
90
|
* are heuristic but cover the common managers. On no match we fall back to
|
|
@@ -58,8 +101,10 @@ export interface InstallResult {
|
|
|
58
101
|
export declare function runInstaller(method: InstallMethod, opts?: SpawnOptions): InstallResult;
|
|
59
102
|
/**
|
|
60
103
|
* Fire-and-forget: spawn a detached child that runs `agent-memory upgrade
|
|
61
|
-
* --
|
|
62
|
-
*
|
|
104
|
+
* --background --refresh --quiet` so the next session-start has a fresh
|
|
105
|
+
* cache. Unlike a plain check, `--background` also installs any target whose
|
|
106
|
+
* policy is `"auto"` (see `readUpgradePolicy`) — this is the one place
|
|
107
|
+
* auto-upgrade actually happens. Never awaits, never throws.
|
|
63
108
|
*/
|
|
64
109
|
export declare function refreshUpgradeCacheBackground(): void;
|
|
65
110
|
export interface CheckOptions {
|
|
@@ -77,4 +122,12 @@ export interface CheckOptions {
|
|
|
77
122
|
pluginUpgradeAvailable?: boolean;
|
|
78
123
|
}
|
|
79
124
|
export declare function checkForUpgrades(opts: CheckOptions): Promise<UpgradeStatus>;
|
|
80
|
-
|
|
125
|
+
/**
|
|
126
|
+
* `cache` (when passed) lets this distinguish a plain "notify" signal from the
|
|
127
|
+
* outcome of the last `--background` auto-install attempt for that target:
|
|
128
|
+
* - succeeded, but this process is running older code than what's on disk
|
|
129
|
+
* (e.g. a long-running `serve --mcp`) → "auto-upgraded, restart to use it"
|
|
130
|
+
* - failed → surface the error and point at the manual command
|
|
131
|
+
* - succeeded and already caught up (this process's own version matches) → silent
|
|
132
|
+
*/
|
|
133
|
+
export declare function formatUpgradeNotice(status: UpgradeStatus, cache?: UpgradeCache | null): string | null;
|
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
|
-
*
|
|
4
|
+
* Three consumers:
|
|
5
5
|
* 1. `agent-memory upgrade` — explicit user command; checks and (optionally) installs.
|
|
6
|
-
* 2. `agent-memory
|
|
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,15 +110,91 @@ 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
|
// ---------------------------------------------------------------------------
|
|
170
|
+
export function resolveSelfLaunch(input) {
|
|
171
|
+
const scriptCandidate = input.scriptCandidate;
|
|
172
|
+
const isRealScript = typeof scriptCandidate === "string" &&
|
|
173
|
+
scriptCandidate.length > 0 &&
|
|
174
|
+
!scriptCandidate.startsWith("/$bunfs/") &&
|
|
175
|
+
input.fileExists(scriptCandidate);
|
|
176
|
+
return isRealScript ? { command: input.execPath, args: [scriptCandidate] } : { command: input.execPath, args: [] };
|
|
177
|
+
}
|
|
178
|
+
function currentSelfLaunch() {
|
|
179
|
+
return resolveSelfLaunch({
|
|
180
|
+
execPath: process.execPath,
|
|
181
|
+
scriptCandidate: process.argv[1],
|
|
182
|
+
fileExists: fs.existsSync,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
99
185
|
function selfInstallPath() {
|
|
186
|
+
const launch = currentSelfLaunch();
|
|
187
|
+
const candidate = launch.args[0] ?? launch.command;
|
|
100
188
|
try {
|
|
101
|
-
return
|
|
189
|
+
return fs.realpathSync(candidate);
|
|
102
190
|
}
|
|
103
191
|
catch {
|
|
104
|
-
|
|
192
|
+
try {
|
|
193
|
+
return url.fileURLToPath(import.meta.url);
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return candidate;
|
|
197
|
+
}
|
|
105
198
|
}
|
|
106
199
|
}
|
|
107
200
|
/**
|
|
@@ -113,6 +206,16 @@ export function detectInstallMethod(location = selfInstallPath()) {
|
|
|
113
206
|
const normalized = location.replace(/\\/g, "/");
|
|
114
207
|
const home = os.homedir().replace(/\\/g, "/");
|
|
115
208
|
const pkg = `${NPM_PACKAGE_NAME}@latest`;
|
|
209
|
+
// Compiled CLI installed by the official Homebrew formula. Resolve symlinks
|
|
210
|
+
// before detection so /opt/homebrew/bin/agent-memory reaches its Cellar path.
|
|
211
|
+
if (normalized.includes("/Cellar/agent-memory/")) {
|
|
212
|
+
return {
|
|
213
|
+
manager: "homebrew",
|
|
214
|
+
global: true,
|
|
215
|
+
origin: location,
|
|
216
|
+
command: ["brew", "upgrade", "jayzeng/agentmemory/agent-memory"],
|
|
217
|
+
};
|
|
218
|
+
}
|
|
116
219
|
// bun global install
|
|
117
220
|
if (normalized.includes("/.bun/install/global/") || normalized.includes("/bun/install/global/")) {
|
|
118
221
|
return { manager: "bun", global: true, origin: location, command: ["bun", "add", "-g", pkg] };
|
|
@@ -163,16 +266,17 @@ export function runInstaller(method, opts = {}) {
|
|
|
163
266
|
// ---------------------------------------------------------------------------
|
|
164
267
|
/**
|
|
165
268
|
* Fire-and-forget: spawn a detached child that runs `agent-memory upgrade
|
|
166
|
-
* --
|
|
167
|
-
*
|
|
269
|
+
* --background --refresh --quiet` so the next session-start has a fresh
|
|
270
|
+
* cache. Unlike a plain check, `--background` also installs any target whose
|
|
271
|
+
* policy is `"auto"` (see `readUpgradePolicy`) — this is the one place
|
|
272
|
+
* auto-upgrade actually happens. Never awaits, never throws.
|
|
168
273
|
*/
|
|
169
274
|
export function refreshUpgradeCacheBackground() {
|
|
170
275
|
try {
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
if (!binary || !script)
|
|
276
|
+
const launch = currentSelfLaunch();
|
|
277
|
+
if (!launch.command)
|
|
174
278
|
return;
|
|
175
|
-
const child = spawn(
|
|
279
|
+
const child = spawn(launch.command, [...launch.args, "upgrade", "--background", "--refresh", "--quiet", "--json"], {
|
|
176
280
|
detached: true,
|
|
177
281
|
stdio: "ignore",
|
|
178
282
|
env: { ...process.env, AGENT_MEMORY_UPGRADE_BACKGROUND: "1" },
|
|
@@ -231,13 +335,40 @@ export async function checkForUpgrades(opts) {
|
|
|
231
335
|
fromCache,
|
|
232
336
|
};
|
|
233
337
|
}
|
|
234
|
-
|
|
338
|
+
/**
|
|
339
|
+
* `cache` (when passed) lets this distinguish a plain "notify" signal from the
|
|
340
|
+
* outcome of the last `--background` auto-install attempt for that target:
|
|
341
|
+
* - succeeded, but this process is running older code than what's on disk
|
|
342
|
+
* (e.g. a long-running `serve --mcp`) → "auto-upgraded, restart to use it"
|
|
343
|
+
* - failed → surface the error and point at the manual command
|
|
344
|
+
* - succeeded and already caught up (this process's own version matches) → silent
|
|
345
|
+
*/
|
|
346
|
+
export function formatUpgradeNotice(status, cache) {
|
|
235
347
|
const parts = [];
|
|
236
|
-
|
|
348
|
+
let needsManualRun = false;
|
|
349
|
+
if (cache?.cliAuto && !cache.cliAuto.ok) {
|
|
350
|
+
parts.push(`CLI auto-upgrade failed (${cache.cliAuto.error ?? "unknown error"})`);
|
|
351
|
+
needsManualRun = true;
|
|
352
|
+
}
|
|
353
|
+
else if (cache?.cliAuto?.ok && cache.cliAuto.version && cache.cliAuto.version !== status.cli.current) {
|
|
354
|
+
parts.push(`CLI auto-upgraded → ${cache.cliAuto.version} (restart any long-running agent-memory process to use it)`);
|
|
355
|
+
}
|
|
356
|
+
else if (status.cli.upgradeAvailable) {
|
|
237
357
|
parts.push(`CLI ${status.cli.current} → ${status.cli.latest ?? "new"}`);
|
|
238
|
-
|
|
358
|
+
needsManualRun = true;
|
|
359
|
+
}
|
|
360
|
+
if (cache?.pluginAuto && !cache.pluginAuto.ok) {
|
|
361
|
+
parts.push(`Pro auto-upgrade failed (${cache.pluginAuto.error ?? "unknown error"})`);
|
|
362
|
+
needsManualRun = true;
|
|
363
|
+
}
|
|
364
|
+
else if (cache?.pluginAuto?.ok && cache.pluginAuto.version && cache.pluginAuto.version !== status.plugin.current) {
|
|
365
|
+
parts.push(`Pro auto-upgraded → ${cache.pluginAuto.version}`);
|
|
366
|
+
}
|
|
367
|
+
else if (status.plugin.upgradeAvailable) {
|
|
239
368
|
parts.push(`Pro ${status.plugin.current ?? "?"} → ${status.plugin.latest ?? "new"}`);
|
|
369
|
+
needsManualRun = true;
|
|
370
|
+
}
|
|
240
371
|
if (!parts.length)
|
|
241
372
|
return null;
|
|
242
|
-
return `agent-memory:
|
|
373
|
+
return `agent-memory: ${parts.join("; ")}${needsManualRun ? ". Run: agent-memory upgrade" : ""}`;
|
|
243
374
|
}
|
|
@@ -89,7 +89,7 @@ The `pro` namespace is the user-facing surface. The `plugin` namespace remains s
|
|
|
89
89
|
- `status` is read-only. It reports the installed bundle, selected channel, compatibility, entitlement state, and update availability.
|
|
90
90
|
- `install` authenticates when necessary, then installs, upgrades, or reports current state.
|
|
91
91
|
- `update` requires an existing installation and never starts a new purchase implicitly.
|
|
92
|
-
- `uninstall` removes executable plugin material and the active receipt. It preserves core memory, plugin state, and the permission-restricted activation
|
|
92
|
+
- `uninstall` removes executable plugin material and the active receipt. It preserves core memory, plugin state, and the permission-restricted local activation record.
|
|
93
93
|
- `manage` remains unavailable until authenticated account and billing management exists.
|
|
94
94
|
|
|
95
95
|
Installed plugins contribute top-level commands including `recall` and `learn`; `dashboard` is a product-facing alias for the lower-level `web` command. Bootstrap command names are reserved by the core and cannot be replaced by a plugin.
|
|
@@ -172,7 +172,6 @@ An Enterprise administrator may pre-provision an organization entitlement or man
|
|
|
172
172
|
The service exposes:
|
|
173
173
|
|
|
174
174
|
- `POST /v1/plugin/access` for an anonymous free-preview policy, compatibility credential, and short-lived artifact grant;
|
|
175
|
-
- `POST /v1/plugin/sessions/reserve|commit|release` for migration compatibility with activation-v2 clients;
|
|
176
175
|
- `GET /v1/plugin/releases` for an Ed25519-signed release selected from the private R2 catalog;
|
|
177
176
|
- `GET|HEAD /v1/artifacts/download` for the exact content-addressed object authorized by the bearer grant.
|
|
178
177
|
|
|
@@ -191,7 +190,7 @@ The bootstrap may send only:
|
|
|
191
190
|
- core version, plugin-host API version, platform, and architecture;
|
|
192
191
|
- requested bundle ID, installed bundle version, and release channel;
|
|
193
192
|
- a pseudonymous license or organization identifier;
|
|
194
|
-
- protocol nonces
|
|
193
|
+
- protocol nonces and authentication material required for the request.
|
|
195
194
|
|
|
196
195
|
It must never send memory contents, search queries, session contents, raw agent session identifiers, working-directory names, repository names, filesystem paths, or qmd data. The bounded allowance counter is authorization state, not general product telemetry.
|
|
197
196
|
|
|
@@ -267,7 +266,7 @@ An install or upgrade must:
|
|
|
267
266
|
|
|
268
267
|
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
268
|
|
|
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
|
|
269
|
+
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 local activation 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 activation state) once the user opts in and confirms.
|
|
271
270
|
|
|
272
271
|
## Plugin host API v1
|
|
273
272
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "myagentmemory",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.4",
|
|
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",
|
|
@@ -93,7 +93,6 @@
|
|
|
93
93
|
"dist/plugin-runtime.js",
|
|
94
94
|
"dist/plugin-service.d.ts",
|
|
95
95
|
"dist/plugin-service.js",
|
|
96
|
-
|
|
97
96
|
"dist/mcp-server.d.ts",
|
|
98
97
|
"dist/mcp-server.js",
|
|
99
98
|
"dist/upgrade.d.ts",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# Install (or uninstall) agent-memory skills for Claude Code, Codex, Cursor,
|
|
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
|
package/skills/agent/SKILL.md
CHANGED
|
@@ -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
|
|
package/skills/codex/SKILL.md
CHANGED
|
@@ -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
|
package/skills/cursor/SKILL.md
CHANGED
|
@@ -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
|