@bluewombat/integrator 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 +92 -0
- package/SPECS.md +381 -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 +222 -0
- package/dist/args/parse-args.js.map +1 -0
- package/dist/child/run-child.d.ts +41 -0
- package/dist/child/run-child.d.ts.map +1 -0
- package/dist/child/run-child.js +145 -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/fold/backend.d.ts +32 -0
- package/dist/fold/backend.d.ts.map +1 -0
- package/dist/fold/backend.js +2 -0
- package/dist/fold/backend.js.map +1 -0
- package/dist/fold/fold.d.ts +32 -0
- package/dist/fold/fold.d.ts.map +1 -0
- package/dist/fold/fold.js +49 -0
- package/dist/fold/fold.js.map +1 -0
- package/dist/fold/working-files.d.ts +28 -0
- package/dist/fold/working-files.d.ts.map +1 -0
- package/dist/fold/working-files.js +122 -0
- package/dist/fold/working-files.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/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-integrator.d.ts +35 -0
- package/dist/run/run-integrator.d.ts.map +1 -0
- package/dist/run/run-integrator.js +172 -0
- package/dist/run/run-integrator.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 +32 -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,92 @@
|
|
|
1
|
+
# Integrator
|
|
2
|
+
|
|
3
|
+
Transformer: runs **one Integration**. It takes a Child directory and a
|
|
4
|
+
Parent directory, both already existing, and folds the Child's working files
|
|
5
|
+
into the Parent. Never forced: `integrated` or `conflict`.
|
|
6
|
+
|
|
7
|
+
Behavioural contract: [SPECS.md](./SPECS.md).
|
|
8
|
+
|
|
9
|
+
## Stack
|
|
10
|
+
|
|
11
|
+
Repository stack — TypeScript, Node 24.20, Biome, `node:test`. See [docs/DEVELOPMENT.md](../../../docs/DEVELOPMENT.md).
|
|
12
|
+
|
|
13
|
+
## Setup
|
|
14
|
+
|
|
15
|
+
From the repository root:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
nvm use
|
|
19
|
+
npm install
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Commands
|
|
23
|
+
|
|
24
|
+
| Task | Command |
|
|
25
|
+
| --------- | ---------------- |
|
|
26
|
+
| Lint | `npm run lint` |
|
|
27
|
+
| Format | `npm run format` |
|
|
28
|
+
| Typecheck | `npm run tsc` |
|
|
29
|
+
| Test | `npm test` |
|
|
30
|
+
| Build | `npm run build` |
|
|
31
|
+
|
|
32
|
+
Binary after build: `dist/cli.js` (package bin name `integrator`).
|
|
33
|
+
|
|
34
|
+
## Run
|
|
35
|
+
|
|
36
|
+
Parent and Child must already exist. Example:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm run build
|
|
40
|
+
node dist/cli.js \
|
|
41
|
+
--id feat-1 \
|
|
42
|
+
--parent /absolute/path/to/parent \
|
|
43
|
+
--child /absolute/path/to/child \
|
|
44
|
+
--duration-ms 60000 \
|
|
45
|
+
--strategy @bluewombat/isolation-copy
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The CLI requires `--strategy`: a package name or path that exports `strategy` with a `fold` backend. Integrator does not sniff `.git` and does not choose git versus copy.
|
|
49
|
+
|
|
50
|
+
Progress is JSON lines on stdout (`status`, `integration-started`,
|
|
51
|
+
`integration-finished`). Exit codes: `0` integrated, `1` conflict, `2`
|
|
52
|
+
invalid-invocation, `3` failed, `130` interrupted.
|
|
53
|
+
|
|
54
|
+
## Import
|
|
55
|
+
|
|
56
|
+
Same Transformer, in process. `cli.ts` is an adapter over this function — it reads argv
|
|
57
|
+
and stdin, calls `runIntegrator`, and maps the outcome to an exit code. Nothing the CLI
|
|
58
|
+
can do is unreachable from here.
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import { strategy } from "@bluewombat/isolation-copy";
|
|
62
|
+
import { runIntegrator } from "@bluewombat/integrator";
|
|
63
|
+
|
|
64
|
+
const result = await runIntegrator({
|
|
65
|
+
invocation, // same shape the CLI builds from argv
|
|
66
|
+
backend: strategy.fold, // Host / CLI loads a strategy package
|
|
67
|
+
write: (line) => events.push(line), // progress as values, not stdout
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`src/index.ts` exports `runIntegrator`, `FoldBackend`, `RunOptions` /
|
|
72
|
+
`RunResult`, `ProgressWriter`, and this Transformer's domain types. Isolation
|
|
73
|
+
strategies live under `packages/plugins/isolation-*`.
|
|
74
|
+
|
|
75
|
+
## Layout
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
SPECS.md behavioural contract
|
|
79
|
+
README.md how to build and run
|
|
80
|
+
src/
|
|
81
|
+
cli.ts entry
|
|
82
|
+
types.ts Transformer-owned types
|
|
83
|
+
args/ CLI parsing
|
|
84
|
+
status/ Status labels and --on-status
|
|
85
|
+
progress/ JSON-line progress writer
|
|
86
|
+
child/ spawn (--on-status)
|
|
87
|
+
fold/ fold via injected FoldBackend (snapshot restore + contract)
|
|
88
|
+
run/ invocation orchestration
|
|
89
|
+
fixtures/ fake --on-status scripts for tests
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Sources stay colocated: helpers used once live next to their caller.
|
package/SPECS.md
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
# Integrator
|
|
2
|
+
|
|
3
|
+
Independent Transformer: it has a binary, a contract, and nothing else. Integrator is
|
|
4
|
+
alone. Its code, identifiers, comments, and messages name only what it owns: the
|
|
5
|
+
Integration, its arguments, the Parent path, the Child path, Status, clocks, and
|
|
6
|
+
the Integration outcome. No other component is mentioned there, because none of
|
|
7
|
+
them exist inside this perimeter.
|
|
8
|
+
|
|
9
|
+
Integrator runs **one Integration**. It takes a Child directory and a Parent
|
|
10
|
+
directory, both of which already exist. It folds the Child's working files into
|
|
11
|
+
the Parent's working files. It never forces that fold: when the two trees cannot
|
|
12
|
+
be combined without choosing a side, the outcome is `conflict`.
|
|
13
|
+
|
|
14
|
+
The invocation is always the same. How Integrator folds is an injected
|
|
15
|
+
**Fold backend** (`fold`). Integrator does not choose a strategy. The CLI
|
|
16
|
+
requires `--strategy <specifier>`; Host loads the package named in
|
|
17
|
+
`workLine.isolation`. Strategies live under `packages/plugins/isolation-*`.
|
|
18
|
+
|
|
19
|
+
Integrator does not create either directory. It does not delete either
|
|
20
|
+
directory. It does not run work in either directory. A directory that is Parent
|
|
21
|
+
of one Integration may be Child of another; Integrator does not know or care.
|
|
22
|
+
|
|
23
|
+
Stack and binary layout: [README.md](./README.md).
|
|
24
|
+
|
|
25
|
+
## 1. Job
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
arguments Integrator disk
|
|
29
|
+
--------- ---------- ----
|
|
30
|
+
Integration one invocation write Parent only on `integrated`
|
|
31
|
+
Parent fold Child working files do not write Child working files
|
|
32
|
+
Child into Parent, never forced do not create or delete either
|
|
33
|
+
bounds
|
|
34
|
+
← Integration outcome + Status
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
**In:** arguments. **Out:** one Integration outcome, and a live Status each time
|
|
38
|
+
it changes. Integrator does not wait for a listener to acknowledge.
|
|
39
|
+
|
|
40
|
+
## 2. Options
|
|
41
|
+
|
|
42
|
+
Integrator is invoked with arguments. It does not read an input file. It does
|
|
43
|
+
not read configuration from the Parent or the Child.
|
|
44
|
+
|
|
45
|
+
| Argument | Content |
|
|
46
|
+
| ------------------------ | ------------------------------------------------------------------------------------------------------- |
|
|
47
|
+
| `--id` | Integration id. Copied onto every Status and progress line. Non-empty. |
|
|
48
|
+
| `--parent` | Absolute path. Must already exist as a directory. Destination of the fold. |
|
|
49
|
+
| `--child` | Absolute path. Must already exist as a directory. Source of the fold. Integrator does not create this. |
|
|
50
|
+
| `--duration-ms` | Positive integer. Wall clock of the Integration, from the moment Integrator starts folding into Parent. |
|
|
51
|
+
| `--strategy` | Package name or path. CLI only. Loads `strategy.fold`. `runIntegrator` receives the backend as an argument; it never chooses one. |
|
|
52
|
+
| `--on-status -- <argv…>` | Optional. Command to run each time Status changes. Omitted: Status still goes to stdout. |
|
|
53
|
+
|
|
54
|
+
The import face may also pass `subject` and `mergeSubject` through to the Fold backend (commit messages for the fold). They are not CLI arguments.
|
|
55
|
+
|
|
56
|
+
No other argument is read.
|
|
57
|
+
|
|
58
|
+
Malformed arguments, empty id, non-absolute path, missing Parent, missing Child,
|
|
59
|
+
Parent or Child not a directory, Parent and Child the same path, Parent a prefix
|
|
60
|
+
of Child, Child a prefix of Parent, or a non-positive `--duration-ms` →
|
|
61
|
+
Integration outcome `invalid-invocation`. No fold is attempted. Parent and Child
|
|
62
|
+
are left as they were.
|
|
63
|
+
|
|
64
|
+
## 3. Workflow
|
|
65
|
+
|
|
66
|
+
One invocation runs one Integration. There is no loop.
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
Check arguments and paths (§2). Unusable → `invalid-invocation`.
|
|
70
|
+
Announce Status `integrating`.
|
|
71
|
+
Start the Integration clock.
|
|
72
|
+
Fold the Child's working files into the Parent (§4).
|
|
73
|
+
If the fold cannot complete without choosing a side
|
|
74
|
+
→ restore Parent to invocation start → Integration outcome `conflict`.
|
|
75
|
+
If the clock fires, a stop signal arrives, or the fold cannot complete
|
|
76
|
+
for a reason that is not a conflict
|
|
77
|
+
→ restore Parent to invocation start → Integration outcome `failed` or `interrupted` (§5).
|
|
78
|
+
If the fold completes without choosing a side
|
|
79
|
+
→ Integration outcome `integrated`. Parent holds the result. Child stays as it was.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```mermaid
|
|
83
|
+
flowchart TD
|
|
84
|
+
START[Check arguments] --> OK{Usable?}
|
|
85
|
+
OK -->|no| INV[invalid-invocation]
|
|
86
|
+
OK -->|yes| MER[Fold Child into Parent]
|
|
87
|
+
MER -->|complete, no side chosen| DONE[integrated]
|
|
88
|
+
MER -->|cannot combine without choosing a side| CON[conflict — Parent restored]
|
|
89
|
+
MER -->|clock| FAIL[failed — Parent restored]
|
|
90
|
+
MER -->|stop signal| INT[interrupted — Parent restored]
|
|
91
|
+
MER -->|cannot complete| FAIL
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## 4. Integration
|
|
95
|
+
|
|
96
|
+
Integration is a property of two directories after a successful invocation. It
|
|
97
|
+
is not a later process, not a snapshot, and not a lock on either directory.
|
|
98
|
+
|
|
99
|
+
### Fold backend
|
|
100
|
+
|
|
101
|
+
Integrator does not choose a strategy. The caller injects a `FoldBackend`.
|
|
102
|
+
Strategies live under `packages/plugins/isolation-*` and export
|
|
103
|
+
`strategy: { isolation, fold }`.
|
|
104
|
+
|
|
105
|
+
The binary's `cli.ts` requires `--strategy <specifier>` and loads that package.
|
|
106
|
+
Host resolves `workLine.isolation` the same way. There is no `.git` sniff and no
|
|
107
|
+
`"git"` / `"copy"` alias. A strategy **conflict** is `conflict`. A strategy
|
|
108
|
+
failure that is not a conflict is `failed`, not a silent switch to another
|
|
109
|
+
method.
|
|
110
|
+
|
|
111
|
+
`.git` at the root of Parent or Child is not a working file. Integrator does
|
|
112
|
+
not fold it as content.
|
|
113
|
+
|
|
114
|
+
Same `--id`, `--parent`, `--child`. Same outcomes. The working-file contract
|
|
115
|
+
(§4) holds either way.
|
|
116
|
+
|
|
117
|
+
### Working files
|
|
118
|
+
|
|
119
|
+
At Integration start, Integrator reads each directory's **working files**: the
|
|
120
|
+
tree a process with that directory as its working directory would see as the
|
|
121
|
+
work.
|
|
122
|
+
|
|
123
|
+
When the Integration outcome is `integrated`:
|
|
124
|
+
|
|
125
|
+
- The Parent's working files are the combination of both trees: every change
|
|
126
|
+
that exists only in the Child is present in the Parent, and every change that
|
|
127
|
+
exists only in the Parent is still present in the Parent.
|
|
128
|
+
- The Child's working files are what they were at invocation start.
|
|
129
|
+
|
|
130
|
+
The contract is the working files. Git vs copy is how Integrator combines them.
|
|
131
|
+
|
|
132
|
+
Uncommitted working-file changes participate. Integrator does not ignore a
|
|
133
|
+
change because it is not a commit.
|
|
134
|
+
|
|
135
|
+
### Never force
|
|
136
|
+
|
|
137
|
+
Integrator never chooses a side to make a **conflict** succeed. It never
|
|
138
|
+
overwrites a conflicting Parent path with the Child, or the reverse. It never
|
|
139
|
+
deletes a conflicting Parent path to accept the Child. It never writes
|
|
140
|
+
conflict-marker content into Parent working files. It never passes a force
|
|
141
|
+
option to git. It never rewrites the Parent's git history (no hard reset of
|
|
142
|
+
existing commits, no discard of Parent commits) to make a merge succeed.
|
|
143
|
+
|
|
144
|
+
A merge commit that **adds** history is not a rewrite. Force-taking one side of
|
|
145
|
+
a conflict is.
|
|
146
|
+
|
|
147
|
+
### Conflict
|
|
148
|
+
|
|
149
|
+
A **conflict** is when the fold cannot complete without choosing a side.
|
|
150
|
+
|
|
151
|
+
On git, that is an overlapping independent change on the same path (both sides
|
|
152
|
+
edited it, or the types cannot be combined). Different bytes on a path is not
|
|
153
|
+
by itself a conflict: a change that exists on only one side is applied.
|
|
154
|
+
|
|
155
|
+
On copy, that is an incompatible type at the same path (file vs directory vs
|
|
156
|
+
symlink). Copy has no third tree, so it cannot see overlapping independent
|
|
157
|
+
edits; a same-type bytes difference is incoming Child work (§4 Copy merge), not
|
|
158
|
+
a conflict.
|
|
159
|
+
|
|
160
|
+
On `conflict`:
|
|
161
|
+
|
|
162
|
+
- Parent working files are what they were at invocation start. No partial fold
|
|
163
|
+
remains. No conflict-marker files remain.
|
|
164
|
+
- Child working files are what they were at invocation start.
|
|
165
|
+
- Both directories still exist.
|
|
166
|
+
|
|
167
|
+
`conflict` is a complete Integration outcome. It is not `failed`. The fold was
|
|
168
|
+
possible to attempt and must not be forced.
|
|
169
|
+
|
|
170
|
+
### Git merge
|
|
171
|
+
|
|
172
|
+
When Integrator uses git, it merges the Child into the Parent using git. This
|
|
173
|
+
is a three-way merge of working files. The Child is the incoming side. The
|
|
174
|
+
Parent is the destination side. Git's merge finds whether a path changed on
|
|
175
|
+
both sides independently.
|
|
176
|
+
|
|
177
|
+
| Situation | Result on Parent | Outcome |
|
|
178
|
+
| -------------------------------------------------------- | -------------------- | ----------- |
|
|
179
|
+
| Path changed only in the Child | Child's content | (continues) |
|
|
180
|
+
| Path changed only in the Parent | Parent's content | (continues) |
|
|
181
|
+
| Path unchanged on both, or still the same bytes | Parent's content | (continues) |
|
|
182
|
+
| Path changed on both, changes cannot be combined | restored, not merged | `conflict` |
|
|
183
|
+
| Git cannot run or cannot complete (not a merge conflict) | restored | `failed` |
|
|
184
|
+
|
|
185
|
+
When every path continues and the fold completes → `integrated`.
|
|
186
|
+
|
|
187
|
+
Integrator does not fall back to copy after a git conflict or a git failure.
|
|
188
|
+
|
|
189
|
+
If `--parent/.git` exists and the Child is not usable as a git incoming side
|
|
190
|
+
(missing `.git`, unrelated repo, git refuses the merge for a reason that is not
|
|
191
|
+
a content conflict), the outcome is `failed`, not `conflict`, not copy.
|
|
192
|
+
|
|
193
|
+
### Copy merge
|
|
194
|
+
|
|
195
|
+
When Integrator uses copy, it merges working files without git. Copy has no
|
|
196
|
+
ancestor tree, so it cannot tell a Parent-only edit from a Child-only edit on
|
|
197
|
+
the same path. The Child is the incoming working tree. Integrator applies this
|
|
198
|
+
path-wise fold, skipping `.git` only at the root of Parent and the root of
|
|
199
|
+
Child:
|
|
200
|
+
|
|
201
|
+
| Parent path | Child path | Action |
|
|
202
|
+
| -------------------------- | -------------------------- | ----------------------------------------- |
|
|
203
|
+
| Same type and bytes | Same type and bytes | Leave Parent as is |
|
|
204
|
+
| Missing | Present | Copy the Child path onto Parent |
|
|
205
|
+
| Present | Missing | Leave Parent as is (copy does not delete) |
|
|
206
|
+
| Same type, different bytes | Same type, different bytes | Take the Child's bytes (incoming work) |
|
|
207
|
+
| Incompatible types | Incompatible types | **conflict** |
|
|
208
|
+
|
|
209
|
+
Copy does not choose a side of a type conflict. A bytes difference is not a
|
|
210
|
+
type conflict: it is the Child's work being folded. Parent-only paths stay.
|
|
211
|
+
Child deletions are not applied: copy cannot tell a Child delete from a Parent
|
|
212
|
+
addition, so it does not delete.
|
|
213
|
+
|
|
214
|
+
On a `conflict` row, Integrator stops, restores Parent to invocation start,
|
|
215
|
+
and does not continue the walk as a partial fold.
|
|
216
|
+
|
|
217
|
+
### Parent
|
|
218
|
+
|
|
219
|
+
Integrator writes Parent working files only when the outcome is `integrated`.
|
|
220
|
+
On every other outcome, Parent working files are what they were at invocation
|
|
221
|
+
start.
|
|
222
|
+
|
|
223
|
+
If Integrator began to write and then hit `conflict`, `failed`, or
|
|
224
|
+
`interrupted`, it restores Parent before returning. A leftover merge in
|
|
225
|
+
progress (index, merge state) does not remain.
|
|
226
|
+
|
|
227
|
+
Integrator may write git bookkeeping that is not working content, if the
|
|
228
|
+
Parent's storage requires it to record a completed merge. That bookkeeping is
|
|
229
|
+
not a working file.
|
|
230
|
+
|
|
231
|
+
Integrator never deletes the Parent.
|
|
232
|
+
|
|
233
|
+
### Child
|
|
234
|
+
|
|
235
|
+
Both directories already exist. Integrator creates neither. Integrator does not
|
|
236
|
+
add, remove, or edit the Child's working files. After any outcome, those files
|
|
237
|
+
are what they were at invocation start.
|
|
238
|
+
|
|
239
|
+
Integrator does not delete the Child, including after `integrated`. Callers
|
|
240
|
+
that destroy a Child do so outside this process.
|
|
241
|
+
|
|
242
|
+
### What Integrator does not do
|
|
243
|
+
|
|
244
|
+
- Interpret files in the Parent or the Child (no language-aware merge of its own).
|
|
245
|
+
- Spawn a worker whose job is the content.
|
|
246
|
+
- Create a directory.
|
|
247
|
+
- Delete the Parent or the Child.
|
|
248
|
+
- Choose a Parent or Child path of its own: `--parent` and `--child` are the paths.
|
|
249
|
+
- Reuse a previous Integration's in-memory state: every invocation is the same job.
|
|
250
|
+
- Force a fold.
|
|
251
|
+
|
|
252
|
+
## 5. Clocks and interrupt
|
|
253
|
+
|
|
254
|
+
**Integration clock.** Starts when Integrator begins folding into the Parent. On
|
|
255
|
+
`--duration-ms`, Integrator stops the fold, restores Parent to invocation start,
|
|
256
|
+
Integration outcome `failed`. The report names the clock.
|
|
257
|
+
|
|
258
|
+
**Interrupt.** SIGINT and SIGTERM stop this invocation. Integrator stops the
|
|
259
|
+
fold, restores Parent to invocation start, Integration outcome `interrupted`.
|
|
260
|
+
It does **not** delete the Parent. It does **not** delete the Child. It does
|
|
261
|
+
**not** undo an Integration that already reached `integrated` (that Integration
|
|
262
|
+
is finished).
|
|
263
|
+
|
|
264
|
+
A stop signal that races a clock uses `interrupted`. A stop signal that races a
|
|
265
|
+
just-completed `integrated` fold uses `integrated`.
|
|
266
|
+
|
|
267
|
+
## 6. Status
|
|
268
|
+
|
|
269
|
+
Status is the live snapshot of this invocation. It changes at phase boundaries
|
|
270
|
+
(Integration about to run, Integration outcome known). It is not a history. The
|
|
271
|
+
`label` is meant to be shown as-is.
|
|
272
|
+
|
|
273
|
+
### Shape
|
|
274
|
+
|
|
275
|
+
| Field | Content |
|
|
276
|
+
| ------- | ------------------------------------------------------------------------------ |
|
|
277
|
+
| `phase` | `integrating`, `integrated`, `conflict`, `failed`, `interrupted`, or `invalid` |
|
|
278
|
+
| `id` | From `--id`. Absent on `invalid` when `--id` itself is unusable. |
|
|
279
|
+
| `label` | Canonical display string. See below. |
|
|
280
|
+
|
|
281
|
+
### Label
|
|
282
|
+
|
|
283
|
+
Built by Integrator. Do not invent another spelling.
|
|
284
|
+
|
|
285
|
+
| `phase` | `label` | Example |
|
|
286
|
+
| ------------- | ------------------ | -------------------- |
|
|
287
|
+
| `integrating` | `integrating:<id>` | `integrating:feat-1` |
|
|
288
|
+
| `integrated` | `integrated:<id>` | `integrated:feat-1` |
|
|
289
|
+
| `conflict` | `conflict:<id>` | `conflict:feat-1` |
|
|
290
|
+
| `failed` | `failed:<id>` | `failed:feat-1` |
|
|
291
|
+
| `interrupted` | `interrupted:<id>` | `interrupted:feat-1` |
|
|
292
|
+
| `invalid` | `invalid` | `invalid` |
|
|
293
|
+
|
|
294
|
+
`<id>` is the `--id` argument, as given.
|
|
295
|
+
|
|
296
|
+
### When it is announced
|
|
297
|
+
|
|
298
|
+
| Moment | `phase` |
|
|
299
|
+
| ------------------------------------------------------------------------ | ------------- |
|
|
300
|
+
| Arguments or paths unusable | `invalid` |
|
|
301
|
+
| Fold about to start | `integrating` |
|
|
302
|
+
| Integration outcome `integrated` / `conflict` / `failed` / `interrupted` | that outcome |
|
|
303
|
+
|
|
304
|
+
Announced on stdout as a JSON line (`event`: `status`) carrying the fields
|
|
305
|
+
above. If `--on-status` was given, Integrator also runs that command, cwd
|
|
306
|
+
unchanged (not the Parent, not the Child), and appends:
|
|
307
|
+
|
|
308
|
+
| Argument | Content |
|
|
309
|
+
| --------- | ---------------------------- |
|
|
310
|
+
| `--id` | Integration id, when present |
|
|
311
|
+
| `--label` | The label |
|
|
312
|
+
| `--phase` | The phase |
|
|
313
|
+
|
|
314
|
+
`--on-status` does not count against the Integration clock. A non-zero exit, a
|
|
315
|
+
missing command, or a hang that Integrator must kill does **not** change the
|
|
316
|
+
Integration outcome. Visibility must not take the Integration down.
|
|
317
|
+
|
|
318
|
+
## 7. Progress
|
|
319
|
+
|
|
320
|
+
JSON lines on stdout. A `status` line is the live snapshot (§6). The other
|
|
321
|
+
lines record the Integration.
|
|
322
|
+
|
|
323
|
+
| `event` | When |
|
|
324
|
+
| ---------------------- | ---------------------------- |
|
|
325
|
+
| `status` | Each time Status changes |
|
|
326
|
+
| `integration-started` | Fold about to start |
|
|
327
|
+
| `integration-finished` | Integration outcome is known |
|
|
328
|
+
|
|
329
|
+
Each line carries `id` when the Integration id is usable.
|
|
330
|
+
|
|
331
|
+
`integration-finished` also carries:
|
|
332
|
+
|
|
333
|
+
| Field | Content |
|
|
334
|
+
| --------- | --------------------------------------------------------------------------------------- |
|
|
335
|
+
| `outcome` | The Integration outcome (§8). |
|
|
336
|
+
| `parent` | Absolute `--parent` path. Present when the outcome is `integrated`. |
|
|
337
|
+
| `report` | Why, when `outcome` is `conflict`, `failed`, or `invalid-invocation`. Absent otherwise. |
|
|
338
|
+
|
|
339
|
+
Integrator creates no working file under the Child. It writes Parent working
|
|
340
|
+
files only on `integrated`. It deletes nothing under the Child. It deletes
|
|
341
|
+
nothing under the Parent except, on `integrated`, paths the fold must replace
|
|
342
|
+
as part of applying a Child-only change that is not a conflict.
|
|
343
|
+
|
|
344
|
+
## 8. Integration outcomes
|
|
345
|
+
|
|
346
|
+
Exactly one per invocation. The meaning is entirely inside this process.
|
|
347
|
+
|
|
348
|
+
| Outcome | Meaning |
|
|
349
|
+
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
350
|
+
| `invalid-invocation` | Arguments or paths unusable. No fold attempted. Parent and Child untouched. |
|
|
351
|
+
| `integrated` | Parent working files hold the combined trees. Child unchanged. Both stay. |
|
|
352
|
+
| `conflict` | Fold cannot complete without choosing a side. Parent restored to invocation start. Child unchanged. Both stay. |
|
|
353
|
+
| `failed` | Integration started and could not complete (clock, I/O, spawn of Integrator's own tools, git failure that is not a merge conflict). Parent restored. Child unchanged. |
|
|
354
|
+
| `interrupted` | Stop signal before `integrated` or `conflict`. Parent restored. Child unchanged. |
|
|
355
|
+
|
|
356
|
+
No partial Integration. After this process exits, Parent working files are
|
|
357
|
+
either what they were at invocation start, or the complete `integrated` result.
|
|
358
|
+
|
|
359
|
+
## 9. Acceptance
|
|
360
|
+
|
|
361
|
+
1. Child has a path the Parent does not; Integration completes → `integrated`; Parent has that path with the Child's content; Child unchanged.
|
|
362
|
+
2. Parent has a path the Child does not; Integration completes → `integrated`; that Parent path is still there; Child unchanged.
|
|
363
|
+
3. A path exists in both with the same content; Integration completes → `integrated`; that path unchanged on Parent; Child unchanged.
|
|
364
|
+
4. `@bluewombat/isolation-git`; a path changed only in the Child (Parent still has the pre-change bytes) → `integrated`; Parent has the Child's bytes; Child unchanged.
|
|
365
|
+
5. `@bluewombat/isolation-git`; a path changed only in the Parent (Child still has the pre-change bytes) → `integrated`; Parent keeps its bytes; Child unchanged.
|
|
366
|
+
6. `@bluewombat/isolation-git`; both sides changed the same path with different bytes that git cannot combine → `conflict`; Parent still has its invocation-start content; Child unchanged; no conflict-marker files on Parent.
|
|
367
|
+
7. `@bluewombat/isolation-copy`; a path exists in both with different bytes of the same type → `integrated`; Parent has the Child's bytes (copy incoming work); Child unchanged.
|
|
368
|
+
8. A path exists in both with incompatible types → `conflict`; Parent restored; Child unchanged.
|
|
369
|
+
9. `--child` missing, `--parent` missing, relative path, empty `--id`, `--child` inside `--parent`, or `--parent` inside `--child` → `invalid-invocation`; both directories left as they were when they existed.
|
|
370
|
+
10. SIGTERM during the fold → `interrupted`; Parent working files are the invocation-start tree; Child remains on disk with its invocation-start tree.
|
|
371
|
+
11. Integration clock fires during the fold → `failed`; Parent restored; Child remains; report names the clock.
|
|
372
|
+
12. Integrator never deletes the Parent, never deletes the Child, never writes a working file of its own into the Child, never chooses a side on a conflict, never leaves a partial fold on Parent.
|
|
373
|
+
13. A directory that was Parent of one Integration can be `--child` of another; that second Integration is the same job.
|
|
374
|
+
14. Entering the fold with `--id feat-1` announces `label` `integrating:feat-1` on stdout, and via `--on-status` when that argument is set.
|
|
375
|
+
15. `--on-status` exiting non-zero does not change an `integrated` Integration.
|
|
376
|
+
16. `@bluewombat/isolation-git` → git inside; a git merge conflict is `conflict`, not copy; Parent restored; Child unchanged.
|
|
377
|
+
17. `@bluewombat/isolation-copy` → copy inside; a same-type bytes difference is taken from the Child, not `conflict`.
|
|
378
|
+
18. `@bluewombat/isolation-git` and git cannot complete for a reason that is not a merge conflict → `failed`, not a copy, not `conflict`.
|
|
379
|
+
19. The CLI requires `--strategy <specifier>`; `runIntegrator` never chooses a strategy.
|
|
380
|
+
|
|
381
|
+
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,CAoJrD"}
|