@codyswann/lisa 4.28.4 → 4.29.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.
- package/README.md +3 -1
- package/all/copy-overwrite/scripts/lisa-gates.mjs +2 -1
- package/all/copy-overwrite/scripts/lisa-hooks/sonar-secrets.sh +3 -2
- package/all/copy-overwrite/scripts/lisa-postinstall.mjs +6 -2
- package/cdk/create-only/vitest.config.local.ts +5 -1
- package/cdk/package-lisa/package.lisa.json +14 -7
- package/dist/cli/apply.d.ts +20 -0
- package/dist/cli/apply.d.ts.map +1 -1
- package/dist/cli/apply.js +70 -3
- package/dist/cli/apply.js.map +1 -1
- package/dist/cli/doctor-apply-freshness.d.ts.map +1 -1
- package/dist/cli/doctor-apply-freshness.js +10 -4
- package/dist/cli/doctor-apply-freshness.js.map +1 -1
- package/dist/cli/lisa-test-run-bootstrap.d.ts +3 -0
- package/dist/cli/lisa-test-run-bootstrap.d.ts.map +1 -0
- package/dist/cli/lisa-test-run-bootstrap.js +201 -0
- package/dist/cli/lisa-test-run-bootstrap.js.map +1 -0
- package/dist/cli/lisa-test-run-ipc.d.ts +42 -0
- package/dist/cli/lisa-test-run-ipc.d.ts.map +1 -0
- package/dist/cli/lisa-test-run-ipc.js +200 -0
- package/dist/cli/lisa-test-run-ipc.js.map +1 -0
- package/dist/cli/lisa-test-run-process-group.d.ts +30 -0
- package/dist/cli/lisa-test-run-process-group.d.ts.map +1 -0
- package/dist/cli/lisa-test-run-process-group.js +123 -0
- package/dist/cli/lisa-test-run-process-group.js.map +1 -0
- package/dist/cli/lisa-test-run-reaper.d.ts +3 -0
- package/dist/cli/lisa-test-run-reaper.d.ts.map +1 -0
- package/dist/cli/lisa-test-run-reaper.js +195 -0
- package/dist/cli/lisa-test-run-reaper.js.map +1 -0
- package/dist/cli/lisa-test-run-runtime.d.ts +46 -0
- package/dist/cli/lisa-test-run-runtime.d.ts.map +1 -0
- package/dist/cli/lisa-test-run-runtime.js +123 -0
- package/dist/cli/lisa-test-run-runtime.js.map +1 -0
- package/dist/cli/lisa-test-run-supervisor.d.ts +13 -0
- package/dist/cli/lisa-test-run-supervisor.d.ts.map +1 -0
- package/dist/cli/lisa-test-run-supervisor.js +268 -0
- package/dist/cli/lisa-test-run-supervisor.js.map +1 -0
- package/dist/cli/lisa-test-run.d.ts +3 -0
- package/dist/cli/lisa-test-run.d.ts.map +1 -0
- package/dist/cli/lisa-test-run.js +66 -0
- package/dist/cli/lisa-test-run.js.map +1 -0
- package/dist/cli/shared-options.d.ts +11 -4
- package/dist/cli/shared-options.d.ts.map +1 -1
- package/dist/cli/shared-options.js +8 -8
- package/dist/cli/shared-options.js.map +1 -1
- package/dist/configs/vitest/base.d.ts.map +1 -1
- package/dist/configs/vitest/base.js +5 -2
- package/dist/configs/vitest/base.js.map +1 -1
- package/dist/configs/vitest/cdk.d.ts +4 -0
- package/dist/configs/vitest/cdk.d.ts.map +1 -1
- package/dist/configs/vitest/cdk.js +5 -0
- package/dist/configs/vitest/cdk.js.map +1 -1
- package/dist/configs/vitest/harper-fabric.d.ts.map +1 -1
- package/dist/configs/vitest/harper-fabric.js +1 -0
- package/dist/configs/vitest/harper-fabric.js.map +1 -1
- package/dist/configs/vitest/nestjs.d.ts.map +1 -1
- package/dist/configs/vitest/nestjs.js +1 -0
- package/dist/configs/vitest/nestjs.js.map +1 -1
- package/dist/configs/vitest/phaser.d.ts.map +1 -1
- package/dist/configs/vitest/phaser.js +1 -0
- package/dist/configs/vitest/phaser.js.map +1 -1
- package/dist/configs/vitest/scratch-authority.d.ts +25 -0
- package/dist/configs/vitest/scratch-authority.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-authority.js +107 -0
- package/dist/configs/vitest/scratch-authority.js.map +1 -0
- package/dist/configs/vitest/scratch-bound-cleanup-programs.d.ts +5 -0
- package/dist/configs/vitest/scratch-bound-cleanup-programs.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-bound-cleanup-programs.js +219 -0
- package/dist/configs/vitest/scratch-bound-cleanup-programs.js.map +1 -0
- package/dist/configs/vitest/scratch-bound-cleanup.d.ts +28 -0
- package/dist/configs/vitest/scratch-bound-cleanup.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-bound-cleanup.js +155 -0
- package/dist/configs/vitest/scratch-bound-cleanup.js.map +1 -0
- package/dist/configs/vitest/scratch-bound-root-cleanup.d.ts +17 -0
- package/dist/configs/vitest/scratch-bound-root-cleanup.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-bound-root-cleanup.js +149 -0
- package/dist/configs/vitest/scratch-bound-root-cleanup.js.map +1 -0
- package/dist/configs/vitest/scratch-global-setup.d.ts +17 -9
- package/dist/configs/vitest/scratch-global-setup.d.ts.map +1 -1
- package/dist/configs/vitest/scratch-global-setup.js +103 -35
- package/dist/configs/vitest/scratch-global-setup.js.map +1 -1
- package/dist/configs/vitest/scratch-leak-setup.d.ts +2 -0
- package/dist/configs/vitest/scratch-leak-setup.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-leak-setup.js +108 -0
- package/dist/configs/vitest/scratch-leak-setup.js.map +1 -0
- package/dist/configs/vitest/scratch-namespace-authority.d.ts +80 -0
- package/dist/configs/vitest/scratch-namespace-authority.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-namespace-authority.js +291 -0
- package/dist/configs/vitest/scratch-namespace-authority.js.map +1 -0
- package/dist/configs/vitest/scratch-owner.d.ts +131 -0
- package/dist/configs/vitest/scratch-owner.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-owner.js +297 -0
- package/dist/configs/vitest/scratch-owner.js.map +1 -0
- package/dist/configs/vitest/scratch-route-profile.d.ts +36 -0
- package/dist/configs/vitest/scratch-route-profile.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-route-profile.js +217 -0
- package/dist/configs/vitest/scratch-route-profile.js.map +1 -0
- package/dist/configs/vitest/scratch-run-root-compatibility.d.ts +33 -0
- package/dist/configs/vitest/scratch-run-root-compatibility.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-run-root-compatibility.js +137 -0
- package/dist/configs/vitest/scratch-run-root-compatibility.js.map +1 -0
- package/dist/configs/vitest/scratch-run-root-intent.d.ts +66 -0
- package/dist/configs/vitest/scratch-run-root-intent.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-run-root-intent.js +183 -0
- package/dist/configs/vitest/scratch-run-root-intent.js.map +1 -0
- package/dist/configs/vitest/scratch-setup.d.ts.map +1 -1
- package/dist/configs/vitest/scratch-setup.js +45 -15
- package/dist/configs/vitest/scratch-setup.js.map +1 -1
- package/dist/configs/vitest/scratch-supervision-intent.d.ts +8 -0
- package/dist/configs/vitest/scratch-supervision-intent.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-supervision-intent.js +125 -0
- package/dist/configs/vitest/scratch-supervision-intent.js.map +1 -0
- package/dist/configs/vitest/scratch-supervision-protocol.d.ts +12 -0
- package/dist/configs/vitest/scratch-supervision-protocol.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-supervision-protocol.js +230 -0
- package/dist/configs/vitest/scratch-supervision-protocol.js.map +1 -0
- package/dist/configs/vitest/scratch-supervision.d.ts +64 -0
- package/dist/configs/vitest/scratch-supervision.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-supervision.js +209 -0
- package/dist/configs/vitest/scratch-supervision.js.map +1 -0
- package/dist/configs/vitest/scratch-sweep.d.ts +66 -0
- package/dist/configs/vitest/scratch-sweep.d.ts.map +1 -0
- package/dist/configs/vitest/scratch-sweep.js +82 -0
- package/dist/configs/vitest/scratch-sweep.js.map +1 -0
- package/dist/configs/vitest/scratch.d.ts +14 -187
- package/dist/configs/vitest/scratch.d.ts.map +1 -1
- package/dist/configs/vitest/scratch.js +18 -285
- package/dist/configs/vitest/scratch.js.map +1 -1
- package/dist/configs/vitest/typescript.d.ts.map +1 -1
- package/dist/configs/vitest/typescript.js +1 -0
- package/dist/configs/vitest/typescript.js.map +1 -1
- package/dist/core/apply-mode.d.ts +80 -29
- package/dist/core/apply-mode.d.ts.map +1 -1
- package/dist/core/apply-mode.js +23 -2
- package/dist/core/apply-mode.js.map +1 -1
- package/dist/core/apply-receipt.d.ts +5 -1
- package/dist/core/apply-receipt.d.ts.map +1 -1
- package/dist/core/apply-receipt.js.map +1 -1
- package/dist/core/config.d.ts +24 -12
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.d.ts.map +1 -1
- package/dist/core/lisa-owned-hash-ledger.js +8 -0
- package/dist/core/lisa-owned-hash-ledger.js.map +1 -1
- package/dist/core/nightly-e2e-guard-behavior-certificate.js +2 -2
- package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
- package/dist/core/upstream-evidence-manifest.js +63 -15
- package/dist/core/upstream-evidence-manifest.js.map +1 -1
- package/dist/migrations/ensure-lisa-postinstall.d.ts +1 -1
- package/dist/migrations/ensure-lisa-postinstall.d.ts.map +1 -1
- package/dist/migrations/ensure-lisa-postinstall.js +28 -5
- package/dist/migrations/ensure-lisa-postinstall.js.map +1 -1
- package/dist/utils/postinstall-trampoline-source.js +10 -1
- package/dist/utils/postinstall-trampoline-source.js.map +1 -1
- package/expo/package-lisa/package.lisa.json +14 -14
- package/harper-fabric/package-lisa/package.lisa.json +8 -3
- package/nestjs/create-only/vitest.config.local.ts +5 -1
- package/nestjs/package-lisa/package.lisa.json +14 -8
- package/npm-package/package-lisa/package.lisa.json +8 -0
- package/package.json +17 -13
- package/phaser/package-lisa/package.lisa.json +9 -3
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/hooks/sonar-secrets.sh +3 -2
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/hooks/sonar-secrets.sh +3 -2
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/hooks/sonar-secrets.sh +3 -2
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-agy/plugin.json +1 -1
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/base/hooks/sonar-secrets.sh +3 -2
- package/scripts/install-claude-plugins.sh +7 -2
- package/typescript/create-only/vitest.config.local.ts +5 -1
- package/typescript/package-lisa/package.lisa.json +14 -8
|
@@ -1,301 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Bounded, self-reclaiming Vitest scratch lifecycle.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* That is a ratchet rather than a slowdown. Cleanup in a suite is written as
|
|
10
|
-
* `afterEach`, `afterAll` or `try`/`finally`, and all three are IN-PROCESS
|
|
11
|
-
* callbacks: when the runner is killed — SIGKILL, `exit 137`, which is how this
|
|
12
|
-
* failed in practice — none of them run and every directory the run had open is
|
|
13
|
-
* abandoned. A run that dies enlarges the directory the next run depends on, so
|
|
14
|
-
* the next run is slower and likelier to die.
|
|
15
|
-
*
|
|
16
|
-
* Measured on one saturated workstation, against a directory this module
|
|
17
|
-
* governs on the same machine at the same moment:
|
|
18
|
-
*
|
|
19
|
-
* ```
|
|
20
|
-
* shared platform root inside a run root
|
|
21
|
-
* inode size (stat -f %z) 24,902,496 bytes 64 bytes
|
|
22
|
-
* one stat() 189.9 ms 0.2 ms
|
|
23
|
-
* five mkdtemp() calls 35,619.7 ms 0.8 ms
|
|
24
|
-
* ```
|
|
25
|
-
*
|
|
26
|
-
* Seven seconds for a single `mkdtemp`. A fixture creating two directories
|
|
27
|
-
* exhausted a 60-second budget having done no work, which is why every symptom
|
|
28
|
-
* of this was a timeout and never an assertion failure.
|
|
29
|
-
*
|
|
30
|
-
* Three properties, each chosen against a specific way the previous state
|
|
31
|
-
* failed:
|
|
32
|
-
*
|
|
33
|
-
* 1. **One entry, ever.** Everything lives under a single `lisa-scratch`
|
|
34
|
-
* directory in the platform temp root, so a project contributes ONE name to
|
|
35
|
-
* the shared directory regardless of how many fixtures it creates. The
|
|
36
|
-
* expensive lookup is paid once per process instead of once per fixture.
|
|
37
|
-
* 2. **Wholesale teardown.** A run's directories nest under one per-process
|
|
38
|
-
* root, so ending a run is a single recursive removal rather than hundreds
|
|
39
|
-
* of cooperating call sites.
|
|
40
|
-
* 3. **Reclaim on start, not on exit.** A process that is SIGKILLed cannot run
|
|
41
|
-
* cleanup — no design can make it. So the residue of a killed run is
|
|
42
|
-
* reclaimed by the NEXT run instead: roots are named with the pid that owns
|
|
43
|
-
* them, and a sweep removes any whose owner is gone. This is the only
|
|
44
|
-
* mechanism that survives an abnormal exit, and it is why the loop above
|
|
45
|
-
* cannot restart.
|
|
46
|
-
*
|
|
47
|
-
* Deliberately NOT repo-local. A scratch root inside the project would give
|
|
48
|
-
* every fixture two ancestors it must not have: the repository's `.git` (so a
|
|
49
|
-
* fixture asserting "not a git repository" would find the project's) and the
|
|
50
|
-
* repository's `node_modules` (so a fixture asserting a dependency is absent
|
|
51
|
-
* would resolve the project's copy). Both change what fixtures mean, which is a
|
|
52
|
-
* worse defect than the one being fixed.
|
|
4
|
+
* Every fixture directory lives under one platform-temp namespace and one
|
|
5
|
+
* per-process owned root. The public facade stays deliberately small: naming,
|
|
6
|
+
* authority, startup sweeping, transactional allocation, and token-bound
|
|
7
|
+
* teardown live in focused sibling modules.
|
|
53
8
|
* @module configs/vitest/scratch
|
|
54
9
|
*/
|
|
55
|
-
import { randomBytes } from "node:crypto";
|
|
56
10
|
import * as fs from "node:fs";
|
|
57
|
-
import * as os from "node:os";
|
|
58
|
-
import * as path from "node:path";
|
|
59
|
-
import { env } from "node:process";
|
|
60
|
-
/**
|
|
61
|
-
* Single directory name every Lisa scratch root nests under.
|
|
62
|
-
*
|
|
63
|
-
* The name is the contract: it is what makes "one entry in the shared temp
|
|
64
|
-
* root, ever" checkable, and what the sweep enumerates instead of the
|
|
65
|
-
* (unenumerable) platform root.
|
|
66
|
-
*/
|
|
67
|
-
export const SCRATCH_NAMESPACE = "lisa-scratch";
|
|
68
|
-
/** Prefix identifying a per-process run root inside the namespace. */
|
|
69
|
-
export const RUN_ROOT_PREFIX = "run-";
|
|
70
|
-
/**
|
|
71
|
-
* Backstop age after which a run root is reclaimed even though its recorded pid
|
|
72
|
-
* still resolves to a live process.
|
|
73
|
-
*
|
|
74
|
-
* Pids are recycled, so liveness alone can pin an abandoned root forever if an
|
|
75
|
-
* unrelated process happens to inherit its number. Six hours is longer than any
|
|
76
|
-
* legitimate suite and short enough that a recycled pid cannot hold a root
|
|
77
|
-
* across a working day.
|
|
78
|
-
*/
|
|
79
|
-
export const DEFAULT_RECLAIM_AGE_MS = 6 * 60 * 60 * 1000;
|
|
80
|
-
/** Environment variable that relocates the namespace away from the platform temp root. */
|
|
81
|
-
export const SCRATCH_ROOT_ENV = "LISA_TEST_SCRATCH_ROOT";
|
|
82
|
-
/**
|
|
83
|
-
* Resolves the directory the namespace lives in.
|
|
84
|
-
*
|
|
85
|
-
* Honours `LISA_TEST_SCRATCH_ROOT` first so an operator or CI job can point
|
|
86
|
-
* scratch space at a specific volume, then `os.tmpdir()` — which itself re-reads
|
|
87
|
-
* `TMPDIR` on every call, so the pre-existing `export TMPDIR=...` mitigation
|
|
88
|
-
* composes with this rather than being defeated by it.
|
|
89
|
-
* @returns Absolute path to the directory containing the scratch namespace.
|
|
90
|
-
*/
|
|
91
|
-
export const scratchBaseDir = () => {
|
|
92
|
-
const override = env[SCRATCH_ROOT_ENV];
|
|
93
|
-
return override !== undefined && override.trim() !== ""
|
|
94
|
-
? override
|
|
95
|
-
: os.tmpdir();
|
|
96
|
-
};
|
|
97
|
-
/**
|
|
98
|
-
* Absolute path of the shared namespace directory.
|
|
99
|
-
* @returns Path to `<base>/lisa-scratch`.
|
|
100
|
-
*/
|
|
101
|
-
export const scratchNamespaceDir = () => path.join(scratchBaseDir(), SCRATCH_NAMESPACE);
|
|
102
|
-
/**
|
|
103
|
-
* Builds the name of a per-process run root.
|
|
104
|
-
*
|
|
105
|
-
* The pid is encoded in the name because it is the only durable record of who
|
|
106
|
-
* owns the directory: a killed process leaves no other trace, and the sweep has
|
|
107
|
-
* to tell an abandoned root from one a sibling run is using right now.
|
|
108
|
-
* @param pid - Owning process id
|
|
109
|
-
* @param startedAt - Epoch milliseconds the root was created
|
|
110
|
-
* @param suffix - Random suffix disambiguating two roots created in the same millisecond
|
|
111
|
-
* @returns The directory name, without any leading path.
|
|
112
|
-
*/
|
|
113
|
-
export const runRootName = (pid, startedAt, suffix) => `${RUN_ROOT_PREFIX}${pid}-${startedAt}-${suffix}`;
|
|
114
|
-
/**
|
|
115
|
-
* Recovers the pid and creation time encoded in a run root's name.
|
|
116
|
-
* @param name - A directory name from inside the namespace
|
|
117
|
-
* @returns The owner, or `undefined` when the name was not produced by {@link runRootName}.
|
|
118
|
-
*/
|
|
119
|
-
export const parseRunRootName = (name) => {
|
|
120
|
-
// Derived from RUN_ROOT_PREFIX rather than spelled out again. A literal here
|
|
121
|
-
// would let the writer and the reader drift apart, and the failure mode of
|
|
122
|
-
// that drift is the worst one available: creation keeps working, the sweep
|
|
123
|
-
// silently matches nothing, and the namespace fills while every run passes.
|
|
124
|
-
const match = new RegExp(`^${RUN_ROOT_PREFIX}(\\d+)-(\\d+)-[^-]+$`).exec(name);
|
|
125
|
-
if (match === null) {
|
|
126
|
-
return undefined;
|
|
127
|
-
}
|
|
128
|
-
const pid = Number(match[1]);
|
|
129
|
-
const startedAt = Number(match[2]);
|
|
130
|
-
return Number.isSafeInteger(pid) && Number.isSafeInteger(startedAt)
|
|
131
|
-
? { pid, startedAt }
|
|
132
|
-
: undefined;
|
|
133
|
-
};
|
|
134
|
-
/**
|
|
135
|
-
* Decides whether a namespace entry is abandoned residue.
|
|
136
|
-
*
|
|
137
|
-
* A name this module did not produce is not judged here — see
|
|
138
|
-
* {@link isStaleForeignEntry}, which reclaims it on age alone. Deleting another
|
|
139
|
-
* tool's fresh data is not this sweep's business; leaving it forever would let
|
|
140
|
-
* one stray directory wedge every future run.
|
|
141
|
-
* @param input - The entry and the facts needed to judge it
|
|
142
|
-
* @param input.name - Directory name inside the namespace
|
|
143
|
-
* @param input.now - Current epoch milliseconds
|
|
144
|
-
* @param input.isProcessAlive - Liveness probe for the recorded pid
|
|
145
|
-
* @param input.maxAgeMs - Age after which a live-pid root is reclaimed anyway
|
|
146
|
-
* @param input.selfName - Caller's own root name, never reclaimed
|
|
147
|
-
* @returns True when the entry may be removed.
|
|
148
|
-
*/
|
|
149
|
-
export const isReclaimable = ({ name, now, isProcessAlive, maxAgeMs = DEFAULT_RECLAIM_AGE_MS, selfName, }) => {
|
|
150
|
-
if (selfName !== undefined && name === selfName) {
|
|
151
|
-
return false;
|
|
152
|
-
}
|
|
153
|
-
const owner = parseRunRootName(name);
|
|
154
|
-
if (owner === undefined) {
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
|
-
if (now - owner.startedAt > maxAgeMs) {
|
|
158
|
-
return true;
|
|
159
|
-
}
|
|
160
|
-
return !isProcessAlive(owner.pid);
|
|
161
|
-
};
|
|
162
11
|
/**
|
|
163
|
-
*
|
|
12
|
+
* Remove a non-authoritative fixture directory on a best-effort basis.
|
|
164
13
|
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
* @param
|
|
169
|
-
* @returns True when a process with that id exists.
|
|
170
|
-
*/
|
|
171
|
-
export const isProcessAlive = (pid) => {
|
|
172
|
-
try {
|
|
173
|
-
process.kill(pid, 0);
|
|
174
|
-
return true;
|
|
175
|
-
}
|
|
176
|
-
catch (error) {
|
|
177
|
-
return error.code === "EPERM";
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
/**
|
|
181
|
-
* Decides whether an entry this module did not create may be removed.
|
|
182
|
-
*
|
|
183
|
-
* Age is the only signal available: a foreign name carries no owner, so there is
|
|
184
|
-
* nothing to ask the kernel about. Reclaiming on the same backstop the pid arm
|
|
185
|
-
* uses means the namespace self-heals from anything parked in it — an older
|
|
186
|
-
* release's naming scheme, a stray `mktemp` — without this sweep ever deleting
|
|
187
|
-
* something a live tool is still writing to.
|
|
188
|
-
*
|
|
189
|
-
* The alternative was to treat a foreign name as a hard failure. That was tried
|
|
190
|
-
* and rejected: it wedges permanently on one stray directory, and the message a
|
|
191
|
-
* downstream user gets — "run roots must be named by runRootName()" — names
|
|
192
|
-
* something they cannot act on.
|
|
193
|
-
* @param entryPath - Absolute path of the entry
|
|
194
|
-
* @param now - Current epoch milliseconds
|
|
195
|
-
* @param maxAgeMs - Age past which a foreign entry is reclaimed
|
|
196
|
-
* @returns True when the entry is old enough to remove.
|
|
197
|
-
*/
|
|
198
|
-
export const isStaleForeignEntry = (entryPath, now, maxAgeMs) => {
|
|
199
|
-
try {
|
|
200
|
-
return now - fs.statSync(entryPath).mtimeMs > maxAgeMs;
|
|
201
|
-
}
|
|
202
|
-
catch {
|
|
203
|
-
return false;
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
/**
|
|
207
|
-
* Lists the namespace's direct children, treating an absent namespace as empty.
|
|
208
|
-
*
|
|
209
|
-
* A directory that cannot be read is not a directory that is empty — but for the
|
|
210
|
-
* one case that occurs here, the namespace not existing yet, the two are the
|
|
211
|
-
* same answer and every caller wants to continue rather than fail.
|
|
212
|
-
* @param dir - Namespace directory to list
|
|
213
|
-
* @returns The entry names, or an empty list.
|
|
214
|
-
*/
|
|
215
|
-
export const readNamespaceEntries = (dir) => {
|
|
216
|
-
try {
|
|
217
|
-
return fs.readdirSync(dir);
|
|
218
|
-
}
|
|
219
|
-
catch {
|
|
220
|
-
return [];
|
|
221
|
-
}
|
|
222
|
-
};
|
|
223
|
-
/**
|
|
224
|
-
* Removes abandoned run roots from the namespace.
|
|
225
|
-
*
|
|
226
|
-
* This is the arm of the design that survives a kill. It runs at the START of a
|
|
227
|
-
* run precisely because the run that leaked cannot be the one to clean up.
|
|
228
|
-
* @param options - Sweep inputs
|
|
229
|
-
* @param options.dir - Namespace directory to sweep
|
|
230
|
-
* @param options.now - Current epoch milliseconds
|
|
231
|
-
* @param options.isProcessAlive - Liveness probe for recorded pids
|
|
232
|
-
* @param options.maxAgeMs - Age after which a live-pid root is reclaimed anyway
|
|
233
|
-
* @param options.selfName - Caller's own root name, never reclaimed
|
|
234
|
-
* @returns Which entries were removed and which were kept.
|
|
235
|
-
*/
|
|
236
|
-
export const sweepScratchNamespace = ({ dir = scratchNamespaceDir(), now = Date.now(), isProcessAlive: alive = isProcessAlive, maxAgeMs = DEFAULT_RECLAIM_AGE_MS, selfName, } = {}) => readNamespaceEntries(dir).reduce((acc, name) => {
|
|
237
|
-
const entryPath = path.join(dir, name);
|
|
238
|
-
const decision = {
|
|
239
|
-
name,
|
|
240
|
-
now,
|
|
241
|
-
isProcessAlive: alive,
|
|
242
|
-
maxAgeMs,
|
|
243
|
-
...(selfName === undefined ? {} : { selfName }),
|
|
244
|
-
};
|
|
245
|
-
const reclaimable = parseRunRootName(name) === undefined
|
|
246
|
-
? name !== selfName && isStaleForeignEntry(entryPath, now, maxAgeMs)
|
|
247
|
-
: isReclaimable(decision);
|
|
248
|
-
if (!reclaimable) {
|
|
249
|
-
return { removed: acc.removed, kept: [...acc.kept, name] };
|
|
250
|
-
}
|
|
251
|
-
try {
|
|
252
|
-
fs.rmSync(entryPath, { recursive: true, force: true });
|
|
253
|
-
}
|
|
254
|
-
catch {
|
|
255
|
-
// A root another process is removing right now races us here. Losing
|
|
256
|
-
// that race is the correct outcome and is not worth failing a run over.
|
|
257
|
-
return { removed: acc.removed, kept: [...acc.kept, name] };
|
|
258
|
-
}
|
|
259
|
-
return { removed: [...acc.removed, name], kept: acc.kept };
|
|
260
|
-
}, { removed: [], kept: [] });
|
|
261
|
-
/**
|
|
262
|
-
* Creates a run root owned by the current process and returns its path.
|
|
263
|
-
* @param options - Overrides for the namespace directory and clock
|
|
264
|
-
* @param options.dir - Namespace directory to create the root inside
|
|
265
|
-
* @param options.now - Epoch milliseconds recorded in the root's name
|
|
266
|
-
* @returns Absolute path of this process's run root.
|
|
267
|
-
*/
|
|
268
|
-
export const createRunRoot = ({ dir = scratchNamespaceDir(), now = Date.now(), } = {}) => {
|
|
269
|
-
const suffix = randomBytes(4).toString("hex");
|
|
270
|
-
const root = path.join(dir, runRootName(process.pid, now, suffix));
|
|
271
|
-
fs.mkdirSync(root, { recursive: true });
|
|
272
|
-
return root;
|
|
273
|
-
};
|
|
274
|
-
/**
|
|
275
|
-
* Reclaims abandoned roots, then allocates one for this process.
|
|
276
|
-
*
|
|
277
|
-
* The order is the point, and it is why this is one function rather than two
|
|
278
|
-
* calls at the call site: reclaiming AFTER allocating leaves a window in which
|
|
279
|
-
* the namespace holds both, and reclaiming somewhere else entirely is how a
|
|
280
|
-
* caller ends up allocating without ever reclaiming at all.
|
|
281
|
-
* @param dir - Namespace directory
|
|
282
|
-
* @returns Absolute path of the newly created run root.
|
|
283
|
-
*/
|
|
284
|
-
export const reclaimAndCreateRunRoot = (dir) => {
|
|
285
|
-
sweepScratchNamespace({ dir });
|
|
286
|
-
return createRunRoot({ dir });
|
|
287
|
-
};
|
|
288
|
-
/**
|
|
289
|
-
* Removes a directory tree, ignoring an already-absent path.
|
|
290
|
-
* @param dir - Directory to remove
|
|
14
|
+
* Owned run-root teardown must use `removeOwnedScratchRunRoot`; this helper is
|
|
15
|
+
* retained only for nested fixture compatibility, where the next bounded sweep
|
|
16
|
+
* can recover residue.
|
|
17
|
+
* @param dir - Nested fixture directory to remove
|
|
291
18
|
*/
|
|
292
19
|
export const removeScratchDir = (dir) => {
|
|
293
20
|
try {
|
|
294
21
|
fs.rmSync(dir, { recursive: true, force: true });
|
|
295
22
|
}
|
|
296
23
|
catch {
|
|
297
|
-
//
|
|
298
|
-
// sweep rather than failing the current one.
|
|
24
|
+
// The next owned-root teardown or startup sweep recovers nested residue.
|
|
299
25
|
}
|
|
300
26
|
};
|
|
27
|
+
export { DEFAULT_RECLAIM_AGE_MS, RUN_ROOT_PREFIX, SCRATCH_NAMESPACE, parseRunRootName, runRootName, scratchBaseDir, scratchNamespaceDir, } from "./scratch-authority.js";
|
|
28
|
+
export { SCRATCH_PREFIXES_ENV, SCRATCH_SUITE_ENV, } from "./scratch-route-profile.js";
|
|
29
|
+
export { registeredScratchPrefixes, scratchSuiteLabel, } from "./scratch-route-profile.js";
|
|
30
|
+
export { isProcessAlive, isReclaimable, isStaleForeignEntry, liveOwnerBirthProbe, readNamespaceEntries, sweepScratchNamespace, } from "./scratch-sweep.js";
|
|
31
|
+
export { materializeOwnedScratchRunRoot, openOwnedScratchRunRoot, prepareOwnedScratchRunRoot, } from "./scratch-run-root-intent.js";
|
|
32
|
+
export { adoptOwnedScratchRunRoot, createRunRoot, reclaimAndCreateOwnedRunRoot, reclaimAndCreateRunRoot, } from "./scratch-run-root-compatibility.js";
|
|
33
|
+
export { removeOwnedScratchRunRoot } from "./scratch-run-root-intent.js";
|
|
301
34
|
//# sourceMappingURL=scratch.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scratch.js","sourceRoot":"","sources":["../../../src/configs/vitest/scratch.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"scratch.js","sourceRoot":"","sources":["../../../src/configs/vitest/scratch.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAE9B;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,GAAW,EAAQ,EAAE;IACpD,IAAI,CAAC;QACH,EAAE,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,CAAC;IAAC,MAAM,CAAC;QACP,yEAAyE;IAC3E,CAAC;AACH,CAAC,CAAC;AAEF,OAAO,EACL,sBAAsB,EACtB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,oBAAoB,EACpB,iBAAiB,GAClB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,yBAAyB,EACzB,iBAAiB,GAClB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,EACL,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAQ5B,OAAO,EACL,8BAA8B,EAC9B,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,8BAA8B,CAAC;AAOtC,OAAO,EACL,wBAAwB,EACxB,aAAa,EACb,4BAA4B,EAC5B,uBAAuB,GACxB,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EAAE,yBAAyB,EAAE,MAAM,8BAA8B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typescript.d.ts","sourceRoot":"","sources":["../../../src/configs/vitest/typescript.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,8DAA8D;AAC9D,KAAK,UAAU,GAAG,cAAc,CAAC;AAEjC,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAGpD,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,GACnB,CAAC;AAEF,YAAY,EAAE,kBAAkB,EAAE,CAAC;AAEnC;;GAEG;AACH,UAAU,uBAAuB;IAC/B,mFAAmF;IACnF,QAAQ,CAAC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CAC1C;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,GAAI,kBAEvC,uBAA4B,KAAG,
|
|
1
|
+
{"version":3,"file":"typescript.d.ts","sourceRoot":"","sources":["../../../src/configs/vitest/typescript.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,8DAA8D;AAC9D,KAAK,UAAU,GAAG,cAAc,CAAC;AAEjC,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAGpD,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,GACnB,CAAC;AAEF,YAAY,EAAE,kBAAkB,EAAE,CAAC;AAEnC;;GAEG;AACH,UAAU,uBAAuB;IAC/B,mFAAmF;IACnF,QAAQ,CAAC,UAAU,CAAC,EAAE,kBAAkB,CAAC;CAC1C;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,GAAI,kBAEvC,uBAA4B,KAAG,UAiBhC,CAAC"}
|
|
@@ -15,6 +15,7 @@ export const getTypescriptVitestConfig = ({ thresholds = defaultThresholds, } =
|
|
|
15
15
|
test: {
|
|
16
16
|
setupFiles: [...scratchSetupFiles()],
|
|
17
17
|
globalSetup: [...scratchGlobalSetup()],
|
|
18
|
+
sequence: { setupFiles: "list", hooks: "stack" },
|
|
18
19
|
globals: true,
|
|
19
20
|
environment: "node",
|
|
20
21
|
include: ["tests/**/*.test.ts", "src/**/*.test.ts"],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"typescript.js","sourceRoot":"","sources":["../../../src/configs/vitest/typescript.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,WAAW,CAAC;AAInB,6DAA6D;AAC7D,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,GACnB,CAAC;AAYF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,EACxC,UAAU,GAAG,iBAAiB,MACH,EAAE,EAAc,EAAE,CAAC,CAAC;IAC/C,IAAI,EAAE;QACJ,UAAU,EAAE,CAAC,GAAG,iBAAiB,EAAE,CAAC;QACpC,WAAW,EAAE,CAAC,GAAG,kBAAkB,EAAE,CAAC;QACtC,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,MAAM;QACnB,OAAO,EAAE,CAAC,oBAAoB,EAAE,kBAAkB,CAAC;QACnD,OAAO,EAAE,CAAC,GAAG,qBAAqB,EAAE,GAAG,kBAAkB,EAAE,CAAC;QAC5D,WAAW,EAAE,KAAK;QAClB,QAAQ,EAAE;YACR,QAAQ,EAAE,IAAI;YACd,OAAO,EAAE,CAAC,aAAa,CAAC;YACxB,OAAO,EAAE,CAAC,GAAG,yBAAyB,EAAE,GAAG,kBAAkB,EAAE,CAAC;YAChE,UAAU,EAAE,aAAa,CAAC,UAAU,CAAC;SACtC;KACF;CACF,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"typescript.js","sourceRoot":"","sources":["../../../src/configs/vitest/typescript.ts"],"names":[],"mappings":"AAaA,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,GACnB,MAAM,WAAW,CAAC;AAInB,6DAA6D;AAC7D,OAAO,EACL,yBAAyB,EACzB,qBAAqB,EACrB,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,iBAAiB,EACjB,kBAAkB,GACnB,CAAC;AAYF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,EACxC,UAAU,GAAG,iBAAiB,MACH,EAAE,EAAc,EAAE,CAAC,CAAC;IAC/C,IAAI,EAAE;QACJ,UAAU,EAAE,CAAC,GAAG,iBAAiB,EAAE,CAAC;QACpC,WAAW,EAAE,CAAC,GAAG,kBAAkB,EAAE,CAAC;QACtC,QAAQ,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE;QAChD,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,MAAM;QACnB,OAAO,EAAE,CAAC,oBAAoB,EAAE,kBAAkB,CAAC;QACnD,OAAO,EAAE,CAAC,GAAG,qBAAqB,EAAE,GAAG,kBAAkB,EAAE,CAAC;QAC5D,WAAW,EAAE,KAAK;QAClB,QAAQ,EAAE;YACR,QAAQ,EAAE,IAAI;YACd,OAAO,EAAE,CAAC,aAAa,CAAC;YACxB,OAAO,EAAE,CAAC,GAAG,yBAAyB,EAAE,GAAG,kBAAkB,EAAE,CAAC;YAChE,UAAU,EAAE,aAAa,CAAC,UAAU,CAAC;SACtC;KACF;CACF,CAAC,CAAC"}
|
|
@@ -20,42 +20,78 @@
|
|
|
20
20
|
* fleet. A silent gap is bad; a silent gap with an instrument attesting to it
|
|
21
21
|
* is worse.
|
|
22
22
|
*
|
|
23
|
-
* ##
|
|
24
|
-
*
|
|
25
|
-
* `--skip-git-check`
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
23
|
+
* ## The conflation, and how it is separated
|
|
24
|
+
*
|
|
25
|
+
* `--skip-git-check` used to carry two unrelated propositions, and selecting
|
|
26
|
+
* the reduced subset was the one nothing in its name suggested
|
|
27
|
+
* (CodySwannGT/lisa#3066). They are separated here because they are scoped to
|
|
28
|
+
* different things:
|
|
29
|
+
*
|
|
30
|
+
* | proposition | scoped to | expressed by |
|
|
31
|
+
* |---|---|---|
|
|
32
|
+
* | "do not require a clean working tree" | the INVOCATION — the caller knows its own tree | `--skip-git-check` |
|
|
33
|
+
* | "run the reduced subset" | the CONTEXT — is this a package manager's install lifecycle | `--postinstall-safe` / `LISA_POSTINSTALL=1` |
|
|
34
|
+
*
|
|
35
|
+
* `skipGitCheck` is accepted by {@link ApplyModeInputs} and deliberately read
|
|
36
|
+
* by nothing in this module. Keeping the field makes the separation directly
|
|
37
|
+
* assertable and makes any future re-reading of it a visible diff rather than
|
|
38
|
+
* a silent regression.
|
|
39
|
+
*
|
|
40
|
+
* ## Why the context is DECLARED and not detected
|
|
41
|
+
*
|
|
42
|
+
* Lisa already has an ambient detector — `isRunningAsLifecycleScript()`, which
|
|
43
|
+
* reads `npm_package_json`. It cannot decide this, and the reason is measured
|
|
44
|
+
* rather than assumed:
|
|
45
|
+
*
|
|
46
|
+
* - `npm install` postinstall sets `npm_lifecycle_event=postinstall`.
|
|
47
|
+
* - **`bun install` postinstall sets neither `npm_lifecycle_event` nor
|
|
48
|
+
* `npm_command`** while still running the script; it does set
|
|
49
|
+
* `npm_config_user_agent` and `npm_package_json`.
|
|
50
|
+
* - Every one of those leaks into the descendants of ANY `bun run` / `npm run`
|
|
51
|
+
* — including the shell an operator, a CI job, or an agent runs an apply
|
|
52
|
+
* from.
|
|
53
|
+
*
|
|
54
|
+
* A detector keyed on the first would classify every bun-based project's
|
|
55
|
+
* postinstall as a full apply, and a full apply under `bun install`
|
|
56
|
+
* regenerates agent trees — exactly what the reduced mode exists to prevent. A
|
|
57
|
+
* detector keyed on the second over-fires instead, handing the reduced subset
|
|
58
|
+
* back to the very callers this fixes, silently. A declaration can do neither:
|
|
59
|
+
* only Lisa's own postinstall invocations carry it.
|
|
60
|
+
*
|
|
61
|
+
* The declaration is also concrete at the moment the decision is taken — a
|
|
62
|
+
* plain string already present in the process, never a deferred or
|
|
63
|
+
* lazily-resolved value that could still be token-shaped when read.
|
|
47
64
|
* @module core/apply-mode
|
|
48
65
|
*/
|
|
49
66
|
import type { ApplyMode } from "./apply-receipt.js";
|
|
67
|
+
/** Environment variable a postinstall invocation sets to declare itself. */
|
|
68
|
+
export declare const LISA_POSTINSTALL_ENV = "LISA_POSTINSTALL";
|
|
69
|
+
/** The value {@link LISA_POSTINSTALL_ENV} must hold to count as declared. */
|
|
70
|
+
export declare const LISA_POSTINSTALL_ENV_VALUE = "1";
|
|
50
71
|
/** The subset of config this decision reads. */
|
|
51
72
|
export interface ApplyModeInputs {
|
|
52
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* Whether the dirty-tree check was waived.
|
|
75
|
+
*
|
|
76
|
+
* Accepted and DELIBERATELY UNREAD. This field used to decide the mode, and
|
|
77
|
+
* that conflation is the defect this module resolves; it stays in the shape
|
|
78
|
+
* so the separation can be asserted directly and so re-reading it would show
|
|
79
|
+
* up as a diff here rather than as behaviour nobody notices.
|
|
80
|
+
*/
|
|
53
81
|
readonly skipGitCheck: boolean;
|
|
54
82
|
/**
|
|
55
|
-
*
|
|
83
|
+
* Whether this apply declared itself a package-manager install lifecycle.
|
|
84
|
+
*
|
|
85
|
+
* Set by `--postinstall-safe` or `LISA_POSTINSTALL=1`, which every
|
|
86
|
+
* Lisa-written postinstall invocation carries. This is the only input that
|
|
87
|
+
* selects the reduced subset.
|
|
88
|
+
*/
|
|
89
|
+
readonly postinstall?: boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Explicit request for the full apply even inside a declared postinstall.
|
|
56
92
|
*
|
|
57
|
-
* The
|
|
58
|
-
*
|
|
93
|
+
* The override of last resort, for an operator who means to force the
|
|
94
|
+
* complete apply from inside a lifecycle script.
|
|
59
95
|
*/
|
|
60
96
|
readonly fullApply?: boolean;
|
|
61
97
|
}
|
|
@@ -63,7 +99,7 @@ export interface ApplyModeInputs {
|
|
|
63
99
|
* Resolves the mode this apply runs in.
|
|
64
100
|
*
|
|
65
101
|
* Every consumer — agent emits, `package.json` protection, and the receipt —
|
|
66
|
-
* MUST read this rather than re-deriving from
|
|
102
|
+
* MUST read this rather than re-deriving from any single flag, so the recorded
|
|
67
103
|
* mode can never describe work the run did not do.
|
|
68
104
|
* @param config - The apply's resolved configuration.
|
|
69
105
|
* @returns `"postinstall-safe"` for the reduced subset, otherwise `"full"`.
|
|
@@ -79,4 +115,19 @@ export declare function resolveApplyMode(config: ApplyModeInputs): ApplyMode;
|
|
|
79
115
|
* @returns True when the reduced `postinstall-safe` subset applies.
|
|
80
116
|
*/
|
|
81
117
|
export declare function isPostinstallSafeApply(config: ApplyModeInputs): boolean;
|
|
118
|
+
/**
|
|
119
|
+
* Resolve the postinstall declaration from the CLI flag and the environment.
|
|
120
|
+
*
|
|
121
|
+
* Two spellings, one meaning. The flag is what Lisa's own spawned invocations
|
|
122
|
+
* pass, because a spawned child's environment is sanitised of package-manager
|
|
123
|
+
* variables and a flag survives that; the environment variable is what the
|
|
124
|
+
* hook text in a consumer's `package.json` carries, because prefixing an
|
|
125
|
+
* assignment leaves the command tail untouched and therefore leaves the
|
|
126
|
+
* recogniser in `ensure-lisa-postinstall` matching both shapes with a single
|
|
127
|
+
* added alternative.
|
|
128
|
+
* @param flag - Value of `--postinstall-safe`, if passed.
|
|
129
|
+
* @param env - Environment to read {@link LISA_POSTINSTALL_ENV} from.
|
|
130
|
+
* @returns True when this apply declared itself a postinstall.
|
|
131
|
+
*/
|
|
132
|
+
export declare function resolvePostinstallDeclaration(flag: boolean | undefined, env: Readonly<Record<string, string | undefined>>): boolean;
|
|
82
133
|
//# sourceMappingURL=apply-mode.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-mode.d.ts","sourceRoot":"","sources":["../../src/core/apply-mode.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"apply-mode.d.ts","sourceRoot":"","sources":["../../src/core/apply-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAEpD,4EAA4E;AAC5E,eAAO,MAAM,oBAAoB,qBAAqB,CAAC;AAEvD,6EAA6E;AAC7E,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,gDAAgD;AAChD,MAAM,WAAW,eAAe;IAC9B;;;;;;;OAOG;IACH,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,eAAe,GAAG,SAAS,CAKnE;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAEvE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,OAAO,GAAG,SAAS,EACzB,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GAChD,OAAO,CAIT"}
|
package/dist/core/apply-mode.js
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
/** Environment variable a postinstall invocation sets to declare itself. */
|
|
2
|
+
export const LISA_POSTINSTALL_ENV = "LISA_POSTINSTALL";
|
|
3
|
+
/** The value {@link LISA_POSTINSTALL_ENV} must hold to count as declared. */
|
|
4
|
+
export const LISA_POSTINSTALL_ENV_VALUE = "1";
|
|
1
5
|
/**
|
|
2
6
|
* Resolves the mode this apply runs in.
|
|
3
7
|
*
|
|
4
8
|
* Every consumer — agent emits, `package.json` protection, and the receipt —
|
|
5
|
-
* MUST read this rather than re-deriving from
|
|
9
|
+
* MUST read this rather than re-deriving from any single flag, so the recorded
|
|
6
10
|
* mode can never describe work the run did not do.
|
|
7
11
|
* @param config - The apply's resolved configuration.
|
|
8
12
|
* @returns `"postinstall-safe"` for the reduced subset, otherwise `"full"`.
|
|
@@ -11,7 +15,7 @@ export function resolveApplyMode(config) {
|
|
|
11
15
|
if (config.fullApply === true) {
|
|
12
16
|
return "full";
|
|
13
17
|
}
|
|
14
|
-
return config.
|
|
18
|
+
return config.postinstall === true ? "postinstall-safe" : "full";
|
|
15
19
|
}
|
|
16
20
|
/**
|
|
17
21
|
* Whether this apply runs the reduced subset.
|
|
@@ -25,4 +29,21 @@ export function resolveApplyMode(config) {
|
|
|
25
29
|
export function isPostinstallSafeApply(config) {
|
|
26
30
|
return resolveApplyMode(config) === "postinstall-safe";
|
|
27
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve the postinstall declaration from the CLI flag and the environment.
|
|
34
|
+
*
|
|
35
|
+
* Two spellings, one meaning. The flag is what Lisa's own spawned invocations
|
|
36
|
+
* pass, because a spawned child's environment is sanitised of package-manager
|
|
37
|
+
* variables and a flag survives that; the environment variable is what the
|
|
38
|
+
* hook text in a consumer's `package.json` carries, because prefixing an
|
|
39
|
+
* assignment leaves the command tail untouched and therefore leaves the
|
|
40
|
+
* recogniser in `ensure-lisa-postinstall` matching both shapes with a single
|
|
41
|
+
* added alternative.
|
|
42
|
+
* @param flag - Value of `--postinstall-safe`, if passed.
|
|
43
|
+
* @param env - Environment to read {@link LISA_POSTINSTALL_ENV} from.
|
|
44
|
+
* @returns True when this apply declared itself a postinstall.
|
|
45
|
+
*/
|
|
46
|
+
export function resolvePostinstallDeclaration(flag, env) {
|
|
47
|
+
return (flag === true || env[LISA_POSTINSTALL_ENV] === LISA_POSTINSTALL_ENV_VALUE);
|
|
48
|
+
}
|
|
28
49
|
//# sourceMappingURL=apply-mode.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-mode.js","sourceRoot":"","sources":["../../src/core/apply-mode.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"apply-mode.js","sourceRoot":"","sources":["../../src/core/apply-mode.ts"],"names":[],"mappings":"AAmEA,4EAA4E;AAC5E,MAAM,CAAC,MAAM,oBAAoB,GAAG,kBAAkB,CAAC;AAEvD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,0BAA0B,GAAG,GAAG,CAAC;AA8B9C;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAuB;IACtD,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;QAC9B,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,OAAO,MAAM,CAAC,WAAW,KAAK,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,MAAM,CAAC;AACnE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,sBAAsB,CAAC,MAAuB;IAC5D,OAAO,gBAAgB,CAAC,MAAM,CAAC,KAAK,kBAAkB,CAAC;AACzD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,6BAA6B,CAC3C,IAAyB,EACzB,GAAiD;IAEjD,OAAO,CACL,IAAI,KAAK,IAAI,IAAI,GAAG,CAAC,oBAAoB,CAAC,KAAK,0BAA0B,CAC1E,CAAC;AACJ,CAAC"}
|
|
@@ -8,7 +8,11 @@ export declare const APPLY_RECEIPT_SCHEMA_VERSION = 1;
|
|
|
8
8
|
/**
|
|
9
9
|
* How complete the recorded apply was.
|
|
10
10
|
*
|
|
11
|
-
* `postinstall-safe` is the
|
|
11
|
+
* `postinstall-safe` is the path a package manager's install runs, selected by
|
|
12
|
+
* the `--postinstall-safe` / `LISA_POSTINSTALL=1` declaration every
|
|
13
|
+
* Lisa-written postinstall invocation carries. (It used to be selected by
|
|
14
|
+
* `--skip-git-check`, which also meant something else entirely — see
|
|
15
|
+
* `core/apply-mode` and CodySwannGT/lisa#3066.) It
|
|
12
16
|
* deliberately skips every agent emit (Codex, Claude, agy, Copilot, OpenCode)
|
|
13
17
|
* and the Sonar integration, because those rewrite host-owned files that must
|
|
14
18
|
* not change under an install. That is the right behaviour and the wrong
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-receipt.d.ts","sourceRoot":"","sources":["../../src/core/apply-receipt.ts"],"names":[],"mappings":"AA2BA,+EAA+E;AAC/E,eAAO,MAAM,0BAA0B,6BAA6B,CAAC;AAErE;;;GAGG;AACH,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C
|
|
1
|
+
{"version":3,"file":"apply-receipt.d.ts","sourceRoot":"","sources":["../../src/core/apply-receipt.ts"],"names":[],"mappings":"AA2BA,+EAA+E;AAC/E,eAAO,MAAM,0BAA0B,6BAA6B,CAAC;AAErE;;;GAGG;AACH,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,kBAAkB,GAAG,SAAS,CAAC;AAEhE,sDAAsD;AACtD,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,6CAA6C;IAC7C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,mCAAmC;IACnC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,+CAA+C;IAC/C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wEAAwE;IACxE,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B;;;;;;;;;;;;;OAaG;IACH,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AA8BD;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5D;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAmB9B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;IACP,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC,EACD,GAAG,GAAE,MAAM,IAAuB,GACjC,OAAO,CAAC,OAAO,CAAC,CAmBlB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apply-receipt.js","sourceRoot":"","sources":["../../src/core/apply-receipt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,+EAA+E;AAC/E,MAAM,CAAC,MAAM,0BAA0B,GAAG,0BAA0B,CAAC;AAErE;;;GAGG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"apply-receipt.js","sourceRoot":"","sources":["../../src/core/apply-receipt.ts"],"names":[],"mappings":"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"}
|