@supen-ai/cli 1.3.3 → 1.3.4
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 +1 -1
- package/daemon/dist/agent-sdk/driver-output-ui.d.ts +1 -1
- package/daemon/dist/agent-sdk/driver-output-ui.d.ts.map +1 -1
- package/daemon/dist/agent-sdk/driver-output-ui.js +10 -275
- package/daemon/dist/agent-sdk/driver-output-ui.js.map +1 -1
- package/daemon/dist/core/cortex.d.ts.map +1 -1
- package/daemon/dist/core/cortex.js +0 -17
- package/daemon/dist/core/cortex.js.map +1 -1
- package/daemon/dist/core/thread-runtime-state.d.ts.map +1 -1
- package/daemon/dist/core/thread-runtime-state.js +1 -37
- package/daemon/dist/core/thread-runtime-state.js.map +1 -1
- package/daemon/dist/http/routes/system.d.ts.map +1 -1
- package/daemon/dist/http/routes/system.js +71 -354
- package/daemon/dist/http/routes/system.js.map +1 -1
- package/daemon/package.json +1 -1
- package/dist/computer.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -31,10 +31,6 @@ const MIRRORED_THREAD_LIMIT = 80;
|
|
|
31
31
|
const MIRRORED_THREAD_HISTORY_LIMIT = 100;
|
|
32
32
|
const MIRRORED_THREAD_HISTORY_MAX_BYTES = 64 * 1024 * 1024;
|
|
33
33
|
const MIRRORED_THREAD_TEXT_LIMIT = 48_000;
|
|
34
|
-
const MIRRORED_THREAD_TOOL_STRING_LIMIT = 24_000;
|
|
35
|
-
const MIRRORED_THREAD_OBJECT_DEPTH_LIMIT = 4;
|
|
36
|
-
const MIRRORED_THREAD_OBJECT_KEY_LIMIT = 80;
|
|
37
|
-
const MIRRORED_THREAD_OBJECT_ARRAY_LIMIT = 80;
|
|
38
34
|
const MIRRORED_THREAD_INLINE_DATA_URL_LIMIT = 120_000;
|
|
39
35
|
const MIRRORED_THREAD_STREAM_REPLAY_LIMIT = 500;
|
|
40
36
|
const MIRRORED_THREAD_STREAM_REPLAY_MAX_BYTES = 8 * 1024 * 1024;
|
|
@@ -44,7 +40,7 @@ const require = createRequire(import.meta.url);
|
|
|
44
40
|
const HOST_DAEMON_INSTALL_DIR = path.join(SUPEN_HOME, 'daemon');
|
|
45
41
|
const HOST_DAEMON_CLI_PACKAGE_ROOT = path.join(HOST_DAEMON_INSTALL_DIR, 'node_modules', '@supen-ai', 'cli');
|
|
46
42
|
const HOST_DAEMON_BIN_PATH = path.join(HOST_DAEMON_CLI_PACKAGE_ROOT, 'daemon', 'scripts', 'supen-daemon.js');
|
|
47
|
-
const HOST_DAEMON_PACKAGE_SPEC = '@supen-ai/cli';
|
|
43
|
+
const HOST_DAEMON_PACKAGE_SPEC = '@supen-ai/cli@latest';
|
|
48
44
|
function readSqliteRows(dbPath, query) {
|
|
49
45
|
try {
|
|
50
46
|
const { DatabaseSync } = require('node:sqlite');
|
|
@@ -953,34 +949,6 @@ function truncateMirroredHistoryString(value, limit, label) {
|
|
|
953
949
|
const omitted = value.length - limit;
|
|
954
950
|
return `${value.slice(0, limit)}\n\n[${label} truncated: ${omitted.toLocaleString()} more characters omitted]`;
|
|
955
951
|
}
|
|
956
|
-
function sanitizeMirroredHistoryPayload(value, depth = 0) {
|
|
957
|
-
if (typeof value === 'string') {
|
|
958
|
-
return truncateMirroredHistoryString(value, MIRRORED_THREAD_TOOL_STRING_LIMIT, 'Tool output');
|
|
959
|
-
}
|
|
960
|
-
if (value === null || typeof value !== 'object')
|
|
961
|
-
return value;
|
|
962
|
-
if (depth >= MIRRORED_THREAD_OBJECT_DEPTH_LIMIT) {
|
|
963
|
-
return Array.isArray(value) ? '[Nested array omitted]' : '[Nested object omitted]';
|
|
964
|
-
}
|
|
965
|
-
if (Array.isArray(value)) {
|
|
966
|
-
const visibleItems = value
|
|
967
|
-
.slice(0, MIRRORED_THREAD_OBJECT_ARRAY_LIMIT)
|
|
968
|
-
.map((item) => sanitizeMirroredHistoryPayload(item, depth + 1));
|
|
969
|
-
if (value.length > MIRRORED_THREAD_OBJECT_ARRAY_LIMIT) {
|
|
970
|
-
visibleItems.push(`[${value.length - MIRRORED_THREAD_OBJECT_ARRAY_LIMIT} more items omitted]`);
|
|
971
|
-
}
|
|
972
|
-
return visibleItems;
|
|
973
|
-
}
|
|
974
|
-
const result = {};
|
|
975
|
-
const entries = Object.entries(value);
|
|
976
|
-
for (const [key, entryValue] of entries.slice(0, MIRRORED_THREAD_OBJECT_KEY_LIMIT)) {
|
|
977
|
-
result[key] = sanitizeMirroredHistoryPayload(entryValue, depth + 1);
|
|
978
|
-
}
|
|
979
|
-
if (entries.length > MIRRORED_THREAD_OBJECT_KEY_LIMIT) {
|
|
980
|
-
result.__truncated_keys = `${entries.length - MIRRORED_THREAD_OBJECT_KEY_LIMIT} more keys omitted`;
|
|
981
|
-
}
|
|
982
|
-
return result;
|
|
983
|
-
}
|
|
984
952
|
function safeMirroredHistoryAttachmentUrl(url) {
|
|
985
953
|
const trimmed = url.trim();
|
|
986
954
|
if (trimmed.startsWith('data:') &&
|
|
@@ -1088,111 +1056,6 @@ function isMirroredGoalContextMessage(text) {
|
|
|
1088
1056
|
const trimmed = text.trim();
|
|
1089
1057
|
return trimmed.startsWith('<goal_context>') && trimmed.endsWith('</goal_context>');
|
|
1090
1058
|
}
|
|
1091
|
-
function parseJsonObject(value) {
|
|
1092
|
-
if (typeof value !== 'string')
|
|
1093
|
-
return value;
|
|
1094
|
-
try {
|
|
1095
|
-
return JSON.parse(value);
|
|
1096
|
-
}
|
|
1097
|
-
catch {
|
|
1098
|
-
return value;
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
function readableOutputFromMcpResult(result) {
|
|
1102
|
-
if (!result || typeof result !== 'object')
|
|
1103
|
-
return result;
|
|
1104
|
-
const ok = result.Ok;
|
|
1105
|
-
const error = result.Err;
|
|
1106
|
-
const payload = ok && typeof ok === 'object' ? ok : error;
|
|
1107
|
-
if (!payload || typeof payload !== 'object')
|
|
1108
|
-
return result;
|
|
1109
|
-
const content = payload.content;
|
|
1110
|
-
if (!Array.isArray(content))
|
|
1111
|
-
return payload;
|
|
1112
|
-
const text = content
|
|
1113
|
-
.map((entry) => {
|
|
1114
|
-
if (typeof entry === 'string')
|
|
1115
|
-
return entry;
|
|
1116
|
-
if (entry && typeof entry === 'object' && typeof entry.text === 'string') {
|
|
1117
|
-
return entry.text;
|
|
1118
|
-
}
|
|
1119
|
-
return '';
|
|
1120
|
-
})
|
|
1121
|
-
.filter(Boolean)
|
|
1122
|
-
.join('\n');
|
|
1123
|
-
return text || payload;
|
|
1124
|
-
}
|
|
1125
|
-
function fileNameFromPath(value) {
|
|
1126
|
-
const trimmed = value.trim();
|
|
1127
|
-
if (!trimmed)
|
|
1128
|
-
return '';
|
|
1129
|
-
return path.basename(trimmed);
|
|
1130
|
-
}
|
|
1131
|
-
function displayPatchPath(filePath, workspacePath) {
|
|
1132
|
-
const trimmed = filePath.trim();
|
|
1133
|
-
if (!trimmed || !workspacePath || !path.isAbsolute(trimmed))
|
|
1134
|
-
return trimmed;
|
|
1135
|
-
const relativePath = path.relative(workspacePath, trimmed);
|
|
1136
|
-
if (!relativePath || relativePath.startsWith('..') || path.isAbsolute(relativePath))
|
|
1137
|
-
return trimmed;
|
|
1138
|
-
return relativePath;
|
|
1139
|
-
}
|
|
1140
|
-
function diffStatsFromText(value) {
|
|
1141
|
-
let additions = 0;
|
|
1142
|
-
let deletions = 0;
|
|
1143
|
-
for (const line of value.split(/\r?\n/)) {
|
|
1144
|
-
if (line.startsWith('+++') || line.startsWith('---'))
|
|
1145
|
-
continue;
|
|
1146
|
-
if (line.startsWith('+'))
|
|
1147
|
-
additions += 1;
|
|
1148
|
-
if (line.startsWith('-'))
|
|
1149
|
-
deletions += 1;
|
|
1150
|
-
}
|
|
1151
|
-
return { additions, deletions };
|
|
1152
|
-
}
|
|
1153
|
-
function extractPatchFiles(input) {
|
|
1154
|
-
if (typeof input !== 'string')
|
|
1155
|
-
return [];
|
|
1156
|
-
const files = [];
|
|
1157
|
-
const seen = new Set();
|
|
1158
|
-
for (const line of input.split(/\r?\n/)) {
|
|
1159
|
-
const match = line.match(/^\*\*\* (?:Update|Add|Delete) File:\s+(.+?)\s*$/);
|
|
1160
|
-
if (!match)
|
|
1161
|
-
continue;
|
|
1162
|
-
const filePath = match[1]?.trim();
|
|
1163
|
-
if (!filePath || seen.has(filePath))
|
|
1164
|
-
continue;
|
|
1165
|
-
seen.add(filePath);
|
|
1166
|
-
files.push({ path: filePath, name: fileNameFromPath(filePath) || filePath });
|
|
1167
|
-
}
|
|
1168
|
-
return files;
|
|
1169
|
-
}
|
|
1170
|
-
function extractPatchEndFiles(changes, workspacePath) {
|
|
1171
|
-
if (!changes || typeof changes !== 'object')
|
|
1172
|
-
return [];
|
|
1173
|
-
return Object.entries(changes).map(([filePath, change]) => {
|
|
1174
|
-
const diff = typeof change?.unified_diff === 'string' ? change.unified_diff : '';
|
|
1175
|
-
const displayPath = displayPatchPath(filePath, workspacePath);
|
|
1176
|
-
return {
|
|
1177
|
-
path: displayPath,
|
|
1178
|
-
name: fileNameFromPath(displayPath) || displayPath,
|
|
1179
|
-
...(diff ? { diff } : {}),
|
|
1180
|
-
...diffStatsFromText(diff),
|
|
1181
|
-
};
|
|
1182
|
-
});
|
|
1183
|
-
}
|
|
1184
|
-
function codexReplayEvent(eventId, timestamp, taskId, raw) {
|
|
1185
|
-
return {
|
|
1186
|
-
id: eventId,
|
|
1187
|
-
timestamp,
|
|
1188
|
-
task_id: taskId,
|
|
1189
|
-
chunk: {
|
|
1190
|
-
type: 'data-codex-event',
|
|
1191
|
-
id: eventId,
|
|
1192
|
-
data: { raw },
|
|
1193
|
-
},
|
|
1194
|
-
};
|
|
1195
|
-
}
|
|
1196
1059
|
function mirroredThreadWorkspacePath(sessionPath, stateEntry) {
|
|
1197
1060
|
const stateCwd = typeof stateEntry?.cwd === 'string' ? stateEntry.cwd : null;
|
|
1198
1061
|
const sessionWorkspace = readThreadWorkspacePath(sessionPath);
|
|
@@ -1216,10 +1079,8 @@ export function readCodexThreadHistory(threadId, limit = MIRRORED_THREAD_HISTORY
|
|
|
1216
1079
|
const messages = [];
|
|
1217
1080
|
const events = [];
|
|
1218
1081
|
let messageIndex = 0;
|
|
1219
|
-
let eventIndex = 0;
|
|
1220
1082
|
let latestTimestamp = indexEntry?.updated_at || '';
|
|
1221
1083
|
let recentGoalContext = null;
|
|
1222
|
-
const toolCalls = new Map();
|
|
1223
1084
|
const mirroredUserMessageKey = (text) => sanitizeMirroredUserText(text)
|
|
1224
1085
|
.replace(/\s+/g, ' ')
|
|
1225
1086
|
.trim();
|
|
@@ -1309,39 +1170,6 @@ export function readCodexThreadHistory(threadId, limit = MIRRORED_THREAD_HISTORY
|
|
|
1309
1170
|
const messageId = typeof payload.id === 'string' ? payload.id : `${threadId}-web-user-${event.sequence}`;
|
|
1310
1171
|
pushUserMessage(text, timestamp, messageId, attachments);
|
|
1311
1172
|
};
|
|
1312
|
-
const pushEvent = (timestamp, chunk) => {
|
|
1313
|
-
eventIndex += 1;
|
|
1314
|
-
events.push({
|
|
1315
|
-
id: `${threadId}-event-${eventIndex}`,
|
|
1316
|
-
timestamp,
|
|
1317
|
-
task_id: threadId,
|
|
1318
|
-
chunk,
|
|
1319
|
-
});
|
|
1320
|
-
};
|
|
1321
|
-
const pushToolInput = (timestamp, toolCallId, toolName, input) => {
|
|
1322
|
-
const sanitizedInput = sanitizeMirroredHistoryPayload(input);
|
|
1323
|
-
toolCalls.set(toolCallId, { toolName, input: sanitizedInput });
|
|
1324
|
-
pushEvent(timestamp, {
|
|
1325
|
-
type: 'tool-input-available',
|
|
1326
|
-
toolCallId,
|
|
1327
|
-
toolName,
|
|
1328
|
-
input: sanitizedInput,
|
|
1329
|
-
});
|
|
1330
|
-
};
|
|
1331
|
-
const pushToolOutput = (timestamp, toolCallId, output, fallbackToolName, fallbackInput, failed = false) => {
|
|
1332
|
-
const toolCall = toolCalls.get(toolCallId);
|
|
1333
|
-
const toolName = toolCall?.toolName || fallbackToolName;
|
|
1334
|
-
const input = toolCall?.input ?? (fallbackInput === undefined ? undefined : sanitizeMirroredHistoryPayload(fallbackInput));
|
|
1335
|
-
pushEvent(timestamp, {
|
|
1336
|
-
type: failed ? 'tool-output-error' : 'tool-output-available',
|
|
1337
|
-
toolCallId,
|
|
1338
|
-
...(toolName ? { toolName } : {}),
|
|
1339
|
-
...(input !== undefined ? { input } : {}),
|
|
1340
|
-
...(failed
|
|
1341
|
-
? { errorText: typeof output === 'string' ? output : 'Tool failed' }
|
|
1342
|
-
: { output: sanitizeMirroredHistoryPayload(parseJsonObject(output)) }),
|
|
1343
|
-
});
|
|
1344
|
-
};
|
|
1345
1173
|
for (const line of lines) {
|
|
1346
1174
|
const parsed = parseJsonLine(line);
|
|
1347
1175
|
if (typeof parsed?.timestamp === 'string')
|
|
@@ -1356,146 +1184,11 @@ export function readCodexThreadHistory(threadId, limit = MIRRORED_THREAD_HISTORY
|
|
|
1356
1184
|
if (payload.type === 'user_message') {
|
|
1357
1185
|
const text = typeof payload.message === 'string' ? payload.message.trim() : '';
|
|
1358
1186
|
pushUserMessage(text, timestamp, undefined, imageAttachmentsFromUnknown(payload.images));
|
|
1359
|
-
continue;
|
|
1360
|
-
}
|
|
1361
|
-
if (payload.type === 'turn_aborted') {
|
|
1362
|
-
if (eventLogThreadId !== threadId) {
|
|
1363
|
-
events.push(codexReplayEvent(`${threadId}-turn-aborted-${eventIndex + 1}`, timestamp, threadId, {
|
|
1364
|
-
method: 'turn/completed',
|
|
1365
|
-
params: {
|
|
1366
|
-
turn: {
|
|
1367
|
-
id: payload.turn_id || payload.turnId || 'turn',
|
|
1368
|
-
status: 'interrupted',
|
|
1369
|
-
},
|
|
1370
|
-
},
|
|
1371
|
-
}));
|
|
1372
|
-
eventIndex += 1;
|
|
1373
|
-
}
|
|
1374
|
-
continue;
|
|
1375
|
-
}
|
|
1376
|
-
if (payload.type === 'context_compacted') {
|
|
1377
|
-
events.push(codexReplayEvent(`${threadId}-context-compacted-${eventIndex + 1}`, timestamp, threadId, {
|
|
1378
|
-
method: 'contextCompaction/completed',
|
|
1379
|
-
params: {
|
|
1380
|
-
threadId,
|
|
1381
|
-
messageCount: payload.message_count || payload.messageCount,
|
|
1382
|
-
tokensSaved: payload.tokens_saved || payload.tokensSaved,
|
|
1383
|
-
},
|
|
1384
|
-
}));
|
|
1385
|
-
eventIndex += 1;
|
|
1386
|
-
continue;
|
|
1387
1187
|
}
|
|
1388
|
-
if (payload.type === 'web_search_end') {
|
|
1389
|
-
const toolCallId = typeof payload.call_id === 'string' ? payload.call_id : `${threadId}-web-search-${eventIndex + 1}`;
|
|
1390
|
-
const input = {
|
|
1391
|
-
query: payload.query,
|
|
1392
|
-
action: payload.action,
|
|
1393
|
-
};
|
|
1394
|
-
pushToolInput(timestamp, toolCallId, 'web_search', input);
|
|
1395
|
-
pushToolOutput(timestamp, toolCallId, payload.action || payload.query || 'completed');
|
|
1396
|
-
continue;
|
|
1397
|
-
}
|
|
1398
|
-
if (payload.type === 'mcp_tool_call_end') {
|
|
1399
|
-
const toolCallId = typeof payload.call_id === 'string' ? payload.call_id : `${threadId}-mcp-tool-${eventIndex + 1}`;
|
|
1400
|
-
const invocation = payload.invocation && typeof payload.invocation === 'object'
|
|
1401
|
-
? payload.invocation
|
|
1402
|
-
: {};
|
|
1403
|
-
const server = typeof invocation.server === 'string' ? invocation.server : '';
|
|
1404
|
-
const tool = typeof invocation.tool === 'string' ? invocation.tool : '';
|
|
1405
|
-
const toolName = [server, tool].filter(Boolean).join('.') || 'mcpToolCall';
|
|
1406
|
-
const input = invocation.arguments;
|
|
1407
|
-
const result = payload.result && typeof payload.result === 'object'
|
|
1408
|
-
? payload.result
|
|
1409
|
-
: payload.result;
|
|
1410
|
-
const failed = Boolean(result && typeof result === 'object' && 'Err' in result);
|
|
1411
|
-
pushToolInput(timestamp, toolCallId, toolName, input);
|
|
1412
|
-
pushToolOutput(timestamp, toolCallId, readableOutputFromMcpResult(result), toolName, input, failed);
|
|
1413
|
-
continue;
|
|
1414
|
-
}
|
|
1415
|
-
if (payload.type === 'patch_apply_end') {
|
|
1416
|
-
const files = extractPatchEndFiles(payload.changes, workspacePath);
|
|
1417
|
-
const additions = files.reduce((sum, file) => sum + file.additions, 0);
|
|
1418
|
-
const deletions = files.reduce((sum, file) => sum + file.deletions, 0);
|
|
1419
|
-
events.push(codexReplayEvent(`${threadId}-patch-end-${eventIndex + 1}`, timestamp, threadId, {
|
|
1420
|
-
method: 'codex/patchApply/completed',
|
|
1421
|
-
params: {
|
|
1422
|
-
callId: payload.call_id,
|
|
1423
|
-
success: payload.success !== false,
|
|
1424
|
-
files,
|
|
1425
|
-
fileCount: files.length,
|
|
1426
|
-
additions,
|
|
1427
|
-
deletions,
|
|
1428
|
-
status: payload.status,
|
|
1429
|
-
},
|
|
1430
|
-
}));
|
|
1431
|
-
eventIndex += 1;
|
|
1432
|
-
continue;
|
|
1433
|
-
}
|
|
1434
|
-
}
|
|
1435
|
-
if (parsed?.type === 'compacted') {
|
|
1436
|
-
events.push(codexReplayEvent(`${threadId}-context-compacted-${eventIndex + 1}`, timestamp, threadId, {
|
|
1437
|
-
method: 'contextCompaction/completed',
|
|
1438
|
-
params: { threadId },
|
|
1439
|
-
}));
|
|
1440
|
-
eventIndex += 1;
|
|
1441
1188
|
continue;
|
|
1442
1189
|
}
|
|
1443
1190
|
if (parsed?.type !== 'response_item')
|
|
1444
1191
|
continue;
|
|
1445
|
-
if (payload.type === 'function_call') {
|
|
1446
|
-
const toolCallId = typeof payload.call_id === 'string' ? payload.call_id : `${threadId}-tool-${eventIndex + 1}`;
|
|
1447
|
-
const toolName = typeof payload.name === 'string' ? payload.name : 'tool';
|
|
1448
|
-
const input = sanitizeMirroredHistoryPayload(parseJsonObject(payload.arguments));
|
|
1449
|
-
pushToolInput(timestamp, toolCallId, toolName, input);
|
|
1450
|
-
continue;
|
|
1451
|
-
}
|
|
1452
|
-
if (payload.type === 'function_call_output') {
|
|
1453
|
-
const toolCallId = typeof payload.call_id === 'string' ? payload.call_id : `${threadId}-tool-${eventIndex + 1}`;
|
|
1454
|
-
pushToolOutput(timestamp, toolCallId, payload.output);
|
|
1455
|
-
continue;
|
|
1456
|
-
}
|
|
1457
|
-
if (payload.type === 'tool_search_call') {
|
|
1458
|
-
const toolCallId = typeof payload.call_id === 'string' ? payload.call_id : `${threadId}-tool-search-${eventIndex + 1}`;
|
|
1459
|
-
pushToolInput(timestamp, toolCallId, 'tool_search', payload.arguments);
|
|
1460
|
-
continue;
|
|
1461
|
-
}
|
|
1462
|
-
if (payload.type === 'tool_search_output') {
|
|
1463
|
-
const toolCallId = typeof payload.call_id === 'string' ? payload.call_id : `${threadId}-tool-search-${eventIndex + 1}`;
|
|
1464
|
-
pushToolOutput(timestamp, toolCallId, {
|
|
1465
|
-
status: payload.status,
|
|
1466
|
-
tools: payload.tools,
|
|
1467
|
-
}, 'tool_search');
|
|
1468
|
-
continue;
|
|
1469
|
-
}
|
|
1470
|
-
if (payload.type === 'custom_tool_call') {
|
|
1471
|
-
const toolName = typeof payload.name === 'string' ? payload.name : 'custom_tool';
|
|
1472
|
-
const toolCallId = typeof payload.call_id === 'string' ? payload.call_id : `${threadId}-tool-${eventIndex + 1}`;
|
|
1473
|
-
if (toolName === 'apply_patch') {
|
|
1474
|
-
const input = typeof payload.input === 'string' ? payload.input : '';
|
|
1475
|
-
const files = extractPatchFiles(input);
|
|
1476
|
-
events.push(codexReplayEvent(`${threadId}-patch-start-${eventIndex + 1}`, timestamp, threadId, {
|
|
1477
|
-
method: 'codex/patchApply/started',
|
|
1478
|
-
params: {
|
|
1479
|
-
callId: payload.call_id,
|
|
1480
|
-
files,
|
|
1481
|
-
fileCount: files.length,
|
|
1482
|
-
...diffStatsFromText(input),
|
|
1483
|
-
},
|
|
1484
|
-
}));
|
|
1485
|
-
eventIndex += 1;
|
|
1486
|
-
}
|
|
1487
|
-
else {
|
|
1488
|
-
pushToolInput(timestamp, toolCallId, toolName, parseJsonObject(payload.input));
|
|
1489
|
-
}
|
|
1490
|
-
continue;
|
|
1491
|
-
}
|
|
1492
|
-
if (payload.type === 'custom_tool_call_output') {
|
|
1493
|
-
const toolCallId = typeof payload.call_id === 'string' ? payload.call_id : `${threadId}-tool-${eventIndex + 1}`;
|
|
1494
|
-
if (toolCalls.has(toolCallId)) {
|
|
1495
|
-
pushToolOutput(timestamp, toolCallId, payload.output);
|
|
1496
|
-
}
|
|
1497
|
-
continue;
|
|
1498
|
-
}
|
|
1499
1192
|
if (payload.type !== 'message')
|
|
1500
1193
|
continue;
|
|
1501
1194
|
messageIndex += 1;
|
|
@@ -1708,7 +1401,7 @@ function threadStreamChunkForEvent(event) {
|
|
|
1708
1401
|
!Array.isArray(event.raw_payload) &&
|
|
1709
1402
|
typeof event.raw_payload.type === 'string' &&
|
|
1710
1403
|
String(event.raw_payload.type).trim()) {
|
|
1711
|
-
return
|
|
1404
|
+
return event.raw_payload;
|
|
1712
1405
|
}
|
|
1713
1406
|
return {
|
|
1714
1407
|
type: 'data-codex-event',
|
|
@@ -1718,28 +1411,6 @@ function threadStreamChunkForEvent(event) {
|
|
|
1718
1411
|
},
|
|
1719
1412
|
};
|
|
1720
1413
|
}
|
|
1721
|
-
function normalizeStoredCodexThreadChunk(chunk) {
|
|
1722
|
-
if (chunk.type !== 'data-supen-event')
|
|
1723
|
-
return chunk;
|
|
1724
|
-
const data = chunk.data && typeof chunk.data === 'object' && !Array.isArray(chunk.data)
|
|
1725
|
-
? chunk.data
|
|
1726
|
-
: {};
|
|
1727
|
-
const raw = data.raw && typeof data.raw === 'object' && !Array.isArray(data.raw)
|
|
1728
|
-
? data.raw
|
|
1729
|
-
: {};
|
|
1730
|
-
return {
|
|
1731
|
-
...chunk,
|
|
1732
|
-
type: 'data-codex-event',
|
|
1733
|
-
data: {
|
|
1734
|
-
...data,
|
|
1735
|
-
eventType: typeof data.eventType === 'string' && data.eventType.trim()
|
|
1736
|
-
? data.eventType
|
|
1737
|
-
: typeof raw.method === 'string' && raw.method.trim()
|
|
1738
|
-
? raw.method
|
|
1739
|
-
: 'codex-event',
|
|
1740
|
-
},
|
|
1741
|
-
};
|
|
1742
|
-
}
|
|
1743
1414
|
function buildMcpSettingsResponse() {
|
|
1744
1415
|
const overrides = getMcpEnvOverrides();
|
|
1745
1416
|
const runtimeEnv = { ...process.env };
|
|
@@ -1902,7 +1573,6 @@ function readPackageVersion(packageRoot) {
|
|
|
1902
1573
|
}
|
|
1903
1574
|
}
|
|
1904
1575
|
function detectDaemonPackageStatus() {
|
|
1905
|
-
const envVersion = process.env.SUPEN_DAEMON_VERSION || process.env.npm_package_version || null;
|
|
1906
1576
|
let packageRoot = null;
|
|
1907
1577
|
try {
|
|
1908
1578
|
packageRoot = findPackageRootFrom(require.resolve('@supen-ai/daemon'), '@supen-ai/daemon');
|
|
@@ -1945,7 +1615,7 @@ function detectDaemonPackageStatus() {
|
|
|
1945
1615
|
? 'local-package'
|
|
1946
1616
|
: null;
|
|
1947
1617
|
return {
|
|
1948
|
-
version:
|
|
1618
|
+
version: bundledDaemonVersion || packageVersion,
|
|
1949
1619
|
package_root: packageRoot || bundledDaemonRoot,
|
|
1950
1620
|
install_source: installSource,
|
|
1951
1621
|
update_supported: installSource === 'supen-cli-bundle' || installSource === 'npm-global',
|
|
@@ -2341,6 +2011,47 @@ function readInstalledAppsPayload() {
|
|
|
2341
2011
|
}),
|
|
2342
2012
|
};
|
|
2343
2013
|
}
|
|
2014
|
+
const CODEX_SUBSCRIPTION_STATUS_WAIT_MS = 1800;
|
|
2015
|
+
const CODEX_SUBSCRIPTION_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
2016
|
+
let cachedCodexSubscription = null;
|
|
2017
|
+
let codexSubscriptionRefreshInFlight = null;
|
|
2018
|
+
function refreshCodexSubscriptionStatus() {
|
|
2019
|
+
if (codexSubscriptionRefreshInFlight)
|
|
2020
|
+
return codexSubscriptionRefreshInFlight;
|
|
2021
|
+
codexSubscriptionRefreshInFlight = readCodexSubscription()
|
|
2022
|
+
.then((payload) => {
|
|
2023
|
+
cachedCodexSubscription = { payload, cachedAt: Date.now() };
|
|
2024
|
+
return payload;
|
|
2025
|
+
})
|
|
2026
|
+
.finally(() => {
|
|
2027
|
+
codexSubscriptionRefreshInFlight = null;
|
|
2028
|
+
});
|
|
2029
|
+
return codexSubscriptionRefreshInFlight;
|
|
2030
|
+
}
|
|
2031
|
+
async function readCodexSubscriptionForStatus() {
|
|
2032
|
+
if (cachedCodexSubscription &&
|
|
2033
|
+
Date.now() - cachedCodexSubscription.cachedAt < CODEX_SUBSCRIPTION_CACHE_TTL_MS) {
|
|
2034
|
+
return { payload: cachedCodexSubscription.payload, error: null };
|
|
2035
|
+
}
|
|
2036
|
+
const refresh = refreshCodexSubscriptionStatus();
|
|
2037
|
+
const timeout = new Promise((resolve) => {
|
|
2038
|
+
setTimeout(() => resolve(null), CODEX_SUBSCRIPTION_STATUS_WAIT_MS).unref?.();
|
|
2039
|
+
});
|
|
2040
|
+
try {
|
|
2041
|
+
const payload = await Promise.race([refresh, timeout]);
|
|
2042
|
+
if (payload)
|
|
2043
|
+
return { payload, error: null };
|
|
2044
|
+
}
|
|
2045
|
+
catch (err) {
|
|
2046
|
+
if (cachedCodexSubscription)
|
|
2047
|
+
return { payload: cachedCodexSubscription.payload, error: null };
|
|
2048
|
+
return { payload: null, error: err?.message || 'Unable to read Codex subscription details.' };
|
|
2049
|
+
}
|
|
2050
|
+
if (cachedCodexSubscription)
|
|
2051
|
+
return { payload: cachedCodexSubscription.payload, error: null };
|
|
2052
|
+
refresh.catch(() => undefined);
|
|
2053
|
+
return { payload: null, error: null };
|
|
2054
|
+
}
|
|
2344
2055
|
function readCachedCodingCliStatusPayload(options) {
|
|
2345
2056
|
startCodingCliStatusCache({
|
|
2346
2057
|
build: () => ({
|
|
@@ -2415,14 +2126,22 @@ function codexSubscriptionSummary(subscription) {
|
|
|
2415
2126
|
: {};
|
|
2416
2127
|
return {
|
|
2417
2128
|
plan_type: typeof rateLimits.planType === 'string' && rateLimits.planType.trim() ? rateLimits.planType.trim() : null,
|
|
2418
|
-
credits_balance: typeof credits.balance === 'string' && credits.balance.trim()
|
|
2129
|
+
credits_balance: typeof credits.balance === 'string' && credits.balance.trim()
|
|
2130
|
+
? credits.balance.trim()
|
|
2131
|
+
: typeof credits.balance === 'number' && Number.isFinite(credits.balance)
|
|
2132
|
+
? String(credits.balance)
|
|
2133
|
+
: null,
|
|
2419
2134
|
};
|
|
2420
2135
|
}
|
|
2421
2136
|
async function readCodexAgentStatusPayload() {
|
|
2422
|
-
const status =
|
|
2137
|
+
const status = {
|
|
2138
|
+
...readCachedCodingCliStatusPayload(),
|
|
2139
|
+
daemon: detectDaemonPackageStatus(),
|
|
2140
|
+
};
|
|
2423
2141
|
const quotaStatus = readLatestSpaceQuotaStatus();
|
|
2424
|
-
|
|
2425
|
-
|
|
2142
|
+
const subscriptionResult = await readCodexSubscriptionForStatus();
|
|
2143
|
+
const subscription = subscriptionResult.payload;
|
|
2144
|
+
if (subscription) {
|
|
2426
2145
|
const subscriptionWindows = mergeQuotaWindows(normalizeCodexSubscriptionQuotaWindows(subscription), normalizeQuotaWindows(subscription.rate_limits), normalizeQuotaWindows(subscription.rate_limits_by_limit_id));
|
|
2427
2146
|
return {
|
|
2428
2147
|
...status,
|
|
@@ -2437,23 +2156,21 @@ async function readCodexAgentStatusPayload() {
|
|
|
2437
2156
|
quota_windows: mergeQuotaWindows(quotaStatus.windows, subscriptionWindows),
|
|
2438
2157
|
};
|
|
2439
2158
|
}
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
};
|
|
2456
|
-
}
|
|
2159
|
+
return {
|
|
2160
|
+
...status,
|
|
2161
|
+
subscription: {
|
|
2162
|
+
ok: false,
|
|
2163
|
+
fetched_at: null,
|
|
2164
|
+
payload: null,
|
|
2165
|
+
error: subscriptionResult.error,
|
|
2166
|
+
},
|
|
2167
|
+
subscription_summary: {
|
|
2168
|
+
plan_type: null,
|
|
2169
|
+
credits_balance: null,
|
|
2170
|
+
},
|
|
2171
|
+
quota_status: quotaStatus,
|
|
2172
|
+
quota_windows: quotaStatus.windows,
|
|
2173
|
+
};
|
|
2457
2174
|
}
|
|
2458
2175
|
function readRuntimeModelStatusPayload() {
|
|
2459
2176
|
const selected_cli = process.env.SUPEN_CODING_CLI || readConfigSummary().coding_cli || 'codex';
|