gsd-pi 2.35.0 → 2.36.0-dev.d612764

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 (194) hide show
  1. package/README.md +3 -1
  2. package/dist/cli.js +7 -2
  3. package/dist/resource-loader.d.ts +1 -1
  4. package/dist/resource-loader.js +13 -1
  5. package/dist/resources/extensions/async-jobs/await-tool.js +0 -2
  6. package/dist/resources/extensions/async-jobs/job-manager.js +0 -6
  7. package/dist/resources/extensions/bg-shell/output-formatter.js +1 -19
  8. package/dist/resources/extensions/bg-shell/process-manager.js +0 -4
  9. package/dist/resources/extensions/bg-shell/types.js +0 -2
  10. package/dist/resources/extensions/cmux/index.js +321 -0
  11. package/dist/resources/extensions/context7/index.js +5 -0
  12. package/dist/resources/extensions/get-secrets-from-user.js +2 -30
  13. package/dist/resources/extensions/google-search/index.js +5 -0
  14. package/dist/resources/extensions/gsd/auto-dashboard.js +334 -104
  15. package/dist/resources/extensions/gsd/auto-dispatch.js +43 -1
  16. package/dist/resources/extensions/gsd/auto-loop.js +28 -3
  17. package/dist/resources/extensions/gsd/auto-model-selection.js +15 -3
  18. package/dist/resources/extensions/gsd/auto-recovery.js +35 -0
  19. package/dist/resources/extensions/gsd/auto-start.js +35 -2
  20. package/dist/resources/extensions/gsd/auto.js +75 -4
  21. package/dist/resources/extensions/gsd/commands-cmux.js +120 -0
  22. package/dist/resources/extensions/gsd/commands-handlers.js +2 -2
  23. package/dist/resources/extensions/gsd/commands-inspect.js +10 -3
  24. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
  25. package/dist/resources/extensions/gsd/commands-rate.js +31 -0
  26. package/dist/resources/extensions/gsd/commands.js +94 -2
  27. package/dist/resources/extensions/gsd/docs/preferences-reference.md +25 -0
  28. package/dist/resources/extensions/gsd/doctor-environment.js +26 -17
  29. package/dist/resources/extensions/gsd/files.js +11 -2
  30. package/dist/resources/extensions/gsd/gitignore.js +54 -7
  31. package/dist/resources/extensions/gsd/guided-flow.js +8 -2
  32. package/dist/resources/extensions/gsd/health-widget-core.js +96 -0
  33. package/dist/resources/extensions/gsd/health-widget.js +97 -46
  34. package/dist/resources/extensions/gsd/index.js +31 -33
  35. package/dist/resources/extensions/gsd/migrate-external.js +55 -2
  36. package/dist/resources/extensions/gsd/milestone-ids.js +3 -2
  37. package/dist/resources/extensions/gsd/notifications.js +10 -1
  38. package/dist/resources/extensions/gsd/paths.js +74 -7
  39. package/dist/resources/extensions/gsd/post-unit-hooks.js +4 -1
  40. package/dist/resources/extensions/gsd/preferences-types.js +2 -0
  41. package/dist/resources/extensions/gsd/preferences-validation.js +45 -1
  42. package/dist/resources/extensions/gsd/preferences.js +15 -0
  43. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
  44. package/dist/resources/extensions/gsd/prompts/research-milestone.md +4 -3
  45. package/dist/resources/extensions/gsd/prompts/research-slice.md +3 -2
  46. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
  47. package/dist/resources/extensions/gsd/roadmap-mutations.js +55 -0
  48. package/dist/resources/extensions/gsd/session-lock.js +53 -2
  49. package/dist/resources/extensions/gsd/state.js +2 -1
  50. package/dist/resources/extensions/gsd/templates/plan.md +8 -0
  51. package/dist/resources/extensions/gsd/templates/preferences.md +6 -0
  52. package/dist/resources/extensions/gsd/worktree-resolver.js +12 -0
  53. package/dist/resources/extensions/remote-questions/remote-command.js +2 -22
  54. package/dist/resources/extensions/search-the-web/native-search.js +45 -4
  55. package/dist/resources/extensions/shared/mod.js +1 -1
  56. package/dist/resources/extensions/shared/sanitize.js +30 -0
  57. package/dist/resources/extensions/shared/terminal.js +5 -0
  58. package/dist/resources/extensions/subagent/index.js +186 -74
  59. package/dist/resources/skills/core-web-vitals/SKILL.md +1 -1
  60. package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +1 -1
  61. package/dist/resources/skills/github-workflows/SKILL.md +0 -2
  62. package/dist/resources/skills/web-quality-audit/SKILL.md +0 -2
  63. package/package.json +2 -1
  64. package/packages/pi-agent-core/dist/agent.d.ts +10 -2
  65. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  66. package/packages/pi-agent-core/dist/agent.js +19 -8
  67. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  68. package/packages/pi-agent-core/src/agent.ts +31 -10
  69. package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
  70. package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
  71. package/packages/pi-ai/src/providers/openai-responses.ts +1 -1
  72. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  73. package/packages/pi-coding-agent/dist/core/agent-session.js +20 -4
  74. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  75. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  76. package/packages/pi-coding-agent/dist/core/resource-loader.js +13 -2
  77. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  78. package/packages/pi-coding-agent/package.json +1 -1
  79. package/packages/pi-coding-agent/src/core/agent-session.ts +36 -12
  80. package/packages/pi-coding-agent/src/core/resource-loader.ts +13 -2
  81. package/packages/pi-tui/dist/terminal-image.d.ts.map +1 -1
  82. package/packages/pi-tui/dist/terminal-image.js +4 -0
  83. package/packages/pi-tui/dist/terminal-image.js.map +1 -1
  84. package/packages/pi-tui/src/terminal-image.ts +5 -0
  85. package/pkg/package.json +1 -1
  86. package/src/resources/extensions/async-jobs/await-tool.ts +0 -2
  87. package/src/resources/extensions/async-jobs/job-manager.ts +0 -7
  88. package/src/resources/extensions/bg-shell/output-formatter.ts +0 -17
  89. package/src/resources/extensions/bg-shell/process-manager.ts +0 -4
  90. package/src/resources/extensions/bg-shell/types.ts +0 -12
  91. package/src/resources/extensions/cmux/index.ts +384 -0
  92. package/src/resources/extensions/context7/index.ts +7 -0
  93. package/src/resources/extensions/get-secrets-from-user.ts +2 -35
  94. package/src/resources/extensions/google-search/index.ts +7 -0
  95. package/src/resources/extensions/gsd/auto-dashboard.ts +363 -116
  96. package/src/resources/extensions/gsd/auto-dispatch.ts +49 -1
  97. package/src/resources/extensions/gsd/auto-loop.ts +64 -2
  98. package/src/resources/extensions/gsd/auto-model-selection.ts +23 -2
  99. package/src/resources/extensions/gsd/auto-recovery.ts +39 -0
  100. package/src/resources/extensions/gsd/auto-start.ts +42 -2
  101. package/src/resources/extensions/gsd/auto.ts +82 -3
  102. package/src/resources/extensions/gsd/commands-cmux.ts +143 -0
  103. package/src/resources/extensions/gsd/commands-handlers.ts +2 -2
  104. package/src/resources/extensions/gsd/commands-inspect.ts +10 -3
  105. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
  106. package/src/resources/extensions/gsd/commands-rate.ts +55 -0
  107. package/src/resources/extensions/gsd/commands.ts +97 -2
  108. package/src/resources/extensions/gsd/docs/preferences-reference.md +25 -0
  109. package/src/resources/extensions/gsd/doctor-environment.ts +26 -16
  110. package/src/resources/extensions/gsd/files.ts +12 -2
  111. package/src/resources/extensions/gsd/gitignore.ts +54 -7
  112. package/src/resources/extensions/gsd/guided-flow.ts +8 -2
  113. package/src/resources/extensions/gsd/health-widget-core.ts +129 -0
  114. package/src/resources/extensions/gsd/health-widget.ts +103 -59
  115. package/src/resources/extensions/gsd/index.ts +37 -32
  116. package/src/resources/extensions/gsd/migrate-external.ts +47 -2
  117. package/src/resources/extensions/gsd/milestone-ids.ts +3 -2
  118. package/src/resources/extensions/gsd/notifications.ts +10 -1
  119. package/src/resources/extensions/gsd/paths.ts +73 -7
  120. package/src/resources/extensions/gsd/post-unit-hooks.ts +5 -1
  121. package/src/resources/extensions/gsd/preferences-types.ts +13 -0
  122. package/src/resources/extensions/gsd/preferences-validation.ts +42 -1
  123. package/src/resources/extensions/gsd/preferences.ts +18 -1
  124. package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
  125. package/src/resources/extensions/gsd/prompts/research-milestone.md +4 -3
  126. package/src/resources/extensions/gsd/prompts/research-slice.md +3 -2
  127. package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
  128. package/src/resources/extensions/gsd/roadmap-mutations.ts +66 -0
  129. package/src/resources/extensions/gsd/session-lock.ts +59 -2
  130. package/src/resources/extensions/gsd/state.ts +2 -1
  131. package/src/resources/extensions/gsd/templates/plan.md +8 -0
  132. package/src/resources/extensions/gsd/templates/preferences.md +6 -0
  133. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +2 -0
  134. package/src/resources/extensions/gsd/tests/cmux.test.ts +98 -0
  135. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +46 -0
  136. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +20 -0
  137. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +214 -0
  138. package/src/resources/extensions/gsd/tests/health-widget.test.ts +158 -0
  139. package/src/resources/extensions/gsd/tests/paths.test.ts +113 -0
  140. package/src/resources/extensions/gsd/tests/preferences.test.ts +35 -2
  141. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +26 -0
  142. package/src/resources/extensions/gsd/tests/test-utils.ts +165 -0
  143. package/src/resources/extensions/gsd/tests/validate-directory.test.ts +15 -0
  144. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +7 -0
  145. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +32 -0
  146. package/src/resources/extensions/gsd/worktree-resolver.ts +11 -0
  147. package/src/resources/extensions/remote-questions/remote-command.ts +2 -23
  148. package/src/resources/extensions/search-the-web/native-search.ts +50 -4
  149. package/src/resources/extensions/shared/mod.ts +1 -1
  150. package/src/resources/extensions/shared/sanitize.ts +36 -0
  151. package/src/resources/extensions/shared/terminal.ts +5 -0
  152. package/src/resources/extensions/subagent/index.ts +242 -91
  153. package/src/resources/skills/core-web-vitals/SKILL.md +1 -1
  154. package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +1 -1
  155. package/src/resources/skills/github-workflows/SKILL.md +0 -2
  156. package/src/resources/skills/web-quality-audit/SKILL.md +0 -2
  157. package/dist/resources/extensions/shared/wizard-ui.js +0 -478
  158. package/dist/resources/skills/swiftui/SKILL.md +0 -208
  159. package/dist/resources/skills/swiftui/references/animations.md +0 -921
  160. package/dist/resources/skills/swiftui/references/architecture.md +0 -1561
  161. package/dist/resources/skills/swiftui/references/layout-system.md +0 -1186
  162. package/dist/resources/skills/swiftui/references/navigation.md +0 -1492
  163. package/dist/resources/skills/swiftui/references/networking-async.md +0 -214
  164. package/dist/resources/skills/swiftui/references/performance.md +0 -1706
  165. package/dist/resources/skills/swiftui/references/platform-integration.md +0 -204
  166. package/dist/resources/skills/swiftui/references/state-management.md +0 -1443
  167. package/dist/resources/skills/swiftui/references/swiftdata.md +0 -297
  168. package/dist/resources/skills/swiftui/references/testing-debugging.md +0 -247
  169. package/dist/resources/skills/swiftui/references/uikit-appkit-interop.md +0 -218
  170. package/dist/resources/skills/swiftui/workflows/add-feature.md +0 -191
  171. package/dist/resources/skills/swiftui/workflows/build-new-app.md +0 -311
  172. package/dist/resources/skills/swiftui/workflows/debug-swiftui.md +0 -192
  173. package/dist/resources/skills/swiftui/workflows/optimize-performance.md +0 -197
  174. package/dist/resources/skills/swiftui/workflows/ship-app.md +0 -203
  175. package/dist/resources/skills/swiftui/workflows/write-tests.md +0 -235
  176. package/src/resources/extensions/shared/wizard-ui.ts +0 -551
  177. package/src/resources/skills/swiftui/SKILL.md +0 -208
  178. package/src/resources/skills/swiftui/references/animations.md +0 -921
  179. package/src/resources/skills/swiftui/references/architecture.md +0 -1561
  180. package/src/resources/skills/swiftui/references/layout-system.md +0 -1186
  181. package/src/resources/skills/swiftui/references/navigation.md +0 -1492
  182. package/src/resources/skills/swiftui/references/networking-async.md +0 -214
  183. package/src/resources/skills/swiftui/references/performance.md +0 -1706
  184. package/src/resources/skills/swiftui/references/platform-integration.md +0 -204
  185. package/src/resources/skills/swiftui/references/state-management.md +0 -1443
  186. package/src/resources/skills/swiftui/references/swiftdata.md +0 -297
  187. package/src/resources/skills/swiftui/references/testing-debugging.md +0 -247
  188. package/src/resources/skills/swiftui/references/uikit-appkit-interop.md +0 -218
  189. package/src/resources/skills/swiftui/workflows/add-feature.md +0 -191
  190. package/src/resources/skills/swiftui/workflows/build-new-app.md +0 -311
  191. package/src/resources/skills/swiftui/workflows/debug-swiftui.md +0 -192
  192. package/src/resources/skills/swiftui/workflows/optimize-performance.md +0 -197
  193. package/src/resources/skills/swiftui/workflows/ship-app.md +0 -203
  194. package/src/resources/skills/swiftui/workflows/write-tests.md +0 -235
@@ -23,6 +23,7 @@ import { StringEnum } from "@gsd/pi-ai";
23
23
  import { type ExtensionAPI, getMarkdownTheme } from "@gsd/pi-coding-agent";
24
24
  import { Container, Markdown, Spacer, Text } from "@gsd/pi-tui";
25
25
  import { Type } from "@sinclair/typebox";
26
+ import { formatTokenCount } from "../shared/mod.js";
26
27
  import { type AgentConfig, type AgentScope, discoverAgents } from "./agents.js";
27
28
  import {
28
29
  type IsolationEnvironment,
@@ -33,6 +34,8 @@ import {
33
34
  readIsolationMode,
34
35
  } from "./isolation.js";
35
36
  import { registerWorker, updateWorker } from "./worker-registry.js";
37
+ import { loadEffectiveGSDPreferences } from "../gsd/preferences.js";
38
+ import { CmuxClient, shellEscape } from "../cmux/index.js";
36
39
 
37
40
  const MAX_PARALLEL_TASKS = 8;
38
41
  const MAX_CONCURRENCY = 4;
@@ -76,13 +79,6 @@ async function stopLiveSubagents(): Promise<void> {
76
79
  }
77
80
  }
78
81
 
79
- function formatTokens(count: number): string {
80
- if (count < 1000) return count.toString();
81
- if (count < 10000) return `${(count / 1000).toFixed(1)}k`;
82
- if (count < 1000000) return `${Math.round(count / 1000)}k`;
83
- return `${(count / 1000000).toFixed(1)}M`;
84
- }
85
-
86
82
  function formatUsageStats(
87
83
  usage: {
88
84
  input: number;
@@ -97,13 +93,13 @@ function formatUsageStats(
97
93
  ): string {
98
94
  const parts: string[] = [];
99
95
  if (usage.turns) parts.push(`${usage.turns} turn${usage.turns > 1 ? "s" : ""}`);
100
- if (usage.input) parts.push(`↑${formatTokens(usage.input)}`);
101
- if (usage.output) parts.push(`↓${formatTokens(usage.output)}`);
102
- if (usage.cacheRead) parts.push(`R${formatTokens(usage.cacheRead)}`);
103
- if (usage.cacheWrite) parts.push(`W${formatTokens(usage.cacheWrite)}`);
96
+ if (usage.input) parts.push(`↑${formatTokenCount(usage.input)}`);
97
+ if (usage.output) parts.push(`↓${formatTokenCount(usage.output)}`);
98
+ if (usage.cacheRead) parts.push(`R${formatTokenCount(usage.cacheRead)}`);
99
+ if (usage.cacheWrite) parts.push(`W${formatTokenCount(usage.cacheWrite)}`);
104
100
  if (usage.cost) parts.push(`$${(Number(usage.cost) || 0).toFixed(4)}`);
105
101
  if (usage.contextTokens && usage.contextTokens > 0) {
106
- parts.push(`ctx:${formatTokens(usage.contextTokens)}`);
102
+ parts.push(`ctx:${formatTokenCount(usage.contextTokens)}`);
107
103
  }
108
104
  if (model) parts.push(model);
109
105
  return parts.join(" ");
@@ -263,6 +259,70 @@ function writePromptToTempFile(agentName: string, prompt: string): { dir: string
263
259
  return { dir: tmpDir, filePath };
264
260
  }
265
261
 
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
+
266
326
  type OnUpdateCallback = (partial: AgentToolResult<SubagentDetails>) => void;
267
327
 
268
328
  async function runSingleAgent(
@@ -292,10 +352,6 @@ async function runSingleAgent(
292
352
  };
293
353
  }
294
354
 
295
- const args: string[] = ["--mode", "json", "-p", "--no-session"];
296
- if (agent.model) args.push("--model", agent.model);
297
- if (agent.tools && agent.tools.length > 0) args.push("--tools", agent.tools.join(","));
298
-
299
355
  let tmpPromptDir: string | null = null;
300
356
  let tmpPromptPath: string | null = null;
301
357
 
@@ -325,10 +381,8 @@ async function runSingleAgent(
325
381
  const tmp = writePromptToTempFile(agent.name, agent.systemPrompt);
326
382
  tmpPromptDir = tmp.dir;
327
383
  tmpPromptPath = tmp.filePath;
328
- args.push("--append-system-prompt", tmpPromptPath);
329
384
  }
330
-
331
- args.push(`Task: ${task}`);
385
+ const args = buildSubagentProcessArgs(agent, task, tmpPromptPath);
332
386
  let wasAborted = false;
333
387
 
334
388
  const exitCode = await new Promise<number>((resolve) => {
@@ -342,48 +396,11 @@ async function runSingleAgent(
342
396
  liveSubagentProcesses.add(proc);
343
397
  let buffer = "";
344
398
 
345
- const processLine = (line: string) => {
346
- if (!line.trim()) return;
347
- let event: any;
348
- try {
349
- event = JSON.parse(line);
350
- } catch {
351
- return;
352
- }
353
-
354
- if (event.type === "message_end" && event.message) {
355
- const msg = event.message as Message;
356
- currentResult.messages.push(msg);
357
-
358
- if (msg.role === "assistant") {
359
- currentResult.usage.turns++;
360
- const usage = msg.usage;
361
- if (usage) {
362
- currentResult.usage.input += usage.input || 0;
363
- currentResult.usage.output += usage.output || 0;
364
- currentResult.usage.cacheRead += usage.cacheRead || 0;
365
- currentResult.usage.cacheWrite += usage.cacheWrite || 0;
366
- currentResult.usage.cost += usage.cost?.total || 0;
367
- currentResult.usage.contextTokens = usage.totalTokens || 0;
368
- }
369
- if (!currentResult.model && msg.model) currentResult.model = msg.model;
370
- if (msg.stopReason) currentResult.stopReason = msg.stopReason;
371
- if (msg.errorMessage) currentResult.errorMessage = msg.errorMessage;
372
- }
373
- emitUpdate();
374
- }
375
-
376
- if (event.type === "tool_result_end" && event.message) {
377
- currentResult.messages.push(event.message as Message);
378
- emitUpdate();
379
- }
380
- };
381
-
382
399
  proc.stdout.on("data", (data) => {
383
400
  buffer += data.toString();
384
401
  const lines = buffer.split("\n");
385
402
  buffer = lines.pop() || "";
386
- for (const line of lines) processLine(line);
403
+ for (const line of lines) processSubagentEventLine(line, currentResult, emitUpdate);
387
404
  });
388
405
 
389
406
  proc.stderr.on("data", (data) => {
@@ -392,7 +409,7 @@ async function runSingleAgent(
392
409
 
393
410
  proc.on("close", (code) => {
394
411
  liveSubagentProcesses.delete(proc);
395
- if (buffer.trim()) processLine(buffer);
412
+ if (buffer.trim()) processSubagentEventLine(buffer, currentResult, emitUpdate);
396
413
  resolve(code ?? 0);
397
414
  });
398
415
 
@@ -433,6 +450,120 @@ async function runSingleAgent(
433
450
  }
434
451
  }
435
452
 
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
+
436
567
  const TaskItem = Type.Object({
437
568
  agent: Type.String({ description: "Name of the agent to invoke" }),
438
569
  task: Type.String({ description: "Task to delegate to the agent" }),
@@ -517,6 +648,8 @@ export default function (pi: ExtensionAPI) {
517
648
  const discovery = discoverAgents(ctx.cwd, agentScope);
518
649
  const agents = discovery.agents;
519
650
  const confirmProjectAgents = params.confirmProjectAgents ?? false;
651
+ const cmuxClient = CmuxClient.fromPreferences(loadEffectiveGSDPreferences()?.preferences);
652
+ const cmuxSplitsEnabled = cmuxClient.getConfig().splits;
520
653
 
521
654
  // Resolve isolation mode
522
655
  const isolationMode = readIsolationMode();
@@ -675,28 +808,26 @@ export default function (pi: ExtensionAPI) {
675
808
  const batchSize = params.tasks.length;
676
809
  const results = await mapWithConcurrencyLimit(params.tasks, MAX_CONCURRENCY, async (t, index) => {
677
810
  const workerId = registerWorker(t.agent, t.task, index, batchSize, batchId);
678
- let result = await runSingleAgent(
679
- ctx.cwd,
680
- agents,
681
- t.agent,
682
- t.task,
683
- t.cwd,
684
- undefined,
685
- signal,
686
- // Per-task update callback
687
- (partial) => {
688
- if (partial.details?.results[0]) {
689
- allResults[index] = partial.details.results[0];
690
- emitParallelUpdate();
691
- }
692
- },
693
- makeDetails("parallel"),
694
- );
695
-
696
- // Auto-retry failed tasks (likely API rate limit or transient error)
697
- const isFailed = result.exitCode !== 0 || (result.messages.length === 0 && !signal?.aborted);
698
- if (isFailed && MAX_RETRIES > 0 && !signal?.aborted) {
699
- result = await runSingleAgent(
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(
700
831
  ctx.cwd,
701
832
  agents,
702
833
  t.agent,
@@ -712,6 +843,12 @@ export default function (pi: ExtensionAPI) {
712
843
  },
713
844
  makeDetails("parallel"),
714
845
  );
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();
715
852
  }
716
853
 
717
854
  updateWorker(workerId, result.exitCode === 0 ? "completed" : "failed");
@@ -750,17 +887,31 @@ export default function (pi: ExtensionAPI) {
750
887
  isolation = await createIsolation(effectiveCwd, taskId, isolationMode);
751
888
  }
752
889
 
753
- const result = await runSingleAgent(
754
- ctx.cwd,
755
- agents,
756
- params.agent,
757
- params.task,
758
- isolation ? isolation.workDir : params.cwd,
759
- undefined,
760
- signal,
761
- onUpdate,
762
- makeDetails("single"),
763
- );
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
+ );
764
915
 
765
916
  // Capture and merge delta if isolated
766
917
  if (isolation) {
@@ -438,4 +438,4 @@ startTransition(() => setExpensiveState(newValue));
438
438
  - [web.dev LCP](https://web.dev/articles/lcp)
439
439
  - [web.dev INP](https://web.dev/articles/inp)
440
440
  - [web.dev CLS](https://web.dev/articles/cls)
441
- - [Performance skill](../performance/SKILL.md)
441
+ - [Code Optimizer skill](../code-optimizer/SKILL.md)
@@ -42,7 +42,7 @@ The file must `export default function(pi: ExtensionAPI) { ... }`.
42
42
 
43
43
  ## Step 4: Check for Common Mistakes
44
44
 
45
- Read `references/key-rules-gotchas.md` and verify each rule against the extension code.
45
+ Read `../references/key-rules-gotchas.md` and verify each rule against the extension code.
46
46
 
47
47
  ## Step 5: Add Debugging
48
48
 
@@ -88,5 +88,3 @@ EVIDENCE: [output from ci_monitor.cjs]
88
88
  ## References
89
89
 
90
90
  - `references/gh/SKILL.md` — gh CLI reference
91
- - `scripts/ci_monitor.cjs` — CI monitoring tool
92
- - `scripts/ci_monitor.md` — Tool usage documentation
@@ -163,8 +163,6 @@ When performing an audit, structure findings as:
163
163
  ## References
164
164
 
165
165
  For detailed guidelines on specific areas:
166
- - [Performance Optimization](../performance/SKILL.md)
167
166
  - [Core Web Vitals](../core-web-vitals/SKILL.md)
168
167
  - [Accessibility](../accessibility/SKILL.md)
169
- - [SEO](../seo/SKILL.md)
170
168
  - [Best Practices](../best-practices/SKILL.md)