@manyoars/oars 0.1.1 → 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.
Files changed (240) hide show
  1. package/README.md +134 -26
  2. package/dist/api.js +1 -1
  3. package/dist/bin.js +6 -29
  4. package/dist/cli.d.ts +6 -3
  5. package/dist/cli.js +370 -72
  6. package/dist/commands/keys.d.ts +31 -0
  7. package/dist/commands/keys.js +65 -0
  8. package/dist/commands/login.d.ts +1 -1
  9. package/dist/commands/login.js +3 -5
  10. package/dist/errors.d.ts +13 -13
  11. package/dist/errors.js +28 -11
  12. package/dist/gate/checks.d.ts +68 -0
  13. package/dist/gate/checks.js +584 -0
  14. package/dist/gate/command.d.ts +14 -0
  15. package/dist/gate/command.js +61 -0
  16. package/dist/gate/hook-fill-main.d.ts +1 -0
  17. package/dist/gate/hook-fill-main.js +16 -0
  18. package/dist/gate/hook-fill.d.ts +38 -0
  19. package/dist/gate/hook-fill.js +94 -0
  20. package/dist/gate/hook-main.d.ts +1 -0
  21. package/dist/gate/hook-main.js +35 -0
  22. package/dist/gate/hook-process.d.ts +14 -0
  23. package/dist/gate/hook-process.js +64 -0
  24. package/dist/gate/hook.d.ts +46 -0
  25. package/dist/gate/hook.js +256 -0
  26. package/dist/gate/install.d.ts +25 -0
  27. package/dist/gate/install.js +126 -0
  28. package/dist/gate/local-bin.d.ts +8 -0
  29. package/dist/gate/local-bin.js +36 -0
  30. package/dist/gate/notes.d.ts +19 -0
  31. package/dist/gate/notes.js +27 -0
  32. package/dist/gate/novelty.d.ts +35 -0
  33. package/dist/gate/novelty.js +99 -0
  34. package/dist/gate/policy.d.ts +25 -0
  35. package/dist/gate/policy.js +73 -0
  36. package/dist/gate/record.d.ts +120 -0
  37. package/dist/gate/record.js +125 -0
  38. package/dist/gate/registry-state.d.ts +10 -0
  39. package/dist/gate/registry-state.js +30 -0
  40. package/dist/gate/registry.d.ts +56 -0
  41. package/dist/gate/registry.js +94 -0
  42. package/dist/gate/replay.d.ts +20 -0
  43. package/dist/gate/replay.js +257 -0
  44. package/dist/gate/report.d.ts +50 -0
  45. package/dist/gate/report.js +89 -0
  46. package/dist/gate/scope.d.ts +7 -0
  47. package/dist/gate/scope.js +27 -0
  48. package/dist/gate/transcripts.d.ts +68 -0
  49. package/dist/gate/transcripts.js +232 -0
  50. package/dist/hook-bin.d.ts +1 -0
  51. package/dist/hook-bin.js +25 -0
  52. package/dist/issuer.d.ts +16 -0
  53. package/dist/issuer.js +55 -0
  54. package/dist/main.d.ts +1 -0
  55. package/dist/main.js +64 -0
  56. package/dist/oidc.js +1 -1
  57. package/dist/sessions/actions.d.ts +35 -0
  58. package/dist/sessions/actions.js +351 -0
  59. package/dist/sessions/allow.d.ts +14 -0
  60. package/dist/sessions/allow.js +51 -0
  61. package/dist/sessions/archive.d.ts +11 -0
  62. package/dist/sessions/archive.js +38 -0
  63. package/dist/sessions/audit.d.ts +42 -0
  64. package/dist/sessions/audit.js +104 -0
  65. package/dist/sessions/baseline.d.ts +62 -0
  66. package/dist/sessions/baseline.js +188 -0
  67. package/dist/sessions/capture-runtime.d.ts +10 -0
  68. package/dist/sessions/capture-runtime.js +12 -0
  69. package/dist/sessions/cell-increments.d.ts +43 -0
  70. package/dist/sessions/cell-increments.js +209 -0
  71. package/dist/sessions/cells.d.ts +79 -0
  72. package/dist/sessions/cells.js +181 -0
  73. package/dist/sessions/codex.d.ts +53 -0
  74. package/dist/sessions/codex.js +679 -0
  75. package/dist/sessions/command.d.ts +117 -0
  76. package/dist/sessions/command.js +373 -0
  77. package/dist/sessions/copilot.d.ts +40 -0
  78. package/dist/sessions/copilot.js +432 -0
  79. package/dist/sessions/cursor.d.ts +24 -0
  80. package/dist/sessions/cursor.js +324 -0
  81. package/dist/sessions/derive.d.ts +57 -0
  82. package/dist/sessions/derive.js +320 -0
  83. package/dist/sessions/exclusion.d.ts +81 -0
  84. package/dist/sessions/exclusion.js +353 -0
  85. package/dist/sessions/extract.d.ts +179 -0
  86. package/dist/sessions/extract.js +1774 -0
  87. package/dist/sessions/fold.d.ts +17 -0
  88. package/dist/sessions/fold.js +71 -0
  89. package/dist/sessions/frame.d.ts +24 -0
  90. package/dist/sessions/frame.js +95 -0
  91. package/dist/sessions/gemini.d.ts +37 -0
  92. package/dist/sessions/gemini.js +613 -0
  93. package/dist/sessions/gold-arms.d.ts +67 -0
  94. package/dist/sessions/gold-arms.js +172 -0
  95. package/dist/sessions/gold.d.ts +197 -0
  96. package/dist/sessions/gold.js +463 -0
  97. package/dist/sessions/graph.d.ts +12 -0
  98. package/dist/sessions/graph.js +34 -0
  99. package/dist/sessions/grok.d.ts +36 -0
  100. package/dist/sessions/grok.js +421 -0
  101. package/dist/sessions/hook-calls.d.ts +3 -0
  102. package/dist/sessions/hook-calls.js +47 -0
  103. package/dist/sessions/hook-index.d.ts +53 -0
  104. package/dist/sessions/hook-index.js +157 -0
  105. package/dist/sessions/hooks.d.ts +13 -0
  106. package/dist/sessions/hooks.js +170 -0
  107. package/dist/sessions/identity.d.ts +22 -0
  108. package/dist/sessions/identity.js +101 -0
  109. package/dist/sessions/install.d.ts +54 -0
  110. package/dist/sessions/install.js +201 -0
  111. package/dist/sessions/lineage.d.ts +19 -0
  112. package/dist/sessions/lineage.js +118 -0
  113. package/dist/sessions/mcp.d.ts +6 -0
  114. package/dist/sessions/mcp.js +153 -0
  115. package/dist/sessions/merkle.d.ts +7 -0
  116. package/dist/sessions/merkle.js +28 -0
  117. package/dist/sessions/motif.d.ts +43 -0
  118. package/dist/sessions/motif.js +59 -0
  119. package/dist/sessions/package-resolve.d.ts +30 -0
  120. package/dist/sessions/package-resolve.js +183 -0
  121. package/dist/sessions/pending.d.ts +34 -0
  122. package/dist/sessions/pending.js +142 -0
  123. package/dist/sessions/pool-command.d.ts +44 -0
  124. package/dist/sessions/pool-command.js +542 -0
  125. package/dist/sessions/pool-delta.d.ts +54 -0
  126. package/dist/sessions/pool-delta.js +190 -0
  127. package/dist/sessions/pool-outbox.d.ts +63 -0
  128. package/dist/sessions/pool-outbox.js +260 -0
  129. package/dist/sessions/pool-print.d.ts +26 -0
  130. package/dist/sessions/pool-print.js +68 -0
  131. package/dist/sessions/pool-wire.d.ts +225 -0
  132. package/dist/sessions/pool-wire.js +620 -0
  133. package/dist/sessions/pool.d.ts +32 -0
  134. package/dist/sessions/pool.js +164 -0
  135. package/dist/sessions/projection.d.ts +75 -0
  136. package/dist/sessions/projection.js +165 -0
  137. package/dist/sessions/public-vocabulary.d.ts +73 -0
  138. package/dist/sessions/public-vocabulary.js +302 -0
  139. package/dist/sessions/query.d.ts +111 -0
  140. package/dist/sessions/query.js +246 -0
  141. package/dist/sessions/read-adoption.d.ts +2 -0
  142. package/dist/sessions/read-adoption.js +27 -0
  143. package/dist/sessions/read-call-shape.d.ts +2 -0
  144. package/dist/sessions/read-call-shape.js +25 -0
  145. package/dist/sessions/read-change.d.ts +2 -0
  146. package/dist/sessions/read-change.js +30 -0
  147. package/dist/sessions/read-cost.d.ts +4 -0
  148. package/dist/sessions/read-cost.js +37 -0
  149. package/dist/sessions/read-day-move.d.ts +3 -0
  150. package/dist/sessions/read-day-move.js +65 -0
  151. package/dist/sessions/read-fit.d.ts +7 -0
  152. package/dist/sessions/read-fit.js +41 -0
  153. package/dist/sessions/read-interaction.d.ts +5 -0
  154. package/dist/sessions/read-interaction.js +62 -0
  155. package/dist/sessions/read-lead-lag.d.ts +15 -0
  156. package/dist/sessions/read-lead-lag.js +81 -0
  157. package/dist/sessions/read-live.d.ts +6 -0
  158. package/dist/sessions/read-live.js +38 -0
  159. package/dist/sessions/read-method.d.ts +2 -0
  160. package/dist/sessions/read-method.js +29 -0
  161. package/dist/sessions/read-next-step.d.ts +2 -0
  162. package/dist/sessions/read-next-step.js +35 -0
  163. package/dist/sessions/read-order.d.ts +54 -0
  164. package/dist/sessions/read-order.js +62 -0
  165. package/dist/sessions/read-readable.d.ts +8 -0
  166. package/dist/sessions/read-readable.js +24 -0
  167. package/dist/sessions/read-recovery.d.ts +20 -0
  168. package/dist/sessions/read-recovery.js +97 -0
  169. package/dist/sessions/read-rows.d.ts +13 -0
  170. package/dist/sessions/read-rows.js +47 -0
  171. package/dist/sessions/read-substitution.d.ts +5 -0
  172. package/dist/sessions/read-substitution.js +51 -0
  173. package/dist/sessions/read-support.d.ts +48 -0
  174. package/dist/sessions/read-support.js +73 -0
  175. package/dist/sessions/read-tool-day.d.ts +2 -0
  176. package/dist/sessions/read-tool-day.js +26 -0
  177. package/dist/sessions/read-version-boundary.d.ts +31 -0
  178. package/dist/sessions/read-version-boundary.js +95 -0
  179. package/dist/sessions/read.d.ts +79 -0
  180. package/dist/sessions/read.js +84 -0
  181. package/dist/sessions/recall-consequence.d.ts +45 -0
  182. package/dist/sessions/recall-consequence.js +179 -0
  183. package/dist/sessions/recall-object.d.ts +137 -0
  184. package/dist/sessions/recall-object.js +77 -0
  185. package/dist/sessions/recall-pool.d.ts +19 -0
  186. package/dist/sessions/recall-pool.js +96 -0
  187. package/dist/sessions/recall-push.d.ts +26 -0
  188. package/dist/sessions/recall-push.js +95 -0
  189. package/dist/sessions/recall-reads.d.ts +117 -0
  190. package/dist/sessions/recall-reads.js +410 -0
  191. package/dist/sessions/recall-render.d.ts +19 -0
  192. package/dist/sessions/recall-render.js +168 -0
  193. package/dist/sessions/redact.d.ts +6 -0
  194. package/dist/sessions/redact.js +54 -0
  195. package/dist/sessions/repo-root.d.ts +10 -0
  196. package/dist/sessions/repo-root.js +101 -0
  197. package/dist/sessions/schema.d.ts +644 -0
  198. package/dist/sessions/schema.js +148 -0
  199. package/dist/sessions/session-shape.d.ts +73 -0
  200. package/dist/sessions/session-shape.js +342 -0
  201. package/dist/sessions/sources.d.ts +50 -0
  202. package/dist/sessions/sources.js +159 -0
  203. package/dist/sessions/steps.d.ts +105 -0
  204. package/dist/sessions/steps.js +250 -0
  205. package/dist/sessions/store.d.ts +297 -0
  206. package/dist/sessions/store.js +1478 -0
  207. package/dist/sessions/strata.d.ts +26 -0
  208. package/dist/sessions/strata.js +77 -0
  209. package/dist/sessions/survival.d.ts +25 -0
  210. package/dist/sessions/survival.js +230 -0
  211. package/dist/sessions/verify.d.ts +53 -0
  212. package/dist/sessions/verify.js +286 -0
  213. package/dist/sessions/vocab-load.d.ts +26 -0
  214. package/dist/sessions/vocab-load.js +61 -0
  215. package/dist/sessions/vscode-copilot.d.ts +38 -0
  216. package/dist/sessions/vscode-copilot.js +477 -0
  217. package/package.json +4 -5
  218. package/vocab/crates.json +1 -0
  219. package/vocab/go.json +1 -0
  220. package/vocab/harness.json +1 -0
  221. package/vocab/homebrew.json +1 -0
  222. package/vocab/manifest.json +1 -0
  223. package/vocab/maven.json +1 -0
  224. package/vocab/models.json +1 -0
  225. package/vocab/npm.json +1 -0
  226. package/vocab/programs.json +1 -0
  227. package/vocab/pypi.json +1 -0
  228. package/vocab/rubygems.json +1 -0
  229. package/dist/commands/deploy-input.d.ts +0 -35
  230. package/dist/commands/deploy-input.js +0 -107
  231. package/dist/commands/deploy.d.ts +0 -22
  232. package/dist/commands/deploy.js +0 -120
  233. package/dist/commands/status.d.ts +0 -7
  234. package/dist/commands/status.js +0 -18
  235. package/dist/commands/test-charge.d.ts +0 -11
  236. package/dist/commands/test-charge.js +0 -34
  237. package/dist/journal.d.ts +0 -26
  238. package/dist/journal.js +0 -58
  239. package/parity/deploy-plans/paid-api.json +0 -34
  240. package/parity/deploy-plans/per-task-agent.json +0 -34
@@ -0,0 +1,164 @@
1
+ // The derive pass over cells: motifs and cells from the store, each family's reads from those, and the files they are kept in. `cells.jsonl` and `motifs.jsonl` are
2
+ // rewritten from the log and can be dropped at any time. Each pool version's reads go in a file of their own that is written once and never rewritten, so a read cited by
3
+ // its ID stays what it was.
4
+ import { readdir, readFile, stat } from 'node:fs/promises';
5
+ import { basename, dirname, join } from 'node:path';
6
+ import { CliError, ExitCode } from '../errors.js';
7
+ import { cellsOf, projectedStore } from './cell-increments.js';
8
+ import { poolOf, serializeCells, UNKNOWN } from './cells.js';
9
+ import { shellReader } from './projection.js';
10
+ import { contentHash, FIRST_ORDER_FAMILIES, frozenRead, makeRead, orderResolver } from './read.js';
11
+ import { deriveConsequences, recallGraphOf } from './recall-consequence.js';
12
+ import { readRecalls } from './recall-object.js';
13
+ import { deriveAdoption } from './read-adoption.js';
14
+ import { deriveCallShape } from './read-call-shape.js';
15
+ import { deriveChange } from './read-change.js';
16
+ import { deriveCost } from './read-cost.js';
17
+ import { deriveFit } from './read-fit.js';
18
+ import { deriveLive } from './read-live.js';
19
+ import { deriveMethod } from './read-method.js';
20
+ import { deriveNextStep } from './read-next-step.js';
21
+ import { deriveRecovery } from './read-recovery.js';
22
+ import { deriveToolDay } from './read-tool-day.js';
23
+ import { vocabulary } from './vocab-load.js';
24
+ import { deriveDayMove } from './read-day-move.js';
25
+ import { deriveInteraction } from './read-interaction.js';
26
+ import { deriveLeadLag } from './read-lead-lag.js';
27
+ import { deriveSubstitution } from './read-substitution.js';
28
+ import { deriveVersionBoundary } from './read-version-boundary.js';
29
+ import { writeAtomic } from './store.js';
30
+ // Built on call.
31
+ const derivers = () => ({
32
+ recovery: deriveRecovery,
33
+ fit: (input) => [...deriveFit(input), ...deriveCallShape(input)],
34
+ cost: deriveCost,
35
+ change: deriveChange,
36
+ live: deriveLive,
37
+ adoption: deriveAdoption,
38
+ method: deriveMethod,
39
+ 'next-step': deriveNextStep,
40
+ 'tool-day': deriveToolDay,
41
+ });
42
+ /** Families over reads, one stage per order: a stage reads what the stages before it wrote. Built on call. */
43
+ const relations = () => [[deriveVersionBoundary, deriveSubstitution, deriveInteraction, deriveDayMove], [deriveLeadLag]];
44
+ export const poolFiles = (storeDir) => ({
45
+ cells: join(storeDir, 'cells.jsonl'),
46
+ consequences: join(storeDir, 'consequences.jsonl'),
47
+ motifs: join(storeDir, 'motifs.jsonl'),
48
+ reads: (version) => join(storeDir, 'reads', `${version}.jsonl`),
49
+ });
50
+ const made = (bodies, asOf, orderOf) => bodies
51
+ .map((body) => makeRead({ ...body, asOf }, orderOf))
52
+ .map((read) => ({ read, key: contentHash(read.slice) }))
53
+ .sort((a, b) => (a.key < b.key ? -1 : 1))
54
+ .map(({ read }) => read);
55
+ /** Every family's order 1 reads of one pool, in family order and then by slice, so a rerun writes the same bytes. */
56
+ export const deriveFirstOrder = (pool, store) => {
57
+ const asOf = { pool: pool.version, day: pool.lastDay };
58
+ const orderOf = orderResolver([]);
59
+ const byFamily = derivers();
60
+ return FIRST_ORDER_FAMILIES.flatMap((family) => made(byFamily[family]({ pool, store }), asOf, orderOf));
61
+ };
62
+ /** Order 1, then each stage of `relations` over everything before it. */
63
+ export const deriveReads = (pool, store) => {
64
+ const asOf = { pool: pool.version, day: pool.lastDay };
65
+ return relations().reduce((known, stage) => {
66
+ const orderOf = orderResolver(known);
67
+ return [...known, ...stage.flatMap((derive) => made(derive(known), asOf, orderOf))];
68
+ }, deriveFirstOrder(pool, store));
69
+ };
70
+ export const serializeReads = (reads) => reads.map((read) => `${JSON.stringify(read)}\n`).join('');
71
+ const isRead = (value) => typeof value === 'object' && value !== null && 'readId' in value && 'family' in value;
72
+ const isCell = (value) => typeof value === 'object' && value !== null && 'motifId' in value && 'frameBucket' in value && 'grain' in value;
73
+ const isMotif = (value) => typeof value === 'object' && value !== null && 'motifId' in value && 'level' in value;
74
+ const parsedLine = (file, line) => {
75
+ try {
76
+ return JSON.parse(line);
77
+ }
78
+ catch {
79
+ throw new CliError(`${file} holds a line that is not JSON. Delete that file and run this again: its reads are derived from the store.`, ExitCode.UNEXPECTED, 'read');
80
+ }
81
+ };
82
+ /** A file that is missing, or whose lines are JSON but not all of the kind asked for, is no record of this pool: it is derived and written again. A line that is not JSON is damage, so it stops here and asks the operator to delete the file. */
83
+ const storedRows = async (file, isRow) => {
84
+ try {
85
+ const text = await readFile(file, 'utf8');
86
+ const parsed = text.split('\n').flatMap((line) => (line === '' ? [] : [parsedLine(file, line)]));
87
+ return parsed.every(isRow) ? parsed : undefined;
88
+ }
89
+ catch (error) {
90
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT')
91
+ return undefined;
92
+ throw error;
93
+ }
94
+ };
95
+ const readStored = async (file) => (await storedRows(file, isRead))?.map(frozenRead);
96
+ /** The current pool's reads: already written when this pool has been read before, else derived and written once. */
97
+ export const refreshPool = async (storeDir, store) => {
98
+ const recalls = deriveConsequences(store, await readRecalls(storeDir));
99
+ const set = cellsOf(projectedStore(store, shellReader(vocabulary())), recallGraphOf(store, recalls));
100
+ const pool = poolOf(set, store.errors);
101
+ const files = poolFiles(storeDir);
102
+ await writeAtomic(files.consequences, recalls.flatMap(({ id, n, consequence }) => (consequence === undefined ? [] : [`${JSON.stringify({ id, n, consequence })}\n`])).join(''));
103
+ await writeAtomic(files.cells, serializeCells(set.cells));
104
+ await writeAtomic(files.motifs, set.motifs.map((motif) => `${JSON.stringify(motif)}\n`).join(''));
105
+ const file = files.reads(pool.version);
106
+ const stored = await readStored(file);
107
+ if (stored !== undefined)
108
+ return { pool, reads: stored };
109
+ const reads = deriveReads(pool, store);
110
+ await writeAtomic(file, serializeReads(reads));
111
+ return { pool, reads };
112
+ };
113
+ const POOL_FAILED = 'oars: the read pool was not built, and answers keep their stand-ins: ';
114
+ const unbuilt = (error) => {
115
+ process.stderr.write(`${POOL_FAILED}${error instanceof Error ? error.message : String(error)}\n`);
116
+ };
117
+ /** The pool a deposit's index step reads. It answers without one (spec 2.7): a pool that cannot be read or written costs only the stored read IDs, whose answers keep their stand-ins, and one line on stderr says so. */
118
+ export const currentPool = async (storeDir, store) => {
119
+ try {
120
+ return await refreshPool(storeDir, store);
121
+ }
122
+ catch (error) {
123
+ unbuilt(error);
124
+ return undefined;
125
+ }
126
+ };
127
+ /** The reads file written last: a deposit writes one per new pool version and nothing prunes them, so the newest by time is the pool the last deposit left. */
128
+ const newestReadsFile = async (dir) => {
129
+ try {
130
+ const names = (await readdir(dir)).filter((name) => name.endsWith('.jsonl'));
131
+ const stamped = await Promise.all(names.map(async (name) => ({ file: join(dir, name), at: (await stat(join(dir, name))).mtimeMs })));
132
+ return stamped.sort((a, b) => b.at - a.at || (a.file < b.file ? -1 : 1))[0]?.file;
133
+ }
134
+ catch (error) {
135
+ if (error instanceof Error && 'code' in error && error.code === 'ENOENT')
136
+ return undefined;
137
+ throw error;
138
+ }
139
+ };
140
+ /** The newest stored pool as the files hold it, or undefined when a file of it is missing. A damaged file throws. */
141
+ const storedPool = async (storeDir) => {
142
+ const files = poolFiles(storeDir);
143
+ const file = await newestReadsFile(dirname(files.reads('any')));
144
+ const reads = file === undefined ? undefined : await readStored(file);
145
+ const cells = await storedRows(files.cells, isCell);
146
+ const motifs = await storedRows(files.motifs, isMotif);
147
+ if (file === undefined || reads === undefined || cells === undefined || motifs === undefined)
148
+ return undefined;
149
+ const lastDay = cells.reduce((last, cell) => (cell.day !== UNKNOWN && (last === null || cell.day > last) ? cell.day : last), null);
150
+ return { pool: { cells, motifs: new Map(motifs.map((motif) => [motif.motifId, motif])), version: basename(file, '.jsonl'), lastDay }, reads };
151
+ };
152
+ /**
153
+ * The pool a pull answers from: the newest one already stored, with nothing derived or written. A pull used to refresh the pool, and a deposit that moved it left the next pull to
154
+ * derive every read again (12 to 17 s on a real store) and write a file nothing prunes. Only a store with no stored pool derives one, once, and a stored one is read after that.
155
+ */
156
+ export const servedPool = async (storeDir, store) => {
157
+ try {
158
+ return (await storedPool(storeDir)) ?? (await refreshPool(storeDir, store));
159
+ }
160
+ catch (error) {
161
+ unbuilt(error);
162
+ return undefined;
163
+ }
164
+ };
@@ -0,0 +1,75 @@
1
+ import { type WordOfCommand } from './identity.js';
2
+ import type { ShellReader } from './pool-wire.js';
3
+ import type { Redactor } from './redact.js';
4
+ import { type RepoFilesBucket, type ToolObservation, type ToolPackage } from './schema.js';
5
+ import type { Vocabulary } from './vocab-load.js';
6
+ /** One program of a shell call, as `index` carries it. */
7
+ export interface ProjectedProgram {
8
+ program: string;
9
+ subcommand: string | null;
10
+ flags: string[];
11
+ }
12
+ /** A shell call: its commands in order, and the ordered `program` list a compound command pools as, capped at `pipe_max`. */
13
+ export interface ProjectedShell {
14
+ commands: ProjectedProgram[];
15
+ programs: string[];
16
+ }
17
+ /** What `agentType` pools as when the agent is not a built-in. */
18
+ export declare const CUSTOM = "custom";
19
+ export declare const PRIVATE_PROGRAM: ProjectedProgram;
20
+ export declare const isAdmittedProgram: (vocab: Vocabulary, program: string) => boolean;
21
+ /** One simple command to `program`, `subcommand`, and `flags`. An unlisted subcommand or flag is dropped and not counted: its program already pools. */
22
+ export declare const projectProgram: (vocab: Vocabulary, program: string, args: readonly WordOfCommand[]) => ProjectedProgram;
23
+ /**
24
+ * A shell call to its projection. Quoting, env prefixes, `sudo`-style wrappers, pipes, `&&` chains, and `bash -c` are read by the capture parser;
25
+ * a command it cannot read (no program found in a non-empty text) is one `private` program, never its text.
26
+ */
27
+ export declare const projectShell: (vocab: Vocabulary, command: string, redact: Redactor) => ProjectedShell;
28
+ /**
29
+ * The shell call of a stored tool record, from what the account store holds (migration, spec Section 2): every command of the call, in order, from the
30
+ * record's `steps` (CAPTURE 9 and later), which carry the public program, subcommand, and flag names of each; so a pipeline, an `&&` chain, a `cd` hop,
31
+ * a `bash -c` body, and `git -C repo status` project as the raw command reads. A program the curated list does not name reads `<literal>` in its step and
32
+ * is read from the call's `segments` (`projectLiteralStep`): it stays admitted when only the snapshot lists it, and loses its flags (Q5). A record with no
33
+ * steps (captured before CAPTURE 9) projects its `target` reading alone: one program and its first plain word, no flags (Q5). A target that cannot be
34
+ * read back, a hashed path target, or a record that is not a shell call (a tool other than `Bash` or `PowerShell` holding no `shell.exec` step) projects `private`.
35
+ */
36
+ export declare const projectStoredShell: (vocab: Vocabulary, tool: Pick<ToolObservation, "tool" | "target" | "steps" | "segments">) => ProjectedShell;
37
+ /** The reader a deposit and a local read share: a stored shell call's commands under the pinned vocabulary, one per step, in order. */
38
+ export declare const shellReader: (vocab: Vocabulary) => ShellReader;
39
+ /** A `tool` name: an admitted built-in, `mcp:<server>:<tool>` admitted on both parts, `mcp:private`, or `private`. */
40
+ export declare const projectTool: (tool: string) => string;
41
+ /** A field whose non-admitted members pool only as a count (spec Section 1.3): `privateCount` is exact here, and Section 1.2 buckets it at deposit. */
42
+ export interface ProjectedNames {
43
+ names: string[];
44
+ privateCount: number;
45
+ }
46
+ /** `skills`: the published skills among the names, the rest only counted. */
47
+ export declare const projectSkills: (skills: readonly string[]) => ProjectedNames;
48
+ /** `agentType`: a built-in subagent type of a harness, else `custom`; null stays null (a main transcript). */
49
+ export declare const projectAgentType: (agentType: string | null) => string | null;
50
+ /** `keys` of a call to `tool`: only names its published input schema lists, the rest only counted. An MCP tool lists none. */
51
+ export declare const projectKeys: (tool: string, keys: readonly string[]) => ProjectedNames;
52
+ export interface ProjectedPackage {
53
+ /** `<ecosystem>:<name>` for a seeded name, else `private`. */
54
+ package: string;
55
+ /** Null when no version was stated or the package is private; `private` for a version the snapshot does not list. */
56
+ packageVersion: string | null;
57
+ }
58
+ /**
59
+ * A package is admitted only when it is in its ecosystem's `seed_top` (before the admitted-list service exists, nothing else is admitted): a name
60
+ * that merely resolves, further down the registry, projects to `private`. A version is admitted only when the snapshot lists it for that name.
61
+ */
62
+ export declare const projectPackage: (vocab: Vocabulary, ecosystem: string, name: string, version: string | null) => ProjectedPackage;
63
+ /** A stored package (`<ecosystem>:<name>`, from `packages` on a tool record) as it pools: the name when it is in its ecosystem's `seed_top`, else `private`. */
64
+ export declare const projectStoredPackage: (vocab: Vocabulary, stored: Pick<ToolPackage, "package" | "packageVersion">) => ProjectedPackage;
65
+ /** A model id, lowercased the way the snapshot stores it. */
66
+ export declare const projectModel: (vocab: Vocabulary, model: string) => string;
67
+ /** A harness release up to the snapshot; one published after it pools as `private` until the next VOCAB_VERSION (spec R3). */
68
+ export declare const projectHarnessVersion: (vocab: Vocabulary, harness: string, version: string) => string;
69
+ /** An `errorCode` as it pools: a stored class that is still a member of the closed list, else `other`. A record captured before CAPTURE 14 holds none and projects `other`. */
70
+ export declare const projectErrorCode: (stored: string | undefined) => string;
71
+ export { projectLanguage, projectLanguageShare } from './strata.js';
72
+ /** A stored `repoFiles` bucket as it pools: itself when it is one of the five, else null. */
73
+ export declare const projectRepoFiles: (stored: string | null) => RepoFilesBucket | null;
74
+ /** A stored framework as it pools: a name the vocabulary marks as a framework, else `private`. */
75
+ export declare const projectFramework: (stored: string) => string;
@@ -0,0 +1,165 @@
1
+ // The D11 projection (pool vocabulary spec Sections 1.3 and 2): which names in a P field may pool as themselves. A pure function of the pinned
2
+ // `Vocabulary` and the value, computed at deposit and never written to a file. Every value that leaves here is either a member of a pinned list
3
+ // or the word `private`: the output is built from list members, never from the input text, so a private name cannot be copied through by a
4
+ // parsing mistake. A form the parser cannot read projects to `private`.
5
+ import { SHELL, shellCommands } from './extract.js';
6
+ import { isPositional } from './identity.js';
7
+ import { BUNDLING_PROGRAMS, HARNESS_TOOLS, FRAMEWORKS, isPublicMcpTool, LITERAL, PIPE_MAX, PRIVATE, PUBLIC_FLAGS, PUBLIC_MCP_SERVERS, PUBLIC_PROGRAMS, PUBLIC_SKILLS, projectedAgentType, PUBLIC_SUBCOMMANDS, TOOL_INPUT_KEYS, } from './public-vocabulary.js';
8
+ import { NORMALIZE } from './package-resolve.js';
9
+ import { ERROR_CODES, REPO_FILE_BUCKETS } from './schema.js';
10
+ /** What `agentType` pools as when the agent is not a built-in. */
11
+ export const CUSTOM = 'custom';
12
+ export const PRIVATE_PROGRAM = { program: PRIVATE, subcommand: null, flags: [] };
13
+ const UNREAD_SHELL_PROJECTION = { commands: [PRIVATE_PROGRAM], programs: [PRIVATE] };
14
+ const projectedShell = (commands) => ({ commands, programs: commands.slice(0, PIPE_MAX).map(({ program }) => program) });
15
+ const subcommandsOf = (vocab, program) => {
16
+ const own = vocab.programs.get(program)?.subs;
17
+ const curated = PUBLIC_SUBCOMMANDS.get(program);
18
+ return new Set([...(own ?? []), ...(curated ?? [])]);
19
+ };
20
+ /** A program with a page in the snapshot lists its own flags; one the snapshot lacks (a shell keyword, say) falls back to the curated list. */
21
+ const flagsOf = (vocab, program) => vocab.programs.get(program)?.flags ?? PUBLIC_FLAGS;
22
+ const flagWords = (program, args) => {
23
+ const names = [];
24
+ for (const { text, quoted } of args) {
25
+ if (text === '--')
26
+ break;
27
+ if (quoted || !text.startsWith('-') || text.includes('$'))
28
+ continue;
29
+ // The value of `--flag=value` is never read: only the part before `=` is a candidate.
30
+ const name = text.split('=')[0] ?? text;
31
+ names.push(name);
32
+ if (BUNDLING_PROGRAMS.has(program) && /^-[A-Za-z]{2,}$/.test(name))
33
+ names.push(...Array.from(name.slice(1), (letter) => `-${letter}`));
34
+ }
35
+ return names;
36
+ };
37
+ export const isAdmittedProgram = (vocab, program) => vocab.programs.has(program) || PUBLIC_PROGRAMS.has(program);
38
+ /** `shellTarget` cuts a subcommand at this many characters, and so does a `run` word (`RUN_WORD_CHARS`, extract.ts), so a stored word this long (a program too, `programOf`) may be a prefix of a longer private one. */
39
+ const STORED_SUBCOMMAND_CUT = 30;
40
+ /** One simple command to `program`, `subcommand`, and `flags`. An unlisted subcommand or flag is dropped and not counted: its program already pools. */
41
+ export const projectProgram = (vocab, program, args) => {
42
+ // A program cut at the limit may be the front of a longer private name (`<30 characters>-acme`), so it is never a list member (register row A53).
43
+ if (program.length >= STORED_SUBCOMMAND_CUT || !isAdmittedProgram(vocab, program))
44
+ return PRIVATE_PROGRAM;
45
+ const subs = subcommandsOf(vocab, program);
46
+ const subcommand = args.filter(isPositional).find(({ text }) => subs.has(text))?.text ?? null;
47
+ const listed = flagsOf(vocab, program);
48
+ const flags = [...new Set(flagWords(program, args).filter((name) => listed.has(name)))].sort();
49
+ return { program, subcommand, flags };
50
+ };
51
+ /**
52
+ * A shell call to its projection. Quoting, env prefixes, `sudo`-style wrappers, pipes, `&&` chains, and `bash -c` are read by the capture parser;
53
+ * a command it cannot read (no program found in a non-empty text) is one `private` program, never its text.
54
+ */
55
+ export const projectShell = (vocab, command, redact) => {
56
+ const read = shellCommands(command, redact);
57
+ return projectedShell(read.length === 0 ? [PRIVATE_PROGRAM] : read.map(({ program, args }) => projectProgram(vocab, program, args)));
58
+ };
59
+ /** The first command of a stored call as its class A `target` reads: the program and the first plain word after it. A target cut at the subcommand limit, masked by redaction, or not a program and one word projects `private`. */
60
+ const projectTarget = (vocab, target) => {
61
+ if (target === null || target === '' || target.includes('<'))
62
+ return PRIVATE_PROGRAM;
63
+ const [program = '', sub, ...extra] = target.split(' ');
64
+ if (extra.length > 0 || (sub?.length ?? 0) >= STORED_SUBCOMMAND_CUT)
65
+ return PRIVATE_PROGRAM;
66
+ return projectProgram(vocab, program, sub === undefined ? [] : [{ text: sub, quoted: false }]);
67
+ };
68
+ /** One stored step: its public names, each checked against the pinned vocabulary again, so a step stamped under an older list admits nothing the current one does not. */
69
+ const projectStep = (vocab, identity) => {
70
+ if (!isAdmittedProgram(vocab, identity.program))
71
+ return PRIVATE_PROGRAM;
72
+ const subs = subcommandsOf(vocab, identity.program);
73
+ const listed = flagsOf(vocab, identity.program);
74
+ return {
75
+ program: identity.program,
76
+ subcommand: identity.sub !== null && subs.has(identity.sub) ? identity.sub : null,
77
+ flags: [...new Set(identity.flags.filter((name) => listed.has(name)))].sort(),
78
+ };
79
+ };
80
+ /**
81
+ * A step that reads `<literal>` names no curated program, so its program comes from the same parse, the call's `segments`: `readShell` builds both from
82
+ * the same commands (extract.ts), so segment `at` is step `at`, however many words (`sudo`, `timeout 5`, `bash -c`, an assignment, a block keyword) capture
83
+ * skipped to reach it. `run` is the program and its plain words, so a program only the snapshot lists stays admitted, with a subcommand when a plain word
84
+ * is a listed one; it holds no flag, so flags are lost here (Q5). A word cut at the `run` limit is no subcommand. Segments that do not pair with the
85
+ * steps (none stored, or a different count) cannot say which command ran: `private`.
86
+ */
87
+ const projectLiteralStep = (vocab, segments, steps, at) => {
88
+ const run = segments?.length === steps ? segments[at]?.run : undefined;
89
+ if (run === undefined)
90
+ return PRIVATE_PROGRAM;
91
+ const [program = '', ...words] = run.split(' ');
92
+ return projectProgram(vocab, program, words.filter((text) => text.length < STORED_SUBCOMMAND_CUT).map((text) => ({ text, quoted: false })));
93
+ };
94
+ const isShellStep = (identity) => identity !== null && identity !== undefined && 'program' in identity;
95
+ /**
96
+ * The shell call of a stored tool record, from what the account store holds (migration, spec Section 2): every command of the call, in order, from the
97
+ * record's `steps` (CAPTURE 9 and later), which carry the public program, subcommand, and flag names of each; so a pipeline, an `&&` chain, a `cd` hop,
98
+ * a `bash -c` body, and `git -C repo status` project as the raw command reads. A program the curated list does not name reads `<literal>` in its step and
99
+ * is read from the call's `segments` (`projectLiteralStep`): it stays admitted when only the snapshot lists it, and loses its flags (Q5). A record with no
100
+ * steps (captured before CAPTURE 9) projects its `target` reading alone: one program and its first plain word, no flags (Q5). A target that cannot be
101
+ * read back, a hashed path target, or a record that is not a shell call (a tool other than `Bash` or `PowerShell` holding no `shell.exec` step) projects `private`.
102
+ */
103
+ export const projectStoredShell = (vocab, tool) => {
104
+ // `SHELL` names Claude Code's two shell tools. Another harness's (`run_terminal_cmd`, `exec_command`) is told by the step capture classed `shell.exec`.
105
+ if (!SHELL.has(tool.tool) && tool.steps?.some(({ action }) => action === 'shell.exec') !== true)
106
+ return UNREAD_SHELL_PROJECTION;
107
+ const steps = (tool.steps ?? []).map(({ identity }) => identity);
108
+ if (steps.length === 0)
109
+ return projectedShell([projectTarget(vocab, tool.target)]);
110
+ return projectedShell(steps.map((identity, at) => (!isShellStep(identity) ? PRIVATE_PROGRAM : identity.program === LITERAL ? projectLiteralStep(vocab, tool.segments, steps.length, at) : projectStep(vocab, identity))));
111
+ };
112
+ /** The reader a deposit and a local read share: a stored shell call's commands under the pinned vocabulary, one per step, in order. */
113
+ export const shellReader = (vocab) => (tool) => projectStoredShell(vocab, tool).commands;
114
+ const MCP_TOOL = /^mcp__(.+?)__(.+)$/;
115
+ /** A `tool` name: an admitted built-in, `mcp:<server>:<tool>` admitted on both parts, `mcp:private`, or `private`. */
116
+ export const projectTool = (tool) => {
117
+ const mcp = MCP_TOOL.exec(tool);
118
+ if (mcp !== null) {
119
+ const [, server = '', name = ''] = mcp;
120
+ return PUBLIC_MCP_SERVERS.has(server) && isPublicMcpTool(server, name) ? `mcp:${server}:${name}` : 'mcp:private';
121
+ }
122
+ return [...HARNESS_TOOLS.values()].some((tools) => tools.has(tool)) ? tool : PRIVATE;
123
+ };
124
+ const admit = (names, admitted) => {
125
+ const unique = [...new Set(names)];
126
+ const kept = unique.filter(admitted);
127
+ return { names: kept.sort(), privateCount: unique.length - kept.length };
128
+ };
129
+ /** `skills`: the published skills among the names, the rest only counted. */
130
+ export const projectSkills = (skills) => admit(skills, (name) => PUBLIC_SKILLS.has(name));
131
+ /** `agentType`: a built-in subagent type of a harness, else `custom`; null stays null (a main transcript). */
132
+ export const projectAgentType = (agentType) => (agentType === null ? null : projectedAgentType(agentType));
133
+ /** `keys` of a call to `tool`: only names its published input schema lists, the rest only counted. An MCP tool lists none. */
134
+ export const projectKeys = (tool, keys) => {
135
+ const listed = TOOL_INPUT_KEYS.get(tool);
136
+ return admit(keys, (name) => listed?.has(name) === true);
137
+ };
138
+ /**
139
+ * A package is admitted only when it is in its ecosystem's `seed_top` (before the admitted-list service exists, nothing else is admitted): a name
140
+ * that merely resolves, further down the registry, projects to `private`. A version is admitted only when the snapshot lists it for that name.
141
+ */
142
+ export const projectPackage = (vocab, ecosystem, name, version) => {
143
+ const normalize = NORMALIZE.get(ecosystem);
144
+ const versions = normalize === undefined ? undefined : vocab.packages.get(ecosystem)?.seed.get(normalize(name));
145
+ if (normalize === undefined || versions === undefined)
146
+ return { package: PRIVATE, packageVersion: null };
147
+ return { package: `${ecosystem}:${normalize(name)}`, packageVersion: version === null ? null : versions.has(version) ? version : PRIVATE };
148
+ };
149
+ /** A stored package (`<ecosystem>:<name>`, from `packages` on a tool record) as it pools: the name when it is in its ecosystem's `seed_top`, else `private`. */
150
+ export const projectStoredPackage = (vocab, stored) => {
151
+ const colon = stored.package.indexOf(':');
152
+ return projectPackage(vocab, stored.package.slice(0, colon), stored.package.slice(colon + 1), stored.packageVersion);
153
+ };
154
+ /** A model id, lowercased the way the snapshot stores it. */
155
+ export const projectModel = (vocab, model) => (vocab.models.has(model.toLowerCase()) ? model.toLowerCase() : PRIVATE);
156
+ /** A harness release up to the snapshot; one published after it pools as `private` until the next VOCAB_VERSION (spec R3). */
157
+ export const projectHarnessVersion = (vocab, harness, version) => (vocab.harnessVersions.get(harness)?.has(version) === true ? version : PRIVATE);
158
+ /** An `errorCode` as it pools: a stored class that is still a member of the closed list, else `other`. A record captured before CAPTURE 14 holds none and projects `other`. */
159
+ export const projectErrorCode = (stored) => (stored !== undefined && ERROR_CODES.has(stored) ? stored : 'other');
160
+ // The language and share projections live in `strata.ts`, which the skeleton builder imports without the extractor; they are the same functions.
161
+ export { projectLanguage, projectLanguageShare } from './strata.js';
162
+ /** A stored `repoFiles` bucket as it pools: itself when it is one of the five, else null. */
163
+ export const projectRepoFiles = (stored) => REPO_FILE_BUCKETS.find((bucket) => bucket === stored) ?? null;
164
+ /** A stored framework as it pools: a name the vocabulary marks as a framework, else `private`. */
165
+ export const projectFramework = (stored) => (FRAMEWORKS.has(stored) ? stored : PRIVATE);
@@ -0,0 +1,73 @@
1
+ /** What every name outside this file becomes. */
2
+ export declare const LITERAL = "<literal>";
3
+ export declare const REPO_SIZES: readonly ["xs", "s", "m", "l", "xl"];
4
+ export type RepoSize = (typeof REPO_SIZES)[number];
5
+ /** A stored size bucket: null is a size that could not be read, and undefined is a value that is not one. */
6
+ export declare const asRepoSize: (value: unknown) => RepoSize | null | undefined;
7
+ /** File extension to language: the stack's language mix. */
8
+ export declare const LANGUAGE_OF_EXTENSION: ReadonlyMap<string, string>;
9
+ export declare const LANGUAGES: ReadonlySet<string>;
10
+ /** A touched file's base name to the framework it shows. */
11
+ export declare const FRAMEWORK_OF_FILE: ReadonlyArray<readonly [RegExp, string]>;
12
+ /** A program a shell call ran to the framework it shows. */
13
+ export declare const FRAMEWORK_OF_PROGRAM: ReadonlyMap<string, string>;
14
+ export declare const FRAMEWORKS: ReadonlySet<string>;
15
+ export declare const publicEffort: (value: string | null) => string | null;
16
+ export declare const publicModel: (value: string | null) => string | null;
17
+ export declare const publicVersion: (value: string | null) => string | null;
18
+ /** Programs whose short flags are commonly bundled, as in `rm -rf`. Elsewhere a short lowercase run is more likely a value joined to its flag, as in `mysql -pabc`. */
19
+ export declare const BUNDLING_PROGRAMS: ReadonlySet<string>;
20
+ /** Programs anyone can install or a system ships. A private script or binary is not here, so it reads as the literal. */
21
+ export declare const PUBLIC_PROGRAMS: ReadonlySet<string>;
22
+ /** The subcommands of a public program. Only a program whose subcommands are its own public interface is here: a `just` recipe or a `make` target belongs to the repository. */
23
+ export declare const PUBLIC_SUBCOMMANDS: ReadonlyMap<string, ReadonlySet<string>>;
24
+ /** Flag names of common public programs. A flag name on another program can be a private script's, so an unlisted name reads as the literal. */
25
+ export declare const PUBLIC_FLAGS: ReadonlySet<string>;
26
+ /** Hosts that say nothing about who asked. Matched whole: `acme.github.io` names a customer even though `github.io` is public. */
27
+ export declare const PUBLIC_HOSTS: ReadonlySet<string>;
28
+ /** MCP servers published for anyone to install. A server someone named themselves can name their company, so it reads as the literal. */
29
+ export declare const PUBLIC_MCP_SERVERS: ReadonlySet<string>;
30
+ /**
31
+ * Tools the published server of that name serves, by server. A server name is a label the user picks, so an allowlisted server does not make
32
+ * its tools public: anything not listed under the server reads as the literal, and a server with no entry here has every tool read that way.
33
+ */
34
+ export declare const PUBLIC_MCP_TOOLS: ReadonlyMap<string, ReadonlySet<string>>;
35
+ /** Skills published for anyone to install. */
36
+ export declare const PUBLIC_SKILLS: ReadonlySet<string>;
37
+ /** Packages a public registry serves and many projects use. No registry is asked at capture, so anything else reads as the literal, including a real public package missing here. */
38
+ export declare const PUBLIC_PACKAGES: ReadonlySet<string>;
39
+ export declare const isRegistryVersion: (version: string) => boolean;
40
+ export declare const isPublicMcpTool: (server: string, tool: string) => boolean;
41
+ /**
42
+ * The version of every pinned snapshot and curated list below, as one number. Change a snapshot file or any curated list in vocab-pin.test.ts's
43
+ * `curatedDigest`, and bump it: that test fails otherwise.
44
+ */
45
+ export declare const VOCAB_VERSION = "1";
46
+ /** The day the snapshots were taken. It must equal `snapshotDate` in vocab/manifest.json, which the loader checks. */
47
+ export declare const VOCAB_SNAPSHOT_DATE = "2026-11-04";
48
+ /** How old a snapshot may be before `deposit` builds no batch (spec Section 7, `registry_max_age`). */
49
+ export declare const REGISTRY_MAX_AGE_DAYS = 30;
50
+ /** Names admitted per package ecosystem, by the registry's own download counts (spec Section 7, `seed_top`). */
51
+ export declare const SEED_TOP = 1000;
52
+ /** The longest ordered `program` list a compound command pools as (spec Section 7, `pipe_max`). */
53
+ export declare const PIPE_MAX = 4;
54
+ /** What a name that is not admitted pools as. */
55
+ export declare const PRIVATE = "private";
56
+ /** A client more than `registry_max_age` past its snapshot builds no batch (the exact elapsed time, not whole days): its sessions wait in `A` until it upgrades. */
57
+ export declare const isVocabularyExpired: (now: Date) => boolean;
58
+ /** The built-in tools of Claude Code, by the names a transcript records. Curated, since no registry publishes them (spec Section 1.3, the name seed). */
59
+ export declare const HARNESS_TOOLS: ReadonlyMap<string, ReadonlySet<string>>;
60
+ /**
61
+ * The built-in subagent types of each harness, by the names a transcript records (`agentType`). Curated, since no registry publishes them. No plugin registry
62
+ * is pinned yet, so an admitted plugin agent is not on this list and pools as `custom` (spec Section 2).
63
+ */
64
+ export declare const HARNESS_AGENT_TYPES: ReadonlyMap<string, ReadonlySet<string>>;
65
+ /** What a subagent type pools as when it is not a built-in: a custom agent's name is private. */
66
+ export declare const CUSTOM_AGENT = "custom";
67
+ /** A subagent type as it pools: a built-in of a harness as itself, anything else as `custom`. */
68
+ export declare const projectedAgentType: (agentType: string) => string;
69
+ /**
70
+ * The input keys each built-in tool's published schema lists, by the tool's name. Curated from the harness's tool reference. A key outside the tool's list, and every
71
+ * key of an MCP tool (no pinned registry lists their schemas), is counted and never named (spec Section 1.3).
72
+ */
73
+ export declare const TOOL_INPUT_KEYS: ReadonlyMap<string, ReadonlySet<string>>;