@sideboard-ai/core 0.1.180 → 0.1.181
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-INEHQH6K.js → abletime-CAFQ4GEG.js} +1 -1
- package/dist/{abletime-BFIDZR3O.js → abletime-J3EGHIAV.js} +1 -1
- package/dist/{agents-K5KPOPUF.js → agents-BQQ6BRJO.js} +2 -2
- package/dist/{agents-RLSNLQJM.js → agents-GBI2YFCE.js} +2 -2
- package/dist/{chunk-MY6TL2OG.js → chunk-26N6LKLE.js} +40 -25
- package/dist/{chunk-SQQLYUEB.js → chunk-B4IENDRW.js} +39 -24
- package/dist/{chunk-ZWXBBKGL.js → chunk-JA7TKTQ4.js} +5 -4
- package/dist/{chunk-WBR5FEAN.js → chunk-JFDCHOU7.js} +5 -4
- package/dist/{chunk-BBNUL4IE.js → chunk-KEVY4GEK.js} +13 -2
- package/dist/{chunk-RE2YWFUQ.js → chunk-TEJU6UJY.js} +13 -2
- package/dist/{chunk-6DSG6NJA.js → chunk-TPOODE27.js} +2 -2
- package/dist/{chunk-PQEXH363.js → chunk-VA76U3BU.js} +3 -2
- package/dist/{coordinator-prompt-EGESQGWI.js → coordinator-prompt-NEF3AEFG.js} +1 -1
- package/dist/{coordinator-prompt-2BCFFPLA.js → coordinator-prompt-UBCXNR5V.js} +1 -1
- package/dist/{global-workspace-GEA27OKN.js → global-workspace-5B6AOK7A.js} +1 -1
- package/dist/{global-workspace-ILYFKJYR.js → global-workspace-RNPHVMFM.js} +1 -1
- package/dist/index.cjs +680 -339
- package/dist/index.d.cts +49 -3
- package/dist/index.d.ts +49 -3
- package/dist/index.js +626 -316
- package/dist/mcp/run-stdio.cjs +852 -516
- package/dist/mcp/run-stdio.js +798 -493
- package/dist/{orchestrator-E7QGQ2FN.js → orchestrator-CMNI3MIS.js} +3 -3
- package/dist/{orchestrator-6A5TLX5O.js → orchestrator-H4G6SN4O.js} +3 -3
- package/dist/{workspaces-4FOAU33G.js → workspaces-4ZTRQX2J.js} +1 -1
- package/dist/{workspaces-UOTJ2YKF.js → workspaces-NQQ5X6L4.js} +1 -1
- package/package.json +1 -1
|
@@ -38,11 +38,11 @@ import {
|
|
|
38
38
|
resolveQuotaFallbackAgent,
|
|
39
39
|
turnCostUsdFromCursorUsage,
|
|
40
40
|
whichOnPath
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-TPOODE27.js";
|
|
42
42
|
import "./chunk-HVIEYTUK.js";
|
|
43
43
|
import "./chunk-Y4MIXGPA.js";
|
|
44
44
|
import "./chunk-VKQGAWHY.js";
|
|
45
|
-
import "./chunk-
|
|
45
|
+
import "./chunk-JA7TKTQ4.js";
|
|
46
46
|
import "./chunk-XBLN52RZ.js";
|
|
47
47
|
import "./chunk-D6JWYJ4P.js";
|
|
48
48
|
import "./chunk-GOZ6T3AG.js";
|
|
@@ -32,8 +32,8 @@ import {
|
|
|
32
32
|
resolveLoginCommand,
|
|
33
33
|
resolveQuotaFallbackAgent,
|
|
34
34
|
whichOnPath
|
|
35
|
-
} from "./chunk-
|
|
36
|
-
import "./chunk-
|
|
35
|
+
} from "./chunk-VA76U3BU.js";
|
|
36
|
+
import "./chunk-JFDCHOU7.js";
|
|
37
37
|
import "./chunk-WXKXSZN4.js";
|
|
38
38
|
import "./chunk-6K64FJDD.js";
|
|
39
39
|
import "./chunk-IEEAVWAP.js";
|
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
stripBrightsyNdjsonNoise,
|
|
25
25
|
sumUsageList,
|
|
26
26
|
toolDescription
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-VA76U3BU.js";
|
|
28
28
|
import {
|
|
29
29
|
SLACK_REPLY_FORMATTING,
|
|
30
30
|
addWorkspace,
|
|
@@ -47,7 +47,7 @@ import {
|
|
|
47
47
|
stageAbsolutePathsAsAttachments,
|
|
48
48
|
stageBuffersAsAttachments,
|
|
49
49
|
syncWorkspacesFromThreads
|
|
50
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-JFDCHOU7.js";
|
|
51
51
|
import {
|
|
52
52
|
addPrStackLayer,
|
|
53
53
|
allocateTeamName,
|
|
@@ -467,7 +467,7 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
467
467
|
await continueOnReply(threadId, prompt);
|
|
468
468
|
return;
|
|
469
469
|
}
|
|
470
|
-
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-
|
|
470
|
+
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-CMNI3MIS.js");
|
|
471
471
|
await getOrchestrator2().send(threadId, prompt);
|
|
472
472
|
} catch {
|
|
473
473
|
}
|
|
@@ -801,9 +801,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
801
801
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
802
802
|
);
|
|
803
803
|
}
|
|
804
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
804
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-5B6AOK7A.js");
|
|
805
805
|
if (isGlobalThread2(thread)) {
|
|
806
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
806
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-NEF3AEFG.js");
|
|
807
807
|
ensureGlobalCoordinatorCwd2(
|
|
808
808
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
809
809
|
);
|
|
@@ -1676,7 +1676,7 @@ The report stays in this chat until the user posts it. Do not call \`github_comm
|
|
|
1676
1676
|
|
|
1677
1677
|
After the Recommendation is in chat, ask_user (**Post this review** / **Keep it in chat**), then wait. If they already asked you to post a specific comment or update in this turn, that is confirmation.
|
|
1678
1678
|
|
|
1679
|
-
The PR author sees those writes immediately \u2014 a draft review will confuse them. Do not request reviewers, change labels, or assign yourself unless they asked.
|
|
1679
|
+
The user should be able to work through the feedback in chat first. The PR or ticket author sees those writes immediately \u2014 a draft review will confuse them. Do not request reviewers, change labels, or assign yourself unless they asked.
|
|
1680
1680
|
|
|
1681
1681
|
## Findings
|
|
1682
1682
|
|
|
@@ -3733,7 +3733,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3733
3733
|
let sourceIsFork = false;
|
|
3734
3734
|
if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
|
|
3735
3735
|
if (isAbleTimeConnected() && getIssueSource() === "abletime") {
|
|
3736
|
-
const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-
|
|
3736
|
+
const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-CAFQ4GEG.js");
|
|
3737
3737
|
const task = await ensureAbleTimeTask({
|
|
3738
3738
|
title: title?.trim() || "Untitled work",
|
|
3739
3739
|
description: input.prompt?.trim() || void 0
|
|
@@ -3835,7 +3835,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3835
3835
|
return readThread(thread.id) ?? thread;
|
|
3836
3836
|
}
|
|
3837
3837
|
async function listLinearIssues(agent, repoPath) {
|
|
3838
|
-
const { getAdapter: getAdapter2 } = await import("./agents-
|
|
3838
|
+
const { getAdapter: getAdapter2 } = await import("./agents-GBI2YFCE.js");
|
|
3839
3839
|
await requireAgent(agent, { requireLinear: true });
|
|
3840
3840
|
const adapter = getAdapter2(agent);
|
|
3841
3841
|
if (!adapter.listLinearIssues) {
|
|
@@ -4257,7 +4257,7 @@ async function adoptThread(input) {
|
|
|
4257
4257
|
messages: input.messages ?? []
|
|
4258
4258
|
});
|
|
4259
4259
|
writeThread(thread);
|
|
4260
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
4260
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-NQQ5X6L4.js");
|
|
4261
4261
|
await ensureWorkspace2(repoPath);
|
|
4262
4262
|
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-X54WSOXM.js");
|
|
4263
4263
|
await ensureWorktreeSideboardIgnored2(input.worktreePath);
|
|
@@ -6091,28 +6091,28 @@ function formatIssueToolsDirective(opts) {
|
|
|
6091
6091
|
];
|
|
6092
6092
|
if (opts.linear) {
|
|
6093
6093
|
lines.push(
|
|
6094
|
-
"- Linear: `linear_get_issue` (comments; pass `include=full` if crush.truncated), `linear_comment`, `linear_update_issue` (state), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
|
|
6094
|
+
"- Linear: `linear_search_issues` (assignee=me; pass `updatedSince` for \u201Cany updates since yesterday?\u201D \u2014 new tickets, edits, and comments), `linear_get_issue` (comments; pass `include=full` if crush.truncated), `linear_comment`, `linear_update_issue` (state), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
|
|
6095
6095
|
);
|
|
6096
6096
|
}
|
|
6097
6097
|
if (github) {
|
|
6098
6098
|
lines.push(
|
|
6099
|
-
"- GitHub: `github_get_issue` (comments; pass `include=full` if crush.truncated), `github_comment`, `github_update_issue` (state open|closed), `github_create_issue` (pass `parent` for spin-offs). Uses Account `gh`."
|
|
6099
|
+
"- GitHub: `github_search_issues` (assignee=me; `updatedSince` for inbox updates + comments), `github_get_issue` (comments; pass `include=full` if crush.truncated), `github_comment`, `github_update_issue` (state open|closed), `github_create_issue` (pass `parent` for spin-offs). Uses Account `gh`."
|
|
6100
6100
|
);
|
|
6101
6101
|
}
|
|
6102
6102
|
if (opts.abletime) {
|
|
6103
6103
|
lines.push(
|
|
6104
|
-
"- AbleTime: `abletime_get_task` (comments; pass `include=full` if crush.truncated), `abletime_comment`, `abletime_update_task` (state), `abletime_create_task` (pass `parent` for spin-offs; `abletime_list_projects` if needed)."
|
|
6104
|
+
"- AbleTime: `abletime_list_tasks` / `abletime_search_tasks` (`updatedSince` for inbox updates + comments), `abletime_get_task` (comments; pass `include=full` if crush.truncated), `abletime_comment`, `abletime_update_task` (state), `abletime_create_task` (pass `parent` for spin-offs; `abletime_list_projects` if needed)."
|
|
6105
6105
|
);
|
|
6106
6106
|
}
|
|
6107
6107
|
lines.push(
|
|
6108
6108
|
"- Do not ask the user to `claude mcp login` for tickets. Reconnect the Account source in Settings \u2192 Issues (or Git for `gh`).",
|
|
6109
|
-
"- When reviewing
|
|
6109
|
+
"- When reviewing a PR or ticket (review inbox or a Review tab): write the review in chat so the user can work through the feedback first; ask_user (Post this review / Keep it in chat) before `github_comment` / `linear_comment` / `*_update_*` / `gh pr review`. The PR or ticket author sees those immediately."
|
|
6110
6110
|
);
|
|
6111
6111
|
const ticket = opts.ticketId?.trim();
|
|
6112
6112
|
if (ticket) {
|
|
6113
6113
|
const provider = opts.ticketProvider ?? "linear";
|
|
6114
6114
|
lines.push(
|
|
6115
|
-
`- This thread's ticket is \`${ticket}\` (${provider}). Use that id for get
|
|
6115
|
+
`- This thread's ticket is \`${ticket}\` (${provider}). Use that id for get. Do not comment or update it with review findings until they confirm (ask_user: Post this review / Keep it in chat) \u2014 they should work through the feedback in chat first. If they asked you to do the work, routine status and spin-offs (\`parent=\`) are OK.`
|
|
6116
6116
|
);
|
|
6117
6117
|
}
|
|
6118
6118
|
return lines.join("\n");
|
|
@@ -6135,8 +6135,8 @@ function formatIssueToolsReminder(opts) {
|
|
|
6135
6135
|
opts.abletime ? "abletime_*" : null
|
|
6136
6136
|
].filter(Boolean);
|
|
6137
6137
|
const ticket = opts.ticketId?.trim();
|
|
6138
|
-
const ticketBit = ticket ? ` This ticket: ${ticket}${opts.ticketProvider ? ` (${opts.ticketProvider})` : ""} \u2014 get
|
|
6139
|
-
return `Issues: Sideboard ${names.join(" / ")} (Account). Ignore vendor issue MCP auth.${ticketBit}
|
|
6138
|
+
const ticketBit = ticket ? ` This ticket: ${ticket}${opts.ticketProvider ? ` (${opts.ticketProvider})` : ""} \u2014 get; comment/update review findings only after ask_user. Spin-offs use parent=.` : " get/comment/update/create (parent= for spin-offs).";
|
|
6139
|
+
return `Issues: Sideboard ${names.join(" / ")} (Account). Ignore vendor issue MCP auth.${ticketBit} Review feedback stays in chat until ask_user (Post this review / Keep it in chat) \u2014 PR and ticket authors see comments immediately.`;
|
|
6140
6140
|
}
|
|
6141
6141
|
function formatLinearReminder(opts) {
|
|
6142
6142
|
return formatIssueToolsReminder({
|
|
@@ -6200,19 +6200,28 @@ function formatUiReminder() {
|
|
|
6200
6200
|
|
|
6201
6201
|
// src/review/review-write-gate.ts
|
|
6202
6202
|
var REVIEW_TAB_TITLE = "Review";
|
|
6203
|
-
function
|
|
6204
|
-
|
|
6203
|
+
function hasLiveReviewSibling(thread, siblings = []) {
|
|
6204
|
+
const selfId = thread.id;
|
|
6205
|
+
return siblings.some(
|
|
6206
|
+
(t) => t.id !== selfId && t.status !== "archived" && t.title.trim() === REVIEW_TAB_TITLE
|
|
6207
|
+
);
|
|
6208
|
+
}
|
|
6209
|
+
function isReviewWriteGatedThread(thread, siblings) {
|
|
6210
|
+
if (thread.sourceType === "pr" || thread.title.trim() === REVIEW_TAB_TITLE) {
|
|
6211
|
+
return true;
|
|
6212
|
+
}
|
|
6213
|
+
return hasLiveReviewSibling(thread, siblings);
|
|
6205
6214
|
}
|
|
6206
6215
|
function formatReviewWriteGateDirective() {
|
|
6207
6216
|
return [
|
|
6208
|
-
"Review writes are public. The PR author sees GitHub/Linear comments, ticket updates, and submitted reviews immediately \u2014 a draft will confuse them.",
|
|
6209
|
-
"Write the recommendation in chat. Do not call github_comment, linear_comment, abletime_comment, github_update_issue, linear_update_issue, abletime_update_task, or run `gh pr review` / `gh pr comment`, until the user confirms.",
|
|
6217
|
+
"Review writes are public. The PR or ticket author sees GitHub/Linear/AbleTime comments, ticket updates, and submitted reviews immediately \u2014 a draft will confuse them.",
|
|
6218
|
+
"Write the recommendation in chat so the user can work through the feedback first. Do not call github_comment, linear_comment, abletime_comment, github_update_issue, linear_update_issue, abletime_update_task, or run `gh pr review` / `gh pr comment`, until the user confirms.",
|
|
6210
6219
|
"After the review is in chat, ask_user (Post this review / Keep it in chat), then wait. If they already asked you to post a specific comment or update in this turn, that is confirmation.",
|
|
6211
6220
|
"Do not request reviewers, change labels, or assign yourself unless they asked \u2014 those also notify the author."
|
|
6212
6221
|
].join("\n");
|
|
6213
6222
|
}
|
|
6214
6223
|
function formatReviewWriteGateReminder() {
|
|
6215
|
-
return "Review writes: keep the review in chat. ask_user (Post this review / Keep it in chat) before github_comment / linear_comment / *_update_* / `gh pr review
|
|
6224
|
+
return "Review writes: keep the review in chat so they can work through it. ask_user (Post this review / Keep it in chat) before github_comment / linear_comment / *_update_* / `gh pr review` on the PR or ticket. Authors see those immediately.";
|
|
6216
6225
|
}
|
|
6217
6226
|
|
|
6218
6227
|
// src/integrations/optional-services.ts
|
|
@@ -6757,7 +6766,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
6757
6766
|
${prompt}`;
|
|
6758
6767
|
}
|
|
6759
6768
|
async function defaultDeps() {
|
|
6760
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
6769
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-CMNI3MIS.js");
|
|
6761
6770
|
const orch = getOrchestrator2();
|
|
6762
6771
|
return {
|
|
6763
6772
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -7588,7 +7597,10 @@ var Orchestrator = class {
|
|
|
7588
7597
|
ticketProvider: issueTicket?.provider
|
|
7589
7598
|
}) : null;
|
|
7590
7599
|
const viewerContextReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatViewerContextReminder() : null;
|
|
7591
|
-
const reviewWriteGateReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) && isReviewWriteGatedThread(
|
|
7600
|
+
const reviewWriteGateReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) && isReviewWriteGatedThread(
|
|
7601
|
+
thread,
|
|
7602
|
+
thread.worktreePath ? threadsSharingWorktree(thread.worktreePath) : []
|
|
7603
|
+
) ? formatReviewWriteGateReminder() : null;
|
|
7592
7604
|
const slackReplyContext = formatSlackRepliesForTurn(
|
|
7593
7605
|
pendingSlackExternalReplies(thread.messages)
|
|
7594
7606
|
);
|
|
@@ -7644,7 +7656,10 @@ var Orchestrator = class {
|
|
|
7644
7656
|
ticketId: freshIssueTicket?.id,
|
|
7645
7657
|
ticketProvider: freshIssueTicket?.provider
|
|
7646
7658
|
});
|
|
7647
|
-
const reviewWriteGateDirective = isBrightsy || isOrchestration || !isReviewWriteGatedThread(
|
|
7659
|
+
const reviewWriteGateDirective = isBrightsy || isOrchestration || !isReviewWriteGatedThread(
|
|
7660
|
+
fresh,
|
|
7661
|
+
fresh.worktreePath ? threadsSharingWorktree(fresh.worktreePath) : []
|
|
7662
|
+
) ? null : formatReviewWriteGateDirective();
|
|
7648
7663
|
let viewerContextDirective = null;
|
|
7649
7664
|
if (!isBrightsy && !isOrchestration) {
|
|
7650
7665
|
try {
|
|
@@ -8873,7 +8888,7 @@ var Orchestrator = class {
|
|
|
8873
8888
|
this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
|
|
8874
8889
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
8875
8890
|
try {
|
|
8876
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
8891
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-NQQ5X6L4.js");
|
|
8877
8892
|
await ensureWorkspace2(thread.repoPath);
|
|
8878
8893
|
} catch {
|
|
8879
8894
|
}
|
|
@@ -33,7 +33,7 @@ import {
|
|
|
33
33
|
summarizeTurnStderr,
|
|
34
34
|
toolDescription,
|
|
35
35
|
turnFailChatText
|
|
36
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-TPOODE27.js";
|
|
37
37
|
import {
|
|
38
38
|
extractPresentedPlan,
|
|
39
39
|
readPlanFile,
|
|
@@ -64,7 +64,7 @@ import {
|
|
|
64
64
|
stageAbsolutePathsAsAttachments,
|
|
65
65
|
stageBuffersAsAttachments,
|
|
66
66
|
syncWorkspacesFromThreads
|
|
67
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-JA7TKTQ4.js";
|
|
68
68
|
import {
|
|
69
69
|
addPrStackLayer,
|
|
70
70
|
allocateTeamName,
|
|
@@ -402,7 +402,7 @@ async function continueSourceThread(threadId, prompt) {
|
|
|
402
402
|
await continueOnReply(threadId, prompt);
|
|
403
403
|
return;
|
|
404
404
|
}
|
|
405
|
-
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-
|
|
405
|
+
const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-H4G6SN4O.js");
|
|
406
406
|
await getOrchestrator2().send(threadId, prompt);
|
|
407
407
|
} catch {
|
|
408
408
|
}
|
|
@@ -795,9 +795,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
|
|
|
795
795
|
`Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
|
|
796
796
|
);
|
|
797
797
|
}
|
|
798
|
-
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-
|
|
798
|
+
const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-RNPHVMFM.js");
|
|
799
799
|
if (isGlobalThread2(thread)) {
|
|
800
|
-
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-
|
|
800
|
+
const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-UBCXNR5V.js");
|
|
801
801
|
ensureGlobalCoordinatorCwd2(
|
|
802
802
|
isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
|
|
803
803
|
);
|
|
@@ -1645,7 +1645,7 @@ The report stays in this chat until the user posts it. Do not call \`github_comm
|
|
|
1645
1645
|
|
|
1646
1646
|
After the Recommendation is in chat, ask_user (**Post this review** / **Keep it in chat**), then wait. If they already asked you to post a specific comment or update in this turn, that is confirmation.
|
|
1647
1647
|
|
|
1648
|
-
The PR author sees those writes immediately \u2014 a draft review will confuse them. Do not request reviewers, change labels, or assign yourself unless they asked.
|
|
1648
|
+
The user should be able to work through the feedback in chat first. The PR or ticket author sees those writes immediately \u2014 a draft review will confuse them. Do not request reviewers, change labels, or assign yourself unless they asked.
|
|
1649
1649
|
|
|
1650
1650
|
## Findings
|
|
1651
1651
|
|
|
@@ -3604,7 +3604,7 @@ async function createThread(input, _onSetupLine) {
|
|
|
3604
3604
|
let sourceIsFork = false;
|
|
3605
3605
|
if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
|
|
3606
3606
|
if (isAbleTimeConnected() && getIssueSource() === "abletime") {
|
|
3607
|
-
const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-
|
|
3607
|
+
const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-J3EGHIAV.js");
|
|
3608
3608
|
const task = await ensureAbleTimeTask({
|
|
3609
3609
|
title: title?.trim() || "Untitled work",
|
|
3610
3610
|
description: input.prompt?.trim() || void 0
|
|
@@ -4116,7 +4116,7 @@ async function adoptThread(input) {
|
|
|
4116
4116
|
messages: input.messages ?? []
|
|
4117
4117
|
});
|
|
4118
4118
|
writeThread(thread);
|
|
4119
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
4119
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-4ZTRQX2J.js");
|
|
4120
4120
|
await ensureWorkspace2(repoPath);
|
|
4121
4121
|
const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-N5X5I422.js");
|
|
4122
4122
|
await ensureWorktreeSideboardIgnored2(input.worktreePath);
|
|
@@ -5933,28 +5933,28 @@ function formatIssueToolsDirective(opts) {
|
|
|
5933
5933
|
];
|
|
5934
5934
|
if (opts.linear) {
|
|
5935
5935
|
lines.push(
|
|
5936
|
-
"- Linear: `linear_get_issue` (comments; pass `include=full` if crush.truncated), `linear_comment`, `linear_update_issue` (state), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
|
|
5936
|
+
"- Linear: `linear_search_issues` (assignee=me; pass `updatedSince` for \u201Cany updates since yesterday?\u201D \u2014 new tickets, edits, and comments), `linear_get_issue` (comments; pass `include=full` if crush.truncated), `linear_comment`, `linear_update_issue` (state), `linear_create_issue` (pass `parent` for spin-offs; call `linear_list_teams` first). Scope errors: reconnect Linear in Settings \u2192 Issues."
|
|
5937
5937
|
);
|
|
5938
5938
|
}
|
|
5939
5939
|
if (github) {
|
|
5940
5940
|
lines.push(
|
|
5941
|
-
"- GitHub: `github_get_issue` (comments; pass `include=full` if crush.truncated), `github_comment`, `github_update_issue` (state open|closed), `github_create_issue` (pass `parent` for spin-offs). Uses Account `gh`."
|
|
5941
|
+
"- GitHub: `github_search_issues` (assignee=me; `updatedSince` for inbox updates + comments), `github_get_issue` (comments; pass `include=full` if crush.truncated), `github_comment`, `github_update_issue` (state open|closed), `github_create_issue` (pass `parent` for spin-offs). Uses Account `gh`."
|
|
5942
5942
|
);
|
|
5943
5943
|
}
|
|
5944
5944
|
if (opts.abletime) {
|
|
5945
5945
|
lines.push(
|
|
5946
|
-
"- AbleTime: `abletime_get_task` (comments; pass `include=full` if crush.truncated), `abletime_comment`, `abletime_update_task` (state), `abletime_create_task` (pass `parent` for spin-offs; `abletime_list_projects` if needed)."
|
|
5946
|
+
"- AbleTime: `abletime_list_tasks` / `abletime_search_tasks` (`updatedSince` for inbox updates + comments), `abletime_get_task` (comments; pass `include=full` if crush.truncated), `abletime_comment`, `abletime_update_task` (state), `abletime_create_task` (pass `parent` for spin-offs; `abletime_list_projects` if needed)."
|
|
5947
5947
|
);
|
|
5948
5948
|
}
|
|
5949
5949
|
lines.push(
|
|
5950
5950
|
"- Do not ask the user to `claude mcp login` for tickets. Reconnect the Account source in Settings \u2192 Issues (or Git for `gh`).",
|
|
5951
|
-
"- When reviewing
|
|
5951
|
+
"- When reviewing a PR or ticket (review inbox or a Review tab): write the review in chat so the user can work through the feedback first; ask_user (Post this review / Keep it in chat) before `github_comment` / `linear_comment` / `*_update_*` / `gh pr review`. The PR or ticket author sees those immediately."
|
|
5952
5952
|
);
|
|
5953
5953
|
const ticket = opts.ticketId?.trim();
|
|
5954
5954
|
if (ticket) {
|
|
5955
5955
|
const provider = opts.ticketProvider ?? "linear";
|
|
5956
5956
|
lines.push(
|
|
5957
|
-
`- This thread's ticket is \`${ticket}\` (${provider}). Use that id for get
|
|
5957
|
+
`- This thread's ticket is \`${ticket}\` (${provider}). Use that id for get. Do not comment or update it with review findings until they confirm (ask_user: Post this review / Keep it in chat) \u2014 they should work through the feedback in chat first. If they asked you to do the work, routine status and spin-offs (\`parent=\`) are OK.`
|
|
5958
5958
|
);
|
|
5959
5959
|
}
|
|
5960
5960
|
return lines.join("\n");
|
|
@@ -5968,8 +5968,8 @@ function formatIssueToolsReminder(opts) {
|
|
|
5968
5968
|
opts.abletime ? "abletime_*" : null
|
|
5969
5969
|
].filter(Boolean);
|
|
5970
5970
|
const ticket = opts.ticketId?.trim();
|
|
5971
|
-
const ticketBit = ticket ? ` This ticket: ${ticket}${opts.ticketProvider ? ` (${opts.ticketProvider})` : ""} \u2014 get
|
|
5972
|
-
return `Issues: Sideboard ${names.join(" / ")} (Account). Ignore vendor issue MCP auth.${ticketBit}
|
|
5971
|
+
const ticketBit = ticket ? ` This ticket: ${ticket}${opts.ticketProvider ? ` (${opts.ticketProvider})` : ""} \u2014 get; comment/update review findings only after ask_user. Spin-offs use parent=.` : " get/comment/update/create (parent= for spin-offs).";
|
|
5972
|
+
return `Issues: Sideboard ${names.join(" / ")} (Account). Ignore vendor issue MCP auth.${ticketBit} Review feedback stays in chat until ask_user (Post this review / Keep it in chat) \u2014 PR and ticket authors see comments immediately.`;
|
|
5973
5973
|
}
|
|
5974
5974
|
function formatPrGateDirective() {
|
|
5975
5975
|
return [
|
|
@@ -6024,19 +6024,28 @@ function formatUiReminder() {
|
|
|
6024
6024
|
|
|
6025
6025
|
// src/review/review-write-gate.ts
|
|
6026
6026
|
var REVIEW_TAB_TITLE = "Review";
|
|
6027
|
-
function
|
|
6028
|
-
|
|
6027
|
+
function hasLiveReviewSibling(thread, siblings = []) {
|
|
6028
|
+
const selfId = thread.id;
|
|
6029
|
+
return siblings.some(
|
|
6030
|
+
(t) => t.id !== selfId && t.status !== "archived" && t.title.trim() === REVIEW_TAB_TITLE
|
|
6031
|
+
);
|
|
6032
|
+
}
|
|
6033
|
+
function isReviewWriteGatedThread(thread, siblings) {
|
|
6034
|
+
if (thread.sourceType === "pr" || thread.title.trim() === REVIEW_TAB_TITLE) {
|
|
6035
|
+
return true;
|
|
6036
|
+
}
|
|
6037
|
+
return hasLiveReviewSibling(thread, siblings);
|
|
6029
6038
|
}
|
|
6030
6039
|
function formatReviewWriteGateDirective() {
|
|
6031
6040
|
return [
|
|
6032
|
-
"Review writes are public. The PR author sees GitHub/Linear comments, ticket updates, and submitted reviews immediately \u2014 a draft will confuse them.",
|
|
6033
|
-
"Write the recommendation in chat. Do not call github_comment, linear_comment, abletime_comment, github_update_issue, linear_update_issue, abletime_update_task, or run `gh pr review` / `gh pr comment`, until the user confirms.",
|
|
6041
|
+
"Review writes are public. The PR or ticket author sees GitHub/Linear/AbleTime comments, ticket updates, and submitted reviews immediately \u2014 a draft will confuse them.",
|
|
6042
|
+
"Write the recommendation in chat so the user can work through the feedback first. Do not call github_comment, linear_comment, abletime_comment, github_update_issue, linear_update_issue, abletime_update_task, or run `gh pr review` / `gh pr comment`, until the user confirms.",
|
|
6034
6043
|
"After the review is in chat, ask_user (Post this review / Keep it in chat), then wait. If they already asked you to post a specific comment or update in this turn, that is confirmation.",
|
|
6035
6044
|
"Do not request reviewers, change labels, or assign yourself unless they asked \u2014 those also notify the author."
|
|
6036
6045
|
].join("\n");
|
|
6037
6046
|
}
|
|
6038
6047
|
function formatReviewWriteGateReminder() {
|
|
6039
|
-
return "Review writes: keep the review in chat. ask_user (Post this review / Keep it in chat) before github_comment / linear_comment / *_update_* / `gh pr review
|
|
6048
|
+
return "Review writes: keep the review in chat so they can work through it. ask_user (Post this review / Keep it in chat) before github_comment / linear_comment / *_update_* / `gh pr review` on the PR or ticket. Authors see those immediately.";
|
|
6040
6049
|
}
|
|
6041
6050
|
|
|
6042
6051
|
// src/integrations/optional-services.ts
|
|
@@ -6410,7 +6419,7 @@ function formatScheduledPrompt(name, prompt) {
|
|
|
6410
6419
|
${prompt}`;
|
|
6411
6420
|
}
|
|
6412
6421
|
async function defaultDeps() {
|
|
6413
|
-
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-
|
|
6422
|
+
const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-H4G6SN4O.js");
|
|
6414
6423
|
const orch = getOrchestrator2();
|
|
6415
6424
|
return {
|
|
6416
6425
|
findThread: (id) => findThreadByRef(id),
|
|
@@ -7241,7 +7250,10 @@ var Orchestrator = class {
|
|
|
7241
7250
|
ticketProvider: issueTicket?.provider
|
|
7242
7251
|
}) : null;
|
|
7243
7252
|
const viewerContextReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) ? formatViewerContextReminder() : null;
|
|
7244
|
-
const reviewWriteGateReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) && isReviewWriteGatedThread(
|
|
7253
|
+
const reviewWriteGateReminder = thread.agent !== "brightsy" && !isOrchestratorThread(thread) && isReviewWriteGatedThread(
|
|
7254
|
+
thread,
|
|
7255
|
+
thread.worktreePath ? threadsSharingWorktree(thread.worktreePath) : []
|
|
7256
|
+
) ? formatReviewWriteGateReminder() : null;
|
|
7245
7257
|
const slackReplyContext = formatSlackRepliesForTurn(
|
|
7246
7258
|
pendingSlackExternalReplies(thread.messages)
|
|
7247
7259
|
);
|
|
@@ -7297,7 +7309,10 @@ var Orchestrator = class {
|
|
|
7297
7309
|
ticketId: freshIssueTicket?.id,
|
|
7298
7310
|
ticketProvider: freshIssueTicket?.provider
|
|
7299
7311
|
});
|
|
7300
|
-
const reviewWriteGateDirective = isBrightsy || isOrchestration || !isReviewWriteGatedThread(
|
|
7312
|
+
const reviewWriteGateDirective = isBrightsy || isOrchestration || !isReviewWriteGatedThread(
|
|
7313
|
+
fresh,
|
|
7314
|
+
fresh.worktreePath ? threadsSharingWorktree(fresh.worktreePath) : []
|
|
7315
|
+
) ? null : formatReviewWriteGateDirective();
|
|
7301
7316
|
let viewerContextDirective = null;
|
|
7302
7317
|
if (!isBrightsy && !isOrchestration) {
|
|
7303
7318
|
try {
|
|
@@ -8526,7 +8541,7 @@ var Orchestrator = class {
|
|
|
8526
8541
|
this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
|
|
8527
8542
|
if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
|
|
8528
8543
|
try {
|
|
8529
|
-
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-
|
|
8544
|
+
const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-4ZTRQX2J.js");
|
|
8530
8545
|
await ensureWorkspace2(thread.repoPath);
|
|
8531
8546
|
} catch {
|
|
8532
8547
|
}
|
|
@@ -329,8 +329,9 @@ var COORDINATOR_TOOL_PLAYBOOK = [
|
|
|
329
329
|
"- list_board \u2014 Home Kanban of worktrees (New / Draft / Review / Merged; one card per checkout). 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, column, limit.",
|
|
330
330
|
'- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces. Review is PRs (the surface for assigned ticket work), not the tickets: "Get me N tickets to review" \u2192 list_prs(queue=review, limit=N) then create_thread sourceType=pr. That is open non-draft PRs labeled eng-review with no individual user reviewer yet. A team request (engineering-team) is not a claim \u2014 the viewer is on that team and can pick it up; claimed means an individual account is the reviewer. Bots ignored. Use Settings \u2192 Agents / Projects context (roles, teams, labels \u2014 freeform text; project adds to account) to prefer the right queues. queue=mine is review-requested:@me; queue=approved|changes uses those labels. Also: state, label, reviewer=me|unassigned|login, query, limit default 40 max 250; raise limit or tighten when truncated. list_issues (query, assignee=me|unassigned|all|user, limit default 40 max 250) lists Linear, AbleTime, or GitHub tickets \u2014 do not use it for that review-inbox ask. When they ask for tickets to work on, follow their context (assignee=me or unassigned as it says).',
|
|
331
331
|
"- Find work: when they ask to find work, pick up tickets, or list reviews, use Settings \u2192 Agents (account) plus Settings \u2192 Projects (per-repo) context. Tickets \u2192 Sideboard list_issues / linear_* (Account Linear). Reviews \u2192 list_prs(queue=review). Do not call Claude Linear MCP or any other vendor Linear MCP \u2014 those HTTP connectors hang or flap on the first turn. If a vendor MCP is down or reconnecting, ignore it and keep going with Sideboard tools. Show the options \u2014 do not create_thread or start unless they also asked to start (e.g. \u201Cfind me work and start it\u201D). Do not start this unprompted. To change that context, show the proposed text, ask_user (Save this context / Do not save), wait, then update_viewer_context with confirmed=true. Never write it without confirmation.",
|
|
332
|
-
"-
|
|
333
|
-
"-
|
|
332
|
+
"- Ticket updates: list_issues / linear_search_issues / github_search_issues with updatedSince (yesterday, 2d, or ISO). One call returns new assignments, ticket edits, and new comments \u2014 do not get_issue every ticket just to check for comments. kind=created vs updated distinguishes new tickets from existing ones.",
|
|
333
|
+
"- linear_* (when Linear is connected) \u2014 list_teams for team key/states; get/create/update/comment with ENG-123. Worktree agents have the same Account tools \u2014 prefer they comment, update status, and create spin-offs (parent=) on their own ticket when they were asked to do the work. When reviewing a PR or ticket, do not comment or update until the user confirms (ask_user: Post this review / Keep it in chat) \u2014 they should work through the feedback in chat first. Scope errors: reconnect Linear in Account settings. Prefer these over any Linear MCP the CLI may still list.",
|
|
334
|
+
"- github_* \u2014 get/comment/update/create GitHub issues via Account `gh` (#123). Worktree agents have these too. Prefer over any vendor GitHub MCP. Pass parent= for spin-offs. When reviewing a PR or ticket, do not comment, submit `gh pr review`, or update the PR/ticket until the user confirms.",
|
|
334
335
|
"- abletime_* (when AbleTime is connected) \u2014 orientation first; get/comment/update/create (parent= for spin-offs); ensure_task when work has no ticket (or create_thread from the default branch auto-creates one). Worktree agents have the same Account tools. Same review-write gate as Linear/GitHub.",
|
|
335
336
|
"- list_teams / slack_list_channels / slack_list_users / slack_search / slack_read / slack_post / slack_replies \u2014 Slack workspaces from Settings \u2192 Remote; pass team_id from list_teams",
|
|
336
337
|
"- Optional connectors (Vercel, Supabase, PostHog, Sentry) in Settings \u2192 Connectors inject tokens into worktree agent env when connected. Prefer official CLIs (`vercel`, `supabase`, `sentry-cli`) with those env vars. PostHog has no first-class CLI \u2014 use the HTTP API (`POSTHOG_PERSONAL_API_KEY`). Tell any worktree agent (Claude / Cursor / Codex / OpenCode) to write CLI output to `.context/cli/` (not `.context/attachments/`) and read a slice \u2014 never stream raw `--json` / `--expand` into a tool result (that crashes the turn). They can `stop_job` if a detached fetch hangs. If a CLI is missing, the user can Install CLI on that row (not auto-installed on Connect). Do not add vendor MCPs or ask the user to paste tokens again. Git (`gh`) stays Settings \u2192 Git; issue tracking stays Settings \u2192 Issues; Slack stays Settings \u2192 Remote (Sideboard MCP).",
|
|
@@ -359,7 +360,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
|
|
|
359
360
|
"Inspect / review / PRs:",
|
|
360
361
|
"- get_diff \u2014 compact diff summary",
|
|
361
362
|
"- get_pr_checks \u2014 snapshot of a worktree thread's PR checks (null = no PR). Use this to inspect status. If the user gave a goal, the worktree agent watches with `gh pr checks --watch` \u2014 do not poll for the human.",
|
|
362
|
-
'- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else .context/review.md copied from .sideboard/review.md / stock; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id. The review stays in that chat until the user confirms posting it \u2014 do not tell the child to comment or update the PR.',
|
|
363
|
+
'- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else .context/review.md copied from .sideboard/review.md / stock; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id. The review stays in that chat until the user confirms posting it \u2014 do not tell the child to comment or update the PR or ticket.',
|
|
363
364
|
"- ask_git \u2014 commit & push, open a draft PR, mark ready for review, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If ask_git / get_thread lastError says the GraphQL/PR body is too long, the branch is already pushed \u2014 send_to_thread so the worktree agent runs `gh pr create --body-file` with a short description. Do not invent SSH or auth failures from that error. If the user gave a goal (Greptile 5/5, CI green), send_to_thread that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
|
|
364
365
|
'- Merge (`ask_git` action=merge / send_to_thread "Merge PR.") only when the user explicitly asked to merge that PR. Do not merge because the work looks done, CI is green, or a typical flow includes it.',
|
|
365
366
|
'- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Ready for review.", "Merge the remote branch (main) into your branch and resolve conflicts. Then, commit and push your changes.", "Merge PR." (draft PRs: `gh pr create --draft -R <origin-owner/name>` using the workspace `github:` slug \u2014 never upstream). Never run git/gh from this orchestration cwd, and never merge the PR yourself.',
|
|
@@ -491,7 +492,7 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
491
492
|
"Typical flow (Home board): list_board \u2192 create_thread (sourceType=ticket|pr|branch) \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft \u2192 wait_for_turn. Merge only if the user explicitly asked (`ask_git` merge).",
|
|
492
493
|
"Typical flow (branch / explicit source): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
|
|
493
494
|
"Typical flow (find work): list_workspaces \u2192 pick repo(s) matching account / project context \u2192 Sideboard list_issues / linear_* (tickets) or list_prs(queue=review) (reviews) \u2192 show the options. Never wait on Claude Linear MCP. Only create_thread + send_to_thread when they asked to start (e.g. \u201Cfind me work and start it\u201D) \u2014 then wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
|
|
494
|
-
'Typical flow (review inbox): list_workspaces \u2192 list_prs(queue=review, limit=N) \u2192 show those PRs (ticket ids in the title when present). create_thread sourceType=pr only when they asked to start / do the work. Do not list_issues for "tickets to review". The child writes the review in chat and ask_user (Post this review / Keep it in chat) \u2014 do not github_comment / linear_comment / update the PR or ticket, and do not tell the child to post, until the user confirms. The PR author sees those writes immediately.',
|
|
495
|
+
'Typical flow (review inbox): list_workspaces \u2192 list_prs(queue=review, limit=N) \u2192 show those PRs (ticket ids in the title when present). create_thread sourceType=pr only when they asked to start / do the work. Do not list_issues for "tickets to review". The child writes the review in chat and ask_user (Post this review / Keep it in chat) \u2014 do not github_comment / linear_comment / update the PR or ticket, and do not tell the child to post, until the user confirms. They should work through the feedback in chat first. The PR or ticket author sees those writes immediately.',
|
|
495
496
|
"Typical flow (new app): Bash create/clone under repos dir \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
|
|
496
497
|
"Always ask worktree agents to commit, push, and open draft PRs (`ask_git` / `send_to_thread`). If the user gave a goal (Greptile 5/5, CI green), pass that goal through so they watch-fix-push until it lands \u2014 do not start that loop on a plain push, and do not tell the human to poll. Tell them to merge only when the user explicitly asked. The worktree agent runs git/gh; never merge from this orchestration cwd."
|
|
497
498
|
].join("\n");
|
|
@@ -374,8 +374,9 @@ var COORDINATOR_TOOL_PLAYBOOK = [
|
|
|
374
374
|
"- list_board \u2014 Home Kanban of worktrees (New / Draft / Review / Merged; one card per checkout). 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, column, limit.",
|
|
375
375
|
'- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces. Review is PRs (the surface for assigned ticket work), not the tickets: "Get me N tickets to review" \u2192 list_prs(queue=review, limit=N) then create_thread sourceType=pr. That is open non-draft PRs labeled eng-review with no individual user reviewer yet. A team request (engineering-team) is not a claim \u2014 the viewer is on that team and can pick it up; claimed means an individual account is the reviewer. Bots ignored. Use Settings \u2192 Agents / Projects context (roles, teams, labels \u2014 freeform text; project adds to account) to prefer the right queues. queue=mine is review-requested:@me; queue=approved|changes uses those labels. Also: state, label, reviewer=me|unassigned|login, query, limit default 40 max 250; raise limit or tighten when truncated. list_issues (query, assignee=me|unassigned|all|user, limit default 40 max 250) lists Linear, AbleTime, or GitHub tickets \u2014 do not use it for that review-inbox ask. When they ask for tickets to work on, follow their context (assignee=me or unassigned as it says).',
|
|
376
376
|
"- Find work: when they ask to find work, pick up tickets, or list reviews, use Settings \u2192 Agents (account) plus Settings \u2192 Projects (per-repo) context. Tickets \u2192 Sideboard list_issues / linear_* (Account Linear). Reviews \u2192 list_prs(queue=review). Do not call Claude Linear MCP or any other vendor Linear MCP \u2014 those HTTP connectors hang or flap on the first turn. If a vendor MCP is down or reconnecting, ignore it and keep going with Sideboard tools. Show the options \u2014 do not create_thread or start unless they also asked to start (e.g. \u201Cfind me work and start it\u201D). Do not start this unprompted. To change that context, show the proposed text, ask_user (Save this context / Do not save), wait, then update_viewer_context with confirmed=true. Never write it without confirmation.",
|
|
377
|
-
"-
|
|
378
|
-
"-
|
|
377
|
+
"- Ticket updates: list_issues / linear_search_issues / github_search_issues with updatedSince (yesterday, 2d, or ISO). One call returns new assignments, ticket edits, and new comments \u2014 do not get_issue every ticket just to check for comments. kind=created vs updated distinguishes new tickets from existing ones.",
|
|
378
|
+
"- linear_* (when Linear is connected) \u2014 list_teams for team key/states; get/create/update/comment with ENG-123. Worktree agents have the same Account tools \u2014 prefer they comment, update status, and create spin-offs (parent=) on their own ticket when they were asked to do the work. When reviewing a PR or ticket, do not comment or update until the user confirms (ask_user: Post this review / Keep it in chat) \u2014 they should work through the feedback in chat first. Scope errors: reconnect Linear in Account settings. Prefer these over any Linear MCP the CLI may still list.",
|
|
379
|
+
"- github_* \u2014 get/comment/update/create GitHub issues via Account `gh` (#123). Worktree agents have these too. Prefer over any vendor GitHub MCP. Pass parent= for spin-offs. When reviewing a PR or ticket, do not comment, submit `gh pr review`, or update the PR/ticket until the user confirms.",
|
|
379
380
|
"- abletime_* (when AbleTime is connected) \u2014 orientation first; get/comment/update/create (parent= for spin-offs); ensure_task when work has no ticket (or create_thread from the default branch auto-creates one). Worktree agents have the same Account tools. Same review-write gate as Linear/GitHub.",
|
|
380
381
|
"- list_teams / slack_list_channels / slack_list_users / slack_search / slack_read / slack_post / slack_replies \u2014 Slack workspaces from Settings \u2192 Remote; pass team_id from list_teams",
|
|
381
382
|
"- Optional connectors (Vercel, Supabase, PostHog, Sentry) in Settings \u2192 Connectors inject tokens into worktree agent env when connected. Prefer official CLIs (`vercel`, `supabase`, `sentry-cli`) with those env vars. PostHog has no first-class CLI \u2014 use the HTTP API (`POSTHOG_PERSONAL_API_KEY`). Tell any worktree agent (Claude / Cursor / Codex / OpenCode) to write CLI output to `.context/cli/` (not `.context/attachments/`) and read a slice \u2014 never stream raw `--json` / `--expand` into a tool result (that crashes the turn). They can `stop_job` if a detached fetch hangs. If a CLI is missing, the user can Install CLI on that row (not auto-installed on Connect). Do not add vendor MCPs or ask the user to paste tokens again. Git (`gh`) stays Settings \u2192 Git; issue tracking stays Settings \u2192 Issues; Slack stays Settings \u2192 Remote (Sideboard MCP).",
|
|
@@ -404,7 +405,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
|
|
|
404
405
|
"Inspect / review / PRs:",
|
|
405
406
|
"- get_diff \u2014 compact diff summary",
|
|
406
407
|
"- get_pr_checks \u2014 snapshot of a worktree thread's PR checks (null = no PR). Use this to inspect status. If the user gave a goal, the worktree agent watches with `gh pr checks --watch` \u2014 do not poll for the human.",
|
|
407
|
-
'- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else .context/review.md copied from .sideboard/review.md / stock; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id. The review stays in that chat until the user confirms posting it \u2014 do not tell the child to comment or update the PR.',
|
|
408
|
+
'- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else .context/review.md copied from .sideboard/review.md / stock; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id. The review stays in that chat until the user confirms posting it \u2014 do not tell the child to comment or update the PR or ticket.',
|
|
408
409
|
"- ask_git \u2014 commit & push, open a draft PR, mark ready for review, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If ask_git / get_thread lastError says the GraphQL/PR body is too long, the branch is already pushed \u2014 send_to_thread so the worktree agent runs `gh pr create --body-file` with a short description. Do not invent SSH or auth failures from that error. If the user gave a goal (Greptile 5/5, CI green), send_to_thread that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
|
|
409
410
|
'- Merge (`ask_git` action=merge / send_to_thread "Merge PR.") only when the user explicitly asked to merge that PR. Do not merge because the work looks done, CI is green, or a typical flow includes it.',
|
|
410
411
|
'- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Ready for review.", "Merge the remote branch (main) into your branch and resolve conflicts. Then, commit and push your changes.", "Merge PR." (draft PRs: `gh pr create --draft -R <origin-owner/name>` using the workspace `github:` slug \u2014 never upstream). Never run git/gh from this orchestration cwd, and never merge the PR yourself.',
|
|
@@ -536,7 +537,7 @@ function ensureGlobalCoordinatorCwd(opts) {
|
|
|
536
537
|
"Typical flow (Home board): list_board \u2192 create_thread (sourceType=ticket|pr|branch) \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft \u2192 wait_for_turn. Merge only if the user explicitly asked (`ask_git` merge).",
|
|
537
538
|
"Typical flow (branch / explicit source): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
|
|
538
539
|
"Typical flow (find work): list_workspaces \u2192 pick repo(s) matching account / project context \u2192 Sideboard list_issues / linear_* (tickets) or list_prs(queue=review) (reviews) \u2192 show the options. Never wait on Claude Linear MCP. Only create_thread + send_to_thread when they asked to start (e.g. \u201Cfind me work and start it\u201D) \u2014 then wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
|
|
539
|
-
'Typical flow (review inbox): list_workspaces \u2192 list_prs(queue=review, limit=N) \u2192 show those PRs (ticket ids in the title when present). create_thread sourceType=pr only when they asked to start / do the work. Do not list_issues for "tickets to review". The child writes the review in chat and ask_user (Post this review / Keep it in chat) \u2014 do not github_comment / linear_comment / update the PR or ticket, and do not tell the child to post, until the user confirms. The PR author sees those writes immediately.',
|
|
540
|
+
'Typical flow (review inbox): list_workspaces \u2192 list_prs(queue=review, limit=N) \u2192 show those PRs (ticket ids in the title when present). create_thread sourceType=pr only when they asked to start / do the work. Do not list_issues for "tickets to review". The child writes the review in chat and ask_user (Post this review / Keep it in chat) \u2014 do not github_comment / linear_comment / update the PR or ticket, and do not tell the child to post, until the user confirms. They should work through the feedback in chat first. The PR or ticket author sees those writes immediately.',
|
|
540
541
|
"Typical flow (new app): Bash create/clone under repos dir \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
|
|
541
542
|
"Always ask worktree agents to commit, push, and open draft PRs (`ask_git` / `send_to_thread`). If the user gave a goal (Greptile 5/5, CI green), pass that goal through so they watch-fix-push until it lands \u2014 do not start that loop on a plain push, and do not tell the human to poll. Tell them to merge only when the user explicitly asked. The worktree agent runs git/gh; never merge from this orchestration cwd."
|
|
542
543
|
].join("\n");
|
|
@@ -281,7 +281,16 @@ function mapAbleTimeTask(raw, host) {
|
|
|
281
281
|
categoryId: firstString(nested, ["category_id", "categoryId"]) || firstString(asRecord2(nested.category), ["id"]) || void 0,
|
|
282
282
|
assignee: assigneeOf(nested),
|
|
283
283
|
labels: labelsOf(nested),
|
|
284
|
-
comments: commentsOf(nested)
|
|
284
|
+
comments: commentsOf(nested),
|
|
285
|
+
createdAt: firstString(nested, ["created_at", "createdAt", "created"]) || void 0,
|
|
286
|
+
updatedAt: firstString(nested, [
|
|
287
|
+
"updated_at",
|
|
288
|
+
"updatedAt",
|
|
289
|
+
"modified_at",
|
|
290
|
+
"modifiedAt",
|
|
291
|
+
"last_activity_at",
|
|
292
|
+
"lastActivityAt"
|
|
293
|
+
]) || void 0
|
|
285
294
|
};
|
|
286
295
|
}
|
|
287
296
|
function toAbleTimeIssueInfo(task) {
|
|
@@ -293,7 +302,9 @@ function toAbleTimeIssueInfo(task) {
|
|
|
293
302
|
labels: task.labels,
|
|
294
303
|
provider: "abletime",
|
|
295
304
|
assignee: task.assignee?.name,
|
|
296
|
-
assignees: task.assignee?.name ? [task.assignee.name] : void 0
|
|
305
|
+
assignees: task.assignee?.name ? [task.assignee.name] : void 0,
|
|
306
|
+
...task.createdAt ? { createdAt: task.createdAt } : {},
|
|
307
|
+
...task.updatedAt ? { updatedAt: task.updatedAt } : {}
|
|
297
308
|
};
|
|
298
309
|
}
|
|
299
310
|
function issueAttachmentForAbleTimeTask(task) {
|
|
@@ -279,7 +279,16 @@ function mapAbleTimeTask(raw, host) {
|
|
|
279
279
|
categoryId: firstString(nested, ["category_id", "categoryId"]) || firstString(asRecord2(nested.category), ["id"]) || void 0,
|
|
280
280
|
assignee: assigneeOf(nested),
|
|
281
281
|
labels: labelsOf(nested),
|
|
282
|
-
comments: commentsOf(nested)
|
|
282
|
+
comments: commentsOf(nested),
|
|
283
|
+
createdAt: firstString(nested, ["created_at", "createdAt", "created"]) || void 0,
|
|
284
|
+
updatedAt: firstString(nested, [
|
|
285
|
+
"updated_at",
|
|
286
|
+
"updatedAt",
|
|
287
|
+
"modified_at",
|
|
288
|
+
"modifiedAt",
|
|
289
|
+
"last_activity_at",
|
|
290
|
+
"lastActivityAt"
|
|
291
|
+
]) || void 0
|
|
283
292
|
};
|
|
284
293
|
}
|
|
285
294
|
function toAbleTimeIssueInfo(task) {
|
|
@@ -291,7 +300,9 @@ function toAbleTimeIssueInfo(task) {
|
|
|
291
300
|
labels: task.labels,
|
|
292
301
|
provider: "abletime",
|
|
293
302
|
assignee: task.assignee?.name,
|
|
294
|
-
assignees: task.assignee?.name ? [task.assignee.name] : void 0
|
|
303
|
+
assignees: task.assignee?.name ? [task.assignee.name] : void 0,
|
|
304
|
+
...task.createdAt ? { createdAt: task.createdAt } : {},
|
|
305
|
+
...task.updatedAt ? { updatedAt: task.updatedAt } : {}
|
|
295
306
|
};
|
|
296
307
|
}
|
|
297
308
|
function issueAttachmentForAbleTimeTask(task) {
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from "./chunk-Y4MIXGPA.js";
|
|
12
12
|
import {
|
|
13
13
|
isOrchestratorThread
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-JA7TKTQ4.js";
|
|
15
15
|
import {
|
|
16
16
|
codexUnattendedGitConfigArgs,
|
|
17
17
|
mergeAgentGitAuthEnv,
|
|
@@ -2342,7 +2342,7 @@ var claudeAdapter = {
|
|
|
2342
2342
|
);
|
|
2343
2343
|
}
|
|
2344
2344
|
const mode = permissionMode(thread);
|
|
2345
|
-
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-
|
|
2345
|
+
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-RNPHVMFM.js");
|
|
2346
2346
|
const isOrchestrator = isOrchestratorThread2(thread);
|
|
2347
2347
|
const injectedServers = await buildInjectedMcpServers({
|
|
2348
2348
|
includeSideboard: true,
|