@adhdev/daemon-core 0.9.44 → 0.9.45
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 +30 -9
- package/dist/index.js +657 -35
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +657 -35
- 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 -0
- package/dist/providers/contracts.d.ts +14 -1
- 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 +27 -3
- package/src/commands/router.ts +9 -3
- package/src/config/chat-history.ts +541 -24
- package/src/launch/macos-app-process.ts +37 -0
- package/src/launch.ts +43 -5
- package/src/providers/cli-provider-instance.ts +52 -3
- package/src/providers/contracts.ts +15 -2
- 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
|
}
|
|
@@ -8203,6 +8228,52 @@ function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
|
8203
8228
|
return false;
|
|
8204
8229
|
}
|
|
8205
8230
|
}
|
|
8231
|
+
function buildHermesNativeHistoryRecords(historySessionId) {
|
|
8232
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8233
|
+
if (!normalizedSessionId) return null;
|
|
8234
|
+
try {
|
|
8235
|
+
const sessionFilePath = path7.join(os5.homedir(), ".hermes", "sessions", `session_${normalizedSessionId}.json`);
|
|
8236
|
+
if (!fs3.existsSync(sessionFilePath)) return null;
|
|
8237
|
+
const raw = JSON.parse(fs3.readFileSync(sessionFilePath, "utf-8"));
|
|
8238
|
+
const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
|
|
8239
|
+
const records = [];
|
|
8240
|
+
let fallbackTs = Date.parse(raw.session_start || raw.last_updated || "") || Date.now();
|
|
8241
|
+
for (const message of canonicalMessages) {
|
|
8242
|
+
const role = String(message.role || "").trim();
|
|
8243
|
+
const content = normalizeCanonicalHermesMessageContent(message.content);
|
|
8244
|
+
if (!content) continue;
|
|
8245
|
+
const receivedAt = extractCanonicalHermesMessageTimestamp(message, fallbackTs);
|
|
8246
|
+
fallbackTs = receivedAt + 1;
|
|
8247
|
+
if (role === "user" || role === "assistant") {
|
|
8248
|
+
records.push({
|
|
8249
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8250
|
+
receivedAt,
|
|
8251
|
+
role,
|
|
8252
|
+
content,
|
|
8253
|
+
kind: "standard",
|
|
8254
|
+
agent: "hermes-cli",
|
|
8255
|
+
historySessionId: normalizedSessionId
|
|
8256
|
+
});
|
|
8257
|
+
continue;
|
|
8258
|
+
}
|
|
8259
|
+
if (role === "tool") {
|
|
8260
|
+
records.push({
|
|
8261
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8262
|
+
receivedAt,
|
|
8263
|
+
role: "assistant",
|
|
8264
|
+
content,
|
|
8265
|
+
kind: "tool",
|
|
8266
|
+
senderName: "Tool",
|
|
8267
|
+
agent: "hermes-cli",
|
|
8268
|
+
historySessionId: normalizedSessionId
|
|
8269
|
+
});
|
|
8270
|
+
}
|
|
8271
|
+
}
|
|
8272
|
+
return records;
|
|
8273
|
+
} catch {
|
|
8274
|
+
return null;
|
|
8275
|
+
}
|
|
8276
|
+
}
|
|
8206
8277
|
function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
|
|
8207
8278
|
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8208
8279
|
if (!normalizedSessionId) return false;
|
|
@@ -8352,6 +8423,77 @@ function extractClaudeUserContentParts(content) {
|
|
|
8352
8423
|
}
|
|
8353
8424
|
return parts;
|
|
8354
8425
|
}
|
|
8426
|
+
function buildClaudeNativeHistoryRecords(historySessionId, workspace) {
|
|
8427
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8428
|
+
if (!normalizedSessionId) return null;
|
|
8429
|
+
try {
|
|
8430
|
+
const transcriptPath = resolveClaudeProjectTranscriptPath(normalizedSessionId, workspace);
|
|
8431
|
+
if (!transcriptPath) return null;
|
|
8432
|
+
const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
|
|
8433
|
+
const records = [];
|
|
8434
|
+
let fallbackTs = Date.now();
|
|
8435
|
+
for (const line of lines) {
|
|
8436
|
+
let parsed = null;
|
|
8437
|
+
try {
|
|
8438
|
+
parsed = JSON.parse(line);
|
|
8439
|
+
} catch {
|
|
8440
|
+
parsed = null;
|
|
8441
|
+
}
|
|
8442
|
+
if (!parsed) continue;
|
|
8443
|
+
const parsedSessionId = String(parsed.sessionId || "").trim();
|
|
8444
|
+
if (parsedSessionId && parsedSessionId !== normalizedSessionId) continue;
|
|
8445
|
+
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
8446
|
+
fallbackTs = receivedAt + 1;
|
|
8447
|
+
const parsedWorkspace = String(parsed.cwd || workspace || "").trim();
|
|
8448
|
+
if (records.length === 0 && parsedWorkspace) {
|
|
8449
|
+
records.push({
|
|
8450
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8451
|
+
receivedAt,
|
|
8452
|
+
role: "system",
|
|
8453
|
+
kind: "session_start",
|
|
8454
|
+
content: parsedWorkspace,
|
|
8455
|
+
agent: "claude-cli",
|
|
8456
|
+
historySessionId: normalizedSessionId,
|
|
8457
|
+
workspace: parsedWorkspace
|
|
8458
|
+
});
|
|
8459
|
+
}
|
|
8460
|
+
const type = String(parsed.type || "").trim();
|
|
8461
|
+
const message = parsed.message && typeof parsed.message === "object" ? parsed.message : null;
|
|
8462
|
+
if (type === "user" && message) {
|
|
8463
|
+
for (const part of extractClaudeUserContentParts(message.content)) {
|
|
8464
|
+
records.push({
|
|
8465
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8466
|
+
receivedAt,
|
|
8467
|
+
role: part.role,
|
|
8468
|
+
content: part.content,
|
|
8469
|
+
kind: part.kind,
|
|
8470
|
+
senderName: part.senderName,
|
|
8471
|
+
agent: "claude-cli",
|
|
8472
|
+
historySessionId: normalizedSessionId
|
|
8473
|
+
});
|
|
8474
|
+
}
|
|
8475
|
+
continue;
|
|
8476
|
+
}
|
|
8477
|
+
if (type === "assistant" && message) {
|
|
8478
|
+
for (const part of extractClaudeAssistantContentParts(message.content)) {
|
|
8479
|
+
records.push({
|
|
8480
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8481
|
+
receivedAt,
|
|
8482
|
+
role: "assistant",
|
|
8483
|
+
content: part.content,
|
|
8484
|
+
kind: part.kind,
|
|
8485
|
+
senderName: part.senderName,
|
|
8486
|
+
agent: "claude-cli",
|
|
8487
|
+
historySessionId: normalizedSessionId
|
|
8488
|
+
});
|
|
8489
|
+
}
|
|
8490
|
+
}
|
|
8491
|
+
}
|
|
8492
|
+
return records;
|
|
8493
|
+
} catch {
|
|
8494
|
+
return null;
|
|
8495
|
+
}
|
|
8496
|
+
}
|
|
8355
8497
|
function rebuildClaudeSavedHistoryFromNativeProject(historySessionId, workspace) {
|
|
8356
8498
|
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8357
8499
|
if (!normalizedSessionId) return false;
|
|
@@ -8430,6 +8572,352 @@ function rebuildClaudeSavedHistoryFromNativeProject(historySessionId, workspace)
|
|
|
8430
8572
|
return false;
|
|
8431
8573
|
}
|
|
8432
8574
|
}
|
|
8575
|
+
function isUuidLikeSessionId(sessionId) {
|
|
8576
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);
|
|
8577
|
+
}
|
|
8578
|
+
function readCodexSessionMeta(filePath) {
|
|
8579
|
+
try {
|
|
8580
|
+
const firstLine = fs3.readFileSync(filePath, "utf-8").split("\n").find(Boolean);
|
|
8581
|
+
if (!firstLine) return null;
|
|
8582
|
+
const parsed = JSON.parse(firstLine);
|
|
8583
|
+
if (String(parsed.type || "") !== "session_meta") return null;
|
|
8584
|
+
const payload = parsed.payload && typeof parsed.payload === "object" ? parsed.payload : null;
|
|
8585
|
+
return payload;
|
|
8586
|
+
} catch {
|
|
8587
|
+
return null;
|
|
8588
|
+
}
|
|
8589
|
+
}
|
|
8590
|
+
function resolveCodexSessionTranscriptPath(historySessionId, workspace) {
|
|
8591
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8592
|
+
if (!normalizedSessionId || !isUuidLikeSessionId(normalizedSessionId)) return null;
|
|
8593
|
+
const sessionsDir = path7.join(os5.homedir(), ".codex", "sessions");
|
|
8594
|
+
if (!fs3.existsSync(sessionsDir)) return null;
|
|
8595
|
+
const normalizedWorkspace = typeof workspace === "string" ? workspace.trim() : "";
|
|
8596
|
+
const candidates = [];
|
|
8597
|
+
const stack = [sessionsDir];
|
|
8598
|
+
while (stack.length > 0) {
|
|
8599
|
+
const current = stack.pop();
|
|
8600
|
+
if (!current) continue;
|
|
8601
|
+
let entries = [];
|
|
8602
|
+
try {
|
|
8603
|
+
entries = fs3.readdirSync(current, { withFileTypes: true });
|
|
8604
|
+
} catch {
|
|
8605
|
+
continue;
|
|
8606
|
+
}
|
|
8607
|
+
for (const entry of entries) {
|
|
8608
|
+
const entryPath = path7.join(current, entry.name);
|
|
8609
|
+
if (entry.isDirectory()) {
|
|
8610
|
+
stack.push(entryPath);
|
|
8611
|
+
continue;
|
|
8612
|
+
}
|
|
8613
|
+
if (!entry.isFile() || !entry.name.endsWith(".jsonl") || !entry.name.includes(normalizedSessionId)) continue;
|
|
8614
|
+
const meta = readCodexSessionMeta(entryPath);
|
|
8615
|
+
const metaSessionId = String(meta?.id || "").trim();
|
|
8616
|
+
if (metaSessionId && metaSessionId !== normalizedSessionId) continue;
|
|
8617
|
+
const metaWorkspace = String(meta?.cwd || "").trim();
|
|
8618
|
+
let mtimeMs = 0;
|
|
8619
|
+
try {
|
|
8620
|
+
mtimeMs = fs3.statSync(entryPath).mtimeMs;
|
|
8621
|
+
} catch {
|
|
8622
|
+
}
|
|
8623
|
+
candidates.push({
|
|
8624
|
+
path: entryPath,
|
|
8625
|
+
mtimeMs,
|
|
8626
|
+
workspaceMatches: !!normalizedWorkspace && metaWorkspace === normalizedWorkspace,
|
|
8627
|
+
metaMatches: metaSessionId === normalizedSessionId
|
|
8628
|
+
});
|
|
8629
|
+
}
|
|
8630
|
+
}
|
|
8631
|
+
candidates.sort((a, b) => Number(b.workspaceMatches) - Number(a.workspaceMatches) || Number(b.metaMatches) - Number(a.metaMatches) || b.mtimeMs - a.mtimeMs);
|
|
8632
|
+
return candidates[0]?.path || null;
|
|
8633
|
+
}
|
|
8634
|
+
function flattenCodexContent(content) {
|
|
8635
|
+
if (typeof content === "string") return content.trim();
|
|
8636
|
+
if (content == null) return "";
|
|
8637
|
+
if (Array.isArray(content)) {
|
|
8638
|
+
return content.map((entry) => flattenCodexContent(entry)).filter(Boolean).join("\n").trim();
|
|
8639
|
+
}
|
|
8640
|
+
if (typeof content === "object") {
|
|
8641
|
+
const record = content;
|
|
8642
|
+
if (typeof record.text === "string") return record.text.trim();
|
|
8643
|
+
if (typeof record.content === "string" || Array.isArray(record.content)) return flattenCodexContent(record.content);
|
|
8644
|
+
if (typeof record.output === "string") return record.output.trim();
|
|
8645
|
+
if (typeof record.message === "string") return record.message.trim();
|
|
8646
|
+
}
|
|
8647
|
+
return "";
|
|
8648
|
+
}
|
|
8649
|
+
function summarizeCodexToolCall(payload) {
|
|
8650
|
+
const name = String(payload.name || payload.type || "tool").trim() || "tool";
|
|
8651
|
+
const rawArguments = payload.arguments ?? payload.input;
|
|
8652
|
+
let argumentValue = "";
|
|
8653
|
+
if (typeof rawArguments === "string") {
|
|
8654
|
+
const trimmed = rawArguments.trim();
|
|
8655
|
+
try {
|
|
8656
|
+
const parsed = JSON.parse(trimmed);
|
|
8657
|
+
argumentValue = summarizeCodexToolArguments(parsed);
|
|
8658
|
+
} catch {
|
|
8659
|
+
argumentValue = trimmed;
|
|
8660
|
+
}
|
|
8661
|
+
} else {
|
|
8662
|
+
argumentValue = summarizeCodexToolArguments(rawArguments);
|
|
8663
|
+
}
|
|
8664
|
+
return argumentValue ? `${name}: ${argumentValue}` : name;
|
|
8665
|
+
}
|
|
8666
|
+
function summarizeCodexToolArguments(value) {
|
|
8667
|
+
if (typeof value === "string") return value.trim();
|
|
8668
|
+
if (Array.isArray(value)) return value.map((entry) => String(entry)).join(" ").trim();
|
|
8669
|
+
if (!value || typeof value !== "object") return "";
|
|
8670
|
+
const record = value;
|
|
8671
|
+
const direct = record.command || record.cmd || record.query || record.path || record.prompt;
|
|
8672
|
+
if (typeof direct === "string") return direct.trim();
|
|
8673
|
+
if (Array.isArray(direct)) return direct.map((entry) => String(entry)).join(" ").trim();
|
|
8674
|
+
try {
|
|
8675
|
+
return JSON.stringify(record).trim();
|
|
8676
|
+
} catch {
|
|
8677
|
+
return "";
|
|
8678
|
+
}
|
|
8679
|
+
}
|
|
8680
|
+
function codexToolOutputContent(payload) {
|
|
8681
|
+
const output = payload.output ?? payload.result ?? payload.content;
|
|
8682
|
+
const text = flattenCodexContent(output);
|
|
8683
|
+
if (text) return text;
|
|
8684
|
+
if (output && typeof output === "object") {
|
|
8685
|
+
try {
|
|
8686
|
+
return JSON.stringify(output).trim();
|
|
8687
|
+
} catch {
|
|
8688
|
+
return "";
|
|
8689
|
+
}
|
|
8690
|
+
}
|
|
8691
|
+
return "";
|
|
8692
|
+
}
|
|
8693
|
+
function buildCodexNativeHistoryRecords(historySessionId, workspace) {
|
|
8694
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8695
|
+
if (!normalizedSessionId || !isUuidLikeSessionId(normalizedSessionId)) return null;
|
|
8696
|
+
try {
|
|
8697
|
+
const transcriptPath = resolveCodexSessionTranscriptPath(normalizedSessionId, workspace);
|
|
8698
|
+
if (!transcriptPath) return null;
|
|
8699
|
+
const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
|
|
8700
|
+
const records = [];
|
|
8701
|
+
let fallbackTs = Date.now();
|
|
8702
|
+
for (const line of lines) {
|
|
8703
|
+
let parsed = null;
|
|
8704
|
+
try {
|
|
8705
|
+
parsed = JSON.parse(line);
|
|
8706
|
+
} catch {
|
|
8707
|
+
parsed = null;
|
|
8708
|
+
}
|
|
8709
|
+
if (!parsed) continue;
|
|
8710
|
+
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
8711
|
+
fallbackTs = receivedAt + 1;
|
|
8712
|
+
const type = String(parsed.type || "").trim();
|
|
8713
|
+
const payload = parsed.payload && typeof parsed.payload === "object" ? parsed.payload : null;
|
|
8714
|
+
if (!payload) continue;
|
|
8715
|
+
if (type === "session_meta") {
|
|
8716
|
+
const parsedSessionId = String(payload.id || "").trim();
|
|
8717
|
+
if (parsedSessionId && parsedSessionId !== normalizedSessionId) return null;
|
|
8718
|
+
const parsedWorkspace = String(payload.cwd || workspace || "").trim();
|
|
8719
|
+
if (records.length === 0 && parsedWorkspace) {
|
|
8720
|
+
records.push({
|
|
8721
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8722
|
+
receivedAt,
|
|
8723
|
+
role: "system",
|
|
8724
|
+
kind: "session_start",
|
|
8725
|
+
content: parsedWorkspace,
|
|
8726
|
+
agent: "codex-cli",
|
|
8727
|
+
historySessionId: normalizedSessionId,
|
|
8728
|
+
workspace: parsedWorkspace
|
|
8729
|
+
});
|
|
8730
|
+
}
|
|
8731
|
+
continue;
|
|
8732
|
+
}
|
|
8733
|
+
if (type !== "response_item") continue;
|
|
8734
|
+
const payloadType = String(payload.type || "").trim();
|
|
8735
|
+
if (payloadType === "message") {
|
|
8736
|
+
const role = String(payload.role || "").trim();
|
|
8737
|
+
if (role !== "user" && role !== "assistant") continue;
|
|
8738
|
+
const content = flattenCodexContent(payload.content);
|
|
8739
|
+
if (!content) continue;
|
|
8740
|
+
records.push({
|
|
8741
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8742
|
+
receivedAt,
|
|
8743
|
+
role,
|
|
8744
|
+
content,
|
|
8745
|
+
kind: "standard",
|
|
8746
|
+
agent: "codex-cli",
|
|
8747
|
+
historySessionId: normalizedSessionId
|
|
8748
|
+
});
|
|
8749
|
+
continue;
|
|
8750
|
+
}
|
|
8751
|
+
if (payloadType === "function_call" || payloadType === "custom_tool_call") {
|
|
8752
|
+
const content = summarizeCodexToolCall(payload);
|
|
8753
|
+
if (!content) continue;
|
|
8754
|
+
records.push({
|
|
8755
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8756
|
+
receivedAt,
|
|
8757
|
+
role: "assistant",
|
|
8758
|
+
content,
|
|
8759
|
+
kind: "tool",
|
|
8760
|
+
senderName: "Tool",
|
|
8761
|
+
agent: "codex-cli",
|
|
8762
|
+
historySessionId: normalizedSessionId
|
|
8763
|
+
});
|
|
8764
|
+
continue;
|
|
8765
|
+
}
|
|
8766
|
+
if (payloadType === "function_call_output" || payloadType === "custom_tool_call_output") {
|
|
8767
|
+
const content = codexToolOutputContent(payload);
|
|
8768
|
+
if (!content) continue;
|
|
8769
|
+
records.push({
|
|
8770
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8771
|
+
receivedAt,
|
|
8772
|
+
role: "assistant",
|
|
8773
|
+
content,
|
|
8774
|
+
kind: "tool",
|
|
8775
|
+
senderName: "Tool",
|
|
8776
|
+
agent: "codex-cli",
|
|
8777
|
+
historySessionId: normalizedSessionId
|
|
8778
|
+
});
|
|
8779
|
+
}
|
|
8780
|
+
}
|
|
8781
|
+
return records;
|
|
8782
|
+
} catch {
|
|
8783
|
+
return null;
|
|
8784
|
+
}
|
|
8785
|
+
}
|
|
8786
|
+
function rebuildCodexSavedHistoryFromNativeSession(historySessionId, workspace) {
|
|
8787
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8788
|
+
if (!normalizedSessionId || !isUuidLikeSessionId(normalizedSessionId)) return false;
|
|
8789
|
+
const records = buildCodexNativeHistoryRecords(normalizedSessionId, workspace);
|
|
8790
|
+
if (!records || records.length === 0) return false;
|
|
8791
|
+
const existingSessionStart = readExistingSessionStartRecord("codex-cli", normalizedSessionId);
|
|
8792
|
+
const recordsToWrite = existingSessionStart && records[0]?.kind !== "session_start" ? [{ ...existingSessionStart, historySessionId: normalizedSessionId }, ...records] : records;
|
|
8793
|
+
return rewriteCanonicalSavedHistory("codex-cli", normalizedSessionId, recordsToWrite);
|
|
8794
|
+
}
|
|
8795
|
+
function isNativeSourceCanonicalHistory(canonicalHistory) {
|
|
8796
|
+
if (!canonicalHistory) return false;
|
|
8797
|
+
if (canonicalHistory.mode === "disabled") return false;
|
|
8798
|
+
if (canonicalHistory.mode === "materialized-mirror") return false;
|
|
8799
|
+
return true;
|
|
8800
|
+
}
|
|
8801
|
+
function buildNativeHistoryRecords(canonicalHistory, historySessionId, workspace) {
|
|
8802
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || "");
|
|
8803
|
+
if (!canonicalHistory || !normalizedSessionId || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
|
|
8804
|
+
if (canonicalHistory.format === "hermes-json") return buildHermesNativeHistoryRecords(normalizedSessionId);
|
|
8805
|
+
if (canonicalHistory.format === "claude-jsonl") return buildClaudeNativeHistoryRecords(normalizedSessionId, workspace);
|
|
8806
|
+
if (canonicalHistory.format === "codex-jsonl") return buildCodexNativeHistoryRecords(normalizedSessionId, workspace);
|
|
8807
|
+
return null;
|
|
8808
|
+
}
|
|
8809
|
+
function readProviderChatHistory(agentType, options = {}) {
|
|
8810
|
+
if (isNativeSourceCanonicalHistory(options.canonicalHistory) && options.historySessionId) {
|
|
8811
|
+
const records = buildNativeHistoryRecords(options.canonicalHistory, options.historySessionId, options.workspace);
|
|
8812
|
+
if (!records) return { messages: [], hasMore: false, source: "native-unavailable" };
|
|
8813
|
+
return {
|
|
8814
|
+
...pageHistoryRecords(agentType, records, options.offset || 0, options.limit || 30, options.excludeRecentCount || 0, options.historyBehavior),
|
|
8815
|
+
source: "provider-native"
|
|
8816
|
+
};
|
|
8817
|
+
}
|
|
8818
|
+
return {
|
|
8819
|
+
...readChatHistory(agentType, options.offset || 0, options.limit || 30, options.historySessionId, options.excludeRecentCount || 0, options.historyBehavior),
|
|
8820
|
+
source: "adhdev-mirror"
|
|
8821
|
+
};
|
|
8822
|
+
}
|
|
8823
|
+
function buildNativeSessionSummary(agentType, historySessionId, records, sourcePath) {
|
|
8824
|
+
const visible = pageHistoryRecords(agentType, records, 0, Number.MAX_SAFE_INTEGER).messages;
|
|
8825
|
+
if (visible.length === 0) return null;
|
|
8826
|
+
let sourceMtimeMs = 0;
|
|
8827
|
+
try {
|
|
8828
|
+
sourceMtimeMs = fs3.statSync(sourcePath).mtimeMs;
|
|
8829
|
+
} catch {
|
|
8830
|
+
}
|
|
8831
|
+
const firstMessageAt = visible[0]?.receivedAt || sourceMtimeMs || Date.now();
|
|
8832
|
+
const lastMessageAt = visible[visible.length - 1]?.receivedAt || firstMessageAt;
|
|
8833
|
+
const lastNonSystem = [...visible].reverse().find((message) => message.role !== "system") || visible[visible.length - 1];
|
|
8834
|
+
const firstSystem = visible.find((message) => message.kind === "session_start");
|
|
8835
|
+
return {
|
|
8836
|
+
historySessionId,
|
|
8837
|
+
sessionTitle: lastNonSystem?.content,
|
|
8838
|
+
messageCount: visible.length,
|
|
8839
|
+
firstMessageAt,
|
|
8840
|
+
lastMessageAt,
|
|
8841
|
+
preview: lastNonSystem?.content,
|
|
8842
|
+
workspace: firstSystem?.workspace || (firstSystem?.kind === "session_start" ? firstSystem.content : void 0),
|
|
8843
|
+
source: "provider-native",
|
|
8844
|
+
sourcePath,
|
|
8845
|
+
sourceMtimeMs
|
|
8846
|
+
};
|
|
8847
|
+
}
|
|
8848
|
+
function listFilesRecursive(root, predicate) {
|
|
8849
|
+
if (!fs3.existsSync(root)) return [];
|
|
8850
|
+
const results = [];
|
|
8851
|
+
const stack = [root];
|
|
8852
|
+
while (stack.length > 0) {
|
|
8853
|
+
const current = stack.pop();
|
|
8854
|
+
if (!current) continue;
|
|
8855
|
+
let entries = [];
|
|
8856
|
+
try {
|
|
8857
|
+
entries = fs3.readdirSync(current, { withFileTypes: true });
|
|
8858
|
+
} catch {
|
|
8859
|
+
continue;
|
|
8860
|
+
}
|
|
8861
|
+
for (const entry of entries) {
|
|
8862
|
+
const entryPath = path7.join(current, entry.name);
|
|
8863
|
+
if (entry.isDirectory()) {
|
|
8864
|
+
stack.push(entryPath);
|
|
8865
|
+
continue;
|
|
8866
|
+
}
|
|
8867
|
+
if (predicate(entryPath, entry)) results.push(entryPath);
|
|
8868
|
+
}
|
|
8869
|
+
}
|
|
8870
|
+
return results;
|
|
8871
|
+
}
|
|
8872
|
+
function collectNativeHistorySessionSummaries(agentType, canonicalHistory) {
|
|
8873
|
+
const summaries = [];
|
|
8874
|
+
if (canonicalHistory.format === "hermes-json") {
|
|
8875
|
+
const root = path7.join(os5.homedir(), ".hermes", "sessions");
|
|
8876
|
+
for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && /^session_.+\.json$/.test(entry.name))) {
|
|
8877
|
+
const fileName = path7.basename(filePath);
|
|
8878
|
+
const historySessionId = fileName.replace(/^session_/, "").replace(/\.json$/, "");
|
|
8879
|
+
const records = buildHermesNativeHistoryRecords(historySessionId);
|
|
8880
|
+
const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
|
|
8881
|
+
if (summary) summaries.push(summary);
|
|
8882
|
+
}
|
|
8883
|
+
} else if (canonicalHistory.format === "claude-jsonl") {
|
|
8884
|
+
const root = path7.join(os5.homedir(), ".claude", "projects");
|
|
8885
|
+
for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && entry.name.endsWith(".jsonl"))) {
|
|
8886
|
+
const historySessionId = path7.basename(filePath, ".jsonl");
|
|
8887
|
+
const records = buildClaudeNativeHistoryRecords(historySessionId);
|
|
8888
|
+
const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
|
|
8889
|
+
if (summary) summaries.push(summary);
|
|
8890
|
+
}
|
|
8891
|
+
} else if (canonicalHistory.format === "codex-jsonl") {
|
|
8892
|
+
const root = path7.join(os5.homedir(), ".codex", "sessions");
|
|
8893
|
+
const uuidPattern = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i;
|
|
8894
|
+
for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && entry.name.endsWith(".jsonl"))) {
|
|
8895
|
+
const meta = readCodexSessionMeta(filePath);
|
|
8896
|
+
const historySessionId = String(meta?.id || path7.basename(filePath).match(uuidPattern)?.[1] || "").trim();
|
|
8897
|
+
if (!historySessionId) continue;
|
|
8898
|
+
const records = buildCodexNativeHistoryRecords(historySessionId, String(meta?.cwd || "").trim() || void 0);
|
|
8899
|
+
const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
|
|
8900
|
+
if (summary) summaries.push(summary);
|
|
8901
|
+
}
|
|
8902
|
+
}
|
|
8903
|
+
return sortSavedHistorySessionSummaries(summaries);
|
|
8904
|
+
}
|
|
8905
|
+
function listProviderHistorySessions(agentType, options = {}) {
|
|
8906
|
+
if (isNativeSourceCanonicalHistory(options.canonicalHistory)) {
|
|
8907
|
+
const offset = Math.max(0, options.offset || 0);
|
|
8908
|
+
const limit = Math.max(1, options.limit || 30);
|
|
8909
|
+
const summaries = collectNativeHistorySessionSummaries(agentType, options.canonicalHistory);
|
|
8910
|
+
return {
|
|
8911
|
+
sessions: summaries.slice(offset, offset + limit),
|
|
8912
|
+
hasMore: offset + limit < summaries.length,
|
|
8913
|
+
source: "provider-native"
|
|
8914
|
+
};
|
|
8915
|
+
}
|
|
8916
|
+
return {
|
|
8917
|
+
...listSavedHistorySessions(agentType, { offset: options.offset, limit: options.limit }, options.historyBehavior),
|
|
8918
|
+
source: "adhdev-mirror"
|
|
8919
|
+
};
|
|
8920
|
+
}
|
|
8433
8921
|
|
|
8434
8922
|
// src/providers/provider-patch-state.ts
|
|
8435
8923
|
function isControlValue(value) {
|
|
@@ -11043,7 +11531,16 @@ async function handleChatHistory(h, args) {
|
|
|
11043
11531
|
const visibleCount = Array.isArray(status?.messages) ? status.messages.length : 0;
|
|
11044
11532
|
if (visibleCount > excludeRecentCount) excludeRecentCount = visibleCount;
|
|
11045
11533
|
}
|
|
11046
|
-
const
|
|
11534
|
+
const workspace = typeof args?.workspace === "string" ? args.workspace : typeof h.currentSession?.workspace === "string" ? h.currentSession.workspace : void 0;
|
|
11535
|
+
const result = readProviderChatHistory(agentStr, {
|
|
11536
|
+
canonicalHistory: provider?.canonicalHistory,
|
|
11537
|
+
historySessionId,
|
|
11538
|
+
workspace,
|
|
11539
|
+
offset: offset || 0,
|
|
11540
|
+
limit: limit || 30,
|
|
11541
|
+
excludeRecentCount,
|
|
11542
|
+
historyBehavior: provider?.historyBehavior
|
|
11543
|
+
});
|
|
11047
11544
|
return { success: true, ...result, agent: agentStr };
|
|
11048
11545
|
} catch (e) {
|
|
11049
11546
|
return { success: false, error: e.message };
|
|
@@ -11068,7 +11565,8 @@ async function handleReadChat(h, args) {
|
|
|
11068
11565
|
}
|
|
11069
11566
|
const parsedRecord = parsedStatus && typeof parsedStatus === "object" ? parsedStatus : null;
|
|
11070
11567
|
const adapterStatus = adapter.getStatus();
|
|
11071
|
-
const
|
|
11568
|
+
const parsedIsProviderAuthoritative = parsedRecord?.transcriptAuthority === "provider" || parsedRecord?.coverage === "full";
|
|
11569
|
+
const shouldPreferAdapterMessages = !parsedIsProviderAuthoritative && Array.isArray(adapterStatus.messages) && adapterStatus.messages.length > 0 && Array.isArray(parsedRecord?.messages) && adapterStatus.messages.length > parsedRecord.messages.length;
|
|
11072
11570
|
const parsedShowsApproval = hasNonEmptyModalButtons(parsedRecord?.activeModal) && parsedRecord?.status === "waiting_approval";
|
|
11073
11571
|
const status = parsedRecord ? {
|
|
11074
11572
|
...parsedRecord,
|
|
@@ -11078,6 +11576,8 @@ async function handleReadChat(h, args) {
|
|
|
11078
11576
|
} : adapterStatus;
|
|
11079
11577
|
const title = typeof parsedRecord?.title === "string" ? parsedRecord.title : void 0;
|
|
11080
11578
|
const providerSessionId = typeof parsedRecord?.providerSessionId === "string" ? parsedRecord.providerSessionId : void 0;
|
|
11579
|
+
const transcriptAuthority = parsedRecord?.transcriptAuthority === "provider" || parsedRecord?.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
|
|
11580
|
+
const coverage = parsedRecord?.coverage === "full" || parsedRecord?.coverage === "tail" || parsedRecord?.coverage === "current-turn" ? parsedRecord.coverage : void 0;
|
|
11081
11581
|
if (status) {
|
|
11082
11582
|
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
11583
|
return buildReadChatCommandResult({
|
|
@@ -11096,7 +11596,9 @@ async function handleReadChat(h, args) {
|
|
|
11096
11596
|
returnedMsgCount: Array.isArray(status.messages) ? status.messages.length : 0
|
|
11097
11597
|
},
|
|
11098
11598
|
...title ? { title } : {},
|
|
11099
|
-
...providerSessionId ? { providerSessionId } : {}
|
|
11599
|
+
...providerSessionId ? { providerSessionId } : {},
|
|
11600
|
+
...transcriptAuthority ? { transcriptAuthority } : {},
|
|
11601
|
+
...coverage ? { coverage } : {}
|
|
11100
11602
|
}, args);
|
|
11101
11603
|
}
|
|
11102
11604
|
}
|
|
@@ -13516,6 +14018,8 @@ var CliProviderInstance = class {
|
|
|
13516
14018
|
lastCanonicalHermesWatchPath = void 0;
|
|
13517
14019
|
lastCanonicalClaudeRebuildMtimeMs = 0;
|
|
13518
14020
|
lastCanonicalClaudeCheckAt = 0;
|
|
14021
|
+
lastCanonicalCodexRebuildMtimeMs = 0;
|
|
14022
|
+
lastCanonicalCodexCheckAt = 0;
|
|
13519
14023
|
cachedSqliteDb = null;
|
|
13520
14024
|
cachedSqliteDbPath = null;
|
|
13521
14025
|
cachedSqliteDbMissingUntil = 0;
|
|
@@ -14215,6 +14719,25 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14215
14719
|
if (!this.providerSessionId) return false;
|
|
14216
14720
|
const canonicalHistory = this.provider.canonicalHistory;
|
|
14217
14721
|
if (!canonicalHistory) return false;
|
|
14722
|
+
if (isNativeSourceCanonicalHistory(canonicalHistory)) {
|
|
14723
|
+
const restoredHistory = readProviderChatHistory(this.type, {
|
|
14724
|
+
canonicalHistory,
|
|
14725
|
+
historySessionId: this.providerSessionId,
|
|
14726
|
+
workspace: this.workingDir,
|
|
14727
|
+
offset: 0,
|
|
14728
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
14729
|
+
historyBehavior: this.provider.historyBehavior
|
|
14730
|
+
});
|
|
14731
|
+
if (restoredHistory.source !== "provider-native") return false;
|
|
14732
|
+
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
14733
|
+
role: message.role,
|
|
14734
|
+
content: message.content,
|
|
14735
|
+
kind: message.kind,
|
|
14736
|
+
senderName: message.senderName,
|
|
14737
|
+
receivedAt: message.receivedAt
|
|
14738
|
+
}));
|
|
14739
|
+
return true;
|
|
14740
|
+
}
|
|
14218
14741
|
try {
|
|
14219
14742
|
let rebuilt = false;
|
|
14220
14743
|
if (canonicalHistory.format === "hermes-json") {
|
|
@@ -14248,6 +14771,23 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14248
14771
|
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalClaudeRebuildMtimeMs) return true;
|
|
14249
14772
|
rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
|
|
14250
14773
|
if (rebuilt) this.lastCanonicalClaudeRebuildMtimeMs = transcriptMtime || Date.now();
|
|
14774
|
+
} else if (canonicalHistory.format === "codex-jsonl") {
|
|
14775
|
+
const now = Date.now();
|
|
14776
|
+
if (now - this.lastCanonicalCodexCheckAt < 2e3 && this.lastCanonicalCodexRebuildMtimeMs !== 0) {
|
|
14777
|
+
return true;
|
|
14778
|
+
}
|
|
14779
|
+
this.lastCanonicalCodexCheckAt = now;
|
|
14780
|
+
const transcriptFile = resolveCodexSessionTranscriptPath(this.providerSessionId, this.workingDir);
|
|
14781
|
+
let transcriptMtime = 0;
|
|
14782
|
+
if (transcriptFile) {
|
|
14783
|
+
try {
|
|
14784
|
+
transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
|
|
14785
|
+
} catch {
|
|
14786
|
+
}
|
|
14787
|
+
}
|
|
14788
|
+
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalCodexRebuildMtimeMs) return true;
|
|
14789
|
+
rebuilt = rebuildCodexSavedHistoryFromNativeSession(this.providerSessionId, this.workingDir);
|
|
14790
|
+
if (rebuilt) this.lastCanonicalCodexRebuildMtimeMs = transcriptMtime || Date.now();
|
|
14251
14791
|
}
|
|
14252
14792
|
if (!rebuilt) return false;
|
|
14253
14793
|
const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
@@ -14266,8 +14806,17 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14266
14806
|
restorePersistedHistoryFromCurrentSession() {
|
|
14267
14807
|
if (!this.providerSessionId) return;
|
|
14268
14808
|
this.syncCanonicalSavedHistoryIfNeeded();
|
|
14269
|
-
this.
|
|
14270
|
-
|
|
14809
|
+
const restoredHistory = isNativeSourceCanonicalHistory(this.provider.canonicalHistory) ? readProviderChatHistory(this.type, {
|
|
14810
|
+
canonicalHistory: this.provider.canonicalHistory,
|
|
14811
|
+
historySessionId: this.providerSessionId,
|
|
14812
|
+
workspace: this.workingDir,
|
|
14813
|
+
offset: 0,
|
|
14814
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
14815
|
+
historyBehavior: this.provider.historyBehavior
|
|
14816
|
+
}) : (() => {
|
|
14817
|
+
this.historyWriter.compactHistorySession(this.type, this.providerSessionId, this.provider.historyBehavior);
|
|
14818
|
+
return readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
14819
|
+
})();
|
|
14271
14820
|
this.historyWriter.seedSessionHistory(
|
|
14272
14821
|
this.type,
|
|
14273
14822
|
restoredHistory.messages,
|
|
@@ -17997,6 +18546,38 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17997
18546
|
}
|
|
17998
18547
|
};
|
|
17999
18548
|
|
|
18549
|
+
// src/launch/macos-app-process.ts
|
|
18550
|
+
function normalizeMacAppPath(appPath) {
|
|
18551
|
+
const trimmed = String(appPath || "").trim();
|
|
18552
|
+
if (!trimmed) return null;
|
|
18553
|
+
return trimmed.replace(/\/+$/, "");
|
|
18554
|
+
}
|
|
18555
|
+
function parsePsLine(line) {
|
|
18556
|
+
const match = line.match(/^\s*(\d+)\s+(.+)$/);
|
|
18557
|
+
if (!match) return null;
|
|
18558
|
+
const pid = Number.parseInt(match[1], 10);
|
|
18559
|
+
if (!Number.isFinite(pid)) return null;
|
|
18560
|
+
return { pid, args: match[2] };
|
|
18561
|
+
}
|
|
18562
|
+
function isMacAppProcessArgs(args, appPath) {
|
|
18563
|
+
const normalized = normalizeMacAppPath(appPath);
|
|
18564
|
+
if (!normalized) return false;
|
|
18565
|
+
return String(args || "").startsWith(`${normalized}/`);
|
|
18566
|
+
}
|
|
18567
|
+
function findMacAppProcessPids(psOutput, appPaths) {
|
|
18568
|
+
const normalizedPaths = appPaths.map(normalizeMacAppPath).filter((value) => !!value);
|
|
18569
|
+
if (normalizedPaths.length === 0) return [];
|
|
18570
|
+
const pids = [];
|
|
18571
|
+
for (const line of String(psOutput || "").split(/\r?\n/)) {
|
|
18572
|
+
const parsed = parsePsLine(line);
|
|
18573
|
+
if (!parsed) continue;
|
|
18574
|
+
if (normalizedPaths.some((appPath) => isMacAppProcessArgs(parsed.args, appPath))) {
|
|
18575
|
+
pids.push(parsed.pid);
|
|
18576
|
+
}
|
|
18577
|
+
}
|
|
18578
|
+
return pids;
|
|
18579
|
+
}
|
|
18580
|
+
|
|
18000
18581
|
// src/launch.ts
|
|
18001
18582
|
var _providerLoader = null;
|
|
18002
18583
|
function getProviderLoader() {
|
|
@@ -18033,6 +18614,35 @@ function getCdpStartupTimeoutMs(ideId) {
|
|
|
18033
18614
|
function escapeForAppleScript(value) {
|
|
18034
18615
|
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
18035
18616
|
}
|
|
18617
|
+
function getIdePathCandidates(ideId) {
|
|
18618
|
+
return getProviderLoader().getIdePathCandidates(ideId);
|
|
18619
|
+
}
|
|
18620
|
+
function getMacAppProcessPids(ideId) {
|
|
18621
|
+
const appPaths = getIdePathCandidates(ideId);
|
|
18622
|
+
if (appPaths.length === 0) return [];
|
|
18623
|
+
try {
|
|
18624
|
+
const output = (0, import_child_process7.execSync)("ps axww -o pid=,args=", {
|
|
18625
|
+
encoding: "utf-8",
|
|
18626
|
+
timeout: 3e3,
|
|
18627
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
18628
|
+
});
|
|
18629
|
+
return findMacAppProcessPids(output, appPaths);
|
|
18630
|
+
} catch {
|
|
18631
|
+
return [];
|
|
18632
|
+
}
|
|
18633
|
+
}
|
|
18634
|
+
function killMacAppPathProcesses(ideId, signal) {
|
|
18635
|
+
const pids = getMacAppProcessPids(ideId);
|
|
18636
|
+
let signalled = false;
|
|
18637
|
+
for (const pid of pids) {
|
|
18638
|
+
try {
|
|
18639
|
+
process.kill(pid, signal);
|
|
18640
|
+
signalled = true;
|
|
18641
|
+
} catch {
|
|
18642
|
+
}
|
|
18643
|
+
}
|
|
18644
|
+
return signalled;
|
|
18645
|
+
}
|
|
18036
18646
|
async function findFreePort(ports) {
|
|
18037
18647
|
for (const port2 of ports) {
|
|
18038
18648
|
const free = await checkPortFree(port2);
|
|
@@ -18094,6 +18704,7 @@ async function killIdeProcess(ideId) {
|
|
|
18094
18704
|
} catch {
|
|
18095
18705
|
}
|
|
18096
18706
|
}
|
|
18707
|
+
killMacAppPathProcesses(ideId, "SIGTERM");
|
|
18097
18708
|
} else if (plat === "win32" && winProcesses) {
|
|
18098
18709
|
for (const proc of winProcesses) {
|
|
18099
18710
|
try {
|
|
@@ -18123,6 +18734,7 @@ async function killIdeProcess(ideId) {
|
|
|
18123
18734
|
(0, import_child_process7.execSync)(`pkill -9 -x "${appName}" 2>/dev/null`, { timeout: 5e3 });
|
|
18124
18735
|
} catch {
|
|
18125
18736
|
}
|
|
18737
|
+
killMacAppPathProcesses(ideId, "SIGKILL");
|
|
18126
18738
|
} else if (plat === "win32" && winProcesses) {
|
|
18127
18739
|
for (const proc of winProcesses) {
|
|
18128
18740
|
try {
|
|
@@ -18142,14 +18754,16 @@ function isIdeRunning(ideId) {
|
|
|
18142
18754
|
try {
|
|
18143
18755
|
if (plat === "darwin") {
|
|
18144
18756
|
const appName = getMacAppIdentifiers()[ideId];
|
|
18145
|
-
if (!appName) return
|
|
18757
|
+
if (!appName) return getMacAppProcessPids(ideId).length > 0;
|
|
18146
18758
|
try {
|
|
18147
18759
|
const result = (0, import_child_process7.execSync)(`pgrep -x "${appName}" 2>/dev/null`, {
|
|
18148
18760
|
encoding: "utf-8",
|
|
18149
18761
|
timeout: 3e3
|
|
18150
18762
|
});
|
|
18151
|
-
|
|
18763
|
+
if (result.trim().length > 0) return true;
|
|
18152
18764
|
} catch {
|
|
18765
|
+
}
|
|
18766
|
+
try {
|
|
18153
18767
|
const result = (0, import_child_process7.execSync)(
|
|
18154
18768
|
`osascript -e 'tell application "System Events" to count (every process whose name is "${escapeForAppleScript(appName)}")'`,
|
|
18155
18769
|
{
|
|
@@ -18158,8 +18772,10 @@ function isIdeRunning(ideId) {
|
|
|
18158
18772
|
stdio: ["pipe", "pipe", "pipe"]
|
|
18159
18773
|
}
|
|
18160
18774
|
);
|
|
18161
|
-
|
|
18775
|
+
if (Number.parseInt(result.trim() || "0", 10) > 0) return true;
|
|
18776
|
+
} catch {
|
|
18162
18777
|
}
|
|
18778
|
+
return getMacAppProcessPids(ideId).length > 0;
|
|
18163
18779
|
} else if (plat === "win32") {
|
|
18164
18780
|
const winProcesses = getWinProcessNames()[ideId];
|
|
18165
18781
|
if (!winProcesses) return false;
|
|
@@ -19526,13 +20142,18 @@ var DaemonCommandRouter = class {
|
|
|
19526
20142
|
const wantsAll = args?.all === true;
|
|
19527
20143
|
const offset = wantsAll ? 0 : Math.max(0, Number(args?.offset) || 0);
|
|
19528
20144
|
const limit = wantsAll ? Number.MAX_SAFE_INTEGER : Math.max(1, Math.min(100, Number(args?.limit) || 30));
|
|
19529
|
-
const
|
|
20145
|
+
const providerMeta = this.deps.providerLoader.getMeta(providerType);
|
|
20146
|
+
const { sessions: historySessions, hasMore, source } = listProviderHistorySessions(providerType, {
|
|
20147
|
+
canonicalHistory: providerMeta?.canonicalHistory,
|
|
20148
|
+
offset,
|
|
20149
|
+
limit,
|
|
20150
|
+
historyBehavior: providerMeta?.historyBehavior
|
|
20151
|
+
});
|
|
19530
20152
|
const state = loadState();
|
|
19531
20153
|
const savedSessions = getSavedProviderSessions(state, { providerType, kind });
|
|
19532
20154
|
const recentSessions = getRecentActivity(state, 200).filter((entry) => entry.providerType === providerType && entry.kind === kind && entry.providerSessionId);
|
|
19533
20155
|
const savedSessionById = new Map(savedSessions.map((entry) => [entry.providerSessionId, entry]));
|
|
19534
20156
|
const recentSessionById = new Map(recentSessions.map((entry) => [entry.providerSessionId, entry]));
|
|
19535
|
-
const providerMeta = this.deps.providerLoader.getMeta(providerType);
|
|
19536
20157
|
const canResumeById = supportsExplicitSessionResume(providerMeta?.resume);
|
|
19537
20158
|
return {
|
|
19538
20159
|
success: true,
|
|
@@ -19555,7 +20176,8 @@ var DaemonCommandRouter = class {
|
|
|
19555
20176
|
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById
|
|
19556
20177
|
};
|
|
19557
20178
|
}),
|
|
19558
|
-
hasMore
|
|
20179
|
+
hasMore,
|
|
20180
|
+
source
|
|
19559
20181
|
};
|
|
19560
20182
|
}
|
|
19561
20183
|
// ─── restart_session: IDE / CLI / ACP unified ───
|