@sideboard-ai/core 0.1.318 → 0.1.319

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.
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  ableTimeDependencyTarget,
3
+ ableTimeStateIsClosed,
3
4
  commentAbleTimeTask,
4
5
  createAbleTimeTask,
5
6
  downloadAbleTimeAttachment,
@@ -16,9 +17,9 @@ import {
16
17
  toAbleTimeIssueInfo,
17
18
  updateAbleTimeTask,
18
19
  verifyAbleTimeConnection
19
- } from "./chunk-W5QZWAUB.js";
20
- import "./chunk-2HOZMSKQ.js";
21
- import "./chunk-7ADEYEMH.js";
20
+ } from "./chunk-WLZHRNE6.js";
21
+ import "./chunk-AUJ4XB6H.js";
22
+ import "./chunk-LXBZQP2Q.js";
22
23
  import "./chunk-JAT3JFOS.js";
23
24
  import "./chunk-6K64FJDD.js";
24
25
  import "./chunk-E52SQENB.js";
@@ -30,6 +31,7 @@ import "./chunk-JT7R45JB.js";
30
31
  import "./chunk-H4UEFJRI.js";
31
32
  export {
32
33
  ableTimeDependencyTarget,
34
+ ableTimeStateIsClosed,
33
35
  commentAbleTimeTask,
34
36
  createAbleTimeTask,
35
37
  downloadAbleTimeAttachment,
@@ -2,6 +2,7 @@
2
2
 
3
3
  import {
4
4
  ableTimeDependencyTarget,
5
+ ableTimeStateIsClosed,
5
6
  commentAbleTimeTask,
6
7
  createAbleTimeTask,
7
8
  downloadAbleTimeAttachment,
@@ -18,9 +19,9 @@ import {
18
19
  toAbleTimeIssueInfo,
19
20
  updateAbleTimeTask,
20
21
  verifyAbleTimeConnection
21
- } from "./chunk-I5CLCWUK.js";
22
- import "./chunk-VZAJVX36.js";
23
- import "./chunk-7SCVGGF6.js";
22
+ } from "./chunk-QPLQXWND.js";
23
+ import "./chunk-JD7CC6SW.js";
24
+ import "./chunk-ZM43NTJJ.js";
24
25
  import "./chunk-2GPQZZLY.js";
25
26
  import "./chunk-N2WW62LF.js";
26
27
  import "./chunk-GCHSJCCX.js";
@@ -32,6 +33,7 @@ import "./chunk-KGZBYWZ3.js";
32
33
  import "./chunk-WOU343SI.js";
33
34
  export {
34
35
  ableTimeDependencyTarget,
36
+ ableTimeStateIsClosed,
35
37
  commentAbleTimeTask,
36
38
  createAbleTimeTask,
37
39
  downloadAbleTimeAttachment,
@@ -3,7 +3,7 @@
3
3
  import {
4
4
  DEFAULT_ABLETIME_HOST,
5
5
  normalizeAbleTimeHost
6
- } from "./chunk-7SCVGGF6.js";
6
+ } from "./chunk-ZM43NTJJ.js";
7
7
  import {
8
8
  httpFetch
9
9
  } from "./chunk-2GPQZZLY.js";
@@ -288,7 +288,7 @@ async function startAbleTimeOAuth(opts) {
288
288
  persistAbleTimeTokens(data, { host });
289
289
  const token = data.access_token.trim();
290
290
  try {
291
- const { getAbleTimeOrientation } = await import("./abletime-TKAFNXCM.js");
291
+ const { getAbleTimeOrientation } = await import("./abletime-L3ODNTBT.js");
292
292
  const orientation = await getAbleTimeOrientation({ token, host });
293
293
  return saveAbleTimeConnection({
294
294
  accessToken: token,
@@ -20,8 +20,8 @@ import {
20
20
  parseAbleTimeOAuthCallbackUrl,
21
21
  resolveAbleTimeOAuthHost,
22
22
  startAbleTimeOAuth
23
- } from "./chunk-XOZNEAWF.js";
24
- import "./chunk-7ADEYEMH.js";
23
+ } from "./chunk-5OM7UCTQ.js";
24
+ import "./chunk-LXBZQP2Q.js";
25
25
  import "./chunk-JAT3JFOS.js";
26
26
  import "./chunk-E52SQENB.js";
27
27
  import "./chunk-77WWLBCI.js";
@@ -7,8 +7,8 @@ import {
7
7
  callAbleTimeRestTool,
8
8
  looksLikeAbleTimeUlid,
9
9
  textFromAbleTimeDoc
10
- } from "./chunk-VZAJVX36.js";
11
- import "./chunk-7SCVGGF6.js";
10
+ } from "./chunk-JD7CC6SW.js";
11
+ import "./chunk-ZM43NTJJ.js";
12
12
  import "./chunk-2GPQZZLY.js";
13
13
  import "./chunk-GCHSJCCX.js";
14
14
  import "./chunk-NSTQ6QKD.js";
@@ -5,8 +5,8 @@ import {
5
5
  callAbleTimeRestTool,
6
6
  looksLikeAbleTimeUlid,
7
7
  textFromAbleTimeDoc
8
- } from "./chunk-2HOZMSKQ.js";
9
- import "./chunk-7ADEYEMH.js";
8
+ } from "./chunk-AUJ4XB6H.js";
9
+ import "./chunk-LXBZQP2Q.js";
10
10
  import "./chunk-JAT3JFOS.js";
11
11
  import "./chunk-E52SQENB.js";
12
12
  import "./chunk-77WWLBCI.js";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  DEFAULT_ABLETIME_HOST,
3
3
  normalizeAbleTimeHost
4
- } from "./chunk-7ADEYEMH.js";
4
+ } from "./chunk-LXBZQP2Q.js";
5
5
  import {
6
6
  httpFetch
7
7
  } from "./chunk-JAT3JFOS.js";
@@ -280,7 +280,7 @@ async function startAbleTimeOAuth(opts) {
280
280
  persistAbleTimeTokens(data, { host });
281
281
  const token = data.access_token.trim();
282
282
  try {
283
- const { getAbleTimeOrientation } = await import("./abletime-KWOBUL46.js");
283
+ const { getAbleTimeOrientation } = await import("./abletime-DVYO4IVS.js");
284
284
  const orientation = await getAbleTimeOrientation({ token, host });
285
285
  return saveAbleTimeConnection({
286
286
  accessToken: token,
@@ -4,7 +4,7 @@ import {
4
4
  normalizeAbleTimeCredential,
5
5
  normalizeAbleTimeHost,
6
6
  rewriteAbleTimeError
7
- } from "./chunk-7ADEYEMH.js";
7
+ } from "./chunk-LXBZQP2Q.js";
8
8
  import {
9
9
  httpFetch
10
10
  } from "./chunk-JAT3JFOS.js";
@@ -6,7 +6,7 @@ import {
6
6
  normalizeAbleTimeCredential,
7
7
  normalizeAbleTimeHost,
8
8
  rewriteAbleTimeError
9
- } from "./chunk-7SCVGGF6.js";
9
+ } from "./chunk-ZM43NTJJ.js";
10
10
  import {
11
11
  httpFetch
12
12
  } from "./chunk-2GPQZZLY.js";
@@ -153,7 +153,7 @@ function textsFromUnknown(value) {
153
153
  return "";
154
154
  }
155
155
  async function abletimeMcpRequest(method, params, opts) {
156
- const rawToken = opts?.token ?? await import("./abletime-oauth-IUIAGLFJ.js").then((m) => m.ensureAbleTimeAccessToken());
156
+ const rawToken = opts?.token ?? await import("./abletime-oauth-6DTX7LB7.js").then((m) => m.ensureAbleTimeAccessToken());
157
157
  if (!rawToken?.trim()) {
158
158
  throw new Error("AbleTime is not connected \u2014 paste a personal access token in Account settings");
159
159
  }
@@ -224,9 +224,9 @@ async function callAbleTimeTool(name, args = {}, opts) {
224
224
  if (!opts?.token && !isAbleTimeConnected()) {
225
225
  throw new Error("AbleTime is not connected \u2014 paste a personal access token in Account settings");
226
226
  }
227
- const rawToken = opts?.token ?? await import("./abletime-oauth-IUIAGLFJ.js").then((m) => m.ensureAbleTimeAccessToken());
227
+ const rawToken = opts?.token ?? await import("./abletime-oauth-6DTX7LB7.js").then((m) => m.ensureAbleTimeAccessToken());
228
228
  if (rawToken && ableTimeUsesRest(rawToken)) {
229
- const { callAbleTimeRestTool } = await import("./abletime-rest-RWN4EPY3.js");
229
+ const { callAbleTimeRestTool } = await import("./abletime-rest-PYQM234B.js");
230
230
  return callAbleTimeRestTool(name, args, { ...opts, token: rawToken });
231
231
  }
232
232
  const requestOpts = { ...opts, pm: opts?.pm ?? abletimeToolUsesPm(name) };
@@ -242,7 +242,7 @@ async function callAbleTimeTool(name, args = {}, opts) {
242
242
  return await call();
243
243
  }
244
244
  if (rawToken && ableTimeUsesRest(rawToken) && isAbleTimeRejectedCredential(message)) {
245
- const { callAbleTimeRestTool } = await import("./abletime-rest-RWN4EPY3.js");
245
+ const { callAbleTimeRestTool } = await import("./abletime-rest-PYQM234B.js");
246
246
  return callAbleTimeRestTool(name, args, { ...opts, token: rawToken });
247
247
  }
248
248
  throw err instanceof Error ? new Error(rewriteAbleTimeError(err.message)) : err;
@@ -2691,7 +2691,7 @@ async function createThread(input, _onSetupLine) {
2691
2691
  let sourceIsFork = false;
2692
2692
  if (!input.cowboy && sourceType === "branch" && (!sourceRef || sourceRef === "HEAD" || sourceRef === "default")) {
2693
2693
  if (isAbleTimeConnected() && getIssueSource() === "abletime") {
2694
- const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-TKAFNXCM.js");
2694
+ const { ensureAbleTimeTask, issueAttachmentForAbleTimeTask } = await import("./abletime-L3ODNTBT.js");
2695
2695
  const task = await ensureAbleTimeTask({
2696
2696
  title: title?.trim() || "Untitled work",
2697
2697
  description: input.prompt?.trim() || void 0
@@ -3210,6 +3210,9 @@ function writeTurnLive(threadId, progress) {
3210
3210
  }
3211
3211
  }
3212
3212
  }
3213
+ function readTurnLiveParts(threadId) {
3214
+ return buffers.get(threadId)?.parts.slice() ?? [];
3215
+ }
3213
3216
  function readTurnLive(threadId) {
3214
3217
  const path = threadLivePath(threadId);
3215
3218
  if (!existsSync6(path)) return null;
@@ -5384,6 +5387,36 @@ function expandComposerPrompt(worktreePath, prompt, opts) {
5384
5387
  };
5385
5388
  }
5386
5389
 
5390
+ // src/composer/agent-has-replied.ts
5391
+ function joinSteerPrompt(base, addition) {
5392
+ const next = addition.trim();
5393
+ if (!next) return base;
5394
+ const head = base.replace(/\s+$/, "");
5395
+ if (!head) return next;
5396
+ return `${head}
5397
+ ${next}`;
5398
+ }
5399
+ function trailingUnansweredUserText(messages) {
5400
+ for (let i = messages.length - 1; i >= 0; i--) {
5401
+ const message = messages[i];
5402
+ if (!message || message.origin === "continue" || message.role === "summary") continue;
5403
+ if (message.role === "agent") {
5404
+ const text3 = (message.text ?? "").trim();
5405
+ if (text3 || (message.parts?.length ?? 0) > 0) return null;
5406
+ continue;
5407
+ }
5408
+ if (message.role === "user") return message.text;
5409
+ }
5410
+ return null;
5411
+ }
5412
+ function livePartsShowAgentReply(parts) {
5413
+ for (const part of parts) {
5414
+ if (part.type === "tool") return true;
5415
+ if ((part.type === "text" || part.type === "thinking") && part.text.trim()) return true;
5416
+ }
5417
+ return false;
5418
+ }
5419
+
5387
5420
  // src/composer/consume-attachments.ts
5388
5421
  function consumeComposerAttachments(thread) {
5389
5422
  return {
@@ -5436,6 +5469,128 @@ function shiftQueuedItem(queue, queueAttachments) {
5436
5469
  };
5437
5470
  }
5438
5471
 
5472
+ // src/orchestrator/enqueue-thread-send.ts
5473
+ function resolveSendFollowUp(thread, requested) {
5474
+ if (requested === "steer" || requested === "queue") return requested;
5475
+ return isOrchestratorThread(thread) ? followUpBehavior() : "queue";
5476
+ }
5477
+ function rewriteTrailingUserPrompt(threadId, from, to) {
5478
+ if (from === to) return;
5479
+ const thread = readThread(threadId);
5480
+ if (!thread) return;
5481
+ const messages = thread.messages.slice();
5482
+ for (let i = messages.length - 1; i >= 0; i--) {
5483
+ const message = messages[i];
5484
+ if (!message || message.origin === "continue" || message.role === "summary") continue;
5485
+ if (message.role === "user" && message.text === from) {
5486
+ messages[i] = { ...message, text: to };
5487
+ updateThread(threadId, { messages });
5488
+ }
5489
+ return;
5490
+ }
5491
+ }
5492
+ function reuseJoinedUserBubble(reused, threadId, last, promptText) {
5493
+ return reused.delete(threadId) && last?.role === "user" && last.origin !== "continue" && last.text === promptText;
5494
+ }
5495
+ function promptForJoinedSteer(input) {
5496
+ if (input.latestPrompt === input.promptText) return input.agentPrompt;
5497
+ rewriteTrailingUserPrompt(input.threadId, input.promptText, input.latestPrompt);
5498
+ const { agentPrompt: expandedLatest } = expandComposerPrompt(
5499
+ input.worktreePath,
5500
+ expandCanonicalGitRequest(input.latestPrompt),
5501
+ { attachments: input.attachments }
5502
+ );
5503
+ return input.expandedPrompt && input.agentPrompt.endsWith(input.expandedPrompt) ? input.agentPrompt.slice(0, -input.expandedPrompt.length) + expandedLatest : `${input.agentPrompt}
5504
+
5505
+ ${expandedLatest}`;
5506
+ }
5507
+ function clearSendBookkeeping(host, threadId) {
5508
+ host.crashContinued.delete(threadId);
5509
+ host.jobContinueCount.delete(threadId);
5510
+ host.jobContinueNudged.delete(threadId);
5511
+ host.haltDrain.delete(threadId);
5512
+ }
5513
+ async function enqueueThreadSend(host, threadRef, prompt, opts) {
5514
+ const thread = host.requireThread(threadRef);
5515
+ if (thread.status === "archived") {
5516
+ throw new Error(`Thread is archived: ${thread.id}`);
5517
+ }
5518
+ let shouldSteer = false;
5519
+ const sent = await withThreadLock(thread.id, async () => {
5520
+ const current = host.requireThread(thread.id);
5521
+ if (current.status === "archived") {
5522
+ throw new Error(`Thread is archived: ${thread.id}`);
5523
+ }
5524
+ const followUp = resolveSendFollowUp(current, opts?.followUp);
5525
+ const explicit = opts?.attachments;
5526
+ const consumed = explicit !== void 0 ? { attachments: current.attachments, consumed: explicit } : consumeComposerAttachments(current);
5527
+ const inFlightEarly = host.activeTurns.has(thread.id) || host.startingTurns.has(thread.id) || current.status === "running";
5528
+ const agentHasRepliedEarly = livePartsShowAgentReply(readTurnLiveParts(current.id));
5529
+ const draft = host.openSteerPrompt.get(current.id);
5530
+ const queuedHead = !inFlightEarly && current.status === "queued" && current.queue.length > 0 ? current.queue[0] : null;
5531
+ const unanswered = followUp === "steer" && !agentHasRepliedEarly ? draft?.text ?? (inFlightEarly ? trailingUnansweredUserText(current.messages) : queuedHead) : null;
5532
+ if (unanswered != null && (draft ? !draft.spawned : queuedHead != null)) {
5533
+ clearSendBookkeeping(host, thread.id);
5534
+ const combined = joinSteerPrompt(unanswered, prompt);
5535
+ if (draft && !draft.spawned) {
5536
+ draft.text = combined;
5537
+ rewriteTrailingUserPrompt(current.id, unanswered, combined);
5538
+ } else {
5539
+ const queue = current.queue.slice();
5540
+ queue[0] = combined;
5541
+ const queueAttachments = alignQueueAttachments(queue.length, current.queueAttachments);
5542
+ if (consumed.consumed.length > 0) {
5543
+ queueAttachments[0] = [...queueAttachments[0] ?? [], ...consumed.consumed];
5544
+ }
5545
+ const patch2 = { queue, queueAttachments };
5546
+ if (explicit === void 0 && consumed.consumed.length > 0) {
5547
+ patch2.attachments = consumed.attachments;
5548
+ }
5549
+ updateThread(current.id, patch2);
5550
+ host.emit({ type: "queue_changed", threadId: current.id, queue });
5551
+ }
5552
+ if (thisProcessShouldDrainAgentQueues() && !inFlightEarly) {
5553
+ host.armDrain(current.id);
5554
+ }
5555
+ return host.requireThread(current.id);
5556
+ }
5557
+ const promptToQueue = unanswered != null ? joinSteerPrompt(unanswered, prompt) : prompt;
5558
+ if (unanswered != null) {
5559
+ if (draft) draft.text = promptToQueue;
5560
+ rewriteTrailingUserPrompt(current.id, unanswered, promptToQueue);
5561
+ host.reusedUserPrompt.add(current.id);
5562
+ }
5563
+ const queued = appendQueuedItem(
5564
+ current.queue,
5565
+ current.queueAttachments,
5566
+ promptToQueue,
5567
+ consumed.consumed
5568
+ );
5569
+ clearSendBookkeeping(host, thread.id);
5570
+ const inFlight = host.activeTurns.has(thread.id) || host.startingTurns.has(thread.id) || current.status === "running";
5571
+ shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
5572
+ const patch = queued;
5573
+ if (explicit === void 0 && consumed.consumed.length > 0) {
5574
+ patch.attachments = consumed.attachments;
5575
+ }
5576
+ if (!inFlight) patch.status = "queued";
5577
+ const pid = current.agentPid;
5578
+ if (typeof pid === "number" && pid > 0 && !host.pidAlive(pid)) {
5579
+ patch.agentPid = null;
5580
+ }
5581
+ updateThread(thread.id, patch);
5582
+ host.emit({ type: "queue_changed", threadId: thread.id, queue: queued.queue });
5583
+ if (!inFlight) {
5584
+ host.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
5585
+ }
5586
+ if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
5587
+ host.armDrain(thread.id);
5588
+ }
5589
+ return host.requireThread(thread.id);
5590
+ });
5591
+ return { thread: sent, shouldSteer };
5592
+ }
5593
+
5439
5594
  // src/agents/instructions.ts
5440
5595
  import { existsSync as existsSync12 } from "fs";
5441
5596
  import { join as join12 } from "path";
@@ -6458,7 +6613,7 @@ function formatScheduledPrompt(name, prompt) {
6458
6613
  ${prompt}`;
6459
6614
  }
6460
6615
  async function defaultDeps() {
6461
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-N54V3B76.js");
6616
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-H3DSZ5RM.js");
6462
6617
  const orch = getOrchestrator2();
6463
6618
  return {
6464
6619
  findThread: (id) => findThreadByRef(id),
@@ -6574,10 +6729,6 @@ async function waitForPidExit(pid, timeoutMs) {
6574
6729
  }
6575
6730
  return true;
6576
6731
  }
6577
- function resolveSendFollowUp(thread, requested) {
6578
- if (requested === "steer" || requested === "queue") return requested;
6579
- return isOrchestratorThread(thread) ? followUpBehavior() : "queue";
6580
- }
6581
6732
  function resolveOrchChildFollowUp(requested) {
6582
6733
  if (requested === "steer" || requested === "queue") return requested;
6583
6734
  return followUpBehavior();
@@ -6606,6 +6757,13 @@ var Orchestrator = class {
6606
6757
  draining = /* @__PURE__ */ new Set();
6607
6758
  /** Threads past setStatus(running) but not yet in activeTurns (spawn in flight). */
6608
6759
  startingTurns = /* @__PURE__ */ new Set();
6760
+ /**
6761
+ * Prompt for the turn that has not been answered yet. Steer follow-ups before
6762
+ * any agent output are joined onto this text instead of starting a second bubble.
6763
+ */
6764
+ openSteerPrompt = /* @__PURE__ */ new Map();
6765
+ /** Next runTurn should keep the user bubble already rewritten to this prompt. */
6766
+ reusedUserPrompt = /* @__PURE__ */ new Set();
6609
6767
  /** Last sync thread-file read for false-stop heal (throttled per thread). */
6610
6768
  lastReconcileHealAt = /* @__PURE__ */ new Map();
6611
6769
  /** Per-repo timestamp of the last `reconcile(repo, { light: true })`. */
@@ -7216,54 +7374,29 @@ var Orchestrator = class {
7216
7374
  return thread;
7217
7375
  }
7218
7376
  async send(threadRef, prompt, opts) {
7219
- const thread = this.requireThread(threadRef);
7220
- if (thread.status === "archived") {
7221
- throw new Error(`Thread is archived: ${thread.id}`);
7222
- }
7223
- let shouldSteer = false;
7224
- const sent = await withThreadLock(thread.id, async () => {
7225
- const current = this.requireThread(thread.id);
7226
- if (current.status === "archived") {
7227
- throw new Error(`Thread is archived: ${thread.id}`);
7228
- }
7229
- const followUp = resolveSendFollowUp(current, opts?.followUp);
7230
- const explicit = opts?.attachments;
7231
- const consumed = explicit !== void 0 ? { attachments: current.attachments, consumed: explicit } : consumeComposerAttachments(current);
7232
- const queued = appendQueuedItem(
7233
- current.queue,
7234
- current.queueAttachments,
7235
- prompt,
7236
- consumed.consumed
7237
- );
7238
- this.crashContinued.delete(thread.id);
7239
- this.jobContinueCount.delete(thread.id);
7240
- this.jobContinueNudged.delete(thread.id);
7241
- this.haltDrain.delete(thread.id);
7242
- const inFlight = this.activeTurns.has(thread.id) || this.startingTurns.has(thread.id) || current.status === "running";
7243
- shouldSteer = followUp === "steer" && (inFlight || current.queue.length > 0);
7244
- const patch = queued;
7245
- if (explicit === void 0 && consumed.consumed.length > 0) {
7246
- patch.attachments = consumed.attachments;
7247
- }
7248
- if (!inFlight) patch.status = "queued";
7249
- const pid = current.agentPid;
7250
- if (typeof pid === "number" && pid > 0 && !isPidAlive(pid)) {
7251
- patch.agentPid = null;
7252
- }
7253
- updateThread(thread.id, patch);
7254
- this.emit({ type: "queue_changed", threadId: thread.id, queue: queued.queue });
7255
- if (!inFlight) {
7256
- this.emit({ type: "status_changed", threadId: thread.id, status: "queued" });
7257
- }
7258
- if (thisProcessShouldDrainAgentQueues() && !shouldSteer) {
7259
- this.armDrain(thread.id);
7260
- }
7261
- return this.requireThread(thread.id);
7262
- });
7263
- if (shouldSteer && sent.queue.length > 0) {
7264
- return this.sendQueuedMessageNow(sent.id, sent.queue.length - 1);
7377
+ const sent = await enqueueThreadSend(
7378
+ {
7379
+ activeTurns: this.activeTurns,
7380
+ startingTurns: this.startingTurns,
7381
+ openSteerPrompt: this.openSteerPrompt,
7382
+ reusedUserPrompt: this.reusedUserPrompt,
7383
+ crashContinued: this.crashContinued,
7384
+ jobContinueCount: this.jobContinueCount,
7385
+ jobContinueNudged: this.jobContinueNudged,
7386
+ haltDrain: this.haltDrain,
7387
+ emit: (event) => this.emit(event),
7388
+ armDrain: (id) => this.armDrain(id),
7389
+ requireThread: (ref) => this.requireThread(ref),
7390
+ pidAlive: (pid) => isPidAlive(pid)
7391
+ },
7392
+ threadRef,
7393
+ prompt,
7394
+ opts
7395
+ );
7396
+ if (sent.shouldSteer && sent.thread.queue.length > 0) {
7397
+ return this.sendQueuedMessageNow(sent.thread.id, sent.thread.queue.length - 1);
7265
7398
  }
7266
- return sent;
7399
+ return sent.thread;
7267
7400
  }
7268
7401
  async fanOut(threadRefs, prompt, opts) {
7269
7402
  const results = [];
@@ -7420,6 +7553,10 @@ var Orchestrator = class {
7420
7553
  this.emit({ type: "status_changed", threadId, status: "running" });
7421
7554
  this.emit({ type: "turn_started", threadId, prompt });
7422
7555
  try {
7556
+ this.openSteerPrompt.set(threadId, {
7557
+ text: typeof prompt === "string" ? prompt : "",
7558
+ spawned: false
7559
+ });
7423
7560
  try {
7424
7561
  const baseline = await captureTurnBaseline(thread.worktreePath);
7425
7562
  if (baseline) this.turnBaselines.set(threadId, baseline);
@@ -7445,18 +7582,21 @@ var Orchestrator = class {
7445
7582
  this.emit({ type: "error", threadId, message: `context compact failed: ${message}` });
7446
7583
  thread = this.requireThread(threadId);
7447
7584
  }
7448
- const promptText = typeof prompt === "string" ? prompt : "";
7585
+ const promptText = this.openSteerPrompt.get(threadId)?.text ?? (typeof prompt === "string" ? prompt : "");
7449
7586
  const autoContinue = isJobContinuePrompt(promptText) || promptText.startsWith("The previous agent process ended before it finished.");
7450
7587
  const parked = takePendingTurnAttachments(thread);
7451
7588
  const sentAttachments = !autoContinue && parked.length > 0 ? parked : void 0;
7452
7589
  if (!autoContinue) clearAgentBlock(threadId);
7453
- appendMessage(threadId, {
7454
- role: "user",
7455
- text: promptText,
7456
- ...sentAttachments ? { attachments: sentAttachments } : {},
7457
- ...autoContinue ? { origin: "continue" } : {},
7458
- ts: (/* @__PURE__ */ new Date()).toISOString()
7459
- });
7590
+ const lastShown = this.requireThread(threadId).messages.at(-1);
7591
+ if (!reuseJoinedUserBubble(this.reusedUserPrompt, threadId, lastShown, promptText)) {
7592
+ appendMessage(threadId, {
7593
+ role: "user",
7594
+ text: promptText,
7595
+ ...sentAttachments ? { attachments: sentAttachments } : {},
7596
+ ...autoContinue ? { origin: "continue" } : {},
7597
+ ts: (/* @__PURE__ */ new Date()).toISOString()
7598
+ });
7599
+ }
7460
7600
  if (!autoContinue) {
7461
7601
  const live = this.requireThread(threadId);
7462
7602
  const stamp = agentPurposeStamp({
@@ -7655,11 +7795,22 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
7655
7795
  ].filter(Boolean).join("\n\n---\n\n");
7656
7796
  const stderrTail = [];
7657
7797
  traceTurn("runTurn.beforeSpawn", { threadId, agent: fresh.agent });
7798
+ const steerDraft = this.openSteerPrompt.get(threadId);
7799
+ if (steerDraft) steerDraft.spawned = true;
7800
+ const promptForAgent = promptForJoinedSteer({
7801
+ threadId,
7802
+ promptText,
7803
+ latestPrompt: steerDraft?.text ?? promptText,
7804
+ agentPrompt,
7805
+ expandedPrompt,
7806
+ worktreePath: fresh.worktreePath,
7807
+ attachments: autoContinue ? [] : sentAttachments ?? []
7808
+ });
7658
7809
  const handle = await spawnAgentTurn(
7659
7810
  fresh,
7660
7811
  {
7661
7812
  cachedPrefix,
7662
- prompt: agentPrompt,
7813
+ prompt: promptForAgent,
7663
7814
  systemPrompt: turnReminders,
7664
7815
  isolateCodexPlugins: fresh.isolateCodexPlugins === true
7665
7816
  },
@@ -7787,7 +7938,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
7787
7938
  retryThread,
7788
7939
  {
7789
7940
  cachedPrefix: retryPrefix,
7790
- prompt: agentPrompt,
7941
+ prompt: promptForAgent,
7791
7942
  systemPrompt: turnReminders,
7792
7943
  isolateCodexPlugins: isolateCodexPluginRetry || retryThread.isolateCodexPlugins === true
7793
7944
  },
@@ -7947,6 +8098,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
7947
8098
  } finally {
7948
8099
  this.startingTurns.delete(threadId);
7949
8100
  this.activeTurns.delete(threadId);
8101
+ this.openSteerPrompt.delete(threadId);
7950
8102
  this.processes.delete(`${threadId}:agent`);
7951
8103
  this.stoppedTurns.delete(threadId);
7952
8104
  this.runningCount = Math.max(0, this.runningCount - 1);
@@ -9396,6 +9548,7 @@ export {
9396
9548
  listFleetArchive,
9397
9549
  formatFleetArchive,
9398
9550
  readTurnLive,
9551
+ resolveSendFollowUp,
9399
9552
  localhostPreviewUrl,
9400
9553
  parseIssueSince,
9401
9554
  formatGitHubSearchUpdatedSince,
@@ -9419,7 +9572,6 @@ export {
9419
9572
  RUN_SCRIPT_DESKTOP_ADOPT_MS,
9420
9573
  isPidAlive,
9421
9574
  waitForPidExit,
9422
- resolveSendFollowUp,
9423
9575
  resolveOrchChildFollowUp,
9424
9576
  LIGHT_RECONCILE_THROTTLE_MS,
9425
9577
  Orchestrator,
@@ -3,13 +3,13 @@
3
3
  import {
4
4
  abletimeRestUrl,
5
5
  textFromAbleTimeDoc
6
- } from "./chunk-VZAJVX36.js";
6
+ } from "./chunk-JD7CC6SW.js";
7
7
  import {
8
8
  assertAbleTimeCredential,
9
9
  callAbleTimeTool,
10
10
  normalizeAbleTimeHost,
11
11
  rewriteAbleTimeError
12
- } from "./chunk-7SCVGGF6.js";
12
+ } from "./chunk-ZM43NTJJ.js";
13
13
  import {
14
14
  httpFetch
15
15
  } from "./chunk-2GPQZZLY.js";
@@ -551,9 +551,12 @@ function issueAttachmentForAbleTimeTask(task) {
551
551
  ].filter(Boolean).join("\n")
552
552
  };
553
553
  }
554
+ function ableTimeStateIsClosed(state) {
555
+ const value = (state ?? "").trim().toLowerCase();
556
+ return Boolean(value && CLOSED_STATES.has(value));
557
+ }
554
558
  function isOpenTask(task) {
555
- const state = (task.state ?? "").toLowerCase();
556
- return !state || !CLOSED_STATES.has(state);
559
+ return !ableTimeStateIsClosed(task.state);
557
560
  }
558
561
  async function getAbleTimeOrientation(opts) {
559
562
  const raw = await callAbleTimeTool("orientation", {}, opts);
@@ -849,6 +852,7 @@ export {
849
852
  mapAbleTimeTask,
850
853
  toAbleTimeIssueInfo,
851
854
  issueAttachmentForAbleTimeTask,
855
+ ableTimeStateIsClosed,
852
856
  getAbleTimeOrientation,
853
857
  listAbleTimeProjects,
854
858
  listAbleTimeTasks,