@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 +29 -26
- package/dist/index.d.ts +13 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +276 -182
- package/dist/index.js.map +1 -1
- package/package.json +8 -3
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({
|
|
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
|
|
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?`).
|
|
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
|
|
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
|
|
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
|
|
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
|
|
90
|
-
- `agent.getSnapshot()` → `
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 `
|
|
114
|
-
- **auth
|
|
115
|
-
- **
|
|
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
|
|
120
|
-
- **permission-request exit**:
|
|
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
|
|
123
|
-
- **listener-callback exceptions**: session-state listeners and permission listeners that throw are isolated (swallowed, without interrupting dispatch to the rest of the batch
|
|
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,
|
|
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:
|
|
26
|
-
load: (sessionId: string, params:
|
|
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
|
-
|
|
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
|
|
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
|
|
57
|
+
list: () => Promise<readonly SessionSnapshotWire$1[]>;
|
|
68
58
|
attach: (sessionId: string) => Promise<AcpSession>;
|
|
69
|
-
restore: () => Promise<readonly
|
|
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
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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":";;;
|
|
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 {
|
|
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
|
|
54
|
-
|
|
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
|
-
|
|
27
|
+
return applySessionSnapshot(await call(ACPJS_HOST_RPC_METHODS.createSession, {
|
|
78
28
|
agentId,
|
|
79
|
-
|
|
80
|
-
|
|
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(
|
|
33
|
+
await call(ACPJS_HOST_RPC_METHODS.loadSession, {
|
|
92
34
|
agentId,
|
|
93
35
|
sessionId,
|
|
94
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
125
|
-
if (
|
|
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
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
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(
|
|
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(
|
|
260
|
+
await call(ACPJS_HOST_RPC_METHODS.cancel, { sessionId });
|
|
204
261
|
},
|
|
205
262
|
async close() {
|
|
206
|
-
await call(
|
|
263
|
+
await call(ACPJS_HOST_RPC_METHODS.closeSession, { sessionId });
|
|
207
264
|
},
|
|
208
265
|
async setMode(modeId) {
|
|
209
|
-
await call(
|
|
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(
|
|
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
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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
|
|
279
|
-
onInboundRequest(
|
|
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-
|
|
306
|
-
else if (event.type === "
|
|
307
|
-
else if (event.type === "
|
|
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
|
-
|
|
315
|
-
ensureOpen
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
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(
|
|
446
|
+
return await call(ACPJS_HOST_RPC_METHODS.listAgents, {});
|
|
377
447
|
}
|
|
378
448
|
async function listAllSessions() {
|
|
379
|
-
return await call(
|
|
449
|
+
return await call(ACPJS_HOST_RPC_METHODS.getAllSessions, {});
|
|
380
450
|
}
|
|
381
451
|
function registerAgent(snapshot) {
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
25
|
+
"@acpjs/protocol": "0.2.0"
|
|
21
26
|
},
|
|
22
27
|
"devDependencies": {
|
|
23
28
|
"@types/node": "^25.9.2",
|
|
24
|
-
"@acpjs/core": "0.
|
|
29
|
+
"@acpjs/core": "0.2.0",
|
|
25
30
|
"@acpjs/fixture-agent": "0.0.0"
|
|
26
31
|
},
|
|
27
32
|
"engines": {
|