@wipcomputer/wip-ldm-os 0.4.57 → 0.4.58
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 +54 -0
- package/bin/wip-install.js +0 -0
- package/package.json +1 -1
- package/scripts/ldm-backup.sh +25 -10
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.58"
|
|
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
|
@@ -1791,6 +1791,57 @@ function cmdStatus() {
|
|
|
1791
1791
|
|
|
1792
1792
|
// ── ldm sessions ──
|
|
1793
1793
|
|
|
1794
|
+
// ── ldm backup ──
|
|
1795
|
+
|
|
1796
|
+
async function cmdBackup() {
|
|
1797
|
+
const BACKUP_SCRIPT = join(LDM_ROOT, 'bin', 'ldm-backup.sh');
|
|
1798
|
+
|
|
1799
|
+
if (!existsSync(BACKUP_SCRIPT)) {
|
|
1800
|
+
console.error(' x Backup script not found at ' + BACKUP_SCRIPT);
|
|
1801
|
+
console.error(' Run: ldm install (deploys the backup script)');
|
|
1802
|
+
process.exit(1);
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
const backupArgs = [];
|
|
1806
|
+
if (DRY_RUN) backupArgs.push('--dry-run');
|
|
1807
|
+
|
|
1808
|
+
// --pin: mark the latest backup to skip rotation
|
|
1809
|
+
const pinIndex = args.indexOf('--pin');
|
|
1810
|
+
if (pinIndex !== -1) {
|
|
1811
|
+
const reason = args[pinIndex + 1] || 'pinned';
|
|
1812
|
+
// Find latest backup dir
|
|
1813
|
+
const backupRoot = join(LDM_ROOT, 'backups');
|
|
1814
|
+
const dirs = readdirSync(backupRoot)
|
|
1815
|
+
.filter(d => d.match(/^20\d\d-\d\d-\d\d--/))
|
|
1816
|
+
.sort()
|
|
1817
|
+
.reverse();
|
|
1818
|
+
if (dirs.length === 0) {
|
|
1819
|
+
console.error(' x No backups found to pin.');
|
|
1820
|
+
process.exit(1);
|
|
1821
|
+
}
|
|
1822
|
+
const latest = dirs[0];
|
|
1823
|
+
const pinFile = join(backupRoot, latest, '.pinned');
|
|
1824
|
+
writeFileSync(pinFile, `Pinned: ${reason}\nDate: ${new Date().toISOString()}\n`);
|
|
1825
|
+
console.log(` + Pinned backup ${latest}: ${reason}`);
|
|
1826
|
+
console.log(' This backup will be skipped during rotation.');
|
|
1827
|
+
return;
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
console.log(' Running backup...');
|
|
1831
|
+
console.log('');
|
|
1832
|
+
try {
|
|
1833
|
+
execSync(`bash "${BACKUP_SCRIPT}" ${backupArgs.join(' ')}`, {
|
|
1834
|
+
stdio: 'inherit',
|
|
1835
|
+
timeout: 600000,
|
|
1836
|
+
});
|
|
1837
|
+
} catch (e) {
|
|
1838
|
+
console.error(' x Backup failed: ' + e.message);
|
|
1839
|
+
process.exit(1);
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1842
|
+
|
|
1843
|
+
// ── ldm sessions ──
|
|
1844
|
+
|
|
1794
1845
|
async function cmdSessions() {
|
|
1795
1846
|
const { listSessions } = await import('../lib/sessions.mjs');
|
|
1796
1847
|
const sessions = listSessions({ includeStale: CLEANUP_FLAG });
|
|
@@ -2842,6 +2893,9 @@ async function main() {
|
|
|
2842
2893
|
case 'worktree':
|
|
2843
2894
|
await cmdWorktree();
|
|
2844
2895
|
break;
|
|
2896
|
+
case 'backup':
|
|
2897
|
+
await cmdBackup();
|
|
2898
|
+
break;
|
|
2845
2899
|
default:
|
|
2846
2900
|
console.error(` Unknown command: ${command}`);
|
|
2847
2901
|
console.error(` Run: ldm --help`);
|
package/bin/wip-install.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
package/scripts/ldm-backup.sh
CHANGED
|
@@ -193,16 +193,26 @@ echo "--- ~/.claude/ ---"
|
|
|
193
193
|
|
|
194
194
|
if [ -n "$WORKSPACE" ] && [ -d "$WORKSPACE" ]; then
|
|
195
195
|
echo "--- $WORKSPACE/ ---"
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
196
|
+
|
|
197
|
+
# Size guard: estimate workspace size before tarring
|
|
198
|
+
ESTIMATED_KB=$(du -sk --exclude="node_modules" --exclude=".git" --exclude="_temp/_archive" --exclude="_trash" "$WORKSPACE" 2>/dev/null | cut -f1 || echo "0")
|
|
199
|
+
MAX_KB=10000000 # 10GB
|
|
200
|
+
if [ "$ESTIMATED_KB" -gt "$MAX_KB" ] 2>/dev/null; then
|
|
201
|
+
echo " ERROR: Workspace estimated at ${ESTIMATED_KB}KB (>10GB). Aborting tar to prevent disk fill."
|
|
202
|
+
echo " Check for large directories: du -sh $WORKSPACE/*/"
|
|
203
|
+
else
|
|
204
|
+
tar -cf "$DEST/wipcomputerinc.tar" \
|
|
205
|
+
--exclude "node_modules" \
|
|
206
|
+
--exclude ".git/objects" \
|
|
207
|
+
--exclude ".DS_Store" \
|
|
208
|
+
--exclude "*/staff/cc-mini/documents/backups" \
|
|
209
|
+
--exclude "*/_temp/backups" \
|
|
210
|
+
--exclude "*/_temp/_archive" \
|
|
211
|
+
--exclude "*/_trash" \
|
|
212
|
+
-C "$(dirname "$WORKSPACE")" "$(basename "$WORKSPACE")" 2>/dev/null \
|
|
213
|
+
&& echo " workspace: tar OK (est ${ESTIMATED_KB}KB)" \
|
|
214
|
+
|| echo " workspace: tar FAILED"
|
|
215
|
+
fi
|
|
206
216
|
fi
|
|
207
217
|
|
|
208
218
|
# ── 5. iCloud offsite ──
|
|
@@ -235,6 +245,11 @@ BACKUP_COUNT=$(ls -1d "$BACKUP_ROOT"/20??-??-??--* 2>/dev/null | wc -l | tr -d '
|
|
|
235
245
|
if [ "$BACKUP_COUNT" -gt "$KEEP" ]; then
|
|
236
246
|
REMOVE_COUNT=$((BACKUP_COUNT - KEEP))
|
|
237
247
|
ls -1d "$BACKUP_ROOT"/20??-??-??--* | head -n "$REMOVE_COUNT" | while read OLD; do
|
|
248
|
+
# Skip pinned backups
|
|
249
|
+
if [ -f "$OLD/.pinned" ]; then
|
|
250
|
+
echo " Skipped (pinned): $(basename "$OLD")"
|
|
251
|
+
continue
|
|
252
|
+
fi
|
|
238
253
|
rm -rf "$OLD"
|
|
239
254
|
echo " Removed: $(basename "$OLD")"
|
|
240
255
|
done
|