bareloop 0.33.0 → 0.35.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.
Files changed (56) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/bareloop.context.md +263 -27
  3. package/package.json +1 -1
  4. package/src/bundlerun.js +13 -4
  5. package/src/draftspend.js +82 -0
  6. package/src/exits.js +10 -1
  7. package/src/interviewrun.js +10 -9
  8. package/src/job.js +39 -2
  9. package/src/judged.js +25 -5
  10. package/src/kinds.js +2 -0
  11. package/src/ledger.js +104 -9
  12. package/src/legs.js +171 -0
  13. package/src/monthly.js +133 -87
  14. package/src/panel/authorroutes.js +95 -15
  15. package/src/panel/authorsession.js +408 -113
  16. package/src/panel/importroutes.js +359 -0
  17. package/src/panel/importrun.js +203 -0
  18. package/src/panel/index.html +1071 -184
  19. package/src/panel/runroutes.js +219 -0
  20. package/src/panel/server.js +855 -81
  21. package/src/panel/status.js +51 -0
  22. package/src/planrun.js +63 -31
  23. package/src/providerrows.js +21 -2
  24. package/src/providers.js +4 -4
  25. package/src/ralph.js +3 -0
  26. package/src/replay.js +139 -19
  27. package/src/replayio.js +11 -4
  28. package/src/reuse.js +20 -3
  29. package/src/run.js +6 -3
  30. package/src/runlist.js +90 -7
  31. package/src/text.js +20 -0
  32. package/src/u-readout.js +9 -1
  33. package/src/u-watchdog.mjs +4 -2
  34. package/src/userrun.js +166 -65
  35. package/types/draftspend.d.ts +53 -0
  36. package/types/job.d.ts +25 -0
  37. package/types/judged.d.ts +5 -2
  38. package/types/ledger.d.ts +44 -0
  39. package/types/legs.d.ts +103 -0
  40. package/types/monthly.d.ts +39 -22
  41. package/types/panel/authorroutes.d.ts +38 -1
  42. package/types/panel/authorsession.d.ts +109 -2
  43. package/types/panel/importroutes.d.ts +129 -0
  44. package/types/panel/importrun.d.ts +77 -0
  45. package/types/panel/runroutes.d.ts +32 -0
  46. package/types/panel/server.d.ts +255 -2
  47. package/types/panel/status.d.ts +51 -0
  48. package/types/planrun.d.ts +13 -21
  49. package/types/providerrows.d.ts +14 -1
  50. package/types/providers.d.ts +1 -2
  51. package/types/replay.d.ts +25 -1
  52. package/types/replayio.d.ts +2 -2
  53. package/types/reuse.d.ts +5 -0
  54. package/types/run.d.ts +6 -2
  55. package/types/runlist.d.ts +66 -2
  56. package/types/text.d.ts +19 -0
@@ -13,9 +13,12 @@ export function runlistHome(override?: string): string;
13
13
  */
14
14
  export function runlistPath(home?: string): string;
15
15
  /**
16
- * @typedef {{ at: string, runid: string, job: string, spine: string, patient: string|null, via: 'run-u'|'bundle'|'backfill', pid?: number, capUsd?: number }} RunRow
16
+ * @typedef {{ at: string, runid: string, job: string, spine: string, patient: string|null, via: 'run-u'|'bundle'|'backfill', pid?: number, capUsd?: number, leg?: number }} RunRow
17
17
  * `pid`/`capUsd` (optional; older and backfilled rows carry neither): the runner's process id and the
18
18
  * leg's $ cap — what the monthly limit holds while that pid is a live bareloop runner (src/monthly.js).
19
+ * `leg` (P5-R; only on a row {@link readRunList} FOLDED from `leg-start` entries, i.e. a RESUMED run):
20
+ * the number of the run's latest leg — a resumed run is the same run, one row, and its `pid`/`capUsd`
21
+ * are that latest leg's.
19
22
  */
20
23
  /**
21
24
  * Append one row to the run list, mkdir -p'ing the home directory first.
@@ -45,7 +48,10 @@ export function appendRun(row: RunRow, opts?: {
45
48
  reason?: "duplicate-runid";
46
49
  };
47
50
  /**
48
- * @typedef {{ runid: string, type: 'settled'|'released', by: string, at: string, reason?: string, spentUsd?: number, spendComplete?: boolean }} RunEvent
51
+ * @typedef {{ runid: string, type: 'settled'|'released', by: string, at: string, reason?: string, spentUsd?: number, spendComplete?: boolean, leg?: number }} RunEvent
52
+ * `leg` (P5-R): which leg of the run the write-back is about; absent = leg 1 (every entry written before P5-R).
53
+ * A resumed run is ONE row, so `settled`/`released` are per leg: a later leg's `released` gives back THAT leg's
54
+ * claim and never removes the run.
49
55
  * A claim's write-back, appended (never rewritten) beside the run rows. `settled` = the run's claim on the
50
56
  * monthly limit is over (`spentUsd`/`spendComplete` are its final figure, `by` is WHO wrote it: the run itself
51
57
  * at its `job-end`, or the next run that found its process gone, `reason: 'process gone'`). `released` = the
@@ -61,6 +67,30 @@ export function appendRun(row: RunRow, opts?: {
61
67
  export function appendRunEvent(event: RunEvent, opts?: {
62
68
  home?: string;
63
69
  }): void;
70
+ /**
71
+ * @typedef {{ type: 'leg-start', runid: string, leg: number, pid?: number, capUsd?: number, at: string }} LegStart
72
+ * A resumed run's NEW claim (P5-R, hamr 2026-10-02: one run, one id, one row): appended beside the run's row
73
+ * instead of a second row. {@link readRunList} folds it into the row.
74
+ */
75
+ /**
76
+ * Append one {@link LegStart}: a resumed run's leg claim. Not locked: one short line, one append. THROWS on IO failure.
77
+ * @param {LegStart} entry
78
+ * @param {{ home?: string }} [opts]
79
+ * @returns {void}
80
+ */
81
+ export function appendLegStart(entry: LegStart, opts?: {
82
+ home?: string;
83
+ }): void;
84
+ /**
85
+ * Has this row's LATEST leg been settled? The ONE spelling (the monthly limit and the settle writer share it).
86
+ * @param {RunEvent[]} events {@link readRunList}'s `events`
87
+ * @param {{ runid: string, leg?: number }} row
88
+ * @returns {boolean}
89
+ */
90
+ export function isSettled(events: RunEvent[], row: {
91
+ runid: string;
92
+ leg?: number;
93
+ }): boolean;
64
94
  /**
65
95
  * Tolerant reader — reuses {@link parseJsonl} (never a second hand-rolled
66
96
  * parser). An absent file reads as an empty list, not an error: a fresh
@@ -95,6 +125,20 @@ export function readRunList(opts?: {
95
125
  * @returns {boolean}
96
126
  */
97
127
  export function isLiveRunner(pid: number): boolean;
128
+ /**
129
+ * The ONE "is this run alive" rule, for the panel's glyph ([▶] vs [?]) and the monthly limit's hold. A
130
+ * row that carries its runner's `pid` is alive exactly while that pid is a live bareloop runner
131
+ * ({@link isLiveRunner}) however quiet its spine; only a row with NO pid (an older row) falls back to
132
+ * the spine-mtime rule above. A run that has ENDED (a `job-end` on its spine) is a different fact the
133
+ * callers read off the spine itself — this answers "is a process still running it", nothing more.
134
+ * @param {{ pid?: number, spine: string }} row
135
+ * @param {number} [nowMs] the clock for the mtime fallback
136
+ * @returns {boolean}
137
+ */
138
+ export function runIsAlive(row: {
139
+ pid?: number;
140
+ spine: string;
141
+ }, nowMs?: number): boolean;
98
142
  /**
99
143
  * `bareloop runs backfill <dir>` — recursively scan `dir` (bounded to
100
144
  * {@link MAX_BACKFILL_DEPTH} levels, never into `node_modules`/`.git`,
@@ -146,6 +190,9 @@ export const MAX_BACKFILL_DEPTH: 6;
146
190
  /**
147
191
  * `pid`/`capUsd` (optional; older and backfilled rows carry neither): the runner's process id and the
148
192
  * leg's $ cap — what the monthly limit holds while that pid is a live bareloop runner (src/monthly.js).
193
+ * `leg` (P5-R; only on a row {@link readRunList} FOLDED from `leg-start` entries, i.e. a RESUMED run):
194
+ * the number of the run's latest leg — a resumed run is the same run, one row, and its `pid`/`capUsd`
195
+ * are that latest leg's.
149
196
  */
150
197
  export type RunRow = {
151
198
  at: string;
@@ -156,8 +203,12 @@ export type RunRow = {
156
203
  via: "run-u" | "bundle" | "backfill";
157
204
  pid?: number;
158
205
  capUsd?: number;
206
+ leg?: number;
159
207
  };
160
208
  /**
209
+ * `leg` (P5-R): which leg of the run the write-back is about; absent = leg 1 (every entry written before P5-R).
210
+ * A resumed run is ONE row, so `settled`/`released` are per leg: a later leg's `released` gives back THAT leg's
211
+ * claim and never removes the run.
161
212
  * A claim's write-back, appended (never rewritten) beside the run rows. `settled` = the run's claim on the
162
213
  * monthly limit is over (`spentUsd`/`spendComplete` are its final figure, `by` is WHO wrote it: the run itself
163
214
  * at its `job-end`, or the next run that found its process gone, `reason: 'process gone'`). `released` = the
@@ -172,4 +223,17 @@ export type RunEvent = {
172
223
  reason?: string;
173
224
  spentUsd?: number;
174
225
  spendComplete?: boolean;
226
+ leg?: number;
227
+ };
228
+ /**
229
+ * A resumed run's NEW claim (P5-R, hamr 2026-10-02: one run, one id, one row): appended beside the run's row
230
+ * instead of a second row. {@link readRunList} folds it into the row.
231
+ */
232
+ export type LegStart = {
233
+ type: "leg-start";
234
+ runid: string;
235
+ leg: number;
236
+ pid?: number;
237
+ capUsd?: number;
238
+ at: string;
175
239
  };
package/types/text.d.ts CHANGED
@@ -200,6 +200,25 @@ export function stampRaw<T extends {
200
200
  cause?: string | null;
201
201
  reason?: string | null;
202
202
  }): T;
203
+ /**
204
+ * BA-21 — the WRITE side of the pricing-provenance signal (read side: `rateProvenance` /
205
+ * `spendProvenance` in src/ledger.js). bare-agent >=0.37 rides `rateSource` beside
206
+ * `pricing` on every metering payload; both metering callbacks below forward it onto the
207
+ * spine through THIS one helper, because two sites spelling one rule are two instruments
208
+ * (the ripgrep fix that landed in ci.yml but not publish.yml).
209
+ *
210
+ * Forwarded VERBATIM — the write side reports what upstream said, and src/ledger.js is
211
+ * the one place that decides what counts as a guess. And an ABSENT provenance stays
212
+ * absent: a payload carrying no `rateSource` (bare-agent <0.37, and every round already
213
+ * in the archive) emits no field at all, so a reader sees UNKNOWN rather than a label we
214
+ * invented. Never defaulted to `null` here — `null` is upstream saying "nothing was
215
+ * priced", which is a different fact from "nobody told us".
216
+ * @param {any} arg an `onLlmResult` / `onTurn` payload
217
+ * @returns {{rateSource?: string|null}} the field to spread into the spine record
218
+ */
219
+ export function rateSourceFields(arg: any): {
220
+ rateSource?: string | null;
221
+ };
203
222
  /**
204
223
  * The ceiling on ONE persisted raw. Sized to the survey's own prompt-ingredient
205
224
  * cap (`AUTHOR_SCOUT_BLOB_MAX`, 8000) rather than picked: the largest raw this