@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 +1 -1
- package/bin/ldm.js +197 -3
- package/catalog.json +17 -0
- package/package.json +1 -1
package/SKILL.md
CHANGED
package/bin/ldm.js
CHANGED
|
@@ -778,10 +778,35 @@ async function cmdInstallCatalog() {
|
|
|
778
778
|
cleaned++;
|
|
779
779
|
continue;
|
|
780
780
|
}
|
|
781
|
-
//
|
|
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
|
|
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
|
|
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
|
}
|