bareloop 0.27.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,247 @@
1
+ /**
2
+ * A token count, k/M-abbreviated — 2 decimals at and above a million (the tail's own
3
+ * `.2M`-shaped resolution matters more once six figures are folded into a suffix), 1
4
+ * decimal in the thousands, and the bare integer under that (a two- or three-digit
5
+ * round is more readable plain than as `"0.2k"`).
6
+ * @param {number} n
7
+ * @returns {string}
8
+ */
9
+ export function fmtTokens(n: number): string;
10
+ /**
11
+ * THE TOKENS TAIL LINE — hamr's 2026-09-01 order: `job-end` carries dollars only, and
12
+ * the run tail never prints a token total anywhere, though tokens exist per round on
13
+ * `worker-round.usage` and `judge-round.usage`
14
+ * ({inputTokens, outputTokens, cacheReadTokens, cacheCreationTokens}).
15
+ *
16
+ * Summed off THIS LEG's own spine, over every round TYPE that spends money —
17
+ * worker-round AND judge-round (house rule: a spend-slicing instrument must enumerate
18
+ * every round type that spends, or it silently undercounts). `worker-result` is an
19
+ * ATTEMPT-LEVEL ECHO of round sums, not a round, and is deliberately never matched
20
+ * here — folding it in would double the real figure.
21
+ *
22
+ * A round whose `usage` is missing or not an object (today: every `judge-round` — the
23
+ * payload at `src/planrun.js`'s `onJudgeCost` does not carry one) is counted as
24
+ * UNKNOWN, never laundered into a silent 0 — the same rule `costUsd` already lives by
25
+ * (F6/F44): an unpriced round is reported as unpriced, not folded into the total as
26
+ * if it cost nothing.
27
+ *
28
+ * @param {{events: any[]}} o `events` this leg's own parsed spine, never a folded
29
+ * chain — a resumed leg's tokens are this leg's own bill, same as `rounds` above it.
30
+ * @returns {string}
31
+ */
32
+ export function tokensLine({ events }: {
33
+ events: any[];
34
+ }): string;
35
+ /**
36
+ * The banner's wall line: what this run has consumed of its signed cap.
37
+ * @param {{legMs: number, priorWallMs?: number, wallLabel: string}} o
38
+ * `legMs`: wall this process bought. `priorWallMs`: wall its predecessors burnt,
39
+ * as `readResume` folded it (0/absent on a cold run). `wallLabel`: the signed cap
40
+ * as the runner spells it, including the honest UNBOUNDED prose.
41
+ * @returns {string}
42
+ */
43
+ export function wallLine({ legMs, priorWallMs, wallLabel }: {
44
+ legMs: number;
45
+ priorWallMs?: number;
46
+ wallLabel: string;
47
+ }): string;
48
+ /**
49
+ * THE EVIDENCE PACKAGE (N4, ruling 2) — what a person is shown before they answer.
50
+ *
51
+ * *"Before/after changes plus every mechanical stage's result; never a bare
52
+ * 'approve?'"*. The LIBRARY assembles the facts and puts them on the `hitl-pause`
53
+ * spine record — the ask the close itself declared, every stage's own result, and
54
+ * WHICH files the run changed (`src/planrun.js`'s `emitHitlPause`). This renders
55
+ * them, and adds the one thing a library cannot state honestly from where it sits:
56
+ * the LINE-level diff, which needs a screen and a repository in front of it.
57
+ *
58
+ * Nothing here derives a verdict, and nothing here decides. It is a readout of a
59
+ * record that already exists — so an absence is written as prose (F6: an empty
60
+ * stage list is "the checkpoint carries none", never a blank screen that reads as
61
+ * "nothing happened") and a trim is announced (F28).
62
+ *
63
+ * @param {{pause: any, diff: {lines: string[], truncated?: number, untracked?: string[],
64
+ * unavailable?: string|null}|null}} o `pause` the spine record; `diff` what the
65
+ * runner read off the patient, or null when it did not look.
66
+ * @returns {string[]} lines, ready to print
67
+ */
68
+ export function evidencePackage({ pause, diff }: {
69
+ pause: any;
70
+ diff: {
71
+ lines: string[];
72
+ truncated?: number;
73
+ untracked?: string[];
74
+ unavailable?: string | null;
75
+ } | null;
76
+ }): string[];
77
+ /**
78
+ * THE REVIEW DOOR's package (softgreen module 8) — the same evidence, at the door
79
+ * at the END of a run rather than at a stage inside the close.
80
+ *
81
+ * It is a SEPARATE renderer from `evidencePackage` and deliberately so: that one
82
+ * opens with *"this run reached the one stage a machine cannot render, and it is
83
+ * waiting on you"*, which at a review door would be false twice over — the machine
84
+ * rendered every stage, and the run is over. What a person needs told here is the
85
+ * opposite fact: a verdict was minted, it STANDS, and what happens to the work is
86
+ * theirs. The stage/changed/diff body is shared, because it is the same evidence.
87
+ * @param {{door: any, diff?: any}} o
88
+ * @returns {string[]}
89
+ */
90
+ export function reviewDoorPackage({ door, diff }: {
91
+ door: any;
92
+ diff?: any;
93
+ }): string[];
94
+ /**
95
+ * The door's OWN `close-timing-red` refusal (F137, hamr's ruling 2026-09-07,
96
+ * `docs/product/CLOSE-INTEGRITY-BUILD.md` "Ruled 2026-09-07"): when the
97
+ * door's timing pass (`resolveCloseTimeoutMs`) times out, the accept must
98
+ * REFUSE outright rather than fall through to the library's 120s default —
99
+ * mirroring the wording/options list `scripts/run-u.mjs`'s in-run
100
+ * `close-timing-red` escalation already prints (~line 1173), never a second
101
+ * invented phrasing. Pure so the wording is unit-testable without spawning
102
+ * the script or waiting out the real 600s timing-preflight ceiling.
103
+ * @param {{names: string}} args comma-joined names of the stage(s) that timed out
104
+ * @returns {string[]}
105
+ */
106
+ export function doorTimingRedLines({ names }: {
107
+ names: string;
108
+ }): string[];
109
+ /**
110
+ * The three doors AT THE REVIEW DOOR. Same order and the same rule as
111
+ * `doorLines` (rerun leads, ~40% rubber-stamp), different consequences: this run
112
+ * is OVER, so a rerun is a fresh engagement rather than a continuation, and a
113
+ * pause keeps the door rather than a step checkpoint.
114
+ * @param {{rerun: string, accept: string, pause: string, ttlDays: number, held: boolean}} o
115
+ * @returns {string[]}
116
+ */
117
+ export function runDoorLines({ rerun, accept, pause, ttlDays, held }: {
118
+ rerun: string;
119
+ accept: string;
120
+ pause: string;
121
+ ttlDays: number;
122
+ held: boolean;
123
+ }): string[];
124
+ /**
125
+ * THE THREE DOORS, rendered — and the 2026-08-12 §4 rule is the ORDER.
126
+ *
127
+ * ~40% of human reviewers approve without reading. That datum is a design input:
128
+ * the default must lean toward rerun and never toward accept, because a default
129
+ * that costs one extra cycle when wrong is cheap and a default that mints a green
130
+ * nobody read is the failure mode the whole class exists to prevent.
131
+ *
132
+ * "Default" here is which door the prompt LEADS with — never an action taken for
133
+ * the operator. No door happens without its flag, and this says so.
134
+ *
135
+ * The third door is PAUSE (2026-08-18), not cancel. hamr: *"what's the point of
136
+ * cancel anyways? pause can resume — that would be more honest"*. A person who does
137
+ * not want to carry on today is not making a permanent judgment, and the door should
138
+ * not ask them to: the checkpoint keeps, and an unanswered one expires on its own.
139
+ *
140
+ * @param {{rerun: string, accept: string, pause: string}} invocations the exact
141
+ * command each door costs, so nobody has to reconstruct one
142
+ * @returns {string[]}
143
+ */
144
+ export function doorLines({ rerun, accept, pause }: {
145
+ rerun: string;
146
+ accept: string;
147
+ pause: string;
148
+ }): string[];
149
+ /**
150
+ * WHEN THE DEAD LEG STOPPED — the input `readResume` folds into `priorWallMs`, and
151
+ * therefore what the resumed leg's wall remainder is computed from.
152
+ *
153
+ * The runner has two candidate witnesses and they answer different questions:
154
+ *
155
+ * - the WATCHDOG's kill record (`<spine>.watchdog.json`), which is written when the
156
+ * outside guard reaps a run. For a run that was killed it is later and better
157
+ * evidence than the last spine event: the process was alive, silently, right up to
158
+ * the signal, and billing only to its last emitted event would under-report the
159
+ * wall it really burnt.
160
+ * - the SPINE's own landed terminal (`job-end`). A run that wrote one did not die —
161
+ * it ENDED ITSELF and dated its own stop.
162
+ *
163
+ * So the preference order is not "the later record wins", it is "the run's own record
164
+ * wins when there is one". N4 §1.6 is where that distinction stopped being academic:
165
+ * a `hitl-pause` is a clean terminal a person may answer days later, and any record
166
+ * dated after it bills their deciding time to the run's wall. The POC measured the
167
+ * shape — a report 45 days after the pause made `RESUME_WALL_MS` exactly 0, dooming
168
+ * the resumed leg before it opened, on a run that had barely started. W-2 holds by
169
+ * construction only if this reads the pause.
170
+ *
171
+ * Returning `null` is not a failure: it hands `readResume` back its own documented
172
+ * default (the last event's timestamp), which for a clean terminal IS the terminal.
173
+ *
174
+ * @param {{watchdogAt?: unknown, events?: unknown}} o `watchdogAt` as the report
175
+ * spells it (an ISO string, or anything at all — the file is read off disk);
176
+ * `events` the dead spine, parsed.
177
+ * @returns {number|null} ms, or null to leave the default in place
178
+ */
179
+ export function deathAtOf({ watchdogAt, events }?: {
180
+ watchdogAt?: unknown;
181
+ events?: unknown;
182
+ }): number | null;
183
+ /**
184
+ * WHERE A RESUME PICKS UP — the preview's `at` line, which is what says how much of
185
+ * the signed dollars this leg can still spend.
186
+ *
187
+ * `readStepCheckpoint` (src/reuse.js) knows two phases and a null: `steps` (re-enter
188
+ * the plan at the first unfinished step), `close` (every step landed; the close and
189
+ * its fix loop are what is left), and no checkpoint at all (the halt landed before a
190
+ * plan was accepted). The runner rendered those three directly, and a PAUSE fits none
191
+ * of them cleanly:
192
+ *
193
+ * - a pause happens AFTER the plan's steps, at the close's human stage. On the
194
+ * fixture a person actually meets, the checkpoint reads `phase:'steps'` with every
195
+ * step green (the pause site emits no `outer-close` of its own), so the step
196
+ * arithmetic ran off the end and printed `at step 2 of 1 "(unknown)"` — a step
197
+ * count larger than the plan and an id nobody drafted. hamr found it on the first
198
+ * resume preview he read;
199
+ * - and the same walk-off is reachable one terminal over, with no person involved:
200
+ * a kill between the last `step-end` and the `outer-close` leaves exactly that
201
+ * shape, and read `step 3 of 2`.
202
+ *
203
+ * So the count is never allowed to exceed the plan, and the PHASE is said in words.
204
+ * Rendering only; it decides nothing and bounds nothing.
205
+ *
206
+ * @param {{seed: {phase?: string, plan?: any, completedSteps?: any[]}|null|undefined,
207
+ * paused: boolean}} o `seed` is `readResume`'s `restart.seed`; `paused` is the
208
+ * recorded terminal being `hitl-pause` — read off the spine, never off a flag.
209
+ * @returns {string[]} lines, ready to print
210
+ */
211
+ export function resumeAtLines({ seed, paused }: {
212
+ seed: {
213
+ phase?: string;
214
+ plan?: any;
215
+ completedSteps?: any[];
216
+ } | null | undefined;
217
+ paused: boolean;
218
+ }): string[];
219
+ /**
220
+ * F97 — the DOOMED RESUME read, the one the operator should make before signing.
221
+ *
222
+ * `u-msn0uccv` spent $0.82 re-entering the exact plan whose action was the diagnosed
223
+ * defect, carrying `priorReplans: 2` and `priorReplanGrantUsed: true`. A resume does
224
+ * not re-draft — `scout-skipped {reason:"resumed"}` and the plan comes back
225
+ * byte-for-byte — so with the replan ledger empty there was no mechanism left that
226
+ * could replace it. Two attempts, 26 rounds, 0 writes, `step-red` with money and
227
+ * minutes still on the clock. Nothing in the library was at fault; every part of that
228
+ * leg reported honestly. The DECISION to fire was the defect, and the read that would
229
+ * have refused it costs $0: both facts are already parsed by the preview gate.
230
+ *
231
+ * WARNING ONLY. This never blocks and never changes behaviour — a resume of a
232
+ * mechanical gap (a named wall, a count) converts on re-entry all the time, and the
233
+ * operator is the one who can tell which kind of gap it is. Blocking here would be
234
+ * this file inventing a gate; the arbiter's gates are signed, not derived from a
235
+ * readout module.
236
+ *
237
+ * @param {{seed?: {phase?: string}|null, replans?: number, replanGrantUsed?: boolean}|null} [restart]
238
+ * `readResume`'s `restart` fold: WHERE it picks up and WHAT LEDGER it inherited.
239
+ * @returns {boolean} true only for the shape F97 measured.
240
+ */
241
+ export function doomedResume(restart?: {
242
+ seed?: {
243
+ phase?: string;
244
+ } | null;
245
+ replans?: number;
246
+ replanGrantUsed?: boolean;
247
+ } | null): boolean;
@@ -0,0 +1,141 @@
1
+ /**
2
+ * A fresh run — today's `--job` / `--spec` path. `opts.workdir`/`opts.seed`/
3
+ * `opts.spineName` name the patient (the JOBS-table row, or the `--spec`
4
+ * manifest's own reading of it, when called through `main`/`scripts/run-u.mjs`).
5
+ * @param {any} spec the parsed, not-yet-validated job spec
6
+ * @param {RunOpts} [opts]
7
+ * @returns {Promise<number>} an exit code — never calls process.exit
8
+ */
9
+ export function startRun(spec: any, opts?: RunOpts): Promise<number>;
10
+ /**
11
+ * A halted run — today's `--resume` path.
12
+ * @param {string} runId the runid (or an explicit spine path, for tests)
13
+ * @param {RunOpts & {decide?: string|null, text?: string|null}} [opts]
14
+ * @returns {Promise<number>} an exit code — never calls process.exit
15
+ */
16
+ export function resumeRun(runId: string, opts?: RunOpts & {
17
+ decide?: string | null;
18
+ text?: string | null;
19
+ }): Promise<number>;
20
+ /**
21
+ * A finished run's review door — today's `--door` path.
22
+ * @param {string} runId the runid (or an explicit spine path, for tests)
23
+ * @param {{decide: string|null, text?: string|null}} decision
24
+ * @param {RunOpts} [opts]
25
+ * @returns {Promise<number>} an exit code — never calls process.exit
26
+ */
27
+ export function answerDoor(runId: string, decision: {
28
+ decide: string | null;
29
+ text?: string | null;
30
+ }, opts?: RunOpts): Promise<number>;
31
+ /**
32
+ * Parses this runner's own argv shape — the JOBS table's `--job <key>` /
33
+ * `--spec <path>`, plus `--resume`/`--door`/`--decide`/`--text`/
34
+ * `--review-door`/`--approve`/`--registry`/`--workflow`/`--model`/
35
+ * `--read-shim`/`--scout` — and dispatches to whichever of the three doors
36
+ * above the flags name. `scripts/run-u.mjs` is the thin adapter over this,
37
+ * the same shape `bin/bareloop.mjs` already is over `src/cli.js`'s own
38
+ * `main(argv, deps)`.
39
+ * @param {string[]} argv
40
+ * @param {Deps} [deps]
41
+ * @returns {Promise<number>}
42
+ */
43
+ export function main(argv: string[], deps?: Deps): Promise<number>;
44
+ export type Deps = {
45
+ env?: Record<string, string | undefined> | undefined;
46
+ out?: ((s: string) => void) | undefined;
47
+ err?: ((s: string) => void) | undefined;
48
+ /**
49
+ * the TEST SEAM: supplying this skips the real-key
50
+ * check entirely, the same shape `src/cli.js`'s `main(argv, deps)` uses.
51
+ */
52
+ provider?: any;
53
+ providerFor?: ((tier: string) => any) | undefined;
54
+ judgeProvider?: any;
55
+ /**
56
+ * F196 — a test seam for `appendRun`'s
57
+ * (src/runlist.js) `home` override, the same shape `deps.provider` already
58
+ * is. Production never sets it; `appendRun` falls through to its own
59
+ * `os.homedir()`-based default.
60
+ */
61
+ runlistHome?: string | undefined;
62
+ };
63
+ export type RunOpts = {
64
+ /**
65
+ * the parsed, not-yet-validated job spec — read by
66
+ * `resumeRun`/`answerDoor`, whose positional argument is the runid rather
67
+ * than the spec (unlike `startRun`, which takes `spec` positionally and
68
+ * never reads this).
69
+ */
70
+ spec?: any;
71
+ /**
72
+ * the patient's tree
73
+ */
74
+ workdir?: string | undefined;
75
+ /**
76
+ * the patient's frozen seed commit
77
+ */
78
+ seed?: string | undefined;
79
+ /**
80
+ * the spine directory name, beside `workdir`
81
+ */
82
+ spineName?: string | undefined;
83
+ /**
84
+ * the raw `--model` tier name (`sonnet`/`haiku`), or null for the default
85
+ */
86
+ model?: string | null | undefined;
87
+ /**
88
+ * the raw `--read-shim` arm name, or null for the default
89
+ */
90
+ readShim?: string | null | undefined;
91
+ /**
92
+ * the raw `--scout` value (`on`/`off`), or null for the default
93
+ */
94
+ scout?: string | null | undefined;
95
+ /**
96
+ * a bridge registry directory
97
+ */
98
+ registry?: string | null | undefined;
99
+ /**
100
+ * the registry's workflow name (defaults to `spec.job`)
101
+ */
102
+ workflow?: string | null | undefined;
103
+ /**
104
+ * the spec hash being signed; omitted previews only
105
+ */
106
+ approve?: string | null | undefined;
107
+ /**
108
+ * opt in to a green-class run opening a review door
109
+ */
110
+ reviewDoor?: boolean | undefined;
111
+ /**
112
+ * how the re-invocation commands this prints should name the job (`--job x` / `--spec <path>`)
113
+ */
114
+ selector?: string | undefined;
115
+ /**
116
+ * how a "go edit the spec" hint should read
117
+ */
118
+ specDesc?: string | undefined;
119
+ deps?: Deps | undefined;
120
+ };
121
+ export type RunCtx = {
122
+ spec: any;
123
+ specPath: string;
124
+ selector: string;
125
+ specDesc: string;
126
+ workdir: string;
127
+ seed: string;
128
+ spineName: string;
129
+ model: string | null;
130
+ readShim: string | null;
131
+ scout: string | null;
132
+ registry: string | null;
133
+ workflow: string | null;
134
+ approve: string | null;
135
+ reviewDoor: boolean;
136
+ resume: string | null;
137
+ door: string | null;
138
+ decide: string | null;
139
+ text: string | null;
140
+ deps: Deps;
141
+ };