@bluewombat/isolator 0.1.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 +94 -0
- package/SPECS.md +294 -0
- package/dist/args/parse-args.d.ts +6 -0
- package/dist/args/parse-args.d.ts.map +1 -0
- package/dist/args/parse-args.js +223 -0
- package/dist/args/parse-args.js.map +1 -0
- package/dist/child/run-child.d.ts +39 -0
- package/dist/child/run-child.d.ts.map +1 -0
- package/dist/child/run-child.js +132 -0
- package/dist/child/run-child.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +99 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/isolate/backend.d.ts +31 -0
- package/dist/isolate/backend.d.ts.map +1 -0
- package/dist/isolate/backend.js +2 -0
- package/dist/isolate/backend.js.map +1 -0
- package/dist/isolate/create-child.d.ts +26 -0
- package/dist/isolate/create-child.d.ts.map +1 -0
- package/dist/isolate/create-child.js +62 -0
- package/dist/isolate/create-child.js.map +1 -0
- package/dist/isolate/stop.d.ts +7 -0
- package/dist/isolate/stop.d.ts.map +1 -0
- package/dist/isolate/stop.js +17 -0
- package/dist/isolate/stop.js.map +1 -0
- package/dist/progress/emit.d.ts +5 -0
- package/dist/progress/emit.d.ts.map +1 -0
- package/dist/progress/emit.js +17 -0
- package/dist/progress/emit.js.map +1 -0
- package/dist/run/run-isolator.d.ts +35 -0
- package/dist/run/run-isolator.d.ts.map +1 -0
- package/dist/run/run-isolator.js +164 -0
- package/dist/run/run-isolator.js.map +1 -0
- package/dist/status/announce.d.ts +14 -0
- package/dist/status/announce.d.ts.map +1 -0
- package/dist/status/announce.js +28 -0
- package/dist/status/announce.js.map +1 -0
- package/dist/status/make-status.d.ts +7 -0
- package/dist/status/make-status.d.ts.map +1 -0
- package/dist/status/make-status.js +19 -0
- package/dist/status/make-status.js.map +1 -0
- package/dist/types.d.ts +28 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Isolator
|
|
2
|
+
|
|
3
|
+
Transformer: runs **one Isolation**. It takes a Parent directory that
|
|
4
|
+
already exists and creates a Child directory that did not. The Child is a
|
|
5
|
+
snapshot of the Parent's working files at Isolation time, then independent of
|
|
6
|
+
the Parent.
|
|
7
|
+
|
|
8
|
+
Behavioural contract: [SPECS.md](./SPECS.md).
|
|
9
|
+
|
|
10
|
+
## Stack
|
|
11
|
+
|
|
12
|
+
Repository stack — TypeScript, Node 24.20, Biome, `node:test`. See [docs/DEVELOPMENT.md](../../../docs/DEVELOPMENT.md).
|
|
13
|
+
|
|
14
|
+
## Setup
|
|
15
|
+
|
|
16
|
+
From the repository root:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
nvm use
|
|
20
|
+
npm install
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Commands
|
|
24
|
+
|
|
25
|
+
| Task | Command |
|
|
26
|
+
| --------- | ---------------- |
|
|
27
|
+
| Lint | `npm run lint` |
|
|
28
|
+
| Format | `npm run format` |
|
|
29
|
+
| Typecheck | `npm run tsc` |
|
|
30
|
+
| Test | `npm test` |
|
|
31
|
+
| Build | `npm run build` |
|
|
32
|
+
|
|
33
|
+
Binary after build: `dist/cli.js` (package bin name `isolator`).
|
|
34
|
+
|
|
35
|
+
## Run
|
|
36
|
+
|
|
37
|
+
Parent must already exist. Child must not. Missing ancestors of `--child` are
|
|
38
|
+
created. Example:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm run build
|
|
42
|
+
node dist/cli.js \
|
|
43
|
+
--id feat-1 \
|
|
44
|
+
--parent /absolute/path/to/parent \
|
|
45
|
+
--child /absolute/path/to/child \
|
|
46
|
+
--duration-ms 60000 \
|
|
47
|
+
--strategy @bluewombat/isolation-copy
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
The CLI requires `--strategy`: a package name or path that exports `strategy` with an `isolation` backend. Isolator does not sniff `.git` and does not choose git versus copy.
|
|
51
|
+
|
|
52
|
+
Progress is JSON lines on stdout (`status`, `isolation-started`,
|
|
53
|
+
`isolation-finished`). Exit codes: `0` isolated, `1` failed, `2`
|
|
54
|
+
invalid-invocation, `130` interrupted.
|
|
55
|
+
|
|
56
|
+
## Import
|
|
57
|
+
|
|
58
|
+
Same Transformer, in process. `cli.ts` is an adapter over this function — it reads argv
|
|
59
|
+
and stdin, calls `runIsolator`, and maps the outcome to an exit code. Nothing the CLI
|
|
60
|
+
can do is unreachable from here.
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { strategy } from "@bluewombat/isolation-copy";
|
|
64
|
+
import { runIsolator } from "@bluewombat/isolator";
|
|
65
|
+
|
|
66
|
+
const result = await runIsolator({
|
|
67
|
+
invocation, // same shape the CLI builds from argv
|
|
68
|
+
backend: strategy.isolation, // Host / CLI loads a strategy package
|
|
69
|
+
write: (line) => events.push(line), // progress as values, not stdout
|
|
70
|
+
});
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`src/index.ts` exports `runIsolator`, `IsolationBackend`, `RunOptions` /
|
|
74
|
+
`RunResult`, `ProgressWriter`, and this Transformer's domain types. Isolation
|
|
75
|
+
strategies live under `packages/plugins/isolation-*`.
|
|
76
|
+
|
|
77
|
+
## Layout
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
SPECS.md behavioural contract
|
|
81
|
+
README.md how to build and run
|
|
82
|
+
src/
|
|
83
|
+
cli.ts entry
|
|
84
|
+
types.ts Transformer-owned types
|
|
85
|
+
args/ CLI parsing
|
|
86
|
+
status/ Status labels and --on-status
|
|
87
|
+
progress/ JSON-line progress writer
|
|
88
|
+
child/ spawn (--on-status)
|
|
89
|
+
isolate/ snapshot via injected IsolationBackend (stop + create-child)
|
|
90
|
+
run/ invocation orchestration
|
|
91
|
+
fixtures/ fake --on-status scripts for tests
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Sources stay colocated: helpers used once live next to their caller.
|
package/SPECS.md
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# Isolator
|
|
2
|
+
|
|
3
|
+
Independent Transformer: it has a binary, a contract, and nothing else. Isolator is
|
|
4
|
+
alone. Its code, identifiers, comments, and messages name only what it owns: the
|
|
5
|
+
Isolation, its arguments, the Parent path, the Child path, Status, clocks, and
|
|
6
|
+
the Isolation outcome. No other component is mentioned there, because none of
|
|
7
|
+
them exist inside this perimeter.
|
|
8
|
+
|
|
9
|
+
Isolator runs **one Isolation**. It takes a Parent directory it did not create
|
|
10
|
+
and produces a Child directory that did not exist. The Child is a snapshot of
|
|
11
|
+
the Parent's working files at Isolation time, then independent of the Parent.
|
|
12
|
+
|
|
13
|
+
The invocation is always the same. How Isolator produces the Child is an
|
|
14
|
+
injected **Isolation backend** (`attach` / `abort`). Isolator does not choose a
|
|
15
|
+
strategy. The CLI requires `--strategy <specifier>`; Host loads the package
|
|
16
|
+
named in `workLine.isolation`. Strategies live under `packages/plugins/isolation-*`.
|
|
17
|
+
|
|
18
|
+
Isolator does not run work in either directory. It does not fold the Child back
|
|
19
|
+
into the Parent. It does not delete a Child that reached `isolated`.
|
|
20
|
+
|
|
21
|
+
Stack and binary layout: [README.md](./README.md).
|
|
22
|
+
|
|
23
|
+
## 1. Job
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
arguments Isolator disk
|
|
27
|
+
--------- -------- ----
|
|
28
|
+
Isolation one invocation create the Child
|
|
29
|
+
Parent snapshot Parent working files do not write Parent working files
|
|
30
|
+
Child path then independent
|
|
31
|
+
bounds
|
|
32
|
+
← Isolation outcome + Child path + Status
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**In:** arguments. **Out:** one Isolation outcome, the Child path when the
|
|
36
|
+
outcome is `isolated`, and a live Status each time it changes. Isolator does
|
|
37
|
+
not wait for a listener to acknowledge.
|
|
38
|
+
|
|
39
|
+
A Child of one Isolation may be the Parent of a later Isolation. Isolator does
|
|
40
|
+
not know or care; every invocation is the same job.
|
|
41
|
+
|
|
42
|
+
## 2. Options
|
|
43
|
+
|
|
44
|
+
Isolator is invoked with arguments. It does not read an input file. It does not
|
|
45
|
+
read configuration from the Parent or the Child.
|
|
46
|
+
|
|
47
|
+
| Argument | Content |
|
|
48
|
+
| ------------------------ | -------------------------------------------------------------------------------------------------- |
|
|
49
|
+
| `--id` | Isolation id. Copied onto every Status and progress line. Non-empty. |
|
|
50
|
+
| `--parent` | Absolute path. Must already exist as a directory. Working files here are the snapshot source. |
|
|
51
|
+
| `--child` | Absolute path. Must not exist. Isolator creates this directory, including missing ancestors. |
|
|
52
|
+
| `--duration-ms` | Positive integer. Wall clock of the Isolation, from the moment Isolator starts creating the Child. |
|
|
53
|
+
| `--strategy` | Package name or path. CLI only. Loads `strategy.isolation`. `runIsolator` receives the backend as an argument; it never chooses one. |
|
|
54
|
+
| `--on-status -- <argv…>` | Optional. Command to run each time Status changes. Omitted: Status still goes to stdout. |
|
|
55
|
+
|
|
56
|
+
No other argument is read.
|
|
57
|
+
|
|
58
|
+
Malformed arguments, empty id, non-absolute path, missing Parent, Parent not a
|
|
59
|
+
directory, Child already exists, Child's containing path exists but is not a
|
|
60
|
+
directory, Parent and Child the same path, Parent a prefix of Child, Child a
|
|
61
|
+
prefix of Parent, or a non-positive `--duration-ms` → Isolation outcome
|
|
62
|
+
`invalid-invocation`. No Child is created. Parent is left as it was.
|
|
63
|
+
|
|
64
|
+
## 3. Workflow
|
|
65
|
+
|
|
66
|
+
One invocation runs one Isolation. There is no loop.
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
Check arguments and paths (§2). Unusable → `invalid-invocation`.
|
|
70
|
+
Announce Status `isolating`.
|
|
71
|
+
Start the Isolation clock.
|
|
72
|
+
Create the Child as a snapshot of the Parent's working files (§4).
|
|
73
|
+
If the clock fires, a stop signal arrives, or creation cannot complete
|
|
74
|
+
→ remove any incomplete Child → Isolation outcome `failed` or `interrupted` (§5).
|
|
75
|
+
If creation completes
|
|
76
|
+
→ Isolation outcome `isolated`. The Child stays.
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```mermaid
|
|
80
|
+
flowchart TD
|
|
81
|
+
START[Check arguments] --> OK{Usable?}
|
|
82
|
+
OK -->|no| INV[invalid-invocation]
|
|
83
|
+
OK -->|yes| ISO[Create Child from Parent]
|
|
84
|
+
ISO -->|complete| DONE[isolated]
|
|
85
|
+
ISO -->|clock| FAIL[failed — incomplete Child removed]
|
|
86
|
+
ISO -->|stop signal| INT[interrupted — incomplete Child removed]
|
|
87
|
+
ISO -->|cannot complete| FAIL
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 4. Isolation
|
|
91
|
+
|
|
92
|
+
Isolation is a property of two directories after a successful invocation. It is
|
|
93
|
+
not a later process, not a merge, and not a lock on the Parent.
|
|
94
|
+
|
|
95
|
+
### Isolation backend
|
|
96
|
+
|
|
97
|
+
Isolator does not choose a strategy. The caller injects an `IsolationBackend`
|
|
98
|
+
(`attach` / `abort`). Strategies live under `packages/plugins/isolation-*` and export
|
|
99
|
+
`strategy: { isolation, fold }`.
|
|
100
|
+
|
|
101
|
+
| Field on `attach` | Meaning |
|
|
102
|
+
| ----------------- | ------- |
|
|
103
|
+
| `id?` | Isolation id; a strategy may derive a branch or other label from it |
|
|
104
|
+
| `parent` / `child` | Absolute paths |
|
|
105
|
+
| `timeoutMs` / `shouldInterrupt` / `shouldStop` | Budgets and stop signals |
|
|
106
|
+
|
|
107
|
+
The binary's `cli.ts` requires `--strategy <specifier>` and loads that package.
|
|
108
|
+
Host resolves `workLine.isolation` the same way. There is no `.git` sniff and no
|
|
109
|
+
`"git"` / `"copy"` alias. A strategy failure is `failed`, not a silent switch.
|
|
110
|
+
|
|
111
|
+
Git bookkeeping under the Parent (when using `@bluewombat/isolation-git`) is
|
|
112
|
+
Isolation bookkeeping, not working files. A copy strategy writes nothing on the
|
|
113
|
+
Parent.
|
|
114
|
+
|
|
115
|
+
Same `--id`, `--parent`, `--child`. Same outcomes. Snapshot and independence
|
|
116
|
+
(§4) hold either way.
|
|
117
|
+
|
|
118
|
+
### Snapshot
|
|
119
|
+
|
|
120
|
+
At Isolation start, Isolator reads the Parent's **working files**: the tree a
|
|
121
|
+
process with that directory as its working directory would see as the work.
|
|
122
|
+
When the Isolation outcome is `isolated`, the Child has the same relative paths
|
|
123
|
+
and the same content for those working files.
|
|
124
|
+
|
|
125
|
+
Isolator adds no working file of its own under the Child. The Child is the
|
|
126
|
+
snapshot, not a wrapper around it.
|
|
127
|
+
|
|
128
|
+
The contract is the working files. Git vs copy is how Isolator produces them.
|
|
129
|
+
|
|
130
|
+
### Independence
|
|
131
|
+
|
|
132
|
+
After `isolated`:
|
|
133
|
+
|
|
134
|
+
- A write under the Child does not change the Parent's working files.
|
|
135
|
+
- A write under the Parent does not change the Child's working files.
|
|
136
|
+
|
|
137
|
+
The two trees may then diverge. Isolator does not keep them in sync. A new
|
|
138
|
+
Isolation is a new invocation.
|
|
139
|
+
|
|
140
|
+
### Parent
|
|
141
|
+
|
|
142
|
+
Isolator does not add, remove, or edit the Parent's working files. After any
|
|
143
|
+
outcome, those files are what they were at invocation start.
|
|
144
|
+
|
|
145
|
+
Isolator may write Isolation bookkeeping that is not working content, if the
|
|
146
|
+
Parent's storage requires it to attach a Child. That bookkeeping is not a
|
|
147
|
+
working file.
|
|
148
|
+
|
|
149
|
+
Isolator never deletes the Parent.
|
|
150
|
+
|
|
151
|
+
### Child
|
|
152
|
+
|
|
153
|
+
Isolator creates `--child`. Missing ancestor directories are created. A
|
|
154
|
+
containing path that already exists and is not a directory is
|
|
155
|
+
`invalid-invocation`.
|
|
156
|
+
|
|
157
|
+
Isolator does not delete a Child whose Isolation outcome is `isolated`.
|
|
158
|
+
Callers that destroy a Child do so outside this process.
|
|
159
|
+
|
|
160
|
+
If Isolation does not complete, Isolator removes the incomplete Child so a
|
|
161
|
+
retry with the same `--child` is not blocked by a half-created directory. A
|
|
162
|
+
directory that already existed before this invocation is never that incomplete
|
|
163
|
+
Child — that case is `invalid-invocation` and Isolator does not touch it.
|
|
164
|
+
|
|
165
|
+
### What Isolator does not do
|
|
166
|
+
|
|
167
|
+
- Interpret files in the Parent or the Child.
|
|
168
|
+
- Spawn a worker whose job is the content.
|
|
169
|
+
- Fold the Child into the Parent.
|
|
170
|
+
- Reuse an existing Child.
|
|
171
|
+
- Overwrite `--child`.
|
|
172
|
+
- Choose a Child path of its own: `--child` is the path.
|
|
173
|
+
|
|
174
|
+
## 5. Clocks and interrupt
|
|
175
|
+
|
|
176
|
+
**Isolation clock.** Starts when Isolator begins creating the Child. On
|
|
177
|
+
`--duration-ms`, Isolator stops creation, removes any incomplete Child, Isolation
|
|
178
|
+
outcome `failed`. The report names the clock.
|
|
179
|
+
|
|
180
|
+
**Interrupt.** SIGINT and SIGTERM stop this invocation. Isolator stops creation,
|
|
181
|
+
removes any incomplete Child, Isolation outcome `interrupted`. It does **not**
|
|
182
|
+
delete the Parent. It does **not** delete a Child that already reached
|
|
183
|
+
`isolated` (that Isolation is finished).
|
|
184
|
+
|
|
185
|
+
A stop signal that races a clock uses `interrupted`.
|
|
186
|
+
|
|
187
|
+
## 6. Status
|
|
188
|
+
|
|
189
|
+
Status is the live snapshot of this invocation. It changes at phase boundaries
|
|
190
|
+
(Isolation about to run, Isolation outcome known). It is not a history. The
|
|
191
|
+
`label` is meant to be shown as-is.
|
|
192
|
+
|
|
193
|
+
### Shape
|
|
194
|
+
|
|
195
|
+
| Field | Content |
|
|
196
|
+
| ------- | ---------------------------------------------------------------- |
|
|
197
|
+
| `phase` | `isolating`, `isolated`, `failed`, `interrupted`, or `invalid` |
|
|
198
|
+
| `id` | From `--id`. Absent on `invalid` when `--id` itself is unusable. |
|
|
199
|
+
| `label` | Canonical display string. See below. |
|
|
200
|
+
|
|
201
|
+
### Label
|
|
202
|
+
|
|
203
|
+
Built by Isolator. Do not invent another spelling.
|
|
204
|
+
|
|
205
|
+
| `phase` | `label` | Example |
|
|
206
|
+
| ------------- | ------------------ | -------------------- |
|
|
207
|
+
| `isolating` | `isolating:<id>` | `isolating:feat-1` |
|
|
208
|
+
| `isolated` | `isolated:<id>` | `isolated:feat-1` |
|
|
209
|
+
| `failed` | `failed:<id>` | `failed:feat-1` |
|
|
210
|
+
| `interrupted` | `interrupted:<id>` | `interrupted:feat-1` |
|
|
211
|
+
| `invalid` | `invalid` | `invalid` |
|
|
212
|
+
|
|
213
|
+
`<id>` is the `--id` argument, as given.
|
|
214
|
+
|
|
215
|
+
### When it is announced
|
|
216
|
+
|
|
217
|
+
| Moment | `phase` |
|
|
218
|
+
| ------------------------------------------------------- | ------------ |
|
|
219
|
+
| Arguments or paths unusable | `invalid` |
|
|
220
|
+
| Child about to be created | `isolating` |
|
|
221
|
+
| Isolation outcome `isolated` / `failed` / `interrupted` | that outcome |
|
|
222
|
+
|
|
223
|
+
Announced on stdout as a JSON line (`event`: `status`) carrying the fields
|
|
224
|
+
above. If `--on-status` was given, Isolator also runs that command, cwd
|
|
225
|
+
unchanged (not the Parent, not the Child), and appends:
|
|
226
|
+
|
|
227
|
+
| Argument | Content |
|
|
228
|
+
| --------- | -------------------------- |
|
|
229
|
+
| `--id` | Isolation id, when present |
|
|
230
|
+
| `--label` | The label |
|
|
231
|
+
| `--phase` | The phase |
|
|
232
|
+
|
|
233
|
+
`--on-status` does not count against the Isolation clock. A non-zero exit, a
|
|
234
|
+
missing command, or a hang that Isolator must kill does **not** change the
|
|
235
|
+
Isolation outcome. Visibility must not take the Isolation down.
|
|
236
|
+
|
|
237
|
+
## 7. Progress
|
|
238
|
+
|
|
239
|
+
JSON lines on stdout. A `status` line is the live snapshot (§6). The other
|
|
240
|
+
lines record the Isolation.
|
|
241
|
+
|
|
242
|
+
| `event` | When |
|
|
243
|
+
| -------------------- | -------------------------- |
|
|
244
|
+
| `status` | Each time Status changes |
|
|
245
|
+
| `isolation-started` | Child about to be created |
|
|
246
|
+
| `isolation-finished` | Isolation outcome is known |
|
|
247
|
+
|
|
248
|
+
Each line carries `id` when the Isolation id is usable.
|
|
249
|
+
|
|
250
|
+
`isolation-finished` also carries:
|
|
251
|
+
|
|
252
|
+
| Field | Content |
|
|
253
|
+
| --------- | -------------------------------------------------------------------------- |
|
|
254
|
+
| `outcome` | The Isolation outcome (§8). |
|
|
255
|
+
| `child` | Absolute `--child` path. Present only when `outcome` is `isolated`. |
|
|
256
|
+
| `report` | Why, when `outcome` is `failed` or `invalid-invocation`. Absent otherwise. |
|
|
257
|
+
|
|
258
|
+
Isolator creates no working file under the Parent. It creates no working file
|
|
259
|
+
under the Child other than the snapshot. It deletes nothing under the Parent.
|
|
260
|
+
|
|
261
|
+
## 8. Isolation outcomes
|
|
262
|
+
|
|
263
|
+
Exactly one per invocation. The meaning is entirely inside this process.
|
|
264
|
+
|
|
265
|
+
| Outcome | Meaning |
|
|
266
|
+
| -------------------- | --------------------------------------------------------------------------------------------------------------- |
|
|
267
|
+
| `invalid-invocation` | Arguments or paths unusable. No Child created. Parent untouched. |
|
|
268
|
+
| `isolated` | Child exists, snapshot taken, independence holds. Child stays. |
|
|
269
|
+
| `failed` | Isolation started and could not complete (clock, I/O, spawn of Isolator's own tools). Incomplete Child removed. |
|
|
270
|
+
| `interrupted` | Stop signal before `isolated`. Incomplete Child removed. |
|
|
271
|
+
|
|
272
|
+
No partial Isolation. A Child that exists after this process exits was either
|
|
273
|
+
already there (`invalid-invocation`, left alone) or fully `isolated`.
|
|
274
|
+
|
|
275
|
+
## 9. Acceptance
|
|
276
|
+
|
|
277
|
+
1. Parent has working files; Isolation completes → `isolated`; Child has those files at the same relative paths; Parent working files unchanged.
|
|
278
|
+
2. After `isolated`, a new file written only under the Child is absent from the Parent.
|
|
279
|
+
3. After `isolated`, a new file written only under the Parent is absent from the Child.
|
|
280
|
+
4. `--child` already exists → `invalid-invocation`; that directory unchanged; Parent unchanged.
|
|
281
|
+
5. Missing Parent, relative path, empty `--id`, `--child` inside `--parent`, or `--parent` inside `--child` → `invalid-invocation`; no Child created.
|
|
282
|
+
6. SIGTERM during creation → `interrupted`; `--child` does not exist afterwards; Parent remains.
|
|
283
|
+
7. Isolation clock fires during creation → `failed`; `--child` does not exist afterwards; Parent remains.
|
|
284
|
+
8. Isolator never deletes the Parent, never deletes an `isolated` Child, never writes a working file of its own into the Child, never folds the Child into the Parent.
|
|
285
|
+
9. A Child produced by one Isolation can be `--parent` of another Isolation; that second Isolation is the same job.
|
|
286
|
+
10. Entering creation with `--id feat-1` announces `label` `isolating:feat-1` on stdout, and via `--on-status` when that argument is set.
|
|
287
|
+
11. `--on-status` exiting non-zero does not change an `isolated` Isolation.
|
|
288
|
+
12. `@bluewombat/isolation-git` → `isolated` via git; Child is a worktree; Parent working files unchanged; independence holds.
|
|
289
|
+
13. `@bluewombat/isolation-copy` → `isolated` via copy; same snapshot and independence; Parent unchanged.
|
|
290
|
+
14. `@bluewombat/isolation-git` and git cannot complete → `failed`, not a copy.
|
|
291
|
+
15. `--child` whose containing directory is missing → Isolator creates the ancestors; `isolated`.
|
|
292
|
+
16. The CLI requires `--strategy <specifier>`; `runIsolator` never chooses a strategy.
|
|
293
|
+
|
|
294
|
+
How to build and run this Transformer: [README.md](./README.md).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-args.d.ts","sourceRoot":"","sources":["../../src/args/parse-args.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAc,WAAW,EAAE,MAAM,aAAa,CAAC;AAgH3D;;GAEG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,WAAW,CAyJrD"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { existsSync, statSync } from "node:fs";
|
|
2
|
+
import { dirname, isAbsolute, relative, resolve } from "node:path";
|
|
3
|
+
const ISOLATOR_FLAGS = new Set([
|
|
4
|
+
"--id",
|
|
5
|
+
"--parent",
|
|
6
|
+
"--child",
|
|
7
|
+
"--duration-ms",
|
|
8
|
+
"--on-status",
|
|
9
|
+
"--strategy",
|
|
10
|
+
]);
|
|
11
|
+
function isIsolatorFlag(token) {
|
|
12
|
+
return ISOLATOR_FLAGS.has(token);
|
|
13
|
+
}
|
|
14
|
+
function takeValue(argv, index) {
|
|
15
|
+
const value = argv[index + 1];
|
|
16
|
+
if (value === undefined || value.startsWith("--")) {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
return { value, next: index + 2 };
|
|
20
|
+
}
|
|
21
|
+
function takeCommandArgv(argv, start) {
|
|
22
|
+
if (argv[start] !== "--") {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
const command = [];
|
|
26
|
+
let i = start + 1;
|
|
27
|
+
while (i < argv.length) {
|
|
28
|
+
const token = argv[i];
|
|
29
|
+
if (token !== undefined && isIsolatorFlag(token)) {
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
if (token !== undefined) {
|
|
33
|
+
command.push(token);
|
|
34
|
+
}
|
|
35
|
+
i += 1;
|
|
36
|
+
}
|
|
37
|
+
if (command.length === 0) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
return { command, next: i };
|
|
41
|
+
}
|
|
42
|
+
function parsePositiveInt(raw) {
|
|
43
|
+
if (!/^\d+$/.test(raw)) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
const value = Number(raw);
|
|
47
|
+
if (!Number.isSafeInteger(value) || value < 1) {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
function isDirectory(path) {
|
|
53
|
+
try {
|
|
54
|
+
return statSync(path).isDirectory();
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function pathsOverlap(parent, child) {
|
|
61
|
+
const parentResolved = resolve(parent);
|
|
62
|
+
const childResolved = resolve(child);
|
|
63
|
+
if (parentResolved === childResolved) {
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
const fromParent = relative(parentResolved, childResolved);
|
|
67
|
+
const fromChild = relative(childResolved, parentResolved);
|
|
68
|
+
const childInsideParent = fromParent !== "" && !fromParent.startsWith("..") && !isAbsolute(fromParent);
|
|
69
|
+
const parentInsideChild = fromChild !== "" && !fromChild.startsWith("..") && !isAbsolute(fromChild);
|
|
70
|
+
return childInsideParent || parentInsideChild;
|
|
71
|
+
}
|
|
72
|
+
function snapshotPartial(id, onStatusArgv) {
|
|
73
|
+
const partial = {};
|
|
74
|
+
if (id !== undefined && id.length > 0) {
|
|
75
|
+
partial.id = id;
|
|
76
|
+
}
|
|
77
|
+
if (onStatusArgv !== undefined) {
|
|
78
|
+
partial.onStatusArgv = onStatusArgv;
|
|
79
|
+
}
|
|
80
|
+
return partial;
|
|
81
|
+
}
|
|
82
|
+
function withPartial(reason, id, onStatusArgv) {
|
|
83
|
+
const failure = { ok: false, reason };
|
|
84
|
+
const partial = snapshotPartial(id, onStatusArgv);
|
|
85
|
+
if (partial.id !== undefined) {
|
|
86
|
+
failure.id = partial.id;
|
|
87
|
+
}
|
|
88
|
+
if (partial.onStatusArgv !== undefined) {
|
|
89
|
+
failure.onStatusArgv = partial.onStatusArgv;
|
|
90
|
+
}
|
|
91
|
+
return failure;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Parse Isolator CLI argv (without node/script). Malformed input → not ok.
|
|
95
|
+
*/
|
|
96
|
+
export function parseArgs(argv) {
|
|
97
|
+
let id;
|
|
98
|
+
let parent;
|
|
99
|
+
let child;
|
|
100
|
+
let durationMs;
|
|
101
|
+
let strategy;
|
|
102
|
+
let onStatusArgv;
|
|
103
|
+
let i = 0;
|
|
104
|
+
while (i < argv.length) {
|
|
105
|
+
const token = argv[i];
|
|
106
|
+
if (token === undefined) {
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
if (token === "--id") {
|
|
110
|
+
const taken = takeValue(argv, i);
|
|
111
|
+
if (!taken) {
|
|
112
|
+
return withPartial("Missing value for --id.", id, onStatusArgv);
|
|
113
|
+
}
|
|
114
|
+
id = taken.value;
|
|
115
|
+
i = taken.next;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (token === "--parent") {
|
|
119
|
+
const taken = takeValue(argv, i);
|
|
120
|
+
if (!taken) {
|
|
121
|
+
return withPartial("Missing value for --parent.", id, onStatusArgv);
|
|
122
|
+
}
|
|
123
|
+
parent = taken.value;
|
|
124
|
+
i = taken.next;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (token === "--child") {
|
|
128
|
+
const taken = takeValue(argv, i);
|
|
129
|
+
if (!taken) {
|
|
130
|
+
return withPartial("Missing value for --child.", id, onStatusArgv);
|
|
131
|
+
}
|
|
132
|
+
child = taken.value;
|
|
133
|
+
i = taken.next;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (token === "--duration-ms") {
|
|
137
|
+
const taken = takeValue(argv, i);
|
|
138
|
+
if (!taken) {
|
|
139
|
+
return withPartial("Missing value for --duration-ms.", id, onStatusArgv);
|
|
140
|
+
}
|
|
141
|
+
const value = parsePositiveInt(taken.value);
|
|
142
|
+
if (value === null) {
|
|
143
|
+
return withPartial("--duration-ms must be a positive integer.", id, onStatusArgv);
|
|
144
|
+
}
|
|
145
|
+
durationMs = value;
|
|
146
|
+
i = taken.next;
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
if (token === "--strategy") {
|
|
150
|
+
const taken = takeValue(argv, i);
|
|
151
|
+
if (!taken) {
|
|
152
|
+
return withPartial("Missing value for --strategy.", id, onStatusArgv);
|
|
153
|
+
}
|
|
154
|
+
if (taken.value.length === 0) {
|
|
155
|
+
return withPartial("--strategy must be a non-empty package name or path.", id, onStatusArgv);
|
|
156
|
+
}
|
|
157
|
+
strategy = taken.value;
|
|
158
|
+
i = taken.next;
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
if (token === "--on-status") {
|
|
162
|
+
const command = takeCommandArgv(argv, i + 1);
|
|
163
|
+
if (!command) {
|
|
164
|
+
return withPartial("Missing non-empty command after --on-status --.", id, onStatusArgv);
|
|
165
|
+
}
|
|
166
|
+
onStatusArgv = command.command;
|
|
167
|
+
i = command.next;
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
return withPartial(`Unknown argument "${token}".`, id, onStatusArgv);
|
|
171
|
+
}
|
|
172
|
+
if (id === undefined) {
|
|
173
|
+
return withPartial("Missing required --id.", id, onStatusArgv);
|
|
174
|
+
}
|
|
175
|
+
if (id.length === 0) {
|
|
176
|
+
return withPartial("--id must be non-empty.", undefined, onStatusArgv);
|
|
177
|
+
}
|
|
178
|
+
if (parent === undefined) {
|
|
179
|
+
return withPartial("Missing required --parent.", id, onStatusArgv);
|
|
180
|
+
}
|
|
181
|
+
if (child === undefined) {
|
|
182
|
+
return withPartial("Missing required --child.", id, onStatusArgv);
|
|
183
|
+
}
|
|
184
|
+
if (durationMs === undefined) {
|
|
185
|
+
return withPartial("Missing required --duration-ms.", id, onStatusArgv);
|
|
186
|
+
}
|
|
187
|
+
if (strategy === undefined) {
|
|
188
|
+
return withPartial("Missing required --strategy. Pass a package name or path that exports strategy.", id, onStatusArgv);
|
|
189
|
+
}
|
|
190
|
+
if (!isAbsolute(parent)) {
|
|
191
|
+
return withPartial("--parent must be an absolute path.", id, onStatusArgv);
|
|
192
|
+
}
|
|
193
|
+
if (!isAbsolute(child)) {
|
|
194
|
+
return withPartial("--child must be an absolute path.", id, onStatusArgv);
|
|
195
|
+
}
|
|
196
|
+
if (!existsSync(parent)) {
|
|
197
|
+
return withPartial(`--parent does not exist: ${parent}`, id, onStatusArgv);
|
|
198
|
+
}
|
|
199
|
+
if (!isDirectory(parent)) {
|
|
200
|
+
return withPartial(`--parent is not a directory: ${parent}`, id, onStatusArgv);
|
|
201
|
+
}
|
|
202
|
+
if (existsSync(child)) {
|
|
203
|
+
return withPartial(`--child already exists: ${child}`, id, onStatusArgv);
|
|
204
|
+
}
|
|
205
|
+
const childContainer = dirname(child);
|
|
206
|
+
if (existsSync(childContainer) && !isDirectory(childContainer)) {
|
|
207
|
+
return withPartial(`Child containing directory is not a directory: ${childContainer}`, id, onStatusArgv);
|
|
208
|
+
}
|
|
209
|
+
if (pathsOverlap(parent, child)) {
|
|
210
|
+
return withPartial("--parent and --child must not be the same path, and neither may be a prefix of the other.", id, onStatusArgv);
|
|
211
|
+
}
|
|
212
|
+
const invocation = {
|
|
213
|
+
id,
|
|
214
|
+
parent: resolve(parent),
|
|
215
|
+
child: resolve(child),
|
|
216
|
+
durationMs,
|
|
217
|
+
};
|
|
218
|
+
if (onStatusArgv !== undefined) {
|
|
219
|
+
invocation.onStatusArgv = onStatusArgv;
|
|
220
|
+
}
|
|
221
|
+
return { ok: true, invocation, strategy };
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=parse-args.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse-args.js","sourceRoot":"","sources":["../../src/args/parse-args.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { ClockName } from "../types.js";
|
|
2
|
+
export type SpawnRequest = {
|
|
3
|
+
argv: string[];
|
|
4
|
+
/** Undefined lets the child inherit the caller's directory. */
|
|
5
|
+
cwd?: string | undefined;
|
|
6
|
+
/** Wall-clock budget for this child (ms). */
|
|
7
|
+
timeoutMs: number;
|
|
8
|
+
/** Which clock owns the nearer deadline when timeoutMs hits. */
|
|
9
|
+
timeoutClock: ClockName;
|
|
10
|
+
/** When true, treat kill as interrupted (stop signal). */
|
|
11
|
+
shouldInterrupt: () => boolean;
|
|
12
|
+
/** Undefined lets the child inherit the caller's environment. */
|
|
13
|
+
env?: NodeJS.ProcessEnv | undefined;
|
|
14
|
+
};
|
|
15
|
+
export type SpawnOutcome = {
|
|
16
|
+
kind: "exited";
|
|
17
|
+
exitCode: number | null;
|
|
18
|
+
signal: NodeJS.Signals | null;
|
|
19
|
+
stdout: string;
|
|
20
|
+
stderr: string;
|
|
21
|
+
} | {
|
|
22
|
+
kind: "timed_out";
|
|
23
|
+
clock: ClockName;
|
|
24
|
+
stdout: string;
|
|
25
|
+
stderr: string;
|
|
26
|
+
} | {
|
|
27
|
+
kind: "interrupted";
|
|
28
|
+
stdout: string;
|
|
29
|
+
stderr: string;
|
|
30
|
+
} | {
|
|
31
|
+
kind: "spawn_error";
|
|
32
|
+
detail: string;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Run one child with a wall-clock timeout. Does not inherit Isolator stdin.
|
|
36
|
+
*/
|
|
37
|
+
export declare function runChild(request: SpawnRequest): Promise<SpawnOutcome>;
|
|
38
|
+
export declare function combinedOutput(stdout: string, stderr: string): string;
|
|
39
|
+
//# sourceMappingURL=run-child.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-child.d.ts","sourceRoot":"","sources":["../../src/child/run-child.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAK7C,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,YAAY,EAAE,SAAS,CAAC;IACxB,0DAA0D;IAC1D,eAAe,EAAE,MAAM,OAAO,CAAC;IAC/B,iEAAiE;IACjE,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,GAAG,SAAS,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,YAAY,GACpB;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,GACD;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAiBN;;GAEG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAsHrE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGrE"}
|