@manyoars/oars 0.2.0 → 0.4.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/README.md +147 -28
- package/dist/api.js +1 -1
- package/dist/bin.js +6 -29
- package/dist/cli.d.ts +10 -4
- package/dist/cli.js +440 -91
- package/dist/commands/keys.d.ts +31 -0
- package/dist/commands/keys.js +65 -0
- package/dist/commands/login.d.ts +1 -1
- package/dist/commands/login.js +3 -3
- package/dist/errors.d.ts +13 -13
- package/dist/errors.js +28 -11
- package/dist/gate/checks.d.ts +68 -0
- package/dist/gate/checks.js +584 -0
- package/dist/gate/command.d.ts +14 -0
- package/dist/gate/command.js +61 -0
- package/dist/gate/hook-fill-main.d.ts +1 -0
- package/dist/gate/hook-fill-main.js +16 -0
- package/dist/gate/hook-fill.d.ts +38 -0
- package/dist/gate/hook-fill.js +94 -0
- package/dist/gate/hook-main.d.ts +1 -0
- package/dist/gate/hook-main.js +47 -0
- package/dist/gate/hook-process.d.ts +24 -0
- package/dist/gate/hook-process.js +112 -0
- package/dist/gate/hook-record.d.ts +3 -0
- package/dist/gate/hook-record.js +8 -0
- package/dist/gate/hook.d.ts +48 -0
- package/dist/gate/hook.js +259 -0
- package/dist/gate/install.d.ts +25 -0
- package/dist/gate/install.js +126 -0
- package/dist/gate/local-bin.d.ts +8 -0
- package/dist/gate/local-bin.js +36 -0
- package/dist/gate/notes.d.ts +19 -0
- package/dist/gate/notes.js +27 -0
- package/dist/gate/novelty.d.ts +35 -0
- package/dist/gate/novelty.js +99 -0
- package/dist/gate/policy.d.ts +25 -0
- package/dist/gate/policy.js +73 -0
- package/dist/gate/record.d.ts +120 -0
- package/dist/gate/record.js +125 -0
- package/dist/gate/registry-state.d.ts +10 -0
- package/dist/gate/registry-state.js +30 -0
- package/dist/gate/registry.d.ts +56 -0
- package/dist/gate/registry.js +94 -0
- package/dist/gate/replay.d.ts +20 -0
- package/dist/gate/replay.js +254 -0
- package/dist/gate/report.d.ts +50 -0
- package/dist/gate/report.js +89 -0
- package/dist/gate/scope.d.ts +7 -0
- package/dist/gate/scope.js +27 -0
- package/dist/gate/transcripts.d.ts +68 -0
- package/dist/gate/transcripts.js +232 -0
- package/dist/hook-bin.d.ts +1 -0
- package/dist/hook-bin.js +50 -0
- package/dist/issuer.d.ts +10 -6
- package/dist/issuer.js +19 -24
- package/dist/main.d.ts +1 -0
- package/dist/main.js +67 -0
- package/dist/oidc.js +1 -1
- package/dist/sessions/actions.d.ts +35 -0
- package/dist/sessions/actions.js +429 -0
- package/dist/sessions/allow.d.ts +23 -0
- package/dist/sessions/allow.js +71 -0
- package/dist/sessions/archive.d.ts +11 -0
- package/dist/sessions/archive.js +38 -0
- package/dist/sessions/audit.d.ts +42 -0
- package/dist/sessions/audit.js +104 -0
- package/dist/sessions/baseline.d.ts +62 -0
- package/dist/sessions/baseline.js +190 -0
- package/dist/sessions/call-shape.d.ts +19 -0
- package/dist/sessions/call-shape.js +85 -0
- package/dist/sessions/capture-runtime.d.ts +10 -0
- package/dist/sessions/capture-runtime.js +12 -0
- package/dist/sessions/cell-increments.d.ts +47 -0
- package/dist/sessions/cell-increments.js +243 -0
- package/dist/sessions/cells.d.ts +109 -0
- package/dist/sessions/cells.js +261 -0
- package/dist/sessions/codex.d.ts +53 -0
- package/dist/sessions/codex.js +745 -0
- package/dist/sessions/command.d.ts +127 -0
- package/dist/sessions/command.js +419 -0
- package/dist/sessions/copilot.d.ts +40 -0
- package/dist/sessions/copilot.js +432 -0
- package/dist/sessions/coverage.d.ts +19 -0
- package/dist/sessions/coverage.js +56 -0
- package/dist/sessions/cursor.d.ts +24 -0
- package/dist/sessions/cursor.js +324 -0
- package/dist/sessions/derive.d.ts +57 -0
- package/dist/sessions/derive.js +386 -0
- package/dist/sessions/exclusion.d.ts +87 -0
- package/dist/sessions/exclusion.js +361 -0
- package/dist/sessions/extract.d.ts +181 -0
- package/dist/sessions/extract.js +1806 -0
- package/dist/sessions/fold.d.ts +17 -0
- package/dist/sessions/fold.js +71 -0
- package/dist/sessions/frame.d.ts +24 -0
- package/dist/sessions/frame.js +95 -0
- package/dist/sessions/gemini.d.ts +37 -0
- package/dist/sessions/gemini.js +613 -0
- package/dist/sessions/gold-arms.d.ts +67 -0
- package/dist/sessions/gold-arms.js +172 -0
- package/dist/sessions/gold.d.ts +197 -0
- package/dist/sessions/gold.js +463 -0
- package/dist/sessions/graph.d.ts +12 -0
- package/dist/sessions/graph.js +34 -0
- package/dist/sessions/grok.d.ts +36 -0
- package/dist/sessions/grok.js +421 -0
- package/dist/sessions/hook-calls.d.ts +3 -0
- package/dist/sessions/hook-calls.js +47 -0
- package/dist/sessions/hook-index.d.ts +66 -0
- package/dist/sessions/hook-index.js +164 -0
- package/dist/sessions/hooks.d.ts +17 -0
- package/dist/sessions/hooks.js +281 -0
- package/dist/sessions/identity.d.ts +27 -0
- package/dist/sessions/identity.js +131 -0
- package/dist/sessions/install.d.ts +70 -0
- package/dist/sessions/install.js +246 -0
- package/dist/sessions/lineage.d.ts +19 -0
- package/dist/sessions/lineage.js +118 -0
- package/dist/sessions/mcp.d.ts +7 -0
- package/dist/sessions/mcp.js +157 -0
- package/dist/sessions/merkle.d.ts +7 -0
- package/dist/sessions/merkle.js +28 -0
- package/dist/sessions/motif.d.ts +44 -0
- package/dist/sessions/motif.js +59 -0
- package/dist/sessions/opencode.d.ts +33 -0
- package/dist/sessions/opencode.js +319 -0
- package/dist/sessions/otel.d.ts +60 -0
- package/dist/sessions/otel.js +494 -0
- package/dist/sessions/package-books.d.ts +48 -0
- package/dist/sessions/package-books.js +120 -0
- package/dist/sessions/package-resolve.d.ts +32 -0
- package/dist/sessions/package-resolve.js +185 -0
- package/dist/sessions/pending.d.ts +34 -0
- package/dist/sessions/pending.js +142 -0
- package/dist/sessions/pi.d.ts +36 -0
- package/dist/sessions/pi.js +353 -0
- package/dist/sessions/pool-books.d.ts +21 -0
- package/dist/sessions/pool-books.js +75 -0
- package/dist/sessions/pool-choices.d.ts +5 -0
- package/dist/sessions/pool-choices.js +11 -0
- package/dist/sessions/pool-command.d.ts +115 -0
- package/dist/sessions/pool-command.js +669 -0
- package/dist/sessions/pool-delta.d.ts +54 -0
- package/dist/sessions/pool-delta.js +190 -0
- package/dist/sessions/pool-nightly-deps.d.ts +3 -0
- package/dist/sessions/pool-nightly-deps.js +11 -0
- package/dist/sessions/pool-nightly.d.ts +10 -0
- package/dist/sessions/pool-nightly.js +85 -0
- package/dist/sessions/pool-outbox.d.ts +76 -0
- package/dist/sessions/pool-outbox.js +313 -0
- package/dist/sessions/pool-print.d.ts +26 -0
- package/dist/sessions/pool-print.js +68 -0
- package/dist/sessions/pool-raw.d.ts +27 -0
- package/dist/sessions/pool-raw.js +68 -0
- package/dist/sessions/pool-replica.d.ts +35 -0
- package/dist/sessions/pool-replica.js +91 -0
- package/dist/sessions/pool-send-lock.d.ts +20 -0
- package/dist/sessions/pool-send-lock.js +87 -0
- package/dist/sessions/pool-sent.d.ts +4 -0
- package/dist/sessions/pool-sent.js +26 -0
- package/dist/sessions/pool-totals.d.ts +10 -0
- package/dist/sessions/pool-totals.js +21 -0
- package/dist/sessions/pool-wire.d.ts +435 -0
- package/dist/sessions/pool-wire.js +1100 -0
- package/dist/sessions/pool.d.ts +32 -0
- package/dist/sessions/pool.js +164 -0
- package/dist/sessions/projection.d.ts +75 -0
- package/dist/sessions/projection.js +165 -0
- package/dist/sessions/public-vocabulary.d.ts +72 -0
- package/dist/sessions/public-vocabulary.js +295 -0
- package/dist/sessions/query.d.ts +123 -0
- package/dist/sessions/query.js +268 -0
- package/dist/sessions/read-adoption.d.ts +2 -0
- package/dist/sessions/read-adoption.js +27 -0
- package/dist/sessions/read-call-shape.d.ts +2 -0
- package/dist/sessions/read-call-shape.js +25 -0
- package/dist/sessions/read-change.d.ts +2 -0
- package/dist/sessions/read-change.js +30 -0
- package/dist/sessions/read-cost.d.ts +4 -0
- package/dist/sessions/read-cost.js +48 -0
- package/dist/sessions/read-day-move.d.ts +3 -0
- package/dist/sessions/read-day-move.js +65 -0
- package/dist/sessions/read-fit.d.ts +7 -0
- package/dist/sessions/read-fit.js +41 -0
- package/dist/sessions/read-interaction.d.ts +5 -0
- package/dist/sessions/read-interaction.js +62 -0
- package/dist/sessions/read-lead-lag.d.ts +15 -0
- package/dist/sessions/read-lead-lag.js +81 -0
- package/dist/sessions/read-live.d.ts +6 -0
- package/dist/sessions/read-live.js +38 -0
- package/dist/sessions/read-method.d.ts +2 -0
- package/dist/sessions/read-method.js +29 -0
- package/dist/sessions/read-next-step.d.ts +2 -0
- package/dist/sessions/read-next-step.js +35 -0
- package/dist/sessions/read-order.d.ts +54 -0
- package/dist/sessions/read-order.js +62 -0
- package/dist/sessions/read-readable.d.ts +8 -0
- package/dist/sessions/read-readable.js +24 -0
- package/dist/sessions/read-recovery-edge.d.ts +2 -0
- package/dist/sessions/read-recovery-edge.js +26 -0
- package/dist/sessions/read-recovery.d.ts +20 -0
- package/dist/sessions/read-recovery.js +97 -0
- package/dist/sessions/read-rows.d.ts +13 -0
- package/dist/sessions/read-rows.js +47 -0
- package/dist/sessions/read-substitution.d.ts +5 -0
- package/dist/sessions/read-substitution.js +51 -0
- package/dist/sessions/read-support.d.ts +48 -0
- package/dist/sessions/read-support.js +73 -0
- package/dist/sessions/read-tool-day.d.ts +2 -0
- package/dist/sessions/read-tool-day.js +26 -0
- package/dist/sessions/read-version-boundary.d.ts +31 -0
- package/dist/sessions/read-version-boundary.js +95 -0
- package/dist/sessions/read.d.ts +86 -0
- package/dist/sessions/read.js +87 -0
- package/dist/sessions/recall-bundle.d.ts +12 -0
- package/dist/sessions/recall-bundle.js +33 -0
- package/dist/sessions/recall-consequence.d.ts +45 -0
- package/dist/sessions/recall-consequence.js +179 -0
- package/dist/sessions/recall-frames.d.ts +18 -0
- package/dist/sessions/recall-frames.js +44 -0
- package/dist/sessions/recall-next.d.ts +145 -0
- package/dist/sessions/recall-next.js +241 -0
- package/dist/sessions/recall-object.d.ts +139 -0
- package/dist/sessions/recall-object.js +78 -0
- package/dist/sessions/recall-pool.d.ts +19 -0
- package/dist/sessions/recall-pool.js +96 -0
- package/dist/sessions/recall-push.d.ts +26 -0
- package/dist/sessions/recall-push.js +47 -0
- package/dist/sessions/recall-reads.d.ts +124 -0
- package/dist/sessions/recall-reads.js +417 -0
- package/dist/sessions/recall-render.d.ts +19 -0
- package/dist/sessions/recall-render.js +168 -0
- package/dist/sessions/recovery-calls.d.ts +21 -0
- package/dist/sessions/recovery-calls.js +25 -0
- package/dist/sessions/redact.d.ts +17 -0
- package/dist/sessions/redact.js +113 -0
- package/dist/sessions/repo-root.d.ts +10 -0
- package/dist/sessions/repo-root.js +101 -0
- package/dist/sessions/schema.d.ts +694 -0
- package/dist/sessions/schema.js +167 -0
- package/dist/sessions/session-shape.d.ts +76 -0
- package/dist/sessions/session-shape.js +355 -0
- package/dist/sessions/sources.d.ts +50 -0
- package/dist/sessions/sources.js +233 -0
- package/dist/sessions/steps.d.ts +105 -0
- package/dist/sessions/steps.js +250 -0
- package/dist/sessions/store.d.ts +309 -0
- package/dist/sessions/store.js +1498 -0
- package/dist/sessions/strata.d.ts +26 -0
- package/dist/sessions/strata.js +77 -0
- package/dist/sessions/survival.d.ts +27 -0
- package/dist/sessions/survival.js +230 -0
- package/dist/sessions/transcript-tail.d.ts +14 -0
- package/dist/sessions/transcript-tail.js +64 -0
- package/dist/sessions/verify.d.ts +53 -0
- package/dist/sessions/verify.js +286 -0
- package/dist/sessions/vocab-load.d.ts +26 -0
- package/dist/sessions/vocab-load.js +61 -0
- package/dist/sessions/vscode-copilot.d.ts +38 -0
- package/dist/sessions/vscode-copilot.js +494 -0
- package/dist/telemetry/command.d.ts +8 -0
- package/dist/telemetry/command.js +85 -0
- package/dist/telemetry/consent.d.ts +17 -0
- package/dist/telemetry/consent.js +63 -0
- package/dist/telemetry/crash.d.ts +8 -0
- package/dist/telemetry/crash.js +52 -0
- package/dist/telemetry/emit.d.ts +31 -0
- package/dist/telemetry/emit.js +42 -0
- package/dist/telemetry/fields.d.ts +16 -0
- package/dist/telemetry/fields.js +26 -0
- package/dist/telemetry/health.d.ts +21 -0
- package/dist/telemetry/health.js +108 -0
- package/dist/telemetry/hook-emit.d.ts +4 -0
- package/dist/telemetry/hook-emit.js +18 -0
- package/dist/telemetry/measures.d.ts +32 -0
- package/dist/telemetry/measures.js +128 -0
- package/dist/telemetry/observe.d.ts +13 -0
- package/dist/telemetry/observe.js +51 -0
- package/dist/telemetry/read-events.d.ts +9 -0
- package/dist/telemetry/read-events.js +17 -0
- package/dist/telemetry/record.d.ts +17 -0
- package/dist/telemetry/record.js +26 -0
- package/dist/telemetry/report.d.ts +77 -0
- package/dist/telemetry/report.js +188 -0
- package/dist/telemetry/schema.d.ts +40 -0
- package/dist/telemetry/schema.js +187 -0
- package/dist/telemetry/send-main.d.ts +1 -0
- package/dist/telemetry/send-main.js +11 -0
- package/dist/telemetry/send.d.ts +36 -0
- package/dist/telemetry/send.js +172 -0
- package/dist/telemetry/spool.d.ts +17 -0
- package/dist/telemetry/spool.js +70 -0
- package/dist/telemetry/wire.d.ts +25 -0
- package/dist/telemetry/wire.js +76 -0
- package/package.json +4 -5
- package/vocab/crates.json +1 -0
- package/vocab/go.json +1 -0
- package/vocab/harness.json +1 -0
- package/vocab/homebrew.json +1 -0
- package/vocab/manifest.json +1 -0
- package/vocab/maven.json +1 -0
- package/vocab/models.json +1 -0
- package/vocab/npm.json +1 -0
- package/vocab/programs.json +1 -0
- package/vocab/pypi.json +1 -0
- package/vocab/rubygems.json +1 -0
- package/dist/commands/deploy-input.d.ts +0 -38
- package/dist/commands/deploy-input.js +0 -150
- package/dist/commands/deploy.d.ts +0 -22
- package/dist/commands/deploy.js +0 -124
- package/dist/commands/status.d.ts +0 -7
- package/dist/commands/status.js +0 -18
- package/dist/commands/templates.d.ts +0 -11
- package/dist/commands/templates.js +0 -32
- package/dist/commands/test-charge.d.ts +0 -11
- package/dist/commands/test-charge.js +0 -34
- package/dist/journal.d.ts +0 -26
- package/dist/journal.js +0 -58
- package/parity/deploy-plans/paid-api.json +0 -34
- package/parity/deploy-plans/per-task-agent.json +0 -34
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type DeltaEntry, type SessionRecords } from './pool-wire.js';
|
|
2
|
+
/** `delta_days` and `delta_min_sessions` (spec Section 7): a week on each side spans a work cycle, and five sessions keep one session from being the delta. */
|
|
3
|
+
export declare const DELTA_DAYS = 7;
|
|
4
|
+
export declare const DELTA_MIN_SESSIONS = 5;
|
|
5
|
+
/** A session as a window sees it: when it began (epoch milliseconds) and an id that orders two sessions of one instant. */
|
|
6
|
+
export interface Placed {
|
|
7
|
+
id: string;
|
|
8
|
+
at: number;
|
|
9
|
+
}
|
|
10
|
+
/** A before and an after window, each of `DELTA_DAYS`, the after window's place on the grid (its index), and the session that brought the after window to its minimum. */
|
|
11
|
+
export interface Windows<T> {
|
|
12
|
+
index: number;
|
|
13
|
+
before: T[];
|
|
14
|
+
after: T[];
|
|
15
|
+
filler: T;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The pairs of windows a set of sessions holds. Windows are consecutive spans of `days` on a grid counted from the epoch, not from any session, so a session belongs to exactly one window and the grid does
|
|
19
|
+
* not move when a session is added, lost to a gate, or not yet ended: the `index` of a window is the same whenever the deposit runs. A pair is two windows next to each other that each hold at least
|
|
20
|
+
* `min` sessions; a gap of an empty window, or of one with too few, compares nothing across it. The `filler` is the `min`th session of the after window in time order. It chooses which batch carries
|
|
21
|
+
* the delta and can change from one deposit to the next, so nothing that must hold still is keyed on it.
|
|
22
|
+
*/
|
|
23
|
+
export declare const windowsOf: <T extends Placed>(sessions: readonly T[], days?: number, min?: number) => Windows<T>[];
|
|
24
|
+
/**
|
|
25
|
+
* The entries a pair of windows holds, each window in time order (the caller sorts). A plugin is added or removed, a `permissionMode` or `effort` changed by name alone (the most common value of each
|
|
26
|
+
* window differs, a value outside its list read as one word), and a `package` removed. Each entry carries the move of one metric in its field's own buckets: calls per session for a plugin, a permission
|
|
27
|
+
* mode, and a package, thinking per prompt for an effort. A name outside its list is `private`, and everything that is `private` in one field is one entry.
|
|
28
|
+
*/
|
|
29
|
+
export declare const deltasOf: (before: readonly SessionRecords[], after: readonly SessionRecords[]) => DeltaEntry[];
|
|
30
|
+
/**
|
|
31
|
+
* The once-only mark of a delta: a hash of the account, the entry without the size of its move, and the index of its after window on the grid. The move is left out so a recount of the same windows is
|
|
32
|
+
* the same delta, and the index is in so a later pair that shows the same change is a new one. The filler is not in it: which session fills a window moves with the sessions ready, a window's index does not.
|
|
33
|
+
*/
|
|
34
|
+
export declare const deltaMark: (account: string, { deltaKind, field, name, registry, metric }: DeltaEntry, index: number) => string;
|
|
35
|
+
/** The marks of the deltas this outbox has already carried in a written batch. A folder with no log holds none; a log that cannot be read is an error, not an empty one, so a delta is never built twice by mistake. */
|
|
36
|
+
export declare const sentDeltas: (outbox: string) => Promise<Set<string>>;
|
|
37
|
+
/** Marks deltas as sent, one line each. The caller writes this only after the batch that carries them is written, so a deposit that stopped before it builds them again. */
|
|
38
|
+
export declare const markDeltasSent: (outbox: string, marks: readonly string[]) => Promise<void>;
|
|
39
|
+
/** A session that passed the session gates, placed for the windows: its records, when it began, and its id. */
|
|
40
|
+
export interface Gated extends Placed {
|
|
41
|
+
records: SessionRecords;
|
|
42
|
+
}
|
|
43
|
+
/** The session placed by when it began (epoch milliseconds) and its own id; none when it has no start that reads as a time, since no window can hold it. */
|
|
44
|
+
export declare const placedOf: (records: SessionRecords) => Gated | undefined;
|
|
45
|
+
/** What one batch carries: its delta entries and the marks to write once the batch is written. */
|
|
46
|
+
export interface Carried {
|
|
47
|
+
entries: DeltaEntry[];
|
|
48
|
+
marks: string[];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The deltas not yet sent, by the id of the session that filled their after window: that session's batch carries them, and the mark is the window's index, so it holds whichever session fills. A delta whose mark is held is dropped, so a rebuilt session, or a batch written
|
|
52
|
+
* again under the same key, builds none it already carried. Nothing is marked here: the caller marks them once the batch is written.
|
|
53
|
+
*/
|
|
54
|
+
export declare const carriedDeltas: (account: string, sessions: readonly Gated[], sent: ReadonlySet<string>) => Map<string, Carried>;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { appendFile, mkdir, readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { isMissing } from './pool-outbox.js';
|
|
4
|
+
import { contentHash } from './read.js';
|
|
5
|
+
import { bucketOf, PACKAGE_REGISTRIES } from './pool-wire.js';
|
|
6
|
+
import { PRIVATE, PUBLIC_PACKAGES, publicEffort } from './public-vocabulary.js';
|
|
7
|
+
import { harnessOf } from './schema.js';
|
|
8
|
+
// Local deltas (spec Section 2, "Deltas"): the client compares its own before and after windows and builds each change once. Nothing here reads a store or sends a byte; `pool deposit` hands it the
|
|
9
|
+
// sessions that passed the session gates and carries what comes back in the batch of the session that filled the after window.
|
|
10
|
+
/** `delta_days` and `delta_min_sessions` (spec Section 7): a week on each side spans a work cycle, and five sessions keep one session from being the delta. */
|
|
11
|
+
export const DELTA_DAYS = 7;
|
|
12
|
+
export const DELTA_MIN_SESSIONS = 5;
|
|
13
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
14
|
+
/**
|
|
15
|
+
* The pairs of windows a set of sessions holds. Windows are consecutive spans of `days` on a grid counted from the epoch, not from any session, so a session belongs to exactly one window and the grid does
|
|
16
|
+
* not move when a session is added, lost to a gate, or not yet ended: the `index` of a window is the same whenever the deposit runs. A pair is two windows next to each other that each hold at least
|
|
17
|
+
* `min` sessions; a gap of an empty window, or of one with too few, compares nothing across it. The `filler` is the `min`th session of the after window in time order. It chooses which batch carries
|
|
18
|
+
* the delta and can change from one deposit to the next, so nothing that must hold still is keyed on it.
|
|
19
|
+
*/
|
|
20
|
+
export const windowsOf = (sessions, days = DELTA_DAYS, min = DELTA_MIN_SESSIONS) => {
|
|
21
|
+
const ordered = [...sessions].sort((a, b) => a.at - b.at || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
|
|
22
|
+
const span = days * DAY_MS;
|
|
23
|
+
const windows = new Map();
|
|
24
|
+
for (const session of ordered) {
|
|
25
|
+
const index = Math.floor(session.at / span);
|
|
26
|
+
const held = windows.get(index);
|
|
27
|
+
if (held === undefined)
|
|
28
|
+
windows.set(index, [session]);
|
|
29
|
+
else
|
|
30
|
+
held.push(session);
|
|
31
|
+
}
|
|
32
|
+
const pairs = [];
|
|
33
|
+
for (const [index, after] of windows) {
|
|
34
|
+
const before = windows.get(index - 1);
|
|
35
|
+
const filler = after[min - 1];
|
|
36
|
+
if (before !== undefined && before.length >= min && filler !== undefined)
|
|
37
|
+
pairs.push({ index, before, after, filler });
|
|
38
|
+
}
|
|
39
|
+
return pairs;
|
|
40
|
+
};
|
|
41
|
+
const sum = (values) => values.reduce((total, value) => total + value, 0);
|
|
42
|
+
const mean = (values, count) => (count === 0 ? 0 : sum(values) / count);
|
|
43
|
+
/** The signed bucket of a move: the bucket of its size, negative when it fell. Zero stays zero, never negative zero. */
|
|
44
|
+
const signed = (kind, move) => {
|
|
45
|
+
const bucket = bucketOf(kind, Math.abs(move));
|
|
46
|
+
return move < 0 && bucket > 0 ? -bucket : bucket;
|
|
47
|
+
};
|
|
48
|
+
/** The value most sessions hold; the smaller of two that tie, so two runs agree. */
|
|
49
|
+
const modal = (values) => {
|
|
50
|
+
const counts = new Map();
|
|
51
|
+
for (const value of values)
|
|
52
|
+
counts.set(value, (counts.get(value) ?? 0) + 1);
|
|
53
|
+
return [...counts].sort(([a, countA], [b, countB]) => countB - countA || (a < b ? -1 : 1))[0]?.[0];
|
|
54
|
+
};
|
|
55
|
+
const callsOf = (window) => mean(window.map((records) => sum(records.transcripts.map(({ tools }) => tools.length))), window.length);
|
|
56
|
+
const thinkingOf = (window) => {
|
|
57
|
+
const prompts = window.flatMap((records) => records.transcripts.flatMap((transcript) => transcript.prompts));
|
|
58
|
+
return mean(prompts.map(({ usage }) => usage.thinking), prompts.length);
|
|
59
|
+
};
|
|
60
|
+
/** The effort a session ran at: the one most of its main run's prompts held, read through the public list so a value outside it is one word. */
|
|
61
|
+
const effortOf = (records) => modal((records.transcripts[0]?.prompts ?? []).flatMap(({ efforts }) => efforts.flatMap((effort) => publicEffort(effort) ?? [])));
|
|
62
|
+
const entryOf = (name, field, deltaKind, metric, change, registry = null) => ({ deltaKind, field, name, registry, metric, change });
|
|
63
|
+
/** Only Claude Code records `setup.plugins`; another harness holds none because it records none, not because none were loaded, so it says nothing of a plugin. */
|
|
64
|
+
const recordsPlugins = ({ main }) => harnessOf(main) === 'claude-code';
|
|
65
|
+
const pluginsIn = (window) => new Set(window.filter(recordsPlugins).flatMap(({ main }) => main.setup?.plugins ?? []));
|
|
66
|
+
/** A stored `<ecosystem>:<name>` as the wire spells it: the public name and its registry, else the word `private` with no registry. */
|
|
67
|
+
const packageNamed = (stored) => {
|
|
68
|
+
const colon = stored.indexOf(':');
|
|
69
|
+
const registry = PACKAGE_REGISTRIES.find((entry) => entry === stored.slice(0, colon));
|
|
70
|
+
const name = stored.slice(colon + 1);
|
|
71
|
+
return registry !== undefined && PUBLIC_PACKAGES.has(name) ? { name, registry } : { name: PRIVATE, registry: null };
|
|
72
|
+
};
|
|
73
|
+
/** The manifests a window's calls showed, in the order they ran. A call that did not come back clean shows none. */
|
|
74
|
+
const manifestsIn = (window) => window.flatMap((records) => records.transcripts.flatMap(({ tools }) => [...tools].sort((a, b) => a.n - b.n).flatMap(({ manifest, status, target, tool }) => (manifest === undefined || status !== 'ok' ? [] : [{ tool, target, seen: manifest.seen, added: manifest.added, removed: manifest.removed }]))));
|
|
75
|
+
/**
|
|
76
|
+
* Whether the manifests of the after window leave a package gone. An edit that removes it, or a Write that lists a file that held it in the before window and no longer does, says gone; a later edit that
|
|
77
|
+
* adds it back, or any listing that holds it, says it stayed. A Read says nothing of what is missing, since it may have shown part of the file (an `offset` or a `limit`), and a listing of any other
|
|
78
|
+
* file says nothing, since one repository's manifest is not another's.
|
|
79
|
+
*/
|
|
80
|
+
const goneFrom = (stored, before, after) => {
|
|
81
|
+
const held = new Set(before.flatMap(({ target, seen }) => (target !== null && seen.includes(stored) ? [target] : [])));
|
|
82
|
+
let gone = false;
|
|
83
|
+
for (const { tool, target, seen, added, removed } of after) {
|
|
84
|
+
if (removed.includes(stored))
|
|
85
|
+
gone = true;
|
|
86
|
+
else if (added.includes(stored) || seen.includes(stored))
|
|
87
|
+
gone = false;
|
|
88
|
+
else if (tool === 'Write' && seen.length > 0 && target !== null && held.has(target))
|
|
89
|
+
gone = true;
|
|
90
|
+
}
|
|
91
|
+
return gone;
|
|
92
|
+
};
|
|
93
|
+
/** A package's calls per session: tool calls of the window that install or run it. */
|
|
94
|
+
const callsNaming = (window, stored) => mean(window.map((records) => sum(records.transcripts.map(({ tools }) => tools.filter(({ packages }) => packages?.some(({ package: held }) => held === stored) === true).length))), window.length);
|
|
95
|
+
const packagesCalledIn = (window) => [...new Set(window.flatMap((records) => records.transcripts.flatMap(({ tools }) => tools.flatMap(({ packages }) => (packages ?? []).map(({ package: held }) => held)))))].sort();
|
|
96
|
+
const order = (a, b) => {
|
|
97
|
+
const key = (entry) => [entry.field, entry.deltaKind, entry.name ?? '', entry.registry ?? ''].join(' ');
|
|
98
|
+
return key(a) < key(b) ? -1 : key(a) > key(b) ? 1 : 0;
|
|
99
|
+
};
|
|
100
|
+
/**
|
|
101
|
+
* The entries a pair of windows holds, each window in time order (the caller sorts). A plugin is added or removed, a `permissionMode` or `effort` changed by name alone (the most common value of each
|
|
102
|
+
* window differs, a value outside its list read as one word), and a `package` removed. Each entry carries the move of one metric in its field's own buckets: calls per session for a plugin, a permission
|
|
103
|
+
* mode, and a package, thinking per prompt for an effort. A name outside its list is `private`, and everything that is `private` in one field is one entry.
|
|
104
|
+
*/
|
|
105
|
+
export const deltasOf = (before, after) => {
|
|
106
|
+
const calls = signed('count', callsOf(after) - callsOf(before));
|
|
107
|
+
const entries = [];
|
|
108
|
+
// No plugin registry is pinned, so a plugin's name never passes its row: it goes as the word `private`. Plugins are compared only when both windows hold a session that records them.
|
|
109
|
+
if (before.some(recordsPlugins) && after.some(recordsPlugins)) {
|
|
110
|
+
const pluginsBefore = pluginsIn(before);
|
|
111
|
+
const pluginsAfter = pluginsIn(after);
|
|
112
|
+
if ([...pluginsAfter].some((plugin) => !pluginsBefore.has(plugin)))
|
|
113
|
+
entries.push(entryOf(PRIVATE, 'plugin', 'added', 'callsPerSession', calls));
|
|
114
|
+
if ([...pluginsBefore].some((plugin) => !pluginsAfter.has(plugin)))
|
|
115
|
+
entries.push(entryOf(PRIVATE, 'plugin', 'removed', 'callsPerSession', calls));
|
|
116
|
+
}
|
|
117
|
+
const modeBefore = modal(before.flatMap(({ main }) => main.setup?.permissionMode ?? []));
|
|
118
|
+
const modeAfter = modal(after.flatMap(({ main }) => main.setup?.permissionMode ?? []));
|
|
119
|
+
if (modeBefore !== undefined && modeAfter !== undefined && modeBefore !== modeAfter)
|
|
120
|
+
entries.push(entryOf(null, 'permissionMode', 'changed', 'callsPerSession', calls));
|
|
121
|
+
const effortBefore = modal(before.flatMap((records) => effortOf(records) ?? []));
|
|
122
|
+
const effortAfter = modal(after.flatMap((records) => effortOf(records) ?? []));
|
|
123
|
+
if (effortBefore !== undefined && effortAfter !== undefined && effortBefore !== effortAfter)
|
|
124
|
+
entries.push(entryOf(null, 'effort', 'changed', 'thinking', signed('tokens', thinkingOf(after) - thinkingOf(before))));
|
|
125
|
+
const manifestsBefore = manifestsIn(before);
|
|
126
|
+
const manifestsAfter = manifestsIn(after);
|
|
127
|
+
const moves = new Map();
|
|
128
|
+
for (const stored of packagesCalledIn(before)) {
|
|
129
|
+
if (!goneFrom(stored, manifestsBefore, manifestsAfter))
|
|
130
|
+
continue;
|
|
131
|
+
const { name, registry } = packageNamed(stored);
|
|
132
|
+
const key = `${registry ?? ''}:${name}`;
|
|
133
|
+
moves.set(key, { name, registry, move: (moves.get(key)?.move ?? 0) + callsNaming(after, stored) - callsNaming(before, stored) });
|
|
134
|
+
}
|
|
135
|
+
for (const { name, registry, move } of moves.values())
|
|
136
|
+
entries.push(entryOf(name, 'package', 'removed', 'callsPerSession', signed('count', move), registry));
|
|
137
|
+
return entries.sort(order);
|
|
138
|
+
};
|
|
139
|
+
const MARKS_FILE = 'deltas-sent.log';
|
|
140
|
+
/**
|
|
141
|
+
* The once-only mark of a delta: a hash of the account, the entry without the size of its move, and the index of its after window on the grid. The move is left out so a recount of the same windows is
|
|
142
|
+
* the same delta, and the index is in so a later pair that shows the same change is a new one. The filler is not in it: which session fills a window moves with the sessions ready, a window's index does not.
|
|
143
|
+
*/
|
|
144
|
+
export const deltaMark = (account, { deltaKind, field, name, registry, metric }, index) => contentHash([account, deltaKind, field, name, registry, metric, index]);
|
|
145
|
+
/** The marks of the deltas this outbox has already carried in a written batch. A folder with no log holds none; a log that cannot be read is an error, not an empty one, so a delta is never built twice by mistake. */
|
|
146
|
+
export const sentDeltas = async (outbox) => {
|
|
147
|
+
try {
|
|
148
|
+
return new Set((await readFile(join(outbox, MARKS_FILE), 'utf8')).split('\n').filter((line) => line !== ''));
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
if (isMissing(error))
|
|
152
|
+
return new Set();
|
|
153
|
+
throw error;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
/** Marks deltas as sent, one line each. The caller writes this only after the batch that carries them is written, so a deposit that stopped before it builds them again. */
|
|
157
|
+
export const markDeltasSent = async (outbox, marks) => {
|
|
158
|
+
if (marks.length === 0)
|
|
159
|
+
return;
|
|
160
|
+
await mkdir(outbox, { recursive: true });
|
|
161
|
+
await appendFile(join(outbox, MARKS_FILE), marks.map((mark) => `${mark}\n`).join(''), 'utf8');
|
|
162
|
+
};
|
|
163
|
+
/** The session placed by when it began (epoch milliseconds) and its own id; none when it has no start that reads as a time, since no window can hold it. */
|
|
164
|
+
export const placedOf = (records) => {
|
|
165
|
+
const at = records.main.tsFirst === null ? Number.NaN : Date.parse(records.main.tsFirst);
|
|
166
|
+
return Number.isNaN(at) ? undefined : { id: records.main.session, at, records };
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* The deltas not yet sent, by the id of the session that filled their after window: that session's batch carries them, and the mark is the window's index, so it holds whichever session fills. A delta whose mark is held is dropped, so a rebuilt session, or a batch written
|
|
170
|
+
* again under the same key, builds none it already carried. Nothing is marked here: the caller marks them once the batch is written.
|
|
171
|
+
*/
|
|
172
|
+
export const carriedDeltas = (account, sessions, sent) => {
|
|
173
|
+
const carried = new Map();
|
|
174
|
+
for (const { index, before, after, filler } of windowsOf(sessions)) {
|
|
175
|
+
const entries = [];
|
|
176
|
+
const marks = [];
|
|
177
|
+
for (const entry of deltasOf(before.map(({ records }) => records),
|
|
178
|
+
// The outcome is fixed at the fill: sessions after the filler change nothing, so a delta is the same whenever it is built.
|
|
179
|
+
after.slice(0, DELTA_MIN_SESSIONS).map(({ records }) => records))) {
|
|
180
|
+
const mark = deltaMark(account, entry, index);
|
|
181
|
+
if (sent.has(mark))
|
|
182
|
+
continue;
|
|
183
|
+
entries.push(entry);
|
|
184
|
+
marks.push(mark);
|
|
185
|
+
}
|
|
186
|
+
if (entries.length > 0)
|
|
187
|
+
carried.set(filler.id, { entries, marks });
|
|
188
|
+
}
|
|
189
|
+
return carried;
|
|
190
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const nightlyPoolDeps = (env, sessions, version, now) => ({
|
|
2
|
+
env,
|
|
3
|
+
io: { stdout: () => undefined, stderr: () => undefined },
|
|
4
|
+
store: { read: () => Promise.resolve(undefined), write: () => Promise.resolve(), delete: () => Promise.resolve() },
|
|
5
|
+
version,
|
|
6
|
+
sleep: () => Promise.resolve(),
|
|
7
|
+
random: () => 0,
|
|
8
|
+
now,
|
|
9
|
+
openBrowser: () => Promise.resolve(),
|
|
10
|
+
sessions,
|
|
11
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RunDeps } from '../cli.js';
|
|
2
|
+
import { type Sender } from './pool-command.js';
|
|
3
|
+
export type NightlyOutcome = 'no-server' | 'not-signed-in' | 'not-accepted' | 'failed' | 'sent';
|
|
4
|
+
export interface NightlyPool {
|
|
5
|
+
outcome: NightlyOutcome;
|
|
6
|
+
/** Batches and raw copies this night sent. */
|
|
7
|
+
batches: number;
|
|
8
|
+
raw: number;
|
|
9
|
+
}
|
|
10
|
+
export declare const nightlyPoolSend: (deps: RunDeps, via?: Sender) => Promise<NightlyPool>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// The nightly send (t884 Item 4). After the person has accepted the pool's covenant, the nightly task builds the outbox and sends what is new: skeleton batches, and, only after a yes to the raw prompt, the locally redacted raw copies.
|
|
2
|
+
// Acceptance is the consent: this module never accepts a covenant, and with an unusable server URL, no sign-in, or no acceptance it makes one request at most (the covenant read) and sends nothing. `oars pool outbox` still prints everything that is queued.
|
|
3
|
+
// It never throws, and what it records is counts and an outcome word, never a path, a host, or a byte of a transcript.
|
|
4
|
+
import { writeFile } from 'node:fs/promises';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { ask, DEPOSIT, isObject, networkSender, poolDeposit, poolServer, postBatch, postRaw, runtimeOf, signedIn, textIn, vocabularyExpired } from './pool-command.js';
|
|
7
|
+
import { heldBatches, lockedBatch, outboxFolder } from './pool-outbox.js';
|
|
8
|
+
import { heldRaw } from './pool-raw.js';
|
|
9
|
+
import { withSendLock } from './pool-send-lock.js';
|
|
10
|
+
import { markSent, sentHashes } from './pool-sent.js';
|
|
11
|
+
import { readState } from './store.js';
|
|
12
|
+
const record = async (storeDir, result, at) => {
|
|
13
|
+
// A note that cannot be written changes nothing about the night.
|
|
14
|
+
await writeFile(join(storeDir, 'pool-nightly.json'), `${JSON.stringify({ at: new Date(at).toISOString(), ...result })}\n`, 'utf8').catch(() => undefined);
|
|
15
|
+
};
|
|
16
|
+
/** Whether the pool says this account has accepted the covenant now in force. Anything else, a closed pool and a refusal included, is no. */
|
|
17
|
+
const accepted = async (deps, server, token, via) => {
|
|
18
|
+
const reply = await ask(deps, DEPOSIT, server, '/v1/covenant', { token }, via);
|
|
19
|
+
return reply.status === 200 && isObject(reply.body) && textIn(reply.body, 'version') !== undefined && Reflect.get(reply.body, 'accepted') === true;
|
|
20
|
+
};
|
|
21
|
+
const night = async (deps, net, tally) => {
|
|
22
|
+
const none = (outcome) => ({ outcome, batches: 0, raw: 0 });
|
|
23
|
+
let server;
|
|
24
|
+
try {
|
|
25
|
+
server = poolServer(deps.env, DEPOSIT);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return none('no-server');
|
|
29
|
+
}
|
|
30
|
+
const { storeDir } = runtimeOf(deps);
|
|
31
|
+
let token;
|
|
32
|
+
try {
|
|
33
|
+
({ token } = await signedIn(deps, storeDir, server, DEPOSIT));
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return none('not-signed-in');
|
|
37
|
+
}
|
|
38
|
+
if (vocabularyExpired(deps) !== undefined)
|
|
39
|
+
return none('failed');
|
|
40
|
+
if (!(await accepted(deps, server, token, net)))
|
|
41
|
+
return none('not-accepted');
|
|
42
|
+
const outbox = outboxFolder(storeDir, server);
|
|
43
|
+
tally.outcome = 'sent';
|
|
44
|
+
// One sender at a time per outbox, the lock `deposit --send` takes: a second run waits, then finds `sent.log` full and sends nothing twice.
|
|
45
|
+
await withSendLock(outbox, async () => {
|
|
46
|
+
// The outbox is built only for an account that has accepted, then sent: the same gates `oars pool deposit` runs, so nothing queues that a person could not print.
|
|
47
|
+
await poolDeposit(deps, { server });
|
|
48
|
+
const done = await sentHashes(outbox);
|
|
49
|
+
for (const batch of (await heldBatches(outbox)).batches) {
|
|
50
|
+
if (done.has(batch.hash))
|
|
51
|
+
continue;
|
|
52
|
+
// Acceptance is the consent, so nothing was printed first; the file is still read and hashed again just before the request.
|
|
53
|
+
const locked = await lockedBatch(outbox, batch.hash, { requireShown: false });
|
|
54
|
+
if (!locked.ok)
|
|
55
|
+
continue;
|
|
56
|
+
await postBatch(deps, { server, token, bytes: locked.bytes, hash: batch.hash, via: net });
|
|
57
|
+
await markSent(outbox, batch.hash, deps.now());
|
|
58
|
+
tally.batches += 1;
|
|
59
|
+
}
|
|
60
|
+
// Raw goes only with its own yes, read again here so an answer changed since the build wins.
|
|
61
|
+
if ((await readState(storeDir)).pool.rawConsent === 'granted') {
|
|
62
|
+
for (const copy of (await heldRaw(outbox)).copies) {
|
|
63
|
+
if (done.has(copy.hash) || copy.bytes === 0)
|
|
64
|
+
continue;
|
|
65
|
+
await postRaw(deps, { server, token, hash: copy.hash, body: copy.body, bytes: copy.bytes, via: net });
|
|
66
|
+
await markSent(outbox, copy.hash, deps.now());
|
|
67
|
+
tally.raw += 1;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
return tally;
|
|
72
|
+
};
|
|
73
|
+
export const nightlyPoolSend = async (deps, via) => {
|
|
74
|
+
// The tally is filled as sends land, so a night that fails halfway still records what it did send.
|
|
75
|
+
const tally = { outcome: 'failed', batches: 0, raw: 0 };
|
|
76
|
+
let result;
|
|
77
|
+
try {
|
|
78
|
+
result = await night(deps, via ?? networkSender(deps, DEPOSIT), tally);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
result = { ...tally, outcome: 'failed' };
|
|
82
|
+
}
|
|
83
|
+
await record(runtimeOf(deps).storeDir, result, deps.now());
|
|
84
|
+
return result;
|
|
85
|
+
};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/** The batch as one canonical JSON line: sorted keys, no optional whitespace, UTF-8 when written, and a newline at the end. These are the bytes that are hashed, printed, and sent. */
|
|
2
|
+
export declare const canonicalBytes: (batch: unknown) => string;
|
|
3
|
+
/** The most bytes one request of a deposit carries. The pool refuses a request past 1 MiB, so a batch past this goes in parts, each of them under that cap. */
|
|
4
|
+
export declare const PART_BYTES: number;
|
|
5
|
+
/**
|
|
6
|
+
* The batch cut into parts of at most `limit` UTF-8 bytes, never inside a character, so the parts join back to exactly the bytes that were hashed. A batch within the limit is one part.
|
|
7
|
+
*/
|
|
8
|
+
export declare const partsOf: (bytes: string, limit?: number) => string[];
|
|
9
|
+
export declare const batchHash: (bytes: string) => string;
|
|
10
|
+
/**
|
|
11
|
+
* `oars pool outbox --explain`: one row for each field name a batch holds, at any depth, saying what admits its values. A field with no row fails the command, so a field added to the batch adds its row here.
|
|
12
|
+
* A name that sits at more than one depth (`status`, `harness`, `frame`) has one row that reads true at each.
|
|
13
|
+
*/
|
|
14
|
+
export declare const FIELD_ROWS: {
|
|
15
|
+
readonly [field: string]: string;
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Every field name a batch holds, at any depth, sorted: the rows above. A batch is filed under this list, the skeleton format, and `VOCAB_VERSION`, so one built under an older list, form, or vocabulary is never printed or sent.
|
|
19
|
+
* A test holds this list equal to the fields of a real batch, so a field the sample holds without its row fails there.
|
|
20
|
+
*/
|
|
21
|
+
export declare const BATCH_FIELDS: readonly string[];
|
|
22
|
+
/** The folder name of the batches this client builds now. A folder of any other name holds batches built under an older vocabulary, field list, or skeleton format. */
|
|
23
|
+
export declare const currentStamp: (fields?: readonly string[], format?: number) => string;
|
|
24
|
+
/** One server's outbox: batches are per server, since a printed batch carries that server's credential. */
|
|
25
|
+
export declare const outboxFolder: (storeDir: string, server: string) => string;
|
|
26
|
+
/** Writes one session's batch under the current stamp. A session has one batch: an older batch of it is removed, and an identical one is written again, so an edited file is restored. */
|
|
27
|
+
export declare const writeBatch: (outbox: string, key: string, batch: unknown, stamp?: string) => Promise<{
|
|
28
|
+
hash: string;
|
|
29
|
+
folder: string;
|
|
30
|
+
bytes: number;
|
|
31
|
+
}>;
|
|
32
|
+
export declare const isMissing: (error: unknown) => boolean;
|
|
33
|
+
/** Removes every batch under this stamp whose session is not in `kept`, and returns how many went. A session that fails a gate, leaves the allowlist, or is gone from the store never enters the outbox, so an earlier pass's batch of it cannot stay. */
|
|
34
|
+
export declare const removeBatchesExcept: (outbox: string, kept: ReadonlySet<string>, stamp?: string, only?: string) => Promise<number>;
|
|
35
|
+
/** Removes the batch of one session, if it has one under this stamp, and returns how many files went. */
|
|
36
|
+
export declare const removeBatchOf: (outbox: string, key: string, stamp?: string) => Promise<number>;
|
|
37
|
+
/** The bytes of a batch file, when they still hash to the name the file was written under; undefined when the file is gone or was edited. */
|
|
38
|
+
export declare const unchangedBytes: (file: string, hash: string) => Promise<string | undefined>;
|
|
39
|
+
export interface Held {
|
|
40
|
+
/** The session's key in the outbox (the batch's account-hashed id). */
|
|
41
|
+
key: string;
|
|
42
|
+
hash: string;
|
|
43
|
+
file: string;
|
|
44
|
+
bytes: string;
|
|
45
|
+
}
|
|
46
|
+
/** The batches built under this client's vocabulary, field list, and skeleton format, and how many of their files no longer hash to their names. An edited file is not printed and cannot be sent: run `deposit` again to rebuild it. */
|
|
47
|
+
export declare const heldBatches: (outbox: string, stamp?: string) => Promise<{
|
|
48
|
+
batches: Held[];
|
|
49
|
+
edited: number;
|
|
50
|
+
}>;
|
|
51
|
+
/** Records that this hash was printed, one line for each print: the lock below sends only a hash that appears here. */
|
|
52
|
+
export declare const markShown: (outbox: string, hash: string, at: number) => Promise<void>;
|
|
53
|
+
export type LockRefusal = 'batch_unknown' | 'batch_not_shown' | 'batch_changed';
|
|
54
|
+
/**
|
|
55
|
+
* The lock on a send: a batch goes only if it is in the outbox, its hash was printed, and its file still hashes to that hash. The first check that fails names why. The nightly task sends with `requireShown: false`,
|
|
56
|
+
* because covenant acceptance is its consent and it prints nothing; the other two checks still hold.
|
|
57
|
+
*/
|
|
58
|
+
export declare const lockedBatch: (outbox: string, hash: string, options?: {
|
|
59
|
+
stamp?: string;
|
|
60
|
+
requireShown?: boolean;
|
|
61
|
+
}) => Promise<{
|
|
62
|
+
ok: true;
|
|
63
|
+
file: string;
|
|
64
|
+
bytes: string;
|
|
65
|
+
} | {
|
|
66
|
+
ok: false;
|
|
67
|
+
code: LockRefusal;
|
|
68
|
+
}>;
|
|
69
|
+
/** Batches in one server's outbox that were built under another vocabulary, field list, or skeleton format: never printed, never sent. */
|
|
70
|
+
export declare const staleBatches: (outbox: string, stamp?: string) => Promise<number>;
|
|
71
|
+
/** Every server's stale batches, for `verify`. */
|
|
72
|
+
export declare const staleBatchesAnywhere: (storeDir: string, stamp?: string) => Promise<number>;
|
|
73
|
+
/** Removes one server's stale batches, and returns how many there were. */
|
|
74
|
+
export declare const discardStale: (outbox: string, stamp?: string) => Promise<number>;
|
|
75
|
+
/** Every field name in a batch, at any depth, each once and sorted. */
|
|
76
|
+
export declare const fieldsOf: (batchBytes: string) => string[];
|