use-acp 0.1.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.
Files changed (59) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +110 -0
  3. package/dist/client/acp-client.d.ts +40 -0
  4. package/dist/client/acp-client.d.ts.map +1 -0
  5. package/dist/client/acp-client.js +88 -0
  6. package/dist/client/acp-client.js.map +1 -0
  7. package/dist/client/types.d.ts +25 -0
  8. package/dist/client/types.d.ts.map +1 -0
  9. package/dist/client/types.js +2 -0
  10. package/dist/client/types.js.map +1 -0
  11. package/dist/components/diff-viewer.d.ts +2 -0
  12. package/dist/components/diff-viewer.d.ts.map +1 -0
  13. package/dist/components/diff-viewer.js +2 -0
  14. package/dist/components/diff-viewer.js.map +1 -0
  15. package/dist/components/request-perms.d.ts +2 -0
  16. package/dist/components/request-perms.d.ts.map +1 -0
  17. package/dist/components/request-perms.js +2 -0
  18. package/dist/components/request-perms.js.map +1 -0
  19. package/dist/components/streams.d.ts +25 -0
  20. package/dist/components/streams.d.ts.map +1 -0
  21. package/dist/components/streams.js +74 -0
  22. package/dist/components/streams.js.map +1 -0
  23. package/dist/connection/websocket-manager.d.ts +27 -0
  24. package/dist/connection/websocket-manager.d.ts.map +1 -0
  25. package/dist/connection/websocket-manager.js +109 -0
  26. package/dist/connection/websocket-manager.js.map +1 -0
  27. package/dist/hooks/use-acp-client.d.ts +23 -0
  28. package/dist/hooks/use-acp-client.d.ts.map +1 -0
  29. package/dist/hooks/use-acp-client.js +146 -0
  30. package/dist/hooks/use-acp-client.js.map +1 -0
  31. package/dist/hooks/use-event-callback.d.ts +3 -0
  32. package/dist/hooks/use-event-callback.d.ts.map +1 -0
  33. package/dist/hooks/use-event-callback.js +13 -0
  34. package/dist/hooks/use-event-callback.js.map +1 -0
  35. package/dist/index.d.ts +4 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +4 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/state/atoms.d.ts +14 -0
  40. package/dist/state/atoms.d.ts.map +1 -0
  41. package/dist/state/atoms.js +48 -0
  42. package/dist/state/atoms.js.map +1 -0
  43. package/dist/state/types.d.ts +21 -0
  44. package/dist/state/types.d.ts.map +1 -0
  45. package/dist/state/types.js +2 -0
  46. package/dist/state/types.js.map +1 -0
  47. package/dist/state/utils.d.ts +8 -0
  48. package/dist/state/utils.d.ts.map +1 -0
  49. package/dist/state/utils.js +53 -0
  50. package/dist/state/utils.js.map +1 -0
  51. package/dist/utils/deferred.d.ts +7 -0
  52. package/dist/utils/deferred.d.ts.map +1 -0
  53. package/dist/utils/deferred.js +12 -0
  54. package/dist/utils/deferred.js.map +1 -0
  55. package/dist/utils/never.d.ts +3 -0
  56. package/dist/utils/never.d.ts.map +1 -0
  57. package/dist/utils/never.js +9 -0
  58. package/dist/utils/never.js.map +1 -0
  59. package/package.json +79 -0
@@ -0,0 +1,27 @@
1
+ import { type NodeReadableStream } from "../components/streams.js";
2
+ import type { ConnectionState } from "../state/types.js";
3
+ export interface WebSocketManagerOptions {
4
+ url: string;
5
+ onConnectionStateChange: (state: ConnectionState) => void;
6
+ onError: (error: Error) => void;
7
+ reconnectAttempts?: number;
8
+ reconnectDelay?: number;
9
+ }
10
+ export declare class WebSocketManager {
11
+ private ws;
12
+ private options;
13
+ private reconnectCount;
14
+ private reconnectTimer;
15
+ private readableStream;
16
+ private writableStream;
17
+ constructor(options: WebSocketManagerOptions);
18
+ connect(): Promise<{
19
+ readable: NodeReadableStream;
20
+ writable: WritableStream<Uint8Array>;
21
+ }>;
22
+ disconnect(): void;
23
+ private attemptReconnect;
24
+ private updateConnectionState;
25
+ getConnectionState(): ConnectionState["status"];
26
+ }
27
+ //# sourceMappingURL=websocket-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket-manager.d.ts","sourceRoot":"","sources":["../../src/connection/websocket-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEzD,MAAM,WAAW,uBAAuB;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,uBAAuB,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IAC1D,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAChC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,OAAO,CAA0B;IACzC,OAAO,CAAC,cAAc,CAAK;IAC3B,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,cAAc,CAAmC;IACzD,OAAO,CAAC,cAAc,CAA2C;gBAErD,OAAO,EAAE,uBAAuB;IAQtC,OAAO,IAAI,OAAO,CAAC;QAAE,QAAQ,EAAE,kBAAkB,CAAC;QAAC,QAAQ,EAAE,cAAc,CAAC,UAAU,CAAC,CAAA;KAAE,CAAC;IAuDhG,UAAU;IAgBV,OAAO,CAAC,gBAAgB;IAaxB,OAAO,CAAC,qBAAqB;IAI7B,kBAAkB,IAAI,eAAe,CAAC,QAAQ,CAAC;CAehD"}
@@ -0,0 +1,109 @@
1
+ import { createWebSocketReadableStream, createWebSocketWritableStream, } from "../components/streams.js";
2
+ export class WebSocketManager {
3
+ ws = null;
4
+ options;
5
+ reconnectCount = 0;
6
+ reconnectTimer = null;
7
+ readableStream = null;
8
+ writableStream = null;
9
+ constructor(options) {
10
+ this.options = {
11
+ reconnectAttempts: 3,
12
+ reconnectDelay: 1000,
13
+ ...options,
14
+ };
15
+ }
16
+ async connect() {
17
+ this.updateConnectionState({ status: "connecting", url: this.options.url });
18
+ try {
19
+ this.ws = new WebSocket(this.options.url);
20
+ return new Promise((resolve, reject) => {
21
+ if (!this.ws) {
22
+ reject(new Error("WebSocket not initialized"));
23
+ return;
24
+ }
25
+ this.ws.onopen = () => {
26
+ this.reconnectCount = 0;
27
+ this.updateConnectionState({ status: "connected", url: this.options.url });
28
+ if (this.ws) {
29
+ this.readableStream = createWebSocketReadableStream(this.ws);
30
+ this.writableStream = createWebSocketWritableStream(this.ws);
31
+ resolve({
32
+ readable: this.readableStream,
33
+ writable: this.writableStream,
34
+ });
35
+ }
36
+ };
37
+ this.ws.onerror = (_event) => {
38
+ const error = new Error("WebSocket connection error");
39
+ this.options.onError(error);
40
+ this.updateConnectionState({
41
+ status: "error",
42
+ error: error.message,
43
+ url: this.options.url,
44
+ });
45
+ reject(error);
46
+ };
47
+ this.ws.onclose = () => {
48
+ this.updateConnectionState({ status: "disconnected", url: this.options.url });
49
+ this.attemptReconnect();
50
+ };
51
+ });
52
+ }
53
+ catch (error) {
54
+ const errorObj = error instanceof Error ? error : new Error(String(error));
55
+ this.options.onError(errorObj);
56
+ this.updateConnectionState({
57
+ status: "error",
58
+ error: errorObj.message,
59
+ url: this.options.url,
60
+ });
61
+ throw errorObj;
62
+ }
63
+ }
64
+ disconnect() {
65
+ if (this.reconnectTimer) {
66
+ clearTimeout(this.reconnectTimer);
67
+ this.reconnectTimer = null;
68
+ }
69
+ if (this.ws) {
70
+ this.ws.close();
71
+ this.ws = null;
72
+ }
73
+ this.readableStream = null;
74
+ this.writableStream = null;
75
+ this.updateConnectionState({ status: "disconnected" });
76
+ }
77
+ attemptReconnect() {
78
+ if (this.reconnectCount < (this.options.reconnectAttempts || 3)) {
79
+ this.reconnectCount++;
80
+ this.reconnectTimer = setTimeout(async () => {
81
+ try {
82
+ await this.connect();
83
+ }
84
+ catch (_error) {
85
+ // Error is already handled in connect method
86
+ }
87
+ }, this.options.reconnectDelay);
88
+ }
89
+ }
90
+ updateConnectionState(state) {
91
+ this.options.onConnectionStateChange(state);
92
+ }
93
+ getConnectionState() {
94
+ if (!this.ws)
95
+ return "disconnected";
96
+ switch (this.ws.readyState) {
97
+ case WebSocket.CONNECTING:
98
+ return "connecting";
99
+ case WebSocket.OPEN:
100
+ return "connected";
101
+ case WebSocket.CLOSING:
102
+ case WebSocket.CLOSED:
103
+ return "disconnected";
104
+ default:
105
+ return "error";
106
+ }
107
+ }
108
+ }
109
+ //# sourceMappingURL=websocket-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"websocket-manager.js","sourceRoot":"","sources":["../../src/connection/websocket-manager.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n createWebSocketReadableStream,\n createWebSocketWritableStream,\n type NodeReadableStream,\n} from \"../components/streams.js\";\nimport type { ConnectionState } from \"../state/types.js\";\n\nexport interface WebSocketManagerOptions {\n url: string;\n onConnectionStateChange: (state: ConnectionState) => void;\n onError: (error: Error) => void;\n reconnectAttempts?: number;\n reconnectDelay?: number;\n}\n\nexport class WebSocketManager {\n private ws: WebSocket | null = null;\n private options: WebSocketManagerOptions;\n private reconnectCount = 0;\n private reconnectTimer: NodeJS.Timeout | null = null;\n private readableStream: NodeReadableStream | null = null;\n private writableStream: WritableStream<Uint8Array> | null = null;\n\n constructor(options: WebSocketManagerOptions) {\n this.options = {\n reconnectAttempts: 3,\n reconnectDelay: 1000,\n ...options,\n };\n }\n\n async connect(): Promise<{ readable: NodeReadableStream; writable: WritableStream<Uint8Array> }> {\n this.updateConnectionState({ status: \"connecting\", url: this.options.url });\n\n try {\n this.ws = new WebSocket(this.options.url);\n\n return new Promise((resolve, reject) => {\n if (!this.ws) {\n reject(new Error(\"WebSocket not initialized\"));\n return;\n }\n\n this.ws.onopen = () => {\n this.reconnectCount = 0;\n this.updateConnectionState({ status: \"connected\", url: this.options.url });\n\n if (this.ws) {\n this.readableStream = createWebSocketReadableStream(this.ws);\n this.writableStream = createWebSocketWritableStream(this.ws);\n\n resolve({\n readable: this.readableStream,\n writable: this.writableStream,\n });\n }\n };\n\n this.ws.onerror = (_event) => {\n const error = new Error(\"WebSocket connection error\");\n this.options.onError(error);\n this.updateConnectionState({\n status: \"error\",\n error: error.message,\n url: this.options.url,\n });\n reject(error);\n };\n\n this.ws.onclose = () => {\n this.updateConnectionState({ status: \"disconnected\", url: this.options.url });\n this.attemptReconnect();\n };\n });\n } catch (error) {\n const errorObj = error instanceof Error ? error : new Error(String(error));\n this.options.onError(errorObj);\n this.updateConnectionState({\n status: \"error\",\n error: errorObj.message,\n url: this.options.url,\n });\n throw errorObj;\n }\n }\n\n disconnect() {\n if (this.reconnectTimer) {\n clearTimeout(this.reconnectTimer);\n this.reconnectTimer = null;\n }\n\n if (this.ws) {\n this.ws.close();\n this.ws = null;\n }\n\n this.readableStream = null;\n this.writableStream = null;\n this.updateConnectionState({ status: \"disconnected\" });\n }\n\n private attemptReconnect() {\n if (this.reconnectCount < (this.options.reconnectAttempts || 3)) {\n this.reconnectCount++;\n this.reconnectTimer = setTimeout(async () => {\n try {\n await this.connect();\n } catch (_error) {\n // Error is already handled in connect method\n }\n }, this.options.reconnectDelay);\n }\n }\n\n private updateConnectionState(state: ConnectionState) {\n this.options.onConnectionStateChange(state);\n }\n\n getConnectionState(): ConnectionState[\"status\"] {\n if (!this.ws) return \"disconnected\";\n\n switch (this.ws.readyState) {\n case WebSocket.CONNECTING:\n return \"connecting\";\n case WebSocket.OPEN:\n return \"connected\";\n case WebSocket.CLOSING:\n case WebSocket.CLOSED:\n return \"disconnected\";\n default:\n return \"error\";\n }\n }\n}\n"]}
@@ -0,0 +1,23 @@
1
+ import { type Agent, type RequestPermissionResponse } from "@zed-industries/agent-client-protocol";
2
+ import { type IdentifiedPermissionRequest } from "../client/acp-client.js";
3
+ import type { ConnectionState, NotificationEvent } from "../state/types.js";
4
+ export interface UseAcpClientOptions {
5
+ wsUrl: string;
6
+ autoConnect?: boolean;
7
+ reconnectAttempts?: number;
8
+ reconnectDelay?: number;
9
+ initialSessionId?: string | null;
10
+ }
11
+ export interface UseAcpClientReturn {
12
+ connect: () => Promise<void>;
13
+ disconnect: () => void;
14
+ connectionState: ConnectionState;
15
+ notifications: NotificationEvent[];
16
+ clearNotifications: () => void;
17
+ pendingPermission: IdentifiedPermissionRequest | null;
18
+ resolvePermission: (response: RequestPermissionResponse) => void;
19
+ rejectPermission: (error: Error) => void;
20
+ agent: Agent | null;
21
+ }
22
+ export declare function useAcpClient(options: UseAcpClientOptions): UseAcpClientReturn;
23
+ //# sourceMappingURL=use-acp-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-acp-client.d.ts","sourceRoot":"","sources":["../../src/hooks/use-acp-client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,KAAK,EAEV,KAAK,yBAAyB,EAE/B,MAAM,uCAAuC,CAAC;AAE/C,OAAO,EAEL,KAAK,2BAA2B,EAEjC,MAAM,yBAAyB,CAAC;AAGjC,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAG5E,MAAM,WAAW,mBAAmB;IAElC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,kBAAkB;IAEjC,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,UAAU,EAAE,MAAM,IAAI,CAAC;IACvB,eAAe,EAAE,eAAe,CAAC;IAGjC,aAAa,EAAE,iBAAiB,EAAE,CAAC;IACnC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAG/B,iBAAiB,EAAE,2BAA2B,GAAG,IAAI,CAAC;IACtD,iBAAiB,EAAE,CAAC,QAAQ,EAAE,yBAAyB,KAAK,IAAI,CAAC;IACjE,gBAAgB,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAGzC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACrB;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,kBAAkB,CA+K7E"}
@@ -0,0 +1,146 @@
1
+ import { ClientSideConnection, } from "@zed-industries/agent-client-protocol";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { AcpClient, ListeningAgent, } from "../client/acp-client.js";
4
+ import { WebSocketManager } from "../connection/websocket-manager.js";
5
+ import { useAcpStore } from "../state/atoms.js";
6
+ import { useEventCallback } from "./use-event-callback.js";
7
+ export function useAcpClient(options) {
8
+ const { connectionState, notifications, activeSessionId, setActiveSessionId, setConnectionState, addNotification, clearNotifications, } = useAcpStore();
9
+ // State
10
+ const [pendingPermission, setPendingPermission] = useState(null);
11
+ const [agent, setAgent] = useState(null);
12
+ // Refs
13
+ const wsManagerRef = useRef(null);
14
+ const acpClientRef = useRef(null);
15
+ // Handlers
16
+ const handleConnectionStateChange = useEventCallback((state) => {
17
+ setConnectionState(state);
18
+ addNotification({
19
+ type: "connection_change",
20
+ data: state,
21
+ });
22
+ });
23
+ const handleError = useEventCallback((error) => {
24
+ addNotification({
25
+ type: "error",
26
+ data: error,
27
+ });
28
+ });
29
+ const handleSessionNotification = useEventCallback((notification) => {
30
+ addNotification({
31
+ type: "session_notification",
32
+ data: notification,
33
+ });
34
+ });
35
+ const handleRequestPermission = useEventCallback((params) => {
36
+ setPendingPermission(params);
37
+ });
38
+ const connect = useEventCallback(async () => {
39
+ if (wsManagerRef.current ||
40
+ connectionState.status === "connecting" ||
41
+ connectionState.status === "connected") {
42
+ return;
43
+ }
44
+ const wsManager = new WebSocketManager({
45
+ url: options.wsUrl,
46
+ onConnectionStateChange: handleConnectionStateChange,
47
+ onError: handleError,
48
+ reconnectAttempts: options.reconnectAttempts,
49
+ reconnectDelay: options.reconnectDelay,
50
+ });
51
+ wsManagerRef.current = wsManager;
52
+ try {
53
+ const { readable, writable } = await wsManager.connect();
54
+ // Initialize the connection
55
+ const agent = new ClientSideConnection((agent) => {
56
+ // Initialize the ACP client
57
+ const acpClient = new AcpClient(agent, {
58
+ onRequestPermission: handleRequestPermission,
59
+ onSessionNotification: handleSessionNotification,
60
+ });
61
+ acpClientRef.current = acpClient;
62
+ return acpClient;
63
+ }, writable, readable);
64
+ const listeningAgent = new ListeningAgent(agent, {
65
+ on_newSession_response: (response) => {
66
+ setActiveSessionId(response.sessionId);
67
+ },
68
+ on_prompt_start: (params) => {
69
+ for (const prompt of params.prompt) {
70
+ addNotification({
71
+ type: "session_notification",
72
+ data: {
73
+ sessionId: params.sessionId,
74
+ update: {
75
+ sessionUpdate: "user_message_chunk",
76
+ content: prompt,
77
+ },
78
+ },
79
+ });
80
+ }
81
+ },
82
+ });
83
+ setAgent(listeningAgent);
84
+ }
85
+ catch (error) {
86
+ wsManagerRef.current = null;
87
+ throw error;
88
+ }
89
+ });
90
+ const disconnect = useEventCallback(() => {
91
+ if (wsManagerRef.current) {
92
+ wsManagerRef.current.disconnect();
93
+ wsManagerRef.current = null;
94
+ }
95
+ acpClientRef.current = null;
96
+ setAgent(null);
97
+ setPendingPermission(null);
98
+ });
99
+ const resolvePermission = useEventCallback((response) => {
100
+ if (pendingPermission && acpClientRef.current) {
101
+ const permissionId = pendingPermission.id;
102
+ if (permissionId) {
103
+ acpClientRef.current.resolvePermission(permissionId, response);
104
+ }
105
+ }
106
+ setPendingPermission(null);
107
+ });
108
+ const rejectPermissionCallback = useEventCallback((error) => {
109
+ if (pendingPermission && acpClientRef.current) {
110
+ const permissionId = pendingPermission.id;
111
+ if (permissionId) {
112
+ acpClientRef.current.rejectPermission(permissionId, error);
113
+ }
114
+ }
115
+ setPendingPermission(null);
116
+ });
117
+ // Effects
118
+ // Update active session id if it changes externally
119
+ useEffect(() => {
120
+ if (options.initialSessionId) {
121
+ setActiveSessionId(options.initialSessionId);
122
+ }
123
+ }, [options.initialSessionId, setActiveSessionId]);
124
+ // Auto-connect on mount if specified
125
+ // biome-ignore lint/correctness/useExhaustiveDependencies: Don't include connect/disconnect to avoid re-connecting on every render
126
+ useEffect(() => {
127
+ if (options.autoConnect) {
128
+ connect().catch(console.error);
129
+ }
130
+ return () => {
131
+ disconnect();
132
+ };
133
+ }, [options.autoConnect]);
134
+ return {
135
+ connect,
136
+ disconnect,
137
+ connectionState,
138
+ notifications: activeSessionId ? notifications[activeSessionId] || [] : [],
139
+ clearNotifications,
140
+ pendingPermission,
141
+ resolvePermission,
142
+ rejectPermission: rejectPermissionCallback,
143
+ agent: agent,
144
+ };
145
+ }
146
+ //# sourceMappingURL=use-acp-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-acp-client.js","sourceRoot":"","sources":["../../src/hooks/use-acp-client.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type Agent,\n ClientSideConnection,\n type RequestPermissionResponse,\n type SessionNotification,\n} from \"@zed-industries/agent-client-protocol\";\nimport { useEffect, useRef, useState } from \"react\";\nimport {\n AcpClient,\n type IdentifiedPermissionRequest,\n ListeningAgent,\n} from \"../client/acp-client.js\";\nimport { WebSocketManager } from \"../connection/websocket-manager.js\";\nimport { useAcpStore } from \"../state/atoms.js\";\nimport type { ConnectionState, NotificationEvent } from \"../state/types.js\";\nimport { useEventCallback } from \"./use-event-callback.js\";\n\nexport interface UseAcpClientOptions {\n // Connection management\n wsUrl: string;\n autoConnect?: boolean;\n reconnectAttempts?: number;\n reconnectDelay?: number;\n\n // Defaults\n initialSessionId?: string | null;\n}\n\nexport interface UseAcpClientReturn {\n // Connection management\n connect: () => Promise<void>;\n disconnect: () => void;\n connectionState: ConnectionState;\n\n // State management\n notifications: NotificationEvent[];\n clearNotifications: () => void;\n\n // Permission handling\n pendingPermission: IdentifiedPermissionRequest | null;\n resolvePermission: (response: RequestPermissionResponse) => void;\n rejectPermission: (error: Error) => void;\n\n // ACP connection\n agent: Agent | null;\n}\n\nexport function useAcpClient(options: UseAcpClientOptions): UseAcpClientReturn {\n const {\n connectionState,\n notifications,\n activeSessionId,\n setActiveSessionId,\n setConnectionState,\n addNotification,\n clearNotifications,\n } = useAcpStore();\n\n // State\n const [pendingPermission, setPendingPermission] = useState<IdentifiedPermissionRequest | null>(\n null,\n );\n const [agent, setAgent] = useState<Agent | null>(null);\n\n // Refs\n const wsManagerRef = useRef<WebSocketManager | null>(null);\n const acpClientRef = useRef<AcpClient | null>(null);\n\n // Handlers\n const handleConnectionStateChange = useEventCallback((state: ConnectionState) => {\n setConnectionState(state);\n addNotification({\n type: \"connection_change\",\n data: state,\n });\n });\n\n const handleError = useEventCallback((error: Error) => {\n addNotification({\n type: \"error\",\n data: error,\n });\n });\n\n const handleSessionNotification = useEventCallback((notification: SessionNotification) => {\n addNotification({\n type: \"session_notification\",\n data: notification,\n });\n });\n\n const handleRequestPermission = useEventCallback((params: IdentifiedPermissionRequest) => {\n setPendingPermission(params);\n });\n\n const connect = useEventCallback(async () => {\n if (\n wsManagerRef.current ||\n connectionState.status === \"connecting\" ||\n connectionState.status === \"connected\"\n ) {\n return;\n }\n\n const wsManager = new WebSocketManager({\n url: options.wsUrl,\n onConnectionStateChange: handleConnectionStateChange,\n onError: handleError,\n reconnectAttempts: options.reconnectAttempts,\n reconnectDelay: options.reconnectDelay,\n });\n\n wsManagerRef.current = wsManager;\n\n try {\n const { readable, writable } = await wsManager.connect();\n\n // Initialize the connection\n const agent = new ClientSideConnection(\n (agent) => {\n // Initialize the ACP client\n const acpClient = new AcpClient(agent, {\n onRequestPermission: handleRequestPermission,\n onSessionNotification: handleSessionNotification,\n });\n acpClientRef.current = acpClient;\n return acpClient;\n },\n writable,\n readable,\n );\n\n const listeningAgent: Agent = new ListeningAgent(agent, {\n on_newSession_response: (response) => {\n setActiveSessionId(response.sessionId);\n },\n on_prompt_start: (params) => {\n for (const prompt of params.prompt) {\n addNotification({\n type: \"session_notification\",\n data: {\n sessionId: params.sessionId,\n update: {\n sessionUpdate: \"user_message_chunk\",\n content: prompt,\n },\n },\n });\n }\n },\n });\n\n setAgent(listeningAgent);\n } catch (error) {\n wsManagerRef.current = null;\n throw error;\n }\n });\n\n const disconnect = useEventCallback(() => {\n if (wsManagerRef.current) {\n wsManagerRef.current.disconnect();\n wsManagerRef.current = null;\n }\n\n acpClientRef.current = null;\n setAgent(null);\n setPendingPermission(null);\n });\n\n const resolvePermission = useEventCallback((response: RequestPermissionResponse) => {\n if (pendingPermission && acpClientRef.current) {\n const permissionId = pendingPermission.id;\n if (permissionId) {\n acpClientRef.current.resolvePermission(permissionId, response);\n }\n }\n setPendingPermission(null);\n });\n\n const rejectPermissionCallback = useEventCallback((error: Error) => {\n if (pendingPermission && acpClientRef.current) {\n const permissionId = pendingPermission.id;\n if (permissionId) {\n acpClientRef.current.rejectPermission(permissionId, error);\n }\n }\n setPendingPermission(null);\n });\n\n // Effects\n\n // Update active session id if it changes externally\n useEffect(() => {\n if (options.initialSessionId) {\n setActiveSessionId(options.initialSessionId);\n }\n }, [options.initialSessionId, setActiveSessionId]);\n\n // Auto-connect on mount if specified\n // biome-ignore lint/correctness/useExhaustiveDependencies: Don't include connect/disconnect to avoid re-connecting on every render\n useEffect(() => {\n if (options.autoConnect) {\n connect().catch(console.error);\n }\n\n return () => {\n disconnect();\n };\n }, [options.autoConnect]);\n\n return {\n connect,\n disconnect,\n connectionState,\n notifications: activeSessionId ? notifications[activeSessionId] || [] : [],\n clearNotifications,\n pendingPermission,\n resolvePermission,\n rejectPermission: rejectPermissionCallback,\n agent: agent,\n };\n}\n"]}
@@ -0,0 +1,3 @@
1
+ export declare function useEventCallback<Args extends unknown[], R>(fn: (...args: Args) => R): (...args: Args) => R;
2
+ export declare function useEventCallback<Args extends unknown[], R>(fn: ((...args: Args) => R) | undefined): ((...args: Args) => R) | undefined;
3
+ //# sourceMappingURL=use-event-callback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-event-callback.d.ts","sourceRoot":"","sources":["../../src/hooks/use-event-callback.ts"],"names":[],"mappings":"AAIA,wBAAgB,gBAAgB,CAAC,IAAI,SAAS,OAAO,EAAE,EAAE,CAAC,EACxD,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,CAAC,GACvB,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,CAAC,CAAC;AACxB,wBAAgB,gBAAgB,CAAC,IAAI,SAAS,OAAO,EAAE,EAAE,CAAC,EACxD,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,CAAC,CAAC,GAAG,SAAS,GACrC,CAAC,CAAC,GAAG,IAAI,EAAE,IAAI,KAAK,CAAC,CAAC,GAAG,SAAS,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { useCallback, useEffect, useLayoutEffect, useRef } from "react";
2
+ const useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
3
+ export function useEventCallback(fn) {
4
+ const ref = useRef(() => {
5
+ throw new Error("Cannot call an event handler while rendering.");
6
+ });
7
+ useIsomorphicLayoutEffect(() => {
8
+ ref.current = fn;
9
+ }, [fn]);
10
+ // biome-ignore lint/correctness/useExhaustiveDependencies: ref should not change
11
+ return useCallback((...args) => ref.current?.(...args), [ref]);
12
+ }
13
+ //# sourceMappingURL=use-event-callback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-event-callback.js","sourceRoot":"","sources":["../../src/hooks/use-event-callback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAExE,MAAM,yBAAyB,GAAG,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,SAAS,CAAC;AAQ9F,MAAM,UAAU,gBAAgB,CAC9B,EAAsC;IAEtC,MAAM,GAAG,GAAG,MAAM,CAAY,GAAG,EAAE;QACjC,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;IAEH,yBAAyB,CAAC,GAAG,EAAE;QAC7B,GAAG,CAAC,OAAO,GAAG,EAAE,CAAC;IACnB,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IAET,iFAAiF;IACjF,OAAO,WAAW,CAAC,CAAC,GAAG,IAAU,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,CAAyB,CAAC;AAC/F,CAAC","sourcesContent":["import { useCallback, useEffect, useLayoutEffect, useRef } from \"react\";\n\nconst useIsomorphicLayoutEffect = typeof window !== \"undefined\" ? useLayoutEffect : useEffect;\n\nexport function useEventCallback<Args extends unknown[], R>(\n fn: (...args: Args) => R,\n): (...args: Args) => R;\nexport function useEventCallback<Args extends unknown[], R>(\n fn: ((...args: Args) => R) | undefined,\n): ((...args: Args) => R) | undefined;\nexport function useEventCallback<Args extends unknown[], R>(\n fn: ((...args: Args) => R) | undefined,\n): ((...args: Args) => R) | undefined {\n const ref = useRef<typeof fn>(() => {\n throw new Error(\"Cannot call an event handler while rendering.\");\n });\n\n useIsomorphicLayoutEffect(() => {\n ref.current = fn;\n }, [fn]);\n\n // biome-ignore lint/correctness/useExhaustiveDependencies: ref should not change\n return useCallback((...args: Args) => ref.current?.(...args), [ref]) as (...args: Args) => R;\n}\n"]}
@@ -0,0 +1,4 @@
1
+ export * from "./hooks/use-acp-client.js";
2
+ export { useAcpStore } from "./state/atoms.js";
3
+ export { groupNotifications, mergeToolCalls, } from "./state/utils.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,kBAAkB,EAClB,cAAc,GACf,MAAM,kBAAkB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export * from "./hooks/use-acp-client.js";
2
+ export { useAcpStore } from "./state/atoms.js";
3
+ export { groupNotifications, mergeToolCalls, } from "./state/utils.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC;AAC1C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,kBAAkB,EAClB,cAAc,GACf,MAAM,kBAAkB,CAAC","sourcesContent":["export * from \"./hooks/use-acp-client.js\";\nexport { useAcpStore } from \"./state/atoms.js\";\nexport {\n groupNotifications,\n mergeToolCalls,\n} from \"./state/utils.js\";\n"]}
@@ -0,0 +1,14 @@
1
+ import type { ConnectionState, NotificationEvent, NotificationEventData } from "./types.js";
2
+ interface AcpState {
3
+ connectionState: ConnectionState;
4
+ activeSessionId: string | null;
5
+ notifications: Record<string, NotificationEvent[]>;
6
+ setConnectionState: (state: ConnectionState) => void;
7
+ setActiveSessionId: (sessionId: string | null) => void;
8
+ addNotification: (notification: NotificationEventData) => void;
9
+ clearNotifications: (sessionId?: string) => void;
10
+ getActiveNotifications: () => NotificationEvent[];
11
+ }
12
+ export declare const useAcpStore: import("zustand").UseBoundStore<import("zustand").StoreApi<AcpState>>;
13
+ export {};
14
+ //# sourceMappingURL=atoms.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atoms.d.ts","sourceRoot":"","sources":["../../src/state/atoms.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAE5F,UAAU,QAAQ;IAChB,eAAe,EAAE,eAAe,CAAC;IACjC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,EAAE,CAAC,CAAC;IACnD,kBAAkB,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IACrD,kBAAkB,EAAE,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvD,eAAe,EAAE,CAAC,YAAY,EAAE,qBAAqB,KAAK,IAAI,CAAC;IAC/D,kBAAkB,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,sBAAsB,EAAE,MAAM,iBAAiB,EAAE,CAAC;CACnD;AAED,eAAO,MAAM,WAAW,uEAkDrB,CAAC"}
@@ -0,0 +1,48 @@
1
+ import { create } from "zustand";
2
+ export const useAcpStore = create((set, get) => ({
3
+ connectionState: {
4
+ status: "disconnected",
5
+ },
6
+ activeSessionId: null,
7
+ notifications: {},
8
+ setConnectionState: (connectionState) => {
9
+ set({ connectionState });
10
+ },
11
+ setActiveSessionId: (sessionId) => {
12
+ set({ activeSessionId: sessionId });
13
+ },
14
+ addNotification: (notification) => {
15
+ const current = get().notifications;
16
+ const sessionId = get().activeSessionId;
17
+ if (!sessionId) {
18
+ return;
19
+ }
20
+ const newNotification = {
21
+ ...notification,
22
+ id: `${Date.now()}-${Math.random()}`,
23
+ timestamp: Date.now(),
24
+ };
25
+ const sessionNotifications = current[sessionId] || [];
26
+ const updated = {
27
+ ...current,
28
+ [sessionId]: [...sessionNotifications, newNotification],
29
+ };
30
+ set({ notifications: updated });
31
+ },
32
+ clearNotifications: (sessionId) => {
33
+ if (sessionId) {
34
+ const current = get().notifications;
35
+ const updated = { ...current };
36
+ delete updated[sessionId];
37
+ set({ notifications: updated });
38
+ }
39
+ else {
40
+ set({ notifications: {} });
41
+ }
42
+ },
43
+ getActiveNotifications: () => {
44
+ const { activeSessionId, notifications } = get();
45
+ return activeSessionId ? notifications[activeSessionId] || [] : [];
46
+ },
47
+ }));
48
+ //# sourceMappingURL=atoms.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atoms.js","sourceRoot":"","sources":["../../src/state/atoms.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAcjC,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAW,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IACzD,eAAe,EAAE;QACf,MAAM,EAAE,cAAc;KACvB;IACD,eAAe,EAAE,IAAI;IACrB,aAAa,EAAE,EAAE;IAEjB,kBAAkB,EAAE,CAAC,eAAgC,EAAE,EAAE;QACvD,GAAG,CAAC,EAAE,eAAe,EAAE,CAAC,CAAC;IAC3B,CAAC;IAED,kBAAkB,EAAE,CAAC,SAAwB,EAAE,EAAE;QAC/C,GAAG,CAAC,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,eAAe,EAAE,CAAC,YAAmC,EAAE,EAAE;QACvD,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,aAAa,CAAC;QACpC,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC,eAAe,CAAC;QACxC,IAAI,CAAC,SAAS,EAAE,CAAC;YACf,OAAO;QACT,CAAC;QACD,MAAM,eAAe,GAAsB;YACzC,GAAG,YAAY;YACf,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE;YACpC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACtB,CAAC;QAEF,MAAM,oBAAoB,GAAG,OAAO,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;QACtD,MAAM,OAAO,GAAG;YACd,GAAG,OAAO;YACV,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,oBAAoB,EAAE,eAAe,CAAC;SACxD,CAAC;QACF,GAAG,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,kBAAkB,EAAE,CAAC,SAAkB,EAAE,EAAE;QACzC,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,GAAG,EAAE,CAAC,aAAa,CAAC;YACpC,MAAM,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,CAAC;YAC/B,OAAO,OAAO,CAAC,SAAS,CAAC,CAAC;YAC1B,GAAG,CAAC,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,CAAC;QAClC,CAAC;aAAM,CAAC;YACN,GAAG,CAAC,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC;IAED,sBAAsB,EAAE,GAAG,EAAE;QAC3B,MAAM,EAAE,eAAe,EAAE,aAAa,EAAE,GAAG,GAAG,EAAE,CAAC;QACjD,OAAO,eAAe,CAAC,CAAC,CAAC,aAAa,CAAC,eAAe,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACrE,CAAC;CACF,CAAC,CAAC,CAAC","sourcesContent":["import { create } from \"zustand\";\nimport type { ConnectionState, NotificationEvent, NotificationEventData } from \"./types.js\";\n\ninterface AcpState {\n connectionState: ConnectionState;\n activeSessionId: string | null;\n notifications: Record<string, NotificationEvent[]>;\n setConnectionState: (state: ConnectionState) => void;\n setActiveSessionId: (sessionId: string | null) => void;\n addNotification: (notification: NotificationEventData) => void;\n clearNotifications: (sessionId?: string) => void;\n getActiveNotifications: () => NotificationEvent[];\n}\n\nexport const useAcpStore = create<AcpState>((set, get) => ({\n connectionState: {\n status: \"disconnected\",\n },\n activeSessionId: null,\n notifications: {},\n\n setConnectionState: (connectionState: ConnectionState) => {\n set({ connectionState });\n },\n\n setActiveSessionId: (sessionId: string | null) => {\n set({ activeSessionId: sessionId });\n },\n\n addNotification: (notification: NotificationEventData) => {\n const current = get().notifications;\n const sessionId = get().activeSessionId;\n if (!sessionId) {\n return;\n }\n const newNotification: NotificationEvent = {\n ...notification,\n id: `${Date.now()}-${Math.random()}`,\n timestamp: Date.now(),\n };\n\n const sessionNotifications = current[sessionId] || [];\n const updated = {\n ...current,\n [sessionId]: [...sessionNotifications, newNotification],\n };\n set({ notifications: updated });\n },\n\n clearNotifications: (sessionId?: string) => {\n if (sessionId) {\n const current = get().notifications;\n const updated = { ...current };\n delete updated[sessionId];\n set({ notifications: updated });\n } else {\n set({ notifications: {} });\n }\n },\n\n getActiveNotifications: () => {\n const { activeSessionId, notifications } = get();\n return activeSessionId ? notifications[activeSessionId] || [] : [];\n },\n}));\n"]}
@@ -0,0 +1,21 @@
1
+ import type { SessionNotification } from "@zed-industries/agent-client-protocol";
2
+ export interface ConnectionState {
3
+ status: "disconnected" | "connecting" | "connected" | "error";
4
+ error?: string;
5
+ url?: string;
6
+ }
7
+ export type NotificationEventData = {
8
+ type: "session_notification";
9
+ data: SessionNotification;
10
+ } | {
11
+ type: "connection_change";
12
+ data: ConnectionState;
13
+ } | {
14
+ type: "error";
15
+ data: Error;
16
+ };
17
+ export type NotificationEvent = {
18
+ id: string;
19
+ timestamp: number;
20
+ } & NotificationEventData;
21
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/state/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAEjF,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,CAAC;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,qBAAqB,GAC7B;IACE,IAAI,EAAE,sBAAsB,CAAC;IAC7B,IAAI,EAAE,mBAAmB,CAAC;CAC3B,GACD;IACE,IAAI,EAAE,mBAAmB,CAAC;IAC1B,IAAI,EAAE,eAAe,CAAC;CACvB,GACD;IACE,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,KAAK,CAAC;CACb,CAAC;AAEN,MAAM,MAAM,iBAAiB,GAAG;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,qBAAqB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/state/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { SessionNotification } from \"@zed-industries/agent-client-protocol\";\n\nexport interface ConnectionState {\n status: \"disconnected\" | \"connecting\" | \"connected\" | \"error\";\n error?: string;\n url?: string;\n}\n\nexport type NotificationEventData =\n | {\n type: \"session_notification\";\n data: SessionNotification;\n }\n | {\n type: \"connection_change\";\n data: ConnectionState;\n }\n | {\n type: \"error\";\n data: Error;\n };\n\nexport type NotificationEvent = {\n id: string;\n timestamp: number;\n} & NotificationEventData;\n"]}
@@ -0,0 +1,8 @@
1
+ import type { ToolCallUpdate } from "@zed-industries/agent-client-protocol";
2
+ import type { NotificationEvent } from "./types.js";
3
+ /**
4
+ * Group notifications by their type
5
+ */
6
+ export declare function groupNotifications(notifications: NotificationEvent[]): NotificationEvent[][];
7
+ export declare function mergeToolCalls(calls: ToolCallUpdate[]): ToolCallUpdate[];
8
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/state/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAG5E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAEpD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,iBAAiB,EAAE,GAAG,iBAAiB,EAAE,EAAE,CAW5F;AAmBD,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,EAAE,GAAG,cAAc,EAAE,CAoBxE"}
@@ -0,0 +1,53 @@
1
+ import { invariant } from "../utils/never.js";
2
+ /**
3
+ * Group notifications by their type
4
+ */
5
+ export function groupNotifications(notifications) {
6
+ const result = [];
7
+ for (const notification of notifications) {
8
+ const lastGroup = result[result.length - 1];
9
+ if (lastGroup && isSameType(lastGroup.at(0), notification)) {
10
+ lastGroup.push(notification);
11
+ }
12
+ else {
13
+ result.push([notification]);
14
+ }
15
+ }
16
+ return result;
17
+ }
18
+ const TOOL_TYPES = ["tool_call", "tool_call_update"];
19
+ function isSameType(a, b) {
20
+ if (!a)
21
+ return false;
22
+ if (a.type === "session_notification" && b.type === "session_notification") {
23
+ // Group tool calls together (may have multiple tool-ids)
24
+ if (TOOL_TYPES.includes(a.data.update.sessionUpdate) &&
25
+ TOOL_TYPES.includes(b.data.update.sessionUpdate)) {
26
+ return true;
27
+ }
28
+ return a.data.update.sessionUpdate === b.data.update.sessionUpdate;
29
+ }
30
+ return a.type === b.type;
31
+ }
32
+ export function mergeToolCalls(calls) {
33
+ const map = new Map();
34
+ for (const call of calls) {
35
+ if (!map.has(call.toolCallId)) {
36
+ map.set(call.toolCallId, []);
37
+ }
38
+ map.get(call.toolCallId)?.push(call);
39
+ }
40
+ return Array.from(map.values()).map((calls) => {
41
+ const first = calls.at(0);
42
+ invariant(!!first?.toolCallId, "Tool call ID is required");
43
+ return {
44
+ ...first,
45
+ toolCallId: first.toolCallId,
46
+ status: calls.at(-1)?.status,
47
+ rawOutput: Object.assign({}, ...calls.map((call) => call.rawOutput)),
48
+ locations: calls.flatMap((call) => call.locations || []),
49
+ content: calls.flatMap((call) => call.content || []),
50
+ };
51
+ });
52
+ }
53
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/state/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ToolCallUpdate } from \"@zed-industries/agent-client-protocol\";\nimport type { SessionUpdate } from \"../client/types.js\";\nimport { invariant } from \"../utils/never.js\";\nimport type { NotificationEvent } from \"./types.js\";\n\n/**\n * Group notifications by their type\n */\nexport function groupNotifications(notifications: NotificationEvent[]): NotificationEvent[][] {\n const result: NotificationEvent[][] = [];\n for (const notification of notifications) {\n const lastGroup = result[result.length - 1];\n if (lastGroup && isSameType(lastGroup.at(0), notification)) {\n lastGroup.push(notification);\n } else {\n result.push([notification]);\n }\n }\n return result;\n}\n\nconst TOOL_TYPES: SessionUpdate[\"sessionUpdate\"][] = [\"tool_call\", \"tool_call_update\"];\n\nfunction isSameType(a: NotificationEvent | undefined, b: NotificationEvent): boolean {\n if (!a) return false;\n if (a.type === \"session_notification\" && b.type === \"session_notification\") {\n // Group tool calls together (may have multiple tool-ids)\n if (\n TOOL_TYPES.includes(a.data.update.sessionUpdate) &&\n TOOL_TYPES.includes(b.data.update.sessionUpdate)\n ) {\n return true;\n }\n return a.data.update.sessionUpdate === b.data.update.sessionUpdate;\n }\n return a.type === b.type;\n}\n\nexport function mergeToolCalls(calls: ToolCallUpdate[]): ToolCallUpdate[] {\n const map = new Map<string, ToolCallUpdate[]>();\n for (const call of calls) {\n if (!map.has(call.toolCallId)) {\n map.set(call.toolCallId, []);\n }\n map.get(call.toolCallId)?.push(call);\n }\n return Array.from(map.values()).map((calls) => {\n const first = calls.at(0);\n invariant(!!first?.toolCallId, \"Tool call ID is required\");\n return {\n ...first,\n toolCallId: first.toolCallId,\n status: calls.at(-1)?.status,\n rawOutput: Object.assign({}, ...calls.map((call) => call.rawOutput)),\n locations: calls.flatMap((call) => call.locations || []),\n content: calls.flatMap((call) => call.content || []),\n } satisfies ToolCallUpdate;\n });\n}\n"]}
@@ -0,0 +1,7 @@
1
+ export declare class Deferred<T> {
2
+ promise: Promise<T>;
3
+ resolve: (value: T) => void;
4
+ reject: (error: Error) => void;
5
+ constructor();
6
+ }
7
+ //# sourceMappingURL=deferred.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deferred.d.ts","sourceRoot":"","sources":["../../src/utils/deferred.ts"],"names":[],"mappings":"AAAA,qBAAa,QAAQ,CAAC,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACpB,OAAO,EAAG,CAAC,KAAK,EAAE,CAAC,KAAK,IAAI,CAAC;IAC7B,MAAM,EAAG,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;;CAQjC"}
@@ -0,0 +1,12 @@
1
+ export class Deferred {
2
+ promise;
3
+ resolve;
4
+ reject;
5
+ constructor() {
6
+ this.promise = new Promise((resolve, reject) => {
7
+ this.resolve = resolve;
8
+ this.reject = reject;
9
+ });
10
+ }
11
+ }
12
+ //# sourceMappingURL=deferred.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deferred.js","sourceRoot":"","sources":["../../src/utils/deferred.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAQ;IACnB,OAAO,CAAa;IACpB,OAAO,CAAsB;IAC7B,MAAM,CAA0B;IAEhC;QACE,IAAI,CAAC,OAAO,GAAG,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC7C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;YACvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACvB,CAAC,CAAC,CAAC;IACL,CAAC;CACF","sourcesContent":["export class Deferred<T> {\n promise: Promise<T>;\n resolve!: (value: T) => void;\n reject!: (error: Error) => void;\n\n constructor() {\n this.promise = new Promise((resolve, reject) => {\n this.resolve = resolve;\n this.reject = reject;\n });\n }\n}\n"]}