instabox 0.8.6 → 0.8.8
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/cli/SHA256SUMS +6 -6
- package/cli/instabox-darwin-amd64 +0 -0
- package/cli/instabox-darwin-arm64 +0 -0
- package/cli/instabox-linux-amd64 +0 -0
- package/cli/instabox-linux-arm64 +0 -0
- package/cli/instabox-windows-amd64.exe +0 -0
- package/cli/instabox-windows-arm64.exe +0 -0
- package/package.json +1 -1
- package/skills/instabox-move-repo/SKILL.md +6 -5
- package/skills/instabox-move-repo/scripts/repo-files.mjs +13 -12
package/cli/SHA256SUMS
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
68aed6ff418946b2fabdbe2b2404191d6d2caef666ea22fc938d75067cfe4c06 instabox-darwin-amd64
|
|
2
|
+
373cb6dd024d07ab2aeac6665cc9a187bfc3bb3e05bdfabe3b6ffd85e28ba69c instabox-darwin-arm64
|
|
3
|
+
54f4408ce12596e52d953fb9638cfd6d90dd88ac89a6f4da833e6f02cf3df131 instabox-linux-amd64
|
|
4
|
+
cba38617e9f98bccff21f5bf2e9bf05d7259c9d1b27c090eb76935515b8f2fa8 instabox-linux-arm64
|
|
5
|
+
edbf876282c1901e798d77297ca8b43465a8bdacf64b16f2e66ab2fc6efb2c0d instabox-windows-amd64.exe
|
|
6
|
+
b04f7dbf884bab7a0e817fd7f5eb9fc5becc1a17fde61278eff38c8c4b53eca6 instabox-windows-arm64.exe
|
|
Binary file
|
|
Binary file
|
package/cli/instabox-linux-amd64
CHANGED
|
Binary file
|
package/cli/instabox-linux-arm64
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -38,6 +38,7 @@ Before starting, tell the user plainly:
|
|
|
38
38
|
Run with **bash**, anywhere inside the repo or one of its worktrees:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
+
export MSYS2_ARG_CONV_EXCL=/data/ # Git Bash on Windows: keep box paths as they are
|
|
41
42
|
instabox whoami # signed in? otherwise: instabox login
|
|
42
43
|
S=~/.claude/skills/instabox-move-repo/scripts # or ~/.agents/skills/instabox-move-repo/scripts: wherever this file is
|
|
43
44
|
W=$(mktemp -d)
|
|
@@ -58,7 +59,7 @@ Show the user the plan in short: the worktrees with their sizes and state, the t
|
|
|
58
59
|
SKIP=() # one --skip-worktree per worktree the user unchecked: SKIP+=(--skip-worktree /path/to/it)
|
|
59
60
|
KEEP=() # one --keep per excluded name the user wants copied anyway: KEEP+=(--keep build)
|
|
60
61
|
node "$S/repo-files.mjs" "${SKIP[@]}" "${KEEP[@]}" --json > "$W/plan.json"
|
|
61
|
-
DEST=$(jq -r .main.box "$W/plan.json")
|
|
62
|
+
DEST=$(jq -r .main.box "$W/plan.json" | tr -d '\r') # tr: Windows jq.exe ends lines in CRLF
|
|
62
63
|
jq -r '.totals' "$W/plan.json" # sendBytes must fit well inside /data: instabox usage
|
|
63
64
|
```
|
|
64
65
|
|
|
@@ -81,7 +82,7 @@ The main checkout first (it carries `.git`), then each worktree, each as its own
|
|
|
81
82
|
```bash
|
|
82
83
|
export COPYFILE_DISABLE=1 # macOS tar: no ._ AppleDouble files
|
|
83
84
|
X='tar -xzf - --warning=no-unknown-keyword' # the box runs GNU tar
|
|
84
|
-
jq -r '.main, (.worktrees[] | select(.move)) | [.src, .box] | @tsv' "$W/plan.json" |
|
|
85
|
+
jq -r '.main, (.worktrees[] | select(.move)) | [.src, .box] | @tsv' "$W/plan.json" | tr -d '\r' |
|
|
85
86
|
while IFS=$'\t' read -r src box; do
|
|
86
87
|
echo "== $src -> $box"
|
|
87
88
|
node "$S/repo-files.mjs" --list0 "$src" "${SKIP[@]}" "${KEEP[@]}" </dev/null |
|
|
@@ -93,7 +94,7 @@ done
|
|
|
93
94
|
Then point the worktrees at their new places (each worktree's `.git` file and `.git/worktrees/<id>/gitdir` still name the local paths; `git worktree repair` with the new paths rewrites both sides):
|
|
94
95
|
|
|
95
96
|
```bash
|
|
96
|
-
WTS=$(jq -r '[.worktrees[] | select(.move) | .box] | join(" ")' "$W/plan.json")
|
|
97
|
+
WTS=$(jq -r '[.worktrees[] | select(.move) | .box] | join(" ")' "$W/plan.json" | tr -d '\r')
|
|
97
98
|
[ -z "$WTS" ] || instabox ssh "$BOX" -- "cd '$DEST' && git worktree repair $WTS"
|
|
98
99
|
```
|
|
99
100
|
|
|
@@ -102,7 +103,7 @@ Box paths contain only letters, digits and `._-/`, so they are safe unquoted the
|
|
|
102
103
|
Check that every checkout has the same state, and the same worktrees:
|
|
103
104
|
|
|
104
105
|
```bash
|
|
105
|
-
jq -r '.main, (.worktrees[] | select(.move)) | [.src, .box] | @tsv' "$W/plan.json" |
|
|
106
|
+
jq -r '.main, (.worktrees[] | select(.move)) | [.src, .box] | @tsv' "$W/plan.json" | tr -d '\r' |
|
|
106
107
|
while IFS=$'\t' read -r src box; do
|
|
107
108
|
echo "== $box"
|
|
108
109
|
diff <(cd "$src" && { git status --porcelain | sort; git rev-parse HEAD; }) \
|
|
@@ -119,7 +120,7 @@ The only allowed differences are `<` lines starting with `??` for what the plan
|
|
|
119
120
|
H=$(mktemp -d)
|
|
120
121
|
node "$S/history.mjs" --plan "$W/plan.json" --out "$H" > "$W/history.json" # --no-claude / --no-codex to skip one
|
|
121
122
|
jq '{claude: .claude | {sessions, bytes, recent}, codex: .codex | {sessions, bytes, recent}}' "$W/history.json" # null: skipped
|
|
122
|
-
tar -C "$H" -czf - $(jq -r '.entries[]' "$W/history.json") | instabox ssh "$BOX" -- "$X --no-overwrite-dir -C ~"
|
|
123
|
+
tar -C "$H" -czf - $(jq -r '.entries[]' "$W/history.json" | tr -d '\r') | instabox ssh "$BOX" -- "$X --no-overwrite-dir -C ~"
|
|
123
124
|
instabox ssh "$BOX" -- 'bash ~/.cache/instabox-move-repo/apply-history.sh'
|
|
124
125
|
rm -rf "$H"
|
|
125
126
|
```
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
// difference is `??` lines for what was left out. File contents are never read, only names and sizes.
|
|
22
22
|
import { spawnSync } from 'node:child_process';
|
|
23
23
|
import { lstatSync, readdirSync, readFileSync, realpathSync } from 'node:fs';
|
|
24
|
-
import { basename, dirname, join, relative, resolve } from 'node:path';
|
|
24
|
+
import { basename, dirname, join, relative, resolve, sep } from 'node:path';
|
|
25
25
|
import { fileURLToPath } from 'node:url';
|
|
26
26
|
|
|
27
27
|
// Directory names that hold build output, dependencies or caches: regenerated on the box.
|
|
@@ -161,10 +161,10 @@ function treeBytes(p, skip = new Set()) {
|
|
|
161
161
|
return { bytes, files };
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
-
//
|
|
165
|
-
function walk(dir,
|
|
164
|
+
// Archive names are joined with '/' whatever the host separator.
|
|
165
|
+
function walk(dir, rel, skip, out = []) {
|
|
166
166
|
if (skip.has(dir)) return out;
|
|
167
|
-
out.push(
|
|
167
|
+
out.push(rel);
|
|
168
168
|
let names = [];
|
|
169
169
|
try {
|
|
170
170
|
names = readdirSync(dir).sort();
|
|
@@ -173,8 +173,8 @@ function walk(dir, base, skip, out = []) {
|
|
|
173
173
|
const p = join(dir, n);
|
|
174
174
|
const st = lstat(p);
|
|
175
175
|
if (!st || skip.has(p)) continue;
|
|
176
|
-
if (st.isDirectory()) walk(p,
|
|
177
|
-
else out.push(
|
|
176
|
+
if (st.isDirectory()) walk(p, `${rel}/${n}`, skip, out);
|
|
177
|
+
else out.push(`${rel}/${n}`);
|
|
178
178
|
}
|
|
179
179
|
return out;
|
|
180
180
|
}
|
|
@@ -217,7 +217,8 @@ const real = (p) => {
|
|
|
217
217
|
return resolve(p);
|
|
218
218
|
}
|
|
219
219
|
};
|
|
220
|
-
|
|
220
|
+
// s: sep for native paths, '/' for git's.
|
|
221
|
+
const inside = (p, dir, s = sep) => p === dir || p.startsWith(dir + s);
|
|
221
222
|
|
|
222
223
|
// `git worktree list --porcelain -z`, parsed. The first entry is the main checkout.
|
|
223
224
|
export function listWorktrees(cwd) {
|
|
@@ -258,14 +259,14 @@ function checkoutFiles(top, { keep, nested = [] }) {
|
|
|
258
259
|
}
|
|
259
260
|
const trackedFiles = files.length;
|
|
260
261
|
const tracked = new Set(files);
|
|
261
|
-
const nestedRel = nested.map((p) => relative(top, p));
|
|
262
|
+
const nestedRel = nested.map((p) => relative(top, p).split(sep).join('/'));
|
|
262
263
|
|
|
263
264
|
let untrackedBytes = 0;
|
|
264
265
|
let untrackedFiles = 0;
|
|
265
266
|
const groups = new Map();
|
|
266
267
|
for (const f of split0(git(['ls-files', '-z', '--others', '--exclude-standard'], top))) {
|
|
267
268
|
const bare = f.replace(/\/$/, '');
|
|
268
|
-
if (tracked.has(f) || nestedRel.some((n) => inside(bare, n))) continue;
|
|
269
|
+
if (tracked.has(f) || nestedRel.some((n) => inside(bare, n, '/'))) continue;
|
|
269
270
|
const st = lstat(join(top, bare));
|
|
270
271
|
if (!st) continue;
|
|
271
272
|
const isDir = st.isDirectory();
|
|
@@ -286,7 +287,7 @@ function checkoutFiles(top, { keep, nested = [] }) {
|
|
|
286
287
|
// .env files git ignores (names only): they stay behind too, and the user should know.
|
|
287
288
|
const ignoredEnv = split0(git(['ls-files', '-z', '--others', '--ignored', '--exclude-standard', '--directory'], top))
|
|
288
289
|
.filter((f) => !f.endsWith('/') && isEnvName(f))
|
|
289
|
-
.filter((f) => !nestedRel.some((n) => inside(f, n)));
|
|
290
|
+
.filter((f) => !nestedRel.some((n) => inside(f, n, '/')));
|
|
290
291
|
const left = [...groups.entries()]
|
|
291
292
|
.map(([path, g]) => ({ path, ...g }))
|
|
292
293
|
.sort((a, b) => b.bytes - a.bytes || a.path.localeCompare(b.path));
|
|
@@ -377,7 +378,7 @@ export function planRepo(cwd = process.cwd(), { dest, keep = [], skip = [], lite
|
|
|
377
378
|
}
|
|
378
379
|
// Box paths are safe in a single-quoted shell word: [A-Za-z0-9._-/] only.
|
|
379
380
|
let box = inside(src, mainSrc)
|
|
380
|
-
? `${dest}/${relative(mainSrc, src).split(
|
|
381
|
+
? `${dest}/${relative(mainSrc, src).split(sep).map(safeName).join('/')}`
|
|
381
382
|
: `${dest}.worktrees/${safeName(basename(src))}`;
|
|
382
383
|
for (let i = 2, b = box; used.has(box); i++) box = `${b}-${i}`;
|
|
383
384
|
entry.box = box;
|
|
@@ -456,7 +457,7 @@ export function listFor(path, { keep = [], skip = [] } = {}) {
|
|
|
456
457
|
if (!isMain) return ['.git', ...files];
|
|
457
458
|
// The admin dirs of worktrees that stay behind (unchecked, prunable, missing) stay too.
|
|
458
459
|
const skipAdmin = new Set(plan.worktrees.filter((x) => !x.move && x.adminDir).map((x) => x.adminDir));
|
|
459
|
-
return [...walk(real(join(top, '.git')),
|
|
460
|
+
return [...walk(real(join(top, '.git')), '.git', skipAdmin), ...files];
|
|
460
461
|
}
|
|
461
462
|
|
|
462
463
|
function describe(w) {
|