@compaction/cli 0.1.4 → 0.3.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 +51 -12
- package/dist/cli/commands/activity.d.ts +8 -0
- package/dist/cli/commands/activity.js +35 -0
- package/dist/cli/commands/apply-context.js +68 -0
- package/dist/cli/commands/billing-delta.js +12 -1
- package/dist/cli/commands/capture-claude-code.d.ts +44 -0
- package/dist/cli/commands/capture-claude-code.js +206 -0
- package/dist/cli/commands/capture.js +283 -1
- package/dist/cli/commands/compact.js +24 -11
- package/dist/cli/commands/context.d.ts +2 -0
- package/dist/cli/commands/context.js +130 -0
- package/dist/cli/commands/dev.d.ts +17 -0
- package/dist/cli/commands/dev.js +131 -0
- package/dist/cli/commands/gateway.d.ts +31 -0
- package/dist/cli/commands/gateway.js +312 -0
- package/dist/cli/commands/hooks.d.ts +5 -0
- package/dist/cli/commands/hooks.js +181 -0
- package/dist/cli/commands/import.js +3 -1
- package/dist/cli/commands/init.js +422 -17
- package/dist/cli/commands/input-compaction-ab.d.ts +2 -0
- package/dist/cli/commands/input-compaction-ab.js +125 -0
- package/dist/cli/commands/optimize-hosted.d.ts +54 -0
- package/dist/cli/commands/optimize-hosted.js +123 -0
- package/dist/cli/commands/optimize.js +8 -0
- package/dist/cli/commands/output-shaping-ab.d.ts +2 -0
- package/dist/cli/commands/output-shaping-ab.js +132 -0
- package/dist/cli/commands/output-shaping.d.ts +7 -0
- package/dist/cli/commands/output-shaping.js +43 -0
- package/dist/cli/commands/policies.d.ts +2 -0
- package/dist/cli/commands/policies.js +80 -0
- package/dist/cli/commands/precall.d.ts +19 -0
- package/dist/cli/commands/precall.js +436 -0
- package/dist/cli/commands/recommend.js +1 -1
- package/dist/cli/commands/run.js +310 -18
- package/dist/cli/commands/upgrade-status.d.ts +42 -0
- package/dist/cli/commands/upgrade-status.js +152 -0
- package/dist/cli/cursor-export-read.d.ts +13 -0
- package/dist/cli/cursor-export-read.js +53 -0
- package/dist/cli/cursor-live-preflight.d.ts +19 -0
- package/dist/cli/cursor-live-preflight.js +46 -0
- package/dist/cli/index.js +39 -2
- package/dist/cli/onboarding/GatewayTui.d.ts +33 -0
- package/dist/cli/onboarding/GatewayTui.js +113 -0
- package/dist/cli/onboarding/model.d.ts +32 -1
- package/dist/cli/onboarding/model.js +27 -2
- package/dist/cli/terminal-logo.d.ts +27 -0
- package/dist/cli/terminal-logo.js +49 -0
- package/dist/core/activity-event.d.ts +107 -0
- package/dist/core/activity-event.js +182 -0
- package/dist/core/activity-store.d.ts +63 -0
- package/dist/core/activity-store.js +254 -0
- package/dist/core/activity-view.d.ts +76 -0
- package/dist/core/activity-view.js +120 -0
- package/dist/core/api-client/index.d.ts +3 -1
- package/dist/core/api-client/index.js +4 -0
- package/dist/core/api-client/payload.d.ts +5 -1
- package/dist/core/api-client/payload.js +8 -6
- package/dist/core/api-client/persisted-config.d.ts +57 -0
- package/dist/core/api-client/persisted-config.js +156 -0
- package/dist/core/api-client/tool.d.ts +29 -0
- package/dist/core/api-client/tool.js +50 -0
- package/dist/core/api-client/types.d.ts +15 -4
- package/dist/core/auto-apply-ask.d.ts +58 -0
- package/dist/core/auto-apply-ask.js +105 -0
- package/dist/core/auto-apply-gates.d.ts +76 -0
- package/dist/core/auto-apply-gates.js +113 -0
- package/dist/core/before-call-activity.d.ts +35 -0
- package/dist/core/before-call-activity.js +103 -0
- package/dist/core/before-call-recovery.d.ts +19 -0
- package/dist/core/before-call-recovery.js +46 -0
- package/dist/core/before-call-stdin.d.ts +59 -0
- package/dist/core/before-call-stdin.js +78 -0
- package/dist/core/before-call.d.ts +149 -0
- package/dist/core/before-call.js +358 -0
- package/dist/core/billing-delta/billing-delta-record.d.ts +28 -0
- package/dist/core/billing-delta/billing-delta-record.js +26 -0
- package/dist/core/capture-record.d.ts +40 -0
- package/dist/core/capture-record.js +55 -0
- package/dist/core/claude-code-before-call.d.ts +37 -0
- package/dist/core/claude-code-before-call.js +120 -0
- package/dist/core/claude-code-connect.d.ts +31 -0
- package/dist/core/claude-code-connect.js +87 -0
- package/dist/core/claude-code-hook-record.d.ts +71 -0
- package/dist/core/claude-code-hook-record.js +0 -0
- package/dist/core/claude-code-hooks.d.ts +77 -0
- package/dist/core/claude-code-hooks.js +141 -0
- package/dist/core/codex-capture.d.ts +45 -0
- package/dist/core/codex-capture.js +204 -0
- package/dist/core/command-runner.js +5 -1
- package/dist/core/compaction-artifacts.d.ts +51 -0
- package/dist/core/compaction-artifacts.js +242 -0
- package/dist/core/compactor.d.ts +9 -0
- package/dist/core/compactor.js +95 -0
- package/dist/core/context-store-eval-cases.d.ts +6 -0
- package/dist/core/context-store-eval-cases.js +331 -0
- package/dist/core/context-store-eval.d.ts +140 -0
- package/dist/core/context-store-eval.js +138 -0
- package/dist/core/context-store-fs.d.ts +73 -0
- package/dist/core/context-store-fs.js +157 -0
- package/dist/core/context-store-sufficiency.d.ts +98 -0
- package/dist/core/context-store-sufficiency.js +135 -0
- package/dist/core/context-store.d.ts +155 -0
- package/dist/core/context-store.js +228 -0
- package/dist/core/cross-surface-event.d.ts +306 -0
- package/dist/core/cross-surface-event.js +330 -0
- package/dist/core/cursor-capture.d.ts +54 -0
- package/dist/core/cursor-capture.js +215 -0
- package/dist/core/cursor-preflight-probe.d.ts +8 -0
- package/dist/core/cursor-preflight-probe.js +88 -0
- package/dist/core/cursor-preflight.d.ts +86 -0
- package/dist/core/cursor-preflight.js +126 -0
- package/dist/core/gateway/apply-activation.d.ts +39 -0
- package/dist/core/gateway/apply-activation.js +84 -0
- package/dist/core/gateway/apply-policy.d.ts +64 -0
- package/dist/core/gateway/apply-policy.js +221 -0
- package/dist/core/gateway/apply-receipt.d.ts +36 -0
- package/dist/core/gateway/apply-receipt.js +75 -0
- package/dist/core/gateway/cache-proof.d.ts +45 -0
- package/dist/core/gateway/cache-proof.js +65 -0
- package/dist/core/gateway/configure.d.ts +50 -0
- package/dist/core/gateway/configure.js +169 -0
- package/dist/core/gateway/openai-usage.d.ts +56 -0
- package/dist/core/gateway/openai-usage.js +128 -0
- package/dist/core/gateway/receipt.d.ts +138 -0
- package/dist/core/gateway/receipt.js +120 -0
- package/dist/core/gateway/recovery.d.ts +23 -0
- package/dist/core/gateway/recovery.js +68 -0
- package/dist/core/gateway/server.d.ts +51 -0
- package/dist/core/gateway/server.js +276 -0
- package/dist/core/gateway/status.d.ts +45 -0
- package/dist/core/gateway/status.js +109 -0
- package/dist/core/hook-usage-aggregate.d.ts +47 -0
- package/dist/core/hook-usage-aggregate.js +161 -0
- package/dist/core/input-compaction-ab.d.ts +111 -0
- package/dist/core/input-compaction-ab.js +158 -0
- package/dist/core/local-run-record.d.ts +109 -0
- package/dist/core/local-run-record.js +223 -0
- package/dist/core/output-shaping-ab.d.ts +140 -0
- package/dist/core/output-shaping-ab.js +146 -0
- package/dist/core/output-shaping-attach.d.ts +31 -0
- package/dist/core/output-shaping-attach.js +57 -0
- package/dist/core/output-shaping.d.ts +56 -0
- package/dist/core/output-shaping.js +89 -0
- package/dist/core/policy-middleware.d.ts +121 -0
- package/dist/core/policy-middleware.js +919 -0
- package/dist/core/policy-preferences.d.ts +99 -0
- package/dist/core/policy-preferences.js +232 -0
- package/dist/core/report-generator.d.ts +19 -1
- package/dist/core/report-generator.js +51 -0
- package/dist/core/run-aggregator.d.ts +56 -1
- package/dist/core/run-aggregator.js +93 -2
- package/dist/core/run-flow-report.d.ts +82 -0
- package/dist/core/run-flow-report.js +71 -0
- package/dist/core/safety-report.js +8 -1
- package/dist/core/shim-capture-bridge.d.ts +32 -0
- package/dist/core/shim-capture-bridge.js +88 -0
- package/dist/core/skill-injection-policy.d.ts +72 -0
- package/dist/core/skill-injection-policy.js +183 -0
- package/dist/core/spend-attribution.js +1 -1
- package/dist/core/token-accounting.d.ts +1 -1
- package/dist/core/tool-shim.d.ts +129 -0
- package/dist/core/tool-shim.js +447 -0
- package/dist/core/trace-adapters.d.ts +8 -0
- package/dist/core/trace-adapters.js +4 -0
- package/dist/core/trace-parser.d.ts +13 -13
- package/dist/core/trace-parser.js +6 -6
- package/dist/core/types.d.ts +45 -2
- package/dist/core/waste-detector.d.ts +20 -0
- package/dist/core/waste-detector.js +160 -6
- package/package.json +1 -1
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { contentHash } from "./content-hash.js";
|
|
2
|
+
import { estimateTextTokens } from "./token-estimator.js";
|
|
3
|
+
import { computeTraceFingerprint } from "./trace-fingerprint.js";
|
|
4
|
+
/**
|
|
5
|
+
* V0.4 context store — rung-1 (local, deterministic, source-grounded).
|
|
6
|
+
*
|
|
7
|
+
* SCOPE (accepted design doc `docs/design/v0.4-context-store-retrieval.md`,
|
|
8
|
+
* 2026-06-24): a durable, local, file-based store of source-pointed context items
|
|
9
|
+
* accumulated across runs, plus DETERMINISTIC local retrieval and assembly under a
|
|
10
|
+
* token budget. This module is the rung-1 core.
|
|
11
|
+
*
|
|
12
|
+
* HARD NON-GOALS (load-bearing — do not add here):
|
|
13
|
+
* - NO semantic / embedding retrieval. Retrieval ranks by deterministic signals only
|
|
14
|
+
* (source-pointer match, lexical overlap, recency). Semantic retrieval needs a model
|
|
15
|
+
* → not free-CLI local-first → deferred to the gated private engine/API.
|
|
16
|
+
* - NO network call, credential, upload, or model invocation. This module is pure +
|
|
17
|
+
* local-file I/O only (see `loadContextStore` / `appendContextItems`).
|
|
18
|
+
* - NO hosted DB / vector store / auth.
|
|
19
|
+
* - NO large-memory / 300M-token / retrieval-correctness claim. Those are gated on the
|
|
20
|
+
* four-axis eval harness (a follow-up increment) and rung-6 evidence.
|
|
21
|
+
*
|
|
22
|
+
* HONESTY: token figures here are `local_estimate` (chars/4), never provider-reported.
|
|
23
|
+
* Every stored item retains its `source_pointer` + recoverability so the assembled
|
|
24
|
+
* context stays recoverable to its sources (the substrate invariant).
|
|
25
|
+
*/
|
|
26
|
+
/** Algorithm + schema version, so a persisted store is self-describing. */
|
|
27
|
+
export const CONTEXT_STORE_ITEM_VERSION = "context-store-item-v1";
|
|
28
|
+
function normalizeContent(content) {
|
|
29
|
+
return content.trim().replace(/\s+/g, " ");
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Build a single context item, deriving the dedup hash + local token estimate.
|
|
33
|
+
* Pure — no I/O, no clock (the caller supplies `created_at` so this stays
|
|
34
|
+
* deterministic and testable).
|
|
35
|
+
*/
|
|
36
|
+
export function makeContextItem(input) {
|
|
37
|
+
const content = normalizeContent(input.content);
|
|
38
|
+
return {
|
|
39
|
+
version: CONTEXT_STORE_ITEM_VERSION,
|
|
40
|
+
content_sha256: contentHash(content),
|
|
41
|
+
content,
|
|
42
|
+
estimated_tokens: estimateTextTokens(content),
|
|
43
|
+
source_pointer: input.source_pointer,
|
|
44
|
+
recoverability: input.recoverability ?? "unknown",
|
|
45
|
+
trace_fingerprint: input.trace_fingerprint,
|
|
46
|
+
source_trace_id: input.source_trace_id,
|
|
47
|
+
provenance: input.provenance,
|
|
48
|
+
labels: input.labels ? [...input.labels] : [],
|
|
49
|
+
created_at: input.created_at
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Derive context items from a `StateCapsule`. Each retained fact / open question /
|
|
54
|
+
* safety note becomes a source-pointed item, inheriting the capsule's source pointer +
|
|
55
|
+
* recoverability + the originating trace id (and the supplied per-run fingerprint).
|
|
56
|
+
* Pure — `created_at` is supplied by the caller.
|
|
57
|
+
*/
|
|
58
|
+
export function contextItemsFromCapsule(capsule, opts) {
|
|
59
|
+
const primaryProvenance = capsule.provenance_entries?.[0];
|
|
60
|
+
const base = {
|
|
61
|
+
source_pointer: capsule.source_pointer ?? primaryProvenance?.source_pointer,
|
|
62
|
+
recoverability: capsule.source_recoverable ?? primaryProvenance?.source_recoverable ?? "unknown",
|
|
63
|
+
source_trace_id: capsule.source_trace_id ?? capsule.traceId,
|
|
64
|
+
provenance: primaryProvenance,
|
|
65
|
+
trace_fingerprint: opts.trace_fingerprint,
|
|
66
|
+
created_at: opts.created_at
|
|
67
|
+
};
|
|
68
|
+
const items = [];
|
|
69
|
+
for (const fact of capsule.retainedFacts) {
|
|
70
|
+
if (fact.trim().length === 0)
|
|
71
|
+
continue;
|
|
72
|
+
items.push(makeContextItem({ ...base, content: fact, labels: ["retained_fact"] }));
|
|
73
|
+
}
|
|
74
|
+
for (const question of capsule.openQuestions) {
|
|
75
|
+
if (question.trim().length === 0)
|
|
76
|
+
continue;
|
|
77
|
+
items.push(makeContextItem({ ...base, content: question, labels: ["open_question"] }));
|
|
78
|
+
}
|
|
79
|
+
for (const note of capsule.safetyNotes) {
|
|
80
|
+
if (note.trim().length === 0)
|
|
81
|
+
continue;
|
|
82
|
+
items.push(makeContextItem({ ...base, content: note, labels: ["safety_note"] }));
|
|
83
|
+
}
|
|
84
|
+
return dedupeContextItems(items);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Derive context items from a normalized `AgentTrace` (the local artifact `compaction capture`
|
|
88
|
+
* / `import` produces). Each non-empty message becomes a source-pointed item recoverable to its
|
|
89
|
+
* `trace=<id> message=<id>` origin, tagged with the run's distinctness fingerprint. This is the
|
|
90
|
+
* free-CLI populate path (state-capsules require the gated engine; trace messages do not). Pure —
|
|
91
|
+
* `created_at` is supplied by the caller.
|
|
92
|
+
*/
|
|
93
|
+
export function contextItemsFromTrace(trace, opts) {
|
|
94
|
+
const trace_fingerprint = computeTraceFingerprint(trace).content_sha256;
|
|
95
|
+
const items = [];
|
|
96
|
+
for (const message of trace.messages) {
|
|
97
|
+
if (message.content.trim().length === 0)
|
|
98
|
+
continue;
|
|
99
|
+
const labels = [message.role];
|
|
100
|
+
if (message.toolName)
|
|
101
|
+
labels.push(message.toolName);
|
|
102
|
+
items.push(makeContextItem({
|
|
103
|
+
content: message.content,
|
|
104
|
+
source_pointer: `trace=${trace.id} message=${message.id}`,
|
|
105
|
+
source_trace_id: trace.id,
|
|
106
|
+
recoverability: true,
|
|
107
|
+
trace_fingerprint,
|
|
108
|
+
labels,
|
|
109
|
+
created_at: opts.created_at
|
|
110
|
+
}));
|
|
111
|
+
}
|
|
112
|
+
return dedupeContextItems(items);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Dedup by `content_sha256`, keeping the EARLIEST item deterministically (ties broken
|
|
116
|
+
* by `created_at`, then by the existing order). Reuses the fingerprint discipline:
|
|
117
|
+
* byte-identical content is one item, not many. Output order follows the
|
|
118
|
+
* first-occurrence order of each distinct hash in the input array.
|
|
119
|
+
*/
|
|
120
|
+
export function dedupeContextItems(items) {
|
|
121
|
+
const byHash = new Map();
|
|
122
|
+
for (const item of items) {
|
|
123
|
+
const existing = byHash.get(item.content_sha256);
|
|
124
|
+
if (!existing || item.created_at < existing.created_at) {
|
|
125
|
+
// Merge labels so a later duplicate's labels are not lost.
|
|
126
|
+
if (existing) {
|
|
127
|
+
const labels = Array.from(new Set([...item.labels, ...existing.labels])).sort();
|
|
128
|
+
byHash.set(item.content_sha256, { ...item, labels });
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
byHash.set(item.content_sha256, item);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
const labels = Array.from(new Set([...existing.labels, ...item.labels])).sort();
|
|
136
|
+
byHash.set(item.content_sha256, { ...existing, labels });
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return Array.from(byHash.values());
|
|
140
|
+
}
|
|
141
|
+
const WORD_RE = /[a-z0-9]+/g;
|
|
142
|
+
function tokenSet(text) {
|
|
143
|
+
const set = new Set();
|
|
144
|
+
const matches = text.toLowerCase().match(WORD_RE);
|
|
145
|
+
if (matches) {
|
|
146
|
+
for (const word of matches)
|
|
147
|
+
set.add(word);
|
|
148
|
+
}
|
|
149
|
+
return set;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Deterministic, local retrieval. Ranks items by:
|
|
153
|
+
* score = sourceMatchWeight * (exact source/trace match ? 1 : 0)
|
|
154
|
+
* + lexicalWeight * lexical overlap coefficient in [0,1]
|
|
155
|
+
*
|
|
156
|
+
* Ties are broken deterministically by recency (newer first) then `content_sha256`
|
|
157
|
+
* ascending, so the same store + query always yields the same order. No model, no
|
|
158
|
+
* embeddings, no network — overlap is a pure word-set intersection.
|
|
159
|
+
*/
|
|
160
|
+
export function retrieveContextItems(items, query, options = {}) {
|
|
161
|
+
const sourceWeight = options.sourceMatchWeight ?? 1;
|
|
162
|
+
const lexicalWeight = options.lexicalWeight ?? 1;
|
|
163
|
+
const queryWords = tokenSet(query.text);
|
|
164
|
+
const wantedPointers = new Set(query.source_pointers ?? []);
|
|
165
|
+
const wantedTraces = new Set(query.trace_ids ?? []);
|
|
166
|
+
const ranked = items.map((item) => {
|
|
167
|
+
const sourceMatch = (item.source_pointer !== undefined && wantedPointers.has(item.source_pointer)) ||
|
|
168
|
+
(item.source_trace_id !== undefined && wantedTraces.has(item.source_trace_id));
|
|
169
|
+
let overlap = 0;
|
|
170
|
+
if (queryWords.size > 0) {
|
|
171
|
+
const itemWords = tokenSet(item.content);
|
|
172
|
+
if (itemWords.size > 0) {
|
|
173
|
+
let intersection = 0;
|
|
174
|
+
const [small, large] = queryWords.size <= itemWords.size ? [queryWords, itemWords] : [itemWords, queryWords];
|
|
175
|
+
for (const word of small) {
|
|
176
|
+
if (large.has(word))
|
|
177
|
+
intersection += 1;
|
|
178
|
+
}
|
|
179
|
+
// Overlap coefficient: intersection / min(|q|, |item|) — in [0, 1].
|
|
180
|
+
overlap = intersection / Math.min(queryWords.size, itemWords.size);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
const score = sourceWeight * (sourceMatch ? 1 : 0) + lexicalWeight * overlap;
|
|
184
|
+
return { item, score, source_match: sourceMatch, lexical_overlap: overlap };
|
|
185
|
+
});
|
|
186
|
+
ranked.sort((a, b) => {
|
|
187
|
+
if (b.score !== a.score)
|
|
188
|
+
return b.score - a.score;
|
|
189
|
+
if (a.item.created_at !== b.item.created_at)
|
|
190
|
+
return a.item.created_at < b.item.created_at ? 1 : -1;
|
|
191
|
+
return a.item.content_sha256 < b.item.content_sha256 ? -1 : 1;
|
|
192
|
+
});
|
|
193
|
+
const withSignal = ranked.filter((entry) => entry.score > 0);
|
|
194
|
+
return options.limit !== undefined ? withSignal.slice(0, options.limit) : withSignal;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Assemble ranked items into the sufficient active context under a token budget.
|
|
198
|
+
* Greedy in ranked order; dedups by `content_sha256`; PRESERVES the source pointer +
|
|
199
|
+
* provenance on every included item (so the assembled context stays recoverable).
|
|
200
|
+
* Token figures are local estimates.
|
|
201
|
+
*/
|
|
202
|
+
export function assembleContext(ranked, options) {
|
|
203
|
+
const items = ranked.map((entry) => ("item" in entry ? entry.item : entry));
|
|
204
|
+
const included = [];
|
|
205
|
+
const dropped = [];
|
|
206
|
+
const seen = new Set();
|
|
207
|
+
let total = 0;
|
|
208
|
+
for (const item of items) {
|
|
209
|
+
if (seen.has(item.content_sha256))
|
|
210
|
+
continue;
|
|
211
|
+
seen.add(item.content_sha256);
|
|
212
|
+
if (total + item.estimated_tokens <= options.tokenBudget) {
|
|
213
|
+
included.push(item);
|
|
214
|
+
total += item.estimated_tokens;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
dropped.push(item);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
text: included.map((item) => item.content).join("\n"),
|
|
222
|
+
included,
|
|
223
|
+
dropped,
|
|
224
|
+
estimated_tokens: total,
|
|
225
|
+
within_budget: dropped.length === 0
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=context-store.js.map
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ADDITIVE typed representation of the cross-surface evidence & reporting contract —
|
|
3
|
+
* `docs/ops/cross-surface-evidence-contract.md` (authority doc; founder decisions D1–D6, 2026-07-03).
|
|
4
|
+
*
|
|
5
|
+
* One event model, many surfaces: every Compaction surface reports the SAME kind of event with
|
|
6
|
+
* different honest evidence tiers. This module is the *contract/type level* of that model:
|
|
7
|
+
*
|
|
8
|
+
* - It is ADDITIVE. It does NOT change the existing `usage_event` wire shape
|
|
9
|
+
* (`src/core/capture-record.ts`), the local run record (`src/core/local-run-record.ts`), or any
|
|
10
|
+
* current writer/reader. No writer is REQUIRED to populate these fields (named follow-ups in
|
|
11
|
+
* the contract §7 stay follow-ups); the Cursor `run cursor` local run record is the first
|
|
12
|
+
* writer that does (D3 alignment, charter 2026-07-03-run-5), via
|
|
13
|
+
* `buildCursorRunCrossSurfaceEvent` below.
|
|
14
|
+
* - It makes the D5 HARD GUARDRAIL structural where TypeScript allows: a fixed-plan /
|
|
15
|
+
* plan-efficiency event can NEVER be billing-confirmed. `claim_scope:
|
|
16
|
+
* "billing-confirmed-workflow-scoped"` is only constructible on `surface: "api_metered"` with
|
|
17
|
+
* `cost_source: "provider-reported" | "operator-entered"` (contract §5 / D6), and a
|
|
18
|
+
* plan-efficiency payload structurally excludes it (`plan_efficiency?: never` on that arm;
|
|
19
|
+
* `billing_confirmed: false` is a literal type on the payload itself).
|
|
20
|
+
* - Where the type system cannot enforce a rule on parsed/unknown data, the REPORT-ONLY validator
|
|
21
|
+
* `validateCrossSurfaceEvent` catches it: it returns problems and never throws.
|
|
22
|
+
* - Honesty rails (contract §2): per-axis `token_source` with `unavailable_reason` required when
|
|
23
|
+
* unavailable; never a silent zero (an unavailable axis never carries a numeric count); input
|
|
24
|
+
* and output are independent axes; "generalized" is not a representable claim scope.
|
|
25
|
+
*
|
|
26
|
+
* NOTE on naming: contract `surface` values use underscores (`claude_code`, `browser_extension`)
|
|
27
|
+
* per the founder-verbatim field contract; the existing wire `ToolName` enum uses dashes
|
|
28
|
+
* (`claude-code`). `surfaceForToolName` maps between them without changing either.
|
|
29
|
+
*/
|
|
30
|
+
import type { ToolName } from "./api-client/index.js";
|
|
31
|
+
import type { RunFlowTokenReport } from "./run-flow-report.js";
|
|
32
|
+
/** Contract §2: which Compaction surface produced the event (exact values, verbatim). */
|
|
33
|
+
export declare const CROSS_SURFACE_SURFACES: readonly ["cli", "claude_code", "codex", "cursor", "browser_extension", "api_metered"];
|
|
34
|
+
export type CrossSurfaceSurface = (typeof CROSS_SURFACE_SURFACES)[number];
|
|
35
|
+
/** Contract §2: whose model/service was used — distinct from `surface`. */
|
|
36
|
+
export declare const CROSS_SURFACE_PROVIDERS: readonly ["anthropic", "openai", "cursor", "chatgpt", "other"];
|
|
37
|
+
export type CrossSurfaceProvider = (typeof CROSS_SURFACE_PROVIDERS)[number];
|
|
38
|
+
/** Contract §2: per-axis token source. Input and output are INDEPENDENT axes. */
|
|
39
|
+
export declare const CROSS_SURFACE_TOKEN_SOURCES: readonly ["provider-reported", "local-estimate", "unavailable"];
|
|
40
|
+
export type CrossSurfaceTokenSource = (typeof CROSS_SURFACE_TOKEN_SOURCES)[number];
|
|
41
|
+
/** Contract §2: how the cost figure (if any) is known. `operator-entered` is the billing-delta operator path. */
|
|
42
|
+
export declare const CROSS_SURFACE_COST_SOURCES: readonly ["provider-reported", "operator-entered", "local-estimate", "unavailable"];
|
|
43
|
+
export type CrossSurfaceCostSource = (typeof CROSS_SURFACE_COST_SOURCES)[number];
|
|
44
|
+
/** Contract §5 (D6): the ONLY cost sources that can underwrite a billing-confirmed figure. */
|
|
45
|
+
export type BillingConfirmedCostSource = "provider-reported" | "operator-entered";
|
|
46
|
+
/**
|
|
47
|
+
* Contract §2 honesty rule: what a figure may be scoped to — this run / this workflow / these
|
|
48
|
+
* conditions. A GENERALIZED claim is intentionally NOT representable (D6: "Generalized
|
|
49
|
+
* billing-confirmed = future only. Public generalized 'saves X%' is forbidden.").
|
|
50
|
+
* `billing-confirmed-workflow-scoped` exists only on the `BillingConfirmedCrossSurfaceEvent` arm.
|
|
51
|
+
*/
|
|
52
|
+
export declare const CROSS_SURFACE_CLAIM_SCOPES: readonly ["run-scoped", "workflow-scoped", "conditions-scoped", "billing-confirmed-workflow-scoped"];
|
|
53
|
+
export type CrossSurfaceClaimScope = (typeof CROSS_SURFACE_CLAIM_SCOPES)[number];
|
|
54
|
+
/** Every claim scope EXCEPT billing-confirmed — the only scopes a standard event may carry. */
|
|
55
|
+
export type NonBillingClaimScope = Exclude<CrossSurfaceClaimScope, "billing-confirmed-workflow-scoped">;
|
|
56
|
+
/** Contract §2: accepted/reverted — reverts are honest signal, never hidden. */
|
|
57
|
+
export type CrossSurfaceAcceptance = "accepted" | "reverted";
|
|
58
|
+
/** Contract §2: result of the applicable eval gate, or `not_evaluated` (never auto-certified). */
|
|
59
|
+
export type CrossSurfaceEvalStatus = "passed" | "failed" | "not_computed" | "not_evaluated";
|
|
60
|
+
/** How the underlying product is billed. `fixed-plan` marks quota/subscription billing (D5). */
|
|
61
|
+
export type CrossSurfaceBillingModel = "fixed-plan" | "metered" | "unknown";
|
|
62
|
+
/**
|
|
63
|
+
* One token axis: its honest source, plus the EXACT reason (and optional rerun guidance) when the
|
|
64
|
+
* axis is `unavailable`. Contract §2: "field-level unavailable WITH the exact reason".
|
|
65
|
+
*/
|
|
66
|
+
export interface CrossSurfaceTokenAxis {
|
|
67
|
+
source: CrossSurfaceTokenSource;
|
|
68
|
+
/** REQUIRED (validator-enforced) when `source` is "unavailable" — the exact honest reason. */
|
|
69
|
+
unavailable_reason?: string;
|
|
70
|
+
}
|
|
71
|
+
/** Per-axis token sources. Neither axis ever inherits the other's tier (contract §2). */
|
|
72
|
+
export interface CrossSurfaceTokenSources {
|
|
73
|
+
input: CrossSurfaceTokenAxis;
|
|
74
|
+
output: CrossSurfaceTokenAxis;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Contract §4 (D5): plan-efficiency — a NEW evidence type for fixed-plan products
|
|
78
|
+
* (quota-extension). DEFINED only; ZERO evidence exists today and no claim may be made.
|
|
79
|
+
* `billing_confirmed` is the LITERAL `false`: a plan-efficiency figure is structurally incapable
|
|
80
|
+
* of being billing-confirmed, however strong the measurement.
|
|
81
|
+
*/
|
|
82
|
+
export interface PlanEfficiencySignals {
|
|
83
|
+
evidence_type: "plan-efficiency";
|
|
84
|
+
/** HARD GUARDRAIL (D5): literal `false` — a fixed-plan figure can NEVER be billing-confirmed. */
|
|
85
|
+
billing_confirmed: false;
|
|
86
|
+
/** Identity of the quota window the signals were observed in (content-free). */
|
|
87
|
+
quota_window_id?: string;
|
|
88
|
+
/** More useful work per quota window (contract §4). */
|
|
89
|
+
tasks_completed_in_window?: number | null;
|
|
90
|
+
/** Fewer / later cap events (contract §4). */
|
|
91
|
+
cap_events_in_window?: number | null;
|
|
92
|
+
/** Fewer visible tokens per task — LOCAL-ESTIMATE per the tier table (contract §4). */
|
|
93
|
+
visible_tokens_per_task_estimate?: number | null;
|
|
94
|
+
/** More successful tasks before reset (contract §4). */
|
|
95
|
+
successful_tasks_before_reset?: number | null;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Fields shared by every event arm. ALL fields are optional/additive (contract §2: "a surface
|
|
99
|
+
* omits what it genuinely cannot observe, with a reason") — the discriminating fields live on the
|
|
100
|
+
* arms below. Counts may be `null` to mean "explicitly not counted" (never rendered as 0).
|
|
101
|
+
*/
|
|
102
|
+
export interface CrossSurfaceEventCommon {
|
|
103
|
+
/** Existing user/team model (paid reporting aggregates by these). Free/local may omit (no sync). */
|
|
104
|
+
user_id?: string;
|
|
105
|
+
team_id?: string;
|
|
106
|
+
/** Whose model/service was used — e.g. surface `browser_extension` + provider `chatgpt`. */
|
|
107
|
+
provider?: CrossSurfaceProvider;
|
|
108
|
+
/** The model as honestly known — `unknown` stays `unknown`, never inferred. */
|
|
109
|
+
model_label?: string;
|
|
110
|
+
/** Identity for rollup and A/B comparability (billing-delta requires pinned workflow identity). */
|
|
111
|
+
workflow_id?: string;
|
|
112
|
+
session_id?: string;
|
|
113
|
+
run_id?: string;
|
|
114
|
+
/** Input tokens before/after Compaction acted, counted per `token_source.input`. */
|
|
115
|
+
input_before?: number | null;
|
|
116
|
+
input_after?: number | null;
|
|
117
|
+
/** Output tokens before/after (or estimate), counted per `token_source.output`. */
|
|
118
|
+
output_before?: number | null;
|
|
119
|
+
output_after?: number | null;
|
|
120
|
+
/** An estimate is an estimate and says so — it never upgrades the axis tier. */
|
|
121
|
+
output_estimate?: number | null;
|
|
122
|
+
/** Per-axis honest sources. A numeric count without a labeled axis is a validator problem. */
|
|
123
|
+
token_source?: CrossSurfaceTokenSources;
|
|
124
|
+
/** Which deterministic policy acted (content-free identifier). */
|
|
125
|
+
policy_used?: string;
|
|
126
|
+
/** Whether the user kept or reverted the optimization. */
|
|
127
|
+
acceptance?: CrossSurfaceAcceptance;
|
|
128
|
+
/** Result of the applicable recoverability eval gate, or `not_evaluated`. */
|
|
129
|
+
recoverability?: CrossSurfaceEvalStatus;
|
|
130
|
+
/** Result of the applicable output eval gate (short-but-sufficient), or `not_evaluated`. */
|
|
131
|
+
eval_status?: CrossSurfaceEvalStatus;
|
|
132
|
+
/** The exact honest label for this event's figures — never stronger than the sources support. */
|
|
133
|
+
evidence_level?: string;
|
|
134
|
+
/** Per-surface honesty caveats carried WITH the event, never stripped in rollup. */
|
|
135
|
+
caveats?: string[];
|
|
136
|
+
/** Exact reason when `cost_source` is "unavailable". */
|
|
137
|
+
cost_unavailable_reason?: string;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* The standard event arm: any surface, any honest cost source, any NON-billing-confirmed claim
|
|
141
|
+
* scope. Fixed-plan surfaces and plan-efficiency events live here — and ONLY here.
|
|
142
|
+
*/
|
|
143
|
+
export interface StandardCrossSurfaceEvent extends CrossSurfaceEventCommon {
|
|
144
|
+
surface: CrossSurfaceSurface;
|
|
145
|
+
billing_model?: CrossSurfaceBillingModel;
|
|
146
|
+
cost_source?: CrossSurfaceCostSource;
|
|
147
|
+
/** Structurally excludes "billing-confirmed-workflow-scoped" (D5/D6). */
|
|
148
|
+
claim_scope?: NonBillingClaimScope;
|
|
149
|
+
/** Plan-efficiency signals (fixed-plan quota-extension) — never on the billing-confirmed arm. */
|
|
150
|
+
plan_efficiency?: PlanEfficiencySignals;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* The ONLY arm that can carry a billing-confirmed claim (contract §5 / D6): `api_metered`
|
|
154
|
+
* surface, provider-billed or operator-entered cost, workflow-scoped only. A plan-efficiency
|
|
155
|
+
* payload is structurally unrepresentable here (`never`), and `billing_model` can never be
|
|
156
|
+
* "fixed-plan".
|
|
157
|
+
*/
|
|
158
|
+
export interface BillingConfirmedCrossSurfaceEvent extends CrossSurfaceEventCommon {
|
|
159
|
+
surface: "api_metered";
|
|
160
|
+
claim_scope: "billing-confirmed-workflow-scoped";
|
|
161
|
+
cost_source: BillingConfirmedCostSource;
|
|
162
|
+
billing_model?: "metered";
|
|
163
|
+
plan_efficiency?: never;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* The cross-surface event. A discriminated union: constructing a fixed-plan / non-metered /
|
|
167
|
+
* plan-efficiency event with a billing-confirmed claim scope is a TYPE ERROR, not just a
|
|
168
|
+
* validator problem.
|
|
169
|
+
*/
|
|
170
|
+
export type CrossSurfaceEvent = StandardCrossSurfaceEvent | BillingConfirmedCrossSurfaceEvent;
|
|
171
|
+
type Assert<T extends true> = T;
|
|
172
|
+
type BillingConfirmedArm = Extract<CrossSurfaceEvent, {
|
|
173
|
+
claim_scope: "billing-confirmed-workflow-scoped";
|
|
174
|
+
}>;
|
|
175
|
+
/** The billing-confirmed arm exists (so the guards below can never pass vacuously via `never`). */
|
|
176
|
+
export type StructuralGuard_BillingConfirmedArmExists = Assert<[BillingConfirmedArm] extends [never] ? false : true>;
|
|
177
|
+
/** A billing-confirmed claim can ONLY exist on the api_metered surface. */
|
|
178
|
+
export type StructuralGuard_BillingConfirmedRequiresMeteredSurface = Assert<BillingConfirmedArm["surface"] extends "api_metered" ? true : false>;
|
|
179
|
+
/** A billing-confirmed claim can ONLY carry provider-reported | operator-entered cost. */
|
|
180
|
+
export type StructuralGuard_BillingConfirmedCostSource = Assert<BillingConfirmedArm["cost_source"] extends BillingConfirmedCostSource ? true : false>;
|
|
181
|
+
/** A billing-confirmed event can NEVER carry a plan-efficiency payload. */
|
|
182
|
+
export type StructuralGuard_BillingConfirmedExcludesPlanEfficiency = Assert<Required<BillingConfirmedArm>["plan_efficiency"] extends never ? true : false>;
|
|
183
|
+
/** A plan-efficiency payload is structurally incapable of claiming billing_confirmed. */
|
|
184
|
+
export type StructuralGuard_PlanEfficiencyNeverBillingConfirmed = Assert<PlanEfficiencySignals["billing_confirmed"] extends false ? true : false>;
|
|
185
|
+
/** A billing-confirmed event can never be marked fixed-plan. */
|
|
186
|
+
export type StructuralGuard_BillingConfirmedNeverFixedPlan = Assert<Required<BillingConfirmedArm>["billing_model"] extends "metered" ? true : false>;
|
|
187
|
+
/**
|
|
188
|
+
* Map the EXISTING wire `ToolName` to the contract `surface` value, honestly:
|
|
189
|
+
* - `claude-code` → `claude_code`, `codex` → `codex`, `cursor` → `cursor`;
|
|
190
|
+
* - `other` (the bare `compaction run -- <cmd>` wrapper) → `cli` per the tier table ("bare
|
|
191
|
+
* run/trace analysis without provider usage");
|
|
192
|
+
* - `openai-agents` → `undefined`: the contract names no surface for it, and unknown stays
|
|
193
|
+
* unknown — this helper never guesses (named residual, like the control-plane enum alignment).
|
|
194
|
+
*/
|
|
195
|
+
export declare function surfaceForToolName(tool: ToolName): CrossSurfaceSurface | undefined;
|
|
196
|
+
/**
|
|
197
|
+
* Contract tier table (§3, D3/D4): surfaces whose token tier can NEVER be provider-reported —
|
|
198
|
+
* Cursor emits no usage (vendor gap; "never provider-reported"), and the browser's visible
|
|
199
|
+
* surface exposes no provider usage ("may NOT claim provider-reported web tokens").
|
|
200
|
+
*/
|
|
201
|
+
export declare const NEVER_PROVIDER_REPORTED_SURFACES: readonly CrossSurfaceSurface[];
|
|
202
|
+
export interface CrossSurfaceEventValidation {
|
|
203
|
+
/** Empty when the event honors the contract. Report-only: nothing throws, nothing exits. */
|
|
204
|
+
problems: string[];
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Validate one parsed/unknown cross-surface event against the contract. REPORT-ONLY: returns the
|
|
208
|
+
* list of problems (empty = contract-honest) and NEVER throws — mirroring the repo's
|
|
209
|
+
* skipped-with-reason validator style. Rules enforced here are exactly the ones the type system
|
|
210
|
+
* cannot enforce on unknown data:
|
|
211
|
+
*
|
|
212
|
+
* 1. exact enums for surface / provider / token sources / cost source / claim scope;
|
|
213
|
+
* 2. D5 hard guardrail: a fixed-plan or plan-efficiency event is NEVER billing-confirmed;
|
|
214
|
+
* 3. D6: billing-confirmed requires surface api_metered + provider-reported|operator-entered cost;
|
|
215
|
+
* 4. tier table (D3/D4): cursor and browser_extension events never carry provider-reported tokens;
|
|
216
|
+
* 5. no silent zero: an unavailable axis never carries a numeric count;
|
|
217
|
+
* 6. per-axis unavailable_reason required when an axis is unavailable;
|
|
218
|
+
* 7. a numeric count requires its axis to be labeled (a count without a token_source is unlabeled).
|
|
219
|
+
*/
|
|
220
|
+
export declare function validateCrossSurfaceEvent(value: unknown): CrossSurfaceEventValidation;
|
|
221
|
+
/**
|
|
222
|
+
* Per-surface constraints for the `run` local-run-record writers (contract tier table §3):
|
|
223
|
+
* - `codex` — `run codex`: provider `openai`; token axes are provider-reported where a
|
|
224
|
+
* `turn.completed.usage` block existed (the report says which). Codex reports token usage but
|
|
225
|
+
* never a cost/billing figure, so cost is UNAVAILABLE with that exact reason.
|
|
226
|
+
* - `cursor` — `run cursor`: provider `cursor`; LOCAL-ESTIMATE/unavailable only (D3 ceiling —
|
|
227
|
+
* Cursor emits no usage), and no cost data exists at all.
|
|
228
|
+
* - `cli` — bare `run -- <cmd>`: an arbitrary wrapped command, provider `other` (no provider is
|
|
229
|
+
* involved that Compaction can observe); input is a local chars/4 estimate, output is
|
|
230
|
+
* unavailable with the command-surface reason, and no billing surface exists.
|
|
231
|
+
* - `claude_code` — the `capture claude-code --from-hook` always-on path (charter 2026-07-04-run-8):
|
|
232
|
+
* provider `anthropic`; token axes are PROVIDER-REPORTED where the Claude Code session usage
|
|
233
|
+
* fields carried them (the report says which — a missing axis stays unavailable-with-reason,
|
|
234
|
+
* never a silent zero). Claude Code reports tokens but no cost/billing figure, so cost is
|
|
235
|
+
* UNAVAILABLE with that exact reason. This is NOT invented evidence: the Stop-hook capture reads
|
|
236
|
+
* the session's OWN provider usage metadata — the same provider-reported tokens `capture
|
|
237
|
+
* claude-code` already surfaces — it simply also records a metrics-only activity event so a
|
|
238
|
+
* subsequent session appears in `compaction activity` with no manual import.
|
|
239
|
+
*/
|
|
240
|
+
export declare const RUN_RECORD_EVENT_SURFACES: {
|
|
241
|
+
readonly codex: {
|
|
242
|
+
readonly surface: "codex";
|
|
243
|
+
readonly provider: "openai";
|
|
244
|
+
readonly cost_unavailable_reason: "codex exec --json reports token usage (turn.completed.usage) but no cost or billing figure; no cost data exists on this path";
|
|
245
|
+
};
|
|
246
|
+
readonly claude_code: {
|
|
247
|
+
readonly surface: "claude_code";
|
|
248
|
+
readonly provider: "anthropic";
|
|
249
|
+
readonly cost_unavailable_reason: "Claude Code session usage reports provider tokens (input/output) but no cost or billing figure; no cost data exists on this path";
|
|
250
|
+
};
|
|
251
|
+
readonly cursor: {
|
|
252
|
+
readonly surface: "cursor";
|
|
253
|
+
readonly provider: "cursor";
|
|
254
|
+
readonly cost_unavailable_reason: "Cursor emits no usage or cost data; no cost figure exists for this run";
|
|
255
|
+
};
|
|
256
|
+
readonly cli: {
|
|
257
|
+
readonly surface: "cli";
|
|
258
|
+
readonly provider: "other";
|
|
259
|
+
readonly cost_unavailable_reason: "a bare wrapped command has no provider usage or billing surface; no cost figure exists for this run";
|
|
260
|
+
};
|
|
261
|
+
};
|
|
262
|
+
export type RunRecordEventSurface = keyof typeof RUN_RECORD_EVENT_SURFACES;
|
|
263
|
+
export interface RunCrossSurfaceEventParams {
|
|
264
|
+
runId: string;
|
|
265
|
+
tokenReport: RunFlowTokenReport;
|
|
266
|
+
/** TRUE per-axis unavailability reasons from the capture (required content for unavailable axes). */
|
|
267
|
+
reasons?: {
|
|
268
|
+
input?: string;
|
|
269
|
+
output?: string;
|
|
270
|
+
};
|
|
271
|
+
/** The model as the capture HONESTLY knows it. Omitted → "unknown" (unknown stays unknown, never inferred). */
|
|
272
|
+
modelLabel?: string;
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Build the honest cross-surface event for one `run` local run record (any of the three `run`
|
|
276
|
+
* surfaces above):
|
|
277
|
+
* - `surface`/`provider` fixed per surface; `model_label` only as honestly known, else `"unknown"`;
|
|
278
|
+
* - per-axis `token_source` copied VERBATIM from the token report (input and output INDEPENDENT),
|
|
279
|
+
* with the capture's TRUE per-run reason on any unavailable axis (never a bare "unavailable");
|
|
280
|
+
* - counts only on available axes, under the count field that matches the axis tier:
|
|
281
|
+
* `input_before` for the counted/estimated input; a provider-reported output is a COUNT
|
|
282
|
+
* (`output_before`), a local-estimate output is an ESTIMATE and says so (`output_estimate`) —
|
|
283
|
+
* an unavailable axis carries NO count (never a silent zero);
|
|
284
|
+
* - `cost_source: "unavailable"` with the exact per-surface reason (no `run` path has billing data);
|
|
285
|
+
* - `claim_scope: "run-scoped"` (never generalized); caveats = the report's honest notes.
|
|
286
|
+
*
|
|
287
|
+
* The tier ceilings stay intact: this builder never SETS provider-reported (it only copies the
|
|
288
|
+
* report's label), and if a never-provider-reported surface (Cursor) is handed one it passes it
|
|
289
|
+
* through unchanged so the report-only validator rejects it (rule 4) instead of hiding it.
|
|
290
|
+
*/
|
|
291
|
+
export declare function buildRunCrossSurfaceEvent(surfaceKey: RunRecordEventSurface, params: RunCrossSurfaceEventParams): StandardCrossSurfaceEvent;
|
|
292
|
+
/**
|
|
293
|
+
* The Cursor writer (D3 alignment, #583) — kept as the named entry point its call/test sites use;
|
|
294
|
+
* now a thin delegate to the generalized builder with the `cursor` constraints (`surface:
|
|
295
|
+
* "cursor"`, `provider: "cursor"`, `model_label: "unknown"` — never inferred, D3 ceiling intact).
|
|
296
|
+
*/
|
|
297
|
+
export declare function buildCursorRunCrossSurfaceEvent(params: {
|
|
298
|
+
runId: string;
|
|
299
|
+
tokenReport: RunFlowTokenReport;
|
|
300
|
+
/** TRUE per-axis unavailability reasons from the capture (required content for unavailable axes). */
|
|
301
|
+
reasons?: {
|
|
302
|
+
input?: string;
|
|
303
|
+
output?: string;
|
|
304
|
+
};
|
|
305
|
+
}): StandardCrossSurfaceEvent;
|
|
306
|
+
export {};
|