@sideboard-ai/core 0.1.155 → 0.1.157

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 (29) hide show
  1. package/dist/{abletime-JSTJLXAW.js → abletime-BEIDJG7W.js} +5 -1
  2. package/dist/{abletime-H7LPGIP2.js → abletime-GWZE6OYM.js} +5 -1
  3. package/dist/agents/cursor-runner.cjs +6 -1
  4. package/dist/agents/cursor-runner.js +6 -1
  5. package/dist/{agents-V24DYZI4.js → agents-C55LAEUR.js} +4 -2
  6. package/dist/{agents-YVW75KBO.js → agents-LCDXN2B2.js} +4 -2
  7. package/dist/{chunk-RNC3GR6L.js → chunk-4I4VKAPZ.js} +5 -4
  8. package/dist/{chunk-2F63IMCL.js → chunk-CVR4RJ6G.js} +5 -4
  9. package/dist/{chunk-JOK4XWBG.js → chunk-DVJBO3M7.js} +87 -3
  10. package/dist/{chunk-J2OKVOBM.js → chunk-GWEEGE6L.js} +119 -10
  11. package/dist/{chunk-4THE3EY7.js → chunk-KQ4JOGUH.js} +214 -39
  12. package/dist/{chunk-FDCFXMDG.js → chunk-N27GVFZY.js} +87 -3
  13. package/dist/{chunk-46ZTBUVJ.js → chunk-SUCJAWV4.js} +90 -9
  14. package/dist/{chunk-QZEZXYVV.js → chunk-TIJ6QVX5.js} +305 -33
  15. package/dist/{coordinator-prompt-7FHKCWXB.js → coordinator-prompt-26IJU2AV.js} +1 -1
  16. package/dist/{coordinator-prompt-KX2FVVYT.js → coordinator-prompt-AM47SATF.js} +1 -1
  17. package/dist/{global-workspace-2BRRKSDN.js → global-workspace-5BIW26YR.js} +1 -1
  18. package/dist/{global-workspace-4LHCZ2DC.js → global-workspace-QV7CC7SK.js} +1 -1
  19. package/dist/index.cjs +1438 -695
  20. package/dist/index.d.cts +150 -3
  21. package/dist/index.d.ts +150 -3
  22. package/dist/index.js +600 -322
  23. package/dist/mcp/run-stdio.cjs +1223 -573
  24. package/dist/mcp/run-stdio.js +501 -199
  25. package/dist/{orchestrator-HC7XVGJB.js → orchestrator-BUH3LJLL.js} +3 -3
  26. package/dist/{orchestrator-3FWEKDAQ.js → orchestrator-KQO4MXBI.js} +3 -3
  27. package/dist/{workspaces-5UNDTN4G.js → workspaces-NYSM2EPX.js} +1 -1
  28. package/dist/{workspaces-MQYNZXUK.js → workspaces-Q2VCHIAS.js} +1 -1
  29. package/package.json +1 -1
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-S42XV45P.js";
12
12
  import {
13
13
  isOrchestratorThread
14
- } from "./chunk-RNC3GR6L.js";
14
+ } from "./chunk-4I4VKAPZ.js";
15
15
  import {
16
16
  codexUnattendedGitConfigArgs,
17
17
  mergeAgentGitAuthEnv,
@@ -27,7 +27,9 @@ import {
27
27
  } from "./chunk-FNQNJOHY.js";
28
28
  import {
29
29
  claudeChromeEnabled,
30
+ isAbleTimeConnected,
30
31
  isElectronLikeCommand,
32
+ isLinearConnected,
31
33
  loadAppSettings,
32
34
  resolveAgentExecutable,
33
35
  resolveClaudeExecutable,
@@ -1476,6 +1478,16 @@ var SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS = [
1476
1478
  "mcp__sideboard__ask_user",
1477
1479
  "mcp__sideboard__present_plan"
1478
1480
  ];
1481
+ var SIDEBOARD_GITHUB_MCP_ALLOWED_TOOLS = ["mcp__sideboard__github_*"];
1482
+ var SIDEBOARD_LINEAR_MCP_ALLOWED_TOOLS = ["mcp__sideboard__linear_*"];
1483
+ var SIDEBOARD_ABLETIME_MCP_ALLOWED_TOOLS = ["mcp__sideboard__abletime_*"];
1484
+ function sideboardWorktreeAllowedTools(opts) {
1485
+ const out = [...SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS];
1486
+ if (opts?.github !== false) out.push(...SIDEBOARD_GITHUB_MCP_ALLOWED_TOOLS);
1487
+ if (opts?.linear) out.push(...SIDEBOARD_LINEAR_MCP_ALLOWED_TOOLS);
1488
+ if (opts?.abletime) out.push(...SIDEBOARD_ABLETIME_MCP_ALLOWED_TOOLS);
1489
+ return out;
1490
+ }
1479
1491
  var brightsyMcpCommandCache = null;
1480
1492
  async function resolveBrightsyMcpCommand() {
1481
1493
  const now = Date.now();
@@ -1709,7 +1721,7 @@ function toCodexMcpConfigArgs(servers) {
1709
1721
  }
1710
1722
  return args;
1711
1723
  }
1712
- function toOpencodeMcpConfigContent(servers) {
1724
+ function toOpencodeMcpConfigContent(servers, opts) {
1713
1725
  const mcp = {};
1714
1726
  for (const s of servers) {
1715
1727
  const env = mcpSpawnEnv(s.env);
@@ -1720,6 +1732,11 @@ function toOpencodeMcpConfigContent(servers) {
1720
1732
  ...env ? { environment: env } : {}
1721
1733
  };
1722
1734
  }
1735
+ for (const name of opts?.disableNames ?? []) {
1736
+ const key = name.trim();
1737
+ if (!key || mcp[key]?.enabled === true) continue;
1738
+ mcp[key] = { ...mcp[key], enabled: false };
1739
+ }
1723
1740
  return JSON.stringify({ mcp });
1724
1741
  }
1725
1742
  function writeMcpServersConfig(servers) {
@@ -1935,13 +1952,50 @@ function claudeString(obj, key) {
1935
1952
  const v = obj[key];
1936
1953
  return typeof v === "string" && v.trim() ? v.trim() : void 0;
1937
1954
  }
1955
+ function mcpStatusThinkingFromClaudeInit(obj) {
1956
+ const raw = obj.mcp_servers ?? obj.mcpServers;
1957
+ const servers = [];
1958
+ if (Array.isArray(raw)) {
1959
+ for (const item of raw) {
1960
+ if (!item || typeof item !== "object" || Array.isArray(item)) continue;
1961
+ const rec = item;
1962
+ const name = typeof rec.name === "string" && rec.name.trim() || typeof rec.server === "string" && rec.server.trim() || "";
1963
+ const status = typeof rec.status === "string" && rec.status.trim() || typeof rec.state === "string" && rec.state.trim() || "";
1964
+ if (name) servers.push({ name, status: status || "unknown" });
1965
+ }
1966
+ } else if (raw && typeof raw === "object") {
1967
+ for (const [name, value] of Object.entries(raw)) {
1968
+ if (!name.trim()) continue;
1969
+ if (typeof value === "string" && value.trim()) {
1970
+ servers.push({ name, status: value.trim() });
1971
+ continue;
1972
+ }
1973
+ if (value && typeof value === "object" && !Array.isArray(value)) {
1974
+ const rec = value;
1975
+ const status = typeof rec.status === "string" && rec.status.trim() || typeof rec.state === "string" && rec.state.trim() || "unknown";
1976
+ servers.push({ name, status });
1977
+ }
1978
+ }
1979
+ }
1980
+ const notable = servers.filter((s) => !isCleanMcpConnect(s.status));
1981
+ if (notable.length === 0) return null;
1982
+ return `MCP: ${notable.map((s) => `${s.name} ${s.status}`).join(", ")}`;
1983
+ }
1984
+ function isCleanMcpConnect(status) {
1985
+ return /^(connected|ok|ready|success)$/i.test(status.trim());
1986
+ }
1938
1987
  function eventsFromClaudeSystem(obj) {
1939
1988
  const subtype = claudeString(obj, "subtype") ?? "";
1940
1989
  const parentId = claudeParentToolUseId(obj);
1941
1990
  if (subtype === "init") {
1942
1991
  if (parentId) return null;
1943
1992
  const sid = claudeString(obj, "session_id");
1944
- return sid ? { type: "session_id", data: sid } : null;
1993
+ const mcpNote = mcpStatusThinkingFromClaudeInit(obj);
1994
+ const events = [];
1995
+ if (sid) events.push({ type: "session_id", data: sid });
1996
+ if (mcpNote) events.push({ type: "thinking", data: mcpNote, replace: true });
1997
+ if (events.length === 0) return null;
1998
+ return events.length === 1 ? events[0] : events;
1945
1999
  }
1946
2000
  if (subtype === "task_started") {
1947
2001
  const id = claudeString(obj, "tool_use_id") ?? claudeString(obj, "task_id");
@@ -2098,7 +2152,7 @@ var claudeAdapter = {
2098
2152
  );
2099
2153
  }
2100
2154
  const mode = permissionMode(thread);
2101
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-4LHCZ2DC.js");
2155
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-QV7CC7SK.js");
2102
2156
  const isOrchestrator = isOrchestratorThread2(thread);
2103
2157
  const injectedServers = await buildInjectedMcpServers({
2104
2158
  includeSideboard: true,
@@ -2121,7 +2175,11 @@ var claudeAdapter = {
2121
2175
  allowedTools = [
2122
2176
  ...BASE_ALLOWED_TOOLS,
2123
2177
  ...mcpAllowTools(servers),
2124
- ...SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS,
2178
+ ...sideboardWorktreeAllowedTools({
2179
+ github: true,
2180
+ linear: isLinearConnected(),
2181
+ abletime: isAbleTimeConnected()
2182
+ }),
2125
2183
  ...brightsyMcpAllowedTools(injectedBrightsyNames)
2126
2184
  ];
2127
2185
  }
@@ -2141,6 +2199,9 @@ var claudeAdapter = {
2141
2199
  const mcpConfigPath = writeMcpServersConfig(injectedServers);
2142
2200
  if (mcpConfigPath) {
2143
2201
  args.push("--mcp-config", mcpConfigPath);
2202
+ if (isOrchestrator) {
2203
+ args.push("--strict-mcp-config");
2204
+ }
2144
2205
  }
2145
2206
  if (chromeOn) {
2146
2207
  args.push("--chrome");
@@ -2170,7 +2231,10 @@ var claudeAdapter = {
2170
2231
  // abandoned at Claude Code’s 10-minute default.
2171
2232
  env: {
2172
2233
  CLAUDE_CODE_FORWARD_SUBAGENT_TEXT: "1",
2173
- CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS: process.env.CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS ?? String(CLAUDE_PRINT_BG_WAIT_CEILING_MS)
2234
+ CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS: process.env.CLAUDE_CODE_PRINT_BG_WAIT_CEILING_MS ?? String(CLAUDE_PRINT_BG_WAIT_CEILING_MS),
2235
+ // `--strict-mcp-config` still fetches claude.ai connectors on some CLI
2236
+ // builds (anthropics/claude-code#60252). Coordinators do not need them.
2237
+ ...isOrchestrator ? { ENABLE_CLAUDEAI_MCP_SERVERS: "false" } : {}
2174
2238
  }
2175
2239
  };
2176
2240
  },
@@ -2318,9 +2382,106 @@ function parseIssuesJson(raw) {
2318
2382
  }
2319
2383
 
2320
2384
  // src/agents/codex.ts
2321
- import { existsSync as existsSync6, readFileSync, statSync } from "fs";
2385
+ import { existsSync as existsSync8, readFileSync as readFileSync3, statSync } from "fs";
2386
+ import { homedir as homedir4 } from "os";
2387
+ import { join as join6 } from "path";
2388
+
2389
+ // src/agents/orch-mcp-isolation.ts
2390
+ import { existsSync as existsSync7, readFileSync as readFileSync2 } from "fs";
2391
+ import { homedir as homedir3 } from "os";
2392
+ import { join as join5 } from "path";
2393
+ import { parse as parseToml } from "smol-toml";
2394
+
2395
+ // src/agents/user-mcp-config.ts
2396
+ import { existsSync as existsSync6, mkdirSync, readFileSync, writeFileSync as writeFileSync2 } from "fs";
2322
2397
  import { homedir as homedir2 } from "os";
2323
- import { join as join4 } from "path";
2398
+ import { dirname as dirname2, join as join4 } from "path";
2399
+
2400
+ // src/agents/orch-mcp-isolation.ts
2401
+ function isInjectedOrchMcpName(name) {
2402
+ const n = name.trim().toLowerCase();
2403
+ return n === "sideboard" || n === "brightsy" || n.startsWith("brightsy_");
2404
+ }
2405
+ function asObject(value) {
2406
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
2407
+ return value;
2408
+ }
2409
+ function listMcpNamesFromJsonMap(raw, key) {
2410
+ return Object.keys(asObject(asObject(raw)[key])).filter((n) => n.trim());
2411
+ }
2412
+ function listMcpNamesFromCodexToml(text) {
2413
+ try {
2414
+ const parsed = parseToml(text);
2415
+ return Object.keys(asObject(parsed.mcp_servers)).filter((n) => n.trim());
2416
+ } catch {
2417
+ return [];
2418
+ }
2419
+ }
2420
+ function readJsonObject(path) {
2421
+ try {
2422
+ return JSON.parse(readFileSync2(path, "utf8"));
2423
+ } catch {
2424
+ return {};
2425
+ }
2426
+ }
2427
+ function readText(path) {
2428
+ try {
2429
+ return readFileSync2(path, "utf8");
2430
+ } catch {
2431
+ return "";
2432
+ }
2433
+ }
2434
+ function userCodexConfigPaths(home = homedir3()) {
2435
+ return [join5(home, ".codex", "config.toml"), join5(home, ".config", "codex", "config.toml")];
2436
+ }
2437
+ function userOpencodeConfigPaths(home = homedir3()) {
2438
+ return [
2439
+ join5(home, ".config", "opencode", "opencode.json"),
2440
+ join5(home, ".config", "opencode", "opencode.jsonc")
2441
+ ];
2442
+ }
2443
+ function userMcpNamesToDisable(opts) {
2444
+ const keep = new Set(
2445
+ [...opts.injectedNames ?? []].map((n) => n.trim().toLowerCase()).filter(Boolean)
2446
+ );
2447
+ const out = [];
2448
+ const seen = /* @__PURE__ */ new Set();
2449
+ for (const raw of opts.names) {
2450
+ const name = raw.trim();
2451
+ if (!name) continue;
2452
+ const key = name.toLowerCase();
2453
+ if (seen.has(key) || keep.has(key) || isInjectedOrchMcpName(name)) continue;
2454
+ seen.add(key);
2455
+ out.push(name);
2456
+ }
2457
+ return out;
2458
+ }
2459
+ function listUserCodexMcpNames(home = homedir3()) {
2460
+ const names = [];
2461
+ for (const path of userCodexConfigPaths(home)) {
2462
+ if (!existsSync7(path)) continue;
2463
+ names.push(...listMcpNamesFromCodexToml(readText(path)));
2464
+ }
2465
+ return names;
2466
+ }
2467
+ function listUserOpencodeMcpNames(home = homedir3()) {
2468
+ const names = [];
2469
+ for (const path of userOpencodeConfigPaths(home)) {
2470
+ if (!existsSync7(path)) continue;
2471
+ names.push(...listMcpNamesFromJsonMap(readJsonObject(path), "mcp"));
2472
+ }
2473
+ return names;
2474
+ }
2475
+ function toCodexDisableUserMcpArgs(names) {
2476
+ const args = [];
2477
+ for (const name of names) {
2478
+ if (!/^[A-Za-z0-9_-]+$/.test(name)) continue;
2479
+ args.push("-c", `mcp_servers.${name}.enabled=false`);
2480
+ }
2481
+ return args;
2482
+ }
2483
+
2484
+ // src/agents/codex.ts
2324
2485
  var CODEX_PROMPT_ARG_MAX = 2e5;
2325
2486
  var FALLBACK_CODEX_MODELS = [
2326
2487
  { id: "gpt-5.6-sol", displayName: "GPT-5.6 Sol" },
@@ -2340,7 +2501,7 @@ async function listCodexModels() {
2340
2501
  if (codex === "codex") {
2341
2502
  const which = await run("which", ["codex"], { reject: false });
2342
2503
  if (which.exitCode !== 0) return FALLBACK_CODEX_MODELS;
2343
- } else if (!existsSync6(codex)) {
2504
+ } else if (!existsSync8(codex)) {
2344
2505
  return FALLBACK_CODEX_MODELS;
2345
2506
  }
2346
2507
  const listed = await run(codex, ["debug", "models"], { reject: false });
@@ -2375,12 +2536,12 @@ function usageFromCodex(usage) {
2375
2536
  }
2376
2537
  function codexConfigHasNetworkAccess() {
2377
2538
  const candidates = [
2378
- join4(homedir2(), ".codex", "config.toml"),
2379
- join4(homedir2(), ".config", "codex", "config.toml")
2539
+ join6(homedir4(), ".codex", "config.toml"),
2540
+ join6(homedir4(), ".config", "codex", "config.toml")
2380
2541
  ];
2381
2542
  for (const path of candidates) {
2382
- if (!existsSync6(path)) continue;
2383
- const text = readFileSync(path, "utf8");
2543
+ if (!existsSync8(path)) continue;
2544
+ const text = readFileSync3(path, "utf8");
2384
2545
  if (/network_access\s*=\s*true/.test(text)) return true;
2385
2546
  }
2386
2547
  return false;
@@ -2412,8 +2573,8 @@ function asRecord2(value) {
2412
2573
  return void 0;
2413
2574
  }
2414
2575
  function codexLooksAuthenticated() {
2415
- const authPath = join4(homedir2(), ".codex", "auth.json");
2416
- if (!existsSync6(authPath)) return false;
2576
+ const authPath = join6(homedir4(), ".codex", "auth.json");
2577
+ if (!existsSync8(authPath)) return false;
2417
2578
  try {
2418
2579
  return statSync(authPath).size > 2;
2419
2580
  } catch {
@@ -2425,7 +2586,7 @@ var codexAdapter = {
2425
2586
  async detect() {
2426
2587
  const codex = resolveAgentExecutable("codex");
2427
2588
  if (codex !== "codex") {
2428
- if (!existsSync6(codex)) {
2589
+ if (!existsSync8(codex)) {
2429
2590
  return {
2430
2591
  agent: "codex",
2431
2592
  installed: false,
@@ -2485,7 +2646,15 @@ var codexAdapter = {
2485
2646
  }),
2486
2647
  orchestratorThreadId: isOrchestrator ? thread.id : null
2487
2648
  });
2488
- const mcpOverrides = toCodexMcpConfigArgs(injected);
2649
+ const mcpOverrides = [
2650
+ ...toCodexMcpConfigArgs(injected),
2651
+ ...isOrchestrator ? toCodexDisableUserMcpArgs(
2652
+ userMcpNamesToDisable({
2653
+ injectedNames: injected.map((s) => s.name),
2654
+ names: listUserCodexMcpNames()
2655
+ })
2656
+ ) : []
2657
+ ];
2489
2658
  const execOpts = [
2490
2659
  // Global orchestration cwd is not a git repo; without this Codex ≥0.147
2491
2660
  // refuses to start ("Not inside a trusted directory").
@@ -2685,9 +2854,9 @@ var codexAdapter = {
2685
2854
  };
2686
2855
 
2687
2856
  // src/agents/cursor.ts
2688
- import { existsSync as existsSync8 } from "fs";
2857
+ import { existsSync as existsSync10 } from "fs";
2689
2858
  import { createRequire as createRequire3 } from "module";
2690
- import { dirname as dirname3, join as join6 } from "path";
2859
+ import { dirname as dirname4, join as join8 } from "path";
2691
2860
  import { fileURLToPath as fileURLToPath2 } from "url";
2692
2861
  import { Cursor } from "@cursor/sdk";
2693
2862
 
@@ -2903,9 +3072,9 @@ function parseCursorRunnerLine(line) {
2903
3072
  }
2904
3073
 
2905
3074
  // src/agents/cursor-ripgrep.ts
2906
- import { existsSync as existsSync7 } from "fs";
3075
+ import { existsSync as existsSync9 } from "fs";
2907
3076
  import { createRequire as createRequire2 } from "module";
2908
- import { dirname as dirname2, isAbsolute, join as join5, parse, resolve as resolvePath } from "path";
3077
+ import { dirname as dirname3, isAbsolute, join as join7, parse, resolve as resolvePath } from "path";
2909
3078
  var RIPGREP_ENV = "CURSOR_RIPGREP_PATH";
2910
3079
  function rgBinaryName() {
2911
3080
  return process.platform === "win32" ? "rg.exe" : "rg";
@@ -2917,19 +3086,19 @@ function usableRipgrepPath(candidate) {
2917
3086
  const raw = candidate?.trim();
2918
3087
  if (!raw || !isAbsolute(raw)) return null;
2919
3088
  const readable = nodeReadableScriptPath(raw);
2920
- if (!existsSync7(readable) || isAsarPath(readable)) return null;
3089
+ if (!existsSync9(readable) || isAsarPath(readable)) return null;
2921
3090
  return readable;
2922
3091
  }
2923
3092
  function walkForBundledRipgrep(startFile) {
2924
3093
  if (!startFile) return null;
2925
3094
  const pkg = platformRipgrepPackage();
2926
3095
  const name = rgBinaryName();
2927
- let dir = dirname2(resolvePath(startFile));
3096
+ let dir = dirname3(resolvePath(startFile));
2928
3097
  const root = parse(dir).root;
2929
3098
  while (dir !== root) {
2930
- const hit = usableRipgrepPath(join5(dir, "node_modules", pkg, "bin", name));
3099
+ const hit = usableRipgrepPath(join7(dir, "node_modules", pkg, "bin", name));
2931
3100
  if (hit) return hit;
2932
- const next = dirname2(dir);
3101
+ const next = dirname3(dir);
2933
3102
  if (next === dir) break;
2934
3103
  dir = next;
2935
3104
  }
@@ -2939,7 +3108,7 @@ function requireResolveBundledRipgrep(fromFile) {
2939
3108
  try {
2940
3109
  const req = createRequire2(fromFile);
2941
3110
  const pkgJson = req.resolve(`${platformRipgrepPackage()}/package.json`);
2942
- return usableRipgrepPath(join5(dirname2(pkgJson), "bin", rgBinaryName()));
3111
+ return usableRipgrepPath(join7(dirname3(pkgJson), "bin", rgBinaryName()));
2943
3112
  } catch {
2944
3113
  return null;
2945
3114
  }
@@ -3008,11 +3177,11 @@ function entryDir() {
3008
3177
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
3009
3178
  if (cjsDir) return cjsDir;
3010
3179
  try {
3011
- return dirname3(fileURLToPath2(import.meta.url));
3180
+ return dirname4(fileURLToPath2(import.meta.url));
3012
3181
  } catch {
3013
3182
  try {
3014
3183
  const req = createRequire3(process.cwd() + "/");
3015
- return dirname3(req.resolve("@sideboard-ai/core"));
3184
+ return dirname4(req.resolve("@sideboard-ai/core"));
3016
3185
  } catch {
3017
3186
  return process.cwd();
3018
3187
  }
@@ -3023,17 +3192,17 @@ function cursorRunnerPath() {
3023
3192
  if (packaged) return packaged;
3024
3193
  const root = entryDir();
3025
3194
  const candidates = [
3026
- join6(root, "agents", "cursor-runner.js"),
3027
- join6(root, "agents", "cursor-runner.cjs"),
3195
+ join8(root, "agents", "cursor-runner.js"),
3196
+ join8(root, "agents", "cursor-runner.cjs"),
3028
3197
  // If somehow resolved from package root instead of dist/
3029
- join6(root, "dist", "agents", "cursor-runner.js"),
3030
- join6(root, "dist", "agents", "cursor-runner.cjs"),
3198
+ join8(root, "dist", "agents", "cursor-runner.js"),
3199
+ join8(root, "dist", "agents", "cursor-runner.cjs"),
3031
3200
  // Source tree (dev): packages/core/src/agents/cursor-runner.ts
3032
- join6(root, "cursor-runner.ts"),
3033
- join6(root, "src", "agents", "cursor-runner.ts")
3201
+ join8(root, "cursor-runner.ts"),
3202
+ join8(root, "src", "agents", "cursor-runner.ts")
3034
3203
  ];
3035
3204
  for (const candidate of candidates) {
3036
- if (existsSync8(candidate)) return candidate;
3205
+ if (existsSync10(candidate)) return candidate;
3037
3206
  }
3038
3207
  return candidates[0];
3039
3208
  }
@@ -3082,6 +3251,7 @@ var cursorAdapter = {
3082
3251
  fast: thread.fast,
3083
3252
  planMode: thread.planMode,
3084
3253
  apiKey,
3254
+ ...isOrchestrator ? { isolateAmbientMcp: true } : {},
3085
3255
  ...Object.keys(mcpServers).length > 0 ? { mcpServers } : {}
3086
3256
  };
3087
3257
  const runner = cursorRunnerPath();
@@ -3120,7 +3290,7 @@ var cursorAdapter = {
3120
3290
  };
3121
3291
 
3122
3292
  // src/agents/opencode.ts
3123
- import { existsSync as existsSync9 } from "fs";
3293
+ import { existsSync as existsSync11 } from "fs";
3124
3294
  var FALLBACK_OPENCODE_MODELS = [
3125
3295
  { id: "opencode/big-pickle", displayName: "opencode \xB7 big-pickle" },
3126
3296
  {
@@ -3179,7 +3349,7 @@ async function listOpencodeModels() {
3179
3349
  if (opencode === "opencode") {
3180
3350
  const which = await run("which", ["opencode"], { reject: false });
3181
3351
  if (which.exitCode !== 0) return FALLBACK_OPENCODE_MODELS;
3182
- } else if (!existsSync9(opencode)) {
3352
+ } else if (!existsSync11(opencode)) {
3183
3353
  return FALLBACK_OPENCODE_MODELS;
3184
3354
  }
3185
3355
  const listed = await run(opencode, ["models"], { reject: false });
@@ -3214,7 +3384,7 @@ var opencodeAdapter = {
3214
3384
  async detect() {
3215
3385
  const opencode = resolveAgentExecutable("opencode");
3216
3386
  if (opencode !== "opencode") {
3217
- if (!existsSync9(opencode)) {
3387
+ if (!existsSync11(opencode)) {
3218
3388
  return {
3219
3389
  agent: "opencode",
3220
3390
  installed: false,
@@ -3276,7 +3446,11 @@ var opencodeAdapter = {
3276
3446
  }),
3277
3447
  orchestratorThreadId: isOrchestrator ? thread.id : null
3278
3448
  });
3279
- const mcpContent = injected.length > 0 ? toOpencodeMcpConfigContent(injected) : null;
3449
+ const disableNames = isOrchestrator ? userMcpNamesToDisable({
3450
+ injectedNames: injected.map((s) => s.name),
3451
+ names: listUserOpencodeMcpNames()
3452
+ }) : [];
3453
+ const mcpContent = injected.length > 0 || disableNames.length > 0 ? toOpencodeMcpConfigContent(injected, { disableNames }) : null;
3280
3454
  return {
3281
3455
  file: resolveAgentExecutable("opencode"),
3282
3456
  args,
@@ -3949,6 +4123,7 @@ export {
3949
4123
  applyAgentRunnerHeapEnv,
3950
4124
  PLAN_MODE_INSTRUCTION,
3951
4125
  permissionMode,
4126
+ mcpStatusThinkingFromClaudeInit,
3952
4127
  claudeAdapter,
3953
4128
  listCodexModels,
3954
4129
  codexAdapter,
@@ -226,6 +226,27 @@ function labelsOf(record) {
226
226
  return rec ? firstString(rec, ["name", "title", "label"]) : "";
227
227
  }).filter(Boolean);
228
228
  }
229
+ function commentsOf(record) {
230
+ const raw = record.comments ?? record.notes ?? record.discussion;
231
+ const out = [];
232
+ for (const item of asList(raw)) {
233
+ const rec = asRecord2(item);
234
+ if (!rec) continue;
235
+ const body = firstString(rec, ["body", "text", "comment", "content", "message"]);
236
+ if (!body) continue;
237
+ const user = firstString(asRecord2(rec.user) ?? asRecord2(rec.author), ["name", "display_name"]) || firstString(rec, ["user_name", "author"]);
238
+ const comment = { body };
239
+ const id = firstString(rec, ["id", "comment_id"]);
240
+ if (id) comment.id = id;
241
+ const url = firstString(rec, ["url", "permalink"]);
242
+ if (url) comment.url = url;
243
+ const createdAt = firstString(rec, ["created_at", "createdAt", "created"]);
244
+ if (createdAt) comment.createdAt = createdAt;
245
+ if (user) comment.user = user;
246
+ out.push(comment);
247
+ }
248
+ return out;
249
+ }
229
250
  function assigneeOf(record) {
230
251
  const nested = firstRecord(record, ["assignee", "assigned_to", "user", "owner"]);
231
252
  const name = firstString(nested, ["name", "display_name", "full_name", "email"]) || firstString(record, ["assignee_name", "assigneeName"]);
@@ -259,7 +280,8 @@ function mapAbleTimeTask(raw, host) {
259
280
  projectId: firstString(nested, ["project_id", "projectId"]) || firstString(asRecord2(nested.project), ["id"]) || void 0,
260
281
  categoryId: firstString(nested, ["category_id", "categoryId"]) || firstString(asRecord2(nested.category), ["id"]) || void 0,
261
282
  assignee: assigneeOf(nested),
262
- labels: labelsOf(nested)
283
+ labels: labelsOf(nested),
284
+ comments: commentsOf(nested)
263
285
  };
264
286
  }
265
287
  function toAbleTimeIssueInfo(task) {
@@ -352,16 +374,24 @@ async function createAbleTimeTask(input, opts) {
352
374
  if (!title) throw new Error("AbleTime task title is required");
353
375
  const project = await resolveAbleTimeProject(input.projectId, opts);
354
376
  const category = resolveAbleTimeCategory(project, input.categoryId);
377
+ const parent = input.parent?.trim();
378
+ const descriptionParts = [
379
+ parent ? `Spin-off of ${parent}.` : null,
380
+ input.description?.trim() || null
381
+ ].filter(Boolean);
355
382
  const raw = await callAbleTimeTool(
356
383
  "create_task",
357
384
  {
358
385
  title,
359
- description: input.description?.trim() || void 0,
386
+ description: descriptionParts.join("\n\n") || void 0,
360
387
  state: input.state ?? "todo",
361
388
  project: project.id,
362
389
  project_id: project.id,
363
390
  category: category?.id,
364
- category_id: category?.id
391
+ category_id: category?.id,
392
+ parent,
393
+ parent_id: parent,
394
+ related_task_id: parent
365
395
  },
366
396
  opts
367
397
  );
@@ -369,6 +399,58 @@ async function createAbleTimeTask(input, opts) {
369
399
  if (!task) throw new Error("AbleTime create_task returned no task");
370
400
  return task;
371
401
  }
402
+ async function commentAbleTimeTask(input, opts) {
403
+ const id = input.id.trim();
404
+ const body = input.body.trim();
405
+ if (!id) throw new Error("AbleTime task id is required");
406
+ if (!body) throw new Error("AbleTime comment body is required");
407
+ const raw = await callAbleTimeTool(
408
+ "create_comment",
409
+ { id, task_id: id, task: id, body, comment: body, text: body },
410
+ opts
411
+ );
412
+ const rec = asRecord2(raw);
413
+ return {
414
+ id: rec ? firstString(rec, ["id", "comment_id"]) || void 0 : void 0,
415
+ body: rec ? firstString(rec, ["body", "text", "comment"]) || body : body
416
+ };
417
+ }
418
+ async function updateAbleTimeTask(input, opts) {
419
+ const id = input.id.trim();
420
+ if (!id) throw new Error("AbleTime task id is required");
421
+ const title = input.title?.trim();
422
+ const description = input.description;
423
+ const state = input.state?.trim();
424
+ if (!title && description === void 0 && !state) {
425
+ throw new Error("abletime_update_task needs at least one of title, description, state");
426
+ }
427
+ if (state) {
428
+ await callAbleTimeTool(
429
+ "set_task_state",
430
+ { id, task_id: id, task: id, state },
431
+ opts
432
+ ).catch(async () => {
433
+ await callAbleTimeTool(
434
+ "update_task",
435
+ { id, task_id: id, title, description, state },
436
+ opts
437
+ );
438
+ });
439
+ }
440
+ if (title || description !== void 0) {
441
+ await callAbleTimeTool(
442
+ "update_task",
443
+ {
444
+ id,
445
+ task_id: id,
446
+ ...title ? { title } : {},
447
+ ...description !== void 0 ? { description } : {}
448
+ },
449
+ opts
450
+ );
451
+ }
452
+ return getAbleTimeTask(id, opts);
453
+ }
372
454
  async function resolveAbleTimeProject(projectId, opts) {
373
455
  const wanted = projectId?.trim().toLowerCase();
374
456
  const fromOrientation = (await getAbleTimeOrientation(opts).catch(() => null))?.projects ?? [];
@@ -457,6 +539,8 @@ export {
457
539
  searchAbleTimeTasks,
458
540
  getAbleTimeTask,
459
541
  createAbleTimeTask,
542
+ commentAbleTimeTask,
543
+ updateAbleTimeTask,
460
544
  ensureAbleTimeTask,
461
545
  listAbleTimeAssignedIssues,
462
546
  verifyAbleTimeConnection