Skip to content

Commit d2778b5

Browse files
macclaude
authored andcommitted
refactor: unify executeSkill and executeSkillForAcp
Merge the two functions into a single executeSkill with a captureOutput option. When captureOutput is true, stdout/stderr are captured and returned as a string (ACP mode). When false (default), spinner UX is applied (interactive mode). executeSkillForAcp is kept as a thin backward-compatible alias. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 80ea7b5 commit d2778b5

1 file changed

Lines changed: 43 additions & 41 deletions

File tree

src/skills/executor.ts

Lines changed: 43 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export interface ExecuteOptions {
1818
cwd: string;
1919
config: DexConfig;
2020
logger: Logger;
21+
captureOutput?: boolean;
2122
}
2223

2324
async function collectContext(
@@ -130,17 +131,52 @@ function buildSkillContext(
130131
export async function executeSkill(
131132
skill: LoadedSkill,
132133
opts: ExecuteOptions,
133-
): Promise<void> {
134+
): Promise<string | void> {
134135
const { manifest, handler } = skill;
135136
const logger = opts.logger.child(manifest.name);
137+
const captureOutput = opts.captureOutput ?? false;
136138

137139
const context = await collectContext(manifest.inputs.context ?? [], opts);
138140
const agent = createAgent(opts.config);
139-
const ctx = buildSkillContext(skill, context, agent, opts);
141+
const manifestAgent = manifest.agent;
142+
143+
if (captureOutput) {
144+
// ACP mode: wrap agent without spinner, capture stdout/stderr
145+
const realAgent = agent;
146+
const capturingAgent: AgentInterface = {
147+
async *query(prompt, options) {
148+
for await (const msg of realAgent.query(prompt, options)) {
149+
yield msg;
150+
}
151+
},
152+
};
153+
154+
const ctx = buildSkillContext(skill, context, capturingAgent, opts);
140155

141-
// Inject manifest agent config + spinner UX
156+
const chunks: string[] = [];
157+
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
158+
const originalStderrWrite = process.stderr.write.bind(process.stderr);
159+
160+
const capture = (chunk: string | Uint8Array, ...args: unknown[]) => {
161+
chunks.push(String(chunk));
162+
return true;
163+
};
164+
165+
process.stdout.write = capture;
166+
process.stderr.write = capture;
167+
try {
168+
await handler(ctx);
169+
} finally {
170+
process.stdout.write = originalStdoutWrite;
171+
process.stderr.write = originalStderrWrite;
172+
}
173+
174+
return chunks.join("");
175+
}
176+
177+
// Interactive mode: spinner UX
178+
const ctx = buildSkillContext(skill, context, agent, opts);
142179
const spinner = createSpinner();
143-
const manifestAgent = manifest.agent;
144180
let firstToken = false;
145181
const originalQuery = agent.query.bind(agent);
146182

@@ -191,45 +227,11 @@ export async function executeSkill(
191227

192228
/**
193229
* Execute a skill and capture output as a string (for ACP server).
230+
* Thin alias for executeSkill with captureOutput: true.
194231
*/
195232
export async function executeSkillForAcp(
196233
skill: LoadedSkill,
197-
opts: ExecuteOptions,
234+
opts: Omit<ExecuteOptions, "captureOutput">,
198235
): Promise<string> {
199-
const { manifest, handler } = skill;
200-
const logger = opts.logger.child(manifest.name);
201-
202-
const context = await collectContext(manifest.inputs.context ?? [], opts);
203-
const realAgent = createAgent(opts.config);
204-
205-
const capturingAgent: AgentInterface = {
206-
async *query(prompt, options) {
207-
for await (const msg of realAgent.query(prompt, options)) {
208-
yield msg;
209-
}
210-
},
211-
};
212-
213-
const ctx = buildSkillContext(skill, context, capturingAgent, opts);
214-
215-
// Capture both stdout and stderr
216-
const chunks: string[] = [];
217-
const originalStdoutWrite = process.stdout.write.bind(process.stdout);
218-
const originalStderrWrite = process.stderr.write.bind(process.stderr);
219-
220-
const capture = (chunk: string | Uint8Array, ...args: unknown[]) => {
221-
chunks.push(String(chunk));
222-
return true;
223-
};
224-
225-
process.stdout.write = capture;
226-
process.stderr.write = capture;
227-
try {
228-
await handler(ctx);
229-
} finally {
230-
process.stdout.write = originalStdoutWrite;
231-
process.stderr.write = originalStderrWrite;
232-
}
233-
234-
return chunks.join("");
236+
return (await executeSkill(skill, { ...opts, captureOutput: true })) as string;
235237
}

0 commit comments

Comments
 (0)