@sideboard-ai/core 0.1.286 → 0.1.288

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 (61) hide show
  1. package/dist/{abletime-I4RODUKT.js → abletime-4WJUVE64.js} +4 -4
  2. package/dist/{abletime-4CH2IOX5.js → abletime-VFKYNSJT.js} +4 -4
  3. package/dist/{abletime-oauth-7OZZ3ABX.js → abletime-oauth-FW24YHYX.js} +3 -3
  4. package/dist/{abletime-oauth-C2HN2Q6F.js → abletime-oauth-ICMB2XV2.js} +3 -3
  5. package/dist/{abletime-rest-E4LBRFLM.js → abletime-rest-HFMRTUDT.js} +3 -3
  6. package/dist/{abletime-rest-WFI2HWBU.js → abletime-rest-OGWC7BC6.js} +3 -3
  7. package/dist/agents/cursor-runner.js +3 -3
  8. package/dist/{agents-BHUXZ7XO.js → agents-GZLTMGSH.js} +19 -17
  9. package/dist/{agents-QNIFTZPN.js → agents-UQMHFZSM.js} +17 -15
  10. package/dist/{app-settings-EQQZQNYD.js → app-settings-EHMXHNG5.js} +1 -1
  11. package/dist/{app-settings-NI4X5HW3.js → app-settings-MR2U6AXN.js} +1 -1
  12. package/dist/{chunk-3H5U4QLD.js → chunk-2N77CLRQ.js} +8 -298
  13. package/dist/{chunk-YNTXWFXT.js → chunk-36J3IZBS.js} +12 -12
  14. package/dist/{chunk-IJMUYHPT.js → chunk-3E4NOIXN.js} +3 -3
  15. package/dist/{chunk-5MGLNVNK.js → chunk-3W5SL5EW.js} +1 -1
  16. package/dist/{chunk-CBIUGGPI.js → chunk-442O6OXM.js} +25 -127
  17. package/dist/chunk-4BXRRHDC.js +139 -0
  18. package/dist/{chunk-ETZPTOK7.js → chunk-4NM72HJZ.js} +5 -5
  19. package/dist/{chunk-PCNH74SF.js → chunk-6NVQNTJO.js} +10 -300
  20. package/dist/{chunk-VOIWX5HA.js → chunk-7UUILVMV.js} +1 -1
  21. package/dist/chunk-AF2DMY3K.js +295 -0
  22. package/dist/{chunk-5QOLFOAX.js → chunk-AFLNFGGB.js} +1 -1
  23. package/dist/{chunk-5T4YWFLD.js → chunk-AHH5USEA.js} +2 -2
  24. package/dist/{chunk-6CVVNAIU.js → chunk-B3BPLPKQ.js} +2 -2
  25. package/dist/{chunk-MGJ7R7UX.js → chunk-DBOFDEQ7.js} +4 -4
  26. package/dist/{chunk-VQEARG5H.js → chunk-GU6DT6NO.js} +5 -5
  27. package/dist/{chunk-K5XSTHHP.js → chunk-HNB2HTCV.js} +1 -1
  28. package/dist/{chunk-ULSY2BJF.js → chunk-IA4MPG7F.js} +4 -4
  29. package/dist/{chunk-S2OOM7AU.js → chunk-K6IOJI3L.js} +1 -1
  30. package/dist/{chunk-U6QDXT4K.js → chunk-MIVX7QKI.js} +1 -1
  31. package/dist/{chunk-WRIMAEF2.js → chunk-MVZO7QZ2.js} +12 -12
  32. package/dist/{chunk-LS4FFCPL.js → chunk-MYJYINTS.js} +3 -3
  33. package/dist/{chunk-DEJALWKM.js → chunk-NFPWLDCH.js} +5 -5
  34. package/dist/chunk-NXXQFLNQ.js +300 -0
  35. package/dist/chunk-OH4EN323.js +89 -0
  36. package/dist/chunk-W2KZTDET.js +302 -0
  37. package/dist/{chunk-ABOH7GBG.js → chunk-WQSIUZEB.js} +6 -6
  38. package/dist/{chunk-HJNFK5SP.js → chunk-WW5XGEMY.js} +33 -313
  39. package/dist/{chunk-TMM4FEZ5.js → chunk-Y67TBJD5.js} +3 -3
  40. package/dist/{chunk-XSDCLM3F.js → chunk-YSLCWCMJ.js} +1 -1
  41. package/dist/{conductor-RBJYEF7L.js → conductor-MCU63Z5U.js} +5 -5
  42. package/dist/{conductor-WYOWFB7I.js → conductor-ZLYZVIAV.js} +6 -6
  43. package/dist/{coordinator-prompt-R42WEL3T.js → coordinator-prompt-KHCXXDRO.js} +3 -3
  44. package/dist/{coordinator-prompt-5DE3XBNT.js → coordinator-prompt-UV6THLMD.js} +3 -3
  45. package/dist/{global-workspace-IPIEC6FM.js → global-workspace-AXTSYVAE.js} +3 -3
  46. package/dist/{global-workspace-NXMYLS34.js → global-workspace-GDHZSFP6.js} +3 -3
  47. package/dist/index.cjs +470 -275
  48. package/dist/index.d.cts +29 -9
  49. package/dist/index.d.ts +29 -9
  50. package/dist/index.js +369 -256
  51. package/dist/mcp/run-stdio.cjs +603 -226
  52. package/dist/mcp/run-stdio.js +333 -187
  53. package/dist/optional-cli-6SW4OOX3.js +23 -0
  54. package/dist/optional-cli-FRUZSZ3U.js +98 -0
  55. package/dist/{orchestrator-YEZV35G7.js → orchestrator-5ZBHR6BJ.js} +9 -7
  56. package/dist/{orchestrator-65QGA6BB.js → orchestrator-SDH6W6ZL.js} +12 -10
  57. package/dist/{workspaces-LIFFWK23.js → workspaces-L2UR4KC2.js} +3 -3
  58. package/dist/{workspaces-5C5ESWPU.js → workspaces-Q2R2XGO3.js} +3 -3
  59. package/dist/{worktree-NKLNVNXX.js → worktree-2GOK4VYT.js} +2 -2
  60. package/dist/{worktree-YTZC3UQN.js → worktree-YEUTJ7MZ.js} +2 -2
  61. package/package.json +1 -1
@@ -6,14 +6,14 @@ import {
6
6
  normalizeAbleTimeCredential,
7
7
  normalizeAbleTimeHost,
8
8
  rewriteAbleTimeError
9
- } from "./chunk-VQEARG5H.js";
9
+ } from "./chunk-GU6DT6NO.js";
10
10
  import {
11
11
  httpFetch
12
12
  } from "./chunk-2GPQZZLY.js";
13
13
  import {
14
14
  getAbleTimeAccessToken,
15
15
  getAbleTimeHost
16
- } from "./chunk-WRIMAEF2.js";
16
+ } from "./chunk-MVZO7QZ2.js";
17
17
 
18
18
  // src/integrations/abletime-rest.ts
19
19
  var ABLETIME_REST_PREFIX = "/api/public/v2";
@@ -4,14 +4,14 @@ import {
4
4
  normalizeAbleTimeCredential,
5
5
  normalizeAbleTimeHost,
6
6
  rewriteAbleTimeError
7
- } from "./chunk-DEJALWKM.js";
7
+ } from "./chunk-NFPWLDCH.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-YNTXWFXT.js";
14
+ } from "./chunk-36J3IZBS.js";
15
15
 
16
16
  // src/integrations/abletime-rest.ts
17
17
  var ABLETIME_REST_PREFIX = "/api/public/v2";
@@ -3,7 +3,7 @@ import {
3
3
  ensureGhPreferOrigin,
4
4
  resolveGithubRepoSlug,
5
5
  resolveRepoRoot
6
- } from "./chunk-K5XSTHHP.js";
6
+ } from "./chunk-HNB2HTCV.js";
7
7
  import {
8
8
  allocateTeamName,
9
9
  createEmptyThread,
@@ -29,7 +29,7 @@ import {
29
29
  resolveThreadDefaults,
30
30
  resolveViewerProfile,
31
31
  resolveViewerProfileForRepo
32
- } from "./chunk-YNTXWFXT.js";
32
+ } from "./chunk-36J3IZBS.js";
33
33
  import {
34
34
  appDataDir,
35
35
  globalAgentCwd,
@@ -391,7 +391,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
391
391
  "- 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.",
392
392
  "- 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.",
393
393
  "- 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.",
394
- "- Optional connectors (Vercel, Supabase, PostHog, Sentry) in Settings \u2192 Connectors inject tokens into worktree agent env when connected. Prefer official CLIs (`vercel`, `supabase`, `sentry-cli`) with those env vars. PostHog has no first-class CLI \u2014 use the HTTP API (`POSTHOG_PERSONAL_API_KEY`). If a connector MCP is listed but needsAuth or unauthorized, do not sign in \u2014 check that native CLI or HTTP API. Tell any worktree agent (Claude / Cursor / Codex / OpenCode) to write CLI output to `.context/cli/` (not `.context/attachments/`) and read a slice \u2014 never stream raw `--json` / `--expand` into a tool result (that crashes the turn). They can `stop_job` if a detached fetch hangs. If a CLI is missing, the user can Install CLI on that row (not auto-installed on Connect). Do not add vendor MCPs or ask the user to paste tokens again. 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.",
394
+ "- Optional connectors (Vercel, Supabase, Sentry) in Settings \u2192 Connectors inject tokens into worktree agent env when connected. Prefer official CLIs (`vercel`, `supabase`, `sentry-cli`). 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. If a connector MCP needsAuth or is unauthorized, do not sign in \u2014 use the native CLI or `posthog_api`. 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.",
395
395
  "- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
396
396
  "- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
397
397
  "- 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.",
@@ -913,7 +913,7 @@ function isRemovedWorkspace(repoPath) {
913
913
  }
914
914
  function archivesWithRemovedWorkspace(threadRepoPath, removedPath) {
915
915
  if (!threadRepoPath || isGlobalRepoPath(threadRepoPath)) return false;
916
- return isRemovedWorkspace(threadRepoPath) || sameWorkspacePath(threadRepoPath, removedPath);
916
+ return removedMatches(removedPath, threadRepoPath);
917
917
  }
918
918
  function rememberRemoved(repoPath) {
919
919
  const next = readRemoved();
@@ -6,7 +6,7 @@ import {
6
6
  import {
7
7
  getAbleTimeHost,
8
8
  isAbleTimeConnected
9
- } from "./chunk-WRIMAEF2.js";
9
+ } from "./chunk-MVZO7QZ2.js";
10
10
 
11
11
  // src/integrations/abletime-mcp.ts
12
12
  var DEFAULT_ABLETIME_HOST = "https://track.abletime.com";
@@ -155,7 +155,7 @@ function textsFromUnknown(value) {
155
155
  return "";
156
156
  }
157
157
  async function abletimeMcpRequest(method, params, opts) {
158
- const rawToken = opts?.token ?? await import("./abletime-oauth-7OZZ3ABX.js").then((m) => m.ensureAbleTimeAccessToken());
158
+ const rawToken = opts?.token ?? await import("./abletime-oauth-FW24YHYX.js").then((m) => m.ensureAbleTimeAccessToken());
159
159
  if (!rawToken?.trim()) {
160
160
  throw new Error("AbleTime is not connected \u2014 paste a personal access token in Account settings");
161
161
  }
@@ -226,9 +226,9 @@ async function callAbleTimeTool(name, args = {}, opts) {
226
226
  if (!opts?.token && !isAbleTimeConnected()) {
227
227
  throw new Error("AbleTime is not connected \u2014 paste a personal access token in Account settings");
228
228
  }
229
- const rawToken = opts?.token ?? await import("./abletime-oauth-7OZZ3ABX.js").then((m) => m.ensureAbleTimeAccessToken());
229
+ const rawToken = opts?.token ?? await import("./abletime-oauth-FW24YHYX.js").then((m) => m.ensureAbleTimeAccessToken());
230
230
  if (rawToken && ableTimeUsesRest(rawToken)) {
231
- const { callAbleTimeRestTool } = await import("./abletime-rest-WFI2HWBU.js");
231
+ const { callAbleTimeRestTool } = await import("./abletime-rest-OGWC7BC6.js");
232
232
  return callAbleTimeRestTool(name, args, { ...opts, token: rawToken });
233
233
  }
234
234
  const requestOpts = { ...opts, pm: opts?.pm ?? abletimeToolUsesPm(name) };
@@ -244,7 +244,7 @@ async function callAbleTimeTool(name, args = {}, opts) {
244
244
  return await call();
245
245
  }
246
246
  if (rawToken && ableTimeUsesRest(rawToken) && isAbleTimeRejectedCredential(message)) {
247
- const { callAbleTimeRestTool } = await import("./abletime-rest-WFI2HWBU.js");
247
+ const { callAbleTimeRestTool } = await import("./abletime-rest-OGWC7BC6.js");
248
248
  return callAbleTimeRestTool(name, args, { ...opts, token: rawToken });
249
249
  }
250
250
  throw err instanceof Error ? new Error(rewriteAbleTimeError(err.message)) : err;
@@ -24,7 +24,7 @@ import {
24
24
  import {
25
25
  getGithubGitAuthMode,
26
26
  getGithubPat
27
- } from "./chunk-YNTXWFXT.js";
27
+ } from "./chunk-36J3IZBS.js";
28
28
  import {
29
29
  worktreesRoot
30
30
  } from "./chunk-EHT2DRT4.js";
@@ -5,7 +5,7 @@ import {
5
5
  ensureGhPreferOrigin,
6
6
  resolveGithubRepoSlug,
7
7
  resolveRepoRoot
8
- } from "./chunk-5MGLNVNK.js";
8
+ } from "./chunk-3W5SL5EW.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-WRIMAEF2.js";
25
+ } from "./chunk-MVZO7QZ2.js";
26
26
  import {
27
27
  allocateTeamName,
28
28
  createEmptyThread,
@@ -346,7 +346,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
346
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
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.",
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, PostHog, Sentry) in Settings \u2192 Connectors inject tokens into worktree agent env when connected. Prefer official CLIs (`vercel`, `supabase`, `sentry-cli`) with those env vars. PostHog has no first-class CLI \u2014 use the HTTP API (`POSTHOG_PERSONAL_API_KEY`). If a connector MCP is listed but needsAuth or unauthorized, do not sign in \u2014 check that native CLI or HTTP API. Tell any worktree agent (Claude / Cursor / Codex / OpenCode) to write CLI output to `.context/cli/` (not `.context/attachments/`) and read a slice \u2014 never stream raw `--json` / `--expand` into a tool result (that crashes the turn). They can `stop_job` if a detached fetch hangs. If a CLI is missing, the user can Install CLI on that row (not auto-installed on Connect). Do not add vendor MCPs or ask the user to paste tokens again. 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`). 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. If a connector MCP needsAuth or is unauthorized, do not sign in \u2014 use the native CLI or `posthog_api`. 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.",
@@ -868,7 +868,7 @@ function isRemovedWorkspace(repoPath) {
868
868
  }
869
869
  function archivesWithRemovedWorkspace(threadRepoPath, removedPath) {
870
870
  if (!threadRepoPath || isGlobalRepoPath(threadRepoPath)) return false;
871
- return isRemovedWorkspace(threadRepoPath) || sameWorkspacePath(threadRepoPath, removedPath);
871
+ return removedMatches(removedPath, threadRepoPath);
872
872
  }
873
873
  function rememberRemoved(repoPath) {
874
874
  const next = readRemoved();
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  clipToolResultForStore,
3
3
  looksLikeHugeToolResultDump
4
- } from "./chunk-U6QDXT4K.js";
4
+ } from "./chunk-MIVX7QKI.js";
5
5
  import {
6
6
  CLI_DIR
7
7
  } from "./chunk-6K64FJDD.js";
@@ -269,7 +269,7 @@ function humanizeAgentFailDetail(detail) {
269
269
  return "Cursor local file search failed (ripgrep / resource_exhausted). Wait a minute and retry; if it keeps happening, check Cursor usage.";
270
270
  }
271
271
  if (looksLikeCodexMcpError(raw)) {
272
- return `${raw} \u2014 skip that vendor MCP and continue (PostHog: Settings \u2192 Connectors + HTTP API).`;
272
+ return `${raw} \u2014 skip that vendor MCP and continue (PostHog: Settings \u2192 Connectors and posthog_api).`;
273
273
  }
274
274
  if (/invalid user api key|invalid api key|not logged in|not authenticated|unauthorized|authentication|please run.*login|codex login|claude auth|cursor api/.test(
275
275
  lower
@@ -2211,22 +2211,21 @@ function applyAppEnvironment(target = process.env, settings = loadAppSettings())
2211
2211
  applyOptionalServiceTokens(target, settings.integrations);
2212
2212
  return target;
2213
2213
  }
2214
- function fillEnvGap(target, key, value) {
2214
+ function assignEnv(target, key, value) {
2215
2215
  const v = value?.trim();
2216
2216
  if (!key || !v) return;
2217
- if (target[key] == null || target[key] === "") target[key] = v;
2217
+ target[key] = v;
2218
+ }
2219
+ function scrubPosthogAgentEnv(target) {
2220
+ delete target.POSTHOG_PERSONAL_API_KEY;
2221
+ delete target.POSTHOG_HOST;
2218
2222
  }
2219
2223
  function applyOptionalServiceTokens(target, integrations) {
2220
- fillEnvGap(target, "VERCEL_TOKEN", integrations.vercelToken);
2221
- fillEnvGap(target, "SUPABASE_ACCESS_TOKEN", integrations.supabaseAccessToken);
2222
- fillEnvGap(target, "POSTHOG_PERSONAL_API_KEY", integrations.posthogPersonalApiKey);
2223
- fillEnvGap(
2224
- target,
2225
- "POSTHOG_HOST",
2226
- integrations.posthogPersonalApiKey ? integrations.posthogHost || "https://us.posthog.com" : void 0
2227
- );
2228
- fillEnvGap(target, "SENTRY_AUTH_TOKEN", integrations.sentryAuthToken);
2229
- fillEnvGap(
2224
+ assignEnv(target, "VERCEL_TOKEN", integrations.vercelToken);
2225
+ assignEnv(target, "SUPABASE_ACCESS_TOKEN", integrations.supabaseAccessToken);
2226
+ scrubPosthogAgentEnv(target);
2227
+ assignEnv(target, "SENTRY_AUTH_TOKEN", integrations.sentryAuthToken);
2228
+ assignEnv(
2230
2229
  target,
2231
2230
  "SENTRY_URL",
2232
2231
  integrations.sentryAuthToken ? integrations.sentryHost || "https://sentry.io" : void 0
@@ -2241,6 +2240,7 @@ function childEnvWithAppSettings(extra) {
2241
2240
  if (v != null) env[k] = v;
2242
2241
  }
2243
2242
  }
2243
+ scrubPosthogAgentEnv(env);
2244
2244
  return env;
2245
2245
  }
2246
2246
  function harnessEnvKey(harness) {
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  abletimeRestUrl,
3
3
  textFromAbleTimeDoc
4
- } from "./chunk-6CVVNAIU.js";
4
+ } from "./chunk-B3BPLPKQ.js";
5
5
  import {
6
6
  assertAbleTimeCredential,
7
7
  callAbleTimeTool,
8
8
  normalizeAbleTimeHost,
9
9
  rewriteAbleTimeError
10
- } from "./chunk-DEJALWKM.js";
10
+ } from "./chunk-NFPWLDCH.js";
11
11
  import {
12
12
  httpFetch
13
13
  } from "./chunk-JAT3JFOS.js";
@@ -20,7 +20,7 @@ import {
20
20
  getAbleTimeHost,
21
21
  isAbleTimeConnected,
22
22
  saveAbleTimeConnection
23
- } from "./chunk-YNTXWFXT.js";
23
+ } from "./chunk-36J3IZBS.js";
24
24
 
25
25
  // src/integrations/issue-attachments.ts
26
26
  import { existsSync, mkdirSync, writeFileSync } from "fs";
@@ -4,7 +4,7 @@ import {
4
4
  import {
5
5
  getAbleTimeHost,
6
6
  isAbleTimeConnected
7
- } from "./chunk-YNTXWFXT.js";
7
+ } from "./chunk-36J3IZBS.js";
8
8
 
9
9
  // src/integrations/abletime-mcp.ts
10
10
  var DEFAULT_ABLETIME_HOST = "https://track.abletime.com";
@@ -153,7 +153,7 @@ function textsFromUnknown(value) {
153
153
  return "";
154
154
  }
155
155
  async function abletimeMcpRequest(method, params, opts) {
156
- const rawToken = opts?.token ?? await import("./abletime-oauth-C2HN2Q6F.js").then((m) => m.ensureAbleTimeAccessToken());
156
+ const rawToken = opts?.token ?? await import("./abletime-oauth-ICMB2XV2.js").then((m) => m.ensureAbleTimeAccessToken());
157
157
  if (!rawToken?.trim()) {
158
158
  throw new Error("AbleTime is not connected \u2014 paste a personal access token in Account settings");
159
159
  }
@@ -224,9 +224,9 @@ async function callAbleTimeTool(name, args = {}, opts) {
224
224
  if (!opts?.token && !isAbleTimeConnected()) {
225
225
  throw new Error("AbleTime is not connected \u2014 paste a personal access token in Account settings");
226
226
  }
227
- const rawToken = opts?.token ?? await import("./abletime-oauth-C2HN2Q6F.js").then((m) => m.ensureAbleTimeAccessToken());
227
+ const rawToken = opts?.token ?? await import("./abletime-oauth-ICMB2XV2.js").then((m) => m.ensureAbleTimeAccessToken());
228
228
  if (rawToken && ableTimeUsesRest(rawToken)) {
229
- const { callAbleTimeRestTool } = await import("./abletime-rest-E4LBRFLM.js");
229
+ const { callAbleTimeRestTool } = await import("./abletime-rest-HFMRTUDT.js");
230
230
  return callAbleTimeRestTool(name, args, { ...opts, token: rawToken });
231
231
  }
232
232
  const requestOpts = { ...opts, pm: opts?.pm ?? abletimeToolUsesPm(name) };
@@ -242,7 +242,7 @@ async function callAbleTimeTool(name, args = {}, opts) {
242
242
  return await call();
243
243
  }
244
244
  if (rawToken && ableTimeUsesRest(rawToken) && isAbleTimeRejectedCredential(message)) {
245
- const { callAbleTimeRestTool } = await import("./abletime-rest-E4LBRFLM.js");
245
+ const { callAbleTimeRestTool } = await import("./abletime-rest-HFMRTUDT.js");
246
246
  return callAbleTimeRestTool(name, args, { ...opts, token: rawToken });
247
247
  }
248
248
  throw err instanceof Error ? new Error(rewriteAbleTimeError(err.message)) : err;
@@ -0,0 +1,300 @@
1
+ import {
2
+ enrichPathWithNpmGlobalBin,
3
+ isConductorBundledCli,
4
+ resolveCommandBinarySync,
5
+ run,
6
+ withExportedPath
7
+ } from "./chunk-QVN2WOKJ.js";
8
+ import {
9
+ resolveAgentExecutable
10
+ } from "./chunk-36J3IZBS.js";
11
+
12
+ // src/agents/install.ts
13
+ import { existsSync } from "fs";
14
+ var SETUP = {
15
+ claude: {
16
+ agent: "claude",
17
+ kind: "cli",
18
+ summary: "Install the Claude Code CLI, then complete login in a terminal.",
19
+ docsUrl: "https://code.claude.com/docs/en/install",
20
+ installCommand: "npm install -g @anthropic-ai/claude-code",
21
+ loginCommand: "claude auth login",
22
+ npmPackage: "@anthropic-ai/claude-code",
23
+ updateArgs: ["update"]
24
+ },
25
+ codex: {
26
+ agent: "codex",
27
+ kind: "cli",
28
+ summary: "Install the Codex CLI, then run login in a terminal.",
29
+ docsUrl: "https://github.com/openai/codex",
30
+ installCommand: "npm install -g @openai/codex",
31
+ loginCommand: "codex login",
32
+ npmPackage: "@openai/codex",
33
+ updateArgs: ["update"]
34
+ },
35
+ opencode: {
36
+ agent: "opencode",
37
+ kind: "cli",
38
+ summary: "Install OpenCode (curl installer or npm), then authenticate providers.",
39
+ docsUrl: "https://opencode.ai/docs",
40
+ // Prefer the official installer; npm package name is opencode-ai.
41
+ installCommand: "curl -fsSL https://opencode.ai/install | bash",
42
+ loginCommand: "opencode auth login",
43
+ npmPackage: "opencode-ai@latest",
44
+ updateArgs: ["upgrade"]
45
+ },
46
+ cursor: {
47
+ agent: "cursor",
48
+ kind: "cli",
49
+ summary: "Install (or update) @cursor/sdk with npm \u2014 Sideboard does not pin it in the app. Then add a CURSOR_API_KEY.",
50
+ docsUrl: "https://www.npmjs.com/package/@cursor/sdk",
51
+ installCommand: "npm install -g @cursor/sdk",
52
+ loginCommand: null,
53
+ npmPackage: "@cursor/sdk"
54
+ },
55
+ brightsy: {
56
+ agent: "brightsy",
57
+ kind: "cli",
58
+ summary: "Install (or update) the Brightsy CLI with npm, then run `brightsy login`.",
59
+ docsUrl: "https://www.npmjs.com/package/@brightsy/cli",
60
+ installCommand: "npm install -g @brightsy/cli",
61
+ loginCommand: "brightsy login",
62
+ npmPackage: "@brightsy/cli"
63
+ }
64
+ };
65
+ var CLI_BIN = {
66
+ claude: "claude",
67
+ codex: "codex",
68
+ opencode: "opencode",
69
+ brightsy: "brightsy"
70
+ };
71
+ function getAgentSetupInfo(agent) {
72
+ return SETUP[agent];
73
+ }
74
+ function listAgentSetupInfo() {
75
+ return Object.values(SETUP);
76
+ }
77
+ var CLI_LOGIN_AGENTS = /* @__PURE__ */ new Set([
78
+ "claude",
79
+ "codex",
80
+ "opencode",
81
+ "brightsy"
82
+ ]);
83
+ function resolveLoginCommand(agent) {
84
+ const info = getAgentSetupInfo(agent);
85
+ if (!info.loginCommand) return null;
86
+ if (!CLI_LOGIN_AGENTS.has(agent)) return info.loginCommand;
87
+ const exe = resolveAgentExecutable(agent);
88
+ return info.loginCommand.replace(/^\S+/, exe);
89
+ }
90
+ async function prepareTerminalCommand(command) {
91
+ enrichPathWithNpmGlobalBin();
92
+ const trimmed = command.trim();
93
+ if (!trimmed) return trimmed;
94
+ if (/^(export\s+PATH=|PATH=)/.test(trimmed)) return trimmed;
95
+ const match = /^(\S+)(\s[\s\S]*)?$/.exec(trimmed);
96
+ const bin = match?.[1];
97
+ let whichPath = null;
98
+ if (bin && !bin.includes("/") && !bin.includes("\\")) {
99
+ const which = await run("which", [bin], { reject: false, timeoutMs: 3e3 });
100
+ whichPath = which.exitCode === 0 ? which.stdout.trim() : null;
101
+ }
102
+ const resolved = resolveCommandBinarySync(trimmed, whichPath);
103
+ return withExportedPath(resolved, process.env.PATH ?? "");
104
+ }
105
+ async function openInSystemTerminal(command) {
106
+ const trimmed = (await prepareTerminalCommand(command)).trim();
107
+ if (!trimmed) throw new Error("Command is empty");
108
+ if (process.platform === "darwin") {
109
+ const escaped = trimmed.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
110
+ const script = `tell application "Terminal" to do script "${escaped}"`;
111
+ const result = await run("osascript", ["-e", script], { reject: false });
112
+ if (result.exitCode !== 0) {
113
+ throw new Error(result.stderr.trim() || result.stdout.trim() || "Failed to open Terminal");
114
+ }
115
+ await run("osascript", ["-e", 'tell application "Terminal" to activate'], {
116
+ reject: false
117
+ });
118
+ return;
119
+ }
120
+ if (process.platform === "win32") {
121
+ const result = await run(
122
+ "cmd.exe",
123
+ ["/c", "start", "cmd.exe", "/k", trimmed],
124
+ { reject: false }
125
+ );
126
+ if (result.exitCode !== 0) {
127
+ throw new Error(result.stderr.trim() || result.stdout.trim() || "Failed to open cmd");
128
+ }
129
+ return;
130
+ }
131
+ const candidates = [
132
+ { file: "gnome-terminal", args: ["--", "bash", "-lc", `${trimmed}; exec bash`] },
133
+ { file: "x-terminal-emulator", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] },
134
+ { file: "konsole", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] },
135
+ { file: "xterm", args: ["-e", "bash", "-lc", `${trimmed}; exec bash`] }
136
+ ];
137
+ for (const c of candidates) {
138
+ const which = await run("which", [c.file], { reject: false });
139
+ if (which.exitCode !== 0 || !which.stdout.trim()) continue;
140
+ const result = await run(c.file, c.args, { reject: false });
141
+ if (result.exitCode === 0) return;
142
+ }
143
+ throw new Error(
144
+ `No terminal found to run: ${trimmed}. Install gnome-terminal (or similar), or run the command manually.`
145
+ );
146
+ }
147
+ async function whichOnPath(bin) {
148
+ const which = await run("which", [bin], { reject: false, timeoutMs: 3e3 });
149
+ if (which.exitCode !== 0) return null;
150
+ return which.stdout.trim().split(/\r?\n/).find(Boolean) ?? null;
151
+ }
152
+ async function installNpmGlobalPackage(opts) {
153
+ enrichPathWithNpmGlobalBin();
154
+ const result = await run("npm", ["install", "-g", opts.npmPackage], { reject: false });
155
+ const ok = result.exitCode === 0;
156
+ if (!ok) {
157
+ try {
158
+ await openInSystemTerminal(opts.installCommand);
159
+ return {
160
+ ok: false,
161
+ openedTerminal: true,
162
+ command: opts.installCommand,
163
+ exitCode: result.exitCode,
164
+ stdout: result.stdout,
165
+ stderr: result.stderr,
166
+ message: `npm install failed (exit ${result.exitCode}). Opened Terminal with: ${opts.installCommand}`
167
+ };
168
+ } catch {
169
+ return {
170
+ ok: false,
171
+ command: opts.installCommand,
172
+ exitCode: result.exitCode,
173
+ stdout: result.stdout,
174
+ stderr: result.stderr,
175
+ message: result.stderr.trim() || result.stdout.trim() || `npm install failed (exit ${result.exitCode})`
176
+ };
177
+ }
178
+ }
179
+ enrichPathWithNpmGlobalBin();
180
+ const binPath = opts.cliBin ? await whichOnPath(opts.cliBin) : null;
181
+ return {
182
+ ok: true,
183
+ command: opts.installCommand,
184
+ exitCode: 0,
185
+ stdout: result.stdout,
186
+ stderr: result.stderr,
187
+ // Library-only packages (`@cursor/sdk`) have no CLI to look for.
188
+ message: !opts.cliBin ? `Installed ${opts.npmPackage}` : binPath ? `Installed ${opts.npmPackage} \u2192 ${binPath}` : `Installed ${opts.npmPackage} (CLI not yet on PATH)`
189
+ };
190
+ }
191
+ async function resolveExistingCli(agent) {
192
+ if (agent === "cursor") return null;
193
+ const exe = resolveAgentExecutable(agent);
194
+ if ((exe.includes("/") || exe.includes("\\")) && existsSync(exe)) return exe;
195
+ enrichPathWithNpmGlobalBin();
196
+ return whichOnPath(CLI_BIN[agent]);
197
+ }
198
+ async function runVendorUpdate(existing, updateArgs) {
199
+ const result = await run(existing, updateArgs, {
200
+ reject: false,
201
+ timeoutMs: 12e4
202
+ });
203
+ const command = `${existing} ${updateArgs.join(" ")}`;
204
+ const ok = result.exitCode === 0;
205
+ const detail = result.stdout.trim() || result.stderr.trim() || `exit ${result.exitCode}`;
206
+ return {
207
+ ok,
208
+ command,
209
+ exitCode: result.exitCode,
210
+ stdout: result.stdout,
211
+ stderr: result.stderr,
212
+ message: ok ? isConductorBundledCli(existing) ? `Updated Conductor\u2019s CLI at ${existing}. ${detail}` : `Updated ${command}. ${detail}` : `Update failed (${command}): ${detail}`
213
+ };
214
+ }
215
+ function isCurlInstaller(command) {
216
+ return /curl\s| \|\s*bash/.test(command);
217
+ }
218
+ async function installAgent(agent) {
219
+ const info = getAgentSetupInfo(agent);
220
+ if (info.kind === "bundled-sdk" || info.kind === "api-key") {
221
+ return {
222
+ ok: true,
223
+ message: info.summary
224
+ };
225
+ }
226
+ if (!info.installCommand) {
227
+ return { ok: false, message: `No install command for ${agent}` };
228
+ }
229
+ const existing = await resolveExistingCli(agent);
230
+ if (existing && info.updateArgs?.length) {
231
+ return runVendorUpdate(existing, info.updateArgs);
232
+ }
233
+ if (info.npmPackage && !isCurlInstaller(info.installCommand)) {
234
+ const cliBin = agent === "cursor" ? null : CLI_BIN[agent];
235
+ return installNpmGlobalPackage({
236
+ npmPackage: info.npmPackage,
237
+ installCommand: info.installCommand,
238
+ cliBin
239
+ });
240
+ }
241
+ await openInSystemTerminal(info.installCommand);
242
+ return {
243
+ ok: true,
244
+ openedTerminal: true,
245
+ command: info.installCommand,
246
+ message: `Opened Terminal to run: ${info.installCommand}`
247
+ };
248
+ }
249
+ async function loginAgent(agent) {
250
+ const info = getAgentSetupInfo(agent);
251
+ const loginCommand = resolveLoginCommand(agent);
252
+ if (!loginCommand) {
253
+ return {
254
+ ok: true,
255
+ message: info.kind === "bundled-sdk" || info.kind === "api-key" ? info.summary : `No login command for ${agent}`
256
+ };
257
+ }
258
+ const prepared = await prepareTerminalCommand(loginCommand);
259
+ await openInSystemTerminal(prepared);
260
+ return {
261
+ ok: true,
262
+ openedTerminal: true,
263
+ command: prepared,
264
+ message: `Opened Terminal to run: ${prepared}`
265
+ };
266
+ }
267
+ async function loginManagedAccount(accountId) {
268
+ const { loadAppSettings } = await import("./app-settings-MR2U6AXN.js");
269
+ const { loginEnvPrefix } = await import("./managed-accounts-2AK5RIAF.js");
270
+ const account = loadAppSettings().accounts.accounts.find((a) => a.id === accountId);
271
+ if (!account) {
272
+ return { ok: false, message: `Account not found: ${accountId}` };
273
+ }
274
+ const loginCommand = resolveLoginCommand(account.kind);
275
+ if (!loginCommand) {
276
+ return { ok: false, message: `No login command for ${account.kind}` };
277
+ }
278
+ const prepared = await prepareTerminalCommand(loginCommand);
279
+ const prefixed = `${loginEnvPrefix(account)} && ${prepared}`;
280
+ await openInSystemTerminal(prefixed);
281
+ return {
282
+ ok: true,
283
+ openedTerminal: true,
284
+ command: prefixed,
285
+ message: `Opened Terminal to run: ${prefixed}`
286
+ };
287
+ }
288
+
289
+ export {
290
+ getAgentSetupInfo,
291
+ listAgentSetupInfo,
292
+ resolveLoginCommand,
293
+ prepareTerminalCommand,
294
+ openInSystemTerminal,
295
+ whichOnPath,
296
+ installNpmGlobalPackage,
297
+ installAgent,
298
+ loginAgent,
299
+ loginManagedAccount
300
+ };