leerness 1.36.302 → 1.36.304
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/CHANGELOG.md +28 -0
- package/CONTRIBUTING.md +2 -0
- package/README.md +4 -4
- package/bin/leerness.js +1 -1
- package/package.json +1 -1
- package/scripts/agents-bench-output-probe.js +1 -0
- package/scripts/api-skill-match-probe.js +1 -0
- package/scripts/audit-env-text-probe.js +1 -0
- package/scripts/audit-readme-text-probe.js +1 -0
- package/scripts/audit-text-probe.js +1 -0
- package/scripts/authoring-language-probe.js +1 -0
- package/scripts/auto-update-hooks-probe.js +1 -0
- package/scripts/brief-text-probe.js +1 -0
- package/scripts/bugfix-areas-probe.js +1 -0
- package/scripts/ci-shard-probe.js +114 -0
- package/scripts/ci-shard.js +37 -2
- package/scripts/claim-runtime-cache-probe.js +1 -0
- package/scripts/claim-sweep-git-probe.js +1 -0
- package/scripts/claims-baseline-concurrency-probe.js +1 -0
- package/scripts/claims-baseline-probe.js +1 -0
- package/scripts/command-flags-probe.js +1 -0
- package/scripts/context-current-probe.js +1 -0
- package/scripts/context-reading-probe.js +1 -0
- package/scripts/copy-tree-probe.js +1 -0
- package/scripts/crud-check-probe.js +1 -0
- package/scripts/dead-flags-probe.js +1 -0
- package/scripts/done-status-probe.js +1 -0
- package/scripts/dry-run-refusal-probe.js +1 -0
- package/scripts/e2e-child-diagnostics-probe.js +1 -0
- package/scripts/e2e-command-surface.js +1 -0
- package/scripts/e2e-concurrency.js +1 -0
- package/scripts/e2e-core.js +1 -0
- package/scripts/e2e-lived-in-harness.js +1 -0
- package/scripts/e2e-repo-guard.js +1 -0
- package/scripts/e2e-temp-scope-probe.js +1 -0
- package/scripts/e2e.js +5 -0
- package/scripts/encoding-diagnostics-probe.js +1 -0
- package/scripts/encoding-selftest-probe.js +1 -0
- package/scripts/env-snapshot-text-probe.js +1 -0
- package/scripts/env-sync-text-probe.js +1 -0
- package/scripts/execution-ledger-sync-probe.js +1 -0
- package/scripts/false-claim-probe.js +1 -0
- package/scripts/feature-graph-text-probe.js +1 -0
- package/scripts/file-lease-probe.js +1 -0
- package/scripts/fix-evidence-language-probe.js +1 -0
- package/scripts/free-text-args-probe.js +1 -0
- package/scripts/generation-text-probe.js +1 -0
- package/scripts/git-resolution-cache-probe.js +1 -0
- package/scripts/github-login-probe.js +1 -0
- package/scripts/handoff-history-text-probe.js +1 -0
- package/scripts/handoff-i18n-probe.js +1 -0
- package/scripts/handoff-preservation-probe.js +1 -0
- package/scripts/handoff-readonly-probe.js +1 -0
- package/scripts/handoff-text-probe.js +1 -0
- package/scripts/harness-text-probe.js +1 -0
- package/scripts/history-retention-probe.js +1 -0
- package/scripts/history-retention-write-probe.js +1 -0
- package/scripts/i18n-next-cluster-probe.js +1 -0
- package/scripts/i18n-priority-surface-probe.js +1 -0
- package/scripts/install-text-probe.js +1 -0
- package/scripts/installed-cleanroom-probe.js +1 -0
- package/scripts/installed-handoff-lifecycle-probe.js +1 -0
- package/scripts/lazy-auto-track-probe.js +1 -0
- package/scripts/legacy-runtime-negative-probe.js +1 -0
- package/scripts/lock-heartbeat-probe.js +1 -0
- package/scripts/lock-probe.js +1 -0
- package/scripts/managed-text-probe.js +1 -0
- package/scripts/mcp-presence-probe.js +1 -0
- package/scripts/memory-archive-check-probe.js +1 -0
- package/scripts/memory-archive-retention-probe.js +1 -0
- package/scripts/memory-arena-cleanup-probe.js +1 -0
- package/scripts/memory-checked-input-probe.js +1 -0
- package/scripts/memory-guard-order-probe.js +1 -0
- package/scripts/memory-input-preflight-probe.js +1 -0
- package/scripts/memory-input-unit-probe.js +1 -0
- package/scripts/memory-language-probe.js +1 -0
- package/scripts/memory-legacy-retention-probe.js +1 -0
- package/scripts/memory-migration-concurrency-probe.js +1 -0
- package/scripts/memory-migration-test-support.js +11 -28
- package/scripts/memory-migration-transport-probe.js +1 -0
- package/scripts/memory-output-parent-race-probe.js +1 -0
- package/scripts/memory-output-posix-probe.js +1 -0
- package/scripts/memory-output-publication-probe.js +1 -0
- package/scripts/memory-output-unit-probe.js +1 -0
- package/scripts/memory-projection-retention-probe.js +1 -0
- package/scripts/memory-recovery-external-probe.js +1 -0
- package/scripts/memory-recovery-receipt-probe.js +1 -0
- package/scripts/memory-restore-canonical-probe.js +1 -0
- package/scripts/memory-utf8-admission-probe.js +1 -0
- package/scripts/memory-write-budget-meter.js +1 -0
- package/scripts/migration-compat.js +1 -0
- package/scripts/mode-text-probe.js +1 -0
- package/scripts/mutation-integrity-probe.js +1 -0
- package/scripts/next-action-suggestion-probe.js +1 -0
- package/scripts/openai-response-retrieval-probe.js +1 -0
- package/scripts/openai-ui-review-dispatch-probe.js +1 -0
- package/scripts/openai-ui-review-observation-probe.js +1 -0
- package/scripts/openai-ui-review-receipt-probe.js +1 -0
- package/scripts/parent-detect-selftest-probe.js +1 -0
- package/scripts/plain-language-reporting-probe.js +1 -0
- package/scripts/plan-text-probe.js +1 -0
- package/scripts/platform-smoke.js +1 -0
- package/scripts/provider-capacity-probe.js +1 -0
- package/scripts/race-overlap-probe.js +1 -0
- package/scripts/release-bump-probe.js +1 -0
- package/scripts/release-runtime-probe.js +1 -0
- package/scripts/reminder-text-probe.js +1 -0
- package/scripts/review-checkpoint-transport-probe.js +1 -0
- package/scripts/review-control-probe.js +1 -0
- package/scripts/review-feedback-probe.js +1 -0
- package/scripts/review-request-labels-probe.js +1 -0
- package/scripts/review-request-signals-probe.js +1 -0
- package/scripts/review-snapshot-transport-probe.js +1 -0
- package/scripts/role-agent-schema-probe.js +1 -0
- package/scripts/role-fallback-probe.js +1 -0
- package/scripts/role-file-identity-probe.js +1 -0
- package/scripts/role-store-loader-probe.js +1 -0
- package/scripts/rule-applicability-probe.js +1 -0
- package/scripts/rule-text-probe.js +1 -0
- package/scripts/rule-verification-probe.js +1 -0
- package/scripts/runtime-admission-probe.js +1 -0
- package/scripts/runtime-cost-probe.js +1 -0
- package/scripts/runtime-descriptor-identity-probe.js +1 -0
- package/scripts/runtime-layout-probe.js +1 -0
- package/scripts/runtime-repl-probe.js +1 -0
- package/scripts/runtime-replacement-probe.js +1 -0
- package/scripts/runtime-write-probe.js +1 -0
- package/scripts/secret-scan-scope-probe.js +1 -0
- package/scripts/selftest-cleanup-probe.js +1 -0
- package/scripts/session-close-text-probe.js +1 -0
- package/scripts/shared-state-lock-probe.js +1 -0
- package/scripts/skill-archive-probe.js +1 -0
- package/scripts/smoke.js +1 -0
- package/scripts/state-inspect-cli-probe.js +1 -0
- package/scripts/state-scopes-probe.js +1 -0
- package/scripts/store-diagnostic-identity-probe.js +1 -0
- package/scripts/store-diagnostic-probe.js +1 -0
- package/scripts/store-values-probe.js +1 -0
- package/scripts/task-sync-roundtrip-probe.js +1 -0
- package/scripts/teams-text-probe.js +1 -0
- package/scripts/temp-cleanup-probe.js +433 -0
- package/scripts/temp-cleanup.js +182 -1
- package/scripts/test-execution-plan-probe.js +1 -0
- package/scripts/test-firestore-probe.js +1 -0
- package/scripts/test-http-probe.js +1 -0
- package/scripts/test-node-runner-probe.js +1 -0
- package/scripts/test-npm-script-probe.js +1 -0
- package/scripts/test-npm-script-runner-probe.js +1 -0
- package/scripts/test-prerequisite-probe.js +1 -0
- package/scripts/test-suite-list-runner-probe.js +1 -0
- package/scripts/title-args-probe.js +1 -0
- package/scripts/tracker-write-language-probe.js +1 -0
- package/scripts/ui-boundary-browser-probe.js +1 -0
- package/scripts/ui-boundary-contracts-probe.js +1 -0
- package/scripts/ui-boundary-dashboard-probe.js +1 -0
- package/scripts/ui-copy-boundary-probe.js +1 -0
- package/scripts/ui-review-attempt-probe.js +1 -0
- package/scripts/ui-review-authority-floor-probe.js +1 -0
- package/scripts/ui-review-authority-host-probe.js +1 -0
- package/scripts/ui-review-authorization-probe.js +1 -0
- package/scripts/ui-review-ledger-probe.js +1 -0
- package/scripts/ui-review-observation-probe.js +1 -0
- package/scripts/ui-review-proof-use-probe.js +1 -0
- package/scripts/ui-review-publication-probe.js +1 -0
- package/scripts/ui-review-recovery-probe.js +1 -0
- package/scripts/ui-review-result-probe.js +1 -0
- package/scripts/ui-review-run-probe.js +1 -0
- package/scripts/ui-review-target-probe.js +1 -0
- package/scripts/ui-review-transport-probe.js +1 -0
- package/scripts/verify-code-cross-runtime-probe.js +1 -0
- package/scripts/which-shim-probe.js +1 -0
- package/scripts/workspace-dir-lock-order-probe.js +1 -0
- package/scripts/workspace-dir-migration-probe.js +1 -0
- package/scripts/workspace-migration-heartbeat-probe.js +1 -0
- package/scripts/workspace-selection-probe.js +1 -0
- package/scripts/write-path-language-probe.js +1 -0
- package/scripts/write-primitive-language-probe.js +1 -0
package/scripts/temp-cleanup.js
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
// fails after 0-1 ms on Windows. So the wait is explicit and bounded, on the codes Node documents
|
|
7
7
|
// for maxRetries. rm options pass through unchanged; callers keep their own path-safety checks.
|
|
8
8
|
const fs = require('fs');
|
|
9
|
+
const os = require('os');
|
|
10
|
+
const path = require('path');
|
|
9
11
|
|
|
10
12
|
const RETRY_CODES = new Set(['EBUSY', 'EMFILE', 'ENFILE', 'ENOTEMPTY', 'EPERM']);
|
|
11
13
|
|
|
@@ -20,4 +22,183 @@ function removeTree(target, rmOptions = {}, { timeoutMs = 5000, intervalMs = 100
|
|
|
20
22
|
}
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
// T-0357: removing a folder a test made, moved here from T-0354's arena cleanup (memory-migration-test-support.js,
|
|
26
|
+
// three review rounds) so every probe uses the same checks. ownTree() records the folder right after it is made.
|
|
27
|
+
// removeOwnedTree() removes it only while it is still that folder (same file identity, not a link): a test that
|
|
28
|
+
// renamed it away and put a link in its place would otherwise have the walk run inside the link's target. Links
|
|
29
|
+
// inside are removed first, as links, so the removal never walks into a link's target, wherever that points, and
|
|
30
|
+
// each folder must still resolve inside the tree just before it is listed and before a link in it is removed.
|
|
31
|
+
// A process that kept swapping folders while this runs could still race these checks.
|
|
32
|
+
function ownTree(dir) {
|
|
33
|
+
const st = fs.lstatSync(dir, { bigint: true });
|
|
34
|
+
return { dir, dev: st.dev, ino: st.ino, real: fs.realpathSync.native(dir) };
|
|
35
|
+
}
|
|
36
|
+
function removeOwnedTree(owned, { code = 'E_TEMP_REPLACED', timeoutMs = 5000 } = {}) {
|
|
37
|
+
const replaced = () => Object.assign(new Error('the folder was replaced'), { code });
|
|
38
|
+
const st = fs.lstatSync(owned.dir, { bigint: true });
|
|
39
|
+
if (st.isSymbolicLink() || !st.isDirectory() || st.dev !== owned.dev || st.ino !== owned.ino) throw replaced();
|
|
40
|
+
const resolvesInside = dir => {
|
|
41
|
+
const relative = path.relative(owned.real, fs.realpathSync.native(dir));
|
|
42
|
+
return !(relative === '..' || relative.startsWith('..' + path.sep) || path.isAbsolute(relative));
|
|
43
|
+
};
|
|
44
|
+
const removeLinks = dir => {
|
|
45
|
+
if (!resolvesInside(dir)) throw replaced();
|
|
46
|
+
for (const name of fs.readdirSync(dir)) {
|
|
47
|
+
const file = path.join(dir, name), entry = fs.lstatSync(file);
|
|
48
|
+
if (entry.isSymbolicLink()) {
|
|
49
|
+
if (!resolvesInside(dir)) throw replaced();
|
|
50
|
+
try { fs.unlinkSync(file); } catch { fs.rmdirSync(file); }
|
|
51
|
+
} else if (entry.isDirectory()) removeLinks(file);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
removeLinks(owned.dir);
|
|
55
|
+
removeTree(owned.dir, { recursive: true, force: true }, { timeoutMs });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// T-0357: probes and e2e cases made temp folders and many never removed them (8,434 leerness-* folders were in this
|
|
59
|
+
// machine's TEMP on 2026-10-14). The work is split: the test process records the folders it makes, and the runner
|
|
60
|
+
// that started it removes them once it has seen the process end with exit status 0 (scripts/ci-shard.js runNpm).
|
|
61
|
+
// 1.36.302 and 1.36.303 decided inside the test process at exit; in eight review rounds a later piece of JavaScript
|
|
62
|
+
// (another exit listener, a microtask, an exception handler, an interrupted process.exit()) kept changing the verdict
|
|
63
|
+
// after the decision. The exit status the runner reads cannot change any more.
|
|
64
|
+
// trackTemp(module), the first statement of every script that names mkdtemp, records only when the environment carries
|
|
65
|
+
// LEERNESS_TEMP_RECORD (an absolute directory the runner made for this run); without it nothing is wrapped and the
|
|
66
|
+
// script behaves as before. It wraps fs.mkdtempSync (the asynchronous forms are not recorded; see below) and, when a
|
|
67
|
+
// call returns a folder, appends one line to its own file in that directory at once. It removes nothing and installs no exit,
|
|
68
|
+
// emit or exception hook. Processes the test starts that inherit the variable record into the same directory, so
|
|
69
|
+
// their folders go too once the test passed. Call it before the probe requires anything that captures these
|
|
70
|
+
// functions (lib/runtime-writes.js binds fs.mkdtempSync when it loads).
|
|
71
|
+
// What is recorded (from the 1.36.303 review rounds): only a call whose prefix is an absolute path without '.' or '..'
|
|
72
|
+
// segments (a relative prefix names a folder only through the working directory as the file system sees it when the
|
|
73
|
+
// folder is made, and '..' after a link is resolved physically); a Buffer prefix or result only if it is UTF-8 that
|
|
74
|
+
// decodes and encodes back to the same bytes; a result only if it is the prefix followed by the six characters
|
|
75
|
+
// mkdtemp adds (another encoding returns the path encoded); a folder only if it is strictly below the temp directory
|
|
76
|
+
// of the moment of the call.
|
|
77
|
+
// A script loaded with --require into another process (lock-probe.js into the CLI, a probe that preloads itself) must
|
|
78
|
+
// not change what that process does. So trackTemp(module) runs only for code the main script loaded: the caller or
|
|
79
|
+
// a module up its chain is the main module (Node gives it the id '.'). A preload, loaded before the main script, and
|
|
80
|
+
// anything it loads, through require() at any depth or through createRequire(), never reach it (1.36.302 review
|
|
81
|
+
// round 2: the earlier check looked for the preload's parent instead, and createRequire() gives a parent outside that
|
|
82
|
+
// chain). The id is read from the module, not from this file's require.main, which stays undefined when this file
|
|
83
|
+
// was itself preloaded (round 3). Called without a module it does nothing (1.36.304 review round 1: the check was
|
|
84
|
+
// skipped then, so a preload that called trackTemp() recorded). It never runs in a worker thread.
|
|
85
|
+
const RECORD_ENV = 'LEERNESS_TEMP_RECORD';
|
|
86
|
+
let tracker = null;
|
|
87
|
+
const INACTIVE = Object.freeze({ active: false, pending: () => 0 });
|
|
88
|
+
function loadedFromMain(caller) {
|
|
89
|
+
const seen = new Set();
|
|
90
|
+
for (let m = caller; m && !seen.has(m); m = m.parent) { seen.add(m); if (m.id === '.') return true; }
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
// real is root or below it.
|
|
94
|
+
function within(root, real) {
|
|
95
|
+
const relative = path.relative(root, real);
|
|
96
|
+
return !(relative === '..' || relative.startsWith('..' + path.sep) || path.isAbsolute(relative));
|
|
97
|
+
}
|
|
98
|
+
const strictlyWithin = (root, real) => real !== root && within(root, real);
|
|
99
|
+
// A path value as text, or null: a Buffer only if it survives decoding (1.36.303 review round 4: a lossy decoding named
|
|
100
|
+
// another folder), a file: URL through fileURLToPath.
|
|
101
|
+
function pathText(value) {
|
|
102
|
+
if (typeof value === 'string') return value;
|
|
103
|
+
if (Buffer.isBuffer(value)) { const s = value.toString('utf8'); return Buffer.from(s, 'utf8').equals(value) ? s : null; }
|
|
104
|
+
if (value instanceof URL) return require('url').fileURLToPath(value);
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
function trackTemp(caller) {
|
|
108
|
+
if (!loadedFromMain(caller)) return INACTIVE;
|
|
109
|
+
if (!require('worker_threads').isMainThread) return INACTIVE;
|
|
110
|
+
const recordDir = process.env[RECORD_ENV];
|
|
111
|
+
if (!recordDir || !path.isAbsolute(recordDir)) return INACTIVE;
|
|
112
|
+
if (tracker) return tracker;
|
|
113
|
+
const file = path.join(recordDir, `${process.pid}-${require('crypto').randomBytes(4).toString('hex')}.jsonl`);
|
|
114
|
+
// The record is written and the folder read with the fs functions of this moment: lib/runtime-writes.js intercepts
|
|
115
|
+
// fs writes when it loads, and fs.appendFileSync goes through the current fs.openSync, so the memory recovery
|
|
116
|
+
// bundles it makes while writes are latched went unrecorded (found by this version's first full run). Tests that
|
|
117
|
+
// replace fs functions later do not stop or change a record either.
|
|
118
|
+
const { openSync, writeSync, closeSync, lstatSync, readdirSync } = fs;
|
|
119
|
+
const realpathNative = fs.realpathSync.native;
|
|
120
|
+
let count = 0;
|
|
121
|
+
const callContext = prefix => {
|
|
122
|
+
try {
|
|
123
|
+
const p = pathText(prefix);
|
|
124
|
+
if (p === null || !path.isAbsolute(p) || p.split(/[\\/]/).some(s => s === '.' || s === '..')) return null;
|
|
125
|
+
return { prefix: p, temp: realpathNative(os.tmpdir()) };
|
|
126
|
+
} catch { return null; }
|
|
127
|
+
};
|
|
128
|
+
const record = (dir, at) => {
|
|
129
|
+
try {
|
|
130
|
+
const d = pathText(dir);
|
|
131
|
+
if (d === null || !at || d.length !== at.prefix.length + 6 || !d.startsWith(at.prefix)) return;
|
|
132
|
+
const st = lstatSync(d, { bigint: true }), real = realpathNative(d);
|
|
133
|
+
if (st.isSymbolicLink() || !st.isDirectory() || !strictlyWithin(at.temp, real)) return;
|
|
134
|
+
// A folder mkdtempSync just made is empty. A wrapper installed before the tracker (a preload) can call the original
|
|
135
|
+
// and put a folder that already existed in its place (1.36.304 review round 2); one with anything in it is not
|
|
136
|
+
// recorded, so it is never removed.
|
|
137
|
+
if (readdirSync(d).length !== 0) return;
|
|
138
|
+
const fd = openSync(file, 'a');
|
|
139
|
+
try { writeSync(fd, JSON.stringify({ path: d, dev: String(st.dev), ino: String(st.ino), real, temp: at.temp }) + '\n'); }
|
|
140
|
+
finally { closeSync(fd); }
|
|
141
|
+
count++;
|
|
142
|
+
} catch { /* not recorded: the folder is only left behind */ }
|
|
143
|
+
};
|
|
144
|
+
// Only the synchronous form is recorded, in the same synchronous step that made the folder, so no code of the test
|
|
145
|
+
// runs between the creation and the record. The callback and promise forms complete later, and another folder put
|
|
146
|
+
// in place before then was recorded instead (1.36.304 review round 1); they are not wrapped, and their folders are
|
|
147
|
+
// left, like those of a process that does not inherit the variable. No script in scripts/ uses them.
|
|
148
|
+
const originalSync = fs.mkdtempSync;
|
|
149
|
+
fs.mkdtempSync = function mkdtempSync(...args) {
|
|
150
|
+
const at = callContext(args[0]);
|
|
151
|
+
const dir = originalSync.apply(this, args);
|
|
152
|
+
record(dir, at);
|
|
153
|
+
return dir;
|
|
154
|
+
};
|
|
155
|
+
tracker = { active: true, pending: () => count };
|
|
156
|
+
return tracker;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// The runner's half: remove what the processes of one passed run recorded in recordDir, newest first. Each folder
|
|
160
|
+
// must still be the one recorded (same file identity, not a link: removeOwnedTree), and its real path must be strictly
|
|
161
|
+
// below both the temp directory recorded with it and the runner's own temp directory (tempRoot). A line that does not
|
|
162
|
+
// parse or lacks a field is skipped; a folder already gone is counted as gone; one that is replaced, outside, or still
|
|
163
|
+
// held after the budget is left. A folder still held by a process that outlived the run waits at most 2 s, and the
|
|
164
|
+
// whole removal at most budgetMs.
|
|
165
|
+
function readRecordLines(recordDir) {
|
|
166
|
+
let names;
|
|
167
|
+
try { names = fs.readdirSync(recordDir).filter(n => n.endsWith('.jsonl')).sort(); } catch { return []; }
|
|
168
|
+
const lines = [];
|
|
169
|
+
for (const name of names) {
|
|
170
|
+
let text;
|
|
171
|
+
try { text = fs.readFileSync(path.join(recordDir, name), 'utf8'); } catch { continue; }
|
|
172
|
+
for (const line of text.split('\n')) if (line.trim()) lines.push(line);
|
|
173
|
+
}
|
|
174
|
+
return lines;
|
|
175
|
+
}
|
|
176
|
+
function removeRecorded(recordDir, { tempRoot = os.tmpdir(), budgetMs = 60000 } = {}) {
|
|
177
|
+
const result = { removed: 0, gone: 0, left: 0, skipped: 0 };
|
|
178
|
+
const deadline = Date.now() + budgetMs;
|
|
179
|
+
let root;
|
|
180
|
+
try { root = fs.realpathSync.native(tempRoot); } catch { root = null; }
|
|
181
|
+
const records = [];
|
|
182
|
+
for (const line of readRecordLines(recordDir)) {
|
|
183
|
+
let x;
|
|
184
|
+
try { x = JSON.parse(line); } catch { result.skipped++; continue; }
|
|
185
|
+
if (!x || typeof x !== 'object' || ['path', 'dev', 'ino', 'real', 'temp'].some(k => typeof x[k] !== 'string' || !x[k])) { result.skipped++; continue; }
|
|
186
|
+
records.push(x);
|
|
187
|
+
}
|
|
188
|
+
for (const x of records.reverse()) {
|
|
189
|
+
if (!root || !path.isAbsolute(x.path) || !strictlyWithin(x.temp, x.real) || !strictlyWithin(root, x.real)) { result.left++; continue; }
|
|
190
|
+
try {
|
|
191
|
+
const st = fs.lstatSync(x.path, { bigint: true });
|
|
192
|
+
if (st.isSymbolicLink() || !st.isDirectory() || String(st.dev) !== x.dev || String(st.ino) !== x.ino) { result.left++; continue; }
|
|
193
|
+
if (fs.realpathSync.native(x.path) !== x.real) { result.left++; continue; }
|
|
194
|
+
removeOwnedTree({ dir: x.path, dev: st.dev, ino: st.ino, real: x.real }, { timeoutMs: Math.max(0, Math.min(2000, deadline - Date.now())) });
|
|
195
|
+
result.removed++;
|
|
196
|
+
} catch (error) {
|
|
197
|
+
if (error && error.code === 'ENOENT') result.gone++;
|
|
198
|
+
else result.left++;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
module.exports = { removeTree, RETRY_CODES, ownTree, removeOwnedTree, trackTemp, removeRecorded, RECORD_ENV };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
require('./temp-cleanup').trackTemp(module); // T-0357: records this run's temp folders; the runner that started it removes them after a clean exit
|
|
2
3
|
// T-0324 (follow-up of T-0321): titles and targets reach leerness intact through MCP and after `--`.
|
|
3
4
|
// The MCP title and target tools put the text before their flags without "--", so the child CLI read a title
|
|
4
5
|
// that begins with "-" as an option and dropped it (a markdown bullet as a task title answered empty_title).
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
require('./temp-cleanup').trackTemp(module); // T-0357: records this run's temp folders; the runner that started it removes them after a clean exit
|
|
2
3
|
// T-0336: errors on the shared progress-tracker write path follow the project language. The row-loss guard in
|
|
3
4
|
// writeProgressRows (E_PROGRESS_ROW_LOSS) printed Korean in English projects through the commands that rewrite tracker
|
|
4
5
|
// rows (task fix-evidence --set, task add, task update, task sync and others); lib/managed-text.js errors
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
require('./temp-cleanup').trackTemp(module); // T-0357: records this run's temp folders; the runner that started it removes them after a clean exit
|
|
2
3
|
|
|
3
4
|
const assert = require('node:assert/strict');
|
|
4
5
|
const { scanUiBoundaryBrowser: scan, UiBoundaryBrowserError, INPUT_SCHEMA, OUTPUT_SCHEMA,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
require('./temp-cleanup').trackTemp(module); // T-0357: records this run's temp folders; the runner that started it removes them after a clean exit
|
|
2
3
|
|
|
3
4
|
// T-0309: the UI copy boundary reaches the UI-building agent as an on-demand skill.
|
|
4
5
|
const assert = require('assert');
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
require('./temp-cleanup').trackTemp(module); // T-0357: records this run's temp folders; the runner that started it removes them after a clean exit
|
|
2
3
|
const assert = require('node:assert/strict');
|
|
3
4
|
const fs = require('node:fs');
|
|
4
5
|
const os = require('node:os');
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
|
+
require('./temp-cleanup').trackTemp(module); // T-0357: records this run's temp folders; the runner that started it removes them after a clean exit
|
|
3
4
|
|
|
4
5
|
// T-0143: verify-code must execute its own fixed Python/Go/Rust runners under
|
|
5
6
|
// fresh basic permissions, and a failed run must not become green gate evidence.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
|
+
require('./temp-cleanup').trackTemp(module); // T-0357: records this run's temp folders; the runner that started it removes them after a clean exit
|
|
3
4
|
|
|
4
5
|
// A live legacy migration must own its project lock before migration revalidation.
|
|
5
6
|
// Otherwise a peer can populate `.leerness/` after validation and
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
require('./temp-cleanup').trackTemp(module); // T-0357: records this run's temp folders; the runner that started it removes them after a clean exit
|
|
2
3
|
// T-0348: the workspace migration lock wait counts time without progress, not time in all. The migrating process
|
|
3
4
|
// refreshes the lock file's modification time while it works, and a waiting command keeps waiting while that time
|
|
4
5
|
// moves; a lock that does not move still fails after LEERNESS_WORKSPACE_MIGRATION_LOCK_WAIT_MS. Each case uses a
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
|
+
require('./temp-cleanup').trackTemp(module); // T-0357: records this run's temp folders; the runner that started it removes them after a clean exit
|
|
3
4
|
|
|
4
5
|
// Snapshot selection must preserve the resolver's decisions and diagnostics
|
|
5
6
|
// while adding no filesystem calls, writes, or ambient environment dependency.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
require('./temp-cleanup').trackTemp(module); // T-0357: records this run's temp folders; the runner that started it removes them after a clean exit
|
|
2
3
|
// T-0337: the remaining fixed-language errors on the shared write path follow the project language. lib/memory-input.js
|
|
3
4
|
// and lib/memory-output.js gave every project an English reason with Korean advice; lib/memory-input-bytes.js,
|
|
4
5
|
// lib/memory-publication-read.js, the session handoff update (lib/context-current.js) and two state-lock errors were
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
|
+
require('./temp-cleanup').trackTemp(module); // T-0357: records this run's temp folders; the runner that started it removes them after a clean exit
|
|
2
3
|
// T-0338: the write primitives' fixed-language texts follow the project language. In lib/io.js the dry-run guard,
|
|
3
4
|
// the compare-and-set refusal (E_CONCURRENT_MODIFICATION) with its recovery backup and recovery artifact suffixes, the
|
|
4
5
|
// link and file type refusals, the two Windows replacement failures and the damaged-JSON notice were Korean in every
|