@digitalforgestudios/openclaw-sulcus 3.2.1 → 3.3.0
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/bin/configure.mjs +399 -0
- package/hooks.defaults.json +5 -5
- package/package.json +5 -1
- package/wasm/sulcus_wasm.js +7 -2
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Sulcus Configuration Wizard
|
|
4
|
+
* Interactive CLI to configure the openclaw-sulcus plugin in openclaw.json
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* npx @digitalforgestudios/openclaw-sulcus configure
|
|
8
|
+
* node bin/configure.mjs [--no-color] [--help]
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import readline from 'readline';
|
|
12
|
+
import fs from 'fs';
|
|
13
|
+
import path from 'path';
|
|
14
|
+
import os from 'os';
|
|
15
|
+
|
|
16
|
+
// ─── Colour support ───────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
const noColor =
|
|
19
|
+
process.argv.includes('--no-color') ||
|
|
20
|
+
process.env.NO_COLOR !== undefined ||
|
|
21
|
+
!process.stdout.isTTY;
|
|
22
|
+
|
|
23
|
+
const c = {
|
|
24
|
+
reset: noColor ? '' : '\x1b[0m',
|
|
25
|
+
bold: noColor ? '' : '\x1b[1m',
|
|
26
|
+
dim: noColor ? '' : '\x1b[2m',
|
|
27
|
+
red: noColor ? '' : '\x1b[31m',
|
|
28
|
+
green: noColor ? '' : '\x1b[32m',
|
|
29
|
+
yellow: noColor ? '' : '\x1b[33m',
|
|
30
|
+
blue: noColor ? '' : '\x1b[34m',
|
|
31
|
+
magenta: noColor ? '' : '\x1b[35m',
|
|
32
|
+
cyan: noColor ? '' : '\x1b[36m',
|
|
33
|
+
white: noColor ? '' : '\x1b[37m',
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const bold = (s) => `${c.bold}${s}${c.reset}`;
|
|
37
|
+
const dim = (s) => `${c.dim}${s}${c.reset}`;
|
|
38
|
+
const green = (s) => `${c.green}${s}${c.reset}`;
|
|
39
|
+
const yellow = (s) => `${c.yellow}${s}${c.reset}`;
|
|
40
|
+
const red = (s) => `${c.red}${s}${c.reset}`;
|
|
41
|
+
const cyan = (s) => `${c.cyan}${s}${c.reset}`;
|
|
42
|
+
const magenta = (s) => `${c.magenta}${s}${c.reset}`;
|
|
43
|
+
|
|
44
|
+
// ─── Help ─────────────────────────────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
47
|
+
console.log(`
|
|
48
|
+
${bold('Sulcus Configuration Wizard')}
|
|
49
|
+
|
|
50
|
+
Interactively configure the openclaw-sulcus plugin inside your openclaw.json.
|
|
51
|
+
|
|
52
|
+
${bold('Usage:')}
|
|
53
|
+
npx @digitalforgestudios/openclaw-sulcus configure [options]
|
|
54
|
+
node bin/configure.mjs [options]
|
|
55
|
+
|
|
56
|
+
${bold('Options:')}
|
|
57
|
+
--help, -h Show this help message
|
|
58
|
+
--no-color Disable coloured output
|
|
59
|
+
|
|
60
|
+
${bold('What it does:')}
|
|
61
|
+
1. Locates your openclaw.json (checks \$OPENCLAW_CONFIG_PATH, ~/.openclaw/, ./)
|
|
62
|
+
2. Walks you through backend mode, dylib path, namespace, hooks, and tools
|
|
63
|
+
3. Deep-merges settings under plugins.entries.openclaw-sulcus.config
|
|
64
|
+
4. Validates that your native dylibs exist and warns if they are missing
|
|
65
|
+
5. Reminds you to restart the OpenClaw gateway
|
|
66
|
+
|
|
67
|
+
${bold('Example:')}
|
|
68
|
+
npx @digitalforgestudios/openclaw-sulcus configure
|
|
69
|
+
`);
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ─── Readline helpers ─────────────────────────────────────────────────────────
|
|
74
|
+
|
|
75
|
+
const rl = readline.createInterface({
|
|
76
|
+
input: process.stdin,
|
|
77
|
+
output: process.stdout,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Graceful Ctrl+C
|
|
81
|
+
rl.on('SIGINT', () => {
|
|
82
|
+
console.log(`\n\n${yellow('⚡ Wizard cancelled — no changes were written.')}\n`);
|
|
83
|
+
process.exit(0);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Prompt the user with an optional default value.
|
|
88
|
+
* Returns the trimmed answer, or the default if empty.
|
|
89
|
+
*/
|
|
90
|
+
function ask(question, defaultValue = '') {
|
|
91
|
+
return new Promise((resolve) => {
|
|
92
|
+
const hint = defaultValue !== '' ? dim(` [${defaultValue}]`) : '';
|
|
93
|
+
rl.question(`${question}${hint} `, (answer) => {
|
|
94
|
+
const trimmed = answer.trim();
|
|
95
|
+
resolve(trimmed === '' ? defaultValue : trimmed);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Ask a yes/no question. Returns boolean.
|
|
102
|
+
* @param {string} question
|
|
103
|
+
* @param {boolean} defaultVal
|
|
104
|
+
*/
|
|
105
|
+
function askYN(question, defaultVal = false) {
|
|
106
|
+
return new Promise((resolve) => {
|
|
107
|
+
const hint = dim(` [${defaultVal ? 'Y/n' : 'y/N'}]`);
|
|
108
|
+
rl.question(` ${question}${hint} `, (answer) => {
|
|
109
|
+
const a = answer.trim().toLowerCase();
|
|
110
|
+
if (a === '') resolve(defaultVal);
|
|
111
|
+
else resolve(a === 'y' || a === 'yes');
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ─── openclaw.json discovery ──────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
function expandHome(p) {
|
|
119
|
+
if (p.startsWith('~')) return path.join(os.homedir(), p.slice(1));
|
|
120
|
+
return p;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function findOpenclawJson() {
|
|
124
|
+
const candidates = [
|
|
125
|
+
process.env.OPENCLAW_CONFIG_PATH,
|
|
126
|
+
path.join(os.homedir(), '.openclaw', 'openclaw.json'),
|
|
127
|
+
path.join(process.cwd(), 'openclaw.json'),
|
|
128
|
+
].filter(Boolean);
|
|
129
|
+
|
|
130
|
+
for (const candidate of candidates) {
|
|
131
|
+
const resolved = expandHome(candidate);
|
|
132
|
+
if (fs.existsSync(resolved)) return resolved;
|
|
133
|
+
}
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Deep-merge two plain objects (target mutated).
|
|
138
|
+
function deepMerge(target, source) {
|
|
139
|
+
for (const key of Object.keys(source)) {
|
|
140
|
+
if (
|
|
141
|
+
source[key] !== null &&
|
|
142
|
+
typeof source[key] === 'object' &&
|
|
143
|
+
!Array.isArray(source[key]) &&
|
|
144
|
+
typeof target[key] === 'object' &&
|
|
145
|
+
target[key] !== null &&
|
|
146
|
+
!Array.isArray(target[key])
|
|
147
|
+
) {
|
|
148
|
+
deepMerge(target[key], source[key]);
|
|
149
|
+
} else {
|
|
150
|
+
target[key] = source[key];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return target;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ─── Main wizard ──────────────────────────────────────────────────────────────
|
|
157
|
+
|
|
158
|
+
async function run() {
|
|
159
|
+
console.log(`
|
|
160
|
+
${bold(magenta('🧠 Sulcus Configuration Wizard'))}
|
|
161
|
+
${dim('────────────────────────────────────────────')}
|
|
162
|
+
Configures the ${cyan('openclaw-sulcus')} plugin inside your ${cyan('openclaw.json')}.
|
|
163
|
+
Press ${bold('Enter')} to accept defaults. ${bold('Ctrl+C')} to cancel at any time.
|
|
164
|
+
`);
|
|
165
|
+
|
|
166
|
+
// ── Step 1: Locate openclaw.json ──────────────────────────────────────────
|
|
167
|
+
|
|
168
|
+
console.log(`${bold('Step 1 · Locate openclaw.json')}`);
|
|
169
|
+
|
|
170
|
+
let configPath = findOpenclawJson();
|
|
171
|
+
|
|
172
|
+
if (configPath) {
|
|
173
|
+
console.log(` ${green('✓')} Found: ${cyan(configPath)}\n`);
|
|
174
|
+
} else {
|
|
175
|
+
console.log(` ${yellow('⚠')} Could not find openclaw.json in the usual locations.`);
|
|
176
|
+
console.log(` Checked:`);
|
|
177
|
+
if (process.env.OPENCLAW_CONFIG_PATH)
|
|
178
|
+
console.log(` • \$OPENCLAW_CONFIG_PATH → ${process.env.OPENCLAW_CONFIG_PATH}`);
|
|
179
|
+
console.log(` • ~/.openclaw/openclaw.json`);
|
|
180
|
+
console.log(` • ./openclaw.json\n`);
|
|
181
|
+
|
|
182
|
+
const choice = await ask(
|
|
183
|
+
` Enter full path to openclaw.json, or press Enter to create ~/.openclaw/openclaw.json:`,
|
|
184
|
+
path.join(os.homedir(), '.openclaw', 'openclaw.json'),
|
|
185
|
+
);
|
|
186
|
+
configPath = expandHome(choice);
|
|
187
|
+
|
|
188
|
+
if (!fs.existsSync(configPath)) {
|
|
189
|
+
const dir = path.dirname(configPath);
|
|
190
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
191
|
+
fs.writeFileSync(configPath, JSON.stringify({}, null, 2), 'utf8');
|
|
192
|
+
console.log(` ${green('✓')} Created: ${cyan(configPath)}\n`);
|
|
193
|
+
} else {
|
|
194
|
+
console.log(` ${green('✓')} Using: ${cyan(configPath)}\n`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Read existing config
|
|
199
|
+
let existingConfig = {};
|
|
200
|
+
try {
|
|
201
|
+
existingConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
202
|
+
} catch (err) {
|
|
203
|
+
console.log(` ${red('✗')} Failed to parse openclaw.json: ${err.message}`);
|
|
204
|
+
console.log(` Fix the JSON syntax and re-run the wizard.\n`);
|
|
205
|
+
rl.close();
|
|
206
|
+
process.exit(1);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ── Step 2: Wizard questions ──────────────────────────────────────────────
|
|
210
|
+
|
|
211
|
+
console.log(`${bold('Step 2 · Configure Sulcus')}`);
|
|
212
|
+
console.log();
|
|
213
|
+
|
|
214
|
+
// Backend mode
|
|
215
|
+
console.log(` ${bold('Backend mode:')}`);
|
|
216
|
+
console.log(` ${cyan('[1]')} Local only ${dim('(WASM + native dylibs, no network)')}`);
|
|
217
|
+
console.log(` ${cyan('[2]')} Cloud sync ${dim('(local + server replication)')}`);
|
|
218
|
+
const modeRaw = await ask(` >`, '1');
|
|
219
|
+
const cloudSync = modeRaw === '2';
|
|
220
|
+
console.log();
|
|
221
|
+
|
|
222
|
+
// Native dylib path
|
|
223
|
+
const libDirDefault = '~/.sulcus/lib';
|
|
224
|
+
const libDirRaw = await ask(
|
|
225
|
+
` ${bold('Where are your native dylibs?')}`,
|
|
226
|
+
libDirDefault,
|
|
227
|
+
);
|
|
228
|
+
const libDir = libDirRaw;
|
|
229
|
+
console.log();
|
|
230
|
+
|
|
231
|
+
// Agent namespace
|
|
232
|
+
const namespace = await ask(` ${bold('Agent namespace:')}`, 'default');
|
|
233
|
+
console.log();
|
|
234
|
+
|
|
235
|
+
// Hooks
|
|
236
|
+
console.log(` ${bold('Enable hooks:')}`);
|
|
237
|
+
const injectAwareness = await askYN(
|
|
238
|
+
'Inject memory awareness into prompts? (before_prompt_build)',
|
|
239
|
+
false,
|
|
240
|
+
);
|
|
241
|
+
const autoRecall = await askYN(
|
|
242
|
+
'Auto-recall memories on each turn? (before_agent_start)',
|
|
243
|
+
false,
|
|
244
|
+
);
|
|
245
|
+
console.log();
|
|
246
|
+
|
|
247
|
+
// Tools
|
|
248
|
+
console.log(` ${bold('Enable tools:')}`);
|
|
249
|
+
const toolMemoryRecall = await askYN('memory_recall — search memories', true);
|
|
250
|
+
const toolMemoryStore = await askYN('memory_store — save memories', true);
|
|
251
|
+
const toolMemoryStatus = await askYN('memory_status — check memory stats', true);
|
|
252
|
+
const toolConsolidate = await askYN('consolidate — cluster similar memories', false);
|
|
253
|
+
const toolExportMarkdown = await askYN('export_markdown — export memories as markdown', false);
|
|
254
|
+
const toolImportMarkdown = await askYN('import_markdown — import from markdown', false);
|
|
255
|
+
const toolEvalTriggers = await askYN('evaluate_triggers — reactive trigger engine', false);
|
|
256
|
+
console.log();
|
|
257
|
+
|
|
258
|
+
// Cloud sync extras
|
|
259
|
+
let serverUrl = '';
|
|
260
|
+
let apiKey = '';
|
|
261
|
+
if (cloudSync) {
|
|
262
|
+
console.log(` ${bold('Cloud sync settings:')}`);
|
|
263
|
+
serverUrl = await ask(` Server URL:`, 'https://api.sulcus.ca');
|
|
264
|
+
apiKey = await ask(` API Key:`, '');
|
|
265
|
+
console.log();
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ── Step 3: Build and write config ───────────────────────────────────────
|
|
269
|
+
|
|
270
|
+
console.log(`${bold('Step 3 · Write openclaw.json')}`);
|
|
271
|
+
|
|
272
|
+
const sulcusConfig = {
|
|
273
|
+
libDir,
|
|
274
|
+
namespace: namespace === 'default' ? undefined : namespace,
|
|
275
|
+
...(cloudSync && serverUrl ? { serverUrl } : {}),
|
|
276
|
+
...(cloudSync && apiKey ? { apiKey } : {}),
|
|
277
|
+
hooks: {
|
|
278
|
+
before_prompt_build: { action: 'inject_awareness', enabled: injectAwareness },
|
|
279
|
+
before_agent_start: { action: 'auto_recall', enabled: autoRecall, limit: 5, minScore: 0.3 },
|
|
280
|
+
},
|
|
281
|
+
tools: {
|
|
282
|
+
memory_recall: { enabled: toolMemoryRecall },
|
|
283
|
+
memory_store: { enabled: toolMemoryStore },
|
|
284
|
+
memory_status: { enabled: toolMemoryStatus },
|
|
285
|
+
consolidate: { enabled: toolConsolidate },
|
|
286
|
+
export_markdown: { enabled: toolExportMarkdown },
|
|
287
|
+
import_markdown: { enabled: toolImportMarkdown },
|
|
288
|
+
evaluate_triggers: { enabled: toolEvalTriggers },
|
|
289
|
+
},
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
// Remove undefined keys
|
|
293
|
+
Object.keys(sulcusConfig).forEach(
|
|
294
|
+
(k) => sulcusConfig[k] === undefined && delete sulcusConfig[k],
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
// Deep-merge into existing config
|
|
298
|
+
const merged = deepMerge(existingConfig, {
|
|
299
|
+
plugins: {
|
|
300
|
+
entries: {
|
|
301
|
+
'openclaw-sulcus': {
|
|
302
|
+
enabled: true,
|
|
303
|
+
config: sulcusConfig,
|
|
304
|
+
},
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
let written = false;
|
|
310
|
+
try {
|
|
311
|
+
fs.writeFileSync(configPath, JSON.stringify(merged, null, 2) + '\n', 'utf8');
|
|
312
|
+
written = true;
|
|
313
|
+
} catch (err) {
|
|
314
|
+
console.log(` ${red('✗')} Failed to write ${configPath}: ${err.message}\n`);
|
|
315
|
+
rl.close();
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (written) {
|
|
320
|
+
console.log(` ${green('✓')} Written to ${cyan(configPath)}`);
|
|
321
|
+
console.log();
|
|
322
|
+
|
|
323
|
+
// Summary
|
|
324
|
+
console.log(` ${dim('──── Summary ────────────────────────────────────')}`);
|
|
325
|
+
console.log(` Plugin: ${cyan('openclaw-sulcus')} ${green('enabled')}`);
|
|
326
|
+
console.log(` Backend: ${cyan(cloudSync ? 'cloud sync' : 'local only')}`);
|
|
327
|
+
console.log(` Dylib dir: ${cyan(libDir)}`);
|
|
328
|
+
console.log(` Namespace: ${cyan(namespace)}`);
|
|
329
|
+
if (cloudSync && serverUrl) console.log(` Server: ${cyan(serverUrl)}`);
|
|
330
|
+
|
|
331
|
+
const enabledHooks = [];
|
|
332
|
+
if (injectAwareness) enabledHooks.push('before_prompt_build');
|
|
333
|
+
if (autoRecall) enabledHooks.push('before_agent_start');
|
|
334
|
+
console.log(` Hooks: ${enabledHooks.length ? cyan(enabledHooks.join(', ')) : dim('(none enabled)')}`);
|
|
335
|
+
|
|
336
|
+
const enabledTools = [
|
|
337
|
+
toolMemoryRecall && 'memory_recall',
|
|
338
|
+
toolMemoryStore && 'memory_store',
|
|
339
|
+
toolMemoryStatus && 'memory_status',
|
|
340
|
+
toolConsolidate && 'consolidate',
|
|
341
|
+
toolExportMarkdown && 'export_markdown',
|
|
342
|
+
toolImportMarkdown && 'import_markdown',
|
|
343
|
+
toolEvalTriggers && 'evaluate_triggers',
|
|
344
|
+
].filter(Boolean);
|
|
345
|
+
console.log(` Tools: ${enabledTools.length ? cyan(enabledTools.join(', ')) : dim('(none enabled)')}`);
|
|
346
|
+
console.log(` ${dim('─────────────────────────────────────────────────')}`);
|
|
347
|
+
console.log();
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// ── Step 4: Validate dylib path ───────────────────────────────────────────
|
|
351
|
+
|
|
352
|
+
console.log(`${bold('Step 4 · Validate')}`);
|
|
353
|
+
|
|
354
|
+
const resolvedLibDir = expandHome(libDir);
|
|
355
|
+
const dylibNames = ['libsulcus_store', 'libsulcus_vectors'];
|
|
356
|
+
const ext = process.platform === 'darwin' ? '.dylib'
|
|
357
|
+
: process.platform === 'win32' ? '.dll'
|
|
358
|
+
: '.so';
|
|
359
|
+
|
|
360
|
+
let dylibsOk = true;
|
|
361
|
+
|
|
362
|
+
if (!fs.existsSync(resolvedLibDir)) {
|
|
363
|
+
dylibsOk = false;
|
|
364
|
+
console.log(` ${yellow('⚠')} Dylib directory not found: ${cyan(resolvedLibDir)}`);
|
|
365
|
+
} else {
|
|
366
|
+
for (const lib of dylibNames) {
|
|
367
|
+
const full = path.join(resolvedLibDir, lib + ext);
|
|
368
|
+
if (fs.existsSync(full)) {
|
|
369
|
+
console.log(` ${green('✓')} Found: ${dim(full)}`);
|
|
370
|
+
} else {
|
|
371
|
+
dylibsOk = false;
|
|
372
|
+
console.log(` ${yellow('⚠')} Missing: ${dim(full)}`);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (!dylibsOk) {
|
|
378
|
+
console.log();
|
|
379
|
+
console.log(` ${yellow(bold('Native dylibs missing — Sulcus will not load.'))}`);;
|
|
380
|
+
console.log(` Run the setup script to download and install them:`);
|
|
381
|
+
console.log(` ${cyan('bash ~/.sulcus/setup-local.sh')}`);
|
|
382
|
+
console.log(` Or visit: ${cyan('https://sulcus.ca/docs/install')}`);
|
|
383
|
+
} else {
|
|
384
|
+
console.log(` ${green('✓')} All dylibs present — Sulcus is ready to go.`);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
console.log();
|
|
388
|
+
console.log(` ${bold(green('✅ Configuration complete!'))} Restart the OpenClaw gateway to pick up changes:`);
|
|
389
|
+
console.log(` ${cyan('openclaw gateway restart')}`);
|
|
390
|
+
console.log();
|
|
391
|
+
|
|
392
|
+
rl.close();
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
run().catch((err) => {
|
|
396
|
+
console.error(`\n${red('Fatal error:')} ${err.message}\n`);
|
|
397
|
+
rl.close();
|
|
398
|
+
process.exit(1);
|
|
399
|
+
});
|
package/hooks.defaults.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"hooks": {
|
|
5
5
|
"before_prompt_build": {
|
|
6
6
|
"action": "inject_awareness",
|
|
7
|
-
"enabled":
|
|
7
|
+
"enabled": false
|
|
8
8
|
},
|
|
9
9
|
"before_agent_start": {
|
|
10
10
|
"action": "auto_recall",
|
|
@@ -14,13 +14,13 @@
|
|
|
14
14
|
},
|
|
15
15
|
"agent_end": {
|
|
16
16
|
"action": "none",
|
|
17
|
-
"enabled":
|
|
17
|
+
"enabled": false
|
|
18
18
|
}
|
|
19
19
|
},
|
|
20
20
|
"tools": {
|
|
21
|
-
"memory_recall": { "enabled":
|
|
22
|
-
"memory_store": { "enabled":
|
|
23
|
-
"memory_status": { "enabled":
|
|
21
|
+
"memory_recall": { "enabled": false },
|
|
22
|
+
"memory_store": { "enabled": false },
|
|
23
|
+
"memory_status": { "enabled": false },
|
|
24
24
|
"consolidate": { "enabled": false },
|
|
25
25
|
"export_markdown": { "enabled": false },
|
|
26
26
|
"import_markdown": { "enabled": false },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@digitalforgestudios/openclaw-sulcus",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.0",
|
|
4
4
|
"description": "Sulcus — reactive, thermodynamic memory plugin for OpenClaw. Opt-in persistent memory with heat-based decay, semantic search, and cross-agent sync. Auto-recall and auto-capture disabled by default.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"openclaw",
|
|
@@ -37,7 +37,11 @@
|
|
|
37
37
|
"openclawVersion": "2026.3.28"
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
|
+
"bin": {
|
|
41
|
+
"openclaw-sulcus": "./bin/configure.mjs"
|
|
42
|
+
},
|
|
40
43
|
"files": [
|
|
44
|
+
"bin/",
|
|
41
45
|
"index.ts",
|
|
42
46
|
"wasm/",
|
|
43
47
|
"openclaw.plugin.json",
|
package/wasm/sulcus_wasm.js
CHANGED
|
@@ -277,8 +277,13 @@ function __wbg_get_imports() {
|
|
|
277
277
|
return ret;
|
|
278
278
|
},
|
|
279
279
|
__wbg_new_no_args_1c7c842f08d00ebb: function(arg0, arg1) {
|
|
280
|
-
|
|
281
|
-
|
|
280
|
+
// Avoid dynamic code execution (new Function) — use safe globalThis fallback
|
|
281
|
+
const body = getStringFromWasm0(arg0, arg1);
|
|
282
|
+
if (body.includes('return this')) {
|
|
283
|
+
const ret = { call: () => globalThis };
|
|
284
|
+
return ret;
|
|
285
|
+
}
|
|
286
|
+
throw new Error(`sulcus-wasm: refusing dynamic code execution: ${body.substring(0, 60)}`);
|
|
282
287
|
},
|
|
283
288
|
__wbg_parse_708461a1feddfb38: function() { return handleError(function (arg0, arg1) {
|
|
284
289
|
const ret = JSON.parse(getStringFromWasm0(arg0, arg1));
|