@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.js
CHANGED
|
@@ -8160,29 +8160,6 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
8160
8160
|
return { sessions: [], hasMore: false };
|
|
8161
8161
|
}
|
|
8162
8162
|
}
|
|
8163
|
-
function normalizeCanonicalHermesMessageContent(content) {
|
|
8164
|
-
if (typeof content === "string") return content.trim();
|
|
8165
|
-
if (content == null) return "";
|
|
8166
|
-
try {
|
|
8167
|
-
return JSON.stringify(content).trim();
|
|
8168
|
-
} catch {
|
|
8169
|
-
return String(content).trim();
|
|
8170
|
-
}
|
|
8171
|
-
}
|
|
8172
|
-
function extractCanonicalHermesMessageTimestamp(message, fallbackTs) {
|
|
8173
|
-
const numericTimestamp = Number(message.receivedAt || message.timestamp || message.ts || 0);
|
|
8174
|
-
if (Number.isFinite(numericTimestamp) && numericTimestamp > 0) return numericTimestamp;
|
|
8175
|
-
const stringTimestamp = typeof message.ts === "string" ? Date.parse(message.ts) : typeof message.timestamp === "string" ? Date.parse(message.timestamp) : NaN;
|
|
8176
|
-
if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
|
|
8177
|
-
return fallbackTs;
|
|
8178
|
-
}
|
|
8179
|
-
function extractTimestampValue(value) {
|
|
8180
|
-
const numericTimestamp = Number(value || 0);
|
|
8181
|
-
if (Number.isFinite(numericTimestamp) && numericTimestamp > 0) return numericTimestamp;
|
|
8182
|
-
const stringTimestamp = typeof value === "string" ? Date.parse(value) : NaN;
|
|
8183
|
-
if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
|
|
8184
|
-
return 0;
|
|
8185
|
-
}
|
|
8186
8163
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
8187
8164
|
try {
|
|
8188
8165
|
const dir = path7.join(HISTORY_DIR, agentType);
|
|
@@ -8228,569 +8205,77 @@ function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
|
8228
8205
|
return false;
|
|
8229
8206
|
}
|
|
8230
8207
|
}
|
|
8231
|
-
function
|
|
8232
|
-
const
|
|
8233
|
-
if (
|
|
8234
|
-
|
|
8235
|
-
const sessionFilePath = path7.join(os5.homedir(), ".hermes", "sessions", `session_${normalizedSessionId}.json`);
|
|
8236
|
-
if (!fs3.existsSync(sessionFilePath)) return null;
|
|
8237
|
-
const raw = JSON.parse(fs3.readFileSync(sessionFilePath, "utf-8"));
|
|
8238
|
-
const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
|
|
8239
|
-
const records = [];
|
|
8240
|
-
let fallbackTs = Date.parse(raw.session_start || raw.last_updated || "") || Date.now();
|
|
8241
|
-
for (const message of canonicalMessages) {
|
|
8242
|
-
const role = String(message.role || "").trim();
|
|
8243
|
-
const content = normalizeCanonicalHermesMessageContent(message.content);
|
|
8244
|
-
if (!content) continue;
|
|
8245
|
-
const receivedAt = extractCanonicalHermesMessageTimestamp(message, fallbackTs);
|
|
8246
|
-
fallbackTs = receivedAt + 1;
|
|
8247
|
-
if (role === "user" || role === "assistant") {
|
|
8248
|
-
records.push({
|
|
8249
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8250
|
-
receivedAt,
|
|
8251
|
-
role,
|
|
8252
|
-
content,
|
|
8253
|
-
kind: "standard",
|
|
8254
|
-
agent: "hermes-cli",
|
|
8255
|
-
historySessionId: normalizedSessionId
|
|
8256
|
-
});
|
|
8257
|
-
continue;
|
|
8258
|
-
}
|
|
8259
|
-
if (role === "tool") {
|
|
8260
|
-
records.push({
|
|
8261
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8262
|
-
receivedAt,
|
|
8263
|
-
role: "assistant",
|
|
8264
|
-
content,
|
|
8265
|
-
kind: "tool",
|
|
8266
|
-
senderName: "Tool",
|
|
8267
|
-
agent: "hermes-cli",
|
|
8268
|
-
historySessionId: normalizedSessionId
|
|
8269
|
-
});
|
|
8270
|
-
}
|
|
8271
|
-
}
|
|
8272
|
-
return records;
|
|
8273
|
-
} catch {
|
|
8274
|
-
return null;
|
|
8275
|
-
}
|
|
8276
|
-
}
|
|
8277
|
-
function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
|
|
8278
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8279
|
-
if (!normalizedSessionId) return false;
|
|
8280
|
-
try {
|
|
8281
|
-
const sessionFilePath = path7.join(os5.homedir(), ".hermes", "sessions", `session_${normalizedSessionId}.json`);
|
|
8282
|
-
if (!fs3.existsSync(sessionFilePath)) return false;
|
|
8283
|
-
const raw = JSON.parse(fs3.readFileSync(sessionFilePath, "utf-8"));
|
|
8284
|
-
const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
|
|
8285
|
-
const dir = path7.join(HISTORY_DIR, "hermes-cli");
|
|
8286
|
-
fs3.mkdirSync(dir, { recursive: true });
|
|
8287
|
-
const existingSessionStart = readExistingSessionStartRecord("hermes-cli", normalizedSessionId);
|
|
8288
|
-
const records = [];
|
|
8289
|
-
if (existingSessionStart) {
|
|
8290
|
-
records.push({
|
|
8291
|
-
...existingSessionStart,
|
|
8292
|
-
historySessionId: normalizedSessionId
|
|
8293
|
-
});
|
|
8294
|
-
}
|
|
8295
|
-
let fallbackTs = Date.parse(raw.session_start || raw.last_updated || "") || Date.now();
|
|
8296
|
-
for (const message of canonicalMessages) {
|
|
8297
|
-
const role = String(message.role || "").trim();
|
|
8298
|
-
const content = normalizeCanonicalHermesMessageContent(message.content);
|
|
8299
|
-
if (!content) continue;
|
|
8300
|
-
const receivedAt = extractCanonicalHermesMessageTimestamp(message, fallbackTs);
|
|
8301
|
-
fallbackTs = receivedAt + 1;
|
|
8302
|
-
if (role === "user") {
|
|
8303
|
-
records.push({
|
|
8304
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8305
|
-
receivedAt,
|
|
8306
|
-
role: "user",
|
|
8307
|
-
content,
|
|
8308
|
-
kind: "standard",
|
|
8309
|
-
agent: "hermes-cli",
|
|
8310
|
-
historySessionId: normalizedSessionId
|
|
8311
|
-
});
|
|
8312
|
-
continue;
|
|
8313
|
-
}
|
|
8314
|
-
if (role === "assistant") {
|
|
8315
|
-
records.push({
|
|
8316
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8317
|
-
receivedAt,
|
|
8318
|
-
role: "assistant",
|
|
8319
|
-
content,
|
|
8320
|
-
kind: "standard",
|
|
8321
|
-
agent: "hermes-cli",
|
|
8322
|
-
historySessionId: normalizedSessionId
|
|
8323
|
-
});
|
|
8324
|
-
continue;
|
|
8325
|
-
}
|
|
8326
|
-
if (role === "tool") {
|
|
8327
|
-
records.push({
|
|
8328
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8329
|
-
receivedAt,
|
|
8330
|
-
role: "assistant",
|
|
8331
|
-
content,
|
|
8332
|
-
kind: "tool",
|
|
8333
|
-
senderName: "Tool",
|
|
8334
|
-
agent: "hermes-cli",
|
|
8335
|
-
historySessionId: normalizedSessionId
|
|
8336
|
-
});
|
|
8337
|
-
}
|
|
8338
|
-
}
|
|
8339
|
-
return rewriteCanonicalSavedHistory("hermes-cli", normalizedSessionId, records);
|
|
8340
|
-
} catch {
|
|
8341
|
-
return false;
|
|
8342
|
-
}
|
|
8343
|
-
}
|
|
8344
|
-
function resolveClaudeProjectTranscriptPath(historySessionId, workspace) {
|
|
8345
|
-
const claudeProjectsDir = path7.join(os5.homedir(), ".claude", "projects");
|
|
8346
|
-
if (!fs3.existsSync(claudeProjectsDir)) return null;
|
|
8347
|
-
const normalizedWorkspace = typeof workspace === "string" ? workspace.trim() : "";
|
|
8348
|
-
if (normalizedWorkspace) {
|
|
8349
|
-
const directPath = path7.join(claudeProjectsDir, normalizedWorkspace.replace(/[\\/]/g, "-"), `${historySessionId}.jsonl`);
|
|
8350
|
-
if (fs3.existsSync(directPath)) return directPath;
|
|
8351
|
-
}
|
|
8352
|
-
const stack = [claudeProjectsDir];
|
|
8353
|
-
while (stack.length > 0) {
|
|
8354
|
-
const current = stack.pop();
|
|
8355
|
-
if (!current) continue;
|
|
8356
|
-
for (const entry of fs3.readdirSync(current, { withFileTypes: true })) {
|
|
8357
|
-
const entryPath = path7.join(current, entry.name);
|
|
8358
|
-
if (entry.isDirectory()) {
|
|
8359
|
-
stack.push(entryPath);
|
|
8360
|
-
continue;
|
|
8361
|
-
}
|
|
8362
|
-
if (entry.isFile() && entry.name === `${historySessionId}.jsonl`) {
|
|
8363
|
-
return entryPath;
|
|
8364
|
-
}
|
|
8365
|
-
}
|
|
8366
|
-
}
|
|
8367
|
-
return null;
|
|
8368
|
-
}
|
|
8369
|
-
function extractClaudeAssistantContentParts(content) {
|
|
8370
|
-
if (typeof content === "string") {
|
|
8371
|
-
const trimmed = content.trim();
|
|
8372
|
-
return trimmed ? [{ content: trimmed, kind: "standard", role: "assistant" }] : [];
|
|
8373
|
-
}
|
|
8374
|
-
if (!Array.isArray(content)) return [];
|
|
8375
|
-
const parts = [];
|
|
8376
|
-
for (const block of content) {
|
|
8377
|
-
if (!block || typeof block !== "object") continue;
|
|
8378
|
-
const record = block;
|
|
8379
|
-
const type = String(record.type || "").trim();
|
|
8380
|
-
if (type === "text") {
|
|
8381
|
-
const text = String(record.text || "").trim();
|
|
8382
|
-
if (text) parts.push({ content: text, kind: "standard", role: "assistant" });
|
|
8383
|
-
continue;
|
|
8384
|
-
}
|
|
8385
|
-
if (type === "tool_use") {
|
|
8386
|
-
const name = String(record.name || "").trim() || "Tool";
|
|
8387
|
-
const input = record.input && typeof record.input === "object" ? record.input : null;
|
|
8388
|
-
const command = input ? String(input.command || "").trim() : "";
|
|
8389
|
-
const summary = command ? `${name}: ${command}` : name;
|
|
8390
|
-
if (summary) parts.push({ content: summary, kind: "tool", senderName: "Tool", role: "assistant" });
|
|
8391
|
-
}
|
|
8392
|
-
}
|
|
8393
|
-
return parts;
|
|
8394
|
-
}
|
|
8395
|
-
function extractClaudeUserContentParts(content) {
|
|
8396
|
-
if (typeof content === "string") {
|
|
8397
|
-
const trimmed = content.trim();
|
|
8398
|
-
return trimmed ? [{ role: "user", content: trimmed, kind: "standard" }] : [];
|
|
8399
|
-
}
|
|
8400
|
-
if (!Array.isArray(content)) return [];
|
|
8401
|
-
const parts = [];
|
|
8402
|
-
for (const block of content) {
|
|
8403
|
-
if (!block || typeof block !== "object") continue;
|
|
8404
|
-
const record = block;
|
|
8405
|
-
const type = String(record.type || "").trim();
|
|
8406
|
-
if (type === "text") {
|
|
8407
|
-
const text = String(record.text || "").trim();
|
|
8408
|
-
if (text) parts.push({ role: "user", content: text, kind: "standard" });
|
|
8409
|
-
continue;
|
|
8410
|
-
}
|
|
8411
|
-
if (type === "tool_result") {
|
|
8412
|
-
const rawContent = record.content;
|
|
8413
|
-
const text = typeof rawContent === "string" ? rawContent.trim() : Array.isArray(rawContent) ? rawContent.map((entry) => {
|
|
8414
|
-
if (typeof entry === "string") return entry.trim();
|
|
8415
|
-
if (!entry || typeof entry !== "object") return "";
|
|
8416
|
-
const nested = entry;
|
|
8417
|
-
if (typeof nested.text === "string") return nested.text.trim();
|
|
8418
|
-
if (typeof nested.content === "string") return nested.content.trim();
|
|
8419
|
-
return "";
|
|
8420
|
-
}).filter(Boolean).join("\n") : "";
|
|
8421
|
-
if (text) parts.push({ role: "assistant", content: text, kind: "tool", senderName: "Tool" });
|
|
8422
|
-
}
|
|
8423
|
-
}
|
|
8424
|
-
return parts;
|
|
8425
|
-
}
|
|
8426
|
-
function buildClaudeNativeHistoryRecords(historySessionId, workspace) {
|
|
8427
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8428
|
-
if (!normalizedSessionId) return null;
|
|
8429
|
-
try {
|
|
8430
|
-
const transcriptPath = resolveClaudeProjectTranscriptPath(normalizedSessionId, workspace);
|
|
8431
|
-
if (!transcriptPath) return null;
|
|
8432
|
-
const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
|
|
8433
|
-
const records = [];
|
|
8434
|
-
let fallbackTs = Date.now();
|
|
8435
|
-
for (const line of lines) {
|
|
8436
|
-
let parsed = null;
|
|
8437
|
-
try {
|
|
8438
|
-
parsed = JSON.parse(line);
|
|
8439
|
-
} catch {
|
|
8440
|
-
parsed = null;
|
|
8441
|
-
}
|
|
8442
|
-
if (!parsed) continue;
|
|
8443
|
-
const parsedSessionId = String(parsed.sessionId || "").trim();
|
|
8444
|
-
if (parsedSessionId && parsedSessionId !== normalizedSessionId) continue;
|
|
8445
|
-
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
8446
|
-
fallbackTs = receivedAt + 1;
|
|
8447
|
-
const parsedWorkspace = String(parsed.cwd || workspace || "").trim();
|
|
8448
|
-
if (records.length === 0 && parsedWorkspace) {
|
|
8449
|
-
records.push({
|
|
8450
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8451
|
-
receivedAt,
|
|
8452
|
-
role: "system",
|
|
8453
|
-
kind: "session_start",
|
|
8454
|
-
content: parsedWorkspace,
|
|
8455
|
-
agent: "claude-cli",
|
|
8456
|
-
historySessionId: normalizedSessionId,
|
|
8457
|
-
workspace: parsedWorkspace
|
|
8458
|
-
});
|
|
8459
|
-
}
|
|
8460
|
-
const type = String(parsed.type || "").trim();
|
|
8461
|
-
const message = parsed.message && typeof parsed.message === "object" ? parsed.message : null;
|
|
8462
|
-
if (type === "user" && message) {
|
|
8463
|
-
for (const part of extractClaudeUserContentParts(message.content)) {
|
|
8464
|
-
records.push({
|
|
8465
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8466
|
-
receivedAt,
|
|
8467
|
-
role: part.role,
|
|
8468
|
-
content: part.content,
|
|
8469
|
-
kind: part.kind,
|
|
8470
|
-
senderName: part.senderName,
|
|
8471
|
-
agent: "claude-cli",
|
|
8472
|
-
historySessionId: normalizedSessionId
|
|
8473
|
-
});
|
|
8474
|
-
}
|
|
8475
|
-
continue;
|
|
8476
|
-
}
|
|
8477
|
-
if (type === "assistant" && message) {
|
|
8478
|
-
for (const part of extractClaudeAssistantContentParts(message.content)) {
|
|
8479
|
-
records.push({
|
|
8480
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8481
|
-
receivedAt,
|
|
8482
|
-
role: "assistant",
|
|
8483
|
-
content: part.content,
|
|
8484
|
-
kind: part.kind,
|
|
8485
|
-
senderName: part.senderName,
|
|
8486
|
-
agent: "claude-cli",
|
|
8487
|
-
historySessionId: normalizedSessionId
|
|
8488
|
-
});
|
|
8489
|
-
}
|
|
8490
|
-
}
|
|
8491
|
-
}
|
|
8492
|
-
return records;
|
|
8493
|
-
} catch {
|
|
8494
|
-
return null;
|
|
8495
|
-
}
|
|
8496
|
-
}
|
|
8497
|
-
function rebuildClaudeSavedHistoryFromNativeProject(historySessionId, workspace) {
|
|
8498
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8499
|
-
if (!normalizedSessionId) return false;
|
|
8500
|
-
try {
|
|
8501
|
-
const transcriptPath = resolveClaudeProjectTranscriptPath(normalizedSessionId, workspace);
|
|
8502
|
-
if (!transcriptPath) return false;
|
|
8503
|
-
const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
|
|
8504
|
-
const records = [];
|
|
8505
|
-
const existingSessionStart = readExistingSessionStartRecord("claude-cli", normalizedSessionId);
|
|
8506
|
-
if (existingSessionStart) {
|
|
8507
|
-
records.push({
|
|
8508
|
-
...existingSessionStart,
|
|
8509
|
-
historySessionId: normalizedSessionId
|
|
8510
|
-
});
|
|
8511
|
-
}
|
|
8512
|
-
let fallbackTs = Date.now();
|
|
8513
|
-
for (const line of lines) {
|
|
8514
|
-
let parsed = null;
|
|
8515
|
-
try {
|
|
8516
|
-
parsed = JSON.parse(line);
|
|
8517
|
-
} catch {
|
|
8518
|
-
parsed = null;
|
|
8519
|
-
}
|
|
8520
|
-
if (!parsed) continue;
|
|
8521
|
-
const parsedSessionId = String(parsed.sessionId || "").trim();
|
|
8522
|
-
if (parsedSessionId && parsedSessionId !== normalizedSessionId) continue;
|
|
8523
|
-
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
8524
|
-
fallbackTs = receivedAt + 1;
|
|
8525
|
-
const parsedWorkspace = String(parsed.cwd || workspace || "").trim();
|
|
8526
|
-
if (records.length === 0 && parsedWorkspace) {
|
|
8527
|
-
records.push({
|
|
8528
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8529
|
-
receivedAt,
|
|
8530
|
-
role: "system",
|
|
8531
|
-
kind: "session_start",
|
|
8532
|
-
content: parsedWorkspace,
|
|
8533
|
-
agent: "claude-cli",
|
|
8534
|
-
historySessionId: normalizedSessionId,
|
|
8535
|
-
workspace: parsedWorkspace
|
|
8536
|
-
});
|
|
8537
|
-
}
|
|
8538
|
-
const type = String(parsed.type || "").trim();
|
|
8539
|
-
const message = parsed.message && typeof parsed.message === "object" ? parsed.message : null;
|
|
8540
|
-
if (type === "user" && message) {
|
|
8541
|
-
for (const part of extractClaudeUserContentParts(message.content)) {
|
|
8542
|
-
records.push({
|
|
8543
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8544
|
-
receivedAt,
|
|
8545
|
-
role: part.role,
|
|
8546
|
-
content: part.content,
|
|
8547
|
-
kind: part.kind,
|
|
8548
|
-
senderName: part.senderName,
|
|
8549
|
-
agent: "claude-cli",
|
|
8550
|
-
historySessionId: normalizedSessionId
|
|
8551
|
-
});
|
|
8552
|
-
}
|
|
8553
|
-
continue;
|
|
8554
|
-
}
|
|
8555
|
-
if (type === "assistant" && message) {
|
|
8556
|
-
for (const part of extractClaudeAssistantContentParts(message.content)) {
|
|
8557
|
-
records.push({
|
|
8558
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8559
|
-
receivedAt,
|
|
8560
|
-
role: "assistant",
|
|
8561
|
-
content: part.content,
|
|
8562
|
-
kind: part.kind,
|
|
8563
|
-
senderName: part.senderName,
|
|
8564
|
-
agent: "claude-cli",
|
|
8565
|
-
historySessionId: normalizedSessionId
|
|
8566
|
-
});
|
|
8567
|
-
}
|
|
8568
|
-
}
|
|
8569
|
-
}
|
|
8570
|
-
return rewriteCanonicalSavedHistory("claude-cli", normalizedSessionId, records);
|
|
8571
|
-
} catch {
|
|
8572
|
-
return false;
|
|
8573
|
-
}
|
|
8574
|
-
}
|
|
8575
|
-
function isUuidLikeSessionId(sessionId) {
|
|
8576
|
-
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);
|
|
8208
|
+
function getNativeHistoryScriptName(canonicalHistory, key) {
|
|
8209
|
+
const configured = canonicalHistory?.scripts?.[key];
|
|
8210
|
+
if (typeof configured === "string" && configured.trim()) return configured.trim();
|
|
8211
|
+
return key === "readSession" ? "readNativeHistory" : "listNativeHistory";
|
|
8577
8212
|
}
|
|
8578
|
-
function
|
|
8579
|
-
|
|
8580
|
-
|
|
8581
|
-
|
|
8582
|
-
const parsed = JSON.parse(firstLine);
|
|
8583
|
-
if (String(parsed.type || "") !== "session_meta") return null;
|
|
8584
|
-
const payload = parsed.payload && typeof parsed.payload === "object" ? parsed.payload : null;
|
|
8585
|
-
return payload;
|
|
8586
|
-
} catch {
|
|
8587
|
-
return null;
|
|
8588
|
-
}
|
|
8213
|
+
function getProviderNativeHistoryScript(scripts, canonicalHistory, key) {
|
|
8214
|
+
if (!canonicalHistory?.scripts) return null;
|
|
8215
|
+
const fn = scripts?.[getNativeHistoryScriptName(canonicalHistory, key)];
|
|
8216
|
+
return typeof fn === "function" ? fn : null;
|
|
8589
8217
|
}
|
|
8590
|
-
function
|
|
8218
|
+
function normalizeProviderNativeHistoryRecords(agentType, historySessionId, records) {
|
|
8219
|
+
if (!Array.isArray(records)) return [];
|
|
8591
8220
|
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8592
|
-
|
|
8593
|
-
|
|
8594
|
-
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
8598
|
-
|
|
8599
|
-
|
|
8600
|
-
|
|
8601
|
-
|
|
8602
|
-
|
|
8603
|
-
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
|
|
8607
|
-
|
|
8608
|
-
|
|
8609
|
-
|
|
8610
|
-
|
|
8611
|
-
|
|
8612
|
-
|
|
8613
|
-
|
|
8614
|
-
|
|
8615
|
-
|
|
8616
|
-
|
|
8617
|
-
|
|
8618
|
-
|
|
8619
|
-
|
|
8620
|
-
|
|
8621
|
-
|
|
8622
|
-
|
|
8623
|
-
|
|
8624
|
-
|
|
8625
|
-
|
|
8626
|
-
workspaceMatches: !!normalizedWorkspace && metaWorkspace === normalizedWorkspace,
|
|
8627
|
-
metaMatches: metaSessionId === normalizedSessionId
|
|
8628
|
-
});
|
|
8629
|
-
}
|
|
8630
|
-
}
|
|
8631
|
-
candidates.sort((a, b) => Number(b.workspaceMatches) - Number(a.workspaceMatches) || Number(b.metaMatches) - Number(a.metaMatches) || b.mtimeMs - a.mtimeMs);
|
|
8632
|
-
return candidates[0]?.path || null;
|
|
8633
|
-
}
|
|
8634
|
-
function flattenCodexContent(content) {
|
|
8635
|
-
if (typeof content === "string") return content.trim();
|
|
8636
|
-
if (content == null) return "";
|
|
8637
|
-
if (Array.isArray(content)) {
|
|
8638
|
-
return content.map((entry) => flattenCodexContent(entry)).filter(Boolean).join("\n").trim();
|
|
8639
|
-
}
|
|
8640
|
-
if (typeof content === "object") {
|
|
8641
|
-
const record = content;
|
|
8642
|
-
if (typeof record.text === "string") return record.text.trim();
|
|
8643
|
-
if (typeof record.content === "string" || Array.isArray(record.content)) return flattenCodexContent(record.content);
|
|
8644
|
-
if (typeof record.output === "string") return record.output.trim();
|
|
8645
|
-
if (typeof record.message === "string") return record.message.trim();
|
|
8646
|
-
}
|
|
8647
|
-
return "";
|
|
8648
|
-
}
|
|
8649
|
-
function summarizeCodexToolCall(payload) {
|
|
8650
|
-
const name = String(payload.name || payload.type || "tool").trim() || "tool";
|
|
8651
|
-
const rawArguments = payload.arguments ?? payload.input;
|
|
8652
|
-
let argumentValue = "";
|
|
8653
|
-
if (typeof rawArguments === "string") {
|
|
8654
|
-
const trimmed = rawArguments.trim();
|
|
8655
|
-
try {
|
|
8656
|
-
const parsed = JSON.parse(trimmed);
|
|
8657
|
-
argumentValue = summarizeCodexToolArguments(parsed);
|
|
8658
|
-
} catch {
|
|
8659
|
-
argumentValue = trimmed;
|
|
8660
|
-
}
|
|
8661
|
-
} else {
|
|
8662
|
-
argumentValue = summarizeCodexToolArguments(rawArguments);
|
|
8663
|
-
}
|
|
8664
|
-
return argumentValue ? `${name}: ${argumentValue}` : name;
|
|
8665
|
-
}
|
|
8666
|
-
function summarizeCodexToolArguments(value) {
|
|
8667
|
-
if (typeof value === "string") return value.trim();
|
|
8668
|
-
if (Array.isArray(value)) return value.map((entry) => String(entry)).join(" ").trim();
|
|
8669
|
-
if (!value || typeof value !== "object") return "";
|
|
8670
|
-
const record = value;
|
|
8671
|
-
const direct = record.command || record.cmd || record.query || record.path || record.prompt;
|
|
8672
|
-
if (typeof direct === "string") return direct.trim();
|
|
8673
|
-
if (Array.isArray(direct)) return direct.map((entry) => String(entry)).join(" ").trim();
|
|
8674
|
-
try {
|
|
8675
|
-
return JSON.stringify(record).trim();
|
|
8676
|
-
} catch {
|
|
8677
|
-
return "";
|
|
8678
|
-
}
|
|
8221
|
+
return records.map((record) => sanitizeHistoryMessage(agentType, {
|
|
8222
|
+
ts: typeof record?.ts === "string" ? record.ts : new Date(Number(record?.receivedAt) || Date.now()).toISOString(),
|
|
8223
|
+
receivedAt: Number(record?.receivedAt) || Date.parse(record?.ts || "") || Date.now(),
|
|
8224
|
+
role: record?.role,
|
|
8225
|
+
content: String(record?.content || ""),
|
|
8226
|
+
kind: record?.kind || (record?.role === "system" ? "session_start" : "standard"),
|
|
8227
|
+
senderName: record?.senderName,
|
|
8228
|
+
agent: agentType,
|
|
8229
|
+
instanceId: record?.instanceId,
|
|
8230
|
+
historySessionId: normalizeSavedHistorySessionId(record?.historySessionId || normalizedSessionId),
|
|
8231
|
+
sessionTitle: record?.sessionTitle,
|
|
8232
|
+
workspace: record?.workspace
|
|
8233
|
+
})).filter(Boolean);
|
|
8234
|
+
}
|
|
8235
|
+
function callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, historySessionId, workspace) {
|
|
8236
|
+
const fn = getProviderNativeHistoryScript(scripts, canonicalHistory, "readSession");
|
|
8237
|
+
if (!fn) return null;
|
|
8238
|
+
const result = fn({
|
|
8239
|
+
agentType,
|
|
8240
|
+
sessionId: historySessionId,
|
|
8241
|
+
historySessionId,
|
|
8242
|
+
workspace,
|
|
8243
|
+
format: canonicalHistory?.format,
|
|
8244
|
+
watchPath: canonicalHistory?.watchPath,
|
|
8245
|
+
args: { sessionId: historySessionId, historySessionId, workspace }
|
|
8246
|
+
});
|
|
8247
|
+
if (!result || typeof result !== "object") return null;
|
|
8248
|
+
const records = normalizeProviderNativeHistoryRecords(agentType, historySessionId, result.messages || result.records);
|
|
8249
|
+
if (records.length === 0) return null;
|
|
8250
|
+
return {
|
|
8251
|
+
records,
|
|
8252
|
+
sourcePath: typeof result.sourcePath === "string" ? result.sourcePath : "",
|
|
8253
|
+
sourceMtimeMs: Number(result.sourceMtimeMs) || 0
|
|
8254
|
+
};
|
|
8679
8255
|
}
|
|
8680
|
-
function
|
|
8681
|
-
const
|
|
8682
|
-
|
|
8683
|
-
|
|
8684
|
-
if (output && typeof output === "object") {
|
|
8685
|
-
try {
|
|
8686
|
-
return JSON.stringify(output).trim();
|
|
8687
|
-
} catch {
|
|
8688
|
-
return "";
|
|
8689
|
-
}
|
|
8690
|
-
}
|
|
8691
|
-
return "";
|
|
8256
|
+
function buildNativeHistoryReadResult(agentType, canonicalHistory, scripts, historySessionId, workspace) {
|
|
8257
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || "");
|
|
8258
|
+
if (!canonicalHistory || !normalizedSessionId || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
|
|
8259
|
+
return callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace);
|
|
8692
8260
|
}
|
|
8693
|
-
function
|
|
8261
|
+
function materializeNativeHistoryToMirror(agentType, canonicalHistory, historySessionId, workspace, scripts) {
|
|
8694
8262
|
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8695
|
-
if (!normalizedSessionId
|
|
8696
|
-
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
|
|
8704
|
-
|
|
8705
|
-
|
|
8706
|
-
|
|
8707
|
-
parsed = null;
|
|
8708
|
-
}
|
|
8709
|
-
if (!parsed) continue;
|
|
8710
|
-
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
8711
|
-
fallbackTs = receivedAt + 1;
|
|
8712
|
-
const type = String(parsed.type || "").trim();
|
|
8713
|
-
const payload = parsed.payload && typeof parsed.payload === "object" ? parsed.payload : null;
|
|
8714
|
-
if (!payload) continue;
|
|
8715
|
-
if (type === "session_meta") {
|
|
8716
|
-
const parsedSessionId = String(payload.id || "").trim();
|
|
8717
|
-
if (parsedSessionId && parsedSessionId !== normalizedSessionId) return null;
|
|
8718
|
-
const parsedWorkspace = String(payload.cwd || workspace || "").trim();
|
|
8719
|
-
if (records.length === 0 && parsedWorkspace) {
|
|
8720
|
-
records.push({
|
|
8721
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8722
|
-
receivedAt,
|
|
8723
|
-
role: "system",
|
|
8724
|
-
kind: "session_start",
|
|
8725
|
-
content: parsedWorkspace,
|
|
8726
|
-
agent: "codex-cli",
|
|
8727
|
-
historySessionId: normalizedSessionId,
|
|
8728
|
-
workspace: parsedWorkspace
|
|
8729
|
-
});
|
|
8730
|
-
}
|
|
8731
|
-
continue;
|
|
8732
|
-
}
|
|
8733
|
-
if (type !== "response_item") continue;
|
|
8734
|
-
const payloadType = String(payload.type || "").trim();
|
|
8735
|
-
if (payloadType === "message") {
|
|
8736
|
-
const role = String(payload.role || "").trim();
|
|
8737
|
-
if (role !== "user" && role !== "assistant") continue;
|
|
8738
|
-
const content = flattenCodexContent(payload.content);
|
|
8739
|
-
if (!content) continue;
|
|
8740
|
-
records.push({
|
|
8741
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8742
|
-
receivedAt,
|
|
8743
|
-
role,
|
|
8744
|
-
content,
|
|
8745
|
-
kind: "standard",
|
|
8746
|
-
agent: "codex-cli",
|
|
8747
|
-
historySessionId: normalizedSessionId
|
|
8748
|
-
});
|
|
8749
|
-
continue;
|
|
8750
|
-
}
|
|
8751
|
-
if (payloadType === "function_call" || payloadType === "custom_tool_call") {
|
|
8752
|
-
const content = summarizeCodexToolCall(payload);
|
|
8753
|
-
if (!content) continue;
|
|
8754
|
-
records.push({
|
|
8755
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8756
|
-
receivedAt,
|
|
8757
|
-
role: "assistant",
|
|
8758
|
-
content,
|
|
8759
|
-
kind: "tool",
|
|
8760
|
-
senderName: "Tool",
|
|
8761
|
-
agent: "codex-cli",
|
|
8762
|
-
historySessionId: normalizedSessionId
|
|
8763
|
-
});
|
|
8764
|
-
continue;
|
|
8765
|
-
}
|
|
8766
|
-
if (payloadType === "function_call_output" || payloadType === "custom_tool_call_output") {
|
|
8767
|
-
const content = codexToolOutputContent(payload);
|
|
8768
|
-
if (!content) continue;
|
|
8769
|
-
records.push({
|
|
8770
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8771
|
-
receivedAt,
|
|
8772
|
-
role: "assistant",
|
|
8773
|
-
content,
|
|
8774
|
-
kind: "tool",
|
|
8775
|
-
senderName: "Tool",
|
|
8776
|
-
agent: "codex-cli",
|
|
8777
|
-
historySessionId: normalizedSessionId
|
|
8778
|
-
});
|
|
8779
|
-
}
|
|
8780
|
-
}
|
|
8781
|
-
return records;
|
|
8782
|
-
} catch {
|
|
8783
|
-
return null;
|
|
8784
|
-
}
|
|
8263
|
+
if (!normalizedSessionId) return false;
|
|
8264
|
+
const nativeResult = callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace);
|
|
8265
|
+
const nativeRecords = nativeResult?.records || [];
|
|
8266
|
+
if (nativeRecords.length === 0) return false;
|
|
8267
|
+
const normalizedRecords = nativeRecords.map((record) => ({
|
|
8268
|
+
...record,
|
|
8269
|
+
agent: agentType,
|
|
8270
|
+
historySessionId: normalizedSessionId
|
|
8271
|
+
}));
|
|
8272
|
+
const existingSessionStart = readExistingSessionStartRecord(agentType, normalizedSessionId);
|
|
8273
|
+
const records = existingSessionStart && normalizedRecords[0]?.kind !== "session_start" ? [{ ...existingSessionStart, historySessionId: normalizedSessionId, agent: agentType }, ...normalizedRecords] : normalizedRecords;
|
|
8274
|
+
return rewriteCanonicalSavedHistory(agentType, normalizedSessionId, records);
|
|
8785
8275
|
}
|
|
8786
|
-
function
|
|
8787
|
-
|
|
8788
|
-
|
|
8789
|
-
const records = buildCodexNativeHistoryRecords(normalizedSessionId, workspace);
|
|
8790
|
-
if (!records || records.length === 0) return false;
|
|
8791
|
-
const existingSessionStart = readExistingSessionStartRecord("codex-cli", normalizedSessionId);
|
|
8792
|
-
const recordsToWrite = existingSessionStart && records[0]?.kind !== "session_start" ? [{ ...existingSessionStart, historySessionId: normalizedSessionId }, ...records] : records;
|
|
8793
|
-
return rewriteCanonicalSavedHistory("codex-cli", normalizedSessionId, recordsToWrite);
|
|
8276
|
+
function materializeProviderNativeHistory(agentType, canonicalHistory, historySessionId, workspace, scripts) {
|
|
8277
|
+
if (!canonicalHistory || canonicalHistory.mode !== "materialized-mirror") return false;
|
|
8278
|
+
return materializeNativeHistoryToMirror(agentType, canonicalHistory, historySessionId, workspace, scripts);
|
|
8794
8279
|
}
|
|
8795
8280
|
function isNativeSourceCanonicalHistory(canonicalHistory) {
|
|
8796
8281
|
if (!canonicalHistory) return false;
|
|
@@ -8798,21 +8283,15 @@ function isNativeSourceCanonicalHistory(canonicalHistory) {
|
|
|
8798
8283
|
if (canonicalHistory.mode === "materialized-mirror") return false;
|
|
8799
8284
|
return true;
|
|
8800
8285
|
}
|
|
8801
|
-
function buildNativeHistoryRecords(canonicalHistory, historySessionId, workspace) {
|
|
8802
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || "");
|
|
8803
|
-
if (!canonicalHistory || !normalizedSessionId || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
|
|
8804
|
-
if (canonicalHistory.format === "hermes-json") return buildHermesNativeHistoryRecords(normalizedSessionId);
|
|
8805
|
-
if (canonicalHistory.format === "claude-jsonl") return buildClaudeNativeHistoryRecords(normalizedSessionId, workspace);
|
|
8806
|
-
if (canonicalHistory.format === "codex-jsonl") return buildCodexNativeHistoryRecords(normalizedSessionId, workspace);
|
|
8807
|
-
return null;
|
|
8808
|
-
}
|
|
8809
8286
|
function readProviderChatHistory(agentType, options = {}) {
|
|
8810
8287
|
if (isNativeSourceCanonicalHistory(options.canonicalHistory) && options.historySessionId) {
|
|
8811
|
-
const
|
|
8812
|
-
if (!
|
|
8288
|
+
const nativeResult = buildNativeHistoryReadResult(agentType, options.canonicalHistory, options.scripts, options.historySessionId, options.workspace);
|
|
8289
|
+
if (!nativeResult) return { messages: [], hasMore: false, source: "native-unavailable" };
|
|
8813
8290
|
return {
|
|
8814
|
-
...pageHistoryRecords(agentType, records, options.offset || 0, options.limit || 30, options.excludeRecentCount || 0, options.historyBehavior),
|
|
8815
|
-
source: "provider-native"
|
|
8291
|
+
...pageHistoryRecords(agentType, nativeResult.records, options.offset || 0, options.limit || 30, options.excludeRecentCount || 0, options.historyBehavior),
|
|
8292
|
+
source: "provider-native",
|
|
8293
|
+
sourcePath: nativeResult.sourcePath,
|
|
8294
|
+
sourceMtimeMs: nativeResult.sourceMtimeMs
|
|
8816
8295
|
};
|
|
8817
8296
|
}
|
|
8818
8297
|
return {
|
|
@@ -8845,68 +8324,64 @@ function buildNativeSessionSummary(agentType, historySessionId, records, sourceP
|
|
|
8845
8324
|
sourceMtimeMs
|
|
8846
8325
|
};
|
|
8847
8326
|
}
|
|
8848
|
-
function
|
|
8849
|
-
|
|
8850
|
-
|
|
8851
|
-
const
|
|
8852
|
-
|
|
8853
|
-
|
|
8854
|
-
|
|
8855
|
-
|
|
8856
|
-
|
|
8857
|
-
|
|
8858
|
-
|
|
8859
|
-
|
|
8860
|
-
|
|
8861
|
-
|
|
8862
|
-
|
|
8863
|
-
|
|
8864
|
-
|
|
8865
|
-
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
}
|
|
8869
|
-
}
|
|
8870
|
-
return results;
|
|
8327
|
+
function normalizeProviderNativeHistorySessionSummary(agentType, item) {
|
|
8328
|
+
const historySessionId = normalizeSavedHistorySessionId(item?.historySessionId || item?.sessionId || "");
|
|
8329
|
+
if (!historySessionId) return null;
|
|
8330
|
+
const sourcePath = typeof item?.sourcePath === "string" ? item.sourcePath : "";
|
|
8331
|
+
const sourceMtimeMs = Number(item?.sourceMtimeMs) || 0;
|
|
8332
|
+
const firstMessageAt = Number(item?.firstMessageAt) || sourceMtimeMs || Date.now();
|
|
8333
|
+
const lastMessageAt = Number(item?.lastMessageAt) || firstMessageAt;
|
|
8334
|
+
const messageCount = Math.max(0, Number(item?.messageCount) || 0);
|
|
8335
|
+
return {
|
|
8336
|
+
historySessionId,
|
|
8337
|
+
sessionTitle: typeof item?.sessionTitle === "string" ? item.sessionTitle : void 0,
|
|
8338
|
+
messageCount,
|
|
8339
|
+
firstMessageAt,
|
|
8340
|
+
lastMessageAt,
|
|
8341
|
+
preview: typeof item?.preview === "string" ? item.preview : void 0,
|
|
8342
|
+
workspace: typeof item?.workspace === "string" ? item.workspace : void 0,
|
|
8343
|
+
source: "provider-native",
|
|
8344
|
+
sourcePath,
|
|
8345
|
+
sourceMtimeMs
|
|
8346
|
+
};
|
|
8871
8347
|
}
|
|
8872
|
-
function
|
|
8348
|
+
function collectProviderScriptNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) {
|
|
8349
|
+
const fn = getProviderNativeHistoryScript(scripts, canonicalHistory, "listSessions");
|
|
8350
|
+
if (!fn) return null;
|
|
8351
|
+
const result = fn({
|
|
8352
|
+
agentType,
|
|
8353
|
+
format: canonicalHistory.format,
|
|
8354
|
+
watchPath: canonicalHistory.watchPath,
|
|
8355
|
+
args: {}
|
|
8356
|
+
});
|
|
8357
|
+
if (!result || typeof result !== "object") return [];
|
|
8358
|
+
const sessions = Array.isArray(result.sessions) ? result.sessions : [];
|
|
8873
8359
|
const summaries = [];
|
|
8874
|
-
|
|
8875
|
-
|
|
8876
|
-
|
|
8877
|
-
const fileName = path7.basename(filePath);
|
|
8878
|
-
const historySessionId = fileName.replace(/^session_/, "").replace(/\.json$/, "");
|
|
8879
|
-
const records = buildHermesNativeHistoryRecords(historySessionId);
|
|
8880
|
-
const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
|
|
8881
|
-
if (summary) summaries.push(summary);
|
|
8882
|
-
}
|
|
8883
|
-
} else if (canonicalHistory.format === "claude-jsonl") {
|
|
8884
|
-
const root = path7.join(os5.homedir(), ".claude", "projects");
|
|
8885
|
-
for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && entry.name.endsWith(".jsonl"))) {
|
|
8886
|
-
const historySessionId = path7.basename(filePath, ".jsonl");
|
|
8887
|
-
const records = buildClaudeNativeHistoryRecords(historySessionId);
|
|
8888
|
-
const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
|
|
8889
|
-
if (summary) summaries.push(summary);
|
|
8890
|
-
}
|
|
8891
|
-
} else if (canonicalHistory.format === "codex-jsonl") {
|
|
8892
|
-
const root = path7.join(os5.homedir(), ".codex", "sessions");
|
|
8893
|
-
const uuidPattern = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i;
|
|
8894
|
-
for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && entry.name.endsWith(".jsonl"))) {
|
|
8895
|
-
const meta = readCodexSessionMeta(filePath);
|
|
8896
|
-
const historySessionId = String(meta?.id || path7.basename(filePath).match(uuidPattern)?.[1] || "").trim();
|
|
8360
|
+
for (const item of sessions) {
|
|
8361
|
+
if (Array.isArray(item?.messages || item?.records)) {
|
|
8362
|
+
const historySessionId = normalizeSavedHistorySessionId(item?.historySessionId || item?.sessionId || "");
|
|
8897
8363
|
if (!historySessionId) continue;
|
|
8898
|
-
const records =
|
|
8899
|
-
const
|
|
8900
|
-
if (
|
|
8364
|
+
const records = normalizeProviderNativeHistoryRecords(agentType, historySessionId, item.messages || item.records);
|
|
8365
|
+
const summary2 = buildNativeSessionSummary(agentType, historySessionId, records, typeof item?.sourcePath === "string" ? item.sourcePath : "");
|
|
8366
|
+
if (summary2) {
|
|
8367
|
+
if (Number(item?.sourceMtimeMs)) summary2.sourceMtimeMs = Number(item.sourceMtimeMs);
|
|
8368
|
+
summaries.push(summary2);
|
|
8369
|
+
}
|
|
8370
|
+
continue;
|
|
8901
8371
|
}
|
|
8372
|
+
const summary = normalizeProviderNativeHistorySessionSummary(agentType, item);
|
|
8373
|
+
if (summary) summaries.push(summary);
|
|
8902
8374
|
}
|
|
8903
8375
|
return sortSavedHistorySessionSummaries(summaries);
|
|
8904
8376
|
}
|
|
8377
|
+
function collectNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) {
|
|
8378
|
+
return collectProviderScriptNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) || [];
|
|
8379
|
+
}
|
|
8905
8380
|
function listProviderHistorySessions(agentType, options = {}) {
|
|
8906
8381
|
if (isNativeSourceCanonicalHistory(options.canonicalHistory)) {
|
|
8907
8382
|
const offset = Math.max(0, options.offset || 0);
|
|
8908
8383
|
const limit = Math.max(1, options.limit || 30);
|
|
8909
|
-
const summaries = collectNativeHistorySessionSummaries(agentType, options.canonicalHistory);
|
|
8384
|
+
const summaries = collectNativeHistorySessionSummaries(agentType, options.canonicalHistory, options.scripts);
|
|
8910
8385
|
return {
|
|
8911
8386
|
sessions: summaries.slice(offset, offset + limit),
|
|
8912
8387
|
hasMore: offset + limit < summaries.length,
|
|
@@ -11539,7 +11014,8 @@ async function handleChatHistory(h, args) {
|
|
|
11539
11014
|
offset: offset || 0,
|
|
11540
11015
|
limit: limit || 30,
|
|
11541
11016
|
excludeRecentCount,
|
|
11542
|
-
historyBehavior: provider?.historyBehavior
|
|
11017
|
+
historyBehavior: provider?.historyBehavior,
|
|
11018
|
+
scripts: provider?.scripts
|
|
11543
11019
|
});
|
|
11544
11020
|
return { success: true, ...result, agent: agentStr };
|
|
11545
11021
|
} catch (e) {
|
|
@@ -14013,13 +13489,8 @@ var CliProviderInstance = class {
|
|
|
14013
13489
|
historyWriter;
|
|
14014
13490
|
runtimeMessages = [];
|
|
14015
13491
|
lastPersistedHistoryMessages = [];
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
lastCanonicalHermesWatchPath = void 0;
|
|
14019
|
-
lastCanonicalClaudeRebuildMtimeMs = 0;
|
|
14020
|
-
lastCanonicalClaudeCheckAt = 0;
|
|
14021
|
-
lastCanonicalCodexRebuildMtimeMs = 0;
|
|
14022
|
-
lastCanonicalCodexCheckAt = 0;
|
|
13492
|
+
lastNativeSourceCanonicalCheckAt = 0;
|
|
13493
|
+
lastNativeSourceCanonicalCacheKey = void 0;
|
|
14023
13494
|
cachedSqliteDb = null;
|
|
14024
13495
|
cachedSqliteDbPath = null;
|
|
14025
13496
|
cachedSqliteDbMissingUntil = 0;
|
|
@@ -14720,76 +14191,44 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14720
14191
|
const canonicalHistory = this.provider.canonicalHistory;
|
|
14721
14192
|
if (!canonicalHistory) return false;
|
|
14722
14193
|
if (isNativeSourceCanonicalHistory(canonicalHistory)) {
|
|
14194
|
+
const cacheKey = [this.type, this.providerSessionId, this.workingDir].join("\0");
|
|
14195
|
+
const now = Date.now();
|
|
14196
|
+
if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
|
|
14197
|
+
return true;
|
|
14198
|
+
}
|
|
14199
|
+
this.lastNativeSourceCanonicalCacheKey = cacheKey;
|
|
14200
|
+
this.lastNativeSourceCanonicalCheckAt = now;
|
|
14723
14201
|
const restoredHistory = readProviderChatHistory(this.type, {
|
|
14724
14202
|
canonicalHistory,
|
|
14725
14203
|
historySessionId: this.providerSessionId,
|
|
14726
14204
|
workspace: this.workingDir,
|
|
14727
14205
|
offset: 0,
|
|
14728
14206
|
limit: Number.MAX_SAFE_INTEGER,
|
|
14729
|
-
historyBehavior: this.provider.historyBehavior
|
|
14207
|
+
historyBehavior: this.provider.historyBehavior,
|
|
14208
|
+
scripts: this.provider.scripts
|
|
14730
14209
|
});
|
|
14731
|
-
if (restoredHistory.source
|
|
14732
|
-
|
|
14733
|
-
|
|
14734
|
-
|
|
14735
|
-
|
|
14736
|
-
|
|
14737
|
-
|
|
14738
|
-
|
|
14210
|
+
if (restoredHistory.source === "provider-native") {
|
|
14211
|
+
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
14212
|
+
role: message.role,
|
|
14213
|
+
content: message.content,
|
|
14214
|
+
kind: message.kind,
|
|
14215
|
+
senderName: message.senderName,
|
|
14216
|
+
receivedAt: message.receivedAt
|
|
14217
|
+
}));
|
|
14218
|
+
}
|
|
14739
14219
|
return true;
|
|
14740
14220
|
}
|
|
14741
14221
|
try {
|
|
14742
|
-
|
|
14743
|
-
|
|
14744
|
-
|
|
14745
|
-
|
|
14746
|
-
|
|
14747
|
-
|
|
14748
|
-
|
|
14749
|
-
|
|
14750
|
-
|
|
14751
|
-
if (!fs5.existsSync(watchPath)) return false;
|
|
14752
|
-
}
|
|
14753
|
-
const stat = fs5.statSync(watchPath);
|
|
14754
|
-
if (stat.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
|
|
14755
|
-
rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
|
|
14756
|
-
if (rebuilt) this.lastCanonicalHermesSyncMtimeMs = stat.mtimeMs;
|
|
14757
|
-
} else if (canonicalHistory.format === "claude-jsonl") {
|
|
14758
|
-
const now = Date.now();
|
|
14759
|
-
if (now - this.lastCanonicalClaudeCheckAt < 2e3 && this.lastCanonicalClaudeRebuildMtimeMs !== 0) {
|
|
14760
|
-
return true;
|
|
14761
|
-
}
|
|
14762
|
-
this.lastCanonicalClaudeCheckAt = now;
|
|
14763
|
-
const claudeProjectsDir = path11.join(os11.homedir(), ".claude", "projects");
|
|
14764
|
-
const workspaceSegment = typeof this.workingDir === "string" ? this.workingDir.replace(/[\\/]/g, "-").replace(/^-+/, "") : "";
|
|
14765
|
-
const transcriptFile = path11.join(claudeProjectsDir, workspaceSegment, `${this.providerSessionId}.jsonl`);
|
|
14766
|
-
let transcriptMtime = 0;
|
|
14767
|
-
try {
|
|
14768
|
-
transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
|
|
14769
|
-
} catch {
|
|
14770
|
-
}
|
|
14771
|
-
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalClaudeRebuildMtimeMs) return true;
|
|
14772
|
-
rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
|
|
14773
|
-
if (rebuilt) this.lastCanonicalClaudeRebuildMtimeMs = transcriptMtime || Date.now();
|
|
14774
|
-
} else if (canonicalHistory.format === "codex-jsonl") {
|
|
14775
|
-
const now = Date.now();
|
|
14776
|
-
if (now - this.lastCanonicalCodexCheckAt < 2e3 && this.lastCanonicalCodexRebuildMtimeMs !== 0) {
|
|
14777
|
-
return true;
|
|
14778
|
-
}
|
|
14779
|
-
this.lastCanonicalCodexCheckAt = now;
|
|
14780
|
-
const transcriptFile = resolveCodexSessionTranscriptPath(this.providerSessionId, this.workingDir);
|
|
14781
|
-
let transcriptMtime = 0;
|
|
14782
|
-
if (transcriptFile) {
|
|
14783
|
-
try {
|
|
14784
|
-
transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
|
|
14785
|
-
} catch {
|
|
14786
|
-
}
|
|
14787
|
-
}
|
|
14788
|
-
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalCodexRebuildMtimeMs) return true;
|
|
14789
|
-
rebuilt = rebuildCodexSavedHistoryFromNativeSession(this.providerSessionId, this.workingDir);
|
|
14790
|
-
if (rebuilt) this.lastCanonicalCodexRebuildMtimeMs = transcriptMtime || Date.now();
|
|
14222
|
+
const cacheKey = [this.type, this.providerSessionId, this.workingDir, canonicalHistory.mode || "materialized-mirror"].join("\0");
|
|
14223
|
+
const now = Date.now();
|
|
14224
|
+
if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
|
|
14225
|
+
return true;
|
|
14226
|
+
}
|
|
14227
|
+
this.lastNativeSourceCanonicalCacheKey = cacheKey;
|
|
14228
|
+
this.lastNativeSourceCanonicalCheckAt = now;
|
|
14229
|
+
if (!materializeProviderNativeHistory(this.type, canonicalHistory, this.providerSessionId, this.workingDir, this.provider.scripts)) {
|
|
14230
|
+
return false;
|
|
14791
14231
|
}
|
|
14792
|
-
if (!rebuilt) return false;
|
|
14793
14232
|
const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
14794
14233
|
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
14795
14234
|
role: message.role,
|
|
@@ -14812,7 +14251,8 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14812
14251
|
workspace: this.workingDir,
|
|
14813
14252
|
offset: 0,
|
|
14814
14253
|
limit: Number.MAX_SAFE_INTEGER,
|
|
14815
|
-
historyBehavior: this.provider.historyBehavior
|
|
14254
|
+
historyBehavior: this.provider.historyBehavior,
|
|
14255
|
+
scripts: this.provider.scripts
|
|
14816
14256
|
}) : (() => {
|
|
14817
14257
|
this.historyWriter.compactHistorySession(this.type, this.providerSessionId, this.provider.historyBehavior);
|
|
14818
14258
|
return readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
@@ -16947,6 +16387,7 @@ function validateProviderDefinition(raw) {
|
|
|
16947
16387
|
warnings.push("Extension providers should have extensionId");
|
|
16948
16388
|
}
|
|
16949
16389
|
validateCapabilities(provider, controls, errors);
|
|
16390
|
+
validateCanonicalHistory(provider.canonicalHistory, errors);
|
|
16950
16391
|
for (const control of controls) {
|
|
16951
16392
|
validateControl(control, errors);
|
|
16952
16393
|
}
|
|
@@ -17004,6 +16445,39 @@ function validateCapabilities(provider, controls, errors) {
|
|
|
17004
16445
|
errors.push("providers declaring controls must set capabilities.controls.typedResults=true");
|
|
17005
16446
|
}
|
|
17006
16447
|
}
|
|
16448
|
+
function validateCanonicalHistory(raw, errors) {
|
|
16449
|
+
if (raw === void 0) return;
|
|
16450
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
16451
|
+
errors.push("canonicalHistory must be an object");
|
|
16452
|
+
return;
|
|
16453
|
+
}
|
|
16454
|
+
const canonicalHistory = raw;
|
|
16455
|
+
const format = canonicalHistory.format;
|
|
16456
|
+
if (format !== void 0 && (typeof format !== "string" || !format.trim())) {
|
|
16457
|
+
errors.push("canonicalHistory.format must be a non-empty string when provided");
|
|
16458
|
+
}
|
|
16459
|
+
const watchPath = canonicalHistory.watchPath;
|
|
16460
|
+
if (watchPath !== void 0 && (typeof watchPath !== "string" || !watchPath.trim())) {
|
|
16461
|
+
errors.push("canonicalHistory.watchPath must be a non-empty string when provided");
|
|
16462
|
+
}
|
|
16463
|
+
const mode = canonicalHistory.mode;
|
|
16464
|
+
if (mode !== void 0 && !["native-source", "materialized-mirror", "disabled"].includes(String(mode))) {
|
|
16465
|
+
errors.push("canonicalHistory.mode must be one of: native-source, materialized-mirror, disabled");
|
|
16466
|
+
}
|
|
16467
|
+
const scripts = canonicalHistory.scripts;
|
|
16468
|
+
if (scripts === void 0) return;
|
|
16469
|
+
if (!scripts || typeof scripts !== "object" || Array.isArray(scripts)) {
|
|
16470
|
+
errors.push("canonicalHistory.scripts must be an object");
|
|
16471
|
+
return;
|
|
16472
|
+
}
|
|
16473
|
+
const scriptConfig = scripts;
|
|
16474
|
+
for (const key of ["readSession", "listSessions"]) {
|
|
16475
|
+
const value = scriptConfig[key];
|
|
16476
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
16477
|
+
errors.push(`canonicalHistory.scripts.${key} must be a non-empty string`);
|
|
16478
|
+
}
|
|
16479
|
+
}
|
|
16480
|
+
}
|
|
17007
16481
|
function validateControl(control, errors) {
|
|
17008
16482
|
if (!control || typeof control !== "object") {
|
|
17009
16483
|
errors.push("controls: each control must be an object");
|
|
@@ -20147,7 +19621,8 @@ var DaemonCommandRouter = class {
|
|
|
20147
19621
|
canonicalHistory: providerMeta?.canonicalHistory,
|
|
20148
19622
|
offset,
|
|
20149
19623
|
limit,
|
|
20150
|
-
historyBehavior: providerMeta?.historyBehavior
|
|
19624
|
+
historyBehavior: providerMeta?.historyBehavior,
|
|
19625
|
+
scripts: providerMeta?.scripts
|
|
20151
19626
|
});
|
|
20152
19627
|
const state = loadState();
|
|
20153
19628
|
const savedSessions = getSavedProviderSessions(state, { providerType, kind });
|
|
@@ -20173,7 +19648,10 @@ var DaemonCommandRouter = class {
|
|
|
20173
19648
|
messageCount: session.messageCount,
|
|
20174
19649
|
firstMessageAt: session.firstMessageAt,
|
|
20175
19650
|
lastMessageAt: session.lastMessageAt,
|
|
20176
|
-
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById
|
|
19651
|
+
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById,
|
|
19652
|
+
historySource: session.source,
|
|
19653
|
+
sourcePath: session.sourcePath,
|
|
19654
|
+
sourceMtimeMs: session.sourceMtimeMs
|
|
20177
19655
|
};
|
|
20178
19656
|
}),
|
|
20179
19657
|
hasMore,
|