gsd-pi 2.36.0-dev.d612764 → 2.36.0-dev.f887f4e

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 (46) hide show
  1. package/dist/resources/extensions/gsd/auto-dashboard.js +104 -334
  2. package/dist/resources/extensions/gsd/auto-loop.js +0 -11
  3. package/dist/resources/extensions/gsd/auto.js +0 -16
  4. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  5. package/dist/resources/extensions/gsd/commands.js +1 -51
  6. package/dist/resources/extensions/gsd/docs/preferences-reference.md +0 -25
  7. package/dist/resources/extensions/gsd/index.js +0 -5
  8. package/dist/resources/extensions/gsd/notifications.js +1 -10
  9. package/dist/resources/extensions/gsd/preferences-types.js +0 -2
  10. package/dist/resources/extensions/gsd/preferences-validation.js +0 -29
  11. package/dist/resources/extensions/gsd/preferences.js +0 -3
  12. package/dist/resources/extensions/gsd/prompts/research-milestone.md +3 -4
  13. package/dist/resources/extensions/gsd/prompts/research-slice.md +2 -3
  14. package/dist/resources/extensions/gsd/templates/preferences.md +0 -6
  15. package/dist/resources/extensions/search-the-web/native-search.js +4 -45
  16. package/dist/resources/extensions/shared/terminal.js +0 -5
  17. package/dist/resources/extensions/subagent/index.js +60 -180
  18. package/package.json +1 -1
  19. package/packages/pi-tui/dist/terminal-image.d.ts.map +1 -1
  20. package/packages/pi-tui/dist/terminal-image.js +0 -4
  21. package/packages/pi-tui/dist/terminal-image.js.map +1 -1
  22. package/packages/pi-tui/src/terminal-image.ts +0 -5
  23. package/src/resources/extensions/gsd/auto-dashboard.ts +116 -363
  24. package/src/resources/extensions/gsd/auto-loop.ts +0 -42
  25. package/src/resources/extensions/gsd/auto.ts +0 -21
  26. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  27. package/src/resources/extensions/gsd/commands.ts +1 -54
  28. package/src/resources/extensions/gsd/docs/preferences-reference.md +0 -25
  29. package/src/resources/extensions/gsd/index.ts +0 -8
  30. package/src/resources/extensions/gsd/notifications.ts +1 -10
  31. package/src/resources/extensions/gsd/preferences-types.ts +0 -13
  32. package/src/resources/extensions/gsd/preferences-validation.ts +0 -26
  33. package/src/resources/extensions/gsd/preferences.ts +0 -4
  34. package/src/resources/extensions/gsd/prompts/research-milestone.md +3 -4
  35. package/src/resources/extensions/gsd/prompts/research-slice.md +2 -3
  36. package/src/resources/extensions/gsd/templates/preferences.md +0 -6
  37. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +0 -2
  38. package/src/resources/extensions/gsd/tests/preferences.test.ts +0 -23
  39. package/src/resources/extensions/search-the-web/native-search.ts +4 -50
  40. package/src/resources/extensions/shared/terminal.ts +0 -5
  41. package/src/resources/extensions/subagent/index.ts +79 -236
  42. package/dist/resources/extensions/cmux/index.js +0 -321
  43. package/dist/resources/extensions/gsd/commands-cmux.js +0 -120
  44. package/src/resources/extensions/cmux/index.ts +0 -384
  45. package/src/resources/extensions/gsd/commands-cmux.ts +0 -143
  46. package/src/resources/extensions/gsd/tests/cmux.test.ts +0 -98
@@ -16,16 +16,6 @@ export const CUSTOM_SEARCH_TOOL_NAMES = ["search-the-web", "search_and_read", "g
16
16
  /** Thinking block types that require signature validation by the API */
17
17
  const THINKING_TYPES = new Set(["thinking", "redacted_thinking"]);
18
18
 
19
- /**
20
- * Maximum number of native web searches allowed per session (agent unit).
21
- * The Anthropic API's `max_uses` is per-request — it resets on each API call.
22
- * When `pause_turn` triggers a resubmit, the model gets a fresh budget.
23
- * This session-level cap prevents unbounded search accumulation (#1309).
24
- *
25
- * 15 = 3 full turns of 5 searches each — generous for research, but bounded.
26
- */
27
- export const MAX_NATIVE_SEARCHES_PER_SESSION = 15;
28
-
29
19
  /** When true, skip native web search injection and keep Brave/custom tools active on Anthropic. */
30
20
  export function preferBraveSearch(): boolean {
31
21
  // preferences.md takes priority over env var
@@ -84,11 +74,6 @@ export function registerNativeSearchHooks(pi: NativeSearchPI): { getIsAnthropic:
84
74
  let isAnthropicProvider = false;
85
75
  let modelSelectFired = false;
86
76
 
87
- // Session-level native search counter (#1309).
88
- // Tracks cumulative web_search_tool_result blocks across all turns in a session.
89
- // Reset on session_start. Used to compute remaining budget for max_uses.
90
- let sessionSearchCount = 0;
91
-
92
77
  // Track provider changes via model selection — also handles diagnostics
93
78
  // since model_select fires AFTER session_start and knows the provider.
94
79
  pi.on("model_select", async (event: any, ctx: any) => {
@@ -176,41 +161,13 @@ export function registerNativeSearchHooks(pi: NativeSearchPI): { getIsAnthropic:
176
161
  );
177
162
  payload.tools = tools;
178
163
 
179
- // ── Session-level search budget (#1309) ──────────────────────────────
180
- // Count web_search_tool_result blocks in the conversation history to
181
- // determine how many native searches have already been used this session.
182
- // The Anthropic API's max_uses resets per request, so without this guard,
183
- // pause_turn → resubmit cycles allow unlimited total searches.
184
- if (Array.isArray(messages)) {
185
- let historySearchCount = 0;
186
- for (const msg of messages) {
187
- const content = msg.content;
188
- if (!Array.isArray(content)) continue;
189
- for (const block of content) {
190
- if ((block as any)?.type === "web_search_tool_result") {
191
- historySearchCount++;
192
- }
193
- }
194
- }
195
- // Sync counter from history (handles session restore / context replay)
196
- sessionSearchCount = historySearchCount;
197
- }
198
-
199
- const remaining = Math.max(0, MAX_NATIVE_SEARCHES_PER_SESSION - sessionSearchCount);
200
-
201
- if (remaining <= 0) {
202
- // Budget exhausted — don't inject the search tool at all.
203
- // The model will proceed without web search capability.
204
- return payload;
205
- }
206
-
207
164
  tools.push({
208
165
  type: "web_search_20250305",
209
166
  name: "web_search",
210
- // Cap per-request searches to the lesser of 5 (per-turn cap) or the
211
- // remaining session budget (#1309). This prevents the model from
212
- // consuming unlimited searches via pause_turn resubmit cycles.
213
- max_uses: Math.min(5, remaining),
167
+ // Cap server-side searches per response to prevent the model from
168
+ // looping on web_search without synthesizing results (#817).
169
+ // 5 searches is generous most queries need 1-2.
170
+ max_uses: 5,
214
171
  });
215
172
 
216
173
  return payload;
@@ -218,9 +175,6 @@ export function registerNativeSearchHooks(pi: NativeSearchPI): { getIsAnthropic:
218
175
 
219
176
  // Basic startup diagnostics — provider-specific info comes from model_select
220
177
  pi.on("session_start", async (_event: any, ctx: any) => {
221
- // Reset session-level search budget (#1309)
222
- sessionSearchCount = 0;
223
-
224
178
  const hasBrave = !!process.env.BRAVE_API_KEY;
225
179
  const hasJina = !!process.env.JINA_API_KEY;
226
180
  const hasAnswers = !!process.env.BRAVE_ANSWERS_KEY;
@@ -7,14 +7,9 @@
7
7
 
8
8
  const UNSUPPORTED_TERMS = ["apple_terminal", "warpterm"];
9
9
 
10
- export function isCmuxTerminal(env: NodeJS.ProcessEnv = process.env): boolean {
11
- return Boolean(env.CMUX_WORKSPACE_ID && env.CMUX_SURFACE_ID);
12
- }
13
-
14
10
  export function supportsCtrlAltShortcuts(): boolean {
15
11
  const term = (process.env.TERM_PROGRAM || "").toLowerCase();
16
12
  const jetbrains = (process.env.TERMINAL_EMULATOR || "").toLowerCase().includes("jetbrains");
17
- if (isCmuxTerminal()) return true;
18
13
  return !UNSUPPORTED_TERMS.some((t) => term.includes(t)) && !jetbrains;
19
14
  }
20
15
 
@@ -34,8 +34,6 @@ import {
34
34
  readIsolationMode,
35
35
  } from "./isolation.js";
36
36
  import { registerWorker, updateWorker } from "./worker-registry.js";
37
- import { loadEffectiveGSDPreferences } from "../gsd/preferences.js";
38
- import { CmuxClient, shellEscape } from "../cmux/index.js";
39
37
 
40
38
  const MAX_PARALLEL_TASKS = 8;
41
39
  const MAX_CONCURRENCY = 4;
@@ -259,70 +257,6 @@ function writePromptToTempFile(agentName: string, prompt: string): { dir: string
259
257
  return { dir: tmpDir, filePath };
260
258
  }
261
259
 
262
- function buildSubagentProcessArgs(
263
- agent: AgentConfig,
264
- task: string,
265
- tmpPromptPath: string | null,
266
- ): string[] {
267
- const args: string[] = ["--mode", "json", "-p", "--no-session"];
268
- if (agent.model) args.push("--model", agent.model);
269
- if (agent.tools && agent.tools.length > 0) args.push("--tools", agent.tools.join(","));
270
- if (tmpPromptPath) args.push("--append-system-prompt", tmpPromptPath);
271
- args.push(`Task: ${task}`);
272
- return args;
273
- }
274
-
275
- function processSubagentEventLine(
276
- line: string,
277
- currentResult: SingleResult,
278
- emitUpdate: () => void,
279
- ): void {
280
- if (!line.trim()) return;
281
- let event: any;
282
- try {
283
- event = JSON.parse(line);
284
- } catch {
285
- return;
286
- }
287
-
288
- if (event.type === "message_end" && event.message) {
289
- const msg = event.message as Message;
290
- currentResult.messages.push(msg);
291
-
292
- if (msg.role === "assistant") {
293
- currentResult.usage.turns++;
294
- const usage = msg.usage;
295
- if (usage) {
296
- currentResult.usage.input += usage.input || 0;
297
- currentResult.usage.output += usage.output || 0;
298
- currentResult.usage.cacheRead += usage.cacheRead || 0;
299
- currentResult.usage.cacheWrite += usage.cacheWrite || 0;
300
- currentResult.usage.cost += usage.cost?.total || 0;
301
- currentResult.usage.contextTokens = usage.totalTokens || 0;
302
- }
303
- if (!currentResult.model && msg.model) currentResult.model = msg.model;
304
- if (msg.stopReason) currentResult.stopReason = msg.stopReason;
305
- if (msg.errorMessage) currentResult.errorMessage = msg.errorMessage;
306
- }
307
- emitUpdate();
308
- }
309
-
310
- if (event.type === "tool_result_end" && event.message) {
311
- currentResult.messages.push(event.message as Message);
312
- emitUpdate();
313
- }
314
- }
315
-
316
- async function waitForFile(filePath: string, signal: AbortSignal | undefined, timeoutMs = 30 * 60 * 1000): Promise<boolean> {
317
- const started = Date.now();
318
- while (Date.now() - started < timeoutMs) {
319
- if (signal?.aborted) return false;
320
- if (fs.existsSync(filePath)) return true;
321
- await new Promise((resolve) => setTimeout(resolve, 150));
322
- }
323
- return false;
324
- }
325
-
326
260
  type OnUpdateCallback = (partial: AgentToolResult<SubagentDetails>) => void;
327
261
 
328
262
  async function runSingleAgent(
@@ -352,6 +286,10 @@ async function runSingleAgent(
352
286
  };
353
287
  }
354
288
 
289
+ const args: string[] = ["--mode", "json", "-p", "--no-session"];
290
+ if (agent.model) args.push("--model", agent.model);
291
+ if (agent.tools && agent.tools.length > 0) args.push("--tools", agent.tools.join(","));
292
+
355
293
  let tmpPromptDir: string | null = null;
356
294
  let tmpPromptPath: string | null = null;
357
295
 
@@ -381,8 +319,10 @@ async function runSingleAgent(
381
319
  const tmp = writePromptToTempFile(agent.name, agent.systemPrompt);
382
320
  tmpPromptDir = tmp.dir;
383
321
  tmpPromptPath = tmp.filePath;
322
+ args.push("--append-system-prompt", tmpPromptPath);
384
323
  }
385
- const args = buildSubagentProcessArgs(agent, task, tmpPromptPath);
324
+
325
+ args.push(`Task: ${task}`);
386
326
  let wasAborted = false;
387
327
 
388
328
  const exitCode = await new Promise<number>((resolve) => {
@@ -396,11 +336,48 @@ async function runSingleAgent(
396
336
  liveSubagentProcesses.add(proc);
397
337
  let buffer = "";
398
338
 
339
+ const processLine = (line: string) => {
340
+ if (!line.trim()) return;
341
+ let event: any;
342
+ try {
343
+ event = JSON.parse(line);
344
+ } catch {
345
+ return;
346
+ }
347
+
348
+ if (event.type === "message_end" && event.message) {
349
+ const msg = event.message as Message;
350
+ currentResult.messages.push(msg);
351
+
352
+ if (msg.role === "assistant") {
353
+ currentResult.usage.turns++;
354
+ const usage = msg.usage;
355
+ if (usage) {
356
+ currentResult.usage.input += usage.input || 0;
357
+ currentResult.usage.output += usage.output || 0;
358
+ currentResult.usage.cacheRead += usage.cacheRead || 0;
359
+ currentResult.usage.cacheWrite += usage.cacheWrite || 0;
360
+ currentResult.usage.cost += usage.cost?.total || 0;
361
+ currentResult.usage.contextTokens = usage.totalTokens || 0;
362
+ }
363
+ if (!currentResult.model && msg.model) currentResult.model = msg.model;
364
+ if (msg.stopReason) currentResult.stopReason = msg.stopReason;
365
+ if (msg.errorMessage) currentResult.errorMessage = msg.errorMessage;
366
+ }
367
+ emitUpdate();
368
+ }
369
+
370
+ if (event.type === "tool_result_end" && event.message) {
371
+ currentResult.messages.push(event.message as Message);
372
+ emitUpdate();
373
+ }
374
+ };
375
+
399
376
  proc.stdout.on("data", (data) => {
400
377
  buffer += data.toString();
401
378
  const lines = buffer.split("\n");
402
379
  buffer = lines.pop() || "";
403
- for (const line of lines) processSubagentEventLine(line, currentResult, emitUpdate);
380
+ for (const line of lines) processLine(line);
404
381
  });
405
382
 
406
383
  proc.stderr.on("data", (data) => {
@@ -409,7 +386,7 @@ async function runSingleAgent(
409
386
 
410
387
  proc.on("close", (code) => {
411
388
  liveSubagentProcesses.delete(proc);
412
- if (buffer.trim()) processSubagentEventLine(buffer, currentResult, emitUpdate);
389
+ if (buffer.trim()) processLine(buffer);
413
390
  resolve(code ?? 0);
414
391
  });
415
392
 
@@ -450,120 +427,6 @@ async function runSingleAgent(
450
427
  }
451
428
  }
452
429
 
453
- async function runSingleAgentInCmuxSplit(
454
- cmuxClient: CmuxClient,
455
- direction: "right" | "down",
456
- defaultCwd: string,
457
- agents: AgentConfig[],
458
- agentName: string,
459
- task: string,
460
- cwd: string | undefined,
461
- step: number | undefined,
462
- signal: AbortSignal | undefined,
463
- onUpdate: OnUpdateCallback | undefined,
464
- makeDetails: (results: SingleResult[]) => SubagentDetails,
465
- ): Promise<SingleResult> {
466
- const agent = agents.find((a) => a.name === agentName);
467
- if (!agent) {
468
- return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails);
469
- }
470
-
471
- let tmpPromptDir: string | null = null;
472
- let tmpPromptPath: string | null = null;
473
- let tmpOutputDir: string | null = null;
474
-
475
- const currentResult: SingleResult = {
476
- agent: agentName,
477
- agentSource: agent.source,
478
- task,
479
- exitCode: 0,
480
- messages: [],
481
- stderr: "",
482
- usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 },
483
- model: agent.model,
484
- step,
485
- };
486
-
487
- const emitUpdate = () => {
488
- if (onUpdate) {
489
- onUpdate({
490
- content: [{ type: "text", text: getFinalOutput(currentResult.messages) || "(running...)" }],
491
- details: makeDetails([currentResult]),
492
- });
493
- }
494
- };
495
-
496
- try {
497
- if (agent.systemPrompt.trim()) {
498
- const tmp = writePromptToTempFile(agent.name, agent.systemPrompt);
499
- tmpPromptDir = tmp.dir;
500
- tmpPromptPath = tmp.filePath;
501
- }
502
- tmpOutputDir = fs.mkdtempSync(path.join(os.tmpdir(), "pi-subagent-cmux-"));
503
- const stdoutPath = path.join(tmpOutputDir, "stdout.jsonl");
504
- const stderrPath = path.join(tmpOutputDir, "stderr.log");
505
- const exitPath = path.join(tmpOutputDir, "exit.code");
506
- const cmuxSurfaceId = await cmuxClient.createSplit(direction);
507
- if (!cmuxSurfaceId) {
508
- return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails);
509
- }
510
-
511
- const bundledPaths = (process.env.GSD_BUNDLED_EXTENSION_PATHS ?? "").split(path.delimiter).map((s) => s.trim()).filter(Boolean);
512
- const extensionArgs = bundledPaths.flatMap((p) => ["--extension", p]);
513
- const processArgs = [process.env.GSD_BIN_PATH!, ...extensionArgs, ...buildSubagentProcessArgs(agent, task, tmpPromptPath)];
514
- const innerScript = [
515
- `cd ${shellEscape(cwd ?? defaultCwd)}`,
516
- "set -o pipefail",
517
- `${shellEscape(process.execPath)} ${processArgs.map(shellEscape).join(" ")} 2> >(tee ${shellEscape(stderrPath)} >&2) | tee ${shellEscape(stdoutPath)}`,
518
- "status=${PIPESTATUS[0]}",
519
- `printf '%s' "$status" > ${shellEscape(exitPath)}`,
520
- ].join("; ");
521
-
522
- const sent = await cmuxClient.sendSurface(cmuxSurfaceId, `bash -lc ${shellEscape(innerScript)}`);
523
- if (!sent) {
524
- return runSingleAgent(defaultCwd, agents, agentName, task, cwd, step, signal, onUpdate, makeDetails);
525
- }
526
-
527
- const finished = await waitForFile(exitPath, signal);
528
- if (!finished) {
529
- currentResult.exitCode = 1;
530
- currentResult.stderr = "cmux split execution timed out or was aborted";
531
- return currentResult;
532
- }
533
-
534
- if (fs.existsSync(stdoutPath)) {
535
- const stdout = fs.readFileSync(stdoutPath, "utf-8");
536
- for (const line of stdout.split("\n")) {
537
- processSubagentEventLine(line, currentResult, emitUpdate);
538
- }
539
- }
540
- if (fs.existsSync(stderrPath)) {
541
- currentResult.stderr = fs.readFileSync(stderrPath, "utf-8");
542
- }
543
- currentResult.exitCode = Number.parseInt(fs.readFileSync(exitPath, "utf-8").trim() || "1", 10) || 0;
544
- return currentResult;
545
- } finally {
546
- if (tmpPromptPath)
547
- try {
548
- fs.unlinkSync(tmpPromptPath);
549
- } catch {
550
- /* ignore */
551
- }
552
- if (tmpPromptDir)
553
- try {
554
- fs.rmdirSync(tmpPromptDir);
555
- } catch {
556
- /* ignore */
557
- }
558
- if (tmpOutputDir)
559
- try {
560
- fs.rmSync(tmpOutputDir, { recursive: true, force: true });
561
- } catch {
562
- /* ignore */
563
- }
564
- }
565
- }
566
-
567
430
  const TaskItem = Type.Object({
568
431
  agent: Type.String({ description: "Name of the agent to invoke" }),
569
432
  task: Type.String({ description: "Task to delegate to the agent" }),
@@ -648,8 +511,6 @@ export default function (pi: ExtensionAPI) {
648
511
  const discovery = discoverAgents(ctx.cwd, agentScope);
649
512
  const agents = discovery.agents;
650
513
  const confirmProjectAgents = params.confirmProjectAgents ?? false;
651
- const cmuxClient = CmuxClient.fromPreferences(loadEffectiveGSDPreferences()?.preferences);
652
- const cmuxSplitsEnabled = cmuxClient.getConfig().splits;
653
514
 
654
515
  // Resolve isolation mode
655
516
  const isolationMode = readIsolationMode();
@@ -808,26 +669,28 @@ export default function (pi: ExtensionAPI) {
808
669
  const batchSize = params.tasks.length;
809
670
  const results = await mapWithConcurrencyLimit(params.tasks, MAX_CONCURRENCY, async (t, index) => {
810
671
  const workerId = registerWorker(t.agent, t.task, index, batchSize, batchId);
811
- const runTask = () => cmuxSplitsEnabled
812
- ? runSingleAgentInCmuxSplit(
813
- cmuxClient,
814
- index % 2 === 0 ? "right" : "down",
815
- ctx.cwd,
816
- agents,
817
- t.agent,
818
- t.task,
819
- t.cwd,
820
- undefined,
821
- signal,
822
- (partial) => {
823
- if (partial.details?.results[0]) {
824
- allResults[index] = partial.details.results[0];
825
- emitParallelUpdate();
826
- }
827
- },
828
- makeDetails("parallel"),
829
- )
830
- : runSingleAgent(
672
+ let result = await runSingleAgent(
673
+ ctx.cwd,
674
+ agents,
675
+ t.agent,
676
+ t.task,
677
+ t.cwd,
678
+ undefined,
679
+ signal,
680
+ // Per-task update callback
681
+ (partial) => {
682
+ if (partial.details?.results[0]) {
683
+ allResults[index] = partial.details.results[0];
684
+ emitParallelUpdate();
685
+ }
686
+ },
687
+ makeDetails("parallel"),
688
+ );
689
+
690
+ // Auto-retry failed tasks (likely API rate limit or transient error)
691
+ const isFailed = result.exitCode !== 0 || (result.messages.length === 0 && !signal?.aborted);
692
+ if (isFailed && MAX_RETRIES > 0 && !signal?.aborted) {
693
+ result = await runSingleAgent(
831
694
  ctx.cwd,
832
695
  agents,
833
696
  t.agent,
@@ -843,12 +706,6 @@ export default function (pi: ExtensionAPI) {
843
706
  },
844
707
  makeDetails("parallel"),
845
708
  );
846
- let result = await runTask();
847
-
848
- // Auto-retry failed tasks (likely API rate limit or transient error)
849
- const isFailed = result.exitCode !== 0 || (result.messages.length === 0 && !signal?.aborted);
850
- if (isFailed && MAX_RETRIES > 0 && !signal?.aborted) {
851
- result = await runTask();
852
709
  }
853
710
 
854
711
  updateWorker(workerId, result.exitCode === 0 ? "completed" : "failed");
@@ -887,31 +744,17 @@ export default function (pi: ExtensionAPI) {
887
744
  isolation = await createIsolation(effectiveCwd, taskId, isolationMode);
888
745
  }
889
746
 
890
- const result = cmuxSplitsEnabled
891
- ? await runSingleAgentInCmuxSplit(
892
- cmuxClient,
893
- "right",
894
- ctx.cwd,
895
- agents,
896
- params.agent,
897
- params.task,
898
- isolation ? isolation.workDir : params.cwd,
899
- undefined,
900
- signal,
901
- onUpdate,
902
- makeDetails("single"),
903
- )
904
- : await runSingleAgent(
905
- ctx.cwd,
906
- agents,
907
- params.agent,
908
- params.task,
909
- isolation ? isolation.workDir : params.cwd,
910
- undefined,
911
- signal,
912
- onUpdate,
913
- makeDetails("single"),
914
- );
747
+ const result = await runSingleAgent(
748
+ ctx.cwd,
749
+ agents,
750
+ params.agent,
751
+ params.task,
752
+ isolation ? isolation.workDir : params.cwd,
753
+ undefined,
754
+ signal,
755
+ onUpdate,
756
+ makeDetails("single"),
757
+ );
915
758
 
916
759
  // Capture and merge delta if isolated
917
760
  if (isolation) {