cogmem 3.6.2 → 3.6.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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.6.3
4
+
5
+ - Added a GitHub Release `published` workflow for npm Trusted Publishing with OIDC provenance, full tests, build, version-tag validation, and package dry-run verification before `npm publish`.
6
+ - Fixed `cogmem migrate --dry-run` so it opens SQLite read-only and plans legacy `_meta.schema_version` adoption without creating `_schema_migrations` or writing migration rows.
7
+ - Hardened `cogmem update` target resolution for npm global installs, one-line installer homes, local project dependencies, and source checkouts so `cogmem update --yes` does not silently install into an arbitrary current directory.
8
+ - Updated OpenClaw diagnostics and generated bridge behavior to propagate `rememberDrainTimeoutMs`, recover stale `.processing` queue files, and report pending/dead/lock/processing queue state.
9
+
3
10
  ## 3.6.2
4
11
 
5
12
  - Switched the public distribution channel to the npm registry while keeping GitHub as the source and review mirror.
package/CONTRIBUTING.md CHANGED
@@ -18,10 +18,10 @@ bun run typecheck
18
18
  bun test
19
19
  npm pack --dry-run --json
20
20
  npm publish --dry-run --access public
21
- npm publish --access public
21
+ npm publish --provenance --access public
22
22
  ```
23
23
 
24
- `cogmem` is distributed through the npm registry. Use `npm pack --dry-run --json` to verify package contents, then `npm publish --dry-run --access public` before `npm publish --access public`. Keep the GitHub branch or release synchronized for source review and for older GitHub-installed users migrating onto the npm-first updater.
24
+ `cogmem` is distributed through the npm registry. Use `npm pack --dry-run --json` to verify package contents. Normal publishing happens by creating a GitHub Release from the matching version tag; `.github/workflows/publish.yml` is intentionally triggered by the release `published` event, not by tag pushes. Use `npm publish --provenance --access public` only as an emergency manual fallback.
25
25
 
26
26
  ## API Discipline
27
27
 
package/README.md CHANGED
@@ -11,7 +11,7 @@ It is not a knowledge-base app, a note-taking app, a vector RAG wrapper, an Obsi
11
11
 
12
12
  ## Status
13
13
 
14
- Current version: `3.6.2`
14
+ Current version: `3.6.3`
15
15
 
16
16
  Distribution: npm registry. GitHub remains the source mirror and hosts this installer, but package install and upgrade resolve `cogmem` from npm by default.
17
17
 
@@ -178,6 +178,13 @@ npm install cogmem@latest
178
178
  ./node_modules/.bin/cogmem init
179
179
  ```
180
180
 
181
+ Or install globally with npm when Bun is already on PATH:
182
+
183
+ ```bash
184
+ npm install -g cogmem@latest
185
+ cogmem init
186
+ ```
187
+
181
188
  Validate configuration:
182
189
 
183
190
  ```bash
@@ -190,7 +197,7 @@ Upgrade from npm and migrate an existing database:
190
197
  cogmem update --yes
191
198
  ```
192
199
 
193
- `cogmem update --yes` installs `cogmem@latest` from npm, then runs the newly installed `cogmem migrate --yes --backup --config <resolved-config>`. If OpenClaw is configured, the updater also runs the newly installed plugin-only repair command so stale `index.js` and `bridge.mjs` files are refreshed before you restart the agent. To inspect changes without writing:
200
+ `cogmem update --yes` installs `cogmem@latest` from npm, then runs the newly installed `cogmem migrate --yes --backup --config <resolved-config>`. It updates npm-global installs with `npm install -g`, the one-line installer home under `~/.cogmem/pkg`, or the current workspace dependency when Cogmem is a project dependency. If OpenClaw is configured, the updater also runs the newly installed plugin-only repair command so stale `index.js` and `bridge.mjs` files are refreshed before you restart the agent. To inspect changes without writing:
194
201
 
195
202
  ```bash
196
203
  cogmem update --dry-run --json
@@ -199,7 +206,7 @@ cogmem migrate --dry-run --json
199
206
 
200
207
  For a manual migration, run `cogmem migrate --yes --backup`. The migration runner adopts the existing `_meta.schema_version`, applies only later idempotent migrations, preserves Raw Ledger rows, and creates a timestamped, transaction-consistent standalone database backup before changing an on-disk database. The backup includes committed SQLite WAL pages instead of copying only the main database file.
201
208
 
202
- Upgrade a 3.5.2 database, a 3.6.0 database, or a pre-release schema-25 test database into the 3.6.2 schema set with one command:
209
+ Upgrade a 3.5.2 database, a 3.6.0 database, or a pre-release schema-25 test database into the 3.6.3 schema set with one command:
203
210
 
204
211
  ```bash
205
212
  cogmem migrate --yes --backup --json
@@ -241,7 +248,7 @@ For a host timer, call `dream tick`; the timer only wakes the scheduler. An empt
241
248
  cogmem dream tick --project my-agent --mode auto --max-episodes 10 --json
242
249
  ```
243
250
 
244
- Raw events are always written first. `KernelAgentMemoryBackend` and OpenClaw plugin 0.6.2 assemble live turns automatically. The foreground hook uses deterministic rules and previous assistant/user context; background import and repair paths may use the advisory hybrid classifier. Advisory output is allow-listed and cannot directly mutate durable memory. Unknown turns now fail closed as ambiguous. Continuation requires explicit continuation language or project/topic/entity/semantic overlap; Cogmem does not route domains with an expanding hard-coded keyword dictionary.
251
+ Raw events are always written first. `KernelAgentMemoryBackend` and OpenClaw plugin 0.6.3 assemble live turns automatically. The foreground hook uses deterministic rules and previous assistant/user context; background import and repair paths may use the advisory hybrid classifier. Advisory output is allow-listed and cannot directly mutate durable memory. Unknown turns now fail closed as ambiguous. Continuation requires explicit continuation language or project/topic/entity/semantic overlap; Cogmem does not route domains with an expanding hard-coded keyword dictionary.
245
252
 
246
253
  Hookless MCP agents can call `cogmem_episode_append` or bounded `cogmem_episode_import`. Existing OpenClaw/Hermes import commands use stable content identities and the same episode schema. Low-confidence imported groups soft-seal for review unless an operator explicitly forces sealing. Episode semantic summaries and closure receipts are control hints, never durable evidence; every Dream candidate must cite a non-empty subset of the episode's raw event IDs and still pass CPU governance.
247
254
 
@@ -337,7 +344,7 @@ cogmem strategy plan --project hermes --query "我当时的原话是什么?" -
337
344
  cogmem strategy outcomes --project hermes --json
338
345
  ```
339
346
 
340
- OpenClaw plugin 0.6.2 skips Cogmem entirely for greetings, uses only session state/turn bridge for short continuations, and applies Strategy Cortex before full recall. Navigation turns use one bridge/kernel lifecycle for Atlas exploration, evidence-bearing node/timeline drill-down, and recall. The bounded volatile `<COGMEM_MEMORY_ATLAS>` block includes evidence event IDs and drill-down commands; OpenClaw does not need MCP for this path.
347
+ OpenClaw plugin 0.6.3 skips Cogmem entirely for greetings, uses only session state/turn bridge for short continuations, and applies Strategy Cortex before full recall. Navigation turns use one bridge/kernel lifecycle for Atlas exploration, evidence-bearing node/timeline drill-down, and recall. The bounded volatile `<COGMEM_MEMORY_ATLAS>` block includes evidence event IDs and drill-down commands; OpenClaw does not need MCP for this path.
341
348
 
342
349
  `ProspectiveMemoryService` stores future intentions, commitments, reminders, open loops, and plans as candidates only. A candidate is not actionable until an explicit user event confirms it. Rejected candidates stay suppressed unless genuinely new evidence creates a new version. The service and `cogmem prospective` CLI manage state only; they expose no task or tool execution capability.
343
350
 
@@ -732,7 +739,15 @@ npm pack --dry-run --json
732
739
  npm publish --dry-run --access public
733
740
  ```
734
741
 
735
- Publish with `npm publish --access public` after the dry run and full tests pass. Keep GitHub branches/releases in sync so old GitHub-installed 3.6.1 users have a discoverable bridge to the npm-first 3.6.2 updater.
742
+ Create a GitHub Release from the matching version tag, for example `v3.6.3`. The `.github/workflows/publish.yml` workflow publishes to npm only when the release is published, not when a tag is pushed. The npm Trusted Publisher entry must match repository `liuqin164/cogmem`, workflow file `publish.yml`, and environment `npm publish`.
743
+
744
+ Publish manually only for emergency fallback:
745
+
746
+ ```bash
747
+ npm publish --provenance --access public
748
+ ```
749
+
750
+ Keep GitHub branches/releases in sync so old GitHub-installed users have a discoverable bridge to the npm-first updater.
736
751
 
737
752
  ## Security and Privacy
738
753
 
@@ -1,11 +1,11 @@
1
- # cogmem 3.6.2 Release Checklist
1
+ # cogmem 3.6.3 Release Checklist
2
2
 
3
3
  This release is distributed through the npm registry. GitHub remains the source and review mirror.
4
4
 
5
5
  ## Required Metadata
6
6
 
7
7
  - `package.json` name is `cogmem`.
8
- - `package.json` version is `3.6.2`.
8
+ - `package.json` version is `3.6.3`.
9
9
  - `package.json` has `publishConfig.access = public`.
10
10
  - Public export `.` points to `dist/public.js` and `dist/public.d.ts`.
11
11
  - Internal subpath `./internal` exists only as an explicit advanced subpath.
@@ -85,8 +85,10 @@ npm publish --dry-run --access public
85
85
 
86
86
  The pack dry-run must include built public API files, CLI files, examples, docs, and `install.sh`. It must not include local databases or machine-specific files.
87
87
 
88
- After verification, publish with:
88
+ After verification, create a GitHub Release from the matching version tag, for example `v3.6.3`. The release workflow publishes through npm Trusted Publishing when the release is published. It must not publish on tag push alone.
89
+
90
+ Emergency manual fallback:
89
91
 
90
92
  ```bash
91
- npm publish --access public
93
+ npm publish --provenance --access public
92
94
  ```
@@ -62,11 +62,13 @@ async function main() {
62
62
  const args = parseArgs(process.argv.slice(2));
63
63
  const dbPath = resolveDbPath(args);
64
64
  const shouldBackup = !args.dryRun && args.backup && dbPath !== ':memory:' && existsSync(dbPath);
65
- const db = new Database(dbPath);
65
+ const db = new Database(dbPath, args.dryRun && dbPath !== ':memory:' ? { readonly: true, create: false } : undefined);
66
66
  db.exec('PRAGMA busy_timeout = 5000;');
67
+ if (args.dryRun)
68
+ db.exec('PRAGMA query_only = ON;');
67
69
  try {
68
70
  const backupPath = shouldBackup ? backupDatabase(db, dbPath) : undefined;
69
- const runner = new SchemaMigrationRunner(db, ALL_MIGRATIONS);
71
+ const runner = new SchemaMigrationRunner(db, ALL_MIGRATIONS, { readonly: args.dryRun });
70
72
  const result = runner.run({ dryRun: args.dryRun });
71
73
  if (!args.dryRun) {
72
74
  db.exec(`CREATE TABLE IF NOT EXISTS _meta (key TEXT PRIMARY KEY, value TEXT NOT NULL);`);
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bun
2
- import { existsSync, readFileSync } from 'node:fs';
3
- import { join, resolve } from 'node:path';
2
+ import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
3
+ import { dirname, join, resolve } from 'node:path';
4
4
  import { defaultOpenClawAutoMemoryPluginDir, inspectOpenClawAutoMemoryPlugin, } from '../host/openclaw/AutoMemoryPluginInstaller.js';
5
5
  function readArg(name) {
6
6
  const index = process.argv.indexOf(name);
@@ -42,6 +42,54 @@ function readAudit(workspaceRoot) {
42
42
  recentErrors: records.filter((record) => record.action === 'error').slice(-20),
43
43
  };
44
44
  }
45
+ function countJsonlLines(path) {
46
+ if (!existsSync(path))
47
+ return 0;
48
+ return readFileSync(path, 'utf8').split('\n').map((line) => line.trim()).filter(Boolean).length;
49
+ }
50
+ function readLock(path) {
51
+ if (!existsSync(path))
52
+ return undefined;
53
+ const ownerPath = join(path, 'owner.json');
54
+ let owner;
55
+ if (existsSync(ownerPath)) {
56
+ try {
57
+ owner = JSON.parse(readFileSync(ownerPath, 'utf8'));
58
+ }
59
+ catch {
60
+ owner = { parseError: true };
61
+ }
62
+ }
63
+ const stat = statSync(path);
64
+ return {
65
+ path,
66
+ mtimeMs: stat.mtimeMs,
67
+ ageMs: Date.now() - stat.mtimeMs,
68
+ owner,
69
+ };
70
+ }
71
+ function inspectQueue(workspaceRoot) {
72
+ const queuePath = join(workspaceRoot, '.cogmem', 'queue', 'openclaw-remember.jsonl');
73
+ const queueDir = dirname(queuePath);
74
+ const processingFiles = existsSync(queueDir)
75
+ ? readdirSync(queueDir)
76
+ .filter((entry) => entry.startsWith('openclaw-remember.jsonl.') && entry.endsWith('.processing'))
77
+ .map((entry) => {
78
+ const path = join(queueDir, entry);
79
+ const stat = statSync(path);
80
+ return { path, lines: countJsonlLines(path), mtimeMs: stat.mtimeMs, ageMs: Date.now() - stat.mtimeMs };
81
+ })
82
+ : [];
83
+ return {
84
+ queuePath,
85
+ pendingLines: countJsonlLines(queuePath),
86
+ deadPath: `${queuePath}.dead.jsonl`,
87
+ deadLines: countJsonlLines(`${queuePath}.dead.jsonl`),
88
+ lock: readLock(`${queuePath}.lock`),
89
+ spawnLock: readLock(`${queuePath}.spawn.lock`),
90
+ processingFiles,
91
+ };
92
+ }
45
93
  function main() {
46
94
  const [command] = process.argv.slice(2).filter((arg) => !arg.startsWith('--'));
47
95
  if (command !== 'diagnose' || hasFlag('--help') || hasFlag('-h')) {
@@ -55,12 +103,14 @@ function main() {
55
103
  const pluginDir = readArg('--plugin-dir') || defaultOpenClawAutoMemoryPluginDir(workspaceRoot);
56
104
  const plugin = inspectOpenClawAutoMemoryPlugin({ workspaceRoot, pluginDir });
57
105
  const audit = readAudit(workspaceRoot);
106
+ const queue = inspectQueue(workspaceRoot);
58
107
  const payload = {
59
108
  schemaVersion: 'cogmem.cli.v1',
60
109
  command: 'openclaw diagnose',
61
110
  workspaceRoot,
62
111
  plugin,
63
112
  audit,
113
+ queue,
64
114
  };
65
115
  if (hasFlag('--json')) {
66
116
  console.log(JSON.stringify(payload));
@@ -74,5 +124,6 @@ function main() {
74
124
  else {
75
125
  console.log('last before_prompt_build: none');
76
126
  }
127
+ console.log(`queue: pending=${queue.pendingLines} dead=${queue.deadLines} processing=${Array.isArray(queue.processingFiles) ? queue.processingFiles.length : 0}`);
77
128
  }
78
129
  main();
@@ -1,7 +1,8 @@
1
1
  #!/usr/bin/env bun
2
2
  import { existsSync, readFileSync } from 'node:fs';
3
3
  import { homedir } from 'node:os';
4
- import { join } from 'node:path';
4
+ import { dirname, join, resolve, sep } from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
5
6
  import { loadCogmemConfig, resolveCogmemConfigPath } from '../config/CogmemConfig.js';
6
7
  import { printCliJson } from './CliJson.js';
7
8
  import { DEFAULT_NPM_PACKAGE, resolveLatestNpmSpec } from './update-release.js';
@@ -29,6 +30,8 @@ function readArgs(argv) {
29
30
  json: values.json === true,
30
31
  from: typeof values.from === 'string' ? values.from : 'latest',
31
32
  installHome: typeof values['install-home'] === 'string' ? values['install-home'] : undefined,
33
+ global: values.global === true,
34
+ localDev: values['local-dev'] === true,
32
35
  manager,
33
36
  configPath: typeof values.config === 'string' ? values.config : undefined,
34
37
  skipMigrate: values['skip-migrate'] === true,
@@ -42,7 +45,10 @@ function detectManager(cwd) {
42
45
  return 'pnpm';
43
46
  return 'npm';
44
47
  }
45
- function buildCommand(manager, spec) {
48
+ function buildCommand(target, spec) {
49
+ if (target.kind === 'npm_global')
50
+ return ['npm', 'install', '-g', `cogmem@${spec}`];
51
+ const manager = target.manager;
46
52
  if (manager === 'bun')
47
53
  return ['bun', 'add', `cogmem@${spec}`];
48
54
  if (manager === 'pnpm')
@@ -52,18 +58,18 @@ function buildCommand(manager, spec) {
52
58
  function localCogmemBin(cwd) {
53
59
  return join(cwd, 'node_modules', '.bin', 'cogmem');
54
60
  }
55
- function buildMigrationExec(targetCwd, configPath) {
61
+ function buildMigrationExecForTarget(target, configPath) {
56
62
  return [
57
- localCogmemBin(targetCwd),
63
+ target.bin,
58
64
  'migrate',
59
65
  '--yes',
60
66
  '--backup',
61
67
  ...(configPath ? ['--config', configPath] : []),
62
68
  ];
63
69
  }
64
- function buildOpenClawRepairExec(targetCwd, configPath, workspaceRoot) {
70
+ function buildOpenClawRepairExecForTarget(target, configPath, workspaceRoot) {
65
71
  return [
66
- localCogmemBin(targetCwd),
72
+ target.bin,
67
73
  'doctor',
68
74
  '--fix',
69
75
  '--agent',
@@ -99,16 +105,57 @@ function shouldUpdateCwd(cwd) {
99
105
  const manifest = readPackageManifest(cwd);
100
106
  return manifest?.name === 'cogmem' || installedSpec(cwd) !== undefined;
101
107
  }
102
- function resolveUpdateCwd(args, env) {
108
+ function isCogmemSourceCheckout(cwd) {
109
+ const manifest = readPackageManifest(cwd);
110
+ return manifest?.name === 'cogmem'
111
+ && existsSync(join(cwd, 'src', 'bin', 'update.ts'))
112
+ && existsSync(join(cwd, '.git'));
113
+ }
114
+ function ownPackageRoot() {
115
+ return resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
116
+ }
117
+ function isLikelyNpmGlobalInstall(env) {
118
+ if (env.COGMEM_INSTALL_KIND === 'npm_global')
119
+ return true;
120
+ const root = ownPackageRoot();
121
+ const marker = `${sep}node_modules${sep}cogmem`;
122
+ if (!root.includes(marker))
123
+ return false;
124
+ const cwd = resolve(process.cwd());
125
+ return !cwd.startsWith(root + sep);
126
+ }
127
+ function resolveUpdateTarget(args, env) {
103
128
  const cwd = process.cwd();
104
- if (args.installHome)
105
- return args.installHome;
106
- if (shouldUpdateCwd(cwd))
107
- return cwd;
129
+ if (args.global || isLikelyNpmGlobalInstall(env)) {
130
+ return { cwd, kind: 'npm_global', manager: 'npm', bin: 'cogmem' };
131
+ }
132
+ if (args.installHome) {
133
+ const targetCwd = args.installHome;
134
+ return { cwd: targetCwd, kind: 'install_home', manager: args.manager || detectManager(targetCwd), bin: localCogmemBin(targetCwd) };
135
+ }
136
+ if (isCogmemSourceCheckout(cwd)) {
137
+ return {
138
+ cwd,
139
+ kind: 'source_checkout',
140
+ manager: args.manager || detectManager(cwd),
141
+ bin: localCogmemBin(cwd),
142
+ warning: args.localDev ? undefined : 'source_checkout_requires_local_dev_for_write',
143
+ };
144
+ }
145
+ if (shouldUpdateCwd(cwd)) {
146
+ return { cwd, kind: 'local_project', manager: args.manager || detectManager(cwd), bin: localCogmemBin(cwd) };
147
+ }
108
148
  const installHome = defaultInstallHome(env);
109
- if (existsSync(join(installHome, 'package.json')))
110
- return installHome;
111
- return cwd;
149
+ if (existsSync(join(installHome, 'package.json'))) {
150
+ return { cwd: installHome, kind: 'install_home', manager: args.manager || detectManager(installHome), bin: localCogmemBin(installHome) };
151
+ }
152
+ return {
153
+ cwd,
154
+ kind: 'cwd_fallback',
155
+ manager: args.manager || detectManager(cwd),
156
+ bin: localCogmemBin(cwd),
157
+ warning: 'no_install_home_or_project_dependency_detected',
158
+ };
112
159
  }
113
160
  function loadConfigForUpdate(args) {
114
161
  const resolution = resolveCogmemConfigPath({ configPath: args.configPath, cwd: process.cwd() });
@@ -136,18 +183,24 @@ async function main() {
136
183
  const resolvedSpec = args.from === 'latest'
137
184
  ? resolveLatestNpmSpec({ env: process.env })
138
185
  : args.from;
139
- const targetCwd = resolveUpdateCwd(args, process.env);
140
- const manager = args.manager || detectManager(targetCwd);
141
- const command = buildCommand(manager, resolvedSpec);
186
+ const target = resolveUpdateTarget(args, process.env);
187
+ if (!args.dryRun && target.kind === 'source_checkout' && !args.localDev) {
188
+ throw new Error('Refusing to update the Cogmem source checkout. Pass --local-dev for an intentional development update, --global for npm global, or --install-home <dir> for the one-line installer home.');
189
+ }
190
+ if (!args.dryRun && target.kind === 'cwd_fallback') {
191
+ throw new Error('Unable to find an installed Cogmem package to update. Pass --global for npm global installs or --install-home <dir> for the one-line installer home.');
192
+ }
193
+ const manager = target.manager;
194
+ const command = buildCommand(target, resolvedSpec);
142
195
  const config = loadConfigForUpdate(args);
143
196
  const migrationExec = !args.skipMigrate && config.configPath
144
- ? buildMigrationExec(targetCwd, config.configPath)
197
+ ? buildMigrationExecForTarget(target, config.configPath)
145
198
  : undefined;
146
199
  const openclawWorkspace = config.loaded?.integrations.openclaw.enabled
147
200
  ? config.loaded.integrations.openclaw.workspaceDir || process.cwd()
148
201
  : undefined;
149
202
  const openclawRepairExec = !args.skipAgentRefresh && openclawWorkspace && config.configPath
150
- ? buildOpenClawRepairExec(targetCwd, config.configPath, openclawWorkspace)
203
+ ? buildOpenClawRepairExecForTarget(target, config.configPath, openclawWorkspace)
151
204
  : undefined;
152
205
  const restartRequired = [
153
206
  ...(openclawWorkspace ? ['restart OpenClaw gateway or agent host'] : []),
@@ -157,13 +210,15 @@ async function main() {
157
210
  command: 'update',
158
211
  dryRun: args.dryRun,
159
212
  manager,
213
+ installKind: target.kind,
160
214
  from: args.from,
161
215
  source: 'npm',
162
216
  npmPackage: DEFAULT_NPM_PACKAGE,
163
217
  packageSpec: resolvedSpec,
164
- targetCwd,
165
- currentSpec: installedSpec(targetCwd),
218
+ targetCwd: target.cwd,
219
+ currentSpec: target.kind === 'npm_global' ? 'npm:global' : installedSpec(target.cwd),
166
220
  nextCommand: command.join(' '),
221
+ updateWarning: target.warning,
167
222
  configPath: config.configPath,
168
223
  migrationCommand: migrationExec?.join(' '),
169
224
  migrationSkippedReason: migrationExec ? undefined : (args.skipMigrate ? 'skip_migrate_flag' : config.skippedReason),
@@ -182,6 +237,8 @@ async function main() {
182
237
  else {
183
238
  console.log(`cogmem update ${args.dryRun ? 'dry-run' : 'running'}`);
184
239
  console.log(`target: ${result.targetCwd}`);
240
+ if (result.updateWarning)
241
+ console.log(`warning: ${result.updateWarning}`);
185
242
  console.log(`current: ${result.currentSpec || 'not listed in package.json'}`);
186
243
  console.log(`command: ${result.nextCommand}`);
187
244
  if (result.migrationCommand)
@@ -191,7 +248,7 @@ async function main() {
191
248
  console.log(result.followUp);
192
249
  }
193
250
  if (!args.dryRun) {
194
- const updateExitCode = await runCommand(command, targetCwd);
251
+ const updateExitCode = await runCommand(command, target.cwd);
195
252
  if (updateExitCode !== 0)
196
253
  process.exit(updateExitCode);
197
254
  if (migrationExec) {
package/dist/factory.js CHANGED
@@ -83,7 +83,7 @@ import { SqliteVecStore } from './store/SqliteVecStore.js';
83
83
  import { VectorStore } from './store/VectorStore.js';
84
84
  import { config } from './utils/Config.js';
85
85
  import { KernelRunningError, SnapshotExporter, SnapshotImporter, } from './snapshot/index.js';
86
- const CORE_VERSION = '3.6.1';
86
+ const CORE_VERSION = '3.6.3';
87
87
  const LATEST_SCHEMA_VERSION = 27;
88
88
  export class MemoryKernel {
89
89
  options;
@@ -5,7 +5,7 @@ import { basename, dirname, join, resolve } from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { resolveCogmemConfigPath } from '../../config/CogmemConfig.js';
7
7
  const PLUGIN_ID = 'cogmem-auto-memory';
8
- const PLUGIN_VERSION = '0.6.2';
8
+ const PLUGIN_VERSION = '0.6.3';
9
9
  function defaultPublicEntrypoint() {
10
10
  return join(resolve(dirname(fileURLToPath(import.meta.url)), '../..'), 'public.js');
11
11
  }
@@ -735,6 +735,7 @@ function bridgeConfig(config) {
735
735
  rememberQueuePath: rememberQueuePath(config),
736
736
  rememberMaxAttempts: config.rememberMaxAttempts || 3,
737
737
  rememberDrainBatchSize: config.rememberDrainBatchSize || 20,
738
+ rememberDrainTimeoutMs: config.rememberDrainTimeoutMs || 60000,
738
739
  };
739
740
  }
740
741
 
@@ -988,7 +989,7 @@ function audit(config, record) {
988
989
  const plugin = {
989
990
  id: PLUGIN_ID,
990
991
  name: 'CogMem Auto Memory',
991
- version: '0.6.2',
992
+ version: '0.6.3',
992
993
  register(api) {
993
994
  if (!api || typeof api.on !== 'function') {
994
995
  throw new Error('OpenClaw plugin API missing api.on');
@@ -1231,7 +1232,7 @@ module.exports.__testing = {
1231
1232
  }
1232
1233
  function pluginBridgeMjs() {
1233
1234
  return String.raw `#!/usr/bin/env bun
1234
- import { appendFileSync, existsSync, mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
1235
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
1235
1236
  import { dirname, join } from 'node:path';
1236
1237
  import { pathToFileURL } from 'node:url';
1237
1238
 
@@ -1581,7 +1582,8 @@ function acquireRememberQueueLock(bridgeConfig) {
1581
1582
  if (!queuePath) throw new Error('missing rememberQueuePath');
1582
1583
  mkdirSync(dirname(queuePath), { recursive: true });
1583
1584
  const lockPath = queuePath + '.lock';
1584
- if (!existsSync(queuePath)) return { acquired: false, locked: false, empty: true, lockPath };
1585
+ const recoveredProcessing = recoverStaleProcessingFiles(bridgeConfig);
1586
+ if (!existsSync(queuePath)) return { acquired: false, locked: false, empty: true, lockPath, recoveredProcessing };
1585
1587
  const timeoutMs = Number(bridgeConfig.rememberDrainTimeoutMs || 60000);
1586
1588
  try {
1587
1589
  mkdirSync(lockPath);
@@ -1602,12 +1604,12 @@ function acquireRememberQueueLock(bridgeConfig) {
1602
1604
  staleLockRecovered: true,
1603
1605
  queuePath,
1604
1606
  }) + '\n');
1605
- return { acquired: true, locked: false, empty: false, lockPath, staleRecovered: true };
1607
+ return { acquired: true, locked: false, empty: false, lockPath, staleRecovered: true, recoveredProcessing };
1606
1608
  }
1607
1609
  } catch {}
1608
1610
  return { acquired: false, locked: true, empty: false, lockPath };
1609
1611
  }
1610
- return { acquired: true, locked: false, empty: false, lockPath };
1612
+ return { acquired: true, locked: false, empty: false, lockPath, recoveredProcessing };
1611
1613
  }
1612
1614
 
1613
1615
  async function drainRememberQueueWithLock(bridgeConfig, queueLock, kernel, memory) {
@@ -1655,7 +1657,29 @@ async function drainRememberQueueWithLock(bridgeConfig, queueLock, kernel, memor
1655
1657
  } finally {
1656
1658
  if (queueLock.acquired) rmSync(queueLock.lockPath, { recursive: true, force: true });
1657
1659
  }
1658
- return { drained, failed, deferred, locked: false, staleRecovered: queueLock.staleRecovered === true };
1660
+ return { drained, failed, deferred, locked: false, staleRecovered: queueLock.staleRecovered === true, recoveredProcessing: queueLock.recoveredProcessing || 0 };
1661
+ }
1662
+
1663
+ function recoverStaleProcessingFiles(bridgeConfig) {
1664
+ const queuePath = bridgeConfig.rememberQueuePath;
1665
+ const dir = dirname(queuePath);
1666
+ const prefix = queuePath.split('/').pop() + '.';
1667
+ const timeoutMs = Number(bridgeConfig.rememberDrainTimeoutMs || 60000);
1668
+ let recovered = 0;
1669
+ if (!existsSync(dir)) return recovered;
1670
+ for (const entry of readdirSync(dir)) {
1671
+ if (!entry.startsWith(prefix) || !entry.endsWith('.processing')) continue;
1672
+ const path = join(dir, entry);
1673
+ try {
1674
+ const ageMs = Date.now() - statSync(path).mtimeMs;
1675
+ if (!Number.isFinite(ageMs) || ageMs < timeoutMs) continue;
1676
+ const lines = readFileSync(path, 'utf8').split('\n').map((line) => line.trim()).filter(Boolean);
1677
+ for (const line of lines) appendFileSync(queuePath, line + '\n');
1678
+ rmSync(path, { force: true });
1679
+ recovered += lines.length;
1680
+ } catch {}
1681
+ }
1682
+ return recovered;
1659
1683
  }
1660
1684
 
1661
1685
  function compactRecallItems(items, config) {
@@ -3,6 +3,9 @@ import type { Migration } from '../types/Migration.js';
3
3
  export interface SchemaMigrationRunOptions {
4
4
  dryRun?: boolean;
5
5
  }
6
+ export interface SchemaMigrationRunnerOptions {
7
+ readonly?: boolean;
8
+ }
6
9
  export interface SchemaMigrationResult {
7
10
  pending: string[];
8
11
  applied: string[];
@@ -12,10 +15,15 @@ export interface SchemaMigrationResult {
12
15
  export declare class SchemaMigrationRunner {
13
16
  private readonly db;
14
17
  private readonly migrations;
15
- constructor(db: Database, migrations: Migration[]);
18
+ private readonly options;
19
+ constructor(db: Database, migrations: Migration[], options?: SchemaMigrationRunnerOptions);
16
20
  plan(): Migration[];
17
21
  run(options?: SchemaMigrationRunOptions): SchemaMigrationResult;
18
22
  currentVersion(): string | undefined;
23
+ private appliedVersions;
24
+ private schemaMigrationsTableExists;
25
+ private legacySchemaVersion;
26
+ private legacyCurrentVersion;
19
27
  private adoptLegacyVersion;
20
28
  }
21
29
  //# sourceMappingURL=SchemaMigrationRunner.d.ts.map
@@ -1,9 +1,13 @@
1
1
  export class SchemaMigrationRunner {
2
2
  db;
3
3
  migrations;
4
- constructor(db, migrations) {
4
+ options;
5
+ constructor(db, migrations, options = {}) {
5
6
  this.db = db;
6
7
  this.migrations = migrations;
8
+ this.options = options;
9
+ if (this.options.readonly)
10
+ return;
7
11
  this.db.exec(`
8
12
  CREATE TABLE IF NOT EXISTS _schema_migrations (
9
13
  version TEXT PRIMARY KEY,
@@ -14,7 +18,7 @@ export class SchemaMigrationRunner {
14
18
  this.adoptLegacyVersion();
15
19
  }
16
20
  plan() {
17
- const applied = new Set(this.db.prepare(`SELECT version FROM _schema_migrations`).all().map((row) => row.version));
21
+ const applied = this.appliedVersions();
18
22
  return [...this.migrations]
19
23
  .sort((a, b) => a.version.localeCompare(b.version))
20
24
  .filter((migration) => !applied.has(migration.version));
@@ -39,20 +43,57 @@ export class SchemaMigrationRunner {
39
43
  return { pending: pending.map((item) => item.version), applied, currentVersion: this.currentVersion(), dryRun: false };
40
44
  }
41
45
  currentVersion() {
46
+ const legacyCurrent = this.legacyCurrentVersion();
47
+ if (!this.schemaMigrationsTableExists()) {
48
+ return legacyCurrent;
49
+ }
42
50
  const row = this.db.prepare(`
43
51
  SELECT version FROM _schema_migrations ORDER BY version DESC LIMIT 1
44
52
  `).get();
45
- return row?.version;
53
+ return [row?.version, legacyCurrent].filter((version) => Boolean(version)).sort((a, b) => b.localeCompare(a))[0];
46
54
  }
47
- adoptLegacyVersion() {
55
+ appliedVersions() {
56
+ const applied = new Set();
57
+ const legacyVersion = this.legacySchemaVersion();
58
+ for (const migration of this.migrations) {
59
+ if (legacyVersion !== undefined && Number.parseInt(migration.version, 10) <= legacyVersion) {
60
+ applied.add(migration.version);
61
+ }
62
+ }
63
+ if (!this.schemaMigrationsTableExists()) {
64
+ return applied;
65
+ }
66
+ for (const row of this.db.prepare(`SELECT version FROM _schema_migrations`).all()) {
67
+ applied.add(row.version);
68
+ }
69
+ return applied;
70
+ }
71
+ schemaMigrationsTableExists() {
72
+ return Boolean(this.db.prepare(`
73
+ SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = '_schema_migrations'
74
+ `).get());
75
+ }
76
+ legacySchemaVersion() {
48
77
  const metaExists = this.db.prepare(`
49
78
  SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = '_meta'
50
79
  `).get();
51
80
  if (!metaExists)
52
- return;
81
+ return undefined;
53
82
  const row = this.db.prepare(`SELECT value FROM _meta WHERE key = 'schema_version'`).get();
54
83
  const legacyVersion = Number.parseInt(row?.value || '', 10);
55
- if (!Number.isFinite(legacyVersion))
84
+ return Number.isFinite(legacyVersion) ? legacyVersion : undefined;
85
+ }
86
+ legacyCurrentVersion() {
87
+ const legacyVersion = this.legacySchemaVersion();
88
+ if (legacyVersion === undefined)
89
+ return undefined;
90
+ return [...this.migrations]
91
+ .filter((migration) => Number.parseInt(migration.version, 10) <= legacyVersion)
92
+ .sort((a, b) => b.version.localeCompare(a.version))[0]?.version;
93
+ }
94
+ adoptLegacyVersion() {
95
+ const legacyVersion = this.legacySchemaVersion();
96
+ if (legacyVersion === undefined)
56
97
  return;
57
98
  const insert = this.db.prepare(`
58
99
  INSERT OR IGNORE INTO _schema_migrations (version, description, applied_at)
@@ -21,6 +21,14 @@ cogmem connect hermes --workspace . --auto
21
21
  cogmem connect hermes --workspace .
22
22
  ```
23
23
 
24
+ If Bun is already installed, npm global install is also supported:
25
+
26
+ ```bash
27
+ npm install -g cogmem@latest
28
+ cogmem init --yes --agent hermes
29
+ cogmem connect hermes --workspace . --auto --force
30
+ ```
31
+
24
32
  Hermes integration is currently a skill plus MCP bridge. It does not replace a native Hermes memory provider and it does not patch Hermes runtime internals.
25
33
 
26
34
  ## Local Quantized Embeddings
@@ -89,7 +97,7 @@ Dream stores explicit user clarification as organizational correction evidence r
89
97
 
90
98
  After upgrades, reload MCP. Rerun `cogmem connect hermes --workspace . --auto --force` when MCP wiring, allow-listed tools, or the installed skill bundle changed.
91
99
 
92
- Cogmem 3.6.2 exposes seven read-only/idempotent Memory Atlas query tools plus explicit `cogmem_graph_touch`, and installs from npm by default. Use explore for broad memory inventory/history, search and node for a known concept, path/neighbors for relations, timeline for ordered reconstruction, and normal recall for a direct fact. Query facets combine the user's actual project, time, topic, entity/target, memory-kind, action, and keyword conditions like table filters, so cold memory can be revived without requiring an entity-time-action tuple. Touch only nodes actually used, and follow returned event IDs to raw evidence before quoting exact wording.
100
+ Cogmem 3.6.3 exposes seven read-only/idempotent Memory Atlas query tools plus explicit `cogmem_graph_touch`, and installs from npm by default. Use explore for broad memory inventory/history, search and node for a known concept, path/neighbors for relations, timeline for ordered reconstruction, and normal recall for a direct fact. Query facets combine the user's actual project, time, topic, entity/target, memory-kind, action, and keyword conditions like table filters, so cold memory can be revived without requiring an entity-time-action tuple. Touch only nodes actually used, and follow returned event IDs to raw evidence before quoting exact wording.
93
101
 
94
102
  ## Runtime
95
103
 
@@ -40,6 +40,14 @@ cogmem doctor
40
40
  cogmem connect hermes --workspace . --auto --force
41
41
  ```
42
42
 
43
+ If Bun is already installed and the operator wants npm global installation instead of the one-line installer, use:
44
+
45
+ ```bash
46
+ npm install -g cogmem@latest
47
+ cogmem init --yes --agent hermes
48
+ cogmem connect hermes --workspace . --auto --force
49
+ ```
50
+
43
51
  Use project-local config only when this workspace needs isolation:
44
52
 
45
53
  ```bash
@@ -98,7 +106,7 @@ cogmem update --yes
98
106
  # Manual equivalent: cogmem migrate --yes --backup
99
107
  ```
100
108
 
101
- `cogmem update --yes` installs `cogmem@latest` from npm, runs the newly installed backed-up migration with the resolved config, and then reports that the Hermes MCP server or agent host must be reloaded. Agents should inspect `cogmem update --dry-run --json` or `cogmem migrate --dry-run --json` when an operator wants a preview. Schema migration preserves Raw Ledger events; it updates governed projections and indexes only.
109
+ `cogmem update --yes` installs `cogmem@latest` from npm, runs the newly installed backed-up migration with the resolved config, and then reports that the Hermes MCP server or agent host must be reloaded. For npm global installs, `cogmem update --yes` resolves to `npm install -g cogmem@latest` instead of writing into the current directory. Agents should inspect `cogmem update --dry-run --json` or `cogmem migrate --dry-run --json` when an operator wants a preview. Schema migration preserves Raw Ledger events; dry-run is read-only and updates governed projections and indexes only during apply.
102
110
 
103
111
  Default Hermes memory contract:
104
112
 
@@ -1,4 +1,4 @@
1
- # Cogmem 3.6.2 Operations Reference for Hermes
1
+ # Cogmem 3.6.3 Operations Reference for Hermes
2
2
 
3
3
  Read this file when installing, upgrading, importing, repairing, or operating Cogmem. `SKILL.md` contains the decision rules; this file records the operational commands.
4
4
 
@@ -28,6 +28,14 @@ cogmem doctor
28
28
  cogmem connect hermes --workspace . --auto --force --json
29
29
  ```
30
30
 
31
+ If Bun is already installed and the operator prefers npm global installation:
32
+
33
+ ```bash
34
+ npm install -g cogmem@latest
35
+ cogmem init --yes --agent hermes
36
+ cogmem connect hermes --workspace . --auto --force --json
37
+ ```
38
+
31
39
  Then run `/reload-mcp` inside Hermes. `connect --auto` installs this skill bundle and updates the Hermes MCP allow-list; it does not claim a native `memory.provider` integration.
32
40
 
33
41
  ## Upgrade and migrate
@@ -38,7 +46,7 @@ For normal upgrades, use one command:
38
46
  cogmem update --yes
39
47
  ```
40
48
 
41
- `cogmem update --yes` installs `cogmem@latest` from npm, then runs post-install work through the newly installed local CLI. With a valid config it runs `cogmem migrate --yes --backup --config <config>` and reports that the Hermes MCP server or agent host must be reloaded.
49
+ `cogmem update --yes` installs `cogmem@latest` from npm, then runs post-install work through the newly installed CLI. For npm global installs it uses `npm install -g cogmem@latest`; for the one-line installer it updates `~/.cogmem/pkg`; for a workspace dependency it updates that workspace. With a valid config it runs `cogmem migrate --yes --backup --config <config>` and reports that the Hermes MCP server or agent host must be reloaded.
42
50
 
43
51
  Preview the package and migration plan without writing:
44
52
 
@@ -53,7 +61,7 @@ cogmem doctor
53
61
  cogmem connect hermes --workspace . --auto --force --json
54
62
  ```
55
63
 
56
- The backed-up command upgrades 3.5.2 schema 24, an existing 3.6.0 schema-26 database, or a pre-release schema-25 test database to the 3.6.2 schema-27 state in one run and preserves Raw Ledger evidence. Reload MCP after reconnecting.
64
+ The backed-up command upgrades 3.5.2 schema 24, an existing 3.6.0 schema-26 database, or a pre-release schema-25 test database to the 3.6.3 schema-27 state in one run and preserves Raw Ledger evidence. `--dry-run` is read-only and does not create `_schema_migrations`. Reload MCP after reconnecting.
57
65
 
58
66
  ## Import Hermes memory
59
67
 
@@ -16,6 +16,14 @@ cogmem connect openclaw --workspace .
16
16
  cogmem connect openclaw --workspace . --auto --force
17
17
  ```
18
18
 
19
+ If Bun is already installed, npm global install is also supported:
20
+
21
+ ```bash
22
+ npm install -g cogmem@latest
23
+ cogmem init --yes --agent openclaw --scope project
24
+ cogmem connect openclaw --workspace . --auto --force
25
+ ```
26
+
19
27
  ## Local Quantized Embeddings
20
28
 
21
29
  Imports use the configured kernel embedder. To import existing OpenClaw memory through a local quantized model, configure the kernel before running the import command:
@@ -78,7 +86,7 @@ cogmem memory tick --project openclaw --json
78
86
  cogmem memory bind --project openclaw --json
79
87
  ```
80
88
 
81
- Cogmem 3.6.2 keeps the 3.6.x Memory Atlas and OpenClaw reliability work, then makes npm the default install and update channel. The auto plugin uses one shared bridge/kernel lifecycle for graph exploration, evidence-bearing node/timeline drill-down, and recall, so OpenClaw does not need MCP for broad inventory/history questions. Atlas combines the query's actual project, time, topic, entity/target, memory-kind, action, and keyword conditions like table filters; no fixed entity-time-action tuple is required.
89
+ Cogmem 3.6.3 keeps the 3.6.x Memory Atlas and OpenClaw reliability work, then makes npm the default install and update channel. The auto plugin uses one shared bridge/kernel lifecycle for graph exploration, evidence-bearing node/timeline drill-down, and recall, so OpenClaw does not need MCP for broad inventory/history questions. Atlas combines the query's actual project, time, topic, entity/target, memory-kind, action, and keyword conditions like table filters; no fixed entity-time-action tuple is required.
82
90
 
83
91
  ```bash
84
92
  cogmem memory graph-explore --project openclaw --query "去年与 Hermes 有关的决定" --json
@@ -206,7 +214,7 @@ To make future OpenClaw turns automatically recall and record memory, run:
206
214
  cogmem connect openclaw --workspace . --auto --force
207
215
  ```
208
216
 
209
- `--auto` installs `<workspace>/extensions/cogmem-auto-memory/`, patches OpenClaw `plugins.load.paths`, and enables a local plugin wrapper with `before_prompt_build` and `agent_end` hooks. The wrapper calls `KernelAgentMemoryBackend` through the public `cogmem` API via a Bun bridge; core still does not import OpenClaw. Plugin 0.6.2 uses singleton queue/spawn locks, stale-lock recovery, and bounded remember batches so queued `agent_end` recording does not hold SQLite open longer than necessary.
217
+ `--auto` installs `<workspace>/extensions/cogmem-auto-memory/`, patches OpenClaw `plugins.load.paths`, and enables a local plugin wrapper with `before_prompt_build` and `agent_end` hooks. The wrapper calls `KernelAgentMemoryBackend` through the public `cogmem` API via a Bun bridge; core still does not import OpenClaw. Plugin 0.6.3 uses singleton queue/spawn locks, stale-lock and stale-processing recovery, and bounded remember batches so queued `agent_end` recording does not hold SQLite open longer than necessary.
210
218
 
211
219
  The wrapper does not rewrite OpenClaw's native prompt, tool instructions, skills, or conversation order. It only prepends Cogmem-owned blocks:
212
220
 
@@ -40,6 +40,14 @@ cogmem doctor
40
40
  cogmem connect openclaw --workspace . --auto --force
41
41
  ```
42
42
 
43
+ If Bun is already installed and the operator wants npm global installation instead of the one-line installer, use:
44
+
45
+ ```bash
46
+ npm install -g cogmem@latest
47
+ cogmem init --yes --agent openclaw --scope project
48
+ cogmem connect openclaw --workspace . --auto --force
49
+ ```
50
+
43
51
  This creates project-local kernel config and storage under `.cogmem/`, which is the recommended OpenClaw workspace setup.
44
52
 
45
53
  ```bash
@@ -98,7 +106,7 @@ cogmem update --yes
98
106
  # Manual equivalent: cogmem migrate --yes --backup && cogmem doctor --fix --agent openclaw --workspace . --plugin-only
99
107
  ```
100
108
 
101
- `cogmem update --yes` installs `cogmem@latest` from npm, runs the newly installed backed-up migration with the resolved config, refreshes OpenClaw's generated plugin files when the integration is configured, and then reports that the OpenClaw gateway or agent host must be restarted. Agents should inspect `cogmem update --dry-run --json` or `cogmem migrate --dry-run --json` when an operator wants a preview. Schema migration preserves Raw Ledger events; it updates governed projections and indexes only.
109
+ `cogmem update --yes` installs `cogmem@latest` from npm, runs the newly installed backed-up migration with the resolved config, refreshes OpenClaw's generated plugin files when the integration is configured, and then reports that the OpenClaw gateway or agent host must be restarted. For npm global installs, `cogmem update --yes` resolves to `npm install -g cogmem@latest` instead of writing into the current directory. Agents should inspect `cogmem update --dry-run --json` or `cogmem migrate --dry-run --json` when an operator wants a preview. Schema migration preserves Raw Ledger events; dry-run is read-only and updates governed projections and indexes only during apply.
102
110
 
103
111
  After any 3.5.2 -> 3.6.x OpenClaw upgrade, refresh the generated OpenClaw plugin files. Use the plugin-only path first when OpenClaw is misbehaving, because it does not open the Cogmem database:
104
112
 
@@ -298,7 +306,7 @@ cogmem connect openclaw --workspace . --auto --force
298
306
 
299
307
  `--auto` writes `<workspace>/extensions/cogmem-auto-memory/`, patches `plugins.load.paths`, and enables `hooks.allowPromptInjection=true` and `hooks.allowConversationAccess=true` for the wrapper. The wrapper registers `before_prompt_build` for governed recall and `agent_end` for turn recording, then calls `KernelAgentMemoryBackend` through `cogmem` public API via a Bun bridge. Core does not import OpenClaw.
300
308
 
301
- Queued remember is the default. `agent_end` appends a durable JSONL job under `.cogmem/queue/openclaw-remember.jsonl` and starts a singleton drainer, so Telegram or gateway responses are not blocked by embeddings, SQLite writes, or slow local models. Plugin 0.6.2 acquires the queue lock before opening Cogmem, recovers stale lock directories older than `rememberDrainTimeoutMs`, writes `owner.json` lock metadata, and processes bounded batches controlled by `rememberDrainBatchSize` (default `20`). If a drain fails, the job is retried and then moved to a dead-letter file instead of being silently discarded.
309
+ Queued remember is the default. `agent_end` appends a durable JSONL job under `.cogmem/queue/openclaw-remember.jsonl` and starts a singleton drainer, so Telegram or gateway responses are not blocked by embeddings, SQLite writes, or slow local models. Plugin 0.6.3 acquires the queue lock before opening Cogmem, recovers stale lock directories and stale `.processing` queue files older than `rememberDrainTimeoutMs`, writes `owner.json` lock metadata, and processes bounded batches controlled by `rememberDrainBatchSize` (default `20`). If a drain fails, the job is retried and then moved to a dead-letter file instead of being silently discarded.
302
310
 
303
311
  When automatic memory recording looks stuck, do not delete queue files first. Diagnose the plugin and locks:
304
312
 
@@ -309,6 +317,8 @@ cat .cogmem/queue/openclaw-remember.jsonl.lock/owner.json 2>/dev/null || true
309
317
  cat .cogmem/queue/openclaw-remember.jsonl.spawn.lock/owner.json 2>/dev/null || true
310
318
  ```
311
319
 
320
+ `openclaw diagnose` reports pending queue lines, dead-letter lines, active lock metadata, spawn-lock metadata, and stale `.processing` files. Use that JSON before deleting anything manually.
321
+
312
322
  If `plugin.current=false`, refresh without opening the database:
313
323
 
314
324
  ```bash
@@ -1,4 +1,4 @@
1
- # Cogmem 3.6.2 Operations Reference for OpenClaw
1
+ # Cogmem 3.6.3 Operations Reference for OpenClaw
2
2
 
3
3
  Read this file when installing, upgrading, importing, repairing, or operating Cogmem. `SKILL.md` contains the decision rules; this file is the command reference.
4
4
 
@@ -33,6 +33,14 @@ cogmem doctor
33
33
  cogmem connect openclaw --workspace . --auto --force --json
34
34
  ```
35
35
 
36
+ If Bun is already installed and the operator prefers npm global installation:
37
+
38
+ ```bash
39
+ npm install -g cogmem@latest
40
+ cogmem init --yes --agent openclaw --scope project
41
+ cogmem connect openclaw --workspace . --auto --force --json
42
+ ```
43
+
36
44
  Restart the OpenClaw Gateway after plugin or config changes. `connect --auto` installs the direct OpenClaw hook bridge; OpenClaw does not need MCP for automatic recall, recording, or Atlas navigation.
37
45
 
38
46
  ## Upgrade and migrate
@@ -44,7 +52,7 @@ cogmem update --yes
44
52
  openclaw gateway restart
45
53
  ```
46
54
 
47
- `cogmem update --yes` installs `cogmem@latest` from npm, then runs post-install work through the newly installed local CLI. With a valid config it runs `cogmem migrate --yes --backup --config <config>`. When OpenClaw integration is enabled, it also runs `cogmem doctor --fix --agent openclaw --plugin-only --config <config> --workspace <workspace>` so stale generated plugin files are replaced before restart.
55
+ `cogmem update --yes` installs `cogmem@latest` from npm, then runs post-install work through the newly installed CLI. For npm global installs it uses `npm install -g cogmem@latest`; for the one-line installer it updates `~/.cogmem/pkg`; for a workspace dependency it updates that workspace. With a valid config it runs `cogmem migrate --yes --backup --config <config>`. When OpenClaw integration is enabled, it also runs `cogmem doctor --fix --agent openclaw --plugin-only --config <config> --workspace <workspace>` so stale generated plugin files are replaced before restart.
48
56
 
49
57
  Preview the package, migration, and plugin-refresh plan without writing:
50
58
 
@@ -62,7 +70,7 @@ openclaw gateway restart
62
70
  cogmem openclaw diagnose --workspace . --json
63
71
  ```
64
72
 
65
- The second command upgrades 3.5.2 schema 24, an existing 3.6.0 schema-26 database, or a pre-release schema-25 test database to the 3.6.2 schema-27 state in one run. It preserves Raw Ledger evidence. Keep the returned `backupPath` until verification passes.
73
+ The second command upgrades 3.5.2 schema 24, an existing 3.6.0 schema-26 database, or a pre-release schema-25 test database to the 3.6.3 schema-27 state in one run. It preserves Raw Ledger evidence. Keep the returned `backupPath` until verification passes. `--dry-run` is read-only and does not create `_schema_migrations`.
66
74
 
67
75
  After upgrading the package/database, refresh OpenClaw's generated plugin files. `doctor --plugin-only` avoids opening the Cogmem kernel, so it can repair stale `extensions/cogmem-auto-memory/index.js` and `bridge.mjs` even when an old drainer has SQLite busy. Use `connect --auto --force` when intentionally reinstalling the full integration and patching OpenClaw config:
68
76
 
@@ -75,15 +83,16 @@ Use `cogmem openclaw diagnose --workspace . --json` when automatic memory blocks
75
83
  - `plugin.current=false`: generated files are stale; run plugin-only fix and restart gateway.
76
84
  - no `audit.lastBeforePromptBuild`: plugin is not loaded or the hook did not fire.
77
85
  - `audit.lastBeforePromptBuild.action=error`: bridge or DB failure; inspect `reason`, `bridgeCommand`, and `dbLocked`.
78
- - `action=inject` but no visible block: inspect `returnedInjectionShape`. Plugin 0.6.2 returns `prependContext`, `context`, and `promptPrefix`; if OpenClaw still ignores all three, the host hook contract changed and the OpenClaw plugin API must be checked before blaming recall.
86
+ - `action=inject` but no visible block: inspect `returnedInjectionShape`. Plugin 0.6.3 returns `prependContext`, `context`, and `promptPrefix`; if OpenClaw still ignores all three, the host hook contract changed and the OpenClaw plugin API must be checked before blaming recall.
79
87
 
80
- Plugin 0.6.2 queue behavior:
88
+ Plugin 0.6.3 queue behavior:
81
89
 
82
90
  - `agent_end` only appends durable JSONL jobs, then starts at most one drainer through queue/spawn locks.
83
91
  - `drain-remember-queue` acquires the queue lock before opening Cogmem or SQLite. A second drainer exits without opening the DB.
84
- - Stale `.cogmem/queue/openclaw-remember.jsonl.lock` and `.spawn.lock` directories older than `rememberDrainTimeoutMs` are recovered automatically and carry `owner.json` metadata for diagnosis.
92
+ - Stale `.cogmem/queue/openclaw-remember.jsonl.lock`, `.spawn.lock`, and `.processing` files older than `rememberDrainTimeoutMs` are recovered automatically and carry enough metadata for diagnosis.
85
93
  - `rememberDrainBatchSize` defaults to `20`, so a busy workspace drains bounded batches and releases DB handles quickly. Lower it temporarily if OpenClaw shares a slow SQLite disk.
86
94
  - Failed jobs retry up to `rememberMaxAttempts`; exhausted jobs move to `.dead.jsonl`.
95
+ - `cogmem openclaw diagnose --workspace . --json` reports pending queue lines, dead-letter lines, lock owners, spawn-lock owners, and `.processing` files.
87
96
 
88
97
  If the queue is not draining, diagnose before deleting files:
89
98
 
package/install.sh CHANGED
@@ -50,6 +50,12 @@ link_cli() {
50
50
  fi
51
51
  done
52
52
  log "Installed CLI: $BIN_DIR/cogmem"
53
+ case ":$PATH:" in
54
+ *":$BIN_DIR:"*) ;;
55
+ *)
56
+ log "Warning: $BIN_DIR is not on PATH. Add it to PATH or run $BIN_DIR/cogmem directly."
57
+ ;;
58
+ esac
53
59
  }
54
60
 
55
61
  main() {
package/package.json CHANGED
@@ -1,10 +1,14 @@
1
1
  {
2
2
  "name": "cogmem",
3
3
 
4
- "version": "3.6.2",
4
+ "version": "3.6.3",
5
5
 
6
6
  "type": "module",
7
7
  "description": "cogmem — agent-native memory kernel for a single local-first AI agent",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/liuqin164/cogmem.git"
11
+ },
8
12
  "main": "./dist/public.js",
9
13
  "types": "./dist/public.d.ts",
10
14
  "exports": {
@@ -46,7 +50,7 @@
46
50
  "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
47
51
  "build": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json",
48
52
  "prepare": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json",
49
- "prepublishOnly": "bun run typecheck && bun test __tests__/release-metadata.unit.test.ts __tests__/update-release.unit.test.ts __tests__/agent-import-cli.unit.test.ts && bun run build",
53
+ "prepublishOnly": "bun run typecheck && bun test __tests__ && bun run build && npm pack --dry-run --json",
50
54
  "type": "tsc -p tsconfig.json --noEmit",
51
55
  "test": "bun test __tests__",
52
56
  "typecheck": "tsc -p tsconfig.json --noEmit"