@mmnto/totem 1.112.0 → 1.113.0

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.
@@ -0,0 +1,286 @@
1
+ /**
2
+ * The user-level worktree registry (`~/.totem/worktrees.json`) behind
3
+ * `totem wt create|remove|list` (mmnto-ai/totem#2580 slice-2).
4
+ *
5
+ * A SIBLING file to `registry.json`, never a key inside it: `RegistrySchema` is
6
+ * `z.record(repoPath, RegistryEntrySchema)`, so any non-repo-entry key would
7
+ * fail schema validation and flip the WHOLE sync registry to "unreadable". The
8
+ * two files share one lock directory (`~/.totem`) and nothing else — the read
9
+ * path of `registry.json` is untouched by every verb here.
10
+ *
11
+ * Two independent lifecycles live in this file, and the independence is the
12
+ * point:
13
+ * - `roots[]` accretes every container root a worktree was ever created
14
+ * under and is NEVER pruned by removal. It is what keeps a recorded
15
+ * location reachable for `doctor --estate` after the last live entry under
16
+ * it is gone (PR #2586 round-3 MINOR-3).
17
+ * - `worktrees{}` is entry accounting: written BEFORE `git worktree add`
18
+ * (an intent record — a phantom entry fails VISIBLY in `wt list`, an
19
+ * unrecorded worktree fails invisibly), deleted ONLY after a removal has
20
+ * verified the directory is actually gone.
21
+ *
22
+ * Concurrency and durability copy `updateRegistryEntry` exactly: `acquireLock`
23
+ * on `~/.totem` serializes mutations, and every write is a PID-suffixed temp
24
+ * file renamed into place. Reads warn-and-degrade (`readRegistry`'s posture);
25
+ * mutations REFUSE to overwrite a file whose schema does not parse.
26
+ */
27
+ import fs from 'node:fs';
28
+ import os from 'node:os';
29
+ import path from 'node:path';
30
+ import { z } from 'zod';
31
+ import { TotemParseError } from './errors.js';
32
+ import { acquireLock } from './lock.js';
33
+ import { readJsonSafe } from './sys/fs.js';
34
+ /** The on-disk compatibility contract for `~/.totem/worktrees.json`. */
35
+ export const WORKTREE_REGISTRY_SCHEMA_VERSION = 1;
36
+ export const WorktreeEntrySchema = z
37
+ .object({
38
+ /** Home repo root (absolute) the worktree was created from. */
39
+ repo: z.string(),
40
+ /** Creating seat id (`resolveSelfSender`, or an explicit `--seat`). */
41
+ seat: z.string(),
42
+ branch: z.string(),
43
+ /** Issue number the worktree was cut for, when one was named. */
44
+ ticket: z.string().optional(),
45
+ /** ISO instant, stamped at the write site. */
46
+ createdAt: z.string(),
47
+ })
48
+ .passthrough(); // Preserve unknown fields from newer CLI versions
49
+ export const WorktreeFileSchema = z.object({
50
+ schemaVersion: z.literal(WORKTREE_REGISTRY_SCHEMA_VERSION),
51
+ /** Every container root ever created under — accretes, never auto-pruned. */
52
+ roots: z.array(z.string()),
53
+ /** Absolute worktree path → entry. */
54
+ worktrees: z.record(z.string(), WorktreeEntrySchema),
55
+ });
56
+ /** Resolve the registry directory lazily so tests can mock os.homedir(). */
57
+ function worktreeRegistryDir() {
58
+ return path.join(os.homedir(), '.totem');
59
+ }
60
+ /** Resolve the registry file path lazily so tests can mock os.homedir(). */
61
+ export function worktreeRegistryPath() {
62
+ return path.join(worktreeRegistryDir(), 'worktrees.json');
63
+ }
64
+ /** The zero-config container root (`~/.totem/worktrees`) — the ruling's Q1 default. */
65
+ export function defaultWorktreeRoot() {
66
+ return path.join(worktreeRegistryDir(), 'worktrees');
67
+ }
68
+ /** A fresh, valid, empty registry — the first-run and degraded-read value. */
69
+ export function emptyWorktreeFile() {
70
+ return { schemaVersion: WORKTREE_REGISTRY_SCHEMA_VERSION, roots: [], worktrees: {} };
71
+ }
72
+ /**
73
+ * Windows git and Node can disagree on drive-letter case (GCA #2293), so path
74
+ * identity folds on win32 ONLY — POSIX filesystems are case-sensitive and
75
+ * folding there conflates real paths (the author-sandbox.ts:121 precedent).
76
+ */
77
+ function foldCase(p) {
78
+ return process.platform === 'win32' ? p.toLowerCase() : p;
79
+ }
80
+ /** Case-folded (win32 only), resolved key for comparing two worktree paths. */
81
+ export function worktreePathKey(p) {
82
+ return foldCase(path.resolve(p));
83
+ }
84
+ /**
85
+ * No-follow existence probe: a dangling symlink/junction still EXISTS here,
86
+ * and the probe FAILS CLOSED — only ENOENT/ENOTDIR mean "absent". Any other
87
+ * errno (EACCES on a denied parent, EIO, an offline share) reports the path as
88
+ * PRESENT: a caller that cannot KNOW must fail loud, never delete a registry
89
+ * entry for a directory that may still stand (#2580 bot round, CR findings
90
+ * 8 + 9 — this retires the errno-tri-state deferral).
91
+ */
92
+ export function worktreePathExists(p) {
93
+ // totem-context: intentional cleanup — the catch IS the answer, not a swallow: ENOENT/ENOTDIR are the two errnos that PROVE absence, and every other lstat failure deliberately reports "present" so removal fails closed instead of reading an unknowable path as gone.
94
+ try {
95
+ fs.lstatSync(p);
96
+ return true;
97
+ // totem-context: intentional cleanup — see directive above the try; dual placement so the rule fires on either the catch-keyword line or the catch-body line.
98
+ }
99
+ catch (err) {
100
+ // A non-object throw carries no errno and cannot PROVE absence — it reads
101
+ // as present, the same fail-closed answer as any unrecognized failure
102
+ // (round 2, GCA null-safety finding).
103
+ const code = err !== null && typeof err === 'object' && 'code' in err
104
+ ? err.code
105
+ : undefined;
106
+ return code !== 'ENOENT' && code !== 'ENOTDIR';
107
+ }
108
+ }
109
+ /** No-follow directory probe — a symlinked/junctioned path is not a directory. */
110
+ function isRealDirectory(p) {
111
+ // totem-context: intentional cleanup — an unreadable or missing recorded root degrades to "not a directory", which the doctor coupling reads as an empty sweep rather than a scan hole (the ruling's Q3 filter).
112
+ try {
113
+ return fs.lstatSync(p).isDirectory();
114
+ // totem-context: intentional cleanup — see directive above the try; dual placement so the rule fires on either the catch-keyword line or the catch-body line.
115
+ }
116
+ catch {
117
+ return false;
118
+ }
119
+ }
120
+ /**
121
+ * Read the worktree registry. Missing file → empty (expected on first run);
122
+ * any other failure warns and degrades to empty, mirroring `readRegistry` so a
123
+ * corrupt file can never take a read-only verb down with it.
124
+ */
125
+ export function readWorktreeRegistry(onWarn) {
126
+ // totem-context: intentional cleanup — warn-not-throw is the ruled read contract (mirrors readRegistry): a corrupt registry file must never take a read-only verb down with it; the onWarn callback is the loud path, and a missing file is the expected first-run case.
127
+ try {
128
+ return readJsonSafe(worktreeRegistryPath(), WorktreeFileSchema);
129
+ // totem-context: intentional cleanup — see directive above the try; dual placement so the rule fires on either the catch-keyword line or the catch-body line.
130
+ }
131
+ catch (err) {
132
+ if (err instanceof TotemParseError && err.message.includes('File not found')) {
133
+ // Expected until the first `wt create` — silently return empty
134
+ return emptyWorktreeFile();
135
+ }
136
+ onWarn?.(`Cannot read worktree registry: ${err instanceof Error ? err.message : String(err)} — using empty registry`);
137
+ return emptyWorktreeFile();
138
+ }
139
+ }
140
+ /**
141
+ * Find a recorded entry by path, folding case on win32 only. Returns the
142
+ * STORED key alongside the entry so a caller can delete exactly what it found.
143
+ */
144
+ export function findWorktreeEntry(file, worktreePath) {
145
+ const wanted = worktreePathKey(worktreePath);
146
+ for (const [key, entry] of Object.entries(file.worktrees)) {
147
+ if (worktreePathKey(key) === wanted)
148
+ return { key, entry };
149
+ }
150
+ return undefined;
151
+ }
152
+ /**
153
+ * The recorded roots that still EXIST on disk — the projection both doctor
154
+ * consumers sweep. A recorded root that is gone is an empty sweep, not a scan
155
+ * hole (the ruling's Q3), so it is filtered here rather than handed to
156
+ * `scanEstate` as an unscannable row.
157
+ */
158
+ export function existingWorktreeRoots(file) {
159
+ const seen = new Set();
160
+ const roots = [];
161
+ for (const root of file.roots) {
162
+ const resolved = path.resolve(root);
163
+ const key = foldCase(resolved);
164
+ if (seen.has(key))
165
+ continue;
166
+ seen.add(key);
167
+ if (isRealDirectory(resolved))
168
+ roots.push(resolved);
169
+ }
170
+ return roots;
171
+ }
172
+ /**
173
+ * Partition recorded roots into the sweep classes the estate consumers hand to
174
+ * `scanEstate`. Only the DEFAULT root (`~/.totem/worktrees`) carries container
175
+ * semantics — it exists solely to hold worktrees, so location alone is husk
176
+ * evidence there. Every other recorded root is a location the operator also
177
+ * uses for other things (a shared tmp, a scratch dir); those sweep as STANDARD
178
+ * roots, where husk-ness needs shape evidence — so one `wt create --root`
179
+ * against a scratch dir can never permanently arm by-location residue rows for
180
+ * every unrelated directory in it (#2580 slice-2 falsification, finding 11).
181
+ */
182
+ export function partitionWorktreeRoots(roots) {
183
+ const defaultKey = foldCase(path.resolve(defaultWorktreeRoot()));
184
+ const container = [];
185
+ const standard = [];
186
+ for (const root of roots) {
187
+ (foldCase(path.resolve(root)) === defaultKey ? container : standard).push(root);
188
+ }
189
+ return { container, standard };
190
+ }
191
+ /**
192
+ * Load the file for MUTATION. Unlike the read path this REFUSES to proceed on
193
+ * a schema failure: silently replacing an unparseable registry would delete
194
+ * every recorded root and entry it holds (`updateRegistryEntry`'s posture).
195
+ */
196
+ function loadForMutation(filePath) {
197
+ if (!fs.existsSync(filePath))
198
+ return emptyWorktreeFile();
199
+ try {
200
+ return readJsonSafe(filePath, WorktreeFileSchema);
201
+ }
202
+ catch (err) {
203
+ if (err instanceof TotemParseError && err.message.includes('Schema validation failed')) {
204
+ throw new TotemParseError('Worktree registry file has invalid schema — refusing to overwrite.', `Delete ${filePath} to reset (recorded roots and entries are lost).`, err.cause);
205
+ }
206
+ throw err;
207
+ }
208
+ }
209
+ /** PID-unique temp + rename: a concurrent reader never sees partial JSON. */
210
+ function writeAtomic(filePath, file) {
211
+ const tmpPath = `${filePath}.${process.pid}.tmp`;
212
+ fs.writeFileSync(tmpPath, JSON.stringify(file, null, 2) + '\n');
213
+ fs.renameSync(tmpPath, filePath);
214
+ }
215
+ /**
216
+ * Record a worktree and the root it lives under, under the `~/.totem` lock.
217
+ * Called BEFORE `git worktree add` — the intent record is what makes a failed
218
+ * creation visible instead of invisible.
219
+ */
220
+ export async function addWorktreeEntry(args) {
221
+ const dir = worktreeRegistryDir();
222
+ const filePath = worktreeRegistryPath();
223
+ fs.mkdirSync(dir, { recursive: true });
224
+ const release = await acquireLock(dir);
225
+ try {
226
+ const file = loadForMutation(filePath);
227
+ const root = path.resolve(args.root);
228
+ // Roots accrete and are deduped case-folded on win32 only; the recorded
229
+ // spelling of the FIRST writer wins so the disclosure stays stable.
230
+ if (!file.roots.some((existing) => foldCase(path.resolve(existing)) === foldCase(root))) {
231
+ file.roots.push(root);
232
+ }
233
+ // Overwrite of an occupied key is BY DESIGN, not an oversight: the only
234
+ // path that reaches here with an existing entry is a re-create over a
235
+ // STALE record (create refuses when the target directory exists, so the
236
+ // dir is gone and the old entry describes nothing). Replacing it is the
237
+ // recovery; callers must not assume exclusive-write semantics. The
238
+ // delete side is what carries identity (expectCreatedAt guard below).
239
+ file.worktrees[path.resolve(args.worktreePath)] = args.entry;
240
+ writeAtomic(filePath, file);
241
+ }
242
+ finally {
243
+ release();
244
+ }
245
+ }
246
+ /**
247
+ * Delete a recorded entry under the `~/.totem` lock. Roots are deliberately
248
+ * untouched: their durability is independent of entry lifecycle, which is what
249
+ * keeps an emptied container root reachable for the estate sweep.
250
+ *
251
+ * Callers must only reach this AFTER verifying the directory is absent.
252
+ * Returns whether an entry was actually deleted (a git-listed worktree with no
253
+ * registry entry — the legacy estate — is a no-op, not an error).
254
+ *
255
+ * `expectCreatedAt` is an identity guard for the verify→delete window: a
256
+ * concurrent `wt create` can re-record the SAME path between a removal's
257
+ * absence check and this lock acquisition, and an unguarded delete-by-path
258
+ * would erase the replacement's durable record — the invisible-unrecorded
259
+ * class this registry exists to prevent (#2580 bot round, Greptile P1). When
260
+ * the stored entry's `createdAt` differs from the expected one, the entry is
261
+ * left in place and `false` is returned.
262
+ */
263
+ export async function deleteWorktreeEntry(worktreePath, opts) {
264
+ const dir = worktreeRegistryDir();
265
+ const filePath = worktreeRegistryPath();
266
+ if (!fs.existsSync(filePath))
267
+ return false;
268
+ fs.mkdirSync(dir, { recursive: true });
269
+ const release = await acquireLock(dir);
270
+ try {
271
+ const file = loadForMutation(filePath);
272
+ const found = findWorktreeEntry(file, worktreePath);
273
+ if (found === undefined)
274
+ return false;
275
+ if (opts?.expectCreatedAt !== undefined && found.entry.createdAt !== opts.expectCreatedAt) {
276
+ return false;
277
+ }
278
+ delete file.worktrees[found.key];
279
+ writeAtomic(filePath, file);
280
+ return true;
281
+ }
282
+ finally {
283
+ release();
284
+ }
285
+ }
286
+ //# sourceMappingURL=worktree-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-registry.js","sourceRoot":"","sources":["../src/worktree-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Worktree-registry tests (mmnto-ai/totem#2580 slice-2).
3
+ *
4
+ * The file is resolved through `os.homedir()`, so every test pins
5
+ * HOME/USERPROFILE at a temp directory — the same fixture shape the
6
+ * `readRegistry` tests in doctor.test.ts use. Nothing here mocks the
7
+ * filesystem: the contract being pinned is what actually lands on disk
8
+ * (atomic write, lock, accreting roots) and a mocked fs would assert the mock.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=worktree-registry.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-registry.test.d.ts","sourceRoot":"","sources":["../src/worktree-registry.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
@@ -0,0 +1,297 @@
1
+ /**
2
+ * Worktree-registry tests (mmnto-ai/totem#2580 slice-2).
3
+ *
4
+ * The file is resolved through `os.homedir()`, so every test pins
5
+ * HOME/USERPROFILE at a temp directory — the same fixture shape the
6
+ * `readRegistry` tests in doctor.test.ts use. Nothing here mocks the
7
+ * filesystem: the contract being pinned is what actually lands on disk
8
+ * (atomic write, lock, accreting roots) and a mocked fs would assert the mock.
9
+ */
10
+ import * as fs from 'node:fs';
11
+ import * as os from 'node:os';
12
+ import * as path from 'node:path';
13
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
14
+ // Module-namespace exports are not spyable under ESM, so `node:fs` is mocked
15
+ // ONCE with a pass-through `lstatSync` whose implementation individual tests
16
+ // override via `mockImplementationOnce` (the ecl-gc.test.ts house pattern);
17
+ // every other fs call, and every unconsumed call, is the real thing.
18
+ vi.mock('node:fs', async (importOriginal) => {
19
+ const actual = await importOriginal();
20
+ const lstatSync = vi.fn(actual.lstatSync);
21
+ return { ...actual, default: { ...actual, lstatSync }, lstatSync };
22
+ });
23
+ import { addWorktreeEntry, defaultWorktreeRoot, deleteWorktreeEntry, existingWorktreeRoots, findWorktreeEntry, partitionWorktreeRoots, readWorktreeRegistry, WORKTREE_REGISTRY_SCHEMA_VERSION, WorktreeFileSchema, worktreePathExists, worktreeRegistryPath, } from './worktree-registry.js';
24
+ const IS_WIN32 = process.platform === 'win32';
25
+ let home;
26
+ let prevHome;
27
+ let prevProfile;
28
+ beforeEach(() => {
29
+ home = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'totem-wtreg-')));
30
+ prevHome = process.env['HOME'];
31
+ prevProfile = process.env['USERPROFILE'];
32
+ process.env['HOME'] = home;
33
+ process.env['USERPROFILE'] = home;
34
+ });
35
+ afterEach(() => {
36
+ if (prevHome === undefined)
37
+ delete process.env['HOME'];
38
+ else
39
+ process.env['HOME'] = prevHome;
40
+ if (prevProfile === undefined)
41
+ delete process.env['USERPROFILE'];
42
+ else
43
+ process.env['USERPROFILE'] = prevProfile;
44
+ fs.rmSync(home, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
45
+ });
46
+ function entryFor(overrides = {}) {
47
+ return {
48
+ repo: path.join(home, 'repo'),
49
+ seat: 'totem-claude',
50
+ branch: 'wt/demo',
51
+ createdAt: '2026-08-07T10:00:00.000Z',
52
+ ...overrides,
53
+ };
54
+ }
55
+ function writeRaw(contents) {
56
+ fs.mkdirSync(path.join(home, '.totem'), { recursive: true });
57
+ fs.writeFileSync(worktreeRegistryPath(), contents, 'utf-8');
58
+ }
59
+ // ─── Read path ──────────────────────────────────────────
60
+ describe('readWorktreeRegistry', () => {
61
+ it('returns an empty registry when the file has never been written', () => {
62
+ const warnings = [];
63
+ const file = readWorktreeRegistry((msg) => warnings.push(msg));
64
+ expect(file).toEqual({
65
+ schemaVersion: WORKTREE_REGISTRY_SCHEMA_VERSION,
66
+ roots: [],
67
+ worktrees: {},
68
+ });
69
+ // First run is not a degradation — it must not warn.
70
+ expect(warnings).toEqual([]);
71
+ });
72
+ // The `readRegistry` posture: a corrupt file warns LOUDLY and degrades to
73
+ // empty, so a read-only verb still runs and the operator still learns.
74
+ it('warns and degrades to empty on an unparseable file', () => {
75
+ writeRaw('{ not json');
76
+ const warnings = [];
77
+ const file = readWorktreeRegistry((msg) => warnings.push(msg));
78
+ expect(file.worktrees).toEqual({});
79
+ expect(warnings).toHaveLength(1);
80
+ expect(warnings[0]).toContain('Cannot read worktree registry');
81
+ });
82
+ it('warns on a schema-invalid file rather than trusting the shape', () => {
83
+ writeRaw(JSON.stringify({ schemaVersion: 2, roots: [], worktrees: {} }));
84
+ const warnings = [];
85
+ readWorktreeRegistry((msg) => warnings.push(msg));
86
+ expect(warnings).toHaveLength(1);
87
+ });
88
+ it('preserves unknown entry fields written by a newer CLI (passthrough)', async () => {
89
+ const target = path.join(home, 'container', 'repo-seat-slug');
90
+ await addWorktreeEntry({
91
+ worktreePath: target,
92
+ entry: { ...entryFor(), futureField: 'kept' },
93
+ root: path.join(home, 'container'),
94
+ });
95
+ const file = readWorktreeRegistry();
96
+ const found = findWorktreeEntry(file, target);
97
+ expect(found?.entry['futureField']).toBe('kept');
98
+ });
99
+ });
100
+ // ─── Mutation path ──────────────────────────────────────
101
+ describe('addWorktreeEntry', () => {
102
+ it('creates the file with the entry and its root', async () => {
103
+ const root = path.join(home, 'container');
104
+ const target = path.join(root, 'repo-totem-claude-demo');
105
+ await addWorktreeEntry({ worktreePath: target, entry: entryFor(), root });
106
+ const file = readWorktreeRegistry();
107
+ expect(file.schemaVersion).toBe(WORKTREE_REGISTRY_SCHEMA_VERSION);
108
+ expect(file.roots).toEqual([path.resolve(root)]);
109
+ expect(findWorktreeEntry(file, target)?.entry.branch).toBe('wt/demo');
110
+ // The written bytes must satisfy the schema — a reader on another version
111
+ // parses the same file.
112
+ const raw = JSON.parse(fs.readFileSync(worktreeRegistryPath(), 'utf-8'));
113
+ expect(() => WorktreeFileSchema.parse(raw)).not.toThrow();
114
+ });
115
+ it('accretes roots, deduped case-folded on win32 ONLY', async () => {
116
+ const root = path.join(home, 'container');
117
+ await addWorktreeEntry({
118
+ worktreePath: path.join(root, 'a'),
119
+ entry: entryFor(),
120
+ root,
121
+ });
122
+ await addWorktreeEntry({
123
+ worktreePath: path.join(root, 'b'),
124
+ entry: entryFor(),
125
+ root: root.toUpperCase(),
126
+ });
127
+ const file = readWorktreeRegistry();
128
+ // Invariant 9: win32 folds (one root), POSIX does not (two distinct paths).
129
+ expect(file.roots).toHaveLength(IS_WIN32 ? 1 : 2);
130
+ // The FIRST spelling wins on win32, so the disclosure stays stable.
131
+ expect(file.roots[0]).toBe(path.resolve(root));
132
+ });
133
+ it('refuses to overwrite a file whose schema does not parse', async () => {
134
+ writeRaw(JSON.stringify({ schemaVersion: 99, roots: 'not-an-array' }));
135
+ await expect(addWorktreeEntry({
136
+ worktreePath: path.join(home, 'x'),
137
+ entry: entryFor(),
138
+ root: home,
139
+ })).rejects.toThrow(/refusing to overwrite/);
140
+ // The bytes are untouched — a mutation that cannot read cannot destroy.
141
+ expect(fs.readFileSync(worktreeRegistryPath(), 'utf-8')).toContain('not-an-array');
142
+ });
143
+ });
144
+ describe('deleteWorktreeEntry', () => {
145
+ it('deletes the entry and RETAINS the root (invariant 8, registry half)', async () => {
146
+ const root = path.join(home, 'container');
147
+ const target = path.join(root, 'repo-totem-claude-demo');
148
+ await addWorktreeEntry({ worktreePath: target, entry: entryFor(), root });
149
+ expect(await deleteWorktreeEntry(target)).toBe(true);
150
+ const file = readWorktreeRegistry();
151
+ expect(file.worktrees).toEqual({});
152
+ // The whole point: a container root outlives every entry under it, so the
153
+ // location stays reachable for the estate sweep with zero live entries.
154
+ expect(file.roots).toEqual([path.resolve(root)]);
155
+ });
156
+ it('is a no-op (false, not an error) for a path with no entry', async () => {
157
+ const root = path.join(home, 'container');
158
+ await addWorktreeEntry({
159
+ worktreePath: path.join(root, 'kept'),
160
+ entry: entryFor(),
161
+ root,
162
+ });
163
+ expect(await deleteWorktreeEntry(path.join(root, 'legacy-worktree'))).toBe(false);
164
+ expect(Object.keys(readWorktreeRegistry().worktrees)).toHaveLength(1);
165
+ });
166
+ it('is a no-op when the file does not exist at all', async () => {
167
+ expect(await deleteWorktreeEntry(path.join(home, 'anything'))).toBe(false);
168
+ });
169
+ // The verify→delete window guard (bot round, Greptile P1): a concurrent
170
+ // `wt create` can re-record the same path between a removal's absence check
171
+ // and this delete — the identity guard must leave the replacement's record.
172
+ it('refuses the delete and RETAINS the entry when expectCreatedAt differs', async () => {
173
+ const root = path.join(home, 'container');
174
+ const target = path.join(root, 'repo-totem-claude-demo');
175
+ await addWorktreeEntry({ worktreePath: target, entry: entryFor(), root });
176
+ expect(await deleteWorktreeEntry(target, { expectCreatedAt: '2026-08-07T23:59:59.000Z' })).toBe(false);
177
+ // The (replacement-shaped) entry survives untouched.
178
+ expect(findWorktreeEntry(readWorktreeRegistry(), target)?.entry.createdAt).toBe(entryFor().createdAt);
179
+ });
180
+ it('deletes normally when expectCreatedAt matches the stored entry', async () => {
181
+ const root = path.join(home, 'container');
182
+ const target = path.join(root, 'repo-totem-claude-demo');
183
+ await addWorktreeEntry({ worktreePath: target, entry: entryFor(), root });
184
+ expect(await deleteWorktreeEntry(target, { expectCreatedAt: entryFor().createdAt })).toBe(true);
185
+ expect(readWorktreeRegistry().worktrees).toEqual({});
186
+ });
187
+ });
188
+ // ─── Path identity (invariant 9) ────────────────────────
189
+ describe('findWorktreeEntry', () => {
190
+ it('folds case on win32 only', async () => {
191
+ const root = path.join(home, 'container');
192
+ const target = path.join(root, 'repo-totem-claude-demo');
193
+ await addWorktreeEntry({ worktreePath: target, entry: entryFor(), root });
194
+ const file = readWorktreeRegistry();
195
+ expect(findWorktreeEntry(file, target)).toBeDefined();
196
+ const shouted = findWorktreeEntry(file, target.toUpperCase());
197
+ if (IS_WIN32)
198
+ expect(shouted).toBeDefined();
199
+ else
200
+ expect(shouted).toBeUndefined();
201
+ });
202
+ });
203
+ // ─── Root projection for the doctor coupling ────────────
204
+ describe('existingWorktreeRoots', () => {
205
+ it('keeps roots that exist and drops the ones that do not', () => {
206
+ const present = path.join(home, 'present');
207
+ fs.mkdirSync(present, { recursive: true });
208
+ const gone = path.join(home, 'gone');
209
+ const roots = existingWorktreeRoots({
210
+ schemaVersion: WORKTREE_REGISTRY_SCHEMA_VERSION,
211
+ // Duplicated deliberately — the sweep must receive each root once.
212
+ roots: [present, present, gone],
213
+ worktrees: {},
214
+ });
215
+ expect(roots).toEqual([path.resolve(present)]);
216
+ });
217
+ it('drops a recorded root that is a FILE, never sweeping it as a directory', () => {
218
+ const file = path.join(home, 'not-a-dir');
219
+ fs.writeFileSync(file, 'x', 'utf-8');
220
+ expect(existingWorktreeRoots({
221
+ schemaVersion: WORKTREE_REGISTRY_SCHEMA_VERSION,
222
+ roots: [file],
223
+ worktrees: {},
224
+ })).toEqual([]);
225
+ });
226
+ });
227
+ describe('worktreePathExists', () => {
228
+ it('is no-follow: a dangling link still reports as PRESENT', () => {
229
+ const target = path.join(home, 'target');
230
+ fs.mkdirSync(target, { recursive: true });
231
+ const link = path.join(home, 'link');
232
+ fs.symlinkSync(target, link, IS_WIN32 ? 'junction' : 'dir');
233
+ fs.rmSync(target, { recursive: true, force: true });
234
+ // `existsSync` follows and would answer false here; the removal verb must
235
+ // not read a dangling junction as "already gone".
236
+ expect(worktreePathExists(link)).toBe(true);
237
+ expect(worktreePathExists(path.join(home, 'never-existed'))).toBe(false);
238
+ });
239
+ // Fail-closed (bot round, CR findings 8+9): only ENOENT/ENOTDIR PROVE
240
+ // absence; an unknowable path must read as present so removal fails loud
241
+ // rather than deleting a record for a directory that may still stand.
242
+ it('fails CLOSED: a non-ENOENT lstat failure reads as PRESENT', () => {
243
+ vi.mocked(fs.lstatSync).mockImplementationOnce(() => {
244
+ throw Object.assign(new Error('EACCES: permission denied'), { code: 'EACCES' });
245
+ });
246
+ expect(worktreePathExists(path.join(home, 'denied'))).toBe(true);
247
+ });
248
+ it('reads ENOENT as absent through the same mock seam', () => {
249
+ vi.mocked(fs.lstatSync).mockImplementationOnce(() => {
250
+ throw Object.assign(new Error('ENOENT: no such file or directory'), { code: 'ENOENT' });
251
+ });
252
+ expect(worktreePathExists(path.join(home, 'missing'))).toBe(false);
253
+ });
254
+ it('fails CLOSED on a non-object throw — no errno cannot prove absence', () => {
255
+ // Round 2, GCA null-safety finding: a throw that is not an object carries
256
+ // no `code`; the probe must answer present, not crash on the extraction.
257
+ vi.mocked(fs.lstatSync).mockImplementationOnce(() => {
258
+ throw null;
259
+ });
260
+ expect(worktreePathExists(path.join(home, 'null-throw'))).toBe(true);
261
+ });
262
+ });
263
+ describe('defaultWorktreeRoot', () => {
264
+ it('is ~/.totem/worktrees under the pinned home', () => {
265
+ expect(path.resolve(defaultWorktreeRoot())).toBe(path.join(home, '.totem', 'worktrees'));
266
+ });
267
+ });
268
+ describe('partitionWorktreeRoots', () => {
269
+ it('routes the default root to container and everything else to standard', () => {
270
+ const scratch = path.join(home, 'scratch');
271
+ const { container, standard } = partitionWorktreeRoots([defaultWorktreeRoot(), scratch]);
272
+ expect(container).toEqual([defaultWorktreeRoot()]);
273
+ expect(standard).toEqual([scratch]);
274
+ });
275
+ it('returns empty partitions for empty input', () => {
276
+ expect(partitionWorktreeRoots([])).toEqual({ container: [], standard: [] });
277
+ });
278
+ it('keeps duplicate roots on their side rather than deduping — accretion is the writer’s charge', () => {
279
+ const scratch = path.join(home, 'scratch');
280
+ const { container, standard } = partitionWorktreeRoots([scratch, scratch]);
281
+ expect(container).toEqual([]);
282
+ expect(standard).toEqual([scratch, scratch]);
283
+ });
284
+ it('matches the default root case-insensitively on win32 ONLY (invariant 9)', () => {
285
+ const shouted = path.join(home, '.TOTEM', 'WORKTREES');
286
+ const { container, standard } = partitionWorktreeRoots([shouted]);
287
+ if (IS_WIN32) {
288
+ expect(container).toEqual([shouted]);
289
+ expect(standard).toEqual([]);
290
+ }
291
+ else {
292
+ expect(container).toEqual([]);
293
+ expect(standard).toEqual([shouted]);
294
+ }
295
+ });
296
+ });
297
+ //# sourceMappingURL=worktree-registry.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worktree-registry.test.js","sourceRoot":"","sources":["../src/worktree-registry.test.ts"],"names":[],"mappings":"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"}