@sideboard-ai/core 0.1.262 → 0.1.263

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.
Files changed (55) hide show
  1. package/dist/{abletime-OQ4PC52L.js → abletime-6AOJI2YZ.js} +4 -4
  2. package/dist/{abletime-CDGINDXG.js → abletime-U75ZGDIX.js} +5 -5
  3. package/dist/{abletime-oauth-KX2TDFTE.js → abletime-oauth-LOAHGG4X.js} +3 -3
  4. package/dist/{abletime-oauth-5A5EOH2A.js → abletime-oauth-TA2YDCYX.js} +4 -4
  5. package/dist/{abletime-rest-UEHOBLXD.js → abletime-rest-CTA5WV26.js} +4 -4
  6. package/dist/{abletime-rest-PUGKYTRR.js → abletime-rest-YZPFM6IY.js} +3 -3
  7. package/dist/agents/claude-runner.cjs +463 -0
  8. package/dist/agents/claude-runner.d.cts +1 -0
  9. package/dist/agents/claude-runner.d.ts +1 -0
  10. package/dist/agents/claude-runner.js +134 -0
  11. package/dist/agents/cursor-runner.cjs +388 -7
  12. package/dist/agents/cursor-runner.js +34 -7
  13. package/dist/{agents-J2P4KNEY.js → agents-3TUMFSMH.js} +10 -9
  14. package/dist/{agents-IKVUGW5H.js → agents-6FWDRVA2.js} +4 -4
  15. package/dist/{app-settings-OM7H64YM.js → app-settings-MVZPM6WW.js} +1 -1
  16. package/dist/{app-settings-VQEUCONM.js → app-settings-RKFFUIFQ.js} +2 -2
  17. package/dist/{chunk-6PFZ6XO7.js → chunk-2QUQH2SZ.js} +81 -6
  18. package/dist/{chunk-VIC6TDYT.js → chunk-36FOBJBF.js} +76 -3
  19. package/dist/{chunk-ABPNIYRS.js → chunk-3H7O27X2.js} +389 -102
  20. package/dist/{chunk-FSZ7YYFQ.js → chunk-4ALDX5IO.js} +5 -3
  21. package/dist/{chunk-5OKJDCBK.js → chunk-5PK53SAP.js} +5 -5
  22. package/dist/{chunk-U3AOJLH3.js → chunk-5ZPT5YAV.js} +8 -6
  23. package/dist/{chunk-YFTO7U2A.js → chunk-6YOXQVJ7.js} +3 -3
  24. package/dist/{chunk-J6ONZP74.js → chunk-6YY7XPPL.js} +5 -5
  25. package/dist/{chunk-WV7KJH2E.js → chunk-A5SAYFJ4.js} +1 -0
  26. package/dist/{chunk-B6XFBNYM.js → chunk-BOMSJUXW.js} +2 -2
  27. package/dist/{chunk-S7VDDJ34.js → chunk-CEOTK5GZ.js} +3 -3
  28. package/dist/{chunk-4F7J6UWD.js → chunk-EK3KVT7I.js} +515 -139
  29. package/dist/{chunk-HHEKVR6C.js → chunk-F5MFNUAA.js} +40 -2
  30. package/dist/{chunk-KVQX62XI.js → chunk-K7B25HO4.js} +3 -3
  31. package/dist/{chunk-JTNY5CK4.js → chunk-L5WGAIL2.js} +46 -46
  32. package/dist/chunk-NYBFYFK7.js +415 -0
  33. package/dist/{chunk-GIZQAOHZ.js → chunk-QX6QUZVD.js} +121 -91
  34. package/dist/{chunk-X2OTZ36G.js → chunk-RKPBIB2U.js} +52 -52
  35. package/dist/{chunk-W5PWGEKS.js → chunk-T3AYRQJZ.js} +107 -77
  36. package/dist/{chunk-D554YCHG.js → chunk-YKYEHDMX.js} +2 -2
  37. package/dist/connected-teams-RU6VATCM.js +1 -1
  38. package/dist/{coordinator-prompt-VQHQ3RIX.js → coordinator-prompt-HZCQZ6C5.js} +6 -6
  39. package/dist/{coordinator-prompt-TU6656OK.js → coordinator-prompt-J7DKHOCH.js} +3 -3
  40. package/dist/{global-workspace-PHF2MOGW.js → global-workspace-6LDUZ2NF.js} +3 -3
  41. package/dist/{global-workspace-47NZVA44.js → global-workspace-TI26K25J.js} +6 -6
  42. package/dist/index.cjs +1712 -721
  43. package/dist/index.d.cts +181 -41
  44. package/dist/index.d.ts +181 -41
  45. package/dist/index.js +693 -285
  46. package/dist/mcp/run-stdio.cjs +10469 -9896
  47. package/dist/mcp/run-stdio.js +193 -168
  48. package/dist/{orchestrator-VLTO5JBR.js → orchestrator-4JSG7BWC.js} +5 -5
  49. package/dist/{orchestrator-OCG4QVA5.js → orchestrator-5YU46YNS.js} +11 -10
  50. package/dist/{workspaces-I7TWFTJM.js → workspaces-QJ3XIPUJ.js} +6 -6
  51. package/dist/{workspaces-2XTDS7N2.js → workspaces-WOQHJFRQ.js} +3 -3
  52. package/dist/{worktree-DDDF3WHV.js → worktree-6U2FA5LO.js} +2 -2
  53. package/dist/{worktree-YASFE65H.js → worktree-KQA4ON2G.js} +5 -5
  54. package/package.json +4 -3
  55. /package/dist/{chunk-LDXSAVWO.js → chunk-GWFVCCJZ.js} +0 -0
@@ -2,13 +2,13 @@
2
2
 
3
3
  import {
4
4
  isOrchestratorThread
5
- } from "./chunk-JTNY5CK4.js";
5
+ } from "./chunk-L5WGAIL2.js";
6
6
  import {
7
7
  codexUnattendedGitConfigArgs,
8
8
  mergeAgentGitAuthEnv,
9
9
  resolveAgentGitAuthEnv,
10
10
  resolveCodexGitWritableRoots
11
- } from "./chunk-FSZ7YYFQ.js";
11
+ } from "./chunk-4ALDX5IO.js";
12
12
  import {
13
13
  applyConnectedTeamToCli,
14
14
  brightsyMcpServerName,
@@ -37,7 +37,7 @@ import {
37
37
  loadAppSettings,
38
38
  resolveAgentExecutable,
39
39
  resolveClaudeExecutable
40
- } from "./chunk-VIC6TDYT.js";
40
+ } from "./chunk-36FOBJBF.js";
41
41
  import {
42
42
  isElectronLikeCommand,
43
43
  unwrapStrippedElectronLaunch,
@@ -803,7 +803,7 @@ var brightsyAdapter = {
803
803
  };
804
804
 
805
805
  // src/agents/claude.ts
806
- import { existsSync as existsSync8 } from "fs";
806
+ import { existsSync as existsSync10 } from "fs";
807
807
 
808
808
  // src/agents/claude-mcp.ts
809
809
  function sanitizeMcpServerName(name) {
@@ -825,6 +825,29 @@ function mcpAllowToolsFromNames(names) {
825
825
  [...names].map((name) => name.trim()).filter(Boolean).map((name) => ({ name, connected: true, needsAuth: false }))
826
826
  );
827
827
  }
828
+ var BASE_ALLOWED_TOOLS = [
829
+ "Edit",
830
+ "Write",
831
+ "Bash",
832
+ "Read",
833
+ "Glob",
834
+ "Grep",
835
+ "WebFetch",
836
+ "WebSearch",
837
+ "Task",
838
+ "Agent",
839
+ "TaskOutput",
840
+ "TaskStop",
841
+ "EnterWorktree",
842
+ "ExitWorktree",
843
+ "Skill"
844
+ ];
845
+ var CLAUDE_PRINT_BG_WAIT_CEILING_MS = 72e5;
846
+ var CLAUDE_CHROME_ALLOWED_TOOLS = [
847
+ "mcp__claude-in-chrome",
848
+ "mcp__claude-in-chrome__*",
849
+ "Skill(claude-in-chrome)"
850
+ ];
828
851
 
829
852
  // src/agents/orch-mcp-isolation.ts
830
853
  import { existsSync as existsSync7, readFileSync as readFileSync3 } from "fs";
@@ -844,9 +867,67 @@ import { tmpdir } from "os";
844
867
  import { dirname as dirname2, join as join4 } from "path";
845
868
  import { fileURLToPath } from "url";
846
869
 
870
+ // src/agent-rpc/protocol.ts
871
+ var AGENT_RPC_PROTOCOL_VERSION = 1;
872
+ var AGENT_RPC_TOKEN_QUERY = "authToken";
873
+ var AGENT_RPC_NATIVE_ENV = "SIDEBOARD_AGENT_RPC_NATIVE";
874
+ var AGENT_RPC_URL_ENV = "SIDEBOARD_AGENT_RPC_URL";
875
+ var AGENT_RPC_TOKEN_ENV = "SIDEBOARD_AGENT_RPC_TOKEN";
876
+ var AGENT_RPC_CWD_ENV = "SIDEBOARD_AGENT_RPC_CWD";
877
+ var AGENT_RPC_CLAUDE_SDK_SERVER = "sideboard_rpc";
878
+
847
879
  // src/mcp/profile.ts
848
880
  var SIDEBOARD_MCP_PROFILE_ENV = "SIDEBOARD_MCP_PROFILE";
849
881
  var SIDEBOARD_THREAD_ID_ENV = "SIDEBOARD_THREAD_ID";
882
+ function agentRpcOwnsPilotTools(env = process.env) {
883
+ return env[AGENT_RPC_NATIVE_ENV]?.trim() === "1";
884
+ }
885
+ function injectedSideboardMcpEnv(opts) {
886
+ const orchId = opts.orchestratorThreadId?.trim();
887
+ const threadId = opts.threadId?.trim() || orchId;
888
+ const env = {
889
+ SIDEBOARD_APP_DATA: appDataDir(),
890
+ [SIDEBOARD_MCP_PROFILE_ENV]: orchId ? "orchestration" : "worktree"
891
+ };
892
+ if (orchId) env.SIDEBOARD_ORCHESTRATOR_THREAD_ID = orchId;
893
+ if (threadId) env[SIDEBOARD_THREAD_ID_ENV] = threadId;
894
+ if (opts.rpcNativeTools) env[AGENT_RPC_NATIVE_ENV] = "1";
895
+ return env;
896
+ }
897
+ var AGENT_RPC_PILOT_MCP_TOOLS = [
898
+ "present_artifact",
899
+ "wait_for_job",
900
+ "stop_job"
901
+ ];
902
+ function shouldRegisterMcpWaitForTurn(env = process.env) {
903
+ return !agentRpcOwnsPilotTools(env);
904
+ }
905
+ function worktreeMcpToolNames(env = process.env) {
906
+ if (!agentRpcOwnsPilotTools(env)) return WORKTREE_MCP_TOOLS;
907
+ const omit = new Set(AGENT_RPC_PILOT_MCP_TOOLS);
908
+ return WORKTREE_MCP_TOOLS.filter((name) => !omit.has(name));
909
+ }
910
+ var WORKTREE_MCP_TOOLS = [
911
+ "present_artifact",
912
+ "ask_user",
913
+ "present_plan",
914
+ "present_schema",
915
+ "present_files",
916
+ "wait_for_job",
917
+ "stop_job",
918
+ "list_run_scripts",
919
+ "run_dev_script",
920
+ "stop_dev_script",
921
+ "get_run_log",
922
+ "notify_orchestrator",
923
+ "get_viewer_context",
924
+ "update_viewer_context",
925
+ "list_schedules",
926
+ "create_schedule",
927
+ "update_schedule",
928
+ "delete_schedule",
929
+ "run_schedule"
930
+ ];
850
931
  function sideboardMcpProfile(env = process.env) {
851
932
  return env[SIDEBOARD_MCP_PROFILE_ENV]?.trim().toLowerCase() === "worktree" ? "worktree" : "orchestration";
852
933
  }
@@ -1408,20 +1489,10 @@ async function buildInjectedMcpServers(opts) {
1408
1489
  const servers = [];
1409
1490
  if (opts.includeSideboard) {
1410
1491
  const sideboard = await resolveSideboardMcpServer();
1411
- const orchId = opts.orchestratorThreadId?.trim();
1412
- const profile = orchId ? "orchestration" : "worktree";
1413
- const threadId = opts.threadId?.trim() || orchId;
1414
1492
  sideboard.env = {
1415
1493
  ...sideboard.env ?? {},
1416
- SIDEBOARD_APP_DATA: appDataDir(),
1417
- [SIDEBOARD_MCP_PROFILE_ENV]: profile
1494
+ ...injectedSideboardMcpEnv(opts)
1418
1495
  };
1419
- if (orchId) {
1420
- sideboard.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID = orchId;
1421
- }
1422
- if (threadId) {
1423
- sideboard.env[SIDEBOARD_THREAD_ID_ENV] = threadId;
1424
- }
1425
1496
  try {
1426
1497
  mergeAgentGitAuthEnv(
1427
1498
  sideboard.env,
@@ -1526,7 +1597,7 @@ function stripElectronFromUserMcpEntry(entry) {
1526
1597
  next.env = cleaned;
1527
1598
  return next;
1528
1599
  }
1529
- function writeMcpServersConfig(servers, extraServers) {
1600
+ function mcpServersRecord(servers, extraServers) {
1530
1601
  const mcpServers = {};
1531
1602
  for (const s of servers) {
1532
1603
  const env = mcpSpawnEnv(s.env);
@@ -1543,6 +1614,10 @@ function writeMcpServersConfig(servers, extraServers) {
1543
1614
  mcpServers[name] = stripElectronFromUserMcpEntry(entry);
1544
1615
  }
1545
1616
  }
1617
+ return mcpServers;
1618
+ }
1619
+ function writeMcpServersConfig(servers, extraServers) {
1620
+ const mcpServers = mcpServersRecord(servers, extraServers);
1546
1621
  if (Object.keys(mcpServers).length === 0) return null;
1547
1622
  const dir = mkdtempSync(join4(tmpdir(), "sideboard-mcp-"));
1548
1623
  const cfgPath = join4(dir, "mcp.json");
@@ -2524,34 +2599,166 @@ function permissionMode(thread) {
2524
2599
  };
2525
2600
  }
2526
2601
 
2527
- // src/agents/claude.ts
2528
- var BASE_ALLOWED_TOOLS = [
2529
- "Edit",
2530
- "Write",
2531
- "Bash",
2532
- "Read",
2533
- "Glob",
2534
- "Grep",
2535
- "WebFetch",
2536
- "WebSearch",
2537
- // Subagents (Claude Code v2.1.63 renamed Task → Agent; allow both).
2538
- "Task",
2539
- "Agent",
2540
- "TaskOutput",
2541
- "TaskStop",
2542
- "EnterWorktree",
2543
- "ExitWorktree",
2544
- "Skill"
2602
+ // src/agent-rpc/metadata.ts
2603
+ import { existsSync as existsSync8, readFileSync as readFileSync4, unlinkSync, writeFileSync as writeFileSync4 } from "fs";
2604
+ import { join as join7 } from "path";
2605
+ function agentRuntimeMetadataPath() {
2606
+ return join7(appDataDir(), "agent-runtime.json");
2607
+ }
2608
+ function readAgentRuntimeMetadata() {
2609
+ try {
2610
+ const raw = JSON.parse(readFileSync4(agentRuntimeMetadataPath(), "utf8"));
2611
+ if (!raw || typeof raw !== "object") return null;
2612
+ const rec = raw;
2613
+ if (typeof rec.runtimeId !== "string" || !rec.runtimeId.trim()) return null;
2614
+ if (typeof rec.authToken !== "string" || !rec.authToken.trim()) return null;
2615
+ const pid = Number(rec.pid);
2616
+ if (!Number.isInteger(pid) || pid <= 0) return null;
2617
+ const transports = Array.isArray(rec.transports) ? rec.transports : [];
2618
+ const ws = transports.filter((t) => {
2619
+ if (!t || typeof t !== "object") return false;
2620
+ const row = t;
2621
+ return row.kind === "websocket" && typeof row.url === "string" && Boolean(row.url.trim());
2622
+ });
2623
+ return {
2624
+ runtimeId: rec.runtimeId.trim(),
2625
+ pid,
2626
+ protocolVersion: Number(rec.protocolVersion) || AGENT_RPC_PROTOCOL_VERSION,
2627
+ authToken: rec.authToken,
2628
+ startedAt: Number(rec.startedAt) || 0,
2629
+ transports: ws
2630
+ };
2631
+ } catch {
2632
+ return null;
2633
+ }
2634
+ }
2635
+ function websocketUrlFromMetadata(meta) {
2636
+ const url = meta?.transports.find((t) => t.kind === "websocket")?.url?.trim();
2637
+ return url || null;
2638
+ }
2639
+ function agentRpcConnectFromMetadata(meta = readAgentRuntimeMetadata()) {
2640
+ if (!agentRuntimeLooksLive(meta)) return null;
2641
+ const url = websocketUrlFromMetadata(meta);
2642
+ const authToken = meta?.authToken;
2643
+ if (!url || !authToken) return null;
2644
+ return { url, authToken };
2645
+ }
2646
+ function pidAlive(pid) {
2647
+ try {
2648
+ process.kill(pid, 0);
2649
+ return true;
2650
+ } catch {
2651
+ return false;
2652
+ }
2653
+ }
2654
+ function agentRuntimeLooksLive(meta = readAgentRuntimeMetadata()) {
2655
+ if (!meta) return false;
2656
+ return pidAlive(meta.pid);
2657
+ }
2658
+
2659
+ // src/agent-rpc/rpc-env.ts
2660
+ function worktreeAgentRpc(isOrchestrator) {
2661
+ return isOrchestrator ? null : agentRpcConnectFromMetadata();
2662
+ }
2663
+ function agentRpcChildEnv(rpc, cwd) {
2664
+ return {
2665
+ [AGENT_RPC_NATIVE_ENV]: "1",
2666
+ [AGENT_RPC_URL_ENV]: rpc.url,
2667
+ [AGENT_RPC_TOKEN_ENV]: rpc.authToken,
2668
+ [AGENT_RPC_CWD_ENV]: cwd
2669
+ };
2670
+ }
2671
+
2672
+ // src/agents/claude-host.ts
2673
+ import { existsSync as existsSync9 } from "fs";
2674
+ import { createRequire as createRequire2 } from "module";
2675
+ import { dirname as dirname4, join as join8 } from "path";
2676
+ import { fileURLToPath as fileURLToPath2 } from "url";
2677
+
2678
+ // src/agent-rpc/client.ts
2679
+ import { WebSocket } from "ws";
2680
+
2681
+ // src/agent-rpc/pilot-tools.ts
2682
+ var PILOT_TOOL_NAMES = [
2683
+ "present_artifact",
2684
+ "wait_for_job",
2685
+ "stop_job"
2545
2686
  ];
2546
- var CLAUDE_PRINT_BG_WAIT_CEILING_MS = 72e5;
2687
+ var PILOT_TOOL_DESCRIPTIONS = {
2688
+ present_artifact: "Show a document or live log in Sideboard\u2019s side column. For html/svg/markdown/react, pass the FULL document and do not also fence that same body in chat. For type=log, pass only NEW lines (same artifact_id appends). Prefer type=log for long-running job output \u2014 do not resend HTML. type=react is a single default-export component (JSX/TSX); only react/react-dom imports.",
2689
+ wait_for_job: "Wait until a detached long job (tests, pack, deploy, connector CLI) finishes. This call stays open for up to ~2 minutes. stillRunning true means the runtime hit the max hold; call wait_for_job again immediately. If the job is hanging, producing no useful output, or doing the wrong thing, call stop_job instead. Do not end the turn or tell the user you will let them know later.",
2690
+ stop_job: "Stop a detached job you started with detached-job.cjs when it is hanging, producing no useful output, buffering forever, or doing the wrong thing (wrong project, infinite watch, huge dump). Do not stop a pack/test/deploy that is clearly making progress."
2691
+ };
2692
+
2693
+ // src/agents/claude-host.ts
2694
+ function claudePilotSdkAllowedTools() {
2695
+ return PILOT_TOOL_NAMES.map(
2696
+ (name) => `mcp__${AGENT_RPC_CLAUDE_SDK_SERVER}__${name}`
2697
+ );
2698
+ }
2699
+ function withClaudePilotRpcTools(allowed) {
2700
+ const omit = new Set(PILOT_TOOL_NAMES.map((name) => `mcp__sideboard__${name}`));
2701
+ return [...allowed.filter((name) => !omit.has(name)), ...claudePilotSdkAllowedTools()];
2702
+ }
2703
+ function entryDir() {
2704
+ const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
2705
+ if (cjsDir) return cjsDir;
2706
+ try {
2707
+ return dirname4(fileURLToPath2(import.meta.url));
2708
+ } catch {
2709
+ try {
2710
+ const req = createRequire2(process.cwd() + "/");
2711
+ return dirname4(req.resolve("@sideboard-ai/core"));
2712
+ } catch {
2713
+ return process.cwd();
2714
+ }
2715
+ }
2716
+ }
2717
+ function claudeRunnerPath() {
2718
+ const packagedDir = packagedCursorRuntimeDir();
2719
+ if (packagedDir) {
2720
+ const packaged = join8(packagedDir, "core-dist", "agents", "claude-runner.js");
2721
+ if (existsSync9(packaged)) return packaged;
2722
+ }
2723
+ const root = entryDir();
2724
+ const candidates = [
2725
+ join8(root, "agents", "claude-runner.js"),
2726
+ join8(root, "agents", "claude-runner.cjs"),
2727
+ join8(root, "dist", "agents", "claude-runner.js"),
2728
+ join8(root, "dist", "agents", "claude-runner.cjs"),
2729
+ join8(root, "claude-runner.ts"),
2730
+ join8(root, "src", "agents", "claude-runner.ts")
2731
+ ];
2732
+ for (const candidate of candidates) {
2733
+ if (existsSync9(candidate)) return candidate;
2734
+ }
2735
+ return candidates[0];
2736
+ }
2737
+ async function buildClaudeRpcTurnCommand(req) {
2738
+ const runner = claudeRunnerPath();
2739
+ const isTs = runner.endsWith(".ts");
2740
+ const launch = applyNodeLaunch(
2741
+ await resolveNodeLaunch(runner),
2742
+ isTs ? ["--import", "tsx", runner] : [runner]
2743
+ );
2744
+ return {
2745
+ file: launch.file,
2746
+ args: launch.args,
2747
+ cwd: req.cwd,
2748
+ stdin: JSON.stringify(req),
2749
+ env: {
2750
+ ...launch.env,
2751
+ CLAUDE_CODE_FORWARD_SUBAGENT_TEXT: "1",
2752
+ CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS: process.env.CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS ?? "7200000",
2753
+ ...req.isolateClaudeAiMcp ? { ENABLE_CLAUDEAI_MCP_SERVERS: "false" } : {}
2754
+ }
2755
+ };
2756
+ }
2757
+
2758
+ // src/agents/claude.ts
2547
2759
  function isLocalDevAppDataDir(dir = process.env.SIDEBOARD_APP_DATA) {
2548
2760
  return /[/\\]\.sideboard[/\\]dev-app-data(?:[/\\]|$)/.test(dir ?? "");
2549
2761
  }
2550
- var CLAUDE_CHROME_ALLOWED_TOOLS = [
2551
- "mcp__claude-in-chrome",
2552
- "mcp__claude-in-chrome__*",
2553
- "Skill(claude-in-chrome)"
2554
- ];
2555
2762
  var CLAUDE_PROMPT_ARG_MAX = 2e5;
2556
2763
  function usageFromClaude(usage) {
2557
2764
  if (!usage) return null;
@@ -2589,6 +2796,13 @@ function costUsdFromClaudeResult(obj) {
2589
2796
  }
2590
2797
  return void 0;
2591
2798
  }
2799
+ function sessionCostUsdFromClaudeResult(obj) {
2800
+ const totalCost = obj.total_cost_usd ?? obj.totalCostUsd;
2801
+ if (totalCost != null && Number.isFinite(Number(totalCost))) {
2802
+ return Number(totalCost);
2803
+ }
2804
+ return void 0;
2805
+ }
2592
2806
  function claudeResultErrorDetail(obj) {
2593
2807
  const isError = Boolean(obj.is_error) || typeof obj.subtype === "string" && /^error/i.test(obj.subtype);
2594
2808
  const fromResult = typeof obj.result === "string" ? obj.result.trim() : "";
@@ -2921,7 +3135,7 @@ var claudeAdapter = {
2921
3135
  async detect() {
2922
3136
  const claude = resolveClaudeExecutable();
2923
3137
  if (claude !== "claude") {
2924
- if (!existsSync8(claude)) {
3138
+ if (!existsSync10(claude)) {
2925
3139
  return {
2926
3140
  agent: "claude",
2927
3141
  installed: false,
@@ -2970,15 +3184,17 @@ var claudeAdapter = {
2970
3184
  );
2971
3185
  }
2972
3186
  const mode = permissionMode(thread);
2973
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-PHF2MOGW.js");
3187
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-6LDUZ2NF.js");
2974
3188
  const isOrchestrator = isOrchestratorThread2(thread);
3189
+ const rpc = worktreeAgentRpc(isOrchestrator);
2975
3190
  const injectedServers = await buildInjectedMcpServers({
2976
3191
  includeSideboard: true,
2977
3192
  includeBrightsy: shouldInjectBrightsyMcp(thread, {
2978
3193
  orchestrator: isOrchestrator
2979
3194
  }),
2980
3195
  orchestratorThreadId: isOrchestrator ? thread.id : null,
2981
- threadId: thread.id
3196
+ threadId: thread.id,
3197
+ rpcNativeTools: Boolean(rpc)
2982
3198
  });
2983
3199
  const injectedBrightsyNames = injectedServers.filter((s) => s.name === "brightsy" || s.name.startsWith("brightsy_")).map((s) => s.name);
2984
3200
  const chromeOn = claudeChromeEnabled();
@@ -3006,6 +3222,23 @@ var claudeAdapter = {
3006
3222
  if (chromeOn) {
3007
3223
  allowedTools = [...allowedTools, ...CLAUDE_CHROME_ALLOWED_TOOLS];
3008
3224
  }
3225
+ if (rpc) {
3226
+ return buildClaudeRpcTurnCommand({
3227
+ prompt: promptText,
3228
+ cwd: thread.worktreePath,
3229
+ sessionId,
3230
+ model: thread.model,
3231
+ effort: thread.effort ?? (thread.fast ? "low" : "high"),
3232
+ permissionMode: mode.claude,
3233
+ systemPrompt,
3234
+ claudePath: claude,
3235
+ chrome: chromeOn,
3236
+ mcpServers: mcpServersRecord(injectedServers, userMcpEntries),
3237
+ allowedTools: withClaudePilotRpcTools(allowedTools),
3238
+ agentRpc: rpc,
3239
+ isolateClaudeAiMcp: isOrchestrator || isLocalDevAppDataDir()
3240
+ });
3241
+ }
3009
3242
  const args = [
3010
3243
  "-p",
3011
3244
  ...useStdin ? [] : [promptText],
@@ -3140,6 +3373,8 @@ var claudeAdapter = {
3140
3373
  if (usage) {
3141
3374
  const costUsd = costUsdFromClaudeResult(obj);
3142
3375
  if (costUsd != null) usage.costUsd = costUsd;
3376
+ const sessionCostUsd = sessionCostUsdFromClaudeResult(obj);
3377
+ if (sessionCostUsd != null) usage.sessionCostUsd = sessionCostUsd;
3143
3378
  events.push({ type: "usage", data: usage, scope: "turn" });
3144
3379
  }
3145
3380
  if (events.length === 0) return null;
@@ -3210,9 +3445,9 @@ function parseIssuesJson(raw) {
3210
3445
  }
3211
3446
 
3212
3447
  // src/agents/codex.ts
3213
- import { existsSync as existsSync9, readFileSync as readFileSync4, statSync as statSync2 } from "fs";
3448
+ import { existsSync as existsSync11, readFileSync as readFileSync5, statSync as statSync2 } from "fs";
3214
3449
  import { homedir as homedir4 } from "os";
3215
- import { join as join7 } from "path";
3450
+ import { join as join9 } from "path";
3216
3451
  var CODEX_PROMPT_ARG_MAX = 2e5;
3217
3452
  var FALLBACK_CODEX_MODELS = [
3218
3453
  { id: "gpt-5.6-sol", displayName: "GPT-5.6 Sol" },
@@ -3232,7 +3467,7 @@ async function listCodexModels() {
3232
3467
  if (codex === "codex") {
3233
3468
  const which = await run("which", ["codex"], { reject: false });
3234
3469
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
3235
- } else if (!existsSync9(codex)) {
3470
+ } else if (!existsSync11(codex)) {
3236
3471
  return FALLBACK_CODEX_MODELS;
3237
3472
  }
3238
3473
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -3267,12 +3502,12 @@ function usageFromCodex(usage) {
3267
3502
  }
3268
3503
  function codexConfigHasNetworkAccess() {
3269
3504
  const candidates = [
3270
- join7(homedir4(), ".codex", "config.toml"),
3271
- join7(homedir4(), ".config", "codex", "config.toml")
3505
+ join9(homedir4(), ".codex", "config.toml"),
3506
+ join9(homedir4(), ".config", "codex", "config.toml")
3272
3507
  ];
3273
3508
  for (const path of candidates) {
3274
- if (!existsSync9(path)) continue;
3275
- const text = readFileSync4(path, "utf8");
3509
+ if (!existsSync11(path)) continue;
3510
+ const text = readFileSync5(path, "utf8");
3276
3511
  if (/network_access\s*=\s*true/.test(text)) return true;
3277
3512
  }
3278
3513
  return false;
@@ -3304,8 +3539,8 @@ function asRecord2(value) {
3304
3539
  return void 0;
3305
3540
  }
3306
3541
  function codexLooksAuthenticated() {
3307
- const authPath = join7(homedir4(), ".codex", "auth.json");
3308
- if (!existsSync9(authPath)) return false;
3542
+ const authPath = join9(homedir4(), ".codex", "auth.json");
3543
+ if (!existsSync11(authPath)) return false;
3309
3544
  try {
3310
3545
  return statSync2(authPath).size > 2;
3311
3546
  } catch {
@@ -3317,7 +3552,7 @@ var codexAdapter = {
3317
3552
  async detect() {
3318
3553
  const codex = resolveAgentExecutable("codex");
3319
3554
  if (codex !== "codex") {
3320
- if (!existsSync9(codex)) {
3555
+ if (!existsSync11(codex)) {
3321
3556
  return {
3322
3557
  agent: "codex",
3323
3558
  installed: false,
@@ -3591,40 +3826,40 @@ var codexAdapter = {
3591
3826
  };
3592
3827
 
3593
3828
  // src/agents/cursor.ts
3594
- import { existsSync as existsSync12 } from "fs";
3595
- import { createRequire as createRequire4 } from "module";
3596
- import { dirname as dirname6, join as join10 } from "path";
3597
- import { fileURLToPath as fileURLToPath3 } from "url";
3829
+ import { existsSync as existsSync14 } from "fs";
3830
+ import { createRequire as createRequire5 } from "module";
3831
+ import { dirname as dirname7, join as join12 } from "path";
3832
+ import { fileURLToPath as fileURLToPath4 } from "url";
3598
3833
 
3599
3834
  // src/agents/cursor-sdk-resolve.ts
3600
- import { existsSync as existsSync10, readFileSync as readFileSync5 } from "fs";
3601
- import { createRequire as createRequire2 } from "module";
3602
- import { basename, dirname as dirname4, join as join8 } from "path";
3603
- import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
3835
+ import { existsSync as existsSync12, readFileSync as readFileSync6 } from "fs";
3836
+ import { createRequire as createRequire3 } from "module";
3837
+ import { basename, dirname as dirname5, join as join10 } from "path";
3838
+ import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
3604
3839
  var CURSOR_SDK_INSTALL_HINT = "Cursor SDK is not installed. Settings \u2192 Agents \u2192 Cursor \u2192 Install (`npm i -g @cursor/sdk`). Sideboard does not ship the SDK \u2014 update it anytime without a new Sideboard build.";
3605
3840
  function thisModuleFile() {
3606
3841
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
3607
- if (cjsDir) return join8(cjsDir, "cursor-sdk-resolve.js");
3842
+ if (cjsDir) return join10(cjsDir, "cursor-sdk-resolve.js");
3608
3843
  try {
3609
- return fileURLToPath2(import.meta.url);
3844
+ return fileURLToPath3(import.meta.url);
3610
3845
  } catch {
3611
- return join8(process.cwd(), "package.json");
3846
+ return join10(process.cwd(), "package.json");
3612
3847
  }
3613
3848
  }
3614
3849
  function packageRootLooksLikeSdk(dir) {
3615
3850
  try {
3616
- const raw = readFileSync5(join8(dir, "package.json"), "utf8");
3851
+ const raw = readFileSync6(join10(dir, "package.json"), "utf8");
3617
3852
  const pkg = JSON.parse(raw);
3618
- return pkg.name === "@cursor/sdk" && existsSync10(dir);
3853
+ return pkg.name === "@cursor/sdk" && existsSync12(dir);
3619
3854
  } catch {
3620
3855
  return false;
3621
3856
  }
3622
3857
  }
3623
3858
  function resolvedPackageRoot(fromFile) {
3624
3859
  try {
3625
- const req = createRequire2(fromFile);
3860
+ const req = createRequire3(fromFile);
3626
3861
  const pkgJson = req.resolve("@cursor/sdk/package.json");
3627
- const root = dirname4(pkgJson);
3862
+ const root = dirname5(pkgJson);
3628
3863
  return packageRootLooksLikeSdk(root) ? root : null;
3629
3864
  } catch {
3630
3865
  return null;
@@ -3638,10 +3873,10 @@ function resolveCursorSdkRoot(opts) {
3638
3873
  }
3639
3874
  const globalNm = npmGlobalNodeModules(env);
3640
3875
  if (globalNm) {
3641
- const globalRoot = join8(globalNm, "@cursor/sdk");
3876
+ const globalRoot = join10(globalNm, "@cursor/sdk");
3642
3877
  if (packageRootLooksLikeSdk(globalRoot)) return globalRoot;
3643
3878
  }
3644
- const cwdPkg = join8(process.cwd(), "package.json");
3879
+ const cwdPkg = join10(process.cwd(), "package.json");
3645
3880
  return resolvedPackageRoot(thisModuleFile()) ?? resolvedPackageRoot(cwdPkg);
3646
3881
  }
3647
3882
  function isCursorSdkInstalled(opts) {
@@ -3657,13 +3892,13 @@ function exportTarget(value) {
3657
3892
  }
3658
3893
  function cursorSdkEsmEntry(root) {
3659
3894
  try {
3660
- const pkg = JSON.parse(readFileSync5(join8(root, "package.json"), "utf8"));
3895
+ const pkg = JSON.parse(readFileSync6(join10(root, "package.json"), "utf8"));
3661
3896
  const exp = pkg.exports;
3662
3897
  const dot = exp && typeof exp === "object" && !Array.isArray(exp) && "." in exp ? exp["."] : exp;
3663
3898
  const rel = exportTarget(dot) ?? (typeof pkg.module === "string" ? pkg.module : null);
3664
3899
  if (!rel) return null;
3665
- const entry = join8(root, rel);
3666
- return existsSync10(entry) ? entry : null;
3900
+ const entry = join10(root, rel);
3901
+ return existsSync12(entry) ? entry : null;
3667
3902
  } catch {
3668
3903
  return null;
3669
3904
  }
@@ -3679,7 +3914,7 @@ async function importCursorSdk(opts) {
3679
3914
  try {
3680
3915
  let entry = cursorSdkEsmEntry(root);
3681
3916
  if (!entry) {
3682
- const req = createRequire2(join8(root, "package.json"));
3917
+ const req = createRequire3(join10(root, "package.json"));
3683
3918
  entry = req.resolve("@cursor/sdk");
3684
3919
  }
3685
3920
  return unwrapCursorSdkModule(await import(pathToFileURL(entry).href));
@@ -3691,8 +3926,8 @@ function cursorSdkPlatformRipgrepPackage() {
3691
3926
  return `@cursor/sdk-${process.platform}-${process.arch}`;
3692
3927
  }
3693
3928
  function nodeModulesDirForPackageRoot(packageRoot) {
3694
- const parent = dirname4(packageRoot);
3695
- return basename(parent).startsWith("@") ? dirname4(parent) : parent;
3929
+ const parent = dirname5(packageRoot);
3930
+ return basename(parent).startsWith("@") ? dirname5(parent) : parent;
3696
3931
  }
3697
3932
  function cursorSdkRipgrepCandidate(opts) {
3698
3933
  const root = resolveCursorSdkRoot(opts);
@@ -3700,10 +3935,10 @@ function cursorSdkRipgrepCandidate(opts) {
3700
3935
  const nm = nodeModulesDirForPackageRoot(root);
3701
3936
  const pkg = cursorSdkPlatformRipgrepPackage();
3702
3937
  const bin = process.platform === "win32" ? "rg.exe" : "rg";
3703
- const sibling = join8(nm, pkg, "bin", bin);
3704
- if (existsSync10(sibling)) return sibling;
3705
- const nested = join8(root, "node_modules", pkg, "bin", bin);
3706
- return existsSync10(nested) ? nested : null;
3938
+ const sibling = join10(nm, pkg, "bin", bin);
3939
+ if (existsSync12(sibling)) return sibling;
3940
+ const nested = join10(root, "node_modules", pkg, "bin", bin);
3941
+ return existsSync12(nested) ? nested : null;
3707
3942
  }
3708
3943
 
3709
3944
  // src/agents/cursor-events.ts
@@ -3918,9 +4153,9 @@ function parseCursorRunnerLine(line) {
3918
4153
  }
3919
4154
 
3920
4155
  // src/agents/cursor-ripgrep.ts
3921
- import { existsSync as existsSync11 } from "fs";
3922
- import { createRequire as createRequire3 } from "module";
3923
- import { dirname as dirname5, isAbsolute, join as join9, parse, resolve as resolvePath } from "path";
4156
+ import { existsSync as existsSync13 } from "fs";
4157
+ import { createRequire as createRequire4 } from "module";
4158
+ import { dirname as dirname6, isAbsolute, join as join11, parse, resolve as resolvePath } from "path";
3924
4159
  var RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
3925
4160
  function rgBinaryName() {
3926
4161
  return process.platform === "win32" ? "rg.exe" : "rg";
@@ -3932,19 +4167,19 @@ function usableRipgrepPath(candidate) {
3932
4167
  const raw = candidate?.trim();
3933
4168
  if (!raw || !isAbsolute(raw)) return null;
3934
4169
  const readable = nodeReadableScriptPath(raw);
3935
- if (!existsSync11(readable) || isAsarPath(readable)) return null;
4170
+ if (!existsSync13(readable) || isAsarPath(readable)) return null;
3936
4171
  return readable;
3937
4172
  }
3938
4173
  function walkForBundledRipgrep(startFile) {
3939
4174
  if (!startFile) return null;
3940
4175
  const pkg = platformRipgrepPackage();
3941
4176
  const name = rgBinaryName();
3942
- let dir = dirname5(resolvePath(startFile));
4177
+ let dir = dirname6(resolvePath(startFile));
3943
4178
  const root = parse(dir).root;
3944
4179
  while (dir !== root) {
3945
- const hit = usableRipgrepPath(join9(dir, "node_modules", pkg, "bin", name));
4180
+ const hit = usableRipgrepPath(join11(dir, "node_modules", pkg, "bin", name));
3946
4181
  if (hit) return hit;
3947
- const next = dirname5(dir);
4182
+ const next = dirname6(dir);
3948
4183
  if (next === dir) break;
3949
4184
  dir = next;
3950
4185
  }
@@ -3952,9 +4187,9 @@ function walkForBundledRipgrep(startFile) {
3952
4187
  }
3953
4188
  function requireResolveBundledRipgrep(fromFile) {
3954
4189
  try {
3955
- const req = createRequire3(fromFile);
4190
+ const req = createRequire4(fromFile);
3956
4191
  const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
3957
- return usableRipgrepPath(join9(dirname5(pkgJson), "bin", rgBinaryName()));
4192
+ return usableRipgrepPath(join11(dirname6(pkgJson), "bin", rgBinaryName()));
3958
4193
  } catch {
3959
4194
  return null;
3960
4195
  }
@@ -4024,15 +4259,15 @@ async function listCursorModels() {
4024
4259
  return cachedModels?.models ?? FALLBACK_CURSOR_MODELS;
4025
4260
  }
4026
4261
  }
4027
- function entryDir() {
4262
+ function entryDir2() {
4028
4263
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
4029
4264
  if (cjsDir) return cjsDir;
4030
4265
  try {
4031
- return dirname6(fileURLToPath3(import.meta.url));
4266
+ return dirname7(fileURLToPath4(import.meta.url));
4032
4267
  } catch {
4033
4268
  try {
4034
- const req = createRequire4(process.cwd() + "/");
4035
- return dirname6(req.resolve("@sideboard-ai/core"));
4269
+ const req = createRequire5(process.cwd() + "/");
4270
+ return dirname7(req.resolve("@sideboard-ai/core"));
4036
4271
  } catch {
4037
4272
  return process.cwd();
4038
4273
  }
@@ -4041,19 +4276,19 @@ function entryDir() {
4041
4276
  function cursorRunnerPath() {
4042
4277
  const packaged = packagedCursorRunnerPath();
4043
4278
  if (packaged) return packaged;
4044
- const root = entryDir();
4279
+ const root = entryDir2();
4045
4280
  const candidates = [
4046
- join10(root, "agents", "cursor-runner.js"),
4047
- join10(root, "agents", "cursor-runner.cjs"),
4281
+ join12(root, "agents", "cursor-runner.js"),
4282
+ join12(root, "agents", "cursor-runner.cjs"),
4048
4283
  // If somehow resolved from package root instead of dist/
4049
- join10(root, "dist", "agents", "cursor-runner.js"),
4050
- join10(root, "dist", "agents", "cursor-runner.cjs"),
4284
+ join12(root, "dist", "agents", "cursor-runner.js"),
4285
+ join12(root, "dist", "agents", "cursor-runner.cjs"),
4051
4286
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
4052
- join10(root, "cursor-runner.ts"),
4053
- join10(root, "src", "agents", "cursor-runner.ts")
4287
+ join12(root, "cursor-runner.ts"),
4288
+ join12(root, "src", "agents", "cursor-runner.ts")
4054
4289
  ];
4055
4290
  for (const candidate of candidates) {
4056
- if (existsSync12(candidate)) return candidate;
4291
+ if (existsSync14(candidate)) return candidate;
4057
4292
  }
4058
4293
  return candidates[0];
4059
4294
  }
@@ -4094,13 +4329,15 @@ var cursorAdapter = {
4094
4329
  const prompt = flattenTurnInput(dropCachedPrefixOnResume(input, agentId));
4095
4330
  const apiKey = resolveCursorApiKey() || void 0;
4096
4331
  const isOrchestrator = isOrchestratorThread(thread);
4332
+ const rpc = agentRpcConnectFromMetadata();
4097
4333
  const injected = await buildInjectedMcpServers({
4098
4334
  includeSideboard: true,
4099
4335
  includeBrightsy: shouldInjectBrightsyMcp(thread, {
4100
4336
  orchestrator: isOrchestrator
4101
4337
  }),
4102
4338
  orchestratorThreadId: isOrchestrator ? thread.id : null,
4103
- threadId: thread.id
4339
+ threadId: thread.id,
4340
+ rpcNativeTools: Boolean(rpc)
4104
4341
  });
4105
4342
  const mcpServers = toCursorMcpServers(injected);
4106
4343
  const req = {
@@ -4114,6 +4351,8 @@ var cursorAdapter = {
4114
4351
  planMode: thread.planMode,
4115
4352
  apiKey,
4116
4353
  ...isOrchestrator ? { isolateAmbientMcp: true } : {},
4354
+ ...rpc ? { agentRpc: rpc } : {},
4355
+ ...isOrchestrator && rpc ? { rpcWaitForTurn: true } : {},
4117
4356
  ...Object.keys(mcpServers).length > 0 ? { mcpServers } : {}
4118
4357
  };
4119
4358
  const runner = cursorRunnerPath();
@@ -4152,7 +4391,155 @@ var cursorAdapter = {
4152
4391
  };
4153
4392
 
4154
4393
  // src/agents/opencode.ts
4155
- import { existsSync as existsSync13 } from "fs";
4394
+ import { existsSync as existsSync15 } from "fs";
4395
+
4396
+ // src/agent-rpc/opencode-hook.ts
4397
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "fs";
4398
+ import { join as join13 } from "path";
4399
+ var OPENCODE_PLUGIN_SOURCE = `import { tool } from "@opencode-ai/plugin"
4400
+
4401
+ const URL = process.env[${JSON.stringify(AGENT_RPC_URL_ENV)}] || ""
4402
+ const TOKEN = process.env[${JSON.stringify(AGENT_RPC_TOKEN_ENV)}] || ""
4403
+ const CWD = process.env[${JSON.stringify(AGENT_RPC_CWD_ENV)}] || ""
4404
+
4405
+ function jsonResult(value) {
4406
+ return JSON.stringify(value)
4407
+ }
4408
+
4409
+ function jsonError(err) {
4410
+ return jsonResult({ ok: false, error: err instanceof Error ? err.message : String(err) })
4411
+ }
4412
+
4413
+ function socketUrl() {
4414
+ const u = new URL(URL)
4415
+ u.searchParams.set(${JSON.stringify(AGENT_RPC_TOKEN_QUERY)}, TOKEN)
4416
+ return u.toString()
4417
+ }
4418
+
4419
+ function call(method, params) {
4420
+ if (!URL || !TOKEN) {
4421
+ return Promise.resolve(jsonError(new Error("Agent RPC runtime is not running")))
4422
+ }
4423
+ return new Promise((resolve) => {
4424
+ let settled = false
4425
+ const done = (value) => {
4426
+ if (settled) return
4427
+ settled = true
4428
+ try { ws.close() } catch {}
4429
+ resolve(value)
4430
+ }
4431
+ const ws = new WebSocket(socketUrl())
4432
+ const id = Date.now()
4433
+ ws.addEventListener("open", () => {
4434
+ ws.send(JSON.stringify({ jsonrpc: "2.0", id, method, params, authToken: TOKEN }))
4435
+ })
4436
+ ws.addEventListener("message", (ev) => {
4437
+ let msg
4438
+ try { msg = JSON.parse(String(ev.data)) } catch { return }
4439
+ if (msg && msg.id === id) {
4440
+ if (msg.error) done(jsonError(new Error(msg.error.message || "Agent RPC error")))
4441
+ else done(jsonResult(msg.result))
4442
+ }
4443
+ })
4444
+ ws.addEventListener("error", () => done(jsonError(new Error("Agent RPC socket error"))))
4445
+ ws.addEventListener("close", () => {
4446
+ if (!settled) done(jsonError(new Error("Agent RPC socket closed")))
4447
+ })
4448
+ })
4449
+ }
4450
+
4451
+ function str(description) {
4452
+ return tool.schema.string().describe(description)
4453
+ }
4454
+
4455
+ function opt(description) {
4456
+ return tool.schema.string().optional().describe(description)
4457
+ }
4458
+
4459
+ export const SideboardRpc = async (ctx) => {
4460
+ const cwd = CWD || ctx.worktree || ctx.directory || ""
4461
+ const job = (method, args) => call(method, { ...args, cwd })
4462
+ return {
4463
+ tool: {
4464
+ present_artifact: tool({
4465
+ description: ${JSON.stringify(PILOT_TOOL_DESCRIPTIONS.present_artifact)},
4466
+ args: {
4467
+ title: str("Short title shown in the artifact pane header"),
4468
+ type: tool.schema.enum(["html", "svg", "markdown", "react", "log"]),
4469
+ content: str("html/svg/markdown/react: full document. log: only the new lines."),
4470
+ artifact_id: opt("Stable id. Required for type=log."),
4471
+ status: tool.schema.enum(["running", "ok", "failed", "idle"]).optional(),
4472
+ phase: opt("Progress phase"),
4473
+ mode: tool.schema.enum(["append", "replace"]).optional(),
4474
+ },
4475
+ async execute(args) {
4476
+ return call("ui.presentArtifact", args)
4477
+ },
4478
+ }),
4479
+ wait_for_job: tool({
4480
+ description: ${JSON.stringify(PILOT_TOOL_DESCRIPTIONS.wait_for_job)},
4481
+ args: {
4482
+ id: str("Detached job id (same kebab-case id passed to detached-job.cjs start)"),
4483
+ },
4484
+ async execute(args) {
4485
+ return job("job.wait", args)
4486
+ },
4487
+ }),
4488
+ stop_job: tool({
4489
+ description: ${JSON.stringify(PILOT_TOOL_DESCRIPTIONS.stop_job)},
4490
+ args: {
4491
+ id: str("Detached job id"),
4492
+ reason: opt("Why the job is being stopped"),
4493
+ },
4494
+ async execute(args) {
4495
+ return job("job.stop", args)
4496
+ },
4497
+ }),
4498
+ },
4499
+ }
4500
+ }
4501
+ `;
4502
+ function writeOpencodeRpcPlugin() {
4503
+ const configDir = join13(appDataDir(), "agent-rpc", "opencode");
4504
+ const pluginDir = join13(configDir, "plugins");
4505
+ mkdirSync3(pluginDir, { recursive: true });
4506
+ const pluginFile = join13(pluginDir, "sideboard-rpc.js");
4507
+ writeFileSync5(pluginFile, OPENCODE_PLUGIN_SOURCE);
4508
+ return { configDir, pluginFile };
4509
+ }
4510
+
4511
+ // src/agent-rpc/opencode-host.ts
4512
+ async function buildOpencodeHostEnv(thread) {
4513
+ const isOrchestrator = isOrchestratorThread(thread);
4514
+ const rpc = worktreeAgentRpc(isOrchestrator);
4515
+ const injected = await buildInjectedMcpServers({
4516
+ includeSideboard: true,
4517
+ includeBrightsy: shouldInjectBrightsyMcp(thread, {
4518
+ orchestrator: isOrchestrator
4519
+ }),
4520
+ orchestratorThreadId: isOrchestrator ? thread.id : null,
4521
+ threadId: thread.id,
4522
+ rpcNativeTools: Boolean(rpc)
4523
+ });
4524
+ const disableNames = isOrchestrator ? userMcpNamesToDisable({
4525
+ injectedNames: injected.map((s) => s.name),
4526
+ names: listUserOpencodeMcpNames()
4527
+ }) : [];
4528
+ const config = injected.length > 0 || disableNames.length > 0 ? JSON.parse(toOpencodeMcpConfigContent(injected, { disableNames })) : {};
4529
+ const env = {};
4530
+ if (rpc) {
4531
+ const { configDir, pluginFile } = writeOpencodeRpcPlugin();
4532
+ env.OPENCODE_CONFIG_DIR = configDir;
4533
+ Object.assign(env, agentRpcChildEnv(rpc, thread.worktreePath));
4534
+ config.plugin = [pluginFile];
4535
+ }
4536
+ if (Object.keys(config).length > 0) {
4537
+ env.OPENCODE_CONFIG_CONTENT = JSON.stringify(config);
4538
+ }
4539
+ return env;
4540
+ }
4541
+
4542
+ // src/agents/opencode.ts
4156
4543
  var FALLBACK_OPENCODE_MODELS = [
4157
4544
  { id: "opencode/big-pickle", displayName: "opencode \xB7 big-pickle" },
4158
4545
  {
@@ -4211,7 +4598,7 @@ async function listOpencodeModels() {
4211
4598
  if (opencode === "opencode") {
4212
4599
  const which = await run("which", ["opencode"], { reject: false });
4213
4600
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
4214
- } else if (!existsSync13(opencode)) {
4601
+ } else if (!existsSync15(opencode)) {
4215
4602
  return FALLBACK_OPENCODE_MODELS;
4216
4603
  }
4217
4604
  const listed = await run(opencode, ["models"], { reject: false });
@@ -4246,7 +4633,7 @@ var opencodeAdapter = {
4246
4633
  async detect() {
4247
4634
  const opencode = resolveAgentExecutable("opencode");
4248
4635
  if (opencode !== "opencode") {
4249
- if (!existsSync13(opencode)) {
4636
+ if (!existsSync15(opencode)) {
4250
4637
  return {
4251
4638
  agent: "opencode",
4252
4639
  installed: false,
@@ -4300,20 +4687,7 @@ var opencodeAdapter = {
4300
4687
  if (model) {
4301
4688
  args.push("--model", model);
4302
4689
  }
4303
- const isOrchestrator = isOrchestratorThread(thread);
4304
- const injected = await buildInjectedMcpServers({
4305
- includeSideboard: true,
4306
- includeBrightsy: shouldInjectBrightsyMcp(thread, {
4307
- orchestrator: isOrchestrator
4308
- }),
4309
- orchestratorThreadId: isOrchestrator ? thread.id : null,
4310
- threadId: thread.id
4311
- });
4312
- const disableNames = isOrchestrator ? userMcpNamesToDisable({
4313
- injectedNames: injected.map((s) => s.name),
4314
- names: listUserOpencodeMcpNames()
4315
- }) : [];
4316
- const mcpContent = injected.length > 0 || disableNames.length > 0 ? toOpencodeMcpConfigContent(injected, { disableNames }) : null;
4690
+ const hostEnv = await buildOpencodeHostEnv(thread);
4317
4691
  return {
4318
4692
  file: resolveAgentExecutable("opencode"),
4319
4693
  args,
@@ -4323,7 +4697,7 @@ var opencodeAdapter = {
4323
4697
  stdin: prompt,
4324
4698
  env: {
4325
4699
  OPENCODE_PERMISSION: mode.opencodePermission,
4326
- ...mcpContent ? { OPENCODE_CONFIG_CONTENT: mcpContent } : {}
4700
+ ...hostEnv
4327
4701
  }
4328
4702
  };
4329
4703
  },
@@ -4924,9 +5298,9 @@ function formatClaudeUsageOverLimitWait(windows, now = /* @__PURE__ */ new Date(
4924
5298
  }
4925
5299
 
4926
5300
  // src/agents/claude-usage-client.ts
4927
- import { existsSync as existsSync14, readFileSync as readFileSync6 } from "fs";
5301
+ import { existsSync as existsSync16, readFileSync as readFileSync7 } from "fs";
4928
5302
  import { homedir as homedir5 } from "os";
4929
- import { join as join11 } from "path";
5303
+ import { join as join14 } from "path";
4930
5304
  var CLAUDE_OAUTH_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
4931
5305
  var CLAUDE_USAGE_TTL_MS = 9e4;
4932
5306
  var CLAUDE_USAGE_ERROR_TTL_MS = 5 * 6e4;
@@ -4966,14 +5340,14 @@ function accessTokenFromCredentialsJson(raw) {
4966
5340
  }
4967
5341
  }
4968
5342
  function claudeCredentialsPath(configDir) {
4969
- const root = configDir?.trim() || process.env.CLAUDE_CONFIG_DIR?.trim() || join11(homedir5(), ".claude");
4970
- return join11(root, ".credentials.json");
5343
+ const root = configDir?.trim() || process.env.CLAUDE_CONFIG_DIR?.trim() || join14(homedir5(), ".claude");
5344
+ return join14(root, ".credentials.json");
4971
5345
  }
4972
5346
  async function readFileAccessToken(configDir) {
4973
5347
  const path = claudeCredentialsPath(configDir);
4974
- if (!existsSync14(path)) return null;
5348
+ if (!existsSync16(path)) return null;
4975
5349
  try {
4976
- return accessTokenFromCredentialsJson(readFileSync6(path, "utf8"));
5350
+ return accessTokenFromCredentialsJson(readFileSync7(path, "utf8"));
4977
5351
  } catch {
4978
5352
  return null;
4979
5353
  }
@@ -5086,7 +5460,7 @@ async function getClaudePlanUsage(opts = {}) {
5086
5460
  }
5087
5461
 
5088
5462
  // src/agents/install.ts
5089
- import { existsSync as existsSync15 } from "fs";
5463
+ import { existsSync as existsSync17 } from "fs";
5090
5464
  var SETUP = {
5091
5465
  claude: {
5092
5466
  agent: "claude",
@@ -5267,7 +5641,7 @@ async function installNpmGlobalPackage(opts) {
5267
5641
  async function resolveExistingCli(agent) {
5268
5642
  if (agent === "cursor") return null;
5269
5643
  const exe = resolveAgentExecutable(agent);
5270
- if ((exe.includes("/") || exe.includes("\\")) && existsSync15(exe)) return exe;
5644
+ if ((exe.includes("/") || exe.includes("\\")) && existsSync17(exe)) return exe;
5271
5645
  enrichPathWithNpmGlobalBin();
5272
5646
  return whichOnPath(CLI_BIN[agent]);
5273
5647
  }
@@ -5341,7 +5715,7 @@ async function loginAgent(agent) {
5341
5715
  };
5342
5716
  }
5343
5717
  async function loginManagedAccount(accountId) {
5344
- const { loadAppSettings: loadAppSettings2 } = await import("./app-settings-OM7H64YM.js");
5718
+ const { loadAppSettings: loadAppSettings2 } = await import("./app-settings-MVZPM6WW.js");
5345
5719
  const { loginEnvPrefix } = await import("./managed-accounts-4BLTJKAN.js");
5346
5720
  const account = loadAppSettings2().accounts.accounts.find((a) => a.id === accountId);
5347
5721
  if (!account) {
@@ -5395,16 +5769,6 @@ export {
5395
5769
  shouldFeedErrorBackToAgent,
5396
5770
  formatAgentErrorContinuePrompt,
5397
5771
  formatTurnExitError,
5398
- encodeBrightsyTarget,
5399
- decodeBrightsyTarget,
5400
- parseBrightsyCliLine,
5401
- adjustBrightsyTurnExit,
5402
- listBrightsyChatTargets,
5403
- brightsyAdapter,
5404
- SIDEBOARD_THREAD_ID_ENV,
5405
- sideboardMcpProfile,
5406
- packagedMcpDir,
5407
- applyAgentRunnerHeapEnv,
5408
5772
  toolDescription,
5409
5773
  isInternalAgentStatusText,
5410
5774
  isPollWrapperToolName,
@@ -5418,6 +5782,18 @@ export {
5418
5782
  isBrightsyNdjsonLine,
5419
5783
  finalizeParts,
5420
5784
  normalizeParseResult,
5785
+ encodeBrightsyTarget,
5786
+ decodeBrightsyTarget,
5787
+ parseBrightsyCliLine,
5788
+ adjustBrightsyTurnExit,
5789
+ listBrightsyChatTargets,
5790
+ brightsyAdapter,
5791
+ SIDEBOARD_THREAD_ID_ENV,
5792
+ shouldRegisterMcpWaitForTurn,
5793
+ worktreeMcpToolNames,
5794
+ sideboardMcpProfile,
5795
+ packagedMcpDir,
5796
+ applyAgentRunnerHeapEnv,
5421
5797
  PLAN_MODE_INSTRUCTION,
5422
5798
  PLAN_MODE_OFF_INSTRUCTION,
5423
5799
  planModeTurnInstruction,