@psiclawops/hypermem 0.9.3 → 0.9.5

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.
Files changed (69) hide show
  1. package/CHANGELOG.md +27 -2
  2. package/INSTALL.md +75 -68
  3. package/README.md +18 -36
  4. package/assets/default-config.json +41 -0
  5. package/bench/data-access-bench.mjs +1 -1
  6. package/bin/hypermem-doctor.mjs +76 -2
  7. package/bin/hypermem-status.mjs +255 -7
  8. package/dist/adaptive-lifecycle.d.ts +39 -0
  9. package/dist/adaptive-lifecycle.d.ts.map +1 -1
  10. package/dist/adaptive-lifecycle.js +87 -9
  11. package/dist/background-indexer.d.ts.map +1 -1
  12. package/dist/background-indexer.js +16 -14
  13. package/dist/compositor.d.ts.map +1 -1
  14. package/dist/compositor.js +239 -20
  15. package/dist/cross-agent.d.ts +1 -1
  16. package/dist/cross-agent.js +17 -17
  17. package/dist/hybrid-retrieval.d.ts +8 -0
  18. package/dist/hybrid-retrieval.d.ts.map +1 -1
  19. package/dist/hybrid-retrieval.js +112 -10
  20. package/dist/index.d.ts +16 -5
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +19 -4
  23. package/dist/message-store.d.ts +62 -1
  24. package/dist/message-store.d.ts.map +1 -1
  25. package/dist/message-store.js +355 -2
  26. package/dist/open-domain.d.ts.map +1 -1
  27. package/dist/open-domain.js +3 -2
  28. package/dist/proactive-pass.d.ts +42 -2
  29. package/dist/proactive-pass.d.ts.map +1 -1
  30. package/dist/proactive-pass.js +294 -39
  31. package/dist/seed.d.ts +1 -1
  32. package/dist/seed.js +1 -1
  33. package/dist/session-flusher.d.ts +2 -2
  34. package/dist/session-flusher.js +2 -2
  35. package/dist/spawn-context.d.ts +1 -1
  36. package/dist/spawn-context.js +1 -1
  37. package/dist/topic-store.js +5 -5
  38. package/dist/topic-synthesizer.d.ts.map +1 -1
  39. package/dist/topic-synthesizer.js +10 -4
  40. package/dist/trigger-registry.d.ts +1 -1
  41. package/dist/trigger-registry.js +4 -4
  42. package/dist/types.d.ts +101 -2
  43. package/dist/types.d.ts.map +1 -1
  44. package/dist/vector-store.d.ts +10 -1
  45. package/dist/vector-store.d.ts.map +1 -1
  46. package/dist/vector-store.js +45 -9
  47. package/docs/DIAGNOSTICS.md +88 -1
  48. package/docs/INTEGRATION_VALIDATION.md +40 -1
  49. package/docs/MIGRATION.md +1 -1
  50. package/docs/TUNING.md +47 -6
  51. package/install.sh +5 -60
  52. package/memory-plugin/dist/index.js +192 -0
  53. package/memory-plugin/openclaw.plugin.json +199 -2
  54. package/memory-plugin/package.json +2 -2
  55. package/package.json +29 -10
  56. package/plugin/dist/index.d.ts +2 -0
  57. package/plugin/dist/index.d.ts.map +1 -1
  58. package/plugin/dist/index.js +178 -11
  59. package/plugin/dist/index.js.map +1 -1
  60. package/plugin/openclaw.plugin.json +199 -2
  61. package/plugin/package.json +2 -2
  62. package/scripts/install-packed-runtime.mjs +99 -0
  63. package/scripts/install-runtime.mjs +164 -4
  64. package/ARCHITECTURE.md +0 -298
  65. package/docs/KNOWN_LIMITATIONS.md +0 -35
  66. package/docs/PHASE1-VALIDATION.md +0 -132
  67. package/docs/RELEASE_0.8.0_VALIDATION.md +0 -70
  68. package/docs/RELEASE_PROCESS.md +0 -10
  69. package/docs/ROADMAP.md +0 -266
@@ -3,11 +3,208 @@
3
3
  "enabledByDefault": false,
4
4
  "kind": "context-engine",
5
5
  "activation": {
6
- "onCapabilities": ["context-engine"]
6
+ "onCapabilities": [
7
+ "context-engine"
8
+ ]
7
9
  },
8
10
  "configSchema": {
9
11
  "type": "object",
10
12
  "additionalProperties": false,
11
- "properties": {}
13
+ "properties": {
14
+ "hyperMemPath": {
15
+ "type": "string"
16
+ },
17
+ "dataDir": {
18
+ "type": "string"
19
+ },
20
+ "contextWindowSize": {
21
+ "type": "integer",
22
+ "minimum": 1
23
+ },
24
+ "contextWindowReserve": {
25
+ "type": "number",
26
+ "minimum": 0,
27
+ "maximum": 0.5
28
+ },
29
+ "deferToolPruning": {
30
+ "type": "boolean"
31
+ },
32
+ "verboseLogging": {
33
+ "type": "boolean"
34
+ },
35
+ "warmCacheReplayThresholdMs": {
36
+ "type": "integer",
37
+ "minimum": 0
38
+ },
39
+ "subagentWarming": {
40
+ "type": "string",
41
+ "enum": [
42
+ "full",
43
+ "light",
44
+ "off"
45
+ ]
46
+ },
47
+ "contextWindowOverrides": {
48
+ "type": "object",
49
+ "additionalProperties": {
50
+ "type": "object",
51
+ "additionalProperties": false,
52
+ "properties": {
53
+ "contextTokens": {
54
+ "type": "integer",
55
+ "minimum": 1
56
+ },
57
+ "contextWindow": {
58
+ "type": "integer",
59
+ "minimum": 1
60
+ }
61
+ }
62
+ }
63
+ },
64
+ "compositor": {
65
+ "type": "object",
66
+ "additionalProperties": true
67
+ },
68
+ "eviction": {
69
+ "type": "object",
70
+ "additionalProperties": false,
71
+ "properties": {
72
+ "enabled": {
73
+ "type": "boolean"
74
+ },
75
+ "imageAgeTurns": {
76
+ "type": "integer",
77
+ "minimum": 0
78
+ },
79
+ "toolResultAgeTurns": {
80
+ "type": "integer",
81
+ "minimum": 0
82
+ },
83
+ "minTokensToEvict": {
84
+ "type": "integer",
85
+ "minimum": 0
86
+ },
87
+ "keepPreviewChars": {
88
+ "type": "integer",
89
+ "minimum": 0
90
+ }
91
+ }
92
+ },
93
+ "embedding": {
94
+ "type": "object",
95
+ "additionalProperties": false,
96
+ "properties": {
97
+ "provider": {
98
+ "type": "string",
99
+ "enum": [
100
+ "none",
101
+ "ollama",
102
+ "openai",
103
+ "gemini"
104
+ ]
105
+ },
106
+ "ollamaUrl": {
107
+ "type": "string"
108
+ },
109
+ "openaiApiKey": {
110
+ "type": "string"
111
+ },
112
+ "openaiBaseUrl": {
113
+ "type": "string"
114
+ },
115
+ "geminiApiKey": {
116
+ "type": "string"
117
+ },
118
+ "geminiBaseUrl": {
119
+ "type": "string"
120
+ },
121
+ "geminiIndexTaskType": {
122
+ "type": "string"
123
+ },
124
+ "geminiQueryTaskType": {
125
+ "type": "string"
126
+ },
127
+ "queryInputType": {
128
+ "type": "string"
129
+ },
130
+ "documentInputType": {
131
+ "type": "string"
132
+ },
133
+ "queryPrefix": {
134
+ "type": "string"
135
+ },
136
+ "documentPrefix": {
137
+ "type": "string"
138
+ },
139
+ "model": {
140
+ "type": "string"
141
+ },
142
+ "dimensions": {
143
+ "type": "integer",
144
+ "minimum": 1
145
+ },
146
+ "timeout": {
147
+ "type": "integer",
148
+ "minimum": 1
149
+ },
150
+ "batchSize": {
151
+ "type": "integer",
152
+ "minimum": 1
153
+ }
154
+ }
155
+ },
156
+ "reranker": {
157
+ "type": "object",
158
+ "additionalProperties": false,
159
+ "required": [
160
+ "provider"
161
+ ],
162
+ "properties": {
163
+ "provider": {
164
+ "type": "string",
165
+ "enum": [
166
+ "zeroentropy",
167
+ "openrouter",
168
+ "local",
169
+ "none"
170
+ ]
171
+ },
172
+ "minCandidates": {
173
+ "type": "integer",
174
+ "minimum": 0
175
+ },
176
+ "maxDocuments": {
177
+ "type": "integer",
178
+ "minimum": 1
179
+ },
180
+ "topK": {
181
+ "type": "integer",
182
+ "minimum": 1
183
+ },
184
+ "timeoutMs": {
185
+ "type": "integer",
186
+ "minimum": 1
187
+ },
188
+ "zeroEntropyApiKey": {
189
+ "type": "string"
190
+ },
191
+ "zeroEntropyModel": {
192
+ "type": "string"
193
+ },
194
+ "openrouterApiKey": {
195
+ "type": "string"
196
+ },
197
+ "openrouterModel": {
198
+ "type": "string"
199
+ },
200
+ "ollamaUrl": {
201
+ "type": "string"
202
+ },
203
+ "ollamaModel": {
204
+ "type": "string"
205
+ }
206
+ }
207
+ }
208
+ }
12
209
  }
13
210
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@psiclawops/hypercompositor",
3
- "version": "0.9.3",
3
+ "version": "0.9.5",
4
4
  "description": "HyperCompositor \u2014 context engine plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -40,7 +40,7 @@
40
40
  "typecheck": "tsc --noEmit"
41
41
  },
42
42
  "dependencies": {
43
- "@psiclawops/hypermem": "0.9.2",
43
+ "@psiclawops/hypermem": "0.9.5",
44
44
  "zod": "^4.0.0"
45
45
  },
46
46
  "devDependencies": {
@@ -0,0 +1,99 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { cpSync, existsSync, mkdtempSync, rmSync, statSync } from 'node:fs';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { execFileSync } from 'node:child_process';
8
+
9
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
10
+ const repoRoot = path.resolve(__dirname, '..');
11
+
12
+ const argv = process.argv.slice(2);
13
+ let installRoot = path.join(os.homedir(), '.openclaw/plugins/hypermem');
14
+ let inputTarball = null;
15
+
16
+ for (let i = 0; i < argv.length; i += 1) {
17
+ const arg = argv[i];
18
+ if (arg === '--install-root' && argv[i + 1]) {
19
+ installRoot = path.resolve(argv[++i]);
20
+ } else if (arg === '--tarball' && argv[i + 1]) {
21
+ inputTarball = path.resolve(argv[++i]);
22
+ } else if (arg.endsWith('.tgz')) {
23
+ inputTarball = path.resolve(arg);
24
+ } else if (!arg.startsWith('--')) {
25
+ installRoot = path.resolve(arg);
26
+ }
27
+ }
28
+
29
+ function run(command, args, options = {}) {
30
+ return execFileSync(command, args, {
31
+ cwd: options.cwd ?? repoRoot,
32
+ stdio: options.stdio ?? 'pipe',
33
+ encoding: options.encoding ?? 'utf8',
34
+ env: process.env,
35
+ });
36
+ }
37
+
38
+ function safeRemove(filePath) {
39
+ try {
40
+ if (existsSync(filePath) && statSync(filePath).isFile()) rmSync(filePath, { force: true });
41
+ } catch {
42
+ // Best-effort cleanup only. Never delete directories here.
43
+ }
44
+ }
45
+
46
+ const stamp = new Date().toISOString().replace(/[-:]/g, '').replace(/\.\d{3}Z$/, 'Z');
47
+ const tempRoot = mkdtempSync(path.join(os.tmpdir(), 'hypermem-packed-runtime-'));
48
+ const tempApp = path.join(tempRoot, 'app');
49
+ let tarballPath = inputTarball;
50
+ let createdTarball = false;
51
+
52
+ try {
53
+ if (!tarballPath) {
54
+ console.log('Packing HyperMem via npm pack...');
55
+ const packOutput = run('npm', ['pack', '--silent']).trim();
56
+ const tarballName = packOutput.split('\n').filter(Boolean).pop();
57
+ if (!tarballName) throw new Error('npm pack did not return a tarball name');
58
+ tarballPath = path.join(repoRoot, tarballName);
59
+ createdTarball = true;
60
+ } else if (!existsSync(tarballPath) || !statSync(tarballPath).isFile()) {
61
+ throw new Error(`Tarball not found or not a file: ${tarballPath}`);
62
+ }
63
+
64
+ console.log(`Installing packed artifact into temp app: ${tempApp}`);
65
+ run('npm', ['--prefix', tempApp, 'init', '-y'], { stdio: 'ignore' });
66
+ run('npm', ['--prefix', tempApp, 'install', '--no-audit', '--no-fund', tarballPath], {
67
+ stdio: 'inherit',
68
+ });
69
+
70
+ const backupPath = `${installRoot}.backup.${stamp}`;
71
+ if (existsSync(installRoot)) {
72
+ console.log(`Backing up current runtime: ${backupPath}`);
73
+ cpSync(installRoot, backupPath, { recursive: true, force: false, errorOnExist: true });
74
+ }
75
+
76
+ const installer = path.join(
77
+ tempApp,
78
+ 'node_modules',
79
+ '@psiclawops',
80
+ 'hypermem',
81
+ 'scripts',
82
+ 'install-runtime.mjs',
83
+ );
84
+ console.log(`Installing packed runtime to: ${installRoot}`);
85
+ run(process.execPath, [installer, installRoot], { stdio: 'inherit' });
86
+
87
+ const pkg = JSON.parse(
88
+ run(process.execPath, [
89
+ '-e',
90
+ `console.log(require('fs').readFileSync(${JSON.stringify(path.join(installRoot, 'package.json'))}, 'utf8'))`,
91
+ ]),
92
+ );
93
+ console.log(`Installed ${pkg.name}@${pkg.version} from packed artifact.`);
94
+ console.log(`Runtime path: ${installRoot}`);
95
+ console.log('Restart OpenClaw gateway before validating runtime behavior.');
96
+ } finally {
97
+ if (createdTarball && tarballPath) safeRemove(tarballPath);
98
+ rmSync(tempRoot, { recursive: true, force: true });
99
+ }
@@ -1,23 +1,99 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { cpSync, existsSync, mkdirSync, readdirSync, rmSync, symlinkSync } from 'node:fs';
3
+ import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
4
4
  import os from 'node:os';
5
5
  import path from 'node:path';
6
6
  import { fileURLToPath } from 'node:url';
7
7
 
8
8
  const __dirname = fileURLToPath(new URL('.', import.meta.url));
9
9
  const REPO_ROOT = path.resolve(__dirname, '..');
10
- const installRoot = process.argv[2]
11
- ? path.resolve(process.argv[2])
10
+
11
+ function usage() {
12
+ console.log(`
13
+ hypermem-install — stage the HyperMem runtime for OpenClaw
14
+
15
+ Usage:
16
+ hypermem-install [install-root] [options]
17
+ hypermem-install --install-root <path> [options]
18
+
19
+ Options:
20
+ --install-root <path> Runtime install directory
21
+ default: ~/.openclaw/plugins/hypermem
22
+ --skip-embedding-check Do not require the configured embedding provider
23
+ to be reachable during install
24
+ --skip-openclaw-config Do not attempt OpenClaw config writes. Current
25
+ installer is read-only for OpenClaw config, so
26
+ this is accepted for CI/container scripts.
27
+ -h, --help Show this help
28
+ `);
29
+ }
30
+
31
+ function parseArgs(argv) {
32
+ const options = {
33
+ installRoot: null,
34
+ skipEmbeddingCheck: false,
35
+ skipOpenClawConfig: false,
36
+ help: false,
37
+ };
38
+
39
+ for (let i = 0; i < argv.length; i += 1) {
40
+ const arg = argv[i];
41
+ if (arg === '-h' || arg === '--help') {
42
+ options.help = true;
43
+ } else if (arg === '--install-root') {
44
+ const value = argv[i + 1];
45
+ if (!value || value.startsWith('--')) {
46
+ throw new Error('--install-root requires a path');
47
+ }
48
+ options.installRoot = value;
49
+ i += 1;
50
+ } else if (arg === '--skip-embedding-check') {
51
+ options.skipEmbeddingCheck = true;
52
+ } else if (arg === '--skip-openclaw-config') {
53
+ options.skipOpenClawConfig = true;
54
+ } else if (arg.startsWith('--')) {
55
+ throw new Error(`Unknown option: ${arg}`);
56
+ } else if (!options.installRoot) {
57
+ options.installRoot = arg;
58
+ } else {
59
+ throw new Error(`Unexpected positional argument: ${arg}`);
60
+ }
61
+ }
62
+
63
+ return options;
64
+ }
65
+
66
+ let options;
67
+ try {
68
+ options = parseArgs(process.argv.slice(2));
69
+ } catch (err) {
70
+ console.error(`hypermem-install: ${err.message}`);
71
+ usage();
72
+ process.exit(2);
73
+ }
74
+
75
+ if (options.help) {
76
+ usage();
77
+ process.exit(0);
78
+ }
79
+
80
+ const installRoot = options.installRoot
81
+ ? path.resolve(options.installRoot)
12
82
  : path.join(os.homedir(), '.openclaw/plugins/hypermem');
83
+ const hypermemConfigPath = path.join(os.homedir(), '.openclaw', 'hypermem', 'config.json');
84
+ const defaultConfigSource = path.join(REPO_ROOT, 'assets', 'default-config.json');
13
85
 
14
86
  const requiredEntries = [
15
87
  ['dist', 'dist'],
16
88
  ['package.json', 'package.json'],
17
89
  ['README.md', 'README.md'],
18
90
  ['LICENSE', 'LICENSE'],
91
+ ['assets/default-config.json', 'assets/default-config.json'],
19
92
  ['bin/hypermem-status.mjs', 'bin/hypermem-status.mjs'],
20
93
  ['bin/hypermem-model-audit.mjs', 'bin/hypermem-model-audit.mjs'],
94
+ ['bin/hypermem-doctor.mjs', 'bin/hypermem-doctor.mjs'],
95
+ ['bin/hypermem-bench.mjs', 'bin/hypermem-bench.mjs'],
96
+ ['bench/data-access-bench.mjs', 'bench/data-access-bench.mjs'],
21
97
  ['plugin/dist', 'plugin/dist'],
22
98
  ['plugin/package.json', 'plugin/package.json'],
23
99
  ['plugin/openclaw.plugin.json', 'plugin/openclaw.plugin.json'],
@@ -57,6 +133,77 @@ const entries = [
57
133
  ...sqliteVecNativeEntries.filter(([srcRel]) => existsSync(path.join(REPO_ROOT, srcRel))),
58
134
  ];
59
135
 
136
+
137
+ function readJson(filePath) {
138
+ return JSON.parse(readFileSync(filePath, 'utf8'));
139
+ }
140
+
141
+ function writeDefaultConfigIfMissing() {
142
+ if (!existsSync(defaultConfigSource)) {
143
+ console.error(`Missing default config artifact: ${defaultConfigSource}`);
144
+ process.exit(1);
145
+ }
146
+ if (existsSync(hypermemConfigPath)) {
147
+ return { path: hypermemConfigPath, created: false, config: readJson(hypermemConfigPath) };
148
+ }
149
+ mkdirSync(path.dirname(hypermemConfigPath), { recursive: true, mode: 0o700 });
150
+ const content = readFileSync(defaultConfigSource, 'utf8');
151
+ writeFileSync(hypermemConfigPath, content.endsWith('\n') ? content : `${content}\n`, { mode: 0o600 });
152
+ return { path: hypermemConfigPath, created: true, config: JSON.parse(content) };
153
+ }
154
+
155
+ async function probeEmbeddingProvider(config) {
156
+ const embedding = config?.embedding ?? {};
157
+ const provider = embedding.provider ?? 'ollama';
158
+ if (provider === 'none') return { ok: true, skipped: true, reason: 'embedding provider disabled' };
159
+ if (provider !== 'ollama') return { ok: true, skipped: true, reason: `embedding provider ${provider} is not probed by installer` };
160
+
161
+ const baseUrl = String(embedding.ollamaUrl ?? 'http://localhost:11434').replace(/\/$/, '');
162
+ const controller = new AbortController();
163
+ const timer = setTimeout(() => controller.abort(), 1500);
164
+ try {
165
+ const res = await fetch(`${baseUrl}/api/tags`, { signal: controller.signal });
166
+ if (!res.ok) return { ok: false, provider, baseUrl, reason: `HTTP ${res.status}` };
167
+ const body = await res.json().catch(() => ({}));
168
+ const model = embedding.model ?? 'nomic-embed-text';
169
+ const models = Array.isArray(body.models) ? body.models : [];
170
+ const hasModel = models.some((entry) => entry?.name === model || entry?.model === model || String(entry?.name ?? '').startsWith(`${model}:`));
171
+ if (!hasModel) {
172
+ return { ok: false, provider, baseUrl, reason: `model ${model} is not installed` };
173
+ }
174
+ return { ok: true, provider, baseUrl, model };
175
+ } catch (err) {
176
+ const detail = err.cause?.code ? `${err.message} (${err.cause.code})` : err.message;
177
+ return { ok: false, provider, baseUrl, reason: err.name === 'AbortError' ? 'probe timed out' : `cannot reach ${baseUrl}: ${detail}` };
178
+ } finally {
179
+ clearTimeout(timer);
180
+ }
181
+ }
182
+
183
+ const configResult = writeDefaultConfigIfMissing();
184
+
185
+ if (!options.skipEmbeddingCheck) {
186
+ const probe = await probeEmbeddingProvider(configResult.config);
187
+ if (!probe.ok) {
188
+ console.error(`
189
+ Embedding provider check failed: ${probe.reason}
190
+
191
+ HyperMem default semantic recall uses Ollama with nomic-embed-text.
192
+ Remediation:
193
+ 1. Install and start Ollama: https://ollama.com/download
194
+ 2. Pull the embedding model: ollama pull nomic-embed-text
195
+ 3. Re-run hypermem-install
196
+
197
+ Advanced/CI override:
198
+ hypermem-install --skip-embedding-check
199
+
200
+ Config checked:
201
+ ${configResult.path}
202
+ `);
203
+ process.exit(3);
204
+ }
205
+ }
206
+
60
207
  rmSync(installRoot, { recursive: true, force: true });
61
208
  mkdirSync(installRoot, { recursive: true });
62
209
 
@@ -75,7 +222,17 @@ symlinkSync(openclawInstallPath, path.join(installRoot, 'memory-plugin/node_modu
75
222
  symlinkSync('../../..', path.join(installRoot, 'plugin/node_modules/@psiclawops/hypermem'));
76
223
  symlinkSync('../../..', path.join(installRoot, 'memory-plugin/node_modules/@psiclawops/hypermem'));
77
224
 
78
- console.log(`\n Runtime installed to:\n ${installRoot}\n`);
225
+ console.log(`
226
+ Runtime installed to:
227
+ ${installRoot}
228
+ `);
229
+ console.log(` HyperMem config:
230
+ ${configResult.path} ${configResult.created ? '(created)' : '(already existed, unchanged)'}
231
+ `);
232
+ if (options.skipEmbeddingCheck) {
233
+ console.log(` Embedding provider check skipped by --skip-embedding-check.
234
+ `);
235
+ }
79
236
  console.log(` Next steps — wire the plugins into OpenClaw:\n`);
80
237
  console.log(` openclaw config set plugins.load.paths '["${installRoot}/plugin","${installRoot}/memory-plugin"]' --strict-json`);
81
238
  console.log(` openclaw config set plugins.slots.contextEngine hypercompositor`);
@@ -85,7 +242,10 @@ console.log(` openclaw config get plugins.allow`);
85
242
  console.log(` # Example merge (if "my-plugin" was already allowed):`);
86
243
  console.log(` # openclaw config set plugins.allow '["my-plugin","hypercompositor","hypermem"]' --strict-json`);
87
244
  console.log(` # If plugins.allow is empty or unset, skip that step instead of creating a new allowlist.`);
245
+ console.log(` openclaw plugins registry --refresh`);
246
+ console.log(` openclaw doctor --fix --yes`);
88
247
  console.log(` openclaw gateway restart\n`);
89
248
  console.log(` Verify:\n`);
249
+ console.log(` openclaw plugins registry --refresh`);
90
250
  console.log(` openclaw plugins list`);
91
251
  console.log(` node bin/hypermem-status.mjs --health\n`);