@ericrisco/rsc 3.1.0 → 3.1.1
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/manifest.json +1 -1
- package/package.json +1 -1
- package/targets/team-safe-start.mjs +19 -4
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -12,15 +12,29 @@
|
|
|
12
12
|
// Each returns the text to say, or ''. None throws: a session start is never worth breaking.
|
|
13
13
|
// Standalone siblings under `.rsc/`: trunk-policy.mjs, worktree-reaper.mjs, session-memory-core.mjs.
|
|
14
14
|
import { execFileSync } from 'node:child_process';
|
|
15
|
-
import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs';
|
|
16
|
-
import { basename, join
|
|
15
|
+
import { existsSync, mkdirSync, readFileSync, realpathSync, statSync, writeFileSync } from 'node:fs';
|
|
16
|
+
import { basename, join } from 'node:path';
|
|
17
17
|
|
|
18
18
|
const git = (root, args) => {
|
|
19
19
|
try { return execFileSync('git', args, { windowsHide: true, cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'], timeout: 8000 }).trim(); }
|
|
20
20
|
catch { return null; }
|
|
21
21
|
};
|
|
22
22
|
const ok = (root, args) => git(root, args) !== null;
|
|
23
|
-
|
|
23
|
+
// The native realpath returns the path as the file system stores it. The JS one keeps the case it was
|
|
24
|
+
// given, and Windows hands the same folder over as "c:\…" (VS Code) and "C:/…" (git): #316.
|
|
25
|
+
const real = (p) => { try { return realpathSync.native(p); } catch { try { return realpathSync(p); } catch { return p; } } };
|
|
26
|
+
|
|
27
|
+
/** Whether `path` is `home` or inside it. Windows paths compare case-insensitively and with either slash. */
|
|
28
|
+
export function isInside(path, home, platform = process.platform) {
|
|
29
|
+
const win = platform === 'win32';
|
|
30
|
+
const norm = (p) => { const s = win ? String(p).replace(/\//g, '\\').toLowerCase() : String(p); return s.length > 1 ? s.replace(/[\\/]+$/, '') : s; };
|
|
31
|
+
const a = norm(path), b = norm(home);
|
|
32
|
+
return a === b || a.startsWith(b + (win ? '\\' : '/'));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// The last word on "same folder": two names for one directory share device and inode whatever their
|
|
36
|
+
// spelling. Used before reporting a destination as taken, so a spelling difference never reads as a clash.
|
|
37
|
+
const sameDir = (a, b) => { try { const x = statSync(a), y = statSync(b); return x.dev === y.dev && x.ino === y.ino && x.ino !== 0; } catch { return false; } };
|
|
24
38
|
const stamp = () => new Date().toISOString().slice(0, 16).replace(/[-:T]/g, '').replace(/^(\d{8})(\d{4})$/, '$1-$2');
|
|
25
39
|
|
|
26
40
|
const RESCUE_MARK = '.team-safe-3-rescue';
|
|
@@ -71,11 +85,12 @@ export async function relocateOldWorktrees(root) {
|
|
|
71
85
|
const left = [];
|
|
72
86
|
for (const wt of W.listWorktrees(root)) {
|
|
73
87
|
const path = real(wt.path);
|
|
74
|
-
if (path
|
|
88
|
+
if (isInside(path, home)) continue; // already inside
|
|
75
89
|
if (W.provenanceOf(root, { ...wt, path }) !== 'rsc') continue;
|
|
76
90
|
if (others(path).length) { left.push(`${path} (una sesión trabaja en él)`); continue; }
|
|
77
91
|
const name = basename(path);
|
|
78
92
|
const dest = join(home, '.worktrees', name.startsWith(`${basename(home)}-`) ? name.slice(basename(home).length + 1) : name);
|
|
93
|
+
if (sameDir(dest, path)) continue; // it IS the destination: already inside, under another spelling
|
|
79
94
|
if (existsSync(dest)) { left.push(`${path} (ya existe ${dest})`); continue; }
|
|
80
95
|
mkdirSync(join(home, '.worktrees'), { recursive: true });
|
|
81
96
|
if (ok(root, ['worktree', 'move', path, dest])) moved.push(`${path} → .worktrees/${basename(dest)}`);
|