@adhdev/daemon-core 0.9.45 → 0.9.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.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 buildHermesNativeHistoryRecords(historySessionId) {
8079
- const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
8080
- if (!normalizedSessionId) return null;
8081
- try {
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 readCodexSessionMeta(filePath) {
8426
- try {
8427
- const firstLine = fs3.readFileSync(filePath, "utf-8").split("\n").find(Boolean);
8428
- if (!firstLine) return null;
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 resolveCodexSessionTranscriptPath(historySessionId, workspace) {
8065
+ function normalizeProviderNativeHistoryRecords(agentType, historySessionId, records) {
8066
+ if (!Array.isArray(records)) return [];
8438
8067
  const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
8439
- if (!normalizedSessionId || !isUuidLikeSessionId(normalizedSessionId)) return null;
8440
- const sessionsDir = path7.join(os5.homedir(), ".codex", "sessions");
8441
- if (!fs3.existsSync(sessionsDir)) return null;
8442
- const normalizedWorkspace = typeof workspace === "string" ? workspace.trim() : "";
8443
- const candidates = [];
8444
- const stack = [sessionsDir];
8445
- while (stack.length > 0) {
8446
- const current = stack.pop();
8447
- if (!current) continue;
8448
- let entries = [];
8449
- try {
8450
- entries = fs3.readdirSync(current, { withFileTypes: true });
8451
- } catch {
8452
- continue;
8453
- }
8454
- for (const entry of entries) {
8455
- const entryPath = path7.join(current, entry.name);
8456
- if (entry.isDirectory()) {
8457
- stack.push(entryPath);
8458
- continue;
8459
- }
8460
- if (!entry.isFile() || !entry.name.endsWith(".jsonl") || !entry.name.includes(normalizedSessionId)) continue;
8461
- const meta = readCodexSessionMeta(entryPath);
8462
- const metaSessionId = String(meta?.id || "").trim();
8463
- if (metaSessionId && metaSessionId !== normalizedSessionId) continue;
8464
- const metaWorkspace = String(meta?.cwd || "").trim();
8465
- let mtimeMs = 0;
8466
- try {
8467
- mtimeMs = fs3.statSync(entryPath).mtimeMs;
8468
- } catch {
8469
- }
8470
- candidates.push({
8471
- path: entryPath,
8472
- mtimeMs,
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 codexToolOutputContent(payload) {
8528
- const output = payload.output ?? payload.result ?? payload.content;
8529
- const text = flattenCodexContent(output);
8530
- if (text) return text;
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 buildCodexNativeHistoryRecords(historySessionId, workspace) {
8108
+ function materializeNativeHistoryToMirror(agentType, canonicalHistory, historySessionId, workspace, scripts) {
8541
8109
  const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
8542
- if (!normalizedSessionId || !isUuidLikeSessionId(normalizedSessionId)) return null;
8543
- try {
8544
- const transcriptPath = resolveCodexSessionTranscriptPath(normalizedSessionId, workspace);
8545
- if (!transcriptPath) return null;
8546
- const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
8547
- const records = [];
8548
- let fallbackTs = Date.now();
8549
- for (const line of lines) {
8550
- let parsed = null;
8551
- try {
8552
- parsed = JSON.parse(line);
8553
- } catch {
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 rebuildCodexSavedHistoryFromNativeSession(historySessionId, workspace) {
8634
- const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
8635
- if (!normalizedSessionId || !isUuidLikeSessionId(normalizedSessionId)) return false;
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 records = buildNativeHistoryRecords(options.canonicalHistory, options.historySessionId, options.workspace);
8659
- if (!records) return { messages: [], hasMore: false, source: "native-unavailable" };
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 listFilesRecursive(root, predicate) {
8696
- if (!fs3.existsSync(root)) return [];
8697
- const results = [];
8698
- const stack = [root];
8699
- while (stack.length > 0) {
8700
- const current = stack.pop();
8701
- if (!current) continue;
8702
- let entries = [];
8703
- try {
8704
- entries = fs3.readdirSync(current, { withFileTypes: true });
8705
- } catch {
8706
- continue;
8707
- }
8708
- for (const entry of entries) {
8709
- const entryPath = path7.join(current, entry.name);
8710
- if (entry.isDirectory()) {
8711
- stack.push(entryPath);
8712
- continue;
8713
- }
8714
- if (predicate(entryPath, entry)) results.push(entryPath);
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 collectNativeHistorySessionSummaries(agentType, canonicalHistory) {
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
- if (canonicalHistory.format === "hermes-json") {
8722
- const root = path7.join(os5.homedir(), ".hermes", "sessions");
8723
- for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && /^session_.+\.json$/.test(entry.name))) {
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 = buildCodexNativeHistoryRecords(historySessionId, String(meta?.cwd || "").trim() || void 0);
8746
- const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
8747
- if (summary) summaries.push(summary);
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
- lastCanonicalHermesSyncMtimeMs = 0;
13864
- lastCanonicalHermesExistCheckAt = 0;
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 !== "provider-native") return false;
14579
- this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
14580
- role: message.role,
14581
- content: message.content,
14582
- kind: message.kind,
14583
- senderName: message.senderName,
14584
- receivedAt: message.receivedAt
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
- let rebuilt = false;
14590
- if (canonicalHistory.format === "hermes-json") {
14591
- const watchPath = canonicalHistory.watchPath.replace(/^~/, os11.homedir()).replace("{{sessionId}}", this.providerSessionId);
14592
- const now = Date.now();
14593
- if (watchPath !== this.lastCanonicalHermesWatchPath || now - this.lastCanonicalHermesExistCheckAt >= 2e3) {
14594
- this.lastCanonicalHermesWatchPath = watchPath;
14595
- this.lastCanonicalHermesExistCheckAt = now;
14596
- if (!fs5.existsSync(watchPath)) return false;
14597
- } else if (this.lastCanonicalHermesSyncMtimeMs === 0) {
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");
@@ -19994,12 +19468,13 @@ var DaemonCommandRouter = class {
19994
19468
  const wantsAll = args?.all === true;
19995
19469
  const offset = wantsAll ? 0 : Math.max(0, Number(args?.offset) || 0);
19996
19470
  const limit = wantsAll ? Number.MAX_SAFE_INTEGER : Math.max(1, Math.min(100, Number(args?.limit) || 30));
19997
- const providerMeta = this.deps.providerLoader.getMeta(providerType);
19471
+ const providerMeta = this.deps.providerLoader.resolve?.(providerType) || this.deps.providerLoader.getMeta(providerType);
19998
19472
  const { sessions: historySessions, hasMore, source } = listProviderHistorySessions(providerType, {
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,