@wipcomputer/wip-ldm-os 0.4.32 → 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 +169 -0
  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.32"
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
@@ -1115,6 +1115,9 @@ async function cmdInstallCatalog() {
1115
1115
 
1116
1116
  // Update from npm via catalog repos (#55) and CLIs (#81)
1117
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
+
1118
1121
  // CLI-only entries: install directly from npm (#81)
1119
1122
  if (entry.cliOnly) {
1120
1123
  console.log(` Updating CLI ${entry.name} v${entry.currentVersion} -> v${entry.latestVersion}...`);
@@ -1135,6 +1138,21 @@ async function cmdInstallCatalog() {
1135
1138
  try {
1136
1139
  execSync(`ldm install ${entry.catalogRepo}`, { stdio: 'inherit' });
1137
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
+ }
1138
1156
  } catch (e) {
1139
1157
  console.error(` x Failed to update ${entry.name}: ${e.message}`);
1140
1158
  }
@@ -2368,6 +2386,154 @@ async function main() {
2368
2386
  console.log('');
2369
2387
  }
2370
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
+
2371
2537
  if (command === '--version' || command === '-v') {
2372
2538
  console.log(PKG_VERSION);
2373
2539
  process.exit(0);
@@ -2414,6 +2580,9 @@ async function main() {
2414
2580
  case 'uninstall':
2415
2581
  await cmdUninstall();
2416
2582
  break;
2583
+ case 'worktree':
2584
+ await cmdWorktree();
2585
+ break;
2417
2586
  default:
2418
2587
  console.error(` Unknown command: ${command}`);
2419
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.32",
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",