@wipcomputer/wip-ldm-os 0.3.1 → 0.3.2
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 +97 -0
- package/package.json +1 -1
package/SKILL.md
CHANGED
package/bin/ldm.js
CHANGED
|
@@ -68,6 +68,68 @@ function writeJSON(path, data) {
|
|
|
68
68
|
writeFileSync(path, JSON.stringify(data, null, 2) + '\n');
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
// ── CLI version check (#29) ──
|
|
72
|
+
|
|
73
|
+
function checkCliVersion() {
|
|
74
|
+
try {
|
|
75
|
+
const result = execSync('npm view @wipcomputer/wip-ldm-os version 2>/dev/null', {
|
|
76
|
+
encoding: 'utf8',
|
|
77
|
+
timeout: 10000,
|
|
78
|
+
}).trim();
|
|
79
|
+
if (result && result !== PKG_VERSION) {
|
|
80
|
+
console.log('');
|
|
81
|
+
console.log(` CLI is outdated: v${PKG_VERSION} installed, v${result} available.`);
|
|
82
|
+
console.log(` Run: npm install -g @wipcomputer/wip-ldm-os@${result}`);
|
|
83
|
+
}
|
|
84
|
+
} catch {
|
|
85
|
+
// npm check failed, skip silently
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ── Stale hook cleanup (#30) ──
|
|
90
|
+
|
|
91
|
+
function cleanStaleHooks() {
|
|
92
|
+
const settingsPath = join(HOME, '.claude', 'settings.json');
|
|
93
|
+
const settings = readJSON(settingsPath);
|
|
94
|
+
if (!settings?.hooks) return 0;
|
|
95
|
+
|
|
96
|
+
let cleaned = 0;
|
|
97
|
+
|
|
98
|
+
for (const [event, hookGroups] of Object.entries(settings.hooks)) {
|
|
99
|
+
if (!Array.isArray(hookGroups)) continue;
|
|
100
|
+
|
|
101
|
+
// Filter out hook groups where ALL hooks point to non-existent paths
|
|
102
|
+
const original = hookGroups.length;
|
|
103
|
+
settings.hooks[event] = hookGroups.filter(group => {
|
|
104
|
+
const hooks = group.hooks || [];
|
|
105
|
+
if (hooks.length === 0) return true; // keep empty groups (matcher-only)
|
|
106
|
+
|
|
107
|
+
// Check each hook command for stale paths
|
|
108
|
+
const liveHooks = hooks.filter(h => {
|
|
109
|
+
if (!h.command) return true;
|
|
110
|
+
// Extract the path from "node /path/to/file.mjs" or "node \"/path/to/file.mjs\""
|
|
111
|
+
const match = h.command.match(/node\s+"?([^"]+)"?\s*$/);
|
|
112
|
+
if (!match) return true; // keep non-node commands
|
|
113
|
+
const scriptPath = match[1];
|
|
114
|
+
if (existsSync(scriptPath)) return true;
|
|
115
|
+
console.log(` + Removed stale hook: ${event} -> ${scriptPath}`);
|
|
116
|
+
cleaned++;
|
|
117
|
+
return false;
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Keep the group if it still has live hooks
|
|
121
|
+
group.hooks = liveHooks;
|
|
122
|
+
return liveHooks.length > 0;
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (cleaned > 0) {
|
|
127
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n');
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return cleaned;
|
|
131
|
+
}
|
|
132
|
+
|
|
71
133
|
// ── Catalog helpers ──
|
|
72
134
|
|
|
73
135
|
function loadCatalog() {
|
|
@@ -568,6 +630,10 @@ async function cmdInstallCatalog() {
|
|
|
568
630
|
|
|
569
631
|
console.log('');
|
|
570
632
|
console.log(` Updated ${updated}/${updatable.length} extension(s).`);
|
|
633
|
+
|
|
634
|
+
// Check if CLI itself is outdated (#29)
|
|
635
|
+
checkCliVersion();
|
|
636
|
+
|
|
571
637
|
console.log('');
|
|
572
638
|
}
|
|
573
639
|
|
|
@@ -641,6 +707,14 @@ async function cmdDoctor() {
|
|
|
641
707
|
}
|
|
642
708
|
}
|
|
643
709
|
|
|
710
|
+
// --fix: clean stale hook paths in settings.json (#30)
|
|
711
|
+
if (FIX_FLAG) {
|
|
712
|
+
const hooksCleaned = cleanStaleHooks();
|
|
713
|
+
if (hooksCleaned > 0) {
|
|
714
|
+
issues = Math.max(0, issues - hooksCleaned);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
|
|
644
718
|
// 4. Check sacred locations
|
|
645
719
|
const sacred = [
|
|
646
720
|
{ path: join(LDM_ROOT, 'memory'), label: 'memory/' },
|
|
@@ -665,6 +739,29 @@ async function cmdDoctor() {
|
|
|
665
739
|
if (settings?.hooks) {
|
|
666
740
|
const hookCount = Object.values(settings.hooks).reduce((sum, arr) => sum + (arr?.length || 0), 0);
|
|
667
741
|
console.log(` + Claude Code hooks: ${hookCount} configured`);
|
|
742
|
+
|
|
743
|
+
// Check for stale hook paths
|
|
744
|
+
let staleHooks = 0;
|
|
745
|
+
for (const [event, hookGroups] of Object.entries(settings.hooks)) {
|
|
746
|
+
if (!Array.isArray(hookGroups)) continue;
|
|
747
|
+
for (const group of hookGroups) {
|
|
748
|
+
for (const h of (group.hooks || [])) {
|
|
749
|
+
if (!h.command) continue;
|
|
750
|
+
const match = h.command.match(/node\s+"?([^"]+)"?\s*$/);
|
|
751
|
+
if (!match) continue;
|
|
752
|
+
if (!existsSync(match[1])) {
|
|
753
|
+
staleHooks++;
|
|
754
|
+
if (!FIX_FLAG) {
|
|
755
|
+
console.log(` ! Stale hook: ${event} -> ${match[1]}`);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
if (staleHooks > 0 && !FIX_FLAG) {
|
|
762
|
+
console.log(` Run: ldm doctor --fix to clean ${staleHooks} stale hook(s)`);
|
|
763
|
+
issues += staleHooks;
|
|
764
|
+
}
|
|
668
765
|
} else {
|
|
669
766
|
console.log(` - Claude Code hooks: none configured`);
|
|
670
767
|
}
|