@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,26 @@
|
|
|
1
|
+
import { type RepoSize } from './public-vocabulary.js';
|
|
2
|
+
import { type LanguageShare, type RepoFilesBucket, type Strata } from './schema.js';
|
|
3
|
+
import type { CanonicalAction } from './actions.js';
|
|
4
|
+
/** How many of the given steps only look. */
|
|
5
|
+
export declare const exploreCount: (actions: readonly CanonicalAction[]) => number;
|
|
6
|
+
/**
|
|
7
|
+
* A language's share of the touched files: absent, incidental (under 10 percent), secondary (10 up to 50), primary (50 and over). The lower edge is inclusive.
|
|
8
|
+
* Integers are compared, not a quotient, so 1 of 10 files is exactly 10 percent.
|
|
9
|
+
*/
|
|
10
|
+
export declare const languageShareBucket: (files: number, total: number) => LanguageShare;
|
|
11
|
+
export declare const repoFilesBucketOf: (size: RepoSize | null) => RepoFilesBucket | null;
|
|
12
|
+
/**
|
|
13
|
+
* A package the vocabulary marks as a framework, by `<ecosystem>:<name>` as `resolveName` writes it, to the framework's name in `FRAMEWORKS`. A package
|
|
14
|
+
* is not a program or a file, so this is the one source of `framework` that names a registry entry.
|
|
15
|
+
*/
|
|
16
|
+
export declare const FRAMEWORK_OF_PACKAGE: ReadonlyMap<string, string>;
|
|
17
|
+
/** The strata of a file's evidence but `explore`, which the caller counts for the file and for each prompt. Files are counted, not touches: a path read ten times is one. */
|
|
18
|
+
export declare const strataOf: (evidence: {
|
|
19
|
+
paths: readonly string[];
|
|
20
|
+
packages: readonly string[];
|
|
21
|
+
size: RepoSize | null;
|
|
22
|
+
}) => Omit<Strata, "explore">;
|
|
23
|
+
/** A stored language as it pools: a member of the pinned list, else `other`. */
|
|
24
|
+
export declare const projectLanguage: (stored: string) => string;
|
|
25
|
+
/** A stored share bucket as it pools: itself when it is one of the four, else null (no bucket is guessed from a value this code does not know). */
|
|
26
|
+
export declare const projectLanguageShare: (stored: string) => LanguageShare | null;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// The stack strata a capture stores (pool vocabulary spec Sections 1.1 and 7): language and its share of the touched files, the repository's file
|
|
2
|
+
// count by order of magnitude, the framework a resolved package shows, and how many steps only looked. Every value is a member of a closed list or a count,
|
|
3
|
+
// so no path, package name, or program text is kept. The language and share projections are here; the rest that gate these at deposit are in `projection.ts`.
|
|
4
|
+
import { LANGUAGE_OF_EXTENSION, LANGUAGES } from './public-vocabulary.js';
|
|
5
|
+
import { LANGUAGE_SHARES } from './schema.js';
|
|
6
|
+
/** The steps that only look at the code or the web. `file.read`, `file.search`, `web.search`, and `web.fetch`; a shell step is not counted, because what it does is not known from its action. */
|
|
7
|
+
const EXPLORE_ACTIONS = new Set(['file.read', 'file.search', 'web.search', 'web.fetch']);
|
|
8
|
+
/** How many of the given steps only look. */
|
|
9
|
+
export const exploreCount = (actions) => actions.filter((action) => EXPLORE_ACTIONS.has(action)).length;
|
|
10
|
+
/**
|
|
11
|
+
* A language's share of the touched files: absent, incidental (under 10 percent), secondary (10 up to 50), primary (50 and over). The lower edge is inclusive.
|
|
12
|
+
* Integers are compared, not a quotient, so 1 of 10 files is exactly 10 percent.
|
|
13
|
+
*/
|
|
14
|
+
export const languageShareBucket = (files, total) => {
|
|
15
|
+
if (files <= 0 || total <= 0)
|
|
16
|
+
return '0';
|
|
17
|
+
if (files * 100 < total * 10)
|
|
18
|
+
return 'under-10';
|
|
19
|
+
return files * 100 < total * 50 ? '10-50' : 'over-50';
|
|
20
|
+
};
|
|
21
|
+
/** The repository's size bucket (`repoSizeOf`) as the pool's `repoFiles` bucket: both cut at 100, 1000, 10000, and 100000 with the lower edge inclusive. */
|
|
22
|
+
const REPO_FILES_OF_SIZE = new Map([
|
|
23
|
+
['xs', 'under-100'],
|
|
24
|
+
['s', '100-1k'],
|
|
25
|
+
['m', '1k-10k'],
|
|
26
|
+
['l', '10k-100k'],
|
|
27
|
+
['xl', 'over-100k'],
|
|
28
|
+
]);
|
|
29
|
+
export const repoFilesBucketOf = (size) => (size === null ? null : (REPO_FILES_OF_SIZE.get(size) ?? null));
|
|
30
|
+
/**
|
|
31
|
+
* A package the vocabulary marks as a framework, by `<ecosystem>:<name>` as `resolveName` writes it, to the framework's name in `FRAMEWORKS`. A package
|
|
32
|
+
* is not a program or a file, so this is the one source of `framework` that names a registry entry.
|
|
33
|
+
*/
|
|
34
|
+
export const FRAMEWORK_OF_PACKAGE = new Map([
|
|
35
|
+
['npm:vite', 'vite'],
|
|
36
|
+
['npm:vitest', 'vitest'],
|
|
37
|
+
['npm:astro', 'astro'],
|
|
38
|
+
['npm:next', 'next'],
|
|
39
|
+
['npm:nuxt', 'nuxt'],
|
|
40
|
+
['npm:svelte', 'svelte'],
|
|
41
|
+
['npm:@angular/core', 'angular'],
|
|
42
|
+
['npm:tailwindcss', 'tailwind'],
|
|
43
|
+
['npm:jest', 'jest'],
|
|
44
|
+
['npm:playwright', 'playwright'],
|
|
45
|
+
['npm:@playwright/test', 'playwright'],
|
|
46
|
+
['npm:wrangler', 'cloudflare-workers'],
|
|
47
|
+
['pypi:django', 'django'],
|
|
48
|
+
['rubygems:rails', 'rails'],
|
|
49
|
+
]);
|
|
50
|
+
/** The language of one touched path: the vocabulary's name for its extension, else `other`; null for a path with no extension, which shows no language. A dotfile (`.gitignore`) has none: its only dot leads the name. */
|
|
51
|
+
const languageOfPath = (path) => {
|
|
52
|
+
const base = path.replace(/\\/g, '/').split('/').pop() ?? path;
|
|
53
|
+
if (base.lastIndexOf('.') <= 0)
|
|
54
|
+
return null;
|
|
55
|
+
return LANGUAGE_OF_EXTENSION.get(base.split('.').pop()?.toLowerCase() ?? '') ?? 'other';
|
|
56
|
+
};
|
|
57
|
+
/** The strata of a file's evidence but `explore`, which the caller counts for the file and for each prompt. Files are counted, not touches: a path read ten times is one. */
|
|
58
|
+
export const strataOf = (evidence) => {
|
|
59
|
+
const counts = new Map();
|
|
60
|
+
let total = 0;
|
|
61
|
+
for (const path of new Set(evidence.paths)) {
|
|
62
|
+
const language = languageOfPath(path);
|
|
63
|
+
if (language === null)
|
|
64
|
+
continue;
|
|
65
|
+
counts.set(language, (counts.get(language) ?? 0) + 1);
|
|
66
|
+
total += 1;
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
languages: [...counts].sort(([a], [b]) => a.localeCompare(b)).map(([language, files]) => ({ language, share: languageShareBucket(files, total) })),
|
|
70
|
+
repoFiles: repoFilesBucketOf(evidence.size),
|
|
71
|
+
frameworks: [...new Set(evidence.packages.flatMap((name) => FRAMEWORK_OF_PACKAGE.get(name) ?? []))].sort(),
|
|
72
|
+
};
|
|
73
|
+
};
|
|
74
|
+
/** A stored language as it pools: a member of the pinned list, else `other`. */
|
|
75
|
+
export const projectLanguage = (stored) => (LANGUAGES.has(stored) ? stored : 'other');
|
|
76
|
+
/** A stored share bucket as it pools: itself when it is one of the four, else null (no bucket is guessed from a value this code does not know). */
|
|
77
|
+
export const projectLanguageShare = (stored) => LANGUAGE_SHARES.find((bucket) => bucket === stored) ?? null;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { type SessionsRuntime } from './store.js';
|
|
2
|
+
/** A commit younger than this has not had time to be reverted or dropped, so it is not read yet. */
|
|
3
|
+
export declare const SURVIVAL_DAYS = 7;
|
|
4
|
+
declare const STATES: readonly ["survived", "reverted", "unreachable", "unknown"];
|
|
5
|
+
export type SurvivalState = (typeof STATES)[number];
|
|
6
|
+
/** One line of `commit-survival.jsonl`. `sha` as captured (usually short), and a day-resolution date. */
|
|
7
|
+
export interface SurvivalObservation {
|
|
8
|
+
sha: string;
|
|
9
|
+
state: SurvivalState;
|
|
10
|
+
day: string;
|
|
11
|
+
}
|
|
12
|
+
export type SurvivalCounts = {
|
|
13
|
+
[state in SurvivalState]: number;
|
|
14
|
+
};
|
|
15
|
+
/** Runs one read-only git command in a repository and answers its stdout; rejects on any failure. */
|
|
16
|
+
export type Git = (root: string, args: readonly string[], stdin?: string) => Promise<string>;
|
|
17
|
+
export declare const survivalFile: (storeDir: string) => string;
|
|
18
|
+
export declare const runGit: Git;
|
|
19
|
+
export declare const cwdOfProject: (runtime: Pick<SessionsRuntime, "projectsRoot" | "storeDir">, project: string, sessions: ReadonlySet<string>) => Promise<string | undefined>;
|
|
20
|
+
/** The latest state of each sha. The file only adds to what `books` shows, so a missing or unreadable one reads as nothing observed yet. */
|
|
21
|
+
export declare const readSurvival: (storeDir: string) => Promise<Map<string, SurvivalState>>;
|
|
22
|
+
/**
|
|
23
|
+
* Observes every commit older than `SURVIVAL_DAYS` in the allowlisted folders. Never rejects, since a deposit that has already succeeded
|
|
24
|
+
* must not fail on what it adds: null when the store could not be read or written, and the next run tries again.
|
|
25
|
+
*/
|
|
26
|
+
export declare const recordSurvival: (runtime: SessionsRuntime, allow: readonly string[], now: () => number, git?: Git) => Promise<SurvivalCounts | null>;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
// Commit survival: what became of a commit is an observation made later, not a fact of the transcript, so it never
|
|
2
|
+
// runs at derive time and never from a hook a session waits on. A manual deposit and the nightly run read the repository of each
|
|
3
|
+
// allowlisted folder and append to `commit-survival.jsonl` beside the store, so the log `verify` checks stays untouched.
|
|
4
|
+
import { execFile } from 'node:child_process';
|
|
5
|
+
import { createReadStream } from 'node:fs';
|
|
6
|
+
import { appendFile, readFile } from 'node:fs/promises';
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { createInterface } from 'node:readline';
|
|
9
|
+
import { compileAllow, slugOf } from './allow.js';
|
|
10
|
+
import { makeRepoRoot } from './repo-root.js';
|
|
11
|
+
import { loadStore, paths } from './store.js';
|
|
12
|
+
/** A commit younger than this has not had time to be reverted or dropped, so it is not read yet. */
|
|
13
|
+
export const SURVIVAL_DAYS = 7;
|
|
14
|
+
const DAY_MS = 86_400_000;
|
|
15
|
+
const GIT_TIMEOUT_MS = 120_000;
|
|
16
|
+
/** `rev-list` prints 41 bytes a commit; this holds about 6 million of them. */
|
|
17
|
+
const GIT_MAX_BUFFER = 256 * 1024 * 1024;
|
|
18
|
+
/** How far into a transcript to look for its working directory: the harness stamps every line, so a file without one by here has none. */
|
|
19
|
+
const CWD_SCAN_LINES = 200;
|
|
20
|
+
/** Tried in this order when `origin/HEAD` is not set, which `git clone` sets and `git init` plus `git remote add` does not. */
|
|
21
|
+
const DEFAULT_REFS = ['refs/remotes/origin/main', 'refs/remotes/origin/master', 'refs/heads/main', 'refs/heads/master'];
|
|
22
|
+
const STATES = ['survived', 'reverted', 'unreachable', 'unknown'];
|
|
23
|
+
export const survivalFile = (storeDir) => join(storeDir, 'commit-survival.jsonl');
|
|
24
|
+
export const runGit = (root, args, stdin) => new Promise((resolve, reject) => {
|
|
25
|
+
const child = execFile('git', ['-C', root, ...args], {
|
|
26
|
+
encoding: 'utf8',
|
|
27
|
+
timeout: GIT_TIMEOUT_MS,
|
|
28
|
+
maxBuffer: GIT_MAX_BUFFER,
|
|
29
|
+
windowsHide: true,
|
|
30
|
+
// A partial clone would fetch a missing object from its remote, and this reads no network. `GIT_NO_LAZY_FETCH` needs about 2.45 or later, and a `protocol.allow` key loses to a `protocol.<name>.allow` key in the
|
|
31
|
+
// repository's own config. `GIT_ALLOW_PROTOCOL` is checked first on any git and beats every config key, and setting it here replaces one inherited from the caller. A `GIT_DIR` inherited from a caller's hook would read some other repository than the one named.
|
|
32
|
+
env: { ...process.env, GIT_ALLOW_PROTOCOL: 'none', GIT_NO_LAZY_FETCH: '1', GIT_OPTIONAL_LOCKS: '0', GIT_DIR: undefined, GIT_WORK_TREE: undefined },
|
|
33
|
+
}, (error, stdout) => {
|
|
34
|
+
if (error === null)
|
|
35
|
+
resolve(stdout);
|
|
36
|
+
else
|
|
37
|
+
reject(new Error(error.message));
|
|
38
|
+
});
|
|
39
|
+
// A git that exits before reading its stdin raises EPIPE here; its exit status already reports the failure.
|
|
40
|
+
child.stdin?.on('error', () => undefined);
|
|
41
|
+
child.stdin?.end(stdin ?? '');
|
|
42
|
+
});
|
|
43
|
+
const outputLines = (text) => text.split(/\r?\n/).filter((line) => line !== '');
|
|
44
|
+
const defaultRef = async (git, root) => {
|
|
45
|
+
const head = (await git(root, ['symbolic-ref', '--quiet', 'refs/remotes/origin/HEAD']).catch(() => '')).trim();
|
|
46
|
+
if (head !== '')
|
|
47
|
+
return head;
|
|
48
|
+
const present = new Set(outputLines(await git(root, ['for-each-ref', '--format=%(refname)', ...DEFAULT_REFS])));
|
|
49
|
+
return DEFAULT_REFS.find((ref) => present.has(ref)) ?? null;
|
|
50
|
+
};
|
|
51
|
+
const REVERT_RECORD = /^([0-9a-f]{40})\n([\s\S]*)$/;
|
|
52
|
+
const REVERTS = /This reverts commit ([0-9a-f]{40})/g;
|
|
53
|
+
/**
|
|
54
|
+
* The commits the default branch has undone, from `git revert`'s own message. `git log --topo-order` runs children before parents, so by the
|
|
55
|
+
* time a revert is reached anything that undid it has been seen, and a reverted revert undoes nothing.
|
|
56
|
+
*/
|
|
57
|
+
const revertedIn = (log) => {
|
|
58
|
+
const reverted = new Set();
|
|
59
|
+
for (const record of log.split('\0')) {
|
|
60
|
+
const found = REVERT_RECORD.exec(record.trimStart());
|
|
61
|
+
if (found === null || reverted.has(found[1] ?? ''))
|
|
62
|
+
continue;
|
|
63
|
+
for (const match of (found[2] ?? '').matchAll(REVERTS))
|
|
64
|
+
reverted.add(match[1] ?? '');
|
|
65
|
+
}
|
|
66
|
+
return reverted;
|
|
67
|
+
};
|
|
68
|
+
/** What one repository says of each sha. A sha it does not hold reads `unknown`: the session may have committed in another repository, which a path rule cannot follow. */
|
|
69
|
+
const classify = async (git, root, shas) => {
|
|
70
|
+
const states = new Map();
|
|
71
|
+
if ((await git(root, ['rev-parse', '--is-shallow-repository'])).trim() !== 'false')
|
|
72
|
+
return states;
|
|
73
|
+
const ref = await defaultRef(git, root);
|
|
74
|
+
if (ref === null)
|
|
75
|
+
return states;
|
|
76
|
+
const reachable = new Set(outputLines(await git(root, ['rev-list', ref])));
|
|
77
|
+
const reverted = revertedIn(await git(root, ['log', ref, '--topo-order', '--no-show-signature', '--grep=This reverts commit', '--format=%H%n%B%x00']));
|
|
78
|
+
const resolved = outputLines(await git(root, ['cat-file', '--batch-check=%(objectname) %(objecttype)'], `${shas.join('\n')}\n`));
|
|
79
|
+
shas.forEach((sha, index) => {
|
|
80
|
+
const [full = '', type] = (resolved[index] ?? '').split(' ');
|
|
81
|
+
if (type !== 'commit')
|
|
82
|
+
return;
|
|
83
|
+
states.set(sha, reverted.has(full) ? 'reverted' : reachable.has(full) ? 'survived' : 'unreachable');
|
|
84
|
+
});
|
|
85
|
+
return states;
|
|
86
|
+
};
|
|
87
|
+
/** The shas old enough to read, per allowlisted project. Main-line calls only: a subagent's commits are not attributed yet. */
|
|
88
|
+
const dueByProject = (store, allows, cutoff) => {
|
|
89
|
+
const projectOf = new Map(store.sessions.map((session) => [session.session, session.project]));
|
|
90
|
+
const due = new Map();
|
|
91
|
+
for (const tool of store.tools) {
|
|
92
|
+
const project = projectOf.get(tool.session);
|
|
93
|
+
if (project === undefined || !allows(project) || tool.side || tool.ts === null || tool.ts >= cutoff)
|
|
94
|
+
continue;
|
|
95
|
+
for (const sha of tool.commits ?? []) {
|
|
96
|
+
if (sha === null)
|
|
97
|
+
continue;
|
|
98
|
+
const entry = due.get(project) ?? { sessions: new Set(), shas: new Set() };
|
|
99
|
+
entry.sessions.add(tool.session);
|
|
100
|
+
entry.shas.add(sha);
|
|
101
|
+
due.set(project, entry);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return due;
|
|
105
|
+
};
|
|
106
|
+
const topLevelCwd = (line) => {
|
|
107
|
+
try {
|
|
108
|
+
const parsed = JSON.parse(line);
|
|
109
|
+
const cwd = typeof parsed === 'object' && parsed !== null ? Reflect.get(parsed, 'cwd') : undefined;
|
|
110
|
+
return typeof cwd === 'string' ? cwd : undefined;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
/** The transcript's first `cwd` whose slug is the project. A later `cd` moves `cwd`, and a path a transcript merely names must not choose what gets read. */
|
|
117
|
+
const cwdIn = async (file, project) => {
|
|
118
|
+
const stream = createReadStream(file, { encoding: 'utf8' });
|
|
119
|
+
// An absent file errors here, not in the loop.
|
|
120
|
+
const opened = new Promise((resolve) => {
|
|
121
|
+
stream.once('error', () => {
|
|
122
|
+
resolve(false);
|
|
123
|
+
});
|
|
124
|
+
stream.once('open', () => {
|
|
125
|
+
resolve(true);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
if (!(await opened))
|
|
129
|
+
return undefined;
|
|
130
|
+
const reader = createInterface({ input: stream, crlfDelay: Infinity });
|
|
131
|
+
let read = 0;
|
|
132
|
+
try {
|
|
133
|
+
for await (const line of reader) {
|
|
134
|
+
read += 1;
|
|
135
|
+
if (read > CWD_SCAN_LINES)
|
|
136
|
+
return undefined;
|
|
137
|
+
const cwd = topLevelCwd(line);
|
|
138
|
+
if (cwd !== undefined && slugOf(cwd) === project)
|
|
139
|
+
return cwd;
|
|
140
|
+
}
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
finally {
|
|
144
|
+
reader.close();
|
|
145
|
+
stream.destroy();
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
export const cwdOfProject = async (runtime, project, sessions) => {
|
|
149
|
+
for (const session of sessions) {
|
|
150
|
+
for (const root of [runtime.projectsRoot, paths(runtime.storeDir).raw]) {
|
|
151
|
+
const found = await cwdIn(join(root, project, `${session}.jsonl`), project);
|
|
152
|
+
if (found !== undefined)
|
|
153
|
+
return found;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return undefined;
|
|
157
|
+
};
|
|
158
|
+
const isObservation = (value) => {
|
|
159
|
+
if (typeof value !== 'object' || value === null)
|
|
160
|
+
return false;
|
|
161
|
+
const state = Reflect.get(value, 'state');
|
|
162
|
+
return typeof Reflect.get(value, 'sha') === 'string' && STATES.some((known) => known === state);
|
|
163
|
+
};
|
|
164
|
+
/** The latest state of each sha. The file only adds to what `books` shows, so a missing or unreadable one reads as nothing observed yet. */
|
|
165
|
+
export const readSurvival = async (storeDir) => {
|
|
166
|
+
const states = new Map();
|
|
167
|
+
const text = await readFile(survivalFile(storeDir), 'utf8').catch(() => '');
|
|
168
|
+
for (const line of text.split('\n')) {
|
|
169
|
+
if (line === '')
|
|
170
|
+
continue;
|
|
171
|
+
try {
|
|
172
|
+
const parsed = JSON.parse(line);
|
|
173
|
+
if (isObservation(parsed))
|
|
174
|
+
states.set(parsed.sha, parsed.state);
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// A torn last line from a crashed run: the next run observes that sha again.
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
return states;
|
|
181
|
+
};
|
|
182
|
+
const observe = async (runtime, allowEntries, now, git) => {
|
|
183
|
+
const allow = compileAllow(allowEntries);
|
|
184
|
+
const due = dueByProject(await loadStore(runtime.storeDir), allow.allows, new Date(now() - SURVIVAL_DAYS * DAY_MS).toISOString());
|
|
185
|
+
const repoRoot = makeRepoRoot();
|
|
186
|
+
const byRoot = new Map();
|
|
187
|
+
const shas = new Set();
|
|
188
|
+
for (const [project, entry] of due) {
|
|
189
|
+
for (const sha of entry.shas)
|
|
190
|
+
shas.add(sha);
|
|
191
|
+
const cwd = await cwdOfProject(runtime, project, entry.sessions);
|
|
192
|
+
const root = cwd === undefined ? null : repoRoot(cwd);
|
|
193
|
+
if (root !== null)
|
|
194
|
+
byRoot.set(root, new Set([...(byRoot.get(root) ?? []), ...entry.shas]));
|
|
195
|
+
}
|
|
196
|
+
const fresh = new Map();
|
|
197
|
+
for (const [root, wanted] of byRoot) {
|
|
198
|
+
// Fail-open per repository: one that cannot be read leaves its shas unknown and the others are still read.
|
|
199
|
+
const states = await classify(git, root, [...wanted]).catch(() => new Map());
|
|
200
|
+
for (const [sha, state] of states)
|
|
201
|
+
fresh.set(sha, state);
|
|
202
|
+
}
|
|
203
|
+
const known = await readSurvival(runtime.storeDir);
|
|
204
|
+
const day = new Date(now()).toISOString().slice(0, 10);
|
|
205
|
+
const counts = { survived: 0, reverted: 0, unreachable: 0, unknown: 0 };
|
|
206
|
+
const appended = [];
|
|
207
|
+
for (const sha of shas) {
|
|
208
|
+
const before = known.get(sha);
|
|
209
|
+
// An observation is not undone by a later failure to look: only a state git answered replaces one.
|
|
210
|
+
const state = fresh.get(sha) ?? before ?? 'unknown';
|
|
211
|
+
counts[state] += 1;
|
|
212
|
+
if (state !== before)
|
|
213
|
+
appended.push({ sha, state, day });
|
|
214
|
+
}
|
|
215
|
+
if (appended.length > 0)
|
|
216
|
+
await appendFile(survivalFile(runtime.storeDir), appended.map((line) => `${JSON.stringify(line)}\n`).join(''), { mode: 0o600 });
|
|
217
|
+
return counts;
|
|
218
|
+
};
|
|
219
|
+
/**
|
|
220
|
+
* Observes every commit older than `SURVIVAL_DAYS` in the allowlisted folders. Never rejects, since a deposit that has already succeeded
|
|
221
|
+
* must not fail on what it adds: null when the store could not be read or written, and the next run tries again.
|
|
222
|
+
*/
|
|
223
|
+
export const recordSurvival = async (runtime, allow, now, git = runGit) => {
|
|
224
|
+
try {
|
|
225
|
+
return await observe(runtime, allow, now, git);
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return null;
|
|
229
|
+
}
|
|
230
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** A file's last bytes; a first line this cuts in two fails to parse and is skipped by whoever reads it. */
|
|
2
|
+
export declare const tailOf: (file: string) => Promise<string>;
|
|
3
|
+
export declare const isRecord: (value: unknown) => value is {
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
};
|
|
6
|
+
/** What a transcript's tail states of the asker: the harness version, the model, and the effort, each the newest line's that states it. */
|
|
7
|
+
export interface Stated {
|
|
8
|
+
harnessVersion: string | null;
|
|
9
|
+
model: string | null;
|
|
10
|
+
effort: string | null;
|
|
11
|
+
}
|
|
12
|
+
export declare const statedOf: (tail: string) => Stated;
|
|
13
|
+
/** The same from a transcript file. A file that cannot be read states nothing: telemetry must never cost a hook its answer. */
|
|
14
|
+
export declare const statedAt: (file: string) => Promise<Stated>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// The last bytes of a transcript and what they state, light enough for a hook to import: the bare `oars gate hook` loads this and never the recall machinery.
|
|
2
|
+
import { open } from 'node:fs/promises';
|
|
3
|
+
/** How far back a hook looks in a growing file: enough for the session's latest lines, and a bound on what a hook on every call can cost. */
|
|
4
|
+
const TAIL_BYTES = 64 * 1024;
|
|
5
|
+
const isMissing = (error) => error instanceof Error && 'code' in error && error.code === 'ENOENT';
|
|
6
|
+
const openIfThere = async (file) => {
|
|
7
|
+
try {
|
|
8
|
+
return await open(file, 'r');
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
if (isMissing(error))
|
|
12
|
+
return undefined;
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
/** A file's last bytes; a first line this cuts in two fails to parse and is skipped by whoever reads it. */
|
|
17
|
+
export const tailOf = async (file) => {
|
|
18
|
+
const handle = await openIfThere(file);
|
|
19
|
+
if (handle === undefined)
|
|
20
|
+
return '';
|
|
21
|
+
try {
|
|
22
|
+
const { size } = await handle.stat();
|
|
23
|
+
const length = Math.min(size, TAIL_BYTES);
|
|
24
|
+
const buffer = Buffer.alloc(length);
|
|
25
|
+
await handle.read(buffer, 0, length, size - length);
|
|
26
|
+
return buffer.toString('utf8');
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
await handle.close();
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
export const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
33
|
+
const text = (value) => (typeof value === 'string' && value !== '' ? value : null);
|
|
34
|
+
const parsedLines = (tail) => tail.split('\n').flatMap((line) => {
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(line);
|
|
37
|
+
return isRecord(parsed) ? [parsed] : [];
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
export const statedOf = (tail) => {
|
|
44
|
+
let harnessVersion = null;
|
|
45
|
+
let model = null;
|
|
46
|
+
let effort = null;
|
|
47
|
+
// Oldest first, so the newest line that states a field wins.
|
|
48
|
+
for (const line of parsedLines(tail)) {
|
|
49
|
+
harnessVersion = text(line.version) ?? harnessVersion;
|
|
50
|
+
effort = text(line.effort) ?? effort;
|
|
51
|
+
if (isRecord(line.message))
|
|
52
|
+
model = text(line.message.model) ?? model;
|
|
53
|
+
}
|
|
54
|
+
return { harnessVersion, model, effort };
|
|
55
|
+
};
|
|
56
|
+
/** The same from a transcript file. A file that cannot be read states nothing: telemetry must never cost a hook its answer. */
|
|
57
|
+
export const statedAt = async (file) => {
|
|
58
|
+
try {
|
|
59
|
+
return statedOf(await tailOf(file));
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
return { harnessVersion: null, model: null, effort: null };
|
|
63
|
+
}
|
|
64
|
+
};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type SessionObservation, type Skeleton, type SkeletonLine, type ToolObservation } from './schema.js';
|
|
2
|
+
export interface InvariantResult {
|
|
3
|
+
name: string;
|
|
4
|
+
/** What was compared: lines, pairs, or tool results, as each invariant defines it. */
|
|
5
|
+
checked: number;
|
|
6
|
+
violations: number;
|
|
7
|
+
/** Checks that neither hold nor fail, each counted under the cause it was traced to (the cost-state check only). */
|
|
8
|
+
observed?: ObservedClass[];
|
|
9
|
+
}
|
|
10
|
+
export type CostClass = 'resume scope' | 'subagent transcripts' | 'harness side calls' | 'other';
|
|
11
|
+
export interface ObservedClass {
|
|
12
|
+
cls: CostClass;
|
|
13
|
+
/** True for a check that holds only once its scope is applied; false for a total above the recorded sum. */
|
|
14
|
+
holds: boolean;
|
|
15
|
+
checks: number;
|
|
16
|
+
/** The first session seen in the class. */
|
|
17
|
+
example: string | null;
|
|
18
|
+
}
|
|
19
|
+
export declare const INVARIANTS: readonly ["tool_result names an earlier tool_use", "parentUuid resolves in the file", "message timestamps never step back more than 1 s", "assistant lines carry a request id; shared ids have consecutive apiBlockIndex", "thinking tokens never exceed output tokens", "cost-state totals equal summed usage since the process start, subagents included"];
|
|
20
|
+
/** `delegated` holds the lines of the session's subagent transcripts, which its cost-state totals include. */
|
|
21
|
+
export declare const verifySkeleton: (skeleton: Skeleton, delegated?: readonly SkeletonLine[]) => InvariantResult[];
|
|
22
|
+
/** Sums each invariant over many skeletons, each main session's cost-state checked with its subagent transcripts' lines. */
|
|
23
|
+
export declare const verifyAll: (skeletons: readonly Skeleton[], delegatedFrom?: readonly Skeleton[]) => InvariantResult[];
|
|
24
|
+
export declare const formatVerify: (results: readonly InvariantResult[], sessions: number) => string;
|
|
25
|
+
export declare const CAPTURE_INVARIANTS: readonly ["every session is captured at the current capture version (none is cv-behind)", "sessions captured at the current version share one sid", "every fileHash on a session is a path target of one of its tool calls", "a path target names its base; no other target does"];
|
|
26
|
+
/**
|
|
27
|
+
* The CAPTURE 4 fields, checked over the store's capture records: cv-behind sessions (a session captured at an older readable
|
|
28
|
+
* version, not yet captured again, unless `frozen` names it: its transcript is gone from the harness and `raw/` (or, for a Cursor
|
|
29
|
+
* session, its composer is gone from Cursor), so it is counted apart, never a violation), a mixed `sid` (two salts in one store, so
|
|
30
|
+
* path joins hold only within each), `fileHashes` that no tool call explains, and `targetBase` set on, or missing from, the wrong
|
|
31
|
+
* kind of target. Skeleton invariants stay in {@link verifyAll}.
|
|
32
|
+
*/
|
|
33
|
+
export declare const verifyCaptured: (sessions: readonly SessionObservation[], tools: readonly ToolObservation[], frozen?: ReadonlySet<string>) => InvariantResult[];
|
|
34
|
+
/** `not run` when a row had nothing to check (a session behind the current capture version for rows 8 to 10, a transcript with no stamped lines for row 3, and so on). */
|
|
35
|
+
export type RowStatus = 'pass' | 'fail' | 'not run';
|
|
36
|
+
/** One session's result: the ten rows of {@link INVARIANTS} then {@link CAPTURE_INVARIANTS}, each with its status (spec 5.4 item 5). */
|
|
37
|
+
export interface SessionVerification {
|
|
38
|
+
session: string;
|
|
39
|
+
invariants: Array<InvariantResult & {
|
|
40
|
+
status: RowStatus;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A result for every session with a skeleton or a capture record: {@link verifySkeleton} with the session's subagent transcripts' lines as `delegated`,
|
|
45
|
+
* then {@link verifyCaptured} over the session's own capture records. A session with no skeleton gets rows 1 to 6 at `checked: 0` (`not run`) and its real
|
|
46
|
+
* rows 7 to 10. Row 8 (one `sid`) is read within the one session, so it cannot fail for a session with a non-null `sid`; a current-version session with a
|
|
47
|
+
* null `sid` fails it. The store-wide row stays in `verifyCaptured` over all sessions.
|
|
48
|
+
*/
|
|
49
|
+
export declare const verifySessions: (skeletons: readonly Skeleton[], sessions: readonly SessionObservation[], tools: readonly ToolObservation[], frozen?: ReadonlySet<string>) => SessionVerification[];
|
|
50
|
+
/** Per-session lines the default text prints; the JSON lists them all. */
|
|
51
|
+
export declare const SESSION_LINE_CAP = 20;
|
|
52
|
+
/** One line per session with a failing row, naming the rows, capped at {@link SESSION_LINE_CAP} with a count of the rest; empty when none fails. Ids and row names only. */
|
|
53
|
+
export declare const formatSessionResults: (results: readonly SessionVerification[]) => string;
|