replicas-engine 0.1.869 → 0.1.871
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/src/{asp-host-E3YMFEZU.js → asp-host-YN7ECDD4.js} +4 -4
- package/dist/src/{chunk-RMSEJMO4.js → chunk-6YEU4TRD.js} +2 -2
- package/dist/src/{chunk-TZGLNBWY.js → chunk-GN43A3FI.js} +2 -2
- package/dist/src/{chunk-MR5HFA2D.js → chunk-MFLQVITI.js} +1 -1
- package/dist/src/{chunk-COJG7NIH.js → chunk-TGECCL6C.js} +5 -5
- package/dist/src/{chunk-AZVITHZV.js → chunk-VXF4AHJU.js} +1 -1
- package/dist/src/{chunk-IT5R5GJT.js → chunk-XHX6IRSG.js} +363 -397
- package/dist/src/command-protection-hook.js +3 -3
- package/dist/src/deepseek-command-protection-plugin.js +4 -4
- package/dist/src/headless-agent.js +2 -2
- package/dist/src/index.js +498 -988
- package/dist/src/post-tool-pr-hook.js +2 -2
- package/dist/src/relay-mcp.js +1 -1
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -91,7 +91,7 @@ import {
|
|
|
91
91
|
evaluateCommandProtection,
|
|
92
92
|
extractToolCommand,
|
|
93
93
|
reportCommandProtectionBlock
|
|
94
|
-
} from "./chunk-
|
|
94
|
+
} from "./chunk-6YEU4TRD.js";
|
|
95
95
|
import {
|
|
96
96
|
ACCOUNT_RATE_LIMITS_UPDATED_METHOD,
|
|
97
97
|
AGENT_MESSAGE_DELTA_METHOD,
|
|
@@ -132,20 +132,20 @@ import {
|
|
|
132
132
|
recordCredentialFallback,
|
|
133
133
|
recordExhaustedCredential,
|
|
134
134
|
restartCodexAspHost
|
|
135
|
-
} from "./chunk-
|
|
135
|
+
} from "./chunk-TGECCL6C.js";
|
|
136
136
|
import {
|
|
137
137
|
ENGINE_ENV,
|
|
138
138
|
IS_WARMING_MODE,
|
|
139
139
|
monolithRequest,
|
|
140
140
|
monolithService,
|
|
141
141
|
setAgentCredentialSnapshot
|
|
142
|
-
} from "./chunk-
|
|
142
|
+
} from "./chunk-VXF4AHJU.js";
|
|
143
143
|
import {
|
|
144
144
|
AspClient,
|
|
145
145
|
SUBPROCESS_MAX_BUFFER,
|
|
146
146
|
execAsync,
|
|
147
147
|
execFileAsync
|
|
148
|
-
} from "./chunk-
|
|
148
|
+
} from "./chunk-GN43A3FI.js";
|
|
149
149
|
import {
|
|
150
150
|
isRecord as isRecord2
|
|
151
151
|
} from "./chunk-UZSNFLDQ.js";
|
|
@@ -180,12 +180,13 @@ import {
|
|
|
180
180
|
CLAUDE_SONNET_5_BEDROCK_MODEL,
|
|
181
181
|
CLAUDE_SONNET_5_MODEL,
|
|
182
182
|
CODEX_ASP_ITEM_ID_PAYLOAD_KEY,
|
|
183
|
-
|
|
183
|
+
CODEX_HISTORY_FORMAT_EVENT_TYPE,
|
|
184
184
|
CODEX_QUOTA_STATUS_EVENT_TYPE,
|
|
185
185
|
COMPACTION_STATUS_EVENT_TYPE,
|
|
186
186
|
CONTEXT_USAGE_EVENT_TYPE,
|
|
187
187
|
CREDENTIAL_METHOD,
|
|
188
188
|
CURSOR_CONNECTION_STATUS_EVENT_TYPE,
|
|
189
|
+
CodexHistoryEventFolder,
|
|
189
190
|
DEFAULT_ASTER_MODEL,
|
|
190
191
|
DEFAULT_CHAT_TITLES,
|
|
191
192
|
DEFAULT_CLAUDE_MODEL,
|
|
@@ -233,7 +234,6 @@ import {
|
|
|
233
234
|
USER_MESSAGE_ID_PAYLOAD_KEY,
|
|
234
235
|
VALID_AGENT_PROVIDERS,
|
|
235
236
|
agentQuotaExhaustedPayloadSchema,
|
|
236
|
-
applyCodexAspTranscriptDelta,
|
|
237
237
|
areSameUserMessageEvents,
|
|
238
238
|
areUserMessagesWithinMatchWindow,
|
|
239
239
|
autoCompactThresholdField,
|
|
@@ -248,7 +248,12 @@ import {
|
|
|
248
248
|
clampWarmHookTimeoutMs,
|
|
249
249
|
classifyCanvasFilename,
|
|
250
250
|
claudeAuthEnvFromResponse,
|
|
251
|
+
codexHistoryFormatEvent,
|
|
252
|
+
codexItemEvent,
|
|
251
253
|
codexReasoningEffortForThinkingLevel,
|
|
254
|
+
codexTranscriptToEvents,
|
|
255
|
+
codexTurnEvent,
|
|
256
|
+
codexTurnFromEvent,
|
|
252
257
|
coerceBackgroundTaskPayload,
|
|
253
258
|
coerceChatForkInfo,
|
|
254
259
|
coerceChatGoalPayload,
|
|
@@ -256,7 +261,6 @@ import {
|
|
|
256
261
|
createAcceptedUserMessageEvent,
|
|
257
262
|
createChatHistoryCursor,
|
|
258
263
|
createChatRequestSchema,
|
|
259
|
-
createChatTranscriptPages,
|
|
260
264
|
createErrorResult,
|
|
261
265
|
createProviderSlashCommand,
|
|
262
266
|
createSuccessResult,
|
|
@@ -276,12 +280,9 @@ import {
|
|
|
276
280
|
formatChatForkHandoffMessage,
|
|
277
281
|
getChatExecutionProvider,
|
|
278
282
|
getChatHistoryPageSenders,
|
|
279
|
-
getChatHistoryPageWindow,
|
|
280
|
-
getChatTranscriptHistorySize,
|
|
281
283
|
getClaudeModelContextWindow,
|
|
282
|
-
getClaudePartialMessageStreamId,
|
|
283
|
-
getCodexAspTurnResponse,
|
|
284
284
|
getDefaultAgentModel,
|
|
285
|
+
getEventStreamId,
|
|
285
286
|
getEventTimestampMs,
|
|
286
287
|
getGitHubAccessToken,
|
|
287
288
|
getGoalCommand,
|
|
@@ -295,17 +296,15 @@ import {
|
|
|
295
296
|
githubCredentialLines,
|
|
296
297
|
hasChatStarted,
|
|
297
298
|
imageContentToUserMessageImages,
|
|
298
|
-
isAgentBackendEvent,
|
|
299
299
|
isAgentChatMcpActivityRecord,
|
|
300
300
|
isAgentChatSkillActivityRecord,
|
|
301
301
|
isAgentChatTurnActivityRecord,
|
|
302
302
|
isAuthenticationErrorText,
|
|
303
303
|
isCanvasTextKind,
|
|
304
|
+
isChatHistoryEvent,
|
|
304
305
|
isChatMessageSender,
|
|
305
306
|
isClaudeAuthErrorText,
|
|
306
307
|
isClaudeResultError,
|
|
307
|
-
isCodexAspTranscript,
|
|
308
|
-
isCodexAspTranscriptDelta,
|
|
309
308
|
isCodexAuthError,
|
|
310
309
|
isDefaultChat,
|
|
311
310
|
isExcludedRepoFilePath,
|
|
@@ -330,20 +329,18 @@ import {
|
|
|
330
329
|
normalizeContentBlocks,
|
|
331
330
|
paginateChatHistory,
|
|
332
331
|
paginateEngineLogContent,
|
|
333
|
-
|
|
332
|
+
parseAgentEventJsonlLine,
|
|
334
333
|
parseAgentEvents,
|
|
335
334
|
parseChatHistoryCursor,
|
|
336
335
|
parseChatTranscriptArtifact,
|
|
337
336
|
parseDisplayMessages,
|
|
338
337
|
parseFrontmatter,
|
|
339
338
|
parseGitRemote,
|
|
340
|
-
parseLatestCodexAspTranscriptTurn,
|
|
341
339
|
parseMcpToolName,
|
|
342
340
|
parseReplicasConfigString,
|
|
343
341
|
percentage,
|
|
344
342
|
raceWithTimeout,
|
|
345
343
|
readJsonlPage,
|
|
346
|
-
renumberCodexAspTranscriptItems,
|
|
347
344
|
resolveWarmHookConfig,
|
|
348
345
|
safeJsonParse,
|
|
349
346
|
sanitizeCanvasFilename,
|
|
@@ -358,7 +355,7 @@ import {
|
|
|
358
355
|
waitRelaySubagentRequestSchema,
|
|
359
356
|
withTimeout,
|
|
360
357
|
workspaceCredentialProviderSchema
|
|
361
|
-
} from "./chunk-
|
|
358
|
+
} from "./chunk-XHX6IRSG.js";
|
|
362
359
|
import {
|
|
363
360
|
__commonJS,
|
|
364
361
|
__export,
|
|
@@ -10701,8 +10698,8 @@ async function registerDesktopPreview() {
|
|
|
10701
10698
|
}
|
|
10702
10699
|
|
|
10703
10700
|
// src/services/chat/chat-service.ts
|
|
10704
|
-
import { appendFile as appendFile5, copyFile as copyFile2, mkdir as mkdir21, readFile as
|
|
10705
|
-
import { join as
|
|
10701
|
+
import { appendFile as appendFile5, copyFile as copyFile2, mkdir as mkdir21, readFile as readFile23, rename as rename5, rm as rm4 } from "fs/promises";
|
|
10702
|
+
import { join as join36 } from "path";
|
|
10706
10703
|
import { randomUUID as randomUUID13 } from "crypto";
|
|
10707
10704
|
|
|
10708
10705
|
// ../shared/src/workspace-chat.ts
|
|
@@ -10740,7 +10737,7 @@ function workspaceChatEventSignals(event) {
|
|
|
10740
10737
|
eventJsonCache.set(event, json);
|
|
10741
10738
|
}
|
|
10742
10739
|
return {
|
|
10743
|
-
streamId:
|
|
10740
|
+
streamId: getEventStreamId(event),
|
|
10744
10741
|
json,
|
|
10745
10742
|
userMessage: getComparableUserMessage(event),
|
|
10746
10743
|
userMessageId: event.type === QUEUED_MESSAGE_REMOVED_EVENT_TYPE ? null : getUserMessageId(event)
|
|
@@ -10850,7 +10847,7 @@ function mergeWorkspaceChatHistoryEvents(primary, supplemental, removedMessageId
|
|
|
10850
10847
|
list[position] = null;
|
|
10851
10848
|
unindexEvent(listIndex, previous, position);
|
|
10852
10849
|
addEvent(event);
|
|
10853
|
-
} else if (
|
|
10850
|
+
} else if (getEventStreamId(event) !== null || messageId !== null && messageId === getUserMessageId(previous)) {
|
|
10854
10851
|
list[position] = event;
|
|
10855
10852
|
unindexEvent(listIndex, previous, position);
|
|
10856
10853
|
indexMergedEvent(listIndex, event, position);
|
|
@@ -10880,7 +10877,7 @@ import {
|
|
|
10880
10877
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
10881
10878
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
10882
10879
|
import { dirname as dirname4, join as join16 } from "path";
|
|
10883
|
-
import { mkdir as mkdir10, readdir as readdir4, readFile as
|
|
10880
|
+
import { mkdir as mkdir10, readdir as readdir4, readFile as readFile10 } from "fs/promises";
|
|
10884
10881
|
import { homedir as homedir11 } from "os";
|
|
10885
10882
|
|
|
10886
10883
|
// src/utils/linear-converter.ts
|
|
@@ -12444,7 +12441,13 @@ function isNotFoundError(error) {
|
|
|
12444
12441
|
}
|
|
12445
12442
|
|
|
12446
12443
|
// src/managers/codex-asp/codex-history-file.ts
|
|
12447
|
-
import {
|
|
12444
|
+
import { createReadStream } from "fs";
|
|
12445
|
+
import { appendFile as appendFile2, open, rename as rename2 } from "fs/promises";
|
|
12446
|
+
import { createInterface } from "readline";
|
|
12447
|
+
var MIGRATION_FLUSH_CHARS = 1 << 20;
|
|
12448
|
+
function isMissingFile(error) {
|
|
12449
|
+
return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
|
|
12450
|
+
}
|
|
12448
12451
|
var CodexHistoryFile = class {
|
|
12449
12452
|
constructor(filePath) {
|
|
12450
12453
|
this.filePath = filePath;
|
|
@@ -12464,40 +12467,79 @@ var CodexHistoryFile = class {
|
|
|
12464
12467
|
async flush() {
|
|
12465
12468
|
await this.writeLock.drain();
|
|
12466
12469
|
}
|
|
12467
|
-
|
|
12470
|
+
/**
|
|
12471
|
+
* Rewrites a file that still holds legacy Codex transcript records as plain
|
|
12472
|
+
* item events, once. The file is read line by line: a long-lived chat can
|
|
12473
|
+
* exceed the largest string V8 will hold. The rewritten file starts with a
|
|
12474
|
+
* format marker so later starts only read that first line.
|
|
12475
|
+
*/
|
|
12476
|
+
async ensureItemEventFormat() {
|
|
12477
|
+
const firstLine = await this.readFirstLine();
|
|
12478
|
+
if (firstLine === null) {
|
|
12479
|
+
await this.appendDurably(codexHistoryFormatEvent());
|
|
12480
|
+
return;
|
|
12481
|
+
}
|
|
12482
|
+
if (parseAgentEventJsonlLine(firstLine)?.type === CODEX_HISTORY_FORMAT_EVENT_TYPE) return;
|
|
12483
|
+
await this.writeLock.run(async () => {
|
|
12484
|
+
const events = await this.loadAll();
|
|
12485
|
+
const rewritten = `${this.filePath}.migrating`;
|
|
12486
|
+
const handle = await open(rewritten, "w");
|
|
12487
|
+
try {
|
|
12488
|
+
let pending = "";
|
|
12489
|
+
for (const event of [codexHistoryFormatEvent(), ...events]) {
|
|
12490
|
+
pending += `${JSON.stringify(event)}
|
|
12491
|
+
`;
|
|
12492
|
+
if (pending.length >= MIGRATION_FLUSH_CHARS) {
|
|
12493
|
+
await handle.write(pending);
|
|
12494
|
+
pending = "";
|
|
12495
|
+
}
|
|
12496
|
+
}
|
|
12497
|
+
if (pending) await handle.write(pending);
|
|
12498
|
+
} finally {
|
|
12499
|
+
await handle.close();
|
|
12500
|
+
}
|
|
12501
|
+
await rename2(rewritten, this.filePath);
|
|
12502
|
+
});
|
|
12503
|
+
}
|
|
12504
|
+
/**
|
|
12505
|
+
* Newest event of `type`, scanning the whole file so a value older than the
|
|
12506
|
+
* most recent page is still found. Streams line by line and retains only the
|
|
12507
|
+
* match, so history size does not bound memory.
|
|
12508
|
+
*/
|
|
12509
|
+
async findLastEventOfType(type) {
|
|
12510
|
+
let found = null;
|
|
12468
12511
|
try {
|
|
12469
|
-
const
|
|
12470
|
-
|
|
12512
|
+
for await (const line of createInterface({ input: createReadStream(this.filePath), crlfDelay: Infinity })) {
|
|
12513
|
+
const event = parseAgentEventJsonlLine(line);
|
|
12514
|
+
if (event?.type === type) found = event;
|
|
12515
|
+
}
|
|
12471
12516
|
} catch (error) {
|
|
12472
|
-
if (!(error
|
|
12473
|
-
|
|
12517
|
+
if (!isMissingFile(error)) throw error;
|
|
12518
|
+
}
|
|
12519
|
+
return found;
|
|
12520
|
+
}
|
|
12521
|
+
async loadAll() {
|
|
12522
|
+
const folder = new CodexHistoryEventFolder();
|
|
12523
|
+
try {
|
|
12524
|
+
for await (const line of createInterface({ input: createReadStream(this.filePath), crlfDelay: Infinity })) {
|
|
12525
|
+
const event = parseAgentEventJsonlLine(line);
|
|
12526
|
+
if (event) folder.push(event);
|
|
12474
12527
|
}
|
|
12475
|
-
|
|
12528
|
+
} catch (error) {
|
|
12529
|
+
if (!isMissingFile(error)) throw error;
|
|
12476
12530
|
}
|
|
12531
|
+
return folder.finish();
|
|
12477
12532
|
}
|
|
12478
12533
|
async loadEventsPage(page2) {
|
|
12479
|
-
if (page2.limit === void 0) {
|
|
12480
|
-
const history = await this.load();
|
|
12481
|
-
return { events: history.events };
|
|
12482
|
-
}
|
|
12534
|
+
if (page2.limit === void 0) return { events: await this.loadAll() };
|
|
12483
12535
|
const cursor = parseChatHistoryCursor(page2.beforeCursor);
|
|
12484
12536
|
if (page2.beforeCursor !== void 0 && cursor?.mode !== "range") throw new RangeError("Invalid chat history cursor");
|
|
12485
|
-
if (cursor?.events === null) {
|
|
12486
|
-
return {
|
|
12487
|
-
events: [],
|
|
12488
|
-
beforeCursor: createChatHistoryCursor({
|
|
12489
|
-
events: null,
|
|
12490
|
-
turns: cursor.turns
|
|
12491
|
-
})
|
|
12492
|
-
};
|
|
12493
|
-
}
|
|
12537
|
+
if (cursor?.events === null) return { events: [], beforeCursor: null };
|
|
12494
12538
|
let file;
|
|
12495
12539
|
try {
|
|
12496
12540
|
file = await open(this.filePath, "r");
|
|
12497
12541
|
} catch (error) {
|
|
12498
|
-
if (error
|
|
12499
|
-
return { events: [], beforeCursor: null };
|
|
12500
|
-
}
|
|
12542
|
+
if (isMissingFile(error)) return { events: [], beforeCursor: null };
|
|
12501
12543
|
throw error;
|
|
12502
12544
|
}
|
|
12503
12545
|
try {
|
|
@@ -12510,19 +12552,35 @@ var CodexHistoryFile = class {
|
|
|
12510
12552
|
const { bytesRead } = await file.read(bytes, 0, bytes.length, startByte);
|
|
12511
12553
|
return bytes.subarray(0, bytesRead);
|
|
12512
12554
|
},
|
|
12513
|
-
parse: (value) =>
|
|
12555
|
+
parse: (value) => isChatHistoryEvent(value) ? value : void 0
|
|
12514
12556
|
});
|
|
12515
12557
|
return {
|
|
12516
12558
|
events: result.items,
|
|
12517
|
-
beforeCursor: createChatHistoryCursor({
|
|
12518
|
-
events: result.before,
|
|
12519
|
-
turns: cursor?.turns ?? null
|
|
12520
|
-
})
|
|
12559
|
+
beforeCursor: createChatHistoryCursor({ events: result.before, turns: null })
|
|
12521
12560
|
};
|
|
12522
12561
|
} finally {
|
|
12523
12562
|
await file.close();
|
|
12524
12563
|
}
|
|
12525
12564
|
}
|
|
12565
|
+
async readFirstLine() {
|
|
12566
|
+
let file;
|
|
12567
|
+
try {
|
|
12568
|
+
file = await open(this.filePath, "r");
|
|
12569
|
+
} catch (error) {
|
|
12570
|
+
if (isMissingFile(error)) return null;
|
|
12571
|
+
throw error;
|
|
12572
|
+
}
|
|
12573
|
+
try {
|
|
12574
|
+
const bytes = Buffer.allocUnsafe(4096);
|
|
12575
|
+
const { bytesRead } = await file.read(bytes, 0, bytes.length, 0);
|
|
12576
|
+
if (bytesRead === 0) return null;
|
|
12577
|
+
const text = bytes.subarray(0, bytesRead).toString("utf-8");
|
|
12578
|
+
const newline = text.indexOf("\n");
|
|
12579
|
+
return newline === -1 ? text : text.slice(0, newline);
|
|
12580
|
+
} finally {
|
|
12581
|
+
await file.close();
|
|
12582
|
+
}
|
|
12583
|
+
}
|
|
12526
12584
|
};
|
|
12527
12585
|
|
|
12528
12586
|
// src/managers/claude-activity.ts
|
|
@@ -13100,7 +13158,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
13100
13158
|
const agentId = /^agent-(.+)\.jsonl$/.exec(file)?.[1];
|
|
13101
13159
|
if (!agentId) continue;
|
|
13102
13160
|
const offset = workflow.offsets.get(file) ?? 0;
|
|
13103
|
-
const buffer = await
|
|
13161
|
+
const buffer = await readFile10(join16(workflow.dir, file)).catch(() => Buffer.alloc(0));
|
|
13104
13162
|
const end = buffer.lastIndexOf(10);
|
|
13105
13163
|
if (end < offset) continue;
|
|
13106
13164
|
workflow.offsets.set(file, end + 1);
|
|
@@ -14077,10 +14135,6 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
14077
14135
|
}
|
|
14078
14136
|
};
|
|
14079
14137
|
|
|
14080
|
-
// src/managers/codex-asp/codex-asp-manager.ts
|
|
14081
|
-
import { readdir as readdir5 } from "fs/promises";
|
|
14082
|
-
import { join as join18 } from "path";
|
|
14083
|
-
|
|
14084
14138
|
// src/utils/codex-quota.ts
|
|
14085
14139
|
function buildCodexRateLimitsSnapshot(fields) {
|
|
14086
14140
|
if (fields.authMethod !== "oauth") return null;
|
|
@@ -14508,128 +14562,7 @@ function turnsToAspTranscript(threadId, updatedAt, sourceTurns) {
|
|
|
14508
14562
|
items
|
|
14509
14563
|
};
|
|
14510
14564
|
});
|
|
14511
|
-
return
|
|
14512
|
-
threadId,
|
|
14513
|
-
updatedAt,
|
|
14514
|
-
turns
|
|
14515
|
-
});
|
|
14516
|
-
}
|
|
14517
|
-
function latestIsoTimestamp(a, b) {
|
|
14518
|
-
return Date.parse(a) >= Date.parse(b) ? a : b;
|
|
14519
|
-
}
|
|
14520
|
-
function nextTranscriptSequence(transcript) {
|
|
14521
|
-
let max = -1;
|
|
14522
|
-
for (const turn of transcript.turns) {
|
|
14523
|
-
for (const item of turn.items) {
|
|
14524
|
-
if (typeof item.sequence === "number" && item.sequence > max) {
|
|
14525
|
-
max = item.sequence;
|
|
14526
|
-
}
|
|
14527
|
-
}
|
|
14528
|
-
}
|
|
14529
|
-
return max + 1;
|
|
14530
|
-
}
|
|
14531
|
-
function transcriptItemRank(item) {
|
|
14532
|
-
return item.type === "userMessage" ? 0 : 1;
|
|
14533
|
-
}
|
|
14534
|
-
function transcriptItemSignature(item) {
|
|
14535
|
-
if (item.type === "userMessage") return `user:${item.content.trim()}`;
|
|
14536
|
-
if (item.type === "agentMessage" && item.text.trim()) return `agent:${item.text.trim()}`;
|
|
14537
|
-
if (item.type === "plan" && item.text.trim()) return `plan:${item.text.trim()}`;
|
|
14538
|
-
if (item.type === "error" && item.message.trim()) return `error:${item.message.trim()}`;
|
|
14539
|
-
return null;
|
|
14540
|
-
}
|
|
14541
|
-
function areEquivalentTranscriptItems(current, candidate) {
|
|
14542
|
-
if (current.id === candidate.id) return true;
|
|
14543
|
-
if (current.type !== candidate.type) return false;
|
|
14544
|
-
const signature = transcriptItemSignature(current);
|
|
14545
|
-
return signature !== null && signature === transcriptItemSignature(candidate);
|
|
14546
|
-
}
|
|
14547
|
-
function findEquivalentCodexAspTranscriptItemIndex(items, candidate) {
|
|
14548
|
-
return items.findIndex((current) => areEquivalentTranscriptItems(current, candidate));
|
|
14549
|
-
}
|
|
14550
|
-
function sortTranscriptItems(items) {
|
|
14551
|
-
return [...items].map((item, index) => ({ item, index })).sort((a, b) => {
|
|
14552
|
-
const aSequence = a.item.sequence ?? Number.MAX_SAFE_INTEGER;
|
|
14553
|
-
const bSequence = b.item.sequence ?? Number.MAX_SAFE_INTEGER;
|
|
14554
|
-
return transcriptItemRank(a.item) - transcriptItemRank(b.item) || aSequence - bSequence || Date.parse(a.item.timestamp) - Date.parse(b.item.timestamp) || a.index - b.index;
|
|
14555
|
-
}).map(({ item }) => item);
|
|
14556
|
-
}
|
|
14557
|
-
function dedupeTranscriptItems(items) {
|
|
14558
|
-
const deduped = [];
|
|
14559
|
-
for (const item of items) {
|
|
14560
|
-
const existingIndex = findEquivalentCodexAspTranscriptItemIndex(deduped, item);
|
|
14561
|
-
if (existingIndex === -1) {
|
|
14562
|
-
deduped.push(item);
|
|
14563
|
-
continue;
|
|
14564
|
-
}
|
|
14565
|
-
deduped[existingIndex] = mergeCodexAspTranscriptItem(deduped[existingIndex], item);
|
|
14566
|
-
}
|
|
14567
|
-
return deduped;
|
|
14568
|
-
}
|
|
14569
|
-
function normalizeCodexAspTranscriptSequences(transcript) {
|
|
14570
|
-
const turns = [...transcript.turns].map((turn, index) => ({ turn, index })).sort((a, b) => Date.parse(a.turn.startedAt) - Date.parse(b.turn.startedAt) || a.index - b.index).map(({ turn }) => ({
|
|
14571
|
-
...turn,
|
|
14572
|
-
items: sortTranscriptItems(dedupeTranscriptItems(turn.items))
|
|
14573
|
-
}));
|
|
14574
|
-
return renumberCodexAspTranscriptItems({
|
|
14575
|
-
...transcript,
|
|
14576
|
-
turns
|
|
14577
|
-
});
|
|
14578
|
-
}
|
|
14579
|
-
function mergeCodexAspTranscriptItem(current, candidate) {
|
|
14580
|
-
if (current.type === "agentMessage" && candidate.type === "agentMessage" && candidate.text.length === 0) {
|
|
14581
|
-
return {
|
|
14582
|
-
...current,
|
|
14583
|
-
sequence: current.sequence ?? candidate.sequence
|
|
14584
|
-
};
|
|
14585
|
-
}
|
|
14586
|
-
return {
|
|
14587
|
-
...current,
|
|
14588
|
-
...candidate,
|
|
14589
|
-
id: current.id,
|
|
14590
|
-
...current.type === "userMessage" && candidate.type === "userMessage" && !candidate.images && current.images ? { images: current.images } : {},
|
|
14591
|
-
timestamp: current.timestamp,
|
|
14592
|
-
sequence: current.sequence ?? candidate.sequence
|
|
14593
|
-
};
|
|
14594
|
-
}
|
|
14595
|
-
function mergeCodexAspTranscripts(primary, supplemental) {
|
|
14596
|
-
if (!primary) return supplemental ? normalizeCodexAspTranscriptSequences(supplemental) : null;
|
|
14597
|
-
if (!supplemental) return normalizeCodexAspTranscriptSequences(primary);
|
|
14598
|
-
if (primary.threadId !== supplemental.threadId) return normalizeCodexAspTranscriptSequences(supplemental);
|
|
14599
|
-
let sequence = nextTranscriptSequence(primary);
|
|
14600
|
-
const turns = primary.turns.map((turn) => ({
|
|
14601
|
-
...turn,
|
|
14602
|
-
items: [...turn.items]
|
|
14603
|
-
}));
|
|
14604
|
-
for (const supplementalTurn of supplemental.turns) {
|
|
14605
|
-
const existingTurn = turns.find((turn) => turn.id === supplementalTurn.id);
|
|
14606
|
-
if (!existingTurn) {
|
|
14607
|
-
turns.push({
|
|
14608
|
-
...supplementalTurn,
|
|
14609
|
-
items: supplementalTurn.items.map((item) => typeof item.sequence === "number" ? item : { ...item, sequence: sequence++ })
|
|
14610
|
-
});
|
|
14611
|
-
continue;
|
|
14612
|
-
}
|
|
14613
|
-
existingTurn.status = supplementalTurn.status;
|
|
14614
|
-
existingTurn.completedAt = supplementalTurn.completedAt ?? existingTurn.completedAt;
|
|
14615
|
-
existingTurn.startedAt = Date.parse(existingTurn.startedAt) <= Date.parse(supplementalTurn.startedAt) ? existingTurn.startedAt : supplementalTurn.startedAt;
|
|
14616
|
-
for (const item of supplementalTurn.items) {
|
|
14617
|
-
const existingIndex = findEquivalentCodexAspTranscriptItemIndex(existingTurn.items, item);
|
|
14618
|
-
if (existingIndex === -1) {
|
|
14619
|
-
existingTurn.items.push(
|
|
14620
|
-
typeof item.sequence === "number" ? item : { ...item, sequence: sequence++ }
|
|
14621
|
-
);
|
|
14622
|
-
continue;
|
|
14623
|
-
}
|
|
14624
|
-
existingTurn.items[existingIndex] = mergeCodexAspTranscriptItem(existingTurn.items[existingIndex], item);
|
|
14625
|
-
}
|
|
14626
|
-
existingTurn.items = sortTranscriptItems(existingTurn.items);
|
|
14627
|
-
}
|
|
14628
|
-
return normalizeCodexAspTranscriptSequences({
|
|
14629
|
-
threadId: primary.threadId,
|
|
14630
|
-
updatedAt: latestIsoTimestamp(primary.updatedAt, supplemental.updatedAt),
|
|
14631
|
-
turns: turns.sort((a, b) => Date.parse(a.startedAt) - Date.parse(b.startedAt))
|
|
14632
|
-
});
|
|
14565
|
+
return { threadId, updatedAt, turns };
|
|
14633
14566
|
}
|
|
14634
14567
|
async function buildThreadStartParams(workingDirectory, request, developerInstructions, serviceTier, relayParentChatId) {
|
|
14635
14568
|
const additionalDirectories = await getAgentAdditionalDirectories();
|
|
@@ -14716,96 +14649,42 @@ async function buildTurnStartParams(threadId, request, serviceTier) {
|
|
|
14716
14649
|
};
|
|
14717
14650
|
}
|
|
14718
14651
|
|
|
14719
|
-
// src/managers/codex-asp/
|
|
14720
|
-
var
|
|
14721
|
-
var
|
|
14722
|
-
constructor(flush, intervalMs =
|
|
14652
|
+
// src/managers/codex-asp/item-update-coalescer.ts
|
|
14653
|
+
var ITEM_UPDATE_COALESCE_MS = 250;
|
|
14654
|
+
var ItemUpdateCoalescer = class {
|
|
14655
|
+
constructor(flush, intervalMs = ITEM_UPDATE_COALESCE_MS) {
|
|
14723
14656
|
this.flush = flush;
|
|
14724
14657
|
this.intervalMs = intervalMs;
|
|
14725
14658
|
}
|
|
14726
14659
|
flush;
|
|
14727
14660
|
intervalMs;
|
|
14728
|
-
|
|
14729
|
-
|
|
14730
|
-
|
|
14731
|
-
|
|
14732
|
-
this.
|
|
14733
|
-
if (options.immediate) {
|
|
14734
|
-
this.flushNow(
|
|
14735
|
-
return;
|
|
14736
|
-
}
|
|
14737
|
-
const now = Date.now();
|
|
14738
|
-
const elapsed = now - this.lastFlushAt;
|
|
14739
|
-
if (elapsed >= this.intervalMs) {
|
|
14740
|
-
this.flushNow(threadId);
|
|
14741
|
-
return;
|
|
14742
|
-
}
|
|
14743
|
-
if (this.timer) {
|
|
14661
|
+
timers = /* @__PURE__ */ new Map();
|
|
14662
|
+
lastFlushAt = /* @__PURE__ */ new Map();
|
|
14663
|
+
schedule(key, options = {}) {
|
|
14664
|
+
if (this.timers.has(key)) return;
|
|
14665
|
+
const elapsed = Date.now() - (this.lastFlushAt.get(key) ?? 0);
|
|
14666
|
+
if (options.immediate || elapsed >= this.intervalMs) {
|
|
14667
|
+
this.flushNow(key);
|
|
14744
14668
|
return;
|
|
14745
14669
|
}
|
|
14746
|
-
this.
|
|
14747
|
-
const pendingThreadId = this.pendingThreadId;
|
|
14748
|
-
if (pendingThreadId) {
|
|
14749
|
-
this.flushNow(pendingThreadId);
|
|
14750
|
-
}
|
|
14751
|
-
}, this.intervalMs - elapsed);
|
|
14670
|
+
this.timers.set(key, setTimeout(() => this.flushNow(key), this.intervalMs - elapsed));
|
|
14752
14671
|
}
|
|
14753
14672
|
flushPending() {
|
|
14754
|
-
const
|
|
14755
|
-
if (pendingThreadId) {
|
|
14756
|
-
this.flushNow(pendingThreadId);
|
|
14757
|
-
return;
|
|
14758
|
-
}
|
|
14759
|
-
this.clearTimer();
|
|
14673
|
+
for (const key of [...this.timers.keys()]) this.flushNow(key);
|
|
14760
14674
|
}
|
|
14761
14675
|
dispose() {
|
|
14762
|
-
this.
|
|
14763
|
-
this.
|
|
14676
|
+
for (const timer of this.timers.values()) clearTimeout(timer);
|
|
14677
|
+
this.timers.clear();
|
|
14764
14678
|
}
|
|
14765
|
-
flushNow(
|
|
14766
|
-
this.
|
|
14767
|
-
|
|
14768
|
-
this.
|
|
14769
|
-
this.
|
|
14770
|
-
|
|
14771
|
-
clearTimer() {
|
|
14772
|
-
if (!this.timer) return;
|
|
14773
|
-
clearTimeout(this.timer);
|
|
14774
|
-
this.timer = null;
|
|
14679
|
+
flushNow(key) {
|
|
14680
|
+
const timer = this.timers.get(key);
|
|
14681
|
+
if (timer) clearTimeout(timer);
|
|
14682
|
+
this.timers.delete(key);
|
|
14683
|
+
this.lastFlushAt.set(key, Date.now());
|
|
14684
|
+
this.flush(key);
|
|
14775
14685
|
}
|
|
14776
14686
|
};
|
|
14777
14687
|
|
|
14778
|
-
// src/services/chat/history-paths.ts
|
|
14779
|
-
import { homedir as homedir12 } from "os";
|
|
14780
|
-
import { join as join17 } from "path";
|
|
14781
|
-
var ENGINE_DIR2 = join17(homedir12(), ".replicas", "engine");
|
|
14782
|
-
var CHATS_FILE = join17(ENGINE_DIR2, "chats.json");
|
|
14783
|
-
var CLAUDE_HISTORY_DIR = join17(ENGINE_DIR2, "claude-histories");
|
|
14784
|
-
var RELAY_HISTORY_DIR = join17(ENGINE_DIR2, "relay-histories");
|
|
14785
|
-
var CODEX_HISTORY_DIR = join17(ENGINE_DIR2, "codex-histories");
|
|
14786
|
-
var CURSOR_HISTORY_DIR = join17(ENGINE_DIR2, "cursor-histories");
|
|
14787
|
-
var OPENCODE_HISTORY_DIR = join17(ENGINE_DIR2, "opencode-histories");
|
|
14788
|
-
var PI_HISTORY_DIR = join17(ENGINE_DIR2, "pi-histories");
|
|
14789
|
-
var DEEPSEEK_HISTORY_DIR = join17(ENGINE_DIR2, "deepseek-histories");
|
|
14790
|
-
var FX_HISTORY_DIR = join17(ENGINE_DIR2, "fx-histories");
|
|
14791
|
-
var GEMINI_HISTORY_DIR = join17(ENGINE_DIR2, "gemini-histories");
|
|
14792
|
-
var KIMI_HISTORY_DIR = join17(ENGINE_DIR2, "kimi-histories");
|
|
14793
|
-
var MUSE_HISTORY_DIR = join17(ENGINE_DIR2, "muse-histories");
|
|
14794
|
-
var FORKS_DIR = join17(ENGINE_DIR2, "forks");
|
|
14795
|
-
var HISTORY_DIR_BY_PROVIDER = {
|
|
14796
|
-
claude: CLAUDE_HISTORY_DIR,
|
|
14797
|
-
relay: RELAY_HISTORY_DIR,
|
|
14798
|
-
codex: CODEX_HISTORY_DIR,
|
|
14799
|
-
cursor: CURSOR_HISTORY_DIR,
|
|
14800
|
-
deepseek: DEEPSEEK_HISTORY_DIR,
|
|
14801
|
-
fx: FX_HISTORY_DIR,
|
|
14802
|
-
gemini: GEMINI_HISTORY_DIR,
|
|
14803
|
-
kimi: KIMI_HISTORY_DIR,
|
|
14804
|
-
muse: MUSE_HISTORY_DIR,
|
|
14805
|
-
opencode: OPENCODE_HISTORY_DIR,
|
|
14806
|
-
pi: PI_HISTORY_DIR
|
|
14807
|
-
};
|
|
14808
|
-
|
|
14809
14688
|
// src/services/chat/errors.ts
|
|
14810
14689
|
var ChatNotFoundError = class extends Error {
|
|
14811
14690
|
constructor(chatId) {
|
|
@@ -14853,44 +14732,17 @@ function formatBlockedCommandReason(reason) {
|
|
|
14853
14732
|
return reason?.includes("Blocked by organization policy") ? reason : `Blocked by organization policy: ${reason || "agents may not merge pull requests."}`;
|
|
14854
14733
|
}
|
|
14855
14734
|
async function readCodexAspThreadHistory(threadId) {
|
|
14856
|
-
let
|
|
14857
|
-
try {
|
|
14858
|
-
entries = await readdir5(CODEX_HISTORY_DIR, { withFileTypes: true });
|
|
14859
|
-
} catch (error) {
|
|
14860
|
-
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
14861
|
-
entries = [];
|
|
14862
|
-
} else {
|
|
14863
|
-
throw error;
|
|
14864
|
-
}
|
|
14865
|
-
}
|
|
14866
|
-
for (const entry of entries) {
|
|
14867
|
-
if (!entry.isFile() || !entry.name.endsWith(".jsonl") || entry.name.endsWith(".pages.jsonl")) continue;
|
|
14868
|
-
const history = await new CodexHistoryFile(join18(CODEX_HISTORY_DIR, entry.name)).load();
|
|
14869
|
-
const transcript = history.transcriptsByThreadId.get(threadId);
|
|
14870
|
-
if (transcript) {
|
|
14871
|
-
return {
|
|
14872
|
-
thread_id: threadId,
|
|
14873
|
-
events: [],
|
|
14874
|
-
codexAspTranscript: transcript,
|
|
14875
|
-
goal: null
|
|
14876
|
-
};
|
|
14877
|
-
}
|
|
14878
|
-
}
|
|
14735
|
+
let thread;
|
|
14879
14736
|
try {
|
|
14880
14737
|
const host = await getCodexAspHost();
|
|
14881
|
-
|
|
14738
|
+
({ thread } = await host.client.request(
|
|
14882
14739
|
THREAD_READ_METHOD,
|
|
14883
14740
|
{ threadId, includeTurns: true }
|
|
14884
|
-
);
|
|
14885
|
-
return {
|
|
14886
|
-
thread_id: threadId,
|
|
14887
|
-
events: [],
|
|
14888
|
-
codexAspTranscript: threadToAspTranscript(response.thread),
|
|
14889
|
-
goal: null
|
|
14890
|
-
};
|
|
14741
|
+
));
|
|
14891
14742
|
} catch {
|
|
14743
|
+
throw new CodexThreadNotFoundError(threadId);
|
|
14892
14744
|
}
|
|
14893
|
-
|
|
14745
|
+
return { thread_id: threadId, events: codexTranscriptToEvents(threadToAspTranscript(thread)), goal: null };
|
|
14894
14746
|
}
|
|
14895
14747
|
function skillToSlashCommand(skill) {
|
|
14896
14748
|
if (!skill.enabled) return null;
|
|
@@ -14911,19 +14763,18 @@ function isCompactCommand(message) {
|
|
|
14911
14763
|
var CodexAspManager = class extends CodingAgentManager {
|
|
14912
14764
|
currentThreadId = null;
|
|
14913
14765
|
activeTurnId = null;
|
|
14766
|
+
lastTurnFailure = null;
|
|
14914
14767
|
attachedClient = null;
|
|
14915
14768
|
attachedModel = null;
|
|
14916
14769
|
attachedDeveloperInstructions = null;
|
|
14917
14770
|
historyFile;
|
|
14918
|
-
|
|
14919
|
-
lastEmittedTranscript = null;
|
|
14920
|
-
dirtyTranscriptTurns = /* @__PURE__ */ new Map();
|
|
14921
|
-
codexAspSequence = 0;
|
|
14771
|
+
liveTurn = null;
|
|
14922
14772
|
quotaStatus = new CodexQuotaStatusTracker();
|
|
14923
14773
|
currentGoal = null;
|
|
14924
14774
|
goalHistoryKnown = false;
|
|
14925
|
-
|
|
14926
|
-
this.
|
|
14775
|
+
itemUpdateCoalescer = new ItemUpdateCoalescer((itemId) => {
|
|
14776
|
+
const item = this.liveTurn?.items.get(itemId);
|
|
14777
|
+
if (this.liveTurn && item) this.onEvent(codexItemEvent(this.liveTurn.id, item, true));
|
|
14927
14778
|
});
|
|
14928
14779
|
skillRegistriesApplied = false;
|
|
14929
14780
|
modelServiceTierCache = null;
|
|
@@ -14946,16 +14797,13 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
14946
14797
|
this.initializeManager(this.processMessageInternal.bind(this));
|
|
14947
14798
|
}
|
|
14948
14799
|
async initialize() {
|
|
14949
|
-
|
|
14950
|
-
|
|
14951
|
-
|
|
14952
|
-
}
|
|
14953
|
-
const goalEvent = replayed?.events.findLast((event) => event.type === CHAT_GOAL_EVENT_TYPE);
|
|
14800
|
+
await this.historyFile?.ensureItemEventFormat();
|
|
14801
|
+
this.currentThreadId = this.initialSessionId;
|
|
14802
|
+
const goalEvent = await this.historyFile?.findLastEventOfType(CHAT_GOAL_EVENT_TYPE);
|
|
14954
14803
|
if (goalEvent) {
|
|
14955
14804
|
this.currentGoal = coerceChatGoalPayload(goalEvent.payload);
|
|
14956
14805
|
this.goalHistoryKnown = true;
|
|
14957
14806
|
}
|
|
14958
|
-
this.currentThreadId = this.initialSessionId ?? replayed?.transcript?.threadId ?? null;
|
|
14959
14807
|
}
|
|
14960
14808
|
getHistorySink() {
|
|
14961
14809
|
return {
|
|
@@ -15046,61 +14894,25 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15046
14894
|
}
|
|
15047
14895
|
async getHistory(page2 = {}) {
|
|
15048
14896
|
await this.initialized;
|
|
15049
|
-
this.transcriptUpdateCoalescer.flushPending();
|
|
15050
14897
|
await this.historyFile?.flush();
|
|
15051
|
-
const
|
|
15052
|
-
|
|
15053
|
-
if (page2.limit === void 0) {
|
|
15054
|
-
return {
|
|
15055
|
-
thread_id: this.currentThreadId,
|
|
15056
|
-
events: events.events,
|
|
15057
|
-
codexAspTranscript: transcript,
|
|
15058
|
-
goal: this.currentGoal
|
|
15059
|
-
};
|
|
15060
|
-
}
|
|
15061
|
-
if (!this.currentThreadId) return { thread_id: null, ...events, goal: this.currentGoal };
|
|
15062
|
-
const cursor = parseChatHistoryCursor(page2.beforeCursor);
|
|
15063
|
-
if (page2.beforeCursor !== void 0 && cursor?.mode !== "range") throw new RangeError("Invalid chat history cursor");
|
|
15064
|
-
if (page2.beforeCursor === void 0 && !this.goalHistoryKnown) {
|
|
14898
|
+
const latestPage = isLatestChatHistoryPage(page2);
|
|
14899
|
+
if (latestPage && !this.goalHistoryKnown && this.currentThreadId) {
|
|
15065
14900
|
try {
|
|
15066
14901
|
await this.refreshThreadGoal(await getCodexAspHost(), this.currentThreadId);
|
|
15067
14902
|
} catch (error) {
|
|
15068
14903
|
console.warn("[CodexAspManager] Failed to connect while refreshing thread goal:", error);
|
|
15069
14904
|
}
|
|
15070
14905
|
}
|
|
15071
|
-
|
|
15072
|
-
|
|
15073
|
-
|
|
15074
|
-
const before = cursor?.turns === void 0 ? transcript.turns.length : /^\d+$/.test(cursor.turns) ? Number(cursor.turns) : Number.NaN;
|
|
15075
|
-
if (!Number.isSafeInteger(before) || before < 0) throw new RangeError("Invalid chat history cursor");
|
|
15076
|
-
const { startIndex, endIndex } = getChatHistoryPageWindow(transcript.turns.length, page2.limit, before);
|
|
15077
|
-
transcriptPage = {
|
|
15078
|
-
...transcript,
|
|
15079
|
-
turns: transcript.turns.slice(startIndex, endIndex)
|
|
15080
|
-
};
|
|
15081
|
-
turnsBefore = startIndex > 0 ? String(startIndex) : null;
|
|
15082
|
-
}
|
|
15083
|
-
const eventCursor = parseChatHistoryCursor(events.beforeCursor ?? void 0);
|
|
14906
|
+
const history = await this.historyFile?.loadEventsPage(page2) ?? { events: [] };
|
|
14907
|
+
const liveTurn = latestPage ? this.liveTurn : null;
|
|
14908
|
+
const liveEvents = liveTurn ? [...liveTurn.items.values()].map((item) => codexItemEvent(liveTurn.id, item, true)) : [];
|
|
15084
14909
|
return {
|
|
15085
14910
|
thread_id: this.currentThreadId,
|
|
15086
|
-
...
|
|
15087
|
-
|
|
15088
|
-
goal: this.currentGoal
|
|
15089
|
-
beforeCursor: createChatHistoryCursor({
|
|
15090
|
-
events: eventCursor?.events ?? null,
|
|
15091
|
-
turns: turnsBefore
|
|
15092
|
-
})
|
|
14911
|
+
...history,
|
|
14912
|
+
events: [...history.events, ...liveEvents],
|
|
14913
|
+
goal: this.currentGoal
|
|
15093
14914
|
};
|
|
15094
14915
|
}
|
|
15095
|
-
async ensureTranscriptHistory() {
|
|
15096
|
-
if (this.codexAspTranscript || !this.currentThreadId) return this.codexAspTranscript;
|
|
15097
|
-
const host = await getCodexAspHost();
|
|
15098
|
-
const response = await host.client.request(
|
|
15099
|
-
THREAD_READ_METHOD,
|
|
15100
|
-
{ threadId: this.currentThreadId, includeTurns: true }
|
|
15101
|
-
);
|
|
15102
|
-
return this.mergeTranscriptSnapshot(threadToAspTranscript(response.thread));
|
|
15103
|
-
}
|
|
15104
14916
|
getGoal() {
|
|
15105
14917
|
return this.currentGoal;
|
|
15106
14918
|
}
|
|
@@ -15257,16 +15069,16 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15257
15069
|
}
|
|
15258
15070
|
}
|
|
15259
15071
|
const message = terminalError instanceof Error ? terminalError.message : String(terminalError);
|
|
15260
|
-
const
|
|
15072
|
+
const failedTurnId = this.lastTurnFailure?.message === message ? this.lastTurnFailure.turnId : null;
|
|
15261
15073
|
const event = this.recordCodexHistoryEvent("codex-asp-error", {
|
|
15262
15074
|
message,
|
|
15263
|
-
...
|
|
15075
|
+
...failedTurnId ? { [CODEX_ASP_ITEM_ID_PAYLOAD_KEY]: failedTurnId } : {}
|
|
15264
15076
|
});
|
|
15265
15077
|
this.onEvent(event);
|
|
15266
15078
|
throw terminalError;
|
|
15267
15079
|
} finally {
|
|
15268
|
-
this.
|
|
15269
|
-
this.
|
|
15080
|
+
this.itemUpdateCoalescer.flushPending();
|
|
15081
|
+
this.itemUpdateCoalescer.dispose();
|
|
15270
15082
|
this.activeTurnId = null;
|
|
15271
15083
|
await removeTempImageFiles(this.steeredTempImagePaths.splice(0));
|
|
15272
15084
|
await this.historyFile?.flush();
|
|
@@ -15339,7 +15151,6 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15339
15151
|
this.attachedClient = host.client;
|
|
15340
15152
|
this.attachedModel = requestedModel;
|
|
15341
15153
|
this.attachedDeveloperInstructions = developerInstructions ?? null;
|
|
15342
|
-
this.seedHistoryFromThread(response.thread);
|
|
15343
15154
|
await this.onSaveSessionId(this.currentThreadId);
|
|
15344
15155
|
}
|
|
15345
15156
|
return this.currentThreadId ?? existingThreadId;
|
|
@@ -15443,7 +15254,6 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15443
15254
|
const observedTurnIds = /* @__PURE__ */ new Set();
|
|
15444
15255
|
let lastCompletedTurn = null;
|
|
15445
15256
|
let completedResolved = false;
|
|
15446
|
-
let userMessageAttached = false;
|
|
15447
15257
|
let goalContinuationTimer = null;
|
|
15448
15258
|
const completedItems = [];
|
|
15449
15259
|
const agentMessageDeltas = /* @__PURE__ */ new Map();
|
|
@@ -15472,11 +15282,6 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15472
15282
|
resolveCompleted(lastCompletedTurn);
|
|
15473
15283
|
}, GOAL_TURN_CONTINUATION_GRACE_MS);
|
|
15474
15284
|
};
|
|
15475
|
-
const attachUserMessage = (turn) => {
|
|
15476
|
-
if (userMessageAttached) return;
|
|
15477
|
-
userMessageAttached = true;
|
|
15478
|
-
this.ensureTranscriptTurnUserMessage(threadId, turn, request);
|
|
15479
|
-
};
|
|
15480
15285
|
const handlers = {
|
|
15481
15286
|
[ACCOUNT_RATE_LIMITS_UPDATED_METHOD]: (notification) => {
|
|
15482
15287
|
this.handleRateLimits(notification.params.rateLimits);
|
|
@@ -15518,14 +15323,11 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15518
15323
|
lastCompletedTurn = null;
|
|
15519
15324
|
completedItems.length = 0;
|
|
15520
15325
|
agentMessageDeltas.clear();
|
|
15521
|
-
|
|
15522
|
-
this.mergeTranscriptTurn(notification.params.threadId, notification.params.turn);
|
|
15523
|
-
this.emitTranscriptUpdated(notification.params.threadId, { immediate: true });
|
|
15326
|
+
this.startTurn(notification.params.turn);
|
|
15524
15327
|
linearForwarder.sendEvent(convertCodexAspNotification(notification, linearSessionId ?? ""));
|
|
15525
15328
|
},
|
|
15526
15329
|
[TURN_PLAN_UPDATED_METHOD]: (notification) => {
|
|
15527
15330
|
if (!matchesTurn(notification.params.threadId, notification.params.turnId)) return;
|
|
15528
|
-
this.emitTranscriptUpdated(notification.params.threadId);
|
|
15529
15331
|
linearForwarder.sendPlan(extractPlanFromCodexAspNotification(notification));
|
|
15530
15332
|
},
|
|
15531
15333
|
[ITEM_STARTED_METHOD]: (notification) => {
|
|
@@ -15533,15 +15335,10 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15533
15335
|
if (notification.params.item.type === "contextCompaction") {
|
|
15534
15336
|
this.setCompacting(true);
|
|
15535
15337
|
}
|
|
15536
|
-
this.
|
|
15537
|
-
notification.params.threadId,
|
|
15338
|
+
this.startItem(
|
|
15538
15339
|
notification.params.turnId,
|
|
15539
|
-
notification.params.item,
|
|
15540
|
-
timestampFromMilliseconds(notification.params.startedAtMs),
|
|
15541
|
-
"in_progress",
|
|
15542
|
-
"started"
|
|
15340
|
+
itemToTranscriptItem(notification.params.item, timestampFromMilliseconds(notification.params.startedAtMs), "in_progress")
|
|
15543
15341
|
);
|
|
15544
|
-
this.emitTranscriptUpdated(notification.params.threadId, { immediate: true });
|
|
15545
15342
|
linearForwarder.sendEvent(convertCodexAspNotification(notification, linearSessionId ?? ""));
|
|
15546
15343
|
},
|
|
15547
15344
|
[ITEM_COMPLETED_METHOD]: (notification) => {
|
|
@@ -15551,15 +15348,14 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15551
15348
|
this.setCompacting(false);
|
|
15552
15349
|
}
|
|
15553
15350
|
const itemFailed = notification.params.item.type === "commandExecution" && typeof notification.params.item.exitCode === "number" && notification.params.item.exitCode !== 0;
|
|
15554
|
-
this.
|
|
15555
|
-
notification.params.threadId,
|
|
15351
|
+
this.completeItem(
|
|
15556
15352
|
notification.params.turnId,
|
|
15557
|
-
|
|
15558
|
-
|
|
15559
|
-
|
|
15560
|
-
|
|
15353
|
+
itemToTranscriptItem(
|
|
15354
|
+
notification.params.item,
|
|
15355
|
+
timestampFromMilliseconds(notification.params.completedAtMs),
|
|
15356
|
+
itemFailed ? "failed" : "completed"
|
|
15357
|
+
)
|
|
15561
15358
|
);
|
|
15562
|
-
this.emitTranscriptUpdated(notification.params.threadId, { immediate: true });
|
|
15563
15359
|
linearForwarder.sendEvent(convertCodexAspNotification(notification, linearSessionId ?? ""));
|
|
15564
15360
|
const completedItem = notification.params.item;
|
|
15565
15361
|
if (completedItem.type === "commandExecution" && completedItem.exitCode === 0 && shouldRefreshPullRequests("commandExecution", { command: completedItem.command }) || completedItem.type === "mcpToolCall" && completedItem.status === "completed" && shouldRefreshPullRequests(completedItem.tool, completedItem.arguments) || completedItem.type === "dynamicToolCall" && completedItem.success !== false && shouldRefreshPullRequests(completedItem.tool, completedItem.arguments)) {
|
|
@@ -15571,53 +15367,27 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15571
15367
|
if (!matchesTurn(notification.params.threadId, notification.params.turnId)) return;
|
|
15572
15368
|
const currentText = agentMessageDeltas.get(notification.params.itemId) ?? "";
|
|
15573
15369
|
agentMessageDeltas.set(notification.params.itemId, currentText + notification.params.delta);
|
|
15574
|
-
this.appendAgentMessageDelta(
|
|
15575
|
-
notification.params.threadId,
|
|
15576
|
-
notification.params.turnId,
|
|
15577
|
-
notification.params.itemId,
|
|
15578
|
-
notification.params.delta
|
|
15579
|
-
);
|
|
15580
|
-
this.emitTranscriptUpdated(notification.params.threadId);
|
|
15370
|
+
this.appendAgentMessageDelta(notification.params.turnId, notification.params.itemId, notification.params.delta);
|
|
15581
15371
|
},
|
|
15582
15372
|
[REASONING_SUMMARY_TEXT_DELTA_METHOD]: (notification) => {
|
|
15583
15373
|
if (!matchesTurn(notification.params.threadId, notification.params.turnId)) return;
|
|
15584
|
-
this.appendReasoningDelta(
|
|
15585
|
-
notification.params.threadId,
|
|
15586
|
-
notification.params.turnId,
|
|
15587
|
-
notification.params.itemId,
|
|
15588
|
-
notification.params.delta
|
|
15589
|
-
);
|
|
15590
|
-
this.emitTranscriptUpdated(notification.params.threadId);
|
|
15374
|
+
this.appendReasoningDelta(notification.params.turnId, notification.params.itemId, notification.params.delta);
|
|
15591
15375
|
},
|
|
15592
15376
|
[REASONING_TEXT_DELTA_METHOD]: (notification) => {
|
|
15593
15377
|
if (!matchesTurn(notification.params.threadId, notification.params.turnId)) return;
|
|
15594
|
-
this.appendReasoningDelta(
|
|
15595
|
-
notification.params.threadId,
|
|
15596
|
-
notification.params.turnId,
|
|
15597
|
-
notification.params.itemId,
|
|
15598
|
-
notification.params.delta
|
|
15599
|
-
);
|
|
15600
|
-
this.emitTranscriptUpdated(notification.params.threadId);
|
|
15378
|
+
this.appendReasoningDelta(notification.params.turnId, notification.params.itemId, notification.params.delta);
|
|
15601
15379
|
},
|
|
15602
15380
|
[REASONING_SUMMARY_PART_ADDED_METHOD]: (notification) => {
|
|
15603
15381
|
if (!matchesTurn(notification.params.threadId, notification.params.turnId)) return;
|
|
15604
|
-
this.appendReasoningDelta(
|
|
15605
|
-
notification.params.threadId,
|
|
15606
|
-
notification.params.turnId,
|
|
15607
|
-
notification.params.itemId,
|
|
15608
|
-
"\n\n"
|
|
15609
|
-
);
|
|
15610
|
-
this.emitTranscriptUpdated(notification.params.threadId);
|
|
15382
|
+
this.appendReasoningDelta(notification.params.turnId, notification.params.itemId, "\n\n");
|
|
15611
15383
|
},
|
|
15612
15384
|
[COMMAND_EXECUTION_OUTPUT_DELTA_METHOD]: (notification) => {
|
|
15613
15385
|
if (!matchesTurn(notification.params.threadId, notification.params.turnId)) return;
|
|
15614
|
-
this.
|
|
15615
|
-
this.emitTranscriptUpdated(notification.params.threadId);
|
|
15386
|
+
this.appendOutputDelta(notification.params.turnId, notification.params.itemId, notification.params.delta);
|
|
15616
15387
|
},
|
|
15617
15388
|
[FILE_CHANGE_OUTPUT_DELTA_METHOD]: (notification) => {
|
|
15618
15389
|
if (!matchesTurn(notification.params.threadId, notification.params.turnId)) return;
|
|
15619
|
-
this.
|
|
15620
|
-
this.emitTranscriptUpdated(notification.params.threadId);
|
|
15390
|
+
this.appendOutputDelta(notification.params.turnId, notification.params.itemId, notification.params.delta);
|
|
15621
15391
|
},
|
|
15622
15392
|
[TURN_COMPLETED_METHOD]: (notification) => {
|
|
15623
15393
|
if (notification.params.threadId !== threadId) return;
|
|
@@ -15626,8 +15396,7 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15626
15396
|
observedTurnId = notification.params.turn.id;
|
|
15627
15397
|
this.onCodexTurnCompleted?.(threadId, notification.params.turn.id);
|
|
15628
15398
|
const completedTurn = recoverCompletedTurn(notification.params.turn, completedItems, agentMessageDeltas);
|
|
15629
|
-
this.
|
|
15630
|
-
this.emitTranscriptUpdated(notification.params.threadId, { immediate: true });
|
|
15399
|
+
this.completeTurn(completedTurn);
|
|
15631
15400
|
lastCompletedTurn = completedTurn;
|
|
15632
15401
|
resolveIfGoalIdle();
|
|
15633
15402
|
if (options.waitForActiveGoal && this.currentGoal?.status === "active") {
|
|
@@ -15668,11 +15437,7 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15668
15437
|
observedTurnIds.add(started.turn.id);
|
|
15669
15438
|
this.activeTurnId = started.turn.id;
|
|
15670
15439
|
if (!alreadyObserved) this.onCodexTurnStarted?.(threadId, started.turn.id);
|
|
15671
|
-
if (!alreadyObserved)
|
|
15672
|
-
attachUserMessage(started.turn);
|
|
15673
|
-
this.mergeTranscriptTurn(threadId, started.turn);
|
|
15674
|
-
this.emitTranscriptUpdated(threadId, { immediate: true });
|
|
15675
|
-
}
|
|
15440
|
+
if (!alreadyObserved) this.startTurn(started.turn);
|
|
15676
15441
|
}
|
|
15677
15442
|
const turn = await Promise.race([completed, disposed]);
|
|
15678
15443
|
linearForwarder.flushThoughtAsResponse();
|
|
@@ -15684,7 +15449,7 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15684
15449
|
if (goalContinuationTimer) {
|
|
15685
15450
|
clearTimeout(goalContinuationTimer);
|
|
15686
15451
|
}
|
|
15687
|
-
this.
|
|
15452
|
+
this.itemUpdateCoalescer.flushPending();
|
|
15688
15453
|
await removeTempImageFiles(tempImagePaths);
|
|
15689
15454
|
if (host.client.isDisposed) {
|
|
15690
15455
|
this.attachedClient = null;
|
|
@@ -15711,7 +15476,6 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15711
15476
|
if (!result.allowed) {
|
|
15712
15477
|
console.warn(`[CodexAspManager] blocked command approval: ${result.reason ?? "unknown reason"}`);
|
|
15713
15478
|
this.recordBlockedCommand(
|
|
15714
|
-
serverRequest.params.threadId,
|
|
15715
15479
|
serverRequest.params.turnId,
|
|
15716
15480
|
serverRequest.params.itemId,
|
|
15717
15481
|
serverRequest.params.command ?? "",
|
|
@@ -15752,7 +15516,6 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15752
15516
|
if (!result.allowed) {
|
|
15753
15517
|
console.warn(`[CodexAspManager] blocked legacy command approval: ${result.reason ?? "unknown reason"}`);
|
|
15754
15518
|
this.recordBlockedCommand(
|
|
15755
|
-
this.currentThreadId ?? serverRequest.params.conversationId,
|
|
15756
15519
|
this.activeTurnId ?? `legacy-${requestId}`,
|
|
15757
15520
|
serverRequest.params.callId,
|
|
15758
15521
|
command,
|
|
@@ -15842,12 +15605,7 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15842
15605
|
console.warn("[CodexAspManager] Failed to inject blocked command reason:", error);
|
|
15843
15606
|
}
|
|
15844
15607
|
}
|
|
15845
|
-
|
|
15846
|
-
return this.codexAspSequence++;
|
|
15847
|
-
}
|
|
15848
|
-
recordBlockedCommand(threadId, turnId, itemId, command, reason, startedAtMs, cwd, commandActions) {
|
|
15849
|
-
const output = formatBlockedCommandReason(reason);
|
|
15850
|
-
const timestamp = timestampFromMilliseconds(startedAtMs);
|
|
15608
|
+
recordBlockedCommand(turnId, itemId, command, reason, startedAtMs, cwd, commandActions) {
|
|
15851
15609
|
const blockedItem = {
|
|
15852
15610
|
type: "commandExecution",
|
|
15853
15611
|
id: itemId,
|
|
@@ -15856,231 +15614,80 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
15856
15614
|
processId: null,
|
|
15857
15615
|
source: "agent",
|
|
15858
15616
|
commandActions: commandActions ?? [{ type: "unknown", command }],
|
|
15859
|
-
aggregatedOutput:
|
|
15617
|
+
aggregatedOutput: formatBlockedCommandReason(reason),
|
|
15860
15618
|
exitCode: null,
|
|
15861
15619
|
status: "declined",
|
|
15862
15620
|
durationMs: null
|
|
15863
15621
|
};
|
|
15864
|
-
this.
|
|
15865
|
-
this.emitTranscriptUpdated(threadId, { immediate: true });
|
|
15866
|
-
}
|
|
15867
|
-
syncTranscriptSequence(transcript) {
|
|
15868
|
-
if (!transcript) return;
|
|
15869
|
-
let next = 0;
|
|
15870
|
-
for (const turn of transcript.turns) {
|
|
15871
|
-
for (const item of turn.items) {
|
|
15872
|
-
if (typeof item.sequence === "number" && item.sequence >= next) {
|
|
15873
|
-
next = item.sequence + 1;
|
|
15874
|
-
}
|
|
15875
|
-
}
|
|
15876
|
-
}
|
|
15877
|
-
this.codexAspSequence = next;
|
|
15878
|
-
}
|
|
15879
|
-
mergeTranscriptSnapshot(snapshot) {
|
|
15880
|
-
if (snapshot?.threadId && this.codexAspTranscript?.threadId !== snapshot.threadId) {
|
|
15881
|
-
this.lastEmittedTranscript = null;
|
|
15882
|
-
this.dirtyTranscriptTurns.clear();
|
|
15883
|
-
}
|
|
15884
|
-
this.codexAspTranscript = mergeCodexAspTranscripts(this.codexAspTranscript, snapshot);
|
|
15885
|
-
for (const turn of this.codexAspTranscript?.turns ?? []) {
|
|
15886
|
-
this.dirtyTranscriptTurns.set(turn.id, turn);
|
|
15887
|
-
}
|
|
15888
|
-
this.syncTranscriptSequence(this.codexAspTranscript);
|
|
15889
|
-
return this.codexAspTranscript;
|
|
15890
|
-
}
|
|
15891
|
-
ensureTranscript(threadId) {
|
|
15892
|
-
if (this.codexAspTranscript?.threadId === threadId) {
|
|
15893
|
-
return this.codexAspTranscript;
|
|
15894
|
-
}
|
|
15895
|
-
this.lastEmittedTranscript = null;
|
|
15896
|
-
this.dirtyTranscriptTurns.clear();
|
|
15897
|
-
this.codexAspTranscript = {
|
|
15898
|
-
threadId,
|
|
15899
|
-
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15900
|
-
turns: []
|
|
15901
|
-
};
|
|
15902
|
-
this.codexAspSequence = 0;
|
|
15903
|
-
return this.codexAspTranscript;
|
|
15904
|
-
}
|
|
15905
|
-
ensureTranscriptTurn(threadId, turnId, startedAt) {
|
|
15906
|
-
const transcript = this.ensureTranscript(threadId);
|
|
15907
|
-
let turn = transcript.turns.find((candidate) => candidate.id === turnId);
|
|
15908
|
-
if (!turn) {
|
|
15909
|
-
turn = {
|
|
15910
|
-
id: turnId,
|
|
15911
|
-
status: "inProgress",
|
|
15912
|
-
startedAt,
|
|
15913
|
-
completedAt: null,
|
|
15914
|
-
items: []
|
|
15915
|
-
};
|
|
15916
|
-
transcript.turns.push(turn);
|
|
15917
|
-
transcript.turns.sort((a, b) => Date.parse(a.startedAt) - Date.parse(b.startedAt));
|
|
15918
|
-
}
|
|
15919
|
-
this.dirtyTranscriptTurns.set(turnId, turn);
|
|
15920
|
-
if (Date.parse(startedAt) < Date.parse(turn.startedAt)) {
|
|
15921
|
-
turn.startedAt = startedAt;
|
|
15922
|
-
}
|
|
15923
|
-
return turn;
|
|
15622
|
+
this.completeItem(turnId, itemToTranscriptItem(blockedItem, timestampFromMilliseconds(startedAtMs), "failed"));
|
|
15924
15623
|
}
|
|
15925
|
-
|
|
15926
|
-
|
|
15927
|
-
|
|
15928
|
-
const images = imageContentToUserMessageImages(request.images);
|
|
15929
|
-
const userMessage = {
|
|
15930
|
-
type: "userMessage",
|
|
15931
|
-
id: request.messageId ?? `user-${turn.id}`,
|
|
15932
|
-
content: request.message,
|
|
15933
|
-
...images ? { images } : {},
|
|
15934
|
-
timestamp,
|
|
15935
|
-
sequence: this.nextTranscriptSequence()
|
|
15936
|
-
};
|
|
15937
|
-
const existingIndex = findEquivalentCodexAspTranscriptItemIndex(transcriptTurn.items, userMessage);
|
|
15938
|
-
if (existingIndex === -1) {
|
|
15939
|
-
transcriptTurn.items.push(userMessage);
|
|
15940
|
-
} else {
|
|
15941
|
-
transcriptTurn.items[existingIndex] = mergeCodexAspTranscriptItem(
|
|
15942
|
-
transcriptTurn.items[existingIndex],
|
|
15943
|
-
userMessage
|
|
15944
|
-
);
|
|
15624
|
+
ensureLiveTurn(turnId) {
|
|
15625
|
+
if (this.liveTurn?.id !== turnId) {
|
|
15626
|
+
this.liveTurn = { id: turnId, items: /* @__PURE__ */ new Map(), persistedItemIds: /* @__PURE__ */ new Set() };
|
|
15945
15627
|
}
|
|
15628
|
+
return this.liveTurn;
|
|
15946
15629
|
}
|
|
15947
|
-
|
|
15630
|
+
startTurn(turn) {
|
|
15631
|
+
this.ensureLiveTurn(turn.id);
|
|
15948
15632
|
const startedAt = timestampFromSeconds(turn.startedAt);
|
|
15949
|
-
const completedAt = turn.completedAt === null ? null : timestampFromSeconds(turn.completedAt);
|
|
15950
|
-
const itemTimestamp = completedAt ?? startedAt;
|
|
15951
|
-
const transcriptTurn = this.ensureTranscriptTurn(threadId, turn.id, startedAt);
|
|
15952
|
-
transcriptTurn.status = turn.status;
|
|
15953
|
-
transcriptTurn.completedAt = completedAt;
|
|
15954
|
-
const itemStatus = turn.status === "failed" ? "failed" : turn.status === "completed" ? "completed" : "in_progress";
|
|
15955
15633
|
for (const item of turn.items) {
|
|
15956
|
-
this.
|
|
15957
|
-
|
|
15958
|
-
|
|
15959
|
-
|
|
15960
|
-
|
|
15961
|
-
|
|
15962
|
-
|
|
15963
|
-
|
|
15964
|
-
}
|
|
15965
|
-
|
|
15966
|
-
|
|
15967
|
-
|
|
15968
|
-
if (
|
|
15969
|
-
|
|
15970
|
-
|
|
15971
|
-
|
|
15972
|
-
|
|
15973
|
-
|
|
15974
|
-
|
|
15975
|
-
|
|
15976
|
-
};
|
|
15977
|
-
if (existingIndex === -1) {
|
|
15978
|
-
transcriptTurn.items.push(errorItem);
|
|
15979
|
-
} else {
|
|
15980
|
-
transcriptTurn.items[existingIndex] = errorItem;
|
|
15981
|
-
}
|
|
15982
|
-
}
|
|
15983
|
-
if (this.codexAspTranscript) {
|
|
15984
|
-
this.codexAspTranscript.updatedAt = itemTimestamp;
|
|
15985
|
-
}
|
|
15986
|
-
}
|
|
15987
|
-
upsertTranscriptItem(threadId, turnId, item, timestamp, status, lifecycle) {
|
|
15988
|
-
const turn = this.ensureTranscriptTurn(threadId, turnId, timestamp);
|
|
15989
|
-
const candidate = itemToTranscriptItem(item, timestamp, status);
|
|
15990
|
-
if (!candidate) return;
|
|
15991
|
-
const existingIndex = findEquivalentCodexAspTranscriptItemIndex(turn.items, candidate);
|
|
15992
|
-
const existing = existingIndex === -1 ? null : turn.items[existingIndex];
|
|
15993
|
-
const sequence = existing?.sequence ?? this.nextTranscriptSequence();
|
|
15994
|
-
const itemTimestamp = existing && lifecycle === "completed" ? existing.timestamp : timestamp;
|
|
15995
|
-
const transcriptItem = itemToTranscriptItem(item, itemTimestamp, status);
|
|
15996
|
-
if (!transcriptItem) return;
|
|
15997
|
-
const sequencedItem = { ...transcriptItem, sequence };
|
|
15998
|
-
if (existingIndex === -1) {
|
|
15999
|
-
turn.items.push(sequencedItem);
|
|
16000
|
-
} else {
|
|
16001
|
-
const existingItem = turn.items[existingIndex];
|
|
16002
|
-
const mergedItem = mergeCodexAspTranscriptItem(existingItem, {
|
|
16003
|
-
...sequencedItem,
|
|
16004
|
-
timestamp: itemTimestamp,
|
|
16005
|
-
sequence
|
|
16006
|
-
});
|
|
16007
|
-
turn.items[existingIndex] = existingItem.type === "agentMessage" && mergedItem.type === "agentMessage" && lifecycle === "started" && mergedItem.text.length === 0 ? { ...mergedItem, text: existingItem.text } : mergedItem;
|
|
16008
|
-
}
|
|
16009
|
-
if (this.codexAspTranscript) {
|
|
16010
|
-
this.codexAspTranscript.updatedAt = timestamp;
|
|
16011
|
-
}
|
|
16012
|
-
}
|
|
16013
|
-
appendAgentMessageDelta(threadId, turnId, itemId, delta) {
|
|
16014
|
-
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
16015
|
-
const turn = this.ensureTranscriptTurn(threadId, turnId, timestamp);
|
|
16016
|
-
const existingIndex = turn.items.findIndex((item) => item.id === itemId);
|
|
16017
|
-
if (existingIndex === -1) {
|
|
16018
|
-
turn.items.push({
|
|
16019
|
-
type: "agentMessage",
|
|
16020
|
-
id: itemId,
|
|
16021
|
-
text: delta,
|
|
16022
|
-
timestamp,
|
|
16023
|
-
sequence: this.nextTranscriptSequence()
|
|
16024
|
-
});
|
|
16025
|
-
} else {
|
|
16026
|
-
const existing = turn.items[existingIndex];
|
|
16027
|
-
if (existing.type === "agentMessage") {
|
|
16028
|
-
turn.items[existingIndex] = {
|
|
16029
|
-
...existing,
|
|
16030
|
-
text: `${existing.text}${delta}`
|
|
16031
|
-
};
|
|
16032
|
-
}
|
|
16033
|
-
}
|
|
16034
|
-
if (this.codexAspTranscript) {
|
|
16035
|
-
this.codexAspTranscript.updatedAt = timestamp;
|
|
16036
|
-
}
|
|
15634
|
+
this.startItem(turn.id, itemToTranscriptItem(item, startedAt, "in_progress"));
|
|
15635
|
+
}
|
|
15636
|
+
}
|
|
15637
|
+
startItem(turnId, item) {
|
|
15638
|
+
if (!item) return;
|
|
15639
|
+
const turn = this.ensureLiveTurn(turnId);
|
|
15640
|
+
const existing = turn.items.get(item.id);
|
|
15641
|
+
const started = existing?.type === "agentMessage" && item.type === "agentMessage" && !item.text ? { ...item, text: existing.text } : item;
|
|
15642
|
+
turn.items.set(item.id, { ...started, timestamp: existing?.timestamp ?? item.timestamp });
|
|
15643
|
+
this.itemUpdateCoalescer.schedule(item.id, { immediate: true });
|
|
15644
|
+
}
|
|
15645
|
+
completeItem(turnId, item) {
|
|
15646
|
+
if (!item) return;
|
|
15647
|
+
const turn = this.ensureLiveTurn(turnId);
|
|
15648
|
+
const live = turn.items.get(item.id);
|
|
15649
|
+
turn.items.delete(item.id);
|
|
15650
|
+
turn.persistedItemIds.add(item.id);
|
|
15651
|
+
const event = codexItemEvent(turnId, live ? { ...item, timestamp: live.timestamp } : item);
|
|
15652
|
+
this.historyFile?.append(event);
|
|
15653
|
+
this.onEvent(event);
|
|
16037
15654
|
}
|
|
16038
|
-
|
|
16039
|
-
const
|
|
16040
|
-
const
|
|
16041
|
-
const
|
|
16042
|
-
|
|
16043
|
-
if (!
|
|
16044
|
-
turn.items.push({
|
|
16045
|
-
type: "reasoning",
|
|
16046
|
-
id: itemId,
|
|
16047
|
-
text: delta,
|
|
16048
|
-
timestamp,
|
|
16049
|
-
status: "in_progress",
|
|
16050
|
-
sequence: this.nextTranscriptSequence()
|
|
16051
|
-
});
|
|
16052
|
-
} else {
|
|
16053
|
-
const existing = turn.items[existingIndex];
|
|
16054
|
-
if (existing.type === "reasoning") {
|
|
16055
|
-
if (!delta.trim() && !existing.text.trim()) return;
|
|
16056
|
-
turn.items[existingIndex] = {
|
|
16057
|
-
...existing,
|
|
16058
|
-
text: `${existing.text}${delta}`
|
|
16059
|
-
};
|
|
16060
|
-
}
|
|
15655
|
+
completeTurn(turn) {
|
|
15656
|
+
const live = this.ensureLiveTurn(turn.id);
|
|
15657
|
+
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15658
|
+
const status = turn.status === "failed" ? "failed" : "completed";
|
|
15659
|
+
for (const item of turn.items) {
|
|
15660
|
+
if (!live.persistedItemIds.has(item.id)) this.completeItem(turn.id, itemToTranscriptItem(item, completedAt, status));
|
|
16061
15661
|
}
|
|
16062
|
-
|
|
16063
|
-
this.
|
|
15662
|
+
for (const item of live.items.values()) {
|
|
15663
|
+
this.completeItem(turn.id, item.type === "reasoning" ? { ...item, status } : item);
|
|
16064
15664
|
}
|
|
16065
|
-
|
|
16066
|
-
|
|
16067
|
-
|
|
16068
|
-
|
|
16069
|
-
|
|
16070
|
-
|
|
16071
|
-
|
|
16072
|
-
|
|
16073
|
-
|
|
16074
|
-
|
|
16075
|
-
turn.items
|
|
16076
|
-
|
|
16077
|
-
|
|
16078
|
-
|
|
16079
|
-
|
|
16080
|
-
|
|
16081
|
-
|
|
16082
|
-
|
|
16083
|
-
this.
|
|
15665
|
+
const failure = turn.error ? formatTurnFailure(turn) : void 0;
|
|
15666
|
+
this.lastTurnFailure = failure === void 0 ? null : { turnId: turn.id, message: failure };
|
|
15667
|
+
const event = codexTurnEvent(turn.id, turn.status, completedAt, failure);
|
|
15668
|
+
this.historyFile?.append(event);
|
|
15669
|
+
this.onEvent(event);
|
|
15670
|
+
this.liveTurn = null;
|
|
15671
|
+
}
|
|
15672
|
+
appendAgentMessageDelta(turnId, itemId, delta) {
|
|
15673
|
+
const turn = this.ensureLiveTurn(turnId);
|
|
15674
|
+
const existing = turn.items.get(itemId);
|
|
15675
|
+
turn.items.set(itemId, existing?.type === "agentMessage" ? { ...existing, text: `${existing.text}${delta}` } : { type: "agentMessage", id: itemId, text: delta, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
15676
|
+
this.itemUpdateCoalescer.schedule(itemId);
|
|
15677
|
+
}
|
|
15678
|
+
appendReasoningDelta(turnId, itemId, delta) {
|
|
15679
|
+
const turn = this.ensureLiveTurn(turnId);
|
|
15680
|
+
const existing = turn.items.get(itemId);
|
|
15681
|
+
if (!existing && !delta.trim()) return;
|
|
15682
|
+
turn.items.set(itemId, existing?.type === "reasoning" ? { ...existing, text: `${existing.text}${delta}` } : { type: "reasoning", id: itemId, text: delta, timestamp: (/* @__PURE__ */ new Date()).toISOString(), status: "in_progress" });
|
|
15683
|
+
this.itemUpdateCoalescer.schedule(itemId);
|
|
15684
|
+
}
|
|
15685
|
+
appendOutputDelta(turnId, itemId, delta) {
|
|
15686
|
+
const turn = this.ensureLiveTurn(turnId);
|
|
15687
|
+
const item = turn.items.get(itemId);
|
|
15688
|
+
if (item?.type !== "commandExecution" && item?.type !== "fileChange") return;
|
|
15689
|
+
turn.items.set(itemId, { ...item, output: appendCodexAspTranscriptOutput(item.output, delta), status: "in_progress" });
|
|
15690
|
+
this.itemUpdateCoalescer.schedule(itemId);
|
|
16084
15691
|
}
|
|
16085
15692
|
async refreshThreadGoal(host, threadId) {
|
|
16086
15693
|
try {
|
|
@@ -16119,109 +15726,6 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
16119
15726
|
trackHistoryEvent(event) {
|
|
16120
15727
|
this.historyFile?.append(event);
|
|
16121
15728
|
}
|
|
16122
|
-
emitTranscriptUpdated(threadId, options = {}) {
|
|
16123
|
-
this.transcriptUpdateCoalescer.schedule(threadId, options);
|
|
16124
|
-
}
|
|
16125
|
-
buildTranscriptItemDelta(previous, current) {
|
|
16126
|
-
if (previous === current) return null;
|
|
16127
|
-
if (!previous || previous.type !== current.type) {
|
|
16128
|
-
return { id: current.id, item: structuredClone(current) };
|
|
16129
|
-
}
|
|
16130
|
-
if (current.type === "agentMessage" && previous.type === "agentMessage" && current.text.startsWith(previous.text) && current.text.length > previous.text.length) {
|
|
16131
|
-
return {
|
|
16132
|
-
id: current.id,
|
|
16133
|
-
appendText: current.text.slice(previous.text.length)
|
|
16134
|
-
};
|
|
16135
|
-
}
|
|
16136
|
-
if ((current.type === "commandExecution" || current.type === "fileChange") && previous.type === current.type && current.output && current.output.startsWith(previous.output ?? "") && current.output.length > (previous.output ?? "").length) {
|
|
16137
|
-
const { output: _output, ...itemWithoutOutput } = current;
|
|
16138
|
-
const item = {
|
|
16139
|
-
...itemWithoutOutput,
|
|
16140
|
-
output: previous.output
|
|
16141
|
-
};
|
|
16142
|
-
return {
|
|
16143
|
-
id: current.id,
|
|
16144
|
-
item,
|
|
16145
|
-
appendOutput: current.output.slice((previous.output ?? "").length)
|
|
16146
|
-
};
|
|
16147
|
-
}
|
|
16148
|
-
if (JSON.stringify(previous) === JSON.stringify(current)) {
|
|
16149
|
-
return null;
|
|
16150
|
-
}
|
|
16151
|
-
return { id: current.id, item: structuredClone(current) };
|
|
16152
|
-
}
|
|
16153
|
-
buildTranscriptDelta(threadId, current) {
|
|
16154
|
-
const previous = this.lastEmittedTranscript;
|
|
16155
|
-
const updatedAt = current?.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
16156
|
-
if (!current || !previous || previous.threadId !== current.threadId) {
|
|
16157
|
-
return {
|
|
16158
|
-
threadId,
|
|
16159
|
-
updatedAt,
|
|
16160
|
-
reset: current ? structuredClone(current) : null,
|
|
16161
|
-
turns: []
|
|
16162
|
-
};
|
|
16163
|
-
}
|
|
16164
|
-
const turnDeltas = [];
|
|
16165
|
-
for (const currentTurn of this.dirtyTranscriptTurns.values()) {
|
|
16166
|
-
const previousTurn = previous.turns.get(currentTurn.id);
|
|
16167
|
-
if (!previousTurn) {
|
|
16168
|
-
turnDeltas.push({
|
|
16169
|
-
id: currentTurn.id,
|
|
16170
|
-
status: currentTurn.status,
|
|
16171
|
-
startedAt: currentTurn.startedAt,
|
|
16172
|
-
completedAt: currentTurn.completedAt,
|
|
16173
|
-
items: currentTurn.items.map((item) => ({ id: item.id, item: structuredClone(item) }))
|
|
16174
|
-
});
|
|
16175
|
-
continue;
|
|
16176
|
-
}
|
|
16177
|
-
const previousItems = new Map(previousTurn.items.map((item) => [item.id, item]));
|
|
16178
|
-
const itemDeltas = currentTurn.items.map((item) => this.buildTranscriptItemDelta(
|
|
16179
|
-
previousItems.get(item.id),
|
|
16180
|
-
item
|
|
16181
|
-
)).filter((item) => item !== null);
|
|
16182
|
-
if (itemDeltas.length > 0 || currentTurn.status !== previousTurn.status || currentTurn.startedAt !== previousTurn.startedAt || currentTurn.completedAt !== previousTurn.completedAt) {
|
|
16183
|
-
turnDeltas.push({
|
|
16184
|
-
id: currentTurn.id,
|
|
16185
|
-
status: currentTurn.status,
|
|
16186
|
-
startedAt: currentTurn.startedAt,
|
|
16187
|
-
completedAt: currentTurn.completedAt,
|
|
16188
|
-
items: itemDeltas
|
|
16189
|
-
});
|
|
16190
|
-
}
|
|
16191
|
-
}
|
|
16192
|
-
return {
|
|
16193
|
-
threadId: current.threadId,
|
|
16194
|
-
updatedAt,
|
|
16195
|
-
turns: turnDeltas
|
|
16196
|
-
};
|
|
16197
|
-
}
|
|
16198
|
-
flushTranscriptUpdated(threadId) {
|
|
16199
|
-
const updatedAt = this.codexAspTranscript?.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
16200
|
-
const transcriptDelta = this.buildTranscriptDelta(threadId, this.codexAspTranscript);
|
|
16201
|
-
const updatePayload = {
|
|
16202
|
-
updatedAt,
|
|
16203
|
-
threadId,
|
|
16204
|
-
transcript: transcriptDelta.reset ?? null,
|
|
16205
|
-
transcriptDelta
|
|
16206
|
-
};
|
|
16207
|
-
if (this.codexAspTranscript) {
|
|
16208
|
-
const snapshot = this.lastEmittedTranscript ?? { threadId, turns: /* @__PURE__ */ new Map() };
|
|
16209
|
-
for (const turn of this.dirtyTranscriptTurns.values()) {
|
|
16210
|
-
snapshot.turns.set(turn.id, { ...turn, items: [...turn.items] });
|
|
16211
|
-
}
|
|
16212
|
-
this.lastEmittedTranscript = snapshot;
|
|
16213
|
-
} else {
|
|
16214
|
-
this.lastEmittedTranscript = null;
|
|
16215
|
-
}
|
|
16216
|
-
this.dirtyTranscriptTurns.clear();
|
|
16217
|
-
const event = {
|
|
16218
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16219
|
-
type: CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE,
|
|
16220
|
-
payload: updatePayload
|
|
16221
|
-
};
|
|
16222
|
-
this.historyFile?.append(event);
|
|
16223
|
-
this.onEvent(event);
|
|
16224
|
-
}
|
|
16225
15729
|
handleRateLimits(rateLimits) {
|
|
16226
15730
|
const snapshot = extractRateLimitsSnapshot(rateLimits);
|
|
16227
15731
|
if (snapshot) {
|
|
@@ -16282,23 +15786,23 @@ var CodexAspManager = class extends CodingAgentManager {
|
|
|
16282
15786
|
};
|
|
16283
15787
|
|
|
16284
15788
|
// src/managers/cursor-manager.ts
|
|
16285
|
-
import { mkdir as mkdir12, readFile as
|
|
16286
|
-
import { basename as basename2, dirname as dirname6, extname, join as
|
|
15789
|
+
import { mkdir as mkdir12, readFile as readFile12, readdir as readdir5 } from "fs/promises";
|
|
15790
|
+
import { basename as basename2, dirname as dirname6, extname, join as join18 } from "path";
|
|
16287
15791
|
import { Agent as CursorAgent2 } from "@cursor/sdk";
|
|
16288
15792
|
|
|
16289
15793
|
// src/services/native-command-protection-hooks.ts
|
|
16290
15794
|
import { existsSync as existsSync8 } from "fs";
|
|
16291
|
-
import { mkdir as mkdir11, readFile as
|
|
16292
|
-
import { basename, dirname as dirname5, join as
|
|
15795
|
+
import { mkdir as mkdir11, readFile as readFile11, writeFile as writeFile6 } from "fs/promises";
|
|
15796
|
+
import { basename, dirname as dirname5, join as join17 } from "path";
|
|
16293
15797
|
import { fileURLToPath } from "url";
|
|
16294
15798
|
var moduleDirectory = dirname5(fileURLToPath(import.meta.url));
|
|
16295
15799
|
var hookPath = [
|
|
16296
|
-
|
|
16297
|
-
|
|
15800
|
+
join17(moduleDirectory, "command-protection-hook.js"),
|
|
15801
|
+
join17(moduleDirectory, "..", "command-protection-hook.ts")
|
|
16298
15802
|
].find(existsSync8);
|
|
16299
15803
|
var postToolHookPath = [
|
|
16300
|
-
|
|
16301
|
-
|
|
15804
|
+
join17(moduleDirectory, "post-tool-pr-hook.js"),
|
|
15805
|
+
join17(moduleDirectory, "..", "post-tool-pr-hook.ts")
|
|
16302
15806
|
].find(existsSync8);
|
|
16303
15807
|
function shellCommand(path7, provider) {
|
|
16304
15808
|
if (!path7) throw new Error("Replicas hook executable is missing.");
|
|
@@ -16319,10 +15823,10 @@ function getPostToolPrHookPath() {
|
|
|
16319
15823
|
return postToolHookPath;
|
|
16320
15824
|
}
|
|
16321
15825
|
async function ensureCursorCommandProtectionHook() {
|
|
16322
|
-
const path7 =
|
|
15826
|
+
const path7 = join17(ENGINE_ENV.HOME_DIR, ".cursor", "hooks.json");
|
|
16323
15827
|
let config = {};
|
|
16324
15828
|
try {
|
|
16325
|
-
const parsed = JSON.parse(await
|
|
15829
|
+
const parsed = JSON.parse(await readFile11(path7, "utf8"));
|
|
16326
15830
|
if (!isRecord2(parsed)) throw new Error("Invalid Cursor hooks configuration.");
|
|
16327
15831
|
config = parsed;
|
|
16328
15832
|
} catch (error) {
|
|
@@ -16344,10 +15848,10 @@ async function ensureCursorCommandProtectionHook() {
|
|
|
16344
15848
|
`, "utf8");
|
|
16345
15849
|
}
|
|
16346
15850
|
async function ensureGeminiCommandProtectionHook() {
|
|
16347
|
-
const path7 =
|
|
15851
|
+
const path7 = join17(ENGINE_ENV.HOME_DIR, ".gemini", "settings.json");
|
|
16348
15852
|
let config = {};
|
|
16349
15853
|
try {
|
|
16350
|
-
const parsed = JSON.parse(await
|
|
15854
|
+
const parsed = JSON.parse(await readFile11(path7, "utf8"));
|
|
16351
15855
|
if (!isRecord2(parsed)) throw new Error("Invalid Gemini hooks configuration.");
|
|
16352
15856
|
config = parsed;
|
|
16353
15857
|
} catch (error) {
|
|
@@ -16372,12 +15876,12 @@ async function ensureGeminiCommandProtectionHook() {
|
|
|
16372
15876
|
`, "utf8");
|
|
16373
15877
|
}
|
|
16374
15878
|
async function ensureKimiCommandProtectionHook() {
|
|
16375
|
-
const path7 =
|
|
15879
|
+
const path7 = join17(ENGINE_ENV.HOME_DIR, ".kimi-code", "config.toml");
|
|
16376
15880
|
const start = "# Replicas command protection hook";
|
|
16377
15881
|
const end = "# End Replicas command protection hook";
|
|
16378
15882
|
let config = "";
|
|
16379
15883
|
try {
|
|
16380
|
-
config = await
|
|
15884
|
+
config = await readFile11(path7, "utf8");
|
|
16381
15885
|
} catch (error) {
|
|
16382
15886
|
if (!(error && typeof error === "object" && "code" in error && error.code === "ENOENT")) throw error;
|
|
16383
15887
|
}
|
|
@@ -16464,7 +15968,7 @@ function extractCursorCommandDescription(content) {
|
|
|
16464
15968
|
async function listCursorCommandsInDirectory(directory) {
|
|
16465
15969
|
let entries;
|
|
16466
15970
|
try {
|
|
16467
|
-
entries = await
|
|
15971
|
+
entries = await readdir5(directory, { withFileTypes: true });
|
|
16468
15972
|
} catch (error) {
|
|
16469
15973
|
if (isRecord2(error) && error.code === "ENOENT") return [];
|
|
16470
15974
|
console.warn("[CursorManager] Failed to read slash command directory:", error);
|
|
@@ -16474,7 +15978,7 @@ async function listCursorCommandsInDirectory(directory) {
|
|
|
16474
15978
|
const name = basename2(entry.name, ".md");
|
|
16475
15979
|
let description;
|
|
16476
15980
|
try {
|
|
16477
|
-
description = extractCursorCommandDescription(await
|
|
15981
|
+
description = extractCursorCommandDescription(await readFile12(join18(directory, entry.name), "utf8"));
|
|
16478
15982
|
} catch (error) {
|
|
16479
15983
|
console.warn("[CursorManager] Failed to read slash command file:", error);
|
|
16480
15984
|
}
|
|
@@ -16496,7 +16000,7 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
16496
16000
|
slashCommandsRequest = null;
|
|
16497
16001
|
constructor(options) {
|
|
16498
16002
|
super(options);
|
|
16499
|
-
this.historyFilePath = options.historyFilePath ??
|
|
16003
|
+
this.historyFilePath = options.historyFilePath ?? join18(ENGINE_ENV.HOME_DIR, ".replicas", "cursor", "history.jsonl");
|
|
16500
16004
|
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
16501
16005
|
this.initializeManager(this.processMessageInternal.bind(this));
|
|
16502
16006
|
}
|
|
@@ -16571,7 +16075,7 @@ var CursorManager = class extends CodingAgentManager {
|
|
|
16571
16075
|
this.slashCommandsRequest ??= (async () => {
|
|
16572
16076
|
try {
|
|
16573
16077
|
const repoDirectories = await getAgentAdditionalDirectories();
|
|
16574
|
-
const commandDirectories = [this.workingDirectory, ...repoDirectories, ENGINE_ENV.HOME_DIR].map((directory) =>
|
|
16078
|
+
const commandDirectories = [this.workingDirectory, ...repoDirectories, ENGINE_ENV.HOME_DIR].map((directory) => join18(directory, ".cursor", "commands"));
|
|
16575
16079
|
const commands = mergeSlashCommands(
|
|
16576
16080
|
...await Promise.all(commandDirectories.map(listCursorCommandsInDirectory))
|
|
16577
16081
|
);
|
|
@@ -16852,10 +16356,10 @@ ${instructions}
|
|
|
16852
16356
|
import { spawn as spawn3 } from "child_process";
|
|
16853
16357
|
import { createHash as createHash2, randomUUID as randomUUID6 } from "crypto";
|
|
16854
16358
|
import { createRequire } from "module";
|
|
16855
|
-
import { basename as basename3, dirname as dirname7, join as
|
|
16359
|
+
import { basename as basename3, dirname as dirname7, join as join19 } from "path";
|
|
16856
16360
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
16857
16361
|
import { existsSync as existsSync9 } from "fs";
|
|
16858
|
-
import { mkdir as mkdir13, readFile as
|
|
16362
|
+
import { mkdir as mkdir13, readFile as readFile13, rename as rename3, writeFile as writeFile7 } from "fs/promises";
|
|
16859
16363
|
import { z as z2 } from "zod";
|
|
16860
16364
|
import WebSocket from "ws";
|
|
16861
16365
|
import { AbstractApiClient } from "@deepseek-ai/dsh-host-apiproxy/client";
|
|
@@ -16867,17 +16371,17 @@ var questionSelectionSchema = z2.record(z2.string(), z2.object({
|
|
|
16867
16371
|
custom: z2.string().optional()
|
|
16868
16372
|
}));
|
|
16869
16373
|
var require2 = createRequire(import.meta.url);
|
|
16870
|
-
var DSH_BIN =
|
|
16374
|
+
var DSH_BIN = join19(dirname7(require2.resolve("@deepseek-ai/dsh/package.json")), "lib", "bin.js");
|
|
16871
16375
|
var MANAGER_DIR = dirname7(fileURLToPath2(import.meta.url));
|
|
16872
16376
|
var DSH_PATCH = [
|
|
16873
|
-
|
|
16874
|
-
|
|
16377
|
+
join19(MANAGER_DIR, "..", "..", "scripts", "deepseek", "replicas.cordis.patch.yml"),
|
|
16378
|
+
join19(MANAGER_DIR, "..", "..", "..", "scripts", "deepseek", "replicas.cordis.patch.yml")
|
|
16875
16379
|
].find(existsSync9) ?? "";
|
|
16876
16380
|
var DSH_COMMAND_PROTECTION_PLUGIN = [
|
|
16877
|
-
|
|
16878
|
-
|
|
16381
|
+
join19(MANAGER_DIR, "deepseek-command-protection-plugin.js"),
|
|
16382
|
+
join19(MANAGER_DIR, "..", "deepseek-command-protection-plugin.ts")
|
|
16879
16383
|
].find(existsSync9) ?? "";
|
|
16880
|
-
var DEEPSEEK_HOME =
|
|
16384
|
+
var DEEPSEEK_HOME = join19(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek");
|
|
16881
16385
|
function relayPresetContent(content, instructions, mcp) {
|
|
16882
16386
|
const personaMarker = " text: >-\n";
|
|
16883
16387
|
const personaStart = content.indexOf(personaMarker);
|
|
@@ -17022,8 +16526,8 @@ var DeepseekManager = class extends CodingAgentManager {
|
|
|
17022
16526
|
constructor(options) {
|
|
17023
16527
|
super(options);
|
|
17024
16528
|
this.sessionId = options.initialSessionId ? sessionIdSchema.parse(options.initialSessionId) : null;
|
|
17025
|
-
this.historyFilePath = options.historyFilePath ??
|
|
17026
|
-
this.deepseekHome = this.isRelay ?
|
|
16529
|
+
this.historyFilePath = options.historyFilePath ?? join19(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek", "history.jsonl");
|
|
16530
|
+
this.deepseekHome = this.isRelay ? join19(ENGINE_ENV.HOME_DIR, ".replicas", "deepseek-relay", basename3(this.historyFilePath, ".jsonl")) : DEEPSEEK_HOME;
|
|
17027
16531
|
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
17028
16532
|
this.initializeManager(this.processMessageInternal.bind(this));
|
|
17029
16533
|
}
|
|
@@ -17102,9 +16606,9 @@ var DeepseekManager = class extends CodingAgentManager {
|
|
|
17102
16606
|
async ensureClient() {
|
|
17103
16607
|
if (this.client) return this.client;
|
|
17104
16608
|
if (!DSH_PATCH || !DSH_COMMAND_PROTECTION_PLUGIN) throw new Error("DeepSeek Harness configuration is missing from the engine package.");
|
|
17105
|
-
const runtimePatch =
|
|
16609
|
+
const runtimePatch = join19(this.deepseekHome, "replicas.cordis.patch.yml");
|
|
17106
16610
|
await mkdir13(dirname7(runtimePatch), { recursive: true });
|
|
17107
|
-
await writeFile7(runtimePatch, (await
|
|
16611
|
+
await writeFile7(runtimePatch, (await readFile13(DSH_PATCH, "utf8")).replace(
|
|
17108
16612
|
"__REPLICAS_DSH_COMMAND_PROTECTION_PLUGIN__",
|
|
17109
16613
|
JSON.stringify(DSH_COMMAND_PROTECTION_PLUGIN)
|
|
17110
16614
|
));
|
|
@@ -17177,10 +16681,10 @@ var DeepseekManager = class extends CodingAgentManager {
|
|
|
17177
16681
|
if (!roster.some((preset) => preset.id === agentPreset)) {
|
|
17178
16682
|
const stage = `relay-stage-${randomUUID6().replaceAll("-", "")}`;
|
|
17179
16683
|
unwrap(await client2.agentPresets.copy({ from: "standard", agentPreset: stage, name: "Relay" }));
|
|
17180
|
-
const stageDirectory =
|
|
16684
|
+
const stageDirectory = join19(this.deepseekHome, ".agent-presets", stage);
|
|
17181
16685
|
try {
|
|
17182
|
-
await writeFile7(
|
|
17183
|
-
await
|
|
16686
|
+
await writeFile7(join19(stageDirectory, "agent.cordis.yml"), content, "utf8");
|
|
16687
|
+
await rename3(stageDirectory, join19(this.deepseekHome, ".agent-presets", agentPreset));
|
|
17184
16688
|
} catch (error) {
|
|
17185
16689
|
unwrap(await client2.agentPresets.remove({ agentPreset: stage }));
|
|
17186
16690
|
if (!unwrap(await client2.agentPresets.list({})).presets.some((preset) => preset.id === agentPreset)) throw error;
|
|
@@ -17354,13 +16858,13 @@ ${request.message}` : request.message;
|
|
|
17354
16858
|
};
|
|
17355
16859
|
|
|
17356
16860
|
// src/managers/fx-manager.ts
|
|
17357
|
-
import { readFile as
|
|
16861
|
+
import { readFile as readFile16 } from "fs/promises";
|
|
17358
16862
|
import { spawn as spawn5 } from "child_process";
|
|
17359
16863
|
|
|
17360
16864
|
// src/managers/acp-manager.ts
|
|
17361
16865
|
import { spawn as spawn4 } from "child_process";
|
|
17362
16866
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
17363
|
-
import { mkdir as mkdir14, readFile as
|
|
16867
|
+
import { mkdir as mkdir14, readFile as readFile15, writeFile as writeFile8 } from "fs/promises";
|
|
17364
16868
|
import { dirname as dirname8 } from "path";
|
|
17365
16869
|
import { Writable } from "stream";
|
|
17366
16870
|
import {
|
|
@@ -17371,24 +16875,24 @@ import {
|
|
|
17371
16875
|
} from "@agentclientprotocol/sdk";
|
|
17372
16876
|
|
|
17373
16877
|
// src/services/installed-skill-service.ts
|
|
17374
|
-
import { readFile as
|
|
17375
|
-
import { join as
|
|
16878
|
+
import { readFile as readFile14, readdir as readdir6 } from "fs/promises";
|
|
16879
|
+
import { join as join20 } from "path";
|
|
17376
16880
|
var installedSkillsByHome = /* @__PURE__ */ new Map();
|
|
17377
16881
|
function isNotFoundError2(error) {
|
|
17378
16882
|
return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
|
|
17379
16883
|
}
|
|
17380
16884
|
async function loadInstalledSkills(homeDir) {
|
|
17381
|
-
const skillsDir =
|
|
16885
|
+
const skillsDir = join20(homeDir, ".agents/skills");
|
|
17382
16886
|
let entries;
|
|
17383
16887
|
try {
|
|
17384
|
-
entries = await
|
|
16888
|
+
entries = await readdir6(skillsDir, { withFileTypes: true });
|
|
17385
16889
|
} catch (error) {
|
|
17386
16890
|
if (!isNotFoundError2(error)) console.warn("[InstalledSkills] Failed to list installed skills:", error);
|
|
17387
16891
|
return [];
|
|
17388
16892
|
}
|
|
17389
16893
|
const skills = await Promise.all(entries.filter((entry) => entry.isDirectory() || entry.isSymbolicLink()).map(async (entry) => {
|
|
17390
16894
|
try {
|
|
17391
|
-
const metadata = parseFrontmatter(await
|
|
16895
|
+
const metadata = parseFrontmatter(await readFile14(join20(skillsDir, entry.name, "SKILL.md"), "utf8"));
|
|
17392
16896
|
return metadata.name && metadata.description ? metadata : null;
|
|
17393
16897
|
} catch (error) {
|
|
17394
16898
|
if (!isNotFoundError2(error)) console.warn(`[InstalledSkills] Failed to read ${entry.name}:`, error);
|
|
@@ -17473,7 +16977,7 @@ var AcpManager = class extends CodingAgentManager {
|
|
|
17473
16977
|
});
|
|
17474
16978
|
const app2 = client({ name: "Replicas" }).onNotification(methods.client.session.update, ({ params }) => this.recordUpdate(params)).onRequest(methods.client.fs.readTextFile, async ({ params }) => {
|
|
17475
16979
|
this.assertSession(params.sessionId);
|
|
17476
|
-
const content = await
|
|
16980
|
+
const content = await readFile15(params.path, "utf8");
|
|
17477
16981
|
if (params.line === void 0 && params.limit === void 0) return { content };
|
|
17478
16982
|
const start = Math.max(0, (params.line ?? 1) - 1);
|
|
17479
16983
|
const end = params.limit === null || params.limit === void 0 ? void 0 : start + params.limit;
|
|
@@ -17864,7 +17368,7 @@ ${request.message}` : request.message
|
|
|
17864
17368
|
|
|
17865
17369
|
// src/managers/fx-manager.ts
|
|
17866
17370
|
async function ensureResolvableDnsConfig() {
|
|
17867
|
-
const contents = await
|
|
17371
|
+
const contents = await readFile16("/etc/resolv.conf");
|
|
17868
17372
|
if (contents.length === 0 || contents.at(-1) === 10) return;
|
|
17869
17373
|
await new Promise((resolve7, reject) => {
|
|
17870
17374
|
const child = spawn5("sudo", ["tee", "-a", "/etc/resolv.conf"], { stdio: ["pipe", "ignore", "pipe"] });
|
|
@@ -18474,8 +17978,8 @@ ${pending}
|
|
|
18474
17978
|
|
|
18475
17979
|
// src/managers/opencode-manager.ts
|
|
18476
17980
|
import { existsSync as existsSync10 } from "fs";
|
|
18477
|
-
import { copyFile, mkdir as mkdir16, readFile as
|
|
18478
|
-
import { delimiter, dirname as dirname10, join as
|
|
17981
|
+
import { copyFile, mkdir as mkdir16, readFile as readFile17, rm as rm2 } from "fs/promises";
|
|
17982
|
+
import { delimiter, dirname as dirname10, join as join21 } from "path";
|
|
18479
17983
|
import { randomBytes as randomBytes3 } from "crypto";
|
|
18480
17984
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
18481
17985
|
import { Agent } from "undici";
|
|
@@ -18504,10 +18008,10 @@ async function getAllowedOpenRouterModels() {
|
|
|
18504
18008
|
|
|
18505
18009
|
// src/managers/opencode-manager.ts
|
|
18506
18010
|
var OPENCODE_SHIM_DIR = dirname10(fileURLToPath3(new URL("../../scripts/opencode", import.meta.url)));
|
|
18507
|
-
var OPENCODE_COMMAND_PROTECTION_PLUGIN_SOURCE =
|
|
18508
|
-
var OPENCODE_COMMAND_PROTECTION_PLUGIN_PATH =
|
|
18509
|
-
var OPENCODE_LEGACY_COMMAND_PROTECTION_PLUGIN_PATH =
|
|
18510
|
-
var OPENCODE_CONFIG_PATH =
|
|
18011
|
+
var OPENCODE_COMMAND_PROTECTION_PLUGIN_SOURCE = join21(OPENCODE_SHIM_DIR, "opencode-command-protection-plugin.ts");
|
|
18012
|
+
var OPENCODE_COMMAND_PROTECTION_PLUGIN_PATH = join21(ENGINE_ENV.HOME_DIR, ".config", "opencode", "plugins", "replicas-command-protection.ts");
|
|
18013
|
+
var OPENCODE_LEGACY_COMMAND_PROTECTION_PLUGIN_PATH = join21(ENGINE_ENV.HOME_DIR, ".config", "opencode", "plugins", "replicas-command-protection.mjs");
|
|
18014
|
+
var OPENCODE_CONFIG_PATH = join21(ENGINE_ENV.HOME_DIR, ".config", "opencode", "opencode.json");
|
|
18511
18015
|
var OPENCODE_FETCH_DISPATCHER = new Agent({ headersTimeout: 0, bodyTimeout: 0 });
|
|
18512
18016
|
var OPENCODE_SERVER_STARTUP_TIMEOUT_MS = 3e4;
|
|
18513
18017
|
var OPENCODE_WORKSPACE_PERMISSION = "allow";
|
|
@@ -18528,7 +18032,7 @@ var opencodeAuthSchema = z3.record(z3.string(), z3.object({
|
|
|
18528
18032
|
async function hasOpencodeCredentials(provider) {
|
|
18529
18033
|
if (!existsSync10(OPENCODE_AUTH_PATH)) return false;
|
|
18530
18034
|
try {
|
|
18531
|
-
const auth2 = opencodeAuthSchema.safeParse(JSON.parse(await
|
|
18035
|
+
const auth2 = opencodeAuthSchema.safeParse(JSON.parse(await readFile17(OPENCODE_AUTH_PATH, "utf8")));
|
|
18532
18036
|
return auth2.success && auth2.data[provider]?.type === "api" && Boolean(auth2.data[provider]?.key);
|
|
18533
18037
|
} catch {
|
|
18534
18038
|
return false;
|
|
@@ -18633,7 +18137,7 @@ function isOpencodeMcpEntry(value) {
|
|
|
18633
18137
|
async function readProvisionedOpencodeMcpConfig() {
|
|
18634
18138
|
let raw;
|
|
18635
18139
|
try {
|
|
18636
|
-
raw = await
|
|
18140
|
+
raw = await readFile17(OPENCODE_CONFIG_PATH, "utf8");
|
|
18637
18141
|
} catch (error) {
|
|
18638
18142
|
if (isRecord2(error) && error.code === "ENOENT") return void 0;
|
|
18639
18143
|
console.error("[OpencodeManager] Failed to read Opencode config:", error);
|
|
@@ -18719,7 +18223,7 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
18719
18223
|
constructor(options) {
|
|
18720
18224
|
super({ ...options, provider: "opencode" });
|
|
18721
18225
|
this.sessionId = options.initialSessionId;
|
|
18722
|
-
this.historyFilePath = options.historyFilePath ??
|
|
18226
|
+
this.historyFilePath = options.historyFilePath ?? join21(ENGINE_ENV.HOME_DIR, ".replicas", "opencode", "history.jsonl");
|
|
18723
18227
|
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
18724
18228
|
this.initializeManager(this.processMessageInternal.bind(this));
|
|
18725
18229
|
}
|
|
@@ -19139,8 +18643,8 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
19139
18643
|
};
|
|
19140
18644
|
|
|
19141
18645
|
// src/managers/pi-manager.ts
|
|
19142
|
-
import { mkdir as mkdir18, readFile as
|
|
19143
|
-
import { dirname as dirname18, join as
|
|
18646
|
+
import { mkdir as mkdir18, readFile as readFile18 } from "fs/promises";
|
|
18647
|
+
import { dirname as dirname18, join as join29 } from "path";
|
|
19144
18648
|
import {
|
|
19145
18649
|
createAgentSession,
|
|
19146
18650
|
ModelRegistry,
|
|
@@ -19149,6 +18653,37 @@ import {
|
|
|
19149
18653
|
DefaultResourceLoader
|
|
19150
18654
|
} from "@earendil-works/pi-coding-agent";
|
|
19151
18655
|
|
|
18656
|
+
// src/services/chat/history-paths.ts
|
|
18657
|
+
import { homedir as homedir12 } from "os";
|
|
18658
|
+
import { join as join22 } from "path";
|
|
18659
|
+
var ENGINE_DIR2 = join22(homedir12(), ".replicas", "engine");
|
|
18660
|
+
var CHATS_FILE = join22(ENGINE_DIR2, "chats.json");
|
|
18661
|
+
var CLAUDE_HISTORY_DIR = join22(ENGINE_DIR2, "claude-histories");
|
|
18662
|
+
var RELAY_HISTORY_DIR = join22(ENGINE_DIR2, "relay-histories");
|
|
18663
|
+
var CODEX_HISTORY_DIR = join22(ENGINE_DIR2, "codex-histories");
|
|
18664
|
+
var CURSOR_HISTORY_DIR = join22(ENGINE_DIR2, "cursor-histories");
|
|
18665
|
+
var OPENCODE_HISTORY_DIR = join22(ENGINE_DIR2, "opencode-histories");
|
|
18666
|
+
var PI_HISTORY_DIR = join22(ENGINE_DIR2, "pi-histories");
|
|
18667
|
+
var DEEPSEEK_HISTORY_DIR = join22(ENGINE_DIR2, "deepseek-histories");
|
|
18668
|
+
var FX_HISTORY_DIR = join22(ENGINE_DIR2, "fx-histories");
|
|
18669
|
+
var GEMINI_HISTORY_DIR = join22(ENGINE_DIR2, "gemini-histories");
|
|
18670
|
+
var KIMI_HISTORY_DIR = join22(ENGINE_DIR2, "kimi-histories");
|
|
18671
|
+
var MUSE_HISTORY_DIR = join22(ENGINE_DIR2, "muse-histories");
|
|
18672
|
+
var FORKS_DIR = join22(ENGINE_DIR2, "forks");
|
|
18673
|
+
var HISTORY_DIR_BY_PROVIDER = {
|
|
18674
|
+
claude: CLAUDE_HISTORY_DIR,
|
|
18675
|
+
relay: RELAY_HISTORY_DIR,
|
|
18676
|
+
codex: CODEX_HISTORY_DIR,
|
|
18677
|
+
cursor: CURSOR_HISTORY_DIR,
|
|
18678
|
+
deepseek: DEEPSEEK_HISTORY_DIR,
|
|
18679
|
+
fx: FX_HISTORY_DIR,
|
|
18680
|
+
gemini: GEMINI_HISTORY_DIR,
|
|
18681
|
+
kimi: KIMI_HISTORY_DIR,
|
|
18682
|
+
muse: MUSE_HISTORY_DIR,
|
|
18683
|
+
opencode: OPENCODE_HISTORY_DIR,
|
|
18684
|
+
pi: PI_HISTORY_DIR
|
|
18685
|
+
};
|
|
18686
|
+
|
|
19152
18687
|
// ../node_modules/.bun/typebox@1.3.7/node_modules/typebox/build/system/memory/memory.mjs
|
|
19153
18688
|
var memory_exports = {};
|
|
19154
18689
|
__export(memory_exports, {
|
|
@@ -41679,7 +41214,7 @@ async function probeMcpEndpoint(url3) {
|
|
|
41679
41214
|
|
|
41680
41215
|
// ../node_modules/.bun/pi-mcp-adapter@2.32.1+04b0d7b0bc944965/node_modules/pi-mcp-adapter/npx-resolver.ts
|
|
41681
41216
|
import { existsSync as existsSync11, readFileSync as readFileSync4, realpathSync, readdirSync, statSync, writeFileSync, renameSync, mkdirSync, openSync, readSync, closeSync, unlinkSync } from "fs";
|
|
41682
|
-
import { join as
|
|
41217
|
+
import { join as join23, dirname as dirname11, extname as extname2, resolve as resolve2, sep } from "path";
|
|
41683
41218
|
|
|
41684
41219
|
// ../node_modules/.bun/pi-mcp-adapter@2.32.1+04b0d7b0bc944965/node_modules/pi-mcp-adapter/abort.ts
|
|
41685
41220
|
function throwIfAborted(signal) {
|
|
@@ -41836,7 +41371,7 @@ function resolveFromNpmCache(packageSpec, binName) {
|
|
|
41836
41371
|
const { packageName, exactVersion } = parsedSpec;
|
|
41837
41372
|
const packageDir = findCachedPackageDir(cacheDir, packageName, exactVersion);
|
|
41838
41373
|
if (!packageDir) return null;
|
|
41839
|
-
const packageJsonPath =
|
|
41374
|
+
const packageJsonPath = join23(packageDir, "package.json");
|
|
41840
41375
|
if (!existsSync11(packageJsonPath)) return null;
|
|
41841
41376
|
let pkg = null;
|
|
41842
41377
|
try {
|
|
@@ -41870,7 +41405,7 @@ function resolveFromNpmCache(packageSpec, binName) {
|
|
|
41870
41405
|
}
|
|
41871
41406
|
if (!binRel) return null;
|
|
41872
41407
|
const nodeModulesDir = findNodeModulesDir(packageDir);
|
|
41873
|
-
const binLink = chosenBinName ?
|
|
41408
|
+
const binLink = chosenBinName ? join23(nodeModulesDir, ".bin", chosenBinName) : null;
|
|
41874
41409
|
let resolvedBin = binLink && existsSync11(binLink) ? safeRealpath(binLink) : "";
|
|
41875
41410
|
if (!resolvedBin) {
|
|
41876
41411
|
resolvedBin = resolve2(packageDir, binRel);
|
|
@@ -41972,17 +41507,17 @@ function defaultBinName(packageName) {
|
|
|
41972
41507
|
return packageName;
|
|
41973
41508
|
}
|
|
41974
41509
|
function findCachedPackageDir(cacheDir, packageName, exactVersion) {
|
|
41975
|
-
const npxDir =
|
|
41510
|
+
const npxDir = join23(cacheDir, "_npx");
|
|
41976
41511
|
if (!existsSync11(npxDir)) return null;
|
|
41977
41512
|
const packagePathParts = packageName.startsWith("@") ? packageName.split("/") : [packageName];
|
|
41978
41513
|
const candidates = readdirSync(npxDir, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => {
|
|
41979
|
-
const full =
|
|
41514
|
+
const full = join23(npxDir, entry.name);
|
|
41980
41515
|
const mtime = safeStatMtime(full);
|
|
41981
41516
|
return { name: entry.name, mtime };
|
|
41982
41517
|
}).sort((a, b) => b.mtime - a.mtime);
|
|
41983
41518
|
for (const entry of candidates) {
|
|
41984
|
-
const pkgDir =
|
|
41985
|
-
const packageJsonPath =
|
|
41519
|
+
const pkgDir = join23(npxDir, entry.name, "node_modules", ...packagePathParts);
|
|
41520
|
+
const packageJsonPath = join23(pkgDir, "package.json");
|
|
41986
41521
|
if (!existsSync11(packageJsonPath)) continue;
|
|
41987
41522
|
if (exactVersion) {
|
|
41988
41523
|
try {
|
|
@@ -42002,7 +41537,7 @@ function findNodeModulesDir(packageDir) {
|
|
|
42002
41537
|
if (idx >= 0) {
|
|
42003
41538
|
return parts.slice(0, idx + 1).join(sep);
|
|
42004
41539
|
}
|
|
42005
|
-
return
|
|
41540
|
+
return join23(packageDir, "..");
|
|
42006
41541
|
}
|
|
42007
41542
|
function detectJsBinary(binPath) {
|
|
42008
41543
|
const ext = extname2(binPath).toLowerCase();
|
|
@@ -42194,7 +41729,7 @@ import { spawnSync } from "child_process";
|
|
|
42194
41729
|
import { createHash as createHash3 } from "crypto";
|
|
42195
41730
|
import { createRequire as createRequire2 } from "module";
|
|
42196
41731
|
import { readFileSync as readFileSync5, existsSync as existsSync12, rmSync } from "fs";
|
|
42197
|
-
import { dirname as dirname12, join as
|
|
41732
|
+
import { dirname as dirname12, join as join24 } from "path";
|
|
42198
41733
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
42199
41734
|
var require3 = createRequire2(import.meta.url);
|
|
42200
41735
|
var AUTH_SECRET_SERVICE = "pi-mcp-adapter.oauth";
|
|
@@ -42350,7 +41885,7 @@ function loadKeyringNativeBindingFallback(keyringRequire, platform3, arch2) {
|
|
|
42350
41885
|
for (const target of targets) {
|
|
42351
41886
|
try {
|
|
42352
41887
|
const packageJsonPath = keyringRequire.resolve(`${target.packageName}/package.json`);
|
|
42353
|
-
return keyringRequire(
|
|
41888
|
+
return keyringRequire(join24(dirname12(packageJsonPath), target.bindingFile));
|
|
42354
41889
|
} catch (error) {
|
|
42355
41890
|
lastError = error;
|
|
42356
41891
|
}
|
|
@@ -42455,7 +41990,7 @@ function getServerDir(serverName, options) {
|
|
|
42455
41990
|
throw new Error(`Invalid MCP server name: ${JSON.stringify(serverName)}`);
|
|
42456
41991
|
}
|
|
42457
41992
|
const storageKey = getAuthEntryAccount(serverName);
|
|
42458
|
-
return
|
|
41993
|
+
return join24(getAuthBaseDir(options), storageKey);
|
|
42459
41994
|
}
|
|
42460
41995
|
function getAuthEntryAccount(serverName) {
|
|
42461
41996
|
if (typeof serverName !== "string") {
|
|
@@ -42464,7 +41999,7 @@ function getAuthEntryAccount(serverName) {
|
|
|
42464
41999
|
return `sha256-${createHash3("sha256").update(serverName, "utf8").digest("hex")}`;
|
|
42465
42000
|
}
|
|
42466
42001
|
function getAuthEntryFilePath(serverName, options) {
|
|
42467
|
-
return
|
|
42002
|
+
return join24(getServerDir(serverName, options), "tokens.json");
|
|
42468
42003
|
}
|
|
42469
42004
|
function parseJsonPayload(serverName, payload, source) {
|
|
42470
42005
|
try {
|
|
@@ -45067,7 +44602,7 @@ async function shutdownOAuth(runtime = legacyRuntime) {
|
|
|
45067
44602
|
// ../node_modules/.bun/pi-mcp-adapter@2.32.1+04b0d7b0bc944965/node_modules/pi-mcp-adapter/mcp-bearer-store.ts
|
|
45068
44603
|
import { createHash as createHash4 } from "crypto";
|
|
45069
44604
|
import { createRequire as createRequire3 } from "module";
|
|
45070
|
-
import { dirname as dirname13, join as
|
|
44605
|
+
import { dirname as dirname13, join as join25 } from "path";
|
|
45071
44606
|
var require4 = createRequire3(import.meta.url);
|
|
45072
44607
|
var BEARER_SECRET_SERVICE = "pi-mcp-adapter.bearer";
|
|
45073
44608
|
var TEST_AUTH_STORE_ENV2 = "PI_MCP_ADAPTER_TEST_AUTH_STORE";
|
|
@@ -45169,7 +44704,7 @@ function loadKeyringNativeBindingFallback2(keyringRequire, platform3, arch2) {
|
|
|
45169
44704
|
for (const target of targets) {
|
|
45170
44705
|
try {
|
|
45171
44706
|
const packageJsonPath = keyringRequire.resolve(`${target.packageName}/package.json`);
|
|
45172
|
-
return keyringRequire(
|
|
44707
|
+
return keyringRequire(join25(dirname13(packageJsonPath), target.bindingFile));
|
|
45173
44708
|
} catch (error) {
|
|
45174
44709
|
lastError = error;
|
|
45175
44710
|
}
|
|
@@ -49636,7 +49171,7 @@ async function openMcpAuthPanel(state, pi, ctx, configOverridePath) {
|
|
|
49636
49171
|
// ../node_modules/.bun/pi-mcp-adapter@2.32.1+04b0d7b0bc944965/node_modules/pi-mcp-adapter/tool-registrar.ts
|
|
49637
49172
|
import { mkdtempSync, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
49638
49173
|
import { tmpdir } from "os";
|
|
49639
|
-
import { join as
|
|
49174
|
+
import { join as join26 } from "path";
|
|
49640
49175
|
var MAX_BINARY_RESOURCE_BYTES = 10 * 1024 * 1024;
|
|
49641
49176
|
var MAX_SESSION_RESOURCE_BYTES = 100 * 1024 * 1024;
|
|
49642
49177
|
var MAX_SESSION_RESOURCE_FILES = 1e4;
|
|
@@ -49743,11 +49278,11 @@ function materializeBinaryResource(resource, scope) {
|
|
|
49743
49278
|
return omitBinaryResource(resource, "session resource limit reached");
|
|
49744
49279
|
}
|
|
49745
49280
|
try {
|
|
49746
|
-
session.directory ??= mkdtempSync(
|
|
49281
|
+
session.directory ??= mkdtempSync(join26(tmpdir(), "pi-mcp-resource-"));
|
|
49747
49282
|
} catch {
|
|
49748
49283
|
return omitBinaryResource(resource, "could not be saved");
|
|
49749
49284
|
}
|
|
49750
|
-
const filePath =
|
|
49285
|
+
const filePath = join26(session.directory, `resource-${++session.sequence}.bin`);
|
|
49751
49286
|
session.bytes += decodedBytes;
|
|
49752
49287
|
session.files += 1;
|
|
49753
49288
|
try {
|
|
@@ -49840,7 +49375,7 @@ function stringifyStructuredContent(value) {
|
|
|
49840
49375
|
import { randomBytes as randomBytes4 } from "crypto";
|
|
49841
49376
|
import { mkdtemp, rm as rm3, writeFile as writeFile10 } from "fs/promises";
|
|
49842
49377
|
import { tmpdir as tmpdir2 } from "os";
|
|
49843
|
-
import { dirname as dirname16, join as
|
|
49378
|
+
import { dirname as dirname16, join as join27 } from "path";
|
|
49844
49379
|
var DEFAULT_MCP_OUTPUT_MAX_BYTES = 50 * 1024;
|
|
49845
49380
|
var DEFAULT_MCP_OUTPUT_MAX_LINES = 2e3;
|
|
49846
49381
|
var DEFAULT_MCP_DETAILS_MAX_BYTES = 16 * 1024;
|
|
@@ -50148,8 +49683,8 @@ function serializedObjectEntryBytes(key, value, hasPrevious) {
|
|
|
50148
49683
|
}
|
|
50149
49684
|
async function saveArtifact(kind, text) {
|
|
50150
49685
|
try {
|
|
50151
|
-
const dir = await mkdtemp(
|
|
50152
|
-
const path7 =
|
|
49686
|
+
const dir = await mkdtemp(join27(tmpdir2(), "pi-mcp-output-"));
|
|
49687
|
+
const path7 = join27(dir, `${kind}-${randomBytes4(4).toString("hex")}.txt`);
|
|
50153
49688
|
await writeFile10(path7, text, { encoding: "utf8", mode: 384 });
|
|
50154
49689
|
return { path: path7 };
|
|
50155
49690
|
} catch (error) {
|
|
@@ -51796,7 +51331,7 @@ function sendText(res, status, text) {
|
|
|
51796
51331
|
// ../node_modules/.bun/pi-mcp-adapter@2.32.1+04b0d7b0bc944965/node_modules/pi-mcp-adapter/glimpse-ui.ts
|
|
51797
51332
|
import { existsSync as existsSync15 } from "fs";
|
|
51798
51333
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
51799
|
-
import { join as
|
|
51334
|
+
import { join as join28, dirname as dirname17 } from "path";
|
|
51800
51335
|
import { platform as platform2 } from "os";
|
|
51801
51336
|
import { createRequire as createRequire4 } from "module";
|
|
51802
51337
|
var glimpseAvailable = null;
|
|
@@ -51818,20 +51353,20 @@ function getGlimpseBinaryPath() {
|
|
|
51818
51353
|
try {
|
|
51819
51354
|
const require7 = createRequire4(import.meta.url);
|
|
51820
51355
|
const glimpseuiPath = require7.resolve("glimpseui");
|
|
51821
|
-
const binaryPath =
|
|
51356
|
+
const binaryPath = join28(dirname17(glimpseuiPath), "glimpse");
|
|
51822
51357
|
if (existsSync15(binaryPath)) return binaryPath;
|
|
51823
51358
|
} catch {
|
|
51824
51359
|
}
|
|
51825
51360
|
try {
|
|
51826
51361
|
const globalRoot = execFileSync2("npm", ["root", "-g"], { encoding: "utf-8" }).trim();
|
|
51827
|
-
const binaryPath =
|
|
51362
|
+
const binaryPath = join28(globalRoot, "glimpseui", "src", "glimpse");
|
|
51828
51363
|
if (existsSync15(binaryPath)) return binaryPath;
|
|
51829
51364
|
} catch {
|
|
51830
51365
|
}
|
|
51831
51366
|
return null;
|
|
51832
51367
|
}
|
|
51833
51368
|
async function openGlimpseWindow(html, options) {
|
|
51834
|
-
const modulePath = resolvedBinaryPath ?
|
|
51369
|
+
const modulePath = resolvedBinaryPath ? join28(dirname17(resolvedBinaryPath), "glimpse.mjs") : "glimpseui";
|
|
51835
51370
|
const glimpse = await import(modulePath);
|
|
51836
51371
|
let active = true;
|
|
51837
51372
|
const win = glimpse.open(html, {
|
|
@@ -59621,7 +59156,7 @@ var pi_mcp_adapter_default = createMcpAdapter();
|
|
|
59621
59156
|
// src/managers/pi-manager.ts
|
|
59622
59157
|
async function getManagedPiMcpServers() {
|
|
59623
59158
|
try {
|
|
59624
|
-
const parsed = JSON.parse(await
|
|
59159
|
+
const parsed = JSON.parse(await readFile18(PI_MCP_CONFIG_PATH, "utf8"));
|
|
59625
59160
|
if (!isRecord2(parsed) || !isRecord2(parsed.mcpServers)) return {};
|
|
59626
59161
|
return Object.fromEntries(Object.entries(parsed.mcpServers).filter(
|
|
59627
59162
|
(entry) => isRecord2(entry[1]) && (typeof entry[1].command === "string" || typeof entry[1].url === "string")
|
|
@@ -59743,7 +59278,7 @@ var PiManager = class extends CodingAgentManager {
|
|
|
59743
59278
|
modelRuntime = null;
|
|
59744
59279
|
constructor(options) {
|
|
59745
59280
|
super(options);
|
|
59746
|
-
this.historyFilePath = options.historyFilePath ??
|
|
59281
|
+
this.historyFilePath = options.historyFilePath ?? join29(PI_HISTORY_DIR, `${Date.now()}.jsonl`);
|
|
59747
59282
|
this.historyFile = new CodexHistoryFile(this.historyFilePath);
|
|
59748
59283
|
this.initializeManager(this.processMessageInternal.bind(this));
|
|
59749
59284
|
}
|
|
@@ -59879,7 +59414,7 @@ var PiManager = class extends CodingAgentManager {
|
|
|
59879
59414
|
}
|
|
59880
59415
|
const resourceLoader = new DefaultResourceLoader({
|
|
59881
59416
|
cwd: this.workingDirectory,
|
|
59882
|
-
agentDir:
|
|
59417
|
+
agentDir: join29(ENGINE_ENV.HOME_DIR, ".pi", "agent"),
|
|
59883
59418
|
extensionFactories,
|
|
59884
59419
|
appendSystemPrompt: [this.buildCombinedInstructions() ?? ""]
|
|
59885
59420
|
});
|
|
@@ -59977,11 +59512,6 @@ Match verification depth to the change: use focused checks for small changes and
|
|
|
59977
59512
|
|
|
59978
59513
|
// src/managers/relay-tools.ts
|
|
59979
59514
|
function extractFinalResponse(history, provider) {
|
|
59980
|
-
const turns = history.codexAspTranscript?.turns ?? [];
|
|
59981
|
-
for (let index = turns.length - 1; index >= 0; index--) {
|
|
59982
|
-
const response = getCodexAspTurnResponse(turns[index]);
|
|
59983
|
-
if (response?.text) return response.text;
|
|
59984
|
-
}
|
|
59985
59515
|
const message = parseAgentEvents(history.events ?? [], provider).findLast((candidate) => candidate.type === "agent");
|
|
59986
59516
|
return message?.type === "agent" && message.content ? message.content : null;
|
|
59987
59517
|
}
|
|
@@ -60001,13 +59531,13 @@ async function uploadAnalytics(endpoint, body) {
|
|
|
60001
59531
|
import {
|
|
60002
59532
|
appendFile as appendFile4,
|
|
60003
59533
|
mkdir as mkdir19,
|
|
60004
|
-
readFile as
|
|
60005
|
-
readdir as
|
|
60006
|
-
rename as
|
|
59534
|
+
readFile as readFile19,
|
|
59535
|
+
readdir as readdir7,
|
|
59536
|
+
rename as rename4,
|
|
60007
59537
|
unlink as unlink3
|
|
60008
59538
|
} from "fs/promises";
|
|
60009
59539
|
import { existsSync as existsSync16, readFileSync as readFileSync7, readdirSync as readdirSync2 } from "fs";
|
|
60010
|
-
import { join as
|
|
59540
|
+
import { join as join30 } from "path";
|
|
60011
59541
|
var MAX_FAILED_RECORDS = 500;
|
|
60012
59542
|
var FLUSH_DEBOUNCE_MS = 15e3;
|
|
60013
59543
|
var MAX_UPLOADED_SEGMENTS = 50;
|
|
@@ -60019,7 +59549,7 @@ var AnalyticsRecordBuffer = class {
|
|
|
60019
59549
|
options.storageName,
|
|
60020
59550
|
...options.legacyStorageNames ?? []
|
|
60021
59551
|
];
|
|
60022
|
-
this.liveFile =
|
|
59552
|
+
this.liveFile = join30(ENGINE_DIR2, `${options.storageName}.jsonl`);
|
|
60023
59553
|
this.segmentFilePatterns = this.storageNames.map(
|
|
60024
59554
|
(storageName) => new RegExp(`^${storageName}\\.(\\d+)\\.jsonl$`)
|
|
60025
59555
|
);
|
|
@@ -60057,7 +59587,7 @@ var AnalyticsRecordBuffer = class {
|
|
|
60057
59587
|
if (!existsSync16(ENGINE_DIR2)) return [];
|
|
60058
59588
|
return readdirSync2(ENGINE_DIR2, { withFileTypes: true }).filter((entry) => entry.isFile() && this.storageNames.some(
|
|
60059
59589
|
(storageName) => entry.name === `${storageName}.jsonl` || entry.name.startsWith(`${storageName}.`) && (entry.name.endsWith(".jsonl") || entry.name.endsWith(`.jsonl${UPLOADED_SUFFIX}`))
|
|
60060
|
-
)).map(({ name }) => name).sort().flatMap((name) => this.parseRecords(readFileSync7(
|
|
59590
|
+
)).map(({ name }) => name).sort().flatMap((name) => this.parseRecords(readFileSync7(join30(ENGINE_DIR2, name), "utf-8"))).map((record3) => {
|
|
60061
59591
|
const recordId = this.options.getRecordId?.(record3);
|
|
60062
59592
|
if (recordId) this.recordIds.add(recordId);
|
|
60063
59593
|
return record3;
|
|
@@ -60091,19 +59621,19 @@ var AnalyticsRecordBuffer = class {
|
|
|
60091
59621
|
await Promise.allSettled([...this.pendingAppends]);
|
|
60092
59622
|
}
|
|
60093
59623
|
for (const storageName of this.storageNames) {
|
|
60094
|
-
await
|
|
60095
|
-
|
|
60096
|
-
|
|
59624
|
+
await rename4(
|
|
59625
|
+
join30(ENGINE_DIR2, `${storageName}.jsonl`),
|
|
59626
|
+
join30(ENGINE_DIR2, `${storageName}.${Date.now()}.jsonl`)
|
|
60097
59627
|
).catch(() => {
|
|
60098
59628
|
});
|
|
60099
59629
|
}
|
|
60100
|
-
const entries = await
|
|
59630
|
+
const entries = await readdir7(ENGINE_DIR2).catch(() => []);
|
|
60101
59631
|
let flushed = 0;
|
|
60102
59632
|
let failed = 0;
|
|
60103
59633
|
for (const entry of entries) {
|
|
60104
59634
|
if (!this.segmentFilePatterns.some((pattern) => pattern.test(entry))) continue;
|
|
60105
59635
|
try {
|
|
60106
|
-
await this.uploadSegment(
|
|
59636
|
+
await this.uploadSegment(join30(ENGINE_DIR2, entry));
|
|
60107
59637
|
flushed++;
|
|
60108
59638
|
} catch (error) {
|
|
60109
59639
|
failed++;
|
|
@@ -60132,16 +59662,16 @@ var AnalyticsRecordBuffer = class {
|
|
|
60132
59662
|
(storageName) => entry.startsWith(`${storageName}.`)
|
|
60133
59663
|
) && entry.endsWith(UPLOADED_SUFFIX)).sort();
|
|
60134
59664
|
for (const entry of uploaded.slice(0, -MAX_UPLOADED_SEGMENTS)) {
|
|
60135
|
-
await unlink3(
|
|
59665
|
+
await unlink3(join30(ENGINE_DIR2, entry)).catch(() => {
|
|
60136
59666
|
});
|
|
60137
59667
|
}
|
|
60138
59668
|
}
|
|
60139
59669
|
return { flushed, failed };
|
|
60140
59670
|
}
|
|
60141
59671
|
async uploadSegment(filePath) {
|
|
60142
|
-
const records = this.parseRecords(await
|
|
59672
|
+
const records = this.parseRecords(await readFile19(filePath, "utf-8"));
|
|
60143
59673
|
if (records.length > 0) await this.options.upload(records);
|
|
60144
|
-
await
|
|
59674
|
+
await rename4(filePath, `${filePath}${UPLOADED_SUFFIX}`).catch(() => {
|
|
60145
59675
|
});
|
|
60146
59676
|
}
|
|
60147
59677
|
parseRecords(contents) {
|
|
@@ -60981,9 +60511,9 @@ var KeepAliveService = class _KeepAliveService {
|
|
|
60981
60511
|
var keepAliveService = new KeepAliveService();
|
|
60982
60512
|
|
|
60983
60513
|
// src/services/canvas-service.ts
|
|
60984
|
-
import { readdir as
|
|
60514
|
+
import { readdir as readdir8, readFile as readFile21, stat as stat4 } from "fs/promises";
|
|
60985
60515
|
import { homedir as homedir13 } from "os";
|
|
60986
|
-
import { join as
|
|
60516
|
+
import { join as join31 } from "path";
|
|
60987
60517
|
|
|
60988
60518
|
// src/utils/contained-file.ts
|
|
60989
60519
|
import { realpath, stat as stat3 } from "fs/promises";
|
|
@@ -61009,9 +60539,9 @@ function fileRevision(content) {
|
|
|
61009
60539
|
}
|
|
61010
60540
|
|
|
61011
60541
|
// src/utils/revisioned-text-file.ts
|
|
61012
|
-
import { readFile as
|
|
60542
|
+
import { readFile as readFile20 } from "fs/promises";
|
|
61013
60543
|
async function writeRevisionedTextFile(filePath, content, expectedRevision) {
|
|
61014
|
-
const current = await
|
|
60544
|
+
const current = await readFile20(filePath, "utf8");
|
|
61015
60545
|
const revision = fileRevision(current);
|
|
61016
60546
|
if (revision !== expectedRevision) {
|
|
61017
60547
|
return {
|
|
@@ -61025,15 +60555,15 @@ async function writeRevisionedTextFile(filePath, content, expectedRevision) {
|
|
|
61025
60555
|
|
|
61026
60556
|
// src/services/canvas-service.ts
|
|
61027
60557
|
var GLOBAL_CANVAS_DIRECTORIES = [
|
|
61028
|
-
|
|
61029
|
-
|
|
61030
|
-
|
|
60558
|
+
join31(homedir13(), ".claude", "plans"),
|
|
60559
|
+
join31(process.env.XDG_DATA_HOME ?? join31(homedir13(), ".local", "share"), "opencode", "plans"),
|
|
60560
|
+
join31(homedir13(), ".replicas", "canvas")
|
|
61031
60561
|
];
|
|
61032
60562
|
async function canvasDirectories() {
|
|
61033
60563
|
const repositories = await gitService.listRepositories().catch(() => []);
|
|
61034
60564
|
return [
|
|
61035
60565
|
...GLOBAL_CANVAS_DIRECTORIES,
|
|
61036
|
-
...repositories.map((repository) =>
|
|
60566
|
+
...repositories.map((repository) => join31(repository.path, ".opencode", "plans"))
|
|
61037
60567
|
];
|
|
61038
60568
|
}
|
|
61039
60569
|
var CanvasService = class {
|
|
@@ -61051,14 +60581,14 @@ var CanvasService = class {
|
|
|
61051
60581
|
if (!current) continue;
|
|
61052
60582
|
let entries;
|
|
61053
60583
|
try {
|
|
61054
|
-
entries = await
|
|
60584
|
+
entries = await readdir8(current.directory, { withFileTypes: true });
|
|
61055
60585
|
} catch {
|
|
61056
60586
|
continue;
|
|
61057
60587
|
}
|
|
61058
60588
|
for (const entry of entries) {
|
|
61059
60589
|
if (entry.name.startsWith(".")) continue;
|
|
61060
60590
|
const filename = current.relativePath ? `${current.relativePath}/${entry.name}` : entry.name;
|
|
61061
|
-
const filePath =
|
|
60591
|
+
const filePath = join31(current.directory, entry.name);
|
|
61062
60592
|
if (entry.isDirectory()) {
|
|
61063
60593
|
pending.push({ directory: filePath, relativePath: filename });
|
|
61064
60594
|
continue;
|
|
@@ -61083,7 +60613,7 @@ var CanvasService = class {
|
|
|
61083
60613
|
if (!safe) return null;
|
|
61084
60614
|
const { kind, mimeType } = classifyCanvasFilename(safe);
|
|
61085
60615
|
for (const directory of await this.directories()) {
|
|
61086
|
-
const filePath =
|
|
60616
|
+
const filePath = join31(directory, safe);
|
|
61087
60617
|
let sizeBytes = 0;
|
|
61088
60618
|
let updatedAt = "";
|
|
61089
60619
|
try {
|
|
@@ -61104,7 +60634,7 @@ var CanvasService = class {
|
|
|
61104
60634
|
};
|
|
61105
60635
|
}
|
|
61106
60636
|
try {
|
|
61107
|
-
const bytes = await
|
|
60637
|
+
const bytes = await readFile21(filePath);
|
|
61108
60638
|
return { filename: safe, kind, sizeBytes, mimeType, updatedAt, bytes };
|
|
61109
60639
|
} catch {
|
|
61110
60640
|
continue;
|
|
@@ -61264,16 +60794,16 @@ async function reconcileCanvasItems(filenames) {
|
|
|
61264
60794
|
}
|
|
61265
60795
|
|
|
61266
60796
|
// src/services/upload-chat-transcripts.ts
|
|
61267
|
-
import { createReadStream } from "fs";
|
|
60797
|
+
import { createReadStream as createReadStream2 } from "fs";
|
|
61268
60798
|
import { createHash as createHash8 } from "crypto";
|
|
61269
|
-
import { readFile as
|
|
61270
|
-
import { basename as basename4, join as
|
|
60799
|
+
import { readFile as readFile22, readdir as readdir9, stat as stat5 } from "fs/promises";
|
|
60800
|
+
import { basename as basename4, join as join33 } from "path";
|
|
61271
60801
|
|
|
61272
60802
|
// src/services/chat/chat-senders.ts
|
|
61273
|
-
import { join as
|
|
61274
|
-
var CHAT_SENDERS_DIR =
|
|
60803
|
+
import { join as join32 } from "path";
|
|
60804
|
+
var CHAT_SENDERS_DIR = join32(ENGINE_DIR2, "chat-senders");
|
|
61275
60805
|
function chatMessageSendersFilePath(chatId) {
|
|
61276
|
-
return
|
|
60806
|
+
return join32(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
|
|
61277
60807
|
}
|
|
61278
60808
|
function parseChatMessageSendersJsonl(content) {
|
|
61279
60809
|
return content.split("\n").flatMap((line) => {
|
|
@@ -61306,7 +60836,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map(), ca
|
|
|
61306
60836
|
for (const dir of HISTORY_DIRS) {
|
|
61307
60837
|
let entries;
|
|
61308
60838
|
try {
|
|
61309
|
-
entries = await
|
|
60839
|
+
entries = await readdir9(dir);
|
|
61310
60840
|
} catch {
|
|
61311
60841
|
continue;
|
|
61312
60842
|
}
|
|
@@ -61316,7 +60846,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map(), ca
|
|
|
61316
60846
|
const chat = chatsById.get(chatId);
|
|
61317
60847
|
if (!shouldFlushChatTranscript(dir, chat, chatsById)) continue;
|
|
61318
60848
|
tasks.push(
|
|
61319
|
-
uploadChatTranscript(chatId,
|
|
60849
|
+
uploadChatTranscript(chatId, join33(dir, entry), chat, capture).then((artifact) => {
|
|
61320
60850
|
flushed++;
|
|
61321
60851
|
if (artifact && capture) revisions.push(artifact);
|
|
61322
60852
|
}).catch((err) => {
|
|
@@ -61332,7 +60862,6 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map(), ca
|
|
|
61332
60862
|
async function uploadChatTranscript(chatId, filePath, chat, capture) {
|
|
61333
60863
|
const { size } = await stat5(filePath);
|
|
61334
60864
|
if (size === 0) return null;
|
|
61335
|
-
const historyPages = createChatTranscriptPages(await readFile23(filePath));
|
|
61336
60865
|
const metadata = chat ? {
|
|
61337
60866
|
provider: chat.provider,
|
|
61338
60867
|
...chat.relayBaseProvider ? { relayBaseProvider: chat.relayBaseProvider } : {},
|
|
@@ -61346,21 +60875,23 @@ async function uploadChatTranscript(chatId, filePath, chat, capture) {
|
|
|
61346
60875
|
} : {};
|
|
61347
60876
|
if (capture) {
|
|
61348
60877
|
const hash = createHash8("sha256");
|
|
61349
|
-
for await (const chunk of
|
|
60878
|
+
for await (const chunk of createReadStream2(filePath)) hash.update(chunk);
|
|
61350
60879
|
metadata.captureId = capture.captureId;
|
|
61351
60880
|
metadata.captureReason = capture.reason;
|
|
61352
60881
|
metadata.sha256 = hash.digest("hex");
|
|
61353
60882
|
}
|
|
61354
60883
|
try {
|
|
61355
60884
|
metadata.senders = parseChatMessageSendersJsonl(
|
|
61356
|
-
await
|
|
60885
|
+
await readFile22(chatMessageSendersFilePath(chatId), "utf-8")
|
|
61357
60886
|
);
|
|
61358
60887
|
} catch (error) {
|
|
61359
60888
|
if (!(error && typeof error === "object" && "code" in error && error.code === "ENOENT")) throw error;
|
|
61360
60889
|
}
|
|
61361
|
-
|
|
61362
|
-
|
|
61363
|
-
|
|
60890
|
+
metadata.historyIndex = {
|
|
60891
|
+
version: 2,
|
|
60892
|
+
sourceSize: size,
|
|
60893
|
+
...chat?.removedMessageIds?.length ? { removedMessageIds: chat.removedMessageIds } : {}
|
|
60894
|
+
};
|
|
61364
60895
|
const uploadRequest = { chatId, size, metadata };
|
|
61365
60896
|
const prepareResponse = await monolithRequest("/v1/engine/chat-transcripts/upload-url", {
|
|
61366
60897
|
body: uploadRequest
|
|
@@ -61369,25 +60900,11 @@ async function uploadChatTranscript(chatId, filePath, chat, capture) {
|
|
|
61369
60900
|
throw new Error(`prepare failed: ${prepareResponse.status} ${await prepareResponse.text()}`);
|
|
61370
60901
|
}
|
|
61371
60902
|
const prepareBody = await prepareResponse.json();
|
|
61372
|
-
if (!isRecord(prepareBody) || typeof prepareBody.uploadUrl !== "string" && prepareBody.uploadUrl !== null
|
|
60903
|
+
if (!isRecord(prepareBody) || typeof prepareBody.uploadUrl !== "string" && prepareBody.uploadUrl !== null) {
|
|
61373
60904
|
throw new Error("prepare failed: invalid response");
|
|
61374
60905
|
}
|
|
61375
60906
|
if (prepareBody.uploadUrl === null) return null;
|
|
61376
|
-
|
|
61377
|
-
const historyPagesSize = getChatTranscriptHistorySize(historyPages.index);
|
|
61378
|
-
if (historyPagesSize > 0) {
|
|
61379
|
-
if (typeof prepareBody.historyPagesUploadUrl !== "string") {
|
|
61380
|
-
throw new Error("prepare failed: missing history pages upload URL");
|
|
61381
|
-
}
|
|
61382
|
-
uploads.push(fetch(prepareBody.historyPagesUploadUrl, {
|
|
61383
|
-
method: "PUT",
|
|
61384
|
-
headers: { "content-type": "application/x-ndjson" },
|
|
61385
|
-
body: new Uint8Array(historyPages.bytes).buffer
|
|
61386
|
-
}).then((response) => {
|
|
61387
|
-
if (!response.ok) throw new Error(`history pages upload failed: ${response.status}`);
|
|
61388
|
-
}));
|
|
61389
|
-
}
|
|
61390
|
-
await Promise.all(uploads);
|
|
60907
|
+
await putPresignedFile(prepareBody.uploadUrl, filePath, size, "application/x-ndjson");
|
|
61391
60908
|
const finalizeResponse = await monolithRequest("/v1/engine/chat-transcripts/finalize", {
|
|
61392
60909
|
body: uploadRequest
|
|
61393
60910
|
});
|
|
@@ -61403,9 +60920,9 @@ async function uploadChatTranscript(chatId, filePath, chat, capture) {
|
|
|
61403
60920
|
}
|
|
61404
60921
|
|
|
61405
60922
|
// src/services/upload-engine-logs.ts
|
|
61406
|
-
import { createReadStream as
|
|
61407
|
-
import { readdir as
|
|
61408
|
-
import { join as
|
|
60923
|
+
import { createReadStream as createReadStream3 } from "fs";
|
|
60924
|
+
import { readdir as readdir10, stat as stat6 } from "fs/promises";
|
|
60925
|
+
import { join as join34 } from "path";
|
|
61409
60926
|
var MAX_ENGINE_LOG_FLUSH_SESSIONS = 10;
|
|
61410
60927
|
var MAX_ENGINE_LOG_FLUSH_BYTES = 5 * 1024 * 1024;
|
|
61411
60928
|
var ENGINE_LOG_FLUSH_TIMEOUT_MS = 2e4;
|
|
@@ -61415,7 +60932,7 @@ async function flushAllEngineLogs() {
|
|
|
61415
60932
|
let failed = 0;
|
|
61416
60933
|
const deadline = Date.now() + ENGINE_LOG_FLUSH_TIMEOUT_MS;
|
|
61417
60934
|
await runBeforeDeadline((signal) => engineLogger.flush(signal), deadline);
|
|
61418
|
-
const files = await runBeforeDeadline(() =>
|
|
60935
|
+
const files = await runBeforeDeadline(() => readdir10(LOG_DIR), deadline).catch(() => []);
|
|
61419
60936
|
const currentFilename = engineLogger.sessionId ? `${engineLogger.sessionId}.log` : null;
|
|
61420
60937
|
const filenames = files.filter((filename) => {
|
|
61421
60938
|
if (!filename.endsWith(".log")) return false;
|
|
@@ -61434,7 +60951,7 @@ async function flushAllEngineLogs() {
|
|
|
61434
60951
|
const candidates = (await Promise.all(filenames.slice(0, MAX_ENGINE_LOG_FLUSH_SESSIONS).map(async (filename) => {
|
|
61435
60952
|
try {
|
|
61436
60953
|
const sessionId = filename.slice(0, -".log".length);
|
|
61437
|
-
const filePath =
|
|
60954
|
+
const filePath = join34(LOG_DIR, filename);
|
|
61438
60955
|
const fileStat = await runBeforeDeadline(() => stat6(filePath), deadline);
|
|
61439
60956
|
if (!fileStat.isFile()) {
|
|
61440
60957
|
skipped++;
|
|
@@ -61467,7 +60984,7 @@ async function flushAllEngineLogs() {
|
|
|
61467
60984
|
const content = await runBeforeDeadline(async (signal) => {
|
|
61468
60985
|
if (candidate.length === 0) return Buffer.alloc(0);
|
|
61469
60986
|
const chunks = [];
|
|
61470
|
-
for await (const chunk of
|
|
60987
|
+
for await (const chunk of createReadStream3(candidate.filePath, {
|
|
61471
60988
|
start: candidate.offset,
|
|
61472
60989
|
end: candidate.offset + candidate.length - 1,
|
|
61473
60990
|
signal
|
|
@@ -61531,7 +61048,7 @@ async function uploadEngineLog(input, timeoutMs) {
|
|
|
61531
61048
|
|
|
61532
61049
|
// src/services/chat/fork-handoff.ts
|
|
61533
61050
|
import { mkdir as mkdir20, open as open3, writeFile as writeFile11 } from "fs/promises";
|
|
61534
|
-
import { join as
|
|
61051
|
+
import { join as join35 } from "path";
|
|
61535
61052
|
var EXCERPT_MAX_CHARS = 24e3;
|
|
61536
61053
|
var MAX_SANITIZED_SOURCE_BYTES = 32 * 1024 * 1024;
|
|
61537
61054
|
function unansweredRequest(blocks) {
|
|
@@ -61566,7 +61083,7 @@ function tailBlocks(blocks, maxChars) {
|
|
|
61566
61083
|
return { excerpt, truncated: start > 0 };
|
|
61567
61084
|
}
|
|
61568
61085
|
async function buildForkHandoff(input) {
|
|
61569
|
-
const rawHistoryPath =
|
|
61086
|
+
const rawHistoryPath = join35(HISTORY_DIR_BY_PROVIDER[input.sourceProvider], `${input.sourceChatId}.jsonl`);
|
|
61570
61087
|
const { content, truncated: sourceTruncated } = await readHistoryTail(rawHistoryPath, MAX_SANITIZED_SOURCE_BYTES);
|
|
61571
61088
|
let blocks = canonicalizeChatTranscriptBlocks(content, input.executionProvider, input.senders);
|
|
61572
61089
|
if (input.turnLimit !== void 0) {
|
|
@@ -61574,9 +61091,9 @@ async function buildForkHandoff(input) {
|
|
|
61574
61091
|
const start = blocks.findLastIndex((block) => block.startsWith("## User") && ++turns === input.turnLimit);
|
|
61575
61092
|
blocks = blocks.slice(Math.max(0, start));
|
|
61576
61093
|
}
|
|
61577
|
-
const forkDir =
|
|
61094
|
+
const forkDir = join35(FORKS_DIR, input.targetChatId);
|
|
61578
61095
|
await mkdir20(forkDir, { recursive: true });
|
|
61579
|
-
const transcriptPath =
|
|
61096
|
+
const transcriptPath = join35(forkDir, "source-transcript.md");
|
|
61580
61097
|
const header = sourceTruncated ? `_This file was generated from only the most recent ${MAX_SANITIZED_SOURCE_BYTES / 1024 / 1024} MB of the source chat.${input.turnLimit === void 0 ? ` The complete raw event log is at ${rawHistoryPath}; grep it for anything earlier.` : ""}_
|
|
61581
61098
|
|
|
61582
61099
|
` : "";
|
|
@@ -61624,25 +61141,7 @@ function isSameAcceptedUserEvent(event, acceptedEvent) {
|
|
|
61624
61141
|
{ content: acceptedMessage, timestamp: acceptedEvent.timestamp }
|
|
61625
61142
|
);
|
|
61626
61143
|
}
|
|
61627
|
-
function
|
|
61628
|
-
if (!transcript) return [];
|
|
61629
|
-
const messages = [];
|
|
61630
|
-
for (const turn of transcript.turns) {
|
|
61631
|
-
for (const item of turn.items) {
|
|
61632
|
-
if (item.type === "userMessage" && item.content.trim()) {
|
|
61633
|
-
messages.push(item.content);
|
|
61634
|
-
}
|
|
61635
|
-
}
|
|
61636
|
-
}
|
|
61637
|
-
return messages;
|
|
61638
|
-
}
|
|
61639
|
-
function getCodexTranscriptFromEvent(event) {
|
|
61640
|
-
if (event.type !== CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE) return null;
|
|
61641
|
-
if (isCodexAspTranscript(event.payload.transcript)) return event.payload.transcript;
|
|
61642
|
-
if (!isCodexAspTranscriptDelta(event.payload.transcriptDelta)) return null;
|
|
61643
|
-
return applyCodexAspTranscriptDelta(null, event.payload.transcriptDelta);
|
|
61644
|
-
}
|
|
61645
|
-
function terminalErrorsFromEvent(event, provider, codexTranscript) {
|
|
61144
|
+
function terminalErrorsFromEvent(event, provider) {
|
|
61646
61145
|
if (event.type === "claude-result") {
|
|
61647
61146
|
const payload = coerceClaudeResultPayload(event.payload);
|
|
61648
61147
|
if (!isClaudeResultError(payload)) return null;
|
|
@@ -61655,21 +61154,15 @@ function terminalErrorsFromEvent(event, provider, codexTranscript) {
|
|
|
61655
61154
|
if (event.type === "codex-asp-error") {
|
|
61656
61155
|
return [typeof event.payload.message === "string" ? event.payload.message : "Codex run failed"];
|
|
61657
61156
|
}
|
|
61658
|
-
const
|
|
61659
|
-
if (
|
|
61660
|
-
|
|
61661
|
-
return errors2.length > 0 ? errors2 : ["Codex run failed"];
|
|
61157
|
+
const codexTurn = codexTurnFromEvent(event);
|
|
61158
|
+
if (codexTurn) {
|
|
61159
|
+
return normalizeCodexAspTranscriptStatus(codexTurn.status) === "failed" ? [codexTurn.error ?? "Codex run failed"] : void 0;
|
|
61662
61160
|
}
|
|
61663
61161
|
const mayContainProviderError = provider === "cursor" && event.type === "cursor-error" || provider === "opencode" && (event.type === "opencode-error" || event.type === "opencode-message.updated") || provider === "pi" && (event.type === "pi-error" || event.type === "pi-message_end");
|
|
61664
61162
|
if (!mayContainProviderError) return void 0;
|
|
61665
61163
|
const errors = parseAgentEvents([event], provider).flatMap((message) => message.type === "error" ? [message.message] : []);
|
|
61666
61164
|
return errors.length > 0 ? errors : void 0;
|
|
61667
61165
|
}
|
|
61668
|
-
function acceptedEventInCodexTranscript(acceptedEvent, transcript) {
|
|
61669
|
-
const message = getUserMessage(acceptedEvent);
|
|
61670
|
-
if (!message) return false;
|
|
61671
|
-
return getCodexTranscriptUserMessages(transcript).includes(message);
|
|
61672
|
-
}
|
|
61673
61166
|
var LAST_MESSAGE_PREVIEW_MAX = 200;
|
|
61674
61167
|
var MAX_ACCEPTED_SEND_RESPONSES = 50;
|
|
61675
61168
|
var MAX_REMOVED_MESSAGE_IDS = 6e3;
|
|
@@ -62060,9 +61553,13 @@ var ChatService = class {
|
|
|
62060
61553
|
event: acceptedEvent,
|
|
62061
61554
|
...recordedSender ? { sender: recordedSender } : {}
|
|
62062
61555
|
}
|
|
61556
|
+
}).catch((error) => {
|
|
61557
|
+
console.error("[ChatService] Failed to publish accepted turn:", { chatId, messageId: result.messageId, error });
|
|
62063
61558
|
});
|
|
62064
61559
|
if (chat.persisted.model !== previousModel) {
|
|
62065
|
-
await this.publish({ type: "chat.updated", payload: { chat: this.toSummary(chat) } })
|
|
61560
|
+
await this.publish({ type: "chat.updated", payload: { chat: this.toSummary(chat) } }).catch((error) => {
|
|
61561
|
+
console.error("[ChatService] Failed to publish accepted chat update:", { chatId, error });
|
|
61562
|
+
});
|
|
62066
61563
|
}
|
|
62067
61564
|
}
|
|
62068
61565
|
async appendSender(chatId, sender) {
|
|
@@ -62073,7 +61570,7 @@ var ChatService = class {
|
|
|
62073
61570
|
}
|
|
62074
61571
|
}
|
|
62075
61572
|
async readSenders(chatId) {
|
|
62076
|
-
return
|
|
61573
|
+
return readFile23(chatMessageSendersFilePath(chatId), "utf-8").then(parseChatMessageSendersJsonl).catch((error) => {
|
|
62077
61574
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") return [];
|
|
62078
61575
|
console.error("[ChatService] Failed to read sender records:", error);
|
|
62079
61576
|
return [];
|
|
@@ -62326,17 +61823,24 @@ var ChatService = class {
|
|
|
62326
61823
|
return descendants;
|
|
62327
61824
|
}
|
|
62328
61825
|
async deleteHistoryFile(persisted) {
|
|
62329
|
-
const historyPath =
|
|
61826
|
+
const historyPath = join36(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`);
|
|
62330
61827
|
await Promise.all([
|
|
62331
61828
|
historyPath,
|
|
62332
61829
|
`${historyPath}.pages.jsonl`,
|
|
62333
61830
|
`${historyPath}.pages.index.json`
|
|
62334
61831
|
].map((path7) => rm4(path7, { force: true })));
|
|
62335
61832
|
await rm4(chatMessageSendersFilePath(persisted.id), { force: true });
|
|
62336
|
-
await rm4(
|
|
61833
|
+
await rm4(join36(FORKS_DIR, persisted.id), { recursive: true, force: true });
|
|
62337
61834
|
}
|
|
62338
61835
|
/** Resolves once the target chat exists; the handoff and its first turn run in the background. */
|
|
62339
61836
|
async forkChat(sourceChatId, request, trigger = "manual", reason) {
|
|
61837
|
+
const target = await this.createForkTarget(sourceChatId, request, trigger, reason);
|
|
61838
|
+
this.runFork(target.id, request).catch((error) => {
|
|
61839
|
+
console.error("[ChatService] Fork failed:", { sourceChatId, targetChatId: target.id, error });
|
|
61840
|
+
});
|
|
61841
|
+
return target;
|
|
61842
|
+
}
|
|
61843
|
+
async createForkTarget(sourceChatId, request, trigger, reason) {
|
|
62340
61844
|
const source = this.requireChat(sourceChatId);
|
|
62341
61845
|
const relayBaseProvider = await resolveRelayBaseProvider(request.provider, request.relayBaseProvider);
|
|
62342
61846
|
const executionProvider = request.provider === "relay" ? relayBaseProvider : request.provider;
|
|
@@ -62350,7 +61854,7 @@ var ChatService = class {
|
|
|
62350
61854
|
state: "preparing",
|
|
62351
61855
|
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
62352
61856
|
};
|
|
62353
|
-
|
|
61857
|
+
return this.createChat({
|
|
62354
61858
|
id: request.id,
|
|
62355
61859
|
provider: request.provider,
|
|
62356
61860
|
...relayBaseProvider ? { relayBaseProvider } : {},
|
|
@@ -62358,10 +61862,6 @@ var ChatService = class {
|
|
|
62358
61862
|
clientRequestId: request.clientRequestId,
|
|
62359
61863
|
fork
|
|
62360
61864
|
});
|
|
62361
|
-
this.runFork(target.id, request).catch((error) => {
|
|
62362
|
-
console.error("[ChatService] Fork failed:", { sourceChatId, targetChatId: target.id, error });
|
|
62363
|
-
});
|
|
62364
|
-
return target;
|
|
62365
61865
|
}
|
|
62366
61866
|
async createForkHandoffMessage(targetChatId, options) {
|
|
62367
61867
|
const source = this.requireChat(options.source.chatId);
|
|
@@ -62376,10 +61876,10 @@ var ChatService = class {
|
|
|
62376
61876
|
});
|
|
62377
61877
|
return formatChatForkHandoffMessage({ ...handoff, ...options });
|
|
62378
61878
|
}
|
|
62379
|
-
async runFork(targetId, request) {
|
|
61879
|
+
async runFork(targetId, request, errorNotificationTarget) {
|
|
62380
61880
|
const target = this.chats.get(targetId);
|
|
62381
61881
|
const fork = target?.persisted.fork;
|
|
62382
|
-
if (!target || !fork) return;
|
|
61882
|
+
if (!target || !fork) return false;
|
|
62383
61883
|
try {
|
|
62384
61884
|
if (!isAgentAvailable(getChatExecutionProvider(target.persisted))) throw new ChatProviderUnavailableError(request.provider);
|
|
62385
61885
|
const message = await this.createForkHandoffMessage(targetId, {
|
|
@@ -62388,7 +61888,7 @@ var ChatService = class {
|
|
|
62388
61888
|
reason: fork.reason,
|
|
62389
61889
|
message: request.message
|
|
62390
61890
|
});
|
|
62391
|
-
if (target.persisted.deletedAt) return;
|
|
61891
|
+
if (target.persisted.deletedAt) return false;
|
|
62392
61892
|
await this.sendMessage(targetId, {
|
|
62393
61893
|
message,
|
|
62394
61894
|
model: request.model,
|
|
@@ -62398,15 +61898,19 @@ var ChatService = class {
|
|
|
62398
61898
|
senderEmail: request.senderEmail,
|
|
62399
61899
|
senderDisplayName: request.senderDisplayName,
|
|
62400
61900
|
senderAvatarUrl: request.senderAvatarUrl,
|
|
61901
|
+
errorNotificationTarget,
|
|
62401
61902
|
idempotencyKey: `chat-fork:${targetId}`
|
|
62402
61903
|
});
|
|
62403
|
-
await this.updateFork(target, { state: "ready", completedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
62404
61904
|
} catch (error) {
|
|
62405
|
-
if (target.persisted.deletedAt) return;
|
|
61905
|
+
if (target.persisted.deletedAt) return false;
|
|
62406
61906
|
const message = error instanceof Error ? error.message : String(error);
|
|
62407
61907
|
await this.updateFork(target, { state: "failed", error: message.slice(0, 500), completedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
62408
61908
|
throw error;
|
|
62409
61909
|
}
|
|
61910
|
+
await this.updateFork(target, { state: "ready", completedAt: (/* @__PURE__ */ new Date()).toISOString() }).catch((error) => {
|
|
61911
|
+
console.error("[ChatService] Failed to finalize accepted fork:", { targetId, error });
|
|
61912
|
+
});
|
|
61913
|
+
return true;
|
|
62410
61914
|
}
|
|
62411
61915
|
async updateFork(chat, patch) {
|
|
62412
61916
|
if (!chat.persisted.fork) return;
|
|
@@ -62430,11 +61934,11 @@ var ChatService = class {
|
|
|
62430
61934
|
}
|
|
62431
61935
|
async autoForkAfterQuota(chat, exhaustion) {
|
|
62432
61936
|
const target = exhaustion.forkTo;
|
|
62433
|
-
if (!target || chat.persisted.deletedAt) return;
|
|
61937
|
+
if (!target || chat.persisted.deletedAt) return false;
|
|
62434
61938
|
const alreadyForked = [...this.chats.values()].some((other) => other.persisted.fork?.trigger === "auto" && other.persisted.fork.source.chatId === chat.persisted.id && !other.persisted.deletedAt);
|
|
62435
|
-
if (alreadyForked) return;
|
|
61939
|
+
if (alreadyForked) return false;
|
|
62436
61940
|
const last = chat.lastSendRequest;
|
|
62437
|
-
|
|
61941
|
+
const request = {
|
|
62438
61942
|
provider: target.provider,
|
|
62439
61943
|
relayBaseProvider: target.relayBaseProvider,
|
|
62440
61944
|
model: target.model,
|
|
@@ -62444,7 +61948,13 @@ var ChatService = class {
|
|
|
62444
61948
|
senderEmail: last?.senderEmail,
|
|
62445
61949
|
senderDisplayName: last?.senderDisplayName,
|
|
62446
61950
|
senderAvatarUrl: last?.senderAvatarUrl
|
|
62447
|
-
}
|
|
61951
|
+
};
|
|
61952
|
+
const fallback = await this.createForkTarget(chat.persisted.id, request, "auto", exhaustion.reason);
|
|
61953
|
+
const accepted = await this.runFork(fallback.id, request, chat.activeErrorNotificationTarget ?? void 0);
|
|
61954
|
+
if (!accepted) return false;
|
|
61955
|
+
chat.lastTurnErrors = null;
|
|
61956
|
+
chat.activeErrorNotificationTarget = null;
|
|
61957
|
+
return true;
|
|
62448
61958
|
}
|
|
62449
61959
|
async getChatHistory(chatId, page2 = {}) {
|
|
62450
61960
|
const chat = this.requireChat(chatId);
|
|
@@ -62458,13 +61968,13 @@ var ChatService = class {
|
|
|
62458
61968
|
chat.persisted.removedMessageIds
|
|
62459
61969
|
);
|
|
62460
61970
|
for (const [messageId, acceptedEvent] of chat.acceptedUserEvents) {
|
|
62461
|
-
if (
|
|
61971
|
+
if (historyEvents.some((event) => isSameAcceptedUserEvent(event, acceptedEvent))) {
|
|
62462
61972
|
chat.acceptedUserEvents.delete(messageId);
|
|
62463
61973
|
}
|
|
62464
61974
|
}
|
|
62465
61975
|
const isLatestPage = isLatestChatHistoryPage(page2);
|
|
62466
61976
|
const queuedMessageIds = new Set(chat.provider.getQueue().map((message) => message.id));
|
|
62467
|
-
const acceptedEvents = (isLatestPage ? [...chat.acceptedUserEvents.entries()] : []).filter(([messageId]) => messageId === chat.activeMessageId || !chat.hasActiveTurn && chat.pendingMessageIds[0] === messageId && !queuedMessageIds.has(messageId)).map(([, acceptedEvent]) => acceptedEvent).filter((acceptedEvent) => !
|
|
61977
|
+
const acceptedEvents = (isLatestPage ? [...chat.acceptedUserEvents.entries()] : []).filter(([messageId]) => messageId === chat.activeMessageId || !chat.hasActiveTurn && chat.pendingMessageIds[0] === messageId && !queuedMessageIds.has(messageId)).map(([, acceptedEvent]) => acceptedEvent).filter((acceptedEvent) => !historyEvents.some((event) => isSameAcceptedUserEvent(event, acceptedEvent)));
|
|
62468
61978
|
const events = excludeQueuedAcceptedEvents(
|
|
62469
61979
|
[...historyEvents, ...acceptedEvents].sort((a, b) => getEventTimestampMs(a) - getEventTimestampMs(b)),
|
|
62470
61980
|
[],
|
|
@@ -62498,7 +62008,6 @@ var ChatService = class {
|
|
|
62498
62008
|
thread_id: history.thread_id,
|
|
62499
62009
|
events,
|
|
62500
62010
|
removedMessageIds: chat.persisted.removedMessageIds,
|
|
62501
|
-
codexAspTranscript: history.codexAspTranscript ?? null,
|
|
62502
62011
|
goal: history.goal ?? chat.provider.getGoal?.() ?? null,
|
|
62503
62012
|
senders
|
|
62504
62013
|
}, page2);
|
|
@@ -62512,14 +62021,17 @@ var ChatService = class {
|
|
|
62512
62021
|
}
|
|
62513
62022
|
return count;
|
|
62514
62023
|
}
|
|
62024
|
+
toTranscriptSource(chat) {
|
|
62025
|
+
return { ...this.toSummary(chat), removedMessageIds: chat.persisted.removedMessageIds };
|
|
62026
|
+
}
|
|
62515
62027
|
async flushAllChatTranscripts() {
|
|
62516
62028
|
return flushAllChatTranscripts(new Map(
|
|
62517
|
-
[...this.chats.entries()].map(([chatId, chat]) => [chatId, this.
|
|
62029
|
+
[...this.chats.entries()].map(([chatId, chat]) => [chatId, this.toTranscriptSource(chat)])
|
|
62518
62030
|
));
|
|
62519
62031
|
}
|
|
62520
62032
|
async flushAllWorkspaceArtifacts(capture) {
|
|
62521
62033
|
const chatsById = new Map(
|
|
62522
|
-
[...this.chats.entries()].map(([chatId, chat]) => [chatId, this.
|
|
62034
|
+
[...this.chats.entries()].map(([chatId, chat]) => [chatId, this.toTranscriptSource(chat)])
|
|
62523
62035
|
);
|
|
62524
62036
|
const [chatTranscripts, canvas, repoState, engineLogs, [chatActivity]] = await Promise.all([
|
|
62525
62037
|
flushAllChatTranscripts(chatsById, capture),
|
|
@@ -62581,7 +62093,7 @@ var ChatService = class {
|
|
|
62581
62093
|
}
|
|
62582
62094
|
const baseProvider = getChatExecutionProvider(persisted);
|
|
62583
62095
|
const additionalInstructions = persisted.provider === "relay" ? buildRelayInstructions(this.workingDirectory) : void 0;
|
|
62584
|
-
const historyFilePath =
|
|
62096
|
+
const historyFilePath = join36(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`);
|
|
62585
62097
|
const managerOptions = {
|
|
62586
62098
|
provider: baseProvider,
|
|
62587
62099
|
workingDirectory: this.workingDirectory,
|
|
@@ -62738,15 +62250,16 @@ var ChatService = class {
|
|
|
62738
62250
|
});
|
|
62739
62251
|
}
|
|
62740
62252
|
this.agentTokenUsageTracker.noteAgentEvent(chatId, event);
|
|
62741
|
-
const codexTranscript = getCodexTranscriptFromEvent(event);
|
|
62742
62253
|
if (chat.hasActiveTurn) {
|
|
62743
|
-
|
|
62744
|
-
|
|
62745
|
-
|
|
62746
|
-
|
|
62747
|
-
|
|
62254
|
+
this.agentChatActivityTrackerService.noteSkillMcpCalls(
|
|
62255
|
+
chatId,
|
|
62256
|
+
parseDisplayMessages([event], getChatExecutionProvider(chat.persisted), {
|
|
62257
|
+
filter: false,
|
|
62258
|
+
parentToolUseId: typeof event.payload.parent_tool_use_id === "string" ? event.payload.parent_tool_use_id : null
|
|
62259
|
+
})
|
|
62260
|
+
);
|
|
62748
62261
|
}
|
|
62749
|
-
const terminalErrors = terminalErrorsFromEvent(event, getChatExecutionProvider(chat.persisted)
|
|
62262
|
+
const terminalErrors = terminalErrorsFromEvent(event, getChatExecutionProvider(chat.persisted));
|
|
62750
62263
|
if (terminalErrors !== void 0) {
|
|
62751
62264
|
chat.lastTurnErrors = terminalErrors;
|
|
62752
62265
|
}
|
|
@@ -62772,13 +62285,6 @@ var ChatService = class {
|
|
|
62772
62285
|
}
|
|
62773
62286
|
}
|
|
62774
62287
|
}
|
|
62775
|
-
if (codexTranscript) {
|
|
62776
|
-
for (const [messageId, acceptedEvent] of chat.acceptedUserEvents) {
|
|
62777
|
-
if (acceptedEventInCodexTranscript(acceptedEvent, codexTranscript)) {
|
|
62778
|
-
chat.acceptedUserEvents.delete(messageId);
|
|
62779
|
-
}
|
|
62780
|
-
}
|
|
62781
|
-
}
|
|
62782
62288
|
if (event.type !== CLAUDE_PARTIAL_MESSAGE_EVENT_TYPE) {
|
|
62783
62289
|
this.touch(chat);
|
|
62784
62290
|
this.observeCurrentBranches(chat).catch(() => {
|
|
@@ -62827,25 +62333,29 @@ var ChatService = class {
|
|
|
62827
62333
|
this.endTrackedTurn(chatId);
|
|
62828
62334
|
const completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
62829
62335
|
const processing = chat.provider.getQueue().length > 0 || (chat.provider.hasActiveBackgroundTasks?.() ?? false);
|
|
62830
|
-
|
|
62336
|
+
const exhaustion = chat.quotaExhaustion;
|
|
62337
|
+
chat.quotaExhaustion = null;
|
|
62831
62338
|
uploadChatTranscript(
|
|
62832
62339
|
chatId,
|
|
62833
|
-
|
|
62834
|
-
this.
|
|
62340
|
+
join36(HISTORY_DIR_BY_PROVIDER[chat.persisted.provider], `${chatId}.jsonl`),
|
|
62341
|
+
this.toTranscriptSource(chat)
|
|
62835
62342
|
).catch((err) => {
|
|
62836
62343
|
console.error("[ChatService] Failed to upload chat transcript:", { chatId, err });
|
|
62837
62344
|
});
|
|
62838
62345
|
flushAllCanvasItems().catch((err) => {
|
|
62839
62346
|
console.error("[ChatService] Failed to upload canvas items:", { chatId, err });
|
|
62840
62347
|
});
|
|
62841
|
-
|
|
62842
|
-
const exhaustion = chat.quotaExhaustion;
|
|
62843
|
-
chat.quotaExhaustion = null;
|
|
62348
|
+
let forked = false;
|
|
62844
62349
|
if (exhaustion) {
|
|
62845
|
-
|
|
62350
|
+
try {
|
|
62351
|
+
forked = await this.autoForkAfterQuota(chat, exhaustion);
|
|
62352
|
+
} catch (error) {
|
|
62846
62353
|
console.error("[ChatService] Automatic fork after quota limit failed:", { chatId, error });
|
|
62847
|
-
}
|
|
62354
|
+
}
|
|
62848
62355
|
}
|
|
62356
|
+
const stillProcessing = processing || forked;
|
|
62357
|
+
this.publishTurnCompleted(chat, completedAt, stillProcessing);
|
|
62358
|
+
await this.publishAgentTurnCompleteWebhook(chat, completedAt, stillProcessing);
|
|
62849
62359
|
this.notifyWorkspaceAgentIdle();
|
|
62850
62360
|
}
|
|
62851
62361
|
publishTurnCompleted(chat, completedAt, processing) {
|
|
@@ -62878,7 +62388,7 @@ var ChatService = class {
|
|
|
62878
62388
|
}
|
|
62879
62389
|
async loadChats() {
|
|
62880
62390
|
try {
|
|
62881
|
-
const content = await
|
|
62391
|
+
const content = await readFile23(CHATS_FILE, "utf-8");
|
|
62882
62392
|
return parsePersistedChatsContent(content);
|
|
62883
62393
|
} catch (error) {
|
|
62884
62394
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
@@ -62887,13 +62397,13 @@ var ChatService = class {
|
|
|
62887
62397
|
const quarantinePath = corruptChatsFilePath();
|
|
62888
62398
|
console.error(`[ChatService] Failed to load ${CHATS_FILE}; quarantining and trying backup:`, error);
|
|
62889
62399
|
try {
|
|
62890
|
-
await
|
|
62400
|
+
await rename5(CHATS_FILE, quarantinePath);
|
|
62891
62401
|
console.error(`[ChatService] Quarantined corrupt chats file at ${quarantinePath}`);
|
|
62892
62402
|
} catch (renameError) {
|
|
62893
62403
|
console.error("[ChatService] Failed to quarantine corrupt chats file:", renameError);
|
|
62894
62404
|
}
|
|
62895
62405
|
try {
|
|
62896
|
-
const backupContent = await
|
|
62406
|
+
const backupContent = await readFile23(CHATS_BACKUP_FILE, "utf-8");
|
|
62897
62407
|
return parsePersistedChatsContent(backupContent);
|
|
62898
62408
|
} catch (backupError) {
|
|
62899
62409
|
if (backupError && typeof backupError === "object" && "code" in backupError && backupError.code === "ENOENT") {
|
|
@@ -62988,14 +62498,14 @@ var ChatService = class {
|
|
|
62988
62498
|
|
|
62989
62499
|
// src/services/repo-file-service.ts
|
|
62990
62500
|
import { execFile as execFile7 } from "child_process";
|
|
62991
|
-
import { readFile as
|
|
62501
|
+
import { readFile as readFile24 } from "fs/promises";
|
|
62992
62502
|
import { extname as extname3 } from "path";
|
|
62993
62503
|
|
|
62994
62504
|
// src/services/language-server-service.ts
|
|
62995
62505
|
import { spawn as spawn9 } from "child_process";
|
|
62996
62506
|
import { existsSync as existsSync17, readFileSync as readFileSync8 } from "fs";
|
|
62997
62507
|
import { createRequire as createRequire6 } from "module";
|
|
62998
|
-
import { delimiter as delimiter2, dirname as dirname19, join as
|
|
62508
|
+
import { delimiter as delimiter2, dirname as dirname19, join as join37, relative as relative2 } from "path";
|
|
62999
62509
|
import { setTimeout as setTimeout2 } from "timers/promises";
|
|
63000
62510
|
import { fileURLToPath as fileURLToPath6, pathToFileURL } from "url";
|
|
63001
62511
|
import { createMessageConnection, StreamMessageReader, StreamMessageWriter } from "vscode-jsonrpc/node.js";
|
|
@@ -63114,7 +62624,7 @@ var LanguageServerService = class {
|
|
|
63114
62624
|
if (config.package && config.bin) command = process.execPath;
|
|
63115
62625
|
else if (config.command) {
|
|
63116
62626
|
const commandName = config.command;
|
|
63117
|
-
command = process.env.PATH?.split(delimiter2).map((directory) =>
|
|
62627
|
+
command = process.env.PATH?.split(delimiter2).map((directory) => join37(directory, commandName)).find(existsSync17);
|
|
63118
62628
|
}
|
|
63119
62629
|
const args = config.package && config.bin ? [packageBin(config.package, config.bin), ...config.args] : config.args;
|
|
63120
62630
|
if (!command) return null;
|
|
@@ -63285,7 +62795,7 @@ var RepoFileService = class {
|
|
|
63285
62795
|
sizeBytes,
|
|
63286
62796
|
binary: true,
|
|
63287
62797
|
tooLarge: false,
|
|
63288
|
-
base64: (await
|
|
62798
|
+
base64: (await readFile24(fullPath)).toString("base64"),
|
|
63289
62799
|
mimeType
|
|
63290
62800
|
};
|
|
63291
62801
|
}
|
|
@@ -63310,7 +62820,7 @@ var RepoFileService = class {
|
|
|
63310
62820
|
tooLarge: true
|
|
63311
62821
|
};
|
|
63312
62822
|
}
|
|
63313
|
-
const content = await
|
|
62823
|
+
const content = await readFile24(fullPath, "utf-8");
|
|
63314
62824
|
return {
|
|
63315
62825
|
repoName,
|
|
63316
62826
|
path: filePath,
|
|
@@ -63342,7 +62852,7 @@ var RepoFileService = class {
|
|
|
63342
62852
|
async inspectSymbol(repoName, filePath, line, character, action) {
|
|
63343
62853
|
const resolved = await this.resolveFile(repoName, filePath);
|
|
63344
62854
|
if (!resolved || line < 1 || character < 0 || isBinaryExtension(filePath)) return null;
|
|
63345
|
-
const content = await
|
|
62855
|
+
const content = await readFile24(resolved.fullPath, "utf8");
|
|
63346
62856
|
const sourceLine = content.split("\n")[line - 1];
|
|
63347
62857
|
if (sourceLine === void 0) return null;
|
|
63348
62858
|
const symbolMatch = Array.from(sourceLine.matchAll(/[\p{L}_$][\p{L}\p{N}_$]*/gu)).find((match) => character >= match.index && character <= match.index + match[0].length);
|
|
@@ -63455,21 +62965,21 @@ var RepoFileService = class {
|
|
|
63455
62965
|
// src/v1-routes.ts
|
|
63456
62966
|
import { Hono } from "hono";
|
|
63457
62967
|
import { z as z6 } from "zod";
|
|
63458
|
-
import { readdir as
|
|
63459
|
-
import { join as
|
|
62968
|
+
import { readdir as readdir12, stat as stat7, readFile as readFile27 } from "fs/promises";
|
|
62969
|
+
import { join as join40, resolve as resolve5 } from "path";
|
|
63460
62970
|
|
|
63461
62971
|
// src/services/warm-hooks-service.ts
|
|
63462
62972
|
import { spawn as spawn10 } from "child_process";
|
|
63463
|
-
import { readFile as
|
|
62973
|
+
import { readFile as readFile26 } from "fs/promises";
|
|
63464
62974
|
import { existsSync as existsSync18 } from "fs";
|
|
63465
|
-
import { join as
|
|
62975
|
+
import { join as join39 } from "path";
|
|
63466
62976
|
|
|
63467
62977
|
// src/services/warm-hook-logs-service.ts
|
|
63468
|
-
import { mkdir as mkdir22, readFile as
|
|
62978
|
+
import { mkdir as mkdir22, readFile as readFile25, writeFile as writeFile12, readdir as readdir11, appendFile as appendFile6, unlink as unlink4 } from "fs/promises";
|
|
63469
62979
|
import { homedir as homedir14 } from "os";
|
|
63470
|
-
import { join as
|
|
63471
|
-
var LOGS_DIR2 =
|
|
63472
|
-
var CURRENT_RUN_LOG =
|
|
62980
|
+
import { join as join38 } from "path";
|
|
62981
|
+
var LOGS_DIR2 = join38(homedir14(), ".replicas", "warm-hook-logs");
|
|
62982
|
+
var CURRENT_RUN_LOG = join38(LOGS_DIR2, "current-run.log");
|
|
63473
62983
|
var GLOBAL_FILENAME = "global.json";
|
|
63474
62984
|
function withPreview2(stored) {
|
|
63475
62985
|
const preview = buildHookOutputPreview(stored.output);
|
|
@@ -63486,7 +62996,7 @@ var WarmHookLogsService = class {
|
|
|
63486
62996
|
hookName: "organization",
|
|
63487
62997
|
...entry
|
|
63488
62998
|
};
|
|
63489
|
-
await writeFile12(
|
|
62999
|
+
await writeFile12(join38(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
|
|
63490
63000
|
`, "utf-8");
|
|
63491
63001
|
}
|
|
63492
63002
|
async saveEnvironmentHookLog(entry) {
|
|
@@ -63496,7 +63006,7 @@ var WarmHookLogsService = class {
|
|
|
63496
63006
|
hookName: "environment",
|
|
63497
63007
|
...entry
|
|
63498
63008
|
};
|
|
63499
|
-
await writeFile12(
|
|
63009
|
+
await writeFile12(join38(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
|
|
63500
63010
|
`, "utf-8");
|
|
63501
63011
|
}
|
|
63502
63012
|
async saveRepoHookLog(repoName, entry) {
|
|
@@ -63506,13 +63016,13 @@ var WarmHookLogsService = class {
|
|
|
63506
63016
|
hookName: repoName,
|
|
63507
63017
|
...entry
|
|
63508
63018
|
};
|
|
63509
|
-
await writeFile12(
|
|
63019
|
+
await writeFile12(join38(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
|
|
63510
63020
|
`, "utf-8");
|
|
63511
63021
|
}
|
|
63512
63022
|
async getAllLogs() {
|
|
63513
63023
|
let files;
|
|
63514
63024
|
try {
|
|
63515
|
-
files = await
|
|
63025
|
+
files = await readdir11(LOGS_DIR2);
|
|
63516
63026
|
} catch (err) {
|
|
63517
63027
|
if (err.code === "ENOENT") {
|
|
63518
63028
|
return [];
|
|
@@ -63525,7 +63035,7 @@ var WarmHookLogsService = class {
|
|
|
63525
63035
|
continue;
|
|
63526
63036
|
}
|
|
63527
63037
|
try {
|
|
63528
|
-
const raw = await
|
|
63038
|
+
const raw = await readFile25(join38(LOGS_DIR2, file), "utf-8");
|
|
63529
63039
|
const stored = JSON.parse(raw);
|
|
63530
63040
|
logs.push(withPreview2(stored));
|
|
63531
63041
|
} catch {
|
|
@@ -63554,7 +63064,7 @@ var WarmHookLogsService = class {
|
|
|
63554
63064
|
}
|
|
63555
63065
|
async getCurrentRunLog() {
|
|
63556
63066
|
try {
|
|
63557
|
-
return await
|
|
63067
|
+
return await readFile25(CURRENT_RUN_LOG, "utf-8");
|
|
63558
63068
|
} catch (err) {
|
|
63559
63069
|
if (err.code === "ENOENT") return null;
|
|
63560
63070
|
throw err;
|
|
@@ -63563,7 +63073,7 @@ var WarmHookLogsService = class {
|
|
|
63563
63073
|
async getFullOutput(hookType, hookName) {
|
|
63564
63074
|
const filename = hookType === "global" ? GLOBAL_FILENAME : hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
|
|
63565
63075
|
try {
|
|
63566
|
-
const raw = await
|
|
63076
|
+
const raw = await readFile25(join38(LOGS_DIR2, filename), "utf-8");
|
|
63567
63077
|
const stored = JSON.parse(raw);
|
|
63568
63078
|
if (stored.hookType !== hookType || stored.hookName !== hookName) {
|
|
63569
63079
|
return null;
|
|
@@ -63582,12 +63092,12 @@ var warmHookLogsService = new WarmHookLogsService();
|
|
|
63582
63092
|
// src/services/warm-hooks-service.ts
|
|
63583
63093
|
async function readRepoWarmHook(repoPath) {
|
|
63584
63094
|
for (const filename of REPLICAS_CONFIG_FILENAMES) {
|
|
63585
|
-
const configPath =
|
|
63095
|
+
const configPath = join39(repoPath, filename);
|
|
63586
63096
|
if (!existsSync18(configPath)) {
|
|
63587
63097
|
continue;
|
|
63588
63098
|
}
|
|
63589
63099
|
try {
|
|
63590
|
-
const raw = await
|
|
63100
|
+
const raw = await readFile26(configPath, "utf-8");
|
|
63591
63101
|
const config = parseReplicasConfigString(raw, filename);
|
|
63592
63102
|
if (!config.warmHook) {
|
|
63593
63103
|
return null;
|
|
@@ -64912,11 +64422,11 @@ data: ${JSON.stringify("Terminal session not found")}
|
|
|
64912
64422
|
});
|
|
64913
64423
|
app2.get("/logs", async (c) => {
|
|
64914
64424
|
try {
|
|
64915
|
-
const files = await
|
|
64425
|
+
const files = await readdir12(LOG_DIR).catch(() => []);
|
|
64916
64426
|
const logFiles = files.filter((f) => f.endsWith(".log"));
|
|
64917
64427
|
const sessions = await Promise.all(
|
|
64918
64428
|
logFiles.map(async (filename) => {
|
|
64919
|
-
const filePath =
|
|
64429
|
+
const filePath = join40(LOG_DIR, filename);
|
|
64920
64430
|
const fileStat = await stat7(filePath);
|
|
64921
64431
|
const sessionId = filename.replace(/\.log$/, "");
|
|
64922
64432
|
return {
|
|
@@ -64951,7 +64461,7 @@ data: ${JSON.stringify("Terminal session not found")}
|
|
|
64951
64461
|
}
|
|
64952
64462
|
let content;
|
|
64953
64463
|
try {
|
|
64954
|
-
content = await
|
|
64464
|
+
content = await readFile27(filePath, "utf-8");
|
|
64955
64465
|
} catch {
|
|
64956
64466
|
return c.json(jsonError("Log session not found"), 404);
|
|
64957
64467
|
}
|