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.
- package/README.md +3 -2
- package/dist/bin/shennian.js +1 -1
- package/dist/publish-build-manifest.json +32 -27
- package/dist/src/agents/adapter.js +1 -19
- package/dist/src/agents/claude-managed-permissions.js +1 -248
- package/dist/src/agents/claude.js +8 -393
- package/dist/src/agents/codex-managed-permissions.js +1 -294
- package/dist/src/agents/codex-managed-room-tools.js +1 -249
- package/dist/src/agents/codex-utils.js +7 -200
- package/dist/src/agents/codex.d.ts +7 -1
- package/dist/src/agents/codex.js +17 -1352
- package/dist/src/agents/config-status.js +1 -226
- package/dist/src/agents/cursor-managed-permissions.js +2 -299
- package/dist/src/agents/cursor.js +1 -314
- package/dist/src/agents/custom.js +4 -418
- package/dist/src/agents/external-channel-instructions.js +11 -94
- package/dist/src/agents/gemini.js +1 -180
- package/dist/src/agents/manager.js +18 -250
- package/dist/src/agents/model-registry/cache.js +1 -37
- package/dist/src/agents/model-registry/discovery.js +2 -188
- package/dist/src/agents/model-registry/parsers.js +4 -521
- package/dist/src/agents/model-registry/runner.js +1 -30
- package/dist/src/agents/model-registry/service.js +1 -115
- package/dist/src/agents/model-registry/types.js +1 -8
- package/dist/src/agents/model-registry.js +1 -19
- package/dist/src/agents/native-capabilities.js +1 -237
- package/dist/src/agents/openclaw.js +2 -293
- package/dist/src/agents/opencode-managed-permissions.js +2 -187
- package/dist/src/agents/opencode.js +1 -298
- package/dist/src/agents/platform-instructions.js +17 -46
- package/dist/src/agents/runtime-compatibility.js +1 -44
- package/dist/src/agents/workbuddy-managed-permissions.js +2 -329
- package/dist/src/agents/workbuddy.js +3 -444
- package/dist/src/commands/logout.d.ts +3 -0
- package/dist/src/commands/logout.js +1 -0
- package/dist/src/daemon-ipc/paths.js +1 -1
- package/dist/src/fs/boundary.js +1 -185
- package/dist/src/fs/handler.js +1 -130
- package/dist/src/fs/security.js +1 -32
- package/dist/src/fs/text-decoder.js +1 -110
- package/dist/src/index.js +3 -587
- package/dist/src/manager/prompt.js +29 -34
- package/dist/src/manager/registry.js +1 -317
- package/dist/src/manager/retired-external-channel-compat.js +1 -40
- package/dist/src/manager/runtime.js +23 -1514
- package/dist/src/native-fusion/codex-parser.d.ts +3 -1
- package/dist/src/native-fusion/codex-parser.js +4 -660
- package/dist/src/native-fusion/codex-user-input.js +5 -102
- package/dist/src/native-fusion/config.js +1 -5
- package/dist/src/native-fusion/file-watcher.js +1 -191
- package/dist/src/native-fusion/local-repository.js +2 -569
- package/dist/src/native-fusion/opencode-parser.js +3 -130
- package/dist/src/native-fusion/parser-common.d.ts +6 -1
- package/dist/src/native-fusion/parser-common.js +4 -4
- package/dist/src/native-fusion/parsers.d.ts +4 -2
- package/dist/src/native-fusion/parsers.js +3 -140
- package/dist/src/native-fusion/service.js +2 -739
- package/dist/src/native-fusion/session-header.js +2 -101
- package/dist/src/native-fusion/state.js +2 -104
- package/dist/src/native-fusion/types.js +1 -1
- package/dist/src/personal-sync/machine-authority.js +1 -34
- package/dist/src/room/activation-audit.js +2 -45
- package/dist/src/room/activation-policy.js +1 -30
- package/dist/src/room/activation-service.js +8 -408
- package/dist/src/room/invite-bootstrap.js +1 -156
- package/dist/src/room/managed-prompt-composer.d.ts +1 -1
- package/dist/src/room/managed-prompt-composer.js +17 -16
- package/dist/src/room/managed-room-binding.js +1 -167
- package/dist/src/room/managed-room-ipc.d.ts +4 -0
- package/dist/src/room/managed-room-ipc.js +2 -2
- package/dist/src/room/mirror-sync-service.d.ts +1 -0
- package/dist/src/room/mirror-sync-service.js +1 -183
- package/dist/src/room/room-binding-client.js +1 -151
- package/dist/src/session/archive-zip.js +1 -220
- package/dist/src/session/deletion-sync-state.js +2 -136
- package/dist/src/session/handlers/agent-capabilities.js +1 -14
- package/dist/src/session/handlers/agent-config.js +1 -150
- package/dist/src/session/handlers/agents.js +1 -55
- package/dist/src/session/handlers/chat.js +2 -1030
- package/dist/src/session/handlers/control.js +1 -61
- package/dist/src/session/handlers/fs.js +1 -594
- package/dist/src/session/handlers/message-status.js +1 -15
- package/dist/src/session/handlers/remote-access.js +1 -43
- package/dist/src/session/handlers/room-managed.js +1 -101
- package/dist/src/session/handlers/session-refresh.js +1 -35
- package/dist/src/session/handlers/title.js +1 -79
- package/dist/src/session/handlers/tool-detail.js +1 -149
- package/dist/src/session/handlers/voice-window.js +1 -62
- package/dist/src/session/history-subscriptions.js +1 -470
- package/dist/src/session/manager.d.ts +1 -0
- package/dist/src/session/manager.js +1 -658
- package/dist/src/session/native-cleanup-outbox.js +2 -287
- package/dist/src/session/native-session-lifecycle.js +6 -327
- package/dist/src/session/queue.d.ts +8 -0
- package/dist/src/session/queue.js +6 -6
- package/dist/src/upgrade/scheduler.js +1 -126
- package/node_modules/@shennian/wire/dist/agent-workspace.js +2 -2
- package/package.json +1 -1
|
@@ -1,660 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
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};
|