leerness 1.36.185 → 1.36.186

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,230 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // Snapshot selection must preserve the resolver's decisions and diagnostics
5
+ // while adding no filesystem calls, writes, or ambient environment dependency.
6
+ const assert = require('assert');
7
+ const crypto = require('crypto');
8
+ const fs = require('fs');
9
+ const os = require('os');
10
+ const path = require('path');
11
+ const W = require('../lib/workspace-dir');
12
+
13
+ const arena = fs.mkdtempSync(path.join(os.tmpdir(), 'leerness-workspace-selection-'));
14
+ const canonical = W.CANONICAL_WORKSPACE_DIR;
15
+ const legacy = W.LEGACY_WORKSPACE_DIR;
16
+ let total = 0;
17
+ let failed = 0;
18
+ let fixtureCount = 0;
19
+
20
+ const check = (label, fn) => {
21
+ total += 1;
22
+ try {
23
+ fn();
24
+ process.stdout.write(`ok - ${label}\n`);
25
+ } catch (error) {
26
+ failed += 1;
27
+ process.stderr.write(`not ok - ${label}: ${error.stack || error.message}\n`);
28
+ }
29
+ };
30
+
31
+ const fixture = (entries = {}) => {
32
+ const root = path.join(arena, `project-${++fixtureCount}`);
33
+ fs.mkdirSync(root);
34
+ for (const [relative, content] of Object.entries(entries)) {
35
+ const file = path.join(root, relative);
36
+ if (content === null) fs.mkdirSync(file, { recursive: true });
37
+ else {
38
+ fs.mkdirSync(path.dirname(file), { recursive: true });
39
+ fs.writeFileSync(file, content, 'utf8');
40
+ }
41
+ }
42
+ return root;
43
+ };
44
+
45
+ const snapshot = root => {
46
+ const rows = [];
47
+ const visit = (file, relative) => {
48
+ const stat = fs.lstatSync(file, { bigint: true });
49
+ const meta = [relative, stat.mode.toString(), stat.size.toString(), stat.mtimeNs.toString()];
50
+ if (stat.isSymbolicLink()) rows.push([...meta, 'link', fs.readlinkSync(file)]);
51
+ else if (stat.isDirectory()) {
52
+ rows.push([...meta, 'directory']);
53
+ for (const child of fs.readdirSync(file).sort()) visit(path.join(file, child), `${relative}/${child}`);
54
+ } else rows.push([...meta, 'file', crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex')]);
55
+ };
56
+ visit(root, '.');
57
+ return JSON.stringify(rows);
58
+ };
59
+
60
+ const outcome = fn => {
61
+ try { return { selected: fn() }; }
62
+ catch (error) {
63
+ return { name: error.name, code: error.code, message: error.message,
64
+ ...Object.fromEntries(['root', 'file', 'legacy', 'canonical', 'value']
65
+ .filter(key => Object.prototype.hasOwnProperty.call(error, key)).map(key => [key, error[key]])) };
66
+ }
67
+ };
68
+
69
+ const freeze = value => {
70
+ if (value && typeof value === 'object') {
71
+ for (const child of Object.values(value)) freeze(child);
72
+ Object.freeze(value);
73
+ }
74
+ return value;
75
+ };
76
+
77
+ const sameSelection = (root, envValue, expected) => {
78
+ const before = snapshot(root);
79
+ const state = freeze(W.inspectWorkspace(root));
80
+ const selected = outcome(() => W.selectWorkspaceDirName(state, envValue));
81
+ const resolved = outcome(() => W.resolveWorkspaceDirName(root, { envValue }));
82
+ assert.deepStrictEqual(selected, expected);
83
+ assert.deepStrictEqual(resolved, expected);
84
+ assert.strictEqual(snapshot(root), before, 'inspection changed bytes or metadata');
85
+ return state;
86
+ };
87
+
88
+ const directoryError = (root, name, symlink = false) => ({
89
+ name: 'WorkspaceDirectoryError',
90
+ code: symlink ? 'E_WORKSPACE_DIR_SYMLINK' : 'E_WORKSPACE_DIR_INVALID',
91
+ message: symlink
92
+ ? `workspace directory must not be a symbolic link or junction: ${path.join(root, name)}`
93
+ : `workspace path is not a directory: ${path.join(root, name)}`,
94
+ root: path.resolve(root), file: path.join(root, name),
95
+ });
96
+
97
+ const conflictError = root => ({
98
+ name: 'WorkspaceDirectoryError', code: 'E_WORKSPACE_DIR_CONFLICT',
99
+ message: `both ${legacy} and ${canonical} contain live workspace files`,
100
+ root: path.resolve(root), legacy: path.join(root, legacy), canonical: path.join(root, canonical),
101
+ });
102
+
103
+ const withEnv = (value, fn) => {
104
+ const previous = process.env.LEERNESS_WORKSPACE_DIR;
105
+ if (value == null) delete process.env.LEERNESS_WORKSPACE_DIR;
106
+ else process.env.LEERNESS_WORKSPACE_DIR = value;
107
+ try { return fn(); }
108
+ finally {
109
+ if (previous === undefined) delete process.env.LEERNESS_WORKSPACE_DIR;
110
+ else process.env.LEERNESS_WORKSPACE_DIR = previous;
111
+ }
112
+ };
113
+
114
+ try {
115
+ const scenarios = [
116
+ ['canonical marker', { [`${canonical}/HARNESS_VERSION`]: '1.36.185\n' }, canonical],
117
+ ['legacy marker', { [`${legacy}/HARNESS_VERSION`]: '1.36.161\n' }, legacy],
118
+ ['empty project', {}, canonical],
119
+ ['two empty directories prefer canonical', { [canonical]: null, [legacy]: null }, canonical],
120
+ ['empty legacy directory', { [legacy]: null }, legacy],
121
+ ['foreign canonical retains default fallback', { [`${canonical}/unrelated.txt`]: 'keep\n' }, canonical],
122
+ ['foreign canonical yields to empty legacy', { [`${canonical}/unrelated.txt`]: 'keep\n', [legacy]: null }, legacy],
123
+ ['canonical substrate yields to live legacy', { [`${canonical}/state.json`]: '{}\n', [`${legacy}/guideline.md`]: '# Keep\n' }, legacy],
124
+ ['canonical marker wins over empty legacy', { [`${canonical}/manifest.json`]: '{}\n', [legacy]: null }, canonical],
125
+ ['corrupt marker content is not parsed by topology inspection', { [`${canonical}/manifest.json`]: '{broken' }, canonical],
126
+ ];
127
+ for (const [label, entries, selected] of scenarios) {
128
+ check(`${label}: resolver and snapshot selector agree without writes`, () => {
129
+ sameSelection(fixture(entries), null, { selected });
130
+ });
131
+ }
132
+
133
+ const conflictRoot = fixture({ [`${canonical}/HARNESS_VERSION`]: '1\n', [`${legacy}/HARNESS_VERSION`]: '2\n' });
134
+ check('dual-live state preserves the exact conflict error', () => sameSelection(conflictRoot, null, conflictError(conflictRoot)));
135
+ check('forced selection cannot bypass a dual-live conflict', () => sameSelection(conflictRoot, canonical, conflictError(conflictRoot)));
136
+ check('migration markers do not turn conflicting state into an authoritative copy', () => {
137
+ const root = fixture({ [`${canonical}/HARNESS_VERSION`]: '1\n', [`${canonical}/MIGRATED_FROM_HARNESS`]: 'previous migration\n', [`${legacy}/HARNESS_VERSION`]: '2\n' });
138
+ sameSelection(root, null, conflictError(root));
139
+ });
140
+ check('invalid override retains its priority over workspace conflict', () => {
141
+ sameSelection(conflictRoot, 'other', { name: 'WorkspaceDirectoryError', code: 'E_WORKSPACE_DIR_INVALID',
142
+ message: `LEERNESS_WORKSPACE_DIR must be ${canonical} or ${legacy}; got: other`, value: 'other' });
143
+ });
144
+
145
+ for (const selected of [canonical, legacy]) {
146
+ check(`existing ${selected} can be selected explicitly`, () => {
147
+ const other = selected === canonical ? legacy : canonical;
148
+ const root = fixture({ [selected]: null, [`${other}/HARNESS_VERSION`]: '1\n' });
149
+ sameSelection(root, selected, { selected });
150
+ sameSelection(root, ` ${selected} `, { selected });
151
+ });
152
+ check(`missing forced ${selected} preserves its error fields`, () => {
153
+ const root = fixture();
154
+ sameSelection(root, selected, { name: 'WorkspaceDirectoryError', code: 'E_WORKSPACE_DIR_MISSING',
155
+ message: `configured workspace directory does not exist: ${path.join(root, selected)}`,
156
+ root, value: selected });
157
+ });
158
+ check(`a file at ${selected} is not accepted as a workspace`, () => {
159
+ const root = fixture({ [selected]: 'not a directory\n' });
160
+ sameSelection(root, null, directoryError(root, selected));
161
+ });
162
+ check(`a link at ${selected} is rejected without following its target`, () => {
163
+ const root = fixture();
164
+ const target = fixture({ 'keep.txt': 'outside workspace\n' });
165
+ fs.symlinkSync(target, path.join(root, selected), process.platform === 'win32' ? 'junction' : 'dir');
166
+ const beforeTarget = snapshot(target);
167
+ sameSelection(root, null, directoryError(root, selected, true));
168
+ assert.strictEqual(snapshot(target), beforeTarget);
169
+ });
170
+ }
171
+
172
+ const envRoot = fixture({ [canonical]: null, [legacy]: null });
173
+ check('public resolver preserves explicit-option precedence over ambient environment', () => {
174
+ withEnv(legacy, () => {
175
+ assert.strictEqual(W.resolveWorkspaceDirName(envRoot), legacy);
176
+ assert.strictEqual(W.resolveWorkspaceDirName(envRoot, { envValue: undefined }), legacy);
177
+ assert.strictEqual(W.resolveWorkspaceDirName(envRoot, { envValue: canonical }), canonical);
178
+ assert.strictEqual(W.resolveWorkspaceDirName(envRoot, { envValue: null }), canonical);
179
+ assert.strictEqual(W.resolveWorkspaceDirName(envRoot, { envValue: '' }), canonical);
180
+ });
181
+ });
182
+ check('pure selector does not read ambient environment', () => {
183
+ const state = freeze(W.inspectWorkspace(envRoot));
184
+ withEnv('invalid-ambient-override', () => {
185
+ assert.strictEqual(W.selectWorkspaceDirName(state), canonical);
186
+ assert.strictEqual(W.selectWorkspaceDirName(state, legacy), legacy);
187
+ });
188
+ });
189
+ check('frozen snapshot selection adds zero filesystem calls', () => {
190
+ const state = freeze(W.inspectWorkspace(envRoot));
191
+ const original = new Map();
192
+ const calls = [];
193
+ // Intercept every sync fs primitive, including reads and writes, after
194
+ // acquiring the snapshot. Restore before assertions or fixture cleanup.
195
+ for (const key of Object.keys(fs).filter(key => /Sync$/.test(key) && typeof fs[key] === 'function')) {
196
+ original.set(key, fs[key]);
197
+ fs[key] = (...args) => { calls.push(key); throw new Error(`unexpected fs.${key}`); };
198
+ }
199
+ let selected;
200
+ try { selected = W.selectWorkspaceDirName(state, null); }
201
+ finally { for (const [key, value] of original) fs[key] = value; }
202
+ assert.strictEqual(selected, canonical);
203
+ assert.deepStrictEqual(calls, []);
204
+ });
205
+ check('public resolver inspects each workspace directory exactly once', () => {
206
+ const originalLstat = fs.lstatSync;
207
+ const originalReadDir = fs.readdirSync;
208
+ const lstatCalls = [];
209
+ const readDirCalls = [];
210
+ fs.lstatSync = function (...args) { lstatCalls.push(path.resolve(String(args[0]))); return originalLstat.apply(this, args); };
211
+ fs.readdirSync = function (...args) { readDirCalls.push(path.resolve(String(args[0]))); return originalReadDir.apply(this, args); };
212
+ let selected;
213
+ try { selected = W.resolveWorkspaceDirName(envRoot, { envValue: null }); }
214
+ finally { fs.lstatSync = originalLstat; fs.readdirSync = originalReadDir; }
215
+ assert.strictEqual(selected, canonical);
216
+ const expected = [path.join(envRoot, legacy), path.join(envRoot, canonical)];
217
+ assert.deepStrictEqual(lstatCalls, expected);
218
+ assert.deepStrictEqual(readDirCalls, expected);
219
+ });
220
+ } finally {
221
+ const cleanupRoot = path.resolve(arena);
222
+ const temporaryRoot = path.resolve(os.tmpdir());
223
+ if (path.dirname(cleanupRoot) !== temporaryRoot || !path.basename(cleanupRoot).startsWith('leerness-workspace-selection-')) {
224
+ throw new Error(`refusing cleanup outside the probe arena: ${cleanupRoot}`);
225
+ }
226
+ fs.rmSync(cleanupRoot, { recursive: true, force: true });
227
+ }
228
+
229
+ process.stdout.write(`WORKSPACE_SELECTION_PROBE ${total - failed}/${total} passed\n`);
230
+ process.exitCode = failed ? 1 : 0;