@wipcomputer/wip-ldm-os 0.4.59 → 0.4.61
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 +63 -10
- package/catalog.json +1 -1
- package/package.json +1 -1
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.61"
|
|
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
|
@@ -229,22 +229,75 @@ function loadCatalog() {
|
|
|
229
229
|
|
|
230
230
|
function findInCatalog(id) {
|
|
231
231
|
const q = id.toLowerCase();
|
|
232
|
+
// Strip org/ prefix for matching (e.g. "wipcomputer/openclaw-tavily" -> "openclaw-tavily")
|
|
233
|
+
const qBase = q.includes('/') ? q.split('/').pop() : q;
|
|
232
234
|
const catalog = loadCatalog();
|
|
233
235
|
// Exact id match
|
|
234
|
-
const exact = catalog.find(c => c.id === id);
|
|
236
|
+
const exact = catalog.find(c => c.id === id || c.id === qBase);
|
|
235
237
|
if (exact) return exact;
|
|
238
|
+
// Exact repo match (e.g. "wipcomputer/openclaw-tavily" matches repo field directly)
|
|
239
|
+
const byRepo = catalog.find(c => c.repo && c.repo.toLowerCase() === q);
|
|
240
|
+
if (byRepo) return byRepo;
|
|
236
241
|
// Partial id match (e.g. "xai-grok" matches "wip-xai-grok")
|
|
237
|
-
|
|
242
|
+
// Check both directions but require word-boundary alignment (hyphen or start of string)
|
|
243
|
+
// to prevent "openclaw" matching "openclaw-tavily"
|
|
244
|
+
const partial = catalog.find(c => {
|
|
245
|
+
const cid = c.id.toLowerCase();
|
|
246
|
+
if (cid === qBase) return false;
|
|
247
|
+
// Query is suffix of catalog id: "xai-grok" matches "wip-xai-grok"
|
|
248
|
+
if (cid.endsWith(qBase) && (cid.length === qBase.length || cid[cid.length - qBase.length - 1] === '-')) return true;
|
|
249
|
+
// Catalog id is suffix of query: "wip-xai-grok" matches when query is "wip-xai-grok-private"
|
|
250
|
+
if (qBase.endsWith(cid) && (qBase.length === cid.length || qBase[qBase.length - cid.length - 1] === '-')) return true;
|
|
251
|
+
return false;
|
|
252
|
+
});
|
|
238
253
|
if (partial) return partial;
|
|
239
254
|
// Name match (case-insensitive, e.g. "xAI Grok")
|
|
240
255
|
const byName = catalog.find(c => c.name && c.name.toLowerCase() === q);
|
|
241
256
|
if (byName) return byName;
|
|
242
257
|
// registryMatches match
|
|
243
|
-
const byRegistry = catalog.find(c => (c.registryMatches || []).some(m => m.toLowerCase() === q));
|
|
258
|
+
const byRegistry = catalog.find(c => (c.registryMatches || []).some(m => m.toLowerCase() === q || m.toLowerCase() === qBase));
|
|
244
259
|
if (byRegistry) return byRegistry;
|
|
245
260
|
return null;
|
|
246
261
|
}
|
|
247
262
|
|
|
263
|
+
// Install a single catalog component directly (no subprocess).
|
|
264
|
+
// Replaces the old execSync('ldm install ${c.repo}') which spawned
|
|
265
|
+
// a full installer process for each component.
|
|
266
|
+
async function installCatalogComponent(c) {
|
|
267
|
+
const { installFromPath } = await import('../lib/deploy.mjs');
|
|
268
|
+
const repoTarget = c.repo;
|
|
269
|
+
const repoName = basename(repoTarget);
|
|
270
|
+
const repoPath = join(LDM_TMP, repoName);
|
|
271
|
+
const httpsUrl = `https://github.com/${repoTarget}.git`;
|
|
272
|
+
const sshUrl = `git@github.com:${repoTarget}.git`;
|
|
273
|
+
|
|
274
|
+
mkdirSync(LDM_TMP, { recursive: true });
|
|
275
|
+
console.log(` Cloning ${repoTarget}...`);
|
|
276
|
+
try {
|
|
277
|
+
if (existsSync(repoPath)) {
|
|
278
|
+
execSync(`rm -rf "${repoPath}"`, { stdio: 'pipe' });
|
|
279
|
+
}
|
|
280
|
+
try {
|
|
281
|
+
execSync(`git clone --depth 1 "${httpsUrl}" "${repoPath}"`, { stdio: 'pipe' });
|
|
282
|
+
} catch {
|
|
283
|
+
console.log(` HTTPS failed. Trying SSH...`);
|
|
284
|
+
if (existsSync(repoPath)) execSync(`rm -rf "${repoPath}"`, { stdio: 'pipe' });
|
|
285
|
+
execSync(`git clone --depth 1 "${sshUrl}" "${repoPath}"`, { stdio: 'pipe' });
|
|
286
|
+
}
|
|
287
|
+
} catch (e) {
|
|
288
|
+
console.error(` x Clone failed: ${e.message}`);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
await installFromPath(repoPath);
|
|
293
|
+
|
|
294
|
+
// Clean up staging clone
|
|
295
|
+
if (repoPath.startsWith(LDM_TMP)) {
|
|
296
|
+
try { execSync(`rm -rf "${repoPath}"`, { stdio: 'pipe' }); } catch {}
|
|
297
|
+
}
|
|
298
|
+
console.log(` ✓ Installed ${c.name}`);
|
|
299
|
+
}
|
|
300
|
+
|
|
248
301
|
// ── ldm init ──
|
|
249
302
|
|
|
250
303
|
async function cmdInit() {
|
|
@@ -669,7 +722,7 @@ async function showCatalogPicker() {
|
|
|
669
722
|
for (const c of recommended) {
|
|
670
723
|
console.log(` Installing ${c.name}...`);
|
|
671
724
|
try {
|
|
672
|
-
|
|
725
|
+
await installCatalogComponent(c);
|
|
673
726
|
} catch (e) {
|
|
674
727
|
console.error(` x Failed to install ${c.name}: ${e.message}`);
|
|
675
728
|
}
|
|
@@ -705,7 +758,7 @@ async function showCatalogPicker() {
|
|
|
705
758
|
console.log('');
|
|
706
759
|
console.log(` Installing ${c.name}...`);
|
|
707
760
|
try {
|
|
708
|
-
|
|
761
|
+
await installCatalogComponent(c);
|
|
709
762
|
} catch (e) {
|
|
710
763
|
console.error(` x Failed to install ${c.name}: ${e.message}`);
|
|
711
764
|
}
|
|
@@ -2727,7 +2780,7 @@ async function main() {
|
|
|
2727
2780
|
|
|
2728
2781
|
if (sub === '--help' || sub === '-h') {
|
|
2729
2782
|
console.log(`
|
|
2730
|
-
ldm worktree add <branch> Create worktree in
|
|
2783
|
+
ldm worktree add <branch> Create worktree in .worktrees/ (auto-detects repo)
|
|
2731
2784
|
ldm worktree list List all worktrees across repos
|
|
2732
2785
|
ldm worktree clean Prune worktrees for merged branches
|
|
2733
2786
|
ldm worktree remove <path> Remove a specific worktree
|
|
@@ -2756,7 +2809,7 @@ async function main() {
|
|
|
2756
2809
|
|
|
2757
2810
|
const repoName = basename(repoRoot);
|
|
2758
2811
|
const branchSuffix = branchName.replace(/\//g, '--');
|
|
2759
|
-
const worktreesDir = join(dirname(repoRoot), '
|
|
2812
|
+
const worktreesDir = join(dirname(repoRoot), '.worktrees');
|
|
2760
2813
|
const worktreePath = join(worktreesDir, `${repoName}--${branchSuffix}`);
|
|
2761
2814
|
|
|
2762
2815
|
mkdirSync(worktreesDir, { recursive: true });
|
|
@@ -2801,14 +2854,14 @@ async function main() {
|
|
|
2801
2854
|
}
|
|
2802
2855
|
} catch {}
|
|
2803
2856
|
|
|
2804
|
-
// Also check
|
|
2805
|
-
const worktreesDir = join(dirname(process.cwd()), '
|
|
2857
|
+
// Also check .worktrees/ dir
|
|
2858
|
+
const worktreesDir = join(dirname(process.cwd()), '.worktrees');
|
|
2806
2859
|
if (existsSync(worktreesDir)) {
|
|
2807
2860
|
try {
|
|
2808
2861
|
const entries = readdirSync(worktreesDir, { withFileTypes: true })
|
|
2809
2862
|
.filter(d => d.isDirectory());
|
|
2810
2863
|
if (entries.length > 0) {
|
|
2811
|
-
console.log(`
|
|
2864
|
+
console.log(` .worktrees/:`);
|
|
2812
2865
|
for (const d of entries) {
|
|
2813
2866
|
console.log(` ${d.name}`);
|
|
2814
2867
|
}
|
package/catalog.json
CHANGED
|
@@ -286,7 +286,7 @@
|
|
|
286
286
|
"id": "tavily",
|
|
287
287
|
"name": "Tavily",
|
|
288
288
|
"description": "Web search and content extraction via Tavily API.",
|
|
289
|
-
"npm": "tavily",
|
|
289
|
+
"npm": "@wipcomputer/openclaw-tavily",
|
|
290
290
|
"repo": "wipcomputer/openclaw-tavily",
|
|
291
291
|
"registryMatches": [
|
|
292
292
|
"tavily"
|