@wipcomputer/wip-ldm-os 0.4.15 → 0.4.16
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 +84 -2
- package/catalog.json +2 -2
- package/lib/deploy.mjs +16 -2
- package/package.json +1 -1
package/SKILL.md
CHANGED
package/bin/ldm.js
CHANGED
|
@@ -447,6 +447,23 @@ async function cmdInstall() {
|
|
|
447
447
|
|
|
448
448
|
setFlags({ dryRun: DRY_RUN, jsonOutput: JSON_OUTPUT });
|
|
449
449
|
|
|
450
|
+
// --help flag (#81)
|
|
451
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
452
|
+
console.log(`
|
|
453
|
+
ldm install Update all registered extensions + CLIs
|
|
454
|
+
ldm install <org/repo> Install from GitHub
|
|
455
|
+
ldm install <npm-package> Install from npm
|
|
456
|
+
ldm install <path> Install from local directory
|
|
457
|
+
|
|
458
|
+
Flags:
|
|
459
|
+
--dry-run Show what would change, don't install
|
|
460
|
+
--json JSON output
|
|
461
|
+
--yes Auto-accept catalog prompts
|
|
462
|
+
--none Skip catalog prompts
|
|
463
|
+
`);
|
|
464
|
+
process.exit(0);
|
|
465
|
+
}
|
|
466
|
+
|
|
450
467
|
// Find the target (skip flags)
|
|
451
468
|
const target = args.slice(1).find(a => !a.startsWith('--'));
|
|
452
469
|
|
|
@@ -493,6 +510,11 @@ async function cmdInstall() {
|
|
|
493
510
|
}
|
|
494
511
|
|
|
495
512
|
await installFromPath(repoPath);
|
|
513
|
+
|
|
514
|
+
// Clean up /tmp/ clone after install (#32)
|
|
515
|
+
if (!DRY_RUN && (repoPath.startsWith('/tmp/') || repoPath.startsWith('/private/tmp/'))) {
|
|
516
|
+
try { execSync(`rm -rf "${repoPath}"`, { stdio: 'pipe' }); } catch {}
|
|
517
|
+
}
|
|
496
518
|
return;
|
|
497
519
|
}
|
|
498
520
|
|
|
@@ -570,6 +592,11 @@ async function cmdInstall() {
|
|
|
570
592
|
}
|
|
571
593
|
|
|
572
594
|
await installFromPath(repoPath);
|
|
595
|
+
|
|
596
|
+
// Clean up /tmp/ clone after install (#32)
|
|
597
|
+
if (!DRY_RUN && (repoPath.startsWith('/tmp/') || repoPath.startsWith('/private/tmp/'))) {
|
|
598
|
+
try { execSync(`rm -rf "${repoPath}"`, { stdio: 'pipe' }); } catch {}
|
|
599
|
+
}
|
|
573
600
|
}
|
|
574
601
|
|
|
575
602
|
// ── Auto-detect unregistered extensions ──
|
|
@@ -689,6 +716,16 @@ async function cmdInstallCatalog() {
|
|
|
689
716
|
return matches.includes(name) || c.id === name;
|
|
690
717
|
});
|
|
691
718
|
|
|
719
|
+
// Fallback: use repository.url from extension's package.json (#82)
|
|
720
|
+
let repoUrl = catalogEntry?.repo || null;
|
|
721
|
+
if (!repoUrl && extPkg?.repository) {
|
|
722
|
+
const raw = typeof extPkg.repository === 'string'
|
|
723
|
+
? extPkg.repository
|
|
724
|
+
: extPkg.repository.url || '';
|
|
725
|
+
const ghMatch = raw.match(/github\.com[:/]([^/]+\/[^/.]+)/);
|
|
726
|
+
if (ghMatch) repoUrl = ghMatch[1];
|
|
727
|
+
}
|
|
728
|
+
|
|
692
729
|
const currentVersion = entry.ldmVersion || entry.ocVersion;
|
|
693
730
|
if (!currentVersion) continue;
|
|
694
731
|
|
|
@@ -700,7 +737,7 @@ async function cmdInstallCatalog() {
|
|
|
700
737
|
if (latestVersion && latestVersion !== currentVersion) {
|
|
701
738
|
npmUpdates.push({
|
|
702
739
|
...entry,
|
|
703
|
-
catalogRepo:
|
|
740
|
+
catalogRepo: repoUrl,
|
|
704
741
|
catalogNpm: npmPkg,
|
|
705
742
|
currentVersion,
|
|
706
743
|
latestVersion,
|
|
@@ -710,6 +747,39 @@ async function cmdInstallCatalog() {
|
|
|
710
747
|
} catch {}
|
|
711
748
|
}
|
|
712
749
|
|
|
750
|
+
// Check global CLIs not tracked by extension loop (#81)
|
|
751
|
+
for (const [binName, binInfo] of Object.entries(state.cliBinaries || {})) {
|
|
752
|
+
const catalogComp = components.find(c =>
|
|
753
|
+
(c.cliMatches || []).includes(binName)
|
|
754
|
+
);
|
|
755
|
+
if (!catalogComp || !catalogComp.npm) continue;
|
|
756
|
+
// Skip if already covered by extension loop
|
|
757
|
+
if (npmUpdates.some(e =>
|
|
758
|
+
e.catalogNpm === catalogComp.npm ||
|
|
759
|
+
(catalogComp.registryMatches || []).includes(e.name)
|
|
760
|
+
)) continue;
|
|
761
|
+
|
|
762
|
+
const currentVersion = binInfo.version;
|
|
763
|
+
if (!currentVersion) continue;
|
|
764
|
+
|
|
765
|
+
try {
|
|
766
|
+
const latestVersion = execSync(`npm view ${catalogComp.npm} version 2>/dev/null`, {
|
|
767
|
+
encoding: 'utf8', timeout: 10000,
|
|
768
|
+
}).trim();
|
|
769
|
+
if (latestVersion && latestVersion !== currentVersion) {
|
|
770
|
+
npmUpdates.push({
|
|
771
|
+
name: binName,
|
|
772
|
+
catalogRepo: catalogComp.repo,
|
|
773
|
+
catalogNpm: catalogComp.npm,
|
|
774
|
+
currentVersion,
|
|
775
|
+
latestVersion,
|
|
776
|
+
hasUpdate: true,
|
|
777
|
+
cliOnly: true,
|
|
778
|
+
});
|
|
779
|
+
}
|
|
780
|
+
} catch {}
|
|
781
|
+
}
|
|
782
|
+
|
|
713
783
|
const totalUpdates = npmUpdates.length;
|
|
714
784
|
|
|
715
785
|
if (DRY_RUN) {
|
|
@@ -802,8 +872,20 @@ async function cmdInstallCatalog() {
|
|
|
802
872
|
|
|
803
873
|
let updated = 0;
|
|
804
874
|
|
|
805
|
-
// Update from npm via catalog repos (#55)
|
|
875
|
+
// Update from npm via catalog repos (#55) and CLIs (#81)
|
|
806
876
|
for (const entry of npmUpdates) {
|
|
877
|
+
// CLI-only entries: install directly from npm (#81)
|
|
878
|
+
if (entry.cliOnly) {
|
|
879
|
+
console.log(` Updating CLI ${entry.name} v${entry.currentVersion} -> v${entry.latestVersion}...`);
|
|
880
|
+
try {
|
|
881
|
+
execSync(`npm install -g ${entry.catalogNpm}@${entry.latestVersion}`, { stdio: 'inherit' });
|
|
882
|
+
updated++;
|
|
883
|
+
} catch (e) {
|
|
884
|
+
console.error(` x Failed to update CLI ${entry.name}: ${e.message}`);
|
|
885
|
+
}
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
|
|
807
889
|
if (!entry.catalogRepo) {
|
|
808
890
|
console.log(` Skipping ${entry.name}: no catalog repo (install manually with ldm install <org/repo>)`);
|
|
809
891
|
continue;
|
package/catalog.json
CHANGED
|
@@ -53,8 +53,8 @@
|
|
|
53
53
|
"description": "Release pipeline, license compliance, repo management, identity file protection.",
|
|
54
54
|
"npm": "@wipcomputer/universal-installer",
|
|
55
55
|
"repo": "wipcomputer/wip-ai-devops-toolbox",
|
|
56
|
-
"registryMatches": ["wip-repos", "wip-release", "wip-file-guard", "wip-license-hook", "wip-repo-permissions-hook", "universal-installer", "deploy-public", "post-merge-rename", "wip-license-guard", "wip-repo-init", "wip-readme-format"],
|
|
57
|
-
"cliMatches": ["wip-release", "wip-repos", "wip-file-guard", "wip-install"],
|
|
56
|
+
"registryMatches": ["wip-repos", "wip-release", "wip-file-guard", "wip-license-hook", "wip-repo-permissions-hook", "universal-installer", "deploy-public", "post-merge-rename", "wip-license-guard", "wip-repo-init", "wip-readme-format", "wip-branch-guard"],
|
|
57
|
+
"cliMatches": ["wip-release", "wip-repos", "wip-file-guard", "wip-install", "wip-branch-guard"],
|
|
58
58
|
"recommended": false,
|
|
59
59
|
"status": "stable",
|
|
60
60
|
"postInstall": null,
|
package/lib/deploy.mjs
CHANGED
|
@@ -372,11 +372,25 @@ function installCLI(repoPath, door) {
|
|
|
372
372
|
return true;
|
|
373
373
|
}
|
|
374
374
|
} catch {
|
|
375
|
-
// Registry check failed, fall through
|
|
375
|
+
// Registry check failed, fall through
|
|
376
376
|
}
|
|
377
|
+
|
|
378
|
+
// Exact version not on npm. Try latest from registry instead of local install (#32, #81)
|
|
379
|
+
try {
|
|
380
|
+
const latestVersion = execSync(`npm view ${packageName} version 2>/dev/null`, {
|
|
381
|
+
encoding: 'utf8', timeout: 15000,
|
|
382
|
+
}).trim();
|
|
383
|
+
if (latestVersion) {
|
|
384
|
+
execSync(`npm install -g ${packageName}@${latestVersion}`, { stdio: 'pipe', timeout: 60000 });
|
|
385
|
+
ensureBinExecutable(binNames);
|
|
386
|
+
ok(`CLI: ${binNames.join(', ')} installed from registry (v${latestVersion}, repo has v${packageVersion})`);
|
|
387
|
+
return true;
|
|
388
|
+
}
|
|
389
|
+
} catch {}
|
|
377
390
|
}
|
|
378
391
|
|
|
379
|
-
//
|
|
392
|
+
// Last resort: local install (creates symlinks ... warns user)
|
|
393
|
+
console.log(` ! Warning: installing locally from ${repoPath} (creates symlinks to source dir)`);
|
|
380
394
|
try {
|
|
381
395
|
execSync('npm install -g .', { cwd: repoPath, stdio: 'pipe' });
|
|
382
396
|
ensureBinExecutable(binNames);
|