@a5c-ai/adapters-codecs 5.1.1-staging.0ad6ac75ae4a

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/LICENSE +21 -0
  2. package/README.md +28 -0
  3. package/dist/adapter-install.d.ts +20 -0
  4. package/dist/adapter-install.d.ts.map +1 -0
  5. package/dist/adapter-install.js +134 -0
  6. package/dist/adapter-install.js.map +1 -0
  7. package/dist/adapters-remote-adapter.d.ts +66 -0
  8. package/dist/adapters-remote-adapter.d.ts.map +1 -0
  9. package/dist/adapters-remote-adapter.js +292 -0
  10. package/dist/adapters-remote-adapter.js.map +1 -0
  11. package/dist/amp-adapter.d.ts +32 -0
  12. package/dist/amp-adapter.d.ts.map +1 -0
  13. package/dist/amp-adapter.js +417 -0
  14. package/dist/amp-adapter.js.map +1 -0
  15. package/dist/auth-config.d.ts +44 -0
  16. package/dist/auth-config.d.ts.map +1 -0
  17. package/dist/auth-config.js +167 -0
  18. package/dist/auth-config.js.map +1 -0
  19. package/dist/babysitter-adapter.d.ts +29 -0
  20. package/dist/babysitter-adapter.d.ts.map +1 -0
  21. package/dist/babysitter-adapter.js +335 -0
  22. package/dist/babysitter-adapter.js.map +1 -0
  23. package/dist/base-adapter-helpers.d.ts +7 -0
  24. package/dist/base-adapter-helpers.d.ts.map +1 -0
  25. package/dist/base-adapter-helpers.js +68 -0
  26. package/dist/base-adapter-helpers.js.map +1 -0
  27. package/dist/base-adapter.d.ts +157 -0
  28. package/dist/base-adapter.d.ts.map +1 -0
  29. package/dist/base-adapter.js +552 -0
  30. package/dist/base-adapter.js.map +1 -0
  31. package/dist/claude-adapter.d.ts +63 -0
  32. package/dist/claude-adapter.d.ts.map +1 -0
  33. package/dist/claude-adapter.js +546 -0
  34. package/dist/claude-adapter.js.map +1 -0
  35. package/dist/claude-agent-sdk-adapter.d.ts +40 -0
  36. package/dist/claude-agent-sdk-adapter.d.ts.map +1 -0
  37. package/dist/claude-agent-sdk-adapter.js +843 -0
  38. package/dist/claude-agent-sdk-adapter.js.map +1 -0
  39. package/dist/claude-code/runtime-hooks/ephemeral-config.d.ts +11 -0
  40. package/dist/claude-code/runtime-hooks/ephemeral-config.d.ts.map +1 -0
  41. package/dist/claude-code/runtime-hooks/ephemeral-config.js +153 -0
  42. package/dist/claude-code/runtime-hooks/ephemeral-config.js.map +1 -0
  43. package/dist/claude-code/runtime-hooks/hook-socket-server.d.ts +9 -0
  44. package/dist/claude-code/runtime-hooks/hook-socket-server.d.ts.map +1 -0
  45. package/dist/claude-code/runtime-hooks/hook-socket-server.js +89 -0
  46. package/dist/claude-code/runtime-hooks/hook-socket-server.js.map +1 -0
  47. package/dist/claude-code/runtime-hooks/lifecycle.d.ts +2 -0
  48. package/dist/claude-code/runtime-hooks/lifecycle.d.ts.map +1 -0
  49. package/dist/claude-code/runtime-hooks/lifecycle.js +24 -0
  50. package/dist/claude-code/runtime-hooks/lifecycle.js.map +1 -0
  51. package/dist/claude-remote-control-adapter.d.ts +43 -0
  52. package/dist/claude-remote-control-adapter.d.ts.map +1 -0
  53. package/dist/claude-remote-control-adapter.js +509 -0
  54. package/dist/claude-remote-control-adapter.js.map +1 -0
  55. package/dist/codex-adapter.d.ts +26 -0
  56. package/dist/codex-adapter.d.ts.map +1 -0
  57. package/dist/codex-adapter.js +336 -0
  58. package/dist/codex-adapter.js.map +1 -0
  59. package/dist/codex-sdk-adapter.d.ts +32 -0
  60. package/dist/codex-sdk-adapter.d.ts.map +1 -0
  61. package/dist/codex-sdk-adapter.js +392 -0
  62. package/dist/codex-sdk-adapter.js.map +1 -0
  63. package/dist/codex-sdk-mocks.d.ts +50 -0
  64. package/dist/codex-sdk-mocks.d.ts.map +1 -0
  65. package/dist/codex-sdk-mocks.js +97 -0
  66. package/dist/codex-sdk-mocks.js.map +1 -0
  67. package/dist/codex-websocket-adapter.d.ts +34 -0
  68. package/dist/codex-websocket-adapter.d.ts.map +1 -0
  69. package/dist/codex-websocket-adapter.js +402 -0
  70. package/dist/codex-websocket-adapter.js.map +1 -0
  71. package/dist/codex-websocket-connection.d.ts +77 -0
  72. package/dist/codex-websocket-connection.d.ts.map +1 -0
  73. package/dist/codex-websocket-connection.js +733 -0
  74. package/dist/codex-websocket-connection.js.map +1 -0
  75. package/dist/copilot-adapter.d.ts +27 -0
  76. package/dist/copilot-adapter.d.ts.map +1 -0
  77. package/dist/copilot-adapter.js +224 -0
  78. package/dist/copilot-adapter.js.map +1 -0
  79. package/dist/cursor-adapter.d.ts +32 -0
  80. package/dist/cursor-adapter.d.ts.map +1 -0
  81. package/dist/cursor-adapter.js +239 -0
  82. package/dist/cursor-adapter.js.map +1 -0
  83. package/dist/droid-adapter.d.ts +32 -0
  84. package/dist/droid-adapter.d.ts.map +1 -0
  85. package/dist/droid-adapter.js +383 -0
  86. package/dist/droid-adapter.js.map +1 -0
  87. package/dist/gemini-adapter.d.ts +38 -0
  88. package/dist/gemini-adapter.d.ts.map +1 -0
  89. package/dist/gemini-adapter.js +270 -0
  90. package/dist/gemini-adapter.js.map +1 -0
  91. package/dist/hermes-adapter.d.ts +33 -0
  92. package/dist/hermes-adapter.d.ts.map +1 -0
  93. package/dist/hermes-adapter.js +269 -0
  94. package/dist/hermes-adapter.js.map +1 -0
  95. package/dist/index.d.ts +32 -0
  96. package/dist/index.d.ts.map +1 -0
  97. package/dist/index.js +33 -0
  98. package/dist/index.js.map +1 -0
  99. package/dist/mcp-plugins.d.ts +14 -0
  100. package/dist/mcp-plugins.d.ts.map +1 -0
  101. package/dist/mcp-plugins.js +97 -0
  102. package/dist/mcp-plugins.js.map +1 -0
  103. package/dist/omp-adapter.d.ts +26 -0
  104. package/dist/omp-adapter.d.ts.map +1 -0
  105. package/dist/omp-adapter.js +203 -0
  106. package/dist/omp-adapter.js.map +1 -0
  107. package/dist/openclaw-adapter.d.ts +32 -0
  108. package/dist/openclaw-adapter.d.ts.map +1 -0
  109. package/dist/openclaw-adapter.js +220 -0
  110. package/dist/openclaw-adapter.js.map +1 -0
  111. package/dist/opencode-adapter.d.ts +32 -0
  112. package/dist/opencode-adapter.d.ts.map +1 -0
  113. package/dist/opencode-adapter.js +315 -0
  114. package/dist/opencode-adapter.js.map +1 -0
  115. package/dist/opencode-http-adapter.d.ts +43 -0
  116. package/dist/opencode-http-adapter.d.ts.map +1 -0
  117. package/dist/opencode-http-adapter.js +378 -0
  118. package/dist/opencode-http-adapter.js.map +1 -0
  119. package/dist/opencode-http-connection.d.ts +32 -0
  120. package/dist/opencode-http-connection.d.ts.map +1 -0
  121. package/dist/opencode-http-connection.js +198 -0
  122. package/dist/opencode-http-connection.js.map +1 -0
  123. package/dist/pi-adapter.d.ts +26 -0
  124. package/dist/pi-adapter.d.ts.map +1 -0
  125. package/dist/pi-adapter.js +204 -0
  126. package/dist/pi-adapter.js.map +1 -0
  127. package/dist/pi-sdk-adapter.d.ts +46 -0
  128. package/dist/pi-sdk-adapter.d.ts.map +1 -0
  129. package/dist/pi-sdk-adapter.js +557 -0
  130. package/dist/pi-sdk-adapter.js.map +1 -0
  131. package/dist/programmatic-adapter-base.d.ts +87 -0
  132. package/dist/programmatic-adapter-base.d.ts.map +1 -0
  133. package/dist/programmatic-adapter-base.js +169 -0
  134. package/dist/programmatic-adapter-base.js.map +1 -0
  135. package/dist/provider-translation.d.ts +9 -0
  136. package/dist/provider-translation.d.ts.map +1 -0
  137. package/dist/provider-translation.js +2 -0
  138. package/dist/provider-translation.js.map +1 -0
  139. package/dist/qwen-adapter.d.ts +38 -0
  140. package/dist/qwen-adapter.d.ts.map +1 -0
  141. package/dist/qwen-adapter.js +269 -0
  142. package/dist/qwen-adapter.js.map +1 -0
  143. package/dist/remote-adapter-base.d.ts +84 -0
  144. package/dist/remote-adapter-base.d.ts.map +1 -0
  145. package/dist/remote-adapter-base.js +100 -0
  146. package/dist/remote-adapter-base.js.map +1 -0
  147. package/dist/session-fs.d.ts +89 -0
  148. package/dist/session-fs.d.ts.map +1 -0
  149. package/dist/session-fs.js +722 -0
  150. package/dist/session-fs.js.map +1 -0
  151. package/dist/shared/runtime-hooks-virtual.d.ts +2 -0
  152. package/dist/shared/runtime-hooks-virtual.d.ts.map +1 -0
  153. package/dist/shared/runtime-hooks-virtual.js +13 -0
  154. package/dist/shared/runtime-hooks-virtual.js.map +1 -0
  155. package/dist/translate-for-harness.d.ts +8 -0
  156. package/dist/translate-for-harness.d.ts.map +1 -0
  157. package/dist/translate-for-harness.js +89 -0
  158. package/dist/translate-for-harness.js.map +1 -0
  159. package/dist/translations/claude-translation.d.ts +3 -0
  160. package/dist/translations/claude-translation.d.ts.map +1 -0
  161. package/dist/translations/claude-translation.js +53 -0
  162. package/dist/translations/claude-translation.js.map +1 -0
  163. package/dist/translations/codex-translation.d.ts +3 -0
  164. package/dist/translations/codex-translation.d.ts.map +1 -0
  165. package/dist/translations/codex-translation.js +54 -0
  166. package/dist/translations/codex-translation.js.map +1 -0
  167. package/dist/translations/gemini-translation.d.ts +3 -0
  168. package/dist/translations/gemini-translation.d.ts.map +1 -0
  169. package/dist/translations/gemini-translation.js +45 -0
  170. package/dist/translations/gemini-translation.js.map +1 -0
  171. package/dist/translations/generic-openai-translation.d.ts +3 -0
  172. package/dist/translations/generic-openai-translation.d.ts.map +1 -0
  173. package/dist/translations/generic-openai-translation.js +47 -0
  174. package/dist/translations/generic-openai-translation.js.map +1 -0
  175. package/dist/translations/opencode-translation.d.ts +3 -0
  176. package/dist/translations/opencode-translation.d.ts.map +1 -0
  177. package/dist/translations/opencode-translation.js +48 -0
  178. package/dist/translations/opencode-translation.js.map +1 -0
  179. package/dist/translations/pi-translation.d.ts +3 -0
  180. package/dist/translations/pi-translation.d.ts.map +1 -0
  181. package/dist/translations/pi-translation.js +43 -0
  182. package/dist/translations/pi-translation.js.map +1 -0
  183. package/package.json +68 -0
@@ -0,0 +1,722 @@
1
+ /**
2
+ * Shared filesystem helpers for adapter session and config I/O.
3
+ *
4
+ * Kept intentionally dependency-free — only uses `node:fs/promises`
5
+ * and `node:path` with forward-slash-safe joins.
6
+ */
7
+ import * as fs from 'node:fs/promises';
8
+ import * as path from 'node:path';
9
+ import * as os from 'node:os';
10
+ import { writeFileAtomic, writeJsonAtomic } from '@a5c-ai/comm-adapter';
11
+ /**
12
+ * Recursively list all files matching `predicate` under `dir`.
13
+ * Returns absolute paths with forward slashes.
14
+ * If `dir` does not exist, returns an empty array.
15
+ */
16
+ import * as syncFs from 'node:fs';
17
+ export function findProjectRootSync(startDir = process.cwd()) {
18
+ let current = path.resolve(startDir);
19
+ while (true) {
20
+ if (syncFs.existsSync(path.join(current, '.git')) ||
21
+ syncFs.existsSync(path.join(current, '.a5c')) ||
22
+ syncFs.existsSync(path.join(current, '.claude.json')) ||
23
+ syncFs.existsSync(path.join(current, '.claude'))) {
24
+ return current;
25
+ }
26
+ const parent = path.dirname(current);
27
+ if (parent === current)
28
+ return startDir;
29
+ current = parent;
30
+ }
31
+ }
32
+ export async function listFilesRecursive(dir, predicate) {
33
+ const out = [];
34
+ async function walk(current) {
35
+ let entries;
36
+ try {
37
+ entries = await fs.readdir(current, { withFileTypes: true });
38
+ }
39
+ catch {
40
+ return;
41
+ }
42
+ for (const entry of entries) {
43
+ const full = path.join(current, entry.name);
44
+ if (entry.isDirectory()) {
45
+ await walk(full);
46
+ }
47
+ else if (entry.isFile() && predicate(entry.name, full)) {
48
+ out.push(full.split(path.sep).join('/'));
49
+ }
50
+ }
51
+ }
52
+ await walk(dir);
53
+ return out;
54
+ }
55
+ /** List *.jsonl files recursively under `dir`. */
56
+ export async function listJsonlFiles(dir) {
57
+ return listFilesRecursive(dir, (name) => name.toLowerCase().endsWith('.jsonl'));
58
+ }
59
+ /** List *.json files recursively under `dir`. */
60
+ export async function listJsonFiles(dir) {
61
+ return listFilesRecursive(dir, (name) => name.toLowerCase().endsWith('.json'));
62
+ }
63
+ /**
64
+ * Parse a JSONL file into an array of record objects (ignores blank lines
65
+ * and lines that fail to parse). Returns empty array if file missing.
66
+ */
67
+ export async function parseJsonlFile(filePath) {
68
+ let raw;
69
+ try {
70
+ raw = await fs.readFile(filePath, 'utf8');
71
+ }
72
+ catch {
73
+ return [];
74
+ }
75
+ const rows = [];
76
+ for (const line of raw.split(/\r?\n/)) {
77
+ const trimmed = line.trim();
78
+ if (!trimmed)
79
+ continue;
80
+ try {
81
+ const parsed = JSON.parse(trimmed);
82
+ if (parsed && typeof parsed === 'object') {
83
+ rows.push(parsed);
84
+ }
85
+ }
86
+ catch {
87
+ // skip malformed line
88
+ }
89
+ }
90
+ return rows;
91
+ }
92
+ /** Read + parse a JSON file. Returns null if missing or invalid. */
93
+ export async function readJsonFile(filePath) {
94
+ try {
95
+ const raw = await fs.readFile(filePath, 'utf8');
96
+ return JSON.parse(raw);
97
+ }
98
+ catch {
99
+ return null;
100
+ }
101
+ }
102
+ /**
103
+ * Atomically write JSON via the unified core helper (tmp + fsync + rename
104
+ * with advisory lockfile). Creates parent directories as needed.
105
+ */
106
+ export async function writeJsonFileAtomic(filePath, data) {
107
+ await writeJsonAtomic(filePath, data);
108
+ }
109
+ /**
110
+ * Minimal flat-YAML parser for simple `key: value` files.
111
+ * Supports:
112
+ * - comments (# ...)
113
+ * - scalar values (strings, numbers, booleans, null)
114
+ * - quoted strings ("..." or '...')
115
+ * - simple nested blocks via two-space indentation (one level deep)
116
+ * Does NOT support lists, anchors, multi-line strings.
117
+ */
118
+ export function parseFlatYaml(text) {
119
+ const out = {};
120
+ let currentParent = null;
121
+ let currentParentIndent = -1;
122
+ for (const rawLine of text.split(/\r?\n/)) {
123
+ const line = rawLine.replace(/\s+#.*$/, '').replace(/^#.*$/, '');
124
+ if (!line.trim())
125
+ continue;
126
+ const indentMatch = /^(\s*)/.exec(line);
127
+ const indent = indentMatch ? indentMatch[1].length : 0;
128
+ const content = line.slice(indent);
129
+ const colonIdx = content.indexOf(':');
130
+ if (colonIdx === -1)
131
+ continue;
132
+ const key = content.slice(0, colonIdx).trim();
133
+ const valueRaw = content.slice(colonIdx + 1).trim();
134
+ const target = indent > currentParentIndent && currentParent ? currentParent : out;
135
+ if (valueRaw === '') {
136
+ // Start of a nested block
137
+ const child = {};
138
+ out[key] = child;
139
+ currentParent = child;
140
+ currentParentIndent = indent;
141
+ }
142
+ else {
143
+ target[key] = coerceYamlScalar(valueRaw);
144
+ if (target === out) {
145
+ currentParent = null;
146
+ currentParentIndent = -1;
147
+ }
148
+ }
149
+ }
150
+ return out;
151
+ }
152
+ function coerceYamlScalar(s) {
153
+ if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) {
154
+ return s.slice(1, -1);
155
+ }
156
+ if (s === 'true')
157
+ return true;
158
+ if (s === 'false')
159
+ return false;
160
+ if (s === 'null' || s === '~')
161
+ return null;
162
+ if (/^-?\d+$/.test(s))
163
+ return Number(s);
164
+ if (/^-?\d+\.\d+$/.test(s))
165
+ return Number(s);
166
+ return s;
167
+ }
168
+ /** Serialize a flat object to simple YAML (top-level + one level of nesting). */
169
+ export function stringifyFlatYaml(obj) {
170
+ const lines = [];
171
+ for (const [key, value] of Object.entries(obj)) {
172
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
173
+ lines.push(`${key}:`);
174
+ for (const [k, v] of Object.entries(value)) {
175
+ lines.push(` ${k}: ${formatYamlScalar(v)}`);
176
+ }
177
+ }
178
+ else {
179
+ lines.push(`${key}: ${formatYamlScalar(value)}`);
180
+ }
181
+ }
182
+ return lines.join('\n') + '\n';
183
+ }
184
+ function formatYamlScalar(v) {
185
+ if (v === null || v === undefined)
186
+ return 'null';
187
+ if (typeof v === 'string') {
188
+ if (/[:#\n]/.test(v) || v === '' || /^\s|\s$/.test(v)) {
189
+ return JSON.stringify(v);
190
+ }
191
+ return v;
192
+ }
193
+ if (typeof v === 'boolean' || typeof v === 'number')
194
+ return String(v);
195
+ return JSON.stringify(v);
196
+ }
197
+ /** Atomically write arbitrary text via the unified core helper. */
198
+ export async function writeTextFileAtomic(filePath, text) {
199
+ await writeFileAtomic(filePath, text);
200
+ }
201
+ /** fs.stat safely: returns null on ENOENT. */
202
+ export async function statSafe(filePath) {
203
+ try {
204
+ const st = await fs.stat(filePath);
205
+ return { mtimeMs: st.mtimeMs, birthtimeMs: st.birthtimeMs, size: st.size };
206
+ }
207
+ catch {
208
+ return null;
209
+ }
210
+ }
211
+ /**
212
+ * Normalize a path to forward slashes (Windows-safe, cross-platform).
213
+ */
214
+ export function toPosix(p) {
215
+ return p.split(path.sep).join('/');
216
+ }
217
+ /**
218
+ * Home-directory-relative join with forward slashes.
219
+ */
220
+ export function homeJoin(...segments) {
221
+ return toPosix(path.join(os.homedir(), ...segments));
222
+ }
223
+ /**
224
+ * Shared `parseSessionFile` logic: read JSONL, derive createdAt from
225
+ * file stat birthtime, updatedAt from mtime, and build SessionMessage[]
226
+ * from rows via `rowToMessage` heuristics.
227
+ * The caller supplies the agent name.
228
+ */
229
+ export async function parseJsonlSessionFile(filePath, agent) {
230
+ const sessionId = path.basename(filePath, path.extname(filePath));
231
+ const rows = await parseJsonlFile(filePath);
232
+ const messages = [];
233
+ const toolCallsById = new Map();
234
+ for (const row of rows) {
235
+ const parsedMessages = rowToMessages(row, toolCallsById);
236
+ if (parsedMessages.length > 0) {
237
+ messages.push(...parsedMessages);
238
+ }
239
+ }
240
+ const stat = await statSafe(filePath);
241
+ const now = new Date().toISOString();
242
+ const createdAt = stat ? new Date(stat.birthtimeMs || stat.mtimeMs).toISOString() : now;
243
+ const updatedAt = stat ? new Date(stat.mtimeMs).toISOString() : now;
244
+ // A "turn" = user message; fallback to assistant count when no users.
245
+ const userTurns = messages.filter((m) => m.role === 'user').length;
246
+ const assistantTurns = messages.filter((m) => m.role === 'assistant').length;
247
+ const turnCount = userTurns || assistantTurns;
248
+ return { sessionId, agent, turnCount, createdAt, updatedAt, messages, raw: rows };
249
+ }
250
+ export async function parseCodexSessionFile(filePath, agent) {
251
+ const rows = await parseJsonlFile(filePath);
252
+ const stat = await statSafe(filePath);
253
+ const now = new Date().toISOString();
254
+ const createdAt = stat ? new Date(stat.birthtimeMs || stat.mtimeMs).toISOString() : now;
255
+ const updatedAt = stat ? new Date(stat.mtimeMs).toISOString() : now;
256
+ let sessionId = path.basename(filePath, path.extname(filePath));
257
+ let cwd;
258
+ let model;
259
+ let title;
260
+ let sessionCost;
261
+ const messages = [];
262
+ const toolCalls = new Map();
263
+ for (const row of rows) {
264
+ const rowType = typeof row['type'] === 'string' ? row['type'] : '';
265
+ if (rowType === 'session_meta') {
266
+ const payload = row['payload'];
267
+ if (payload && typeof payload === 'object') {
268
+ const meta = payload;
269
+ if (typeof meta['cwd'] === 'string' && meta['cwd'].length > 0) {
270
+ cwd = String(meta['cwd']);
271
+ }
272
+ }
273
+ continue;
274
+ }
275
+ if (rowType === 'turn_context') {
276
+ const payload = row['payload'];
277
+ if (payload && typeof payload === 'object') {
278
+ const turnContext = payload;
279
+ if (typeof turnContext['model'] === 'string' && turnContext['model'].length > 0) {
280
+ model = String(turnContext['model']);
281
+ }
282
+ }
283
+ continue;
284
+ }
285
+ if (rowType === 'event_msg') {
286
+ const payload = row['payload'];
287
+ if (!payload || typeof payload !== 'object') {
288
+ continue;
289
+ }
290
+ const event = payload;
291
+ if (event['type'] !== 'token_count') {
292
+ continue;
293
+ }
294
+ const estimatedCost = estimateCodexSessionCost(event, model);
295
+ if (estimatedCost) {
296
+ sessionCost = estimatedCost;
297
+ }
298
+ continue;
299
+ }
300
+ if (rowType !== 'response_item') {
301
+ continue;
302
+ }
303
+ const payload = row['payload'];
304
+ if (!payload || typeof payload !== 'object') {
305
+ continue;
306
+ }
307
+ const item = payload;
308
+ const itemType = typeof item['type'] === 'string' ? item['type'] : '';
309
+ if (itemType === 'message') {
310
+ const roleRaw = typeof item['role'] === 'string' ? item['role'] : '';
311
+ if (roleRaw !== 'user' && roleRaw !== 'assistant') {
312
+ continue;
313
+ }
314
+ const text = flattenCodexMessageText(item['content']);
315
+ if (shouldSkipCodexBootstrapMessage(roleRaw, text)) {
316
+ continue;
317
+ }
318
+ if (roleRaw === 'user' && !title && text.length > 0) {
319
+ title = text.length > 80 ? `${text.slice(0, 77)}...` : text;
320
+ }
321
+ messages.push({
322
+ role: roleRaw,
323
+ content: text,
324
+ });
325
+ continue;
326
+ }
327
+ if (itemType === 'function_call') {
328
+ const toolCallId = String(item['call_id'] ?? item['id'] ?? '');
329
+ const toolName = String(item['name'] ?? 'tool');
330
+ const input = parseMaybeJson(item['arguments']);
331
+ const toolCall = {
332
+ toolCallId,
333
+ toolName,
334
+ input,
335
+ };
336
+ toolCalls.set(toolCallId, toolCall);
337
+ messages.push({
338
+ role: 'assistant',
339
+ content: '',
340
+ toolCalls: [toolCall],
341
+ });
342
+ continue;
343
+ }
344
+ if (itemType === 'function_call_output') {
345
+ const toolCallId = String(item['call_id'] ?? item['id'] ?? '');
346
+ const knownToolCall = toolCalls.get(toolCallId);
347
+ const toolName = knownToolCall?.toolName ?? String(item['name'] ?? 'tool');
348
+ const output = item['output'] ?? '';
349
+ messages.push({
350
+ role: 'tool',
351
+ content: typeof output === 'string' ? output : renderStructuredValue(output),
352
+ toolResult: {
353
+ toolCallId,
354
+ toolName,
355
+ output,
356
+ },
357
+ });
358
+ }
359
+ }
360
+ const userTurns = messages.filter((message) => message.role === 'user').length;
361
+ const assistantTurns = messages.filter((message) => message.role === 'assistant').length;
362
+ const turnCount = userTurns || assistantTurns;
363
+ return {
364
+ sessionId,
365
+ agent,
366
+ turnCount,
367
+ createdAt,
368
+ updatedAt,
369
+ title,
370
+ model,
371
+ cost: sessionCost,
372
+ cwd,
373
+ messages,
374
+ raw: rows,
375
+ };
376
+ }
377
+ const CODEX_SESSION_PRICING = {
378
+ 'gpt-5.4': {
379
+ inputPricePerMillion: 2.5,
380
+ cachedInputPricePerMillion: 0.25,
381
+ outputPricePerMillion: 15,
382
+ },
383
+ 'gpt-5.3-codex': {
384
+ inputPricePerMillion: 1.75,
385
+ cachedInputPricePerMillion: 0.175,
386
+ outputPricePerMillion: 14,
387
+ },
388
+ 'gpt-5-codex': {
389
+ inputPricePerMillion: 1.25,
390
+ cachedInputPricePerMillion: 0.125,
391
+ outputPricePerMillion: 10,
392
+ },
393
+ 'gpt-5.1-codex-mini': {
394
+ inputPricePerMillion: 0.25,
395
+ cachedInputPricePerMillion: 0.025,
396
+ outputPricePerMillion: 2,
397
+ },
398
+ };
399
+ function estimateCodexSessionCost(event, model) {
400
+ if (!model) {
401
+ return undefined;
402
+ }
403
+ const pricing = CODEX_SESSION_PRICING[model];
404
+ if (!pricing) {
405
+ return undefined;
406
+ }
407
+ const info = event['info'];
408
+ if (!info || typeof info !== 'object') {
409
+ return undefined;
410
+ }
411
+ const totalTokenUsage = info['total_token_usage'];
412
+ if (!totalTokenUsage || typeof totalTokenUsage !== 'object') {
413
+ return undefined;
414
+ }
415
+ const usage = totalTokenUsage;
416
+ const inputTokens = numberField(usage['input_tokens']);
417
+ const cachedTokens = numberField(usage['cached_input_tokens']) ?? 0;
418
+ const outputTokens = numberField(usage['output_tokens']);
419
+ const thinkingTokens = numberField(usage['reasoning_output_tokens']) ?? 0;
420
+ if (inputTokens == null || outputTokens == null) {
421
+ return undefined;
422
+ }
423
+ const uncachedInputTokens = Math.max(inputTokens - cachedTokens, 0);
424
+ const totalUsd = ((uncachedInputTokens / 1_000_000) * pricing.inputPricePerMillion) +
425
+ ((cachedTokens / 1_000_000) * pricing.cachedInputPricePerMillion) +
426
+ (((outputTokens + thinkingTokens) / 1_000_000) * pricing.outputPricePerMillion);
427
+ return {
428
+ totalUsd,
429
+ inputTokens,
430
+ outputTokens,
431
+ thinkingTokens,
432
+ cachedTokens,
433
+ };
434
+ }
435
+ function numberField(value) {
436
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
437
+ }
438
+ /**
439
+ * Derive a SessionMessage-like representation from an arbitrary JSONL row.
440
+ * Used by adapters that don't have a more precise schema.
441
+ */
442
+ export function rowToMessage(row) {
443
+ return rowToMessages(row)[0] ?? null;
444
+ }
445
+ function rowToMessages(row, toolCallsById = new Map()) {
446
+ const nestedMessage = row['message'];
447
+ const envelope = nestedMessage && typeof nestedMessage === 'object'
448
+ ? nestedMessage
449
+ : row;
450
+ const role = normalizeSessionRole(envelope['role'] ?? row['role'] ?? row['sender'] ?? row['type']);
451
+ if (!role) {
452
+ return [];
453
+ }
454
+ const timestamp = parseSessionTimestamp(row['timestamp'] ?? envelope['timestamp']);
455
+ const thinkingText = flattenStructuredText(envelope['thinking']);
456
+ const contentInfo = parseStructuredContent(envelope['content'], toolCallsById);
457
+ const messages = [];
458
+ if (role === 'assistant') {
459
+ if (contentInfo.toolCalls) {
460
+ for (const toolCall of contentInfo.toolCalls) {
461
+ toolCallsById.set(toolCall.toolCallId, toolCall);
462
+ }
463
+ }
464
+ const assistantText = contentInfo.text.length > 0
465
+ ? contentInfo.text
466
+ : flattenStructuredText(envelope['text'] ??
467
+ (nestedMessage && typeof nestedMessage !== 'object' ? nestedMessage : row['text'] ?? row['message']));
468
+ if (assistantText.length > 0 || contentInfo.toolCalls?.length || contentInfo.thinking.length > 0) {
469
+ messages.push({
470
+ role,
471
+ content: assistantText,
472
+ ...(timestamp ? { timestamp } : {}),
473
+ ...(contentInfo.toolCalls?.length ? { toolCalls: contentInfo.toolCalls } : {}),
474
+ ...(contentInfo.thinking.length > 0
475
+ ? { thinking: joinTextParts([contentInfo.thinking, thinkingText].filter((value) => value.length > 0)) }
476
+ : thinkingText.length > 0
477
+ ? { thinking: thinkingText }
478
+ : {}),
479
+ });
480
+ }
481
+ return messages;
482
+ }
483
+ if (role === 'user') {
484
+ if (contentInfo.text.length > 0) {
485
+ messages.push({
486
+ role,
487
+ content: contentInfo.text,
488
+ ...(timestamp ? { timestamp } : {}),
489
+ });
490
+ }
491
+ for (const toolResult of contentInfo.toolResults) {
492
+ messages.push({
493
+ role: 'tool',
494
+ content: toolResult.text,
495
+ ...(timestamp ? { timestamp } : {}),
496
+ toolResult: {
497
+ toolCallId: toolResult.toolCallId,
498
+ toolName: toolResult.toolName,
499
+ output: toolResult.output,
500
+ },
501
+ });
502
+ }
503
+ return messages;
504
+ }
505
+ const directContent = contentInfo.text.length > 0
506
+ ? contentInfo.text
507
+ : flattenStructuredText(envelope['content'] ??
508
+ envelope['text'] ??
509
+ (nestedMessage && typeof nestedMessage !== 'object' ? nestedMessage : row['text'] ?? row['message']));
510
+ if (directContent.length === 0 && role !== 'tool') {
511
+ return [];
512
+ }
513
+ messages.push({
514
+ role,
515
+ content: directContent,
516
+ ...(timestamp ? { timestamp } : {}),
517
+ });
518
+ return messages;
519
+ }
520
+ function normalizeSessionRole(value) {
521
+ if (value === 'user' || value === 'human') {
522
+ return 'user';
523
+ }
524
+ if (value === 'assistant' || value === 'ai' || value === 'model') {
525
+ return 'assistant';
526
+ }
527
+ if (value === 'system') {
528
+ return 'system';
529
+ }
530
+ if (value === 'tool' || value === 'tool_result' || value === 'tool_use') {
531
+ return 'tool';
532
+ }
533
+ return null;
534
+ }
535
+ function parseSessionTimestamp(value) {
536
+ if (value instanceof Date) {
537
+ return Number.isFinite(value.getTime()) ? value : undefined;
538
+ }
539
+ if (typeof value === 'string' || typeof value === 'number') {
540
+ const parsed = new Date(value);
541
+ if (Number.isFinite(parsed.getTime())) {
542
+ return parsed;
543
+ }
544
+ }
545
+ return undefined;
546
+ }
547
+ function flattenStructuredText(value) {
548
+ if (typeof value === 'string') {
549
+ return value;
550
+ }
551
+ if (Array.isArray(value)) {
552
+ const parts = value.flatMap((entry) => {
553
+ if (typeof entry === 'string') {
554
+ return [entry];
555
+ }
556
+ if (!entry || typeof entry !== 'object') {
557
+ return [];
558
+ }
559
+ const block = entry;
560
+ const blockType = typeof block['type'] === 'string' ? block['type'] : '';
561
+ if (blockType === 'tool_use') {
562
+ return [];
563
+ }
564
+ if (blockType === 'text' && typeof block['text'] === 'string') {
565
+ return [block['text']];
566
+ }
567
+ if (blockType === 'thinking' && typeof block['thinking'] === 'string') {
568
+ return [block['thinking']];
569
+ }
570
+ if (blockType === 'tool_result') {
571
+ return [flattenStructuredText(block['content'] ?? block['tool_use_result'] ?? block['output'])];
572
+ }
573
+ if (typeof block['text'] === 'string') {
574
+ return [block['text']];
575
+ }
576
+ if (typeof block['content'] === 'string' || Array.isArray(block['content'])) {
577
+ return [flattenStructuredText(block['content'])];
578
+ }
579
+ if (typeof block['thinking'] === 'string') {
580
+ return [block['thinking']];
581
+ }
582
+ return [];
583
+ }).filter((part) => part.length > 0);
584
+ return joinTextParts(parts);
585
+ }
586
+ if (value && typeof value === 'object') {
587
+ const record = value;
588
+ if (typeof record['text'] === 'string') {
589
+ return record['text'];
590
+ }
591
+ if (typeof record['thinking'] === 'string') {
592
+ return record['thinking'];
593
+ }
594
+ if ('content' in record) {
595
+ return flattenStructuredText(record['content']);
596
+ }
597
+ }
598
+ if (value == null) {
599
+ return '';
600
+ }
601
+ return renderStructuredValue(value);
602
+ }
603
+ function parseStructuredContent(value, toolCallsById) {
604
+ if (!Array.isArray(value)) {
605
+ return {
606
+ text: flattenStructuredText(value),
607
+ thinking: '',
608
+ toolResults: [],
609
+ };
610
+ }
611
+ const textParts = [];
612
+ const thinkingParts = [];
613
+ const toolCalls = [];
614
+ const toolResults = [];
615
+ for (const entry of value) {
616
+ if (typeof entry === 'string') {
617
+ if (entry.length > 0) {
618
+ textParts.push(entry);
619
+ }
620
+ continue;
621
+ }
622
+ if (!entry || typeof entry !== 'object') {
623
+ continue;
624
+ }
625
+ const block = entry;
626
+ const blockType = typeof block['type'] === 'string' ? block['type'] : '';
627
+ if (blockType === 'text' && typeof block['text'] === 'string') {
628
+ textParts.push(block['text']);
629
+ continue;
630
+ }
631
+ if (blockType === 'thinking' && typeof block['thinking'] === 'string') {
632
+ thinkingParts.push(block['thinking']);
633
+ continue;
634
+ }
635
+ if (blockType === 'tool_use') {
636
+ const toolCallId = String(block['id'] ?? block['tool_use_id'] ?? '');
637
+ const toolName = String(block['name'] ?? 'tool');
638
+ if (toolCallId.length > 0) {
639
+ toolCalls.push({
640
+ toolCallId,
641
+ toolName,
642
+ input: block['input'],
643
+ });
644
+ }
645
+ continue;
646
+ }
647
+ if (blockType === 'tool_result') {
648
+ const toolCallId = String(block['tool_use_id'] ?? block['toolCallId'] ?? block['id'] ?? '');
649
+ const output = block['content'] ?? block['tool_use_result'] ?? block['output'] ?? '';
650
+ const resolvedToolName = toolCallsById.get(toolCallId)?.toolName;
651
+ toolResults.push({
652
+ toolCallId,
653
+ toolName: resolvedToolName ?? String(block['tool_name'] ?? 'tool'),
654
+ output,
655
+ text: flattenStructuredText(output),
656
+ });
657
+ continue;
658
+ }
659
+ const fallbackText = flattenStructuredText(block);
660
+ if (fallbackText.length > 0) {
661
+ textParts.push(fallbackText);
662
+ }
663
+ }
664
+ return {
665
+ text: joinTextParts(textParts),
666
+ thinking: joinTextParts(thinkingParts),
667
+ ...(toolCalls.length > 0 ? { toolCalls } : {}),
668
+ toolResults,
669
+ };
670
+ }
671
+ function joinTextParts(parts) {
672
+ return parts
673
+ .map((part) => part.trim())
674
+ .filter((part) => part.length > 0)
675
+ .join('\n\n');
676
+ }
677
+ function flattenCodexMessageText(content) {
678
+ if (!Array.isArray(content)) {
679
+ return '';
680
+ }
681
+ const parts = content.flatMap((entry) => {
682
+ if (!entry || typeof entry !== 'object') {
683
+ return [];
684
+ }
685
+ const block = entry;
686
+ const blockType = typeof block['type'] === 'string' ? block['type'] : '';
687
+ if ((blockType === 'input_text' || blockType === 'output_text') && typeof block['text'] === 'string') {
688
+ return [block['text']];
689
+ }
690
+ return [];
691
+ });
692
+ return parts.join('\n').trim();
693
+ }
694
+ function parseMaybeJson(value) {
695
+ if (typeof value !== 'string') {
696
+ return value;
697
+ }
698
+ try {
699
+ return JSON.parse(value);
700
+ }
701
+ catch {
702
+ return value;
703
+ }
704
+ }
705
+ function renderStructuredValue(value) {
706
+ if (typeof value === 'string') {
707
+ return value;
708
+ }
709
+ try {
710
+ return JSON.stringify(value, null, 2);
711
+ }
712
+ catch {
713
+ return String(value);
714
+ }
715
+ }
716
+ function shouldSkipCodexBootstrapMessage(role, text) {
717
+ if (role !== 'user') {
718
+ return false;
719
+ }
720
+ return text.startsWith('# AGENTS.md instructions for ') && text.includes('<environment_context>');
721
+ }
722
+ //# sourceMappingURL=session-fs.js.map