adhdev 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/cli/index.js +228 -724
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +228 -724
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4145,29 +4145,6 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
4145
4145
|
return { sessions: [], hasMore: false };
|
|
4146
4146
|
}
|
|
4147
4147
|
}
|
|
4148
|
-
function normalizeCanonicalHermesMessageContent(content) {
|
|
4149
|
-
if (typeof content === "string") return content.trim();
|
|
4150
|
-
if (content == null) return "";
|
|
4151
|
-
try {
|
|
4152
|
-
return JSON.stringify(content).trim();
|
|
4153
|
-
} catch {
|
|
4154
|
-
return String(content).trim();
|
|
4155
|
-
}
|
|
4156
|
-
}
|
|
4157
|
-
function extractCanonicalHermesMessageTimestamp(message, fallbackTs) {
|
|
4158
|
-
const numericTimestamp = Number(message.receivedAt || message.timestamp || message.ts || 0);
|
|
4159
|
-
if (Number.isFinite(numericTimestamp) && numericTimestamp > 0) return numericTimestamp;
|
|
4160
|
-
const stringTimestamp = typeof message.ts === "string" ? Date.parse(message.ts) : typeof message.timestamp === "string" ? Date.parse(message.timestamp) : NaN;
|
|
4161
|
-
if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
|
|
4162
|
-
return fallbackTs;
|
|
4163
|
-
}
|
|
4164
|
-
function extractTimestampValue(value) {
|
|
4165
|
-
const numericTimestamp = Number(value || 0);
|
|
4166
|
-
if (Number.isFinite(numericTimestamp) && numericTimestamp > 0) return numericTimestamp;
|
|
4167
|
-
const stringTimestamp = typeof value === "string" ? Date.parse(value) : NaN;
|
|
4168
|
-
if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
|
|
4169
|
-
return 0;
|
|
4170
|
-
}
|
|
4171
4148
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
4172
4149
|
try {
|
|
4173
4150
|
const dir = path7.join(HISTORY_DIR, agentType);
|
|
@@ -4213,569 +4190,77 @@ function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
|
4213
4190
|
return false;
|
|
4214
4191
|
}
|
|
4215
4192
|
}
|
|
4216
|
-
function
|
|
4217
|
-
const
|
|
4218
|
-
if (
|
|
4219
|
-
|
|
4220
|
-
const sessionFilePath = path7.join(os5.homedir(), ".hermes", "sessions", `session_${normalizedSessionId}.json`);
|
|
4221
|
-
if (!fs3.existsSync(sessionFilePath)) return null;
|
|
4222
|
-
const raw = JSON.parse(fs3.readFileSync(sessionFilePath, "utf-8"));
|
|
4223
|
-
const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
|
|
4224
|
-
const records = [];
|
|
4225
|
-
let fallbackTs = Date.parse(raw.session_start || raw.last_updated || "") || Date.now();
|
|
4226
|
-
for (const message of canonicalMessages) {
|
|
4227
|
-
const role = String(message.role || "").trim();
|
|
4228
|
-
const content = normalizeCanonicalHermesMessageContent(message.content);
|
|
4229
|
-
if (!content) continue;
|
|
4230
|
-
const receivedAt = extractCanonicalHermesMessageTimestamp(message, fallbackTs);
|
|
4231
|
-
fallbackTs = receivedAt + 1;
|
|
4232
|
-
if (role === "user" || role === "assistant") {
|
|
4233
|
-
records.push({
|
|
4234
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4235
|
-
receivedAt,
|
|
4236
|
-
role,
|
|
4237
|
-
content,
|
|
4238
|
-
kind: "standard",
|
|
4239
|
-
agent: "hermes-cli",
|
|
4240
|
-
historySessionId: normalizedSessionId
|
|
4241
|
-
});
|
|
4242
|
-
continue;
|
|
4243
|
-
}
|
|
4244
|
-
if (role === "tool") {
|
|
4245
|
-
records.push({
|
|
4246
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4247
|
-
receivedAt,
|
|
4248
|
-
role: "assistant",
|
|
4249
|
-
content,
|
|
4250
|
-
kind: "tool",
|
|
4251
|
-
senderName: "Tool",
|
|
4252
|
-
agent: "hermes-cli",
|
|
4253
|
-
historySessionId: normalizedSessionId
|
|
4254
|
-
});
|
|
4255
|
-
}
|
|
4256
|
-
}
|
|
4257
|
-
return records;
|
|
4258
|
-
} catch {
|
|
4259
|
-
return null;
|
|
4260
|
-
}
|
|
4261
|
-
}
|
|
4262
|
-
function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
|
|
4263
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
4264
|
-
if (!normalizedSessionId) return false;
|
|
4265
|
-
try {
|
|
4266
|
-
const sessionFilePath = path7.join(os5.homedir(), ".hermes", "sessions", `session_${normalizedSessionId}.json`);
|
|
4267
|
-
if (!fs3.existsSync(sessionFilePath)) return false;
|
|
4268
|
-
const raw = JSON.parse(fs3.readFileSync(sessionFilePath, "utf-8"));
|
|
4269
|
-
const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
|
|
4270
|
-
const dir = path7.join(HISTORY_DIR, "hermes-cli");
|
|
4271
|
-
fs3.mkdirSync(dir, { recursive: true });
|
|
4272
|
-
const existingSessionStart = readExistingSessionStartRecord("hermes-cli", normalizedSessionId);
|
|
4273
|
-
const records = [];
|
|
4274
|
-
if (existingSessionStart) {
|
|
4275
|
-
records.push({
|
|
4276
|
-
...existingSessionStart,
|
|
4277
|
-
historySessionId: normalizedSessionId
|
|
4278
|
-
});
|
|
4279
|
-
}
|
|
4280
|
-
let fallbackTs = Date.parse(raw.session_start || raw.last_updated || "") || Date.now();
|
|
4281
|
-
for (const message of canonicalMessages) {
|
|
4282
|
-
const role = String(message.role || "").trim();
|
|
4283
|
-
const content = normalizeCanonicalHermesMessageContent(message.content);
|
|
4284
|
-
if (!content) continue;
|
|
4285
|
-
const receivedAt = extractCanonicalHermesMessageTimestamp(message, fallbackTs);
|
|
4286
|
-
fallbackTs = receivedAt + 1;
|
|
4287
|
-
if (role === "user") {
|
|
4288
|
-
records.push({
|
|
4289
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4290
|
-
receivedAt,
|
|
4291
|
-
role: "user",
|
|
4292
|
-
content,
|
|
4293
|
-
kind: "standard",
|
|
4294
|
-
agent: "hermes-cli",
|
|
4295
|
-
historySessionId: normalizedSessionId
|
|
4296
|
-
});
|
|
4297
|
-
continue;
|
|
4298
|
-
}
|
|
4299
|
-
if (role === "assistant") {
|
|
4300
|
-
records.push({
|
|
4301
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4302
|
-
receivedAt,
|
|
4303
|
-
role: "assistant",
|
|
4304
|
-
content,
|
|
4305
|
-
kind: "standard",
|
|
4306
|
-
agent: "hermes-cli",
|
|
4307
|
-
historySessionId: normalizedSessionId
|
|
4308
|
-
});
|
|
4309
|
-
continue;
|
|
4310
|
-
}
|
|
4311
|
-
if (role === "tool") {
|
|
4312
|
-
records.push({
|
|
4313
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4314
|
-
receivedAt,
|
|
4315
|
-
role: "assistant",
|
|
4316
|
-
content,
|
|
4317
|
-
kind: "tool",
|
|
4318
|
-
senderName: "Tool",
|
|
4319
|
-
agent: "hermes-cli",
|
|
4320
|
-
historySessionId: normalizedSessionId
|
|
4321
|
-
});
|
|
4322
|
-
}
|
|
4323
|
-
}
|
|
4324
|
-
return rewriteCanonicalSavedHistory("hermes-cli", normalizedSessionId, records);
|
|
4325
|
-
} catch {
|
|
4326
|
-
return false;
|
|
4327
|
-
}
|
|
4328
|
-
}
|
|
4329
|
-
function resolveClaudeProjectTranscriptPath(historySessionId, workspace) {
|
|
4330
|
-
const claudeProjectsDir = path7.join(os5.homedir(), ".claude", "projects");
|
|
4331
|
-
if (!fs3.existsSync(claudeProjectsDir)) return null;
|
|
4332
|
-
const normalizedWorkspace = typeof workspace === "string" ? workspace.trim() : "";
|
|
4333
|
-
if (normalizedWorkspace) {
|
|
4334
|
-
const directPath = path7.join(claudeProjectsDir, normalizedWorkspace.replace(/[\\/]/g, "-"), `${historySessionId}.jsonl`);
|
|
4335
|
-
if (fs3.existsSync(directPath)) return directPath;
|
|
4336
|
-
}
|
|
4337
|
-
const stack = [claudeProjectsDir];
|
|
4338
|
-
while (stack.length > 0) {
|
|
4339
|
-
const current = stack.pop();
|
|
4340
|
-
if (!current) continue;
|
|
4341
|
-
for (const entry of fs3.readdirSync(current, { withFileTypes: true })) {
|
|
4342
|
-
const entryPath = path7.join(current, entry.name);
|
|
4343
|
-
if (entry.isDirectory()) {
|
|
4344
|
-
stack.push(entryPath);
|
|
4345
|
-
continue;
|
|
4346
|
-
}
|
|
4347
|
-
if (entry.isFile() && entry.name === `${historySessionId}.jsonl`) {
|
|
4348
|
-
return entryPath;
|
|
4349
|
-
}
|
|
4350
|
-
}
|
|
4351
|
-
}
|
|
4352
|
-
return null;
|
|
4193
|
+
function getNativeHistoryScriptName(canonicalHistory, key) {
|
|
4194
|
+
const configured = canonicalHistory?.scripts?.[key];
|
|
4195
|
+
if (typeof configured === "string" && configured.trim()) return configured.trim();
|
|
4196
|
+
return key === "readSession" ? "readNativeHistory" : "listNativeHistory";
|
|
4353
4197
|
}
|
|
4354
|
-
function
|
|
4355
|
-
if (
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
}
|
|
4359
|
-
if (!Array.isArray(content)) return [];
|
|
4360
|
-
const parts = [];
|
|
4361
|
-
for (const block of content) {
|
|
4362
|
-
if (!block || typeof block !== "object") continue;
|
|
4363
|
-
const record2 = block;
|
|
4364
|
-
const type = String(record2.type || "").trim();
|
|
4365
|
-
if (type === "text") {
|
|
4366
|
-
const text = String(record2.text || "").trim();
|
|
4367
|
-
if (text) parts.push({ content: text, kind: "standard", role: "assistant" });
|
|
4368
|
-
continue;
|
|
4369
|
-
}
|
|
4370
|
-
if (type === "tool_use") {
|
|
4371
|
-
const name = String(record2.name || "").trim() || "Tool";
|
|
4372
|
-
const input = record2.input && typeof record2.input === "object" ? record2.input : null;
|
|
4373
|
-
const command = input ? String(input.command || "").trim() : "";
|
|
4374
|
-
const summary = command ? `${name}: ${command}` : name;
|
|
4375
|
-
if (summary) parts.push({ content: summary, kind: "tool", senderName: "Tool", role: "assistant" });
|
|
4376
|
-
}
|
|
4377
|
-
}
|
|
4378
|
-
return parts;
|
|
4198
|
+
function getProviderNativeHistoryScript(scripts, canonicalHistory, key) {
|
|
4199
|
+
if (!canonicalHistory?.scripts) return null;
|
|
4200
|
+
const fn = scripts?.[getNativeHistoryScriptName(canonicalHistory, key)];
|
|
4201
|
+
return typeof fn === "function" ? fn : null;
|
|
4379
4202
|
}
|
|
4380
|
-
function
|
|
4381
|
-
if (
|
|
4382
|
-
const trimmed = content.trim();
|
|
4383
|
-
return trimmed ? [{ role: "user", content: trimmed, kind: "standard" }] : [];
|
|
4384
|
-
}
|
|
4385
|
-
if (!Array.isArray(content)) return [];
|
|
4386
|
-
const parts = [];
|
|
4387
|
-
for (const block of content) {
|
|
4388
|
-
if (!block || typeof block !== "object") continue;
|
|
4389
|
-
const record2 = block;
|
|
4390
|
-
const type = String(record2.type || "").trim();
|
|
4391
|
-
if (type === "text") {
|
|
4392
|
-
const text = String(record2.text || "").trim();
|
|
4393
|
-
if (text) parts.push({ role: "user", content: text, kind: "standard" });
|
|
4394
|
-
continue;
|
|
4395
|
-
}
|
|
4396
|
-
if (type === "tool_result") {
|
|
4397
|
-
const rawContent = record2.content;
|
|
4398
|
-
const text = typeof rawContent === "string" ? rawContent.trim() : Array.isArray(rawContent) ? rawContent.map((entry) => {
|
|
4399
|
-
if (typeof entry === "string") return entry.trim();
|
|
4400
|
-
if (!entry || typeof entry !== "object") return "";
|
|
4401
|
-
const nested = entry;
|
|
4402
|
-
if (typeof nested.text === "string") return nested.text.trim();
|
|
4403
|
-
if (typeof nested.content === "string") return nested.content.trim();
|
|
4404
|
-
return "";
|
|
4405
|
-
}).filter(Boolean).join("\n") : "";
|
|
4406
|
-
if (text) parts.push({ role: "assistant", content: text, kind: "tool", senderName: "Tool" });
|
|
4407
|
-
}
|
|
4408
|
-
}
|
|
4409
|
-
return parts;
|
|
4410
|
-
}
|
|
4411
|
-
function buildClaudeNativeHistoryRecords(historySessionId, workspace) {
|
|
4203
|
+
function normalizeProviderNativeHistoryRecords(agentType, historySessionId, records) {
|
|
4204
|
+
if (!Array.isArray(records)) return [];
|
|
4412
4205
|
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
if (type === "user" && message) {
|
|
4448
|
-
for (const part of extractClaudeUserContentParts(message.content)) {
|
|
4449
|
-
records.push({
|
|
4450
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4451
|
-
receivedAt,
|
|
4452
|
-
role: part.role,
|
|
4453
|
-
content: part.content,
|
|
4454
|
-
kind: part.kind,
|
|
4455
|
-
senderName: part.senderName,
|
|
4456
|
-
agent: "claude-cli",
|
|
4457
|
-
historySessionId: normalizedSessionId
|
|
4458
|
-
});
|
|
4459
|
-
}
|
|
4460
|
-
continue;
|
|
4461
|
-
}
|
|
4462
|
-
if (type === "assistant" && message) {
|
|
4463
|
-
for (const part of extractClaudeAssistantContentParts(message.content)) {
|
|
4464
|
-
records.push({
|
|
4465
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4466
|
-
receivedAt,
|
|
4467
|
-
role: "assistant",
|
|
4468
|
-
content: part.content,
|
|
4469
|
-
kind: part.kind,
|
|
4470
|
-
senderName: part.senderName,
|
|
4471
|
-
agent: "claude-cli",
|
|
4472
|
-
historySessionId: normalizedSessionId
|
|
4473
|
-
});
|
|
4474
|
-
}
|
|
4475
|
-
}
|
|
4476
|
-
}
|
|
4477
|
-
return records;
|
|
4478
|
-
} catch {
|
|
4479
|
-
return null;
|
|
4480
|
-
}
|
|
4481
|
-
}
|
|
4482
|
-
function rebuildClaudeSavedHistoryFromNativeProject(historySessionId, workspace) {
|
|
4483
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
4484
|
-
if (!normalizedSessionId) return false;
|
|
4485
|
-
try {
|
|
4486
|
-
const transcriptPath = resolveClaudeProjectTranscriptPath(normalizedSessionId, workspace);
|
|
4487
|
-
if (!transcriptPath) return false;
|
|
4488
|
-
const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
|
|
4489
|
-
const records = [];
|
|
4490
|
-
const existingSessionStart = readExistingSessionStartRecord("claude-cli", normalizedSessionId);
|
|
4491
|
-
if (existingSessionStart) {
|
|
4492
|
-
records.push({
|
|
4493
|
-
...existingSessionStart,
|
|
4494
|
-
historySessionId: normalizedSessionId
|
|
4495
|
-
});
|
|
4496
|
-
}
|
|
4497
|
-
let fallbackTs = Date.now();
|
|
4498
|
-
for (const line of lines) {
|
|
4499
|
-
let parsed = null;
|
|
4500
|
-
try {
|
|
4501
|
-
parsed = JSON.parse(line);
|
|
4502
|
-
} catch {
|
|
4503
|
-
parsed = null;
|
|
4504
|
-
}
|
|
4505
|
-
if (!parsed) continue;
|
|
4506
|
-
const parsedSessionId = String(parsed.sessionId || "").trim();
|
|
4507
|
-
if (parsedSessionId && parsedSessionId !== normalizedSessionId) continue;
|
|
4508
|
-
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
4509
|
-
fallbackTs = receivedAt + 1;
|
|
4510
|
-
const parsedWorkspace = String(parsed.cwd || workspace || "").trim();
|
|
4511
|
-
if (records.length === 0 && parsedWorkspace) {
|
|
4512
|
-
records.push({
|
|
4513
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4514
|
-
receivedAt,
|
|
4515
|
-
role: "system",
|
|
4516
|
-
kind: "session_start",
|
|
4517
|
-
content: parsedWorkspace,
|
|
4518
|
-
agent: "claude-cli",
|
|
4519
|
-
historySessionId: normalizedSessionId,
|
|
4520
|
-
workspace: parsedWorkspace
|
|
4521
|
-
});
|
|
4522
|
-
}
|
|
4523
|
-
const type = String(parsed.type || "").trim();
|
|
4524
|
-
const message = parsed.message && typeof parsed.message === "object" ? parsed.message : null;
|
|
4525
|
-
if (type === "user" && message) {
|
|
4526
|
-
for (const part of extractClaudeUserContentParts(message.content)) {
|
|
4527
|
-
records.push({
|
|
4528
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4529
|
-
receivedAt,
|
|
4530
|
-
role: part.role,
|
|
4531
|
-
content: part.content,
|
|
4532
|
-
kind: part.kind,
|
|
4533
|
-
senderName: part.senderName,
|
|
4534
|
-
agent: "claude-cli",
|
|
4535
|
-
historySessionId: normalizedSessionId
|
|
4536
|
-
});
|
|
4537
|
-
}
|
|
4538
|
-
continue;
|
|
4539
|
-
}
|
|
4540
|
-
if (type === "assistant" && message) {
|
|
4541
|
-
for (const part of extractClaudeAssistantContentParts(message.content)) {
|
|
4542
|
-
records.push({
|
|
4543
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4544
|
-
receivedAt,
|
|
4545
|
-
role: "assistant",
|
|
4546
|
-
content: part.content,
|
|
4547
|
-
kind: part.kind,
|
|
4548
|
-
senderName: part.senderName,
|
|
4549
|
-
agent: "claude-cli",
|
|
4550
|
-
historySessionId: normalizedSessionId
|
|
4551
|
-
});
|
|
4552
|
-
}
|
|
4553
|
-
}
|
|
4554
|
-
}
|
|
4555
|
-
return rewriteCanonicalSavedHistory("claude-cli", normalizedSessionId, records);
|
|
4556
|
-
} catch {
|
|
4557
|
-
return false;
|
|
4558
|
-
}
|
|
4559
|
-
}
|
|
4560
|
-
function isUuidLikeSessionId(sessionId) {
|
|
4561
|
-
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);
|
|
4562
|
-
}
|
|
4563
|
-
function readCodexSessionMeta(filePath) {
|
|
4564
|
-
try {
|
|
4565
|
-
const firstLine = fs3.readFileSync(filePath, "utf-8").split("\n").find(Boolean);
|
|
4566
|
-
if (!firstLine) return null;
|
|
4567
|
-
const parsed = JSON.parse(firstLine);
|
|
4568
|
-
if (String(parsed.type || "") !== "session_meta") return null;
|
|
4569
|
-
const payload = parsed.payload && typeof parsed.payload === "object" ? parsed.payload : null;
|
|
4570
|
-
return payload;
|
|
4571
|
-
} catch {
|
|
4572
|
-
return null;
|
|
4573
|
-
}
|
|
4574
|
-
}
|
|
4575
|
-
function resolveCodexSessionTranscriptPath(historySessionId, workspace) {
|
|
4576
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
4577
|
-
if (!normalizedSessionId || !isUuidLikeSessionId(normalizedSessionId)) return null;
|
|
4578
|
-
const sessionsDir = path7.join(os5.homedir(), ".codex", "sessions");
|
|
4579
|
-
if (!fs3.existsSync(sessionsDir)) return null;
|
|
4580
|
-
const normalizedWorkspace = typeof workspace === "string" ? workspace.trim() : "";
|
|
4581
|
-
const candidates = [];
|
|
4582
|
-
const stack = [sessionsDir];
|
|
4583
|
-
while (stack.length > 0) {
|
|
4584
|
-
const current = stack.pop();
|
|
4585
|
-
if (!current) continue;
|
|
4586
|
-
let entries = [];
|
|
4587
|
-
try {
|
|
4588
|
-
entries = fs3.readdirSync(current, { withFileTypes: true });
|
|
4589
|
-
} catch {
|
|
4590
|
-
continue;
|
|
4591
|
-
}
|
|
4592
|
-
for (const entry of entries) {
|
|
4593
|
-
const entryPath = path7.join(current, entry.name);
|
|
4594
|
-
if (entry.isDirectory()) {
|
|
4595
|
-
stack.push(entryPath);
|
|
4596
|
-
continue;
|
|
4597
|
-
}
|
|
4598
|
-
if (!entry.isFile() || !entry.name.endsWith(".jsonl") || !entry.name.includes(normalizedSessionId)) continue;
|
|
4599
|
-
const meta3 = readCodexSessionMeta(entryPath);
|
|
4600
|
-
const metaSessionId = String(meta3?.id || "").trim();
|
|
4601
|
-
if (metaSessionId && metaSessionId !== normalizedSessionId) continue;
|
|
4602
|
-
const metaWorkspace = String(meta3?.cwd || "").trim();
|
|
4603
|
-
let mtimeMs = 0;
|
|
4604
|
-
try {
|
|
4605
|
-
mtimeMs = fs3.statSync(entryPath).mtimeMs;
|
|
4606
|
-
} catch {
|
|
4607
|
-
}
|
|
4608
|
-
candidates.push({
|
|
4609
|
-
path: entryPath,
|
|
4610
|
-
mtimeMs,
|
|
4611
|
-
workspaceMatches: !!normalizedWorkspace && metaWorkspace === normalizedWorkspace,
|
|
4612
|
-
metaMatches: metaSessionId === normalizedSessionId
|
|
4613
|
-
});
|
|
4614
|
-
}
|
|
4615
|
-
}
|
|
4616
|
-
candidates.sort((a, b) => Number(b.workspaceMatches) - Number(a.workspaceMatches) || Number(b.metaMatches) - Number(a.metaMatches) || b.mtimeMs - a.mtimeMs);
|
|
4617
|
-
return candidates[0]?.path || null;
|
|
4618
|
-
}
|
|
4619
|
-
function flattenCodexContent(content) {
|
|
4620
|
-
if (typeof content === "string") return content.trim();
|
|
4621
|
-
if (content == null) return "";
|
|
4622
|
-
if (Array.isArray(content)) {
|
|
4623
|
-
return content.map((entry) => flattenCodexContent(entry)).filter(Boolean).join("\n").trim();
|
|
4624
|
-
}
|
|
4625
|
-
if (typeof content === "object") {
|
|
4626
|
-
const record2 = content;
|
|
4627
|
-
if (typeof record2.text === "string") return record2.text.trim();
|
|
4628
|
-
if (typeof record2.content === "string" || Array.isArray(record2.content)) return flattenCodexContent(record2.content);
|
|
4629
|
-
if (typeof record2.output === "string") return record2.output.trim();
|
|
4630
|
-
if (typeof record2.message === "string") return record2.message.trim();
|
|
4631
|
-
}
|
|
4632
|
-
return "";
|
|
4633
|
-
}
|
|
4634
|
-
function summarizeCodexToolCall(payload) {
|
|
4635
|
-
const name = String(payload.name || payload.type || "tool").trim() || "tool";
|
|
4636
|
-
const rawArguments = payload.arguments ?? payload.input;
|
|
4637
|
-
let argumentValue = "";
|
|
4638
|
-
if (typeof rawArguments === "string") {
|
|
4639
|
-
const trimmed = rawArguments.trim();
|
|
4640
|
-
try {
|
|
4641
|
-
const parsed = JSON.parse(trimmed);
|
|
4642
|
-
argumentValue = summarizeCodexToolArguments(parsed);
|
|
4643
|
-
} catch {
|
|
4644
|
-
argumentValue = trimmed;
|
|
4645
|
-
}
|
|
4646
|
-
} else {
|
|
4647
|
-
argumentValue = summarizeCodexToolArguments(rawArguments);
|
|
4648
|
-
}
|
|
4649
|
-
return argumentValue ? `${name}: ${argumentValue}` : name;
|
|
4650
|
-
}
|
|
4651
|
-
function summarizeCodexToolArguments(value) {
|
|
4652
|
-
if (typeof value === "string") return value.trim();
|
|
4653
|
-
if (Array.isArray(value)) return value.map((entry) => String(entry)).join(" ").trim();
|
|
4654
|
-
if (!value || typeof value !== "object") return "";
|
|
4655
|
-
const record2 = value;
|
|
4656
|
-
const direct = record2.command || record2.cmd || record2.query || record2.path || record2.prompt;
|
|
4657
|
-
if (typeof direct === "string") return direct.trim();
|
|
4658
|
-
if (Array.isArray(direct)) return direct.map((entry) => String(entry)).join(" ").trim();
|
|
4659
|
-
try {
|
|
4660
|
-
return JSON.stringify(record2).trim();
|
|
4661
|
-
} catch {
|
|
4662
|
-
return "";
|
|
4663
|
-
}
|
|
4206
|
+
return records.map((record2) => sanitizeHistoryMessage(agentType, {
|
|
4207
|
+
ts: typeof record2?.ts === "string" ? record2.ts : new Date(Number(record2?.receivedAt) || Date.now()).toISOString(),
|
|
4208
|
+
receivedAt: Number(record2?.receivedAt) || Date.parse(record2?.ts || "") || Date.now(),
|
|
4209
|
+
role: record2?.role,
|
|
4210
|
+
content: String(record2?.content || ""),
|
|
4211
|
+
kind: record2?.kind || (record2?.role === "system" ? "session_start" : "standard"),
|
|
4212
|
+
senderName: record2?.senderName,
|
|
4213
|
+
agent: agentType,
|
|
4214
|
+
instanceId: record2?.instanceId,
|
|
4215
|
+
historySessionId: normalizeSavedHistorySessionId(record2?.historySessionId || normalizedSessionId),
|
|
4216
|
+
sessionTitle: record2?.sessionTitle,
|
|
4217
|
+
workspace: record2?.workspace
|
|
4218
|
+
})).filter(Boolean);
|
|
4219
|
+
}
|
|
4220
|
+
function callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, historySessionId, workspace) {
|
|
4221
|
+
const fn = getProviderNativeHistoryScript(scripts, canonicalHistory, "readSession");
|
|
4222
|
+
if (!fn) return null;
|
|
4223
|
+
const result = fn({
|
|
4224
|
+
agentType,
|
|
4225
|
+
sessionId: historySessionId,
|
|
4226
|
+
historySessionId,
|
|
4227
|
+
workspace,
|
|
4228
|
+
format: canonicalHistory?.format,
|
|
4229
|
+
watchPath: canonicalHistory?.watchPath,
|
|
4230
|
+
args: { sessionId: historySessionId, historySessionId, workspace }
|
|
4231
|
+
});
|
|
4232
|
+
if (!result || typeof result !== "object") return null;
|
|
4233
|
+
const records = normalizeProviderNativeHistoryRecords(agentType, historySessionId, result.messages || result.records);
|
|
4234
|
+
if (records.length === 0) return null;
|
|
4235
|
+
return {
|
|
4236
|
+
records,
|
|
4237
|
+
sourcePath: typeof result.sourcePath === "string" ? result.sourcePath : "",
|
|
4238
|
+
sourceMtimeMs: Number(result.sourceMtimeMs) || 0
|
|
4239
|
+
};
|
|
4664
4240
|
}
|
|
4665
|
-
function
|
|
4666
|
-
const
|
|
4667
|
-
|
|
4668
|
-
|
|
4669
|
-
if (output && typeof output === "object") {
|
|
4670
|
-
try {
|
|
4671
|
-
return JSON.stringify(output).trim();
|
|
4672
|
-
} catch {
|
|
4673
|
-
return "";
|
|
4674
|
-
}
|
|
4675
|
-
}
|
|
4676
|
-
return "";
|
|
4241
|
+
function buildNativeHistoryReadResult(agentType, canonicalHistory, scripts, historySessionId, workspace) {
|
|
4242
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || "");
|
|
4243
|
+
if (!canonicalHistory || !normalizedSessionId || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
|
|
4244
|
+
return callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace);
|
|
4677
4245
|
}
|
|
4678
|
-
function
|
|
4246
|
+
function materializeNativeHistoryToMirror(agentType, canonicalHistory, historySessionId, workspace, scripts) {
|
|
4679
4247
|
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
4680
|
-
if (!normalizedSessionId
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
|
|
4692
|
-
parsed = null;
|
|
4693
|
-
}
|
|
4694
|
-
if (!parsed) continue;
|
|
4695
|
-
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
4696
|
-
fallbackTs = receivedAt + 1;
|
|
4697
|
-
const type = String(parsed.type || "").trim();
|
|
4698
|
-
const payload = parsed.payload && typeof parsed.payload === "object" ? parsed.payload : null;
|
|
4699
|
-
if (!payload) continue;
|
|
4700
|
-
if (type === "session_meta") {
|
|
4701
|
-
const parsedSessionId = String(payload.id || "").trim();
|
|
4702
|
-
if (parsedSessionId && parsedSessionId !== normalizedSessionId) return null;
|
|
4703
|
-
const parsedWorkspace = String(payload.cwd || workspace || "").trim();
|
|
4704
|
-
if (records.length === 0 && parsedWorkspace) {
|
|
4705
|
-
records.push({
|
|
4706
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4707
|
-
receivedAt,
|
|
4708
|
-
role: "system",
|
|
4709
|
-
kind: "session_start",
|
|
4710
|
-
content: parsedWorkspace,
|
|
4711
|
-
agent: "codex-cli",
|
|
4712
|
-
historySessionId: normalizedSessionId,
|
|
4713
|
-
workspace: parsedWorkspace
|
|
4714
|
-
});
|
|
4715
|
-
}
|
|
4716
|
-
continue;
|
|
4717
|
-
}
|
|
4718
|
-
if (type !== "response_item") continue;
|
|
4719
|
-
const payloadType = String(payload.type || "").trim();
|
|
4720
|
-
if (payloadType === "message") {
|
|
4721
|
-
const role = String(payload.role || "").trim();
|
|
4722
|
-
if (role !== "user" && role !== "assistant") continue;
|
|
4723
|
-
const content = flattenCodexContent(payload.content);
|
|
4724
|
-
if (!content) continue;
|
|
4725
|
-
records.push({
|
|
4726
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4727
|
-
receivedAt,
|
|
4728
|
-
role,
|
|
4729
|
-
content,
|
|
4730
|
-
kind: "standard",
|
|
4731
|
-
agent: "codex-cli",
|
|
4732
|
-
historySessionId: normalizedSessionId
|
|
4733
|
-
});
|
|
4734
|
-
continue;
|
|
4735
|
-
}
|
|
4736
|
-
if (payloadType === "function_call" || payloadType === "custom_tool_call") {
|
|
4737
|
-
const content = summarizeCodexToolCall(payload);
|
|
4738
|
-
if (!content) continue;
|
|
4739
|
-
records.push({
|
|
4740
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4741
|
-
receivedAt,
|
|
4742
|
-
role: "assistant",
|
|
4743
|
-
content,
|
|
4744
|
-
kind: "tool",
|
|
4745
|
-
senderName: "Tool",
|
|
4746
|
-
agent: "codex-cli",
|
|
4747
|
-
historySessionId: normalizedSessionId
|
|
4748
|
-
});
|
|
4749
|
-
continue;
|
|
4750
|
-
}
|
|
4751
|
-
if (payloadType === "function_call_output" || payloadType === "custom_tool_call_output") {
|
|
4752
|
-
const content = codexToolOutputContent(payload);
|
|
4753
|
-
if (!content) continue;
|
|
4754
|
-
records.push({
|
|
4755
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4756
|
-
receivedAt,
|
|
4757
|
-
role: "assistant",
|
|
4758
|
-
content,
|
|
4759
|
-
kind: "tool",
|
|
4760
|
-
senderName: "Tool",
|
|
4761
|
-
agent: "codex-cli",
|
|
4762
|
-
historySessionId: normalizedSessionId
|
|
4763
|
-
});
|
|
4764
|
-
}
|
|
4765
|
-
}
|
|
4766
|
-
return records;
|
|
4767
|
-
} catch {
|
|
4768
|
-
return null;
|
|
4769
|
-
}
|
|
4248
|
+
if (!normalizedSessionId) return false;
|
|
4249
|
+
const nativeResult = callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace);
|
|
4250
|
+
const nativeRecords = nativeResult?.records || [];
|
|
4251
|
+
if (nativeRecords.length === 0) return false;
|
|
4252
|
+
const normalizedRecords = nativeRecords.map((record2) => ({
|
|
4253
|
+
...record2,
|
|
4254
|
+
agent: agentType,
|
|
4255
|
+
historySessionId: normalizedSessionId
|
|
4256
|
+
}));
|
|
4257
|
+
const existingSessionStart = readExistingSessionStartRecord(agentType, normalizedSessionId);
|
|
4258
|
+
const records = existingSessionStart && normalizedRecords[0]?.kind !== "session_start" ? [{ ...existingSessionStart, historySessionId: normalizedSessionId, agent: agentType }, ...normalizedRecords] : normalizedRecords;
|
|
4259
|
+
return rewriteCanonicalSavedHistory(agentType, normalizedSessionId, records);
|
|
4770
4260
|
}
|
|
4771
|
-
function
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
const records = buildCodexNativeHistoryRecords(normalizedSessionId, workspace);
|
|
4775
|
-
if (!records || records.length === 0) return false;
|
|
4776
|
-
const existingSessionStart = readExistingSessionStartRecord("codex-cli", normalizedSessionId);
|
|
4777
|
-
const recordsToWrite = existingSessionStart && records[0]?.kind !== "session_start" ? [{ ...existingSessionStart, historySessionId: normalizedSessionId }, ...records] : records;
|
|
4778
|
-
return rewriteCanonicalSavedHistory("codex-cli", normalizedSessionId, recordsToWrite);
|
|
4261
|
+
function materializeProviderNativeHistory(agentType, canonicalHistory, historySessionId, workspace, scripts) {
|
|
4262
|
+
if (!canonicalHistory || canonicalHistory.mode !== "materialized-mirror") return false;
|
|
4263
|
+
return materializeNativeHistoryToMirror(agentType, canonicalHistory, historySessionId, workspace, scripts);
|
|
4779
4264
|
}
|
|
4780
4265
|
function isNativeSourceCanonicalHistory(canonicalHistory) {
|
|
4781
4266
|
if (!canonicalHistory) return false;
|
|
@@ -4783,21 +4268,15 @@ function isNativeSourceCanonicalHistory(canonicalHistory) {
|
|
|
4783
4268
|
if (canonicalHistory.mode === "materialized-mirror") return false;
|
|
4784
4269
|
return true;
|
|
4785
4270
|
}
|
|
4786
|
-
function buildNativeHistoryRecords(canonicalHistory, historySessionId, workspace) {
|
|
4787
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || "");
|
|
4788
|
-
if (!canonicalHistory || !normalizedSessionId || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
|
|
4789
|
-
if (canonicalHistory.format === "hermes-json") return buildHermesNativeHistoryRecords(normalizedSessionId);
|
|
4790
|
-
if (canonicalHistory.format === "claude-jsonl") return buildClaudeNativeHistoryRecords(normalizedSessionId, workspace);
|
|
4791
|
-
if (canonicalHistory.format === "codex-jsonl") return buildCodexNativeHistoryRecords(normalizedSessionId, workspace);
|
|
4792
|
-
return null;
|
|
4793
|
-
}
|
|
4794
4271
|
function readProviderChatHistory(agentType, options = {}) {
|
|
4795
4272
|
if (isNativeSourceCanonicalHistory(options.canonicalHistory) && options.historySessionId) {
|
|
4796
|
-
const
|
|
4797
|
-
if (!
|
|
4273
|
+
const nativeResult = buildNativeHistoryReadResult(agentType, options.canonicalHistory, options.scripts, options.historySessionId, options.workspace);
|
|
4274
|
+
if (!nativeResult) return { messages: [], hasMore: false, source: "native-unavailable" };
|
|
4798
4275
|
return {
|
|
4799
|
-
...pageHistoryRecords(agentType, records, options.offset || 0, options.limit || 30, options.excludeRecentCount || 0, options.historyBehavior),
|
|
4800
|
-
source: "provider-native"
|
|
4276
|
+
...pageHistoryRecords(agentType, nativeResult.records, options.offset || 0, options.limit || 30, options.excludeRecentCount || 0, options.historyBehavior),
|
|
4277
|
+
source: "provider-native",
|
|
4278
|
+
sourcePath: nativeResult.sourcePath,
|
|
4279
|
+
sourceMtimeMs: nativeResult.sourceMtimeMs
|
|
4801
4280
|
};
|
|
4802
4281
|
}
|
|
4803
4282
|
return {
|
|
@@ -4830,68 +4309,64 @@ function buildNativeSessionSummary(agentType, historySessionId, records, sourceP
|
|
|
4830
4309
|
sourceMtimeMs
|
|
4831
4310
|
};
|
|
4832
4311
|
}
|
|
4833
|
-
function
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
const
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
}
|
|
4854
|
-
}
|
|
4855
|
-
return results;
|
|
4312
|
+
function normalizeProviderNativeHistorySessionSummary(agentType, item) {
|
|
4313
|
+
const historySessionId = normalizeSavedHistorySessionId(item?.historySessionId || item?.sessionId || "");
|
|
4314
|
+
if (!historySessionId) return null;
|
|
4315
|
+
const sourcePath = typeof item?.sourcePath === "string" ? item.sourcePath : "";
|
|
4316
|
+
const sourceMtimeMs = Number(item?.sourceMtimeMs) || 0;
|
|
4317
|
+
const firstMessageAt = Number(item?.firstMessageAt) || sourceMtimeMs || Date.now();
|
|
4318
|
+
const lastMessageAt = Number(item?.lastMessageAt) || firstMessageAt;
|
|
4319
|
+
const messageCount = Math.max(0, Number(item?.messageCount) || 0);
|
|
4320
|
+
return {
|
|
4321
|
+
historySessionId,
|
|
4322
|
+
sessionTitle: typeof item?.sessionTitle === "string" ? item.sessionTitle : void 0,
|
|
4323
|
+
messageCount,
|
|
4324
|
+
firstMessageAt,
|
|
4325
|
+
lastMessageAt,
|
|
4326
|
+
preview: typeof item?.preview === "string" ? item.preview : void 0,
|
|
4327
|
+
workspace: typeof item?.workspace === "string" ? item.workspace : void 0,
|
|
4328
|
+
source: "provider-native",
|
|
4329
|
+
sourcePath,
|
|
4330
|
+
sourceMtimeMs
|
|
4331
|
+
};
|
|
4856
4332
|
}
|
|
4857
|
-
function
|
|
4333
|
+
function collectProviderScriptNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) {
|
|
4334
|
+
const fn = getProviderNativeHistoryScript(scripts, canonicalHistory, "listSessions");
|
|
4335
|
+
if (!fn) return null;
|
|
4336
|
+
const result = fn({
|
|
4337
|
+
agentType,
|
|
4338
|
+
format: canonicalHistory.format,
|
|
4339
|
+
watchPath: canonicalHistory.watchPath,
|
|
4340
|
+
args: {}
|
|
4341
|
+
});
|
|
4342
|
+
if (!result || typeof result !== "object") return [];
|
|
4343
|
+
const sessions = Array.isArray(result.sessions) ? result.sessions : [];
|
|
4858
4344
|
const summaries = [];
|
|
4859
|
-
|
|
4860
|
-
|
|
4861
|
-
|
|
4862
|
-
const fileName = path7.basename(filePath);
|
|
4863
|
-
const historySessionId = fileName.replace(/^session_/, "").replace(/\.json$/, "");
|
|
4864
|
-
const records = buildHermesNativeHistoryRecords(historySessionId);
|
|
4865
|
-
const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
|
|
4866
|
-
if (summary) summaries.push(summary);
|
|
4867
|
-
}
|
|
4868
|
-
} else if (canonicalHistory.format === "claude-jsonl") {
|
|
4869
|
-
const root = path7.join(os5.homedir(), ".claude", "projects");
|
|
4870
|
-
for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && entry.name.endsWith(".jsonl"))) {
|
|
4871
|
-
const historySessionId = path7.basename(filePath, ".jsonl");
|
|
4872
|
-
const records = buildClaudeNativeHistoryRecords(historySessionId);
|
|
4873
|
-
const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
|
|
4874
|
-
if (summary) summaries.push(summary);
|
|
4875
|
-
}
|
|
4876
|
-
} else if (canonicalHistory.format === "codex-jsonl") {
|
|
4877
|
-
const root = path7.join(os5.homedir(), ".codex", "sessions");
|
|
4878
|
-
const uuidPattern = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i;
|
|
4879
|
-
for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && entry.name.endsWith(".jsonl"))) {
|
|
4880
|
-
const meta3 = readCodexSessionMeta(filePath);
|
|
4881
|
-
const historySessionId = String(meta3?.id || path7.basename(filePath).match(uuidPattern)?.[1] || "").trim();
|
|
4345
|
+
for (const item of sessions) {
|
|
4346
|
+
if (Array.isArray(item?.messages || item?.records)) {
|
|
4347
|
+
const historySessionId = normalizeSavedHistorySessionId(item?.historySessionId || item?.sessionId || "");
|
|
4882
4348
|
if (!historySessionId) continue;
|
|
4883
|
-
const records =
|
|
4884
|
-
const
|
|
4885
|
-
if (
|
|
4349
|
+
const records = normalizeProviderNativeHistoryRecords(agentType, historySessionId, item.messages || item.records);
|
|
4350
|
+
const summary2 = buildNativeSessionSummary(agentType, historySessionId, records, typeof item?.sourcePath === "string" ? item.sourcePath : "");
|
|
4351
|
+
if (summary2) {
|
|
4352
|
+
if (Number(item?.sourceMtimeMs)) summary2.sourceMtimeMs = Number(item.sourceMtimeMs);
|
|
4353
|
+
summaries.push(summary2);
|
|
4354
|
+
}
|
|
4355
|
+
continue;
|
|
4886
4356
|
}
|
|
4357
|
+
const summary = normalizeProviderNativeHistorySessionSummary(agentType, item);
|
|
4358
|
+
if (summary) summaries.push(summary);
|
|
4887
4359
|
}
|
|
4888
4360
|
return sortSavedHistorySessionSummaries(summaries);
|
|
4889
4361
|
}
|
|
4362
|
+
function collectNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) {
|
|
4363
|
+
return collectProviderScriptNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) || [];
|
|
4364
|
+
}
|
|
4890
4365
|
function listProviderHistorySessions(agentType, options = {}) {
|
|
4891
4366
|
if (isNativeSourceCanonicalHistory(options.canonicalHistory)) {
|
|
4892
4367
|
const offset = Math.max(0, options.offset || 0);
|
|
4893
4368
|
const limit = Math.max(1, options.limit || 30);
|
|
4894
|
-
const summaries = collectNativeHistorySessionSummaries(agentType, options.canonicalHistory);
|
|
4369
|
+
const summaries = collectNativeHistorySessionSummaries(agentType, options.canonicalHistory, options.scripts);
|
|
4895
4370
|
return {
|
|
4896
4371
|
sessions: summaries.slice(offset, offset + limit),
|
|
4897
4372
|
hasMore: offset + limit < summaries.length,
|
|
@@ -8183,7 +7658,8 @@ async function handleChatHistory(h, args) {
|
|
|
8183
7658
|
offset: offset || 0,
|
|
8184
7659
|
limit: limit || 30,
|
|
8185
7660
|
excludeRecentCount,
|
|
8186
|
-
historyBehavior: provider?.historyBehavior
|
|
7661
|
+
historyBehavior: provider?.historyBehavior,
|
|
7662
|
+
scripts: provider?.scripts
|
|
8187
7663
|
});
|
|
8188
7664
|
return { success: true, ...result, agent: agentStr };
|
|
8189
7665
|
} catch (e) {
|
|
@@ -14839,13 +14315,8 @@ var init_cli_provider_instance = __esm({
|
|
|
14839
14315
|
historyWriter;
|
|
14840
14316
|
runtimeMessages = [];
|
|
14841
14317
|
lastPersistedHistoryMessages = [];
|
|
14842
|
-
|
|
14843
|
-
|
|
14844
|
-
lastCanonicalHermesWatchPath = void 0;
|
|
14845
|
-
lastCanonicalClaudeRebuildMtimeMs = 0;
|
|
14846
|
-
lastCanonicalClaudeCheckAt = 0;
|
|
14847
|
-
lastCanonicalCodexRebuildMtimeMs = 0;
|
|
14848
|
-
lastCanonicalCodexCheckAt = 0;
|
|
14318
|
+
lastNativeSourceCanonicalCheckAt = 0;
|
|
14319
|
+
lastNativeSourceCanonicalCacheKey = void 0;
|
|
14849
14320
|
cachedSqliteDb = null;
|
|
14850
14321
|
cachedSqliteDbPath = null;
|
|
14851
14322
|
cachedSqliteDbMissingUntil = 0;
|
|
@@ -15546,76 +15017,44 @@ ${effect.notification.body || ""}`.trim();
|
|
|
15546
15017
|
const canonicalHistory = this.provider.canonicalHistory;
|
|
15547
15018
|
if (!canonicalHistory) return false;
|
|
15548
15019
|
if (isNativeSourceCanonicalHistory(canonicalHistory)) {
|
|
15020
|
+
const cacheKey = [this.type, this.providerSessionId, this.workingDir].join("\0");
|
|
15021
|
+
const now = Date.now();
|
|
15022
|
+
if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
|
|
15023
|
+
return true;
|
|
15024
|
+
}
|
|
15025
|
+
this.lastNativeSourceCanonicalCacheKey = cacheKey;
|
|
15026
|
+
this.lastNativeSourceCanonicalCheckAt = now;
|
|
15549
15027
|
const restoredHistory = readProviderChatHistory(this.type, {
|
|
15550
15028
|
canonicalHistory,
|
|
15551
15029
|
historySessionId: this.providerSessionId,
|
|
15552
15030
|
workspace: this.workingDir,
|
|
15553
15031
|
offset: 0,
|
|
15554
15032
|
limit: Number.MAX_SAFE_INTEGER,
|
|
15555
|
-
historyBehavior: this.provider.historyBehavior
|
|
15033
|
+
historyBehavior: this.provider.historyBehavior,
|
|
15034
|
+
scripts: this.provider.scripts
|
|
15556
15035
|
});
|
|
15557
|
-
if (restoredHistory.source
|
|
15558
|
-
|
|
15559
|
-
|
|
15560
|
-
|
|
15561
|
-
|
|
15562
|
-
|
|
15563
|
-
|
|
15564
|
-
|
|
15036
|
+
if (restoredHistory.source === "provider-native") {
|
|
15037
|
+
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
15038
|
+
role: message.role,
|
|
15039
|
+
content: message.content,
|
|
15040
|
+
kind: message.kind,
|
|
15041
|
+
senderName: message.senderName,
|
|
15042
|
+
receivedAt: message.receivedAt
|
|
15043
|
+
}));
|
|
15044
|
+
}
|
|
15565
15045
|
return true;
|
|
15566
15046
|
}
|
|
15567
15047
|
try {
|
|
15568
|
-
|
|
15569
|
-
|
|
15570
|
-
|
|
15571
|
-
|
|
15572
|
-
|
|
15573
|
-
|
|
15574
|
-
|
|
15575
|
-
|
|
15576
|
-
|
|
15577
|
-
if (!fs5.existsSync(watchPath)) return false;
|
|
15578
|
-
}
|
|
15579
|
-
const stat4 = fs5.statSync(watchPath);
|
|
15580
|
-
if (stat4.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
|
|
15581
|
-
rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
|
|
15582
|
-
if (rebuilt) this.lastCanonicalHermesSyncMtimeMs = stat4.mtimeMs;
|
|
15583
|
-
} else if (canonicalHistory.format === "claude-jsonl") {
|
|
15584
|
-
const now = Date.now();
|
|
15585
|
-
if (now - this.lastCanonicalClaudeCheckAt < 2e3 && this.lastCanonicalClaudeRebuildMtimeMs !== 0) {
|
|
15586
|
-
return true;
|
|
15587
|
-
}
|
|
15588
|
-
this.lastCanonicalClaudeCheckAt = now;
|
|
15589
|
-
const claudeProjectsDir = path11.join(os13.homedir(), ".claude", "projects");
|
|
15590
|
-
const workspaceSegment = typeof this.workingDir === "string" ? this.workingDir.replace(/[\\/]/g, "-").replace(/^-+/, "") : "";
|
|
15591
|
-
const transcriptFile = path11.join(claudeProjectsDir, workspaceSegment, `${this.providerSessionId}.jsonl`);
|
|
15592
|
-
let transcriptMtime = 0;
|
|
15593
|
-
try {
|
|
15594
|
-
transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
|
|
15595
|
-
} catch {
|
|
15596
|
-
}
|
|
15597
|
-
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalClaudeRebuildMtimeMs) return true;
|
|
15598
|
-
rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
|
|
15599
|
-
if (rebuilt) this.lastCanonicalClaudeRebuildMtimeMs = transcriptMtime || Date.now();
|
|
15600
|
-
} else if (canonicalHistory.format === "codex-jsonl") {
|
|
15601
|
-
const now = Date.now();
|
|
15602
|
-
if (now - this.lastCanonicalCodexCheckAt < 2e3 && this.lastCanonicalCodexRebuildMtimeMs !== 0) {
|
|
15603
|
-
return true;
|
|
15604
|
-
}
|
|
15605
|
-
this.lastCanonicalCodexCheckAt = now;
|
|
15606
|
-
const transcriptFile = resolveCodexSessionTranscriptPath(this.providerSessionId, this.workingDir);
|
|
15607
|
-
let transcriptMtime = 0;
|
|
15608
|
-
if (transcriptFile) {
|
|
15609
|
-
try {
|
|
15610
|
-
transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
|
|
15611
|
-
} catch {
|
|
15612
|
-
}
|
|
15613
|
-
}
|
|
15614
|
-
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalCodexRebuildMtimeMs) return true;
|
|
15615
|
-
rebuilt = rebuildCodexSavedHistoryFromNativeSession(this.providerSessionId, this.workingDir);
|
|
15616
|
-
if (rebuilt) this.lastCanonicalCodexRebuildMtimeMs = transcriptMtime || Date.now();
|
|
15048
|
+
const cacheKey = [this.type, this.providerSessionId, this.workingDir, canonicalHistory.mode || "materialized-mirror"].join("\0");
|
|
15049
|
+
const now = Date.now();
|
|
15050
|
+
if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
|
|
15051
|
+
return true;
|
|
15052
|
+
}
|
|
15053
|
+
this.lastNativeSourceCanonicalCacheKey = cacheKey;
|
|
15054
|
+
this.lastNativeSourceCanonicalCheckAt = now;
|
|
15055
|
+
if (!materializeProviderNativeHistory(this.type, canonicalHistory, this.providerSessionId, this.workingDir, this.provider.scripts)) {
|
|
15056
|
+
return false;
|
|
15617
15057
|
}
|
|
15618
|
-
if (!rebuilt) return false;
|
|
15619
15058
|
const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
15620
15059
|
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
15621
15060
|
role: message.role,
|
|
@@ -15638,7 +15077,8 @@ ${effect.notification.body || ""}`.trim();
|
|
|
15638
15077
|
workspace: this.workingDir,
|
|
15639
15078
|
offset: 0,
|
|
15640
15079
|
limit: Number.MAX_SAFE_INTEGER,
|
|
15641
|
-
historyBehavior: this.provider.historyBehavior
|
|
15080
|
+
historyBehavior: this.provider.historyBehavior,
|
|
15081
|
+
scripts: this.provider.scripts
|
|
15642
15082
|
}) : (() => {
|
|
15643
15083
|
this.historyWriter.compactHistorySession(this.type, this.providerSessionId, this.provider.historyBehavior);
|
|
15644
15084
|
return readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
@@ -34175,10 +33615,10 @@ var init_readdirp = __esm({
|
|
|
34175
33615
|
}
|
|
34176
33616
|
async _formatEntry(dirent, path28) {
|
|
34177
33617
|
let entry;
|
|
34178
|
-
const
|
|
33618
|
+
const basename9 = this._isDirent ? dirent.name : dirent;
|
|
34179
33619
|
try {
|
|
34180
|
-
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path28,
|
|
34181
|
-
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename:
|
|
33620
|
+
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path28, basename9));
|
|
33621
|
+
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename9 };
|
|
34182
33622
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
34183
33623
|
} catch (err) {
|
|
34184
33624
|
this._onError(err);
|
|
@@ -34709,9 +34149,9 @@ var init_handler2 = __esm({
|
|
|
34709
34149
|
_watchWithNodeFs(path28, listener) {
|
|
34710
34150
|
const opts = this.fsw.options;
|
|
34711
34151
|
const directory = sp.dirname(path28);
|
|
34712
|
-
const
|
|
34152
|
+
const basename9 = sp.basename(path28);
|
|
34713
34153
|
const parent = this.fsw._getWatchedDir(directory);
|
|
34714
|
-
parent.add(
|
|
34154
|
+
parent.add(basename9);
|
|
34715
34155
|
const absolutePath = sp.resolve(path28);
|
|
34716
34156
|
const options = {
|
|
34717
34157
|
persistent: opts.persistent
|
|
@@ -34721,7 +34161,7 @@ var init_handler2 = __esm({
|
|
|
34721
34161
|
let closer;
|
|
34722
34162
|
if (opts.usePolling) {
|
|
34723
34163
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
34724
|
-
options.interval = enableBin && isBinaryPath(
|
|
34164
|
+
options.interval = enableBin && isBinaryPath(basename9) ? opts.binaryInterval : opts.interval;
|
|
34725
34165
|
closer = setFsWatchFileListener(path28, absolutePath, options, {
|
|
34726
34166
|
listener,
|
|
34727
34167
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -34744,10 +34184,10 @@ var init_handler2 = __esm({
|
|
|
34744
34184
|
return;
|
|
34745
34185
|
}
|
|
34746
34186
|
const dirname10 = sp.dirname(file2);
|
|
34747
|
-
const
|
|
34187
|
+
const basename9 = sp.basename(file2);
|
|
34748
34188
|
const parent = this.fsw._getWatchedDir(dirname10);
|
|
34749
34189
|
let prevStats = stats;
|
|
34750
|
-
if (parent.has(
|
|
34190
|
+
if (parent.has(basename9))
|
|
34751
34191
|
return;
|
|
34752
34192
|
const listener = async (path28, newStats) => {
|
|
34753
34193
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
|
|
@@ -34772,9 +34212,9 @@ var init_handler2 = __esm({
|
|
|
34772
34212
|
prevStats = newStats2;
|
|
34773
34213
|
}
|
|
34774
34214
|
} catch (error48) {
|
|
34775
|
-
this.fsw._remove(dirname10,
|
|
34215
|
+
this.fsw._remove(dirname10, basename9);
|
|
34776
34216
|
}
|
|
34777
|
-
} else if (parent.has(
|
|
34217
|
+
} else if (parent.has(basename9)) {
|
|
34778
34218
|
const at = newStats.atimeMs;
|
|
34779
34219
|
const mt = newStats.mtimeMs;
|
|
34780
34220
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -35787,6 +35227,7 @@ function validateProviderDefinition(raw) {
|
|
|
35787
35227
|
warnings.push("Extension providers should have extensionId");
|
|
35788
35228
|
}
|
|
35789
35229
|
validateCapabilities(provider, controls, errors);
|
|
35230
|
+
validateCanonicalHistory(provider.canonicalHistory, errors);
|
|
35790
35231
|
for (const control of controls) {
|
|
35791
35232
|
validateControl(control, errors);
|
|
35792
35233
|
}
|
|
@@ -35844,6 +35285,39 @@ function validateCapabilities(provider, controls, errors) {
|
|
|
35844
35285
|
errors.push("providers declaring controls must set capabilities.controls.typedResults=true");
|
|
35845
35286
|
}
|
|
35846
35287
|
}
|
|
35288
|
+
function validateCanonicalHistory(raw, errors) {
|
|
35289
|
+
if (raw === void 0) return;
|
|
35290
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
35291
|
+
errors.push("canonicalHistory must be an object");
|
|
35292
|
+
return;
|
|
35293
|
+
}
|
|
35294
|
+
const canonicalHistory = raw;
|
|
35295
|
+
const format = canonicalHistory.format;
|
|
35296
|
+
if (format !== void 0 && (typeof format !== "string" || !format.trim())) {
|
|
35297
|
+
errors.push("canonicalHistory.format must be a non-empty string when provided");
|
|
35298
|
+
}
|
|
35299
|
+
const watchPath = canonicalHistory.watchPath;
|
|
35300
|
+
if (watchPath !== void 0 && (typeof watchPath !== "string" || !watchPath.trim())) {
|
|
35301
|
+
errors.push("canonicalHistory.watchPath must be a non-empty string when provided");
|
|
35302
|
+
}
|
|
35303
|
+
const mode = canonicalHistory.mode;
|
|
35304
|
+
if (mode !== void 0 && !["native-source", "materialized-mirror", "disabled"].includes(String(mode))) {
|
|
35305
|
+
errors.push("canonicalHistory.mode must be one of: native-source, materialized-mirror, disabled");
|
|
35306
|
+
}
|
|
35307
|
+
const scripts = canonicalHistory.scripts;
|
|
35308
|
+
if (scripts === void 0) return;
|
|
35309
|
+
if (!scripts || typeof scripts !== "object" || Array.isArray(scripts)) {
|
|
35310
|
+
errors.push("canonicalHistory.scripts must be an object");
|
|
35311
|
+
return;
|
|
35312
|
+
}
|
|
35313
|
+
const scriptConfig = scripts;
|
|
35314
|
+
for (const key of ["readSession", "listSessions"]) {
|
|
35315
|
+
const value = scriptConfig[key];
|
|
35316
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
35317
|
+
errors.push(`canonicalHistory.scripts.${key} must be a non-empty string`);
|
|
35318
|
+
}
|
|
35319
|
+
}
|
|
35320
|
+
}
|
|
35847
35321
|
function validateControl(control, errors) {
|
|
35848
35322
|
if (!control || typeof control !== "object") {
|
|
35849
35323
|
errors.push("controls: each control must be an object");
|
|
@@ -39129,7 +38603,8 @@ var init_router = __esm({
|
|
|
39129
38603
|
canonicalHistory: providerMeta?.canonicalHistory,
|
|
39130
38604
|
offset,
|
|
39131
38605
|
limit,
|
|
39132
|
-
historyBehavior: providerMeta?.historyBehavior
|
|
38606
|
+
historyBehavior: providerMeta?.historyBehavior,
|
|
38607
|
+
scripts: providerMeta?.scripts
|
|
39133
38608
|
});
|
|
39134
38609
|
const state = loadState();
|
|
39135
38610
|
const savedSessions = getSavedProviderSessions(state, { providerType, kind });
|
|
@@ -39155,7 +38630,10 @@ var init_router = __esm({
|
|
|
39155
38630
|
messageCount: session.messageCount,
|
|
39156
38631
|
firstMessageAt: session.firstMessageAt,
|
|
39157
38632
|
lastMessageAt: session.lastMessageAt,
|
|
39158
|
-
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById
|
|
38633
|
+
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById,
|
|
38634
|
+
historySource: session.source,
|
|
38635
|
+
sourcePath: session.sourcePath,
|
|
38636
|
+
sourceMtimeMs: session.sourceMtimeMs
|
|
39159
38637
|
};
|
|
39160
38638
|
}),
|
|
39161
38639
|
hasMore,
|
|
@@ -47844,6 +47322,7 @@ var init_server_connection = __esm({
|
|
|
47844
47322
|
iceServers = null;
|
|
47845
47323
|
planLimits = null;
|
|
47846
47324
|
compatBlocked = false;
|
|
47325
|
+
fatalAuthRejectedReason = null;
|
|
47847
47326
|
get authTimeoutMs() {
|
|
47848
47327
|
return Math.max(1, this.options.authTimeoutMs ?? 15e3);
|
|
47849
47328
|
}
|
|
@@ -47960,6 +47439,7 @@ var init_server_connection = __esm({
|
|
|
47960
47439
|
this.clearAuthTimeout();
|
|
47961
47440
|
this.reconnectAttempts = 0;
|
|
47962
47441
|
this.compatBlocked = false;
|
|
47442
|
+
this.fatalAuthRejectedReason = null;
|
|
47963
47443
|
const payload = message.payload;
|
|
47964
47444
|
this.userPlan = payload.plan || "free";
|
|
47965
47445
|
this.iceServers = payload.iceServers || null;
|
|
@@ -47973,8 +47453,20 @@ var init_server_connection = __esm({
|
|
|
47973
47453
|
this.startHeartbeat();
|
|
47974
47454
|
} else if (message.type === "auth_error") {
|
|
47975
47455
|
this.clearAuthTimeout();
|
|
47976
|
-
|
|
47456
|
+
const payload = message.payload;
|
|
47457
|
+
const reason = String(payload.reason || "Authentication failed");
|
|
47458
|
+
this.fatalAuthRejectedReason = reason;
|
|
47459
|
+
LOG.error("Server", `Auth failed: ${reason}`);
|
|
47460
|
+
if (reason === "machine_limit_exceeded") {
|
|
47461
|
+
LOG.error("Server", `[ServerConn] ${payload.message || "Machine limit exceeded. Remove an unused machine in the dashboard or upgrade your plan."}`);
|
|
47462
|
+
} else {
|
|
47463
|
+
LOG.error("Server", `[ServerConn] Saved machine credentials were rejected. Run 'adhdev setup --force' to re-authenticate, then restart the daemon.`);
|
|
47464
|
+
}
|
|
47977
47465
|
this.setState("error");
|
|
47466
|
+
try {
|
|
47467
|
+
this.ws?.close(1e3, "Authentication rejected");
|
|
47468
|
+
} catch {
|
|
47469
|
+
}
|
|
47978
47470
|
return;
|
|
47979
47471
|
} else if (message.type === "version_mismatch") {
|
|
47980
47472
|
const p = message.payload;
|
|
@@ -48007,6 +47499,18 @@ var init_server_connection = __esm({
|
|
|
48007
47499
|
LOG.info("Server", `[ServerConn] WebSocket closed: ${code} ${reason}`);
|
|
48008
47500
|
this.clearTimers();
|
|
48009
47501
|
this.ws = null;
|
|
47502
|
+
if (code === 4001 || this.fatalAuthRejectedReason) {
|
|
47503
|
+
const authReason = this.fatalAuthRejectedReason;
|
|
47504
|
+
const reasonText = authReason ? `: ${authReason}` : "";
|
|
47505
|
+
LOG.error("Server", `[ServerConn] Authentication rejected${reasonText}. Not reconnecting with the same credentials.`);
|
|
47506
|
+
if (authReason === "machine_limit_exceeded") {
|
|
47507
|
+
LOG.error("Server", `[ServerConn] Remove an unused machine in the dashboard or upgrade your plan, then restart the daemon.`);
|
|
47508
|
+
} else {
|
|
47509
|
+
LOG.error("Server", `[ServerConn] Run 'adhdev setup --force', then 'adhdev daemon:restart'.`);
|
|
47510
|
+
}
|
|
47511
|
+
this.setState("disconnected");
|
|
47512
|
+
return;
|
|
47513
|
+
}
|
|
48010
47514
|
if (code === 4011) {
|
|
48011
47515
|
LOG.info("Server", `[ServerConn] \u26A0 Evicted by another machine. Not reconnecting.`);
|
|
48012
47516
|
LOG.info("Server", `[ServerConn] This connection was released because another machine connected.`);
|
|
@@ -57410,7 +56914,7 @@ var init_adhdev_daemon = __esm({
|
|
|
57410
56914
|
init_version();
|
|
57411
56915
|
init_src();
|
|
57412
56916
|
init_runtime_defaults();
|
|
57413
|
-
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.
|
|
56917
|
+
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.46" });
|
|
57414
56918
|
AdhdevDaemon = class _AdhdevDaemon {
|
|
57415
56919
|
localHttpServer = null;
|
|
57416
56920
|
localWss = null;
|