@teammates/cli 0.2.7 → 0.2.8
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/dist/adapters/cli-proxy.d.ts +21 -1
- package/dist/adapters/cli-proxy.js +40 -17
- package/dist/cli.js +41 -0
- package/dist/types.d.ts +13 -0
- package/package.json +1 -1
|
@@ -16,15 +16,33 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import type { AgentAdapter, InstalledService, RosterEntry } from "../adapter.js";
|
|
18
18
|
import type { SandboxLevel, TaskResult, TeammateConfig } from "../types.js";
|
|
19
|
+
/** Structured result from spawning an agent subprocess. */
|
|
20
|
+
export interface SpawnResult {
|
|
21
|
+
/** Combined stdout + stderr (for backward compat / display) */
|
|
22
|
+
output: string;
|
|
23
|
+
/** stdout only */
|
|
24
|
+
stdout: string;
|
|
25
|
+
/** stderr only */
|
|
26
|
+
stderr: string;
|
|
27
|
+
/** Process exit code (null if killed by signal) */
|
|
28
|
+
exitCode: number | null;
|
|
29
|
+
/** Signal that killed the process (null if exited normally) */
|
|
30
|
+
signal: string | null;
|
|
31
|
+
/** Whether the process was killed by our timeout */
|
|
32
|
+
timedOut: boolean;
|
|
33
|
+
/** Path to the debug log file, if one was written */
|
|
34
|
+
debugFile?: string;
|
|
35
|
+
}
|
|
19
36
|
export interface AgentPreset {
|
|
20
37
|
/** Display name */
|
|
21
38
|
name: string;
|
|
22
39
|
/** Binary / command to spawn */
|
|
23
40
|
command: string;
|
|
24
|
-
/** Build CLI args. `promptFile` is a temp file path, `prompt` is the raw text. */
|
|
41
|
+
/** Build CLI args. `promptFile` is a temp file path, `prompt` is the raw text, `debugFile` is an optional path for agent debug logs. */
|
|
25
42
|
buildArgs(ctx: {
|
|
26
43
|
promptFile: string;
|
|
27
44
|
prompt: string;
|
|
45
|
+
debugFile?: string;
|
|
28
46
|
}, teammate: TeammateConfig, options: CliProxyOptions): string[];
|
|
29
47
|
/** Extra env vars to set (e.g. FORCE_COLOR) */
|
|
30
48
|
env?: Record<string, string>;
|
|
@@ -34,6 +52,8 @@ export interface AgentPreset {
|
|
|
34
52
|
shell?: boolean;
|
|
35
53
|
/** Whether to pipe the prompt via stdin instead of as a CLI argument */
|
|
36
54
|
stdinPrompt?: boolean;
|
|
55
|
+
/** Whether this preset supports a debug log file (--debug-file) */
|
|
56
|
+
supportsDebugFile?: boolean;
|
|
37
57
|
/** Optional output parser — transforms raw stdout into clean agent output */
|
|
38
58
|
parseOutput?(raw: string): string;
|
|
39
59
|
}
|
|
@@ -24,14 +24,17 @@ export const PRESETS = {
|
|
|
24
24
|
claude: {
|
|
25
25
|
name: "claude",
|
|
26
26
|
command: "claude",
|
|
27
|
-
buildArgs(
|
|
27
|
+
buildArgs(ctx, _teammate, options) {
|
|
28
28
|
const args = ["-p", "--verbose", "--dangerously-skip-permissions"];
|
|
29
29
|
if (options.model)
|
|
30
30
|
args.push("--model", options.model);
|
|
31
|
+
if (ctx.debugFile)
|
|
32
|
+
args.push("--debug-file", ctx.debugFile);
|
|
31
33
|
return args;
|
|
32
34
|
},
|
|
33
35
|
env: { FORCE_COLOR: "1", CLAUDECODE: "" },
|
|
34
36
|
stdinPrompt: true,
|
|
37
|
+
supportsDebugFile: true,
|
|
35
38
|
},
|
|
36
39
|
codex: {
|
|
37
40
|
name: "codex",
|
|
@@ -167,12 +170,20 @@ export class CliProxyAdapter {
|
|
|
167
170
|
await writeFile(promptFile, fullPrompt, "utf-8");
|
|
168
171
|
this.pendingTempFiles.add(promptFile);
|
|
169
172
|
try {
|
|
170
|
-
const
|
|
173
|
+
const spawn = await this.spawnAndProxy(teammate, promptFile, fullPrompt);
|
|
171
174
|
const output = this.preset.parseOutput
|
|
172
|
-
? this.preset.parseOutput(
|
|
173
|
-
:
|
|
175
|
+
? this.preset.parseOutput(spawn.output)
|
|
176
|
+
: spawn.output;
|
|
174
177
|
const teammateNames = this.roster.map((r) => r.name);
|
|
175
|
-
|
|
178
|
+
const result = parseResult(teammate.name, output, teammateNames, prompt);
|
|
179
|
+
result.diagnostics = {
|
|
180
|
+
exitCode: spawn.exitCode,
|
|
181
|
+
signal: spawn.signal,
|
|
182
|
+
stderr: spawn.stderr,
|
|
183
|
+
timedOut: spawn.timedOut,
|
|
184
|
+
debugFile: spawn.debugFile,
|
|
185
|
+
};
|
|
186
|
+
return result;
|
|
176
187
|
}
|
|
177
188
|
finally {
|
|
178
189
|
this.pendingTempFiles.delete(promptFile);
|
|
@@ -291,8 +302,12 @@ export class CliProxyAdapter {
|
|
|
291
302
|
*/
|
|
292
303
|
spawnAndProxy(teammate, promptFile, fullPrompt) {
|
|
293
304
|
return new Promise((resolve, reject) => {
|
|
305
|
+
// Generate a debug log file path if the preset supports it
|
|
306
|
+
const debugFile = this.preset.supportsDebugFile
|
|
307
|
+
? join(tmpdir(), `teammates-debug-${teammate.name}-${Date.now()}.log`)
|
|
308
|
+
: undefined;
|
|
294
309
|
const args = [
|
|
295
|
-
...this.preset.buildArgs({ promptFile, prompt: fullPrompt }, teammate, this.options),
|
|
310
|
+
...this.preset.buildArgs({ promptFile, prompt: fullPrompt, debugFile }, teammate, this.options),
|
|
296
311
|
...(this.options.extraFlags ?? []),
|
|
297
312
|
];
|
|
298
313
|
const command = this.options.commandPath ?? this.preset.command;
|
|
@@ -352,12 +367,13 @@ export class CliProxyAdapter {
|
|
|
352
367
|
process.stdin.resume();
|
|
353
368
|
process.stdin.on("data", onUserInput);
|
|
354
369
|
}
|
|
355
|
-
const
|
|
370
|
+
const stdoutBufs = [];
|
|
371
|
+
const stderrBufs = [];
|
|
356
372
|
child.stdout?.on("data", (chunk) => {
|
|
357
|
-
|
|
373
|
+
stdoutBufs.push(chunk);
|
|
358
374
|
});
|
|
359
375
|
child.stderr?.on("data", (chunk) => {
|
|
360
|
-
|
|
376
|
+
stderrBufs.push(chunk);
|
|
361
377
|
});
|
|
362
378
|
const cleanup = () => {
|
|
363
379
|
clearTimeout(timeoutTimer);
|
|
@@ -367,15 +383,22 @@ export class CliProxyAdapter {
|
|
|
367
383
|
process.stdin.removeListener("data", onUserInput);
|
|
368
384
|
}
|
|
369
385
|
};
|
|
370
|
-
child.on("close", (
|
|
386
|
+
child.on("close", (code, signal) => {
|
|
371
387
|
cleanup();
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
388
|
+
const stdout = Buffer.concat(stdoutBufs).toString("utf-8");
|
|
389
|
+
const stderr = Buffer.concat(stderrBufs).toString("utf-8");
|
|
390
|
+
const output = stdout + (stderr ? `\n${stderr}` : "");
|
|
391
|
+
resolve({
|
|
392
|
+
output: killed
|
|
393
|
+
? `${output}\n\n[TIMEOUT] Agent process killed after ${timeout}ms`
|
|
394
|
+
: output,
|
|
395
|
+
stdout,
|
|
396
|
+
stderr,
|
|
397
|
+
exitCode: code,
|
|
398
|
+
signal: signal ?? null,
|
|
399
|
+
timedOut: killed,
|
|
400
|
+
debugFile,
|
|
401
|
+
});
|
|
379
402
|
});
|
|
380
403
|
child.on("error", (err) => {
|
|
381
404
|
cleanup();
|
package/dist/cli.js
CHANGED
|
@@ -2275,6 +2275,9 @@ Do NOT modify any other teammate's files. Only edit your own SOUL.md and daily l
|
|
|
2275
2275
|
}
|
|
2276
2276
|
}
|
|
2277
2277
|
});
|
|
2278
|
+
this.chatView.on("copy", (text) => {
|
|
2279
|
+
this.doCopy(text);
|
|
2280
|
+
});
|
|
2278
2281
|
this.chatView.on("link", (url) => {
|
|
2279
2282
|
const quoted = JSON.stringify(url);
|
|
2280
2283
|
const cmd = process.platform === "darwin"
|
|
@@ -2695,6 +2698,19 @@ Do NOT modify any other teammate's files. Only edit your own SOUL.md and daily l
|
|
|
2695
2698
|
else {
|
|
2696
2699
|
this.feedLine(tp.muted(" (no response text — the agent may have only performed tool actions)"));
|
|
2697
2700
|
this.feedLine(tp.muted(` Use /debug ${event.result.teammate} to view full output`));
|
|
2701
|
+
// Show diagnostic hints for empty responses
|
|
2702
|
+
const diag = event.result.diagnostics;
|
|
2703
|
+
if (diag) {
|
|
2704
|
+
if (diag.exitCode !== 0 && diag.exitCode !== null) {
|
|
2705
|
+
this.feedLine(tp.warning(` ⚠ Process exited with code ${diag.exitCode}`));
|
|
2706
|
+
}
|
|
2707
|
+
if (diag.signal) {
|
|
2708
|
+
this.feedLine(tp.warning(` ⚠ Process killed by signal: ${diag.signal}`));
|
|
2709
|
+
}
|
|
2710
|
+
if (diag.debugFile) {
|
|
2711
|
+
this.feedLine(tp.muted(` Debug log: ${diag.debugFile}`));
|
|
2712
|
+
}
|
|
2713
|
+
}
|
|
2698
2714
|
}
|
|
2699
2715
|
// Render handoffs
|
|
2700
2716
|
const handoffs = event.result.handoffs;
|
|
@@ -2984,6 +3000,31 @@ Do NOT modify any other teammate's files. Only edit your own SOUL.md and daily l
|
|
|
2984
3000
|
if (result.handoffs.length > 0) {
|
|
2985
3001
|
lines.push(`**Handoffs:** ${result.handoffs.map((h) => `@${h.to}`).join(", ")}`);
|
|
2986
3002
|
}
|
|
3003
|
+
// Process diagnostics — exit code, signal, stderr
|
|
3004
|
+
const diag = result.diagnostics;
|
|
3005
|
+
if (diag) {
|
|
3006
|
+
lines.push("");
|
|
3007
|
+
lines.push("### Process");
|
|
3008
|
+
lines.push(`**Exit code:** ${diag.exitCode ?? "(killed by signal)"}`);
|
|
3009
|
+
if (diag.signal)
|
|
3010
|
+
lines.push(`**Signal:** ${diag.signal}`);
|
|
3011
|
+
if (diag.timedOut)
|
|
3012
|
+
lines.push(`**Timed out:** yes`);
|
|
3013
|
+
if (diag.debugFile)
|
|
3014
|
+
lines.push(`**Debug log:** ${diag.debugFile}`);
|
|
3015
|
+
// Show stderr separately — this is where tool call output and errors go
|
|
3016
|
+
if (diag.stderr.trim()) {
|
|
3017
|
+
lines.push("");
|
|
3018
|
+
lines.push("<details><summary>stderr</summary>");
|
|
3019
|
+
lines.push("");
|
|
3020
|
+
lines.push(diag.stderr);
|
|
3021
|
+
lines.push("");
|
|
3022
|
+
lines.push("</details>");
|
|
3023
|
+
}
|
|
3024
|
+
else {
|
|
3025
|
+
lines.push(`**stderr:** (empty)`);
|
|
3026
|
+
}
|
|
3027
|
+
}
|
|
2987
3028
|
lines.push("");
|
|
2988
3029
|
lines.push("<details><summary>Raw output</summary>");
|
|
2989
3030
|
lines.push("");
|
package/dist/types.d.ts
CHANGED
|
@@ -68,6 +68,19 @@ export interface TaskResult {
|
|
|
68
68
|
handoffs: HandoffEnvelope[];
|
|
69
69
|
/** Raw output from the agent */
|
|
70
70
|
rawOutput?: string;
|
|
71
|
+
/** Process diagnostics for debugging empty/failed responses */
|
|
72
|
+
diagnostics?: {
|
|
73
|
+
/** Process exit code (null if killed by signal) */
|
|
74
|
+
exitCode: number | null;
|
|
75
|
+
/** Signal that killed the process (null if exited normally) */
|
|
76
|
+
signal: string | null;
|
|
77
|
+
/** stderr output (separate from stdout) */
|
|
78
|
+
stderr: string;
|
|
79
|
+
/** Whether the process was killed by timeout */
|
|
80
|
+
timedOut: boolean;
|
|
81
|
+
/** Path to the agent's debug log file, if written */
|
|
82
|
+
debugFile?: string;
|
|
83
|
+
};
|
|
71
84
|
}
|
|
72
85
|
/** Task assignment to a teammate */
|
|
73
86
|
export interface TaskAssignment {
|
package/package.json
CHANGED