@acpjs/client 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 CHANGED
@@ -30,7 +30,11 @@ const agent = await client.agents.spawn({
30
30
  args: ['some-acp-agent'],
31
31
  })
32
32
 
33
- const session = await agent.sessions.create({ cwd: process.cwd() })
33
+ const session = await agent.sessions.create({
34
+ cwd: process.cwd(),
35
+ mcpServers: [],
36
+ additionalDirectories: [],
37
+ })
34
38
  session.subscribe(() => render(session.getSnapshot()))
35
39
 
36
40
  client.permissions.subscribe((requests) => {
@@ -63,66 +67,65 @@ await client.dispose()
63
67
  await host.dispose()
64
68
  ```
65
69
 
66
- ## Public API (closed surface, SPEC §6.4)
70
+ ## Public API (closed surface)
67
71
 
68
72
  The export surface is exactly three values: `createAcpClient`, `createInProcessTransport`, and `AcpClientError` (pinned by an API snapshot test). There is no raw RPC send, no raw protocol notification subscription, and no store selector parameter.
69
73
 
70
74
  - `createAcpClient({ transport })` → `AcpClient`
71
- - `client.agents.spawn(definition)` → `Promise<AcpAgent>`. `definition` is an `AgentDefinition` (`id`, `command`, `args?`, `env?`, `cwd?`, `meta?`). The returned handle carries `agentId` plus `capabilities?` / `authMethods?` passed through from initialize.
75
+ - `client.agents.spawn(definition)` → `Promise<AcpAgent>`. `definition` is an `AgentDefinition` (`id`, `command`, `args?`, `env?`, `cwd?`, `meta?`). Read runtime capabilities from `agent.getSnapshot().capabilities`; this projection exposes only acpjs-supported stable ACP capabilities and excludes auth/provider configuration surfaces.
72
76
  - `client.agents.get(agentId)` → `AcpAgent | undefined`: look up a known handle by id (same reference returned by spawn / attach).
73
77
  - `client.agents.getSnapshot()` → `readonly AcpAgent[]`: cached immutable snapshot of the handle set — a new reference is produced only when the set changes (`useSyncExternalStore` compatible).
74
78
  - `client.agents.subscribe(() => ...)`: notification when the agent handle set changes (no immediate callback; read the initial value via `getSnapshot`).
75
- - `client.agents.list()` → `Promise<readonly AgentSnapshot[]>`: a one-shot RPC query of every agent known to the host (`agentId` / `status` / `restartCount` / `reason?` / `exit?` / `capabilities?` / `authMethods?` / `authRequired?`), non-reactive.
79
+ - `client.agents.list()` → `Promise<readonly AgentSnapshotWire[]>`: a one-shot RPC query of every agent known to the host (`agentId` / `status` / `restartCount` / `reason?` / `exit?` / `capabilities?`), non-reactive.
76
80
  - `client.agents.attach(agentId)` → `Promise<AcpAgent>`: hydrate an agent that already exists on the host into a handle (internally calls `list()` to verify existence). An unknown id rejects with `acpjs/agent-exited`; an existing handle is reused.
77
81
  - `client.sessions.get(sessionId)` → `AcpSession | undefined`: look up a known session handle by id. create / load / resume / attach for the same sessionId share one frozen handle.
78
- - `client.sessions.getSnapshot()` → `readonly AcpSession[]`: cached immutable snapshot of the session handle set.
82
+ - `client.sessions.getSnapshot()` → `readonly AcpSession[]`: cached immutable snapshot of the host-projected session handle set.
79
83
  - `client.sessions.subscribe(() => ...)`: notification when the session handle set changes.
80
- - `client.sessions.list()` → `Promise<readonly SessionSnapshot[]>`: a one-shot RPC query of every session known to the host (`sessionId` / `status` / `agentId?` / `cwd?` / `agentDefinitionId?`), non-reactive.
84
+ - `client.sessions.list()` → `Promise<readonly SessionSnapshotWire[]>`: a one-shot RPC query of every session known to the host (`sessionId` / `status` / `agentId?` / `cwd` / `mcpServers?` / `additionalDirectories` / `agentDefinitionId?`), non-reactive.
81
85
  - `client.sessions.attach(sessionId)` → `Promise<AcpSession>`: re-attach to an existing session **without an agent handle** (internally calls `list()`; if present it subscribes and rebuilds state via replay from `fromSeq: 0`). An unknown id rejects with `acpjs/session-closed`.
82
- - `client.sessions.restore()` → `Promise<readonly SessionSnapshot[]>`: after a host restart, rebuild `disconnected` sessions from storage and return their snapshots.
86
+ - `client.sessions.restore()` → `Promise<readonly SessionSnapshotWire[]>`: after a host restart, rebuild `disconnected` sessions from storage and return their snapshots.
83
87
  - `client.permissions.getSnapshot()` → `readonly PermissionRequest[]`: cached immutable reference of the pending permission-request list — a new reference is produced only when the set changes.
84
88
  - `client.permissions.subscribe((requests) => ...)`: notification with the latest snapshot on any add/remove of the pending set (new request, respond, other-client answer / superseded); no immediate callback (read the initial value via `getSnapshot`). Each `request` carries `requestId` / `sessionId` / `toolCall` / `options` (protocol pass-through) and `respond(outcome)`.
89
+ - `client.diagnostics.getSnapshot()` → `readonly DiagnosticEvent[]`: cached immutable snapshot of the diagnostic log — a bounded buffer of the most recent 200 events (oldest evicted), surfacing agent diagnostics such as `stderr`, `spawn-failed`, `restart-scheduled` (with backoff), and `process-error`.
90
+ - `client.diagnostics.subscribe(() => ...)`: notification when a new diagnostic arrives (no immediate callback; read the initial value via `getSnapshot`).
85
91
  - `client.status.getSnapshot()` → `ConnectionStatusSnapshot` (`{ status: 'connecting' | 'connected' | 'closed', error? }`): cached immutable snapshot of the connection status.
86
92
  - `client.status.subscribe(() => ...)`: notification when the connection status changes (no immediate callback; read the initial value via `getSnapshot`).
87
93
  - `client.dispose()`: close the transport; afterwards every call rejects with `acpjs/transport-closed`.
88
94
  - `AcpAgent`
89
- - `agent.agentId`, `agent.capabilities?`, `agent.authMethods?`: readonly handle properties.
90
- - `agent.getSnapshot()` → `AgentSnapshot`: cached immutable snapshot of this agent's runtime state (`status` / `restartCount` / `reason?` / `exit?` / `capabilities?` / `authMethods?` / `authRequired?`). `restartCount` is driven by live `agent-status-change` events; `authRequired` / `authMethods` reflect the waiting-for-auth dimension driven by host-level `auth-required` events (SPEC §4.11, §8.2).
95
+ - `agent.agentId`: readonly handle property.
96
+ - `agent.getSnapshot()` → `AgentSnapshotWire`: cached immutable snapshot of this agent's runtime state (`status` / `restartCount` / `reason?` / `exit?` / `capabilities?`). It is driven by host-level `agent-updated` projections.
91
97
  - `agent.subscribe(() => ...)`: notification when the runtime state changes (no immediate callback; read the initial value via `getSnapshot`).
92
- - `agent.sessions.create({ cwd, mcpServers? })` / `load(sessionId, { cwd, mcpServers? })` / `list({ cursor?, cwd? })` / `resume(sessionId)` / `delete(sessionId)`.
93
- - `agent.authenticate(methodId)` / `agent.logout()`.
98
+ - `agent.sessions.create({ cwd, mcpServers, additionalDirectories })` / `load(sessionId, { cwd, mcpServers, additionalDirectories })` / `list({ cursor?, cwd? })` / `resume(sessionId, { cwd, mcpServers?, additionalDirectories })` / `delete(sessionId)`.
94
99
  - `AcpSession`
95
100
  - `session.sessionId`: readonly id.
96
101
  - `session.getSnapshot()` → `SessionState`: cached immutable reference — a new reference is produced only when a new event arrives (`useSyncExternalStore` compatible).
97
102
  - `session.subscribe((state) => ...)`: notification when state changes (the current value is not replayed; read the initial value via `getSnapshot`).
98
- - `session.prompt(ContentBlock[])` → `Promise<PromptFinishedPayload>`: protocol content blocks passed through with no rewriting (SPEC §12). Also `cancel()`, `close()`, `setMode(modeId)`, `setConfigOption(configId, value)`.
103
+ - `session.prompt(ContentBlock[])` → `Promise<PromptFinishedPayload>`: protocol content blocks passed through with no rewriting. Also `cancel()`, `close()`, `setMode(modeId)`, `setConfigOption(configId, value)`.
99
104
  - Slash commands are not a separate API: `SessionState.availableCommands` only enumerates available commands for autocompletion UI. To invoke a command, write a `/`-prefixed text block in the prompt, which may be mixed with other blocks — `session.prompt([{ type: 'text', text: '/web query' }])`. There is no `invokeCommand`-style method.
100
105
  - Every error is an `AcpClientError` (an `ErrorObject` shape: `code` (acpjs/\*), `message`, `data?`, `retryable`). A capability-gated method whose capability was not declared rejects with `acpjs/capability-unsupported` (core semantics passed through); a second answer to a permission rejects with `acpjs/already-answered`.
101
106
 
102
- ## State construction (SPEC §9.2)
107
+ ## State construction
103
108
 
104
109
  The only client-side state-construction path: the transport receives an `AcpEvent` → the `reduce` function from `@acpjs/protocol` replays it in `seq` order. Subscriptions carry `fromSeq`; a late subscriber / reconnection is backfilled by replay and ends up deeply equal to a full-duration subscriber (INV-2). A duplicate event whose `seq` was already applied is ignored.
105
110
 
106
111
  ## Transport
107
112
 
108
- The client consumes the Transport contract from `@acpjs/protocol` (`connect` / `request` / `subscribe` / `respondInbound` / `close`, with lifecycle `connecting → connected → closed` plus an error termination path). The built-in `createInProcessTransport(endpoint)` connects to `@acpjs/core`'s `createHostEndpoint(host)` (the client only sees contract types and has zero dependency on core; SPEC §6.2). Reconnection is not a transport obligation; a new connection backfills via `fromSeq`.
113
+ The client consumes the Transport contract from `@acpjs/protocol` (`connect` / `request` / `subscribe` / `respondInbound` / `close`, with lifecycle `connecting → connected → closed` plus an error termination path). The built-in `createInProcessTransport(endpoint)` connects to `@acpjs/core`'s `createHostEndpoint(host)` (the client only sees contract types and has zero dependency on core). Reconnection is not a transport obligation; a new connection backfills via `fromSeq`.
109
114
 
110
- ## Implementation-defined decisions (SPEC §15)
115
+ ## Implementation-defined decisions
111
116
 
112
117
  - **RPC id format**: `rpc-<n>` (monotonic counter within a client instance).
113
- - **RPC method names**: sourced from `@acpjs/protocol`'s `ACP_RPC_METHODS` (`agents/spawn|authenticate|logout|list`, `sessions/create|load|list|resume|delete|prompt|cancel|close|setMode|setConfigOption|getAll|restore`), the same constant table consumed by core's `createHostEndpoint` (pinned by protocol and end-to-end tests).
114
- - **auth-required facade shape (create-time)**: `sessions.create` does not return a union type; instead it rejects with an `AcpClientError` (`code: 'acpjs/auth-required'`, `retryable: true`, `data.authMethods` is the protocol original). After `authenticate`, the consumer retries create. In parallel the agent's runtime snapshot becomes observable as waiting-for-auth (`authRequired: true` + `authMethods`), driven by the host-level `auth-required` event.
115
- - **store subscription timing**: one store per sessionId; on first acquiring a session handle (create / load / resume / attach) it subscribes from `fromSeq: 0`. Within one client the same sessionId reuses the same store, the same frozen handle, and the same subscription.
118
+ - **RPC method names**: sourced from `@acpjs/protocol`'s `ACPJS_HOST_RPC_METHODS` (`agents/spawn|list`, `sessions/create|load|list|resume|delete|prompt|cancel|close|setMode|setConfigOption|getAll|restore`), the same constant table consumed by core's `createHostEndpoint` (pinned by protocol and end-to-end tests).
119
+ - **auth errors**: acpjs does not expose login APIs or auth state. Agent-side authentication failures during create/load/resume reject as `AcpClientError` with `code: 'acpjs/agent-error'` and the original JSON-RPC error in `data`; prompt-time agent JSON-RPC errors resolve in `PromptFinishedPayload.error`.
120
+ - **host projection mirror**: agent/session registries are reactive mirrors of the host stream. A session created by Node/main or another renderer appears in `client.sessions.getSnapshot()` when the client receives `session-updated`; no local create/attach call is required.
121
+ - **store subscription timing**: one store per sessionId; on first acquiring a session handle from create / load / resume / attach or from a host `session-updated` projection it subscribes from `fromSeq: 0`. Within one client the same sessionId reuses the same store, the same frozen handle, and the same subscription. Host projections also update the store's connection status/title fields so list UI can reflect status changes before a prompt event arrives.
116
122
  - **subscribe does not call back immediately**: consistent with external-store conventions (session state, agent/session registries, connection status, and the permission list all behave this way); read the initial value via `getSnapshot` / `get`.
117
123
  - **connection status store**: `client.status` maintains a single `ConnectionStatusSnapshot`, advancing `connecting → connected → closed` with the transport lifecycle (termination may carry an `error`); entering `closed` also clears the pending permission snapshot. No duplicate notification when neither status nor error changes.
118
124
  - **sessions.attach semantics**: does not go through an agent handle — it uses `sessions.list()` to verify the sessionId is still known to the host; if present it creates a store and rebuilds state by replaying from `fromSeq: 0`; an unknown id rejects with `acpjs/session-closed`. Suitable for re-attaching to an existing session across windows / after a page reload.
119
- - **agents/sessions list/restore are one-shot RPC queries**: `agents.list()` / `sessions.list()` / `sessions.restore()` are non-reactive request/response snapshots (for enumeration and hydration), returning wire-level `AgentSnapshot` / `SessionSnapshot` without subscribing to subsequent changes; for reactive observation use the corresponding `getSnapshot` / `subscribe`.
120
- - **permission-request exit**: a request leaves the pending set (and subscribers are notified with a new snapshot) when respond succeeds, when respond is rejected with `acpjs/already-answered` (someone else already answered), or when the owning session's event stream emits `permission-request-resolved` (other-client answer / superseded). A late consumer reading `getSnapshot` only sees still-pending requests. Under multi-client races, a respond rejected with `acpjs/already-answered` is the normal path — the pending list has converged and consumers should ignore that code rather than treat it as an error. Inbound requests whose kind is not `permission` are ignored (forward compatibility).
125
+ - **agents/sessions list/restore are one-shot RPC queries**: `agents.list()` / `sessions.list()` / `sessions.restore()` are request/response snapshots for enumeration and hydration, returning wire-level `AgentSnapshotWire` / `SessionSnapshotWire`. Reactive observation uses host projections through the corresponding `getSnapshot` / `subscribe` registries.
126
+ - **permission-request source and exit**: pending permissions are sourced from host-level `permission-updated` projections. Inbound requests are only the response transport path and are not treated as permission state. A request leaves the pending set (and subscribers are notified with a new snapshot) when respond succeeds, when respond is rejected with `acpjs/already-answered` (someone else already answered), or when the host emits `permission-updated` with answered/superseded. A late consumer reading `getSnapshot` only sees still-pending requests. Under multi-client races, a respond rejected with `acpjs/already-answered` is the normal path — the pending list has converged and consumers should ignore that code rather than treat it as an error.
121
127
  - **dispose semantics**: mark closed → unsubscribe all store subscriptions → clear permission subscribers and the pending permission set → `transport.close()`; idempotent.
122
- - **in-process direct-call mechanism** (named in the §15 checklist): `createInProcessTransport(endpoint)` implements the Transport contract via direct function calls — `request` / `subscribe` / `respondInbound` forward straight to `@acpjs/core`'s `EnvelopeEndpoint` (provided by `createHostEndpoint(host)`), with no JSON serialization and no transport boundary. `connect` wires up inbound requests via `endpoint.onInboundRequest` and advances the lifecycle to `connected`; inbound requests (such as permissions) are handed to the client as-is. Payloads remain structured-clone safe (INV-3, asserted by end-to-end tests). After close, `request` responds with an `acpjs/transport-closed` error, `respondInbound` rejects, and `subscribe` throws an `AcpClientError` (surfacing misuse early); a repeated `connect` throws `acpjs/config-invalid`; `close` is idempotent and unsubscribes all active subscriptions. Reconnection is not part of the contract obligation; a new connection backfills state via `fromSeq`.
123
- - **listener-callback exceptions**: session-state listeners and permission listeners that throw are isolated (swallowed, without interrupting dispatch to the rest of the batch; there is no client-side diagnostic channel).
128
+ - **in-process direct-call mechanism**: `createInProcessTransport(endpoint)` implements the Transport contract via direct function calls — `request` / `subscribe` / `respondInbound` forward straight to `@acpjs/core`'s `EnvelopeEndpoint` (provided by `createHostEndpoint(host)`), with no JSON serialization and no transport boundary. `connect` wires up inbound requests via `endpoint.onInboundRequest` and advances the lifecycle to `connected`; inbound requests (such as permissions) are handed to the client as-is. Payloads remain structured-clone safe (INV-3, asserted by end-to-end tests). After close, `request` responds with an `acpjs/transport-closed` error, `respondInbound` rejects, and `subscribe` throws an `AcpClientError` (surfacing misuse early); a repeated `connect` throws `acpjs/config-invalid`; `close` is idempotent and unsubscribes all active subscriptions. Reconnection is not part of the contract obligation; a new connection backfills state via `fromSeq`.
129
+ - **listener-callback exceptions**: session-state listeners and permission listeners that throw are isolated (swallowed, without interrupting dispatch to the rest of the batch).
130
+ - **diagnostics store**: `client.diagnostics` maintains a bounded log (most recent `MAX_DIAGNOSTICS = 200`; oldest evicted) of host-projected `diagnostic` events, surfacing agent stderr, spawn-failed, restart-scheduled (with backoff), and process-error. `getSnapshot` returns a frozen `readonly DiagnosticEvent[]` and `subscribe` notifies on each new event (no immediate callback). Diagnostic-listener exceptions are isolated like the other channels.
124
131
  - **connect failure**: every facade call rejects with the lifecycle error (or `acpjs/transport-closed`).
125
-
126
- ```
127
-
128
- ```
package/dist/index.d.ts CHANGED
@@ -1,8 +1,6 @@
1
- import { AcpErrorCode, AgentCapabilities, AgentDefinition, AgentSnapshotWire, AuthMethod, ContentBlock, EnvelopeEndpoint, ErrorObject, ListSessionsResponse, McpServer, PermissionRequestCreatedPayload, PromptFinishedPayload, RequestPermissionOutcome, SessionConfigOption, SessionConfigValue, SessionSnapshotWire, SessionState, Transport, TransportConnectionStatus } from "@acpjs/protocol";
1
+ import { AcpErrorCode, AgentDefinition, AgentSnapshotWire, AgentSnapshotWire as AgentSnapshotWire$1, ContentBlock, CreateOrLoadSessionParams, DiagnosticEvent, DiagnosticEvent as DiagnosticEvent$1, EnvelopeEndpoint, ErrorObject, ListSessionsResponse, PermissionRequestCreatedPayload, PromptFinishedPayload, RequestPermissionOutcome, ResumeSessionParams, SessionConfigOption, SessionConfigValue, SessionSnapshotWire, SessionSnapshotWire as SessionSnapshotWire$1, SessionState, Transport, TransportConnectionStatus } from "@acpjs/protocol";
2
2
 
3
3
  //#region src/types.d.ts
4
- type AgentSnapshot = AgentSnapshotWire;
5
- type SessionSnapshot = SessionSnapshotWire;
6
4
  interface AcpSession {
7
5
  readonly sessionId: string;
8
6
  getSnapshot: () => SessionState;
@@ -13,30 +11,22 @@ interface AcpSession {
13
11
  setMode: (modeId: string) => Promise<void>;
14
12
  setConfigOption: (configId: string, value: SessionConfigValue) => Promise<SessionConfigOption[]>;
15
13
  }
16
- interface SessionCreateParams {
17
- cwd: string;
18
- mcpServers?: McpServer[];
19
- }
20
14
  interface SessionListParams {
21
15
  cursor?: string;
22
16
  cwd?: string;
23
17
  }
24
18
  interface AcpAgentSessions {
25
- create: (params: SessionCreateParams) => Promise<AcpSession>;
26
- load: (sessionId: string, params: SessionCreateParams) => Promise<AcpSession>;
19
+ create: (params: CreateOrLoadSessionParams) => Promise<AcpSession>;
20
+ load: (sessionId: string, params: CreateOrLoadSessionParams) => Promise<AcpSession>;
27
21
  list: (params?: SessionListParams) => Promise<ListSessionsResponse>;
28
- resume: (sessionId: string) => Promise<AcpSession>;
22
+ resume: (sessionId: string, params: ResumeSessionParams) => Promise<AcpSession>;
29
23
  delete: (sessionId: string) => Promise<void>;
30
24
  }
31
25
  interface AcpAgent {
32
26
  readonly agentId: string;
33
- readonly capabilities?: AgentCapabilities;
34
- readonly authMethods?: AuthMethod[];
35
- getSnapshot: () => AgentSnapshot;
27
+ getSnapshot: () => AgentSnapshotWire$1;
36
28
  subscribe: (listener: ChangeListener) => () => void;
37
29
  readonly sessions: AcpAgentSessions;
38
- authenticate: (methodId: string) => Promise<void>;
39
- logout: () => Promise<void>;
40
30
  }
41
31
  interface PermissionRequest {
42
32
  readonly requestId: string;
@@ -57,21 +47,25 @@ interface AcpClient {
57
47
  get: (agentId: string) => AcpAgent | undefined;
58
48
  getSnapshot: () => readonly AcpAgent[];
59
49
  subscribe: (listener: ChangeListener) => () => void;
60
- list: () => Promise<readonly AgentSnapshot[]>;
50
+ list: () => Promise<readonly AgentSnapshotWire$1[]>;
61
51
  attach: (agentId: string) => Promise<AcpAgent>;
62
52
  };
63
53
  readonly sessions: {
64
54
  get: (sessionId: string) => AcpSession | undefined;
65
55
  getSnapshot: () => readonly AcpSession[];
66
56
  subscribe: (listener: ChangeListener) => () => void;
67
- list: () => Promise<readonly SessionSnapshot[]>;
57
+ list: () => Promise<readonly SessionSnapshotWire$1[]>;
68
58
  attach: (sessionId: string) => Promise<AcpSession>;
69
- restore: () => Promise<readonly SessionSnapshot[]>;
59
+ restore: () => Promise<readonly SessionSnapshotWire$1[]>;
70
60
  };
71
61
  readonly permissions: {
72
62
  getSnapshot: () => readonly PermissionRequest[];
73
63
  subscribe: (listener: PermissionListener) => () => void;
74
64
  };
65
+ readonly diagnostics: {
66
+ getSnapshot: () => readonly DiagnosticEvent$1[];
67
+ subscribe: (listener: ChangeListener) => () => void;
68
+ };
75
69
  readonly status: {
76
70
  getSnapshot: () => ConnectionStatusSnapshot;
77
71
  subscribe: (listener: ChangeListener) => () => void;
@@ -96,5 +90,5 @@ declare class AcpClientError extends Error {
96
90
  //#region src/in-process.d.ts
97
91
  declare function createInProcessTransport(endpoint: EnvelopeEndpoint): Transport;
98
92
  //#endregion
99
- export { type AcpAgent, type AcpAgentSessions, type AcpClient, AcpClientError, type AcpSession, type AgentDefinition, type AgentSnapshot, type ChangeListener, type ConnectionStatusSnapshot, type CreateAcpClientOptions, type PermissionListener, type PermissionRequest, type SessionConfigValue, type SessionCreateParams, type SessionListParams, type SessionSnapshot, createAcpClient, createInProcessTransport };
93
+ export { type AcpAgent, type AcpAgentSessions, type AcpClient, AcpClientError, type AcpSession, type AgentDefinition, type AgentSnapshotWire, type ChangeListener, type ConnectionStatusSnapshot, type CreateAcpClientOptions, type CreateOrLoadSessionParams, type DiagnosticEvent, type PermissionListener, type PermissionRequest, type ResumeSessionParams, type SessionConfigValue, type SessionListParams, type SessionSnapshotWire, createAcpClient, createInProcessTransport };
100
94
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/client.ts","../src/errors.ts","../src/in-process.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/client.ts","../src/errors.ts","../src/in-process.ts"],"mappings":";;;UAuBiB,UAAA;EAAA,SACN,SAAA;EACT,WAAA,QAAmB,YAAA;EACnB,SAAA,GAAY,QAAA,GAAW,KAAA,EAAO,YAAA;EAC9B,MAAA,GAAS,MAAA,EAAQ,YAAA,OAAmB,OAAA,CAAQ,qBAAA;EAC5C,MAAA,QAAc,OAAA;EACd,KAAA,QAAa,OAAA;EACb,OAAA,GAAU,MAAA,aAAmB,OAAA;EAC7B,eAAA,GACE,QAAA,UACA,KAAA,EAAO,kBAAA,KACJ,OAAA,CAAQ,mBAAA;AAAA;AAAA,UAGE,iBAAA;EACf,MAAA;EACA,GAAG;AAAA;AAAA,UAGY,gBAAA;EACf,MAAA,GAAS,MAAA,EAAQ,yBAAA,KAA8B,OAAA,CAAQ,UAAA;EACvD,IAAA,GACE,SAAA,UACA,MAAA,EAAQ,yBAAA,KACL,OAAA,CAAQ,UAAA;EACb,IAAA,GAAO,MAAA,GAAS,iBAAA,KAAsB,OAAA,CAAQ,oBAAA;EAC9C,MAAA,GACE,SAAA,UACA,MAAA,EAAQ,mBAAA,KACL,OAAA,CAAQ,UAAA;EACb,MAAA,GAAS,SAAA,aAAsB,OAAA;AAAA;AAAA,UAGhB,QAAA;EAAA,SACN,OAAA;EACT,WAAA,QAAmB,mBAAA;EACnB,SAAA,GAAY,QAAA,EAAU,cAAA;EAAA,SACb,QAAA,EAAU,gBAAA;AAAA;AAAA,UAGJ,iBAAA;EAAA,SACN,SAAA;EAAA,SACA,SAAA;EAAA,SACA,QAAA,EAAU,+BAAA;EAAA,SACV,OAAA,EAAS,+BAAA;EAClB,OAAA,GAAU,OAAA,EAAS,wBAAA,KAA6B,OAAA;AAAA;AAAA,KAGtC,kBAAA,IACV,QAAsC,WAAnB,iBAAiB;AAAA,KAG1B,cAAA;AAAA,UAEK,wBAAA;EACf,MAAA,EAAQ,yBAAA;EACR,KAAA,GAAQ,WAAW;AAAA;AAAA,UAGJ,SAAA;EAAA,SACN,MAAA;IACP,KAAA,GAAQ,UAAA,EAAY,eAAA,KAAoB,OAAA,CAAQ,QAAA;IAChD,GAAA,GAAM,OAAA,aAAoB,QAAA;IAC1B,WAAA,iBAA4B,QAAA;IAC5B,SAAA,GAAY,QAAA,EAAU,cAAA;IACtB,IAAA,QAAY,OAAA,UAAiB,mBAAA;IAC7B,MAAA,GAAS,OAAA,aAAoB,OAAA,CAAQ,QAAA;EAAA;EAAA,SAE9B,QAAA;IACP,GAAA,GAAM,SAAA,aAAsB,UAAA;IAC5B,WAAA,iBAA4B,UAAA;IAC5B,SAAA,GAAY,QAAA,EAAU,cAAA;IACtB,IAAA,QAAY,OAAA,UAAiB,qBAAA;IAC7B,MAAA,GAAS,SAAA,aAAsB,OAAA,CAAQ,UAAA;IACvC,OAAA,QAAe,OAAA,UAAiB,qBAAA;EAAA;EAAA,SAEzB,WAAA;IACP,WAAA,iBAA4B,iBAAA;IAC5B,SAAA,GAAY,QAAA,EAAU,kBAAA;EAAA;EAAA,SAEf,WAAA;IACP,WAAA,iBAA4B,iBAAA;IAC5B,SAAA,GAAY,QAAA,EAAU,cAAA;EAAA;EAAA,SAEf,MAAA;IACP,WAAA,QAAmB,wBAAA;IACnB,SAAA,GAAY,QAAA,EAAU,cAAA;EAAA;EAExB,OAAA,QAAe,OAAA;AAAA;AAAA,UAGA,sBAAA;EACf,SAAA,EAAW,SAAS;AAAA;;;iBCrFN,eAAA,CAAgB,OAAA,EAAS,sBAAA,GAAyB,SAAS;;;cCvB9D,cAAA,SAAuB,KAAA;EAClC,IAAA,EAAM,YAAA;EACN,IAAA;EACA,SAAA;cAEY,KAAA,EAAO,WAAA;AAAA;;;iBCFL,wBAAA,CACd,QAAA,EAAU,gBAAA,GACT,SAAS"}
package/dist/index.js CHANGED
@@ -1,47 +1,4 @@
1
- import { ACP_ERROR_CODES, ACP_RPC_METHODS, createInitialSessionState, isAcpErrorCode, reduce } from "@acpjs/protocol";
2
- //#region src/errors.ts
3
- var AcpClientError = class extends Error {
4
- code;
5
- data;
6
- retryable;
7
- constructor(error) {
8
- super(error.message);
9
- this.name = "AcpClientError";
10
- this.code = error.code;
11
- this.data = error.data;
12
- this.retryable = error.retryable;
13
- }
14
- };
15
- function transportClosedError() {
16
- return {
17
- code: ACP_ERROR_CODES.transportClosed,
18
- message: "transport is closed",
19
- retryable: true
20
- };
21
- }
22
- function asErrorObject(value) {
23
- if (typeof value !== "object" || value === null) return void 0;
24
- const candidate = value;
25
- if (typeof candidate.code !== "string" || !isAcpErrorCode(candidate.code)) return;
26
- return {
27
- code: candidate.code,
28
- message: typeof candidate.message === "string" ? candidate.message : "",
29
- ...candidate.data === void 0 ? {} : { data: candidate.data },
30
- retryable: candidate.retryable === true
31
- };
32
- }
33
- function toClientError(value) {
34
- if (value instanceof AcpClientError) return value;
35
- const errorObject = asErrorObject(value);
36
- if (errorObject) return new AcpClientError(errorObject);
37
- const message = value instanceof Error ? value.message : typeof value === "string" ? value : "unknown error";
38
- return new AcpClientError({
39
- code: ACP_ERROR_CODES.agentError,
40
- message,
41
- retryable: false
42
- });
43
- }
44
- //#endregion
1
+ import { ACPJS_HOST_RPC_METHODS, ACP_ERROR_CODES, createInitialSessionState, isAcpErrorCode, reduce } from "@acpjs/protocol";
45
2
  //#region src/internal.ts
46
3
  function notifyChange(listeners) {
47
4
  for (const listener of listeners) try {
@@ -50,23 +7,16 @@ function notifyChange(listeners) {
50
7
  }
51
8
  //#endregion
52
9
  //#region src/agent-handle.ts
53
- function sameAuthMethods(current, next) {
54
- if (current === void 0) return next.length === 0;
55
- if (current.length !== next.length) return false;
56
- return current.every((method, index) => method.id === next[index]?.id);
57
- }
58
- function sameRuntimeState(current, payload) {
59
- return current.status === payload.status && current.restartCount === payload.restartCount && current.reason === payload.reason && current.exit?.code === payload.exit?.code && current.exit?.signal === payload.exit?.signal;
10
+ function sameAgentSnapshot(current, next) {
11
+ return JSON.stringify(current) === JSON.stringify(next);
60
12
  }
61
- function createAgentHandle(call, openSession, onStatusChanged, snapshot) {
13
+ function createAgentHandle(call, openSession, applySessionSnapshot, onStatusChanged, snapshot) {
62
14
  const agentId = snapshot.agentId;
63
15
  let current = snapshot;
64
16
  const listeners = /* @__PURE__ */ new Set();
65
17
  return {
66
18
  agent: Object.freeze({
67
19
  agentId,
68
- ...snapshot.capabilities === void 0 ? {} : { capabilities: snapshot.capabilities },
69
- ...snapshot.authMethods === void 0 ? {} : { authMethods: snapshot.authMethods },
70
20
  getSnapshot: () => current,
71
21
  subscribe(listener) {
72
22
  listeners.add(listener);
@@ -74,81 +24,122 @@ function createAgentHandle(call, openSession, onStatusChanged, snapshot) {
74
24
  },
75
25
  sessions: Object.freeze({
76
26
  async create(params) {
77
- const result = await call(ACP_RPC_METHODS.createSession, {
27
+ return applySessionSnapshot(await call(ACPJS_HOST_RPC_METHODS.createSession, {
78
28
  agentId,
79
- cwd: params.cwd,
80
- ...params.mcpServers === void 0 ? {} : { mcpServers: params.mcpServers }
81
- });
82
- if (result.status === "auth-required") throw new AcpClientError({
83
- code: "acpjs/auth-required",
84
- message: "agent requires authentication",
85
- data: { authMethods: result.authMethods },
86
- retryable: true
87
- });
88
- return openSession(result.sessionId);
29
+ ...params
30
+ }));
89
31
  },
90
32
  async load(sessionId, params) {
91
- await call(ACP_RPC_METHODS.loadSession, {
33
+ await call(ACPJS_HOST_RPC_METHODS.loadSession, {
92
34
  agentId,
93
35
  sessionId,
94
- cwd: params.cwd,
95
- ...params.mcpServers === void 0 ? {} : { mcpServers: params.mcpServers }
36
+ ...params
96
37
  });
97
38
  return openSession(sessionId);
98
39
  },
99
40
  async list(params = {}) {
100
- return await call(ACP_RPC_METHODS.listSessions, {
41
+ return await call(ACPJS_HOST_RPC_METHODS.listSessions, {
101
42
  agentId,
102
43
  ...params.cursor === void 0 ? {} : { cursor: params.cursor },
103
44
  ...params.cwd === void 0 ? {} : { cwd: params.cwd }
104
45
  });
105
46
  },
106
- async resume(sessionId) {
107
- await call(ACP_RPC_METHODS.resumeSession, { sessionId });
47
+ async resume(sessionId, params) {
48
+ await call(ACPJS_HOST_RPC_METHODS.resumeSession, {
49
+ agentId,
50
+ sessionId,
51
+ ...params
52
+ });
108
53
  return openSession(sessionId);
109
54
  },
110
55
  async delete(sessionId) {
111
- await call(ACP_RPC_METHODS.deleteSession, { sessionId });
56
+ await call(ACPJS_HOST_RPC_METHODS.deleteSession, {
57
+ agentId,
58
+ sessionId
59
+ });
112
60
  }
113
- }),
114
- async authenticate(methodId) {
115
- await call(ACP_RPC_METHODS.authenticate, {
116
- agentId,
117
- methodId
118
- });
119
- },
120
- async logout() {
121
- await call(ACP_RPC_METHODS.logout, { agentId });
122
- }
61
+ })
123
62
  }),
124
- applyStatus(payload) {
125
- if (sameRuntimeState(current, payload)) return;
126
- current = {
127
- agentId,
128
- status: payload.status,
129
- restartCount: payload.restartCount,
130
- ...payload.reason === void 0 ? {} : { reason: payload.reason },
131
- ...payload.exit === void 0 ? {} : { exit: payload.exit },
132
- ...current.capabilities === void 0 ? {} : { capabilities: current.capabilities },
133
- ...current.authMethods === void 0 ? {} : { authMethods: current.authMethods },
134
- ...current.authRequired === void 0 ? {} : { authRequired: current.authRequired }
135
- };
63
+ applySnapshot(snapshot) {
64
+ if (sameAgentSnapshot(current, snapshot)) return;
65
+ current = snapshot;
136
66
  notifyChange(listeners);
137
67
  onStatusChanged();
68
+ }
69
+ };
70
+ }
71
+ function createDiagnosticsLog() {
72
+ const entries = [];
73
+ const listeners = /* @__PURE__ */ new Set();
74
+ let snapshot = Object.freeze([]);
75
+ function publish() {
76
+ snapshot = Object.freeze([...entries]);
77
+ for (const listener of listeners) try {
78
+ listener();
79
+ } catch {}
80
+ }
81
+ return {
82
+ getSnapshot: () => snapshot,
83
+ subscribe(listener) {
84
+ listeners.add(listener);
85
+ return () => listeners.delete(listener);
138
86
  },
139
- applyAuthRequired(payload) {
140
- if (current.authRequired === true && sameAuthMethods(current.authMethods, payload.authMethods)) return;
141
- current = {
142
- ...current,
143
- authRequired: true,
144
- authMethods: payload.authMethods
145
- };
146
- notifyChange(listeners);
147
- onStatusChanged();
87
+ push(event) {
88
+ entries.push(event);
89
+ if (entries.length > 200) entries.splice(0, entries.length - 200);
90
+ publish();
91
+ },
92
+ clear() {
93
+ entries.length = 0;
94
+ publish();
95
+ listeners.clear();
148
96
  }
149
97
  };
150
98
  }
151
99
  //#endregion
100
+ //#region src/errors.ts
101
+ var AcpClientError = class extends Error {
102
+ code;
103
+ data;
104
+ retryable;
105
+ constructor(error) {
106
+ super(error.message);
107
+ this.name = "AcpClientError";
108
+ this.code = error.code;
109
+ this.data = error.data;
110
+ this.retryable = error.retryable;
111
+ }
112
+ };
113
+ function transportClosedError() {
114
+ return {
115
+ code: ACP_ERROR_CODES.transportClosed,
116
+ message: "transport is closed",
117
+ retryable: true
118
+ };
119
+ }
120
+ function asErrorObject(value) {
121
+ if (typeof value !== "object" || value === null) return void 0;
122
+ const candidate = value;
123
+ if (typeof candidate.code !== "string" || !isAcpErrorCode(candidate.code)) return;
124
+ return {
125
+ code: candidate.code,
126
+ message: typeof candidate.message === "string" ? candidate.message : "",
127
+ ...candidate.data === void 0 ? {} : { data: candidate.data },
128
+ retryable: candidate.retryable === true
129
+ };
130
+ }
131
+ function toClientError(value) {
132
+ if (value instanceof AcpClientError) return value;
133
+ const errorObject = asErrorObject(value);
134
+ if (errorObject) return new AcpClientError(errorObject);
135
+ const message = value instanceof Error ? value.message : typeof value === "string" ? value : "unknown error";
136
+ return new AcpClientError({
137
+ code: ACP_ERROR_CODES.agentError,
138
+ message,
139
+ retryable: false
140
+ });
141
+ }
142
+ //#endregion
152
143
  //#region src/permission-registry.ts
153
144
  function createPermissionRegistry() {
154
145
  const pending = /* @__PURE__ */ new Map();
@@ -167,6 +158,7 @@ function createPermissionRegistry() {
167
158
  return () => listeners.delete(listener);
168
159
  },
169
160
  add(request) {
161
+ if (pending.has(request.requestId)) return;
170
162
  pending.set(request.requestId, request);
171
163
  publish();
172
164
  },
@@ -186,6 +178,71 @@ function createPermissionRegistry() {
186
178
  };
187
179
  }
188
180
  //#endregion
181
+ //#region src/client-permissions.ts
182
+ function createClientPermissionController(options) {
183
+ const registry = options.registry ?? createPermissionRegistry();
184
+ async function respond(requestId, outcome) {
185
+ options.ensureOpen();
186
+ try {
187
+ await options.connected;
188
+ await options.respondInbound({
189
+ id: requestId,
190
+ result: outcome
191
+ });
192
+ } catch (error) {
193
+ const clientError = toClientError(error);
194
+ if (clientError.code === ACP_ERROR_CODES.alreadyAnswered) registry.prune(requestId);
195
+ throw clientError;
196
+ }
197
+ registry.prune(requestId);
198
+ }
199
+ function add(payload) {
200
+ const permission = Object.freeze({
201
+ requestId: payload.requestId,
202
+ sessionId: payload.sessionId,
203
+ toolCall: payload.toolCall,
204
+ options: payload.options,
205
+ respond: (outcome) => respond(payload.requestId, outcome)
206
+ });
207
+ registry.add(permission);
208
+ }
209
+ return {
210
+ registry,
211
+ applyProjection(payload) {
212
+ if (payload.status === "pending") add(payload);
213
+ else registry.prune(payload.requestId);
214
+ },
215
+ respond
216
+ };
217
+ }
218
+ //#endregion
219
+ //#region src/client-rpc.ts
220
+ function createRpcCaller(options) {
221
+ let rpcCounter = 0;
222
+ return async function call(method, params) {
223
+ options.ensureOpen();
224
+ try {
225
+ await options.connected();
226
+ } catch (error) {
227
+ throw toClientError(error);
228
+ }
229
+ options.ensureOpen();
230
+ rpcCounter += 1;
231
+ let response;
232
+ try {
233
+ response = await options.request({
234
+ id: `rpc-${rpcCounter}`,
235
+ method,
236
+ params
237
+ });
238
+ } catch (error) {
239
+ throw toClientError(error);
240
+ }
241
+ if (!response.ok) throw new AcpClientError(response.error);
242
+ return response.result;
243
+ };
244
+ }
245
+ //#endregion
189
246
  //#region src/session-handle.ts
190
247
  function createSessionHandle(call, store) {
191
248
  const sessionId = store.sessionId;
@@ -194,25 +251,25 @@ function createSessionHandle(call, store) {
194
251
  getSnapshot: () => store.getSnapshot(),
195
252
  subscribe: (listener) => store.subscribe(listener),
196
253
  async prompt(blocks) {
197
- return await call(ACP_RPC_METHODS.prompt, {
254
+ return await call(ACPJS_HOST_RPC_METHODS.prompt, {
198
255
  sessionId,
199
256
  prompt: blocks
200
257
  });
201
258
  },
202
259
  async cancel() {
203
- await call(ACP_RPC_METHODS.cancel, { sessionId });
260
+ await call(ACPJS_HOST_RPC_METHODS.cancel, { sessionId });
204
261
  },
205
262
  async close() {
206
- await call(ACP_RPC_METHODS.closeSession, { sessionId });
263
+ await call(ACPJS_HOST_RPC_METHODS.closeSession, { sessionId });
207
264
  },
208
265
  async setMode(modeId) {
209
- await call(ACP_RPC_METHODS.setMode, {
266
+ await call(ACPJS_HOST_RPC_METHODS.setMode, {
210
267
  sessionId,
211
268
  modeId
212
269
  });
213
270
  },
214
271
  async setConfigOption(configId, value) {
215
- return await call(ACP_RPC_METHODS.setConfigOption, {
272
+ return await call(ACPJS_HOST_RPC_METHODS.setConfigOption, {
216
273
  sessionId,
217
274
  configId,
218
275
  value
@@ -226,6 +283,13 @@ function createSessionStore(sessionId) {
226
283
  let state = createInitialSessionState(sessionId);
227
284
  let lastSeq = 0;
228
285
  const listeners = /* @__PURE__ */ new Set();
286
+ function publish(next) {
287
+ if (next === state) return;
288
+ state = next;
289
+ for (const listener of listeners) try {
290
+ listener(state);
291
+ } catch {}
292
+ }
229
293
  return {
230
294
  sessionId,
231
295
  getSnapshot: () => state,
@@ -235,14 +299,32 @@ function createSessionStore(sessionId) {
235
299
  },
236
300
  apply(event) {
237
301
  if (!("sessionId" in event) || event.sessionId !== sessionId) return;
302
+ if (event.type === "session-reset") {
303
+ lastSeq = event.seq;
304
+ publish(reduce(state, event));
305
+ return;
306
+ }
238
307
  if (event.seq <= lastSeq) return;
239
308
  lastSeq = event.seq;
240
- const next = reduce(state, event);
241
- if (next === state) return;
242
- state = next;
243
- for (const listener of listeners) try {
244
- listener(state);
245
- } catch {}
309
+ publish(reduce(state, event));
310
+ },
311
+ applyProjection(snapshot) {
312
+ if (snapshot.sessionId !== sessionId) return false;
313
+ const title = snapshot.title === void 0 ? state.info.title : snapshot.title;
314
+ const updatedAt = snapshot.updatedAt === void 0 ? state.info.updatedAt : snapshot.updatedAt;
315
+ if (state.connection.status === snapshot.status && state.info.title === title && state.info.updatedAt === updatedAt) return false;
316
+ publish({
317
+ ...state,
318
+ connection: {
319
+ ...state.connection,
320
+ status: snapshot.status
321
+ },
322
+ info: {
323
+ title,
324
+ updatedAt
325
+ }
326
+ });
327
+ return true;
246
328
  },
247
329
  lastSeq: () => lastSeq
248
330
  };
@@ -263,31 +345,22 @@ function createAcpClient(options) {
263
345
  notifyChange(agentListeners);
264
346
  }
265
347
  const sessions = /* @__PURE__ */ new Map();
348
+ const sessionUnsubscribers = /* @__PURE__ */ new Map();
266
349
  const sessionListeners = /* @__PURE__ */ new Set();
267
350
  let sessionsSnapshot = Object.freeze([]);
268
351
  function publishSessions() {
269
352
  sessionsSnapshot = Object.freeze([...sessions.values()]);
270
353
  notifyChange(sessionListeners);
271
354
  }
272
- const permissions = createPermissionRegistry();
273
355
  let statusSnapshot = Object.freeze({ status: "connecting" });
274
356
  const statusListeners = /* @__PURE__ */ new Set();
357
+ const permissions = createPermissionRegistry();
358
+ const diagnostics = createDiagnosticsLog();
275
359
  function ensureOpen() {
276
360
  if (closedError) throw new AcpClientError(closedError);
277
361
  }
278
- const handlers = {
279
- onInboundRequest(request) {
280
- if (request.kind !== "permission") return;
281
- const payload = request.payload;
282
- const permission = Object.freeze({
283
- requestId: payload.requestId,
284
- sessionId: payload.sessionId,
285
- toolCall: payload.toolCall,
286
- options: payload.options,
287
- respond: (outcome) => respondPermission(request.id, payload.requestId, outcome)
288
- });
289
- permissions.add(permission);
290
- },
362
+ const connected = transport.connect({
363
+ onInboundRequest() {},
291
364
  onLifecycle(event) {
292
365
  if (event.status === "closed") {
293
366
  closedError = event.error ?? transportClosedError();
@@ -299,56 +372,32 @@ function createAcpClient(options) {
299
372
  ...event.error === void 0 ? {} : { error: event.error }
300
373
  });
301
374
  notifyChange(statusListeners);
375
+ },
376
+ onSubscriptionError(params) {
377
+ if (params.sessionId !== void 0) closeSessionHandle(params.sessionId);
302
378
  }
303
- };
379
+ });
380
+ const permissionController = createClientPermissionController({
381
+ ensureOpen,
382
+ connected,
383
+ respondInbound: (response) => transport.respondInbound(response),
384
+ registry: permissions
385
+ });
304
386
  function onHostEvent(event) {
305
- if (event.type === "agent-status-change") agentUpdaters.get(event.agentId)?.applyStatus(event.payload);
306
- else if (event.type === "auth-required") agentUpdaters.get(event.agentId)?.applyAuthRequired(event.payload);
307
- else if (event.type === "session-created" || event.type === "session-closed") notifyChange(sessionListeners);
387
+ if (event.type === "agent-updated") registerAgent(event.payload);
388
+ else if (event.type === "session-updated") applySessionProjection(event.payload);
389
+ else if (event.type === "permission-updated") permissionController.applyProjection(event.payload);
390
+ else if (event.type === "diagnostic") diagnostics.push(event);
308
391
  }
309
- const connected = transport.connect(handlers);
310
392
  connected.then(() => {
311
393
  if (closedError) return;
312
394
  storeUnsubscribers.add(transport.subscribe({ fromSeq: 0 }, onHostEvent));
313
395
  }).catch(() => {});
314
- async function respondPermission(inboundId, requestId, outcome) {
315
- ensureOpen();
316
- try {
317
- await connected;
318
- await transport.respondInbound({
319
- id: inboundId,
320
- result: outcome
321
- });
322
- } catch (error) {
323
- const clientError = toClientError(error);
324
- if (clientError.code === ACP_ERROR_CODES.alreadyAnswered) permissions.prune(requestId);
325
- throw clientError;
326
- }
327
- permissions.prune(requestId);
328
- }
329
- let rpcCounter = 0;
330
- async function call(method, params) {
331
- ensureOpen();
332
- try {
333
- await connected;
334
- } catch (error) {
335
- throw toClientError(error);
336
- }
337
- ensureOpen();
338
- rpcCounter += 1;
339
- let response;
340
- try {
341
- response = await transport.request({
342
- id: `rpc-${rpcCounter}`,
343
- method,
344
- params
345
- });
346
- } catch (error) {
347
- throw toClientError(error);
348
- }
349
- if (!response.ok) throw new AcpClientError(response.error);
350
- return response.result;
351
- }
396
+ const call = createRpcCaller({
397
+ ensureOpen,
398
+ connected: () => connected,
399
+ request: (request) => transport.request(request)
400
+ });
352
401
  function attachStore(sessionId) {
353
402
  const existing = stores.get(sessionId);
354
403
  if (existing) return existing;
@@ -362,6 +411,7 @@ function createAcpClient(options) {
362
411
  store.apply(event);
363
412
  });
364
413
  storeUnsubscribers.add(unsubscribe);
414
+ sessionUnsubscribers.set(sessionId, unsubscribe);
365
415
  return store;
366
416
  }
367
417
  function openSession(sessionId) {
@@ -372,18 +422,48 @@ function createAcpClient(options) {
372
422
  publishSessions();
373
423
  return session;
374
424
  }
425
+ function closeSessionHandle(sessionId) {
426
+ if (!sessions.delete(sessionId)) return;
427
+ const unsubscribe = sessionUnsubscribers.get(sessionId);
428
+ unsubscribe?.();
429
+ if (unsubscribe) storeUnsubscribers.delete(unsubscribe);
430
+ sessionUnsubscribers.delete(sessionId);
431
+ stores.delete(sessionId);
432
+ publishSessions();
433
+ }
434
+ function applySessionProjection(snapshot) {
435
+ if (snapshot.status === "deleted") {
436
+ closeSessionHandle(snapshot.sessionId);
437
+ return;
438
+ }
439
+ const existing = sessions.has(snapshot.sessionId);
440
+ const changed = attachStore(snapshot.sessionId).applyProjection(snapshot);
441
+ const session = openSession(snapshot.sessionId);
442
+ if (existing && changed) publishSessions();
443
+ return session;
444
+ }
375
445
  async function listAgents() {
376
- return await call(ACP_RPC_METHODS.listAgents, {});
446
+ return await call(ACPJS_HOST_RPC_METHODS.listAgents, {});
377
447
  }
378
448
  async function listAllSessions() {
379
- return await call(ACP_RPC_METHODS.getAllSessions, {});
449
+ return await call(ACPJS_HOST_RPC_METHODS.getAllSessions, {});
380
450
  }
381
451
  function registerAgent(snapshot) {
382
- const { agent, applyStatus, applyAuthRequired } = createAgentHandle(call, openSession, publishAgents, snapshot);
383
- agentUpdaters.set(agent.agentId, {
384
- applyStatus,
385
- applyAuthRequired
386
- });
452
+ const existing = agents.get(snapshot.agentId);
453
+ if (existing) {
454
+ agentUpdaters.get(snapshot.agentId)?.applySnapshot(snapshot);
455
+ return existing;
456
+ }
457
+ const { agent, applySnapshot } = createAgentHandle(call, openSession, (snapshot) => {
458
+ const session = applySessionProjection(snapshot);
459
+ if (session === void 0) throw new AcpClientError({
460
+ code: ACP_ERROR_CODES.sessionClosed,
461
+ message: `session ${snapshot.sessionId} is deleted`,
462
+ retryable: false
463
+ });
464
+ return session;
465
+ }, publishAgents, snapshot);
466
+ agentUpdaters.set(agent.agentId, { applySnapshot });
387
467
  agents.set(agent.agentId, agent);
388
468
  publishAgents();
389
469
  return agent;
@@ -391,7 +471,7 @@ function createAcpClient(options) {
391
471
  return Object.freeze({
392
472
  agents: Object.freeze({
393
473
  async spawn(definition) {
394
- return registerAgent(await call(ACP_RPC_METHODS.spawnAgent, { definition }));
474
+ return registerAgent(await call(ACPJS_HOST_RPC_METHODS.spawnAgent, { definition }));
395
475
  },
396
476
  get: (agentId) => agents.get(agentId),
397
477
  getSnapshot: () => agentsSnapshot,
@@ -419,21 +499,34 @@ function createAcpClient(options) {
419
499
  },
420
500
  list: listAllSessions,
421
501
  async attach(sessionId) {
422
- if (!(await listAllSessions()).some((candidate) => candidate.sessionId === sessionId)) throw new AcpClientError({
502
+ const snapshot = (await listAllSessions()).find((candidate) => candidate.sessionId === sessionId);
503
+ if (!snapshot) throw new AcpClientError({
423
504
  code: ACP_ERROR_CODES.sessionClosed,
424
505
  message: `session ${sessionId} is not known to the host`,
425
506
  retryable: false
426
507
  });
427
- return openSession(sessionId);
508
+ const session = applySessionProjection(snapshot);
509
+ if (session === void 0) throw new AcpClientError({
510
+ code: ACP_ERROR_CODES.sessionClosed,
511
+ message: `session ${sessionId} is deleted`,
512
+ retryable: false
513
+ });
514
+ return session;
428
515
  },
429
516
  async restore() {
430
- return await call(ACP_RPC_METHODS.restoreSessions, {});
517
+ const restored = await call(ACPJS_HOST_RPC_METHODS.restoreSessions, {});
518
+ for (const snapshot of restored) applySessionProjection(snapshot);
519
+ return restored;
431
520
  }
432
521
  }),
433
522
  permissions: Object.freeze({
434
523
  getSnapshot: permissions.getSnapshot,
435
524
  subscribe: permissions.subscribe
436
525
  }),
526
+ diagnostics: Object.freeze({
527
+ getSnapshot: diagnostics.getSnapshot,
528
+ subscribe: diagnostics.subscribe
529
+ }),
437
530
  status: Object.freeze({
438
531
  getSnapshot: () => statusSnapshot,
439
532
  subscribe(listener) {
@@ -447,6 +540,7 @@ function createAcpClient(options) {
447
540
  for (const unsubscribe of storeUnsubscribers) unsubscribe();
448
541
  storeUnsubscribers.clear();
449
542
  permissions.clear();
543
+ diagnostics.clear();
450
544
  await transport.close();
451
545
  }
452
546
  });
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/errors.ts","../src/internal.ts","../src/agent-handle.ts","../src/permission-registry.ts","../src/session-handle.ts","../src/store.ts","../src/client.ts","../src/in-process.ts"],"sourcesContent":["import {\n ACP_ERROR_CODES,\n isAcpErrorCode,\n type AcpErrorCode,\n type ErrorObject,\n} from '@acpjs/protocol'\n\nexport class AcpClientError extends Error {\n code: AcpErrorCode\n data: unknown\n retryable: boolean\n\n constructor(error: ErrorObject) {\n super(error.message)\n this.name = 'AcpClientError'\n this.code = error.code\n this.data = error.data\n this.retryable = error.retryable\n }\n}\n\nexport function transportClosedError(): ErrorObject {\n return {\n code: ACP_ERROR_CODES.transportClosed,\n message: 'transport is closed',\n retryable: true,\n }\n}\n\nfunction asErrorObject(value: unknown): ErrorObject | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const candidate = value as {\n code?: unknown\n message?: unknown\n data?: unknown\n retryable?: unknown\n }\n if (typeof candidate.code !== 'string' || !isAcpErrorCode(candidate.code)) {\n return undefined\n }\n return {\n code: candidate.code,\n message: typeof candidate.message === 'string' ? candidate.message : '',\n ...(candidate.data === undefined ? {} : { data: candidate.data }),\n retryable: candidate.retryable === true,\n }\n}\n\nexport function toClientError(value: unknown): AcpClientError {\n if (value instanceof AcpClientError) return value\n const errorObject = asErrorObject(value)\n if (errorObject) return new AcpClientError(errorObject)\n const message =\n value instanceof Error\n ? value.message\n : typeof value === 'string'\n ? value\n : 'unknown error'\n return new AcpClientError({\n code: ACP_ERROR_CODES.agentError,\n message,\n retryable: false,\n })\n}\n","import type { ChangeListener } from './types.ts'\n\nexport type RpcCall = (\n method: string,\n params: Record<string, unknown>,\n) => Promise<unknown>\n\nexport function notifyChange(listeners: ReadonlySet<ChangeListener>): void {\n for (const listener of listeners) {\n try {\n listener()\n } catch {}\n }\n}\n","import {\n ACP_RPC_METHODS,\n type AgentSnapshotWire,\n type AgentStatusChangePayload,\n type AuthRequiredPayload,\n type CreateSessionResult,\n type ListSessionsResponse,\n} from '@acpjs/protocol'\n\nimport { AcpClientError } from './errors.ts'\nimport { notifyChange, type RpcCall } from './internal.ts'\n\nimport type {\n AcpAgent,\n AcpSession,\n ChangeListener,\n SessionCreateParams,\n SessionListParams,\n} from './types.ts'\n\nexport interface AgentHandle {\n agent: AcpAgent\n applyStatus: (payload: AgentStatusChangePayload) => void\n applyAuthRequired: (payload: AuthRequiredPayload) => void\n}\n\nfunction sameAuthMethods(\n current: AgentSnapshotWire['authMethods'],\n next: AuthRequiredPayload['authMethods'],\n): boolean {\n if (current === undefined) return next.length === 0\n if (current.length !== next.length) return false\n return current.every((method, index) => method.id === next[index]?.id)\n}\n\nfunction sameRuntimeState(\n current: AgentSnapshotWire,\n payload: AgentStatusChangePayload,\n): boolean {\n return (\n current.status === payload.status &&\n current.restartCount === payload.restartCount &&\n current.reason === payload.reason &&\n current.exit?.code === payload.exit?.code &&\n current.exit?.signal === payload.exit?.signal\n )\n}\n\nexport function createAgentHandle(\n call: RpcCall,\n openSession: (sessionId: string) => AcpSession,\n onStatusChanged: () => void,\n snapshot: AgentSnapshotWire,\n): AgentHandle {\n const agentId = snapshot.agentId\n let current = snapshot\n const listeners = new Set<ChangeListener>()\n const agent: AcpAgent = Object.freeze({\n agentId,\n ...(snapshot.capabilities === undefined\n ? {}\n : { capabilities: snapshot.capabilities }),\n ...(snapshot.authMethods === undefined\n ? {}\n : { authMethods: snapshot.authMethods }),\n getSnapshot: () => current,\n subscribe(listener: ChangeListener): () => void {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n sessions: Object.freeze({\n async create(params: SessionCreateParams): Promise<AcpSession> {\n const result = (await call(ACP_RPC_METHODS.createSession, {\n agentId,\n cwd: params.cwd,\n ...(params.mcpServers === undefined\n ? {}\n : { mcpServers: params.mcpServers }),\n })) as CreateSessionResult\n if (result.status === 'auth-required') {\n throw new AcpClientError({\n code: 'acpjs/auth-required',\n message: 'agent requires authentication',\n data: { authMethods: result.authMethods },\n retryable: true,\n })\n }\n return openSession(result.sessionId)\n },\n async load(\n sessionId: string,\n params: SessionCreateParams,\n ): Promise<AcpSession> {\n await call(ACP_RPC_METHODS.loadSession, {\n agentId,\n sessionId,\n cwd: params.cwd,\n ...(params.mcpServers === undefined\n ? {}\n : { mcpServers: params.mcpServers }),\n })\n return openSession(sessionId)\n },\n async list(\n params: SessionListParams = {},\n ): Promise<ListSessionsResponse> {\n return (await call(ACP_RPC_METHODS.listSessions, {\n agentId,\n ...(params.cursor === undefined ? {} : { cursor: params.cursor }),\n ...(params.cwd === undefined ? {} : { cwd: params.cwd }),\n })) as ListSessionsResponse\n },\n async resume(sessionId: string): Promise<AcpSession> {\n await call(ACP_RPC_METHODS.resumeSession, { sessionId })\n return openSession(sessionId)\n },\n async delete(sessionId: string): Promise<void> {\n await call(ACP_RPC_METHODS.deleteSession, { sessionId })\n },\n }),\n async authenticate(methodId: string): Promise<void> {\n await call(ACP_RPC_METHODS.authenticate, { agentId, methodId })\n },\n async logout(): Promise<void> {\n await call(ACP_RPC_METHODS.logout, { agentId })\n },\n })\n return {\n agent,\n applyStatus(payload: AgentStatusChangePayload): void {\n if (sameRuntimeState(current, payload)) return\n current = {\n agentId,\n status: payload.status,\n restartCount: payload.restartCount,\n ...(payload.reason === undefined ? {} : { reason: payload.reason }),\n ...(payload.exit === undefined ? {} : { exit: payload.exit }),\n ...(current.capabilities === undefined\n ? {}\n : { capabilities: current.capabilities }),\n ...(current.authMethods === undefined\n ? {}\n : { authMethods: current.authMethods }),\n ...(current.authRequired === undefined\n ? {}\n : { authRequired: current.authRequired }),\n }\n notifyChange(listeners)\n onStatusChanged()\n },\n applyAuthRequired(payload: AuthRequiredPayload): void {\n if (\n current.authRequired === true &&\n sameAuthMethods(current.authMethods, payload.authMethods)\n ) {\n return\n }\n current = {\n ...current,\n authRequired: true,\n authMethods: payload.authMethods,\n }\n notifyChange(listeners)\n onStatusChanged()\n },\n }\n}\n","import type { PermissionListener, PermissionRequest } from './types.ts'\n\nexport interface PermissionRegistry {\n getSnapshot: () => readonly PermissionRequest[]\n subscribe: (listener: PermissionListener) => () => void\n add: (request: PermissionRequest) => void\n prune: (requestId: string) => void\n reset: () => void\n clear: () => void\n}\n\nexport function createPermissionRegistry(): PermissionRegistry {\n const pending = new Map<string, PermissionRequest>()\n const listeners = new Set<PermissionListener>()\n let snapshot: readonly PermissionRequest[] = Object.freeze([])\n\n function publish(): void {\n snapshot = Object.freeze([...pending.values()])\n for (const listener of listeners) {\n try {\n listener(snapshot)\n } catch {}\n }\n }\n\n return {\n getSnapshot: () => snapshot,\n subscribe(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n add(request) {\n pending.set(request.requestId, request)\n publish()\n },\n prune(requestId) {\n if (pending.delete(requestId)) publish()\n },\n reset() {\n if (pending.size === 0) return\n pending.clear()\n publish()\n },\n clear() {\n pending.clear()\n publish()\n listeners.clear()\n },\n }\n}\n","import {\n ACP_RPC_METHODS,\n type ContentBlock,\n type PromptFinishedPayload,\n type SessionConfigOption,\n} from '@acpjs/protocol'\n\nimport type { RpcCall } from './internal.ts'\nimport type { SessionStore, StateListener } from './store.ts'\nimport type { AcpSession, SessionConfigValue } from './types.ts'\n\nexport function createSessionHandle(\n call: RpcCall,\n store: SessionStore,\n): AcpSession {\n const sessionId = store.sessionId\n return Object.freeze({\n sessionId,\n getSnapshot: () => store.getSnapshot(),\n subscribe: (listener: StateListener) => store.subscribe(listener),\n async prompt(blocks: ContentBlock[]): Promise<PromptFinishedPayload> {\n return (await call(ACP_RPC_METHODS.prompt, {\n sessionId,\n prompt: blocks,\n })) as PromptFinishedPayload\n },\n async cancel(): Promise<void> {\n await call(ACP_RPC_METHODS.cancel, { sessionId })\n },\n async close(): Promise<void> {\n await call(ACP_RPC_METHODS.closeSession, { sessionId })\n },\n async setMode(modeId: string): Promise<void> {\n await call(ACP_RPC_METHODS.setMode, { sessionId, modeId })\n },\n async setConfigOption(\n configId: string,\n value: SessionConfigValue,\n ): Promise<SessionConfigOption[]> {\n return (await call(ACP_RPC_METHODS.setConfigOption, {\n sessionId,\n configId,\n value,\n })) as SessionConfigOption[]\n },\n })\n}\n","import {\n createInitialSessionState,\n reduce,\n type AcpEvent,\n type SessionState,\n} from '@acpjs/protocol'\n\nexport type StateListener = (state: SessionState) => void\n\nexport interface SessionStore {\n readonly sessionId: string\n getSnapshot: () => SessionState\n subscribe: (listener: StateListener) => () => void\n apply: (event: AcpEvent) => void\n lastSeq: () => number\n}\n\nexport function createSessionStore(sessionId: string): SessionStore {\n let state = createInitialSessionState(sessionId)\n let lastSeq = 0\n const listeners = new Set<StateListener>()\n return {\n sessionId,\n getSnapshot: () => state,\n subscribe(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n apply(event) {\n if (!('sessionId' in event) || event.sessionId !== sessionId) return\n if (event.seq <= lastSeq) return\n lastSeq = event.seq\n const next = reduce(state, event)\n if (next === state) return\n state = next\n for (const listener of listeners) {\n try {\n listener(state)\n } catch {}\n }\n },\n lastSeq: () => lastSeq,\n }\n}\n","import {\n ACP_ERROR_CODES,\n ACP_RPC_METHODS,\n type AcpEvent,\n type AgentSnapshotWire,\n type AgentStatusChangePayload,\n type AuthRequiredPayload,\n type ErrorObject,\n type PermissionRequestCreatedPayload,\n type RequestPermissionOutcome,\n type SessionSnapshotWire,\n type TransportHandlers,\n} from '@acpjs/protocol'\n\nimport { createAgentHandle } from './agent-handle.ts'\nimport {\n AcpClientError,\n toClientError,\n transportClosedError,\n} from './errors.ts'\nimport { notifyChange } from './internal.ts'\nimport { createPermissionRegistry } from './permission-registry.ts'\nimport { createSessionHandle } from './session-handle.ts'\nimport { createSessionStore, type SessionStore } from './store.ts'\n\nimport type {\n AcpAgent,\n AcpClient,\n AcpSession,\n AgentDefinition,\n ChangeListener,\n ConnectionStatusSnapshot,\n CreateAcpClientOptions,\n PermissionRequest,\n} from './types.ts'\n\nexport function createAcpClient(options: CreateAcpClientOptions): AcpClient {\n const transport = options.transport\n let closedError: ErrorObject | undefined\n const stores = new Map<string, SessionStore>()\n const storeUnsubscribers = new Set<() => void>()\n const agents = new Map<string, AcpAgent>()\n const agentListeners = new Set<ChangeListener>()\n const agentUpdaters = new Map<\n string,\n {\n applyStatus: (payload: AgentStatusChangePayload) => void\n applyAuthRequired: (payload: AuthRequiredPayload) => void\n }\n >()\n let agentsSnapshot: readonly AcpAgent[] = Object.freeze([])\n\n function publishAgents(): void {\n agentsSnapshot = Object.freeze([...agents.values()])\n notifyChange(agentListeners)\n }\n\n const sessions = new Map<string, AcpSession>()\n const sessionListeners = new Set<ChangeListener>()\n let sessionsSnapshot: readonly AcpSession[] = Object.freeze([])\n\n function publishSessions(): void {\n sessionsSnapshot = Object.freeze([...sessions.values()])\n notifyChange(sessionListeners)\n }\n\n const permissions = createPermissionRegistry()\n\n let statusSnapshot: ConnectionStatusSnapshot = Object.freeze({\n status: 'connecting' as const,\n })\n const statusListeners = new Set<ChangeListener>()\n\n function ensureOpen(): void {\n if (closedError) throw new AcpClientError(closedError)\n }\n\n const handlers: TransportHandlers = {\n onInboundRequest(request) {\n if (request.kind !== 'permission') return\n const payload = request.payload as PermissionRequestCreatedPayload & {\n sessionId: string\n }\n const permission: PermissionRequest = Object.freeze({\n requestId: payload.requestId,\n sessionId: payload.sessionId,\n toolCall: payload.toolCall,\n options: payload.options,\n respond: (outcome: RequestPermissionOutcome) =>\n respondPermission(request.id, payload.requestId, outcome),\n })\n permissions.add(permission)\n },\n onLifecycle(event) {\n if (event.status === 'closed') {\n closedError = event.error ?? transportClosedError()\n permissions.reset()\n }\n if (\n statusSnapshot.status === event.status &&\n statusSnapshot.error === event.error\n ) {\n return\n }\n statusSnapshot = Object.freeze({\n status: event.status,\n ...(event.error === undefined ? {} : { error: event.error }),\n })\n notifyChange(statusListeners)\n },\n }\n\n function onHostEvent(event: AcpEvent): void {\n if (event.type === 'agent-status-change') {\n agentUpdaters.get(event.agentId)?.applyStatus(event.payload)\n } else if (event.type === 'auth-required') {\n agentUpdaters.get(event.agentId)?.applyAuthRequired(event.payload)\n } else if (\n event.type === 'session-created' ||\n event.type === 'session-closed'\n ) {\n notifyChange(sessionListeners)\n }\n }\n\n const connected = transport.connect(handlers)\n connected\n .then(() => {\n if (closedError) return\n storeUnsubscribers.add(transport.subscribe({ fromSeq: 0 }, onHostEvent))\n })\n .catch(() => {})\n\n async function respondPermission(\n inboundId: string,\n requestId: string,\n outcome: RequestPermissionOutcome,\n ): Promise<void> {\n ensureOpen()\n try {\n await connected\n await transport.respondInbound({ id: inboundId, result: outcome })\n } catch (error) {\n const clientError = toClientError(error)\n if (clientError.code === ACP_ERROR_CODES.alreadyAnswered) {\n permissions.prune(requestId)\n }\n throw clientError\n }\n permissions.prune(requestId)\n }\n\n let rpcCounter = 0\n async function call(\n method: string,\n params: Record<string, unknown>,\n ): Promise<unknown> {\n ensureOpen()\n try {\n await connected\n } catch (error) {\n throw toClientError(error)\n }\n ensureOpen()\n rpcCounter += 1\n let response\n try {\n response = await transport.request({\n id: `rpc-${rpcCounter}`,\n method,\n params,\n })\n } catch (error) {\n throw toClientError(error)\n }\n if (!response.ok) throw new AcpClientError(response.error)\n return response.result\n }\n\n function attachStore(sessionId: string): SessionStore {\n const existing = stores.get(sessionId)\n if (existing) return existing\n const store = createSessionStore(sessionId)\n stores.set(sessionId, store)\n const unsubscribe = transport.subscribe(\n { sessionId, fromSeq: store.lastSeq() },\n (event) => {\n if (event.type === 'permission-request-resolved') {\n permissions.prune(event.payload.requestId)\n }\n store.apply(event)\n },\n )\n storeUnsubscribers.add(unsubscribe)\n return store\n }\n\n function openSession(sessionId: string): AcpSession {\n const existing = sessions.get(sessionId)\n if (existing) return existing\n const session = createSessionHandle(call, attachStore(sessionId))\n sessions.set(sessionId, session)\n publishSessions()\n return session\n }\n\n async function listAgents(): Promise<readonly AgentSnapshotWire[]> {\n return (await call(ACP_RPC_METHODS.listAgents, {})) as AgentSnapshotWire[]\n }\n\n async function listAllSessions(): Promise<readonly SessionSnapshotWire[]> {\n return (await call(\n ACP_RPC_METHODS.getAllSessions,\n {},\n )) as SessionSnapshotWire[]\n }\n\n function registerAgent(snapshot: AgentSnapshotWire): AcpAgent {\n const { agent, applyStatus, applyAuthRequired } = createAgentHandle(\n call,\n openSession,\n publishAgents,\n snapshot,\n )\n agentUpdaters.set(agent.agentId, { applyStatus, applyAuthRequired })\n agents.set(agent.agentId, agent)\n publishAgents()\n return agent\n }\n\n return Object.freeze({\n agents: Object.freeze({\n async spawn(definition: AgentDefinition): Promise<AcpAgent> {\n const snapshot = (await call(ACP_RPC_METHODS.spawnAgent, {\n definition,\n })) as AgentSnapshotWire\n return registerAgent(snapshot)\n },\n get: (agentId: string) => agents.get(agentId),\n getSnapshot: () => agentsSnapshot,\n subscribe(listener: ChangeListener): () => void {\n agentListeners.add(listener)\n return () => agentListeners.delete(listener)\n },\n list: listAgents,\n async attach(agentId: string): Promise<AcpAgent> {\n const snapshots = await listAgents()\n const snapshot = snapshots.find(\n (candidate) => candidate.agentId === agentId,\n )\n if (!snapshot) {\n throw new AcpClientError({\n code: ACP_ERROR_CODES.agentExited,\n message: `agent ${agentId} is not known to the host`,\n retryable: false,\n })\n }\n return agents.get(agentId) ?? registerAgent(snapshot)\n },\n }),\n sessions: Object.freeze({\n get: (sessionId: string) => sessions.get(sessionId),\n getSnapshot: () => sessionsSnapshot,\n subscribe(listener: ChangeListener): () => void {\n sessionListeners.add(listener)\n return () => sessionListeners.delete(listener)\n },\n list: listAllSessions,\n async attach(sessionId: string): Promise<AcpSession> {\n const snapshots = await listAllSessions()\n const known = snapshots.some(\n (candidate) => candidate.sessionId === sessionId,\n )\n if (!known) {\n throw new AcpClientError({\n code: ACP_ERROR_CODES.sessionClosed,\n message: `session ${sessionId} is not known to the host`,\n retryable: false,\n })\n }\n return openSession(sessionId)\n },\n async restore(): Promise<readonly SessionSnapshotWire[]> {\n return (await call(\n ACP_RPC_METHODS.restoreSessions,\n {},\n )) as SessionSnapshotWire[]\n },\n }),\n permissions: Object.freeze({\n getSnapshot: permissions.getSnapshot,\n subscribe: permissions.subscribe,\n }),\n status: Object.freeze({\n getSnapshot: () => statusSnapshot,\n subscribe(listener: ChangeListener): () => void {\n statusListeners.add(listener)\n return () => statusListeners.delete(listener)\n },\n }),\n async dispose(): Promise<void> {\n if (closedError) return\n closedError = transportClosedError()\n for (const unsubscribe of storeUnsubscribers) unsubscribe()\n storeUnsubscribers.clear()\n permissions.clear()\n await transport.close()\n },\n })\n}\n","import {\n ACP_ERROR_CODES,\n type EnvelopeEndpoint,\n type Transport,\n type TransportConnectionStatus,\n type TransportHandlers,\n} from '@acpjs/protocol'\n\nimport { AcpClientError, transportClosedError } from './errors.ts'\n\nexport function createInProcessTransport(\n endpoint: EnvelopeEndpoint,\n): Transport {\n let status: TransportConnectionStatus = 'connecting'\n let handlers: TransportHandlers | undefined\n const unsubscribers = new Set<() => void>()\n let detachInbound: (() => void) | undefined\n\n return {\n async connect(next: TransportHandlers): Promise<void> {\n if (status === 'closed') {\n throw new AcpClientError(transportClosedError())\n }\n if (handlers) {\n throw new AcpClientError({\n code: ACP_ERROR_CODES.configInvalid,\n message: 'transport already connected',\n retryable: false,\n })\n }\n handlers = next\n next.onLifecycle({ status: 'connecting' })\n detachInbound = endpoint.onInboundRequest((request) => {\n next.onInboundRequest(request)\n })\n status = 'connected'\n next.onLifecycle({ status: 'connected' })\n },\n async request(request) {\n if (status !== 'connected') {\n return { id: request.id, ok: false, error: transportClosedError() }\n }\n return endpoint.request(request)\n },\n subscribe(params, onEvent) {\n if (status !== 'connected') {\n throw new AcpClientError(transportClosedError())\n }\n const unsubscribe = endpoint.subscribe(params, onEvent)\n unsubscribers.add(unsubscribe)\n return () => {\n unsubscribers.delete(unsubscribe)\n unsubscribe()\n }\n },\n async respondInbound(response) {\n if (status !== 'connected') {\n throw new AcpClientError(transportClosedError())\n }\n await endpoint.respondInbound(response)\n },\n async close() {\n if (status === 'closed') return\n status = 'closed'\n detachInbound?.()\n for (const unsubscribe of unsubscribers) unsubscribe()\n unsubscribers.clear()\n handlers?.onLifecycle({ status: 'closed' })\n },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/internal.ts","../src/agent-handle.ts","../src/client-diagnostics.ts","../src/errors.ts","../src/permission-registry.ts","../src/client-permissions.ts","../src/client-rpc.ts","../src/session-handle.ts","../src/store.ts","../src/client.ts","../src/in-process.ts"],"sourcesContent":["import type { ChangeListener } from './types.ts'\n\nexport type RpcCall = (\n method: string,\n params: Record<string, unknown>,\n) => Promise<unknown>\n\nexport function notifyChange(listeners: ReadonlySet<ChangeListener>): void {\n for (const listener of listeners) {\n try {\n listener()\n } catch {}\n }\n}\n","import {\n ACPJS_HOST_RPC_METHODS,\n type AgentSnapshotWire,\n type CreateSessionResult,\n type ListSessionsResponse,\n type SessionSnapshotWire,\n} from '@acpjs/protocol'\n\nimport { notifyChange, type RpcCall } from './internal.ts'\n\nimport type {\n AcpAgent,\n AcpSession,\n ChangeListener,\n CreateOrLoadSessionParams,\n ResumeSessionParams,\n SessionListParams,\n} from './types.ts'\n\nexport interface AgentHandle {\n agent: AcpAgent\n applySnapshot: (snapshot: AgentSnapshotWire) => void\n}\n\nfunction sameAgentSnapshot(\n current: AgentSnapshotWire,\n next: AgentSnapshotWire,\n): boolean {\n return JSON.stringify(current) === JSON.stringify(next)\n}\n\nexport function createAgentHandle(\n call: RpcCall,\n openSession: (sessionId: string) => AcpSession,\n applySessionSnapshot: (snapshot: SessionSnapshotWire) => AcpSession,\n onStatusChanged: () => void,\n snapshot: AgentSnapshotWire,\n): AgentHandle {\n const agentId = snapshot.agentId\n let current = snapshot\n const listeners = new Set<ChangeListener>()\n const agent: AcpAgent = Object.freeze({\n agentId,\n getSnapshot: () => current,\n subscribe(listener: ChangeListener): () => void {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n sessions: Object.freeze({\n async create(params: CreateOrLoadSessionParams): Promise<AcpSession> {\n const result = (await call(ACPJS_HOST_RPC_METHODS.createSession, {\n agentId,\n ...params,\n })) as CreateSessionResult\n return applySessionSnapshot(result)\n },\n async load(\n sessionId: string,\n params: CreateOrLoadSessionParams,\n ): Promise<AcpSession> {\n await call(ACPJS_HOST_RPC_METHODS.loadSession, {\n agentId,\n sessionId,\n ...params,\n })\n return openSession(sessionId)\n },\n async list(\n params: SessionListParams = {},\n ): Promise<ListSessionsResponse> {\n return (await call(ACPJS_HOST_RPC_METHODS.listSessions, {\n agentId,\n ...(params.cursor === undefined ? {} : { cursor: params.cursor }),\n ...(params.cwd === undefined ? {} : { cwd: params.cwd }),\n })) as ListSessionsResponse\n },\n async resume(\n sessionId: string,\n params: ResumeSessionParams,\n ): Promise<AcpSession> {\n await call(ACPJS_HOST_RPC_METHODS.resumeSession, {\n agentId,\n sessionId,\n ...params,\n })\n return openSession(sessionId)\n },\n async delete(sessionId: string): Promise<void> {\n await call(ACPJS_HOST_RPC_METHODS.deleteSession, { agentId, sessionId })\n },\n }),\n })\n return {\n agent,\n applySnapshot(snapshot: AgentSnapshotWire): void {\n if (sameAgentSnapshot(current, snapshot)) return\n current = snapshot\n notifyChange(listeners)\n onStatusChanged()\n },\n }\n}\n","import type { DiagnosticEvent } from '@acpjs/protocol'\n\nimport type { ChangeListener } from './types.ts'\n\nexport const MAX_DIAGNOSTICS = 200\n\nexport interface DiagnosticsLog {\n getSnapshot: () => readonly DiagnosticEvent[]\n subscribe: (listener: ChangeListener) => () => void\n push: (event: DiagnosticEvent) => void\n clear: () => void\n}\n\nexport function createDiagnosticsLog(): DiagnosticsLog {\n const entries: DiagnosticEvent[] = []\n const listeners = new Set<ChangeListener>()\n let snapshot: readonly DiagnosticEvent[] = Object.freeze([])\n\n function publish(): void {\n snapshot = Object.freeze([...entries])\n for (const listener of listeners) {\n try {\n listener()\n } catch {}\n }\n }\n\n return {\n getSnapshot: () => snapshot,\n subscribe(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n push(event) {\n entries.push(event)\n if (entries.length > MAX_DIAGNOSTICS) {\n entries.splice(0, entries.length - MAX_DIAGNOSTICS)\n }\n publish()\n },\n clear() {\n entries.length = 0\n publish()\n listeners.clear()\n },\n }\n}\n","import {\n ACP_ERROR_CODES,\n isAcpErrorCode,\n type AcpErrorCode,\n type ErrorObject,\n} from '@acpjs/protocol'\n\nexport class AcpClientError extends Error {\n code: AcpErrorCode\n data: unknown\n retryable: boolean\n\n constructor(error: ErrorObject) {\n super(error.message)\n this.name = 'AcpClientError'\n this.code = error.code\n this.data = error.data\n this.retryable = error.retryable\n }\n}\n\nexport function transportClosedError(): ErrorObject {\n return {\n code: ACP_ERROR_CODES.transportClosed,\n message: 'transport is closed',\n retryable: true,\n }\n}\n\nfunction asErrorObject(value: unknown): ErrorObject | undefined {\n if (typeof value !== 'object' || value === null) return undefined\n const candidate = value as {\n code?: unknown\n message?: unknown\n data?: unknown\n retryable?: unknown\n }\n if (typeof candidate.code !== 'string' || !isAcpErrorCode(candidate.code)) {\n return undefined\n }\n return {\n code: candidate.code,\n message: typeof candidate.message === 'string' ? candidate.message : '',\n ...(candidate.data === undefined ? {} : { data: candidate.data }),\n retryable: candidate.retryable === true,\n }\n}\n\nexport function toClientError(value: unknown): AcpClientError {\n if (value instanceof AcpClientError) return value\n const errorObject = asErrorObject(value)\n if (errorObject) return new AcpClientError(errorObject)\n const message =\n value instanceof Error\n ? value.message\n : typeof value === 'string'\n ? value\n : 'unknown error'\n return new AcpClientError({\n code: ACP_ERROR_CODES.agentError,\n message,\n retryable: false,\n })\n}\n","import type { PermissionListener, PermissionRequest } from './types.ts'\n\nexport interface PermissionRegistry {\n getSnapshot: () => readonly PermissionRequest[]\n subscribe: (listener: PermissionListener) => () => void\n add: (request: PermissionRequest) => void\n prune: (requestId: string) => void\n reset: () => void\n clear: () => void\n}\n\nexport function createPermissionRegistry(): PermissionRegistry {\n const pending = new Map<string, PermissionRequest>()\n const listeners = new Set<PermissionListener>()\n let snapshot: readonly PermissionRequest[] = Object.freeze([])\n\n function publish(): void {\n snapshot = Object.freeze([...pending.values()])\n for (const listener of listeners) {\n try {\n listener(snapshot)\n } catch {}\n }\n }\n\n return {\n getSnapshot: () => snapshot,\n subscribe(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n add(request) {\n if (pending.has(request.requestId)) return\n pending.set(request.requestId, request)\n publish()\n },\n prune(requestId) {\n if (pending.delete(requestId)) publish()\n },\n reset() {\n if (pending.size === 0) return\n pending.clear()\n publish()\n },\n clear() {\n pending.clear()\n publish()\n listeners.clear()\n },\n }\n}\n","import {\n ACP_ERROR_CODES,\n type HostPermissionSnapshot,\n type RequestPermissionOutcome,\n type Transport,\n} from '@acpjs/protocol'\n\nimport { toClientError } from './errors.ts'\nimport {\n createPermissionRegistry,\n type PermissionRegistry,\n} from './permission-registry.ts'\n\nimport type { PermissionRequest } from './types.ts'\n\nexport interface ClientPermissionController {\n readonly registry: PermissionRegistry\n applyProjection: (payload: HostPermissionSnapshot) => void\n respond: (\n requestId: string,\n outcome: RequestPermissionOutcome,\n ) => Promise<void>\n}\n\nexport function createClientPermissionController(options: {\n ensureOpen: () => void\n connected: Promise<void>\n respondInbound: Transport['respondInbound']\n registry?: PermissionRegistry\n}): ClientPermissionController {\n const registry = options.registry ?? createPermissionRegistry()\n\n async function respond(\n requestId: string,\n outcome: RequestPermissionOutcome,\n ): Promise<void> {\n options.ensureOpen()\n try {\n await options.connected\n await options.respondInbound({ id: requestId, result: outcome })\n } catch (error) {\n const clientError = toClientError(error)\n if (clientError.code === ACP_ERROR_CODES.alreadyAnswered) {\n registry.prune(requestId)\n }\n throw clientError\n }\n registry.prune(requestId)\n }\n\n function add(\n payload: Pick<\n HostPermissionSnapshot,\n 'requestId' | 'sessionId' | 'toolCall' | 'options'\n >,\n ): void {\n const permission: PermissionRequest = Object.freeze({\n requestId: payload.requestId,\n sessionId: payload.sessionId,\n toolCall: payload.toolCall,\n options: payload.options,\n respond: (outcome: RequestPermissionOutcome) =>\n respond(payload.requestId, outcome),\n })\n registry.add(permission)\n }\n\n return {\n registry,\n applyProjection(payload) {\n if (payload.status === 'pending') {\n add(payload)\n } else {\n registry.prune(payload.requestId)\n }\n },\n respond,\n }\n}\n","import { AcpClientError, toClientError } from './errors.ts'\n\nimport type { Transport } from '@acpjs/protocol'\n\nimport type { RpcCall } from './internal.ts'\n\nexport function createRpcCaller(options: {\n ensureOpen: () => void\n connected: () => Promise<void>\n request: Transport['request']\n}): RpcCall {\n let rpcCounter = 0\n return async function call(\n method: string,\n params: Record<string, unknown>,\n ): Promise<unknown> {\n options.ensureOpen()\n try {\n await options.connected()\n } catch (error) {\n throw toClientError(error)\n }\n options.ensureOpen()\n rpcCounter += 1\n let response\n try {\n response = await options.request({\n id: `rpc-${rpcCounter}`,\n method,\n params,\n })\n } catch (error) {\n throw toClientError(error)\n }\n if (!response.ok) throw new AcpClientError(response.error)\n return response.result\n }\n}\n","import {\n ACPJS_HOST_RPC_METHODS,\n type ContentBlock,\n type PromptFinishedPayload,\n type SessionConfigOption,\n} from '@acpjs/protocol'\n\nimport type { RpcCall } from './internal.ts'\nimport type { SessionStore, StateListener } from './store.ts'\nimport type { AcpSession, SessionConfigValue } from './types.ts'\n\nexport function createSessionHandle(\n call: RpcCall,\n store: SessionStore,\n): AcpSession {\n const sessionId = store.sessionId\n return Object.freeze({\n sessionId,\n getSnapshot: () => store.getSnapshot(),\n subscribe: (listener: StateListener) => store.subscribe(listener),\n async prompt(blocks: ContentBlock[]): Promise<PromptFinishedPayload> {\n return (await call(ACPJS_HOST_RPC_METHODS.prompt, {\n sessionId,\n prompt: blocks,\n })) as PromptFinishedPayload\n },\n async cancel(): Promise<void> {\n await call(ACPJS_HOST_RPC_METHODS.cancel, { sessionId })\n },\n async close(): Promise<void> {\n await call(ACPJS_HOST_RPC_METHODS.closeSession, { sessionId })\n },\n async setMode(modeId: string): Promise<void> {\n await call(ACPJS_HOST_RPC_METHODS.setMode, { sessionId, modeId })\n },\n async setConfigOption(\n configId: string,\n value: SessionConfigValue,\n ): Promise<SessionConfigOption[]> {\n return (await call(ACPJS_HOST_RPC_METHODS.setConfigOption, {\n sessionId,\n configId,\n value,\n })) as SessionConfigOption[]\n },\n })\n}\n","import {\n createInitialSessionState,\n reduce,\n type AcpEvent,\n type SessionState,\n type SessionSnapshotWire,\n} from '@acpjs/protocol'\n\nexport type StateListener = (state: SessionState) => void\n\nexport interface SessionStore {\n readonly sessionId: string\n getSnapshot: () => SessionState\n subscribe: (listener: StateListener) => () => void\n apply: (event: AcpEvent) => void\n applyProjection: (snapshot: SessionSnapshotWire) => boolean\n lastSeq: () => number\n}\n\nexport function createSessionStore(sessionId: string): SessionStore {\n let state = createInitialSessionState(sessionId)\n let lastSeq = 0\n const listeners = new Set<StateListener>()\n function publish(next: SessionState): void {\n if (next === state) return\n state = next\n for (const listener of listeners) {\n try {\n listener(state)\n } catch {}\n }\n }\n return {\n sessionId,\n getSnapshot: () => state,\n subscribe(listener) {\n listeners.add(listener)\n return () => listeners.delete(listener)\n },\n apply(event) {\n if (!('sessionId' in event) || event.sessionId !== sessionId) return\n if (event.type === 'session-reset') {\n lastSeq = event.seq\n publish(reduce(state, event))\n return\n }\n if (event.seq <= lastSeq) return\n lastSeq = event.seq\n const next = reduce(state, event)\n publish(next)\n },\n applyProjection(snapshot) {\n if (snapshot.sessionId !== sessionId) return false\n const title =\n snapshot.title === undefined ? state.info.title : snapshot.title\n const updatedAt =\n snapshot.updatedAt === undefined\n ? state.info.updatedAt\n : snapshot.updatedAt\n if (\n state.connection.status === snapshot.status &&\n state.info.title === title &&\n state.info.updatedAt === updatedAt\n ) {\n return false\n }\n const next = {\n ...state,\n connection: {\n ...state.connection,\n status: snapshot.status,\n },\n info: {\n title,\n updatedAt,\n },\n }\n publish(next)\n return true\n },\n lastSeq: () => lastSeq,\n }\n}\n","import {\n ACP_ERROR_CODES,\n ACPJS_HOST_RPC_METHODS,\n type AcpEvent,\n type AgentSnapshotWire,\n type ErrorObject,\n type SessionSnapshotWire,\n type TransportHandlers,\n} from '@acpjs/protocol'\n\nimport { createAgentHandle } from './agent-handle.ts'\nimport { createDiagnosticsLog } from './client-diagnostics.ts'\nimport { createClientPermissionController } from './client-permissions.ts'\nimport { createRpcCaller } from './client-rpc.ts'\nimport { AcpClientError, transportClosedError } from './errors.ts'\nimport { notifyChange } from './internal.ts'\nimport { createPermissionRegistry } from './permission-registry.ts'\nimport { createSessionHandle } from './session-handle.ts'\nimport { createSessionStore, type SessionStore } from './store.ts'\n\nimport type {\n AcpAgent,\n AcpClient,\n AcpSession,\n AgentDefinition,\n ChangeListener,\n ConnectionStatusSnapshot,\n CreateAcpClientOptions,\n} from './types.ts'\n\nexport function createAcpClient(options: CreateAcpClientOptions): AcpClient {\n const transport = options.transport\n let closedError: ErrorObject | undefined\n const stores = new Map<string, SessionStore>()\n const storeUnsubscribers = new Set<() => void>()\n const agents = new Map<string, AcpAgent>()\n const agentListeners = new Set<ChangeListener>()\n const agentUpdaters = new Map<\n string,\n {\n applySnapshot: (snapshot: AgentSnapshotWire) => void\n }\n >()\n let agentsSnapshot: readonly AcpAgent[] = Object.freeze([])\n\n function publishAgents(): void {\n agentsSnapshot = Object.freeze([...agents.values()])\n notifyChange(agentListeners)\n }\n\n const sessions = new Map<string, AcpSession>()\n const sessionUnsubscribers = new Map<string, () => void>()\n const sessionListeners = new Set<ChangeListener>()\n let sessionsSnapshot: readonly AcpSession[] = Object.freeze([])\n\n function publishSessions(): void {\n sessionsSnapshot = Object.freeze([...sessions.values()])\n notifyChange(sessionListeners)\n }\n\n let statusSnapshot: ConnectionStatusSnapshot = Object.freeze({\n status: 'connecting' as const,\n })\n const statusListeners = new Set<ChangeListener>()\n const permissions = createPermissionRegistry()\n const diagnostics = createDiagnosticsLog()\n\n function ensureOpen(): void {\n if (closedError) throw new AcpClientError(closedError)\n }\n\n const handlers: TransportHandlers = {\n onInboundRequest() {},\n onLifecycle(event) {\n if (event.status === 'closed') {\n closedError = event.error ?? transportClosedError()\n permissions.reset()\n }\n if (\n statusSnapshot.status === event.status &&\n statusSnapshot.error === event.error\n ) {\n return\n }\n statusSnapshot = Object.freeze({\n status: event.status,\n ...(event.error === undefined ? {} : { error: event.error }),\n })\n notifyChange(statusListeners)\n },\n onSubscriptionError(params) {\n if (params.sessionId !== undefined) closeSessionHandle(params.sessionId)\n },\n }\n\n const connected = transport.connect(handlers)\n const permissionController = createClientPermissionController({\n ensureOpen,\n connected,\n respondInbound: (response) => transport.respondInbound(response),\n registry: permissions,\n })\n\n function onHostEvent(event: AcpEvent): void {\n if (event.type === 'agent-updated') {\n registerAgent(event.payload)\n } else if (event.type === 'session-updated') {\n applySessionProjection(event.payload)\n } else if (event.type === 'permission-updated') {\n permissionController.applyProjection(event.payload)\n } else if (event.type === 'diagnostic') {\n diagnostics.push(event)\n }\n }\n\n connected\n .then(() => {\n if (closedError) return\n storeUnsubscribers.add(transport.subscribe({ fromSeq: 0 }, onHostEvent))\n })\n .catch(() => {})\n\n const call = createRpcCaller({\n ensureOpen,\n connected: () => connected,\n request: (request) => transport.request(request),\n })\n\n function attachStore(sessionId: string): SessionStore {\n const existing = stores.get(sessionId)\n if (existing) return existing\n const store = createSessionStore(sessionId)\n stores.set(sessionId, store)\n const unsubscribe = transport.subscribe(\n { sessionId, fromSeq: store.lastSeq() },\n (event) => {\n if (event.type === 'permission-request-resolved') {\n permissions.prune(event.payload.requestId)\n }\n store.apply(event)\n },\n )\n storeUnsubscribers.add(unsubscribe)\n sessionUnsubscribers.set(sessionId, unsubscribe)\n return store\n }\n\n function openSession(sessionId: string): AcpSession {\n const existing = sessions.get(sessionId)\n if (existing) return existing\n const session = createSessionHandle(call, attachStore(sessionId))\n sessions.set(sessionId, session)\n publishSessions()\n return session\n }\n\n function closeSessionHandle(sessionId: string): void {\n if (!sessions.delete(sessionId)) return\n const unsubscribe = sessionUnsubscribers.get(sessionId)\n unsubscribe?.()\n if (unsubscribe) storeUnsubscribers.delete(unsubscribe)\n sessionUnsubscribers.delete(sessionId)\n stores.delete(sessionId)\n publishSessions()\n }\n\n function applySessionProjection(\n snapshot: SessionSnapshotWire,\n ): AcpSession | undefined {\n if (snapshot.status === 'deleted') {\n closeSessionHandle(snapshot.sessionId)\n return undefined\n }\n const existing = sessions.has(snapshot.sessionId)\n const store = attachStore(snapshot.sessionId)\n const changed = store.applyProjection(snapshot)\n const session = openSession(snapshot.sessionId)\n if (existing && changed) publishSessions()\n return session\n }\n\n async function listAgents(): Promise<readonly AgentSnapshotWire[]> {\n return (await call(\n ACPJS_HOST_RPC_METHODS.listAgents,\n {},\n )) as AgentSnapshotWire[]\n }\n\n async function listAllSessions(): Promise<readonly SessionSnapshotWire[]> {\n return (await call(\n ACPJS_HOST_RPC_METHODS.getAllSessions,\n {},\n )) as SessionSnapshotWire[]\n }\n\n function registerAgent(snapshot: AgentSnapshotWire): AcpAgent {\n const existing = agents.get(snapshot.agentId)\n if (existing) {\n agentUpdaters.get(snapshot.agentId)?.applySnapshot(snapshot)\n return existing\n }\n const { agent, applySnapshot } = createAgentHandle(\n call,\n openSession,\n (snapshot) => {\n const session = applySessionProjection(snapshot)\n if (session === undefined) {\n throw new AcpClientError({\n code: ACP_ERROR_CODES.sessionClosed,\n message: `session ${snapshot.sessionId} is deleted`,\n retryable: false,\n })\n }\n return session\n },\n publishAgents,\n snapshot,\n )\n agentUpdaters.set(agent.agentId, { applySnapshot })\n agents.set(agent.agentId, agent)\n publishAgents()\n return agent\n }\n\n return Object.freeze({\n agents: Object.freeze({\n async spawn(definition: AgentDefinition): Promise<AcpAgent> {\n const snapshot = (await call(ACPJS_HOST_RPC_METHODS.spawnAgent, {\n definition,\n })) as AgentSnapshotWire\n return registerAgent(snapshot)\n },\n get: (agentId: string) => agents.get(agentId),\n getSnapshot: () => agentsSnapshot,\n subscribe(listener: ChangeListener): () => void {\n agentListeners.add(listener)\n return () => agentListeners.delete(listener)\n },\n list: listAgents,\n async attach(agentId: string): Promise<AcpAgent> {\n const snapshots = await listAgents()\n const snapshot = snapshots.find(\n (candidate) => candidate.agentId === agentId,\n )\n if (!snapshot) {\n throw new AcpClientError({\n code: ACP_ERROR_CODES.agentExited,\n message: `agent ${agentId} is not known to the host`,\n retryable: false,\n })\n }\n return agents.get(agentId) ?? registerAgent(snapshot)\n },\n }),\n sessions: Object.freeze({\n get: (sessionId: string) => sessions.get(sessionId),\n getSnapshot: () => sessionsSnapshot,\n subscribe(listener: ChangeListener): () => void {\n sessionListeners.add(listener)\n return () => sessionListeners.delete(listener)\n },\n list: listAllSessions,\n async attach(sessionId: string): Promise<AcpSession> {\n const snapshots = await listAllSessions()\n const snapshot = snapshots.find(\n (candidate) => candidate.sessionId === sessionId,\n )\n if (!snapshot) {\n throw new AcpClientError({\n code: ACP_ERROR_CODES.sessionClosed,\n message: `session ${sessionId} is not known to the host`,\n retryable: false,\n })\n }\n const session = applySessionProjection(snapshot)\n if (session === undefined) {\n throw new AcpClientError({\n code: ACP_ERROR_CODES.sessionClosed,\n message: `session ${sessionId} is deleted`,\n retryable: false,\n })\n }\n return session\n },\n async restore(): Promise<readonly SessionSnapshotWire[]> {\n const restored = (await call(\n ACPJS_HOST_RPC_METHODS.restoreSessions,\n {},\n )) as SessionSnapshotWire[]\n for (const snapshot of restored) applySessionProjection(snapshot)\n return restored\n },\n }),\n permissions: Object.freeze({\n getSnapshot: permissions.getSnapshot,\n subscribe: permissions.subscribe,\n }),\n diagnostics: Object.freeze({\n getSnapshot: diagnostics.getSnapshot,\n subscribe: diagnostics.subscribe,\n }),\n status: Object.freeze({\n getSnapshot: () => statusSnapshot,\n subscribe(listener: ChangeListener): () => void {\n statusListeners.add(listener)\n return () => statusListeners.delete(listener)\n },\n }),\n async dispose(): Promise<void> {\n if (closedError) return\n closedError = transportClosedError()\n for (const unsubscribe of storeUnsubscribers) unsubscribe()\n storeUnsubscribers.clear()\n permissions.clear()\n diagnostics.clear()\n await transport.close()\n },\n })\n}\n","import {\n ACP_ERROR_CODES,\n type EnvelopeEndpoint,\n type Transport,\n type TransportConnectionStatus,\n type TransportHandlers,\n} from '@acpjs/protocol'\n\nimport { AcpClientError, transportClosedError } from './errors.ts'\n\nexport function createInProcessTransport(\n endpoint: EnvelopeEndpoint,\n): Transport {\n let status: TransportConnectionStatus = 'connecting'\n let handlers: TransportHandlers | undefined\n const unsubscribers = new Set<() => void>()\n let detachInbound: (() => void) | undefined\n\n return {\n async connect(next: TransportHandlers): Promise<void> {\n if (status === 'closed') {\n throw new AcpClientError(transportClosedError())\n }\n if (handlers) {\n throw new AcpClientError({\n code: ACP_ERROR_CODES.configInvalid,\n message: 'transport already connected',\n retryable: false,\n })\n }\n handlers = next\n next.onLifecycle({ status: 'connecting' })\n detachInbound = endpoint.onInboundRequest((request) => {\n next.onInboundRequest(request)\n })\n status = 'connected'\n next.onLifecycle({ status: 'connected' })\n },\n async request(request) {\n if (status !== 'connected') {\n return { id: request.id, ok: false, error: transportClosedError() }\n }\n return endpoint.request(request)\n },\n subscribe(params, onEvent) {\n if (status !== 'connected') {\n throw new AcpClientError(transportClosedError())\n }\n const unsubscribe = endpoint.subscribe(params, onEvent)\n unsubscribers.add(unsubscribe)\n return () => {\n unsubscribers.delete(unsubscribe)\n unsubscribe()\n }\n },\n async respondInbound(response) {\n if (status !== 'connected') {\n throw new AcpClientError(transportClosedError())\n }\n await endpoint.respondInbound(response)\n },\n async close() {\n if (status === 'closed') return\n status = 'closed'\n detachInbound?.()\n for (const unsubscribe of unsubscribers) unsubscribe()\n unsubscribers.clear()\n handlers?.onLifecycle({ status: 'closed' })\n },\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,8 +1,13 @@
1
1
  {
2
2
  "name": "@acpjs/client",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "acpjs typed facade, reducer-driven snapshot+subscribe store, and in-process transport.",
5
5
  "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/zhangyu1818/acpjs.git",
9
+ "directory": "packages/client"
10
+ },
6
11
  "files": [
7
12
  "dist"
8
13
  ],
@@ -17,11 +22,11 @@
17
22
  "access": "public"
18
23
  },
19
24
  "dependencies": {
20
- "@acpjs/protocol": "0.1.0"
25
+ "@acpjs/protocol": "0.2.0"
21
26
  },
22
27
  "devDependencies": {
23
28
  "@types/node": "^25.9.2",
24
- "@acpjs/core": "0.1.0",
29
+ "@acpjs/core": "0.2.0",
25
30
  "@acpjs/fixture-agent": "0.0.0"
26
31
  },
27
32
  "engines": {