bareloop 0.42.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 +88 -0
- package/bareloop.context.md +103 -41
- package/package.json +2 -2
- package/src/authorflow.js +26 -11
- package/src/authoring.js +1 -1
- package/src/authorjob.js +33 -15
- package/src/authorreadout.js +7 -6
- package/src/declaredclose.js +6 -3
- 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/interviewrun.js +0 -1
- package/src/job.js +39 -12
- 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 +138 -60
- package/src/panel/authorsession.js +88 -32
- package/src/panel/index.html +1251 -522
- package/src/panel/jobplan.js +4 -2
- package/src/panel/runroutes.js +188 -6
- package/src/panel/scheduler.js +156 -0
- package/src/panel/schedules.js +667 -0
- package/src/panel/schedulestart.js +243 -0
- package/src/panel/server.js +1234 -68
- package/src/panel/status.js +33 -0
- package/src/panelmoney.js +29 -0
- package/src/planrun.js +92 -11
- package/src/promptregisters.js +4 -0
- package/src/providerrows.js +3 -3
- package/src/replay.js +118 -7
- package/src/reviewdoor.js +37 -0
- package/src/rubricstep.js +123 -11
- package/src/runlist.js +37 -1
- package/src/schedulewords.js +299 -0
- package/src/source.js +18 -0
- package/src/thinking.js +63 -2
- package/src/trigger.js +48 -0
- package/src/triggerclock.js +127 -0
- package/src/triggerfiles.js +215 -0
- package/src/triggerledger.js +79 -0
- package/src/userrun.js +34 -21
- package/types/authorflow.d.ts +42 -6
- package/types/authorjob.d.ts +10 -2
- package/types/declaredclose.d.ts +3 -1
- 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/job.d.ts +8 -1
- 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 +50 -14
- package/types/panel/authorsession.d.ts +37 -12
- package/types/panel/runroutes.d.ts +32 -1
- package/types/panel/scheduler.d.ts +17 -0
- package/types/panel/schedules.d.ts +412 -0
- package/types/panel/schedulestart.d.ts +106 -0
- package/types/panel/server.d.ts +297 -15
- package/types/panel/status.d.ts +51 -0
- package/types/panelmoney.d.ts +5 -0
- package/types/planrun.d.ts +2 -0
- package/types/providerrows.d.ts +2 -2
- package/types/replay.d.ts +21 -1
- package/types/reviewdoor.d.ts +27 -0
- package/types/rubricstep.d.ts +57 -1
- package/types/runlist.d.ts +24 -1
- package/types/schedulewords.d.ts +137 -0
- package/types/source.d.ts +11 -0
- package/types/thinking.d.ts +39 -0
- package/types/trigger.d.ts +37 -0
- package/types/triggerclock.d.ts +52 -0
- package/types/triggerfiles.d.ts +93 -0
- package/types/triggerledger.d.ts +35 -0
- package/types/userrun.d.ts +4 -0
package/types/rubricstep.d.ts
CHANGED
|
@@ -35,6 +35,13 @@ export function rubricGoal({ jobLines, files, confirmedGoal, closeDecl }: {
|
|
|
35
35
|
confirmedGoal?: string | null;
|
|
36
36
|
closeDecl?: any;
|
|
37
37
|
}): string;
|
|
38
|
+
/**
|
|
39
|
+
* The sentence the person confirmed, out of a goal text: for a rubric brief the rest of the `CONFIRMED_GOAL_PREFIX` line,
|
|
40
|
+
* or null when the brief has none; any other goal (a code job's) comes back unchanged.
|
|
41
|
+
* @param {string} goal
|
|
42
|
+
* @returns {string|null}
|
|
43
|
+
*/
|
|
44
|
+
export function confirmedGoalOf(goal: string): string | null;
|
|
38
45
|
/**
|
|
39
46
|
* The SHAPE of a `rubric-step` stage's parameters — what a part may carry — and nothing about which class is allowed in
|
|
40
47
|
* this build (that is `checkRubricParts`, which also sees the whole job). Pure, never throws.
|
|
@@ -58,6 +65,28 @@ export function buildStepSpec(params: {
|
|
|
58
65
|
step: number;
|
|
59
66
|
parts: any[];
|
|
60
67
|
}, inputShas: Record<string, string>): Record<string, any>;
|
|
68
|
+
/**
|
|
69
|
+
* The files one named check READS, tree-relative: a `rubric-step` stage's own step file (`output/steps/N.json`). Any other kind reads
|
|
70
|
+
* none that a try's output can be told by, so `[]`. From the signed declaration, never guessed.
|
|
71
|
+
* @param {any} closeDecl @param {string|null|undefined} checkName
|
|
72
|
+
* @returns {string[]}
|
|
73
|
+
*/
|
|
74
|
+
export function judgedFilesOf(closeDecl: any, checkName: string | null | undefined): string[];
|
|
75
|
+
/**
|
|
76
|
+
* PRD v1.106 Part 5: what each file a try's `check-passes` checks read looked like WHEN it was judged: `{path, bytes, sha256}`. The step
|
|
77
|
+
* file is overwritten by the next try, so the spine's `output-judged` record is the only trace; the content itself is never written (hard
|
|
78
|
+
* line). A missing, non-regular or over-size file is skipped — nothing was judged there.
|
|
79
|
+
* @param {any} closeDecl @param {string} workdir @param {Array<{type?: string, name?: string}>} exits a step's declared exits
|
|
80
|
+
* @returns {Promise<Array<{path: string, bytes: number, sha256: string}>>}
|
|
81
|
+
*/
|
|
82
|
+
export function outputJudgedRecords(closeDecl: any, workdir: string, exits: Array<{
|
|
83
|
+
type?: string;
|
|
84
|
+
name?: string;
|
|
85
|
+
}>): Promise<Array<{
|
|
86
|
+
path: string;
|
|
87
|
+
bytes: number;
|
|
88
|
+
sha256: string;
|
|
89
|
+
}>>;
|
|
61
90
|
/**
|
|
62
91
|
* The step file's bytes as the close reads them: the parsed JSON object, or WHY there is none. A file cut off mid-write
|
|
63
92
|
* parses to nothing (reason `not-json`); text cut off INSIDE an otherwise valid JSON object cannot be told from a short
|
|
@@ -101,7 +130,9 @@ export function plainStepGap(step: number, why: string, g: any, params?: any): s
|
|
|
101
130
|
* `inputs` maps each cited label to its frozen TEXT; its sha256 is taken here from that text, and bareguard compares it to
|
|
102
131
|
* the manifest's recorded sha via `inputShas`.
|
|
103
132
|
* @param {Record<string, string>} inputShas the manifest's recorded sha256 per cited label
|
|
104
|
-
* @returns {Promise<{verdict: 'green'|'red'|'stopped', gapLines: string[], fault: string|null, detail: Record<string, any
|
|
133
|
+
* @returns {Promise<{verdict: 'green'|'red'|'stopped', gapLines: string[], fault: string|null, detail: Record<string, any>,
|
|
134
|
+
* evidence?: any[], evidenceTotal?: number}>} `evidence`/`evidenceTotal` are bareguard's `full.evidence` (what each `cited` check read), carried out
|
|
135
|
+
* for the report-only `rubric-evidence` spine record; no verdict, gap or count above is derived from them
|
|
105
136
|
*/
|
|
106
137
|
export function gradeStep({ params, bytes, outputBytes, inputs, factQuotes, factMissing }: {
|
|
107
138
|
params: {
|
|
@@ -118,6 +149,8 @@ export function gradeStep({ params, bytes, outputBytes, inputs, factQuotes, fact
|
|
|
118
149
|
gapLines: string[];
|
|
119
150
|
fault: string | null;
|
|
120
151
|
detail: Record<string, any>;
|
|
152
|
+
evidence?: any[];
|
|
153
|
+
evidenceTotal?: number;
|
|
121
154
|
}>;
|
|
122
155
|
/**
|
|
123
156
|
* The labels of a job's numbered inputs, or null when it carries none (a caller that has no inputs in hand skips the label rule).
|
|
@@ -178,6 +211,17 @@ export function settlePersonsWords(declaration: any, jobLines: any[] | null | un
|
|
|
178
211
|
* @param {any} declaration @returns {any}
|
|
179
212
|
*/
|
|
180
213
|
export function withFactBindings(declaration: any): any;
|
|
214
|
+
/**
|
|
215
|
+
* NO SILENT DROP (idea A core, spec 4.4): code writes the Not checked rows for what the page rules removed, before the declaration is validated.
|
|
216
|
+
* - a dropped FACT that carries a `~` rule no part carries and no `refused` entry names -> `closeDecl.refused` gets {line, rule, reason}
|
|
217
|
+
* (shown under that line in the person's own rule words by {@link ruleNotChecked});
|
|
218
|
+
* - any other drop (a fact from the job line itself, a rule another fact carries, a word dropped from a fact that is still checked, so a
|
|
219
|
+
* narrower check is still said) -> one line in `closeDecl.notes`, shown as Not checked (the AI's own reading).
|
|
220
|
+
* Never a line-level `refused` entry without `rule` (that would silence every other rule red on the line). A rule the drafter already listed
|
|
221
|
+
* itself is never listed twice, and running this twice adds nothing. Pure; the input is untouched.
|
|
222
|
+
* @param {any} declaration @param {import('./pagerules.js').Dropped[]|null|undefined} dropped @param {any[]|null|undefined} jobLines @returns {any}
|
|
223
|
+
*/
|
|
224
|
+
export function withDropNotes(declaration: any, dropped: import("./pagerules.js").Dropped[] | null | undefined, jobLines: any[] | null | undefined): any;
|
|
181
225
|
/**
|
|
182
226
|
* The ~ rules the drafter listed under Not checked (`refused` entries that name a `rule`), each as one line in the person's own
|
|
183
227
|
* words: `line N: "<the rule as written>" — <the drafter's reason>` (PART 1b, RF6 / RF16).
|
|
@@ -190,6 +234,11 @@ export function ruleNotChecked(closeDecl: any, jobLines: any[] | null | undefine
|
|
|
190
234
|
* @param {any} closeDecl @returns {string[]}
|
|
191
235
|
*/
|
|
192
236
|
export function proseNotChecked(closeDecl: any): string[];
|
|
237
|
+
/** the same items as {@link proseNotChecked} with the job line each belongs to (the stage's own `step`) @param {any} closeDecl @returns {{line: number, text: string}[]} */
|
|
238
|
+
export function proseNotCheckedItems(closeDecl: any): {
|
|
239
|
+
line: number;
|
|
240
|
+
text: string;
|
|
241
|
+
}[];
|
|
193
242
|
/**
|
|
194
243
|
* One countable part as a plain sentence, written by code from the part's signed fields (never from the model's words), so the
|
|
195
244
|
* plan card and the close are one thing seen twice.
|
|
@@ -269,6 +318,11 @@ export const STEP_DIR: "output/steps";
|
|
|
269
318
|
export function stepFileRel(n: number): string;
|
|
270
319
|
/** the largest step file the close reads: a bigger one is a stop, never silently truncated (bareguard's own source cap) */
|
|
271
320
|
export const STEP_MAX_BYTES: number;
|
|
321
|
+
/**
|
|
322
|
+
* What a rubric job's goal text is: the worker brief `rubricGoal` builds. The Job tab's "AI's summary" is only the one
|
|
323
|
+
* sentence the person confirmed, never this brief, so the first line and the confirmed-sentence prefix have ONE spelling.
|
|
324
|
+
*/
|
|
325
|
+
export const RUBRIC_GOAL_HEAD: "Do the job below from the input files, then write one JSON file per numbered line.";
|
|
272
326
|
/** the closed set of classes a part is sorted into; `none` = "I could not sort this one" (a red, in plain words, never a guess) */
|
|
273
327
|
export const PART_CLASSES: readonly string[];
|
|
274
328
|
/**
|
|
@@ -279,6 +333,8 @@ export const PART_CLASSES: readonly string[];
|
|
|
279
333
|
*/
|
|
280
334
|
export const COUNT_CHECKS: Readonly<Record<string, readonly string[]>>;
|
|
281
335
|
export function sha256Of(b: string | Buffer): string;
|
|
336
|
+
export function boundInWords(b: unknown, said: string): boolean;
|
|
337
|
+
export function wordsSaidOn(jl: any): string;
|
|
282
338
|
export type ShapeRed = {
|
|
283
339
|
code: string;
|
|
284
340
|
path: string;
|
package/types/runlist.d.ts
CHANGED
|
@@ -48,7 +48,8 @@ export function appendRun(row: RunRow, opts?: {
|
|
|
48
48
|
reason?: "duplicate-runid";
|
|
49
49
|
};
|
|
50
50
|
/**
|
|
51
|
-
* @typedef {{ runid: string, type: 'settled'|'released', by: string, at: string, reason?: string, spentUsd?: number, spendComplete?: boolean, leg?: number }} RunEvent
|
|
51
|
+
* @typedef {{ runid: string, type: 'settled'|'released', by: string, at: string, reason?: string, words?: string, spentUsd?: number, spendComplete?: boolean, leg?: number }} RunEvent
|
|
52
|
+
* `words` (2026-10-19): on a `settled` with `reason: 'refused before start'`, the plain refusal the panel shows for that run (it has no spine).
|
|
52
53
|
* `leg` (P5-R): which leg of the run the write-back is about; absent = leg 1 (every entry written before P5-R).
|
|
53
54
|
* A resumed run is ONE row, so `settled`/`released` are per leg: a later leg's `released` gives back THAT leg's
|
|
54
55
|
* claim and never removes the run.
|
|
@@ -67,6 +68,26 @@ export function appendRun(row: RunRow, opts?: {
|
|
|
67
68
|
export function appendRunEvent(event: RunEvent, opts?: {
|
|
68
69
|
home?: string;
|
|
69
70
|
}): void;
|
|
71
|
+
/**
|
|
72
|
+
* RULED 2026-10-15 ("Remove from Needs you"): the person took a stopped run's card out of the Needs-you list. ONE row
|
|
73
|
+
* `{runid, type:'needs-removed', at}` appended beside the run rows; it is not a run, a claim or an event ({@link readRunList}
|
|
74
|
+
* ignores it, so the monthly limit, the run counter and the scheduler never see it). Nothing is rewritten.
|
|
75
|
+
* @param {string} runid
|
|
76
|
+
* @param {{ home?: string, now?: () => number }} [opts]
|
|
77
|
+
* @returns {string} the `at` written
|
|
78
|
+
*/
|
|
79
|
+
export function appendNeedsRemoved(runid: string, opts?: {
|
|
80
|
+
home?: string;
|
|
81
|
+
now?: () => number;
|
|
82
|
+
}): string;
|
|
83
|
+
/**
|
|
84
|
+
* The newest `needs-removed` time (ms) per run id. An absent file is an empty map; a row with no readable time is not a removal.
|
|
85
|
+
* @param {{ home?: string }} [opts]
|
|
86
|
+
* @returns {Map<string, number>}
|
|
87
|
+
*/
|
|
88
|
+
export function readNeedsRemovals(opts?: {
|
|
89
|
+
home?: string;
|
|
90
|
+
}): Map<string, number>;
|
|
70
91
|
/**
|
|
71
92
|
* @typedef {{ type: 'leg-start', runid: string, leg: number, pid?: number, capUsd?: number, at: string }} LegStart
|
|
72
93
|
* A resumed run's NEW claim (P5-R, hamr 2026-10-02: one run, one id, one row): appended beside the run's row
|
|
@@ -206,6 +227,7 @@ export type RunRow = {
|
|
|
206
227
|
leg?: number;
|
|
207
228
|
};
|
|
208
229
|
/**
|
|
230
|
+
* `words` (2026-10-19): on a `settled` with `reason: 'refused before start'`, the plain refusal the panel shows for that run (it has no spine).
|
|
209
231
|
* `leg` (P5-R): which leg of the run the write-back is about; absent = leg 1 (every entry written before P5-R).
|
|
210
232
|
* A resumed run is ONE row, so `settled`/`released` are per leg: a later leg's `released` gives back THAT leg's
|
|
211
233
|
* claim and never removes the run.
|
|
@@ -221,6 +243,7 @@ export type RunEvent = {
|
|
|
221
243
|
by: string;
|
|
222
244
|
at: string;
|
|
223
245
|
reason?: string;
|
|
246
|
+
words?: string;
|
|
224
247
|
spentUsd?: number;
|
|
225
248
|
spendComplete?: boolean;
|
|
226
249
|
leg?: number;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What starts the job, in words. `null` (by hand) has no sentence.
|
|
3
|
+
* @param {Trigger|null|undefined} t @param {string} [home]
|
|
4
|
+
* @returns {string|null}
|
|
5
|
+
*/
|
|
6
|
+
export function scheduledWords(t: Trigger | null | undefined, home?: string): string | null;
|
|
7
|
+
/** "Mon 13 Oct, 09:00" — local time, fixed English names (never the machine's locale). @param {number} ms */
|
|
8
|
+
export function slotWords(ms: number): string;
|
|
9
|
+
/**
|
|
10
|
+
* The Scheduled card's first line: "today 17:00", "tomorrow 09:00", else the date the NEXT line already says
|
|
11
|
+
* ("Tue 20 Oct, 09:05"). Local time, by calendar day. @param {number} ms the next run @param {number} now
|
|
12
|
+
*/
|
|
13
|
+
export function nextTimeWords(ms: number, now: number): string;
|
|
14
|
+
/** "next in 20m" / "next in 3h" / "next in 3d" (whole units, rounded down, never "0m"). @param {number} ms @param {number} now */
|
|
15
|
+
export function nextInWords(ms: number, now: number): string;
|
|
16
|
+
/**
|
|
17
|
+
* NEXT of a scheduled job: one sentence, first match wins.
|
|
18
|
+
* 1. a run of this job is waiting for the person's Accept (the next scheduled run does NOT wait for it, T7);
|
|
19
|
+
* 2. the latest outcome this month is `monthly-exhausted` (amounts from the row), RED;
|
|
20
|
+
* 3. a clock kind with a next slot; 4. a file kind that is armed; 5. not armed yet.
|
|
21
|
+
* A last outcome of `refused` goes in front of 3-5, so a trigger that cannot start is never silent.
|
|
22
|
+
* `red` is the typed flag for "the person must act": the page paints it and never guesses from the text.
|
|
23
|
+
* @param {{trigger: Trigger, armed: boolean, nextSlotMs: number|null, lastOutcome: any, waitingRunNo: number|null, now: number, retryInMs?: number|null, gaveUp?: any}} f
|
|
24
|
+
* `lastOutcome` = the newest outcome row of the CURRENT signing (`kind`, `at` in ms, `why`, `leftUsd`, `needUsd`, `atLeast`)
|
|
25
|
+
* @returns {{text: string, red: boolean}}
|
|
26
|
+
*/
|
|
27
|
+
export function scheduledNextFor(f: {
|
|
28
|
+
trigger: Trigger;
|
|
29
|
+
armed: boolean;
|
|
30
|
+
nextSlotMs: number | null;
|
|
31
|
+
lastOutcome: any;
|
|
32
|
+
waitingRunNo: number | null;
|
|
33
|
+
now: number;
|
|
34
|
+
retryInMs?: number | null;
|
|
35
|
+
gaveUp?: any;
|
|
36
|
+
}): {
|
|
37
|
+
text: string;
|
|
38
|
+
red: boolean;
|
|
39
|
+
};
|
|
40
|
+
/** Is `atMs` in the same local calendar month as `nowMs`? A non-number is never. @param {unknown} atMs @param {number} nowMs */
|
|
41
|
+
export function sameMonthAs(atMs: unknown, nowMs: number): boolean;
|
|
42
|
+
/** RULED 2026-10-15: the red NEXT of a schedule that gave up. @param {unknown} why the refusal's own words */
|
|
43
|
+
export function gaveUpNextWords(why: unknown): string;
|
|
44
|
+
/** The give-up date on the Needs-you card, local `MM/DD HH:MM`. @param {number} ms */
|
|
45
|
+
export function gaveUpDateWords(ms: number): string;
|
|
46
|
+
/** RULED 2026-10-15: after an install-needed refusal, the wait that is left, in whole minutes rounded up; '' when no wait. @param {number|null|undefined} ms */
|
|
47
|
+
export function retryWords(ms: number | null | undefined): string;
|
|
48
|
+
/** The fixed catch-up sentence from a run's `trigger.json`. @param {any} rec */
|
|
49
|
+
export function catchUpWords(rec: any): "This run was a catch-up: it started more than 2 minutes after its set time (the panel was off)." | null;
|
|
50
|
+
/**
|
|
51
|
+
* A spawn error AFTER the consuming row: `tries` releases so far, `max` the bound. Under the bound it will be tried again;
|
|
52
|
+
* at the bound it stays consumed and says so. @param {string} why @param {number} tries @param {number} max
|
|
53
|
+
*/
|
|
54
|
+
export function lateRefusalWords(why: string, tries: number, max: number): string;
|
|
55
|
+
/** "Thu 10/16 08:15" — local time, fixed English day names. @param {number} ms */
|
|
56
|
+
export function nextSlotShort(ms: number): string;
|
|
57
|
+
/**
|
|
58
|
+
* Job tab, "Started": how the run began, then its local start time. `rec` = the run's `trigger.json` (null on a hand run).
|
|
59
|
+
* @param {any} rec @param {number|null} atMs the run's start
|
|
60
|
+
*/
|
|
61
|
+
export function startedWords(rec: any, atMs: number | null): string;
|
|
62
|
+
/**
|
|
63
|
+
* Audit, first row of a run a schedule started. @param {any} rec `trigger.json` @param {number|null} originNo the origin run's number
|
|
64
|
+
*/
|
|
65
|
+
export function startedAuditWords(rec: any, originNo: number | null): string;
|
|
66
|
+
/**
|
|
67
|
+
* A fire that started nothing, in plain words. `short` = the SCHEDULE row's `last` reason; else the Audit group's line.
|
|
68
|
+
* @param {any} row a ledger row (`busy` | `monthly-exhausted` | `refused` | `gave-up`) @param {boolean} [short]
|
|
69
|
+
*/
|
|
70
|
+
export function skippedWords(row: any, short?: boolean): string;
|
|
71
|
+
/**
|
|
72
|
+
* Job tab, "Schedule": the job's schedule NOW and what it is bound to. The first part IS the Run tab's line ({@link scheduledWords}),
|
|
73
|
+
* first letter lowered, so the two can never disagree.
|
|
74
|
+
* @param {{trigger: Trigger|null, originNo: number|null, model: string|null, destination: string|null, home?: string}} f
|
|
75
|
+
*/
|
|
76
|
+
export function jobScheduleWords(f: {
|
|
77
|
+
trigger: Trigger | null;
|
|
78
|
+
originNo: number | null;
|
|
79
|
+
model: string | null;
|
|
80
|
+
destination: string | null;
|
|
81
|
+
home?: string;
|
|
82
|
+
}): string;
|
|
83
|
+
/** RULED 2026-10-15: the SCHEDULE row's `next` while an install-needed refusal is waiting to be tried again. @param {number} ms */
|
|
84
|
+
export function retryNextWords(ms: number): string;
|
|
85
|
+
/**
|
|
86
|
+
* RULED 2026-10-15: the sign on the head of the Audit's `schedule` section. ONE small rule (hamr may still adjust it): [▶] only while a
|
|
87
|
+
* run of the job is running (as everywhere in the panel), [✗] when the SCHEDULE row is red, else [·] (on, waiting). RULED 2026-10-18 (v1.106
|
|
88
|
+
* Part 4): the header reads `[sign] word schedule · ...`, the sign AND the word both from the one status table (src/panel/status.js), never typed here.
|
|
89
|
+
* @param {{running: boolean, red: boolean}} f @returns {{sign: string, word: string}}
|
|
90
|
+
*/
|
|
91
|
+
export function scheduleSignFor(f: {
|
|
92
|
+
running: boolean;
|
|
93
|
+
red: boolean;
|
|
94
|
+
}): {
|
|
95
|
+
sign: string;
|
|
96
|
+
word: string;
|
|
97
|
+
};
|
|
98
|
+
/** Audit schedule section, the `this run` words of a run the schedule started (the head already says which schedule and from where). @param {any} rec `trigger.json` */
|
|
99
|
+
export function sectionThisRunWords(rec: any): string;
|
|
100
|
+
/** Audit schedule section, folded tail: `1 try started nothing` / `N tries started nothing`; '' for none. @param {number} n */
|
|
101
|
+
export function triesTailWords(n: number): string;
|
|
102
|
+
/**
|
|
103
|
+
* Every schedule button/word the page shows lives here, so a reword is ONE edit (hamr will reword on his walk).
|
|
104
|
+
* The server sends this table with the run detail and the schedule card; the page reads every label from it.
|
|
105
|
+
*/
|
|
106
|
+
export const SCHEDULE_WORDS: Readonly<{
|
|
107
|
+
byHand: "By hand";
|
|
108
|
+
cancelSchedule: "Cancel schedule";
|
|
109
|
+
cancelWords: "Cancel schedule";
|
|
110
|
+
scheduleRun: "Schedule run";
|
|
111
|
+
cancelModify: "Cancel / modify schedule";
|
|
112
|
+
signSchedule: "Sign schedule";
|
|
113
|
+
nothingChanged: "Nothing changed yet. This card only sets or adjusts the schedule; it never runs the job.";
|
|
114
|
+
confirmPrefix: "Confirm: ";
|
|
115
|
+
whenLabel: "When";
|
|
116
|
+
nowPrefix: "Now: ";
|
|
117
|
+
scheduledLabel: "SCHEDULE";
|
|
118
|
+
nextLabel: "NEXT";
|
|
119
|
+
options: Readonly<{
|
|
120
|
+
hand: "By hand";
|
|
121
|
+
daily: "Every day at HH:MM";
|
|
122
|
+
weekdays: "Weekdays at HH:MM";
|
|
123
|
+
weekly: "Every <day> at HH:MM";
|
|
124
|
+
'file-updated': "When <file> is updated";
|
|
125
|
+
'new-file': "When a new file arrives in <folder>";
|
|
126
|
+
}>;
|
|
127
|
+
gaveUpPill: "Check";
|
|
128
|
+
problemNext: "next: fix it in Cancel / modify schedule";
|
|
129
|
+
monthNext: "next: raise the limit in Settings, or it starts on the 1st";
|
|
130
|
+
acceptWaiting: "waiting for your Accept (the next run does not wait)";
|
|
131
|
+
scheduleGroup: "schedule";
|
|
132
|
+
notGreen: "This job has not had a good run yet. Run it by hand and get it right first; then you can set when it runs. A rubric job also needs your Accept once. Nothing was changed.";
|
|
133
|
+
stale: "What you were shown is not what is on the card now. Nothing was signed. Look again, then sign.";
|
|
134
|
+
}>;
|
|
135
|
+
export function dateTimeWords(ms: number): string;
|
|
136
|
+
export function lowerFirst(s: string): string;
|
|
137
|
+
export type Trigger = import("./trigger.js").Trigger;
|
package/types/source.d.ts
CHANGED
|
@@ -421,6 +421,17 @@ export function refreezeUrlInputs({ into, fetchUrl }: {
|
|
|
421
421
|
ok: false;
|
|
422
422
|
error: string;
|
|
423
423
|
}>;
|
|
424
|
+
/**
|
|
425
|
+
* PRD v1.106 Part 5 Q2: what `source.json` says about web inputs, read synchronously and never throwing: whether the copy has any web input
|
|
426
|
+
* (`inputs[].url`) and when the run-start refetch last finished (`refrozenAt`, written last by {@link refreezeUrlInputs}). The panel decides
|
|
427
|
+
* "fetching the page..." from this: it applies while a web input exists and no refetch has finished at or after `sinceIso`.
|
|
428
|
+
* @param {string} sourceJsonPath @param {string|null|undefined} sinceIso
|
|
429
|
+
* @returns {{ hasWeb: boolean, fetching: boolean }}
|
|
430
|
+
*/
|
|
431
|
+
export function webFetchState(sourceJsonPath: string, sinceIso: string | null | undefined): {
|
|
432
|
+
hasWeb: boolean;
|
|
433
|
+
fetching: boolean;
|
|
434
|
+
};
|
|
424
435
|
/** the per-file ceiling for a rubric input: bareguard's `cited` check searches a quote in a source only up to this size
|
|
425
436
|
* (its `quoteSourceMaxBytes`); a bigger file could never be cited from, so the door refuses it at $0 */
|
|
426
437
|
export const RUBRIC_INPUT_MAX_BYTES: number;
|
package/types/thinking.d.ts
CHANGED
|
@@ -84,6 +84,45 @@ export function thinkingRowText({ mode, support, status }: {
|
|
|
84
84
|
support?: true | false | "unverified";
|
|
85
85
|
status?: string;
|
|
86
86
|
}): string;
|
|
87
|
+
/**
|
|
88
|
+
* THE one decision for a worker model call (PRD v1.106 Part 1): from the phase label and attempt iteration `mkWorker` already holds,
|
|
89
|
+
* and the job's tick (`job.thinking === true`). Decided in code, never by the model.
|
|
90
|
+
* tick on -> 'on' for every call
|
|
91
|
+
* plan (draft, redraft, replan) -> 'on' (the planner is the hard part of a run)
|
|
92
|
+
* scout -> 'off'
|
|
93
|
+
* step:<id> attempt 1 -> 'off'
|
|
94
|
+
* step:<id> attempt >= 2 -> 'on'
|
|
95
|
+
* fix (close-fix) -> 'on'
|
|
96
|
+
* A step or fix iteration that is not a whole number >= 1 throws (operator error), as does an unknown phase — never a guess.
|
|
97
|
+
* @param {{ phase: unknown, iteration?: unknown, tick?: unknown }} o
|
|
98
|
+
* @returns {'on'|'off'}
|
|
99
|
+
*/
|
|
100
|
+
export function workerThinkingMode({ phase, iteration, tick }: {
|
|
101
|
+
phase: unknown;
|
|
102
|
+
iteration?: unknown;
|
|
103
|
+
tick?: unknown;
|
|
104
|
+
}): "on" | "off";
|
|
105
|
+
/**
|
|
106
|
+
* PRD v1.106 Part 3 — the words one worker call carries in the Audit, READ from the run's own spine, never guessed. Finds the LAST
|
|
107
|
+
* `thinking-decision` of `phase` (and `iteration`, when given) whose seq lies strictly between `lo` and `hi`, pairs it with the first
|
|
108
|
+
* `thinking-status` of the same phase and iteration after it (before the next decision), and words both through {@link thinkingRowText}
|
|
109
|
+
* (drafting's own words). `null` when the window holds no decision: a run from before the records existed shows no thinking word.
|
|
110
|
+
* @param {any[]} spine the run's spine records (each with a numeric `seq`)
|
|
111
|
+
* @param {{ phase: string, lo?: number, hi?: number, iteration?: number|null }} q
|
|
112
|
+
* @returns {string|null}
|
|
113
|
+
*/
|
|
114
|
+
export function thinkingWordsFrom(spine: any[], { phase, lo, hi, iteration }: {
|
|
115
|
+
phase: string;
|
|
116
|
+
lo?: number;
|
|
117
|
+
hi?: number;
|
|
118
|
+
iteration?: number | null;
|
|
119
|
+
}): string | null;
|
|
120
|
+
/**
|
|
121
|
+
* The Job tab's row words (PRD v1.106 Part 3): the default rule, or the job's "Thinking on" tick, but only for a run whose spine
|
|
122
|
+
* recorded a `thinking-decision`; a run from before the thinking rule reads `—`, never a guess from the job's tick (fwdloop M4d am28).
|
|
123
|
+
* @param {boolean} tick @param {boolean} recorded the run's spine holds at least one `thinking-decision` @returns {string}
|
|
124
|
+
*/
|
|
125
|
+
export function thinkingJobText(tick: boolean, recorded: boolean): string;
|
|
87
126
|
/** The words under a greyed "Thinking on" box (the server's `thinking.canChange` decides; the page decides nothing). */
|
|
88
127
|
export const THINKING_FIXED_SAY: "can't change this for this model";
|
|
89
128
|
/** The enumerated operator knob a drafting call is built with: 'on' | 'off' (the tick, spelled as a word). */
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The only way a trigger enters the system. Returns the typed trigger, or says what to fix (and which field).
|
|
3
|
+
* @param {unknown} t
|
|
4
|
+
* @returns {{ok: true, trigger: Trigger} | {ok: false, say: string, code: 'invalid-value'|'unknown-field', path: string}}
|
|
5
|
+
*/
|
|
6
|
+
export function validateTrigger(t: unknown): {
|
|
7
|
+
ok: true;
|
|
8
|
+
trigger: Trigger;
|
|
9
|
+
} | {
|
|
10
|
+
ok: false;
|
|
11
|
+
say: string;
|
|
12
|
+
code: "invalid-value" | "unknown-field";
|
|
13
|
+
path: string;
|
|
14
|
+
};
|
|
15
|
+
/** @typedef {import('./triggerclock.js').Schedule | {kind:'new-file', folder:string} | {kind:'file-updated', path:string}} Trigger */
|
|
16
|
+
export const TRIGGER_KINDS: readonly string[];
|
|
17
|
+
export const CLOCK_KINDS: readonly string[];
|
|
18
|
+
export const FILE_KINDS: readonly string[];
|
|
19
|
+
export function isClockTrigger(t: unknown): t is {
|
|
20
|
+
kind: "daily" | "weekdays" | "weekly";
|
|
21
|
+
hour: number;
|
|
22
|
+
minute: number;
|
|
23
|
+
};
|
|
24
|
+
export function isFileTrigger(t: unknown): t is {
|
|
25
|
+
kind: "new-file";
|
|
26
|
+
folder: string;
|
|
27
|
+
} | {
|
|
28
|
+
kind: "file-updated";
|
|
29
|
+
path: string;
|
|
30
|
+
};
|
|
31
|
+
export type Trigger = import("./triggerclock.js").Schedule | {
|
|
32
|
+
kind: "new-file";
|
|
33
|
+
folder: string;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "file-updated";
|
|
36
|
+
path: string;
|
|
37
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The only way a clock schedule enters the system. Refuses anything else, naming the field.
|
|
3
|
+
* @param {unknown} s
|
|
4
|
+
* @returns {Schedule}
|
|
5
|
+
*/
|
|
6
|
+
export function validateSchedule(s: unknown): Schedule;
|
|
7
|
+
/**
|
|
8
|
+
* Is a run due at `now`? Slots missed (panel off) collapse to ONE fire, for the latest slot, marked catch-up.
|
|
9
|
+
* Catch-up = more than one slot was missed, or the latest slot is more than GRACE_MS old.
|
|
10
|
+
* @param {Schedule} schedule
|
|
11
|
+
* @param {ClockRow[]} rows
|
|
12
|
+
* @param {number} now epoch ms
|
|
13
|
+
* @returns {Due}
|
|
14
|
+
*/
|
|
15
|
+
export function due(schedule: Schedule, rows: ClockRow[], now: number): Due;
|
|
16
|
+
/**
|
|
17
|
+
* The next slot time strictly after `afterMs` (epoch ms). Words are the caller's (schedulewords.js).
|
|
18
|
+
* @param {Schedule} schedule
|
|
19
|
+
* @param {number} afterMs
|
|
20
|
+
* @returns {number}
|
|
21
|
+
*/
|
|
22
|
+
export function nextSlot(schedule: Schedule, afterMs: number): number;
|
|
23
|
+
/** The trigger was set at `now` under signature `sig`: no slot before this ever fires. @param {string} file @param {number} now @param {string} sig */
|
|
24
|
+
export function armTrigger(file: string, now: number, sig: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Record that the run for this due slot is starting (the consuming row). Write-once per slot.
|
|
27
|
+
* @param {string} file @param {Due} d the result of `due` with fire true @param {number} now @param {string} sig
|
|
28
|
+
*/
|
|
29
|
+
export function recordFire(file: string, d: Due, now: number, sig: string): void;
|
|
30
|
+
/** @typedef {{kind:'daily'|'weekdays', hour:number, minute:number} | {kind:'weekly', day:string, hour:number, minute:number}} Schedule */
|
|
31
|
+
/** @typedef {import('./triggerledger.js').LedgerRow} ClockRow */
|
|
32
|
+
/** @typedef {{fire:boolean, catchUp:boolean, missed:number, slot?:number}} Due */
|
|
33
|
+
/** A slot seen MORE than this after its set time is a catch-up. Exactly this late is on time. */
|
|
34
|
+
export const GRACE_MS: 120000;
|
|
35
|
+
export const DAYS: string[];
|
|
36
|
+
export type Schedule = {
|
|
37
|
+
kind: "daily" | "weekdays";
|
|
38
|
+
hour: number;
|
|
39
|
+
minute: number;
|
|
40
|
+
} | {
|
|
41
|
+
kind: "weekly";
|
|
42
|
+
day: string;
|
|
43
|
+
hour: number;
|
|
44
|
+
minute: number;
|
|
45
|
+
};
|
|
46
|
+
export type ClockRow = import("./triggerledger.js").LedgerRow;
|
|
47
|
+
export type Due = {
|
|
48
|
+
fire: boolean;
|
|
49
|
+
catchUp: boolean;
|
|
50
|
+
missed: number;
|
|
51
|
+
slot?: number;
|
|
52
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/** The file-kind rows of the job's ledger that still count (a released `ran` does not). @param {string} file @returns {SeenRow[]} */
|
|
2
|
+
export function readSeen(file: string): SeenRow[];
|
|
3
|
+
/** Arrived rows are never overwritten: the 2nd arrival of a sha (after a drop) gets its own id. @param {string} ledger @param {ToRun & {name?:string}} item @param {number} at the scheduler's clock, never the file's mtime @param {string} sig */
|
|
4
|
+
export function recordArrived(ledger: string, item: ToRun & {
|
|
5
|
+
name?: string;
|
|
6
|
+
}, at: number, sig: string): boolean;
|
|
7
|
+
/** `of` = the arrived row it cancels (item.id when a queue row is passed). @param {string} ledger @param {{sha:string, path:string, size:number, id?:string}} item @param {string} why a plain reason: deleted, changed, schedule-changed, schedule-cancelled @param {number} at @param {string} sig */
|
|
8
|
+
export function recordDropped(ledger: string, item: {
|
|
9
|
+
sha: string;
|
|
10
|
+
path: string;
|
|
11
|
+
size: number;
|
|
12
|
+
id?: string;
|
|
13
|
+
}, why: string, at: number, sig: string): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The queue: arrived and neither ran nor dropped, oldest arrival first. Identical arrival times: by name, then by sha (deterministic).
|
|
16
|
+
* @param {SeenRow[]} rows @returns {(SeenRow & {path:string})[]}
|
|
17
|
+
*/
|
|
18
|
+
export function queueOf(rows: SeenRow[]): (SeenRow & {
|
|
19
|
+
path: string;
|
|
20
|
+
})[];
|
|
21
|
+
/**
|
|
22
|
+
* At a queued file's turn, look at it again, at use time: lstat (no symlink, a regular file), realpath of its folder, re-hash.
|
|
23
|
+
* @param {{path:string, sha:string}} item
|
|
24
|
+
* @returns {{state:'ok', path:string, sha:string, size:number} | {state:'deleted', say:string} | {state:'changed', sha:string}}
|
|
25
|
+
*/
|
|
26
|
+
export function recheck(item: {
|
|
27
|
+
path: string;
|
|
28
|
+
sha: string;
|
|
29
|
+
}): {
|
|
30
|
+
state: "ok";
|
|
31
|
+
path: string;
|
|
32
|
+
sha: string;
|
|
33
|
+
size: number;
|
|
34
|
+
} | {
|
|
35
|
+
state: "deleted";
|
|
36
|
+
say: string;
|
|
37
|
+
} | {
|
|
38
|
+
state: "changed";
|
|
39
|
+
sha: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The target is usable NOW, or an Error naming why: a file that is not a symlink and not something else (a file that does not exist yet
|
|
43
|
+
* is allowed: it may arrive), a folder that exists, resolved with realpathSync. The one rule `arm` and a door's set-time check share.
|
|
44
|
+
* @param {'new'|'updated'} mode @param {string} target
|
|
45
|
+
*/
|
|
46
|
+
export function checkTarget(mode: "new" | "updated", target: string): void;
|
|
47
|
+
/**
|
|
48
|
+
* @param {{mode:'new'|'updated', target:string, ledger:string, sig:string, now?:() => number}} opts target = folder (new) or file (updated)
|
|
49
|
+
*/
|
|
50
|
+
export function createFileTrigger({ mode, target, ledger, sig, now }: {
|
|
51
|
+
mode: "new" | "updated";
|
|
52
|
+
target: string;
|
|
53
|
+
ledger: string;
|
|
54
|
+
sig: string;
|
|
55
|
+
now?: () => number;
|
|
56
|
+
}): {
|
|
57
|
+
arm: () => void;
|
|
58
|
+
poll: () => {
|
|
59
|
+
arrived: ToRun[];
|
|
60
|
+
refused: Refused[];
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
/** @typedef {{id:string, kind:'baseline'|'arrived'|'ran'|'dropped', sha:string, name:string, size:number, at:number, sig?:string, path?:string, why?:string, of?:string}} SeenRow */
|
|
64
|
+
/** @typedef {{path:string, sha:string, size:number}} ToRun */
|
|
65
|
+
/** @typedef {{path:string, why:string}} Refused */
|
|
66
|
+
/** Consecutive polls with the same size and mtime before a file is taken. (Two matches in a row = taken on the third sighting.) */
|
|
67
|
+
export const STABLE_POLLS: 2;
|
|
68
|
+
export function recordRan(ledger: string, item: {
|
|
69
|
+
sha: string;
|
|
70
|
+
path: string;
|
|
71
|
+
size: number;
|
|
72
|
+
}, at: number, sig: string): boolean;
|
|
73
|
+
export type SeenRow = {
|
|
74
|
+
id: string;
|
|
75
|
+
kind: "baseline" | "arrived" | "ran" | "dropped";
|
|
76
|
+
sha: string;
|
|
77
|
+
name: string;
|
|
78
|
+
size: number;
|
|
79
|
+
at: number;
|
|
80
|
+
sig?: string;
|
|
81
|
+
path?: string;
|
|
82
|
+
why?: string;
|
|
83
|
+
of?: string;
|
|
84
|
+
};
|
|
85
|
+
export type ToRun = {
|
|
86
|
+
path: string;
|
|
87
|
+
sha: string;
|
|
88
|
+
size: number;
|
|
89
|
+
};
|
|
90
|
+
export type Refused = {
|
|
91
|
+
path: string;
|
|
92
|
+
why: string;
|
|
93
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** @typedef {{id?: string, kind: string, sig?: string, at?: number, [k: string]: unknown}} LedgerRow */
|
|
2
|
+
/**
|
|
3
|
+
* Every row that parses, oldest first, and how many lines did not. A missing file is no rows.
|
|
4
|
+
* @param {string} file
|
|
5
|
+
* @returns {{rows: LedgerRow[], skipped: number}}
|
|
6
|
+
*/
|
|
7
|
+
export function readLedger(file: string): {
|
|
8
|
+
rows: LedgerRow[];
|
|
9
|
+
skipped: number;
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Append one row (dir 0700, file 0600). A torn tail gets a newline first. `once` refuses a row whose `id` is
|
|
13
|
+
* already on disk (write-once ids), by throwing.
|
|
14
|
+
* @param {string} file
|
|
15
|
+
* @param {LedgerRow} row
|
|
16
|
+
* @param {{once?: boolean}} [opts]
|
|
17
|
+
*/
|
|
18
|
+
export function appendRow(file: string, row: LedgerRow, opts?: {
|
|
19
|
+
once?: boolean;
|
|
20
|
+
}): void;
|
|
21
|
+
/**
|
|
22
|
+
* Walk the rows in order: a `released` row (`of` = an id) cancels the latest earlier live row with that id, and
|
|
23
|
+
* is itself dropped. A released `fire` or `ran` is not consumed, so its slot or file is retryable (Part 4) and
|
|
24
|
+
* the same id may be written again.
|
|
25
|
+
* @param {LedgerRow[]} rows
|
|
26
|
+
* @returns {LedgerRow[]}
|
|
27
|
+
*/
|
|
28
|
+
export function withoutReleased(rows: LedgerRow[]): LedgerRow[];
|
|
29
|
+
export type LedgerRow = {
|
|
30
|
+
id?: string;
|
|
31
|
+
kind: string;
|
|
32
|
+
sig?: string;
|
|
33
|
+
at?: number;
|
|
34
|
+
[k: string]: unknown;
|
|
35
|
+
};
|
package/types/userrun.d.ts
CHANGED
|
@@ -219,6 +219,10 @@ export type RunCtx = {
|
|
|
219
219
|
* see `RunOpts.into`
|
|
220
220
|
*/
|
|
221
221
|
into?: string | undefined;
|
|
222
|
+
/**
|
|
223
|
+
* a FRESH `--spec` run: fetch the web inputs again AFTER the run is listed (never on resume/door/decide)
|
|
224
|
+
*/
|
|
225
|
+
refreeze?: boolean | undefined;
|
|
222
226
|
model: string | null;
|
|
223
227
|
providerKey: string | null;
|
|
224
228
|
readShim: string | null;
|