bareloop 0.39.0 → 0.41.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 +60 -0
- package/bareloop.context.md +137 -112
- package/package.json +2 -2
- package/src/authorflow.js +333 -58
- package/src/authoring.js +65 -2
- package/src/authorjob.js +57 -9
- package/src/authorreadout.js +50 -2
- package/src/authorrun.js +30 -27
- package/src/authorscout.js +9 -6
- package/src/bridges.js +1 -1
- package/src/bundle.js +7 -4
- package/src/bundlerun.js +4 -1
- package/src/calibrate.js +1 -1
- package/src/cardauthor.js +4 -1
- package/src/cli.js +1 -1
- package/src/config.js +129 -29
- package/src/declaredclose.js +4 -3
- package/src/draftspend.js +6 -1
- package/src/index.js +2 -4
- package/src/interviewrun.js +73 -52
- package/src/job.js +50 -11
- package/src/jobblock.js +140 -0
- package/src/judged.js +12 -44
- package/src/keysfile.js +15 -7
- package/src/kinds.js +2 -2
- package/src/ledger.js +1 -1
- package/src/modellist.js +84 -0
- package/src/monthly.js +23 -43
- package/src/panel/authorroutes.js +34 -19
- package/src/panel/authorsession.js +187 -72
- package/src/panel/index.html +699 -215
- package/src/panel/jobplan.js +107 -0
- package/src/panel/runroutes.js +3 -0
- package/src/panel/server.js +102 -28
- package/src/panel/settingsroutes.js +232 -173
- package/src/planrun.js +6 -6
- package/src/promptregisters.js +1 -1
- package/src/providerrows.js +226 -141
- package/src/providers.js +58 -250
- package/src/providershapes.js +18 -0
- package/src/replay.js +1 -1
- package/src/reuse.js +1 -1
- package/src/root.js +1 -1
- package/src/run.js +3 -3
- package/src/selection.js +1 -1
- package/src/source.js +64 -1
- package/src/text.js +13 -0
- package/src/thinking.js +130 -0
- package/src/transport.js +1 -1
- package/src/userrun.js +53 -76
- package/types/authorflow.d.ts +258 -39
- package/types/authoring.d.ts +7 -1
- package/types/authorjob.d.ts +35 -3
- package/types/authorreadout.d.ts +17 -1
- package/types/authorscout.d.ts +5 -3
- package/types/config.d.ts +23 -6
- package/types/declaredclose.d.ts +4 -1
- package/types/draftspend.d.ts +8 -2
- package/types/index.d.ts +1 -1
- package/types/job.d.ts +6 -6
- package/types/jobblock.d.ts +102 -0
- package/types/judged.d.ts +5 -36
- package/types/keysfile.d.ts +15 -4
- package/types/modellist.d.ts +50 -0
- package/types/monthly.d.ts +4 -3
- package/types/panel/authorsession.d.ts +44 -15
- package/types/panel/jobplan.d.ts +58 -0
- package/types/panel/server.d.ts +34 -4
- package/types/planrun.d.ts +1 -1
- package/types/providerrows.d.ts +192 -99
- package/types/providers.d.ts +35 -116
- package/types/providershapes.d.ts +10 -0
- package/types/run.d.ts +1 -1
- package/types/source.d.ts +26 -0
- package/types/thinking.d.ts +90 -0
- package/types/userrun.d.ts +6 -1
|
@@ -23,11 +23,14 @@ import { openSync } from 'node:fs';
|
|
|
23
23
|
import { join } from 'node:path';
|
|
24
24
|
import { readFileSync } from 'node:fs';
|
|
25
25
|
import { createSession, validateJobCard, validateReuseCard, lockedFieldChanged, buildReuseSpec, cardFields, STEP_LABELS } from './authorsession.js';
|
|
26
|
+
import { parseInputs } from '../jobblock.js';
|
|
27
|
+
import { proveInputFiles } from '../source.js';
|
|
26
28
|
import { validateJob } from '../job.js';
|
|
27
29
|
import { checkMonthlyRoom, monthlyRefusalText } from '../monthly.js';
|
|
28
30
|
import { ConfigError } from '../config.js';
|
|
29
31
|
import { keysForDoor, keysHome } from '../keysfile.js';
|
|
30
|
-
import {
|
|
32
|
+
import { endpointOf, judgePick, keyValueOf, rowsForHome, tickedLines } from '../providerrows.js';
|
|
33
|
+
import { thinkingForLine } from '../thinking.js';
|
|
31
34
|
import { apiKeyProblem, checkProviderReachable } from '../providers.js';
|
|
32
35
|
|
|
33
36
|
/** @returns {string} a fresh per-process token — never persisted, never logged */
|
|
@@ -135,13 +138,13 @@ export function createAuthorRoutes(opts) {
|
|
|
135
138
|
if (pathname === '/api/author/model-check') {
|
|
136
139
|
if (req.method !== 'GET') { send(405, { ok: false, error: 'GET only' }); return true; }
|
|
137
140
|
const q = new URL(/** @type {string} */ (req.url), 'http://127.0.0.1').searchParams;
|
|
138
|
-
const
|
|
139
|
-
const
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
// the key of the Settings row this
|
|
143
|
-
const keyName =
|
|
144
|
-
const raw = envNow()
|
|
141
|
+
const rows = rowsForHome(keysHome(opts.home), envNow());
|
|
142
|
+
const pick = judgePick(rows, { provider: q.get('provider'), model: q.get('model') });
|
|
143
|
+
if (!pick.ok) { send(400, { ok: false, error: pick.say }); return true; }
|
|
144
|
+
const choice = pick.choice;
|
|
145
|
+
// the key of the Settings row this line belongs to
|
|
146
|
+
const keyName = choice.envName;
|
|
147
|
+
const raw = keyValueOf(envNow(), keyName);
|
|
145
148
|
const problem = raw ? apiKeyProblem(raw) : null;
|
|
146
149
|
const keyStatus = !raw ? 'missing' : (problem ? 'bad-shape' : 'found');
|
|
147
150
|
if (keyStatus !== 'found') {
|
|
@@ -155,7 +158,7 @@ export function createAuthorRoutes(opts) {
|
|
|
155
158
|
// `checkProviderReachable`'s own doc) — a short timeout so a flaky
|
|
156
159
|
// endpoint never hangs the card.
|
|
157
160
|
checkProviderReachable({
|
|
158
|
-
providerName: choice.provider, apiKey: /** @type {string} */ (
|
|
161
|
+
providerName: choice.provider, apiKey: /** @type {string} */ (raw), model: choice.name,
|
|
159
162
|
baseUrl: choice.baseUrl, fetchImpl, timeoutMs: 4000,
|
|
160
163
|
}).then((r) => {
|
|
161
164
|
send(200, {
|
|
@@ -178,7 +181,11 @@ export function createAuthorRoutes(opts) {
|
|
|
178
181
|
// ── P4b: Chat's Model menu IS the Settings rows (a blank Name is not offered). ──
|
|
179
182
|
if (pathname === '/api/author/models') {
|
|
180
183
|
if (req.method !== 'GET') { send(405, { ok: false, error: 'GET only' }); return true; }
|
|
181
|
-
|
|
184
|
+
// every ticked-and-priced line of a row, labelled `<KEY> · <model>`; `thinking` is the server's answer for the "Thinking on" box
|
|
185
|
+
const lines = tickedLines(rowsForHome(keysHome(opts.home), envNow())).map(({ row, line }) => ({
|
|
186
|
+
slot: row.envName, model: line.model, label: `${row.envName} · ${line.model}`, shape: row.provider, endpoint: endpointOf(row.provider, row.baseUrl), thinking: thinkingForLine(row.provider, line.model, row.baseUrl),
|
|
187
|
+
}));
|
|
188
|
+
send(200, { ok: true, lines, say: lines.length === 0 ? 'Tick a model in Settings > Providers.' : '' });
|
|
182
189
|
return true;
|
|
183
190
|
}
|
|
184
191
|
|
|
@@ -205,14 +212,14 @@ export function createAuthorRoutes(opts) {
|
|
|
205
212
|
const sp = new URL(/** @type {string} */ (req.url), 'http://127.0.0.1').searchParams;
|
|
206
213
|
const runid = sp.get('runid') ?? '';
|
|
207
214
|
// `model` = the card's Model box right now: the estimate line counts only runs on that worker
|
|
208
|
-
const asModel = sp.has('model') ? { model: sp.get('model') ?? '' } : {};
|
|
215
|
+
const asModel = sp.has('model') ? { model: sp.get('model') ?? '', provider: sp.get('provider') ?? '' } : {};
|
|
209
216
|
const pre = sp.has('import') ? opts.startFrom.getImport(sp.get('import') ?? '', asModel) : opts.startFrom.get(runid, asModel);
|
|
210
217
|
if (pre === null) { send(404, { ok: false, error: 'no such run' }); return true; }
|
|
211
218
|
if (!pre.ok) { send(409, pre); return true; }
|
|
212
219
|
send(200, {
|
|
213
220
|
ok: true, origin: pre.origin, card: pre.card, from: pre.from, note: pre.note,
|
|
214
221
|
locked: pre.locked, open: pre.open, specHash: pre.specHash, workflowKey: pre.workflowKey, trackRecord: pre.trackRecord,
|
|
215
|
-
line: pre.line,
|
|
222
|
+
line: pre.line, specNamesModel: pre.specNamesModel, specWorker: pre.specWorker,
|
|
216
223
|
});
|
|
217
224
|
return true;
|
|
218
225
|
}
|
|
@@ -223,7 +230,7 @@ export function createAuthorRoutes(opts) {
|
|
|
223
230
|
if (!opts.startFrom || !opts.startFrom.listJobs) { send(404, { ok: false, error: 'not found' }); return true; }
|
|
224
231
|
if (req.method !== 'GET') { send(405, { ok: false, error: 'GET only' }); return true; }
|
|
225
232
|
const sp = new URL(/** @type {string} */ (req.url), 'http://127.0.0.1').searchParams;
|
|
226
|
-
const asModel = sp.has('model') ? { model: sp.get('model') ?? '' } : {};
|
|
233
|
+
const asModel = sp.has('model') ? { model: sp.get('model') ?? '', provider: sp.get('provider') ?? '' } : {};
|
|
227
234
|
send(200, { ok: true, jobs: opts.startFrom.listJobs(asModel) });
|
|
228
235
|
return true;
|
|
229
236
|
}
|
|
@@ -241,7 +248,7 @@ export function createAuthorRoutes(opts) {
|
|
|
241
248
|
if (req.method !== 'POST') { send(405, { ok: false, error: 'POST only' }); return true; }
|
|
242
249
|
if (hasLiveSession()) { send(409, { ok: false, error: 'an authoring session is already live — one at a time' }); return true; }
|
|
243
250
|
const card = body ?? {};
|
|
244
|
-
const rows = rowsForHome(keysHome(opts.home));
|
|
251
|
+
const rows = rowsForHome(keysHome(opts.home), envNow());
|
|
245
252
|
// Reuse workflow — started from a green run or an imported job: only Source, Destination and the two caps may
|
|
246
253
|
// differ from the signed workflow. The SERVER refuses any other change (the page greys those boxes, but is
|
|
247
254
|
// never trusted); the spec it signs is a copy of the origin's with just those four set. Nothing is drafted.
|
|
@@ -274,11 +281,19 @@ export function createAuthorRoutes(opts) {
|
|
|
274
281
|
const v = validateJobCard(card, { jobsDir: opts.jobsDir, rows });
|
|
275
282
|
if (!v.ok) { send(400, { ok: false, error: v.error }); return true; }
|
|
276
283
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
284
|
+
// P7: the Inputs are proven at $0 before a session (so before any token): line 1 the repo, lines 2+ tracked files inside it.
|
|
285
|
+
// A miss is a plain 400 naming the line, shown under the card exactly like every other refused start.
|
|
286
|
+
const ip = parseInputs(card.inputs);
|
|
287
|
+
if (!ip.ok) { send(400, { ok: false, error: ip.error }); return true; }
|
|
288
|
+
proveInputFiles(ip.inputs).then((proof) => {
|
|
289
|
+
if (!proof.ok) { send(400, { ok: false, error: proof.error }); return; }
|
|
290
|
+
if (hasLiveSession()) { send(409, { ok: false, error: 'an authoring session is already live — one at a time' }); return; }
|
|
291
|
+
const session = createSession(cardFields(card), {
|
|
292
|
+
env: envNow(), sessionsRoot: opts.sessionsRoot, ...(opts.home !== undefined ? { home: opts.home } : {}), ...(reuse ? { reuse } : {}),
|
|
293
|
+
});
|
|
294
|
+
sessions.set(session.id, session);
|
|
295
|
+
send(200, { ok: true, sessionId: session.id, reuse: reuse !== null, state: session.state });
|
|
296
|
+
}).catch((e) => { send(500, { ok: false, error: `could not check the inputs: ${/** @type {Error} */ (e)?.message ?? e}` }); });
|
|
282
297
|
return true;
|
|
283
298
|
}
|
|
284
299
|
|