@plaited/acp-harness 0.2.5 → 0.3.1

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.
Files changed (57) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +120 -16
  3. package/bin/cli.ts +105 -636
  4. package/bin/tests/cli.spec.ts +218 -51
  5. package/package.json +20 -4
  6. package/src/acp-client.ts +5 -4
  7. package/src/acp-transport.ts +14 -7
  8. package/src/adapter-check.ts +542 -0
  9. package/src/adapter-scaffold.ts +934 -0
  10. package/src/balance.ts +232 -0
  11. package/src/calibrate.ts +300 -0
  12. package/src/capture.ts +457 -0
  13. package/src/constants.ts +94 -0
  14. package/src/grader-loader.ts +174 -0
  15. package/src/harness.ts +35 -0
  16. package/src/schemas-cli.ts +239 -0
  17. package/src/schemas.ts +567 -0
  18. package/src/summarize.ts +245 -0
  19. package/src/tests/adapter-check.spec.ts +70 -0
  20. package/src/tests/adapter-scaffold.spec.ts +112 -0
  21. package/src/tests/fixtures/grader-bad-module.ts +5 -0
  22. package/src/tests/fixtures/grader-exec-fail.py +9 -0
  23. package/src/tests/fixtures/grader-exec-invalid.py +6 -0
  24. package/src/tests/fixtures/grader-exec.py +29 -0
  25. package/src/tests/fixtures/grader-module.ts +14 -0
  26. package/src/tests/grader-loader.spec.ts +153 -0
  27. package/src/trials.ts +395 -0
  28. package/src/validate-refs.ts +188 -0
  29. package/.claude/rules/accuracy.md +0 -43
  30. package/.claude/rules/bun-apis.md +0 -80
  31. package/.claude/rules/code-review.md +0 -254
  32. package/.claude/rules/git-workflow.md +0 -37
  33. package/.claude/rules/github.md +0 -154
  34. package/.claude/rules/testing.md +0 -172
  35. package/.claude/skills/acp-harness/SKILL.md +0 -310
  36. package/.claude/skills/acp-harness/assets/Dockerfile.acp +0 -25
  37. package/.claude/skills/acp-harness/assets/docker-compose.acp.yml +0 -19
  38. package/.claude/skills/acp-harness/references/downstream.md +0 -288
  39. package/.claude/skills/acp-harness/references/output-formats.md +0 -221
  40. package/.claude-plugin/marketplace.json +0 -15
  41. package/.claude-plugin/plugin.json +0 -16
  42. package/.github/CODEOWNERS +0 -6
  43. package/.github/workflows/ci.yml +0 -63
  44. package/.github/workflows/publish.yml +0 -146
  45. package/.mcp.json +0 -20
  46. package/CLAUDE.md +0 -92
  47. package/Dockerfile.test +0 -23
  48. package/biome.json +0 -96
  49. package/bun.lock +0 -513
  50. package/docker-compose.test.yml +0 -21
  51. package/scripts/bun-test-wrapper.sh +0 -46
  52. package/src/acp.constants.ts +0 -56
  53. package/src/acp.schemas.ts +0 -161
  54. package/src/acp.types.ts +0 -28
  55. package/src/tests/fixtures/.claude/settings.local.json +0 -8
  56. package/src/tests/fixtures/.claude/skills/greeting/SKILL.md +0 -17
  57. package/tsconfig.json +0 -32
@@ -1,221 +0,0 @@
1
- # Output Formats
2
-
3
- The harness supports two output formats optimized for different use cases.
4
-
5
- ## Format Selection
6
-
7
- ```bash
8
- bunx @plaited/acp-harness prompts.jsonl --format <format> -o <output>
9
- ```
10
-
11
- | Format | Files Created | Use Case |
12
- |--------|---------------|----------|
13
- | `summary` | Single JSONL | Quick metrics, dashboards, jq analysis |
14
- | `judge` | `.md` + `.full.jsonl` | Downstream LLM-as-judge scoring |
15
-
16
- ## Summary Format (Default)
17
-
18
- Minimal JSONL for quick metrics and analysis.
19
-
20
- ### Schema
21
-
22
- ```typescript
23
- type SummaryResult = {
24
- id: string // Prompt identifier
25
- input: string // Original prompt text
26
- output: string // Final agent response
27
- toolCalls: string[] // List of tool names used
28
- status: 'passed' | 'failed' | 'error' | 'timeout'
29
- duration: number // Total execution time (ms)
30
- }
31
- ```
32
-
33
- ### Example Output
34
-
35
- ```jsonl
36
- {"id":"test-001","input":"Create a primary button","output":"I created the button in src/button.tsx","toolCalls":["Write"],"status":"passed","duration":1234}
37
- {"id":"test-002","input":"Fix the TypeScript error","output":"I fixed the type error...","toolCalls":["Read","Edit"],"status":"passed","duration":2567}
38
- ```
39
-
40
- ### Analysis with jq
41
-
42
- ```bash
43
- # Calculate average duration
44
- cat results.jsonl | jq -s 'map(.duration) | add / length'
45
-
46
- # Count tool usage
47
- cat results.jsonl | jq -s 'map(.toolCalls) | flatten | group_by(.) | map({tool: .[0], count: length})'
48
-
49
- # Filter by status
50
- cat results.jsonl | jq 'select(.status == "failed")'
51
-
52
- # Pass rate
53
- cat results.jsonl | jq -s 'map(select(.status == "passed")) | length as $p | length as $t | "\($p)/\($t) passed"'
54
- ```
55
-
56
- ## Judge Format (Two-Tier)
57
-
58
- Creates two files for downstream LLM-as-judge scoring with step-level correlation.
59
-
60
- ```bash
61
- bunx @plaited/acp-harness prompts.jsonl --format judge -o results
62
- # Creates: results.md + results.full.jsonl
63
- ```
64
-
65
- ### Markdown File (`<output>.md`)
66
-
67
- Human-readable summary with step IDs and code previews.
68
-
69
- **Structure:**
70
-
71
- ```markdown
72
- ## Capture Record: <id>
73
-
74
- **Input:** <original prompt>
75
-
76
- **Trajectory:**
77
- 1. [THOUGHT] <truncated content> [->stepId]
78
- 2. [TOOL:<name>] -> <status> (<duration>ms) [->stepId]
79
- File: <path> (<size> chars)
80
- ```<ext>
81
- <head lines>
82
-
83
- // ... N lines omitted ...
84
-
85
- <tail lines>
86
- ```
87
- 3. [PLAN] <plan summary> [->stepId]
88
- 4. [MESSAGE] <truncated content> [->stepId]
89
-
90
- **Output:** <truncated final output>
91
- **Metadata:** category=ui, agent=claude-code-acp, ...
92
- **Status:** passed|failed|error|timeout
93
- **Duration:** <ms>ms
94
-
95
- ---
96
- ```
97
-
98
- **Step ID Format:** `<prompt-id>-step-<N>` (e.g., `test-001-step-2`)
99
-
100
- **Truncation Rules:**
101
- - Thought/message content: First 100 characters
102
- - Output: First 200 characters
103
- - Code preview: Head (8 lines) + tail (4 lines) for files > 12 lines
104
-
105
- ### Full JSONL File (`<output>.full.jsonl`)
106
-
107
- Complete trajectory with step IDs for correlation.
108
-
109
- **Schema:**
110
-
111
- ```typescript
112
- type FullResult = {
113
- id: string
114
- input: string
115
- output: string
116
- expected?: string
117
- trajectory: IndexedStep[] // Steps with stepId
118
- metadata: Record<string, unknown>
119
- timing: {
120
- start: number // Unix timestamp (ms)
121
- end: number // Unix timestamp (ms)
122
- firstResponse?: number // Time to first response (ms)
123
- }
124
- status: 'passed' | 'failed' | 'error' | 'timeout'
125
- errors?: string[]
126
- }
127
-
128
- type IndexedStep = TrajectoryStep & { stepId: string }
129
-
130
- type TrajectoryStep =
131
- | { type: 'thought'; content: string; timestamp: number }
132
- | { type: 'message'; content: string; timestamp: number }
133
- | {
134
- type: 'tool_call'
135
- name: string // Tool title from ACP SDK
136
- status: string // pending, in_progress, completed, failed
137
- input?: unknown // Raw input parameters
138
- output?: unknown // Raw output
139
- duration?: number // Execution time (ms)
140
- timestamp: number
141
- }
142
- | { type: 'plan'; entries: PlanEntry[]; timestamp: number }
143
- ```
144
-
145
- **Example:**
146
-
147
- ```jsonl
148
- {"id":"test-001","input":"Create a primary button","output":"I created the button...","trajectory":[{"type":"thought","content":"I'll create a styled button template with createStyles","timestamp":100,"stepId":"test-001-step-1"},{"type":"tool_call","name":"Write","status":"completed","input":{"file_path":"src/button.tsx","content":"import { createStyles }..."},"output":"File written successfully","duration":234,"timestamp":150,"stepId":"test-001-step-2"},{"type":"message","content":"I created the button template","timestamp":500,"stepId":"test-001-step-3"}],"metadata":{"category":"ui","agent":"claude"},"timing":{"start":1704067200000,"end":1704067201234,"firstResponse":100},"status":"passed"}
149
- ```
150
-
151
- ## Two-Tier Scoring Workflow
152
-
153
- ### Direct Scoring (Large Context)
154
-
155
- For judges with large context windows (Gemini 1M+, Claude 200k):
156
-
157
- ```bash
158
- # Feed full JSONL directly
159
- cat results.full.jsonl | your-gemini-judge.ts
160
- ```
161
-
162
- ### Step-Level Retrieval (Small Context)
163
-
164
- For smaller models or step-specific analysis:
165
-
166
- ```typescript
167
- // Load both files
168
- const markdown = await Bun.file('results.md').text()
169
- const fullLines = (await Bun.file('results.full.jsonl').text()).trim().split('\n')
170
-
171
- // Parse full results indexed by step ID
172
- const stepIndex = new Map<string, unknown>()
173
- for (const line of fullLines) {
174
- const result = JSON.parse(line)
175
- for (const step of result.trajectory) {
176
- stepIndex.set(step.stepId, step)
177
- }
178
- }
179
-
180
- // Judge requests full content for specific step
181
- const stepId = 'test-001-step-2' // From markdown [->stepId]
182
- const fullStep = stepIndex.get(stepId)
183
- console.log(fullStep.input) // Complete tool input
184
- ```
185
-
186
- ## Status Values
187
-
188
- | Status | Meaning |
189
- |--------|---------|
190
- | `passed` | Completed without tool errors |
191
- | `failed` | Completed but one or more tool calls failed |
192
- | `error` | Unhandled exception during execution |
193
- | `timeout` | Request exceeded timeout limit |
194
-
195
- ## Input Format
196
-
197
- Both formats accept the same JSONL input:
198
-
199
- ```jsonl
200
- {"id":"test-001","input":"Create a primary button","expected":"should contain <button>","metadata":{"category":"ui"}}
201
- ```
202
-
203
- | Field | Required | Description |
204
- |-------|----------|-------------|
205
- | `id` | Yes | Unique identifier |
206
- | `input` | Yes | Prompt text for the agent |
207
- | `expected` | No | Expected output (for downstream scoring) |
208
- | `metadata` | No | Tags, category, difficulty for filtering |
209
- | `timeout` | No | Override default timeout for this prompt |
210
-
211
- ## Streaming Behavior
212
-
213
- Both formats stream output line-by-line as results complete:
214
-
215
- ```bash
216
- # Watch results in real-time
217
- bunx @plaited/acp-harness prompts.jsonl --progress -o results.jsonl &
218
- tail -f results.jsonl
219
- ```
220
-
221
- Use `--append` to continue interrupted runs without overwriting previous results.
@@ -1,15 +0,0 @@
1
- {
2
- "name": "plaited-acp-harness",
3
- "metadata": {
4
- "description": "Claude Code plugin for Agent Client Protocol testing and evaluation"
5
- },
6
- "owner": {
7
- "name": "Plaited Labs"
8
- },
9
- "plugins": [
10
- {
11
- "name": "acp-harness",
12
- "source": "./"
13
- }
14
- ]
15
- }
@@ -1,16 +0,0 @@
1
- {
2
- "name": "acp-harness",
3
- "version": "0.2.5",
4
- "description": "Agent Client Protocol client and evaluation harness for TypeScript/Bun projects. Includes: createACPClient for programmatic agent access, run-harness.ts for trajectory capture, and LLM-as-judge evaluation templates. Requires Bun runtime.",
5
- "author": {
6
- "name": "Plaited Labs"
7
- },
8
- "license": "ISC",
9
- "mcpServers": {
10
- "agent-client-protocol": {
11
- "type": "http",
12
- "url": "https://agentclientprotocol.com/mcp"
13
- }
14
- },
15
- "skills": "./.claude/skills"
16
- }
@@ -1,6 +0,0 @@
1
- # Code owners for acp-harness repository
2
- # These users will be automatically requested for review when someone opens a pull request.
3
- # See https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners
4
-
5
- # Organization admins own all files
6
- * @EdwardIrby @alisonailea
@@ -1,63 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches:
6
- - main
7
- pull_request:
8
-
9
- permissions:
10
- contents: read
11
-
12
- jobs:
13
- # Detect which paths changed to conditionally run expensive jobs
14
- changes:
15
- runs-on: ubuntu-latest
16
- permissions:
17
- pull-requests: read
18
- outputs:
19
- acp: ${{ steps.filter.outputs.acp }}
20
- steps:
21
- - uses: actions/checkout@v4
22
- - uses: dorny/paths-filter@v3
23
- id: filter
24
- with:
25
- filters: |
26
- acp:
27
- - 'src/**'
28
-
29
- test-pr:
30
- runs-on: ubuntu-latest
31
-
32
- steps:
33
- - uses: actions/checkout@v4
34
- - uses: oven-sh/setup-bun@v2
35
- with:
36
- bun-version: latest
37
- - name: Install dependencies
38
- run: bun install
39
- - name: Run check
40
- run: bun run check
41
- - name: Run test
42
- run: bun run test
43
-
44
- # ACP integration tests run in Docker container for consistent environment
45
- # Only runs when src/ files change to reduce API costs
46
- test-acp-integration:
47
- needs: changes
48
- if: ${{ needs.changes.outputs.acp == 'true' }}
49
- runs-on: ubuntu-latest
50
- container:
51
- image: oven/bun:1.2.9
52
- options: --user root
53
-
54
- steps:
55
- - uses: actions/checkout@v4
56
-
57
- - name: Install dependencies
58
- run: bun install --frozen-lockfile
59
-
60
- - name: Run ACP integration tests
61
- env:
62
- ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
63
- run: bun test ./src/tests/acp-integration.docker.ts
@@ -1,146 +0,0 @@
1
- name: Publish
2
-
3
- on:
4
- workflow_dispatch:
5
- inputs:
6
- version:
7
- description: "New version tag (e.g., 1.0.0)"
8
- required: true
9
- next:
10
- description: "Next prerelease number (optional, will create a version like x.y.z-next.N)"
11
- required: false
12
- jobs:
13
- publish:
14
- runs-on: ubuntu-22.04
15
- permissions:
16
- contents: write
17
- id-token: write
18
-
19
- steps:
20
- - name: Validate inputs
21
- env:
22
- INPUT_VERSION: ${{ github.event.inputs.version }}
23
- INPUT_NEXT: ${{ github.event.inputs.next }}
24
- run: |
25
- # SECURITY: Validate all inputs before use to prevent injection
26
- # Using env vars instead of direct interpolation to prevent shell injection
27
-
28
- # Validate version format (semver)
29
- if ! echo "$INPUT_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
30
- echo "::error::Invalid version format: $INPUT_VERSION"
31
- echo "::error::Expected: X.Y.Z (e.g., 1.0.0)"
32
- exit 1
33
- fi
34
-
35
- # Validate next is a number if provided
36
- if [[ -n "$INPUT_NEXT" ]] && ! echo "$INPUT_NEXT" | grep -qE '^[0-9]+$'; then
37
- echo "::error::Invalid next value: $INPUT_NEXT"
38
- echo "::error::Expected: number (e.g., 1, 2, 3)"
39
- exit 1
40
- fi
41
-
42
- echo "✓ Input validation passed"
43
-
44
- - name: Set version
45
- id: set_version
46
- env:
47
- INPUT_VERSION: ${{ github.event.inputs.version }}
48
- INPUT_NEXT: ${{ github.event.inputs.next }}
49
- run: |
50
- base_version="$INPUT_VERSION"
51
- next="$INPUT_NEXT"
52
-
53
- if [[ -n "$next" ]]; then
54
- echo "version=${base_version}-next.${next}" >> $GITHUB_OUTPUT
55
- echo "is_prerelease=true" >> $GITHUB_OUTPUT
56
- else
57
- echo "version=${base_version}" >> $GITHUB_OUTPUT
58
- echo "is_prerelease=false" >> $GITHUB_OUTPUT
59
- fi
60
-
61
- - name: Validate version format
62
- env:
63
- VERSION: ${{ steps.set_version.outputs.version }}
64
- run: |
65
- version="$VERSION"
66
-
67
- # Check for 'v' prefix (common mistake)
68
- if [[ "$version" =~ ^v ]]; then
69
- echo "::error::Version should not include 'v' prefix"
70
- echo "::error::Enter '1.3.4' not 'v1.3.4'"
71
- echo "::error::The workflow will automatically add 'v' for Git tags"
72
- exit 1
73
- fi
74
-
75
- # Validate semver format (allows dots in prerelease suffix for formats like 1.0.0-next.1)
76
- if [[ ! "$version" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(-([a-zA-Z0-9._-]+))?$ ]]; then
77
- echo "::error::Version must have the format 'x.y.z' or 'x.y.z-<string>', where x, y, and z are numbers."
78
- exit 1
79
- fi
80
-
81
- echo "✅ Version format validated: $version"
82
-
83
- - name: Checkout repository
84
- uses: actions/checkout@v4
85
- with:
86
- token: ${{ secrets.GH_PAT }}
87
-
88
- - name: Setup Node.js (for NPM OIDC)
89
- uses: actions/setup-node@v4
90
- with:
91
- node-version: "lts/*"
92
- registry-url: https://registry.npmjs.org
93
- check-latest: true
94
-
95
- - uses: oven-sh/setup-bun@v1
96
-
97
- - name: Setup
98
- run: |
99
- bun install
100
-
101
- - name: Configure Git
102
- env:
103
- GIT_AUTHOR_NAME: ${{ github.actor }}
104
- GIT_AUTHOR_EMAIL: ${{ github.actor }}@users.noreply.github.com
105
- run: |
106
- git config user.name "$GIT_AUTHOR_NAME"
107
- git config user.email "$GIT_AUTHOR_EMAIL"
108
-
109
- - name: Version
110
- env:
111
- GH_TOKEN: ${{ secrets.GH_PAT }}
112
- VERSION: ${{ steps.set_version.outputs.version }}
113
- IS_PRERELEASE: ${{ steps.set_version.outputs.is_prerelease }}
114
- run: |
115
- npm version --no-git-tag-version "$VERSION"
116
-
117
- # Update plugin.json version
118
- jq --arg v "$VERSION" '.version = $v' .claude-plugin/plugin.json > .claude-plugin/plugin.json.tmp
119
- mv .claude-plugin/plugin.json.tmp .claude-plugin/plugin.json
120
-
121
- git add -A
122
- git commit -m "ci: publish [skip ci]"
123
- git push
124
-
125
- # Create GitHub release
126
- if [[ "$IS_PRERELEASE" == "true" ]]; then
127
- gh release create "v$VERSION" --generate-notes --prerelease
128
- else
129
- gh release create "v$VERSION" --generate-notes
130
- fi
131
-
132
- - name: Publish to NPM (Trusted Publishing)
133
- env:
134
- IS_PRERELEASE: ${{ steps.set_version.outputs.is_prerelease }}
135
- run: |
136
- # NPM trusted publishing uses OIDC token automatically
137
- # Provenance attestations are generated automatically (npm >=11.5.1)
138
- # No NPM_TOKEN secret needed - authentication via GitHub OIDC
139
-
140
- if [[ "$IS_PRERELEASE" == "true" ]]; then
141
- echo "Publishing as next (prerelease)"
142
- npm publish --access public --tag next
143
- else
144
- echo "Publishing as latest (stable)"
145
- npm publish --access public
146
- fi
package/.mcp.json DELETED
@@ -1,20 +0,0 @@
1
- {
2
- "mcpServers": {
3
- "agent-skills-spec": {
4
- "type": "http",
5
- "url": "https://agentskills.io/mcp"
6
- },
7
- "agent-client-protocol": {
8
- "type": "http",
9
- "url": "https://agentclientprotocol.com/mcp"
10
- },
11
- "model-context-protocol-docs":{
12
- "type": "http",
13
- "url": "https://modelcontextprotocol.io/mcp"
14
- },
15
- "braintrust-docs": {
16
- "type": "http",
17
- "url": "https://www.braintrust.dev/docs/mcp"
18
- }
19
- }
20
- }
package/CLAUDE.md DELETED
@@ -1,92 +0,0 @@
1
- # CLAUDE.md
2
-
3
- This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
-
5
- ## Essential Commands
6
-
7
- ### Development Setup
8
- ```bash
9
- # Install dependencies (requires bun >= v1.2.9)
10
- bun install
11
-
12
- # Type, lint, and format check (check only, no fixes)
13
- bun run check
14
-
15
- # Lint and format fix (auto-fix issues)
16
- bun run check:write
17
-
18
- # Run unit tests
19
- bun test
20
-
21
- # Run Docker integration tests (requires ANTHROPIC_API_KEY)
22
- ANTHROPIC_API_KEY=sk-... bun run test:docker
23
- ```
24
-
25
- ## Project Organization
26
-
27
- This project uses `.claude/rules/` for project-specific guidance:
28
-
29
- - **Testing**: @.claude/rules/testing.md - Test commands and workflow
30
- - **Code Review**: @.claude/rules/code-review.md - Review standards
31
- - **Accuracy**: @.claude/rules/accuracy.md - Confidence thresholds
32
- - **Bun APIs**: @.claude/rules/bun-apis.md - Bun platform API preferences
33
- - **Git Workflow**: @.claude/rules/git-workflow.md - Commit conventions
34
- - **GitHub**: @.claude/rules/github.md - GitHub CLI integration
35
-
36
- ## Quick Reference
37
-
38
- ### Package Overview
39
-
40
- `@plaited/acp-harness` is a CLI tool for capturing agent trajectories from ACP-compatible agents. It executes prompts, captures full trajectories (tools, thoughts, plans), and outputs structured JSONL for downstream scoring.
41
-
42
- **CLI usage:**
43
- ```bash
44
- bunx @plaited/acp-harness prompts.jsonl -o results.jsonl
45
- ```
46
-
47
- ### Code Style Essentials
48
-
49
- - Prefer arrow functions and `type` over `interface`
50
- - Use `test` instead of `it` in test files
51
- - Prefer Bun native APIs over Node.js equivalents
52
- - Object parameters for functions with 2+ parameters
53
- - JSON imports require `with { type: 'json' }` attribute
54
-
55
- For complete conventions, see `.claude/rules/code-review.md`
56
-
57
- ### Plugin Development
58
-
59
- This project is a Claude Code plugin distributed via the plaited/marketplace aggregator. Structure:
60
- - `.claude/.claude-plugin/plugin.json` - Plugin manifest
61
- - `.claude/` - Plugin source (skills, rules, settings)
62
-
63
- When working on plugins:
64
- - Clear cache after changes: `rm -rf ~/.claude/plugins-cache`
65
- - Restart Claude Code to see updates
66
- - Skills are auto-invoked (won't show in `/plugins` UI)
67
- - Test installation locally: `claude plugins add github:plaited/marketplace`
68
-
69
- ### Documentation
70
-
71
- - Public APIs require comprehensive TSDoc documentation
72
- - No `@example` sections - tests are living examples
73
- - Use `@internal` marker for non-public APIs
74
- - Always use `type` over `interface`
75
- - Use Mermaid diagrams only (not ASCII art)
76
-
77
- ## Important Constraints
78
-
79
- 1. **No Open Contribution**: This is open-source but not open-contribution
80
- 2. **Bun Required**: Development requires bun >= v1.2.9
81
- 3. **ES2024 Features**: Uses Promise.withResolvers() and other modern APIs
82
-
83
- ## Plugin
84
-
85
- The bundled **acp-harness** skill (`.claude/skills/acp-harness/`) provides:
86
- - CLI usage and examples
87
- - Output format specifications
88
- - Downstream integration patterns
89
-
90
- Install via Claude Code: `/plugin marketplace add plaited/acp-harness`
91
-
92
- See `.claude/skills/acp-harness/SKILL.md` for complete documentation.
package/Dockerfile.test DELETED
@@ -1,23 +0,0 @@
1
- # Dockerfile for integration tests requiring Docker environment
2
- # Uses same bun version as CI for consistency
3
- #
4
- # Tests use *.docker.ts naming to:
5
- # 1. Avoid bun test pattern matching in normal test runs
6
- # 2. Signal these tests require Docker (external APIs, etc.)
7
-
8
- FROM oven/bun:1.2.9
9
-
10
- # Install git (required for some operations)
11
- RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/*
12
-
13
- WORKDIR /app
14
-
15
- # Copy source
16
- COPY . .
17
-
18
- # Install dependencies
19
- RUN bun install --frozen-lockfile
20
-
21
- # Run all Docker integration tests
22
- # The wrapper script handles finding and running *.docker.ts files
23
- CMD ["bash", "scripts/bun-test-wrapper.sh"]