orkestrator 2.34.4-beta → 2.35.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/README.md +12 -0
- package/bin/orkestrator-launcher.js +42 -3
- package/dist/client.js +1852 -146
- package/dist/main.js +216258 -201848
- package/package.json +4 -4
- package/resources/acp-bridge/dist/index.js +22797 -0
- package/resources/claude-bridge/dist/index.js +837 -433
- package/resources/codex-bridge/dist/index.js +744 -119
- package/resources/cursor-bridge/dist/index.js +36885 -0
- package/resources/cursor-bridge/runtime/bun.lock +40 -0
- package/resources/cursor-bridge/runtime/install.json +4 -0
- package/resources/cursor-bridge/runtime/package.json +11 -0
- package/resources/cursor-bridge/runtime/patches/@cursor%2Fsdk@1.2.0.patch +19 -0
- package/resources/pi-bridge/dist/index.js +36084 -0
- package/resources/pi-bridge/runtime/bun.lock +259 -0
- package/resources/pi-bridge/runtime/install.json +4 -0
- package/resources/pi-bridge/runtime/package.json +10 -0
|
@@ -2666,14 +2666,30 @@ import { join as join2 } from "node:path";
|
|
|
2666
2666
|
|
|
2667
2667
|
// ../../bridges/claude-bridge/src/services/claude-home.ts
|
|
2668
2668
|
import { homedir } from "node:os";
|
|
2669
|
-
import { join } from "node:path";
|
|
2669
|
+
import { join, resolve } from "node:path";
|
|
2670
2670
|
var overrideHome = null;
|
|
2671
|
+
var overrideAccountHome;
|
|
2672
|
+
var CLAUDE_ACCOUNT_HOME_ENV = "ORKESTRATOR_CLAUDE_ACCOUNT_HOME";
|
|
2671
2673
|
function claudeHome() {
|
|
2672
2674
|
return overrideHome ?? homedir();
|
|
2673
2675
|
}
|
|
2674
2676
|
function claudeJsonPath() {
|
|
2675
2677
|
return join(claudeHome(), ".claude.json");
|
|
2676
2678
|
}
|
|
2679
|
+
function claudeAccountJsonPath() {
|
|
2680
|
+
let home = overrideAccountHome;
|
|
2681
|
+
if (home === undefined) {
|
|
2682
|
+
if (overrideHome !== null)
|
|
2683
|
+
return null;
|
|
2684
|
+
const marked = process.env[CLAUDE_ACCOUNT_HOME_ENV]?.trim();
|
|
2685
|
+
const configDir = process.env.CLAUDE_CONFIG_DIR?.trim();
|
|
2686
|
+
home = marked && configDir && resolve(marked) === resolve(configDir) ? configDir : null;
|
|
2687
|
+
}
|
|
2688
|
+
if (!home)
|
|
2689
|
+
return null;
|
|
2690
|
+
const file = join(home, ".claude.json");
|
|
2691
|
+
return resolve(file) === resolve(claudeJsonPath()) ? null : file;
|
|
2692
|
+
}
|
|
2677
2693
|
function claudeUserSettingsPath() {
|
|
2678
2694
|
const configDir = overrideHome === null ? process.env.CLAUDE_CONFIG_DIR?.trim() : undefined;
|
|
2679
2695
|
return join(configDir || join(claudeHome(), ".claude"), "settings.json");
|
|
@@ -4117,6 +4133,43 @@ import { tmpdir } from "node:os";
|
|
|
4117
4133
|
import path from "node:path";
|
|
4118
4134
|
import { promisify } from "node:util";
|
|
4119
4135
|
|
|
4136
|
+
// ../protocol/src/native-agent-goal.ts
|
|
4137
|
+
var NATIVE_AGENT_GOAL_LIMITS = Object.freeze({
|
|
4138
|
+
objectiveMaxChars: 4000,
|
|
4139
|
+
checkMaxBytes: 4 * 1024,
|
|
4140
|
+
reportMessageMaxBytes: 2 * 1024,
|
|
4141
|
+
checkOutputMaxBytes: 8 * 1024,
|
|
4142
|
+
statusDetailMaxBytes: 1024,
|
|
4143
|
+
maxIterationsDefault: 20,
|
|
4144
|
+
maxIterationsLimit: 100,
|
|
4145
|
+
noProgressLimit: 3,
|
|
4146
|
+
checkTimeoutDefaultMs: 10 * 60000,
|
|
4147
|
+
checkTimeoutMaxMs: 30 * 60000,
|
|
4148
|
+
verifierModelMaxChars: 200,
|
|
4149
|
+
verifierTimeoutDefaultMs: 30 * 60000,
|
|
4150
|
+
verdictSummaryMaxBytes: 2 * 1024,
|
|
4151
|
+
verdictReasonsMax: 16,
|
|
4152
|
+
verdictReasonMaxBytes: 512,
|
|
4153
|
+
historyLimit: 5
|
|
4154
|
+
});
|
|
4155
|
+
var AGENT_GOAL_TOOL_NAMES = Object.freeze(["report_goal"]);
|
|
4156
|
+
var GOAL_QUALIFIED_PLATFORMS = Object.freeze([
|
|
4157
|
+
"claude",
|
|
4158
|
+
"codex",
|
|
4159
|
+
"opencode",
|
|
4160
|
+
"cursor",
|
|
4161
|
+
"grok",
|
|
4162
|
+
"pi"
|
|
4163
|
+
]);
|
|
4164
|
+
var GOAL_TOKEN_BUDGET_PLATFORMS = Object.freeze([
|
|
4165
|
+
"claude",
|
|
4166
|
+
"codex",
|
|
4167
|
+
"opencode",
|
|
4168
|
+
"cursor",
|
|
4169
|
+
"grok",
|
|
4170
|
+
"pi"
|
|
4171
|
+
]);
|
|
4172
|
+
|
|
4120
4173
|
// ../protocol/src/native-agent-transcript-patch.ts
|
|
4121
4174
|
var FORBIDDEN_KEYS = new Set(["__proto__", "constructor", "prototype"]);
|
|
4122
4175
|
|
|
@@ -4517,6 +4570,7 @@ var PROJECTION_FIELD_SET = new Set([
|
|
|
4517
4570
|
"queue",
|
|
4518
4571
|
"asyncQuestionResponses",
|
|
4519
4572
|
"contextUsage",
|
|
4573
|
+
"goal",
|
|
4520
4574
|
"rateLimits",
|
|
4521
4575
|
"runtime",
|
|
4522
4576
|
"runtimeHealthAuthoritative",
|
|
@@ -4541,6 +4595,7 @@ var OPTIONAL_PROJECTION_FIELD_SET = new Set([
|
|
|
4541
4595
|
"queue",
|
|
4542
4596
|
"asyncQuestionResponses",
|
|
4543
4597
|
"contextUsage",
|
|
4598
|
+
"goal",
|
|
4544
4599
|
"rateLimits",
|
|
4545
4600
|
"runtime",
|
|
4546
4601
|
"runtimeHealthAuthoritative",
|
|
@@ -4642,6 +4697,15 @@ async function runtimeEnvironmentForSessionQuery(policy, env = process.env, opti
|
|
|
4642
4697
|
const ghConfigDir = await (options.ghConfigDir ?? emptyGhConfigDir)();
|
|
4643
4698
|
return withheldGitHubCredentialEnvironment(env, { ghConfigDir });
|
|
4644
4699
|
}
|
|
4700
|
+
var UNATTENDED_OVERLOAD_RETRY_ENV = {
|
|
4701
|
+
CLAUDE_CODE_OVERLOADED_RETRY_BASE_DELAY_MS: "4000",
|
|
4702
|
+
CLAUDE_CODE_OVERLOADED_RETRY_MAX_DELAY_MS: "64000"
|
|
4703
|
+
};
|
|
4704
|
+
function withUnattendedOverloadRetry(sessionPolicy, environment) {
|
|
4705
|
+
if (sessionPolicy?.id !== "pipeline")
|
|
4706
|
+
return environment;
|
|
4707
|
+
return { ...UNATTENDED_OVERLOAD_RETRY_ENV, ...environment };
|
|
4708
|
+
}
|
|
4645
4709
|
|
|
4646
4710
|
// ../../bridges/claude-bridge/src/services/coordinator-skills.ts
|
|
4647
4711
|
import { createHash as createHash4, randomBytes } from "node:crypto";
|
|
@@ -4669,16 +4733,19 @@ var COORDINATOR_CONTROL_TOOL_NAMES = Object.freeze([
|
|
|
4669
4733
|
"add_ticket_comment",
|
|
4670
4734
|
"address_multi_review",
|
|
4671
4735
|
"adopt_workflow",
|
|
4736
|
+
"answer_worker_question",
|
|
4672
4737
|
"cancel_build_pipeline",
|
|
4673
4738
|
"cancel_graph_run",
|
|
4674
4739
|
"cancel_multi_review",
|
|
4675
4740
|
"cancel_schedule",
|
|
4741
|
+
"clear_worker_goal",
|
|
4676
4742
|
"compare_project_files",
|
|
4677
4743
|
"create_pr",
|
|
4678
4744
|
"create_schedule",
|
|
4679
4745
|
"create_ticket",
|
|
4680
4746
|
"custom_fix_multi_review",
|
|
4681
4747
|
"edit_worker_tab",
|
|
4748
|
+
"fork_worker",
|
|
4682
4749
|
"get_build_pipeline",
|
|
4683
4750
|
"get_environment",
|
|
4684
4751
|
"get_feature_plan",
|
|
@@ -4691,6 +4758,9 @@ var COORDINATOR_CONTROL_TOOL_NAMES = Object.freeze([
|
|
|
4691
4758
|
"get_tab_state",
|
|
4692
4759
|
"get_tab_transcript",
|
|
4693
4760
|
"get_ticket",
|
|
4761
|
+
"get_usage_limits",
|
|
4762
|
+
"get_worker_changes",
|
|
4763
|
+
"get_worker_goal",
|
|
4694
4764
|
"launch_environment",
|
|
4695
4765
|
"launch_feature_plan",
|
|
4696
4766
|
"launch_graph",
|
|
@@ -4705,14 +4775,18 @@ var COORDINATOR_CONTROL_TOOL_NAMES = Object.freeze([
|
|
|
4705
4775
|
"list_node_environments",
|
|
4706
4776
|
"list_nodes",
|
|
4707
4777
|
"list_projects",
|
|
4778
|
+
"list_provider_accounts",
|
|
4708
4779
|
"list_schedules",
|
|
4709
4780
|
"list_tabs",
|
|
4710
4781
|
"list_tickets",
|
|
4782
|
+
"list_worker_commands",
|
|
4711
4783
|
"list_workflows",
|
|
4712
4784
|
"open_multi_review",
|
|
4713
4785
|
"open_multi_review_fix",
|
|
4714
4786
|
"open_worker_browser",
|
|
4715
4787
|
"pause_build_pipeline",
|
|
4788
|
+
"pause_schedule",
|
|
4789
|
+
"pause_worker_goal",
|
|
4716
4790
|
"propose_agents_md_update",
|
|
4717
4791
|
"read_messages",
|
|
4718
4792
|
"read_node_environment",
|
|
@@ -4721,18 +4795,26 @@ var COORDINATOR_CONTROL_TOOL_NAMES = Object.freeze([
|
|
|
4721
4795
|
"request_project_file_update",
|
|
4722
4796
|
"request_project_on_node",
|
|
4723
4797
|
"request_root_changes",
|
|
4798
|
+
"resolve_conflicts",
|
|
4724
4799
|
"resume_build_pipeline",
|
|
4800
|
+
"resume_schedule",
|
|
4801
|
+
"run_worker_command",
|
|
4725
4802
|
"send_message",
|
|
4726
4803
|
"send_node_message",
|
|
4727
4804
|
"send_prompt_to_node_tab",
|
|
4728
4805
|
"send_prompt_to_tab",
|
|
4806
|
+
"set_worker_goal",
|
|
4729
4807
|
"start_build_pipeline",
|
|
4730
4808
|
"start_environment",
|
|
4731
4809
|
"start_multi_review",
|
|
4732
4810
|
"start_node_environment",
|
|
4733
4811
|
"stop_environment",
|
|
4734
4812
|
"stop_node_environment",
|
|
4813
|
+
"stop_worker_turn",
|
|
4814
|
+
"switch_provider_account",
|
|
4815
|
+
"set_account_auto_switch",
|
|
4735
4816
|
"transfer_files",
|
|
4817
|
+
"update_schedule",
|
|
4736
4818
|
"update_ticket"
|
|
4737
4819
|
]);
|
|
4738
4820
|
|
|
@@ -8783,6 +8865,8 @@ function claudeLaunchConflict(runtime, request) {
|
|
|
8783
8865
|
return "adaptive thinking";
|
|
8784
8866
|
if (request.bypassCapable && !runtime.bypassCapable)
|
|
8785
8867
|
return "bypass permission capability";
|
|
8868
|
+
if (request.repositoryInstructions !== undefined && runtime.repositoryInstructions !== request.repositoryInstructions)
|
|
8869
|
+
return "repository instructions";
|
|
8786
8870
|
if (request.plugins !== undefined && runtime.plugins !== request.plugins)
|
|
8787
8871
|
return "plugins";
|
|
8788
8872
|
if (request.credentials !== undefined && runtime.credentials !== request.credentials)
|
|
@@ -8931,7 +9015,7 @@ function noMessages() {
|
|
|
8931
9015
|
// ../../bridges/claude-bridge/src/services/session-manager-persistence.ts
|
|
8932
9016
|
import { constants as constants2 } from "node:fs";
|
|
8933
9017
|
import { lstat as lstat2, open as open2, realpath as realpath2 } from "node:fs/promises";
|
|
8934
|
-
import { isAbsolute as isAbsolute3, join as join10, relative, resolve as
|
|
9018
|
+
import { isAbsolute as isAbsolute3, join as join10, relative, resolve as resolve3, sep } from "node:path";
|
|
8935
9019
|
|
|
8936
9020
|
// ../protocol/src/node/command-change-journal.ts
|
|
8937
9021
|
import { appendFile, mkdir as mkdir3, readFile as readFile5, rename as rename3, rm as rm3, stat as stat4, writeFile as writeFile3 } from "node:fs/promises";
|
|
@@ -9088,7 +9172,7 @@ import { randomUUID as randomUUID2 } from "node:crypto";
|
|
|
9088
9172
|
import { rmSync } from "node:fs";
|
|
9089
9173
|
import { copyFile, lstat, mkdtemp as mkdtemp2, rm as rm4 } from "node:fs/promises";
|
|
9090
9174
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
9091
|
-
import { delimiter as delimiter2, isAbsolute as isAbsolute2, join as join6, resolve } from "node:path";
|
|
9175
|
+
import { delimiter as delimiter2, isAbsolute as isAbsolute2, join as join6, resolve as resolve2 } from "node:path";
|
|
9092
9176
|
var DEFAULT_MAX_UNTRACKED_FILE_BYTES = 2 * 1024 * 1024;
|
|
9093
9177
|
var DEFAULT_MAX_UNTRACKED_FILES = 5000;
|
|
9094
9178
|
var DEFAULT_SLOW_SNAPSHOT_MS = 500;
|
|
@@ -9370,8 +9454,8 @@ class WorkspaceChangeProbe {
|
|
|
9370
9454
|
return;
|
|
9371
9455
|
return {
|
|
9372
9456
|
root,
|
|
9373
|
-
indexPath: isAbsolute2(index) ? index :
|
|
9374
|
-
objectsPath: isAbsolute2(objects) ? objects :
|
|
9457
|
+
indexPath: isAbsolute2(index) ? index : resolve2(cwd, index),
|
|
9458
|
+
objectsPath: isAbsolute2(objects) ? objects : resolve2(cwd, objects)
|
|
9375
9459
|
};
|
|
9376
9460
|
}).catch(() => {
|
|
9377
9461
|
return;
|
|
@@ -11777,13 +11861,13 @@ class ClaudeAttachmentError extends Error {
|
|
|
11777
11861
|
var BRIDGE_ATTACHMENT_ROOT_ENV = "ORKESTRATOR_BRIDGE_ATTACHMENT_ROOT";
|
|
11778
11862
|
function configuredAttachmentRoot(env = process.env) {
|
|
11779
11863
|
const value = env[BRIDGE_ATTACHMENT_ROOT_ENV]?.trim();
|
|
11780
|
-
return value && isAbsolute3(value) ?
|
|
11864
|
+
return value && isAbsolute3(value) ? resolve3(value) : undefined;
|
|
11781
11865
|
}
|
|
11782
11866
|
function attachmentContainmentRoot(filePath, cwd, extraRoot = configuredAttachmentRoot()) {
|
|
11783
|
-
if (extraRoot && isAbsolute3(filePath) && isPathWithin2(extraRoot,
|
|
11867
|
+
if (extraRoot && isAbsolute3(filePath) && isPathWithin2(extraRoot, resolve3(filePath))) {
|
|
11784
11868
|
return extraRoot;
|
|
11785
11869
|
}
|
|
11786
|
-
return
|
|
11870
|
+
return resolve3(cwd);
|
|
11787
11871
|
}
|
|
11788
11872
|
function isPathWithin2(rootPath, targetPath) {
|
|
11789
11873
|
const childPath = relative(rootPath, targetPath);
|
|
@@ -11831,7 +11915,7 @@ async function assertOpenedWorkspaceFile(targetPath, canonicalRoot, openedStats)
|
|
|
11831
11915
|
}
|
|
11832
11916
|
async function readWorkspaceImageAttachment(filePath, cwd, afterSymlinkValidation, afterCanonicalValidation, afterInitialValidation) {
|
|
11833
11917
|
const lexicalRoot = attachmentContainmentRoot(filePath, cwd);
|
|
11834
|
-
const targetPath = isAbsolute3(filePath) ?
|
|
11918
|
+
const targetPath = isAbsolute3(filePath) ? resolve3(filePath) : resolve3(lexicalRoot, filePath);
|
|
11835
11919
|
if (!isPathWithin2(lexicalRoot, targetPath)) {
|
|
11836
11920
|
throw new ClaudeAttachmentError("attachment_outside_workspace", "Image attachment must be contained in the current workspace.");
|
|
11837
11921
|
}
|
|
@@ -13605,7 +13689,11 @@ function claudeUserMcpQueryOptions(policy) {
|
|
|
13605
13689
|
async function loadScopedMcpServers(cwd, scope) {
|
|
13606
13690
|
if (scope === "none") {
|
|
13607
13691
|
const sources = { user: "excluded", project: "excluded" };
|
|
13608
|
-
return {
|
|
13692
|
+
return {
|
|
13693
|
+
configs: {},
|
|
13694
|
+
layers: new Map,
|
|
13695
|
+
revision: { fingerprint: revisionFingerprint(sources), sources, scope }
|
|
13696
|
+
};
|
|
13609
13697
|
}
|
|
13610
13698
|
const path = claudeJsonPath();
|
|
13611
13699
|
const [global2, projectGlobal, projectLocal] = await Promise.all([
|
|
@@ -13618,11 +13706,33 @@ async function loadScopedMcpServers(cwd, scope) {
|
|
|
13618
13706
|
...projectGlobal?.value,
|
|
13619
13707
|
...projectLocal?.value
|
|
13620
13708
|
};
|
|
13709
|
+
const layers = new Map;
|
|
13710
|
+
for (const name of Object.keys(global2.value ?? {}))
|
|
13711
|
+
layers.set(name, "user");
|
|
13712
|
+
for (const name of Object.keys(projectGlobal?.value ?? {}))
|
|
13713
|
+
layers.set(name, "local");
|
|
13714
|
+
for (const name of Object.keys(projectLocal?.value ?? {}))
|
|
13715
|
+
layers.set(name, "project");
|
|
13621
13716
|
const sources = {
|
|
13622
13717
|
user: sourceDigest(global2.digest),
|
|
13623
13718
|
project: projectLocal ? sourceDigest(projectLocal.digest) : "excluded"
|
|
13624
13719
|
};
|
|
13625
|
-
return {
|
|
13720
|
+
return {
|
|
13721
|
+
configs,
|
|
13722
|
+
layers,
|
|
13723
|
+
revision: { fingerprint: revisionFingerprint(sources), sources, scope }
|
|
13724
|
+
};
|
|
13725
|
+
}
|
|
13726
|
+
async function claudeAccountOnlyMcpServerNames(cwd, settingSources, declared, strictMcpConfig = false) {
|
|
13727
|
+
const path = claudeAccountJsonPath();
|
|
13728
|
+
if (!path || strictMcpConfig)
|
|
13729
|
+
return [];
|
|
13730
|
+
const [user, local] = await Promise.all([
|
|
13731
|
+
settingSources.includes("user") ? readJsonSliceCached(path, "mcpServers", (config) => config?.mcpServers) : undefined,
|
|
13732
|
+
settingSources.includes("local") ? readJsonSliceCached(path, `projects:${cwd}:mcpServers`, (config) => config?.projects?.[cwd]?.mcpServers) : undefined
|
|
13733
|
+
]);
|
|
13734
|
+
const names = new Set([...Object.keys(user ?? {}), ...Object.keys(local ?? {})]);
|
|
13735
|
+
return Array.from(names).filter((name) => !declared.has(name)).sort();
|
|
13626
13736
|
}
|
|
13627
13737
|
function revisionFingerprint(sources) {
|
|
13628
13738
|
return createHash9("sha256").update(`user=${sources.user}\x00project=${sources.project}`).digest("base64url");
|
|
@@ -13631,21 +13741,28 @@ async function getMcpRuntimeConfig(cwd, env = process.env, connection, sources =
|
|
|
13631
13741
|
const scoped = await loadScopedMcpServers(cwd, normalizeScope(sources));
|
|
13632
13742
|
const { revision } = scoped;
|
|
13633
13743
|
const configs = allowConfigured ? Object.fromEntries(Object.entries(scoped.configs).filter(([name]) => allowConfigured(name))) : scoped.configs;
|
|
13634
|
-
const agentServer = getOrkestratorAgentMcpServerFromConnection(connection) ?? getOrkestratorAgentMcpServer(env);
|
|
13635
13744
|
const servers = toSdkServers(configs);
|
|
13745
|
+
const layers = new Map(Array.from(scoped.layers).filter(([name]) => Object.hasOwn(servers, name)));
|
|
13746
|
+
const agentServer = getOrkestratorAgentMcpServerFromConnection(connection) ?? getOrkestratorAgentMcpServer(env);
|
|
13636
13747
|
if (agentServer) {
|
|
13637
13748
|
servers[AGENT_MCP_SERVER_NAME] = agentServer;
|
|
13638
|
-
|
|
13749
|
+
layers.set(AGENT_MCP_SERVER_NAME, "orkestrator");
|
|
13750
|
+
if (connection?.design) {
|
|
13639
13751
|
servers["orkestrator-design"] = {
|
|
13640
13752
|
...agentServer,
|
|
13641
13753
|
url: new URL("/design-mcp", agentServer.url).toString()
|
|
13642
13754
|
};
|
|
13755
|
+
layers.set("orkestrator-design", "orkestrator");
|
|
13756
|
+
}
|
|
13643
13757
|
}
|
|
13644
13758
|
const artifactServer = getOrkestratorArtifactMcpServer(connection);
|
|
13645
|
-
if (artifactServer)
|
|
13759
|
+
if (artifactServer) {
|
|
13646
13760
|
servers[ORKESTRATOR_ARTIFACT_MCP_SERVER_NAME] = artifactServer;
|
|
13647
|
-
|
|
13761
|
+
layers.set(ORKESTRATOR_ARTIFACT_MCP_SERVER_NAME, "orkestrator");
|
|
13762
|
+
} else {
|
|
13648
13763
|
delete servers[ORKESTRATOR_ARTIFACT_MCP_SERVER_NAME];
|
|
13764
|
+
layers.delete(ORKESTRATOR_ARTIFACT_MCP_SERVER_NAME);
|
|
13765
|
+
}
|
|
13649
13766
|
const research = normalizeScope(sources) === "none" ? coordinatorResearchMcpServersFromEnv(env) : [];
|
|
13650
13767
|
for (const server of research)
|
|
13651
13768
|
servers[server.name] = { type: "http", url: server.url };
|
|
@@ -13657,6 +13774,7 @@ async function getMcpRuntimeConfig(cwd, env = process.env, connection, sources =
|
|
|
13657
13774
|
...artifactServer ? [ORKESTRATOR_ARTIFACT_MCP_SERVER_NAME] : [],
|
|
13658
13775
|
...research.map((server) => server.name)
|
|
13659
13776
|
]),
|
|
13777
|
+
layers,
|
|
13660
13778
|
revision
|
|
13661
13779
|
};
|
|
13662
13780
|
}
|
|
@@ -13664,130 +13782,508 @@ async function getMcpRuntimeConfig(cwd, env = process.env, connection, sources =
|
|
|
13664
13782
|
// ../../bridges/claude-bridge/src/services/session-manager-commands.ts
|
|
13665
13783
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
13666
13784
|
|
|
13667
|
-
//
|
|
13668
|
-
|
|
13669
|
-
|
|
13670
|
-
|
|
13671
|
-
|
|
13672
|
-
|
|
13673
|
-
|
|
13674
|
-
|
|
13675
|
-
|
|
13676
|
-
|
|
13677
|
-
|
|
13678
|
-
|
|
13679
|
-
|
|
13680
|
-
|
|
13681
|
-
|
|
13682
|
-
|
|
13683
|
-
"builtin",
|
|
13684
|
-
"project",
|
|
13685
|
-
"user",
|
|
13686
|
-
"plugin",
|
|
13687
|
-
"skill",
|
|
13688
|
-
"template",
|
|
13689
|
-
"extension",
|
|
13690
|
-
"orkestrator",
|
|
13691
|
-
"unknown"
|
|
13692
|
-
]);
|
|
13693
|
-
var EXECUTION_KINDS = new Set(NATIVE_AGENT_COMMAND_EXECUTION_KINDS);
|
|
13694
|
-
var ORIGINS2 = new Set(NATIVE_AGENT_COMMAND_ORIGINS);
|
|
13695
|
-
var UNAVAILABLE_REASONS = new Set(NATIVE_AGENT_COMMAND_UNAVAILABLE_REASONS);
|
|
13696
|
-
var ERROR_CODES = new Set(NATIVE_AGENT_COMMAND_CATALOGUE_ERROR_CODES);
|
|
13697
|
-
var encoder = new TextEncoder;
|
|
13698
|
-
function utf8ByteLength(value) {
|
|
13699
|
-
if (/^[\x00-\x7f]*$/.test(value))
|
|
13700
|
-
return value.length;
|
|
13701
|
-
return encoder.encode(value).byteLength;
|
|
13785
|
+
// ../../bridges/claude-bridge/src/services/claude-model-catalog.ts
|
|
13786
|
+
import { homedir as homedir2 } from "node:os";
|
|
13787
|
+
import { join as join12 } from "node:path";
|
|
13788
|
+
import { stat as stat5 } from "node:fs/promises";
|
|
13789
|
+
|
|
13790
|
+
// ../../bridges/claude-bridge/src/services/live-claude-control.ts
|
|
13791
|
+
var LIVE_CLAUDE_READ_TIMEOUT_MS = 5000;
|
|
13792
|
+
function readsProbeSettings(settingSources) {
|
|
13793
|
+
if (settingSources === undefined)
|
|
13794
|
+
return false;
|
|
13795
|
+
try {
|
|
13796
|
+
const sources = JSON.parse(settingSources);
|
|
13797
|
+
return Array.isArray(sources) && ["user", "project", "local"].every((source) => sources.includes(source));
|
|
13798
|
+
} catch {
|
|
13799
|
+
return false;
|
|
13800
|
+
}
|
|
13702
13801
|
}
|
|
13703
|
-
function
|
|
13704
|
-
|
|
13705
|
-
|
|
13706
|
-
|
|
13707
|
-
|
|
13708
|
-
|
|
13709
|
-
|
|
13710
|
-
|
|
13711
|
-
|
|
13712
|
-
|
|
13713
|
-
|
|
13714
|
-
bytes += size;
|
|
13715
|
-
out += char;
|
|
13802
|
+
function liveClaudeControls() {
|
|
13803
|
+
const runtimes = [];
|
|
13804
|
+
for (const session of sessions.values()) {
|
|
13805
|
+
const runtime = session.claudeRuntime;
|
|
13806
|
+
if (runtime?.state !== "open" || runtime.abortController.signal.aborted)
|
|
13807
|
+
continue;
|
|
13808
|
+
if (session.queryControlDraining === runtime.control || session.deleting)
|
|
13809
|
+
continue;
|
|
13810
|
+
if (!readsProbeSettings(runtime.launch.settingSources))
|
|
13811
|
+
continue;
|
|
13812
|
+
runtimes.push(runtime);
|
|
13716
13813
|
}
|
|
13717
|
-
return
|
|
13814
|
+
return runtimes.sort((left, right) => right.lastFrameAt - left.lastFrameAt).map((runtime) => runtime.control);
|
|
13718
13815
|
}
|
|
13719
|
-
function
|
|
13720
|
-
|
|
13721
|
-
|
|
13722
|
-
|
|
13723
|
-
|
|
13724
|
-
|
|
13725
|
-
|
|
13726
|
-
|
|
13816
|
+
async function readFromLiveClaude(read, timeoutMs = LIVE_CLAUDE_READ_TIMEOUT_MS) {
|
|
13817
|
+
for (const control of liveClaudeControls()) {
|
|
13818
|
+
let timer;
|
|
13819
|
+
try {
|
|
13820
|
+
const answer = read(control);
|
|
13821
|
+
if (answer === undefined)
|
|
13822
|
+
continue;
|
|
13823
|
+
answer.catch(() => {
|
|
13824
|
+
return;
|
|
13825
|
+
});
|
|
13826
|
+
const value = await Promise.race([
|
|
13827
|
+
answer,
|
|
13828
|
+
new Promise((resolve) => {
|
|
13829
|
+
timer = setTimeout(() => resolve(undefined), timeoutMs);
|
|
13830
|
+
})
|
|
13831
|
+
]);
|
|
13832
|
+
if (value !== undefined)
|
|
13833
|
+
return value;
|
|
13834
|
+
} catch (error) {
|
|
13835
|
+
debugLog("[live-claude-control] A running CLI could not answer:", error);
|
|
13836
|
+
} finally {
|
|
13837
|
+
clearTimeout(timer);
|
|
13727
13838
|
}
|
|
13728
|
-
hash ^= 0xffn;
|
|
13729
|
-
hash = hash * prime & mask;
|
|
13730
13839
|
}
|
|
13731
|
-
return
|
|
13732
|
-
}
|
|
13733
|
-
function isRecord2(value) {
|
|
13734
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
13840
|
+
return;
|
|
13735
13841
|
}
|
|
13736
|
-
function
|
|
13737
|
-
if (typeof
|
|
13738
|
-
return;
|
|
13739
|
-
if (value.length === 0 || value.trim() !== value || /\s/.test(value))
|
|
13842
|
+
function liveInitializationResult(control) {
|
|
13843
|
+
if (typeof control.initializationResult !== "function")
|
|
13740
13844
|
return;
|
|
13741
|
-
return
|
|
13845
|
+
return control.initializationResult().then((result) => result && typeof result === "object" ? result : undefined);
|
|
13742
13846
|
}
|
|
13743
|
-
|
|
13744
|
-
|
|
13745
|
-
|
|
13746
|
-
|
|
13747
|
-
|
|
13847
|
+
|
|
13848
|
+
// ../../bridges/claude-bridge/src/services/claude-sign-in.ts
|
|
13849
|
+
var AUTH_CACHE_TTL_MS = 30000;
|
|
13850
|
+
var FAILED_AUTH_CACHE_TTL_MS = 5000;
|
|
13851
|
+
var CLAUDE_SIGN_IN = {
|
|
13852
|
+
kind: "terminal",
|
|
13853
|
+
hint: "Sign in to Claude from the sign-in card in this tab or from Settings → Claude."
|
|
13854
|
+
};
|
|
13855
|
+
var CLAUDE_SIGN_IN_REQUIRED_MESSAGE = "Claude isn't signed in. Sign in to Claude to keep working.";
|
|
13856
|
+
var authCache;
|
|
13857
|
+
var authRead;
|
|
13858
|
+
var authReadGeneration;
|
|
13859
|
+
var authRefreshPending = false;
|
|
13860
|
+
var authGeneration = 0;
|
|
13861
|
+
var turnAuthenticationFailedUntil = 0;
|
|
13862
|
+
var reuseLiveAccounts = true;
|
|
13863
|
+
function withTurnFailure(value) {
|
|
13864
|
+
return Date.now() < turnAuthenticationFailedUntil && value.state === "signed-in" ? { ...value, state: "expired" } : value;
|
|
13748
13865
|
}
|
|
13749
|
-
function
|
|
13750
|
-
return
|
|
13866
|
+
function presentSource(value) {
|
|
13867
|
+
return value && value !== "none" ? value : undefined;
|
|
13751
13868
|
}
|
|
13752
|
-
function
|
|
13753
|
-
|
|
13754
|
-
|
|
13755
|
-
|
|
13756
|
-
|
|
13757
|
-
const reason = typeof value.reason === "string" && UNAVAILABLE_REASONS.has(value.reason) ? value.reason : undefined;
|
|
13758
|
-
const message = boundedText(value.message, COMMAND_CATALOGUE_LIMITS.maxAvailabilityMessageBytes);
|
|
13759
|
-
if (value.state === "available")
|
|
13760
|
-
return { state: "available" };
|
|
13869
|
+
function normalizeClaudeAccount(account) {
|
|
13870
|
+
const source = presentSource(account.apiKeySource) ?? presentSource(account.tokenSource);
|
|
13871
|
+
const externalProvider = account.apiProvider && account.apiProvider !== "firstParty" ? account.apiProvider : undefined;
|
|
13872
|
+
const signedIn = Boolean(source || account.subscriptionType || account.organization || externalProvider);
|
|
13873
|
+
const label = account.organization || account.subscriptionType || externalProvider;
|
|
13761
13874
|
return {
|
|
13762
|
-
state: "
|
|
13763
|
-
|
|
13764
|
-
|
|
13875
|
+
state: signedIn ? "signed-in" : "needs-auth",
|
|
13876
|
+
...label ? {
|
|
13877
|
+
account: {
|
|
13878
|
+
label,
|
|
13879
|
+
...account.subscriptionType ? { plan: account.subscriptionType } : {}
|
|
13880
|
+
}
|
|
13881
|
+
} : {},
|
|
13882
|
+
signIn: CLAUDE_SIGN_IN,
|
|
13883
|
+
signOut: false
|
|
13765
13884
|
};
|
|
13766
13885
|
}
|
|
13767
|
-
function
|
|
13768
|
-
|
|
13769
|
-
|
|
13770
|
-
|
|
13771
|
-
|
|
13772
|
-
|
|
13773
|
-
|
|
13774
|
-
|
|
13775
|
-
|
|
13886
|
+
function claudeAccountKey(status) {
|
|
13887
|
+
return JSON.stringify([status.state, status.account?.label, status.account?.plan]);
|
|
13888
|
+
}
|
|
13889
|
+
function claudeObservedAccountKey() {
|
|
13890
|
+
const value = authCache?.value;
|
|
13891
|
+
return value && value.state !== "unknown" ? claudeAccountKey(value) : undefined;
|
|
13892
|
+
}
|
|
13893
|
+
function liveSignedInAccount() {
|
|
13894
|
+
return readFromLiveClaude((control) => liveInitializationResult(control)?.then((result) => {
|
|
13895
|
+
const account = result?.account;
|
|
13896
|
+
if (!account || typeof account !== "object")
|
|
13897
|
+
return;
|
|
13898
|
+
const status = normalizeClaudeAccount(account);
|
|
13899
|
+
return status.state === "signed-in" ? status : undefined;
|
|
13900
|
+
}));
|
|
13901
|
+
}
|
|
13902
|
+
async function probeAccount() {
|
|
13903
|
+
if (reuseLiveAccounts) {
|
|
13904
|
+
const live = await liveSignedInAccount();
|
|
13905
|
+
if (live && reuseLiveAccounts)
|
|
13906
|
+
return live;
|
|
13776
13907
|
}
|
|
13777
|
-
|
|
13778
|
-
|
|
13908
|
+
let probe;
|
|
13909
|
+
try {
|
|
13910
|
+
probe = controlOnlyQuery({
|
|
13911
|
+
cwd: process.env.CWD || process.cwd(),
|
|
13912
|
+
env: { ...process.env },
|
|
13913
|
+
...claudeExecutableOptions()
|
|
13914
|
+
});
|
|
13915
|
+
return normalizeClaudeAccount(await probe.accountInfo());
|
|
13916
|
+
} finally {
|
|
13917
|
+
await Promise.resolve(probe?.close()).catch(() => {
|
|
13918
|
+
return;
|
|
13919
|
+
});
|
|
13779
13920
|
}
|
|
13780
|
-
return Object.keys(policy).length > 0 ? policy : undefined;
|
|
13781
13921
|
}
|
|
13782
|
-
function
|
|
13783
|
-
|
|
13784
|
-
|
|
13785
|
-
|
|
13786
|
-
|
|
13787
|
-
|
|
13788
|
-
|
|
13789
|
-
|
|
13790
|
-
|
|
13922
|
+
function readClaudeAuthStatus() {
|
|
13923
|
+
if (authCache && authCache.expiresAt > Date.now()) {
|
|
13924
|
+
return Promise.resolve(withTurnFailure(authCache.value));
|
|
13925
|
+
}
|
|
13926
|
+
if (authRead)
|
|
13927
|
+
return authRead;
|
|
13928
|
+
const generation = authGeneration;
|
|
13929
|
+
const read = probeAccount().then((value) => ({ value, ttl: AUTH_CACHE_TTL_MS }), () => ({
|
|
13930
|
+
value: {
|
|
13931
|
+
state: "unknown",
|
|
13932
|
+
signIn: CLAUDE_SIGN_IN,
|
|
13933
|
+
signOut: false
|
|
13934
|
+
},
|
|
13935
|
+
ttl: FAILED_AUTH_CACHE_TTL_MS
|
|
13936
|
+
})).then(({ value, ttl }) => {
|
|
13937
|
+
if (generation === authGeneration) {
|
|
13938
|
+
authCache = { expiresAt: Date.now() + ttl, value };
|
|
13939
|
+
}
|
|
13940
|
+
return withTurnFailure(value);
|
|
13941
|
+
}).finally(() => {
|
|
13942
|
+
if (authRead !== read)
|
|
13943
|
+
return;
|
|
13944
|
+
authRead = undefined;
|
|
13945
|
+
authReadGeneration = undefined;
|
|
13946
|
+
if (authRefreshPending) {
|
|
13947
|
+
authRefreshPending = false;
|
|
13948
|
+
readClaudeAuthStatus();
|
|
13949
|
+
}
|
|
13950
|
+
});
|
|
13951
|
+
authReadGeneration = generation;
|
|
13952
|
+
authRead = read;
|
|
13953
|
+
return read;
|
|
13954
|
+
}
|
|
13955
|
+
function noteClaudeAuthenticationFailure() {
|
|
13956
|
+
reuseLiveAccounts = false;
|
|
13957
|
+
turnAuthenticationFailedUntil = Date.now() + AUTH_CACHE_TTL_MS;
|
|
13958
|
+
authCache = undefined;
|
|
13959
|
+
if (authRead && authReadGeneration !== authGeneration)
|
|
13960
|
+
authRefreshPending = true;
|
|
13961
|
+
readClaudeAuthStatus();
|
|
13962
|
+
}
|
|
13963
|
+
function noteClaudeAuthenticationWorked() {
|
|
13964
|
+
reuseLiveAccounts = true;
|
|
13965
|
+
authGeneration += 1;
|
|
13966
|
+
authRefreshPending = false;
|
|
13967
|
+
turnAuthenticationFailedUntil = 0;
|
|
13968
|
+
if (authCache?.value.state === "needs-auth")
|
|
13969
|
+
authCache = undefined;
|
|
13970
|
+
}
|
|
13971
|
+
function claudeReadiness() {
|
|
13972
|
+
const cached = authCache;
|
|
13973
|
+
if (cached?.value.state !== "needs-auth")
|
|
13974
|
+
return;
|
|
13975
|
+
if (cached.expiresAt <= Date.now())
|
|
13976
|
+
readClaudeAuthStatus();
|
|
13977
|
+
return {
|
|
13978
|
+
state: "authentication-required",
|
|
13979
|
+
message: CLAUDE_SIGN_IN_REQUIRED_MESSAGE,
|
|
13980
|
+
signIn: CLAUDE_SIGN_IN
|
|
13981
|
+
};
|
|
13982
|
+
}
|
|
13983
|
+
|
|
13984
|
+
// ../../bridges/claude-bridge/src/services/claude-model-catalog.ts
|
|
13985
|
+
var CLAUDE_MODEL_CACHE_TTL_MS = 60 * 60000;
|
|
13986
|
+
var CLAUDE_MODEL_PROBE_TIMEOUT_MS = 25000;
|
|
13987
|
+
var remembered;
|
|
13988
|
+
var liveAnswers = new WeakMap;
|
|
13989
|
+
var invalidLiveAnswers = new WeakSet;
|
|
13990
|
+
var generation = 0;
|
|
13991
|
+
var probe;
|
|
13992
|
+
function invalidateClaudeModelCatalog() {
|
|
13993
|
+
for (const control of liveClaudeControls())
|
|
13994
|
+
invalidLiveAnswers.add(control);
|
|
13995
|
+
remembered = undefined;
|
|
13996
|
+
generation += 1;
|
|
13997
|
+
}
|
|
13998
|
+
function catalogModels(models) {
|
|
13999
|
+
return models.map((model) => ({
|
|
14000
|
+
id: model.value,
|
|
14001
|
+
resolvedModel: model.resolvedModel,
|
|
14002
|
+
name: model.displayName,
|
|
14003
|
+
description: model.description,
|
|
14004
|
+
supportsFastMode: model.supportsFastMode,
|
|
14005
|
+
supportsEffort: model.supportsEffort,
|
|
14006
|
+
supportedEffortLevels: model.supportedEffortLevels,
|
|
14007
|
+
supportsAdaptiveThinking: model.supportsAdaptiveThinking,
|
|
14008
|
+
supportsAutoMode: model.supportsAutoMode
|
|
14009
|
+
}));
|
|
14010
|
+
}
|
|
14011
|
+
async function claudeCliIdentity() {
|
|
14012
|
+
const configDir = process.env.CLAUDE_CONFIG_DIR?.trim() || join12(homedir2(), ".claude");
|
|
14013
|
+
const executable = process.env.CLAUDE_CLI_PATH?.trim();
|
|
14014
|
+
const resolved = executable ? Bun.which(executable, { PATH: process.env.PATH }) || executable : undefined;
|
|
14015
|
+
const cwd = process.env.CWD || process.cwd();
|
|
14016
|
+
const paths = [
|
|
14017
|
+
resolved,
|
|
14018
|
+
join12(configDir, "settings.json"),
|
|
14019
|
+
join12(cwd, ".claude/settings.json"),
|
|
14020
|
+
join12(cwd, ".claude/settings.local.json")
|
|
14021
|
+
];
|
|
14022
|
+
const files = await Promise.all(paths.map(async (path) => {
|
|
14023
|
+
const file = path ? await stat5(path).catch(() => {
|
|
14024
|
+
return;
|
|
14025
|
+
}) : undefined;
|
|
14026
|
+
return [path, file?.size, file?.mtimeMs, file?.ctimeMs];
|
|
14027
|
+
}));
|
|
14028
|
+
return JSON.stringify([configDir, cwd, files]);
|
|
14029
|
+
}
|
|
14030
|
+
function accountKeyOf(account) {
|
|
14031
|
+
if (!account || typeof account !== "object")
|
|
14032
|
+
return;
|
|
14033
|
+
return claudeAccountKey(normalizeClaudeAccount(account));
|
|
14034
|
+
}
|
|
14035
|
+
async function rememberModels(models, account, at = generation, cli, expiresAt) {
|
|
14036
|
+
if (!account || typeof account !== "object" || models.length === 0)
|
|
14037
|
+
return;
|
|
14038
|
+
const status = normalizeClaudeAccount(account);
|
|
14039
|
+
if (status.state !== "signed-in")
|
|
14040
|
+
return;
|
|
14041
|
+
const identity = cli ?? await claudeCliIdentity();
|
|
14042
|
+
if (at !== generation)
|
|
14043
|
+
return;
|
|
14044
|
+
remembered = {
|
|
14045
|
+
cli: identity,
|
|
14046
|
+
account: claudeAccountKey(status),
|
|
14047
|
+
models,
|
|
14048
|
+
expiresAt: expiresAt ?? Date.now() + CLAUDE_MODEL_CACHE_TTL_MS
|
|
14049
|
+
};
|
|
14050
|
+
}
|
|
14051
|
+
async function rememberedModels() {
|
|
14052
|
+
const entry = remembered;
|
|
14053
|
+
if (!entry || entry.expiresAt <= Date.now())
|
|
14054
|
+
return;
|
|
14055
|
+
const observed = claudeObservedAccountKey();
|
|
14056
|
+
if (observed !== undefined && observed !== entry.account)
|
|
14057
|
+
return;
|
|
14058
|
+
return entry.cli === await claudeCliIdentity() ? entry.models : undefined;
|
|
14059
|
+
}
|
|
14060
|
+
async function liveModels() {
|
|
14061
|
+
const observed = claudeObservedAccountKey();
|
|
14062
|
+
const at = generation;
|
|
14063
|
+
const cli = await claudeCliIdentity();
|
|
14064
|
+
return readFromLiveClaude(async (control) => {
|
|
14065
|
+
if (invalidLiveAnswers.has(control))
|
|
14066
|
+
return;
|
|
14067
|
+
let identity = liveAnswers.get(control);
|
|
14068
|
+
if (!identity) {
|
|
14069
|
+
identity = { cli, expiresAt: Date.now() + CLAUDE_MODEL_CACHE_TTL_MS };
|
|
14070
|
+
liveAnswers.set(control, identity);
|
|
14071
|
+
}
|
|
14072
|
+
if (identity.cli !== cli || identity.expiresAt <= Date.now())
|
|
14073
|
+
return;
|
|
14074
|
+
const result = await liveInitializationResult(control);
|
|
14075
|
+
if (at !== generation || invalidLiveAnswers.has(control))
|
|
14076
|
+
return;
|
|
14077
|
+
if (!Array.isArray(result?.models) || result.models.length === 0)
|
|
14078
|
+
return;
|
|
14079
|
+
const account = accountKeyOf(result.account);
|
|
14080
|
+
if (observed !== undefined && account !== undefined && account !== observed)
|
|
14081
|
+
return;
|
|
14082
|
+
return { models: result.models, account: result.account, at, ...identity };
|
|
14083
|
+
});
|
|
14084
|
+
}
|
|
14085
|
+
function fallbackCatalog() {
|
|
14086
|
+
return {
|
|
14087
|
+
source: "fallback",
|
|
14088
|
+
models: CLAUDE_FALLBACK_MODEL_CATALOG.map((model) => ({
|
|
14089
|
+
...model,
|
|
14090
|
+
...model.supportedEffortLevels ? { supportedEffortLevels: [...model.supportedEffortLevels] } : {}
|
|
14091
|
+
}))
|
|
14092
|
+
};
|
|
14093
|
+
}
|
|
14094
|
+
async function probeModels(at) {
|
|
14095
|
+
let q;
|
|
14096
|
+
let timer;
|
|
14097
|
+
try {
|
|
14098
|
+
const cwd = process.env.CWD || process.cwd();
|
|
14099
|
+
debugLog("[session-manager] Fetching supported models", { cwd });
|
|
14100
|
+
q = controlOnlyQuery({
|
|
14101
|
+
cwd,
|
|
14102
|
+
env: { ...process.env },
|
|
14103
|
+
...claudeExecutableOptions()
|
|
14104
|
+
});
|
|
14105
|
+
const control = q;
|
|
14106
|
+
const answer = Promise.all([
|
|
14107
|
+
control.supportedModels(),
|
|
14108
|
+
typeof control.accountInfo === "function" ? control.accountInfo().catch(() => {
|
|
14109
|
+
return;
|
|
14110
|
+
}) : undefined
|
|
14111
|
+
]);
|
|
14112
|
+
answer.catch(() => {
|
|
14113
|
+
return;
|
|
14114
|
+
});
|
|
14115
|
+
const [models, account] = await Promise.race([
|
|
14116
|
+
answer,
|
|
14117
|
+
new Promise((_resolve, reject) => {
|
|
14118
|
+
timer = setTimeout(() => reject(new Error("The model probe did not answer in time")), CLAUDE_MODEL_PROBE_TIMEOUT_MS);
|
|
14119
|
+
})
|
|
14120
|
+
]);
|
|
14121
|
+
debugLog("[session-manager] Supported models fetched", { count: models.length });
|
|
14122
|
+
await rememberModels(models, account, at);
|
|
14123
|
+
return { source: "sdk", models: catalogModels(models) };
|
|
14124
|
+
} catch (error) {
|
|
14125
|
+
console.error("[session-manager] Error fetching supported models:", error);
|
|
14126
|
+
return fallbackCatalog();
|
|
14127
|
+
} finally {
|
|
14128
|
+
clearTimeout(timer);
|
|
14129
|
+
if (q?.return) {
|
|
14130
|
+
try {
|
|
14131
|
+
await q.return();
|
|
14132
|
+
} catch (error) {
|
|
14133
|
+
debugLog("[session-manager] Failed to clean up model query:", error);
|
|
14134
|
+
}
|
|
14135
|
+
}
|
|
14136
|
+
}
|
|
14137
|
+
}
|
|
14138
|
+
function sharedProbe() {
|
|
14139
|
+
if (probe?.generation === generation)
|
|
14140
|
+
return probe.read;
|
|
14141
|
+
const read = probeModels(generation).finally(() => {
|
|
14142
|
+
if (probe?.read === read)
|
|
14143
|
+
probe = undefined;
|
|
14144
|
+
});
|
|
14145
|
+
probe = { generation, read };
|
|
14146
|
+
return read;
|
|
14147
|
+
}
|
|
14148
|
+
async function getAvailableModelCatalog() {
|
|
14149
|
+
const live = liveClaudeControls().length ? await liveModels() : undefined;
|
|
14150
|
+
if (live) {
|
|
14151
|
+
debugLog("[session-manager] Supported models read from a running CLI", {
|
|
14152
|
+
count: live.models.length
|
|
14153
|
+
});
|
|
14154
|
+
await rememberModels(live.models, live.account, live.at, live.cli, live.expiresAt);
|
|
14155
|
+
return { source: "sdk", models: catalogModels(live.models) };
|
|
14156
|
+
}
|
|
14157
|
+
const known = await rememberedModels();
|
|
14158
|
+
if (known)
|
|
14159
|
+
return { source: "sdk", models: catalogModels(known) };
|
|
14160
|
+
return sharedProbe();
|
|
14161
|
+
}
|
|
14162
|
+
|
|
14163
|
+
// ../protocol/src/agent-command-catalogue.ts
|
|
14164
|
+
var NATIVE_AGENT_COMMAND_CATALOGUE_VERSION = 1;
|
|
14165
|
+
var COMMAND_CATALOGUE_LIMITS = Object.freeze({
|
|
14166
|
+
maxCommands: 512,
|
|
14167
|
+
maxNameBytes: 256,
|
|
14168
|
+
maxIdBytes: 256,
|
|
14169
|
+
maxAliasesPerCommand: 16,
|
|
14170
|
+
maxAliasesTotal: 2048,
|
|
14171
|
+
maxDescriptionBytes: 1000,
|
|
14172
|
+
maxArgumentHintBytes: 512,
|
|
14173
|
+
maxAvailabilityMessageBytes: 512,
|
|
14174
|
+
maxBindingRevisionBytes: 128,
|
|
14175
|
+
maxWireBytes: 512 * 1024,
|
|
14176
|
+
maxArgumentBytes: 256 * 1024
|
|
14177
|
+
});
|
|
14178
|
+
var SOURCES = new Set([
|
|
14179
|
+
"builtin",
|
|
14180
|
+
"project",
|
|
14181
|
+
"user",
|
|
14182
|
+
"plugin",
|
|
14183
|
+
"skill",
|
|
14184
|
+
"template",
|
|
14185
|
+
"extension",
|
|
14186
|
+
"orkestrator",
|
|
14187
|
+
"unknown"
|
|
14188
|
+
]);
|
|
14189
|
+
var EXECUTION_KINDS = new Set(NATIVE_AGENT_COMMAND_EXECUTION_KINDS);
|
|
14190
|
+
var ORIGINS2 = new Set(NATIVE_AGENT_COMMAND_ORIGINS);
|
|
14191
|
+
var UNAVAILABLE_REASONS = new Set(NATIVE_AGENT_COMMAND_UNAVAILABLE_REASONS);
|
|
14192
|
+
var ERROR_CODES = new Set(NATIVE_AGENT_COMMAND_CATALOGUE_ERROR_CODES);
|
|
14193
|
+
var encoder = new TextEncoder;
|
|
14194
|
+
function utf8ByteLength(value) {
|
|
14195
|
+
if (/^[\x00-\x7f]*$/.test(value))
|
|
14196
|
+
return value.length;
|
|
14197
|
+
return encoder.encode(value).byteLength;
|
|
14198
|
+
}
|
|
14199
|
+
function truncateUtf8(value, maxBytes) {
|
|
14200
|
+
if (utf8ByteLength(value) <= maxBytes)
|
|
14201
|
+
return value;
|
|
14202
|
+
const marker = "…";
|
|
14203
|
+
const budget = Math.max(0, maxBytes - utf8ByteLength(marker));
|
|
14204
|
+
let bytes = 0;
|
|
14205
|
+
let out = "";
|
|
14206
|
+
for (const char of value) {
|
|
14207
|
+
const size = utf8ByteLength(char);
|
|
14208
|
+
if (bytes + size > budget)
|
|
14209
|
+
break;
|
|
14210
|
+
bytes += size;
|
|
14211
|
+
out += char;
|
|
14212
|
+
}
|
|
14213
|
+
return `${out}${marker}`;
|
|
14214
|
+
}
|
|
14215
|
+
function commandBindingRevision(parts) {
|
|
14216
|
+
let hash = 0xcbf29ce484222325n;
|
|
14217
|
+
const prime = 0x100000001b3n;
|
|
14218
|
+
const mask = 0xffffffffffffffffn;
|
|
14219
|
+
for (const part of parts) {
|
|
14220
|
+
for (const byte of encoder.encode(part)) {
|
|
14221
|
+
hash ^= BigInt(byte);
|
|
14222
|
+
hash = hash * prime & mask;
|
|
14223
|
+
}
|
|
14224
|
+
hash ^= 0xffn;
|
|
14225
|
+
hash = hash * prime & mask;
|
|
14226
|
+
}
|
|
14227
|
+
return hash.toString(16).padStart(16, "0");
|
|
14228
|
+
}
|
|
14229
|
+
function isRecord2(value) {
|
|
14230
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
14231
|
+
}
|
|
14232
|
+
function boundedIdentity(value, maxBytes) {
|
|
14233
|
+
if (typeof value !== "string")
|
|
14234
|
+
return;
|
|
14235
|
+
if (value.length === 0 || value.trim() !== value || /\s/.test(value))
|
|
14236
|
+
return;
|
|
14237
|
+
return utf8ByteLength(value) <= maxBytes ? value : undefined;
|
|
14238
|
+
}
|
|
14239
|
+
function boundedText(value, maxBytes) {
|
|
14240
|
+
if (typeof value !== "string")
|
|
14241
|
+
return;
|
|
14242
|
+
const trimmed = value.trim();
|
|
14243
|
+
return trimmed ? truncateUtf8(trimmed, maxBytes) : undefined;
|
|
14244
|
+
}
|
|
14245
|
+
function displayCommandName(name) {
|
|
14246
|
+
return name.startsWith("/") || name.startsWith("$") ? name : `/${name}`;
|
|
14247
|
+
}
|
|
14248
|
+
function normalizeAvailability(value) {
|
|
14249
|
+
if (!isRecord2(value))
|
|
14250
|
+
return;
|
|
14251
|
+
if (typeof value.state !== "string")
|
|
14252
|
+
return;
|
|
14253
|
+
const reason = typeof value.reason === "string" && UNAVAILABLE_REASONS.has(value.reason) ? value.reason : undefined;
|
|
14254
|
+
const message = boundedText(value.message, COMMAND_CATALOGUE_LIMITS.maxAvailabilityMessageBytes);
|
|
14255
|
+
if (value.state === "available")
|
|
14256
|
+
return { state: "available" };
|
|
14257
|
+
return {
|
|
14258
|
+
state: "unavailable",
|
|
14259
|
+
reason: reason ?? "unsupported",
|
|
14260
|
+
...message ? { message } : {}
|
|
14261
|
+
};
|
|
14262
|
+
}
|
|
14263
|
+
function normalizeInputPolicy(value) {
|
|
14264
|
+
if (!isRecord2(value))
|
|
14265
|
+
return;
|
|
14266
|
+
const policy = {};
|
|
14267
|
+
if (value.arguments === "none" || value.arguments === "optional" || value.arguments === "required") {
|
|
14268
|
+
policy.arguments = value.arguments;
|
|
14269
|
+
}
|
|
14270
|
+
if (value.attachments === "none" || value.attachments === "images" || value.attachments === "any") {
|
|
14271
|
+
policy.attachments = value.attachments;
|
|
14272
|
+
}
|
|
14273
|
+
if (value.busy === "queue" || value.busy === "idle" || value.busy === "running") {
|
|
14274
|
+
policy.busy = value.busy;
|
|
14275
|
+
}
|
|
14276
|
+
return Object.keys(policy).length > 0 ? policy : undefined;
|
|
14277
|
+
}
|
|
14278
|
+
function normalizeCommandCataloguePayload(payload, options = {}) {
|
|
14279
|
+
const record = isRecord2(payload) ? payload : {};
|
|
14280
|
+
const enhanced = record.catalogueVersion === NATIVE_AGENT_COMMAND_CATALOGUE_VERSION;
|
|
14281
|
+
const rows = Array.isArray(record.commands) ? record.commands : [];
|
|
14282
|
+
const byId = new Map;
|
|
14283
|
+
let truncated = record.truncated === true || rows.length > COMMAND_CATALOGUE_LIMITS.maxCommands;
|
|
14284
|
+
let rejected = 0;
|
|
14285
|
+
let aliasBudget = COMMAND_CATALOGUE_LIMITS.maxAliasesTotal;
|
|
14286
|
+
for (const candidate of rows.slice(0, COMMAND_CATALOGUE_LIMITS.maxCommands)) {
|
|
13791
14287
|
const row = typeof candidate === "string" ? { name: candidate } : candidate;
|
|
13792
14288
|
if (!isRecord2(row)) {
|
|
13793
14289
|
rejected += 1;
|
|
@@ -13968,7 +14464,7 @@ function idleSteerPromptReply(prompt, agentLabel) {
|
|
|
13968
14464
|
|
|
13969
14465
|
// ../../bridges/claude-bridge/src/services/claude-terminal-commands.ts
|
|
13970
14466
|
import { mkdir as mkdir5, readFile as readFile6, rename as rename5, writeFile as writeFile5 } from "node:fs/promises";
|
|
13971
|
-
import { join as
|
|
14467
|
+
import { join as join13 } from "node:path";
|
|
13972
14468
|
var FILE_NAME = "terminal-slash-commands.json";
|
|
13973
14469
|
var MAX_VERSIONS = 4;
|
|
13974
14470
|
var MAX_NAMES = 512;
|
|
@@ -13979,7 +14475,7 @@ var dirty = false;
|
|
|
13979
14475
|
var entries = [];
|
|
13980
14476
|
var writes = Promise.resolve();
|
|
13981
14477
|
function filePath() {
|
|
13982
|
-
return
|
|
14478
|
+
return join13(claudeOrkestratorDir(), FILE_NAME);
|
|
13983
14479
|
}
|
|
13984
14480
|
function validVersion(value) {
|
|
13985
14481
|
return typeof value === "string" && value.length > 0 && value.length <= MAX_VERSION_LENGTH;
|
|
@@ -14031,84 +14527,26 @@ function recordTerminalSlashCommands(version, commands) {
|
|
|
14031
14527
|
{ version, commands: names },
|
|
14032
14528
|
...entries.filter((entry) => entry.version !== version)
|
|
14033
14529
|
].slice(0, MAX_VERSIONS);
|
|
14034
|
-
writes = writes.then(async () => {
|
|
14035
|
-
await load();
|
|
14036
|
-
const directory = claudeOrkestratorDir();
|
|
14037
|
-
await mkdir5(directory, { recursive: true });
|
|
14038
|
-
const target = filePath();
|
|
14039
|
-
const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
|
|
14040
|
-
const snapshot = entries;
|
|
14041
|
-
await writeFile5(temporary, `${JSON.stringify({ versions: snapshot })}
|
|
14042
|
-
`, {
|
|
14043
|
-
mode: 384
|
|
14044
|
-
});
|
|
14045
|
-
await rename5(temporary, target);
|
|
14046
|
-
if (entries === snapshot)
|
|
14047
|
-
dirty = false;
|
|
14048
|
-
}).catch(() => {});
|
|
14049
|
-
}
|
|
14050
|
-
|
|
14051
|
-
// ../../bridges/claude-bridge/src/services/session-manager-catalog.ts
|
|
14052
|
-
import { createHash as createHash10 } from "node:crypto";
|
|
14053
|
-
|
|
14054
|
-
// ../../bridges/claude-bridge/src/services/live-claude-control.ts
|
|
14055
|
-
var LIVE_CLAUDE_READ_TIMEOUT_MS = 5000;
|
|
14056
|
-
function readsProbeSettings(settingSources) {
|
|
14057
|
-
if (settingSources === undefined)
|
|
14058
|
-
return false;
|
|
14059
|
-
try {
|
|
14060
|
-
const sources = JSON.parse(settingSources);
|
|
14061
|
-
return Array.isArray(sources) && ["user", "project", "local"].every((source) => sources.includes(source));
|
|
14062
|
-
} catch {
|
|
14063
|
-
return false;
|
|
14064
|
-
}
|
|
14065
|
-
}
|
|
14066
|
-
function liveClaudeControls() {
|
|
14067
|
-
const runtimes = [];
|
|
14068
|
-
for (const session of sessions.values()) {
|
|
14069
|
-
const runtime = session.claudeRuntime;
|
|
14070
|
-
if (runtime?.state !== "open" || runtime.abortController.signal.aborted)
|
|
14071
|
-
continue;
|
|
14072
|
-
if (session.queryControlDraining === runtime.control || session.deleting)
|
|
14073
|
-
continue;
|
|
14074
|
-
if (!readsProbeSettings(runtime.launch.settingSources))
|
|
14075
|
-
continue;
|
|
14076
|
-
runtimes.push(runtime);
|
|
14077
|
-
}
|
|
14078
|
-
return runtimes.sort((left, right) => right.lastFrameAt - left.lastFrameAt).map((runtime) => runtime.control);
|
|
14079
|
-
}
|
|
14080
|
-
async function readFromLiveClaude(read, timeoutMs = LIVE_CLAUDE_READ_TIMEOUT_MS) {
|
|
14081
|
-
for (const control of liveClaudeControls()) {
|
|
14082
|
-
let timer;
|
|
14083
|
-
try {
|
|
14084
|
-
const answer = read(control);
|
|
14085
|
-
if (answer === undefined)
|
|
14086
|
-
continue;
|
|
14087
|
-
answer.catch(() => {
|
|
14088
|
-
return;
|
|
14089
|
-
});
|
|
14090
|
-
const value = await Promise.race([
|
|
14091
|
-
answer,
|
|
14092
|
-
new Promise((resolve) => {
|
|
14093
|
-
timer = setTimeout(() => resolve(undefined), timeoutMs);
|
|
14094
|
-
})
|
|
14095
|
-
]);
|
|
14096
|
-
if (value !== undefined)
|
|
14097
|
-
return value;
|
|
14098
|
-
} catch (error) {
|
|
14099
|
-
debugLog("[live-claude-control] A running CLI could not answer:", error);
|
|
14100
|
-
} finally {
|
|
14101
|
-
clearTimeout(timer);
|
|
14102
|
-
}
|
|
14103
|
-
}
|
|
14104
|
-
return;
|
|
14105
|
-
}
|
|
14106
|
-
function liveInitializationResult(control) {
|
|
14107
|
-
if (typeof control.initializationResult !== "function")
|
|
14108
|
-
return;
|
|
14109
|
-
return control.initializationResult().then((result) => result && typeof result === "object" ? result : undefined);
|
|
14530
|
+
writes = writes.then(async () => {
|
|
14531
|
+
await load();
|
|
14532
|
+
const directory = claudeOrkestratorDir();
|
|
14533
|
+
await mkdir5(directory, { recursive: true });
|
|
14534
|
+
const target = filePath();
|
|
14535
|
+
const temporary = `${target}.${process.pid}.${Date.now()}.tmp`;
|
|
14536
|
+
const snapshot = entries;
|
|
14537
|
+
await writeFile5(temporary, `${JSON.stringify({ versions: snapshot })}
|
|
14538
|
+
`, {
|
|
14539
|
+
mode: 384
|
|
14540
|
+
});
|
|
14541
|
+
await rename5(temporary, target);
|
|
14542
|
+
if (entries === snapshot)
|
|
14543
|
+
dirty = false;
|
|
14544
|
+
}).catch(() => {});
|
|
14110
14545
|
}
|
|
14111
14546
|
|
|
14547
|
+
// ../../bridges/claude-bridge/src/services/session-manager-catalog.ts
|
|
14548
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
14549
|
+
|
|
14112
14550
|
// ../protocol/src/secret-redaction.ts
|
|
14113
14551
|
var TEXT_RULES = [
|
|
14114
14552
|
{
|
|
@@ -14145,7 +14583,11 @@ function redactSecrets(value) {
|
|
|
14145
14583
|
}
|
|
14146
14584
|
|
|
14147
14585
|
// ../../bridges/claude-bridge/src/services/mcp-runtime-status.ts
|
|
14148
|
-
|
|
14586
|
+
var FOREIGN_MCP_SOURCES = new Set(["plugin", "sdk", "claudeai"]);
|
|
14587
|
+
function mcpScope(scope, name, source, layers) {
|
|
14588
|
+
const layer = FOREIGN_MCP_SOURCES.has(source ?? "") ? undefined : layers?.get(name);
|
|
14589
|
+
if (layer)
|
|
14590
|
+
return layer;
|
|
14149
14591
|
if (name === "orkestrator")
|
|
14150
14592
|
return "orkestrator";
|
|
14151
14593
|
if (source?.includes("plugin") || scope?.includes("plugin"))
|
|
@@ -14167,145 +14609,16 @@ function mcpRuntimeState(status) {
|
|
|
14167
14609
|
return "unknown";
|
|
14168
14610
|
}
|
|
14169
14611
|
}
|
|
14170
|
-
function initMcpServerStatus(raw) {
|
|
14612
|
+
function initMcpServerStatus(raw, layers) {
|
|
14171
14613
|
const source = typeof raw.source === "string" ? raw.source : undefined;
|
|
14172
14614
|
return {
|
|
14173
14615
|
name: raw.name,
|
|
14174
14616
|
status: mcpRuntimeState(raw.status),
|
|
14175
|
-
...source ? { scope: mcpScope(source, raw.name) } : {},
|
|
14617
|
+
...source || layers?.has(raw.name) ? { scope: mcpScope(source, raw.name, source, layers) } : {},
|
|
14176
14618
|
...typeof raw.error === "string" && raw.error ? { error: raw.error } : {},
|
|
14177
14619
|
...Array.isArray(raw.tools) ? { tools: raw.tools.filter((tool) => typeof tool === "string") } : {}
|
|
14178
14620
|
};
|
|
14179
14621
|
}
|
|
14180
|
-
|
|
14181
|
-
// ../../bridges/claude-bridge/src/services/claude-sign-in.ts
|
|
14182
|
-
var AUTH_CACHE_TTL_MS = 30000;
|
|
14183
|
-
var FAILED_AUTH_CACHE_TTL_MS = 5000;
|
|
14184
|
-
var CLAUDE_SIGN_IN = {
|
|
14185
|
-
kind: "terminal",
|
|
14186
|
-
hint: "Sign in to Claude from the sign-in card in this tab or from Settings → Claude."
|
|
14187
|
-
};
|
|
14188
|
-
var CLAUDE_SIGN_IN_REQUIRED_MESSAGE = "Claude isn't signed in. Sign in to Claude to keep working.";
|
|
14189
|
-
var authCache;
|
|
14190
|
-
var authRead;
|
|
14191
|
-
var authReadGeneration;
|
|
14192
|
-
var authRefreshPending = false;
|
|
14193
|
-
var authGeneration = 0;
|
|
14194
|
-
var turnAuthenticationFailedUntil = 0;
|
|
14195
|
-
var reuseLiveAccounts = true;
|
|
14196
|
-
function withTurnFailure(value) {
|
|
14197
|
-
return Date.now() < turnAuthenticationFailedUntil && value.state === "signed-in" ? { ...value, state: "expired" } : value;
|
|
14198
|
-
}
|
|
14199
|
-
function presentSource(value) {
|
|
14200
|
-
return value && value !== "none" ? value : undefined;
|
|
14201
|
-
}
|
|
14202
|
-
function normalizeClaudeAccount(account) {
|
|
14203
|
-
const source = presentSource(account.apiKeySource) ?? presentSource(account.tokenSource);
|
|
14204
|
-
const externalProvider = account.apiProvider && account.apiProvider !== "firstParty" ? account.apiProvider : undefined;
|
|
14205
|
-
const signedIn = Boolean(source || account.subscriptionType || account.organization || externalProvider);
|
|
14206
|
-
const label = account.organization || account.subscriptionType || externalProvider;
|
|
14207
|
-
return {
|
|
14208
|
-
state: signedIn ? "signed-in" : "needs-auth",
|
|
14209
|
-
...label ? {
|
|
14210
|
-
account: {
|
|
14211
|
-
label,
|
|
14212
|
-
...account.subscriptionType ? { plan: account.subscriptionType } : {}
|
|
14213
|
-
}
|
|
14214
|
-
} : {},
|
|
14215
|
-
signIn: CLAUDE_SIGN_IN,
|
|
14216
|
-
signOut: false
|
|
14217
|
-
};
|
|
14218
|
-
}
|
|
14219
|
-
function liveSignedInAccount() {
|
|
14220
|
-
return readFromLiveClaude((control) => liveInitializationResult(control)?.then((result) => {
|
|
14221
|
-
const account = result?.account;
|
|
14222
|
-
if (!account || typeof account !== "object")
|
|
14223
|
-
return;
|
|
14224
|
-
const status = normalizeClaudeAccount(account);
|
|
14225
|
-
return status.state === "signed-in" ? status : undefined;
|
|
14226
|
-
}));
|
|
14227
|
-
}
|
|
14228
|
-
async function probeAccount() {
|
|
14229
|
-
if (reuseLiveAccounts) {
|
|
14230
|
-
const live = await liveSignedInAccount();
|
|
14231
|
-
if (live && reuseLiveAccounts)
|
|
14232
|
-
return live;
|
|
14233
|
-
}
|
|
14234
|
-
let probe;
|
|
14235
|
-
try {
|
|
14236
|
-
probe = controlOnlyQuery({
|
|
14237
|
-
cwd: process.env.CWD || process.cwd(),
|
|
14238
|
-
env: { ...process.env },
|
|
14239
|
-
...claudeExecutableOptions()
|
|
14240
|
-
});
|
|
14241
|
-
return normalizeClaudeAccount(await probe.accountInfo());
|
|
14242
|
-
} finally {
|
|
14243
|
-
await Promise.resolve(probe?.close()).catch(() => {
|
|
14244
|
-
return;
|
|
14245
|
-
});
|
|
14246
|
-
}
|
|
14247
|
-
}
|
|
14248
|
-
function readClaudeAuthStatus() {
|
|
14249
|
-
if (authCache && authCache.expiresAt > Date.now()) {
|
|
14250
|
-
return Promise.resolve(withTurnFailure(authCache.value));
|
|
14251
|
-
}
|
|
14252
|
-
if (authRead)
|
|
14253
|
-
return authRead;
|
|
14254
|
-
const generation = authGeneration;
|
|
14255
|
-
const read = probeAccount().then((value) => ({ value, ttl: AUTH_CACHE_TTL_MS }), () => ({
|
|
14256
|
-
value: {
|
|
14257
|
-
state: "unknown",
|
|
14258
|
-
signIn: CLAUDE_SIGN_IN,
|
|
14259
|
-
signOut: false
|
|
14260
|
-
},
|
|
14261
|
-
ttl: FAILED_AUTH_CACHE_TTL_MS
|
|
14262
|
-
})).then(({ value, ttl }) => {
|
|
14263
|
-
if (generation === authGeneration) {
|
|
14264
|
-
authCache = { expiresAt: Date.now() + ttl, value };
|
|
14265
|
-
}
|
|
14266
|
-
return withTurnFailure(value);
|
|
14267
|
-
}).finally(() => {
|
|
14268
|
-
if (authRead !== read)
|
|
14269
|
-
return;
|
|
14270
|
-
authRead = undefined;
|
|
14271
|
-
authReadGeneration = undefined;
|
|
14272
|
-
if (authRefreshPending) {
|
|
14273
|
-
authRefreshPending = false;
|
|
14274
|
-
readClaudeAuthStatus();
|
|
14275
|
-
}
|
|
14276
|
-
});
|
|
14277
|
-
authReadGeneration = generation;
|
|
14278
|
-
authRead = read;
|
|
14279
|
-
return read;
|
|
14280
|
-
}
|
|
14281
|
-
function noteClaudeAuthenticationFailure() {
|
|
14282
|
-
reuseLiveAccounts = false;
|
|
14283
|
-
turnAuthenticationFailedUntil = Date.now() + AUTH_CACHE_TTL_MS;
|
|
14284
|
-
authCache = undefined;
|
|
14285
|
-
if (authRead && authReadGeneration !== authGeneration)
|
|
14286
|
-
authRefreshPending = true;
|
|
14287
|
-
readClaudeAuthStatus();
|
|
14288
|
-
}
|
|
14289
|
-
function noteClaudeAuthenticationWorked() {
|
|
14290
|
-
reuseLiveAccounts = true;
|
|
14291
|
-
authGeneration += 1;
|
|
14292
|
-
authRefreshPending = false;
|
|
14293
|
-
turnAuthenticationFailedUntil = 0;
|
|
14294
|
-
if (authCache?.value.state === "needs-auth")
|
|
14295
|
-
authCache = undefined;
|
|
14296
|
-
}
|
|
14297
|
-
function claudeReadiness() {
|
|
14298
|
-
const cached = authCache;
|
|
14299
|
-
if (cached?.value.state !== "needs-auth")
|
|
14300
|
-
return;
|
|
14301
|
-
if (cached.expiresAt <= Date.now())
|
|
14302
|
-
readClaudeAuthStatus();
|
|
14303
|
-
return {
|
|
14304
|
-
state: "authentication-required",
|
|
14305
|
-
message: CLAUDE_SIGN_IN_REQUIRED_MESSAGE,
|
|
14306
|
-
signIn: CLAUDE_SIGN_IN
|
|
14307
|
-
};
|
|
14308
|
-
}
|
|
14309
14622
|
// ../../bridges/claude-bridge/src/services/session-manager-catalog.ts
|
|
14310
14623
|
function readableControl(session) {
|
|
14311
14624
|
if (!session)
|
|
@@ -14456,7 +14769,7 @@ function mcpTransport(status) {
|
|
|
14456
14769
|
function mcpError(error) {
|
|
14457
14770
|
return redactSecrets(error).slice(0, 2000);
|
|
14458
14771
|
}
|
|
14459
|
-
function normalizeMcp(status) {
|
|
14772
|
+
function normalizeMcp(status, layers) {
|
|
14460
14773
|
const mappedStatus = status.status === "pending" ? "connecting" : status.status;
|
|
14461
14774
|
const tools = (status.tools ?? []).map((tool) => tool.name).filter(Boolean).slice(0, 256);
|
|
14462
14775
|
const actions = status.status === "disabled" ? ["enable"] : status.status === "needs-auth" ? ["sign-in", "reconnect", "disable"] : ["reconnect", "disable"];
|
|
@@ -14465,7 +14778,7 @@ function normalizeMcp(status) {
|
|
|
14465
14778
|
id: status.name,
|
|
14466
14779
|
name: status.serverInfo?.name || status.name,
|
|
14467
14780
|
status: mappedStatus,
|
|
14468
|
-
scope: mcpScope(status.scope, status.name, status.source),
|
|
14781
|
+
scope: mcpScope(status.scope, status.name, status.source, layers),
|
|
14469
14782
|
...transport ? { transport } : {},
|
|
14470
14783
|
toolCount: tools.length,
|
|
14471
14784
|
...tools.length ? { tools } : {},
|
|
@@ -14473,18 +14786,11 @@ function normalizeMcp(status) {
|
|
|
14473
14786
|
actions
|
|
14474
14787
|
};
|
|
14475
14788
|
}
|
|
14476
|
-
|
|
14477
|
-
|
|
14478
|
-
|
|
14479
|
-
|
|
14480
|
-
|
|
14481
|
-
if (control?.mcpServerStatus) {
|
|
14482
|
-
try {
|
|
14483
|
-
session.mcpInventory = (await control.mcpServerStatus()).slice(0, 128).map(normalizeMcp);
|
|
14484
|
-
} catch (error) {
|
|
14485
|
-
rethrowUnlessClosedTransport(error);
|
|
14486
|
-
}
|
|
14487
|
-
} else if (!session.mcpInventory && session.initData?.mcpServers) {
|
|
14789
|
+
function liveMcpInventory(session, statuses) {
|
|
14790
|
+
return statuses.slice(0, 128).map((status) => normalizeMcp(status, session.mcpServerLayers));
|
|
14791
|
+
}
|
|
14792
|
+
function retainedMcpInventory(session) {
|
|
14793
|
+
if (!session.mcpInventory && session.initData?.mcpServers) {
|
|
14488
14794
|
session.mcpInventory = session.initData.mcpServers.slice(0, 128).map((server) => ({
|
|
14489
14795
|
id: server.name,
|
|
14490
14796
|
name: server.name,
|
|
@@ -14496,7 +14802,34 @@ async function readSessionMcpServers(sessionId) {
|
|
|
14496
14802
|
...server.error ? { error: mcpError(server.error) } : {}
|
|
14497
14803
|
}));
|
|
14498
14804
|
}
|
|
14499
|
-
return session.mcpInventory
|
|
14805
|
+
return session.mcpInventory;
|
|
14806
|
+
}
|
|
14807
|
+
function applyProbeMcpStatus(session, serverId, statuses) {
|
|
14808
|
+
const status = statuses.find((candidate) => candidate.name === serverId);
|
|
14809
|
+
if (!status)
|
|
14810
|
+
return;
|
|
14811
|
+
const inventory = retainedMcpInventory(session);
|
|
14812
|
+
session.mcpInventory = inventory?.map((row) => {
|
|
14813
|
+
if (row.id !== serverId)
|
|
14814
|
+
return row;
|
|
14815
|
+
const updated = normalizeMcp(status, session.mcpServerLayers);
|
|
14816
|
+
return { ...updated, scope: row.scope ?? updated.scope };
|
|
14817
|
+
});
|
|
14818
|
+
}
|
|
14819
|
+
async function readSessionMcpServers(sessionId) {
|
|
14820
|
+
const session = sessions.get(sessionId);
|
|
14821
|
+
if (!session)
|
|
14822
|
+
return [];
|
|
14823
|
+
const control = readableControl(session);
|
|
14824
|
+
if (control?.mcpServerStatus) {
|
|
14825
|
+
try {
|
|
14826
|
+
session.mcpInventory = liveMcpInventory(session, await control.mcpServerStatus());
|
|
14827
|
+
} catch (error) {
|
|
14828
|
+
rethrowUnlessClosedTransport(error);
|
|
14829
|
+
}
|
|
14830
|
+
return session.mcpInventory ?? [];
|
|
14831
|
+
}
|
|
14832
|
+
return retainedMcpInventory(session) ?? [];
|
|
14500
14833
|
}
|
|
14501
14834
|
async function performSessionMcpAction(sessionId, serverId, action) {
|
|
14502
14835
|
const session = sessions.get(sessionId);
|
|
@@ -14519,7 +14852,11 @@ async function performSessionMcpAction(sessionId, serverId, action) {
|
|
|
14519
14852
|
await control.reconnectMcpServer?.(serverId);
|
|
14520
14853
|
}
|
|
14521
14854
|
if (control.mcpServerStatus) {
|
|
14522
|
-
|
|
14855
|
+
const statuses = await control.mcpServerStatus();
|
|
14856
|
+
if (probe)
|
|
14857
|
+
applyProbeMcpStatus(session, serverId, statuses);
|
|
14858
|
+
else
|
|
14859
|
+
session.mcpInventory = liveMcpInventory(session, statuses);
|
|
14523
14860
|
}
|
|
14524
14861
|
return {};
|
|
14525
14862
|
} finally {
|
|
@@ -15140,6 +15477,7 @@ async function refreshClaudeCommandCatalogue(sessionId) {
|
|
|
15140
15477
|
}
|
|
15141
15478
|
}
|
|
15142
15479
|
async function refreshClaudeCatalogs() {
|
|
15480
|
+
invalidateClaudeModelCatalog();
|
|
15143
15481
|
const sessionIds = Array.from(sessions.keys()).slice(0, 128);
|
|
15144
15482
|
let next = 0;
|
|
15145
15483
|
await Promise.allSettled(Array.from({ length: Math.min(8, sessionIds.length) }, async () => {
|
|
@@ -15229,10 +15567,17 @@ function appendLocalCommandResult(session, content, key) {
|
|
|
15229
15567
|
}
|
|
15230
15568
|
|
|
15231
15569
|
// ../../bridges/claude-bridge/src/services/session-manager-prompt-mcp-sync.ts
|
|
15232
|
-
function createClaudeRuntimeMcp(servers, declared) {
|
|
15233
|
-
|
|
15570
|
+
function createClaudeRuntimeMcp(servers, declared, accountOnly = []) {
|
|
15571
|
+
const declaredNames = new Set(declared);
|
|
15572
|
+
const loadedOnlyByAccount = new Set(Array.from(accountOnly).filter((name) => !declaredNames.has(name)));
|
|
15573
|
+
return {
|
|
15574
|
+
servers,
|
|
15575
|
+
claimed: false,
|
|
15576
|
+
declared: declaredNames,
|
|
15577
|
+
stale: new Set(loadedOnlyByAccount),
|
|
15578
|
+
accountOnly: loadedOnlyByAccount
|
|
15579
|
+
};
|
|
15234
15580
|
}
|
|
15235
|
-
var FOREIGN_SOURCES = new Set(["plugin", "sdk", "claudeai"]);
|
|
15236
15581
|
var MAX_REPORTED_STALE_SERVERS = 256;
|
|
15237
15582
|
function conflict(message) {
|
|
15238
15583
|
return sessionOperationError("conflict", message);
|
|
@@ -15287,10 +15632,12 @@ async function syncClaudeRuntimeMcp(runtime, next) {
|
|
|
15287
15632
|
runtime.mcpServers = "";
|
|
15288
15633
|
throw conflict("Claude required MCP server is not connected; retry the prompt");
|
|
15289
15634
|
}
|
|
15290
|
-
const stillRuns = (name) => statuses ? statuses.some((server) => server.name === name && server.status !== "disabled" && !
|
|
15635
|
+
const stillRuns = (name) => statuses ? statuses.some((server) => server.name === name && server.status !== "disabled" && !FOREIGN_MCP_SOURCES.has(server.source ?? "")) : !removed?.has(name);
|
|
15291
15636
|
for (const name of Array.from(mcp.stale)) {
|
|
15292
|
-
if (next.names.has(name) || !stillRuns(name))
|
|
15637
|
+
if (next.names.has(name) || !stillRuns(name)) {
|
|
15293
15638
|
mcp.stale.delete(name);
|
|
15639
|
+
mcp.accountOnly.delete(name);
|
|
15640
|
+
}
|
|
15294
15641
|
}
|
|
15295
15642
|
for (const name of undeclared)
|
|
15296
15643
|
if (stillRuns(name))
|
|
@@ -15332,7 +15679,7 @@ function createStaleMcpServerHook(mcp) {
|
|
|
15332
15679
|
hookSpecificOutput: {
|
|
15333
15680
|
hookEventName: "PreToolUse",
|
|
15334
15681
|
permissionDecision: "deny",
|
|
15335
|
-
permissionDecisionReason: `The MCP server "${server}" was removed from this session's configuration, so ${input.tool_name} is not available. This Claude process loaded it at launch and cannot unload it; it is gone once the process closes after an idle period, or when the session is stopped.`
|
|
15682
|
+
permissionDecisionReason: mcp.accountOnly.has(server) ? `The MCP server "${server}" is only in this Claude account's own configuration, not in the user's Claude configuration, so ${input.tool_name} is not available. Orkestrator replaces an account's MCP servers with the user's when the account's Claude starts; add the server to the user's Claude configuration to use it.` : `The MCP server "${server}" was removed from this session's configuration, so ${input.tool_name} is not available. This Claude process loaded it at launch and cannot unload it; it is gone once the process closes after an idle period, or when the session is stopped.`
|
|
15336
15683
|
}
|
|
15337
15684
|
};
|
|
15338
15685
|
};
|
|
@@ -15584,6 +15931,60 @@ function claudeArtifactServerTools(servers) {
|
|
|
15584
15931
|
return ARTIFACT_TOOL_NAMES.map((name) => `mcp__${ORKESTRATOR_ARTIFACT_MCP_SERVER_NAME}__${name}`);
|
|
15585
15932
|
}
|
|
15586
15933
|
|
|
15934
|
+
// ../protocol/src/node/repository-instructions.ts
|
|
15935
|
+
import { open as open3, realpath as realpath3 } from "node:fs/promises";
|
|
15936
|
+
import { join as join14, relative as relative2, isAbsolute as isAbsolute4 } from "node:path";
|
|
15937
|
+
|
|
15938
|
+
// ../protocol/src/agent-system-instructions.ts
|
|
15939
|
+
var AGENT_IMAGE_PREVIEW_INSTRUCTION = "Orkestrator renders Markdown images inline in the transcript. When you show the user an image in your reply (a screenshot, rendered preview, or chart) using Markdown image syntax, reference it by its absolute path. In a managed worktree or container environment, save the file inside the working directory, preferably in a git-ignored folder so preview files stay out of the change set. Local image previews are limited to Orkestrator-managed workspace storage or the container's /workspace. Project-home checkouts are excluded from host preview reads, even when they are the working directory, so images saved there cannot be previewed from a local Markdown path. Paths outside previewable storage, such as /tmp, also show a placeholder.";
|
|
15940
|
+
var AGENT_DOCUMENT_INSTRUCTION = "When the user asks for a document (a report, design doc, plan, analysis, guide, or other writing to keep), prefer writing it as a Markdown file in a `docs/` folder at the root of the working directory, and tell the user the file's path. Project instructions (such as AGENTS.md or CLAUDE.md), local skills, and the user's own request take priority over this default when they say where or how to write documents.";
|
|
15941
|
+
var GENERAL_AGENT_INSTRUCTIONS = [
|
|
15942
|
+
AGENT_IMAGE_PREVIEW_INSTRUCTION,
|
|
15943
|
+
AGENT_DOCUMENT_INSTRUCTION
|
|
15944
|
+
];
|
|
15945
|
+
function agentSystemInstructions(providerSpecific = []) {
|
|
15946
|
+
return [...GENERAL_AGENT_INSTRUCTIONS, ...providerSpecific].filter((line) => line.trim().length > 0).join(`
|
|
15947
|
+
|
|
15948
|
+
`);
|
|
15949
|
+
}
|
|
15950
|
+
var REPOSITORY_INSTRUCTIONS_FILE = "AGENTS.md";
|
|
15951
|
+
function repositoryInstructionsBlock(path, content, truncated) {
|
|
15952
|
+
return [
|
|
15953
|
+
`# Repository instructions (${REPOSITORY_INSTRUCTIONS_FILE})`,
|
|
15954
|
+
`This session does not load the repository's ${REPOSITORY_INSTRUCTIONS_FILE} on its own, so Orkestrator includes it here. Follow it as project instructions. Contents of ${path}:`,
|
|
15955
|
+
content.trimEnd(),
|
|
15956
|
+
...truncated ? [
|
|
15957
|
+
`[${REPOSITORY_INSTRUCTIONS_FILE} is longer than this session can hold, so it is cut here. Read the rest from ${path} before relying on anything it may say.]`
|
|
15958
|
+
] : []
|
|
15959
|
+
].join(`
|
|
15960
|
+
|
|
15961
|
+
`);
|
|
15962
|
+
}
|
|
15963
|
+
|
|
15964
|
+
// ../protocol/src/node/repository-instructions.ts
|
|
15965
|
+
var MAX_REPOSITORY_INSTRUCTIONS_BYTES = 256 * 1024;
|
|
15966
|
+
async function readRepositoryInstructions(cwd, maxBytes = MAX_REPOSITORY_INSTRUCTIONS_BYTES) {
|
|
15967
|
+
const path = join14(cwd, REPOSITORY_INSTRUCTIONS_FILE);
|
|
15968
|
+
try {
|
|
15969
|
+
const [root, target] = await Promise.all([realpath3(cwd), realpath3(path)]);
|
|
15970
|
+
const inside = relative2(root, target);
|
|
15971
|
+
if (!inside || inside.startsWith("..") || isAbsolute4(inside))
|
|
15972
|
+
return;
|
|
15973
|
+
const handle = await open3(target, "r");
|
|
15974
|
+
try {
|
|
15975
|
+
const buffer = Buffer.alloc(maxBytes + 1);
|
|
15976
|
+
const { bytesRead } = await handle.read(buffer, 0, maxBytes + 1, 0);
|
|
15977
|
+
const truncated = bytesRead > maxBytes;
|
|
15978
|
+
const text = new TextDecoder().decode(buffer.subarray(0, Math.min(bytesRead, maxBytes))).replace(/�$/, "");
|
|
15979
|
+
return text.trim() ? repositoryInstructionsBlock(path, text, truncated) : undefined;
|
|
15980
|
+
} finally {
|
|
15981
|
+
await handle.close();
|
|
15982
|
+
}
|
|
15983
|
+
} catch {
|
|
15984
|
+
return;
|
|
15985
|
+
}
|
|
15986
|
+
}
|
|
15987
|
+
|
|
15587
15988
|
// ../protocol/src/claude-background-commands.ts
|
|
15588
15989
|
var CLAUDE_BASH_MAX_TIMEOUT_ENV = "BASH_MAX_TIMEOUT_MS";
|
|
15589
15990
|
var CLAUDE_BASH_DEFAULT_TIMEOUT_ENV = "BASH_DEFAULT_TIMEOUT_MS";
|
|
@@ -15632,6 +16033,17 @@ function backgroundCommandInstruction(env) {
|
|
|
15632
16033
|
return `Background shell commands in this session are stopped when they reach their timeout (${defaultText} by default, ${maxText} at most). Pass a longer \`timeout\` when a background command needs more than ${defaultText}. For a dev server or watcher that must keep running longer than ${maxText}, tell the user to start it in an Orkestrator terminal tab instead of running it yourself.`;
|
|
15633
16034
|
}
|
|
15634
16035
|
|
|
16036
|
+
// ../../bridges/claude-bridge/src/services/system-prompt-append.ts
|
|
16037
|
+
var READ_BEFORE_EDIT_INSTRUCTION = "IMPORTANT: You MUST read a file before editing or writing to it. The Edit and Write tools will fail if you have not first used the Read tool to read the file in this conversation. Always read files before attempting to modify them.";
|
|
16038
|
+
var CLAUDE_DOCS_INSTRUCTION = "Write a requested document as that Markdown file rather than as a Claude Doc or claude.ai artifact: Orkestrator cannot open those, so the user would never see it.";
|
|
16039
|
+
function claudeSystemPromptAppend(env) {
|
|
16040
|
+
return agentSystemInstructions([
|
|
16041
|
+
CLAUDE_DOCS_INSTRUCTION,
|
|
16042
|
+
READ_BEFORE_EDIT_INSTRUCTION,
|
|
16043
|
+
backgroundCommandInstruction(env)
|
|
16044
|
+
]);
|
|
16045
|
+
}
|
|
16046
|
+
|
|
15635
16047
|
// ../protocol/src/agent-interaction-deadline.ts
|
|
15636
16048
|
var SYSTEM_CLOCK = {
|
|
15637
16049
|
now: () => Date.now(),
|
|
@@ -15777,7 +16189,7 @@ function canAdmitInteraction(candidate, family) {
|
|
|
15777
16189
|
// ../../bridges/claude-bridge/src/services/session-manager-interactions.ts
|
|
15778
16190
|
import { readFile as readFile7 } from "node:fs/promises";
|
|
15779
16191
|
|
|
15780
|
-
//
|
|
16192
|
+
// ../protocol/src/mcp-elicitation-form.ts
|
|
15781
16193
|
function record2(value) {
|
|
15782
16194
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
15783
16195
|
}
|
|
@@ -15802,7 +16214,7 @@ var FIELD_KEYS = new Set([
|
|
|
15802
16214
|
"minimum",
|
|
15803
16215
|
"maximum"
|
|
15804
16216
|
]);
|
|
15805
|
-
function
|
|
16217
|
+
function isSupportedMcpForm(schema) {
|
|
15806
16218
|
if (!record2(schema) || schema.type !== "object" || Object.keys(schema).some((key) => !ROOT_KEYS.has(key)))
|
|
15807
16219
|
return false;
|
|
15808
16220
|
if (schema.additionalProperties !== undefined && schema.additionalProperties !== false)
|
|
@@ -15832,8 +16244,8 @@ function isSupportedClaudeForm(schema) {
|
|
|
15832
16244
|
return true;
|
|
15833
16245
|
});
|
|
15834
16246
|
}
|
|
15835
|
-
function
|
|
15836
|
-
if (!
|
|
16247
|
+
function isValidMcpFormContent(schema, content) {
|
|
16248
|
+
if (!isSupportedMcpForm(schema) || !record2(content))
|
|
15837
16249
|
return false;
|
|
15838
16250
|
const properties = schema.properties ?? {};
|
|
15839
16251
|
if (schema.required?.some((key) => !Object.hasOwn(content, key)))
|
|
@@ -15954,7 +16366,7 @@ function respondToInteraction(requestId, response, sessionId) {
|
|
|
15954
16366
|
const resolve = interactionResolvers.get(key);
|
|
15955
16367
|
if (!resolve)
|
|
15956
16368
|
return false;
|
|
15957
|
-
if (response.action === "accept" && request.kind === "mcp-form" && !
|
|
16369
|
+
if (response.action === "accept" && request.kind === "mcp-form" && !isValidMcpFormContent(request.schema, response.content))
|
|
15958
16370
|
return false;
|
|
15959
16371
|
pendingInteractions.delete(key);
|
|
15960
16372
|
interactionResolvers.delete(key);
|
|
@@ -15974,61 +16386,6 @@ function getSessionInitData(sessionId) {
|
|
|
15974
16386
|
const session = sessions.get(sessionId);
|
|
15975
16387
|
return session?.initData;
|
|
15976
16388
|
}
|
|
15977
|
-
function catalogModels(models) {
|
|
15978
|
-
return models.map((model) => ({
|
|
15979
|
-
id: model.value,
|
|
15980
|
-
resolvedModel: model.resolvedModel,
|
|
15981
|
-
name: model.displayName,
|
|
15982
|
-
description: model.description,
|
|
15983
|
-
supportsFastMode: model.supportsFastMode,
|
|
15984
|
-
supportsEffort: model.supportsEffort,
|
|
15985
|
-
supportedEffortLevels: model.supportedEffortLevels,
|
|
15986
|
-
supportsAdaptiveThinking: model.supportsAdaptiveThinking,
|
|
15987
|
-
supportsAutoMode: model.supportsAutoMode
|
|
15988
|
-
}));
|
|
15989
|
-
}
|
|
15990
|
-
function liveModels() {
|
|
15991
|
-
return readFromLiveClaude((control) => liveInitializationResult(control)?.then((result) => Array.isArray(result?.models) && result.models.length > 0 ? result.models : undefined));
|
|
15992
|
-
}
|
|
15993
|
-
async function getAvailableModelCatalog() {
|
|
15994
|
-
const live = await liveModels();
|
|
15995
|
-
if (live) {
|
|
15996
|
-
debugLog("[session-manager] Supported models read from a running CLI", {
|
|
15997
|
-
count: live.length
|
|
15998
|
-
});
|
|
15999
|
-
return { source: "sdk", models: catalogModels(live) };
|
|
16000
|
-
}
|
|
16001
|
-
let q;
|
|
16002
|
-
try {
|
|
16003
|
-
const cwd = process.env.CWD || process.cwd();
|
|
16004
|
-
debugLog("[session-manager] Fetching supported models", { cwd });
|
|
16005
|
-
q = controlOnlyQuery({
|
|
16006
|
-
cwd,
|
|
16007
|
-
env: { ...process.env },
|
|
16008
|
-
...claudeExecutableOptions()
|
|
16009
|
-
});
|
|
16010
|
-
const models = await q.supportedModels();
|
|
16011
|
-
debugLog("[session-manager] Supported models fetched", { count: models.length });
|
|
16012
|
-
return { source: "sdk", models: catalogModels(models) };
|
|
16013
|
-
} catch (error) {
|
|
16014
|
-
console.error("[session-manager] Error fetching supported models:", error);
|
|
16015
|
-
return {
|
|
16016
|
-
source: "fallback",
|
|
16017
|
-
models: CLAUDE_FALLBACK_MODEL_CATALOG.map((model) => ({
|
|
16018
|
-
...model,
|
|
16019
|
-
...model.supportedEffortLevels ? { supportedEffortLevels: [...model.supportedEffortLevels] } : {}
|
|
16020
|
-
}))
|
|
16021
|
-
};
|
|
16022
|
-
} finally {
|
|
16023
|
-
if (q?.return) {
|
|
16024
|
-
try {
|
|
16025
|
-
await q.return();
|
|
16026
|
-
} catch (error) {
|
|
16027
|
-
debugLog("[session-manager] Failed to clean up model query:", error);
|
|
16028
|
-
}
|
|
16029
|
-
}
|
|
16030
|
-
}
|
|
16031
|
-
}
|
|
16032
16389
|
async function getClaudeRuntimeVersions() {
|
|
16033
16390
|
let sdkVersion;
|
|
16034
16391
|
let bundledCliVersion;
|
|
@@ -16182,7 +16539,7 @@ async function answerClaudeElicitation(session, sessionId, request, options) {
|
|
|
16182
16539
|
const url = request.mode === "url" ? bounded2(request.url) : undefined;
|
|
16183
16540
|
const schema = request.mode === "url" ? undefined : request.requestedSchema ?? { type: "object" };
|
|
16184
16541
|
const schemaText = schema === undefined ? "" : JSON.stringify(schema);
|
|
16185
|
-
if (request.mode === "url" && (!url || url !== request.url) || new TextEncoder().encode(schemaText).byteLength > AGENT_INTERACTION_LIMITS.maxTextLength || schema !== undefined && !
|
|
16542
|
+
if (request.mode === "url" && (!url || url !== request.url) || new TextEncoder().encode(schemaText).byteLength > AGENT_INTERACTION_LIMITS.maxTextLength || schema !== undefined && !isSupportedMcpForm(schema)) {
|
|
16186
16543
|
appendTranscriptNotice(session, sessionId, (event) => eventEmitter.emit(event), {
|
|
16187
16544
|
type: "status",
|
|
16188
16545
|
severity: "warning",
|
|
@@ -16230,9 +16587,9 @@ function proposedBashPrefix(suggestions) {
|
|
|
16230
16587
|
const { toolName, ruleContent } = rule;
|
|
16231
16588
|
if (toolName !== "Bash" || typeof ruleContent !== "string")
|
|
16232
16589
|
continue;
|
|
16233
|
-
const prefix = ruleContent.
|
|
16590
|
+
const prefix = ruleContent.replace(/(?::| )\*$/, "");
|
|
16234
16591
|
const words = prefix.trim().split(/\s+/);
|
|
16235
|
-
if (words.length === 0 || words.length > MAX_PROPOSED_PREFIX_TOKENS || words.some((word) => word.length === 0 || word.length > MAX_PROPOSED_PREFIX_TOKEN_LENGTH)) {
|
|
16592
|
+
if (words.length === 0 || words.length > MAX_PROPOSED_PREFIX_TOKENS || words.some((word) => word.length === 0 || word.length > MAX_PROPOSED_PREFIX_TOKEN_LENGTH || word.includes("*"))) {
|
|
16236
16593
|
continue;
|
|
16237
16594
|
}
|
|
16238
16595
|
return words;
|
|
@@ -16443,6 +16800,9 @@ function turnHook(turn, hook) {
|
|
|
16443
16800
|
}
|
|
16444
16801
|
|
|
16445
16802
|
// ../../bridges/claude-bridge/src/services/session-manager-prompt-query.ts
|
|
16803
|
+
function withNativeGoalClosed(disallowed) {
|
|
16804
|
+
return [...disallowed ?? [], "ProposeGoal"];
|
|
16805
|
+
}
|
|
16446
16806
|
var PLAN_MODE_INSTRUCTIONS = `The user has enabled planning mode. Use this phase to:
|
|
16447
16807
|
1. Thoroughly explore the codebase and its existing patterns.
|
|
16448
16808
|
2. Consider viable approaches and their trade-offs.
|
|
@@ -16463,15 +16823,22 @@ async function resolveQueryPlan(turn, sdkTextPrompt, testHooks) {
|
|
|
16463
16823
|
};
|
|
16464
16824
|
const settingSources = claudeTurnSettingSources(session, options);
|
|
16465
16825
|
session.commandDiscoveryInputs.includeLocalSettings = settingSources.includes("local");
|
|
16826
|
+
const repositoryInstructions = options?.readOnly || policy?.id === "coordinator-read-only" || settingSources.includes("project") ? undefined : await readRepositoryInstructions(cwd);
|
|
16466
16827
|
const readOnlyCommandSandbox = isCoordinatorReadOnlyPolicy(policy) ? claudeReadOnlyCommandSandbox() : undefined;
|
|
16467
16828
|
const [
|
|
16468
|
-
{
|
|
16829
|
+
{
|
|
16830
|
+
servers: mcpServers,
|
|
16831
|
+
names: mcpServerNames,
|
|
16832
|
+
layers: mcpServerLayers,
|
|
16833
|
+
revision: mcpConfigRevision
|
|
16834
|
+
},
|
|
16469
16835
|
{ plugins, coordinatorSkills }
|
|
16470
16836
|
] = await Promise.all([
|
|
16471
16837
|
getMcpRuntimeConfig(cwd, process.env, options?.agentMcp, mcpSourceScopeForPolicy(policy), userMcpServerFilter(policy)),
|
|
16472
16838
|
resolveClaudeTurnPlugins(cwd, policy, settingSources)
|
|
16473
16839
|
]);
|
|
16474
16840
|
turn.mcpServerNames = mcpServerNames;
|
|
16841
|
+
const accountOnlyMcpServers = await claudeAccountOnlyMcpServerNames(cwd, settingSources, mcpServerNames, claudeUserMcpQueryOptions(policy).strictMcpConfig === true);
|
|
16475
16842
|
const mcpServerCount = Object.keys(mcpServers).length;
|
|
16476
16843
|
const pluginCount = plugins.length;
|
|
16477
16844
|
const policyPermissionMode = claudePolicyPermissionMode(policy);
|
|
@@ -16492,7 +16859,7 @@ async function resolveQueryPlan(turn, sdkTextPrompt, testHooks) {
|
|
|
16492
16859
|
];
|
|
16493
16860
|
const coordinatorReadOnly = isCoordinatorReadOnlyPolicy(policy);
|
|
16494
16861
|
const grantedMcpServerNames = claudeAsksForApproval(policy, options) ? [] : claudeGrantedMcpServerNames(policy, mcpServerNames);
|
|
16495
|
-
const agentMailTools = mcpServerNames.has(AGENT_MCP_SERVER_NAME) ? [...AGENT_MAIL_TOOL_NAMES, ...ARTIFACT_TOOL_NAMES].map((name) => `mcp__${AGENT_MCP_SERVER_NAME}__${name}`) : [];
|
|
16862
|
+
const agentMailTools = mcpServerNames.has(AGENT_MCP_SERVER_NAME) ? [...AGENT_MAIL_TOOL_NAMES, ...ARTIFACT_TOOL_NAMES, ...AGENT_GOAL_TOOL_NAMES].map((name) => `mcp__${AGENT_MCP_SERVER_NAME}__${name}`) : [];
|
|
16496
16863
|
const allowedTools = coordinatorReadOnly ? claudeReadOnlyAllowedTools({
|
|
16497
16864
|
agentMcpServerNames: mcpServerNames.has(AGENT_MCP_SERVER_NAME) ? [AGENT_MCP_SERVER_NAME] : [],
|
|
16498
16865
|
policy,
|
|
@@ -16506,7 +16873,7 @@ async function resolveQueryPlan(turn, sdkTextPrompt, testHooks) {
|
|
|
16506
16873
|
...claudeArtifactServerTools(mcpServerNames),
|
|
16507
16874
|
...grantedMcpServerNames.map((name) => `${claudeMcpToolPrefix(name)}*`)
|
|
16508
16875
|
];
|
|
16509
|
-
const disallowedTools = coordinatorReadOnly ? claudeDeniedTools(policy) : claudeDisallowedTools(policy);
|
|
16876
|
+
const disallowedTools = withNativeGoalClosed(coordinatorReadOnly ? claudeDeniedTools(policy) : claudeDisallowedTools(policy));
|
|
16510
16877
|
const fastMode = options?.fastMode === true;
|
|
16511
16878
|
const ultracode = requestsUltracode(options?.parameterValues);
|
|
16512
16879
|
session.ultracode = ultracode;
|
|
@@ -16528,7 +16895,7 @@ async function resolveQueryPlan(turn, sdkTextPrompt, testHooks) {
|
|
|
16528
16895
|
const envPath = process.env.PATH;
|
|
16529
16896
|
debugLog("[session-manager] SDK env PATH", { path: envPath });
|
|
16530
16897
|
const sdkPrompt = await buildSdkPrompt(sdkTextPrompt, options?.attachments, cwd, testHooks?.afterAttachmentSymlinkValidation, testHooks?.afterAttachmentCanonicalValidation, testHooks?.afterAttachmentInitialValidation);
|
|
16531
|
-
const queryEnvironment = await runtimeEnvironmentForSessionQuery(policy);
|
|
16898
|
+
const queryEnvironment = withUnattendedOverloadRetry(session.executionPolicy, await runtimeEnvironmentForSessionQuery(policy));
|
|
16532
16899
|
const liveSettings = claudeLiveSettings({
|
|
16533
16900
|
model: options?.model,
|
|
16534
16901
|
permissionMode,
|
|
@@ -16539,11 +16906,14 @@ async function resolveQueryPlan(turn, sdkTextPrompt, testHooks) {
|
|
|
16539
16906
|
const mcpServersKey = createHash11("sha256").update(JSON.stringify(mcpServers)).digest("hex");
|
|
16540
16907
|
return {
|
|
16541
16908
|
settingSources,
|
|
16909
|
+
repositoryInstructions,
|
|
16542
16910
|
cwd,
|
|
16543
16911
|
policy,
|
|
16544
16912
|
effortLevel,
|
|
16545
16913
|
mcpServers,
|
|
16546
16914
|
mcpServerNames,
|
|
16915
|
+
mcpServerLayers,
|
|
16916
|
+
accountOnlyMcpServers,
|
|
16547
16917
|
mcpConfigRevision,
|
|
16548
16918
|
plugins,
|
|
16549
16919
|
mcpServerCount,
|
|
@@ -16564,6 +16934,7 @@ async function resolveQueryPlan(turn, sdkTextPrompt, testHooks) {
|
|
|
16564
16934
|
}
|
|
16565
16935
|
function recordMcpConfigRevision(session, plan, mcp) {
|
|
16566
16936
|
const { mcpConfigRevision } = plan;
|
|
16937
|
+
session.mcpServerLayers = plan.mcpServerLayers;
|
|
16567
16938
|
if (!mcpConfigRevision)
|
|
16568
16939
|
return;
|
|
16569
16940
|
const staleServers = reportedStaleServers(mcp);
|
|
@@ -16646,11 +17017,9 @@ function claudeQueryOptions(turn, plan, turnFor, mcp) {
|
|
|
16646
17017
|
systemPrompt: {
|
|
16647
17018
|
type: "preset",
|
|
16648
17019
|
preset: "claude_code",
|
|
16649
|
-
append:
|
|
16650
|
-
"
|
|
16651
|
-
|
|
16652
|
-
"When the user asks for a document (a report, design doc, plan, analysis, guide, or other writing to keep), prefer writing it as a Markdown file in a `docs/` folder at the root of the working directory over creating a Claude Doc or claude.ai artifact, and tell the user the file's path. Project instructions (such as CLAUDE.md or AGENTS.md), local skills, and the user's own request take priority over this default when they say where or how to write documents.",
|
|
16653
|
-
"When you show the user an image in your reply (a screenshot, rendered preview, or chart) using Markdown image syntax, reference it by its absolute path. In a managed worktree or container environment, save the file inside the working directory, preferably in a git-ignored folder so preview files stay out of the change set. Local image previews are limited to Orkestrator-managed workspace storage or the container's /workspace. Project-home checkouts are excluded from host preview reads, even when they are the working directory, so images saved there cannot be previewed from a local Markdown path. Paths outside previewable storage, such as /tmp, also show a placeholder."
|
|
17020
|
+
append: [
|
|
17021
|
+
coordinatorReadOnly ? "You are a read-only coordinator. Inspect the checkout with reading tools and use the trusted research tools available for this turn. Delegate all mutations and artifact creation to worker environments through Orkestrator tools. Present findings directly in your response." : claudeSystemPromptAppend(queryEnvironment),
|
|
17022
|
+
...plan.repositoryInstructions ? [plan.repositoryInstructions] : []
|
|
16654
17023
|
].join(`
|
|
16655
17024
|
|
|
16656
17025
|
`)
|
|
@@ -16985,7 +17354,7 @@ async function handleInitMessage(turn, message) {
|
|
|
16985
17354
|
}
|
|
16986
17355
|
const allMcpServers = initMsg.mcp_servers || [];
|
|
16987
17356
|
const regularMcpServers = allMcpServers.filter((s) => !s.name?.startsWith("plugin:"));
|
|
16988
|
-
const mcpServerStatuses = regularMcpServers.map(initMcpServerStatus);
|
|
17357
|
+
const mcpServerStatuses = regularMcpServers.map((server) => initMcpServerStatus(server, session.mcpServerLayers));
|
|
16989
17358
|
const { statuses: pluginStatuses, errors: pluginErrors } = pluginStatusesFromInit(initMsg);
|
|
16990
17359
|
const previousPluginErrors = new Set(session.pluginErrorSignatures);
|
|
16991
17360
|
session.pluginErrorSignatures = pluginErrors.map(({ plugin, type, message, path, loaded }) => JSON.stringify([plugin, type, message, path, loaded]));
|
|
@@ -17172,6 +17541,28 @@ var LEAF_MESSAGE_HANDLERS = {
|
|
|
17172
17541
|
conversation_reset: handleConversationReset
|
|
17173
17542
|
};
|
|
17174
17543
|
|
|
17544
|
+
// ../protocol/src/agent-usage-limits.ts
|
|
17545
|
+
var USAGE_LIMIT_PATTERNS = [
|
|
17546
|
+
/usage[\s_-]?limit/i,
|
|
17547
|
+
/hit your (?:usage |session |weekly )?limit/i,
|
|
17548
|
+
/\b(?:5|five)[\s-]?hour limit\b/i,
|
|
17549
|
+
/\bweekly limit\b/i,
|
|
17550
|
+
/\b(?:usage|quota|credits?|allowance) (?:is |has been )?(?:exhausted|exceeded|used up)\b/i,
|
|
17551
|
+
/\bquota exceeded\b|\binsufficient_quota\b|\bout of (?:credits|usage)\b/i,
|
|
17552
|
+
/\bUSAGE_EXHAUSTED\b|\bPAYMENT_REQUIRED\b/,
|
|
17553
|
+
/\b(?:usage|plan|session|daily|weekly|monthly|go) limit reached\b/i
|
|
17554
|
+
];
|
|
17555
|
+
function classifyUsageLimitError(text) {
|
|
17556
|
+
if (typeof text !== "string" || !text.trim())
|
|
17557
|
+
return null;
|
|
17558
|
+
const bounded = text.slice(0, 2000);
|
|
17559
|
+
if (!USAGE_LIMIT_PATTERNS.some((pattern) => pattern.test(bounded)))
|
|
17560
|
+
return null;
|
|
17561
|
+
const reset = bounded.match(/\b(?:resets?|try again)(?:\s+(?:at|in|after))?\s+([^.\n·]{1,60})/i);
|
|
17562
|
+
const hint = reset?.[1]?.trim();
|
|
17563
|
+
return hint ? { resetHint: hint } : {};
|
|
17564
|
+
}
|
|
17565
|
+
|
|
17175
17566
|
// ../../bridges/claude-bridge/src/services/session-manager-prompt-handlers/result.ts
|
|
17176
17567
|
function claudeStartupFailureMessage(reason) {
|
|
17177
17568
|
switch (reason) {
|
|
@@ -17213,8 +17604,11 @@ function claudeStartupFailureMessage(reason) {
|
|
|
17213
17604
|
return "Claude could not load the policy limits and managed settings your organization requires. Check connectivity and any proxy, then retry.";
|
|
17214
17605
|
case "org_config_refused":
|
|
17215
17606
|
return "Anthropic refused your organization's required Claude settings for this sign-in. Sign in to Claude again; if that does not help, ask an administrator to allow Claude Code for this account.";
|
|
17607
|
+
case "sandbox_required_unavailable":
|
|
17608
|
+
return "Claude requires a working command sandbox, and it cannot run here (for example, bubblewrap is missing or the platform is unsupported). Make the sandbox available or have the requirement changed, then retry.";
|
|
17216
17609
|
}
|
|
17217
17610
|
}
|
|
17611
|
+
var MAX_USAGE_LIMIT_ERROR_CHARS = 500;
|
|
17218
17612
|
var STOPPED_TERMINAL_REASONS = new Set([
|
|
17219
17613
|
"aborted_streaming",
|
|
17220
17614
|
"aborted_tools"
|
|
@@ -17347,8 +17741,9 @@ async function handleResultMessage(turn, message) {
|
|
|
17347
17741
|
isError: resultIsError
|
|
17348
17742
|
});
|
|
17349
17743
|
const startupFailure = resultMsg.startup_failure_reason ? claudeStartupFailureMessage(resultMsg.startup_failure_reason) : undefined;
|
|
17744
|
+
const usageLimit = resultMsg.subtype === "success" && classifyUsageLimitError(resultMsg.result) ? resultMsg.result.trim().slice(0, MAX_USAGE_LIMIT_ERROR_CHARS) : undefined;
|
|
17350
17745
|
const resultError = startupFailure || resultMsg.errors?.filter(Boolean).join(`
|
|
17351
|
-
`) || (resultMsg.subtype === "success" ? "Claude ended the turn on an API error." : `Claude query failed: ${resultMsg.subtype}`);
|
|
17746
|
+
`) || usageLimit || (resultMsg.subtype === "success" ? "Claude ended the turn on an API error." : `Claude query failed: ${resultMsg.subtype}`);
|
|
17352
17747
|
if (startupFailure) {
|
|
17353
17748
|
appendTranscriptNotice(session, sessionId, (event) => eventEmitter.emit(event), {
|
|
17354
17749
|
type: "status",
|
|
@@ -18280,7 +18675,8 @@ async function prepareJoin(turn, plan, running) {
|
|
|
18280
18675
|
const required = mcpServers[AGENT_MCP_SERVER_NAME] ? [AGENT_MCP_SERVER_NAME, ...options?.agentMcp?.design ? ["orkestrator-design"] : []] : [];
|
|
18281
18676
|
await assertClaudeRuntimeAccepts(session, options, {
|
|
18282
18677
|
...claudeLaunchResourceProfile(plugins, queryEnvironment),
|
|
18283
|
-
settingSources: JSON.stringify(plan.settingSources)
|
|
18678
|
+
settingSources: JSON.stringify(plan.settingSources),
|
|
18679
|
+
repositoryInstructions: plan.repositoryInstructions ?? ""
|
|
18284
18680
|
}, plan.readOnlyCommandSandbox);
|
|
18285
18681
|
session.queryControl = running.control;
|
|
18286
18682
|
turn.queryIteratorControl = running.control;
|
|
@@ -18321,7 +18717,7 @@ function launchClaudeRuntime(turn, plan) {
|
|
|
18321
18717
|
const { session, options, abortController, stream } = turn;
|
|
18322
18718
|
const { plugins, sdkPrompt, queryEnvironment, mcpServers, mcpServerNames, mcpServersKey } = plan;
|
|
18323
18719
|
const heldSdkPrompt = holdSdkPromptOpen(sdkPrompt, abortController.signal, turn.promptUuid);
|
|
18324
|
-
const mcp = createClaudeRuntimeMcp(mcpServers, mcpServerNames);
|
|
18720
|
+
const mcp = createClaudeRuntimeMcp(mcpServers, mcpServerNames, plan.accountOnlyMcpServers);
|
|
18325
18721
|
const turnFor = (toolUseId) => (toolUseId ? turn.runtime?.toolOwners.get(toolUseId) : undefined) ?? turn.runtime?.latestTurn ?? turn.thisTurn;
|
|
18326
18722
|
const queryIterator = query2({
|
|
18327
18723
|
prompt: heldSdkPrompt.prompt,
|
|
@@ -18340,6 +18736,7 @@ function launchClaudeRuntime(turn, plan) {
|
|
|
18340
18736
|
launch: {
|
|
18341
18737
|
...claudeLaunchedProfile(session, options, plan.readOnlyCommandSandbox),
|
|
18342
18738
|
settingSources: JSON.stringify(plan.settingSources),
|
|
18739
|
+
repositoryInstructions: plan.repositoryInstructions ?? "",
|
|
18343
18740
|
...claudeLaunchResourceProfile(plugins, queryEnvironment)
|
|
18344
18741
|
},
|
|
18345
18742
|
mcpServers: mcpServersKey,
|
|
@@ -18396,6 +18793,7 @@ function joinableRuntime(turn, plan) {
|
|
|
18396
18793
|
const requested = {
|
|
18397
18794
|
...claudeLaunchProfile(turn.session, turn.options, plan.readOnlyCommandSandbox),
|
|
18398
18795
|
settingSources: JSON.stringify(plan.settingSources),
|
|
18796
|
+
repositoryInstructions: plan.repositoryInstructions ?? "",
|
|
18399
18797
|
...claudeLaunchResourceProfile(plan.plugins, plan.queryEnvironment)
|
|
18400
18798
|
};
|
|
18401
18799
|
return claudeLaunchConflict(running.launch, requested) ? undefined : running;
|
|
@@ -18790,6 +19188,8 @@ async function settlesBy(work, deadline) {
|
|
|
18790
19188
|
// ../../bridges/claude-bridge/src/routes/config.ts
|
|
18791
19189
|
var config = new Hono2;
|
|
18792
19190
|
config.get("/models", async (c) => {
|
|
19191
|
+
if (c.req.query("forceRefresh") === "true")
|
|
19192
|
+
invalidateClaudeModelCatalog();
|
|
18793
19193
|
const startedAt = Date.now();
|
|
18794
19194
|
console.log("[config] /models requested");
|
|
18795
19195
|
const [{ models, source }, versions] = await Promise.all([
|
|
@@ -19093,7 +19493,7 @@ function parseSessionActivityObservation(value) {
|
|
|
19093
19493
|
if (!isRecord4(value))
|
|
19094
19494
|
return;
|
|
19095
19495
|
const { activity, readyForInput, completionPending, asyncQuestionItemIds, closing } = value;
|
|
19096
|
-
const { contentRevision } = value;
|
|
19496
|
+
const { contentRevision, turnFailed } = value;
|
|
19097
19497
|
if (typeof activity !== "string" || !SESSION_ACTIVITY_STATES.has(activity))
|
|
19098
19498
|
return;
|
|
19099
19499
|
if (readyForInput !== undefined && typeof readyForInput !== "boolean")
|
|
@@ -19102,6 +19502,8 @@ function parseSessionActivityObservation(value) {
|
|
|
19102
19502
|
return;
|
|
19103
19503
|
if (closing !== undefined && typeof closing !== "boolean")
|
|
19104
19504
|
return;
|
|
19505
|
+
if (turnFailed !== undefined && typeof turnFailed !== "boolean")
|
|
19506
|
+
return;
|
|
19105
19507
|
if (contentRevision !== undefined && !isContentRevision(contentRevision))
|
|
19106
19508
|
return;
|
|
19107
19509
|
let itemIds;
|
|
@@ -19117,6 +19519,7 @@ function parseSessionActivityObservation(value) {
|
|
|
19117
19519
|
...completionPending !== undefined ? { completionPending } : {},
|
|
19118
19520
|
...itemIds !== undefined ? { asyncQuestionItemIds: itemIds } : {},
|
|
19119
19521
|
...closing !== undefined ? { closing } : {},
|
|
19522
|
+
...turnFailed === true ? { turnFailed } : {},
|
|
19120
19523
|
...contentRevision !== undefined ? { contentRevision } : {}
|
|
19121
19524
|
};
|
|
19122
19525
|
}
|
|
@@ -19248,6 +19651,7 @@ async function readSessionActivityObservation(sessionId) {
|
|
|
19248
19651
|
return {
|
|
19249
19652
|
activity: activity === "idle" && completionPending ? "working" : activity,
|
|
19250
19653
|
...resident?.status === "idle" ? { readyForInput: true, completionPending } : {},
|
|
19654
|
+
...resident?.status === "error" ? { turnFailed: true } : {},
|
|
19251
19655
|
...activity === "missing" ? {} : contentRevisionField(resident)
|
|
19252
19656
|
};
|
|
19253
19657
|
}
|
|
@@ -20725,7 +21129,7 @@ session.post("/:id/interactions/:interactionId", interactionBodyLimit, async (c)
|
|
|
20725
21129
|
} else if (action === "accept" && pending.kind === "mcp-form") {
|
|
20726
21130
|
return c.json({ error: "An MCP form answer requires 'content'" }, 400);
|
|
20727
21131
|
}
|
|
20728
|
-
if (action === "accept" && pending.kind === "mcp-form" && !
|
|
21132
|
+
if (action === "accept" && pending.kind === "mcp-form" && !isValidMcpFormContent(pending.schema, content)) {
|
|
20729
21133
|
return c.json({ error: "The answer does not match the MCP form schema" }, 400);
|
|
20730
21134
|
}
|
|
20731
21135
|
const response = action === "accept" ? content ? { action, content } : { action } : { action };
|