@sideboard-ai/core 0.1.318 → 0.1.320

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 (61) hide show
  1. package/dist/{abletime-TKAFNXCM.js → abletime-CRRLEYTE.js} +6 -4
  2. package/dist/{abletime-KWOBUL46.js → abletime-ICW6Q2AB.js} +6 -4
  3. package/dist/{abletime-oauth-S4AXA4WR.js → abletime-oauth-P3KPPJE4.js} +3 -3
  4. package/dist/{abletime-oauth-IUIAGLFJ.js → abletime-oauth-Q76XBSPG.js} +3 -3
  5. package/dist/{abletime-rest-RWN4EPY3.js → abletime-rest-DNFAYYLP.js} +3 -3
  6. package/dist/{abletime-rest-ORBELZQO.js → abletime-rest-DQ3PNKXP.js} +3 -3
  7. package/dist/{agents-KABJUDPI.js → agents-CJZYJOWP.js} +7 -7
  8. package/dist/{agents-2AR7I6B6.js → agents-F2E2HACB.js} +7 -7
  9. package/dist/{app-settings-CZVFMOI5.js → app-settings-KMPVI2B7.js} +1 -1
  10. package/dist/{app-settings-V6YPYY57.js → app-settings-P3H4SEIK.js} +1 -1
  11. package/dist/{chunk-YEIHCSZS.js → chunk-4GZC6DDH.js} +2 -0
  12. package/dist/{chunk-XOZNEAWF.js → chunk-56M6VEXI.js} +3 -3
  13. package/dist/{chunk-7SCVGGF6.js → chunk-5OQONGHO.js} +5 -5
  14. package/dist/{chunk-A6C67DY5.js → chunk-5S3YP5KH.js} +4 -4
  15. package/dist/{chunk-I5CLCWUK.js → chunk-72PUPPV2.js} +9 -5
  16. package/dist/{chunk-BXTISNKW.js → chunk-B7UL36WH.js} +428 -99
  17. package/dist/{chunk-W5QZWAUB.js → chunk-BTIXTH4N.js} +9 -5
  18. package/dist/{chunk-AESO2KJS.js → chunk-CB5Z5C3J.js} +2 -2
  19. package/dist/{chunk-2HOZMSKQ.js → chunk-DFUXW2IT.js} +2 -2
  20. package/dist/{chunk-ST2UQBJT.js → chunk-DJZRDTZY.js} +6 -6
  21. package/dist/{chunk-TUJFCJJU.js → chunk-EDXTP2VR.js} +2 -2
  22. package/dist/{chunk-I5TESHDN.js → chunk-EQ52JR3Q.js} +5 -5
  23. package/dist/{chunk-FDXHNROD.js → chunk-EQ5JY3MJ.js} +2 -2
  24. package/dist/{chunk-E52SQENB.js → chunk-FZKAAAEB.js} +3 -1
  25. package/dist/{chunk-VZAJVX36.js → chunk-HHPTGIKS.js} +2 -2
  26. package/dist/{chunk-23ZUL2EX.js → chunk-IDPFLXRY.js} +429 -100
  27. package/dist/{chunk-GCHSJCCX.js → chunk-IFU4W4C4.js} +3 -1
  28. package/dist/{chunk-IAPO7ZFG.js → chunk-LLIEU2ZB.js} +5 -5
  29. package/dist/{chunk-MBYGWNLQ.js → chunk-OAFBHCSM.js} +1 -1
  30. package/dist/{chunk-NRSC4N5X.js → chunk-P74GXA5V.js} +6 -6
  31. package/dist/{chunk-A46CIARU.js → chunk-PNLGWAYE.js} +2 -2
  32. package/dist/{chunk-53OCOGND.js → chunk-QGY3UNNL.js} +2 -2
  33. package/dist/{chunk-7Q327QF2.js → chunk-QIC2JXHW.js} +5 -5
  34. package/dist/{chunk-YALFZKSC.js → chunk-RHJPP26T.js} +11 -11
  35. package/dist/{chunk-AZ4GEEGL.js → chunk-UK2KESBN.js} +2 -2
  36. package/dist/{chunk-7ADEYEMH.js → chunk-V76MQ7MH.js} +5 -5
  37. package/dist/{chunk-HOLB6ZFZ.js → chunk-XMHMVEIY.js} +2 -0
  38. package/dist/{chunk-GH7UMULC.js → chunk-ZYZBCLJR.js} +6 -6
  39. package/dist/{conductor-MG2RAQNT.js → conductor-FPFY6Z5S.js} +6 -6
  40. package/dist/{conductor-NIUBJLTS.js → conductor-JA5W3L7C.js} +6 -6
  41. package/dist/{coordinator-prompt-3CT3D5UM.js → coordinator-prompt-M75TAN43.js} +4 -4
  42. package/dist/{coordinator-prompt-X74F3JIC.js → coordinator-prompt-NUC2ZXMJ.js} +4 -4
  43. package/dist/{global-workspace-BUWMRNW5.js → global-workspace-5A4H34AF.js} +4 -4
  44. package/dist/{global-workspace-FTNJEML3.js → global-workspace-SCLQUNUI.js} +4 -4
  45. package/dist/index.cjs +861 -475
  46. package/dist/index.d.cts +56 -13
  47. package/dist/index.d.ts +56 -13
  48. package/dist/index.js +54 -31
  49. package/dist/mcp/run-stdio.cjs +459 -95
  50. package/dist/mcp/run-stdio.js +23 -23
  51. package/dist/{optional-cli-EMSZBYDE.js → optional-cli-2V3SLME5.js} +3 -3
  52. package/dist/{optional-cli-6GGESWGE.js → optional-cli-MRNQKVIR.js} +4 -4
  53. package/dist/{orchestrator-N54V3B76.js → orchestrator-7BDZ5GWD.js} +10 -10
  54. package/dist/{orchestrator-2SXK4U65.js → orchestrator-NPFWU3XU.js} +10 -10
  55. package/dist/{thread-store-PLNIWFZ4.js → thread-store-JWHVXLDX.js} +1 -1
  56. package/dist/{thread-store-7BBA63KV.js → thread-store-QHYN2ZMQ.js} +1 -1
  57. package/dist/{workspaces-2V5UYPYC.js → workspaces-5QA3YM4L.js} +4 -4
  58. package/dist/{workspaces-MGKEAYNM.js → workspaces-KWMBOTQD.js} +4 -4
  59. package/dist/{worktree-THAXW5U7.js → worktree-7EATHVYQ.js} +3 -3
  60. package/dist/{worktree-XJKLDYOL.js → worktree-O6BANO2I.js} +3 -3
  61. package/package.json +1 -1
@@ -14,7 +14,7 @@ import {
14
14
  parseSessionQuotaResetAt,
15
15
  planModeTurnInstruction,
16
16
  resolveQuotaFallbackAgent
17
- } from "./chunk-IAPO7ZFG.js";
17
+ } from "./chunk-LLIEU2ZB.js";
18
18
  import {
19
19
  applyWorktreePkgCacheEnv,
20
20
  askBlockStillWaiting,
@@ -52,7 +52,7 @@ import {
52
52
  worktreeDevProcessKey,
53
53
  worktreeRunProcessKey,
54
54
  worktreeSetupProcessKey
55
- } from "./chunk-ST2UQBJT.js";
55
+ } from "./chunk-DJZRDTZY.js";
56
56
  import {
57
57
  applyAgentEvent,
58
58
  clipAgentEventForPaint,
@@ -67,14 +67,14 @@ import {
67
67
  partsToAssistantText,
68
68
  stripBrightsyNdjsonNoise,
69
69
  toolDescription
70
- } from "./chunk-7Q327QF2.js";
70
+ } from "./chunk-QIC2JXHW.js";
71
71
  import {
72
72
  titleFromPrompt
73
73
  } from "./chunk-7H655NEW.js";
74
74
  import {
75
75
  formatOptionalServicesDirectiveForTurn,
76
76
  formatOptionalServicesReminderForTurn
77
- } from "./chunk-FDXHNROD.js";
77
+ } from "./chunk-EQ5JY3MJ.js";
78
78
  import {
79
79
  SLACK_REPLY_FORMATTING,
80
80
  addWorkspace,
@@ -99,7 +99,7 @@ import {
99
99
  stageAbsolutePathsAsAttachments,
100
100
  stageBuffersAsAttachments,
101
101
  syncWorkspacesFromThreads
102
- } from "./chunk-YALFZKSC.js";
102
+ } from "./chunk-RHJPP26T.js";
103
103
  import {
104
104
  addPrStackLayer,
105
105
  allocateTeamSlug,
@@ -143,7 +143,7 @@ import {
143
143
  resolveRepoRoot,
144
144
  switchWorktreeBranch,
145
145
  withRepoGitLock
146
- } from "./chunk-TUJFCJJU.js";
146
+ } from "./chunk-EDXTP2VR.js";
147
147
  import {
148
148
  REVIEW_TAB_TITLE,
149
149
  agentNicknameFromWorktreePath,
@@ -171,7 +171,7 @@ import {
171
171
  worktreeNameFromPath,
172
172
  worktreeSlugForTicket,
173
173
  writeThread
174
- } from "./chunk-YEIHCSZS.js";
174
+ } from "./chunk-4GZC6DDH.js";
175
175
  import {
176
176
  mcpServerIdForPermission,
177
177
  mcpServerPermissionUpdate
@@ -239,7 +239,10 @@ import {
239
239
  usageOnLimit,
240
240
  withTurnScopedCost,
241
241
  writeViewerContext
242
- } from "./chunk-E52SQENB.js";
242
+ } from "./chunk-FZKAAAEB.js";
243
+ import {
244
+ normalizeThinkingEffort
245
+ } from "./chunk-77WWLBCI.js";
243
246
  import {
244
247
  examplePrefixedBranch,
245
248
  sanitizeGitBranchPrefix
@@ -461,9 +464,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
461
464
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
462
465
  );
463
466
  }
464
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-FTNJEML3.js");
467
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-SCLQUNUI.js");
465
468
  if (isGlobalThread2(thread)) {
466
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-X74F3JIC.js");
469
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-NUC2ZXMJ.js");
467
470
  ensureGlobalCoordinatorCwd2(
468
471
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
469
472
  );
@@ -2074,6 +2077,71 @@ function claimSteerRequest(threadId) {
2074
2077
  });
2075
2078
  }
2076
2079
 
2080
+ // src/orchestrator/ephemeral-automation.ts
2081
+ function ephemeralRunReadyToArchive(thread) {
2082
+ if (!thread.ephemeralAutomationId?.trim()) return false;
2083
+ if (thread.status !== "idle" && thread.status !== "error") return false;
2084
+ if (thread.queue.length > 0) return false;
2085
+ if (thread.agentBlock?.reason?.trim()) return false;
2086
+ if (thread.quotaResumeAt) return false;
2087
+ return true;
2088
+ }
2089
+ function markEphemeralAutomation(threadId, opts) {
2090
+ const id = opts.ephemeralAutomationId?.trim();
2091
+ const current = readThread(threadId);
2092
+ if (!current) throw new Error(`Thread not found: ${threadId}`);
2093
+ if (!id) return current;
2094
+ const title = opts.ephemeralTitle?.trim();
2095
+ return updateThread(threadId, {
2096
+ ephemeralAutomationId: id,
2097
+ ...title ? { title, userSetTitle: true } : {}
2098
+ });
2099
+ }
2100
+ async function archiveEphemeralAutomationIfReady(threadId, archive) {
2101
+ const keep = await withThreadLock(threadId, async () => {
2102
+ const thread = readThread(threadId);
2103
+ if (!thread || !ephemeralRunReadyToArchive(thread)) return null;
2104
+ const automationId = thread.ephemeralAutomationId?.trim();
2105
+ if (!automationId) return null;
2106
+ await archive(thread.id);
2107
+ return {
2108
+ automationId,
2109
+ keepId: archivedContinuationId(automationId, threadId) ?? threadId
2110
+ };
2111
+ });
2112
+ if (keep) forgetOlderEphemeralRuns(keep.automationId, keep.keepId);
2113
+ }
2114
+ function archivedContinuationId(automationId, sourceId) {
2115
+ for (const thread of listThreads({ includeArchived: true })) {
2116
+ if (thread.id === sourceId || thread.status !== "archived") continue;
2117
+ if (thread.ephemeralAutomationId !== automationId) continue;
2118
+ if (thread.quotaContinuedFromId !== sourceId) continue;
2119
+ return thread.id;
2120
+ }
2121
+ return null;
2122
+ }
2123
+ function clearEphemeralAutomation(threadId) {
2124
+ const thread = readThread(threadId);
2125
+ if (!thread?.ephemeralAutomationId?.trim()) return;
2126
+ updateThread(threadId, { ephemeralAutomationId: void 0 });
2127
+ }
2128
+ function forgetOlderEphemeralRuns(automationId, keepId) {
2129
+ const id = automationId.trim();
2130
+ if (!id || !keepId) return [];
2131
+ const removed = [];
2132
+ for (const thread of listThreads({ includeArchived: true })) {
2133
+ if (thread.id === keepId) continue;
2134
+ if (thread.status !== "archived") continue;
2135
+ if (thread.ephemeralAutomationId !== id) continue;
2136
+ try {
2137
+ deleteThreadRecord(thread.id);
2138
+ removed.push(thread.id);
2139
+ } catch {
2140
+ }
2141
+ }
2142
+ return removed;
2143
+ }
2144
+
2077
2145
  // src/threads/agent-purpose-title.ts
2078
2146
  function agentPurposeStamp(input) {
2079
2147
  if (input.autoContinue) return null;
@@ -2930,7 +2998,7 @@ async function createThread(input, _onSetupLine) {
2930
2998
  });
2931
2999
  await requireAgent(resolved.agent);
2932
3000
  if (input.cowboy) {
2933
- const { cowboyModeEnabled } = await import("./app-settings-V6YPYY57.js");
3001
+ const { cowboyModeEnabled } = await import("./app-settings-P3H4SEIK.js");
2934
3002
  if (!cowboyModeEnabled()) {
2935
3003
  throw new Error(
2936
3004
  "Cowboy mode is off. Enable it in Settings \u2192 Advanced."
@@ -2989,7 +3057,7 @@ async function createThread(input, _onSetupLine) {
2989
3057
  let sourceIsFork = false;
2990
3058
  if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
2991
3059
  if (isAbleTimeConnected() && getIssueSource() === "abletime") {
2992
- const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-KWOBUL46.js");
3060
+ const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-ICW6Q2AB.js");
2993
3061
  const task = await ensureAbleTimeTask({
2994
3062
  title: title?.trim() || "Untitled work",
2995
3063
  description: input.prompt?.trim() || void 0
@@ -3100,7 +3168,7 @@ async function createThread(input, _onSetupLine) {
3100
3168
  return readThread(thread.id) ?? thread;
3101
3169
  }
3102
3170
  async function listLinearIssues(agent, repoPath) {
3103
- const { getAdapter: getAdapter2 } = await import("./agents-2AR7I6B6.js");
3171
+ const { getAdapter: getAdapter2 } = await import("./agents-F2E2HACB.js");
3104
3172
  await requireAgent(agent, { requireLinear: true });
3105
3173
  const adapter = getAdapter2(agent);
3106
3174
  if (!adapter.listLinearIssues) {
@@ -3760,17 +3828,23 @@ async function isolateQuotaFailover(run) {
3760
3828
  }
3761
3829
  }
3762
3830
  function createQuotaFailoverChat(from, fallbackAgent, limitText, opts) {
3831
+ const ephemeralAutomationId = from.ephemeralAutomationId?.trim();
3832
+ const ephemeralTitle = ephemeralAutomationId ? from.title.trim() : "";
3763
3833
  const handoff = buildQuotaHandoffAttachment(from, limitText, fallbackAgent);
3764
3834
  const tab = createChatTab({
3765
3835
  fromThreadId: from.id,
3766
3836
  agent: fallbackAgent,
3767
3837
  model: null,
3768
3838
  attachments: [handoff],
3839
+ ...ephemeralTitle ? { title: ephemeralTitle } : {},
3769
3840
  ...opts && "accountId" in opts ? { accountId: opts.accountId } : {}
3770
3841
  });
3771
3842
  const patch = {
3772
3843
  quotaContinuedFromId: from.id,
3773
- sourceRef: from.sourceRef
3844
+ sourceRef: from.sourceRef,
3845
+ // The original drain archives as idle. This sibling has to carry the one-off
3846
+ // so it archives when the continued turn finishes and History keeps it.
3847
+ ...ephemeralAutomationId ? { ephemeralAutomationId } : {}
3774
3848
  };
3775
3849
  if (isOrchestratorThread(from)) {
3776
3850
  patch.parentThreadId = from.id;
@@ -3877,7 +3951,7 @@ async function adoptThread(input) {
3877
3951
  messages: input.messages ?? []
3878
3952
  });
3879
3953
  writeThread(thread);
3880
- const { addWorkspace: addWorkspace2 } = await import("./workspaces-MGKEAYNM.js");
3954
+ const { addWorkspace: addWorkspace2 } = await import("./workspaces-KWMBOTQD.js");
3881
3955
  await addWorkspace2(repoPath);
3882
3956
  const { ensureWorktreeSideboardIgnored } = await import("./worktree-exclude-RXZPTCNH.js");
3883
3957
  await ensureWorktreeSideboardIgnored(input.worktreePath);
@@ -5710,6 +5784,36 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
5710
5784
  };
5711
5785
  }
5712
5786
 
5787
+ // src/composer/agent-has-replied.ts
5788
+ function joinSteerPrompt(base, addition) {
5789
+ const next = addition.trim();
5790
+ if (!next) return base;
5791
+ const head = base.replace(/\s+$/, "");
5792
+ if (!head) return next;
5793
+ return `${head}
5794
+ ${next}`;
5795
+ }
5796
+ function trailingUnansweredUserText(messages) {
5797
+ for (let i = messages.length - 1; i >= 0; i--) {
5798
+ const message = messages[i];
5799
+ if (!message || message.origin === "continue" || message.role === "summary") continue;
5800
+ if (message.role === "agent") {
5801
+ const text3 = (message.text ?? "").trim();
5802
+ if (text3 || (message.parts?.length ?? 0) > 0) return null;
5803
+ continue;
5804
+ }
5805
+ if (message.role === "user") return message.text;
5806
+ }
5807
+ return null;
5808
+ }
5809
+ function livePartsShowAgentReply(parts) {
5810
+ for (const part of parts) {
5811
+ if (part.type === "tool") return true;
5812
+ if ((part.type === "text" || part.type === "thinking") && part.text.trim()) return true;
5813
+ }
5814
+ return false;
5815
+ }
5816
+
5713
5817
  // src/composer/consume-attachments.ts
5714
5818
  function consumeComposerAttachments(thread) {
5715
5819
  return {
@@ -5762,6 +5866,128 @@ function shiftQueuedItem(queue, queueAttachments) {
5762
5866
  };
5763
5867
  }
5764
5868
 
5869
+ // src/orchestrator/enqueue-thread-send.ts
5870
+ function resolveSendFollowUp(thread, requested) {
5871
+ if (requested === "steer" || requested === "queue") return requested;
5872
+ return isOrchestratorThread(thread) ? followUpBehavior() : "queue";
5873
+ }
5874
+ function rewriteTrailingUserPrompt(threadId, from, to) {
5875
+ if (from === to) return;
5876
+ const thread = readThread(threadId);
5877
+ if (!thread) return;
5878
+ const messages = thread.messages.slice();
5879
+ for (let i = messages.length - 1; i >= 0; i--) {
5880
+ const message = messages[i];
5881
+ if (!message || message.origin === "continue" || message.role === "summary") continue;
5882
+ if (message.role === "user" && message.text === from) {
5883
+ messages[i] = { ...message, text: to };
5884
+ updateThread(threadId, { messages });
5885
+ }
5886
+ return;
5887
+ }
5888
+ }
5889
+ function reuseJoinedUserBubble(reused, threadId, last, promptText) {
5890
+ return reused.delete(threadId) && last?.role === "user" && last.origin !== "continue" && last.text === promptText;
5891
+ }
5892
+ function promptForJoinedSteer(input) {
5893
+ if (input.latestPrompt === input.promptText) return input.agentPrompt;
5894
+ rewriteTrailingUserPrompt(input.threadId, input.promptText, input.latestPrompt);
5895
+ const { agentPrompt: expandedLatest } = expandComposerPrompt(
5896
+ input.worktreePath,
5897
+ expandCanonicalGitRequest(input.latestPrompt),
5898
+ { attachments: input.attachments }
5899
+ );
5900
+ return input.expandedPrompt && input.agentPrompt.endsWith(input.expandedPrompt) ? input.agentPrompt.slice(0, -input.expandedPrompt.length) + expandedLatest : `${input.agentPrompt}
5901
+
5902
+ ${expandedLatest}`;
5903
+ }
5904
+ function clearSendBookkeeping(host, threadId) {
5905
+ host.crashContinued.delete(threadId);
5906
+ host.jobContinueCount.delete(threadId);
5907
+ host.jobContinueNudged.delete(threadId);
5908
+ host.haltDrain.delete(threadId);
5909
+ }
5910
+ async function enqueueThreadSend(host, threadRef, prompt, opts) {
5911
+ const thread = host.requireThread(threadRef);
5912
+ if (thread.status === "archived") {
5913
+ throw new Error(`Thread is archived: ${thread.id}`);
5914
+ }
5915
+ let shouldSteer = false;
5916
+ const sent = await withThreadLock(thread.id, async () => {
5917
+ const current = host.requireThread(thread.id);
5918
+ if (current.status === "archived") {
5919
+ throw new Error(`Thread is archived: ${thread.id}`);
5920
+ }
5921
+ const followUp = resolveSendFollowUp(current, opts?.followUp);
5922
+ const explicit = opts?.attachments;
5923
+ const consumed = explicit !== void 0 ? { attachments: current.attachments, consumed: explicit } : consumeComposerAttachments(current);
5924
+ const inFlightEarly = host.activeTurns.has(thread.id) || host.startingTurns.has(thread.id) || current.status === "running";
5925
+ const agentHasRepliedEarly = livePartsShowAgentReply(readTurnLiveParts(current.id));
5926
+ const draft = host.openSteerPrompt.get(current.id);
5927
+ const queuedHead = !inFlightEarly && current.status === "queued" && current.queue.length > 0 ? current.queue[0] : null;
5928
+ const unanswered = followUp === "steer" && !agentHasRepliedEarly ? draft?.text ?? (inFlightEarly ? trailingUnansweredUserText(current.messages) : queuedHead) : null;
5929
+ if (unanswered != null && (draft ? !draft.spawned : queuedHead != null)) {
5930
+ clearSendBookkeeping(host, thread.id);
5931
+ const combined = joinSteerPrompt(unanswered, prompt);
5932
+ if (draft && !draft.spawned) {
5933
+ draft.text = combined;
5934
+ rewriteTrailingUserPrompt(current.id, unanswered, combined);
5935
+ } else {
5936
+ const queue = current.queue.slice();
5937
+ queue[0] = combined;
5938
+ const queueAttachments = alignQueueAttachments(queue.length, current.queueAttachments);
5939
+ if (consumed.consumed.length > 0) {
5940
+ queueAttachments[0] = [...queueAttachments[0] ?? [], ...consumed.consumed];
5941
+ }
5942
+ const patch2 = { queue, queueAttachments };
5943
+ if (explicit === void 0 && consumed.consumed.length > 0) {
5944
+ patch2.attachments = consumed.attachments;
5945
+ }
5946
+ updateThread(current.id, patch2);
5947
+ host.emit({ type: "queue_changed", threadId: current.id, queue });
5948
+ }
5949
+ if (thisProcessShouldDrainAgentQueues() && !inFlightEarly) {
5950
+ host.armDrain(current.id);
5951
+ }
5952
+ return host.requireThread(current.id);
5953
+ }
5954
+ const promptToQueue = unanswered != null ? joinSteerPrompt(unanswered, prompt) : prompt;
5955
+ if (unanswered != null) {
5956
+ if (draft) draft.text = promptToQueue;
5957
+ rewriteTrailingUserPrompt(current.id, unanswered, promptToQueue);
5958
+ host.reusedUserPrompt.add(current.id);
5959
+ }
5960
+ const queued = appendQueuedItem(
5961
+ current.queue,
5962
+ current.queueAttachments,
5963
+ promptToQueue,
5964
+ consumed.consumed
5965
+ );
5966
+ clearSendBookkeeping(host, thread.id);
5967
+ const inFlight = host.activeTurns.has(thread.id) || host.startingTurns.has(thread.id) || current.status === "running";
5968
+ shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
5969
+ const patch = queued;
5970
+ if (explicit === void 0 && consumed.consumed.length > 0) {
5971
+ patch.attachments = consumed.attachments;
5972
+ }
5973
+ if (!inFlight) patch.status = "queued";
5974
+ const pid = current.agentPid;
5975
+ if (typeof pid === "number" && pid > 0 && !host.pidAlive(pid)) {
5976
+ patch.agentPid = null;
5977
+ }
5978
+ updateThread(thread.id, patch);
5979
+ host.emit({ type: "queue_changed", threadId: thread.id, queue: queued.queue });
5980
+ if (!inFlight) {
5981
+ host.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
5982
+ }
5983
+ if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
5984
+ host.armDrain(thread.id);
5985
+ }
5986
+ return host.requireThread(thread.id);
5987
+ });
5988
+ return { thread: sent, shouldSteer };
5989
+ }
5990
+
5765
5991
  // src/agents/instructions.ts
5766
5992
  import { existsSync as existsSync12 } from "fs";
5767
5993
  import { join as join12 } from "path";
@@ -5920,7 +6146,7 @@ function formatWorktreeDirective(thread, opts) {
5920
6146
  lines.push(formatDevAccessHint(opts?.activeRuns));
5921
6147
  lines.push("");
5922
6148
  lines.push(
5923
- "Schedules: `create_schedule` / `list_schedules` (`at` / `every` / `cron`). `chatId=self` continues this chat; omit chatId for a new Global chat. Fires only while Sideboard.app is running. A future job turns on Settings \u2192 Advanced \u2192 Caffeinate while schedules are enabled."
6149
+ "Automations (sidebar, after Board): `create_schedule` / `list_schedules` (`at` / `every` / `cron`). `chatId=self` continues this chat; omit chatId for a new Global chat. Fires only while Sideboard.app is running. A future job turns on Settings \u2192 Advanced \u2192 Caffeinate while automations are enabled."
5924
6150
  );
5925
6151
  lines.push(
5926
6152
  "`set_workspace_tags` labels this checkout (omit ref; replace, add, or remove). Not another checkout."
@@ -5940,7 +6166,7 @@ function connectedOrchestratorTurnReminder(thread, find) {
5940
6166
  return formatConnectedOrchestratorReminder(connectedOrchestrator(thread, find));
5941
6167
  }
5942
6168
  function formatWorktreeReminder() {
5943
- return "Sideboard workspace: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout. If a goal is given (Greptile 5/5, CI green), watch-fix-push until it lands \u2014 do not watch after every push. Schedules: create_schedule (at / every / cron; chatId=self for this chat). set_workspace_tags updates labels on this workspace (omit ref).";
6169
+ return "Sideboard workspace: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout. If a goal is given (Greptile 5/5, CI green), watch-fix-push until it lands \u2014 do not watch after every push. Automations: create_schedule (at / every / cron; chatId=self for this chat). set_workspace_tags updates labels on this workspace (omit ref).";
5944
6170
  }
5945
6171
  function formatClaudeSubagentReminder() {
5946
6172
  return 'Claude subagents: if Task/Agent workers will edit files, write a short plan in this chat and continue in the same turn. Do not ask the user whether to isolate, and do not set worktree.bgIsolation to none. One writer may edit this workspace. Every other writer is an Agent with isolation "worktree" and a disjoint file list (read-only explore agents may overlap). While those agents run, leave their files alone. Merge each returned branch into this workspace, then remove the temporary worktree. You stay in this cwd. If Claude says another write-capable agent is in this directory, or that writes to the shared checkout are blocked, re-spawn that agent with isolation "worktree" or make the edit yourself. That note is another worker in this chat, or a worker Claude still has marked running. Do not mention it to the user.';
@@ -6580,7 +6806,7 @@ function parseDurationMs(every) {
6580
6806
  }
6581
6807
  function defaultScheduleName(prompt) {
6582
6808
  const line = prompt.trim().split(/\r?\n/, 1)[0]?.trim() ?? "";
6583
- if (!line) return "Untitled schedule";
6809
+ if (!line) return "Untitled automation";
6584
6810
  return line.length > 60 ? `${line.slice(0, 57).trimEnd()}\u2026` : line;
6585
6811
  }
6586
6812
  function resolveScheduleThreadId(raw, env = process.env) {
@@ -6651,6 +6877,45 @@ function normalizeWhen(raw) {
6651
6877
  }
6652
6878
  throw new Error("Schedule `when` must be once, every, or cron");
6653
6879
  }
6880
+ var ATTACHMENT_KINDS = /* @__PURE__ */ new Set([
6881
+ "transcript",
6882
+ "file",
6883
+ "issue",
6884
+ "workspace",
6885
+ "diff-comment",
6886
+ "code-ref"
6887
+ ]);
6888
+ function normalizeOptionalBool(raw) {
6889
+ if (raw === true || raw === false) return raw;
6890
+ return null;
6891
+ }
6892
+ function normalizeAutonomy(raw) {
6893
+ return raw === "default" || raw === "full" ? raw : null;
6894
+ }
6895
+ function normalizeAttachments(raw) {
6896
+ if (!Array.isArray(raw)) return [];
6897
+ const out = [];
6898
+ for (const item of raw) {
6899
+ if (!item || typeof item !== "object") continue;
6900
+ const row = item;
6901
+ if (typeof row.id !== "string" || !row.id.trim()) continue;
6902
+ if (typeof row.name !== "string" || !row.name) continue;
6903
+ if (typeof row.content !== "string") continue;
6904
+ if (!ATTACHMENT_KINDS.has(row.kind)) continue;
6905
+ const next = {
6906
+ id: row.id,
6907
+ name: row.name,
6908
+ kind: row.kind,
6909
+ content: row.content
6910
+ };
6911
+ if (typeof row.path === "string" && row.path) next.path = row.path;
6912
+ if (typeof row.previewDataUrl === "string" && row.previewDataUrl) {
6913
+ next.previewDataUrl = row.previewDataUrl;
6914
+ }
6915
+ out.push(next);
6916
+ }
6917
+ return out;
6918
+ }
6654
6919
  function normalizeTask(raw) {
6655
6920
  const when = normalizeWhen(raw.when);
6656
6921
  const agent = raw.agent && isOrchestratorCapableAgent(raw.agent) ? raw.agent : null;
@@ -6663,6 +6928,11 @@ function normalizeTask(raw) {
6663
6928
  threadId: raw.threadId?.trim() || null,
6664
6929
  agent,
6665
6930
  model: raw.model?.trim() || null,
6931
+ effort: normalizeThinkingEffort(raw.effort),
6932
+ fast: normalizeOptionalBool(raw.fast),
6933
+ planMode: normalizeOptionalBool(raw.planMode),
6934
+ autonomy: normalizeAutonomy(raw.autonomy),
6935
+ attachments: normalizeAttachments(raw.attachments),
6666
6936
  nextRunAt: raw.nextRunAt,
6667
6937
  lastRunAt: raw.lastRunAt ?? null,
6668
6938
  lastThreadId: raw.lastThreadId ?? null,
@@ -6709,6 +6979,11 @@ function buildTask(input, now) {
6709
6979
  threadId: input.threadId?.trim() || null,
6710
6980
  agent,
6711
6981
  model: input.model?.trim() || null,
6982
+ effort: input.effort != null ? normalizeThinkingEffort(input.effort) : null,
6983
+ fast: normalizeOptionalBool(input.fast),
6984
+ planMode: normalizeOptionalBool(input.planMode),
6985
+ autonomy: normalizeAutonomy(input.autonomy),
6986
+ attachments: normalizeAttachments(input.attachments),
6712
6987
  nextRunAt,
6713
6988
  lastRunAt: null,
6714
6989
  lastThreadId: null,
@@ -6753,7 +7028,7 @@ function createSchedule(input) {
6753
7028
  function updateSchedule(id, patch) {
6754
7029
  const rows = readAll();
6755
7030
  const idx = rows.findIndex((row) => row.id === id || id.length >= 8 && row.id.startsWith(id));
6756
- if (idx < 0) throw new Error(`Schedule not found: ${id}`);
7031
+ if (idx < 0) throw new Error(`Automation not found: ${id}`);
6757
7032
  const prev = rows[idx];
6758
7033
  const when = patch.when ? normalizeWhen(patch.when) : prev.when;
6759
7034
  const prompt = patch.prompt !== void 0 ? patch.prompt.trim() : prev.prompt;
@@ -6768,6 +7043,11 @@ function updateSchedule(id, patch) {
6768
7043
  threadId: patch.threadId !== void 0 ? patch.threadId?.trim() || null : prev.threadId,
6769
7044
  agent: patch.agent !== void 0 ? patch.agent ? coerceOrchestratorAgent(patch.agent) : null : prev.agent,
6770
7045
  model: patch.model !== void 0 ? patch.model?.trim() || null : prev.model,
7046
+ effort: patch.effort !== void 0 ? normalizeThinkingEffort(patch.effort) : prev.effort,
7047
+ fast: patch.fast !== void 0 ? normalizeOptionalBool(patch.fast) : prev.fast,
7048
+ planMode: patch.planMode !== void 0 ? normalizeOptionalBool(patch.planMode) : prev.planMode,
7049
+ autonomy: patch.autonomy !== void 0 ? normalizeAutonomy(patch.autonomy) : prev.autonomy,
7050
+ attachments: patch.attachments !== void 0 ? normalizeAttachments(patch.attachments) : prev.attachments,
6771
7051
  nextRunAt: whenChanged ? computeNextRunAt(when).toISOString() : prev.nextRunAt,
6772
7052
  lastError: whenChanged ? null : prev.lastError,
6773
7053
  updatedAt: nowIso()
@@ -6782,13 +7062,13 @@ function deleteSchedule(id) {
6782
7062
  const next = rows.filter(
6783
7063
  (row) => row.id !== id && !(id.length >= 8 && row.id.startsWith(id))
6784
7064
  );
6785
- if (next.length === rows.length) throw new Error(`Schedule not found: ${id}`);
7065
+ if (next.length === rows.length) throw new Error(`Automation not found: ${id}`);
6786
7066
  writeAll(next);
6787
7067
  }
6788
7068
  function recordScheduleRun(id, result) {
6789
7069
  const rows = readAll();
6790
7070
  const idx = rows.findIndex((row) => row.id === id);
6791
- if (idx < 0) throw new Error(`Schedule not found: ${id}`);
7071
+ if (idx < 0) throw new Error(`Automation not found: ${id}`);
6792
7072
  const prev = rows[idx];
6793
7073
  const firedAt = result.firedAt ?? /* @__PURE__ */ new Date();
6794
7074
  const next = {
@@ -6815,21 +7095,56 @@ function formatScheduledPrompt(name, prompt) {
6815
7095
  ${prompt}`;
6816
7096
  }
6817
7097
  async function defaultDeps() {
6818
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-2SXK4U65.js");
7098
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-NPFWU3XU.js");
6819
7099
  const orch = getOrchestrator2();
6820
7100
  return {
6821
7101
  findThread: (id) => findThreadByRef(id),
6822
- send: (id, prompt) => orch.send(id, prompt),
7102
+ send: async (id, prompt, opts) => {
7103
+ if (opts?.options && Object.keys(opts.options).length > 0) {
7104
+ try {
7105
+ orch.setThreadOptions(id, opts.options);
7106
+ } catch {
7107
+ const rest = scheduleOptionsAfterRefusedAgentSwitch(opts.options);
7108
+ if (Object.keys(rest).length > 0) {
7109
+ try {
7110
+ orch.setThreadOptions(id, rest);
7111
+ } catch {
7112
+ }
7113
+ }
7114
+ }
7115
+ }
7116
+ const thread = findThreadByRef(id);
7117
+ const attachments = thread ? persistPendingFileAttachments(thread.worktreePath, opts?.attachments ?? []) : opts?.attachments ?? [];
7118
+ return orch.send(id, prompt, { attachments });
7119
+ },
6823
7120
  startOrchestration: (opts) => startOrchestration2(opts)
6824
7121
  };
6825
7122
  }
7123
+ function scheduleOptionsAfterRefusedAgentSwitch(options) {
7124
+ const { agent: _agent, model: _model, ...rest } = options;
7125
+ return rest;
7126
+ }
7127
+ function scheduleSendOptions(schedule) {
7128
+ const patch = {};
7129
+ if (schedule.agent) {
7130
+ patch.agent = schedule.agent;
7131
+ patch.model = schedule.model;
7132
+ } else if (schedule.model) {
7133
+ patch.model = schedule.model;
7134
+ }
7135
+ if (schedule.effort) patch.effort = schedule.effort;
7136
+ if (schedule.fast != null) patch.fast = schedule.fast;
7137
+ if (schedule.planMode != null) patch.planMode = schedule.planMode;
7138
+ if (schedule.autonomy) patch.autonomy = schedule.autonomy;
7139
+ return Object.keys(patch).length > 0 ? patch : void 0;
7140
+ }
6826
7141
  function pickAgent(schedule) {
6827
7142
  if (schedule.agent) return schedule.agent;
6828
7143
  return coerceOrchestratorAgent(resolveOrchestratorDefaults().agent);
6829
7144
  }
6830
7145
  async function fireSchedule(id) {
6831
7146
  const schedule = getSchedule(id);
6832
- if (!schedule) throw new Error(`Schedule not found: ${id}`);
7147
+ if (!schedule) throw new Error(`Automation not found: ${id}`);
6833
7148
  if (firing.has(schedule.id)) return schedule;
6834
7149
  firing.add(schedule.id);
6835
7150
  try {
@@ -6837,18 +7152,28 @@ async function fireSchedule(id) {
6837
7152
  const prompt = formatScheduledPrompt(schedule.name, schedule.prompt);
6838
7153
  const target = schedule.threadId ? deps.findThread(schedule.threadId) : null;
6839
7154
  if (target && target.status !== "archived") {
6840
- const sent = await deps.send(target.id, prompt);
7155
+ const sent = await deps.send(target.id, prompt, {
7156
+ attachments: schedule.attachments,
7157
+ options: scheduleSendOptions(schedule)
7158
+ });
6841
7159
  return recordScheduleRun(schedule.id, {
6842
7160
  lastThreadId: sent.id,
6843
7161
  lastError: null
6844
7162
  });
6845
7163
  }
7164
+ const pinReplacement = Boolean(schedule.threadId) && schedule.when.kind !== "once";
6846
7165
  const created = await deps.startOrchestration({
6847
7166
  goal: prompt,
6848
7167
  agent: pickAgent(schedule),
6849
- model: schedule.model
7168
+ model: schedule.model,
7169
+ ...schedule.effort ? { effort: schedule.effort } : {},
7170
+ ...schedule.fast != null ? { fast: schedule.fast } : {},
7171
+ ...schedule.planMode != null ? { planMode: schedule.planMode } : {},
7172
+ ...schedule.autonomy ? { autonomy: schedule.autonomy } : {},
7173
+ attachments: schedule.attachments,
7174
+ ...pinReplacement ? {} : { ephemeralAutomationId: schedule.id, ephemeralTitle: schedule.name }
6850
7175
  });
6851
- if (schedule.threadId && schedule.when.kind !== "once") {
7176
+ if (pinReplacement) {
6852
7177
  updateSchedule(schedule.id, { threadId: created.id });
6853
7178
  }
6854
7179
  return recordScheduleRun(schedule.id, {
@@ -6931,10 +7256,6 @@ async function waitForPidExit(pid, timeoutMs) {
6931
7256
  }
6932
7257
  return true;
6933
7258
  }
6934
- function resolveSendFollowUp(thread, requested) {
6935
- if (requested === "steer" || requested === "queue") return requested;
6936
- return isOrchestratorThread(thread) ? followUpBehavior() : "queue";
6937
- }
6938
7259
  function resolveOrchChildFollowUp(requested) {
6939
7260
  if (requested === "steer" || requested === "queue") return requested;
6940
7261
  return followUpBehavior();
@@ -6963,6 +7284,13 @@ var Orchestrator = class {
6963
7284
  draining = /* @__PURE__ */ new Set();
6964
7285
  /** Threads past setStatus(running) but not yet in activeTurns (spawn in flight). */
6965
7286
  startingTurns = /* @__PURE__ */ new Set();
7287
+ /**
7288
+ * Prompt for the turn that has not been answered yet. Steer follow-ups before
7289
+ * any agent output are joined onto this text instead of starting a second bubble.
7290
+ */
7291
+ openSteerPrompt = /* @__PURE__ */ new Map();
7292
+ /** Next runTurn should keep the user bubble already rewritten to this prompt. */
7293
+ reusedUserPrompt = /* @__PURE__ */ new Set();
6966
7294
  /** Last sync thread-file read for false-stop heal (throttled per thread). */
6967
7295
  lastReconcileHealAt = /* @__PURE__ */ new Map();
6968
7296
  /** Per-repo timestamp of the last `reconcile(repo, { light: true })`. */
@@ -7133,7 +7461,7 @@ var Orchestrator = class {
7133
7461
  orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
7134
7462
  });
7135
7463
  }
7136
- const { autoCleanupOrphansEnabled } = await import("./app-settings-V6YPYY57.js");
7464
+ const { autoCleanupOrphansEnabled } = await import("./app-settings-P3H4SEIK.js");
7137
7465
  if (autoCleanupOrphansEnabled() && shouldRunWorktreeCleanup() && orphans.length > 0) {
7138
7466
  await cleanupOrphanWorktrees({ repoPaths });
7139
7467
  }
@@ -7527,7 +7855,7 @@ var Orchestrator = class {
7527
7855
  }
7528
7856
  await setup;
7529
7857
  if (skipSetup) return;
7530
- const { autoRunAfterSetupEnabled } = await import("./app-settings-V6YPYY57.js");
7858
+ const { autoRunAfterSetupEnabled } = await import("./app-settings-P3H4SEIK.js");
7531
7859
  if (autoRunAfterSetupEnabled()) {
7532
7860
  try {
7533
7861
  await this.startDev(threadId);
@@ -7573,54 +7901,29 @@ var Orchestrator = class {
7573
7901
  return thread;
7574
7902
  }
7575
7903
  async send(threadRef, prompt, opts) {
7576
- const thread = this.requireThread(threadRef);
7577
- if (thread.status === "archived") {
7578
- throw new Error(`Thread is archived: ${thread.id}`);
7579
- }
7580
- let shouldSteer = false;
7581
- const sent = await withThreadLock(thread.id, async () => {
7582
- const current = this.requireThread(thread.id);
7583
- if (current.status === "archived") {
7584
- throw new Error(`Thread is archived: ${thread.id}`);
7585
- }
7586
- const followUp = resolveSendFollowUp(current, opts?.followUp);
7587
- const explicit = opts?.attachments;
7588
- const consumed = explicit !== void 0 ? { attachments: current.attachments, consumed: explicit } : consumeComposerAttachments(current);
7589
- const queued = appendQueuedItem(
7590
- current.queue,
7591
- current.queueAttachments,
7592
- prompt,
7593
- consumed.consumed
7594
- );
7595
- this.crashContinued.delete(thread.id);
7596
- this.jobContinueCount.delete(thread.id);
7597
- this.jobContinueNudged.delete(thread.id);
7598
- this.haltDrain.delete(thread.id);
7599
- const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
7600
- shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
7601
- const patch = queued;
7602
- if (explicit === void 0 && consumed.consumed.length > 0) {
7603
- patch.attachments = consumed.attachments;
7604
- }
7605
- if (!inFlight) patch.status = "queued";
7606
- const pid = current.agentPid;
7607
- if (typeof pid === "number" && pid > 0 && !isPidAlive(pid)) {
7608
- patch.agentPid = null;
7609
- }
7610
- updateThread(thread.id, patch);
7611
- this.emit({ type: "queue_changed", threadId: thread.id, queue: queued.queue });
7612
- if (!inFlight) {
7613
- this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
7614
- }
7615
- if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
7616
- this.armDrain(thread.id);
7617
- }
7618
- return this.requireThread(thread.id);
7619
- });
7620
- if (shouldSteer && sent.queue.length > 0) {
7621
- return this.sendQueuedMessageNow(sent.id, sent.queue.length - 1);
7904
+ const sent = await enqueueThreadSend(
7905
+ {
7906
+ activeTurns: this.activeTurns,
7907
+ startingTurns: this.startingTurns,
7908
+ openSteerPrompt: this.openSteerPrompt,
7909
+ reusedUserPrompt: this.reusedUserPrompt,
7910
+ crashContinued: this.crashContinued,
7911
+ jobContinueCount: this.jobContinueCount,
7912
+ jobContinueNudged: this.jobContinueNudged,
7913
+ haltDrain: this.haltDrain,
7914
+ emit: (event) => this.emit(event),
7915
+ armDrain: (id) => this.armDrain(id),
7916
+ requireThread: (ref) => this.requireThread(ref),
7917
+ pidAlive: (pid) => isPidAlive(pid)
7918
+ },
7919
+ threadRef,
7920
+ prompt,
7921
+ opts
7922
+ );
7923
+ if (sent.shouldSteer && sent.thread.queue.length > 0) {
7924
+ return this.sendQueuedMessageNow(sent.thread.id, sent.thread.queue.length - 1);
7622
7925
  }
7623
- return sent;
7926
+ return sent.thread;
7624
7927
  }
7625
7928
  async fanOut(threadRefs, prompt, opts) {
7626
7929
  const results = [];
@@ -7761,6 +8064,7 @@ var Orchestrator = class {
7761
8064
  } finally {
7762
8065
  this.draining.delete(threadId);
7763
8066
  }
8067
+ await archiveEphemeralAutomationIfReady(threadId, (id) => this.archive(id));
7764
8068
  }
7765
8069
  async runTurn(threadId, prompt) {
7766
8070
  const existing = readThread(threadId);
@@ -7777,6 +8081,10 @@ var Orchestrator = class {
7777
8081
  this.emit({ type: "status_changed", threadId, status: "running" });
7778
8082
  this.emit({ type: "turn_started", threadId, prompt });
7779
8083
  try {
8084
+ this.openSteerPrompt.set(threadId, {
8085
+ text: typeof prompt === "string" ? prompt : "",
8086
+ spawned: false
8087
+ });
7780
8088
  try {
7781
8089
  const baseline = await captureTurnBaseline(thread.worktreePath);
7782
8090
  if (baseline) this.turnBaselines.set(threadId, baseline);
@@ -7802,18 +8110,21 @@ var Orchestrator = class {
7802
8110
  this.emit({ type: "error", threadId, message: `context compact failed: ${message}` });
7803
8111
  thread = this.requireThread(threadId);
7804
8112
  }
7805
- const promptText = typeof prompt === "string" ? prompt : "";
8113
+ const promptText = this.openSteerPrompt.get(threadId)?.text ?? (typeof prompt === "string" ? prompt : "");
7806
8114
  const autoContinue = isJobContinuePrompt(promptText) || promptText.startsWith("The previous agent process ended before it finished.");
7807
8115
  const parked = takePendingTurnAttachments(thread);
7808
8116
  const sentAttachments = !autoContinue && parked.length > 0 ? parked : void 0;
7809
8117
  if (!autoContinue) clearAgentBlock(threadId);
7810
- appendMessage(threadId, {
7811
- role: "user",
7812
- text: promptText,
7813
- ...sentAttachments ? { attachments: sentAttachments } : {},
7814
- ...autoContinue ? { origin: "continue" } : {},
7815
- ts: (/* @__PURE__ */ new Date()).toISOString()
7816
- });
8118
+ const lastShown = this.requireThread(threadId).messages.at(-1);
8119
+ if (!reuseJoinedUserBubble(this.reusedUserPrompt, threadId, lastShown, promptText)) {
8120
+ appendMessage(threadId, {
8121
+ role: "user",
8122
+ text: promptText,
8123
+ ...sentAttachments ? { attachments: sentAttachments } : {},
8124
+ ...autoContinue ? { origin: "continue" } : {},
8125
+ ts: (/* @__PURE__ */ new Date()).toISOString()
8126
+ });
8127
+ }
7817
8128
  if (!autoContinue) {
7818
8129
  const live = this.requireThread(threadId);
7819
8130
  const stamp = agentPurposeStamp({
@@ -7921,7 +8232,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
7921
8232
  }
7922
8233
  const isBrightsy = fresh.agent === "brightsy";
7923
8234
  const isOrchestration = isOrchestratorThread(fresh);
7924
- const { autoRenameBranchEnabled, getGithubGitAuthMode, gitBranchPrefixSetting } = await import("./app-settings-V6YPYY57.js");
8235
+ const { autoRenameBranchEnabled, getGithubGitAuthMode, gitBranchPrefixSetting } = await import("./app-settings-P3H4SEIK.js");
7925
8236
  const gitAuthMode = getGithubGitAuthMode();
7926
8237
  const worktreeDirective = isBrightsy || isOrchestration ? null : formatWorktreeDirective(fresh, {
7927
8238
  githubSlug: await withTimeout(
@@ -8012,11 +8323,22 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
8012
8323
  ].filter(Boolean).join("\n\n---\n\n");
8013
8324
  const stderrTail = [];
8014
8325
  traceTurn("runTurn.beforeSpawn", { threadId, agent: fresh.agent });
8326
+ const steerDraft = this.openSteerPrompt.get(threadId);
8327
+ if (steerDraft) steerDraft.spawned = true;
8328
+ const promptForAgent = promptForJoinedSteer({
8329
+ threadId,
8330
+ promptText,
8331
+ latestPrompt: steerDraft?.text ?? promptText,
8332
+ agentPrompt,
8333
+ expandedPrompt,
8334
+ worktreePath: fresh.worktreePath,
8335
+ attachments: autoContinue ? [] : sentAttachments ?? []
8336
+ });
8015
8337
  const handle = await spawnAgentTurn(
8016
8338
  fresh,
8017
8339
  {
8018
8340
  cachedPrefix,
8019
- prompt: agentPrompt,
8341
+ prompt: promptForAgent,
8020
8342
  systemPrompt: turnReminders,
8021
8343
  isolateCodexPlugins: fresh.isolateCodexPlugins === true
8022
8344
  },
@@ -8144,7 +8466,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
8144
8466
  retryThread,
8145
8467
  {
8146
8468
  cachedPrefix: retryPrefix,
8147
- prompt: agentPrompt,
8469
+ prompt: promptForAgent,
8148
8470
  systemPrompt: turnReminders,
8149
8471
  isolateCodexPlugins: isolateCodexPluginRetry || retryThread.isolateCodexPlugins === true
8150
8472
  },
@@ -8304,6 +8626,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
8304
8626
  } finally {
8305
8627
  this.startingTurns.delete(threadId);
8306
8628
  this.activeTurns.delete(threadId);
8629
+ this.openSteerPrompt.delete(threadId);
8307
8630
  this.processes.delete(`${threadId}:agent`);
8308
8631
  this.stoppedTurns.delete(threadId);
8309
8632
  this.runningCount = Math.max(0, this.runningCount - 1);
@@ -9237,7 +9560,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
9237
9560
  if (Object.keys(patch).length === 0) continue;
9238
9561
  updateThread(t.id, patch);
9239
9562
  }
9240
- const { autoArchiveOnMergeEnabled } = await import("./app-settings-V6YPYY57.js");
9563
+ const { autoArchiveOnMergeEnabled } = await import("./app-settings-P3H4SEIK.js");
9241
9564
  const latest = this.requireThread(thread.id);
9242
9565
  if (!shouldAutoArchiveOnPrMerge({
9243
9566
  previousPrState: prevState || null,
@@ -9561,7 +9884,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
9561
9884
  await runArchiveScript(thread.repoPath, thread.worktreePath);
9562
9885
  } catch {
9563
9886
  }
9564
- const { deleteBranchOnPurgeEnabled } = await import("./app-settings-V6YPYY57.js");
9887
+ const { deleteBranchOnPurgeEnabled } = await import("./app-settings-P3H4SEIK.js");
9565
9888
  const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled();
9566
9889
  await removeWorktree(thread.repoPath, thread.worktreePath, {
9567
9890
  deleteBranch: deleteBranch ? thread.branchName : void 0
@@ -9575,6 +9898,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
9575
9898
  if (thread.status !== "archived") {
9576
9899
  throw new Error("Thread is not archived");
9577
9900
  }
9901
+ clearEphemeralAutomation(thread.id);
9578
9902
  if (isGlobalThread(thread)) {
9579
9903
  const { globalAgentCwd } = await import("./paths-PHWEVXD5.js");
9580
9904
  updateThread(thread.id, { worktreePath: globalAgentCwd() });
@@ -9674,10 +9998,11 @@ async function startOrchestration(opts) {
9674
9998
  planMode: opts.planMode,
9675
9999
  attachments: opts.attachments
9676
10000
  });
10001
+ const ready2 = markEphemeralAutomation(thread2.id, opts);
9677
10002
  if (goal) {
9678
- return orch.send(thread2.id, goal);
10003
+ return orch.send(ready2.id, goal);
9679
10004
  }
9680
- return thread2;
10005
+ return ready2;
9681
10006
  }
9682
10007
  const { titleFromPrompt: titleFromPrompt2 } = await import("./title-Z7WAJN57.js");
9683
10008
  const title = titleFromPrompt2(goal) || "Orchestration";
@@ -9697,7 +10022,7 @@ async function startOrchestration(opts) {
9697
10022
  sourceRef: "default",
9698
10023
  ...createOpts
9699
10024
  }).catch(async () => {
9700
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-THAXW5U7.js");
10025
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-7EATHVYQ.js");
9701
10026
  const repo = await resolveRepoRoot2(repoPath);
9702
10027
  const def = await resolveDefaultBranch2(repo);
9703
10028
  return orch.createThread({
@@ -9707,15 +10032,16 @@ async function startOrchestration(opts) {
9707
10032
  repoPath: repo
9708
10033
  });
9709
10034
  });
9710
- const { updateThread: upd } = await import("./thread-store-7BBA63KV.js");
10035
+ const { updateThread: upd } = await import("./thread-store-QHYN2ZMQ.js");
9711
10036
  const updated = upd(thread.id, {
9712
10037
  sourceType: "orchestration",
9713
10038
  sourceRef: goal
9714
10039
  });
10040
+ const ready = markEphemeralAutomation(updated.id, opts);
9715
10041
  if (goal) {
9716
- return orch.send(updated.id, goal);
10042
+ return orch.send(ready.id, goal);
9717
10043
  }
9718
- return updated;
10044
+ return ready;
9719
10045
  }
9720
10046
 
9721
10047
  export {
@@ -9867,6 +10193,9 @@ export {
9867
10193
  discoverSkills,
9868
10194
  readSkillBody,
9869
10195
  expandComposerPrompt,
10196
+ joinSteerPrompt,
10197
+ trailingUnansweredUserText,
10198
+ livePartsShowAgentReply,
9870
10199
  consumeComposerAttachments,
9871
10200
  takePendingTurnAttachments,
9872
10201
  alignQueueAttachments,
@@ -9875,6 +10204,7 @@ export {
9875
10204
  removeQueuedItem,
9876
10205
  moveQueuedItemToFront,
9877
10206
  shiftQueuedItem,
10207
+ resolveSendFollowUp,
9878
10208
  packagedDetachedJobPath,
9879
10209
  resolveDetachedJobScript,
9880
10210
  formatDetachedJobInvoke,
@@ -9914,7 +10244,6 @@ export {
9914
10244
  RUN_SCRIPT_DESKTOP_ADOPT_MS,
9915
10245
  isPidAlive,
9916
10246
  waitForPidExit,
9917
- resolveSendFollowUp,
9918
10247
  resolveOrchChildFollowUp,
9919
10248
  LIGHT_RECONCILE_THROTTLE_MS,
9920
10249
  Orchestrator,