@wipcomputer/wip-ldm-os 0.2.3 → 0.2.5

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 CHANGED
@@ -5,7 +5,7 @@ license: MIT
5
5
  interface: [cli, skill]
6
6
  metadata:
7
7
  display-name: "LDM OS"
8
- version: "0.2.3"
8
+ version: "0.2.5"
9
9
  homepage: "https://github.com/wipcomputer/wip-ldm-os"
10
10
  author: "Parker Todd Brooks"
11
11
  category: infrastructure
@@ -69,12 +69,11 @@ npm install -g @wipcomputer/wip-ldm-os
69
69
  ldm init --dry-run
70
70
  ```
71
71
 
72
- Show the user the dry run output. Explain what each directory is for:
72
+ Show the user the dry run output. Explain what it creates:
73
73
  - `~/.ldm/extensions/` ... where tools and plugins live
74
- - `~/.ldm/agents/` ... agent identity files (SOUL.md, journals, daily logs)
75
- - `~/.ldm/memory/` ... shared memory database
76
- - `~/.ldm/state/` ... watermarks, role config
77
- - `~/.ldm/secrets/` ... encryption keys
74
+ - `~/.ldm/agents/` ... each AI gets its own identity, personality, and memory here
75
+ - `~/.ldm/memory/` ... shared memory across all your AIs
76
+ - `~/.ldm/state/` ... configuration and sync state
78
77
 
79
78
  When the user approves:
80
79
  ```bash
package/bin/ldm.mjs CHANGED
@@ -411,15 +411,26 @@ async function cmdInstallCatalog() {
411
411
  // Show the real system state
412
412
  console.log(formatReconciliation(reconciled));
413
413
 
414
- // Show catalog items not yet managed
414
+ // Check catalog: use registryMatches + cliMatches to detect what's really installed
415
415
  const registry = readJSON(REGISTRY_PATH);
416
416
  const registeredNames = Object.keys(registry?.extensions || {});
417
+ const reconciledNames = Object.keys(reconciled);
417
418
  const components = loadCatalog();
419
+
420
+ function isCatalogItemInstalled(c) {
421
+ // Direct ID match
422
+ if (registeredNames.includes(c.id) || reconciled[c.id]) return true;
423
+ // Check registryMatches (aliases)
424
+ const matches = c.registryMatches || [];
425
+ if (matches.some(m => registeredNames.includes(m) || reconciled[m])) return true;
426
+ // Check CLI binaries
427
+ const cliMatches = c.cliMatches || [];
428
+ if (cliMatches.some(b => state.cliBinaries[b])) return true;
429
+ return false;
430
+ }
431
+
418
432
  const available = components.filter(c =>
419
- c.status !== 'coming-soon'
420
- && !registeredNames.includes(c.id)
421
- // Also check if it's in reconciled as external (already installed outside LDM)
422
- && !reconciled[c.id]
433
+ c.status !== 'coming-soon' && !isCatalogItemInstalled(c)
423
434
  );
424
435
 
425
436
  if (available.length > 0) {
@@ -428,29 +439,23 @@ async function cmdInstallCatalog() {
428
439
  console.log(` [ ] ${c.name} ... ${c.description}`);
429
440
  }
430
441
  console.log('');
442
+ } else {
443
+ console.log(' All catalog components are installed.');
444
+ console.log('');
431
445
  }
432
446
 
433
447
  if (DRY_RUN) {
434
448
  // Show what an update would do
435
449
  const updatable = Object.values(reconciled).filter(e =>
436
- e.status === 'healthy' && e.registryHasSource
437
- );
438
- const unlinked = Object.values(reconciled).filter(e =>
439
- e.status === 'installed-unlinked'
450
+ e.registryHasSource
440
451
  );
441
452
 
442
453
  if (updatable.length > 0) {
443
454
  console.log(` Would update ${updatable.length} extension(s) from source repos.`);
444
- console.log(' No data (crystal.db, secrets, agent files) would be touched.');
455
+ console.log(' No data (crystal.db, agent files) would be touched.');
445
456
  console.log(' Old versions would be moved to ~/.ldm/_trash/ (never deleted).');
446
457
  } else {
447
- console.log(' Nothing to update from source repos.');
448
- }
449
-
450
- if (unlinked.length > 0) {
451
- console.log('');
452
- console.log(` ${unlinked.length} extension(s) are installed but have no source repo linked.`);
453
- console.log(' These are safe. Link them with: ldm install <org/repo>');
458
+ console.log(' Everything is up to date. No changes needed.');
454
459
  }
455
460
 
456
461
  console.log('');
package/catalog.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.1.0",
2
+ "version": "0.2.0",
3
3
  "components": [
4
4
  {
5
5
  "id": "memory-crystal",
@@ -7,6 +7,8 @@
7
7
  "description": "Persistent memory for your AI. Search, capture, consolidation.",
8
8
  "npm": "memory-crystal",
9
9
  "repo": "wipcomputer/memory-crystal",
10
+ "registryMatches": ["memory-crystal"],
11
+ "cliMatches": ["crystal"],
10
12
  "recommended": true,
11
13
  "status": "stable",
12
14
  "postInstall": "crystal doctor"
@@ -17,6 +19,8 @@
17
19
  "description": "Release pipeline, license compliance, repo management, identity file protection.",
18
20
  "npm": "@wipcomputer/universal-installer",
19
21
  "repo": "wipcomputer/wip-ai-devops-toolbox",
22
+ "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"],
23
+ "cliMatches": ["wip-release", "wip-repos", "wip-file-guard", "wip-install"],
20
24
  "recommended": false,
21
25
  "status": "stable",
22
26
  "postInstall": null
@@ -27,6 +31,8 @@
27
31
  "description": "1Password secrets for AI agents.",
28
32
  "npm": null,
29
33
  "repo": "wipcomputer/wip-1password",
34
+ "registryMatches": ["wip-1password", "op-secrets"],
35
+ "cliMatches": [],
30
36
  "recommended": false,
31
37
  "status": "stable",
32
38
  "postInstall": null
@@ -37,6 +43,8 @@
37
43
  "description": "Live markdown viewer for AI pair-editing. Updates render instantly in any browser.",
38
44
  "npm": "@wipcomputer/markdown-viewer",
39
45
  "repo": "wipcomputer/wip-markdown-viewer",
46
+ "registryMatches": ["wip-markdown-viewer", "markdown-viewer"],
47
+ "cliMatches": ["mdview"],
40
48
  "recommended": false,
41
49
  "status": "stable",
42
50
  "postInstall": null
@@ -47,6 +55,8 @@
47
55
  "description": "xAI Grok API. Search the web, search X, generate images, generate video.",
48
56
  "npm": null,
49
57
  "repo": "wipcomputer/wip-xai-grok",
58
+ "registryMatches": ["wip-xai-grok", "grok-search"],
59
+ "cliMatches": [],
50
60
  "recommended": false,
51
61
  "status": "stable",
52
62
  "postInstall": null
@@ -57,6 +67,8 @@
57
67
  "description": "X Platform API. Read posts, search tweets, post, upload media.",
58
68
  "npm": null,
59
69
  "repo": "wipcomputer/wip-xai-x",
70
+ "registryMatches": ["wip-xai-x"],
71
+ "cliMatches": [],
60
72
  "recommended": false,
61
73
  "status": "stable",
62
74
  "postInstall": null
@@ -67,6 +79,8 @@
67
79
  "description": "AI agent platform. Run AI agents 24/7 with identity, memory, and tool access.",
68
80
  "npm": null,
69
81
  "repo": "openclaw/openclaw",
82
+ "registryMatches": ["openclaw"],
83
+ "cliMatches": ["openclaw"],
70
84
  "recommended": false,
71
85
  "status": "stable",
72
86
  "postInstall": null
@@ -74,9 +88,11 @@
74
88
  {
75
89
  "id": "dream-weaver-protocol",
76
90
  "name": "Dream Weaver Protocol",
77
- "description": "Memory consolidation protocol for AI agents with bounded context windows. A practical guide for remembering memories.",
91
+ "description": "Memory consolidation protocol for AI agents with bounded context windows.",
78
92
  "npm": null,
79
93
  "repo": "wipcomputer/dream-weaver-protocol",
94
+ "registryMatches": ["dream-weaver-protocol", "dream-weaver"],
95
+ "cliMatches": [],
80
96
  "recommended": false,
81
97
  "status": "stable",
82
98
  "postInstall": null
@@ -87,6 +103,8 @@
87
103
  "description": "Cross-platform agent bridge. Enables Claude Code CLI to talk to OpenClaw CLI without a human in the middle.",
88
104
  "npm": null,
89
105
  "repo": "wipcomputer/wip-bridge",
106
+ "registryMatches": ["wip-bridge", "lesa-bridge"],
107
+ "cliMatches": [],
90
108
  "recommended": false,
91
109
  "status": "stable",
92
110
  "postInstall": null
package/lib/state.mjs CHANGED
@@ -223,25 +223,19 @@ export function reconcileState(systemState) {
223
223
  // ── Display ──
224
224
 
225
225
  export function formatReconciliation(reconciled, { verbose = false } = {}) {
226
- const healthy = [];
227
- const unlinked = [];
228
- const needsAttention = [];
229
- const external = [];
226
+ const installed = [];
227
+ const broken = [];
230
228
 
231
229
  for (const entry of Object.values(reconciled)) {
232
- switch (entry.status) {
233
- case 'healthy':
234
- healthy.push(entry);
235
- break;
236
- case 'installed-unlinked':
237
- unlinked.push(entry);
238
- break;
239
- case 'mcp-only':
240
- case 'deployed-unregistered':
241
- external.push(entry);
242
- break;
243
- default:
244
- needsAttention.push(entry);
230
+ // Hide internal registry issues from normal output
231
+ if (entry.status === 'registered-missing') {
232
+ if (verbose) broken.push(entry);
233
+ continue;
234
+ }
235
+
236
+ // Everything that's actually deployed, registered, or has an MCP server = installed
237
+ if (entry.deployedLdm || entry.deployedOc || entry.mcpRegistered || entry.inRegistry) {
238
+ installed.push(entry);
245
239
  }
246
240
  }
247
241
 
@@ -252,52 +246,21 @@ export function formatReconciliation(reconciled, { verbose = false } = {}) {
252
246
  lines.push(' System State');
253
247
  lines.push(' ────────────────────────────────────');
254
248
 
255
- if (healthy.length > 0) {
249
+ if (installed.length > 0) {
256
250
  lines.push('');
257
- lines.push(` Managed by LDM (${healthy.length}):`);
258
- for (const e of healthy.sort(sort)) {
259
- const ver = e.ldmVersion || e.registryVersion || '?';
260
- const ifaces = e.registryInterfaces.length > 0 ? ` (${e.registryInterfaces.join(', ')})` : '';
261
- const mcp = e.mcpRegistered ? ' [MCP]' : '';
262
- lines.push(` [x] ${e.name} v${ver}${ifaces}${mcp}`);
263
- }
264
- }
265
-
266
- if (unlinked.length > 0) {
267
- lines.push('');
268
- lines.push(` Installed, no source repo linked (${unlinked.length}):`);
269
- lines.push(` (These work fine. Link them to enable updates via ldm install.)`);
270
- for (const e of unlinked.sort(sort)) {
251
+ lines.push(` Installed (${installed.length}):`);
252
+ for (const e of installed.sort(sort)) {
271
253
  const ver = e.ldmVersion || e.ocVersion || e.registryVersion || '?';
272
- const mcp = e.mcpRegistered ? ' [MCP]' : '';
273
- lines.push(` [-] ${e.name} v${ver}${mcp}`);
274
- if (verbose) {
275
- for (const issue of e.issues) {
276
- lines.push(` ${issue}`);
277
- }
278
- }
254
+ const mcp = e.mcpRegistered ? ' [MCP connected]' : '';
255
+ lines.push(` [x] ${e.name} v${ver}${mcp}`);
279
256
  }
280
257
  }
281
258
 
282
- if (external.length > 0) {
259
+ if (broken.length > 0) {
283
260
  lines.push('');
284
- lines.push(` Not managed by LDM (${external.length}):`);
285
- for (const e of external.sort(sort)) {
286
- const ver = e.ldmVersion || e.ocVersion || '?';
287
- const detail = e.mcpRegistered ? 'MCP registered' : 'extension deployed';
288
- lines.push(` [ ] ${e.name} v${ver} ... ${detail}`);
289
- }
290
- }
291
-
292
- if (needsAttention.length > 0) {
293
- lines.push('');
294
- lines.push(` Needs attention (${needsAttention.length}):`);
295
- for (const e of needsAttention.sort(sort)) {
296
- const ver = e.ldmVersion || e.ocVersion || e.registryVersion || '?';
297
- lines.push(` [!] ${e.name} v${ver} ... ${e.status}`);
298
- for (const issue of e.issues) {
299
- lines.push(` ${issue}`);
300
- }
261
+ lines.push(` Needs cleanup (${broken.length}):`);
262
+ for (const e of broken.sort(sort)) {
263
+ lines.push(` [!] ${e.name} ... ${e.status}`);
301
264
  }
302
265
  }
303
266
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipcomputer/wip-ldm-os",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
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",