@wipcomputer/wip-ldm-os 0.4.64 → 0.4.66

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/SKILL.md CHANGED
@@ -9,7 +9,7 @@ license: MIT
9
9
  compatibility: Requires git, npm, node. Node.js 18+.
10
10
  metadata:
11
11
  display-name: "LDM OS"
12
- version: "0.4.64"
12
+ version: "0.4.66"
13
13
  homepage: "https://github.com/wipcomputer/wip-ldm-os"
14
14
  author: "Parker Todd Brooks"
15
15
  category: infrastructure
package/bin/ldm.js CHANGED
@@ -397,10 +397,16 @@ async function installCatalogComponent(c) {
397
397
  // never get copied to ~/.ldm/extensions/lesa-bridge/dist/. This function fixes that.
398
398
 
399
399
  function deployBridge() {
400
- const bridgeDest = join(LDM_EXTENSIONS, 'lesa-bridge', 'dist');
400
+ const ldmBridgeDir = join(LDM_EXTENSIONS, 'lesa-bridge');
401
+ const ocBridgeDir = join(HOME, '.openclaw', 'extensions', 'lesa-bridge');
401
402
 
402
- // Only deploy if the extension is installed
403
- if (!existsSync(join(LDM_EXTENSIONS, 'lesa-bridge'))) return 0;
403
+ // Deploy targets: LDM path (canonical) and OpenClaw path (where the plugin loads)
404
+ const targets = [
405
+ { dir: ldmBridgeDir, label: '~/.ldm/extensions/lesa-bridge/dist/' },
406
+ { dir: ocBridgeDir, label: '~/.openclaw/extensions/lesa-bridge/dist/' },
407
+ ].filter(t => existsSync(t.dir)); // Only deploy if the extension dir exists
408
+
409
+ if (targets.length === 0) return 0;
404
410
 
405
411
  // Find the npm package bridge files. Try require.resolve first, fall back to known path.
406
412
  let bridgeSrc = '';
@@ -427,13 +433,14 @@ function deployBridge() {
427
433
 
428
434
  if (!bridgeSrc || !existsSync(bridgeSrc)) return 0;
429
435
 
430
- // Check if files differ before copying
436
+ // Check if files differ (compare against the LDM target, or first available)
437
+ const checkDest = join(targets[0].dir, 'dist');
431
438
  let changed = false;
432
439
  try {
433
440
  const srcFiles = readdirSync(bridgeSrc).filter(f => f.endsWith('.js') || f.endsWith('.d.ts'));
434
441
  for (const file of srcFiles) {
435
442
  const srcPath = join(bridgeSrc, file);
436
- const destPath = join(bridgeDest, file);
443
+ const destPath = join(checkDest, file);
437
444
  if (!existsSync(destPath)) {
438
445
  changed = true;
439
446
  break;
@@ -445,6 +452,17 @@ function deployBridge() {
445
452
  break;
446
453
  }
447
454
  }
455
+ // Also check if there are stale files in the target that aren't in the source
456
+ if (!changed) {
457
+ const destFiles = readdirSync(checkDest).filter(f => f.endsWith('.js'));
458
+ const srcFileSet = new Set(srcFiles);
459
+ for (const file of destFiles) {
460
+ if (!srcFileSet.has(file)) {
461
+ changed = true; // stale chunk file found
462
+ break;
463
+ }
464
+ }
465
+ }
448
466
  } catch {
449
467
  changed = true; // if comparison fails, copy anyway
450
468
  }
@@ -452,23 +470,57 @@ function deployBridge() {
452
470
  if (!changed) return 0;
453
471
 
454
472
  if (DRY_RUN) {
455
- console.log(` + would deploy bridge files to ~/.ldm/extensions/lesa-bridge/dist/`);
473
+ console.log(` + would deploy bridge files to ${targets.map(t => t.label).join(' + ')}`);
456
474
  return 0;
457
475
  }
458
476
 
459
- try {
460
- mkdirSync(bridgeDest, { recursive: true });
461
- const files = readdirSync(bridgeSrc).filter(f => f.endsWith('.js') || f.endsWith('.d.ts'));
462
- for (const file of files) {
463
- cpSync(join(bridgeSrc, file), join(bridgeDest, file));
464
- }
465
- console.log(` + bridge deployed to ~/.ldm/extensions/lesa-bridge/dist/ (${files.length} files)`);
466
- installLog(`Bridge deployed: ${files.length} files to ~/.ldm/extensions/lesa-bridge/dist/`);
467
- return files.length;
468
- } catch (e) {
469
- console.log(` ! bridge deploy failed: ${e.message}`);
470
- return 0;
477
+ const srcFiles = readdirSync(bridgeSrc).filter(f => f.endsWith('.js') || f.endsWith('.d.ts'));
478
+ let totalDeployed = 0;
479
+
480
+ for (const target of targets) {
481
+ const dest = join(target.dir, 'dist');
482
+ try {
483
+ mkdirSync(dest, { recursive: true });
484
+
485
+ // Clean stale .js files before copying (chunk hashes change between builds)
486
+ try {
487
+ const existing = readdirSync(dest).filter(f => f.endsWith('.js'));
488
+ const srcFileSet = new Set(srcFiles.filter(f => f.endsWith('.js')));
489
+ for (const file of existing) {
490
+ if (!srcFileSet.has(file)) {
491
+ unlinkSync(join(dest, file));
492
+ }
493
+ }
494
+ } catch {}
495
+
496
+ for (const file of srcFiles) {
497
+ cpSync(join(bridgeSrc, file), join(dest, file));
498
+ }
499
+ console.log(` + bridge deployed to ${target.label} (${srcFiles.length} files)`);
500
+ installLog(`Bridge deployed: ${srcFiles.length} files to ${target.label}`);
501
+ totalDeployed += srcFiles.length;
502
+ } catch (e) {
503
+ console.log(` ! bridge deploy to ${target.label} failed: ${e.message}`);
504
+ }
505
+ }
506
+
507
+ // Re-register MCP server to point to the canonical LDM path
508
+ if (totalDeployed > 0 && existsSync(join(ldmBridgeDir, 'dist', 'mcp-server.js'))) {
509
+ try {
510
+ const mcpPath = join(ldmBridgeDir, 'dist', 'mcp-server.js');
511
+ execSync(`claude mcp add lesa-bridge --scope user -- node ${mcpPath}`, {
512
+ stdio: 'pipe',
513
+ timeout: 10000,
514
+ });
515
+ console.log(` + MCP registration updated: lesa-bridge -> ~/.ldm/extensions/lesa-bridge/dist/mcp-server.js`);
516
+ installLog('MCP registration updated: lesa-bridge -> ~/.ldm/extensions/lesa-bridge/dist/mcp-server.js');
517
+ } catch (e) {
518
+ // Non-fatal: MCP registration is a convenience, not a requirement
519
+ console.log(` ! MCP registration update failed: ${e.message}`);
520
+ }
471
521
  }
522
+
523
+ return totalDeployed;
472
524
  }
473
525
 
474
526
  // ── ldm init ──
@@ -892,7 +944,7 @@ async function cmdInit() {
892
944
  }
893
945
  }
894
946
 
895
- // Deploy bridge files to ~/.ldm/extensions/lesa-bridge/dist/ (#245)
947
+ // Deploy bridge files to all targets and re-register MCP (#245, #251)
896
948
  deployBridge();
897
949
 
898
950
  // Clean up dead backup triggers (#207)
@@ -1266,9 +1318,9 @@ async function cmdInstallCatalog() {
1266
1318
 
1267
1319
  autoDetectExtensions();
1268
1320
 
1269
- // Deploy bridge files after self-update or on every catalog install (#245)
1321
+ // Deploy bridge files after self-update or on every catalog install (#245, #251)
1270
1322
  // After npm install -g, the new bridge files are in the npm package but not
1271
- // in ~/.ldm/extensions/lesa-bridge/dist/. This copies them.
1323
+ // in the extension directories. This copies them to both LDM and OpenClaw targets.
1272
1324
  deployBridge();
1273
1325
 
1274
1326
  const { detectSystemState, reconcileState, formatReconciliation } = await import('../lib/state.mjs');
@@ -103,11 +103,12 @@ async function sendMessage(openclawDir, message, options) {
103
103
  method: "POST",
104
104
  headers: {
105
105
  Authorization: `Bearer ${token}`,
106
- "Content-Type": "application/json"
106
+ "Content-Type": "application/json",
107
+ "x-openclaw-scopes": "operator.read,operator.write",
108
+ "x-openclaw-session-key": `agent:${agentId}:main`
107
109
  },
108
110
  body: JSON.stringify({
109
111
  model: `openclaw/${agentId}`,
110
- user: "main",
111
112
  messages: [
112
113
  {
113
114
  role: "user",
@@ -8,7 +8,7 @@ import {
8
8
  searchConversations,
9
9
  searchWorkspace,
10
10
  sendMessage
11
- } from "./chunk-QZ4DNVJM.js";
11
+ } from "./chunk-5EOEBBUV.js";
12
12
 
13
13
  // cli.ts
14
14
  import { existsSync, statSync } from "fs";
@@ -17,7 +17,7 @@ import {
17
17
  searchConversations,
18
18
  searchWorkspace,
19
19
  sendMessage
20
- } from "./chunk-QZ4DNVJM.js";
20
+ } from "./chunk-5EOEBBUV.js";
21
21
  export {
22
22
  LDM_ROOT,
23
23
  blobToEmbedding,
@@ -9,7 +9,7 @@ import {
9
9
  searchConversations,
10
10
  searchWorkspace,
11
11
  sendMessage
12
- } from "./chunk-QZ4DNVJM.js";
12
+ } from "./chunk-5EOEBBUV.js";
13
13
 
14
14
  // mcp-server.ts
15
15
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipcomputer/wip-ldm-os",
3
- "version": "0.4.64",
3
+ "version": "0.4.66",
4
4
  "type": "module",
5
5
  "description": "LDM OS: identity, memory, and sovereignty infrastructure for AI agents",
6
6
  "engines": {
@@ -196,10 +196,11 @@ export async function sendMessage(
196
196
  headers: {
197
197
  Authorization: `Bearer ${token}`,
198
198
  "Content-Type": "application/json",
199
+ "x-openclaw-scopes": "operator.read,operator.write",
200
+ "x-openclaw-session-key": `agent:${agentId}:main`,
199
201
  },
200
202
  body: JSON.stringify({
201
203
  model: `openclaw/${agentId}`,
202
- user: "main",
203
204
  messages: [
204
205
  {
205
206
  role: "user",