@wipcomputer/wip-ldm-os 0.4.31 → 0.4.33

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.
Files changed (3) hide show
  1. package/SKILL.md +1 -1
  2. package/bin/ldm.js +174 -3
  3. package/package.json +1 -1
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.31"
8
+ version: "0.4.33"
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
@@ -895,9 +895,11 @@ async function cmdInstallCatalog() {
895
895
  // Check parent packages for toolbox-style repos (#132)
896
896
  // If sub-tools are installed but the parent npm package has a newer version,
897
897
  // report the parent as needing an update (not the individual sub-tool).
898
- const checkedNpm = new Set(npmUpdates.map(u => u.catalogNpm));
898
+ // Don't skip packages already found by the extension loop. The parent check
899
+ // REPLACES sub-tool entries with the parent name.
900
+ const checkedParentNpm = new Set();
899
901
  for (const comp of components) {
900
- if (!comp.npm || checkedNpm.has(comp.npm)) continue;
902
+ if (!comp.npm || checkedParentNpm.has(comp.npm)) continue;
901
903
  if (!comp.registryMatches || comp.registryMatches.length === 0) continue;
902
904
 
903
905
  // If any registryMatch is installed, check the parent package
@@ -929,7 +931,7 @@ async function cmdInstallCatalog() {
929
931
  });
930
932
  }
931
933
  } catch {}
932
- checkedNpm.add(comp.npm);
934
+ checkedParentNpm.add(comp.npm);
933
935
  }
934
936
 
935
937
  const totalUpdates = npmUpdates.length;
@@ -1113,6 +1115,9 @@ async function cmdInstallCatalog() {
1113
1115
 
1114
1116
  // Update from npm via catalog repos (#55) and CLIs (#81)
1115
1117
  for (const entry of npmUpdates) {
1118
+ // CLI self-update is handled by the self-update block at the top of cmdInstallCatalog()
1119
+ if (entry.isCLI) continue;
1120
+
1116
1121
  // CLI-only entries: install directly from npm (#81)
1117
1122
  if (entry.cliOnly) {
1118
1123
  console.log(` Updating CLI ${entry.name} v${entry.currentVersion} -> v${entry.latestVersion}...`);
@@ -1133,6 +1138,21 @@ async function cmdInstallCatalog() {
1133
1138
  try {
1134
1139
  execSync(`ldm install ${entry.catalogRepo}`, { stdio: 'inherit' });
1135
1140
  updated++;
1141
+
1142
+ // For parent packages, update registry version for all sub-tools (#139)
1143
+ if (entry.isParent && entry.registryMatches) {
1144
+ const registry = readJSON(REGISTRY_PATH);
1145
+ if (registry?.extensions) {
1146
+ for (const subTool of entry.registryMatches) {
1147
+ if (registry.extensions[subTool]) {
1148
+ registry.extensions[subTool].version = entry.latestVersion;
1149
+ registry.extensions[subTool].updatedAt = new Date().toISOString();
1150
+ }
1151
+ }
1152
+ writeFileSync(REGISTRY_PATH, JSON.stringify(registry, null, 2));
1153
+ console.log(` + Updated registry for ${entry.registryMatches.length} sub-tools`);
1154
+ }
1155
+ }
1136
1156
  } catch (e) {
1137
1157
  console.error(` x Failed to update ${entry.name}: ${e.message}`);
1138
1158
  }
@@ -2366,6 +2386,154 @@ async function main() {
2366
2386
  console.log('');
2367
2387
  }
2368
2388
 
2389
+ // ── ldm worktree ──
2390
+
2391
+ async function cmdWorktree() {
2392
+ const sub = args[1] || 'list';
2393
+
2394
+ if (sub === '--help' || sub === '-h') {
2395
+ console.log(`
2396
+ ldm worktree add <branch> Create worktree in _worktrees/ (auto-detects repo)
2397
+ ldm worktree list List all worktrees across repos
2398
+ ldm worktree clean Prune worktrees for merged branches
2399
+ ldm worktree remove <path> Remove a specific worktree
2400
+ `);
2401
+ process.exit(0);
2402
+ }
2403
+
2404
+ if (sub === 'add') {
2405
+ const branchName = args[2];
2406
+ if (!branchName) {
2407
+ console.error(' Usage: ldm worktree add <branch-name>');
2408
+ console.error(' Example: ldm worktree add cc-mini/fix-bug');
2409
+ process.exit(1);
2410
+ }
2411
+
2412
+ // Auto-detect repo from CWD
2413
+ let repoRoot;
2414
+ try {
2415
+ repoRoot = execSync('git rev-parse --show-toplevel 2>/dev/null', {
2416
+ encoding: 'utf8', timeout: 3000
2417
+ }).trim();
2418
+ } catch {
2419
+ console.error(' Not inside a git repo. cd into a repo first.');
2420
+ process.exit(1);
2421
+ }
2422
+
2423
+ const repoName = basename(repoRoot);
2424
+ const branchSuffix = branchName.replace(/\//g, '--');
2425
+ const worktreesDir = join(dirname(repoRoot), '_worktrees');
2426
+ const worktreePath = join(worktreesDir, `${repoName}--${branchSuffix}`);
2427
+
2428
+ mkdirSync(worktreesDir, { recursive: true });
2429
+
2430
+ console.log(` Creating worktree for ${repoName}...`);
2431
+ console.log(` Branch: ${branchName}`);
2432
+ console.log(` Path: ${worktreePath}`);
2433
+
2434
+ try {
2435
+ execSync(`git worktree add "${worktreePath}" -b "${branchName}"`, {
2436
+ cwd: repoRoot, stdio: 'inherit'
2437
+ });
2438
+ console.log('');
2439
+ console.log(` Done. Work in: ${worktreePath}`);
2440
+ console.log(` When done: ldm worktree remove "${worktreePath}"`);
2441
+ } catch (e) {
2442
+ console.error(` Failed: ${e.message}`);
2443
+ process.exit(1);
2444
+ }
2445
+ return;
2446
+ }
2447
+
2448
+ if (sub === 'list') {
2449
+ // Find all repos and list their worktrees
2450
+ const reposBase = process.env.LDM_REPOS || process.cwd();
2451
+ let found = 0;
2452
+
2453
+ // Check CWD repo
2454
+ try {
2455
+ const root = execSync('git rev-parse --show-toplevel 2>/dev/null', {
2456
+ encoding: 'utf8', timeout: 3000
2457
+ }).trim();
2458
+ const result = execSync('git worktree list', {
2459
+ cwd: root, encoding: 'utf8', timeout: 5000
2460
+ }).trim();
2461
+ if (result.split('\n').length > 1) {
2462
+ console.log(` ${basename(root)}:`);
2463
+ for (const line of result.split('\n')) {
2464
+ console.log(` ${line}`);
2465
+ }
2466
+ found++;
2467
+ }
2468
+ } catch {}
2469
+
2470
+ // Also check _worktrees/ dir
2471
+ const worktreesDir = join(dirname(process.cwd()), '_worktrees');
2472
+ if (existsSync(worktreesDir)) {
2473
+ try {
2474
+ const entries = readdirSync(worktreesDir, { withFileTypes: true })
2475
+ .filter(d => d.isDirectory());
2476
+ if (entries.length > 0) {
2477
+ console.log(` _worktrees/:`);
2478
+ for (const d of entries) {
2479
+ console.log(` ${d.name}`);
2480
+ }
2481
+ found++;
2482
+ }
2483
+ } catch {}
2484
+ }
2485
+
2486
+ if (found === 0) {
2487
+ console.log(' No active worktrees found.');
2488
+ }
2489
+ return;
2490
+ }
2491
+
2492
+ if (sub === 'remove') {
2493
+ const wtPath = args[2];
2494
+ if (!wtPath) {
2495
+ console.error(' Usage: ldm worktree remove <path>');
2496
+ process.exit(1);
2497
+ }
2498
+ try {
2499
+ // Find the repo root for this worktree
2500
+ const root = execSync('git rev-parse --show-toplevel 2>/dev/null', {
2501
+ cwd: resolve(wtPath), encoding: 'utf8', timeout: 3000
2502
+ }).trim();
2503
+ const mainRoot = execSync('git -C "' + root + '" worktree list --porcelain 2>/dev/null', {
2504
+ encoding: 'utf8', timeout: 5000
2505
+ }).split('\n').find(l => l.startsWith('worktree '))?.replace('worktree ', '');
2506
+
2507
+ execSync(`git worktree remove "${resolve(wtPath)}"`, {
2508
+ cwd: mainRoot || root, stdio: 'inherit'
2509
+ });
2510
+ console.log(` Removed worktree: ${wtPath}`);
2511
+ } catch (e) {
2512
+ console.error(` Failed: ${e.message}`);
2513
+ process.exit(1);
2514
+ }
2515
+ return;
2516
+ }
2517
+
2518
+ if (sub === 'clean') {
2519
+ console.log(' Pruning stale worktrees...');
2520
+ try {
2521
+ const root = execSync('git rev-parse --show-toplevel 2>/dev/null', {
2522
+ encoding: 'utf8', timeout: 3000
2523
+ }).trim();
2524
+ execSync('git worktree prune', { cwd: root, stdio: 'inherit' });
2525
+ console.log(' Done.');
2526
+ } catch (e) {
2527
+ console.error(` Failed: ${e.message}`);
2528
+ }
2529
+ return;
2530
+ }
2531
+
2532
+ console.error(` Unknown subcommand: ${sub}`);
2533
+ console.error(' Run: ldm worktree --help');
2534
+ process.exit(1);
2535
+ }
2536
+
2369
2537
  if (command === '--version' || command === '-v') {
2370
2538
  console.log(PKG_VERSION);
2371
2539
  process.exit(0);
@@ -2412,6 +2580,9 @@ async function main() {
2412
2580
  case 'uninstall':
2413
2581
  await cmdUninstall();
2414
2582
  break;
2583
+ case 'worktree':
2584
+ await cmdWorktree();
2585
+ break;
2415
2586
  default:
2416
2587
  console.error(` Unknown command: ${command}`);
2417
2588
  console.error(` Run: ldm --help`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipcomputer/wip-ldm-os",
3
- "version": "0.4.31",
3
+ "version": "0.4.33",
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",