@sideboard-ai/core 0.1.313 → 0.1.315

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 (59) hide show
  1. package/dist/{abletime-SJUVZVRU.js → abletime-QK3KMRQD.js} +4 -4
  2. package/dist/{abletime-T5YSJLNZ.js → abletime-QQZWYJXC.js} +4 -4
  3. package/dist/{abletime-oauth-73TFJME4.js → abletime-oauth-CAHTMB4V.js} +3 -3
  4. package/dist/{abletime-oauth-2TOOZ2FN.js → abletime-oauth-I2RRPVKT.js} +3 -3
  5. package/dist/{abletime-rest-PNUGH2FS.js → abletime-rest-5V4KGMSY.js} +3 -3
  6. package/dist/{abletime-rest-5TDRIFEV.js → abletime-rest-W5TLQK7C.js} +3 -3
  7. package/dist/{agents-OHIE3Z7L.js → agents-5XJ7EHGU.js} +6 -6
  8. package/dist/{agents-PSNWJMEC.js → agents-Y3M3EKLY.js} +6 -6
  9. package/dist/{app-settings-CC65VPBL.js → app-settings-CZVFMOI5.js} +3 -1
  10. package/dist/{app-settings-DZ5AY7N5.js → app-settings-RQAFJZCD.js} +3 -1
  11. package/dist/{chunk-EGTCXNQM.js → chunk-53OCOGND.js} +2 -2
  12. package/dist/{chunk-DLGGLV2M.js → chunk-5CTG5W7S.js} +2 -2
  13. package/dist/{chunk-JARCAPKL.js → chunk-72OWKHFJ.js} +3 -3
  14. package/dist/{chunk-CW4FIIDE.js → chunk-7J2KOIYD.js} +3 -3
  15. package/dist/{chunk-U3J2YY4T.js → chunk-BMORGDYI.js} +48 -28
  16. package/dist/{chunk-BIPXOHZI.js → chunk-BPBDGJ43.js} +2 -2
  17. package/dist/{chunk-HG25AYBV.js → chunk-CHUPIJP7.js} +14 -0
  18. package/dist/{chunk-E2NJ6RH7.js → chunk-CYPFOIUK.js} +47 -27
  19. package/dist/{chunk-JWW66PO3.js → chunk-DV6ID6CK.js} +5 -5
  20. package/dist/{chunk-2JOBQUUS.js → chunk-FVTR54LY.js} +120 -56
  21. package/dist/{chunk-PHMFAU35.js → chunk-GCHSJCCX.js} +96 -64
  22. package/dist/{chunk-5QX2NYXL.js → chunk-GFM63DTU.js} +12 -9
  23. package/dist/{chunk-QC2TQMPJ.js → chunk-IODJCVMN.js} +5 -5
  24. package/dist/{chunk-CFTOKVQN.js → chunk-JRZTJ4F7.js} +5 -5
  25. package/dist/{chunk-62ESCTJ4.js → chunk-MBYGWNLQ.js} +3 -3
  26. package/dist/{chunk-OLSLE3LO.js → chunk-MKGSMPWB.js} +3 -3
  27. package/dist/{chunk-TDXORDN6.js → chunk-NKVNHBDB.js} +119 -55
  28. package/dist/{chunk-U4WACWBC.js → chunk-NXNNYY3Q.js} +2 -2
  29. package/dist/{chunk-SZ3XS2WM.js → chunk-NZVD5EVX.js} +2 -2
  30. package/dist/{chunk-WRZRX4Q7.js → chunk-OLYNM52B.js} +4 -4
  31. package/dist/{chunk-X3FSWWW2.js → chunk-PN32Z4JL.js} +12 -9
  32. package/dist/{chunk-RU6DTCCV.js → chunk-S3U4HR5F.js} +2 -2
  33. package/dist/{chunk-3UDRWMIM.js → chunk-U35AHE2P.js} +14 -0
  34. package/dist/{chunk-A2YXQC65.js → chunk-U7PNCYNX.js} +96 -64
  35. package/dist/{chunk-6424BACS.js → chunk-Y4WARKPW.js} +2 -2
  36. package/dist/{chunk-ZW7RSQHY.js → chunk-YR7NZYUT.js} +5 -5
  37. package/dist/{conductor-YOBSYPLT.js → conductor-DKWTQADV.js} +5 -5
  38. package/dist/{conductor-CTWR6NH4.js → conductor-IMKNYQWZ.js} +5 -5
  39. package/dist/{coordinator-prompt-GZCWQAAV.js → coordinator-prompt-HUZC4DZ2.js} +4 -4
  40. package/dist/{coordinator-prompt-YAZRQ4BI.js → coordinator-prompt-SPOYUZG5.js} +4 -4
  41. package/dist/{global-workspace-BZAVBOH3.js → global-workspace-3NNDDTFD.js} +4 -4
  42. package/dist/{global-workspace-H6X32IJZ.js → global-workspace-SK4JQBPN.js} +4 -4
  43. package/dist/index.cjs +285 -123
  44. package/dist/index.d.cts +84 -59
  45. package/dist/index.d.ts +84 -59
  46. package/dist/index.js +25 -21
  47. package/dist/mcp/run-stdio.cjs +280 -121
  48. package/dist/mcp/run-stdio.js +15 -14
  49. package/dist/{optional-cli-QDIT57VD.js → optional-cli-EMSZBYDE.js} +3 -3
  50. package/dist/{optional-cli-QY6V5S5N.js → optional-cli-LMSRZNH4.js} +4 -4
  51. package/dist/{orchestrator-BF7TKSA2.js → orchestrator-4XFRK57E.js} +9 -9
  52. package/dist/{orchestrator-RRHB7RNN.js → orchestrator-ZRMZ4TCL.js} +9 -9
  53. package/dist/{thread-store-HY22M5A7.js → thread-store-5OF6M6VZ.js} +1 -1
  54. package/dist/{thread-store-XMUQDO5O.js → thread-store-GOVVXQV2.js} +1 -1
  55. package/dist/{workspaces-BQUDYTBX.js → workspaces-52L6NZ3P.js} +4 -4
  56. package/dist/{workspaces-AGOLRBYZ.js → workspaces-EYNZDL45.js} +4 -4
  57. package/dist/{worktree-C5VI46RZ.js → worktree-BP5ICYQ2.js} +3 -3
  58. package/dist/{worktree-FMK57ULT.js → worktree-UCOSAI7J.js} +3 -3
  59. package/package.json +1 -1
@@ -12,13 +12,13 @@ import {
12
12
  } from "./chunk-7Q327QF2.js";
13
13
  import {
14
14
  isOrchestratorThread
15
- } from "./chunk-5QX2NYXL.js";
15
+ } from "./chunk-GFM63DTU.js";
16
16
  import {
17
17
  codexUnattendedGitConfigArgs,
18
18
  mergeAgentGitAuthEnv,
19
19
  resolveAgentGitAuthEnv,
20
20
  resolveCodexGitWritableRoots
21
- } from "./chunk-BIPXOHZI.js";
21
+ } from "./chunk-BPBDGJ43.js";
22
22
  import {
23
23
  loadBrightsyConfig
24
24
  } from "./chunk-RSA47QYR.js";
@@ -53,6 +53,7 @@ import {
53
53
  looksLikeBrightsyEmptyCompletion
54
54
  } from "./chunk-5XNT6BCG.js";
55
55
  import {
56
+ githubAgentAuthReady,
56
57
  run
57
58
  } from "./chunk-QVN2WOKJ.js";
58
59
  import {
@@ -75,7 +76,7 @@ import {
75
76
  loadAppSettings,
76
77
  resolveAgentExecutable,
77
78
  resolveClaudeExecutable
78
- } from "./chunk-A2YXQC65.js";
79
+ } from "./chunk-U7PNCYNX.js";
79
80
  import {
80
81
  isElectronLikeCommand,
81
82
  unwrapStrippedElectronLaunch
@@ -514,6 +515,119 @@ var brightsyAdapter = {
514
515
  // src/agents/claude.ts
515
516
  import { existsSync as existsSync7 } from "fs";
516
517
 
518
+ // src/agents/claude-mcp-status.ts
519
+ var SIDEBOARD_CONNECTOR_SERVICES = [
520
+ "github",
521
+ "linear",
522
+ "posthog",
523
+ "vercel",
524
+ "supabase",
525
+ "sentry"
526
+ ];
527
+ function mcpStatusThinkingFromClaudeInit(obj) {
528
+ const raw = obj.mcp_servers ?? obj.mcpServers;
529
+ const servers = [];
530
+ if (Array.isArray(raw)) {
531
+ for (const item of raw) {
532
+ if (!item || typeof item !== "object" || Array.isArray(item)) continue;
533
+ const rec = item;
534
+ const name = typeof rec.name === "string" && rec.name.trim() || typeof rec.server === "string" && rec.server.trim() || "";
535
+ const status = typeof rec.status === "string" && rec.status.trim() || typeof rec.state === "string" && rec.state.trim() || "";
536
+ if (name) servers.push({ name, status: status || "unknown" });
537
+ }
538
+ } else if (raw && typeof raw === "object") {
539
+ for (const [name, value] of Object.entries(raw)) {
540
+ if (!name.trim()) continue;
541
+ if (typeof value === "string" && value.trim()) {
542
+ servers.push({ name, status: value.trim() });
543
+ continue;
544
+ }
545
+ if (value && typeof value === "object" && !Array.isArray(value)) {
546
+ const rec = value;
547
+ const status = typeof rec.status === "string" && rec.status.trim() || typeof rec.state === "string" && rec.state.trim() || "unknown";
548
+ servers.push({ name, status });
549
+ }
550
+ }
551
+ }
552
+ const coverage = claudeConnectorCoverage();
553
+ const sideboardOk = sideboardMcpOk(servers);
554
+ const notable = servers.filter(
555
+ (server) => isNotableMcpInitStatus(server, sideboardOk, coverage)
556
+ );
557
+ if (notable.length === 0) return null;
558
+ return `MCP: ${notable.map((s) => `${s.name} ${s.status}`).join(", ")}`;
559
+ }
560
+ function isCleanMcpConnect(status) {
561
+ return /^(connected|ok|ready|success)$/i.test(status.trim());
562
+ }
563
+ function isMcpAuthStatus(status) {
564
+ return /needs[_-]?auth|needs authentication|unauthorized|not authenticated|authrequired/i.test(
565
+ status
566
+ );
567
+ }
568
+ function isSideboardMcpName(name) {
569
+ return /^sideboard$/i.test(name.trim()) || /^mcp__sideboard$/i.test(name.trim());
570
+ }
571
+ function isVendorClaudeAiMcpName(name) {
572
+ return /^claude\.ai\b/i.test(name.trim()) || /^mcp__claude_ai_/i.test(name.trim());
573
+ }
574
+ function sideboardMcpOk(servers) {
575
+ const row = servers.find((server) => isSideboardMcpName(server.name));
576
+ return Boolean(row && isCleanMcpConnect(row.status));
577
+ }
578
+ function sideboardServiceForClaudeConnector(name) {
579
+ const raw = name.trim();
580
+ if (!raw || isSideboardMcpName(raw)) return null;
581
+ const pluginLike = /^(?:plugin[:_]|mcp__plugin_|claude\.ai\s|(?:mcp__)?claude_ai_)/i.test(raw);
582
+ const doubled = raw.match(/^mcp_([a-z0-9]+)_([a-z0-9]+)$/i);
583
+ if (!pluginLike && !(doubled && doubled[1].toLowerCase() === doubled[2].toLowerCase())) {
584
+ return null;
585
+ }
586
+ let body = raw;
587
+ if (/^claude\.ai\s+/i.test(body)) body = body.replace(/^claude\.ai\s+/i, "");
588
+ else if (/^(?:mcp__)?claude_ai_/i.test(body)) body = body.replace(/^(?:mcp__)?claude_ai_/i, "");
589
+ else if (/^mcp__plugin_/i.test(body)) body = body.slice("mcp__plugin_".length);
590
+ else if (/^plugin_/i.test(body)) body = body.slice("plugin_".length);
591
+ else if (/^plugin:/i.test(body)) body = body.slice("plugin:".length);
592
+ else if (/^mcp_/i.test(body)) body = body.slice("mcp_".length);
593
+ const head = body.toLowerCase().split(/[^a-z0-9]+/).filter(Boolean)[0];
594
+ if (!head || !SIDEBOARD_CONNECTOR_SERVICES.includes(head)) return null;
595
+ return head;
596
+ }
597
+ function claudeConnectorCoverage() {
598
+ let github = false;
599
+ try {
600
+ github = githubAgentAuthReady();
601
+ } catch {
602
+ github = false;
603
+ }
604
+ let linear = false;
605
+ let posthog = false;
606
+ let vercel = false;
607
+ let supabase = false;
608
+ let sentry = false;
609
+ try {
610
+ linear = isLinearConnected();
611
+ posthog = isPosthogConnected();
612
+ const integrations = loadAppSettings().integrations ?? {};
613
+ if (integrations.githubPat?.trim()) github = true;
614
+ vercel = Boolean(integrations.vercelToken?.trim());
615
+ supabase = Boolean(integrations.supabaseAccessToken?.trim());
616
+ sentry = Boolean(integrations.sentryAuthToken?.trim());
617
+ } catch {
618
+ }
619
+ return { github, linear, posthog, vercel, supabase, sentry };
620
+ }
621
+ function isNotableMcpInitStatus(server, sideboardOk, coverage) {
622
+ if (isCleanMcpConnect(server.status)) return false;
623
+ if (isSideboardMcpName(server.name)) return true;
624
+ if (isMcpAuthStatus(server.status)) return false;
625
+ const service = sideboardServiceForClaudeConnector(server.name);
626
+ if (service) return !(sideboardOk && coverage[service]);
627
+ if (isVendorClaudeAiMcpName(server.name)) return false;
628
+ return true;
629
+ }
630
+
517
631
  // src/mcp-ui/host.ts
518
632
  import { createHash } from "crypto";
519
633
  import { homedir as homedir4 } from "os";
@@ -2326,56 +2440,6 @@ function claudeString(obj, key) {
2326
2440
  const v = obj[key];
2327
2441
  return typeof v === "string" && v.trim() ? v.trim() : void 0;
2328
2442
  }
2329
- function mcpStatusThinkingFromClaudeInit(obj) {
2330
- const raw = obj.mcp_servers ?? obj.mcpServers;
2331
- const servers = [];
2332
- if (Array.isArray(raw)) {
2333
- for (const item of raw) {
2334
- if (!item || typeof item !== "object" || Array.isArray(item)) continue;
2335
- const rec = item;
2336
- const name = typeof rec.name === "string" && rec.name.trim() || typeof rec.server === "string" && rec.server.trim() || "";
2337
- const status = typeof rec.status === "string" && rec.status.trim() || typeof rec.state === "string" && rec.state.trim() || "";
2338
- if (name) servers.push({ name, status: status || "unknown" });
2339
- }
2340
- } else if (raw && typeof raw === "object") {
2341
- for (const [name, value] of Object.entries(raw)) {
2342
- if (!name.trim()) continue;
2343
- if (typeof value === "string" && value.trim()) {
2344
- servers.push({ name, status: value.trim() });
2345
- continue;
2346
- }
2347
- if (value && typeof value === "object" && !Array.isArray(value)) {
2348
- const rec = value;
2349
- const status = typeof rec.status === "string" && rec.status.trim() || typeof rec.state === "string" && rec.state.trim() || "unknown";
2350
- servers.push({ name, status });
2351
- }
2352
- }
2353
- }
2354
- const notable = servers.filter(isNotableMcpInitStatus);
2355
- if (notable.length === 0) return null;
2356
- return `MCP: ${notable.map((s) => `${s.name} ${s.status}`).join(", ")}`;
2357
- }
2358
- function isCleanMcpConnect(status) {
2359
- return /^(connected|ok|ready|success)$/i.test(status.trim());
2360
- }
2361
- function isMcpAuthStatus(status) {
2362
- return /needs[_-]?auth|needs authentication|unauthorized|not authenticated|authrequired/i.test(
2363
- status
2364
- );
2365
- }
2366
- function isSideboardMcpName(name) {
2367
- return /^sideboard$/i.test(name.trim()) || /^mcp__sideboard$/i.test(name.trim());
2368
- }
2369
- function isVendorClaudeAiMcpName(name) {
2370
- return /^claude\.ai\b/i.test(name.trim()) || /^mcp__claude_ai_/i.test(name.trim());
2371
- }
2372
- function isNotableMcpInitStatus(server) {
2373
- if (isCleanMcpConnect(server.status)) return false;
2374
- if (isSideboardMcpName(server.name)) return true;
2375
- if (isVendorClaudeAiMcpName(server.name)) return false;
2376
- if (isMcpAuthStatus(server.status)) return false;
2377
- return true;
2378
- }
2379
2443
  function eventsFromClaudeSystem(obj) {
2380
2444
  const subtype = claudeString(obj, "subtype") ?? "";
2381
2445
  const parentId = claudeParentToolUseId(obj);
@@ -2545,7 +2609,7 @@ var claudeAdapter = {
2545
2609
  );
2546
2610
  }
2547
2611
  const mode = permissionMode(thread);
2548
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-BZAVBOH3.js");
2612
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-3NNDDTFD.js");
2549
2613
  const isOrchestrator = isOrchestratorThread2(thread);
2550
2614
  const rpc = worktreeAgentRpc(isOrchestrator);
2551
2615
  const injectedServers = await buildInjectedMcpServers({
@@ -4472,6 +4536,7 @@ export {
4472
4536
  adjustBrightsyTurnExit,
4473
4537
  listBrightsyChatTargets,
4474
4538
  brightsyAdapter,
4539
+ mcpStatusThinkingFromClaudeInit,
4475
4540
  mcpUiContentSecurityPolicy,
4476
4541
  SIDEBOARD_MCP_PROFILE_ENV,
4477
4542
  SIDEBOARD_THREAD_ID_ENV,
@@ -4502,7 +4567,6 @@ export {
4502
4567
  PLAN_MODE_OFF_INSTRUCTION,
4503
4568
  planModeTurnInstruction,
4504
4569
  permissionMode,
4505
- mcpStatusThinkingFromClaudeInit,
4506
4570
  claudeAdapter,
4507
4571
  listCodexModels,
4508
4572
  codexAdapter,
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-QVN2WOKJ.js";
8
8
  import {
9
9
  resolveAgentExecutable
10
- } from "./chunk-A2YXQC65.js";
10
+ } from "./chunk-U7PNCYNX.js";
11
11
 
12
12
  // src/agents/install.ts
13
13
  import { existsSync } from "fs";
@@ -265,7 +265,7 @@ async function loginAgent(agent) {
265
265
  };
266
266
  }
267
267
  async function loginManagedAccount(accountId) {
268
- const { loadAppSettings } = await import("./app-settings-DZ5AY7N5.js");
268
+ const { loadAppSettings } = await import("./app-settings-RQAFJZCD.js");
269
269
  const { loginEnvPrefix } = await import("./managed-accounts-JJTAKHMG.js");
270
270
  const account = loadAppSettings().accounts.accounts.find((a) => a.id === accountId);
271
271
  if (!account) {
@@ -4,14 +4,14 @@ import {
4
4
  normalizeAbleTimeCredential,
5
5
  normalizeAbleTimeHost,
6
6
  rewriteAbleTimeError
7
- } from "./chunk-JWW66PO3.js";
7
+ } from "./chunk-DV6ID6CK.js";
8
8
  import {
9
9
  httpFetch
10
10
  } from "./chunk-JAT3JFOS.js";
11
11
  import {
12
12
  getAbleTimeAccessToken,
13
13
  getAbleTimeHost
14
- } from "./chunk-A2YXQC65.js";
14
+ } from "./chunk-U7PNCYNX.js";
15
15
 
16
16
  // src/integrations/abletime-rest.ts
17
17
  var ABLETIME_REST_PREFIX = "/api/public/v2";
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  loadAppSettings,
6
6
  saveAppSettings
7
- } from "./chunk-A2YXQC65.js";
7
+ } from "./chunk-U7PNCYNX.js";
8
8
 
9
9
  // src/integrations/optional-services.ts
10
10
  var OPTIONAL_SERVICE_IDS = ["vercel", "supabase", "posthog", "sentry"];
@@ -239,7 +239,7 @@ function connectorAuthCaution(posthog, cliConnected) {
239
239
  const signIn = posthog ? "If a connector MCP is listed but needsAuth or returns unauthorized, do not sign in to that MCP." : "If a Vercel, Supabase, or Sentry MCP is listed but needsAuth or returns unauthorized, do not sign in to that MCP.";
240
240
  const token = cliConnected ? " CLI tokens are already in this process." : "";
241
241
  const key = posthog ? " Do not read a PostHog key from the environment." : "";
242
- return `${signIn}${token}${key}`;
242
+ return `${signIn}${token}${key} When this Sideboard connection works, ignore a Claude connector that failed to start. Use the Claude connector only when this connection is not set or the CLI call fails.`;
243
243
  }
244
244
  function connectorReminderBit(spec, cli) {
245
245
  if (!spec.cli) return `${spec.label}: \`posthog_api\``;
@@ -266,14 +266,14 @@ function formatOptionalServicesReminder(integrations, cli) {
266
266
  const bits = connected.map((spec) => connectorReminderBit(spec, cli)).join(". ");
267
267
  const tokenBit = connected.some((spec) => spec.cli) ? "CLI tokens are already in this process. " : "";
268
268
  const posthog = connected.some((spec) => spec.id === "posthog");
269
- const auth = posthog ? "If a connector MCP needsAuth or is unauthorized, ignore it and use the CLI or `posthog_api`. Do not read a PostHog key from the environment." : "If a Vercel, Supabase, or Sentry MCP needsAuth or is unauthorized, ignore it and use the CLI.";
269
+ const auth = posthog ? "If a connector MCP needsAuth or is unauthorized, ignore it and use the CLI or `posthog_api` while this Sideboard connection works. Use the Claude connector only when it is not set or the call fails. Do not read a PostHog key from the environment." : "If a Vercel, Supabase, or Sentry MCP needsAuth or is unauthorized, ignore it and use the CLI while this Sideboard connection works. Use the Claude connector only when it is not set or the CLI call fails.";
270
270
  return `Settings \u2192 Connectors: ${tokenBit}${bits}. ${auth} Do not add vendor MCPs. Shell dumps from those CLIs go in \`.context/cli/\` \u2014 read a slice.`;
271
271
  }
272
272
  async function connectedCliPresence(integrations) {
273
273
  const ids = connectedOptionalServices(integrations).filter((spec) => spec.cli).map((spec) => spec.id);
274
274
  if (ids.length === 0) return void 0;
275
275
  try {
276
- const { optionalCliPresence } = await import("./optional-cli-QY6V5S5N.js");
276
+ const { optionalCliPresence } = await import("./optional-cli-LMSRZNH4.js");
277
277
  return await optionalCliPresence(ids);
278
278
  } catch {
279
279
  return void 0;
@@ -5,7 +5,7 @@ import {
5
5
  ensureGhPreferOrigin,
6
6
  resolveGithubRepoSlug,
7
7
  resolveRepoRoot
8
- } from "./chunk-DLGGLV2M.js";
8
+ } from "./chunk-5CTG5W7S.js";
9
9
  import {
10
10
  ATTACHMENTS_DIR,
11
11
  attachmentsGitignoreBody
@@ -22,7 +22,7 @@ import {
22
22
  resolveThreadDefaults,
23
23
  resolveViewerProfile,
24
24
  resolveViewerProfileForRepo
25
- } from "./chunk-PHMFAU35.js";
25
+ } from "./chunk-GCHSJCCX.js";
26
26
  import {
27
27
  allocateTeamName,
28
28
  createEmptyThread,
@@ -31,7 +31,7 @@ import {
31
31
  teamSlugFromName,
32
32
  updateThread,
33
33
  writeThread
34
- } from "./chunk-3UDRWMIM.js";
34
+ } from "./chunk-U35AHE2P.js";
35
35
  import {
36
36
  appDataDir,
37
37
  globalAgentCwd,
@@ -341,12 +341,12 @@ var COORDINATOR_TOOL_PLAYBOOK = [
341
341
  "- list_projects \u2014 registered repos (path + github slug + project context when set). Use account / project context to pick the right repo for tickets or reviews.",
342
342
  "- list_board \u2014 Home Kanban of workspaces (New / Draft / Review / Approved / Merged; one card per checkout). Sibling chats on a card are separate agents, not one agent. Path to merge: no PR \u2192 draft PR \u2192 open PR \u2192 approved \u2192 merged. Archive removes the card to Settings \u2192 History (list_archive to browse, restore_workspace to bring it back). Queued/running are activity on the card, not columns. Orchestration chats are not on the board. Filters: query, repoPath, kind, column, limit.",
343
343
  `- list_branches / list_prs / list_issues \u2014 pass repoPath from list_projects. Review is PRs (the surface for assigned ticket work), not the tickets: "Get me N tickets to review" \u2192 list_prs(queue=review, limit=N) then create_workspace sourceType=pr. That is open non-draft PRs labeled with this project's ready-for-review GitHub label (Settings \u2192 Projects; default eng-review) with no individual user reviewer yet. A team request (engineering-team) is not a claim \u2014 the viewer is on that team and can pick it up; claimed means an individual account is the reviewer. Bots ignored. Use Settings \u2192 Agents / Projects context (roles, teams, labels \u2014 freeform text; project adds to account) to prefer the right queues. queue=mine is review-requested:@me; queue=approved|changes uses those labels. Also: state, label, reviewer=me|unassigned|login, query, limit default 40 max 250; raise limit or tighten when truncated. list_issues (query, assignee=me|unassigned|all|user, limit default 40 max 250) lists Linear, AbleTime, or GitHub tickets \u2014 do not use it for that review-inbox ask. When they ask for tickets to work on, follow their context (assignee=me or unassigned as it says).`,
344
- "- Find work: when they ask to find work, pick up tickets, or list reviews, use Settings \u2192 Agents (account) plus Settings \u2192 Projects (per-repo) context. Tickets \u2192 Sideboard list_issues / linear_* (Account Linear). Reviews \u2192 list_prs(queue=review). Do not call Claude Linear MCP or any other vendor Linear MCP \u2014 those HTTP connectors hang or flap on the first turn. If a vendor MCP is down or reconnecting, ignore it and keep going with Sideboard tools. Show the options \u2014 do not create_workspace or start unless they also asked to start (e.g. \u201Cfind me work and start it\u201D). Do not start this unprompted. To change that context, show the proposed text, ask_user (Save this context / Do not save), wait, then update_viewer_context with confirmed=true. Never write it without confirmation.",
344
+ "- Find work: when they ask to find work, pick up tickets, or list reviews, use Settings \u2192 Agents (account) plus Settings \u2192 Projects (per-repo) context. Tickets \u2192 Sideboard list_issues / linear_* (Account Linear). Reviews \u2192 list_prs(queue=review). Do not call Claude Linear MCP or any other vendor Linear MCP \u2014 those HTTP connectors hang or flap on the first turn. If a vendor MCP is down or reconnecting, ignore it and keep going with Sideboard tools. A failed Claude connector is not a Sideboard outage \u2014 do not mention it when the Account connection works. Show the options \u2014 do not create_workspace or start unless they also asked to start (e.g. \u201Cfind me work and start it\u201D). Do not start this unprompted. To change that context, show the proposed text, ask_user (Save this context / Do not save), wait, then update_viewer_context with confirmed=true. Never write it without confirmation.",
345
345
  "- Ticket updates: list_issues / linear_search_issues / github_search_issues with updatedSince (yesterday, 2d, or ISO). One call returns new assignments, ticket edits, and new comments \u2014 do not get_issue every ticket just to check for comments. kind=created vs updated distinguishes new tickets from existing ones.",
346
- "- linear_* (when Linear is connected) \u2014 list_teams for team key/states; linear_list_projects for project names; get/search include the project a ticket is on; get/create/update/comment with ENG-123. Worktree agents have the same Account tools \u2014 prefer they comment, update status, and create spin-offs (parent=) on their own ticket when they were asked to do the work. When reviewing a PR or ticket, do not comment or update until the user types a next step \u2014 they should work through the feedback in chat first. Do not tell the child to ask_user after the review. Scope errors: reconnect Linear in Account settings. Prefer these over any Linear MCP the CLI may still list.",
347
- "- github_* \u2014 get/comment/update/create GitHub issues via Account `gh` (#123). github_list_projects and get/search include GitHub Projects. projectsError or a missing read:project scope \u2192 `gh auth refresh -s read:project`. Worktree agents have these too. Prefer over any vendor GitHub MCP. Pass parent= for spin-offs. When reviewing a PR or ticket, do not comment, submit `gh pr review`, or update the PR/ticket until the user types a next step.",
346
+ "- linear_* (when Linear is connected) \u2014 list_teams for team key/states; linear_list_projects for project names; get/search include the project a ticket is on; get/create/update/comment with ENG-123. Worktree agents have the same Account tools \u2014 prefer they comment, update status, and create spin-offs (parent=) on their own ticket when they were asked to do the work. When reviewing a PR or ticket, do not comment or update until the user types a next step \u2014 they should work through the feedback in chat first. Do not tell the child to ask_user after the review. Scope errors: reconnect Linear in Account settings. Prefer these over any Linear MCP the CLI may still list. Worktree agents use the Claude Linear connector only when Account Linear is not set or the Sideboard call fails, and they do not mention that connector startup failure when Sideboard works.",
347
+ "- github_* \u2014 get/comment/update/create GitHub issues via Account `gh` (#123). github_list_projects and get/search include GitHub Projects. projectsError or a missing read:project scope \u2192 `gh auth refresh -s read:project`. Worktree agents have these too. Prefer Sideboard `github_*` while Account `gh` works. A failed Claude GitHub connector (`mcp_github_github`) is not a Sideboard outage \u2014 do not mention it. Use that connector only when `gh` is not set up or the Sideboard call fails. Pass parent= for spin-offs. When reviewing a PR or ticket, do not comment, submit `gh pr review`, or update the PR/ticket until the user types a next step.",
348
348
  "- abletime_* (when AbleTime is connected) \u2014 orientation first; abletime_list_projects lists projects; get/list include the project a task is on; get/comment/update/create (parent= for spin-offs); ensure_task when work has no ticket (or create_workspace from the default branch auto-creates one). Worktree agents have the same Account tools. Same review-write gate as Linear/GitHub.",
349
- "- Optional connectors (Vercel, Supabase, Sentry) in Settings \u2192 Connectors inject tokens into worktree agent env when connected. Prefer official CLIs (`vercel`, `supabase`, `sentry-cli`). When Settings \u2192 Connectors has a PostHog personal API key, PostHog is the Sideboard tool `posthog_api` (GET by default; POST `/api/projects/:id/query/` or `/api/environments/:id/query/` is a read and does not need write=true; other POST and PATCH need write=true only when the user asked to change data). The PostHog key stays in the vault \u2014 do not read it from the environment, and do not sign in to a PostHog MCP. When no PostHog API key is set, leave the Claude PostHog connector alone. If a Vercel, Supabase, or Sentry MCP needsAuth or is unauthorized, do not sign in \u2014 use the native CLI. Tell any worktree agent (Claude / Cursor / Codex / OpenCode) to write CLI output to `.context/cli/` and read a slice. If a CLI is missing, the user presses Install CLI on that row. Do not add vendor MCPs. Git (`gh`) stays Settings \u2192 Git; issue tracking stays Settings \u2192 Issues. The phone remote is Settings \u2192 Remote \u2014 do not look up Slack users.",
349
+ "- Optional connectors (Vercel, Supabase, Sentry) in Settings \u2192 Connectors inject tokens into worktree agent env when connected. Prefer official CLIs (`vercel`, `supabase`, `sentry-cli`). When Settings \u2192 Connectors has a PostHog personal API key, PostHog is the Sideboard tool `posthog_api` (GET by default; POST `/api/projects/:id/query/` or `/api/environments/:id/query/` is a read and does not need write=true; other POST and PATCH need write=true only when the user asked to change data). The PostHog key stays in the vault \u2014 do not read it from the environment, and do not sign in to a PostHog MCP. When no PostHog API key is set, use the Claude PostHog connector. When a key is set, ignore a failed Claude PostHog connector and do not sign in to a PostHog MCP. If a Vercel, Supabase, or Sentry MCP needsAuth or is unauthorized while that Sideboard token is set, do not sign in \u2014 use the native CLI. When that token is not set or the CLI call fails, the Claude connector is the fallback. Do not mention a Claude connector startup failure when the Sideboard connection works. Tell any worktree agent (Claude / Cursor / Codex / OpenCode) to write CLI output to `.context/cli/` and read a slice. If a CLI is missing, the user presses Install CLI on that row. Do not add vendor MCPs. Git (`gh`) stays Settings \u2192 Git; issue tracking stays Settings \u2192 Issues. The phone remote is Settings \u2192 Remote \u2014 do not look up Slack users.",
350
350
  "- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
351
351
  "- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
352
352
  "- list_chats / get_chat \u2014 live thread list (parent id + last message preview). get_chat on this orchestration chat lists child worktree agents (status + lastText). blockedReason is why that agent is waiting on a person. Also includes usage / lastTurnUsage. Archived workspaces and agents are list_archive, not this list.",
@@ -618,7 +618,8 @@ function createGlobalChat(opts) {
618
618
  agent: opts.agent,
619
619
  model: opts.model,
620
620
  effort: opts.effort,
621
- fast: opts.fast
621
+ fast: opts.fast,
622
+ autonomy: opts.autonomy
622
623
  });
623
624
  const agent = assertOrchestratorCapableAgent(resolved.agent);
624
625
  const worktreePath = globalAgentCwd();
@@ -632,7 +633,7 @@ function createGlobalChat(opts) {
632
633
  worktreePath,
633
634
  repoPath: GLOBAL_WORKSPACE_ID,
634
635
  agent,
635
- autonomy: opts.autonomy ?? "default",
636
+ autonomy: resolved.autonomy,
636
637
  model: resolved.model,
637
638
  effort: resolved.effort,
638
639
  fast: resolved.fast,
@@ -709,6 +710,7 @@ function ensureSlackCoordinator(teamId, userId, agent, opts) {
709
710
  if (existing.model !== defaults.model) patch.model = defaults.model;
710
711
  if (existing.effort !== defaults.effort) patch.effort = defaults.effort;
711
712
  if (existing.fast !== defaults.fast) patch.fast = defaults.fast;
713
+ if (existing.autonomy !== defaults.autonomy) patch.autonomy = defaults.autonomy;
712
714
  }
713
715
  if (Object.keys(patch).length > 0) {
714
716
  return updateThread(existing.id, patch);
@@ -767,6 +769,7 @@ function ensureCloudCoordinator(agent) {
767
769
  if (existing.model !== defaults.model) patch.model = defaults.model;
768
770
  if (existing.effort !== defaults.effort) patch.effort = defaults.effort;
769
771
  if (existing.fast !== defaults.fast) patch.fast = defaults.fast;
772
+ if (existing.autonomy !== defaults.autonomy) patch.autonomy = defaults.autonomy;
770
773
  }
771
774
  if (Object.keys(patch).length > 0) {
772
775
  return updateThread(existing.id, patch);
@@ -2,11 +2,11 @@ import {
2
2
  OPTIONAL_SERVICES,
3
3
  isOptionalServiceId,
4
4
  optionalServiceSpec
5
- } from "./chunk-WRZRX4Q7.js";
5
+ } from "./chunk-OLYNM52B.js";
6
6
  import {
7
7
  installNpmGlobalPackage,
8
8
  whichOnPath
9
- } from "./chunk-U4WACWBC.js";
9
+ } from "./chunk-NXNNYY3Q.js";
10
10
  import {
11
11
  enrichPathWithNpmGlobalBin
12
12
  } from "./chunk-QVN2WOKJ.js";
@@ -1029,6 +1029,19 @@ function normalizeRunScriptRequest(raw) {
1029
1029
  error: req.error ?? null
1030
1030
  };
1031
1031
  }
1032
+ function sanitizeIssueBlockedBy(value) {
1033
+ if (!Array.isArray(value)) return void 0;
1034
+ const out = [];
1035
+ const seen = /* @__PURE__ */ new Set();
1036
+ for (const item of value) {
1037
+ const id = String(item ?? "").trim();
1038
+ const key = id.toLowerCase();
1039
+ if (!id || seen.has(key)) continue;
1040
+ seen.add(key);
1041
+ out.push(id);
1042
+ }
1043
+ return out;
1044
+ }
1032
1045
  function normalizeThread(raw) {
1033
1046
  return {
1034
1047
  ...raw,
@@ -1053,6 +1066,7 @@ function normalizeThread(raw) {
1053
1066
  prIsInMergeQueue: Boolean(raw.prIsInMergeQueue),
1054
1067
  prLabels: Array.isArray(raw.prLabels) ? raw.prLabels : [],
1055
1068
  prChecksFailed: typeof raw.prChecksFailed === "boolean" ? raw.prChecksFailed : void 0,
1069
+ issueBlockedBy: sanitizeIssueBlockedBy(raw.issueBlockedBy),
1056
1070
  skipAutoArchiveOnMerge: Boolean(raw.skipAutoArchiveOnMerge),
1057
1071
  cowboy: Boolean(raw.cowboy),
1058
1072
  stackId: raw.stackId ?? null,
@@ -53,6 +53,73 @@ function coerceOrchestratorAgent(agent, fallback = "claude") {
53
53
  return isOrchestratorCapableAgent(agent) ? agent : fallback;
54
54
  }
55
55
 
56
+ // src/store/thread-option-defaults.ts
57
+ function normalizeAutonomy(value) {
58
+ return value === "default" || value === "full" ? value : void 0;
59
+ }
60
+ function getDefaultAgent(settings = loadAppSettings()) {
61
+ return settings.defaults.agent ?? "claude";
62
+ }
63
+ function getDefaultModel(settings = loadAppSettings()) {
64
+ const model = settings.defaults.model?.trim();
65
+ return model || null;
66
+ }
67
+ function getDefaultEffort(settings = loadAppSettings()) {
68
+ return normalizeThinkingEffort(settings.defaults.effort) ?? "high";
69
+ }
70
+ function getDefaultFast(settings = loadAppSettings()) {
71
+ return settings.defaults.fast === true;
72
+ }
73
+ function getDefaultAutonomy(settings = loadAppSettings()) {
74
+ return settings.defaults.autonomy === "default" ? "default" : "full";
75
+ }
76
+ function resolveThreadDefaults(settings = loadAppSettings()) {
77
+ return {
78
+ agent: getDefaultAgent(settings),
79
+ model: getDefaultModel(settings),
80
+ effort: getDefaultEffort(settings),
81
+ fast: getDefaultFast(settings),
82
+ autonomy: getDefaultAutonomy(settings)
83
+ };
84
+ }
85
+ function resolveOrchestratorDefaults(settings = loadAppSettings()) {
86
+ const account = resolveThreadDefaults(settings);
87
+ const orch = settings.defaults.orchestrator;
88
+ const agent = coerceOrchestratorAgent(orch?.agent ?? account.agent);
89
+ let model = orch ? orch.model?.trim() || null : account.model;
90
+ if (model && agent !== "cursor" && /^(default|auto)$/i.test(model.trim())) {
91
+ model = null;
92
+ }
93
+ return {
94
+ agent,
95
+ model,
96
+ effort: orch?.effort ?? account.effort,
97
+ fast: orch?.fast ?? account.fast,
98
+ autonomy: orch?.autonomy ?? account.autonomy
99
+ };
100
+ }
101
+ function mergeThreadOptionOverrides(defaults, overrides) {
102
+ const effort = overrides.effort === void 0 || overrides.effort === null ? defaults.effort : normalizeThinkingEffort(overrides.effort) ?? defaults.effort;
103
+ const agent = overrides.agent ?? defaults.agent;
104
+ let model = overrides.model === void 0 ? defaults.model : overrides.model?.trim() || null;
105
+ if (model && agent !== "cursor" && /^(default|auto)$/i.test(model.trim())) {
106
+ model = null;
107
+ }
108
+ return {
109
+ agent,
110
+ model,
111
+ effort,
112
+ fast: overrides.fast === void 0 || overrides.fast === null ? defaults.fast : Boolean(overrides.fast),
113
+ autonomy: overrides.autonomy == null ? defaults.autonomy : normalizeAutonomy(overrides.autonomy) ?? defaults.autonomy
114
+ };
115
+ }
116
+ function resolveNewThreadOptions(overrides = {}, settings = loadAppSettings()) {
117
+ return mergeThreadOptionOverrides(resolveThreadDefaults(settings), overrides);
118
+ }
119
+ function resolveNewOrchestratorOptions(overrides = {}, settings = loadAppSettings()) {
120
+ return mergeThreadOptionOverrides(resolveOrchestratorDefaults(settings), overrides);
121
+ }
122
+
56
123
  // src/store/account-profile.ts
57
124
  var PROFILE_NOTES_MAX = 2e3;
58
125
  var LEGACY_ROLE_LABELS = {
@@ -1239,6 +1306,8 @@ function normalizeOrchestratorDefaults(raw) {
1239
1306
  if (typeof source.fast === "boolean") {
1240
1307
  out.fast = source.fast;
1241
1308
  }
1309
+ const autonomy = normalizeAutonomy(source.autonomy);
1310
+ if (autonomy) out.autonomy = autonomy;
1242
1311
  return Object.keys(out).length > 0 ? out : void 0;
1243
1312
  }
1244
1313
  function normalizeDefaults(raw) {
@@ -1258,6 +1327,8 @@ function normalizeDefaults(raw) {
1258
1327
  if (typeof source.fast === "boolean") {
1259
1328
  out.fast = source.fast;
1260
1329
  }
1330
+ const autonomy = normalizeAutonomy(source.autonomy);
1331
+ if (autonomy) out.autonomy = autonomy;
1261
1332
  const notes = foldLegacyRolesIntoNotes(source.roles, source.role, source.notes);
1262
1333
  if (notes) out.notes = notes;
1263
1334
  const orchestrator = normalizeOrchestratorDefaults(source.orchestrator);
@@ -1923,6 +1994,14 @@ function applyOrchestratorDefaultsPatch(current, patch) {
1923
1994
  next.fast = Boolean(patch.fast);
1924
1995
  }
1925
1996
  }
1997
+ if ("autonomy" in patch) {
1998
+ if (patch.autonomy == null) {
1999
+ delete next.autonomy;
2000
+ } else {
2001
+ const autonomy = normalizeAutonomy(patch.autonomy);
2002
+ if (autonomy) next.autonomy = autonomy;
2003
+ }
2004
+ }
1926
2005
  return Object.keys(next).length > 0 ? next : void 0;
1927
2006
  }
1928
2007
  function updateDefaultsSettings(patch) {
@@ -1957,6 +2036,14 @@ function updateDefaultsSettings(patch) {
1957
2036
  defaults.fast = Boolean(patch.fast);
1958
2037
  }
1959
2038
  }
2039
+ if ("autonomy" in patch) {
2040
+ if (patch.autonomy == null) {
2041
+ delete defaults.autonomy;
2042
+ } else {
2043
+ const autonomy = normalizeAutonomy(patch.autonomy);
2044
+ if (autonomy) defaults.autonomy = autonomy;
2045
+ }
2046
+ }
1960
2047
  if ("notes" in patch) {
1961
2048
  const notes = normalizeProfileNotes(patch.notes);
1962
2049
  if (!notes) delete defaults.notes;
@@ -2006,19 +2093,6 @@ function resolveProjectReviewLabel(settings, repoPath) {
2006
2093
  if (!key) return "";
2007
2094
  return settings.projects[key]?.reviewLabel?.trim() || "";
2008
2095
  }
2009
- function getDefaultAgent(settings = loadAppSettings()) {
2010
- return settings.defaults.agent ?? "claude";
2011
- }
2012
- function getDefaultModel(settings = loadAppSettings()) {
2013
- const model = settings.defaults.model?.trim();
2014
- return model || null;
2015
- }
2016
- function getDefaultEffort(settings = loadAppSettings()) {
2017
- return normalizeThinkingEffort(settings.defaults.effort) ?? "high";
2018
- }
2019
- function getDefaultFast(settings = loadAppSettings()) {
2020
- return settings.defaults.fast === true;
2021
- }
2022
2096
  function resolveAccountProfileFromSettings(settings = loadAppSettings()) {
2023
2097
  return resolveViewerProfile(settings.defaults);
2024
2098
  }
@@ -2083,49 +2157,6 @@ function writeViewerContext(input) {
2083
2157
  updateDefaultsSettings({ notes: proposed || null });
2084
2158
  return { ok: true, scope: "account", context: proposed };
2085
2159
  }
2086
- function resolveThreadDefaults(settings = loadAppSettings()) {
2087
- return {
2088
- agent: getDefaultAgent(settings),
2089
- model: getDefaultModel(settings),
2090
- effort: getDefaultEffort(settings),
2091
- fast: getDefaultFast(settings)
2092
- };
2093
- }
2094
- function resolveOrchestratorDefaults(settings = loadAppSettings()) {
2095
- const account = resolveThreadDefaults(settings);
2096
- const orch = settings.defaults.orchestrator;
2097
- const agent = coerceOrchestratorAgent(orch?.agent ?? account.agent);
2098
- let model = orch ? orch.model?.trim() || null : account.model;
2099
- if (model && agent !== "cursor" && /^(default|auto)$/i.test(model.trim())) {
2100
- model = null;
2101
- }
2102
- return {
2103
- agent,
2104
- model,
2105
- effort: orch?.effort ?? account.effort,
2106
- fast: orch?.fast ?? account.fast
2107
- };
2108
- }
2109
- function mergeThreadOptionOverrides(defaults, overrides) {
2110
- const effort = overrides.effort === void 0 || overrides.effort === null ? defaults.effort : normalizeThinkingEffort(overrides.effort) ?? defaults.effort;
2111
- const agent = overrides.agent ?? defaults.agent;
2112
- let model = overrides.model === void 0 ? defaults.model : overrides.model?.trim() || null;
2113
- if (model && agent !== "cursor" && /^(default|auto)$/i.test(model.trim())) {
2114
- model = null;
2115
- }
2116
- return {
2117
- agent,
2118
- model,
2119
- effort,
2120
- fast: overrides.fast === void 0 || overrides.fast === null ? defaults.fast : Boolean(overrides.fast)
2121
- };
2122
- }
2123
- function resolveNewThreadOptions(overrides = {}, settings = loadAppSettings()) {
2124
- return mergeThreadOptionOverrides(resolveThreadDefaults(settings), overrides);
2125
- }
2126
- function resolveNewOrchestratorOptions(overrides = {}, settings = loadAppSettings()) {
2127
- return mergeThreadOptionOverrides(resolveOrchestratorDefaults(settings), overrides);
2128
- }
2129
2160
  function isLinearConnected(settings = loadAppSettings()) {
2130
2161
  return hasLinearCredentials(settings.integrations);
2131
2162
  }
@@ -2533,6 +2564,15 @@ export {
2533
2564
  isOrchestratorCapableAgent,
2534
2565
  assertOrchestratorCapableAgent,
2535
2566
  coerceOrchestratorAgent,
2567
+ getDefaultAgent,
2568
+ getDefaultModel,
2569
+ getDefaultEffort,
2570
+ getDefaultFast,
2571
+ getDefaultAutonomy,
2572
+ resolveThreadDefaults,
2573
+ resolveOrchestratorDefaults,
2574
+ resolveNewThreadOptions,
2575
+ resolveNewOrchestratorOptions,
2536
2576
  PROFILE_NOTES_MAX,
2537
2577
  foldLegacyRolesIntoNotes,
2538
2578
  resolveAccountProfile,
@@ -2625,18 +2665,10 @@ export {
2625
2665
  updateDefaultsSettings,
2626
2666
  updateProjectProfileSettings,
2627
2667
  resolveProjectReviewLabel,
2628
- getDefaultAgent,
2629
- getDefaultModel,
2630
- getDefaultEffort,
2631
- getDefaultFast,
2632
2668
  resolveAccountProfileFromSettings,
2633
2669
  resolveViewerProfileForRepo,
2634
2670
  readViewerContext,
2635
2671
  writeViewerContext,
2636
- resolveThreadDefaults,
2637
- resolveOrchestratorDefaults,
2638
- resolveNewThreadOptions,
2639
- resolveNewOrchestratorOptions,
2640
2672
  isLinearConnected,
2641
2673
  saveLinearOAuth,
2642
2674
  disconnectLinearConnection,