@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.js
CHANGED
|
@@ -985,6 +985,8 @@ function validateReadChatResultPayload(raw, source = "read_chat") {
|
|
|
985
985
|
if (raw.summaryMetadata !== void 0) normalized.summaryMetadata = raw.summaryMetadata;
|
|
986
986
|
if (Array.isArray(raw.effects)) normalized.effects = raw.effects;
|
|
987
987
|
if (typeof raw.providerSessionId === "string") normalized.providerSessionId = raw.providerSessionId;
|
|
988
|
+
if (raw.transcriptAuthority === "provider" || raw.transcriptAuthority === "daemon") normalized.transcriptAuthority = raw.transcriptAuthority;
|
|
989
|
+
if (raw.coverage === "full" || raw.coverage === "tail" || raw.coverage === "current-turn") normalized.coverage = raw.coverage;
|
|
988
990
|
return normalized;
|
|
989
991
|
}
|
|
990
992
|
var VALID_STATUSES, VALID_ROLES, VALID_BUBBLE_STATES, VALID_TURN_STATUSES;
|
|
@@ -2059,7 +2061,8 @@ __export(provider_cli_adapter_exports, {
|
|
|
2059
2061
|
ProviderCliAdapter: () => ProviderCliAdapter,
|
|
2060
2062
|
appendBoundedText: () => appendBoundedText,
|
|
2061
2063
|
normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime,
|
|
2062
|
-
sanitizeCliStandardMessageContent: () => sanitizeCliStandardMessageContent
|
|
2064
|
+
sanitizeCliStandardMessageContent: () => sanitizeCliStandardMessageContent,
|
|
2065
|
+
trimLastAssistantEchoForCliMessages: () => trimLastAssistantEchoForCliMessages
|
|
2063
2066
|
});
|
|
2064
2067
|
function normalizeComparableTranscriptText(value) {
|
|
2065
2068
|
return sanitizeTerminalText(String(value || "")).replace(/\s+/g, " ").trim();
|
|
@@ -2155,6 +2158,19 @@ function sanitizeCommittedMessageForDisplay(message) {
|
|
|
2155
2158
|
if (content === message.content) return message;
|
|
2156
2159
|
return { ...message, content };
|
|
2157
2160
|
}
|
|
2161
|
+
function trimLastAssistantEchoForCliMessages(messages, prompt) {
|
|
2162
|
+
if (!prompt) return;
|
|
2163
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
2164
|
+
const message = messages[index];
|
|
2165
|
+
if (!message || message.role !== "assistant" || typeof message.content !== "string") continue;
|
|
2166
|
+
if ((message.kind || "standard") !== "standard") continue;
|
|
2167
|
+
message.content = trimPromptEchoPrefix(message.content, prompt);
|
|
2168
|
+
if (!message.content.trim()) {
|
|
2169
|
+
messages.splice(index, 1);
|
|
2170
|
+
}
|
|
2171
|
+
return;
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2158
2174
|
var os10, COMMITTED_ACTIVITY_PREFIX_BLOCK_RE, ProviderCliAdapter;
|
|
2159
2175
|
var init_provider_cli_adapter = __esm({
|
|
2160
2176
|
"src/cli-adapters/provider-cli-adapter.ts"() {
|
|
@@ -2352,7 +2368,14 @@ var init_provider_cli_adapter = __esm({
|
|
|
2352
2368
|
}
|
|
2353
2369
|
return null;
|
|
2354
2370
|
}
|
|
2371
|
+
providerOwnsTranscript() {
|
|
2372
|
+
return this.provider.transcriptAuthority === "provider";
|
|
2373
|
+
}
|
|
2374
|
+
shouldUseFullProviderTranscriptContext() {
|
|
2375
|
+
return this.providerOwnsTranscript() && this.provider.transcriptContext === "full";
|
|
2376
|
+
}
|
|
2355
2377
|
selectParseBaseMessages(baseMessages) {
|
|
2378
|
+
if (this.shouldUseFullProviderTranscriptContext()) return baseMessages;
|
|
2356
2379
|
if (baseMessages.length <= _ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT) return baseMessages;
|
|
2357
2380
|
return baseMessages.slice(-_ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT);
|
|
2358
2381
|
}
|
|
@@ -2835,9 +2858,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
2835
2858
|
);
|
|
2836
2859
|
}
|
|
2837
2860
|
trimLastAssistantEcho(messages, prompt) {
|
|
2838
|
-
|
|
2839
|
-
const last = [...messages].reverse().find((m) => m.role === "assistant" && typeof m.content === "string");
|
|
2840
|
-
if (last) last.content = trimPromptEchoPrefix(last.content, prompt);
|
|
2861
|
+
trimLastAssistantEchoForCliMessages(messages, prompt);
|
|
2841
2862
|
}
|
|
2842
2863
|
clearAllTimers() {
|
|
2843
2864
|
if (this.responseTimeout) {
|
|
@@ -3691,7 +3712,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
3691
3712
|
title: parsed.title || this.cliName,
|
|
3692
3713
|
messages: hydratedMessages,
|
|
3693
3714
|
activeModal: parsed.activeModal ?? this.activeModal,
|
|
3694
|
-
providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0
|
|
3715
|
+
providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0,
|
|
3716
|
+
...this.providerOwnsTranscript() ? { transcriptAuthority: "provider", coverage: this.shouldUseFullProviderTranscriptContext() ? "full" : "tail" } : {}
|
|
3695
3717
|
};
|
|
3696
3718
|
} else {
|
|
3697
3719
|
const messages = [...this.committedMessages];
|
|
@@ -8025,6 +8047,27 @@ var ChatHistoryWriter = class {
|
|
|
8025
8047
|
return name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8026
8048
|
}
|
|
8027
8049
|
};
|
|
8050
|
+
function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeRecentCount = 0, historyBehavior) {
|
|
8051
|
+
const allMessages = records.map((message) => sanitizeHistoryMessage(agentType, message)).filter(Boolean);
|
|
8052
|
+
allMessages.sort((a, b) => a.receivedAt - b.receivedAt);
|
|
8053
|
+
const chronological = [];
|
|
8054
|
+
let lastTurn = null;
|
|
8055
|
+
for (const message of allMessages) {
|
|
8056
|
+
const previous = chronological[chronological.length - 1];
|
|
8057
|
+
if (isAdjacentHistoryDuplicate(agentType, previous, message)) continue;
|
|
8058
|
+
if (message.role !== "system" && isAdjacentHistoryDuplicate(agentType, lastTurn, message)) continue;
|
|
8059
|
+
chronological.push(message);
|
|
8060
|
+
if (message.role !== "system") lastTurn = message;
|
|
8061
|
+
}
|
|
8062
|
+
const collapsed = collapseReplayAssistantTurns(chronological, historyBehavior);
|
|
8063
|
+
const boundedLimit = Math.max(1, limit);
|
|
8064
|
+
const boundedOffset = Math.max(0, offset);
|
|
8065
|
+
const boundedExclude = Math.max(0, Math.min(excludeRecentCount, collapsed.length));
|
|
8066
|
+
const endExclusive = Math.max(0, collapsed.length - boundedExclude - boundedOffset);
|
|
8067
|
+
const startInclusive = Math.max(0, endExclusive - boundedLimit);
|
|
8068
|
+
const sliced = collapsed.slice(startInclusive, endExclusive);
|
|
8069
|
+
return { messages: sliced, hasMore: startInclusive > 0 };
|
|
8070
|
+
}
|
|
8028
8071
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
8029
8072
|
try {
|
|
8030
8073
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
@@ -8050,25 +8093,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
8050
8093
|
}
|
|
8051
8094
|
}
|
|
8052
8095
|
}
|
|
8053
|
-
|
|
8054
|
-
const chronological = [];
|
|
8055
|
-
let lastTurn = null;
|
|
8056
|
-
for (const message of allMessages) {
|
|
8057
|
-
const previous = chronological[chronological.length - 1];
|
|
8058
|
-
if (isAdjacentHistoryDuplicate(agentType, previous, message)) continue;
|
|
8059
|
-
if (message.role !== "system" && isAdjacentHistoryDuplicate(agentType, lastTurn, message)) continue;
|
|
8060
|
-
chronological.push(message);
|
|
8061
|
-
if (message.role !== "system") lastTurn = message;
|
|
8062
|
-
}
|
|
8063
|
-
const collapsed = collapseReplayAssistantTurns(chronological, historyBehavior);
|
|
8064
|
-
const boundedLimit = Math.max(1, limit);
|
|
8065
|
-
const boundedOffset = Math.max(0, offset);
|
|
8066
|
-
const boundedExclude = Math.max(0, Math.min(excludeRecentCount, collapsed.length));
|
|
8067
|
-
const endExclusive = Math.max(0, collapsed.length - boundedExclude - boundedOffset);
|
|
8068
|
-
const startInclusive = Math.max(0, endExclusive - boundedLimit);
|
|
8069
|
-
const sliced = collapsed.slice(startInclusive, endExclusive);
|
|
8070
|
-
const hasMore = startInclusive > 0;
|
|
8071
|
-
return { messages: sliced, hasMore };
|
|
8096
|
+
return pageHistoryRecords(agentType, allMessages, offset, limit, excludeRecentCount, historyBehavior);
|
|
8072
8097
|
} catch {
|
|
8073
8098
|
return { messages: [], hasMore: false };
|
|
8074
8099
|
}
|
|
@@ -8135,29 +8160,6 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
8135
8160
|
return { sessions: [], hasMore: false };
|
|
8136
8161
|
}
|
|
8137
8162
|
}
|
|
8138
|
-
function normalizeCanonicalHermesMessageContent(content) {
|
|
8139
|
-
if (typeof content === "string") return content.trim();
|
|
8140
|
-
if (content == null) return "";
|
|
8141
|
-
try {
|
|
8142
|
-
return JSON.stringify(content).trim();
|
|
8143
|
-
} catch {
|
|
8144
|
-
return String(content).trim();
|
|
8145
|
-
}
|
|
8146
|
-
}
|
|
8147
|
-
function extractCanonicalHermesMessageTimestamp(message, fallbackTs) {
|
|
8148
|
-
const numericTimestamp = Number(message.receivedAt || message.timestamp || message.ts || 0);
|
|
8149
|
-
if (Number.isFinite(numericTimestamp) && numericTimestamp > 0) return numericTimestamp;
|
|
8150
|
-
const stringTimestamp = typeof message.ts === "string" ? Date.parse(message.ts) : typeof message.timestamp === "string" ? Date.parse(message.timestamp) : NaN;
|
|
8151
|
-
if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
|
|
8152
|
-
return fallbackTs;
|
|
8153
|
-
}
|
|
8154
|
-
function extractTimestampValue(value) {
|
|
8155
|
-
const numericTimestamp = Number(value || 0);
|
|
8156
|
-
if (Number.isFinite(numericTimestamp) && numericTimestamp > 0) return numericTimestamp;
|
|
8157
|
-
const stringTimestamp = typeof value === "string" ? Date.parse(value) : NaN;
|
|
8158
|
-
if (Number.isFinite(stringTimestamp) && stringTimestamp > 0) return stringTimestamp;
|
|
8159
|
-
return 0;
|
|
8160
|
-
}
|
|
8161
8163
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
8162
8164
|
try {
|
|
8163
8165
|
const dir = path7.join(HISTORY_DIR, agentType);
|
|
@@ -8203,232 +8205,193 @@ function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
|
8203
8205
|
return false;
|
|
8204
8206
|
}
|
|
8205
8207
|
}
|
|
8206
|
-
function
|
|
8208
|
+
function getNativeHistoryScriptName(canonicalHistory, key) {
|
|
8209
|
+
const configured = canonicalHistory?.scripts?.[key];
|
|
8210
|
+
if (typeof configured === "string" && configured.trim()) return configured.trim();
|
|
8211
|
+
return key === "readSession" ? "readNativeHistory" : "listNativeHistory";
|
|
8212
|
+
}
|
|
8213
|
+
function getProviderNativeHistoryScript(scripts, canonicalHistory, key) {
|
|
8214
|
+
if (!canonicalHistory?.scripts) return null;
|
|
8215
|
+
const fn = scripts?.[getNativeHistoryScriptName(canonicalHistory, key)];
|
|
8216
|
+
return typeof fn === "function" ? fn : null;
|
|
8217
|
+
}
|
|
8218
|
+
function normalizeProviderNativeHistoryRecords(agentType, historySessionId, records) {
|
|
8219
|
+
if (!Array.isArray(records)) return [];
|
|
8220
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8221
|
+
return records.map((record) => sanitizeHistoryMessage(agentType, {
|
|
8222
|
+
ts: typeof record?.ts === "string" ? record.ts : new Date(Number(record?.receivedAt) || Date.now()).toISOString(),
|
|
8223
|
+
receivedAt: Number(record?.receivedAt) || Date.parse(record?.ts || "") || Date.now(),
|
|
8224
|
+
role: record?.role,
|
|
8225
|
+
content: String(record?.content || ""),
|
|
8226
|
+
kind: record?.kind || (record?.role === "system" ? "session_start" : "standard"),
|
|
8227
|
+
senderName: record?.senderName,
|
|
8228
|
+
agent: agentType,
|
|
8229
|
+
instanceId: record?.instanceId,
|
|
8230
|
+
historySessionId: normalizeSavedHistorySessionId(record?.historySessionId || normalizedSessionId),
|
|
8231
|
+
sessionTitle: record?.sessionTitle,
|
|
8232
|
+
workspace: record?.workspace
|
|
8233
|
+
})).filter(Boolean);
|
|
8234
|
+
}
|
|
8235
|
+
function callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, historySessionId, workspace) {
|
|
8236
|
+
const fn = getProviderNativeHistoryScript(scripts, canonicalHistory, "readSession");
|
|
8237
|
+
if (!fn) return null;
|
|
8238
|
+
const result = fn({
|
|
8239
|
+
agentType,
|
|
8240
|
+
sessionId: historySessionId,
|
|
8241
|
+
historySessionId,
|
|
8242
|
+
workspace,
|
|
8243
|
+
format: canonicalHistory?.format,
|
|
8244
|
+
watchPath: canonicalHistory?.watchPath,
|
|
8245
|
+
args: { sessionId: historySessionId, historySessionId, workspace }
|
|
8246
|
+
});
|
|
8247
|
+
if (!result || typeof result !== "object") return null;
|
|
8248
|
+
const records = normalizeProviderNativeHistoryRecords(agentType, historySessionId, result.messages || result.records);
|
|
8249
|
+
if (records.length === 0) return null;
|
|
8250
|
+
return {
|
|
8251
|
+
records,
|
|
8252
|
+
sourcePath: typeof result.sourcePath === "string" ? result.sourcePath : "",
|
|
8253
|
+
sourceMtimeMs: Number(result.sourceMtimeMs) || 0
|
|
8254
|
+
};
|
|
8255
|
+
}
|
|
8256
|
+
function buildNativeHistoryReadResult(agentType, canonicalHistory, scripts, historySessionId, workspace) {
|
|
8257
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || "");
|
|
8258
|
+
if (!canonicalHistory || !normalizedSessionId || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
|
|
8259
|
+
return callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace);
|
|
8260
|
+
}
|
|
8261
|
+
function materializeNativeHistoryToMirror(agentType, canonicalHistory, historySessionId, workspace, scripts) {
|
|
8207
8262
|
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8208
8263
|
if (!normalizedSessionId) return false;
|
|
8264
|
+
const nativeResult = callProviderNativeHistoryRead(agentType, canonicalHistory, scripts, normalizedSessionId, workspace);
|
|
8265
|
+
const nativeRecords = nativeResult?.records || [];
|
|
8266
|
+
if (nativeRecords.length === 0) return false;
|
|
8267
|
+
const normalizedRecords = nativeRecords.map((record) => ({
|
|
8268
|
+
...record,
|
|
8269
|
+
agent: agentType,
|
|
8270
|
+
historySessionId: normalizedSessionId
|
|
8271
|
+
}));
|
|
8272
|
+
const existingSessionStart = readExistingSessionStartRecord(agentType, normalizedSessionId);
|
|
8273
|
+
const records = existingSessionStart && normalizedRecords[0]?.kind !== "session_start" ? [{ ...existingSessionStart, historySessionId: normalizedSessionId, agent: agentType }, ...normalizedRecords] : normalizedRecords;
|
|
8274
|
+
return rewriteCanonicalSavedHistory(agentType, normalizedSessionId, records);
|
|
8275
|
+
}
|
|
8276
|
+
function materializeProviderNativeHistory(agentType, canonicalHistory, historySessionId, workspace, scripts) {
|
|
8277
|
+
if (!canonicalHistory || canonicalHistory.mode !== "materialized-mirror") return false;
|
|
8278
|
+
return materializeNativeHistoryToMirror(agentType, canonicalHistory, historySessionId, workspace, scripts);
|
|
8279
|
+
}
|
|
8280
|
+
function isNativeSourceCanonicalHistory(canonicalHistory) {
|
|
8281
|
+
if (!canonicalHistory) return false;
|
|
8282
|
+
if (canonicalHistory.mode === "disabled") return false;
|
|
8283
|
+
if (canonicalHistory.mode === "materialized-mirror") return false;
|
|
8284
|
+
return true;
|
|
8285
|
+
}
|
|
8286
|
+
function readProviderChatHistory(agentType, options = {}) {
|
|
8287
|
+
if (isNativeSourceCanonicalHistory(options.canonicalHistory) && options.historySessionId) {
|
|
8288
|
+
const nativeResult = buildNativeHistoryReadResult(agentType, options.canonicalHistory, options.scripts, options.historySessionId, options.workspace);
|
|
8289
|
+
if (!nativeResult) return { messages: [], hasMore: false, source: "native-unavailable" };
|
|
8290
|
+
return {
|
|
8291
|
+
...pageHistoryRecords(agentType, nativeResult.records, options.offset || 0, options.limit || 30, options.excludeRecentCount || 0, options.historyBehavior),
|
|
8292
|
+
source: "provider-native",
|
|
8293
|
+
sourcePath: nativeResult.sourcePath,
|
|
8294
|
+
sourceMtimeMs: nativeResult.sourceMtimeMs
|
|
8295
|
+
};
|
|
8296
|
+
}
|
|
8297
|
+
return {
|
|
8298
|
+
...readChatHistory(agentType, options.offset || 0, options.limit || 30, options.historySessionId, options.excludeRecentCount || 0, options.historyBehavior),
|
|
8299
|
+
source: "adhdev-mirror"
|
|
8300
|
+
};
|
|
8301
|
+
}
|
|
8302
|
+
function buildNativeSessionSummary(agentType, historySessionId, records, sourcePath) {
|
|
8303
|
+
const visible = pageHistoryRecords(agentType, records, 0, Number.MAX_SAFE_INTEGER).messages;
|
|
8304
|
+
if (visible.length === 0) return null;
|
|
8305
|
+
let sourceMtimeMs = 0;
|
|
8209
8306
|
try {
|
|
8210
|
-
|
|
8211
|
-
if (!fs3.existsSync(sessionFilePath)) return false;
|
|
8212
|
-
const raw = JSON.parse(fs3.readFileSync(sessionFilePath, "utf-8"));
|
|
8213
|
-
const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
|
|
8214
|
-
const dir = path7.join(HISTORY_DIR, "hermes-cli");
|
|
8215
|
-
fs3.mkdirSync(dir, { recursive: true });
|
|
8216
|
-
const existingSessionStart = readExistingSessionStartRecord("hermes-cli", normalizedSessionId);
|
|
8217
|
-
const records = [];
|
|
8218
|
-
if (existingSessionStart) {
|
|
8219
|
-
records.push({
|
|
8220
|
-
...existingSessionStart,
|
|
8221
|
-
historySessionId: normalizedSessionId
|
|
8222
|
-
});
|
|
8223
|
-
}
|
|
8224
|
-
let fallbackTs = Date.parse(raw.session_start || raw.last_updated || "") || Date.now();
|
|
8225
|
-
for (const message of canonicalMessages) {
|
|
8226
|
-
const role = String(message.role || "").trim();
|
|
8227
|
-
const content = normalizeCanonicalHermesMessageContent(message.content);
|
|
8228
|
-
if (!content) continue;
|
|
8229
|
-
const receivedAt = extractCanonicalHermesMessageTimestamp(message, fallbackTs);
|
|
8230
|
-
fallbackTs = receivedAt + 1;
|
|
8231
|
-
if (role === "user") {
|
|
8232
|
-
records.push({
|
|
8233
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8234
|
-
receivedAt,
|
|
8235
|
-
role: "user",
|
|
8236
|
-
content,
|
|
8237
|
-
kind: "standard",
|
|
8238
|
-
agent: "hermes-cli",
|
|
8239
|
-
historySessionId: normalizedSessionId
|
|
8240
|
-
});
|
|
8241
|
-
continue;
|
|
8242
|
-
}
|
|
8243
|
-
if (role === "assistant") {
|
|
8244
|
-
records.push({
|
|
8245
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8246
|
-
receivedAt,
|
|
8247
|
-
role: "assistant",
|
|
8248
|
-
content,
|
|
8249
|
-
kind: "standard",
|
|
8250
|
-
agent: "hermes-cli",
|
|
8251
|
-
historySessionId: normalizedSessionId
|
|
8252
|
-
});
|
|
8253
|
-
continue;
|
|
8254
|
-
}
|
|
8255
|
-
if (role === "tool") {
|
|
8256
|
-
records.push({
|
|
8257
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8258
|
-
receivedAt,
|
|
8259
|
-
role: "assistant",
|
|
8260
|
-
content,
|
|
8261
|
-
kind: "tool",
|
|
8262
|
-
senderName: "Tool",
|
|
8263
|
-
agent: "hermes-cli",
|
|
8264
|
-
historySessionId: normalizedSessionId
|
|
8265
|
-
});
|
|
8266
|
-
}
|
|
8267
|
-
}
|
|
8268
|
-
return rewriteCanonicalSavedHistory("hermes-cli", normalizedSessionId, records);
|
|
8307
|
+
sourceMtimeMs = fs3.statSync(sourcePath).mtimeMs;
|
|
8269
8308
|
} catch {
|
|
8270
|
-
return false;
|
|
8271
8309
|
}
|
|
8310
|
+
const firstMessageAt = visible[0]?.receivedAt || sourceMtimeMs || Date.now();
|
|
8311
|
+
const lastMessageAt = visible[visible.length - 1]?.receivedAt || firstMessageAt;
|
|
8312
|
+
const lastNonSystem = [...visible].reverse().find((message) => message.role !== "system") || visible[visible.length - 1];
|
|
8313
|
+
const firstSystem = visible.find((message) => message.kind === "session_start");
|
|
8314
|
+
return {
|
|
8315
|
+
historySessionId,
|
|
8316
|
+
sessionTitle: lastNonSystem?.content,
|
|
8317
|
+
messageCount: visible.length,
|
|
8318
|
+
firstMessageAt,
|
|
8319
|
+
lastMessageAt,
|
|
8320
|
+
preview: lastNonSystem?.content,
|
|
8321
|
+
workspace: firstSystem?.workspace || (firstSystem?.kind === "session_start" ? firstSystem.content : void 0),
|
|
8322
|
+
source: "provider-native",
|
|
8323
|
+
sourcePath,
|
|
8324
|
+
sourceMtimeMs
|
|
8325
|
+
};
|
|
8272
8326
|
}
|
|
8273
|
-
function
|
|
8274
|
-
const
|
|
8275
|
-
if (!
|
|
8276
|
-
const
|
|
8277
|
-
|
|
8278
|
-
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
|
|
8282
|
-
|
|
8283
|
-
|
|
8284
|
-
|
|
8285
|
-
|
|
8286
|
-
|
|
8287
|
-
|
|
8288
|
-
|
|
8289
|
-
|
|
8290
|
-
|
|
8291
|
-
|
|
8292
|
-
|
|
8293
|
-
}
|
|
8294
|
-
}
|
|
8295
|
-
}
|
|
8296
|
-
return null;
|
|
8327
|
+
function normalizeProviderNativeHistorySessionSummary(agentType, item) {
|
|
8328
|
+
const historySessionId = normalizeSavedHistorySessionId(item?.historySessionId || item?.sessionId || "");
|
|
8329
|
+
if (!historySessionId) return null;
|
|
8330
|
+
const sourcePath = typeof item?.sourcePath === "string" ? item.sourcePath : "";
|
|
8331
|
+
const sourceMtimeMs = Number(item?.sourceMtimeMs) || 0;
|
|
8332
|
+
const firstMessageAt = Number(item?.firstMessageAt) || sourceMtimeMs || Date.now();
|
|
8333
|
+
const lastMessageAt = Number(item?.lastMessageAt) || firstMessageAt;
|
|
8334
|
+
const messageCount = Math.max(0, Number(item?.messageCount) || 0);
|
|
8335
|
+
return {
|
|
8336
|
+
historySessionId,
|
|
8337
|
+
sessionTitle: typeof item?.sessionTitle === "string" ? item.sessionTitle : void 0,
|
|
8338
|
+
messageCount,
|
|
8339
|
+
firstMessageAt,
|
|
8340
|
+
lastMessageAt,
|
|
8341
|
+
preview: typeof item?.preview === "string" ? item.preview : void 0,
|
|
8342
|
+
workspace: typeof item?.workspace === "string" ? item.workspace : void 0,
|
|
8343
|
+
source: "provider-native",
|
|
8344
|
+
sourcePath,
|
|
8345
|
+
sourceMtimeMs
|
|
8346
|
+
};
|
|
8297
8347
|
}
|
|
8298
|
-
function
|
|
8299
|
-
|
|
8300
|
-
|
|
8301
|
-
|
|
8302
|
-
|
|
8303
|
-
|
|
8304
|
-
|
|
8305
|
-
|
|
8306
|
-
|
|
8307
|
-
|
|
8308
|
-
|
|
8309
|
-
|
|
8310
|
-
|
|
8311
|
-
|
|
8348
|
+
function collectProviderScriptNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) {
|
|
8349
|
+
const fn = getProviderNativeHistoryScript(scripts, canonicalHistory, "listSessions");
|
|
8350
|
+
if (!fn) return null;
|
|
8351
|
+
const result = fn({
|
|
8352
|
+
agentType,
|
|
8353
|
+
format: canonicalHistory.format,
|
|
8354
|
+
watchPath: canonicalHistory.watchPath,
|
|
8355
|
+
args: {}
|
|
8356
|
+
});
|
|
8357
|
+
if (!result || typeof result !== "object") return [];
|
|
8358
|
+
const sessions = Array.isArray(result.sessions) ? result.sessions : [];
|
|
8359
|
+
const summaries = [];
|
|
8360
|
+
for (const item of sessions) {
|
|
8361
|
+
if (Array.isArray(item?.messages || item?.records)) {
|
|
8362
|
+
const historySessionId = normalizeSavedHistorySessionId(item?.historySessionId || item?.sessionId || "");
|
|
8363
|
+
if (!historySessionId) continue;
|
|
8364
|
+
const records = normalizeProviderNativeHistoryRecords(agentType, historySessionId, item.messages || item.records);
|
|
8365
|
+
const summary2 = buildNativeSessionSummary(agentType, historySessionId, records, typeof item?.sourcePath === "string" ? item.sourcePath : "");
|
|
8366
|
+
if (summary2) {
|
|
8367
|
+
if (Number(item?.sourceMtimeMs)) summary2.sourceMtimeMs = Number(item.sourceMtimeMs);
|
|
8368
|
+
summaries.push(summary2);
|
|
8369
|
+
}
|
|
8312
8370
|
continue;
|
|
8313
8371
|
}
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
const input = record.input && typeof record.input === "object" ? record.input : null;
|
|
8317
|
-
const command = input ? String(input.command || "").trim() : "";
|
|
8318
|
-
const summary = command ? `${name}: ${command}` : name;
|
|
8319
|
-
if (summary) parts.push({ content: summary, kind: "tool", senderName: "Tool", role: "assistant" });
|
|
8320
|
-
}
|
|
8372
|
+
const summary = normalizeProviderNativeHistorySessionSummary(agentType, item);
|
|
8373
|
+
if (summary) summaries.push(summary);
|
|
8321
8374
|
}
|
|
8322
|
-
return
|
|
8375
|
+
return sortSavedHistorySessionSummaries(summaries);
|
|
8323
8376
|
}
|
|
8324
|
-
function
|
|
8325
|
-
|
|
8326
|
-
const trimmed = content.trim();
|
|
8327
|
-
return trimmed ? [{ role: "user", content: trimmed, kind: "standard" }] : [];
|
|
8328
|
-
}
|
|
8329
|
-
if (!Array.isArray(content)) return [];
|
|
8330
|
-
const parts = [];
|
|
8331
|
-
for (const block of content) {
|
|
8332
|
-
if (!block || typeof block !== "object") continue;
|
|
8333
|
-
const record = block;
|
|
8334
|
-
const type = String(record.type || "").trim();
|
|
8335
|
-
if (type === "text") {
|
|
8336
|
-
const text = String(record.text || "").trim();
|
|
8337
|
-
if (text) parts.push({ role: "user", content: text, kind: "standard" });
|
|
8338
|
-
continue;
|
|
8339
|
-
}
|
|
8340
|
-
if (type === "tool_result") {
|
|
8341
|
-
const rawContent = record.content;
|
|
8342
|
-
const text = typeof rawContent === "string" ? rawContent.trim() : Array.isArray(rawContent) ? rawContent.map((entry) => {
|
|
8343
|
-
if (typeof entry === "string") return entry.trim();
|
|
8344
|
-
if (!entry || typeof entry !== "object") return "";
|
|
8345
|
-
const nested = entry;
|
|
8346
|
-
if (typeof nested.text === "string") return nested.text.trim();
|
|
8347
|
-
if (typeof nested.content === "string") return nested.content.trim();
|
|
8348
|
-
return "";
|
|
8349
|
-
}).filter(Boolean).join("\n") : "";
|
|
8350
|
-
if (text) parts.push({ role: "assistant", content: text, kind: "tool", senderName: "Tool" });
|
|
8351
|
-
}
|
|
8352
|
-
}
|
|
8353
|
-
return parts;
|
|
8377
|
+
function collectNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) {
|
|
8378
|
+
return collectProviderScriptNativeHistorySessionSummaries(agentType, canonicalHistory, scripts) || [];
|
|
8354
8379
|
}
|
|
8355
|
-
function
|
|
8356
|
-
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
const
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
records.push({
|
|
8366
|
-
...existingSessionStart,
|
|
8367
|
-
historySessionId: normalizedSessionId
|
|
8368
|
-
});
|
|
8369
|
-
}
|
|
8370
|
-
let fallbackTs = Date.now();
|
|
8371
|
-
for (const line of lines) {
|
|
8372
|
-
let parsed = null;
|
|
8373
|
-
try {
|
|
8374
|
-
parsed = JSON.parse(line);
|
|
8375
|
-
} catch {
|
|
8376
|
-
parsed = null;
|
|
8377
|
-
}
|
|
8378
|
-
if (!parsed) continue;
|
|
8379
|
-
const parsedSessionId = String(parsed.sessionId || "").trim();
|
|
8380
|
-
if (parsedSessionId && parsedSessionId !== normalizedSessionId) continue;
|
|
8381
|
-
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
8382
|
-
fallbackTs = receivedAt + 1;
|
|
8383
|
-
const parsedWorkspace = String(parsed.cwd || workspace || "").trim();
|
|
8384
|
-
if (records.length === 0 && parsedWorkspace) {
|
|
8385
|
-
records.push({
|
|
8386
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8387
|
-
receivedAt,
|
|
8388
|
-
role: "system",
|
|
8389
|
-
kind: "session_start",
|
|
8390
|
-
content: parsedWorkspace,
|
|
8391
|
-
agent: "claude-cli",
|
|
8392
|
-
historySessionId: normalizedSessionId,
|
|
8393
|
-
workspace: parsedWorkspace
|
|
8394
|
-
});
|
|
8395
|
-
}
|
|
8396
|
-
const type = String(parsed.type || "").trim();
|
|
8397
|
-
const message = parsed.message && typeof parsed.message === "object" ? parsed.message : null;
|
|
8398
|
-
if (type === "user" && message) {
|
|
8399
|
-
for (const part of extractClaudeUserContentParts(message.content)) {
|
|
8400
|
-
records.push({
|
|
8401
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8402
|
-
receivedAt,
|
|
8403
|
-
role: part.role,
|
|
8404
|
-
content: part.content,
|
|
8405
|
-
kind: part.kind,
|
|
8406
|
-
senderName: part.senderName,
|
|
8407
|
-
agent: "claude-cli",
|
|
8408
|
-
historySessionId: normalizedSessionId
|
|
8409
|
-
});
|
|
8410
|
-
}
|
|
8411
|
-
continue;
|
|
8412
|
-
}
|
|
8413
|
-
if (type === "assistant" && message) {
|
|
8414
|
-
for (const part of extractClaudeAssistantContentParts(message.content)) {
|
|
8415
|
-
records.push({
|
|
8416
|
-
ts: new Date(receivedAt).toISOString(),
|
|
8417
|
-
receivedAt,
|
|
8418
|
-
role: "assistant",
|
|
8419
|
-
content: part.content,
|
|
8420
|
-
kind: part.kind,
|
|
8421
|
-
senderName: part.senderName,
|
|
8422
|
-
agent: "claude-cli",
|
|
8423
|
-
historySessionId: normalizedSessionId
|
|
8424
|
-
});
|
|
8425
|
-
}
|
|
8426
|
-
}
|
|
8427
|
-
}
|
|
8428
|
-
return rewriteCanonicalSavedHistory("claude-cli", normalizedSessionId, records);
|
|
8429
|
-
} catch {
|
|
8430
|
-
return false;
|
|
8380
|
+
function listProviderHistorySessions(agentType, options = {}) {
|
|
8381
|
+
if (isNativeSourceCanonicalHistory(options.canonicalHistory)) {
|
|
8382
|
+
const offset = Math.max(0, options.offset || 0);
|
|
8383
|
+
const limit = Math.max(1, options.limit || 30);
|
|
8384
|
+
const summaries = collectNativeHistorySessionSummaries(agentType, options.canonicalHistory, options.scripts);
|
|
8385
|
+
return {
|
|
8386
|
+
sessions: summaries.slice(offset, offset + limit),
|
|
8387
|
+
hasMore: offset + limit < summaries.length,
|
|
8388
|
+
source: "provider-native"
|
|
8389
|
+
};
|
|
8431
8390
|
}
|
|
8391
|
+
return {
|
|
8392
|
+
...listSavedHistorySessions(agentType, { offset: options.offset, limit: options.limit }, options.historyBehavior),
|
|
8393
|
+
source: "adhdev-mirror"
|
|
8394
|
+
};
|
|
8432
8395
|
}
|
|
8433
8396
|
|
|
8434
8397
|
// src/providers/provider-patch-state.ts
|
|
@@ -11043,7 +11006,17 @@ async function handleChatHistory(h, args) {
|
|
|
11043
11006
|
const visibleCount = Array.isArray(status?.messages) ? status.messages.length : 0;
|
|
11044
11007
|
if (visibleCount > excludeRecentCount) excludeRecentCount = visibleCount;
|
|
11045
11008
|
}
|
|
11046
|
-
const
|
|
11009
|
+
const workspace = typeof args?.workspace === "string" ? args.workspace : typeof h.currentSession?.workspace === "string" ? h.currentSession.workspace : void 0;
|
|
11010
|
+
const result = readProviderChatHistory(agentStr, {
|
|
11011
|
+
canonicalHistory: provider?.canonicalHistory,
|
|
11012
|
+
historySessionId,
|
|
11013
|
+
workspace,
|
|
11014
|
+
offset: offset || 0,
|
|
11015
|
+
limit: limit || 30,
|
|
11016
|
+
excludeRecentCount,
|
|
11017
|
+
historyBehavior: provider?.historyBehavior,
|
|
11018
|
+
scripts: provider?.scripts
|
|
11019
|
+
});
|
|
11047
11020
|
return { success: true, ...result, agent: agentStr };
|
|
11048
11021
|
} catch (e) {
|
|
11049
11022
|
return { success: false, error: e.message };
|
|
@@ -11068,7 +11041,8 @@ async function handleReadChat(h, args) {
|
|
|
11068
11041
|
}
|
|
11069
11042
|
const parsedRecord = parsedStatus && typeof parsedStatus === "object" ? parsedStatus : null;
|
|
11070
11043
|
const adapterStatus = adapter.getStatus();
|
|
11071
|
-
const
|
|
11044
|
+
const parsedIsProviderAuthoritative = parsedRecord?.transcriptAuthority === "provider" || parsedRecord?.coverage === "full";
|
|
11045
|
+
const shouldPreferAdapterMessages = !parsedIsProviderAuthoritative && Array.isArray(adapterStatus.messages) && adapterStatus.messages.length > 0 && Array.isArray(parsedRecord?.messages) && adapterStatus.messages.length > parsedRecord.messages.length;
|
|
11072
11046
|
const parsedShowsApproval = hasNonEmptyModalButtons(parsedRecord?.activeModal) && parsedRecord?.status === "waiting_approval";
|
|
11073
11047
|
const status = parsedRecord ? {
|
|
11074
11048
|
...parsedRecord,
|
|
@@ -11078,6 +11052,8 @@ async function handleReadChat(h, args) {
|
|
|
11078
11052
|
} : adapterStatus;
|
|
11079
11053
|
const title = typeof parsedRecord?.title === "string" ? parsedRecord.title : void 0;
|
|
11080
11054
|
const providerSessionId = typeof parsedRecord?.providerSessionId === "string" ? parsedRecord.providerSessionId : void 0;
|
|
11055
|
+
const transcriptAuthority = parsedRecord?.transcriptAuthority === "provider" || parsedRecord?.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
|
|
11056
|
+
const coverage = parsedRecord?.coverage === "full" || parsedRecord?.coverage === "tail" || parsedRecord?.coverage === "current-turn" ? parsedRecord.coverage : void 0;
|
|
11081
11057
|
if (status) {
|
|
11082
11058
|
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}`);
|
|
11083
11059
|
return buildReadChatCommandResult({
|
|
@@ -11096,7 +11072,9 @@ async function handleReadChat(h, args) {
|
|
|
11096
11072
|
returnedMsgCount: Array.isArray(status.messages) ? status.messages.length : 0
|
|
11097
11073
|
},
|
|
11098
11074
|
...title ? { title } : {},
|
|
11099
|
-
...providerSessionId ? { providerSessionId } : {}
|
|
11075
|
+
...providerSessionId ? { providerSessionId } : {},
|
|
11076
|
+
...transcriptAuthority ? { transcriptAuthority } : {},
|
|
11077
|
+
...coverage ? { coverage } : {}
|
|
11100
11078
|
}, args);
|
|
11101
11079
|
}
|
|
11102
11080
|
}
|
|
@@ -13511,11 +13489,8 @@ var CliProviderInstance = class {
|
|
|
13511
13489
|
historyWriter;
|
|
13512
13490
|
runtimeMessages = [];
|
|
13513
13491
|
lastPersistedHistoryMessages = [];
|
|
13514
|
-
|
|
13515
|
-
|
|
13516
|
-
lastCanonicalHermesWatchPath = void 0;
|
|
13517
|
-
lastCanonicalClaudeRebuildMtimeMs = 0;
|
|
13518
|
-
lastCanonicalClaudeCheckAt = 0;
|
|
13492
|
+
lastNativeSourceCanonicalCheckAt = 0;
|
|
13493
|
+
lastNativeSourceCanonicalCacheKey = void 0;
|
|
13519
13494
|
cachedSqliteDb = null;
|
|
13520
13495
|
cachedSqliteDbPath = null;
|
|
13521
13496
|
cachedSqliteDbMissingUntil = 0;
|
|
@@ -14215,41 +14190,45 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14215
14190
|
if (!this.providerSessionId) return false;
|
|
14216
14191
|
const canonicalHistory = this.provider.canonicalHistory;
|
|
14217
14192
|
if (!canonicalHistory) return false;
|
|
14193
|
+
if (isNativeSourceCanonicalHistory(canonicalHistory)) {
|
|
14194
|
+
const cacheKey = [this.type, this.providerSessionId, this.workingDir].join("\0");
|
|
14195
|
+
const now = Date.now();
|
|
14196
|
+
if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
|
|
14197
|
+
return true;
|
|
14198
|
+
}
|
|
14199
|
+
this.lastNativeSourceCanonicalCacheKey = cacheKey;
|
|
14200
|
+
this.lastNativeSourceCanonicalCheckAt = now;
|
|
14201
|
+
const restoredHistory = readProviderChatHistory(this.type, {
|
|
14202
|
+
canonicalHistory,
|
|
14203
|
+
historySessionId: this.providerSessionId,
|
|
14204
|
+
workspace: this.workingDir,
|
|
14205
|
+
offset: 0,
|
|
14206
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
14207
|
+
historyBehavior: this.provider.historyBehavior,
|
|
14208
|
+
scripts: this.provider.scripts
|
|
14209
|
+
});
|
|
14210
|
+
if (restoredHistory.source === "provider-native") {
|
|
14211
|
+
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
14212
|
+
role: message.role,
|
|
14213
|
+
content: message.content,
|
|
14214
|
+
kind: message.kind,
|
|
14215
|
+
senderName: message.senderName,
|
|
14216
|
+
receivedAt: message.receivedAt
|
|
14217
|
+
}));
|
|
14218
|
+
}
|
|
14219
|
+
return true;
|
|
14220
|
+
}
|
|
14218
14221
|
try {
|
|
14219
|
-
|
|
14220
|
-
|
|
14221
|
-
|
|
14222
|
-
|
|
14223
|
-
|
|
14224
|
-
|
|
14225
|
-
|
|
14226
|
-
|
|
14227
|
-
|
|
14228
|
-
if (!fs5.existsSync(watchPath)) return false;
|
|
14229
|
-
}
|
|
14230
|
-
const stat = fs5.statSync(watchPath);
|
|
14231
|
-
if (stat.mtimeMs <= this.lastCanonicalHermesSyncMtimeMs) return true;
|
|
14232
|
-
rebuilt = rebuildHermesSavedHistoryFromCanonicalSession(this.providerSessionId);
|
|
14233
|
-
if (rebuilt) this.lastCanonicalHermesSyncMtimeMs = stat.mtimeMs;
|
|
14234
|
-
} else if (canonicalHistory.format === "claude-jsonl") {
|
|
14235
|
-
const now = Date.now();
|
|
14236
|
-
if (now - this.lastCanonicalClaudeCheckAt < 2e3 && this.lastCanonicalClaudeRebuildMtimeMs !== 0) {
|
|
14237
|
-
return true;
|
|
14238
|
-
}
|
|
14239
|
-
this.lastCanonicalClaudeCheckAt = now;
|
|
14240
|
-
const claudeProjectsDir = path11.join(os11.homedir(), ".claude", "projects");
|
|
14241
|
-
const workspaceSegment = typeof this.workingDir === "string" ? this.workingDir.replace(/[\\/]/g, "-").replace(/^-+/, "") : "";
|
|
14242
|
-
const transcriptFile = path11.join(claudeProjectsDir, workspaceSegment, `${this.providerSessionId}.jsonl`);
|
|
14243
|
-
let transcriptMtime = 0;
|
|
14244
|
-
try {
|
|
14245
|
-
transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
|
|
14246
|
-
} catch {
|
|
14247
|
-
}
|
|
14248
|
-
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalClaudeRebuildMtimeMs) return true;
|
|
14249
|
-
rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
|
|
14250
|
-
if (rebuilt) this.lastCanonicalClaudeRebuildMtimeMs = transcriptMtime || Date.now();
|
|
14222
|
+
const cacheKey = [this.type, this.providerSessionId, this.workingDir, canonicalHistory.mode || "materialized-mirror"].join("\0");
|
|
14223
|
+
const now = Date.now();
|
|
14224
|
+
if (cacheKey === this.lastNativeSourceCanonicalCacheKey && now - this.lastNativeSourceCanonicalCheckAt < 2e3) {
|
|
14225
|
+
return true;
|
|
14226
|
+
}
|
|
14227
|
+
this.lastNativeSourceCanonicalCacheKey = cacheKey;
|
|
14228
|
+
this.lastNativeSourceCanonicalCheckAt = now;
|
|
14229
|
+
if (!materializeProviderNativeHistory(this.type, canonicalHistory, this.providerSessionId, this.workingDir, this.provider.scripts)) {
|
|
14230
|
+
return false;
|
|
14251
14231
|
}
|
|
14252
|
-
if (!rebuilt) return false;
|
|
14253
14232
|
const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
14254
14233
|
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
14255
14234
|
role: message.role,
|
|
@@ -14266,8 +14245,18 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14266
14245
|
restorePersistedHistoryFromCurrentSession() {
|
|
14267
14246
|
if (!this.providerSessionId) return;
|
|
14268
14247
|
this.syncCanonicalSavedHistoryIfNeeded();
|
|
14269
|
-
this.
|
|
14270
|
-
|
|
14248
|
+
const restoredHistory = isNativeSourceCanonicalHistory(this.provider.canonicalHistory) ? readProviderChatHistory(this.type, {
|
|
14249
|
+
canonicalHistory: this.provider.canonicalHistory,
|
|
14250
|
+
historySessionId: this.providerSessionId,
|
|
14251
|
+
workspace: this.workingDir,
|
|
14252
|
+
offset: 0,
|
|
14253
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
14254
|
+
historyBehavior: this.provider.historyBehavior,
|
|
14255
|
+
scripts: this.provider.scripts
|
|
14256
|
+
}) : (() => {
|
|
14257
|
+
this.historyWriter.compactHistorySession(this.type, this.providerSessionId, this.provider.historyBehavior);
|
|
14258
|
+
return readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
14259
|
+
})();
|
|
14271
14260
|
this.historyWriter.seedSessionHistory(
|
|
14272
14261
|
this.type,
|
|
14273
14262
|
restoredHistory.messages,
|
|
@@ -16398,6 +16387,7 @@ function validateProviderDefinition(raw) {
|
|
|
16398
16387
|
warnings.push("Extension providers should have extensionId");
|
|
16399
16388
|
}
|
|
16400
16389
|
validateCapabilities(provider, controls, errors);
|
|
16390
|
+
validateCanonicalHistory(provider.canonicalHistory, errors);
|
|
16401
16391
|
for (const control of controls) {
|
|
16402
16392
|
validateControl(control, errors);
|
|
16403
16393
|
}
|
|
@@ -16455,6 +16445,39 @@ function validateCapabilities(provider, controls, errors) {
|
|
|
16455
16445
|
errors.push("providers declaring controls must set capabilities.controls.typedResults=true");
|
|
16456
16446
|
}
|
|
16457
16447
|
}
|
|
16448
|
+
function validateCanonicalHistory(raw, errors) {
|
|
16449
|
+
if (raw === void 0) return;
|
|
16450
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
16451
|
+
errors.push("canonicalHistory must be an object");
|
|
16452
|
+
return;
|
|
16453
|
+
}
|
|
16454
|
+
const canonicalHistory = raw;
|
|
16455
|
+
const format = canonicalHistory.format;
|
|
16456
|
+
if (format !== void 0 && (typeof format !== "string" || !format.trim())) {
|
|
16457
|
+
errors.push("canonicalHistory.format must be a non-empty string when provided");
|
|
16458
|
+
}
|
|
16459
|
+
const watchPath = canonicalHistory.watchPath;
|
|
16460
|
+
if (watchPath !== void 0 && (typeof watchPath !== "string" || !watchPath.trim())) {
|
|
16461
|
+
errors.push("canonicalHistory.watchPath must be a non-empty string when provided");
|
|
16462
|
+
}
|
|
16463
|
+
const mode = canonicalHistory.mode;
|
|
16464
|
+
if (mode !== void 0 && !["native-source", "materialized-mirror", "disabled"].includes(String(mode))) {
|
|
16465
|
+
errors.push("canonicalHistory.mode must be one of: native-source, materialized-mirror, disabled");
|
|
16466
|
+
}
|
|
16467
|
+
const scripts = canonicalHistory.scripts;
|
|
16468
|
+
if (scripts === void 0) return;
|
|
16469
|
+
if (!scripts || typeof scripts !== "object" || Array.isArray(scripts)) {
|
|
16470
|
+
errors.push("canonicalHistory.scripts must be an object");
|
|
16471
|
+
return;
|
|
16472
|
+
}
|
|
16473
|
+
const scriptConfig = scripts;
|
|
16474
|
+
for (const key of ["readSession", "listSessions"]) {
|
|
16475
|
+
const value = scriptConfig[key];
|
|
16476
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
16477
|
+
errors.push(`canonicalHistory.scripts.${key} must be a non-empty string`);
|
|
16478
|
+
}
|
|
16479
|
+
}
|
|
16480
|
+
}
|
|
16458
16481
|
function validateControl(control, errors) {
|
|
16459
16482
|
if (!control || typeof control !== "object") {
|
|
16460
16483
|
errors.push("controls: each control must be an object");
|
|
@@ -17997,6 +18020,38 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17997
18020
|
}
|
|
17998
18021
|
};
|
|
17999
18022
|
|
|
18023
|
+
// src/launch/macos-app-process.ts
|
|
18024
|
+
function normalizeMacAppPath(appPath) {
|
|
18025
|
+
const trimmed = String(appPath || "").trim();
|
|
18026
|
+
if (!trimmed) return null;
|
|
18027
|
+
return trimmed.replace(/\/+$/, "");
|
|
18028
|
+
}
|
|
18029
|
+
function parsePsLine(line) {
|
|
18030
|
+
const match = line.match(/^\s*(\d+)\s+(.+)$/);
|
|
18031
|
+
if (!match) return null;
|
|
18032
|
+
const pid = Number.parseInt(match[1], 10);
|
|
18033
|
+
if (!Number.isFinite(pid)) return null;
|
|
18034
|
+
return { pid, args: match[2] };
|
|
18035
|
+
}
|
|
18036
|
+
function isMacAppProcessArgs(args, appPath) {
|
|
18037
|
+
const normalized = normalizeMacAppPath(appPath);
|
|
18038
|
+
if (!normalized) return false;
|
|
18039
|
+
return String(args || "").startsWith(`${normalized}/`);
|
|
18040
|
+
}
|
|
18041
|
+
function findMacAppProcessPids(psOutput, appPaths) {
|
|
18042
|
+
const normalizedPaths = appPaths.map(normalizeMacAppPath).filter((value) => !!value);
|
|
18043
|
+
if (normalizedPaths.length === 0) return [];
|
|
18044
|
+
const pids = [];
|
|
18045
|
+
for (const line of String(psOutput || "").split(/\r?\n/)) {
|
|
18046
|
+
const parsed = parsePsLine(line);
|
|
18047
|
+
if (!parsed) continue;
|
|
18048
|
+
if (normalizedPaths.some((appPath) => isMacAppProcessArgs(parsed.args, appPath))) {
|
|
18049
|
+
pids.push(parsed.pid);
|
|
18050
|
+
}
|
|
18051
|
+
}
|
|
18052
|
+
return pids;
|
|
18053
|
+
}
|
|
18054
|
+
|
|
18000
18055
|
// src/launch.ts
|
|
18001
18056
|
var _providerLoader = null;
|
|
18002
18057
|
function getProviderLoader() {
|
|
@@ -18033,6 +18088,35 @@ function getCdpStartupTimeoutMs(ideId) {
|
|
|
18033
18088
|
function escapeForAppleScript(value) {
|
|
18034
18089
|
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
18035
18090
|
}
|
|
18091
|
+
function getIdePathCandidates(ideId) {
|
|
18092
|
+
return getProviderLoader().getIdePathCandidates(ideId);
|
|
18093
|
+
}
|
|
18094
|
+
function getMacAppProcessPids(ideId) {
|
|
18095
|
+
const appPaths = getIdePathCandidates(ideId);
|
|
18096
|
+
if (appPaths.length === 0) return [];
|
|
18097
|
+
try {
|
|
18098
|
+
const output = (0, import_child_process7.execSync)("ps axww -o pid=,args=", {
|
|
18099
|
+
encoding: "utf-8",
|
|
18100
|
+
timeout: 3e3,
|
|
18101
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
18102
|
+
});
|
|
18103
|
+
return findMacAppProcessPids(output, appPaths);
|
|
18104
|
+
} catch {
|
|
18105
|
+
return [];
|
|
18106
|
+
}
|
|
18107
|
+
}
|
|
18108
|
+
function killMacAppPathProcesses(ideId, signal) {
|
|
18109
|
+
const pids = getMacAppProcessPids(ideId);
|
|
18110
|
+
let signalled = false;
|
|
18111
|
+
for (const pid of pids) {
|
|
18112
|
+
try {
|
|
18113
|
+
process.kill(pid, signal);
|
|
18114
|
+
signalled = true;
|
|
18115
|
+
} catch {
|
|
18116
|
+
}
|
|
18117
|
+
}
|
|
18118
|
+
return signalled;
|
|
18119
|
+
}
|
|
18036
18120
|
async function findFreePort(ports) {
|
|
18037
18121
|
for (const port2 of ports) {
|
|
18038
18122
|
const free = await checkPortFree(port2);
|
|
@@ -18094,6 +18178,7 @@ async function killIdeProcess(ideId) {
|
|
|
18094
18178
|
} catch {
|
|
18095
18179
|
}
|
|
18096
18180
|
}
|
|
18181
|
+
killMacAppPathProcesses(ideId, "SIGTERM");
|
|
18097
18182
|
} else if (plat === "win32" && winProcesses) {
|
|
18098
18183
|
for (const proc of winProcesses) {
|
|
18099
18184
|
try {
|
|
@@ -18123,6 +18208,7 @@ async function killIdeProcess(ideId) {
|
|
|
18123
18208
|
(0, import_child_process7.execSync)(`pkill -9 -x "${appName}" 2>/dev/null`, { timeout: 5e3 });
|
|
18124
18209
|
} catch {
|
|
18125
18210
|
}
|
|
18211
|
+
killMacAppPathProcesses(ideId, "SIGKILL");
|
|
18126
18212
|
} else if (plat === "win32" && winProcesses) {
|
|
18127
18213
|
for (const proc of winProcesses) {
|
|
18128
18214
|
try {
|
|
@@ -18142,14 +18228,16 @@ function isIdeRunning(ideId) {
|
|
|
18142
18228
|
try {
|
|
18143
18229
|
if (plat === "darwin") {
|
|
18144
18230
|
const appName = getMacAppIdentifiers()[ideId];
|
|
18145
|
-
if (!appName) return
|
|
18231
|
+
if (!appName) return getMacAppProcessPids(ideId).length > 0;
|
|
18146
18232
|
try {
|
|
18147
18233
|
const result = (0, import_child_process7.execSync)(`pgrep -x "${appName}" 2>/dev/null`, {
|
|
18148
18234
|
encoding: "utf-8",
|
|
18149
18235
|
timeout: 3e3
|
|
18150
18236
|
});
|
|
18151
|
-
|
|
18237
|
+
if (result.trim().length > 0) return true;
|
|
18152
18238
|
} catch {
|
|
18239
|
+
}
|
|
18240
|
+
try {
|
|
18153
18241
|
const result = (0, import_child_process7.execSync)(
|
|
18154
18242
|
`osascript -e 'tell application "System Events" to count (every process whose name is "${escapeForAppleScript(appName)}")'`,
|
|
18155
18243
|
{
|
|
@@ -18158,8 +18246,10 @@ function isIdeRunning(ideId) {
|
|
|
18158
18246
|
stdio: ["pipe", "pipe", "pipe"]
|
|
18159
18247
|
}
|
|
18160
18248
|
);
|
|
18161
|
-
|
|
18249
|
+
if (Number.parseInt(result.trim() || "0", 10) > 0) return true;
|
|
18250
|
+
} catch {
|
|
18162
18251
|
}
|
|
18252
|
+
return getMacAppProcessPids(ideId).length > 0;
|
|
18163
18253
|
} else if (plat === "win32") {
|
|
18164
18254
|
const winProcesses = getWinProcessNames()[ideId];
|
|
18165
18255
|
if (!winProcesses) return false;
|
|
@@ -19526,13 +19616,19 @@ var DaemonCommandRouter = class {
|
|
|
19526
19616
|
const wantsAll = args?.all === true;
|
|
19527
19617
|
const offset = wantsAll ? 0 : Math.max(0, Number(args?.offset) || 0);
|
|
19528
19618
|
const limit = wantsAll ? Number.MAX_SAFE_INTEGER : Math.max(1, Math.min(100, Number(args?.limit) || 30));
|
|
19529
|
-
const
|
|
19619
|
+
const providerMeta = this.deps.providerLoader.getMeta(providerType);
|
|
19620
|
+
const { sessions: historySessions, hasMore, source } = listProviderHistorySessions(providerType, {
|
|
19621
|
+
canonicalHistory: providerMeta?.canonicalHistory,
|
|
19622
|
+
offset,
|
|
19623
|
+
limit,
|
|
19624
|
+
historyBehavior: providerMeta?.historyBehavior,
|
|
19625
|
+
scripts: providerMeta?.scripts
|
|
19626
|
+
});
|
|
19530
19627
|
const state = loadState();
|
|
19531
19628
|
const savedSessions = getSavedProviderSessions(state, { providerType, kind });
|
|
19532
19629
|
const recentSessions = getRecentActivity(state, 200).filter((entry) => entry.providerType === providerType && entry.kind === kind && entry.providerSessionId);
|
|
19533
19630
|
const savedSessionById = new Map(savedSessions.map((entry) => [entry.providerSessionId, entry]));
|
|
19534
19631
|
const recentSessionById = new Map(recentSessions.map((entry) => [entry.providerSessionId, entry]));
|
|
19535
|
-
const providerMeta = this.deps.providerLoader.getMeta(providerType);
|
|
19536
19632
|
const canResumeById = supportsExplicitSessionResume(providerMeta?.resume);
|
|
19537
19633
|
return {
|
|
19538
19634
|
success: true,
|
|
@@ -19552,10 +19648,14 @@ var DaemonCommandRouter = class {
|
|
|
19552
19648
|
messageCount: session.messageCount,
|
|
19553
19649
|
firstMessageAt: session.firstMessageAt,
|
|
19554
19650
|
lastMessageAt: session.lastMessageAt,
|
|
19555
|
-
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById
|
|
19651
|
+
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById,
|
|
19652
|
+
historySource: session.source,
|
|
19653
|
+
sourcePath: session.sourcePath,
|
|
19654
|
+
sourceMtimeMs: session.sourceMtimeMs
|
|
19556
19655
|
};
|
|
19557
19656
|
}),
|
|
19558
|
-
hasMore
|
|
19657
|
+
hasMore,
|
|
19658
|
+
source
|
|
19559
19659
|
};
|
|
19560
19660
|
}
|
|
19561
19661
|
// ─── restart_session: IDE / CLI / ACP unified ───
|