@teammates/cli 0.1.0 → 0.2.0
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 +31 -22
- package/dist/adapter.d.ts +1 -1
- package/dist/adapter.js +68 -56
- package/dist/adapter.test.js +34 -21
- package/dist/adapters/cli-proxy.d.ts +11 -4
- package/dist/adapters/cli-proxy.js +176 -162
- package/dist/adapters/copilot.d.ts +50 -0
- package/dist/adapters/copilot.js +210 -0
- package/dist/adapters/echo.d.ts +2 -2
- package/dist/adapters/echo.js +2 -1
- package/dist/adapters/echo.test.js +4 -2
- package/dist/cli-utils.d.ts +21 -0
- package/dist/cli-utils.js +74 -0
- package/dist/cli-utils.test.d.ts +1 -0
- package/dist/cli-utils.test.js +179 -0
- package/dist/cli.js +3160 -961
- package/dist/compact.d.ts +39 -0
- package/dist/compact.js +269 -0
- package/dist/compact.test.d.ts +1 -0
- package/dist/compact.test.js +198 -0
- package/dist/console/ansi.d.ts +18 -0
- package/dist/console/ansi.js +20 -0
- package/dist/console/ansi.test.d.ts +1 -0
- package/dist/console/ansi.test.js +50 -0
- package/dist/console/dropdown.d.ts +23 -0
- package/dist/console/dropdown.js +63 -0
- package/dist/console/file-drop.d.ts +59 -0
- package/dist/console/file-drop.js +186 -0
- package/dist/console/file-drop.test.d.ts +1 -0
- package/dist/console/file-drop.test.js +145 -0
- package/dist/console/index.d.ts +22 -0
- package/dist/console/index.js +23 -0
- package/dist/console/interactive-readline.d.ts +65 -0
- package/dist/console/interactive-readline.js +132 -0
- package/dist/console/markdown-table.d.ts +17 -0
- package/dist/console/markdown-table.js +270 -0
- package/dist/console/markdown-table.test.d.ts +1 -0
- package/dist/console/markdown-table.test.js +130 -0
- package/dist/console/mutable-output.d.ts +21 -0
- package/dist/console/mutable-output.js +51 -0
- package/dist/console/paste-handler.d.ts +63 -0
- package/dist/console/paste-handler.js +177 -0
- package/dist/console/prompt-box.d.ts +55 -0
- package/dist/console/prompt-box.js +120 -0
- package/dist/console/prompt-input.d.ts +136 -0
- package/dist/console/prompt-input.js +618 -0
- package/dist/console/startup.d.ts +20 -0
- package/dist/console/startup.js +138 -0
- package/dist/console/startup.test.d.ts +1 -0
- package/dist/console/startup.test.js +41 -0
- package/dist/console/wordwheel.d.ts +75 -0
- package/dist/console/wordwheel.js +123 -0
- package/dist/dropdown.js +4 -21
- package/dist/index.d.ts +5 -5
- package/dist/index.js +3 -3
- package/dist/onboard.d.ts +24 -0
- package/dist/onboard.js +174 -11
- package/dist/orchestrator.d.ts +8 -11
- package/dist/orchestrator.js +33 -81
- package/dist/orchestrator.test.js +59 -79
- package/dist/registry.d.ts +1 -1
- package/dist/registry.js +56 -12
- package/dist/registry.test.js +57 -13
- package/dist/theme.d.ts +56 -0
- package/dist/theme.js +54 -0
- package/dist/types.d.ts +18 -13
- package/package.json +8 -3
- package/template/CROSS-TEAM.md +2 -2
- package/template/PROTOCOL.md +72 -15
- package/template/README.md +2 -2
- package/template/TEMPLATE.md +118 -15
- package/template/example/SOUL.md +2 -1
- package/template/example/WISDOM.md +9 -0
- package/dist/adapters/codex.d.ts +0 -50
- package/dist/adapters/codex.js +0 -213
- package/template/example/MEMORIES.md +0 -26
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @teammates/cli
|
|
2
2
|
|
|
3
|
+
> Part of the [teammates](https://github.com/Stevenic/teammates) monorepo.
|
|
4
|
+
|
|
3
5
|
Agent-agnostic CLI orchestrator for teammates. Routes tasks to teammates, manages handoffs, and plugs into any coding agent backend.
|
|
4
6
|
|
|
5
7
|
## Quick Start
|
|
@@ -53,16 +55,17 @@ Once inside the REPL, you can interact with teammates using `@mentions`, `/comma
|
|
|
53
55
|
|
|
54
56
|
| Command | Aliases | Description |
|
|
55
57
|
|---|---|---|
|
|
56
|
-
| `/
|
|
57
|
-
| `/status` | `/s` | Show teammate roster and session status |
|
|
58
|
-
| `/teammates` | `/team`, `/t` | List all teammates and their roles |
|
|
58
|
+
| `/status` | `/s`, `/queue`, `/qu` | Show teammates, active tasks, and queue |
|
|
59
59
|
| `/log [teammate]` | `/l` | Show the last task result (optionally for a specific teammate) |
|
|
60
60
|
| `/debug [teammate]` | `/raw` | Show raw agent output from the last task |
|
|
61
|
-
| `/queue @teammate <task>` | `/qu` | Add a task to the background queue |
|
|
62
|
-
| `/queue` | `/qu` | Show the current queue |
|
|
63
61
|
| `/cancel <n>` | | Cancel a queued task by number |
|
|
64
|
-
| `/
|
|
65
|
-
| `/
|
|
62
|
+
| `/init` | `/onboard`, `/setup` | Run onboarding to set up teammates for this project |
|
|
63
|
+
| `/install <service>` | | Install a teammates service (e.g. `recall`) |
|
|
64
|
+
| `/compact [teammate]` | | Compact daily logs into weekly/monthly summaries |
|
|
65
|
+
| `/retro [teammate]` | | Run a structured self-retrospective for a teammate |
|
|
66
|
+
| `/copy` | `/cp` | Copy the last response to clipboard |
|
|
67
|
+
| `/theme` | | Show current theme colors |
|
|
68
|
+
| `/clear` | `/cls`, `/reset` | Clear history and reset the session |
|
|
66
69
|
| `/help` | `/h`, `/?` | Show available commands |
|
|
67
70
|
| `/exit` | `/q`, `/quit` | Exit the session |
|
|
68
71
|
|
|
@@ -87,7 +90,16 @@ Queued tasks drain one at a time. If a handoff requires approval, the queue paus
|
|
|
87
90
|
|
|
88
91
|
## Handoffs
|
|
89
92
|
|
|
90
|
-
|
|
93
|
+
Teammates propose handoffs by including fenced handoff blocks in their response:
|
|
94
|
+
|
|
95
|
+
````
|
|
96
|
+
```handoff
|
|
97
|
+
@beacon
|
|
98
|
+
Update the search index to support the new memory format
|
|
99
|
+
```
|
|
100
|
+
````
|
|
101
|
+
|
|
102
|
+
Multiple handoff blocks can appear anywhere in a single response. The CLI detects them automatically and presents each one with an approval menu:
|
|
91
103
|
|
|
92
104
|
```
|
|
93
105
|
1) Approve — execute the handoff
|
|
@@ -95,7 +107,7 @@ When a teammate finishes a task, it may propose a handoff to another teammate. T
|
|
|
95
107
|
3) Reject — decline the handoff
|
|
96
108
|
```
|
|
97
109
|
|
|
98
|
-
|
|
110
|
+
Each handoff is approved individually — there is no automatic chaining.
|
|
99
111
|
|
|
100
112
|
## Conversation History
|
|
101
113
|
|
|
@@ -120,7 +132,7 @@ The CLI uses a generic adapter interface to support any coding agent. Each adapt
|
|
|
120
132
|
2. The prompt is written to a temp file
|
|
121
133
|
3. The agent CLI is spawned with the prompt
|
|
122
134
|
4. stdout/stderr are captured for result parsing
|
|
123
|
-
5. The output is parsed for
|
|
135
|
+
5. The output is parsed for embedded handoff blocks
|
|
124
136
|
6. Temp files are cleaned up
|
|
125
137
|
|
|
126
138
|
### Writing a Custom Adapter
|
|
@@ -155,7 +167,7 @@ Or add a preset to `cli-proxy.ts` for any CLI agent that accepts a prompt and ru
|
|
|
155
167
|
```
|
|
156
168
|
cli/src/
|
|
157
169
|
cli.ts # Entry point, REPL, slash commands, wordwheel UI
|
|
158
|
-
orchestrator.ts # Task routing,
|
|
170
|
+
orchestrator.ts # Task routing, session management
|
|
159
171
|
adapter.ts # AgentAdapter interface, prompt builder, handoff formatting
|
|
160
172
|
registry.ts # Discovers teammates from .teammates/, loads SOUL.md + memory
|
|
161
173
|
types.ts # Core types (TeammateConfig, TaskResult, HandoffEnvelope)
|
|
@@ -167,19 +179,16 @@ cli/src/
|
|
|
167
179
|
|
|
168
180
|
### Output Protocol
|
|
169
181
|
|
|
170
|
-
Agents
|
|
171
|
-
|
|
172
|
-
```json
|
|
173
|
-
{ "result": { "summary": "...", "changedFiles": ["..."] } }
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
Or for handoffs:
|
|
182
|
+
Agents format their response as a markdown message with a `# Subject` line. Handoffs are embedded as fenced code blocks:
|
|
177
183
|
|
|
178
|
-
|
|
179
|
-
|
|
184
|
+
````
|
|
185
|
+
```handoff
|
|
186
|
+
@<teammate>
|
|
187
|
+
<task description with full context>
|
|
180
188
|
```
|
|
189
|
+
````
|
|
181
190
|
|
|
182
|
-
The CLI parses
|
|
191
|
+
The CLI parses all `` ```handoff `` fences in the output. Multiple handoff blocks are supported in a single response. Each is presented to the user for individual approval.
|
|
183
192
|
|
|
184
193
|
## Testing
|
|
185
194
|
|
|
@@ -201,7 +210,7 @@ Tests use [Vitest](https://vitest.dev/) and cover the core modules:
|
|
|
201
210
|
| File | Covers |
|
|
202
211
|
|---|---|
|
|
203
212
|
| `src/adapter.test.ts` | `buildTeammatePrompt`, `formatHandoffContext` |
|
|
204
|
-
| `src/orchestrator.test.ts` | Task routing, assignment,
|
|
213
|
+
| `src/orchestrator.test.ts` | Task routing, assignment, reset |
|
|
205
214
|
| `src/registry.test.ts` | Teammate discovery, SOUL.md parsing (role, ownership), daily logs |
|
|
206
215
|
| `src/adapters/echo.test.ts` | Echo adapter session and task execution |
|
|
207
216
|
|
package/dist/adapter.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Each adapter wraps a specific agent backend (Codex, Claude Code, Cursor, etc.)
|
|
6
6
|
* and translates between the orchestrator's protocol and the agent's native API.
|
|
7
7
|
*/
|
|
8
|
-
import type {
|
|
8
|
+
import type { TaskResult, TeammateConfig } from "./types.js";
|
|
9
9
|
export interface AgentAdapter {
|
|
10
10
|
/** Human-readable name of the agent backend (e.g. "codex", "claude-code") */
|
|
11
11
|
readonly name: string;
|
package/dist/adapter.js
CHANGED
|
@@ -15,19 +15,27 @@ export function buildTeammatePrompt(teammate, taskPrompt, options) {
|
|
|
15
15
|
parts.push(`# You are ${teammate.name}\n`);
|
|
16
16
|
parts.push(teammate.soul);
|
|
17
17
|
parts.push("\n---\n");
|
|
18
|
-
// ──
|
|
19
|
-
if (teammate.
|
|
20
|
-
parts.push("## Your
|
|
21
|
-
parts.push(teammate.
|
|
18
|
+
// ── Wisdom ───────────────────────────────────────────────────────
|
|
19
|
+
if (teammate.wisdom.trim()) {
|
|
20
|
+
parts.push("## Your Wisdom\n");
|
|
21
|
+
parts.push(teammate.wisdom);
|
|
22
22
|
parts.push("\n---\n");
|
|
23
23
|
}
|
|
24
24
|
if (teammate.dailyLogs.length > 0) {
|
|
25
25
|
parts.push("## Recent Daily Logs\n");
|
|
26
|
-
for (const log of teammate.dailyLogs.slice(0,
|
|
26
|
+
for (const log of teammate.dailyLogs.slice(0, 7)) {
|
|
27
27
|
parts.push(`### ${log.date}\n${log.content}\n`);
|
|
28
28
|
}
|
|
29
29
|
parts.push("\n---\n");
|
|
30
30
|
}
|
|
31
|
+
// ── Weekly summaries (recent episodic context) ─────────────────────
|
|
32
|
+
if (teammate.weeklyLogs.length > 0) {
|
|
33
|
+
parts.push("## Recent Weekly Summaries\n");
|
|
34
|
+
for (const log of teammate.weeklyLogs.slice(0, 2)) {
|
|
35
|
+
parts.push(`### ${log.week}\n${log.content}\n`);
|
|
36
|
+
}
|
|
37
|
+
parts.push("\n---\n");
|
|
38
|
+
}
|
|
31
39
|
// ── Team roster ───────────────────────────────────────────────────
|
|
32
40
|
if (options?.roster && options.roster.length > 0) {
|
|
33
41
|
parts.push("## Your Team\n");
|
|
@@ -62,69 +70,73 @@ export function buildTeammatePrompt(teammate, taskPrompt, options) {
|
|
|
62
70
|
// ── Session state ────────────────────────────────────────────────
|
|
63
71
|
if (options?.sessionFile) {
|
|
64
72
|
parts.push("## Session State\n");
|
|
65
|
-
parts.push(`Your session file is at: \`${options.sessionFile}\`
|
|
66
|
-
|
|
67
|
-
**Read this file first** — it contains context from your prior tasks in this session.
|
|
68
|
-
|
|
69
|
-
**Before returning your result**, append a brief entry to this file with:
|
|
70
|
-
- What you did
|
|
71
|
-
- Key decisions made
|
|
72
|
-
- Files changed
|
|
73
|
-
- Anything the next task should know
|
|
74
|
-
|
|
75
|
-
This is how you maintain continuity across tasks. Always read it, always update it.
|
|
73
|
+
parts.push(`Your session file is at: \`${options.sessionFile}\`
|
|
74
|
+
|
|
75
|
+
**Read this file first** — it contains context from your prior tasks in this session.
|
|
76
|
+
|
|
77
|
+
**Before returning your result**, append a brief entry to this file with:
|
|
78
|
+
- What you did
|
|
79
|
+
- Key decisions made
|
|
80
|
+
- Files changed
|
|
81
|
+
- Anything the next task should know
|
|
82
|
+
|
|
83
|
+
This is how you maintain continuity across tasks. Always read it, always update it.
|
|
76
84
|
`);
|
|
77
85
|
parts.push("\n---\n");
|
|
78
86
|
}
|
|
79
87
|
// ── Memory updates ─────────────────────────────────────────────────
|
|
80
88
|
const today = new Date().toISOString().slice(0, 10);
|
|
81
89
|
parts.push("## Memory Updates\n");
|
|
82
|
-
parts.push(`**Before returning your result**, update your memory files:
|
|
83
|
-
|
|
84
|
-
1. **Daily log** — Read \`.teammates/${teammate.name}/memory/${today}.md\` first (it may have entries from earlier tasks today), then write it back with your entry added. Create the file if it doesn't exist.
|
|
85
|
-
- What you did
|
|
86
|
-
- Key decisions made
|
|
87
|
-
- Files changed
|
|
88
|
-
- Anything the next task should know
|
|
89
|
-
|
|
90
|
-
2. **
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
parts.push(`**Before returning your result**, update your memory files:
|
|
91
|
+
|
|
92
|
+
1. **Daily log** — Read \`.teammates/${teammate.name}/memory/${today}.md\` first (it may have entries from earlier tasks today), then write it back with your entry added. Create the file if it doesn't exist.
|
|
93
|
+
- What you did
|
|
94
|
+
- Key decisions made
|
|
95
|
+
- Files changed
|
|
96
|
+
- Anything the next task should know
|
|
97
|
+
|
|
98
|
+
2. **Typed memories** — If you learned something durable (a decision, pattern, feedback, or reference), create a typed memory file at \`.teammates/${teammate.name}/memory/<type>_<topic>.md\` with frontmatter (\`name\`, \`description\`, \`type\`). Update existing memory files if the topic already has one.
|
|
99
|
+
|
|
100
|
+
3. **WISDOM.md** — Do not edit directly. Wisdom entries are distilled from typed memories during compaction.
|
|
101
|
+
|
|
102
|
+
These files are your persistent memory. Without them, your next session starts from scratch.
|
|
93
103
|
`);
|
|
94
104
|
parts.push("\n---\n");
|
|
95
105
|
// ── Output protocol ───────────────────────────────────────────────
|
|
96
106
|
parts.push("## Output Protocol\n");
|
|
97
|
-
parts.push(`
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
\`\`\`
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
-
|
|
123
|
-
- Only hand off to teammates listed in "Your Team" above.
|
|
124
|
-
- Do as much of the work as you can before handing off.
|
|
125
|
-
- If the task is outside everyone's ownership, do your best and return a result.
|
|
107
|
+
parts.push(`Your response is a message. Format it as:
|
|
108
|
+
|
|
109
|
+
\`\`\`
|
|
110
|
+
TO: user
|
|
111
|
+
# <Subject line>
|
|
112
|
+
|
|
113
|
+
<Body — full markdown response>
|
|
114
|
+
\`\`\`
|
|
115
|
+
|
|
116
|
+
**Handoffs:** To hand off work to a teammate, include a fenced handoff block anywhere in your response:
|
|
117
|
+
|
|
118
|
+
\`\`\`
|
|
119
|
+
\`\`\`handoff
|
|
120
|
+
@<teammate>
|
|
121
|
+
<task description — what you need them to do, with full context>
|
|
122
|
+
\`\`\`
|
|
123
|
+
\`\`\`
|
|
124
|
+
|
|
125
|
+
**Rules:**
|
|
126
|
+
- The \`# Subject\` line is REQUIRED — it becomes the message title.
|
|
127
|
+
- Always write a substantive body. Never return just the subject.
|
|
128
|
+
- **Your final message MUST contain your response text.** Do not end your turn with only tool calls — always finish with a visible message to the user.
|
|
129
|
+
- Use markdown: headings, lists, code blocks, bold, etc.
|
|
130
|
+
- Do as much work as you can before handing off.
|
|
131
|
+
- Only hand off to teammates listed in "Your Team" above.
|
|
132
|
+
- The handoff block can appear anywhere in your response — it will be detected automatically.
|
|
126
133
|
`);
|
|
127
134
|
parts.push("\n---\n");
|
|
135
|
+
// ── Current date/time ────────────────────────────────────────────
|
|
136
|
+
const now = new Date();
|
|
137
|
+
parts.push(`**Current date:** ${now.toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" })} (${today})`);
|
|
138
|
+
parts.push(`**Current time:** ${now.toLocaleTimeString("en-US", { hour: "2-digit", minute: "2-digit" })}\n`);
|
|
139
|
+
parts.push("---\n");
|
|
128
140
|
// ── Task ──────────────────────────────────────────────────────────
|
|
129
141
|
parts.push("## Task\n");
|
|
130
142
|
parts.push(taskPrompt);
|
package/dist/adapter.test.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { describe,
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { buildTeammatePrompt, formatHandoffContext } from "./adapter.js";
|
|
3
3
|
function makeConfig(overrides) {
|
|
4
4
|
return {
|
|
5
5
|
name: "beacon",
|
|
6
6
|
role: "Platform engineer.",
|
|
7
7
|
soul: "# Beacon\n\nBeacon owns the recall package.",
|
|
8
|
-
|
|
8
|
+
wisdom: "",
|
|
9
9
|
dailyLogs: [],
|
|
10
|
+
weeklyLogs: [],
|
|
10
11
|
ownership: { primary: ["recall/src/**"], secondary: [] },
|
|
12
|
+
routingKeywords: [],
|
|
11
13
|
...overrides,
|
|
12
14
|
};
|
|
13
15
|
}
|
|
@@ -28,42 +30,53 @@ describe("buildTeammatePrompt", () => {
|
|
|
28
30
|
it("includes output protocol", () => {
|
|
29
31
|
const prompt = buildTeammatePrompt(makeConfig(), "task");
|
|
30
32
|
expect(prompt).toContain("## Output Protocol");
|
|
31
|
-
expect(prompt).toContain(
|
|
32
|
-
expect(prompt).toContain(
|
|
33
|
+
expect(prompt).toContain("TO: user");
|
|
34
|
+
expect(prompt).toContain("```handoff");
|
|
33
35
|
});
|
|
34
36
|
it("includes memory updates section", () => {
|
|
35
37
|
const prompt = buildTeammatePrompt(makeConfig(), "task");
|
|
36
38
|
expect(prompt).toContain("## Memory Updates");
|
|
37
39
|
expect(prompt).toContain(".teammates/beacon/memory/");
|
|
38
40
|
});
|
|
39
|
-
it("skips
|
|
40
|
-
const prompt = buildTeammatePrompt(makeConfig({
|
|
41
|
-
expect(prompt).not.toContain("## Your
|
|
41
|
+
it("skips wisdom section when empty", () => {
|
|
42
|
+
const prompt = buildTeammatePrompt(makeConfig({ wisdom: "" }), "task");
|
|
43
|
+
expect(prompt).not.toContain("## Your Wisdom");
|
|
42
44
|
});
|
|
43
|
-
it("includes
|
|
44
|
-
const prompt = buildTeammatePrompt(makeConfig({
|
|
45
|
-
expect(prompt).toContain("## Your
|
|
46
|
-
expect(prompt).toContain("Some important
|
|
45
|
+
it("includes wisdom when present", () => {
|
|
46
|
+
const prompt = buildTeammatePrompt(makeConfig({ wisdom: "Some important wisdom" }), "task");
|
|
47
|
+
expect(prompt).toContain("## Your Wisdom");
|
|
48
|
+
expect(prompt).toContain("Some important wisdom");
|
|
47
49
|
});
|
|
48
|
-
it("includes daily logs (up to
|
|
50
|
+
it("includes daily logs (up to 7)", () => {
|
|
49
51
|
const logs = [
|
|
50
|
-
{ date: "2026-03-13", content: "
|
|
51
|
-
{ date: "2026-03-12", content: "
|
|
52
|
-
{ date: "2026-03-11", content: "Day
|
|
53
|
-
{ date: "2026-03-10", content: "
|
|
52
|
+
{ date: "2026-03-13", content: "Day 1" },
|
|
53
|
+
{ date: "2026-03-12", content: "Day 2" },
|
|
54
|
+
{ date: "2026-03-11", content: "Day 3" },
|
|
55
|
+
{ date: "2026-03-10", content: "Day 4" },
|
|
56
|
+
{ date: "2026-03-09", content: "Day 5" },
|
|
57
|
+
{ date: "2026-03-08", content: "Day 6" },
|
|
58
|
+
{ date: "2026-03-07", content: "Day 7" },
|
|
59
|
+
{ date: "2026-03-06", content: "Should be excluded" },
|
|
54
60
|
];
|
|
55
61
|
const prompt = buildTeammatePrompt(makeConfig({ dailyLogs: logs }), "task");
|
|
56
62
|
expect(prompt).toContain("## Recent Daily Logs");
|
|
57
63
|
expect(prompt).toContain("2026-03-13");
|
|
58
|
-
expect(prompt).toContain("2026-03-
|
|
59
|
-
expect(prompt).toContain("2026-03-
|
|
60
|
-
expect(prompt).not.toContain("2026-03-10");
|
|
64
|
+
expect(prompt).toContain("2026-03-07");
|
|
65
|
+
expect(prompt).not.toContain("2026-03-06");
|
|
61
66
|
expect(prompt).not.toContain("Should be excluded");
|
|
62
67
|
});
|
|
63
68
|
it("includes roster excluding self", () => {
|
|
64
69
|
const roster = [
|
|
65
|
-
{
|
|
66
|
-
|
|
70
|
+
{
|
|
71
|
+
name: "beacon",
|
|
72
|
+
role: "Platform engineer.",
|
|
73
|
+
ownership: { primary: [], secondary: [] },
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
name: "scribe",
|
|
77
|
+
role: "Documentation writer.",
|
|
78
|
+
ownership: { primary: ["docs/**"], secondary: [] },
|
|
79
|
+
},
|
|
67
80
|
];
|
|
68
81
|
const prompt = buildTeammatePrompt(makeConfig(), "task", { roster });
|
|
69
82
|
expect(prompt).toContain("## Your Team");
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
* 3. Tees stdout/stderr to the user's terminal in real time
|
|
15
15
|
* 4. Captures output for result parsing (changed files, handoff envelopes)
|
|
16
16
|
*/
|
|
17
|
-
import type { AgentAdapter,
|
|
18
|
-
import type {
|
|
17
|
+
import type { AgentAdapter, InstalledService, RosterEntry } from "../adapter.js";
|
|
18
|
+
import type { SandboxLevel, TaskResult, TeammateConfig } from "../types.js";
|
|
19
19
|
export interface AgentPreset {
|
|
20
20
|
/** Display name */
|
|
21
21
|
name: string;
|
|
@@ -32,6 +32,10 @@ export interface AgentPreset {
|
|
|
32
32
|
interactive?: boolean;
|
|
33
33
|
/** Whether the command needs shell: true to run */
|
|
34
34
|
shell?: boolean;
|
|
35
|
+
/** Whether to pipe the prompt via stdin instead of as a CLI argument */
|
|
36
|
+
stdinPrompt?: boolean;
|
|
37
|
+
/** Optional output parser — transforms raw stdout into clean agent output */
|
|
38
|
+
parseOutput?(raw: string): string;
|
|
35
39
|
}
|
|
36
40
|
export declare const PRESETS: Record<string, AgentPreset>;
|
|
37
41
|
export interface CliProxyOptions {
|
|
@@ -64,11 +68,14 @@ export declare class CliProxyAdapter implements AgentAdapter {
|
|
|
64
68
|
private pendingTempFiles;
|
|
65
69
|
constructor(options: CliProxyOptions);
|
|
66
70
|
startSession(teammate: TeammateConfig): Promise<string>;
|
|
67
|
-
executeTask(
|
|
71
|
+
executeTask(_sessionId: string, teammate: TeammateConfig, prompt: string): Promise<TaskResult>;
|
|
68
72
|
routeTask(task: string, roster: RosterEntry[]): Promise<string | null>;
|
|
69
|
-
destroySession(
|
|
73
|
+
destroySession(_sessionId: string): Promise<void>;
|
|
70
74
|
/**
|
|
71
75
|
* Spawn the agent, stream its output live, and capture it.
|
|
72
76
|
*/
|
|
73
77
|
private spawnAndProxy;
|
|
74
78
|
}
|
|
79
|
+
export declare function parseResult(teammateName: string, output: string, teammateNames?: string[], _originalTask?: string): TaskResult;
|
|
80
|
+
/** Extract file paths from agent output. */
|
|
81
|
+
export declare function parseChangedFiles(output: string): string[];
|