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/cli/index.js
CHANGED
|
@@ -4665,29 +4665,6 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
4665
4665
|
return { sessions: [], hasMore: false };
|
|
4666
4666
|
}
|
|
4667
4667
|
}
|
|
4668
|
-
function normalizeCanonicalHermesMessageContent(content) {
|
|
4669
|
-
if (typeof content === "string") return content.trim();
|
|
4670
|
-
if (content == null) return "";
|
|
4671
|
-
try {
|
|
4672
|
-
return JSON.stringify(content).trim();
|
|
4673
|
-
} catch {
|
|
4674
|
-
return String(content).trim();
|
|
4675
|
-
}
|
|
4676
|
-
}
|
|
4677
|
-
function extractCanonicalHermesMessageTimestamp(message, fallbackTs) {
|
|
4678
|
-
const numericTimestamp = Number(message.receivedAt || message.timestamp || message.ts || 0);
|
|
4679
|
-
if (Number.isFinite(numericTimestamp) && numericTimestamp > 0) return numericTimestamp;
|
|
4680
|
-
const stringTimestamp = typeof message.ts === "string" ? Date.parse(message.ts) : typeof message.timestamp === "string" ? Date.parse(message.timestamp) : NaN;
|
|
4681
|
-
if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
|
|
4682
|
-
return fallbackTs;
|
|
4683
|
-
}
|
|
4684
|
-
function extractTimestampValue(value) {
|
|
4685
|
-
const numericTimestamp = Number(value || 0);
|
|
4686
|
-
if (Number.isFinite(numericTimestamp) && numericTimestamp > 0) return numericTimestamp;
|
|
4687
|
-
const stringTimestamp = typeof value === "string" ? Date.parse(value) : NaN;
|
|
4688
|
-
if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
|
|
4689
|
-
return 0;
|
|
4690
|
-
}
|
|
4691
4668
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
4692
4669
|
try {
|
|
4693
4670
|
const dir = path7.join(HISTORY_DIR, agentType);
|
|
@@ -4733,569 +4710,77 @@ function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
|
4733
4710
|
return false;
|
|
4734
4711
|
}
|
|
4735
4712
|
}
|
|
4736
|
-
function
|
|
4737
|
-
const
|
|
4738
|
-
if (
|
|
4739
|
-
|
|
4740
|
-
const sessionFilePath = path7.join(os6.homedir(), ".hermes", "sessions", `session_${normalizedSessionId}.json`);
|
|
4741
|
-
if (!fs3.existsSync(sessionFilePath)) return null;
|
|
4742
|
-
const raw = JSON.parse(fs3.readFileSync(sessionFilePath, "utf-8"));
|
|
4743
|
-
const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
|
|
4744
|
-
const records = [];
|
|
4745
|
-
let fallbackTs = Date.parse(raw.session_start || raw.last_updated || "") || Date.now();
|
|
4746
|
-
for (const message of canonicalMessages) {
|
|
4747
|
-
const role = String(message.role || "").trim();
|
|
4748
|
-
const content = normalizeCanonicalHermesMessageContent(message.content);
|
|
4749
|
-
if (!content) continue;
|
|
4750
|
-
const receivedAt = extractCanonicalHermesMessageTimestamp(message, fallbackTs);
|
|
4751
|
-
fallbackTs = receivedAt + 1;
|
|
4752
|
-
if (role === "user" || role === "assistant") {
|
|
4753
|
-
records.push({
|
|
4754
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4755
|
-
receivedAt,
|
|
4756
|
-
role,
|
|
4757
|
-
content,
|
|
4758
|
-
kind: "standard",
|
|
4759
|
-
agent: "hermes-cli",
|
|
4760
|
-
historySessionId: normalizedSessionId
|
|
4761
|
-
});
|
|
4762
|
-
continue;
|
|
4763
|
-
}
|
|
4764
|
-
if (role === "tool") {
|
|
4765
|
-
records.push({
|
|
4766
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4767
|
-
receivedAt,
|
|
4768
|
-
role: "assistant",
|
|
4769
|
-
content,
|
|
4770
|
-
kind: "tool",
|
|
4771
|
-
senderName: "Tool",
|
|
4772
|
-
agent: "hermes-cli",
|
|
4773
|
-
historySessionId: normalizedSessionId
|
|
4774
|
-
});
|
|
4775
|
-
}
|
|
4776
|
-
}
|
|
4777
|
-
return records;
|
|
4778
|
-
} catch {
|
|
4779
|
-
return null;
|
|
4780
|
-
}
|
|
4781
|
-
}
|
|
4782
|
-
function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
|
|
4783
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
4784
|
-
if (!normalizedSessionId) return false;
|
|
4785
|
-
try {
|
|
4786
|
-
const sessionFilePath = path7.join(os6.homedir(), ".hermes", "sessions", `session_${normalizedSessionId}.json`);
|
|
4787
|
-
if (!fs3.existsSync(sessionFilePath)) return false;
|
|
4788
|
-
const raw = JSON.parse(fs3.readFileSync(sessionFilePath, "utf-8"));
|
|
4789
|
-
const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
|
|
4790
|
-
const dir = path7.join(HISTORY_DIR, "hermes-cli");
|
|
4791
|
-
fs3.mkdirSync(dir, { recursive: true });
|
|
4792
|
-
const existingSessionStart = readExistingSessionStartRecord("hermes-cli", normalizedSessionId);
|
|
4793
|
-
const records = [];
|
|
4794
|
-
if (existingSessionStart) {
|
|
4795
|
-
records.push({
|
|
4796
|
-
...existingSessionStart,
|
|
4797
|
-
historySessionId: normalizedSessionId
|
|
4798
|
-
});
|
|
4799
|
-
}
|
|
4800
|
-
let fallbackTs = Date.parse(raw.session_start || raw.last_updated || "") || Date.now();
|
|
4801
|
-
for (const message of canonicalMessages) {
|
|
4802
|
-
const role = String(message.role || "").trim();
|
|
4803
|
-
const content = normalizeCanonicalHermesMessageContent(message.content);
|
|
4804
|
-
if (!content) continue;
|
|
4805
|
-
const receivedAt = extractCanonicalHermesMessageTimestamp(message, fallbackTs);
|
|
4806
|
-
fallbackTs = receivedAt + 1;
|
|
4807
|
-
if (role === "user") {
|
|
4808
|
-
records.push({
|
|
4809
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4810
|
-
receivedAt,
|
|
4811
|
-
role: "user",
|
|
4812
|
-
content,
|
|
4813
|
-
kind: "standard",
|
|
4814
|
-
agent: "hermes-cli",
|
|
4815
|
-
historySessionId: normalizedSessionId
|
|
4816
|
-
});
|
|
4817
|
-
continue;
|
|
4818
|
-
}
|
|
4819
|
-
if (role === "assistant") {
|
|
4820
|
-
records.push({
|
|
4821
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4822
|
-
receivedAt,
|
|
4823
|
-
role: "assistant",
|
|
4824
|
-
content,
|
|
4825
|
-
kind: "standard",
|
|
4826
|
-
agent: "hermes-cli",
|
|
4827
|
-
historySessionId: normalizedSessionId
|
|
4828
|
-
});
|
|
4829
|
-
continue;
|
|
4830
|
-
}
|
|
4831
|
-
if (role === "tool") {
|
|
4832
|
-
records.push({
|
|
4833
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4834
|
-
receivedAt,
|
|
4835
|
-
role: "assistant",
|
|
4836
|
-
content,
|
|
4837
|
-
kind: "tool",
|
|
4838
|
-
senderName: "Tool",
|
|
4839
|
-
agent: "hermes-cli",
|
|
4840
|
-
historySessionId: normalizedSessionId
|
|
4841
|
-
});
|
|
4842
|
-
}
|
|
4843
|
-
}
|
|
4844
|
-
return rewriteCanonicalSavedHistory("hermes-cli", normalizedSessionId, records);
|
|
4845
|
-
} catch {
|
|
4846
|
-
return false;
|
|
4847
|
-
}
|
|
4848
|
-
}
|
|
4849
|
-
function resolveClaudeProjectTranscriptPath(historySessionId, workspace) {
|
|
4850
|
-
const claudeProjectsDir = path7.join(os6.homedir(), ".claude", "projects");
|
|
4851
|
-
if (!fs3.existsSync(claudeProjectsDir)) return null;
|
|
4852
|
-
const normalizedWorkspace = typeof workspace === "string" ? workspace.trim() : "";
|
|
4853
|
-
if (normalizedWorkspace) {
|
|
4854
|
-
const directPath = path7.join(claudeProjectsDir, normalizedWorkspace.replace(/[\\/]/g, "-"), `${historySessionId}.jsonl`);
|
|
4855
|
-
if (fs3.existsSync(directPath)) return directPath;
|
|
4856
|
-
}
|
|
4857
|
-
const stack = [claudeProjectsDir];
|
|
4858
|
-
while (stack.length > 0) {
|
|
4859
|
-
const current = stack.pop();
|
|
4860
|
-
if (!current) continue;
|
|
4861
|
-
for (const entry of fs3.readdirSync(current, { withFileTypes: true })) {
|
|
4862
|
-
const entryPath = path7.join(current, entry.name);
|
|
4863
|
-
if (entry.isDirectory()) {
|
|
4864
|
-
stack.push(entryPath);
|
|
4865
|
-
continue;
|
|
4866
|
-
}
|
|
4867
|
-
if (entry.isFile() && entry.name === `${historySessionId}.jsonl`) {
|
|
4868
|
-
return entryPath;
|
|
4869
|
-
}
|
|
4870
|
-
}
|
|
4871
|
-
}
|
|
4872
|
-
return null;
|
|
4713
|
+
function getNativeHistoryScriptName(canonicalHistory, key) {
|
|
4714
|
+
const configured = canonicalHistory?.scripts?.[key];
|
|
4715
|
+
if (typeof configured === "string" && configured.trim()) return configured.trim();
|
|
4716
|
+
return key === "readSession" ? "readNativeHistory" : "listNativeHistory";
|
|
4873
4717
|
}
|
|
4874
|
-
function
|
|
4875
|
-
if (
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
}
|
|
4879
|
-
if (!Array.isArray(content)) return [];
|
|
4880
|
-
const parts = [];
|
|
4881
|
-
for (const block of content) {
|
|
4882
|
-
if (!block || typeof block !== "object") continue;
|
|
4883
|
-
const record2 = block;
|
|
4884
|
-
const type = String(record2.type || "").trim();
|
|
4885
|
-
if (type === "text") {
|
|
4886
|
-
const text = String(record2.text || "").trim();
|
|
4887
|
-
if (text) parts.push({ content: text, kind: "standard", role: "assistant" });
|
|
4888
|
-
continue;
|
|
4889
|
-
}
|
|
4890
|
-
if (type === "tool_use") {
|
|
4891
|
-
const name = String(record2.name || "").trim() || "Tool";
|
|
4892
|
-
const input = record2.input && typeof record2.input === "object" ? record2.input : null;
|
|
4893
|
-
const command = input ? String(input.command || "").trim() : "";
|
|
4894
|
-
const summary = command ? `${name}: ${command}` : name;
|
|
4895
|
-
if (summary) parts.push({ content: summary, kind: "tool", senderName: "Tool", role: "assistant" });
|
|
4896
|
-
}
|
|
4897
|
-
}
|
|
4898
|
-
return parts;
|
|
4718
|
+
function getProviderNativeHistoryScript(scripts, canonicalHistory, key) {
|
|
4719
|
+
if (!canonicalHistory?.scripts) return null;
|
|
4720
|
+
const fn = scripts?.[getNativeHistoryScriptName(canonicalHistory, key)];
|
|
4721
|
+
return typeof fn === "function" ? fn : null;
|
|
4899
4722
|
}
|
|
4900
|
-
function
|
|
4901
|
-
if (
|
|
4902
|
-
const trimmed = content.trim();
|
|
4903
|
-
return trimmed ? [{ role: "user", content: trimmed, kind: "standard" }] : [];
|
|
4904
|
-
}
|
|
4905
|
-
if (!Array.isArray(content)) return [];
|
|
4906
|
-
const parts = [];
|
|
4907
|
-
for (const block of content) {
|
|
4908
|
-
if (!block || typeof block !== "object") continue;
|
|
4909
|
-
const record2 = block;
|
|
4910
|
-
const type = String(record2.type || "").trim();
|
|
4911
|
-
if (type === "text") {
|
|
4912
|
-
const text = String(record2.text || "").trim();
|
|
4913
|
-
if (text) parts.push({ role: "user", content: text, kind: "standard" });
|
|
4914
|
-
continue;
|
|
4915
|
-
}
|
|
4916
|
-
if (type === "tool_result") {
|
|
4917
|
-
const rawContent = record2.content;
|
|
4918
|
-
const text = typeof rawContent === "string" ? rawContent.trim() : Array.isArray(rawContent) ? rawContent.map((entry) => {
|
|
4919
|
-
if (typeof entry === "string") return entry.trim();
|
|
4920
|
-
if (!entry || typeof entry !== "object") return "";
|
|
4921
|
-
const nested = entry;
|
|
4922
|
-
if (typeof nested.text === "string") return nested.text.trim();
|
|
4923
|
-
if (typeof nested.content === "string") return nested.content.trim();
|
|
4924
|
-
return "";
|
|
4925
|
-
}).filter(Boolean).join("\n") : "";
|
|
4926
|
-
if (text) parts.push({ role: "assistant", content: text, kind: "tool", senderName: "Tool" });
|
|
4927
|
-
}
|
|
4928
|
-
}
|
|
4929
|
-
return parts;
|
|
4930
|
-
}
|
|
4931
|
-
function buildClaudeNativeHistoryRecords(historySessionId, workspace) {
|
|
4723
|
+
function normalizeProviderNativeHistoryRecords(agentType, historySessionId, records) {
|
|
4724
|
+
if (!Array.isArray(records)) return [];
|
|
4932
4725
|
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
if (type === "user" && message) {
|
|
4968
|
-
for (const part of extractClaudeUserContentParts(message.content)) {
|
|
4969
|
-
records.push({
|
|
4970
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4971
|
-
receivedAt,
|
|
4972
|
-
role: part.role,
|
|
4973
|
-
content: part.content,
|
|
4974
|
-
kind: part.kind,
|
|
4975
|
-
senderName: part.senderName,
|
|
4976
|
-
agent: "claude-cli",
|
|
4977
|
-
historySessionId: normalizedSessionId
|
|
4978
|
-
});
|
|
4979
|
-
}
|
|
4980
|
-
continue;
|
|
4981
|
-
}
|
|
4982
|
-
if (type === "assistant" && message) {
|
|
4983
|
-
for (const part of extractClaudeAssistantContentParts(message.content)) {
|
|
4984
|
-
records.push({
|
|
4985
|
-
ts: new Date(receivedAt).toISOString(),
|
|
4986
|
-
receivedAt,
|
|
4987
|
-
role: "assistant",
|
|
4988
|
-
content: part.content,
|
|
4989
|
-
kind: part.kind,
|
|
4990
|
-
senderName: part.senderName,
|
|
4991
|
-
agent: "claude-cli",
|
|
4992
|
-
historySessionId: normalizedSessionId
|
|
4993
|
-
});
|
|
4994
|
-
}
|
|
4995
|
-
}
|
|
4996
|
-
}
|
|
4997
|
-
return records;
|
|
4998
|
-
} catch {
|
|
4999
|
-
return null;
|
|
5000
|
-
}
|
|
5001
|
-
}
|
|
5002
|
-
function rebuildClaudeSavedHistoryFromNativeProject(historySessionId, workspace) {
|
|
5003
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
5004
|
-
if (!normalizedSessionId) return false;
|
|
5005
|
-
try {
|
|
5006
|
-
const transcriptPath = resolveClaudeProjectTranscriptPath(normalizedSessionId, workspace);
|
|
5007
|
-
if (!transcriptPath) return false;
|
|
5008
|
-
const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
|
|
5009
|
-
const records = [];
|
|
5010
|
-
const existingSessionStart = readExistingSessionStartRecord("claude-cli", normalizedSessionId);
|
|
5011
|
-
if (existingSessionStart) {
|
|
5012
|
-
records.push({
|
|
5013
|
-
...existingSessionStart,
|
|
5014
|
-
historySessionId: normalizedSessionId
|
|
5015
|
-
});
|
|
5016
|
-
}
|
|
5017
|
-
let fallbackTs = Date.now();
|
|
5018
|
-
for (const line of lines) {
|
|
5019
|
-
let parsed = null;
|
|
5020
|
-
try {
|
|
5021
|
-
parsed = JSON.parse(line);
|
|
5022
|
-
} catch {
|
|
5023
|
-
parsed = null;
|
|
5024
|
-
}
|
|
5025
|
-
if (!parsed) continue;
|
|
5026
|
-
const parsedSessionId = String(parsed.sessionId || "").trim();
|
|
5027
|
-
if (parsedSessionId && parsedSessionId !== normalizedSessionId) continue;
|
|
5028
|
-
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
5029
|
-
fallbackTs = receivedAt + 1;
|
|
5030
|
-
const parsedWorkspace = String(parsed.cwd || workspace || "").trim();
|
|
5031
|
-
if (records.length === 0 && parsedWorkspace) {
|
|
5032
|
-
records.push({
|
|
5033
|
-
ts: new Date(receivedAt).toISOString(),
|
|
5034
|
-
receivedAt,
|
|
5035
|
-
role: "system",
|
|
5036
|
-
kind: "session_start",
|
|
5037
|
-
content: parsedWorkspace,
|
|
5038
|
-
agent: "claude-cli",
|
|
5039
|
-
historySessionId: normalizedSessionId,
|
|
5040
|
-
workspace: parsedWorkspace
|
|
5041
|
-
});
|
|
5042
|
-
}
|
|
5043
|
-
const type = String(parsed.type || "").trim();
|
|
5044
|
-
const message = parsed.message && typeof parsed.message === "object" ? parsed.message : null;
|
|
5045
|
-
if (type === "user" && message) {
|
|
5046
|
-
for (const part of extractClaudeUserContentParts(message.content)) {
|
|
5047
|
-
records.push({
|
|
5048
|
-
ts: new Date(receivedAt).toISOString(),
|
|
5049
|
-
receivedAt,
|
|
5050
|
-
role: part.role,
|
|
5051
|
-
content: part.content,
|
|
5052
|
-
kind: part.kind,
|
|
5053
|
-
senderName: part.senderName,
|
|
5054
|
-
agent: "claude-cli",
|
|
5055
|
-
historySessionId: normalizedSessionId
|
|
5056
|
-
});
|
|
5057
|
-
}
|
|
5058
|
-
continue;
|
|
5059
|
-
}
|
|
5060
|
-
if (type === "assistant" && message) {
|
|
5061
|
-
for (const part of extractClaudeAssistantContentParts(message.content)) {
|
|
5062
|
-
records.push({
|
|
5063
|
-
ts: new Date(receivedAt).toISOString(),
|
|
5064
|
-
receivedAt,
|
|
5065
|
-
role: "assistant",
|
|
5066
|
-
content: part.content,
|
|
5067
|
-
kind: part.kind,
|
|
5068
|
-
senderName: part.senderName,
|
|
5069
|
-
agent: "claude-cli",
|
|
5070
|
-
historySessionId: normalizedSessionId
|
|
5071
|
-
});
|
|
5072
|
-
}
|
|
5073
|
-
}
|
|
5074
|
-
}
|
|
5075
|
-
return rewriteCanonicalSavedHistory("claude-cli", normalizedSessionId, records);
|
|
5076
|
-
} catch {
|
|
5077
|
-
return false;
|
|
5078
|
-
}
|
|
5079
|
-
}
|
|
5080
|
-
function isUuidLikeSessionId(sessionId) {
|
|
5081
|
-
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);
|
|
5082
|
-
}
|
|
5083
|
-
function readCodexSessionMeta(filePath) {
|
|
5084
|
-
try {
|
|
5085
|
-
const firstLine = fs3.readFileSync(filePath, "utf-8").split("\n").find(Boolean);
|
|
5086
|
-
if (!firstLine) return null;
|
|
5087
|
-
const parsed = JSON.parse(firstLine);
|
|
5088
|
-
if (String(parsed.type || "") !== "session_meta") return null;
|
|
5089
|
-
const payload = parsed.payload && typeof parsed.payload === "object" ? parsed.payload : null;
|
|
5090
|
-
return payload;
|
|
5091
|
-
} catch {
|
|
5092
|
-
return null;
|
|
5093
|
-
}
|
|
5094
|
-
}
|
|
5095
|
-
function resolveCodexSessionTranscriptPath(historySessionId, workspace) {
|
|
5096
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
5097
|
-
if (!normalizedSessionId || !isUuidLikeSessionId(normalizedSessionId)) return null;
|
|
5098
|
-
const sessionsDir = path7.join(os6.homedir(), ".codex", "sessions");
|
|
5099
|
-
if (!fs3.existsSync(sessionsDir)) return null;
|
|
5100
|
-
const normalizedWorkspace = typeof workspace === "string" ? workspace.trim() : "";
|
|
5101
|
-
const candidates = [];
|
|
5102
|
-
const stack = [sessionsDir];
|
|
5103
|
-
while (stack.length > 0) {
|
|
5104
|
-
const current = stack.pop();
|
|
5105
|
-
if (!current) continue;
|
|
5106
|
-
let entries = [];
|
|
5107
|
-
try {
|
|
5108
|
-
entries = fs3.readdirSync(current, { withFileTypes: true });
|
|
5109
|
-
} catch {
|
|
5110
|
-
continue;
|
|
5111
|
-
}
|
|
5112
|
-
for (const entry of entries) {
|
|
5113
|
-
const entryPath = path7.join(current, entry.name);
|
|
5114
|
-
if (entry.isDirectory()) {
|
|
5115
|
-
stack.push(entryPath);
|
|
5116
|
-
continue;
|
|
5117
|
-
}
|
|
5118
|
-
if (!entry.isFile() || !entry.name.endsWith(".jsonl") || !entry.name.includes(normalizedSessionId)) continue;
|
|
5119
|
-
const meta3 = readCodexSessionMeta(entryPath);
|
|
5120
|
-
const metaSessionId = String(meta3?.id || "").trim();
|
|
5121
|
-
if (metaSessionId && metaSessionId !== normalizedSessionId) continue;
|
|
5122
|
-
const metaWorkspace = String(meta3?.cwd || "").trim();
|
|
5123
|
-
let mtimeMs = 0;
|
|
5124
|
-
try {
|
|
5125
|
-
mtimeMs = fs3.statSync(entryPath).mtimeMs;
|
|
5126
|
-
} catch {
|
|
5127
|
-
}
|
|
5128
|
-
candidates.push({
|
|
5129
|
-
path: entryPath,
|
|
5130
|
-
mtimeMs,
|
|
5131
|
-
workspaceMatches: !!normalizedWorkspace && metaWorkspace === normalizedWorkspace,
|
|
5132
|
-
metaMatches: metaSessionId === normalizedSessionId
|
|
5133
|
-
});
|
|
5134
|
-
}
|
|
5135
|
-
}
|
|
5136
|
-
candidates.sort((a, b) => Number(b.workspaceMatches) - Number(a.workspaceMatches) || Number(b.metaMatches) - Number(a.metaMatches) || b.mtimeMs - a.mtimeMs);
|
|
5137
|
-
return candidates[0]?.path || null;
|
|
5138
|
-
}
|
|
5139
|
-
function flattenCodexContent(content) {
|
|
5140
|
-
if (typeof content === "string") return content.trim();
|
|
5141
|
-
if (content == null) return "";
|
|
5142
|
-
if (Array.isArray(content)) {
|
|
5143
|
-
return content.map((entry) => flattenCodexContent(entry)).filter(Boolean).join("\n").trim();
|
|
5144
|
-
}
|
|
5145
|
-
if (typeof content === "object") {
|
|
5146
|
-
const record2 = content;
|
|
5147
|
-
if (typeof record2.text === "string") return record2.text.trim();
|
|
5148
|
-
if (typeof record2.content === "string" || Array.isArray(record2.content)) return flattenCodexContent(record2.content);
|
|
5149
|
-
if (typeof record2.output === "string") return record2.output.trim();
|
|
5150
|
-
if (typeof record2.message === "string") return record2.message.trim();
|
|
5151
|
-
}
|
|
5152
|
-
return "";
|
|
5153
|
-
}
|
|
5154
|
-
function summarizeCodexToolCall(payload) {
|
|
5155
|
-
const name = String(payload.name || payload.type || "tool").trim() || "tool";
|
|
5156
|
-
const rawArguments = payload.arguments ?? payload.input;
|
|
5157
|
-
let argumentValue = "";
|
|
5158
|
-
if (typeof rawArguments === "string") {
|
|
5159
|
-
const trimmed = rawArguments.trim();
|
|
5160
|
-
try {
|
|
5161
|
-
const parsed = JSON.parse(trimmed);
|
|
5162
|
-
argumentValue = summarizeCodexToolArguments(parsed);
|
|
5163
|
-
} catch {
|
|
5164
|
-
argumentValue = trimmed;
|
|
5165
|
-
}
|
|
5166
|
-
} else {
|
|
5167
|
-
argumentValue = summarizeCodexToolArguments(rawArguments);
|
|
5168
|
-
}
|
|
5169
|
-
return argumentValue ? `${name}: ${argumentValue}` : name;
|
|
5170
|
-
}
|
|
5171
|
-
function summarizeCodexToolArguments(value) {
|
|
5172
|
-
if (typeof value === "string") return value.trim();
|
|
5173
|
-
if (Array.isArray(value)) return value.map((entry) => String(entry)).join(" ").trim();
|
|
5174
|
-
if (!value || typeof value !== "object") return "";
|
|
5175
|
-
const record2 = value;
|
|
5176
|
-
const direct = record2.command || record2.cmd || record2.query || record2.path || record2.prompt;
|
|
5177
|
-
if (typeof direct === "string") return direct.trim();
|
|
5178
|
-
if (Array.isArray(direct)) return direct.map((entry) => String(entry)).join(" ").trim();
|
|
5179
|
-
try {
|
|
5180
|
-
return JSON.stringify(record2).trim();
|
|
5181
|
-
} catch {
|
|
5182
|
-
return "";
|
|
5183
|
-
}
|
|
4726
|
+
return records.map((record2) => sanitizeHistoryMessage(agentType, {
|
|
4727
|
+
ts: typeof record2?.ts === "string" ? record2.ts : new Date(Number(record2?.receivedAt) || Date.now()).toISOString(),
|
|
4728
|
+
receivedAt: Number(record2?.receivedAt) || Date.parse(record2?.ts || "") || Date.now(),
|
|
4729
|
+
role: record2?.role,
|
|
4730
|
+
content: String(record2?.content || ""),
|
|
4731
|
+
kind: record2?.kind || (record2?.role === "system" ? "session_start" : "standard"),
|
|
4732
|
+
senderName: record2?.senderName,
|
|
4733
|
+
agent: agentType,
|
|
4734
|
+
instanceId: record2?.instanceId,
|
|
4735
|
+
historySessionId: normalizeSavedHistorySessionId(record2?.historySessionId || normalizedSessionId),
|
|
4736
|
+
sessionTitle: record2?.sessionTitle,
|
|
4737
|
+
workspace: record2?.workspace
|
|
4738
|
+
})).filter(Boolean);
|
|
4739
|
+
}
|
|
4740
|
+
function callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, historySessionId, workspace) {
|
|
4741
|
+
const fn = getProviderNativeHistoryScript(scripts, canonicalHistory, "readSession");
|
|
4742
|
+
if (!fn) return null;
|
|
4743
|
+
const result = fn({
|
|
4744
|
+
agentType,
|
|
4745
|
+
sessionId: historySessionId,
|
|
4746
|
+
historySessionId,
|
|
4747
|
+
workspace,
|
|
4748
|
+
format: canonicalHistory?.format,
|
|
4749
|
+
watchPath: canonicalHistory?.watchPath,
|
|
4750
|
+
args: { sessionId: historySessionId, historySessionId, workspace }
|
|
4751
|
+
});
|
|
4752
|
+
if (!result || typeof result !== "object") return null;
|
|
4753
|
+
const records = normalizeProviderNativeHistoryRecords(agentType, historySessionId, result.messages || result.records);
|
|
4754
|
+
if (records.length === 0) return null;
|
|
4755
|
+
return {
|
|
4756
|
+
records,
|
|
4757
|
+
sourcePath: typeof result.sourcePath === "string" ? result.sourcePath : "",
|
|
4758
|
+
sourceMtimeMs: Number(result.sourceMtimeMs) || 0
|
|
4759
|
+
};
|
|
5184
4760
|
}
|
|
5185
|
-
function
|
|
5186
|
-
const
|
|
5187
|
-
|
|
5188
|
-
|
|
5189
|
-
if (output && typeof output === "object") {
|
|
5190
|
-
try {
|
|
5191
|
-
return JSON.stringify(output).trim();
|
|
5192
|
-
} catch {
|
|
5193
|
-
return "";
|
|
5194
|
-
}
|
|
5195
|
-
}
|
|
5196
|
-
return "";
|
|
4761
|
+
function buildNativeHistoryReadResult(agentType, canonicalHistory, scripts, historySessionId, workspace) {
|
|
4762
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || "");
|
|
4763
|
+
if (!canonicalHistory || !normalizedSessionId || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
|
|
4764
|
+
return callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace);
|
|
5197
4765
|
}
|
|
5198
|
-
function
|
|
4766
|
+
function materializeNativeHistoryToMirror(agentType, canonicalHistory, historySessionId, workspace, scripts) {
|
|
5199
4767
|
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
5200
|
-
if (!normalizedSessionId
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
parsed = null;
|
|
5213
|
-
}
|
|
5214
|
-
if (!parsed) continue;
|
|
5215
|
-
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
5216
|
-
fallbackTs = receivedAt + 1;
|
|
5217
|
-
const type = String(parsed.type || "").trim();
|
|
5218
|
-
const payload = parsed.payload && typeof parsed.payload === "object" ? parsed.payload : null;
|
|
5219
|
-
if (!payload) continue;
|
|
5220
|
-
if (type === "session_meta") {
|
|
5221
|
-
const parsedSessionId = String(payload.id || "").trim();
|
|
5222
|
-
if (parsedSessionId && parsedSessionId !== normalizedSessionId) return null;
|
|
5223
|
-
const parsedWorkspace = String(payload.cwd || workspace || "").trim();
|
|
5224
|
-
if (records.length === 0 && parsedWorkspace) {
|
|
5225
|
-
records.push({
|
|
5226
|
-
ts: new Date(receivedAt).toISOString(),
|
|
5227
|
-
receivedAt,
|
|
5228
|
-
role: "system",
|
|
5229
|
-
kind: "session_start",
|
|
5230
|
-
content: parsedWorkspace,
|
|
5231
|
-
agent: "codex-cli",
|
|
5232
|
-
historySessionId: normalizedSessionId,
|
|
5233
|
-
workspace: parsedWorkspace
|
|
5234
|
-
});
|
|
5235
|
-
}
|
|
5236
|
-
continue;
|
|
5237
|
-
}
|
|
5238
|
-
if (type !== "response_item") continue;
|
|
5239
|
-
const payloadType = String(payload.type || "").trim();
|
|
5240
|
-
if (payloadType === "message") {
|
|
5241
|
-
const role = String(payload.role || "").trim();
|
|
5242
|
-
if (role !== "user" && role !== "assistant") continue;
|
|
5243
|
-
const content = flattenCodexContent(payload.content);
|
|
5244
|
-
if (!content) continue;
|
|
5245
|
-
records.push({
|
|
5246
|
-
ts: new Date(receivedAt).toISOString(),
|
|
5247
|
-
receivedAt,
|
|
5248
|
-
role,
|
|
5249
|
-
content,
|
|
5250
|
-
kind: "standard",
|
|
5251
|
-
agent: "codex-cli",
|
|
5252
|
-
historySessionId: normalizedSessionId
|
|
5253
|
-
});
|
|
5254
|
-
continue;
|
|
5255
|
-
}
|
|
5256
|
-
if (payloadType === "function_call" || payloadType === "custom_tool_call") {
|
|
5257
|
-
const content = summarizeCodexToolCall(payload);
|
|
5258
|
-
if (!content) continue;
|
|
5259
|
-
records.push({
|
|
5260
|
-
ts: new Date(receivedAt).toISOString(),
|
|
5261
|
-
receivedAt,
|
|
5262
|
-
role: "assistant",
|
|
5263
|
-
content,
|
|
5264
|
-
kind: "tool",
|
|
5265
|
-
senderName: "Tool",
|
|
5266
|
-
agent: "codex-cli",
|
|
5267
|
-
historySessionId: normalizedSessionId
|
|
5268
|
-
});
|
|
5269
|
-
continue;
|
|
5270
|
-
}
|
|
5271
|
-
if (payloadType === "function_call_output" || payloadType === "custom_tool_call_output") {
|
|
5272
|
-
const content = codexToolOutputContent(payload);
|
|
5273
|
-
if (!content) continue;
|
|
5274
|
-
records.push({
|
|
5275
|
-
ts: new Date(receivedAt).toISOString(),
|
|
5276
|
-
receivedAt,
|
|
5277
|
-
role: "assistant",
|
|
5278
|
-
content,
|
|
5279
|
-
kind: "tool",
|
|
5280
|
-
senderName: "Tool",
|
|
5281
|
-
agent: "codex-cli",
|
|
5282
|
-
historySessionId: normalizedSessionId
|
|
5283
|
-
});
|
|
5284
|
-
}
|
|
5285
|
-
}
|
|
5286
|
-
return records;
|
|
5287
|
-
} catch {
|
|
5288
|
-
return null;
|
|
5289
|
-
}
|
|
4768
|
+
if (!normalizedSessionId) return false;
|
|
4769
|
+
const nativeResult = callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace);
|
|
4770
|
+
const nativeRecords = nativeResult?.records || [];
|
|
4771
|
+
if (nativeRecords.length === 0) return false;
|
|
4772
|
+
const normalizedRecords = nativeRecords.map((record2) => ({
|
|
4773
|
+
...record2,
|
|
4774
|
+
agent: agentType,
|
|
4775
|
+
historySessionId: normalizedSessionId
|
|
4776
|
+
}));
|
|
4777
|
+
const existingSessionStart = readExistingSessionStartRecord(agentType, normalizedSessionId);
|
|
4778
|
+
const records = existingSessionStart && normalizedRecords[0]?.kind !== "session_start" ? [{ ...existingSessionStart, historySessionId: normalizedSessionId, agent: agentType }, ...normalizedRecords] : normalizedRecords;
|
|
4779
|
+
return rewriteCanonicalSavedHistory(agentType, normalizedSessionId, records);
|
|
5290
4780
|
}
|
|
5291
|
-
function
|
|
5292
|
-
|
|
5293
|
-
|
|
5294
|
-
const records = buildCodexNativeHistoryRecords(normalizedSessionId, workspace);
|
|
5295
|
-
if (!records || records.length === 0) return false;
|
|
5296
|
-
const existingSessionStart = readExistingSessionStartRecord("codex-cli", normalizedSessionId);
|
|
5297
|
-
const recordsToWrite = existingSessionStart && records[0]?.kind !== "session_start" ? [{ ...existingSessionStart, historySessionId: normalizedSessionId }, ...records] : records;
|
|
5298
|
-
return rewriteCanonicalSavedHistory("codex-cli", normalizedSessionId, recordsToWrite);
|
|
4781
|
+
function materializeProviderNativeHistory(agentType, canonicalHistory, historySessionId, workspace, scripts) {
|
|
4782
|
+
if (!canonicalHistory || canonicalHistory.mode !== "materialized-mirror") return false;
|
|
4783
|
+
return materializeNativeHistoryToMirror(agentType, canonicalHistory, historySessionId, workspace, scripts);
|
|
5299
4784
|
}
|
|
5300
4785
|
function isNativeSourceCanonicalHistory(canonicalHistory) {
|
|
5301
4786
|
if (!canonicalHistory) return false;
|
|
@@ -5303,21 +4788,15 @@ function isNativeSourceCanonicalHistory(canonicalHistory) {
|
|
|
5303
4788
|
if (canonicalHistory.mode === "materialized-mirror") return false;
|
|
5304
4789
|
return true;
|
|
5305
4790
|
}
|
|
5306
|
-
function buildNativeHistoryRecords(canonicalHistory, historySessionId, workspace) {
|
|
5307
|
-
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || "");
|
|
5308
|
-
if (!canonicalHistory || !normalizedSessionId || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
|
|
5309
|
-
if (canonicalHistory.format === "hermes-json") return buildHermesNativeHistoryRecords(normalizedSessionId);
|
|
5310
|
-
if (canonicalHistory.format === "claude-jsonl") return buildClaudeNativeHistoryRecords(normalizedSessionId, workspace);
|
|
5311
|
-
if (canonicalHistory.format === "codex-jsonl") return buildCodexNativeHistoryRecords(normalizedSessionId, workspace);
|
|
5312
|
-
return null;
|
|
5313
|
-
}
|
|
5314
4791
|
function readProviderChatHistory(agentType, options = {}) {
|
|
5315
4792
|
if (isNativeSourceCanonicalHistory(options.canonicalHistory) && options.historySessionId) {
|
|
5316
|
-
const
|
|
5317
|
-
if (!
|
|
4793
|
+
const nativeResult = buildNativeHistoryReadResult(agentType, options.canonicalHistory, options.scripts, options.historySessionId, options.workspace);
|
|
4794
|
+
if (!nativeResult) return { messages: [], hasMore: false, source: "native-unavailable" };
|
|
5318
4795
|
return {
|
|
5319
|
-
...pageHistoryRecords(agentType, records, options.offset || 0, options.limit || 30, options.excludeRecentCount || 0, options.historyBehavior),
|
|
5320
|
-
source: "provider-native"
|
|
4796
|
+
...pageHistoryRecords(agentType, nativeResult.records, options.offset || 0, options.limit || 30, options.excludeRecentCount || 0, options.historyBehavior),
|
|
4797
|
+
source: "provider-native",
|
|
4798
|
+
sourcePath: nativeResult.sourcePath,
|
|
4799
|
+
sourceMtimeMs: nativeResult.sourceMtimeMs
|
|
5321
4800
|
};
|
|
5322
4801
|
}
|
|
5323
4802
|
return {
|
|
@@ -5350,68 +4829,64 @@ function buildNativeSessionSummary(agentType, historySessionId, records, sourceP
|
|
|
5350
4829
|
sourceMtimeMs
|
|
5351
4830
|
};
|
|
5352
4831
|
}
|
|
5353
|
-
function
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
const
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
}
|
|
5374
|
-
}
|
|
5375
|
-
return results;
|
|
4832
|
+
function normalizeProviderNativeHistorySessionSummary(agentType, item) {
|
|
4833
|
+
const historySessionId = normalizeSavedHistorySessionId(item?.historySessionId || item?.sessionId || "");
|
|
4834
|
+
if (!historySessionId) return null;
|
|
4835
|
+
const sourcePath = typeof item?.sourcePath === "string" ? item.sourcePath : "";
|
|
4836
|
+
const sourceMtimeMs = Number(item?.sourceMtimeMs) || 0;
|
|
4837
|
+
const firstMessageAt = Number(item?.firstMessageAt) || sourceMtimeMs || Date.now();
|
|
4838
|
+
const lastMessageAt = Number(item?.lastMessageAt) || firstMessageAt;
|
|
4839
|
+
const messageCount = Math.max(0, Number(item?.messageCount) || 0);
|
|
4840
|
+
return {
|
|
4841
|
+
historySessionId,
|
|
4842
|
+
sessionTitle: typeof item?.sessionTitle === "string" ? item.sessionTitle : void 0,
|
|
4843
|
+
messageCount,
|
|
4844
|
+
firstMessageAt,
|
|
4845
|
+
lastMessageAt,
|
|
4846
|
+
preview: typeof item?.preview === "string" ? item.preview : void 0,
|
|
4847
|
+
workspace: typeof item?.workspace === "string" ? item.workspace : void 0,
|
|
4848
|
+
source: "provider-native",
|
|
4849
|
+
sourcePath,
|
|
4850
|
+
sourceMtimeMs
|
|
4851
|
+
};
|
|
5376
4852
|
}
|
|
5377
|
-
function
|
|
4853
|
+
function collectProviderScriptNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) {
|
|
4854
|
+
const fn = getProviderNativeHistoryScript(scripts, canonicalHistory, "listSessions");
|
|
4855
|
+
if (!fn) return null;
|
|
4856
|
+
const result = fn({
|
|
4857
|
+
agentType,
|
|
4858
|
+
format: canonicalHistory.format,
|
|
4859
|
+
watchPath: canonicalHistory.watchPath,
|
|
4860
|
+
args: {}
|
|
4861
|
+
});
|
|
4862
|
+
if (!result || typeof result !== "object") return [];
|
|
4863
|
+
const sessions = Array.isArray(result.sessions) ? result.sessions : [];
|
|
5378
4864
|
const summaries = [];
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
const fileName = path7.basename(filePath);
|
|
5383
|
-
const historySessionId = fileName.replace(/^session_/, "").replace(/\.json$/, "");
|
|
5384
|
-
const records = buildHermesNativeHistoryRecords(historySessionId);
|
|
5385
|
-
const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
|
|
5386
|
-
if (summary) summaries.push(summary);
|
|
5387
|
-
}
|
|
5388
|
-
} else if (canonicalHistory.format === "claude-jsonl") {
|
|
5389
|
-
const root = path7.join(os6.homedir(), ".claude", "projects");
|
|
5390
|
-
for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && entry.name.endsWith(".jsonl"))) {
|
|
5391
|
-
const historySessionId = path7.basename(filePath, ".jsonl");
|
|
5392
|
-
const records = buildClaudeNativeHistoryRecords(historySessionId);
|
|
5393
|
-
const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
|
|
5394
|
-
if (summary) summaries.push(summary);
|
|
5395
|
-
}
|
|
5396
|
-
} else if (canonicalHistory.format === "codex-jsonl") {
|
|
5397
|
-
const root = path7.join(os6.homedir(), ".codex", "sessions");
|
|
5398
|
-
const uuidPattern = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i;
|
|
5399
|
-
for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && entry.name.endsWith(".jsonl"))) {
|
|
5400
|
-
const meta3 = readCodexSessionMeta(filePath);
|
|
5401
|
-
const historySessionId = String(meta3?.id || path7.basename(filePath).match(uuidPattern)?.[1] || "").trim();
|
|
4865
|
+
for (const item of sessions) {
|
|
4866
|
+
if (Array.isArray(item?.messages || item?.records)) {
|
|
4867
|
+
const historySessionId = normalizeSavedHistorySessionId(item?.historySessionId || item?.sessionId || "");
|
|
5402
4868
|
if (!historySessionId) continue;
|
|
5403
|
-
const records =
|
|
5404
|
-
const
|
|
5405
|
-
if (
|
|
4869
|
+
const records = normalizeProviderNativeHistoryRecords(agentType, historySessionId, item.messages || item.records);
|
|
4870
|
+
const summary2 = buildNativeSessionSummary(agentType, historySessionId, records, typeof item?.sourcePath === "string" ? item.sourcePath : "");
|
|
4871
|
+
if (summary2) {
|
|
4872
|
+
if (Number(item?.sourceMtimeMs)) summary2.sourceMtimeMs = Number(item.sourceMtimeMs);
|
|
4873
|
+
summaries.push(summary2);
|
|
4874
|
+
}
|
|
4875
|
+
continue;
|
|
5406
4876
|
}
|
|
4877
|
+
const summary = normalizeProviderNativeHistorySessionSummary(agentType, item);
|
|
4878
|
+
if (summary) summaries.push(summary);
|
|
5407
4879
|
}
|
|
5408
4880
|
return sortSavedHistorySessionSummaries(summaries);
|
|
5409
4881
|
}
|
|
4882
|
+
function collectNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) {
|
|
4883
|
+
return collectProviderScriptNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) || [];
|
|
4884
|
+
}
|
|
5410
4885
|
function listProviderHistorySessions(agentType, options = {}) {
|
|
5411
4886
|
if (isNativeSourceCanonicalHistory(options.canonicalHistory)) {
|
|
5412
4887
|
const offset = Math.max(0, options.offset || 0);
|
|
5413
4888
|
const limit = Math.max(1, options.limit || 30);
|
|
5414
|
-
const summaries = collectNativeHistorySessionSummaries(agentType, options.canonicalHistory);
|
|
4889
|
+
const summaries = collectNativeHistorySessionSummaries(agentType, options.canonicalHistory, options.scripts);
|
|
5415
4890
|
return {
|
|
5416
4891
|
sessions: summaries.slice(offset, offset + limit),
|
|
5417
4892
|
hasMore: offset + limit < summaries.length,
|
|
@@ -8703,7 +8178,8 @@ async function handleChatHistory(h, args) {
|
|
|
8703
8178
|
offset: offset || 0,
|
|
8704
8179
|
limit: limit || 30,
|
|
8705
8180
|
excludeRecentCount,
|
|
8706
|
-
historyBehavior: provider?.historyBehavior
|
|
8181
|
+
historyBehavior: provider?.historyBehavior,
|
|
8182
|
+
scripts: provider?.scripts
|
|
8707
8183
|
});
|
|
8708
8184
|
return { success: true, ...result, agent: agentStr };
|
|
8709
8185
|
} catch (e) {
|
|
@@ -15796,13 +15272,8 @@ var init_cli_provider_instance = __esm({
|
|
|
15796
15272
|
historyWriter;
|
|
15797
15273
|
runtimeMessages = [];
|
|
15798
15274
|
lastPersistedHistoryMessages = [];
|
|
15799
|
-
|
|
15800
|
-
|
|
15801
|
-
lastCanonicalHermesWatchPath = void 0;
|
|
15802
|
-
lastCanonicalClaudeRebuildMtimeMs = 0;
|
|
15803
|
-
lastCanonicalClaudeCheckAt = 0;
|
|
15804
|
-
lastCanonicalCodexRebuildMtimeMs = 0;
|
|
15805
|
-
lastCanonicalCodexCheckAt = 0;
|
|
15275
|
+
lastNativeSourceCanonicalCheckAt = 0;
|
|
15276
|
+
lastNativeSourceCanonicalCacheKey = void 0;
|
|
15806
15277
|
cachedSqliteDb = null;
|
|
15807
15278
|
cachedSqliteDbPath = null;
|
|
15808
15279
|
cachedSqliteDbMissingUntil = 0;
|
|
@@ -16503,76 +15974,44 @@ ${effect.notification.body || ""}`.trim();
|
|
|
16503
15974
|
const canonicalHistory = this.provider.canonicalHistory;
|
|
16504
15975
|
if (!canonicalHistory) return false;
|
|
16505
15976
|
if (isNativeSourceCanonicalHistory(canonicalHistory)) {
|
|
15977
|
+
const cacheKey = [this.type, this.providerSessionId, this.workingDir].join("\0");
|
|
15978
|
+
const now = Date.now();
|
|
15979
|
+
if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
|
|
15980
|
+
return true;
|
|
15981
|
+
}
|
|
15982
|
+
this.lastNativeSourceCanonicalCacheKey = cacheKey;
|
|
15983
|
+
this.lastNativeSourceCanonicalCheckAt = now;
|
|
16506
15984
|
const restoredHistory = readProviderChatHistory(this.type, {
|
|
16507
15985
|
canonicalHistory,
|
|
16508
15986
|
historySessionId: this.providerSessionId,
|
|
16509
15987
|
workspace: this.workingDir,
|
|
16510
15988
|
offset: 0,
|
|
16511
15989
|
limit: Number.MAX_SAFE_INTEGER,
|
|
16512
|
-
historyBehavior: this.provider.historyBehavior
|
|
15990
|
+
historyBehavior: this.provider.historyBehavior,
|
|
15991
|
+
scripts: this.provider.scripts
|
|
16513
15992
|
});
|
|
16514
|
-
if (restoredHistory.source
|
|
16515
|
-
|
|
16516
|
-
|
|
16517
|
-
|
|
16518
|
-
|
|
16519
|
-
|
|
16520
|
-
|
|
16521
|
-
|
|
15993
|
+
if (restoredHistory.source === "provider-native") {
|
|
15994
|
+
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
15995
|
+
role: message.role,
|
|
15996
|
+
content: message.content,
|
|
15997
|
+
kind: message.kind,
|
|
15998
|
+
senderName: message.senderName,
|
|
15999
|
+
receivedAt: message.receivedAt
|
|
16000
|
+
}));
|
|
16001
|
+
}
|
|
16522
16002
|
return true;
|
|
16523
16003
|
}
|
|
16524
16004
|
try {
|
|
16525
|
-
|
|
16526
|
-
|
|
16527
|
-
|
|
16528
|
-
|
|
16529
|
-
|
|
16530
|
-
|
|
16531
|
-
|
|
16532
|
-
|
|
16533
|
-
|
|
16534
|
-
if (!fs5.existsSync(watchPath)) return false;
|
|
16535
|
-
}
|
|
16536
|
-
const stat4 = fs5.statSync(watchPath);
|
|
16537
|
-
if (stat4.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
|
|
16538
|
-
rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
|
|
16539
|
-
if (rebuilt) this.lastCanonicalHermesSyncMtimeMs = stat4.mtimeMs;
|
|
16540
|
-
} else if (canonicalHistory.format === "claude-jsonl") {
|
|
16541
|
-
const now = Date.now();
|
|
16542
|
-
if (now - this.lastCanonicalClaudeCheckAt < 2e3 && this.lastCanonicalClaudeRebuildMtimeMs !== 0) {
|
|
16543
|
-
return true;
|
|
16544
|
-
}
|
|
16545
|
-
this.lastCanonicalClaudeCheckAt = now;
|
|
16546
|
-
const claudeProjectsDir = path12.join(os14.homedir(), ".claude", "projects");
|
|
16547
|
-
const workspaceSegment = typeof this.workingDir === "string" ? this.workingDir.replace(/[\\/]/g, "-").replace(/^-+/, "") : "";
|
|
16548
|
-
const transcriptFile = path12.join(claudeProjectsDir, workspaceSegment, `${this.providerSessionId}.jsonl`);
|
|
16549
|
-
let transcriptMtime = 0;
|
|
16550
|
-
try {
|
|
16551
|
-
transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
|
|
16552
|
-
} catch {
|
|
16553
|
-
}
|
|
16554
|
-
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalClaudeRebuildMtimeMs) return true;
|
|
16555
|
-
rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
|
|
16556
|
-
if (rebuilt) this.lastCanonicalClaudeRebuildMtimeMs = transcriptMtime || Date.now();
|
|
16557
|
-
} else if (canonicalHistory.format === "codex-jsonl") {
|
|
16558
|
-
const now = Date.now();
|
|
16559
|
-
if (now - this.lastCanonicalCodexCheckAt < 2e3 && this.lastCanonicalCodexRebuildMtimeMs !== 0) {
|
|
16560
|
-
return true;
|
|
16561
|
-
}
|
|
16562
|
-
this.lastCanonicalCodexCheckAt = now;
|
|
16563
|
-
const transcriptFile = resolveCodexSessionTranscriptPath(this.providerSessionId, this.workingDir);
|
|
16564
|
-
let transcriptMtime = 0;
|
|
16565
|
-
if (transcriptFile) {
|
|
16566
|
-
try {
|
|
16567
|
-
transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
|
|
16568
|
-
} catch {
|
|
16569
|
-
}
|
|
16570
|
-
}
|
|
16571
|
-
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalCodexRebuildMtimeMs) return true;
|
|
16572
|
-
rebuilt = rebuildCodexSavedHistoryFromNativeSession(this.providerSessionId, this.workingDir);
|
|
16573
|
-
if (rebuilt) this.lastCanonicalCodexRebuildMtimeMs = transcriptMtime || Date.now();
|
|
16005
|
+
const cacheKey = [this.type, this.providerSessionId, this.workingDir, canonicalHistory.mode || "materialized-mirror"].join("\0");
|
|
16006
|
+
const now = Date.now();
|
|
16007
|
+
if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
|
|
16008
|
+
return true;
|
|
16009
|
+
}
|
|
16010
|
+
this.lastNativeSourceCanonicalCacheKey = cacheKey;
|
|
16011
|
+
this.lastNativeSourceCanonicalCheckAt = now;
|
|
16012
|
+
if (!materializeProviderNativeHistory(this.type, canonicalHistory, this.providerSessionId, this.workingDir, this.provider.scripts)) {
|
|
16013
|
+
return false;
|
|
16574
16014
|
}
|
|
16575
|
-
if (!rebuilt) return false;
|
|
16576
16015
|
const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
16577
16016
|
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
16578
16017
|
role: message.role,
|
|
@@ -16595,7 +16034,8 @@ ${effect.notification.body || ""}`.trim();
|
|
|
16595
16034
|
workspace: this.workingDir,
|
|
16596
16035
|
offset: 0,
|
|
16597
16036
|
limit: Number.MAX_SAFE_INTEGER,
|
|
16598
|
-
historyBehavior: this.provider.historyBehavior
|
|
16037
|
+
historyBehavior: this.provider.historyBehavior,
|
|
16038
|
+
scripts: this.provider.scripts
|
|
16599
16039
|
}) : (() => {
|
|
16600
16040
|
this.historyWriter.compactHistorySession(this.type, this.providerSessionId, this.provider.historyBehavior);
|
|
16601
16041
|
return readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
@@ -35132,10 +34572,10 @@ var init_readdirp = __esm({
|
|
|
35132
34572
|
}
|
|
35133
34573
|
async _formatEntry(dirent, path35) {
|
|
35134
34574
|
let entry;
|
|
35135
|
-
const
|
|
34575
|
+
const basename10 = this._isDirent ? dirent.name : dirent;
|
|
35136
34576
|
try {
|
|
35137
|
-
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path35,
|
|
35138
|
-
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename:
|
|
34577
|
+
const fullPath = (0, import_node_path.resolve)((0, import_node_path.join)(path35, basename10));
|
|
34578
|
+
entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename10 };
|
|
35139
34579
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
35140
34580
|
} catch (err) {
|
|
35141
34581
|
this._onError(err);
|
|
@@ -35666,9 +35106,9 @@ var init_handler2 = __esm({
|
|
|
35666
35106
|
_watchWithNodeFs(path35, listener) {
|
|
35667
35107
|
const opts = this.fsw.options;
|
|
35668
35108
|
const directory = sp.dirname(path35);
|
|
35669
|
-
const
|
|
35109
|
+
const basename10 = sp.basename(path35);
|
|
35670
35110
|
const parent = this.fsw._getWatchedDir(directory);
|
|
35671
|
-
parent.add(
|
|
35111
|
+
parent.add(basename10);
|
|
35672
35112
|
const absolutePath = sp.resolve(path35);
|
|
35673
35113
|
const options = {
|
|
35674
35114
|
persistent: opts.persistent
|
|
@@ -35678,7 +35118,7 @@ var init_handler2 = __esm({
|
|
|
35678
35118
|
let closer;
|
|
35679
35119
|
if (opts.usePolling) {
|
|
35680
35120
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
35681
|
-
options.interval = enableBin && isBinaryPath(
|
|
35121
|
+
options.interval = enableBin && isBinaryPath(basename10) ? opts.binaryInterval : opts.interval;
|
|
35682
35122
|
closer = setFsWatchFileListener(path35, absolutePath, options, {
|
|
35683
35123
|
listener,
|
|
35684
35124
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -35701,10 +35141,10 @@ var init_handler2 = __esm({
|
|
|
35701
35141
|
return;
|
|
35702
35142
|
}
|
|
35703
35143
|
const dirname11 = sp.dirname(file2);
|
|
35704
|
-
const
|
|
35144
|
+
const basename10 = sp.basename(file2);
|
|
35705
35145
|
const parent = this.fsw._getWatchedDir(dirname11);
|
|
35706
35146
|
let prevStats = stats;
|
|
35707
|
-
if (parent.has(
|
|
35147
|
+
if (parent.has(basename10))
|
|
35708
35148
|
return;
|
|
35709
35149
|
const listener = async (path35, newStats) => {
|
|
35710
35150
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
|
|
@@ -35729,9 +35169,9 @@ var init_handler2 = __esm({
|
|
|
35729
35169
|
prevStats = newStats2;
|
|
35730
35170
|
}
|
|
35731
35171
|
} catch (error48) {
|
|
35732
|
-
this.fsw._remove(dirname11,
|
|
35172
|
+
this.fsw._remove(dirname11, basename10);
|
|
35733
35173
|
}
|
|
35734
|
-
} else if (parent.has(
|
|
35174
|
+
} else if (parent.has(basename10)) {
|
|
35735
35175
|
const at = newStats.atimeMs;
|
|
35736
35176
|
const mt = newStats.mtimeMs;
|
|
35737
35177
|
if (!at || at <= mt || mt !== prevStats.mtimeMs) {
|
|
@@ -36744,6 +36184,7 @@ function validateProviderDefinition(raw) {
|
|
|
36744
36184
|
warnings.push("Extension providers should have extensionId");
|
|
36745
36185
|
}
|
|
36746
36186
|
validateCapabilities(provider, controls, errors);
|
|
36187
|
+
validateCanonicalHistory(provider.canonicalHistory, errors);
|
|
36747
36188
|
for (const control of controls) {
|
|
36748
36189
|
validateControl(control, errors);
|
|
36749
36190
|
}
|
|
@@ -36801,6 +36242,39 @@ function validateCapabilities(provider, controls, errors) {
|
|
|
36801
36242
|
errors.push("providers declaring controls must set capabilities.controls.typedResults=true");
|
|
36802
36243
|
}
|
|
36803
36244
|
}
|
|
36245
|
+
function validateCanonicalHistory(raw, errors) {
|
|
36246
|
+
if (raw === void 0) return;
|
|
36247
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
36248
|
+
errors.push("canonicalHistory must be an object");
|
|
36249
|
+
return;
|
|
36250
|
+
}
|
|
36251
|
+
const canonicalHistory = raw;
|
|
36252
|
+
const format = canonicalHistory.format;
|
|
36253
|
+
if (format !== void 0 && (typeof format !== "string" || !format.trim())) {
|
|
36254
|
+
errors.push("canonicalHistory.format must be a non-empty string when provided");
|
|
36255
|
+
}
|
|
36256
|
+
const watchPath = canonicalHistory.watchPath;
|
|
36257
|
+
if (watchPath !== void 0 && (typeof watchPath !== "string" || !watchPath.trim())) {
|
|
36258
|
+
errors.push("canonicalHistory.watchPath must be a non-empty string when provided");
|
|
36259
|
+
}
|
|
36260
|
+
const mode = canonicalHistory.mode;
|
|
36261
|
+
if (mode !== void 0 && !["native-source", "materialized-mirror", "disabled"].includes(String(mode))) {
|
|
36262
|
+
errors.push("canonicalHistory.mode must be one of: native-source, materialized-mirror, disabled");
|
|
36263
|
+
}
|
|
36264
|
+
const scripts = canonicalHistory.scripts;
|
|
36265
|
+
if (scripts === void 0) return;
|
|
36266
|
+
if (!scripts || typeof scripts !== "object" || Array.isArray(scripts)) {
|
|
36267
|
+
errors.push("canonicalHistory.scripts must be an object");
|
|
36268
|
+
return;
|
|
36269
|
+
}
|
|
36270
|
+
const scriptConfig = scripts;
|
|
36271
|
+
for (const key of ["readSession", "listSessions"]) {
|
|
36272
|
+
const value = scriptConfig[key];
|
|
36273
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
36274
|
+
errors.push(`canonicalHistory.scripts.${key} must be a non-empty string`);
|
|
36275
|
+
}
|
|
36276
|
+
}
|
|
36277
|
+
}
|
|
36804
36278
|
function validateControl(control, errors) {
|
|
36805
36279
|
if (!control || typeof control !== "object") {
|
|
36806
36280
|
errors.push("controls: each control must be an object");
|
|
@@ -40086,7 +39560,8 @@ var init_router = __esm({
|
|
|
40086
39560
|
canonicalHistory: providerMeta?.canonicalHistory,
|
|
40087
39561
|
offset,
|
|
40088
39562
|
limit,
|
|
40089
|
-
historyBehavior: providerMeta?.historyBehavior
|
|
39563
|
+
historyBehavior: providerMeta?.historyBehavior,
|
|
39564
|
+
scripts: providerMeta?.scripts
|
|
40090
39565
|
});
|
|
40091
39566
|
const state = loadState();
|
|
40092
39567
|
const savedSessions = getSavedProviderSessions(state, { providerType, kind });
|
|
@@ -40112,7 +39587,10 @@ var init_router = __esm({
|
|
|
40112
39587
|
messageCount: session.messageCount,
|
|
40113
39588
|
firstMessageAt: session.firstMessageAt,
|
|
40114
39589
|
lastMessageAt: session.lastMessageAt,
|
|
40115
|
-
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById
|
|
39590
|
+
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById,
|
|
39591
|
+
historySource: session.source,
|
|
39592
|
+
sourcePath: session.sourcePath,
|
|
39593
|
+
sourceMtimeMs: session.sourceMtimeMs
|
|
40116
39594
|
};
|
|
40117
39595
|
}),
|
|
40118
39596
|
hasMore,
|
|
@@ -79480,6 +78958,7 @@ var init_server_connection = __esm({
|
|
|
79480
78958
|
iceServers = null;
|
|
79481
78959
|
planLimits = null;
|
|
79482
78960
|
compatBlocked = false;
|
|
78961
|
+
fatalAuthRejectedReason = null;
|
|
79483
78962
|
get authTimeoutMs() {
|
|
79484
78963
|
return Math.max(1, this.options.authTimeoutMs ?? 15e3);
|
|
79485
78964
|
}
|
|
@@ -79596,6 +79075,7 @@ var init_server_connection = __esm({
|
|
|
79596
79075
|
this.clearAuthTimeout();
|
|
79597
79076
|
this.reconnectAttempts = 0;
|
|
79598
79077
|
this.compatBlocked = false;
|
|
79078
|
+
this.fatalAuthRejectedReason = null;
|
|
79599
79079
|
const payload = message.payload;
|
|
79600
79080
|
this.userPlan = payload.plan || "free";
|
|
79601
79081
|
this.iceServers = payload.iceServers || null;
|
|
@@ -79609,8 +79089,20 @@ var init_server_connection = __esm({
|
|
|
79609
79089
|
this.startHeartbeat();
|
|
79610
79090
|
} else if (message.type === "auth_error") {
|
|
79611
79091
|
this.clearAuthTimeout();
|
|
79612
|
-
|
|
79092
|
+
const payload = message.payload;
|
|
79093
|
+
const reason = String(payload.reason || "Authentication failed");
|
|
79094
|
+
this.fatalAuthRejectedReason = reason;
|
|
79095
|
+
LOG.error("Server", `Auth failed: ${reason}`);
|
|
79096
|
+
if (reason === "machine_limit_exceeded") {
|
|
79097
|
+
LOG.error("Server", `[ServerConn] ${payload.message || "Machine limit exceeded. Remove an unused machine in the dashboard or upgrade your plan."}`);
|
|
79098
|
+
} else {
|
|
79099
|
+
LOG.error("Server", `[ServerConn] Saved machine credentials were rejected. Run 'adhdev setup --force' to re-authenticate, then restart the daemon.`);
|
|
79100
|
+
}
|
|
79613
79101
|
this.setState("error");
|
|
79102
|
+
try {
|
|
79103
|
+
this.ws?.close(1e3, "Authentication rejected");
|
|
79104
|
+
} catch {
|
|
79105
|
+
}
|
|
79614
79106
|
return;
|
|
79615
79107
|
} else if (message.type === "version_mismatch") {
|
|
79616
79108
|
const p = message.payload;
|
|
@@ -79643,6 +79135,18 @@ var init_server_connection = __esm({
|
|
|
79643
79135
|
LOG.info("Server", `[ServerConn] WebSocket closed: ${code} ${reason}`);
|
|
79644
79136
|
this.clearTimers();
|
|
79645
79137
|
this.ws = null;
|
|
79138
|
+
if (code === 4001 || this.fatalAuthRejectedReason) {
|
|
79139
|
+
const authReason = this.fatalAuthRejectedReason;
|
|
79140
|
+
const reasonText = authReason ? `: ${authReason}` : "";
|
|
79141
|
+
LOG.error("Server", `[ServerConn] Authentication rejected${reasonText}. Not reconnecting with the same credentials.`);
|
|
79142
|
+
if (authReason === "machine_limit_exceeded") {
|
|
79143
|
+
LOG.error("Server", `[ServerConn] Remove an unused machine in the dashboard or upgrade your plan, then restart the daemon.`);
|
|
79144
|
+
} else {
|
|
79145
|
+
LOG.error("Server", `[ServerConn] Run 'adhdev setup --force', then 'adhdev daemon:restart'.`);
|
|
79146
|
+
}
|
|
79147
|
+
this.setState("disconnected");
|
|
79148
|
+
return;
|
|
79149
|
+
}
|
|
79646
79150
|
if (code === 4011) {
|
|
79647
79151
|
LOG.info("Server", `[ServerConn] \u26A0 Evicted by another machine. Not reconnecting.`);
|
|
79648
79152
|
LOG.info("Server", `[ServerConn] This connection was released because another machine connected.`);
|
|
@@ -88552,7 +88056,7 @@ var init_adhdev_daemon = __esm({
|
|
|
88552
88056
|
init_version();
|
|
88553
88057
|
init_src();
|
|
88554
88058
|
init_runtime_defaults();
|
|
88555
|
-
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.
|
|
88059
|
+
pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.46" });
|
|
88556
88060
|
AdhdevDaemon = class _AdhdevDaemon {
|
|
88557
88061
|
localHttpServer = null;
|
|
88558
88062
|
localWss = null;
|