bareloop 0.40.0 → 0.42.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 +96 -1
- package/README.md +13 -21
- package/bareloop.context.md +141 -128
- package/package.json +5 -4
- package/src/authorflow.js +346 -38
- package/src/authoring.js +92 -7
- package/src/authorjob.js +82 -20
- package/src/authorreadout.js +89 -5
- package/src/authorrun.js +39 -30
- package/src/authorscout.js +112 -4
- package/src/bundle.js +7 -4
- package/src/bundlerun.js +4 -1
- package/src/cli.js +1 -1
- package/src/config.js +129 -29
- package/src/declaredclose.js +23 -12
- package/src/draftspend.js +4 -4
- package/src/facts.js +317 -0
- package/src/factwords.js +129 -0
- package/src/index.js +2 -4
- package/src/inputlook.js +301 -0
- package/src/interviewrun.js +17 -25
- package/src/job.js +15 -8
- package/src/jobblock.js +7 -2
- package/src/judged.js +11 -43
- package/src/keysfile.js +15 -7
- package/src/kinds.js +86 -5
- package/src/labelscan.js +170 -0
- package/src/modellist.js +84 -0
- package/src/monthly.js +23 -43
- package/src/pagefetch.js +125 -0
- package/src/panel/authorroutes.js +34 -16
- package/src/panel/authorsession.js +161 -80
- package/src/panel/index.html +553 -152
- package/src/panel/jobplan.js +34 -11
- package/src/panel/runroutes.js +3 -0
- package/src/panel/server.js +54 -18
- package/src/panel/settingsroutes.js +232 -173
- package/src/planrun.js +5 -4
- package/src/providerrows.js +226 -141
- package/src/providers.js +58 -332
- package/src/providershapes.js +18 -0
- package/src/replay.js +1 -1
- package/src/rubricstep.js +804 -0
- package/src/source.js +166 -1
- package/src/thinking.js +130 -0
- package/src/u-readout.js +1 -1
- package/src/userrun.js +64 -75
- package/types/authorflow.d.ts +272 -18
- package/types/authoring.d.ts +29 -1
- package/types/authorjob.d.ts +9 -7
- package/types/authorreadout.d.ts +27 -2
- package/types/authorscout.d.ts +72 -2
- package/types/config.d.ts +23 -6
- package/types/declaredclose.d.ts +4 -2
- package/types/draftspend.d.ts +8 -8
- package/types/facts.d.ts +71 -0
- package/types/factwords.d.ts +42 -0
- package/types/index.d.ts +1 -1
- package/types/inputlook.d.ts +238 -0
- package/types/job.d.ts +5 -5
- package/types/jobblock.d.ts +8 -1
- package/types/judged.d.ts +5 -36
- package/types/keysfile.d.ts +15 -4
- package/types/labelscan.d.ts +38 -0
- package/types/modellist.d.ts +50 -0
- package/types/monthly.d.ts +4 -3
- package/types/pagefetch.d.ts +71 -0
- package/types/panel/authorsession.d.ts +20 -11
- package/types/panel/jobplan.d.ts +12 -4
- package/types/panel/server.d.ts +18 -6
- package/types/providerrows.d.ts +192 -99
- package/types/providers.d.ts +34 -159
- package/types/providershapes.d.ts +10 -0
- package/types/rubricstep.d.ts +286 -0
- package/types/source.d.ts +94 -0
- package/types/thinking.d.ts +90 -0
- package/types/userrun.d.ts +17 -1
package/types/judged.d.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* item 31.4 a green job runs on its own key alone, and this is what lets a
|
|
18
18
|
* JUDGED one do the same.
|
|
19
19
|
*
|
|
20
|
-
* There is deliberately NO third fallback to
|
|
20
|
+
* There is deliberately NO third fallback to a library-pinned model. A caller that cannot
|
|
21
21
|
* say which model will grade has not wired a judge, and the grading path stops
|
|
22
22
|
* as a wiring gap rather than grading under an identity nobody chose — the same
|
|
23
23
|
* answer an absent `judgeLoop` already gets. A silent default here would be the
|
|
@@ -79,7 +79,7 @@ export function resolveJudge({ specJudge, workerProvider, workerModel }?: {
|
|
|
79
79
|
*
|
|
80
80
|
* @param {{provider?: string, model?: string, judge?: any}} source draft or spec
|
|
81
81
|
* @param {string} fallbackProviderName used only when `source.provider` is absent
|
|
82
|
-
* @param {(o: {specModel?: string, flagModel?: string,
|
|
82
|
+
* @param {(o: {specModel?: string, flagModel?: string, suppliedModel?: string}) => {model: string, source: string}} resolveWorkerModelFn `resolveWorkerModel` from `./job.js`
|
|
83
83
|
* @returns {{provider: string, model: string}}
|
|
84
84
|
*/
|
|
85
85
|
export function resolveJobJudge(source: {
|
|
@@ -89,7 +89,7 @@ export function resolveJobJudge(source: {
|
|
|
89
89
|
}, fallbackProviderName: string, resolveWorkerModelFn: (o: {
|
|
90
90
|
specModel?: string;
|
|
91
91
|
flagModel?: string;
|
|
92
|
-
|
|
92
|
+
suppliedModel?: string;
|
|
93
93
|
}) => {
|
|
94
94
|
model: string;
|
|
95
95
|
source: string;
|
|
@@ -309,38 +309,6 @@ export function decide(facts: any, card: any, { artifactText }?: {
|
|
|
309
309
|
firstRed: string | null;
|
|
310
310
|
reason: string | null;
|
|
311
311
|
};
|
|
312
|
-
/**
|
|
313
|
-
* THE JUDGE'S HISTORICAL PIN. Until PRD item 32 (2026-09-10) this constant WAS
|
|
314
|
-
* the judge: every grading path imported it, so bareloop could run a worker on
|
|
315
|
-
* any provider and still judge only on Claude.
|
|
316
|
-
*
|
|
317
|
-
* It is no longer read by any grading path. The judge identity is now RESOLVED
|
|
318
|
-
* per job (`resolveJudge` below) and travels as data — `ctx.judgeModel` into
|
|
319
|
-
* `runJudgedFloor`, an explicit argument into the calibration gate, and
|
|
320
|
-
* `closeDecl.calibration.judgeModel` into the signed spec, exactly as before.
|
|
321
|
-
* Keeping the export is deliberate: it is part of the public API
|
|
322
|
-
* (`src/index.js`) and an adopter importing it should not break on a minor.
|
|
323
|
-
* What it means now is "the judge bareloop pinned before item 32", which is
|
|
324
|
-
* still the right DEFAULT for an anthropic-api job and still the only tier with
|
|
325
|
-
* established injection resistance upstream (BA-20's `INJECTION_BATTERY` is
|
|
326
|
-
* haiku-4.5 only).
|
|
327
|
-
*
|
|
328
|
-
* THE ENFORCEMENT IS UNCHANGED, and still lives in three wired places because a
|
|
329
|
-
* rule with no detector is prose (F45) — only the value being compared moved
|
|
330
|
-
* from this constant to the resolved identity:
|
|
331
|
-
* 1. the identity is STORED with the set it graded — `foldJudgedArtifacts`
|
|
332
|
-
* writes it as `closeDecl.calibration.judgeModel`, inside the spec, so
|
|
333
|
-
* `jobSpecHash` covers it by construction. Change the judge and every
|
|
334
|
-
* signed judged spec hashes differently: the signature dies, and re-signing
|
|
335
|
-
* is what re-runs the calibration gate.
|
|
336
|
-
* 2. `validateCloseDecl` REQUIRES it on any stored set — a set nobody can
|
|
337
|
-
* attribute to a judge is a floor nobody can tell apart from a moved one.
|
|
338
|
-
* 3. `runJudgedFloor` refuses to grade when the stored identity is not the one
|
|
339
|
-
* about to grade, naming both. It does not degrade in either direction:
|
|
340
|
-
* grading on the new judge judges against a floor nobody calibrated, and
|
|
341
|
-
* the old judge is not on offer.
|
|
342
|
-
*/
|
|
343
|
-
export const JUDGE_MODEL: "claude-haiku-4-5";
|
|
344
312
|
/**
|
|
345
313
|
* The locate call's token ceiling. The POC's two real artifacts came back well
|
|
346
314
|
* inside 2000; this doubles that for headroom on a longer artifact, and the
|
|
@@ -402,13 +370,14 @@ export const JUDGE_RULE_IDS: readonly string[];
|
|
|
402
370
|
export const CALIBRATION_SIZE: 10;
|
|
403
371
|
/** the two verdicts a case may expect — `decide()`'s own closed set */
|
|
404
372
|
export const CASE_VERDICTS: readonly string[];
|
|
405
|
-
export function defaultJudgeLoop({ provider, system, rates }: {
|
|
373
|
+
export function defaultJudgeLoop({ provider, system, rates, thinking }: {
|
|
406
374
|
provider: any;
|
|
407
375
|
system: string;
|
|
408
376
|
rates?: {
|
|
409
377
|
in: number;
|
|
410
378
|
out: number;
|
|
411
379
|
} | null;
|
|
380
|
+
thinking?: boolean;
|
|
412
381
|
}): {
|
|
413
382
|
run: (msgs: any[], tools: any[], opts?: any) => Promise<any>;
|
|
414
383
|
};
|
package/types/keysfile.d.ts
CHANGED
|
@@ -25,19 +25,20 @@ export function parseKeysText(text: string): Record<string, string>;
|
|
|
25
25
|
*/
|
|
26
26
|
export function filledKeyNames(home?: string): string[];
|
|
27
27
|
/**
|
|
28
|
-
* Create the keys file with
|
|
29
|
-
* exist (mode 600). An existing file is never touched.
|
|
30
|
-
* @param {readonly string[]} presetNames the names to seed, in order
|
|
28
|
+
* Create the keys file with {@link KEYS_FILE_BODY} when — and only when — it does not
|
|
29
|
+
* exist (mode 600, dir 700). An existing file is never touched.
|
|
31
30
|
* @param {string} [home]
|
|
32
31
|
* @returns {boolean} true if it was created
|
|
33
32
|
*/
|
|
34
|
-
export function ensureKeysFile(
|
|
33
|
+
export function ensureKeysFile(home?: string): boolean;
|
|
35
34
|
/**
|
|
36
35
|
* @typedef {object} KeysLoad
|
|
37
36
|
* @property {boolean} exists the file is there
|
|
38
37
|
* @property {string[]} names the NAMES the file defines (sorted; never values)
|
|
39
38
|
* @property {string|null} warning a plain-words warning (file readable by others, or
|
|
40
39
|
* unreadable), else null — a warning, never a refusal
|
|
40
|
+
* @property {boolean} [unreadable] true only when the file is there but could not be read (the Settings row then
|
|
41
|
+
* reads "refused — see above"); absent otherwise
|
|
41
42
|
* @property {Record<string,string|undefined>} env shell env with the file filling the
|
|
42
43
|
* names the shell does not set. THE ONLY place values leave this module.
|
|
43
44
|
*/
|
|
@@ -68,6 +69,11 @@ export function keysForDoor(deps: {
|
|
|
68
69
|
env: Record<string, string | undefined>;
|
|
69
70
|
home: string | undefined;
|
|
70
71
|
};
|
|
72
|
+
/**
|
|
73
|
+
* The two comment lines a fresh keys file is created with — no provider name, no preset key.
|
|
74
|
+
* Each key the person types becomes a row in Settings > Providers.
|
|
75
|
+
*/
|
|
76
|
+
export const KEYS_FILE_BODY: string;
|
|
71
77
|
export type KeysLoad = {
|
|
72
78
|
/**
|
|
73
79
|
* the file is there
|
|
@@ -82,6 +88,11 @@ export type KeysLoad = {
|
|
|
82
88
|
* unreadable), else null — a warning, never a refusal
|
|
83
89
|
*/
|
|
84
90
|
warning: string | null;
|
|
91
|
+
/**
|
|
92
|
+
* true only when the file is there but could not be read (the Settings row then
|
|
93
|
+
* reads "refused — see above"); absent otherwise
|
|
94
|
+
*/
|
|
95
|
+
unreadable?: boolean | undefined;
|
|
85
96
|
/**
|
|
86
97
|
* shell env with the file filling the
|
|
87
98
|
* names the shell does not set. THE ONLY place values leave this module.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/** @typedef {{id: string, label: string, count: number, example: string}} LabelEntry */
|
|
2
|
+
/** @typedef {Record<'money'|'number'|'date'|'time'|'text', LabelEntry[]>} LabelScan */
|
|
3
|
+
/** @param {string} t @returns {string} white space made one space, quote marks at the edges dropped, trimmed - how a label is compared */
|
|
4
|
+
export function normLabel(t: string): string;
|
|
5
|
+
/**
|
|
6
|
+
* Scan one source text for the labels that sit before values, per shape.
|
|
7
|
+
* @param {string} text
|
|
8
|
+
* @returns {LabelScan}
|
|
9
|
+
*/
|
|
10
|
+
export function scanLabels(text: string): LabelScan;
|
|
11
|
+
/**
|
|
12
|
+
* Is this label on the list for this shape? Compared the way a label is read: white space of any kind is one space, quote marks at the
|
|
13
|
+
* edges are dropped. `idOrText` may be a list id (`t1`) or the exact words.
|
|
14
|
+
* @param {LabelScan} scan @param {string} shape @param {unknown} idOrText
|
|
15
|
+
* @returns {LabelEntry|null}
|
|
16
|
+
*/
|
|
17
|
+
export function labelOnList(scan: LabelScan, shape: string, idOrText: unknown): LabelEntry | null;
|
|
18
|
+
/**
|
|
19
|
+
* The list as the look and the drafter are shown it, one block per shape that has any label.
|
|
20
|
+
* @param {string} inputLabel the input the list belongs to @param {LabelScan} scan
|
|
21
|
+
* @returns {string}
|
|
22
|
+
*/
|
|
23
|
+
export function renderLabelList(inputLabel: string, scan: LabelScan): string;
|
|
24
|
+
/** the shapes a list is made for */
|
|
25
|
+
export const LABEL_SHAPES: readonly string[];
|
|
26
|
+
/** a label must occur at least this often to be listed (1: a one-page document with one total still has its label; the list is cut to the highest counts) */
|
|
27
|
+
export const MIN_COUNT: 1;
|
|
28
|
+
/** how many labels one shape's list holds at most (the highest counts first) */
|
|
29
|
+
export const MAX_PER_SHAPE: 40;
|
|
30
|
+
/** only this much of a source is scanned (a source over it is scanned up to a line end) */
|
|
31
|
+
export const SCAN_MAX_CHARS: 2000000;
|
|
32
|
+
export type LabelEntry = {
|
|
33
|
+
id: string;
|
|
34
|
+
label: string;
|
|
35
|
+
count: number;
|
|
36
|
+
example: string;
|
|
37
|
+
};
|
|
38
|
+
export type LabelScan = Record<"money" | "number" | "date" | "time" | "text", LabelEntry[]>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The key goes only in a header, in the form each shape expects.
|
|
3
|
+
* @param {string} shape an API shape id (src/providershapes.js)
|
|
4
|
+
* @param {string} key
|
|
5
|
+
* @returns {Record<string, string>}
|
|
6
|
+
*/
|
|
7
|
+
export function authHeaders(shape: string, key: string): Record<string, string>;
|
|
8
|
+
/**
|
|
9
|
+
* The model ids a provider's list answer holds, per API shape (`data[].id` for two shapes;
|
|
10
|
+
* `models[].name` minus its `models/` prefix for the third). Sorted, de-duplicated.
|
|
11
|
+
* @param {string} shape
|
|
12
|
+
* @param {any} body
|
|
13
|
+
* @returns {string[]}
|
|
14
|
+
*/
|
|
15
|
+
export function idsOf(shape: string, body: any): string[];
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {{ ok: true, models: string[], ms: number }
|
|
18
|
+
* | { ok: false, why: string, status: string, detail?: string }} ListResult
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* One free GET of `<baseUrl>/models` with the key in the header only and a deadline.
|
|
22
|
+
* Failure is data, never a throw: `why` is a plain sentence, `status` a short machine word
|
|
23
|
+
* (`no-base-url`, `redirect`, `HTTP <n>`, `timeout`, `unreachable`) for callers that need it.
|
|
24
|
+
* @param {object} o
|
|
25
|
+
* @param {string} o.shape an API shape id
|
|
26
|
+
* @param {string} o.baseUrl the row's Base URL ('' = no call)
|
|
27
|
+
* @param {string} o.key the key value (header only)
|
|
28
|
+
* @param {typeof fetch} [o.fetchImpl] test seam; defaults to the global `fetch`
|
|
29
|
+
* @param {number} [o.timeoutMs]
|
|
30
|
+
* @returns {Promise<ListResult>}
|
|
31
|
+
*/
|
|
32
|
+
export function listModels({ shape, baseUrl, key, fetchImpl, timeoutMs }: {
|
|
33
|
+
shape: string;
|
|
34
|
+
baseUrl: string;
|
|
35
|
+
key: string;
|
|
36
|
+
fetchImpl?: typeof fetch | undefined;
|
|
37
|
+
timeoutMs?: number | undefined;
|
|
38
|
+
}): Promise<ListResult>;
|
|
39
|
+
/** The default deadline for the one GET. */
|
|
40
|
+
export const LIST_TIMEOUT_MS: 4000;
|
|
41
|
+
export type ListResult = {
|
|
42
|
+
ok: true;
|
|
43
|
+
models: string[];
|
|
44
|
+
ms: number;
|
|
45
|
+
} | {
|
|
46
|
+
ok: false;
|
|
47
|
+
why: string;
|
|
48
|
+
status: string;
|
|
49
|
+
detail?: string;
|
|
50
|
+
};
|
package/types/monthly.d.ts
CHANGED
|
@@ -48,11 +48,11 @@ export function monthSpend(opts?: {
|
|
|
48
48
|
};
|
|
49
49
|
/**
|
|
50
50
|
* The Money tab's figures: all-time and this-month spend, and per-provider breakdown
|
|
51
|
-
* (
|
|
52
|
-
* pooled into another row). Any leg with unknown spend makes the figure it belongs to
|
|
51
|
+
* (grouped by the matched Providers row's key variable name; a run on no row lands under its
|
|
52
|
+
* own provider name, never pooled into another row). Any leg with unknown spend makes the figure it belongs to
|
|
53
53
|
* an "at least".
|
|
54
54
|
* @param {{ home?: string, sessionsRoot?: string, now?: () => number, rows?: readonly import('./providerrows.js').KeyRow[] }} [opts] `rows` = the Providers rows: when given, `tokensByRow` sums each row's tokens
|
|
55
|
-
* @returns {{ tokensByRow: Record<string, number>, total: {usd: number, atLeast: boolean, tokens: number}, month: {usd: number, atLeast: boolean, tokens: number},
|
|
55
|
+
* @returns {{ tokensByRow: Record<string, number>, tokensByModel: Record<string, Record<string, number>>, total: {usd: number, atLeast: boolean, tokens: number}, month: {usd: number, atLeast: boolean, tokens: number},
|
|
56
56
|
* byProvider: Record<string, {label: string, monthUsd: number, monthAtLeast: boolean, totalUsd: number, totalAtLeast: boolean, tokens: number, vouchedRounds: number, otherRounds: number, monthWallMs: number|null, monthWallAtLeast: boolean, totalWallMs: number|null, totalWallAtLeast: boolean}> }}
|
|
57
57
|
*/
|
|
58
58
|
export function spendSummary(opts?: {
|
|
@@ -62,6 +62,7 @@ export function spendSummary(opts?: {
|
|
|
62
62
|
rows?: readonly import("./providerrows.js").KeyRow[];
|
|
63
63
|
}): {
|
|
64
64
|
tokensByRow: Record<string, number>;
|
|
65
|
+
tokensByModel: Record<string, Record<string, number>>;
|
|
65
66
|
total: {
|
|
66
67
|
usd: number;
|
|
67
68
|
atLeast: boolean;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/** @param {unknown} v @returns {boolean} an http(s) address (the one spelling of "this Inputs value is a web address") */
|
|
2
|
+
export function isWebUrl(v: unknown): boolean;
|
|
3
|
+
/**
|
|
4
|
+
* How much of a fetched page is the page's own content: the snapshot's header lines (url, size note, hint) and every part of the tree
|
|
5
|
+
* under a banner / navigation / contentinfo landmark are taken out, the page reader's bracketed tags are removed, and what is left is
|
|
6
|
+
* counted. Generic - no site names, only the ARIA landmark roles. Text that is not a snapshot tree (a plain file) has no landmark, so it
|
|
7
|
+
* counts whole.
|
|
8
|
+
* @param {string} text @returns {number}
|
|
9
|
+
*/
|
|
10
|
+
export function pageContentChars(text: string): number;
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {{goto: (url: string, timeout?: number) => Promise<void>, waitForNetworkIdle: (o?: {idle?: number, timeout?: number}) => Promise<void>,
|
|
13
|
+
* snapshot: (o?: {mode?: string}) => Promise<string>, close: () => Promise<void>}} FetchPage the part of barebrowse's page handle the fetch uses
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Fetch one page's text. `connect` is injected (a test never reaches the network); the default is barebrowse's own `connect`.
|
|
17
|
+
* @param {string} url
|
|
18
|
+
* @param {{connect?: (opts: Record<string, any>) => Promise<FetchPage>, timeoutMs?: number, idleMs?: number, idleTimeoutMs?: number, closeWaitMs?: number}} [o]
|
|
19
|
+
* @returns {Promise<{ok: true, text: string, url: string}|{ok: false, error: string}>} `error` is plain words, without a spend line
|
|
20
|
+
*/
|
|
21
|
+
export function fetchPageText(url: string, { connect, timeoutMs, idleMs, idleTimeoutMs, closeWaitMs }?: {
|
|
22
|
+
connect?: (opts: Record<string, any>) => Promise<FetchPage>;
|
|
23
|
+
timeoutMs?: number;
|
|
24
|
+
idleMs?: number;
|
|
25
|
+
idleTimeoutMs?: number;
|
|
26
|
+
closeWaitMs?: number;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
ok: true;
|
|
29
|
+
text: string;
|
|
30
|
+
url: string;
|
|
31
|
+
} | {
|
|
32
|
+
ok: false;
|
|
33
|
+
error: string;
|
|
34
|
+
}>;
|
|
35
|
+
/** the session options (incognito: no auth ever enters; blockPrivateNetwork: SSRF guard); ONE frozen object so a test can pin them */
|
|
36
|
+
export const CONNECT_OPTIONS: Readonly<{
|
|
37
|
+
incognito: true;
|
|
38
|
+
blockPrivateNetwork: true;
|
|
39
|
+
}>;
|
|
40
|
+
/** the snapshot options step 0 proved */
|
|
41
|
+
export const SNAPSHOT_OPTIONS: Readonly<{
|
|
42
|
+
mode: "act";
|
|
43
|
+
}>;
|
|
44
|
+
/** the page's network must be quiet this long (ms) before we read it: long enough to span the gap between a page's first load and the
|
|
45
|
+
* script requests that fill the results, short enough not to stretch a plain page */
|
|
46
|
+
export const NETWORK_IDLE_MS: 1500;
|
|
47
|
+
/** the most we wait for the network to go quiet (ms); a page that never settles (polling, streaming) is read as it stands after this */
|
|
48
|
+
export const NETWORK_IDLE_TIMEOUT_MS: 20000;
|
|
49
|
+
/** the most we wait for the page to load at all (ms) */
|
|
50
|
+
export const GOTO_TIMEOUT_MS: 30000;
|
|
51
|
+
/** a page that comes back with fewer characters than this (after trimming) is treated as "nothing came back" */
|
|
52
|
+
export const MIN_PAGE_CHARS: 200;
|
|
53
|
+
/** the page text left after the site's own header, menus and footer are taken out must hold at least this many characters, or the page is
|
|
54
|
+
* "only site chrome" (L2: a 719-character fetch of Google's header and sign-in passed the 200-character floor) */
|
|
55
|
+
export const MIN_CONTENT_CHARS: 100;
|
|
56
|
+
/** our own deadline around one whole fetch (a hung browser leaves no trace; this is the only thing that fires on the absence of an answer) */
|
|
57
|
+
export const PAGE_FETCH_TIMEOUT_MS: 90000;
|
|
58
|
+
/**
|
|
59
|
+
* the part of barebrowse's page handle the fetch uses
|
|
60
|
+
*/
|
|
61
|
+
export type FetchPage = {
|
|
62
|
+
goto: (url: string, timeout?: number) => Promise<void>;
|
|
63
|
+
waitForNetworkIdle: (o?: {
|
|
64
|
+
idle?: number;
|
|
65
|
+
timeout?: number;
|
|
66
|
+
}) => Promise<void>;
|
|
67
|
+
snapshot: (o?: {
|
|
68
|
+
mode?: string;
|
|
69
|
+
}) => Promise<string>;
|
|
70
|
+
close: () => Promise<void>;
|
|
71
|
+
};
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The first drafting row's words (hamr 2026-10-11) — code-owned, one owner, ALWAYS starting "thinking on" or "thinking off".
|
|
3
|
-
* `sent` is what the drafting calls carry (`draftThinkingFor`); `thoughtAnyway` = a call reported `thinkingApplied === false`
|
|
4
|
-
* after 'off' was sent (bare-agent saw reasoning in the reply).
|
|
5
|
-
* @param {'on'|'off'|'not-switchable'|'unverified'} sent @param {boolean} [thoughtAnyway]
|
|
6
|
-
* @returns {string}
|
|
7
|
-
*/
|
|
8
|
-
export function thinkingRowText(sent: "on" | "off" | "not-switchable" | "unverified", thoughtAnyway?: boolean): string;
|
|
9
1
|
/** @typedef {{id: string, label: string, status: 'running'|'done'|'failed', detail: string}} StepLine */
|
|
10
2
|
/** @param {StepLine[]} steps @param {string} id the LATEST line carrying this id (the list is a time-ordered log; an id can repeat) */
|
|
11
3
|
export function latestStep(steps: StepLine[], id: string): StepLine | undefined;
|
|
@@ -15,8 +7,9 @@ export function latestStep(steps: StepLine[], id: string): StepLine | undefined;
|
|
|
15
7
|
* earlier line keeps its status and detail). Existing lines are never moved. Re-starting the step that is still the
|
|
16
8
|
* LAST line just resumes that line.
|
|
17
9
|
* @param {StepLine[]} steps @param {string} id @param {string} [detail] (absent = keep what the line has)
|
|
10
|
+
* @param {Readonly<Record<string, string>>} [labels] the label table (a file job passes its own)
|
|
18
11
|
*/
|
|
19
|
-
export function advanceSteps(steps: StepLine[], id: string, detail?: string): void;
|
|
12
|
+
export function advanceSteps(steps: StepLine[], id: string, detail?: string, labels?: Readonly<Record<string, string>>): void;
|
|
20
13
|
/**
|
|
21
14
|
* The confirm turn's plan as a chat message (P7): a STRUCTURED `{role:'bot', kind:'plan', plan}` the page draws with the
|
|
22
15
|
* same renderer the Job tab uses — each numbered job line, its `~` rule, its drafted checks folded; the AI's own "not
|
|
@@ -147,7 +140,7 @@ export function validateJobCard(card: any, opts?: {
|
|
|
147
140
|
* @param {any} card the validated job card (see {@link validateJobCard})
|
|
148
141
|
* @param {{env?: Record<string,string|undefined>, sessionsRoot?: string, home?: string, timeoutMs?: number,
|
|
149
142
|
* scout?: any, generate?: Function, confirmGenerate?: Function, authorFn?: Function,
|
|
150
|
-
* prepareSigningFn?: Function, npmCiFn?: Function, draftThinking?: "on"|"off", reuse?: {spec: any, workflowKey: string}}} [deps] `scout`..`prepareSigningFn` are
|
|
143
|
+
* prepareSigningFn?: Function, npmCiFn?: Function, lookFn?: Function|null, fetchUrl?: (url: string) => Promise<{ok: true, text: string, url: string}|{ok: false, error: string}>, draftThinking?: "on"|"off", reuse?: {spec: any, workflowKey: string}}} [deps] `scout`..`prepareSigningFn` are
|
|
151
144
|
* TEST SEAMS ONLY — see the note just above where each is read, below. `reuse` (Reuse workflow) is NOT a seam: the
|
|
152
145
|
* caller (`/api/author/start`) sets it only when the server's own same-job rule held.
|
|
153
146
|
* @returns {any} the session object
|
|
@@ -163,6 +156,15 @@ export function createSession(card: any, deps?: {
|
|
|
163
156
|
authorFn?: Function;
|
|
164
157
|
prepareSigningFn?: Function;
|
|
165
158
|
npmCiFn?: Function;
|
|
159
|
+
lookFn?: Function | null;
|
|
160
|
+
fetchUrl?: (url: string) => Promise<{
|
|
161
|
+
ok: true;
|
|
162
|
+
text: string;
|
|
163
|
+
url: string;
|
|
164
|
+
} | {
|
|
165
|
+
ok: false;
|
|
166
|
+
error: string;
|
|
167
|
+
}>;
|
|
166
168
|
draftThinking?: "on" | "off";
|
|
167
169
|
reuse?: {
|
|
168
170
|
spec: any;
|
|
@@ -176,6 +178,12 @@ export function createSession(card: any, deps?: {
|
|
|
176
178
|
* @type {Readonly<Record<string, string>>}
|
|
177
179
|
*/
|
|
178
180
|
export const STEP_LABELS: Readonly<Record<string, string>>;
|
|
181
|
+
/**
|
|
182
|
+
* The same steps, worded for a job on the person's own local FILES (Part 1a): there is no worktree and no repo to read.
|
|
183
|
+
* Code-owned, one table beside STEP_LABELS; a step with no entry keeps its STEP_LABELS word.
|
|
184
|
+
* @type {Readonly<Record<string, string>>}
|
|
185
|
+
*/
|
|
186
|
+
export const FILE_JOB_STEP_LABELS: Readonly<Record<string, string>>;
|
|
179
187
|
/**
|
|
180
188
|
* The library's own `onPhase(name, ...)` calls (`src/authorjob.js`/`src/authorflow.js`) -> the step each one advances.
|
|
181
189
|
* A phase with no entry leaves the current step as it was.
|
|
@@ -195,7 +203,6 @@ export const CARD_FIELDS: readonly string[];
|
|
|
195
203
|
export const REUSE_OPEN_FIELDS: readonly string[];
|
|
196
204
|
/** every card field that is NOT open on a reuse card, in card order */
|
|
197
205
|
export const REUSE_LOCKED_FIELDS: readonly string[];
|
|
198
|
-
export { nonRepoSourceMessage };
|
|
199
206
|
export type StepLine = {
|
|
200
207
|
id: string;
|
|
201
208
|
label: string;
|
|
@@ -203,4 +210,6 @@ export type StepLine = {
|
|
|
203
210
|
detail: string;
|
|
204
211
|
};
|
|
205
212
|
import { planFromConfirm } from './jobplan.js';
|
|
213
|
+
import { thinkingRowText } from '../thinking.js';
|
|
206
214
|
import { nonRepoSourceMessage } from '../source.js';
|
|
215
|
+
export { thinkingRowText, nonRepoSourceMessage };
|
package/types/panel/jobplan.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** @typedef {{name: string, cls: 'machine check'|'judge'|null}} PlanCheck */
|
|
2
|
-
/** @typedef {{n: number, text: string, rule: string, checks: PlanCheck[], refused: string[]}} PlanLine */
|
|
2
|
+
/** @typedef {{n: number, text: string, rule: string, rules: string[], checks: PlanCheck[], refused: string[]}} PlanLine */
|
|
3
3
|
/** @typedef {{lines: PlanLine[], loose: PlanCheck[], notChecked: string[], alwaysOn: string[], older: boolean, goal?: string}} JobPlan */
|
|
4
4
|
/**
|
|
5
5
|
* `machine check` for a kind a command decides, `judge` for one that needs judgement; `null` for a stage whose kind is
|
|
@@ -8,9 +8,15 @@
|
|
|
8
8
|
* @returns {'machine check'|'judge'|null}
|
|
9
9
|
*/
|
|
10
10
|
export function checkClassOfKind(kind: unknown): "machine check" | "judge" | null;
|
|
11
|
+
/**
|
|
12
|
+
* The `~` rules of one job line, each on its own (the page draws one `~` row per rule): the line's own `rules` array when it
|
|
13
|
+
* has one (a rule may itself contain "; "), else the joined `rule` split on "; " (an older line that saved only the join).
|
|
14
|
+
* @param {any} l @returns {string[]}
|
|
15
|
+
*/
|
|
16
|
+
export function rulesOfLine(l: any): string[];
|
|
11
17
|
/**
|
|
12
18
|
* The plan of a SIGNED spec. With `jobLines`, each stage lands under EACH line its `fromLine` array names (a stage with none is
|
|
13
|
-
* a mandatory guard: "Always
|
|
19
|
+
* a mandatory guard: "Always checked"), `closeDecl.refused` reasons land under their line, and `closeDecl.notes` are the
|
|
14
20
|
* drafter's own "not checked" words. Without `jobLines` (a spec that predates the job block) the signed goal sentence is
|
|
15
21
|
* line 1 and every stage name is a check under it — `older: true`.
|
|
16
22
|
* @param {any} spec
|
|
@@ -19,8 +25,8 @@ export function checkClassOfKind(kind: unknown): "machine check" | "judge" | nul
|
|
|
19
25
|
export function planFromSpec(spec: any): JobPlan;
|
|
20
26
|
/**
|
|
21
27
|
* The plan of the confirm turn, before anything is drafted: the person's own job lines, the model's checks under the
|
|
22
|
-
* line each names, its own "not checked" words, and the real protections (code-owned) as "Always
|
|
23
|
-
* @param {{n: number, text: string, rule: string}[]|null|undefined} jobLines
|
|
28
|
+
* line each names, its own "not checked" words, and the real protections (code-owned) as "Always checked".
|
|
29
|
+
* @param {{n: number, text: string, rule: string, rules?: string[]}[]|null|undefined} jobLines
|
|
24
30
|
* @param {{checkItems?: {text: string, fromLine: number[]|null}[], checks?: string[], notChecked?: string[], protections?: string[]}} plan
|
|
25
31
|
* @returns {JobPlan}
|
|
26
32
|
*/
|
|
@@ -28,6 +34,7 @@ export function planFromConfirm(jobLines: {
|
|
|
28
34
|
n: number;
|
|
29
35
|
text: string;
|
|
30
36
|
rule: string;
|
|
37
|
+
rules?: string[];
|
|
31
38
|
}[] | null | undefined, plan: {
|
|
32
39
|
checkItems?: {
|
|
33
40
|
text: string;
|
|
@@ -45,6 +52,7 @@ export type PlanLine = {
|
|
|
45
52
|
n: number;
|
|
46
53
|
text: string;
|
|
47
54
|
rule: string;
|
|
55
|
+
rules: string[];
|
|
48
56
|
checks: PlanCheck[];
|
|
49
57
|
refused: string[];
|
|
50
58
|
};
|
package/types/panel/server.d.ts
CHANGED
|
@@ -400,15 +400,17 @@ export function reuseLine(record: {
|
|
|
400
400
|
* $ cap and the Time cap — start at what the run had. `ok:false` when the run's signed job is not on disk (nothing
|
|
401
401
|
* to copy: change the job: Clear the card). `null` when the runid is not listed.
|
|
402
402
|
* @param {string} runid
|
|
403
|
-
* @param {{ home?: string, model?: string }} [opts] `model` = the Model box's current Name (the estimate counts only runs on that worker); absent = the card's own Model
|
|
403
|
+
* @param {{ home?: string, model?: string, provider?: string }} [opts] `model` = the Model box's current Name (the estimate counts only runs on that worker); absent = the card's own Model
|
|
404
404
|
* @returns {{ok: true, origin: {runid: string, job: string}, outcome: string|null, card: Record<string, any>, from: 'signed job',
|
|
405
405
|
* locked: readonly string[], open: readonly string[], note: string|null,
|
|
406
|
-
* specHash: string, workflowKey: string, spec: any, specPath: string,
|
|
406
|
+
* specHash: string, workflowKey: string, spec: any, specPath: string, specNamesModel: boolean,
|
|
407
|
+
* specWorker: {provider: string, endpoint: string, label: string},
|
|
407
408
|
* trackRecord: ReturnType<typeof trackRecordFor>, line: string}|{ok: false, error: string}|null}
|
|
408
409
|
*/
|
|
409
410
|
export function getStartFrom(runid: string, opts?: {
|
|
410
411
|
home?: string;
|
|
411
412
|
model?: string;
|
|
413
|
+
provider?: string;
|
|
412
414
|
}): {
|
|
413
415
|
ok: true;
|
|
414
416
|
origin: {
|
|
@@ -425,6 +427,12 @@ export function getStartFrom(runid: string, opts?: {
|
|
|
425
427
|
workflowKey: string;
|
|
426
428
|
spec: any;
|
|
427
429
|
specPath: string;
|
|
430
|
+
specNamesModel: boolean;
|
|
431
|
+
specWorker: {
|
|
432
|
+
provider: string;
|
|
433
|
+
endpoint: string;
|
|
434
|
+
label: string;
|
|
435
|
+
};
|
|
428
436
|
trackRecord: ReturnType<typeof trackRecordFor>;
|
|
429
437
|
line: string;
|
|
430
438
|
} | {
|
|
@@ -436,12 +444,13 @@ export function getStartFrom(runid: string, opts?: {
|
|
|
436
444
|
* that has at least one GREEN local run, newest green first. `runid` = that job's newest green run, so the page hands
|
|
437
445
|
* it to the existing start-from flow unchanged; `line` is `getStartFrom`'s own estimate line (never a second
|
|
438
446
|
* spelling). Local runs only — an imported job keeps its Reuse button in the Import view. $0, read-only.
|
|
439
|
-
* @param {{ home?: string, model?: string }} [opts] `model` passes through to the estimate line, as start-from's does
|
|
447
|
+
* @param {{ home?: string, model?: string, provider?: string }} [opts] `model` passes through to the estimate line, as start-from's does
|
|
440
448
|
* @returns {{job: string, runid: string, checkType: 'deterministic'|'rubric', line: string}[]}
|
|
441
449
|
*/
|
|
442
450
|
export function listReuseJobs(opts?: {
|
|
443
451
|
home?: string;
|
|
444
452
|
model?: string;
|
|
453
|
+
provider?: string;
|
|
445
454
|
}): {
|
|
446
455
|
job: string;
|
|
447
456
|
runid: string;
|
|
@@ -458,7 +467,7 @@ export function listReuseJobs(opts?: {
|
|
|
458
467
|
* signs it on this machine at [Sign & run]. Same card, same locked/open boxes as a run's reuse. `null` when no such
|
|
459
468
|
* imported job.
|
|
460
469
|
* @param {string} id
|
|
461
|
-
* @param {{ home?: string, model?: string }} [opts] `model` as for {@link getStartFrom}
|
|
470
|
+
* @param {{ home?: string, model?: string, provider?: string }} [opts] `model` as for {@link getStartFrom}
|
|
462
471
|
* @returns {{ok: true, origin: {runid: null, job: string, importId: string}, card: Record<string, any>, from: 'imported job',
|
|
463
472
|
* locked: readonly string[], open: readonly string[], note: string|null, specHash: string, workflowKey: string, spec: any,
|
|
464
473
|
* specPath: null, trackRecord: ReturnType<typeof trackRecordFor>, line: string}|{ok: false, error: string}|null}
|
|
@@ -466,6 +475,7 @@ export function listReuseJobs(opts?: {
|
|
|
466
475
|
export function getStartFromImport(id: string, opts?: {
|
|
467
476
|
home?: string;
|
|
468
477
|
model?: string;
|
|
478
|
+
provider?: string;
|
|
469
479
|
}): {
|
|
470
480
|
ok: true;
|
|
471
481
|
origin: {
|
|
@@ -504,10 +514,11 @@ export function getStartFromImport(id: string, opts?: {
|
|
|
504
514
|
* only `createPanelServer` below always supplies one.
|
|
505
515
|
* @param {import('node:http').IncomingMessage} req
|
|
506
516
|
* @param {import('node:http').ServerResponse} res
|
|
507
|
-
* @param {{ home?: string, port: number, token?: string, authorRoutes?: ReturnType<typeof createAuthorRoutes>, settingsRoutes?: ReturnType<typeof createSettingsRoutes>, runRoutes?: ReturnType<typeof createRunRoutes>, importRoutes?: ReturnType<typeof createImportRoutes> }} opts
|
|
517
|
+
* @param {{ home?: string, packageJsonPath?: string, port: number, token?: string, authorRoutes?: ReturnType<typeof createAuthorRoutes>, settingsRoutes?: ReturnType<typeof createSettingsRoutes>, runRoutes?: ReturnType<typeof createRunRoutes>, importRoutes?: ReturnType<typeof createImportRoutes> }} opts
|
|
508
518
|
*/
|
|
509
519
|
export function handleRequest(req: import("node:http").IncomingMessage, res: import("node:http").ServerResponse, opts: {
|
|
510
520
|
home?: string;
|
|
521
|
+
packageJsonPath?: string;
|
|
511
522
|
port: number;
|
|
512
523
|
token?: string;
|
|
513
524
|
authorRoutes?: ReturnType<typeof createAuthorRoutes>;
|
|
@@ -534,7 +545,7 @@ export function handleRequest(req: import("node:http").IncomingMessage, res: imp
|
|
|
534
545
|
* @param {{ port?: number, home?: string, env?: Record<string,string|undefined>,
|
|
535
546
|
* sessionsRoot?: string, spawnFn?: (...a: any[]) => any, bareloopBin?: string,
|
|
536
547
|
* fetchImpl?: typeof fetch, settleMs?: number, userHome?: string,
|
|
537
|
-
* openFolderSpawn?: (cmd: string, args: string[], o: object) => any, platform?: string }} [opts]
|
|
548
|
+
* openFolderSpawn?: (cmd: string, args: string[], o: object) => any, platform?: string, packageJsonPath?: string }} [opts]
|
|
538
549
|
* @returns {Promise<{ server: import('node:http').Server, port: number, token: string, close: () => Promise<void> }>}
|
|
539
550
|
*/
|
|
540
551
|
export function createPanelServer(opts?: {
|
|
@@ -549,6 +560,7 @@ export function createPanelServer(opts?: {
|
|
|
549
560
|
userHome?: string;
|
|
550
561
|
openFolderSpawn?: (cmd: string, args: string[], o: object) => any;
|
|
551
562
|
platform?: string;
|
|
563
|
+
packageJsonPath?: string;
|
|
552
564
|
}): Promise<{
|
|
553
565
|
server: import("node:http").Server;
|
|
554
566
|
port: number;
|