bareloop 0.41.0 → 0.43.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 +109 -1
- package/README.md +13 -21
- package/bareloop.context.md +97 -34
- package/package.json +4 -3
- package/src/authorflow.js +337 -29
- package/src/authoring.js +92 -7
- package/src/authorjob.js +84 -16
- package/src/authorreadout.js +89 -5
- package/src/authorrun.js +14 -5
- package/src/authorscout.js +108 -0
- package/src/declaredclose.js +25 -14
- package/src/facts.js +317 -0
- package/src/factwords.js +129 -0
- package/src/inputlook.js +301 -0
- package/src/interviewrun.js +0 -1
- package/src/job.js +40 -12
- package/src/jobblock.js +7 -2
- package/src/kinds.js +84 -3
- package/src/labelscan.js +170 -0
- package/src/pagefetch.js +125 -0
- package/src/panel/authorroutes.js +121 -34
- package/src/panel/authorsession.js +154 -45
- package/src/panel/index.html +845 -490
- package/src/panel/jobplan.js +34 -11
- package/src/panel/runroutes.js +163 -5
- 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 +467 -48
- package/src/planrun.js +42 -9
- package/src/providerrows.js +3 -3
- package/src/reviewdoor.js +37 -0
- package/src/rubricstep.js +804 -0
- package/src/runlist.js +35 -0
- package/src/schedulewords.js +296 -0
- package/src/source.js +166 -1
- 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/u-readout.js +1 -1
- package/src/userrun.js +20 -9
- package/types/authorflow.d.ts +267 -13
- package/types/authoring.d.ts +29 -1
- package/types/authorjob.d.ts +7 -5
- package/types/authorreadout.d.ts +27 -2
- package/types/authorscout.d.ts +70 -0
- package/types/declaredclose.d.ts +5 -3
- package/types/facts.d.ts +71 -0
- package/types/factwords.d.ts +42 -0
- package/types/inputlook.d.ts +238 -0
- package/types/job.d.ts +8 -1
- package/types/jobblock.d.ts +8 -1
- package/types/labelscan.d.ts +38 -0
- package/types/pagefetch.d.ts +71 -0
- package/types/panel/authorroutes.d.ts +34 -1
- package/types/panel/authorsession.d.ts +55 -14
- package/types/panel/jobplan.d.ts +12 -4
- 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 +145 -14
- package/types/planrun.d.ts +2 -0
- package/types/providerrows.d.ts +2 -2
- package/types/reviewdoor.d.ts +27 -0
- package/types/rubricstep.d.ts +286 -0
- package/types/runlist.d.ts +20 -0
- package/types/schedulewords.d.ts +135 -0
- package/types/source.d.ts +94 -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 +11 -0
|
@@ -7,8 +7,9 @@ export function latestStep(steps: StepLine[], id: string): StepLine | undefined;
|
|
|
7
7
|
* earlier line keeps its status and detail). Existing lines are never moved. Re-starting the step that is still the
|
|
8
8
|
* LAST line just resumes that line.
|
|
9
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)
|
|
10
11
|
*/
|
|
11
|
-
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;
|
|
12
13
|
/**
|
|
13
14
|
* The confirm turn's plan as a chat message (P7): a STRUCTURED `{role:'bot', kind:'plan', plan}` the page draws with the
|
|
14
15
|
* same renderer the Job tab uses — each numbered job line, its `~` rule, its drafted checks folded; the AI's own "not
|
|
@@ -53,6 +54,18 @@ export function planMessage(p: {
|
|
|
53
54
|
export function jobNameTaken(name: string, opts?: {
|
|
54
55
|
jobsDir?: string;
|
|
55
56
|
}): boolean;
|
|
57
|
+
/**
|
|
58
|
+
* The next free name for a NEW workflow made from `origin` (RULED 2026-10-15, v1.101): `<base>-N`, N the next free number from 2.
|
|
59
|
+
* Base: when the origin ends in `-<digits>` AND the part before it is itself a job (in the run list or jobs/), that part (so `x-2`
|
|
60
|
+
* suggests `x-3`, never `x-2-2`); else the origin's own name. Free = not a run-list job and not {@link jobNameTaken}.
|
|
61
|
+
* @param {string} origin
|
|
62
|
+
* @param {Iterable<string>} runJobs job names in the panel's run list
|
|
63
|
+
* @param {{jobsDir?: string}} [opts] test seam for {@link jobNameTaken}
|
|
64
|
+
* @returns {string}
|
|
65
|
+
*/
|
|
66
|
+
export function nextFreeJobName(origin: string, runJobs: Iterable<string>, opts?: {
|
|
67
|
+
jobsDir?: string;
|
|
68
|
+
}): string;
|
|
56
69
|
/**
|
|
57
70
|
* The repo a card names: Inputs line 1 (P7 — the Source box is gone; the first input IS the repo). `''` when the Inputs
|
|
58
71
|
* box does not parse (the card validator refuses that before anything uses this).
|
|
@@ -67,13 +80,13 @@ export function cardSource(card: any): string;
|
|
|
67
80
|
*/
|
|
68
81
|
export function cardFields(card: any): Record<string, any>;
|
|
69
82
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
83
|
+
* Did any JOB box on `card` change from what the origin run prefilled (`origin`)? Whitespace is not compared (a one-line input drops
|
|
84
|
+
* a text's newlines); an absent thinking tick reads as off.
|
|
72
85
|
* @param {Record<string, any>} card the form as it was submitted
|
|
73
86
|
* @param {Record<string, any>} origin the form as the server prefilled it
|
|
74
|
-
* @returns {
|
|
87
|
+
* @returns {boolean}
|
|
75
88
|
*/
|
|
76
|
-
export function
|
|
89
|
+
export function jobBoxesChanged(card: Record<string, any>, origin: Record<string, any>): boolean;
|
|
77
90
|
/**
|
|
78
91
|
* The spec a reuse signs: a COPY of the origin's signed spec with ONLY the open fields set from the card —
|
|
79
92
|
* `writeScope` from Destination, `inputs` from the Inputs box (P7), `budgetUsd` from the $ cap, `maxWallMs` from the Time cap (absent when blank), and the
|
|
@@ -105,6 +118,18 @@ export function validateReuseCard(card: any, opts?: {
|
|
|
105
118
|
ok: false;
|
|
106
119
|
error: string;
|
|
107
120
|
};
|
|
121
|
+
/**
|
|
122
|
+
* THE ONE Destination check of a session start, at $0, before any session, copy or model call. The session's own pipeline, the HTTP
|
|
123
|
+
* start (`startSession`), the schedule's two clicks and a scheduled fire's `wouldAccept` all call THIS (never a copy of it), so a start
|
|
124
|
+
* that would be refused for its Destination is refused before anything is made.
|
|
125
|
+
* @param {{inputs?: unknown, destination?: unknown, checkType?: unknown}} card the Inputs text (line 1 = the source), the Destination and the check type
|
|
126
|
+
* @returns {string|null} the plain refusal, or null when the Destination is fine
|
|
127
|
+
*/
|
|
128
|
+
export function startDestinationProblem(card: {
|
|
129
|
+
inputs?: unknown;
|
|
130
|
+
destination?: unknown;
|
|
131
|
+
checkType?: unknown;
|
|
132
|
+
}): string | null;
|
|
108
133
|
/**
|
|
109
134
|
* The ONE Destination rule for a REPO source (fresh card and Reuse card alike): there Destination is the write fence,
|
|
110
135
|
* relative to the repo, so an absolute path is refused — at $0, before any copy or model call. A FOLDER source (or a
|
|
@@ -119,11 +144,12 @@ export function repoDestinationProblem(destination: string, isRepoLike: boolean)
|
|
|
119
144
|
* creates a session or spends anything — never inside the async pipeline,
|
|
120
145
|
* so a bad card refuses synchronously, in the same HTTP response.
|
|
121
146
|
* @param {any} card
|
|
122
|
-
* @param {{jobsDir?: string, rows?: readonly import('../providerrows.js').KeyRow[]}} [opts] `rows` = the Settings rows (the Model menu); jobsDir is a server-side test seam — NEVER read off the client card
|
|
147
|
+
* @param {{jobsDir?: string, allowName?: string, rows?: readonly import('../providerrows.js').KeyRow[]}} [opts] `rows` = the Settings rows (the Model menu); jobsDir is a server-side test seam — NEVER read off the client card; `allowName` = the origin job's own name on an unchanged red Reuse (it is the same job, not a collision)
|
|
123
148
|
* @returns {{ok: true}|{ok: false, error: string}}
|
|
124
149
|
*/
|
|
125
150
|
export function validateJobCard(card: any, opts?: {
|
|
126
151
|
jobsDir?: string;
|
|
152
|
+
allowName?: string;
|
|
127
153
|
rows?: readonly import("../providerrows.js").KeyRow[];
|
|
128
154
|
}): {
|
|
129
155
|
ok: true;
|
|
@@ -139,7 +165,7 @@ export function validateJobCard(card: any, opts?: {
|
|
|
139
165
|
* @param {any} card the validated job card (see {@link validateJobCard})
|
|
140
166
|
* @param {{env?: Record<string,string|undefined>, sessionsRoot?: string, home?: string, timeoutMs?: number,
|
|
141
167
|
* scout?: any, generate?: Function, confirmGenerate?: Function, authorFn?: Function,
|
|
142
|
-
* prepareSigningFn?: Function, npmCiFn?: Function, draftThinking?: "on"|"off", reuse?: {spec: any, workflowKey: string}}} [deps] `scout`..`prepareSigningFn` are
|
|
168
|
+
* 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
|
|
143
169
|
* TEST SEAMS ONLY — see the note just above where each is read, below. `reuse` (Reuse workflow) is NOT a seam: the
|
|
144
170
|
* caller (`/api/author/start`) sets it only when the server's own same-job rule held.
|
|
145
171
|
* @returns {any} the session object
|
|
@@ -155,6 +181,15 @@ export function createSession(card: any, deps?: {
|
|
|
155
181
|
authorFn?: Function;
|
|
156
182
|
prepareSigningFn?: Function;
|
|
157
183
|
npmCiFn?: Function;
|
|
184
|
+
lookFn?: Function | null;
|
|
185
|
+
fetchUrl?: (url: string) => Promise<{
|
|
186
|
+
ok: true;
|
|
187
|
+
text: string;
|
|
188
|
+
url: string;
|
|
189
|
+
} | {
|
|
190
|
+
ok: false;
|
|
191
|
+
error: string;
|
|
192
|
+
}>;
|
|
158
193
|
draftThinking?: "on" | "off";
|
|
159
194
|
reuse?: {
|
|
160
195
|
spec: any;
|
|
@@ -168,6 +203,12 @@ export function createSession(card: any, deps?: {
|
|
|
168
203
|
* @type {Readonly<Record<string, string>>}
|
|
169
204
|
*/
|
|
170
205
|
export const STEP_LABELS: Readonly<Record<string, string>>;
|
|
206
|
+
/**
|
|
207
|
+
* 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.
|
|
208
|
+
* Code-owned, one table beside STEP_LABELS; a step with no entry keeps its STEP_LABELS word.
|
|
209
|
+
* @type {Readonly<Record<string, string>>}
|
|
210
|
+
*/
|
|
211
|
+
export const FILE_JOB_STEP_LABELS: Readonly<Record<string, string>>;
|
|
171
212
|
/**
|
|
172
213
|
* The library's own `onPhase(name, ...)` calls (`src/authorjob.js`/`src/authorflow.js`) -> the step each one advances.
|
|
173
214
|
* A phase with no entry leaves the current step as it was.
|
|
@@ -179,14 +220,14 @@ export const PLAN_FOOTER: "Sign & run to confirm this plan, or Revise to edit th
|
|
|
179
220
|
/** the form's fields, in card order — what `card.json` stores, verbatim (P5 item 3) */
|
|
180
221
|
export const CARD_FIELDS: readonly string[];
|
|
181
222
|
/**
|
|
182
|
-
* REUSE WORKFLOW (
|
|
183
|
-
*
|
|
184
|
-
*
|
|
185
|
-
*
|
|
223
|
+
* REUSE WORKFLOW, ONE DOOR (RULED 2026-10-15, v1.101; replaces v1.88's five open boxes). Every box on the card is open. What decides
|
|
224
|
+
* the path is the CARD compared with the origin run's card, never the drafted spec: the JOB boxes are the job text (numbered lines,
|
|
225
|
+
* `~` rules, `~ PASS`/`~ FAIL`), the check type and the thinking tick. The RUN boxes (Inputs, Destination, Model, $ cap, Time cap)
|
|
226
|
+
* never decide it. A green origin with no job box changed reuses the signed plan verbatim (no drafting); anything else drafts.
|
|
186
227
|
*/
|
|
187
|
-
export const
|
|
188
|
-
/**
|
|
189
|
-
export const
|
|
228
|
+
export const JOB_BOXES: readonly string[];
|
|
229
|
+
/** the refusal for a plain-files rubric job whose Destination is not an absolute folder (ends with the words the session start shows) */
|
|
230
|
+
export const FILES_DESTINATION_WORDS: "Destination must be the full path of a folder, like /home/me/out \u2014 the finished files are delivered there. Nothing spent.";
|
|
190
231
|
export type StepLine = {
|
|
191
232
|
id: string;
|
|
192
233
|
label: string;
|
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
|
};
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RULED 2026-10-16: the person never sees raw engine output. Of the engine's log tail, only a line it
|
|
3
|
+
* owns as a plain sentence passes through (a `Nothing spent.` / `Nothing was spent.` refusal, `DOOR REFUSED (...) — nothing was
|
|
4
|
+
* recorded...`, `CHECKPOINT EXPIRED — ...`); anything else (validator reds, exit statuses, stack traces, argv) becomes ONE fixed
|
|
5
|
+
* sentence naming the log. The one owner for the Resume and Accept routes.
|
|
6
|
+
* @param {string} tail the log tail
|
|
7
|
+
* @param {'resume'|'accept'} kind
|
|
8
|
+
* @param {string} logFile
|
|
9
|
+
* @param {(stage: string) => string|null} [questionOf] stage name to the panel's plain question (`null` = none)
|
|
10
|
+
* @returns {string}
|
|
11
|
+
*/
|
|
12
|
+
export function engineRefusalWords(tail: string, kind: "resume" | "accept", logFile: string, questionOf?: (stage: string) => string | null): string;
|
|
1
13
|
/**
|
|
2
14
|
* The run routes' handler. `getResumeContext(runid)` is the server's own reader (the same
|
|
3
15
|
* `resumePlanFor` the Ended block uses, so the page never offers what this refuses):
|
|
@@ -5,7 +17,11 @@
|
|
|
5
17
|
* @param {{ port: number, token: string, env?: Record<string,string|undefined>, home?: string,
|
|
6
18
|
* spawnFn?: typeof realSpawn, bareloopBin?: string, settleMs?: number,
|
|
7
19
|
* getResumeContext: (runid: string) => ({row: any, plan: any}|null),
|
|
8
|
-
* getStopContext?: (runid: string) => ({row: any, live: boolean, spineExists: boolean}|null)
|
|
20
|
+
* getStopContext?: (runid: string) => ({row: any, live: boolean, spineExists: boolean}|null),
|
|
21
|
+
* getNeedsContext?: (runid: string) => ({row: any, needs: 'Accept'|'Resume'|null}|null),
|
|
22
|
+
* getAcceptContext?: (runid: string) => ({row: any, live: boolean, waiting: boolean, specPath: string|null, specHash: string|null}|null),
|
|
23
|
+
* stageQuestionsOfSpec?: (spec: any) => Map<string, string|null>,
|
|
24
|
+
* acceptWaitMs?: number }} opts
|
|
9
25
|
*/
|
|
10
26
|
export function createRunRoutes(opts: {
|
|
11
27
|
port: number;
|
|
@@ -24,9 +40,24 @@ export function createRunRoutes(opts: {
|
|
|
24
40
|
live: boolean;
|
|
25
41
|
spineExists: boolean;
|
|
26
42
|
} | null);
|
|
43
|
+
getNeedsContext?: (runid: string) => ({
|
|
44
|
+
row: any;
|
|
45
|
+
needs: "Accept" | "Resume" | null;
|
|
46
|
+
} | null);
|
|
47
|
+
getAcceptContext?: (runid: string) => ({
|
|
48
|
+
row: any;
|
|
49
|
+
live: boolean;
|
|
50
|
+
waiting: boolean;
|
|
51
|
+
specPath: string | null;
|
|
52
|
+
specHash: string | null;
|
|
53
|
+
} | null);
|
|
54
|
+
stageQuestionsOfSpec?: (spec: any) => Map<string, string | null>;
|
|
55
|
+
acceptWaitMs?: number;
|
|
27
56
|
}): {
|
|
28
57
|
handle: (req: import("node:http").IncomingMessage, res: import("node:http").ServerResponse, pathname: string, body: any) => boolean;
|
|
29
58
|
};
|
|
30
59
|
/** how long a resume waits for an early engine exit before reporting "started" (ms) */
|
|
31
60
|
export const DEFAULT_SETTLE_MS: 6000;
|
|
61
|
+
/** how long an Accept waits for the engine's answer (it re-runs the mechanical close stages) before saying it is still checking (ms) */
|
|
62
|
+
export const DEFAULT_ACCEPT_WAIT_MS: number;
|
|
32
63
|
import { spawn as realSpawn } from 'node:child_process';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {{ door: ReturnType<typeof import('./schedules.js').createScheduleDoor>, now?: () => number, intervalMs?: number }} opts
|
|
3
|
+
* `intervalMs` 0 = no timer (a test drives `tick`).
|
|
4
|
+
*/
|
|
5
|
+
export function createScheduler(opts: {
|
|
6
|
+
door: ReturnType<typeof import("./schedules.js").createScheduleDoor>;
|
|
7
|
+
now?: () => number;
|
|
8
|
+
intervalMs?: number;
|
|
9
|
+
}): {
|
|
10
|
+
tick: () => Promise<void>;
|
|
11
|
+
/** Start the real timer (idempotent). */
|
|
12
|
+
start(): void;
|
|
13
|
+
/** Stop it (idempotent). The server's close calls this. */
|
|
14
|
+
stop(): void;
|
|
15
|
+
/** whether the real timer is running (a test reads this) */
|
|
16
|
+
readonly running: boolean;
|
|
17
|
+
};
|