@manyoars/oars 0.1.1 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/README.md +134 -26
  2. package/dist/api.js +1 -1
  3. package/dist/bin.js +6 -29
  4. package/dist/cli.d.ts +6 -3
  5. package/dist/cli.js +370 -72
  6. package/dist/commands/keys.d.ts +31 -0
  7. package/dist/commands/keys.js +65 -0
  8. package/dist/commands/login.d.ts +1 -1
  9. package/dist/commands/login.js +3 -5
  10. package/dist/errors.d.ts +13 -13
  11. package/dist/errors.js +28 -11
  12. package/dist/gate/checks.d.ts +68 -0
  13. package/dist/gate/checks.js +584 -0
  14. package/dist/gate/command.d.ts +14 -0
  15. package/dist/gate/command.js +61 -0
  16. package/dist/gate/hook-fill-main.d.ts +1 -0
  17. package/dist/gate/hook-fill-main.js +16 -0
  18. package/dist/gate/hook-fill.d.ts +38 -0
  19. package/dist/gate/hook-fill.js +94 -0
  20. package/dist/gate/hook-main.d.ts +1 -0
  21. package/dist/gate/hook-main.js +35 -0
  22. package/dist/gate/hook-process.d.ts +14 -0
  23. package/dist/gate/hook-process.js +64 -0
  24. package/dist/gate/hook.d.ts +46 -0
  25. package/dist/gate/hook.js +256 -0
  26. package/dist/gate/install.d.ts +25 -0
  27. package/dist/gate/install.js +126 -0
  28. package/dist/gate/local-bin.d.ts +8 -0
  29. package/dist/gate/local-bin.js +36 -0
  30. package/dist/gate/notes.d.ts +19 -0
  31. package/dist/gate/notes.js +27 -0
  32. package/dist/gate/novelty.d.ts +35 -0
  33. package/dist/gate/novelty.js +99 -0
  34. package/dist/gate/policy.d.ts +25 -0
  35. package/dist/gate/policy.js +73 -0
  36. package/dist/gate/record.d.ts +120 -0
  37. package/dist/gate/record.js +125 -0
  38. package/dist/gate/registry-state.d.ts +10 -0
  39. package/dist/gate/registry-state.js +30 -0
  40. package/dist/gate/registry.d.ts +56 -0
  41. package/dist/gate/registry.js +94 -0
  42. package/dist/gate/replay.d.ts +20 -0
  43. package/dist/gate/replay.js +257 -0
  44. package/dist/gate/report.d.ts +50 -0
  45. package/dist/gate/report.js +89 -0
  46. package/dist/gate/scope.d.ts +7 -0
  47. package/dist/gate/scope.js +27 -0
  48. package/dist/gate/transcripts.d.ts +68 -0
  49. package/dist/gate/transcripts.js +232 -0
  50. package/dist/hook-bin.d.ts +1 -0
  51. package/dist/hook-bin.js +25 -0
  52. package/dist/issuer.d.ts +16 -0
  53. package/dist/issuer.js +55 -0
  54. package/dist/main.d.ts +1 -0
  55. package/dist/main.js +64 -0
  56. package/dist/oidc.js +1 -1
  57. package/dist/sessions/actions.d.ts +35 -0
  58. package/dist/sessions/actions.js +351 -0
  59. package/dist/sessions/allow.d.ts +14 -0
  60. package/dist/sessions/allow.js +51 -0
  61. package/dist/sessions/archive.d.ts +11 -0
  62. package/dist/sessions/archive.js +38 -0
  63. package/dist/sessions/audit.d.ts +42 -0
  64. package/dist/sessions/audit.js +104 -0
  65. package/dist/sessions/baseline.d.ts +62 -0
  66. package/dist/sessions/baseline.js +188 -0
  67. package/dist/sessions/capture-runtime.d.ts +10 -0
  68. package/dist/sessions/capture-runtime.js +12 -0
  69. package/dist/sessions/cell-increments.d.ts +43 -0
  70. package/dist/sessions/cell-increments.js +209 -0
  71. package/dist/sessions/cells.d.ts +79 -0
  72. package/dist/sessions/cells.js +181 -0
  73. package/dist/sessions/codex.d.ts +53 -0
  74. package/dist/sessions/codex.js +679 -0
  75. package/dist/sessions/command.d.ts +117 -0
  76. package/dist/sessions/command.js +373 -0
  77. package/dist/sessions/copilot.d.ts +40 -0
  78. package/dist/sessions/copilot.js +432 -0
  79. package/dist/sessions/cursor.d.ts +24 -0
  80. package/dist/sessions/cursor.js +324 -0
  81. package/dist/sessions/derive.d.ts +57 -0
  82. package/dist/sessions/derive.js +320 -0
  83. package/dist/sessions/exclusion.d.ts +81 -0
  84. package/dist/sessions/exclusion.js +353 -0
  85. package/dist/sessions/extract.d.ts +179 -0
  86. package/dist/sessions/extract.js +1774 -0
  87. package/dist/sessions/fold.d.ts +17 -0
  88. package/dist/sessions/fold.js +71 -0
  89. package/dist/sessions/frame.d.ts +24 -0
  90. package/dist/sessions/frame.js +95 -0
  91. package/dist/sessions/gemini.d.ts +37 -0
  92. package/dist/sessions/gemini.js +613 -0
  93. package/dist/sessions/gold-arms.d.ts +67 -0
  94. package/dist/sessions/gold-arms.js +172 -0
  95. package/dist/sessions/gold.d.ts +197 -0
  96. package/dist/sessions/gold.js +463 -0
  97. package/dist/sessions/graph.d.ts +12 -0
  98. package/dist/sessions/graph.js +34 -0
  99. package/dist/sessions/grok.d.ts +36 -0
  100. package/dist/sessions/grok.js +421 -0
  101. package/dist/sessions/hook-calls.d.ts +3 -0
  102. package/dist/sessions/hook-calls.js +47 -0
  103. package/dist/sessions/hook-index.d.ts +53 -0
  104. package/dist/sessions/hook-index.js +157 -0
  105. package/dist/sessions/hooks.d.ts +13 -0
  106. package/dist/sessions/hooks.js +170 -0
  107. package/dist/sessions/identity.d.ts +22 -0
  108. package/dist/sessions/identity.js +101 -0
  109. package/dist/sessions/install.d.ts +54 -0
  110. package/dist/sessions/install.js +201 -0
  111. package/dist/sessions/lineage.d.ts +19 -0
  112. package/dist/sessions/lineage.js +118 -0
  113. package/dist/sessions/mcp.d.ts +6 -0
  114. package/dist/sessions/mcp.js +153 -0
  115. package/dist/sessions/merkle.d.ts +7 -0
  116. package/dist/sessions/merkle.js +28 -0
  117. package/dist/sessions/motif.d.ts +43 -0
  118. package/dist/sessions/motif.js +59 -0
  119. package/dist/sessions/package-resolve.d.ts +30 -0
  120. package/dist/sessions/package-resolve.js +183 -0
  121. package/dist/sessions/pending.d.ts +34 -0
  122. package/dist/sessions/pending.js +142 -0
  123. package/dist/sessions/pool-command.d.ts +44 -0
  124. package/dist/sessions/pool-command.js +542 -0
  125. package/dist/sessions/pool-delta.d.ts +54 -0
  126. package/dist/sessions/pool-delta.js +190 -0
  127. package/dist/sessions/pool-outbox.d.ts +63 -0
  128. package/dist/sessions/pool-outbox.js +260 -0
  129. package/dist/sessions/pool-print.d.ts +26 -0
  130. package/dist/sessions/pool-print.js +68 -0
  131. package/dist/sessions/pool-wire.d.ts +225 -0
  132. package/dist/sessions/pool-wire.js +620 -0
  133. package/dist/sessions/pool.d.ts +32 -0
  134. package/dist/sessions/pool.js +164 -0
  135. package/dist/sessions/projection.d.ts +75 -0
  136. package/dist/sessions/projection.js +165 -0
  137. package/dist/sessions/public-vocabulary.d.ts +73 -0
  138. package/dist/sessions/public-vocabulary.js +302 -0
  139. package/dist/sessions/query.d.ts +111 -0
  140. package/dist/sessions/query.js +246 -0
  141. package/dist/sessions/read-adoption.d.ts +2 -0
  142. package/dist/sessions/read-adoption.js +27 -0
  143. package/dist/sessions/read-call-shape.d.ts +2 -0
  144. package/dist/sessions/read-call-shape.js +25 -0
  145. package/dist/sessions/read-change.d.ts +2 -0
  146. package/dist/sessions/read-change.js +30 -0
  147. package/dist/sessions/read-cost.d.ts +4 -0
  148. package/dist/sessions/read-cost.js +37 -0
  149. package/dist/sessions/read-day-move.d.ts +3 -0
  150. package/dist/sessions/read-day-move.js +65 -0
  151. package/dist/sessions/read-fit.d.ts +7 -0
  152. package/dist/sessions/read-fit.js +41 -0
  153. package/dist/sessions/read-interaction.d.ts +5 -0
  154. package/dist/sessions/read-interaction.js +62 -0
  155. package/dist/sessions/read-lead-lag.d.ts +15 -0
  156. package/dist/sessions/read-lead-lag.js +81 -0
  157. package/dist/sessions/read-live.d.ts +6 -0
  158. package/dist/sessions/read-live.js +38 -0
  159. package/dist/sessions/read-method.d.ts +2 -0
  160. package/dist/sessions/read-method.js +29 -0
  161. package/dist/sessions/read-next-step.d.ts +2 -0
  162. package/dist/sessions/read-next-step.js +35 -0
  163. package/dist/sessions/read-order.d.ts +54 -0
  164. package/dist/sessions/read-order.js +62 -0
  165. package/dist/sessions/read-readable.d.ts +8 -0
  166. package/dist/sessions/read-readable.js +24 -0
  167. package/dist/sessions/read-recovery.d.ts +20 -0
  168. package/dist/sessions/read-recovery.js +97 -0
  169. package/dist/sessions/read-rows.d.ts +13 -0
  170. package/dist/sessions/read-rows.js +47 -0
  171. package/dist/sessions/read-substitution.d.ts +5 -0
  172. package/dist/sessions/read-substitution.js +51 -0
  173. package/dist/sessions/read-support.d.ts +48 -0
  174. package/dist/sessions/read-support.js +73 -0
  175. package/dist/sessions/read-tool-day.d.ts +2 -0
  176. package/dist/sessions/read-tool-day.js +26 -0
  177. package/dist/sessions/read-version-boundary.d.ts +31 -0
  178. package/dist/sessions/read-version-boundary.js +95 -0
  179. package/dist/sessions/read.d.ts +79 -0
  180. package/dist/sessions/read.js +84 -0
  181. package/dist/sessions/recall-consequence.d.ts +45 -0
  182. package/dist/sessions/recall-consequence.js +179 -0
  183. package/dist/sessions/recall-object.d.ts +137 -0
  184. package/dist/sessions/recall-object.js +77 -0
  185. package/dist/sessions/recall-pool.d.ts +19 -0
  186. package/dist/sessions/recall-pool.js +96 -0
  187. package/dist/sessions/recall-push.d.ts +26 -0
  188. package/dist/sessions/recall-push.js +95 -0
  189. package/dist/sessions/recall-reads.d.ts +117 -0
  190. package/dist/sessions/recall-reads.js +410 -0
  191. package/dist/sessions/recall-render.d.ts +19 -0
  192. package/dist/sessions/recall-render.js +168 -0
  193. package/dist/sessions/redact.d.ts +6 -0
  194. package/dist/sessions/redact.js +54 -0
  195. package/dist/sessions/repo-root.d.ts +10 -0
  196. package/dist/sessions/repo-root.js +101 -0
  197. package/dist/sessions/schema.d.ts +644 -0
  198. package/dist/sessions/schema.js +148 -0
  199. package/dist/sessions/session-shape.d.ts +73 -0
  200. package/dist/sessions/session-shape.js +342 -0
  201. package/dist/sessions/sources.d.ts +50 -0
  202. package/dist/sessions/sources.js +159 -0
  203. package/dist/sessions/steps.d.ts +105 -0
  204. package/dist/sessions/steps.js +250 -0
  205. package/dist/sessions/store.d.ts +297 -0
  206. package/dist/sessions/store.js +1478 -0
  207. package/dist/sessions/strata.d.ts +26 -0
  208. package/dist/sessions/strata.js +77 -0
  209. package/dist/sessions/survival.d.ts +25 -0
  210. package/dist/sessions/survival.js +230 -0
  211. package/dist/sessions/verify.d.ts +53 -0
  212. package/dist/sessions/verify.js +286 -0
  213. package/dist/sessions/vocab-load.d.ts +26 -0
  214. package/dist/sessions/vocab-load.js +61 -0
  215. package/dist/sessions/vscode-copilot.d.ts +38 -0
  216. package/dist/sessions/vscode-copilot.js +477 -0
  217. package/package.json +4 -5
  218. package/vocab/crates.json +1 -0
  219. package/vocab/go.json +1 -0
  220. package/vocab/harness.json +1 -0
  221. package/vocab/homebrew.json +1 -0
  222. package/vocab/manifest.json +1 -0
  223. package/vocab/maven.json +1 -0
  224. package/vocab/models.json +1 -0
  225. package/vocab/npm.json +1 -0
  226. package/vocab/programs.json +1 -0
  227. package/vocab/pypi.json +1 -0
  228. package/vocab/rubygems.json +1 -0
  229. package/dist/commands/deploy-input.d.ts +0 -35
  230. package/dist/commands/deploy-input.js +0 -107
  231. package/dist/commands/deploy.d.ts +0 -22
  232. package/dist/commands/deploy.js +0 -120
  233. package/dist/commands/status.d.ts +0 -7
  234. package/dist/commands/status.js +0 -18
  235. package/dist/commands/test-charge.d.ts +0 -11
  236. package/dist/commands/test-charge.js +0 -34
  237. package/dist/journal.d.ts +0 -26
  238. package/dist/journal.js +0 -58
  239. package/parity/deploy-plans/paid-api.json +0 -34
  240. package/parity/deploy-plans/per-task-agent.json +0 -34
@@ -0,0 +1,17 @@
1
+ import type { ErrorLineObservation, SessionObservation, ToolObservation } from './schema.js';
2
+ /**
3
+ * One record per `toolUseId`, in the order of the first record of each. The kept record is the first, with the `status` and `durationMs` of the first
4
+ * record that has a status when its own is `none`, and the `target`, `targetBase`, `ts`, and `harnessVersion` of the first record that has a `ts` when
5
+ * its own has none, so a call keeps its position and prompt and the result and path it was given. A record with no id is its own call.
6
+ *
7
+ * The kept records are renumbered to their place in the array, and each error line's `after` (the count of records written before it) is mapped to the
8
+ * count of kept records written before it, so `derive.ts`, which slices the calls at `after`, reads the calls capture version 8 would have numbered.
9
+ * Returns the records dropped too, so the session's own counts can be brought into line.
10
+ */
11
+ export declare const foldToolRows: (written: readonly ToolObservation[], errorLines: readonly ErrorLineObservation[]) => {
12
+ tools: ToolObservation[];
13
+ dropped: ToolObservation[];
14
+ errorLines: ErrorLineObservation[];
15
+ };
16
+ /** The session with the dropped calls taken out of its per-tool counts and its shell count, the numbers capture version 8 would have written. */
17
+ export declare const withoutReplays: (session: SessionObservation, dropped: readonly ToolObservation[]) => SessionObservation;
@@ -0,0 +1,71 @@
1
+ import { SHELL } from './extract.js';
2
+ // One tool call is one observation. Capture version 8 writes a call once; a record set captured before it holds a second `tool` record, status
3
+ // `none`, for every call a resumed transcript replayed. The reader folds those so every count over `store.tools` agrees with the new capture until each
4
+ // transcript is captured again.
5
+ /** The record a folded call keeps when a later copy of it is the one with the real line: its status, duration, and the fields a blob copy cannot know. */
6
+ const settled = (held, later) => {
7
+ const status = held.status === 'none' && later.status !== 'none' ? { status: later.status, durationMs: later.durationMs } : {};
8
+ // A copy with no `ts` came from a line with no `cwd` either, so its path hash is against the working directory, not the repository.
9
+ const line = held.ts === null && later.ts !== null ? { target: later.target, targetBase: later.targetBase, ts: later.ts, harnessVersion: later.harnessVersion } : {};
10
+ return { ...held, ...status, ...line };
11
+ };
12
+ /**
13
+ * One record per `toolUseId`, in the order of the first record of each. The kept record is the first, with the `status` and `durationMs` of the first
14
+ * record that has a status when its own is `none`, and the `target`, `targetBase`, `ts`, and `harnessVersion` of the first record that has a `ts` when
15
+ * its own has none, so a call keeps its position and prompt and the result and path it was given. A record with no id is its own call.
16
+ *
17
+ * The kept records are renumbered to their place in the array, and each error line's `after` (the count of records written before it) is mapped to the
18
+ * count of kept records written before it, so `derive.ts`, which slices the calls at `after`, reads the calls capture version 8 would have numbered.
19
+ * Returns the records dropped too, so the session's own counts can be brought into line.
20
+ */
21
+ export const foldToolRows = (written, errorLines) => {
22
+ const first = new Map();
23
+ const kept = [];
24
+ const dropped = [];
25
+ const keptAt = [];
26
+ for (const tool of [...written].sort((a, b) => a.n - b.n)) {
27
+ const at = tool.toolUseId === null ? undefined : first.get(tool.toolUseId);
28
+ if (tool.toolUseId !== null && at === undefined)
29
+ first.set(tool.toolUseId, kept.length);
30
+ if (at === undefined) {
31
+ kept.push(tool);
32
+ keptAt.push(tool.n);
33
+ continue;
34
+ }
35
+ dropped.push(tool);
36
+ const held = kept[at];
37
+ if (held !== undefined)
38
+ kept[at] = settled(held, tool);
39
+ }
40
+ // `keptAt` is ascending, so the kept records written before `after` are the ones whose old `n` is below it.
41
+ const before = (after) => {
42
+ let low = 0;
43
+ let high = keptAt.length;
44
+ while (low < high) {
45
+ const middle = Math.floor((low + high) / 2);
46
+ if ((keptAt[middle] ?? 0) < after)
47
+ low = middle + 1;
48
+ else
49
+ high = middle;
50
+ }
51
+ return low;
52
+ };
53
+ return {
54
+ tools: kept.map((tool, n) => ({ ...tool, n })),
55
+ dropped,
56
+ errorLines: errorLines.map((error) => ({ ...error, after: before(error.after) })),
57
+ };
58
+ };
59
+ /** The session with the dropped calls taken out of its per-tool counts and its shell count, the numbers capture version 8 would have written. */
60
+ export const withoutReplays = (session, dropped) => {
61
+ if (dropped.length === 0)
62
+ return session;
63
+ const counts = { ...session.tools };
64
+ let shell = session.bashCmds;
65
+ for (const tool of dropped) {
66
+ counts[tool.tool] = Math.max((counts[tool.tool] ?? 0) - 1, 0);
67
+ if (SHELL.has(tool.tool))
68
+ shell = Math.max(shell - 1, 0);
69
+ }
70
+ return { ...session, tools: Object.fromEntries(Object.entries(counts).filter(([, count]) => count > 0)), bashCmds: shell };
71
+ };
@@ -0,0 +1,24 @@
1
+ import { type RepoSize } from './public-vocabulary.js';
2
+ import type { Frame, FrameStack } from './schema.js';
3
+ /** The UTC day of a timestamp, whatever offset it was written in; null when there is none or it does not parse. */
4
+ export declare const utcDay: (ts: string | null | undefined) => string | null;
5
+ /** A stack holding only closed-vocabulary values, sorted; anything else is dropped, not masked, because the stack has no room for an unknown. */
6
+ export declare const closedStack: (raw: {
7
+ languages: readonly string[];
8
+ frameworks: readonly string[];
9
+ size: string | null;
10
+ }) => FrameStack;
11
+ /** The bucket of a repository's tracked-file count; null when the count is not known. */
12
+ export declare const repoSizeOf: (files: number | null) => RepoSize | null;
13
+ /** The stack a file's evidence shows. Only names from the vocabulary come out, so a path or a program name can never pass through. */
14
+ export declare const stackOf: (evidence: {
15
+ paths: readonly string[];
16
+ programs: readonly string[];
17
+ size: RepoSize | null;
18
+ }) => FrameStack;
19
+ /** The frame with every free-standing name held to the public vocabulary. */
20
+ export declare const closedFrame: (raw: Frame) => Frame;
21
+ /** The frame's hash: unsalted, so one frame reads alike across accounts (D1's `hP`), 16 hex characters, over the fields in a fixed order. */
22
+ export declare const frameIdOf: (frame: Frame) => string;
23
+ /** How many files a repository tracks, from its git index's header: no git process, and null when there is no readable index. */
24
+ export declare const repoFilesFromIndex: (root: string) => number | null;
@@ -0,0 +1,95 @@
1
+ // The frame (recall spec Section 2.1): where and when a prompt ran, as public names only, and its hash. A step takes its prompt's frame,
2
+ // and reading one motif across frames is how the record compares models, harnesses, versions, and dates.
3
+ import { createHash } from 'node:crypto';
4
+ import { closeSync, openSync, readFileSync, readSync, statSync } from 'node:fs';
5
+ import { join, resolve } from 'node:path';
6
+ import { FRAMEWORK_OF_FILE, FRAMEWORK_OF_PROGRAM, FRAMEWORKS, LANGUAGE_OF_EXTENSION, LANGUAGES, publicEffort, publicModel, publicVersion, REPO_SIZES } from './public-vocabulary.js';
7
+ /** The language mix keeps this many languages, so a frame stays a coordinate and not a fingerprint of one repository. */
8
+ const LANGUAGES_PER_STACK = 3;
9
+ /** The UTC day of a timestamp, whatever offset it was written in; null when there is none or it does not parse. */
10
+ export const utcDay = (ts) => {
11
+ if (ts === null || ts === undefined || ts === '')
12
+ return null;
13
+ const millis = Date.parse(ts);
14
+ return Number.isNaN(millis) ? null : new Date(millis).toISOString().slice(0, 10);
15
+ };
16
+ /** A stack holding only closed-vocabulary values, sorted; anything else is dropped, not masked, because the stack has no room for an unknown. */
17
+ export const closedStack = (raw) => ({
18
+ languages: [...new Set(raw.languages)].filter((language) => LANGUAGES.has(language)).sort(),
19
+ frameworks: [...new Set(raw.frameworks)].filter((framework) => FRAMEWORKS.has(framework)).sort(),
20
+ size: REPO_SIZES.find((size) => size === raw.size) ?? null,
21
+ });
22
+ /** The bucket of a repository's tracked-file count; null when the count is not known. */
23
+ export const repoSizeOf = (files) => {
24
+ if (files === null)
25
+ return null;
26
+ if (files < 100)
27
+ return 'xs';
28
+ if (files < 1000)
29
+ return 's';
30
+ if (files < 10000)
31
+ return 'm';
32
+ return files < 100000 ? 'l' : 'xl';
33
+ };
34
+ const baseName = (path) => path.replace(/\\/g, '/').split('/').pop() ?? path;
35
+ /** The stack a file's evidence shows. Only names from the vocabulary come out, so a path or a program name can never pass through. */
36
+ export const stackOf = (evidence) => {
37
+ const counts = new Map();
38
+ const frameworks = [];
39
+ for (const path of evidence.paths) {
40
+ const base = baseName(path);
41
+ const language = LANGUAGE_OF_EXTENSION.get(base.split('.').pop()?.toLowerCase() ?? '');
42
+ if (base.includes('.') && language !== undefined)
43
+ counts.set(language, (counts.get(language) ?? 0) + 1);
44
+ for (const [pattern, name] of FRAMEWORK_OF_FILE)
45
+ if (pattern.test(base))
46
+ frameworks.push(name);
47
+ }
48
+ for (const program of evidence.programs) {
49
+ const name = FRAMEWORK_OF_PROGRAM.get(program);
50
+ if (name !== undefined)
51
+ frameworks.push(name);
52
+ }
53
+ // Most touched first, a tie by name, so the mix does not depend on the order the files were touched in.
54
+ const languages = [...counts].sort(([a, one], [b, two]) => two - one || a.localeCompare(b)).slice(0, LANGUAGES_PER_STACK).map(([language]) => language);
55
+ return closedStack({ languages, frameworks, size: evidence.size });
56
+ };
57
+ /** The frame with every free-standing name held to the public vocabulary. */
58
+ export const closedFrame = (raw) => ({
59
+ ...raw,
60
+ harnessVersion: publicVersion(raw.harnessVersion),
61
+ model: publicModel(raw.model),
62
+ effort: publicEffort(raw.effort),
63
+ });
64
+ /** The frame's hash: unsalted, so one frame reads alike across accounts (D1's `hP`), 16 hex characters, over the fields in a fixed order. */
65
+ export const frameIdOf = (frame) => {
66
+ const { harness, harnessVersion, model, effort, day, platform, shell, stack } = frame;
67
+ const canonical = JSON.stringify([harness, harnessVersion, model, effort, day, platform, shell, stack.languages, stack.frameworks, stack.size]);
68
+ return createHash('sha256').update(canonical).digest('hex').slice(0, 16);
69
+ };
70
+ const INDEX_HEADER_BYTES = 12;
71
+ /** Where a checkout's git index is. In a linked worktree or a submodule `.git` is a file whose `gitdir:` line names the real git folder, absolute or relative to the checkout. */
72
+ const indexPathOf = (root) => {
73
+ const dotGit = join(root, '.git');
74
+ if (statSync(dotGit).isDirectory())
75
+ return join(dotGit, 'index');
76
+ const pointer = /^gitdir:\s*(.+?)\s*$/m.exec(readFileSync(dotGit, 'utf8'))?.[1];
77
+ return pointer === undefined ? join(dotGit, 'index') : join(resolve(root, pointer), 'index');
78
+ };
79
+ /** How many files a repository tracks, from its git index's header: no git process, and null when there is no readable index. */
80
+ export const repoFilesFromIndex = (root) => {
81
+ let descriptor;
82
+ try {
83
+ descriptor = openSync(indexPathOf(root), 'r');
84
+ const header = Buffer.alloc(INDEX_HEADER_BYTES);
85
+ const read = readSync(descriptor, header, 0, INDEX_HEADER_BYTES, 0);
86
+ return read === INDEX_HEADER_BYTES && header.toString('latin1', 0, 4) === 'DIRC' ? header.readUInt32BE(8) : null;
87
+ }
88
+ catch {
89
+ return null;
90
+ }
91
+ finally {
92
+ if (descriptor !== undefined)
93
+ closeSync(descriptor);
94
+ }
95
+ };
@@ -0,0 +1,37 @@
1
+ /** The Gemini folder for an environment; a test passes its own so it never reads the real one. */
2
+ export declare const geminiRoot: (env: {
3
+ [name: string]: string | undefined;
4
+ }, home?: string) => string;
5
+ type Obj = {
6
+ [key: string]: unknown;
7
+ };
8
+ /** A session found in the store, before its records are read. */
9
+ export interface GeminiSession {
10
+ /** The head's `sessionId` (else the file's name); a subagent's is `<parent>-<file name>`. It names the skeleton. */
11
+ id: string;
12
+ /** What `.project_root` names, or for a hash-named folder a path that hashes to its name; null when neither gives one. */
13
+ folder: string | null;
14
+ file: string;
15
+ size: number;
16
+ mtimeMs: number;
17
+ /** The parent session's id for a subagent's file; null for a main session. */
18
+ parent: string | null;
19
+ }
20
+ export interface GeminiStore {
21
+ sessions: GeminiSession[];
22
+ /** The session as transcript text for `captureSession`; throws when the file cannot be read or holds no parseable line. */
23
+ transcript: (session: GeminiSession) => Promise<string>;
24
+ /** Sessions skipped because their id is not a safe file name (it names a skeleton), counted so the skip is never silent. */
25
+ rejected: number;
26
+ /** Items that could not be inspected, reported once each and never fatal; the reason names no path. */
27
+ unreadable: {
28
+ file: string;
29
+ reason: string;
30
+ }[];
31
+ }
32
+ /** The non-blank lines that are not JSON (a torn write), kept so `captureSession` counts them and the deposit line reports them. */
33
+ export declare const chatBadLines: (text: string) => string[];
34
+ /** The chat file as the lines `captureSession` reads; `cwd` is the project folder: the marker (`.project_root`), or for a hash-named folder a path that hashes to its name. Gemini CLI records no other working directory. */
35
+ export declare const chatLines: (text: string, fallbackId: string, cwd: string | null) => Obj[];
36
+ export declare const openGeminiStore: (root: string) => Promise<GeminiStore | undefined>;
37
+ export {};