@redue/cli 0.1.0-alpha.3 → 0.1.0-alpha.31
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 +831 -0
- package/README.md +157 -99
- package/bin/redue.mjs +322 -66
- package/docs/README.md +3 -1
- package/docs/user/agents.md +333 -15
- package/docs/user/configuration.md +28 -2
- package/docs/user/direct-typescript.md +219 -0
- package/docs/user/getting-started.md +50 -7
- package/docs/user/json.md +4 -2
- package/docs/user/node-script.md +177 -0
- package/docs/user/npm-launcher-notice.md +42 -0
- package/docs/user/pilot.md +146 -0
- package/docs/user/sandbox.md +326 -0
- package/docs/user/shell.md +3 -3
- package/docs/user/supported-projects.md +69 -23
- package/docs/user/tests-direct.md +143 -0
- package/package.json +4 -3
- package/src/agent-integration.mjs +467 -0
- package/src/agent-policy.md +28 -0
- package/src/cached-state.mjs +24 -1
- package/src/claude-hook.mjs +616 -0
- package/src/cli.mjs +449 -54
- package/src/daemon.mjs +442 -93
- package/src/decision-profile.mjs +15 -1
- package/src/decision-validation.mjs +12 -1
- package/src/declared-plan.mjs +38 -6
- package/src/direct-run-certificate.mjs +254 -0
- package/src/direct-typescript-probe.mjs +27 -0
- package/src/direct-typescript.mjs +205 -0
- package/src/glob.mjs +8 -0
- package/src/history-worker.mjs +21 -13
- package/src/index.mjs +108 -21
- package/src/installed-inputs.mjs +7 -1
- package/src/installed-observation.mjs +23 -0
- package/src/landlock.py +527 -0
- package/src/linux-inotify.py +39 -10
- package/src/node-onboarding.mjs +203 -54
- package/src/node-script.mjs +406 -0
- package/src/npm-integrity.mjs +124 -0
- package/src/npm-typecheck-environment.mjs +36 -0
- package/src/npmrc.mjs +16 -0
- package/src/observation.mjs +34 -12
- package/src/path-identity.mjs +8 -0
- package/src/plan-worker.mjs +17 -17
- package/src/pnpm-inputs.mjs +122 -57
- package/src/pnpm-shim-templates.json +180 -0
- package/src/pnpm-shims.mjs +54 -0
- package/src/pnpm-typecheck-probe.mjs +11 -6
- package/src/presentation.mjs +13 -4
- package/src/probe-deadline.mjs +37 -0
- package/src/probe-result.mjs +7 -3
- package/src/project-location.mjs +34 -0
- package/src/python-onboarding.mjs +89 -0
- package/src/run-recorder.cjs +91 -0
- package/src/sandbox.mjs +659 -0
- package/src/setup.mjs +224 -0
- package/src/stats.mjs +72 -0
- package/src/test-direct.mjs +608 -0
- package/src/test-recorder.cjs +435 -0
- package/src/typescript-contract-probe.mjs +4 -187
- package/src/typescript-input-facts.mjs +92 -0
- package/src/typescript-invocation.mjs +92 -0
- package/src/typescript-list.mjs +118 -13
- package/src/typescript-qualification.mjs +29 -49
- package/src/workspace-manifests.mjs +24 -0
- package/src/yarn-workspace-inputs.mjs +3 -0
- package/src/yarn-workspace-typecheck-probe.mjs +2 -1
|
@@ -0,0 +1,326 @@
|
|
|
1
|
+
# Sandboxed recipe (typecheck, lint and tests, any language)
|
|
2
|
+
|
|
3
|
+
The sandboxed recipe runs a typecheck, lint or test command inside an operating
|
|
4
|
+
system sandbox and reports later whether that result still applies to the
|
|
5
|
+
files you have. The sandbox holds for every process the command starts, so it
|
|
6
|
+
covers programs REDUE cannot record: TypeScript 7's native compiler, esbuild,
|
|
7
|
+
oxlint and tsgolint, biome, turbo, and Python tools such as mypy, pyright, ty
|
|
8
|
+
and ruff, and test runners such as pytest.
|
|
9
|
+
|
|
10
|
+
**The claim.** A sandboxed result holds for a run that sees only the project's
|
|
11
|
+
files that git doesn't ignore, except its documentation, its installed
|
|
12
|
+
packages and the toolchain, the way CI does. It does not say that a run with
|
|
13
|
+
your own configuration files, a service on your machine or the network would
|
|
14
|
+
give the same result.
|
|
15
|
+
|
|
16
|
+
A check that reads the documentation (a doctest over `README.md`) sees it
|
|
17
|
+
too. A check that needs files git ignores (generated code, another package's
|
|
18
|
+
built declarations) gets the whole checkout. See
|
|
19
|
+
[hidden files](#files-git-ignores-and-documentation).
|
|
20
|
+
|
|
21
|
+
## Where it applies
|
|
22
|
+
|
|
23
|
+
- **Tests:** a root `test` script, and pytest in the project's `.venv`. See
|
|
24
|
+
[tests](#tests). For a Node test script, `init` tries the sandbox before the
|
|
25
|
+
[direct test recipe](tests-direct.md), which becomes the fallback, when
|
|
26
|
+
both would run the same script. In the
|
|
27
|
+
census, on the repos where both qualified, the direct recipe's results went
|
|
28
|
+
STALE when the project's build rewrote its output, and the sandboxed ones,
|
|
29
|
+
with ignored files hidden, stayed CURRENT.
|
|
30
|
+
- **Node projects:** a root `typecheck` or `lint` script (npm, pnpm, or Yarn
|
|
31
|
+
with the `node-modules` linker). `init` tries the
|
|
32
|
+
[direct TypeScript recipe](direct-typescript.md) and the pnpm and Yarn
|
|
33
|
+
TypeScript recipes first; they stay first where they apply. Then the
|
|
34
|
+
sandboxed recipe, before the [general recipe](node-script.md), since it
|
|
35
|
+
also covers the native programs a script starts. Where init's trials show
|
|
36
|
+
a difference, or the sandbox cannot run, `init` writes the general recipe
|
|
37
|
+
as before. Where the sandbox cannot start at run time (inside Claude Code's
|
|
38
|
+
macOS sandbox), a script the general recipe takes is recorded as it records
|
|
39
|
+
it.
|
|
40
|
+
- **Python projects:** mypy, pyright, ty and ruff installed in the project's
|
|
41
|
+
`.venv` (`uv sync` makes one; Poetry does with `virtualenvs.in-project`).
|
|
42
|
+
`init` uses the arguments your CI workflow, Makefile, tox, nox, justfile or
|
|
43
|
+
shell scripts in `scripts/` run the tool with, through `uv run`, `poetry run`,
|
|
44
|
+
`python -m` or `.venv/bin`. Without them it uses the tool's default:
|
|
45
|
+
`ruff check`, `ty check`, `pyright`, and `mypy` (with `.` when mypy's
|
|
46
|
+
configuration names no `files`).
|
|
47
|
+
- **Platforms:** macOS (Seatbelt, `sandbox-exec`) and Linux 6.7 or later
|
|
48
|
+
(Landlock; the launcher needs Python 3).
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
redue init
|
|
52
|
+
redue start
|
|
53
|
+
redue run typecheck
|
|
54
|
+
redue status --sync
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
A Python check in the config:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{"name": "typecheck", "kind": "typecheck", "qualification": "sandbox-v3",
|
|
61
|
+
"command": [".venv/bin/mypy", "src"], "inputs": ["**", "..."], "installedInputs": [".venv/**", "..."]}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
A Node check names its script, as the general recipe's do:
|
|
65
|
+
`{"name": "lint", "script": "lint", "kind": "lint", "qualification": "sandbox-v3", ...}`.
|
|
66
|
+
`sandbox-v3` hides the files git ignores and the documentation from the run,
|
|
67
|
+
`sandbox-v2` only the files git ignores; `sandbox-v1` runs it on the whole
|
|
68
|
+
checkout.
|
|
69
|
+
|
|
70
|
+
With the Claude Code hook, `uv run mypy src`, `poetry run mypy src`,
|
|
71
|
+
`python -m mypy src`, `.venv/bin/mypy src` and `mypy src` are recognized as
|
|
72
|
+
that check. The last two count only when PATH finds the tool or Python in the
|
|
73
|
+
project's `.venv/bin` first. When the hook runs the check through REDUE, it
|
|
74
|
+
keeps `uv run` or `poetry run` in front, so the environment still syncs first.
|
|
75
|
+
|
|
76
|
+
## Files git ignores and documentation
|
|
77
|
+
|
|
78
|
+
`init` runs each check plainly, then sandboxed with the files git ignores and
|
|
79
|
+
the documentation hidden. When both give the same result, it writes
|
|
80
|
+
`sandbox-v3`. When the plain run passed and the sandboxed one failed only
|
|
81
|
+
because it was refused a file it hid (no other refusal line, and not a line
|
|
82
|
+
the plain run printed too), it writes `sandbox-v1` (the whole checkout)
|
|
83
|
+
without running it again: without the hiding, a run can then only fail
|
|
84
|
+
where a plain one passes, never pass where it fails. When the runs differ
|
|
85
|
+
in another way, `init` runs the check once more with the whole checkout,
|
|
86
|
+
reusing the plain run, and writes `sandbox-v1` only if that agrees. So a
|
|
87
|
+
check runs two or three times at init, not four. `init` no longer writes
|
|
88
|
+
`sandbox-v2`; a check already set up with it keeps it.
|
|
89
|
+
|
|
90
|
+
Each trial run stops after 5 minutes. A run that stops there never counts as
|
|
91
|
+
agreeing: when the plain run reaches the limit, `init` runs nothing in the
|
|
92
|
+
sandbox and writes the fallback; when a sandboxed run reaches it, no further
|
|
93
|
+
trial follows. `init` marks such a check (`time_limit` in `--json` gives
|
|
94
|
+
its kind), and `redue setup` names them and prints one command:
|
|
95
|
+
`redue init --check typecheck --no-time-limit` (or `redue init
|
|
96
|
+
--no-time-limit` for several kinds). With an existing config, that command
|
|
97
|
+
runs with no limit the checks the config has and does not run in the
|
|
98
|
+
sandbox, and a check it lacks when `--check` names its kind. It replaces
|
|
99
|
+
the row of each that qualifies, if the row runs the same script, or adds
|
|
100
|
+
it, and leaves the rest of the config as it was. It restarts a running
|
|
101
|
+
observer with the new config, and `redue remove` still deletes a config
|
|
102
|
+
`setup` created.
|
|
103
|
+
|
|
104
|
+
With `sandbox-v3`, each run also hides the documentation: the files git
|
|
105
|
+
lists (and does not ignore) named `*.md`, `*.mdx`, `*.rst`, `LICENSE*` or
|
|
106
|
+
`CHANGELOG*` anywhere, and text, image and PDF files (`.txt`, `.adoc`,
|
|
107
|
+
`.png`, `.jpg`, `.jpeg`, `.gif`, `.svg`, `.webp`, `.pdf`) in the root `docs/`
|
|
108
|
+
folder. Code in `docs/` (examples a typecheck includes) is not hidden, and
|
|
109
|
+
folders stay listable. The receipt names the files the run hid. A later edit
|
|
110
|
+
to one of them, or its deletion, leaves the result CURRENT: editing the
|
|
111
|
+
README does not make the tests STALE. A new documentation file, a link named
|
|
112
|
+
like one, or a change made while the run ran still counts. On macOS the
|
|
113
|
+
files with those extensions are refused by name pattern, in any case and in
|
|
114
|
+
`node_modules` too: `README.MD` or `Docs/logo.svg` is refused but not
|
|
115
|
+
listed, so an edit to it counts, and a check that reads one gets
|
|
116
|
+
`sandbox-v1` on macOS. `LICENSE*` and `CHANGELOG*` files are refused by the
|
|
117
|
+
exact paths git lists, so `license-check.ts` stays readable. On Linux each
|
|
118
|
+
listed file is hidden like a git-ignored one. In a checkout with more than
|
|
119
|
+
100 `LICENSE*` and `CHANGELOG*` files (vendored packages), those files are
|
|
120
|
+
not hidden on either platform and count as inputs.
|
|
121
|
+
|
|
122
|
+
With `sandbox-v2`, each run hides what `git ls-files --others --ignored
|
|
123
|
+
--exclude-standard --directory` lists, except `node_modules`, `.venv` and
|
|
124
|
+
runner caches: build output (`dist/`, `.next/`), coverage files, `.env` files.
|
|
125
|
+
Only the project's rules count: its `.gitignore` files and
|
|
126
|
+
`.git/info/exclude`, not your global excludes file. Those files are not
|
|
127
|
+
inputs, so a build or test run that writes them leaves the result CURRENT.
|
|
128
|
+
|
|
129
|
+
When a `sandbox-v2` or `sandbox-v3` run fails with a refusal that names a
|
|
130
|
+
hidden file (a missing file counts only when it names one, since Linux tools
|
|
131
|
+
report an unreadable file as missing), REDUE runs the check again in the
|
|
132
|
+
sandbox without hiding anything. That result is kept and compared on every
|
|
133
|
+
file, git-ignored ones and documentation included. Run `redue init` again to
|
|
134
|
+
write another recipe for a check that keeps needing them.
|
|
135
|
+
|
|
136
|
+
## What the run sees
|
|
137
|
+
|
|
138
|
+
It may read and execute only beneath:
|
|
139
|
+
|
|
140
|
+
- the checkout, without the files git ignores for `sandbox-v2`, and without
|
|
141
|
+
its documentation too for `sandbox-v3`;
|
|
142
|
+
- the toolchain: Node's installation and the package managers' (with
|
|
143
|
+
Corepack's downloads), or the Python installation the `.venv` was made from;
|
|
144
|
+
- system directories (`/usr`, `/bin`, `/etc` and the like on Linux; `/usr`,
|
|
145
|
+
`/System`, `/Library`, `/opt/homebrew` and the like on macOS);
|
|
146
|
+
- a private home directory and a fresh temporary directory, in REDUE's state.
|
|
147
|
+
|
|
148
|
+
A typecheck or lint has no network: no TCP connection, loopback included
|
|
149
|
+
(a test run on Linux gets loopback; see [tests](#tests)). On macOS its only
|
|
150
|
+
Unix sockets are in its own temporary directory, which is new for each run.
|
|
151
|
+
On Linux 6.12 and later it cannot reach an abstract Unix socket outside the
|
|
152
|
+
run.
|
|
153
|
+
|
|
154
|
+
What the check leaves running is stopped when it exits, as at the end of a
|
|
155
|
+
CI job: its process group gets SIGTERM, and SIGKILL a second later. On Linux
|
|
156
|
+
the launcher also stops daemons that started their own session. On macOS
|
|
157
|
+
such a daemon outlives the run, but no later run can reach it: its socket
|
|
158
|
+
was in a temporary directory that is gone. The run gets no terminal input.
|
|
159
|
+
|
|
160
|
+
The checkout's `.git` is not an input. Tools still see it, as they do in a CI
|
|
161
|
+
checkout (a linter that applies `.gitignore` only inside a repository does),
|
|
162
|
+
but git commands find no repository: `GIT_DIR` points nowhere. A script that
|
|
163
|
+
runs git (`git diff --exit-code`) gives a different result inside the
|
|
164
|
+
sandbox, and `init` leaves it to the other recipes.
|
|
165
|
+
|
|
166
|
+
It gets a controlled environment, not yours:
|
|
167
|
+
|
|
168
|
+
- the variables the check declares (`TZ`, `LANG`, `CI`, `USER`, `LC_*`,
|
|
169
|
+
`DYLD_*`, `LD_*`, and `NODE_*`, `npm_config_*`, `PNPM_*`, `YARN_*`,
|
|
170
|
+
`COREPACK_*` for Node, or `PYTHON*`, `MYPY*`, `RUFF_*`, `PYRIGHT*`, `TY_*`
|
|
171
|
+
for Python), with your values;
|
|
172
|
+
- your PATH, without the project's `.venv/bin`, which a Python check gets
|
|
173
|
+
first instead, so `uv run` and an activated environment give the same PATH;
|
|
174
|
+
- `HOME`, `TMPDIR` and the XDG directories in its private directories;
|
|
175
|
+
`VIRTUAL_ENV` for a Python check; Corepack's home where Corepack keeps it.
|
|
176
|
+
|
|
177
|
+
## Tests
|
|
178
|
+
|
|
179
|
+
A test run gets what a typecheck or lint gets, and also:
|
|
180
|
+
|
|
181
|
+
- **On Linux, loopback, and no remote host.** It may listen on any address
|
|
182
|
+
and accept connections, and connect only to the local host (`127.0.0.0/8`,
|
|
183
|
+
`::1`, `0.0.0.0`, `::`) and Unix sockets.
|
|
184
|
+
- Landlock cannot tell a loopback address from a remote one, so a
|
|
185
|
+
seccomp filter in the test's processes does instead. It refuses sockets
|
|
186
|
+
other than Unix, netlink and TCP when they are created (UDP included),
|
|
187
|
+
TCP Fast Open (`MSG_FASTOPEN`) and `io_uring`. It hands each `connect` to
|
|
188
|
+
REDUE's launcher. The launcher allows a local port no process listens on
|
|
189
|
+
(the test gets "connection refused") or one the run's own processes
|
|
190
|
+
listen on, and a Unix socket file in the checkout, the run's home or its
|
|
191
|
+
temporary directory. It refuses a service started outside the run (your
|
|
192
|
+
local database) and every remote host. Nothing else goes through the
|
|
193
|
+
launcher, so worker processes talk to each other as usual. If the
|
|
194
|
+
launcher's supervisor cannot start, or stops before the run ends, the
|
|
195
|
+
result is UNVERIFIED, never CURRENT.
|
|
196
|
+
- **On macOS, no network.** No TCP or UDP, loopback included: only Unix
|
|
197
|
+
sockets in its own temporary directory (its home is beneath it), as a
|
|
198
|
+
typecheck or lint gets. Seatbelt cannot refuse a service started outside
|
|
199
|
+
the run while allowing the run's own servers: a rule that refuses one
|
|
200
|
+
loopback port under a loopback allow is not applied, and an allow list of
|
|
201
|
+
every other port does not compile. A suite that starts a server on
|
|
202
|
+
loopback, or reads a local database, fails init's trial: init leaves the
|
|
203
|
+
test check out, and the tests run without REDUE, as before. A test check
|
|
204
|
+
set up by alpha.28 on macOS is not CURRENT after the upgrade; if its runs
|
|
205
|
+
now fail inside the sandbox, run `redue init` again.
|
|
206
|
+
- **A fresh home.** Its home directory is new and empty for each run, as on
|
|
207
|
+
CI: what a test leaves there is not observed, so it must not reach a later
|
|
208
|
+
run.
|
|
209
|
+
- **A private `/tmp`.** Its `TMPDIR` is its own, new for each run, and it may
|
|
210
|
+
not write in `/tmp` or `/var/tmp` outside it. A test that writes to a fixed
|
|
211
|
+
path there is refused.
|
|
212
|
+
|
|
213
|
+
`init` compares a test run's exit status and the counts its summary prints
|
|
214
|
+
(passed, failed, skipped), not every line: test runners print in the order
|
|
215
|
+
their workers finish. Git-ignored files are hidden from a test run when the
|
|
216
|
+
trial agrees, as for typecheck and lint. A suite that reads back git-ignored
|
|
217
|
+
files it writes in the same run (a coverage database, a build it starts
|
|
218
|
+
itself) gets the whole checkout. Files a hidden run writes beneath hidden
|
|
219
|
+
folders, or new files git ignores, are not changes to its inputs.
|
|
220
|
+
|
|
221
|
+
## What REDUE claims
|
|
222
|
+
|
|
223
|
+
CURRENT means the last sandboxed run's inputs are unchanged:
|
|
224
|
+
|
|
225
|
+
- every file in the checkout git doesn't ignore but its documentation
|
|
226
|
+
(`sandbox-v3`), every file git doesn't ignore (`sandbox-v2`), or every file
|
|
227
|
+
in it, git-ignored files and git-ignored links to files in it included
|
|
228
|
+
(`sandbox-v1`), except `.git` and runner caches (the general recipe's, plus
|
|
229
|
+
`__pycache__`, `.mypy_cache`, `.ruff_cache` and `.pytest_cache`);
|
|
230
|
+
- `node_modules` and `.venv`, observed as installed files, by identity;
|
|
231
|
+
- the environment the run gets (without display variables such as `TERM`
|
|
232
|
+
and `COLUMNS`), and the places it may read;
|
|
233
|
+
- Node's and the package managers' executables, or the interpreter the
|
|
234
|
+
`.venv` was made from, by file identity;
|
|
235
|
+
- every directory on PATH, by identity: installing, removing or upgrading a
|
|
236
|
+
program in one makes the result STALE;
|
|
237
|
+
- `.git/info/exclude` and `.git/config`, by content: ruff and biome read the
|
|
238
|
+
ignore rules there, and they decide what `sandbox-v2` hides. For a project
|
|
239
|
+
in a subdirectory of its repository, also the `.gitignore` files above it.
|
|
240
|
+
|
|
241
|
+
## Telling a refusal from a real failure
|
|
242
|
+
|
|
243
|
+
A run the sandbox refused something fails like any other. REDUE does not run
|
|
244
|
+
every failure twice to find out:
|
|
245
|
+
|
|
246
|
+
- `init` runs each proposed check plainly and sandboxed, and proposes it
|
|
247
|
+
when both give the same exit status and the same output, and a failure
|
|
248
|
+
shows no sign of a refusal. The output is compared without colors,
|
|
249
|
+
timings, the temporary and home directories, and lines about caches. The
|
|
250
|
+
one exception is a check that passed plainly and failed only because it
|
|
251
|
+
was refused a hidden file: it gets the whole checkout without another run
|
|
252
|
+
(see [files git ignores](#files-git-ignores-and-documentation)).
|
|
253
|
+
Otherwise `init` writes what it would have without this recipe and says why.
|
|
254
|
+
These are the only runs `init` makes.
|
|
255
|
+
- When a `sandbox-v2` or `sandbox-v3` run fails with a refusal that names a hidden file, it
|
|
256
|
+
runs again in the sandbox without hiding (see
|
|
257
|
+
[files git ignores](#files-git-ignores-and-documentation)).
|
|
258
|
+
- When a sandboxed run fails and its output has a line that looks like a
|
|
259
|
+
refusal ("Operation not permitted", "Permission denied", "Read-only file
|
|
260
|
+
system", a name lookup or a connection that failed), REDUE runs the check
|
|
261
|
+
again outside the sandbox. If that exits differently, the result is the
|
|
262
|
+
plain run's and UNVERIFIED: "the sandbox changed the result", with the
|
|
263
|
+
line. A failure without such a line is not run again.
|
|
264
|
+
|
|
265
|
+
## The private home
|
|
266
|
+
|
|
267
|
+
A typecheck or lint's home directory is kept between runs, per check, so caches tools
|
|
268
|
+
build there (font caches, a type checker's cache) are not rebuilt every run.
|
|
269
|
+
It starts empty: your configuration files are not in it. What a run leaves
|
|
270
|
+
there can change a later run, and REDUE trusts it like a runner cache. Remove
|
|
271
|
+
it with `redue remove-state`.
|
|
272
|
+
|
|
273
|
+
## Limits
|
|
274
|
+
|
|
275
|
+
- Inside Claude Code's own sandbox on macOS, `sandbox-exec` cannot start: the
|
|
276
|
+
run goes ahead unsandboxed and is UNVERIFIED ("the run was not sandboxed").
|
|
277
|
+
On Linux, Landlock works inside it.
|
|
278
|
+
- Windows is not supported. The check stays recording-only there.
|
|
279
|
+
- Linux before 6.7 (Landlock ABI below 4) cannot refuse TCP connections, so a
|
|
280
|
+
run there is UNVERIFIED. UDP is not refused on Linux.
|
|
281
|
+
- System files (time zones, certificates, `/etc`) are not inputs: a change to
|
|
282
|
+
them does not make a result STALE.
|
|
283
|
+
- A program that reads files in `.git` itself, without git (a commit hash for
|
|
284
|
+
a version string), reads something REDUE does not observe: a commit does
|
|
285
|
+
not make the result STALE.
|
|
286
|
+
- Runner caches in the checkout are trusted as the general recipe trusts them.
|
|
287
|
+
- On Linux, a run can still reach a daemon started outside it through a Unix
|
|
288
|
+
socket file (Landlock does not cover them), and what that daemon reads is
|
|
289
|
+
not seen. On macOS it cannot.
|
|
290
|
+
- On Linux, uv hard-links `.venv` files to its cache. The cache is
|
|
291
|
+
toolchain: a file rewritten through the cache, not through the `.venv`, is
|
|
292
|
+
noticed only when the observer next reads the `.venv` (when it starts).
|
|
293
|
+
- A `.venv` link that leads out of the checkout, other than the interpreter's,
|
|
294
|
+
keeps the check recording-only and names the link, and so does a `.venv`
|
|
295
|
+
that uses the system site-packages.
|
|
296
|
+
- A git-ignored link to a directory, or out of the checkout, is not observed,
|
|
297
|
+
and neither is a `node_modules` directory outside the installed ones (a
|
|
298
|
+
nested example project's).
|
|
299
|
+
- A script that changes files (`--fix`, `--write`) does not get this recipe:
|
|
300
|
+
`init` would run it twice.
|
|
301
|
+
- With `sandbox-v2` or `sandbox-v3`, a run cannot read a hidden file, but it can still see
|
|
302
|
+
that one exists, its size and its times, and write beneath it. On Linux it
|
|
303
|
+
can also list a hidden folder; on macOS it cannot. A tool that acts on
|
|
304
|
+
whether a git-ignored file exists, without reading it, is not covered: a
|
|
305
|
+
new or removed one does not make the result STALE. In a census of 136
|
|
306
|
+
test suites with ignored files after their build, none did.
|
|
307
|
+
- On Linux, a test run's UDP is refused, loopback included: the filter
|
|
308
|
+
decides when the socket is made, before its address is known. A test that
|
|
309
|
+
needs it fails its trial and keeps another recipe.
|
|
310
|
+
- On Linux, the launcher decides a `connect` from the address it reads in
|
|
311
|
+
the process's memory, and the kernel reads it again after. A process that
|
|
312
|
+
changes the address in between, from another thread, could reach another
|
|
313
|
+
host. Honest test code does not.
|
|
314
|
+
- On Linux, a typecheck or lint can still connect to a Unix socket file
|
|
315
|
+
outside it (a local database's).
|
|
316
|
+
- On Linux, a file a `sandbox-v2` or `sandbox-v3` run creates in a folder that holds hidden
|
|
317
|
+
files (the checkout's root, when anything in it is hidden; with `sandbox-v3`,
|
|
318
|
+
any folder with a README) cannot be read
|
|
319
|
+
back in the same run. `init`'s trial and the rerun without hiding catch a
|
|
320
|
+
check that needs to.
|
|
321
|
+
- A file whose git status changes without a change to its content (`git add
|
|
322
|
+
-f` of an ignored file, `git rm --cached` of a tracked one) is noticed only
|
|
323
|
+
when its content next changes. A change to `.gitignore` or
|
|
324
|
+
`.git/info/exclude` makes the result STALE.
|
|
325
|
+
- A run that moves a hidden folder into a visible place can read it there.
|
|
326
|
+
That changes the checkout during the run, so the run is not reused.
|
package/docs/user/shell.md
CHANGED
|
@@ -11,9 +11,9 @@ REDUE UNVERIFIED
|
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
It reads the cached snapshot, checks its expiry and observer liveness, and never
|
|
14
|
-
synchronizes, traverses installed packages, or runs probes/checks. Like
|
|
15
|
-
status
|
|
16
|
-
need a synchronized read. Do not turn that uncertainty into a green badge.
|
|
14
|
+
synchronizes, traverses installed packages, or runs probes/checks. Like
|
|
15
|
+
`status --cached`, it can remain conservative when caller context or installed
|
|
16
|
+
hardlinks need a synchronized read. Do not turn that uncertainty into a green badge.
|
|
17
17
|
|
|
18
18
|
For an existing async/bounded prompt framework, use `redue status --short` from
|
|
19
19
|
the project root as the segment command and display unavailable on errors or
|
|
@@ -12,18 +12,37 @@ is known. When npm is not pinned in `package.json`,
|
|
|
12
12
|
leaves the version unknown rather than guessing if that inspection fails.
|
|
13
13
|
|
|
14
14
|
At the repository root, `init` looks for existing typecheck, test, lint, and
|
|
15
|
-
build scripts. It prefers familiar script names
|
|
15
|
+
build scripts. It prefers familiar script names (for typecheck: `typecheck`,
|
|
16
|
+
`type-check`, `check-types`, `check:types`, `types:check`, `tsc`, `types`,
|
|
17
|
+
`lint:types`), then for typecheck one script named under such a name
|
|
18
|
+
(`typecheck:test`, `tsc:build`; not a watch script), then unique recognizable
|
|
16
19
|
`tsc`, Vitest/Jest, ESLint, or Vite commands under other names. Multiple
|
|
17
20
|
matches are reported as ambiguous rather than guessed. It never creates a new
|
|
18
|
-
project script.
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
21
|
+
project script. Without `--recipe`, `init` tries the strict recipes below first, then,
|
|
22
|
+
for a root typecheck, lint or test script, the [sandboxed recipe](sandbox.md) on
|
|
23
|
+
macOS and Linux (the script run inside an OS sandbox, with the files git
|
|
24
|
+
ignores and the documentation hidden when it gives the same result that way,
|
|
25
|
+
else with only the files git ignores hidden, else on the whole checkout; a
|
|
26
|
+
test run also gets a private `/tmp`, and loopback-only network on Linux or no
|
|
27
|
+
network on macOS),
|
|
28
|
+
then, for typecheck and lint, the [general recipe](node-script.md): the script run
|
|
29
|
+
through the package manager with every Node process recorded and the whole
|
|
30
|
+
checkout as its input. Python projects get the sandboxed recipe for mypy,
|
|
31
|
+
pyright, ty, ruff and pytest in their `.venv`. `--recipe typescript-direct`,
|
|
32
|
+
`tests-direct`, `node-script` or `sandbox` selects one recipe alone. The direct TypeScript recipe supports
|
|
33
|
+
a typecheck script of `tsc --noEmit` runs in any argument order, chained runs,
|
|
34
|
+
or no typecheck script at all (a proposed `tsc --noEmit`; see
|
|
35
|
+
[script forms](direct-typescript.md#script-forms)), in a single-package npm installation using
|
|
36
|
+
TypeScript 5.x or 6.0 (a reviewed release, or one whose installed files match the
|
|
37
|
+
tarball package-lock.json names in npm's cache; see
|
|
38
|
+
[compiler identity](direct-typescript.md#compiler-identity)) and Node 22/24. It executes the local compiler,
|
|
39
|
+
not npm. Full installed compiler identity, config/membership, installed inputs
|
|
40
|
+
and relevant Node environment are checked before reuse. See the
|
|
41
|
+
[exact direct boundary](direct-typescript.md). Unsupported plugins, preloads,
|
|
42
|
+
configuration or outside-root inputs remain UNVERIFIED. Root and package-level npm/Yarn workspace scripts are discovered from
|
|
43
|
+
`package.json` workspace declarations. In a workspace of more than 50
|
|
44
|
+
packages, `init` proposes the root's checks only and names what it skipped;
|
|
45
|
+
add package checks to the config yourself. Up to 1000 packages are read. Pinned Yarn 4 `node-modules`/classic
|
|
27
46
|
workspaces with a standalone `tsc -p .` script, local TypeScript, a conventional
|
|
28
47
|
`src` include, and Node module resolution can qualify automatically. For one
|
|
29
48
|
workspace, use `redue init --workspace NAME --check typecheck`; it writes only
|
|
@@ -36,21 +55,48 @@ When an internal dependency is consumed through built declarations, changing
|
|
|
36
55
|
only its source does not stale the selected check until the consumed output
|
|
37
56
|
changes. Unsupported custom resolution, project references, outside-root
|
|
38
57
|
source links, and installation modes remain recording-only. Other Yarn
|
|
39
|
-
typechecks, Vitest/Jest, ESLint, and builds
|
|
40
|
-
separately justified explicit contract is provided.
|
|
58
|
+
typechecks, Vitest/Jest, ESLint, and builds in workspace packages start
|
|
59
|
+
recording-only unless a separately justified explicit contract is provided.
|
|
60
|
+
A root test script gets the sandboxed recipe when its trial gives the same
|
|
61
|
+
exit status and test counts as a plain run. Otherwise, for a single-package
|
|
62
|
+
project whose test script runs Vitest 4/5 or Jest 29 directly, `init` uses the
|
|
63
|
+
direct test recipe, which records the run and guards its inputs; see
|
|
64
|
+
[direct tests](tests-direct.md).
|
|
41
65
|
In particular, test caches and build-generated inputs are not excluded to
|
|
42
66
|
make evidence green.
|
|
43
67
|
|
|
44
|
-
|
|
45
|
-
the lockfile, and the installed `node_modules/.modules.yaml`
|
|
68
|
+
pnpm 9-12 projects are read from `packageManager`, `pnpm-workspace.yaml`,
|
|
69
|
+
`.npmrc`, the lockfile, and the installed `node_modules/.modules.yaml`
|
|
70
|
+
metadata. The installed metadata names the pnpm version; a `packageManager`
|
|
71
|
+
pin is optional, and when present (with or without Corepack's `+sha512` hash)
|
|
72
|
+
it must name the installed version. Settings that only change what gets
|
|
73
|
+
installed are accepted, because the installed files are what REDUE observes.
|
|
74
|
+
Settings that move or copy installed files, or run code during install, are
|
|
75
|
+
not: custom `modulesDir`, `virtualStoreDir` or `lockfileDir`, the global
|
|
76
|
+
virtual store, injected workspace packages, separate workspace lockfiles,
|
|
77
|
+
pnpmfile hooks and `configDependencies`. They are refused when either
|
|
78
|
+
`pnpm-workspace.yaml` or `.npmrc` sets them. The linker is read from the file
|
|
79
|
+
the installed major reads (`.npmrc` for pnpm 9, `pnpm-workspace.yaml` then
|
|
80
|
+
`.npmrc` for pnpm 10, `pnpm-workspace.yaml` for pnpm 11 and 12) and must match
|
|
81
|
+
the installed one. Only the project's files are read: settings from a user or
|
|
82
|
+
global rc file, or `npm_config_*` variables during install, are not. The
|
|
46
83
|
supported local layouts are pnpm's standard isolated and hoisted
|
|
47
84
|
`node_modules` with a project-local `.pnpm` virtual store. `init` can discover
|
|
48
|
-
root and workspace scripts. For a
|
|
49
|
-
script
|
|
50
|
-
|
|
85
|
+
root and workspace scripts. For a typecheck script of `tsc` runs
|
|
86
|
+
([script forms](direct-typescript.md#script-forms); `tsc -p .` without
|
|
87
|
+
`--noEmit` is also accepted), or a package with a `tsconfig.json` and no
|
|
88
|
+
typecheck script, it records the exact installed compiler invocation directly.
|
|
89
|
+
The source inputs are the directories the config's `include` covers, as
|
|
90
|
+
TypeScript itself computes them for new files, minus `node_modules` (`exclude`
|
|
91
|
+
entries stay inputs: an import can still reach an excluded file); a file the
|
|
92
|
+
program reads outside them keeps the check recording-only. This avoids pnpm's task-run bookkeeping
|
|
51
93
|
writes during `pnpm run`; it does not alter the project's script. Test, lint,
|
|
52
|
-
build, and ambiguous TypeScript scripts still execute through `pnpm run
|
|
53
|
-
|
|
94
|
+
build, and ambiguous TypeScript scripts still execute through `pnpm run`; root
|
|
95
|
+
typecheck and lint ones can use the [general recipe](node-script.md). The pnpm
|
|
96
|
+
and Yarn TypeScript recipes read TypeScript's compiler API, which TypeScript 7
|
|
97
|
+
does not ship: with TypeScript 7 installed they refuse and say so. The
|
|
98
|
+
general recipe runs such a script, but TypeScript 7's native compiler is a
|
|
99
|
+
program REDUE does not record, so the result is UNVERIFIED. The generated `@typescript-bin:WORKSPACE` token resolves
|
|
54
100
|
the local compiler when the check runs; it is not an absolute machine path.
|
|
55
101
|
|
|
56
102
|
The pnpm contract indexes consumed installed package contents inside the
|
|
@@ -61,10 +107,10 @@ global virtual stores, injected workspace dependencies, and external links
|
|
|
61
107
|
without an observed boundary remain recording-only with a reason. Installed
|
|
62
108
|
files with hard-linked aliases outside the checkout remain recording-only on
|
|
63
109
|
macOS: writes through an unseen alias cannot support CURRENT there. On Linux,
|
|
64
|
-
redue watches project-installed file inodes and
|
|
65
|
-
installed inputs on every synchronized read. A cached read remains UNVERIFIED
|
|
66
|
-
for these pnpm checks; a synchronized read can establish CURRENT after
|
|
67
|
-
|
|
110
|
+
redue watches project-installed file inodes and re-reads the identity of the
|
|
111
|
+
selected installed inputs on every synchronized read. A cached read remains UNVERIFIED
|
|
112
|
+
for these pnpm checks; a synchronized read can establish CURRENT after that
|
|
113
|
+
re-read. If an inode watch cannot be installed, observation becomes unavailable
|
|
68
114
|
instead of dropping that file. The global store is not watched. An absent
|
|
69
115
|
optional package remains unqualified when Node could later
|
|
70
116
|
resolve it from an unobserved ancestor `node_modules`; project-local candidate
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Direct test recipe (Vitest and Jest)
|
|
2
|
+
|
|
3
|
+
`redue init --recipe tests-direct --check test` (or `redue init`, where the
|
|
4
|
+
[sandboxed recipe](sandbox.md) cannot take the test script) records a project's unit test run and reports later whether that result
|
|
5
|
+
still applies to the files you have.
|
|
6
|
+
It supports a single-package project installed by npm, pnpm 9-12 (isolated or
|
|
7
|
+
hoisted `node_modules`) or Yarn with the `node-modules` linker, whose test
|
|
8
|
+
script runs Vitest 4 or 5, or Jest 29, directly. It runs on macOS and Linux with
|
|
9
|
+
Node 22 or 24. The project has one lockfile kind, matching any
|
|
10
|
+
`packageManager` declaration; Yarn needs that declaration. With pnpm, the
|
|
11
|
+
runner is the package `node_modules/RUNNER` links to, inside the checkout.
|
|
12
|
+
Jest also needs jest-util 29 at `node_modules/jest-util`, which pnpm does not
|
|
13
|
+
place there unless it hoists.
|
|
14
|
+
|
|
15
|
+
In a workspace (npm or Yarn `workspaces`, or `packages` in
|
|
16
|
+
`pnpm-workspace.yaml`), `init` gives each package whose test script runs
|
|
17
|
+
Vitest directly its own check, `PACKAGE:test`, run in the package's directory
|
|
18
|
+
with the Vitest that Node finds from there. Its inputs are still the whole
|
|
19
|
+
checkout, so an edit in any package makes it STALE. The root's and every
|
|
20
|
+
package's `node_modules` are observed as installed files, without Vite's
|
|
21
|
+
caches in them. Jest is not supported in workspace packages, and neither is a
|
|
22
|
+
test script at the workspace root. A package added later needs `init` again:
|
|
23
|
+
its manifest appearing makes the workspace's checks UNVERIFIED until then.
|
|
24
|
+
|
|
25
|
+
## Setup
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
redue init --recipe tests-direct --check test
|
|
29
|
+
redue start
|
|
30
|
+
redue run test
|
|
31
|
+
redue status --sync
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`init` picks the `test`, `test:unit` or `test:check` script when it runs a
|
|
35
|
+
runner directly, otherwise the only script that does. The script must be one
|
|
36
|
+
runner invocation: no `&&`, quotes, globs or variable assignments. Watch mode,
|
|
37
|
+
`--changed`, `related`, snapshot updates (`-u`), shuffling, sharding and
|
|
38
|
+
Jest's `--onlyChanged` are refused. Vitest needs `run`, `--run` or
|
|
39
|
+
`--watch=false`. Other test scripts stay recording-only: the
|
|
40
|
+
[general recipe](node-script.md) covers typecheck and lint scripts, not tests.
|
|
41
|
+
|
|
42
|
+
REDUE runs the local runner with Node directly. The package manager, its
|
|
43
|
+
lifecycle scripts and `package.json` are not changed or executed.
|
|
44
|
+
|
|
45
|
+
## What REDUE claims
|
|
46
|
+
|
|
47
|
+
CURRENT means the last run's inputs are unchanged: every file in the checkout
|
|
48
|
+
outside `node_modules`, the installed files in `node_modules`, the Node binary,
|
|
49
|
+
the exact command, and the environment. Every environment variable the run's
|
|
50
|
+
JavaScript read directly must have the same value, or still be unset. Node and
|
|
51
|
+
libc read some variables natively, and Vite lists the environment for its own,
|
|
52
|
+
so these are always compared: `TZ`, `LANG` and every `NODE_*`, `LC_*`,
|
|
53
|
+
`VITE_*`, `DYLD_*` and `LD_*` variable. Display-only variables are not
|
|
54
|
+
compared: `_`, `TERM`, `TERM_PROGRAM`, `COLORTERM`, `FORCE_COLOR`, `NO_COLOR`,
|
|
55
|
+
`FORCE_TTY`, `COLUMNS`, `LINES` and `AI_AGENT`.
|
|
56
|
+
It does not mean a rerun would give the same result. A test that depends on the
|
|
57
|
+
time of day or on randomness can pass now and fail later on the same inputs.
|
|
58
|
+
|
|
59
|
+
The default config excludes `**/*.md`, `**/*.mdx` and, with `--coverage`,
|
|
60
|
+
`coverage/**`. Editing those files keeps a result CURRENT unless the run read
|
|
61
|
+
them. A run may create git-ignored files (for example under `test/tmp`) and
|
|
62
|
+
read back what it wrote, in the same process or inside a directory it created:
|
|
63
|
+
when every change during the run is such an output, the result keeps the files
|
|
64
|
+
as the run left them.
|
|
65
|
+
|
|
66
|
+
## The guard
|
|
67
|
+
|
|
68
|
+
Every Node process and worker thread of the run loads a recorder
|
|
69
|
+
(`src/test-recorder.cjs`). After the run REDUE checks the record. The result is
|
|
70
|
+
kept but marked UNVERIFIED, with the reason, when the run:
|
|
71
|
+
|
|
72
|
+
- read a file that the config excludes, or a git-ignored file REDUE does not
|
|
73
|
+
observe, that the run did not create first;
|
|
74
|
+
- changed an input during the run, or read a git-ignored output an earlier
|
|
75
|
+
run left before writing it again: the result depends on that leftover;
|
|
76
|
+
- listed a directory, or read a file over 1 MB, outside the checkout, other
|
|
77
|
+
than files and directories the run created, Jest's cache directory and the
|
|
78
|
+
runners' data directories (Vitest's `vitest` folder in the user data
|
|
79
|
+
directory);
|
|
80
|
+
- connected to anything other than loopback or a local socket, or asked DNS
|
|
81
|
+
about a name other than localhost;
|
|
82
|
+
- started a process that did not load the recorder: a shell, a binary, or a
|
|
83
|
+
Node process with its own environment. A process that replaces itself with
|
|
84
|
+
another program (`process.execve`) counts as starting it, and it must
|
|
85
|
+
become a recorded Node process. A shell is read by its command, as the
|
|
86
|
+
[general recipe](node-script.md#programs) reads it: one that runs another
|
|
87
|
+
program before it becomes Node counts too;
|
|
88
|
+
- used one of Node's bindings with file, network or program access
|
|
89
|
+
(`process.binding('fs')`, `'spawn_sync'` and others), or ran Node with
|
|
90
|
+
`--expose-internals`: the recorder cannot follow those;
|
|
91
|
+
- had an installed file with another hard link, other than a link into the
|
|
92
|
+
pnpm store the install recorded in `node_modules/.modules.yaml` (pnpm's
|
|
93
|
+
default on Linux) or, without a pnpm store, links that are all installed
|
|
94
|
+
files the check observes (esbuild's install links its binary into its
|
|
95
|
+
platform package). The link count of each such file is checked again
|
|
96
|
+
before every answer, so a link added later is noticed. A change through a
|
|
97
|
+
link elsewhere, such as Yarn's hardlinks modes, is not seen. This applies
|
|
98
|
+
to the [general recipe](node-script.md) too.
|
|
99
|
+
|
|
100
|
+
Lookups that can be asked again become run facts, checked before every CURRENT
|
|
101
|
+
answer: whether a path outside the checkout exists, where a link resolves, the
|
|
102
|
+
content of each smaller file read outside it (Linux native bindings read
|
|
103
|
+
`/proc/version` and `/usr/bin/ldd` to pick their C library), and
|
|
104
|
+
the existence and listings of excluded or ignored files in the checkout.
|
|
105
|
+
|
|
106
|
+
When two runs on the same inputs and environment give different results, the
|
|
107
|
+
check is UNVERIFIED until the inputs change.
|
|
108
|
+
|
|
109
|
+
A `--coverage` run may read back the default `coverage/` report: Jest reads
|
|
110
|
+
every JavaScript file under its roots, an earlier report's included, only to
|
|
111
|
+
map dependencies, and that does not decide pass or fail. This is not allowed
|
|
112
|
+
when the configuration names coverage thresholds, which make the report decide
|
|
113
|
+
the result, or another report directory. Configuration can be code, so REDUE
|
|
114
|
+
looks for `coverageThreshold`, `thresholds`, `coverageDirectory` and
|
|
115
|
+
`reportsDirectory` in `package.json`'s `jest` field and the runner's config
|
|
116
|
+
files; when one appears, reading an old report is UNVERIFIED.
|
|
117
|
+
|
|
118
|
+
## Known causes of UNVERIFIED
|
|
119
|
+
|
|
120
|
+
Tests that write files git does not ignore change the run's inputs.
|
|
121
|
+
|
|
122
|
+
## Limits
|
|
123
|
+
|
|
124
|
+
- Runner caches and data are trusted: `node_modules/.vite`,
|
|
125
|
+
`node_modules/.vite-temp`, `node_modules/.vitest`, Vitest's typecheck build
|
|
126
|
+
info in `node_modules/vitest/dist`, Jest's cache directory and Vitest's user
|
|
127
|
+
data directory are not inputs.
|
|
128
|
+
- Code that copies the environment and reads the copy, and native code that
|
|
129
|
+
reads files, environment variables or the network, is not seen.
|
|
130
|
+
- Metadata of excluded files (size, times) is not compared, only their
|
|
131
|
+
existence.
|
|
132
|
+
- A file the run creates and another process reads is the run's output only
|
|
133
|
+
when it is inside a directory the run created.
|
|
134
|
+
- Outputs a run keeps are part of the result's inputs afterwards. Deleting
|
|
135
|
+
them, or an observer restart that reindexes without them (git-ignored files
|
|
136
|
+
are not indexed at start), makes the result STALE.
|
|
137
|
+
- A config written by an earlier build of this recipe is UNVERIFIED with "run
|
|
138
|
+
redue init again"; move `redue.config.json` aside and run init.
|
|
139
|
+
- pnpm's store is trusted not to change a file in place, as pnpm never does.
|
|
140
|
+
Editing an installed file in another project that shares the same store
|
|
141
|
+
file changes it here too, unseen. Use `pnpm patch`, or a copying install
|
|
142
|
+
(`package-import-method=copy`), if you edit installed files.
|
|
143
|
+
- Windows is not supported; the check stays recording-only there.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redue/cli",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
4
|
+
"version": "0.1.0-alpha.31",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"tag": "alpha"
|
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
"redue": "./bin/redue.mjs"
|
|
12
12
|
},
|
|
13
13
|
"scripts": {
|
|
14
|
-
"test": "node
|
|
14
|
+
"test": "node test/run-suite.mjs",
|
|
15
15
|
"test:package": "node test/acceptance/package-smoke.mjs",
|
|
16
|
-
"demo": "node test/acceptance/package-smoke.mjs --demo"
|
|
16
|
+
"demo": "node test/acceptance/package-smoke.mjs --demo",
|
|
17
|
+
"pretest": "npm --prefix test/fixtures/typescript-5-5-2 ci --no-audit --no-fund && npm --prefix test/fixtures/typescript-6-0-2 ci --no-audit --no-fund && npm --prefix test/fixtures/typescript-6-0-3 ci --no-audit --no-fund"
|
|
17
18
|
},
|
|
18
19
|
"dependencies": {
|
|
19
20
|
"@parcel/watcher": "2.5.6",
|