@sideboard-ai/core 0.1.42 → 0.1.44

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.
@@ -152,13 +152,19 @@ function emit(event) {
152
152
  process.stdout.write(`${JSON.stringify(event)}
153
153
  `);
154
154
  }
155
- function modelSelection(model, fast) {
155
+ function modelSelection(model, opts) {
156
156
  const raw = model && model.trim() || "";
157
157
  const id = !raw || raw.toLowerCase() === "auto" || raw.toLowerCase() === "default" ? "default" : raw;
158
- if (fast) {
159
- return { id, params: [{ id: "fast", value: "true" }] };
158
+ const params = [];
159
+ const effort = (opts.effort ?? "").trim().toLowerCase();
160
+ const normalized = effort === "normal" ? "medium" : effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" || effort === "max" ? effort : "";
161
+ if (normalized) {
162
+ params.push({ id: "effort", value: normalized });
160
163
  }
161
- return { id };
164
+ if (opts.fast) {
165
+ params.push({ id: "fast", value: "true" });
166
+ }
167
+ return params.length > 0 ? { id, params } : { id };
162
168
  }
163
169
  function localAgentStore() {
164
170
  const root = (0, import_node_path4.join)(appDataDir(), "cursor-sdk-store");
@@ -193,7 +199,10 @@ async function main() {
193
199
  return 1;
194
200
  }
195
201
  const apiKey = (req.apiKey || process.env.CURSOR_API_KEY || "").trim() || void 0;
196
- const model = modelSelection(req.model, Boolean(req.fast));
202
+ const model = modelSelection(req.model, {
203
+ effort: req.effort,
204
+ fast: Boolean(req.fast)
205
+ });
197
206
  const mode = req.planMode ? "plan" : "agent";
198
207
  const store = localAgentStore();
199
208
  const local = { cwd: req.cwd, store };
@@ -16,13 +16,19 @@ function emit(event) {
16
16
  process.stdout.write(`${JSON.stringify(event)}
17
17
  `);
18
18
  }
19
- function modelSelection(model, fast) {
19
+ function modelSelection(model, opts) {
20
20
  const raw = model && model.trim() || "";
21
21
  const id = !raw || raw.toLowerCase() === "auto" || raw.toLowerCase() === "default" ? "default" : raw;
22
- if (fast) {
23
- return { id, params: [{ id: "fast", value: "true" }] };
22
+ const params = [];
23
+ const effort = (opts.effort ?? "").trim().toLowerCase();
24
+ const normalized = effort === "normal" ? "medium" : effort === "low" || effort === "medium" || effort === "high" || effort === "xhigh" || effort === "max" ? effort : "";
25
+ if (normalized) {
26
+ params.push({ id: "effort", value: normalized });
24
27
  }
25
- return { id };
28
+ if (opts.fast) {
29
+ params.push({ id: "fast", value: "true" });
30
+ }
31
+ return params.length > 0 ? { id, params } : { id };
26
32
  }
27
33
  function localAgentStore() {
28
34
  const root = join(appDataDir(), "cursor-sdk-store");
@@ -57,7 +63,10 @@ async function main() {
57
63
  return 1;
58
64
  }
59
65
  const apiKey = (req.apiKey || process.env.CURSOR_API_KEY || "").trim() || void 0;
60
- const model = modelSelection(req.model, Boolean(req.fast));
66
+ const model = modelSelection(req.model, {
67
+ effort: req.effort,
68
+ fast: Boolean(req.fast)
69
+ });
61
70
  const mode = req.planMode ? "plan" : "agent";
62
71
  const store = localAgentStore();
63
72
  const local = { cwd: req.cwd, store };
@@ -21,13 +21,14 @@ import {
21
21
  opencodeAdapter,
22
22
  permissionMode,
23
23
  resolveCursorModelId
24
- } from "./chunk-SX2R2PCE.js";
24
+ } from "./chunk-XX26NCB6.js";
25
25
  import "./chunk-ILQK4P5R.js";
26
26
  import {
27
27
  cursorSdkMessageToEvents,
28
28
  parseCursorRunnerLine
29
29
  } from "./chunk-PU27NUO4.js";
30
- import "./chunk-YZ23S32T.js";
30
+ import "./chunk-FSIK442J.js";
31
+ import "./chunk-77WWLBCI.js";
31
32
  import "./chunk-M37RITA6.js";
32
33
  import {
33
34
  ensureAgentPath
@@ -14,6 +14,8 @@ import {
14
14
  claudeUserSettingsPath,
15
15
  deleteBranchOnPurgeEnabled,
16
16
  getDefaultAgent,
17
+ getDefaultEffort,
18
+ getDefaultFast,
17
19
  getDefaultModel,
18
20
  getIssueSource,
19
21
  getLinearApiKey,
@@ -31,7 +33,8 @@ import {
31
33
  updateClaudeSettings,
32
34
  updateDefaultsSettings,
33
35
  updateIntegrationsSettings
34
- } from "./chunk-YZ23S32T.js";
36
+ } from "./chunk-FSIK442J.js";
37
+ import "./chunk-77WWLBCI.js";
35
38
  import "./chunk-M37RITA6.js";
36
39
  export {
37
40
  HARNESS_ENV_KEYS,
@@ -49,6 +52,8 @@ export {
49
52
  claudeUserSettingsPath,
50
53
  deleteBranchOnPurgeEnabled,
51
54
  getDefaultAgent,
55
+ getDefaultEffort,
56
+ getDefaultFast,
52
57
  getDefaultModel,
53
58
  getIssueSource,
54
59
  getLinearApiKey,
@@ -0,0 +1,50 @@
1
+ // src/types/thinking-effort.ts
2
+ var THINKING_EFFORTS = [
3
+ "low",
4
+ "medium",
5
+ "high",
6
+ "xhigh",
7
+ "max"
8
+ ];
9
+ var EFFORT_SET = new Set(THINKING_EFFORTS);
10
+ function normalizeThinkingEffort(value) {
11
+ if (typeof value !== "string") return null;
12
+ const v = value.trim().toLowerCase();
13
+ if (v === "normal") return "medium";
14
+ if (EFFORT_SET.has(v)) return v;
15
+ return null;
16
+ }
17
+ function isThinkingEffort(value) {
18
+ return typeof value === "string" && EFFORT_SET.has(value.trim().toLowerCase());
19
+ }
20
+ function nextThinkingEffort(current) {
21
+ const i = THINKING_EFFORTS.indexOf(current);
22
+ return THINKING_EFFORTS[(i + 1) % THINKING_EFFORTS.length];
23
+ }
24
+ function thinkingEffortBars(effort) {
25
+ const i = THINKING_EFFORTS.indexOf(effort);
26
+ return i >= 0 ? i + 1 : 3;
27
+ }
28
+ function thinkingEffortLabel(effort) {
29
+ switch (effort) {
30
+ case "low":
31
+ return "Low";
32
+ case "medium":
33
+ return "Medium";
34
+ case "high":
35
+ return "High";
36
+ case "xhigh":
37
+ return "Extra High";
38
+ case "max":
39
+ return "Max";
40
+ }
41
+ }
42
+
43
+ export {
44
+ THINKING_EFFORTS,
45
+ normalizeThinkingEffort,
46
+ isThinkingEffort,
47
+ nextThinkingEffort,
48
+ thinkingEffortBars,
49
+ thinkingEffortLabel
50
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  listThreads
3
- } from "./chunk-5UIKSPDD.js";
3
+ } from "./chunk-ENSD62HW.js";
4
4
  import {
5
5
  worktreesRoot
6
6
  } from "./chunk-M37RITA6.js";
@@ -1,3 +1,6 @@
1
+ import {
2
+ normalizeThinkingEffort
3
+ } from "./chunk-77WWLBCI.js";
1
4
  import {
2
5
  threadFilePath,
3
6
  threadLockPath,
@@ -18,10 +21,17 @@ import lockfile from "proper-lockfile";
18
21
  function nowIso() {
19
22
  return (/* @__PURE__ */ new Date()).toISOString();
20
23
  }
24
+ function resolveThreadEffort(raw) {
25
+ const fromField = normalizeThinkingEffort(raw.effort);
26
+ if (fromField) return fromField;
27
+ if (raw.fast) return "low";
28
+ return "high";
29
+ }
21
30
  function normalizeThread(raw) {
22
31
  return {
23
32
  ...raw,
24
33
  model: raw.model ?? null,
34
+ effort: resolveThreadEffort(raw),
25
35
  fast: Boolean(raw.fast),
26
36
  planMode: Boolean(raw.planMode),
27
37
  autonomy: raw.autonomy ?? "default",
@@ -40,6 +50,7 @@ function createEmptyThread(partial) {
40
50
  sessionId: partial.sessionId ?? null,
41
51
  autonomy: partial.autonomy ?? "default",
42
52
  model: partial.model ?? null,
53
+ effort: partial.effort ?? "high",
43
54
  fast: partial.fast ?? false,
44
55
  planMode: partial.planMode ?? false,
45
56
  sourceIsFork: partial.sourceIsFork ?? false,
@@ -142,6 +153,7 @@ function findThreadByRef(ref) {
142
153
  }
143
154
 
144
155
  export {
156
+ resolveThreadEffort,
145
157
  normalizeThread,
146
158
  createEmptyThread,
147
159
  withThreadLock,
@@ -1,3 +1,6 @@
1
+ import {
2
+ normalizeThinkingEffort
3
+ } from "./chunk-77WWLBCI.js";
1
4
  import {
2
5
  appDataDir
3
6
  } from "./chunk-M37RITA6.js";
@@ -82,6 +85,12 @@ function normalizeDefaults(raw) {
82
85
  const model = source.model.trim();
83
86
  if (model) out.model = model;
84
87
  }
88
+ if (normalizeThinkingEffort(source.effort)) {
89
+ out.effort = normalizeThinkingEffort(source.effort);
90
+ }
91
+ if (typeof source.fast === "boolean") {
92
+ out.fast = source.fast;
93
+ }
85
94
  return out;
86
95
  }
87
96
  function normalizeAdvanced(raw) {
@@ -268,6 +277,21 @@ function updateDefaultsSettings(patch) {
268
277
  defaults.model = patch.model.trim();
269
278
  }
270
279
  }
280
+ if ("effort" in patch) {
281
+ if (patch.effort == null) {
282
+ delete defaults.effort;
283
+ } else {
284
+ const effort = normalizeThinkingEffort(patch.effort);
285
+ if (effort) defaults.effort = effort;
286
+ }
287
+ }
288
+ if ("fast" in patch) {
289
+ if (patch.fast == null) {
290
+ delete defaults.fast;
291
+ } else {
292
+ defaults.fast = Boolean(patch.fast);
293
+ }
294
+ }
271
295
  return saveAppSettings({ ...current, defaults });
272
296
  }
273
297
  function getDefaultAgent(settings = loadAppSettings()) {
@@ -277,10 +301,18 @@ function getDefaultModel(settings = loadAppSettings()) {
277
301
  const model = settings.defaults.model?.trim();
278
302
  return model || null;
279
303
  }
304
+ function getDefaultEffort(settings = loadAppSettings()) {
305
+ return normalizeThinkingEffort(settings.defaults.effort) ?? "high";
306
+ }
307
+ function getDefaultFast(settings = loadAppSettings()) {
308
+ return settings.defaults.fast === true;
309
+ }
280
310
  function resolveThreadDefaults(settings = loadAppSettings()) {
281
311
  return {
282
312
  agent: getDefaultAgent(settings),
283
- model: getDefaultModel(settings)
313
+ model: getDefaultModel(settings),
314
+ effort: getDefaultEffort(settings),
315
+ fast: getDefaultFast(settings)
284
316
  };
285
317
  }
286
318
  function isLinearConnected(settings = loadAppSettings()) {
@@ -411,6 +443,8 @@ export {
411
443
  updateDefaultsSettings,
412
444
  getDefaultAgent,
413
445
  getDefaultModel,
446
+ getDefaultEffort,
447
+ getDefaultFast,
414
448
  resolveThreadDefaults,
415
449
  isLinearConnected,
416
450
  getIssueSource,
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  ensureGlobalCoordinatorCwd
3
- } from "./chunk-UPMGXM4X.js";
3
+ } from "./chunk-JM2TVGNW.js";
4
4
  import {
5
5
  allocateTeamName,
6
6
  takenSlugsFromThread,
7
7
  teamSlugFromName
8
- } from "./chunk-VA2U5EQH.js";
8
+ } from "./chunk-7PCTK4WO.js";
9
9
  import {
10
10
  createEmptyThread,
11
11
  listThreads,
12
12
  updateThread,
13
13
  writeThread
14
- } from "./chunk-5UIKSPDD.js";
14
+ } from "./chunk-ENSD62HW.js";
15
15
  import {
16
16
  globalAgentCwd
17
17
  } from "./chunk-M37RITA6.js";
@@ -122,6 +122,7 @@ function createGlobalChat(opts) {
122
122
  agent: opts.agent,
123
123
  autonomy: opts.autonomy ?? "default",
124
124
  model: opts.model ?? null,
125
+ effort: opts.effort ?? "high",
125
126
  fast: Boolean(opts.fast),
126
127
  planMode: Boolean(opts.planMode),
127
128
  attachments: opts.attachments ?? [],
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveGithubRepoSlug
3
- } from "./chunk-VA2U5EQH.js";
3
+ } from "./chunk-7PCTK4WO.js";
4
4
  import {
5
5
  globalAgentCwd,
6
6
  sideboardReposDir
@@ -54,8 +54,9 @@ var COORDINATOR_TOOL_PLAYBOOK = [
54
54
  "Setup / run:",
55
55
  "- run_setup \u2014 re-run worktree setup",
56
56
  "- list_run_scripts / run_dev_script / stop_dev_script \u2014 start/stop named run scripts",
57
- "Inspect / PRs:",
57
+ "Inspect / review / PRs:",
58
58
  "- get_diff \u2014 compact diff summary",
59
+ "- request_review \u2014 open a Review chat tab on a worktree thread (merge-readiness recommendation); then wait_for_turn / get_turn_result on the returned id",
59
60
  "- Ask the worktree agent via send_to_thread to open a draft PR with `gh pr create --draft -R <origin-owner/name>` (workspace `github:` slug / that worktree's origin \u2014 never upstream). Do not open PRs from the orchestrator yourself.",
60
61
  "Human-only (do not attempt): merge, ready-for-review land, purge_thread.",
61
62
  "Thread links in replies: when mentioning a chat/thread for the user, include a markdown link `[Title](sideboard://thread/<id>)` using the full id (or the link field from create_thread / list_threads). Sideboard renders these as clickable opens.",
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  isGlobalRepoPath
3
- } from "./chunk-6TZSJMXF.js";
3
+ } from "./chunk-I3PKMLFW.js";
4
4
  import {
5
5
  ensureGhPreferOrigin,
6
6
  resolveRepoRoot
7
- } from "./chunk-VA2U5EQH.js";
7
+ } from "./chunk-7PCTK4WO.js";
8
8
  import {
9
9
  appDataDir
10
10
  } from "./chunk-M37RITA6.js";
@@ -3,7 +3,7 @@ import {
3
3
  ensureWorkspace,
4
4
  removeWorkspace,
5
5
  syncWorkspacesFromThreads
6
- } from "./chunk-44LYDJFB.js";
6
+ } from "./chunk-TXFJEXFB.js";
7
7
  import {
8
8
  GLOBAL_WORKSPACE_ID,
9
9
  createGlobalChat,
@@ -13,19 +13,19 @@ import {
13
13
  isGlobalThread,
14
14
  isOrchestratorThread,
15
15
  orchestratorSessionPoisonedByBuiltins
16
- } from "./chunk-6TZSJMXF.js";
16
+ } from "./chunk-I3PKMLFW.js";
17
17
  import {
18
18
  coordinatorSystemPrompt,
19
19
  coordinatorTurnReminder,
20
20
  enrichWorkspacesWithGithub,
21
21
  ensureGlobalCoordinatorCwd
22
- } from "./chunk-UPMGXM4X.js";
22
+ } from "./chunk-JM2TVGNW.js";
23
23
  import {
24
24
  PLAN_MODE_INSTRUCTION,
25
25
  allAdapters,
26
26
  getAdapter,
27
27
  parseBrightsyCliLine
28
- } from "./chunk-SX2R2PCE.js";
28
+ } from "./chunk-XX26NCB6.js";
29
29
  import {
30
30
  fallbackTurnFailDetail,
31
31
  formatTurnExitError,
@@ -40,7 +40,7 @@ import {
40
40
  loadAppSettings,
41
41
  resolveEffectiveIssueSource,
42
42
  updateAdvancedSettings
43
- } from "./chunk-YZ23S32T.js";
43
+ } from "./chunk-FSIK442J.js";
44
44
  import {
45
45
  allocateTeamName,
46
46
  allocateTeamSlug,
@@ -71,7 +71,7 @@ import {
71
71
  takenSlugsFromThread,
72
72
  threadDisplayLabel,
73
73
  worktreeNameFromPath
74
- } from "./chunk-VA2U5EQH.js";
74
+ } from "./chunk-7PCTK4WO.js";
75
75
  import {
76
76
  appendMessage,
77
77
  createEmptyThread,
@@ -83,7 +83,7 @@ import {
83
83
  updateThread,
84
84
  withThreadLock,
85
85
  writeThread
86
- } from "./chunk-5UIKSPDD.js";
86
+ } from "./chunk-ENSD62HW.js";
87
87
  import {
88
88
  loadRepoSettings,
89
89
  loadWorkspaceSettings,
@@ -459,9 +459,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
459
459
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
460
460
  );
461
461
  }
462
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-4GVWSCEX.js");
462
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-FU6UIPDY.js");
463
463
  if (isGlobalThread2(thread)) {
464
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-FAILHO4J.js");
464
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-I5YNS27B.js");
465
465
  ensureGlobalCoordinatorCwd2();
466
466
  }
467
467
  const adapter = getAdapter(thread.agent);
@@ -2610,6 +2610,7 @@ async function createThread(input, onSetupLine) {
2610
2610
  agent: input.agent,
2611
2611
  autonomy: input.autonomy ?? "default",
2612
2612
  model: input.model ?? null,
2613
+ effort: input.effort ?? "high",
2613
2614
  fast: Boolean(input.fast),
2614
2615
  planMode: Boolean(input.planMode),
2615
2616
  attachments: input.attachments ?? [],
@@ -2639,7 +2640,7 @@ async function createThread(input, onSetupLine) {
2639
2640
  return readThread(thread.id) ?? thread;
2640
2641
  }
2641
2642
  async function listLinearIssues(agent, repoPath) {
2642
- const { getAdapter: getAdapter2 } = await import("./agents-T6XHC5OV.js");
2643
+ const { getAdapter: getAdapter2 } = await import("./agents-PP3URTSF.js");
2643
2644
  await requireAgent(agent, { requireLinear: true });
2644
2645
  const adapter = getAdapter2(agent);
2645
2646
  if (!adapter.listLinearIssues) {
@@ -2720,7 +2721,8 @@ function createChatTab(input) {
2720
2721
  ...binding,
2721
2722
  agent: input.agent ?? from.agent,
2722
2723
  model: input.model !== void 0 ? input.model : input.agent && input.agent !== from.agent ? null : from.model,
2723
- fast: from.fast,
2724
+ effort: input.effort !== void 0 ? input.effort : from.effort,
2725
+ fast: input.fast !== void 0 ? Boolean(input.fast) : from.fast,
2724
2726
  planMode: from.planMode,
2725
2727
  autonomy: input.autonomy ?? from.autonomy,
2726
2728
  attachments: input.attachments ?? [],
@@ -2759,6 +2761,7 @@ async function forkThreadWorktree(input, onSetupLine) {
2759
2761
  agent: input.agent ?? from.agent,
2760
2762
  autonomy: from.autonomy,
2761
2763
  model: from.model,
2764
+ effort: from.effort,
2762
2765
  fast: from.fast,
2763
2766
  planMode: from.planMode,
2764
2767
  title: input.title?.trim() || void 0,
@@ -2859,7 +2862,7 @@ async function adoptThread(input) {
2859
2862
  messages: input.messages ?? []
2860
2863
  });
2861
2864
  writeThread(thread);
2862
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-Z7CSL4O6.js");
2865
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-RSEDTBGJ.js");
2863
2866
  await ensureWorkspace2(repoPath);
2864
2867
  return thread;
2865
2868
  }
@@ -3286,9 +3289,59 @@ async function cloneRepoIntoSideboard(opts) {
3286
3289
  return { repoPath, workspace };
3287
3290
  }
3288
3291
 
3292
+ // src/review/request-review.ts
3293
+ import { randomUUID as randomUUID3 } from "crypto";
3294
+ import { readFileSync as readFileSync8, existsSync as existsSync11 } from "fs";
3295
+ import { join as join10 } from "path";
3296
+ var REVIEW_REQUEST_PATH = ".sideboard/attachments/Review request.md";
3297
+ var REVIEW_REQUEST_NAME = "Review request.md";
3298
+ var REVIEW_REQUEST_PREFILL = `Please review the changes in this workspace and recommend whether they are ready to merge.
3299
+
3300
+ Start with a **Recommendation**: Approve, Approve with nits, Request changes, or Needs more information \u2014 and say why in 1\u20133 sentences. Then list blocking findings vs nits (findings may be empty).`;
3301
+ function buildReviewRequestAttachment(content) {
3302
+ return {
3303
+ id: randomUUID3(),
3304
+ name: REVIEW_REQUEST_NAME,
3305
+ kind: "file",
3306
+ path: REVIEW_REQUEST_PATH,
3307
+ content
3308
+ };
3309
+ }
3310
+ function readExistingReviewRequestFile(worktreePath) {
3311
+ const abs = join10(worktreePath, REVIEW_REQUEST_PATH);
3312
+ if (!existsSync11(abs)) return null;
3313
+ try {
3314
+ const content = readFileSync8(abs, "utf8");
3315
+ return content.trim() ? content : null;
3316
+ } catch {
3317
+ return null;
3318
+ }
3319
+ }
3320
+ async function requestReview(threadRef, send) {
3321
+ const from = findThreadByRef(threadRef);
3322
+ if (!from) throw new Error(`Thread not found: ${threadRef}`);
3323
+ if (isOrchestratorThread(from)) {
3324
+ throw new Error(
3325
+ "request_review targets a worktree agent thread (not the orchestrator). Pass a child/worktree thread ref."
3326
+ );
3327
+ }
3328
+ if (from.status === "archived") {
3329
+ throw new Error(`Thread is archived: ${from.id}`);
3330
+ }
3331
+ const existing = readExistingReviewRequestFile(from.worktreePath);
3332
+ const attachments = existing ? [buildReviewRequestAttachment(existing)] : [];
3333
+ const tab = createChatTab({
3334
+ fromThreadId: from.id,
3335
+ title: "Review",
3336
+ attachments
3337
+ });
3338
+ const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
3339
+ return { tab: started, from };
3340
+ }
3341
+
3289
3342
  // src/orchestrator/orchestrator.ts
3290
3343
  import { EventEmitter } from "events";
3291
- import { existsSync as existsSync11 } from "fs";
3344
+ import { existsSync as existsSync12 } from "fs";
3292
3345
 
3293
3346
  // src/threads/sync-branch.ts
3294
3347
  async function syncThreadBranchFromGit(threadId) {
@@ -3399,7 +3452,7 @@ var Orchestrator = class {
3399
3452
  }
3400
3453
  continue;
3401
3454
  }
3402
- if (!existsSync11(thread.worktreePath)) {
3455
+ if (!existsSync12(thread.worktreePath)) {
3403
3456
  setStatus(thread.id, "broken", "Worktree missing on disk");
3404
3457
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
3405
3458
  continue;
@@ -3418,7 +3471,7 @@ var Orchestrator = class {
3418
3471
  orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
3419
3472
  });
3420
3473
  }
3421
- const { autoCleanupOrphansEnabled } = await import("./app-settings-RSKDEMUI.js");
3474
+ const { autoCleanupOrphansEnabled } = await import("./app-settings-ZKVZHJPQ.js");
3422
3475
  if (autoCleanupOrphansEnabled() && shouldRunWorktreeCleanup() && orphans.length > 0) {
3423
3476
  await cleanupOrphanWorktrees({ repoPaths });
3424
3477
  }
@@ -3445,7 +3498,7 @@ var Orchestrator = class {
3445
3498
  });
3446
3499
  });
3447
3500
  this.emit({ type: "status_changed", threadId: thread.id, status: thread.status });
3448
- const { autoRunAfterSetupEnabled } = await import("./app-settings-RSKDEMUI.js");
3501
+ const { autoRunAfterSetupEnabled } = await import("./app-settings-ZKVZHJPQ.js");
3449
3502
  if (autoRunAfterSetupEnabled()) {
3450
3503
  try {
3451
3504
  await this.startDev(thread.id);
@@ -3691,7 +3744,7 @@ var Orchestrator = class {
3691
3744
  });
3692
3745
  const artifactDirective = isBrightsy ? null : formatArtifactDirective();
3693
3746
  const settings = loadWorkspaceSettings(fresh.worktreePath, fresh.repoPath);
3694
- const { autoRenameBranchEnabled } = await import("./app-settings-RSKDEMUI.js");
3747
+ const { autoRenameBranchEnabled } = await import("./app-settings-ZKVZHJPQ.js");
3695
3748
  const renameBranchDirective = !isBrightsy && !isOrchestration && autoRenameBranchEnabled() ? formatRenameBranchDirective(fresh, {
3696
3749
  customPrompt: settings?.prompts?.renameBranch
3697
3750
  }) : null;
@@ -4297,10 +4350,20 @@ var Orchestrator = class {
4297
4350
  setAutonomy(threadRef, autonomy) {
4298
4351
  return this.setThreadOptions(threadRef, { autonomy });
4299
4352
  }
4353
+ /**
4354
+ * Open a Review chat tab on a worktree thread (same as the desktop Review button)
4355
+ * and send the merge-readiness prefill.
4356
+ */
4357
+ async requestReview(threadRef) {
4358
+ const { tab } = await requestReview(threadRef, (ref, prompt) => this.send(ref, prompt));
4359
+ this.emit({ type: "status_changed", threadId: tab.id, status: tab.status });
4360
+ return tab;
4361
+ }
4300
4362
  setThreadOptions(threadRef, patch) {
4301
4363
  const thread = this.requireThread(threadRef);
4302
4364
  const next = {};
4303
4365
  if (patch.autonomy !== void 0) next.autonomy = patch.autonomy;
4366
+ if (patch.effort !== void 0) next.effort = patch.effort;
4304
4367
  if (patch.fast !== void 0) next.fast = patch.fast;
4305
4368
  if (patch.planMode !== void 0) next.planMode = patch.planMode;
4306
4369
  if (patch.model !== void 0) next.model = patch.model;
@@ -4402,7 +4465,7 @@ var Orchestrator = class {
4402
4465
  await runArchiveScript(thread.repoPath, thread.worktreePath);
4403
4466
  } catch {
4404
4467
  }
4405
- const { deleteBranchOnPurgeEnabled } = await import("./app-settings-RSKDEMUI.js");
4468
+ const { deleteBranchOnPurgeEnabled } = await import("./app-settings-ZKVZHJPQ.js");
4406
4469
  const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled();
4407
4470
  await removeWorktree(thread.repoPath, thread.worktreePath, {
4408
4471
  deleteBranch: deleteBranch ? thread.branchName : void 0
@@ -4420,8 +4483,8 @@ var Orchestrator = class {
4420
4483
  updateThread(thread.id, { worktreePath: globalAgentCwd() });
4421
4484
  return setStatus(thread.id, "idle");
4422
4485
  }
4423
- if (!existsSync11(thread.worktreePath)) {
4424
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-M3DTPYBW.js");
4486
+ if (!existsSync12(thread.worktreePath)) {
4487
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-N4PRV4V3.js");
4425
4488
  const { execa: execa6 } = await import("execa");
4426
4489
  const slug = thread.worktreePath.split("/").pop();
4427
4490
  const dest = thread.worktreePath;
@@ -4478,6 +4541,7 @@ async function startOrchestration(opts) {
4478
4541
  agent: opts.agent,
4479
4542
  autonomy: opts.autonomy,
4480
4543
  model: opts.model,
4544
+ effort: opts.effort,
4481
4545
  fast: opts.fast,
4482
4546
  planMode: opts.planMode,
4483
4547
  attachments: opts.attachments
@@ -4495,6 +4559,7 @@ async function startOrchestration(opts) {
4495
4559
  title,
4496
4560
  autonomy: opts.autonomy,
4497
4561
  model: opts.model,
4562
+ effort: opts.effort,
4498
4563
  fast: opts.fast,
4499
4564
  planMode: opts.planMode,
4500
4565
  attachments: opts.attachments
@@ -4504,7 +4569,7 @@ async function startOrchestration(opts) {
4504
4569
  sourceRef: "default",
4505
4570
  ...createOpts
4506
4571
  }).catch(async () => {
4507
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-M3DTPYBW.js");
4572
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-N4PRV4V3.js");
4508
4573
  const repo = await resolveRepoRoot2(repoPath);
4509
4574
  const def = await resolveDefaultBranch2(repo);
4510
4575
  return createThread({
@@ -4514,7 +4579,7 @@ async function startOrchestration(opts) {
4514
4579
  repoPath: repo
4515
4580
  });
4516
4581
  });
4517
- const { updateThread: upd } = await import("./thread-store-WPLT3IXM.js");
4582
+ const { updateThread: upd } = await import("./thread-store-EHROA3VZ.js");
4518
4583
  const updated = upd(thread.id, {
4519
4584
  sourceType: "orchestration",
4520
4585
  sourceRef: goal
@@ -4917,6 +4982,34 @@ async function startMcpServer() {
4917
4982
  };
4918
4983
  }
4919
4984
  );
4985
+ server.tool(
4986
+ "request_review",
4987
+ "Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, optionally attaches .sideboard/attachments/Review request.md when present, and asks for Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn / get_turn_result on the returned review tab id.",
4988
+ { ref: z.string().describe("Worktree thread id/ref to review") },
4989
+ async ({ ref }) => {
4990
+ try {
4991
+ const tab = await orch.requestReview(ref);
4992
+ const from = orch.getThread(ref);
4993
+ return {
4994
+ content: [
4995
+ {
4996
+ type: "text",
4997
+ text: JSON.stringify({
4998
+ id: tab.id,
4999
+ title: tab.title,
5000
+ status: tab.status,
5001
+ fromThreadId: from?.id ?? ref,
5002
+ link: `sideboard://thread/${tab.id}`
5003
+ })
5004
+ }
5005
+ ]
5006
+ };
5007
+ } catch (err) {
5008
+ const message = err instanceof Error ? err.message : String(err);
5009
+ return { content: [{ type: "text", text: message }], isError: true };
5010
+ }
5011
+ }
5012
+ );
4920
5013
  server.tool(
4921
5014
  "run_dev_script",
4922
5015
  "Start a .sideboard/.conductor run script for a thread (default script if name omitted); returns port",
@@ -5197,6 +5290,12 @@ export {
5197
5290
  worktreeCleanupSettings,
5198
5291
  applyThreadIntoMain,
5199
5292
  cloneRepoIntoSideboard,
5293
+ REVIEW_REQUEST_PATH,
5294
+ REVIEW_REQUEST_NAME,
5295
+ REVIEW_REQUEST_PREFILL,
5296
+ buildReviewRequestAttachment,
5297
+ readExistingReviewRequestFile,
5298
+ requestReview,
5200
5299
  isPidAlive,
5201
5300
  Orchestrator,
5202
5301
  getOrchestrator,