@adhdev/daemon-core 0.9.45 → 0.9.46
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/config/chat-history.d.ts +6 -4
- package/dist/index.js +190 -712
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +190 -712
- package/dist/index.mjs.map +1 -1
- package/dist/providers/cli-provider-instance.d.ts +2 -7
- package/dist/providers/contracts.d.ts +23 -14
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/commands/chat-commands.ts +1 -0
- package/src/commands/router.ts +4 -0
- package/src/config/chat-history.ts +161 -680
- package/src/providers/cli-provider-instance.ts +32 -70
- package/src/providers/contracts.ts +24 -14
- package/src/providers/provider-schema.ts +40 -0
package/dist/index.mjs
CHANGED
|
@@ -8007,29 +8007,6 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
8007
8007
|
return { sessions: [], hasMore: false };
|
|
8008
8008
|
}
|
|
8009
8009
|
}
|
|
8010
|
-
function normalizeCanonicalHermesMessageContent(content) {
|
|
8011
|
-
if (typeof content === "string") return content.trim();
|
|
8012
|
-
if (content == null) return "";
|
|
8013
|
-
try {
|
|
8014
|
-
return JSON.stringify(content).trim();
|
|
8015
|
-
} catch {
|
|
8016
|
-
return String(content).trim();
|
|
8017
|
-
}
|
|
8018
|
-
}
|
|
8019
|
-
function extractCanonicalHermesMessageTimestamp(message, fallbackTs) {
|
|
8020
|
-
const numericTimestamp = Number(message.receivedAt || message.timestamp || message.ts || 0);
|
|
8021
|
-
if (Number.isFinite(numericTimestamp) && numericTimestamp > 0) return numericTimestamp;
|
|
8022
|
-
const stringTimestamp = typeof message.ts === "string" ? Date.parse(message.ts) : typeof message.timestamp === "string" ? Date.parse(message.timestamp) : NaN;
|
|
8023
|
-
if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
|
|
8024
|
-
return fallbackTs;
|
|
8025
|
-
}
|
|
8026
|
-
function extractTimestampValue(value) {
|
|
8027
|
-
const numericTimestamp = Number(value || 0);
|
|
8028
|
-
if (Number.isFinite(numericTimestamp) && numericTimestamp > 0) return numericTimestamp;
|
|
8029
|
-
const stringTimestamp = typeof value === "string" ? Date.parse(value) : NaN;
|
|
8030
|
-
if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
|
|
8031
|
-
return 0;
|
|
8032
|
-
}
|
|
8033
8010
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
8034
8011
|
try {
|
|
8035
8012
|
const dir = path7.join(HISTORY_DIR, agentType);
|
|
@@ -8075,569 +8052,77 @@ function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
|
8075
8052
|
return false;
|
|
8076
8053
|
}
|
|
8077
8054
|
}
|
|
8078
|
-
function
|
|
8079
|
-
const
|
|
8080
|
-
if (
|
|
8081
|
-
|
|
8082
|
-
const sessionFilePath = path7.join(os5.homedir(), ".hermes", "sessions", `session_${normalizedSessionId}.json`);
|
|
8083
|
-
if (!fs3.existsSync(sessionFilePath)) return null;
|
|
8084
|
-
const raw = JSON.parse(fs3.readFileSync(sessionFilePath, "utf-8"));
|
|
8085
|
-
const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
|
|
8086
|
-
const records = [];
|
|
8087
|
-
let fallbackTs = Date.parse(raw.session_start || raw.last_updated || "") || Date.now();
|
|
8088
|
-
for (const message of canonicalMessages) {
|
|
8089
|
-
const role = String(message.role || "").trim();
|
|
8090
|
-
const content = normalizeCanonicalHermesMessageContent(message.content);
|
|
8091
|
-
if (!content) continue;
|
|
8092
|
-
const receivedAt = extractCanonicalHermesMessageTimestamp(message, fallbackTs);
|
|
8093
|
-
fallbackTs = receivedAt + 1;
|
|
8094
|
-
if (role === "user" || role === "assistant") {
|
|
8095
|
-
records.push({
|
|
8096
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8097
|
-
receivedAt,
|
|
8098
|
-
role,
|
|
8099
|
-
content,
|
|
8100
|
-
kind: "standard",
|
|
8101
|
-
agent: "hermes-cli",
|
|
8102
|
-
historySessionId: normalizedSessionId
|
|
8103
|
-
});
|
|
8104
|
-
continue;
|
|
8105
|
-
}
|
|
8106
|
-
if (role === "tool") {
|
|
8107
|
-
records.push({
|
|
8108
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8109
|
-
receivedAt,
|
|
8110
|
-
role: "assistant",
|
|
8111
|
-
content,
|
|
8112
|
-
kind: "tool",
|
|
8113
|
-
senderName: "Tool",
|
|
8114
|
-
agent: "hermes-cli",
|
|
8115
|
-
historySessionId: normalizedSessionId
|
|
8116
|
-
});
|
|
8117
|
-
}
|
|
8118
|
-
}
|
|
8119
|
-
return records;
|
|
8120
|
-
} catch {
|
|
8121
|
-
return null;
|
|
8122
|
-
}
|
|
8123
|
-
}
|
|
8124
|
-
function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
|
|
8125
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8126
|
-
if (!normalizedSessionId) return false;
|
|
8127
|
-
try {
|
|
8128
|
-
const sessionFilePath = path7.join(os5.homedir(), ".hermes", "sessions", `session_${normalizedSessionId}.json`);
|
|
8129
|
-
if (!fs3.existsSync(sessionFilePath)) return false;
|
|
8130
|
-
const raw = JSON.parse(fs3.readFileSync(sessionFilePath, "utf-8"));
|
|
8131
|
-
const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
|
|
8132
|
-
const dir = path7.join(HISTORY_DIR, "hermes-cli");
|
|
8133
|
-
fs3.mkdirSync(dir, { recursive: true });
|
|
8134
|
-
const existingSessionStart = readExistingSessionStartRecord("hermes-cli", normalizedSessionId);
|
|
8135
|
-
const records = [];
|
|
8136
|
-
if (existingSessionStart) {
|
|
8137
|
-
records.push({
|
|
8138
|
-
...existingSessionStart,
|
|
8139
|
-
historySessionId: normalizedSessionId
|
|
8140
|
-
});
|
|
8141
|
-
}
|
|
8142
|
-
let fallbackTs = Date.parse(raw.session_start || raw.last_updated || "") || Date.now();
|
|
8143
|
-
for (const message of canonicalMessages) {
|
|
8144
|
-
const role = String(message.role || "").trim();
|
|
8145
|
-
const content = normalizeCanonicalHermesMessageContent(message.content);
|
|
8146
|
-
if (!content) continue;
|
|
8147
|
-
const receivedAt = extractCanonicalHermesMessageTimestamp(message, fallbackTs);
|
|
8148
|
-
fallbackTs = receivedAt + 1;
|
|
8149
|
-
if (role === "user") {
|
|
8150
|
-
records.push({
|
|
8151
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8152
|
-
receivedAt,
|
|
8153
|
-
role: "user",
|
|
8154
|
-
content,
|
|
8155
|
-
kind: "standard",
|
|
8156
|
-
agent: "hermes-cli",
|
|
8157
|
-
historySessionId: normalizedSessionId
|
|
8158
|
-
});
|
|
8159
|
-
continue;
|
|
8160
|
-
}
|
|
8161
|
-
if (role === "assistant") {
|
|
8162
|
-
records.push({
|
|
8163
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8164
|
-
receivedAt,
|
|
8165
|
-
role: "assistant",
|
|
8166
|
-
content,
|
|
8167
|
-
kind: "standard",
|
|
8168
|
-
agent: "hermes-cli",
|
|
8169
|
-
historySessionId: normalizedSessionId
|
|
8170
|
-
});
|
|
8171
|
-
continue;
|
|
8172
|
-
}
|
|
8173
|
-
if (role === "tool") {
|
|
8174
|
-
records.push({
|
|
8175
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8176
|
-
receivedAt,
|
|
8177
|
-
role: "assistant",
|
|
8178
|
-
content,
|
|
8179
|
-
kind: "tool",
|
|
8180
|
-
senderName: "Tool",
|
|
8181
|
-
agent: "hermes-cli",
|
|
8182
|
-
historySessionId: normalizedSessionId
|
|
8183
|
-
});
|
|
8184
|
-
}
|
|
8185
|
-
}
|
|
8186
|
-
return rewriteCanonicalSavedHistory("hermes-cli", normalizedSessionId, records);
|
|
8187
|
-
} catch {
|
|
8188
|
-
return false;
|
|
8189
|
-
}
|
|
8190
|
-
}
|
|
8191
|
-
function resolveClaudeProjectTranscriptPath(historySessionId, workspace) {
|
|
8192
|
-
const claudeProjectsDir = path7.join(os5.homedir(), ".claude", "projects");
|
|
8193
|
-
if (!fs3.existsSync(claudeProjectsDir)) return null;
|
|
8194
|
-
const normalizedWorkspace = typeof workspace === "string" ? workspace.trim() : "";
|
|
8195
|
-
if (normalizedWorkspace) {
|
|
8196
|
-
const directPath = path7.join(claudeProjectsDir, normalizedWorkspace.replace(/[\\/]/g, "-"), `${historySessionId}.jsonl`);
|
|
8197
|
-
if (fs3.existsSync(directPath)) return directPath;
|
|
8198
|
-
}
|
|
8199
|
-
const stack = [claudeProjectsDir];
|
|
8200
|
-
while (stack.length > 0) {
|
|
8201
|
-
const current = stack.pop();
|
|
8202
|
-
if (!current) continue;
|
|
8203
|
-
for (const entry of fs3.readdirSync(current, { withFileTypes: true })) {
|
|
8204
|
-
const entryPath = path7.join(current, entry.name);
|
|
8205
|
-
if (entry.isDirectory()) {
|
|
8206
|
-
stack.push(entryPath);
|
|
8207
|
-
continue;
|
|
8208
|
-
}
|
|
8209
|
-
if (entry.isFile() && entry.name === `${historySessionId}.jsonl`) {
|
|
8210
|
-
return entryPath;
|
|
8211
|
-
}
|
|
8212
|
-
}
|
|
8213
|
-
}
|
|
8214
|
-
return null;
|
|
8215
|
-
}
|
|
8216
|
-
function extractClaudeAssistantContentParts(content) {
|
|
8217
|
-
if (typeof content === "string") {
|
|
8218
|
-
const trimmed = content.trim();
|
|
8219
|
-
return trimmed ? [{ content: trimmed, kind: "standard", role: "assistant" }] : [];
|
|
8220
|
-
}
|
|
8221
|
-
if (!Array.isArray(content)) return [];
|
|
8222
|
-
const parts = [];
|
|
8223
|
-
for (const block of content) {
|
|
8224
|
-
if (!block || typeof block !== "object") continue;
|
|
8225
|
-
const record = block;
|
|
8226
|
-
const type = String(record.type || "").trim();
|
|
8227
|
-
if (type === "text") {
|
|
8228
|
-
const text = String(record.text || "").trim();
|
|
8229
|
-
if (text) parts.push({ content: text, kind: "standard", role: "assistant" });
|
|
8230
|
-
continue;
|
|
8231
|
-
}
|
|
8232
|
-
if (type === "tool_use") {
|
|
8233
|
-
const name = String(record.name || "").trim() || "Tool";
|
|
8234
|
-
const input = record.input && typeof record.input === "object" ? record.input : null;
|
|
8235
|
-
const command = input ? String(input.command || "").trim() : "";
|
|
8236
|
-
const summary = command ? `${name}: ${command}` : name;
|
|
8237
|
-
if (summary) parts.push({ content: summary, kind: "tool", senderName: "Tool", role: "assistant" });
|
|
8238
|
-
}
|
|
8239
|
-
}
|
|
8240
|
-
return parts;
|
|
8241
|
-
}
|
|
8242
|
-
function extractClaudeUserContentParts(content) {
|
|
8243
|
-
if (typeof content === "string") {
|
|
8244
|
-
const trimmed = content.trim();
|
|
8245
|
-
return trimmed ? [{ role: "user", content: trimmed, kind: "standard" }] : [];
|
|
8246
|
-
}
|
|
8247
|
-
if (!Array.isArray(content)) return [];
|
|
8248
|
-
const parts = [];
|
|
8249
|
-
for (const block of content) {
|
|
8250
|
-
if (!block || typeof block !== "object") continue;
|
|
8251
|
-
const record = block;
|
|
8252
|
-
const type = String(record.type || "").trim();
|
|
8253
|
-
if (type === "text") {
|
|
8254
|
-
const text = String(record.text || "").trim();
|
|
8255
|
-
if (text) parts.push({ role: "user", content: text, kind: "standard" });
|
|
8256
|
-
continue;
|
|
8257
|
-
}
|
|
8258
|
-
if (type === "tool_result") {
|
|
8259
|
-
const rawContent = record.content;
|
|
8260
|
-
const text = typeof rawContent === "string" ? rawContent.trim() : Array.isArray(rawContent) ? rawContent.map((entry) => {
|
|
8261
|
-
if (typeof entry === "string") return entry.trim();
|
|
8262
|
-
if (!entry || typeof entry !== "object") return "";
|
|
8263
|
-
const nested = entry;
|
|
8264
|
-
if (typeof nested.text === "string") return nested.text.trim();
|
|
8265
|
-
if (typeof nested.content === "string") return nested.content.trim();
|
|
8266
|
-
return "";
|
|
8267
|
-
}).filter(Boolean).join("\n") : "";
|
|
8268
|
-
if (text) parts.push({ role: "assistant", content: text, kind: "tool", senderName: "Tool" });
|
|
8269
|
-
}
|
|
8270
|
-
}
|
|
8271
|
-
return parts;
|
|
8272
|
-
}
|
|
8273
|
-
function buildClaudeNativeHistoryRecords(historySessionId, workspace) {
|
|
8274
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8275
|
-
if (!normalizedSessionId) return null;
|
|
8276
|
-
try {
|
|
8277
|
-
const transcriptPath = resolveClaudeProjectTranscriptPath(normalizedSessionId, workspace);
|
|
8278
|
-
if (!transcriptPath) return null;
|
|
8279
|
-
const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
|
|
8280
|
-
const records = [];
|
|
8281
|
-
let fallbackTs = Date.now();
|
|
8282
|
-
for (const line of lines) {
|
|
8283
|
-
let parsed = null;
|
|
8284
|
-
try {
|
|
8285
|
-
parsed = JSON.parse(line);
|
|
8286
|
-
} catch {
|
|
8287
|
-
parsed = null;
|
|
8288
|
-
}
|
|
8289
|
-
if (!parsed) continue;
|
|
8290
|
-
const parsedSessionId = String(parsed.sessionId || "").trim();
|
|
8291
|
-
if (parsedSessionId && parsedSessionId !== normalizedSessionId) continue;
|
|
8292
|
-
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
8293
|
-
fallbackTs = receivedAt + 1;
|
|
8294
|
-
const parsedWorkspace = String(parsed.cwd || workspace || "").trim();
|
|
8295
|
-
if (records.length === 0 && parsedWorkspace) {
|
|
8296
|
-
records.push({
|
|
8297
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8298
|
-
receivedAt,
|
|
8299
|
-
role: "system",
|
|
8300
|
-
kind: "session_start",
|
|
8301
|
-
content: parsedWorkspace,
|
|
8302
|
-
agent: "claude-cli",
|
|
8303
|
-
historySessionId: normalizedSessionId,
|
|
8304
|
-
workspace: parsedWorkspace
|
|
8305
|
-
});
|
|
8306
|
-
}
|
|
8307
|
-
const type = String(parsed.type || "").trim();
|
|
8308
|
-
const message = parsed.message && typeof parsed.message === "object" ? parsed.message : null;
|
|
8309
|
-
if (type === "user" && message) {
|
|
8310
|
-
for (const part of extractClaudeUserContentParts(message.content)) {
|
|
8311
|
-
records.push({
|
|
8312
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8313
|
-
receivedAt,
|
|
8314
|
-
role: part.role,
|
|
8315
|
-
content: part.content,
|
|
8316
|
-
kind: part.kind,
|
|
8317
|
-
senderName: part.senderName,
|
|
8318
|
-
agent: "claude-cli",
|
|
8319
|
-
historySessionId: normalizedSessionId
|
|
8320
|
-
});
|
|
8321
|
-
}
|
|
8322
|
-
continue;
|
|
8323
|
-
}
|
|
8324
|
-
if (type === "assistant" && message) {
|
|
8325
|
-
for (const part of extractClaudeAssistantContentParts(message.content)) {
|
|
8326
|
-
records.push({
|
|
8327
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8328
|
-
receivedAt,
|
|
8329
|
-
role: "assistant",
|
|
8330
|
-
content: part.content,
|
|
8331
|
-
kind: part.kind,
|
|
8332
|
-
senderName: part.senderName,
|
|
8333
|
-
agent: "claude-cli",
|
|
8334
|
-
historySessionId: normalizedSessionId
|
|
8335
|
-
});
|
|
8336
|
-
}
|
|
8337
|
-
}
|
|
8338
|
-
}
|
|
8339
|
-
return records;
|
|
8340
|
-
} catch {
|
|
8341
|
-
return null;
|
|
8342
|
-
}
|
|
8343
|
-
}
|
|
8344
|
-
function rebuildClaudeSavedHistoryFromNativeProject(historySessionId, workspace) {
|
|
8345
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8346
|
-
if (!normalizedSessionId) return false;
|
|
8347
|
-
try {
|
|
8348
|
-
const transcriptPath = resolveClaudeProjectTranscriptPath(normalizedSessionId, workspace);
|
|
8349
|
-
if (!transcriptPath) return false;
|
|
8350
|
-
const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
|
|
8351
|
-
const records = [];
|
|
8352
|
-
const existingSessionStart = readExistingSessionStartRecord("claude-cli", normalizedSessionId);
|
|
8353
|
-
if (existingSessionStart) {
|
|
8354
|
-
records.push({
|
|
8355
|
-
...existingSessionStart,
|
|
8356
|
-
historySessionId: normalizedSessionId
|
|
8357
|
-
});
|
|
8358
|
-
}
|
|
8359
|
-
let fallbackTs = Date.now();
|
|
8360
|
-
for (const line of lines) {
|
|
8361
|
-
let parsed = null;
|
|
8362
|
-
try {
|
|
8363
|
-
parsed = JSON.parse(line);
|
|
8364
|
-
} catch {
|
|
8365
|
-
parsed = null;
|
|
8366
|
-
}
|
|
8367
|
-
if (!parsed) continue;
|
|
8368
|
-
const parsedSessionId = String(parsed.sessionId || "").trim();
|
|
8369
|
-
if (parsedSessionId && parsedSessionId !== normalizedSessionId) continue;
|
|
8370
|
-
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
8371
|
-
fallbackTs = receivedAt + 1;
|
|
8372
|
-
const parsedWorkspace = String(parsed.cwd || workspace || "").trim();
|
|
8373
|
-
if (records.length === 0 && parsedWorkspace) {
|
|
8374
|
-
records.push({
|
|
8375
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8376
|
-
receivedAt,
|
|
8377
|
-
role: "system",
|
|
8378
|
-
kind: "session_start",
|
|
8379
|
-
content: parsedWorkspace,
|
|
8380
|
-
agent: "claude-cli",
|
|
8381
|
-
historySessionId: normalizedSessionId,
|
|
8382
|
-
workspace: parsedWorkspace
|
|
8383
|
-
});
|
|
8384
|
-
}
|
|
8385
|
-
const type = String(parsed.type || "").trim();
|
|
8386
|
-
const message = parsed.message && typeof parsed.message === "object" ? parsed.message : null;
|
|
8387
|
-
if (type === "user" && message) {
|
|
8388
|
-
for (const part of extractClaudeUserContentParts(message.content)) {
|
|
8389
|
-
records.push({
|
|
8390
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8391
|
-
receivedAt,
|
|
8392
|
-
role: part.role,
|
|
8393
|
-
content: part.content,
|
|
8394
|
-
kind: part.kind,
|
|
8395
|
-
senderName: part.senderName,
|
|
8396
|
-
agent: "claude-cli",
|
|
8397
|
-
historySessionId: normalizedSessionId
|
|
8398
|
-
});
|
|
8399
|
-
}
|
|
8400
|
-
continue;
|
|
8401
|
-
}
|
|
8402
|
-
if (type === "assistant" && message) {
|
|
8403
|
-
for (const part of extractClaudeAssistantContentParts(message.content)) {
|
|
8404
|
-
records.push({
|
|
8405
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8406
|
-
receivedAt,
|
|
8407
|
-
role: "assistant",
|
|
8408
|
-
content: part.content,
|
|
8409
|
-
kind: part.kind,
|
|
8410
|
-
senderName: part.senderName,
|
|
8411
|
-
agent: "claude-cli",
|
|
8412
|
-
historySessionId: normalizedSessionId
|
|
8413
|
-
});
|
|
8414
|
-
}
|
|
8415
|
-
}
|
|
8416
|
-
}
|
|
8417
|
-
return rewriteCanonicalSavedHistory("claude-cli", normalizedSessionId, records);
|
|
8418
|
-
} catch {
|
|
8419
|
-
return false;
|
|
8420
|
-
}
|
|
8421
|
-
}
|
|
8422
|
-
function isUuidLikeSessionId(sessionId) {
|
|
8423
|
-
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);
|
|
8055
|
+
function getNativeHistoryScriptName(canonicalHistory, key) {
|
|
8056
|
+
const configured = canonicalHistory?.scripts?.[key];
|
|
8057
|
+
if (typeof configured === "string" && configured.trim()) return configured.trim();
|
|
8058
|
+
return key === "readSession" ? "readNativeHistory" : "listNativeHistory";
|
|
8424
8059
|
}
|
|
8425
|
-
function
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
const parsed = JSON.parse(firstLine);
|
|
8430
|
-
if (String(parsed.type || "") !== "session_meta") return null;
|
|
8431
|
-
const payload = parsed.payload && typeof parsed.payload === "object" ? parsed.payload : null;
|
|
8432
|
-
return payload;
|
|
8433
|
-
} catch {
|
|
8434
|
-
return null;
|
|
8435
|
-
}
|
|
8060
|
+
function getProviderNativeHistoryScript(scripts, canonicalHistory, key) {
|
|
8061
|
+
if (!canonicalHistory?.scripts) return null;
|
|
8062
|
+
const fn = scripts?.[getNativeHistoryScriptName(canonicalHistory, key)];
|
|
8063
|
+
return typeof fn === "function" ? fn : null;
|
|
8436
8064
|
}
|
|
8437
|
-
function
|
|
8065
|
+
function normalizeProviderNativeHistoryRecords(agentType, historySessionId, records) {
|
|
8066
|
+
if (!Array.isArray(records)) return [];
|
|
8438
8067
|
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8459
|
-
|
|
8460
|
-
|
|
8461
|
-
|
|
8462
|
-
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
workspaceMatches: !!normalizedWorkspace && metaWorkspace === normalizedWorkspace,
|
|
8474
|
-
metaMatches: metaSessionId === normalizedSessionId
|
|
8475
|
-
});
|
|
8476
|
-
}
|
|
8477
|
-
}
|
|
8478
|
-
candidates.sort((a, b) => Number(b.workspaceMatches) - Number(a.workspaceMatches) || Number(b.metaMatches) - Number(a.metaMatches) || b.mtimeMs - a.mtimeMs);
|
|
8479
|
-
return candidates[0]?.path || null;
|
|
8480
|
-
}
|
|
8481
|
-
function flattenCodexContent(content) {
|
|
8482
|
-
if (typeof content === "string") return content.trim();
|
|
8483
|
-
if (content == null) return "";
|
|
8484
|
-
if (Array.isArray(content)) {
|
|
8485
|
-
return content.map((entry) => flattenCodexContent(entry)).filter(Boolean).join("\n").trim();
|
|
8486
|
-
}
|
|
8487
|
-
if (typeof content === "object") {
|
|
8488
|
-
const record = content;
|
|
8489
|
-
if (typeof record.text === "string") return record.text.trim();
|
|
8490
|
-
if (typeof record.content === "string" || Array.isArray(record.content)) return flattenCodexContent(record.content);
|
|
8491
|
-
if (typeof record.output === "string") return record.output.trim();
|
|
8492
|
-
if (typeof record.message === "string") return record.message.trim();
|
|
8493
|
-
}
|
|
8494
|
-
return "";
|
|
8495
|
-
}
|
|
8496
|
-
function summarizeCodexToolCall(payload) {
|
|
8497
|
-
const name = String(payload.name || payload.type || "tool").trim() || "tool";
|
|
8498
|
-
const rawArguments = payload.arguments ?? payload.input;
|
|
8499
|
-
let argumentValue = "";
|
|
8500
|
-
if (typeof rawArguments === "string") {
|
|
8501
|
-
const trimmed = rawArguments.trim();
|
|
8502
|
-
try {
|
|
8503
|
-
const parsed = JSON.parse(trimmed);
|
|
8504
|
-
argumentValue = summarizeCodexToolArguments(parsed);
|
|
8505
|
-
} catch {
|
|
8506
|
-
argumentValue = trimmed;
|
|
8507
|
-
}
|
|
8508
|
-
} else {
|
|
8509
|
-
argumentValue = summarizeCodexToolArguments(rawArguments);
|
|
8510
|
-
}
|
|
8511
|
-
return argumentValue ? `${name}: ${argumentValue}` : name;
|
|
8512
|
-
}
|
|
8513
|
-
function summarizeCodexToolArguments(value) {
|
|
8514
|
-
if (typeof value === "string") return value.trim();
|
|
8515
|
-
if (Array.isArray(value)) return value.map((entry) => String(entry)).join(" ").trim();
|
|
8516
|
-
if (!value || typeof value !== "object") return "";
|
|
8517
|
-
const record = value;
|
|
8518
|
-
const direct = record.command || record.cmd || record.query || record.path || record.prompt;
|
|
8519
|
-
if (typeof direct === "string") return direct.trim();
|
|
8520
|
-
if (Array.isArray(direct)) return direct.map((entry) => String(entry)).join(" ").trim();
|
|
8521
|
-
try {
|
|
8522
|
-
return JSON.stringify(record).trim();
|
|
8523
|
-
} catch {
|
|
8524
|
-
return "";
|
|
8525
|
-
}
|
|
8068
|
+
return records.map((record) => sanitizeHistoryMessage(agentType, {
|
|
8069
|
+
ts: typeof record?.ts === "string" ? record.ts : new Date(Number(record?.receivedAt) || Date.now()).toISOString(),
|
|
8070
|
+
receivedAt: Number(record?.receivedAt) || Date.parse(record?.ts || "") || Date.now(),
|
|
8071
|
+
role: record?.role,
|
|
8072
|
+
content: String(record?.content || ""),
|
|
8073
|
+
kind: record?.kind || (record?.role === "system" ? "session_start" : "standard"),
|
|
8074
|
+
senderName: record?.senderName,
|
|
8075
|
+
agent: agentType,
|
|
8076
|
+
instanceId: record?.instanceId,
|
|
8077
|
+
historySessionId: normalizeSavedHistorySessionId(record?.historySessionId || normalizedSessionId),
|
|
8078
|
+
sessionTitle: record?.sessionTitle,
|
|
8079
|
+
workspace: record?.workspace
|
|
8080
|
+
})).filter(Boolean);
|
|
8081
|
+
}
|
|
8082
|
+
function callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, historySessionId, workspace) {
|
|
8083
|
+
const fn = getProviderNativeHistoryScript(scripts, canonicalHistory, "readSession");
|
|
8084
|
+
if (!fn) return null;
|
|
8085
|
+
const result = fn({
|
|
8086
|
+
agentType,
|
|
8087
|
+
sessionId: historySessionId,
|
|
8088
|
+
historySessionId,
|
|
8089
|
+
workspace,
|
|
8090
|
+
format: canonicalHistory?.format,
|
|
8091
|
+
watchPath: canonicalHistory?.watchPath,
|
|
8092
|
+
args: { sessionId: historySessionId, historySessionId, workspace }
|
|
8093
|
+
});
|
|
8094
|
+
if (!result || typeof result !== "object") return null;
|
|
8095
|
+
const records = normalizeProviderNativeHistoryRecords(agentType, historySessionId, result.messages || result.records);
|
|
8096
|
+
if (records.length === 0) return null;
|
|
8097
|
+
return {
|
|
8098
|
+
records,
|
|
8099
|
+
sourcePath: typeof result.sourcePath === "string" ? result.sourcePath : "",
|
|
8100
|
+
sourceMtimeMs: Number(result.sourceMtimeMs) || 0
|
|
8101
|
+
};
|
|
8526
8102
|
}
|
|
8527
|
-
function
|
|
8528
|
-
const
|
|
8529
|
-
|
|
8530
|
-
|
|
8531
|
-
if (output && typeof output === "object") {
|
|
8532
|
-
try {
|
|
8533
|
-
return JSON.stringify(output).trim();
|
|
8534
|
-
} catch {
|
|
8535
|
-
return "";
|
|
8536
|
-
}
|
|
8537
|
-
}
|
|
8538
|
-
return "";
|
|
8103
|
+
function buildNativeHistoryReadResult(agentType, canonicalHistory, scripts, historySessionId, workspace) {
|
|
8104
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || "");
|
|
8105
|
+
if (!canonicalHistory || !normalizedSessionId || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
|
|
8106
|
+
return callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace);
|
|
8539
8107
|
}
|
|
8540
|
-
function
|
|
8108
|
+
function materializeNativeHistoryToMirror(agentType, canonicalHistory, historySessionId, workspace, scripts) {
|
|
8541
8109
|
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8542
|
-
if (!normalizedSessionId
|
|
8543
|
-
|
|
8544
|
-
|
|
8545
|
-
|
|
8546
|
-
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
|
|
8550
|
-
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
parsed = null;
|
|
8555
|
-
}
|
|
8556
|
-
if (!parsed) continue;
|
|
8557
|
-
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
8558
|
-
fallbackTs = receivedAt + 1;
|
|
8559
|
-
const type = String(parsed.type || "").trim();
|
|
8560
|
-
const payload = parsed.payload && typeof parsed.payload === "object" ? parsed.payload : null;
|
|
8561
|
-
if (!payload) continue;
|
|
8562
|
-
if (type === "session_meta") {
|
|
8563
|
-
const parsedSessionId = String(payload.id || "").trim();
|
|
8564
|
-
if (parsedSessionId && parsedSessionId !== normalizedSessionId) return null;
|
|
8565
|
-
const parsedWorkspace = String(payload.cwd || workspace || "").trim();
|
|
8566
|
-
if (records.length === 0 && parsedWorkspace) {
|
|
8567
|
-
records.push({
|
|
8568
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8569
|
-
receivedAt,
|
|
8570
|
-
role: "system",
|
|
8571
|
-
kind: "session_start",
|
|
8572
|
-
content: parsedWorkspace,
|
|
8573
|
-
agent: "codex-cli",
|
|
8574
|
-
historySessionId: normalizedSessionId,
|
|
8575
|
-
workspace: parsedWorkspace
|
|
8576
|
-
});
|
|
8577
|
-
}
|
|
8578
|
-
continue;
|
|
8579
|
-
}
|
|
8580
|
-
if (type !== "response_item") continue;
|
|
8581
|
-
const payloadType = String(payload.type || "").trim();
|
|
8582
|
-
if (payloadType === "message") {
|
|
8583
|
-
const role = String(payload.role || "").trim();
|
|
8584
|
-
if (role !== "user" && role !== "assistant") continue;
|
|
8585
|
-
const content = flattenCodexContent(payload.content);
|
|
8586
|
-
if (!content) continue;
|
|
8587
|
-
records.push({
|
|
8588
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8589
|
-
receivedAt,
|
|
8590
|
-
role,
|
|
8591
|
-
content,
|
|
8592
|
-
kind: "standard",
|
|
8593
|
-
agent: "codex-cli",
|
|
8594
|
-
historySessionId: normalizedSessionId
|
|
8595
|
-
});
|
|
8596
|
-
continue;
|
|
8597
|
-
}
|
|
8598
|
-
if (payloadType === "function_call" || payloadType === "custom_tool_call") {
|
|
8599
|
-
const content = summarizeCodexToolCall(payload);
|
|
8600
|
-
if (!content) continue;
|
|
8601
|
-
records.push({
|
|
8602
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8603
|
-
receivedAt,
|
|
8604
|
-
role: "assistant",
|
|
8605
|
-
content,
|
|
8606
|
-
kind: "tool",
|
|
8607
|
-
senderName: "Tool",
|
|
8608
|
-
agent: "codex-cli",
|
|
8609
|
-
historySessionId: normalizedSessionId
|
|
8610
|
-
});
|
|
8611
|
-
continue;
|
|
8612
|
-
}
|
|
8613
|
-
if (payloadType === "function_call_output" || payloadType === "custom_tool_call_output") {
|
|
8614
|
-
const content = codexToolOutputContent(payload);
|
|
8615
|
-
if (!content) continue;
|
|
8616
|
-
records.push({
|
|
8617
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8618
|
-
receivedAt,
|
|
8619
|
-
role: "assistant",
|
|
8620
|
-
content,
|
|
8621
|
-
kind: "tool",
|
|
8622
|
-
senderName: "Tool",
|
|
8623
|
-
agent: "codex-cli",
|
|
8624
|
-
historySessionId: normalizedSessionId
|
|
8625
|
-
});
|
|
8626
|
-
}
|
|
8627
|
-
}
|
|
8628
|
-
return records;
|
|
8629
|
-
} catch {
|
|
8630
|
-
return null;
|
|
8631
|
-
}
|
|
8110
|
+
if (!normalizedSessionId) return false;
|
|
8111
|
+
const nativeResult = callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace);
|
|
8112
|
+
const nativeRecords = nativeResult?.records || [];
|
|
8113
|
+
if (nativeRecords.length === 0) return false;
|
|
8114
|
+
const normalizedRecords = nativeRecords.map((record) => ({
|
|
8115
|
+
...record,
|
|
8116
|
+
agent: agentType,
|
|
8117
|
+
historySessionId: normalizedSessionId
|
|
8118
|
+
}));
|
|
8119
|
+
const existingSessionStart = readExistingSessionStartRecord(agentType, normalizedSessionId);
|
|
8120
|
+
const records = existingSessionStart && normalizedRecords[0]?.kind !== "session_start" ? [{ ...existingSessionStart, historySessionId: normalizedSessionId, agent: agentType }, ...normalizedRecords] : normalizedRecords;
|
|
8121
|
+
return rewriteCanonicalSavedHistory(agentType, normalizedSessionId, records);
|
|
8632
8122
|
}
|
|
8633
|
-
function
|
|
8634
|
-
|
|
8635
|
-
|
|
8636
|
-
const records = buildCodexNativeHistoryRecords(normalizedSessionId, workspace);
|
|
8637
|
-
if (!records || records.length === 0) return false;
|
|
8638
|
-
const existingSessionStart = readExistingSessionStartRecord("codex-cli", normalizedSessionId);
|
|
8639
|
-
const recordsToWrite = existingSessionStart && records[0]?.kind !== "session_start" ? [{ ...existingSessionStart, historySessionId: normalizedSessionId }, ...records] : records;
|
|
8640
|
-
return rewriteCanonicalSavedHistory("codex-cli", normalizedSessionId, recordsToWrite);
|
|
8123
|
+
function materializeProviderNativeHistory(agentType, canonicalHistory, historySessionId, workspace, scripts) {
|
|
8124
|
+
if (!canonicalHistory || canonicalHistory.mode !== "materialized-mirror") return false;
|
|
8125
|
+
return materializeNativeHistoryToMirror(agentType, canonicalHistory, historySessionId, workspace, scripts);
|
|
8641
8126
|
}
|
|
8642
8127
|
function isNativeSourceCanonicalHistory(canonicalHistory) {
|
|
8643
8128
|
if (!canonicalHistory) return false;
|
|
@@ -8645,21 +8130,15 @@ function isNativeSourceCanonicalHistory(canonicalHistory) {
|
|
|
8645
8130
|
if (canonicalHistory.mode === "materialized-mirror") return false;
|
|
8646
8131
|
return true;
|
|
8647
8132
|
}
|
|
8648
|
-
function buildNativeHistoryRecords(canonicalHistory, historySessionId, workspace) {
|
|
8649
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || "");
|
|
8650
|
-
if (!canonicalHistory || !normalizedSessionId || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
|
|
8651
|
-
if (canonicalHistory.format === "hermes-json") return buildHermesNativeHistoryRecords(normalizedSessionId);
|
|
8652
|
-
if (canonicalHistory.format === "claude-jsonl") return buildClaudeNativeHistoryRecords(normalizedSessionId, workspace);
|
|
8653
|
-
if (canonicalHistory.format === "codex-jsonl") return buildCodexNativeHistoryRecords(normalizedSessionId, workspace);
|
|
8654
|
-
return null;
|
|
8655
|
-
}
|
|
8656
8133
|
function readProviderChatHistory(agentType, options = {}) {
|
|
8657
8134
|
if (isNativeSourceCanonicalHistory(options.canonicalHistory) && options.historySessionId) {
|
|
8658
|
-
const
|
|
8659
|
-
if (!
|
|
8135
|
+
const nativeResult = buildNativeHistoryReadResult(agentType, options.canonicalHistory, options.scripts, options.historySessionId, options.workspace);
|
|
8136
|
+
if (!nativeResult) return { messages: [], hasMore: false, source: "native-unavailable" };
|
|
8660
8137
|
return {
|
|
8661
|
-
...pageHistoryRecords(agentType, records, options.offset || 0, options.limit || 30, options.excludeRecentCount || 0, options.historyBehavior),
|
|
8662
|
-
source: "provider-native"
|
|
8138
|
+
...pageHistoryRecords(agentType, nativeResult.records, options.offset || 0, options.limit || 30, options.excludeRecentCount || 0, options.historyBehavior),
|
|
8139
|
+
source: "provider-native",
|
|
8140
|
+
sourcePath: nativeResult.sourcePath,
|
|
8141
|
+
sourceMtimeMs: nativeResult.sourceMtimeMs
|
|
8663
8142
|
};
|
|
8664
8143
|
}
|
|
8665
8144
|
return {
|
|
@@ -8692,68 +8171,64 @@ function buildNativeSessionSummary(agentType, historySessionId, records, sourceP
|
|
|
8692
8171
|
sourceMtimeMs
|
|
8693
8172
|
};
|
|
8694
8173
|
}
|
|
8695
|
-
function
|
|
8696
|
-
|
|
8697
|
-
|
|
8698
|
-
const
|
|
8699
|
-
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
8712
|
-
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
}
|
|
8716
|
-
}
|
|
8717
|
-
return results;
|
|
8174
|
+
function normalizeProviderNativeHistorySessionSummary(agentType, item) {
|
|
8175
|
+
const historySessionId = normalizeSavedHistorySessionId(item?.historySessionId || item?.sessionId || "");
|
|
8176
|
+
if (!historySessionId) return null;
|
|
8177
|
+
const sourcePath = typeof item?.sourcePath === "string" ? item.sourcePath : "";
|
|
8178
|
+
const sourceMtimeMs = Number(item?.sourceMtimeMs) || 0;
|
|
8179
|
+
const firstMessageAt = Number(item?.firstMessageAt) || sourceMtimeMs || Date.now();
|
|
8180
|
+
const lastMessageAt = Number(item?.lastMessageAt) || firstMessageAt;
|
|
8181
|
+
const messageCount = Math.max(0, Number(item?.messageCount) || 0);
|
|
8182
|
+
return {
|
|
8183
|
+
historySessionId,
|
|
8184
|
+
sessionTitle: typeof item?.sessionTitle === "string" ? item.sessionTitle : void 0,
|
|
8185
|
+
messageCount,
|
|
8186
|
+
firstMessageAt,
|
|
8187
|
+
lastMessageAt,
|
|
8188
|
+
preview: typeof item?.preview === "string" ? item.preview : void 0,
|
|
8189
|
+
workspace: typeof item?.workspace === "string" ? item.workspace : void 0,
|
|
8190
|
+
source: "provider-native",
|
|
8191
|
+
sourcePath,
|
|
8192
|
+
sourceMtimeMs
|
|
8193
|
+
};
|
|
8718
8194
|
}
|
|
8719
|
-
function
|
|
8195
|
+
function collectProviderScriptNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) {
|
|
8196
|
+
const fn = getProviderNativeHistoryScript(scripts, canonicalHistory, "listSessions");
|
|
8197
|
+
if (!fn) return null;
|
|
8198
|
+
const result = fn({
|
|
8199
|
+
agentType,
|
|
8200
|
+
format: canonicalHistory.format,
|
|
8201
|
+
watchPath: canonicalHistory.watchPath,
|
|
8202
|
+
args: {}
|
|
8203
|
+
});
|
|
8204
|
+
if (!result || typeof result !== "object") return [];
|
|
8205
|
+
const sessions = Array.isArray(result.sessions) ? result.sessions : [];
|
|
8720
8206
|
const summaries = [];
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
const fileName = path7.basename(filePath);
|
|
8725
|
-
const historySessionId = fileName.replace(/^session_/, "").replace(/\.json$/, "");
|
|
8726
|
-
const records = buildHermesNativeHistoryRecords(historySessionId);
|
|
8727
|
-
const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
|
|
8728
|
-
if (summary) summaries.push(summary);
|
|
8729
|
-
}
|
|
8730
|
-
} else if (canonicalHistory.format === "claude-jsonl") {
|
|
8731
|
-
const root = path7.join(os5.homedir(), ".claude", "projects");
|
|
8732
|
-
for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && entry.name.endsWith(".jsonl"))) {
|
|
8733
|
-
const historySessionId = path7.basename(filePath, ".jsonl");
|
|
8734
|
-
const records = buildClaudeNativeHistoryRecords(historySessionId);
|
|
8735
|
-
const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
|
|
8736
|
-
if (summary) summaries.push(summary);
|
|
8737
|
-
}
|
|
8738
|
-
} else if (canonicalHistory.format === "codex-jsonl") {
|
|
8739
|
-
const root = path7.join(os5.homedir(), ".codex", "sessions");
|
|
8740
|
-
const uuidPattern = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i;
|
|
8741
|
-
for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && entry.name.endsWith(".jsonl"))) {
|
|
8742
|
-
const meta = readCodexSessionMeta(filePath);
|
|
8743
|
-
const historySessionId = String(meta?.id || path7.basename(filePath).match(uuidPattern)?.[1] || "").trim();
|
|
8207
|
+
for (const item of sessions) {
|
|
8208
|
+
if (Array.isArray(item?.messages || item?.records)) {
|
|
8209
|
+
const historySessionId = normalizeSavedHistorySessionId(item?.historySessionId || item?.sessionId || "");
|
|
8744
8210
|
if (!historySessionId) continue;
|
|
8745
|
-
const records =
|
|
8746
|
-
const
|
|
8747
|
-
if (
|
|
8211
|
+
const records = normalizeProviderNativeHistoryRecords(agentType, historySessionId, item.messages || item.records);
|
|
8212
|
+
const summary2 = buildNativeSessionSummary(agentType, historySessionId, records, typeof item?.sourcePath === "string" ? item.sourcePath : "");
|
|
8213
|
+
if (summary2) {
|
|
8214
|
+
if (Number(item?.sourceMtimeMs)) summary2.sourceMtimeMs = Number(item.sourceMtimeMs);
|
|
8215
|
+
summaries.push(summary2);
|
|
8216
|
+
}
|
|
8217
|
+
continue;
|
|
8748
8218
|
}
|
|
8219
|
+
const summary = normalizeProviderNativeHistorySessionSummary(agentType, item);
|
|
8220
|
+
if (summary) summaries.push(summary);
|
|
8749
8221
|
}
|
|
8750
8222
|
return sortSavedHistorySessionSummaries(summaries);
|
|
8751
8223
|
}
|
|
8224
|
+
function collectNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) {
|
|
8225
|
+
return collectProviderScriptNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) || [];
|
|
8226
|
+
}
|
|
8752
8227
|
function listProviderHistorySessions(agentType, options = {}) {
|
|
8753
8228
|
if (isNativeSourceCanonicalHistory(options.canonicalHistory)) {
|
|
8754
8229
|
const offset = Math.max(0, options.offset || 0);
|
|
8755
8230
|
const limit = Math.max(1, options.limit || 30);
|
|
8756
|
-
const summaries = collectNativeHistorySessionSummaries(agentType, options.canonicalHistory);
|
|
8231
|
+
const summaries = collectNativeHistorySessionSummaries(agentType, options.canonicalHistory, options.scripts);
|
|
8757
8232
|
return {
|
|
8758
8233
|
sessions: summaries.slice(offset, offset + limit),
|
|
8759
8234
|
hasMore: offset + limit < summaries.length,
|
|
@@ -11386,7 +10861,8 @@ async function handleChatHistory(h, args) {
|
|
|
11386
10861
|
offset: offset || 0,
|
|
11387
10862
|
limit: limit || 30,
|
|
11388
10863
|
excludeRecentCount,
|
|
11389
|
-
historyBehavior: provider?.historyBehavior
|
|
10864
|
+
historyBehavior: provider?.historyBehavior,
|
|
10865
|
+
scripts: provider?.scripts
|
|
11390
10866
|
});
|
|
11391
10867
|
return { success: true, ...result, agent: agentStr };
|
|
11392
10868
|
} catch (e) {
|
|
@@ -13860,13 +13336,8 @@ var CliProviderInstance = class {
|
|
|
13860
13336
|
historyWriter;
|
|
13861
13337
|
runtimeMessages = [];
|
|
13862
13338
|
lastPersistedHistoryMessages = [];
|
|
13863
|
-
|
|
13864
|
-
|
|
13865
|
-
lastCanonicalHermesWatchPath = void 0;
|
|
13866
|
-
lastCanonicalClaudeRebuildMtimeMs = 0;
|
|
13867
|
-
lastCanonicalClaudeCheckAt = 0;
|
|
13868
|
-
lastCanonicalCodexRebuildMtimeMs = 0;
|
|
13869
|
-
lastCanonicalCodexCheckAt = 0;
|
|
13339
|
+
lastNativeSourceCanonicalCheckAt = 0;
|
|
13340
|
+
lastNativeSourceCanonicalCacheKey = void 0;
|
|
13870
13341
|
cachedSqliteDb = null;
|
|
13871
13342
|
cachedSqliteDbPath = null;
|
|
13872
13343
|
cachedSqliteDbMissingUntil = 0;
|
|
@@ -14567,76 +14038,44 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14567
14038
|
const canonicalHistory = this.provider.canonicalHistory;
|
|
14568
14039
|
if (!canonicalHistory) return false;
|
|
14569
14040
|
if (isNativeSourceCanonicalHistory(canonicalHistory)) {
|
|
14041
|
+
const cacheKey = [this.type, this.providerSessionId, this.workingDir].join("\0");
|
|
14042
|
+
const now = Date.now();
|
|
14043
|
+
if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
|
|
14044
|
+
return true;
|
|
14045
|
+
}
|
|
14046
|
+
this.lastNativeSourceCanonicalCacheKey = cacheKey;
|
|
14047
|
+
this.lastNativeSourceCanonicalCheckAt = now;
|
|
14570
14048
|
const restoredHistory = readProviderChatHistory(this.type, {
|
|
14571
14049
|
canonicalHistory,
|
|
14572
14050
|
historySessionId: this.providerSessionId,
|
|
14573
14051
|
workspace: this.workingDir,
|
|
14574
14052
|
offset: 0,
|
|
14575
14053
|
limit: Number.MAX_SAFE_INTEGER,
|
|
14576
|
-
historyBehavior: this.provider.historyBehavior
|
|
14054
|
+
historyBehavior: this.provider.historyBehavior,
|
|
14055
|
+
scripts: this.provider.scripts
|
|
14577
14056
|
});
|
|
14578
|
-
if (restoredHistory.source
|
|
14579
|
-
|
|
14580
|
-
|
|
14581
|
-
|
|
14582
|
-
|
|
14583
|
-
|
|
14584
|
-
|
|
14585
|
-
|
|
14057
|
+
if (restoredHistory.source === "provider-native") {
|
|
14058
|
+
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
14059
|
+
role: message.role,
|
|
14060
|
+
content: message.content,
|
|
14061
|
+
kind: message.kind,
|
|
14062
|
+
senderName: message.senderName,
|
|
14063
|
+
receivedAt: message.receivedAt
|
|
14064
|
+
}));
|
|
14065
|
+
}
|
|
14586
14066
|
return true;
|
|
14587
14067
|
}
|
|
14588
14068
|
try {
|
|
14589
|
-
|
|
14590
|
-
|
|
14591
|
-
|
|
14592
|
-
|
|
14593
|
-
|
|
14594
|
-
|
|
14595
|
-
|
|
14596
|
-
|
|
14597
|
-
|
|
14598
|
-
if (!fs5.existsSync(watchPath)) return false;
|
|
14599
|
-
}
|
|
14600
|
-
const stat = fs5.statSync(watchPath);
|
|
14601
|
-
if (stat.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
|
|
14602
|
-
rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
|
|
14603
|
-
if (rebuilt) this.lastCanonicalHermesSyncMtimeMs = stat.mtimeMs;
|
|
14604
|
-
} else if (canonicalHistory.format === "claude-jsonl") {
|
|
14605
|
-
const now = Date.now();
|
|
14606
|
-
if (now - this.lastCanonicalClaudeCheckAt < 2e3 && this.lastCanonicalClaudeRebuildMtimeMs !== 0) {
|
|
14607
|
-
return true;
|
|
14608
|
-
}
|
|
14609
|
-
this.lastCanonicalClaudeCheckAt = now;
|
|
14610
|
-
const claudeProjectsDir = path11.join(os11.homedir(), ".claude", "projects");
|
|
14611
|
-
const workspaceSegment = typeof this.workingDir === "string" ? this.workingDir.replace(/[\\/]/g, "-").replace(/^-+/, "") : "";
|
|
14612
|
-
const transcriptFile = path11.join(claudeProjectsDir, workspaceSegment, `${this.providerSessionId}.jsonl`);
|
|
14613
|
-
let transcriptMtime = 0;
|
|
14614
|
-
try {
|
|
14615
|
-
transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
|
|
14616
|
-
} catch {
|
|
14617
|
-
}
|
|
14618
|
-
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalClaudeRebuildMtimeMs) return true;
|
|
14619
|
-
rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
|
|
14620
|
-
if (rebuilt) this.lastCanonicalClaudeRebuildMtimeMs = transcriptMtime || Date.now();
|
|
14621
|
-
} else if (canonicalHistory.format === "codex-jsonl") {
|
|
14622
|
-
const now = Date.now();
|
|
14623
|
-
if (now - this.lastCanonicalCodexCheckAt < 2e3 && this.lastCanonicalCodexRebuildMtimeMs !== 0) {
|
|
14624
|
-
return true;
|
|
14625
|
-
}
|
|
14626
|
-
this.lastCanonicalCodexCheckAt = now;
|
|
14627
|
-
const transcriptFile = resolveCodexSessionTranscriptPath(this.providerSessionId, this.workingDir);
|
|
14628
|
-
let transcriptMtime = 0;
|
|
14629
|
-
if (transcriptFile) {
|
|
14630
|
-
try {
|
|
14631
|
-
transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
|
|
14632
|
-
} catch {
|
|
14633
|
-
}
|
|
14634
|
-
}
|
|
14635
|
-
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalCodexRebuildMtimeMs) return true;
|
|
14636
|
-
rebuilt = rebuildCodexSavedHistoryFromNativeSession(this.providerSessionId, this.workingDir);
|
|
14637
|
-
if (rebuilt) this.lastCanonicalCodexRebuildMtimeMs = transcriptMtime || Date.now();
|
|
14069
|
+
const cacheKey = [this.type, this.providerSessionId, this.workingDir, canonicalHistory.mode || "materialized-mirror"].join("\0");
|
|
14070
|
+
const now = Date.now();
|
|
14071
|
+
if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
|
|
14072
|
+
return true;
|
|
14073
|
+
}
|
|
14074
|
+
this.lastNativeSourceCanonicalCacheKey = cacheKey;
|
|
14075
|
+
this.lastNativeSourceCanonicalCheckAt = now;
|
|
14076
|
+
if (!materializeProviderNativeHistory(this.type, canonicalHistory, this.providerSessionId, this.workingDir, this.provider.scripts)) {
|
|
14077
|
+
return false;
|
|
14638
14078
|
}
|
|
14639
|
-
if (!rebuilt) return false;
|
|
14640
14079
|
const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
14641
14080
|
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
14642
14081
|
role: message.role,
|
|
@@ -14659,7 +14098,8 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14659
14098
|
workspace: this.workingDir,
|
|
14660
14099
|
offset: 0,
|
|
14661
14100
|
limit: Number.MAX_SAFE_INTEGER,
|
|
14662
|
-
historyBehavior: this.provider.historyBehavior
|
|
14101
|
+
historyBehavior: this.provider.historyBehavior,
|
|
14102
|
+
scripts: this.provider.scripts
|
|
14663
14103
|
}) : (() => {
|
|
14664
14104
|
this.historyWriter.compactHistorySession(this.type, this.providerSessionId, this.provider.historyBehavior);
|
|
14665
14105
|
return readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
@@ -16799,6 +16239,7 @@ function validateProviderDefinition(raw) {
|
|
|
16799
16239
|
warnings.push("Extension providers should have extensionId");
|
|
16800
16240
|
}
|
|
16801
16241
|
validateCapabilities(provider, controls, errors);
|
|
16242
|
+
validateCanonicalHistory(provider.canonicalHistory, errors);
|
|
16802
16243
|
for (const control of controls) {
|
|
16803
16244
|
validateControl(control, errors);
|
|
16804
16245
|
}
|
|
@@ -16856,6 +16297,39 @@ function validateCapabilities(provider, controls, errors) {
|
|
|
16856
16297
|
errors.push("providers declaring controls must set capabilities.controls.typedResults=true");
|
|
16857
16298
|
}
|
|
16858
16299
|
}
|
|
16300
|
+
function validateCanonicalHistory(raw, errors) {
|
|
16301
|
+
if (raw === void 0) return;
|
|
16302
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
16303
|
+
errors.push("canonicalHistory must be an object");
|
|
16304
|
+
return;
|
|
16305
|
+
}
|
|
16306
|
+
const canonicalHistory = raw;
|
|
16307
|
+
const format = canonicalHistory.format;
|
|
16308
|
+
if (format !== void 0 && (typeof format !== "string" || !format.trim())) {
|
|
16309
|
+
errors.push("canonicalHistory.format must be a non-empty string when provided");
|
|
16310
|
+
}
|
|
16311
|
+
const watchPath = canonicalHistory.watchPath;
|
|
16312
|
+
if (watchPath !== void 0 && (typeof watchPath !== "string" || !watchPath.trim())) {
|
|
16313
|
+
errors.push("canonicalHistory.watchPath must be a non-empty string when provided");
|
|
16314
|
+
}
|
|
16315
|
+
const mode = canonicalHistory.mode;
|
|
16316
|
+
if (mode !== void 0 && !["native-source", "materialized-mirror", "disabled"].includes(String(mode))) {
|
|
16317
|
+
errors.push("canonicalHistory.mode must be one of: native-source, materialized-mirror, disabled");
|
|
16318
|
+
}
|
|
16319
|
+
const scripts = canonicalHistory.scripts;
|
|
16320
|
+
if (scripts === void 0) return;
|
|
16321
|
+
if (!scripts || typeof scripts !== "object" || Array.isArray(scripts)) {
|
|
16322
|
+
errors.push("canonicalHistory.scripts must be an object");
|
|
16323
|
+
return;
|
|
16324
|
+
}
|
|
16325
|
+
const scriptConfig = scripts;
|
|
16326
|
+
for (const key of ["readSession", "listSessions"]) {
|
|
16327
|
+
const value = scriptConfig[key];
|
|
16328
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
16329
|
+
errors.push(`canonicalHistory.scripts.${key} must be a non-empty string`);
|
|
16330
|
+
}
|
|
16331
|
+
}
|
|
16332
|
+
}
|
|
16859
16333
|
function validateControl(control, errors) {
|
|
16860
16334
|
if (!control || typeof control !== "object") {
|
|
16861
16335
|
errors.push("controls: each control must be an object");
|
|
@@ -19999,7 +19473,8 @@ var DaemonCommandRouter = class {
|
|
|
19999
19473
|
canonicalHistory: providerMeta?.canonicalHistory,
|
|
20000
19474
|
offset,
|
|
20001
19475
|
limit,
|
|
20002
|
-
historyBehavior: providerMeta?.historyBehavior
|
|
19476
|
+
historyBehavior: providerMeta?.historyBehavior,
|
|
19477
|
+
scripts: providerMeta?.scripts
|
|
20003
19478
|
});
|
|
20004
19479
|
const state = loadState();
|
|
20005
19480
|
const savedSessions = getSavedProviderSessions(state, { providerType, kind });
|
|
@@ -20025,7 +19500,10 @@ var DaemonCommandRouter = class {
|
|
|
20025
19500
|
messageCount: session.messageCount,
|
|
20026
19501
|
firstMessageAt: session.firstMessageAt,
|
|
20027
19502
|
lastMessageAt: session.lastMessageAt,
|
|
20028
|
-
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById
|
|
19503
|
+
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById,
|
|
19504
|
+
historySource: session.source,
|
|
19505
|
+
sourcePath: session.sourcePath,
|
|
19506
|
+
sourceMtimeMs: session.sourceMtimeMs
|
|
20029
19507
|
};
|
|
20030
19508
|
}),
|
|
20031
19509
|
hasMore,
|