@wipcomputer/wip-ldm-os 0.4.62 → 0.4.63

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
@@ -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.62"
12
+ version: "0.4.63"
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
@@ -226,6 +226,22 @@ function cleanDeadBackupTriggers() {
226
226
  cleaned++;
227
227
  }
228
228
 
229
+ // 3. Unload and disable com.wipcomputer.cc-watcher LaunchAgent
230
+ // Broken since Mar 24 migration (old iCloud path, wrong node path).
231
+ // The agent communication channel needs redesign, not screen automation.
232
+ const ccWatcherPlist = join(HOME, 'Library', 'LaunchAgents', 'com.wipcomputer.cc-watcher.plist');
233
+ const ccWatcherDisabled = ccWatcherPlist + '.disabled';
234
+ if (existsSync(ccWatcherPlist)) {
235
+ try { execSync(`launchctl unload "${ccWatcherPlist}" 2>/dev/null`, { stdio: 'pipe' }); } catch {}
236
+ try {
237
+ renameSync(ccWatcherPlist, ccWatcherDisabled);
238
+ } catch {
239
+ try { unlinkSync(ccWatcherPlist); } catch {}
240
+ }
241
+ console.log(' + Disabled dead LaunchAgent: com.wipcomputer.cc-watcher');
242
+ cleaned++;
243
+ }
244
+
229
245
  return cleaned;
230
246
  }
231
247
 
@@ -396,6 +412,32 @@ async function cmdInit() {
396
412
  join(LDM_ROOT, 'hooks'),
397
413
  ];
398
414
 
415
+ // Migrate config-from-home.json into config.json (one-time merge)
416
+ // config-from-home.json held org identity (coAuthors, paths, agents, backup, etc.)
417
+ // config.json held runtime/harness info. Now they are one file.
418
+ const configFromHomePath = join(LDM_ROOT, 'config-from-home.json');
419
+ if (existsSync(configFromHomePath) && existsSync(join(LDM_ROOT, 'config.json'))) {
420
+ try {
421
+ const existing = JSON.parse(readFileSync(join(LDM_ROOT, 'config.json'), 'utf8'));
422
+ const fromHome = JSON.parse(readFileSync(configFromHomePath, 'utf8'));
423
+ // Merge: config-from-home.json wins where keys overlap (richer data)
424
+ const merged = { ...existing, ...fromHome };
425
+ // Preserve harnesses from existing config (not in config-from-home.json)
426
+ if (existing.harnesses) merged.harnesses = existing.harnesses;
427
+ // Preserve version and created from existing config
428
+ if (existing.version) merged.version = existing.version;
429
+ if (existing.created) merged.created = existing.created;
430
+ // Update timestamp
431
+ merged.updatedAt = new Date().toISOString();
432
+ writeFileSync(join(LDM_ROOT, 'config.json'), JSON.stringify(merged, null, 2) + '\n');
433
+ renameSync(configFromHomePath, configFromHomePath + '.migrated');
434
+ console.log(` + config-from-home.json merged into config.json`);
435
+ console.log(` + config-from-home.json renamed to config-from-home.json.migrated`);
436
+ } catch (e) {
437
+ console.log(` ! config-from-home.json migration failed: ${e.message}`);
438
+ }
439
+ }
440
+
399
441
  // Scaffold per-agent memory dirs
400
442
  try {
401
443
  const config = JSON.parse(readFileSync(join(LDM_ROOT, 'config.json'), 'utf8'));
@@ -674,10 +716,9 @@ async function cmdInit() {
674
716
  mkdirSync(docsDest, { recursive: true });
675
717
  let docsCount = 0;
676
718
 
677
- // Build template values from BOTH configs:
678
- // ~/.ldm/config.json (harnesses, workspace) + settings/config.json (agents, paths, org)
679
- const settingsConfig = JSON.parse(readFileSync(join(workspacePath, 'settings', 'config.json'), 'utf8'));
680
- const sc = settingsConfig;
719
+ // Build template values from ~/.ldm/config.json (unified config)
720
+ // Legacy: settings/config.json was a separate file, now merged into config.json
721
+ const sc = ldmConfig;
681
722
  const lc = ldmConfig;
682
723
 
683
724
  // Agents from settings config (rich objects with harness/machine/prefix)
@@ -1384,6 +1425,9 @@ async function cmdInstallCatalog() {
1384
1425
  return matches.includes(name) || c.id === name;
1385
1426
  });
1386
1427
 
1428
+ // Skip pinned components (e.g. OpenClaw). Upgrades must be explicit.
1429
+ if (catalogEntry?.pinned) continue;
1430
+
1387
1431
  // Fallback: use repository.url from extension's package.json (#82)
1388
1432
  let repoUrl = catalogEntry?.repo || null;
1389
1433
  if (!repoUrl && extPkg?.repository) {
package/catalog.json CHANGED
@@ -255,6 +255,8 @@
255
255
  ],
256
256
  "recommended": false,
257
257
  "status": "stable",
258
+ "pinned": true,
259
+ "pinnedReason": "OpenClaw is the runtime. Upgrades overwrite dist patches and can change API behavior. Use: ldm upgrade openclaw",
258
260
  "postInstall": null,
259
261
  "installs": {
260
262
  "cli": [
@@ -106,7 +106,7 @@ async function sendMessage(openclawDir, message, options) {
106
106
  "Content-Type": "application/json"
107
107
  },
108
108
  body: JSON.stringify({
109
- model: agentId,
109
+ model: `openclaw/${agentId}`,
110
110
  user: "main",
111
111
  messages: [
112
112
  {
@@ -8,7 +8,7 @@ import {
8
8
  searchConversations,
9
9
  searchWorkspace,
10
10
  sendMessage
11
- } from "./chunk-I5FNBIR2.js";
11
+ } from "./chunk-QZ4DNVJM.js";
12
12
 
13
13
  // cli.ts
14
14
  import { existsSync, statSync } from "fs";
@@ -17,7 +17,7 @@ import {
17
17
  searchConversations,
18
18
  searchWorkspace,
19
19
  sendMessage
20
- } from "./chunk-I5FNBIR2.js";
20
+ } from "./chunk-QZ4DNVJM.js";
21
21
  export {
22
22
  LDM_ROOT,
23
23
  blobToEmbedding,
@@ -9,7 +9,7 @@ import {
9
9
  searchConversations,
10
10
  searchWorkspace,
11
11
  sendMessage
12
- } from "./chunk-I5FNBIR2.js";
12
+ } from "./chunk-QZ4DNVJM.js";
13
13
 
14
14
  // mcp-server.ts
15
15
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipcomputer/wip-ldm-os",
3
- "version": "0.4.62",
3
+ "version": "0.4.63",
4
4
  "type": "module",
5
5
  "description": "LDM OS: identity, memory, and sovereignty infrastructure for AI agents",
6
6
  "engines": {
@@ -1,6 +1,6 @@
1
1
  #!/bin/bash
2
2
  # ldm-backup.sh — Unified backup for LDM OS
3
- # Backs up: ~/.ldm/, ~/.openclaw/, ~/.claude/, ~/wipcomputerinc/
3
+ # Backs up: ~/.ldm/, ~/.openclaw/, ~/.claude/, $WORKSPACE/
4
4
  # Handles SQLite safely (sqlite3 .backup). Tars to iCloud for offsite.
5
5
  #
6
6
  # Source of truth: wip-ldm-os-private/scripts/ldm-backup.sh
@@ -12,7 +12,7 @@
12
12
  # ldm-backup.sh --keep 14 # keep last 14 backups (default: 7)
13
13
  # ldm-backup.sh --include-secrets # include ~/.ldm/secrets/
14
14
  #
15
- # Config: ~/.ldm/config.json (workspace path) + {workspace}/settings/config.json (backup settings)
15
+ # Config: ~/.ldm/config.json (workspace path, backup settings, iCloud path)
16
16
 
17
17
  set -euo pipefail
18
18
 
@@ -45,20 +45,29 @@ if [ -z "$WORKSPACE" ]; then
45
45
  echo "WARNING: No workspace in ~/.ldm/config.json. Skipping workspace backup."
46
46
  fi
47
47
 
48
- # Read iCloud backup path from workspace config
48
+ # Read org name from config (used for tar filename)
49
+ ORG=""
50
+ if [ -f "$LDM_HOME/config.json" ]; then
51
+ ORG=$(python3 -c "import json; print(json.load(open('$LDM_HOME/config.json')).get('org',''))" 2>/dev/null || true)
52
+ fi
53
+ if [ -z "$ORG" ]; then
54
+ ORG="workspace"
55
+ fi
56
+
57
+ # Read iCloud backup path from ~/.ldm/config.json
49
58
  ICLOUD_BACKUP=""
50
- if [ -n "$WORKSPACE" ] && [ -f "$WORKSPACE/settings/config.json" ]; then
59
+ if [ -f "$LDM_HOME/config.json" ]; then
51
60
  ICLOUD_BACKUP=$(python3 -c "
52
61
  import json, os
53
- c = json.load(open('$WORKSPACE/settings/config.json'))
62
+ c = json.load(open('$LDM_HOME/config.json'))
54
63
  p = c.get('paths',{}).get('icloudBackup','')
55
64
  print(os.path.expanduser(p))
56
65
  " 2>/dev/null || true)
57
66
  fi
58
67
 
59
- # Read keep from workspace config (override if set there)
60
- if [ -n "$WORKSPACE" ] && [ -f "$WORKSPACE/settings/config.json" ]; then
61
- CONFIG_KEEP=$(python3 -c "import json; print(json.load(open('$WORKSPACE/settings/config.json')).get('backup',{}).get('keep',0))" 2>/dev/null || true)
68
+ # Read keep from ~/.ldm/config.json (override if set there)
69
+ if [ -f "$LDM_HOME/config.json" ]; then
70
+ CONFIG_KEEP=$(python3 -c "import json; print(json.load(open('$LDM_HOME/config.json')).get('backup',{}).get('keep',0))" 2>/dev/null || true)
62
71
  if [ -n "$CONFIG_KEEP" ] && [ "$CONFIG_KEEP" -gt 0 ] 2>/dev/null; then
63
72
  KEEP="$CONFIG_KEEP"
64
73
  fi
@@ -211,7 +220,7 @@ if [ -n "$WORKSPACE" ] && [ -d "$WORKSPACE" ]; then
211
220
  echo " ERROR: Workspace estimated at ${ESTIMATED_KB}KB (>10GB). Aborting tar to prevent disk fill."
212
221
  echo " Check for large directories: du -sh $WORKSPACE/*/"
213
222
  else
214
- tar -cf "$DEST/wipcomputerinc.tar" \
223
+ tar -cf "$DEST/$ORG.tar" \
215
224
  --exclude "node_modules" \
216
225
  --exclude ".git/objects" \
217
226
  --exclude ".DS_Store" \
@@ -198,7 +198,7 @@ export async function sendMessage(
198
198
  "Content-Type": "application/json",
199
199
  },
200
200
  body: JSON.stringify({
201
- model: agentId,
201
+ model: `openclaw/${agentId}`,
202
202
  user: "main",
203
203
  messages: [
204
204
  {