bareloop 0.43.0 → 0.44.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 +42 -0
- package/bareloop.context.md +52 -13
- package/package.json +2 -2
- package/src/authorflow.js +26 -11
- package/src/authoring.js +1 -1
- package/src/authorjob.js +27 -15
- package/src/authorreadout.js +7 -6
- package/src/declaredclose.js +4 -1
- package/src/draftspend.js +20 -2
- package/src/facts.js +54 -9
- package/src/factwords.js +58 -6
- package/src/inputlook.js +38 -3
- package/src/job.js +1 -1
- package/src/kinds.js +5 -0
- package/src/pagedropwords.js +64 -0
- package/src/pagemap.js +264 -0
- package/src/pagerules.js +319 -0
- package/src/panel/authorroutes.js +34 -30
- package/src/panel/authorsession.js +29 -5
- package/src/panel/index.html +465 -65
- package/src/panel/jobplan.js +4 -2
- package/src/panel/runroutes.js +46 -22
- package/src/panel/server.js +791 -28
- package/src/panel/status.js +33 -0
- package/src/panelmoney.js +29 -0
- package/src/planrun.js +53 -4
- package/src/promptregisters.js +4 -0
- package/src/replay.js +118 -7
- package/src/rubricstep.js +123 -11
- package/src/runlist.js +2 -1
- package/src/schedulewords.js +6 -3
- package/src/source.js +18 -0
- package/src/thinking.js +63 -2
- package/src/userrun.js +28 -14
- package/types/authorflow.d.ts +42 -6
- package/types/authorjob.d.ts +10 -2
- package/types/declaredclose.d.ts +2 -0
- package/types/draftspend.d.ts +27 -1
- package/types/facts.d.ts +15 -0
- package/types/factwords.d.ts +26 -3
- package/types/inputlook.d.ts +15 -0
- package/types/kinds.d.ts +5 -0
- package/types/pagedropwords.d.ts +26 -0
- package/types/pagemap.d.ts +154 -0
- package/types/pagerules.d.ts +86 -0
- package/types/panel/authorroutes.d.ts +17 -14
- package/types/panel/runroutes.d.ts +2 -2
- package/types/panel/server.d.ts +155 -2
- package/types/panel/status.d.ts +51 -0
- package/types/panelmoney.d.ts +5 -0
- package/types/replay.d.ts +21 -1
- package/types/rubricstep.d.ts +57 -1
- package/types/runlist.d.ts +4 -1
- package/types/schedulewords.d.ts +4 -2
- package/types/source.d.ts +11 -0
- package/types/thinking.d.ts +39 -0
- package/types/userrun.d.ts +4 -0
package/types/draftspend.d.ts
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* - `step-start` {no, id, label, at}
|
|
4
4
|
* - `step-end` {no, status: 'done'|'failed', label, at} (a re-opened step writes `step-reopen` {no, at} first)
|
|
5
5
|
* - `step-label` {no, label, at} (the step reads `label` from now on, status and times untouched: the thinking row's "the model thought anyway" / "can't change it" / "not confirmed")
|
|
6
|
+
* - `human` {no, source: 'confirm'|'try-3'|'look', question, answer, line?, at}: one question the person was asked and what they answered (the answer is secret-masked
|
|
7
|
+
* before it is written; the row is written only when BOTH exist, so a question nobody answered leaves no row)
|
|
6
8
|
* - `call` {no, step, label, model, thinking, thinkingSupport, thinkingStatus?, costUsd (null stays null), unpricedRounds, at}: one METERED model call
|
|
7
9
|
* (`thinking` = the tick's mode: off | on; `thinkingSupport` = bare-agent's lookup for the model: true | false | 'unverified';
|
|
8
10
|
* `thinkingStatus` = bare-agent's own verdict for the call's run: applied | unsupported | ignored | unknown, present only when thinkingMode was sent)
|
|
@@ -58,12 +60,33 @@ export function sessionDirForRow(row: {
|
|
|
58
60
|
home?: string;
|
|
59
61
|
sessionsRoot?: string;
|
|
60
62
|
}): string | null;
|
|
63
|
+
/**
|
|
64
|
+
* PRD v1.106 Part 5 Q1: one answered question as the two lines the Audit's drafting table shows under its step. ONE place owns the words.
|
|
65
|
+
* @param {{question: string, answer: string, source?: string, line?: number, at?: string}} h
|
|
66
|
+
* @returns {{question: string, answer: string, source: string, line?: number, at?: string, askedText: string, saidText: string}}
|
|
67
|
+
*/
|
|
68
|
+
export function humanRowWords(h: {
|
|
69
|
+
question: string;
|
|
70
|
+
answer: string;
|
|
71
|
+
source?: string;
|
|
72
|
+
line?: number;
|
|
73
|
+
at?: string;
|
|
74
|
+
}): {
|
|
75
|
+
question: string;
|
|
76
|
+
answer: string;
|
|
77
|
+
source: string;
|
|
78
|
+
line?: number;
|
|
79
|
+
at?: string;
|
|
80
|
+
askedText: string;
|
|
81
|
+
saidText: string;
|
|
82
|
+
};
|
|
61
83
|
/**
|
|
62
84
|
* Fold `<dir>/draft-log.jsonl` into one record per drafting step, each with its calls. A line that cannot be parsed is
|
|
63
85
|
* skipped (a torn last line must not hide the rest).
|
|
64
86
|
* @param {string} dir
|
|
65
87
|
* @returns {{no: number, id: string, label: string, status: 'running'|'done'|'failed', startedAt: string, endedAt: string|null, wallMs: number|null,
|
|
66
|
-
* calls: {label: string, model: string|null, costUsd: number|null, unpricedRounds: number, at: string}[]
|
|
88
|
+
* calls: {label: string, model: string|null, costUsd: number|null, unpricedRounds: number, at: string}[],
|
|
89
|
+
* humans: ReturnType<typeof humanRowWords>[]}[]}
|
|
67
90
|
*/
|
|
68
91
|
export function readDraftSteps(dir: string): {
|
|
69
92
|
no: number;
|
|
@@ -80,6 +103,7 @@ export function readDraftSteps(dir: string): {
|
|
|
80
103
|
unpricedRounds: number;
|
|
81
104
|
at: string;
|
|
82
105
|
}[];
|
|
106
|
+
humans: ReturnType<typeof humanRowWords>[];
|
|
83
107
|
}[];
|
|
84
108
|
/**
|
|
85
109
|
* The DRAFTING PART of a run (hamr 2026-10-06, option A): the first part of the run's views, built from the session's
|
|
@@ -109,6 +133,8 @@ export const DRAFT_LOG_FILE: "draft-log.jsonl";
|
|
|
109
133
|
* - `step-start` {no, id, label, at}
|
|
110
134
|
* - `step-end` {no, status: 'done'|'failed', label, at} (a re-opened step writes `step-reopen` {no, at} first)
|
|
111
135
|
* - `step-label` {no, label, at} (the step reads `label` from now on, status and times untouched: the thinking row's "the model thought anyway" / "can't change it" / "not confirmed")
|
|
136
|
+
* - `human` {no, source: 'confirm'|'try-3'|'look', question, answer, line?, at}: one question the person was asked and what they answered (the answer is secret-masked
|
|
137
|
+
* before it is written; the row is written only when BOTH exist, so a question nobody answered leaves no row)
|
|
112
138
|
* - `call` {no, step, label, model, thinking, thinkingSupport, thinkingStatus?, costUsd (null stays null), unpricedRounds, at}: one METERED model call
|
|
113
139
|
* (`thinking` = the tick's mode: off | on; `thinkingSupport` = bare-agent's lookup for the model: true | false | 'unverified';
|
|
114
140
|
* `thinkingStatus` = bare-agent's own verdict for the call's run: applied | unsupported | ignored | unknown, present only when thinkingMode was sent)
|
package/types/facts.d.ts
CHANGED
|
@@ -23,6 +23,14 @@ export function factClaims(part: any, results: unknown): {
|
|
|
23
23
|
quote: string;
|
|
24
24
|
values?: Record<string, string>;
|
|
25
25
|
}[];
|
|
26
|
+
/**
|
|
27
|
+
* One amount of a money fact in the fact's OWN signed forms, never a hardcoded sign: `symbolFirst` puts the currency sign before the amount
|
|
28
|
+
* ("$144") when the fact has one, else the unit after it ("144 US dollars"); not `symbolFirst` (a rule's bound) prefers the unit.
|
|
29
|
+
* @param {any} f a money fact @param {string|number} n @param {boolean} symbolFirst @returns {string}
|
|
30
|
+
*/
|
|
31
|
+
export function moneyAs(f: any, n: string | number, symbolFirst: boolean): string;
|
|
32
|
+
/** @param {any} f a fact with a rule @returns {string} the rule in words, e.g. "at most 450 US dollars" */
|
|
33
|
+
export function ruleWords(f: any): string;
|
|
26
34
|
/**
|
|
27
35
|
* One fact as a plain row, written by code from the signed fields:
|
|
28
36
|
* `fact · price — money, at most 450 US dollars, after "Price", quoted from "Flights"`.
|
|
@@ -69,3 +77,10 @@ export const FACT_OPS: readonly string[];
|
|
|
69
77
|
export const MAX_FACTS: 10;
|
|
70
78
|
/** every field a part of class `fact` may carry (the shared ones are checked by rubricStepShapeReds) */
|
|
71
79
|
export const FACT_PART_FIELDS: readonly string[];
|
|
80
|
+
/** the limits bareguard 0.24 puts on a money fact's lists (ruling #65), enforced here first so the red is ours and plain */
|
|
81
|
+
export const MAX_CURRENCIES: 3;
|
|
82
|
+
export const MAX_UNITS: 10;
|
|
83
|
+
export const MAX_UNIT_CHARS: 100;
|
|
84
|
+
export function asList(v: unknown): string[];
|
|
85
|
+
export function moneyForms(f: any): string[];
|
|
86
|
+
export function boundOk(shape: string, v: unknown): boolean;
|
package/types/factwords.d.ts
CHANGED
|
@@ -9,16 +9,35 @@ export function countExact(source: string, words: string): number;
|
|
|
9
9
|
* @param {string} source @param {string} words @returns {number}
|
|
10
10
|
*/
|
|
11
11
|
export function countPhrase(source: string, words: string): number;
|
|
12
|
+
/**
|
|
13
|
+
* What the page-word map (src/pagemap.js) KEPT and DROPPED for one input: the sets the second proof reads. A look from the old search-and-read
|
|
14
|
+
* path has no `dropped` list, so it gives null and the label is proved against the code-made list as before.
|
|
15
|
+
* @param {{facts?: any[], dropped?: (import('./pagerules.js').Dropped & {source?: string})[]}|null|undefined} look @param {string} source
|
|
16
|
+
* @returns {{labels: Set<string>, units: Set<string>, currencies: Set<string>, words: Set<string>, dropped: Map<string, import('./pagerules.js').Dropped>}|null}
|
|
17
|
+
*/
|
|
18
|
+
export function keptSetOf(look: {
|
|
19
|
+
facts?: any[];
|
|
20
|
+
dropped?: (import("./pagerules.js").Dropped & {
|
|
21
|
+
source?: string;
|
|
22
|
+
})[];
|
|
23
|
+
} | null | undefined, source: string): {
|
|
24
|
+
labels: Set<string>;
|
|
25
|
+
units: Set<string>;
|
|
26
|
+
currencies: Set<string>;
|
|
27
|
+
words: Set<string>;
|
|
28
|
+
dropped: Map<string, import("./pagerules.js").Dropped>;
|
|
29
|
+
} | null;
|
|
12
30
|
/**
|
|
13
31
|
* The reds for ONE fact part against its frozen source text.
|
|
14
|
-
* @param {{part: any, text: string, line: number|string, scan?: import('./labelscan.js').LabelScan}} o
|
|
32
|
+
* @param {{part: any, text: string, line: number|string, scan?: import('./labelscan.js').LabelScan, kept?: ReturnType<typeof keptSetOf>}} o
|
|
15
33
|
* @returns {{code: string, detail: string}[]}
|
|
16
34
|
*/
|
|
17
|
-
export function checkFactWords({ part, text, line, scan }: {
|
|
35
|
+
export function checkFactWords({ part, text, line, scan, kept }: {
|
|
18
36
|
part: any;
|
|
19
37
|
text: string;
|
|
20
38
|
line: number | string;
|
|
21
39
|
scan?: import("./labelscan.js").LabelScan;
|
|
40
|
+
kept?: ReturnType<typeof keptSetOf>;
|
|
22
41
|
}): {
|
|
23
42
|
code: string;
|
|
24
43
|
detail: string;
|
|
@@ -27,9 +46,13 @@ export function checkFactWords({ part, text, line, scan }: {
|
|
|
27
46
|
* The reds for every fact part of a declaration. A fact part whose input text is not at hand is a red: a check whose words were never
|
|
28
47
|
* proved against the source is never signed.
|
|
29
48
|
* @param {any} declaration @param {Record<string, string>|null} texts label -> frozen text
|
|
49
|
+
* @param {{facts?: any[], dropped?: any[]}|null} [look] the page-word map's report: what it kept and dropped (null = no map, the code-made list is the proof)
|
|
30
50
|
* @returns {{code: string, path: string, detail: string}[]}
|
|
31
51
|
*/
|
|
32
|
-
export function checkDeclarationWords(declaration: any, texts: Record<string, string> | null
|
|
52
|
+
export function checkDeclarationWords(declaration: any, texts: Record<string, string> | null, look?: {
|
|
53
|
+
facts?: any[];
|
|
54
|
+
dropped?: any[];
|
|
55
|
+
} | null): {
|
|
33
56
|
code: string;
|
|
34
57
|
path: string;
|
|
35
58
|
detail: string;
|
package/types/inputlook.d.ts
CHANGED
|
@@ -148,6 +148,12 @@ export function lookPrompt({ jobLines, labels, lists }: {
|
|
|
148
148
|
labels: string[];
|
|
149
149
|
lists: Record<string, string>;
|
|
150
150
|
}): string;
|
|
151
|
+
/**
|
|
152
|
+
* A fact the page-word map kept (src/pagerules.js `KeptFact`), as the look report carries it: a phrase fact holds its alternative
|
|
153
|
+
* phrases; any other holds its labels (the first is the primary), and a money fact its units and currencies.
|
|
154
|
+
* @param {import('./pagerules.js').KeptFact} k @param {string} source @returns {LookFact}
|
|
155
|
+
*/
|
|
156
|
+
export function lookFactOf(k: import("./pagerules.js").KeptFact, source: string): LookFact;
|
|
151
157
|
/**
|
|
152
158
|
* Turn the AI's raw report into a VERIFIED one, by code, at $0. A fact is carried only when: its shape is a real shape, its source is
|
|
153
159
|
* a real input, and its label is ON THE LIST for that input and shape (an id is resolved to its exact words). Anything else is moved
|
|
@@ -207,6 +213,9 @@ export const LOOK_REPORT_TOOL: "report_look";
|
|
|
207
213
|
/** how many hits one search returns at most, and how long a snippet or a read line is */
|
|
208
214
|
export const LOOK_MAX_HITS: 40;
|
|
209
215
|
export { LABEL_SHAPES };
|
|
216
|
+
/**
|
|
217
|
+
* `words` / `labels` / `unit` / `currency`: what the page-word map kept (idea A core)
|
|
218
|
+
*/
|
|
210
219
|
export type LookFact = {
|
|
211
220
|
line: number;
|
|
212
221
|
name: string;
|
|
@@ -220,6 +229,11 @@ export type LookFact = {
|
|
|
220
229
|
rule?: any;
|
|
221
230
|
aiProposal?: boolean;
|
|
222
231
|
forRule?: number;
|
|
232
|
+
reading?: import("./pagerules.js").Reading;
|
|
233
|
+
words?: string[];
|
|
234
|
+
labels?: string[];
|
|
235
|
+
unit?: string[];
|
|
236
|
+
currency?: string[];
|
|
223
237
|
};
|
|
224
238
|
export type LookNotFound = {
|
|
225
239
|
line: number;
|
|
@@ -234,5 +248,6 @@ export type LookReport = {
|
|
|
234
248
|
text?: string;
|
|
235
249
|
}[];
|
|
236
250
|
notFound: LookNotFound[];
|
|
251
|
+
dropped?: import("./pagerules.js").Dropped[];
|
|
237
252
|
};
|
|
238
253
|
import { LABEL_SHAPES } from './labelscan.js';
|
package/types/kinds.d.ts
CHANGED
|
@@ -645,6 +645,11 @@ export type Ctx = {
|
|
|
645
645
|
timeoutMs?: number;
|
|
646
646
|
deadlineMs?: number;
|
|
647
647
|
};
|
|
648
|
+
onRubricEvidence?: (e: {
|
|
649
|
+
step: number;
|
|
650
|
+
evidence: any[];
|
|
651
|
+
evidenceTotal?: number;
|
|
652
|
+
}) => void;
|
|
648
653
|
onStage?: (row: {
|
|
649
654
|
stage: string | null;
|
|
650
655
|
kind: string | null;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** @param {Dropped} d @returns {string} the plain sentence for one drop */
|
|
2
|
+
export function dropSentence(d: Dropped): string;
|
|
3
|
+
/**
|
|
4
|
+
* One row per fact that lost something: the sentences (one per dropped word, then the fact's own), and whether the whole fact went.
|
|
5
|
+
* @param {Dropped[]|undefined|null} dropped
|
|
6
|
+
* @returns {{line: number, rule?: number, fact: string, full: boolean, sentences: string[]}[]}
|
|
7
|
+
*/
|
|
8
|
+
export function dropRows(dropped: Dropped[] | undefined | null): {
|
|
9
|
+
line: number;
|
|
10
|
+
rule?: number;
|
|
11
|
+
fact: string;
|
|
12
|
+
full: boolean;
|
|
13
|
+
sentences: string[];
|
|
14
|
+
}[];
|
|
15
|
+
/**
|
|
16
|
+
* A row as one Not-checked line, in the person's own words: `line N: "<the ~ rule as written, or the fact's name>" — <sentences>`.
|
|
17
|
+
* @param {{line: number, rule?: number, fact: string, sentences: string[]}} row @param {any[]|null|undefined} jobLines @param {(l: any) => string[]} rulesOf
|
|
18
|
+
* @returns {string}
|
|
19
|
+
*/
|
|
20
|
+
export function dropLine(row: {
|
|
21
|
+
line: number;
|
|
22
|
+
rule?: number;
|
|
23
|
+
fact: string;
|
|
24
|
+
sentences: string[];
|
|
25
|
+
}, jobLines: any[] | null | undefined, rulesOf: (l: any) => string[]): string;
|
|
26
|
+
export type Dropped = import("./pagerules.js").Dropped;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the AI is told, for ONE page input. Ported from the POC prompt: the job, the `~` rules, "a result is one item", the answer form
|
|
3
|
+
* and the shape meanings.
|
|
4
|
+
* @param {{jobLines: {n: number, text: string, rule?: string, rules?: string[]}[], label: string, text: string}} o
|
|
5
|
+
* @returns {string}
|
|
6
|
+
*/
|
|
7
|
+
export function mapPrompt({ jobLines, label, text }: {
|
|
8
|
+
jobLines: {
|
|
9
|
+
n: number;
|
|
10
|
+
text: string;
|
|
11
|
+
rule?: string;
|
|
12
|
+
rules?: string[];
|
|
13
|
+
}[];
|
|
14
|
+
label: string;
|
|
15
|
+
text: string;
|
|
16
|
+
}): string;
|
|
17
|
+
/**
|
|
18
|
+
* Read the AI's answer: ONE JSON object of the answer form, and nothing else. No repair (hamr's ruling): text that is not JSON, JSON of
|
|
19
|
+
* another form, or a fact whose shape or lists are not of the form is a malformed answer.
|
|
20
|
+
* @param {unknown} text @returns {{ok: true, mapping: import('./pagerules.js').PageMap}|{ok: false}}
|
|
21
|
+
*/
|
|
22
|
+
export function parseMapAnswer(text: unknown): {
|
|
23
|
+
ok: true;
|
|
24
|
+
mapping: import("./pagerules.js").PageMap;
|
|
25
|
+
} | {
|
|
26
|
+
ok: false;
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Run the map: one call per page input.
|
|
30
|
+
* @param {{texts: Record<string, string>, inputs: {n: number, label: string}[], jobLines: {n: number, text: string, rule?: string, rules?: string[]}[],
|
|
31
|
+
* provider?: any, maxTokens?: number, ceilingUsd?: number|null, callTimeoutMs?: number,
|
|
32
|
+
* onCall?: (call: {label: string, costUsd: number|null, unpricedRounds: number, thinkingStatus?: string, raw?: string}) => void,
|
|
33
|
+
* createLoop?: (o: {system: string, onLlmResult: any, provider: any, rates?: {in: number, out: number}}) => any,
|
|
34
|
+
* rates?: {in: number, out: number}|null, callOptions?: Record<string, any>, sleep?: (ms: number) => Promise<void>, prove?: Function}} o
|
|
35
|
+
* @returns {Promise<{state: 'PRESENT'|'ABSENT', facts: any, reason: string|null, cause: string|null, meta: any, raw: string,
|
|
36
|
+
* raws: ReturnType<typeof scrubRaw>[], calls: {label: string, costUsd: number|null, unpricedRounds: number}[],
|
|
37
|
+
* budgetStop: 'cap-halt'|'pricing-red'|null}>}
|
|
38
|
+
*/
|
|
39
|
+
export function runPageMap({ texts, inputs, jobLines, provider, maxTokens, ceilingUsd, callTimeoutMs, onCall, createLoop, rates, callOptions, sleep, }: {
|
|
40
|
+
texts: Record<string, string>;
|
|
41
|
+
inputs: {
|
|
42
|
+
n: number;
|
|
43
|
+
label: string;
|
|
44
|
+
}[];
|
|
45
|
+
jobLines: {
|
|
46
|
+
n: number;
|
|
47
|
+
text: string;
|
|
48
|
+
rule?: string;
|
|
49
|
+
rules?: string[];
|
|
50
|
+
}[];
|
|
51
|
+
provider?: any;
|
|
52
|
+
maxTokens?: number;
|
|
53
|
+
ceilingUsd?: number | null;
|
|
54
|
+
callTimeoutMs?: number;
|
|
55
|
+
onCall?: (call: {
|
|
56
|
+
label: string;
|
|
57
|
+
costUsd: number | null;
|
|
58
|
+
unpricedRounds: number;
|
|
59
|
+
thinkingStatus?: string;
|
|
60
|
+
raw?: string;
|
|
61
|
+
}) => void;
|
|
62
|
+
createLoop?: (o: {
|
|
63
|
+
system: string;
|
|
64
|
+
onLlmResult: any;
|
|
65
|
+
provider: any;
|
|
66
|
+
rates?: {
|
|
67
|
+
in: number;
|
|
68
|
+
out: number;
|
|
69
|
+
};
|
|
70
|
+
}) => any;
|
|
71
|
+
rates?: {
|
|
72
|
+
in: number;
|
|
73
|
+
out: number;
|
|
74
|
+
} | null;
|
|
75
|
+
callOptions?: Record<string, any>;
|
|
76
|
+
sleep?: (ms: number) => Promise<void>;
|
|
77
|
+
prove?: Function;
|
|
78
|
+
}): Promise<{
|
|
79
|
+
state: "PRESENT" | "ABSENT";
|
|
80
|
+
facts: any;
|
|
81
|
+
reason: string | null;
|
|
82
|
+
cause: string | null;
|
|
83
|
+
meta: any;
|
|
84
|
+
raw: string;
|
|
85
|
+
raws: ReturnType<typeof scrubRaw>[];
|
|
86
|
+
calls: {
|
|
87
|
+
label: string;
|
|
88
|
+
costUsd: number | null;
|
|
89
|
+
unpricedRounds: number;
|
|
90
|
+
}[];
|
|
91
|
+
budgetStop: "cap-halt" | "pricing-red" | null;
|
|
92
|
+
}>;
|
|
93
|
+
/** @param {unknown} q a recorded question @returns {string|null} the reading a reading ask proposed, or null when it was another kind of question */
|
|
94
|
+
export function readingOfQuestion(q: unknown): string | null;
|
|
95
|
+
/**
|
|
96
|
+
* PRD v1.107 Part 5b ("the look reads, code asks"): the early asks CODE forces before any paid drafting, from the look's own result. Every `~` rule is
|
|
97
|
+
* one of three kinds:
|
|
98
|
+
* - PAGE: a kept page word carries it (a kept fact with `forRule` and no `reading`): no ask.
|
|
99
|
+
* - READING: a kept fact carries it with a `reading` (a limit the page cannot hold, e.g. "not a red-eye" -> departure time between 06:00 and 21:00).
|
|
100
|
+
* Asked only when a bound of the reading is NOT in the words the person wrote (the same test as `rubric-fact-unmarked`, `boundInWords`); a
|
|
101
|
+
* bound they wrote themselves is theirs and nothing is asked. `agree` writes the reading as a `~` rule in plain words (the answer text is
|
|
102
|
+
* `reading`), so the drafter is told it and the fact signs plain.
|
|
103
|
+
* - CAN'T CHECK: no kept fact carries it (PRD v1.106 Part 5 Q3 T2). `drop it` leaves it Not checked.
|
|
104
|
+
* One ask per rule text on a line; readings first, then can't-check asks, each in line order. The caller applies the machine's cap and the answer gate.
|
|
105
|
+
* @param {{facts?: {line: number, forRule?: number, name?: string, shape?: string, unit?: string[], currency?: string[], reading?: import('./pagerules.js').Reading}[]}|null|undefined} look
|
|
106
|
+
* @param {{n: number, text?: string, rule?: string, rules?: string[]}[]|null|undefined} jobLines
|
|
107
|
+
* @returns {LookAsk[]}
|
|
108
|
+
*/
|
|
109
|
+
export function askableFromLook(look: {
|
|
110
|
+
facts?: {
|
|
111
|
+
line: number;
|
|
112
|
+
forRule?: number;
|
|
113
|
+
name?: string;
|
|
114
|
+
shape?: string;
|
|
115
|
+
unit?: string[];
|
|
116
|
+
currency?: string[];
|
|
117
|
+
reading?: import("./pagerules.js").Reading;
|
|
118
|
+
}[];
|
|
119
|
+
} | null | undefined, jobLines: {
|
|
120
|
+
n: number;
|
|
121
|
+
text?: string;
|
|
122
|
+
rule?: string;
|
|
123
|
+
rules?: string[];
|
|
124
|
+
}[] | null | undefined): LookAsk[];
|
|
125
|
+
/**
|
|
126
|
+
* PRD v1.107 Part 5b: more asks than the machine's cap means the job needs a rewrite, not a questionnaire. The code-owned stop words list EVERY ask and
|
|
127
|
+
* its reading as the suggestion (no extra paid call). A secret in a rule is masked.
|
|
128
|
+
* @param {LookAsk[]} asks @returns {string}
|
|
129
|
+
*/
|
|
130
|
+
export function tooManyAsksText(asks: LookAsk[]): string;
|
|
131
|
+
/** the label of the one paid call, as the drafting book and the progress line see it */
|
|
132
|
+
export const MAP_CALL_LABEL: "page-map";
|
|
133
|
+
/** the shapes the map may name; a `place` is read by code as a phrase */
|
|
134
|
+
export const MAP_SHAPES: readonly string[];
|
|
135
|
+
export const MAP_SYSTEM: "You map a person's job to the exact words of ONE saved web page. You never grade and never invent words: every string you return must be copied from the page text, character for character.";
|
|
136
|
+
/** the plain-word stop when the answer was not readable twice (no Resume: a draft is not a run) */
|
|
137
|
+
export const MAP_UNREADABLE: "The AI's answer about the page was not readable twice. Nothing was signed.";
|
|
138
|
+
/** the answer that drops a `~` rule the page cannot check: the person types it (any case, a closing full stop allowed) */
|
|
139
|
+
export const DROP_IT: "drop it";
|
|
140
|
+
export function isDropIt(text: unknown): boolean;
|
|
141
|
+
export function isAgree(text: unknown): boolean;
|
|
142
|
+
/**
|
|
143
|
+
* `reading` = the plain words an `agree` writes as a `~` rule (a reading ask only)
|
|
144
|
+
*/
|
|
145
|
+
export type LookAsk = {
|
|
146
|
+
line: number;
|
|
147
|
+
rule: number;
|
|
148
|
+
source: "look";
|
|
149
|
+
question: string;
|
|
150
|
+
ask: "reading" | "cant-check";
|
|
151
|
+
ruleText: string;
|
|
152
|
+
reading?: string;
|
|
153
|
+
};
|
|
154
|
+
import { scrubRaw } from './text.js';
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which job line, and which `~` rule under it, a map fact carries out. The map writes `from` as "line N", "line N rule M", "rule M" or
|
|
3
|
+
* "job line"; anything else is the first job line.
|
|
4
|
+
* @param {unknown} from @param {{n: number, text?: string, rule?: string, rules?: string[]}[]} jobLines
|
|
5
|
+
* @returns {{line: number, rule?: number}}
|
|
6
|
+
*/
|
|
7
|
+
export function tieOf(from: unknown, jobLines: {
|
|
8
|
+
n: number;
|
|
9
|
+
text?: string;
|
|
10
|
+
rule?: string;
|
|
11
|
+
rules?: string[];
|
|
12
|
+
}[]): {
|
|
13
|
+
line: number;
|
|
14
|
+
rule?: number;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Is this a legal `reading` for a fact of this shape? Only a time or money fact carries one, with the op set and the bound types of a signed
|
|
18
|
+
* fact rule (src/facts.js): no other key, no missing bound. A malformed one makes the whole map answer malformed (no repair).
|
|
19
|
+
* @param {unknown} shape @param {unknown} r @returns {boolean}
|
|
20
|
+
*/
|
|
21
|
+
export function validReading(shape: unknown, r: unknown): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Apply the rules to the AI's map over one saved page. Returns the kept facts and, for everything a rule removed, one `dropped` entry.
|
|
24
|
+
* The order of the rules is the POC's (apply-v3.mjs): found-on-page, then the rules that read the page. A place is read as a phrase.
|
|
25
|
+
* @param {string} text the frozen page text @param {PageMap} mapping @param {{n: number, text?: string, rule?: string, rules?: string[]}[]} jobLines
|
|
26
|
+
* @returns {{facts: KeptFact[], dropped: Dropped[]}}
|
|
27
|
+
*/
|
|
28
|
+
export function applyPageRules(text: string, mapping: PageMap, jobLines: {
|
|
29
|
+
n: number;
|
|
30
|
+
text?: string;
|
|
31
|
+
rule?: string;
|
|
32
|
+
rules?: string[];
|
|
33
|
+
}[]): {
|
|
34
|
+
facts: KeptFact[];
|
|
35
|
+
dropped: Dropped[];
|
|
36
|
+
};
|
|
37
|
+
export function linesOf(text: string): string[];
|
|
38
|
+
/**
|
|
39
|
+
* what a `~` rule means as a limit (PRD v1.107 Part 5b): the same shape as a signed fact rule
|
|
40
|
+
*/
|
|
41
|
+
export type Reading = {
|
|
42
|
+
op: string;
|
|
43
|
+
value?: string | number;
|
|
44
|
+
lo?: string | number;
|
|
45
|
+
hi?: string | number;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* the AI's map, one fact
|
|
49
|
+
*/
|
|
50
|
+
export type MapFact = {
|
|
51
|
+
name: string;
|
|
52
|
+
from?: string;
|
|
53
|
+
shape: string;
|
|
54
|
+
words?: string[];
|
|
55
|
+
currency?: string[];
|
|
56
|
+
unit?: string[];
|
|
57
|
+
reading?: Reading;
|
|
58
|
+
};
|
|
59
|
+
export type PageMap = {
|
|
60
|
+
facts: MapFact[];
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* `words` = what the page proves: the labels of a money/number/time fact, or the alternative phrases of a phrase fact (a place is a phrase)
|
|
64
|
+
*/
|
|
65
|
+
export type KeptFact = {
|
|
66
|
+
line: number;
|
|
67
|
+
name: string;
|
|
68
|
+
shape: string;
|
|
69
|
+
from: string;
|
|
70
|
+
words: string[];
|
|
71
|
+
unit?: string[];
|
|
72
|
+
currency?: string[];
|
|
73
|
+
forRule?: number;
|
|
74
|
+
reading?: Reading;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* `other` = what the drop is compared to: the first label (R1), the primary form (R1L), the fact it would have repeated (S1)
|
|
78
|
+
*/
|
|
79
|
+
export type Dropped = {
|
|
80
|
+
line: number;
|
|
81
|
+
rule?: number;
|
|
82
|
+
fact: string;
|
|
83
|
+
word?: string;
|
|
84
|
+
reason: string;
|
|
85
|
+
other?: string;
|
|
86
|
+
};
|
|
@@ -33,6 +33,19 @@ export function checkHumanGuard(req: import("node:http").IncomingMessage, { toke
|
|
|
33
33
|
ok: false;
|
|
34
34
|
reason: string;
|
|
35
35
|
};
|
|
36
|
+
/**
|
|
37
|
+
* The one-at-a-time authoring session store (build spec: "one authoring
|
|
38
|
+
* session at a time — a second Start is refused while one is live"). A
|
|
39
|
+
* session is "live" from creation until its phase settles into a terminal
|
|
40
|
+
* one; a terminal session is kept (so its chat/hash stay readable) but no
|
|
41
|
+
* longer counts against the one-at-a-time rule.
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* PRD v1.106 Part 5 Q2: the "fetching the page..." step is done once the run's own refetch has written `refrozenAt` (source.json, written last).
|
|
45
|
+
* Settled when the state is read, so nothing polls and the step never stays running after the fetch.
|
|
46
|
+
* @param {any} state
|
|
47
|
+
*/
|
|
48
|
+
export function settleFetchingStep(state: any): void;
|
|
36
49
|
/**
|
|
37
50
|
* Builds this file's own request handler, holding its session store in a
|
|
38
51
|
* closure (one per `createPanelServer` call, exactly like `handleRequest`'s
|
|
@@ -79,7 +92,6 @@ export function createAuthorRoutes(opts: {
|
|
|
79
92
|
workflowKey: string;
|
|
80
93
|
} | null, inputs: import("../jobblock.js").JobInput[], o?: {
|
|
81
94
|
headless?: boolean;
|
|
82
|
-
filesJob?: boolean;
|
|
83
95
|
}) => Promise<{
|
|
84
96
|
ok: true;
|
|
85
97
|
session: ReturnType<typeof createSession>;
|
|
@@ -94,19 +106,6 @@ export function createAuthorRoutes(opts: {
|
|
|
94
106
|
/** a headless session the starter has removed from disk leaves its map too @param {string} id */
|
|
95
107
|
forgetHeadless: (id: string) => void;
|
|
96
108
|
};
|
|
97
|
-
/**
|
|
98
|
-
* The panel's OWN 2-decimal money render for a chat line — hamr's ruling
|
|
99
|
-
* 2026-09-28 (2nd addendum, panel money 2-decimals): a positive amount below
|
|
100
|
-
* a cent reads `<$0.01`, never `$0.00` (a real cost must never read as
|
|
101
|
-
* free). This is the server-side (Node, chat-text) sibling of
|
|
102
|
-
* `src/panel/index.html`'s own inline `panelMoney` — the two can't share
|
|
103
|
-
* code (one runs in the browser as inlined script, the other in Node), the
|
|
104
|
-
* same duplication `src/replay.js`'s `money()`/`index.html`'s `money()`
|
|
105
|
-
* already carry, so both apply the identical rule rather than drift.
|
|
106
|
-
* @param {number} n a non-negative dollar amount
|
|
107
|
-
* @returns {string}
|
|
108
|
-
*/
|
|
109
|
-
export function panelMoney2(n: number): string;
|
|
110
109
|
/**
|
|
111
110
|
* THE ONLY function in this file (or anywhere in the panel) that spawns a
|
|
112
111
|
* run. Refuses unless the session is `prepared` AND the hash the request
|
|
@@ -136,5 +135,9 @@ export function signRun(session: ReturnType<typeof createSession>, claimedHash:
|
|
|
136
135
|
export const OLD_JOB_REUSE_WORDS: "This run was made by an older bareloop. Its saved job doesn't pass today's checks, so it can't be reused. Start a new job instead.";
|
|
137
136
|
export const OLD_JOB_RESUME_WORDS: "This run was made by an older bareloop. Its saved job doesn't pass today's checks, so it can't be resumed. Use Reuse workflow on a newer run, or start a new job.";
|
|
138
137
|
export const OLD_JOB_ACCEPT_WORDS: "This run was made by an older bareloop. Its saved job doesn't pass today's checks, so it can't be accepted. Use Reuse workflow on a newer run, or start a new job.";
|
|
138
|
+
export const OLD_JOB_RERUN_WORDS: "This run was made by an older bareloop. Its saved job doesn't pass today's checks, so it can't be rerun. Use Reuse workflow on a newer run, or start a new job.";
|
|
139
|
+
export const OLD_JOB_PAUSE_WORDS: "This run was made by an older bareloop. Its saved job doesn't pass today's checks, so it can't be paused from here. Use Reuse workflow on a newer run, or start a new job.";
|
|
140
|
+
export { panelMoney2 };
|
|
139
141
|
import { spawn as realSpawn } from 'node:child_process';
|
|
140
142
|
import { createSession } from './authorsession.js';
|
|
143
|
+
import { panelMoney2 } from '../panelmoney.js';
|
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
* recorded...`, `CHECKPOINT EXPIRED — ...`); anything else (validator reds, exit statuses, stack traces, argv) becomes ONE fixed
|
|
5
5
|
* sentence naming the log. The one owner for the Resume and Accept routes.
|
|
6
6
|
* @param {string} tail the log tail
|
|
7
|
-
* @param {'resume'|'accept'} kind
|
|
7
|
+
* @param {'resume'|'accept'|'rerun'|'pause'} kind
|
|
8
8
|
* @param {string} logFile
|
|
9
9
|
* @param {(stage: string) => string|null} [questionOf] stage name to the panel's plain question (`null` = none)
|
|
10
10
|
* @returns {string}
|
|
11
11
|
*/
|
|
12
|
-
export function engineRefusalWords(tail: string, kind: "resume" | "accept", logFile: string, questionOf?: (stage: string) => string | null): string;
|
|
12
|
+
export function engineRefusalWords(tail: string, kind: "resume" | "accept" | "rerun" | "pause", logFile: string, questionOf?: (stage: string) => string | null): string;
|
|
13
13
|
/**
|
|
14
14
|
* The run routes' handler. `getResumeContext(runid)` is the server's own reader (the same
|
|
15
15
|
* `resumePlanFor` the Ended block uses, so the page never offers what this refuses):
|