remote-codex 0.11.10 → 0.11.12
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/apps/relay-server/dist/index.js +10 -2
- package/apps/supervisor-api/dist/{chunk-HMFJNQDI.js → chunk-TQUNANIS.js} +1238 -382
- package/apps/supervisor-api/dist/index.js +1 -1
- package/apps/supervisor-api/dist/worker-index.js +1 -1
- package/apps/supervisor-web/dist/assets/index-Dsq8QmDr.js +6 -0
- package/apps/supervisor-web/dist/index.html +1 -1
- package/package.json +1 -1
- package/packages/agent-runtime/src/types.ts +1 -0
- package/packages/codex/src/appServerManager.test.ts +52 -0
- package/packages/codex/src/appServerManager.ts +12 -14
- package/packages/codex/src/historyItems.test.ts +33 -0
- package/packages/codex/src/historyItems.ts +49 -2
- package/packages/codex/src/runtimeAdapter.test.ts +76 -0
- package/packages/codex/src/runtimeAdapter.ts +72 -2
- package/packages/codex/src/types.ts +13 -0
- package/packages/shared/src/index.ts +2 -0
- package/apps/supervisor-web/dist/assets/index-M5xKhovw.js +0 -5
|
@@ -8,9 +8,9 @@ var __export = (target, all) => {
|
|
|
8
8
|
import Fastify from "fastify";
|
|
9
9
|
import multipart from "@fastify/multipart";
|
|
10
10
|
import websocket from "@fastify/websocket";
|
|
11
|
-
import { spawn as
|
|
11
|
+
import { spawn as spawn6 } from "child_process";
|
|
12
12
|
import fs26 from "fs";
|
|
13
|
-
import
|
|
13
|
+
import path26 from "path";
|
|
14
14
|
import { ZodError } from "zod";
|
|
15
15
|
|
|
16
16
|
// ../../packages/config/src/index.ts
|
|
@@ -176,7 +176,7 @@ function loadRuntimeConfig(env = process.env) {
|
|
|
176
176
|
nodeEnv === "production"
|
|
177
177
|
);
|
|
178
178
|
const enabledProviders = new Set(
|
|
179
|
-
(parsed.REMOTE_CODEX_ENABLED_AGENT_PROVIDERS ?? agentBackendIds.join(",")).split(",").map((
|
|
179
|
+
(parsed.REMOTE_CODEX_ENABLED_AGENT_PROVIDERS ?? agentBackendIds.join(",")).split(",").map((provider2) => provider2.trim().toLowerCase()).filter(Boolean)
|
|
180
180
|
);
|
|
181
181
|
const defaultAgentHomeRoot = runtimeRole === "worker" ? "/home/agent" : os.homedir();
|
|
182
182
|
const codexHome = parsed.CODEX_HOME?.trim() ? path.resolve(parsed.CODEX_HOME) : path.join(defaultAgentHomeRoot, agentBackendMetadata.codex.defaultHomeDir);
|
|
@@ -465,15 +465,15 @@ var AgentRuntimeRegistry = class {
|
|
|
465
465
|
}
|
|
466
466
|
defaultProvider;
|
|
467
467
|
runtimes = /* @__PURE__ */ new Map();
|
|
468
|
-
get(
|
|
469
|
-
const runtime = this.runtimes.get(
|
|
468
|
+
get(provider2) {
|
|
469
|
+
const runtime = this.runtimes.get(provider2);
|
|
470
470
|
if (!runtime) {
|
|
471
|
-
throw new Error(`Agent runtime provider is not configured: ${
|
|
471
|
+
throw new Error(`Agent runtime provider is not configured: ${provider2}`);
|
|
472
472
|
}
|
|
473
473
|
return runtime;
|
|
474
474
|
}
|
|
475
|
-
getOptional(
|
|
476
|
-
return this.runtimes.get(
|
|
475
|
+
getOptional(provider2) {
|
|
476
|
+
return this.runtimes.get(provider2) ?? null;
|
|
477
477
|
}
|
|
478
478
|
all() {
|
|
479
479
|
return [...this.runtimes.values()];
|
|
@@ -501,9 +501,9 @@ var transientAgentHistoryItemSymbol = /* @__PURE__ */ Symbol(
|
|
|
501
501
|
"remoteCodex.transientAgentHistoryItem"
|
|
502
502
|
);
|
|
503
503
|
var AgentRuntimeError = class extends Error {
|
|
504
|
-
constructor(message,
|
|
504
|
+
constructor(message, provider2, code = "request_failed", details, cause) {
|
|
505
505
|
super(message);
|
|
506
|
-
this.provider =
|
|
506
|
+
this.provider = provider2;
|
|
507
507
|
this.code = code;
|
|
508
508
|
this.details = details;
|
|
509
509
|
this.cause = cause;
|
|
@@ -2316,7 +2316,7 @@ Subquery.prototype.getSQL = function() {
|
|
|
2316
2316
|
function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
2317
2317
|
const nullifyMap = {};
|
|
2318
2318
|
const result = columns.reduce(
|
|
2319
|
-
(result2, { path:
|
|
2319
|
+
(result2, { path: path27, field }, columnIndex) => {
|
|
2320
2320
|
let decoder;
|
|
2321
2321
|
if (is(field, Column)) {
|
|
2322
2322
|
decoder = field;
|
|
@@ -2326,8 +2326,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
|
2326
2326
|
decoder = field.sql.decoder;
|
|
2327
2327
|
}
|
|
2328
2328
|
let node = result2;
|
|
2329
|
-
for (const [pathChunkIndex, pathChunk] of
|
|
2330
|
-
if (pathChunkIndex <
|
|
2329
|
+
for (const [pathChunkIndex, pathChunk] of path27.entries()) {
|
|
2330
|
+
if (pathChunkIndex < path27.length - 1) {
|
|
2331
2331
|
if (!(pathChunk in node)) {
|
|
2332
2332
|
node[pathChunk] = {};
|
|
2333
2333
|
}
|
|
@@ -2335,8 +2335,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
|
2335
2335
|
} else {
|
|
2336
2336
|
const rawValue = row[columnIndex];
|
|
2337
2337
|
const value = node[pathChunk] = rawValue === null ? null : decoder.mapFromDriverValue(rawValue);
|
|
2338
|
-
if (joinsNotNullableMap && is(field, Column) &&
|
|
2339
|
-
const objectName =
|
|
2338
|
+
if (joinsNotNullableMap && is(field, Column) && path27.length === 2) {
|
|
2339
|
+
const objectName = path27[0];
|
|
2340
2340
|
if (!(objectName in nullifyMap)) {
|
|
2341
2341
|
nullifyMap[objectName] = value === null ? getTableName(field.table) : false;
|
|
2342
2342
|
} else if (typeof nullifyMap[objectName] === "string" && nullifyMap[objectName] !== getTableName(field.table)) {
|
|
@@ -7008,10 +7008,10 @@ function listThreadRecordsByWorkspaceId(db, workspaceId) {
|
|
|
7008
7008
|
function getThreadRecordById(db, id) {
|
|
7009
7009
|
return db.select().from(threads).where(eq(threads.id, id)).get();
|
|
7010
7010
|
}
|
|
7011
|
-
function getThreadRecordByProviderSessionId(db,
|
|
7011
|
+
function getThreadRecordByProviderSessionId(db, provider2, providerSessionId) {
|
|
7012
7012
|
return db.select().from(threads).where(
|
|
7013
7013
|
and(
|
|
7014
|
-
eq(threads.provider,
|
|
7014
|
+
eq(threads.provider, provider2),
|
|
7015
7015
|
eq(threads.providerSessionId, providerSessionId)
|
|
7016
7016
|
)
|
|
7017
7017
|
).get();
|
|
@@ -7956,6 +7956,15 @@ function mapTurn(record) {
|
|
|
7956
7956
|
items: Array.isArray(record.items) ? record.items : []
|
|
7957
7957
|
};
|
|
7958
7958
|
}
|
|
7959
|
+
function textOnlyUserInput(prompt) {
|
|
7960
|
+
return [
|
|
7961
|
+
{
|
|
7962
|
+
type: "text",
|
|
7963
|
+
text: prompt,
|
|
7964
|
+
text_elements: []
|
|
7965
|
+
}
|
|
7966
|
+
];
|
|
7967
|
+
}
|
|
7959
7968
|
function mapModel(record) {
|
|
7960
7969
|
return {
|
|
7961
7970
|
id: record.id,
|
|
@@ -8279,13 +8288,7 @@ var CodexAppServerManager = class extends EventEmitter3 {
|
|
|
8279
8288
|
await this.ensureReady();
|
|
8280
8289
|
const response = await this.client.request("turn/start", {
|
|
8281
8290
|
threadId: input.threadId,
|
|
8282
|
-
input:
|
|
8283
|
-
{
|
|
8284
|
-
type: "text",
|
|
8285
|
-
text: input.prompt,
|
|
8286
|
-
text_elements: []
|
|
8287
|
-
}
|
|
8288
|
-
],
|
|
8291
|
+
input: input.input ?? textOnlyUserInput(input.prompt),
|
|
8289
8292
|
model: input.model ?? null,
|
|
8290
8293
|
serviceTier: input.serviceTier === void 0 ? void 0 : input.serviceTier,
|
|
8291
8294
|
effort: input.effort ?? null,
|
|
@@ -8306,13 +8309,7 @@ var CodexAppServerManager = class extends EventEmitter3 {
|
|
|
8306
8309
|
const response = await this.client.request("turn/steer", {
|
|
8307
8310
|
threadId: input.threadId,
|
|
8308
8311
|
expectedTurnId: input.turnId,
|
|
8309
|
-
input:
|
|
8310
|
-
{
|
|
8311
|
-
type: "text",
|
|
8312
|
-
text: input.prompt,
|
|
8313
|
-
text_elements: []
|
|
8314
|
-
}
|
|
8315
|
-
]
|
|
8312
|
+
input: input.input ?? textOnlyUserInput(input.prompt)
|
|
8316
8313
|
});
|
|
8317
8314
|
return response.turn ? mapTurn(response.turn) : null;
|
|
8318
8315
|
}
|
|
@@ -8614,12 +8611,58 @@ ${entryPreview}` : null
|
|
|
8614
8611
|
var DEFERRED_COMMAND_DETAIL_TITLE = "Command Output";
|
|
8615
8612
|
var DEFERRED_TOOL_DETAIL_TITLE = "Tool Call Details";
|
|
8616
8613
|
var DEFERRED_AGENT_TOOL_DETAIL_TITLE = "Agent Details";
|
|
8614
|
+
function parseUuidV7Timestamp(id) {
|
|
8615
|
+
const normalized = id.replace(/-/g, "");
|
|
8616
|
+
if (!/^[0-9a-f]{32}$/i.test(normalized) || normalized[12]?.toLowerCase() !== "7") {
|
|
8617
|
+
return null;
|
|
8618
|
+
}
|
|
8619
|
+
const millis = Number.parseInt(normalized.slice(0, 12), 16);
|
|
8620
|
+
if (!Number.isFinite(millis)) {
|
|
8621
|
+
return null;
|
|
8622
|
+
}
|
|
8623
|
+
return new Date(millis).toISOString();
|
|
8624
|
+
}
|
|
8617
8625
|
function isRecord4(value) {
|
|
8618
8626
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
8619
8627
|
}
|
|
8620
8628
|
function stringOrNull(value) {
|
|
8621
8629
|
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
8622
8630
|
}
|
|
8631
|
+
function isoTimestampOrNull(value) {
|
|
8632
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
8633
|
+
const epochMs = value < 1e10 ? value * 1e3 : value;
|
|
8634
|
+
return new Date(epochMs).toISOString();
|
|
8635
|
+
}
|
|
8636
|
+
const text2 = stringOrNull(value);
|
|
8637
|
+
if (!text2) {
|
|
8638
|
+
return null;
|
|
8639
|
+
}
|
|
8640
|
+
const parsed = Date.parse(text2);
|
|
8641
|
+
return Number.isFinite(parsed) ? new Date(parsed).toISOString() : null;
|
|
8642
|
+
}
|
|
8643
|
+
function codexItemCreatedAt(item) {
|
|
8644
|
+
const candidates = [
|
|
8645
|
+
item.createdAt,
|
|
8646
|
+
item.created_at,
|
|
8647
|
+
item.startedAt,
|
|
8648
|
+
item.started_at,
|
|
8649
|
+
item.completedAt,
|
|
8650
|
+
item.completed_at
|
|
8651
|
+
];
|
|
8652
|
+
for (const candidate of candidates) {
|
|
8653
|
+
const timestamp = isoTimestampOrNull(candidate);
|
|
8654
|
+
if (timestamp) {
|
|
8655
|
+
return timestamp;
|
|
8656
|
+
}
|
|
8657
|
+
}
|
|
8658
|
+
return parseUuidV7Timestamp(item.id);
|
|
8659
|
+
}
|
|
8660
|
+
function withCodexItemTimestamp(item, historyItem) {
|
|
8661
|
+
return {
|
|
8662
|
+
...historyItem,
|
|
8663
|
+
createdAt: historyItem.createdAt ?? codexItemCreatedAt(item)
|
|
8664
|
+
};
|
|
8665
|
+
}
|
|
8623
8666
|
function numberOrNull(value) {
|
|
8624
8667
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
8625
8668
|
return value;
|
|
@@ -9108,7 +9151,7 @@ function extractFileChangeEntries(item) {
|
|
|
9108
9151
|
isRecord4(entry.summary) ? entry.summary : null,
|
|
9109
9152
|
isRecord4(entry.diff) ? entry.diff : null
|
|
9110
9153
|
].filter((candidate) => Boolean(candidate));
|
|
9111
|
-
const
|
|
9154
|
+
const path27 = uniqueStrings([
|
|
9112
9155
|
stringOrNull(valueFromRecords(nestedRecords, ["path", "filePath", "targetPath"])),
|
|
9113
9156
|
stringOrNull(
|
|
9114
9157
|
valueFromRecords(nestedRecords, [
|
|
@@ -9155,7 +9198,7 @@ function extractFileChangeEntries(item) {
|
|
|
9155
9198
|
const diffStats = explicitAdditions === 0 && explicitDeletions === 0 && diffText ? countUnifiedDiffStats(diffText) : null;
|
|
9156
9199
|
const additions = explicitAdditions || diffStats?.additions || 0;
|
|
9157
9200
|
const deletions = explicitDeletions || diffStats?.deletions || 0;
|
|
9158
|
-
const normalizedPath =
|
|
9201
|
+
const normalizedPath = path27 ?? (diffText ? projectRelativePathLabel(extractPathFromDiffText(diffText)) : null);
|
|
9159
9202
|
if (!normalizedPath && additions === 0 && deletions === 0) {
|
|
9160
9203
|
return null;
|
|
9161
9204
|
}
|
|
@@ -9320,7 +9363,7 @@ function itemToHistoryItem(item, deferredDetails) {
|
|
|
9320
9363
|
}
|
|
9321
9364
|
}
|
|
9322
9365
|
function liveCodexItemToHistoryItem(item, phase) {
|
|
9323
|
-
const historyItem = itemToHistoryItem(item);
|
|
9366
|
+
const historyItem = withCodexItemTimestamp(item, itemToHistoryItem(item));
|
|
9324
9367
|
if (historyItem.kind !== "commandExecution" && historyItem.kind !== "toolCall" && historyItem.kind !== "agentToolCall" && historyItem.kind !== "skillToolCall" && historyItem.kind !== "fileChange" && historyItem.kind !== "webSearch") {
|
|
9325
9368
|
return null;
|
|
9326
9369
|
}
|
|
@@ -9335,7 +9378,9 @@ function codexTurnToAgentTurn(turn) {
|
|
|
9335
9378
|
rawTurnId: turn.id,
|
|
9336
9379
|
status: turn.status,
|
|
9337
9380
|
error: turn.error,
|
|
9338
|
-
items: turn.items.map(
|
|
9381
|
+
items: turn.items.map(
|
|
9382
|
+
(item) => withCodexItemTimestamp(item, itemToHistoryItem(item))
|
|
9383
|
+
),
|
|
9339
9384
|
rawTurn: turn
|
|
9340
9385
|
};
|
|
9341
9386
|
}
|
|
@@ -9940,8 +9985,8 @@ var CodexManagementService = class {
|
|
|
9940
9985
|
isRuntimeRequestError(error) {
|
|
9941
9986
|
return isCodexRuntimeRequestError(error);
|
|
9942
9987
|
}
|
|
9943
|
-
canManageHookFiles(
|
|
9944
|
-
return !
|
|
9988
|
+
canManageHookFiles(provider2) {
|
|
9989
|
+
return !provider2 || provider2 === "codex";
|
|
9945
9990
|
}
|
|
9946
9991
|
isUnsupportedHooksListError(error) {
|
|
9947
9992
|
return isUnsupportedHooksListError(error);
|
|
@@ -10110,6 +10155,7 @@ var CodexManagementService = class {
|
|
|
10110
10155
|
|
|
10111
10156
|
// ../../packages/codex/src/runtimeAdapter.ts
|
|
10112
10157
|
import { EventEmitter as EventEmitter4 } from "events";
|
|
10158
|
+
import path9 from "path";
|
|
10113
10159
|
|
|
10114
10160
|
// ../../packages/codex/src/requestMapper.ts
|
|
10115
10161
|
function isRecord6(value) {
|
|
@@ -10447,6 +10493,50 @@ function mapCodexProviderRequest(providerRequest, approvalMode) {
|
|
|
10447
10493
|
}
|
|
10448
10494
|
|
|
10449
10495
|
// ../../packages/codex/src/runtimeAdapter.ts
|
|
10496
|
+
var promptPhotoTokenPattern = /\[PHOTO\s+([^\]]+)\]/g;
|
|
10497
|
+
function resolvePromptAssetPath(assetPath, cwd) {
|
|
10498
|
+
if (!assetPath) {
|
|
10499
|
+
return null;
|
|
10500
|
+
}
|
|
10501
|
+
if (path9.isAbsolute(assetPath)) {
|
|
10502
|
+
return path9.normalize(assetPath);
|
|
10503
|
+
}
|
|
10504
|
+
if (!cwd) {
|
|
10505
|
+
return null;
|
|
10506
|
+
}
|
|
10507
|
+
return path9.resolve(cwd, assetPath);
|
|
10508
|
+
}
|
|
10509
|
+
function codexUserInputFromPrompt(prompt, cwd) {
|
|
10510
|
+
const matches = [...prompt.matchAll(promptPhotoTokenPattern)];
|
|
10511
|
+
if (matches.length === 0) {
|
|
10512
|
+
return void 0;
|
|
10513
|
+
}
|
|
10514
|
+
const input = [];
|
|
10515
|
+
let cursor = 0;
|
|
10516
|
+
let includedImage = false;
|
|
10517
|
+
for (const match of matches) {
|
|
10518
|
+
const token = match[0];
|
|
10519
|
+
const assetPath = match[1]?.trim() ?? "";
|
|
10520
|
+
const start = match.index ?? 0;
|
|
10521
|
+
const precedingText = prompt.slice(cursor, start);
|
|
10522
|
+
if (precedingText) {
|
|
10523
|
+
input.push({ type: "text", text: precedingText, text_elements: [] });
|
|
10524
|
+
}
|
|
10525
|
+
const resolvedPath = resolvePromptAssetPath(assetPath, cwd);
|
|
10526
|
+
if (resolvedPath) {
|
|
10527
|
+
input.push({ type: "localImage", path: resolvedPath });
|
|
10528
|
+
includedImage = true;
|
|
10529
|
+
} else {
|
|
10530
|
+
input.push({ type: "text", text: token, text_elements: [] });
|
|
10531
|
+
}
|
|
10532
|
+
cursor = start + token.length;
|
|
10533
|
+
}
|
|
10534
|
+
const trailingText = prompt.slice(cursor);
|
|
10535
|
+
if (trailingText) {
|
|
10536
|
+
input.push({ type: "text", text: trailingText, text_elements: [] });
|
|
10537
|
+
}
|
|
10538
|
+
return includedImage ? input : void 0;
|
|
10539
|
+
}
|
|
10450
10540
|
var codexCapabilities = {
|
|
10451
10541
|
sessions: {
|
|
10452
10542
|
list: true,
|
|
@@ -10961,6 +11051,13 @@ var CodexRuntimeAdapter = class extends EventEmitter4 {
|
|
|
10961
11051
|
threadId: input.providerSessionId,
|
|
10962
11052
|
prompt: input.prompt
|
|
10963
11053
|
};
|
|
11054
|
+
const structuredInput = codexUserInputFromPrompt(
|
|
11055
|
+
input.prompt,
|
|
11056
|
+
input.workspacePath
|
|
11057
|
+
);
|
|
11058
|
+
if (structuredInput) {
|
|
11059
|
+
turnInput.input = structuredInput;
|
|
11060
|
+
}
|
|
10964
11061
|
if (input.developerInstructions !== void 0) {
|
|
10965
11062
|
turnInput.developerInstructions = input.developerInstructions;
|
|
10966
11063
|
}
|
|
@@ -10987,11 +11084,17 @@ var CodexRuntimeAdapter = class extends EventEmitter4 {
|
|
|
10987
11084
|
return mapTurn2(await codexRuntimeCall(() => this.manager.startTurn(turnInput)));
|
|
10988
11085
|
}
|
|
10989
11086
|
async sendInput(input) {
|
|
10990
|
-
const
|
|
11087
|
+
const structuredInput = codexUserInputFromPrompt(
|
|
11088
|
+
input.prompt,
|
|
11089
|
+
input.workspacePath
|
|
11090
|
+
);
|
|
11091
|
+
const steerInput = {
|
|
10991
11092
|
threadId: input.providerSessionId,
|
|
10992
11093
|
turnId: input.providerTurnId,
|
|
10993
|
-
prompt: input.prompt
|
|
10994
|
-
|
|
11094
|
+
prompt: input.prompt,
|
|
11095
|
+
...structuredInput ? { input: structuredInput } : {}
|
|
11096
|
+
};
|
|
11097
|
+
const turn = await codexRuntimeCall(() => this.manager.steerTurn(steerInput));
|
|
10995
11098
|
return turn ? mapTurn2(turn) : null;
|
|
10996
11099
|
}
|
|
10997
11100
|
async interruptTurn(input) {
|
|
@@ -11640,13 +11743,13 @@ import { EventEmitter as EventEmitter5 } from "events";
|
|
|
11640
11743
|
import { execFile } from "child_process";
|
|
11641
11744
|
import fs8 from "fs/promises";
|
|
11642
11745
|
import { createRequire } from "module";
|
|
11643
|
-
import
|
|
11746
|
+
import path10 from "path";
|
|
11644
11747
|
import { pathToFileURL } from "url";
|
|
11645
11748
|
import { promisify } from "util";
|
|
11646
11749
|
var execFileAsync = promisify(execFile);
|
|
11647
|
-
var
|
|
11750
|
+
var promptPhotoTokenPattern2 = /\[PHOTO\s+([^\]]+)\]/g;
|
|
11648
11751
|
function mimeTypeForImagePath(filePath) {
|
|
11649
|
-
const extension =
|
|
11752
|
+
const extension = path10.extname(filePath).toLowerCase();
|
|
11650
11753
|
switch (extension) {
|
|
11651
11754
|
case ".jpg":
|
|
11652
11755
|
case ".jpeg":
|
|
@@ -11676,13 +11779,13 @@ function extensionForImageMediaType(mediaType) {
|
|
|
11676
11779
|
return null;
|
|
11677
11780
|
}
|
|
11678
11781
|
}
|
|
11679
|
-
function
|
|
11782
|
+
function resolvePromptAssetPath2(assetPath, cwd) {
|
|
11680
11783
|
if (!cwd) {
|
|
11681
11784
|
return null;
|
|
11682
11785
|
}
|
|
11683
|
-
const resolvedPath =
|
|
11684
|
-
const relativePath =
|
|
11685
|
-
if (relativePath === "" || !relativePath.startsWith("..") && !
|
|
11786
|
+
const resolvedPath = path10.isAbsolute(assetPath) ? path10.normalize(assetPath) : path10.resolve(cwd, assetPath);
|
|
11787
|
+
const relativePath = path10.relative(cwd, resolvedPath);
|
|
11788
|
+
if (relativePath === "" || !relativePath.startsWith("..") && !path10.isAbsolute(relativePath)) {
|
|
11686
11789
|
return resolvedPath;
|
|
11687
11790
|
}
|
|
11688
11791
|
return null;
|
|
@@ -11701,7 +11804,7 @@ async function* singleUserMessage(content) {
|
|
|
11701
11804
|
};
|
|
11702
11805
|
}
|
|
11703
11806
|
async function promptWithImageBlocks(prompt, cwd) {
|
|
11704
|
-
const matches = [...prompt.matchAll(
|
|
11807
|
+
const matches = [...prompt.matchAll(promptPhotoTokenPattern2)];
|
|
11705
11808
|
if (matches.length === 0) {
|
|
11706
11809
|
return prompt;
|
|
11707
11810
|
}
|
|
@@ -11716,7 +11819,7 @@ async function promptWithImageBlocks(prompt, cwd) {
|
|
|
11716
11819
|
if (precedingText) {
|
|
11717
11820
|
blocks.push({ type: "text", text: precedingText });
|
|
11718
11821
|
}
|
|
11719
|
-
const resolvedPath =
|
|
11822
|
+
const resolvedPath = resolvePromptAssetPath2(assetPath, cwd);
|
|
11720
11823
|
const mediaType = resolvedPath ? mimeTypeForImagePath(resolvedPath) : null;
|
|
11721
11824
|
if (!resolvedPath || !mediaType) {
|
|
11722
11825
|
blocks.push({ type: "text", text: token });
|
|
@@ -13099,13 +13202,13 @@ var ClaudeRuntimeAdapter = class extends EventEmitter5 {
|
|
|
13099
13202
|
return null;
|
|
13100
13203
|
}
|
|
13101
13204
|
const relativePath = `./.temp/threads/${input.localThreadId}/claude-history-${safeAssetFilePart(input.messageId)}-${input.blockIndex}.${extension}`;
|
|
13102
|
-
const targetPath =
|
|
13103
|
-
const relativeToWorkspace =
|
|
13104
|
-
if (relativeToWorkspace === "" || relativeToWorkspace.startsWith("..") ||
|
|
13205
|
+
const targetPath = path10.resolve(input.workspacePath, relativePath);
|
|
13206
|
+
const relativeToWorkspace = path10.relative(input.workspacePath, targetPath);
|
|
13207
|
+
if (relativeToWorkspace === "" || relativeToWorkspace.startsWith("..") || path10.isAbsolute(relativeToWorkspace)) {
|
|
13105
13208
|
return null;
|
|
13106
13209
|
}
|
|
13107
13210
|
try {
|
|
13108
|
-
await fs8.mkdir(
|
|
13211
|
+
await fs8.mkdir(path10.dirname(targetPath), { recursive: true });
|
|
13109
13212
|
await fs8.writeFile(targetPath, Buffer.from(data, "base64"));
|
|
13110
13213
|
return `[PHOTO ${relativePath}]`;
|
|
13111
13214
|
} catch {
|
|
@@ -13264,7 +13367,7 @@ async function importOptionalPackage(specifier) {
|
|
|
13264
13367
|
throw localError;
|
|
13265
13368
|
}
|
|
13266
13369
|
try {
|
|
13267
|
-
const requireFromGlobal = createRequire(
|
|
13370
|
+
const requireFromGlobal = createRequire(path10.join(globalRoot, "remote-codex-global.cjs"));
|
|
13268
13371
|
const resolved = requireFromGlobal.resolve(specifier);
|
|
13269
13372
|
return await dynamicImport(pathToFileURL(resolved).href);
|
|
13270
13373
|
} catch {
|
|
@@ -13284,7 +13387,7 @@ async function npmGlobalRoot() {
|
|
|
13284
13387
|
}
|
|
13285
13388
|
|
|
13286
13389
|
// ../../packages/opencode/src/historyItems.ts
|
|
13287
|
-
import
|
|
13390
|
+
import path11 from "path";
|
|
13288
13391
|
function isRecord9(value) {
|
|
13289
13392
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
13290
13393
|
}
|
|
@@ -13394,25 +13497,25 @@ function displayPath(pathValue, options) {
|
|
|
13394
13497
|
if (!pathValue) {
|
|
13395
13498
|
return null;
|
|
13396
13499
|
}
|
|
13397
|
-
if (!
|
|
13500
|
+
if (!path11.isAbsolute(pathValue) || !options.workspacePath) {
|
|
13398
13501
|
return pathValue;
|
|
13399
13502
|
}
|
|
13400
|
-
const root =
|
|
13401
|
-
const absolutePath =
|
|
13402
|
-
const relativePath =
|
|
13403
|
-
if (!relativePath || relativePath.startsWith("..") ||
|
|
13503
|
+
const root = path11.resolve(options.workspacePath);
|
|
13504
|
+
const absolutePath = path11.resolve(pathValue);
|
|
13505
|
+
const relativePath = path11.relative(root, absolutePath);
|
|
13506
|
+
if (!relativePath || relativePath.startsWith("..") || path11.isAbsolute(relativePath)) {
|
|
13404
13507
|
return pathValue;
|
|
13405
13508
|
}
|
|
13406
13509
|
return relativePath;
|
|
13407
13510
|
}
|
|
13408
|
-
function toolIsLowInformationPatch(normalized, state, input, patchText,
|
|
13511
|
+
function toolIsLowInformationPatch(normalized, state, input, patchText, path27, metadataStats) {
|
|
13409
13512
|
if (normalized !== "applypatch" && normalized !== "patch") {
|
|
13410
13513
|
return false;
|
|
13411
13514
|
}
|
|
13412
13515
|
if (toolStateStatus(state) !== "running") {
|
|
13413
13516
|
return false;
|
|
13414
13517
|
}
|
|
13415
|
-
if (
|
|
13518
|
+
if (path27 || patchText || metadataStats || stringValue2(state.output)) {
|
|
13416
13519
|
return false;
|
|
13417
13520
|
}
|
|
13418
13521
|
return !isRecord9(input) || Object.keys(input).length === 0;
|
|
@@ -13455,7 +13558,7 @@ function fileChangeStatsFromMetadata(metadata) {
|
|
|
13455
13558
|
if (files.length === 0) {
|
|
13456
13559
|
return null;
|
|
13457
13560
|
}
|
|
13458
|
-
const paths = files.map((file) => stringValue2(file.filePath) ?? stringValue2(file.path) ?? stringValue2(file.relativePath)).filter((
|
|
13561
|
+
const paths = files.map((file) => stringValue2(file.filePath) ?? stringValue2(file.path) ?? stringValue2(file.relativePath)).filter((path27) => Boolean(path27));
|
|
13459
13562
|
const addedLines = files.reduce((total, file) => total + (numberValue(file.additions) ?? numberValue(file.addedLines) ?? numberValue(file.added) ?? 0), 0);
|
|
13460
13563
|
const removedLines = files.reduce((total, file) => total + (numberValue(file.deletions) ?? numberValue(file.removedLines) ?? numberValue(file.removed) ?? 0), 0);
|
|
13461
13564
|
return {
|
|
@@ -13603,28 +13706,28 @@ function mapAssistantTool(messageId2, tool, options) {
|
|
|
13603
13706
|
].includes(normalized)) {
|
|
13604
13707
|
const metadataStats = fileChangeStatsFromMetadata(state.metadata);
|
|
13605
13708
|
const patchText = isRecord9(input) ? stringValue2(input.patchText) ?? stringValue2(input.patch) ?? stringValue2(input.diff) : null;
|
|
13606
|
-
const
|
|
13607
|
-
if (toolIsLowInformationPatch(normalized, state, input, patchText,
|
|
13709
|
+
const path27 = metadataStats?.path ?? filePathFromInput(input) ?? extractPathFromPatchText(patchText);
|
|
13710
|
+
if (toolIsLowInformationPatch(normalized, state, input, patchText, path27, metadataStats)) {
|
|
13608
13711
|
return null;
|
|
13609
13712
|
}
|
|
13610
13713
|
const output = stringValue2(state.output);
|
|
13611
13714
|
const diffStats = countUnifiedDiffStats2(patchText);
|
|
13612
|
-
const displayFilePath = displayPath(
|
|
13715
|
+
const displayFilePath = displayPath(path27, options);
|
|
13613
13716
|
return {
|
|
13614
13717
|
id,
|
|
13615
13718
|
kind: "fileChange",
|
|
13616
13719
|
text: metadataStats ? metadataStats.changedFiles > 1 ? `${metadataStats.changedFiles} changed files` : displayFilePath ?? metadataStats.previewText : displayFilePath ?? output ?? summary ?? name,
|
|
13617
13720
|
previewText: metadataStats ? metadataStats.changedFiles > 1 ? `${metadataStats.changedFiles} changed files` : displayFilePath ?? metadataStats.previewText : displayFilePath ? `${name}: ${displayFilePath}` : output ?? summary ?? name,
|
|
13618
13721
|
detailText,
|
|
13619
|
-
changedFiles: metadataStats?.changedFiles ?? (
|
|
13722
|
+
changedFiles: metadataStats?.changedFiles ?? (path27 ? 1 : null),
|
|
13620
13723
|
addedLines: metadataStats?.addedLines ?? diffStats?.addedLines ?? null,
|
|
13621
13724
|
removedLines: metadataStats?.removedLines ?? diffStats?.removedLines ?? null,
|
|
13622
13725
|
status: toolStateStatus(state)
|
|
13623
13726
|
};
|
|
13624
13727
|
}
|
|
13625
13728
|
if (["read", "grep", "glob", "list", "ls", "bashoutput"].includes(normalized)) {
|
|
13626
|
-
const
|
|
13627
|
-
const text2 = displayPath(
|
|
13729
|
+
const path27 = filePathFromInput(input);
|
|
13730
|
+
const text2 = displayPath(path27, options) ?? summary ?? name;
|
|
13628
13731
|
return {
|
|
13629
13732
|
id,
|
|
13630
13733
|
kind: "fileRead",
|
|
@@ -13970,7 +14073,7 @@ import { execFile as execFile2 } from "child_process";
|
|
|
13970
14073
|
import fs9 from "fs/promises";
|
|
13971
14074
|
import net from "net";
|
|
13972
14075
|
import { createRequire as createRequire2 } from "module";
|
|
13973
|
-
import
|
|
14076
|
+
import path12 from "path";
|
|
13974
14077
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
13975
14078
|
import { promisify as promisify2 } from "util";
|
|
13976
14079
|
var execFileAsync2 = promisify2(execFile2);
|
|
@@ -14102,21 +14205,21 @@ function configuredProviderModelRecords(config) {
|
|
|
14102
14205
|
if (!providerConfig) {
|
|
14103
14206
|
return configured;
|
|
14104
14207
|
}
|
|
14105
|
-
Object.entries(providerConfig).forEach(([providerID,
|
|
14106
|
-
if (!isRecord10(
|
|
14208
|
+
Object.entries(providerConfig).forEach(([providerID, provider2]) => {
|
|
14209
|
+
if (!isRecord10(provider2) || !isRecord10(provider2.models)) {
|
|
14107
14210
|
return;
|
|
14108
14211
|
}
|
|
14109
|
-
Object.entries(
|
|
14212
|
+
Object.entries(provider2.models).forEach(([modelID, model]) => {
|
|
14110
14213
|
configured.set(providerModelKey(providerID, modelID), isRecord10(model) ? model : {});
|
|
14111
14214
|
});
|
|
14112
14215
|
});
|
|
14113
14216
|
return configured;
|
|
14114
14217
|
}
|
|
14115
|
-
function mapProviderModel(
|
|
14116
|
-
if (!isRecord10(
|
|
14218
|
+
function mapProviderModel(provider2, record, index, configuredRecord) {
|
|
14219
|
+
if (!isRecord10(provider2) || !isRecord10(record)) {
|
|
14117
14220
|
return null;
|
|
14118
14221
|
}
|
|
14119
|
-
const providerID = stringValue3(record.providerID) ?? stringValue3(
|
|
14222
|
+
const providerID = stringValue3(record.providerID) ?? stringValue3(provider2.id);
|
|
14120
14223
|
const id = stringValue3(record.id);
|
|
14121
14224
|
if (!providerID || !id) {
|
|
14122
14225
|
return null;
|
|
@@ -14124,8 +14227,8 @@ function mapProviderModel(provider, record, index, configuredRecord) {
|
|
|
14124
14227
|
const name = stringValue3(configuredRecord?.name) ?? stringValue3(record.name) ?? id;
|
|
14125
14228
|
const variants = configuredRecord ? isRecord10(configuredRecord.variants) ? Object.keys(configuredRecord.variants) : [] : isRecord10(record.variants) ? Object.keys(record.variants) : [];
|
|
14126
14229
|
const model = providerModelKey(providerID, id);
|
|
14127
|
-
const providerName = stringValue3(
|
|
14128
|
-
const disabled = configuredRecord?.status === "disabled" || record.status === "disabled" ||
|
|
14230
|
+
const providerName = stringValue3(provider2.name) ?? providerID;
|
|
14231
|
+
const disabled = configuredRecord?.status === "disabled" || record.status === "disabled" || provider2.disabled === true;
|
|
14129
14232
|
const reasoningEfforts = variants.map((variant) => ({
|
|
14130
14233
|
reasoningEffort: variant,
|
|
14131
14234
|
description: variant === "none" ? "No reasoning" : variant === "xhigh" ? "Maximum reasoning" : `${variant[0]?.toUpperCase() ?? ""}${variant.slice(1)} reasoning`
|
|
@@ -14145,15 +14248,15 @@ function providerModels(result, configuredModels) {
|
|
|
14145
14248
|
const data = isRecord10(result) && Array.isArray(result.providers) ? result : isRecord10(result) && isRecord10(result.data) && Array.isArray(result.data.providers) ? result.data : null;
|
|
14146
14249
|
const providers = Array.isArray(data?.providers) ? data.providers : [];
|
|
14147
14250
|
const models = [];
|
|
14148
|
-
providers.forEach((
|
|
14149
|
-
if (!isRecord10(
|
|
14251
|
+
providers.forEach((provider2) => {
|
|
14252
|
+
if (!isRecord10(provider2) || !isRecord10(provider2.models)) {
|
|
14150
14253
|
return;
|
|
14151
14254
|
}
|
|
14152
|
-
Object.values(
|
|
14255
|
+
Object.values(provider2.models).forEach((model) => {
|
|
14153
14256
|
if (!isRecord10(model)) {
|
|
14154
14257
|
return;
|
|
14155
14258
|
}
|
|
14156
|
-
const providerID = stringValue3(model.providerID) ?? stringValue3(
|
|
14259
|
+
const providerID = stringValue3(model.providerID) ?? stringValue3(provider2.id);
|
|
14157
14260
|
const modelID = stringValue3(model.id);
|
|
14158
14261
|
if (!providerID || !modelID) {
|
|
14159
14262
|
return;
|
|
@@ -14162,7 +14265,7 @@ function providerModels(result, configuredModels) {
|
|
|
14162
14265
|
if (configuredModels && configuredModels.size > 0 && !configuredRecord) {
|
|
14163
14266
|
return;
|
|
14164
14267
|
}
|
|
14165
|
-
const mapped = mapProviderModel(
|
|
14268
|
+
const mapped = mapProviderModel(provider2, model, models.length, configuredRecord);
|
|
14166
14269
|
if (mapped) {
|
|
14167
14270
|
models.push(mapped);
|
|
14168
14271
|
}
|
|
@@ -15045,7 +15148,7 @@ async function importOptionalPackage2(specifier) {
|
|
|
15045
15148
|
throw localError;
|
|
15046
15149
|
}
|
|
15047
15150
|
try {
|
|
15048
|
-
const requireFromGlobal = createRequire2(
|
|
15151
|
+
const requireFromGlobal = createRequire2(path12.join(globalRoot, "remote-codex-global.cjs"));
|
|
15049
15152
|
const resolved = resolveOptionalPackage(requireFromGlobal, globalRoot, specifier);
|
|
15050
15153
|
return await dynamicImport(pathToFileURL2(resolved).href);
|
|
15051
15154
|
} catch {
|
|
@@ -15058,7 +15161,7 @@ function resolveOptionalPackage(requireFromGlobal, globalRoot, specifier) {
|
|
|
15058
15161
|
return requireFromGlobal.resolve(specifier);
|
|
15059
15162
|
} catch (error) {
|
|
15060
15163
|
if (error.code === "ERR_PACKAGE_PATH_NOT_EXPORTED" && specifier === "@opencode-ai/sdk/v2") {
|
|
15061
|
-
return
|
|
15164
|
+
return path12.join(globalRoot, "@opencode-ai", "sdk", "dist", "v2", "index.js");
|
|
15062
15165
|
}
|
|
15063
15166
|
throw error;
|
|
15064
15167
|
}
|
|
@@ -15074,6 +15177,498 @@ async function npmGlobalRoot2() {
|
|
|
15074
15177
|
}
|
|
15075
15178
|
}
|
|
15076
15179
|
|
|
15180
|
+
// src/e2e-fake-runtime.ts
|
|
15181
|
+
import { EventEmitter as EventEmitter7 } from "events";
|
|
15182
|
+
var provider = "claude";
|
|
15183
|
+
var firstDelta = "IOS_STREAM_DELTA_READY";
|
|
15184
|
+
var secondDelta = " IOS_STREAM_COMPLETED";
|
|
15185
|
+
var approvalPromptMarker = "IOS_PENDING_APPROVAL";
|
|
15186
|
+
var questionPromptMarker = "IOS_PENDING_QUESTION";
|
|
15187
|
+
var planPromptMarker = "IOS_PENDING_PLAN";
|
|
15188
|
+
var E2EFakeRuntime = class extends EventEmitter7 {
|
|
15189
|
+
provider = provider;
|
|
15190
|
+
displayName = "E2E Fake Runtime";
|
|
15191
|
+
description = "Deterministic runtime for live iOS and web end-to-end tests.";
|
|
15192
|
+
capabilities = {
|
|
15193
|
+
sessions: { list: true, read: true, resume: true, importLocal: false },
|
|
15194
|
+
turns: { start: true, streamInput: false, steer: false, interrupt: true, compact: false },
|
|
15195
|
+
branching: { fork: false, hardRollback: false, resumeAt: false, rewindFiles: false },
|
|
15196
|
+
controls: {
|
|
15197
|
+
planMode: false,
|
|
15198
|
+
permissionRequests: false,
|
|
15199
|
+
sandboxMode: true,
|
|
15200
|
+
performanceMode: false,
|
|
15201
|
+
goals: false
|
|
15202
|
+
},
|
|
15203
|
+
management: {
|
|
15204
|
+
models: true,
|
|
15205
|
+
mcpStatus: true,
|
|
15206
|
+
skills: false,
|
|
15207
|
+
hooks: false,
|
|
15208
|
+
hookTrust: false,
|
|
15209
|
+
hostConfigFiles: false,
|
|
15210
|
+
providerSettings: false
|
|
15211
|
+
},
|
|
15212
|
+
usage: { contextWindow: true, tokenUsage: true, costUsd: true }
|
|
15213
|
+
};
|
|
15214
|
+
managementSchema = {
|
|
15215
|
+
hostConfigFiles: [],
|
|
15216
|
+
toolboxItems: [],
|
|
15217
|
+
hookCommandTemplates: [],
|
|
15218
|
+
providerConfigFormat: "none",
|
|
15219
|
+
mcpConfigFormat: "none",
|
|
15220
|
+
configArchives: false,
|
|
15221
|
+
buildRestart: false
|
|
15222
|
+
};
|
|
15223
|
+
installation = {
|
|
15224
|
+
packageName: "remote-codex-e2e-fake-runtime",
|
|
15225
|
+
installed: true,
|
|
15226
|
+
installedVersion: "test",
|
|
15227
|
+
latestVersion: null,
|
|
15228
|
+
installCommand: "",
|
|
15229
|
+
updateCommand: "",
|
|
15230
|
+
busy: false,
|
|
15231
|
+
lastError: null
|
|
15232
|
+
};
|
|
15233
|
+
sessions = /* @__PURE__ */ new Map();
|
|
15234
|
+
providerRequests = /* @__PURE__ */ new Map();
|
|
15235
|
+
activeTurnId = null;
|
|
15236
|
+
startedAt = null;
|
|
15237
|
+
getStatus() {
|
|
15238
|
+
return {
|
|
15239
|
+
state: "ready",
|
|
15240
|
+
transport: "none",
|
|
15241
|
+
lastStartedAt: this.startedAt,
|
|
15242
|
+
lastError: null,
|
|
15243
|
+
restartCount: 0
|
|
15244
|
+
};
|
|
15245
|
+
}
|
|
15246
|
+
async start() {
|
|
15247
|
+
this.startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15248
|
+
}
|
|
15249
|
+
async stop() {
|
|
15250
|
+
this.activeTurnId = null;
|
|
15251
|
+
}
|
|
15252
|
+
async listModels() {
|
|
15253
|
+
return [
|
|
15254
|
+
{
|
|
15255
|
+
id: "ios-e2e-stream",
|
|
15256
|
+
model: "ios-e2e-stream",
|
|
15257
|
+
displayName: "iOS E2E Stream",
|
|
15258
|
+
description: "Deterministic streaming test model.",
|
|
15259
|
+
isDefault: true,
|
|
15260
|
+
hidden: false,
|
|
15261
|
+
supportedReasoningEfforts: [
|
|
15262
|
+
{ reasoningEffort: "low", description: "Low" },
|
|
15263
|
+
{ reasoningEffort: "medium", description: "Medium" },
|
|
15264
|
+
{ reasoningEffort: "high", description: "High" }
|
|
15265
|
+
],
|
|
15266
|
+
defaultReasoningEffort: "medium"
|
|
15267
|
+
}
|
|
15268
|
+
];
|
|
15269
|
+
}
|
|
15270
|
+
async listSessions() {
|
|
15271
|
+
return [...this.sessions.values()].map((session) => ({
|
|
15272
|
+
provider,
|
|
15273
|
+
providerSessionId: session.providerSessionId,
|
|
15274
|
+
cwd: session.cwd,
|
|
15275
|
+
title: session.title,
|
|
15276
|
+
preview: session.preview,
|
|
15277
|
+
createdAt: session.createdAt,
|
|
15278
|
+
updatedAt: session.updatedAt,
|
|
15279
|
+
status: session.status,
|
|
15280
|
+
rawSession: session
|
|
15281
|
+
}));
|
|
15282
|
+
}
|
|
15283
|
+
async listLoadedSessions() {
|
|
15284
|
+
return [...this.sessions.keys()];
|
|
15285
|
+
}
|
|
15286
|
+
async readSession(providerSessionId) {
|
|
15287
|
+
const session = this.sessions.get(providerSessionId);
|
|
15288
|
+
if (!session) {
|
|
15289
|
+
throw new Error(`E2E fake session missing: ${providerSessionId}`);
|
|
15290
|
+
}
|
|
15291
|
+
return session;
|
|
15292
|
+
}
|
|
15293
|
+
async startSession(input) {
|
|
15294
|
+
const providerSessionId = `e2e-session-${this.sessions.size + 1}`;
|
|
15295
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15296
|
+
const session = {
|
|
15297
|
+
provider,
|
|
15298
|
+
providerSessionId,
|
|
15299
|
+
cwd: input.cwd,
|
|
15300
|
+
title: null,
|
|
15301
|
+
preview: null,
|
|
15302
|
+
createdAt: now,
|
|
15303
|
+
updatedAt: now,
|
|
15304
|
+
status: "idle",
|
|
15305
|
+
turns: [],
|
|
15306
|
+
totalTurnCount: 0,
|
|
15307
|
+
rawSession: null
|
|
15308
|
+
};
|
|
15309
|
+
this.sessions.set(providerSessionId, session);
|
|
15310
|
+
return {
|
|
15311
|
+
provider,
|
|
15312
|
+
providerSessionId,
|
|
15313
|
+
model: input.model,
|
|
15314
|
+
reasoningEffort: input.reasoningEffort ?? null,
|
|
15315
|
+
sandboxMode: input.sandboxMode ?? null,
|
|
15316
|
+
session,
|
|
15317
|
+
rawSession: session
|
|
15318
|
+
};
|
|
15319
|
+
}
|
|
15320
|
+
async resumeSession(input) {
|
|
15321
|
+
const session = await this.readSession(input.providerSessionId);
|
|
15322
|
+
return {
|
|
15323
|
+
provider,
|
|
15324
|
+
providerSessionId: input.providerSessionId,
|
|
15325
|
+
model: input.model ?? null,
|
|
15326
|
+
reasoningEffort: null,
|
|
15327
|
+
sandboxMode: input.sandboxMode ?? null,
|
|
15328
|
+
session,
|
|
15329
|
+
rawSession: session
|
|
15330
|
+
};
|
|
15331
|
+
}
|
|
15332
|
+
async startTurn(input) {
|
|
15333
|
+
const session = await this.readSession(input.providerSessionId);
|
|
15334
|
+
const providerTurnId = `e2e-turn-${session.turns.length + 1}`;
|
|
15335
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
15336
|
+
const userItem = {
|
|
15337
|
+
id: `${providerTurnId}:user`,
|
|
15338
|
+
createdAt: now,
|
|
15339
|
+
kind: "userMessage",
|
|
15340
|
+
text: input.prompt
|
|
15341
|
+
};
|
|
15342
|
+
const assistantItem = {
|
|
15343
|
+
id: `${providerTurnId}:assistant`,
|
|
15344
|
+
createdAt: now,
|
|
15345
|
+
kind: "agentMessage",
|
|
15346
|
+
text: "",
|
|
15347
|
+
status: "running"
|
|
15348
|
+
};
|
|
15349
|
+
const turn = {
|
|
15350
|
+
providerTurnId,
|
|
15351
|
+
startedAt: now,
|
|
15352
|
+
status: "inProgress",
|
|
15353
|
+
error: null,
|
|
15354
|
+
items: input.hidden ? [] : [userItem],
|
|
15355
|
+
rawTurn: null
|
|
15356
|
+
};
|
|
15357
|
+
session.turns.push(turn);
|
|
15358
|
+
session.totalTurnCount = session.turns.length;
|
|
15359
|
+
session.status = "running";
|
|
15360
|
+
session.updatedAt = now;
|
|
15361
|
+
session.preview = input.prompt;
|
|
15362
|
+
this.activeTurnId = providerTurnId;
|
|
15363
|
+
this.emitRuntimeEvent({
|
|
15364
|
+
type: "turn.started",
|
|
15365
|
+
provider,
|
|
15366
|
+
providerSessionId: input.providerSessionId,
|
|
15367
|
+
turn
|
|
15368
|
+
});
|
|
15369
|
+
if (input.prompt.includes(approvalPromptMarker)) {
|
|
15370
|
+
setTimeout(() => {
|
|
15371
|
+
if (turn.status !== "inProgress") {
|
|
15372
|
+
return;
|
|
15373
|
+
}
|
|
15374
|
+
const requestId = `${providerTurnId}:approval`;
|
|
15375
|
+
this.providerRequests.set(requestId, {
|
|
15376
|
+
providerSessionId: input.providerSessionId,
|
|
15377
|
+
providerTurnId,
|
|
15378
|
+
assistantText: "IOS_PENDING_APPROVAL_RESOLVED"
|
|
15379
|
+
});
|
|
15380
|
+
this.emit("provider-request", {
|
|
15381
|
+
provider,
|
|
15382
|
+
id: requestId,
|
|
15383
|
+
method: "item/commandExecution/requestApproval",
|
|
15384
|
+
params: {
|
|
15385
|
+
providerSessionId: input.providerSessionId,
|
|
15386
|
+
providerTurnId,
|
|
15387
|
+
itemId: `${providerTurnId}:approval-item`,
|
|
15388
|
+
command: "printf ios-e2e-approval",
|
|
15389
|
+
cwd: session.cwd,
|
|
15390
|
+
reason: "iOS E2E approval request."
|
|
15391
|
+
}
|
|
15392
|
+
});
|
|
15393
|
+
}, 250);
|
|
15394
|
+
return turn;
|
|
15395
|
+
}
|
|
15396
|
+
if (input.prompt.includes(questionPromptMarker)) {
|
|
15397
|
+
setTimeout(() => {
|
|
15398
|
+
if (turn.status !== "inProgress") {
|
|
15399
|
+
return;
|
|
15400
|
+
}
|
|
15401
|
+
const requestId = `${providerTurnId}:question`;
|
|
15402
|
+
this.providerRequests.set(requestId, {
|
|
15403
|
+
providerSessionId: input.providerSessionId,
|
|
15404
|
+
providerTurnId,
|
|
15405
|
+
assistantText: "IOS_PENDING_QUESTION_RESOLVED"
|
|
15406
|
+
});
|
|
15407
|
+
this.emit("provider-request", {
|
|
15408
|
+
provider,
|
|
15409
|
+
id: requestId,
|
|
15410
|
+
method: "tool/AskUserQuestion",
|
|
15411
|
+
params: {
|
|
15412
|
+
providerSessionId: input.providerSessionId,
|
|
15413
|
+
providerTurnId,
|
|
15414
|
+
toolUseId: `${providerTurnId}:question-item`
|
|
15415
|
+
}
|
|
15416
|
+
});
|
|
15417
|
+
}, 250);
|
|
15418
|
+
return turn;
|
|
15419
|
+
}
|
|
15420
|
+
if (input.prompt.includes(planPromptMarker)) {
|
|
15421
|
+
const planItem = {
|
|
15422
|
+
id: `${providerTurnId}:plan`,
|
|
15423
|
+
createdAt: now,
|
|
15424
|
+
kind: "plan",
|
|
15425
|
+
text: "1. Verify the iOS pending request path.\n2. Keep plan mode active until the user decides.",
|
|
15426
|
+
status: "completed"
|
|
15427
|
+
};
|
|
15428
|
+
setTimeout(() => {
|
|
15429
|
+
if (turn.status !== "inProgress") {
|
|
15430
|
+
return;
|
|
15431
|
+
}
|
|
15432
|
+
turn.items.push(planItem);
|
|
15433
|
+
this.emitRuntimeEvent({
|
|
15434
|
+
type: "item.started",
|
|
15435
|
+
provider,
|
|
15436
|
+
providerSessionId: input.providerSessionId,
|
|
15437
|
+
providerTurnId,
|
|
15438
|
+
item: { ...planItem }
|
|
15439
|
+
});
|
|
15440
|
+
this.completeTurn(input.providerSessionId, providerTurnId);
|
|
15441
|
+
}, 250);
|
|
15442
|
+
return turn;
|
|
15443
|
+
}
|
|
15444
|
+
setTimeout(() => {
|
|
15445
|
+
if (turn.status !== "inProgress") {
|
|
15446
|
+
return;
|
|
15447
|
+
}
|
|
15448
|
+
assistantItem.text = firstDelta;
|
|
15449
|
+
turn.items.push(assistantItem);
|
|
15450
|
+
this.emitRuntimeEvent({
|
|
15451
|
+
type: "item.started",
|
|
15452
|
+
provider,
|
|
15453
|
+
providerSessionId: input.providerSessionId,
|
|
15454
|
+
providerTurnId,
|
|
15455
|
+
item: { ...assistantItem }
|
|
15456
|
+
});
|
|
15457
|
+
this.emitRuntimeEvent({
|
|
15458
|
+
type: "output.delta",
|
|
15459
|
+
provider,
|
|
15460
|
+
providerSessionId: input.providerSessionId,
|
|
15461
|
+
providerTurnId,
|
|
15462
|
+
itemId: assistantItem.id,
|
|
15463
|
+
delta: firstDelta
|
|
15464
|
+
});
|
|
15465
|
+
}, 250);
|
|
15466
|
+
setTimeout(() => {
|
|
15467
|
+
if (turn.status !== "inProgress") {
|
|
15468
|
+
return;
|
|
15469
|
+
}
|
|
15470
|
+
assistantItem.text = `${firstDelta}${secondDelta}`;
|
|
15471
|
+
assistantItem.status = "completed";
|
|
15472
|
+
turn.status = "completed";
|
|
15473
|
+
session.status = "idle";
|
|
15474
|
+
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15475
|
+
this.activeTurnId = null;
|
|
15476
|
+
this.emitRuntimeEvent({
|
|
15477
|
+
type: "output.delta",
|
|
15478
|
+
provider,
|
|
15479
|
+
providerSessionId: input.providerSessionId,
|
|
15480
|
+
providerTurnId,
|
|
15481
|
+
itemId: assistantItem.id,
|
|
15482
|
+
delta: secondDelta
|
|
15483
|
+
});
|
|
15484
|
+
this.emitRuntimeEvent({
|
|
15485
|
+
type: "item.completed",
|
|
15486
|
+
provider,
|
|
15487
|
+
providerSessionId: input.providerSessionId,
|
|
15488
|
+
providerTurnId,
|
|
15489
|
+
item: { ...assistantItem }
|
|
15490
|
+
});
|
|
15491
|
+
this.emitRuntimeEvent({
|
|
15492
|
+
type: "turn.completed",
|
|
15493
|
+
provider,
|
|
15494
|
+
providerSessionId: input.providerSessionId,
|
|
15495
|
+
turn
|
|
15496
|
+
});
|
|
15497
|
+
}, 2e4);
|
|
15498
|
+
return turn;
|
|
15499
|
+
}
|
|
15500
|
+
async interruptTurn(input) {
|
|
15501
|
+
const session = await this.readSession(input.providerSessionId);
|
|
15502
|
+
const turn = session.turns.find((entry) => entry.providerTurnId === input.providerTurnId);
|
|
15503
|
+
if (!turn) {
|
|
15504
|
+
return null;
|
|
15505
|
+
}
|
|
15506
|
+
turn.status = "interrupted";
|
|
15507
|
+
session.status = "interrupted";
|
|
15508
|
+
this.activeTurnId = null;
|
|
15509
|
+
return turn;
|
|
15510
|
+
}
|
|
15511
|
+
async listMcpServers() {
|
|
15512
|
+
return [];
|
|
15513
|
+
}
|
|
15514
|
+
mapProviderRequest(request) {
|
|
15515
|
+
if (request.provider !== provider || !isRecord11(request.params)) {
|
|
15516
|
+
return null;
|
|
15517
|
+
}
|
|
15518
|
+
const providerSessionId = stringValue4(request.params.providerSessionId);
|
|
15519
|
+
const providerTurnId = stringValue4(request.params.providerTurnId);
|
|
15520
|
+
if (!providerSessionId) {
|
|
15521
|
+
return null;
|
|
15522
|
+
}
|
|
15523
|
+
if (request.method === "item/commandExecution/requestApproval") {
|
|
15524
|
+
const requestId = String(request.id);
|
|
15525
|
+
const description = [
|
|
15526
|
+
stringValue4(request.params.reason),
|
|
15527
|
+
stringValue4(request.params.command) ? `Command: ${stringValue4(request.params.command)}` : null,
|
|
15528
|
+
stringValue4(request.params.cwd) ? `CWD: ${stringValue4(request.params.cwd)}` : null
|
|
15529
|
+
].filter(Boolean).join("\n");
|
|
15530
|
+
return {
|
|
15531
|
+
providerRequestId: request.id,
|
|
15532
|
+
providerSessionId,
|
|
15533
|
+
autoApprovedResult: null,
|
|
15534
|
+
pendingRequest: {
|
|
15535
|
+
providerRequestId: request.id,
|
|
15536
|
+
responseKind: "commandExecutionApproval",
|
|
15537
|
+
request: {
|
|
15538
|
+
id: requestId,
|
|
15539
|
+
kind: "requestUserInput",
|
|
15540
|
+
title: "Command approval required",
|
|
15541
|
+
description: description || "iOS E2E approval request.",
|
|
15542
|
+
turnId: providerTurnId,
|
|
15543
|
+
itemId: stringValue4(request.params.itemId),
|
|
15544
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15545
|
+
questions: [
|
|
15546
|
+
{
|
|
15547
|
+
id: "approval",
|
|
15548
|
+
header: "Command approval required",
|
|
15549
|
+
question: description || "iOS E2E approval request.",
|
|
15550
|
+
isOther: false,
|
|
15551
|
+
isSecret: false,
|
|
15552
|
+
options: [
|
|
15553
|
+
{ label: "Allow", description: "Permit this action and continue the current turn." },
|
|
15554
|
+
{ label: "Deny", description: "Decline this action." }
|
|
15555
|
+
]
|
|
15556
|
+
}
|
|
15557
|
+
]
|
|
15558
|
+
}
|
|
15559
|
+
}
|
|
15560
|
+
};
|
|
15561
|
+
}
|
|
15562
|
+
if (request.method === "tool/AskUserQuestion") {
|
|
15563
|
+
const requestId = String(request.id);
|
|
15564
|
+
return {
|
|
15565
|
+
providerRequestId: request.id,
|
|
15566
|
+
providerSessionId,
|
|
15567
|
+
autoApprovedResult: null,
|
|
15568
|
+
pendingRequest: {
|
|
15569
|
+
providerRequestId: request.id,
|
|
15570
|
+
responseKind: "askUserQuestion",
|
|
15571
|
+
request: {
|
|
15572
|
+
id: requestId,
|
|
15573
|
+
kind: "requestUserInput",
|
|
15574
|
+
title: "Mode",
|
|
15575
|
+
description: "Which iOS E2E path should continue?",
|
|
15576
|
+
turnId: providerTurnId,
|
|
15577
|
+
itemId: stringValue4(request.params.toolUseId),
|
|
15578
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15579
|
+
questions: [
|
|
15580
|
+
{
|
|
15581
|
+
id: "question-1",
|
|
15582
|
+
header: "Mode",
|
|
15583
|
+
question: "Which iOS E2E path should continue?",
|
|
15584
|
+
isOther: true,
|
|
15585
|
+
isSecret: false,
|
|
15586
|
+
options: [
|
|
15587
|
+
{ label: "Short", description: "Keep the response concise." },
|
|
15588
|
+
{ label: "Detailed", description: "Include more context." }
|
|
15589
|
+
]
|
|
15590
|
+
}
|
|
15591
|
+
]
|
|
15592
|
+
},
|
|
15593
|
+
responsePayload: {
|
|
15594
|
+
continueAsPrompt: false
|
|
15595
|
+
}
|
|
15596
|
+
}
|
|
15597
|
+
};
|
|
15598
|
+
}
|
|
15599
|
+
return null;
|
|
15600
|
+
}
|
|
15601
|
+
buildProviderRequestResponse(pending, input) {
|
|
15602
|
+
if (pending.responseKind === "commandExecutionApproval") {
|
|
15603
|
+
const answer = input.answers.approval?.answers[0]?.trim().toLowerCase();
|
|
15604
|
+
return { decision: answer === "allow" ? "accept" : "deny" };
|
|
15605
|
+
}
|
|
15606
|
+
return {
|
|
15607
|
+
kind: pending.responseKind,
|
|
15608
|
+
answers: input.answers
|
|
15609
|
+
};
|
|
15610
|
+
}
|
|
15611
|
+
respondToProviderRequest(id, result) {
|
|
15612
|
+
void result;
|
|
15613
|
+
const request = this.providerRequests.get(id);
|
|
15614
|
+
if (!request) {
|
|
15615
|
+
return;
|
|
15616
|
+
}
|
|
15617
|
+
this.providerRequests.delete(id);
|
|
15618
|
+
const session = this.sessions.get(request.providerSessionId);
|
|
15619
|
+
const turn = session?.turns.find((entry) => entry.providerTurnId === request.providerTurnId);
|
|
15620
|
+
if (!session || !turn || turn.status !== "inProgress") {
|
|
15621
|
+
return;
|
|
15622
|
+
}
|
|
15623
|
+
const assistantItem = {
|
|
15624
|
+
id: `${request.providerTurnId}:assistant`,
|
|
15625
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15626
|
+
kind: "agentMessage",
|
|
15627
|
+
text: request.assistantText,
|
|
15628
|
+
status: "completed"
|
|
15629
|
+
};
|
|
15630
|
+
turn.items.push(assistantItem);
|
|
15631
|
+
this.emitRuntimeEvent({
|
|
15632
|
+
type: "item.started",
|
|
15633
|
+
provider,
|
|
15634
|
+
providerSessionId: request.providerSessionId,
|
|
15635
|
+
providerTurnId: request.providerTurnId,
|
|
15636
|
+
item: { ...assistantItem }
|
|
15637
|
+
});
|
|
15638
|
+
this.completeTurn(request.providerSessionId, request.providerTurnId);
|
|
15639
|
+
}
|
|
15640
|
+
completeTurn(providerSessionId, providerTurnId) {
|
|
15641
|
+
const session = this.sessions.get(providerSessionId);
|
|
15642
|
+
const turn = session?.turns.find((entry) => entry.providerTurnId === providerTurnId);
|
|
15643
|
+
if (!session || !turn || turn.status !== "inProgress") {
|
|
15644
|
+
return;
|
|
15645
|
+
}
|
|
15646
|
+
turn.status = "completed";
|
|
15647
|
+
session.status = "idle";
|
|
15648
|
+
session.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
15649
|
+
this.activeTurnId = null;
|
|
15650
|
+
this.emitRuntimeEvent({
|
|
15651
|
+
type: "turn.completed",
|
|
15652
|
+
provider,
|
|
15653
|
+
providerSessionId,
|
|
15654
|
+
turn
|
|
15655
|
+
});
|
|
15656
|
+
}
|
|
15657
|
+
emitRuntimeEvent(event) {
|
|
15658
|
+
this.emit("event", event);
|
|
15659
|
+
}
|
|
15660
|
+
};
|
|
15661
|
+
function isE2EFakeRuntimeEnabled(env = process.env) {
|
|
15662
|
+
const value = env.REMOTE_CODEX_E2E_FAKE_RUNTIME;
|
|
15663
|
+
return value ? ["1", "true", "yes", "on"].includes(value.toLowerCase()) : false;
|
|
15664
|
+
}
|
|
15665
|
+
function isRecord11(value) {
|
|
15666
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
15667
|
+
}
|
|
15668
|
+
function stringValue4(value) {
|
|
15669
|
+
return typeof value === "string" ? value : null;
|
|
15670
|
+
}
|
|
15671
|
+
|
|
15077
15672
|
// src/agent-runtime-bootstrap.ts
|
|
15078
15673
|
function createAgentRuntimeBootstrap(config) {
|
|
15079
15674
|
const runtimes = [];
|
|
@@ -15104,6 +15699,10 @@ function createAgentRuntimeBootstrap(config) {
|
|
|
15104
15699
|
runtimes.push(createOpenCodeRuntime(config));
|
|
15105
15700
|
providerHostHomes.opencode = opencodeConfig.home;
|
|
15106
15701
|
}
|
|
15702
|
+
if (isE2EFakeRuntimeEnabled()) {
|
|
15703
|
+
runtimes.push(new E2EFakeRuntime());
|
|
15704
|
+
providerHostHomes.claude = claudeConfig.home;
|
|
15705
|
+
}
|
|
15107
15706
|
return {
|
|
15108
15707
|
agentRuntimes: new AgentRuntimeRegistry(runtimes),
|
|
15109
15708
|
localCodexSessionStore: new LocalCodexSessionStore(codexConfig.home),
|
|
@@ -15137,8 +15736,8 @@ function createOpenCodeRuntime(config) {
|
|
|
15137
15736
|
}
|
|
15138
15737
|
|
|
15139
15738
|
// src/event-bus.ts
|
|
15140
|
-
import { EventEmitter as
|
|
15141
|
-
var SupervisorEventBus = class extends
|
|
15739
|
+
import { EventEmitter as EventEmitter8 } from "events";
|
|
15740
|
+
var SupervisorEventBus = class extends EventEmitter8 {
|
|
15142
15741
|
emitThreadEvent(event) {
|
|
15143
15742
|
this.emit("thread-event", event);
|
|
15144
15743
|
}
|
|
@@ -15475,8 +16074,8 @@ var ThreadGoalCoordinator = class {
|
|
|
15475
16074
|
normalizeThreadGoalStatusForThread(goal, record) {
|
|
15476
16075
|
return normalizeThreadGoalStatusForThread(goal, record);
|
|
15477
16076
|
}
|
|
15478
|
-
async ensureGoalsFeatureEnabled(
|
|
15479
|
-
await this.goalFeatureManagement.ensureGoalsFeatureEnabled(
|
|
16077
|
+
async ensureGoalsFeatureEnabled(provider2) {
|
|
16078
|
+
await this.goalFeatureManagement.ensureGoalsFeatureEnabled(provider2);
|
|
15480
16079
|
}
|
|
15481
16080
|
};
|
|
15482
16081
|
function toIsoFromEpoch2(value) {
|
|
@@ -15590,7 +16189,7 @@ var DEFERRED_FILE_CHANGE_DETAIL_TITLE = "File Change Details";
|
|
|
15590
16189
|
var DEFERRED_FILE_READ_DETAIL_TITLE = "File Read Details";
|
|
15591
16190
|
var DEFERRED_WEB_SEARCH_DETAIL_TITLE = "Web Search Details";
|
|
15592
16191
|
var DEFERRED_HOOK_DETAIL_TITLE = "Hook Details";
|
|
15593
|
-
function
|
|
16192
|
+
function parseUuidV7Timestamp2(id) {
|
|
15594
16193
|
const normalized = id.replace(/-/g, "");
|
|
15595
16194
|
if (!/^[0-9a-f]{32}$/i.test(normalized) || normalized[12]?.toLowerCase() !== "7") {
|
|
15596
16195
|
return null;
|
|
@@ -15955,7 +16554,7 @@ function mergePersistedHistoryItemsIntoTurns(turns, persistedItemsByTurnId, defe
|
|
|
15955
16554
|
function agentTurnToThreadTurnDto(turn, deferredDetails) {
|
|
15956
16555
|
const baseTurn = {
|
|
15957
16556
|
id: turn.providerTurnId,
|
|
15958
|
-
startedAt: turn.startedAt ??
|
|
16557
|
+
startedAt: turn.startedAt ?? parseUuidV7Timestamp2(turn.providerTurnId),
|
|
15959
16558
|
status: turn.status,
|
|
15960
16559
|
error: turn.error?.message ?? null,
|
|
15961
16560
|
items: visibleRuntimeTurnItems(turn.items).map(
|
|
@@ -16200,6 +16799,7 @@ var ThreadLiveStateStore = class {
|
|
|
16200
16799
|
sequence: input.sequence
|
|
16201
16800
|
} : {
|
|
16202
16801
|
id: input.itemId,
|
|
16802
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
16203
16803
|
kind: "agentMessage",
|
|
16204
16804
|
text: input.delta,
|
|
16205
16805
|
sequence: input.sequence
|
|
@@ -16310,7 +16910,7 @@ function agentMessageMatchScore(finalText, liveText) {
|
|
|
16310
16910
|
|
|
16311
16911
|
// src/thread-usage-accounting.ts
|
|
16312
16912
|
var CONTEXT_BASELINE_TOKENS = 12e3;
|
|
16313
|
-
function
|
|
16913
|
+
function isRecord12(value) {
|
|
16314
16914
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16315
16915
|
}
|
|
16316
16916
|
function numberOrNull2(value) {
|
|
@@ -16358,11 +16958,11 @@ function computeContextRemainingPercent(tokensInContextWindow, contextWindow) {
|
|
|
16358
16958
|
return clampPercentage(Math.round(remaining / effectiveWindow * 100));
|
|
16359
16959
|
}
|
|
16360
16960
|
function buildThreadContextUsageFromPayload(payload, model = null, timestamp = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
16361
|
-
const tokenUsage =
|
|
16961
|
+
const tokenUsage = isRecord12(payload) ? payload : null;
|
|
16362
16962
|
const modelContextWindow = numberOrNull2(
|
|
16363
16963
|
tokenUsage?.modelContextWindow ?? tokenUsage?.model_context_window
|
|
16364
16964
|
) ?? contextWindowForModel(model);
|
|
16365
|
-
const lastUsage =
|
|
16965
|
+
const lastUsage = isRecord12(tokenUsage?.last) ? tokenUsage.last : null;
|
|
16366
16966
|
const tokensInContextWindow = numberOrNull2(
|
|
16367
16967
|
lastUsage?.totalTokens ?? lastUsage?.total_tokens
|
|
16368
16968
|
);
|
|
@@ -16394,7 +16994,7 @@ function shouldResetThreadContextUsageForTurnStart(current) {
|
|
|
16394
16994
|
return current?.availability !== "available";
|
|
16395
16995
|
}
|
|
16396
16996
|
function buildTurnTokenBreakdown(payload) {
|
|
16397
|
-
const usage =
|
|
16997
|
+
const usage = isRecord12(payload) ? payload : null;
|
|
16398
16998
|
const totalTokens2 = numberOrNull2(usage?.totalTokens ?? usage?.total_tokens);
|
|
16399
16999
|
const inputTokens = numberOrNull2(usage?.inputTokens ?? usage?.input_tokens);
|
|
16400
17000
|
const cachedInputTokens = numberOrNull2(
|
|
@@ -16440,12 +17040,12 @@ function subtractTurnTokenBreakdowns(current, previous) {
|
|
|
16440
17040
|
};
|
|
16441
17041
|
}
|
|
16442
17042
|
function parseThreadTurnTokenUsage(payload) {
|
|
16443
|
-
const tokenUsage =
|
|
17043
|
+
const tokenUsage = isRecord12(payload) ? payload : null;
|
|
16444
17044
|
const total = buildTurnTokenBreakdown(
|
|
16445
|
-
|
|
17045
|
+
isRecord12(tokenUsage?.total) ? tokenUsage.total : null
|
|
16446
17046
|
);
|
|
16447
17047
|
const last = buildTurnTokenBreakdown(
|
|
16448
|
-
|
|
17048
|
+
isRecord12(tokenUsage?.last) ? tokenUsage.last : null
|
|
16449
17049
|
);
|
|
16450
17050
|
const modelContextWindow = numberOrNull2(
|
|
16451
17051
|
tokenUsage?.modelContextWindow ?? tokenUsage?.model_context_window
|
|
@@ -16469,7 +17069,7 @@ function parseStoredThreadTurnTokenUsageState(value) {
|
|
|
16469
17069
|
try {
|
|
16470
17070
|
const parsed = JSON.parse(value);
|
|
16471
17071
|
const baselineTotal = buildTurnTokenBreakdown(
|
|
16472
|
-
|
|
17072
|
+
isRecord12(parsed?.baselineTotal) ? parsed.baselineTotal : null
|
|
16473
17073
|
);
|
|
16474
17074
|
return {
|
|
16475
17075
|
baselineTotal,
|
|
@@ -16509,12 +17109,12 @@ function stringifyStoredThreadTurnTokenUsageState(state) {
|
|
|
16509
17109
|
});
|
|
16510
17110
|
}
|
|
16511
17111
|
function buildThreadTurnTokenUsage(payload, baselineTotal, previous = null) {
|
|
16512
|
-
const tokenUsage =
|
|
17112
|
+
const tokenUsage = isRecord12(payload) ? payload : null;
|
|
16513
17113
|
const cumulativeTotal = buildTurnTokenBreakdown(
|
|
16514
|
-
|
|
17114
|
+
isRecord12(tokenUsage?.total) ? tokenUsage.total : null
|
|
16515
17115
|
);
|
|
16516
17116
|
const last = buildTurnTokenBreakdown(
|
|
16517
|
-
|
|
17117
|
+
isRecord12(tokenUsage?.last) ? tokenUsage.last : null
|
|
16518
17118
|
);
|
|
16519
17119
|
const modelContextWindow = numberOrNull2(
|
|
16520
17120
|
tokenUsage?.modelContextWindow ?? tokenUsage?.model_context_window
|
|
@@ -16586,7 +17186,7 @@ var ThreadUsageAccounting = class {
|
|
|
16586
17186
|
input.localThreadId
|
|
16587
17187
|
);
|
|
16588
17188
|
const currentCumulativeTotal = buildTurnTokenBreakdown(
|
|
16589
|
-
|
|
17189
|
+
isRecord12(input.tokenUsage?.total) ? input.tokenUsage.total : null
|
|
16590
17190
|
);
|
|
16591
17191
|
if (currentCumulativeTotal) {
|
|
16592
17192
|
this.threadCumulativeTokenUsage.set(input.localThreadId, currentCumulativeTotal);
|
|
@@ -16976,10 +17576,10 @@ var ThreadRuntimeEventProjector = class {
|
|
|
16976
17576
|
}
|
|
16977
17577
|
}
|
|
16978
17578
|
}
|
|
16979
|
-
findRecordByProviderSessionId(
|
|
17579
|
+
findRecordByProviderSessionId(provider2, providerSessionId) {
|
|
16980
17580
|
return getThreadRecordByProviderSessionId(
|
|
16981
17581
|
this.input.db,
|
|
16982
|
-
|
|
17582
|
+
provider2 ?? "codex",
|
|
16983
17583
|
providerSessionId
|
|
16984
17584
|
);
|
|
16985
17585
|
}
|
|
@@ -17069,8 +17669,8 @@ var ProviderRequestCoordinator = class {
|
|
|
17069
17669
|
dismissedTurnId
|
|
17070
17670
|
};
|
|
17071
17671
|
}
|
|
17072
|
-
respondToProviderRequest(
|
|
17073
|
-
const runtime = this.callbacks.runtimeForProvider(
|
|
17672
|
+
respondToProviderRequest(provider2, pending, input) {
|
|
17673
|
+
const runtime = this.callbacks.runtimeForProvider(provider2);
|
|
17074
17674
|
if (!runtime.buildProviderRequestResponse) {
|
|
17075
17675
|
throw new HttpError(409, {
|
|
17076
17676
|
code: "conflict",
|
|
@@ -17099,7 +17699,7 @@ var ProviderRequestCoordinator = class {
|
|
|
17099
17699
|
const defaultMappedRequest = runtime.mapProviderRequest?.(request, {
|
|
17100
17700
|
approvalMode: "guarded"
|
|
17101
17701
|
});
|
|
17102
|
-
const providerSessionIdFromParams =
|
|
17702
|
+
const providerSessionIdFromParams = isRecord13(request.params) ? request.params.providerSessionId ?? request.params.threadId ?? request.params.conversationId ?? request.params.sessionId : null;
|
|
17103
17703
|
const providerSessionId = defaultMappedRequest?.providerSessionId ?? (typeof providerSessionIdFromParams === "string" ? providerSessionIdFromParams : null);
|
|
17104
17704
|
const record = providerSessionId ? this.callbacks.findRecordByProviderSessionId(request.provider, providerSessionId) : null;
|
|
17105
17705
|
if (!record) {
|
|
@@ -17312,7 +17912,7 @@ function buildRequestAnswerLines(request, input) {
|
|
|
17312
17912
|
return `- ${question.question}: ${answers.join(", ")}`;
|
|
17313
17913
|
}).filter((line) => Boolean(line));
|
|
17314
17914
|
}
|
|
17315
|
-
function
|
|
17915
|
+
function isRecord13(value) {
|
|
17316
17916
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17317
17917
|
}
|
|
17318
17918
|
|
|
@@ -17702,20 +18302,20 @@ var ThreadProviderRuntimeCoordinator = class {
|
|
|
17702
18302
|
this.agentRuntimes = agentRuntimes;
|
|
17703
18303
|
}
|
|
17704
18304
|
agentRuntimes;
|
|
17705
|
-
normalizeProvider(
|
|
17706
|
-
if (!
|
|
18305
|
+
normalizeProvider(provider2) {
|
|
18306
|
+
if (!provider2) {
|
|
17707
18307
|
return defaultAgentBackendId;
|
|
17708
18308
|
}
|
|
17709
|
-
if (isAgentBackendId(
|
|
17710
|
-
return
|
|
18309
|
+
if (isAgentBackendId(provider2)) {
|
|
18310
|
+
return provider2;
|
|
17711
18311
|
}
|
|
17712
18312
|
throw new HttpError(400, {
|
|
17713
18313
|
code: "bad_request",
|
|
17714
|
-
message: `Unsupported agent runtime provider: ${
|
|
18314
|
+
message: `Unsupported agent runtime provider: ${provider2}`
|
|
17715
18315
|
});
|
|
17716
18316
|
}
|
|
17717
|
-
runtimeForProvider(
|
|
17718
|
-
const normalizedProvider = this.normalizeProvider(
|
|
18317
|
+
runtimeForProvider(provider2) {
|
|
18318
|
+
const normalizedProvider = this.normalizeProvider(provider2);
|
|
17719
18319
|
const runtime = this.optionalRuntimeForProvider(normalizedProvider);
|
|
17720
18320
|
if (!runtime) {
|
|
17721
18321
|
throw new HttpError(501, {
|
|
@@ -17725,8 +18325,8 @@ var ThreadProviderRuntimeCoordinator = class {
|
|
|
17725
18325
|
}
|
|
17726
18326
|
return runtime;
|
|
17727
18327
|
}
|
|
17728
|
-
optionalRuntimeForProvider(
|
|
17729
|
-
return this.agentRuntimes.getOptional(this.normalizeProvider(
|
|
18328
|
+
optionalRuntimeForProvider(provider2) {
|
|
18329
|
+
return this.agentRuntimes.getOptional(this.normalizeProvider(provider2)) ?? null;
|
|
17730
18330
|
}
|
|
17731
18331
|
allRuntimes() {
|
|
17732
18332
|
return this.agentRuntimes.all();
|
|
@@ -17734,22 +18334,22 @@ var ThreadProviderRuntimeCoordinator = class {
|
|
|
17734
18334
|
providerForRecord(record) {
|
|
17735
18335
|
return this.normalizeProvider(record.provider);
|
|
17736
18336
|
}
|
|
17737
|
-
isCodexProvider(
|
|
17738
|
-
return this.providerForRecord({ provider }) === "codex";
|
|
18337
|
+
isCodexProvider(provider2) {
|
|
18338
|
+
return this.providerForRecord({ provider: provider2 }) === "codex";
|
|
17739
18339
|
}
|
|
17740
|
-
runtimeSupportsFastMode(
|
|
17741
|
-
return this.optionalRuntimeForProvider(
|
|
18340
|
+
runtimeSupportsFastMode(provider2) {
|
|
18341
|
+
return this.optionalRuntimeForProvider(provider2)?.capabilities.controls.performanceMode ?? false;
|
|
17742
18342
|
}
|
|
17743
|
-
fastModeForProvider(
|
|
17744
|
-
return this.runtimeSupportsFastMode(
|
|
18343
|
+
fastModeForProvider(provider2, fastMode) {
|
|
18344
|
+
return this.runtimeSupportsFastMode(provider2) ? normalizeFastMode(fastMode) : false;
|
|
17745
18345
|
}
|
|
17746
18346
|
performanceModeForRecord(record) {
|
|
17747
18347
|
return performanceModeForFastMode(
|
|
17748
18348
|
this.fastModeForProvider(record.provider, record.fastMode)
|
|
17749
18349
|
);
|
|
17750
18350
|
}
|
|
17751
|
-
async listLoadedProviderSessionIds(
|
|
17752
|
-
const runtime = this.optionalRuntimeForProvider(
|
|
18351
|
+
async listLoadedProviderSessionIds(provider2 = "codex") {
|
|
18352
|
+
const runtime = this.optionalRuntimeForProvider(provider2);
|
|
17753
18353
|
if (!runtime) {
|
|
17754
18354
|
return /* @__PURE__ */ new Set();
|
|
17755
18355
|
}
|
|
@@ -17757,11 +18357,11 @@ var ThreadProviderRuntimeCoordinator = class {
|
|
|
17757
18357
|
await runtime.listLoadedSessions().catch(() => [])
|
|
17758
18358
|
);
|
|
17759
18359
|
}
|
|
17760
|
-
async listProviderModels(
|
|
17761
|
-
return this.runtimeForProvider(
|
|
18360
|
+
async listProviderModels(provider2 = "codex") {
|
|
18361
|
+
return this.runtimeForProvider(provider2).listModels().catch(() => []);
|
|
17762
18362
|
}
|
|
17763
|
-
async listProviderModelOptions(
|
|
17764
|
-
const models = await this.runtimeForProvider(
|
|
18363
|
+
async listProviderModelOptions(provider2 = "codex") {
|
|
18364
|
+
const models = await this.runtimeForProvider(provider2).listModels();
|
|
17765
18365
|
return models.map((model) => this.modelOptionFromAgentModel(model));
|
|
17766
18366
|
}
|
|
17767
18367
|
normalizeReasoningForModel(modelRecords, model, requested) {
|
|
@@ -17946,15 +18546,15 @@ var ThreadManagementCoordinator = class {
|
|
|
17946
18546
|
});
|
|
17947
18547
|
}
|
|
17948
18548
|
}
|
|
17949
|
-
assertHookFileManagement(
|
|
17950
|
-
if (!this.hookFileManagement.canManageHookFiles(
|
|
18549
|
+
assertHookFileManagement(provider2) {
|
|
18550
|
+
if (!this.hookFileManagement.canManageHookFiles(provider2)) {
|
|
17951
18551
|
throw new HttpError(409, {
|
|
17952
18552
|
code: "conflict",
|
|
17953
18553
|
message: "This backend does not support hooks file editing."
|
|
17954
18554
|
});
|
|
17955
18555
|
}
|
|
17956
18556
|
}
|
|
17957
|
-
async toThreadHooksDto(
|
|
18557
|
+
async toThreadHooksDto(provider2, workspacePath, entry, fallbackWarnings = []) {
|
|
17958
18558
|
const { globalHooksPath, projectHooksPath } = this.hookFileManagement.hooksPaths(workspacePath);
|
|
17959
18559
|
const officialHooks = (entry?.hooks ?? []).map((hook) => ({
|
|
17960
18560
|
key: hook.key,
|
|
@@ -17973,7 +18573,7 @@ var ThreadManagementCoordinator = class {
|
|
|
17973
18573
|
currentHash: hook.currentHash,
|
|
17974
18574
|
trustStatus: hook.trustStatus
|
|
17975
18575
|
}));
|
|
17976
|
-
const [globalHooks, projectHooks] = this.hookFileManagement.canManageHookFiles(
|
|
18576
|
+
const [globalHooks, projectHooks] = this.hookFileManagement.canManageHookFiles(provider2) ? await Promise.all([
|
|
17977
18577
|
this.hookFileManagement.readLocalHookDtos({
|
|
17978
18578
|
hooksPath: globalHooksPath,
|
|
17979
18579
|
source: "user",
|
|
@@ -18125,7 +18725,8 @@ var ThreadPromptTurnCoordinator = class {
|
|
|
18125
18725
|
await runtime.sendInput({
|
|
18126
18726
|
providerSessionId: record.providerSessionId,
|
|
18127
18727
|
providerTurnId: steerTurnId,
|
|
18128
|
-
prompt: input.prompt
|
|
18728
|
+
prompt: input.prompt,
|
|
18729
|
+
workspacePath: input.workspacePath
|
|
18129
18730
|
});
|
|
18130
18731
|
updateThreadRecord(this.db, localThreadId, {
|
|
18131
18732
|
providerTurnId: steerTurnId,
|
|
@@ -18256,9 +18857,9 @@ var ThreadSessionCoordinator = class {
|
|
|
18256
18857
|
performanceModeSettings;
|
|
18257
18858
|
localSessionLookup;
|
|
18258
18859
|
async startThreadSession(input) {
|
|
18259
|
-
const
|
|
18860
|
+
const provider2 = this.providerRuntime.normalizeProvider(input.threadInput.provider);
|
|
18260
18861
|
const normalizedTitle = input.threadInput.title?.trim() || input.defaultTitle;
|
|
18261
|
-
const runtime = this.providerRuntime.runtimeForProvider(
|
|
18862
|
+
const runtime = this.providerRuntime.runtimeForProvider(provider2);
|
|
18262
18863
|
const modelRecords = await runtime.listModels().catch(() => []);
|
|
18263
18864
|
const reasoningEffort = this.providerRuntime.normalizeReasoningForModel(
|
|
18264
18865
|
modelRecords,
|
|
@@ -18266,8 +18867,8 @@ var ThreadSessionCoordinator = class {
|
|
|
18266
18867
|
input.threadInput.reasoningEffort ?? null
|
|
18267
18868
|
);
|
|
18268
18869
|
const sandboxMode = defaultSandboxModeForApprovalMode(input.threadInput.approvalMode);
|
|
18269
|
-
const fastMode = this.providerRuntime.runtimeSupportsFastMode(
|
|
18270
|
-
if (this.providerRuntime.runtimeSupportsFastMode(
|
|
18870
|
+
const fastMode = this.providerRuntime.runtimeSupportsFastMode(provider2) ? this.performanceModeSettings.readFastMode() : false;
|
|
18871
|
+
if (this.providerRuntime.runtimeSupportsFastMode(provider2)) {
|
|
18271
18872
|
ensureFastModeSupported(input.threadInput.model, fastMode, modelRecords);
|
|
18272
18873
|
}
|
|
18273
18874
|
const response = await runtime.startSession({
|
|
@@ -18279,7 +18880,7 @@ var ThreadSessionCoordinator = class {
|
|
|
18279
18880
|
performanceMode: performanceModeForFastMode(fastMode)
|
|
18280
18881
|
});
|
|
18281
18882
|
return {
|
|
18282
|
-
provider,
|
|
18883
|
+
provider: provider2,
|
|
18283
18884
|
normalizedTitle,
|
|
18284
18885
|
response,
|
|
18285
18886
|
reasoningEffort,
|
|
@@ -18308,30 +18909,30 @@ var ThreadSessionCoordinator = class {
|
|
|
18308
18909
|
return this.localSessionLookup.findSession(providerSessionId);
|
|
18309
18910
|
}
|
|
18310
18911
|
async resolveLocalImportSession(input) {
|
|
18311
|
-
const
|
|
18312
|
-
if (
|
|
18313
|
-
return this.resolveRuntimeImportSession(
|
|
18912
|
+
const provider2 = normalizeAgentBackendId(input.provider) ?? "codex";
|
|
18913
|
+
if (provider2 !== "codex") {
|
|
18914
|
+
return this.resolveRuntimeImportSession(provider2, input.sessionId);
|
|
18314
18915
|
}
|
|
18315
18916
|
return this.localSessionLookup.findImportSession(input.sessionId, {
|
|
18316
18917
|
fastMode: this.performanceModeSettings.readFastMode(),
|
|
18317
|
-
provider
|
|
18918
|
+
provider: provider2
|
|
18318
18919
|
});
|
|
18319
18920
|
}
|
|
18320
|
-
async resolveRuntimeImportSession(
|
|
18921
|
+
async resolveRuntimeImportSession(provider2, sessionId) {
|
|
18321
18922
|
try {
|
|
18322
|
-
const session = await this.providerRuntime.runtimeForProvider(
|
|
18923
|
+
const session = await this.providerRuntime.runtimeForProvider(provider2).readSession(sessionId);
|
|
18323
18924
|
if (!session.cwd) {
|
|
18324
18925
|
return null;
|
|
18325
18926
|
}
|
|
18326
18927
|
return {
|
|
18327
|
-
provider,
|
|
18928
|
+
provider: provider2,
|
|
18328
18929
|
source: "supervisor",
|
|
18329
18930
|
sessionId,
|
|
18330
18931
|
cwd: session.cwd,
|
|
18331
18932
|
title: session.title?.trim() || session.preview?.trim() || "Untitled imported session",
|
|
18332
18933
|
model: null,
|
|
18333
18934
|
summaryText: session.preview,
|
|
18334
|
-
fastMode: this.providerRuntime.runtimeSupportsFastMode(
|
|
18935
|
+
fastMode: this.providerRuntime.runtimeSupportsFastMode(provider2) ? this.performanceModeSettings.readFastMode() : false
|
|
18335
18936
|
};
|
|
18336
18937
|
} catch {
|
|
18337
18938
|
return null;
|
|
@@ -18703,9 +19304,9 @@ var ThreadHistoryPersistenceCoordinator = class {
|
|
|
18703
19304
|
|
|
18704
19305
|
// src/thread-deletion-coordinator.ts
|
|
18705
19306
|
import fs10 from "fs/promises";
|
|
18706
|
-
import
|
|
19307
|
+
import path13 from "path";
|
|
18707
19308
|
function threadTempDirectoryPath(workspacePath, localThreadId) {
|
|
18708
|
-
return
|
|
19309
|
+
return path13.join(workspacePath, ".temp", "threads", localThreadId);
|
|
18709
19310
|
}
|
|
18710
19311
|
var ThreadDeletionCoordinator = class {
|
|
18711
19312
|
constructor(db, requestCoordinator, usageAccounting, liveState, auxiliaryState, callbacks) {
|
|
@@ -18756,7 +19357,11 @@ var ThreadDeletionCoordinator = class {
|
|
|
18756
19357
|
};
|
|
18757
19358
|
|
|
18758
19359
|
// src/exports/thread-pdf-export.ts
|
|
19360
|
+
import { spawn as spawn2 } from "child_process";
|
|
18759
19361
|
import fs11 from "fs";
|
|
19362
|
+
import os3 from "os";
|
|
19363
|
+
import path14 from "path";
|
|
19364
|
+
import { pathToFileURL as pathToFileURL3 } from "url";
|
|
18760
19365
|
import puppeteer from "puppeteer-core";
|
|
18761
19366
|
import { marked } from "marked";
|
|
18762
19367
|
var MAX_TEXT_CHARS = 12e3;
|
|
@@ -18770,6 +19375,8 @@ var EMBEDDED_CJK_FONT_CANDIDATES = [
|
|
|
18770
19375
|
{ path: "/mnt/c/Windows/Fonts/msyh.ttc", format: "truetype", weight: 400 }
|
|
18771
19376
|
];
|
|
18772
19377
|
var PUPPETEER_CHANNEL = "chrome";
|
|
19378
|
+
var PDF_EXPORT_TIMEOUT_MS = 45e3;
|
|
19379
|
+
var MAX_CHROME_STDERR_CHARS = 4e3;
|
|
18773
19380
|
var embeddedCjkFontCss = null;
|
|
18774
19381
|
function escapeHtml(value) {
|
|
18775
19382
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
@@ -19796,35 +20403,15 @@ endobj
|
|
|
19796
20403
|
`
|
|
19797
20404
|
);
|
|
19798
20405
|
}
|
|
19799
|
-
|
|
19800
|
-
try {
|
|
19801
|
-
const page = await browser.newPage();
|
|
19802
|
-
await page.setContent(renderThreadExportHtml(snapshot), {
|
|
19803
|
-
waitUntil: "load"
|
|
19804
|
-
});
|
|
19805
|
-
return Buffer.from(
|
|
19806
|
-
await page.pdf({
|
|
19807
|
-
format: "Letter",
|
|
19808
|
-
printBackground: true,
|
|
19809
|
-
preferCSSPageSize: true
|
|
19810
|
-
})
|
|
19811
|
-
);
|
|
19812
|
-
} finally {
|
|
19813
|
-
await browser.close();
|
|
19814
|
-
}
|
|
20406
|
+
return renderPdfWithChromeCli(renderThreadExportHtml(snapshot));
|
|
19815
20407
|
}
|
|
19816
|
-
|
|
19817
|
-
const launchOptions = {
|
|
19818
|
-
headless: true,
|
|
19819
|
-
args: ["--no-sandbox", "--disable-setuid-sandbox", "--font-render-hinting=none"]
|
|
19820
|
-
};
|
|
19821
|
-
if (process.env.PUPPETEER_EXECUTABLE_PATH) {
|
|
19822
|
-
launchOptions.executablePath = process.env.PUPPETEER_EXECUTABLE_PATH;
|
|
19823
|
-
} else {
|
|
19824
|
-
launchOptions.channel = PUPPETEER_CHANNEL;
|
|
19825
|
-
}
|
|
20408
|
+
function resolvePdfBrowserExecutablePath() {
|
|
19826
20409
|
try {
|
|
19827
|
-
|
|
20410
|
+
const executablePath = process.env.PUPPETEER_EXECUTABLE_PATH ? process.env.PUPPETEER_EXECUTABLE_PATH : puppeteer.executablePath(PUPPETEER_CHANNEL);
|
|
20411
|
+
if (!fs11.existsSync(executablePath)) {
|
|
20412
|
+
throw new Error(`Browser executable was not found at ${executablePath}`);
|
|
20413
|
+
}
|
|
20414
|
+
return executablePath;
|
|
19828
20415
|
} catch (error) {
|
|
19829
20416
|
const detail = error instanceof Error ? error.message : String(error);
|
|
19830
20417
|
throw new Error(
|
|
@@ -19832,6 +20419,89 @@ async function launchPdfBrowser() {
|
|
|
19832
20419
|
);
|
|
19833
20420
|
}
|
|
19834
20421
|
}
|
|
20422
|
+
async function renderPdfWithChromeCli(html) {
|
|
20423
|
+
const executablePath = resolvePdfBrowserExecutablePath();
|
|
20424
|
+
const tempDir = await fs11.promises.mkdtemp(path14.join(os3.tmpdir(), "remote-codex-pdf-"));
|
|
20425
|
+
const htmlPath = path14.join(tempDir, "thread-export.html");
|
|
20426
|
+
const pdfPath = path14.join(tempDir, "thread-export.pdf");
|
|
20427
|
+
try {
|
|
20428
|
+
await fs11.promises.writeFile(htmlPath, html, "utf8");
|
|
20429
|
+
await printHtmlToPdf({
|
|
20430
|
+
executablePath,
|
|
20431
|
+
htmlPath,
|
|
20432
|
+
pdfPath
|
|
20433
|
+
});
|
|
20434
|
+
const pdf = await fs11.promises.readFile(pdfPath);
|
|
20435
|
+
if (pdf.length === 0 || !pdf.subarray(0, 4).equals(Buffer.from("%PDF"))) {
|
|
20436
|
+
throw new Error("Chrome did not produce a valid PDF file.");
|
|
20437
|
+
}
|
|
20438
|
+
return pdf;
|
|
20439
|
+
} finally {
|
|
20440
|
+
await fs11.promises.rm(tempDir, { force: true, recursive: true });
|
|
20441
|
+
}
|
|
20442
|
+
}
|
|
20443
|
+
async function printHtmlToPdf(input) {
|
|
20444
|
+
const args = [
|
|
20445
|
+
"--headless",
|
|
20446
|
+
"--disable-gpu",
|
|
20447
|
+
"--disable-dev-shm-usage",
|
|
20448
|
+
"--no-sandbox",
|
|
20449
|
+
"--disable-setuid-sandbox",
|
|
20450
|
+
"--font-render-hinting=none",
|
|
20451
|
+
"--no-pdf-header-footer",
|
|
20452
|
+
"--print-to-pdf-no-header",
|
|
20453
|
+
`--print-to-pdf=${input.pdfPath}`,
|
|
20454
|
+
pathToFileURL3(input.htmlPath).href
|
|
20455
|
+
];
|
|
20456
|
+
await new Promise((resolve, reject) => {
|
|
20457
|
+
const child = spawn2(input.executablePath, args, {
|
|
20458
|
+
stdio: ["ignore", "ignore", "pipe"]
|
|
20459
|
+
});
|
|
20460
|
+
let settled = false;
|
|
20461
|
+
let stderr = "";
|
|
20462
|
+
const complete = (error) => {
|
|
20463
|
+
if (settled) {
|
|
20464
|
+
return;
|
|
20465
|
+
}
|
|
20466
|
+
settled = true;
|
|
20467
|
+
clearTimeout(timeout);
|
|
20468
|
+
child.kill("SIGTERM");
|
|
20469
|
+
if (error) {
|
|
20470
|
+
reject(error);
|
|
20471
|
+
} else {
|
|
20472
|
+
resolve();
|
|
20473
|
+
}
|
|
20474
|
+
};
|
|
20475
|
+
const timeout = setTimeout(() => {
|
|
20476
|
+
child.kill("SIGKILL");
|
|
20477
|
+
complete(new Error(`Chrome PDF export timed out after ${PDF_EXPORT_TIMEOUT_MS}ms.`));
|
|
20478
|
+
}, PDF_EXPORT_TIMEOUT_MS);
|
|
20479
|
+
child.stderr.on("data", (chunk) => {
|
|
20480
|
+
stderr = truncateChromeStderr(`${stderr}${chunk.toString("utf8")}`);
|
|
20481
|
+
if (stderr.includes("bytes written to file")) {
|
|
20482
|
+
complete();
|
|
20483
|
+
}
|
|
20484
|
+
});
|
|
20485
|
+
child.on("error", (error) => {
|
|
20486
|
+
complete(error);
|
|
20487
|
+
});
|
|
20488
|
+
child.on("close", (code, signal) => {
|
|
20489
|
+
if (code === 0) {
|
|
20490
|
+
complete();
|
|
20491
|
+
return;
|
|
20492
|
+
}
|
|
20493
|
+
const reason = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`;
|
|
20494
|
+
const detail = stderr ? ` ${stderr}` : "";
|
|
20495
|
+
complete(new Error(`Chrome PDF export failed with ${reason}.${detail}`));
|
|
20496
|
+
});
|
|
20497
|
+
});
|
|
20498
|
+
}
|
|
20499
|
+
function truncateChromeStderr(value) {
|
|
20500
|
+
if (value.length <= MAX_CHROME_STDERR_CHARS) {
|
|
20501
|
+
return value;
|
|
20502
|
+
}
|
|
20503
|
+
return value.slice(value.length - MAX_CHROME_STDERR_CHARS);
|
|
20504
|
+
}
|
|
19835
20505
|
|
|
19836
20506
|
// src/thread-export-coordinator.ts
|
|
19837
20507
|
function userPromptPreviewFromTurn(turn) {
|
|
@@ -20102,7 +20772,7 @@ var ThreadForkCoordinator = class {
|
|
|
20102
20772
|
// src/thread-attachment-coordinator.ts
|
|
20103
20773
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
20104
20774
|
import fs12 from "fs/promises";
|
|
20105
|
-
import
|
|
20775
|
+
import path15 from "path";
|
|
20106
20776
|
async function pathExists(absPath) {
|
|
20107
20777
|
try {
|
|
20108
20778
|
await fs12.access(absPath);
|
|
@@ -20112,8 +20782,8 @@ async function pathExists(absPath) {
|
|
|
20112
20782
|
}
|
|
20113
20783
|
}
|
|
20114
20784
|
function sanitizeAttachmentFileName(originalName) {
|
|
20115
|
-
const basename =
|
|
20116
|
-
const extension =
|
|
20785
|
+
const basename = path15.basename(originalName).trim() || "attachment";
|
|
20786
|
+
const extension = path15.extname(basename).replace(/[^a-zA-Z0-9.]/g, "");
|
|
20117
20787
|
const rawStem = extension ? basename.slice(0, -extension.length) : basename;
|
|
20118
20788
|
const sanitizedStem = rawStem.replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "").slice(0, 64);
|
|
20119
20789
|
const stem = sanitizedStem || "attachment";
|
|
@@ -20121,7 +20791,7 @@ function sanitizeAttachmentFileName(originalName) {
|
|
|
20121
20791
|
return `${stem}-${randomUUID3().slice(0, 8)}${normalizedExtension}`;
|
|
20122
20792
|
}
|
|
20123
20793
|
function threadTempDirectoryPath2(workspacePath, localThreadId) {
|
|
20124
|
-
return
|
|
20794
|
+
return path15.join(workspacePath, ".temp", "threads", localThreadId);
|
|
20125
20795
|
}
|
|
20126
20796
|
var ThreadAttachmentCoordinator = class {
|
|
20127
20797
|
constructor(db) {
|
|
@@ -20162,7 +20832,7 @@ var ThreadAttachmentCoordinator = class {
|
|
|
20162
20832
|
const savedFileName = sanitizeAttachmentFileName(
|
|
20163
20833
|
attachment.manifest.originalName
|
|
20164
20834
|
);
|
|
20165
|
-
await fs12.writeFile(
|
|
20835
|
+
await fs12.writeFile(path15.join(tempDirectory, savedFileName), attachment.buffer);
|
|
20166
20836
|
const relativePath = `./.temp/threads/${localThreadId}/${savedFileName}`;
|
|
20167
20837
|
const replacementToken = attachment.manifest.kind === "photo" ? `[PHOTO ${relativePath}]` : `[FILE ${relativePath}]`;
|
|
20168
20838
|
rewrittenPrompt = rewrittenPrompt.split(attachment.manifest.placeholder).join(replacementToken);
|
|
@@ -20176,7 +20846,7 @@ var ThreadAttachmentCoordinator = class {
|
|
|
20176
20846
|
|
|
20177
20847
|
// src/thread-import-coordinator.ts
|
|
20178
20848
|
import fs13 from "fs/promises";
|
|
20179
|
-
import
|
|
20849
|
+
import path16 from "path";
|
|
20180
20850
|
async function pathExists2(absPath) {
|
|
20181
20851
|
try {
|
|
20182
20852
|
await fs13.access(absPath);
|
|
@@ -20186,19 +20856,19 @@ async function pathExists2(absPath) {
|
|
|
20186
20856
|
}
|
|
20187
20857
|
}
|
|
20188
20858
|
async function resolveComparablePath2(absPath) {
|
|
20189
|
-
const resolved =
|
|
20859
|
+
const resolved = path16.resolve(absPath);
|
|
20190
20860
|
if (await pathExists2(resolved)) {
|
|
20191
20861
|
return fs13.realpath(resolved);
|
|
20192
20862
|
}
|
|
20193
|
-
const parentPath =
|
|
20863
|
+
const parentPath = path16.dirname(resolved);
|
|
20194
20864
|
if (parentPath === resolved) {
|
|
20195
20865
|
return resolved;
|
|
20196
20866
|
}
|
|
20197
20867
|
const resolvedParent = await resolveComparablePath2(parentPath);
|
|
20198
|
-
return
|
|
20868
|
+
return path16.join(resolvedParent, path16.basename(resolved));
|
|
20199
20869
|
}
|
|
20200
20870
|
async function resolveImportedWorkspacePath(workspaceRoot, candidatePath) {
|
|
20201
|
-
if (!
|
|
20871
|
+
if (!path16.isAbsolute(candidatePath)) {
|
|
20202
20872
|
throw new HttpError(400, {
|
|
20203
20873
|
code: "bad_request",
|
|
20204
20874
|
message: "Imported session path must be absolute."
|
|
@@ -20206,7 +20876,7 @@ async function resolveImportedWorkspacePath(workspaceRoot, candidatePath) {
|
|
|
20206
20876
|
}
|
|
20207
20877
|
const resolvedRoot = await resolveComparablePath2(workspaceRoot);
|
|
20208
20878
|
const resolvedCandidate = await resolveComparablePath2(candidatePath);
|
|
20209
|
-
const normalizedRoot = resolvedRoot.endsWith(
|
|
20879
|
+
const normalizedRoot = resolvedRoot.endsWith(path16.sep) ? resolvedRoot : `${resolvedRoot}${path16.sep}`;
|
|
20210
20880
|
if (resolvedCandidate !== resolvedRoot && !resolvedCandidate.startsWith(normalizedRoot)) {
|
|
20211
20881
|
throw new HttpError(403, {
|
|
20212
20882
|
code: "forbidden",
|
|
@@ -20232,17 +20902,17 @@ var ThreadImportCoordinator = class {
|
|
|
20232
20902
|
message: "Session id is required."
|
|
20233
20903
|
});
|
|
20234
20904
|
}
|
|
20235
|
-
const
|
|
20905
|
+
const provider2 = normalizeAgentBackendId(input.provider ?? "codex") ?? "codex";
|
|
20236
20906
|
const existingThread = getThreadRecordByProviderSessionId(
|
|
20237
20907
|
this.db,
|
|
20238
|
-
|
|
20908
|
+
provider2,
|
|
20239
20909
|
normalizedSessionId
|
|
20240
20910
|
);
|
|
20241
20911
|
if (existingThread) {
|
|
20242
20912
|
return existingThread.id;
|
|
20243
20913
|
}
|
|
20244
20914
|
const importSession = await this.sessionCoordinator.resolveLocalImportSession({
|
|
20245
|
-
provider,
|
|
20915
|
+
provider: provider2,
|
|
20246
20916
|
sessionId: normalizedSessionId
|
|
20247
20917
|
});
|
|
20248
20918
|
if (!importSession) {
|
|
@@ -20259,7 +20929,7 @@ var ThreadImportCoordinator = class {
|
|
|
20259
20929
|
if (!workspace) {
|
|
20260
20930
|
workspace = createWorkspaceRecord(this.db, {
|
|
20261
20931
|
absPath: importedPath,
|
|
20262
|
-
label:
|
|
20932
|
+
label: path16.basename(importedPath) || "workspace"
|
|
20263
20933
|
});
|
|
20264
20934
|
}
|
|
20265
20935
|
const created = createThreadRecord(this.db, {
|
|
@@ -20316,8 +20986,8 @@ var ProviderFeatureCoordinator = class {
|
|
|
20316
20986
|
mapGoalError(error) {
|
|
20317
20987
|
this.codexGoalFeatures.mapGoalError(error);
|
|
20318
20988
|
}
|
|
20319
|
-
async ensureGoalsFeatureEnabled(
|
|
20320
|
-
if (!this.providerRuntime.isCodexProvider(
|
|
20989
|
+
async ensureGoalsFeatureEnabled(provider2) {
|
|
20990
|
+
if (!this.providerRuntime.isCodexProvider(provider2)) {
|
|
20321
20991
|
return;
|
|
20322
20992
|
}
|
|
20323
20993
|
await this.codexGoalFeatures.ensureGoalsFeatureEnabled(
|
|
@@ -20382,7 +21052,7 @@ var ThreadService = class {
|
|
|
20382
21052
|
this.historyPersistence = new ThreadHistoryPersistenceCoordinator(db, this.liveState);
|
|
20383
21053
|
this.attachmentCoordinator = new ThreadAttachmentCoordinator(db);
|
|
20384
21054
|
this.managementCoordinator = new ThreadManagementCoordinator(providerManagement, {
|
|
20385
|
-
runtimeForProvider: (
|
|
21055
|
+
runtimeForProvider: (provider2) => this.runtimeForProvider(provider2)
|
|
20386
21056
|
});
|
|
20387
21057
|
this.sessionCoordinator = new ThreadSessionCoordinator(
|
|
20388
21058
|
this.providerRuntime,
|
|
@@ -20408,7 +21078,7 @@ var ThreadService = class {
|
|
|
20408
21078
|
this.liveState,
|
|
20409
21079
|
this.providerRuntime,
|
|
20410
21080
|
{
|
|
20411
|
-
runtimeForProvider: (
|
|
21081
|
+
runtimeForProvider: (provider2) => this.runtimeForProvider(provider2),
|
|
20412
21082
|
resetThreadContextUsage: (localThreadId, emitEvent) => this.resetThreadContextUsage(localThreadId, emitEvent),
|
|
20413
21083
|
getThreadContextUsage: (localThreadId) => this.getThreadContextUsage(localThreadId),
|
|
20414
21084
|
invalidateThreadDetailCache: (localThreadId) => this.invalidateThreadDetailCache(localThreadId),
|
|
@@ -20466,7 +21136,7 @@ var ThreadService = class {
|
|
|
20466
21136
|
emitThreadEvent: (type, threadId, payload) => this.emitThreadEvent(type, threadId, payload),
|
|
20467
21137
|
ensureThreadLoaded: (record) => this.ensureThreadLoadedForProviderOperation(record),
|
|
20468
21138
|
requireProviderSessionId: (record) => this.requireProviderSessionId(record),
|
|
20469
|
-
runtimeForProvider: (
|
|
21139
|
+
runtimeForProvider: (provider2) => this.runtimeForProvider(provider2)
|
|
20470
21140
|
});
|
|
20471
21141
|
this.auxiliaryState = new ThreadAuxiliaryStateStore(db, {
|
|
20472
21142
|
cachedTurns: (localThreadId) => this.detailAssembler.cachedTurns(localThreadId),
|
|
@@ -20478,9 +21148,9 @@ var ThreadService = class {
|
|
|
20478
21148
|
});
|
|
20479
21149
|
this.requestCoordinator = new ProviderRequestCoordinator({
|
|
20480
21150
|
emitThreadEvent: (type, threadId, payload) => this.emitThreadEvent(type, threadId, payload),
|
|
20481
|
-
findRecordByProviderSessionId: (
|
|
21151
|
+
findRecordByProviderSessionId: (provider2, providerSessionId) => this.findRecordByProviderSessionId(provider2, providerSessionId),
|
|
20482
21152
|
normalizeCollaborationMode,
|
|
20483
|
-
runtimeForProvider: (
|
|
21153
|
+
runtimeForProvider: (provider2) => this.runtimeForProvider(provider2)
|
|
20484
21154
|
});
|
|
20485
21155
|
this.deletionCoordinator = new ThreadDeletionCoordinator(
|
|
20486
21156
|
db,
|
|
@@ -20506,7 +21176,7 @@ var ThreadService = class {
|
|
|
20506
21176
|
this.sessionCoordinator,
|
|
20507
21177
|
{
|
|
20508
21178
|
buildThreadPatch: (remoteSession, model, reasoningEffort) => buildThreadPatch(remoteSession, model, reasoningEffort),
|
|
20509
|
-
fastModeForProvider: (
|
|
21179
|
+
fastModeForProvider: (provider2, fastMode) => this.fastModeForProvider(provider2, fastMode),
|
|
20510
21180
|
getThreadDetail: (localThreadId) => this.getThreadDetail(localThreadId),
|
|
20511
21181
|
invalidateThreadDetailCache: (localThreadId) => this.invalidateThreadDetailCache(localThreadId),
|
|
20512
21182
|
normalizeCollaborationMode,
|
|
@@ -20540,7 +21210,7 @@ var ThreadService = class {
|
|
|
20540
21210
|
deletePersistedHistoryItemsForTurn: (localThreadId, turnId) => this.historyPersistence.deletePersistedHistoryItemsForTurn(localThreadId, turnId),
|
|
20541
21211
|
dismissPlanDecisionTurn: (localThreadId) => this.requestCoordinator.dismissPlanDecisionTurn(localThreadId),
|
|
20542
21212
|
emitThreadEvent: (type, threadId, payload) => this.emitThreadEvent(type, threadId, payload),
|
|
20543
|
-
fastModeForProvider: (
|
|
21213
|
+
fastModeForProvider: (provider2, fastMode) => this.fastModeForProvider(provider2, fastMode),
|
|
20544
21214
|
hasPendingAskUserQuestion: (localThreadId) => this.hasPendingAskUserQuestion(localThreadId),
|
|
20545
21215
|
invalidateThreadDetailCache: (localThreadId) => this.invalidateThreadDetailCache(localThreadId),
|
|
20546
21216
|
listThreadGoalHistory: (localThreadId) => this.goalCoordinator.listThreadGoalHistory(localThreadId),
|
|
@@ -20595,14 +21265,14 @@ var ThreadService = class {
|
|
|
20595
21265
|
forkCoordinator;
|
|
20596
21266
|
attachmentCoordinator;
|
|
20597
21267
|
importCoordinator;
|
|
20598
|
-
normalizeProvider(
|
|
20599
|
-
return this.providerRuntime.normalizeProvider(
|
|
21268
|
+
normalizeProvider(provider2) {
|
|
21269
|
+
return this.providerRuntime.normalizeProvider(provider2);
|
|
20600
21270
|
}
|
|
20601
|
-
runtimeForProvider(
|
|
20602
|
-
return this.providerRuntime.runtimeForProvider(
|
|
21271
|
+
runtimeForProvider(provider2) {
|
|
21272
|
+
return this.providerRuntime.runtimeForProvider(provider2);
|
|
20603
21273
|
}
|
|
20604
|
-
optionalRuntimeForProvider(
|
|
20605
|
-
return this.providerRuntime.optionalRuntimeForProvider(
|
|
21274
|
+
optionalRuntimeForProvider(provider2) {
|
|
21275
|
+
return this.providerRuntime.optionalRuntimeForProvider(provider2);
|
|
20606
21276
|
}
|
|
20607
21277
|
providerForRecord(record) {
|
|
20608
21278
|
return this.providerRuntime.providerForRecord(record);
|
|
@@ -20634,18 +21304,18 @@ var ThreadService = class {
|
|
|
20634
21304
|
);
|
|
20635
21305
|
}
|
|
20636
21306
|
}
|
|
20637
|
-
findRecordByProviderSessionId(
|
|
21307
|
+
findRecordByProviderSessionId(provider2, providerSessionId) {
|
|
20638
21308
|
return getThreadRecordByProviderSessionId(
|
|
20639
21309
|
this.db,
|
|
20640
|
-
this.providerForRecord({ provider }),
|
|
21310
|
+
this.providerForRecord({ provider: provider2 }),
|
|
20641
21311
|
providerSessionId
|
|
20642
21312
|
);
|
|
20643
21313
|
}
|
|
20644
|
-
runtimeSupportsFastMode(
|
|
20645
|
-
return this.providerRuntime.runtimeSupportsFastMode(
|
|
21314
|
+
runtimeSupportsFastMode(provider2) {
|
|
21315
|
+
return this.providerRuntime.runtimeSupportsFastMode(provider2);
|
|
20646
21316
|
}
|
|
20647
|
-
fastModeForProvider(
|
|
20648
|
-
return this.providerRuntime.fastModeForProvider(
|
|
21317
|
+
fastModeForProvider(provider2, fastMode) {
|
|
21318
|
+
return this.providerRuntime.fastModeForProvider(provider2, fastMode);
|
|
20649
21319
|
}
|
|
20650
21320
|
performanceModeForRecord(record) {
|
|
20651
21321
|
return this.providerRuntime.performanceModeForRecord(record);
|
|
@@ -20653,11 +21323,11 @@ var ThreadService = class {
|
|
|
20653
21323
|
async handleProviderRequest(request) {
|
|
20654
21324
|
await this.handleProviderRuntimeRequest(request);
|
|
20655
21325
|
}
|
|
20656
|
-
async listLoadedProviderSessionIds(
|
|
20657
|
-
return this.providerRuntime.listLoadedProviderSessionIds(
|
|
21326
|
+
async listLoadedProviderSessionIds(provider2 = "codex") {
|
|
21327
|
+
return this.providerRuntime.listLoadedProviderSessionIds(provider2);
|
|
20658
21328
|
}
|
|
20659
|
-
async listProviderModels(
|
|
20660
|
-
return this.providerRuntime.listProviderModels(
|
|
21329
|
+
async listProviderModels(provider2 = "codex") {
|
|
21330
|
+
return this.providerRuntime.listProviderModels(provider2);
|
|
20661
21331
|
}
|
|
20662
21332
|
invalidateThreadDetailCache(localThreadId) {
|
|
20663
21333
|
this.detailAssembler.invalidate(localThreadId);
|
|
@@ -20938,19 +21608,18 @@ var ThreadService = class {
|
|
|
20938
21608
|
return this.getThreadDetail(localThreadId);
|
|
20939
21609
|
}
|
|
20940
21610
|
async sendPrompt(localThreadId, input, options = {}) {
|
|
20941
|
-
|
|
21611
|
+
let record = getThreadRecordById(this.db, localThreadId);
|
|
20942
21612
|
if (!record) {
|
|
20943
21613
|
throw new HttpError(404, {
|
|
20944
21614
|
code: "not_found",
|
|
20945
21615
|
message: "Thread was not found."
|
|
20946
21616
|
});
|
|
20947
21617
|
}
|
|
20948
|
-
const providerSessionId = this.requireProviderSessionId(record);
|
|
20949
21618
|
await this.importCoordinator.assertImportedThreadReadyForPrompt({
|
|
20950
21619
|
source: record.source,
|
|
20951
21620
|
provider: record.provider,
|
|
20952
|
-
providerSessionId,
|
|
20953
|
-
listLoadedProviderSessionIds: (
|
|
21621
|
+
providerSessionId: this.requireProviderSessionId(record),
|
|
21622
|
+
listLoadedProviderSessionIds: (provider2) => this.listLoadedProviderSessionIds(provider2)
|
|
20954
21623
|
});
|
|
20955
21624
|
if (record.isConnected === false) {
|
|
20956
21625
|
throw new HttpError(409, {
|
|
@@ -20958,6 +21627,23 @@ var ThreadService = class {
|
|
|
20958
21627
|
message: "Connect this thread before sending a new prompt."
|
|
20959
21628
|
});
|
|
20960
21629
|
}
|
|
21630
|
+
if (this.providerForRecord(record) === "codex") {
|
|
21631
|
+
const providerSessionId2 = this.requireProviderSessionId(record);
|
|
21632
|
+
const loadedIds = await this.listLoadedProviderSessionIds(record.provider);
|
|
21633
|
+
if (!loadedIds.has(providerSessionId2)) {
|
|
21634
|
+
await this.ensureThreadLoadedForProviderOperation(record);
|
|
21635
|
+
record = getThreadRecordById(this.db, localThreadId);
|
|
21636
|
+
const resumedProviderSessionId = this.requireProviderSessionId(record);
|
|
21637
|
+
const refreshedLoadedIds = await this.listLoadedProviderSessionIds(record.provider);
|
|
21638
|
+
if (!refreshedLoadedIds.has(resumedProviderSessionId)) {
|
|
21639
|
+
throw new HttpError(409, {
|
|
21640
|
+
code: "conflict",
|
|
21641
|
+
message: "Connect this thread before sending a new prompt."
|
|
21642
|
+
});
|
|
21643
|
+
}
|
|
21644
|
+
}
|
|
21645
|
+
}
|
|
21646
|
+
const providerSessionId = this.requireProviderSessionId(record);
|
|
20961
21647
|
const prompt = input.prompt.trim();
|
|
20962
21648
|
const displayPrompt = options.displayPrompt?.trim() || prompt;
|
|
20963
21649
|
if (!prompt) {
|
|
@@ -21381,7 +22067,7 @@ var ThreadService = class {
|
|
|
21381
22067
|
provider: record.provider,
|
|
21382
22068
|
providerSessionId: this.requireProviderSessionId(record),
|
|
21383
22069
|
model: record.model,
|
|
21384
|
-
listLoadedProviderSessionIds: (
|
|
22070
|
+
listLoadedProviderSessionIds: (provider2) => this.listLoadedProviderSessionIds(provider2),
|
|
21385
22071
|
resumeThread: (input2) => this.resumeThread(localThreadId, input2)
|
|
21386
22072
|
});
|
|
21387
22073
|
await this.updateThreadSettings(localThreadId, {
|
|
@@ -21407,7 +22093,7 @@ var ThreadService = class {
|
|
|
21407
22093
|
}
|
|
21408
22094
|
toThreadDto(record, loadedIds) {
|
|
21409
22095
|
return toThreadDto(record, loadedIds, {
|
|
21410
|
-
fastModeForProvider: (
|
|
22096
|
+
fastModeForProvider: (provider2, fastMode) => this.fastModeForProvider(provider2, fastMode),
|
|
21411
22097
|
getThreadContextUsage: (localThreadId) => this.getThreadContextUsage(localThreadId)
|
|
21412
22098
|
});
|
|
21413
22099
|
}
|
|
@@ -21501,8 +22187,8 @@ var ThreadService = class {
|
|
|
21501
22187
|
|
|
21502
22188
|
// src/routes/agent-runtimes.ts
|
|
21503
22189
|
import fs15 from "fs/promises";
|
|
21504
|
-
import { spawn as
|
|
21505
|
-
import
|
|
22190
|
+
import { spawn as spawn3 } from "child_process";
|
|
22191
|
+
import path17 from "path";
|
|
21506
22192
|
import { z as z3 } from "zod";
|
|
21507
22193
|
|
|
21508
22194
|
// src/provider-schemas.ts
|
|
@@ -21521,15 +22207,15 @@ var npmManagedPackageNames = {
|
|
|
21521
22207
|
claude: ["@anthropic-ai/claude-code", "@anthropic-ai/claude-agent-sdk"],
|
|
21522
22208
|
opencode: ["opencode-ai", "@opencode-ai/sdk"]
|
|
21523
22209
|
};
|
|
21524
|
-
function providerNotConfigured(
|
|
21525
|
-
const error = new Error(`Agent runtime provider is not configured: ${
|
|
22210
|
+
function providerNotConfigured(provider2) {
|
|
22211
|
+
const error = new Error(`Agent runtime provider is not configured: ${provider2}`);
|
|
21526
22212
|
error.statusCode = 404;
|
|
21527
22213
|
return error;
|
|
21528
22214
|
}
|
|
21529
|
-
function runtimeDto(app,
|
|
21530
|
-
const runtime = app.services.agentRuntimes.getOptional(
|
|
22215
|
+
function runtimeDto(app, provider2) {
|
|
22216
|
+
const runtime = app.services.agentRuntimes.getOptional(provider2);
|
|
21531
22217
|
if (!runtime) {
|
|
21532
|
-
throw providerNotConfigured(
|
|
22218
|
+
throw providerNotConfigured(provider2);
|
|
21533
22219
|
}
|
|
21534
22220
|
const installation = {
|
|
21535
22221
|
...runtime.installation
|
|
@@ -21539,7 +22225,7 @@ function runtimeDto(app, provider) {
|
|
|
21539
22225
|
displayName: runtime.displayName,
|
|
21540
22226
|
description: runtime.description,
|
|
21541
22227
|
enabled: isAgentRuntimeEnabled({ ...runtime, installation }),
|
|
21542
|
-
isDefault:
|
|
22228
|
+
isDefault: provider2 === defaultAgentBackendId,
|
|
21543
22229
|
status: runtime.getStatus(),
|
|
21544
22230
|
capabilities: runtime.capabilities,
|
|
21545
22231
|
managementSchema: runtime.managementSchema,
|
|
@@ -21559,18 +22245,18 @@ async function registerAgentRuntimeRoutes(app) {
|
|
|
21559
22245
|
});
|
|
21560
22246
|
});
|
|
21561
22247
|
app.get("/api/agent-runtimes/:provider/status", async (request) => {
|
|
21562
|
-
const { provider } = providerParamSchema.parse(request.params);
|
|
21563
|
-
return runtimeDto(app,
|
|
22248
|
+
const { provider: provider2 } = providerParamSchema.parse(request.params);
|
|
22249
|
+
return runtimeDto(app, provider2);
|
|
21564
22250
|
});
|
|
21565
22251
|
app.post("/api/agent-runtimes/:provider/restart", async (request) => {
|
|
21566
|
-
const { provider } = providerParamSchema.parse(request.params);
|
|
21567
|
-
const runtime = app.services.agentRuntimes.getOptional(
|
|
22252
|
+
const { provider: provider2 } = providerParamSchema.parse(request.params);
|
|
22253
|
+
const runtime = app.services.agentRuntimes.getOptional(provider2);
|
|
21568
22254
|
if (!runtime) {
|
|
21569
|
-
throw providerNotConfigured(
|
|
22255
|
+
throw providerNotConfigured(provider2);
|
|
21570
22256
|
}
|
|
21571
22257
|
await runtime.stop();
|
|
21572
22258
|
await runtime.start();
|
|
21573
|
-
return runtimeDto(app,
|
|
22259
|
+
return runtimeDto(app, provider2);
|
|
21574
22260
|
});
|
|
21575
22261
|
app.post("/api/agent-runtimes/:provider/install", async (request) => {
|
|
21576
22262
|
if (!app.services.config.agentRuntimeManagementEnabled) {
|
|
@@ -21579,11 +22265,11 @@ async function registerAgentRuntimeRoutes(app) {
|
|
|
21579
22265
|
message: "Agent runtime install and update are disabled for this worker."
|
|
21580
22266
|
});
|
|
21581
22267
|
}
|
|
21582
|
-
const { provider } = providerParamSchema.parse(request.params);
|
|
22268
|
+
const { provider: provider2 } = providerParamSchema.parse(request.params);
|
|
21583
22269
|
const { action } = installActionSchema.parse(request.body ?? {});
|
|
21584
|
-
const runtime = app.services.agentRuntimes.getOptional(
|
|
22270
|
+
const runtime = app.services.agentRuntimes.getOptional(provider2);
|
|
21585
22271
|
if (!runtime) {
|
|
21586
|
-
throw providerNotConfigured(
|
|
22272
|
+
throw providerNotConfigured(provider2);
|
|
21587
22273
|
}
|
|
21588
22274
|
const command = action === "install" ? runtime.installation.installCommand : runtime.installation.updateCommand;
|
|
21589
22275
|
if (!command) {
|
|
@@ -21616,16 +22302,16 @@ async function registerAgentRuntimeRoutes(app) {
|
|
|
21616
22302
|
if (updateWarning) {
|
|
21617
22303
|
runtime.installation.lastError = updateWarning;
|
|
21618
22304
|
}
|
|
21619
|
-
return runtimeDto(app,
|
|
22305
|
+
return runtimeDto(app, provider2);
|
|
21620
22306
|
} finally {
|
|
21621
22307
|
runtime.installation.busy = false;
|
|
21622
22308
|
}
|
|
21623
22309
|
});
|
|
21624
22310
|
app.get("/api/agent-runtimes/:provider/models", async (request) => {
|
|
21625
|
-
const { provider } = providerParamSchema.parse(request.params);
|
|
21626
|
-
const runtime = app.services.agentRuntimes.getOptional(
|
|
22311
|
+
const { provider: provider2 } = providerParamSchema.parse(request.params);
|
|
22312
|
+
const runtime = app.services.agentRuntimes.getOptional(provider2);
|
|
21627
22313
|
if (!runtime) {
|
|
21628
|
-
throw providerNotConfigured(
|
|
22314
|
+
throw providerNotConfigured(provider2);
|
|
21629
22315
|
}
|
|
21630
22316
|
return (await runtime.listModels()).map((model) => ({
|
|
21631
22317
|
id: model.id,
|
|
@@ -21649,10 +22335,10 @@ async function registerAgentRuntimeRoutes(app) {
|
|
|
21649
22335
|
message: "Build restart is disabled for this worker."
|
|
21650
22336
|
});
|
|
21651
22337
|
}
|
|
21652
|
-
const { provider } = providerParamSchema.parse(request.params);
|
|
21653
|
-
const runtime = app.services.agentRuntimes.getOptional(
|
|
22338
|
+
const { provider: provider2 } = providerParamSchema.parse(request.params);
|
|
22339
|
+
const runtime = app.services.agentRuntimes.getOptional(provider2);
|
|
21654
22340
|
if (!runtime) {
|
|
21655
|
-
throw providerNotConfigured(
|
|
22341
|
+
throw providerNotConfigured(provider2);
|
|
21656
22342
|
}
|
|
21657
22343
|
if (!runtime.managementSchema.buildRestart) {
|
|
21658
22344
|
const error = new Error("This backend does not support build and restart.");
|
|
@@ -21723,7 +22409,7 @@ async function refreshBackendInstallation(app, runtime) {
|
|
|
21723
22409
|
async function installedPackageVersion(packageName) {
|
|
21724
22410
|
const globalRoot = await npmGlobalRoot3();
|
|
21725
22411
|
if (globalRoot) {
|
|
21726
|
-
const global = await packageVersionFromPath(
|
|
22412
|
+
const global = await packageVersionFromPath(path17.join(globalRoot, packageName, "package.json"));
|
|
21727
22413
|
if (global) {
|
|
21728
22414
|
return global;
|
|
21729
22415
|
}
|
|
@@ -21760,8 +22446,8 @@ async function updatePathWarning(app, runtime, before, command) {
|
|
|
21760
22446
|
`Command: ${command}`
|
|
21761
22447
|
].filter(Boolean).join(" ");
|
|
21762
22448
|
}
|
|
21763
|
-
function runtimeCommand(app,
|
|
21764
|
-
switch (
|
|
22449
|
+
function runtimeCommand(app, provider2) {
|
|
22450
|
+
switch (provider2) {
|
|
21765
22451
|
case "codex":
|
|
21766
22452
|
return app.services.config.agentProviders.codex.command;
|
|
21767
22453
|
case "claude":
|
|
@@ -21774,7 +22460,7 @@ function versionStringContains(installedVersion, latestVersion) {
|
|
|
21774
22460
|
return Boolean(installedVersion && latestVersion && installedVersion.includes(latestVersion));
|
|
21775
22461
|
}
|
|
21776
22462
|
async function packageVersionFromNode(packageName) {
|
|
21777
|
-
return packageVersionFromPath(
|
|
22463
|
+
return packageVersionFromPath(path17.resolve("node_modules", packageName, "package.json"));
|
|
21778
22464
|
}
|
|
21779
22465
|
async function packageVersionFromPath(packageJsonPath) {
|
|
21780
22466
|
try {
|
|
@@ -21801,14 +22487,14 @@ async function npmGlobalBin() {
|
|
|
21801
22487
|
return firstLine(result.stdout);
|
|
21802
22488
|
}
|
|
21803
22489
|
const prefix = await npmGlobalPrefix();
|
|
21804
|
-
return prefix ?
|
|
22490
|
+
return prefix ? path17.join(prefix, "bin") : null;
|
|
21805
22491
|
}
|
|
21806
22492
|
async function npmGlobalPrefix() {
|
|
21807
22493
|
const result = await runShellCommand("npm prefix -g", 3e3);
|
|
21808
22494
|
return result.code === 0 ? firstLine(result.stdout) : null;
|
|
21809
22495
|
}
|
|
21810
22496
|
async function commandPathFor(command) {
|
|
21811
|
-
if (
|
|
22497
|
+
if (path17.isAbsolute(command)) {
|
|
21812
22498
|
return command;
|
|
21813
22499
|
}
|
|
21814
22500
|
const result = await runShellCommand(`command -v ${shellQuote(command)}`, 3e3);
|
|
@@ -21833,7 +22519,7 @@ function commandFailureMessage(command, result) {
|
|
|
21833
22519
|
}
|
|
21834
22520
|
function runShellCommand(command, timeoutMs = 0) {
|
|
21835
22521
|
return new Promise((resolve) => {
|
|
21836
|
-
const child =
|
|
22522
|
+
const child = spawn3(command, {
|
|
21837
22523
|
shell: true,
|
|
21838
22524
|
stdio: ["ignore", "pipe", "pipe"]
|
|
21839
22525
|
});
|
|
@@ -22415,8 +23101,8 @@ async function registerSystemRoutes(app) {
|
|
|
22415
23101
|
message: "Provider config archives are disabled for this worker."
|
|
22416
23102
|
});
|
|
22417
23103
|
}
|
|
22418
|
-
const { provider } = providerParamSchema2.parse(request.params);
|
|
22419
|
-
return app.services.providerHostConfigService.listArchives(
|
|
23104
|
+
const { provider: provider2 } = providerParamSchema2.parse(request.params);
|
|
23105
|
+
return app.services.providerHostConfigService.listArchives(provider2);
|
|
22420
23106
|
});
|
|
22421
23107
|
app.post("/api/config/providers/:provider/archives", async (request) => {
|
|
22422
23108
|
if (!app.services.config.managementRoutesEnabled) {
|
|
@@ -22425,13 +23111,13 @@ async function registerSystemRoutes(app) {
|
|
|
22425
23111
|
message: "Provider config archives are disabled for this worker."
|
|
22426
23112
|
});
|
|
22427
23113
|
}
|
|
22428
|
-
const { provider } = providerParamSchema2.parse(request.params);
|
|
23114
|
+
const { provider: provider2 } = providerParamSchema2.parse(request.params);
|
|
22429
23115
|
const body = {};
|
|
22430
23116
|
const parsedBody = createProviderHostConfigArchiveSchema.parse(request.body ?? {});
|
|
22431
23117
|
if (parsedBody.label !== void 0) {
|
|
22432
23118
|
body.label = parsedBody.label;
|
|
22433
23119
|
}
|
|
22434
|
-
return app.services.providerHostConfigService.createArchive(
|
|
23120
|
+
return app.services.providerHostConfigService.createArchive(provider2, body);
|
|
22435
23121
|
});
|
|
22436
23122
|
app.patch("/api/config/providers/:provider/archives/:id", async (request) => {
|
|
22437
23123
|
if (!app.services.config.managementRoutesEnabled) {
|
|
@@ -22480,7 +23166,7 @@ async function registerSystemRoutes(app) {
|
|
|
22480
23166
|
|
|
22481
23167
|
// src/routes/threads.ts
|
|
22482
23168
|
import fs17 from "fs/promises";
|
|
22483
|
-
import
|
|
23169
|
+
import path18 from "path";
|
|
22484
23170
|
import { z as z5 } from "zod";
|
|
22485
23171
|
|
|
22486
23172
|
// src/worker-identity.ts
|
|
@@ -22952,7 +23638,7 @@ async function registerThreadRoutes(app) {
|
|
|
22952
23638
|
message: "Workspace was not found for this thread."
|
|
22953
23639
|
});
|
|
22954
23640
|
}
|
|
22955
|
-
const candidatePath =
|
|
23641
|
+
const candidatePath = path18.isAbsolute(query.path) ? query.path : path18.resolve(workspace.absPath, query.path);
|
|
22956
23642
|
const requestedPath = await fs17.realpath(candidatePath).catch(() => null);
|
|
22957
23643
|
if (!requestedPath) {
|
|
22958
23644
|
throw new HttpError(404, {
|
|
@@ -22960,8 +23646,8 @@ async function registerThreadRoutes(app) {
|
|
|
22960
23646
|
message: "Image file was not found."
|
|
22961
23647
|
});
|
|
22962
23648
|
}
|
|
22963
|
-
const resolvedWorkspaceRoot = await fs17.realpath(app.services.config.workspaceRoot).catch(() =>
|
|
22964
|
-
const workspacePrefix = resolvedWorkspaceRoot.endsWith(
|
|
23649
|
+
const resolvedWorkspaceRoot = await fs17.realpath(app.services.config.workspaceRoot).catch(() => path18.resolve(app.services.config.workspaceRoot));
|
|
23650
|
+
const workspacePrefix = resolvedWorkspaceRoot.endsWith(path18.sep) ? resolvedWorkspaceRoot : `${resolvedWorkspaceRoot}${path18.sep}`;
|
|
22965
23651
|
if (requestedPath !== resolvedWorkspaceRoot && !requestedPath.startsWith(workspacePrefix)) {
|
|
22966
23652
|
throw new HttpError(403, {
|
|
22967
23653
|
code: "forbidden",
|
|
@@ -23157,8 +23843,10 @@ async function registerThreadRoutes(app) {
|
|
|
23157
23843
|
|
|
23158
23844
|
// src/routes/workspaces.ts
|
|
23159
23845
|
import fs18 from "fs/promises";
|
|
23160
|
-
import
|
|
23161
|
-
import
|
|
23846
|
+
import { createReadStream } from "fs";
|
|
23847
|
+
import os4 from "os";
|
|
23848
|
+
import path19 from "path";
|
|
23849
|
+
import { spawn as spawn4 } from "child_process";
|
|
23162
23850
|
import { Readable } from "stream";
|
|
23163
23851
|
import { z as z6 } from "zod";
|
|
23164
23852
|
var createWorkspaceSchema = z6.union([
|
|
@@ -23214,6 +23902,8 @@ var workspacePreviewQuerySchema = z6.object({
|
|
|
23214
23902
|
});
|
|
23215
23903
|
var PREVIEW_DEFAULT_LIMIT_BYTES = 5e4;
|
|
23216
23904
|
var WORKSPACE_UPLOAD_MAX_BYTES = 50 * 1024 * 1024;
|
|
23905
|
+
var WORKSPACE_FOLDER_DOWNLOAD_MAX_BYTES = 100 * 1024 * 1024;
|
|
23906
|
+
var WORKSPACE_FOLDER_DOWNLOAD_MAX_FILES = 300;
|
|
23217
23907
|
var WORKSPACE_TREE_IGNORED_NAMES = /* @__PURE__ */ new Set([
|
|
23218
23908
|
".git",
|
|
23219
23909
|
"node_modules",
|
|
@@ -23243,7 +23933,7 @@ function toWorkspaceFileDto(file) {
|
|
|
23243
23933
|
};
|
|
23244
23934
|
}
|
|
23245
23935
|
function languageForPath(filePath) {
|
|
23246
|
-
const extension =
|
|
23936
|
+
const extension = path19.extname(filePath).slice(1).toLowerCase();
|
|
23247
23937
|
switch (extension) {
|
|
23248
23938
|
case "js":
|
|
23249
23939
|
case "jsx":
|
|
@@ -23289,18 +23979,18 @@ function languageForPath(filePath) {
|
|
|
23289
23979
|
}
|
|
23290
23980
|
}
|
|
23291
23981
|
function relativeWorkspacePath(rootPath, absPath) {
|
|
23292
|
-
const relative =
|
|
23293
|
-
return relative === "" ? "" : relative.split(
|
|
23982
|
+
const relative = path19.relative(rootPath, absPath);
|
|
23983
|
+
return relative === "" ? "" : relative.split(path19.sep).join("/");
|
|
23294
23984
|
}
|
|
23295
23985
|
async function resolveWorkspaceItemPath(rootPath, relativePath = "") {
|
|
23296
|
-
const candidate =
|
|
23986
|
+
const candidate = path19.resolve(rootPath, relativePath || ".");
|
|
23297
23987
|
const comparable = await assertPathWithinRoot(rootPath, candidate);
|
|
23298
23988
|
return comparable;
|
|
23299
23989
|
}
|
|
23300
23990
|
async function buildWorkspaceTreeNode(rootPath, absPath, depth = 0) {
|
|
23301
23991
|
const stats = await fs18.stat(absPath);
|
|
23302
23992
|
const relativePath = relativeWorkspacePath(rootPath, absPath);
|
|
23303
|
-
const name = relativePath ?
|
|
23993
|
+
const name = relativePath ? path19.basename(absPath) : path19.basename(rootPath);
|
|
23304
23994
|
if (!stats.isDirectory()) {
|
|
23305
23995
|
return {
|
|
23306
23996
|
name,
|
|
@@ -23335,7 +24025,7 @@ async function buildWorkspaceTreeNode(rootPath, absPath, depth = 0) {
|
|
|
23335
24025
|
}).slice(0, 400);
|
|
23336
24026
|
node.children = (await Promise.all(
|
|
23337
24027
|
visible.map(async (entry) => {
|
|
23338
|
-
const childPath =
|
|
24028
|
+
const childPath = path19.join(absPath, entry.name);
|
|
23339
24029
|
try {
|
|
23340
24030
|
if (!entry.isDirectory() && !entry.isFile()) {
|
|
23341
24031
|
return null;
|
|
@@ -23359,19 +24049,19 @@ function requireWorkspaceRecord(app, workspaceId) {
|
|
|
23359
24049
|
return record;
|
|
23360
24050
|
}
|
|
23361
24051
|
function artifactRoot(record) {
|
|
23362
|
-
return
|
|
24052
|
+
return path19.join(record.absPath, ".remote-codex", "artifacts");
|
|
23363
24053
|
}
|
|
23364
24054
|
function artifactFilePath(record, artifactId) {
|
|
23365
|
-
return
|
|
24055
|
+
return path19.join(artifactRoot(record), artifactId, "artifact.bin");
|
|
23366
24056
|
}
|
|
23367
24057
|
function artifactMetadataPath(record, artifactId) {
|
|
23368
|
-
return
|
|
24058
|
+
return path19.join(artifactRoot(record), artifactId, "metadata.json");
|
|
23369
24059
|
}
|
|
23370
24060
|
function safeArtifactFileName(value) {
|
|
23371
|
-
return
|
|
24061
|
+
return path19.basename(value).replace(/[^a-zA-Z0-9_. -]/g, "_") || "artifact.bin";
|
|
23372
24062
|
}
|
|
23373
24063
|
function artifactIdFromName(name) {
|
|
23374
|
-
const base =
|
|
24064
|
+
const base = path19.basename(name).replace(/[^a-zA-Z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 96);
|
|
23375
24065
|
return `${base || "artifact"}-${Date.now().toString(36)}`;
|
|
23376
24066
|
}
|
|
23377
24067
|
async function readArtifactMetadata(record, artifactId) {
|
|
@@ -23414,7 +24104,7 @@ async function listWorkspaceArtifacts(record) {
|
|
|
23414
24104
|
return artifacts.sort((left, right) => right.createdAt.localeCompare(left.createdAt));
|
|
23415
24105
|
}
|
|
23416
24106
|
function contentTypeForPath(filePath) {
|
|
23417
|
-
switch (
|
|
24107
|
+
switch (path19.extname(filePath).slice(1).toLowerCase()) {
|
|
23418
24108
|
case "png":
|
|
23419
24109
|
return "image/png";
|
|
23420
24110
|
case "jpg":
|
|
@@ -23443,8 +24133,135 @@ function contentTypeForPath(filePath) {
|
|
|
23443
24133
|
return "application/octet-stream";
|
|
23444
24134
|
}
|
|
23445
24135
|
}
|
|
24136
|
+
async function collectFolderZipEntries(rootPath, folderPath) {
|
|
24137
|
+
const folderName = path19.basename(folderPath) || "workspace-folder";
|
|
24138
|
+
const entries = [];
|
|
24139
|
+
let totalBytes = 0;
|
|
24140
|
+
const pending = [folderPath];
|
|
24141
|
+
while (pending.length > 0) {
|
|
24142
|
+
const current = pending.pop();
|
|
24143
|
+
const children = await fs18.readdir(current, { withFileTypes: true });
|
|
24144
|
+
for (const child of children) {
|
|
24145
|
+
const childPath = await resolveWorkspaceItemPath(rootPath, path19.relative(rootPath, path19.join(current, child.name)));
|
|
24146
|
+
if (child.isDirectory()) {
|
|
24147
|
+
pending.push(childPath);
|
|
24148
|
+
continue;
|
|
24149
|
+
}
|
|
24150
|
+
if (!child.isFile()) {
|
|
24151
|
+
continue;
|
|
24152
|
+
}
|
|
24153
|
+
const stats = await fs18.stat(childPath);
|
|
24154
|
+
totalBytes += stats.size;
|
|
24155
|
+
entries.push({
|
|
24156
|
+
absPath: childPath,
|
|
24157
|
+
archivePath: `${folderName}/${relativeWorkspacePath(folderPath, childPath)}`,
|
|
24158
|
+
size: stats.size,
|
|
24159
|
+
updatedAt: stats.mtime
|
|
24160
|
+
});
|
|
24161
|
+
if (entries.length >= WORKSPACE_FOLDER_DOWNLOAD_MAX_FILES) {
|
|
24162
|
+
throw new HttpError(400, {
|
|
24163
|
+
code: "bad_request",
|
|
24164
|
+
message: "Folder downloads must contain fewer than 300 files."
|
|
24165
|
+
});
|
|
24166
|
+
}
|
|
24167
|
+
if (totalBytes >= WORKSPACE_FOLDER_DOWNLOAD_MAX_BYTES) {
|
|
24168
|
+
throw new HttpError(400, {
|
|
24169
|
+
code: "bad_request",
|
|
24170
|
+
message: "Folder downloads must be smaller than 100 MB."
|
|
24171
|
+
});
|
|
24172
|
+
}
|
|
24173
|
+
}
|
|
24174
|
+
}
|
|
24175
|
+
return entries.sort((left, right) => left.archivePath.localeCompare(right.archivePath));
|
|
24176
|
+
}
|
|
24177
|
+
var crc32Table = new Uint32Array(256);
|
|
24178
|
+
for (let index = 0; index < 256; index += 1) {
|
|
24179
|
+
let value = index;
|
|
24180
|
+
for (let bit = 0; bit < 8; bit += 1) {
|
|
24181
|
+
value = value & 1 ? 3988292384 ^ value >>> 1 : value >>> 1;
|
|
24182
|
+
}
|
|
24183
|
+
crc32Table[index] = value >>> 0;
|
|
24184
|
+
}
|
|
24185
|
+
function crc32(buffer) {
|
|
24186
|
+
let value = 4294967295;
|
|
24187
|
+
for (const byte of buffer) {
|
|
24188
|
+
value = crc32Table[(value ^ byte) & 255] ^ value >>> 8;
|
|
24189
|
+
}
|
|
24190
|
+
return (value ^ 4294967295) >>> 0;
|
|
24191
|
+
}
|
|
24192
|
+
function zipDosDateTime(updatedAt) {
|
|
24193
|
+
const year = Math.max(1980, updatedAt.getFullYear());
|
|
24194
|
+
const dosTime = updatedAt.getHours() << 11 | updatedAt.getMinutes() << 5 | Math.floor(updatedAt.getSeconds() / 2);
|
|
24195
|
+
const dosDate = year - 1980 << 9 | updatedAt.getMonth() + 1 << 5 | updatedAt.getDate();
|
|
24196
|
+
return { dosDate, dosTime };
|
|
24197
|
+
}
|
|
24198
|
+
async function createFolderZipFile(rootPath, folderPath) {
|
|
24199
|
+
const entries = await collectFolderZipEntries(rootPath, folderPath);
|
|
24200
|
+
const localParts = [];
|
|
24201
|
+
const centralParts = [];
|
|
24202
|
+
let offset = 0;
|
|
24203
|
+
for (const entry of entries) {
|
|
24204
|
+
const data = await fs18.readFile(entry.absPath);
|
|
24205
|
+
const name = Buffer.from(entry.archivePath.split(path19.sep).join("/"), "utf8");
|
|
24206
|
+
const checksum = crc32(data);
|
|
24207
|
+
const { dosDate, dosTime } = zipDosDateTime(entry.updatedAt);
|
|
24208
|
+
const localHeader = Buffer.alloc(30);
|
|
24209
|
+
localHeader.writeUInt32LE(67324752, 0);
|
|
24210
|
+
localHeader.writeUInt16LE(20, 4);
|
|
24211
|
+
localHeader.writeUInt16LE(0, 6);
|
|
24212
|
+
localHeader.writeUInt16LE(0, 8);
|
|
24213
|
+
localHeader.writeUInt16LE(dosTime, 10);
|
|
24214
|
+
localHeader.writeUInt16LE(dosDate, 12);
|
|
24215
|
+
localHeader.writeUInt32LE(checksum, 14);
|
|
24216
|
+
localHeader.writeUInt32LE(data.length, 18);
|
|
24217
|
+
localHeader.writeUInt32LE(data.length, 22);
|
|
24218
|
+
localHeader.writeUInt16LE(name.length, 26);
|
|
24219
|
+
localHeader.writeUInt16LE(0, 28);
|
|
24220
|
+
localParts.push(localHeader, name, data);
|
|
24221
|
+
const centralHeader = Buffer.alloc(46);
|
|
24222
|
+
centralHeader.writeUInt32LE(33639248, 0);
|
|
24223
|
+
centralHeader.writeUInt16LE(20, 4);
|
|
24224
|
+
centralHeader.writeUInt16LE(20, 6);
|
|
24225
|
+
centralHeader.writeUInt16LE(0, 8);
|
|
24226
|
+
centralHeader.writeUInt16LE(0, 10);
|
|
24227
|
+
centralHeader.writeUInt16LE(dosTime, 12);
|
|
24228
|
+
centralHeader.writeUInt16LE(dosDate, 14);
|
|
24229
|
+
centralHeader.writeUInt32LE(checksum, 16);
|
|
24230
|
+
centralHeader.writeUInt32LE(data.length, 20);
|
|
24231
|
+
centralHeader.writeUInt32LE(data.length, 24);
|
|
24232
|
+
centralHeader.writeUInt16LE(name.length, 28);
|
|
24233
|
+
centralHeader.writeUInt16LE(0, 30);
|
|
24234
|
+
centralHeader.writeUInt16LE(0, 32);
|
|
24235
|
+
centralHeader.writeUInt16LE(0, 34);
|
|
24236
|
+
centralHeader.writeUInt16LE(0, 36);
|
|
24237
|
+
centralHeader.writeUInt32LE(0, 38);
|
|
24238
|
+
centralHeader.writeUInt32LE(offset, 42);
|
|
24239
|
+
centralParts.push(centralHeader, name);
|
|
24240
|
+
offset += localHeader.length + name.length + data.length;
|
|
24241
|
+
}
|
|
24242
|
+
const centralSize = centralParts.reduce((sum, part) => sum + part.length, 0);
|
|
24243
|
+
const endRecord = Buffer.alloc(22);
|
|
24244
|
+
endRecord.writeUInt32LE(101010256, 0);
|
|
24245
|
+
endRecord.writeUInt16LE(0, 4);
|
|
24246
|
+
endRecord.writeUInt16LE(0, 6);
|
|
24247
|
+
endRecord.writeUInt16LE(entries.length, 8);
|
|
24248
|
+
endRecord.writeUInt16LE(entries.length, 10);
|
|
24249
|
+
endRecord.writeUInt32LE(centralSize, 12);
|
|
24250
|
+
endRecord.writeUInt32LE(offset, 16);
|
|
24251
|
+
endRecord.writeUInt16LE(0, 20);
|
|
24252
|
+
const tempDir = await fs18.mkdtemp(path19.join(os4.tmpdir(), "remote-codex-folder-download-"));
|
|
24253
|
+
const zipPath = path19.join(tempDir, `${path19.basename(folderPath) || "workspace-folder"}.zip`);
|
|
24254
|
+
await fs18.writeFile(zipPath, Buffer.concat([...localParts, ...centralParts, endRecord]));
|
|
24255
|
+
return { zipPath, tempDir };
|
|
24256
|
+
}
|
|
24257
|
+
function cleanupTemporaryZip(zipPath, tempDir) {
|
|
24258
|
+
return async () => {
|
|
24259
|
+
await fs18.rm(zipPath, { force: true }).catch(() => void 0);
|
|
24260
|
+
await fs18.rm(tempDir, { recursive: true, force: true }).catch(() => void 0);
|
|
24261
|
+
};
|
|
24262
|
+
}
|
|
23446
24263
|
function sanitizeUploadFilename(filename) {
|
|
23447
|
-
const baseName =
|
|
24264
|
+
const baseName = path19.basename(filename?.trim() || "upload");
|
|
23448
24265
|
if (!baseName || baseName === "." || baseName === "..") {
|
|
23449
24266
|
return "upload";
|
|
23450
24267
|
}
|
|
@@ -23456,7 +24273,7 @@ function inferGitRepoName(gitUrl) {
|
|
|
23456
24273
|
const normalized = withoutQuery.replace(/[\\/]+$/, "");
|
|
23457
24274
|
const rawName = normalized.split(/[/:]/).filter(Boolean).at(-1) ?? "";
|
|
23458
24275
|
const repoName = rawName.endsWith(".git") ? rawName.slice(0, -4) : rawName;
|
|
23459
|
-
if (!repoName || repoName === "." || repoName === ".." || repoName.includes(
|
|
24276
|
+
if (!repoName || repoName === "." || repoName === ".." || repoName.includes(path19.sep)) {
|
|
23460
24277
|
throw new HttpError(400, {
|
|
23461
24278
|
code: "bad_request",
|
|
23462
24279
|
message: "Unable to infer a target directory from the Git URL."
|
|
@@ -23477,7 +24294,7 @@ async function pathExists4(absPath) {
|
|
|
23477
24294
|
}
|
|
23478
24295
|
function cloneRepository(gitUrl, targetPath) {
|
|
23479
24296
|
return new Promise((resolve, reject) => {
|
|
23480
|
-
const child =
|
|
24297
|
+
const child = spawn4("git", ["clone", gitUrl, targetPath], {
|
|
23481
24298
|
stdio: ["ignore", "ignore", "pipe"]
|
|
23482
24299
|
});
|
|
23483
24300
|
let stderr = "";
|
|
@@ -23521,7 +24338,7 @@ async function registerWorkspaceRoutes(app) {
|
|
|
23521
24338
|
});
|
|
23522
24339
|
app.get("/api/workspaces/tree", async (request) => {
|
|
23523
24340
|
const query = treeQuerySchema.parse(request.query);
|
|
23524
|
-
const requestedPath = query.path ?
|
|
24341
|
+
const requestedPath = query.path ? path19.resolve(query.path) : app.services.config.workspaceRoot;
|
|
23525
24342
|
const tree = await readWorkspaceTree({
|
|
23526
24343
|
rootPath: app.services.config.workspaceRoot,
|
|
23527
24344
|
targetPath: requestedPath,
|
|
@@ -23587,7 +24404,7 @@ async function registerWorkspaceRoutes(app) {
|
|
|
23587
24404
|
const nextOffset = offset + read.bytesRead;
|
|
23588
24405
|
return {
|
|
23589
24406
|
path: relativeWorkspacePath(rootPath, filePath),
|
|
23590
|
-
name:
|
|
24407
|
+
name: path19.basename(filePath),
|
|
23591
24408
|
content: buffer.subarray(0, read.bytesRead).toString("utf8"),
|
|
23592
24409
|
language: languageForPath(filePath),
|
|
23593
24410
|
size: stats.size,
|
|
@@ -23621,13 +24438,25 @@ async function registerWorkspaceRoutes(app) {
|
|
|
23621
24438
|
const rootPath = await fs18.realpath(record.absPath);
|
|
23622
24439
|
const itemPath = await resolveWorkspaceItemPath(rootPath, query.path);
|
|
23623
24440
|
const stats = await fs18.stat(itemPath);
|
|
24441
|
+
if (stats.isDirectory()) {
|
|
24442
|
+
const { zipPath, tempDir } = await createFolderZipFile(rootPath, itemPath);
|
|
24443
|
+
const filename2 = `${path19.basename(itemPath) || "workspace-folder"}.zip`;
|
|
24444
|
+
const cleanup = cleanupTemporaryZip(zipPath, tempDir);
|
|
24445
|
+
reply.raw.once("finish", () => void cleanup());
|
|
24446
|
+
reply.raw.once("close", () => void cleanup());
|
|
24447
|
+
reply.header("content-type", "application/zip").header(
|
|
24448
|
+
"content-disposition",
|
|
24449
|
+
`attachment; filename="${filename2}"; filename*=UTF-8''${encodeURIComponent(filename2)}`
|
|
24450
|
+
);
|
|
24451
|
+
return reply.send(createReadStream(zipPath));
|
|
24452
|
+
}
|
|
23624
24453
|
if (!stats.isFile()) {
|
|
23625
24454
|
throw new HttpError(400, {
|
|
23626
24455
|
code: "bad_request",
|
|
23627
|
-
message: "Only file downloads are supported from this endpoint."
|
|
24456
|
+
message: "Only file and folder downloads are supported from this endpoint."
|
|
23628
24457
|
});
|
|
23629
24458
|
}
|
|
23630
|
-
const filename =
|
|
24459
|
+
const filename = path19.basename(itemPath);
|
|
23631
24460
|
reply.header("content-type", contentTypeForPath(itemPath)).header(
|
|
23632
24461
|
"content-disposition",
|
|
23633
24462
|
`attachment; filename="${filename}"; filename*=UTF-8''${encodeURIComponent(filename)}`
|
|
@@ -23693,7 +24522,7 @@ async function registerWorkspaceRoutes(app) {
|
|
|
23693
24522
|
kind: "file",
|
|
23694
24523
|
file: {
|
|
23695
24524
|
path: file.path,
|
|
23696
|
-
name:
|
|
24525
|
+
name: path19.basename(file.path),
|
|
23697
24526
|
size: file.size
|
|
23698
24527
|
}
|
|
23699
24528
|
};
|
|
@@ -23735,7 +24564,7 @@ async function registerWorkspaceRoutes(app) {
|
|
|
23735
24564
|
message: "Artifact content must not be empty."
|
|
23736
24565
|
});
|
|
23737
24566
|
}
|
|
23738
|
-
const dir =
|
|
24567
|
+
const dir = path19.dirname(artifactFilePath(record, artifactId));
|
|
23739
24568
|
await fs18.mkdir(dir, { recursive: true, mode: 448 });
|
|
23740
24569
|
const filePath = artifactFilePath(record, artifactId);
|
|
23741
24570
|
await fs18.writeFile(filePath, content, { flag: "wx" }).catch((error) => {
|
|
@@ -23798,7 +24627,7 @@ async function registerWorkspaceRoutes(app) {
|
|
|
23798
24627
|
const params = z6.object({ id: z6.string().uuid(), artifactId: workspaceArtifactIdSchema }).parse(request.params);
|
|
23799
24628
|
const record = requireWorkspaceRecord(app, params.id);
|
|
23800
24629
|
const artifact = await readArtifactMetadata(record, params.artifactId);
|
|
23801
|
-
await fs18.rm(
|
|
24630
|
+
await fs18.rm(path19.dirname(artifactFilePath(record, params.artifactId)), {
|
|
23802
24631
|
recursive: true,
|
|
23803
24632
|
force: true
|
|
23804
24633
|
});
|
|
@@ -23813,7 +24642,7 @@ async function registerWorkspaceRoutes(app) {
|
|
|
23813
24642
|
let validated;
|
|
23814
24643
|
if ("gitUrl" in body) {
|
|
23815
24644
|
const repoName = inferGitRepoName(body.gitUrl);
|
|
23816
|
-
const targetPath =
|
|
24645
|
+
const targetPath = path19.join(settings.devHome, repoName);
|
|
23817
24646
|
if (await pathExists4(targetPath)) {
|
|
23818
24647
|
throw new HttpError(409, {
|
|
23819
24648
|
code: "conflict",
|
|
@@ -24077,7 +24906,7 @@ async function registerAuthRoutes(app) {
|
|
|
24077
24906
|
|
|
24078
24907
|
// src/provider-host-config-service.ts
|
|
24079
24908
|
import fs19 from "fs/promises";
|
|
24080
|
-
import
|
|
24909
|
+
import path20 from "path";
|
|
24081
24910
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
24082
24911
|
function providerError(message, statusCode = 404) {
|
|
24083
24912
|
const error = new Error(message);
|
|
@@ -24085,16 +24914,16 @@ function providerError(message, statusCode = 404) {
|
|
|
24085
24914
|
return error;
|
|
24086
24915
|
}
|
|
24087
24916
|
function resolveProviderHostFilePath(providerHome, name) {
|
|
24088
|
-
return
|
|
24917
|
+
return path20.join(providerHome, name);
|
|
24089
24918
|
}
|
|
24090
24919
|
function resolveArchiveRoot(providerHome) {
|
|
24091
|
-
return
|
|
24920
|
+
return path20.join(providerHome, "supervisor-config-archives");
|
|
24092
24921
|
}
|
|
24093
24922
|
function resolveArchiveIndexPath(providerHome) {
|
|
24094
|
-
return
|
|
24923
|
+
return path20.join(resolveArchiveRoot(providerHome), "index.json");
|
|
24095
24924
|
}
|
|
24096
24925
|
function resolveArchivePath(providerHome, archiveId) {
|
|
24097
|
-
return
|
|
24926
|
+
return path20.join(resolveArchiveRoot(providerHome), archiveId);
|
|
24098
24927
|
}
|
|
24099
24928
|
function defaultArchiveLabel(createdAt) {
|
|
24100
24929
|
return `Backup ${createdAt.replace("T", " ").replace(/\.\d{3}Z$/, " UTC")}`;
|
|
@@ -24147,44 +24976,44 @@ var ProviderHostConfigService = class {
|
|
|
24147
24976
|
}
|
|
24148
24977
|
agentRuntimes;
|
|
24149
24978
|
providerHomes;
|
|
24150
|
-
runtime(
|
|
24151
|
-
const runtime = this.agentRuntimes.getOptional(
|
|
24979
|
+
runtime(provider2) {
|
|
24980
|
+
const runtime = this.agentRuntimes.getOptional(provider2);
|
|
24152
24981
|
if (!runtime) {
|
|
24153
|
-
throw providerError(`Agent runtime provider is not configured: ${
|
|
24982
|
+
throw providerError(`Agent runtime provider is not configured: ${provider2}`);
|
|
24154
24983
|
}
|
|
24155
24984
|
return runtime;
|
|
24156
24985
|
}
|
|
24157
|
-
providerHome(
|
|
24158
|
-
const home = this.providerHomes[
|
|
24986
|
+
providerHome(provider2) {
|
|
24987
|
+
const home = this.providerHomes[provider2];
|
|
24159
24988
|
if (!home) {
|
|
24160
24989
|
throw providerError("This backend does not expose host config files.");
|
|
24161
24990
|
}
|
|
24162
24991
|
return home;
|
|
24163
24992
|
}
|
|
24164
|
-
hostFileNames(
|
|
24165
|
-
const runtime = this.runtime(
|
|
24993
|
+
hostFileNames(provider2) {
|
|
24994
|
+
const runtime = this.runtime(provider2);
|
|
24166
24995
|
if (!runtime.capabilities.management.hostConfigFiles) {
|
|
24167
24996
|
throw providerError("This backend does not expose host config files.");
|
|
24168
24997
|
}
|
|
24169
24998
|
return runtime.managementSchema.hostConfigFiles.map((file) => file.name);
|
|
24170
24999
|
}
|
|
24171
|
-
assertHostFile(
|
|
24172
|
-
const fileNames = this.hostFileNames(
|
|
25000
|
+
assertHostFile(provider2, name) {
|
|
25001
|
+
const fileNames = this.hostFileNames(provider2);
|
|
24173
25002
|
if (!fileNames.includes(name)) {
|
|
24174
25003
|
throw providerError("Host config file is not exposed by this backend.", 400);
|
|
24175
25004
|
}
|
|
24176
25005
|
return name;
|
|
24177
25006
|
}
|
|
24178
|
-
archiveFileNames(
|
|
24179
|
-
const runtime = this.runtime(
|
|
25007
|
+
archiveFileNames(provider2) {
|
|
25008
|
+
const runtime = this.runtime(provider2);
|
|
24180
25009
|
if (!runtime.managementSchema.configArchives) {
|
|
24181
25010
|
throw providerError("This backend does not support config archives.");
|
|
24182
25011
|
}
|
|
24183
|
-
return this.hostFileNames(
|
|
25012
|
+
return this.hostFileNames(provider2);
|
|
24184
25013
|
}
|
|
24185
|
-
async readFile(
|
|
24186
|
-
const providerHome = this.providerHome(
|
|
24187
|
-
const fileName = this.assertHostFile(
|
|
25014
|
+
async readFile(provider2, name) {
|
|
25015
|
+
const providerHome = this.providerHome(provider2);
|
|
25016
|
+
const fileName = this.assertHostFile(provider2, name);
|
|
24188
25017
|
const filePath = resolveProviderHostFilePath(providerHome, fileName);
|
|
24189
25018
|
try {
|
|
24190
25019
|
const content = await fs19.readFile(filePath, "utf8");
|
|
@@ -24206,25 +25035,25 @@ var ProviderHostConfigService = class {
|
|
|
24206
25035
|
};
|
|
24207
25036
|
}
|
|
24208
25037
|
}
|
|
24209
|
-
async updateFile(
|
|
24210
|
-
const providerHome = this.providerHome(
|
|
24211
|
-
const fileName = this.assertHostFile(
|
|
25038
|
+
async updateFile(provider2, name, input) {
|
|
25039
|
+
const providerHome = this.providerHome(provider2);
|
|
25040
|
+
const fileName = this.assertHostFile(provider2, name);
|
|
24212
25041
|
const filePath = resolveProviderHostFilePath(providerHome, fileName);
|
|
24213
|
-
await fs19.mkdir(
|
|
25042
|
+
await fs19.mkdir(path20.dirname(filePath), { recursive: true });
|
|
24214
25043
|
await fs19.writeFile(filePath, input.content, "utf8");
|
|
24215
|
-
return this.readFile(
|
|
25044
|
+
return this.readFile(provider2, fileName);
|
|
24216
25045
|
}
|
|
24217
|
-
async listArchives(
|
|
24218
|
-
const runtime = this.runtime(
|
|
25046
|
+
async listArchives(provider2) {
|
|
25047
|
+
const runtime = this.runtime(provider2);
|
|
24219
25048
|
if (!runtime.managementSchema.configArchives) {
|
|
24220
25049
|
return [];
|
|
24221
25050
|
}
|
|
24222
|
-
const index = await readArchiveIndex(this.providerHome(
|
|
25051
|
+
const index = await readArchiveIndex(this.providerHome(provider2));
|
|
24223
25052
|
return index.archives;
|
|
24224
25053
|
}
|
|
24225
|
-
async createArchive(
|
|
24226
|
-
const providerHome = this.providerHome(
|
|
24227
|
-
const fileNames = this.archiveFileNames(
|
|
25054
|
+
async createArchive(provider2, input) {
|
|
25055
|
+
const providerHome = this.providerHome(provider2);
|
|
25056
|
+
const fileNames = this.archiveFileNames(provider2);
|
|
24228
25057
|
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
24229
25058
|
const id = `${createdAt.replace(/[-:.TZ]/g, "").slice(0, 14)}-${randomUUID4().slice(0, 8)}`;
|
|
24230
25059
|
const archivePath = resolveArchivePath(providerHome, id);
|
|
@@ -24239,13 +25068,13 @@ var ProviderHostConfigService = class {
|
|
|
24239
25068
|
);
|
|
24240
25069
|
await fs19.mkdir(archivePath, { recursive: true });
|
|
24241
25070
|
for (const name of fileNames) {
|
|
24242
|
-
const hostFile = await this.readFile(
|
|
25071
|
+
const hostFile = await this.readFile(provider2, name);
|
|
24243
25072
|
files[name] = {
|
|
24244
25073
|
name,
|
|
24245
25074
|
exists: hostFile.exists
|
|
24246
25075
|
};
|
|
24247
25076
|
if (hostFile.exists) {
|
|
24248
|
-
await fs19.writeFile(
|
|
25077
|
+
await fs19.writeFile(path20.join(archivePath, name), hostFile.content, "utf8");
|
|
24249
25078
|
}
|
|
24250
25079
|
}
|
|
24251
25080
|
const archive = {
|
|
@@ -24261,9 +25090,9 @@ var ProviderHostConfigService = class {
|
|
|
24261
25090
|
});
|
|
24262
25091
|
return archive;
|
|
24263
25092
|
}
|
|
24264
|
-
async renameArchive(
|
|
24265
|
-
const providerHome = this.providerHome(
|
|
24266
|
-
this.archiveFileNames(
|
|
25093
|
+
async renameArchive(provider2, id, input) {
|
|
25094
|
+
const providerHome = this.providerHome(provider2);
|
|
25095
|
+
this.archiveFileNames(provider2);
|
|
24267
25096
|
const { index, archive } = await findArchiveOrThrow(providerHome, id);
|
|
24268
25097
|
const updated = {
|
|
24269
25098
|
...archive,
|
|
@@ -24275,17 +25104,17 @@ var ProviderHostConfigService = class {
|
|
|
24275
25104
|
});
|
|
24276
25105
|
return updated;
|
|
24277
25106
|
}
|
|
24278
|
-
async applyArchive(
|
|
24279
|
-
const runtime = this.runtime(
|
|
24280
|
-
const providerHome = this.providerHome(
|
|
24281
|
-
const fileNames = this.archiveFileNames(
|
|
25107
|
+
async applyArchive(provider2, id) {
|
|
25108
|
+
const runtime = this.runtime(provider2);
|
|
25109
|
+
const providerHome = this.providerHome(provider2);
|
|
25110
|
+
const fileNames = this.archiveFileNames(provider2);
|
|
24282
25111
|
const { archive } = await findArchiveOrThrow(providerHome, id);
|
|
24283
25112
|
const archivePath = resolveArchivePath(providerHome, archive.id);
|
|
24284
25113
|
await fs19.mkdir(providerHome, { recursive: true });
|
|
24285
25114
|
for (const name of fileNames) {
|
|
24286
25115
|
const hostPath = resolveProviderHostFilePath(providerHome, name);
|
|
24287
25116
|
if (archive.files[name]?.exists) {
|
|
24288
|
-
const content = await fs19.readFile(
|
|
25117
|
+
const content = await fs19.readFile(path20.join(archivePath, name), "utf8");
|
|
24289
25118
|
await fs19.writeFile(hostPath, content, "utf8");
|
|
24290
25119
|
} else {
|
|
24291
25120
|
await fs19.rm(hostPath, { force: true });
|
|
@@ -24305,8 +25134,8 @@ import fs21 from "fs/promises";
|
|
|
24305
25134
|
|
|
24306
25135
|
// src/shell/shell-prompt.ts
|
|
24307
25136
|
import fs20 from "fs/promises";
|
|
24308
|
-
import
|
|
24309
|
-
import
|
|
25137
|
+
import os5 from "os";
|
|
25138
|
+
import path21 from "path";
|
|
24310
25139
|
function basenameFromPath2(filePath) {
|
|
24311
25140
|
if (!filePath) {
|
|
24312
25141
|
return "";
|
|
@@ -24315,7 +25144,7 @@ function basenameFromPath2(filePath) {
|
|
|
24315
25144
|
if (!normalized) {
|
|
24316
25145
|
return "";
|
|
24317
25146
|
}
|
|
24318
|
-
return
|
|
25147
|
+
return path21.basename(normalized) || normalized;
|
|
24319
25148
|
}
|
|
24320
25149
|
function isInteractiveShellCommand(command) {
|
|
24321
25150
|
const normalized = (command ?? "").trim().toLowerCase();
|
|
@@ -24476,8 +25305,8 @@ function buildShellPromptInitScriptContents(command) {
|
|
|
24476
25305
|
async function ensureShellPromptInitScript(command) {
|
|
24477
25306
|
const normalized = command.trim().toLowerCase();
|
|
24478
25307
|
const extension = normalized === "zsh" ? "zsh" : "sh";
|
|
24479
|
-
const filePath =
|
|
24480
|
-
|
|
25308
|
+
const filePath = path21.join(
|
|
25309
|
+
os5.tmpdir(),
|
|
24481
25310
|
`remote-codex-shell-prompt.${extension}`
|
|
24482
25311
|
);
|
|
24483
25312
|
await fs20.writeFile(filePath, buildShellPromptInitScriptContents(command), "utf8");
|
|
@@ -25159,7 +25988,7 @@ var builtinPlugins = [
|
|
|
25159
25988
|
|
|
25160
25989
|
// src/plugins/plugin-service.ts
|
|
25161
25990
|
import fs22 from "fs/promises";
|
|
25162
|
-
import
|
|
25991
|
+
import path22 from "path";
|
|
25163
25992
|
var MANAGED_CODEX_MCP_BEGIN = "# BEGIN remote-codex managed plugin MCP servers";
|
|
25164
25993
|
var MANAGED_CODEX_MCP_END = "# END remote-codex managed plugin MCP servers";
|
|
25165
25994
|
var REMOTE_CODEX_MOLECULE_MCP_TOOL_NAME = "remote_codex_render_molecule";
|
|
@@ -25171,7 +26000,7 @@ function normalizeManagedCommand(server, repoRoot) {
|
|
|
25171
26000
|
if (server.name === "remote_codex_plugins") {
|
|
25172
26001
|
return {
|
|
25173
26002
|
command: process.execPath,
|
|
25174
|
-
args: [
|
|
26003
|
+
args: [path22.join(repoRoot, "bin", "remote-codex-plugin-mcp.mjs")]
|
|
25175
26004
|
};
|
|
25176
26005
|
}
|
|
25177
26006
|
return {
|
|
@@ -25358,7 +26187,7 @@ var PluginService = class {
|
|
|
25358
26187
|
if (!input.codexHome) {
|
|
25359
26188
|
return;
|
|
25360
26189
|
}
|
|
25361
|
-
const configPath =
|
|
26190
|
+
const configPath = path22.join(input.codexHome, "config.toml");
|
|
25362
26191
|
let current = "";
|
|
25363
26192
|
try {
|
|
25364
26193
|
current = await fs22.readFile(configPath, "utf8");
|
|
@@ -25376,7 +26205,7 @@ var PluginService = class {
|
|
|
25376
26205
|
if (next === current) {
|
|
25377
26206
|
return;
|
|
25378
26207
|
}
|
|
25379
|
-
await fs22.mkdir(
|
|
26208
|
+
await fs22.mkdir(path22.dirname(configPath), { recursive: true });
|
|
25380
26209
|
await fs22.writeFile(configPath, next, "utf8");
|
|
25381
26210
|
}
|
|
25382
26211
|
async importPlugin(input) {
|
|
@@ -25617,7 +26446,7 @@ var PluginSettingsStore = class {
|
|
|
25617
26446
|
|
|
25618
26447
|
// src/worker-bootstrap.ts
|
|
25619
26448
|
import fs23 from "fs/promises";
|
|
25620
|
-
import
|
|
26449
|
+
import path23 from "path";
|
|
25621
26450
|
function trimTrailingSlash(value) {
|
|
25622
26451
|
return value.replace(/\/+$/, "");
|
|
25623
26452
|
}
|
|
@@ -25628,7 +26457,7 @@ function tomlString(value) {
|
|
|
25628
26457
|
return JSON.stringify(value);
|
|
25629
26458
|
}
|
|
25630
26459
|
async function writePrivateFile(filePath, content) {
|
|
25631
|
-
await fs23.mkdir(
|
|
26460
|
+
await fs23.mkdir(path23.dirname(filePath), { recursive: true, mode: 448 });
|
|
25632
26461
|
await fs23.writeFile(filePath, content, { encoding: "utf8", mode: 384 });
|
|
25633
26462
|
await fs23.chmod(filePath, 384);
|
|
25634
26463
|
}
|
|
@@ -25644,7 +26473,7 @@ async function configureWorkerProviderGateway(config) {
|
|
|
25644
26473
|
process.env.ANTHROPIC_BASE_URL = anthropicBaseUrl;
|
|
25645
26474
|
if (config.agentProviders.codex.enabled) {
|
|
25646
26475
|
await writePrivateFile(
|
|
25647
|
-
|
|
26476
|
+
path23.join(config.agentProviders.codex.home, "config.toml"),
|
|
25648
26477
|
[
|
|
25649
26478
|
'model_provider = "sub2api"',
|
|
25650
26479
|
'forced_login_method = "api"',
|
|
@@ -25660,7 +26489,7 @@ async function configureWorkerProviderGateway(config) {
|
|
|
25660
26489
|
].join("\n")
|
|
25661
26490
|
);
|
|
25662
26491
|
await writePrivateFile(
|
|
25663
|
-
|
|
26492
|
+
path23.join(config.agentProviders.codex.home, "auth.json"),
|
|
25664
26493
|
`${JSON.stringify(
|
|
25665
26494
|
{
|
|
25666
26495
|
OPENAI_API_KEY: config.llmGatewayToken
|
|
@@ -25673,7 +26502,7 @@ async function configureWorkerProviderGateway(config) {
|
|
|
25673
26502
|
}
|
|
25674
26503
|
if (config.agentProviders.claude.enabled) {
|
|
25675
26504
|
await writePrivateFile(
|
|
25676
|
-
|
|
26505
|
+
path23.join(config.agentProviders.claude.home, "settings.json"),
|
|
25677
26506
|
`${JSON.stringify(
|
|
25678
26507
|
{
|
|
25679
26508
|
env: {
|
|
@@ -25689,7 +26518,7 @@ async function configureWorkerProviderGateway(config) {
|
|
|
25689
26518
|
}
|
|
25690
26519
|
if (config.agentProviders.opencode.enabled) {
|
|
25691
26520
|
await writePrivateFile(
|
|
25692
|
-
|
|
26521
|
+
path23.join(config.agentProviders.opencode.home, "opencode.json"),
|
|
25693
26522
|
`${JSON.stringify(
|
|
25694
26523
|
{
|
|
25695
26524
|
provider: {
|
|
@@ -25736,8 +26565,8 @@ var BackendPluginHost = class {
|
|
|
25736
26565
|
};
|
|
25737
26566
|
|
|
25738
26567
|
// src/shell/pty-shell-backend.ts
|
|
25739
|
-
import
|
|
25740
|
-
import { spawn as
|
|
26568
|
+
import path24 from "path";
|
|
26569
|
+
import { spawn as spawn5 } from "@homebridge/node-pty-prebuilt-multiarch";
|
|
25741
26570
|
|
|
25742
26571
|
// src/shell/default-shell.ts
|
|
25743
26572
|
import fs24 from "fs";
|
|
@@ -25756,7 +26585,7 @@ function resolveDefaultShell(env = process.env) {
|
|
|
25756
26585
|
var MAX_SCROLLBACK_BYTES = 512 * 1024;
|
|
25757
26586
|
var ANSI_ESCAPE_PATTERN = new RegExp(String.raw`\u001B\[[0-?]*[ -/]*[@-~]`, "g");
|
|
25758
26587
|
function shellArgs(shell) {
|
|
25759
|
-
const shellName =
|
|
26588
|
+
const shellName = path24.basename(shell).toLowerCase();
|
|
25760
26589
|
if (process.platform === "win32") {
|
|
25761
26590
|
return [];
|
|
25762
26591
|
}
|
|
@@ -25778,7 +26607,7 @@ function lastVisibleLine(snapshot) {
|
|
|
25778
26607
|
}
|
|
25779
26608
|
function inferRuntime(session) {
|
|
25780
26609
|
const promptLine = lastVisibleLine(session.scrollback);
|
|
25781
|
-
const shell =
|
|
26610
|
+
const shell = path24.basename(session.shell);
|
|
25782
26611
|
const isCommandRunning = session.exitCode !== null ? false : !/[$#>]\s*$/.test(promptLine.trimEnd());
|
|
25783
26612
|
return {
|
|
25784
26613
|
panePid: session.pty.pid,
|
|
@@ -25806,7 +26635,7 @@ var PtyShellBackend = class {
|
|
|
25806
26635
|
if (this.sessions.has(input.sessionId)) {
|
|
25807
26636
|
return;
|
|
25808
26637
|
}
|
|
25809
|
-
const pty =
|
|
26638
|
+
const pty = spawn5(this.shell, shellArgs(this.shell), {
|
|
25810
26639
|
name: "xterm-256color",
|
|
25811
26640
|
cwd: input.cwd,
|
|
25812
26641
|
cols: input.cols ?? 120,
|
|
@@ -25925,7 +26754,7 @@ var PtyShellBackend = class {
|
|
|
25925
26754
|
|
|
25926
26755
|
// src/shell/tmux-manager.ts
|
|
25927
26756
|
import fs25 from "fs";
|
|
25928
|
-
import
|
|
26757
|
+
import path25 from "path";
|
|
25929
26758
|
import { spawn as spawnChild } from "child_process";
|
|
25930
26759
|
async function defaultExecCommand(command, args) {
|
|
25931
26760
|
return await new Promise((resolve, reject) => {
|
|
@@ -25952,16 +26781,16 @@ async function defaultExecCommand(command, args) {
|
|
|
25952
26781
|
});
|
|
25953
26782
|
}
|
|
25954
26783
|
function resolveExecutablePath(command) {
|
|
25955
|
-
if (command.includes(
|
|
26784
|
+
if (command.includes(path25.sep)) {
|
|
25956
26785
|
return command;
|
|
25957
26786
|
}
|
|
25958
26787
|
const searchPath = process.env.PATH ?? "";
|
|
25959
|
-
for (const entry of searchPath.split(
|
|
26788
|
+
for (const entry of searchPath.split(path25.delimiter)) {
|
|
25960
26789
|
const trimmed = entry.trim();
|
|
25961
26790
|
if (!trimmed) {
|
|
25962
26791
|
continue;
|
|
25963
26792
|
}
|
|
25964
|
-
const candidate =
|
|
26793
|
+
const candidate = path25.join(trimmed, command);
|
|
25965
26794
|
if (fs25.existsSync(candidate)) {
|
|
25966
26795
|
return candidate;
|
|
25967
26796
|
}
|
|
@@ -26720,22 +27549,22 @@ function payloadItems(payload, fields) {
|
|
|
26720
27549
|
const record = recordFrom(payload);
|
|
26721
27550
|
return arrayField(record, fields) ?? (record ? [record] : []);
|
|
26722
27551
|
}
|
|
26723
|
-
function artifactPreviewKind(type, format,
|
|
27552
|
+
function artifactPreviewKind(type, format, path27) {
|
|
26724
27553
|
const candidates = [
|
|
26725
27554
|
type,
|
|
26726
27555
|
format,
|
|
26727
|
-
|
|
27556
|
+
path27?.split(".").pop() ?? null
|
|
26728
27557
|
].map((value) => value?.trim().toLowerCase()).filter(Boolean);
|
|
26729
27558
|
return candidates.some((value) => MOLECULE_ARTIFACT_TYPES.has(value)) ? "molecule" : "file";
|
|
26730
27559
|
}
|
|
26731
27560
|
function normalizeArtifactRef(value) {
|
|
26732
27561
|
const record = recordFrom(value);
|
|
26733
|
-
const
|
|
27562
|
+
const path27 = stringField3(record, ["path", "filePath", "file_path", "filename", "fileName", "name"]);
|
|
26734
27563
|
const type = stringField3(record, ["type", "artifactType", "artifact_type", "format", "extension"]);
|
|
26735
|
-
const title = stringField3(record, ["title", "label", "name", "filename", "fileName"]) ??
|
|
27564
|
+
const title = stringField3(record, ["title", "label", "name", "filename", "fileName"]) ?? path27 ?? "artifact";
|
|
26736
27565
|
return {
|
|
26737
27566
|
title,
|
|
26738
|
-
path:
|
|
27567
|
+
path: path27,
|
|
26739
27568
|
type,
|
|
26740
27569
|
downloadUrl: stringField3(record, ["downloadUrl", "download_url", "url", "href"])
|
|
26741
27570
|
};
|
|
@@ -26769,21 +27598,21 @@ function normalizeArtifact(module, runId, value) {
|
|
|
26769
27598
|
if (!record) {
|
|
26770
27599
|
return null;
|
|
26771
27600
|
}
|
|
26772
|
-
const
|
|
27601
|
+
const path27 = stringField3(record, ["path", "filePath", "file_path", "filename", "fileName", "name"]);
|
|
26773
27602
|
const type = stringField3(record, ["type", "artifactType", "artifact_type"]);
|
|
26774
27603
|
const format = stringField3(record, ["format", "fileFormat", "file_format", "extension"]) ?? type;
|
|
26775
|
-
const title = stringField3(record, ["title", "label", "name", "filename", "fileName"]) ??
|
|
27604
|
+
const title = stringField3(record, ["title", "label", "name", "filename", "fileName"]) ?? path27 ?? `${module} artifact`;
|
|
26776
27605
|
return {
|
|
26777
27606
|
module,
|
|
26778
27607
|
runId,
|
|
26779
27608
|
title,
|
|
26780
|
-
path:
|
|
27609
|
+
path: path27,
|
|
26781
27610
|
type,
|
|
26782
27611
|
format,
|
|
26783
27612
|
mimeType: stringField3(record, ["mimeType", "mime_type", "contentType", "content_type"]),
|
|
26784
27613
|
sizeBytes: numberField2(record, ["sizeBytes", "size_bytes", "bytes"]),
|
|
26785
27614
|
downloadUrl: stringField3(record, ["downloadUrl", "download_url", "url", "href"]),
|
|
26786
|
-
previewKind: artifactPreviewKind(type, format,
|
|
27615
|
+
previewKind: artifactPreviewKind(type, format, path27)
|
|
26787
27616
|
};
|
|
26788
27617
|
}
|
|
26789
27618
|
function normalizeRuns(module, result) {
|
|
@@ -26910,9 +27739,9 @@ var WorkerHarnessClient = class {
|
|
|
26910
27739
|
}
|
|
26911
27740
|
return { baseUrl, apiKey };
|
|
26912
27741
|
}
|
|
26913
|
-
async fetchText(
|
|
27742
|
+
async fetchText(path27) {
|
|
26914
27743
|
const config = this.requireHarnessConfig();
|
|
26915
|
-
const response = await this.fetchImpl(`${config.baseUrl}${
|
|
27744
|
+
const response = await this.fetchImpl(`${config.baseUrl}${path27}`, {
|
|
26916
27745
|
headers: {
|
|
26917
27746
|
"x-api-key": config.apiKey
|
|
26918
27747
|
}
|
|
@@ -26923,11 +27752,11 @@ var WorkerHarnessClient = class {
|
|
|
26923
27752
|
}
|
|
26924
27753
|
return { text: text2 };
|
|
26925
27754
|
}
|
|
26926
|
-
async fetchPayload(
|
|
27755
|
+
async fetchPayload(path27, init = {}) {
|
|
26927
27756
|
const config = this.requireHarnessConfig();
|
|
26928
27757
|
const headers = new Headers(init.headers);
|
|
26929
27758
|
headers.set("x-api-key", config.apiKey);
|
|
26930
|
-
const response = await this.fetchImpl(`${config.baseUrl}${
|
|
27759
|
+
const response = await this.fetchImpl(`${config.baseUrl}${path27}`, {
|
|
26931
27760
|
...init,
|
|
26932
27761
|
headers
|
|
26933
27762
|
});
|
|
@@ -26941,9 +27770,9 @@ var WorkerHarnessClient = class {
|
|
|
26941
27770
|
return { text: text2 };
|
|
26942
27771
|
}
|
|
26943
27772
|
}
|
|
26944
|
-
async fetchBinary(
|
|
27773
|
+
async fetchBinary(path27) {
|
|
26945
27774
|
const config = this.requireHarnessConfig();
|
|
26946
|
-
const response = await this.fetchImpl(`${config.baseUrl}${
|
|
27775
|
+
const response = await this.fetchImpl(`${config.baseUrl}${path27}`, {
|
|
26947
27776
|
headers: {
|
|
26948
27777
|
"x-api-key": config.apiKey
|
|
26949
27778
|
}
|
|
@@ -27488,16 +28317,16 @@ var HttpError = class extends Error {
|
|
|
27488
28317
|
};
|
|
27489
28318
|
function findRepoRoot(start = process.cwd()) {
|
|
27490
28319
|
if (process.env.REMOTE_CODEX_REPO_ROOT) {
|
|
27491
|
-
return
|
|
28320
|
+
return path26.resolve(process.env.REMOTE_CODEX_REPO_ROOT);
|
|
27492
28321
|
}
|
|
27493
|
-
let current =
|
|
27494
|
-
while (current !==
|
|
27495
|
-
if (fs26.existsSync(
|
|
28322
|
+
let current = path26.resolve(start);
|
|
28323
|
+
while (current !== path26.dirname(current)) {
|
|
28324
|
+
if (fs26.existsSync(path26.join(current, "pnpm-workspace.yaml")) && fs26.existsSync(path26.join(current, "scripts", "service-restart.mjs"))) {
|
|
27496
28325
|
return current;
|
|
27497
28326
|
}
|
|
27498
|
-
current =
|
|
28327
|
+
current = path26.dirname(current);
|
|
27499
28328
|
}
|
|
27500
|
-
return
|
|
28329
|
+
return path26.resolve(process.cwd());
|
|
27501
28330
|
}
|
|
27502
28331
|
function createServiceLifecycle() {
|
|
27503
28332
|
return {
|
|
@@ -27509,14 +28338,14 @@ function createServiceLifecycle() {
|
|
|
27509
28338
|
});
|
|
27510
28339
|
}
|
|
27511
28340
|
const repoRoot = findRepoRoot();
|
|
27512
|
-
const restartScript =
|
|
27513
|
-
if (!fs26.existsSync(restartScript) || !fs26.existsSync(
|
|
28341
|
+
const restartScript = path26.join(repoRoot, "scripts", "service-restart.mjs");
|
|
28342
|
+
if (!fs26.existsSync(restartScript) || !fs26.existsSync(path26.join(repoRoot, "pnpm-workspace.yaml"))) {
|
|
27514
28343
|
throw new HttpError(503, {
|
|
27515
28344
|
code: "service_unavailable",
|
|
27516
28345
|
message: "Build and restart requires a Remote Codex source checkout. Set REMOTE_CODEX_REPO_ROOT to the checkout path, or update the npm package with npm install -g remote-codex@latest."
|
|
27517
28346
|
});
|
|
27518
28347
|
}
|
|
27519
|
-
const child =
|
|
28348
|
+
const child = spawn6(process.execPath, [restartScript, "launch"], {
|
|
27520
28349
|
cwd: repoRoot,
|
|
27521
28350
|
detached: true,
|
|
27522
28351
|
env: process.env,
|
|
@@ -27652,9 +28481,10 @@ function buildApp(options = {}) {
|
|
|
27652
28481
|
});
|
|
27653
28482
|
},
|
|
27654
28483
|
wsHandler: (socket, request) => {
|
|
28484
|
+
const supervisorSocket = socket;
|
|
27655
28485
|
const session = authService.verifyRequest(request);
|
|
27656
28486
|
if (!session.authenticated) {
|
|
27657
|
-
|
|
28487
|
+
supervisorSocket.close(1008, "Authentication is required.");
|
|
27658
28488
|
return;
|
|
27659
28489
|
}
|
|
27660
28490
|
const supervisorSession = createSupervisorSocketSession({
|
|
@@ -27662,15 +28492,15 @@ function buildApp(options = {}) {
|
|
|
27662
28492
|
eventBus,
|
|
27663
28493
|
backendPluginHost,
|
|
27664
28494
|
send(message) {
|
|
27665
|
-
if (
|
|
27666
|
-
|
|
28495
|
+
if (supervisorSocket.readyState === 1) {
|
|
28496
|
+
supervisorSocket.send(JSON.stringify(message));
|
|
27667
28497
|
}
|
|
27668
28498
|
}
|
|
27669
28499
|
});
|
|
27670
|
-
|
|
28500
|
+
supervisorSocket.on("message", async (rawMessage) => {
|
|
27671
28501
|
await supervisorSession.handleMessage(rawMessage.toString());
|
|
27672
28502
|
});
|
|
27673
|
-
|
|
28503
|
+
supervisorSocket.on("close", () => {
|
|
27674
28504
|
supervisorSession.close();
|
|
27675
28505
|
});
|
|
27676
28506
|
}
|
|
@@ -27829,13 +28659,39 @@ function createRelayRequestHandler(app) {
|
|
|
27829
28659
|
},
|
|
27830
28660
|
...payload !== void 0 ? { payload } : {}
|
|
27831
28661
|
});
|
|
28662
|
+
const responseBody = relayResponseBody(response);
|
|
27832
28663
|
return {
|
|
27833
28664
|
statusCode: response.statusCode,
|
|
27834
28665
|
headers: relayResponseHeaders(response.headers),
|
|
27835
|
-
body:
|
|
28666
|
+
body: responseBody.body,
|
|
28667
|
+
...responseBody.bodyEncoding ? { bodyEncoding: responseBody.bodyEncoding } : {}
|
|
27836
28668
|
};
|
|
27837
28669
|
};
|
|
27838
28670
|
}
|
|
28671
|
+
function relayResponseBody(response) {
|
|
28672
|
+
const contentType = responseHeader(response.headers, "content-type");
|
|
28673
|
+
if (isTextRelayResponse(contentType)) {
|
|
28674
|
+
return { body: response.body };
|
|
28675
|
+
}
|
|
28676
|
+
return {
|
|
28677
|
+
body: response.rawPayload.toString("base64"),
|
|
28678
|
+
bodyEncoding: "base64"
|
|
28679
|
+
};
|
|
28680
|
+
}
|
|
28681
|
+
function responseHeader(headers, name) {
|
|
28682
|
+
const lowerName = name.toLowerCase();
|
|
28683
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
28684
|
+
if (key.toLowerCase() !== lowerName || value === void 0) {
|
|
28685
|
+
continue;
|
|
28686
|
+
}
|
|
28687
|
+
return Array.isArray(value) ? value.join(", ") : String(value);
|
|
28688
|
+
}
|
|
28689
|
+
return "";
|
|
28690
|
+
}
|
|
28691
|
+
function isTextRelayResponse(contentType) {
|
|
28692
|
+
const lower = contentType.toLowerCase();
|
|
28693
|
+
return lower.startsWith("text/") || lower.includes("application/json") || lower.includes("+json") || lower.includes("application/javascript") || lower.includes("application/xml") || lower.includes("+xml") || lower.includes("image/svg+xml");
|
|
28694
|
+
}
|
|
27839
28695
|
function createSupervisorSocketSession(input) {
|
|
27840
28696
|
const closeHandlers = [];
|
|
27841
28697
|
const socketState = /* @__PURE__ */ new Map();
|