agent-working-memory 0.14.6 → 0.15.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/.claude-plugin/marketplace.json +17 -0
- package/README.md +16 -3
- package/dist/adapters/claude-code.d.ts +9 -0
- package/dist/adapters/claude-code.d.ts.map +1 -1
- package/dist/adapters/claude-code.js +1 -1
- package/dist/adapters/claude-code.js.map +1 -1
- package/dist/adapters/common.d.ts +4 -1
- package/dist/adapters/common.d.ts.map +1 -1
- package/dist/adapters/common.js +2 -2
- package/dist/adapters/common.js.map +1 -1
- package/dist/cli.js +54 -2
- package/dist/cli.js.map +1 -1
- package/dist/core/write-pipeline.js +17 -0
- package/dist/core/write-pipeline.js.map +1 -1
- package/dist/storage/factory.d.ts.map +1 -1
- package/dist/storage/factory.js +20 -8
- package/dist/storage/factory.js.map +1 -1
- package/package.json +9 -3
- package/plugin/.claude-plugin/plugin.json +34 -0
- package/plugin/README.md +36 -0
- package/plugin/bin/awm-mcp-launcher.cjs +109 -0
- package/plugin/hooks/awm-checkpoint.cjs +55 -0
- package/plugin/hooks/awm-db-mutation-reminder.cjs +25 -0
- package/plugin/hooks/awm-find-sidecar.cjs +145 -0
- package/plugin/hooks/awm-prime.cjs +97 -0
- package/plugin/hooks/hooks.json +66 -0
- package/plugin/skills/awm-memory/SKILL.md +445 -0
- package/src/adapters/claude-code.ts +1 -1
- package/src/adapters/common.ts +5 -3
- package/src/cli.ts +58 -1
- package/src/core/write-pipeline.ts +18 -0
- package/src/plugin/awm-mcp-launcher.cjs +109 -0
- package/src/storage/factory.ts +19 -7
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Copyright 2026 Robert Winter / Complete Ideas
|
|
3
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
//
|
|
5
|
+
// Entry point for the Claude Code plugin's MCP server.
|
|
6
|
+
//
|
|
7
|
+
// This is a REAL source file, not a string inside the generator, because it is real code:
|
|
8
|
+
// it gets syntax-checked, linted and tested like everything else. `npm run build:plugin`
|
|
9
|
+
// copies it to plugin/bin/ and substitutes __AWM_VERSION__.
|
|
10
|
+
//
|
|
11
|
+
// Two jobs a bare `mcpServers` entry in plugin.json cannot do:
|
|
12
|
+
//
|
|
13
|
+
// 1. Default the store to ~/.awm/memory.db — the SAME file `awm setup --global` writes.
|
|
14
|
+
// Without this the plugin opens its own empty database and "your memory follows you
|
|
15
|
+
// between Claude Code, Desktop and Cowork" is simply false.
|
|
16
|
+
//
|
|
17
|
+
// 2. Find the server. A plugin does not know whether the package is installed globally,
|
|
18
|
+
// sits in a local node_modules, or is a checkout on disk.
|
|
19
|
+
//
|
|
20
|
+
// Fails loudly on stderr. A silent exit here looks like "the memory tools just aren't there",
|
|
21
|
+
// which is the least debuggable failure this could have.
|
|
22
|
+
'use strict';
|
|
23
|
+
|
|
24
|
+
const { join, resolve, sep } = require('node:path');
|
|
25
|
+
const { homedir } = require('node:os');
|
|
26
|
+
const { existsSync } = require('node:fs');
|
|
27
|
+
const { pathToFileURL } = require('node:url');
|
|
28
|
+
const { spawn, execFileSync } = require('node:child_process');
|
|
29
|
+
|
|
30
|
+
const NL = '\n';
|
|
31
|
+
|
|
32
|
+
// Claude Desktop substitutes user_config values into env, and a field the user cleared
|
|
33
|
+
// arrives as an empty string rather than being absent. An empty AWM_AGENT_ID would override
|
|
34
|
+
// the server's directory-derived default with nothing, so drop empties before anything reads
|
|
35
|
+
// them and let the normal defaults apply.
|
|
36
|
+
for (const k of ['AWM_DB_PATH', 'AWM_AGENT_ID', 'AWM_HOOK_PORT', 'AWM_PACKAGE_ROOT']) {
|
|
37
|
+
if (process.env[k] !== undefined && String(process.env[k]).trim() === '') delete process.env[k];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// An explicit AWM_DB_PATH always wins, so per-project pools still work.
|
|
41
|
+
if (!process.env.AWM_DB_PATH) {
|
|
42
|
+
process.env.AWM_DB_PATH = join(homedir(), '.awm', 'memory.db').split(sep).join('/');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const tried = [];
|
|
46
|
+
function candidate(p) {
|
|
47
|
+
if (!p) return null;
|
|
48
|
+
tried.push(p);
|
|
49
|
+
return existsSync(p) ? p : null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// In priority order. npx is last: on a cold cache it rebuilds better-sqlite3, which takes
|
|
53
|
+
// minutes and is indistinguishable from a hang.
|
|
54
|
+
let found =
|
|
55
|
+
// 1. An explicit override.
|
|
56
|
+
candidate(process.env.AWM_PACKAGE_ROOT && join(process.env.AWM_PACKAGE_ROOT, 'dist', 'mcp.js')) ||
|
|
57
|
+
// 2. The plugin sitting inside an AWM checkout (plugin/bin -> ../../dist).
|
|
58
|
+
candidate(resolve(__dirname, '..', '..', 'dist', 'mcp.js')) ||
|
|
59
|
+
// 3. A local dependency of the project being worked on.
|
|
60
|
+
candidate(join(process.cwd(), 'node_modules', 'agent-working-memory', 'dist', 'mcp.js'));
|
|
61
|
+
|
|
62
|
+
// 4. A global install. require.resolve does not search global roots, so ask npm once.
|
|
63
|
+
if (!found) {
|
|
64
|
+
try {
|
|
65
|
+
const isWin = process.platform === 'win32';
|
|
66
|
+
const root = execFileSync(isWin ? 'npm.cmd' : 'npm', ['root', '-g'], {
|
|
67
|
+
encoding: 'utf-8',
|
|
68
|
+
shell: isWin,
|
|
69
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
70
|
+
}).trim();
|
|
71
|
+
found = candidate(root && join(root, 'agent-working-memory', 'dist', 'mcp.js'));
|
|
72
|
+
} catch {
|
|
73
|
+
/* npm not on PATH — fall through */
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// 5. Anywhere node can resolve it from here.
|
|
78
|
+
if (!found) {
|
|
79
|
+
try {
|
|
80
|
+
found = require.resolve('agent-working-memory/dist/mcp.js');
|
|
81
|
+
} catch {
|
|
82
|
+
/* not installed where this script can see it */
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (found) {
|
|
87
|
+
// dist/ is ESM ("type": "module"), so import() — require() throws ERR_REQUIRE_ESM.
|
|
88
|
+
import(pathToFileURL(found).href).catch((e) => {
|
|
89
|
+
process.stderr.write('[awm] failed to load ' + found + ': ' + e.message + NL);
|
|
90
|
+
process.exit(1);
|
|
91
|
+
});
|
|
92
|
+
} else {
|
|
93
|
+
// Last resort, pinned so the tools match the hook scripts shipped beside them.
|
|
94
|
+
// shell:true on Windows: spawning npx.cmd directly throws EINVAL since Node 18.20/20.12.
|
|
95
|
+
const isWin = process.platform === 'win32';
|
|
96
|
+
const child = spawn(
|
|
97
|
+
isWin ? 'npx.cmd' : 'npx',
|
|
98
|
+
['-y', '-p', 'agent-working-memory@__AWM_VERSION__', 'awm', 'mcp'],
|
|
99
|
+
{ stdio: 'inherit', env: process.env, shell: isWin }
|
|
100
|
+
);
|
|
101
|
+
child.on('error', (e) => {
|
|
102
|
+
process.stderr.write('[awm] could not start the MCP server: ' + e.message + NL);
|
|
103
|
+
process.stderr.write('[awm] looked in:' + NL);
|
|
104
|
+
for (const t of tried) process.stderr.write(' ' + t + NL);
|
|
105
|
+
process.stderr.write('[awm] fix: npm install -g agent-working-memory' + NL);
|
|
106
|
+
process.exit(1);
|
|
107
|
+
});
|
|
108
|
+
child.on('exit', (code) => process.exit(code == null ? 0 : code));
|
|
109
|
+
}
|
package/src/storage/factory.ts
CHANGED
|
@@ -49,13 +49,25 @@ export type StoreBackend = 'sqlite' | 'pglite' | 'postgres';
|
|
|
49
49
|
function detectBackendFromDisk(): StoreBackend | null {
|
|
50
50
|
// If AWM_DB_PATH is set, infer from its shape.
|
|
51
51
|
const explicitPath = process.env.AWM_DB_PATH;
|
|
52
|
-
if (explicitPath
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
52
|
+
if (explicitPath) {
|
|
53
|
+
if (existsSync(explicitPath)) {
|
|
54
|
+
try {
|
|
55
|
+
const stat = statSync(explicitPath);
|
|
56
|
+
if (stat.isDirectory()) return 'pglite'; // PGlite uses a directory
|
|
57
|
+
if (stat.isFile()) return 'sqlite'; // SQLite is a single file
|
|
58
|
+
} catch { /* fall through to the default below */ }
|
|
59
|
+
}
|
|
60
|
+
// The caller named a path that does not exist yet — a brand-new store. Default it to
|
|
61
|
+
// SQLite and STOP: falling through to the cwd conventions below would pick the backend
|
|
62
|
+
// from files that have nothing to do with the path that was asked for.
|
|
63
|
+
//
|
|
64
|
+
// Not hypothetical. Running from a checkout containing a `memory-pglite/` directory
|
|
65
|
+
// made a fresh AWM_DB_PATH=/tmp/new-store.db resolve to PGlite, which is
|
|
66
|
+
// single-process — so two surfaces pointed at 'the same store' would have had the
|
|
67
|
+
// second refuse to start. Found by the cross-surface end-to-end test.
|
|
68
|
+
// PGlite at a new path is still reachable via AWM_STORE_BACKEND=pglite.
|
|
69
|
+
return 'sqlite';
|
|
70
|
+
}
|
|
59
71
|
|
|
60
72
|
// Otherwise look for the conventional defaults in cwd.
|
|
61
73
|
// PGlite directory wins over SQLite file when both exist — assume the
|