instabox 0.8.5 → 0.8.7
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
|
+
27fa581ad33ebabce3229045ebb12d9a760be0ccd363139a57b580d7aa3dac0a instabox-darwin-amd64
|
|
2
|
+
0c5620128fa44dbda291bdafbfa2178b909d8457a5ad0751a428044e6adc25e5 instabox-darwin-arm64
|
|
3
|
+
c47e1086ee1e532340b95ff116cc58b31e8a1bddb8ab7e7aaf76454e6f8d5ab5 instabox-linux-amd64
|
|
4
|
+
32c8096ecb7a782f2a51341b1b75b65b305c773597982976fb1888215fe773b0 instabox-linux-arm64
|
|
5
|
+
940bed7319b187ff873a939d25738e02e44f5f5e71948cf901be5f5d05e0295e instabox-windows-amd64.exe
|
|
6
|
+
8a6ec5b8daf403a969dc89d87f4180f276cdfbeee335c8469f466fdade9fec61 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) {
|