agentel 0.2.5 → 0.2.8
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 +77 -37
- package/docs/code-reference.md +26 -13
- package/docs/history-source-handling.md +247 -82
- package/docs/release.md +1 -1
- package/package.json +5 -2
- package/src/archive.js +200 -17
- package/src/canonical-events.js +74 -25
- package/src/cli.js +2561 -204
- package/src/config.js +11 -0
- package/src/doctor.js +2 -0
- package/src/importers/claude.js +309 -11
- package/src/importers/gemini.js +2 -1
- package/src/importers/providers.js +22 -0
- package/src/importers.js +2142 -212
- package/src/parser-versions.js +1 -0
- package/src/search.js +417 -176
- package/src/sources.js +1 -0
- package/src/web-export-instructions.js +79 -0
package/src/config.js
CHANGED
|
@@ -45,6 +45,7 @@ function defaultConfig(env = process.env) {
|
|
|
45
45
|
},
|
|
46
46
|
imports: {
|
|
47
47
|
defaultSinceDays: 30,
|
|
48
|
+
updateSince: "",
|
|
48
49
|
sources: IMPORT_SOURCE_ORDER,
|
|
49
50
|
autoDiscoverSources: true
|
|
50
51
|
},
|
|
@@ -246,6 +247,7 @@ function parseConfigValue(value) {
|
|
|
246
247
|
function normalizeConfigKeyValue(key, value) {
|
|
247
248
|
if (key === "imports.sources") return normalizeImportSources(value);
|
|
248
249
|
if (key === "imports.defaultSinceDays") return normalizeNonNegativeInteger(value, 30);
|
|
250
|
+
if (key === "imports.updateSince") return normalizeImportSinceValue(value);
|
|
249
251
|
if (key === "sync.intervalMinutes" || key === "index.intervalMinutes" || key === "index.batteryIntervalMinutes") {
|
|
250
252
|
return normalizeSyncInterval(value);
|
|
251
253
|
}
|
|
@@ -253,6 +255,15 @@ function normalizeConfigKeyValue(key, value) {
|
|
|
253
255
|
return value;
|
|
254
256
|
}
|
|
255
257
|
|
|
258
|
+
function normalizeImportSinceValue(value) {
|
|
259
|
+
const text = String(value || "").trim().toLowerCase();
|
|
260
|
+
if (!text) return "";
|
|
261
|
+
if (text === "all") return "all";
|
|
262
|
+
const match = text.match(/^(\d+)([dhm])$/);
|
|
263
|
+
if (!match) return text;
|
|
264
|
+
return `${Math.max(1, Math.round(Number(match[1])))}${match[2]}`;
|
|
265
|
+
}
|
|
266
|
+
|
|
256
267
|
function normalizeImportSources(value) {
|
|
257
268
|
const raw = Array.isArray(value)
|
|
258
269
|
? value
|
package/src/doctor.js
CHANGED
|
@@ -59,6 +59,7 @@ function sourceCoverage(discovery, cfg) {
|
|
|
59
59
|
const rows = [
|
|
60
60
|
coverageRow("codex-cli", "Codex CLI", discovery.codexCli, configured),
|
|
61
61
|
coverageRow("codex-desktop", "Codex Desktop", discovery.codexDesktop, configured),
|
|
62
|
+
coverageRow("codex-sdk", "Codex SDK jobs", discovery.codexSdk, configured),
|
|
62
63
|
coverageRow("claude", "Claude Code CLI", discovery.claude, configured),
|
|
63
64
|
coverageRow("claude-code-desktop", "Claude Code Desktop", discovery.claudeCodeDesktop, configured),
|
|
64
65
|
coverageRow("claude-workspace", "Claude Workspace", discovery.claudeWorkspace, configured),
|
|
@@ -194,6 +195,7 @@ function parserUpdateCommand(sourceType) {
|
|
|
194
195
|
const source = {
|
|
195
196
|
"codex-cli-history": "codex-cli",
|
|
196
197
|
"codex-desktop-history": "codex-desktop",
|
|
198
|
+
"codex-sdk-history": "codex-sdk",
|
|
197
199
|
"cli-history": "claude",
|
|
198
200
|
"claude-sdk-history": "claude-sdk",
|
|
199
201
|
"claude-code-desktop-metadata": "claude-code-desktop",
|
package/src/importers/claude.js
CHANGED
|
@@ -17,6 +17,9 @@ function extractClaudeMessagesFromEvent(event, provider, context = {}) {
|
|
|
17
17
|
const role = normalizeRole(message.role || event.role || type);
|
|
18
18
|
const timestamp = eventTimestamp(event);
|
|
19
19
|
|
|
20
|
+
const remoteMessages = remoteControlLifecycleMessages(event, provider, context, type, timestamp);
|
|
21
|
+
if (remoteMessages.length) return remoteMessages;
|
|
22
|
+
|
|
20
23
|
if (type === "summary" || event.summary) {
|
|
21
24
|
const content = firstString(event.summary, message.summary);
|
|
22
25
|
return content ? [supplementaryMessage(provider, "Claude summary", content, timestamp, "summary")] : [];
|
|
@@ -34,9 +37,12 @@ function assistantMessages(event, message, provider, context, timestamp, content
|
|
|
34
37
|
const text = visibleText(content);
|
|
35
38
|
const thinking = thinkingText(content);
|
|
36
39
|
const toolCalls = toolUseParts(content).map((part) => normalizeToolCall(part, provider)).filter(Boolean);
|
|
40
|
+
rememberToolCalls(context, toolCalls);
|
|
41
|
+
const eventMetadata = claudeEventMetadata(event);
|
|
37
42
|
const metadata = {
|
|
38
43
|
provider,
|
|
39
44
|
eventType: firstString(event.type, event.kind),
|
|
45
|
+
...eventMetadata,
|
|
40
46
|
model: firstString(message.model, event.model, context.model) || undefined,
|
|
41
47
|
requestId: firstString(event.requestId, event.request_id, message.id) || undefined,
|
|
42
48
|
status: firstString(message.stop_reason, event.stop_reason, event.status) || undefined,
|
|
@@ -51,7 +57,8 @@ function assistantMessages(event, message, provider, context, timestamp, content
|
|
|
51
57
|
|
|
52
58
|
function userMessages(event, message, provider, context, timestamp, content) {
|
|
53
59
|
const text = visibleText(content);
|
|
54
|
-
const
|
|
60
|
+
const eventMetadata = claudeEventMetadata(event);
|
|
61
|
+
const toolResults = toolResultParts(content).map((part) => normalizeToolResult(part, provider, event, context)).filter(Boolean);
|
|
55
62
|
const result = [];
|
|
56
63
|
if (text) {
|
|
57
64
|
result.push({
|
|
@@ -61,6 +68,7 @@ function userMessages(event, message, provider, context, timestamp, content) {
|
|
|
61
68
|
metadata: {
|
|
62
69
|
provider,
|
|
63
70
|
eventType: firstString(event.type, event.kind),
|
|
71
|
+
...eventMetadata,
|
|
64
72
|
model: firstString(message.model, event.model, context.model) || undefined
|
|
65
73
|
}
|
|
66
74
|
});
|
|
@@ -74,6 +82,7 @@ function userMessages(event, message, provider, context, timestamp, content) {
|
|
|
74
82
|
metadata: {
|
|
75
83
|
provider,
|
|
76
84
|
eventType: "claude-tool-result",
|
|
85
|
+
...eventMetadata,
|
|
77
86
|
toolResult
|
|
78
87
|
}
|
|
79
88
|
});
|
|
@@ -81,6 +90,49 @@ function userMessages(event, message, provider, context, timestamp, content) {
|
|
|
81
90
|
return result;
|
|
82
91
|
}
|
|
83
92
|
|
|
93
|
+
function claudeEventMetadata(event) {
|
|
94
|
+
return compactMetadata({
|
|
95
|
+
uuid: firstString(event.uuid),
|
|
96
|
+
parentUuid: firstString(event.parentUuid, event.parent_uuid),
|
|
97
|
+
logicalParentUuid: firstString(event.logicalParentUuid, event.logical_parent_uuid),
|
|
98
|
+
leafUuid: firstString(event.leafUuid, event.leaf_uuid),
|
|
99
|
+
promptId: firstString(event.promptId, event.prompt_id),
|
|
100
|
+
sourceToolAssistantUUID: firstString(event.sourceToolAssistantUUID, event.source_tool_assistant_uuid),
|
|
101
|
+
sourceToolUseID: firstString(event.sourceToolUseID, event.source_tool_use_id),
|
|
102
|
+
parentToolUseID: firstString(event.parentToolUseID, event.parent_tool_use_id),
|
|
103
|
+
toolUseID: firstString(event.toolUseID, event.tool_use_id),
|
|
104
|
+
isSidechain: typeof event.isSidechain === "boolean" ? event.isSidechain : undefined,
|
|
105
|
+
isVisibleInTranscriptOnly: typeof event.isVisibleInTranscriptOnly === "boolean" ? event.isVisibleInTranscriptOnly : undefined,
|
|
106
|
+
isCompactSummary: typeof event.isCompactSummary === "boolean" ? event.isCompactSummary : undefined,
|
|
107
|
+
userType: firstString(event.userType, event.user_type),
|
|
108
|
+
entrypoint: firstString(event.entrypoint),
|
|
109
|
+
claudeCodeVersion: firstString(event.version),
|
|
110
|
+
gitBranch: firstString(event.gitBranch, event.git_branch),
|
|
111
|
+
permissionMode: firstString(event.permissionMode, event.permission_mode),
|
|
112
|
+
agentId: firstString(event.agentId, event.agent_id),
|
|
113
|
+
slug: firstString(event.slug),
|
|
114
|
+
attributionSkill: firstString(event.attributionSkill, event.attribution_skill),
|
|
115
|
+
origin: firstString(event.origin),
|
|
116
|
+
mcpMeta: event.mcpMeta && typeof event.mcpMeta === "object" ? event.mcpMeta : undefined,
|
|
117
|
+
compactMetadata: event.compactMetadata && typeof event.compactMetadata === "object" ? event.compactMetadata : undefined,
|
|
118
|
+
apiError: claudeApiErrorMetadata(event) || undefined
|
|
119
|
+
}) || {};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function claudeApiErrorMetadata(event) {
|
|
123
|
+
if (!event || typeof event !== "object") return null;
|
|
124
|
+
if (event.isApiErrorMessage !== true && !event.error && event.apiErrorStatus == null) return null;
|
|
125
|
+
return compactMetadata({
|
|
126
|
+
isApiErrorMessage: event.isApiErrorMessage === true ? true : undefined,
|
|
127
|
+
status: numberValue(event.apiErrorStatus, event.api_error_status) ?? undefined,
|
|
128
|
+
type: firstString(event.error) || undefined,
|
|
129
|
+
retryAttempt: numberValue(event.retryAttempt, event.retry_attempt) ?? undefined,
|
|
130
|
+
maxRetries: numberValue(event.maxRetries, event.max_retries) ?? undefined,
|
|
131
|
+
retryInMs: numberValue(event.retryInMs, event.retry_in_ms) ?? undefined,
|
|
132
|
+
cause: firstString(event.cause?.message, event.cause) || undefined
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
|
|
84
136
|
function supplementaryMessage(provider, title, content, timestamp, summaryKind, model = "") {
|
|
85
137
|
return {
|
|
86
138
|
role: "assistant",
|
|
@@ -96,6 +148,209 @@ function supplementaryMessage(provider, title, content, timestamp, summaryKind,
|
|
|
96
148
|
};
|
|
97
149
|
}
|
|
98
150
|
|
|
151
|
+
function remoteControlLifecycleMessages(event, provider, context, type, timestamp) {
|
|
152
|
+
if (!isClaudeRemoteControlSession(context)) return [];
|
|
153
|
+
if (type === "user" || type === "assistant" || type === "summary") return [];
|
|
154
|
+
if (type === "queue-operation") return [remoteQueueMessage(event, provider, timestamp)];
|
|
155
|
+
if (type === "attachment") return [remoteAttachmentMessage(event, provider, timestamp)].filter(Boolean);
|
|
156
|
+
if (type === "progress") return [remoteProgressMessage(event, provider, timestamp)];
|
|
157
|
+
if (type === "system") return [remoteSystemMessage(event, provider, timestamp)];
|
|
158
|
+
if (type === "permission-mode") return [remotePermissionModeMessage(event, provider, timestamp)].filter(Boolean);
|
|
159
|
+
if (type === "file-history-snapshot") return [remoteFileHistorySnapshotMessage(event, provider, timestamp)];
|
|
160
|
+
return [];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function isClaudeRemoteControlSession(context) {
|
|
164
|
+
return context?.claudeJsonl?.remoteControl === true;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function remoteQueueMessage(event, provider, timestamp) {
|
|
168
|
+
const operation = firstString(event.operation, "operation").toLowerCase();
|
|
169
|
+
const content = firstString(event.content);
|
|
170
|
+
const label = operation ? operation.replace(/_/g, " ") : "operation";
|
|
171
|
+
const suffix = content ? `: ${previewText(content, 240)}` : "";
|
|
172
|
+
return remoteContextMessage(provider, event, timestamp, "remote_control_queue", `Remote Control queue ${label}${suffix}`, {
|
|
173
|
+
queueOperation: operation || undefined,
|
|
174
|
+
queueContent: content || undefined
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function remoteAttachmentMessage(event, provider, timestamp) {
|
|
179
|
+
const attachment = event.attachment && typeof event.attachment === "object" ? event.attachment : {};
|
|
180
|
+
const metadata = normalizeRemoteAttachment(attachment);
|
|
181
|
+
if (!metadata) return null;
|
|
182
|
+
return remoteContextMessage(provider, event, timestamp, remoteAttachmentContextKind(metadata.type), remoteAttachmentText(metadata), {
|
|
183
|
+
attachment: metadata
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function remoteProgressMessage(event, provider, timestamp) {
|
|
188
|
+
const data = event.data && typeof event.data === "object" ? event.data : {};
|
|
189
|
+
const hookName = firstString(data.hookName, data.hook_name);
|
|
190
|
+
const hookEvent = firstString(data.hookEvent, data.hook_event);
|
|
191
|
+
const progressType = firstString(data.type);
|
|
192
|
+
const label = firstString(hookName, hookEvent, progressType, "progress");
|
|
193
|
+
return remoteContextMessage(provider, event, timestamp, "remote_control_progress", `Remote Control progress: ${label}`, {
|
|
194
|
+
progress: compactMetadata({
|
|
195
|
+
type: progressType || undefined,
|
|
196
|
+
hookEvent: hookEvent || undefined,
|
|
197
|
+
hookName: hookName || undefined,
|
|
198
|
+
command: firstString(data.command) || undefined,
|
|
199
|
+
parentToolUseID: firstString(event.parentToolUseID, event.parent_tool_use_id) || undefined,
|
|
200
|
+
toolUseID: firstString(event.toolUseID, event.tool_use_id) || undefined
|
|
201
|
+
})
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function remoteSystemMessage(event, provider, timestamp) {
|
|
206
|
+
const subtype = firstString(event.subtype, event.kind, "system");
|
|
207
|
+
const hookCount = numberValue(event.hookCount, event.hook_count);
|
|
208
|
+
const hookErrors = Array.isArray(event.hookErrors) ? event.hookErrors : [];
|
|
209
|
+
const body = subtype === "stop_hook_summary"
|
|
210
|
+
? `Remote Control stop hook summary: ${hookCount ?? 0} ${plural("hook", hookCount ?? 0)}${hookErrors.length ? `, ${hookErrors.length} ${plural("error", hookErrors.length)}` : ""}`
|
|
211
|
+
: `Remote Control system event: ${subtype}`;
|
|
212
|
+
return remoteContextMessage(provider, event, timestamp, "remote_control_system", body, {
|
|
213
|
+
system: compactMetadata({
|
|
214
|
+
subtype,
|
|
215
|
+
hookCount: hookCount ?? undefined,
|
|
216
|
+
hookInfos: Array.isArray(event.hookInfos) ? event.hookInfos.map((hook) => compactMetadata({ command: firstString(hook?.command) || undefined })).filter(Boolean) : undefined,
|
|
217
|
+
hookErrors: hookErrors.length ? hookErrors : undefined,
|
|
218
|
+
preventedContinuation: typeof event.preventedContinuation === "boolean" ? event.preventedContinuation : undefined,
|
|
219
|
+
stopReason: firstString(event.stopReason, event.stop_reason) || undefined,
|
|
220
|
+
hasOutput: typeof event.hasOutput === "boolean" ? event.hasOutput : undefined,
|
|
221
|
+
level: firstString(event.level) || undefined
|
|
222
|
+
})
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function remotePermissionModeMessage(event, provider, timestamp) {
|
|
227
|
+
if (!timestamp) return null;
|
|
228
|
+
const permissionMode = firstString(event.permissionMode, event.permission_mode, "unknown");
|
|
229
|
+
return remoteContextMessage(provider, event, timestamp, "remote_control_permission", `Remote Control permission mode: ${permissionMode}`, {
|
|
230
|
+
permissionMode
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function remoteFileHistorySnapshotMessage(event, provider, timestamp) {
|
|
235
|
+
const snapshot = event.snapshot && typeof event.snapshot === "object" ? event.snapshot : {};
|
|
236
|
+
const snapshotTimestamp = timestamp || eventTimestamp(snapshot);
|
|
237
|
+
const backups = snapshot.trackedFileBackups && typeof snapshot.trackedFileBackups === "object" ? snapshot.trackedFileBackups : {};
|
|
238
|
+
const paths = Object.keys(backups).sort();
|
|
239
|
+
const action = event.isSnapshotUpdate ? "updated" : "recorded";
|
|
240
|
+
const target = paths.length ? `: ${namesPreview(paths)}` : "";
|
|
241
|
+
return remoteContextMessage(provider, event, snapshotTimestamp, "remote_control_file_history", `Remote Control file history snapshot ${action}${target}`, {
|
|
242
|
+
fileHistorySnapshot: compactMetadata({
|
|
243
|
+
messageId: firstString(event.messageId, event.message_id, snapshot.messageId, snapshot.message_id) || undefined,
|
|
244
|
+
isSnapshotUpdate: typeof event.isSnapshotUpdate === "boolean" ? event.isSnapshotUpdate : undefined,
|
|
245
|
+
timestamp: snapshotTimestamp || undefined,
|
|
246
|
+
backupFileCount: paths.length || undefined,
|
|
247
|
+
paths: paths.length ? paths : undefined
|
|
248
|
+
})
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function remoteContextMessage(provider, event, timestamp, contextKind, content, extraMetadata = {}) {
|
|
253
|
+
return {
|
|
254
|
+
role: "system",
|
|
255
|
+
content,
|
|
256
|
+
timestamp,
|
|
257
|
+
metadata: compactMetadata({
|
|
258
|
+
provider,
|
|
259
|
+
eventType: firstString(event.type, event.kind),
|
|
260
|
+
...claudeEventMetadata(event),
|
|
261
|
+
providerGenerated: true,
|
|
262
|
+
contextKind,
|
|
263
|
+
contextSource: "claude-remote-control",
|
|
264
|
+
...extraMetadata
|
|
265
|
+
})
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function normalizeRemoteAttachment(attachment) {
|
|
270
|
+
const type = firstString(attachment.type);
|
|
271
|
+
if (!type) return null;
|
|
272
|
+
const content = attachment.content && typeof attachment.content === "object" ? attachment.content : {};
|
|
273
|
+
const text = firstString(content.content, attachment.content);
|
|
274
|
+
return compactMetadata({
|
|
275
|
+
type,
|
|
276
|
+
addedNames: asStringArray(attachment.addedNames),
|
|
277
|
+
removedNames: asStringArray(attachment.removedNames),
|
|
278
|
+
path: firstString(attachment.path, content.path) || undefined,
|
|
279
|
+
displayPath: firstString(attachment.displayPath, attachment.display_path) || undefined,
|
|
280
|
+
prompt: previewText(firstString(attachment.prompt), 500) || undefined,
|
|
281
|
+
commandMode: firstString(attachment.commandMode, attachment.command_mode) || undefined,
|
|
282
|
+
allowedTools: asStringArray(attachment.allowedTools),
|
|
283
|
+
newDate: firstString(attachment.newDate, attachment.new_date) || undefined,
|
|
284
|
+
itemCount: numberValue(attachment.itemCount, attachment.item_count) ?? undefined,
|
|
285
|
+
maxTurns: numberValue(attachment.maxTurns, attachment.max_turns) ?? undefined,
|
|
286
|
+
turnCount: numberValue(attachment.turnCount, attachment.turn_count) ?? undefined,
|
|
287
|
+
contentType: firstString(content.type) || undefined,
|
|
288
|
+
contentPath: firstString(content.path) || undefined,
|
|
289
|
+
contentDiffersFromDisk: typeof content.contentDiffersFromDisk === "boolean" ? content.contentDiffersFromDisk : undefined,
|
|
290
|
+
contentPreview: text ? previewText(text, 240) : undefined
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function remoteAttachmentContextKind(type) {
|
|
295
|
+
return `remote_control_${String(type || "attachment").replace(/[^a-z0-9]+/gi, "_").replace(/^_+|_+$/g, "").toLowerCase() || "attachment"}`;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
function remoteAttachmentText(metadata) {
|
|
299
|
+
const type = metadata.type;
|
|
300
|
+
if (type === "deferred_tools_delta") {
|
|
301
|
+
const names = [...(metadata.addedNames || []), ...(metadata.removedNames || [])];
|
|
302
|
+
return names.length ? `Remote Control tools updated: ${namesPreview(names)}` : "Remote Control tools updated";
|
|
303
|
+
}
|
|
304
|
+
if (type === "mcp_instructions_delta") {
|
|
305
|
+
return metadata.addedNames?.length ? `Remote Control MCP instructions updated: ${namesPreview(metadata.addedNames)}` : "Remote Control MCP instructions updated";
|
|
306
|
+
}
|
|
307
|
+
if (type === "skill_listing") {
|
|
308
|
+
return metadata.addedNames?.length ? `Remote Control skills available: ${namesPreview(metadata.addedNames)}` : "Remote Control skills updated";
|
|
309
|
+
}
|
|
310
|
+
if (type === "nested_memory") {
|
|
311
|
+
return `Remote Control memory loaded: ${firstString(metadata.displayPath, metadata.path, metadata.contentPath, "memory")}`;
|
|
312
|
+
}
|
|
313
|
+
if (type === "queued_command") {
|
|
314
|
+
return metadata.prompt ? `Remote Control queued command: ${metadata.prompt}` : "Remote Control queued command";
|
|
315
|
+
}
|
|
316
|
+
if (type === "command_permissions") {
|
|
317
|
+
return metadata.allowedTools?.length ? `Remote Control command permissions: ${namesPreview(metadata.allowedTools)}` : "Remote Control command permissions updated";
|
|
318
|
+
}
|
|
319
|
+
if (type === "edited_text_file") {
|
|
320
|
+
return `Remote Control edited text file: ${firstString(metadata.displayPath, metadata.path, metadata.contentPath, "file")}`;
|
|
321
|
+
}
|
|
322
|
+
if (type === "date_change") {
|
|
323
|
+
return metadata.newDate ? `Remote Control date changed: ${metadata.newDate}` : "Remote Control date changed";
|
|
324
|
+
}
|
|
325
|
+
if (type === "max_turns_reached") {
|
|
326
|
+
return `Remote Control max turns reached: ${metadata.turnCount ?? 0}/${metadata.maxTurns ?? 0}`;
|
|
327
|
+
}
|
|
328
|
+
if (type === "compact_file_reference") {
|
|
329
|
+
return `Remote Control compact file reference: ${firstString(metadata.displayPath, metadata.path, "file")}`;
|
|
330
|
+
}
|
|
331
|
+
if (type === "task_reminder" || type === "todo_reminder") {
|
|
332
|
+
return `Remote Control ${type.replace(/_/g, " ")}: ${metadata.itemCount ?? 0} ${plural("item", metadata.itemCount ?? 0)}`;
|
|
333
|
+
}
|
|
334
|
+
return `Remote Control attachment: ${type.replace(/_/g, " ")}`;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function namesPreview(names, limit = 8) {
|
|
338
|
+
const values = asStringArray(names);
|
|
339
|
+
const visible = values.slice(0, limit).join(", ");
|
|
340
|
+
const remaining = values.length - limit;
|
|
341
|
+
return remaining > 0 ? `${visible}, +${remaining} more` : visible;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function previewText(value, max = 240) {
|
|
345
|
+
const text = String(value || "").replace(/\s+/g, " ").trim();
|
|
346
|
+
if (!text) return "";
|
|
347
|
+
return text.length > max ? `${text.slice(0, max - 3).trimEnd()}...` : text;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function plural(word, count) {
|
|
351
|
+
return count === 1 ? word : `${word}s`;
|
|
352
|
+
}
|
|
353
|
+
|
|
99
354
|
function toolUseParts(content) {
|
|
100
355
|
return arrayContent(content).filter((part) => {
|
|
101
356
|
const type = String(part?.type || part?.kind || "").toLowerCase();
|
|
@@ -137,6 +392,14 @@ function thinkingText(content) {
|
|
|
137
392
|
.trim();
|
|
138
393
|
}
|
|
139
394
|
|
|
395
|
+
function rememberToolCalls(context, toolCalls) {
|
|
396
|
+
if (!context || !toolCalls.length) return;
|
|
397
|
+
if (!context.claudeToolNamesById) context.claudeToolNamesById = new Map();
|
|
398
|
+
for (const call of toolCalls) {
|
|
399
|
+
if (call.id && call.name) context.claudeToolNamesById.set(call.id, call.name);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
140
403
|
function normalizeToolCall(part, provider) {
|
|
141
404
|
const rawName = firstString(part.name, part.tool_name, part.toolName, part.function?.name, "tool");
|
|
142
405
|
const rawArgs = parseArgs(part.input ?? part.arguments ?? part.args ?? part.function?.arguments);
|
|
@@ -170,14 +433,16 @@ function normalizeToolCall(part, provider) {
|
|
|
170
433
|
};
|
|
171
434
|
}
|
|
172
435
|
|
|
173
|
-
function normalizeToolResult(part, provider,
|
|
174
|
-
const output = extractToolResultOutput(part,
|
|
436
|
+
function normalizeToolResult(part, provider, event, context = {}) {
|
|
437
|
+
const output = extractToolResultOutput(part, event?.toolUseResult);
|
|
175
438
|
if (!output) return null;
|
|
176
|
-
const
|
|
439
|
+
const id = firstString(part.tool_use_id, part.id, part.call_id, part.callId);
|
|
440
|
+
const name = firstString(part.name, part.tool_name, part.toolName, id ? context.claudeToolNamesById?.get(id) : "", "Tool output");
|
|
177
441
|
const category = toolCategory(name, part.type);
|
|
178
|
-
return {
|
|
442
|
+
return compactMetadata({
|
|
179
443
|
provider,
|
|
180
|
-
id:
|
|
444
|
+
id: id || undefined,
|
|
445
|
+
name,
|
|
181
446
|
kind: displayName(name),
|
|
182
447
|
title: part.is_error ? "Tool error" : "Tool result",
|
|
183
448
|
rawCategory: firstString(part.type, part.kind) || undefined,
|
|
@@ -187,8 +452,10 @@ function normalizeToolResult(part, provider, eventToolUseResult) {
|
|
|
187
452
|
output,
|
|
188
453
|
lineCount: output.split("\n").length,
|
|
189
454
|
collapsed: output.split("\n").length > 18,
|
|
190
|
-
status: part.is_error ? "error" : "completed"
|
|
191
|
-
|
|
455
|
+
status: part.is_error ? "error" : "completed",
|
|
456
|
+
sourceToolUseID: firstString(event?.sourceToolUseID, event?.source_tool_use_id) || undefined,
|
|
457
|
+
structuredContent: event?.mcpMeta?.structuredContent && typeof event.mcpMeta.structuredContent === "object" ? event.mcpMeta.structuredContent : undefined
|
|
458
|
+
});
|
|
192
459
|
}
|
|
193
460
|
|
|
194
461
|
function extractToolResultOutput(part, eventToolUseResult) {
|
|
@@ -204,13 +471,27 @@ function claudeUsage(usage) {
|
|
|
204
471
|
const cacheCreation = numberValue(usage.cache_creation_input_tokens, usage.cacheCreationInputTokens);
|
|
205
472
|
const cacheRead = numberValue(usage.cache_read_input_tokens, usage.cacheReadInputTokens);
|
|
206
473
|
if ([input, output, cacheCreation, cacheRead].every((value) => value == null)) return null;
|
|
207
|
-
|
|
474
|
+
const serverToolUse = compactMetadata({
|
|
475
|
+
webSearchRequests: numberValue(usage.server_tool_use?.web_search_requests, usage.serverToolUse?.webSearchRequests),
|
|
476
|
+
webFetchRequests: numberValue(usage.server_tool_use?.web_fetch_requests, usage.serverToolUse?.webFetchRequests)
|
|
477
|
+
});
|
|
478
|
+
const cacheCreationDetails = compactMetadata({
|
|
479
|
+
ephemeral1hInputTokens: numberValue(usage.cache_creation?.ephemeral_1h_input_tokens, usage.cacheCreation?.ephemeral1hInputTokens),
|
|
480
|
+
ephemeral5mInputTokens: numberValue(usage.cache_creation?.ephemeral_5m_input_tokens, usage.cacheCreation?.ephemeral5mInputTokens)
|
|
481
|
+
});
|
|
482
|
+
return compactMetadata({
|
|
208
483
|
inputTokens: input ?? undefined,
|
|
209
484
|
outputTokens: output ?? undefined,
|
|
210
485
|
cacheCreationInputTokens: cacheCreation ?? undefined,
|
|
211
486
|
cacheReadInputTokens: cacheRead ?? undefined,
|
|
212
|
-
totalTokens: [input, output, cacheCreation, cacheRead].reduce((sum, value) => sum + (value || 0), 0)
|
|
213
|
-
|
|
487
|
+
totalTokens: [input, output, cacheCreation, cacheRead].reduce((sum, value) => sum + (value || 0), 0),
|
|
488
|
+
serviceTier: firstString(usage.service_tier, usage.serviceTier) || undefined,
|
|
489
|
+
speed: firstString(usage.speed) || undefined,
|
|
490
|
+
inferenceGeo: firstString(usage.inference_geo, usage.inferenceGeo) || undefined,
|
|
491
|
+
serverToolUse: serverToolUse || undefined,
|
|
492
|
+
cacheCreation: cacheCreationDetails || undefined,
|
|
493
|
+
iterationCount: Array.isArray(usage.iterations) ? usage.iterations.length : undefined
|
|
494
|
+
});
|
|
214
495
|
}
|
|
215
496
|
|
|
216
497
|
function extractText(value, depth = 0) {
|
|
@@ -328,6 +609,11 @@ function numberValue(...values) {
|
|
|
328
609
|
return null;
|
|
329
610
|
}
|
|
330
611
|
|
|
612
|
+
function asStringArray(value) {
|
|
613
|
+
if (!Array.isArray(value)) return [];
|
|
614
|
+
return value.filter((item) => typeof item === "string" && item.trim()).map((item) => item.trim());
|
|
615
|
+
}
|
|
616
|
+
|
|
331
617
|
function firstString(...values) {
|
|
332
618
|
for (const value of values) {
|
|
333
619
|
if (typeof value === "string" && value.trim()) return value.trim();
|
|
@@ -339,6 +625,18 @@ function firstLine(value) {
|
|
|
339
625
|
return String(value || "").split(/\r?\n/).find((line) => line.trim())?.trim() || "";
|
|
340
626
|
}
|
|
341
627
|
|
|
628
|
+
function compactMetadata(value) {
|
|
629
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return value || null;
|
|
630
|
+
const result = {};
|
|
631
|
+
for (const [key, item] of Object.entries(value)) {
|
|
632
|
+
if (item === undefined || item === null || item === "") continue;
|
|
633
|
+
if (Array.isArray(item) && !item.length) continue;
|
|
634
|
+
if (item && typeof item === "object" && !Array.isArray(item) && !Object.keys(item).length) continue;
|
|
635
|
+
result[key] = item;
|
|
636
|
+
}
|
|
637
|
+
return Object.keys(result).length ? result : null;
|
|
638
|
+
}
|
|
639
|
+
|
|
342
640
|
function isClaudeProvider(provider) {
|
|
343
641
|
return provider === "claude_code" || provider === "claude_sdk" || provider === "claude_desktop";
|
|
344
642
|
}
|
package/src/importers/gemini.js
CHANGED
|
@@ -607,6 +607,7 @@ function geminiUsage(value) {
|
|
|
607
607
|
totalTokens,
|
|
608
608
|
thoughtsTokens,
|
|
609
609
|
cacheReadTokens,
|
|
610
|
+
cacheReadTokensIncludedInInput: cacheReadTokens ? true : undefined,
|
|
610
611
|
toolUsePromptTokens
|
|
611
612
|
});
|
|
612
613
|
return Object.keys(normalized).length ? normalized : null;
|
|
@@ -880,7 +881,7 @@ function geminiSessionSummaryUsage(summary) {
|
|
|
880
881
|
cacheInputTokens += numberValue(model.cacheReadTokens) || 0;
|
|
881
882
|
}
|
|
882
883
|
if (!inputTokens && !outputTokens && !cacheInputTokens) return null;
|
|
883
|
-
return { inputTokens, outputTokens, cacheInputTokens, totalTokens: inputTokens + outputTokens };
|
|
884
|
+
return { inputTokens, outputTokens, cacheInputTokens, cacheInputTokensIncludedInInput: cacheInputTokens ? true : undefined, totalTokens: inputTokens + outputTokens };
|
|
884
885
|
}
|
|
885
886
|
|
|
886
887
|
function mergeGeminiSessionSummaries(summaries) {
|
|
@@ -23,6 +23,21 @@ const PROVIDER_ADAPTERS = [
|
|
|
23
23
|
run: ({ helpers, since, options, env }) =>
|
|
24
24
|
helpers.importCodexProvider("codex", since, { ...options, codexSource: "vscode" }, env)
|
|
25
25
|
},
|
|
26
|
+
{
|
|
27
|
+
source: "codex-sdk",
|
|
28
|
+
provider: "codex",
|
|
29
|
+
sourceType: "codex-sdk-history",
|
|
30
|
+
label: "Codex SDK jobs",
|
|
31
|
+
run: ({ helpers, since, options, env }) =>
|
|
32
|
+
helpers.importCodexProvider("codex", since, { ...options, codexSource: "exec" }, env)
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
source: "chatgpt",
|
|
36
|
+
provider: "chatgpt",
|
|
37
|
+
label: "ChatGPT",
|
|
38
|
+
manual: true,
|
|
39
|
+
run: ({ helpers }) => helpers.manualImportInstructionResult("chatgpt")
|
|
40
|
+
},
|
|
26
41
|
{
|
|
27
42
|
source: "claude",
|
|
28
43
|
provider: "claude_code",
|
|
@@ -59,6 +74,13 @@ const PROVIDER_ADAPTERS = [
|
|
|
59
74
|
run: ({ helpers, since, options, env }) =>
|
|
60
75
|
helpers.importClaudeDesktopProvider("claude_desktop", since, { ...options, claudeDesktopKind: "claude-workspace-desktop" }, env)
|
|
61
76
|
},
|
|
77
|
+
{
|
|
78
|
+
source: "claude-web",
|
|
79
|
+
provider: "claude_web",
|
|
80
|
+
label: "Claude.ai",
|
|
81
|
+
manual: true,
|
|
82
|
+
run: ({ helpers }) => helpers.manualImportInstructionResult("claude-web")
|
|
83
|
+
},
|
|
62
84
|
{
|
|
63
85
|
source: "cursor",
|
|
64
86
|
provider: "cursor",
|