orkestrator 2.27.0-beta → 2.28.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client.js +116 -115
- package/dist/main.js +5324 -2513
- package/package.json +4 -4
- package/resources/claude-bridge/dist/index.js +35 -9
- package/resources/codex-bridge/dist/index.js +223 -22
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "orkestrator",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.28.0-beta",
|
|
4
4
|
"description": "Run the Orkestrator backend service without the desktop application",
|
|
5
5
|
"homepage": "https://orkestrator.dev",
|
|
6
6
|
"repository": {
|
|
@@ -34,13 +34,13 @@
|
|
|
34
34
|
"typecheck": "bunx tsc --noEmit -p tsconfig.json"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
37
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.309",
|
|
38
38
|
"playwright-core": "1.64.0",
|
|
39
39
|
"sharp": "0.35.5"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@orkestrator/protocol": "2.
|
|
43
|
-
"@orkestrator/toolchain": "2.
|
|
42
|
+
"@orkestrator/protocol": "2.28.0-beta",
|
|
43
|
+
"@orkestrator/toolchain": "2.28.0-beta"
|
|
44
44
|
},
|
|
45
45
|
"engines": {
|
|
46
46
|
"bun": ">=1.4.3"
|
|
@@ -3344,6 +3344,24 @@ function createStructuredUsageRefreshCoordinator(session, queryControl) {
|
|
|
3344
3344
|
}
|
|
3345
3345
|
};
|
|
3346
3346
|
}
|
|
3347
|
+
var CLAUDE_CONTEXT_CATEGORY_IDS = {
|
|
3348
|
+
system_prompt: "system-prompt",
|
|
3349
|
+
system_tools: "tools",
|
|
3350
|
+
system_tools_deferred: "deferred-tools",
|
|
3351
|
+
mcp_tools: "mcp-tools",
|
|
3352
|
+
mcp_tools_deferred: "deferred-mcp-tools",
|
|
3353
|
+
mcp_instructions: "mcp-instructions",
|
|
3354
|
+
custom_agents: "agents",
|
|
3355
|
+
memory_files: "memory",
|
|
3356
|
+
skills: "skills",
|
|
3357
|
+
messages: "messages",
|
|
3358
|
+
autocompact_buffer: "reserved",
|
|
3359
|
+
compact_buffer: "reserved",
|
|
3360
|
+
free_space: "free-space"
|
|
3361
|
+
};
|
|
3362
|
+
function claudeContextCategoryId(value) {
|
|
3363
|
+
return typeof value === "string" && Object.hasOwn(CLAUDE_CONTEXT_CATEGORY_IDS, value) ? CLAUDE_CONTEXT_CATEGORY_IDS[value] : undefined;
|
|
3364
|
+
}
|
|
3347
3365
|
function parseClaudeContextUsage(raw) {
|
|
3348
3366
|
if (!raw || typeof raw !== "object")
|
|
3349
3367
|
return;
|
|
@@ -3361,8 +3379,10 @@ function parseClaudeContextUsage(raw) {
|
|
|
3361
3379
|
const tokens = parseTokenValue(item.tokens);
|
|
3362
3380
|
if (!name || tokens === undefined)
|
|
3363
3381
|
return [];
|
|
3382
|
+
const id = claudeContextCategoryId(item.id);
|
|
3364
3383
|
return [
|
|
3365
3384
|
{
|
|
3385
|
+
...id ? { id } : {},
|
|
3366
3386
|
name,
|
|
3367
3387
|
tokens,
|
|
3368
3388
|
color: typeof item.color === "string" ? item.color : undefined
|
|
@@ -3502,6 +3522,7 @@ async function buildClaudeUsageSnapshot(session, result, queryControl, fallbackM
|
|
|
3502
3522
|
const turnId = typeof result.user_message_uuid === "string" && result.user_message_uuid.trim() || typeof result.uuid === "string" && result.uuid.trim() || `claude-turn-${session.latestTurnGeneration ?? updatedAt}`;
|
|
3503
3523
|
const turn = {
|
|
3504
3524
|
turnId,
|
|
3525
|
+
at: updatedAt,
|
|
3505
3526
|
costUsd: totals.cost,
|
|
3506
3527
|
inputTokens: totals.input,
|
|
3507
3528
|
outputTokens: totals.output,
|
|
@@ -4392,6 +4413,15 @@ var OPTIONAL_PROJECTION_FIELD_SET = new Set([
|
|
|
4392
4413
|
"slashCommandCatalogue"
|
|
4393
4414
|
]);
|
|
4394
4415
|
|
|
4416
|
+
// ../../bridges/claude-bridge/src/services/mcp-tool-prefix.ts
|
|
4417
|
+
function claudeMcpToolPrefix(name) {
|
|
4418
|
+
let normalized = name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
4419
|
+
if (name.startsWith("claude.ai ")) {
|
|
4420
|
+
normalized = normalized.replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
4421
|
+
}
|
|
4422
|
+
return `mcp__${normalized}__`;
|
|
4423
|
+
}
|
|
4424
|
+
|
|
4395
4425
|
// ../../bridges/claude-bridge/src/services/read-only-policy.ts
|
|
4396
4426
|
var CAPABILITY_TOOLS = new Map([
|
|
4397
4427
|
["file.write", ["Write", "NotebookEdit"]],
|
|
@@ -4417,8 +4447,7 @@ var WAITING_TOOLS = new Set([
|
|
|
4417
4447
|
"CronCreate",
|
|
4418
4448
|
"CronList",
|
|
4419
4449
|
"CronDelete",
|
|
4420
|
-
"SendMessage"
|
|
4421
|
-
"TaskOutput"
|
|
4450
|
+
"SendMessage"
|
|
4422
4451
|
]);
|
|
4423
4452
|
var READ_ONLY_COMMANDS = Object.freeze(new Set([
|
|
4424
4453
|
"awk",
|
|
@@ -4607,8 +4636,8 @@ function claudeReadOnlyAllowedTools(options) {
|
|
|
4607
4636
|
return [
|
|
4608
4637
|
...READ_ONLY_TOOLS,
|
|
4609
4638
|
...options.policy && !nativeAgentPolicyDeniesWebSearch(options.policy) ? ["WebSearch"] : [],
|
|
4610
|
-
...(options.agentMcpServerNames ?? []).map((name) =>
|
|
4611
|
-
...(options.researchMcpServerNames ?? []).map((name) =>
|
|
4639
|
+
...(options.agentMcpServerNames ?? []).map((name) => `${claudeMcpToolPrefix(name)}*`),
|
|
4640
|
+
...(options.researchMcpServerNames ?? []).map((name) => `${claudeMcpToolPrefix(name)}*`)
|
|
4612
4641
|
];
|
|
4613
4642
|
}
|
|
4614
4643
|
function claudeReadOnlySandbox(policy) {
|
|
@@ -4679,8 +4708,8 @@ function deny(reason) {
|
|
|
4679
4708
|
function createCoordinatorReadOnlyHook(policy, researchMcpServerNames = coordinatorResearchMcpServersFromEnv(process.env).map((server) => server.name)) {
|
|
4680
4709
|
const deniedTools = new Set(claudeDeniedTools(policy));
|
|
4681
4710
|
const allowedMcpPrefixes = [
|
|
4682
|
-
"
|
|
4683
|
-
...researchMcpServerNames.map(
|
|
4711
|
+
claudeMcpToolPrefix("orkestrator"),
|
|
4712
|
+
...researchMcpServerNames.map(claudeMcpToolPrefix)
|
|
4684
4713
|
];
|
|
4685
4714
|
return async (input) => {
|
|
4686
4715
|
if (input.hook_event_name !== "PreToolUse")
|
|
@@ -13651,9 +13680,6 @@ function reportedStaleServers(mcp) {
|
|
|
13651
13680
|
return;
|
|
13652
13681
|
return Array.from(mcp.stale).sort().slice(0, MAX_REPORTED_STALE_SERVERS);
|
|
13653
13682
|
}
|
|
13654
|
-
function claudeMcpToolPrefix(name) {
|
|
13655
|
-
return `mcp__${name.replace(/[^a-zA-Z0-9_-]/g, "_")}__`;
|
|
13656
|
-
}
|
|
13657
13683
|
function staleMcpServerFor(mcp, toolName, toolInput) {
|
|
13658
13684
|
if (!mcp.stale.size)
|
|
13659
13685
|
return;
|
|
@@ -10826,6 +10826,7 @@ var STRONG_REFUSAL_MARKERS = [
|
|
|
10826
10826
|
"read-only file system"
|
|
10827
10827
|
];
|
|
10828
10828
|
var SCRIPT_FAILED = "script failed";
|
|
10829
|
+
var INTERRUPTED_CELL = /^aborted by user\b/i;
|
|
10829
10830
|
var MAX_PENDING_CELLS = 256;
|
|
10830
10831
|
var MAX_CELL_TEXT_CHARS = 64 * 1024;
|
|
10831
10832
|
var ROLLOUT_POLL_INTERVAL_MS = 200;
|
|
@@ -10857,7 +10858,12 @@ function reportsRefusal(output) {
|
|
|
10857
10858
|
}
|
|
10858
10859
|
function codeModeCellOutcome(output) {
|
|
10859
10860
|
const refused = reportsRefusal(output);
|
|
10860
|
-
|
|
10861
|
+
const trimmed = output.trimStart();
|
|
10862
|
+
return {
|
|
10863
|
+
refused,
|
|
10864
|
+
failed: refused || trimmed.toLowerCase().startsWith(SCRIPT_FAILED),
|
|
10865
|
+
interrupted: !refused && INTERRUPTED_CELL.test(trimmed)
|
|
10866
|
+
};
|
|
10861
10867
|
}
|
|
10862
10868
|
function defaultWatch(_path, onChange) {
|
|
10863
10869
|
const timer = setInterval(onChange, ROLLOUT_POLL_INTERVAL_MS);
|
|
@@ -10986,7 +10992,9 @@ class RefusedCellTail {
|
|
|
10986
10992
|
this.pending.delete(callId);
|
|
10987
10993
|
const output = cellOutputText(payload.output);
|
|
10988
10994
|
const completedAtMs = recordTimeMs(record, payload);
|
|
10989
|
-
const { refused, failed } = codeModeCellOutcome(output);
|
|
10995
|
+
const { refused, failed, interrupted } = codeModeCellOutcome(output);
|
|
10996
|
+
if (interrupted)
|
|
10997
|
+
return;
|
|
10990
10998
|
const unseen = !Number.isFinite(cell.startedAtMs) || !Number.isFinite(completedAtMs) || !this.options.itemStartedBetween(cell.startedAtMs, completedAtMs);
|
|
10991
10999
|
if (!refused && !unseen)
|
|
10992
11000
|
return;
|
|
@@ -11003,6 +11011,7 @@ class RefusedCellTail {
|
|
|
11003
11011
|
}
|
|
11004
11012
|
|
|
11005
11013
|
// ../../bridges/codex-bridge/src/app-server/item-adapter.ts
|
|
11014
|
+
import { isAbsolute as isAbsolute5 } from "node:path";
|
|
11006
11015
|
function isRecord5(value) {
|
|
11007
11016
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
11008
11017
|
}
|
|
@@ -11015,6 +11024,20 @@ function durationMs(value) {
|
|
|
11015
11024
|
function strArray(value) {
|
|
11016
11025
|
return Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [];
|
|
11017
11026
|
}
|
|
11027
|
+
var MAX_IMAGE_GENERATION_INPUTS = 8;
|
|
11028
|
+
function imageGenerationInputPaths(value) {
|
|
11029
|
+
if (!Array.isArray(value))
|
|
11030
|
+
return [];
|
|
11031
|
+
const paths = new Set;
|
|
11032
|
+
for (const entry of value) {
|
|
11033
|
+
if (paths.size >= MAX_IMAGE_GENERATION_INPUTS)
|
|
11034
|
+
break;
|
|
11035
|
+
const path = isRecord5(entry) ? str(entry.path) : undefined;
|
|
11036
|
+
if (path && isAbsolute5(path))
|
|
11037
|
+
paths.add(path);
|
|
11038
|
+
}
|
|
11039
|
+
return [...paths];
|
|
11040
|
+
}
|
|
11018
11041
|
var MAX_ASYNC_QUESTIONS = 16;
|
|
11019
11042
|
var MAX_ASYNC_OPTIONS = 32;
|
|
11020
11043
|
var MAX_ASYNC_TEXT_LENGTH = 16384;
|
|
@@ -11276,13 +11299,15 @@ function adaptAppServerItem(raw) {
|
|
|
11276
11299
|
}
|
|
11277
11300
|
case "imageGeneration": {
|
|
11278
11301
|
const path = str(raw.savedPath);
|
|
11302
|
+
const inputPaths = imageGenerationInputPaths(raw.inputImages);
|
|
11279
11303
|
return {
|
|
11280
11304
|
item: {
|
|
11281
11305
|
id,
|
|
11282
11306
|
type: "image",
|
|
11283
11307
|
text: str(raw.revisedPrompt) ?? "Generated image",
|
|
11284
11308
|
...path ? { path } : {},
|
|
11285
|
-
source: "generated"
|
|
11309
|
+
source: "generated",
|
|
11310
|
+
...inputPaths.length > 0 ? { input_paths: inputPaths } : {}
|
|
11286
11311
|
}
|
|
11287
11312
|
};
|
|
11288
11313
|
}
|
|
@@ -12085,6 +12110,13 @@ async function itemToParts(item, cwd, fileChangeContext) {
|
|
|
12085
12110
|
return [];
|
|
12086
12111
|
case "image":
|
|
12087
12112
|
return [
|
|
12113
|
+
...(item.input_paths ?? []).map((path) => ({
|
|
12114
|
+
type: "image",
|
|
12115
|
+
content: path.split(/[\\/]/).pop() || "Image",
|
|
12116
|
+
fileUrl: `file://${path}`,
|
|
12117
|
+
filename: path,
|
|
12118
|
+
imageSource: "viewed"
|
|
12119
|
+
})),
|
|
12088
12120
|
{
|
|
12089
12121
|
type: "image",
|
|
12090
12122
|
content: item.text,
|
|
@@ -12381,11 +12413,8 @@ async function walkJsonlFiles(dir) {
|
|
|
12381
12413
|
}
|
|
12382
12414
|
return files;
|
|
12383
12415
|
}
|
|
12384
|
-
async function listTranscriptPaths() {
|
|
12385
|
-
const searchRoots = [
|
|
12386
|
-
join8(getCodexHomeDir(), "sessions"),
|
|
12387
|
-
join8(getCodexHomeDir(), "archived_sessions")
|
|
12388
|
-
];
|
|
12416
|
+
async function listTranscriptPaths(codexHome = getCodexHomeDir()) {
|
|
12417
|
+
const searchRoots = [join8(codexHome, "sessions"), join8(codexHome, "archived_sessions")];
|
|
12389
12418
|
return (await Promise.all(searchRoots.map((root) => walkJsonlFiles(root)))).flat();
|
|
12390
12419
|
}
|
|
12391
12420
|
var cachedTranscriptPaths = new Map;
|
|
@@ -13010,6 +13039,18 @@ async function replayPersistedRollout(threadId, snapshot, meta, structuredTurns)
|
|
|
13010
13039
|
const settleCodeModeCell = (cell, output) => {
|
|
13011
13040
|
openCells.delete(cell.callId);
|
|
13012
13041
|
const outcome = output === undefined ? undefined : codeModeCellOutcome(cellOutputText(output));
|
|
13042
|
+
if (outcome?.interrupted) {
|
|
13043
|
+
const { toolState: _claimed, ...stopped } = cell.message.parts[cell.execPartIndex];
|
|
13044
|
+
cell.message.parts[cell.execPartIndex] = stopped;
|
|
13045
|
+
if (!cell.keepExecRow) {
|
|
13046
|
+
dropPart(cell.message, cell.execPartIndex);
|
|
13047
|
+
for (const call of cell.sourceCalls) {
|
|
13048
|
+
if (!call.replaced)
|
|
13049
|
+
dropPart(cell.message, call.partIndex);
|
|
13050
|
+
}
|
|
13051
|
+
return;
|
|
13052
|
+
}
|
|
13053
|
+
}
|
|
13013
13054
|
if (cell.sawMcpRecord) {
|
|
13014
13055
|
for (const call of cell.sourceCalls) {
|
|
13015
13056
|
if (!call.replaced)
|
|
@@ -14098,9 +14139,9 @@ var ORKESTRATOR_ARTIFACT_MCP_SERVER_NAME = "orkestrator-artifacts";
|
|
|
14098
14139
|
var ORKESTRATOR_ARTIFACT_MCP_PATH = "/artifact-mcp";
|
|
14099
14140
|
|
|
14100
14141
|
// ../../bridges/codex-bridge/src/engine/app-server-engine.ts
|
|
14101
|
-
import { open as
|
|
14142
|
+
import { open as open6 } from "node:fs/promises";
|
|
14102
14143
|
import { createHash as createHash8 } from "node:crypto";
|
|
14103
|
-
import { isAbsolute as
|
|
14144
|
+
import { isAbsolute as isAbsolute7, join as join13 } from "node:path";
|
|
14104
14145
|
|
|
14105
14146
|
// ../../bridges/codex-bridge/src/app-server/process-supervisor.ts
|
|
14106
14147
|
import { execFile as execFile3, spawn as spawn3 } from "node:child_process";
|
|
@@ -16735,6 +16776,7 @@ var IGNORED_METHODS = new Set([
|
|
|
16735
16776
|
"thread/project/updated",
|
|
16736
16777
|
"thread/queue/changed",
|
|
16737
16778
|
"thread/prediction/updated",
|
|
16779
|
+
"thread/readState/changed",
|
|
16738
16780
|
"autoApprovalReview/strictReviewRequired",
|
|
16739
16781
|
"mcpServer/event/stream/notification",
|
|
16740
16782
|
"thread/reverted",
|
|
@@ -16839,6 +16881,7 @@ function reduceNotification(notification, generation, handle) {
|
|
|
16839
16881
|
turns: [
|
|
16840
16882
|
{
|
|
16841
16883
|
turnId,
|
|
16884
|
+
at: new Date().toISOString(),
|
|
16842
16885
|
inputTokens: num(last.inputTokens),
|
|
16843
16886
|
outputTokens: num(last.outputTokens),
|
|
16844
16887
|
cacheReadTokens: num(last.cachedInputTokens),
|
|
@@ -18030,7 +18073,7 @@ function coordinatorCapabilityPolicy(mode) {
|
|
|
18030
18073
|
|
|
18031
18074
|
// ../../bridges/codex-bridge/src/codex-config.ts
|
|
18032
18075
|
import { realpathSync } from "node:fs";
|
|
18033
|
-
import { isAbsolute as
|
|
18076
|
+
import { isAbsolute as isAbsolute6 } from "node:path";
|
|
18034
18077
|
var CODEX_MAX_CONCURRENT_THREADS_ENV = "CODEX_MAX_CONCURRENT_THREADS_PER_SESSION";
|
|
18035
18078
|
var DEFAULT_CODEX_MAX_CONCURRENT_THREADS = 5;
|
|
18036
18079
|
var ORKESTRATOR_AGENT_MCP_URL_ENV = "ORKESTRATOR_AGENT_MCP_URL";
|
|
@@ -18050,7 +18093,7 @@ function codexNetworkDeniedConfig(policy) {
|
|
|
18050
18093
|
};
|
|
18051
18094
|
}
|
|
18052
18095
|
function codexProjectTrustConfig(policy, cwd) {
|
|
18053
|
-
if (!policy || policy.projectResources || !cwd || !
|
|
18096
|
+
if (!policy || policy.projectResources || !cwd || !isAbsolute6(cwd))
|
|
18054
18097
|
return {};
|
|
18055
18098
|
const roots = new Set([cwd]);
|
|
18056
18099
|
try {
|
|
@@ -18073,7 +18116,7 @@ function codexProjectSkillsConfig(listed) {
|
|
|
18073
18116
|
const { path, scope, enabled } = skill ?? {};
|
|
18074
18117
|
if (enabled === true && typeof scope === "string" && KEPT_SKILL_SCOPES.has(scope))
|
|
18075
18118
|
continue;
|
|
18076
|
-
if (typeof path !== "string" || !
|
|
18119
|
+
if (typeof path !== "string" || !isAbsolute6(path)) {
|
|
18077
18120
|
throw new Error("Codex listed a project skill without a path it can be disabled by");
|
|
18078
18121
|
}
|
|
18079
18122
|
disabled.add(path);
|
|
@@ -18100,6 +18143,14 @@ function codexReadOnlyTurnPolicy(policy) {
|
|
|
18100
18143
|
const denied = base.capabilityPolicy?.deny ?? [];
|
|
18101
18144
|
return { ...base, capabilityPolicy: { deny: [...denied, "network"] } };
|
|
18102
18145
|
}
|
|
18146
|
+
function codexToolHistoryGaps(config) {
|
|
18147
|
+
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
18148
|
+
return ["config/read returned no configuration"];
|
|
18149
|
+
}
|
|
18150
|
+
const features = config.features;
|
|
18151
|
+
const value = features && typeof features === "object" && !Array.isArray(features) ? features.incremental_tools : undefined;
|
|
18152
|
+
return value === false ? [] : [`features.incremental_tools is ${JSON.stringify(value ?? null)}, not false`];
|
|
18153
|
+
}
|
|
18103
18154
|
function codexHostedNetworkLockGaps(config, expected = "disabled") {
|
|
18104
18155
|
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
18105
18156
|
return ["config/read returned no configuration"];
|
|
@@ -18113,6 +18164,7 @@ function codexHostedNetworkLockGaps(config, expected = "disabled") {
|
|
|
18113
18164
|
if (features && typeof features === "object" && features.standalone_web_search === true) {
|
|
18114
18165
|
gaps.push("features.standalone_web_search is on");
|
|
18115
18166
|
}
|
|
18167
|
+
gaps.push(...codexToolHistoryGaps(config));
|
|
18116
18168
|
return gaps;
|
|
18117
18169
|
}
|
|
18118
18170
|
function isCoordinatorReadOnlyEnvironment(env) {
|
|
@@ -18139,7 +18191,8 @@ function codexAppServerConfigOverrides(env = process.env) {
|
|
|
18139
18191
|
const childLimit = resolveCodexMaxConcurrentThreads(env[CODEX_MAX_CONCURRENT_THREADS_ENV]);
|
|
18140
18192
|
const overrides = {
|
|
18141
18193
|
"agents.max_concurrent_threads_per_session": String(childLimit),
|
|
18142
|
-
"features.multi_agent_v2.max_concurrent_threads_per_session": String(childLimit + 1)
|
|
18194
|
+
"features.multi_agent_v2.max_concurrent_threads_per_session": String(childLimit + 1),
|
|
18195
|
+
"features.incremental_tools": "false"
|
|
18143
18196
|
};
|
|
18144
18197
|
const rawUrl = env[ORKESTRATOR_AGENT_MCP_URL_ENV]?.trim();
|
|
18145
18198
|
const token = env[ORKESTRATOR_AGENT_MCP_TOKEN_ENV]?.trim();
|
|
@@ -18148,11 +18201,11 @@ function codexAppServerConfigOverrides(env = process.env) {
|
|
|
18148
18201
|
const readableRuntimeRoot = env.CODEX_BRIDGE_READABLE_RUNTIME_ROOT?.trim();
|
|
18149
18202
|
const projectRoot = env.CWD?.trim();
|
|
18150
18203
|
const attachmentRoot = env[BRIDGE_ATTACHMENT_ROOT_ENV]?.trim();
|
|
18151
|
-
if (!permissionProfile || !/^[A-Za-z0-9_-]+$/.test(permissionProfile) || !readableRuntimeRoot || !
|
|
18204
|
+
if (!permissionProfile || !/^[A-Za-z0-9_-]+$/.test(permissionProfile) || !readableRuntimeRoot || !isAbsolute6(readableRuntimeRoot) || !projectRoot || !isAbsolute6(projectRoot)) {
|
|
18152
18205
|
throw new Error("Coordinator Codex permission profile configuration is invalid");
|
|
18153
18206
|
}
|
|
18154
18207
|
overrides.default_permissions = JSON.stringify(permissionProfile);
|
|
18155
|
-
overrides[`permissions.${permissionProfile}.filesystem`] = `{ ":root" = "deny", ":minimal" = "read", ":tmpdir" = "deny", ` + `":slash_tmp" = "deny", ${JSON.stringify(readableRuntimeRoot)} = "read", ` + (attachmentRoot &&
|
|
18208
|
+
overrides[`permissions.${permissionProfile}.filesystem`] = `{ ":root" = "deny", ":minimal" = "read", ":tmpdir" = "deny", ` + `":slash_tmp" = "deny", ${JSON.stringify(readableRuntimeRoot)} = "read", ` + (attachmentRoot && isAbsolute6(attachmentRoot) ? `${JSON.stringify(attachmentRoot)} = "read", ` : "") + `":workspace_roots" = { "." = "read" } }`;
|
|
18156
18209
|
overrides[`permissions.${permissionProfile}.network.enabled`] = "false";
|
|
18157
18210
|
overrides.web_search = JSON.stringify(codexNetworkDeniedSearchMode(codexCoordinatorPolicy(env)));
|
|
18158
18211
|
overrides["features.standalone_web_search"] = "false";
|
|
@@ -18218,6 +18271,106 @@ function codexAppServerConfigOverrides(env = process.env) {
|
|
|
18218
18271
|
return overrides;
|
|
18219
18272
|
}
|
|
18220
18273
|
|
|
18274
|
+
// ../../bridges/codex-bridge/src/sessions/tool-history-guard.ts
|
|
18275
|
+
import { open as open5 } from "node:fs/promises";
|
|
18276
|
+
var TOOL_HISTORY_MARKER = '"type":"additional_tools"';
|
|
18277
|
+
var MAX_TOOL_HISTORY_LINEAGE_DEPTH = 32;
|
|
18278
|
+
async function rolloutDeclaresToolHistory(path, end) {
|
|
18279
|
+
const handle = await open5(path, "r");
|
|
18280
|
+
try {
|
|
18281
|
+
const size = (await handle.stat()).size;
|
|
18282
|
+
const limit = end === undefined ? size : Math.min(end, size);
|
|
18283
|
+
const marker = Buffer.from(TOOL_HISTORY_MARKER);
|
|
18284
|
+
const buffer = Buffer.allocUnsafe(ROLLOUT_CHUNK_BYTES + marker.length);
|
|
18285
|
+
let carried = 0;
|
|
18286
|
+
for (let position = 0;position < limit; ) {
|
|
18287
|
+
const length = Math.min(ROLLOUT_CHUNK_BYTES, limit - position);
|
|
18288
|
+
const { bytesRead } = await handle.read(buffer, carried, length, position);
|
|
18289
|
+
if (bytesRead <= 0)
|
|
18290
|
+
break;
|
|
18291
|
+
const filled = carried + bytesRead;
|
|
18292
|
+
if (buffer.subarray(0, filled).includes(marker))
|
|
18293
|
+
return true;
|
|
18294
|
+
position += bytesRead;
|
|
18295
|
+
carried = Math.min(marker.length - 1, filled);
|
|
18296
|
+
buffer.copy(buffer, 0, filled - carried, filled);
|
|
18297
|
+
}
|
|
18298
|
+
return false;
|
|
18299
|
+
} finally {
|
|
18300
|
+
await handle.close();
|
|
18301
|
+
}
|
|
18302
|
+
}
|
|
18303
|
+
async function historyBase(path) {
|
|
18304
|
+
const handle = await open5(path, "r");
|
|
18305
|
+
try {
|
|
18306
|
+
const chunks = [];
|
|
18307
|
+
let filled = 0;
|
|
18308
|
+
let complete = false;
|
|
18309
|
+
while (filled < MAX_ROLLOUT_RECORD_BYTES) {
|
|
18310
|
+
const chunk = Buffer.allocUnsafe(ROLLOUT_CHUNK_BYTES);
|
|
18311
|
+
const { bytesRead } = await handle.read(chunk, 0, chunk.length, filled);
|
|
18312
|
+
if (bytesRead <= 0) {
|
|
18313
|
+
complete = true;
|
|
18314
|
+
break;
|
|
18315
|
+
}
|
|
18316
|
+
const newline = chunk.subarray(0, bytesRead).indexOf(10);
|
|
18317
|
+
chunks.push(chunk.subarray(0, newline >= 0 ? newline : bytesRead));
|
|
18318
|
+
filled += bytesRead;
|
|
18319
|
+
if (newline >= 0) {
|
|
18320
|
+
complete = true;
|
|
18321
|
+
break;
|
|
18322
|
+
}
|
|
18323
|
+
}
|
|
18324
|
+
if (!complete)
|
|
18325
|
+
return "unreadable";
|
|
18326
|
+
const line = Buffer.concat(chunks).toString("utf8");
|
|
18327
|
+
if (!line.trim())
|
|
18328
|
+
return null;
|
|
18329
|
+
let record;
|
|
18330
|
+
try {
|
|
18331
|
+
record = JSON.parse(line);
|
|
18332
|
+
} catch {
|
|
18333
|
+
return "unreadable";
|
|
18334
|
+
}
|
|
18335
|
+
if (record.type !== "session_meta" || !record.payload)
|
|
18336
|
+
return null;
|
|
18337
|
+
const base = record.payload.history_base;
|
|
18338
|
+
if (base && typeof base === "object") {
|
|
18339
|
+
if (typeof base.thread_id !== "string")
|
|
18340
|
+
return "unreadable";
|
|
18341
|
+
return {
|
|
18342
|
+
threadId: base.thread_id,
|
|
18343
|
+
...typeof base.end_byte_offset === "number" ? { endByte: base.end_byte_offset } : {}
|
|
18344
|
+
};
|
|
18345
|
+
}
|
|
18346
|
+
return null;
|
|
18347
|
+
} finally {
|
|
18348
|
+
await handle.close();
|
|
18349
|
+
}
|
|
18350
|
+
}
|
|
18351
|
+
async function threadToolHistoryVerdict(rolloutPath, resolveRollout) {
|
|
18352
|
+
let path = rolloutPath;
|
|
18353
|
+
let end;
|
|
18354
|
+
for (let depth = 0;depth <= MAX_TOOL_HISTORY_LINEAGE_DEPTH; depth += 1) {
|
|
18355
|
+
if (!path)
|
|
18356
|
+
return "unknown";
|
|
18357
|
+
try {
|
|
18358
|
+
if (await rolloutDeclaresToolHistory(path, end))
|
|
18359
|
+
return "declares";
|
|
18360
|
+
const base = await historyBase(path);
|
|
18361
|
+
if (base === "unreadable")
|
|
18362
|
+
return "unknown";
|
|
18363
|
+
if (!base)
|
|
18364
|
+
return "clean";
|
|
18365
|
+
end = base.endByte;
|
|
18366
|
+
path = await resolveRollout(base.threadId);
|
|
18367
|
+
} catch {
|
|
18368
|
+
return "unknown";
|
|
18369
|
+
}
|
|
18370
|
+
}
|
|
18371
|
+
return "unknown";
|
|
18372
|
+
}
|
|
18373
|
+
|
|
18221
18374
|
// ../../bridges/codex-bridge/src/engine/mcp-tool-availability.ts
|
|
18222
18375
|
var MCP_TOOL_AVAILABILITY_TIMEOUT_MS = 5000;
|
|
18223
18376
|
var MCP_TOOL_AVAILABILITY_POLL_MS = 100;
|
|
@@ -18638,7 +18791,7 @@ function signedOutAccountRead(error) {
|
|
|
18638
18791
|
}
|
|
18639
18792
|
async function readStoredLoginFingerprint(codexHome) {
|
|
18640
18793
|
try {
|
|
18641
|
-
const file = await
|
|
18794
|
+
const file = await open6(join13(codexHome, "auth.json"), "r");
|
|
18642
18795
|
let raw;
|
|
18643
18796
|
try {
|
|
18644
18797
|
const bytes = Buffer.alloc(65537);
|
|
@@ -18687,6 +18840,9 @@ var MAX_UNKNOWN_METHODS = 16;
|
|
|
18687
18840
|
var MAX_UNKNOWN_METHOD_LENGTH = 128;
|
|
18688
18841
|
var MAX_ACCOUNT_PROOF_TURNS = 1024;
|
|
18689
18842
|
var MAX_ACCOUNT_PROOF_ID_LENGTH = 256;
|
|
18843
|
+
function deniesHostedSearch(config) {
|
|
18844
|
+
return Object.keys(codexNetworkDeniedConfig(config.policy)).length > 0 && codexNetworkDeniedSearchMode(config.policy) === "disabled";
|
|
18845
|
+
}
|
|
18690
18846
|
|
|
18691
18847
|
class AppServerEngine {
|
|
18692
18848
|
options;
|
|
@@ -18713,6 +18869,7 @@ class AppServerEngine {
|
|
|
18713
18869
|
accountProofInvalidatedSequence = 0;
|
|
18714
18870
|
accountProofTurns = new Map;
|
|
18715
18871
|
hostedNetworkLockVerifiedGeneration = null;
|
|
18872
|
+
toolHistoryLockVerifiedGeneration = null;
|
|
18716
18873
|
accountReloadFingerprint;
|
|
18717
18874
|
pendingAccountReloadFingerprint;
|
|
18718
18875
|
accountCheckSequence = 0;
|
|
@@ -18753,6 +18910,7 @@ class AppServerEngine {
|
|
|
18753
18910
|
this.clearPendingSignIn();
|
|
18754
18911
|
this.loginSequence++;
|
|
18755
18912
|
this.hostedNetworkLockVerifiedGeneration = null;
|
|
18913
|
+
this.toolHistoryLockVerifiedGeneration = null;
|
|
18756
18914
|
this.rejectAllWaiters();
|
|
18757
18915
|
this.router.abandonGeneration(generation);
|
|
18758
18916
|
}
|
|
@@ -19190,8 +19348,47 @@ class AppServerEngine {
|
|
|
19190
19348
|
this.hostedNetworkLockVerifiedGeneration = generation;
|
|
19191
19349
|
return generation;
|
|
19192
19350
|
}
|
|
19351
|
+
async assertToolHistoryLock(generation, config) {
|
|
19352
|
+
if (!deniesHostedSearch(config) || config.permissionProfile)
|
|
19353
|
+
return;
|
|
19354
|
+
if (this.toolHistoryLockVerifiedGeneration === generation)
|
|
19355
|
+
return;
|
|
19356
|
+
const result = await this.supervisor.requestOnGeneration(generation, "config/read", { cwd: config.cwd ?? this.options.cwd });
|
|
19357
|
+
const gaps = codexToolHistoryGaps(result?.config);
|
|
19358
|
+
if (gaps.length > 0) {
|
|
19359
|
+
throw new Error(`Codex did not confirm that tool declarations stay out of thread history (${gaps.join("; ")}), so this session, which has web search off, was refused`);
|
|
19360
|
+
}
|
|
19361
|
+
if (!this.supervisor.isReady() || this.supervisor.getGeneration() !== generation) {
|
|
19362
|
+
throw new Error("Codex exited during tool history verification");
|
|
19363
|
+
}
|
|
19364
|
+
this.toolHistoryLockVerifiedGeneration = generation;
|
|
19365
|
+
}
|
|
19366
|
+
async assertNoToolHistory(threadId, config, release) {
|
|
19367
|
+
if (!deniesHostedSearch(config))
|
|
19368
|
+
return;
|
|
19369
|
+
const verdict = await (this.options.toolHistoryVerdict ?? ((id) => this.readToolHistory(id)))(threadId).catch(() => "unknown");
|
|
19370
|
+
if (verdict === "clean")
|
|
19371
|
+
return;
|
|
19372
|
+
if (release) {
|
|
19373
|
+
for (const [handle, binding] of this.bindings) {
|
|
19374
|
+
if (binding.threadId === threadId)
|
|
19375
|
+
this.bindings.delete(handle);
|
|
19376
|
+
}
|
|
19377
|
+
await this.supervisor.request("thread/unsubscribe", { threadId }).catch(() => {
|
|
19378
|
+
return;
|
|
19379
|
+
});
|
|
19380
|
+
}
|
|
19381
|
+
throw new Error(verdict === "declares" ? "This Codex thread was offered web search in an earlier turn and still declares it in its history, so a turn with web search off was refused. Start a new session for it." : "Could not confirm that this Codex thread's history declares no web search, so a turn with web search off was refused.");
|
|
19382
|
+
}
|
|
19383
|
+
async readToolHistory(threadId) {
|
|
19384
|
+
const codexHome = this.options.codexHome;
|
|
19385
|
+
const resolve = async (id) => this.rolloutPaths.get(id) ?? findTranscriptPath(id, () => listTranscriptPaths(codexHome), { allowNegativeCache: false });
|
|
19386
|
+
const path = await resolve(threadId);
|
|
19387
|
+
return path ? threadToolHistoryVerdict(path, resolve) : "unknown";
|
|
19388
|
+
}
|
|
19193
19389
|
async startThread(options) {
|
|
19194
19390
|
const generation = await this.assertHostedNetworkLock(options.config);
|
|
19391
|
+
await this.assertToolHistoryLock(generation, options.config);
|
|
19195
19392
|
const extra = await this.projectResourceThreadConfig(generation, options.config);
|
|
19196
19393
|
const response = await this.supervisor.requestOnGeneration(generation, "thread/start", this.toThreadParams(options.config, extra));
|
|
19197
19394
|
this.assertPermissionProfile(response.activePermissionProfile, options.config);
|
|
@@ -19199,10 +19396,12 @@ class AppServerEngine {
|
|
|
19199
19396
|
}
|
|
19200
19397
|
async resumeThread(threadId, options) {
|
|
19201
19398
|
const generation = await this.assertHostedNetworkLock(options.config);
|
|
19399
|
+
await this.assertToolHistoryLock(generation, options.config);
|
|
19202
19400
|
const extra = await this.projectResourceThreadConfig(generation, options.config);
|
|
19203
19401
|
const response = await this.supervisor.requestOnGeneration(generation, "thread/resume", { threadId, ...this.toThreadParams(options.config, extra) });
|
|
19204
19402
|
this.assertPermissionProfile(response.activePermissionProfile, options.config);
|
|
19205
19403
|
const thread = this.bindThread(response.thread, options.config, response.model);
|
|
19404
|
+
await this.assertNoToolHistory(thread.id ?? threadId, options.config, true);
|
|
19206
19405
|
thread.turns = this.extractTurns(response.thread);
|
|
19207
19406
|
return thread;
|
|
19208
19407
|
}
|
|
@@ -19218,6 +19417,8 @@ class AppServerEngine {
|
|
|
19218
19417
|
}
|
|
19219
19418
|
async forkThread(threadId, config, lastTurnId) {
|
|
19220
19419
|
const generation = await this.assertHostedNetworkLock(config);
|
|
19420
|
+
await this.assertToolHistoryLock(generation, config);
|
|
19421
|
+
await this.assertNoToolHistory(threadId, config, false);
|
|
19221
19422
|
const extra = await this.projectResourceThreadConfig(generation, config);
|
|
19222
19423
|
const response = await this.supervisor.requestOnGeneration(generation, "thread/fork", {
|
|
19223
19424
|
threadId,
|
|
@@ -19495,7 +19696,7 @@ class AppServerEngine {
|
|
|
19495
19696
|
thread.model = confirmedModel.trim();
|
|
19496
19697
|
}
|
|
19497
19698
|
if (thread.id) {
|
|
19498
|
-
if (typeof raw.path === "string" &&
|
|
19699
|
+
if (typeof raw.path === "string" && isAbsolute7(raw.path)) {
|
|
19499
19700
|
this.rolloutPaths.set(thread.id, raw.path);
|
|
19500
19701
|
}
|
|
19501
19702
|
this.bindings.set(thread.id, {
|
|
@@ -21453,7 +21654,7 @@ function parseCommandToken(text, sigils = ["/"]) {
|
|
|
21453
21654
|
|
|
21454
21655
|
// ../../bridges/codex-bridge/src/prompts/template-discovery.ts
|
|
21455
21656
|
import { createHash as createHash10 } from "node:crypto";
|
|
21456
|
-
import { open as
|
|
21657
|
+
import { open as open7, readdir as readdir3, stat as stat7 } from "node:fs/promises";
|
|
21457
21658
|
import { join as join14 } from "node:path";
|
|
21458
21659
|
|
|
21459
21660
|
// ../../bridges/codex-bridge/src/prompts/template-format.ts
|
|
@@ -21608,7 +21809,7 @@ function isReservedName(name) {
|
|
|
21608
21809
|
var metadataCache = new Map;
|
|
21609
21810
|
var METADATA_CACHE_MAX = 1024;
|
|
21610
21811
|
async function readBounded(absolutePath, maxBytes) {
|
|
21611
|
-
const handle = await
|
|
21812
|
+
const handle = await open7(absolutePath, "r");
|
|
21612
21813
|
try {
|
|
21613
21814
|
const info = await handle.stat();
|
|
21614
21815
|
if (!info.isFile())
|
|
@@ -21855,7 +22056,7 @@ async function loadTemplateBody(entry, limits = TEMPLATE_LIMITS) {
|
|
|
21855
22056
|
}
|
|
21856
22057
|
|
|
21857
22058
|
// ../../bridges/codex-bridge/src/commands/skill-inventory.ts
|
|
21858
|
-
import { isAbsolute as
|
|
22059
|
+
import { isAbsolute as isAbsolute8 } from "node:path";
|
|
21859
22060
|
var SKILL_INVENTORY_LIMITS = Object.freeze({
|
|
21860
22061
|
maxSkills: 512,
|
|
21861
22062
|
maxDescriptionBytes: 1000,
|
|
@@ -21905,7 +22106,7 @@ function normalizeSkillsList(raw, context) {
|
|
|
21905
22106
|
}
|
|
21906
22107
|
const name = nonEmpty(candidate.name);
|
|
21907
22108
|
const path = typeof candidate.path === "string" ? candidate.path : undefined;
|
|
21908
|
-
if (!name || !usableSkillName(name) || !path || !
|
|
22109
|
+
if (!name || !usableSkillName(name) || !path || !isAbsolute8(path)) {
|
|
21909
22110
|
truncated = true;
|
|
21910
22111
|
continue;
|
|
21911
22112
|
}
|