@nyte-ai/host 0.0.0-stage → 0.0.19

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 (250) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +6 -2
  3. package/THIRD-PARTY-NOTICES.md +866 -0
  4. package/dist/chunks/canvas-preview-0cmbkp2j.js +65 -0
  5. package/dist/chunks/canvas-preview-0nq75h9k.js +7 -0
  6. package/dist/chunks/canvas-preview-11nadadc.js +241 -0
  7. package/dist/chunks/canvas-preview-1sq7z9jq.js +17 -0
  8. package/dist/chunks/canvas-preview-2jwbe14k.js +130 -0
  9. package/dist/chunks/canvas-preview-2zdyh9ny.js +26 -0
  10. package/dist/chunks/canvas-preview-31w7xm8z.js +34 -0
  11. package/dist/chunks/canvas-preview-4b6sayhg.js +295 -0
  12. package/dist/chunks/canvas-preview-4e0pxa32.js +63 -0
  13. package/dist/chunks/canvas-preview-518dh8by.js +169 -0
  14. package/dist/chunks/canvas-preview-55s0y68g.js +387 -0
  15. package/dist/chunks/canvas-preview-5ekjx6sw.js +613 -0
  16. package/dist/chunks/canvas-preview-5mex725c.js +14 -0
  17. package/dist/chunks/canvas-preview-5z63am63.js +295 -0
  18. package/dist/chunks/canvas-preview-65xqjw7f.js +20 -0
  19. package/dist/chunks/canvas-preview-69fkk9yn.js +95 -0
  20. package/dist/chunks/canvas-preview-8xc0vn7v.js +458 -0
  21. package/dist/chunks/canvas-preview-9aqczacs.js +73 -0
  22. package/dist/chunks/canvas-preview-af86jz8t.js +141 -0
  23. package/dist/chunks/canvas-preview-aq5j4p25.js +240 -0
  24. package/dist/chunks/canvas-preview-b2v8wfnz.js +36 -0
  25. package/dist/chunks/canvas-preview-befkjea2.js +60 -0
  26. package/dist/chunks/canvas-preview-bxnqt8cd.js +103 -0
  27. package/dist/chunks/canvas-preview-cawy6vbz.js +352 -0
  28. package/dist/chunks/canvas-preview-crmzxxt8.js +518 -0
  29. package/dist/chunks/canvas-preview-drctegz4.js +591 -0
  30. package/dist/chunks/canvas-preview-e3vnkkc5.js +134 -0
  31. package/dist/chunks/canvas-preview-ec2mt7es.js +108 -0
  32. package/dist/chunks/canvas-preview-fxa0rfb0.js +61 -0
  33. package/dist/chunks/canvas-preview-g5fkjs34.js +598 -0
  34. package/dist/chunks/canvas-preview-jeddjex8.js +166 -0
  35. package/dist/chunks/canvas-preview-k1yg4fgp.js +571 -0
  36. package/dist/chunks/canvas-preview-kdqgrstc.js +194 -0
  37. package/dist/chunks/canvas-preview-kn7kvbfj.js +12 -0
  38. package/dist/chunks/canvas-preview-kp75gb63.js +141 -0
  39. package/dist/chunks/canvas-preview-mgcx2b2p.js +271 -0
  40. package/dist/chunks/canvas-preview-n2a35zv5.js +81 -0
  41. package/dist/chunks/canvas-preview-pkzqg96v.js +63 -0
  42. package/dist/chunks/canvas-preview-rp4x6y1h.js +144 -0
  43. package/dist/chunks/canvas-preview-s94ebwf5.js +112 -0
  44. package/dist/chunks/canvas-preview-skzwvw4d.js +23 -0
  45. package/dist/chunks/canvas-preview-srgfpdmf.js +60 -0
  46. package/dist/chunks/canvas-preview-tjhabynd.js +252 -0
  47. package/dist/chunks/canvas-preview-tnqe7k0b.js +374 -0
  48. package/dist/chunks/canvas-preview-vaatfznm.js +189 -0
  49. package/dist/chunks/canvas-preview-vm9zdp2t.js +398 -0
  50. package/dist/chunks/canvas-preview-w54ymtb3.js +272 -0
  51. package/dist/chunks/canvas-preview-wg80rbc2.js +46 -0
  52. package/dist/chunks/canvas-preview-y5y6ghaw.js +125 -0
  53. package/dist/chunks/canvas-preview-ycepb05s.js +176 -0
  54. package/dist/chunks/canvas-preview-yjz0f7n4.js +50 -0
  55. package/dist/chunks/canvas-preview-zaaj99wd.js +244 -0
  56. package/dist/src/canvas-preview.d.ts +29 -0
  57. package/dist/src/canvas-preview.js +271 -0
  58. package/dist/src/credentials.d.ts +44 -0
  59. package/dist/src/credentials.js +10 -0
  60. package/dist/src/deploy/cloudflare/worker.d.ts +50 -0
  61. package/dist/src/deploy/cloudflare/worker.js +196 -0
  62. package/dist/src/deploy/vercel/nitro.config.d.ts +2 -0
  63. package/dist/src/deploy/vercel/nitro.config.js +30 -0
  64. package/dist/src/deploy/vercel/server/routes/[...].d.ts +2 -0
  65. package/dist/src/deploy/vercel/server/routes/[...].js +18 -0
  66. package/dist/src/deploy/vercel/server/utils/host.d.ts +13 -0
  67. package/dist/src/deploy/vercel/server/utils/host.js +7 -0
  68. package/dist/src/deploy/vercel/server/utils/repair.d.ts +1 -0
  69. package/dist/src/deploy/vercel/server/utils/repair.js +6 -0
  70. package/dist/src/deploy/vercel/server/utils/step.d.ts +10 -0
  71. package/dist/src/deploy/vercel/server/utils/step.js +6 -0
  72. package/dist/src/deploy/vercel/server/workflows/drive.d.ts +14 -0
  73. package/dist/src/deploy/vercel/server/workflows/drive.js +13 -0
  74. package/dist/src/durable-object.d.ts +14 -0
  75. package/dist/src/durable-object.js +231 -0
  76. package/dist/src/hash.d.ts +1 -0
  77. package/dist/src/hash.js +6 -0
  78. package/dist/src/identity-key.d.ts +11 -0
  79. package/dist/src/identity-key.js +9 -0
  80. package/dist/src/identity.d.ts +12 -0
  81. package/dist/src/identity.js +6 -0
  82. package/dist/src/images/exif.d.ts +1 -0
  83. package/dist/src/images/exif.js +6 -0
  84. package/dist/src/images/node.d.ts +37 -0
  85. package/dist/src/images/node.js +12 -0
  86. package/dist/src/images/photon.d.ts +3 -0
  87. package/dist/src/images/photon.js +7 -0
  88. package/dist/src/images/worker.d.ts +1 -0
  89. package/dist/src/images/worker.js +23 -0
  90. package/dist/src/index.d.ts +20 -0
  91. package/dist/src/index.js +121 -0
  92. package/dist/src/key-file.d.ts +1 -0
  93. package/dist/src/key-file.js +7 -0
  94. package/dist/src/listen-fetch.d.ts +8 -0
  95. package/dist/src/listen-fetch.js +9 -0
  96. package/dist/src/listen.d.ts +4 -0
  97. package/dist/src/listen.js +10 -0
  98. package/dist/src/local/command.d.ts +20 -0
  99. package/dist/src/local/command.js +12 -0
  100. package/dist/src/local/feed.d.ts +7 -0
  101. package/dist/src/local/feed.js +6 -0
  102. package/dist/src/local/files.d.ts +18 -0
  103. package/dist/src/local/files.js +13 -0
  104. package/dist/src/local/git-watch.d.ts +15 -0
  105. package/dist/src/local/git-watch.js +7 -0
  106. package/dist/src/local/git.d.ts +5 -0
  107. package/dist/src/local/git.js +13 -0
  108. package/dist/src/local/github.d.ts +30 -0
  109. package/dist/src/local/github.js +9 -0
  110. package/dist/src/local/identity.d.ts +3 -0
  111. package/dist/src/local/identity.js +7 -0
  112. package/dist/src/local/jobs.d.ts +7 -0
  113. package/dist/src/local/jobs.js +7 -0
  114. package/dist/src/local/legacy-trust.d.ts +10 -0
  115. package/dist/src/local/legacy-trust.js +6 -0
  116. package/dist/src/local/patch.d.ts +16 -0
  117. package/dist/src/local/patch.js +17 -0
  118. package/dist/src/local/provider.d.ts +11 -0
  119. package/dist/src/local/provider.js +20 -0
  120. package/dist/src/local/snapshots.d.ts +7 -0
  121. package/dist/src/local/snapshots.js +11 -0
  122. package/dist/src/local/text.d.ts +1 -0
  123. package/dist/src/local/text.js +6 -0
  124. package/dist/src/local/tree.d.ts +50 -0
  125. package/dist/src/local/tree.js +16 -0
  126. package/dist/src/local/workspace-migration.d.ts +2 -0
  127. package/dist/src/local/workspace-migration.js +7 -0
  128. package/dist/src/local/worktrees.d.ts +46 -0
  129. package/dist/src/local/worktrees.js +14 -0
  130. package/dist/src/mcp/config.d.ts +75 -0
  131. package/dist/src/mcp/config.js +12 -0
  132. package/dist/src/mcp/connect.d.ts +15 -0
  133. package/dist/src/mcp/connect.js +9 -0
  134. package/dist/src/mcp/hub.d.ts +19 -0
  135. package/dist/src/mcp/hub.js +11 -0
  136. package/dist/src/mcp/oauth.d.ts +46 -0
  137. package/dist/src/mcp/oauth.js +12 -0
  138. package/dist/src/mcp/tools.d.ts +29 -0
  139. package/dist/src/mcp/tools.js +12 -0
  140. package/dist/src/open.d.ts +14 -0
  141. package/dist/src/open.js +46 -0
  142. package/dist/src/plugins/loader.d.ts +21 -0
  143. package/dist/src/plugins/loader.js +11 -0
  144. package/dist/src/postgres.d.ts +19 -0
  145. package/dist/src/postgres.js +8 -0
  146. package/dist/src/providers.d.ts +16 -0
  147. package/dist/src/providers.js +112 -0
  148. package/dist/src/secrets.d.ts +12 -0
  149. package/dist/src/secrets.js +8 -0
  150. package/dist/src/serve/binding.d.ts +39 -0
  151. package/dist/src/serve/binding.js +6 -0
  152. package/dist/src/serve/handler.d.ts +15 -0
  153. package/dist/src/serve/handler.js +8 -0
  154. package/dist/src/serve/stream-server.d.ts +6 -0
  155. package/dist/src/serve/stream-server.js +6 -0
  156. package/dist/src/session-index.d.ts +11 -0
  157. package/dist/src/session-index.js +11 -0
  158. package/dist/src/shell-env.d.ts +14 -0
  159. package/dist/src/shell-env.js +108 -0
  160. package/dist/src/sqlite-workers.d.ts +6 -0
  161. package/dist/src/sqlite-workers.js +6 -0
  162. package/dist/src/sqlite.d.ts +8 -0
  163. package/dist/src/sqlite.js +11 -0
  164. package/dist/src/store-rows.d.ts +13 -0
  165. package/dist/src/store-rows.js +26 -0
  166. package/dist/src/store-usage.d.ts +25 -0
  167. package/dist/src/store-usage.js +19 -0
  168. package/dist/src/usage-history.d.ts +54 -0
  169. package/dist/src/usage-history.js +14 -0
  170. package/dist/src/usage-scan.d.ts +24 -0
  171. package/dist/src/usage-scan.js +65 -0
  172. package/dist/src/usage-service.d.ts +23 -0
  173. package/dist/src/usage-service.js +16 -0
  174. package/dist/src/usage-summary.d.ts +9 -0
  175. package/dist/src/usage-summary.js +16 -0
  176. package/dist/src/usage-types.d.ts +86 -0
  177. package/dist/src/usage-types.js +0 -0
  178. package/dist/src/usage-worker.d.ts +1 -0
  179. package/dist/src/usage-worker.js +29 -0
  180. package/dist/src/usage.d.ts +195 -0
  181. package/dist/src/usage.js +23 -0
  182. package/package.json +140 -3
  183. package/src/canvas-preview.ts +403 -0
  184. package/src/credentials.ts +294 -0
  185. package/src/deploy/cloudflare/README.md +3 -0
  186. package/src/deploy/cloudflare/worker.ts +306 -0
  187. package/src/deploy/cloudflare/wrangler.jsonc +12 -0
  188. package/src/deploy/vercel/README.md +3 -0
  189. package/src/deploy/vercel/nitro.config.ts +29 -0
  190. package/src/deploy/vercel/server/routes/[...].ts +10 -0
  191. package/src/deploy/vercel/server/utils/host.ts +104 -0
  192. package/src/deploy/vercel/server/utils/repair.ts +35 -0
  193. package/src/deploy/vercel/server/utils/step.ts +25 -0
  194. package/src/deploy/vercel/server/workflows/drive.ts +46 -0
  195. package/src/deploy/vercel/tsconfig.json +9 -0
  196. package/src/deploy/vercel/types/bun.d.ts +2 -0
  197. package/src/durable-object.ts +386 -0
  198. package/src/hash.ts +5 -0
  199. package/src/identity-key.ts +20 -0
  200. package/src/identity.ts +66 -0
  201. package/src/images/exif.ts +69 -0
  202. package/src/images/node.ts +163 -0
  203. package/src/images/photon.ts +141 -0
  204. package/src/images/worker.ts +29 -0
  205. package/src/index.ts +39 -0
  206. package/src/key-file.ts +53 -0
  207. package/src/listen-fetch.ts +409 -0
  208. package/src/listen.ts +228 -0
  209. package/src/local/command.ts +161 -0
  210. package/src/local/feed.ts +70 -0
  211. package/src/local/files.ts +817 -0
  212. package/src/local/git-watch.ts +199 -0
  213. package/src/local/git.ts +919 -0
  214. package/src/local/github.ts +691 -0
  215. package/src/local/identity.ts +21 -0
  216. package/src/local/jobs.ts +573 -0
  217. package/src/local/legacy-trust.ts +105 -0
  218. package/src/local/patch.ts +334 -0
  219. package/src/local/provider.ts +184 -0
  220. package/src/local/snapshots.ts +778 -0
  221. package/src/local/text.ts +9 -0
  222. package/src/local/tree.ts +398 -0
  223. package/src/local/workspace-migration.ts +95 -0
  224. package/src/local/worktrees.ts +239 -0
  225. package/src/mcp/config.ts +330 -0
  226. package/src/mcp/connect.ts +92 -0
  227. package/src/mcp/hub.ts +836 -0
  228. package/src/mcp/oauth.ts +436 -0
  229. package/src/mcp/tools.ts +333 -0
  230. package/src/open.ts +449 -0
  231. package/src/plugins/loader.ts +186 -0
  232. package/src/postgres.ts +492 -0
  233. package/src/providers.ts +135 -0
  234. package/src/secrets.ts +31 -0
  235. package/src/serve/binding.ts +629 -0
  236. package/src/serve/handler.ts +362 -0
  237. package/src/serve/stream-server.ts +176 -0
  238. package/src/session-index.ts +99 -0
  239. package/src/shell-env.ts +153 -0
  240. package/src/sqlite-workers.ts +283 -0
  241. package/src/sqlite.ts +553 -0
  242. package/src/store-rows.ts +110 -0
  243. package/src/store-usage.ts +347 -0
  244. package/src/usage-history.ts +219 -0
  245. package/src/usage-scan.ts +81 -0
  246. package/src/usage-service.ts +82 -0
  247. package/src/usage-summary.ts +79 -0
  248. package/src/usage-types.ts +87 -0
  249. package/src/usage-worker.ts +24 -0
  250. package/src/usage.ts +776 -0
@@ -0,0 +1,571 @@
1
+ import {
2
+ emptyModelUsage2,
3
+ recordedUsage2,
4
+ summarizeModels2
5
+ } from "./canvas-preview-srgfpdmf.js";
6
+ import {
7
+ localDay2
8
+ } from "./canvas-preview-11nadadc.js";
9
+ import {
10
+ fileScanSchema2,
11
+ UsageScanCache2,
12
+ readHistory2,
13
+ readCacheDocument2,
14
+ writeCacheDocument2
15
+ } from "./canvas-preview-kp75gb63.js";
16
+
17
+ // src/usage.ts
18
+ import { existsSync } from "node:fs";
19
+ import { lstat, opendir, stat } from "node:fs/promises";
20
+ import { homedir } from "node:os";
21
+ import { join, resolve } from "node:path";
22
+ import process from "node:process";
23
+ import { Type } from "typebox";
24
+ import { Compile } from "typebox/compile";
25
+ import { Value } from "typebox/value";
26
+ import { calculateCost } from "@nyte-ai/ai";
27
+ var tokens = Type.Integer({ minimum: 0, maximum: Number.MAX_SAFE_INTEGER });
28
+ var count = Type.Number({ minimum: 0 });
29
+ var modelUsage = Type.Object({
30
+ input: count,
31
+ output: count,
32
+ cacheRead: count,
33
+ cacheWrite: count,
34
+ cacheWrite1h: Type.Optional(count),
35
+ reasoning: Type.Optional(count),
36
+ totalTokens: count,
37
+ cost: Type.Object({
38
+ input: Type.Number(),
39
+ output: Type.Number(),
40
+ cacheRead: Type.Number(),
41
+ cacheWrite: Type.Number(),
42
+ total: Type.Number()
43
+ })
44
+ });
45
+ var recordedAt = Type.Union([Type.Number(), Type.Null()]);
46
+ var snapshot = Type.Object({
47
+ model: Type.String(),
48
+ usage: modelUsage,
49
+ costUSD: Type.Optional(Type.Number()),
50
+ at: recordedAt
51
+ });
52
+ var claudeCodeFileScan = Type.Object({
53
+ keyed: Type.Array(Type.Tuple([Type.String(), snapshot])),
54
+ anonymous: Type.Array(snapshot),
55
+ malformedRecords: Type.Integer({ minimum: 0 })
56
+ });
57
+ var envelope = Type.Object({ type: Type.String() });
58
+ var assistantRecord = Type.Object({
59
+ type: Type.Literal("assistant"),
60
+ timestamp: Type.Optional(Type.String()),
61
+ requestId: Type.Optional(Type.String()),
62
+ costUSD: Type.Optional(Type.Unknown()),
63
+ message: Type.Object({
64
+ id: Type.Optional(Type.String()),
65
+ model: Type.String({ minLength: 1, pattern: "\\S" }),
66
+ usage: Type.Object({
67
+ input_tokens: tokens,
68
+ output_tokens: tokens,
69
+ cache_read_input_tokens: Type.Optional(tokens),
70
+ cache_creation_input_tokens: Type.Optional(tokens),
71
+ cache_creation: Type.Optional(Type.Object({
72
+ ephemeral_5m_input_tokens: Type.Optional(tokens),
73
+ ephemeral_1h_input_tokens: Type.Optional(tokens)
74
+ }))
75
+ })
76
+ })
77
+ });
78
+ var reportedCost = Type.Number({ minimum: 0, maximum: Number.MAX_VALUE });
79
+ function betterSnapshot(previous, next) {
80
+ if (previous === undefined)
81
+ return true;
82
+ const usage = next.usage;
83
+ return usage.totalTokens > previous.usage.totalTokens || usage.totalTokens === previous.usage.totalTokens && (usage.output > previous.usage.output || usage.output === previous.usage.output && previous.costUSD === undefined && next.costUSD !== undefined);
84
+ }
85
+ function parseRecordedAt(value) {
86
+ if (value === undefined)
87
+ return null;
88
+ const parsed = Date.parse(value);
89
+ return Number.isNaN(parsed) ? null : parsed;
90
+ }
91
+ function recordedIn(window, at) {
92
+ if (at === null)
93
+ return window.sinceDay === null;
94
+ const day = localDay2(at);
95
+ return day <= window.untilDay && (window.sinceDay === null || day >= window.sinceDay);
96
+ }
97
+ var claudeCodeParser = (from) => {
98
+ const keyed = new Map(from?.keyed);
99
+ const anonymous = [...from?.anonymous ?? []];
100
+ let malformedRecords = from?.malformedRecords ?? 0;
101
+ const line = ({ text, terminated }) => {
102
+ if (!text.trim())
103
+ return;
104
+ let value;
105
+ try {
106
+ value = JSON.parse(text);
107
+ } catch {
108
+ if (terminated)
109
+ malformedRecords++;
110
+ return;
111
+ }
112
+ if (!Value.Check(envelope, value)) {
113
+ malformedRecords++;
114
+ return;
115
+ }
116
+ if (value.type !== "assistant")
117
+ return;
118
+ if (!Value.Check(assistantRecord, value)) {
119
+ malformedRecords++;
120
+ return;
121
+ }
122
+ const raw = value.message.usage;
123
+ const cacheWrite = raw.cache_creation_input_tokens ?? 0;
124
+ const cacheWrite1h = raw.cache_creation?.ephemeral_1h_input_tokens;
125
+ if ((cacheWrite1h ?? 0) + (raw.cache_creation?.ephemeral_5m_input_tokens ?? 0) > cacheWrite) {
126
+ malformedRecords++;
127
+ return;
128
+ }
129
+ const usage = {
130
+ ...emptyModelUsage2(),
131
+ input: raw.input_tokens,
132
+ output: raw.output_tokens,
133
+ cacheRead: raw.cache_read_input_tokens ?? 0,
134
+ cacheWrite,
135
+ totalTokens: raw.input_tokens + raw.output_tokens + (raw.cache_read_input_tokens ?? 0) + cacheWrite
136
+ };
137
+ if (cacheWrite1h !== undefined)
138
+ usage.cacheWrite1h = cacheWrite1h;
139
+ const snapshot = {
140
+ model: value.message.model,
141
+ usage,
142
+ at: parseRecordedAt(value.timestamp)
143
+ };
144
+ if (Value.Check(reportedCost, value.costUSD))
145
+ snapshot.costUSD = value.costUSD;
146
+ const messageId = value.message.id?.trim() || null;
147
+ const requestId = value.requestId?.trim() || null;
148
+ if (messageId === null && requestId === null) {
149
+ anonymous.push(snapshot);
150
+ return;
151
+ }
152
+ const identity = JSON.stringify([messageId, requestId]);
153
+ if (betterSnapshot(keyed.get(identity), snapshot))
154
+ keyed.set(identity, snapshot);
155
+ };
156
+ return { line, scan: () => ({ keyed: [...keyed], anonymous: [...anonymous], malformedRecords }) };
157
+ };
158
+ async function readHistoryInWindow(path, window, read) {
159
+ read.seen.add(path);
160
+ const info = await lstat(path);
161
+ if (!info.isFile())
162
+ throw new Error("History is not a regular file.");
163
+ const opens = window.sinceDay === null ? 0 : new Date(`${window.sinceDay}T00:00:00`).getTime();
164
+ if (info.mtimeMs < opens)
165
+ return;
166
+ return readHistory2(path, info, read.parser, read.cache, read.signal);
167
+ }
168
+ async function readClaudeCodeUsage2(options) {
169
+ options.signal?.throwIfAborted();
170
+ const projects = join(resolve(options.configDir ?? (process.env.CLAUDE_CONFIG_DIR?.trim() || join(homedir(), ".claude"))), "projects");
171
+ if (!existsSync(projects))
172
+ return { kind: "missing" };
173
+ try {
174
+ const root = await stat(projects);
175
+ options.signal?.throwIfAborted();
176
+ if (!root.isDirectory())
177
+ return { kind: "failed", message: "Claude Code history path is not a directory." };
178
+ } catch {
179
+ options.signal?.throwIfAborted();
180
+ return { kind: "failed", message: "Could not open Claude Code local history." };
181
+ }
182
+ const keyed = new Map;
183
+ const anonymous = [];
184
+ const seen = new Set;
185
+ let malformedRecords = 0;
186
+ let unreadableFiles = 0;
187
+ try {
188
+ const directories = [projects];
189
+ for (const directory of directories) {
190
+ options.signal?.throwIfAborted();
191
+ try {
192
+ if (directory !== projects && (await lstat(directory)).isSymbolicLink())
193
+ continue;
194
+ const entries = await opendir(directory);
195
+ for await (const entry of entries) {
196
+ options.signal?.throwIfAborted();
197
+ const path = join(directory, entry.name);
198
+ if (entry.isDirectory()) {
199
+ directories.push(path);
200
+ continue;
201
+ }
202
+ if (!entry.isFile() || !entry.name.endsWith(".jsonl"))
203
+ continue;
204
+ try {
205
+ const scan = await readHistoryInWindow(path, options.window, {
206
+ parser: claudeCodeParser,
207
+ cache: options.cache,
208
+ seen,
209
+ signal: options.signal
210
+ });
211
+ if (scan === undefined)
212
+ continue;
213
+ malformedRecords += scan.malformedRecords;
214
+ anonymous.push(...scan.anonymous);
215
+ for (const [identity, snapshot] of scan.keyed) {
216
+ if (betterSnapshot(keyed.get(identity), snapshot))
217
+ keyed.set(identity, snapshot);
218
+ }
219
+ } catch {
220
+ options.signal?.throwIfAborted();
221
+ unreadableFiles++;
222
+ }
223
+ }
224
+ } catch (error) {
225
+ options.signal?.throwIfAborted();
226
+ if (directory === projects)
227
+ throw error;
228
+ unreadableFiles++;
229
+ }
230
+ }
231
+ options.signal?.throwIfAborted();
232
+ options.cache?.keepOnly(seen);
233
+ const catalog = options.models.getModels("anthropic").filter((model) => model.provider === "anthropic");
234
+ const rows = [];
235
+ let unpricedRecords = 0;
236
+ for (const snapshot of [...keyed.values(), ...anonymous]) {
237
+ options.signal?.throwIfAborted();
238
+ if (!recordedIn(options.window, snapshot.at))
239
+ continue;
240
+ const usage = { ...snapshot.usage, cost: { ...snapshot.usage.cost } };
241
+ if (snapshot.costUSD !== undefined) {
242
+ usage.cost.total = snapshot.costUSD;
243
+ } else {
244
+ const matches = catalog.filter((model) => model.id === snapshot.model);
245
+ const model = matches.length === 1 ? matches[0] : undefined;
246
+ if (model)
247
+ calculateCost(model, usage);
248
+ else
249
+ unpricedRecords++;
250
+ }
251
+ rows.push({
252
+ provider: "anthropic",
253
+ model: snapshot.model,
254
+ turns: 1,
255
+ usage: recordedUsage2(usage)
256
+ });
257
+ }
258
+ options.signal?.throwIfAborted();
259
+ return {
260
+ kind: "ready",
261
+ summary: summarizeModels2(rows),
262
+ unpricedRecords,
263
+ malformedRecords,
264
+ unreadableFiles
265
+ };
266
+ } catch {
267
+ options.signal?.throwIfAborted();
268
+ return { kind: "failed", message: "Could not read Claude Code local history." };
269
+ }
270
+ }
271
+ var codexRow = Type.Object({ model: Type.String(), usage: modelUsage, at: recordedAt });
272
+ var codexCursor = Type.Object({
273
+ model: Type.String(),
274
+ sawMeta: Type.Boolean(),
275
+ signature: Type.Optional(Type.String()),
276
+ forkAnchorMs: Type.Optional(Type.Number())
277
+ });
278
+ var codexFileScan = Type.Object({
279
+ modern: Type.Array(Type.Tuple([Type.String(), codexRow])),
280
+ legacy: Type.Array(codexRow),
281
+ malformedRecords: Type.Integer({ minimum: 0 }),
282
+ cursor: codexCursor
283
+ });
284
+ var codexTokens = Type.Object({
285
+ input_tokens: Type.Optional(tokens),
286
+ cached_input_tokens: Type.Optional(tokens),
287
+ cache_write_input_tokens: Type.Optional(tokens),
288
+ output_tokens: Type.Optional(tokens),
289
+ reasoning_output_tokens: Type.Optional(tokens)
290
+ });
291
+ var usageRecord = Type.Object({
292
+ type: Type.Literal("token_usage_record"),
293
+ timestamp: Type.Optional(Type.String()),
294
+ payload: Type.Object({
295
+ response_id: Type.Optional(Type.String()),
296
+ usage: codexTokens
297
+ })
298
+ });
299
+ var turnContext = Type.Object({
300
+ type: Type.Literal("turn_context"),
301
+ payload: Type.Object({ model: Type.Optional(Type.String({ minLength: 1 })) })
302
+ });
303
+ var sessionMeta = Type.Object({
304
+ type: Type.Literal("session_meta"),
305
+ timestamp: Type.Optional(Type.String()),
306
+ payload: Type.Object({
307
+ forked_from_id: Type.Optional(Type.String()),
308
+ parent_thread_id: Type.Optional(Type.String())
309
+ })
310
+ });
311
+ var tokenCount = Type.Object({
312
+ type: Type.Literal("event_msg"),
313
+ timestamp: Type.Optional(Type.String()),
314
+ payload: Type.Object({
315
+ type: Type.Literal("token_count"),
316
+ info: Type.Object({ last_token_usage: Type.Optional(codexTokens) })
317
+ })
318
+ });
319
+ function codexUsage(raw) {
320
+ const input = raw.input_tokens ?? 0;
321
+ const cacheRead = raw.cached_input_tokens ?? 0;
322
+ const cacheWrite = raw.cache_write_input_tokens ?? 0;
323
+ const output = raw.output_tokens ?? 0;
324
+ const uncached = Math.max(0, input - cacheRead - cacheWrite);
325
+ return {
326
+ ...emptyModelUsage2(),
327
+ input: uncached,
328
+ output,
329
+ cacheRead,
330
+ cacheWrite,
331
+ reasoning: Math.min(output, raw.reasoning_output_tokens ?? 0),
332
+ totalTokens: uncached + output + cacheRead + cacheWrite
333
+ };
334
+ }
335
+ var FORK_COPY_MAX_GAP_MS = 1000;
336
+ async function readCodexUsage2(options) {
337
+ options.signal?.throwIfAborted();
338
+ const home = resolve(options.homeDir ?? (process.env.CODEX_HOME?.trim() || join(homedir(), ".codex")));
339
+ const roots = [join(home, "sessions"), join(home, "archived_sessions")];
340
+ const present = [];
341
+ for (const root of roots) {
342
+ if (!existsSync(root))
343
+ continue;
344
+ try {
345
+ if ((await stat(root)).isDirectory())
346
+ present.push(root);
347
+ } catch {
348
+ options.signal?.throwIfAborted();
349
+ return { kind: "failed", message: "Could not open Codex local history." };
350
+ }
351
+ }
352
+ if (present.length === 0)
353
+ return { kind: "missing" };
354
+ const responses = new Map;
355
+ const legacy = [];
356
+ const seen = new Set;
357
+ let malformedRecords = 0;
358
+ let unreadableFiles = 0;
359
+ try {
360
+ for (const root of present) {
361
+ for await (const path of jsonlFiles(root, options.signal)) {
362
+ try {
363
+ const scan = await readHistoryInWindow(path, options.window, {
364
+ parser: codexParser,
365
+ cache: options.cache,
366
+ seen,
367
+ signal: options.signal
368
+ });
369
+ if (scan === undefined)
370
+ continue;
371
+ malformedRecords += scan.malformedRecords;
372
+ if (scan.modern.length > 0) {
373
+ for (const [id, row] of scan.modern)
374
+ if (!responses.has(id))
375
+ responses.set(id, row);
376
+ } else {
377
+ legacy.push(...scan.legacy);
378
+ }
379
+ } catch {
380
+ options.signal?.throwIfAborted();
381
+ unreadableFiles++;
382
+ }
383
+ }
384
+ }
385
+ options.signal?.throwIfAborted();
386
+ options.cache?.keepOnly(seen);
387
+ const catalog = options.models.getModels("openai-codex").filter((model) => model.provider === "openai-codex");
388
+ const rows = [];
389
+ let unpricedRecords = 0;
390
+ for (const row of [...responses.values(), ...legacy]) {
391
+ options.signal?.throwIfAborted();
392
+ if (!recordedIn(options.window, row.at))
393
+ continue;
394
+ const usage = { ...row.usage, cost: { ...row.usage.cost } };
395
+ const matches = catalog.filter((model) => model.id === row.model);
396
+ const model = matches.length === 1 ? matches[0] : undefined;
397
+ if (model)
398
+ calculateCost(model, usage);
399
+ else
400
+ unpricedRecords++;
401
+ rows.push({
402
+ provider: "openai-codex",
403
+ model: row.model,
404
+ turns: 1,
405
+ usage: recordedUsage2(usage)
406
+ });
407
+ }
408
+ return {
409
+ kind: "ready",
410
+ summary: summarizeModels2(rows),
411
+ unpricedRecords,
412
+ malformedRecords,
413
+ unreadableFiles
414
+ };
415
+ } catch {
416
+ options.signal?.throwIfAborted();
417
+ return { kind: "failed", message: "Could not read Codex local history." };
418
+ }
419
+ }
420
+ var codexParser = (from) => {
421
+ const modern = new Map(from?.modern);
422
+ const legacy = [...from?.legacy ?? []];
423
+ let malformedRecords = from?.malformedRecords ?? 0;
424
+ const cursor = { ...from?.cursor ?? { model: "", sawMeta: false } };
425
+ const line = ({ text, terminated }) => {
426
+ if (!text.trim())
427
+ return;
428
+ let value;
429
+ try {
430
+ value = JSON.parse(text);
431
+ } catch {
432
+ if (terminated)
433
+ malformedRecords++;
434
+ return;
435
+ }
436
+ if (!Value.Check(envelope, value)) {
437
+ malformedRecords++;
438
+ return;
439
+ }
440
+ if (Value.Check(turnContext, value)) {
441
+ if (value.payload.model !== undefined)
442
+ cursor.model = value.payload.model;
443
+ return;
444
+ }
445
+ if (Value.Check(sessionMeta, value)) {
446
+ if (cursor.sawMeta)
447
+ return;
448
+ cursor.sawMeta = true;
449
+ const forked = value.payload.forked_from_id !== undefined || value.payload.parent_thread_id !== undefined;
450
+ const anchor = parseRecordedAt(value.timestamp);
451
+ if (forked && anchor !== null)
452
+ cursor.forkAnchorMs = anchor;
453
+ return;
454
+ }
455
+ if (Value.Check(usageRecord, value)) {
456
+ const id = value.payload.response_id;
457
+ if (id === undefined || cursor.model === "")
458
+ return;
459
+ const usage = codexUsage(value.payload.usage);
460
+ if (usage.totalTokens > 0 && !modern.has(id))
461
+ modern.set(id, { model: cursor.model, usage, at: parseRecordedAt(value.timestamp) });
462
+ return;
463
+ }
464
+ if (!Value.Check(tokenCount, value))
465
+ return;
466
+ const last = value.payload.info.last_token_usage;
467
+ if (last === undefined || cursor.model === "")
468
+ return;
469
+ const next = JSON.stringify(last);
470
+ if (next === cursor.signature)
471
+ return;
472
+ cursor.signature = next;
473
+ const at = parseRecordedAt(value.timestamp);
474
+ if (cursor.forkAnchorMs !== undefined) {
475
+ if (at !== null && at - cursor.forkAnchorMs < FORK_COPY_MAX_GAP_MS) {
476
+ cursor.forkAnchorMs = at;
477
+ return;
478
+ }
479
+ delete cursor.forkAnchorMs;
480
+ }
481
+ const usage = codexUsage(last);
482
+ if (usage.totalTokens > 0)
483
+ legacy.push({ model: cursor.model, usage, at });
484
+ };
485
+ return {
486
+ line,
487
+ scan: () => ({
488
+ modern: [...modern],
489
+ legacy: [...legacy],
490
+ malformedRecords,
491
+ cursor: { ...cursor }
492
+ })
493
+ };
494
+ };
495
+ async function* jsonlFiles(root, signal) {
496
+ const directories = [root];
497
+ for (const directory of directories) {
498
+ signal?.throwIfAborted();
499
+ try {
500
+ if (directory !== root && (await lstat(directory)).isSymbolicLink())
501
+ continue;
502
+ for await (const entry of await opendir(directory)) {
503
+ signal?.throwIfAborted();
504
+ const path = join(directory, entry.name);
505
+ if (entry.isDirectory())
506
+ directories.push(path);
507
+ else if (entry.isFile() && entry.name.endsWith(".jsonl"))
508
+ yield path;
509
+ }
510
+ } catch (error) {
511
+ if (directory === root)
512
+ throw error;
513
+ }
514
+ }
515
+ }
516
+ function createUsageScanCaches2() {
517
+ return { claudeCode: new UsageScanCache2, codex: new UsageScanCache2 };
518
+ }
519
+ var USAGE_SCAN_CACHE_VERSION = 1;
520
+ var usageScanCacheDocument = Type.Object({
521
+ version: Type.Literal(USAGE_SCAN_CACHE_VERSION),
522
+ claudeCode: Type.Array(Type.Tuple([Type.String(), fileScanSchema2(claudeCodeFileScan)])),
523
+ codex: Type.Array(Type.Tuple([Type.String(), fileScanSchema2(codexFileScan)]))
524
+ });
525
+ var usageScanCacheValidator = Compile(usageScanCacheDocument);
526
+ async function loadUsageScanCaches2(path) {
527
+ const document = await readCacheDocument2(path, usageScanCacheValidator);
528
+ if (document === undefined)
529
+ return createUsageScanCaches2();
530
+ return {
531
+ claudeCode: new UsageScanCache2(document.claudeCode),
532
+ codex: new UsageScanCache2(document.codex)
533
+ };
534
+ }
535
+ async function saveUsageScanCaches2(path, caches) {
536
+ if (!caches.claudeCode.changed && !caches.codex.changed)
537
+ return;
538
+ const saved = await writeCacheDocument2(path, {
539
+ version: USAGE_SCAN_CACHE_VERSION,
540
+ claudeCode: [...caches.claudeCode.entries()],
541
+ codex: [...caches.codex.entries()]
542
+ });
543
+ if (!saved)
544
+ return;
545
+ caches.claudeCode.markSaved();
546
+ caches.codex.markSaved();
547
+ }
548
+ async function readLocalUsage2(options) {
549
+ const failed = (message) => {
550
+ options.signal?.throwIfAborted();
551
+ return { kind: "failed", message };
552
+ };
553
+ const [claudeCode, codex] = await Promise.all([
554
+ readClaudeCodeUsage2({
555
+ models: options.models,
556
+ window: options.window,
557
+ signal: options.signal,
558
+ cache: options.caches?.claudeCode
559
+ }).catch(() => failed("Could not read Claude Code history.")),
560
+ readCodexUsage2({
561
+ models: options.models,
562
+ window: options.window,
563
+ signal: options.signal,
564
+ cache: options.caches?.codex
565
+ }).catch(() => failed("Could not read Codex history."))
566
+ ]);
567
+ options.signal?.throwIfAborted();
568
+ return { claudeCode, codex };
569
+ }
570
+
571
+ export { readClaudeCodeUsage2, readCodexUsage2, createUsageScanCaches2, loadUsageScanCaches2, saveUsageScanCaches2, readLocalUsage2 };