@sideboard-ai/core 0.1.295 → 0.1.297

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/agents/claude-runner.cjs +55 -0
  2. package/dist/agents/claude-runner.js +57 -1
  3. package/dist/agents/cursor-runner.js +2 -2
  4. package/dist/{agents-S55DBAVO.js → agents-DZTPUKVF.js} +4 -4
  5. package/dist/{agents-EFHYZUZT.js → agents-ICHYDSCD.js} +5 -5
  6. package/dist/{chunk-ABLHTRRG.js → chunk-2O3ICR77.js} +3 -3
  7. package/dist/{chunk-KCP6IVRI.js → chunk-67BWWLEB.js} +4 -4
  8. package/dist/{chunk-RWIYYFID.js → chunk-6GTABVNG.js} +4 -4
  9. package/dist/{chunk-YEIPPZ5W.js → chunk-BGEECLKH.js} +2 -2
  10. package/dist/{chunk-ER6BGGME.js → chunk-J54UPHXZ.js} +1 -1
  11. package/dist/{chunk-ZEP6JIRF.js → chunk-JWXJXEA3.js} +1 -1
  12. package/dist/{chunk-NYBFYFK7.js → chunk-QDA6NXRA.js} +1 -0
  13. package/dist/{chunk-YFKAC4LB.js → chunk-QT36F4TD.js} +54 -25
  14. package/dist/{chunk-YRXV3E7J.js → chunk-TVN4TDFB.js} +9 -0
  15. package/dist/{chunk-6SGYGYH7.js → chunk-VXNZG4J6.js} +1 -1
  16. package/dist/{chunk-XXT3C2EF.js → chunk-W2A63ZOK.js} +176 -39
  17. package/dist/{chunk-E7G7RY6T.js → chunk-WQREAX35.js} +2 -2
  18. package/dist/{chunk-QB5MDOHL.js → chunk-WZLV4WNS.js} +9 -0
  19. package/dist/{chunk-HWIIRVYE.js → chunk-ZXWRNA4G.js} +4 -4
  20. package/dist/{conductor-GURU5XD7.js → conductor-HJFDYIZD.js} +4 -4
  21. package/dist/{conductor-HT2UANDY.js → conductor-ZXDIA6OF.js} +4 -4
  22. package/dist/{coordinator-prompt-AROMFCP2.js → coordinator-prompt-ILHSVPOG.js} +3 -3
  23. package/dist/{coordinator-prompt-K6XHUG3N.js → coordinator-prompt-L3V2CMWX.js} +3 -3
  24. package/dist/{global-workspace-4WAU4PAL.js → global-workspace-47G453ZU.js} +3 -3
  25. package/dist/{global-workspace-PX4GUVLW.js → global-workspace-NMRUGGFF.js} +3 -3
  26. package/dist/index.cjs +1014 -698
  27. package/dist/index.d.cts +25 -4
  28. package/dist/index.d.ts +25 -4
  29. package/dist/index.js +282 -119
  30. package/dist/mcp/run-stdio.cjs +201 -118
  31. package/dist/mcp/run-stdio.js +46 -8
  32. package/dist/{orchestrator-VNSEXL62.js → orchestrator-MR7TCIPP.js} +6 -6
  33. package/dist/{orchestrator-VDYZSZWY.js → orchestrator-ZQU62CES.js} +7 -7
  34. package/dist/{thread-store-DPKESDFR.js → thread-store-H6D6MDUM.js} +1 -1
  35. package/dist/{thread-store-X6S2GIR5.js → thread-store-SADLLKRE.js} +1 -1
  36. package/dist/{workspaces-MFU3IGAP.js → workspaces-PGY4UWZ3.js} +3 -3
  37. package/dist/{workspaces-U7SSD27C.js → workspaces-WGZPRQJX.js} +3 -3
  38. package/dist/{worktree-TQKASYPZ.js → worktree-3MF5J5XZ.js} +2 -2
  39. package/dist/{worktree-2VSHRI72.js → worktree-JZXDAKQF.js} +2 -2
  40. package/package.json +1 -1
@@ -384,6 +384,53 @@ function createClaudePilotSdkServer(createSdkMcpServer, tool, opts) {
384
384
  return { server, exec };
385
385
  }
386
386
 
387
+ // src/agents/claude-permission.ts
388
+ function deny(message) {
389
+ return { behavior: "deny", message, decisionClassification: "user_reject" };
390
+ }
391
+ function fromAnswer(raw) {
392
+ if (!raw || typeof raw !== "object") return deny("Sideboard did not return a permission decision.");
393
+ const rec = raw;
394
+ if (rec.behavior === "allow") {
395
+ return {
396
+ behavior: "allow",
397
+ ...Array.isArray(rec.updatedPermissions) && rec.updatedPermissions.length > 0 ? { updatedPermissions: rec.updatedPermissions } : {},
398
+ decisionClassification: rec.decisionClassification === "user_permanent" ? "user_permanent" : "user_temporary"
399
+ };
400
+ }
401
+ const message = typeof rec.message === "string" && rec.message.trim() ? rec.message.trim() : "The user denied this action.";
402
+ return deny(message);
403
+ }
404
+ async function claudePermissionResult(input) {
405
+ if (input.permissionMode === "plan") {
406
+ return deny("Plan mode is on, so this action stays blocked.");
407
+ }
408
+ const threadId = input.threadId.trim();
409
+ if (!threadId) return deny("Sideboard could not tell which chat to ask.");
410
+ if (input.options.signal?.aborted) return deny("The turn was cancelled.");
411
+ const call = input.call ?? (input.rpc ? (method, params) => new AgentRpcClient(input.rpc).call(method, params) : null);
412
+ if (!call) return deny("Sideboard has no permission prompt for this turn.");
413
+ try {
414
+ const raw = await call("permission.ask", {
415
+ threadId,
416
+ toolName: input.toolName,
417
+ input: input.toolInput,
418
+ blockedPath: input.options.blockedPath,
419
+ title: input.options.title,
420
+ description: input.options.description,
421
+ displayName: input.options.displayName,
422
+ suggestions: input.options.suggestions,
423
+ suppressAlwaysAllow: input.options.suppressAlwaysAllowRule === true,
424
+ defaultToNo: input.options.defaultToNo === true
425
+ });
426
+ if (input.options.signal?.aborted) return deny("The turn was cancelled.");
427
+ return fromAnswer(raw);
428
+ } catch (err) {
429
+ const message = err instanceof Error ? err.message : String(err);
430
+ return deny(message || "Sideboard could not ask for permission.");
431
+ }
432
+ }
433
+
387
434
  // src/agents/claude-runner.ts
388
435
  dropNestedElectronEnvFromProcess();
389
436
  function emit(value) {
@@ -446,6 +493,14 @@ async function main() {
446
493
  if (req.systemPrompt) options.appendSystemPrompt = req.systemPrompt;
447
494
  if (req.effort) options.effort = req.effort;
448
495
  if (req.chrome) options.chrome = true;
496
+ options.canUseTool = (toolName, toolInput, toolOpts) => claudePermissionResult({
497
+ permissionMode: req.permissionMode,
498
+ threadId: process.env.SIDEBOARD_THREAD_ID?.trim() || "",
499
+ toolName,
500
+ toolInput,
501
+ options: toolOpts,
502
+ rpc: req.agentRpc
503
+ });
449
504
  options.settingSources = [];
450
505
  for await (const message of sdk.query({ prompt: req.prompt, options })) {
451
506
  emit(message);
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  AGENT_RPC_CLAUDE_SDK_SERVER,
4
+ AgentRpcClient,
4
5
  PILOT_TOOL_DESCRIPTIONS,
5
6
  createPilotRpcExecutors
6
- } from "../chunk-NYBFYFK7.js";
7
+ } from "../chunk-QDA6NXRA.js";
7
8
  import {
8
9
  dropNestedElectronEnvFromProcess
9
10
  } from "../chunk-4TR3HZFT.js";
@@ -55,6 +56,53 @@ function createClaudePilotSdkServer(createSdkMcpServer, tool, opts) {
55
56
  return { server, exec };
56
57
  }
57
58
 
59
+ // src/agents/claude-permission.ts
60
+ function deny(message) {
61
+ return { behavior: "deny", message, decisionClassification: "user_reject" };
62
+ }
63
+ function fromAnswer(raw) {
64
+ if (!raw || typeof raw !== "object") return deny("Sideboard did not return a permission decision.");
65
+ const rec = raw;
66
+ if (rec.behavior === "allow") {
67
+ return {
68
+ behavior: "allow",
69
+ ...Array.isArray(rec.updatedPermissions) && rec.updatedPermissions.length > 0 ? { updatedPermissions: rec.updatedPermissions } : {},
70
+ decisionClassification: rec.decisionClassification === "user_permanent" ? "user_permanent" : "user_temporary"
71
+ };
72
+ }
73
+ const message = typeof rec.message === "string" && rec.message.trim() ? rec.message.trim() : "The user denied this action.";
74
+ return deny(message);
75
+ }
76
+ async function claudePermissionResult(input) {
77
+ if (input.permissionMode === "plan") {
78
+ return deny("Plan mode is on, so this action stays blocked.");
79
+ }
80
+ const threadId = input.threadId.trim();
81
+ if (!threadId) return deny("Sideboard could not tell which chat to ask.");
82
+ if (input.options.signal?.aborted) return deny("The turn was cancelled.");
83
+ const call = input.call ?? (input.rpc ? (method, params) => new AgentRpcClient(input.rpc).call(method, params) : null);
84
+ if (!call) return deny("Sideboard has no permission prompt for this turn.");
85
+ try {
86
+ const raw = await call("permission.ask", {
87
+ threadId,
88
+ toolName: input.toolName,
89
+ input: input.toolInput,
90
+ blockedPath: input.options.blockedPath,
91
+ title: input.options.title,
92
+ description: input.options.description,
93
+ displayName: input.options.displayName,
94
+ suggestions: input.options.suggestions,
95
+ suppressAlwaysAllow: input.options.suppressAlwaysAllowRule === true,
96
+ defaultToNo: input.options.defaultToNo === true
97
+ });
98
+ if (input.options.signal?.aborted) return deny("The turn was cancelled.");
99
+ return fromAnswer(raw);
100
+ } catch (err) {
101
+ const message = err instanceof Error ? err.message : String(err);
102
+ return deny(message || "Sideboard could not ask for permission.");
103
+ }
104
+ }
105
+
58
106
  // src/agents/claude-runner.ts
59
107
  dropNestedElectronEnvFromProcess();
60
108
  function emit(value) {
@@ -117,6 +165,14 @@ async function main() {
117
165
  if (req.systemPrompt) options.appendSystemPrompt = req.systemPrompt;
118
166
  if (req.effort) options.effort = req.effort;
119
167
  if (req.chrome) options.chrome = true;
168
+ options.canUseTool = (toolName, toolInput, toolOpts) => claudePermissionResult({
169
+ permissionMode: req.permissionMode,
170
+ threadId: process.env.SIDEBOARD_THREAD_ID?.trim() || "",
171
+ toolName,
172
+ toolInput,
173
+ options: toolOpts,
174
+ rpc: req.agentRpc
175
+ });
120
176
  options.settingSources = [];
121
177
  for await (const message of sdk.query({ prompt: req.prompt, options })) {
122
178
  emit(message);
@@ -5,7 +5,7 @@ import {
5
5
  guardCursorCustomTool,
6
6
  shouldReturnRunErrorToAgent,
7
7
  sideboardCursorRpcTools
8
- } from "../chunk-ER6BGGME.js";
8
+ } from "../chunk-J54UPHXZ.js";
9
9
  import {
10
10
  createAgentStreamCoalescer
11
11
  } from "../chunk-AXQ4ZWHK.js";
@@ -31,7 +31,7 @@ import {
31
31
  cursorSdkStoreDir
32
32
  } from "../chunk-UWQ6UCIB.js";
33
33
  import "../chunk-QVN2WOKJ.js";
34
- import "../chunk-NYBFYFK7.js";
34
+ import "../chunk-QDA6NXRA.js";
35
35
  import {
36
36
  dropNestedElectronEnvFromProcess
37
37
  } from "../chunk-4TR3HZFT.js";
@@ -46,7 +46,7 @@ import {
46
46
  resolveCursorSdkRoot,
47
47
  resolveQuotaFallbackAgent,
48
48
  turnCostUsdFromCursorUsage
49
- } from "./chunk-ABLHTRRG.js";
49
+ } from "./chunk-2O3ICR77.js";
50
50
  import {
51
51
  getAgentSetupInfo,
52
52
  installAgent,
@@ -63,8 +63,8 @@ import "./chunk-7IAMHN2N.js";
63
63
  import "./chunk-PXMLMBMI.js";
64
64
  import "./chunk-2GPQZZLY.js";
65
65
  import "./chunk-ED4ZXQVO.js";
66
- import "./chunk-E7G7RY6T.js";
67
- import "./chunk-6SGYGYH7.js";
66
+ import "./chunk-WQREAX35.js";
67
+ import "./chunk-VXNZG4J6.js";
68
68
  import "./chunk-N2WW62LF.js";
69
69
  import "./chunk-DD67JWTN.js";
70
70
  import {
@@ -88,7 +88,7 @@ import "./chunk-NSTQ6QKD.js";
88
88
  import "./chunk-WWUABK6B.js";
89
89
  import "./chunk-FJZWM2ON.js";
90
90
  import "./chunk-UN5Q7POQ.js";
91
- import "./chunk-YRXV3E7J.js";
91
+ import "./chunk-TVN4TDFB.js";
92
92
  import "./chunk-4RZRHTSZ.js";
93
93
  import "./chunk-KGZBYWZ3.js";
94
94
  import "./chunk-H5XL4KUS.js";
@@ -37,7 +37,7 @@ import {
37
37
  planModeTurnInstruction,
38
38
  resolveCursorModelId,
39
39
  resolveQuotaFallbackAgent
40
- } from "./chunk-RWIYYFID.js";
40
+ } from "./chunk-6GTABVNG.js";
41
41
  import "./chunk-VGNLMGBK.js";
42
42
  import "./chunk-Q3DPZ4DE.js";
43
43
  import {
@@ -52,9 +52,9 @@ import {
52
52
  resolveLoginCommand,
53
53
  whichOnPath
54
54
  } from "./chunk-B42H6GJR.js";
55
- import "./chunk-YEIPPZ5W.js";
56
- import "./chunk-ZEP6JIRF.js";
57
- import "./chunk-QB5MDOHL.js";
55
+ import "./chunk-BGEECLKH.js";
56
+ import "./chunk-JWXJXEA3.js";
57
+ import "./chunk-WZLV4WNS.js";
58
58
  import "./chunk-2P4XKWV2.js";
59
59
  import "./chunk-33KDPEK4.js";
60
60
  import "./chunk-JAT3JFOS.js";
@@ -81,7 +81,7 @@ import {
81
81
  resolveCommandBinarySync,
82
82
  withExportedPath
83
83
  } from "./chunk-QVN2WOKJ.js";
84
- import "./chunk-NYBFYFK7.js";
84
+ import "./chunk-QDA6NXRA.js";
85
85
  import {
86
86
  ORCHESTRATOR_AGENT_KINDS,
87
87
  assertOrchestratorCapableAgent,
@@ -24,13 +24,13 @@ import {
24
24
  } from "./chunk-ED4ZXQVO.js";
25
25
  import {
26
26
  isOrchestratorThread
27
- } from "./chunk-E7G7RY6T.js";
27
+ } from "./chunk-WQREAX35.js";
28
28
  import {
29
29
  codexUnattendedGitConfigArgs,
30
30
  mergeAgentGitAuthEnv,
31
31
  resolveAgentGitAuthEnv,
32
32
  resolveCodexGitWritableRoots
33
- } from "./chunk-6SGYGYH7.js";
33
+ } from "./chunk-VXNZG4J6.js";
34
34
  import {
35
35
  npmGlobalNodeModules,
36
36
  run
@@ -2018,7 +2018,7 @@ var claudeAdapter = {
2018
2018
  );
2019
2019
  }
2020
2020
  const mode = permissionMode(thread);
2021
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-PX4GUVLW.js");
2021
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-NMRUGGFF.js");
2022
2022
  const isOrchestrator = isOrchestratorThread2(thread);
2023
2023
  const rpc = worktreeAgentRpc(isOrchestrator);
2024
2024
  const injectedServers = await buildInjectedMcpServers({
@@ -8,11 +8,11 @@ import {
8
8
  isGlobalThread,
9
9
  isOrchestratorThread,
10
10
  isSlackCoordinatorThread
11
- } from "./chunk-YEIPPZ5W.js";
11
+ } from "./chunk-BGEECLKH.js";
12
12
  import {
13
13
  mergeAgentGitAuthEnv,
14
14
  resolveAgentGitAuthEnv
15
- } from "./chunk-ZEP6JIRF.js";
15
+ } from "./chunk-JWXJXEA3.js";
16
16
  import {
17
17
  allocateTeamName,
18
18
  createEmptyThread,
@@ -23,7 +23,7 @@ import {
23
23
  updateThread,
24
24
  worktreeNameFromPath,
25
25
  writeThread
26
- } from "./chunk-QB5MDOHL.js";
26
+ } from "./chunk-WZLV4WNS.js";
27
27
  import {
28
28
  ensureWorktreeSideboardIgnored
29
29
  } from "./chunk-2P4XKWV2.js";
@@ -1776,7 +1776,7 @@ var PORT_RANGE_SIZE = 10;
1776
1776
  var RECLAIM_RETRY_DELAY_MS = 40;
1777
1777
  var RECLAIM_TRIES = 8;
1778
1778
  async function killReclaimable(ports, worktreePath, signal) {
1779
- const { killListenersOnPorts: killListenersOnPorts2, killStaleWorktreeListeners: killStaleWorktreeListeners2 } = await import("./conductor-HT2UANDY.js");
1779
+ const { killListenersOnPorts: killListenersOnPorts2, killStaleWorktreeListeners: killStaleWorktreeListeners2 } = await import("./conductor-ZXDIA6OF.js");
1780
1780
  if (worktreePath) killStaleWorktreeListeners2(ports, worktreePath, signal);
1781
1781
  else killListenersOnPorts2(ports);
1782
1782
  }
@@ -12,13 +12,13 @@ import {
12
12
  } from "./chunk-Q3DPZ4DE.js";
13
13
  import {
14
14
  isOrchestratorThread
15
- } from "./chunk-YEIPPZ5W.js";
15
+ } from "./chunk-BGEECLKH.js";
16
16
  import {
17
17
  codexUnattendedGitConfigArgs,
18
18
  mergeAgentGitAuthEnv,
19
19
  resolveAgentGitAuthEnv,
20
20
  resolveCodexGitWritableRoots
21
- } from "./chunk-ZEP6JIRF.js";
21
+ } from "./chunk-JWXJXEA3.js";
22
22
  import {
23
23
  loadBrightsyConfig
24
24
  } from "./chunk-33KDPEK4.js";
@@ -58,7 +58,7 @@ import {
58
58
  PILOT_TOOL_DESCRIPTIONS,
59
59
  PILOT_TOOL_NAMES,
60
60
  agentRpcConnectFromMetadata
61
- } from "./chunk-NYBFYFK7.js";
61
+ } from "./chunk-QDA6NXRA.js";
62
62
  import {
63
63
  claudeChromeEnabled,
64
64
  fromInclusiveInputUsage,
@@ -1755,7 +1755,7 @@ var claudeAdapter = {
1755
1755
  );
1756
1756
  }
1757
1757
  const mode = permissionMode(thread);
1758
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-4WAU4PAL.js");
1758
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-47G453ZU.js");
1759
1759
  const isOrchestrator = isOrchestratorThread2(thread);
1760
1760
  const rpc = worktreeAgentRpc(isOrchestrator);
1761
1761
  const injectedServers = await buildInjectedMcpServers({
@@ -3,7 +3,7 @@ import {
3
3
  ensureGhPreferOrigin,
4
4
  resolveGithubRepoSlug,
5
5
  resolveRepoRoot
6
- } from "./chunk-ZEP6JIRF.js";
6
+ } from "./chunk-JWXJXEA3.js";
7
7
  import {
8
8
  allocateTeamName,
9
9
  createEmptyThread,
@@ -12,7 +12,7 @@ import {
12
12
  teamSlugFromName,
13
13
  updateThread,
14
14
  writeThread
15
- } from "./chunk-QB5MDOHL.js";
15
+ } from "./chunk-WZLV4WNS.js";
16
16
  import {
17
17
  ATTACHMENTS_DIR,
18
18
  attachmentsGitignoreBody
@@ -14,7 +14,7 @@ import {
14
14
  WAIT_FOR_TURN_DESCRIPTION,
15
15
  WAIT_FOR_TURN_SCHEMA,
16
16
  createPilotRpcExecutors
17
- } from "./chunk-NYBFYFK7.js";
17
+ } from "./chunk-QDA6NXRA.js";
18
18
 
19
19
  // src/agents/tool-result-clip.ts
20
20
  import { mkdirSync, writeFileSync } from "fs";
@@ -4,7 +4,7 @@ import {
4
4
  normalizeTakenSlug,
5
5
  normalizeWorktreePath,
6
6
  takenSlugsFromThread
7
- } from "./chunk-QB5MDOHL.js";
7
+ } from "./chunk-WZLV4WNS.js";
8
8
  import {
9
9
  ensureWorktreeSideboardIgnored
10
10
  } from "./chunk-2P4XKWV2.js";
@@ -406,6 +406,7 @@ export {
406
406
  readAgentRuntimeMetadata,
407
407
  agentRpcConnectFromMetadata,
408
408
  clearAgentRuntimeMetadataIfOwned,
409
+ AgentRpcClient,
409
410
  PILOT_TOOL_NAMES,
410
411
  PILOT_TOOL_DESCRIPTIONS,
411
412
  WAIT_FOR_TURN_DESCRIPTION,
@@ -27,7 +27,7 @@ import {
27
27
  parseSessionQuotaResetAt,
28
28
  planModeTurnInstruction,
29
29
  resolveQuotaFallbackAgent
30
- } from "./chunk-ABLHTRRG.js";
30
+ } from "./chunk-2O3ICR77.js";
31
31
  import {
32
32
  REVIEW_TAB_TITLE,
33
33
  applyWorktreePkgCacheEnv,
@@ -66,7 +66,7 @@ import {
66
66
  worktreeDevProcessKey,
67
67
  worktreeRunProcessKey,
68
68
  worktreeSetupProcessKey
69
- } from "./chunk-HWIIRVYE.js";
69
+ } from "./chunk-ZXWRNA4G.js";
70
70
  import {
71
71
  applyAgentEvent,
72
72
  clipAgentEventForPaint,
@@ -118,7 +118,7 @@ import {
118
118
  stageAbsolutePathsAsAttachments,
119
119
  stageBuffersAsAttachments,
120
120
  syncWorkspacesFromThreads
121
- } from "./chunk-E7G7RY6T.js";
121
+ } from "./chunk-WQREAX35.js";
122
122
  import {
123
123
  addPrStackLayer,
124
124
  allocateTeamSlug,
@@ -160,7 +160,7 @@ import {
160
160
  resolveRepoRoot,
161
161
  switchWorktreeBranch,
162
162
  withRepoGitLock
163
- } from "./chunk-6SGYGYH7.js";
163
+ } from "./chunk-VXNZG4J6.js";
164
164
  import {
165
165
  clearStaleIndexLocks,
166
166
  enrichPathWithNpmGlobalBin,
@@ -238,7 +238,7 @@ import {
238
238
  worktreeNameFromPath,
239
239
  worktreeSlugForTicket,
240
240
  writeThread
241
- } from "./chunk-YRXV3E7J.js";
241
+ } from "./chunk-TVN4TDFB.js";
242
242
  import {
243
243
  annotateDevAccessRuns,
244
244
  appDataDir,
@@ -292,7 +292,7 @@ function formatInjectedNoticesForTurn(notices) {
292
292
  }
293
293
 
294
294
  // src/orchestrator/orchestrator.ts
295
- import { randomUUID as randomUUID4 } from "crypto";
295
+ import { randomUUID as randomUUID5 } from "crypto";
296
296
  import { existsSync as existsSync14 } from "fs";
297
297
 
298
298
  // src/agents/spawn.ts
@@ -503,9 +503,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
503
503
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
504
504
  );
505
505
  }
506
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-PX4GUVLW.js");
506
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-NMRUGGFF.js");
507
507
  if (isGlobalThread2(thread)) {
508
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-K6XHUG3N.js");
508
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-L3V2CMWX.js");
509
509
  ensureGlobalCoordinatorCwd2(
510
510
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
511
511
  );
@@ -545,6 +545,7 @@ async function spawnAgentTurn(thread, input, onEvent) {
545
545
  }
546
546
  applyManagedAccountEnv(env, thread.agent, resolveAccountForThread(thread, accounts));
547
547
  sanitizeAgentHostEnv(env, cmd.cwd);
548
+ env[SIDEBOARD_THREAD_ID_ENV] = thread.id;
548
549
  ensureAgentPath(env);
549
550
  applyPromptCacheTtlEnv(thread.agent, env);
550
551
  applyAgentRunnerHeapEnv(env);
@@ -1496,6 +1497,31 @@ function thisProcessShouldDrainAgentQueues() {
1496
1497
  return !isDesktopHostAlive();
1497
1498
  }
1498
1499
 
1500
+ // src/agents/tool-permission.ts
1501
+ import { randomUUID } from "crypto";
1502
+ import { dirname } from "path";
1503
+ var queues = /* @__PURE__ */ new Map();
1504
+ var publisher = null;
1505
+ function setToolPermissionPublisher(next) {
1506
+ publisher = next;
1507
+ }
1508
+ function denied(message) {
1509
+ return { behavior: "deny", message, decisionClassification: "user_reject" };
1510
+ }
1511
+ function clearPrompt(threadId, id) {
1512
+ publisher?.clear(threadId, id);
1513
+ }
1514
+ function denyPendingToolPermissions(threadId) {
1515
+ const q = queues.get(threadId);
1516
+ if (!q?.length) return;
1517
+ const pending = q.splice(0, q.length);
1518
+ queues.delete(threadId);
1519
+ const answer = denied("The turn ended before this was allowed.");
1520
+ for (const item of pending) item.resolve(answer);
1521
+ const last = pending[pending.length - 1];
1522
+ if (last) clearPrompt(threadId, last.id);
1523
+ }
1524
+
1499
1525
  // src/orchestrator/notify-orchestrator.ts
1500
1526
  var MAX_NOTIFY_ORCHESTRATOR_MESSAGE_CHARS = 1500;
1501
1527
  var inputRequiredNotified = /* @__PURE__ */ new Set();
@@ -1649,6 +1675,7 @@ function writeAgentBlock(threadId, block) {
1649
1675
  updateThread(threadId, { agentBlock: block });
1650
1676
  }
1651
1677
  function settleAgentBlock(threadId, parts, failed) {
1678
+ denyPendingToolPermissions(threadId);
1652
1679
  const thread = readThread(threadId);
1653
1680
  if (!thread || thread.status === "archived") return;
1654
1681
  const next = agentBlockAfterTurn({
@@ -1762,13 +1789,13 @@ function writeStoppedStatus(threadId, reason) {
1762
1789
  }
1763
1790
 
1764
1791
  // src/orchestrator/steer-request.ts
1765
- import { randomUUID } from "crypto";
1792
+ import { randomUUID as randomUUID2 } from "crypto";
1766
1793
  function isUnclaimedSteerRequest(req) {
1767
1794
  return Boolean(req?.requestId && !req.claimedAt);
1768
1795
  }
1769
1796
  function nextSteerRequest(existing) {
1770
1797
  if (existing?.requestId && !existing.claimedAt) return existing;
1771
- return { requestId: randomUUID(), requestedAt: (/* @__PURE__ */ new Date()).toISOString() };
1798
+ return { requestId: randomUUID2(), requestedAt: (/* @__PURE__ */ new Date()).toISOString() };
1772
1799
  }
1773
1800
  function claimSteerRequest(threadId) {
1774
1801
  const pending = readThread(threadId)?.steerRequest;
@@ -1781,7 +1808,6 @@ function claimSteerRequest(threadId) {
1781
1808
  // src/threads/agent-purpose-title.ts
1782
1809
  function agentPurposeStamp(input) {
1783
1810
  if (input.autoContinue) return null;
1784
- if (input.thread.sourceType === "orchestration") return null;
1785
1811
  if (input.thread.title.trim() === REVIEW_TAB_TITLE) return null;
1786
1812
  const identities = worktreeIdentityTitles(input.thread);
1787
1813
  const titled = input.thread.title?.trim() || "";
@@ -2859,7 +2885,7 @@ async function forkThreadWorktree(input, onSetupLine) {
2859
2885
  }
2860
2886
 
2861
2887
  // src/orchestrator/quota-failover.ts
2862
- import { randomUUID as randomUUID2 } from "crypto";
2888
+ import { randomUUID as randomUUID3 } from "crypto";
2863
2889
  function managedKindForAgent(agent) {
2864
2890
  return agent === "claude" || agent === "codex" ? agent : null;
2865
2891
  }
@@ -2979,7 +3005,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
2979
3005
  ...instructions
2980
3006
  ].join("\n");
2981
3007
  return {
2982
- id: randomUUID2(),
3008
+ id: randomUUID3(),
2983
3009
  name: orch ? "Orchestration quota handoff.md" : "Quota handoff.md",
2984
3010
  kind: "transcript",
2985
3011
  content: body
@@ -3119,7 +3145,7 @@ async function adoptThread(input) {
3119
3145
  messages: input.messages ?? []
3120
3146
  });
3121
3147
  writeThread(thread);
3122
- const { addWorkspace: addWorkspace2 } = await import("./workspaces-MFU3IGAP.js");
3148
+ const { addWorkspace: addWorkspace2 } = await import("./workspaces-PGY4UWZ3.js");
3123
3149
  await addWorkspace2(repoPath);
3124
3150
  const { ensureWorktreeSideboardIgnored } = await import("./worktree-exclude-5N2KTYIT.js");
3125
3151
  await ensureWorktreeSideboardIgnored(input.worktreePath);
@@ -3602,7 +3628,7 @@ async function createPrStack(input, onSetupLine) {
3602
3628
 
3603
3629
  // src/diff/diff.ts
3604
3630
  import { existsSync as existsSync9, mkdirSync, readFileSync as readFileSync6, statSync as statSync2, writeFileSync as writeFileSync5 } from "fs";
3605
- import { dirname, join as join8 } from "path";
3631
+ import { dirname as dirname2, join as join8 } from "path";
3606
3632
  async function inspectGitWorktree(worktreePath) {
3607
3633
  if (!worktreePath || !existsSync9(worktreePath)) return "missing_worktree";
3608
3634
  const check = await git(["rev-parse", "--is-inside-work-tree"], worktreePath, {
@@ -4331,7 +4357,7 @@ function assertSafeRelativePath(relativePath) {
4331
4357
  function writeWorktreeFile(worktreePath, relativePath, content) {
4332
4358
  assertSafeRelativePath(relativePath);
4333
4359
  const abs = join8(worktreePath, relativePath);
4334
- mkdirSync(dirname(abs), { recursive: true });
4360
+ mkdirSync(dirname2(abs), { recursive: true });
4335
4361
  writeFileSync5(abs, content, "utf8");
4336
4362
  return { path: relativePath };
4337
4363
  }
@@ -4997,7 +5023,7 @@ import { join as join12 } from "path";
4997
5023
 
4998
5024
  // src/skills/detached-job-path.ts
4999
5025
  import { existsSync as existsSync11 } from "fs";
5000
- import { dirname as dirname2, join as join11 } from "path";
5026
+ import { dirname as dirname3, join as join11 } from "path";
5001
5027
  import { fileURLToPath } from "url";
5002
5028
  var DETACHED_JOB_FILENAMES = ["detached-job.cjs", "detached-job.js"];
5003
5029
  function compiledModuleDir() {
@@ -5006,7 +5032,7 @@ function compiledModuleDir() {
5006
5032
  try {
5007
5033
  const url = import.meta.url;
5008
5034
  if (typeof url === "string" && url.length > 0) {
5009
- return dirname2(fileURLToPath(url));
5035
+ return dirname3(fileURLToPath(url));
5010
5036
  }
5011
5037
  } catch {
5012
5038
  }
@@ -5032,7 +5058,7 @@ function resolveDetachedJobScript() {
5032
5058
  for (let i = 0; i < 8; i++) {
5033
5059
  const candidate = detachedJobScriptIn(dir);
5034
5060
  if (candidate) return candidate;
5035
- const parent = dirname2(dir);
5061
+ const parent = dirname3(dir);
5036
5062
  if (parent === dir) break;
5037
5063
  dir = parent;
5038
5064
  }
@@ -5744,7 +5770,7 @@ async function syncThreadBranchFromGit(threadId) {
5744
5770
  }
5745
5771
 
5746
5772
  // src/store/schedules.ts
5747
- import { randomUUID as randomUUID3 } from "crypto";
5773
+ import { randomUUID as randomUUID4 } from "crypto";
5748
5774
  import { existsSync as existsSync13, readFileSync as readFileSync8 } from "fs";
5749
5775
  import { join as join13 } from "path";
5750
5776
  import { Cron } from "croner";
@@ -5883,7 +5909,7 @@ function buildTask(input, now) {
5883
5909
  const ts = nowIso(now);
5884
5910
  const agent = input.agent ? coerceOrchestratorAgent(input.agent) : null;
5885
5911
  return {
5886
- id: randomUUID3(),
5912
+ id: randomUUID4(),
5887
5913
  name: input.name?.trim() || defaultScheduleName(prompt),
5888
5914
  prompt,
5889
5915
  enabled: input.enabled !== false,
@@ -5994,7 +6020,7 @@ function formatScheduledPrompt(name, prompt) {
5994
6020
  ${prompt}`;
5995
6021
  }
5996
6022
  async function defaultDeps() {
5997
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-VNSEXL62.js");
6023
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-MR7TCIPP.js");
5998
6024
  const orch = getOrchestrator2();
5999
6025
  return {
6000
6026
  findThread: (id) => findThreadByRef(id),
@@ -7707,7 +7733,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
7707
7733
  const request = sameIntent ? pending : {
7708
7734
  op,
7709
7735
  scriptName: scriptName ?? null,
7710
- requestId: randomUUID4(),
7736
+ requestId: randomUUID5(),
7711
7737
  requestedAt: (/* @__PURE__ */ new Date()).toISOString()
7712
7738
  };
7713
7739
  if (!sameIntent) {
@@ -8866,7 +8892,7 @@ async function startOrchestration(opts) {
8866
8892
  sourceRef: "default",
8867
8893
  ...createOpts
8868
8894
  }).catch(async () => {
8869
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-2VSHRI72.js");
8895
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-JZXDAKQF.js");
8870
8896
  const repo = await resolveRepoRoot2(repoPath);
8871
8897
  const def = await resolveDefaultBranch2(repo);
8872
8898
  return orch.createThread({
@@ -8876,7 +8902,7 @@ async function startOrchestration(opts) {
8876
8902
  repoPath: repo
8877
8903
  });
8878
8904
  });
8879
- const { updateThread: upd } = await import("./thread-store-DPKESDFR.js");
8905
+ const { updateThread: upd } = await import("./thread-store-H6D6MDUM.js");
8880
8906
  const updated = upd(thread.id, {
8881
8907
  sourceType: "orchestration",
8882
8908
  sourceRef: goal
@@ -8893,8 +8919,11 @@ export {
8893
8919
  MAX_RUN_LOG_CHARS,
8894
8920
  DEFAULT_RUN_LOG_TAIL_CHARS,
8895
8921
  sliceRunLogOutput,
8922
+ setToolPermissionPublisher,
8896
8923
  resolveNotifyCallerThread,
8897
8924
  notifyOrchestrator,
8925
+ clampBlockReason,
8926
+ writeAgentBlock,
8898
8927
  chatBlockedSuffix,
8899
8928
  agentBlockFields,
8900
8929
  stampAskUserBlock,
@@ -873,9 +873,18 @@ function branchDisplayLabel(branchName, worktreePath) {
873
873
  }
874
874
  return branchName.trim();
875
875
  }
876
+ function taskPurposeTitle(title) {
877
+ const trimmed = title?.trim() ?? "";
878
+ if (!trimmed || teamSlugFromName(trimmed)) return null;
879
+ return trimmed;
880
+ }
876
881
  function threadDisplayLabel(thread) {
877
882
  if (thread.userSetTitle && thread.title?.trim()) return thread.title.trim();
878
883
  if (thread.prTitle?.trim()) return thread.prTitle.trim();
884
+ if (isPlaceholderBranch(thread.branchName, thread.worktreePath)) {
885
+ const purpose = taskPurposeTitle(thread.title);
886
+ if (purpose) return purpose;
887
+ }
879
888
  return branchDisplayLabel(thread.branchName, thread.worktreePath);
880
889
  }
881
890
  function worktreeDisplayLabel(thread) {
@@ -26,7 +26,7 @@ import {
26
26
  normalizeTakenSlug,
27
27
  normalizeWorktreePath,
28
28
  takenSlugsFromThread
29
- } from "./chunk-YRXV3E7J.js";
29
+ } from "./chunk-TVN4TDFB.js";
30
30
  import {
31
31
  worktreesRoot
32
32
  } from "./chunk-H5XL4KUS.js";