@plaited/acp-harness 0.2.5

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 (45) hide show
  1. package/.claude/rules/accuracy.md +43 -0
  2. package/.claude/rules/bun-apis.md +80 -0
  3. package/.claude/rules/code-review.md +254 -0
  4. package/.claude/rules/git-workflow.md +37 -0
  5. package/.claude/rules/github.md +154 -0
  6. package/.claude/rules/testing.md +172 -0
  7. package/.claude/skills/acp-harness/SKILL.md +310 -0
  8. package/.claude/skills/acp-harness/assets/Dockerfile.acp +25 -0
  9. package/.claude/skills/acp-harness/assets/docker-compose.acp.yml +19 -0
  10. package/.claude/skills/acp-harness/references/downstream.md +288 -0
  11. package/.claude/skills/acp-harness/references/output-formats.md +221 -0
  12. package/.claude-plugin/marketplace.json +15 -0
  13. package/.claude-plugin/plugin.json +16 -0
  14. package/.github/CODEOWNERS +6 -0
  15. package/.github/workflows/ci.yml +63 -0
  16. package/.github/workflows/publish.yml +146 -0
  17. package/.mcp.json +20 -0
  18. package/CLAUDE.md +92 -0
  19. package/Dockerfile.test +23 -0
  20. package/LICENSE +15 -0
  21. package/README.md +94 -0
  22. package/bin/cli.ts +670 -0
  23. package/bin/tests/cli.spec.ts +362 -0
  24. package/biome.json +96 -0
  25. package/bun.lock +513 -0
  26. package/docker-compose.test.yml +21 -0
  27. package/package.json +57 -0
  28. package/scripts/bun-test-wrapper.sh +46 -0
  29. package/src/acp-client.ts +503 -0
  30. package/src/acp-helpers.ts +121 -0
  31. package/src/acp-transport.ts +455 -0
  32. package/src/acp-utils.ts +341 -0
  33. package/src/acp.constants.ts +56 -0
  34. package/src/acp.schemas.ts +161 -0
  35. package/src/acp.ts +27 -0
  36. package/src/acp.types.ts +28 -0
  37. package/src/tests/acp-client.spec.ts +205 -0
  38. package/src/tests/acp-helpers.spec.ts +105 -0
  39. package/src/tests/acp-integration.docker.ts +214 -0
  40. package/src/tests/acp-transport.spec.ts +153 -0
  41. package/src/tests/acp-utils.spec.ts +394 -0
  42. package/src/tests/fixtures/.claude/settings.local.json +8 -0
  43. package/src/tests/fixtures/.claude/skills/greeting/SKILL.md +17 -0
  44. package/src/tests/fixtures/calculator-mcp.ts +215 -0
  45. package/tsconfig.json +32 -0
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Internal utilities for ACP content manipulation.
3
+ *
4
+ * @remarks
5
+ * Low-level functions for building content blocks and extracting data
6
+ * from session responses. These are used internally by the higher-level
7
+ * helpers in acp-helpers.ts.
8
+ *
9
+ * @internal
10
+ */
11
+
12
+ import type {
13
+ BlobResourceContents,
14
+ ContentBlock,
15
+ PlanEntry,
16
+ SessionNotification,
17
+ SessionUpdate,
18
+ TextContent,
19
+ TextResourceContents,
20
+ ToolCall,
21
+ ToolCallContent,
22
+ } from '@agentclientprotocol/sdk'
23
+
24
+ // ============================================================================
25
+ // Content Block Builders
26
+ // ============================================================================
27
+
28
+ /**
29
+ * Creates a text content block.
30
+ *
31
+ * @param text - The text content
32
+ * @returns Text content block
33
+ */
34
+ export const createTextContent = (text: string): ContentBlock => ({
35
+ type: 'text',
36
+ text,
37
+ })
38
+
39
+ /**
40
+ * Creates an image content block from base64 data.
41
+ *
42
+ * @param data - Base64-encoded image data
43
+ * @param mimeType - MIME type (e.g., 'image/png', 'image/jpeg')
44
+ * @returns Image content block
45
+ */
46
+ export const createImageContent = (data: string, mimeType: string): ContentBlock => ({
47
+ type: 'image',
48
+ data,
49
+ mimeType,
50
+ })
51
+
52
+ /**
53
+ * Creates an audio content block from base64 data.
54
+ *
55
+ * @param data - Base64-encoded audio data
56
+ * @param mimeType - MIME type (e.g., 'audio/wav', 'audio/mp3')
57
+ * @returns Audio content block
58
+ */
59
+ export const createAudioContent = (data: string, mimeType: string): ContentBlock => ({
60
+ type: 'audio',
61
+ data,
62
+ mimeType,
63
+ })
64
+
65
+ /** Parameters for creating a resource link */
66
+ export type CreateResourceLinkParams = {
67
+ /** URI to the resource */
68
+ uri: string
69
+ /** Resource name (required by SDK) */
70
+ name: string
71
+ /** Optional MIME type */
72
+ mimeType?: string
73
+ }
74
+
75
+ /**
76
+ * Creates a resource link content block.
77
+ *
78
+ * @param params - Resource link parameters
79
+ * @returns Resource link content block
80
+ */
81
+ export const createResourceLink = ({ uri, name, mimeType }: CreateResourceLinkParams): ContentBlock => ({
82
+ type: 'resource_link',
83
+ uri,
84
+ name,
85
+ ...(mimeType && { mimeType }),
86
+ })
87
+
88
+ /** Parameters for creating an embedded text resource */
89
+ export type CreateTextResourceParams = {
90
+ /** URI identifying the resource */
91
+ uri: string
92
+ /** Text content of the resource */
93
+ text: string
94
+ /** Optional MIME type */
95
+ mimeType?: string
96
+ }
97
+
98
+ /**
99
+ * Creates an embedded text resource content block.
100
+ *
101
+ * @param params - Text resource parameters
102
+ * @returns Resource content block
103
+ */
104
+ export const createTextResource = ({ uri, text, mimeType }: CreateTextResourceParams): ContentBlock => ({
105
+ type: 'resource',
106
+ resource: {
107
+ uri,
108
+ text,
109
+ ...(mimeType && { mimeType }),
110
+ } as TextResourceContents,
111
+ })
112
+
113
+ /** Parameters for creating an embedded blob resource */
114
+ export type CreateBlobResourceParams = {
115
+ /** URI identifying the resource */
116
+ uri: string
117
+ /** Base64-encoded binary data */
118
+ blob: string
119
+ /** Optional MIME type */
120
+ mimeType?: string
121
+ }
122
+
123
+ /**
124
+ * Creates an embedded blob resource content block.
125
+ *
126
+ * @param params - Blob resource parameters
127
+ * @returns Resource content block
128
+ */
129
+ export const createBlobResource = ({ uri, blob, mimeType }: CreateBlobResourceParams): ContentBlock => ({
130
+ type: 'resource',
131
+ resource: {
132
+ uri,
133
+ blob,
134
+ ...(mimeType && { mimeType }),
135
+ } as BlobResourceContents,
136
+ })
137
+
138
+ // ============================================================================
139
+ // Content Extraction
140
+ // ============================================================================
141
+
142
+ /**
143
+ * Extracts all text from content blocks.
144
+ *
145
+ * @param content - Array of content blocks
146
+ * @returns Concatenated text content
147
+ */
148
+ export const extractText = (content: ContentBlock[]): string => {
149
+ return content
150
+ .filter((block): block is TextContent & { type: 'text' } => block.type === 'text')
151
+ .map((block) => block.text)
152
+ .join('\n')
153
+ }
154
+
155
+ /**
156
+ * Helper to extract content from SessionUpdate (discriminated union)
157
+ */
158
+ const getUpdateContent = (update: SessionUpdate): ContentBlock | undefined => {
159
+ if (
160
+ update.sessionUpdate === 'user_message_chunk' ||
161
+ update.sessionUpdate === 'agent_message_chunk' ||
162
+ update.sessionUpdate === 'agent_thought_chunk'
163
+ ) {
164
+ return update.content
165
+ }
166
+ return undefined
167
+ }
168
+
169
+ /**
170
+ * Helper to extract tool call from SessionUpdate
171
+ */
172
+ const getUpdateToolCall = (update: SessionUpdate): ToolCall | undefined => {
173
+ if (update.sessionUpdate === 'tool_call') {
174
+ return update
175
+ }
176
+ return undefined
177
+ }
178
+
179
+ /**
180
+ * Helper to extract plan from SessionUpdate
181
+ */
182
+ const getUpdatePlan = (update: SessionUpdate): PlanEntry[] | undefined => {
183
+ if (update.sessionUpdate === 'plan') {
184
+ return update.entries
185
+ }
186
+ return undefined
187
+ }
188
+
189
+ /**
190
+ * Extracts text from session notifications.
191
+ *
192
+ * @remarks
193
+ * Streaming produces partial tokens that should be concatenated directly.
194
+ * Uses empty string join to preserve the original text structure.
195
+ *
196
+ * @param notifications - Array of session notifications
197
+ * @returns Concatenated text from all updates
198
+ */
199
+ export const extractTextFromUpdates = (notifications: SessionNotification[]): string => {
200
+ const texts: string[] = []
201
+ for (const notification of notifications) {
202
+ const content = getUpdateContent(notification.update)
203
+ if (content && content.type === 'text') {
204
+ texts.push(content.text)
205
+ }
206
+ }
207
+ // Join without separator - streaming chunks should be concatenated directly
208
+ return texts.join('')
209
+ }
210
+
211
+ /**
212
+ * Extracts all tool calls from session notifications.
213
+ *
214
+ * @param notifications - Array of session notifications
215
+ * @returns Array of all tool calls
216
+ */
217
+ export const extractToolCalls = (notifications: SessionNotification[]): ToolCall[] => {
218
+ const calls: ToolCall[] = []
219
+ for (const notification of notifications) {
220
+ const toolCall = getUpdateToolCall(notification.update)
221
+ if (toolCall) {
222
+ calls.push(toolCall)
223
+ }
224
+ }
225
+ return calls
226
+ }
227
+
228
+ /**
229
+ * Extracts the latest state of each tool call (deduplicated by toolCallId).
230
+ *
231
+ * @param notifications - Array of session notifications
232
+ * @returns Map of tool call ID to latest tool call state
233
+ */
234
+ export const extractLatestToolCalls = (notifications: SessionNotification[]): Map<string, ToolCall> => {
235
+ const latest = new Map<string, ToolCall>()
236
+ for (const notification of notifications) {
237
+ const toolCall = getUpdateToolCall(notification.update)
238
+ if (toolCall) {
239
+ latest.set(toolCall.toolCallId, toolCall)
240
+ }
241
+ }
242
+ return latest
243
+ }
244
+
245
+ /**
246
+ * Extracts the latest plan from session notifications.
247
+ *
248
+ * @param notifications - Array of session notifications
249
+ * @returns Latest plan entries or undefined if no plan
250
+ */
251
+ export const extractPlan = (notifications: SessionNotification[]): PlanEntry[] | undefined => {
252
+ // Plans are replaced entirely, so find the last one
253
+ for (let i = notifications.length - 1; i >= 0; i--) {
254
+ const notification = notifications[i]
255
+ if (notification) {
256
+ const plan = getUpdatePlan(notification.update)
257
+ if (plan) {
258
+ return plan
259
+ }
260
+ }
261
+ }
262
+ return undefined
263
+ }
264
+
265
+ // ============================================================================
266
+ // Tool Call Utilities
267
+ // ============================================================================
268
+
269
+ /**
270
+ * Filters tool calls by status.
271
+ *
272
+ * @param toolCalls - Array of tool calls
273
+ * @param status - Status to filter by
274
+ * @returns Filtered tool calls
275
+ */
276
+ export const filterToolCallsByStatus = (toolCalls: ToolCall[], status: ToolCall['status']): ToolCall[] => {
277
+ return toolCalls.filter((call) => call.status === status)
278
+ }
279
+
280
+ /**
281
+ * Filters tool calls by title.
282
+ *
283
+ * @param toolCalls - Array of tool calls
284
+ * @param title - Tool title to filter by
285
+ * @returns Filtered tool calls
286
+ */
287
+ export const filterToolCallsByTitle = (toolCalls: ToolCall[], title: string): ToolCall[] => {
288
+ return toolCalls.filter((call) => call.title === title)
289
+ }
290
+
291
+ /**
292
+ * Checks if any tool calls have failed.
293
+ *
294
+ * @param toolCalls - Array of tool calls
295
+ * @returns True if any tool call has 'failed' status
296
+ */
297
+ export const hasToolCallErrors = (toolCalls: ToolCall[]): boolean => {
298
+ return toolCalls.some((call) => call.status === 'failed')
299
+ }
300
+
301
+ /**
302
+ * Gets completed tool calls with their output content.
303
+ *
304
+ * @param toolCalls - Array of tool calls
305
+ * @returns Tool calls that completed with content
306
+ */
307
+ export const getCompletedToolCallsWithContent = (
308
+ toolCalls: ToolCall[],
309
+ ): Array<ToolCall & { content: ToolCallContent[] }> => {
310
+ return toolCalls.filter(
311
+ (call): call is ToolCall & { content: ToolCallContent[] } =>
312
+ call.status === 'completed' && call.content !== undefined && call.content.length > 0,
313
+ )
314
+ }
315
+
316
+ // ============================================================================
317
+ // Plan Utilities
318
+ // ============================================================================
319
+
320
+ /**
321
+ * Gets plan entries by status.
322
+ *
323
+ * @param plan - Array of plan entries
324
+ * @param status - Status to filter by
325
+ * @returns Filtered plan entries
326
+ */
327
+ export const filterPlanByStatus = (plan: PlanEntry[], status: PlanEntry['status']): PlanEntry[] => {
328
+ return plan.filter((entry) => entry.status === status)
329
+ }
330
+
331
+ /**
332
+ * Calculates plan completion percentage.
333
+ *
334
+ * @param plan - Array of plan entries
335
+ * @returns Percentage of completed entries (0-100)
336
+ */
337
+ export const getPlanProgress = (plan: PlanEntry[]): number => {
338
+ if (plan.length === 0) return 100
339
+ const completed = plan.filter((entry) => entry.status === 'completed').length
340
+ return Math.round((completed / plan.length) * 100)
341
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * ACP protocol constants.
3
+ *
4
+ * @remarks
5
+ * Contains all constant values used across the ACP client implementation:
6
+ * - Protocol method names
7
+ * - Protocol version
8
+ * - JSON-RPC error codes
9
+ */
10
+
11
+ // ============================================================================
12
+ // Protocol Methods
13
+ // ============================================================================
14
+
15
+ /** ACP method names */
16
+ export const ACP_METHODS = {
17
+ // Lifecycle
18
+ INITIALIZE: 'initialize',
19
+ SHUTDOWN: 'shutdown',
20
+
21
+ // Sessions
22
+ CREATE_SESSION: 'session/new',
23
+ LOAD_SESSION: 'session/load',
24
+ PROMPT: 'session/prompt',
25
+ CANCEL: 'session/cancel',
26
+ UPDATE: 'session/update',
27
+ REQUEST_PERMISSION: 'session/request_permission',
28
+ SET_MODEL: 'session/set_model',
29
+
30
+ // Protocol-level
31
+ CANCEL_REQUEST: '$/cancel_request',
32
+ } as const
33
+
34
+ // ============================================================================
35
+ // Protocol Version
36
+ // ============================================================================
37
+
38
+ /** Current protocol version - SDK uses number type */
39
+ export const ACP_PROTOCOL_VERSION = 1 as const
40
+
41
+ // ============================================================================
42
+ // JSON-RPC Error Codes
43
+ // ============================================================================
44
+
45
+ /** Standard JSON-RPC error codes */
46
+ export const JSON_RPC_ERRORS = {
47
+ PARSE_ERROR: -32700,
48
+ INVALID_REQUEST: -32600,
49
+ METHOD_NOT_FOUND: -32601,
50
+ INVALID_PARAMS: -32602,
51
+ INTERNAL_ERROR: -32603,
52
+ REQUEST_CANCELLED: -32800,
53
+ } as const
54
+
55
+ /** Default ACP Client Name */
56
+ export const DEFAULT_ACP_CLIENT_NAME = 'plaited-acp-client'
@@ -0,0 +1,161 @@
1
+ /**
2
+ * JSON-RPC 2.0 Zod schemas with runtime validation.
3
+ *
4
+ * @remarks
5
+ * These schemas provide runtime validation for JSON-RPC messages at the
6
+ * transport boundary. While the ACP SDK handles protocol-level types,
7
+ * the JSON-RPC framing layer is our responsibility since we implement
8
+ * a custom stdio transport.
9
+ *
10
+ * The schemas follow JSON-RPC 2.0 specification:
11
+ * - Requests have `id` and `method`
12
+ * - Notifications have `method` but no `id`
13
+ * - Responses have `id` and either `result` or `error`
14
+ */
15
+
16
+ import type { RequestPermissionRequest, SessionNotification } from '@agentclientprotocol/sdk'
17
+ import { z } from 'zod'
18
+
19
+ // ============================================================================
20
+ // Inlined Type Utilities
21
+ // ============================================================================
22
+
23
+ /** Precise type detection beyond typeof operator */
24
+ const trueTypeOf = (obj?: unknown): string => Object.prototype.toString.call(obj).slice(8, -1).toLowerCase()
25
+
26
+ /** Type guard for precise type checking with TypeScript narrowing */
27
+ const isTypeOf = <T>(obj: unknown, type: string): obj is T => trueTypeOf(obj) === type
28
+
29
+ // ============================================================================
30
+ // JSON-RPC Base Schemas
31
+ // ============================================================================
32
+
33
+ /** JSON-RPC version literal */
34
+ const JsonRpcVersionSchema = z.literal('2.0')
35
+
36
+ /** Request/response identifier */
37
+ const RequestIdSchema = z.union([z.string(), z.number()])
38
+
39
+ /**
40
+ * JSON-RPC 2.0 error object schema.
41
+ *
42
+ * @remarks
43
+ * Standard error codes:
44
+ * - `-32700`: Parse error
45
+ * - `-32600`: Invalid request
46
+ * - `-32601`: Method not found
47
+ * - `-32602`: Invalid params
48
+ * - `-32603`: Internal error
49
+ * - `-32800`: Request cancelled (ACP extension)
50
+ */
51
+ export const JsonRpcErrorSchema = z.object({
52
+ code: z.number(),
53
+ message: z.string(),
54
+ data: z.unknown().optional(),
55
+ })
56
+
57
+ /** JSON-RPC 2.0 request schema */
58
+ export const JsonRpcRequestSchema = z.object({
59
+ jsonrpc: JsonRpcVersionSchema,
60
+ id: RequestIdSchema,
61
+ method: z.string(),
62
+ params: z.unknown().optional(),
63
+ })
64
+
65
+ /** JSON-RPC 2.0 notification schema (no id, no response expected) */
66
+ export const JsonRpcNotificationSchema = z.object({
67
+ jsonrpc: JsonRpcVersionSchema,
68
+ method: z.string(),
69
+ params: z.unknown().optional(),
70
+ })
71
+
72
+ /** JSON-RPC 2.0 success response schema */
73
+ export const JsonRpcSuccessResponseSchema = z.object({
74
+ jsonrpc: JsonRpcVersionSchema,
75
+ id: RequestIdSchema,
76
+ result: z.unknown(),
77
+ })
78
+
79
+ /** JSON-RPC 2.0 error response schema */
80
+ export const JsonRpcErrorResponseSchema = z.object({
81
+ jsonrpc: JsonRpcVersionSchema,
82
+ id: z.union([RequestIdSchema, z.null()]),
83
+ error: JsonRpcErrorSchema,
84
+ })
85
+
86
+ /** Union of all JSON-RPC response types */
87
+ export const JsonRpcResponseSchema = z.union([JsonRpcSuccessResponseSchema, JsonRpcErrorResponseSchema])
88
+
89
+ /**
90
+ * Union of all JSON-RPC message types.
91
+ *
92
+ * @remarks
93
+ * Use `safeParse` at transport boundaries for runtime validation.
94
+ * See transport tests for usage patterns.
95
+ */
96
+ export const JsonRpcMessageSchema = z.union([JsonRpcRequestSchema, JsonRpcNotificationSchema, JsonRpcResponseSchema])
97
+
98
+ // ============================================================================
99
+ // Inferred Types
100
+ // ============================================================================
101
+
102
+ /** JSON-RPC 2.0 error object */
103
+ export type JsonRpcError = z.infer<typeof JsonRpcErrorSchema>
104
+
105
+ /** JSON-RPC 2.0 request structure */
106
+ export type JsonRpcRequest<T = unknown> = Omit<z.infer<typeof JsonRpcRequestSchema>, 'params'> & {
107
+ params?: T
108
+ }
109
+
110
+ /** JSON-RPC 2.0 notification structure (no id, no response expected) */
111
+ export type JsonRpcNotification<T = unknown> = Omit<z.infer<typeof JsonRpcNotificationSchema>, 'params'> & {
112
+ params?: T
113
+ }
114
+
115
+ /** JSON-RPC 2.0 success response */
116
+ export type JsonRpcSuccessResponse<T = unknown> = Omit<z.infer<typeof JsonRpcSuccessResponseSchema>, 'result'> & {
117
+ result: T
118
+ }
119
+
120
+ /** JSON-RPC 2.0 error response */
121
+ export type JsonRpcErrorResponse = z.infer<typeof JsonRpcErrorResponseSchema>
122
+
123
+ /** Union of all JSON-RPC response types */
124
+ export type JsonRpcResponse<T = unknown> = JsonRpcSuccessResponse<T> | JsonRpcErrorResponse
125
+
126
+ /** Union of all JSON-RPC message types */
127
+ export type JsonRpcMessage<T = unknown> = JsonRpcRequest<T> | JsonRpcNotification<T> | JsonRpcResponse<T>
128
+
129
+ // ============================================================================
130
+ // ACP SDK Type Schemas
131
+ // ============================================================================
132
+
133
+ /**
134
+ * These schemas use z.custom() to validate SDK types at runtime.
135
+ * They validate only the fields we actually use, keeping SDK types
136
+ * as the source of truth while adding runtime safety.
137
+ */
138
+
139
+ /** Type guard for object shape validation */
140
+ const isRecord = (val: unknown): val is Record<string, unknown> => isTypeOf<Record<string, unknown>>(val, 'object')
141
+
142
+ /**
143
+ * Schema for session update notifications.
144
+ *
145
+ * @remarks
146
+ * Validates `sessionId` and `update` fields used in notification handling.
147
+ */
148
+ export const SessionNotificationSchema = z.custom<SessionNotification>(
149
+ (val): val is SessionNotification =>
150
+ isRecord(val) && 'sessionId' in val && typeof val.sessionId === 'string' && 'update' in val && isRecord(val.update),
151
+ )
152
+
153
+ /**
154
+ * Schema for permission requests from agent.
155
+ *
156
+ * @remarks
157
+ * Validates `options` array used in permission handling.
158
+ */
159
+ export const RequestPermissionRequestSchema = z.custom<RequestPermissionRequest>(
160
+ (val): val is RequestPermissionRequest => isRecord(val) && 'options' in val && Array.isArray(val.options),
161
+ )
package/src/acp.ts ADDED
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @plaited/acp-harness - ACP client and evaluation harness for TypeScript/Bun projects.
3
+ *
4
+ * @remarks
5
+ * This module provides a headless ACP client for programmatic agent interaction,
6
+ * optimized for testing, evaluation, and training data generation.
7
+ *
8
+ * **Primary exports:**
9
+ * - `createACPClient` - Factory for headless ACP client instances
10
+ * - `createPrompt`, `createPromptWithFiles`, `createPromptWithImage` - Prompt builders
11
+ * - `summarizeResponse` - Response analysis utility
12
+ *
13
+ * **Re-exports from acp-utils (for advanced usage):**
14
+ * - Content builders: `createTextContent`, `createImageContent`, `createAudioContent`,
15
+ * `createResourceLink`, `createTextResource`, `createBlobResource`
16
+ * - Content extractors: `extractText`, `extractTextFromUpdates`, `extractToolCalls`,
17
+ * `extractLatestToolCalls`, `extractPlan`
18
+ * - Tool call utilities: `filterToolCallsByStatus`, `filterToolCallsByTitle`,
19
+ * `hasToolCallErrors`, `getCompletedToolCallsWithContent`
20
+ * - Plan utilities: `filterPlanByStatus`, `getPlanProgress`
21
+ *
22
+ * @packageDocumentation
23
+ */
24
+
25
+ export * from './acp-client.ts'
26
+ export * from './acp-helpers.ts'
27
+ export * from './acp-utils.ts'
@@ -0,0 +1,28 @@
1
+ /**
2
+ * ACP type definitions.
3
+ *
4
+ * @remarks
5
+ * This module contains types specific to the ACP client implementation.
6
+ * For SDK types (ToolCall, ContentBlock, SessionNotification, etc.), import
7
+ * directly from `@agentclientprotocol/sdk`.
8
+ *
9
+ * For runtime validation of JSON-RPC messages, import Zod schemas from
10
+ * `./acp.schemas.ts`.
11
+ *
12
+ * For protocol constants, import from `./acp.constants.ts`.
13
+ */
14
+
15
+ import type { SessionId } from '@agentclientprotocol/sdk'
16
+
17
+ // ============================================================================
18
+ // Session Types
19
+ // ============================================================================
20
+
21
+ /**
22
+ * Session object returned from session creation.
23
+ * Contains the session ID for subsequent operations.
24
+ */
25
+ export type Session = {
26
+ id: SessionId
27
+ _meta?: { [key: string]: unknown } | null
28
+ }