@manyoars/oars 0.5.3 → 0.5.5
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/README.md +6 -3
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +79 -6
- package/dist/club.d.ts +2 -0
- package/dist/club.js +10 -4
- package/dist/errors.d.ts +2 -0
- package/dist/errors.js +2 -0
- package/dist/sessions/archive.js +1 -1
- package/dist/sessions/card-command.d.ts +2 -2
- package/dist/sessions/card-command.js +7 -5
- package/dist/sessions/card-line.d.ts +6 -2
- package/dist/sessions/card-line.js +6 -3
- package/dist/sessions/cell-increments.d.ts +7 -0
- package/dist/sessions/cell-increments.js +25 -10
- package/dist/sessions/cells.d.ts +7 -0
- package/dist/sessions/cells.js +118 -107
- package/dist/sessions/crew-mark.d.ts +6 -0
- package/dist/sessions/crew-mark.js +22 -0
- package/dist/sessions/hook-index.d.ts +2 -1
- package/dist/sessions/hook-index.js +2 -2
- package/dist/sessions/pool-command.d.ts +47 -1
- package/dist/sessions/pool-command.js +694 -90
- package/dist/sessions/pool-delta.d.ts +5 -0
- package/dist/sessions/pool-delta.js +32 -12
- package/dist/sessions/pool-fold.d.ts +22 -0
- package/dist/sessions/pool-fold.js +65 -0
- package/dist/sessions/pool-outbox.d.ts +22 -0
- package/dist/sessions/pool-outbox.js +78 -11
- package/dist/sessions/pool-send-lock.d.ts +2 -1
- package/dist/sessions/pool-send-lock.js +4 -2
- package/dist/sessions/pool.d.ts +10 -5
- package/dist/sessions/pool.js +16 -15
- package/dist/sessions/read-call-shape.js +3 -2
- package/dist/sessions/read-folds.d.ts +21 -0
- package/dist/sessions/read-folds.js +37 -0
- package/dist/sessions/read-recovery.d.ts +1 -1
- package/dist/sessions/read-recovery.js +6 -5
- package/dist/sessions/read-support.d.ts +4 -1
- package/dist/sessions/recall-consequence.d.ts +2 -1
- package/dist/sessions/recall-consequence.js +1 -2
- package/dist/sessions/recall-reads.d.ts +23 -1
- package/dist/sessions/recall-reads.js +91 -63
- package/dist/sessions/reversion.d.ts +41 -2
- package/dist/sessions/reversion.js +17 -10
- package/dist/sessions/store.d.ts +55 -2
- package/dist/sessions/store.js +312 -61
- package/dist/telemetry/measures.d.ts +5 -0
- package/dist/telemetry/measures.js +16 -2
- package/dist/telemetry/schema.js +3 -1
- package/dist/telemetry/words.d.ts +6 -0
- package/dist/telemetry/words.js +4 -0
- package/package.json +1 -1
package/dist/sessions/cells.js
CHANGED
|
@@ -160,7 +160,8 @@ const linesOf = (tools) => {
|
|
|
160
160
|
}
|
|
161
161
|
return [...lines.values()].map((line) => line.sort((a, b) => a.n - b.n));
|
|
162
162
|
};
|
|
163
|
-
|
|
163
|
+
/** `deriveCells` as a fold: each `add` tallies one run of sessions into the same tallies, and `finish` sorts them. The runs must come in the order the whole store holds its rows, so sums of floats match. */
|
|
164
|
+
export const cellFold = (graph = NO_RECALLS) => {
|
|
164
165
|
const tallies = new Map();
|
|
165
166
|
const motifs = new Map();
|
|
166
167
|
const tallyAt = (motif, frameBucket, grain, day, exposure) => {
|
|
@@ -181,128 +182,138 @@ export const deriveCells = (store, graph = NO_RECALLS) => {
|
|
|
181
182
|
// Fit's (name, platform, shell) cell: a week cell beside the versioned one, counting the same call.
|
|
182
183
|
return isPlainCall(motif) ? [...tallies, tallyAt(motif, environmentBucketOf(frame), 'week', weekStartOf(day), exposure)] : tallies;
|
|
183
184
|
};
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
const
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
tally.
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
185
|
+
const add = (store) => {
|
|
186
|
+
const sessions = new Map([...store.sessions, ...store.subagents].map((session) => [session.session, session]));
|
|
187
|
+
const prompts = new Map(store.prompts.map((prompt) => [`${prompt.session}#${String(prompt.index)}`, prompt]));
|
|
188
|
+
for (const line of linesOf(store.tools)) {
|
|
189
|
+
const [first] = line;
|
|
190
|
+
const session = first === undefined ? undefined : sessions.get(first.session);
|
|
191
|
+
if (first === undefined || session === undefined)
|
|
192
|
+
continue;
|
|
193
|
+
const harness = harnessOf(session);
|
|
194
|
+
const version = first.harnessVersion ?? session.env.harness;
|
|
195
|
+
const prompt = prompts.get(`${first.session}#${String(first.prompt)}`);
|
|
196
|
+
const frame = prompt === undefined
|
|
197
|
+
? (session.frame ?? oldFrame({ harness, version, model: mostUsedModel(session.models), effort: null, ts: first.ts ?? session.tsFirst, platform: session.env.os }))
|
|
198
|
+
: framedPrompt(prompt, harness, version, first.ts, session.env.os);
|
|
199
|
+
const placed = line.flatMap((tool) => graph.place(tool, stepsOfCall(tool, harness)));
|
|
200
|
+
const steps = placed.map(({ step }) => step);
|
|
201
|
+
for (const { motif, start } of motifsOf(steps)) {
|
|
202
|
+
const window = steps.slice(start, start + motif.steps.length);
|
|
203
|
+
const status = window.at(-1)?.status;
|
|
204
|
+
const covered = placed.slice(start, start + motif.steps.length);
|
|
205
|
+
for (const tally of talliesOf(motif, frame, exposureOf(covered.some(({ exposed }) => exposed), covered.some((step) => 'held' in step && step.held)))) {
|
|
206
|
+
tally.sessions.add(first.parent);
|
|
207
|
+
if (status === 'ok')
|
|
208
|
+
tally.ok += 1;
|
|
209
|
+
if (status === 'error')
|
|
210
|
+
tally.failed += 1;
|
|
211
|
+
for (const step of window) {
|
|
212
|
+
// A step with no recorded cost has no tokens to count, so it joins neither the sum nor the coverage (its duration is still counted).
|
|
213
|
+
if (step.tokens !== null) {
|
|
214
|
+
tally.tokens += step.tokens;
|
|
215
|
+
tally.recorded.add(first.parent);
|
|
216
|
+
tally.recordedUnits += 1;
|
|
217
|
+
}
|
|
218
|
+
tally.durationMs += step.durationMs;
|
|
215
219
|
}
|
|
216
|
-
tally.durationMs += step.durationMs;
|
|
217
220
|
}
|
|
218
221
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const motif = classMotif(recoveryClass(code, calls[at]?.steps[0]?.action ?? 'other', followed.next[0] ?? NO_NEXT));
|
|
229
|
-
motifs.set(motif.motifId, motif);
|
|
230
|
-
const tally = tallyAt(motif, versionBucketOf(frame), 'week', weekStartOf(frame.day ?? UNKNOWN), 'unknown');
|
|
231
|
-
tally.sessions.add(first.parent);
|
|
232
|
-
tally.failed += 1;
|
|
233
|
-
}
|
|
234
|
-
// Each call's shape, by its first step's action: a week cell per facet it holds, counted by the call's own status.
|
|
235
|
-
for (const [at, tool] of line.entries()) {
|
|
236
|
-
const action = calls[at]?.steps[0]?.action ?? 'other';
|
|
237
|
-
for (const [facet, value] of shapeFacetsOf(tool)) {
|
|
238
|
-
const motif = classMotif(shapeClass(action, facet, value));
|
|
222
|
+
// What followed each failed call that has a code (t868): a week cell per (code, failed action, next action).
|
|
223
|
+
// A call is read by its first step's action, as a skeleton's is; a record captured before steps has the action its native name maps to.
|
|
224
|
+
const calls = line.map((call) => ({ side: call.side, prompt: call.prompt, status: call.status, steps: stepsOfCall(call, harness) }));
|
|
225
|
+
for (const [at, tool] of line.entries()) {
|
|
226
|
+
const followed = recoveryCallsOf(calls, at);
|
|
227
|
+
if (followed === null || tool.errorCode === undefined)
|
|
228
|
+
continue;
|
|
229
|
+
const code = ERROR_CODES.has(tool.errorCode) ? tool.errorCode : 'other';
|
|
230
|
+
const motif = classMotif(recoveryClass(code, calls[at]?.steps[0]?.action ?? 'other', followed.next[0] ?? NO_NEXT));
|
|
239
231
|
motifs.set(motif.motifId, motif);
|
|
240
232
|
const tally = tallyAt(motif, versionBucketOf(frame), 'week', weekStartOf(frame.day ?? UNKNOWN), 'unknown');
|
|
241
233
|
tally.sessions.add(first.parent);
|
|
242
|
-
|
|
243
|
-
tally.ok += 1;
|
|
244
|
-
if (tool.status === 'error')
|
|
245
|
-
tally.failed += 1;
|
|
234
|
+
tally.failed += 1;
|
|
246
235
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
236
|
+
// Each call's shape, by its first step's action: a week cell per facet it holds, counted by the call's own status.
|
|
237
|
+
for (const [at, tool] of line.entries()) {
|
|
238
|
+
const action = calls[at]?.steps[0]?.action ?? 'other';
|
|
239
|
+
for (const [facet, value] of shapeFacetsOf(tool)) {
|
|
240
|
+
const motif = classMotif(shapeClass(action, facet, value));
|
|
241
|
+
motifs.set(motif.motifId, motif);
|
|
242
|
+
const tally = tallyAt(motif, versionBucketOf(frame), 'week', weekStartOf(frame.day ?? UNKNOWN), 'unknown');
|
|
243
|
+
tally.sessions.add(first.parent);
|
|
244
|
+
if (tool.status === 'ok')
|
|
245
|
+
tally.ok += 1;
|
|
246
|
+
if (tool.status === 'error')
|
|
247
|
+
tally.failed += 1;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
// The failed calls by their `errorCode` (t868). Rule 6: a day cell exists for a known day only.
|
|
251
|
+
const failedDay = frame.day ?? UNKNOWN;
|
|
252
|
+
for (const tool of failedDay === UNKNOWN ? [] : line) {
|
|
253
|
+
if (tool.status !== 'error' || tool.errorCode === undefined)
|
|
256
254
|
continue;
|
|
257
|
-
|
|
258
|
-
for (const
|
|
259
|
-
if (
|
|
255
|
+
const code = ERROR_CODES.has(tool.errorCode) ? tool.errorCode : 'other';
|
|
256
|
+
for (const counted of stepsOfCall(tool, harness)) {
|
|
257
|
+
if (counted.status !== 'error')
|
|
260
258
|
continue;
|
|
261
|
-
|
|
262
|
-
for (const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
const
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
tally
|
|
270
|
-
tally.
|
|
271
|
-
tally.
|
|
259
|
+
// The call's name at both levels: its action alone, and a named call (a flag or a pull would be a second dimension, so those steps are named by program and subcommand alone upstream).
|
|
260
|
+
for (const { motif: named } of motifsOf([counted])) {
|
|
261
|
+
if (named.level === 'named' && counted.identity === null)
|
|
262
|
+
continue;
|
|
263
|
+
const name = motifName(named);
|
|
264
|
+
for (const [prefix, bucket] of [[ERROR_CLASS, `${frame.harness}/${NO_AXES}/${frame.model ?? UNKNOWN}`], [ERROR_VERSION_CLASS, versionBucketOf(frame)]]) {
|
|
265
|
+
const motif = classMotif(`${prefix}${code}/${name}`);
|
|
266
|
+
motifs.set(motif.motifId, motif);
|
|
267
|
+
const tally = tallyAt(motif, bucket, 'day', failedDay, 'unknown');
|
|
268
|
+
tally.sessions.add(first.parent);
|
|
269
|
+
tally.failed += 1;
|
|
270
|
+
if (counted.tokens !== null) {
|
|
271
|
+
tally.tokens += counted.tokens;
|
|
272
|
+
tally.recorded.add(first.parent);
|
|
273
|
+
tally.recordedUnits += 1;
|
|
274
|
+
}
|
|
275
|
+
tally.durationMs += counted.durationMs;
|
|
272
276
|
}
|
|
273
|
-
tally.durationMs += counted.durationMs;
|
|
274
277
|
}
|
|
275
278
|
}
|
|
276
279
|
}
|
|
277
280
|
}
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
281
|
+
for (const prompt of store.prompts) {
|
|
282
|
+
const session = sessions.get(prompt.session);
|
|
283
|
+
const frame = framedPrompt(prompt, harnessOf(session ?? {}), session?.env.harness ?? null, null, session?.env.os ?? UNKNOWN);
|
|
284
|
+
const exposure = exposureOf(graph.exposedPrompt(prompt.session, prompt.index), statesExposure(graph) && graph.heldPrompt(prompt.session, prompt.index));
|
|
285
|
+
const effort = frame.effort === null ? [] : talliesOf(classMotif(effortClass(frame.effort, prompt.usage.thinking)), frame, exposure, NO_AXES);
|
|
286
|
+
for (const tally of [...talliesOf(classMotif(prompt.cls), frame, exposure), ...effort]) {
|
|
287
|
+
tally.sessions.add(prompt.session);
|
|
288
|
+
if (prompt.errors > 0)
|
|
289
|
+
tally.failed += 1;
|
|
290
|
+
else
|
|
291
|
+
tally.ok += 1;
|
|
292
|
+
// A prompt that recorded no input has no whole usage to count, and a category it never recorded is a placeholder zero, so neither enters the sum.
|
|
293
|
+
if (observesUsage(prompt, 'input')) {
|
|
294
|
+
tally.recorded.add(prompt.session);
|
|
295
|
+
tally.recordedUnits += 1;
|
|
296
|
+
for (const field of TOKEN_FIELDS)
|
|
297
|
+
if (observesUsage(prompt, field))
|
|
298
|
+
tally.tokens += prompt.usage[field];
|
|
299
|
+
}
|
|
300
|
+
tally.durationMs += (prompt.wallSec ?? 0) * 1000;
|
|
297
301
|
}
|
|
298
|
-
tally.durationMs += (prompt.wallSec ?? 0) * 1000;
|
|
299
302
|
}
|
|
300
|
-
}
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
303
|
+
};
|
|
304
|
+
const finish = () => {
|
|
305
|
+
const stated = statesExposure(graph);
|
|
306
|
+
const cells = [...tallies.values()]
|
|
307
|
+
.sort((a, b) => compare(a.motifId, b.motifId) || compare(a.frameBucket, b.frameBucket) || compare(a.grain, b.grain) || compare(a.day, b.day) || EXPOSURE_CODES[a.exposure] - EXPOSURE_CODES[b.exposure])
|
|
308
|
+
.map((tally) => ({ motifId: tally.motifId, frameBucket: tally.frameBucket, grain: tally.grain, day: tally.day, sessions: tally.sessions.size, clusters: ONE_OPERATOR, ok: tally.ok, failed: tally.failed, tokens: tally.recorded.size === 0 ? null : tally.tokens, tokenSessions: tally.recorded.size, tokenPrompts: tally.recordedUnits, durationMs: tally.durationMs, exposed: tally.exposure === 'shown', ...(stated ? { exposure: tally.exposure } : {}) }));
|
|
309
|
+
return { cells, motifs: [...motifs.values()].sort((a, b) => compare(a.motifId, b.motifId)) };
|
|
310
|
+
};
|
|
311
|
+
return { add, finish };
|
|
312
|
+
};
|
|
313
|
+
export const deriveCells = (store, graph = NO_RECALLS) => {
|
|
314
|
+
const fold = cellFold(graph);
|
|
315
|
+
fold.add(store);
|
|
316
|
+
return fold.finish();
|
|
306
317
|
};
|
|
307
318
|
export const serializeCells = (cells) => cells.map((cell) => `${JSON.stringify(cell)}\n`).join('');
|
|
308
319
|
/** The fields of an error row a recovery read depends on, as text: only those, so a change elsewhere is not a new pool, and sorted, so record order is not one either. */
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** The crew number held for `account` on `server`, or undefined: no file, another pool or account, a file that is not ours, or an account that is not in the crew. */
|
|
2
|
+
export declare const crewNumberOf: (storeDir: string, server: string, account: string) => Promise<number | undefined>;
|
|
3
|
+
/** Keeps what the pool said, replacing the earlier answer: the number, or none when the account holds none. */
|
|
4
|
+
export declare const keepCrewNumber: (storeDir: string, server: string, account: string, crewNumber: number | undefined) => Promise<void>;
|
|
5
|
+
/** The card's words for a crew number. */
|
|
6
|
+
export declare const crewMarkText: (crewNumber: number) => string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// The founding crew number this machine last learned for a pool (t1229): `GET /v1/me` states it, and `oars pool invite` and `oars pool join` keep it here so the share card, which makes no network call, can show it. A number only; no count of members is ever stored or printed.
|
|
2
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { isObject, numberIn } from './pool-replica.js';
|
|
5
|
+
const fileOf = (storeDir) => join(storeDir, 'pool-crew.json');
|
|
6
|
+
/** The crew number held for `account` on `server`, or undefined: no file, another pool or account, a file that is not ours, or an account that is not in the crew. */
|
|
7
|
+
export const crewNumberOf = async (storeDir, server, account) => {
|
|
8
|
+
try {
|
|
9
|
+
const held = JSON.parse(await readFile(fileOf(storeDir), 'utf8'));
|
|
10
|
+
return isObject(held) && Reflect.get(held, 'server') === server && Reflect.get(held, 'account') === account ? numberIn(held, 'crewNumber') : undefined;
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
/** Keeps what the pool said, replacing the earlier answer: the number, or none when the account holds none. */
|
|
17
|
+
export const keepCrewNumber = async (storeDir, server, account, crewNumber) => {
|
|
18
|
+
await mkdir(storeDir, { recursive: true });
|
|
19
|
+
await writeFile(fileOf(storeDir), JSON.stringify({ server, account, ...(crewNumber === undefined ? {} : { crewNumber }) }));
|
|
20
|
+
};
|
|
21
|
+
/** The card's words for a crew number. */
|
|
22
|
+
export const crewMarkText = (crewNumber) => `founding crew #${String(crewNumber)}`;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Read } from './read.js';
|
|
2
2
|
import type { Position, RecoveryEdges } from './recall-next.js';
|
|
3
3
|
import type { NextByFrame } from './recall-frames.js';
|
|
4
|
+
import type { ReadFolds } from './read-folds.js';
|
|
4
5
|
import { type RecallRead } from './recall-reads.js';
|
|
5
6
|
import { type Store } from './store.js';
|
|
6
7
|
/** A signature is "recurring" once it has been seen in this many sessions. */
|
|
@@ -47,7 +48,7 @@ export interface HookIndex {
|
|
|
47
48
|
[frame: string]: Position[];
|
|
48
49
|
};
|
|
49
50
|
}
|
|
50
|
-
export declare const buildIndex: (store: Store, redactDomains: readonly string[], at: string, reads?: readonly Read[], next?: NextByFrame) => HookIndex;
|
|
51
|
+
export declare const buildIndex: (store: Store, redactDomains: readonly string[], at: string, reads?: readonly Read[], next?: NextByFrame, folds?: ReadFolds) => HookIndex;
|
|
51
52
|
export declare const indexPath: (storeDir: string) => string;
|
|
52
53
|
/** The index as written, or undefined when there is none (or it is torn): a hook then says nothing. */
|
|
53
54
|
export declare const readIndex: (storeDir: string) => Promise<HookIndex | undefined>;
|
|
@@ -33,7 +33,7 @@ const repositoryOf = (projects) => {
|
|
|
33
33
|
return bases.find((candidate) => base === candidate || base.startsWith(`${candidate}-`)) ?? base;
|
|
34
34
|
};
|
|
35
35
|
};
|
|
36
|
-
export const buildIndex = (store, redactDomains, at, reads = [], next) => {
|
|
36
|
+
export const buildIndex = (store, redactDomains, at, reads = [], next, folds) => {
|
|
37
37
|
const projectOf = new Map(store.sessions.map((session) => [session.session, session.project]));
|
|
38
38
|
// The latest 300 of each repository, not of the whole store: another repository's deposits must not move this one's ranking.
|
|
39
39
|
const family = repositoryOf([...new Set(store.sessions.map((session) => session.project))]);
|
|
@@ -92,7 +92,7 @@ export const buildIndex = (store, redactDomains, at, reads = [], next) => {
|
|
|
92
92
|
redactDomains: [...redactDomains],
|
|
93
93
|
projects,
|
|
94
94
|
signatures,
|
|
95
|
-
fit: Object.fromEntries(resolveReads(aboveBaseRate(store, fitReads(store, PUSH_FLOORS)), reads).map((read) => [toolShapeId(read.tool, read.keys), read])),
|
|
95
|
+
fit: Object.fromEntries(resolveReads(folds?.push ?? aboveBaseRate(store, fitReads(store, PUSH_FLOORS)), reads).map((read) => [toolShapeId(read.tool, read.keys), read])),
|
|
96
96
|
...(next === undefined ? {} : { recoveryByFrame: next.recovery, positionsByFrame: next.positions }),
|
|
97
97
|
};
|
|
98
98
|
};
|
|
@@ -70,6 +70,7 @@ export declare const poolLogin: (deps: RunDeps, options: {
|
|
|
70
70
|
server?: string | undefined;
|
|
71
71
|
provider?: string | undefined;
|
|
72
72
|
verbose?: boolean;
|
|
73
|
+
signal?: AbortSignal;
|
|
73
74
|
}) => Promise<Outcome>;
|
|
74
75
|
/**
|
|
75
76
|
* `oars pool logout` (S8): revokes this machine's credential at the pool (`DELETE /v1/login`), then removes the local entry. A pool that cannot be reached does not keep the entry: the person asked to be signed out here, so the entry
|
|
@@ -117,6 +118,9 @@ export interface SendLock {
|
|
|
117
118
|
times: Partial<LockTimes>;
|
|
118
119
|
fs: LockFs;
|
|
119
120
|
}
|
|
121
|
+
/** What `--send-all` does with the pool's busy answers: a 429 or a 5xx is asked again, up to `SEND_ATTEMPTS` in all, after the wait the pool names in `retry-after` (seconds, at most 30) or else 1 second, then 2. Any other answer, and a request that never got one, goes up unchanged. A batch or a part sent again is harmless, so the retry covers every request alike. */
|
|
122
|
+
export type Pause = (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
123
|
+
export declare const sleeps: Pause;
|
|
120
124
|
/**
|
|
121
125
|
* How long the pool gets to answer one request of a send (an interactive `--send` and the background sender) before the send ends. It is a deadline for the whole request, the upload and the answer together,
|
|
122
126
|
* not an idle timeout: a batch is one session's skeleton, whose largest fixture is 887 KB (docs/pool.md), which a link of 240 kbit/s or better uploads inside 30 seconds. A slower link fails each try with the stall
|
|
@@ -131,6 +135,15 @@ export declare const waitingLine: ({ holder, ageMs, waitMs }: Waiting) => string
|
|
|
131
135
|
* retry is certain once the lock has gone untouched for staleMs.
|
|
132
136
|
*/
|
|
133
137
|
export declare const busyLine: ({ holder, local, ageMs, untouchedMs, waitedMs, staleMs }: BusyDetail) => string;
|
|
138
|
+
/**
|
|
139
|
+
* `oars pool remove <hash>`: takes one batch out of this machine's outbox, the batch `oars pool outbox` printed under that hash. It takes the send lock without waiting, because a send in progress may be reading the very file, and refuses while another run holds it.
|
|
140
|
+
* It reads nothing from the pool and sends nothing, so it needs no sign-in, and it changes only files here. The session of a local batch goes on `removed.json`, which `poolDeposit` (and so the background sender) honors: nothing of it is built, queued, or sent until `--restore <hash>` takes it off. One a cloud session held is admitted again only by `oars pool hold pull`.
|
|
141
|
+
*/
|
|
142
|
+
export declare const poolRemove: (deps: RunDeps, hash: string, options: {
|
|
143
|
+
server?: string | undefined;
|
|
144
|
+
restore?: boolean | undefined;
|
|
145
|
+
lock?: SendLock | undefined;
|
|
146
|
+
}) => Promise<Outcome>;
|
|
134
147
|
/** The outbox key, and the skeleton `id`, of a machine's session: from the environment's session salt (per account, not per machine), else its own name standing in for the account, which a machine has none of. The holding route names its branch by the same key. */
|
|
135
148
|
export declare const machineKeyOf: (machine: MachineConfig, session: string) => string;
|
|
136
149
|
/**
|
|
@@ -143,16 +156,22 @@ export declare const poolDeposit: (deps: RunDeps, options: {
|
|
|
143
156
|
acceptCovenant?: string | undefined;
|
|
144
157
|
inEuEeaUk?: string | undefined;
|
|
145
158
|
send?: string | undefined;
|
|
159
|
+
sendAll?: boolean | undefined;
|
|
160
|
+
pause?: Pause | undefined;
|
|
146
161
|
via?: Sender | undefined;
|
|
147
162
|
git?: Git | undefined;
|
|
148
163
|
session?: string | undefined;
|
|
149
164
|
covenant?: string | undefined;
|
|
150
165
|
lock?: SendLock | undefined;
|
|
151
166
|
}) => Promise<Outcome>;
|
|
152
|
-
/**
|
|
167
|
+
/**
|
|
168
|
+
* `oars pool outbox`: prints each batch as it would be sent (a batch past one request prints each part's request, in order), the request line and every header included, with the bearer credential as its size and nothing else masked, then its SHA-256, and records that it was shown. `--explain` adds each field's rule.
|
|
169
|
+
* With `print` each batch is written as soon as it is built and marked shown right after, and the outcome carries no text: an outbox of thousands of sessions is far past V8's string length as one string. Without it (`--json`) the document carries each batch's request, and `--json` writes it element by element.
|
|
170
|
+
*/
|
|
153
171
|
export declare const poolOutbox: (deps: RunDeps, options: {
|
|
154
172
|
server?: string | undefined;
|
|
155
173
|
explain?: boolean | undefined;
|
|
174
|
+
print?: ((chunk: string) => void) | undefined;
|
|
156
175
|
}) => Promise<Outcome>;
|
|
157
176
|
/** `oars pool fetch`: one harness's signed bundle at one version, kept only once the key pinned at login has verified it. It keeps the signed form, so the replica can be checked again later, and the ETag, so the next fetch asks only whether it changed. The request prints before it is sent. */
|
|
158
177
|
export declare const poolFetch: (deps: RunDeps, options: {
|
|
@@ -160,6 +179,33 @@ export declare const poolFetch: (deps: RunDeps, options: {
|
|
|
160
179
|
harness?: string | undefined;
|
|
161
180
|
harnessVersion: string;
|
|
162
181
|
}) => Promise<Outcome>;
|
|
182
|
+
/**
|
|
183
|
+
* `oars pool join`: the first deposit in one run, each step by the handler its own command uses: sign-in (`login`), the region question, the exclusion term file (scaffolded empty, never filled in), the batch (`deposit`), what it holds (`outbox
|
|
184
|
+
* --explain`), the covenant (the screen and typed phrase `deposit --send` shows), and the send (`deposit --send <hash>` for each batch not yet sent), then `fetch` when a harness version is named. A step that stops ends the run with its own
|
|
185
|
+
* error. Run again, each step that stands is skipped: a held sign-in, terms in the file, a prepared batch, an accepted covenant, a batch in `sent.log`. Acceptance is the person's own: this never types the phrase, and off a terminal it stops.
|
|
186
|
+
* Each step's text prints as it finishes, so the explanation is on screen before the send asks anything: on stdout, or with `json` on stderr, so stdout holds the one document. One `join-step` event per step says which of the closed steps ran and
|
|
187
|
+
* what it did (done, skipped, or stopped), and nothing else.
|
|
188
|
+
*/
|
|
189
|
+
export declare const poolJoin: (deps: RunDeps, options: {
|
|
190
|
+
server?: string | undefined;
|
|
191
|
+
provider?: string | undefined;
|
|
192
|
+
verbose?: boolean;
|
|
193
|
+
acceptCovenant?: string | undefined;
|
|
194
|
+
inEuEeaUk?: string | undefined;
|
|
195
|
+
harness?: string | undefined;
|
|
196
|
+
harnessVersion?: string | undefined;
|
|
197
|
+
invite?: string | undefined;
|
|
198
|
+
json?: boolean;
|
|
199
|
+
plan?: boolean;
|
|
200
|
+
}) => Promise<Outcome>;
|
|
201
|
+
/** The one line an invitee runs. `<version>` stays a placeholder: the harness version is the invitee's own to name. */
|
|
202
|
+
export declare const joinLineOf: (code: string) => string;
|
|
203
|
+
/**
|
|
204
|
+
* `oars pool invite`: makes one invite code (`POST /v1/invites`, a founding or standing account, three open at most) and prints it once with the line to hand on and what the vouch gives. The code is the only secret here, so it is the one thing the pool never shows again.
|
|
205
|
+
*/
|
|
206
|
+
export declare const poolInvite: (deps: RunDeps, options: {
|
|
207
|
+
server?: string | undefined;
|
|
208
|
+
}) => Promise<Outcome>;
|
|
163
209
|
/** The raw prompt, in plain words: shown by `oars pool raw` until it is answered, and what the detached sender relies on. Redaction is best effort and the text says so. */
|
|
164
210
|
export declare const RAW_PROMPT: string;
|
|
165
211
|
/** What a person types to say yes to the raw prompt: consent is a statement made at a terminal (GDPR Articles 7 and 9(2)(a)), not a flag a script can pass. */
|