@adhdev/daemon-core 0.9.44 → 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-adapters/provider-cli-adapter.d.ts +3 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +6 -0
- package/dist/config/chat-history.d.ts +34 -11
- package/dist/index.js +410 -310
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +410 -310
- package/dist/index.mjs.map +1 -1
- package/dist/launch/macos-app-process.d.ts +2 -0
- package/dist/providers/cli-provider-instance.d.ts +2 -5
- package/dist/providers/contracts.d.ts +33 -11
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/cli-adapters/provider-cli-adapter.ts +25 -3
- package/src/cli-adapters/provider-cli-shared.ts +6 -0
- package/src/commands/chat-commands.ts +28 -3
- package/src/commands/router.ts +13 -3
- package/src/config/chat-history.ts +282 -284
- package/src/launch/macos-app-process.ts +37 -0
- package/src/launch.ts +43 -5
- package/src/providers/cli-provider-instance.ts +57 -46
- package/src/providers/contracts.ts +35 -12
- package/src/providers/provider-schema.ts +40 -0
- package/src/providers/read-chat-contract.ts +2 -0
package/dist/index.mjs
CHANGED
|
@@ -980,6 +980,8 @@ function validateReadChatResultPayload(raw, source = "read_chat") {
|
|
|
980
980
|
if (raw.summaryMetadata !== void 0) normalized.summaryMetadata = raw.summaryMetadata;
|
|
981
981
|
if (Array.isArray(raw.effects)) normalized.effects = raw.effects;
|
|
982
982
|
if (typeof raw.providerSessionId === "string") normalized.providerSessionId = raw.providerSessionId;
|
|
983
|
+
if (raw.transcriptAuthority === "provider" || raw.transcriptAuthority === "daemon") normalized.transcriptAuthority = raw.transcriptAuthority;
|
|
984
|
+
if (raw.coverage === "full" || raw.coverage === "tail" || raw.coverage === "current-turn") normalized.coverage = raw.coverage;
|
|
983
985
|
return normalized;
|
|
984
986
|
}
|
|
985
987
|
var VALID_STATUSES, VALID_ROLES, VALID_BUBBLE_STATES, VALID_TURN_STATUSES;
|
|
@@ -2056,7 +2058,8 @@ __export(provider_cli_adapter_exports, {
|
|
|
2056
2058
|
ProviderCliAdapter: () => ProviderCliAdapter,
|
|
2057
2059
|
appendBoundedText: () => appendBoundedText,
|
|
2058
2060
|
normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime,
|
|
2059
|
-
sanitizeCliStandardMessageContent: () => sanitizeCliStandardMessageContent
|
|
2061
|
+
sanitizeCliStandardMessageContent: () => sanitizeCliStandardMessageContent,
|
|
2062
|
+
trimLastAssistantEchoForCliMessages: () => trimLastAssistantEchoForCliMessages
|
|
2060
2063
|
});
|
|
2061
2064
|
import * as os10 from "os";
|
|
2062
2065
|
function normalizeComparableTranscriptText(value) {
|
|
@@ -2153,6 +2156,19 @@ function sanitizeCommittedMessageForDisplay(message) {
|
|
|
2153
2156
|
if (content === message.content) return message;
|
|
2154
2157
|
return { ...message, content };
|
|
2155
2158
|
}
|
|
2159
|
+
function trimLastAssistantEchoForCliMessages(messages, prompt) {
|
|
2160
|
+
if (!prompt) return;
|
|
2161
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
2162
|
+
const message = messages[index];
|
|
2163
|
+
if (!message || message.role !== "assistant" || typeof message.content !== "string") continue;
|
|
2164
|
+
if ((message.kind || "standard") !== "standard") continue;
|
|
2165
|
+
message.content = trimPromptEchoPrefix(message.content, prompt);
|
|
2166
|
+
if (!message.content.trim()) {
|
|
2167
|
+
messages.splice(index, 1);
|
|
2168
|
+
}
|
|
2169
|
+
return;
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2156
2172
|
var COMMITTED_ACTIVITY_PREFIX_BLOCK_RE, ProviderCliAdapter;
|
|
2157
2173
|
var init_provider_cli_adapter = __esm({
|
|
2158
2174
|
"src/cli-adapters/provider-cli-adapter.ts"() {
|
|
@@ -2349,7 +2365,14 @@ var init_provider_cli_adapter = __esm({
|
|
|
2349
2365
|
}
|
|
2350
2366
|
return null;
|
|
2351
2367
|
}
|
|
2368
|
+
providerOwnsTranscript() {
|
|
2369
|
+
return this.provider.transcriptAuthority === "provider";
|
|
2370
|
+
}
|
|
2371
|
+
shouldUseFullProviderTranscriptContext() {
|
|
2372
|
+
return this.providerOwnsTranscript() && this.provider.transcriptContext === "full";
|
|
2373
|
+
}
|
|
2352
2374
|
selectParseBaseMessages(baseMessages) {
|
|
2375
|
+
if (this.shouldUseFullProviderTranscriptContext()) return baseMessages;
|
|
2353
2376
|
if (baseMessages.length <= _ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT) return baseMessages;
|
|
2354
2377
|
return baseMessages.slice(-_ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT);
|
|
2355
2378
|
}
|
|
@@ -2832,9 +2855,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
2832
2855
|
);
|
|
2833
2856
|
}
|
|
2834
2857
|
trimLastAssistantEcho(messages, prompt) {
|
|
2835
|
-
|
|
2836
|
-
const last = [...messages].reverse().find((m) => m.role === "assistant" && typeof m.content === "string");
|
|
2837
|
-
if (last) last.content = trimPromptEchoPrefix(last.content, prompt);
|
|
2858
|
+
trimLastAssistantEchoForCliMessages(messages, prompt);
|
|
2838
2859
|
}
|
|
2839
2860
|
clearAllTimers() {
|
|
2840
2861
|
if (this.responseTimeout) {
|
|
@@ -3688,7 +3709,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
3688
3709
|
title: parsed.title || this.cliName,
|
|
3689
3710
|
messages: hydratedMessages,
|
|
3690
3711
|
activeModal: parsed.activeModal ?? this.activeModal,
|
|
3691
|
-
providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0
|
|
3712
|
+
providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0,
|
|
3713
|
+
...this.providerOwnsTranscript() ? { transcriptAuthority: "provider", coverage: this.shouldUseFullProviderTranscriptContext() ? "full" : "tail" } : {}
|
|
3692
3714
|
};
|
|
3693
3715
|
} else {
|
|
3694
3716
|
const messages = [...this.committedMessages];
|
|
@@ -7872,6 +7894,27 @@ var ChatHistoryWriter = class {
|
|
|
7872
7894
|
return name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
7873
7895
|
}
|
|
7874
7896
|
};
|
|
7897
|
+
function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeRecentCount = 0, historyBehavior) {
|
|
7898
|
+
const allMessages = records.map((message) => sanitizeHistoryMessage(agentType, message)).filter(Boolean);
|
|
7899
|
+
allMessages.sort((a, b) => a.receivedAt - b.receivedAt);
|
|
7900
|
+
const chronological = [];
|
|
7901
|
+
let lastTurn = null;
|
|
7902
|
+
for (const message of allMessages) {
|
|
7903
|
+
const previous = chronological[chronological.length - 1];
|
|
7904
|
+
if (isAdjacentHistoryDuplicate(agentType, previous, message)) continue;
|
|
7905
|
+
if (message.role !== "system" && isAdjacentHistoryDuplicate(agentType, lastTurn, message)) continue;
|
|
7906
|
+
chronological.push(message);
|
|
7907
|
+
if (message.role !== "system") lastTurn = message;
|
|
7908
|
+
}
|
|
7909
|
+
const collapsed = collapseReplayAssistantTurns(chronological, historyBehavior);
|
|
7910
|
+
const boundedLimit = Math.max(1, limit);
|
|
7911
|
+
const boundedOffset = Math.max(0, offset);
|
|
7912
|
+
const boundedExclude = Math.max(0, Math.min(excludeRecentCount, collapsed.length));
|
|
7913
|
+
const endExclusive = Math.max(0, collapsed.length - boundedExclude - boundedOffset);
|
|
7914
|
+
const startInclusive = Math.max(0, endExclusive - boundedLimit);
|
|
7915
|
+
const sliced = collapsed.slice(startInclusive, endExclusive);
|
|
7916
|
+
return { messages: sliced, hasMore: startInclusive > 0 };
|
|
7917
|
+
}
|
|
7875
7918
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
7876
7919
|
try {
|
|
7877
7920
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
@@ -7897,25 +7940,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
7897
7940
|
}
|
|
7898
7941
|
}
|
|
7899
7942
|
}
|
|
7900
|
-
|
|
7901
|
-
const chronological = [];
|
|
7902
|
-
let lastTurn = null;
|
|
7903
|
-
for (const message of allMessages) {
|
|
7904
|
-
const previous = chronological[chronological.length - 1];
|
|
7905
|
-
if (isAdjacentHistoryDuplicate(agentType, previous, message)) continue;
|
|
7906
|
-
if (message.role !== "system" && isAdjacentHistoryDuplicate(agentType, lastTurn, message)) continue;
|
|
7907
|
-
chronological.push(message);
|
|
7908
|
-
if (message.role !== "system") lastTurn = message;
|
|
7909
|
-
}
|
|
7910
|
-
const collapsed = collapseReplayAssistantTurns(chronological, historyBehavior);
|
|
7911
|
-
const boundedLimit = Math.max(1, limit);
|
|
7912
|
-
const boundedOffset = Math.max(0, offset);
|
|
7913
|
-
const boundedExclude = Math.max(0, Math.min(excludeRecentCount, collapsed.length));
|
|
7914
|
-
const endExclusive = Math.max(0, collapsed.length - boundedExclude - boundedOffset);
|
|
7915
|
-
const startInclusive = Math.max(0, endExclusive - boundedLimit);
|
|
7916
|
-
const sliced = collapsed.slice(startInclusive, endExclusive);
|
|
7917
|
-
const hasMore = startInclusive > 0;
|
|
7918
|
-
return { messages: sliced, hasMore };
|
|
7943
|
+
return pageHistoryRecords(agentType, allMessages, offset, limit, excludeRecentCount, historyBehavior);
|
|
7919
7944
|
} catch {
|
|
7920
7945
|
return { messages: [], hasMore: false };
|
|
7921
7946
|
}
|
|
@@ -7982,29 +8007,6 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
7982
8007
|
return { sessions: [], hasMore: false };
|
|
7983
8008
|
}
|
|
7984
8009
|
}
|
|
7985
|
-
function normalizeCanonicalHermesMessageContent(content) {
|
|
7986
|
-
if (typeof content === "string") return content.trim();
|
|
7987
|
-
if (content == null) return "";
|
|
7988
|
-
try {
|
|
7989
|
-
return JSON.stringify(content).trim();
|
|
7990
|
-
} catch {
|
|
7991
|
-
return String(content).trim();
|
|
7992
|
-
}
|
|
7993
|
-
}
|
|
7994
|
-
function extractCanonicalHermesMessageTimestamp(message, fallbackTs) {
|
|
7995
|
-
const numericTimestamp = Number(message.receivedAt || message.timestamp || message.ts || 0);
|
|
7996
|
-
if (Number.isFinite(numericTimestamp) && numericTimestamp > 0) return numericTimestamp;
|
|
7997
|
-
const stringTimestamp = typeof message.ts === "string" ? Date.parse(message.ts) : typeof message.timestamp === "string" ? Date.parse(message.timestamp) : NaN;
|
|
7998
|
-
if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
|
|
7999
|
-
return fallbackTs;
|
|
8000
|
-
}
|
|
8001
|
-
function extractTimestampValue(value) {
|
|
8002
|
-
const numericTimestamp = Number(value || 0);
|
|
8003
|
-
if (Number.isFinite(numericTimestamp) && numericTimestamp > 0) return numericTimestamp;
|
|
8004
|
-
const stringTimestamp = typeof value === "string" ? Date.parse(value) : NaN;
|
|
8005
|
-
if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
|
|
8006
|
-
return 0;
|
|
8007
|
-
}
|
|
8008
8010
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
8009
8011
|
try {
|
|
8010
8012
|
const dir = path7.join(HISTORY_DIR, agentType);
|
|
@@ -8050,232 +8052,193 @@ function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
|
8050
8052
|
return false;
|
|
8051
8053
|
}
|
|
8052
8054
|
}
|
|
8053
|
-
function
|
|
8055
|
+
function getNativeHistoryScriptName(canonicalHistory, key) {
|
|
8056
|
+
const configured = canonicalHistory?.scripts?.[key];
|
|
8057
|
+
if (typeof configured === "string" && configured.trim()) return configured.trim();
|
|
8058
|
+
return key === "readSession" ? "readNativeHistory" : "listNativeHistory";
|
|
8059
|
+
}
|
|
8060
|
+
function getProviderNativeHistoryScript(scripts, canonicalHistory, key) {
|
|
8061
|
+
if (!canonicalHistory?.scripts) return null;
|
|
8062
|
+
const fn = scripts?.[getNativeHistoryScriptName(canonicalHistory, key)];
|
|
8063
|
+
return typeof fn === "function" ? fn : null;
|
|
8064
|
+
}
|
|
8065
|
+
function normalizeProviderNativeHistoryRecords(agentType, historySessionId, records) {
|
|
8066
|
+
if (!Array.isArray(records)) return [];
|
|
8067
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8068
|
+
return records.map((record) => sanitizeHistoryMessage(agentType, {
|
|
8069
|
+
ts: typeof record?.ts === "string" ? record.ts : new Date(Number(record?.receivedAt) || Date.now()).toISOString(),
|
|
8070
|
+
receivedAt: Number(record?.receivedAt) || Date.parse(record?.ts || "") || Date.now(),
|
|
8071
|
+
role: record?.role,
|
|
8072
|
+
content: String(record?.content || ""),
|
|
8073
|
+
kind: record?.kind || (record?.role === "system" ? "session_start" : "standard"),
|
|
8074
|
+
senderName: record?.senderName,
|
|
8075
|
+
agent: agentType,
|
|
8076
|
+
instanceId: record?.instanceId,
|
|
8077
|
+
historySessionId: normalizeSavedHistorySessionId(record?.historySessionId || normalizedSessionId),
|
|
8078
|
+
sessionTitle: record?.sessionTitle,
|
|
8079
|
+
workspace: record?.workspace
|
|
8080
|
+
})).filter(Boolean);
|
|
8081
|
+
}
|
|
8082
|
+
function callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, historySessionId, workspace) {
|
|
8083
|
+
const fn = getProviderNativeHistoryScript(scripts, canonicalHistory, "readSession");
|
|
8084
|
+
if (!fn) return null;
|
|
8085
|
+
const result = fn({
|
|
8086
|
+
agentType,
|
|
8087
|
+
sessionId: historySessionId,
|
|
8088
|
+
historySessionId,
|
|
8089
|
+
workspace,
|
|
8090
|
+
format: canonicalHistory?.format,
|
|
8091
|
+
watchPath: canonicalHistory?.watchPath,
|
|
8092
|
+
args: { sessionId: historySessionId, historySessionId, workspace }
|
|
8093
|
+
});
|
|
8094
|
+
if (!result || typeof result !== "object") return null;
|
|
8095
|
+
const records = normalizeProviderNativeHistoryRecords(agentType, historySessionId, result.messages || result.records);
|
|
8096
|
+
if (records.length === 0) return null;
|
|
8097
|
+
return {
|
|
8098
|
+
records,
|
|
8099
|
+
sourcePath: typeof result.sourcePath === "string" ? result.sourcePath : "",
|
|
8100
|
+
sourceMtimeMs: Number(result.sourceMtimeMs) || 0
|
|
8101
|
+
};
|
|
8102
|
+
}
|
|
8103
|
+
function buildNativeHistoryReadResult(agentType, canonicalHistory, scripts, historySessionId, workspace) {
|
|
8104
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || "");
|
|
8105
|
+
if (!canonicalHistory || !normalizedSessionId || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
|
|
8106
|
+
return callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace);
|
|
8107
|
+
}
|
|
8108
|
+
function materializeNativeHistoryToMirror(agentType, canonicalHistory, historySessionId, workspace, scripts) {
|
|
8054
8109
|
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8055
8110
|
if (!normalizedSessionId) return false;
|
|
8111
|
+
const nativeResult = callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace);
|
|
8112
|
+
const nativeRecords = nativeResult?.records || [];
|
|
8113
|
+
if (nativeRecords.length === 0) return false;
|
|
8114
|
+
const normalizedRecords = nativeRecords.map((record) => ({
|
|
8115
|
+
...record,
|
|
8116
|
+
agent: agentType,
|
|
8117
|
+
historySessionId: normalizedSessionId
|
|
8118
|
+
}));
|
|
8119
|
+
const existingSessionStart = readExistingSessionStartRecord(agentType, normalizedSessionId);
|
|
8120
|
+
const records = existingSessionStart && normalizedRecords[0]?.kind !== "session_start" ? [{ ...existingSessionStart, historySessionId: normalizedSessionId, agent: agentType }, ...normalizedRecords] : normalizedRecords;
|
|
8121
|
+
return rewriteCanonicalSavedHistory(agentType, normalizedSessionId, records);
|
|
8122
|
+
}
|
|
8123
|
+
function materializeProviderNativeHistory(agentType, canonicalHistory, historySessionId, workspace, scripts) {
|
|
8124
|
+
if (!canonicalHistory || canonicalHistory.mode !== "materialized-mirror") return false;
|
|
8125
|
+
return materializeNativeHistoryToMirror(agentType, canonicalHistory, historySessionId, workspace, scripts);
|
|
8126
|
+
}
|
|
8127
|
+
function isNativeSourceCanonicalHistory(canonicalHistory) {
|
|
8128
|
+
if (!canonicalHistory) return false;
|
|
8129
|
+
if (canonicalHistory.mode === "disabled") return false;
|
|
8130
|
+
if (canonicalHistory.mode === "materialized-mirror") return false;
|
|
8131
|
+
return true;
|
|
8132
|
+
}
|
|
8133
|
+
function readProviderChatHistory(agentType, options = {}) {
|
|
8134
|
+
if (isNativeSourceCanonicalHistory(options.canonicalHistory) && options.historySessionId) {
|
|
8135
|
+
const nativeResult = buildNativeHistoryReadResult(agentType, options.canonicalHistory, options.scripts, options.historySessionId, options.workspace);
|
|
8136
|
+
if (!nativeResult) return { messages: [], hasMore: false, source: "native-unavailable" };
|
|
8137
|
+
return {
|
|
8138
|
+
...pageHistoryRecords(agentType, nativeResult.records, options.offset || 0, options.limit || 30, options.excludeRecentCount || 0, options.historyBehavior),
|
|
8139
|
+
source: "provider-native",
|
|
8140
|
+
sourcePath: nativeResult.sourcePath,
|
|
8141
|
+
sourceMtimeMs: nativeResult.sourceMtimeMs
|
|
8142
|
+
};
|
|
8143
|
+
}
|
|
8144
|
+
return {
|
|
8145
|
+
...readChatHistory(agentType, options.offset || 0, options.limit || 30, options.historySessionId, options.excludeRecentCount || 0, options.historyBehavior),
|
|
8146
|
+
source: "adhdev-mirror"
|
|
8147
|
+
};
|
|
8148
|
+
}
|
|
8149
|
+
function buildNativeSessionSummary(agentType, historySessionId, records, sourcePath) {
|
|
8150
|
+
const visible = pageHistoryRecords(agentType, records, 0, Number.MAX_SAFE_INTEGER).messages;
|
|
8151
|
+
if (visible.length === 0) return null;
|
|
8152
|
+
let sourceMtimeMs = 0;
|
|
8056
8153
|
try {
|
|
8057
|
-
|
|
8058
|
-
if (!fs3.existsSync(sessionFilePath)) return false;
|
|
8059
|
-
const raw = JSON.parse(fs3.readFileSync(sessionFilePath, "utf-8"));
|
|
8060
|
-
const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
|
|
8061
|
-
const dir = path7.join(HISTORY_DIR, "hermes-cli");
|
|
8062
|
-
fs3.mkdirSync(dir, { recursive: true });
|
|
8063
|
-
const existingSessionStart = readExistingSessionStartRecord("hermes-cli", normalizedSessionId);
|
|
8064
|
-
const records = [];
|
|
8065
|
-
if (existingSessionStart) {
|
|
8066
|
-
records.push({
|
|
8067
|
-
...existingSessionStart,
|
|
8068
|
-
historySessionId: normalizedSessionId
|
|
8069
|
-
});
|
|
8070
|
-
}
|
|
8071
|
-
let fallbackTs = Date.parse(raw.session_start || raw.last_updated || "") || Date.now();
|
|
8072
|
-
for (const message of canonicalMessages) {
|
|
8073
|
-
const role = String(message.role || "").trim();
|
|
8074
|
-
const content = normalizeCanonicalHermesMessageContent(message.content);
|
|
8075
|
-
if (!content) continue;
|
|
8076
|
-
const receivedAt = extractCanonicalHermesMessageTimestamp(message, fallbackTs);
|
|
8077
|
-
fallbackTs = receivedAt + 1;
|
|
8078
|
-
if (role === "user") {
|
|
8079
|
-
records.push({
|
|
8080
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8081
|
-
receivedAt,
|
|
8082
|
-
role: "user",
|
|
8083
|
-
content,
|
|
8084
|
-
kind: "standard",
|
|
8085
|
-
agent: "hermes-cli",
|
|
8086
|
-
historySessionId: normalizedSessionId
|
|
8087
|
-
});
|
|
8088
|
-
continue;
|
|
8089
|
-
}
|
|
8090
|
-
if (role === "assistant") {
|
|
8091
|
-
records.push({
|
|
8092
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8093
|
-
receivedAt,
|
|
8094
|
-
role: "assistant",
|
|
8095
|
-
content,
|
|
8096
|
-
kind: "standard",
|
|
8097
|
-
agent: "hermes-cli",
|
|
8098
|
-
historySessionId: normalizedSessionId
|
|
8099
|
-
});
|
|
8100
|
-
continue;
|
|
8101
|
-
}
|
|
8102
|
-
if (role === "tool") {
|
|
8103
|
-
records.push({
|
|
8104
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8105
|
-
receivedAt,
|
|
8106
|
-
role: "assistant",
|
|
8107
|
-
content,
|
|
8108
|
-
kind: "tool",
|
|
8109
|
-
senderName: "Tool",
|
|
8110
|
-
agent: "hermes-cli",
|
|
8111
|
-
historySessionId: normalizedSessionId
|
|
8112
|
-
});
|
|
8113
|
-
}
|
|
8114
|
-
}
|
|
8115
|
-
return rewriteCanonicalSavedHistory("hermes-cli", normalizedSessionId, records);
|
|
8154
|
+
sourceMtimeMs = fs3.statSync(sourcePath).mtimeMs;
|
|
8116
8155
|
} catch {
|
|
8117
|
-
return false;
|
|
8118
8156
|
}
|
|
8157
|
+
const firstMessageAt = visible[0]?.receivedAt || sourceMtimeMs || Date.now();
|
|
8158
|
+
const lastMessageAt = visible[visible.length - 1]?.receivedAt || firstMessageAt;
|
|
8159
|
+
const lastNonSystem = [...visible].reverse().find((message) => message.role !== "system") || visible[visible.length - 1];
|
|
8160
|
+
const firstSystem = visible.find((message) => message.kind === "session_start");
|
|
8161
|
+
return {
|
|
8162
|
+
historySessionId,
|
|
8163
|
+
sessionTitle: lastNonSystem?.content,
|
|
8164
|
+
messageCount: visible.length,
|
|
8165
|
+
firstMessageAt,
|
|
8166
|
+
lastMessageAt,
|
|
8167
|
+
preview: lastNonSystem?.content,
|
|
8168
|
+
workspace: firstSystem?.workspace || (firstSystem?.kind === "session_start" ? firstSystem.content : void 0),
|
|
8169
|
+
source: "provider-native",
|
|
8170
|
+
sourcePath,
|
|
8171
|
+
sourceMtimeMs
|
|
8172
|
+
};
|
|
8119
8173
|
}
|
|
8120
|
-
function
|
|
8121
|
-
const
|
|
8122
|
-
if (!
|
|
8123
|
-
const
|
|
8124
|
-
|
|
8125
|
-
|
|
8126
|
-
|
|
8127
|
-
|
|
8128
|
-
|
|
8129
|
-
|
|
8130
|
-
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
}
|
|
8141
|
-
}
|
|
8142
|
-
}
|
|
8143
|
-
return null;
|
|
8174
|
+
function normalizeProviderNativeHistorySessionSummary(agentType, item) {
|
|
8175
|
+
const historySessionId = normalizeSavedHistorySessionId(item?.historySessionId || item?.sessionId || "");
|
|
8176
|
+
if (!historySessionId) return null;
|
|
8177
|
+
const sourcePath = typeof item?.sourcePath === "string" ? item.sourcePath : "";
|
|
8178
|
+
const sourceMtimeMs = Number(item?.sourceMtimeMs) || 0;
|
|
8179
|
+
const firstMessageAt = Number(item?.firstMessageAt) || sourceMtimeMs || Date.now();
|
|
8180
|
+
const lastMessageAt = Number(item?.lastMessageAt) || firstMessageAt;
|
|
8181
|
+
const messageCount = Math.max(0, Number(item?.messageCount) || 0);
|
|
8182
|
+
return {
|
|
8183
|
+
historySessionId,
|
|
8184
|
+
sessionTitle: typeof item?.sessionTitle === "string" ? item.sessionTitle : void 0,
|
|
8185
|
+
messageCount,
|
|
8186
|
+
firstMessageAt,
|
|
8187
|
+
lastMessageAt,
|
|
8188
|
+
preview: typeof item?.preview === "string" ? item.preview : void 0,
|
|
8189
|
+
workspace: typeof item?.workspace === "string" ? item.workspace : void 0,
|
|
8190
|
+
source: "provider-native",
|
|
8191
|
+
sourcePath,
|
|
8192
|
+
sourceMtimeMs
|
|
8193
|
+
};
|
|
8144
8194
|
}
|
|
8145
|
-
function
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8195
|
+
function collectProviderScriptNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) {
|
|
8196
|
+
const fn = getProviderNativeHistoryScript(scripts, canonicalHistory, "listSessions");
|
|
8197
|
+
if (!fn) return null;
|
|
8198
|
+
const result = fn({
|
|
8199
|
+
agentType,
|
|
8200
|
+
format: canonicalHistory.format,
|
|
8201
|
+
watchPath: canonicalHistory.watchPath,
|
|
8202
|
+
args: {}
|
|
8203
|
+
});
|
|
8204
|
+
if (!result || typeof result !== "object") return [];
|
|
8205
|
+
const sessions = Array.isArray(result.sessions) ? result.sessions : [];
|
|
8206
|
+
const summaries = [];
|
|
8207
|
+
for (const item of sessions) {
|
|
8208
|
+
if (Array.isArray(item?.messages || item?.records)) {
|
|
8209
|
+
const historySessionId = normalizeSavedHistorySessionId(item?.historySessionId || item?.sessionId || "");
|
|
8210
|
+
if (!historySessionId) continue;
|
|
8211
|
+
const records = normalizeProviderNativeHistoryRecords(agentType, historySessionId, item.messages || item.records);
|
|
8212
|
+
const summary2 = buildNativeSessionSummary(agentType, historySessionId, records, typeof item?.sourcePath === "string" ? item.sourcePath : "");
|
|
8213
|
+
if (summary2) {
|
|
8214
|
+
if (Number(item?.sourceMtimeMs)) summary2.sourceMtimeMs = Number(item.sourceMtimeMs);
|
|
8215
|
+
summaries.push(summary2);
|
|
8216
|
+
}
|
|
8159
8217
|
continue;
|
|
8160
8218
|
}
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
const input = record.input && typeof record.input === "object" ? record.input : null;
|
|
8164
|
-
const command = input ? String(input.command || "").trim() : "";
|
|
8165
|
-
const summary = command ? `${name}: ${command}` : name;
|
|
8166
|
-
if (summary) parts.push({ content: summary, kind: "tool", senderName: "Tool", role: "assistant" });
|
|
8167
|
-
}
|
|
8219
|
+
const summary = normalizeProviderNativeHistorySessionSummary(agentType, item);
|
|
8220
|
+
if (summary) summaries.push(summary);
|
|
8168
8221
|
}
|
|
8169
|
-
return
|
|
8222
|
+
return sortSavedHistorySessionSummaries(summaries);
|
|
8170
8223
|
}
|
|
8171
|
-
function
|
|
8172
|
-
|
|
8173
|
-
const trimmed = content.trim();
|
|
8174
|
-
return trimmed ? [{ role: "user", content: trimmed, kind: "standard" }] : [];
|
|
8175
|
-
}
|
|
8176
|
-
if (!Array.isArray(content)) return [];
|
|
8177
|
-
const parts = [];
|
|
8178
|
-
for (const block of content) {
|
|
8179
|
-
if (!block || typeof block !== "object") continue;
|
|
8180
|
-
const record = block;
|
|
8181
|
-
const type = String(record.type || "").trim();
|
|
8182
|
-
if (type === "text") {
|
|
8183
|
-
const text = String(record.text || "").trim();
|
|
8184
|
-
if (text) parts.push({ role: "user", content: text, kind: "standard" });
|
|
8185
|
-
continue;
|
|
8186
|
-
}
|
|
8187
|
-
if (type === "tool_result") {
|
|
8188
|
-
const rawContent = record.content;
|
|
8189
|
-
const text = typeof rawContent === "string" ? rawContent.trim() : Array.isArray(rawContent) ? rawContent.map((entry) => {
|
|
8190
|
-
if (typeof entry === "string") return entry.trim();
|
|
8191
|
-
if (!entry || typeof entry !== "object") return "";
|
|
8192
|
-
const nested = entry;
|
|
8193
|
-
if (typeof nested.text === "string") return nested.text.trim();
|
|
8194
|
-
if (typeof nested.content === "string") return nested.content.trim();
|
|
8195
|
-
return "";
|
|
8196
|
-
}).filter(Boolean).join("\n") : "";
|
|
8197
|
-
if (text) parts.push({ role: "assistant", content: text, kind: "tool", senderName: "Tool" });
|
|
8198
|
-
}
|
|
8199
|
-
}
|
|
8200
|
-
return parts;
|
|
8224
|
+
function collectNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) {
|
|
8225
|
+
return collectProviderScriptNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) || [];
|
|
8201
8226
|
}
|
|
8202
|
-
function
|
|
8203
|
-
|
|
8204
|
-
|
|
8205
|
-
|
|
8206
|
-
const
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
|
|
8210
|
-
|
|
8211
|
-
|
|
8212
|
-
records.push({
|
|
8213
|
-
...existingSessionStart,
|
|
8214
|
-
historySessionId: normalizedSessionId
|
|
8215
|
-
});
|
|
8216
|
-
}
|
|
8217
|
-
let fallbackTs = Date.now();
|
|
8218
|
-
for (const line of lines) {
|
|
8219
|
-
let parsed = null;
|
|
8220
|
-
try {
|
|
8221
|
-
parsed = JSON.parse(line);
|
|
8222
|
-
} catch {
|
|
8223
|
-
parsed = null;
|
|
8224
|
-
}
|
|
8225
|
-
if (!parsed) continue;
|
|
8226
|
-
const parsedSessionId = String(parsed.sessionId || "").trim();
|
|
8227
|
-
if (parsedSessionId && parsedSessionId !== normalizedSessionId) continue;
|
|
8228
|
-
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
8229
|
-
fallbackTs = receivedAt + 1;
|
|
8230
|
-
const parsedWorkspace = String(parsed.cwd || workspace || "").trim();
|
|
8231
|
-
if (records.length === 0 && parsedWorkspace) {
|
|
8232
|
-
records.push({
|
|
8233
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8234
|
-
receivedAt,
|
|
8235
|
-
role: "system",
|
|
8236
|
-
kind: "session_start",
|
|
8237
|
-
content: parsedWorkspace,
|
|
8238
|
-
agent: "claude-cli",
|
|
8239
|
-
historySessionId: normalizedSessionId,
|
|
8240
|
-
workspace: parsedWorkspace
|
|
8241
|
-
});
|
|
8242
|
-
}
|
|
8243
|
-
const type = String(parsed.type || "").trim();
|
|
8244
|
-
const message = parsed.message && typeof parsed.message === "object" ? parsed.message : null;
|
|
8245
|
-
if (type === "user" && message) {
|
|
8246
|
-
for (const part of extractClaudeUserContentParts(message.content)) {
|
|
8247
|
-
records.push({
|
|
8248
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8249
|
-
receivedAt,
|
|
8250
|
-
role: part.role,
|
|
8251
|
-
content: part.content,
|
|
8252
|
-
kind: part.kind,
|
|
8253
|
-
senderName: part.senderName,
|
|
8254
|
-
agent: "claude-cli",
|
|
8255
|
-
historySessionId: normalizedSessionId
|
|
8256
|
-
});
|
|
8257
|
-
}
|
|
8258
|
-
continue;
|
|
8259
|
-
}
|
|
8260
|
-
if (type === "assistant" && message) {
|
|
8261
|
-
for (const part of extractClaudeAssistantContentParts(message.content)) {
|
|
8262
|
-
records.push({
|
|
8263
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8264
|
-
receivedAt,
|
|
8265
|
-
role: "assistant",
|
|
8266
|
-
content: part.content,
|
|
8267
|
-
kind: part.kind,
|
|
8268
|
-
senderName: part.senderName,
|
|
8269
|
-
agent: "claude-cli",
|
|
8270
|
-
historySessionId: normalizedSessionId
|
|
8271
|
-
});
|
|
8272
|
-
}
|
|
8273
|
-
}
|
|
8274
|
-
}
|
|
8275
|
-
return rewriteCanonicalSavedHistory("claude-cli", normalizedSessionId, records);
|
|
8276
|
-
} catch {
|
|
8277
|
-
return false;
|
|
8227
|
+
function listProviderHistorySessions(agentType, options = {}) {
|
|
8228
|
+
if (isNativeSourceCanonicalHistory(options.canonicalHistory)) {
|
|
8229
|
+
const offset = Math.max(0, options.offset || 0);
|
|
8230
|
+
const limit = Math.max(1, options.limit || 30);
|
|
8231
|
+
const summaries = collectNativeHistorySessionSummaries(agentType, options.canonicalHistory, options.scripts);
|
|
8232
|
+
return {
|
|
8233
|
+
sessions: summaries.slice(offset, offset + limit),
|
|
8234
|
+
hasMore: offset + limit < summaries.length,
|
|
8235
|
+
source: "provider-native"
|
|
8236
|
+
};
|
|
8278
8237
|
}
|
|
8238
|
+
return {
|
|
8239
|
+
...listSavedHistorySessions(agentType, { offset: options.offset, limit: options.limit }, options.historyBehavior),
|
|
8240
|
+
source: "adhdev-mirror"
|
|
8241
|
+
};
|
|
8279
8242
|
}
|
|
8280
8243
|
|
|
8281
8244
|
// src/providers/provider-patch-state.ts
|
|
@@ -10890,7 +10853,17 @@ async function handleChatHistory(h, args) {
|
|
|
10890
10853
|
const visibleCount = Array.isArray(status?.messages) ? status.messages.length : 0;
|
|
10891
10854
|
if (visibleCount > excludeRecentCount) excludeRecentCount = visibleCount;
|
|
10892
10855
|
}
|
|
10893
|
-
const
|
|
10856
|
+
const workspace = typeof args?.workspace === "string" ? args.workspace : typeof h.currentSession?.workspace === "string" ? h.currentSession.workspace : void 0;
|
|
10857
|
+
const result = readProviderChatHistory(agentStr, {
|
|
10858
|
+
canonicalHistory: provider?.canonicalHistory,
|
|
10859
|
+
historySessionId,
|
|
10860
|
+
workspace,
|
|
10861
|
+
offset: offset || 0,
|
|
10862
|
+
limit: limit || 30,
|
|
10863
|
+
excludeRecentCount,
|
|
10864
|
+
historyBehavior: provider?.historyBehavior,
|
|
10865
|
+
scripts: provider?.scripts
|
|
10866
|
+
});
|
|
10894
10867
|
return { success: true, ...result, agent: agentStr };
|
|
10895
10868
|
} catch (e) {
|
|
10896
10869
|
return { success: false, error: e.message };
|
|
@@ -10915,7 +10888,8 @@ async function handleReadChat(h, args) {
|
|
|
10915
10888
|
}
|
|
10916
10889
|
const parsedRecord = parsedStatus && typeof parsedStatus === "object" ? parsedStatus : null;
|
|
10917
10890
|
const adapterStatus = adapter.getStatus();
|
|
10918
|
-
const
|
|
10891
|
+
const parsedIsProviderAuthoritative = parsedRecord?.transcriptAuthority === "provider" || parsedRecord?.coverage === "full";
|
|
10892
|
+
const shouldPreferAdapterMessages = !parsedIsProviderAuthoritative && Array.isArray(adapterStatus.messages) && adapterStatus.messages.length > 0 && Array.isArray(parsedRecord?.messages) && adapterStatus.messages.length > parsedRecord.messages.length;
|
|
10919
10893
|
const parsedShowsApproval = hasNonEmptyModalButtons(parsedRecord?.activeModal) && parsedRecord?.status === "waiting_approval";
|
|
10920
10894
|
const status = parsedRecord ? {
|
|
10921
10895
|
...parsedRecord,
|
|
@@ -10925,6 +10899,8 @@ async function handleReadChat(h, args) {
|
|
|
10925
10899
|
} : adapterStatus;
|
|
10926
10900
|
const title = typeof parsedRecord?.title === "string" ? parsedRecord.title : void 0;
|
|
10927
10901
|
const providerSessionId = typeof parsedRecord?.providerSessionId === "string" ? parsedRecord.providerSessionId : void 0;
|
|
10902
|
+
const transcriptAuthority = parsedRecord?.transcriptAuthority === "provider" || parsedRecord?.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
|
|
10903
|
+
const coverage = parsedRecord?.coverage === "full" || parsedRecord?.coverage === "tail" || parsedRecord?.coverage === "current-turn" ? parsedRecord.coverage : void 0;
|
|
10928
10904
|
if (status) {
|
|
10929
10905
|
LOG.debug("Command", `[read_chat] cli-like resolved provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord?.status || "")} shouldPreferAdapterMessages=${String(shouldPreferAdapterMessages)} adapterMsgCount=${Array.isArray(adapterStatus.messages) ? adapterStatus.messages.length : 0} parsedMsgCount=${Array.isArray(parsedRecord?.messages) ? parsedRecord.messages.length : 0} returnedMsgCount=${Array.isArray(status.messages) ? status.messages.length : 0}`);
|
|
10930
10906
|
return buildReadChatCommandResult({
|
|
@@ -10943,7 +10919,9 @@ async function handleReadChat(h, args) {
|
|
|
10943
10919
|
returnedMsgCount: Array.isArray(status.messages) ? status.messages.length : 0
|
|
10944
10920
|
},
|
|
10945
10921
|
...title ? { title } : {},
|
|
10946
|
-
...providerSessionId ? { providerSessionId } : {}
|
|
10922
|
+
...providerSessionId ? { providerSessionId } : {},
|
|
10923
|
+
...transcriptAuthority ? { transcriptAuthority } : {},
|
|
10924
|
+
...coverage ? { coverage } : {}
|
|
10947
10925
|
}, args);
|
|
10948
10926
|
}
|
|
10949
10927
|
}
|
|
@@ -13358,11 +13336,8 @@ var CliProviderInstance = class {
|
|
|
13358
13336
|
historyWriter;
|
|
13359
13337
|
runtimeMessages = [];
|
|
13360
13338
|
lastPersistedHistoryMessages = [];
|
|
13361
|
-
|
|
13362
|
-
|
|
13363
|
-
lastCanonicalHermesWatchPath = void 0;
|
|
13364
|
-
lastCanonicalClaudeRebuildMtimeMs = 0;
|
|
13365
|
-
lastCanonicalClaudeCheckAt = 0;
|
|
13339
|
+
lastNativeSourceCanonicalCheckAt = 0;
|
|
13340
|
+
lastNativeSourceCanonicalCacheKey = void 0;
|
|
13366
13341
|
cachedSqliteDb = null;
|
|
13367
13342
|
cachedSqliteDbPath = null;
|
|
13368
13343
|
cachedSqliteDbMissingUntil = 0;
|
|
@@ -14062,41 +14037,45 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14062
14037
|
if (!this.providerSessionId) return false;
|
|
14063
14038
|
const canonicalHistory = this.provider.canonicalHistory;
|
|
14064
14039
|
if (!canonicalHistory) return false;
|
|
14040
|
+
if (isNativeSourceCanonicalHistory(canonicalHistory)) {
|
|
14041
|
+
const cacheKey = [this.type, this.providerSessionId, this.workingDir].join("\0");
|
|
14042
|
+
const now = Date.now();
|
|
14043
|
+
if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
|
|
14044
|
+
return true;
|
|
14045
|
+
}
|
|
14046
|
+
this.lastNativeSourceCanonicalCacheKey = cacheKey;
|
|
14047
|
+
this.lastNativeSourceCanonicalCheckAt = now;
|
|
14048
|
+
const restoredHistory = readProviderChatHistory(this.type, {
|
|
14049
|
+
canonicalHistory,
|
|
14050
|
+
historySessionId: this.providerSessionId,
|
|
14051
|
+
workspace: this.workingDir,
|
|
14052
|
+
offset: 0,
|
|
14053
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
14054
|
+
historyBehavior: this.provider.historyBehavior,
|
|
14055
|
+
scripts: this.provider.scripts
|
|
14056
|
+
});
|
|
14057
|
+
if (restoredHistory.source === "provider-native") {
|
|
14058
|
+
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
14059
|
+
role: message.role,
|
|
14060
|
+
content: message.content,
|
|
14061
|
+
kind: message.kind,
|
|
14062
|
+
senderName: message.senderName,
|
|
14063
|
+
receivedAt: message.receivedAt
|
|
14064
|
+
}));
|
|
14065
|
+
}
|
|
14066
|
+
return true;
|
|
14067
|
+
}
|
|
14065
14068
|
try {
|
|
14066
|
-
|
|
14067
|
-
|
|
14068
|
-
|
|
14069
|
-
|
|
14070
|
-
|
|
14071
|
-
|
|
14072
|
-
|
|
14073
|
-
|
|
14074
|
-
|
|
14075
|
-
if (!fs5.existsSync(watchPath)) return false;
|
|
14076
|
-
}
|
|
14077
|
-
const stat = fs5.statSync(watchPath);
|
|
14078
|
-
if (stat.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
|
|
14079
|
-
rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
|
|
14080
|
-
if (rebuilt) this.lastCanonicalHermesSyncMtimeMs = stat.mtimeMs;
|
|
14081
|
-
} else if (canonicalHistory.format === "claude-jsonl") {
|
|
14082
|
-
const now = Date.now();
|
|
14083
|
-
if (now - this.lastCanonicalClaudeCheckAt < 2e3 && this.lastCanonicalClaudeRebuildMtimeMs !== 0) {
|
|
14084
|
-
return true;
|
|
14085
|
-
}
|
|
14086
|
-
this.lastCanonicalClaudeCheckAt = now;
|
|
14087
|
-
const claudeProjectsDir = path11.join(os11.homedir(), ".claude", "projects");
|
|
14088
|
-
const workspaceSegment = typeof this.workingDir === "string" ? this.workingDir.replace(/[\\/]/g, "-").replace(/^-+/, "") : "";
|
|
14089
|
-
const transcriptFile = path11.join(claudeProjectsDir, workspaceSegment, `${this.providerSessionId}.jsonl`);
|
|
14090
|
-
let transcriptMtime = 0;
|
|
14091
|
-
try {
|
|
14092
|
-
transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
|
|
14093
|
-
} catch {
|
|
14094
|
-
}
|
|
14095
|
-
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalClaudeRebuildMtimeMs) return true;
|
|
14096
|
-
rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
|
|
14097
|
-
if (rebuilt) this.lastCanonicalClaudeRebuildMtimeMs = transcriptMtime || Date.now();
|
|
14069
|
+
const cacheKey = [this.type, this.providerSessionId, this.workingDir, canonicalHistory.mode || "materialized-mirror"].join("\0");
|
|
14070
|
+
const now = Date.now();
|
|
14071
|
+
if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
|
|
14072
|
+
return true;
|
|
14073
|
+
}
|
|
14074
|
+
this.lastNativeSourceCanonicalCacheKey = cacheKey;
|
|
14075
|
+
this.lastNativeSourceCanonicalCheckAt = now;
|
|
14076
|
+
if (!materializeProviderNativeHistory(this.type, canonicalHistory, this.providerSessionId, this.workingDir, this.provider.scripts)) {
|
|
14077
|
+
return false;
|
|
14098
14078
|
}
|
|
14099
|
-
if (!rebuilt) return false;
|
|
14100
14079
|
const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
14101
14080
|
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
14102
14081
|
role: message.role,
|
|
@@ -14113,8 +14092,18 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14113
14092
|
restorePersistedHistoryFromCurrentSession() {
|
|
14114
14093
|
if (!this.providerSessionId) return;
|
|
14115
14094
|
this.syncCanonicalSavedHistoryIfNeeded();
|
|
14116
|
-
this.
|
|
14117
|
-
|
|
14095
|
+
const restoredHistory = isNativeSourceCanonicalHistory(this.provider.canonicalHistory) ? readProviderChatHistory(this.type, {
|
|
14096
|
+
canonicalHistory: this.provider.canonicalHistory,
|
|
14097
|
+
historySessionId: this.providerSessionId,
|
|
14098
|
+
workspace: this.workingDir,
|
|
14099
|
+
offset: 0,
|
|
14100
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
14101
|
+
historyBehavior: this.provider.historyBehavior,
|
|
14102
|
+
scripts: this.provider.scripts
|
|
14103
|
+
}) : (() => {
|
|
14104
|
+
this.historyWriter.compactHistorySession(this.type, this.providerSessionId, this.provider.historyBehavior);
|
|
14105
|
+
return readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
14106
|
+
})();
|
|
14118
14107
|
this.historyWriter.seedSessionHistory(
|
|
14119
14108
|
this.type,
|
|
14120
14109
|
restoredHistory.messages,
|
|
@@ -16250,6 +16239,7 @@ function validateProviderDefinition(raw) {
|
|
|
16250
16239
|
warnings.push("Extension providers should have extensionId");
|
|
16251
16240
|
}
|
|
16252
16241
|
validateCapabilities(provider, controls, errors);
|
|
16242
|
+
validateCanonicalHistory(provider.canonicalHistory, errors);
|
|
16253
16243
|
for (const control of controls) {
|
|
16254
16244
|
validateControl(control, errors);
|
|
16255
16245
|
}
|
|
@@ -16307,6 +16297,39 @@ function validateCapabilities(provider, controls, errors) {
|
|
|
16307
16297
|
errors.push("providers declaring controls must set capabilities.controls.typedResults=true");
|
|
16308
16298
|
}
|
|
16309
16299
|
}
|
|
16300
|
+
function validateCanonicalHistory(raw, errors) {
|
|
16301
|
+
if (raw === void 0) return;
|
|
16302
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
16303
|
+
errors.push("canonicalHistory must be an object");
|
|
16304
|
+
return;
|
|
16305
|
+
}
|
|
16306
|
+
const canonicalHistory = raw;
|
|
16307
|
+
const format = canonicalHistory.format;
|
|
16308
|
+
if (format !== void 0 && (typeof format !== "string" || !format.trim())) {
|
|
16309
|
+
errors.push("canonicalHistory.format must be a non-empty string when provided");
|
|
16310
|
+
}
|
|
16311
|
+
const watchPath = canonicalHistory.watchPath;
|
|
16312
|
+
if (watchPath !== void 0 && (typeof watchPath !== "string" || !watchPath.trim())) {
|
|
16313
|
+
errors.push("canonicalHistory.watchPath must be a non-empty string when provided");
|
|
16314
|
+
}
|
|
16315
|
+
const mode = canonicalHistory.mode;
|
|
16316
|
+
if (mode !== void 0 && !["native-source", "materialized-mirror", "disabled"].includes(String(mode))) {
|
|
16317
|
+
errors.push("canonicalHistory.mode must be one of: native-source, materialized-mirror, disabled");
|
|
16318
|
+
}
|
|
16319
|
+
const scripts = canonicalHistory.scripts;
|
|
16320
|
+
if (scripts === void 0) return;
|
|
16321
|
+
if (!scripts || typeof scripts !== "object" || Array.isArray(scripts)) {
|
|
16322
|
+
errors.push("canonicalHistory.scripts must be an object");
|
|
16323
|
+
return;
|
|
16324
|
+
}
|
|
16325
|
+
const scriptConfig = scripts;
|
|
16326
|
+
for (const key of ["readSession", "listSessions"]) {
|
|
16327
|
+
const value = scriptConfig[key];
|
|
16328
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
16329
|
+
errors.push(`canonicalHistory.scripts.${key} must be a non-empty string`);
|
|
16330
|
+
}
|
|
16331
|
+
}
|
|
16332
|
+
}
|
|
16310
16333
|
function validateControl(control, errors) {
|
|
16311
16334
|
if (!control || typeof control !== "object") {
|
|
16312
16335
|
errors.push("controls: each control must be an object");
|
|
@@ -17849,6 +17872,38 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17849
17872
|
}
|
|
17850
17873
|
};
|
|
17851
17874
|
|
|
17875
|
+
// src/launch/macos-app-process.ts
|
|
17876
|
+
function normalizeMacAppPath(appPath) {
|
|
17877
|
+
const trimmed = String(appPath || "").trim();
|
|
17878
|
+
if (!trimmed) return null;
|
|
17879
|
+
return trimmed.replace(/\/+$/, "");
|
|
17880
|
+
}
|
|
17881
|
+
function parsePsLine(line) {
|
|
17882
|
+
const match = line.match(/^\s*(\d+)\s+(.+)$/);
|
|
17883
|
+
if (!match) return null;
|
|
17884
|
+
const pid = Number.parseInt(match[1], 10);
|
|
17885
|
+
if (!Number.isFinite(pid)) return null;
|
|
17886
|
+
return { pid, args: match[2] };
|
|
17887
|
+
}
|
|
17888
|
+
function isMacAppProcessArgs(args, appPath) {
|
|
17889
|
+
const normalized = normalizeMacAppPath(appPath);
|
|
17890
|
+
if (!normalized) return false;
|
|
17891
|
+
return String(args || "").startsWith(`${normalized}/`);
|
|
17892
|
+
}
|
|
17893
|
+
function findMacAppProcessPids(psOutput, appPaths) {
|
|
17894
|
+
const normalizedPaths = appPaths.map(normalizeMacAppPath).filter((value) => !!value);
|
|
17895
|
+
if (normalizedPaths.length === 0) return [];
|
|
17896
|
+
const pids = [];
|
|
17897
|
+
for (const line of String(psOutput || "").split(/\r?\n/)) {
|
|
17898
|
+
const parsed = parsePsLine(line);
|
|
17899
|
+
if (!parsed) continue;
|
|
17900
|
+
if (normalizedPaths.some((appPath) => isMacAppProcessArgs(parsed.args, appPath))) {
|
|
17901
|
+
pids.push(parsed.pid);
|
|
17902
|
+
}
|
|
17903
|
+
}
|
|
17904
|
+
return pids;
|
|
17905
|
+
}
|
|
17906
|
+
|
|
17852
17907
|
// src/launch.ts
|
|
17853
17908
|
var _providerLoader = null;
|
|
17854
17909
|
function getProviderLoader() {
|
|
@@ -17885,6 +17940,35 @@ function getCdpStartupTimeoutMs(ideId) {
|
|
|
17885
17940
|
function escapeForAppleScript(value) {
|
|
17886
17941
|
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
17887
17942
|
}
|
|
17943
|
+
function getIdePathCandidates(ideId) {
|
|
17944
|
+
return getProviderLoader().getIdePathCandidates(ideId);
|
|
17945
|
+
}
|
|
17946
|
+
function getMacAppProcessPids(ideId) {
|
|
17947
|
+
const appPaths = getIdePathCandidates(ideId);
|
|
17948
|
+
if (appPaths.length === 0) return [];
|
|
17949
|
+
try {
|
|
17950
|
+
const output = execSync4("ps axww -o pid=,args=", {
|
|
17951
|
+
encoding: "utf-8",
|
|
17952
|
+
timeout: 3e3,
|
|
17953
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
17954
|
+
});
|
|
17955
|
+
return findMacAppProcessPids(output, appPaths);
|
|
17956
|
+
} catch {
|
|
17957
|
+
return [];
|
|
17958
|
+
}
|
|
17959
|
+
}
|
|
17960
|
+
function killMacAppPathProcesses(ideId, signal) {
|
|
17961
|
+
const pids = getMacAppProcessPids(ideId);
|
|
17962
|
+
let signalled = false;
|
|
17963
|
+
for (const pid of pids) {
|
|
17964
|
+
try {
|
|
17965
|
+
process.kill(pid, signal);
|
|
17966
|
+
signalled = true;
|
|
17967
|
+
} catch {
|
|
17968
|
+
}
|
|
17969
|
+
}
|
|
17970
|
+
return signalled;
|
|
17971
|
+
}
|
|
17888
17972
|
async function findFreePort(ports) {
|
|
17889
17973
|
for (const port2 of ports) {
|
|
17890
17974
|
const free = await checkPortFree(port2);
|
|
@@ -17946,6 +18030,7 @@ async function killIdeProcess(ideId) {
|
|
|
17946
18030
|
} catch {
|
|
17947
18031
|
}
|
|
17948
18032
|
}
|
|
18033
|
+
killMacAppPathProcesses(ideId, "SIGTERM");
|
|
17949
18034
|
} else if (plat === "win32" && winProcesses) {
|
|
17950
18035
|
for (const proc of winProcesses) {
|
|
17951
18036
|
try {
|
|
@@ -17975,6 +18060,7 @@ async function killIdeProcess(ideId) {
|
|
|
17975
18060
|
execSync4(`pkill -9 -x "${appName}" 2>/dev/null`, { timeout: 5e3 });
|
|
17976
18061
|
} catch {
|
|
17977
18062
|
}
|
|
18063
|
+
killMacAppPathProcesses(ideId, "SIGKILL");
|
|
17978
18064
|
} else if (plat === "win32" && winProcesses) {
|
|
17979
18065
|
for (const proc of winProcesses) {
|
|
17980
18066
|
try {
|
|
@@ -17994,14 +18080,16 @@ function isIdeRunning(ideId) {
|
|
|
17994
18080
|
try {
|
|
17995
18081
|
if (plat === "darwin") {
|
|
17996
18082
|
const appName = getMacAppIdentifiers()[ideId];
|
|
17997
|
-
if (!appName) return
|
|
18083
|
+
if (!appName) return getMacAppProcessPids(ideId).length > 0;
|
|
17998
18084
|
try {
|
|
17999
18085
|
const result = execSync4(`pgrep -x "${appName}" 2>/dev/null`, {
|
|
18000
18086
|
encoding: "utf-8",
|
|
18001
18087
|
timeout: 3e3
|
|
18002
18088
|
});
|
|
18003
|
-
|
|
18089
|
+
if (result.trim().length > 0) return true;
|
|
18004
18090
|
} catch {
|
|
18091
|
+
}
|
|
18092
|
+
try {
|
|
18005
18093
|
const result = execSync4(
|
|
18006
18094
|
`osascript -e 'tell application "System Events" to count (every process whose name is "${escapeForAppleScript(appName)}")'`,
|
|
18007
18095
|
{
|
|
@@ -18010,8 +18098,10 @@ function isIdeRunning(ideId) {
|
|
|
18010
18098
|
stdio: ["pipe", "pipe", "pipe"]
|
|
18011
18099
|
}
|
|
18012
18100
|
);
|
|
18013
|
-
|
|
18101
|
+
if (Number.parseInt(result.trim() || "0", 10) > 0) return true;
|
|
18102
|
+
} catch {
|
|
18014
18103
|
}
|
|
18104
|
+
return getMacAppProcessPids(ideId).length > 0;
|
|
18015
18105
|
} else if (plat === "win32") {
|
|
18016
18106
|
const winProcesses = getWinProcessNames()[ideId];
|
|
18017
18107
|
if (!winProcesses) return false;
|
|
@@ -19378,13 +19468,19 @@ var DaemonCommandRouter = class {
|
|
|
19378
19468
|
const wantsAll = args?.all === true;
|
|
19379
19469
|
const offset = wantsAll ? 0 : Math.max(0, Number(args?.offset) || 0);
|
|
19380
19470
|
const limit = wantsAll ? Number.MAX_SAFE_INTEGER : Math.max(1, Math.min(100, Number(args?.limit) || 30));
|
|
19381
|
-
const
|
|
19471
|
+
const providerMeta = this.deps.providerLoader.getMeta(providerType);
|
|
19472
|
+
const { sessions: historySessions, hasMore, source } = listProviderHistorySessions(providerType, {
|
|
19473
|
+
canonicalHistory: providerMeta?.canonicalHistory,
|
|
19474
|
+
offset,
|
|
19475
|
+
limit,
|
|
19476
|
+
historyBehavior: providerMeta?.historyBehavior,
|
|
19477
|
+
scripts: providerMeta?.scripts
|
|
19478
|
+
});
|
|
19382
19479
|
const state = loadState();
|
|
19383
19480
|
const savedSessions = getSavedProviderSessions(state, { providerType, kind });
|
|
19384
19481
|
const recentSessions = getRecentActivity(state, 200).filter((entry) => entry.providerType === providerType && entry.kind === kind && entry.providerSessionId);
|
|
19385
19482
|
const savedSessionById = new Map(savedSessions.map((entry) => [entry.providerSessionId, entry]));
|
|
19386
19483
|
const recentSessionById = new Map(recentSessions.map((entry) => [entry.providerSessionId, entry]));
|
|
19387
|
-
const providerMeta = this.deps.providerLoader.getMeta(providerType);
|
|
19388
19484
|
const canResumeById = supportsExplicitSessionResume(providerMeta?.resume);
|
|
19389
19485
|
return {
|
|
19390
19486
|
success: true,
|
|
@@ -19404,10 +19500,14 @@ var DaemonCommandRouter = class {
|
|
|
19404
19500
|
messageCount: session.messageCount,
|
|
19405
19501
|
firstMessageAt: session.firstMessageAt,
|
|
19406
19502
|
lastMessageAt: session.lastMessageAt,
|
|
19407
|
-
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById
|
|
19503
|
+
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById,
|
|
19504
|
+
historySource: session.source,
|
|
19505
|
+
sourcePath: session.sourcePath,
|
|
19506
|
+
sourceMtimeMs: session.sourceMtimeMs
|
|
19408
19507
|
};
|
|
19409
19508
|
}),
|
|
19410
|
-
hasMore
|
|
19509
|
+
hasMore,
|
|
19510
|
+
source
|
|
19411
19511
|
};
|
|
19412
19512
|
}
|
|
19413
19513
|
// ─── restart_session: IDE / CLI / ACP unified ───
|