@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.mjs
CHANGED
|
@@ -980,6 +980,8 @@ function validateReadChatResultPayload(raw, source = "read_chat") {
|
|
|
980
980
|
if (raw.summaryMetadata !== void 0) normalized.summaryMetadata = raw.summaryMetadata;
|
|
981
981
|
if (Array.isArray(raw.effects)) normalized.effects = raw.effects;
|
|
982
982
|
if (typeof raw.providerSessionId === "string") normalized.providerSessionId = raw.providerSessionId;
|
|
983
|
+
if (raw.transcriptAuthority === "provider" || raw.transcriptAuthority === "daemon") normalized.transcriptAuthority = raw.transcriptAuthority;
|
|
984
|
+
if (raw.coverage === "full" || raw.coverage === "tail" || raw.coverage === "current-turn") normalized.coverage = raw.coverage;
|
|
983
985
|
return normalized;
|
|
984
986
|
}
|
|
985
987
|
var VALID_STATUSES, VALID_ROLES, VALID_BUBBLE_STATES, VALID_TURN_STATUSES;
|
|
@@ -2056,7 +2058,8 @@ __export(provider_cli_adapter_exports, {
|
|
|
2056
2058
|
ProviderCliAdapter: () => ProviderCliAdapter,
|
|
2057
2059
|
appendBoundedText: () => appendBoundedText,
|
|
2058
2060
|
normalizeCliProviderForRuntime: () => normalizeCliProviderForRuntime,
|
|
2059
|
-
sanitizeCliStandardMessageContent: () => sanitizeCliStandardMessageContent
|
|
2061
|
+
sanitizeCliStandardMessageContent: () => sanitizeCliStandardMessageContent,
|
|
2062
|
+
trimLastAssistantEchoForCliMessages: () => trimLastAssistantEchoForCliMessages
|
|
2060
2063
|
});
|
|
2061
2064
|
import * as os10 from "os";
|
|
2062
2065
|
function normalizeComparableTranscriptText(value) {
|
|
@@ -2153,6 +2156,19 @@ function sanitizeCommittedMessageForDisplay(message) {
|
|
|
2153
2156
|
if (content === message.content) return message;
|
|
2154
2157
|
return { ...message, content };
|
|
2155
2158
|
}
|
|
2159
|
+
function trimLastAssistantEchoForCliMessages(messages, prompt) {
|
|
2160
|
+
if (!prompt) return;
|
|
2161
|
+
for (let index = messages.length - 1; index >= 0; index -= 1) {
|
|
2162
|
+
const message = messages[index];
|
|
2163
|
+
if (!message || message.role !== "assistant" || typeof message.content !== "string") continue;
|
|
2164
|
+
if ((message.kind || "standard") !== "standard") continue;
|
|
2165
|
+
message.content = trimPromptEchoPrefix(message.content, prompt);
|
|
2166
|
+
if (!message.content.trim()) {
|
|
2167
|
+
messages.splice(index, 1);
|
|
2168
|
+
}
|
|
2169
|
+
return;
|
|
2170
|
+
}
|
|
2171
|
+
}
|
|
2156
2172
|
var COMMITTED_ACTIVITY_PREFIX_BLOCK_RE, ProviderCliAdapter;
|
|
2157
2173
|
var init_provider_cli_adapter = __esm({
|
|
2158
2174
|
"src/cli-adapters/provider-cli-adapter.ts"() {
|
|
@@ -2349,7 +2365,14 @@ var init_provider_cli_adapter = __esm({
|
|
|
2349
2365
|
}
|
|
2350
2366
|
return null;
|
|
2351
2367
|
}
|
|
2368
|
+
providerOwnsTranscript() {
|
|
2369
|
+
return this.provider.transcriptAuthority === "provider";
|
|
2370
|
+
}
|
|
2371
|
+
shouldUseFullProviderTranscriptContext() {
|
|
2372
|
+
return this.providerOwnsTranscript() && this.provider.transcriptContext === "full";
|
|
2373
|
+
}
|
|
2352
2374
|
selectParseBaseMessages(baseMessages) {
|
|
2375
|
+
if (this.shouldUseFullProviderTranscriptContext()) return baseMessages;
|
|
2353
2376
|
if (baseMessages.length <= _ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT) return baseMessages;
|
|
2354
2377
|
return baseMessages.slice(-_ProviderCliAdapter.PARSE_MESSAGE_TAIL_LIMIT);
|
|
2355
2378
|
}
|
|
@@ -2832,9 +2855,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
2832
2855
|
);
|
|
2833
2856
|
}
|
|
2834
2857
|
trimLastAssistantEcho(messages, prompt) {
|
|
2835
|
-
|
|
2836
|
-
const last = [...messages].reverse().find((m) => m.role === "assistant" && typeof m.content === "string");
|
|
2837
|
-
if (last) last.content = trimPromptEchoPrefix(last.content, prompt);
|
|
2858
|
+
trimLastAssistantEchoForCliMessages(messages, prompt);
|
|
2838
2859
|
}
|
|
2839
2860
|
clearAllTimers() {
|
|
2840
2861
|
if (this.responseTimeout) {
|
|
@@ -3688,7 +3709,8 @@ var init_provider_cli_adapter = __esm({
|
|
|
3688
3709
|
title: parsed.title || this.cliName,
|
|
3689
3710
|
messages: hydratedMessages,
|
|
3690
3711
|
activeModal: parsed.activeModal ?? this.activeModal,
|
|
3691
|
-
providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0
|
|
3712
|
+
providerSessionId: typeof parsed.providerSessionId === "string" ? parsed.providerSessionId : void 0,
|
|
3713
|
+
...this.providerOwnsTranscript() ? { transcriptAuthority: "provider", coverage: this.shouldUseFullProviderTranscriptContext() ? "full" : "tail" } : {}
|
|
3692
3714
|
};
|
|
3693
3715
|
} else {
|
|
3694
3716
|
const messages = [...this.committedMessages];
|
|
@@ -7872,6 +7894,27 @@ var ChatHistoryWriter = class {
|
|
|
7872
7894
|
return name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
7873
7895
|
}
|
|
7874
7896
|
};
|
|
7897
|
+
function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeRecentCount = 0, historyBehavior) {
|
|
7898
|
+
const allMessages = records.map((message) => sanitizeHistoryMessage(agentType, message)).filter(Boolean);
|
|
7899
|
+
allMessages.sort((a, b) => a.receivedAt - b.receivedAt);
|
|
7900
|
+
const chronological = [];
|
|
7901
|
+
let lastTurn = null;
|
|
7902
|
+
for (const message of allMessages) {
|
|
7903
|
+
const previous = chronological[chronological.length - 1];
|
|
7904
|
+
if (isAdjacentHistoryDuplicate(agentType, previous, message)) continue;
|
|
7905
|
+
if (message.role !== "system" && isAdjacentHistoryDuplicate(agentType, lastTurn, message)) continue;
|
|
7906
|
+
chronological.push(message);
|
|
7907
|
+
if (message.role !== "system") lastTurn = message;
|
|
7908
|
+
}
|
|
7909
|
+
const collapsed = collapseReplayAssistantTurns(chronological, historyBehavior);
|
|
7910
|
+
const boundedLimit = Math.max(1, limit);
|
|
7911
|
+
const boundedOffset = Math.max(0, offset);
|
|
7912
|
+
const boundedExclude = Math.max(0, Math.min(excludeRecentCount, collapsed.length));
|
|
7913
|
+
const endExclusive = Math.max(0, collapsed.length - boundedExclude - boundedOffset);
|
|
7914
|
+
const startInclusive = Math.max(0, endExclusive - boundedLimit);
|
|
7915
|
+
const sliced = collapsed.slice(startInclusive, endExclusive);
|
|
7916
|
+
return { messages: sliced, hasMore: startInclusive > 0 };
|
|
7917
|
+
}
|
|
7875
7918
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
7876
7919
|
try {
|
|
7877
7920
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
@@ -7897,25 +7940,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
7897
7940
|
}
|
|
7898
7941
|
}
|
|
7899
7942
|
}
|
|
7900
|
-
|
|
7901
|
-
const chronological = [];
|
|
7902
|
-
let lastTurn = null;
|
|
7903
|
-
for (const message of allMessages) {
|
|
7904
|
-
const previous = chronological[chronological.length - 1];
|
|
7905
|
-
if (isAdjacentHistoryDuplicate(agentType, previous, message)) continue;
|
|
7906
|
-
if (message.role !== "system" && isAdjacentHistoryDuplicate(agentType, lastTurn, message)) continue;
|
|
7907
|
-
chronological.push(message);
|
|
7908
|
-
if (message.role !== "system") lastTurn = message;
|
|
7909
|
-
}
|
|
7910
|
-
const collapsed = collapseReplayAssistantTurns(chronological, historyBehavior);
|
|
7911
|
-
const boundedLimit = Math.max(1, limit);
|
|
7912
|
-
const boundedOffset = Math.max(0, offset);
|
|
7913
|
-
const boundedExclude = Math.max(0, Math.min(excludeRecentCount, collapsed.length));
|
|
7914
|
-
const endExclusive = Math.max(0, collapsed.length - boundedExclude - boundedOffset);
|
|
7915
|
-
const startInclusive = Math.max(0, endExclusive - boundedLimit);
|
|
7916
|
-
const sliced = collapsed.slice(startInclusive, endExclusive);
|
|
7917
|
-
const hasMore = startInclusive > 0;
|
|
7918
|
-
return { messages: sliced, hasMore };
|
|
7943
|
+
return pageHistoryRecords(agentType, allMessages, offset, limit, excludeRecentCount, historyBehavior);
|
|
7919
7944
|
} catch {
|
|
7920
7945
|
return { messages: [], hasMore: false };
|
|
7921
7946
|
}
|
|
@@ -8050,6 +8075,52 @@ function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
|
8050
8075
|
return false;
|
|
8051
8076
|
}
|
|
8052
8077
|
}
|
|
8078
|
+
function buildHermesNativeHistoryRecords(historySessionId) {
|
|
8079
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8080
|
+
if (!normalizedSessionId) return null;
|
|
8081
|
+
try {
|
|
8082
|
+
const sessionFilePath = path7.join(os5.homedir(), ".hermes", "sessions", `session_${normalizedSessionId}.json`);
|
|
8083
|
+
if (!fs3.existsSync(sessionFilePath)) return null;
|
|
8084
|
+
const raw = JSON.parse(fs3.readFileSync(sessionFilePath, "utf-8"));
|
|
8085
|
+
const canonicalMessages = Array.isArray(raw.messages) ? raw.messages : [];
|
|
8086
|
+
const records = [];
|
|
8087
|
+
let fallbackTs = Date.parse(raw.session_start || raw.last_updated || "") || Date.now();
|
|
8088
|
+
for (const message of canonicalMessages) {
|
|
8089
|
+
const role = String(message.role || "").trim();
|
|
8090
|
+
const content = normalizeCanonicalHermesMessageContent(message.content);
|
|
8091
|
+
if (!content) continue;
|
|
8092
|
+
const receivedAt = extractCanonicalHermesMessageTimestamp(message, fallbackTs);
|
|
8093
|
+
fallbackTs = receivedAt + 1;
|
|
8094
|
+
if (role === "user" || role === "assistant") {
|
|
8095
|
+
records.push({
|
|
8096
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8097
|
+
receivedAt,
|
|
8098
|
+
role,
|
|
8099
|
+
content,
|
|
8100
|
+
kind: "standard",
|
|
8101
|
+
agent: "hermes-cli",
|
|
8102
|
+
historySessionId: normalizedSessionId
|
|
8103
|
+
});
|
|
8104
|
+
continue;
|
|
8105
|
+
}
|
|
8106
|
+
if (role === "tool") {
|
|
8107
|
+
records.push({
|
|
8108
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8109
|
+
receivedAt,
|
|
8110
|
+
role: "assistant",
|
|
8111
|
+
content,
|
|
8112
|
+
kind: "tool",
|
|
8113
|
+
senderName: "Tool",
|
|
8114
|
+
agent: "hermes-cli",
|
|
8115
|
+
historySessionId: normalizedSessionId
|
|
8116
|
+
});
|
|
8117
|
+
}
|
|
8118
|
+
}
|
|
8119
|
+
return records;
|
|
8120
|
+
} catch {
|
|
8121
|
+
return null;
|
|
8122
|
+
}
|
|
8123
|
+
}
|
|
8053
8124
|
function rebuildHermesSavedHistoryFromCanonicalSession(historySessionId) {
|
|
8054
8125
|
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8055
8126
|
if (!normalizedSessionId) return false;
|
|
@@ -8199,6 +8270,77 @@ function extractClaudeUserContentParts(content) {
|
|
|
8199
8270
|
}
|
|
8200
8271
|
return parts;
|
|
8201
8272
|
}
|
|
8273
|
+
function buildClaudeNativeHistoryRecords(historySessionId, workspace) {
|
|
8274
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8275
|
+
if (!normalizedSessionId) return null;
|
|
8276
|
+
try {
|
|
8277
|
+
const transcriptPath = resolveClaudeProjectTranscriptPath(normalizedSessionId, workspace);
|
|
8278
|
+
if (!transcriptPath) return null;
|
|
8279
|
+
const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
|
|
8280
|
+
const records = [];
|
|
8281
|
+
let fallbackTs = Date.now();
|
|
8282
|
+
for (const line of lines) {
|
|
8283
|
+
let parsed = null;
|
|
8284
|
+
try {
|
|
8285
|
+
parsed = JSON.parse(line);
|
|
8286
|
+
} catch {
|
|
8287
|
+
parsed = null;
|
|
8288
|
+
}
|
|
8289
|
+
if (!parsed) continue;
|
|
8290
|
+
const parsedSessionId = String(parsed.sessionId || "").trim();
|
|
8291
|
+
if (parsedSessionId && parsedSessionId !== normalizedSessionId) continue;
|
|
8292
|
+
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
8293
|
+
fallbackTs = receivedAt + 1;
|
|
8294
|
+
const parsedWorkspace = String(parsed.cwd || workspace || "").trim();
|
|
8295
|
+
if (records.length === 0 && parsedWorkspace) {
|
|
8296
|
+
records.push({
|
|
8297
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8298
|
+
receivedAt,
|
|
8299
|
+
role: "system",
|
|
8300
|
+
kind: "session_start",
|
|
8301
|
+
content: parsedWorkspace,
|
|
8302
|
+
agent: "claude-cli",
|
|
8303
|
+
historySessionId: normalizedSessionId,
|
|
8304
|
+
workspace: parsedWorkspace
|
|
8305
|
+
});
|
|
8306
|
+
}
|
|
8307
|
+
const type = String(parsed.type || "").trim();
|
|
8308
|
+
const message = parsed.message && typeof parsed.message === "object" ? parsed.message : null;
|
|
8309
|
+
if (type === "user" && message) {
|
|
8310
|
+
for (const part of extractClaudeUserContentParts(message.content)) {
|
|
8311
|
+
records.push({
|
|
8312
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8313
|
+
receivedAt,
|
|
8314
|
+
role: part.role,
|
|
8315
|
+
content: part.content,
|
|
8316
|
+
kind: part.kind,
|
|
8317
|
+
senderName: part.senderName,
|
|
8318
|
+
agent: "claude-cli",
|
|
8319
|
+
historySessionId: normalizedSessionId
|
|
8320
|
+
});
|
|
8321
|
+
}
|
|
8322
|
+
continue;
|
|
8323
|
+
}
|
|
8324
|
+
if (type === "assistant" && message) {
|
|
8325
|
+
for (const part of extractClaudeAssistantContentParts(message.content)) {
|
|
8326
|
+
records.push({
|
|
8327
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8328
|
+
receivedAt,
|
|
8329
|
+
role: "assistant",
|
|
8330
|
+
content: part.content,
|
|
8331
|
+
kind: part.kind,
|
|
8332
|
+
senderName: part.senderName,
|
|
8333
|
+
agent: "claude-cli",
|
|
8334
|
+
historySessionId: normalizedSessionId
|
|
8335
|
+
});
|
|
8336
|
+
}
|
|
8337
|
+
}
|
|
8338
|
+
}
|
|
8339
|
+
return records;
|
|
8340
|
+
} catch {
|
|
8341
|
+
return null;
|
|
8342
|
+
}
|
|
8343
|
+
}
|
|
8202
8344
|
function rebuildClaudeSavedHistoryFromNativeProject(historySessionId, workspace) {
|
|
8203
8345
|
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8204
8346
|
if (!normalizedSessionId) return false;
|
|
@@ -8277,6 +8419,352 @@ function rebuildClaudeSavedHistoryFromNativeProject(historySessionId, workspace)
|
|
|
8277
8419
|
return false;
|
|
8278
8420
|
}
|
|
8279
8421
|
}
|
|
8422
|
+
function isUuidLikeSessionId(sessionId) {
|
|
8423
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(sessionId);
|
|
8424
|
+
}
|
|
8425
|
+
function readCodexSessionMeta(filePath) {
|
|
8426
|
+
try {
|
|
8427
|
+
const firstLine = fs3.readFileSync(filePath, "utf-8").split("\n").find(Boolean);
|
|
8428
|
+
if (!firstLine) return null;
|
|
8429
|
+
const parsed = JSON.parse(firstLine);
|
|
8430
|
+
if (String(parsed.type || "") !== "session_meta") return null;
|
|
8431
|
+
const payload = parsed.payload && typeof parsed.payload === "object" ? parsed.payload : null;
|
|
8432
|
+
return payload;
|
|
8433
|
+
} catch {
|
|
8434
|
+
return null;
|
|
8435
|
+
}
|
|
8436
|
+
}
|
|
8437
|
+
function resolveCodexSessionTranscriptPath(historySessionId, workspace) {
|
|
8438
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8439
|
+
if (!normalizedSessionId || !isUuidLikeSessionId(normalizedSessionId)) return null;
|
|
8440
|
+
const sessionsDir = path7.join(os5.homedir(), ".codex", "sessions");
|
|
8441
|
+
if (!fs3.existsSync(sessionsDir)) return null;
|
|
8442
|
+
const normalizedWorkspace = typeof workspace === "string" ? workspace.trim() : "";
|
|
8443
|
+
const candidates = [];
|
|
8444
|
+
const stack = [sessionsDir];
|
|
8445
|
+
while (stack.length > 0) {
|
|
8446
|
+
const current = stack.pop();
|
|
8447
|
+
if (!current) continue;
|
|
8448
|
+
let entries = [];
|
|
8449
|
+
try {
|
|
8450
|
+
entries = fs3.readdirSync(current, { withFileTypes: true });
|
|
8451
|
+
} catch {
|
|
8452
|
+
continue;
|
|
8453
|
+
}
|
|
8454
|
+
for (const entry of entries) {
|
|
8455
|
+
const entryPath = path7.join(current, entry.name);
|
|
8456
|
+
if (entry.isDirectory()) {
|
|
8457
|
+
stack.push(entryPath);
|
|
8458
|
+
continue;
|
|
8459
|
+
}
|
|
8460
|
+
if (!entry.isFile() || !entry.name.endsWith(".jsonl") || !entry.name.includes(normalizedSessionId)) continue;
|
|
8461
|
+
const meta = readCodexSessionMeta(entryPath);
|
|
8462
|
+
const metaSessionId = String(meta?.id || "").trim();
|
|
8463
|
+
if (metaSessionId && metaSessionId !== normalizedSessionId) continue;
|
|
8464
|
+
const metaWorkspace = String(meta?.cwd || "").trim();
|
|
8465
|
+
let mtimeMs = 0;
|
|
8466
|
+
try {
|
|
8467
|
+
mtimeMs = fs3.statSync(entryPath).mtimeMs;
|
|
8468
|
+
} catch {
|
|
8469
|
+
}
|
|
8470
|
+
candidates.push({
|
|
8471
|
+
path: entryPath,
|
|
8472
|
+
mtimeMs,
|
|
8473
|
+
workspaceMatches: !!normalizedWorkspace && metaWorkspace === normalizedWorkspace,
|
|
8474
|
+
metaMatches: metaSessionId === normalizedSessionId
|
|
8475
|
+
});
|
|
8476
|
+
}
|
|
8477
|
+
}
|
|
8478
|
+
candidates.sort((a, b) => Number(b.workspaceMatches) - Number(a.workspaceMatches) || Number(b.metaMatches) - Number(a.metaMatches) || b.mtimeMs - a.mtimeMs);
|
|
8479
|
+
return candidates[0]?.path || null;
|
|
8480
|
+
}
|
|
8481
|
+
function flattenCodexContent(content) {
|
|
8482
|
+
if (typeof content === "string") return content.trim();
|
|
8483
|
+
if (content == null) return "";
|
|
8484
|
+
if (Array.isArray(content)) {
|
|
8485
|
+
return content.map((entry) => flattenCodexContent(entry)).filter(Boolean).join("\n").trim();
|
|
8486
|
+
}
|
|
8487
|
+
if (typeof content === "object") {
|
|
8488
|
+
const record = content;
|
|
8489
|
+
if (typeof record.text === "string") return record.text.trim();
|
|
8490
|
+
if (typeof record.content === "string" || Array.isArray(record.content)) return flattenCodexContent(record.content);
|
|
8491
|
+
if (typeof record.output === "string") return record.output.trim();
|
|
8492
|
+
if (typeof record.message === "string") return record.message.trim();
|
|
8493
|
+
}
|
|
8494
|
+
return "";
|
|
8495
|
+
}
|
|
8496
|
+
function summarizeCodexToolCall(payload) {
|
|
8497
|
+
const name = String(payload.name || payload.type || "tool").trim() || "tool";
|
|
8498
|
+
const rawArguments = payload.arguments ?? payload.input;
|
|
8499
|
+
let argumentValue = "";
|
|
8500
|
+
if (typeof rawArguments === "string") {
|
|
8501
|
+
const trimmed = rawArguments.trim();
|
|
8502
|
+
try {
|
|
8503
|
+
const parsed = JSON.parse(trimmed);
|
|
8504
|
+
argumentValue = summarizeCodexToolArguments(parsed);
|
|
8505
|
+
} catch {
|
|
8506
|
+
argumentValue = trimmed;
|
|
8507
|
+
}
|
|
8508
|
+
} else {
|
|
8509
|
+
argumentValue = summarizeCodexToolArguments(rawArguments);
|
|
8510
|
+
}
|
|
8511
|
+
return argumentValue ? `${name}: ${argumentValue}` : name;
|
|
8512
|
+
}
|
|
8513
|
+
function summarizeCodexToolArguments(value) {
|
|
8514
|
+
if (typeof value === "string") return value.trim();
|
|
8515
|
+
if (Array.isArray(value)) return value.map((entry) => String(entry)).join(" ").trim();
|
|
8516
|
+
if (!value || typeof value !== "object") return "";
|
|
8517
|
+
const record = value;
|
|
8518
|
+
const direct = record.command || record.cmd || record.query || record.path || record.prompt;
|
|
8519
|
+
if (typeof direct === "string") return direct.trim();
|
|
8520
|
+
if (Array.isArray(direct)) return direct.map((entry) => String(entry)).join(" ").trim();
|
|
8521
|
+
try {
|
|
8522
|
+
return JSON.stringify(record).trim();
|
|
8523
|
+
} catch {
|
|
8524
|
+
return "";
|
|
8525
|
+
}
|
|
8526
|
+
}
|
|
8527
|
+
function codexToolOutputContent(payload) {
|
|
8528
|
+
const output = payload.output ?? payload.result ?? payload.content;
|
|
8529
|
+
const text = flattenCodexContent(output);
|
|
8530
|
+
if (text) return text;
|
|
8531
|
+
if (output && typeof output === "object") {
|
|
8532
|
+
try {
|
|
8533
|
+
return JSON.stringify(output).trim();
|
|
8534
|
+
} catch {
|
|
8535
|
+
return "";
|
|
8536
|
+
}
|
|
8537
|
+
}
|
|
8538
|
+
return "";
|
|
8539
|
+
}
|
|
8540
|
+
function buildCodexNativeHistoryRecords(historySessionId, workspace) {
|
|
8541
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8542
|
+
if (!normalizedSessionId || !isUuidLikeSessionId(normalizedSessionId)) return null;
|
|
8543
|
+
try {
|
|
8544
|
+
const transcriptPath = resolveCodexSessionTranscriptPath(normalizedSessionId, workspace);
|
|
8545
|
+
if (!transcriptPath) return null;
|
|
8546
|
+
const lines = fs3.readFileSync(transcriptPath, "utf-8").split("\n").filter(Boolean);
|
|
8547
|
+
const records = [];
|
|
8548
|
+
let fallbackTs = Date.now();
|
|
8549
|
+
for (const line of lines) {
|
|
8550
|
+
let parsed = null;
|
|
8551
|
+
try {
|
|
8552
|
+
parsed = JSON.parse(line);
|
|
8553
|
+
} catch {
|
|
8554
|
+
parsed = null;
|
|
8555
|
+
}
|
|
8556
|
+
if (!parsed) continue;
|
|
8557
|
+
const receivedAt = extractTimestampValue(parsed.timestamp) || fallbackTs;
|
|
8558
|
+
fallbackTs = receivedAt + 1;
|
|
8559
|
+
const type = String(parsed.type || "").trim();
|
|
8560
|
+
const payload = parsed.payload && typeof parsed.payload === "object" ? parsed.payload : null;
|
|
8561
|
+
if (!payload) continue;
|
|
8562
|
+
if (type === "session_meta") {
|
|
8563
|
+
const parsedSessionId = String(payload.id || "").trim();
|
|
8564
|
+
if (parsedSessionId && parsedSessionId !== normalizedSessionId) return null;
|
|
8565
|
+
const parsedWorkspace = String(payload.cwd || workspace || "").trim();
|
|
8566
|
+
if (records.length === 0 && parsedWorkspace) {
|
|
8567
|
+
records.push({
|
|
8568
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8569
|
+
receivedAt,
|
|
8570
|
+
role: "system",
|
|
8571
|
+
kind: "session_start",
|
|
8572
|
+
content: parsedWorkspace,
|
|
8573
|
+
agent: "codex-cli",
|
|
8574
|
+
historySessionId: normalizedSessionId,
|
|
8575
|
+
workspace: parsedWorkspace
|
|
8576
|
+
});
|
|
8577
|
+
}
|
|
8578
|
+
continue;
|
|
8579
|
+
}
|
|
8580
|
+
if (type !== "response_item") continue;
|
|
8581
|
+
const payloadType = String(payload.type || "").trim();
|
|
8582
|
+
if (payloadType === "message") {
|
|
8583
|
+
const role = String(payload.role || "").trim();
|
|
8584
|
+
if (role !== "user" && role !== "assistant") continue;
|
|
8585
|
+
const content = flattenCodexContent(payload.content);
|
|
8586
|
+
if (!content) continue;
|
|
8587
|
+
records.push({
|
|
8588
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8589
|
+
receivedAt,
|
|
8590
|
+
role,
|
|
8591
|
+
content,
|
|
8592
|
+
kind: "standard",
|
|
8593
|
+
agent: "codex-cli",
|
|
8594
|
+
historySessionId: normalizedSessionId
|
|
8595
|
+
});
|
|
8596
|
+
continue;
|
|
8597
|
+
}
|
|
8598
|
+
if (payloadType === "function_call" || payloadType === "custom_tool_call") {
|
|
8599
|
+
const content = summarizeCodexToolCall(payload);
|
|
8600
|
+
if (!content) continue;
|
|
8601
|
+
records.push({
|
|
8602
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8603
|
+
receivedAt,
|
|
8604
|
+
role: "assistant",
|
|
8605
|
+
content,
|
|
8606
|
+
kind: "tool",
|
|
8607
|
+
senderName: "Tool",
|
|
8608
|
+
agent: "codex-cli",
|
|
8609
|
+
historySessionId: normalizedSessionId
|
|
8610
|
+
});
|
|
8611
|
+
continue;
|
|
8612
|
+
}
|
|
8613
|
+
if (payloadType === "function_call_output" || payloadType === "custom_tool_call_output") {
|
|
8614
|
+
const content = codexToolOutputContent(payload);
|
|
8615
|
+
if (!content) continue;
|
|
8616
|
+
records.push({
|
|
8617
|
+
ts: new Date(receivedAt).toISOString(),
|
|
8618
|
+
receivedAt,
|
|
8619
|
+
role: "assistant",
|
|
8620
|
+
content,
|
|
8621
|
+
kind: "tool",
|
|
8622
|
+
senderName: "Tool",
|
|
8623
|
+
agent: "codex-cli",
|
|
8624
|
+
historySessionId: normalizedSessionId
|
|
8625
|
+
});
|
|
8626
|
+
}
|
|
8627
|
+
}
|
|
8628
|
+
return records;
|
|
8629
|
+
} catch {
|
|
8630
|
+
return null;
|
|
8631
|
+
}
|
|
8632
|
+
}
|
|
8633
|
+
function rebuildCodexSavedHistoryFromNativeSession(historySessionId, workspace) {
|
|
8634
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId);
|
|
8635
|
+
if (!normalizedSessionId || !isUuidLikeSessionId(normalizedSessionId)) return false;
|
|
8636
|
+
const records = buildCodexNativeHistoryRecords(normalizedSessionId, workspace);
|
|
8637
|
+
if (!records || records.length === 0) return false;
|
|
8638
|
+
const existingSessionStart = readExistingSessionStartRecord("codex-cli", normalizedSessionId);
|
|
8639
|
+
const recordsToWrite = existingSessionStart && records[0]?.kind !== "session_start" ? [{ ...existingSessionStart, historySessionId: normalizedSessionId }, ...records] : records;
|
|
8640
|
+
return rewriteCanonicalSavedHistory("codex-cli", normalizedSessionId, recordsToWrite);
|
|
8641
|
+
}
|
|
8642
|
+
function isNativeSourceCanonicalHistory(canonicalHistory) {
|
|
8643
|
+
if (!canonicalHistory) return false;
|
|
8644
|
+
if (canonicalHistory.mode === "disabled") return false;
|
|
8645
|
+
if (canonicalHistory.mode === "materialized-mirror") return false;
|
|
8646
|
+
return true;
|
|
8647
|
+
}
|
|
8648
|
+
function buildNativeHistoryRecords(canonicalHistory, historySessionId, workspace) {
|
|
8649
|
+
const normalizedSessionId = normalizeSavedHistorySessionId(historySessionId || "");
|
|
8650
|
+
if (!canonicalHistory || !normalizedSessionId || !isNativeSourceCanonicalHistory(canonicalHistory)) return null;
|
|
8651
|
+
if (canonicalHistory.format === "hermes-json") return buildHermesNativeHistoryRecords(normalizedSessionId);
|
|
8652
|
+
if (canonicalHistory.format === "claude-jsonl") return buildClaudeNativeHistoryRecords(normalizedSessionId, workspace);
|
|
8653
|
+
if (canonicalHistory.format === "codex-jsonl") return buildCodexNativeHistoryRecords(normalizedSessionId, workspace);
|
|
8654
|
+
return null;
|
|
8655
|
+
}
|
|
8656
|
+
function readProviderChatHistory(agentType, options = {}) {
|
|
8657
|
+
if (isNativeSourceCanonicalHistory(options.canonicalHistory) && options.historySessionId) {
|
|
8658
|
+
const records = buildNativeHistoryRecords(options.canonicalHistory, options.historySessionId, options.workspace);
|
|
8659
|
+
if (!records) return { messages: [], hasMore: false, source: "native-unavailable" };
|
|
8660
|
+
return {
|
|
8661
|
+
...pageHistoryRecords(agentType, records, options.offset || 0, options.limit || 30, options.excludeRecentCount || 0, options.historyBehavior),
|
|
8662
|
+
source: "provider-native"
|
|
8663
|
+
};
|
|
8664
|
+
}
|
|
8665
|
+
return {
|
|
8666
|
+
...readChatHistory(agentType, options.offset || 0, options.limit || 30, options.historySessionId, options.excludeRecentCount || 0, options.historyBehavior),
|
|
8667
|
+
source: "adhdev-mirror"
|
|
8668
|
+
};
|
|
8669
|
+
}
|
|
8670
|
+
function buildNativeSessionSummary(agentType, historySessionId, records, sourcePath) {
|
|
8671
|
+
const visible = pageHistoryRecords(agentType, records, 0, Number.MAX_SAFE_INTEGER).messages;
|
|
8672
|
+
if (visible.length === 0) return null;
|
|
8673
|
+
let sourceMtimeMs = 0;
|
|
8674
|
+
try {
|
|
8675
|
+
sourceMtimeMs = fs3.statSync(sourcePath).mtimeMs;
|
|
8676
|
+
} catch {
|
|
8677
|
+
}
|
|
8678
|
+
const firstMessageAt = visible[0]?.receivedAt || sourceMtimeMs || Date.now();
|
|
8679
|
+
const lastMessageAt = visible[visible.length - 1]?.receivedAt || firstMessageAt;
|
|
8680
|
+
const lastNonSystem = [...visible].reverse().find((message) => message.role !== "system") || visible[visible.length - 1];
|
|
8681
|
+
const firstSystem = visible.find((message) => message.kind === "session_start");
|
|
8682
|
+
return {
|
|
8683
|
+
historySessionId,
|
|
8684
|
+
sessionTitle: lastNonSystem?.content,
|
|
8685
|
+
messageCount: visible.length,
|
|
8686
|
+
firstMessageAt,
|
|
8687
|
+
lastMessageAt,
|
|
8688
|
+
preview: lastNonSystem?.content,
|
|
8689
|
+
workspace: firstSystem?.workspace || (firstSystem?.kind === "session_start" ? firstSystem.content : void 0),
|
|
8690
|
+
source: "provider-native",
|
|
8691
|
+
sourcePath,
|
|
8692
|
+
sourceMtimeMs
|
|
8693
|
+
};
|
|
8694
|
+
}
|
|
8695
|
+
function listFilesRecursive(root, predicate) {
|
|
8696
|
+
if (!fs3.existsSync(root)) return [];
|
|
8697
|
+
const results = [];
|
|
8698
|
+
const stack = [root];
|
|
8699
|
+
while (stack.length > 0) {
|
|
8700
|
+
const current = stack.pop();
|
|
8701
|
+
if (!current) continue;
|
|
8702
|
+
let entries = [];
|
|
8703
|
+
try {
|
|
8704
|
+
entries = fs3.readdirSync(current, { withFileTypes: true });
|
|
8705
|
+
} catch {
|
|
8706
|
+
continue;
|
|
8707
|
+
}
|
|
8708
|
+
for (const entry of entries) {
|
|
8709
|
+
const entryPath = path7.join(current, entry.name);
|
|
8710
|
+
if (entry.isDirectory()) {
|
|
8711
|
+
stack.push(entryPath);
|
|
8712
|
+
continue;
|
|
8713
|
+
}
|
|
8714
|
+
if (predicate(entryPath, entry)) results.push(entryPath);
|
|
8715
|
+
}
|
|
8716
|
+
}
|
|
8717
|
+
return results;
|
|
8718
|
+
}
|
|
8719
|
+
function collectNativeHistorySessionSummaries(agentType, canonicalHistory) {
|
|
8720
|
+
const summaries = [];
|
|
8721
|
+
if (canonicalHistory.format === "hermes-json") {
|
|
8722
|
+
const root = path7.join(os5.homedir(), ".hermes", "sessions");
|
|
8723
|
+
for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && /^session_.+\.json$/.test(entry.name))) {
|
|
8724
|
+
const fileName = path7.basename(filePath);
|
|
8725
|
+
const historySessionId = fileName.replace(/^session_/, "").replace(/\.json$/, "");
|
|
8726
|
+
const records = buildHermesNativeHistoryRecords(historySessionId);
|
|
8727
|
+
const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
|
|
8728
|
+
if (summary) summaries.push(summary);
|
|
8729
|
+
}
|
|
8730
|
+
} else if (canonicalHistory.format === "claude-jsonl") {
|
|
8731
|
+
const root = path7.join(os5.homedir(), ".claude", "projects");
|
|
8732
|
+
for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && entry.name.endsWith(".jsonl"))) {
|
|
8733
|
+
const historySessionId = path7.basename(filePath, ".jsonl");
|
|
8734
|
+
const records = buildClaudeNativeHistoryRecords(historySessionId);
|
|
8735
|
+
const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
|
|
8736
|
+
if (summary) summaries.push(summary);
|
|
8737
|
+
}
|
|
8738
|
+
} else if (canonicalHistory.format === "codex-jsonl") {
|
|
8739
|
+
const root = path7.join(os5.homedir(), ".codex", "sessions");
|
|
8740
|
+
const uuidPattern = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/i;
|
|
8741
|
+
for (const filePath of listFilesRecursive(root, (_entryPath, entry) => entry.isFile() && entry.name.endsWith(".jsonl"))) {
|
|
8742
|
+
const meta = readCodexSessionMeta(filePath);
|
|
8743
|
+
const historySessionId = String(meta?.id || path7.basename(filePath).match(uuidPattern)?.[1] || "").trim();
|
|
8744
|
+
if (!historySessionId) continue;
|
|
8745
|
+
const records = buildCodexNativeHistoryRecords(historySessionId, String(meta?.cwd || "").trim() || void 0);
|
|
8746
|
+
const summary = records ? buildNativeSessionSummary(agentType, historySessionId, records, filePath) : null;
|
|
8747
|
+
if (summary) summaries.push(summary);
|
|
8748
|
+
}
|
|
8749
|
+
}
|
|
8750
|
+
return sortSavedHistorySessionSummaries(summaries);
|
|
8751
|
+
}
|
|
8752
|
+
function listProviderHistorySessions(agentType, options = {}) {
|
|
8753
|
+
if (isNativeSourceCanonicalHistory(options.canonicalHistory)) {
|
|
8754
|
+
const offset = Math.max(0, options.offset || 0);
|
|
8755
|
+
const limit = Math.max(1, options.limit || 30);
|
|
8756
|
+
const summaries = collectNativeHistorySessionSummaries(agentType, options.canonicalHistory);
|
|
8757
|
+
return {
|
|
8758
|
+
sessions: summaries.slice(offset, offset + limit),
|
|
8759
|
+
hasMore: offset + limit < summaries.length,
|
|
8760
|
+
source: "provider-native"
|
|
8761
|
+
};
|
|
8762
|
+
}
|
|
8763
|
+
return {
|
|
8764
|
+
...listSavedHistorySessions(agentType, { offset: options.offset, limit: options.limit }, options.historyBehavior),
|
|
8765
|
+
source: "adhdev-mirror"
|
|
8766
|
+
};
|
|
8767
|
+
}
|
|
8280
8768
|
|
|
8281
8769
|
// src/providers/provider-patch-state.ts
|
|
8282
8770
|
function isControlValue(value) {
|
|
@@ -10890,7 +11378,16 @@ async function handleChatHistory(h, args) {
|
|
|
10890
11378
|
const visibleCount = Array.isArray(status?.messages) ? status.messages.length : 0;
|
|
10891
11379
|
if (visibleCount > excludeRecentCount) excludeRecentCount = visibleCount;
|
|
10892
11380
|
}
|
|
10893
|
-
const
|
|
11381
|
+
const workspace = typeof args?.workspace === "string" ? args.workspace : typeof h.currentSession?.workspace === "string" ? h.currentSession.workspace : void 0;
|
|
11382
|
+
const result = readProviderChatHistory(agentStr, {
|
|
11383
|
+
canonicalHistory: provider?.canonicalHistory,
|
|
11384
|
+
historySessionId,
|
|
11385
|
+
workspace,
|
|
11386
|
+
offset: offset || 0,
|
|
11387
|
+
limit: limit || 30,
|
|
11388
|
+
excludeRecentCount,
|
|
11389
|
+
historyBehavior: provider?.historyBehavior
|
|
11390
|
+
});
|
|
10894
11391
|
return { success: true, ...result, agent: agentStr };
|
|
10895
11392
|
} catch (e) {
|
|
10896
11393
|
return { success: false, error: e.message };
|
|
@@ -10915,7 +11412,8 @@ async function handleReadChat(h, args) {
|
|
|
10915
11412
|
}
|
|
10916
11413
|
const parsedRecord = parsedStatus && typeof parsedStatus === "object" ? parsedStatus : null;
|
|
10917
11414
|
const adapterStatus = adapter.getStatus();
|
|
10918
|
-
const
|
|
11415
|
+
const parsedIsProviderAuthoritative = parsedRecord?.transcriptAuthority === "provider" || parsedRecord?.coverage === "full";
|
|
11416
|
+
const shouldPreferAdapterMessages = !parsedIsProviderAuthoritative && Array.isArray(adapterStatus.messages) && adapterStatus.messages.length > 0 && Array.isArray(parsedRecord?.messages) && adapterStatus.messages.length > parsedRecord.messages.length;
|
|
10919
11417
|
const parsedShowsApproval = hasNonEmptyModalButtons(parsedRecord?.activeModal) && parsedRecord?.status === "waiting_approval";
|
|
10920
11418
|
const status = parsedRecord ? {
|
|
10921
11419
|
...parsedRecord,
|
|
@@ -10925,6 +11423,8 @@ async function handleReadChat(h, args) {
|
|
|
10925
11423
|
} : adapterStatus;
|
|
10926
11424
|
const title = typeof parsedRecord?.title === "string" ? parsedRecord.title : void 0;
|
|
10927
11425
|
const providerSessionId = typeof parsedRecord?.providerSessionId === "string" ? parsedRecord.providerSessionId : void 0;
|
|
11426
|
+
const transcriptAuthority = parsedRecord?.transcriptAuthority === "provider" || parsedRecord?.transcriptAuthority === "daemon" ? parsedRecord.transcriptAuthority : void 0;
|
|
11427
|
+
const coverage = parsedRecord?.coverage === "full" || parsedRecord?.coverage === "tail" || parsedRecord?.coverage === "current-turn" ? parsedRecord.coverage : void 0;
|
|
10928
11428
|
if (status) {
|
|
10929
11429
|
LOG.debug("Command", `[read_chat] cli-like resolved provider=${adapter.cliType} target=${String(args?.targetSessionId || "")} adapterStatus=${String(adapterStatus.status || "")} parsedStatus=${String(parsedRecord?.status || "")} shouldPreferAdapterMessages=${String(shouldPreferAdapterMessages)} adapterMsgCount=${Array.isArray(adapterStatus.messages) ? adapterStatus.messages.length : 0} parsedMsgCount=${Array.isArray(parsedRecord?.messages) ? parsedRecord.messages.length : 0} returnedMsgCount=${Array.isArray(status.messages) ? status.messages.length : 0}`);
|
|
10930
11430
|
return buildReadChatCommandResult({
|
|
@@ -10943,7 +11443,9 @@ async function handleReadChat(h, args) {
|
|
|
10943
11443
|
returnedMsgCount: Array.isArray(status.messages) ? status.messages.length : 0
|
|
10944
11444
|
},
|
|
10945
11445
|
...title ? { title } : {},
|
|
10946
|
-
...providerSessionId ? { providerSessionId } : {}
|
|
11446
|
+
...providerSessionId ? { providerSessionId } : {},
|
|
11447
|
+
...transcriptAuthority ? { transcriptAuthority } : {},
|
|
11448
|
+
...coverage ? { coverage } : {}
|
|
10947
11449
|
}, args);
|
|
10948
11450
|
}
|
|
10949
11451
|
}
|
|
@@ -13363,6 +13865,8 @@ var CliProviderInstance = class {
|
|
|
13363
13865
|
lastCanonicalHermesWatchPath = void 0;
|
|
13364
13866
|
lastCanonicalClaudeRebuildMtimeMs = 0;
|
|
13365
13867
|
lastCanonicalClaudeCheckAt = 0;
|
|
13868
|
+
lastCanonicalCodexRebuildMtimeMs = 0;
|
|
13869
|
+
lastCanonicalCodexCheckAt = 0;
|
|
13366
13870
|
cachedSqliteDb = null;
|
|
13367
13871
|
cachedSqliteDbPath = null;
|
|
13368
13872
|
cachedSqliteDbMissingUntil = 0;
|
|
@@ -14062,6 +14566,25 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14062
14566
|
if (!this.providerSessionId) return false;
|
|
14063
14567
|
const canonicalHistory = this.provider.canonicalHistory;
|
|
14064
14568
|
if (!canonicalHistory) return false;
|
|
14569
|
+
if (isNativeSourceCanonicalHistory(canonicalHistory)) {
|
|
14570
|
+
const restoredHistory = readProviderChatHistory(this.type, {
|
|
14571
|
+
canonicalHistory,
|
|
14572
|
+
historySessionId: this.providerSessionId,
|
|
14573
|
+
workspace: this.workingDir,
|
|
14574
|
+
offset: 0,
|
|
14575
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
14576
|
+
historyBehavior: this.provider.historyBehavior
|
|
14577
|
+
});
|
|
14578
|
+
if (restoredHistory.source !== "provider-native") return false;
|
|
14579
|
+
this.lastPersistedHistoryMessages = restoredHistory.messages.map((message) => ({
|
|
14580
|
+
role: message.role,
|
|
14581
|
+
content: message.content,
|
|
14582
|
+
kind: message.kind,
|
|
14583
|
+
senderName: message.senderName,
|
|
14584
|
+
receivedAt: message.receivedAt
|
|
14585
|
+
}));
|
|
14586
|
+
return true;
|
|
14587
|
+
}
|
|
14065
14588
|
try {
|
|
14066
14589
|
let rebuilt = false;
|
|
14067
14590
|
if (canonicalHistory.format === "hermes-json") {
|
|
@@ -14095,6 +14618,23 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14095
14618
|
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalClaudeRebuildMtimeMs) return true;
|
|
14096
14619
|
rebuilt = rebuildClaudeSavedHistoryFromNativeProject(this.providerSessionId, this.workingDir);
|
|
14097
14620
|
if (rebuilt) this.lastCanonicalClaudeRebuildMtimeMs = transcriptMtime || Date.now();
|
|
14621
|
+
} else if (canonicalHistory.format === "codex-jsonl") {
|
|
14622
|
+
const now = Date.now();
|
|
14623
|
+
if (now - this.lastCanonicalCodexCheckAt < 2e3 && this.lastCanonicalCodexRebuildMtimeMs !== 0) {
|
|
14624
|
+
return true;
|
|
14625
|
+
}
|
|
14626
|
+
this.lastCanonicalCodexCheckAt = now;
|
|
14627
|
+
const transcriptFile = resolveCodexSessionTranscriptPath(this.providerSessionId, this.workingDir);
|
|
14628
|
+
let transcriptMtime = 0;
|
|
14629
|
+
if (transcriptFile) {
|
|
14630
|
+
try {
|
|
14631
|
+
transcriptMtime = fs5.statSync(transcriptFile).mtimeMs;
|
|
14632
|
+
} catch {
|
|
14633
|
+
}
|
|
14634
|
+
}
|
|
14635
|
+
if (transcriptMtime > 0 && transcriptMtime <= this.lastCanonicalCodexRebuildMtimeMs) return true;
|
|
14636
|
+
rebuilt = rebuildCodexSavedHistoryFromNativeSession(this.providerSessionId, this.workingDir);
|
|
14637
|
+
if (rebuilt) this.lastCanonicalCodexRebuildMtimeMs = transcriptMtime || Date.now();
|
|
14098
14638
|
}
|
|
14099
14639
|
if (!rebuilt) return false;
|
|
14100
14640
|
const restoredHistory = readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
@@ -14113,8 +14653,17 @@ ${effect.notification.body || ""}`.trim();
|
|
|
14113
14653
|
restorePersistedHistoryFromCurrentSession() {
|
|
14114
14654
|
if (!this.providerSessionId) return;
|
|
14115
14655
|
this.syncCanonicalSavedHistoryIfNeeded();
|
|
14116
|
-
this.
|
|
14117
|
-
|
|
14656
|
+
const restoredHistory = isNativeSourceCanonicalHistory(this.provider.canonicalHistory) ? readProviderChatHistory(this.type, {
|
|
14657
|
+
canonicalHistory: this.provider.canonicalHistory,
|
|
14658
|
+
historySessionId: this.providerSessionId,
|
|
14659
|
+
workspace: this.workingDir,
|
|
14660
|
+
offset: 0,
|
|
14661
|
+
limit: Number.MAX_SAFE_INTEGER,
|
|
14662
|
+
historyBehavior: this.provider.historyBehavior
|
|
14663
|
+
}) : (() => {
|
|
14664
|
+
this.historyWriter.compactHistorySession(this.type, this.providerSessionId, this.provider.historyBehavior);
|
|
14665
|
+
return readChatHistory(this.type, 0, Number.MAX_SAFE_INTEGER, this.providerSessionId, 0, this.provider.historyBehavior);
|
|
14666
|
+
})();
|
|
14118
14667
|
this.historyWriter.seedSessionHistory(
|
|
14119
14668
|
this.type,
|
|
14120
14669
|
restoredHistory.messages,
|
|
@@ -17849,6 +18398,38 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17849
18398
|
}
|
|
17850
18399
|
};
|
|
17851
18400
|
|
|
18401
|
+
// src/launch/macos-app-process.ts
|
|
18402
|
+
function normalizeMacAppPath(appPath) {
|
|
18403
|
+
const trimmed = String(appPath || "").trim();
|
|
18404
|
+
if (!trimmed) return null;
|
|
18405
|
+
return trimmed.replace(/\/+$/, "");
|
|
18406
|
+
}
|
|
18407
|
+
function parsePsLine(line) {
|
|
18408
|
+
const match = line.match(/^\s*(\d+)\s+(.+)$/);
|
|
18409
|
+
if (!match) return null;
|
|
18410
|
+
const pid = Number.parseInt(match[1], 10);
|
|
18411
|
+
if (!Number.isFinite(pid)) return null;
|
|
18412
|
+
return { pid, args: match[2] };
|
|
18413
|
+
}
|
|
18414
|
+
function isMacAppProcessArgs(args, appPath) {
|
|
18415
|
+
const normalized = normalizeMacAppPath(appPath);
|
|
18416
|
+
if (!normalized) return false;
|
|
18417
|
+
return String(args || "").startsWith(`${normalized}/`);
|
|
18418
|
+
}
|
|
18419
|
+
function findMacAppProcessPids(psOutput, appPaths) {
|
|
18420
|
+
const normalizedPaths = appPaths.map(normalizeMacAppPath).filter((value) => !!value);
|
|
18421
|
+
if (normalizedPaths.length === 0) return [];
|
|
18422
|
+
const pids = [];
|
|
18423
|
+
for (const line of String(psOutput || "").split(/\r?\n/)) {
|
|
18424
|
+
const parsed = parsePsLine(line);
|
|
18425
|
+
if (!parsed) continue;
|
|
18426
|
+
if (normalizedPaths.some((appPath) => isMacAppProcessArgs(parsed.args, appPath))) {
|
|
18427
|
+
pids.push(parsed.pid);
|
|
18428
|
+
}
|
|
18429
|
+
}
|
|
18430
|
+
return pids;
|
|
18431
|
+
}
|
|
18432
|
+
|
|
17852
18433
|
// src/launch.ts
|
|
17853
18434
|
var _providerLoader = null;
|
|
17854
18435
|
function getProviderLoader() {
|
|
@@ -17885,6 +18466,35 @@ function getCdpStartupTimeoutMs(ideId) {
|
|
|
17885
18466
|
function escapeForAppleScript(value) {
|
|
17886
18467
|
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
17887
18468
|
}
|
|
18469
|
+
function getIdePathCandidates(ideId) {
|
|
18470
|
+
return getProviderLoader().getIdePathCandidates(ideId);
|
|
18471
|
+
}
|
|
18472
|
+
function getMacAppProcessPids(ideId) {
|
|
18473
|
+
const appPaths = getIdePathCandidates(ideId);
|
|
18474
|
+
if (appPaths.length === 0) return [];
|
|
18475
|
+
try {
|
|
18476
|
+
const output = execSync4("ps axww -o pid=,args=", {
|
|
18477
|
+
encoding: "utf-8",
|
|
18478
|
+
timeout: 3e3,
|
|
18479
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
18480
|
+
});
|
|
18481
|
+
return findMacAppProcessPids(output, appPaths);
|
|
18482
|
+
} catch {
|
|
18483
|
+
return [];
|
|
18484
|
+
}
|
|
18485
|
+
}
|
|
18486
|
+
function killMacAppPathProcesses(ideId, signal) {
|
|
18487
|
+
const pids = getMacAppProcessPids(ideId);
|
|
18488
|
+
let signalled = false;
|
|
18489
|
+
for (const pid of pids) {
|
|
18490
|
+
try {
|
|
18491
|
+
process.kill(pid, signal);
|
|
18492
|
+
signalled = true;
|
|
18493
|
+
} catch {
|
|
18494
|
+
}
|
|
18495
|
+
}
|
|
18496
|
+
return signalled;
|
|
18497
|
+
}
|
|
17888
18498
|
async function findFreePort(ports) {
|
|
17889
18499
|
for (const port2 of ports) {
|
|
17890
18500
|
const free = await checkPortFree(port2);
|
|
@@ -17946,6 +18556,7 @@ async function killIdeProcess(ideId) {
|
|
|
17946
18556
|
} catch {
|
|
17947
18557
|
}
|
|
17948
18558
|
}
|
|
18559
|
+
killMacAppPathProcesses(ideId, "SIGTERM");
|
|
17949
18560
|
} else if (plat === "win32" && winProcesses) {
|
|
17950
18561
|
for (const proc of winProcesses) {
|
|
17951
18562
|
try {
|
|
@@ -17975,6 +18586,7 @@ async function killIdeProcess(ideId) {
|
|
|
17975
18586
|
execSync4(`pkill -9 -x "${appName}" 2>/dev/null`, { timeout: 5e3 });
|
|
17976
18587
|
} catch {
|
|
17977
18588
|
}
|
|
18589
|
+
killMacAppPathProcesses(ideId, "SIGKILL");
|
|
17978
18590
|
} else if (plat === "win32" && winProcesses) {
|
|
17979
18591
|
for (const proc of winProcesses) {
|
|
17980
18592
|
try {
|
|
@@ -17994,14 +18606,16 @@ function isIdeRunning(ideId) {
|
|
|
17994
18606
|
try {
|
|
17995
18607
|
if (plat === "darwin") {
|
|
17996
18608
|
const appName = getMacAppIdentifiers()[ideId];
|
|
17997
|
-
if (!appName) return
|
|
18609
|
+
if (!appName) return getMacAppProcessPids(ideId).length > 0;
|
|
17998
18610
|
try {
|
|
17999
18611
|
const result = execSync4(`pgrep -x "${appName}" 2>/dev/null`, {
|
|
18000
18612
|
encoding: "utf-8",
|
|
18001
18613
|
timeout: 3e3
|
|
18002
18614
|
});
|
|
18003
|
-
|
|
18615
|
+
if (result.trim().length > 0) return true;
|
|
18004
18616
|
} catch {
|
|
18617
|
+
}
|
|
18618
|
+
try {
|
|
18005
18619
|
const result = execSync4(
|
|
18006
18620
|
`osascript -e 'tell application "System Events" to count (every process whose name is "${escapeForAppleScript(appName)}")'`,
|
|
18007
18621
|
{
|
|
@@ -18010,8 +18624,10 @@ function isIdeRunning(ideId) {
|
|
|
18010
18624
|
stdio: ["pipe", "pipe", "pipe"]
|
|
18011
18625
|
}
|
|
18012
18626
|
);
|
|
18013
|
-
|
|
18627
|
+
if (Number.parseInt(result.trim() || "0", 10) > 0) return true;
|
|
18628
|
+
} catch {
|
|
18014
18629
|
}
|
|
18630
|
+
return getMacAppProcessPids(ideId).length > 0;
|
|
18015
18631
|
} else if (plat === "win32") {
|
|
18016
18632
|
const winProcesses = getWinProcessNames()[ideId];
|
|
18017
18633
|
if (!winProcesses) return false;
|
|
@@ -19378,13 +19994,18 @@ var DaemonCommandRouter = class {
|
|
|
19378
19994
|
const wantsAll = args?.all === true;
|
|
19379
19995
|
const offset = wantsAll ? 0 : Math.max(0, Number(args?.offset) || 0);
|
|
19380
19996
|
const limit = wantsAll ? Number.MAX_SAFE_INTEGER : Math.max(1, Math.min(100, Number(args?.limit) || 30));
|
|
19381
|
-
const
|
|
19997
|
+
const providerMeta = this.deps.providerLoader.getMeta(providerType);
|
|
19998
|
+
const { sessions: historySessions, hasMore, source } = listProviderHistorySessions(providerType, {
|
|
19999
|
+
canonicalHistory: providerMeta?.canonicalHistory,
|
|
20000
|
+
offset,
|
|
20001
|
+
limit,
|
|
20002
|
+
historyBehavior: providerMeta?.historyBehavior
|
|
20003
|
+
});
|
|
19382
20004
|
const state = loadState();
|
|
19383
20005
|
const savedSessions = getSavedProviderSessions(state, { providerType, kind });
|
|
19384
20006
|
const recentSessions = getRecentActivity(state, 200).filter((entry) => entry.providerType === providerType && entry.kind === kind && entry.providerSessionId);
|
|
19385
20007
|
const savedSessionById = new Map(savedSessions.map((entry) => [entry.providerSessionId, entry]));
|
|
19386
20008
|
const recentSessionById = new Map(recentSessions.map((entry) => [entry.providerSessionId, entry]));
|
|
19387
|
-
const providerMeta = this.deps.providerLoader.getMeta(providerType);
|
|
19388
20009
|
const canResumeById = supportsExplicitSessionResume(providerMeta?.resume);
|
|
19389
20010
|
return {
|
|
19390
20011
|
success: true,
|
|
@@ -19407,7 +20028,8 @@ var DaemonCommandRouter = class {
|
|
|
19407
20028
|
canResume: !!(saved?.workspace || recent?.workspace || session.workspace) && canResumeById
|
|
19408
20029
|
};
|
|
19409
20030
|
}),
|
|
19410
|
-
hasMore
|
|
20031
|
+
hasMore,
|
|
20032
|
+
source
|
|
19411
20033
|
};
|
|
19412
20034
|
}
|
|
19413
20035
|
// ─── restart_session: IDE / CLI / ACP unified ───
|