@bluewombat/runtime 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 +473 -0
- package/SPECS.md +303 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +172 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/defaults.d.ts +17 -0
- package/dist/config/defaults.d.ts.map +1 -0
- package/dist/config/defaults.js +17 -0
- package/dist/config/defaults.js.map +1 -0
- package/dist/config/find-config.d.ts +9 -0
- package/dist/config/find-config.d.ts.map +1 -0
- package/dist/config/find-config.js +25 -0
- package/dist/config/find-config.js.map +1 -0
- package/dist/config/home.d.ts +17 -0
- package/dist/config/home.d.ts.map +1 -0
- package/dist/config/home.js +23 -0
- package/dist/config/home.js.map +1 -0
- package/dist/config/load-config.d.ts +13 -0
- package/dist/config/load-config.d.ts.map +1 -0
- package/dist/config/load-config.js +537 -0
- package/dist/config/load-config.js.map +1 -0
- package/dist/config/parse-args.d.ts +25 -0
- package/dist/config/parse-args.d.ts.map +1 -0
- package/dist/config/parse-args.js +478 -0
- package/dist/config/parse-args.js.map +1 -0
- package/dist/config/types.d.ts +144 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/loop/authority.d.ts +51 -0
- package/dist/loop/authority.d.ts.map +1 -0
- package/dist/loop/authority.js +166 -0
- package/dist/loop/authority.js.map +1 -0
- package/dist/loop/context.d.ts +44 -0
- package/dist/loop/context.d.ts.map +1 -0
- package/dist/loop/context.js +2 -0
- package/dist/loop/context.js.map +1 -0
- package/dist/loop/cursor.d.ts +4 -0
- package/dist/loop/cursor.d.ts.map +1 -0
- package/dist/loop/cursor.js +20 -0
- package/dist/loop/cursor.js.map +1 -0
- package/dist/loop/deliveries.d.ts +22 -0
- package/dist/loop/deliveries.d.ts.map +1 -0
- package/dist/loop/deliveries.js +240 -0
- package/dist/loop/deliveries.js.map +1 -0
- package/dist/loop/describe.d.ts +40 -0
- package/dist/loop/describe.d.ts.map +1 -0
- package/dist/loop/describe.js +48 -0
- package/dist/loop/describe.js.map +1 -0
- package/dist/loop/drive.d.ts +15 -0
- package/dist/loop/drive.d.ts.map +1 -0
- package/dist/loop/drive.js +42 -0
- package/dist/loop/drive.js.map +1 -0
- package/dist/loop/journal.d.ts +22 -0
- package/dist/loop/journal.d.ts.map +1 -0
- package/dist/loop/journal.js +49 -0
- package/dist/loop/journal.js.map +1 -0
- package/dist/loop/lock.d.ts +11 -0
- package/dist/loop/lock.d.ts.map +1 -0
- package/dist/loop/lock.js +60 -0
- package/dist/loop/lock.js.map +1 -0
- package/dist/loop/message.d.ts +34 -0
- package/dist/loop/message.d.ts.map +1 -0
- package/dist/loop/message.js +48 -0
- package/dist/loop/message.js.map +1 -0
- package/dist/loop/open-host.d.ts +13 -0
- package/dist/loop/open-host.d.ts.map +1 -0
- package/dist/loop/open-host.js +180 -0
- package/dist/loop/open-host.js.map +1 -0
- package/dist/loop/probe.d.ts +9 -0
- package/dist/loop/probe.d.ts.map +1 -0
- package/dist/loop/probe.js +57 -0
- package/dist/loop/probe.js.map +1 -0
- package/dist/loop/report.d.ts +26 -0
- package/dist/loop/report.d.ts.map +1 -0
- package/dist/loop/report.js +328 -0
- package/dist/loop/report.js.map +1 -0
- package/dist/loop/tick.d.ts +24 -0
- package/dist/loop/tick.d.ts.map +1 -0
- package/dist/loop/tick.js +169 -0
- package/dist/loop/tick.js.map +1 -0
- package/dist/loop/trace.d.ts +16 -0
- package/dist/loop/trace.d.ts.map +1 -0
- package/dist/loop/trace.js +49 -0
- package/dist/loop/trace.js.map +1 -0
- package/dist/loop/transformers.d.ts +27 -0
- package/dist/loop/transformers.d.ts.map +1 -0
- package/dist/loop/transformers.js +229 -0
- package/dist/loop/transformers.js.map +1 -0
- package/dist/loop/work-line.d.ts +73 -0
- package/dist/loop/work-line.d.ts.map +1 -0
- package/dist/loop/work-line.js +109 -0
- package/dist/loop/work-line.js.map +1 -0
- package/dist/operator/board.d.ts +31 -0
- package/dist/operator/board.d.ts.map +1 -0
- package/dist/operator/board.js +67 -0
- package/dist/operator/board.js.map +1 -0
- package/dist/operator/cancel.d.ts +19 -0
- package/dist/operator/cancel.d.ts.map +1 -0
- package/dist/operator/cancel.js +70 -0
- package/dist/operator/cancel.js.map +1 -0
- package/dist/operator/doctor.d.ts +15 -0
- package/dist/operator/doctor.d.ts.map +1 -0
- package/dist/operator/doctor.js +416 -0
- package/dist/operator/doctor.js.map +1 -0
- package/dist/operator/git-remote.d.ts +39 -0
- package/dist/operator/git-remote.d.ts.map +1 -0
- package/dist/operator/git-remote.js +78 -0
- package/dist/operator/git-remote.js.map +1 -0
- package/dist/operator/init.d.ts +28 -0
- package/dist/operator/init.d.ts.map +1 -0
- package/dist/operator/init.js +522 -0
- package/dist/operator/init.js.map +1 -0
- package/dist/operator/live.d.ts +19 -0
- package/dist/operator/live.d.ts.map +1 -0
- package/dist/operator/live.js +149 -0
- package/dist/operator/live.js.map +1 -0
- package/dist/operator/prompt.d.ts +35 -0
- package/dist/operator/prompt.d.ts.map +1 -0
- package/dist/operator/prompt.js +125 -0
- package/dist/operator/prompt.js.map +1 -0
- package/dist/operator/setup.d.ts +18 -0
- package/dist/operator/setup.d.ts.map +1 -0
- package/dist/operator/setup.js +62 -0
- package/dist/operator/setup.js.map +1 -0
- package/dist/plugins/discover.d.ts +13 -0
- package/dist/plugins/discover.d.ts.map +1 -0
- package/dist/plugins/discover.js +81 -0
- package/dist/plugins/discover.js.map +1 -0
- package/dist/plugins/isolation.d.ts +78 -0
- package/dist/plugins/isolation.d.ts.map +1 -0
- package/dist/plugins/isolation.js +64 -0
- package/dist/plugins/isolation.js.map +1 -0
- package/dist/plugins/load.d.ts +35 -0
- package/dist/plugins/load.d.ts.map +1 -0
- package/dist/plugins/load.js +109 -0
- package/dist/plugins/load.js.map +1 -0
- package/dist/plugins/manager.d.ts +43 -0
- package/dist/plugins/manager.d.ts.map +1 -0
- package/dist/plugins/manager.js +47 -0
- package/dist/plugins/manager.js.map +1 -0
- package/dist/plugins/persist.d.ts +33 -0
- package/dist/plugins/persist.d.ts.map +1 -0
- package/dist/plugins/persist.js +26 -0
- package/dist/plugins/persist.js.map +1 -0
- package/package.json +66 -0
package/SPECS.md
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# Host
|
|
2
|
+
|
|
3
|
+
The composition root, not a Transformer. It is the process you run: Cursor, admission,
|
|
4
|
+
Conductor, report. It is not a FeatureStandard transformer and it is not a
|
|
5
|
+
sequencer — Conductor sequences; this package calls it.
|
|
6
|
+
|
|
7
|
+
Host does not know a tracker. It resolves one FeatureManager package, hands it
|
|
8
|
+
the options it never reads, and drives the `ManagerPort` that package returns.
|
|
9
|
+
Adding GitLab or Jira changes nothing here.
|
|
10
|
+
|
|
11
|
+
## 1. Job
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
boot Host, each tick others
|
|
15
|
+
---- --------------- ------
|
|
16
|
+
paths + slots listen: drain the manager since the manager package
|
|
17
|
+
manager + its options the Cursor WorkLedger
|
|
18
|
+
the plugins (isolation, probe: abandon what the tracker Conductor
|
|
19
|
+
persist) no longer lists Publisher / Refresher slots
|
|
20
|
+
the work line copy refresh the work line copy
|
|
21
|
+
one Delivery at a time:
|
|
22
|
+
admit / ready / cancel,
|
|
23
|
+
reconcile, drive, report,
|
|
24
|
+
save Cursor
|
|
25
|
+
sweep: drive what is in flight
|
|
26
|
+
or received, report
|
|
27
|
+
← idle | ran | stopped
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**In:** WorkLineStable, how to isolate and fold it (`workLine.isolation`),
|
|
31
|
+
workspace root, ledger root, a manager specifier and its opaque options,
|
|
32
|
+
Planner / Builder / Gate argv.
|
|
33
|
+
**Out:** a typed result. The CLI maps that to an exit code.
|
|
34
|
+
|
|
35
|
+
## 2. Faces
|
|
36
|
+
|
|
37
|
+
| Face | Entry | Must not |
|
|
38
|
+
| ------ | ------------------------------------------------------------------- | --------------------------------------------- |
|
|
39
|
+
| Import | `openHost(options)` then `runOnce` / `run` | Live inside Conductor `src/run/` |
|
|
40
|
+
| CLI | `mason run \| watch \| status \| cancel \| init \| setup \| doctor` | Interpret a FeatureStandard; pick Child paths |
|
|
41
|
+
|
|
42
|
+
`src/loop/` is the process: `open-host.ts` opens packages (composition),
|
|
43
|
+
`tick.ts` runs the listen / probe / Cursor / sweep loop, `deliveries.ts` handles one
|
|
44
|
+
Delivery, `drive.ts` runs one Project and reports on the Feature that ran,
|
|
45
|
+
`report.ts` maps Conductor outcomes to FeatureManager Events,
|
|
46
|
+
`journal.ts` and `trace.ts` are its film and its stdout. `loop/` may import
|
|
47
|
+
Transformer packages: this package **is** the composition root for the
|
|
48
|
+
execution Transformers. Conductor still must not. Host must not import a
|
|
49
|
+
tracker or an isolation strategy by name: both reach it through `plugins/`.
|
|
50
|
+
§ 1–7 describe `loop/`; § 8 describes `operator/`. The layers and the one
|
|
51
|
+
import rule between them are in [README.md](./README.md) § Layers.
|
|
52
|
+
|
|
53
|
+
## 3. Configuration
|
|
54
|
+
|
|
55
|
+
`mason.config.json`, found by walking up from the working directory, or the
|
|
56
|
+
file `--config` names. Relative paths in the file resolve against the file;
|
|
57
|
+
relative paths in a flag resolve against the working directory. Flags override
|
|
58
|
+
the file. `--manager-option key=value` merges per key, so overriding one option
|
|
59
|
+
does not drop the others; a repeated key becomes an array.
|
|
60
|
+
|
|
61
|
+
Host validates only its own keys. `managerOptions` is copied through untouched:
|
|
62
|
+
a tracker's fields are that package's business, and its errors are that
|
|
63
|
+
package's words.
|
|
64
|
+
|
|
65
|
+
## 4. Loading a manager
|
|
66
|
+
|
|
67
|
+
`manager` is a package name or a path. Resolution imports the bare specifier
|
|
68
|
+
first — mason and its managers installed side by side in one project — then
|
|
69
|
+
walks up from the config file's directory, which covers a global `mason`
|
|
70
|
+
driving a locally installed manager. A module without `createManager` is
|
|
71
|
+
refused by name, and a manager that cannot read its options returns a reason,
|
|
72
|
+
never a throw.
|
|
73
|
+
|
|
74
|
+
Secrets never pass through Host. The manager reads them from the environment
|
|
75
|
+
it is handed.
|
|
76
|
+
|
|
77
|
+
## 5. Cursor
|
|
78
|
+
|
|
79
|
+
Path: `<ledgerRoot>/cursor`. Contents: the last committed Listener Cursor, or
|
|
80
|
+
absent. `runOnce` passes it as the manager's `since`. After each Delivery is
|
|
81
|
+
handled (including skipped / invalid), the Cursor is that Delivery's name.
|
|
82
|
+
`unavailable` / interrupt does **not** advance the Cursor: the Delivery is
|
|
83
|
+
retried on the next tick.
|
|
84
|
+
|
|
85
|
+
A crash may replay one Delivery. Handlers must tolerate a repeat: admit is
|
|
86
|
+
idempotent on `key`; a manager may append an Event twice — accepted trade for
|
|
87
|
+
not losing an Event.
|
|
88
|
+
|
|
89
|
+
## 6. One Delivery
|
|
90
|
+
|
|
91
|
+
`adapt` first. Then:
|
|
92
|
+
|
|
93
|
+
| Adapter | Host |
|
|
94
|
+
| ------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
95
|
+
| `invalid` (new, or the intention changed) | `recordInvalid`, emit `invalid` |
|
|
96
|
+
| `invalid` (same fingerprint as recorded) | leave it; the tracker was told, and telling it is what delivered it again |
|
|
97
|
+
| `upsert` (new/invalid) | `admit`, emit `accepted`, then `runProject` when the Project is free; a Project frozen by an escalation queues the Feature (journal `queued`, one `progress` Event) and the sweep starts it once the Project is free. Post-run Events (`planned` / `done` / `escalated`) are reported on the Feature that was driven, not on the delivered key. `progress` (once per refusal) when the Authority sent the Submission back and a repair is on its way |
|
|
98
|
+
| `upsert` (in-flight / terminal) | leave it; do not restart. In-flight is `planning`, `running`, `escalated`, `integrating`, `submitted`; terminal is `merging`, `done`, `cancelled`. An echo of a Host report (Submitted, a progress comment) is this row: do not admit it |
|
|
99
|
+
| `upsert` (`received`) | same drive as a new upsert (no second `accepted`) |
|
|
100
|
+
| `upsert` + `signalsReady` while `escalated` | same as `ready` — a poll snapshot has no `labeled` edge |
|
|
101
|
+
| `ready` | `resumeReady`, emit `resumed`, `runProject`, then the same post-run Events |
|
|
102
|
+
| `cancel` | `conductor.cancel`. `cancelled`, or `reject_late` when the ledger says point of no return; nothing on `done` (the issue closing is the Submission's own doing) or `cancelled` |
|
|
103
|
+
| `unavailable` / interrupt | stop the tick |
|
|
104
|
+
|
|
105
|
+
`runProject` is always preceded by `reconcile` on that Project. Host never
|
|
106
|
+
drives an `escalated` Feature: that state is frozen until a human `ready`.
|
|
107
|
+
|
|
108
|
+
Every Event Host emits is a write to the tracker, and a tracker that lists by
|
|
109
|
+
"last updated" delivers the intention again on the next pass because of that
|
|
110
|
+
write. No row above may emit on that echo: `invalid` is keyed by fingerprint,
|
|
111
|
+
`accepted` by the ledger not knowing the key (or knowing it `invalid`), the
|
|
112
|
+
queued `progress` by `eventId`, the post-run Events by the Feature that was
|
|
113
|
+
driven, `resumed` by taking the signal back, `cancelled` by the ledger
|
|
114
|
+
refusing a second cancel, an in-flight Feature (including `submitted`) by
|
|
115
|
+
leaving the upsert.
|
|
116
|
+
|
|
117
|
+
On top of that, every Event that states a fact carries an `eventId`, so a
|
|
118
|
+
manager that already has it says nothing — after a restart as much as within
|
|
119
|
+
a pass. The id names the fact: `<key>:accepted:<fingerprint>` and
|
|
120
|
+
`<key>:invalid:<fingerprint>` (an edit is a new fact), `<key>:planned:<planned_at>`,
|
|
121
|
+
`<key>:integrated:<subtask>`, `<key>:submitted:<reference>`,
|
|
122
|
+
`<key>:refused:<n>`, `<key>:queued:<blocker>`, `<key>:resumed:<round>`,
|
|
123
|
+
`<key>:escalated:<round>:<kind>[:<subtask>]`, `<key>:done`,
|
|
124
|
+
`<key>:cancelled`, `<key>:reject_late:…`. The round is the ledger's count of
|
|
125
|
+
`ready` taken: a Plan refused, resumed and refused again has the same Attempt
|
|
126
|
+
count both times, and only the round tells the two escalations apart.
|
|
127
|
+
`escalation_reminder` alone would carry none, repetition being its point.
|
|
128
|
+
|
|
129
|
+
## 7. Loop
|
|
130
|
+
|
|
131
|
+
`run`: `runOnce` then, if `pollIntervalMs` is set, sleep and repeat until
|
|
132
|
+
interrupt.
|
|
133
|
+
|
|
134
|
+
SIGINT / SIGTERM: set the interrupt flag, `conductor.pause()`, stop after the
|
|
135
|
+
current Delivery.
|
|
136
|
+
|
|
137
|
+
Each pass appends JSON lines to `<ledgerRoot>/events.jsonl` (listen, probed,
|
|
138
|
+
Transformer progress, admitted, reported, queued, idle, a heartbeat while
|
|
139
|
+
`submitted`). That file is a film, not truth: a crash may drop the last lines;
|
|
140
|
+
the ledger is still right. `mason run` still writes a human Trace on stdout.
|
|
141
|
+
The journal is how another process attaches.
|
|
142
|
+
|
|
143
|
+
After listen, if the manager declares `probe` and the listen reached the source
|
|
144
|
+
(`completed`, `listened` — not `source-lost` / `interrupted` / `invalid-invocation`),
|
|
145
|
+
Host asks `probe` of every Feature abandon is still legal for (`received`,
|
|
146
|
+
`planning`, `running`, `escalated`, `integrating`, `submitted`). `gone` is the
|
|
147
|
+
same abandon as a `cancel` delivery, so a deleted item a poll can never list
|
|
148
|
+
still frees the Project; `unavailable` is not abandon. Probe runs before the
|
|
149
|
+
work-line refresh and the deliveries, so a cancel in this pass can start the
|
|
150
|
+
`received` queue on a copy that was just fast-forwarded.
|
|
151
|
+
|
|
152
|
+
The sweep after the deliveries drives every Project that has work in flight
|
|
153
|
+
**or** `received`, once per tick. The result is reported on the Feature that
|
|
154
|
+
was driven. A `received` Feature behind an escalation is journaled `queued`
|
|
155
|
+
and left; the next sweep that finds the Project free claims it. The same set
|
|
156
|
+
(`in-flight ∪ received`) decides whether this pass refreshes the work line
|
|
157
|
+
copy: starting a queued Feature on a copy that was not fast-forwarded this
|
|
158
|
+
tick would build on a version that no longer exists.
|
|
159
|
+
|
|
160
|
+
## 8. init, setup, doctor, watch, status and cancel
|
|
161
|
+
|
|
162
|
+
`init` writes a config that already runs: the Planner is the bootstrap one from
|
|
163
|
+
`@bluewombat/slots/planners/`, the Builder is a stub that says what to replace
|
|
164
|
+
(example Cursor CLI and Claude Code Builders live in `@bluewombat/slots/builders/`),
|
|
165
|
+
and the Gate sequence starts empty. Example Gates live in
|
|
166
|
+
`@bluewombat/slots/gates/` (`parent-clean`, `sensitive-path`,
|
|
167
|
+
`workspace-changed`, `ci-green`).
|
|
168
|
+
|
|
169
|
+
Two Gate sequences: `builder.gates` is judged on each Subtask, `assembly.gates`
|
|
170
|
+
on the feature they assemble into. A check that is right for one can be wrong for the
|
|
171
|
+
other — `workspace-changed` says an Attempt that changed nothing did nothing,
|
|
172
|
+
which is true of a Subtask and false of an assembly whose correct outcome is that
|
|
173
|
+
nothing was left to do. The assembly produces nothing unless something refused it
|
|
174
|
+
first: it is a judgement, and a refusal is `assembly.fix`, not a second first-pass.
|
|
175
|
+
|
|
176
|
+
Every child of a Task carries its own ceiling and no other. Every `cmd` names
|
|
177
|
+
its own `timeoutMs`, and none is inherited from a neighbour — nothing else
|
|
178
|
+
bounds a producer. A Gate takes its own `timeoutMs`,
|
|
179
|
+
or its sequence's `defaultTimeoutMs`, and a Gate that would end up with neither
|
|
180
|
+
is refused when the config loads. Nothing is derived from what another child
|
|
181
|
+
left behind, so what bounds a whole Task is arithmetic the Project can do:
|
|
182
|
+
the builder's `maxAttempts` times its producer's ceiling plus the sum of its Gates'.
|
|
183
|
+
An assembly fix is bounded the same way from `assembly.maxAttempts` and `assembly.fix`.
|
|
184
|
+
Root `timeoutMs` bounds what is outside a Task — the manager, the
|
|
185
|
+
isolations. Host has no flag named after a tracker (`--repo` is not a Host
|
|
186
|
+
flag): tracker fields come from that package.
|
|
187
|
+
|
|
188
|
+
At a terminal it asks rather than demands. Which manager comes from the packages
|
|
189
|
+
installed nearby that declare the `mason-manager` keyword — Host holds no list
|
|
190
|
+
of trackers, so a third-party one is offered the same way. A single one is named
|
|
191
|
+
and confirmed rather than assumed: picking it silently reads as though the tool
|
|
192
|
+
only speaks that tracker. None installed is an error naming the install
|
|
193
|
+
command. What that manager needs comes from its own `questionsManager`: it
|
|
194
|
+
declares the wording and the validation, Host reads the line. An option already
|
|
195
|
+
given on the command line is not asked for again.
|
|
196
|
+
|
|
197
|
+
WorkLineStable must exist before a run, so `init` inspects the path, names the
|
|
198
|
+
branch when it is a git tree, writes `workLine.isolation` to
|
|
199
|
+
`@bluewombat/isolation-git` or `@bluewombat/isolation-copy` from that inspection
|
|
200
|
+
(Isolator and Integrator do not choose a strategy; Host loads the package named
|
|
201
|
+
here), and offers to clone one —
|
|
202
|
+
after listing the
|
|
203
|
+
remote's branches and refusing a name that is not among them, because a
|
|
204
|
+
`git clone --branch` that misses complains about the repository rather than the
|
|
205
|
+
name that was wrong. `--clone REMOTE` (with an optional `--branch`, defaulting
|
|
206
|
+
to the remote's own HEAD) answers that question ahead of time, so a script
|
|
207
|
+
reaches the same place through the same code. An existing directory is never
|
|
208
|
+
re-cloned. `init` then runs `setup` and offers to apply it, so nothing has to be
|
|
209
|
+
re-run by hand.
|
|
210
|
+
|
|
211
|
+
A flag is read by the same question that would have asked for it, so
|
|
212
|
+
`--manager-option labels=mason` lands in the config in the shape a typed answer
|
|
213
|
+
would, and a malformed one is refused before anything is written. The setup plan
|
|
214
|
+
that follows never decides `init`'s exit code: it wrote its files, and
|
|
215
|
+
`mason init && mason setup --apply` must not stop because a token is not
|
|
216
|
+
exported yet.
|
|
217
|
+
|
|
218
|
+
`--manager` turns every question off, which is what a script wants;
|
|
219
|
+
`--interactive` forces them when stdin is a pipe. Overwriting an existing config
|
|
220
|
+
needs `--force`, or a yes to the question. Ctrl-C, Ctrl-D, or a pipe running dry
|
|
221
|
+
stops on the spot with `Cancelled. Nothing written.` and exit 130 — a read after
|
|
222
|
+
the input has ended raises rather than answering empty, so no question is ever
|
|
223
|
+
re-asked at a terminal nobody is at. A refused answer is re-asked at most three
|
|
224
|
+
times, each time saying what was wrong with it.
|
|
225
|
+
|
|
226
|
+
`setup` asks the manager to bring the tracker to the shape a run expects. Host
|
|
227
|
+
knows none of that shape: it resolves the manager, calls `setupManager`, and
|
|
228
|
+
prints the steps. Without `--apply` nothing is written — a plan says what is
|
|
229
|
+
`satisfied` and what is `missing`. With `--apply`, a step it fixed is `applied`.
|
|
230
|
+
A `blocked` step exits 1; a `missing` step in a plan does not. A manager with no
|
|
231
|
+
`setupManager` is reported as having nothing to do, and exits 0.
|
|
232
|
+
|
|
233
|
+
`doctor` reports one line per check and exits 1 on any `fail`: the Node
|
|
234
|
+
version, which config was found, whether the invocation is complete, whether
|
|
235
|
+
WorkLineStable exists (and whether it is a git tree), whether `workLine.isolation`
|
|
236
|
+
matches that tree and Authority, whether the created
|
|
237
|
+
directories have an existing ancestor, whether every slot command resolves,
|
|
238
|
+
whether the manager loads, and then the manager's own findings. It parses
|
|
239
|
+
without demanding that paths exist, so one missing directory does not hide
|
|
240
|
+
every other check, and it never uses the network.
|
|
241
|
+
|
|
242
|
+
`watch` and `status` are the operator live view. They open the ledger the same
|
|
243
|
+
way `run` does (`openFilesystemPersist` then `openWorkLedger`) and they do not
|
|
244
|
+
open a manager, Conductor, or Host. `status` prints a snapshot of every known
|
|
245
|
+
Feature and exits. `watch` prints that snapshot, then follows new journal lines
|
|
246
|
+
until SIGINT (exit 0). A missing journal is not an error: the snapshot still
|
|
247
|
+
stands. `--json` prints the snapshot as JSON. Ctrl-C on watch leaves the worker
|
|
248
|
+
running. The file can grow without rotation.
|
|
249
|
+
|
|
250
|
+
`cancel <key>` abandons one Feature the same way a `cancel` delivery does. The
|
|
251
|
+
team still abandons in the FeatureManager; this is the hatch when the tracker
|
|
252
|
+
cannot say the intention is gone (a manager with no `probe`, or an operator
|
|
253
|
+
who already knows) and the ledger would otherwise freeze the Project. It
|
|
254
|
+
takes the ledger lock — stop `run` first if it holds it. Exit 0 on cancel or
|
|
255
|
+
already cancelled, 1 when abandon is refused (`done`, point of no return), 2
|
|
256
|
+
when the key is missing or the ledger does not know it. The key is the first
|
|
257
|
+
positional: `cancel github:owner/name#19`.
|
|
258
|
+
|
|
259
|
+
## 9. Acceptance
|
|
260
|
+
|
|
261
|
+
1. Convertible upsert in an empty Source → WorkLineStable carries the Builder
|
|
262
|
+
marker, Thread `accepted`, `planned`, `done`, Cursor is that file name.
|
|
263
|
+
2. Unconvertible upsert → Thread `invalid`, no Conductor work, Cursor advanced.
|
|
264
|
+
3. Fail-blocking Gate, then a `ready` Event, then passing Gates → Thread
|
|
265
|
+
contains `escalated` then `resumed` then `done`.
|
|
266
|
+
4. `cancel` while `escalated` → Thread `cancelled`; WorkLineStable seed-only.
|
|
267
|
+
5. Re-running `runOnce` with the saved Cursor does not re-deliver the first Event.
|
|
268
|
+
6. GitHub: convertible issue (mocked API) → WorkLineStable marker, comments
|
|
269
|
+
`accepted`, `planned`, `done`.
|
|
270
|
+
7. GitHub: fail-blocking then the same issue with the ready label → `escalated`,
|
|
271
|
+
`resumed`, `done`.
|
|
272
|
+
8. A manager named by path, and one named by package, both load; a module without
|
|
273
|
+
`createManager` is refused by name.
|
|
274
|
+
9. `init --manager` then `doctor` in an empty directory reports exactly what is missing;
|
|
275
|
+
`init` without `--manager` and without a terminal is refused.
|
|
276
|
+
10. `setup` without `--apply` writes nothing, and names the flag that would;
|
|
277
|
+
a manager without `setupManager` exits 0 saying so.
|
|
278
|
+
11. The wizard names the only installed manager, repeats a question its manager
|
|
279
|
+
refused, and skips an option already passed as a flag.
|
|
280
|
+
12. `--clone` takes the named branch, falls back to the remote's default,
|
|
281
|
+
refuses a branch the remote does not carry, and re-clones nothing.
|
|
282
|
+
13. `list()` after admit of two keys returns two summaries; a refused command
|
|
283
|
+
does not appear; `listInFlight()` is the mid-flight subset.
|
|
284
|
+
14. A Transformer `status` line and a `gate-finished` line during `runProject`
|
|
285
|
+
appear in `<ledgerRoot>/events.jsonl`.
|
|
286
|
+
15. `watch` on a ledger with Features and no journal prints the snapshot,
|
|
287
|
+
including a `submitted` Feature's reference, and exits 0 on interrupt. It
|
|
288
|
+
does not import `openHost` or a manager package.
|
|
289
|
+
16. Two Features on one Project, the first `escalated`: admitting the second
|
|
290
|
+
emits `accepted` and one `progress` (queued), not `escalated`; the second
|
|
291
|
+
stays `received`. Cancelling the first in a later pass starts the second.
|
|
292
|
+
A `submitted` Feature that reaches `done` while a second is delivered
|
|
293
|
+
reports `done` on the first.
|
|
294
|
+
17. After an escalation, a `probe` of `gone` cancels that Feature and the sweep
|
|
295
|
+
starts the `received` queue in the same pass. `unavailable` leaves the
|
|
296
|
+
escalation. A listen that missed the source does not probe. GitHub: a 404
|
|
297
|
+
on `GET /issues/{n}` after a completed listen cancels, even when the
|
|
298
|
+
listing is empty. `cancel <key>` abandons an escalated Feature.
|
|
299
|
+
18. A Feature `submitted`, then the same upsert delivered again, then the
|
|
300
|
+
Authority refuses: Host skips the echo, records no `pending_fingerprint`,
|
|
301
|
+
and the next pass repairs. It does not escalate as a plan refusal.
|
|
302
|
+
|
|
303
|
+
How to install, configure and run: [README.md](./README.md).
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { PRODUCT } from "@bluewombat/manager-kit";
|
|
3
|
+
import { CONFIG_FILENAME } from "./config/find-config.js";
|
|
4
|
+
import { DEFAULT_HOME } from "./config/home.js";
|
|
5
|
+
import { parseArgs } from "./config/parse-args.js";
|
|
6
|
+
import { openHost } from "./loop/open-host.js";
|
|
7
|
+
import { runCancel } from "./operator/cancel.js";
|
|
8
|
+
import { runDoctor } from "./operator/doctor.js";
|
|
9
|
+
import { runInit } from "./operator/init.js";
|
|
10
|
+
import { runLive } from "./operator/live.js";
|
|
11
|
+
import { isInteractive, terminalAsk } from "./operator/prompt.js";
|
|
12
|
+
import { runSetup } from "./operator/setup.js";
|
|
13
|
+
const USAGE = `Usage: ${PRODUCT} <command>
|
|
14
|
+
|
|
15
|
+
run drain the FeatureManager, run Conductor, report
|
|
16
|
+
watch snapshot the ledger and follow the journal
|
|
17
|
+
status snapshot the ledger, then exit
|
|
18
|
+
cancel abandon a Feature by key (when the tracker cannot say it is gone)
|
|
19
|
+
init set this directory up — asks, writes, then runs setup
|
|
20
|
+
doctor check the config, the slots, and the manager
|
|
21
|
+
setup prepare the tracker (--apply to write; a plan without it)
|
|
22
|
+
|
|
23
|
+
init flags: --manager PKG --manager-option KEY=VALUE --work-line-stable DIR
|
|
24
|
+
--clone REMOTE [--branch NAME] --force --interactive
|
|
25
|
+
|
|
26
|
+
Shared flags: --config FILE --manager NAME --manager-option KEY=VALUE --home DIR
|
|
27
|
+
--work-line-stable DIR --work-line-branch NAME --workspace-root DIR --ledger DIR
|
|
28
|
+
--planner -- CMD --planner-timeout-ms N
|
|
29
|
+
--builder -- CMD --builder-timeout-ms N --builder-max-attempts N
|
|
30
|
+
--builder-repair -- CMD --builder-repair-timeout-ms N
|
|
31
|
+
--builder-gate ID -- CMD --builder-gate-timeout-ms N
|
|
32
|
+
--assembly-fix -- CMD --assembly-fix-timeout-ms N --assembly-max-attempts N
|
|
33
|
+
--assembly-gate ID -- CMD --assembly-gate-timeout-ms N
|
|
34
|
+
--timeout-ms N --poll-interval-ms N
|
|
35
|
+
|
|
36
|
+
A gate's --*-gate-timeout-ms comes before the --*-gate it bounds.
|
|
37
|
+
|
|
38
|
+
watch / status also take --json (snapshot as JSON).
|
|
39
|
+
|
|
40
|
+
Without --config, the nearest ${CONFIG_FILENAME} is used. --home is where Host
|
|
41
|
+
keeps its own files (default ${DEFAULT_HOME}): the ledger, the workspaces, its copy of
|
|
42
|
+
the work line.
|
|
43
|
+
`;
|
|
44
|
+
function installSignalHandlers(state) {
|
|
45
|
+
const onSignal = () => {
|
|
46
|
+
state.interrupted = true;
|
|
47
|
+
};
|
|
48
|
+
process.on("SIGINT", onSignal);
|
|
49
|
+
process.on("SIGTERM", onSignal);
|
|
50
|
+
return () => {
|
|
51
|
+
process.off("SIGINT", onSignal);
|
|
52
|
+
process.off("SIGTERM", onSignal);
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
async function run(argv) {
|
|
56
|
+
const parsed = parseArgs(argv, { cwd: process.cwd() });
|
|
57
|
+
if (!parsed.ok) {
|
|
58
|
+
process.stderr.write(`${parsed.reason}\n`);
|
|
59
|
+
return 2;
|
|
60
|
+
}
|
|
61
|
+
const interruptFlag = { interrupted: false };
|
|
62
|
+
const options = { ...parsed.invocation, interruptFlag };
|
|
63
|
+
const detachSignals = installSignalHandlers(interruptFlag);
|
|
64
|
+
let host;
|
|
65
|
+
try {
|
|
66
|
+
host = await openHost(options);
|
|
67
|
+
const result = await host.run();
|
|
68
|
+
if (result.lastRun?.outcome === "refused") {
|
|
69
|
+
return 1;
|
|
70
|
+
}
|
|
71
|
+
return interruptFlag.interrupted ? 130 : 0;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
75
|
+
return 2;
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
await host?.close();
|
|
79
|
+
detachSignals();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function main(argv) {
|
|
83
|
+
const command = argv[0];
|
|
84
|
+
const rest = argv.slice(1);
|
|
85
|
+
if (command === "run") {
|
|
86
|
+
return await run(rest);
|
|
87
|
+
}
|
|
88
|
+
if (command === "watch" || command === "status") {
|
|
89
|
+
const interruptFlag = { interrupted: false };
|
|
90
|
+
const detachSignals = installSignalHandlers(interruptFlag);
|
|
91
|
+
try {
|
|
92
|
+
return await runLive({
|
|
93
|
+
cwd: process.cwd(),
|
|
94
|
+
argv: rest,
|
|
95
|
+
write: (line) => process.stdout.write(line),
|
|
96
|
+
interruptFlag,
|
|
97
|
+
follow: command === "watch",
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
detachSignals();
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (command === "init") {
|
|
105
|
+
// Asking only makes sense at a terminal; a script gets the flags-only path.
|
|
106
|
+
// `--interactive` forces the questions when stdin is a pipe.
|
|
107
|
+
const wizard = (isInteractive() || rest.includes("--interactive")) && !rest.includes("--manager");
|
|
108
|
+
const terminal = wizard ? terminalAsk() : undefined;
|
|
109
|
+
try {
|
|
110
|
+
const result = await runInit({
|
|
111
|
+
cwd: process.cwd(),
|
|
112
|
+
argv: rest,
|
|
113
|
+
env: process.env,
|
|
114
|
+
write: (line) => process.stdout.write(line),
|
|
115
|
+
...(terminal === undefined ? {} : { ask: terminal.ask }),
|
|
116
|
+
});
|
|
117
|
+
if (!result.ok) {
|
|
118
|
+
process.stderr.write(`${result.reason}\n`);
|
|
119
|
+
return result.exitCode ?? 2;
|
|
120
|
+
}
|
|
121
|
+
return result.exitCode;
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
terminal?.close();
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (command === "setup") {
|
|
128
|
+
const interruptFlag = { interrupted: false };
|
|
129
|
+
const detachSignals = installSignalHandlers(interruptFlag);
|
|
130
|
+
try {
|
|
131
|
+
return await runSetup({
|
|
132
|
+
cwd: process.cwd(),
|
|
133
|
+
argv: rest,
|
|
134
|
+
env: process.env,
|
|
135
|
+
write: (line) => process.stdout.write(line),
|
|
136
|
+
interruptFlag,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
finally {
|
|
140
|
+
detachSignals();
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (command === "doctor") {
|
|
144
|
+
return await runDoctor({
|
|
145
|
+
cwd: process.cwd(),
|
|
146
|
+
argv: rest,
|
|
147
|
+
env: process.env,
|
|
148
|
+
write: (line) => process.stdout.write(line),
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
if (command === "cancel") {
|
|
152
|
+
const interruptFlag = { interrupted: false };
|
|
153
|
+
const detachSignals = installSignalHandlers(interruptFlag);
|
|
154
|
+
try {
|
|
155
|
+
return await runCancel({
|
|
156
|
+
cwd: process.cwd(),
|
|
157
|
+
argv: rest,
|
|
158
|
+
env: process.env,
|
|
159
|
+
write: (line) => process.stdout.write(line),
|
|
160
|
+
interruptFlag,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
detachSignals();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
process.stderr.write(USAGE);
|
|
168
|
+
return 2;
|
|
169
|
+
}
|
|
170
|
+
const exitCode = await main(process.argv.slice(2));
|
|
171
|
+
process.exitCode = exitCode;
|
|
172
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plugins Host ships with, by name — the one place these names are
|
|
3
|
+
* written. Host's code never imports a plugin; it loads one by the name a
|
|
4
|
+
* config gives, and these are the names `mason init` writes and `persist`
|
|
5
|
+
* falls back to. Host's package.json declares exactly these, so a config
|
|
6
|
+
* `init` wrote runs with nothing else installed. A manager has no default:
|
|
7
|
+
* Host cannot pick a tracker.
|
|
8
|
+
*/
|
|
9
|
+
/** Isolation by git worktree, for a work line that is a git tree. */
|
|
10
|
+
export declare const ISOLATION_GIT = "@bluewombat/isolation-git";
|
|
11
|
+
/** Isolation by directory copy, for a plain directory. */
|
|
12
|
+
export declare const ISOLATION_COPY = "@bluewombat/isolation-copy";
|
|
13
|
+
/** Where the ledger goes when a config says nothing: one JSON file per key. */
|
|
14
|
+
export declare const DEFAULT_PERSIST = "@bluewombat/persist-fs";
|
|
15
|
+
/** The Planner `init` points a new config at until the Project writes its own. */
|
|
16
|
+
export declare const BOOTSTRAP_PLANNER = "@bluewombat/slots/planners/one-subtask.mjs";
|
|
17
|
+
//# sourceMappingURL=defaults.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,qEAAqE;AACrE,eAAO,MAAM,aAAa,8BAA8B,CAAC;AACzD,0DAA0D;AAC1D,eAAO,MAAM,cAAc,+BAA+B,CAAC;AAC3D,+EAA+E;AAC/E,eAAO,MAAM,eAAe,2BAA2B,CAAC;AACxD,kFAAkF;AAClF,eAAO,MAAM,iBAAiB,+CAA+C,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The plugins Host ships with, by name — the one place these names are
|
|
3
|
+
* written. Host's code never imports a plugin; it loads one by the name a
|
|
4
|
+
* config gives, and these are the names `mason init` writes and `persist`
|
|
5
|
+
* falls back to. Host's package.json declares exactly these, so a config
|
|
6
|
+
* `init` wrote runs with nothing else installed. A manager has no default:
|
|
7
|
+
* Host cannot pick a tracker.
|
|
8
|
+
*/
|
|
9
|
+
/** Isolation by git worktree, for a work line that is a git tree. */
|
|
10
|
+
export const ISOLATION_GIT = "@bluewombat/isolation-git";
|
|
11
|
+
/** Isolation by directory copy, for a plain directory. */
|
|
12
|
+
export const ISOLATION_COPY = "@bluewombat/isolation-copy";
|
|
13
|
+
/** Where the ledger goes when a config says nothing: one JSON file per key. */
|
|
14
|
+
export const DEFAULT_PERSIST = "@bluewombat/persist-fs";
|
|
15
|
+
/** The Planner `init` points a new config at until the Project writes its own. */
|
|
16
|
+
export const BOOTSTRAP_PLANNER = "@bluewombat/slots/planners/one-subtask.mjs";
|
|
17
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,qEAAqE;AACrE,MAAM,CAAC,MAAM,aAAa,GAAG,2BAA2B,CAAC;AACzD,0DAA0D;AAC1D,MAAM,CAAC,MAAM,cAAc,GAAG,4BAA4B,CAAC;AAC3D,+EAA+E;AAC/E,MAAM,CAAC,MAAM,eAAe,GAAG,wBAAwB,CAAC;AACxD,kFAAkF;AAClF,MAAM,CAAC,MAAM,iBAAiB,GAAG,4CAA4C,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare const CONFIG_FILENAME = "mason.config.json";
|
|
2
|
+
/**
|
|
3
|
+
* The nearest `mason.config.json`, walking up from `startDir`.
|
|
4
|
+
*
|
|
5
|
+
* Running from a subdirectory of the project is the common case, so the file is
|
|
6
|
+
* looked up the way a toolchain config is, not demanded on the command line.
|
|
7
|
+
*/
|
|
8
|
+
export declare function findConfig(startDir: string): string | undefined;
|
|
9
|
+
//# sourceMappingURL=find-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-config.d.ts","sourceRoot":"","sources":["../../src/config/find-config.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,eAAe,sBAA2B,CAAC;AAExD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAa/D"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { PRODUCT } from "@bluewombat/manager-kit";
|
|
4
|
+
export const CONFIG_FILENAME = `${PRODUCT}.config.json`;
|
|
5
|
+
/**
|
|
6
|
+
* The nearest `mason.config.json`, walking up from `startDir`.
|
|
7
|
+
*
|
|
8
|
+
* Running from a subdirectory of the project is the common case, so the file is
|
|
9
|
+
* looked up the way a toolchain config is, not demanded on the command line.
|
|
10
|
+
*/
|
|
11
|
+
export function findConfig(startDir) {
|
|
12
|
+
let dir = resolve(startDir);
|
|
13
|
+
for (;;) {
|
|
14
|
+
const candidate = join(dir, CONFIG_FILENAME);
|
|
15
|
+
if (existsSync(candidate)) {
|
|
16
|
+
return candidate;
|
|
17
|
+
}
|
|
18
|
+
const parent = dirname(dir);
|
|
19
|
+
if (parent === dir) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
dir = parent;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=find-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find-config.js","sourceRoot":"","sources":["../../src/config/find-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAElD,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,OAAO,cAAc,CAAC;AAExD;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,QAAgB;IACzC,IAAI,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5B,SAAS,CAAC;QACR,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;QAC7C,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC1B,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5B,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACnB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,GAAG,GAAG,MAAM,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where Host keeps what is its own — the ledger, the workspaces, its copy of
|
|
3
|
+
* the work line. One directory, so one line in a `.gitignore` covers it and
|
|
4
|
+
* nothing the system writes lands next to the operator's files.
|
|
5
|
+
*
|
|
6
|
+
* `workspaceRoot` and `ledger` in the config still move each part on its own;
|
|
7
|
+
* this is only where they go when nobody says.
|
|
8
|
+
*/
|
|
9
|
+
export declare const DEFAULT_HOME = "./.mason";
|
|
10
|
+
export declare const HOME_LAYOUT: {
|
|
11
|
+
readonly workspaces: "workspaces";
|
|
12
|
+
readonly ledger: "ledger";
|
|
13
|
+
readonly workLine: "work-line";
|
|
14
|
+
};
|
|
15
|
+
export declare function homeOf(configDir: string, home: string | undefined): string;
|
|
16
|
+
export declare function inHome(home: string, part: keyof typeof HOME_LAYOUT): string;
|
|
17
|
+
//# sourceMappingURL=home.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"home.d.ts","sourceRoot":"","sources":["../../src/config/home.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,aAAkB,CAAC;AAE5C,eAAO,MAAM,WAAW;;;;CAId,CAAC;AAEX,wBAAgB,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAE1E;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,WAAW,GAAG,MAAM,CAE3E"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { join, resolve } from "node:path";
|
|
2
|
+
import { PRODUCT } from "@bluewombat/manager-kit";
|
|
3
|
+
/**
|
|
4
|
+
* Where Host keeps what is its own — the ledger, the workspaces, its copy of
|
|
5
|
+
* the work line. One directory, so one line in a `.gitignore` covers it and
|
|
6
|
+
* nothing the system writes lands next to the operator's files.
|
|
7
|
+
*
|
|
8
|
+
* `workspaceRoot` and `ledger` in the config still move each part on its own;
|
|
9
|
+
* this is only where they go when nobody says.
|
|
10
|
+
*/
|
|
11
|
+
export const DEFAULT_HOME = `./.${PRODUCT}`;
|
|
12
|
+
export const HOME_LAYOUT = {
|
|
13
|
+
workspaces: "workspaces",
|
|
14
|
+
ledger: "ledger",
|
|
15
|
+
workLine: "work-line",
|
|
16
|
+
};
|
|
17
|
+
export function homeOf(configDir, home) {
|
|
18
|
+
return resolve(configDir, home ?? DEFAULT_HOME);
|
|
19
|
+
}
|
|
20
|
+
export function inHome(home, part) {
|
|
21
|
+
return join(home, HOME_LAYOUT[part]);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=home.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"home.js","sourceRoot":"","sources":["../../src/config/home.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAElD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,MAAM,OAAO,EAAE,CAAC;AAE5C,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,UAAU,EAAE,YAAY;IACxB,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,WAAW;CACb,CAAC;AAEX,MAAM,UAAU,MAAM,CAAC,SAAiB,EAAE,IAAwB;IAChE,OAAO,OAAO,CAAC,SAAS,EAAE,IAAI,IAAI,YAAY,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAY,EAAE,IAA8B;IACjE,OAAO,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;AACvC,CAAC"}
|