openclaw-overlay-plugin 0.7.47 → 0.7.49
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/dist/index.js +6 -2
- package/dist/src/core/wallet.js +16 -7
- package/dist/src/test/identity-consistency.test.d.ts +6 -0
- package/dist/src/test/identity-consistency.test.js +60 -0
- package/index.ts +7 -2
- package/package.json +1 -1
- package/src/core/wallet.ts +17 -8
- package/src/test/identity-consistency.test.ts +68 -0
package/dist/index.js
CHANGED
|
@@ -418,7 +418,11 @@ function stopBackgroundService() {
|
|
|
418
418
|
export async function activate(api) {
|
|
419
419
|
return register(api);
|
|
420
420
|
}
|
|
421
|
+
let isInitialized = false;
|
|
421
422
|
export default function register(api) {
|
|
423
|
+
if (isInitialized)
|
|
424
|
+
return;
|
|
425
|
+
isInitialized = true;
|
|
422
426
|
// Capture config at registration time
|
|
423
427
|
// Check all possible IDs for backward compatibility and various installation methods
|
|
424
428
|
const entries = api.getConfig?.()?.plugins?.entries || {};
|
|
@@ -589,7 +593,7 @@ export default function register(api) {
|
|
|
589
593
|
// Register a skill-style wake handler
|
|
590
594
|
api.registerHook({
|
|
591
595
|
id: "openclaw-overlay-wake",
|
|
592
|
-
|
|
596
|
+
events: ["gateway:start"],
|
|
593
597
|
handler: async (ctx) => {
|
|
594
598
|
// Auto-check for registration on startup
|
|
595
599
|
(async () => {
|
|
@@ -1459,7 +1463,7 @@ function buildEnvironment(config) {
|
|
|
1459
1463
|
function parseCliOutput(stdout) {
|
|
1460
1464
|
try {
|
|
1461
1465
|
const str = typeof stdout === 'string' ? stdout : String(stdout || '');
|
|
1462
|
-
return JSON.parse(str
|
|
1466
|
+
return JSON.parse(str.trim());
|
|
1463
1467
|
}
|
|
1464
1468
|
catch (error) {
|
|
1465
1469
|
throw new Error(`Failed to parse CLI output: ${error.message}`);
|
package/dist/src/core/wallet.js
CHANGED
|
@@ -186,18 +186,27 @@ export class BSVAgentWallet {
|
|
|
186
186
|
const serviceOptions = Services.createDefaultOptions(chain);
|
|
187
187
|
const chaintracksUrl = process.env.BSV_CHAINTRACKS_URL || 'https://chaintracks-us-1.bsvb.tech';
|
|
188
188
|
const arcUrl = process.env.BSV_ARC_URL;
|
|
189
|
-
|
|
190
|
-
if (
|
|
191
|
-
serviceOptions.
|
|
189
|
+
const isTestMode = config.enableMonitor === false;
|
|
190
|
+
if (!isTestMode) {
|
|
191
|
+
serviceOptions.chaintracks = new ChaintracksServiceClient(chain, chaintracksUrl);
|
|
192
|
+
if (arcUrl) {
|
|
193
|
+
serviceOptions.arcUrl = arcUrl;
|
|
194
|
+
}
|
|
192
195
|
}
|
|
193
196
|
serviceOptions.taalApiKey = taalApiKey;
|
|
194
197
|
const services = new Services(serviceOptions);
|
|
195
198
|
// 4. Background monitor
|
|
196
199
|
const monopts = Monitor.createDefaultWalletMonitorOptions(chain, storage, services);
|
|
197
200
|
const monitor = new Monitor(monopts);
|
|
198
|
-
|
|
201
|
+
if (!isTestMode) {
|
|
202
|
+
monitor.addDefaultTasks();
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
// In test mode, we clear all tasks to ensure no background activity
|
|
206
|
+
monitor.tasks = [];
|
|
207
|
+
}
|
|
199
208
|
// 5. The BRC-100 Wallet
|
|
200
|
-
const wallet = new Wallet({ chain, keyDeriver, storage, services, monitor });
|
|
209
|
+
const wallet = isTestMode ? undefined : new Wallet({ chain, keyDeriver, storage, services, monitor });
|
|
201
210
|
// 6. SQLite storage via knex
|
|
202
211
|
const filePath = path.join(config.storageDir, `${DEFAULT_DB_NAME}.sqlite`);
|
|
203
212
|
const knex = knexLib({
|
|
@@ -225,8 +234,8 @@ export class BSVAgentWallet {
|
|
|
225
234
|
keyDeriver,
|
|
226
235
|
chain,
|
|
227
236
|
storage,
|
|
228
|
-
services,
|
|
229
|
-
monitor,
|
|
237
|
+
services: isTestMode ? undefined : services,
|
|
238
|
+
monitor: isTestMode ? undefined : monitor,
|
|
230
239
|
wallet,
|
|
231
240
|
};
|
|
232
241
|
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity Consistency tests
|
|
3
|
+
*
|
|
4
|
+
* Verifies that all plugins produce the exact same identityKey from the same root secret.
|
|
5
|
+
*/
|
|
6
|
+
import { BSVAgentWallet } from '../core/wallet.js';
|
|
7
|
+
import * as fs from 'node:fs';
|
|
8
|
+
import * as path from 'node:path';
|
|
9
|
+
import * as os from 'node:os';
|
|
10
|
+
// Simple test runner
|
|
11
|
+
let passed = 0;
|
|
12
|
+
let failed = 0;
|
|
13
|
+
async function test(name, fn) {
|
|
14
|
+
try {
|
|
15
|
+
await fn();
|
|
16
|
+
console.log(` ✓ ${name}`);
|
|
17
|
+
passed++;
|
|
18
|
+
}
|
|
19
|
+
catch (err) {
|
|
20
|
+
console.log(` ✗ ${name}`);
|
|
21
|
+
console.log(err);
|
|
22
|
+
failed++;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
function assert(condition, message) {
|
|
26
|
+
if (!condition)
|
|
27
|
+
throw new Error(`Assertion failed: ${message}`);
|
|
28
|
+
}
|
|
29
|
+
async function run() {
|
|
30
|
+
console.log('Identity Consistency tests\n');
|
|
31
|
+
const SHARED_ROOT_KEY = '0000000000000000000000000000000000000000000000000000000000000001';
|
|
32
|
+
const EXPECTED_IDENTITY = '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798';
|
|
33
|
+
await test('Overlay plugin derives correct compressed pubkey', async () => {
|
|
34
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'identity-test-'));
|
|
35
|
+
try {
|
|
36
|
+
const wallet = await BSVAgentWallet.load({
|
|
37
|
+
network: 'mainnet',
|
|
38
|
+
storageDir: tmpDir,
|
|
39
|
+
rootKeyHex: SHARED_ROOT_KEY,
|
|
40
|
+
enableMonitor: false
|
|
41
|
+
});
|
|
42
|
+
const identity = await wallet.getIdentityKey();
|
|
43
|
+
assert(identity === EXPECTED_IDENTITY, `Should match expected identity. Got: ${identity}`);
|
|
44
|
+
assert(identity.length === 66, `Should be 66 chars (compressed hex). Got: ${identity.length}`);
|
|
45
|
+
await wallet.destroy();
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
// Since both use the same core logic (copied or shared), we verify the logic here
|
|
52
|
+
// against the known secp256k1 base point G (compressed).
|
|
53
|
+
console.log(`\n${passed} passed, ${failed} failed`);
|
|
54
|
+
if (failed > 0)
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
run().catch(err => {
|
|
58
|
+
console.error(err);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
});
|
package/index.ts
CHANGED
|
@@ -462,7 +462,12 @@ export async function activate(api: any) {
|
|
|
462
462
|
return register(api);
|
|
463
463
|
}
|
|
464
464
|
|
|
465
|
+
let isInitialized = false;
|
|
466
|
+
|
|
465
467
|
export default function register(api: any) {
|
|
468
|
+
if (isInitialized) return;
|
|
469
|
+
isInitialized = true;
|
|
470
|
+
|
|
466
471
|
// Capture config at registration time
|
|
467
472
|
// Check all possible IDs for backward compatibility and various installation methods
|
|
468
473
|
const entries = api.getConfig?.()?.plugins?.entries || {};
|
|
@@ -638,7 +643,7 @@ export default function register(api: any) {
|
|
|
638
643
|
// Register a skill-style wake handler
|
|
639
644
|
api.registerHook({
|
|
640
645
|
id: "openclaw-overlay-wake",
|
|
641
|
-
|
|
646
|
+
events: ["gateway:start"],
|
|
642
647
|
handler: async (ctx: any) => {
|
|
643
648
|
// Auto-check for registration on startup
|
|
644
649
|
(async () => {
|
|
@@ -1644,7 +1649,7 @@ function buildEnvironment(config: any) {
|
|
|
1644
1649
|
function parseCliOutput(stdout: any) {
|
|
1645
1650
|
try {
|
|
1646
1651
|
const str = typeof stdout === 'string' ? stdout : String(stdout || '');
|
|
1647
|
-
return JSON.parse(str
|
|
1652
|
+
return JSON.parse(str.trim());
|
|
1648
1653
|
} catch (error: any) {
|
|
1649
1654
|
throw new Error(`Failed to parse CLI output: ${error.message}`);
|
|
1650
1655
|
}
|
package/package.json
CHANGED
package/src/core/wallet.ts
CHANGED
|
@@ -243,9 +243,13 @@ export class BSVAgentWallet {
|
|
|
243
243
|
const chaintracksUrl = process.env.BSV_CHAINTRACKS_URL || 'https://chaintracks-us-1.bsvb.tech';
|
|
244
244
|
const arcUrl = process.env.BSV_ARC_URL;
|
|
245
245
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
246
|
+
const isTestMode = (config as any).enableMonitor === false;
|
|
247
|
+
|
|
248
|
+
if (!isTestMode) {
|
|
249
|
+
serviceOptions.chaintracks = new ChaintracksServiceClient(chain, chaintracksUrl);
|
|
250
|
+
if (arcUrl) {
|
|
251
|
+
serviceOptions.arcUrl = arcUrl;
|
|
252
|
+
}
|
|
249
253
|
}
|
|
250
254
|
|
|
251
255
|
serviceOptions.taalApiKey = taalApiKey;
|
|
@@ -254,10 +258,15 @@ export class BSVAgentWallet {
|
|
|
254
258
|
// 4. Background monitor
|
|
255
259
|
const monopts = Monitor.createDefaultWalletMonitorOptions(chain, storage, services);
|
|
256
260
|
const monitor = new Monitor(monopts);
|
|
257
|
-
|
|
261
|
+
if (!isTestMode) {
|
|
262
|
+
monitor.addDefaultTasks();
|
|
263
|
+
} else {
|
|
264
|
+
// In test mode, we clear all tasks to ensure no background activity
|
|
265
|
+
(monitor as any).tasks = [];
|
|
266
|
+
}
|
|
258
267
|
|
|
259
268
|
// 5. The BRC-100 Wallet
|
|
260
|
-
const wallet = new Wallet({ chain, keyDeriver, storage, services, monitor });
|
|
269
|
+
const wallet = isTestMode ? undefined : new Wallet({ chain, keyDeriver, storage, services, monitor });
|
|
261
270
|
|
|
262
271
|
// 6. SQLite storage via knex
|
|
263
272
|
const filePath = path.join(config.storageDir, `${DEFAULT_DB_NAME}.sqlite`);
|
|
@@ -290,9 +299,9 @@ export class BSVAgentWallet {
|
|
|
290
299
|
keyDeriver,
|
|
291
300
|
chain,
|
|
292
301
|
storage,
|
|
293
|
-
services,
|
|
294
|
-
monitor,
|
|
302
|
+
services: isTestMode ? undefined : services,
|
|
303
|
+
monitor: isTestMode ? undefined : monitor,
|
|
295
304
|
wallet,
|
|
296
|
-
};
|
|
305
|
+
} as any;
|
|
297
306
|
}
|
|
298
307
|
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Identity Consistency tests
|
|
3
|
+
*
|
|
4
|
+
* Verifies that all plugins produce the exact same identityKey from the same root secret.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { BSVAgentWallet } from '../core/wallet.js';
|
|
8
|
+
import * as fs from 'node:fs';
|
|
9
|
+
import * as path from 'node:path';
|
|
10
|
+
import * as os from 'node:os';
|
|
11
|
+
|
|
12
|
+
// Simple test runner
|
|
13
|
+
let passed = 0;
|
|
14
|
+
let failed = 0;
|
|
15
|
+
|
|
16
|
+
async function test(name: string, fn: () => void | Promise<void>) {
|
|
17
|
+
try {
|
|
18
|
+
await fn();
|
|
19
|
+
console.log(` ✓ ${name}`);
|
|
20
|
+
passed++;
|
|
21
|
+
} catch (err: unknown) {
|
|
22
|
+
console.log(` ✗ ${name}`);
|
|
23
|
+
console.log(err);
|
|
24
|
+
failed++;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function assert(condition: boolean, message: string) {
|
|
29
|
+
if (!condition) throw new Error(`Assertion failed: ${message}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function run() {
|
|
33
|
+
console.log('Identity Consistency tests\n');
|
|
34
|
+
|
|
35
|
+
const SHARED_ROOT_KEY = '0000000000000000000000000000000000000000000000000000000000000001';
|
|
36
|
+
const EXPECTED_IDENTITY = '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798';
|
|
37
|
+
|
|
38
|
+
await test('Overlay plugin derives correct compressed pubkey', async () => {
|
|
39
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'identity-test-'));
|
|
40
|
+
try {
|
|
41
|
+
const wallet = await BSVAgentWallet.load({
|
|
42
|
+
network: 'mainnet',
|
|
43
|
+
storageDir: tmpDir,
|
|
44
|
+
rootKeyHex: SHARED_ROOT_KEY,
|
|
45
|
+
enableMonitor: false
|
|
46
|
+
} as any);
|
|
47
|
+
|
|
48
|
+
const identity = await wallet.getIdentityKey();
|
|
49
|
+
assert(identity === EXPECTED_IDENTITY, `Should match expected identity. Got: ${identity}`);
|
|
50
|
+
assert(identity.length === 66, `Should be 66 chars (compressed hex). Got: ${identity.length}`);
|
|
51
|
+
|
|
52
|
+
await wallet.destroy();
|
|
53
|
+
} finally {
|
|
54
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Since both use the same core logic (copied or shared), we verify the logic here
|
|
59
|
+
// against the known secp256k1 base point G (compressed).
|
|
60
|
+
|
|
61
|
+
console.log(`\n${passed} passed, ${failed} failed`);
|
|
62
|
+
if (failed > 0) process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
run().catch(err => {
|
|
66
|
+
console.error(err);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
});
|