@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
@@ -32,16 +32,16 @@ import {
32
32
  resolveCursorModelId,
33
33
  resolveLoginCommand,
34
34
  resolveQuotaFallbackAgent
35
- } from "./chunk-47RBLBRK.js";
35
+ } from "./chunk-NG7S3OPX.js";
36
36
  import "./chunk-VROPG6QF.js";
37
37
  import {
38
38
  ORCHESTRATOR_AGENT_KINDS,
39
39
  assertOrchestratorCapableAgent,
40
40
  coerceOrchestratorAgent,
41
41
  isOrchestratorCapableAgent
42
- } from "./chunk-OICHV4DH.js";
43
- import "./chunk-N5LMEP65.js";
44
- import "./chunk-REKGFVUX.js";
42
+ } from "./chunk-DGPUAZA4.js";
43
+ import "./chunk-7NCIHRAU.js";
44
+ import "./chunk-OE7YBB5X.js";
45
45
  import "./chunk-B3SJXYIJ.js";
46
46
  import "./chunk-7FD7COKE.js";
47
47
  import {
@@ -53,7 +53,8 @@ import {
53
53
  resolveCommandBinarySync,
54
54
  withExportedPath
55
55
  } from "./chunk-AE5VBOFE.js";
56
- import "./chunk-BPOTVI5J.js";
56
+ import "./chunk-PTJJIQK7.js";
57
+ import "./chunk-NSTQ6QKD.js";
57
58
  import "./chunk-KGZBYWZ3.js";
58
59
  import "./chunk-7MV3RXSC.js";
59
60
  export {
@@ -28,21 +28,22 @@ import {
28
28
  resolveCursorModelId,
29
29
  resolveLoginCommand,
30
30
  resolveQuotaFallbackAgent
31
- } from "./chunk-6Q7H6SMX.js";
31
+ } from "./chunk-S25IHL5H.js";
32
32
  import {
33
33
  ORCHESTRATOR_AGENT_KINDS,
34
34
  assertOrchestratorCapableAgent,
35
35
  coerceOrchestratorAgent,
36
36
  isOrchestratorCapableAgent
37
- } from "./chunk-ROXEENBT.js";
37
+ } from "./chunk-57ROTAFD.js";
38
+ import "./chunk-H2IXNFQ2.js";
38
39
  import "./chunk-BTL7EMGT.js";
39
40
  import {
40
41
  cursorSdkMessageToEvents,
41
42
  parseCursorRunnerLine
42
43
  } from "./chunk-3WJAUKIL.js";
43
- import "./chunk-VX6ACNXS.js";
44
- import "./chunk-MHR4OGZ4.js";
45
- import "./chunk-EEBDVLDK.js";
44
+ import "./chunk-W7YOTDVO.js";
45
+ import "./chunk-JT7R45JB.js";
46
+ import "./chunk-MF2YMEGD.js";
46
47
  import "./chunk-FKOIHGKV.js";
47
48
  import "./chunk-FWJYLBO6.js";
48
49
  import "./chunk-77WWLBCI.js";
@@ -11,10 +11,13 @@ import {
11
11
  brightsyInjectWorktreeMcpEnabled,
12
12
  caffeinateWhileCloudConnectEnabled,
13
13
  caffeinateWhileRunningEnabled,
14
+ caffeinateWhileSlackListenEnabled,
14
15
  childEnvWithAppSettings,
15
16
  claudeChromeEnabled,
16
17
  claudeUserSettingsPath,
17
18
  deleteBranchOnPurgeEnabled,
19
+ disconnectLinearConnection,
20
+ ensureSlackDeviceIdentity,
18
21
  getDefaultAgent,
19
22
  getDefaultEffort,
20
23
  getDefaultFast,
@@ -33,6 +36,10 @@ import {
33
36
  resolveNewThreadOptions,
34
37
  resolveThreadDefaults,
35
38
  saveAppSettings,
39
+ saveLinearOAuth,
40
+ slackAppLevelToken,
41
+ slackListenEnabled,
42
+ toPublicAppSettings,
36
43
  updateAdvancedSettings,
37
44
  updateAgentExecutable,
38
45
  updateAppEnvironment,
@@ -42,7 +49,8 @@ import {
42
49
  updateDefaultsSettings,
43
50
  updateIntegrationsSettings,
44
51
  updateOpencodeSettings
45
- } from "./chunk-MHR4OGZ4.js";
52
+ } from "./chunk-W7YOTDVO.js";
53
+ import "./chunk-JT7R45JB.js";
46
54
  import "./chunk-77WWLBCI.js";
47
55
  import "./chunk-M37RITA6.js";
48
56
  export {
@@ -58,10 +66,13 @@ export {
58
66
  brightsyInjectWorktreeMcpEnabled,
59
67
  caffeinateWhileCloudConnectEnabled,
60
68
  caffeinateWhileRunningEnabled,
69
+ caffeinateWhileSlackListenEnabled,
61
70
  childEnvWithAppSettings,
62
71
  claudeChromeEnabled,
63
72
  claudeUserSettingsPath,
64
73
  deleteBranchOnPurgeEnabled,
74
+ disconnectLinearConnection,
75
+ ensureSlackDeviceIdentity,
65
76
  getDefaultAgent,
66
77
  getDefaultEffort,
67
78
  getDefaultFast,
@@ -80,6 +91,10 @@ export {
80
91
  resolveNewThreadOptions,
81
92
  resolveThreadDefaults,
82
93
  saveAppSettings,
94
+ saveLinearOAuth,
95
+ slackAppLevelToken,
96
+ slackListenEnabled,
97
+ toPublicAppSettings,
83
98
  updateAdvancedSettings,
84
99
  updateAgentExecutable,
85
100
  updateAppEnvironment,
@@ -13,10 +13,13 @@ import {
13
13
  brightsyInjectWorktreeMcpEnabled,
14
14
  caffeinateWhileCloudConnectEnabled,
15
15
  caffeinateWhileRunningEnabled,
16
+ caffeinateWhileSlackListenEnabled,
16
17
  childEnvWithAppSettings,
17
18
  claudeChromeEnabled,
18
19
  claudeUserSettingsPath,
19
20
  deleteBranchOnPurgeEnabled,
21
+ disconnectLinearConnection,
22
+ ensureSlackDeviceIdentity,
20
23
  getDefaultAgent,
21
24
  getDefaultEffort,
22
25
  getDefaultFast,
@@ -35,6 +38,10 @@ import {
35
38
  resolveNewThreadOptions,
36
39
  resolveThreadDefaults,
37
40
  saveAppSettings,
41
+ saveLinearOAuth,
42
+ slackAppLevelToken,
43
+ slackListenEnabled,
44
+ toPublicAppSettings,
38
45
  updateAdvancedSettings,
39
46
  updateAgentExecutable,
40
47
  updateAppEnvironment,
@@ -44,7 +51,8 @@ import {
44
51
  updateDefaultsSettings,
45
52
  updateIntegrationsSettings,
46
53
  updateOpencodeSettings
47
- } from "./chunk-BPOTVI5J.js";
54
+ } from "./chunk-PTJJIQK7.js";
55
+ import "./chunk-NSTQ6QKD.js";
48
56
  import "./chunk-KGZBYWZ3.js";
49
57
  import "./chunk-7MV3RXSC.js";
50
58
  export {
@@ -60,10 +68,13 @@ export {
60
68
  brightsyInjectWorktreeMcpEnabled,
61
69
  caffeinateWhileCloudConnectEnabled,
62
70
  caffeinateWhileRunningEnabled,
71
+ caffeinateWhileSlackListenEnabled,
63
72
  childEnvWithAppSettings,
64
73
  claudeChromeEnabled,
65
74
  claudeUserSettingsPath,
66
75
  deleteBranchOnPurgeEnabled,
76
+ disconnectLinearConnection,
77
+ ensureSlackDeviceIdentity,
67
78
  getDefaultAgent,
68
79
  getDefaultEffort,
69
80
  getDefaultFast,
@@ -82,6 +93,10 @@ export {
82
93
  resolveNewThreadOptions,
83
94
  resolveThreadDefaults,
84
95
  saveAppSettings,
96
+ saveLinearOAuth,
97
+ slackAppLevelToken,
98
+ slackListenEnabled,
99
+ toPublicAppSettings,
85
100
  updateAdvancedSettings,
86
101
  updateAgentExecutable,
87
102
  updateAppEnvironment,
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env node
2
+
3
+ import {
4
+ writePrivateFile
5
+ } from "./chunk-NSTQ6QKD.js";
6
+ import {
7
+ appDataDir
8
+ } from "./chunk-7MV3RXSC.js";
9
+
10
+ // src/store/caffeinate-hold.ts
11
+ import { spawn } from "child_process";
12
+ import { existsSync, readFileSync, unlinkSync } from "fs";
13
+ import { join } from "path";
14
+ var hooks = {};
15
+ function setCaffeinateHoldHooks(next) {
16
+ hooks = next;
17
+ }
18
+ function caffeinateHoldPath() {
19
+ return join(appDataDir(), "caffeinate-hold.json");
20
+ }
21
+ function processAlive(pid) {
22
+ if (hooks.processAlive) return hooks.processAlive(pid);
23
+ try {
24
+ process.kill(pid, 0);
25
+ return true;
26
+ } catch {
27
+ return false;
28
+ }
29
+ }
30
+ function killPid(pid) {
31
+ if (hooks.kill) {
32
+ hooks.kill(pid);
33
+ return;
34
+ }
35
+ try {
36
+ process.kill(pid, "SIGTERM");
37
+ } catch {
38
+ }
39
+ }
40
+ function readHold() {
41
+ const path = caffeinateHoldPath();
42
+ if (!existsSync(path)) return null;
43
+ try {
44
+ const parsed = JSON.parse(readFileSync(path, "utf8"));
45
+ if (typeof parsed?.pid === "number" && parsed.pid > 0) return parsed;
46
+ } catch {
47
+ }
48
+ return null;
49
+ }
50
+ function writeHold(pid) {
51
+ writePrivateFile(caffeinateHoldPath(), `${JSON.stringify({ pid })}
52
+ `);
53
+ }
54
+ function clearHold() {
55
+ try {
56
+ unlinkSync(caffeinateHoldPath());
57
+ } catch {
58
+ }
59
+ }
60
+ function getCaffeinateHold() {
61
+ const platform = hooks.platform ?? process.platform;
62
+ const hold = readHold();
63
+ if (!hold) {
64
+ return { held: false, pid: null, running: false, platform };
65
+ }
66
+ const running = processAlive(hold.pid);
67
+ if (!running) {
68
+ clearHold();
69
+ return { held: false, pid: null, running: false, platform };
70
+ }
71
+ return { held: true, pid: hold.pid, running: true, platform };
72
+ }
73
+ function setCaffeinateHold(enabled) {
74
+ const platform = hooks.platform ?? process.platform;
75
+ const current = getCaffeinateHold();
76
+ if (!enabled) {
77
+ if (current.pid) killPid(current.pid);
78
+ clearHold();
79
+ return { held: false, pid: null, running: false, platform };
80
+ }
81
+ if (current.running && current.pid) return current;
82
+ if (platform !== "darwin") {
83
+ return { held: false, pid: null, running: false, platform };
84
+ }
85
+ const spawnImpl = hooks.spawn ?? spawn;
86
+ const child = spawnImpl("caffeinate", ["-dimsu"], {
87
+ detached: true,
88
+ stdio: "ignore"
89
+ });
90
+ const pid = child.pid;
91
+ if (!pid) {
92
+ try {
93
+ child.kill();
94
+ } catch {
95
+ }
96
+ return { held: false, pid: null, running: false, platform };
97
+ }
98
+ child.unref();
99
+ writeHold(pid);
100
+ return { held: true, pid, running: true, platform };
101
+ }
102
+ export {
103
+ caffeinateHoldPath,
104
+ getCaffeinateHold,
105
+ setCaffeinateHold,
106
+ setCaffeinateHoldHooks
107
+ };
@@ -0,0 +1,14 @@
1
+ import {
2
+ caffeinateHoldPath,
3
+ getCaffeinateHold,
4
+ setCaffeinateHold,
5
+ setCaffeinateHoldHooks
6
+ } from "./chunk-JAWEDVVA.js";
7
+ import "./chunk-JT7R45JB.js";
8
+ import "./chunk-M37RITA6.js";
9
+ export {
10
+ caffeinateHoldPath,
11
+ getCaffeinateHold,
12
+ setCaffeinateHold,
13
+ setCaffeinateHoldHooks
14
+ };
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  isGlobalRepoPath
3
- } from "./chunk-ROXEENBT.js";
3
+ } from "./chunk-57ROTAFD.js";
4
4
  import {
5
5
  ensureGhPreferOrigin,
6
6
  resolveRepoRoot
7
- } from "./chunk-EEBDVLDK.js";
7
+ } from "./chunk-MF2YMEGD.js";
8
8
  import {
9
9
  appDataDir
10
10
  } from "./chunk-M37RITA6.js";
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  ensureGlobalCoordinatorCwd
3
- } from "./chunk-VX6ACNXS.js";
3
+ } from "./chunk-H2IXNFQ2.js";
4
4
  import {
5
5
  resolveNewThreadOptions,
6
6
  resolveThreadDefaults
7
- } from "./chunk-MHR4OGZ4.js";
7
+ } from "./chunk-W7YOTDVO.js";
8
8
  import {
9
9
  allocateTeamName,
10
10
  takenSlugsFromThread,
11
11
  teamSlugFromName
12
- } from "./chunk-EEBDVLDK.js";
12
+ } from "./chunk-MF2YMEGD.js";
13
13
  import {
14
14
  createEmptyThread,
15
15
  listThreads,
@@ -190,6 +190,62 @@ function findCloudCoordinator() {
190
190
  (t) => t.status !== "archived" && isCloudCoordinatorThread(t)
191
191
  );
192
192
  }
193
+ function slackCoordinatorSourceRef(teamId, userId) {
194
+ const team = teamId.trim();
195
+ const user = userId.trim();
196
+ if (!team || !user) {
197
+ throw new Error("Slack coordinator needs teamId and userId");
198
+ }
199
+ return `slack:${team}:${user}`;
200
+ }
201
+ function isSlackCoordinatorThread(thread) {
202
+ const ref = thread.sourceRef?.trim() ?? "";
203
+ if (!ref.startsWith("slack:")) return false;
204
+ return isGlobalThread(thread) || thread.sourceType === "orchestration";
205
+ }
206
+ function findSlackCoordinator(teamId, userId) {
207
+ const ref = slackCoordinatorSourceRef(teamId, userId);
208
+ return listThreads({ includeArchived: true }).find(
209
+ (t) => t.status !== "archived" && t.sourceRef === ref && isSlackCoordinatorThread(t)
210
+ );
211
+ }
212
+ function ensureSlackCoordinator(teamId, userId, agent) {
213
+ const defaults = resolveThreadDefaults();
214
+ const desired = assertOrchestratorCapableAgent(agent);
215
+ const ref = slackCoordinatorSourceRef(teamId, userId);
216
+ const existing = findSlackCoordinator(teamId, userId);
217
+ if (existing) {
218
+ const patch = {};
219
+ if (existing.repoPath !== GLOBAL_WORKSPACE_ID) {
220
+ patch.repoPath = GLOBAL_WORKSPACE_ID;
221
+ patch.worktreePath = globalAgentCwd();
222
+ patch.branchName = "global";
223
+ }
224
+ const hasAgentTurns = existing.messages.some((m) => m.role === "agent");
225
+ const canRetarget = !existing.sessionId && !hasAgentTurns && existing.status !== "running" && existing.status !== "queued";
226
+ if (canRetarget) {
227
+ if (existing.agent !== desired) patch.agent = desired;
228
+ if (existing.model !== defaults.model) patch.model = defaults.model;
229
+ if (existing.effort !== defaults.effort) patch.effort = defaults.effort;
230
+ if (existing.fast !== defaults.fast) patch.fast = defaults.fast;
231
+ }
232
+ if (Object.keys(patch).length > 0) {
233
+ return updateThread(existing.id, patch);
234
+ }
235
+ return existing;
236
+ }
237
+ const created = createGlobalChat({
238
+ sourceRef: ref,
239
+ agent: desired,
240
+ model: defaults.model,
241
+ effort: defaults.effort,
242
+ fast: defaults.fast
243
+ });
244
+ const all = listThreads({ includeArchived: true }).filter(
245
+ (t) => t.status !== "archived" && t.sourceRef === ref && isSlackCoordinatorThread(t)
246
+ ).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
247
+ return all[0] ?? created;
248
+ }
193
249
  function ensureCloudCoordinator(agent) {
194
250
  const defaults = resolveThreadDefaults();
195
251
  const desired = assertOrchestratorCapableAgent(agent);
@@ -249,5 +305,8 @@ export {
249
305
  createGlobalChat,
250
306
  healOrchestrationSoccerTitles,
251
307
  listGlobalThreads,
308
+ slackCoordinatorSourceRef,
309
+ isSlackCoordinatorThread,
310
+ ensureSlackCoordinator,
252
311
  ensureCloudCoordinator
253
312
  };
@@ -2,10 +2,10 @@
2
2
 
3
3
  import {
4
4
  resolveGithubRepoSlug
5
- } from "./chunk-REKGFVUX.js";
5
+ } from "./chunk-OE7YBB5X.js";
6
6
  import {
7
7
  resolveThreadDefaults
8
- } from "./chunk-BPOTVI5J.js";
8
+ } from "./chunk-PTJJIQK7.js";
9
9
  import {
10
10
  globalAgentCwd,
11
11
  sideboardReposDir
@@ -47,9 +47,12 @@ var COORDINATOR_TOOL_PLAYBOOK = [
47
47
  "Discover:",
48
48
  "- list_workspaces \u2014 registered repos (path + github slug when known)",
49
49
  "- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear API or GitHub Issues)",
50
+ "- list_teams / slack_list_channels / slack_list_users / slack_search / slack_read / slack_post \u2014 Slack workspaces from Account settings; pass team_id from list_teams",
51
+ "- Slack notify (only when the user asks): list_teams \u2192 slack_list_users or slack_list_channels \u2192 slack_post with to=@user or #channel and optional github_url (PR, blob permalink, or review/issue comment). Do not notify proactively.",
50
52
  "- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
51
53
  "- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
52
54
  "- list_threads / get_thread \u2014 fleet status (what is going on)",
55
+ "- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for Slack / away-from-keyboard work. Turn OFF when the user says they are done, wrapping up, going to sleep, or no longer need the machine awake.",
53
56
  "Workspaces:",
54
57
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
55
58
  "Worktree threads (chats):",
@@ -71,6 +74,13 @@ var COORDINATOR_TOOL_PLAYBOOK = [
71
74
  "Thread links in replies: when mentioning a chat/thread for the user, include a markdown link `[Title](sideboard://thread/<id>)` using the full id (or the link field from create_thread / list_threads). Sideboard renders these as clickable opens.",
72
75
  "Bash / Read / etc: allowed for (1) inspecting target worktrees / registered repo paths from MCP, and (2) greenfield setup under ~/sideboard/repos (git clone, gh repo create, git init+remote). Never git init/clone *inside* this synthetic home cwd \u2014 emptiness here is expected, not a bug."
73
76
  ].join("\n");
77
+ var SLACK_REPLY_FORMATTING = [
78
+ "Slack formatting (mandatory \u2014 your reply is posted verbatim to Slack):",
79
+ "- Use Slack mrkdwn, NOT GitHub/CommonMark markdown. Slack does not render `**bold**`, `# headings`, or `[label](url)`.",
80
+ "- Bold: *text* (single asterisks). Italic: _text_. Strikethrough: ~text~. Inline code: `code`.",
81
+ "- Links: <https://example.com|label> or bare URLs. Thread ids: plain `sideboard://thread/<id>` (no markdown link syntax).",
82
+ "- Prefer short paragraphs and *bold* section labels over markdown headings or bullet trees with `**`."
83
+ ].join("\n");
74
84
  function accountDefaultsPlaybookLine() {
75
85
  const d = resolveThreadDefaults();
76
86
  const model = d.model?.trim() || "Auto";
@@ -91,7 +101,8 @@ function coordinatorTurnReminder(opts) {
91
101
  `- For "what's going on": call list_threads (and list_workspaces if needed). Summarize fleet status \u2014 do not ls/git-status this synthetic home.`,
92
102
  "- Existing repo: create_thread on a repoPath \u2192 send_to_thread \u2192 wait_for_turn.",
93
103
  "- New repo: Bash (clone or gh repo create under ~/sideboard/repos/<name>) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 draft PR.",
94
- "- When naming threads for the user, link them as `[Title](sideboard://thread/<id>)`."
104
+ "- When naming threads for the user, link them as `[Title](sideboard://thread/<id>)`.",
105
+ "- If they will wait on Slack or leave the Mac, call set_caffeinate enabled=true. When they say they are done / wrapping up / going to sleep, call set_caffeinate enabled=false."
95
106
  ].filter(Boolean).join("\n");
96
107
  }
97
108
  function ensureGlobalCoordinatorCwd(opts) {
@@ -159,8 +170,14 @@ function coordinatorSystemPrompt(opts) {
159
170
  const audience = opts.audience ?? "cloud";
160
171
  const reposDir = sideboardReposDir();
161
172
  const intro = audience === "cloud" ? [
162
- "You are a Sideboard coordinator responding to a request from a Brightsy cloud agent (Slack, Discord, Teams, or other chat).",
173
+ "You are a Sideboard coordinator responding to a request from a Brightsy cloud agent (Discord, Teams, or other chat).",
163
174
  "Your reply will be sent back to that cloud agent \u2014 be concise and actionable."
175
+ ] : audience === "slack" ? [
176
+ "You are a Sideboard coordinator responding to a Slack DM or @mention via the Sideboard Slack app.",
177
+ "Your reply will be posted back in Slack \u2014 be concise and actionable.",
178
+ "Sideboard signs the Slack reply with this Mac's destination name (Personal / Work). Do not prefix that name yourself.",
179
+ "Call set_caffeinate enabled=true when they start a stretch of remote work so the Mac stays awake. Call set_caffeinate enabled=false when they say they are done, wrapping up, or going to sleep.",
180
+ SLACK_REPLY_FORMATTING
164
181
  ] : [
165
182
  "You are a Sideboard orchestration agent: you oversee worktree agents across registered workspaces in the Sideboard app.",
166
183
  "Stay concise and actionable; prefer Sideboard MCP for fleet status; use Bash for greenfield repo setup and inspecting target worktree paths."
@@ -188,6 +205,7 @@ export {
188
205
  enrichWorkspacesWithGithub,
189
206
  coordinatorGreenfieldPlaybook,
190
207
  COORDINATOR_TOOL_PLAYBOOK,
208
+ SLACK_REPLY_FORMATTING,
191
209
  coordinatorTurnReminder,
192
210
  ensureGlobalCoordinatorCwd,
193
211
  coordinatorSystemPrompt
@@ -2,12 +2,12 @@
2
2
 
3
3
  import {
4
4
  ensureGlobalCoordinatorCwd
5
- } from "./chunk-N5LMEP65.js";
5
+ } from "./chunk-7NCIHRAU.js";
6
6
  import {
7
7
  allocateTeamName,
8
8
  takenSlugsFromThread,
9
9
  teamSlugFromName
10
- } from "./chunk-REKGFVUX.js";
10
+ } from "./chunk-OE7YBB5X.js";
11
11
  import {
12
12
  createEmptyThread,
13
13
  listThreads,
@@ -17,7 +17,7 @@ import {
17
17
  import {
18
18
  resolveNewThreadOptions,
19
19
  resolveThreadDefaults
20
- } from "./chunk-BPOTVI5J.js";
20
+ } from "./chunk-PTJJIQK7.js";
21
21
  import {
22
22
  globalAgentCwd
23
23
  } from "./chunk-7MV3RXSC.js";
@@ -184,6 +184,62 @@ function findCloudCoordinator() {
184
184
  (t) => t.status !== "archived" && isCloudCoordinatorThread(t)
185
185
  );
186
186
  }
187
+ function slackCoordinatorSourceRef(teamId, userId) {
188
+ const team = teamId.trim();
189
+ const user = userId.trim();
190
+ if (!team || !user) {
191
+ throw new Error("Slack coordinator needs teamId and userId");
192
+ }
193
+ return `slack:${team}:${user}`;
194
+ }
195
+ function isSlackCoordinatorThread(thread) {
196
+ const ref = thread.sourceRef?.trim() ?? "";
197
+ if (!ref.startsWith("slack:")) return false;
198
+ return isGlobalThread(thread) || thread.sourceType === "orchestration";
199
+ }
200
+ function findSlackCoordinator(teamId, userId) {
201
+ const ref = slackCoordinatorSourceRef(teamId, userId);
202
+ return listThreads({ includeArchived: true }).find(
203
+ (t) => t.status !== "archived" && t.sourceRef === ref && isSlackCoordinatorThread(t)
204
+ );
205
+ }
206
+ function ensureSlackCoordinator(teamId, userId, agent) {
207
+ const defaults = resolveThreadDefaults();
208
+ const desired = assertOrchestratorCapableAgent(agent);
209
+ const ref = slackCoordinatorSourceRef(teamId, userId);
210
+ const existing = findSlackCoordinator(teamId, userId);
211
+ if (existing) {
212
+ const patch = {};
213
+ if (existing.repoPath !== GLOBAL_WORKSPACE_ID) {
214
+ patch.repoPath = GLOBAL_WORKSPACE_ID;
215
+ patch.worktreePath = globalAgentCwd();
216
+ patch.branchName = "global";
217
+ }
218
+ const hasAgentTurns = existing.messages.some((m) => m.role === "agent");
219
+ const canRetarget = !existing.sessionId && !hasAgentTurns && existing.status !== "running" && existing.status !== "queued";
220
+ if (canRetarget) {
221
+ if (existing.agent !== desired) patch.agent = desired;
222
+ if (existing.model !== defaults.model) patch.model = defaults.model;
223
+ if (existing.effort !== defaults.effort) patch.effort = defaults.effort;
224
+ if (existing.fast !== defaults.fast) patch.fast = defaults.fast;
225
+ }
226
+ if (Object.keys(patch).length > 0) {
227
+ return updateThread(existing.id, patch);
228
+ }
229
+ return existing;
230
+ }
231
+ const created = createGlobalChat({
232
+ sourceRef: ref,
233
+ agent: desired,
234
+ model: defaults.model,
235
+ effort: defaults.effort,
236
+ fast: defaults.fast
237
+ });
238
+ const all = listThreads({ includeArchived: true }).filter(
239
+ (t) => t.status !== "archived" && t.sourceRef === ref && isSlackCoordinatorThread(t)
240
+ ).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
241
+ return all[0] ?? created;
242
+ }
187
243
  function ensureCloudCoordinator(agent) {
188
244
  const defaults = resolveThreadDefaults();
189
245
  const desired = assertOrchestratorCapableAgent(agent);
@@ -237,5 +293,8 @@ export {
237
293
  createGlobalChat,
238
294
  healOrchestrationSoccerTitles,
239
295
  listGlobalThreads,
296
+ slackCoordinatorSourceRef,
297
+ isSlackCoordinatorThread,
298
+ ensureSlackCoordinator,
240
299
  ensureCloudCoordinator
241
300
  };
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  resolveThreadDefaults
3
- } from "./chunk-MHR4OGZ4.js";
3
+ } from "./chunk-W7YOTDVO.js";
4
4
  import {
5
5
  resolveGithubRepoSlug
6
- } from "./chunk-EEBDVLDK.js";
6
+ } from "./chunk-MF2YMEGD.js";
7
7
  import {
8
8
  globalAgentCwd,
9
9
  sideboardReposDir
@@ -45,9 +45,12 @@ var COORDINATOR_TOOL_PLAYBOOK = [
45
45
  "Discover:",
46
46
  "- list_workspaces \u2014 registered repos (path + github slug when known)",
47
47
  "- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear API or GitHub Issues)",
48
+ "- list_teams / slack_list_channels / slack_list_users / slack_search / slack_read / slack_post \u2014 Slack workspaces from Account settings; pass team_id from list_teams",
49
+ "- Slack notify (only when the user asks): list_teams \u2192 slack_list_users or slack_list_channels \u2192 slack_post with to=@user or #channel and optional github_url (PR, blob permalink, or review/issue comment). Do not notify proactively.",
48
50
  "- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
49
51
  "- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
50
52
  "- list_threads / get_thread \u2014 fleet status (what is going on)",
53
+ "- set_caffeinate \u2014 keep this Mac awake across turns (macOS caffeinate). Turn on for Slack / away-from-keyboard work. Turn OFF when the user says they are done, wrapping up, going to sleep, or no longer need the machine awake.",
51
54
  "Workspaces:",
52
55
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
53
56
  "Worktree threads (chats):",
@@ -69,6 +72,13 @@ var COORDINATOR_TOOL_PLAYBOOK = [
69
72
  "Thread links in replies: when mentioning a chat/thread for the user, include a markdown link `[Title](sideboard://thread/<id>)` using the full id (or the link field from create_thread / list_threads). Sideboard renders these as clickable opens.",
70
73
  "Bash / Read / etc: allowed for (1) inspecting target worktrees / registered repo paths from MCP, and (2) greenfield setup under ~/sideboard/repos (git clone, gh repo create, git init+remote). Never git init/clone *inside* this synthetic home cwd \u2014 emptiness here is expected, not a bug."
71
74
  ].join("\n");
75
+ var SLACK_REPLY_FORMATTING = [
76
+ "Slack formatting (mandatory \u2014 your reply is posted verbatim to Slack):",
77
+ "- Use Slack mrkdwn, NOT GitHub/CommonMark markdown. Slack does not render `**bold**`, `# headings`, or `[label](url)`.",
78
+ "- Bold: *text* (single asterisks). Italic: _text_. Strikethrough: ~text~. Inline code: `code`.",
79
+ "- Links: <https://example.com|label> or bare URLs. Thread ids: plain `sideboard://thread/<id>` (no markdown link syntax).",
80
+ "- Prefer short paragraphs and *bold* section labels over markdown headings or bullet trees with `**`."
81
+ ].join("\n");
72
82
  function accountDefaultsPlaybookLine() {
73
83
  const d = resolveThreadDefaults();
74
84
  const model = d.model?.trim() || "Auto";
@@ -89,7 +99,8 @@ function coordinatorTurnReminder(opts) {
89
99
  `- For "what's going on": call list_threads (and list_workspaces if needed). Summarize fleet status \u2014 do not ls/git-status this synthetic home.`,
90
100
  "- Existing repo: create_thread on a repoPath \u2192 send_to_thread \u2192 wait_for_turn.",
91
101
  "- New repo: Bash (clone or gh repo create under ~/sideboard/repos/<name>) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 draft PR.",
92
- "- When naming threads for the user, link them as `[Title](sideboard://thread/<id>)`."
102
+ "- When naming threads for the user, link them as `[Title](sideboard://thread/<id>)`.",
103
+ "- If they will wait on Slack or leave the Mac, call set_caffeinate enabled=true. When they say they are done / wrapping up / going to sleep, call set_caffeinate enabled=false."
93
104
  ].filter(Boolean).join("\n");
94
105
  }
95
106
  function ensureGlobalCoordinatorCwd(opts) {
@@ -157,8 +168,14 @@ function coordinatorSystemPrompt(opts) {
157
168
  const audience = opts.audience ?? "cloud";
158
169
  const reposDir = sideboardReposDir();
159
170
  const intro = audience === "cloud" ? [
160
- "You are a Sideboard coordinator responding to a request from a Brightsy cloud agent (Slack, Discord, Teams, or other chat).",
171
+ "You are a Sideboard coordinator responding to a request from a Brightsy cloud agent (Discord, Teams, or other chat).",
161
172
  "Your reply will be sent back to that cloud agent \u2014 be concise and actionable."
173
+ ] : audience === "slack" ? [
174
+ "You are a Sideboard coordinator responding to a Slack DM or @mention via the Sideboard Slack app.",
175
+ "Your reply will be posted back in Slack \u2014 be concise and actionable.",
176
+ "Sideboard signs the Slack reply with this Mac's destination name (Personal / Work). Do not prefix that name yourself.",
177
+ "Call set_caffeinate enabled=true when they start a stretch of remote work so the Mac stays awake. Call set_caffeinate enabled=false when they say they are done, wrapping up, or going to sleep.",
178
+ SLACK_REPLY_FORMATTING
162
179
  ] : [
163
180
  "You are a Sideboard orchestration agent: you oversee worktree agents across registered workspaces in the Sideboard app.",
164
181
  "Stay concise and actionable; prefer Sideboard MCP for fleet status; use Bash for greenfield repo setup and inspecting target worktree paths."
@@ -186,6 +203,7 @@ export {
186
203
  enrichWorkspacesWithGithub,
187
204
  coordinatorGreenfieldPlaybook,
188
205
  COORDINATOR_TOOL_PLAYBOOK,
206
+ SLACK_REPLY_FORMATTING,
189
207
  coordinatorTurnReminder,
190
208
  ensureGlobalCoordinatorCwd,
191
209
  coordinatorSystemPrompt