@sideboard-ai/core 0.1.68 → 0.1.71

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 (36) hide show
  1. package/dist/{agents-PE3RHQS5.js → agents-GB7XL2LI.js} +6 -5
  2. package/dist/{agents-JBD7IAGK.js → agents-TCAK3MXN.js} +6 -5
  3. package/dist/{app-settings-ONKMFSEJ.js → app-settings-3TLA2EJ7.js} +16 -1
  4. package/dist/{app-settings-GJVZGU3M.js → app-settings-P42Z3VOB.js} +16 -1
  5. package/dist/caffeinate-hold-BEJIYPJ7.js +107 -0
  6. package/dist/caffeinate-hold-KLC6SABD.js +14 -0
  7. package/dist/{chunk-DPDGMMGI.js → chunk-3CY6WJ7O.js} +2 -2
  8. package/dist/{chunk-ROXEENBT.js → chunk-57ROTAFD.js} +62 -3
  9. package/dist/{chunk-N5LMEP65.js → chunk-7NCIHRAU.js} +22 -4
  10. package/dist/{chunk-OICHV4DH.js → chunk-DGPUAZA4.js} +62 -3
  11. package/dist/{chunk-VX6ACNXS.js → chunk-H2IXNFQ2.js} +22 -4
  12. package/dist/chunk-JAWEDVVA.js +106 -0
  13. package/dist/chunk-JT7R45JB.js +20 -0
  14. package/dist/{chunk-EEBDVLDK.js → chunk-MF2YMEGD.js} +61 -9
  15. package/dist/{chunk-47RBLBRK.js → chunk-NG7S3OPX.js} +10 -4
  16. package/dist/chunk-NSTQ6QKD.js +23 -0
  17. package/dist/{chunk-REKGFVUX.js → chunk-OE7YBB5X.js} +61 -9
  18. package/dist/{chunk-BPOTVI5J.js → chunk-PTJJIQK7.js} +472 -18
  19. package/dist/{chunk-6Q7H6SMX.js → chunk-S25IHL5H.js} +10 -4
  20. package/dist/{chunk-QQC2D4MY.js → chunk-UH57WVFP.js} +2 -2
  21. package/dist/{chunk-MHR4OGZ4.js → chunk-W7YOTDVO.js} +493 -18
  22. package/dist/{coordinator-prompt-YZYZ5P6P.js → coordinator-prompt-2J4PIMUF.js} +6 -3
  23. package/dist/{coordinator-prompt-HD6IMCKS.js → coordinator-prompt-QYYG2IBB.js} +6 -3
  24. package/dist/{global-workspace-Z6GF7D2K.js → global-workspace-KHIFQUUM.js} +11 -4
  25. package/dist/{global-workspace-7P5NG3JZ.js → global-workspace-SVRYNJZA.js} +11 -4
  26. package/dist/index.cjs +4184 -850
  27. package/dist/index.d.cts +543 -21
  28. package/dist/index.d.ts +543 -21
  29. package/dist/index.js +3285 -748
  30. package/dist/mcp/run-stdio.cjs +1995 -482
  31. package/dist/mcp/run-stdio.js +943 -151
  32. package/dist/{workspaces-BWJNGEE6.js → workspaces-AHFTHVBT.js} +6 -5
  33. package/dist/{workspaces-O6EZGKQK.js → workspaces-SVQIEVIZ.js} +6 -5
  34. package/dist/{worktree-VDXLUOWR.js → worktree-KWXHMKRN.js} +1 -1
  35. package/dist/{worktree-ZPSKEZFE.js → worktree-VOCH3WS3.js} +1 -1
  36. package/package.json +3 -1
package/dist/index.d.ts CHANGED
@@ -284,6 +284,8 @@ interface PrMeta {
284
284
  reviewDecision: string | null;
285
285
  baseRefName: string;
286
286
  headRefName: string;
287
+ /** True when the PR is sitting in a GitHub merge queue. */
288
+ isInMergeQueue: boolean;
287
289
  }
288
290
  /** One layer in a GitHub PR stack (bottom = position 1). */
289
291
  interface PrStackLayer {
@@ -602,7 +604,7 @@ interface CliExecutableSettings {
602
604
  }
603
605
  /** Local agent that runs the Brightsy cloud coordinator. */
604
606
  type BrightsyCloudConnectAgent = 'claude' | 'codex' | 'opencode' | 'cursor';
605
- /** Brightsy cloud remote-orchestrator preferences (Slack / Discord / Teams). */
607
+ /** Brightsy cloud remote-orchestrator preferences. */
606
608
  interface BrightsyHarnessSettings {
607
609
  /** Absolute path to the Brightsy CLI. Empty/omitted = `brightsy` on PATH. */
608
610
  executablePath?: string;
@@ -621,16 +623,48 @@ interface BrightsyHarnessSettings {
621
623
  type IssueSource = 'linear' | 'github';
622
624
  /**
623
625
  * Sideboard-owned third-party connections (Account / Integrations).
624
- * GitHub uses machine `gh` auth; Linear uses a stored API key.
626
+ * GitHub uses machine `gh` auth; Linear uses OAuth (or a stored API key).
625
627
  */
626
628
  interface IntegrationsSettings {
627
- /** Linear personal API key (https://linear.app/settings/api). */
629
+ /** Linear personal API key (https://linear.app/settings/api). Fallback when OAuth is unused. */
628
630
  linearApiKey?: string;
631
+ /** Linear OAuth access token (Account → Linear → Connect via browser). */
632
+ linearAccessToken?: string;
633
+ /** Linear OAuth refresh token (rotated on each refresh). */
634
+ linearRefreshToken?: string;
635
+ /** Epoch ms when {@link IntegrationsSettings.linearAccessToken} expires. */
636
+ linearTokenExpiresAt?: number;
637
+ /** Linear OAuth app Client ID override (else baked / env). */
638
+ linearClientId?: string;
639
+ /** Linear OAuth app Client Secret override (optional with PKCE). */
640
+ linearClientSecret?: string;
641
+ /** Display name of the connected Linear user (non-secret). */
642
+ linearViewerName?: string;
643
+ /** Display name of the connected Linear workspace (non-secret). */
644
+ linearOrganizationName?: string;
629
645
  /**
630
646
  * Preferred issue source for Create-from / Link issue (default: GitHub).
631
- * When `linear` but no API key, runtime falls back to GitHub Issues.
647
+ * When `linear` but not connected, runtime falls back to GitHub Issues.
632
648
  */
633
649
  issueSource?: IssueSource;
650
+ /** Slack app Client ID for browser OAuth (Account → Slack). */
651
+ slackClientId?: string;
652
+ /** Slack app Client Secret for browser OAuth. */
653
+ slackClientSecret?: string;
654
+ /**
655
+ * Slack app-level token (`xapp-…`, `connections:write`) for Socket Mode listen.
656
+ * App-wide — not per workspace.
657
+ */
658
+ slackAppToken?: string;
659
+ /** When true, desktop/CLI listen for Slack DMs and @mentions via Socket Mode. */
660
+ slackListenEnabled?: boolean;
661
+ /**
662
+ * Stable per-Mac id for the Slack relay (Personal vs Work can both stay online).
663
+ * Generated once; do not copy between machines.
664
+ */
665
+ slackDeviceId?: string;
666
+ /** Human label for this Mac destination, e.g. Personal / Work. */
667
+ slackDeviceLabel?: string;
634
668
  }
635
669
  /**
636
670
  * Conductor-inspired power-user preferences (Settings → Advanced).
@@ -654,8 +688,12 @@ interface AdvancedAppSettings {
654
688
  */
655
689
  caffeinateWhileRunning?: boolean;
656
690
  /**
657
- * Keep the Mac awake with `caffeinate` while Brightsy cloud connect is listening
658
- * (so Slack/Discord/Teams tasks can be polled). Default off.
691
+ * Keep the Mac awake with `caffeinate` while Slack Listen is connected
692
+ * (so Personal/Work stay reachable with the lid closed on AC). Default off.
693
+ */
694
+ caffeinateWhileSlackListen?: boolean;
695
+ /**
696
+ * @deprecated Prefer `caffeinateWhileSlackListen`. Still read on load for migration.
659
697
  */
660
698
  caffeinateWhileCloudConnect?: boolean;
661
699
  /**
@@ -699,7 +737,7 @@ interface AppSettings {
699
737
  codex: CliExecutableSettings;
700
738
  /** OpenCode CLI executable override. */
701
739
  opencode: CliExecutableSettings;
702
- /** Brightsy cloud connect preferences (Slack / Discord / Teams). */
740
+ /** Brightsy cloud connect preferences. */
703
741
  brightsy: BrightsyHarnessSettings;
704
742
  /** GitHub / Linear connections and issue-source preference. */
705
743
  integrations: IntegrationsSettings;
@@ -708,6 +746,19 @@ interface AppSettings {
708
746
  /** Power-user / Conductor-style advanced preferences. */
709
747
  advanced: AdvancedAppSettings;
710
748
  }
749
+ /** Integrations fields safe to send to the renderer (no token values). */
750
+ type PublicIntegrationsSettings = Omit<IntegrationsSettings, 'linearApiKey' | 'linearAccessToken' | 'linearRefreshToken' | 'linearClientSecret' | 'slackClientSecret' | 'slackAppToken'> & {
751
+ /** True when Linear is connected (OAuth or API key). */
752
+ hasLinearApiKey: boolean;
753
+ hasLinearOAuth: boolean;
754
+ hasSlackClientSecret: boolean;
755
+ hasSlackAppToken: boolean;
756
+ };
757
+ /** Settings payload for the desktop UI. Secret values are omitted. */
758
+ type PublicAppSettings = Omit<AppSettings, 'integrations'> & {
759
+ integrations: PublicIntegrationsSettings;
760
+ };
761
+ declare function toPublicAppSettings(settings: AppSettings): PublicAppSettings;
711
762
  declare function appSettingsPath(): string;
712
763
  /** User-level Claude Code settings file (`~/.claude/settings.json`). */
713
764
  declare function claudeUserSettingsPath(): string;
@@ -732,7 +783,15 @@ declare function updateOpencodeSettings(patch: {
732
783
  }): AppSettings;
733
784
  declare function updateIntegrationsSettings(patch: {
734
785
  linearApiKey?: string | null;
786
+ linearClientId?: string | null;
787
+ linearClientSecret?: string | null;
735
788
  issueSource?: IssueSource | null;
789
+ slackClientId?: string | null;
790
+ slackClientSecret?: string | null;
791
+ slackAppToken?: string | null;
792
+ slackListenEnabled?: boolean | null;
793
+ slackDeviceId?: string | null;
794
+ slackDeviceLabel?: string | null;
736
795
  }): AppSettings;
737
796
  declare function updateDefaultsSettings(patch: {
738
797
  agent?: AgentKind | null;
@@ -772,8 +831,18 @@ declare function resolveNewThreadOptions(overrides?: {
772
831
  effort: ThinkingEffort;
773
832
  fast: boolean;
774
833
  };
775
- /** True when Sideboard has a Linear API key stored. */
834
+ /** True when Sideboard has Linear OAuth tokens or an API key stored. */
776
835
  declare function isLinearConnected(settings?: AppSettings): boolean;
836
+ /** Persist Linear OAuth tokens after authorize or refresh. */
837
+ declare function saveLinearOAuth(input: {
838
+ accessToken: string;
839
+ refreshToken?: string;
840
+ expiresIn?: number;
841
+ viewerName?: string;
842
+ organizationName?: string;
843
+ }): AppSettings;
844
+ /** Clear Linear OAuth tokens and API key. Does not revoke remotely. */
845
+ declare function disconnectLinearConnection(): AppSettings;
777
846
  /** Preferred issue source (default GitHub). */
778
847
  declare function getIssueSource(settings?: AppSettings): IssueSource;
779
848
  /**
@@ -783,6 +852,21 @@ declare function getIssueSource(settings?: AppSettings): IssueSource;
783
852
  declare function resolveEffectiveIssueSource(settings?: AppSettings): IssueSource;
784
853
  declare function getLinearApiKey(settings?: AppSettings): string | null;
785
854
  declare function brightsyCloudConnectEnabled(settings?: AppSettings): boolean;
855
+ /** Slack Socket Mode inbound (Account → Slack). Default off. */
856
+ declare function slackListenEnabled(settings?: AppSettings): boolean;
857
+ /**
858
+ * Stable per-Mac identity for the Slack relay so Personal and Work can both
859
+ * stay online as separate destinations.
860
+ */
861
+ declare function ensureSlackDeviceIdentity(settings?: AppSettings): {
862
+ deviceId: string;
863
+ deviceLabel: string;
864
+ };
865
+ /**
866
+ * App-level token for Slack Socket Mode (`xapp-…`).
867
+ * Env `SIDEBOARD_SLACK_APP_TOKEN` wins over settings.
868
+ */
869
+ declare function slackAppLevelToken(settings?: AppSettings): string;
786
870
  /** Default off — worktree agents only get Brightsy MCP on ask / prior use. */
787
871
  declare function brightsyInjectWorktreeMcpEnabled(settings?: AppSettings): boolean;
788
872
  /**
@@ -797,6 +881,8 @@ declare function updateAdvancedSettings(patch: Partial<AdvancedAppSettings>): Ap
797
881
  declare function autoRenameBranchEnabled(settings?: AppSettings): boolean;
798
882
  declare function autoRunAfterSetupEnabled(settings?: AppSettings): boolean;
799
883
  declare function caffeinateWhileRunningEnabled(settings?: AppSettings): boolean;
884
+ declare function caffeinateWhileSlackListenEnabled(settings?: AppSettings): boolean;
885
+ /** @deprecated Use caffeinateWhileSlackListenEnabled. */
800
886
  declare function caffeinateWhileCloudConnectEnabled(settings?: AppSettings): boolean;
801
887
  declare function deleteBranchOnPurgeEnabled(settings?: AppSettings): boolean;
802
888
  /** Conductor-style opt-in — default off. */
@@ -825,6 +911,33 @@ declare function applyAppEnvironment(target?: NodeJS.ProcessEnv, settings?: AppS
825
911
  declare function childEnvWithAppSettings(extra?: Record<string, string | undefined>): NodeJS.ProcessEnv;
826
912
  declare function harnessEnvKey(harness: HarnessId): string | null;
827
913
 
914
+ interface CaffeinateHoldState {
915
+ held: boolean;
916
+ pid: number | null;
917
+ running: boolean;
918
+ platform: NodeJS.Platform;
919
+ }
920
+ declare function caffeinateHoldPath(): string;
921
+ declare function getCaffeinateHold(): CaffeinateHoldState;
922
+ /**
923
+ * Session hold so the Mac stays awake across orchestration turns (MCP
924
+ * processes exit). Detached `caffeinate` on macOS; no-op elsewhere.
925
+ */
926
+ declare function setCaffeinateHold(enabled: boolean): CaffeinateHoldState;
927
+
928
+ /** Desktop registers a 32-byte key from Electron safeStorage. */
929
+ declare function setVaultMasterKey(key: Buffer | null): void;
930
+ declare function persistVaultKeyInKeychain(key: Buffer): void;
931
+ /** Existing Keychain vault key, if any. Does not create a new item. */
932
+ declare function readKeychainVaultKey(): Buffer | null;
933
+ /**
934
+ * AES-256-GCM key for secret files.
935
+ * `SIDEBOARD_SECRET_VAULT=plain` (tests) skips encryption.
936
+ */
937
+ declare function resolveVaultKey(): Buffer | null;
938
+ /** True if `path` is missing, plaintext, or decrypts with `key`. */
939
+ declare function secureFileUnlocksWith(path: string, key: Buffer): boolean;
940
+
828
941
  /**
829
942
  * Resolve thinking effort for persisted threads.
830
943
  * Legacy threads only had `fast` (which also drove Claude `--effort low`);
@@ -901,6 +1014,15 @@ declare function createGlobalChat(opts: CreateGlobalChatOpts): Thread;
901
1014
  */
902
1015
  declare function healOrchestrationSoccerTitles(): number;
903
1016
  declare function listGlobalThreads(includeArchived?: boolean): Thread[];
1017
+ /** Stable sourceRef for a Slack inbound orchestration chat (one per Slack user). */
1018
+ declare function slackCoordinatorSourceRef(teamId: string, userId: string): string;
1019
+ declare function isSlackCoordinatorThread(thread: Pick<Thread, 'sourceType' | 'sourceRef' | 'repoPath'>): boolean;
1020
+ /**
1021
+ * Find or create a Global orchestration chat for one Slack user (team + user).
1022
+ * Inbound DMs/@mentions from that person continue this thread — not the Brightsy
1023
+ * cloud singleton and not other Slack users' chats.
1024
+ */
1025
+ declare function ensureSlackCoordinator(teamId: string, userId: string, agent: AgentKind): Thread;
904
1026
  /** Find or create the singleton Brightsy cloud coordinator under Global. */
905
1027
  declare function ensureCloudCoordinator(agent: AgentKind): Thread;
906
1028
 
@@ -1220,7 +1342,7 @@ declare function refreshGitHubAuth(): Promise<GitHubStatus>;
1220
1342
 
1221
1343
  /**
1222
1344
  * List open issues assigned to the authenticated Linear user via GraphQL.
1223
- * Uses Sideboard-stored API key (Account → Linear), not agent MCP.
1345
+ * Uses Sideboard-stored OAuth token or API key (Account → Linear), not agent MCP.
1224
1346
  */
1225
1347
  declare function listLinearIssuesDirect(opts?: {
1226
1348
  limit?: number;
@@ -1229,6 +1351,39 @@ declare function listLinearIssuesDirect(opts?: {
1229
1351
  /** Probe Linear with the stored key (or provided key). */
1230
1352
  declare function validateLinearApiKey(apiKey: string): Promise<boolean>;
1231
1353
 
1354
+ declare function hasBakedLinearOAuth(): boolean;
1355
+
1356
+ /** Fixed port so the Linear OAuth redirect URI can be registered once. */
1357
+ declare const LINEAR_OAUTH_PORT = 19848;
1358
+ declare const LINEAR_OAUTH_REDIRECT = "http://127.0.0.1:19848/callback";
1359
+ /** Read-only — Sideboard lists assigned issues; it does not create them. */
1360
+ declare const LINEAR_OAUTH_SCOPES = "read";
1361
+ declare function linearOAuthCredentials(): {
1362
+ clientId: string;
1363
+ clientSecret: string;
1364
+ };
1365
+ declare function createLinearPkce(): {
1366
+ verifier: string;
1367
+ challenge: string;
1368
+ };
1369
+ declare function linearOAuthAuthorizeUrl(clientId: string, state: string, codeChallenge: string): string;
1370
+ /** Authorization header for Linear GraphQL: personal keys as-is, OAuth as Bearer. */
1371
+ declare function linearAuthorizationHeader(token: string): string;
1372
+ /**
1373
+ * Token for Linear GraphQL: valid OAuth access token (refreshing if needed),
1374
+ * else a stored personal API key.
1375
+ */
1376
+ declare function getLinearAuthToken(settings?: AppSettings): Promise<string | null>;
1377
+ /**
1378
+ * Open Linear OAuth in the browser, listen on a localhost callback, store tokens.
1379
+ */
1380
+ declare function startLinearOAuth(opts?: {
1381
+ openUrl?: (url: string) => void | Promise<void>;
1382
+ timeoutMs?: number;
1383
+ }): Promise<AppSettings>;
1384
+ /** Revoke OAuth tokens (best-effort) and clear Linear credentials including API key. */
1385
+ declare function disconnectLinear(): Promise<AppSettings>;
1386
+
1232
1387
  interface ListIssuesResult {
1233
1388
  source: IssueSource;
1234
1389
  /** Preference before fallback (useful for “Set up Linear” UI). */
@@ -2780,6 +2935,11 @@ declare function formatWorkspaceInventory(workspaces: WorkspaceInventoryEntry[])
2780
2935
  /** Resolve GitHub slugs for registered workspaces (best-effort). */
2781
2936
  declare function enrichWorkspacesWithGithub(workspaces: Workspace[]): Promise<WorkspaceInventoryEntry[]>;
2782
2937
  declare const COORDINATOR_TOOL_PLAYBOOK: string;
2938
+ /**
2939
+ * Formatting rules when the coordinator reply is posted into Slack (DM / @mention).
2940
+ * Slack uses mrkdwn, not CommonMark — `**bold**` shows literal asterisks.
2941
+ */
2942
+ declare const SLACK_REPLY_FORMATTING: string;
2783
2943
  /**
2784
2944
  * Short identity block prepended to every orchestration turn prompt.
2785
2945
  * Survives Claude `--resume` (which drops cachedPrefix).
@@ -2801,8 +2961,8 @@ declare function coordinatorSystemPrompt(opts: {
2801
2961
  goal: string;
2802
2962
  parentId: string;
2803
2963
  workspaces: WorkspaceInventoryEntry[];
2804
- /** cloud = Brightsy reply framing; desktop = local Orchestration chat */
2805
- audience?: 'cloud' | 'desktop';
2964
+ /** cloud = Brightsy reply framing; slack = Sideboard Slack app; desktop = local Orchestration chat */
2965
+ audience?: 'cloud' | 'slack' | 'desktop';
2806
2966
  }): string;
2807
2967
 
2808
2968
  /**
@@ -2875,6 +3035,82 @@ declare function getBrightsySession(): Promise<BrightsySession>;
2875
3035
  */
2876
3036
  declare function switchBrightsyAccount(accountIdOrSlug: string): Promise<BrightsySession>;
2877
3037
 
3038
+ interface SlackOutboundWatch {
3039
+ id: string;
3040
+ teamId: string;
3041
+ channelId: string;
3042
+ /** Posted message ts. */
3043
+ ts: string;
3044
+ /** Parent thread ts (same as `ts` for top-level posts). */
3045
+ threadTs: string;
3046
+ kind: 'dm' | 'channel';
3047
+ toUserId?: string;
3048
+ toLabel: string;
3049
+ ownerUserId?: string;
3050
+ postedAt: string;
3051
+ lastSeenTs: string;
3052
+ unread: boolean;
3053
+ replyUserId?: string;
3054
+ replyUserName?: string;
3055
+ replyTs?: string;
3056
+ replyPreview?: string;
3057
+ permalink?: string;
3058
+ }
3059
+ interface SlackReplyBadge {
3060
+ id: string;
3061
+ userId: string;
3062
+ userName: string;
3063
+ initials: string;
3064
+ hue: number;
3065
+ permalink: string;
3066
+ label: string;
3067
+ preview?: string;
3068
+ repliedAt: string;
3069
+ }
3070
+ declare function slackArchiveUrl(channelId: string, ts: string): string;
3071
+ declare function recordSlackOutboundWatch(input: {
3072
+ teamId: string;
3073
+ channelId: string;
3074
+ ts: string;
3075
+ threadTs?: string;
3076
+ kind: 'dm' | 'channel';
3077
+ toUserId?: string;
3078
+ toLabel: string;
3079
+ ownerUserId?: string;
3080
+ }): SlackOutboundWatch | null;
3081
+ declare function listSlackReplyBadges(): SlackReplyBadge[];
3082
+ declare function dismissSlackReplyBadge(badgeKey: string): SlackReplyBadge[];
3083
+ declare function permalinkForSlackReplyBadge(badgeKey: string): string | null;
3084
+ declare function refreshSlackReplyBadges(opts?: {
3085
+ fetchImpl?: typeof fetch;
3086
+ force?: boolean;
3087
+ now?: number;
3088
+ }): Promise<SlackReplyBadge[]>;
3089
+
3090
+ interface SlackWorkspace {
3091
+ team_id: string;
3092
+ team_name: string;
3093
+ user_id?: string;
3094
+ bot_token?: string;
3095
+ user_token?: string;
3096
+ scopes?: string;
3097
+ connected_at: string;
3098
+ }
3099
+ /** Safe to send to the renderer / MCP (no tokens). */
3100
+ interface SlackWorkspaceInfo {
3101
+ team_id: string;
3102
+ team_name: string;
3103
+ user_id?: string;
3104
+ has_bot_token: boolean;
3105
+ has_user_token: boolean;
3106
+ connected_at: string;
3107
+ }
3108
+ declare function listSlackWorkspaces(): SlackWorkspaceInfo[];
3109
+ declare function getSlackWorkspace(teamId: string): SlackWorkspace | null;
3110
+ declare function disconnectSlackWorkspace(teamId: string): SlackWorkspaceInfo[];
3111
+ /** Add or update a workspace from a pasted bot (`xoxb-`) or user (`xoxp-`) token. */
3112
+ declare function connectSlackToken(rawToken: string): Promise<SlackWorkspaceInfo>;
3113
+
2878
3114
  /** Live status of the Brightsy cloud connect daemon in the desktop app. */
2879
3115
  interface CloudConnectStatus {
2880
3116
  enabled: boolean;
@@ -2885,6 +3121,21 @@ interface CloudConnectStatus {
2885
3121
  lastError: string | null;
2886
3122
  lastLog: string | null;
2887
3123
  }
3124
+ /** Live status of Sideboard Slack Listen (hosted relay). */
3125
+ interface SlackListenStatus {
3126
+ enabled: boolean;
3127
+ running: boolean;
3128
+ hasAppToken: boolean;
3129
+ /** Built-in Sideboard Slack app Client ID/Secret are present (not sent to renderer). */
3130
+ bakedOAuth: boolean;
3131
+ /** How inbound events arrive when listening. */
3132
+ mode: 'relay' | null;
3133
+ workspaceCount: number;
3134
+ /** This Mac’s Slack destination label (Personal / Work). */
3135
+ deviceLabel: string | null;
3136
+ lastError: string | null;
3137
+ lastLog: string | null;
3138
+ }
2888
3139
  /** Shared typed surface for Electron preload ↔ renderer (and docs). */
2889
3140
  interface IpcApi {
2890
3141
  detectAgents(): Promise<AgentStatus[]>;
@@ -2894,14 +3145,14 @@ interface IpcApi {
2894
3145
  installAgent(agent: AgentKind): Promise<AgentSetupActionResult>;
2895
3146
  /** Open the agent’s login/auth command in the system terminal. */
2896
3147
  loginAgent(agent: AgentKind): Promise<AgentSetupActionResult>;
2897
- getAppSettings(): Promise<AppSettings>;
2898
- saveAppSettings(settings: AppSettings): Promise<AppSettings>;
2899
- updateAppEnvironment(patch: Record<string, string | null | undefined>): Promise<AppSettings>;
3148
+ getAppSettings(): Promise<PublicAppSettings>;
3149
+ saveAppSettings(settings: AppSettings): Promise<PublicAppSettings>;
3150
+ updateAppEnvironment(patch: Record<string, string | null | undefined>): Promise<PublicAppSettings>;
2900
3151
  updateClaudeSettings(patch: Partial<ClaudeHarnessSettings> & {
2901
3152
  executablePath?: string | null;
2902
- }): Promise<AppSettings>;
3153
+ }): Promise<PublicAppSettings>;
2903
3154
  /** Persist a custom executable path for Claude / Codex / OpenCode / Brightsy. */
2904
- updateAgentExecutable(agent: CliAgentKind, executablePath: string | null): Promise<AppSettings>;
3155
+ updateAgentExecutable(agent: CliAgentKind, executablePath: string | null): Promise<PublicAppSettings>;
2905
3156
  /** Native file picker for a Claude Code executable override. */
2906
3157
  pickClaudeExecutable(): Promise<string | null>;
2907
3158
  /** Native file picker for a CLI agent executable override. */
@@ -2947,20 +3198,46 @@ interface IpcApi {
2947
3198
  }): Promise<CloudConnectStatus>;
2948
3199
  updateBrightsySettings(patch: Partial<BrightsyHarnessSettings> & {
2949
3200
  cloudConnectAgent?: BrightsyCloudConnectAgent | null;
2950
- }): Promise<AppSettings>;
2951
- updateAdvancedSettings(patch: Partial<AdvancedAppSettings>): Promise<AppSettings>;
3201
+ }): Promise<PublicAppSettings>;
3202
+ updateAdvancedSettings(patch: Partial<AdvancedAppSettings>): Promise<PublicAppSettings>;
2952
3203
  updateIntegrationsSettings(patch: {
2953
3204
  linearApiKey?: string | null;
2954
3205
  issueSource?: IssueSource | null;
2955
- }): Promise<AppSettings>;
3206
+ slackClientId?: string | null;
3207
+ slackClientSecret?: string | null;
3208
+ slackAppToken?: string | null;
3209
+ slackListenEnabled?: boolean | null;
3210
+ slackDeviceId?: string | null;
3211
+ slackDeviceLabel?: string | null;
3212
+ }): Promise<PublicAppSettings>;
2956
3213
  updateDefaultsSettings(patch: {
2957
3214
  agent?: AgentKind | null;
2958
3215
  model?: string | null;
2959
3216
  effort?: ThinkingEffort | 'normal' | null;
2960
3217
  fast?: boolean | null;
2961
- }): Promise<AppSettings>;
3218
+ }): Promise<PublicAppSettings>;
2962
3219
  /** Machine-global GitHub status via `gh`. */
2963
3220
  getGitHubStatus(): Promise<GitHubStatus>;
3221
+ /** Connected Slack workspaces (no tokens). */
3222
+ getSlackWorkspaces(): Promise<SlackWorkspaceInfo[]>;
3223
+ /** Add a workspace from a pasted bot (xoxb-) or user (xoxp-) token. */
3224
+ connectSlackToken(token: string): Promise<SlackWorkspaceInfo[]>;
3225
+ /** Browser OAuth — opens Slack, waits for localhost callback. */
3226
+ startSlackOAuth(): Promise<SlackWorkspaceInfo[]>;
3227
+ disconnectSlackWorkspace(teamId: string): Promise<SlackWorkspaceInfo[]>;
3228
+ /** Browser OAuth — opens Linear, waits for localhost callback. */
3229
+ startLinearOAuth(): Promise<PublicAppSettings>;
3230
+ /** Revoke Linear OAuth (best-effort) and clear stored Linear credentials. */
3231
+ disconnectLinear(): Promise<PublicAppSettings>;
3232
+ /** Sideboard Slack listen (DMs + @mentions → Global orchestrator). */
3233
+ getSlackListenStatus(): Promise<SlackListenStatus>;
3234
+ setSlackListen(opts: {
3235
+ enabled: boolean;
3236
+ }): Promise<SlackListenStatus>;
3237
+ /** Unread Slack replies to messages this Mac posted (does not drive the Mac). */
3238
+ getSlackReplyBadges(): Promise<SlackReplyBadge[]>;
3239
+ /** Open the Slack thread in the browser/app and clear that user's badge. */
3240
+ openSlackReply(badgeId: string): Promise<SlackReplyBadge[]>;
2964
3241
  /**
2965
3242
  * Unified issues for Create-from / Link issue (Linear API or GitHub Issues,
2966
3243
  * based on Account preference with Linear→GitHub fallback).
@@ -3482,4 +3759,249 @@ declare function writeInjectedMcpConfig(opts: {
3482
3759
  includeBrightsy?: boolean;
3483
3760
  }): Promise<string | null>;
3484
3761
 
3485
- export { ATTACHMENTS_DIR, type ActiveRun, type AddStackLayerInput, type AdoptInput, type AdvancedAppSettings, type AgentAdapter, type AgentEvent, type AgentInstructionFile, type AgentKind, type AgentModelCatalog, type AgentModelInfo, type AgentSetupActionResult, type AgentSetupInfo, type AgentSetupKind, type AgentStatus, type AgentTurnInput, type AnthropicCacheControl, type AppSettings, type ApplyIntoMainResult, type AttachCommand, type Autonomy, BRIGHTSY_MCP_ALLOWED_TOOLS, type BranchInfo, type BrightsyAccount, type BrightsyChatTarget, type BrightsyChatTargets, type BrightsyCloudConnectAgent, type BrightsyHarnessSettings, type BrightsySession, BrightsySideboardApi, type BrightsyTeamTargets, CLAUDE_MODEL_CATALOG, CLOUD_COORDINATOR_BUSY_REPLY, CLOUD_COORDINATOR_STOPPED_REPLY, CLOUD_COORDINATOR_TIMEOUT_REPLY, CLOUD_ORCHESTRATOR_GOAL, CONTEXT_COMPACT_CHARS, CONTEXT_KEEP_RECENT_CHARS, CONTEXT_KEEP_RECENT_MESSAGES, CONTEXT_MIN_MESSAGES, COORDINATOR_TOOL_PLAYBOOK, type ClaudeHarnessSettings, type CleanupOrphansResult, type CliAgentKind, type CliExecutableSettings, type CloudConnectAgent, type CloudConnectOptions, type CloudConnectStatus, type CompactResult, type CompactThresholds, type ComposerFileBuffer, type ConductorSettings, type ConductorWorkspace, type ConnectedBrightsyTeamInfo, type CreateChatTabInput, type CreateGlobalChatOpts, type CreateStackInput, type CreateThreadInput, type CreateWorktreeResult, type CursorModelInfo, type CursorSdkStreamMessage, type CursorTurnRequest, type CursorWorktreesConfig, type DefaultsAppSettings, type DevServerHandle, type DiffCommentInput, type DiffCommentLine, type DiffCommit, type DiffFile, type DiffResult, type DiffScope, type DiffScopeStat, type ExpandResult, FAMOUS_SOCCER_TEAMS, type ForkChatTabInput, type ForkThreadWorktreeInput, type FormatGhLandErrorOptions, GLOBAL_WORKSPACE_ID, type GetDiffOptions, type GhStackStatus, type GitHubStatus, type GitWorktreeStatus, HARNESS_ENV_KEYS, type HarnessId, type InitStackFromThreadInput, type IntegrationsSettings, type IpcApi, type IssueInfo, type IssueSource, LEGACY_ATTACHMENTS_DIR, LEGACY_PLAN_FILE_REL, LEGACY_REVIEW_REQUEST_PATH, type LandPreview, type LandResult, type ListIssuesResult, MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS, type McpServerStatus, type MessagePart, ORCHESTRATOR_AGENT_KINDS, type OpenPrStackLayersInput, type OpenStackLayerInput, type OpenStackLayerResult, type OrchestrationQuotaOnLimit, Orchestrator, type OrchestratorAgentKind, type OrchestratorEvent, type OrchestratorRuntime, type OrphanWorktree, PASTE_ATTACH_MIN_CHARS, PASTE_ATTACH_MIN_LINES, PLAN_FILE_NAME, PLAN_FILE_REL, PLAN_MODE_INSTRUCTION, type PendingPlanQuestions, type PlanQuestion, type PlanQuestionAnswer, type PlanQuestionOption, type PlanToolPartLike, type PrActor, type PrCheckRun, type PrCommentInfo, type PrCommitInfo, type PrDetails, type PrInfo, type PrMeta, type PrReviewInfo, type PrStack, type PrStackLayer, type PresentedPlan, REPO_REVIEW_NAME, REPO_REVIEW_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PATH, REVIEW_REQUEST_PREFILL, type RepoSettings, type RepoSetupInfo, type RequestReviewResult, type ResolvedReviewGuidelines, type ReviewGuidelinesSource, type RunMode, type RunScript, SIDEBOARD_FORCE_STOP, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_MCP_PROFILE_ENV, type ScriptHandle, type SideboardMcpProfile, type SkillInfo, type SourceType, type SpawnTurnHandle, type SummarizeResult, THINKING_EFFORTS, type TeamName, type ThinkingEffort, type Thread, type ThreadAttachment, type ThreadMessage, type ThreadOptionsPatch, type ThreadStatus, type TokenUsage, type ToolPartLike, type TranscriptToolDetail, type TurnCommand, type Workspace, type WorkspaceInventoryEntry, type WorkspaceScriptEnvOpts, addPrStackLayer, addStackLayerFromThread, addWorkspace, adoptThread, allAdapters, allocatePort, allocatePortRange, allocateTeamName, allocateTeamSlug, appDataDir, appSettingsPath, appendMessage, applyAgentEvent, applyAppEnvironment, applyCompaction, applyThreadIntoMain, assertOrchestratorCapableAgent, attachmentFromAbsolutePath, attachmentsFromBuffers, attachmentsFromWorktreePaths, attachmentsGitignoreBody, autoArchiveOnMergeEnabled, autoCleanupOrphansEnabled, autoRenameBranchEnabled, autoRunAfterSetupEnabled, branchDisplayLabel, brightsyAdapter, brightsyCloudConnectAgent, brightsyCloudConnectEnabled, brightsyConfigPath, brightsyInjectWorktreeMcpEnabled, brightsyMcpAllowedTools, brightsyMcpServerName, buildCachedUserContent, buildClaudeStreamJsonUserMessage, buildDiffCommentAttachment, buildForkTranscriptAttachment, buildPastedTextAttachment, buildReviewRequestAttachment, buildSessionSeed, buildWorkspaceScriptEnv, caffeinateWhileCloudConnectEnabled, caffeinateWhileRunningEnabled, captureLoginEnv, captureTurnBaseline, checkoutPrStackLayer, childEnvWithAppSettings, claudeAdapter, claudeChromeEnabled, claudeUserSettingsPath, cleanupOrphanWorktrees, cloneRepoIntoSideboard, codexAdapter, coerceOrchestratorAgent, collectTakenTeamSlugs, commitAll, conductorBundledBinDir, conductorDbPath, confirmLand, connectBrightsyTeam, coordinatorSystemPrompt, coordinatorTurnReminder, copyConfiguredFiles, countCacheControlBlocks, createChatTab, createEmptyThread, createExistingBranchWorktree, createGlobalChat, createOrUpdatePr, createPrStack, createThread, createThreadWorktree, currentBranch, cursorAdapter, cursorSdkMessageToEvents, decodeBrightsyTarget, deleteBranchOnPurgeEnabled, deleteThreadRecord, detectAgents, detectGhStack, detectLocalMergeConflicts, disconnectBrightsyTeam, discoverSkills, dropCachedPrefixOnResume, encodeBrightsyTarget, enrichPathWithNpmGlobalBin, enrichWorkspacesWithGithub, ensureAgentPath, ensureCloudCoordinator, ensureGhPreferOrigin, ensureGlobalCoordinatorCwd, ensureReviewRequestFile, ensureWorkspace, estimateMessageChars, estimateThreadChars, expandComposerPrompt, extractGhErrorDetail, extractPendingPlanQuestions, extractPresentedPlan, extractiveSummary, fetchPrHead, finalizeParts, findInvalidCacheControlTtlOrder, findOrphanWorktrees, findThreadByRef, findThreadForStackLayer, flattenTurnInput, forkChatTab, forkMessageSlice, forkThreadWorktree, formatAgentInstructions, formatArtifactDirective, formatBrightsyFetchError, formatGhLandError, formatIpcInvokeError, formatMessagesAsTranscript, formatPlanQuestionAnswers, formatPlanQuestionsForChat, formatRateLimitResetHint, formatRenameBranchDirective, formatTranscriptMarkdown, formatWorkspaceInventory, formatWorktreeDirective, formatWorktreeReminder, getAdapter, getAgentSetupInfo, getBrightsySession, getDefaultAgent, getDefaultEffort, getDefaultFast, getDefaultModel, getDefaultRunScript, getDiff, getDiffSummary, getGitHubStatus, getIssueSource, getLinearApiKey, getOrchestrator, getPr, getPrChecks, getPrDetails, getPrMeta, getPrStack, getRepoSetupInfo, getRunMode, getRunScript, gh, ghHeadRef, ghRepoSelectArgs, git, globalAgentCwd, harnessEnvKey, hasConductorHook, hasCursorWorktreeSetup, hasRepoHook, hasWorkspaceHook, healOrchestrationSoccerTitles, importConductorWorkspace, importConductorWorkspaceAsync, initPrStack, initStackFromThread, initializeGitRepository, inspectGitWorktree, installAgent, isAskUserToolName, isBrightsyConnected, isBrightsyNdjsonLine, isCloudCoordinatorThread, isConductorBundledCli, isCursorAutoModel, isDirty, isGhRateLimitError, isGlobalRepoPath, isGlobalThread, isImageFilePath, isInPrStack, isLinearConnected, isOrchestratorCapableAgent, isOrchestratorThread, isPidAlive, isPlaceholderBranch, isPresentPlanToolName, isSessionQuotaLimit, isSideboardScratchPath, isThinkingEffort, isWorkspaceScratchPath, listAgentSetupInfo, listBranchCommits, listBranches, listBrightsyAccounts, listBrightsyChatTargets, listCodexModels, listConductorWorkspaces, listConnectedBrightsyTeams, listCursorModels, listGitHubIssues, listGlobalThreads, listIssues, listLinearIssues, listLinearIssuesDirect, listModelsForAgent, listOpencodeModels, listPrs, listRunScripts, listThreads, listWorkspaces, listWorktreeFiles, listWorktrees, loadAgentInstructions, loadAppSettings, loadBrightsyConfig, loadConductorSettings, loadRepoSettings, loadWorkspaceSettings, locksDir, loginAgent, lookupSoccerTeam, maxConcurrentAgents, maybeCompactContext, mcpAllowTools, mcpAuthWarnings, mergePr, mergePrStack, mergeUsage, nextPastedTextName, nextThinkingEffort, normalizeParseResult, normalizeThinkingEffort, normalizeThread, normalizeTurnInput, normalizeWorktreePath, openInSystemTerminal, openPrStackLayers, openStackLayer, opencodeAdapter, orchestrationQuotaFallbackAgent, orchestrationQuotaOnLimit, orchestrationTitleNeedsSoccerNickname, orchestratorSessionPoisonedByBuiltins, originGhRepoEnv, parseCursorRunnerLine, parseForceStopMessage, parseGhStackViewJson, parseGithubSlugFromRemoteUrl, parseMcpList, parsePlanQuestionsInput, parseSessionQuotaResetAt, partsToAssistantText, pastedTextStats, permissionMode, planFileAbs, posixShellSingleQuote, prepareTerminalCommand, previewLand, promptMentionsBrightsy, pushBranch, readExistingReviewRequestFile, readPlanFile, readSkillBody, readThread, readWorktreeFile, readWorktreeFileForUpload, readWorktreeInclude, refreshGitHubAuth, removeWorkspace, removeWorktree, repoSlug, requestReview, requireAgent, resetGhStackDetectCache, resolveAgentExecutable, resolveClaudeExecutable, resolveCommandBinarySync, resolveConductorCursorAgentId, resolveCursorModelId, resolveDefaultBranch, resolveDiffBaseRef, resolveEffectiveIssueSource, resolveFilesToCopy, resolveGhAuthToken, resolveGithubRepoSlug, resolveLoginCommand, resolveNewThreadOptions, resolvePlanMarkdown, resolvePrSelector, resolveQuotaFallbackAgent, resolveRepoRoot, resolveReviewGuidelines, resolveThreadDefaults, resolveThreadEffort, resolveWorktreeStartPoint, run, runArchiveScript, runCloudConnect, runCursorWorktreeSetup, runSetupScript, sameWorktreePath, sanitizeMcpServerName, saveAppSettings, setStatus, settingsSourceLabel, shouldAttachPastedText, shouldCompactContext, shouldInjectBrightsyMcp, shouldRefreshReviewRequestTemplate, shouldRunWorktreeCleanup, sideboardHomeDir, sideboardMcpProfile, sideboardReposDir, sideboardWorkspacesDir, slugify, spawnAgentTurn, splitForCompaction, stackAgentDefaultsFrom, stackIdFrom, stackMergeReadiness, stageAbsolutePathsAsAttachments, stageBuffersAsAttachments, startDevServer, startMcpServer, startOrchestration, stripBrightsyNdjsonNoise, submitPrStack, suggestSlug, summarizeConversation, switchBrightsyAccount, syncWorkspacesFromThreads, takenTeamSlugsForChatTab, takenTeamSlugsForOrchestration, taskMessageText, thinkingEffortBars, thinkingEffortLabel, threadDisplayLabel, threadFilePath, threadLockPath, threadRequestsBrightsyMcp, threadsDir, threadsSharingWorktree, toolDescription, toolDetail, toolFilePath, totalTokens, updateAdvancedSettings, updateAgentExecutable, updateAppEnvironment, updateBrightsySettings, updateClaudeSettings, updateCodexSettings, updateDefaultsSettings, updateIntegrationsSettings, updateOpencodeSettings, updateThread, validateLinearApiKey, withAgentInstructions, withExportedPath, withThreadLock, workspaceSettingsSourceLabel, worktreeCleanupSettings, worktreeDisplayLabel, worktreeDisplayLabelForGroup, worktreeNameFromPath, worktreesRoot, writeInjectedMcpConfig, writePlanFile, writeThread, writeWorktreeFile };
3762
+ /** Public WebSocket URL for the hosted Slack inbound relay (path included). */
3763
+ declare const BAKED_SLACK_RELAY_URL = "wss://slack-relay.sideboard.cloud/desktop";
3764
+ declare function hasBakedSlackOAuth(): boolean;
3765
+ /**
3766
+ * Relay URL for inbound Slack when this Mac has no local xapp-.
3767
+ * Override with SIDEBOARD_SLACK_RELAY_URL for local relay testing.
3768
+ */
3769
+ declare function slackRelayUrl(): string;
3770
+
3771
+ /** Fixed port so the Slack app redirect URI can be registered once. */
3772
+ declare const SLACK_OAUTH_PORT = 19847;
3773
+ declare const SLACK_OAUTH_REDIRECT = "http://127.0.0.1:19847/callback";
3774
+ declare function slackOAuthCredentials(): {
3775
+ clientId: string;
3776
+ clientSecret: string;
3777
+ };
3778
+ /**
3779
+ * Open Slack OAuth in the browser, listen on a localhost callback, store tokens.
3780
+ */
3781
+ declare function startSlackOAuth(opts?: {
3782
+ openUrl?: (url: string) => void | Promise<void>;
3783
+ timeoutMs?: number;
3784
+ }): Promise<SlackWorkspaceInfo>;
3785
+
3786
+ /** Minimal WebSocket surface so tests can inject a fake without DOM lib types. */
3787
+ interface SlackWebSocket {
3788
+ send(data: string): void;
3789
+ close(code?: number, reason?: string): void;
3790
+ addEventListener(type: 'open' | 'message' | 'error' | 'close', listener: (ev: {
3791
+ data?: unknown;
3792
+ }) => void): void;
3793
+ }
3794
+ type SlackWebSocketCtor = new (url: string) => SlackWebSocket;
3795
+ interface SlackInboundMessage {
3796
+ teamId: string;
3797
+ channelId: string;
3798
+ ts: string;
3799
+ threadTs?: string;
3800
+ userId?: string;
3801
+ text: string;
3802
+ kind: 'dm' | 'mention';
3803
+ }
3804
+ interface SlackSocketModeOptions {
3805
+ appToken: string;
3806
+ signal?: AbortSignal;
3807
+ onLog?: (line: string) => void;
3808
+ onEvent: (msg: SlackInboundMessage) => void | Promise<void>;
3809
+ fetchImpl?: typeof fetch;
3810
+ WebSocketImpl?: SlackWebSocketCtor;
3811
+ }
3812
+
3813
+ declare const SLACK_LISTEN_BUSY_REPLY: string;
3814
+ declare const SLACK_LISTEN_STOPPED_REPLY = "Sideboard stopped the in-progress turn. Send another message when you want to continue.";
3815
+ declare const SLACK_LISTEN_TIMEOUT_REPLY: string;
3816
+ interface SlackListenOptions {
3817
+ agent?: AgentKind;
3818
+ signal?: AbortSignal;
3819
+ onLog?: (line: string) => void;
3820
+ /** Override hosted relay URL (tests / local relay). */
3821
+ relayUrl?: string;
3822
+ fetchImpl?: typeof fetch;
3823
+ WebSocketImpl?: SlackSocketModeOptions['WebSocketImpl'];
3824
+ /** Tests: handle without talking to Slack Web API. */
3825
+ postReply?: (msg: SlackInboundMessage, text: string) => Promise<void>;
3826
+ /** Tests: ack reactions without talking to Slack Web API. */
3827
+ addReaction?: (msg: SlackInboundMessage, name: string) => Promise<void>;
3828
+ }
3829
+ declare function formatSlackInboundPrompt(msg: SlackInboundMessage): string;
3830
+ /**
3831
+ * Prefix Slack replies with This Mac's destination (`Work: …`) so a user with
3832
+ * more than one device can see who answered and address follow-ups the same way.
3833
+ */
3834
+ declare function formatSlackSignedReply(deviceLabel: string, text: string): string;
3835
+ /** Slack emoji short name for “seen / got it”. */
3836
+ declare const SLACK_SEEN_REACTION = "+1";
3837
+ /** Thumbs-up the inbound message so Slack shows the bot saw it. */
3838
+ declare function ackSlackInboundSeen(msg: SlackInboundMessage, opts: Pick<SlackListenOptions, 'addReaction' | 'fetchImpl' | 'onLog'>): Promise<void>;
3839
+ declare function handleSlackInbound(msg: SlackInboundMessage, opts: SlackListenOptions): Promise<void>;
3840
+ /**
3841
+ * Only handle Slack events for Slack users who connected this Sideboard
3842
+ * (OAuth authed_user). Other people messaging the bot must run their own Mac.
3843
+ */
3844
+ declare function isInboundForThisDesktop(msg: SlackInboundMessage): boolean;
3845
+ /**
3846
+ * Sideboard-native Slack inbound via the hosted relay.
3847
+ * The Mac never holds an app-level `xapp-` token.
3848
+ */
3849
+ declare function runSlackListen(opts?: SlackListenOptions): Promise<void>;
3850
+ /** How Listen will receive Slack events on this machine. */
3851
+ declare function resolveSlackListenMode(opts?: {
3852
+ relayUrl?: string | null;
3853
+ workspaceCount?: number;
3854
+ }): 'relay' | null;
3855
+
3856
+ interface SlackAuthTest {
3857
+ ok: boolean;
3858
+ url?: string;
3859
+ team?: string;
3860
+ user?: string;
3861
+ team_id?: string;
3862
+ user_id?: string;
3863
+ bot_id?: string;
3864
+ }
3865
+
3866
+ /** Desktop → relay */
3867
+ type SlackRelayClientMessage = {
3868
+ type: 'register';
3869
+ teamId: string;
3870
+ /** Slack user who owns this Sideboard (from OAuth authed_user). */
3871
+ userId: string;
3872
+ /** Stable per-Mac id so Personal and Work can both stay connected. */
3873
+ deviceId: string;
3874
+ /** Human label, e.g. "Personal" / "Work". */
3875
+ deviceLabel?: string;
3876
+ botToken: string;
3877
+ /** User token proves identity (auth.test user_id must match). */
3878
+ userToken: string;
3879
+ } | {
3880
+ type: 'claim';
3881
+ eventId: string;
3882
+ } | {
3883
+ type: 'ping';
3884
+ };
3885
+ /** Relay → desktop */
3886
+ type SlackRelayServerMessage = {
3887
+ type: 'registered';
3888
+ teamId: string;
3889
+ userId: string;
3890
+ deviceId: string;
3891
+ } | {
3892
+ type: 'event';
3893
+ eventId: string;
3894
+ message: SlackInboundMessage;
3895
+ } | {
3896
+ type: 'claim_ok';
3897
+ eventId: string;
3898
+ } | {
3899
+ type: 'claim_denied';
3900
+ eventId: string;
3901
+ } | {
3902
+ type: 'error';
3903
+ message: string;
3904
+ } | {
3905
+ type: 'pong';
3906
+ };
3907
+ declare function parseSlackRelayClientMessage(raw: string): SlackRelayClientMessage | null;
3908
+ declare function parseSlackRelayServerMessage(raw: string): SlackRelayServerMessage | null;
3909
+
3910
+ interface SlackRelaySocket {
3911
+ send(data: string): void;
3912
+ close(code?: number, reason?: string): void;
3913
+ }
3914
+ interface SlackRelaySession {
3915
+ id: string;
3916
+ teamId: string;
3917
+ userId: string;
3918
+ deviceId: string;
3919
+ deviceLabel: string;
3920
+ socket: SlackRelaySocket;
3921
+ connectedAt: number;
3922
+ }
3923
+ interface SlackRelayHubOptions {
3924
+ fetchImpl?: typeof fetch;
3925
+ /** Inject auth.test for tests. */
3926
+ authTest?: (token: string) => Promise<Pick<SlackAuthTest, 'team_id' | 'user_id' | 'ok'>>;
3927
+ onLog?: (line: string) => void;
3928
+ }
3929
+ /**
3930
+ * In-memory registry of desktop sessions keyed by team + Slack user + device.
3931
+ * Personal and Work Macs can both stay online. Inbound events fan out to the
3932
+ * matching destination(s); the first device to claim handles the turn.
3933
+ */
3934
+ declare class SlackRelayHub {
3935
+ private readonly sessions;
3936
+ private readonly bySocket;
3937
+ private readonly pendingClaims;
3938
+ private seq;
3939
+ private readonly fetchImpl?;
3940
+ private readonly authTest;
3941
+ private readonly log;
3942
+ constructor(opts?: SlackRelayHubOptions);
3943
+ sessionFor(teamId: string, userId: string, deviceId: string): SlackRelaySession | null;
3944
+ sessionsForUser(teamId: string, userId: string): SlackRelaySession[];
3945
+ listSessions(): SlackRelaySession[];
3946
+ detachSocket(socket: SlackRelaySocket): void;
3947
+ handleClientMessage(socket: SlackRelaySocket, msg: SlackRelayClientMessage): Promise<void>;
3948
+ register(socket: SlackRelaySocket, teamId: string, userId: string, deviceId: string, deviceLabel: string | undefined, botToken: string, userToken: string): Promise<void>;
3949
+ /**
3950
+ * Fan-out an inbound event to matching device(s) for that Slack user.
3951
+ * Optional leading `Personal:` / `Work:` selects by device label.
3952
+ * Desktops must claim; first claim wins.
3953
+ */
3954
+ routeEvent(message: SlackInboundMessage): boolean;
3955
+ private handleClaim;
3956
+ private send;
3957
+ }
3958
+
3959
+ interface SlackRelayServerOptions {
3960
+ appToken: string;
3961
+ port?: number;
3962
+ host?: string;
3963
+ signal?: AbortSignal;
3964
+ onLog?: (line: string) => void;
3965
+ fetchImpl?: typeof fetch;
3966
+ /** Injected hub (tests). */
3967
+ hub?: SlackRelayHub;
3968
+ }
3969
+ interface SlackRelayServerHandle {
3970
+ port: number;
3971
+ url: string;
3972
+ hub: SlackRelayHub;
3973
+ close: () => Promise<void>;
3974
+ }
3975
+ /**
3976
+ * Hosted Slack inbound relay: one Socket Mode connection (xapp- on the server)
3977
+ * plus desktop WebSocket sessions that register via bot-token auth.test.
3978
+ */
3979
+ declare function startSlackRelayServer(opts: SlackRelayServerOptions): Promise<SlackRelayServerHandle>;
3980
+
3981
+ interface SlackRelayRegisterWorkspace {
3982
+ teamId: string;
3983
+ /** Slack user who owns this Sideboard (OAuth authed_user). */
3984
+ userId: string;
3985
+ botToken: string;
3986
+ userToken: string;
3987
+ }
3988
+ interface SlackRelayClientOptions {
3989
+ /** Full WebSocket URL including path, e.g. wss://slack-relay.sideboard.cloud/desktop */
3990
+ url: string;
3991
+ workspaces: SlackRelayRegisterWorkspace[];
3992
+ /** Stable per-Mac destination id. */
3993
+ deviceId: string;
3994
+ /** Human label shown in relay logs, e.g. Personal / Work. */
3995
+ deviceLabel?: string;
3996
+ signal?: AbortSignal;
3997
+ onEvent: (msg: SlackInboundMessage) => void | Promise<void>;
3998
+ onLog?: (line: string) => void;
3999
+ WebSocketImpl?: SlackWebSocketCtor;
4000
+ }
4001
+ /**
4002
+ * Desktop client: connect to the hosted Slack relay, register this Mac as a
4003
+ * destination for the OAuth Slack user, claim inbound events before handling.
4004
+ */
4005
+ declare function runSlackRelayClient(opts: SlackRelayClientOptions): Promise<void>;
4006
+
4007
+ export { ATTACHMENTS_DIR, type ActiveRun, type AddStackLayerInput, type AdoptInput, type AdvancedAppSettings, type AgentAdapter, type AgentEvent, type AgentInstructionFile, type AgentKind, type AgentModelCatalog, type AgentModelInfo, type AgentSetupActionResult, type AgentSetupInfo, type AgentSetupKind, type AgentStatus, type AgentTurnInput, type AnthropicCacheControl, type AppSettings, type ApplyIntoMainResult, type AttachCommand, type Autonomy, BAKED_SLACK_RELAY_URL, BRIGHTSY_MCP_ALLOWED_TOOLS, type BranchInfo, type BrightsyAccount, type BrightsyChatTarget, type BrightsyChatTargets, type BrightsyCloudConnectAgent, type BrightsyHarnessSettings, type BrightsySession, BrightsySideboardApi, type BrightsyTeamTargets, CLAUDE_MODEL_CATALOG, CLOUD_COORDINATOR_BUSY_REPLY, CLOUD_COORDINATOR_STOPPED_REPLY, CLOUD_COORDINATOR_TIMEOUT_REPLY, CLOUD_ORCHESTRATOR_GOAL, CONTEXT_COMPACT_CHARS, CONTEXT_KEEP_RECENT_CHARS, CONTEXT_KEEP_RECENT_MESSAGES, CONTEXT_MIN_MESSAGES, COORDINATOR_TOOL_PLAYBOOK, type CaffeinateHoldState, type ClaudeHarnessSettings, type CleanupOrphansResult, type CliAgentKind, type CliExecutableSettings, type CloudConnectAgent, type CloudConnectOptions, type CloudConnectStatus, type CompactResult, type CompactThresholds, type ComposerFileBuffer, type ConductorSettings, type ConductorWorkspace, type ConnectedBrightsyTeamInfo, type CreateChatTabInput, type CreateGlobalChatOpts, type CreateStackInput, type CreateThreadInput, type CreateWorktreeResult, type CursorModelInfo, type CursorSdkStreamMessage, type CursorTurnRequest, type CursorWorktreesConfig, type DefaultsAppSettings, type DevServerHandle, type DiffCommentInput, type DiffCommentLine, type DiffCommit, type DiffFile, type DiffResult, type DiffScope, type DiffScopeStat, type ExpandResult, FAMOUS_SOCCER_TEAMS, type ForkChatTabInput, type ForkThreadWorktreeInput, type FormatGhLandErrorOptions, GLOBAL_WORKSPACE_ID, type GetDiffOptions, type GhStackStatus, type GitHubStatus, type GitWorktreeStatus, HARNESS_ENV_KEYS, type HarnessId, type InitStackFromThreadInput, type IntegrationsSettings, type IpcApi, type IssueInfo, type IssueSource, LEGACY_ATTACHMENTS_DIR, LEGACY_PLAN_FILE_REL, LEGACY_REVIEW_REQUEST_PATH, LINEAR_OAUTH_PORT, LINEAR_OAUTH_REDIRECT, LINEAR_OAUTH_SCOPES, type LandPreview, type LandResult, type ListIssuesResult, MAX_ANTHROPIC_CACHE_CONTROL_BLOCKS, type McpServerStatus, type MessagePart, ORCHESTRATOR_AGENT_KINDS, type OpenPrStackLayersInput, type OpenStackLayerInput, type OpenStackLayerResult, type OrchestrationQuotaOnLimit, Orchestrator, type OrchestratorAgentKind, type OrchestratorEvent, type OrchestratorRuntime, type OrphanWorktree, PASTE_ATTACH_MIN_CHARS, PASTE_ATTACH_MIN_LINES, PLAN_FILE_NAME, PLAN_FILE_REL, PLAN_MODE_INSTRUCTION, type PendingPlanQuestions, type PlanQuestion, type PlanQuestionAnswer, type PlanQuestionOption, type PlanToolPartLike, type PrActor, type PrCheckRun, type PrCommentInfo, type PrCommitInfo, type PrDetails, type PrInfo, type PrMeta, type PrReviewInfo, type PrStack, type PrStackLayer, type PresentedPlan, type PublicAppSettings, type PublicIntegrationsSettings, REPO_REVIEW_NAME, REPO_REVIEW_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PATH, REVIEW_REQUEST_PREFILL, type RepoSettings, type RepoSetupInfo, type RequestReviewResult, type ResolvedReviewGuidelines, type ReviewGuidelinesSource, type RunMode, type RunScript, SIDEBOARD_FORCE_STOP, SIDEBOARD_MCP_ALLOWED_TOOLS, SIDEBOARD_MCP_PROFILE_ENV, SLACK_LISTEN_BUSY_REPLY, SLACK_LISTEN_STOPPED_REPLY, SLACK_LISTEN_TIMEOUT_REPLY, SLACK_OAUTH_PORT, SLACK_OAUTH_REDIRECT, SLACK_REPLY_FORMATTING, SLACK_SEEN_REACTION, type ScriptHandle, type SideboardMcpProfile, type SkillInfo, type SlackInboundMessage, type SlackListenOptions, type SlackListenStatus, type SlackOutboundWatch, type SlackRelayClientMessage, type SlackRelayClientOptions, SlackRelayHub, type SlackRelayServerHandle, type SlackRelayServerMessage, type SlackRelayServerOptions, type SlackReplyBadge, type SlackWorkspaceInfo, type SourceType, type SpawnTurnHandle, type SummarizeResult, THINKING_EFFORTS, type TeamName, type ThinkingEffort, type Thread, type ThreadAttachment, type ThreadMessage, type ThreadOptionsPatch, type ThreadStatus, type TokenUsage, type ToolPartLike, type TranscriptToolDetail, type TurnCommand, type Workspace, type WorkspaceInventoryEntry, type WorkspaceScriptEnvOpts, ackSlackInboundSeen, addPrStackLayer, addStackLayerFromThread, addWorkspace, adoptThread, allAdapters, allocatePort, allocatePortRange, allocateTeamName, allocateTeamSlug, appDataDir, appSettingsPath, appendMessage, applyAgentEvent, applyAppEnvironment, applyCompaction, applyThreadIntoMain, assertOrchestratorCapableAgent, attachmentFromAbsolutePath, attachmentsFromBuffers, attachmentsFromWorktreePaths, attachmentsGitignoreBody, autoArchiveOnMergeEnabled, autoCleanupOrphansEnabled, autoRenameBranchEnabled, autoRunAfterSetupEnabled, branchDisplayLabel, brightsyAdapter, brightsyCloudConnectAgent, brightsyCloudConnectEnabled, brightsyConfigPath, brightsyInjectWorktreeMcpEnabled, brightsyMcpAllowedTools, brightsyMcpServerName, buildCachedUserContent, buildClaudeStreamJsonUserMessage, buildDiffCommentAttachment, buildForkTranscriptAttachment, buildPastedTextAttachment, buildReviewRequestAttachment, buildSessionSeed, buildWorkspaceScriptEnv, caffeinateHoldPath, caffeinateWhileCloudConnectEnabled, caffeinateWhileRunningEnabled, caffeinateWhileSlackListenEnabled, captureLoginEnv, captureTurnBaseline, checkoutPrStackLayer, childEnvWithAppSettings, claudeAdapter, claudeChromeEnabled, claudeUserSettingsPath, cleanupOrphanWorktrees, cloneRepoIntoSideboard, codexAdapter, coerceOrchestratorAgent, collectTakenTeamSlugs, commitAll, conductorBundledBinDir, conductorDbPath, confirmLand, connectBrightsyTeam, connectSlackToken, coordinatorSystemPrompt, coordinatorTurnReminder, copyConfiguredFiles, countCacheControlBlocks, createChatTab, createEmptyThread, createExistingBranchWorktree, createGlobalChat, createLinearPkce, createOrUpdatePr, createPrStack, createThread, createThreadWorktree, currentBranch, cursorAdapter, cursorSdkMessageToEvents, decodeBrightsyTarget, deleteBranchOnPurgeEnabled, deleteThreadRecord, detectAgents, detectGhStack, detectLocalMergeConflicts, disconnectBrightsyTeam, disconnectLinear, disconnectLinearConnection, disconnectSlackWorkspace, discoverSkills, dismissSlackReplyBadge, dropCachedPrefixOnResume, encodeBrightsyTarget, enrichPathWithNpmGlobalBin, enrichWorkspacesWithGithub, ensureAgentPath, ensureCloudCoordinator, ensureGhPreferOrigin, ensureGlobalCoordinatorCwd, ensureReviewRequestFile, ensureSlackCoordinator, ensureSlackDeviceIdentity, ensureWorkspace, estimateMessageChars, estimateThreadChars, expandComposerPrompt, extractGhErrorDetail, extractPendingPlanQuestions, extractPresentedPlan, extractiveSummary, fetchPrHead, finalizeParts, findInvalidCacheControlTtlOrder, findOrphanWorktrees, findThreadByRef, findThreadForStackLayer, flattenTurnInput, forkChatTab, forkMessageSlice, forkThreadWorktree, formatAgentInstructions, formatArtifactDirective, formatBrightsyFetchError, formatGhLandError, formatIpcInvokeError, formatMessagesAsTranscript, formatPlanQuestionAnswers, formatPlanQuestionsForChat, formatRateLimitResetHint, formatRenameBranchDirective, formatSlackInboundPrompt, formatSlackSignedReply, formatTranscriptMarkdown, formatWorkspaceInventory, formatWorktreeDirective, formatWorktreeReminder, getAdapter, getAgentSetupInfo, getBrightsySession, getCaffeinateHold, getDefaultAgent, getDefaultEffort, getDefaultFast, getDefaultModel, getDefaultRunScript, getDiff, getDiffSummary, getGitHubStatus, getIssueSource, getLinearApiKey, getLinearAuthToken, getOrchestrator, getPr, getPrChecks, getPrDetails, getPrMeta, getPrStack, getRepoSetupInfo, getRunMode, getRunScript, getSlackWorkspace, gh, ghHeadRef, ghRepoSelectArgs, git, globalAgentCwd, handleSlackInbound, harnessEnvKey, hasBakedLinearOAuth, hasBakedSlackOAuth, hasConductorHook, hasCursorWorktreeSetup, hasRepoHook, hasWorkspaceHook, healOrchestrationSoccerTitles, importConductorWorkspace, importConductorWorkspaceAsync, initPrStack, initStackFromThread, initializeGitRepository, inspectGitWorktree, installAgent, isAskUserToolName, isBrightsyConnected, isBrightsyNdjsonLine, isCloudCoordinatorThread, isConductorBundledCli, isCursorAutoModel, isDirty, isGhRateLimitError, isGlobalRepoPath, isGlobalThread, isImageFilePath, isInPrStack, isInboundForThisDesktop, isLinearConnected, isOrchestratorCapableAgent, isOrchestratorThread, isPidAlive, isPlaceholderBranch, isPresentPlanToolName, isSessionQuotaLimit, isSideboardScratchPath, isSlackCoordinatorThread, isThinkingEffort, isWorkspaceScratchPath, linearAuthorizationHeader, linearOAuthAuthorizeUrl, linearOAuthCredentials, listAgentSetupInfo, listBranchCommits, listBranches, listBrightsyAccounts, listBrightsyChatTargets, listCodexModels, listConductorWorkspaces, listConnectedBrightsyTeams, listCursorModels, listGitHubIssues, listGlobalThreads, listIssues, listLinearIssues, listLinearIssuesDirect, listModelsForAgent, listOpencodeModels, listPrs, listRunScripts, listSlackReplyBadges, listSlackWorkspaces, listThreads, listWorkspaces, listWorktreeFiles, listWorktrees, loadAgentInstructions, loadAppSettings, loadBrightsyConfig, loadConductorSettings, loadRepoSettings, loadWorkspaceSettings, locksDir, loginAgent, lookupSoccerTeam, maxConcurrentAgents, maybeCompactContext, mcpAllowTools, mcpAuthWarnings, mergePr, mergePrStack, mergeUsage, nextPastedTextName, nextThinkingEffort, normalizeParseResult, normalizeThinkingEffort, normalizeThread, normalizeTurnInput, normalizeWorktreePath, openInSystemTerminal, openPrStackLayers, openStackLayer, opencodeAdapter, orchestrationQuotaFallbackAgent, orchestrationQuotaOnLimit, orchestrationTitleNeedsSoccerNickname, orchestratorSessionPoisonedByBuiltins, originGhRepoEnv, parseCursorRunnerLine, parseForceStopMessage, parseGhStackViewJson, parseGithubSlugFromRemoteUrl, parseMcpList, parsePlanQuestionsInput, parseSessionQuotaResetAt, parseSlackRelayClientMessage, parseSlackRelayServerMessage, partsToAssistantText, pastedTextStats, permalinkForSlackReplyBadge, permissionMode, persistVaultKeyInKeychain, planFileAbs, posixShellSingleQuote, prepareTerminalCommand, previewLand, promptMentionsBrightsy, pushBranch, readExistingReviewRequestFile, readKeychainVaultKey, readPlanFile, readSkillBody, readThread, readWorktreeFile, readWorktreeFileForUpload, readWorktreeInclude, recordSlackOutboundWatch, refreshGitHubAuth, refreshSlackReplyBadges, removeWorkspace, removeWorktree, repoSlug, requestReview, requireAgent, resetGhStackDetectCache, resolveAgentExecutable, resolveClaudeExecutable, resolveCommandBinarySync, resolveConductorCursorAgentId, resolveCursorModelId, resolveDefaultBranch, resolveDiffBaseRef, resolveEffectiveIssueSource, resolveFilesToCopy, resolveGhAuthToken, resolveGithubRepoSlug, resolveLoginCommand, resolveNewThreadOptions, resolvePlanMarkdown, resolvePrSelector, resolveQuotaFallbackAgent, resolveRepoRoot, resolveReviewGuidelines, resolveSlackListenMode, resolveThreadDefaults, resolveThreadEffort, resolveVaultKey, resolveWorktreeStartPoint, run, runArchiveScript, runCloudConnect, runCursorWorktreeSetup, runSetupScript, runSlackListen, runSlackRelayClient, sameWorktreePath, sanitizeMcpServerName, saveAppSettings, saveLinearOAuth, secureFileUnlocksWith, setCaffeinateHold, setStatus, setVaultMasterKey, settingsSourceLabel, shouldAttachPastedText, shouldCompactContext, shouldInjectBrightsyMcp, shouldRefreshReviewRequestTemplate, shouldRunWorktreeCleanup, sideboardHomeDir, sideboardMcpProfile, sideboardReposDir, sideboardWorkspacesDir, slackAppLevelToken, slackArchiveUrl, slackCoordinatorSourceRef, slackListenEnabled, slackOAuthCredentials, slackRelayUrl, slugify, spawnAgentTurn, splitForCompaction, stackAgentDefaultsFrom, stackIdFrom, stackMergeReadiness, stageAbsolutePathsAsAttachments, stageBuffersAsAttachments, startDevServer, startLinearOAuth, startMcpServer, startOrchestration, startSlackOAuth, startSlackRelayServer, stripBrightsyNdjsonNoise, submitPrStack, suggestSlug, summarizeConversation, switchBrightsyAccount, syncWorkspacesFromThreads, takenTeamSlugsForChatTab, takenTeamSlugsForOrchestration, taskMessageText, thinkingEffortBars, thinkingEffortLabel, threadDisplayLabel, threadFilePath, threadLockPath, threadRequestsBrightsyMcp, threadsDir, threadsSharingWorktree, toPublicAppSettings, toolDescription, toolDetail, toolFilePath, totalTokens, updateAdvancedSettings, updateAgentExecutable, updateAppEnvironment, updateBrightsySettings, updateClaudeSettings, updateCodexSettings, updateDefaultsSettings, updateIntegrationsSettings, updateOpencodeSettings, updateThread, validateLinearApiKey, withAgentInstructions, withExportedPath, withThreadLock, workspaceSettingsSourceLabel, worktreeCleanupSettings, worktreeDisplayLabel, worktreeDisplayLabelForGroup, worktreeNameFromPath, worktreesRoot, writeInjectedMcpConfig, writePlanFile, writeThread, writeWorktreeFile };