@sideboard-ai/core 0.1.262 → 0.1.264
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.
- package/dist/{abletime-OQ4PC52L.js → abletime-6AOJI2YZ.js} +4 -4
- package/dist/{abletime-CDGINDXG.js → abletime-U75ZGDIX.js} +5 -5
- package/dist/{abletime-oauth-KX2TDFTE.js → abletime-oauth-LOAHGG4X.js} +3 -3
- package/dist/{abletime-oauth-5A5EOH2A.js → abletime-oauth-TA2YDCYX.js} +4 -4
- package/dist/{abletime-rest-UEHOBLXD.js → abletime-rest-CTA5WV26.js} +4 -4
- package/dist/{abletime-rest-PUGKYTRR.js → abletime-rest-YZPFM6IY.js} +3 -3
- package/dist/agents/claude-runner.cjs +463 -0
- package/dist/agents/claude-runner.d.cts +1 -0
- package/dist/agents/claude-runner.d.ts +1 -0
- package/dist/agents/claude-runner.js +134 -0
- package/dist/agents/cursor-runner.cjs +393 -8
- package/dist/agents/cursor-runner.js +39 -8
- package/dist/{agents-J2P4KNEY.js → agents-3TUMFSMH.js} +10 -9
- package/dist/{agents-IKVUGW5H.js → agents-6FWDRVA2.js} +4 -4
- package/dist/{app-settings-OM7H64YM.js → app-settings-MVZPM6WW.js} +1 -1
- package/dist/{app-settings-VQEUCONM.js → app-settings-RKFFUIFQ.js} +2 -2
- package/dist/{chunk-6PFZ6XO7.js → chunk-2QUQH2SZ.js} +81 -6
- package/dist/{chunk-VIC6TDYT.js → chunk-36FOBJBF.js} +76 -3
- package/dist/{chunk-ABPNIYRS.js → chunk-3H7O27X2.js} +389 -102
- package/dist/{chunk-FSZ7YYFQ.js → chunk-4ALDX5IO.js} +5 -3
- package/dist/{chunk-5OKJDCBK.js → chunk-5PK53SAP.js} +5 -5
- package/dist/{chunk-U3AOJLH3.js → chunk-5ZPT5YAV.js} +8 -6
- package/dist/{chunk-YFTO7U2A.js → chunk-6YOXQVJ7.js} +3 -3
- package/dist/{chunk-J6ONZP74.js → chunk-6YY7XPPL.js} +5 -5
- package/dist/{chunk-WV7KJH2E.js → chunk-A5SAYFJ4.js} +1 -0
- package/dist/{chunk-B6XFBNYM.js → chunk-BOMSJUXW.js} +2 -2
- package/dist/{chunk-S7VDDJ34.js → chunk-CEOTK5GZ.js} +3 -3
- package/dist/{chunk-4F7J6UWD.js → chunk-EK3KVT7I.js} +515 -139
- package/dist/{chunk-HHEKVR6C.js → chunk-F5MFNUAA.js} +40 -2
- package/dist/{chunk-KVQX62XI.js → chunk-K7B25HO4.js} +3 -3
- package/dist/{chunk-JTNY5CK4.js → chunk-L5WGAIL2.js} +46 -46
- package/dist/chunk-NYBFYFK7.js +415 -0
- package/dist/{chunk-GIZQAOHZ.js → chunk-QX6QUZVD.js} +121 -91
- package/dist/{chunk-X2OTZ36G.js → chunk-RKPBIB2U.js} +52 -52
- package/dist/{chunk-W5PWGEKS.js → chunk-T3AYRQJZ.js} +107 -77
- package/dist/{chunk-D554YCHG.js → chunk-YKYEHDMX.js} +2 -2
- package/dist/connected-teams-RU6VATCM.js +1 -1
- package/dist/{coordinator-prompt-VQHQ3RIX.js → coordinator-prompt-HZCQZ6C5.js} +6 -6
- package/dist/{coordinator-prompt-TU6656OK.js → coordinator-prompt-J7DKHOCH.js} +3 -3
- package/dist/{global-workspace-PHF2MOGW.js → global-workspace-6LDUZ2NF.js} +3 -3
- package/dist/{global-workspace-47NZVA44.js → global-workspace-TI26K25J.js} +6 -6
- package/dist/index.cjs +1712 -721
- package/dist/index.d.cts +181 -41
- package/dist/index.d.ts +181 -41
- package/dist/index.js +693 -285
- package/dist/mcp/run-stdio.cjs +10469 -9896
- package/dist/mcp/run-stdio.js +193 -168
- package/dist/{orchestrator-VLTO5JBR.js → orchestrator-4JSG7BWC.js} +5 -5
- package/dist/{orchestrator-OCG4QVA5.js → orchestrator-5YU46YNS.js} +11 -10
- package/dist/{workspaces-I7TWFTJM.js → workspaces-QJ3XIPUJ.js} +6 -6
- package/dist/{workspaces-2XTDS7N2.js → workspaces-WOQHJFRQ.js} +3 -3
- package/dist/{worktree-DDDF3WHV.js → worktree-6U2FA5LO.js} +2 -2
- package/dist/{worktree-YASFE65H.js → worktree-KQA4ON2G.js} +5 -5
- package/package.json +4 -3
- /package/dist/{chunk-LDXSAVWO.js → chunk-GWFVCCJZ.js} +0 -0
package/dist/mcp/run-stdio.js
CHANGED
|
@@ -11,9 +11,9 @@ import {
|
|
|
11
11
|
searchAbleTimeTasks,
|
|
12
12
|
toAbleTimeIssueInfo,
|
|
13
13
|
updateAbleTimeTask
|
|
14
|
-
} from "../chunk-
|
|
15
|
-
import "../chunk-
|
|
16
|
-
import "../chunk-
|
|
14
|
+
} from "../chunk-CEOTK5GZ.js";
|
|
15
|
+
import "../chunk-BOMSJUXW.js";
|
|
16
|
+
import "../chunk-5PK53SAP.js";
|
|
17
17
|
import {
|
|
18
18
|
AGENT_GIT_ACTIONS,
|
|
19
19
|
BOARD_COLUMN_DEFS,
|
|
@@ -51,8 +51,9 @@ import {
|
|
|
51
51
|
syncBoardPins,
|
|
52
52
|
threadsSharingWorktree,
|
|
53
53
|
updateSchedule,
|
|
54
|
-
waitForDetachedJob
|
|
55
|
-
|
|
54
|
+
waitForDetachedJob,
|
|
55
|
+
waitForTurnToolResult
|
|
56
|
+
} from "../chunk-T3AYRQJZ.js";
|
|
56
57
|
import {
|
|
57
58
|
PRESENT_PLAN_REQUIRES_PLAN_MODE,
|
|
58
59
|
PRESENT_PLAN_TOOL_DESCRIPTION,
|
|
@@ -69,15 +70,17 @@ import {
|
|
|
69
70
|
listModelsForAgent,
|
|
70
71
|
looksLikeHugeToolResultDump,
|
|
71
72
|
materializeSystemCaBundle,
|
|
73
|
+
shouldRegisterMcpWaitForTurn,
|
|
72
74
|
sideboardMcpProfile,
|
|
73
|
-
trustSystemCertificates
|
|
74
|
-
|
|
75
|
+
trustSystemCertificates,
|
|
76
|
+
worktreeMcpToolNames
|
|
77
|
+
} from "../chunk-EK3KVT7I.js";
|
|
75
78
|
import {
|
|
76
79
|
GLOBAL_WORKSPACE_ID,
|
|
77
80
|
isCloudCoordinatorThread,
|
|
78
81
|
isOrchestratorThread,
|
|
79
82
|
listWorkspaces
|
|
80
|
-
} from "../chunk-
|
|
83
|
+
} from "../chunk-L5WGAIL2.js";
|
|
81
84
|
import {
|
|
82
85
|
canonicalizeRepoPath,
|
|
83
86
|
formatGhLandError,
|
|
@@ -88,7 +91,7 @@ import {
|
|
|
88
91
|
resolveListPrsOptions,
|
|
89
92
|
resolveRepoRoot,
|
|
90
93
|
warmGithubAgentAuth
|
|
91
|
-
} from "../chunk-
|
|
94
|
+
} from "../chunk-4ALDX5IO.js";
|
|
92
95
|
import {
|
|
93
96
|
CLI_DIR
|
|
94
97
|
} from "../chunk-N2WW62LF.js";
|
|
@@ -120,7 +123,7 @@ import {
|
|
|
120
123
|
saveLinearOAuth,
|
|
121
124
|
writeSecureJson,
|
|
122
125
|
writeViewerContext
|
|
123
|
-
} from "../chunk-
|
|
126
|
+
} from "../chunk-36FOBJBF.js";
|
|
124
127
|
import {
|
|
125
128
|
writePrivateFile
|
|
126
129
|
} from "../chunk-NSTQ6QKD.js";
|
|
@@ -229,7 +232,7 @@ function createClippedMcpServer() {
|
|
|
229
232
|
|
|
230
233
|
// src/mcp/server.ts
|
|
231
234
|
import { z as z9 } from "zod";
|
|
232
|
-
import { randomUUID as
|
|
235
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
233
236
|
import { basename } from "path";
|
|
234
237
|
|
|
235
238
|
// src/integrations/issue-since.ts
|
|
@@ -1935,10 +1938,10 @@ function formatAskUserNotifyMessage(questions) {
|
|
|
1935
1938
|
}
|
|
1936
1939
|
function formatNotifyOrchestratorPrompt(input) {
|
|
1937
1940
|
const title = input.child.title?.trim() || "Untitled";
|
|
1938
|
-
const link = `[${title}](sideboard://
|
|
1941
|
+
const link = `[${title}](sideboard://chat/${input.child.id})`;
|
|
1939
1942
|
const body = clampMessage(input.message) || "(no details)";
|
|
1940
1943
|
const state = input.reason === "input-required" ? "is input-required (waiting for the user in that chat)" : "is blocked";
|
|
1941
|
-
const next = input.reason === "input-required" ? "Wait for the user in that chat. Do not
|
|
1944
|
+
const next = input.reason === "input-required" ? "Wait for the user in that chat. Do not send_to_chat a check-in." : "Help if this is your child; otherwise briefly tell the user. Do not send_to_chat a check-in.";
|
|
1942
1945
|
return [
|
|
1943
1946
|
`Sideboard: child worktree ${link} ${state}.`,
|
|
1944
1947
|
body,
|
|
@@ -2457,7 +2460,7 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
2457
2460
|
await continueOnReply(threadId, prompt);
|
|
2458
2461
|
return;
|
|
2459
2462
|
}
|
|
2460
|
-
const { getOrchestrator: getOrchestrator2 } = await import("../orchestrator-
|
|
2463
|
+
const { getOrchestrator: getOrchestrator2 } = await import("../orchestrator-4JSG7BWC.js");
|
|
2461
2464
|
await getOrchestrator2().send(threadId, prompt);
|
|
2462
2465
|
} catch {
|
|
2463
2466
|
}
|
|
@@ -3546,7 +3549,7 @@ function registerAbleTimeTools(server) {
|
|
|
3546
3549
|
);
|
|
3547
3550
|
server.tool(
|
|
3548
3551
|
"abletime_ensure_task",
|
|
3549
|
-
"Find or create an AbleTime task for this work, then
|
|
3552
|
+
"Find or create an AbleTime task for this work, then create_workspace with sourceType=ticket.",
|
|
3550
3553
|
{
|
|
3551
3554
|
title: z4.string(),
|
|
3552
3555
|
description: z4.string().optional(),
|
|
@@ -3870,11 +3873,11 @@ async function resolveProjectRepoPath(repoPath) {
|
|
|
3870
3873
|
}
|
|
3871
3874
|
return matchRegisteredWorkspace(root) ?? matchRegisteredWorkspace(hint);
|
|
3872
3875
|
}
|
|
3873
|
-
var PROJECT_PATH_HINT = "Pass repoPath from
|
|
3876
|
+
var PROJECT_PATH_HINT = "Pass repoPath from list_projects. Orchestration cwd is synthetic and empty \u2014 do not omit repoPath for project context.";
|
|
3874
3877
|
function registerViewerContextTools(server) {
|
|
3875
3878
|
server.tool(
|
|
3876
3879
|
"get_viewer_context",
|
|
3877
|
-
"Read account and project user context (Settings \u2192 Agents / Projects): roles, tickets, and review queues as freeform text. Orchestration must pass repoPath from
|
|
3880
|
+
"Read account and project user context (Settings \u2192 Agents / Projects): roles, tickets, and review queues as freeform text. Orchestration must pass repoPath from list_projects for project context. Worktree turns may omit repoPath (uses cwd).",
|
|
3878
3881
|
{
|
|
3879
3882
|
repoPath: z7.string().optional().describe(
|
|
3880
3883
|
"Registered workspace or worktree path. Required from orchestration for a project. Omit on a worktree turn (uses cwd)."
|
|
@@ -3900,7 +3903,7 @@ function registerViewerContextTools(server) {
|
|
|
3900
3903
|
context: z7.string().describe("Full replacement text (roles, tickets, review queues). Empty clears."),
|
|
3901
3904
|
confirmed: z7.boolean().optional().describe("Must be true after the user confirmed via ask_user. False/omit is rejected."),
|
|
3902
3905
|
repoPath: z7.string().optional().describe(
|
|
3903
|
-
"Required for scope=project from orchestration (path from
|
|
3906
|
+
"Required for scope=project from orchestration (path from list_projects). Worktree turns may omit it (cwd)."
|
|
3904
3907
|
)
|
|
3905
3908
|
},
|
|
3906
3909
|
async ({ scope, context, confirmed, repoPath }) => {
|
|
@@ -4014,7 +4017,7 @@ function registerScheduleTools(server) {
|
|
|
4014
4017
|
);
|
|
4015
4018
|
server.tool(
|
|
4016
4019
|
"create_schedule",
|
|
4017
|
-
"Create a local schedule that, when due, sends a prompt to an existing chat (
|
|
4020
|
+
"Create a local schedule that, when due, sends a prompt to an existing chat (chatId) or starts a new Global orchestration chat (omit chatId). Pass chatId=self to continue this chat. If that chat is missing or archived when the job fires, Sideboard starts a new Global chat (recurring jobs then continue that chat). Exactly one of at (ISO datetime), every (15m/1h/6h/1d), or cron (5-field). Recurring jobs without chatId open a new Global chat each run. Creating or enabling a future job turns on Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled so the Mac stays awake until due. Sideboard.app must be running for the job to fire.",
|
|
4018
4021
|
{
|
|
4019
4022
|
prompt: z8.string().describe("User message / goal queued when the schedule fires"),
|
|
4020
4023
|
name: z8.string().optional(),
|
|
@@ -4022,20 +4025,22 @@ function registerScheduleTools(server) {
|
|
|
4022
4025
|
every: z8.string().optional().describe("Interval such as 15m, 1h, 6h, 1d"),
|
|
4023
4026
|
cron: z8.string().optional().describe("5-field cron expression"),
|
|
4024
4027
|
tz: z8.string().optional().describe("IANA timezone for cron (default: system)"),
|
|
4025
|
-
|
|
4026
|
-
'Existing chat id (orchestration or
|
|
4028
|
+
chatId: z8.string().optional().describe(
|
|
4029
|
+
'Existing chat id (orchestration or workspace), or "self" for this chat. Omit to create a new Global chat on fire.'
|
|
4027
4030
|
),
|
|
4031
|
+
threadId: z8.string().optional().describe("Legacy alias for chatId."),
|
|
4028
4032
|
agent: z8.enum(["claude", "cursor", "codex", "opencode"]).optional().describe("Agent for a new Global chat (omit for Account default)"),
|
|
4029
4033
|
model: z8.string().optional()
|
|
4030
4034
|
},
|
|
4031
4035
|
async (args) => {
|
|
4032
4036
|
try {
|
|
4033
4037
|
const when = parseWhen(args);
|
|
4034
|
-
const
|
|
4035
|
-
|
|
4038
|
+
const rawChatId = args.chatId ?? args.threadId;
|
|
4039
|
+
const threadId = resolveScheduleThreadId(rawChatId);
|
|
4040
|
+
if (rawChatId?.trim().toLowerCase() === "self" && !threadId) {
|
|
4036
4041
|
return fail5(
|
|
4037
4042
|
new Error(
|
|
4038
|
-
"
|
|
4043
|
+
"chatId=self needs this chat id (SIDEBOARD_THREAD_ID or SIDEBOARD_ORCHESTRATOR_THREAD_ID)"
|
|
4039
4044
|
)
|
|
4040
4045
|
);
|
|
4041
4046
|
}
|
|
@@ -4050,7 +4055,7 @@ function registerScheduleTools(server) {
|
|
|
4050
4055
|
});
|
|
4051
4056
|
return text6({
|
|
4052
4057
|
schedule,
|
|
4053
|
-
hint: scheduleNeedsCaffeinate(schedule) ? "Fires while Sideboard.app is running. Recurring jobs without
|
|
4058
|
+
hint: scheduleNeedsCaffeinate(schedule) ? "Fires while Sideboard.app is running. Recurring jobs without chatId create a new orchestration chat each run. Caffeinate while schedules are enabled is now on so the Mac can stay awake until this job is due." : "Fires while Sideboard.app is running. Recurring jobs without chatId create a new orchestration chat each run."
|
|
4054
4059
|
});
|
|
4055
4060
|
} catch (err) {
|
|
4056
4061
|
return fail5(err);
|
|
@@ -4059,7 +4064,7 @@ function registerScheduleTools(server) {
|
|
|
4059
4064
|
);
|
|
4060
4065
|
server.tool(
|
|
4061
4066
|
"update_schedule",
|
|
4062
|
-
"Update a local schedule (prompt, cadence, target
|
|
4067
|
+
"Update a local schedule (prompt, cadence, target chat, enabled). Pass id from list_schedules.",
|
|
4063
4068
|
{
|
|
4064
4069
|
id: z8.string(),
|
|
4065
4070
|
prompt: z8.string().optional(),
|
|
@@ -4068,9 +4073,10 @@ function registerScheduleTools(server) {
|
|
|
4068
4073
|
every: z8.string().optional(),
|
|
4069
4074
|
cron: z8.string().optional(),
|
|
4070
4075
|
tz: z8.string().optional(),
|
|
4071
|
-
|
|
4072
|
-
'Existing chat (orchestration or
|
|
4076
|
+
chatId: z8.string().optional().describe(
|
|
4077
|
+
'Existing chat (orchestration or workspace), "self", or empty string to create a new Global chat each run'
|
|
4073
4078
|
),
|
|
4079
|
+
threadId: z8.string().optional().describe("Legacy alias for chatId."),
|
|
4074
4080
|
agent: z8.enum(["claude", "cursor", "codex", "opencode"]).optional(),
|
|
4075
4081
|
model: z8.string().optional(),
|
|
4076
4082
|
enabled: z8.boolean().optional()
|
|
@@ -4085,12 +4091,13 @@ function registerScheduleTools(server) {
|
|
|
4085
4091
|
tz: args.tz
|
|
4086
4092
|
}) : void 0;
|
|
4087
4093
|
let threadId;
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4094
|
+
const rawChatId = args.chatId ?? args.threadId;
|
|
4095
|
+
if (rawChatId !== void 0) {
|
|
4096
|
+
threadId = resolveScheduleThreadId(rawChatId);
|
|
4097
|
+
if (rawChatId.trim().toLowerCase() === "self" && !threadId) {
|
|
4091
4098
|
return fail5(
|
|
4092
4099
|
new Error(
|
|
4093
|
-
"
|
|
4100
|
+
"chatId=self needs this chat id (SIDEBOARD_THREAD_ID or SIDEBOARD_ORCHESTRATOR_THREAD_ID)"
|
|
4094
4101
|
)
|
|
4095
4102
|
);
|
|
4096
4103
|
}
|
|
@@ -4141,12 +4148,29 @@ function registerScheduleTools(server) {
|
|
|
4141
4148
|
);
|
|
4142
4149
|
}
|
|
4143
4150
|
|
|
4151
|
+
// src/agent-rpc/handlers.ts
|
|
4152
|
+
import { randomUUID } from "crypto";
|
|
4153
|
+
import { isAbsolute } from "path";
|
|
4154
|
+
function presentArtifactResult(input) {
|
|
4155
|
+
const id = input.artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${randomUUID().slice(0, 8)}`;
|
|
4156
|
+
return {
|
|
4157
|
+
ok: true,
|
|
4158
|
+
artifact_id: id,
|
|
4159
|
+
title: input.title,
|
|
4160
|
+
type: input.type,
|
|
4161
|
+
status: input.status,
|
|
4162
|
+
phase: input.phase,
|
|
4163
|
+
mode: input.type === "log" ? input.mode ?? "append" : void 0,
|
|
4164
|
+
message: input.type === "log" ? "Log accepted. Same artifact_id appends; send only new lines next time." : "Artifact accepted. Sideboard desktop opens it in the side column beside chat."
|
|
4165
|
+
};
|
|
4166
|
+
}
|
|
4167
|
+
|
|
4144
4168
|
// src/board/load-home-board.ts
|
|
4145
4169
|
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
4146
4170
|
import { join as join6 } from "path";
|
|
4147
4171
|
|
|
4148
4172
|
// src/board/board-pins.ts
|
|
4149
|
-
import { randomUUID } from "crypto";
|
|
4173
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
4150
4174
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
4151
4175
|
import { join as join5 } from "path";
|
|
4152
4176
|
var FILE = "home-board-pins.json";
|
|
@@ -4467,7 +4491,7 @@ function withTimeout(promise, ms, label) {
|
|
|
4467
4491
|
}
|
|
4468
4492
|
async function createOrchChildThread(orch, args, resolveNewThreadOptions) {
|
|
4469
4493
|
const envParentId = process.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || "";
|
|
4470
|
-
let parentId = args.parentThreadId?.trim() || "";
|
|
4494
|
+
let parentId = args.parentChatId?.trim() || args.parentThreadId?.trim() || "";
|
|
4471
4495
|
let parent = parentId ? orch.getThread(parentId) : null;
|
|
4472
4496
|
let parentCorrectedFrom;
|
|
4473
4497
|
if (envParentId) {
|
|
@@ -4517,7 +4541,7 @@ async function createOrchChildThread(orch, args, resolveNewThreadOptions) {
|
|
|
4517
4541
|
attachments: args.attachments
|
|
4518
4542
|
}),
|
|
4519
4543
|
CREATE_THREAD_TIMEOUT_MS,
|
|
4520
|
-
"
|
|
4544
|
+
"create_workspace"
|
|
4521
4545
|
);
|
|
4522
4546
|
const alreadyStarted = priorIds.has(thread.id);
|
|
4523
4547
|
const parentNote = parentCorrectedFrom ? parentId ? `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; nested under ${parentId}` : `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; created without parent` : void 0;
|
|
@@ -4532,7 +4556,8 @@ async function createOrchChildThread(orch, args, resolveNewThreadOptions) {
|
|
|
4532
4556
|
model: thread.model,
|
|
4533
4557
|
status: thread.status,
|
|
4534
4558
|
cowboy: Boolean(thread.cowboy),
|
|
4535
|
-
link: `sideboard://
|
|
4559
|
+
link: `sideboard://chat/${thread.id}`,
|
|
4560
|
+
parentChatId: thread.parentThreadId,
|
|
4536
4561
|
parentThreadId: thread.parentThreadId,
|
|
4537
4562
|
...alreadyStarted ? { alreadyStarted: true } : {},
|
|
4538
4563
|
...opts.coercedFrom ? { agentCoercedFrom: opts.coercedFrom } : {},
|
|
@@ -4543,7 +4568,7 @@ async function createOrchChildThread(orch, args, resolveNewThreadOptions) {
|
|
|
4543
4568
|
};
|
|
4544
4569
|
} catch (err) {
|
|
4545
4570
|
const message = err instanceof Error ? err.message : String(err);
|
|
4546
|
-
return { ok: false, text: `
|
|
4571
|
+
return { ok: false, text: `create_workspace failed: ${message}` };
|
|
4547
4572
|
}
|
|
4548
4573
|
}
|
|
4549
4574
|
function previewHint(preview) {
|
|
@@ -4560,7 +4585,7 @@ async function startMcpServer() {
|
|
|
4560
4585
|
);
|
|
4561
4586
|
}
|
|
4562
4587
|
try {
|
|
4563
|
-
const { maxConcurrentAgents } = await import("../app-settings-
|
|
4588
|
+
const { maxConcurrentAgents } = await import("../app-settings-MVZPM6WW.js");
|
|
4564
4589
|
orch.setMaxConcurrent(maxConcurrentAgents());
|
|
4565
4590
|
} catch {
|
|
4566
4591
|
}
|
|
@@ -4593,8 +4618,8 @@ async function startMcpServer() {
|
|
|
4593
4618
|
}
|
|
4594
4619
|
if (!worktreeProfile) {
|
|
4595
4620
|
server.tool(
|
|
4596
|
-
"
|
|
4597
|
-
"List registered
|
|
4621
|
+
"list_projects",
|
|
4622
|
+
"List registered projects (git repos). Each line is name, path, github:owner/repo when resolvable, and project context when set \u2014 use path as repoPath for list_board/list_branches/list_prs/list_issues/create_workspace. Account / project context (Settings \u2192 Agents / Projects) says which tickets and review PRs belong to the user.",
|
|
4598
4623
|
{},
|
|
4599
4624
|
async () => {
|
|
4600
4625
|
const workspaces = orch.listWorkspaces();
|
|
@@ -4613,14 +4638,14 @@ async function startMcpServer() {
|
|
|
4613
4638
|
);
|
|
4614
4639
|
return {
|
|
4615
4640
|
content: [
|
|
4616
|
-
{ type: "text", text: lines.join("\n") || "(no
|
|
4641
|
+
{ type: "text", text: lines.join("\n") || "(no projects)" }
|
|
4617
4642
|
]
|
|
4618
4643
|
};
|
|
4619
4644
|
}
|
|
4620
4645
|
);
|
|
4621
4646
|
server.tool(
|
|
4622
|
-
"
|
|
4623
|
-
"List
|
|
4647
|
+
"list_chats",
|
|
4648
|
+
"List chats across all projects (one summary line each \u2014 token-frugal). Includes parent id, last message preview, and live progress so you can see workspace children. Each line ends with sideboard://chat/<id> \u2014 use that URL in markdown links so the UI can open the chat.",
|
|
4624
4649
|
{},
|
|
4625
4650
|
async () => {
|
|
4626
4651
|
const threads = orch.getThreads(true);
|
|
@@ -4632,19 +4657,19 @@ async function startMcpServer() {
|
|
|
4632
4657
|
const previewBit = preview ? ` ${preview}` : "";
|
|
4633
4658
|
const err = t.lastError ? ` error:${t.lastError.replace(/\s+/g, " ").slice(0, 60)}` : "";
|
|
4634
4659
|
const progress = live?.summary && !isInternalAgentStatusText(live.summary) ? ` ${live.summary}` : "";
|
|
4635
|
-
return `${t.id.slice(0, 8)} ${t.status.padEnd(9)} ${t.agent.padEnd(8)} ${repo} ${t.sourceType}:${t.sourceRef} ${t.title}${parent}${previewBit}${err} sideboard://
|
|
4660
|
+
return `${t.id.slice(0, 8)} ${t.status.padEnd(9)} ${t.agent.padEnd(8)} ${repo} ${t.sourceType}:${t.sourceRef} ${t.title}${parent}${previewBit}${err} sideboard://chat/${t.id}${t.devPort ? ` http://localhost:${t.devPort}` : ""}${progress}`;
|
|
4636
4661
|
});
|
|
4637
4662
|
return {
|
|
4638
|
-
content: [{ type: "text", text: lines.join("\n") || "(no
|
|
4663
|
+
content: [{ type: "text", text: lines.join("\n") || "(no chats)" }]
|
|
4639
4664
|
};
|
|
4640
4665
|
}
|
|
4641
4666
|
);
|
|
4642
4667
|
server.tool(
|
|
4643
4668
|
"list_board",
|
|
4644
|
-
"Home Kanban of worktrees (New, Draft, Review, Merged) \u2014 one card per checkout; sibling chat tabs nest as inner cards. Same cards as desktop Home. Path to merge: no PR \u2192 draft PR \u2192 open PR \u2192 merged. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. Orchestration chats are not on the board. Filters: query, repoPath, kind (ticket/PR/branch source), ownership (mine = your PRs / WIP; reviewing = someone else's PR), column, limit (default 40).
|
|
4669
|
+
"Home Kanban of worktrees (New, Draft, Review, Merged) \u2014 one card per checkout; sibling chat tabs nest as inner cards. Same cards as desktop Home. Path to merge: no PR \u2192 draft PR \u2192 open PR \u2192 merged. Archive removes the card to Settings \u2192 History. Queued/running are activity on the card, not columns. Orchestration chats are not on the board. Filters: query, repoPath, kind (ticket/PR/branch source), ownership (mine = your PRs / WIP; reviewing = someone else's PR), column, limit (default 40). create_workspace adds a workspace (and a Home card), or returns the live one if that ticket/PR/named branch is already checked out.",
|
|
4645
4670
|
{
|
|
4646
4671
|
query: z9.string().optional().describe("Case-insensitive token search across title, id, labels, repo"),
|
|
4647
|
-
repoPath: z9.string().optional().describe("Limit to one
|
|
4672
|
+
repoPath: z9.string().optional().describe("Limit to one project path from list_projects"),
|
|
4648
4673
|
kind: z9.enum(["all", "tickets", "prs", "branches", "threads"]).optional().describe("Filter by worktree source (default all)"),
|
|
4649
4674
|
ownership: z9.enum(["all", "mine", "reviewing"]).optional().describe(
|
|
4650
4675
|
"Mine = PRs you authored or local WIP; reviewing = someone else's PR. Uses the gh login."
|
|
@@ -4680,13 +4705,13 @@ async function startMcpServer() {
|
|
|
4680
4705
|
}
|
|
4681
4706
|
);
|
|
4682
4707
|
server.tool(
|
|
4683
|
-
"
|
|
4684
|
-
"Get a compact
|
|
4708
|
+
"get_chat",
|
|
4709
|
+
"Get a compact chat summary by id/ref. Includes last message preview, parentChatId, and child workspace chats (status + lastText). While running, includes progress (last tool/thinking) and lastActivityAt. Includes usage (billed token + costUsd totals when providers reported cost) and lastTurnUsage.",
|
|
4685
4710
|
{ ref: z9.string() },
|
|
4686
4711
|
async ({ ref }) => {
|
|
4687
4712
|
const t = orch.getThread(ref);
|
|
4688
4713
|
if (!t) {
|
|
4689
|
-
return { content: [{ type: "text", text: `
|
|
4714
|
+
return { content: [{ type: "text", text: `Chat not found: ${ref}` }], isError: true };
|
|
4690
4715
|
}
|
|
4691
4716
|
const stillRunning = orch.threadLooksLive(t);
|
|
4692
4717
|
const live = stillRunning ? readTurnLive(t.id) : null;
|
|
@@ -4702,6 +4727,7 @@ async function startMcpServer() {
|
|
|
4702
4727
|
branchName: t.branchName,
|
|
4703
4728
|
worktreePath: t.worktreePath,
|
|
4704
4729
|
sessionId: t.sessionId,
|
|
4730
|
+
parentChatId: t.parentThreadId,
|
|
4705
4731
|
parentThreadId: t.parentThreadId,
|
|
4706
4732
|
children: childThreadRefs(t.id, orch.getThreads(false)),
|
|
4707
4733
|
queueLength: t.queue.length,
|
|
@@ -4720,37 +4746,31 @@ async function startMcpServer() {
|
|
|
4720
4746
|
}
|
|
4721
4747
|
);
|
|
4722
4748
|
}
|
|
4723
|
-
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
mode: type === "log" ? mode ?? "append" : void 0,
|
|
4749
|
-
message: type === "log" ? "Log accepted. Same artifact_id appends; send only new lines next time." : "Artifact accepted. Sideboard desktop opens it in the side column beside chat."
|
|
4750
|
-
};
|
|
4751
|
-
return mcpJson(payload);
|
|
4752
|
-
}
|
|
4753
|
-
);
|
|
4749
|
+
const mcpCatalog = new Set(worktreeMcpToolNames());
|
|
4750
|
+
if (mcpCatalog.has("present_artifact")) {
|
|
4751
|
+
server.tool(
|
|
4752
|
+
"present_artifact",
|
|
4753
|
+
"Show a document or live log in Sideboard\u2019s side column. For html/svg/markdown/react, pass the FULL document and do not also fence that same body in chat. For type=log, pass only NEW lines (same artifact_id appends). Prefer type=log for long-running job output \u2014 do not resend HTML. type=react is a single default-export component (JSX/TSX); only react/react-dom imports.",
|
|
4754
|
+
{
|
|
4755
|
+
title: z9.string().describe("Short title shown in the artifact pane header"),
|
|
4756
|
+
type: z9.enum(["html", "svg", "markdown", "react", "log"]).describe(
|
|
4757
|
+
"html/svg/markdown/react replace the pane. log appends content to the same artifact_id (new lines only)."
|
|
4758
|
+
),
|
|
4759
|
+
content: z9.string().describe(
|
|
4760
|
+
"html/svg/markdown/react: full document. log: only the new lines since the last call (empty is ok for a status-only update)."
|
|
4761
|
+
),
|
|
4762
|
+
artifact_id: z9.string().optional().describe("Stable id. Required for type=log so later calls append to the same pane."),
|
|
4763
|
+
status: z9.enum(["running", "ok", "failed", "idle"]).optional().describe("Log header pill: running (working), ok (done), failed, idle"),
|
|
4764
|
+
phase: z9.string().optional().describe("Log subtitle (Signing, Notarizing, \u2026)"),
|
|
4765
|
+
mode: z9.enum(["append", "replace"]).optional().describe("log only: append (default) or replace the buffer")
|
|
4766
|
+
},
|
|
4767
|
+
async ({ title, type, artifact_id, status, phase, mode }) => {
|
|
4768
|
+
return mcpJson(
|
|
4769
|
+
presentArtifactResult({ title, type, artifact_id, status, phase, mode })
|
|
4770
|
+
);
|
|
4771
|
+
}
|
|
4772
|
+
);
|
|
4773
|
+
}
|
|
4754
4774
|
server.tool(
|
|
4755
4775
|
"ask_user",
|
|
4756
4776
|
"Ask the user a clarifying multiple-choice question in Sideboard\u2019s composer. Call only when work is blocked on choosing among a few concrete options (approach fork, which API, auth vs cookies). Do not call for greetings, check-ins, \u201Chello\u201D, open-ended how-can-I-help, or to invent a menu of possible next tasks \u2014 reply in chat instead. If one option is the obvious default, proceed without asking. Before calling, write a short chat message explaining the decision and what each option means. Include a description on every option. After calling, stop and wait for answers. Not for \u201Cis the plan ready?\u201D.",
|
|
@@ -4867,32 +4887,34 @@ async function startMcpServer() {
|
|
|
4867
4887
|
return mcpJson(payload);
|
|
4868
4888
|
}
|
|
4869
4889
|
);
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
|
|
4890
|
+
if (mcpCatalog.has("wait_for_job")) {
|
|
4891
|
+
server.tool(
|
|
4892
|
+
"wait_for_job",
|
|
4893
|
+
"Wait on a detached long job (tests, pack, deploy, connector CLI) started with detached-job.cjs. MCP clients kill tools around 60s, so this returns within 45s. Sideboard opens a type=log pane from this result (artifact_id = job id, content = delta). stillRunning is the source of truth \u2014 if true, call wait_for_job again. If the job is hanging, producing no useful output, or doing the wrong thing, call stop_job instead of looping forever. Do not end the turn or tell the user you will let them know later. If false, ok/failed is the result.",
|
|
4894
|
+
{
|
|
4895
|
+
id: z9.string().describe("Detached job id (same kebab-case id passed to detached-job.cjs start)"),
|
|
4896
|
+
timeoutMs: z9.number().optional()
|
|
4897
|
+
},
|
|
4898
|
+
async ({ id, timeoutMs }) => {
|
|
4899
|
+
const result = await waitForDetachedJob(process.cwd(), id, {
|
|
4900
|
+
timeoutMs: mcpWaitForJobTimeoutMs(timeoutMs)
|
|
4901
|
+
});
|
|
4902
|
+
return mcpJson(result);
|
|
4903
|
+
}
|
|
4904
|
+
);
|
|
4905
|
+
server.tool(
|
|
4906
|
+
"stop_job",
|
|
4907
|
+
"Stop a detached job you started with detached-job.cjs when it is hanging, producing no useful output, buffering forever, or doing the wrong thing (wrong project, infinite watch, huge dump). Do not stop a pack/test/deploy that is clearly making progress. The type=log pane updates to status=failed with the last delta. Then decide the next step.",
|
|
4908
|
+
{
|
|
4909
|
+
id: z9.string().describe("Detached job id (same kebab-case id passed to detached-job.cjs start)"),
|
|
4910
|
+
reason: z9.string().optional().describe("Why you are stopping (hanging, no progress, wrong output, already have the answer)")
|
|
4911
|
+
},
|
|
4912
|
+
async ({ id, reason }) => {
|
|
4913
|
+
const result = await stopDetachedJob(process.cwd(), id, { reason });
|
|
4914
|
+
return mcpJson(result);
|
|
4915
|
+
}
|
|
4916
|
+
);
|
|
4917
|
+
}
|
|
4896
4918
|
server.tool(
|
|
4897
4919
|
"list_run_scripts",
|
|
4898
4920
|
"List .sideboard/.conductor run scripts for this thread (same menu as the desktop Dev button) and which are active. Each script and active run includes preview: url (open http://localhost:<SIDEBOARD_PORT>) or window (Electron: native window is the app; url is renderer/HMR only). Never guess :3000. Worktree turns may omit ref (uses cwd).",
|
|
@@ -5052,7 +5074,7 @@ async function startMcpServer() {
|
|
|
5052
5074
|
registerSlackTools(server);
|
|
5053
5075
|
registerConnectedIssueVendorTools(server);
|
|
5054
5076
|
const { getCaffeinateHold, setCaffeinateHold } = await import("../caffeinate-hold-UAGLSGMM.js");
|
|
5055
|
-
const { resolveNewThreadOptions, resolveThreadDefaults } = await import("../app-settings-
|
|
5077
|
+
const { resolveNewThreadOptions, resolveThreadDefaults } = await import("../app-settings-MVZPM6WW.js");
|
|
5056
5078
|
const accountDefaults = resolveThreadDefaults();
|
|
5057
5079
|
const accountDefaultsHint = `Account defaults: agent=${accountDefaults.agent}, model=${accountDefaults.model?.trim() || "Auto"}, effort=${accountDefaults.effort}`;
|
|
5058
5080
|
server.tool(
|
|
@@ -5082,8 +5104,8 @@ async function startMcpServer() {
|
|
|
5082
5104
|
}
|
|
5083
5105
|
);
|
|
5084
5106
|
server.tool(
|
|
5085
|
-
"
|
|
5086
|
-
`Create a worktree
|
|
5107
|
+
"create_workspace",
|
|
5108
|
+
`Create a workspace (isolated git worktree + first chat) from branch, pr, or ticket. A ticket, PR, or named branch may have only one live worktree \u2014 if one already matches, returns it (alreadyStarted=true) instead of a second checkout. Creating from the default branch still opens a new isolated worktree. Pass repoPath from list_projects. cowboy=true uses the project folder on the default branch (no isolated worktree; land is commit+push). From an orchestration chat, omit parentChatId (Sideboard binds the child to this chat) or pass the exact id from the turn reminder \u2014 never invent a uuid. Omit agent/model \u2014 Sideboard applies ${accountDefaultsHint}. Do not pass your own agent or agent=cursor; those are ignored. Setup (settings.toml, .cursor/worktrees.json, or script/setup) runs in the background in parallel with the first turn (skipped for cowboy). Then use send_to_chat to chat.`,
|
|
5087
5109
|
{
|
|
5088
5110
|
sourceType: z9.enum(["branch", "pr", "ticket"]),
|
|
5089
5111
|
sourceRef: z9.string(),
|
|
@@ -5098,9 +5120,10 @@ async function startMcpServer() {
|
|
|
5098
5120
|
cowboy: z9.boolean().optional().describe(
|
|
5099
5121
|
"If true, work in the project folder on the default branch (no thread/* worktree). Requires Settings \u2192 Advanced \u2192 Cowboy mode. Land is commit+push to that branch. Archive does not delete the folder."
|
|
5100
5122
|
),
|
|
5101
|
-
|
|
5123
|
+
parentChatId: z9.string().optional().describe(
|
|
5102
5124
|
"Orchestration: omit (preferred) or pass YOUR chat id from the turn reminder / AGENTS.md. Do not invent uuids."
|
|
5103
|
-
)
|
|
5125
|
+
),
|
|
5126
|
+
parentThreadId: z9.string().optional().describe("Legacy alias for parentChatId.")
|
|
5104
5127
|
},
|
|
5105
5128
|
async (args) => {
|
|
5106
5129
|
const result = await createOrchChildThread(orch, args, resolveNewThreadOptions);
|
|
@@ -5112,11 +5135,11 @@ async function startMcpServer() {
|
|
|
5112
5135
|
);
|
|
5113
5136
|
server.tool(
|
|
5114
5137
|
"start_board_card",
|
|
5115
|
-
"Same as
|
|
5138
|
+
"Same as create_workspace for a ticket, PR, or named branch (attaches issue text when Sideboard can resolve it). Does not create a second worktree when one already matches \u2014 returns that thread (alreadyStarted). Then send_to_chat.",
|
|
5116
5139
|
{
|
|
5117
5140
|
kind: z9.enum(["ticket", "pr", "branch"]),
|
|
5118
5141
|
ref: z9.string().describe("Ticket identifier (ENG-12), PR number (44), or branch name from list_board"),
|
|
5119
|
-
repoPath: z9.string().describe("
|
|
5142
|
+
repoPath: z9.string().describe("Project path from list_projects / list_board"),
|
|
5120
5143
|
title: z9.string().optional()
|
|
5121
5144
|
},
|
|
5122
5145
|
async ({ kind, ref, repoPath, title }) => {
|
|
@@ -5139,7 +5162,7 @@ async function startMcpServer() {
|
|
|
5139
5162
|
id: existing.id,
|
|
5140
5163
|
title: existing.title,
|
|
5141
5164
|
status: existing.status,
|
|
5142
|
-
link: `sideboard://
|
|
5165
|
+
link: `sideboard://chat/${existing.id}`
|
|
5143
5166
|
});
|
|
5144
5167
|
}
|
|
5145
5168
|
const workspaces = orch.listWorkspaces();
|
|
@@ -5167,7 +5190,7 @@ async function startMcpServer() {
|
|
|
5167
5190
|
const ident = issue?.identifier ?? ref.trim();
|
|
5168
5191
|
const attachments = issue ? [
|
|
5169
5192
|
{
|
|
5170
|
-
id:
|
|
5193
|
+
id: randomUUID3(),
|
|
5171
5194
|
name: issue.identifier,
|
|
5172
5195
|
kind: "issue",
|
|
5173
5196
|
content: [
|
|
@@ -5211,8 +5234,8 @@ async function startMcpServer() {
|
|
|
5211
5234
|
}
|
|
5212
5235
|
);
|
|
5213
5236
|
server.tool(
|
|
5214
|
-
"
|
|
5215
|
-
'Steer a prompt on a
|
|
5237
|
+
"send_to_chat",
|
|
5238
|
+
'Steer a prompt on a workspace chat (Settings \u2192 Follow-up, default steer: front of the queue, skips the inbox; while the desktop board is running it starts as soon as the in-flight turn yields). Use after create_workspace to start or continue a conversation. For commit/push/PR, prefer ask_git (canonical desktop-button phrases). Send "Merge PR." / ask_git merge only when the user explicitly asked to merge. force_stop=true kills the in-flight turn and clears the queue before this prompt \u2014 only when the current request is wrong and must be replaced. Do not send_to_chat to check in, resume after a halt notice, or because wait_for_turn returned stillRunning; that interrupts the child mid-thought. Call wait_for_turn again instead.',
|
|
5216
5239
|
{
|
|
5217
5240
|
ref: z9.string(),
|
|
5218
5241
|
prompt: z9.string(),
|
|
@@ -5236,36 +5259,38 @@ async function startMcpServer() {
|
|
|
5236
5259
|
});
|
|
5237
5260
|
}
|
|
5238
5261
|
);
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
|
|
5249
|
-
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
|
|
5255
|
-
|
|
5256
|
-
|
|
5257
|
-
|
|
5258
|
-
|
|
5259
|
-
|
|
5260
|
-
|
|
5261
|
-
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
|
|
5265
|
-
|
|
5262
|
+
if (shouldRegisterMcpWaitForTurn()) {
|
|
5263
|
+
server.tool(
|
|
5264
|
+
"wait_for_turn",
|
|
5265
|
+
"Wait until the chat finishes its current/queued turn, or return early with a live progress snapshot. MCP clients often kill tools around 60s, so this returns within 45s even while the child is still working. taskState is the A2A-style lifecycle: submitted (queued, not started), working, input-required (ask_user), completed, failed, canceled. stillRunning is true only for submitted/working. If stillRunning, text and usage are empty (they would be the previous turn) \u2014 read progress and call wait_for_turn again. Do not send_to_chat a check-in (that steers / interrupts). On failed, lastError/text is the failure. On canceled, the child did not finish \u2014 resume with send_to_chat or tell the user. On input-required, wait for the user in that chat. When finished, text is this turn\u2019s assistant reply and usage is that turn\u2019s tokens + costUsd (this turn, not the Claude session total; sessionCostUsd is the provider session total when present).",
|
|
5266
|
+
{
|
|
5267
|
+
ref: z9.string(),
|
|
5268
|
+
timeoutMs: z9.number().optional()
|
|
5269
|
+
},
|
|
5270
|
+
async ({ ref, timeoutMs }) => {
|
|
5271
|
+
const thread = await orch.waitForTurn(ref, mcpWaitForTurnTimeoutMs(timeoutMs), {
|
|
5272
|
+
resolveIfStillRunning: true
|
|
5273
|
+
});
|
|
5274
|
+
const result = orch.getTurnResult(thread.id);
|
|
5275
|
+
return mcpJson(
|
|
5276
|
+
waitForTurnToolResult({
|
|
5277
|
+
id: thread.id,
|
|
5278
|
+
status: result.status,
|
|
5279
|
+
taskState: result.taskState,
|
|
5280
|
+
text: result.text,
|
|
5281
|
+
lastError: result.lastError,
|
|
5282
|
+
stillRunning: result.stillRunning,
|
|
5283
|
+
progress: result.progress,
|
|
5284
|
+
lastActivityAt: result.lastActivityAt,
|
|
5285
|
+
usage: result.usage
|
|
5286
|
+
})
|
|
5287
|
+
);
|
|
5288
|
+
}
|
|
5289
|
+
);
|
|
5290
|
+
}
|
|
5266
5291
|
server.tool(
|
|
5267
5292
|
"get_turn_result",
|
|
5268
|
-
"Assistant message when the turn finished,
|
|
5293
|
+
"Assistant message and last-turn usage when the turn finished. While stillRunning (submitted/working), text and usage are empty so a previous reply cannot be mistaken for this turn \u2014 use progress for tools/thinking. Not the full transcript. Includes taskState (A2A lifecycle).",
|
|
5269
5294
|
{ ref: z9.string() },
|
|
5270
5295
|
async ({ ref }) => {
|
|
5271
5296
|
const result = orch.getTurnResult(ref);
|
|
@@ -5278,7 +5303,7 @@ async function startMcpServer() {
|
|
|
5278
5303
|
}
|
|
5279
5304
|
);
|
|
5280
5305
|
server.tool(
|
|
5281
|
-
"
|
|
5306
|
+
"stop_chat",
|
|
5282
5307
|
"Force-stop a thread: kill any in-flight agent turn AND clear queued prompts so drainQueue cannot continue. Does not archive the worktree. Optional force defaults to true.",
|
|
5283
5308
|
{
|
|
5284
5309
|
ref: z9.string(),
|
|
@@ -5288,7 +5313,7 @@ async function startMcpServer() {
|
|
|
5288
5313
|
const t = orch.getThread(ref);
|
|
5289
5314
|
if (!t) {
|
|
5290
5315
|
return {
|
|
5291
|
-
content: [{ type: "text", text: `
|
|
5316
|
+
content: [{ type: "text", text: `Chat not found: ${ref}` }],
|
|
5292
5317
|
isError: true
|
|
5293
5318
|
};
|
|
5294
5319
|
}
|
|
@@ -5303,14 +5328,14 @@ async function startMcpServer() {
|
|
|
5303
5328
|
}
|
|
5304
5329
|
);
|
|
5305
5330
|
server.tool(
|
|
5306
|
-
"
|
|
5331
|
+
"archive_chat",
|
|
5307
5332
|
"Archive a thread (stops agent/dev, runs archive script, removes worktree when last chat tab). Coordinators commit, push, and open PRs by asking the worktree agent (ask_git). Merge only when the user explicitly asked.",
|
|
5308
5333
|
{ ref: z9.string() },
|
|
5309
5334
|
async ({ ref }) => {
|
|
5310
5335
|
const t = orch.getThread(ref);
|
|
5311
5336
|
if (!t) {
|
|
5312
5337
|
return {
|
|
5313
|
-
content: [{ type: "text", text: `
|
|
5338
|
+
content: [{ type: "text", text: `Chat not found: ${ref}` }],
|
|
5314
5339
|
isError: true
|
|
5315
5340
|
};
|
|
5316
5341
|
}
|
|
@@ -5329,7 +5354,7 @@ async function startMcpServer() {
|
|
|
5329
5354
|
}
|
|
5330
5355
|
);
|
|
5331
5356
|
server.tool(
|
|
5332
|
-
"
|
|
5357
|
+
"restore_chat",
|
|
5333
5358
|
"Restore an archived thread (recreates worktree from branch when needed)",
|
|
5334
5359
|
{ ref: z9.string() },
|
|
5335
5360
|
async ({ ref }) => {
|
|
@@ -5388,7 +5413,7 @@ async function startMcpServer() {
|
|
|
5388
5413
|
title: tab.title,
|
|
5389
5414
|
status: tab.status,
|
|
5390
5415
|
fromThreadId: from?.id ?? ref,
|
|
5391
|
-
link: `sideboard://
|
|
5416
|
+
link: `sideboard://chat/${tab.id}`
|
|
5392
5417
|
});
|
|
5393
5418
|
} catch (err) {
|
|
5394
5419
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -5413,7 +5438,7 @@ async function startMcpServer() {
|
|
|
5413
5438
|
status: thread.status,
|
|
5414
5439
|
queueLength: thread.queue.length,
|
|
5415
5440
|
action,
|
|
5416
|
-
link: `sideboard://
|
|
5441
|
+
link: `sideboard://chat/${thread.id}`
|
|
5417
5442
|
});
|
|
5418
5443
|
} catch (err) {
|
|
5419
5444
|
const raw = err instanceof Error ? err.message : String(err);
|
|
@@ -5423,7 +5448,7 @@ async function startMcpServer() {
|
|
|
5423
5448
|
error: true,
|
|
5424
5449
|
action,
|
|
5425
5450
|
lastError: message,
|
|
5426
|
-
hint: /body is too long/i.test(message) ? "Branch is already pushed.
|
|
5451
|
+
hint: /body is too long/i.test(message) ? "Branch is already pushed. send_to_chat so the worktree agent runs gh pr create --draft --assignee @me -R <origin> --body-file <short.md>. Keep the description short." : void 0
|
|
5427
5452
|
},
|
|
5428
5453
|
true
|
|
5429
5454
|
);
|
|
@@ -5448,8 +5473,8 @@ async function startMcpServer() {
|
|
|
5448
5473
|
}
|
|
5449
5474
|
);
|
|
5450
5475
|
server.tool(
|
|
5451
|
-
"
|
|
5452
|
-
"Fork a worktree agent chat into a NEW git worktree + chat (desktop \u201CFork to new workspace\u201D). Seeds a transcript (through through_index, default all). Optional agent override. Leave model unset for Auto (default) \u2014 only pass model when you have a reason. Not for the orchestrator. Then
|
|
5476
|
+
"fork_workspace",
|
|
5477
|
+
"Fork a worktree agent chat into a NEW git worktree + chat (desktop \u201CFork to new workspace\u201D). Seeds a transcript (through through_index, default all). Optional agent override. Leave model unset for Auto (default) \u2014 only pass model when you have a reason. Not for the orchestrator. Then send_to_chat / wait_for_turn (loop while stillRunning) on the returned id.",
|
|
5453
5478
|
{
|
|
5454
5479
|
ref: z9.string().describe("Worktree thread id/ref to fork"),
|
|
5455
5480
|
through_index: z9.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
|
|
@@ -5477,7 +5502,7 @@ async function startMcpServer() {
|
|
|
5477
5502
|
branchName: thread.branchName,
|
|
5478
5503
|
worktreePath: thread.worktreePath,
|
|
5479
5504
|
fromThreadId: source?.id ?? ref,
|
|
5480
|
-
link: `sideboard://
|
|
5505
|
+
link: `sideboard://chat/${thread.id}`
|
|
5481
5506
|
});
|
|
5482
5507
|
} catch (err) {
|
|
5483
5508
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -5487,7 +5512,7 @@ async function startMcpServer() {
|
|
|
5487
5512
|
);
|
|
5488
5513
|
server.tool(
|
|
5489
5514
|
"fork_chat",
|
|
5490
|
-
"Fork a chat into a NEW tab on the SAME workspace: worktree agent \u2192 same worktree tab; Global orchestration chat \u2192 new orchestration chat (same synthetic home). Seeds a transcript; optional agent override. Leave model unset for Auto unless you have a reason. Orchestration forks require an MCP-capable agent (claude, cursor, codex, opencode \u2014 not brightsy). Slack / Global orchestrators use this to continue an orchestration chat on another agent after session limits. Then
|
|
5515
|
+
"Fork a chat into a NEW tab on the SAME workspace: worktree agent \u2192 same worktree tab; Global orchestration chat \u2192 new orchestration chat (same synthetic home). Seeds a transcript; optional agent override. Leave model unset for Auto unless you have a reason. Orchestration forks require an MCP-capable agent (claude, cursor, codex, opencode \u2014 not brightsy). Slack / Global orchestrators use this to continue an orchestration chat on another agent after session limits. Then send_to_chat / wait_for_turn (loop while stillRunning) on the returned id. Use fork_workspace only for worktree agents that need a new git worktree.",
|
|
5491
5516
|
{
|
|
5492
5517
|
ref: z9.string().describe("Thread id/ref to fork (worktree agent or orchestration chat)"),
|
|
5493
5518
|
through_index: z9.number().optional().describe("Inclusive message index to include in the transcript (default: all)"),
|
|
@@ -5500,7 +5525,7 @@ async function startMcpServer() {
|
|
|
5500
5525
|
const source = orch.getThread(ref);
|
|
5501
5526
|
if (!source) {
|
|
5502
5527
|
return {
|
|
5503
|
-
content: [{ type: "text", text: `
|
|
5528
|
+
content: [{ type: "text", text: `Chat not found: ${ref}` }],
|
|
5504
5529
|
isError: true
|
|
5505
5530
|
};
|
|
5506
5531
|
}
|
|
@@ -5520,7 +5545,7 @@ async function startMcpServer() {
|
|
|
5520
5545
|
sourceType: tab.sourceType,
|
|
5521
5546
|
worktreePath: tab.worktreePath,
|
|
5522
5547
|
fromThreadId: source.id,
|
|
5523
|
-
link: `sideboard://
|
|
5548
|
+
link: `sideboard://chat/${tab.id}`
|
|
5524
5549
|
});
|
|
5525
5550
|
} catch (err) {
|
|
5526
5551
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -5538,7 +5563,7 @@ async function startMcpServer() {
|
|
|
5538
5563
|
}
|
|
5539
5564
|
);
|
|
5540
5565
|
server.tool(
|
|
5541
|
-
"
|
|
5566
|
+
"add_project",
|
|
5542
5567
|
"Register a git repo as a Sideboard workspace",
|
|
5543
5568
|
{ repoPath: z9.string() },
|
|
5544
5569
|
async ({ repoPath }) => {
|
|
@@ -5547,7 +5572,7 @@ async function startMcpServer() {
|
|
|
5547
5572
|
}
|
|
5548
5573
|
);
|
|
5549
5574
|
server.tool(
|
|
5550
|
-
"
|
|
5575
|
+
"remove_project",
|
|
5551
5576
|
"Unregister a Sideboard workspace (does not archive threads)",
|
|
5552
5577
|
{ repoPath: z9.string() },
|
|
5553
5578
|
async ({ repoPath }) => {
|
|
@@ -5580,7 +5605,7 @@ async function startMcpServer() {
|
|
|
5580
5605
|
);
|
|
5581
5606
|
server.tool(
|
|
5582
5607
|
"list_branches",
|
|
5583
|
-
"List git branches in a registered workspace. Pass repoPath from
|
|
5608
|
+
"List git branches in a registered workspace. Pass repoPath from list_projects (unmerged into the default branch by default \u2014 for create_workspace sourceType=branch).",
|
|
5584
5609
|
{
|
|
5585
5610
|
repoPath: z9.string(),
|
|
5586
5611
|
unmergedOnly: z9.boolean().optional()
|
|
@@ -5602,7 +5627,7 @@ async function startMcpServer() {
|
|
|
5602
5627
|
);
|
|
5603
5628
|
server.tool(
|
|
5604
5629
|
"list_prs",
|
|
5605
|
-
`List GitHub PRs for a registered workspace (the review surface for assigned ticket work \u2014 not the tickets). Pass repoPath from
|
|
5630
|
+
`List GitHub PRs for a registered workspace (the review surface for assigned ticket work \u2014 not the tickets). Pass repoPath from list_projects. "Get me N tickets to review" \u2192 queue=review and limit=N: open non-draft PRs labeled with this project's ready-for-review GitHub label (Settings \u2192 Projects; default eng-review) with no individual user reviewer. Prefer teams that match Settings \u2192 Agents / Projects roles for this repo. A team like engineering-team is not a claim (you are on that team). Also: state (open|closed|merged|all|review), label, reviewer (me|unassigned|login), query, limit (default 40, max 250). Then create_workspace with sourceType=pr.`,
|
|
5606
5631
|
{
|
|
5607
5632
|
repoPath: z9.string(),
|
|
5608
5633
|
query: z9.string().optional().describe("GitHub search tokens (title, draft:true, \u2026)"),
|
|
@@ -5674,7 +5699,7 @@ async function startMcpServer() {
|
|
|
5674
5699
|
stackLayer: t.stackLayer,
|
|
5675
5700
|
worktreePath: t.worktreePath,
|
|
5676
5701
|
prUrl: t.prUrl,
|
|
5677
|
-
link: `sideboard://
|
|
5702
|
+
link: `sideboard://chat/${t.id}`
|
|
5678
5703
|
}))
|
|
5679
5704
|
});
|
|
5680
5705
|
}
|
|
@@ -5695,7 +5720,7 @@ async function startMcpServer() {
|
|
|
5695
5720
|
branchName: result.thread.branchName,
|
|
5696
5721
|
stackLayer: result.thread.stackLayer,
|
|
5697
5722
|
worktreePath: result.thread.worktreePath,
|
|
5698
|
-
link: `sideboard://
|
|
5723
|
+
link: `sideboard://chat/${result.thread.id}`
|
|
5699
5724
|
});
|
|
5700
5725
|
}
|
|
5701
5726
|
);
|
|
@@ -5726,14 +5751,14 @@ async function startMcpServer() {
|
|
|
5726
5751
|
branchName: t.branchName,
|
|
5727
5752
|
stackLayer: t.stackLayer,
|
|
5728
5753
|
worktreePath: t.worktreePath,
|
|
5729
|
-
link: `sideboard://
|
|
5754
|
+
link: `sideboard://chat/${t.id}`
|
|
5730
5755
|
}))
|
|
5731
5756
|
});
|
|
5732
5757
|
}
|
|
5733
5758
|
);
|
|
5734
5759
|
server.tool(
|
|
5735
5760
|
"list_issues",
|
|
5736
|
-
"List or search issues (Linear, AbleTime, or GitHub; falls back to GitHub). Use Settings \u2192 Agents / Projects notes and roles to pick tickets relevant to the viewer (query + assignee=me or unassigned as the notes say). Default 40; pass query and/or limit (max 250) when truncated. assignee: me (Linear default), unassigned, all, or a user id. Pass updatedSince for new/updated tickets and new comments (\u201Cany updates since yesterday?\u201D). Then
|
|
5761
|
+
"List or search issues (Linear, AbleTime, or GitHub; falls back to GitHub). Use Settings \u2192 Agents / Projects notes and roles to pick tickets relevant to the viewer (query + assignee=me or unassigned as the notes say). Default 40; pass query and/or limit (max 250) when truncated. assignee: me (Linear default), unassigned, all, or a user id. Pass updatedSince for new/updated tickets and new comments (\u201Cany updates since yesterday?\u201D). Then create_workspace with sourceType=ticket.",
|
|
5737
5762
|
{
|
|
5738
5763
|
repoPath: z9.string(),
|
|
5739
5764
|
query: z9.string().optional().describe("Search title, identifier, or description"),
|