@manyoars/oars 0.4.1 → 0.5.1

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 (183) hide show
  1. package/README.md +79 -29
  2. package/dist/bin.js +3 -1
  3. package/dist/cli.d.ts +2 -0
  4. package/dist/cli.js +206 -20
  5. package/dist/club.d.ts +19 -0
  6. package/dist/club.js +132 -0
  7. package/dist/gate/hook-fill-main.js +1 -1
  8. package/dist/gate/hook-fill.d.ts +1 -1
  9. package/dist/gate/hook-fill.js +1 -1
  10. package/dist/gate/hook-main.js +7 -5
  11. package/dist/gate/hook.d.ts +12 -1
  12. package/dist/gate/hook.js +38 -7
  13. package/dist/hook-bin.js +23 -4
  14. package/dist/main.js +5 -0
  15. package/dist/node-floor.d.ts +10 -0
  16. package/dist/node-floor.js +23 -0
  17. package/dist/oars-hook.d.ts +2 -0
  18. package/dist/oars-hook.js +7 -0
  19. package/dist/sessions/allow.d.ts +1 -0
  20. package/dist/sessions/allow.js +1 -1
  21. package/dist/sessions/call-shape.d.ts +111 -0
  22. package/dist/sessions/call-shape.js +464 -0
  23. package/dist/sessions/candidates.d.ts +65 -0
  24. package/dist/sessions/candidates.js +236 -0
  25. package/dist/sessions/card-command.d.ts +24 -0
  26. package/dist/sessions/card-command.js +71 -0
  27. package/dist/sessions/card-font.d.ts +6 -0
  28. package/dist/sessions/card-font.js +36 -0
  29. package/dist/sessions/card-line.d.ts +30 -0
  30. package/dist/sessions/card-line.js +105 -0
  31. package/dist/sessions/card-render.d.ts +15 -0
  32. package/dist/sessions/card-render.js +146 -0
  33. package/dist/sessions/card.d.ts +59 -0
  34. package/dist/sessions/card.js +107 -0
  35. package/dist/sessions/cell-increments.d.ts +14 -3
  36. package/dist/sessions/cell-increments.js +79 -12
  37. package/dist/sessions/cells.d.ts +42 -4
  38. package/dist/sessions/cells.js +72 -18
  39. package/dist/sessions/codex-hook-bin.d.ts +1 -0
  40. package/dist/sessions/codex-hook-bin.js +24 -0
  41. package/dist/sessions/codex-hook-install.d.ts +21 -0
  42. package/dist/sessions/codex-hook-install.js +47 -0
  43. package/dist/sessions/codex-hook-view.d.ts +20 -0
  44. package/dist/sessions/codex-hook-view.js +20 -0
  45. package/dist/sessions/codex-hook.d.ts +77 -0
  46. package/dist/sessions/codex-hook.js +255 -0
  47. package/dist/sessions/codex.d.ts +9 -0
  48. package/dist/sessions/codex.js +104 -18
  49. package/dist/sessions/command.d.ts +17 -2
  50. package/dist/sessions/command.js +145 -33
  51. package/dist/sessions/copilot.d.ts +3 -0
  52. package/dist/sessions/copilot.js +12 -4
  53. package/dist/sessions/derive.js +2 -1
  54. package/dist/sessions/empty-state.d.ts +17 -0
  55. package/dist/sessions/empty-state.js +38 -0
  56. package/dist/sessions/exclusion.js +48 -3
  57. package/dist/sessions/extract.d.ts +16 -3
  58. package/dist/sessions/extract.js +281 -24
  59. package/dist/sessions/gemini.d.ts +2 -0
  60. package/dist/sessions/gemini.js +29 -2
  61. package/dist/sessions/harness-files.d.ts +27 -0
  62. package/dist/sessions/harness-files.js +109 -0
  63. package/dist/sessions/head-only.d.ts +7 -0
  64. package/dist/sessions/head-only.js +21 -0
  65. package/dist/sessions/hook-calls.js +4 -3
  66. package/dist/sessions/hooks.d.ts +1 -1
  67. package/dist/sessions/hooks.js +6 -2
  68. package/dist/sessions/identity.d.ts +6 -0
  69. package/dist/sessions/injected.d.ts +13 -0
  70. package/dist/sessions/injected.js +212 -0
  71. package/dist/sessions/install.d.ts +31 -20
  72. package/dist/sessions/install.js +80 -82
  73. package/dist/sessions/load-status.d.ts +41 -0
  74. package/dist/sessions/load-status.js +156 -0
  75. package/dist/sessions/machine-child-deps.d.ts +5 -0
  76. package/dist/sessions/machine-child-deps.js +83 -0
  77. package/dist/sessions/machine-child.d.ts +43 -0
  78. package/dist/sessions/machine-child.js +120 -0
  79. package/dist/sessions/machine-credential.d.ts +10 -0
  80. package/dist/sessions/machine-credential.js +20 -0
  81. package/dist/sessions/machine-enroll.d.ts +47 -0
  82. package/dist/sessions/machine-enroll.js +230 -0
  83. package/dist/sessions/machine-hold.d.ts +49 -0
  84. package/dist/sessions/machine-hold.js +88 -0
  85. package/dist/sessions/machine-ids.d.ts +6 -0
  86. package/dist/sessions/machine-ids.js +9 -0
  87. package/dist/sessions/machine-notice.d.ts +21 -0
  88. package/dist/sessions/machine-notice.js +89 -0
  89. package/dist/sessions/machine-pull.d.ts +40 -0
  90. package/dist/sessions/machine-pull.js +220 -0
  91. package/dist/sessions/machine-repo.d.ts +7 -0
  92. package/dist/sessions/machine-repo.js +30 -0
  93. package/dist/sessions/machine-scan-cache.d.ts +12 -0
  94. package/dist/sessions/machine-scan-cache.js +47 -0
  95. package/dist/sessions/machine-send.d.ts +12 -0
  96. package/dist/sessions/machine-send.js +156 -0
  97. package/dist/sessions/machine-stop.d.ts +22 -0
  98. package/dist/sessions/machine-stop.js +53 -0
  99. package/dist/sessions/machine.d.ts +41 -0
  100. package/dist/sessions/machine.js +89 -0
  101. package/dist/sessions/opencode.d.ts +2 -0
  102. package/dist/sessions/opencode.js +6 -0
  103. package/dist/sessions/otel.d.ts +21 -0
  104. package/dist/sessions/otel.js +109 -38
  105. package/dist/sessions/owner-only.d.ts +7 -0
  106. package/dist/sessions/owner-only.js +34 -0
  107. package/dist/sessions/pi.d.ts +13 -1
  108. package/dist/sessions/pi.js +27 -13
  109. package/dist/sessions/pool-books.d.ts +1 -1
  110. package/dist/sessions/pool-books.js +1 -1
  111. package/dist/sessions/pool-choices.d.ts +4 -2
  112. package/dist/sessions/pool-choices.js +4 -2
  113. package/dist/sessions/pool-command.d.ts +46 -6
  114. package/dist/sessions/pool-command.js +577 -133
  115. package/dist/sessions/pool-delta.d.ts +7 -0
  116. package/dist/sessions/pool-delta.js +28 -5
  117. package/dist/sessions/pool-due.d.ts +43 -0
  118. package/dist/sessions/pool-due.js +113 -0
  119. package/dist/sessions/pool-nightly.d.ts +9 -1
  120. package/dist/sessions/pool-nightly.js +65 -21
  121. package/dist/sessions/pool-outbox.d.ts +51 -5
  122. package/dist/sessions/pool-outbox.js +217 -24
  123. package/dist/sessions/pool-print.d.ts +1 -1
  124. package/dist/sessions/pool-raw.js +4 -3
  125. package/dist/sessions/pool-replica.d.ts +4 -4
  126. package/dist/sessions/pool-replica.js +26 -7
  127. package/dist/sessions/pool-send-lock.js +1 -1
  128. package/dist/sessions/pool-sent.d.ts +2 -0
  129. package/dist/sessions/pool-sent.js +21 -4
  130. package/dist/sessions/pool-wire.d.ts +172 -12
  131. package/dist/sessions/pool-wire.js +284 -30
  132. package/dist/sessions/pool.js +4 -2
  133. package/dist/sessions/public-vocabulary.d.ts +5 -0
  134. package/dist/sessions/public-vocabulary.js +16 -0
  135. package/dist/sessions/read-call-shape.js +12 -6
  136. package/dist/sessions/read-fit.d.ts +5 -0
  137. package/dist/sessions/read-fit.js +23 -2
  138. package/dist/sessions/read.d.ts +1 -1
  139. package/dist/sessions/recall-consequence.d.ts +2 -2
  140. package/dist/sessions/recall-consequence.js +14 -9
  141. package/dist/sessions/recall-object.d.ts +9 -2
  142. package/dist/sessions/receipt.d.ts +8 -0
  143. package/dist/sessions/receipt.js +78 -0
  144. package/dist/sessions/recovery-calls.d.ts +3 -2
  145. package/dist/sessions/recovery-calls.js +9 -3
  146. package/dist/sessions/redact.d.ts +2 -2
  147. package/dist/sessions/redact.js +116 -14
  148. package/dist/sessions/reversion.d.ts +8 -0
  149. package/dist/sessions/reversion.js +114 -0
  150. package/dist/sessions/schema.d.ts +78 -4
  151. package/dist/sessions/schema.js +31 -1
  152. package/dist/sessions/session-shape.d.ts +2 -1
  153. package/dist/sessions/session-shape.js +15 -0
  154. package/dist/sessions/sources.d.ts +9 -0
  155. package/dist/sessions/sources.js +16 -5
  156. package/dist/sessions/steps.js +3 -2
  157. package/dist/sessions/store.d.ts +41 -2
  158. package/dist/sessions/store.js +68 -16
  159. package/dist/sessions/try-demo.d.ts +8 -0
  160. package/dist/sessions/try-demo.js +90 -0
  161. package/dist/sessions/try.d.ts +13 -0
  162. package/dist/sessions/try.js +50 -0
  163. package/dist/sessions/vscode-copilot.d.ts +4 -0
  164. package/dist/sessions/vscode-copilot.js +25 -18
  165. package/dist/telemetry/command.js +12 -6
  166. package/dist/telemetry/consent.d.ts +9 -3
  167. package/dist/telemetry/consent.js +25 -9
  168. package/dist/telemetry/fields.d.ts +11 -0
  169. package/dist/telemetry/fields.js +56 -0
  170. package/dist/telemetry/measures.d.ts +13 -0
  171. package/dist/telemetry/measures.js +30 -0
  172. package/dist/telemetry/observe.d.ts +15 -2
  173. package/dist/telemetry/observe.js +34 -7
  174. package/dist/telemetry/region.d.ts +6 -0
  175. package/dist/telemetry/region.js +28 -0
  176. package/dist/telemetry/report.js +1 -1
  177. package/dist/telemetry/schema.d.ts +3 -0
  178. package/dist/telemetry/schema.js +11 -1
  179. package/dist/telemetry/send.d.ts +5 -2
  180. package/dist/telemetry/send.js +15 -7
  181. package/dist/telemetry/words.d.ts +6 -0
  182. package/dist/telemetry/words.js +6 -0
  183. package/package.json +23 -4
@@ -2,6 +2,14 @@
2
2
  export declare const piRoot: (env: {
3
3
  [name: string]: string | undefined;
4
4
  }, home?: string) => string;
5
+ /**
6
+ * The folder the reader reads Pi sessions from. The user's own `PI_CODING_AGENT_SESSION_DIR` wins when set and non-empty: Pi writes session files straight into it, with no per-project
7
+ * subfolder (session-manager.ts:1766-1768, main.ts:749-753), and lists only the `.jsonl` files directly in it (listSessionsFromDir, session-manager.ts:942-955). Otherwise it is `sessions/`
8
+ * under the agent folder, whose files sit in `--<cwd>--` subfolders. `--session-dir` and the `sessionDir` setting are not read by this reader.
9
+ */
10
+ export declare const piSessionsDir: (env: {
11
+ [name: string]: string | undefined;
12
+ }, home?: string) => string;
5
13
  type Obj = {
6
14
  [key: string]: unknown;
7
15
  };
@@ -20,6 +28,8 @@ export interface PiStore {
20
28
  sessions: PiSession[];
21
29
  /** The session as transcript text for `captureSession`; throws when the file cannot be read or holds no parseable line. */
22
30
  transcript: (session: PiSession) => Promise<string>;
31
+ /** True when the file holds only its header and entries that carry no turn (`piHeadOnly`); `sessions verify` counts such a file as empty, not unreadable. */
32
+ headOnly: (session: PiSession) => Promise<boolean>;
23
33
  /** Files skipped because their id is not a safe file name (it names a skeleton), counted so the skip is never silent. */
24
34
  rejected: number;
25
35
  /** Sessions that could not be inspected, reported once each and never fatal; the reason names no path. */
@@ -30,7 +40,9 @@ export interface PiStore {
30
40
  }
31
41
  /** The non-blank lines that are not JSON (a torn write), kept so `captureSession` counts them and the deposit line reports them. */
32
42
  export declare const piBadLines: (text: string) => string[];
43
+ export declare const piHeadOnly: (text: string) => boolean;
33
44
  /** One session as the lines `captureSession` reads. */
34
45
  export declare const piLines: (text: string, fallbackId: string) => Obj[];
35
- export declare const openPiStore: (root: string) => Promise<PiStore | undefined>;
46
+ /** `base` is the sessions folder (`piSessionsDir`): its subfolders hold the files Pi groups by project, and a `.jsonl` file directly in it is one Pi wrote to a session folder the user chose. */
47
+ export declare const openPiStore: (base: string) => Promise<PiStore | undefined>;
36
48
  export {};
@@ -5,9 +5,9 @@
5
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
6
  // so `docs/sessions-store.md` says what a live run would still have to prove.
7
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
8
+ // Where it reads from (`piSessionsDir`): `$PI_CODING_AGENT_SESSION_DIR` when set (a flat folder of session files, session-manager.ts:942-955, main.ts:749-753), else `sessions/` under (`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
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.
10
+ // session-manager.ts:590-593). `--session-dir` and the `sessionDir` setting can also move it (docs/sessions.md:60); this reader does not follow those.
11
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
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
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.
@@ -29,13 +29,22 @@
29
29
  import { open, readdir, readFile, stat } from 'node:fs/promises';
30
30
  import { homedir } from 'node:os';
31
31
  import { basename, join, posix, win32 } from 'node:path';
32
+ import { holdsOnlyKinds } from './head-only.js';
33
+ /** Pi expands a leading ~ in its path settings (config.ts:614, utils/paths.ts:134-137). */
34
+ const expandHome = (path, home) => (path === '~' ? home : /^~[/\\]/.test(path) ? join(home, path.slice(2)) : path);
32
35
  /** The Pi agent folder for an environment; a test passes its own so it never reads the real one. */
33
36
  export const piRoot = (env, home = homedir()) => {
34
37
  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;
38
+ return set === undefined || set === '' ? join(home, '.pi', 'agent') : expandHome(set, home);
39
+ };
40
+ /**
41
+ * The folder the reader reads Pi sessions from. The user's own `PI_CODING_AGENT_SESSION_DIR` wins when set and non-empty: Pi writes session files straight into it, with no per-project
42
+ * subfolder (session-manager.ts:1766-1768, main.ts:749-753), and lists only the `.jsonl` files directly in it (listSessionsFromDir, session-manager.ts:942-955). Otherwise it is `sessions/`
43
+ * under the agent folder, whose files sit in `--<cwd>--` subfolders. `--session-dir` and the `sessionDir` setting are not read by this reader.
44
+ */
45
+ export const piSessionsDir = (env, home = homedir()) => {
46
+ const set = env.PI_CODING_AGENT_SESSION_DIR;
47
+ return set === undefined || set === '' ? join(piRoot(env, home), 'sessions') : expandHome(set, home);
39
48
  };
40
49
  const isObj = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
41
50
  const str = (value) => (typeof value === 'string' && value !== '' ? value : undefined);
@@ -62,6 +71,9 @@ const reasonOf = (error, file) => (error instanceof Error ? error.message : Stri
62
71
  const missing = (error) => error instanceof Error && 'code' in error && error.code === 'ENOENT';
63
72
  /** The non-blank lines that are not JSON (a torn write), kept so `captureSession` counts them and the deposit line reports them. */
64
73
  export const piBadLines = (text) => text.split('\n').filter((raw) => raw.trim() !== '' && parse(raw) === undefined);
74
+ /** The session header and the ten entry kinds the format defines that carry no turn (the list at the top of this file). A file of them alone is a session started and quit. */
75
+ const PI_HEAD_KINDS = new Set(['session', 'model_change', 'thinking_level_change', 'usage', 'compaction', 'branch_summary', 'custom', 'custom_message', 'context_edit', 'label', 'session_info']);
76
+ export const piHeadOnly = (text) => holdsOnlyKinds(text, PI_HEAD_KINDS);
65
77
  /** A time in milliseconds, or undefined when it is not an absolute time after 2000. */
66
78
  const MIN_MS = Date.parse('2000-01-01T00:00:00Z');
67
79
  const absoluteMs = (ms) => (ms !== undefined && ms >= MIN_MS ? ms : undefined);
@@ -291,8 +303,8 @@ const firstLine = async (file) => {
291
303
  await handle.close();
292
304
  }
293
305
  };
294
- export const openPiStore = async (root) => {
295
- const base = join(root, 'sessions');
306
+ /** `base` is the sessions folder (`piSessionsDir`): its subfolders hold the files Pi groups by project, and a `.jsonl` file directly in it is one Pi wrote to a session folder the user chose. */
307
+ export const openPiStore = async (base) => {
296
308
  const unreadable = [];
297
309
  let folders;
298
310
  try {
@@ -301,17 +313,18 @@ export const openPiStore = async (root) => {
301
313
  catch (error) {
302
314
  if (missing(error))
303
315
  return undefined;
304
- return { sessions: [], transcript: () => Promise.reject(new Error('no sessions')), rejected: 0, unreadable: [{ file: base, reason: reasonOf(error, base) }] };
316
+ return { sessions: [], transcript: () => Promise.reject(new Error('no sessions')), headOnly: () => Promise.resolve(false), rejected: 0, unreadable: [{ file: base, reason: reasonOf(error, base) }] };
305
317
  }
306
318
  const sessions = [];
307
319
  let rejected = 0;
308
- for (const folder of folders.filter((candidate) => candidate.isDirectory()).sort((a, b) => a.name.localeCompare(b.name))) {
320
+ const places = [base, ...folders.filter((candidate) => candidate.isDirectory()).sort((a, b) => a.name.localeCompare(b.name)).map((folder) => join(base, folder.name))];
321
+ for (const dir of places) {
309
322
  let files;
310
323
  try {
311
- files = await readdir(join(base, folder.name), { withFileTypes: true });
324
+ files = dir === base ? folders : await readdir(dir, { withFileTypes: true });
312
325
  }
313
326
  catch (error) {
314
- unreadable.push({ file: join(base, folder.name), reason: reasonOf(error, join(base, folder.name)) });
327
+ unreadable.push({ file: dir, reason: reasonOf(error, dir) });
315
328
  continue;
316
329
  }
317
330
  for (const entry of files.filter((candidate) => candidate.isFile() && candidate.name.endsWith('.jsonl')).sort((a, b) => a.name.localeCompare(b.name))) {
@@ -322,7 +335,7 @@ export const openPiStore = async (root) => {
322
335
  rejected += 1;
323
336
  continue;
324
337
  }
325
- const file = join(base, folder.name, entry.name);
338
+ const file = join(dir, entry.name);
326
339
  try {
327
340
  const first = await firstLine(file);
328
341
  const header = first === undefined ? undefined : parse(first);
@@ -344,6 +357,7 @@ export const openPiStore = async (root) => {
344
357
  sessions,
345
358
  rejected,
346
359
  unreadable,
360
+ headOnly: async (session) => piHeadOnly(await readFile(session.file, 'utf8')),
347
361
  transcript: async (session) => {
348
362
  const text = await readFile(session.file, 'utf8');
349
363
  const lines = [...piLines(text, session.id).map((line) => JSON.stringify(line)), ...piBadLines(text)];
@@ -5,7 +5,7 @@ export declare const lastFetchedBundle: (storeDir: string) => Promise<Bundle | u
5
5
  export declare const booksLines: (bundle: Bundle | undefined) => string[];
6
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
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. */
8
+ /** Lineage (section 17 rule 6): the thresholded floor (`floors.public`; a clear cell is held to `floors.clear`) 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
9
  floor: number;
10
10
  asOfDay: string | null;
11
11
  panelDay: string | null;
@@ -25,7 +25,7 @@ const candidatesOf = async (storeDir) => {
25
25
  export const lastFetchedBundle = async (storeDir) => {
26
26
  const keys = await loadSignIns(storeDir, 'books');
27
27
  for (const { file, server, harness, version } of await candidatesOf(storeDir)) {
28
- const key = keys.find((entry) => contentHash(entry.server) === server)?.signingKey;
28
+ const key = keys.find((entry) => contentHash(entry.server) === server)?.signingKeys;
29
29
  if (key === undefined || !isHarness(harness))
30
30
  continue;
31
31
  let parsed;
@@ -1,5 +1,7 @@
1
1
  import type { FolderSend, PoolChoices } from './store.js';
2
2
  export type Sends = 'all' | FolderSend;
3
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;
4
+ /** Whether a yes to the raw prompt is held back because it was given under another covenant than the one in force. With no version known (a build that asked no pool) nothing is held back: nothing leaves then, and the sender checks again. */
5
+ export declare const rawStale: (choices: PoolChoices, version: string | undefined) => boolean;
6
+ /** Whether a raw copy of this folder's sessions may be built: raw consent granted for the covenant in force, and the folder neither skeleton only nor off. */
7
+ export declare const rawAllowed: (choices: PoolChoices, project: string, version?: string) => boolean;
@@ -7,5 +7,7 @@ export const sendsOf = (choices, project) => {
7
7
  return 'off';
8
8
  return modes.includes('skeleton') ? 'skeleton' : 'all';
9
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';
10
+ /** Whether a yes to the raw prompt is held back because it was given under another covenant than the one in force. With no version known (a build that asked no pool) nothing is held back: nothing leaves then, and the sender checks again. */
11
+ export const rawStale = (choices, version) => choices.rawConsent === 'granted' && version !== undefined && choices.rawConsentVersion !== version;
12
+ /** Whether a raw copy of this folder's sessions may be built: raw consent granted for the covenant in force, and the folder neither skeleton only nor off. */
13
+ export const rawAllowed = (choices, project, version) => choices.rawConsent === 'granted' && !rawStale(choices, version) && sendsOf(choices, project) === 'all';
@@ -2,6 +2,7 @@ import type { Outcome, RunDeps } from '../cli.js';
2
2
  import { CliError } from '../errors.js';
3
3
  import { Masker, type Outgoing } from './pool-print.js';
4
4
  import { isObject, loadSignIns, textIn, type SignIn } from './pool-replica.js';
5
+ import { type MachineConfig } from './machine.js';
5
6
  import { type SessionsRuntime } from './store.js';
6
7
  import { type Git } from './survival.js';
7
8
  export declare const DEPOSIT = "pool-deposit";
@@ -34,10 +35,12 @@ interface Call {
34
35
  /** Set for a command that prints what it sends: the print comes first, with these secrets masked. */
35
36
  show?: Masker;
36
37
  /** 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
+ method?: 'PUT' | 'DELETE';
38
39
  type?: string;
39
40
  /** Headers beyond the usual ones (the raw routes state their redaction and capture versions, and the raw consent). */
40
41
  extra?: Array<[string, string]>;
42
+ /** The answer's bytes are kept as bytes when it is a 200, not read as JSON: the person's own raw copy. */
43
+ binary?: boolean;
41
44
  }
42
45
  /** 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
46
  export type Sender = (request: Outgoing) => Promise<Reply>;
@@ -45,19 +48,33 @@ export type Sender = (request: Outgoing) => Promise<Reply>;
45
48
  export declare const ask: (deps: RunDeps, step: string, server: string, path: string, init: Call, via?: Sender) => Promise<Reply>;
46
49
  /** 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
50
  export declare const networkSender: (deps: RunDeps, step: string) => Sender;
51
+ /** The server's named refusal, as a failure: its `error` is the problem's code in `--json`. */
52
+ export declare const refusal: (step: string, { status, body }: Reply) => CliError;
48
53
  /**
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.
54
+ * `oars pool login` (spec Section 1.4): the pool runs the provider's device flow and this client only shows the code and polls the pool, so no provider token, device code, client ID, or secret is ever here. With `--verbose`, every request, which goes to the pool alone,
55
+ * prints before it is sent, with the login handle and the credential masked as `<credential: n bytes>`; without it, a failure's cause is the first line printed.
51
56
  */
52
57
  export declare const poolLogin: (deps: RunDeps, options: {
53
58
  server?: string | undefined;
54
59
  provider?: string | undefined;
60
+ verbose?: boolean;
55
61
  }) => Promise<Outcome>;
62
+ /**
63
+ * `oars pool logout` (S8): revokes this machine's credential at the pool (`DELETE /v1/login`), then removes the local entry. A pool that cannot be reached does not keep the entry: the person asked to be signed out here, so the entry
64
+ * goes and the output says the credential was not revoked there (it lapses on its own, and a login past the pool's cap revokes the oldest). A refusal for any other reason keeps the entry, so the command can be run again.
65
+ */
66
+ export declare const poolLogout: (deps: RunDeps, options: {
67
+ server?: string | undefined;
68
+ }) => Promise<Outcome>;
69
+ /** A person is here when input and the screen's stream are both terminals: a typed phrase counts only for a text that reached a screen. */
70
+ export declare const isTerminal: (deps: RunDeps) => boolean;
71
+ /** The next line a person types, or `undefined` when the input ends first. The interface is closed after it, so the terminal is released. */
72
+ export declare const lineFrom: (input: NodeJS.ReadableStream) => Promise<string | undefined>;
56
73
  export declare const vocabularyExpired: (deps: RunDeps) => CliError | undefined;
57
74
  /** 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
75
  export declare const postBatch: (deps: RunDeps, options: {
59
76
  server: string;
60
- token: string;
77
+ token: string | undefined;
61
78
  bytes: string;
62
79
  hash: string;
63
80
  via: Sender;
@@ -72,19 +89,27 @@ export declare const postRaw: (deps: RunDeps, options: {
72
89
  hash: string;
73
90
  body: string;
74
91
  bytes: number;
92
+ consent: string;
75
93
  via: Sender;
76
94
  }) => Promise<void>;
95
+ /** The exclusion terms in force now, re-read from the term file each time it is asked: empty when the file is missing or unreadable. */
96
+ export declare const currentTerms: (deps: RunDeps) => Promise<string[]>;
97
+ /** The outbox key, and the skeleton `id`, of a machine's session: from the environment's session salt (per account, not per machine), else its own name standing in for the account, which a machine has none of. The holding route names its branch by the same key. */
98
+ export declare const machineKeyOf: (machine: MachineConfig, session: string) => string;
77
99
  /**
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
100
+ * `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: no session data is sent. The gates run before any projection does: the folder
79
101
  * 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
102
  * 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
103
  */
82
104
  export declare const poolDeposit: (deps: RunDeps, options: {
83
105
  server?: string | undefined;
84
106
  acceptCovenant?: string | undefined;
107
+ inEuEeaUk?: string | undefined;
85
108
  send?: string | undefined;
86
109
  via?: Sender | undefined;
87
110
  git?: Git | undefined;
111
+ session?: string | undefined;
112
+ covenant?: string | undefined;
88
113
  }) => Promise<Outcome>;
89
114
  /** `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
115
  export declare const poolOutbox: (deps: RunDeps, options: {
@@ -97,8 +122,10 @@ export declare const poolFetch: (deps: RunDeps, options: {
97
122
  harness?: string | undefined;
98
123
  harnessVersion: string;
99
124
  }) => 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. */
125
+ /** The raw prompt, in plain words: shown by `oars pool raw` until it is answered, and what the detached sender relies on. Redaction is best effort and the text says so. */
101
126
  export declare const RAW_PROMPT: string;
127
+ /** What a person types to say yes to the raw prompt: consent is a statement made at a terminal (GDPR Articles 7 and 9(2)(a)), not a flag a script can pass. */
128
+ export declare const RAW_PHRASE = "I consent to sending raw copies";
102
129
  /** `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
130
  export declare const poolRaw: (deps: RunDeps, options: {
104
131
  consent?: string | undefined;
@@ -113,3 +140,16 @@ export declare const poolCoverage: (deps: RunDeps, options: {
113
140
  orgSize?: string | undefined;
114
141
  repoVisibility?: string | undefined;
115
142
  }) => Promise<Outcome>;
143
+ /**
144
+ * `oars pool prove`: the account proves control of itself with its sign-in token alone (`POST /v1/account/proof`, never a machine key), and the pool stores the time. It prints the account and the time to send, in reply to the operator's request for proof, so the operator can compare them with the stored row (GDPR Art. 12(6)). A lapsed sign-in says to run `oars pool login` first; a closed account proves by that login instead.
145
+ */
146
+ export declare const poolProve: (deps: RunDeps, options: {
147
+ server?: string | undefined;
148
+ }) => Promise<Outcome>;
149
+ /** `oars pool export`: the person's own copy of what the pool holds about their account, saved to a folder (GDPR Articles 15(3) and 20). It follows the pool's cursor page by page and keeps each page as a file; with `raw` it also fetches each raw object the ledger lists that still stands. It writes nothing to the pool. A failed page stops the walk (there is no cursor past it); a failed object does not stop the others. Every failure is named in the error, with what was saved. */
150
+ export declare const poolExport: (deps: RunDeps, options: {
151
+ server?: string | undefined;
152
+ out: string;
153
+ raw?: boolean | undefined;
154
+ via?: Sender | undefined;
155
+ }) => Promise<Outcome>;