leerness 1.36.303 → 1.36.305
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 +34 -0
- package/CONTRIBUTING.md +2 -0
- package/README.md +4 -4
- package/bin/leerness.js +45 -19
- package/lib/claims-baseline.js +2 -1
- package/lib/io.js +6 -5
- package/lib/machine-cache.js +2 -1
- package/lib/memory-output.js +2 -1
- package/lib/migrate.js +2 -1
- package/lib/preview-serve.js +3 -2
- package/lib/runtime-writes.js +7 -1
- package/lib/safe-remove.js +132 -0
- package/lib/test-node-runner.js +2 -1
- package/lib/workspace-dir.js +3 -2
- package/package.json +2 -2
- 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 +99 -0
- package/scripts/ci-shard.js +35 -3
- 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/safe-remove-probe.js +573 -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 +437 -1
- package/scripts/temp-cleanup.js +186 -2
- 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 +9 -4
- 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/lib/workspace-dir.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
// migrated. Keeping the policy in this domain module prevents another
|
|
5
5
|
// read-one-directory/write-another split brain.
|
|
6
6
|
const fs = require('fs');
|
|
7
|
+
const { removeSync } = require('./safe-remove');
|
|
7
8
|
const path = require('path');
|
|
8
9
|
const crypto = require('crypto');
|
|
9
10
|
|
|
@@ -290,7 +291,7 @@ function _safeRemoveCanonicalDir(root, target) {
|
|
|
290
291
|
if (resolvedTarget !== allowed || path.dirname(resolvedTarget) !== resolvedRoot || resolvedRoot === path.parse(resolvedRoot).root) {
|
|
291
292
|
throw new WorkspaceDirectoryError('E_WORKSPACE_DIR_UNSAFE_REMOVE', `unsafe canonical rollback target: ${resolvedTarget}`);
|
|
292
293
|
}
|
|
293
|
-
|
|
294
|
+
removeSync(resolvedTarget, { recursive: true, force: true });
|
|
294
295
|
}
|
|
295
296
|
|
|
296
297
|
function _rewriteLegacyReference(file) {
|
|
@@ -915,7 +916,7 @@ function _migrateLegacyWorkspace(root, opts = {}) {
|
|
|
915
916
|
legacyRenamed = false;
|
|
916
917
|
}
|
|
917
918
|
for (const item of overwritten.reverse()) { _beat(); _copyFile(item.backup, item.dst); }
|
|
918
|
-
for (const file of created.reverse()) { _beat(); if (fs.existsSync(file))
|
|
919
|
+
for (const file of created.reverse()) { _beat(); if (fs.existsSync(file)) removeSync(file, { force: true }); }
|
|
919
920
|
_beat();
|
|
920
921
|
if (!canonicalExisted && fs.existsSync(state.canonical.abs)) _safeRemoveCanonicalDir(state.root, state.canonical.abs);
|
|
921
922
|
} catch (rollbackError) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leerness",
|
|
3
|
-
"version": "1.36.
|
|
3
|
+
"version": "1.36.305",
|
|
4
4
|
"description": "The AI-coding operations layer that makes \"done\" require evidence — persistent memory, evidence-gated completion checks, and clean handoffs for any AI agent (Claude Code, Codex, Cursor). State lives as plain files in your repo. CLI + MCP, 0 runtime dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"leerness",
|
|
@@ -143,7 +143,7 @@
|
|
|
143
143
|
"test:ledger-sync": "node ./scripts/execution-ledger-sync-probe.js",
|
|
144
144
|
"test:state-lock": "node ./scripts/shared-state-lock-probe.js",
|
|
145
145
|
"test:lock-heartbeat": "node ./scripts/lock-heartbeat-probe.js",
|
|
146
|
-
"test:temp-cleanup": "node ./scripts/temp-cleanup-probe.js && node ./scripts/copy-tree-probe.js",
|
|
146
|
+
"test:temp-cleanup": "node ./scripts/temp-cleanup-probe.js && node ./scripts/copy-tree-probe.js && node ./scripts/safe-remove-probe.js",
|
|
147
147
|
"test:path-setup": "node ./scripts/path-setup-powershell-probe.js",
|
|
148
148
|
"test:skill-archive": "node ./scripts/skill-archive-probe.js",
|
|
149
149
|
"test:memory-arena-cleanup": "node ./scripts/memory-arena-cleanup-probe.js",
|
|
@@ -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-0319: saved API skills (.leerness/api-skills/*.md) are matched against the in-progress task by handoff,
|
|
3
4
|
// handoff --json, health --json and session close --json. All four read row.title and row.notes, which progress
|
|
4
5
|
// rows do not have, so nothing ever matched. They now share one task-text helper (request and next action), 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
|
const assert = require('assert'), fs = require('fs'), path = require('path'), os = require('os'), cp = require('child_process');
|
|
3
4
|
const { createHash } = require('crypto');
|
|
4
5
|
const { removeTree } = require('./temp-cleanup');
|
|
@@ -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('assert'), fs = require('fs'), path = require('path'), os = require('os'), cp = require('child_process');
|
|
3
4
|
const { createHash } = require('crypto');
|
|
4
5
|
const { removeTree } = require('./temp-cleanup');
|
|
@@ -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('assert'), fs = require('fs'), path = require('path'), os = require('os'), cp = require('child_process');
|
|
3
4
|
const { createHash } = require('crypto');
|
|
4
5
|
const { removeTree } = require('./temp-cleanup');
|
|
@@ -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('assert'), fs = require('fs'), path = require('path'), os = require('os'), cp = require('child_process');
|
|
3
4
|
const { createHash } = require('crypto');
|
|
4
5
|
const { removeTree } = require('./temp-cleanup');
|
|
@@ -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
|
// Real CLI regressions for the configuration consumed by Codex/Claude hooks.
|
|
5
6
|
const fs = require('fs'), os = require('os'), path = require('path'), cp = require('child_process');
|
|
@@ -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('assert'), fs = require('fs'), path = require('path'), os = require('os'), cp = require('child_process');
|
|
3
4
|
const { createHash } = require('crypto');
|
|
4
5
|
const { removeTree } = require('./temp-cleanup');
|
|
@@ -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-0330: past fixes at completion. `bugfix receipt --areas` declares the files or folders a fix is about;
|
|
3
4
|
// verify-claim then lists the bugfix receipts whose declared areas hold a file the task's evidence names: finished
|
|
4
5
|
// ones (their task is done, also in retained history) as past fixes with the root cause and the probe to re-run,
|
|
@@ -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
|
// T-0359: CI runs e2e.js cases and npm-script leaves in parallel shards (scripts/ci-shard.js). A shard that drops a
|
|
4
5
|
// unit fails nothing — the unit silently stops running — so this probe checks the parts that decide what runs:
|
|
5
6
|
// the assignment is a deterministic partition, every leaf of the real sharded scripts parses and lands in exactly
|
|
@@ -151,6 +152,104 @@ try {
|
|
|
151
152
|
assert.strictEqual(env.LEERNESS_CI_SHARD_TIMES, times, 'the caller\'s environment object was changed');
|
|
152
153
|
});
|
|
153
154
|
|
|
155
|
+
check('runNpm removes the temp folders a passing leaf and its tracked child recorded, and keeps a failing or killed leaf\'s (T-0357)', () => {
|
|
156
|
+
// The leaf only records (scripts/temp-cleanup.js trackTemp); the runner, which sees the exit status, removes.
|
|
157
|
+
const dir = path.join(arena, 'temp-record');
|
|
158
|
+
const leafTemp = path.join(dir, 'temp');
|
|
159
|
+
fs.mkdirSync(leafTemp, { recursive: true });
|
|
160
|
+
const TC = JSON.stringify(path.join(__dirname, 'temp-cleanup.js'));
|
|
161
|
+
const make = (name, end) => fs.writeFileSync(path.join(dir, `${name}.js`), [
|
|
162
|
+
`require(${TC}).trackTemp(module);`,
|
|
163
|
+
"const fs = require('fs'), os = require('os'), path = require('path'), cp = require('child_process');",
|
|
164
|
+
`const d = fs.mkdtempSync(path.join(os.tmpdir(), 'leerness-leaf-${name}-'));`,
|
|
165
|
+
`const c = cp.spawnSync(process.execPath, [${JSON.stringify(path.join(dir, 'child.js'))}], { encoding: 'utf8' }).stdout.trim();`,
|
|
166
|
+
`fs.writeFileSync(${JSON.stringify(path.join(dir, `${name}.out`))}, JSON.stringify({ d, c, rec: process.env.LEERNESS_TEMP_RECORD || null }));`,
|
|
167
|
+
end, ''].join('\n'));
|
|
168
|
+
fs.writeFileSync(path.join(dir, 'child.js'), [`require(${TC}).trackTemp(module);`,
|
|
169
|
+
"const fs = require('fs'), os = require('os'), path = require('path');",
|
|
170
|
+
"process.stdout.write(fs.mkdtempSync(path.join(os.tmpdir(), 'leerness-leaf-child-')));", ''].join('\n'));
|
|
171
|
+
make('pass', 'process.exitCode = 0;');
|
|
172
|
+
make('fail', 'process.exitCode = 1;');
|
|
173
|
+
make('killed', "process.kill(process.pid, 'SIGKILL');");
|
|
174
|
+
const recordRoots = () => fs.readdirSync(os.tmpdir()).filter(n => n.startsWith('leerness-temp-record-')).sort();
|
|
175
|
+
const rootsBefore = recordRoots();
|
|
176
|
+
const lines = [];
|
|
177
|
+
const env = { ...process.env, GITHUB_ACTIONS: '', TEMP: leafTemp, TMP: leafTemp, TMPDIR: leafTemp, LEERNESS_TEMP_RECORD: path.join(dir, 'outer-record') };
|
|
178
|
+
const r = cs.runNpm('suite', { index: 1, count: 1 }, { root: dir, scripts: { suite: 'node ./pass.js && node ./fail.js && node ./killed.js' }, weights: { e2e: {}, npm: {} }, stdio: 'ignore', env, log: l => lines.push(l) });
|
|
179
|
+
assert.deepStrictEqual(r.failed, ['node ./fail.js', 'node ./killed.js']);
|
|
180
|
+
const res = n => JSON.parse(fs.readFileSync(path.join(dir, `${n}.out`), 'utf8'));
|
|
181
|
+
const pass = res('pass'), fail = res('fail');
|
|
182
|
+
assert.ok(pass.d && pass.c && fail.d && fail.c, JSON.stringify({ pass, fail }));
|
|
183
|
+
assert.strictEqual(fs.existsSync(pass.d), false, 'the passing leaf\'s folder was kept');
|
|
184
|
+
assert.strictEqual(fs.existsSync(pass.c), false, 'the passing leaf\'s tracked child\'s folder was kept');
|
|
185
|
+
assert.strictEqual(fs.existsSync(fail.d), true, 'the failing leaf\'s folder was removed');
|
|
186
|
+
assert.strictEqual(fs.existsSync(fail.c), true, 'the failing leaf\'s child\'s folder was removed');
|
|
187
|
+
const killedMade = fs.readdirSync(leafTemp).filter(n => n.startsWith('leerness-leaf-killed-'));
|
|
188
|
+
assert.strictEqual(killedMade.length, 1, 'the killed leaf\'s folder was removed');
|
|
189
|
+
assert.ok(pass.rec && fail.rec && pass.rec !== fail.rec && pass.rec !== env.LEERNESS_TEMP_RECORD, 'each leaf gets its own record directory from the runner');
|
|
190
|
+
assert.strictEqual(fs.existsSync(pass.rec) || fs.existsSync(fail.rec), false, 'a record directory was left');
|
|
191
|
+
assert.deepStrictEqual(recordRoots(), rootsBefore, 'the runner left its record root');
|
|
192
|
+
assert.ok(lines.some(l => /^ci-shard: temp folders: 2 removed after passing leaves/.test(l)), lines.join('\n'));
|
|
193
|
+
assert.strictEqual(env.LEERNESS_TEMP_RECORD, path.join(dir, 'outer-record'), 'the caller\'s environment object was changed');
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// 1.36.304 review round 3: the record root was removed recursively without checking that it was still the folder the
|
|
197
|
+
// runner made. A wrapper of fs.mkdtempSync (or fs.mkdirSync, for a leaf's directory) installed before the runner
|
|
198
|
+
// can put an existing folder there; the runner now checks each directory right after making it (its own identity,
|
|
199
|
+
// empty), records nothing into one that fails, removes only the leaf directories it checked, and the root only when
|
|
200
|
+
// it is empty.
|
|
201
|
+
check('runNpm removes no folder that a wrapper swapped in for its record root or a leaf\'s record directory (T-0357)', () => {
|
|
202
|
+
const dir = path.join(arena, 'temp-record-swap');
|
|
203
|
+
const leafTemp = path.join(dir, 'temp');
|
|
204
|
+
fs.mkdirSync(leafTemp, { recursive: true });
|
|
205
|
+
fs.writeFileSync(path.join(dir, 'pass.js'), [`require(${JSON.stringify(path.join(__dirname, 'temp-cleanup.js'))}).trackTemp(module);`,
|
|
206
|
+
"const fs = require('fs'), os = require('os'), path = require('path');",
|
|
207
|
+
"fs.mkdtempSync(path.join(os.tmpdir(), 'leerness-leaf-swap-'));", ''].join('\n'));
|
|
208
|
+
for (const target of ['root', 'leaf']) {
|
|
209
|
+
const unrelated = path.join(dir, `unrelated-${target}`);
|
|
210
|
+
fs.mkdirSync(unrelated); fs.writeFileSync(path.join(unrelated, 'keep.txt'), 'keep');
|
|
211
|
+
const saved = { mkdtempSync: fs.mkdtempSync, mkdirSync: fs.mkdirSync };
|
|
212
|
+
let swappedAt = null;
|
|
213
|
+
const swapIn = made => { fs.renameSync(made, made + '-aside'); fs.renameSync(unrelated, made); swappedAt = made; };
|
|
214
|
+
if (target === 'root') fs.mkdtempSync = function (prefix, ...rest) { const d = saved.mkdtempSync.call(fs, prefix, ...rest); if (String(prefix).includes('leerness-temp-record-')) swapIn(d); return d; };
|
|
215
|
+
else fs.mkdirSync = function (p, ...rest) { const r = saved.mkdirSync.call(fs, p, ...rest); if (!swappedAt && /leerness-temp-record-/.test(path.dirname(String(p)))) swapIn(String(p)); return r; };
|
|
216
|
+
let r;
|
|
217
|
+
const lines = [];
|
|
218
|
+
try {
|
|
219
|
+
r = cs.runNpm('suite', { index: 1, count: 1 }, { root: dir, scripts: { suite: 'node ./pass.js' }, weights: { e2e: {}, npm: {} }, stdio: 'ignore',
|
|
220
|
+
env: { ...process.env, GITHUB_ACTIONS: '', TEMP: leafTemp, TMP: leafTemp, TMPDIR: leafTemp }, log: l => lines.push(l) });
|
|
221
|
+
} finally { fs.mkdtempSync = saved.mkdtempSync; fs.mkdirSync = saved.mkdirSync; }
|
|
222
|
+
assert.deepStrictEqual(r.failed, [], target);
|
|
223
|
+
assert.ok(swappedAt, `${target}: the wrapper did not run`);
|
|
224
|
+
assert.strictEqual(fs.readFileSync(path.join(swappedAt, 'keep.txt'), 'utf8'), 'keep', `${target}: the folder swapped in was removed`);
|
|
225
|
+
assert.ok(lines.some(l => /^ci-shard: temp folders: .*1 leaves not recorded/.test(l)), `${target}: the leaf was given a directory that failed the check\n${lines.join('\n')}`);
|
|
226
|
+
// What the runner rightly leaves is this test's own, in the temp directory: for the root, the folder swapped in and
|
|
227
|
+
// the root moved aside; for a leaf's directory, the root that holds them (1.36.304 full run: they were left).
|
|
228
|
+
const own = target === 'root' ? [swappedAt, swappedAt + '-aside'] : [path.dirname(swappedAt)];
|
|
229
|
+
for (const p of own) {
|
|
230
|
+
assert.ok(path.resolve(path.dirname(p)) === path.resolve(os.tmpdir()) && path.basename(p).startsWith('leerness-temp-record-'), `${target}: not the runner's folder: ${p}`);
|
|
231
|
+
fs.rmSync(p, { recursive: true, force: true });
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
check('runNpm removes its record root only when it is empty: a folder a leaf moved into it is left (T-0357)', () => {
|
|
237
|
+
const dir = path.join(arena, 'temp-record-into-root');
|
|
238
|
+
const leafTemp = path.join(dir, 'temp');
|
|
239
|
+
fs.mkdirSync(leafTemp, { recursive: true });
|
|
240
|
+
const moved = path.join(dir, 'moved');
|
|
241
|
+
fs.mkdirSync(moved); fs.writeFileSync(path.join(moved, 'keep.txt'), 'keep');
|
|
242
|
+
fs.writeFileSync(path.join(dir, 'mover.js'), ["const fs = require('fs'), path = require('path');",
|
|
243
|
+
`const into = path.join(path.dirname(process.env.LEERNESS_TEMP_RECORD), 'moved'); fs.renameSync(${JSON.stringify(moved)}, into);`,
|
|
244
|
+
`fs.writeFileSync(${JSON.stringify(path.join(dir, 'into.txt'))}, into);`, ''].join('\n'));
|
|
245
|
+
const r = cs.runNpm('suite', { index: 1, count: 1 }, { root: dir, scripts: { suite: 'node ./mover.js' }, weights: { e2e: {}, npm: {} }, stdio: 'ignore',
|
|
246
|
+
env: { ...process.env, GITHUB_ACTIONS: '', TEMP: leafTemp, TMP: leafTemp, TMPDIR: leafTemp }, log: () => {} });
|
|
247
|
+
assert.deepStrictEqual(r.failed, []);
|
|
248
|
+
const into = fs.readFileSync(path.join(dir, 'into.txt'), 'utf8');
|
|
249
|
+
assert.strictEqual(fs.readFileSync(path.join(into, 'keep.txt'), 'utf8'), 'keep', 'the folder moved into the record root was removed with it');
|
|
250
|
+
fs.rmSync(path.dirname(into), { recursive: true, force: true });
|
|
251
|
+
});
|
|
252
|
+
|
|
154
253
|
const CREATE = names => `const e2eShard = require('./ci-shard').e2eShard(__filename, [${names.map(n => `'${n}'`).join(', ')}]);`;
|
|
155
254
|
const START = '// e2e-shard: cases start here';
|
|
156
255
|
|
package/scripts/ci-shard.js
CHANGED
|
@@ -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
|
// T-0359: split CI work across parallel jobs. Until 1.36.300 each Windows gate job ran e2e.js (167-226 min) and the
|
|
4
5
|
// command-surface leaves (43-52 min) one after the other, and the Windows fast job ran its leaves for 79 min, so a
|
|
5
6
|
// release waited about five hours for CI (run 38193803239). A shard runs part of that work. Shards 1..k of one job
|
|
@@ -17,11 +18,17 @@
|
|
|
17
18
|
// guessed: running it differently from npm would test something else. Leaves run with node directly, in the
|
|
18
19
|
// package root, in their order in the script. A shard runs all of its leaves and fails if any failed, so one CI
|
|
19
20
|
// run reports every failing leaf of the shard (a plain `&&` chain stops at the first).
|
|
21
|
+
// T-0357: each leaf records the temp folders it makes (scripts/temp-cleanup.js trackTemp, into a directory this runner
|
|
22
|
+
// gives it through LEERNESS_TEMP_RECORD), and the runner removes them after the leaf ended with status 0, no signal
|
|
23
|
+
// and no spawn error: the verdict it uses for pass/fail, read from the exit status, which no code in the leaf can
|
|
24
|
+
// change afterwards. A failed leaf's folders are kept for inspection.
|
|
20
25
|
// e2e.js uses e2eShard() below: each top-level case is `if (e2eShard.take('<key>')) {`, and finish() checks that the
|
|
21
26
|
// file has no unguarded top-level block and that every guard was reached exactly once.
|
|
22
27
|
const fs = require('fs');
|
|
28
|
+
const os = require('os');
|
|
23
29
|
const path = require('path');
|
|
24
30
|
const cp = require('child_process');
|
|
31
|
+
const temp = require('./temp-cleanup');
|
|
25
32
|
|
|
26
33
|
const ROOT = path.resolve(__dirname, '..');
|
|
27
34
|
const WEIGHTS_FILE = path.join(__dirname, 'ci-shard-weights.json');
|
|
@@ -139,23 +146,48 @@ function runNpm(name, spec, opts = {}) {
|
|
|
139
146
|
const grouped = env.GITHUB_ACTIONS === 'true';
|
|
140
147
|
// Leaves do not see this runner's times file: a leaf that runs runNpm itself (ci-shard-probe.js) would overwrite it.
|
|
141
148
|
const leafEnv = { ...env };
|
|
142
|
-
for (const k of Object.keys(leafEnv)) if (k.toUpperCase()
|
|
149
|
+
for (const k of Object.keys(leafEnv)) if (['LEERNESS_CI_SHARD_TIMES', temp.RECORD_ENV].includes(k.toUpperCase())) delete leafEnv[k];
|
|
143
150
|
log(`ci-shard: ${name} shard ${spec.index}/${spec.count} runs ${mine.length} of ${leaves.length} leaves`);
|
|
151
|
+
// T-0357: one record directory per leaf, below a root this runner makes. Each is checked right after it is made (an
|
|
152
|
+
// empty directory, not a link, its identity kept): a wrapper of fs.mkdtempSync or fs.mkdirSync installed before
|
|
153
|
+
// the runner could put an existing folder there (1.36.304 review round 3). A leaf whose directory fails the check
|
|
154
|
+
// gets no variable and records nothing; only checked directories are removed, and the root only when it is empty.
|
|
155
|
+
const freshDir = d => {
|
|
156
|
+
try {
|
|
157
|
+
const st = fs.lstatSync(d, { bigint: true });
|
|
158
|
+
return st.isSymbolicLink() || !st.isDirectory() || fs.readdirSync(d).length ? null : temp.ownTree(d);
|
|
159
|
+
} catch { return null; }
|
|
160
|
+
};
|
|
161
|
+
let recordRoot = null;
|
|
162
|
+
try { recordRoot = freshDir(fs.mkdtempSync(path.join(os.tmpdir(), 'leerness-temp-record-'))); } catch { /* nothing recorded */ }
|
|
163
|
+
const tempCount = { removed: 0, left: 0, unrecorded: 0 };
|
|
144
164
|
const results = [];
|
|
145
|
-
for (const leaf of mine) {
|
|
165
|
+
for (const [i, leaf] of mine.entries()) {
|
|
146
166
|
if (grouped) log(`::group::${leaf.key}`);
|
|
167
|
+
let recordDir = null;
|
|
168
|
+
if (recordRoot) { const d = path.join(recordRoot.dir, String(i)); try { fs.mkdirSync(d); recordDir = freshDir(d); } catch { /* nothing recorded */ } }
|
|
169
|
+
if (!recordDir) tempCount.unrecorded++;
|
|
147
170
|
const started = Date.now();
|
|
148
|
-
const r = cp.spawnSync(process.execPath, [path.resolve(root, leaf.file), ...leaf.args], { cwd: root, stdio: opts.stdio || 'inherit', env: leafEnv });
|
|
171
|
+
const r = cp.spawnSync(process.execPath, [path.resolve(root, leaf.file), ...leaf.args], { cwd: root, stdio: opts.stdio || 'inherit', env: recordDir ? { ...leafEnv, [temp.RECORD_ENV]: recordDir.dir } : leafEnv });
|
|
149
172
|
const seconds = (Date.now() - started) / 1000;
|
|
150
173
|
const ok = r.status === 0 && !r.signal && !r.error;
|
|
174
|
+
if (ok && recordDir) { const t = temp.removeRecorded(recordDir.dir); tempCount.removed += t.removed; tempCount.left += t.left; }
|
|
175
|
+
if (recordDir) try { temp.removeOwnedTree(recordDir, { timeoutMs: 2000 }); } catch { /* left behind */ }
|
|
151
176
|
results.push({ key: leaf.key, ok, seconds, status: r.status, signal: r.signal || null, error: r.error ? String(r.error.code || r.error.message) : null });
|
|
152
177
|
if (grouped) log('::endgroup::');
|
|
153
178
|
log(`ci-shard: ${ok ? 'ok ' : 'FAIL'} ${seconds.toFixed(1).padStart(7)} s ${leaf.key}${ok ? '' : ` (exit ${r.status}${r.signal ? `, signal ${r.signal}` : ''}${r.error ? `, ${r.error.code || r.error.message}` : ''})`}`);
|
|
154
179
|
}
|
|
180
|
+
if (recordRoot) {
|
|
181
|
+
try {
|
|
182
|
+
const st = fs.lstatSync(recordRoot.dir, { bigint: true });
|
|
183
|
+
if (!st.isSymbolicLink() && st.dev === recordRoot.dev && st.ino === recordRoot.ino) fs.rmdirSync(recordRoot.dir);
|
|
184
|
+
} catch { /* not empty or replaced: left behind */ }
|
|
185
|
+
}
|
|
155
186
|
const failed = results.filter(r => !r.ok);
|
|
156
187
|
const total = results.reduce((s, r) => s + r.seconds, 0);
|
|
157
188
|
log(`ci-shard: ${name} shard ${spec.index}/${spec.count}: ${results.length - failed.length}/${results.length} leaves passed · ${total.toFixed(0)} s`);
|
|
158
189
|
for (const f of failed) log(`ci-shard: failed: ${f.key}`);
|
|
190
|
+
log(`ci-shard: temp folders: ${tempCount.removed} removed after passing leaves${tempCount.left ? `, ${tempCount.left} left (replaced, outside the temp directory, or still held)` : ''}${tempCount.unrecorded ? `, ${tempCount.unrecorded} leaves not recorded (their record directory was not the one made)` : ''}; a failed leaf keeps its own`);
|
|
159
191
|
if (env.LEERNESS_CI_SHARD_TIMES) {
|
|
160
192
|
fs.writeFileSync(env.LEERNESS_CI_SHARD_TIMES, JSON.stringify(Object.fromEntries(results.map(r => [r.key, Math.round(r.seconds * 10) / 10])), null, 1) + '\n');
|
|
161
193
|
}
|
|
@@ -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-0303: generated runtime cache must not create a strict Git mismatch for
|
|
5
6
|
// an unrelated, already committed claim when an older project lacks .gitignore.
|
|
@@ -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-0302: count real Git status requests at the CLI boundary, rather than
|
|
5
6
|
// matching the implementation's source text.
|
|
@@ -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-0145 multi-session regression: two first-time creators may both observe
|
|
5
6
|
// "absent", but the create-only check inside the file lock must let exactly
|
|
@@ -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-0145 regression probe: a reviewed legacy debt boundary unblocks only exact
|
|
5
6
|
// historical failures. Raw/per-task audits, changed rows, new failures, invalid
|
|
@@ -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('assert'), fs = require('fs'), path = require('path'), os = require('os'), cp = require('child_process');
|
|
3
4
|
const { createHash } = require('crypto');
|
|
4
5
|
const { removeTree } = require('./temp-cleanup');
|
|
@@ -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('assert'), fs = require('fs'), path = require('path'), os = require('os'), cp = require('child_process');
|
|
3
4
|
const { removeTree } = require('./temp-cleanup');
|
|
4
5
|
if (!process.argv.includes('--worker')) {
|
|
@@ -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-0343: lib/copy-tree.js copyTreeSync, the fs.cpSync replacement used for fixture and selftest copies.
|
|
3
4
|
// It must copy nested directories and file bytes exactly, copy into an existing directory, never overwrite a file,
|
|
4
5
|
// and work with non-ASCII paths on every supported Node (fs.cpSync crashes on them in Node 22.23.3 on Windows).
|
|
@@ -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-0323 (owner request 2026-09-30): data features get the CRUD operations they need, by default and in every
|
|
3
4
|
// leerness project. The owner chose "guidance plus an automatic check at completion" (advisory, never blocking),
|
|
4
5
|
// for new features and changes to existing ones, and "the four operations plus quality items" as the standard:
|
|
@@ -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-0094: advertised options must change observable behavior (or fail closed).
|
|
5
6
|
// This probe intentionally uses isolated projects and real CLI processes so a
|
|
@@ -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-0332: which tracker statuses read as done. verify-claim (one task, and --all, which gate --claims runs), the claims
|
|
3
4
|
// baseline, lazy detection and past-fix advice share one exact predicate: done, completed, verified or 완료, in any
|
|
4
5
|
// case, with the cell's spaces trimmed, also inside one pair of brackets (the older tracker form, like [진행]).
|
|
@@ -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-0339: commands whose edits need a state lock refuse --dry-run with the dry-run refusal. Under --dry-run the CLI
|
|
3
4
|
// takes no state lock (it would leave lock metadata), so lib/managed-text.js refused every edit with "Managed text
|
|
4
5
|
// requires its existing state lock" (E_TEXT_LOCK) before its first write could meet the dry-run guard (task add, drop
|
|
@@ -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
|
// Observation integration only: original E2E predicates, real temp files, no heavyweight CLI.
|
|
4
5
|
const assert = require('node:assert/strict');
|
|
@@ -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-0099 / UR-0076: historically uncovered command families.
|
|
5
6
|
// Local state commands execute end-to-end in a disposable fixture. Commands that
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
// scripts/e2e-concurrency.js — T-0115의 silent lost-update 회귀 방지.
|
|
2
2
|
// LOCKPROBE_STALL_*은 scripts/lock-probe.js를 명시 preload한 이 테스트에서만 활성화된다.
|
|
3
3
|
'use strict';
|
|
4
|
+
require('./temp-cleanup').trackTemp(module); // T-0357: records this run's temp folders; the runner that started it removes them after a clean exit
|
|
4
5
|
|
|
5
6
|
const fs = require('fs');
|
|
6
7
|
const os = require('os');
|
package/scripts/e2e-core.js
CHANGED
|
@@ -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
|
// 1.35.13 (UR-0014): 3-tier 테스트의 중간 티어 — critical-path 행위(behavioral) 스위트.
|
|
5
6
|
// test:fast (smoke.js) — 명령이 크래시 없이 도는가만 clean 프로젝트에서 확인, <1분. 개발 루프.
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
// dated decision, a lesson, an active rule, an open user request, a closed session (a handoff naming the
|
|
11
11
|
// in-progress task, the current state, a pre-wake report), the manifest, the installed skills and the usage counter.
|
|
12
12
|
'use strict';
|
|
13
|
+
require('./temp-cleanup').trackTemp(module); // T-0357: records this run's temp folders; the runner that started it removes them after a clean exit
|
|
13
14
|
const fs = require('fs');
|
|
14
15
|
const path = require('path');
|
|
15
16
|
const cp = require('child_process');
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// A snapshot records size, mtime (ns) and inode of every file and each directory, gitignored state included.
|
|
9
9
|
// Content hashes are unnecessary: a write moves mtime, and a rename or hard link changes the inode.
|
|
10
10
|
'use strict';
|
|
11
|
+
require('./temp-cleanup').trackTemp(module); // T-0357: records this run's temp folders; the runner that started it removes them after a clean exit
|
|
11
12
|
const fs = require('fs');
|
|
12
13
|
const os = require('os');
|
|
13
14
|
const path = require('path');
|
|
@@ -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-0182: execute the original E2E counter and failure assertion, with real
|
|
5
6
|
// process-local TMP isolation. No product implementation or fs/os mock.
|
package/scripts/e2e.js
CHANGED
|
@@ -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
|
const fs = require('fs');
|
|
5
6
|
const os = require('os');
|
|
@@ -15957,6 +15958,10 @@ setImmediate(() => {
|
|
|
15957
15958
|
failed++;
|
|
15958
15959
|
console.log(`✗ T-0359 e2e 샤드 가드 이상 ${JSON.stringify({ problems: _shard.problems.slice(0, 10), missing: _shard.missing.slice(0, 10), repeated: _shard.repeated.slice(0, 10), unknown: _shard.unknown.slice(0, 10) })}`);
|
|
15959
15960
|
}
|
|
15961
|
+
// T-0357: 케이스가 만든 임시 폴더는 이 프로세스가 기록만 하고, 이 실행을 시작한 러너(scripts/ci-shard.js)가 종료 코드 0 을
|
|
15962
|
+
// 보고 지운다(링크는 링크로만). 러너 없이 실행하면 기록하지 않는다.
|
|
15963
|
+
const _temp = require('./temp-cleanup').trackTemp(module);
|
|
15964
|
+
if (_temp.active) console.log(` 임시 폴더 ${_temp.pending()}개 기록 — 러너가 종료 코드 0 을 보면 삭제, 실패면 남김`);
|
|
15960
15965
|
console.log(`\nE2E result: ${total - failed}/${total} passed${_shard.spec ? ` · shard ${_shard.spec.index}/${_shard.spec.count} (${_shard.ran}/${_shard.total} cases)` : ''} · ${((Date.now() - _e2eStart) / 1000).toFixed(0)}s`);
|
|
15961
15966
|
if (failed > 0) process.exitCode = 1;
|
|
15962
15967
|
});
|
|
@@ -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('assert'), fs = require('fs'), path = require('path'), os = require('os'), cp = require('child_process');
|
|
3
4
|
const { createHash } = require('crypto');
|
|
4
5
|
const { LEGACY_WORKSPACE_DIR } = require('../lib/workspace-dir');
|
|
@@ -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-0181: test the confirmed UR-0113 diagnostic/exit-code defect separately
|
|
5
6
|
// from the unconfirmed Windows CI failure. The default violates the platform's
|
|
@@ -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('assert'), fs = require('fs'), path = require('path'), os = require('os'), cp = require('child_process');
|
|
3
4
|
const { createHash } = require('crypto');
|
|
4
5
|
const { removeTree } = require('./temp-cleanup');
|
|
@@ -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('assert'), fs = require('fs'), path = require('path'), os = require('os'), cp = require('child_process');
|
|
3
4
|
const { removeTree } = require('./temp-cleanup');
|
|
4
5
|
if (!process.argv.includes('--worker')) {
|
|
@@ -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
|
// Real filesystem writes and process termination; injected I/O faults are
|
|
4
5
|
// explicitly synthetic. These checks do not simulate physical power loss.
|
|
@@ -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-0095 regression probe: read/status commands must state what they actually
|
|
5
6
|
// measured. A CLI version is not a project version, an invalid memory verb is
|
|
@@ -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('assert'), fs = require('fs'), path = require('path'), os = require('os'), cp = require('child_process');
|
|
3
4
|
const { removeTree } = require('./temp-cleanup');
|
|
4
5
|
if (!process.argv.includes('--worker')) {
|
|
@@ -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
|
// Exact-file leases are an opt-in coordination primitive. This probe deliberately
|
|
5
6
|
// distinguishes them from the discarded ambient scope advisory: only explicit calls
|
|
@@ -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-0333: `task fix-evidence` speaks the project's language. It printed Korean everywhere: in an English project the
|
|
3
4
|
// header, the guidance, the per-row lines, the suggested evidence and the results of `--set` and of an empty list were
|
|
4
5
|
// Korean. English projects now get English; Korean output stays byte for byte (every expected line below is the text
|
|
@@ -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-0321: free text given to a command is exactly the positional text the user typed.
|
|
3
4
|
// Reported: `clarify "<request>" --path <dir>` appends <dir> to the request. That did not reproduce —
|
|
4
5
|
// main() builds args with nonFlagArgs(), which already drops registered value flags and their values; the
|
|
@@ -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('assert'), fs = require('fs'), path = require('path'), os = require('os'), cp = require('child_process');
|
|
3
4
|
const { createHash } = require('crypto');
|
|
4
5
|
const { removeTree } = require('./temp-cleanup');
|
|
@@ -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
|
// Real loopback TLS; only the test intercepts DNS destination/trust roots.
|
|
4
5
|
const assert = require('node:assert/strict');
|
|
@@ -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('assert'), fs = require('fs'), path = require('path'), os = require('os'), cp = require('child_process');
|
|
3
4
|
const { createHash } = require('crypto');
|
|
4
5
|
const { removeTree } = require('./temp-cleanup');
|
|
@@ -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-0317: English handoff output carries no Korean-only tool text. An English project on Korean Windows saw the
|
|
3
4
|
// terminal-encoding notice, skill suggestions, the official-skill cache note, next-step suggestions and the compact
|
|
4
5
|
// "다음:" line in Korean. Every line the tool writes on the handoff paths now goes through a language helper whose
|
|
@@ -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-0307: session close keeps user-written handoff text by position, and every reader of the
|
|
5
6
|
// handoff looks at the current generated region rather than the whole file.
|