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.
- package/README.md +3 -1
- package/dist/cli.js +7 -2
- package/dist/resource-loader.d.ts +1 -1
- package/dist/resource-loader.js +13 -1
- package/dist/resources/extensions/async-jobs/await-tool.js +0 -2
- package/dist/resources/extensions/async-jobs/job-manager.js +0 -6
- package/dist/resources/extensions/bg-shell/output-formatter.js +1 -19
- package/dist/resources/extensions/bg-shell/process-manager.js +0 -4
- package/dist/resources/extensions/bg-shell/types.js +0 -2
- package/dist/resources/extensions/cmux/index.js +321 -0
- package/dist/resources/extensions/context7/index.js +5 -0
- package/dist/resources/extensions/get-secrets-from-user.js +2 -30
- package/dist/resources/extensions/google-search/index.js +5 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +334 -104
- package/dist/resources/extensions/gsd/auto-dispatch.js +43 -1
- package/dist/resources/extensions/gsd/auto-loop.js +28 -3
- package/dist/resources/extensions/gsd/auto-model-selection.js +15 -3
- package/dist/resources/extensions/gsd/auto-recovery.js +35 -0
- package/dist/resources/extensions/gsd/auto-start.js +35 -2
- package/dist/resources/extensions/gsd/auto.js +75 -4
- package/dist/resources/extensions/gsd/commands-cmux.js +120 -0
- package/dist/resources/extensions/gsd/commands-handlers.js +2 -2
- package/dist/resources/extensions/gsd/commands-inspect.js +10 -3
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +1 -1
- package/dist/resources/extensions/gsd/commands-rate.js +31 -0
- package/dist/resources/extensions/gsd/commands.js +94 -2
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +25 -0
- package/dist/resources/extensions/gsd/doctor-environment.js +26 -17
- package/dist/resources/extensions/gsd/files.js +11 -2
- package/dist/resources/extensions/gsd/gitignore.js +54 -7
- package/dist/resources/extensions/gsd/guided-flow.js +8 -2
- package/dist/resources/extensions/gsd/health-widget-core.js +96 -0
- package/dist/resources/extensions/gsd/health-widget.js +97 -46
- package/dist/resources/extensions/gsd/index.js +31 -33
- package/dist/resources/extensions/gsd/migrate-external.js +55 -2
- package/dist/resources/extensions/gsd/milestone-ids.js +3 -2
- package/dist/resources/extensions/gsd/notifications.js +10 -1
- package/dist/resources/extensions/gsd/paths.js +74 -7
- package/dist/resources/extensions/gsd/post-unit-hooks.js +4 -1
- package/dist/resources/extensions/gsd/preferences-types.js +2 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +45 -1
- package/dist/resources/extensions/gsd/preferences.js +15 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
- package/dist/resources/extensions/gsd/prompts/research-milestone.md +4 -3
- package/dist/resources/extensions/gsd/prompts/research-slice.md +3 -2
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
- package/dist/resources/extensions/gsd/roadmap-mutations.js +55 -0
- package/dist/resources/extensions/gsd/session-lock.js +53 -2
- package/dist/resources/extensions/gsd/state.js +2 -1
- package/dist/resources/extensions/gsd/templates/plan.md +8 -0
- package/dist/resources/extensions/gsd/templates/preferences.md +6 -0
- package/dist/resources/extensions/gsd/worktree-resolver.js +12 -0
- package/dist/resources/extensions/remote-questions/remote-command.js +2 -22
- package/dist/resources/extensions/search-the-web/native-search.js +45 -4
- package/dist/resources/extensions/shared/mod.js +1 -1
- package/dist/resources/extensions/shared/sanitize.js +30 -0
- package/dist/resources/extensions/shared/terminal.js +5 -0
- package/dist/resources/extensions/subagent/index.js +186 -74
- package/dist/resources/skills/core-web-vitals/SKILL.md +1 -1
- package/dist/resources/skills/create-gsd-extension/workflows/debug-extension.md +1 -1
- package/dist/resources/skills/github-workflows/SKILL.md +0 -2
- package/dist/resources/skills/web-quality-audit/SKILL.md +0 -2
- package/package.json +2 -1
- package/packages/pi-agent-core/dist/agent.d.ts +10 -2
- package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent.js +19 -8
- package/packages/pi-agent-core/dist/agent.js.map +1 -1
- package/packages/pi-agent-core/src/agent.ts +31 -10
- package/packages/pi-ai/dist/providers/openai-responses.js +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/packages/pi-ai/src/providers/openai-responses.ts +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session.js +20 -4
- package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +13 -2
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session.ts +36 -12
- package/packages/pi-coding-agent/src/core/resource-loader.ts +13 -2
- package/packages/pi-tui/dist/terminal-image.d.ts.map +1 -1
- package/packages/pi-tui/dist/terminal-image.js +4 -0
- package/packages/pi-tui/dist/terminal-image.js.map +1 -1
- package/packages/pi-tui/src/terminal-image.ts +5 -0
- package/pkg/package.json +1 -1
- package/src/resources/extensions/async-jobs/await-tool.ts +0 -2
- package/src/resources/extensions/async-jobs/job-manager.ts +0 -7
- package/src/resources/extensions/bg-shell/output-formatter.ts +0 -17
- package/src/resources/extensions/bg-shell/process-manager.ts +0 -4
- package/src/resources/extensions/bg-shell/types.ts +0 -12
- package/src/resources/extensions/cmux/index.ts +384 -0
- package/src/resources/extensions/context7/index.ts +7 -0
- package/src/resources/extensions/get-secrets-from-user.ts +2 -35
- package/src/resources/extensions/google-search/index.ts +7 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +363 -116
- package/src/resources/extensions/gsd/auto-dispatch.ts +49 -1
- package/src/resources/extensions/gsd/auto-loop.ts +64 -2
- package/src/resources/extensions/gsd/auto-model-selection.ts +23 -2
- package/src/resources/extensions/gsd/auto-recovery.ts +39 -0
- package/src/resources/extensions/gsd/auto-start.ts +42 -2
- package/src/resources/extensions/gsd/auto.ts +82 -3
- package/src/resources/extensions/gsd/commands-cmux.ts +143 -0
- package/src/resources/extensions/gsd/commands-handlers.ts +2 -2
- package/src/resources/extensions/gsd/commands-inspect.ts +10 -3
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +1 -1
- package/src/resources/extensions/gsd/commands-rate.ts +55 -0
- package/src/resources/extensions/gsd/commands.ts +97 -2
- package/src/resources/extensions/gsd/docs/preferences-reference.md +25 -0
- package/src/resources/extensions/gsd/doctor-environment.ts +26 -16
- package/src/resources/extensions/gsd/files.ts +12 -2
- package/src/resources/extensions/gsd/gitignore.ts +54 -7
- package/src/resources/extensions/gsd/guided-flow.ts +8 -2
- package/src/resources/extensions/gsd/health-widget-core.ts +129 -0
- package/src/resources/extensions/gsd/health-widget.ts +103 -59
- package/src/resources/extensions/gsd/index.ts +37 -32
- package/src/resources/extensions/gsd/migrate-external.ts +47 -2
- package/src/resources/extensions/gsd/milestone-ids.ts +3 -2
- package/src/resources/extensions/gsd/notifications.ts +10 -1
- package/src/resources/extensions/gsd/paths.ts +73 -7
- package/src/resources/extensions/gsd/post-unit-hooks.ts +5 -1
- package/src/resources/extensions/gsd/preferences-types.ts +13 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +42 -1
- package/src/resources/extensions/gsd/preferences.ts +18 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -0
- package/src/resources/extensions/gsd/prompts/research-milestone.md +4 -3
- package/src/resources/extensions/gsd/prompts/research-slice.md +3 -2
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +2 -0
- package/src/resources/extensions/gsd/roadmap-mutations.ts +66 -0
- package/src/resources/extensions/gsd/session-lock.ts +59 -2
- package/src/resources/extensions/gsd/state.ts +2 -1
- package/src/resources/extensions/gsd/templates/plan.md +8 -0
- package/src/resources/extensions/gsd/templates/preferences.md +6 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +2 -0
- package/src/resources/extensions/gsd/tests/cmux.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +214 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +158 -0
- package/src/resources/extensions/gsd/tests/paths.test.ts +113 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +35 -2
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/test-utils.ts +165 -0
- package/src/resources/extensions/gsd/tests/validate-directory.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +7 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +32 -0
- package/src/resources/extensions/gsd/worktree-resolver.ts +11 -0
- package/src/resources/extensions/remote-questions/remote-command.ts +2 -23
- package/src/resources/extensions/search-the-web/native-search.ts +50 -4
- package/src/resources/extensions/shared/mod.ts +1 -1
- package/src/resources/extensions/shared/sanitize.ts +36 -0
- package/src/resources/extensions/shared/terminal.ts +5 -0
- package/src/resources/extensions/subagent/index.ts +242 -91
- package/src/resources/skills/core-web-vitals/SKILL.md +1 -1
- package/src/resources/skills/create-gsd-extension/workflows/debug-extension.md +1 -1
- package/src/resources/skills/github-workflows/SKILL.md +0 -2
- package/src/resources/skills/web-quality-audit/SKILL.md +0 -2
- package/dist/resources/extensions/shared/wizard-ui.js +0 -478
- package/dist/resources/skills/swiftui/SKILL.md +0 -208
- package/dist/resources/skills/swiftui/references/animations.md +0 -921
- package/dist/resources/skills/swiftui/references/architecture.md +0 -1561
- package/dist/resources/skills/swiftui/references/layout-system.md +0 -1186
- package/dist/resources/skills/swiftui/references/navigation.md +0 -1492
- package/dist/resources/skills/swiftui/references/networking-async.md +0 -214
- package/dist/resources/skills/swiftui/references/performance.md +0 -1706
- package/dist/resources/skills/swiftui/references/platform-integration.md +0 -204
- package/dist/resources/skills/swiftui/references/state-management.md +0 -1443
- package/dist/resources/skills/swiftui/references/swiftdata.md +0 -297
- package/dist/resources/skills/swiftui/references/testing-debugging.md +0 -247
- package/dist/resources/skills/swiftui/references/uikit-appkit-interop.md +0 -218
- package/dist/resources/skills/swiftui/workflows/add-feature.md +0 -191
- package/dist/resources/skills/swiftui/workflows/build-new-app.md +0 -311
- package/dist/resources/skills/swiftui/workflows/debug-swiftui.md +0 -192
- package/dist/resources/skills/swiftui/workflows/optimize-performance.md +0 -197
- package/dist/resources/skills/swiftui/workflows/ship-app.md +0 -203
- package/dist/resources/skills/swiftui/workflows/write-tests.md +0 -235
- package/src/resources/extensions/shared/wizard-ui.ts +0 -551
- package/src/resources/skills/swiftui/SKILL.md +0 -208
- package/src/resources/skills/swiftui/references/animations.md +0 -921
- package/src/resources/skills/swiftui/references/architecture.md +0 -1561
- package/src/resources/skills/swiftui/references/layout-system.md +0 -1186
- package/src/resources/skills/swiftui/references/navigation.md +0 -1492
- package/src/resources/skills/swiftui/references/networking-async.md +0 -214
- package/src/resources/skills/swiftui/references/performance.md +0 -1706
- package/src/resources/skills/swiftui/references/platform-integration.md +0 -204
- package/src/resources/skills/swiftui/references/state-management.md +0 -1443
- package/src/resources/skills/swiftui/references/swiftdata.md +0 -297
- package/src/resources/skills/swiftui/references/testing-debugging.md +0 -247
- package/src/resources/skills/swiftui/references/uikit-appkit-interop.md +0 -218
- package/src/resources/skills/swiftui/workflows/add-feature.md +0 -191
- package/src/resources/skills/swiftui/workflows/build-new-app.md +0 -311
- package/src/resources/skills/swiftui/workflows/debug-swiftui.md +0 -192
- package/src/resources/skills/swiftui/workflows/optimize-performance.md +0 -197
- package/src/resources/skills/swiftui/workflows/ship-app.md +0 -203
- 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(`↑${
|
|
101
|
-
if (usage.output) parts.push(`↓${
|
|
102
|
-
if (usage.cacheRead) parts.push(`R${
|
|
103
|
-
if (usage.cacheWrite) parts.push(`W${
|
|
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:${
|
|
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)
|
|
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())
|
|
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
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
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 =
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
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
|
-
- [
|
|
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
|
|
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
|
|
|
@@ -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)
|