@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.
Files changed (320) hide show
  1. package/README.md +147 -28
  2. package/dist/api.js +1 -1
  3. package/dist/bin.js +6 -29
  4. package/dist/cli.d.ts +10 -4
  5. package/dist/cli.js +440 -91
  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 -3
  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 +47 -0
  22. package/dist/gate/hook-process.d.ts +24 -0
  23. package/dist/gate/hook-process.js +112 -0
  24. package/dist/gate/hook-record.d.ts +3 -0
  25. package/dist/gate/hook-record.js +8 -0
  26. package/dist/gate/hook.d.ts +48 -0
  27. package/dist/gate/hook.js +259 -0
  28. package/dist/gate/install.d.ts +25 -0
  29. package/dist/gate/install.js +126 -0
  30. package/dist/gate/local-bin.d.ts +8 -0
  31. package/dist/gate/local-bin.js +36 -0
  32. package/dist/gate/notes.d.ts +19 -0
  33. package/dist/gate/notes.js +27 -0
  34. package/dist/gate/novelty.d.ts +35 -0
  35. package/dist/gate/novelty.js +99 -0
  36. package/dist/gate/policy.d.ts +25 -0
  37. package/dist/gate/policy.js +73 -0
  38. package/dist/gate/record.d.ts +120 -0
  39. package/dist/gate/record.js +125 -0
  40. package/dist/gate/registry-state.d.ts +10 -0
  41. package/dist/gate/registry-state.js +30 -0
  42. package/dist/gate/registry.d.ts +56 -0
  43. package/dist/gate/registry.js +94 -0
  44. package/dist/gate/replay.d.ts +20 -0
  45. package/dist/gate/replay.js +254 -0
  46. package/dist/gate/report.d.ts +50 -0
  47. package/dist/gate/report.js +89 -0
  48. package/dist/gate/scope.d.ts +7 -0
  49. package/dist/gate/scope.js +27 -0
  50. package/dist/gate/transcripts.d.ts +68 -0
  51. package/dist/gate/transcripts.js +232 -0
  52. package/dist/hook-bin.d.ts +1 -0
  53. package/dist/hook-bin.js +50 -0
  54. package/dist/issuer.d.ts +10 -6
  55. package/dist/issuer.js +19 -24
  56. package/dist/main.d.ts +1 -0
  57. package/dist/main.js +67 -0
  58. package/dist/oidc.js +1 -1
  59. package/dist/sessions/actions.d.ts +35 -0
  60. package/dist/sessions/actions.js +429 -0
  61. package/dist/sessions/allow.d.ts +23 -0
  62. package/dist/sessions/allow.js +71 -0
  63. package/dist/sessions/archive.d.ts +11 -0
  64. package/dist/sessions/archive.js +38 -0
  65. package/dist/sessions/audit.d.ts +42 -0
  66. package/dist/sessions/audit.js +104 -0
  67. package/dist/sessions/baseline.d.ts +62 -0
  68. package/dist/sessions/baseline.js +190 -0
  69. package/dist/sessions/call-shape.d.ts +19 -0
  70. package/dist/sessions/call-shape.js +85 -0
  71. package/dist/sessions/capture-runtime.d.ts +10 -0
  72. package/dist/sessions/capture-runtime.js +12 -0
  73. package/dist/sessions/cell-increments.d.ts +47 -0
  74. package/dist/sessions/cell-increments.js +243 -0
  75. package/dist/sessions/cells.d.ts +109 -0
  76. package/dist/sessions/cells.js +261 -0
  77. package/dist/sessions/codex.d.ts +53 -0
  78. package/dist/sessions/codex.js +745 -0
  79. package/dist/sessions/command.d.ts +127 -0
  80. package/dist/sessions/command.js +419 -0
  81. package/dist/sessions/copilot.d.ts +40 -0
  82. package/dist/sessions/copilot.js +432 -0
  83. package/dist/sessions/coverage.d.ts +19 -0
  84. package/dist/sessions/coverage.js +56 -0
  85. package/dist/sessions/cursor.d.ts +24 -0
  86. package/dist/sessions/cursor.js +324 -0
  87. package/dist/sessions/derive.d.ts +57 -0
  88. package/dist/sessions/derive.js +386 -0
  89. package/dist/sessions/exclusion.d.ts +87 -0
  90. package/dist/sessions/exclusion.js +361 -0
  91. package/dist/sessions/extract.d.ts +181 -0
  92. package/dist/sessions/extract.js +1806 -0
  93. package/dist/sessions/fold.d.ts +17 -0
  94. package/dist/sessions/fold.js +71 -0
  95. package/dist/sessions/frame.d.ts +24 -0
  96. package/dist/sessions/frame.js +95 -0
  97. package/dist/sessions/gemini.d.ts +37 -0
  98. package/dist/sessions/gemini.js +613 -0
  99. package/dist/sessions/gold-arms.d.ts +67 -0
  100. package/dist/sessions/gold-arms.js +172 -0
  101. package/dist/sessions/gold.d.ts +197 -0
  102. package/dist/sessions/gold.js +463 -0
  103. package/dist/sessions/graph.d.ts +12 -0
  104. package/dist/sessions/graph.js +34 -0
  105. package/dist/sessions/grok.d.ts +36 -0
  106. package/dist/sessions/grok.js +421 -0
  107. package/dist/sessions/hook-calls.d.ts +3 -0
  108. package/dist/sessions/hook-calls.js +47 -0
  109. package/dist/sessions/hook-index.d.ts +66 -0
  110. package/dist/sessions/hook-index.js +164 -0
  111. package/dist/sessions/hooks.d.ts +17 -0
  112. package/dist/sessions/hooks.js +281 -0
  113. package/dist/sessions/identity.d.ts +27 -0
  114. package/dist/sessions/identity.js +131 -0
  115. package/dist/sessions/install.d.ts +70 -0
  116. package/dist/sessions/install.js +246 -0
  117. package/dist/sessions/lineage.d.ts +19 -0
  118. package/dist/sessions/lineage.js +118 -0
  119. package/dist/sessions/mcp.d.ts +7 -0
  120. package/dist/sessions/mcp.js +157 -0
  121. package/dist/sessions/merkle.d.ts +7 -0
  122. package/dist/sessions/merkle.js +28 -0
  123. package/dist/sessions/motif.d.ts +44 -0
  124. package/dist/sessions/motif.js +59 -0
  125. package/dist/sessions/opencode.d.ts +33 -0
  126. package/dist/sessions/opencode.js +319 -0
  127. package/dist/sessions/otel.d.ts +60 -0
  128. package/dist/sessions/otel.js +494 -0
  129. package/dist/sessions/package-books.d.ts +48 -0
  130. package/dist/sessions/package-books.js +120 -0
  131. package/dist/sessions/package-resolve.d.ts +32 -0
  132. package/dist/sessions/package-resolve.js +185 -0
  133. package/dist/sessions/pending.d.ts +34 -0
  134. package/dist/sessions/pending.js +142 -0
  135. package/dist/sessions/pi.d.ts +36 -0
  136. package/dist/sessions/pi.js +353 -0
  137. package/dist/sessions/pool-books.d.ts +21 -0
  138. package/dist/sessions/pool-books.js +75 -0
  139. package/dist/sessions/pool-choices.d.ts +5 -0
  140. package/dist/sessions/pool-choices.js +11 -0
  141. package/dist/sessions/pool-command.d.ts +115 -0
  142. package/dist/sessions/pool-command.js +669 -0
  143. package/dist/sessions/pool-delta.d.ts +54 -0
  144. package/dist/sessions/pool-delta.js +190 -0
  145. package/dist/sessions/pool-nightly-deps.d.ts +3 -0
  146. package/dist/sessions/pool-nightly-deps.js +11 -0
  147. package/dist/sessions/pool-nightly.d.ts +10 -0
  148. package/dist/sessions/pool-nightly.js +85 -0
  149. package/dist/sessions/pool-outbox.d.ts +76 -0
  150. package/dist/sessions/pool-outbox.js +313 -0
  151. package/dist/sessions/pool-print.d.ts +26 -0
  152. package/dist/sessions/pool-print.js +68 -0
  153. package/dist/sessions/pool-raw.d.ts +27 -0
  154. package/dist/sessions/pool-raw.js +68 -0
  155. package/dist/sessions/pool-replica.d.ts +35 -0
  156. package/dist/sessions/pool-replica.js +91 -0
  157. package/dist/sessions/pool-send-lock.d.ts +20 -0
  158. package/dist/sessions/pool-send-lock.js +87 -0
  159. package/dist/sessions/pool-sent.d.ts +4 -0
  160. package/dist/sessions/pool-sent.js +26 -0
  161. package/dist/sessions/pool-totals.d.ts +10 -0
  162. package/dist/sessions/pool-totals.js +21 -0
  163. package/dist/sessions/pool-wire.d.ts +435 -0
  164. package/dist/sessions/pool-wire.js +1100 -0
  165. package/dist/sessions/pool.d.ts +32 -0
  166. package/dist/sessions/pool.js +164 -0
  167. package/dist/sessions/projection.d.ts +75 -0
  168. package/dist/sessions/projection.js +165 -0
  169. package/dist/sessions/public-vocabulary.d.ts +72 -0
  170. package/dist/sessions/public-vocabulary.js +295 -0
  171. package/dist/sessions/query.d.ts +123 -0
  172. package/dist/sessions/query.js +268 -0
  173. package/dist/sessions/read-adoption.d.ts +2 -0
  174. package/dist/sessions/read-adoption.js +27 -0
  175. package/dist/sessions/read-call-shape.d.ts +2 -0
  176. package/dist/sessions/read-call-shape.js +25 -0
  177. package/dist/sessions/read-change.d.ts +2 -0
  178. package/dist/sessions/read-change.js +30 -0
  179. package/dist/sessions/read-cost.d.ts +4 -0
  180. package/dist/sessions/read-cost.js +48 -0
  181. package/dist/sessions/read-day-move.d.ts +3 -0
  182. package/dist/sessions/read-day-move.js +65 -0
  183. package/dist/sessions/read-fit.d.ts +7 -0
  184. package/dist/sessions/read-fit.js +41 -0
  185. package/dist/sessions/read-interaction.d.ts +5 -0
  186. package/dist/sessions/read-interaction.js +62 -0
  187. package/dist/sessions/read-lead-lag.d.ts +15 -0
  188. package/dist/sessions/read-lead-lag.js +81 -0
  189. package/dist/sessions/read-live.d.ts +6 -0
  190. package/dist/sessions/read-live.js +38 -0
  191. package/dist/sessions/read-method.d.ts +2 -0
  192. package/dist/sessions/read-method.js +29 -0
  193. package/dist/sessions/read-next-step.d.ts +2 -0
  194. package/dist/sessions/read-next-step.js +35 -0
  195. package/dist/sessions/read-order.d.ts +54 -0
  196. package/dist/sessions/read-order.js +62 -0
  197. package/dist/sessions/read-readable.d.ts +8 -0
  198. package/dist/sessions/read-readable.js +24 -0
  199. package/dist/sessions/read-recovery-edge.d.ts +2 -0
  200. package/dist/sessions/read-recovery-edge.js +26 -0
  201. package/dist/sessions/read-recovery.d.ts +20 -0
  202. package/dist/sessions/read-recovery.js +97 -0
  203. package/dist/sessions/read-rows.d.ts +13 -0
  204. package/dist/sessions/read-rows.js +47 -0
  205. package/dist/sessions/read-substitution.d.ts +5 -0
  206. package/dist/sessions/read-substitution.js +51 -0
  207. package/dist/sessions/read-support.d.ts +48 -0
  208. package/dist/sessions/read-support.js +73 -0
  209. package/dist/sessions/read-tool-day.d.ts +2 -0
  210. package/dist/sessions/read-tool-day.js +26 -0
  211. package/dist/sessions/read-version-boundary.d.ts +31 -0
  212. package/dist/sessions/read-version-boundary.js +95 -0
  213. package/dist/sessions/read.d.ts +86 -0
  214. package/dist/sessions/read.js +87 -0
  215. package/dist/sessions/recall-bundle.d.ts +12 -0
  216. package/dist/sessions/recall-bundle.js +33 -0
  217. package/dist/sessions/recall-consequence.d.ts +45 -0
  218. package/dist/sessions/recall-consequence.js +179 -0
  219. package/dist/sessions/recall-frames.d.ts +18 -0
  220. package/dist/sessions/recall-frames.js +44 -0
  221. package/dist/sessions/recall-next.d.ts +145 -0
  222. package/dist/sessions/recall-next.js +241 -0
  223. package/dist/sessions/recall-object.d.ts +139 -0
  224. package/dist/sessions/recall-object.js +78 -0
  225. package/dist/sessions/recall-pool.d.ts +19 -0
  226. package/dist/sessions/recall-pool.js +96 -0
  227. package/dist/sessions/recall-push.d.ts +26 -0
  228. package/dist/sessions/recall-push.js +47 -0
  229. package/dist/sessions/recall-reads.d.ts +124 -0
  230. package/dist/sessions/recall-reads.js +417 -0
  231. package/dist/sessions/recall-render.d.ts +19 -0
  232. package/dist/sessions/recall-render.js +168 -0
  233. package/dist/sessions/recovery-calls.d.ts +21 -0
  234. package/dist/sessions/recovery-calls.js +25 -0
  235. package/dist/sessions/redact.d.ts +17 -0
  236. package/dist/sessions/redact.js +113 -0
  237. package/dist/sessions/repo-root.d.ts +10 -0
  238. package/dist/sessions/repo-root.js +101 -0
  239. package/dist/sessions/schema.d.ts +694 -0
  240. package/dist/sessions/schema.js +167 -0
  241. package/dist/sessions/session-shape.d.ts +76 -0
  242. package/dist/sessions/session-shape.js +355 -0
  243. package/dist/sessions/sources.d.ts +50 -0
  244. package/dist/sessions/sources.js +233 -0
  245. package/dist/sessions/steps.d.ts +105 -0
  246. package/dist/sessions/steps.js +250 -0
  247. package/dist/sessions/store.d.ts +309 -0
  248. package/dist/sessions/store.js +1498 -0
  249. package/dist/sessions/strata.d.ts +26 -0
  250. package/dist/sessions/strata.js +77 -0
  251. package/dist/sessions/survival.d.ts +27 -0
  252. package/dist/sessions/survival.js +230 -0
  253. package/dist/sessions/transcript-tail.d.ts +14 -0
  254. package/dist/sessions/transcript-tail.js +64 -0
  255. package/dist/sessions/verify.d.ts +53 -0
  256. package/dist/sessions/verify.js +286 -0
  257. package/dist/sessions/vocab-load.d.ts +26 -0
  258. package/dist/sessions/vocab-load.js +61 -0
  259. package/dist/sessions/vscode-copilot.d.ts +38 -0
  260. package/dist/sessions/vscode-copilot.js +494 -0
  261. package/dist/telemetry/command.d.ts +8 -0
  262. package/dist/telemetry/command.js +85 -0
  263. package/dist/telemetry/consent.d.ts +17 -0
  264. package/dist/telemetry/consent.js +63 -0
  265. package/dist/telemetry/crash.d.ts +8 -0
  266. package/dist/telemetry/crash.js +52 -0
  267. package/dist/telemetry/emit.d.ts +31 -0
  268. package/dist/telemetry/emit.js +42 -0
  269. package/dist/telemetry/fields.d.ts +16 -0
  270. package/dist/telemetry/fields.js +26 -0
  271. package/dist/telemetry/health.d.ts +21 -0
  272. package/dist/telemetry/health.js +108 -0
  273. package/dist/telemetry/hook-emit.d.ts +4 -0
  274. package/dist/telemetry/hook-emit.js +18 -0
  275. package/dist/telemetry/measures.d.ts +32 -0
  276. package/dist/telemetry/measures.js +128 -0
  277. package/dist/telemetry/observe.d.ts +13 -0
  278. package/dist/telemetry/observe.js +51 -0
  279. package/dist/telemetry/read-events.d.ts +9 -0
  280. package/dist/telemetry/read-events.js +17 -0
  281. package/dist/telemetry/record.d.ts +17 -0
  282. package/dist/telemetry/record.js +26 -0
  283. package/dist/telemetry/report.d.ts +77 -0
  284. package/dist/telemetry/report.js +188 -0
  285. package/dist/telemetry/schema.d.ts +40 -0
  286. package/dist/telemetry/schema.js +187 -0
  287. package/dist/telemetry/send-main.d.ts +1 -0
  288. package/dist/telemetry/send-main.js +11 -0
  289. package/dist/telemetry/send.d.ts +36 -0
  290. package/dist/telemetry/send.js +172 -0
  291. package/dist/telemetry/spool.d.ts +17 -0
  292. package/dist/telemetry/spool.js +70 -0
  293. package/dist/telemetry/wire.d.ts +25 -0
  294. package/dist/telemetry/wire.js +76 -0
  295. package/package.json +4 -5
  296. package/vocab/crates.json +1 -0
  297. package/vocab/go.json +1 -0
  298. package/vocab/harness.json +1 -0
  299. package/vocab/homebrew.json +1 -0
  300. package/vocab/manifest.json +1 -0
  301. package/vocab/maven.json +1 -0
  302. package/vocab/models.json +1 -0
  303. package/vocab/npm.json +1 -0
  304. package/vocab/programs.json +1 -0
  305. package/vocab/pypi.json +1 -0
  306. package/vocab/rubygems.json +1 -0
  307. package/dist/commands/deploy-input.d.ts +0 -38
  308. package/dist/commands/deploy-input.js +0 -150
  309. package/dist/commands/deploy.d.ts +0 -22
  310. package/dist/commands/deploy.js +0 -124
  311. package/dist/commands/status.d.ts +0 -7
  312. package/dist/commands/status.js +0 -18
  313. package/dist/commands/templates.d.ts +0 -11
  314. package/dist/commands/templates.js +0 -32
  315. package/dist/commands/test-charge.d.ts +0 -11
  316. package/dist/commands/test-charge.js +0 -34
  317. package/dist/journal.d.ts +0 -26
  318. package/dist/journal.js +0 -58
  319. package/parity/deploy-plans/paid-api.json +0 -34
  320. package/parity/deploy-plans/per-task-agent.json +0 -34
@@ -0,0 +1,429 @@
1
+ // The canonical action of a tool call (recall spec Section 2.2). Every harness names its tools differently, so one table per adapter
2
+ // maps its native names onto one closed list, and a step reads alike in any harness. A new adapter adds a table here and changes nothing in the
3
+ // extractor. A native name no table lists becomes `other`, and its name stays out of class P (`LITERAL`): the tool record keeps it, class A.
4
+ import { LITERAL } from './public-vocabulary.js';
5
+ export const CANONICAL_ACTIONS = [
6
+ 'file.read',
7
+ 'file.edit',
8
+ 'file.write',
9
+ 'file.search',
10
+ 'shell.exec',
11
+ 'web.search',
12
+ 'web.fetch',
13
+ 'mcp.call',
14
+ 'skill.run',
15
+ 'agent.spawn',
16
+ 'plan.update',
17
+ 'ask.user',
18
+ 'recall.pull',
19
+ 'recall.push',
20
+ 'other',
21
+ ];
22
+ export const ACTION_TABLES = {
23
+ 'claude-code': {
24
+ rows: {
25
+ Read: 'file.read',
26
+ Edit: 'file.edit',
27
+ MultiEdit: 'file.edit',
28
+ NotebookEdit: 'file.edit',
29
+ Write: 'file.write',
30
+ Grep: 'file.search',
31
+ Glob: 'file.search',
32
+ LSP: 'file.search',
33
+ Bash: 'shell.exec',
34
+ PowerShell: 'shell.exec',
35
+ WebSearch: 'web.search',
36
+ WebFetch: 'web.fetch',
37
+ Skill: 'skill.run',
38
+ Agent: 'agent.spawn',
39
+ Task: 'agent.spawn',
40
+ TodoWrite: 'plan.update',
41
+ TaskCreate: 'plan.update',
42
+ TaskUpdate: 'plan.update',
43
+ TaskList: 'plan.update',
44
+ TaskGet: 'plan.update',
45
+ EnterPlanMode: 'plan.update',
46
+ ExitPlanMode: 'plan.update',
47
+ AskUserQuestion: 'ask.user',
48
+ mcp__oars__oars_recall: 'recall.pull',
49
+ 'mcp__oars-sessions__oars_recall': 'recall.pull',
50
+ StructuredOutput: 'other',
51
+ ToolSearch: 'other',
52
+ SendMessage: 'other',
53
+ ListAgents: 'other',
54
+ Monitor: 'other',
55
+ TaskStop: 'other',
56
+ TaskOutput: 'other',
57
+ BashOutput: 'other',
58
+ KillShell: 'other',
59
+ ScheduleWakeup: 'other',
60
+ Workflow: 'other',
61
+ EnterWorktree: 'other',
62
+ ExitWorktree: 'other',
63
+ },
64
+ mcp: /^mcp__(?<server>.+?)__(?<tool>.+)$/,
65
+ toolDelimited: true,
66
+ shells: { Bash: 'bash', PowerShell: 'powershell' },
67
+ },
68
+ cursor: {
69
+ rows: {
70
+ read_file: 'file.read',
71
+ read_file_v2: 'file.read',
72
+ edit_file: 'file.edit',
73
+ edit_file_v2: 'file.edit',
74
+ search_replace: 'file.edit',
75
+ reapply: 'file.edit',
76
+ write: 'file.write',
77
+ grep_search: 'file.search',
78
+ grep: 'file.search',
79
+ codebase_search: 'file.search',
80
+ file_search: 'file.search',
81
+ glob_file_search: 'file.search',
82
+ list_dir: 'file.search',
83
+ list_dir_v2: 'file.search',
84
+ run_terminal_cmd: 'shell.exec',
85
+ web_search: 'web.search',
86
+ web_fetch: 'web.fetch',
87
+ mcp_oars_oars_recall: 'recall.pull',
88
+ todo_write: 'plan.update',
89
+ create_plan: 'plan.update',
90
+ ask_question: 'ask.user',
91
+ task_v2: 'agent.spawn',
92
+ delete_file: 'other',
93
+ read_lints: 'other',
94
+ },
95
+ mcp: /^mcp_(?<server>[^_]+)_(?<tool>.+)$/,
96
+ toolDelimited: false,
97
+ shells: {},
98
+ },
99
+ // Codex's own names: its adapter names a shell and a patch call in the Claude Code vocabulary for the extractor and keeps the Codex name in `native`.
100
+ // `write_stdin` feeds a running process (it runs no command), so it is `other`, as Claude Code's `BashOutput` is; `web_search` is the adapter's name for a
101
+ // persisted `web_search_call`.
102
+ codex: {
103
+ rows: {
104
+ shell: 'shell.exec',
105
+ shell_command: 'shell.exec',
106
+ exec_command: 'shell.exec',
107
+ local_shell: 'shell.exec',
108
+ 'container.exec': 'shell.exec',
109
+ write_stdin: 'other',
110
+ apply_patch: 'file.edit',
111
+ read_file: 'file.read',
112
+ web_search: 'web.search',
113
+ update_plan: 'plan.update',
114
+ },
115
+ mcp: /^mcp__(?<server>.+?)__(?<tool>.+)$/,
116
+ toolDelimited: true,
117
+ shells: {},
118
+ },
119
+ // Copilot CLI's names are not listed by its event schema; these are the ones the SDK's own hook docs use (docs/hooks/*.md). A shell call and an edit are
120
+ // also found by shape (`shellToolInfo`, `shellExecution`, `fileEdits`) or by name and arrive in the transcript as `Bash` and `Edit` with the original name
121
+ // in `native`, which is what this table looks up; so a name this table lacks still reads as a shell call or an edit in the tool log, but its step is `other`.
122
+ copilot: {
123
+ rows: {
124
+ shell: 'shell.exec',
125
+ bash: 'shell.exec',
126
+ powershell: 'shell.exec',
127
+ local_shell: 'shell.exec',
128
+ read_file: 'file.read',
129
+ view: 'file.read',
130
+ glob: 'file.search',
131
+ grep: 'file.search',
132
+ edit: 'file.edit',
133
+ str_replace_editor: 'file.edit',
134
+ apply_patch: 'file.edit',
135
+ write_file: 'file.write',
136
+ delete_file: 'other',
137
+ task: 'agent.spawn',
138
+ web_fetch: 'web.fetch',
139
+ },
140
+ mcp: /^mcp__(?<server>.+?)__(?<tool>.+)$/,
141
+ toolDelimited: true,
142
+ shells: { bash: 'bash', powershell: 'powershell' },
143
+ },
144
+ // VS Code Copilot Chat's tools (microsoft/vscode @ f92b8f3, extensions/copilot/src/extension/tools/common/toolNames.ts): a tool call's `toolId` is the bare name or the
145
+ // contributed `copilot_` one, so both spellings are rows. The adapter names a terminal call `Bash`, an edit `Edit`, and a file creation `Write`, and keeps the toolId in `native`.
146
+ 'vscode-copilot': {
147
+ rows: {
148
+ run_in_terminal: 'shell.exec',
149
+ create_and_run_task: 'shell.exec',
150
+ run_task: 'shell.exec',
151
+ read_file: 'file.read',
152
+ copilot_readFile: 'file.read',
153
+ list_dir: 'file.search',
154
+ copilot_listDirectory: 'file.search',
155
+ file_search: 'file.search',
156
+ copilot_findFiles: 'file.search',
157
+ grep_search: 'file.search',
158
+ copilot_findTextInFiles: 'file.search',
159
+ semantic_search: 'file.search',
160
+ copilot_searchCodebase: 'file.search',
161
+ search_workspace_symbols: 'file.search',
162
+ copilot_searchWorkspaceSymbols: 'file.search',
163
+ test_search: 'file.search',
164
+ copilot_findTestFiles: 'file.search',
165
+ apply_patch: 'file.edit',
166
+ copilot_applyPatch: 'file.edit',
167
+ replace_string_in_file: 'file.edit',
168
+ copilot_replaceString: 'file.edit',
169
+ multi_replace_string_in_file: 'file.edit',
170
+ copilot_multiReplaceString: 'file.edit',
171
+ insert_edit_into_file: 'file.edit',
172
+ copilot_insertEdit: 'file.edit',
173
+ create_file: 'file.write',
174
+ copilot_createFile: 'file.write',
175
+ runSubagent: 'agent.spawn',
176
+ search_subagent: 'agent.spawn',
177
+ explore_subagent: 'agent.spawn',
178
+ execution_subagent: 'agent.spawn',
179
+ fetch_webpage: 'web.fetch',
180
+ copilot_fetchWebPage: 'web.fetch',
181
+ manage_todo_list: 'plan.update',
182
+ // The rest of toolNames.ts, so no public name reads as an unlisted one with its name withheld. Notebook edits are edits, a directory or a new notebook is a write,
183
+ // the tools that drive a terminal or a kernel feed a running process and run no command of their own (as `write_stdin` is `other`), and a skill is a skill.
184
+ edit_notebook_file: 'file.edit',
185
+ copilot_editNotebook: 'file.edit',
186
+ create_new_jupyter_notebook: 'file.write',
187
+ copilot_createNewJupyterNotebook: 'file.write',
188
+ create_directory: 'file.write',
189
+ copilot_createDirectory: 'file.write',
190
+ read_notebook_cell_output: 'file.read',
191
+ copilot_readNotebookCellOutput: 'file.read',
192
+ copilot_getNotebookSummary: 'file.read',
193
+ view_image: 'file.read',
194
+ copilot_viewImage: 'file.read',
195
+ read_project_structure: 'file.search',
196
+ copilot_readProjectStructure: 'file.search',
197
+ skill: 'skill.run',
198
+ send_to_terminal: 'other',
199
+ get_terminal_output: 'other',
200
+ kill_terminal: 'other',
201
+ terminal_selection: 'other',
202
+ terminal_last_command: 'other',
203
+ get_task_output: 'other',
204
+ run_notebook_cell: 'other',
205
+ copilot_runNotebookCell: 'other',
206
+ runTests: 'other',
207
+ testFailure: 'other',
208
+ edit_files: 'other',
209
+ copilot_editFiles: 'other',
210
+ get_vscode_api: 'other',
211
+ copilot_getVSCodeAPI: 'other',
212
+ get_errors: 'other',
213
+ copilot_getErrors: 'other',
214
+ get_changed_files: 'other',
215
+ copilot_getChangedFiles: 'other',
216
+ memory: 'other',
217
+ copilot_memory: 'other',
218
+ resolve_memory_file_uri: 'other',
219
+ copilot_resolveMemoryFileUri: 'other',
220
+ github_repo: 'other',
221
+ copilot_githubRepo: 'other',
222
+ github_text_search: 'other',
223
+ copilot_githubTextSearch: 'other',
224
+ session_store_sql: 'other',
225
+ copilot_sessionStoreSql: 'other',
226
+ switch_agent: 'other',
227
+ copilot_switchAgent: 'other',
228
+ tool_search: 'other',
229
+ vscode_get_confirmation: 'other',
230
+ vscode_get_confirmation_with_options: 'other',
231
+ vscode_reviewPlan: 'other',
232
+ vscode_get_terminal_confirmation: 'other',
233
+ vscode_askQuestions: 'ask.user',
234
+ open_browser_page: 'other',
235
+ click_element: 'other',
236
+ screenshot_page: 'other',
237
+ navigate_page: 'other',
238
+ read_page: 'other',
239
+ hover_element: 'other',
240
+ drag_element: 'other',
241
+ type_in_page: 'other',
242
+ handle_dialog: 'other',
243
+ run_playwright_code: 'other',
244
+ },
245
+ // No pattern: VS Code's spelling of an MCP tool id has not been seen in a real file, so an MCP call reads as `other` with its name withheld until the hand run shows it.
246
+ mcp: null,
247
+ toolDelimited: false,
248
+ shells: {},
249
+ },
250
+ // Gemini CLI's tool names (google-gemini/gemini-cli @ 89e9d25d, packages/core/src/tools/tool-names.ts). Its adapter names the shell, edit, read, and search
251
+ // calls in the Claude Code vocabulary for the extractor and keeps the Gemini name in `native`, which is what this table looks up. An MCP tool is
252
+ // `mcp_<server>_<tool>`, a spelling that does not mark where the server name ends, so its tool stays out of class P.
253
+ gemini: {
254
+ rows: {
255
+ read_file: 'file.read',
256
+ read_many_files: 'file.read',
257
+ glob: 'file.search',
258
+ grep_search: 'file.search',
259
+ search_file_content: 'file.search',
260
+ list_directory: 'file.search',
261
+ replace: 'file.edit',
262
+ write_file: 'file.write',
263
+ run_shell_command: 'shell.exec',
264
+ PowerShell: 'shell.exec',
265
+ google_web_search: 'web.search',
266
+ web_fetch: 'web.fetch',
267
+ activate_skill: 'skill.run',
268
+ invoke_agent: 'agent.spawn',
269
+ write_todos: 'plan.update',
270
+ enter_plan_mode: 'plan.update',
271
+ exit_plan_mode: 'plan.update',
272
+ tracker_create_task: 'plan.update',
273
+ tracker_update_task: 'plan.update',
274
+ tracker_get_task: 'plan.update',
275
+ tracker_list_tasks: 'plan.update',
276
+ tracker_add_dependency: 'plan.update',
277
+ tracker_visualize: 'plan.update',
278
+ ask_user: 'ask.user',
279
+ mcp_oars_oars_recall: 'recall.pull',
280
+ 'mcp_oars-sessions_oars_recall': 'recall.pull',
281
+ get_internal_docs: 'other',
282
+ update_topic: 'other',
283
+ complete_task: 'other',
284
+ read_mcp_resource: 'other',
285
+ list_mcp_resources: 'other',
286
+ },
287
+ mcp: /^mcp_(?<server>[^_]+)_(?<tool>.+)$/,
288
+ toolDelimited: false,
289
+ shells: { run_shell_command: 'bash', PowerShell: 'powershell' },
290
+ },
291
+ // Grok Build's own names (xai-org/grok-build @ 2bdd1d6, crates/codegen/xai-grok-tools): a tool's `title` is its name. A shell call and an edit reach the
292
+ // transcript as `Bash` and `Edit` with the original name in `native`, which is what this table looks up. A name the table lacks keeps its own and its step
293
+ // is `other`. An MCP call is `<server>__<tool>` in Grok Build; the reader spells it `mcp__<server>__<tool>`.
294
+ grok: {
295
+ rows: {
296
+ run_terminal_cmd: 'shell.exec',
297
+ run_terminal_command: 'shell.exec',
298
+ bash: 'shell.exec',
299
+ search_replace: 'file.edit',
300
+ apply_patch: 'file.edit',
301
+ edit: 'file.edit',
302
+ hashline_edit: 'file.edit',
303
+ write: 'file.write',
304
+ read_file: 'file.read',
305
+ read: 'file.read',
306
+ hashline_read: 'file.read',
307
+ list_dir: 'file.search',
308
+ grep: 'file.search',
309
+ grep_files: 'file.search',
310
+ glob: 'file.search',
311
+ hashline_grep: 'file.search',
312
+ web_search: 'web.search',
313
+ // The backend-hosted X search, named from its `variant` by the grok reader (acp_session_impl/tool_dispatch.rs:94-105).
314
+ x_search: 'web.search',
315
+ web_fetch: 'web.fetch',
316
+ ask_user_question: 'ask.user',
317
+ enter_plan_mode: 'plan.update',
318
+ exit_plan_mode: 'plan.update',
319
+ task: 'agent.spawn',
320
+ // The spawn tool also arrives under these wire names (grok_build/task/mod.rs:193-196).
321
+ Task: 'agent.spawn',
322
+ spawn_subagent: 'agent.spawn',
323
+ todo_write: 'plan.update',
324
+ todowrite: 'plan.update',
325
+ skill: 'skill.run',
326
+ },
327
+ mcp: /^mcp__(?<server>.+?)__(?<tool>.+)$/,
328
+ toolDelimited: true,
329
+ shells: { bash: 'bash', run_terminal_cmd: 'bash', run_terminal_command: 'bash' },
330
+ },
331
+ // OpenCode's own names (sst/opencode @ 21bf6b4, packages/core/src/tool/plugin/*.ts, each file's `export const name`): a tool part's `name`. The reader keeps that name in
332
+ // `native`, which is what this table looks up, and writes `Bash`, `Edit`, `Write`, `Read`, `Grep`, and `Glob` for the extractor. An MCP tool is `<server>_<tool>`
333
+ // (tool/runtime.ts:290-293), the same spelling as a built-in's, so it cannot be told apart and reads as an unknown tool with its name withheld.
334
+ opencode: {
335
+ rows: {
336
+ shell: 'shell.exec',
337
+ edit: 'file.edit',
338
+ patch: 'file.edit',
339
+ write: 'file.write',
340
+ read: 'file.read',
341
+ grep: 'file.search',
342
+ glob: 'file.search',
343
+ websearch: 'web.search',
344
+ webfetch: 'web.fetch',
345
+ question: 'ask.user',
346
+ subagent: 'agent.spawn',
347
+ skill: 'skill.run',
348
+ todowrite: 'plan.update',
349
+ // Known public names with no canonical action.
350
+ experimental_image_generate: 'other',
351
+ artifact_create: 'other',
352
+ artifact_read: 'other',
353
+ artifact_update: 'other',
354
+ artifact_delete: 'other',
355
+ schedule_create: 'other',
356
+ schedule_list: 'other',
357
+ schedule_pause: 'other',
358
+ schedule_resume: 'other',
359
+ schedule_delete: 'other',
360
+ },
361
+ mcp: null,
362
+ toolDelimited: false,
363
+ shells: { shell: 'bash' },
364
+ },
365
+ // Pi's own names (badlogic/pi-mono @ 085c84e, packages/coding-agent, docs/cli.md:144-158): `read`, `bash`, `powershell` (Windows), `edit`, `write`, `grep`, `find`, `ls`,
366
+ // `codemode`, and `tool_search`. A shell call and an edit reach the transcript as `Bash` and `Edit` with the original name in `native`, which is what this table looks up.
367
+ // Pi registers an MCP tool as `mcp__<server>__<tool>` (docs/mcp.md:77). It has no sub-agent, skill, plan, or ask tool of its own (README.md:19).
368
+ pi: {
369
+ rows: {
370
+ read: 'file.read',
371
+ bash: 'shell.exec',
372
+ powershell: 'shell.exec',
373
+ edit: 'file.edit',
374
+ write: 'file.write',
375
+ grep: 'file.search',
376
+ find: 'file.search',
377
+ ls: 'file.search',
378
+ codemode: 'other',
379
+ tool_search: 'other',
380
+ },
381
+ mcp: /^mcp__(?<server>.+?)__(?<tool>.+)$/,
382
+ toolDelimited: true,
383
+ shells: { bash: 'bash', powershell: 'powershell' },
384
+ },
385
+ // OpenTelemetry GenAI traces (open-telemetry/semantic-conventions-genai @ e6658f1, docs/gen-ai/execute-tool.md): `gen_ai.tool.name` is whatever the instrumented agent calls its
386
+ // tool, so no name is guaranteed. These are the names the conventions use in their own examples and refinements (the command, skill, and agent-as-tool sections); a span the
387
+ // reader recognizes by attributes alone (a nonzero `process.exit.code`, a `gen_ai.skill.name`) is renamed before this table is read. An MCP call is spelled `mcp__<server>__<tool>`.
388
+ otel: {
389
+ rows: {
390
+ exec_command: 'shell.exec',
391
+ execute: 'shell.exec',
392
+ shell: 'shell.exec',
393
+ bash: 'shell.exec',
394
+ command: 'shell.exec',
395
+ run_skill_script: 'shell.exec',
396
+ load_skill: 'skill.run',
397
+ skills: 'skill.run',
398
+ get_skill_instructions: 'skill.run',
399
+ load_skill_resource: 'file.read',
400
+ read_skill_resource: 'file.read',
401
+ get_skill_reference: 'file.read',
402
+ transfer_to_agent: 'agent.spawn',
403
+ invoke_agent: 'agent.spawn',
404
+ },
405
+ mcp: /^mcp__(?<server>.+?)__(?<tool>.+)$/,
406
+ toolDelimited: true,
407
+ shells: { bash: 'bash', shell: 'bash', exec_command: 'bash' },
408
+ },
409
+ };
410
+ /** The MCP call a native name spells, in full, as the transcript wrote it; undefined for any other name. */
411
+ export const mcpOf = (table, native) => {
412
+ const groups = table.mcp?.exec(native)?.groups;
413
+ const server = groups?.server;
414
+ const tool = groups?.tool;
415
+ return server === undefined || tool === undefined ? undefined : { server, tool };
416
+ };
417
+ /**
418
+ * What a native name becomes on a step. Rows win over the MCP pattern, so a harness can name a recall that travels over MCP. `native` is the
419
+ * name itself only when a row lists it; an MCP name holds a server name, so `callIdentity` decides whether it is shown.
420
+ */
421
+ export const actionOf = (table, native) => {
422
+ // `hasOwn`: a tool named `constructor` must not read the object's prototype.
423
+ const listed = Object.hasOwn(table.rows, native) ? table.rows[native] : undefined;
424
+ if (listed !== undefined)
425
+ return { action: listed, native };
426
+ return { action: mcpOf(table, native) === undefined ? 'other' : 'mcp.call', native: LITERAL };
427
+ };
428
+ /** The shell a native tool runs, or null when the table does not say. */
429
+ export const shellOf = (table, native) => (Object.hasOwn(table.shells, native) ? (table.shells[native] ?? null) : null);
@@ -0,0 +1,23 @@
1
+ /** A leading `~` is the home folder, expanded here because a quoted entry or one read from a list file reaches us unexpanded by any shell. */
2
+ export declare const expandHome: (entry: string) => string;
3
+ /** Claude Code names a project folder after its working directory with every non-alphanumeric character as `-`. */
4
+ export declare const slugOf: (folder: string) => string;
5
+ export interface Allow {
6
+ /** Whether a project folder name is on the allowlist. */
7
+ allows: (name: string) => boolean;
8
+ /** The entries that matched none of `names`. */
9
+ unmatched: (names: readonly string[]) => string[];
10
+ }
11
+ /** The prefix `--deny` saves an entry under. */
12
+ export declare const DENY = "!";
13
+ export declare const denialOf: (entry: string) => string;
14
+ export declare const compileAllow: (entries: readonly string[]) => Allow;
15
+ /**
16
+ * The list a deposit saves: the saved entries and the given ones, where naming a folder again with `--allow` lifts the denial of exactly
17
+ * that entry. A denial is kept until then, so a later `--allow` of a wider prefix cannot read a denied folder.
18
+ */
19
+ export declare const mergeAllow: (saved: readonly string[], given: readonly string[]) => string[];
20
+ /** What one deposit reads: the folders it names, else the saved list (empty is every folder), less every denial saved or given. */
21
+ export declare const runAllow: (saved: readonly string[], given: readonly string[]) => string[];
22
+ /** One entry per line; blank lines and lines starting with `#` are skipped. */
23
+ export declare const parseAllowList: (text: string) => string[];
@@ -0,0 +1,71 @@
1
+ // What `--allow` accepts. An entry names project folders by one of:
2
+ // a folder or slug `~/work/app` or `-home-me-work-app`: that one project folder
3
+ // a folder prefix `~/work/` (trailing slash): that folder and everything under it
4
+ // a glob `*-work-*`, `C:\work\app-*`: `*` any run of characters, `?` one character
5
+ // A path is matched through its slug, because Claude Code names a project folder after its working directory with every
6
+ // non-alphanumeric character as `-`. An entry that starts with `!` (what `--deny` saves) keeps the folders it names out, whatever
7
+ // else names them. With no entry that is not a denial, every folder is on the list: the default is every folder.
8
+ import { homedir } from 'node:os';
9
+ import { resolve } from 'node:path';
10
+ /** A leading `~` is the home folder, expanded here because a quoted entry or one read from a list file reaches us unexpanded by any shell. */
11
+ export const expandHome = (entry) => (/^~(?:[\\/]|$)/.test(entry) ? homedir() + entry.slice(1) : entry);
12
+ /** Claude Code names a project folder after its working directory with every non-alphanumeric character as `-`. */
13
+ export const slugOf = (folder) => resolve(expandHome(folder)).replace(/[^A-Za-z0-9]/g, '-');
14
+ const GLOB = /[*?]/;
15
+ /** A glob over a path or slug, as an anchored expression over slugs: separators become `-`, wildcards stay wildcards. */
16
+ const globPattern = (entry) => {
17
+ // Every character that is neither alphanumeric nor a wildcard becomes the slug's `-`; then the wildcards become expressions.
18
+ const body = entry.replace(/[^A-Za-z0-9*?]/g, '-').replace(/\*/g, '.*').replace(/\?/g, '.');
19
+ return new RegExp(`^${body}$`);
20
+ };
21
+ /** The test a project folder name must pass for one entry. */
22
+ const matcherOf = (entry) => {
23
+ if (GLOB.test(entry)) {
24
+ const pattern = globPattern(entry);
25
+ return (name) => pattern.test(name);
26
+ }
27
+ if (/[\\/]$/.test(entry)) {
28
+ const prefix = slugOf(entry);
29
+ // `resolve` drops the trailing separator, so the prefix is the folder itself; a project under it extends the slug with `-`.
30
+ return (name) => name === prefix || name.startsWith(`${prefix}-`);
31
+ }
32
+ const slug = slugOf(entry);
33
+ return (name) => name === entry || name === slug;
34
+ };
35
+ /** The prefix `--deny` saves an entry under. */
36
+ export const DENY = '!';
37
+ const isDenial = (entry) => entry.startsWith(DENY);
38
+ export const denialOf = (entry) => `${DENY}${entry}`;
39
+ export const compileAllow = (entries) => {
40
+ const compiled = entries.filter((entry) => !isDenial(entry)).map((entry) => ({ entry, matches: matcherOf(expandHome(entry)) }));
41
+ const denied = entries.filter(isDenial).map((entry) => matcherOf(expandHome(entry.slice(DENY.length))));
42
+ return {
43
+ allows: (name) => (compiled.length === 0 || compiled.some((item) => item.matches(name))) && !denied.some((matches) => matches(name)),
44
+ unmatched: (names) => compiled.filter((item) => !names.some((name) => item.matches(name))).map((item) => item.entry),
45
+ };
46
+ };
47
+ /**
48
+ * Whether the named entries only lift saved denials: each is denied in `saved`, and `saved` names no folder. On every-folder scope such
49
+ * an `--allow` drops the denial and adds nothing, because adding the entry would narrow every later run to it.
50
+ */
51
+ const liftsOnly = (saved, named) => named.length > 0 && saved.every(isDenial) && named.every((entry) => saved.includes(denialOf(entry)));
52
+ /**
53
+ * The list a deposit saves: the saved entries and the given ones, where naming a folder again with `--allow` lifts the denial of exactly
54
+ * that entry. A denial is kept until then, so a later `--allow` of a wider prefix cannot read a denied folder.
55
+ */
56
+ export const mergeAllow = (saved, given) => {
57
+ const kept = saved.filter((entry) => !(isDenial(entry) && given.includes(entry.slice(DENY.length))));
58
+ const added = liftsOnly(saved, given.filter((entry) => !isDenial(entry))) ? given.filter(isDenial) : given;
59
+ return [...new Set([...kept, ...added])];
60
+ };
61
+ /** What one deposit reads: the folders it names, else the saved list (empty is every folder), less every denial saved or given. */
62
+ export const runAllow = (saved, given) => {
63
+ const merged = mergeAllow(saved, given);
64
+ const named = given.filter((entry) => !isDenial(entry));
65
+ return named.length === 0 || liftsOnly(saved, named) ? merged : [...named, ...merged.filter(isDenial)];
66
+ };
67
+ /** One entry per line; blank lines and lines starting with `#` are skipped. */
68
+ export const parseAllowList = (text) => text
69
+ .split(/\r?\n/)
70
+ .map((line) => line.trim())
71
+ .filter((line) => line !== '' && !line.startsWith('#'));
@@ -0,0 +1,11 @@
1
+ export type Archived = 'linked' | 'copied' | 'present';
2
+ /** The file operations, injectable so a test can force the cross-volume fallback. */
3
+ export interface ArchiveOps {
4
+ link: (source: string, target: string) => Promise<void>;
5
+ copyFile: (source: string, target: string) => Promise<void>;
6
+ }
7
+ /**
8
+ * Archives `source` at `target`, idempotently. A target that is the same file (a hard link) or a copy at least as new and the same size
9
+ * is left alone; one the harness has since rewritten or grown past is replaced.
10
+ */
11
+ export declare const archiveRaw: (source: string, target: string, ops?: ArchiveOps) => Promise<Archived>;
@@ -0,0 +1,38 @@
1
+ // oars' own raw archive (Matt 2026-11-01, retention point 4c): every deposited transcript is hard-linked under `<store>/raw/`, so the
2
+ // raw behind the log outlives the harness's cleanup without a second copy on disk while both exist. Across volumes, where a hard link
3
+ // cannot reach, it is copied. Local only: nothing here is ever shared.
4
+ import { copyFile, link, mkdir, rm, stat } from 'node:fs/promises';
5
+ import { dirname } from 'node:path';
6
+ const NODE_OPS = { link, copyFile };
7
+ const isCode = (error, ...codes) => error instanceof Error && 'code' in error && typeof error.code === 'string' && codes.includes(error.code);
8
+ // EXDEV: another volume. EPERM, ENOTSUP: a file system without hard links. EMLINK: the source's link count is at its limit.
9
+ const CANNOT_LINK = ['EXDEV', 'EPERM', 'ENOTSUP', 'EMLINK'];
10
+ /**
11
+ * Archives `source` at `target`, idempotently. A target that is the same file (a hard link) or a copy at least as new and the same size
12
+ * is left alone; one the harness has since rewritten or grown past is replaced.
13
+ */
14
+ export const archiveRaw = async (source, target, ops = NODE_OPS) => {
15
+ const from = await stat(source, { bigint: true });
16
+ const to = await stat(target, { bigint: true }).catch((error) => {
17
+ if (isCode(error, 'ENOENT'))
18
+ return undefined;
19
+ throw error;
20
+ });
21
+ if (to !== undefined) {
22
+ const sameFile = to.ino === from.ino && to.dev === from.dev;
23
+ if (sameFile || (to.size === from.size && to.mtimeMs >= from.mtimeMs))
24
+ return 'present';
25
+ await rm(target, { force: true });
26
+ }
27
+ await mkdir(dirname(target), { recursive: true });
28
+ try {
29
+ await ops.link(source, target);
30
+ return 'linked';
31
+ }
32
+ catch (error) {
33
+ if (!isCode(error, ...CANNOT_LINK))
34
+ throw error;
35
+ }
36
+ await ops.copyFile(source, target);
37
+ return 'copied';
38
+ };
@@ -0,0 +1,42 @@
1
+ import type { SessionObservation, Skeleton } from './schema.js';
2
+ import { type SessionsRuntime, type State } from './store.js';
3
+ /** The T0 result table of spec 2.4, one name per row. */
4
+ export declare const T0_RESULTS: readonly ["root matches and the counts bind", "changed since deposit", "root mismatch", "counts do not bind", "not run"];
5
+ export type T0Result = (typeof T0_RESULTS)[number];
6
+ export interface SessionAudit {
7
+ session: string;
8
+ result: T0Result;
9
+ /** `none` means `W` is 0 until a new capture writes a new root; every other T0 result holds the tier at `skeleton`. */
10
+ tier: 'skeleton' | 'none';
11
+ /** How `raw/` holds the file: a hard link to the harness's transcript, or a copy (cross-volume, or a link whose source is gone). Null when there is no raw file or the counts failed first. */
12
+ mode: 'link' | 'copy' | null;
13
+ leaves: number;
14
+ /** Under {@link MIN_ROOT_LEAVES}: the root joins no cluster and the session counts toward no `n` (spec 2.5). */
15
+ belowMinLeaves: boolean;
16
+ changedSinceDeposit: boolean;
17
+ /** A copy whose size differs from `state.json`'s: a copy changes only when `archiveRaw` refreshes it, so growth is not an honest explanation (spec 2.4). */
18
+ possibleTampering: boolean;
19
+ bindings: {
20
+ leaves: number;
21
+ sessionLines: number;
22
+ skeletonLines: number;
23
+ badLines: number;
24
+ bind: boolean;
25
+ };
26
+ }
27
+ /**
28
+ * One session's T0 result. The count bindings come first and need no raw file: a record set that disagrees with itself is `none` whatever `raw/`
29
+ * holds. `state` is `state.json`, read once by {@link auditStore}.
30
+ */
31
+ export declare const auditSession: (runtime: SessionsRuntime, session: SessionObservation, skeleton: Skeleton | undefined, state?: State) => Promise<SessionAudit>;
32
+ /**
33
+ * Every session's T0 result, in the order given, then one `not run` for each skeleton with no capture record (a torn or removed observations line), so
34
+ * the table never shrinks without a signal. A session with no skeleton, or whose raw file cannot be read, is also `not run`.
35
+ */
36
+ export declare const auditStore: (runtime: SessionsRuntime, sessions: readonly SessionObservation[], skeletons: readonly Skeleton[]) => Promise<SessionAudit[]>;
37
+ export type T0Counts = {
38
+ [result in T0Result]: number;
39
+ };
40
+ export declare const auditCounts: (audits: readonly SessionAudit[]) => T0Counts;
41
+ /** A count line for every row of the T0 table, then one FAIL line per session at tier `none` and one note per session that changed. */
42
+ export declare const formatAudit: (audits: readonly SessionAudit[]) => string;