@wipcomputer/wip-ldm-os 0.4.32 → 0.4.34

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
@@ -5,7 +5,7 @@ license: MIT
5
5
  interface: [cli, skill]
6
6
  metadata:
7
7
  display-name: "LDM OS"
8
- version: "0.4.32"
8
+ version: "0.4.34"
9
9
  homepage: "https://github.com/wipcomputer/wip-ldm-os"
10
10
  author: "Parker Todd Brooks"
11
11
  category: infrastructure
package/bin/ldm.js CHANGED
@@ -778,10 +778,35 @@ async function cmdInstallCatalog() {
778
778
  cleaned++;
779
779
  continue;
780
780
  }
781
- // Remove ldm-install- prefixed entries (ghost from /tmp/ clones)
781
+ // Rename ldm-install- prefixed entries to clean names (#141)
782
782
  if (name.startsWith('ldm-install-')) {
783
783
  const cleanName = name.replace(/^ldm-install-/, '');
784
+ // Transfer registry entry to clean name
785
+ if (!registry.extensions[cleanName]) {
786
+ registry.extensions[cleanName] = { ...registry.extensions[name] };
787
+ }
784
788
  delete registry.extensions[name];
789
+ // Rename the actual directory if it exists
790
+ if (!DRY_RUN) {
791
+ const ghostDir = join(LDM_EXTENSIONS, name);
792
+ const cleanDir = join(LDM_EXTENSIONS, cleanName);
793
+ if (existsSync(ghostDir) && !existsSync(cleanDir)) {
794
+ try {
795
+ execSync(`mv "${ghostDir}" "${cleanDir}"`, { stdio: 'pipe' });
796
+ } catch {}
797
+ } else if (existsSync(ghostDir) && existsSync(cleanDir)) {
798
+ // Clean version exists, remove ghost
799
+ try { execSync(`rm -rf "${ghostDir}"`, { stdio: 'pipe' }); } catch {}
800
+ }
801
+ // Same for OC extensions
802
+ const ocGhost = join(HOME, '.openclaw', 'extensions', name);
803
+ const ocClean = join(HOME, '.openclaw', 'extensions', cleanName);
804
+ if (existsSync(ocGhost) && !existsSync(ocClean)) {
805
+ try { execSync(`mv "${ocGhost}" "${ocClean}"`, { stdio: 'pipe' }); } catch {}
806
+ } else if (existsSync(ocGhost) && existsSync(ocClean)) {
807
+ try { execSync(`rm -rf "${ocGhost}"`, { stdio: 'pipe' }); } catch {}
808
+ }
809
+ }
785
810
  cleaned++;
786
811
  }
787
812
  }
@@ -820,7 +845,7 @@ async function cmdInstallCatalog() {
820
845
  const extPkgPath = join(LDM_EXTENSIONS, name, 'package.json');
821
846
  const extPkg = readJSON(extPkgPath);
822
847
  const npmPkg = extPkg?.name;
823
- if (!npmPkg || !npmPkg.startsWith('@')) continue; // skip unscoped packages
848
+ if (!npmPkg) continue; // no package name, skip
824
849
 
825
850
  // Find catalog entry for the repo URL (used for clone if update needed)
826
851
  const catalogEntry = components.find(c => {
@@ -1115,6 +1140,9 @@ async function cmdInstallCatalog() {
1115
1140
 
1116
1141
  // Update from npm via catalog repos (#55) and CLIs (#81)
1117
1142
  for (const entry of npmUpdates) {
1143
+ // CLI self-update is handled by the self-update block at the top of cmdInstallCatalog()
1144
+ if (entry.isCLI) continue;
1145
+
1118
1146
  // CLI-only entries: install directly from npm (#81)
1119
1147
  if (entry.cliOnly) {
1120
1148
  console.log(` Updating CLI ${entry.name} v${entry.currentVersion} -> v${entry.latestVersion}...`);
@@ -1135,6 +1163,21 @@ async function cmdInstallCatalog() {
1135
1163
  try {
1136
1164
  execSync(`ldm install ${entry.catalogRepo}`, { stdio: 'inherit' });
1137
1165
  updated++;
1166
+
1167
+ // For parent packages, update registry version for all sub-tools (#139)
1168
+ if (entry.isParent && entry.registryMatches) {
1169
+ const registry = readJSON(REGISTRY_PATH);
1170
+ if (registry?.extensions) {
1171
+ for (const subTool of entry.registryMatches) {
1172
+ if (registry.extensions[subTool]) {
1173
+ registry.extensions[subTool].version = entry.latestVersion;
1174
+ registry.extensions[subTool].updatedAt = new Date().toISOString();
1175
+ }
1176
+ }
1177
+ writeFileSync(REGISTRY_PATH, JSON.stringify(registry, null, 2));
1178
+ console.log(` + Updated registry for ${entry.registryMatches.length} sub-tools`);
1179
+ }
1180
+ }
1138
1181
  } catch (e) {
1139
1182
  console.error(` x Failed to update ${entry.name}: ${e.message}`);
1140
1183
  }
@@ -1475,7 +1518,7 @@ function cmdStatus() {
1475
1518
  const extPkgPath = join(LDM_EXTENSIONS, name, 'package.json');
1476
1519
  const extPkg = readJSON(extPkgPath);
1477
1520
  const npmPkg = extPkg?.name;
1478
- if (!npmPkg || !npmPkg.startsWith('@')) continue;
1521
+ if (!npmPkg) continue;
1479
1522
  const currentVersion = extPkg.version || info.version;
1480
1523
  if (!currentVersion) continue;
1481
1524
  try {
@@ -2368,6 +2411,154 @@ async function main() {
2368
2411
  console.log('');
2369
2412
  }
2370
2413
 
2414
+ // ── ldm worktree ──
2415
+
2416
+ async function cmdWorktree() {
2417
+ const sub = args[1] || 'list';
2418
+
2419
+ if (sub === '--help' || sub === '-h') {
2420
+ console.log(`
2421
+ ldm worktree add <branch> Create worktree in _worktrees/ (auto-detects repo)
2422
+ ldm worktree list List all worktrees across repos
2423
+ ldm worktree clean Prune worktrees for merged branches
2424
+ ldm worktree remove <path> Remove a specific worktree
2425
+ `);
2426
+ process.exit(0);
2427
+ }
2428
+
2429
+ if (sub === 'add') {
2430
+ const branchName = args[2];
2431
+ if (!branchName) {
2432
+ console.error(' Usage: ldm worktree add <branch-name>');
2433
+ console.error(' Example: ldm worktree add cc-mini/fix-bug');
2434
+ process.exit(1);
2435
+ }
2436
+
2437
+ // Auto-detect repo from CWD
2438
+ let repoRoot;
2439
+ try {
2440
+ repoRoot = execSync('git rev-parse --show-toplevel 2>/dev/null', {
2441
+ encoding: 'utf8', timeout: 3000
2442
+ }).trim();
2443
+ } catch {
2444
+ console.error(' Not inside a git repo. cd into a repo first.');
2445
+ process.exit(1);
2446
+ }
2447
+
2448
+ const repoName = basename(repoRoot);
2449
+ const branchSuffix = branchName.replace(/\//g, '--');
2450
+ const worktreesDir = join(dirname(repoRoot), '_worktrees');
2451
+ const worktreePath = join(worktreesDir, `${repoName}--${branchSuffix}`);
2452
+
2453
+ mkdirSync(worktreesDir, { recursive: true });
2454
+
2455
+ console.log(` Creating worktree for ${repoName}...`);
2456
+ console.log(` Branch: ${branchName}`);
2457
+ console.log(` Path: ${worktreePath}`);
2458
+
2459
+ try {
2460
+ execSync(`git worktree add "${worktreePath}" -b "${branchName}"`, {
2461
+ cwd: repoRoot, stdio: 'inherit'
2462
+ });
2463
+ console.log('');
2464
+ console.log(` Done. Work in: ${worktreePath}`);
2465
+ console.log(` When done: ldm worktree remove "${worktreePath}"`);
2466
+ } catch (e) {
2467
+ console.error(` Failed: ${e.message}`);
2468
+ process.exit(1);
2469
+ }
2470
+ return;
2471
+ }
2472
+
2473
+ if (sub === 'list') {
2474
+ // Find all repos and list their worktrees
2475
+ const reposBase = process.env.LDM_REPOS || process.cwd();
2476
+ let found = 0;
2477
+
2478
+ // Check CWD repo
2479
+ try {
2480
+ const root = execSync('git rev-parse --show-toplevel 2>/dev/null', {
2481
+ encoding: 'utf8', timeout: 3000
2482
+ }).trim();
2483
+ const result = execSync('git worktree list', {
2484
+ cwd: root, encoding: 'utf8', timeout: 5000
2485
+ }).trim();
2486
+ if (result.split('\n').length > 1) {
2487
+ console.log(` ${basename(root)}:`);
2488
+ for (const line of result.split('\n')) {
2489
+ console.log(` ${line}`);
2490
+ }
2491
+ found++;
2492
+ }
2493
+ } catch {}
2494
+
2495
+ // Also check _worktrees/ dir
2496
+ const worktreesDir = join(dirname(process.cwd()), '_worktrees');
2497
+ if (existsSync(worktreesDir)) {
2498
+ try {
2499
+ const entries = readdirSync(worktreesDir, { withFileTypes: true })
2500
+ .filter(d => d.isDirectory());
2501
+ if (entries.length > 0) {
2502
+ console.log(` _worktrees/:`);
2503
+ for (const d of entries) {
2504
+ console.log(` ${d.name}`);
2505
+ }
2506
+ found++;
2507
+ }
2508
+ } catch {}
2509
+ }
2510
+
2511
+ if (found === 0) {
2512
+ console.log(' No active worktrees found.');
2513
+ }
2514
+ return;
2515
+ }
2516
+
2517
+ if (sub === 'remove') {
2518
+ const wtPath = args[2];
2519
+ if (!wtPath) {
2520
+ console.error(' Usage: ldm worktree remove <path>');
2521
+ process.exit(1);
2522
+ }
2523
+ try {
2524
+ // Find the repo root for this worktree
2525
+ const root = execSync('git rev-parse --show-toplevel 2>/dev/null', {
2526
+ cwd: resolve(wtPath), encoding: 'utf8', timeout: 3000
2527
+ }).trim();
2528
+ const mainRoot = execSync('git -C "' + root + '" worktree list --porcelain 2>/dev/null', {
2529
+ encoding: 'utf8', timeout: 5000
2530
+ }).split('\n').find(l => l.startsWith('worktree '))?.replace('worktree ', '');
2531
+
2532
+ execSync(`git worktree remove "${resolve(wtPath)}"`, {
2533
+ cwd: mainRoot || root, stdio: 'inherit'
2534
+ });
2535
+ console.log(` Removed worktree: ${wtPath}`);
2536
+ } catch (e) {
2537
+ console.error(` Failed: ${e.message}`);
2538
+ process.exit(1);
2539
+ }
2540
+ return;
2541
+ }
2542
+
2543
+ if (sub === 'clean') {
2544
+ console.log(' Pruning stale worktrees...');
2545
+ try {
2546
+ const root = execSync('git rev-parse --show-toplevel 2>/dev/null', {
2547
+ encoding: 'utf8', timeout: 3000
2548
+ }).trim();
2549
+ execSync('git worktree prune', { cwd: root, stdio: 'inherit' });
2550
+ console.log(' Done.');
2551
+ } catch (e) {
2552
+ console.error(` Failed: ${e.message}`);
2553
+ }
2554
+ return;
2555
+ }
2556
+
2557
+ console.error(` Unknown subcommand: ${sub}`);
2558
+ console.error(' Run: ldm worktree --help');
2559
+ process.exit(1);
2560
+ }
2561
+
2371
2562
  if (command === '--version' || command === '-v') {
2372
2563
  console.log(PKG_VERSION);
2373
2564
  process.exit(0);
@@ -2414,6 +2605,9 @@ async function main() {
2414
2605
  case 'uninstall':
2415
2606
  await cmdUninstall();
2416
2607
  break;
2608
+ case 'worktree':
2609
+ await cmdWorktree();
2610
+ break;
2417
2611
  default:
2418
2612
  console.error(` Unknown command: ${command}`);
2419
2613
  console.error(` Run: ldm --help`);
package/catalog.json CHANGED
@@ -281,6 +281,23 @@
281
281
  "skill": "SKILL.md (protocol documentation for agents)",
282
282
  "docs": "19-page paper on memory consolidation. No runtime components."
283
283
  }
284
+ },
285
+ {
286
+ "id": "tavily",
287
+ "name": "Tavily",
288
+ "description": "Web search and content extraction via Tavily API.",
289
+ "npm": "tavily",
290
+ "repo": null,
291
+ "registryMatches": [
292
+ "tavily"
293
+ ],
294
+ "cliMatches": [],
295
+ "recommended": false,
296
+ "status": "stable",
297
+ "postInstall": null,
298
+ "installs": {
299
+ "ocPlugin": "Web search and content extraction"
300
+ }
284
301
  }
285
302
  ]
286
303
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipcomputer/wip-ldm-os",
3
- "version": "0.4.32",
3
+ "version": "0.4.34",
4
4
  "type": "module",
5
5
  "description": "LDM OS: identity, memory, and sovereignty infrastructure for AI agents",
6
6
  "main": "src/boot/boot-hook.mjs",