@a5c-ai/babysitter-paperclip 0.0.2-staging.29187771
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/BABYSITTER.md +46 -0
- package/README.md +229 -0
- package/esbuild.config.mjs +12 -0
- package/package.json +29 -0
- package/src/__tests__/delegating-adapter.test.ts +85 -0
- package/src/__tests__/types.test.ts +29 -0
- package/src/babysitter-bridge.ts +313 -0
- package/src/delegating-adapter.ts +97 -0
- package/src/harness-plugin-installer.ts +202 -0
- package/src/manifest.ts +101 -0
- package/src/types.ts +130 -0
- package/src/ui/BabysitterDashboard.tsx +142 -0
- package/src/ui/BabysitterSidebar.tsx +123 -0
- package/src/ui/BreakpointApproval.tsx +212 -0
- package/src/ui/RunDetailTab.tsx +169 -0
- package/src/ui/index.tsx +9 -0
- package/src/ui/styles.ts +75 -0
- package/src/worker.ts +595 -0
- package/tsconfig.json +19 -0
- package/versions.json +3 -0
package/BABYSITTER.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Babysitter Paperclip Plugin
|
|
2
|
+
|
|
3
|
+
## Build
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
cd plugins/babysitter-paperclip
|
|
7
|
+
npm run build
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
Build uses esbuild (configured in `esbuild.config.mjs`). Output goes to `dist/`.
|
|
11
|
+
|
|
12
|
+
## Dev
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
cd plugins/babysitter-paperclip
|
|
16
|
+
npm run dev
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Starts the Paperclip plugin dev server on port 4177 with hot reload for UI components.
|
|
20
|
+
|
|
21
|
+
## Test
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
cd plugins/babysitter-paperclip
|
|
25
|
+
npm run test
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Uses vitest. Test files follow the `*.test.ts` convention in `__tests__/` directories.
|
|
29
|
+
|
|
30
|
+
## Key Files
|
|
31
|
+
|
|
32
|
+
| File | Role |
|
|
33
|
+
|------|------|
|
|
34
|
+
| `src/worker.ts` | Worker entry point -- event handlers, data handlers, action handlers, stream handler, tool registration |
|
|
35
|
+
| `src/manifest.ts` | Plugin manifest -- capabilities, event subscriptions, UI slots, settings schema |
|
|
36
|
+
| `src/babysitter-bridge.ts` | CLI bridge -- typed wrappers around `babysitter` CLI commands (`run:create`, `run:iterate`, `task:post`, etc.) |
|
|
37
|
+
| `src/delegating-adapter.ts` | Harness detection -- three-tier detection of underlying AI harness from Paperclip agent metadata |
|
|
38
|
+
| `src/types.ts` | Shared types -- `TrackedRun`, `PendingBreakpoint`, `RunsOverview`, `RunDetail`, `HarnessDetectionResult`, `ADAPTER_TYPE_MAP` |
|
|
39
|
+
| `src/ui/` | React UI components -- `BabysitterDashboard`, `RunDetailTab`, `BreakpointApproval`, `BabysitterSidebar` |
|
|
40
|
+
|
|
41
|
+
## Dependencies
|
|
42
|
+
|
|
43
|
+
- `@paperclipai/plugin-sdk` (peer, >=0.1.0) -- Paperclip plugin SDK
|
|
44
|
+
- `@a5c-ai/babysitter-sdk` (workspace) -- Babysitter SDK for types and utilities
|
|
45
|
+
- `react` / `react-dom` (dev, ^19.0.0) -- UI component rendering
|
|
46
|
+
- `esbuild` (dev) -- Build tooling
|
package/README.md
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
# @a5c-ai/babysitter-paperclip
|
|
2
|
+
|
|
3
|
+
Babysitter orchestration plugin for Paperclip AI. Integrates Babysitter's
|
|
4
|
+
deterministic, event-sourced orchestration with Paperclip's multi-agent
|
|
5
|
+
platform, providing run lifecycle management, breakpoint approval workflows,
|
|
6
|
+
and real-time observability through Paperclip's UI slot system.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
Install the Babysitter SDK CLI globally:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install -g @a5c-ai/babysitter-sdk
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Then install the plugin from the monorepo:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
cd babysitter
|
|
20
|
+
npm install
|
|
21
|
+
npm run build --workspace=@a5c-ai/babysitter-paperclip
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
In Paperclip, register the plugin by pointing to the built `dist/` output or
|
|
25
|
+
by adding `@a5c-ai/babysitter-paperclip` to your Paperclip workspace plugin
|
|
26
|
+
list.
|
|
27
|
+
|
|
28
|
+
## Configuration
|
|
29
|
+
|
|
30
|
+
Settings are declared in the plugin manifest and configurable through
|
|
31
|
+
Paperclip's plugin settings UI:
|
|
32
|
+
|
|
33
|
+
| Setting | Type | Default | Description |
|
|
34
|
+
|---------|------|---------|-------------|
|
|
35
|
+
| `runsDir` | string | `.a5c/runs` | Directory where babysitter run data is stored |
|
|
36
|
+
| `autoIterate` | boolean | `true` | Automatically iterate runs when effects are resolved |
|
|
37
|
+
| `maxIterations` | number | `256` | Maximum orchestration iterations per run |
|
|
38
|
+
| `breakpointTimeout` | number | `3600000` | Time to wait for breakpoint approval (ms, default 1 hour) |
|
|
39
|
+
|
|
40
|
+
## Architecture Overview
|
|
41
|
+
|
|
42
|
+
### Delegating Adapter Model
|
|
43
|
+
|
|
44
|
+
Paperclip wraps multiple AI harnesses (Claude Code, Codex, Gemini CLI, Cursor,
|
|
45
|
+
GitHub Copilot, etc.). The plugin detects which underlying harness each agent
|
|
46
|
+
uses through a three-tier detection system:
|
|
47
|
+
|
|
48
|
+
1. **Agent metadata (high confidence)** -- Maps the Paperclip agent
|
|
49
|
+
`adapterType` field to a babysitter harness name. Known mappings:
|
|
50
|
+
|
|
51
|
+
| Paperclip adapterType | Babysitter harness |
|
|
52
|
+
|-----------------------|-------------------|
|
|
53
|
+
| `claude_local` | `claude-code` |
|
|
54
|
+
| `codex_local` | `codex` |
|
|
55
|
+
| `gemini_local` | `gemini-cli` |
|
|
56
|
+
| `cursor_local` | `cursor` |
|
|
57
|
+
| `github_copilot` | `github-copilot` |
|
|
58
|
+
| `opencode_local` | `opencode` |
|
|
59
|
+
| `pi_local` | `pi` |
|
|
60
|
+
| `omp_local` | `oh-my-pi` |
|
|
61
|
+
|
|
62
|
+
2. **Environment variable probing (medium confidence)** -- Checks for known
|
|
63
|
+
harness signatures: `CLAUDE_CODE_SESSION`, `CODEX_SESSION`,
|
|
64
|
+
`GEMINI_CLI_SESSION`, `CURSOR_SESSION`, etc.
|
|
65
|
+
|
|
66
|
+
3. **Plugin config fallback (medium confidence)** -- Uses the `defaultHarness`
|
|
67
|
+
setting. If nothing matches, defaults to `claude-code` with low confidence.
|
|
68
|
+
|
|
69
|
+
### Worker
|
|
70
|
+
|
|
71
|
+
The worker (`src/worker.ts`) is the server-side entry point. It registers:
|
|
72
|
+
|
|
73
|
+
- **Event handlers** for `agent.run.started`, `agent.run.finished`,
|
|
74
|
+
`agent.run.failed`, and `agent.run.cancelled` lifecycle events
|
|
75
|
+
- **Data handlers** for `runs-overview`, `run-detail`, and
|
|
76
|
+
`pending-breakpoints` queries
|
|
77
|
+
- **Action handlers** for `approve-breakpoint`, `reject-breakpoint`, and
|
|
78
|
+
`create-run` operations
|
|
79
|
+
- **Stream handler** for `subscribe-run-events` (real-time journal events)
|
|
80
|
+
- **Tool** `babysitter-status` -- available to agents for checking run state
|
|
81
|
+
|
|
82
|
+
All babysitter operations go through the CLI bridge (`src/babysitter-bridge.ts`)
|
|
83
|
+
which shells out to the `babysitter` CLI with `--json` output.
|
|
84
|
+
|
|
85
|
+
### UI Components
|
|
86
|
+
|
|
87
|
+
The plugin registers three UI slots in Paperclip:
|
|
88
|
+
|
|
89
|
+
| Slot Type | Component | Description |
|
|
90
|
+
|-----------|-----------|-------------|
|
|
91
|
+
| `dashboardWidget` | `BabysitterDashboard` | Active runs overview with pending breakpoint badge count |
|
|
92
|
+
| `detailTab` | `RunDetailTab` | Journal timeline view with breakpoint approval/rejection forms (scoped to agent entities) |
|
|
93
|
+
| `sidebarPanel` | `BabysitterSidebar` | Compact run status sidebar |
|
|
94
|
+
|
|
95
|
+
## Event Flow
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
Paperclip Platform
|
|
99
|
+
+----------------------------------------------------------+
|
|
100
|
+
| |
|
|
101
|
+
| Agent starts run |
|
|
102
|
+
| | |
|
|
103
|
+
| v |
|
|
104
|
+
| agent.run.started -----> Worker: detectHarness() |
|
|
105
|
+
| | |
|
|
106
|
+
| v |
|
|
107
|
+
| Store harness |
|
|
108
|
+
| detection in |
|
|
109
|
+
| plugin state |
|
|
110
|
+
+----------------------------------------------------------+
|
|
111
|
+
|
|
|
112
|
+
| (babysitter CLI bridge)
|
|
113
|
+
v
|
|
114
|
+
+----------------------------------------------------------+
|
|
115
|
+
| Babysitter Orchestration |
|
|
116
|
+
| |
|
|
117
|
+
| run:create ---> run:iterate ---> Pending effects? |
|
|
118
|
+
| | |
|
|
119
|
+
| +---------+-------+-------+ |
|
|
120
|
+
| | | | |
|
|
121
|
+
| breakpoint task sleep |
|
|
122
|
+
| | | | |
|
|
123
|
+
+------------------------|---------+---------------|-------+
|
|
124
|
+
| |
|
|
125
|
+
+------------|-------------------------+
|
|
126
|
+
| v
|
|
127
|
+
+-----------|-------------------------------------------------+
|
|
128
|
+
| | Paperclip UI |
|
|
129
|
+
| v |
|
|
130
|
+
| Worker streams pending breakpoint to UI |
|
|
131
|
+
| | |
|
|
132
|
+
| v |
|
|
133
|
+
| RunDetailTab renders approval form |
|
|
134
|
+
| BabysitterDashboard shows badge count |
|
|
135
|
+
| | |
|
|
136
|
+
| v |
|
|
137
|
+
| User clicks Approve / Reject |
|
|
138
|
+
| | |
|
|
139
|
+
| v |
|
|
140
|
+
| Action handler: approve-breakpoint / reject-breakpoint |
|
|
141
|
+
| | |
|
|
142
|
+
+-------|----------------------------------------------------- +
|
|
143
|
+
|
|
|
144
|
+
| (babysitter CLI bridge)
|
|
145
|
+
v
|
|
146
|
+
+----------------------------------------------------------+
|
|
147
|
+
| babysitter task:post <runDir> <effectId> |
|
|
148
|
+
| --status ok |
|
|
149
|
+
| --value-inline '{"approved": true}' (approve) |
|
|
150
|
+
| --value-inline '{"approved": false, (reject) |
|
|
151
|
+
| "feedback": "..."}' |
|
|
152
|
+
| |
|
|
153
|
+
| EFFECT_RESOLVED appended to journal |
|
|
154
|
+
| Next iteration replays with resolved effect |
|
|
155
|
+
+----------------------------------------------------------+
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### Breakpoint Flow (Critical Detail)
|
|
159
|
+
|
|
160
|
+
Both approval and rejection use `--status ok` when posting via `task:post`.
|
|
161
|
+
The distinction is in the value payload:
|
|
162
|
+
|
|
163
|
+
- **Approve**: `{ approved: true, response: "..." }`
|
|
164
|
+
- **Reject**: `{ approved: false, feedback: "..." }`
|
|
165
|
+
|
|
166
|
+
This matches babysitter's breakpoint contract where `BreakpointResult.approved`
|
|
167
|
+
controls the process branch, not the task status. Never use `--status error`
|
|
168
|
+
for rejections.
|
|
169
|
+
|
|
170
|
+
When `autoIterate` is enabled (default), the worker automatically calls
|
|
171
|
+
`run:iterate` after resolving a breakpoint so the process continues without
|
|
172
|
+
manual intervention.
|
|
173
|
+
|
|
174
|
+
## Plugin Events
|
|
175
|
+
|
|
176
|
+
The plugin emits custom events on the Paperclip event bus:
|
|
177
|
+
|
|
178
|
+
| Event | When |
|
|
179
|
+
|-------|------|
|
|
180
|
+
| `plugin.babysitter.run.created` | A new babysitter run is created via the `create-run` action |
|
|
181
|
+
| `plugin.babysitter.breakpoint.requested` | A breakpoint effect is pending approval |
|
|
182
|
+
| `plugin.babysitter.breakpoint.resolved` | A breakpoint is approved or rejected |
|
|
183
|
+
|
|
184
|
+
## Troubleshooting
|
|
185
|
+
|
|
186
|
+
### "babysitter" CLI not found
|
|
187
|
+
|
|
188
|
+
The plugin shells out to the `babysitter` CLI. Ensure it is installed globally
|
|
189
|
+
and available on `PATH`:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
npm install -g @a5c-ai/babysitter-sdk
|
|
193
|
+
babysitter version
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Runs directory not found
|
|
197
|
+
|
|
198
|
+
The default `runsDir` is `.a5c/runs` relative to the workspace. If your
|
|
199
|
+
project uses a different path, update the plugin setting or set the
|
|
200
|
+
`BABYSITTER_RUNS_DIR` environment variable.
|
|
201
|
+
|
|
202
|
+
### Harness detection shows "fallback" / low confidence
|
|
203
|
+
|
|
204
|
+
The plugin could not determine which underlying harness the agent uses. Either:
|
|
205
|
+
1. Set the agent's `adapterType` field in Paperclip to one of the known values
|
|
206
|
+
(e.g., `claude_local`, `codex_local`)
|
|
207
|
+
2. Set the `defaultHarness` plugin config to your preferred harness name
|
|
208
|
+
3. Ensure the harness CLI sets its expected environment variables
|
|
209
|
+
|
|
210
|
+
### Breakpoint times out
|
|
211
|
+
|
|
212
|
+
The default breakpoint timeout is 1 hour (3,600,000 ms). Increase the
|
|
213
|
+
`breakpointTimeout` setting if your workflow requires longer approval windows.
|
|
214
|
+
|
|
215
|
+
### State cache mismatch
|
|
216
|
+
|
|
217
|
+
If run status appears stale, rebuild the state cache:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
babysitter run:rebuild-state .a5c/runs/<runId>
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Journal corruption
|
|
224
|
+
|
|
225
|
+
Repair a corrupted journal:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
babysitter run:repair-journal .a5c/runs/<runId>
|
|
229
|
+
```
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createPluginBundlerPresets } from "@paperclipai/plugin-sdk/bundlers";
|
|
2
|
+
|
|
3
|
+
const presets = createPluginBundlerPresets({ uiEntry: "src/ui/index.tsx" });
|
|
4
|
+
|
|
5
|
+
// Worker bundle
|
|
6
|
+
await presets.esbuild.worker();
|
|
7
|
+
|
|
8
|
+
// Manifest bundle
|
|
9
|
+
await presets.esbuild.manifest();
|
|
10
|
+
|
|
11
|
+
// UI bundle
|
|
12
|
+
await presets.esbuild.ui();
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@a5c-ai/babysitter-paperclip",
|
|
3
|
+
"version": "0.0.2-staging.29187771",
|
|
4
|
+
"description": "Babysitter orchestration plugin for Paperclip AI",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/worker.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "node esbuild.config.mjs",
|
|
9
|
+
"dev": "paperclip-plugin-dev-server --root . --ui-dir dist/ui --port 4177",
|
|
10
|
+
"test": "vitest run",
|
|
11
|
+
"deploy": "npm publish --access public",
|
|
12
|
+
"deploy:staging": "npm publish --access public --tag staging"
|
|
13
|
+
},
|
|
14
|
+
"peerDependencies": {
|
|
15
|
+
"@paperclipai/plugin-sdk": ">=0.1.0"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@a5c-ai/babysitter-sdk": "0.0.187-staging.29187771"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"@paperclipai/plugin-sdk": "latest",
|
|
22
|
+
"esbuild": "^0.21.0",
|
|
23
|
+
"react": "^19.0.0",
|
|
24
|
+
"react-dom": "^19.0.0",
|
|
25
|
+
"@types/react": "^19.0.0",
|
|
26
|
+
"typescript": "^5.5.0",
|
|
27
|
+
"vitest": "^3.0.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
|
2
|
+
import { detectHarness, mapAdapterType } from "../delegating-adapter";
|
|
3
|
+
|
|
4
|
+
describe("detectHarness", () => {
|
|
5
|
+
// Save and clear env vars that trigger Tier 2 detection
|
|
6
|
+
const envKeys = [
|
|
7
|
+
"CLAUDE_CODE_SESSION", "CLAUDE_CODE_ENTRYPOINT",
|
|
8
|
+
"CODEX_SESSION", "CODEX_HOME",
|
|
9
|
+
"GEMINI_CLI_SESSION", "GOOGLE_GENAI_API_KEY",
|
|
10
|
+
"CURSOR_SESSION",
|
|
11
|
+
];
|
|
12
|
+
const savedEnv: Record<string, string | undefined> = {};
|
|
13
|
+
|
|
14
|
+
beforeEach(() => {
|
|
15
|
+
for (const key of envKeys) {
|
|
16
|
+
savedEnv[key] = process.env[key];
|
|
17
|
+
delete process.env[key];
|
|
18
|
+
}
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
for (const key of envKeys) {
|
|
23
|
+
if (savedEnv[key] !== undefined) {
|
|
24
|
+
process.env[key] = savedEnv[key];
|
|
25
|
+
} else {
|
|
26
|
+
delete process.env[key];
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("Tier 1: maps known Paperclip adapter types to babysitter harness names", () => {
|
|
32
|
+
expect(detectHarness("claude_local")).toEqual({
|
|
33
|
+
harnessName: "claude-code",
|
|
34
|
+
detectionTier: "agent-metadata",
|
|
35
|
+
confidence: "high",
|
|
36
|
+
});
|
|
37
|
+
expect(detectHarness("codex_local")).toEqual({
|
|
38
|
+
harnessName: "codex",
|
|
39
|
+
detectionTier: "agent-metadata",
|
|
40
|
+
confidence: "high",
|
|
41
|
+
});
|
|
42
|
+
expect(detectHarness("gemini_local")).toEqual({
|
|
43
|
+
harnessName: "gemini-cli",
|
|
44
|
+
detectionTier: "agent-metadata",
|
|
45
|
+
confidence: "high",
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("Tier 3: falls back to plugin config when adapter type unknown", () => {
|
|
50
|
+
expect(detectHarness("unknown_adapter", { defaultHarness: "cursor" })).toEqual({
|
|
51
|
+
harnessName: "cursor",
|
|
52
|
+
detectionTier: "config",
|
|
53
|
+
confidence: "medium",
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("Tier 4: defaults to claude-code when no detection succeeds", () => {
|
|
58
|
+
expect(detectHarness(undefined)).toEqual({
|
|
59
|
+
harnessName: "claude-code",
|
|
60
|
+
detectionTier: "fallback",
|
|
61
|
+
confidence: "low",
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("handles undefined adapter type with no config", () => {
|
|
66
|
+
expect(detectHarness(undefined, {})).toEqual({
|
|
67
|
+
harnessName: "claude-code",
|
|
68
|
+
detectionTier: "fallback",
|
|
69
|
+
confidence: "low",
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("mapAdapterType", () => {
|
|
75
|
+
test("maps known types", () => {
|
|
76
|
+
expect(mapAdapterType("claude_local")).toBe("claude-code");
|
|
77
|
+
expect(mapAdapterType("pi_local")).toBe("pi");
|
|
78
|
+
expect(mapAdapterType("omp_local")).toBe("oh-my-pi");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("returns undefined for unknown types", () => {
|
|
82
|
+
expect(mapAdapterType("unknown")).toBeUndefined();
|
|
83
|
+
expect(mapAdapterType("")).toBeUndefined();
|
|
84
|
+
});
|
|
85
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { describe, expect, test } from "vitest";
|
|
2
|
+
import { ADAPTER_TYPE_MAP } from "../types";
|
|
3
|
+
|
|
4
|
+
describe("ADAPTER_TYPE_MAP", () => {
|
|
5
|
+
test("maps all known Paperclip adapter types", () => {
|
|
6
|
+
expect(ADAPTER_TYPE_MAP).toEqual({
|
|
7
|
+
claude_local: "claude-code",
|
|
8
|
+
codex_local: "codex",
|
|
9
|
+
gemini_local: "gemini-cli",
|
|
10
|
+
cursor_local: "cursor",
|
|
11
|
+
github_copilot: "github-copilot",
|
|
12
|
+
opencode_local: "opencode",
|
|
13
|
+
pi_local: "pi",
|
|
14
|
+
omp_local: "oh-my-pi",
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test("covers all expected harnesses", () => {
|
|
19
|
+
const harnesses = Object.values(ADAPTER_TYPE_MAP);
|
|
20
|
+
expect(harnesses).toContain("claude-code");
|
|
21
|
+
expect(harnesses).toContain("codex");
|
|
22
|
+
expect(harnesses).toContain("gemini-cli");
|
|
23
|
+
expect(harnesses).toContain("cursor");
|
|
24
|
+
expect(harnesses).toContain("github-copilot");
|
|
25
|
+
expect(harnesses).toContain("opencode");
|
|
26
|
+
expect(harnesses).toContain("pi");
|
|
27
|
+
expect(harnesses).toContain("oh-my-pi");
|
|
28
|
+
});
|
|
29
|
+
});
|