shennian 0.3.86 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/README.md +3 -2
  2. package/dist/bin/shennian.js +1 -1
  3. package/dist/publish-build-manifest.json +32 -27
  4. package/dist/src/agents/adapter.js +1 -19
  5. package/dist/src/agents/claude-managed-permissions.js +1 -248
  6. package/dist/src/agents/claude.js +8 -393
  7. package/dist/src/agents/codex-managed-permissions.js +1 -294
  8. package/dist/src/agents/codex-managed-room-tools.js +1 -249
  9. package/dist/src/agents/codex-utils.js +7 -200
  10. package/dist/src/agents/codex.d.ts +7 -1
  11. package/dist/src/agents/codex.js +17 -1352
  12. package/dist/src/agents/config-status.js +1 -226
  13. package/dist/src/agents/cursor-managed-permissions.js +2 -299
  14. package/dist/src/agents/cursor.js +1 -314
  15. package/dist/src/agents/custom.js +4 -418
  16. package/dist/src/agents/external-channel-instructions.js +11 -94
  17. package/dist/src/agents/gemini.js +1 -180
  18. package/dist/src/agents/manager.js +18 -250
  19. package/dist/src/agents/model-registry/cache.js +1 -37
  20. package/dist/src/agents/model-registry/discovery.js +2 -188
  21. package/dist/src/agents/model-registry/parsers.js +4 -521
  22. package/dist/src/agents/model-registry/runner.js +1 -30
  23. package/dist/src/agents/model-registry/service.js +1 -115
  24. package/dist/src/agents/model-registry/types.js +1 -8
  25. package/dist/src/agents/model-registry.js +1 -19
  26. package/dist/src/agents/native-capabilities.js +1 -237
  27. package/dist/src/agents/openclaw.js +2 -293
  28. package/dist/src/agents/opencode-managed-permissions.js +2 -187
  29. package/dist/src/agents/opencode.js +1 -298
  30. package/dist/src/agents/platform-instructions.js +17 -46
  31. package/dist/src/agents/runtime-compatibility.js +1 -44
  32. package/dist/src/agents/workbuddy-managed-permissions.js +2 -329
  33. package/dist/src/agents/workbuddy.js +3 -444
  34. package/dist/src/commands/logout.d.ts +3 -0
  35. package/dist/src/commands/logout.js +1 -0
  36. package/dist/src/daemon-ipc/paths.js +1 -1
  37. package/dist/src/fs/boundary.js +1 -185
  38. package/dist/src/fs/handler.js +1 -130
  39. package/dist/src/fs/security.js +1 -32
  40. package/dist/src/fs/text-decoder.js +1 -110
  41. package/dist/src/index.js +3 -587
  42. package/dist/src/manager/prompt.js +29 -34
  43. package/dist/src/manager/registry.js +1 -317
  44. package/dist/src/manager/retired-external-channel-compat.js +1 -40
  45. package/dist/src/manager/runtime.js +23 -1514
  46. package/dist/src/native-fusion/codex-parser.d.ts +3 -1
  47. package/dist/src/native-fusion/codex-parser.js +4 -660
  48. package/dist/src/native-fusion/codex-user-input.js +5 -102
  49. package/dist/src/native-fusion/config.js +1 -5
  50. package/dist/src/native-fusion/file-watcher.js +1 -191
  51. package/dist/src/native-fusion/local-repository.js +2 -569
  52. package/dist/src/native-fusion/opencode-parser.js +3 -130
  53. package/dist/src/native-fusion/parser-common.d.ts +6 -1
  54. package/dist/src/native-fusion/parser-common.js +4 -4
  55. package/dist/src/native-fusion/parsers.d.ts +4 -2
  56. package/dist/src/native-fusion/parsers.js +3 -140
  57. package/dist/src/native-fusion/service.js +2 -739
  58. package/dist/src/native-fusion/session-header.js +2 -101
  59. package/dist/src/native-fusion/state.js +2 -104
  60. package/dist/src/native-fusion/types.js +1 -1
  61. package/dist/src/personal-sync/machine-authority.js +1 -34
  62. package/dist/src/room/activation-audit.js +2 -45
  63. package/dist/src/room/activation-policy.js +1 -30
  64. package/dist/src/room/activation-service.js +8 -408
  65. package/dist/src/room/invite-bootstrap.js +1 -156
  66. package/dist/src/room/managed-prompt-composer.d.ts +1 -1
  67. package/dist/src/room/managed-prompt-composer.js +17 -16
  68. package/dist/src/room/managed-room-binding.js +1 -167
  69. package/dist/src/room/managed-room-ipc.d.ts +4 -0
  70. package/dist/src/room/managed-room-ipc.js +2 -2
  71. package/dist/src/room/mirror-sync-service.d.ts +1 -0
  72. package/dist/src/room/mirror-sync-service.js +1 -183
  73. package/dist/src/room/room-binding-client.js +1 -151
  74. package/dist/src/session/archive-zip.js +1 -220
  75. package/dist/src/session/deletion-sync-state.js +2 -136
  76. package/dist/src/session/handlers/agent-capabilities.js +1 -14
  77. package/dist/src/session/handlers/agent-config.js +1 -150
  78. package/dist/src/session/handlers/agents.js +1 -55
  79. package/dist/src/session/handlers/chat.js +2 -1030
  80. package/dist/src/session/handlers/control.js +1 -61
  81. package/dist/src/session/handlers/fs.js +1 -594
  82. package/dist/src/session/handlers/message-status.js +1 -15
  83. package/dist/src/session/handlers/remote-access.js +1 -43
  84. package/dist/src/session/handlers/room-managed.js +1 -101
  85. package/dist/src/session/handlers/session-refresh.js +1 -35
  86. package/dist/src/session/handlers/title.js +1 -79
  87. package/dist/src/session/handlers/tool-detail.js +1 -149
  88. package/dist/src/session/handlers/voice-window.js +1 -62
  89. package/dist/src/session/history-subscriptions.js +1 -470
  90. package/dist/src/session/manager.d.ts +1 -0
  91. package/dist/src/session/manager.js +1 -658
  92. package/dist/src/session/native-cleanup-outbox.js +2 -287
  93. package/dist/src/session/native-session-lifecycle.js +6 -327
  94. package/dist/src/session/queue.d.ts +8 -0
  95. package/dist/src/session/queue.js +6 -6
  96. package/dist/src/upgrade/scheduler.js +1 -126
  97. package/node_modules/@shennian/wire/dist/agent-workspace.js +2 -2
  98. package/package.json +1 -1
@@ -1,660 +1,4 @@
1
- // @arch docs/architecture/cli/native-session-fusion.md
2
- // @test src/__tests__/native-fusion-parsers.test.ts
3
- // @test src/__tests__/native-fusion-codex-current-input.test.ts
4
- // @test src/__tests__/native-fusion-codex-subagent.test.ts
5
- import fs from 'node:fs';
6
- import path from 'node:path';
7
- import { createHash } from 'node:crypto';
8
- import { buildApprovalPendingPayload, buildUserMessagePayload, isSystemControlPayload, isToolPayload } from '@shennian/wire';
9
- import { buildImagePayload, buildToolPayload, findJsonlLookbackOffset, inferMimeType, makeCursor, normalizeText, parseStructuredString, readJsonlLines, readTimestamp, safeParse, shouldIgnoreNativeScanPath, } from './parser-common.js';
10
- import { lookupCodexThreadName } from './codex-files.js';
11
- import { parseCodexDelegationInput, parseCodexResponseUserInput, parseCodexTextElements, stripCodexUserMessageWrapper, } from './codex-user-input.js';
12
- export { listCodexRolloutFiles, lookupCodexThreadName } from './codex-files.js';
13
- function parseCodexLocalImageAttachment(value) {
14
- if (typeof value === 'string') {
15
- const imagePath = value.trim();
16
- if (!imagePath)
17
- return null;
18
- return {
19
- path: imagePath,
20
- name: path.basename(imagePath) || 'image.png',
21
- mimeType: inferMimeType(imagePath),
22
- kind: 'image',
23
- };
24
- }
25
- if (typeof value !== 'object' || value === null)
26
- return null;
27
- const entry = value;
28
- const imagePath = typeof entry.path === 'string' ? entry.path
29
- : typeof entry.file_path === 'string' ? entry.file_path
30
- : typeof entry.saved_path === 'string' ? entry.saved_path
31
- : typeof entry.image_path === 'string' ? entry.image_path
32
- : '';
33
- if (!imagePath.trim())
34
- return null;
35
- const name = typeof entry.name === 'string' && entry.name.trim()
36
- ? entry.name
37
- : path.basename(imagePath) || 'image.png';
38
- const mimeType = typeof entry.mimeType === 'string' && entry.mimeType.trim()
39
- ? entry.mimeType
40
- : inferMimeType(imagePath);
41
- return {
42
- path: imagePath,
43
- name,
44
- mimeType,
45
- kind: 'image',
46
- };
47
- }
48
- function isCodexInjectedContextText(text) {
49
- const normalized = normalizeText(text);
50
- if (!normalized)
51
- return false;
52
- if (isSystemControlPayload(normalized))
53
- return true;
54
- if (/^<environment_context>[\s\S]*<\/environment_context>$/i.test(normalized) &&
55
- normalized.includes('<current_date>') &&
56
- normalized.includes('<timezone>') &&
57
- normalized.includes('<workspace_roots>')) {
58
- return true;
59
- }
60
- const hasRecommendedPluginsPrefix = normalized.startsWith('<recommended_plugins>') &&
61
- normalized.includes('</recommended_plugins>');
62
- const hasProjectInstructions = normalized.includes('# AGENTS.md instructions for ') &&
63
- normalized.includes('<INSTRUCTIONS>') && normalized.includes('</INSTRUCTIONS>');
64
- const hasEnvironmentContext = normalized.includes('<environment_context>') &&
65
- normalized.includes('</environment_context>');
66
- return hasProjectInstructions && hasEnvironmentContext &&
67
- (normalized.startsWith('# AGENTS.md instructions for ') || hasRecommendedPluginsPrefix);
68
- }
69
- function parseCodexUserMessage(payload) {
70
- const textFromElements = parseCodexTextElements(payload.text_elements);
71
- const textFromInput = Array.isArray(payload.input)
72
- ? parseCodexTextElements(payload.input)
73
- : '';
74
- const strippedMessage = typeof payload.message === 'string'
75
- ? stripCodexUserMessageWrapper(payload.message)
76
- : { text: '', strippedWrapper: false };
77
- const textFromMessage = strippedMessage.text;
78
- const text = textFromElements || textFromInput || textFromMessage;
79
- const repairHint = strippedMessage.strippedWrapper ? 'codex_app_context_wrapper' : undefined;
80
- const attachments = Array.isArray(payload.local_images)
81
- ? payload.local_images
82
- .map(parseCodexLocalImageAttachment)
83
- .filter((item) => item != null)
84
- : [];
85
- if (!text && attachments.length === 0)
86
- return null;
87
- if (isSystemControlPayload(text) && attachments.length === 0)
88
- return null;
89
- if (isCodexInjectedContextText(text) && attachments.length === 0)
90
- return null;
91
- if (attachments.length > 0) {
92
- return {
93
- payload: buildUserMessagePayload(text, attachments),
94
- titleText: text,
95
- repairHint,
96
- };
97
- }
98
- return { payload: text, titleText: text, repairHint };
99
- }
100
- function codexTerminalState(eventType) {
101
- if (eventType === 'turn_aborted')
102
- return 'aborted';
103
- if (eventType === 'turn_completed' || eventType === 'turn_complete' || eventType === 'task_complete') {
104
- return 'completed';
105
- }
106
- return null;
107
- }
108
- function isCodexApprovalEventType(eventType) {
109
- return /approval|permission|confirm|user[_-]?input|input[_-]?required/i.test(eventType);
110
- }
111
- function buildCodexApprovalPayload(payload) {
112
- const command = typeof payload.command === 'string'
113
- ? payload.command
114
- : Array.isArray(payload.command)
115
- ? payload.command.join(' ')
116
- : '';
117
- const content = typeof payload.prompt === 'string' ? payload.prompt
118
- : typeof payload.reason === 'string' ? payload.reason
119
- : typeof payload.message === 'string' ? payload.message
120
- : command ? `Codex 请求执行命令:${command}`
121
- : 'Codex 正在等待用户确认后继续。';
122
- return buildApprovalPendingPayload({
123
- title: '需要用户确认',
124
- content,
125
- source: 'codex',
126
- actionHint: '当前神念暂不支持远程确认,请回到运行 Codex 的电脑/终端完成确认。',
127
- });
128
- }
129
- function codexMessageContentText(content, textType) {
130
- if (!Array.isArray(content))
131
- return '';
132
- return normalizeText(content
133
- .map((part) => {
134
- if (typeof part === 'string')
135
- return part;
136
- if (typeof part !== 'object' || part === null)
137
- return '';
138
- const record = part;
139
- if (record.type !== textType)
140
- return '';
141
- return typeof record.text === 'string' ? record.text : '';
142
- })
143
- .filter(Boolean)
144
- .join('\n\n'));
145
- }
146
- function codexMessageInputImageAttachments(content) {
147
- if (!Array.isArray(content))
148
- return [];
149
- const attachments = [];
150
- for (const part of content) {
151
- if (typeof part !== 'object' || part === null)
152
- continue;
153
- const record = part;
154
- if (record.type !== 'input_image')
155
- continue;
156
- const attachment = parseCodexLocalImageAttachment(record);
157
- if (attachment)
158
- attachments.push(attachment);
159
- }
160
- return attachments;
161
- }
162
- function parseCodexResponseMessage(payload) {
163
- if (payload.type !== 'message')
164
- return null;
165
- const role = payload.role === 'assistant' ? 'agent' : payload.role === 'user' ? 'user' : null;
166
- if (!role)
167
- return null;
168
- if (role === 'agent') {
169
- const text = codexMessageContentText(payload.content, 'output_text');
170
- if (isSystemControlPayload(text))
171
- return null;
172
- return text ? { role, payload: text, titleText: text } : null;
173
- }
174
- const parsedInput = parseCodexResponseUserInput(payload.content);
175
- const text = parsedInput.text;
176
- const attachments = [...codexMessageInputImageAttachments(payload.content)];
177
- for (const imagePath of parsedInput.imagePaths) {
178
- const attachment = parseCodexLocalImageAttachment(imagePath);
179
- if (!attachment)
180
- continue;
181
- if (!attachments.some((existing) => existing.path === attachment.path))
182
- attachments.push(attachment);
183
- }
184
- if (!text && attachments.length === 0)
185
- return null;
186
- if (isSystemControlPayload(text) && attachments.length === 0)
187
- return null;
188
- if (isCodexInjectedContextText(text) && attachments.length === 0)
189
- return null;
190
- return {
191
- role,
192
- payload: attachments.length > 0 ? buildUserMessagePayload(text, attachments) : text,
193
- titleText: text,
194
- repairHint: parsedInput.strippedWrapper ? 'codex_app_context_wrapper' : undefined,
195
- };
196
- }
197
- function codexDedupeText(payload) {
198
- if (!payload)
199
- return '';
200
- try {
201
- const parsed = JSON.parse(payload);
202
- if (typeof parsed === 'object' && parsed !== null) {
203
- const record = parsed;
204
- if (record.type === 'user' && typeof record.content === 'string')
205
- return normalizeText(record.content);
206
- }
207
- }
208
- catch {
209
- /* plain text payload */
210
- }
211
- return normalizeText(payload);
212
- }
213
- function isDuplicateCodexChatEvent(event, role, payload, ts) {
214
- if (event.agentType !== 'codex')
215
- return false;
216
- if (event.role !== role)
217
- return false;
218
- if (isToolPayload(event.payload))
219
- return false;
220
- if (Math.abs(event.ts - ts) > 5 * 60 * 1000)
221
- return false;
222
- return codexDedupeText(event.payload) === codexDedupeText(payload);
223
- }
224
- function findDuplicateCodexChatEventIndex(events, role, payload, ts) {
225
- for (let i = events.length - 1; i >= 0; i -= 1) {
226
- const event = events[i];
227
- if (!event)
228
- continue;
229
- if (isDuplicateCodexChatEvent(event, role, payload, ts))
230
- return i;
231
- if (event.agentType === 'codex' && Math.abs(event.ts - ts) > 5 * 60 * 1000)
232
- break;
233
- }
234
- return -1;
235
- }
236
- function pushCodexEvent(events, filePath, lineOffset, kind, sourceSessionKey, ts, payload, title, modelId, workDir, role = 'agent', terminal = false, repairHint) {
237
- if (!payload)
238
- return;
239
- events.push({
240
- agentType: 'codex',
241
- sourceMode: 'codex_rollout_import',
242
- sourceSessionKey,
243
- sourceEventKey: makeCodexEventKey(sourceSessionKey, lineOffset, kind),
244
- cursor: makeCursor(filePath, lineOffset),
245
- role,
246
- ts,
247
- payload,
248
- title,
249
- modelId,
250
- workDir,
251
- terminal,
252
- ...(terminal
253
- ? {
254
- terminalState: kind === 'turn_aborted' ? 'aborted'
255
- : kind === 'error' ? 'failed'
256
- : 'completed',
257
- }
258
- : {}),
259
- repairHint,
260
- });
261
- }
262
- function pushCodexToolEvent(events, filePath, lineOffset, kind, sourceSessionKey, ts, toolName, title, modelId, workDir, args, result, logical) {
263
- const sourceEventKey = makeCodexEventKey(sourceSessionKey, lineOffset, kind);
264
- const callId = typeof logical?.callId === 'string' && logical.callId.trim()
265
- ? logical.callId.trim()
266
- : null;
267
- const logicalDigest = callId
268
- ? createHash('sha256').update(`${sourceSessionKey}\0${callId}`).digest('hex').slice(0, 32)
269
- : null;
270
- const canonicalMessageKey = logicalDigest ? `tool:${logicalDigest}` : undefined;
271
- const toolCallId = logicalDigest ? `native:tool:${logicalDigest}` : `native:${sourceEventKey}`;
272
- const detailRevision = logical?.completed && logicalDigest ? 2 : 1;
273
- const status = result !== undefined ? 'completed' : 'running';
274
- events.push({
275
- agentType: 'codex',
276
- sourceMode: 'codex_rollout_import',
277
- sourceSessionKey,
278
- sourceEventKey,
279
- cursor: makeCursor(filePath, lineOffset),
280
- role: 'agent',
281
- ts,
282
- payload: buildToolPayload({ name: toolName, toolCallId, detailRevision, status }),
283
- title,
284
- modelId,
285
- workDir,
286
- ...(canonicalMessageKey ? {
287
- canonicalMessageKey,
288
- canonicalMutation: logical?.completed ? 'upsert' : 'append',
289
- } : {}),
290
- localToolDetail: {
291
- toolCallId,
292
- detailRevision,
293
- name: toolName,
294
- ...(args !== undefined ? { args } : {}),
295
- ...(result !== undefined ? { result } : {}),
296
- status,
297
- },
298
- });
299
- }
300
- function makeCodexEventKey(sourceSessionKey, offset, kind) {
301
- // Active/archive are discovery locations, never provider identity. Codex
302
- // preserves the rollout bytes when moving a thread, so stable thread ID +
303
- // byte offset + event kind survives rename, move, touch and unarchive.
304
- return `codex:${sourceSessionKey}:${offset}:${kind}`;
305
- }
306
- function parseCodexResponseItem(events, filePath, lineOffset, payload, sourceSessionKey, ts, title, modelId, workDir) {
307
- const itemType = typeof payload.type === 'string' ? payload.type : '';
308
- if (!itemType)
309
- return;
310
- if (itemType === 'message') {
311
- const parsedMessage = parseCodexResponseMessage(payload);
312
- if (!parsedMessage)
313
- return;
314
- const duplicateIndex = findDuplicateCodexChatEventIndex(events, parsedMessage.role, parsedMessage.payload, ts);
315
- if (duplicateIndex >= 0)
316
- return;
317
- pushCodexEvent(events, filePath, lineOffset, `${itemType}:${parsedMessage.role}`, sourceSessionKey, ts, parsedMessage.payload, title, modelId, workDir, parsedMessage.role, false, parsedMessage.repairHint);
318
- return;
319
- }
320
- if (itemType === 'function_call') {
321
- const name = typeof payload.name === 'string' ? payload.name : 'function_call';
322
- pushCodexToolEvent(events, filePath, lineOffset, itemType, sourceSessionKey, ts, name, title, modelId, workDir, parseStructuredString(payload.arguments), undefined, { callId: payload.call_id });
323
- return;
324
- }
325
- if (itemType === 'function_call_output') {
326
- const delegationInput = parseCodexDelegationInput(payload);
327
- if (delegationInput) {
328
- pushCodexEvent(events, filePath, lineOffset, 'delegation:user', sourceSessionKey, ts, delegationInput, title || delegationInput.slice(0, 80), modelId, workDir, 'user');
329
- return;
330
- }
331
- pushCodexToolEvent(events, filePath, lineOffset, itemType, sourceSessionKey, ts, 'function_call_output', title, modelId, workDir, undefined, payload.output, { callId: payload.call_id, completed: true });
332
- return;
333
- }
334
- if (itemType === 'custom_tool_call') {
335
- const name = typeof payload.name === 'string' ? payload.name : 'custom_tool_call';
336
- const args = payload.input !== undefined ? { input: payload.input } : undefined;
337
- pushCodexToolEvent(events, filePath, lineOffset, itemType, sourceSessionKey, ts, name, title, modelId, workDir, args, undefined, { callId: payload.call_id });
338
- return;
339
- }
340
- if (itemType === 'custom_tool_call_output') {
341
- const name = typeof payload.name === 'string' ? payload.name : 'custom_tool_call_output';
342
- const result = payload.output ?? payload.result ?? payload.content;
343
- pushCodexToolEvent(events, filePath, lineOffset, itemType, sourceSessionKey, ts, name, title, modelId, workDir, undefined, result, { callId: payload.call_id, completed: true });
344
- return;
345
- }
346
- if (itemType === 'web_search_call') {
347
- const action = typeof payload.action === 'object' && payload.action !== null
348
- ? payload.action
349
- : null;
350
- pushCodexToolEvent(events, filePath, lineOffset, itemType, sourceSessionKey, ts, 'web_search', title, modelId, workDir, action ?? payload.query);
351
- return;
352
- }
353
- }
354
- function parseCodexEventMessage(events, filePath, lineOffset, payload, sourceSessionKey, ts, title, modelId, workDir) {
355
- const eventType = typeof payload.type === 'string' ? payload.type : '';
356
- if (!eventType)
357
- return;
358
- if (eventType === 'user_message') {
359
- const parsedUser = parseCodexUserMessage(payload);
360
- if (!parsedUser)
361
- return;
362
- pushCodexEvent(events, filePath, lineOffset, eventType, sourceSessionKey, ts, parsedUser.payload, title, modelId, workDir, 'user', false, parsedUser.repairHint);
363
- return;
364
- }
365
- if (eventType === 'agent_message') {
366
- const text = typeof payload.message === 'string' ? normalizeText(payload.message) : '';
367
- if (!text || isSystemControlPayload(text))
368
- return;
369
- pushCodexEvent(events, filePath, lineOffset, eventType, sourceSessionKey, ts, text, title, modelId, workDir);
370
- return;
371
- }
372
- if (eventType === 'turn_aborted' || eventType === 'error') {
373
- const text = typeof payload.message === 'string'
374
- ? normalizeText(payload.message)
375
- : typeof payload.error === 'string'
376
- ? normalizeText(payload.error)
377
- : '';
378
- if (!text)
379
- return;
380
- pushCodexEvent(events, filePath, lineOffset, eventType, sourceSessionKey, ts, text, title, modelId, workDir, 'agent', true);
381
- return;
382
- }
383
- if (isCodexApprovalEventType(eventType)) {
384
- pushCodexEvent(events, filePath, lineOffset, eventType, sourceSessionKey, ts, buildCodexApprovalPayload(payload), title, modelId, workDir, 'agent');
385
- return;
386
- }
387
- if (eventType === 'exec_command_end') {
388
- const command = Array.isArray(payload.command) ? payload.command : payload.parsed_cmd ?? payload.command;
389
- const exitCode = payload.exit_code ?? payload.exitCode;
390
- const output = [
391
- typeof payload.aggregated_output === 'string' ? payload.aggregated_output : '',
392
- exitCode != null ? `\n(exit ${String(exitCode)})` : '',
393
- ].join('');
394
- pushCodexToolEvent(events, filePath, lineOffset, eventType, sourceSessionKey, ts, 'command_execution', title, modelId, workDir, { command }, output);
395
- return;
396
- }
397
- if (eventType === 'patch_apply_end') {
398
- pushCodexToolEvent(events, filePath, lineOffset, eventType, sourceSessionKey, ts, 'apply_patch', title, modelId, workDir, payload.changes, {
399
- success: payload.success,
400
- stdout: payload.stdout,
401
- stderr: payload.stderr,
402
- });
403
- return;
404
- }
405
- if (eventType === 'mcp_tool_call_end') {
406
- const invocation = typeof payload.invocation === 'object' && payload.invocation !== null
407
- ? payload.invocation
408
- : null;
409
- const tool = typeof invocation?.tool === 'string' ? invocation.tool : 'mcp_tool_call';
410
- const args = {
411
- server: invocation?.server,
412
- ...(typeof invocation?.arguments === 'object' && invocation.arguments !== null
413
- ? invocation.arguments
414
- : {}),
415
- };
416
- pushCodexToolEvent(events, filePath, lineOffset, eventType, sourceSessionKey, ts, tool, title, modelId, workDir, args, payload.result);
417
- return;
418
- }
419
- if (eventType === 'dynamic_tool_call_request') {
420
- const tool = typeof payload.tool === 'string' ? payload.tool : 'dynamic_tool_call';
421
- pushCodexToolEvent(events, filePath, lineOffset, eventType, sourceSessionKey, ts, tool, title, modelId, workDir, payload.arguments, undefined, { callId: payload.callId ?? payload.call_id });
422
- return;
423
- }
424
- if (eventType === 'dynamic_tool_call_response') {
425
- const tool = typeof payload.tool === 'string' ? payload.tool : 'dynamic_tool_call';
426
- pushCodexToolEvent(events, filePath, lineOffset, eventType, sourceSessionKey, ts, tool, title, modelId, workDir, undefined, payload.result ?? payload.output, { callId: payload.callId ?? payload.call_id, completed: true });
427
- return;
428
- }
429
- if (eventType === 'web_search_end') {
430
- const action = typeof payload.action === 'object' && payload.action !== null
431
- ? payload.action
432
- : null;
433
- pushCodexToolEvent(events, filePath, lineOffset, eventType, sourceSessionKey, ts, 'web_search', title, modelId, workDir, action ?? payload.query, payload.query);
434
- return;
435
- }
436
- if (eventType === 'image_generation_end') {
437
- const savedPath = typeof payload.saved_path === 'string' ? payload.saved_path.trim() : '';
438
- if (!savedPath)
439
- return;
440
- pushCodexEvent(events, filePath, lineOffset, eventType, sourceSessionKey, ts, buildImagePayload(savedPath), title, modelId, workDir);
441
- return;
442
- }
443
- if (eventType === 'view_image_tool_call') {
444
- pushCodexToolEvent(events, filePath, lineOffset, eventType, sourceSessionKey, ts, 'view_image', title, modelId, workDir, payload.path ?? payload.image_path ?? payload);
445
- }
446
- }
447
- function emptyCodexSessionMeta(skipImport = false) {
448
- return {
449
- sourceSessionKey: '',
450
- workDir: '',
451
- modelId: null,
452
- title: '',
453
- skipImport,
454
- };
455
- }
456
- function isCodexSubagentSessionMeta(payload) {
457
- const threadSource = typeof payload.thread_source === 'string'
458
- ? payload.thread_source.trim().toLowerCase()
459
- : '';
460
- if (threadSource === 'subagent')
461
- return true;
462
- const source = typeof payload.source === 'object' && payload.source !== null
463
- ? payload.source
464
- : null;
465
- if (source && typeof source.subagent === 'object' && source.subagent !== null)
466
- return true;
467
- const hasParentThread = typeof payload.parent_thread_id === 'string'
468
- && payload.parent_thread_id.trim().length > 0;
469
- const hasSubagentIdentity = typeof payload.agent_nickname === 'string'
470
- || typeof payload.agent_role === 'string'
471
- || typeof payload.multi_agent_version === 'string';
472
- return hasParentThread && hasSubagentIdentity;
473
- }
474
- function readCodexSessionMeta(filePath) {
475
- const fd = fs.openSync(filePath, 'r');
476
- try {
477
- const chunks = [];
478
- let position = 0;
479
- let firstLine = '';
480
- while (position < 1024 * 1024) {
481
- const buffer = Buffer.alloc(16 * 1024);
482
- const bytesRead = fs.readSync(fd, buffer, 0, buffer.length, position);
483
- if (bytesRead <= 0)
484
- break;
485
- const chunk = buffer.subarray(0, bytesRead);
486
- chunks.push(chunk);
487
- position += bytesRead;
488
- const combined = Buffer.concat(chunks);
489
- const newlineIndex = combined.indexOf(0x0a);
490
- if (newlineIndex >= 0) {
491
- firstLine = combined.subarray(0, newlineIndex).toString('utf8');
492
- break;
493
- }
494
- }
495
- if (!firstLine && chunks.length > 0) {
496
- firstLine = Buffer.concat(chunks).toString('utf8');
497
- }
498
- const parsed = safeParse(firstLine);
499
- if (!parsed || parsed.type !== 'session_meta') {
500
- return emptyCodexSessionMeta();
501
- }
502
- const payload = typeof parsed.payload === 'object' && parsed.payload !== null
503
- ? parsed.payload
504
- : null;
505
- if (!payload) {
506
- return emptyCodexSessionMeta();
507
- }
508
- if (isCodexSubagentSessionMeta(payload)) {
509
- return emptyCodexSessionMeta(true);
510
- }
511
- const sourceSessionKey = typeof payload.id === 'string' ? payload.id : '';
512
- return {
513
- sourceSessionKey,
514
- workDir: typeof payload.cwd === 'string' ? payload.cwd : '',
515
- modelId: readCodexModelId(payload),
516
- title: lookupCodexThreadName(sourceSessionKey) ?? '',
517
- skipImport: false,
518
- };
519
- }
520
- finally {
521
- fs.closeSync(fd);
522
- }
523
- return emptyCodexSessionMeta();
524
- }
525
- function readCodexModelId(payload) {
526
- const model = typeof payload.model === 'string' ? payload.model.trim() : '';
527
- return model || null;
528
- }
529
- export function parseCodexRolloutChunk(filePath, startOffset) {
530
- const events = [];
531
- const metadata = readCodexSessionMeta(filePath);
532
- let { sourceSessionKey, workDir, modelId, title, skipImport } = metadata;
533
- let nativeTitle = metadata.title;
534
- if (skipImport || shouldIgnoreNativeScanPath(workDir)) {
535
- return { nextOffset: fs.statSync(filePath).size, events: [] };
536
- }
537
- let pendingTerminalState = null;
538
- const terminalReplayKeys = new Set();
539
- const nextOffset = readJsonlLines(filePath, findJsonlLookbackOffset(filePath, startOffset), (line, lineOffset) => {
540
- const parsed = safeParse(line);
541
- if (!parsed)
542
- return;
543
- const type = typeof parsed.type === 'string' ? parsed.type : '';
544
- const payload = typeof parsed.payload === 'object' && parsed.payload !== null
545
- ? parsed.payload
546
- : null;
547
- const ts = readTimestamp(parsed.timestamp);
548
- if (!payload || !ts)
549
- return;
550
- if (type === 'session_meta') {
551
- if (isCodexSubagentSessionMeta(payload)) {
552
- events.length = 0;
553
- skipImport = true;
554
- return;
555
- }
556
- sourceSessionKey = typeof payload.id === 'string' ? payload.id : sourceSessionKey;
557
- workDir = typeof payload.cwd === 'string' ? payload.cwd : workDir;
558
- if (shouldIgnoreNativeScanPath(workDir)) {
559
- events.length = 0;
560
- skipImport = true;
561
- return;
562
- }
563
- modelId = readCodexModelId(payload) ?? modelId;
564
- const observedNativeTitle = lookupCodexThreadName(sourceSessionKey);
565
- if (observedNativeTitle) {
566
- nativeTitle = observedNativeTitle;
567
- title = observedNativeTitle;
568
- }
569
- return;
570
- }
571
- if (skipImport)
572
- return;
573
- if (!sourceSessionKey)
574
- return;
575
- if (type === 'response_item') {
576
- const parsedMessage = parseCodexResponseMessage(payload);
577
- if (parsedMessage?.role === 'user' && parsedMessage.titleText && !title) {
578
- title = parsedMessage.titleText.slice(0, 80);
579
- }
580
- parseCodexResponseItem(events, filePath, lineOffset, payload, sourceSessionKey, ts, title, modelId, workDir);
581
- return;
582
- }
583
- if (type === 'event_msg') {
584
- const eventType = typeof payload.type === 'string' ? payload.type : '';
585
- const terminalState = codexTerminalState(eventType);
586
- if (terminalState) {
587
- let markedTerminal = false;
588
- for (let i = events.length - 1; i >= 0; i -= 1) {
589
- const event = events[i];
590
- if (event?.agentType !== 'codex')
591
- continue;
592
- if (event.role !== 'agent')
593
- continue;
594
- if (isToolPayload(event.payload))
595
- continue;
596
- event.terminal = true;
597
- event.terminalState = terminalState;
598
- if (lineOffset >= startOffset && Number(event.cursor?.slice(filePath.length + 1)) < startOffset) {
599
- terminalReplayKeys.add(event.sourceEventKey);
600
- }
601
- markedTerminal = true;
602
- pendingTerminalState = null;
603
- break;
604
- }
605
- if (!markedTerminal) {
606
- for (let i = events.length - 1; i >= 0; i -= 1) {
607
- const event = events[i];
608
- if (event?.agentType !== 'codex' || event.role !== 'agent')
609
- continue;
610
- event.terminal = true;
611
- event.terminalState = terminalState;
612
- if (lineOffset >= startOffset && Number(event.cursor?.slice(filePath.length + 1)) < startOffset)
613
- terminalReplayKeys.add(event.sourceEventKey);
614
- markedTerminal = true;
615
- pendingTerminalState = null;
616
- break;
617
- }
618
- }
619
- if (!markedTerminal)
620
- pendingTerminalState = terminalState;
621
- return;
622
- }
623
- if (eventType === 'user_message') {
624
- const parsedUser = parseCodexUserMessage(payload);
625
- if (parsedUser?.titleText && !title)
626
- title = parsedUser.titleText.slice(0, 80);
627
- if (parsedUser) {
628
- const duplicateIndex = findDuplicateCodexChatEventIndex(events, 'user', parsedUser.payload, ts);
629
- if (duplicateIndex >= 0)
630
- events.splice(duplicateIndex, 1);
631
- }
632
- }
633
- else if (eventType === 'agent_message') {
634
- const text = typeof payload.message === 'string' ? normalizeText(payload.message) : '';
635
- if (text && !isSystemControlPayload(text)) {
636
- const duplicateIndex = findDuplicateCodexChatEventIndex(events, 'agent', text, ts);
637
- if (duplicateIndex >= 0)
638
- events.splice(duplicateIndex, 1);
639
- }
640
- }
641
- const beforeCount = events.length;
642
- parseCodexEventMessage(events, filePath, lineOffset, payload, sourceSessionKey, ts, title, modelId, workDir);
643
- if (pendingTerminalState && events.length > beforeCount) {
644
- events[events.length - 1].terminal = true;
645
- events[events.length - 1].terminalState = pendingTerminalState;
646
- pendingTerminalState = null;
647
- }
648
- }
649
- });
650
- for (const event of events) {
651
- event.titleSource = nativeTitle && event.title === nativeTitle
652
- ? 'agent_native'
653
- : 'first_user_fallback';
654
- }
655
- return {
656
- nextOffset,
657
- events: events.filter((event) => terminalReplayKeys.has(event.sourceEventKey)
658
- || Number(event.cursor?.slice(filePath.length + 1)) >= startOffset),
659
- };
660
- }
1
+ import j from"node:fs";import $ from"node:path";import{createHash as D}from"node:crypto";import{buildApprovalPendingPayload as K,buildUserMessagePayload as k,isSystemControlPayload as A,isToolPayload as L}from"@shennian/wire";import{buildImagePayload as O,buildToolPayload as ee,findJsonlLookbackOffset as te,inferMimeType as U,makeCursor as H,normalizeText as y,parseStructuredString as ne,readJsonlLines as re,readJsonlLinesCooperatively as oe,readTimestamp as ie,safeParse as W,shouldIgnoreNativeScanPath as q}from"./parser-common.js";import{lookupCodexThreadName as w}from"./codex-files.js";import{parseCodexDelegationInput as ue,parseCodexResponseUserInput as ce,parseCodexTextElements as z,stripCodexUserMessageWrapper as se}from"./codex-user-input.js";import{listCodexRolloutFiles as Ee,lookupCodexThreadName as Re}from"./codex-files.js";function R(e){if(typeof e=="string"){const i=e.trim();return i?{path:i,name:$.basename(i)||"image.png",mimeType:U(i),kind:"image"}:null}if(typeof e!="object"||e===null)return null;const r=e,n=typeof r.path=="string"?r.path:typeof r.file_path=="string"?r.file_path:typeof r.saved_path=="string"?r.saved_path:typeof r.image_path=="string"?r.image_path:"";if(!n.trim())return null;const t=typeof r.name=="string"&&r.name.trim()?r.name:$.basename(n)||"image.png",o=typeof r.mimeType=="string"&&r.mimeType.trim()?r.mimeType:U(n);return{path:n,name:t,mimeType:o,kind:"image"}}function B(e){const r=y(e);if(!r)return!1;if(A(r)||/^<environment_context>[\s\S]*<\/environment_context>$/i.test(r)&&r.includes("<current_date>")&&r.includes("<timezone>")&&r.includes("<workspace_roots>"))return!0;const n=r.startsWith("<recommended_plugins>")&&r.includes("</recommended_plugins>"),t=r.includes("# AGENTS.md instructions for ")&&r.includes("<INSTRUCTIONS>")&&r.includes("</INSTRUCTIONS>"),o=r.includes("<environment_context>")&&r.includes("</environment_context>");return t&&o&&(r.startsWith("# AGENTS.md instructions for ")||n)}function F(e){const r=z(e.text_elements),n=Array.isArray(e.input)?z(e.input):"",t=typeof e.message=="string"?se(e.message):{text:"",strippedWrapper:!1},o=t.text,i=r||n||o,s=t.strippedWrapper?"codex_app_context_wrapper":void 0,a=Array.isArray(e.local_images)?e.local_images.map(R).filter(l=>l!=null):[];return!i&&a.length===0||A(i)&&a.length===0||B(i)&&a.length===0?null:a.length>0?{payload:k(i,a),titleText:i,repairHint:s}:{payload:i,titleText:i,repairHint:s}}function ae(e){return e==="turn_aborted"?"aborted":e==="turn_completed"||e==="turn_complete"||e==="task_complete"?"completed":null}function le(e){return/approval|permission|confirm|user[_-]?input|input[_-]?required/i.test(e)}function me(e){const r=typeof e.command=="string"?e.command:Array.isArray(e.command)?e.command.join(" "):"",n=typeof e.prompt=="string"?e.prompt:typeof e.reason=="string"?e.reason:typeof e.message=="string"?e.message:r?`Codex \u8BF7\u6C42\u6267\u884C\u547D\u4EE4\uFF1A${r}`:"Codex \u6B63\u5728\u7B49\u5F85\u7528\u6237\u786E\u8BA4\u540E\u7EE7\u7EED\u3002";return K({title:"\u9700\u8981\u7528\u6237\u786E\u8BA4",content:n,source:"codex",actionHint:"\u5F53\u524D\u795E\u5FF5\u6682\u4E0D\u652F\u6301\u8FDC\u7A0B\u786E\u8BA4\uFF0C\u8BF7\u56DE\u5230\u8FD0\u884C Codex \u7684\u7535\u8111/\u7EC8\u7AEF\u5B8C\u6210\u786E\u8BA4\u3002"})}function fe(e,r){return Array.isArray(e)?y(e.map(n=>{if(typeof n=="string")return n;if(typeof n!="object"||n===null)return"";const t=n;return t.type!==r?"":typeof t.text=="string"?t.text:""}).filter(Boolean).join(`
2
+
3
+ `)):""}function pe(e){if(!Array.isArray(e))return[];const r=[];for(const n of e){if(typeof n!="object"||n===null)continue;const t=n;if(t.type!=="input_image")continue;const o=R(t);o&&r.push(o)}return r}function J(e){if(e.type!=="message")return null;const r=e.role==="assistant"?"agent":e.role==="user"?"user":null;if(!r)return null;if(r==="agent"){const i=fe(e.content,"output_text");return A(i)?null:i?{role:r,payload:i,titleText:i}:null}const n=ce(e.content),t=n.text,o=[...pe(e.content)];for(const i of n.imagePaths){const s=R(i);s&&(o.some(a=>a.path===s.path)||o.push(s))}return!t&&o.length===0||A(t)&&o.length===0||B(t)&&o.length===0?null:{role:r,payload:o.length>0?k(t,o):t,titleText:t,repairHint:n.strippedWrapper?"codex_app_context_wrapper":void 0}}function G(e){if(!e)return"";try{const r=JSON.parse(e);if(typeof r=="object"&&r!==null){const n=r;if(n.type==="user"&&typeof n.content=="string")return y(n.content)}}catch{}return y(e)}function ge(e,r,n,t){return e.agentType!=="codex"||e.role!==r||L(e.payload)||Math.abs(e.ts-t)>300*1e3?!1:G(e.payload)===G(n)}function N(e,r,n,t){for(let o=e.length-1;o>=0;o-=1){const i=e[o];if(i){if(ge(i,r,n,t))return o;if(i.agentType==="codex"&&Math.abs(i.ts-t)>300*1e3)break}}return-1}function I(e,r,n,t,o,i,s,a,l,c,u="agent",m=!1,p){s&&e.push({agentType:"codex",sourceMode:"codex_rollout_import",sourceSessionKey:o,sourceEventKey:Q(o,n,t),cursor:H(r,n),role:u,ts:i,payload:s,title:a,modelId:l,workDir:c,terminal:m,...m?{terminalState:t==="turn_aborted"?"aborted":t==="error"?"failed":"completed"}:{},repairHint:p})}function C(e,r,n,t,o,i,s,a,l,c,u,m,p){const v=Q(o,n,t),_=typeof p?.callId=="string"&&p.callId.trim()?p.callId.trim():null,x=_?D("sha256").update(`${o}\0${_}`).digest("hex").slice(0,32):null,M=x?`tool:${x}`:void 0,f=x?`native:tool:${x}`:`native:${v}`,T=p?.completed&&x?2:1,g=m!==void 0?"completed":"running";e.push({agentType:"codex",sourceMode:"codex_rollout_import",sourceSessionKey:o,sourceEventKey:v,cursor:H(r,n),role:"agent",ts:i,payload:ee({name:s,toolCallId:f,detailRevision:T,status:g}),title:a,modelId:l,workDir:c,...M?{canonicalMessageKey:M,canonicalMutation:p?.completed?"upsert":"append"}:{},localToolDetail:{toolCallId:f,detailRevision:T,name:s,...u!==void 0?{args:u}:{},...m!==void 0?{result:m}:{},status:g}})}function Q(e,r,n){return`codex:${e}:${r}:${n}`}function de(e,r,n,t,o,i,s,a,l){const c=typeof t.type=="string"?t.type:"";if(c){if(c==="message"){const u=J(t);if(!u||N(e,u.role,u.payload,i)>=0)return;I(e,r,n,`${c}:${u.role}`,o,i,u.payload,s,a,l,u.role,!1,u.repairHint);return}if(c==="function_call"){const u=typeof t.name=="string"?t.name:"function_call";C(e,r,n,c,o,i,u,s,a,l,ne(t.arguments),void 0,{callId:t.call_id});return}if(c==="function_call_output"){const u=ue(t);if(u){I(e,r,n,"delegation:user",o,i,u,s||u.slice(0,80),a,l,"user");return}C(e,r,n,c,o,i,"function_call_output",s,a,l,void 0,t.output,{callId:t.call_id,completed:!0});return}if(c==="custom_tool_call"){const u=typeof t.name=="string"?t.name:"custom_tool_call",m=t.input!==void 0?{input:t.input}:void 0;C(e,r,n,c,o,i,u,s,a,l,m,void 0,{callId:t.call_id});return}if(c==="custom_tool_call_output"){const u=typeof t.name=="string"?t.name:"custom_tool_call_output",m=t.output??t.result??t.content;C(e,r,n,c,o,i,u,s,a,l,void 0,m,{callId:t.call_id,completed:!0});return}if(c==="web_search_call"){const u=typeof t.action=="object"&&t.action!==null?t.action:null;C(e,r,n,c,o,i,"web_search",s,a,l,u??t.query);return}}}function _e(e,r,n,t,o,i,s,a,l){const c=typeof t.type=="string"?t.type:"";if(c){if(c==="user_message"){const u=F(t);if(!u)return;I(e,r,n,c,o,i,u.payload,s,a,l,"user",!1,u.repairHint);return}if(c==="agent_message"){const u=typeof t.message=="string"?y(t.message):"";if(!u||A(u))return;I(e,r,n,c,o,i,u,s,a,l);return}if(c==="turn_aborted"||c==="error"){const u=typeof t.message=="string"?y(t.message):typeof t.error=="string"?y(t.error):"";if(!u)return;I(e,r,n,c,o,i,u,s,a,l,"agent",!0);return}if(le(c)){I(e,r,n,c,o,i,me(t),s,a,l,"agent");return}if(c==="exec_command_end"){const u=Array.isArray(t.command)?t.command:t.parsed_cmd??t.command,m=t.exit_code??t.exitCode,p=[typeof t.aggregated_output=="string"?t.aggregated_output:"",m!=null?`
4
+ (exit ${String(m)})`:""].join("");C(e,r,n,c,o,i,"command_execution",s,a,l,{command:u},p);return}if(c==="patch_apply_end"){C(e,r,n,c,o,i,"apply_patch",s,a,l,t.changes,{success:t.success,stdout:t.stdout,stderr:t.stderr});return}if(c==="mcp_tool_call_end"){const u=typeof t.invocation=="object"&&t.invocation!==null?t.invocation:null,m=typeof u?.tool=="string"?u.tool:"mcp_tool_call",p={server:u?.server,...typeof u?.arguments=="object"&&u.arguments!==null?u.arguments:{}};C(e,r,n,c,o,i,m,s,a,l,p,t.result);return}if(c==="dynamic_tool_call_request"){const u=typeof t.tool=="string"?t.tool:"dynamic_tool_call";C(e,r,n,c,o,i,u,s,a,l,t.arguments,void 0,{callId:t.callId??t.call_id});return}if(c==="dynamic_tool_call_response"){const u=typeof t.tool=="string"?t.tool:"dynamic_tool_call";C(e,r,n,c,o,i,u,s,a,l,void 0,t.result??t.output,{callId:t.callId??t.call_id,completed:!0});return}if(c==="web_search_end"){const u=typeof t.action=="object"&&t.action!==null?t.action:null;C(e,r,n,c,o,i,"web_search",s,a,l,u??t.query,t.query);return}if(c==="image_generation_end"){const u=typeof t.saved_path=="string"?t.saved_path.trim():"";if(!u)return;I(e,r,n,c,o,i,O(u),s,a,l);return}c==="view_image_tool_call"&&C(e,r,n,c,o,i,"view_image",s,a,l,t.path??t.image_path??t)}}function E(e=!1){return{sourceSessionKey:"",workDir:"",modelId:null,title:"",skipImport:e}}function V(e){if((typeof e.thread_source=="string"?e.thread_source.trim().toLowerCase():"")==="subagent")return!0;const n=typeof e.source=="object"&&e.source!==null?e.source:null;if(n&&typeof n.subagent=="object"&&n.subagent!==null)return!0;const t=typeof e.parent_thread_id=="string"&&e.parent_thread_id.trim().length>0,o=typeof e.agent_nickname=="string"||typeof e.agent_role=="string"||typeof e.multi_agent_version=="string";return t&&o}function xe(e){const r=j.openSync(e,"r");try{const n=[];let t=0,o="";for(;t<1024*1024;){const l=Buffer.alloc(16384),c=j.readSync(r,l,0,l.length,t);if(c<=0)break;const u=l.subarray(0,c);n.push(u),t+=c;const m=Buffer.concat(n),p=m.indexOf(10);if(p>=0){o=m.subarray(0,p).toString("utf8");break}}!o&&n.length>0&&(o=Buffer.concat(n).toString("utf8"));const i=W(o);if(!i||i.type!=="session_meta")return E();const s=typeof i.payload=="object"&&i.payload!==null?i.payload:null;if(!s)return E();if(V(s))return E(!0);const a=typeof s.id=="string"?s.id:"";return{sourceSessionKey:a,workDir:typeof s.cwd=="string"?s.cwd:"",modelId:X(s),title:w(a)??"",skipImport:!1}}finally{j.closeSync(r)}return E()}function X(e){return(typeof e.model=="string"?e.model.trim():"")||null}function Y(e,r){const n=[],t=xe(e);let{sourceSessionKey:o,workDir:i,modelId:s,title:a,skipImport:l}=t,c=t.title;if(l||q(i))return{nextOffset:j.statSync(e).size,events:[]};let u=null;const m=new Set,p=(v,_)=>{const x=W(v);if(!x)return;const M=typeof x.type=="string"?x.type:"",f=typeof x.payload=="object"&&x.payload!==null?x.payload:null,T=ie(x.timestamp);if(!(!f||!T)){if(M==="session_meta"){if(V(f)){n.length=0,l=!0;return}if(o=typeof f.id=="string"?f.id:o,i=typeof f.cwd=="string"?f.cwd:i,q(i)){n.length=0,l=!0;return}s=X(f)??s;const g=w(o);g&&(c=g,a=g);return}if(!l&&o){if(M==="response_item"){const g=J(f);g?.role==="user"&&g.titleText&&!a&&(a=g.titleText.slice(0,80)),de(n,e,_,f,o,T,a,s,i);return}if(M==="event_msg"){const g=typeof f.type=="string"?f.type:"",S=ae(g);if(S){let h=!1;for(let b=n.length-1;b>=0;b-=1){const d=n[b];if(d?.agentType==="codex"&&d.role==="agent"&&!L(d.payload)){d.terminal=!0,d.terminalState=S,_>=r&&Number(d.cursor?.slice(e.length+1))<r&&m.add(d.sourceEventKey),h=!0,u=null;break}}if(!h)for(let b=n.length-1;b>=0;b-=1){const d=n[b];if(!(d?.agentType!=="codex"||d.role!=="agent")){d.terminal=!0,d.terminalState=S,_>=r&&Number(d.cursor?.slice(e.length+1))<r&&m.add(d.sourceEventKey),h=!0,u=null;break}}h||(u=S);return}if(g==="user_message"){const h=F(f);if(h?.titleText&&!a&&(a=h.titleText.slice(0,80)),h){const b=N(n,"user",h.payload,T);b>=0&&n.splice(b,1)}}else if(g==="agent_message"){const h=typeof f.message=="string"?y(f.message):"";if(h&&!A(h)){const b=N(n,"agent",h,T);b>=0&&n.splice(b,1)}}const P=n.length;_e(n,e,_,f,o,T,a,s,i),u&&n.length>P&&(n[n.length-1].terminal=!0,n[n.length-1].terminalState=u,u=null)}}}};return{readOffset:te(e,r),onLine:p,finish:v=>{for(const _ of n)_.titleSource=c&&_.title===c?"agent_native":"first_user_fallback";return{nextOffset:v,events:n.filter(_=>m.has(_.sourceEventKey)||Number(_.cursor?.slice(e.length+1))>=r)}}}}function Z(e){return"nextOffset"in e}function Me(e,r){const n=Y(e,r);return Z(n)?n:n.finish(re(e,n.readOffset,n.onLine))}async function Ae(e,r){const n=Y(e,r);return Z(n)?n:n.finish(await oe(e,n.readOffset,n.onLine))}export{Ee as listCodexRolloutFiles,Re as lookupCodexThreadName,Me as parseCodexRolloutChunk,Ae as parseCodexRolloutChunkCooperatively};