@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,353 @@
1
+ // The Pi source: a Pi coding agent session file becomes the same capture records a Claude Code transcript does.
2
+ //
3
+ // FIXTURE-DERIVED: written from the public source and docs of the agent (github.com/badlogic/pi-mono, now earendil-works/pi, @ 085c84e98e7f4c950f2be606466fff4f75d8fe7c,
4
+ // packages/coding-agent/, npm `@earendil-works/pi-coding-agent` 1.5.0; the earlier `@mariozechner/pi-coding-agent` wrote the same files), not from a live store. Nothing was copied; the
5
+ // reader is original. No vendor text promises the format (docs/session-format.md names the file version and says an older file is migrated when loaded, and sends programs to the SDK),
6
+ // so `docs/sessions-store.md` says what a live run would still have to prove.
7
+ //
8
+ // Where it reads from (`piRoot`): `$PI_CODING_AGENT_DIR`, else `~/.pi/agent` (`%USERPROFILE%\.pi\agent` on Windows) (src/config.ts:610, :613-614, :630-636, docs/environment-variables.md:81). A session is
9
+ // `sessions/--<cwd with its leading separator removed and / \ : turned into ->--/<ISO time with : . turned into ->_<session id>.jsonl` (docs/session-format.md:10-14,
10
+ // session-manager.ts:590-593). The sessions folder can be moved by `--session-dir`, `PI_CODING_AGENT_SESSION_DIR`, or a setting (docs/sessions.md:60); this reader does not follow those.
11
+ // A file is written only once a conversation exists, then appended to (session-manager.ts:1176-1190). Line 1 is the header and every later line is an entry:
12
+ // session {version, id, timestamp, cwd, parentSession?}: `version` is the FILE format's (1 linear, 2 tree, 3 `hookMessage` renamed `custom`), not Pi's; no app version is recorded.
13
+ // The session's cwd is fixed (docs/sessions.md:15): a `cd` inside a command is not tracked, and a resume from another folder runs in this one.
14
+ // message {id, parentId, timestamp (ISO), message}: `message.timestamp` is Unix ms (docs/message-types.md:5). Roles read here: `user` (content a string or text/image
15
+ // blocks), `assistant` (content text/thinking/toolCall blocks, `model`, `responseModel?`, `usage`, `stopReason`), `toolResult` (toolCallId, content text blocks,
16
+ // `isError`), and `bashExecution` (the operator's own `!cmd`: command, output, exitCode, cancelled). Every other role (`custom`, `hookMessage`, `branchSummary`,
17
+ // `compactionSummary`, `system`) is an extension's or the harness's text, not a prompt.
18
+ // every other type `model_change`, `thinking_level_change`, `usage`, `compaction`, `branch_summary`, `custom`, `custom_message`, `context_edit`, `label`, `session_info`: not read. The usage
19
+ // on a `compaction`, a `branch_summary`, and a `usage` entry is model work that is not a response, and a tool result's `usage` and `nestedCalls` are nested work
20
+ // (docs/message-types.md:177): none is a response of this session.
21
+ // Entries form a tree (`id`, `parentId`) and the leaf is the LAST entry in the file (session-manager.ts:1104-1112), so the branch the session is on is the path from the last entry to its
22
+ // root; that path is what is read, and an abandoned branch is not. A version 1 file has no ids and is one chain in file order (session-manager.ts:287-313). A fork or clone is a new file
23
+ // that starts with its parent's path and keeps the old entry times (createBranchedSession, session-manager.ts:1643-1735); its header names `parentSession` and carries the time the
24
+ // copy was made, so an entry timed before that is the parent's and is not this session's.
25
+ // `usage.input` is the uncached part already: Pi takes the cache reads and writes out of the provider's prompt count (packages/ai/src/api/openai-completions.ts:1536-1550, packages/ai/src/api/openai-responses-shared.ts:636-642;
26
+ // Anthropic's `input_tokens` is disjoint), and `reasoning` is inside `output` (docs/message-types.md:90), so the figures map one for one onto capture's disjoint fields. A response that
27
+ // ended in an error or an abort with every figure zero never reached the provider's count (packages/ai/src/api/anthropic-messages.ts:824 starts them at zero), so it has no usage rather than a zero one.
28
+ // Pi has no sub-agent in core (README.md:19); the example extension runs `pi --no-session` (examples/extensions/subagent/index.ts:389), which writes no file, so the parent's call is the record.
29
+ import { open, readdir, readFile, stat } from 'node:fs/promises';
30
+ import { homedir } from 'node:os';
31
+ import { basename, join, posix, win32 } from 'node:path';
32
+ /** The Pi agent folder for an environment; a test passes its own so it never reads the real one. */
33
+ export const piRoot = (env, home = homedir()) => {
34
+ const set = env.PI_CODING_AGENT_DIR;
35
+ if (set === undefined || set === '')
36
+ return join(home, '.pi', 'agent');
37
+ // Pi expands a leading ~ (config.ts:614).
38
+ return set === '~' ? home : /^~[/\\]/.test(set) ? join(home, set.slice(2)) : set;
39
+ };
40
+ const isObj = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
41
+ const str = (value) => (typeof value === 'string' && value !== '' ? value : undefined);
42
+ const num = (value) => (typeof value === 'number' && Number.isFinite(value) ? value : undefined);
43
+ const parse = (text) => {
44
+ try {
45
+ return JSON.parse(text);
46
+ }
47
+ catch {
48
+ return undefined;
49
+ }
50
+ };
51
+ const SAFE_ID = /^(?!\.+$)[A-Za-z0-9._-]+$/;
52
+ /** The tools that run a command (docs/cli.md:144-146); `bashExecution` is the operator's own. */
53
+ const SHELL_TOOLS = new Set(['bash', 'powershell']);
54
+ /** The tools that change a file; each names it in `path` (tools/edit.ts:29-31, tools/write.ts:10-12). */
55
+ const EDIT_TOOLS = new Set(['edit', 'write']);
56
+ /** What a non-zero exit appends to the output (tools/bash.ts:436). */
57
+ const EXIT_SUFFIX = /(?:^|\n\n)Command exited with code (-?\d+)$/;
58
+ /** The header is one short line; a file whose first 64 KiB hold no line end is not a Pi file. */
59
+ const HEADER_BYTES = 65536;
60
+ /** An error's message with `file` cut to its base name, so a reason that is logged names no folder. */
61
+ const reasonOf = (error, file) => (error instanceof Error ? error.message : String(error)).split(file).join(basename(file));
62
+ const missing = (error) => error instanceof Error && 'code' in error && error.code === 'ENOENT';
63
+ /** The non-blank lines that are not JSON (a torn write), kept so `captureSession` counts them and the deposit line reports them. */
64
+ export const piBadLines = (text) => text.split('\n').filter((raw) => raw.trim() !== '' && parse(raw) === undefined);
65
+ /** A time in milliseconds, or undefined when it is not an absolute time after 2000. */
66
+ const MIN_MS = Date.parse('2000-01-01T00:00:00Z');
67
+ const absoluteMs = (ms) => (ms !== undefined && ms >= MIN_MS ? ms : undefined);
68
+ const isoMs = (value) => {
69
+ const text = str(value);
70
+ return text === undefined ? undefined : absoluteMs(Date.parse(text) || undefined);
71
+ };
72
+ /** An entry's time: its ISO `timestamp`, else the message's own Unix ms. */
73
+ const timeOf = (entry) => isoMs(entry.timestamp) ?? (isObj(entry.message) ? absoluteMs(num(entry.message.timestamp)) : undefined);
74
+ /** A failed shell call's error line: a nonzero exit says so first, then the output. */
75
+ const failureOf = (exit, output) => (exit < 0 && output.trim() !== '' ? output : `Exit code ${String(exit)}${output === '' ? '' : `\n${output}`}`);
76
+ /** The text of a content value: a string, or the text blocks of an array joined by line ends. */
77
+ const textOf = (content) => {
78
+ if (typeof content === 'string')
79
+ return content;
80
+ if (!Array.isArray(content))
81
+ return '';
82
+ return content.flatMap((block) => (isObj(block) && block.type === 'text' && typeof block.text === 'string' ? [block.text] : [])).join('\n');
83
+ };
84
+ /** A path the model named, made absolute against the session's folder; the folder's own style (POSIX or Windows) decides the join. */
85
+ const absolute = (path, cwd) => {
86
+ if (cwd === undefined || posix.isAbsolute(path) || win32.isAbsolute(path))
87
+ return path;
88
+ return (cwd.startsWith('/') ? posix : win32).join(cwd, path);
89
+ };
90
+ /** The entries on the branch the session is on, in order: the path from the last entry to its root (version 2 and later), or every entry (version 1, which has no ids). */
91
+ const activePath = (header, body) => {
92
+ const version = num(header?.version) ?? 1;
93
+ if (version < 2)
94
+ return body;
95
+ const byId = new Map();
96
+ for (const entry of body) {
97
+ const id = str(entry.id);
98
+ if (id !== undefined)
99
+ byId.set(id, entry);
100
+ }
101
+ const path = [];
102
+ const seen = new Set();
103
+ // The leaf is the last entry written (session-manager.ts:1104-1112); an id seen twice ends a cycle, and a parent that is gone ends a broken chain.
104
+ let current = body.findLast((entry) => str(entry.id) !== undefined);
105
+ while (current !== undefined) {
106
+ const id = str(current.id);
107
+ if (id === undefined || seen.has(id))
108
+ break;
109
+ seen.add(id);
110
+ path.push(current);
111
+ const parent = str(current.parentId);
112
+ current = parent === undefined ? undefined : byId.get(parent);
113
+ }
114
+ return path.reverse();
115
+ };
116
+ /** One session as the lines `captureSession` reads. */
117
+ export const piLines = (text, fallbackId) => {
118
+ const nonblank = text.split('\n').filter((raw) => raw.trim() !== '');
119
+ if (nonblank.length > 0 && !nonblank.some((raw) => isObj(parse(raw))))
120
+ throw new Error('no parseable line');
121
+ const entries = nonblank.map(parse).filter(isObj);
122
+ const header = entries.find((entry) => entry.type === 'session');
123
+ const headerMs = isoMs(header?.timestamp);
124
+ // A fork or clone starts with its parent's path, which keeps the old times; the header's time is when the copy was made (session-manager.ts:1643-1735).
125
+ const copiedBefore = str(header?.parentSession) === undefined ? undefined : headerMs;
126
+ const kept = activePath(header, entries.filter((entry) => entry.type !== 'session')).filter((entry) => {
127
+ const when = timeOf(entry);
128
+ return copiedBefore === undefined || when === undefined || when >= copiedBefore;
129
+ });
130
+ const cwd = str(header?.cwd);
131
+ const base = { sessionId: str(header?.id) ?? fallbackId, ...(cwd === undefined ? {} : { cwd }) };
132
+ const lines = [];
133
+ const calls = new Map();
134
+ const settled = new Set();
135
+ let sequence = 0;
136
+ let at = headerMs ?? 0;
137
+ // The last assistant line since the last prompt, which the operator's own `!cmd` joins rather than counting as a response of its own.
138
+ let lastResponse;
139
+ const stamp = (entry) => {
140
+ const when = timeOf(entry);
141
+ // A missing or earlier time says nothing about when: the latest time so far stands.
142
+ if (when !== undefined && when > at)
143
+ at = when;
144
+ return at === 0 ? undefined : new Date(at).toISOString();
145
+ };
146
+ const result = (id, when, failure, output = '') => {
147
+ sequence += 1;
148
+ lines.push({
149
+ ...base,
150
+ type: 'user',
151
+ uuid: `${fallbackId}-r${String(sequence)}`,
152
+ ...(when === undefined ? {} : { timestamp: when }),
153
+ // The result is stamped with its own time, but the call's start is not paired to it here, so no duration is claimed.
154
+ noDuration: true,
155
+ // The output follows an `Exit code 0` line, the shape a Claude Code Bash result has, so a `[branch sha]` line is still found for commit survival.
156
+ message: { role: 'user', content: [{ type: 'tool_result', tool_use_id: id, is_error: failure !== undefined, content: failure ?? (output === '' ? '' : `Exit code 0\n${output}`) }] },
157
+ });
158
+ };
159
+ const response = (when, content, extra = {}, message = {}) => {
160
+ sequence += 1;
161
+ lines.push({
162
+ ...base,
163
+ type: 'assistant',
164
+ uuid: `${fallbackId}-a${String(sequence)}`,
165
+ // Every assistant line carries a requestId (`verify --strict` needs one), and each response has its own, so its usage counts once.
166
+ requestId: `${fallbackId}-resp${String(sequence)}`,
167
+ ...(when === undefined ? {} : { timestamp: when }),
168
+ ...extra,
169
+ message: { role: 'assistant', content, ...message },
170
+ });
171
+ lastResponse = { content };
172
+ };
173
+ const toolUse = (block) => {
174
+ const id = str(block.id) ?? '';
175
+ const name = str(block.name) ?? '?';
176
+ const input = isObj(block.arguments) ? block.arguments : {};
177
+ if (SHELL_TOOLS.has(name)) {
178
+ calls.set(id, { shell: true });
179
+ const command = str(input.command);
180
+ return { type: 'tool_use', id, name: 'Bash', native: name, input: command === undefined ? {} : { command } };
181
+ }
182
+ calls.set(id, { shell: false });
183
+ if (EDIT_TOOLS.has(name)) {
184
+ const path = str(input.path);
185
+ return { type: 'tool_use', id, name: 'Edit', native: name, input: path === undefined ? {} : { file_path: absolute(path, cwd) } };
186
+ }
187
+ return { type: 'tool_use', id, name, input };
188
+ };
189
+ /** The usage a response reported; undefined when it reported none, or errored before the provider counted anything. */
190
+ const usageOf = (message) => {
191
+ const raw = message.usage;
192
+ if (!isObj(raw))
193
+ return undefined;
194
+ const figures = { input: num(raw.input), read: num(raw.cacheRead), write: num(raw.cacheWrite), output: num(raw.output), thinking: num(raw.reasoning) };
195
+ const stopped = message.stopReason === 'error' || message.stopReason === 'aborted';
196
+ if (stopped && [figures.input, figures.read, figures.write, figures.output].every((figure) => (figure ?? 0) === 0))
197
+ return undefined;
198
+ return {
199
+ ...(figures.input === undefined ? {} : { input_tokens: figures.input }),
200
+ ...(figures.read === undefined ? {} : { cache_read_input_tokens: figures.read }),
201
+ ...(figures.write === undefined ? {} : { cache_creation_input_tokens: figures.write }),
202
+ ...(figures.output === undefined ? {} : { output_tokens: figures.output }),
203
+ ...(figures.thinking === undefined ? {} : { output_tokens_details: { thinking_tokens: figures.thinking } }),
204
+ };
205
+ };
206
+ for (const entry of kept) {
207
+ if (entry.type !== 'message' || !isObj(entry.message))
208
+ continue;
209
+ const message = entry.message;
210
+ const role = str(message.role);
211
+ const when = stamp(entry);
212
+ if (role === 'user') {
213
+ const body = textOf(message.content);
214
+ const image = Array.isArray(message.content) && message.content.some((block) => isObj(block) && block.type === 'image');
215
+ if (body === '' && !image)
216
+ continue;
217
+ sequence += 1;
218
+ lastResponse = undefined;
219
+ // An image-only prompt keeps its line (an image block with no data); capture counts a turn only for a prompt with text, so it is not a counted turn.
220
+ lines.push({ ...base, type: 'user', uuid: `${fallbackId}-u${String(sequence)}`, ...(when === undefined ? {} : { timestamp: when }), message: { role: 'user', content: [body === '' ? { type: 'image' } : { type: 'text', text: body }] } });
221
+ }
222
+ else if (role === 'assistant') {
223
+ const content = [];
224
+ for (const block of Array.isArray(message.content) ? message.content : []) {
225
+ if (!isObj(block))
226
+ continue;
227
+ if (block.type === 'text' && str(block.text) !== undefined)
228
+ content.push({ type: 'text', text: String(block.text) });
229
+ else if (block.type === 'toolCall')
230
+ content.push(toolUse(block));
231
+ }
232
+ const model = str(message.model);
233
+ const reported = str(message.responseModel);
234
+ const usage = usageOf(message);
235
+ response(when, content, model === undefined ? {} : { requestedModel: model }, { ...(reported === undefined ? {} : { model: reported }), ...(usage === undefined ? {} : { usage }) });
236
+ }
237
+ else if (role === 'toolResult') {
238
+ const id = str(message.toolCallId);
239
+ const call = id === undefined ? undefined : calls.get(id);
240
+ if (id === undefined || call === undefined || settled.has(id))
241
+ continue;
242
+ settled.add(id);
243
+ const output = textOf(message.content);
244
+ if (message.isError !== true) {
245
+ result(id, when, undefined, call.shell ? output : '');
246
+ }
247
+ else if (call.shell) {
248
+ // A non-zero exit ends the text with the code (tools/bash.ts:434-440), the one place the persisted result keeps it; an abort, a timeout, and a spawn error carry no such suffix and stand as written.
249
+ const exit = EXIT_SUFFIX.exec(output);
250
+ result(id, when, exit === null ? (output === '' ? 'tool failed' : output) : failureOf(Number(exit[1]), output.slice(0, exit.index)));
251
+ }
252
+ else {
253
+ result(id, when, output === '' ? 'tool failed' : output);
254
+ }
255
+ }
256
+ else if (role === 'bashExecution') {
257
+ // The operator's own `!cmd`: a real exit code, no model behind it.
258
+ sequence += 1;
259
+ const id = `${fallbackId}-bang${String(sequence)}`;
260
+ const command = str(message.command);
261
+ const block = { type: 'tool_use', id, name: 'Bash', native: 'bash', input: command === undefined ? {} : { command } };
262
+ if (lastResponse === undefined)
263
+ response(when, [block]);
264
+ else
265
+ lastResponse.content.push(block);
266
+ const output = typeof message.output === 'string' ? message.output : '';
267
+ const exit = num(message.exitCode);
268
+ let failure;
269
+ if (message.cancelled === true)
270
+ failure = output === '' ? 'Command cancelled' : output;
271
+ else if (exit === undefined)
272
+ failure = output === '' ? 'Command ended without an exit code' : output;
273
+ else if (exit !== 0)
274
+ failure = failureOf(exit, output);
275
+ result(id, when, failure, output);
276
+ }
277
+ }
278
+ return lines;
279
+ };
280
+ /** The first line of a file, read from its first 64 KiB; undefined when the file is empty. */
281
+ const firstLine = async (file) => {
282
+ const handle = await open(file, 'r');
283
+ try {
284
+ const buffer = Buffer.alloc(HEADER_BYTES);
285
+ const { bytesRead } = await handle.read(buffer, 0, HEADER_BYTES, 0);
286
+ const text = buffer.subarray(0, bytesRead).toString('utf8');
287
+ const line = text.split('\n', 1)[0] ?? '';
288
+ return line.trim() === '' ? undefined : line;
289
+ }
290
+ finally {
291
+ await handle.close();
292
+ }
293
+ };
294
+ export const openPiStore = async (root) => {
295
+ const base = join(root, 'sessions');
296
+ const unreadable = [];
297
+ let folders;
298
+ try {
299
+ folders = await readdir(base, { withFileTypes: true });
300
+ }
301
+ catch (error) {
302
+ if (missing(error))
303
+ return undefined;
304
+ return { sessions: [], transcript: () => Promise.reject(new Error('no sessions')), rejected: 0, unreadable: [{ file: base, reason: reasonOf(error, base) }] };
305
+ }
306
+ const sessions = [];
307
+ let rejected = 0;
308
+ for (const folder of folders.filter((candidate) => candidate.isDirectory()).sort((a, b) => a.name.localeCompare(b.name))) {
309
+ let files;
310
+ try {
311
+ files = await readdir(join(base, folder.name), { withFileTypes: true });
312
+ }
313
+ catch (error) {
314
+ unreadable.push({ file: join(base, folder.name), reason: reasonOf(error, join(base, folder.name)) });
315
+ continue;
316
+ }
317
+ for (const entry of files.filter((candidate) => candidate.isFile() && candidate.name.endsWith('.jsonl')).sort((a, b) => a.name.localeCompare(b.name))) {
318
+ // `<timestamp>_<id>.jsonl`: the timestamp has no underscore, so the id is everything after the first one (docs/session-format.md:11-14).
319
+ const stem = entry.name.slice(0, -'.jsonl'.length);
320
+ const id = stem.includes('_') ? stem.slice(stem.indexOf('_') + 1) : stem;
321
+ if (!SAFE_ID.test(id)) {
322
+ rejected += 1;
323
+ continue;
324
+ }
325
+ const file = join(base, folder.name, entry.name);
326
+ try {
327
+ const first = await firstLine(file);
328
+ const header = first === undefined ? undefined : parse(first);
329
+ if (!isObj(header) || header.type !== 'session') {
330
+ unreadable.push({ file, reason: 'no session header on the first line' });
331
+ continue;
332
+ }
333
+ const info = await stat(file);
334
+ sessions.push({ id, folder: str(header.cwd) ?? null, file, size: info.size, mtimeMs: Math.floor(info.mtimeMs) });
335
+ }
336
+ catch (error) {
337
+ if (!missing(error))
338
+ unreadable.push({ file, reason: reasonOf(error, file) });
339
+ }
340
+ }
341
+ }
342
+ sessions.sort((a, b) => a.mtimeMs - b.mtimeMs || a.id.localeCompare(b.id));
343
+ return {
344
+ sessions,
345
+ rejected,
346
+ unreadable,
347
+ transcript: async (session) => {
348
+ const text = await readFile(session.file, 'utf8');
349
+ const lines = [...piLines(text, session.id).map((line) => JSON.stringify(line)), ...piBadLines(text)];
350
+ return lines.join('\n') + (lines.length === 0 ? '' : '\n');
351
+ },
352
+ };
353
+ };
@@ -0,0 +1,21 @@
1
+ import { type Bundle } from './pool-wire.js';
2
+ /** The newest kept bundle that still verifies against the key pinned for its server; undefined when none was fetched or none verifies. An unreadable sign-ins file stops the command (`loadSignIns`) and is not read as no bundle. */
3
+ export declare const lastFetchedBundle: (storeDir: string) => Promise<Bundle | undefined>;
4
+ /** The pool lines of `books`: the four, or one plain line when there is nothing to state them from. */
5
+ export declare const booksLines: (bundle: Bundle | undefined) => string[];
6
+ /** The totals as flat numbers for the health batch to read; a field with no source is null and never 0, and a bundle with no books gives null. */
7
+ export interface BooksTotals {
8
+ /** Lineage (section 17 rule 6): the floor the served count was held to, the day it was as of, and the day the panel was counted, which a 304 can leave days old. */
9
+ floor: number;
10
+ asOfDay: string | null;
11
+ panelDay: string | null;
12
+ servedCells: number;
13
+ belowFloor: number;
14
+ panel: number | null;
15
+ comparisonReadOwners: number | null;
16
+ followOnReads: number | null;
17
+ readYield: number | null;
18
+ costPerServedCell: number | null;
19
+ yieldPerServedCell: number | null;
20
+ }
21
+ export declare const booksTotals: (bundle: Bundle | undefined) => BooksTotals | null;
@@ -0,0 +1,75 @@
1
+ // `oars sessions books`, the pool's side: the set of four (the pool design notes, set of four) from the last fetched bundle. The bundle is the replica a fetch kept, checked again against the key pinned at login, so a
2
+ // file edited on disk prints nothing. A field with no source says so and is never printed as zero.
3
+ import { readdir, readFile, stat } from 'node:fs/promises';
4
+ import { join } from 'node:path';
5
+ import { loadSignIns } from './pool-command.js';
6
+ import { isHarness, verifyBundle } from './pool-wire.js';
7
+ import { contentHash } from './read.js';
8
+ const names = async (folder) => readdir(folder).catch(() => []);
9
+ const candidatesOf = async (storeDir) => {
10
+ const root = join(storeDir, 'pool-replica');
11
+ const found = [];
12
+ for (const server of await names(root)) {
13
+ for (const harness of await names(join(root, server))) {
14
+ for (const name of await names(join(root, server, harness))) {
15
+ if (!name.endsWith('.json'))
16
+ continue;
17
+ const file = join(root, server, harness, name);
18
+ found.push({ file, server, harness, version: decodeURIComponent(name.slice(0, -'.json'.length)), modified: (await stat(file)).mtimeMs });
19
+ }
20
+ }
21
+ }
22
+ return found.sort((a, b) => b.modified - a.modified);
23
+ };
24
+ /** The newest kept bundle that still verifies against the key pinned for its server; undefined when none was fetched or none verifies. An unreadable sign-ins file stops the command (`loadSignIns`) and is not read as no bundle. */
25
+ export const lastFetchedBundle = async (storeDir) => {
26
+ const keys = await loadSignIns(storeDir, 'books');
27
+ for (const { file, server, harness, version } of await candidatesOf(storeDir)) {
28
+ const key = keys.find((entry) => contentHash(entry.server) === server)?.signingKey;
29
+ if (key === undefined || !isHarness(harness))
30
+ continue;
31
+ let parsed;
32
+ try {
33
+ parsed = JSON.parse(await readFile(file, 'utf8'));
34
+ }
35
+ catch {
36
+ continue;
37
+ }
38
+ const verified = await verifyBundle(parsed, key, harness, version);
39
+ if (verified.ok)
40
+ return verified.bundle;
41
+ }
42
+ return undefined;
43
+ };
44
+ const shown = (field, unit) => (field.state === 'value' ? `${String(field.value)}${unit}` : `no source yet (${field.reason})`);
45
+ const linesOf = (books) => [
46
+ `served cells ${String(books.served.total)}, below floor ${String(books.backlog)}, as of ${books.asOf.day ?? 'no known day'}`,
47
+ books.panel.state === 'value' ? `panel: ${String(books.panel.value)} accounts deposited in the last four weeks${books.panelDay === null ? '' : `, as of ${books.panelDay}`}` : `panel: ${shown(books.panel, '')}`,
48
+ `demand: comparison-read owners ${shown(books.demand.comparisonReadOwners, '')}, follow-on reads ${shown(books.demand.followOnReads, '')}`,
49
+ `goal metric: read yield ${shown(books.goal.readYield, '')}, cost per served cell ${shown(books.goal.costPerServedCell, '')}, yield per served cell ${shown(books.goal.yieldPerServedCell, '')}`,
50
+ ];
51
+ /** The pool lines of `books`: the four, or one plain line when there is nothing to state them from. */
52
+ export const booksLines = (bundle) => {
53
+ if (bundle === undefined)
54
+ return ['no pool bundle yet'];
55
+ return bundle.books === undefined ? ['the last fetched bundle carries no pool books; run oars pool fetch again'] : linesOf(bundle.books);
56
+ };
57
+ const valueOf = (field) => (field.state === 'value' ? field.value : null);
58
+ export const booksTotals = (bundle) => {
59
+ const books = bundle?.books;
60
+ if (books === undefined)
61
+ return null;
62
+ return {
63
+ floor: books.floor,
64
+ asOfDay: books.asOf.day,
65
+ panelDay: books.panelDay,
66
+ servedCells: books.served.total,
67
+ belowFloor: books.backlog,
68
+ panel: valueOf(books.panel),
69
+ comparisonReadOwners: valueOf(books.demand.comparisonReadOwners),
70
+ followOnReads: valueOf(books.demand.followOnReads),
71
+ readYield: valueOf(books.goal.readYield),
72
+ costPerServedCell: valueOf(books.goal.costPerServedCell),
73
+ yieldPerServedCell: valueOf(books.goal.yieldPerServedCell),
74
+ };
75
+ };
@@ -0,0 +1,5 @@
1
+ import type { FolderSend, PoolChoices } from './store.js';
2
+ export type Sends = 'all' | FolderSend;
3
+ export declare const sendsOf: (choices: PoolChoices, project: string) => Sends;
4
+ /** Whether a raw copy of this folder's sessions may be built: raw consent granted, and the folder neither skeleton only nor off. */
5
+ export declare const rawAllowed: (choices: PoolChoices, project: string) => boolean;
@@ -0,0 +1,11 @@
1
+ // What a folder may send to a pool, from the choices in `state.json`: everything (the default after the covenant is accepted), skeletons only, or nothing.
2
+ // A project that more than one entry names takes the narrowest of them, so a switch that is off is never undone by a broader entry.
3
+ import { compileAllow } from './allow.js';
4
+ export const sendsOf = (choices, project) => {
5
+ const modes = Object.entries(choices.folders).filter(([entry]) => compileAllow([entry]).allows(project)).map(([, mode]) => mode);
6
+ if (modes.includes('off'))
7
+ return 'off';
8
+ return modes.includes('skeleton') ? 'skeleton' : 'all';
9
+ };
10
+ /** Whether a raw copy of this folder's sessions may be built: raw consent granted, and the folder neither skeleton only nor off. */
11
+ export const rawAllowed = (choices, project) => choices.rawConsent === 'granted' && sendsOf(choices, project) === 'all';
@@ -0,0 +1,115 @@
1
+ import type { Outcome, RunDeps } from '../cli.js';
2
+ import { CliError } from '../errors.js';
3
+ import { Masker, type Outgoing } from './pool-print.js';
4
+ import { isObject, loadSignIns, textIn, type SignIn } from './pool-replica.js';
5
+ import { type SessionsRuntime } from './store.js';
6
+ import { type Git } from './survival.js';
7
+ export declare const DEPOSIT = "pool-deposit";
8
+ export declare const POOL_PROVIDERS: readonly ["github", "google"];
9
+ export { isObject, loadSignIns, textIn };
10
+ /** The Many Oars pool, used when neither `--server` nor `OARS_POOL_URL` names another. */
11
+ export declare const DEFAULT_POOL_URL = "https://pool.manyoars.com";
12
+ /** `--server`, else `OARS_POOL_URL`, else the Many Oars pool. A token and a session's shape cross this connection, so plain http goes only to this machine. */
13
+ export declare const poolServer: (env: NodeJS.ProcessEnv, step: string, named?: string) => string;
14
+ export declare const runtimeOf: (deps: RunDeps) => SessionsRuntime;
15
+ export declare const signedIn: (deps: RunDeps, storeDir: string, server: string, step: string) => Promise<SignIn>;
16
+ export interface Reply {
17
+ status: number;
18
+ body: unknown;
19
+ headers: Headers;
20
+ }
21
+ interface Call {
22
+ body?: unknown;
23
+ /** A body already serialized, sent as it is: a batch from the outbox, whose bytes were hashed and printed. */
24
+ bytes?: string;
25
+ token?: string;
26
+ /** One part of a batch sent in several: its position (from 1), how many there are, and the SHA-256 of the whole batch, which is what keeps the parts one deposit. */
27
+ part?: {
28
+ index: number;
29
+ count: number;
30
+ batch: string;
31
+ };
32
+ /** The ETag of the bundle already kept, so the pool can answer 304 with no bundle. */
33
+ ifNoneMatch?: string;
34
+ /** Set for a command that prints what it sends: the print comes first, with these secrets masked. */
35
+ show?: Masker;
36
+ /** A raw part is a PUT of bytes that are not JSON; every other call is a GET, or a POST when it has a body. */
37
+ method?: 'PUT';
38
+ type?: string;
39
+ /** Headers beyond the usual ones (the raw routes state their redaction and capture versions, and the raw consent). */
40
+ extra?: Array<[string, string]>;
41
+ }
42
+ /** How a request leaves this machine. The command line passes none, so a send goes over the network (`networkSender`); a test passes one to read what would leave. */
43
+ export type Sender = (request: Outgoing) => Promise<Reply>;
44
+ /** One call to the pool. A redirect is an error: it could carry a batch or a token somewhere the checks on the named server never saw. */
45
+ export declare const ask: (deps: RunDeps, step: string, server: string, path: string, init: Call, via?: Sender) => Promise<Reply>;
46
+ /** The sender `deposit --send` uses when none is given: the request goes out over the network as built. The loopback test passes it to read what reaches the socket. */
47
+ export declare const networkSender: (deps: RunDeps, step: string) => Sender;
48
+ /**
49
+ * `oars pool login` (spec Section 1.4): the device flow runs here, against the provider, and the pool sees only the provider's token, once, and answers its own credential. Every request prints before it is sent, with the device code, the provider's token,
50
+ * and the credential masked as `<credential: n bytes>`. A client ID, scope, grant type, and Google's `client_secret` print as they are: none is secret.
51
+ */
52
+ export declare const poolLogin: (deps: RunDeps, options: {
53
+ server?: string | undefined;
54
+ provider?: string | undefined;
55
+ }) => Promise<Outcome>;
56
+ export declare const vocabularyExpired: (deps: RunDeps) => CliError | undefined;
57
+ /** One batch to the pool: a batch past one request's bytes goes in parts, in order, each answered 202 until the last completes the deposit with 201. A part sent again is harmless, so the retry covers every part alike. */
58
+ export declare const postBatch: (deps: RunDeps, options: {
59
+ server: string;
60
+ token: string;
61
+ bytes: string;
62
+ hash: string;
63
+ via: Sender;
64
+ }) => Promise<void>;
65
+ /**
66
+ * One redacted raw copy to the pool: its parts by PUT, then the completion, which the pool checks against the SHA-256 in the path. Every request states the redaction and capture versions and that the person said yes to the raw prompt;
67
+ * the caller sends only for a person who did. A part sent again replaces itself, and one for an object that stands writes nothing, so a copy that failed halfway is sent again whole.
68
+ */
69
+ export declare const postRaw: (deps: RunDeps, options: {
70
+ server: string;
71
+ token: string;
72
+ hash: string;
73
+ body: string;
74
+ bytes: number;
75
+ via: Sender;
76
+ }) => Promise<void>;
77
+ /**
78
+ * `oars pool deposit`: every session in the store that passes both session gates is built into a canonical batch in the outbox, and the command stops: nothing is sent. The gates run before any projection does: the folder
79
+ * allowlist, then the exclusion check. A session that fails either, or has no raw to scan, is counted and never built. A session is built only once it has ended: no transcript of it, main or subagent, has gained a line (the later of its capture
80
+ * and its raw file's last write) for `session_idle_hours` (6 hours). One that has not is counted under `notEnded`, and any batch of it from an earlier pass is withdrawn. `--send <hash>` is the lock in `sendBatch`.
81
+ */
82
+ export declare const poolDeposit: (deps: RunDeps, options: {
83
+ server?: string | undefined;
84
+ acceptCovenant?: string | undefined;
85
+ send?: string | undefined;
86
+ via?: Sender | undefined;
87
+ git?: Git | undefined;
88
+ }) => Promise<Outcome>;
89
+ /** `oars pool outbox`: prints each batch as it would be sent (a batch past one request prints each part's request, in order), the request line and every header included, with the bearer credential as its size and nothing else masked, then its SHA-256, and records that it was shown. `--explain` adds each field's rule. */
90
+ export declare const poolOutbox: (deps: RunDeps, options: {
91
+ server?: string | undefined;
92
+ explain?: boolean | undefined;
93
+ }) => Promise<Outcome>;
94
+ /** `oars pool fetch`: one harness's signed bundle at one version, kept only once the key pinned at login has verified it. It keeps the signed form, so the replica can be checked again later, and the ETag, so the next fetch asks only whether it changed. The request prints before it is sent. */
95
+ export declare const poolFetch: (deps: RunDeps, options: {
96
+ server?: string | undefined;
97
+ harness?: string | undefined;
98
+ harnessVersion: string;
99
+ }) => Promise<Outcome>;
100
+ /** The raw prompt, in plain words: shown by `oars pool raw` until it is answered, and what the nightly send relies on. Redaction is best effort and the text says so. */
101
+ export declare const RAW_PROMPT: string;
102
+ /** `oars pool raw`: shows the raw prompt and the answer so far; `--consent yes|no` records the answer; `--folder <entry> --mode all|skeleton|off` sets what one folder may send. */
103
+ export declare const poolRaw: (deps: RunDeps, options: {
104
+ consent?: string | undefined;
105
+ folder?: string | undefined;
106
+ mode?: string | undefined;
107
+ }) => Promise<Outcome>;
108
+ /**
109
+ * `oars pool coverage`: the two bands only the operator can state, kept on this machine and read at deposit. They are what the pool can say about whom a deposit covers, not a filter; `unknown` states nothing.
110
+ * With no flag it prints what is set.
111
+ */
112
+ export declare const poolCoverage: (deps: RunDeps, options: {
113
+ orgSize?: string | undefined;
114
+ repoVisibility?: string | undefined;
115
+ }) => Promise<Outcome>;