@wipcomputer/wip-ldm-os 0.4.63 → 0.4.65
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 +1 -1
- package/bin/ldm.js +140 -0
- package/dist/bridge/{chunk-QZ4DNVJM.js → chunk-XVIE3HLZ.js} +2 -1
- package/dist/bridge/cli.js +1 -1
- package/dist/bridge/core.js +1 -1
- package/dist/bridge/mcp-server.js +1 -1
- package/package.json +1 -1
- package/src/bridge/core.ts +1 -0
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.
|
|
12
|
+
version: "0.4.65"
|
|
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
|
@@ -391,6 +391,138 @@ async function installCatalogComponent(c) {
|
|
|
391
391
|
console.log(` ✓ Installed ${c.name}`);
|
|
392
392
|
}
|
|
393
393
|
|
|
394
|
+
// ── Bridge deploy (#245) ──
|
|
395
|
+
// The bridge (src/bridge/) builds to dist/bridge/ and ships in the npm package.
|
|
396
|
+
// After `npm install -g`, the updated files live at the npm package location but
|
|
397
|
+
// never get copied to ~/.ldm/extensions/lesa-bridge/dist/. This function fixes that.
|
|
398
|
+
|
|
399
|
+
function deployBridge() {
|
|
400
|
+
const ldmBridgeDir = join(LDM_EXTENSIONS, 'lesa-bridge');
|
|
401
|
+
const ocBridgeDir = join(HOME, '.openclaw', 'extensions', 'lesa-bridge');
|
|
402
|
+
|
|
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;
|
|
410
|
+
|
|
411
|
+
// Find the npm package bridge files. Try require.resolve first, fall back to known path.
|
|
412
|
+
let bridgeSrc = '';
|
|
413
|
+
try {
|
|
414
|
+
const pkgJson = join(__dirname, '..', 'dist', 'bridge');
|
|
415
|
+
if (existsSync(pkgJson)) {
|
|
416
|
+
bridgeSrc = pkgJson;
|
|
417
|
+
}
|
|
418
|
+
} catch {}
|
|
419
|
+
|
|
420
|
+
if (!bridgeSrc) {
|
|
421
|
+
// Fallback: check common global npm locations
|
|
422
|
+
const candidates = [
|
|
423
|
+
'/opt/homebrew/lib/node_modules/@wipcomputer/wip-ldm-os/dist/bridge',
|
|
424
|
+
join(HOME, '.npm-global/lib/node_modules/@wipcomputer/wip-ldm-os/dist/bridge'),
|
|
425
|
+
];
|
|
426
|
+
for (const c of candidates) {
|
|
427
|
+
if (existsSync(c)) {
|
|
428
|
+
bridgeSrc = c;
|
|
429
|
+
break;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
if (!bridgeSrc || !existsSync(bridgeSrc)) return 0;
|
|
435
|
+
|
|
436
|
+
// Check if files differ (compare against the LDM target, or first available)
|
|
437
|
+
const checkDest = join(targets[0].dir, 'dist');
|
|
438
|
+
let changed = false;
|
|
439
|
+
try {
|
|
440
|
+
const srcFiles = readdirSync(bridgeSrc).filter(f => f.endsWith('.js') || f.endsWith('.d.ts'));
|
|
441
|
+
for (const file of srcFiles) {
|
|
442
|
+
const srcPath = join(bridgeSrc, file);
|
|
443
|
+
const destPath = join(checkDest, file);
|
|
444
|
+
if (!existsSync(destPath)) {
|
|
445
|
+
changed = true;
|
|
446
|
+
break;
|
|
447
|
+
}
|
|
448
|
+
const srcContent = readFileSync(srcPath);
|
|
449
|
+
const destContent = readFileSync(destPath);
|
|
450
|
+
if (!srcContent.equals(destContent)) {
|
|
451
|
+
changed = true;
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
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
|
+
}
|
|
466
|
+
} catch {
|
|
467
|
+
changed = true; // if comparison fails, copy anyway
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (!changed) return 0;
|
|
471
|
+
|
|
472
|
+
if (DRY_RUN) {
|
|
473
|
+
console.log(` + would deploy bridge files to ${targets.map(t => t.label).join(' + ')}`);
|
|
474
|
+
return 0;
|
|
475
|
+
}
|
|
476
|
+
|
|
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
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
return totalDeployed;
|
|
524
|
+
}
|
|
525
|
+
|
|
394
526
|
// ── ldm init ──
|
|
395
527
|
|
|
396
528
|
async function cmdInit() {
|
|
@@ -812,6 +944,9 @@ async function cmdInit() {
|
|
|
812
944
|
}
|
|
813
945
|
}
|
|
814
946
|
|
|
947
|
+
// Deploy bridge files to all targets and re-register MCP (#245, #251)
|
|
948
|
+
deployBridge();
|
|
949
|
+
|
|
815
950
|
// Clean up dead backup triggers (#207)
|
|
816
951
|
// Bug: three backup systems were competing. Only ai.openclaw.ldm-backup (3am) works.
|
|
817
952
|
// The old cron entry (LDMDevTools.app) and com.wipcomputer.daily-backup are dead.
|
|
@@ -1183,6 +1318,11 @@ async function cmdInstallCatalog() {
|
|
|
1183
1318
|
|
|
1184
1319
|
autoDetectExtensions();
|
|
1185
1320
|
|
|
1321
|
+
// Deploy bridge files after self-update or on every catalog install (#245, #251)
|
|
1322
|
+
// After npm install -g, the new bridge files are in the npm package but not
|
|
1323
|
+
// in the extension directories. This copies them to both LDM and OpenClaw targets.
|
|
1324
|
+
deployBridge();
|
|
1325
|
+
|
|
1186
1326
|
const { detectSystemState, reconcileState, formatReconciliation } = await import('../lib/state.mjs');
|
|
1187
1327
|
const state = detectSystemState();
|
|
1188
1328
|
const reconciled = reconcileState(state);
|
|
@@ -103,7 +103,8 @@ 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"
|
|
107
108
|
},
|
|
108
109
|
body: JSON.stringify({
|
|
109
110
|
model: `openclaw/${agentId}`,
|
package/dist/bridge/cli.js
CHANGED
package/dist/bridge/core.js
CHANGED
package/package.json
CHANGED
package/src/bridge/core.ts
CHANGED