@bububuger/spanory 0.1.16 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +5143 -1594
- package/package.json +11 -7
- package/dist/alert/evaluate.d.ts +0 -3
- package/dist/alert/evaluate.js +0 -197
- package/dist/env.d.ts +0 -2
- package/dist/env.js +0 -54
- package/dist/issue/state.d.ts +0 -39
- package/dist/issue/state.js +0 -151
- package/dist/otlp.d.ts +0 -5
- package/dist/otlp.js +0 -12
- package/dist/report/aggregate.d.ts +0 -21
- package/dist/report/aggregate.js +0 -245
- package/dist/runtime/claude/adapter.d.ts +0 -18
- package/dist/runtime/claude/adapter.js +0 -222
- package/dist/runtime/codex/adapter.d.ts +0 -18
- package/dist/runtime/codex/adapter.js +0 -493
- package/dist/runtime/codex/proxy.d.ts +0 -9
- package/dist/runtime/codex/proxy.js +0 -212
- package/dist/runtime/openclaw/adapter.d.ts +0 -18
- package/dist/runtime/openclaw/adapter.js +0 -380
- package/dist/runtime/shared/capabilities.d.ts +0 -30
- package/dist/runtime/shared/capabilities.js +0 -39
- package/dist/runtime/shared/file-settle.d.ts +0 -19
- package/dist/runtime/shared/file-settle.js +0 -44
- package/dist/runtime/shared/normalize.d.ts +0 -9
- package/dist/runtime/shared/normalize.js +0 -644
|
@@ -1,493 +0,0 @@
|
|
|
1
|
-
// @ts-nocheck
|
|
2
|
-
import { createHash } from 'node:crypto';
|
|
3
|
-
import { readFile, readdir } from 'node:fs/promises';
|
|
4
|
-
import path from 'node:path';
|
|
5
|
-
import { RUNTIME_CAPABILITIES } from '../shared/capabilities.js';
|
|
6
|
-
import { normalizeTranscriptMessages, pickUsage } from '../shared/normalize.js';
|
|
7
|
-
function parseTimestamp(raw) {
|
|
8
|
-
const date = raw ? new Date(raw) : new Date();
|
|
9
|
-
if (Number.isNaN(date.getTime()))
|
|
10
|
-
return new Date();
|
|
11
|
-
return date;
|
|
12
|
-
}
|
|
13
|
-
function safeJsonParse(raw, fallback = {}) {
|
|
14
|
-
if (typeof raw !== 'string') {
|
|
15
|
-
if (raw && typeof raw === 'object')
|
|
16
|
-
return raw;
|
|
17
|
-
return fallback;
|
|
18
|
-
}
|
|
19
|
-
try {
|
|
20
|
-
const parsed = JSON.parse(raw);
|
|
21
|
-
if (parsed && typeof parsed === 'object')
|
|
22
|
-
return parsed;
|
|
23
|
-
}
|
|
24
|
-
catch {
|
|
25
|
-
// ignore parse errors
|
|
26
|
-
}
|
|
27
|
-
return fallback;
|
|
28
|
-
}
|
|
29
|
-
function normalizeToolCall(name, args, index) {
|
|
30
|
-
const normalizedName = String(name ?? '').trim();
|
|
31
|
-
const shellTools = new Set(['exec_command', 'shell_command', 'write_stdin']);
|
|
32
|
-
const agentTaskTools = new Set(['spawn_agent', 'wait', 'close_agent']);
|
|
33
|
-
if (shellTools.has(normalizedName)) {
|
|
34
|
-
const command = String(args.command ?? args.cmd ?? args.chars ?? '').trim();
|
|
35
|
-
return {
|
|
36
|
-
toolName: 'Bash',
|
|
37
|
-
input: command ? { command } : args,
|
|
38
|
-
callId: `call-shell-${index}`,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
if (agentTaskTools.has(normalizedName)) {
|
|
42
|
-
return {
|
|
43
|
-
toolName: 'Task',
|
|
44
|
-
input: { name: normalizedName, ...args },
|
|
45
|
-
callId: `call-task-${index}`,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
return {
|
|
49
|
-
toolName: normalizedName || 'tool',
|
|
50
|
-
input: args,
|
|
51
|
-
callId: `call-tool-${index}`,
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
function sanitizeProjectBase(name) {
|
|
55
|
-
const text = String(name ?? '').trim();
|
|
56
|
-
if (!text)
|
|
57
|
-
return 'codex';
|
|
58
|
-
const out = text.replace(/[^a-zA-Z0-9._-]+/g, '-').replace(/^-+|-+$/g, '').toLowerCase();
|
|
59
|
-
return out || 'codex';
|
|
60
|
-
}
|
|
61
|
-
function deriveProjectIdFromCwd(cwd) {
|
|
62
|
-
const base = sanitizeProjectBase(path.basename(String(cwd ?? '').trim()) || 'codex');
|
|
63
|
-
const hash = createHash('sha1').update(String(cwd ?? '')).digest('hex').slice(0, 6);
|
|
64
|
-
return `${base}-${hash}`;
|
|
65
|
-
}
|
|
66
|
-
function usageFromTotals(start, end) {
|
|
67
|
-
if (!start || !end)
|
|
68
|
-
return undefined;
|
|
69
|
-
const input = Math.max(0, Number(end.input_tokens ?? 0) - Number(start.input_tokens ?? 0));
|
|
70
|
-
const output = Math.max(0, Number(end.output_tokens ?? 0) - Number(start.output_tokens ?? 0));
|
|
71
|
-
const total = Math.max(0, Number(end.total_tokens ?? 0) - Number(start.total_tokens ?? 0));
|
|
72
|
-
if (input === 0 && output === 0 && total === 0)
|
|
73
|
-
return undefined;
|
|
74
|
-
return pickUsage({
|
|
75
|
-
input_tokens: input,
|
|
76
|
-
output_tokens: output,
|
|
77
|
-
total_tokens: total || input + output,
|
|
78
|
-
});
|
|
79
|
-
}
|
|
80
|
-
function extractPtySessionId(output) {
|
|
81
|
-
const text = String(output ?? '');
|
|
82
|
-
const match = text.match(/session ID\s+(\d+)/i);
|
|
83
|
-
return match ? match[1] : undefined;
|
|
84
|
-
}
|
|
85
|
-
function extractWallTimeMs(output) {
|
|
86
|
-
const text = String(output ?? '');
|
|
87
|
-
const match = text.match(/Wall time:\s*([0-9]+(?:\.[0-9]+)?)\s*seconds?/i);
|
|
88
|
-
if (!match)
|
|
89
|
-
return undefined;
|
|
90
|
-
const seconds = Number(match[1]);
|
|
91
|
-
if (!Number.isFinite(seconds) || seconds <= 0)
|
|
92
|
-
return undefined;
|
|
93
|
-
return Math.floor(seconds * 1000);
|
|
94
|
-
}
|
|
95
|
-
function createTurn(turnId, startedAt) {
|
|
96
|
-
return {
|
|
97
|
-
turnId,
|
|
98
|
-
startedAt,
|
|
99
|
-
endedAt: startedAt,
|
|
100
|
-
completed: false,
|
|
101
|
-
userInput: '',
|
|
102
|
-
lastAgentMessage: '',
|
|
103
|
-
model: undefined,
|
|
104
|
-
cwd: undefined,
|
|
105
|
-
calls: [],
|
|
106
|
-
lastUsage: undefined,
|
|
107
|
-
totalUsageStart: undefined,
|
|
108
|
-
totalUsageEnd: undefined,
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
async function findSessionTranscript(sessionsRoot, sessionId) {
|
|
112
|
-
const targetName = `${sessionId}.jsonl`;
|
|
113
|
-
const stack = [sessionsRoot];
|
|
114
|
-
while (stack.length > 0) {
|
|
115
|
-
const dir = stack.pop();
|
|
116
|
-
let entries = [];
|
|
117
|
-
try {
|
|
118
|
-
entries = await readdir(dir, { withFileTypes: true });
|
|
119
|
-
}
|
|
120
|
-
catch {
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
for (const entry of entries) {
|
|
124
|
-
const full = path.join(dir, entry.name);
|
|
125
|
-
if (entry.isDirectory()) {
|
|
126
|
-
stack.push(full);
|
|
127
|
-
continue;
|
|
128
|
-
}
|
|
129
|
-
if (entry.isFile() && entry.name === targetName) {
|
|
130
|
-
return full;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
throw new Error(`codex session transcript not found: ${targetName} under ${sessionsRoot}`);
|
|
135
|
-
}
|
|
136
|
-
function toIso(timestamp) {
|
|
137
|
-
return parseTimestamp(timestamp).toISOString();
|
|
138
|
-
}
|
|
139
|
-
function buildMessagesFromTurns(turns, runtimeVersion) {
|
|
140
|
-
const messages = [];
|
|
141
|
-
for (const turn of turns) {
|
|
142
|
-
const input = String(turn.userInput ?? '').trim() || '(no user message captured)';
|
|
143
|
-
messages.push({
|
|
144
|
-
role: 'user',
|
|
145
|
-
isMeta: false,
|
|
146
|
-
content: input,
|
|
147
|
-
runtimeVersion,
|
|
148
|
-
messageId: `${turn.turnId}:user`,
|
|
149
|
-
timestamp: parseTimestamp(turn.startedAt),
|
|
150
|
-
});
|
|
151
|
-
for (let i = 0; i < turn.calls.length; i += 1) {
|
|
152
|
-
const call = turn.calls[i];
|
|
153
|
-
const callId = String(call.callId ?? `call-${i + 1}`);
|
|
154
|
-
messages.push({
|
|
155
|
-
role: 'assistant',
|
|
156
|
-
isMeta: false,
|
|
157
|
-
content: [
|
|
158
|
-
{
|
|
159
|
-
type: 'tool_use',
|
|
160
|
-
id: callId,
|
|
161
|
-
name: call.toolName,
|
|
162
|
-
input: call.input ?? {},
|
|
163
|
-
},
|
|
164
|
-
],
|
|
165
|
-
model: turn.model,
|
|
166
|
-
runtimeVersion,
|
|
167
|
-
messageId: `${turn.turnId}:tool-use:${i + 1}`,
|
|
168
|
-
timestamp: parseTimestamp(call.startedAt ?? turn.startedAt),
|
|
169
|
-
});
|
|
170
|
-
messages.push({
|
|
171
|
-
role: 'user',
|
|
172
|
-
isMeta: false,
|
|
173
|
-
content: [
|
|
174
|
-
{
|
|
175
|
-
type: 'tool_result',
|
|
176
|
-
tool_use_id: callId,
|
|
177
|
-
content: String(call.output ?? ''),
|
|
178
|
-
},
|
|
179
|
-
],
|
|
180
|
-
sourceToolUseId: callId,
|
|
181
|
-
toolUseResult: {
|
|
182
|
-
stdout: String(call.output ?? ''),
|
|
183
|
-
},
|
|
184
|
-
runtimeVersion,
|
|
185
|
-
messageId: `${turn.turnId}:tool-result:${i + 1}`,
|
|
186
|
-
timestamp: parseTimestamp(call.endedAt ?? call.startedAt ?? turn.endedAt),
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
messages.push({
|
|
190
|
-
role: 'assistant',
|
|
191
|
-
isMeta: false,
|
|
192
|
-
content: [{ type: 'text', text: String(turn.lastAgentMessage ?? '') }],
|
|
193
|
-
model: turn.model,
|
|
194
|
-
usage: turn.lastUsage ?? usageFromTotals(turn.totalUsageStart, turn.totalUsageEnd),
|
|
195
|
-
runtimeVersion,
|
|
196
|
-
messageId: `${turn.turnId}:assistant`,
|
|
197
|
-
timestamp: parseTimestamp(turn.endedAt),
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
messages.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
201
|
-
return messages;
|
|
202
|
-
}
|
|
203
|
-
async function readCodexSession(transcriptPath) {
|
|
204
|
-
const raw = await readFile(transcriptPath, 'utf-8');
|
|
205
|
-
const lines = raw.split('\n').map((line) => line.trim()).filter(Boolean);
|
|
206
|
-
const turns = [];
|
|
207
|
-
let currentTurn = null;
|
|
208
|
-
let pendingUserInput = '';
|
|
209
|
-
let sessionMeta = null;
|
|
210
|
-
let callCounter = 0;
|
|
211
|
-
const callIndex = new Map();
|
|
212
|
-
const ptyCallBySession = new Map();
|
|
213
|
-
function finalizeCurrentTurn(at) {
|
|
214
|
-
if (!currentTurn)
|
|
215
|
-
return;
|
|
216
|
-
currentTurn.endedAt = at ? toIso(at) : currentTurn.endedAt;
|
|
217
|
-
turns.push(currentTurn);
|
|
218
|
-
currentTurn = null;
|
|
219
|
-
}
|
|
220
|
-
function ensureCurrentTurn(at) {
|
|
221
|
-
if (currentTurn)
|
|
222
|
-
return currentTurn;
|
|
223
|
-
currentTurn = createTurn(`turn-codex-${turns.length + 1}`, toIso(at));
|
|
224
|
-
if (pendingUserInput) {
|
|
225
|
-
currentTurn.userInput = pendingUserInput;
|
|
226
|
-
pendingUserInput = '';
|
|
227
|
-
}
|
|
228
|
-
return currentTurn;
|
|
229
|
-
}
|
|
230
|
-
for (const line of lines) {
|
|
231
|
-
let entry;
|
|
232
|
-
try {
|
|
233
|
-
entry = JSON.parse(line);
|
|
234
|
-
}
|
|
235
|
-
catch {
|
|
236
|
-
continue;
|
|
237
|
-
}
|
|
238
|
-
const isoAt = toIso(entry.timestamp);
|
|
239
|
-
if (entry.type === 'session_meta') {
|
|
240
|
-
sessionMeta = entry.payload ?? {};
|
|
241
|
-
continue;
|
|
242
|
-
}
|
|
243
|
-
if (entry.type === 'turn_context') {
|
|
244
|
-
const turn = ensureCurrentTurn(entry.timestamp);
|
|
245
|
-
const payload = entry.payload ?? {};
|
|
246
|
-
if (payload.turn_id && turn.turnId.startsWith('turn-codex-')) {
|
|
247
|
-
turn.turnId = payload.turn_id;
|
|
248
|
-
}
|
|
249
|
-
if (payload.model)
|
|
250
|
-
turn.model = payload.model;
|
|
251
|
-
if (payload.cwd)
|
|
252
|
-
turn.cwd = payload.cwd;
|
|
253
|
-
continue;
|
|
254
|
-
}
|
|
255
|
-
if (entry.type === 'event_msg') {
|
|
256
|
-
const payload = entry.payload ?? {};
|
|
257
|
-
if (payload.type === 'task_started') {
|
|
258
|
-
finalizeCurrentTurn(entry.timestamp);
|
|
259
|
-
currentTurn = createTurn(payload.turn_id ?? `turn-codex-${turns.length + 1}`, isoAt);
|
|
260
|
-
if (pendingUserInput) {
|
|
261
|
-
currentTurn.userInput = pendingUserInput;
|
|
262
|
-
pendingUserInput = '';
|
|
263
|
-
}
|
|
264
|
-
continue;
|
|
265
|
-
}
|
|
266
|
-
if (payload.type === 'user_message') {
|
|
267
|
-
const text = String(payload.message ?? '').trim();
|
|
268
|
-
if (!text)
|
|
269
|
-
continue;
|
|
270
|
-
if (currentTurn && !currentTurn.userInput) {
|
|
271
|
-
currentTurn.userInput = text;
|
|
272
|
-
}
|
|
273
|
-
else {
|
|
274
|
-
pendingUserInput = text;
|
|
275
|
-
}
|
|
276
|
-
continue;
|
|
277
|
-
}
|
|
278
|
-
if (payload.type === 'token_count') {
|
|
279
|
-
const turn = ensureCurrentTurn(entry.timestamp);
|
|
280
|
-
const info = payload.info ?? {};
|
|
281
|
-
const lastUsage = pickUsage(info.last_token_usage ?? info.lastTokenUsage);
|
|
282
|
-
if (lastUsage) {
|
|
283
|
-
turn.lastUsage = lastUsage;
|
|
284
|
-
}
|
|
285
|
-
const totalUsage = pickUsage(info.total_token_usage ?? info.totalTokenUsage);
|
|
286
|
-
if (totalUsage) {
|
|
287
|
-
if (!turn.totalUsageStart)
|
|
288
|
-
turn.totalUsageStart = totalUsage;
|
|
289
|
-
turn.totalUsageEnd = totalUsage;
|
|
290
|
-
}
|
|
291
|
-
continue;
|
|
292
|
-
}
|
|
293
|
-
if (payload.type === 'agent_message') {
|
|
294
|
-
const turn = ensureCurrentTurn(entry.timestamp);
|
|
295
|
-
if (payload.phase === 'final_answer') {
|
|
296
|
-
turn.lastAgentMessage = String(payload.message ?? turn.lastAgentMessage ?? '');
|
|
297
|
-
}
|
|
298
|
-
continue;
|
|
299
|
-
}
|
|
300
|
-
if (payload.type === 'task_complete' || payload.type === 'turn_aborted') {
|
|
301
|
-
const turn = ensureCurrentTurn(entry.timestamp);
|
|
302
|
-
if (payload.turn_id)
|
|
303
|
-
turn.turnId = payload.turn_id;
|
|
304
|
-
if (payload.last_agent_message) {
|
|
305
|
-
turn.lastAgentMessage = String(payload.last_agent_message);
|
|
306
|
-
}
|
|
307
|
-
turn.completed = true;
|
|
308
|
-
turn.endedAt = isoAt;
|
|
309
|
-
finalizeCurrentTurn(entry.timestamp);
|
|
310
|
-
continue;
|
|
311
|
-
}
|
|
312
|
-
continue;
|
|
313
|
-
}
|
|
314
|
-
if (entry.type !== 'response_item')
|
|
315
|
-
continue;
|
|
316
|
-
const payload = entry.payload ?? {};
|
|
317
|
-
if (payload.type === 'message' && payload.role === 'assistant' && Array.isArray(payload.content)) {
|
|
318
|
-
const turn = ensureCurrentTurn(entry.timestamp);
|
|
319
|
-
const text = payload.content
|
|
320
|
-
.map((block) => {
|
|
321
|
-
if (block?.type === 'output_text' || block?.type === 'input_text')
|
|
322
|
-
return String(block.text ?? '');
|
|
323
|
-
if (typeof block?.text === 'string')
|
|
324
|
-
return block.text;
|
|
325
|
-
if (typeof block?.output_text === 'string')
|
|
326
|
-
return block.output_text;
|
|
327
|
-
return '';
|
|
328
|
-
})
|
|
329
|
-
.filter(Boolean)
|
|
330
|
-
.join('\n')
|
|
331
|
-
.trim();
|
|
332
|
-
if (text)
|
|
333
|
-
turn.lastAgentMessage = text;
|
|
334
|
-
continue;
|
|
335
|
-
}
|
|
336
|
-
if (payload.type === 'function_call' || payload.type === 'custom_tool_call') {
|
|
337
|
-
const turn = ensureCurrentTurn(entry.timestamp);
|
|
338
|
-
callCounter += 1;
|
|
339
|
-
const rawName = payload.name ?? payload.tool_name ?? payload.toolName;
|
|
340
|
-
const rawInput = payload.type === 'custom_tool_call' ? payload.input : payload.arguments;
|
|
341
|
-
const args = safeJsonParse(rawInput, typeof rawInput === 'string' ? { raw: rawInput } : {});
|
|
342
|
-
const ptySessionId = args.session_id != null ? String(args.session_id) : '';
|
|
343
|
-
if (String(rawName ?? '') === 'write_stdin' && ptySessionId && ptyCallBySession.has(ptySessionId)) {
|
|
344
|
-
callIndex.set(String(payload.call_id ?? payload.callId ?? `call-${callCounter}`), ptyCallBySession.get(ptySessionId));
|
|
345
|
-
continue;
|
|
346
|
-
}
|
|
347
|
-
const normalized = normalizeToolCall(rawName, args, callCounter);
|
|
348
|
-
const callId = String(payload.call_id ?? payload.callId ?? normalized.callId ?? `call-${callCounter}`);
|
|
349
|
-
const call = {
|
|
350
|
-
callId,
|
|
351
|
-
toolName: normalized.toolName,
|
|
352
|
-
input: normalized.input,
|
|
353
|
-
output: '',
|
|
354
|
-
startedAt: isoAt,
|
|
355
|
-
endedAt: isoAt,
|
|
356
|
-
};
|
|
357
|
-
turn.calls.push(call);
|
|
358
|
-
callIndex.set(callId, call);
|
|
359
|
-
continue;
|
|
360
|
-
}
|
|
361
|
-
if (payload.type === 'function_call_output' || payload.type === 'custom_tool_call_output') {
|
|
362
|
-
const callId = String(payload.call_id ?? payload.callId ?? '');
|
|
363
|
-
const call = callIndex.get(callId);
|
|
364
|
-
if (call) {
|
|
365
|
-
const output = String(payload.output ?? '');
|
|
366
|
-
if (output)
|
|
367
|
-
call.output = output;
|
|
368
|
-
call.endedAt = isoAt;
|
|
369
|
-
const wallTimeMs = extractWallTimeMs(output);
|
|
370
|
-
if (wallTimeMs) {
|
|
371
|
-
const derivedEndedAt = new Date(parseTimestamp(call.startedAt).getTime() + wallTimeMs).toISOString();
|
|
372
|
-
if (parseTimestamp(derivedEndedAt).getTime() > parseTimestamp(call.endedAt).getTime()) {
|
|
373
|
-
call.endedAt = derivedEndedAt;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
if (call.toolName === 'Bash') {
|
|
377
|
-
const ptySessionId = extractPtySessionId(output);
|
|
378
|
-
if (ptySessionId)
|
|
379
|
-
ptyCallBySession.set(ptySessionId, call);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
continue;
|
|
383
|
-
}
|
|
384
|
-
if (payload.type === 'web_search_call') {
|
|
385
|
-
const turn = ensureCurrentTurn(entry.timestamp);
|
|
386
|
-
callCounter += 1;
|
|
387
|
-
const call = {
|
|
388
|
-
callId: `call-web-search-${callCounter}`,
|
|
389
|
-
toolName: 'WebSearch',
|
|
390
|
-
input: payload.action ?? {},
|
|
391
|
-
output: JSON.stringify({
|
|
392
|
-
status: payload.status ?? 'unknown',
|
|
393
|
-
query: payload.action?.query ?? '',
|
|
394
|
-
}),
|
|
395
|
-
startedAt: isoAt,
|
|
396
|
-
endedAt: isoAt,
|
|
397
|
-
};
|
|
398
|
-
turn.calls.push(call);
|
|
399
|
-
continue;
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
finalizeCurrentTurn(new Date().toISOString());
|
|
403
|
-
const runtimeVersion = String(sessionMeta?.cli_version ?? '').trim() || undefined;
|
|
404
|
-
const cwd = String(sessionMeta?.cwd ?? '').trim() || undefined;
|
|
405
|
-
return {
|
|
406
|
-
turns,
|
|
407
|
-
runtimeVersion,
|
|
408
|
-
cwd,
|
|
409
|
-
};
|
|
410
|
-
}
|
|
411
|
-
function remapTurnIds(events, turns) {
|
|
412
|
-
const generatedTurnIds = events
|
|
413
|
-
.filter((event) => event.category === 'turn')
|
|
414
|
-
.map((event) => event.turnId);
|
|
415
|
-
const map = new Map();
|
|
416
|
-
for (let i = 0; i < generatedTurnIds.length; i += 1) {
|
|
417
|
-
const generated = generatedTurnIds[i];
|
|
418
|
-
const rawTurnId = turns[i]?.turnId;
|
|
419
|
-
if (generated && rawTurnId)
|
|
420
|
-
map.set(generated, rawTurnId);
|
|
421
|
-
}
|
|
422
|
-
return events.map((event) => {
|
|
423
|
-
const mappedTurnId = map.get(event.turnId);
|
|
424
|
-
if (!mappedTurnId)
|
|
425
|
-
return event;
|
|
426
|
-
return {
|
|
427
|
-
...event,
|
|
428
|
-
turnId: mappedTurnId,
|
|
429
|
-
name: event.category === 'turn' ? `codex - Turn ${mappedTurnId}` : event.name,
|
|
430
|
-
};
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
function attachCwdAttribute(events, cwd) {
|
|
434
|
-
if (!cwd)
|
|
435
|
-
return events;
|
|
436
|
-
const sanitizedCwd = deriveProjectIdFromCwd(cwd);
|
|
437
|
-
return events.map((event) => ({
|
|
438
|
-
...event,
|
|
439
|
-
attributes: {
|
|
440
|
-
...(event.attributes ?? {}),
|
|
441
|
-
'agentic.project.cwd': sanitizedCwd,
|
|
442
|
-
},
|
|
443
|
-
}));
|
|
444
|
-
}
|
|
445
|
-
function attachTurnCompletionAttribute(events, turns) {
|
|
446
|
-
const completionByTurnId = new Map(turns.map((turn) => [turn.turnId, Boolean(turn.completed)]));
|
|
447
|
-
return events.map((event) => {
|
|
448
|
-
if (event.category !== 'turn')
|
|
449
|
-
return event;
|
|
450
|
-
return {
|
|
451
|
-
...event,
|
|
452
|
-
attributes: {
|
|
453
|
-
...(event.attributes ?? {}),
|
|
454
|
-
'agentic.turn.completed': completionByTurnId.get(event.turnId) ?? false,
|
|
455
|
-
},
|
|
456
|
-
};
|
|
457
|
-
});
|
|
458
|
-
}
|
|
459
|
-
function resolveRuntimeHome(context) {
|
|
460
|
-
return context.runtimeHome ?? process.env.SPANORY_CODEX_HOME ?? path.join(process.env.HOME || '', '.codex');
|
|
461
|
-
}
|
|
462
|
-
export const codexAdapter = {
|
|
463
|
-
runtimeName: 'codex',
|
|
464
|
-
capabilities: RUNTIME_CAPABILITIES.codex,
|
|
465
|
-
resolveContextFromHook(payload) {
|
|
466
|
-
const sessionId = payload.sessionId;
|
|
467
|
-
if (!sessionId)
|
|
468
|
-
return null;
|
|
469
|
-
const projectId = payload.cwd ? deriveProjectIdFromCwd(payload.cwd) : 'codex';
|
|
470
|
-
return {
|
|
471
|
-
projectId,
|
|
472
|
-
sessionId,
|
|
473
|
-
...(payload.transcriptPath ? { transcriptPath: payload.transcriptPath } : {}),
|
|
474
|
-
};
|
|
475
|
-
},
|
|
476
|
-
async collectEvents(context) {
|
|
477
|
-
const runtimeHome = resolveRuntimeHome(context);
|
|
478
|
-
const transcriptPath = context.transcriptPath
|
|
479
|
-
?? await findSessionTranscript(path.join(runtimeHome, 'sessions'), context.sessionId);
|
|
480
|
-
const parsed = await readCodexSession(transcriptPath);
|
|
481
|
-
const projectId = context.projectId || deriveProjectIdFromCwd(parsed.cwd ?? '');
|
|
482
|
-
const messages = buildMessagesFromTurns(parsed.turns, parsed.runtimeVersion);
|
|
483
|
-
const normalized = normalizeTranscriptMessages({
|
|
484
|
-
runtime: 'codex',
|
|
485
|
-
projectId,
|
|
486
|
-
sessionId: context.sessionId,
|
|
487
|
-
messages,
|
|
488
|
-
});
|
|
489
|
-
const withRawTurnIds = remapTurnIds(normalized, parsed.turns);
|
|
490
|
-
const withCompletion = attachTurnCompletionAttribute(withRawTurnIds, parsed.turns);
|
|
491
|
-
return attachCwdAttribute(withCompletion, parsed.cwd);
|
|
492
|
-
},
|
|
493
|
-
};
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export declare function createCodexProxyServer(options: any): {
|
|
2
|
-
start({ host, port }?: {
|
|
3
|
-
host?: string;
|
|
4
|
-
port?: number;
|
|
5
|
-
}): Promise<void>;
|
|
6
|
-
stop(): Promise<void>;
|
|
7
|
-
url(): string;
|
|
8
|
-
server: import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>;
|
|
9
|
-
};
|