adhdev 0.9.45 → 0.9.47

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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 buildHermesNativeHistoryRecords(historySessionId) {
4737
- const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
4738
- if (!normalizedSessionId) return null;
4739
- try {
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 extractClaudeAssistantContentParts(content) {
4875
- if (typeof content === "string") {
4876
- const trimmed = content.trim();
4877
- return trimmed ? [{ content: trimmed, kind: "standard", role: "assistant" }] : [];
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 extractClaudeUserContentParts(content) {
4901
- if (typeof content === "string") {
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
- if (!normalizedSessionId) return null;
4934
- try {
4935
- const transcriptPath = resolveClaudeProjectTranscriptPath(normalizedSessionId, workspace);
4936
- if (!transcriptPath) return null;
4937
- const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
4938
- const records = [];
4939
- let fallbackTs = Date.now();
4940
- for (const line of lines) {
4941
- let parsed = null;
4942
- try {
4943
- parsed = JSON.parse(line);
4944
- } catch {
4945
- parsed = null;
4946
- }
4947
- if (!parsed) continue;
4948
- const parsedSessionId = String(parsed.sessionId || "").trim();
4949
- if (parsedSessionId && parsedSessionId !== normalizedSessionId) continue;
4950
- const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
4951
- fallbackTs = receivedAt + 1;
4952
- const parsedWorkspace = String(parsed.cwd || workspace || "").trim();
4953
- if (records.length === 0 && parsedWorkspace) {
4954
- records.push({
4955
- ts: new Date(receivedAt).toISOString(),
4956
- receivedAt,
4957
- role: "system",
4958
- kind: "session_start",
4959
- content: parsedWorkspace,
4960
- agent: "claude-cli",
4961
- historySessionId: normalizedSessionId,
4962
- workspace: parsedWorkspace
4963
- });
4964
- }
4965
- const type = String(parsed.type || "").trim();
4966
- const message = parsed.message && typeof parsed.message === "object" ? parsed.message : null;
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 codexToolOutputContent(payload) {
5186
- const output = payload.output ?? payload.result ?? payload.content;
5187
- const text = flattenCodexContent(output);
5188
- if (text) return text;
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 buildCodexNativeHistoryRecords(historySessionId, workspace) {
4766
+ function materializeNativeHistoryToMirror(agentType, canonicalHistory, historySessionId, workspace, scripts) {
5199
4767
  const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
5200
- if (!normalizedSessionId || !isUuidLikeSessionId(normalizedSessionId)) return null;
5201
- try {
5202
- const transcriptPath = resolveCodexSessionTranscriptPath(normalizedSessionId, workspace);
5203
- if (!transcriptPath) return null;
5204
- const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
5205
- const records = [];
5206
- let fallbackTs = Date.now();
5207
- for (const line of lines) {
5208
- let parsed = null;
5209
- try {
5210
- parsed = JSON.parse(line);
5211
- } catch {
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 rebuildCodexSavedHistoryFromNativeSession(historySessionId, workspace) {
5292
- const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
5293
- if (!normalizedSessionId || !isUuidLikeSessionId(normalizedSessionId)) return false;
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 records = buildNativeHistoryRecords(options.canonicalHistory, options.historySessionId, options.workspace);
5317
- if (!records) return { messages: [], hasMore: false, source: "native-unavailable" };
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 listFilesRecursive(root, predicate) {
5354
- if (!fs3.existsSync(root)) return [];
5355
- const results = [];
5356
- const stack = [root];
5357
- while (stack.length > 0) {
5358
- const current = stack.pop();
5359
- if (!current) continue;
5360
- let entries = [];
5361
- try {
5362
- entries = fs3.readdirSync(current, { withFileTypes: true });
5363
- } catch {
5364
- continue;
5365
- }
5366
- for (const entry of entries) {
5367
- const entryPath = path7.join(current, entry.name);
5368
- if (entry.isDirectory()) {
5369
- stack.push(entryPath);
5370
- continue;
5371
- }
5372
- if (predicate(entryPath, entry)) results.push(entryPath);
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 collectNativeHistorySessionSummaries(agentType, canonicalHistory) {
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
- if (canonicalHistory.format === "hermes-json") {
5380
- const root = path7.join(os6.homedir(), ".hermes", "sessions");
5381
- for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && /^session_.+\.json$/.test(entry.name))) {
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 = buildCodexNativeHistoryRecords(historySessionId, String(meta3?.cwd || "").trim() || void 0);
5404
- const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
5405
- if (summary) summaries.push(summary);
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
- lastCanonicalHermesSyncMtimeMs = 0;
15800
- lastCanonicalHermesExistCheckAt = 0;
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 !== "provider-native") return false;
16515
- this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
16516
- role: message.role,
16517
- content: message.content,
16518
- kind: message.kind,
16519
- senderName: message.senderName,
16520
- receivedAt: message.receivedAt
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
- let rebuilt = false;
16526
- if (canonicalHistory.format === "hermes-json") {
16527
- const watchPath = canonicalHistory.watchPath.replace(/^~/, os14.homedir()).replace("{{sessionId}}", this.providerSessionId);
16528
- const now = Date.now();
16529
- if (watchPath !== this.lastCanonicalHermesWatchPath || now - this.lastCanonicalHermesExistCheckAt >= 2e3) {
16530
- this.lastCanonicalHermesWatchPath = watchPath;
16531
- this.lastCanonicalHermesExistCheckAt = now;
16532
- if (!fs5.existsSync(watchPath)) return false;
16533
- } else if (this.lastCanonicalHermesSyncMtimeMs === 0) {
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 basename11 = this._isDirent ? dirent.name : dirent;
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, basename11));
35138
- entry = { path: (0, import_node_path.relative)(this._root, fullPath), fullPath, basename: basename11 };
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 basename11 = sp.basename(path35);
35109
+ const basename10 = sp.basename(path35);
35670
35110
  const parent = this.fsw._getWatchedDir(directory);
35671
- parent.add(basename11);
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(basename11) ? opts.binaryInterval : opts.interval;
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 basename11 = sp.basename(file2);
35144
+ const basename10 = sp.basename(file2);
35705
35145
  const parent = this.fsw._getWatchedDir(dirname11);
35706
35146
  let prevStats = stats;
35707
- if (parent.has(basename11))
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, basename11);
35172
+ this.fsw._remove(dirname11, basename10);
35733
35173
  }
35734
- } else if (parent.has(basename11)) {
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");
@@ -40081,12 +39555,13 @@ var init_router = __esm({
40081
39555
  const wantsAll = args?.all === true;
40082
39556
  const offset = wantsAll ? 0 : Math.max(0, Number(args?.offset) || 0);
40083
39557
  const limit = wantsAll ? Number.MAX_SAFE_INTEGER : Math.max(1, Math.min(100, Number(args?.limit) || 30));
40084
- const providerMeta = this.deps.providerLoader.getMeta(providerType);
39558
+ const providerMeta = this.deps.providerLoader.resolve?.(providerType) || this.deps.providerLoader.getMeta(providerType);
40085
39559
  const { sessions: historySessions, hasMore, source } = listProviderHistorySessions(providerType, {
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
- LOG.error("Server", `Auth failed: ${message.payload.reason}`);
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.45" });
88059
+ pkgVersion = resolvePackageVersion({ injectedVersion: "0.9.47" });
88556
88060
  AdhdevDaemon = class _AdhdevDaemon {
88557
88061
  localHttpServer = null;
88558
88062
  localWss = null;