bareloop 0.34.0 → 0.36.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/CHANGELOG.md +58 -0
- package/bareloop.context.md +276 -20
- package/package.json +1 -1
- package/src/authorrun.js +3 -2
- package/src/bundlerun.js +17 -12
- package/src/draftspend.js +197 -0
- package/src/exits.js +10 -1
- package/src/index.js +3 -3
- package/src/interviewrun.js +7 -7
- package/src/job.js +37 -0
- package/src/judged.js +2 -2
- package/src/kinds.js +2 -1
- package/src/ledger.js +101 -5
- package/src/legs.js +171 -0
- package/src/monthly.js +111 -72
- package/src/movefile.js +22 -0
- package/src/npminstall.js +55 -0
- package/src/panel/authorroutes.js +84 -14
- package/src/panel/authorsession.js +490 -125
- package/src/panel/importroutes.js +359 -0
- package/src/panel/importrun.js +203 -0
- package/src/panel/index.html +1194 -213
- package/src/panel/runroutes.js +219 -0
- package/src/panel/server.js +964 -79
- package/src/panel/settingsroutes.js +52 -2
- package/src/panel/status.js +51 -0
- package/src/planrun.js +60 -26
- package/src/providerrows.js +17 -0
- package/src/ralph.js +4 -1
- package/src/replay.js +139 -19
- package/src/replayio.js +11 -4
- package/src/reuse.js +20 -3
- package/src/run.js +6 -3
- package/src/runlist.js +75 -7
- package/src/source.js +43 -4
- package/src/text.js +20 -0
- package/src/u-patient.js +3 -2
- package/src/u-readout.js +9 -1
- package/src/u-watchdog.mjs +4 -2
- package/src/userrun.js +192 -65
- package/src/worktree.js +120 -0
- package/types/draftspend.d.ts +141 -0
- package/types/job.d.ts +25 -0
- package/types/ledger.d.ts +44 -0
- package/types/legs.d.ts +103 -0
- package/types/monthly.d.ts +23 -18
- package/types/movefile.d.ts +9 -0
- package/types/npminstall.d.ts +30 -0
- package/types/panel/authorroutes.d.ts +23 -1
- package/types/panel/authorsession.d.ts +110 -2
- package/types/panel/importroutes.d.ts +129 -0
- package/types/panel/importrun.d.ts +77 -0
- package/types/panel/runroutes.d.ts +32 -0
- package/types/panel/server.d.ts +266 -2
- package/types/panel/settingsroutes.d.ts +6 -1
- package/types/panel/status.d.ts +51 -0
- package/types/planrun.d.ts +13 -21
- package/types/providerrows.d.ts +12 -0
- package/types/ralph.d.ts +19 -0
- package/types/replay.d.ts +25 -1
- package/types/replayio.d.ts +2 -2
- package/types/reuse.d.ts +5 -0
- package/types/run.d.ts +6 -2
- package/types/runlist.d.ts +52 -2
- package/types/source.d.ts +13 -5
- package/types/text.d.ts +19 -0
- package/types/userrun.d.ts +10 -0
- package/types/worktree.d.ts +48 -0
package/types/runlist.d.ts
CHANGED
|
@@ -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
|
|
@@ -160,6 +190,9 @@ export const MAX_BACKFILL_DEPTH: 6;
|
|
|
160
190
|
/**
|
|
161
191
|
* `pid`/`capUsd` (optional; older and backfilled rows carry neither): the runner's process id and the
|
|
162
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.
|
|
163
196
|
*/
|
|
164
197
|
export type RunRow = {
|
|
165
198
|
at: string;
|
|
@@ -170,8 +203,12 @@ export type RunRow = {
|
|
|
170
203
|
via: "run-u" | "bundle" | "backfill";
|
|
171
204
|
pid?: number;
|
|
172
205
|
capUsd?: number;
|
|
206
|
+
leg?: number;
|
|
173
207
|
};
|
|
174
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.
|
|
175
212
|
* A claim's write-back, appended (never rewritten) beside the run rows. `settled` = the run's claim on the
|
|
176
213
|
* monthly limit is over (`spentUsd`/`spendComplete` are its final figure, `by` is WHO wrote it: the run itself
|
|
177
214
|
* at its `job-end`, or the next run that found its process gone, `reason: 'process gone'`). `released` = the
|
|
@@ -186,4 +223,17 @@ export type RunEvent = {
|
|
|
186
223
|
reason?: string;
|
|
187
224
|
spentUsd?: number;
|
|
188
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;
|
|
189
239
|
};
|
package/types/source.d.ts
CHANGED
|
@@ -71,19 +71,25 @@ export function looksLikeRepoSource(source: string): boolean;
|
|
|
71
71
|
* as declared, unvalidated by `proveDestination`, and `frontDoorFromManifest`
|
|
72
72
|
* never hands a repo source's destination to `copyOut` — wiring it into
|
|
73
73
|
* `writeScope` is M3/M4's job, not this one.
|
|
74
|
-
*
|
|
74
|
+
* `worktree` (P6 item 1, repo sources ONLY — ignored for every other kind): instead of COPYING the repo, make the
|
|
75
|
+
* run's tree a detached git worktree of the person's own repo at that directory (the shared
|
|
76
|
+
* `src/worktree.js`, the bundle door's own spelling), hide `.bareloop/` from their `git status`, and record the
|
|
77
|
+
* worktree and the repo root in the manifest. `into` then holds only `source.json`; the tree is `worktree`, at the
|
|
78
|
+
* repo's current commit (uncommitted edits are NOT in it). No seed commit is made — the seed IS the repo's HEAD.
|
|
79
|
+
* @param {{source: string, into: string, destination?: string, worktree?: string,
|
|
75
80
|
* fetchTimeoutMs?: number, afterScan?: () => (void|Promise<void>)}} args
|
|
76
81
|
* `fetchTimeoutMs` is test-only — production callers omit it and get
|
|
77
82
|
* `PROVIDER_TIMEOUT_MS`. `afterScan` is a test seam too: called exactly once,
|
|
78
83
|
* after the secret scan finished and before the freeze loop re-reads any
|
|
79
84
|
* file's bytes, so a test can swap a file inside that window
|
|
80
85
|
* deterministically. Production never sets it; absent, behaviour is unchanged.
|
|
81
|
-
* @returns {Promise<{stop: null, into: string, tree: string, manifestPath: string, manifest:
|
|
86
|
+
* @returns {Promise<{stop: null, into: string, tree: string, manifestPath: string, manifest: Record<string, any>}|SourceRefusal>}
|
|
82
87
|
*/
|
|
83
|
-
export function prepareSource({ source, into, destination, fetchTimeoutMs, afterScan }: {
|
|
88
|
+
export function prepareSource({ source, into, destination, worktree, fetchTimeoutMs, afterScan }: {
|
|
84
89
|
source: string;
|
|
85
90
|
into: string;
|
|
86
91
|
destination?: string;
|
|
92
|
+
worktree?: string;
|
|
87
93
|
fetchTimeoutMs?: number;
|
|
88
94
|
afterScan?: () => (void | Promise<void>);
|
|
89
95
|
}): Promise<{
|
|
@@ -91,7 +97,7 @@ export function prepareSource({ source, into, destination, fetchTimeoutMs, after
|
|
|
91
97
|
into: string;
|
|
92
98
|
tree: string;
|
|
93
99
|
manifestPath: string;
|
|
94
|
-
manifest:
|
|
100
|
+
manifest: Record<string, any>;
|
|
95
101
|
} | SourceRefusal>;
|
|
96
102
|
/**
|
|
97
103
|
* THE INSTALL-GAP DETECTOR (PRD item 33 close-out, `docs/product/PRD.md:450-452`,
|
|
@@ -127,13 +133,15 @@ export function prepareSource({ source, into, destination, fetchTimeoutMs, after
|
|
|
127
133
|
* manifest)
|
|
128
134
|
* @param {string} [sourceSubdir] the manifest's own `sourceSubdir` ('' or
|
|
129
135
|
* undefined when Source IS the repo root)
|
|
130
|
-
* @returns {{manager: string, command: string, reason: string}|null} `null`
|
|
136
|
+
* @returns {{dir: string, lockFile: string|null, manager: string, command: string, reason: string}|null} `null`
|
|
131
137
|
* when there is nothing to report: no JS/TS manifest found walking up from
|
|
132
138
|
* `sourceSubdir` to `treeDir`, the nearest one found has no dependencies,
|
|
133
139
|
* `node_modules` is already there, or the manifest cannot even be read as
|
|
134
140
|
* JSON (an invalid `package.json` is "cannot tell", never a false alarm).
|
|
135
141
|
*/
|
|
136
142
|
export function missingDependencies(treeDir: string, sourceSubdir?: string): {
|
|
143
|
+
dir: string;
|
|
144
|
+
lockFile: string | null;
|
|
137
145
|
manager: string;
|
|
138
146
|
command: string;
|
|
139
147
|
reason: string;
|
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
|
package/types/userrun.d.ts
CHANGED
|
@@ -129,6 +129,12 @@ export type RunOpts = {
|
|
|
129
129
|
* the spine directory name, beside `workdir`
|
|
130
130
|
*/
|
|
131
131
|
spineName?: string | undefined;
|
|
132
|
+
/**
|
|
133
|
+
* the source door's own directory (`source.json`, and the spine directory beside it).
|
|
134
|
+
* Default `dirname(workdir)` — the copied-tree layout, where the tree is `<into>/tree`. A repo job on a WORKTREE
|
|
135
|
+
* (P6 item 1) has its tree inside the person's repo, so its `into` is passed explicitly.
|
|
136
|
+
*/
|
|
137
|
+
into?: string | undefined;
|
|
132
138
|
/**
|
|
133
139
|
* the raw `--model` tier name (`sonnet`/`haiku`), or null for the default
|
|
134
140
|
*/
|
|
@@ -194,6 +200,10 @@ export type RunCtx = {
|
|
|
194
200
|
workdir: string;
|
|
195
201
|
seed: string;
|
|
196
202
|
spineName: string;
|
|
203
|
+
/**
|
|
204
|
+
* see `RunOpts.into`
|
|
205
|
+
*/
|
|
206
|
+
into?: string | undefined;
|
|
197
207
|
model: string | null;
|
|
198
208
|
readShim: string | null;
|
|
199
209
|
scout: string | null;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** where a run's worktree lives in the person's repo @param {string} repo @param {string} id */
|
|
2
|
+
export function worktreePath(repo: string, id: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* `git worktree add --detach <dir> HEAD` in `repo` (none of the person's hooks run), creating `dir`'s parent first. Throws
|
|
5
|
+
* `Error('git worktree add failed: …')` — a caller decides whether that is a stop or a refusal.
|
|
6
|
+
* @param {string} repo @param {string} dir
|
|
7
|
+
*/
|
|
8
|
+
export function addWorktree(repo: string, dir: string): void;
|
|
9
|
+
/**
|
|
10
|
+
* How many paths `git status --porcelain` lists in `repo` (tracked edits AND untracked files); 0 for a clean
|
|
11
|
+
* tree. A repo git cannot read counts as 0 — this feeds a notice, never a refusal.
|
|
12
|
+
* @param {string} repo @returns {number}
|
|
13
|
+
*/
|
|
14
|
+
export function uncommittedCount(repo: string): number;
|
|
15
|
+
/** the short sha of `repo`'s HEAD, or null @param {string} repo @returns {string|null} */
|
|
16
|
+
export function shortHead(repo: string): string | null;
|
|
17
|
+
/**
|
|
18
|
+
* Hide `.bareloop/` and `node_modules/` (packages installed in a worktree must not read as worker writes) from the person's own `git status` through the repo's PRIVATE exclude file
|
|
19
|
+
* (`<common-git-dir>/info/exclude`), never their tracked `.gitignore`. The common dir, not `.git`: in a linked
|
|
20
|
+
* worktree `.git` is a file and the shared `info/exclude` lives in the main repository's git dir. Idempotent —
|
|
21
|
+
* each line is checked separately and never written twice.
|
|
22
|
+
* @param {string} repo
|
|
23
|
+
* @returns {boolean} true when the line was added now
|
|
24
|
+
*/
|
|
25
|
+
export function hideBareloopDir(repo: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Remove a run's worktree folder from `repo` (`git worktree remove --force`: the folder may hold untracked
|
|
28
|
+
* scratch — a `.litectx/` index, the gate-audit file — and what matters is on the branch by now). Never throws.
|
|
29
|
+
* @param {string} repo @param {string} dir
|
|
30
|
+
* @returns {boolean} true when the folder is gone afterwards
|
|
31
|
+
*/
|
|
32
|
+
export function removeWorktree(repo: string, dir: string): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* The run's final commit, on whatever branch the worktree stands on: everything the run changed except the
|
|
35
|
+
* arbiter's books and `node_modules`. Nothing changed = no commit (a green with nothing to commit is still a green).
|
|
36
|
+
* Throws on a git failure — the caller must not remove a worktree whose work is not safely on the branch.
|
|
37
|
+
* @param {string} dir the worktree
|
|
38
|
+
* @param {string} message
|
|
39
|
+
* @returns {{committed: boolean, sha: string}}
|
|
40
|
+
*/
|
|
41
|
+
export function commitWork(dir: string, message: string): {
|
|
42
|
+
committed: boolean;
|
|
43
|
+
sha: string;
|
|
44
|
+
};
|
|
45
|
+
/** the line that hides bareloop's own folder from the person's `git status` (anchored at the repo root) */
|
|
46
|
+
export const EXCLUDE_LINE: "/.bareloop/";
|
|
47
|
+
/** the line that hides installed packages at any depth */
|
|
48
|
+
export const NODE_MODULES_LINE: "node_modules/";
|