bareloop 0.30.0 → 0.32.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 +154 -0
- package/bareloop.context.md +205 -10
- package/bin/bareloop.mjs +0 -1
- package/package.json +1 -1
- package/src/authorflow.js +22 -42
- package/src/authorjob.js +5 -8
- package/src/authorrun.js +42 -16
- package/src/cli.js +12 -6
- package/src/config.js +135 -0
- package/src/interviewrun.js +10 -2
- package/src/keysfile.js +156 -0
- package/src/ledger.js +26 -0
- package/src/monthly.js +352 -0
- package/src/panel/authorroutes.js +328 -0
- package/src/panel/authorsession.js +555 -0
- package/src/panel/index.html +1247 -50
- package/src/panel/server.js +449 -51
- package/src/panel/settingsroutes.js +230 -0
- package/src/planrun.js +61 -5
- package/src/promptregisters.js +3 -0
- package/src/providerrows.js +217 -0
- package/src/providers.js +84 -0
- package/src/replay.js +80 -2
- package/src/replayio.js +14 -3
- package/src/run.js +48 -2
- package/src/runlist.js +13 -0
- package/src/userrun.js +134 -13
- package/types/authorflow.d.ts +4 -21
- package/types/authorrun.d.ts +5 -0
- package/types/cli.d.ts +2 -1
- package/types/config.d.ts +48 -0
- package/types/interviewrun.d.ts +5 -0
- package/types/keysfile.d.ts +90 -0
- package/types/ledger.d.ts +14 -0
- package/types/monthly.d.ts +192 -0
- package/types/panel/authorroutes.d.ts +67 -0
- package/types/panel/authorsession.d.ts +53 -0
- package/types/panel/server.d.ts +42 -5
- package/types/panel/settingsroutes.d.ts +14 -0
- package/types/providerrows.d.ts +164 -0
- package/types/providers.d.ts +34 -0
- package/types/replay.d.ts +31 -0
- package/types/replayio.d.ts +12 -1
- package/types/run.d.ts +26 -1
- package/types/runlist.d.ts +1 -0
- package/types/userrun.d.ts +22 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The key value to hand a provider: the `null` marker becomes the placeholder, anything else
|
|
3
|
+
* passes through unchanged.
|
|
4
|
+
* @template {string|undefined} T
|
|
5
|
+
* @param {T} raw
|
|
6
|
+
* @returns {T|string}
|
|
7
|
+
*/
|
|
8
|
+
export function usableKey<T extends string | undefined>(raw: T): T | string;
|
|
9
|
+
/**
|
|
10
|
+
* What a key with no saved entry shows. Any name not listed is OpenAI-compatible with a
|
|
11
|
+
* blank URL and a blank Name.
|
|
12
|
+
* @param {string} envName
|
|
13
|
+
* @returns {{ name: string, shape: string, baseUrl: string }}
|
|
14
|
+
*/
|
|
15
|
+
export function defaultsFor(envName: string): {
|
|
16
|
+
name: string;
|
|
17
|
+
shape: string;
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* @typedef {object} KeyRow
|
|
22
|
+
* @property {string} envName the key variable NAME (read-only label; never a value)
|
|
23
|
+
* @property {string} name the model id Chat uses ('' = not offered in Chat)
|
|
24
|
+
* @property {string} provider the `src/providers.js` table entry (the API shape's id)
|
|
25
|
+
* @property {string} baseUrl the saved Base URL ('' = the shape's default host)
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* The rows: one per name in `filled`, saved entry over defaults.
|
|
29
|
+
* @param {{ filled: readonly string[], config: Record<string, any> }} src
|
|
30
|
+
* @returns {KeyRow[]}
|
|
31
|
+
*/
|
|
32
|
+
export function keyRows({ filled, config }: {
|
|
33
|
+
filled: readonly string[];
|
|
34
|
+
config: Record<string, any>;
|
|
35
|
+
}): KeyRow[];
|
|
36
|
+
/**
|
|
37
|
+
* The rows for a keys home. `undefined` home (a door that skipped the keys file) = no
|
|
38
|
+
* rows, so nothing resolves through the file and the provider's built-in variable stands.
|
|
39
|
+
* @param {string|undefined} home
|
|
40
|
+
* @returns {KeyRow[]}
|
|
41
|
+
*/
|
|
42
|
+
export function rowsForHome(home: string | undefined): KeyRow[];
|
|
43
|
+
/**
|
|
44
|
+
* @param {string} provider
|
|
45
|
+
* @returns {string} the shape's default host ('' = the vendor's own)
|
|
46
|
+
*/
|
|
47
|
+
export function defaultUrlOf(provider: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* An endpoint in comparable form: blank = the shape's default host; scheme + host lower-cased,
|
|
50
|
+
* trailing slashes dropped.
|
|
51
|
+
* @param {string} provider
|
|
52
|
+
* @param {string|null|undefined} baseUrl
|
|
53
|
+
* @returns {string}
|
|
54
|
+
*/
|
|
55
|
+
export function endpointOf(provider: string, baseUrl: string | null | undefined): string;
|
|
56
|
+
/**
|
|
57
|
+
* The URL a row talks to, for display ('' = the vendor's own host, which has no URL to show).
|
|
58
|
+
* @param {KeyRow} row
|
|
59
|
+
* @returns {string}
|
|
60
|
+
*/
|
|
61
|
+
export function shownUrl(row: KeyRow): string;
|
|
62
|
+
/**
|
|
63
|
+
* Which row a `(provider, baseUrl[, model])` identity belongs to: the rows on that shape and
|
|
64
|
+
* endpoint; when several share it, the one whose Name is the model, else the first.
|
|
65
|
+
* @param {readonly KeyRow[]} rows
|
|
66
|
+
* @param {{ provider?: string|null, baseUrl?: string|null, model?: string|null }} id
|
|
67
|
+
* @returns {KeyRow|null}
|
|
68
|
+
*/
|
|
69
|
+
export function findRow(rows: readonly KeyRow[], { provider, baseUrl, model }: {
|
|
70
|
+
provider?: string | null;
|
|
71
|
+
baseUrl?: string | null;
|
|
72
|
+
model?: string | null;
|
|
73
|
+
}): KeyRow | null;
|
|
74
|
+
/**
|
|
75
|
+
* What Chat's Model menu offers and how a pick resolves: the row whose Name is the model
|
|
76
|
+
* (a blank Name is never offered). `baseUrl` is absent when blank, exactly as a spec omits it.
|
|
77
|
+
* @param {readonly KeyRow[]} rows
|
|
78
|
+
* @param {string} model
|
|
79
|
+
* @returns {{ provider: string, baseUrl?: string, envName: string, name: string }|null}
|
|
80
|
+
*/
|
|
81
|
+
export function modelChoiceFor(rows: readonly KeyRow[], model: string): {
|
|
82
|
+
provider: string;
|
|
83
|
+
baseUrl?: string;
|
|
84
|
+
envName: string;
|
|
85
|
+
name: string;
|
|
86
|
+
} | null;
|
|
87
|
+
/**
|
|
88
|
+
* The models Chat offers, in keys-file order.
|
|
89
|
+
* @param {readonly KeyRow[]} rows
|
|
90
|
+
* @returns {{ id: string, envName: string, shape: string }[]}
|
|
91
|
+
*/
|
|
92
|
+
export function chatModels(rows: readonly KeyRow[]): {
|
|
93
|
+
id: string;
|
|
94
|
+
envName: string;
|
|
95
|
+
shape: string;
|
|
96
|
+
}[];
|
|
97
|
+
/**
|
|
98
|
+
* The key variable NAME a job on `(provider, baseUrl[, model])` reads: the matching row's
|
|
99
|
+
* variable, else the provider's built-in one (byte-identical to before for anything no row
|
|
100
|
+
* claims).
|
|
101
|
+
* @param {string|null|undefined} provider
|
|
102
|
+
* @param {string|null|undefined} baseUrl
|
|
103
|
+
* @param {readonly KeyRow[]} rows
|
|
104
|
+
* @param {string|null|undefined} [model]
|
|
105
|
+
* @returns {{ name: string, builtIn: string, chosen: boolean }}
|
|
106
|
+
*/
|
|
107
|
+
export function keyNameFor(provider: string | null | undefined, baseUrl: string | null | undefined, rows: readonly KeyRow[], model?: string | null | undefined): {
|
|
108
|
+
name: string;
|
|
109
|
+
builtIn: string;
|
|
110
|
+
chosen: boolean;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* The env a door hands to provider construction, with the matching row's key variable
|
|
114
|
+
* standing in for the provider's built-in one: `env[builtIn] = env[row.envName]` (the `null`
|
|
115
|
+
* no-key marker becomes {@link NO_KEY_PLACEHOLDER}). A copy — never mutates the input.
|
|
116
|
+
* No matching row and no marker = the env unchanged.
|
|
117
|
+
* @param {Record<string,string|undefined>} env
|
|
118
|
+
* @param {string|null|undefined} provider
|
|
119
|
+
* @param {string|null|undefined} baseUrl
|
|
120
|
+
* @param {readonly KeyRow[]} rows
|
|
121
|
+
* @param {string|null|undefined} [model]
|
|
122
|
+
* @returns {Record<string,string|undefined>}
|
|
123
|
+
*/
|
|
124
|
+
export function applyConfiguredKey(env: Record<string, string | undefined>, provider: string | null | undefined, baseUrl: string | null | undefined, rows: readonly KeyRow[], model?: string | null | undefined): Record<string, string | undefined>;
|
|
125
|
+
/** DeepSeek's OpenAI-shaped endpoint (the same string the panel's Model menu used). */
|
|
126
|
+
export const DEEPSEEK_BASE_URL: "https://api.deepseek.com/v1";
|
|
127
|
+
/**
|
|
128
|
+
* The API shapes the dropdown offers. `id` is the `src/providers.js` table name;
|
|
129
|
+
* `defaultUrl` is the host a blank Base URL means ('' = the vendor's own, unshown).
|
|
130
|
+
* @type {readonly {id: string, label: string, defaultUrl: string}[]}
|
|
131
|
+
*/
|
|
132
|
+
export const SHAPES: readonly {
|
|
133
|
+
id: string;
|
|
134
|
+
label: string;
|
|
135
|
+
defaultUrl: string;
|
|
136
|
+
}[];
|
|
137
|
+
/** The five empty lines a fresh keys file is created with, in this order. */
|
|
138
|
+
export const PRESET_KEY_NAMES: readonly string[];
|
|
139
|
+
/** A local server's default endpoint: Ollama's OpenAI-compatible host (LM Studio / llama.cpp: change the URL). */
|
|
140
|
+
export const LOCAL_BASE_URL: "http://127.0.0.1:11434/v1";
|
|
141
|
+
/**
|
|
142
|
+
* A key line whose value is the word `null` is SET and means "no real key": the row exists and
|
|
143
|
+
* the provider is handed this harmless stand-in (local servers ignore auth). It is not a
|
|
144
|
+
* secret and is never shown or logged as a key.
|
|
145
|
+
*/
|
|
146
|
+
export const NO_KEY_PLACEHOLDER: "no-key-needed";
|
|
147
|
+
export type KeyRow = {
|
|
148
|
+
/**
|
|
149
|
+
* the key variable NAME (read-only label; never a value)
|
|
150
|
+
*/
|
|
151
|
+
envName: string;
|
|
152
|
+
/**
|
|
153
|
+
* the model id Chat uses ('' = not offered in Chat)
|
|
154
|
+
*/
|
|
155
|
+
name: string;
|
|
156
|
+
/**
|
|
157
|
+
* the `src/providers.js` table entry (the API shape's id)
|
|
158
|
+
*/
|
|
159
|
+
provider: string;
|
|
160
|
+
/**
|
|
161
|
+
* the saved Base URL ('' = the shape's default host)
|
|
162
|
+
*/
|
|
163
|
+
baseUrl: string;
|
|
164
|
+
};
|
package/types/providers.d.ts
CHANGED
|
@@ -98,6 +98,40 @@ export function buildRunnerProviders({ providerName, apiKey, model, tierModels,
|
|
|
98
98
|
providerFor: (tier: string) => any;
|
|
99
99
|
judgeProvider: any;
|
|
100
100
|
};
|
|
101
|
+
/**
|
|
102
|
+
* $0 reachability check: a GET against `providerName`'s own models-list
|
|
103
|
+
* endpoint, server-side, with the key in a header — NEVER a completion
|
|
104
|
+
* request, so it never spends a token (PANEL-BUILD.md P3 build item 7: "the
|
|
105
|
+
* person must get feedback BEFORE drafting if the chosen model can't
|
|
106
|
+
* work"). Reused, unmodified, by the panel's model-readiness route today
|
|
107
|
+
* (`src/panel/authorroutes.js`) and by the future Settings providers
|
|
108
|
+
* table's own "test" column (PANEL-BUILD.md P4) — ONE function, not two
|
|
109
|
+
* hand-typed copies of the same probe.
|
|
110
|
+
*
|
|
111
|
+
* NEVER returns the key, never logs it — the key only ever appears in a
|
|
112
|
+
* request header sent straight to the provider's own host.
|
|
113
|
+
* @param {object} o
|
|
114
|
+
* @param {string} o.providerName
|
|
115
|
+
* @param {string} o.apiKey
|
|
116
|
+
* @param {string} [o.model] when given, the response is also checked for this model id
|
|
117
|
+
* @param {string} [o.baseUrl]
|
|
118
|
+
* @param {typeof fetch} [o.fetchImpl] TEST SEAM — defaults to the real global `fetch`
|
|
119
|
+
* @param {number} [o.timeoutMs] defaults to 4000 — a flaky endpoint must never hang the caller
|
|
120
|
+
* @returns {Promise<{reachable: boolean, modelListed: boolean|null, status: string, note: string|null}>}
|
|
121
|
+
*/
|
|
122
|
+
export function checkProviderReachable({ providerName, apiKey, model, baseUrl, fetchImpl, timeoutMs, }: {
|
|
123
|
+
providerName: string;
|
|
124
|
+
apiKey: string;
|
|
125
|
+
model?: string | undefined;
|
|
126
|
+
baseUrl?: string | undefined;
|
|
127
|
+
fetchImpl?: typeof fetch | undefined;
|
|
128
|
+
timeoutMs?: number | undefined;
|
|
129
|
+
}): Promise<{
|
|
130
|
+
reachable: boolean;
|
|
131
|
+
modelListed: boolean | null;
|
|
132
|
+
status: string;
|
|
133
|
+
note: string | null;
|
|
134
|
+
}>;
|
|
101
135
|
/**
|
|
102
136
|
* The launch-time warning lines for an ADMITTED-PENDING-PROBE provider, or
|
|
103
137
|
* `null` when the provider has paid for its own end-to-end probe (and for an
|
package/types/replay.d.ts
CHANGED
|
@@ -89,6 +89,8 @@ export function replayRun(spineEvents: any[], auditEvents?: any[], { runId, audi
|
|
|
89
89
|
stopReason: string | null;
|
|
90
90
|
spentUsd: any;
|
|
91
91
|
spendComplete: boolean;
|
|
92
|
+
draftSpentUsd: any;
|
|
93
|
+
draftSpendComplete: boolean | null;
|
|
92
94
|
floorReasons: string[];
|
|
93
95
|
transportRetryCount: number;
|
|
94
96
|
transportRetriesOutsideWindows: number;
|
|
@@ -239,6 +241,35 @@ export function replayRun(spineEvents: any[], auditEvents?: any[], { runId, audi
|
|
|
239
241
|
memoryCache: any;
|
|
240
242
|
skipped: number;
|
|
241
243
|
};
|
|
244
|
+
/**
|
|
245
|
+
* hamr's ruling 2026-09-28 ("one cap covers drafting + run") — the ONE
|
|
246
|
+
* spend display for a run that may carry a drafting share, so every surface
|
|
247
|
+
* that shows a run's money (the CLI's own `spent` line, the panel's Run tab
|
|
248
|
+
* summary/counters, the Runs list row, the Audit header, the Job tab) reads
|
|
249
|
+
* the same string rather than each hand-composing its own. `spendCore` is
|
|
250
|
+
* already-formatted text (`money(...)`, or a `died`/floor line's "at least
|
|
251
|
+
* $X") — this only decides whether to append the `(<draft> drafting)`
|
|
252
|
+
* clause and the `of $<cap>` tail, never re-derives the money itself.
|
|
253
|
+
* Unchanged (`spendCore` alone, or `spendCore of $cap`) when there is no
|
|
254
|
+
* drafting share — a run without one prints exactly what it always did.
|
|
255
|
+
*
|
|
256
|
+
* hamr's ruling 2026-09-28 (2nd addendum) — an INCOMPLETE drafting fold
|
|
257
|
+
* (`draftSpendComplete === false`) is a floor, not a total, and F6's rule
|
|
258
|
+
* ("unpriced is never free, a floor never dresses as exact") applies here
|
|
259
|
+
* exactly as it does to `spendCore` itself: the drafting clause reads `at
|
|
260
|
+
* least $X drafting`, and because a reader summing the two figures would
|
|
261
|
+
* otherwise take the LEADING number as exact too, `spendCore` itself also
|
|
262
|
+
* gains the `at least ` prefix — unless it already carries one (a `died`
|
|
263
|
+
* floor, or an already-prefixed caller), never doubled.
|
|
264
|
+
* @param {string} spendCore already-formatted spend text (e.g. `$3.71` or `at least $2.00`)
|
|
265
|
+
* @param {number|null} draftSpentUsd the drafting share, or null when there isn't one
|
|
266
|
+
* @param {number|null} [budgetUsd] the signed cap, appended as `of $X.XX` when given
|
|
267
|
+
* @param {boolean|null} [draftSpendComplete] whether the drafting fold above was EXACT;
|
|
268
|
+
* `null`/`undefined`/`true` all read as exact (never a new enum value elsewhere) —
|
|
269
|
+
* only an explicit `false` triggers the floor wording.
|
|
270
|
+
* @returns {string}
|
|
271
|
+
*/
|
|
272
|
+
export function moneyWithDraft(spendCore: string, draftSpentUsd: number | null, budgetUsd?: number | null, draftSpendComplete?: boolean | null): string;
|
|
242
273
|
/**
|
|
243
274
|
* Render a {@link replayRun} summary as one printable page: a header block
|
|
244
275
|
* (goal/shape/signed/branch/outcome/spent), a timeline (steps or iterations,
|
package/types/replayio.d.ts
CHANGED
|
@@ -42,7 +42,8 @@ export function resolveSiblings(spinePath: string): {
|
|
|
42
42
|
* Read one run's spine (+ its gate-audit sidecar, when present) off disk and
|
|
43
43
|
* hand both to {@link replayRun}. Read-only, $0, mints no verdict.
|
|
44
44
|
* @param {string} spinePath absolute or cwd-relative path to a `.jsonl` spine
|
|
45
|
-
* @param {{preParsedSpine?: {records: any[], skipped: number}, skipAudit?: boolean
|
|
45
|
+
* @param {{preParsedSpine?: {records: any[], skipped: number}, skipAudit?: boolean,
|
|
46
|
+
* auditPathOverride?: string|null}} [opts]
|
|
46
47
|
* `preParsedSpine`: avoids a second parse of the same file when the caller
|
|
47
48
|
* ({@link listSpines}) already read it once to run {@link looksLikeSpine}.
|
|
48
49
|
* `skipAudit` (PR #23 review item 5, 2026-08-26, carried over): a
|
|
@@ -50,6 +51,15 @@ export function resolveSiblings(spinePath: string): {
|
|
|
50
51
|
* `summarizeForAllLine` reads none of the fields that sidecar feeds inside
|
|
51
52
|
* `replayRun`, so reading every run's sidecar in a directory listing was
|
|
52
53
|
* pure unused I/O, multiplied by every spine found.
|
|
54
|
+
* `auditPathOverride` (build item 7, 2026-09-28): when a caller has ALREADY
|
|
55
|
+
* resolved the real audit path through the one shared resolver
|
|
56
|
+
* (`src/panel/server.js`'s `resolveAuditPathForRow`, which also covers a
|
|
57
|
+
* still-LIVE run's during-run sidecar location — this function's own
|
|
58
|
+
* `resolveSiblings` call only ever finds the FINISHED-run convention), it
|
|
59
|
+
* passes that path here (`null` included) instead of letting this
|
|
60
|
+
* function re-derive a finished-only path on its own. `undefined` (the
|
|
61
|
+
* default) keeps the original resolveSiblings-only behaviour — every
|
|
62
|
+
* existing caller is unaffected.
|
|
53
63
|
* @returns {ReturnType<typeof replayRun>}
|
|
54
64
|
*/
|
|
55
65
|
export function replayOne(spinePath: string, opts?: {
|
|
@@ -58,6 +68,7 @@ export function replayOne(spinePath: string, opts?: {
|
|
|
58
68
|
skipped: number;
|
|
59
69
|
};
|
|
60
70
|
skipAudit?: boolean;
|
|
71
|
+
auditPathOverride?: string | null;
|
|
61
72
|
}): ReturnType<typeof replayRun>;
|
|
62
73
|
/**
|
|
63
74
|
* List every spine found directly in `dir` (not recursive — same as the
|
package/types/run.d.ts
CHANGED
|
@@ -73,6 +73,29 @@
|
|
|
73
73
|
* load gate refuses one: a refusal returns the distinct `recipe-stale` outcome with zero
|
|
74
74
|
* spend rather than silently drafting cold, because starting a paid run on a decision
|
|
75
75
|
* nobody made is the same class of error as widening a cap to manufacture a green.
|
|
76
|
+
* @param {number} [opts.draftSpentUsd=0] hamr's ruling 2026-09-28 ("one cap covers
|
|
77
|
+
* drafting + run") — money the AUTHORING pipeline (`authorCloseForJob`/
|
|
78
|
+
* `prepareSigning`, run under the SAME signed `budgetUsd` as its ceiling) already
|
|
79
|
+
* spent on THIS job before it was ever signed. The signed `budgetUsd` stays the
|
|
80
|
+
* one number in the spec hash; this shrinks the RUN's own enforced ceiling by
|
|
81
|
+
* what drafting already took, so the two phases never spend more than the one
|
|
82
|
+
* cap together. Deliberately NOT `priorSpentUsd` — that key means "a previous
|
|
83
|
+
* ATTEMPT of this same run died and folded its spend forward" and is read by
|
|
84
|
+
* `readResume`/`replay.js`'s `resumed` flag; a drafting spend is not a resume and
|
|
85
|
+
* must never make an ordinary first run of a job read as one. It is also never
|
|
86
|
+
* folded into `spentUsd` (the run's own ledger, cumulative-so-far and what a
|
|
87
|
+
* resume's `priorSpentUsd` seeds) or into `engagementSpentUsd` — drafting is a
|
|
88
|
+
* DIFFERENT phase's spend, reported beside the run's, never inside it. A garbage
|
|
89
|
+
* value (non-finite, negative) is read as 0, belted exactly like `priorSpentUsd`.
|
|
90
|
+
* @param {boolean} [opts.draftSpendComplete=true] hamr's ruling 2026-09-28 — was the
|
|
91
|
+
* `draftSpentUsd` fold above EXACT? The authoring pipeline's own metered-call list can
|
|
92
|
+
* go unpriced (F6) exactly like a resumed attempt's can, and the unknown does not heal
|
|
93
|
+
* by folding forward. A NEW field beside `draftSpentUsd`, never a new state inside
|
|
94
|
+
* `spendComplete`/`priorSpendComplete` — those answer "is THIS run's own ledger exact,"
|
|
95
|
+
* this answers "was the OTHER phase's ledger exact," and the two must never merge into
|
|
96
|
+
* one flag or a floor drafting spend could read as an exact run. Read only when
|
|
97
|
+
* `draftSpentUsd` itself is emitted; a garbage value is read as `true` (the same belt
|
|
98
|
+
* `priorSpendComplete` gets — an unreadable flag never manufactures a false floor).
|
|
76
99
|
* @param {number} [opts.priorSpentUsd=0] RESUME (module C) — money a PREVIOUS, killed
|
|
77
100
|
* attempt of this same try already spent. It seeds the ledger, so the restarted
|
|
78
101
|
* attempt runs under the REMAINDER of the signed `budgetUsd` and the terminal
|
|
@@ -181,7 +204,7 @@
|
|
|
181
204
|
* deliberately NOT in the resumable/checkpoint set (`src/reuse.js`) — an
|
|
182
205
|
* unknown in-flight state is not a known-safe resume point.
|
|
183
206
|
*/
|
|
184
|
-
export function runJob(rawSpec: object | string, { approvals, workdir, provider, nativeProvider, providerFor, judgeProvider, judgeModel, emit, capRuns, strikeLimit, shellCapUsd, closeTimeoutMs, closeDir, layerRoot, readShim, scout, bridge, priorSpentUsd, priorSpendComplete, priorWallMs, resumeSeed, resumeGrades, resumeReplans, resumeBranch, humanRuling, heldRuling, reviewDoor, doorRerun, resumable }: {
|
|
207
|
+
export function runJob(rawSpec: object | string, { approvals, workdir, provider, nativeProvider, providerFor, judgeProvider, judgeModel, emit, capRuns, strikeLimit, shellCapUsd, closeTimeoutMs, closeDir, layerRoot, readShim, scout, bridge, draftSpentUsd, draftSpendComplete, priorSpentUsd, priorSpendComplete, priorWallMs, resumeSeed, resumeGrades, resumeReplans, resumeBranch, humanRuling, heldRuling, reviewDoor, doorRerun, resumable }: {
|
|
185
208
|
approvals: unknown;
|
|
186
209
|
workdir: string;
|
|
187
210
|
provider: any;
|
|
@@ -201,6 +224,8 @@ export function runJob(rawSpec: object | string, { approvals, workdir, provider,
|
|
|
201
224
|
closeTimeoutMs?: number | undefined;
|
|
202
225
|
closeDir?: string | null | undefined;
|
|
203
226
|
bridge?: unknown;
|
|
227
|
+
draftSpentUsd?: number | undefined;
|
|
228
|
+
draftSpendComplete?: boolean | undefined;
|
|
204
229
|
priorSpentUsd?: number | undefined;
|
|
205
230
|
priorSpendComplete?: boolean | undefined;
|
|
206
231
|
priorWallMs?: number | undefined;
|
package/types/runlist.d.ts
CHANGED
|
@@ -101,6 +101,7 @@ export function backfillRuns(dir: string, opts?: {
|
|
|
101
101
|
* @returns {string}
|
|
102
102
|
*/
|
|
103
103
|
export function formatRunRow(row: RunRow): string;
|
|
104
|
+
export const DIED_MTIME_MS: number;
|
|
104
105
|
export const MAX_BACKFILL_DEPTH: 6;
|
|
105
106
|
export type RunRow = {
|
|
106
107
|
at: string;
|
package/types/userrun.d.ts
CHANGED
|
@@ -43,6 +43,11 @@ export function answerDoor(runId: string, decision: {
|
|
|
43
43
|
export function main(argv: string[], deps?: Deps): Promise<number>;
|
|
44
44
|
export type Deps = {
|
|
45
45
|
env?: Record<string, string | undefined> | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* P4a — a test seam naming the home whose `.env` keys file is loaded
|
|
48
|
+
* even when `env` is injected; production never sets it.
|
|
49
|
+
*/
|
|
50
|
+
keysHome?: string | undefined;
|
|
46
51
|
out?: ((s: string) => void) | undefined;
|
|
47
52
|
err?: ((s: string) => void) | undefined;
|
|
48
53
|
/**
|
|
@@ -92,6 +97,21 @@ export type RunOpts = {
|
|
|
92
97
|
* the raw `--scout` value (`on`/`off`), or null for the default
|
|
93
98
|
*/
|
|
94
99
|
scout?: string | null | undefined;
|
|
100
|
+
/**
|
|
101
|
+
* the raw `--draft-spent-usd` value (hamr's
|
|
102
|
+
* ruling 2026-09-28, "one cap covers drafting + run"), or null when the job never
|
|
103
|
+
* drafted through the panel/`bareloop author`. Parsed and validated in `execute`
|
|
104
|
+
* (finite, >= 0, else refused) — never coerced silently, the same param-guard
|
|
105
|
+
* class `--read-shim`/`--scout` already are.
|
|
106
|
+
*/
|
|
107
|
+
draftSpentUsd?: string | null | undefined;
|
|
108
|
+
/**
|
|
109
|
+
* the raw `--draft-spend-incomplete` presence-
|
|
110
|
+
* flag (hamr's ruling 2026-09-28, 2nd addendum) — whether the drafting fold above was a
|
|
111
|
+
* FLOOR, never an exact figure. A new field beside `draftSpentUsd`, same param-guard
|
|
112
|
+
* class, no value to misread.
|
|
113
|
+
*/
|
|
114
|
+
draftSpendIncomplete?: boolean | undefined;
|
|
95
115
|
/**
|
|
96
116
|
* a bridge registry directory
|
|
97
117
|
*/
|
|
@@ -129,6 +149,8 @@ export type RunCtx = {
|
|
|
129
149
|
model: string | null;
|
|
130
150
|
readShim: string | null;
|
|
131
151
|
scout: string | null;
|
|
152
|
+
draftSpentUsd: string | null;
|
|
153
|
+
draftSpendIncomplete: boolean;
|
|
132
154
|
registry: string | null;
|
|
133
155
|
workflow: string | null;
|
|
134
156
|
approve: string | null;
|