@nexus-code/remote-protocol 0.1.0 → 0.3.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 +5 -1
- package/dist/rpc.d.ts +5164 -229
- package/dist/rpc.d.ts.map +1 -1
- package/dist/rpc.js +723 -11
- package/dist/rpc.js.map +1 -1
- package/dist/sealed.d.ts +37 -5
- package/dist/sealed.d.ts.map +1 -1
- package/dist/sealed.js +37 -5
- package/dist/sealed.js.map +1 -1
- package/dist/view.d.ts +440 -0
- package/dist/view.d.ts.map +1 -1
- package/dist/view.js +73 -0
- package/dist/view.js.map +1 -1
- package/package.json +1 -1
- package/src/rpc.ts +766 -10
- package/src/sealed.ts +38 -5
- package/src/view.ts +83 -0
package/src/rpc.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { z } from "zod";
|
|
10
10
|
import {
|
|
11
11
|
AssistantItemSchema,
|
|
12
|
+
ChatPanelSchema,
|
|
12
13
|
ChatStatusSchema,
|
|
13
14
|
ViewItemSchema,
|
|
14
15
|
ViewTaskSchema,
|
|
@@ -83,6 +84,22 @@ export const RemoteWorkspaceSchema = z.object({
|
|
|
83
84
|
name: z.string(),
|
|
84
85
|
/** Its folder, on the serving device. */
|
|
85
86
|
path: z.string(),
|
|
87
|
+
/** A task: a workspace on a git worktree of the workspace `parentId`, on its own branch. */
|
|
88
|
+
parentId: z.string().optional(),
|
|
89
|
+
/** The agent manager's own workspace, where the session that directs the others runs. */
|
|
90
|
+
manager: z.boolean().optional(),
|
|
91
|
+
/**
|
|
92
|
+
* A task's branch and how it stands against its upstream, with how many
|
|
93
|
+
* files it changed and did not commit. Looked at now and then, not live.
|
|
94
|
+
*/
|
|
95
|
+
git: z
|
|
96
|
+
.object({
|
|
97
|
+
branch: z.string().nullable(),
|
|
98
|
+
ahead: z.number().int().nonnegative(),
|
|
99
|
+
behind: z.number().int().nonnegative(),
|
|
100
|
+
uncommitted: z.number().int().nonnegative(),
|
|
101
|
+
})
|
|
102
|
+
.optional(),
|
|
86
103
|
});
|
|
87
104
|
export type RemoteWorkspace = z.infer<typeof RemoteWorkspaceSchema>;
|
|
88
105
|
|
|
@@ -108,19 +125,275 @@ export const RemoteSessionSchema = z.object({
|
|
|
108
125
|
.object({
|
|
109
126
|
kind: z.enum(["permission", "question", "plan"]),
|
|
110
127
|
text: z.string(),
|
|
128
|
+
/** A terminal's Claude Code asking: the request terminal.answer answers. */
|
|
129
|
+
requestId: z.string().optional(),
|
|
111
130
|
})
|
|
112
131
|
.optional(),
|
|
113
132
|
});
|
|
114
133
|
export type RemoteSession = z.infer<typeof RemoteSessionSchema>;
|
|
115
134
|
|
|
135
|
+
/** How the user answers a consent prompt: this once, until the serving app restarts, or no. */
|
|
136
|
+
export const ConsentAnswerSchema = z.enum(["once", "session", "deny"]);
|
|
137
|
+
export type ConsentAnswer = z.infer<typeof ConsentAnswerSchema>;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* A change an agent asks to make that waits on the user's consent on the
|
|
141
|
+
* serving device: an agent of another device of the account, a nexus
|
|
142
|
+
* command changing another workspace there, or its agent manager. The user
|
|
143
|
+
* may answer it there or, when `answerable`, from the device that lists it
|
|
144
|
+
* (consent.answer); unanswered by `expiresAt`, it counts as turned down.
|
|
145
|
+
*/
|
|
146
|
+
export const RemoteConsentSchema = z.object({
|
|
147
|
+
id: z.string(),
|
|
148
|
+
/** When it was asked, by the serving device's clock (Unix ms). */
|
|
149
|
+
at: z.number(),
|
|
150
|
+
/** When it counts as turned down, by the serving device's clock. */
|
|
151
|
+
expiresAt: z.number(),
|
|
152
|
+
/** How long it has left as the list is sent: a countdown that needs no clock in common. */
|
|
153
|
+
expiresInMs: z.number().int().nonnegative(),
|
|
154
|
+
/** Who asks. */
|
|
155
|
+
from: z.object({
|
|
156
|
+
/** An agent of another device of the account; absent: one of the serving device's own. */
|
|
157
|
+
device: z.object({ id: z.string(), name: z.string() }).optional(),
|
|
158
|
+
/** The serving device's agent manager asks. */
|
|
159
|
+
manager: z.boolean().optional(),
|
|
160
|
+
workspaceId: z.string(),
|
|
161
|
+
/** The asking workspace's name, when it is one of the serving device's. */
|
|
162
|
+
workspaceName: z.string().optional(),
|
|
163
|
+
tabId: z.string(),
|
|
164
|
+
/** The asking tab's title. */
|
|
165
|
+
name: z.string().optional(),
|
|
166
|
+
}),
|
|
167
|
+
/** The serving device's workspace it would change. */
|
|
168
|
+
workspaceId: z.string(),
|
|
169
|
+
/**
|
|
170
|
+
* What it would do: `kind` as the serving device names it (chatInput,
|
|
171
|
+
* terminalInput, tabClose, permissionAllow, ...; new ones may come), a
|
|
172
|
+
* line on what to, and the whole of it when a line does not tell it (a
|
|
173
|
+
* command to allow).
|
|
174
|
+
*/
|
|
175
|
+
change: z.object({
|
|
176
|
+
kind: z.string(),
|
|
177
|
+
detail: z.string().optional(),
|
|
178
|
+
body: z.string().optional(),
|
|
179
|
+
}),
|
|
180
|
+
/** It is asked about each time: "session" is not an answer to it. */
|
|
181
|
+
eachTime: z.boolean(),
|
|
182
|
+
/**
|
|
183
|
+
* Whether the device the list goes to may answer it: one that serves it
|
|
184
|
+
* chat.control, and terminal.control too for a change to a terminal; never
|
|
185
|
+
* the device whose agent asks.
|
|
186
|
+
*/
|
|
187
|
+
answerable: z.boolean(),
|
|
188
|
+
});
|
|
189
|
+
export type RemoteConsent = z.infer<typeof RemoteConsentSchema>;
|
|
190
|
+
|
|
116
191
|
const SessionsSchema = z.object({
|
|
117
192
|
workspaces: z.array(RemoteWorkspaceSchema),
|
|
118
193
|
sessions: z.array(RemoteSessionSchema),
|
|
194
|
+
/** The consent prompts waiting on the user, in the order they are asked; absent before 0.3.0. */
|
|
195
|
+
consents: z.array(RemoteConsentSchema).optional(),
|
|
119
196
|
});
|
|
120
197
|
|
|
121
198
|
/** A session of the serving device, by its ids there. */
|
|
122
199
|
const TabRef = { workspaceId: z.string(), tabId: z.string() };
|
|
123
200
|
|
|
201
|
+
/**
|
|
202
|
+
* The agent that sends a request, when an agent does (nexus chat send on
|
|
203
|
+
* another device): its own tab there, which the receiving chat shows as
|
|
204
|
+
* the reply address. The device is the frame's sender. A control method
|
|
205
|
+
* with `from` takes the `agents` capability, not its own, and the serving
|
|
206
|
+
* device may ask its user first (AGENT_CONSENT_MS) or turn it down.
|
|
207
|
+
*/
|
|
208
|
+
export const AgentSenderSchema = z.object({
|
|
209
|
+
/** tab: a Claude or Codex tab; terminal: an agent in a terminal; manager: the agent manager. */
|
|
210
|
+
kind: z.enum(["tab", "terminal", "manager"]),
|
|
211
|
+
agent: z.string().min(1).max(40).optional(),
|
|
212
|
+
workspaceId: z.string(),
|
|
213
|
+
tabId: z.string(),
|
|
214
|
+
/** Its tab's title, as the receiver shows the sender. */
|
|
215
|
+
name: z.string().max(200).optional(),
|
|
216
|
+
/**
|
|
217
|
+
* How many messages between agents led to this one, the first being 1:
|
|
218
|
+
* a device refuses one past MAX_AGENT_HOPS, so agents on two devices
|
|
219
|
+
* cannot keep each other going without end.
|
|
220
|
+
*/
|
|
221
|
+
hops: z.number().int().positive(),
|
|
222
|
+
});
|
|
223
|
+
export type AgentSender = z.infer<typeof AgentSenderSchema>;
|
|
224
|
+
|
|
225
|
+
/** The keys terminal.input presses by name, as `nexus terminal key` names them. */
|
|
226
|
+
export const TERMINAL_KEYS = [
|
|
227
|
+
"enter",
|
|
228
|
+
"tab",
|
|
229
|
+
"shift-tab",
|
|
230
|
+
"esc",
|
|
231
|
+
"space",
|
|
232
|
+
"backspace",
|
|
233
|
+
"delete",
|
|
234
|
+
"up",
|
|
235
|
+
"down",
|
|
236
|
+
"left",
|
|
237
|
+
"right",
|
|
238
|
+
"home",
|
|
239
|
+
"end",
|
|
240
|
+
"pageup",
|
|
241
|
+
"pagedown",
|
|
242
|
+
"ctrl-a",
|
|
243
|
+
"ctrl-b",
|
|
244
|
+
"ctrl-c",
|
|
245
|
+
"ctrl-d",
|
|
246
|
+
"ctrl-e",
|
|
247
|
+
"ctrl-f",
|
|
248
|
+
"ctrl-g",
|
|
249
|
+
"ctrl-h",
|
|
250
|
+
"ctrl-i",
|
|
251
|
+
"ctrl-j",
|
|
252
|
+
"ctrl-k",
|
|
253
|
+
"ctrl-l",
|
|
254
|
+
"ctrl-m",
|
|
255
|
+
"ctrl-n",
|
|
256
|
+
"ctrl-o",
|
|
257
|
+
"ctrl-p",
|
|
258
|
+
"ctrl-q",
|
|
259
|
+
"ctrl-r",
|
|
260
|
+
"ctrl-s",
|
|
261
|
+
"ctrl-t",
|
|
262
|
+
"ctrl-u",
|
|
263
|
+
"ctrl-v",
|
|
264
|
+
"ctrl-w",
|
|
265
|
+
"ctrl-x",
|
|
266
|
+
"ctrl-y",
|
|
267
|
+
"ctrl-z",
|
|
268
|
+
] as const;
|
|
269
|
+
export const TerminalKeySchema = z.enum(TERMINAL_KEYS);
|
|
270
|
+
export type TerminalKey = z.infer<typeof TerminalKeySchema>;
|
|
271
|
+
|
|
272
|
+
/** Most messages between agents one chain may take; past it, `from` requests are refused. */
|
|
273
|
+
export const MAX_AGENT_HOPS = 8;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* How long a serving device may ask its user about a request with `from`
|
|
277
|
+
* before it turns it down: a requester waits this long, and a little more.
|
|
278
|
+
*/
|
|
279
|
+
export const AGENT_CONSENT_MS = 90_000;
|
|
280
|
+
|
|
281
|
+
/** Most requests with `from` one agent (a device's tab) may make a minute; more are Unavailable. */
|
|
282
|
+
export const MAX_AGENT_REQUESTS_PER_MINUTE = 20;
|
|
283
|
+
|
|
284
|
+
/** Longest a chat.wait or terminal.wait holds before it answers that the session is not done yet. */
|
|
285
|
+
export const MAX_WAIT_MS = 10_000;
|
|
286
|
+
|
|
287
|
+
/** Where a chat stands for one that waits on it, as `nexus chat wait` tells it. */
|
|
288
|
+
export const ChatWaitStateSchema = z.enum(["working", "asking", "idle", "error", "closed"]);
|
|
289
|
+
|
|
290
|
+
/** A session state change, as `nexus events` lists them. */
|
|
291
|
+
export const SessionEventSchema = z.object({
|
|
292
|
+
/** Counts the device's events from 1 since its app started. */
|
|
293
|
+
seq: z.number().int().positive(),
|
|
294
|
+
at: z.number(),
|
|
295
|
+
workspaceId: z.string(),
|
|
296
|
+
tabId: z.string(),
|
|
297
|
+
title: z.string(),
|
|
298
|
+
kind: z.enum(["terminal", "claude", "codex"]),
|
|
299
|
+
agent: z.string().optional(),
|
|
300
|
+
/** The phase it left (null: first seen) and the one it came to ("closed" when the tab went). */
|
|
301
|
+
from: z.string().nullable(),
|
|
302
|
+
to: z.string(),
|
|
303
|
+
message: z.string().optional(),
|
|
304
|
+
});
|
|
305
|
+
export type SessionEvent = z.infer<typeof SessionEventSchema>;
|
|
306
|
+
|
|
307
|
+
/** Most images one message takes. */
|
|
308
|
+
export const MAX_ATTACHMENTS = 4;
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Most bytes one image chat.attach takes, before base64: its base64 and the
|
|
312
|
+
* request around it stay inside a frame (MAX_FRAME_BYTES, sealed).
|
|
313
|
+
*/
|
|
314
|
+
export const MAX_ATTACHMENT_BYTES = 560 * 1024;
|
|
315
|
+
|
|
316
|
+
/** The image types a chat takes. */
|
|
317
|
+
export const ImageMediaTypeSchema = z.enum(["image/png", "image/jpeg", "image/gif", "image/webp"]);
|
|
318
|
+
|
|
319
|
+
/** What a chat runs with, and what it may be set to. */
|
|
320
|
+
export const ChatSettingsSchema = z.object({
|
|
321
|
+
agent: z.enum(["claude", "codex"]),
|
|
322
|
+
/** The model it runs, by the id to give back; null before the program says. */
|
|
323
|
+
model: z.string().nullable(),
|
|
324
|
+
effort: z.string().nullable(),
|
|
325
|
+
permissionMode: z.string(),
|
|
326
|
+
options: z.object({
|
|
327
|
+
models: z.array(z.object({ id: z.string(), label: z.string() })),
|
|
328
|
+
/** The effort levels its model takes; none when it takes none. */
|
|
329
|
+
efforts: z.array(z.string()),
|
|
330
|
+
/** The permission modes; `dangerous` ones ask the serving device's policy first. */
|
|
331
|
+
modes: z.array(
|
|
332
|
+
z.object({ id: z.string(), label: z.string(), dangerous: z.boolean().optional() }),
|
|
333
|
+
),
|
|
334
|
+
}),
|
|
335
|
+
});
|
|
336
|
+
export type ChatSettings = z.infer<typeof ChatSettingsSchema>;
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* A slash command of a chat, for a "/" picker: the app's own (run with
|
|
340
|
+
* chat.command), the agent's own (sent as a message: chat.send "/name
|
|
341
|
+
* args"), or one that sets what chat.configure sets.
|
|
342
|
+
*/
|
|
343
|
+
export const ChatCommandSchema = z.object({
|
|
344
|
+
name: z.string(),
|
|
345
|
+
description: z.string(),
|
|
346
|
+
/** command: chat.command; send: chat.send its text; settings: chat.configure. */
|
|
347
|
+
runs: z.enum(["command", "send", "settings"]),
|
|
348
|
+
/** With runs "settings": what it sets, so the picker for it opens. */
|
|
349
|
+
sets: z.enum(["model", "effort", "permissionMode"]).optional(),
|
|
350
|
+
/** What it takes after its name, as its help writes it ("<condition>"). */
|
|
351
|
+
args: z.string().optional(),
|
|
352
|
+
});
|
|
353
|
+
export type ChatCommand = z.infer<typeof ChatCommandSchema>;
|
|
354
|
+
|
|
355
|
+
/** A chat of the past that can be resumed: Claude Code's sessions, Codex's threads. */
|
|
356
|
+
export const PastSessionSchema = z.object({
|
|
357
|
+
sessionId: z.string(),
|
|
358
|
+
title: z.string(),
|
|
359
|
+
/** When it last changed, in Unix milliseconds. */
|
|
360
|
+
at: z.number(),
|
|
361
|
+
/** Its log's size in bytes, when known. */
|
|
362
|
+
bytes: z.number().int().nonnegative().optional(),
|
|
363
|
+
/** The folder it ran in. */
|
|
364
|
+
cwd: z.string().optional(),
|
|
365
|
+
profile: z.string().optional(),
|
|
366
|
+
});
|
|
367
|
+
export type PastSession = z.infer<typeof PastSessionSchema>;
|
|
368
|
+
|
|
369
|
+
/** A file's state in git: a letter as `git status --porcelain` gives it (M, A, D, R, C, U, ?). */
|
|
370
|
+
const GitLetter = z.string().length(1);
|
|
371
|
+
|
|
372
|
+
/** A file git sees changed, staged or not. */
|
|
373
|
+
export const GitFileSchema = z.object({
|
|
374
|
+
path: z.string(),
|
|
375
|
+
/** Renamed or copied from. */
|
|
376
|
+
oldPath: z.string().optional(),
|
|
377
|
+
staged: GitLetter.optional(),
|
|
378
|
+
unstaged: GitLetter.optional(),
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
/** A piece of a diff, as jsdiff's structuredPatch gives it: lines starting " ", "-" or "+". */
|
|
382
|
+
export const DiffHunkSchema = z.object({
|
|
383
|
+
oldStart: z.number().int().nonnegative(),
|
|
384
|
+
oldLines: z.number().int().nonnegative(),
|
|
385
|
+
newStart: z.number().int().nonnegative(),
|
|
386
|
+
newLines: z.number().int().nonnegative(),
|
|
387
|
+
lines: z.array(z.string()),
|
|
388
|
+
});
|
|
389
|
+
export type DiffHunk = z.infer<typeof DiffHunkSchema>;
|
|
390
|
+
|
|
391
|
+
/** Most entries one files.list gives. */
|
|
392
|
+
export const MAX_LIST_ENTRIES = 2000;
|
|
393
|
+
|
|
394
|
+
/** Most bytes of text one files.read gives. */
|
|
395
|
+
export const MAX_READ_BYTES = 512 * 1024;
|
|
396
|
+
|
|
124
397
|
// ---------------------------------------------------------------------------
|
|
125
398
|
// Chats
|
|
126
399
|
// ---------------------------------------------------------------------------
|
|
@@ -158,9 +431,26 @@ export const ChatUpdateSchema = z.object({
|
|
|
158
431
|
tools: z.record(ViewToolCallSchema),
|
|
159
432
|
tasks: z.record(ViewTaskSchema),
|
|
160
433
|
agentItems: z.record(z.array(AssistantItemSchema)),
|
|
434
|
+
/** The side panel, when it changed. */
|
|
435
|
+
panel: ChatPanelSchema.optional(),
|
|
161
436
|
});
|
|
162
437
|
export type ChatUpdate = z.infer<typeof ChatUpdateSchema>;
|
|
163
438
|
|
|
439
|
+
/**
|
|
440
|
+
* A watched terminal's text changed: the text from `start` (a UTF-16
|
|
441
|
+
* offset into the text as it was) is now `text`. A redraw at the bottom
|
|
442
|
+
* sends only the bottom; a scroll, all of it from 0. A watch with `ansi`
|
|
443
|
+
* counts in the text with its escapes.
|
|
444
|
+
*/
|
|
445
|
+
export const TerminalUpdateSchema = z.object({
|
|
446
|
+
watchId: z.string(),
|
|
447
|
+
/** Counts the watch's updates from 1, so one lost shows. */
|
|
448
|
+
rev: z.number().int().positive(),
|
|
449
|
+
start: z.number().int().nonnegative(),
|
|
450
|
+
text: z.string(),
|
|
451
|
+
});
|
|
452
|
+
export type TerminalUpdate = z.infer<typeof TerminalUpdateSchema>;
|
|
453
|
+
|
|
164
454
|
/** The sessions' list as it is now, sent whenever it changes during a sessions.watch. */
|
|
165
455
|
export const SessionsUpdateSchema = SessionsSchema.extend({ watchId: z.string() });
|
|
166
456
|
export type SessionsUpdate = z.infer<typeof SessionsUpdateSchema>;
|
|
@@ -188,6 +478,51 @@ export const RPC_METHODS = {
|
|
|
188
478
|
params: z.object({ watchId: z.string() }),
|
|
189
479
|
result: Ok,
|
|
190
480
|
},
|
|
481
|
+
/**
|
|
482
|
+
* The session state changes after `since` (the first `limit`, `more` when
|
|
483
|
+
* some were left out), or the last `limit`; `cursor` is the latest seq. A
|
|
484
|
+
* `since` past it (from before the app restarted) reads from the start.
|
|
485
|
+
*/
|
|
486
|
+
"events.read": {
|
|
487
|
+
capability: "sessions",
|
|
488
|
+
params: z.object({
|
|
489
|
+
since: z.number().int().nonnegative().optional(),
|
|
490
|
+
limit: z.number().int().positive().max(500).optional(),
|
|
491
|
+
}),
|
|
492
|
+
result: z.object({
|
|
493
|
+
events: z.array(SessionEventSchema),
|
|
494
|
+
cursor: z.number().int().nonnegative(),
|
|
495
|
+
more: z.boolean(),
|
|
496
|
+
}),
|
|
497
|
+
},
|
|
498
|
+
/** The agent profiles a chat can run with (accounts, config folders). */
|
|
499
|
+
"profiles.list": {
|
|
500
|
+
capability: "sessions",
|
|
501
|
+
params: z.object({ agent: z.enum(["claude", "codex"]).optional() }),
|
|
502
|
+
result: z.object({
|
|
503
|
+
profiles: z.array(
|
|
504
|
+
z.object({
|
|
505
|
+
id: z.string(),
|
|
506
|
+
name: z.string(),
|
|
507
|
+
agent: z.enum(["claude", "codex"]),
|
|
508
|
+
/** The one a workspace runs with unless told otherwise. */
|
|
509
|
+
isDefault: z.boolean(),
|
|
510
|
+
}),
|
|
511
|
+
),
|
|
512
|
+
}),
|
|
513
|
+
},
|
|
514
|
+
/** The past chats of a workspace's folder that can be resumed, latest first. */
|
|
515
|
+
"history.list": {
|
|
516
|
+
capability: "chat.read",
|
|
517
|
+
params: z.object({
|
|
518
|
+
workspaceId: z.string(),
|
|
519
|
+
agent: z.enum(["claude", "codex"]),
|
|
520
|
+
/** Only those whose title has it. */
|
|
521
|
+
query: z.string().max(200).optional(),
|
|
522
|
+
limit: z.number().int().positive().max(200).optional(),
|
|
523
|
+
}),
|
|
524
|
+
result: z.object({ sessions: z.array(PastSessionSchema) }),
|
|
525
|
+
},
|
|
191
526
|
|
|
192
527
|
/** The chat's last `limit` items, or those before `before`. */
|
|
193
528
|
"chat.read": {
|
|
@@ -206,19 +541,120 @@ export const RPC_METHODS = {
|
|
|
206
541
|
...TabRef,
|
|
207
542
|
limit: z.number().int().positive().max(MAX_READ_ITEMS).optional(),
|
|
208
543
|
}),
|
|
209
|
-
result: ChatPageSchema.extend({ watchId: z.string() }),
|
|
544
|
+
result: ChatPageSchema.extend({ watchId: z.string(), panel: ChatPanelSchema.optional() }),
|
|
210
545
|
},
|
|
211
546
|
"chat.unwatch": {
|
|
212
547
|
capability: "chat.read",
|
|
213
548
|
params: z.object({ watchId: z.string() }),
|
|
214
549
|
result: Ok,
|
|
215
550
|
},
|
|
551
|
+
/** What the chat runs with and may be set to (model, effort, permission mode). */
|
|
552
|
+
"chat.settings": {
|
|
553
|
+
capability: "chat.read",
|
|
554
|
+
params: z.object(TabRef),
|
|
555
|
+
result: ChatSettingsSchema,
|
|
556
|
+
},
|
|
557
|
+
/** Its slash commands, the app's and the agent's, for a "/" picker. */
|
|
558
|
+
"chat.commands": {
|
|
559
|
+
capability: "chat.read",
|
|
560
|
+
params: z.object(TabRef),
|
|
561
|
+
result: z.object({ commands: z.array(ChatCommandSchema) }),
|
|
562
|
+
},
|
|
563
|
+
/** Its side panel now; a watch sends it again in chat.update as it changes. */
|
|
564
|
+
"chat.panel": {
|
|
565
|
+
capability: "chat.read",
|
|
566
|
+
params: z.object(TabRef),
|
|
567
|
+
result: ChatPanelSchema,
|
|
568
|
+
},
|
|
569
|
+
/** One tool call with as much of its result as a frame takes. */
|
|
570
|
+
"chat.tool": {
|
|
571
|
+
capability: "chat.read",
|
|
572
|
+
params: z.object({ ...TabRef, toolUseId: z.string() }),
|
|
573
|
+
result: ViewToolCallSchema,
|
|
574
|
+
},
|
|
575
|
+
/**
|
|
576
|
+
* Waits up to `timeoutMs` (at most MAX_WAIT_MS) for the chat to be done
|
|
577
|
+
* with its turn: no longer working (asking, idle, error, or closed). Ask
|
|
578
|
+
* again while `done` is false. `after`: a chat.send's `at`, so a message
|
|
579
|
+
* the chat has not shown yet counts as working.
|
|
580
|
+
*/
|
|
581
|
+
"chat.wait": {
|
|
582
|
+
capability: "chat.read",
|
|
583
|
+
params: z.object({
|
|
584
|
+
...TabRef,
|
|
585
|
+
timeoutMs: z.number().int().positive().max(MAX_WAIT_MS).optional(),
|
|
586
|
+
after: z.number().optional(),
|
|
587
|
+
}),
|
|
588
|
+
result: z.object({
|
|
589
|
+
done: z.boolean(),
|
|
590
|
+
state: ChatWaitStateSchema,
|
|
591
|
+
/** Its last answer; when asking, what it asks; on an error, what went wrong. */
|
|
592
|
+
message: z.string().optional(),
|
|
593
|
+
}),
|
|
594
|
+
},
|
|
595
|
+
/**
|
|
596
|
+
* An image of the chat, made small enough for a frame: a user message's
|
|
597
|
+
* (by its item's key and the image's index) or a tool result's.
|
|
598
|
+
*/
|
|
599
|
+
"chat.image": {
|
|
600
|
+
capability: "chat.read",
|
|
601
|
+
params: z.object({
|
|
602
|
+
...TabRef,
|
|
603
|
+
ref: z.discriminatedUnion("kind", [
|
|
604
|
+
z.object({
|
|
605
|
+
kind: z.literal("user"),
|
|
606
|
+
itemKey: z.string(),
|
|
607
|
+
index: z.number().int().nonnegative(),
|
|
608
|
+
}),
|
|
609
|
+
z.object({
|
|
610
|
+
kind: z.literal("tool"),
|
|
611
|
+
toolUseId: z.string(),
|
|
612
|
+
index: z.number().int().nonnegative(),
|
|
613
|
+
}),
|
|
614
|
+
]),
|
|
615
|
+
}),
|
|
616
|
+
result: z.object({
|
|
617
|
+
mediaType: ImageMediaTypeSchema,
|
|
618
|
+
/** Base64. */
|
|
619
|
+
data: z.string(),
|
|
620
|
+
width: z.number().int().positive().optional(),
|
|
621
|
+
height: z.number().int().positive().optional(),
|
|
622
|
+
}),
|
|
623
|
+
},
|
|
216
624
|
|
|
217
|
-
/**
|
|
625
|
+
/**
|
|
626
|
+
* Sends a message, as its composer does: during a turn, the turn reads it
|
|
627
|
+
* next. `text` may be empty only with attachments. Sent by an agent
|
|
628
|
+
* (`from`), the chat shows it as that agent's, not the user's.
|
|
629
|
+
*/
|
|
218
630
|
"chat.send": {
|
|
219
631
|
capability: "chat.control",
|
|
220
|
-
params: z.object({
|
|
221
|
-
|
|
632
|
+
params: z.object({
|
|
633
|
+
...TabRef,
|
|
634
|
+
text: z.string(),
|
|
635
|
+
/** Images chat.attach took, at most MAX_ATTACHMENTS. */
|
|
636
|
+
attachments: z.array(z.string()).max(MAX_ATTACHMENTS).optional(),
|
|
637
|
+
from: AgentSenderSchema.optional(),
|
|
638
|
+
}),
|
|
639
|
+
/** `at`: when the serving device took it, by its clock, for chat.wait's `after`. */
|
|
640
|
+
result: z.object({ at: z.number().optional() }),
|
|
641
|
+
},
|
|
642
|
+
/**
|
|
643
|
+
* Takes an image for the next chat.send to this tab: one image a request,
|
|
644
|
+
* small enough for a frame. Kept 10 minutes, for this device only.
|
|
645
|
+
*/
|
|
646
|
+
"chat.attach": {
|
|
647
|
+
capability: "chat.control",
|
|
648
|
+
params: z.object({
|
|
649
|
+
...TabRef,
|
|
650
|
+
mediaType: ImageMediaTypeSchema,
|
|
651
|
+
/** Base64, of at most MAX_ATTACHMENT_BYTES bytes. */
|
|
652
|
+
data: z
|
|
653
|
+
.string()
|
|
654
|
+
.min(1)
|
|
655
|
+
.max(Math.ceil(MAX_ATTACHMENT_BYTES / 3) * 4),
|
|
656
|
+
}),
|
|
657
|
+
result: z.object({ attachmentId: z.string() }),
|
|
222
658
|
},
|
|
223
659
|
/** Answers the permission request `requestId`, as its card's buttons do. */
|
|
224
660
|
"chat.answer": {
|
|
@@ -233,28 +669,347 @@ export const RPC_METHODS = {
|
|
|
233
669
|
updatedInput: z.record(z.unknown()).optional(),
|
|
234
670
|
/** With deny: the turn stops too, as the card's "No, and stop" does. */
|
|
235
671
|
stop: z.boolean().optional(),
|
|
672
|
+
/** With allow: the request's suggestions to keep from now on, by index ("always allow"). */
|
|
673
|
+
always: z.array(z.number().int().nonnegative()).optional(),
|
|
674
|
+
from: AgentSenderSchema.optional(),
|
|
675
|
+
}),
|
|
676
|
+
result: Ok,
|
|
677
|
+
},
|
|
678
|
+
"chat.interrupt": {
|
|
679
|
+
capability: "chat.control",
|
|
680
|
+
params: z.object({ ...TabRef, from: AgentSenderSchema.optional() }),
|
|
681
|
+
result: Ok,
|
|
682
|
+
},
|
|
683
|
+
/**
|
|
684
|
+
* Sets any of model, effort and permission mode, as the composer's chips
|
|
685
|
+
* do; what it runs with after. A mode the serving device's policy does
|
|
686
|
+
* not allow is refused (Forbidden) with why.
|
|
687
|
+
*/
|
|
688
|
+
"chat.configure": {
|
|
689
|
+
capability: "chat.control",
|
|
690
|
+
params: z.object({
|
|
691
|
+
...TabRef,
|
|
692
|
+
model: z.string().min(1).max(100).optional(),
|
|
693
|
+
effort: z.string().min(1).max(100).optional(),
|
|
694
|
+
permissionMode: z.string().min(1).max(100).optional(),
|
|
695
|
+
from: AgentSenderSchema.optional(),
|
|
696
|
+
}),
|
|
697
|
+
result: ChatSettingsSchema,
|
|
698
|
+
},
|
|
699
|
+
/** Runs one of the app's slash commands (chat.commands' `command` ones), `args` after its name. */
|
|
700
|
+
"chat.command": {
|
|
701
|
+
capability: "chat.control",
|
|
702
|
+
params: z.object({
|
|
703
|
+
...TabRef,
|
|
704
|
+
name: z.string().min(1).max(100),
|
|
705
|
+
args: z.string().max(10_000).optional(),
|
|
236
706
|
}),
|
|
707
|
+
result: z.object({
|
|
708
|
+
/** What it said, when it says something rather than changing the chat. */
|
|
709
|
+
message: z.string().optional(),
|
|
710
|
+
/** The tab it opened, when it opened one. */
|
|
711
|
+
tabId: z.string().optional(),
|
|
712
|
+
}),
|
|
713
|
+
},
|
|
714
|
+
/** Stops a task of the chat's (a background run, a subagent), as the side panel's button does. */
|
|
715
|
+
"chat.stopTask": {
|
|
716
|
+
capability: "chat.control",
|
|
717
|
+
params: z.object({ ...TabRef, taskId: z.string() }),
|
|
237
718
|
result: Ok,
|
|
238
719
|
},
|
|
239
|
-
"chat.
|
|
240
|
-
|
|
720
|
+
"chat.rename": {
|
|
721
|
+
capability: "chat.control",
|
|
722
|
+
params: z.object({ ...TabRef, title: z.string().min(1).max(200) }),
|
|
723
|
+
result: z.object({ title: z.string() }),
|
|
724
|
+
},
|
|
725
|
+
/** Opens a past chat (history.list) in a new tab. */
|
|
726
|
+
"chat.resume": {
|
|
727
|
+
capability: "chat.control",
|
|
728
|
+
params: z.object({
|
|
729
|
+
workspaceId: z.string(),
|
|
730
|
+
agent: z.enum(["claude", "codex"]),
|
|
731
|
+
sessionId: z.string(),
|
|
732
|
+
}),
|
|
733
|
+
result: z.object({ tabId: z.string() }),
|
|
734
|
+
},
|
|
735
|
+
/**
|
|
736
|
+
* Opens a chat in one of the serving device's workspaces, sending it
|
|
737
|
+
* `prompt` if given. `model` and `effort` are set before the prompt goes,
|
|
738
|
+
* named as the agent's own menus name them ("haiku", "low"); the tab's
|
|
739
|
+
* profile's own otherwise.
|
|
740
|
+
*/
|
|
241
741
|
"chat.new": {
|
|
242
742
|
capability: "chat.control",
|
|
243
743
|
params: z.object({
|
|
244
744
|
workspaceId: z.string(),
|
|
245
745
|
agent: z.enum(["claude", "codex"]),
|
|
246
746
|
prompt: z.string().optional(),
|
|
747
|
+
model: z.string().min(1).max(100).optional(),
|
|
748
|
+
effort: z.string().min(1).max(100).optional(),
|
|
749
|
+
permissionMode: z.string().min(1).max(100).optional(),
|
|
750
|
+
/** The agent profile, by id or name (profiles.list); the workspace's otherwise. */
|
|
751
|
+
profile: z.string().min(1).max(100).optional(),
|
|
752
|
+
/** A folder inside the workspace to run in; its own folder otherwise. */
|
|
753
|
+
folder: z.string().min(1).max(4096).optional(),
|
|
754
|
+
/** Sent by an agent: the chat shows the prompt as that agent's. */
|
|
755
|
+
from: AgentSenderSchema.optional(),
|
|
756
|
+
}),
|
|
757
|
+
result: z.object({
|
|
758
|
+
tabId: z.string(),
|
|
759
|
+
/** The tab opened, but the model or effort could not be set: the prompt was not sent. */
|
|
760
|
+
error: z.string().optional(),
|
|
247
761
|
}),
|
|
248
|
-
result: z.object({ tabId: z.string() }),
|
|
249
762
|
},
|
|
250
|
-
"chat.close": {
|
|
763
|
+
"chat.close": {
|
|
764
|
+
capability: "chat.control",
|
|
765
|
+
params: z.object({ ...TabRef, from: AgentSenderSchema.optional() }),
|
|
766
|
+
result: Ok,
|
|
767
|
+
},
|
|
251
768
|
|
|
252
|
-
/**
|
|
769
|
+
/**
|
|
770
|
+
* A terminal's screen and the lines above it, as text; with `ansi`, with
|
|
771
|
+
* its colors and styles as SGR escapes (no other escapes).
|
|
772
|
+
*/
|
|
253
773
|
"terminal.read": {
|
|
254
774
|
capability: "terminal.read",
|
|
255
|
-
params: z.object({
|
|
775
|
+
params: z.object({
|
|
776
|
+
...TabRef,
|
|
777
|
+
lines: z.number().int().positive().max(5000).optional(),
|
|
778
|
+
ansi: z.boolean().optional(),
|
|
779
|
+
}),
|
|
256
780
|
result: z.object({ text: z.string() }),
|
|
257
781
|
},
|
|
782
|
+
/** The terminal's text now, as terminal.read; then a terminal.update each time it changes, until terminal.unwatch. */
|
|
783
|
+
"terminal.watch": {
|
|
784
|
+
capability: "terminal.read",
|
|
785
|
+
params: z.object({
|
|
786
|
+
...TabRef,
|
|
787
|
+
lines: z.number().int().positive().max(5000).optional(),
|
|
788
|
+
ansi: z.boolean().optional(),
|
|
789
|
+
}),
|
|
790
|
+
result: z.object({ text: z.string(), watchId: z.string() }),
|
|
791
|
+
},
|
|
792
|
+
"terminal.unwatch": {
|
|
793
|
+
capability: "terminal.read",
|
|
794
|
+
params: z.object({ watchId: z.string() }),
|
|
795
|
+
result: Ok,
|
|
796
|
+
},
|
|
797
|
+
/**
|
|
798
|
+
* Types into a terminal: `text` as pasted, then `keys` by name
|
|
799
|
+
* (TERMINAL_KEYS), then Enter when `enter`. Sent by an agent (`from`), the receiving device counts it
|
|
800
|
+
* as that agent's.
|
|
801
|
+
*/
|
|
802
|
+
"terminal.input": {
|
|
803
|
+
capability: "terminal.control",
|
|
804
|
+
params: z.object({
|
|
805
|
+
...TabRef,
|
|
806
|
+
text: z
|
|
807
|
+
.string()
|
|
808
|
+
.max(64 * 1024)
|
|
809
|
+
.optional(),
|
|
810
|
+
keys: z.array(TerminalKeySchema).max(64).optional(),
|
|
811
|
+
enter: z.boolean().optional(),
|
|
812
|
+
from: AgentSenderSchema.optional(),
|
|
813
|
+
}),
|
|
814
|
+
/** `at`: when it was typed, by the serving device's clock, for terminal.wait's `after`. */
|
|
815
|
+
result: z.object({ at: z.number().optional() }),
|
|
816
|
+
},
|
|
817
|
+
/**
|
|
818
|
+
* Waits up to `timeoutMs` (at most MAX_WAIT_MS) as `nexus terminal wait`
|
|
819
|
+
* does: for the terminal's agent to finish its turn, its shell to be back
|
|
820
|
+
* at the prompt, or quiet output; with `exit`, for its program to end;
|
|
821
|
+
* with `match`, for a line to match. Ask again while `done` is false.
|
|
822
|
+
*/
|
|
823
|
+
"terminal.wait": {
|
|
824
|
+
capability: "terminal.read",
|
|
825
|
+
params: z.object({
|
|
826
|
+
...TabRef,
|
|
827
|
+
timeoutMs: z.number().int().positive().max(MAX_WAIT_MS).optional(),
|
|
828
|
+
/** A terminal.input's `at`: a turn must have started after it. */
|
|
829
|
+
after: z.number().optional(),
|
|
830
|
+
exit: z.boolean().optional(),
|
|
831
|
+
match: z.string().min(1).max(1000).optional(),
|
|
832
|
+
/** Quiet for this long counts as idle, for a program that is no agent or shell. */
|
|
833
|
+
quietMs: z.number().int().positive().max(600_000).optional(),
|
|
834
|
+
}),
|
|
835
|
+
result: z.object({
|
|
836
|
+
done: z.boolean(),
|
|
837
|
+
/** idle, completed, needsInput, permissionPending, error, notStarted, notified, exited, matched, or waiting. */
|
|
838
|
+
state: z.string(),
|
|
839
|
+
message: z.string().optional(),
|
|
840
|
+
}),
|
|
841
|
+
},
|
|
842
|
+
/**
|
|
843
|
+
* Answers the permission request a terminal's Claude Code holds for the
|
|
844
|
+
* app (its session's `waiting.requestId`), as the agent list's buttons do.
|
|
845
|
+
* An answer for agents, so chat.control's: no typing goes in.
|
|
846
|
+
*/
|
|
847
|
+
"terminal.answer": {
|
|
848
|
+
capability: "chat.control",
|
|
849
|
+
params: z.object({
|
|
850
|
+
...TabRef,
|
|
851
|
+
requestId: z.string(),
|
|
852
|
+
decision: z.enum(["allow", "allowAlways", "deny", "denyStop"]),
|
|
853
|
+
from: AgentSenderSchema.optional(),
|
|
854
|
+
}),
|
|
855
|
+
result: Ok,
|
|
856
|
+
},
|
|
857
|
+
/** The shells a new terminal can run, as "New terminal with" lists them. */
|
|
858
|
+
"terminal.shells": {
|
|
859
|
+
capability: "terminal.control",
|
|
860
|
+
params: z.object({ workspaceId: z.string() }),
|
|
861
|
+
result: z.object({
|
|
862
|
+
shells: z.array(z.object({ id: z.string(), name: z.string(), isDefault: z.boolean() })),
|
|
863
|
+
}),
|
|
864
|
+
},
|
|
865
|
+
/** Opens a terminal: a shell (by its id), in a folder inside the workspace, running `command`. */
|
|
866
|
+
"terminal.open": {
|
|
867
|
+
capability: "terminal.control",
|
|
868
|
+
params: z.object({
|
|
869
|
+
workspaceId: z.string(),
|
|
870
|
+
shell: z.string().min(1).max(200).optional(),
|
|
871
|
+
folder: z.string().min(1).max(4096).optional(),
|
|
872
|
+
command: z.string().min(1).max(10_000).optional(),
|
|
873
|
+
title: z.string().min(1).max(200).optional(),
|
|
874
|
+
from: AgentSenderSchema.optional(),
|
|
875
|
+
}),
|
|
876
|
+
result: z.object({ tabId: z.string() }),
|
|
877
|
+
},
|
|
878
|
+
"terminal.rename": {
|
|
879
|
+
capability: "terminal.control",
|
|
880
|
+
params: z.object({ ...TabRef, title: z.string().min(1).max(200) }),
|
|
881
|
+
result: z.object({ title: z.string() }),
|
|
882
|
+
},
|
|
883
|
+
/** Closes a terminal; one running a program only with `force`. */
|
|
884
|
+
"terminal.close": {
|
|
885
|
+
capability: "terminal.control",
|
|
886
|
+
params: z.object({
|
|
887
|
+
...TabRef,
|
|
888
|
+
force: z.boolean().optional(),
|
|
889
|
+
from: AgentSenderSchema.optional(),
|
|
890
|
+
}),
|
|
891
|
+
result: Ok,
|
|
892
|
+
},
|
|
893
|
+
|
|
894
|
+
/**
|
|
895
|
+
* Answers a consent prompt of sessions.list's `consents`, as the user would
|
|
896
|
+
* on the serving device, where it closes. NotFound when it is no longer
|
|
897
|
+
* waiting (answered there, or timed out); Forbidden when it is not
|
|
898
|
+
* `answerable`, or for "session" to one asked about each time. An
|
|
899
|
+
* agent's request (`from`) is refused: only people answer these.
|
|
900
|
+
*/
|
|
901
|
+
"consent.answer": {
|
|
902
|
+
capability: "chat.control",
|
|
903
|
+
params: z.object({ id: z.string(), answer: ConsentAnswerSchema }),
|
|
904
|
+
result: Ok,
|
|
905
|
+
},
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* A folder's entries, folders first. `path` is absolute or inside the
|
|
909
|
+
* workspace's folder ("" for it); it must be in the workspace's folders
|
|
910
|
+
* (its own, and those its chats were given).
|
|
911
|
+
*/
|
|
912
|
+
"files.list": {
|
|
913
|
+
capability: "files",
|
|
914
|
+
params: z.object({ workspaceId: z.string(), path: z.string().max(4096) }),
|
|
915
|
+
result: z.object({
|
|
916
|
+
/** The folder, absolute. */
|
|
917
|
+
path: z.string(),
|
|
918
|
+
entries: z.array(
|
|
919
|
+
z.object({
|
|
920
|
+
name: z.string(),
|
|
921
|
+
kind: z.enum(["file", "dir", "link"]),
|
|
922
|
+
size: z.number().int().nonnegative().optional(),
|
|
923
|
+
}),
|
|
924
|
+
),
|
|
925
|
+
/** More than MAX_LIST_ENTRIES: the rest left out. */
|
|
926
|
+
truncated: z.boolean().optional(),
|
|
927
|
+
}),
|
|
928
|
+
},
|
|
929
|
+
/** A file: text (its start, up to `maxBytes`), an image made small enough for a frame, or that it is binary. */
|
|
930
|
+
"files.read": {
|
|
931
|
+
capability: "files",
|
|
932
|
+
params: z.object({
|
|
933
|
+
workspaceId: z.string(),
|
|
934
|
+
path: z.string().min(1).max(4096),
|
|
935
|
+
maxBytes: z.number().int().positive().max(MAX_READ_BYTES).optional(),
|
|
936
|
+
}),
|
|
937
|
+
result: z.discriminatedUnion("kind", [
|
|
938
|
+
z.object({
|
|
939
|
+
kind: z.literal("text"),
|
|
940
|
+
path: z.string(),
|
|
941
|
+
text: z.string(),
|
|
942
|
+
size: z.number().int().nonnegative(),
|
|
943
|
+
truncated: z.boolean(),
|
|
944
|
+
}),
|
|
945
|
+
z.object({
|
|
946
|
+
kind: z.literal("image"),
|
|
947
|
+
path: z.string(),
|
|
948
|
+
mediaType: ImageMediaTypeSchema,
|
|
949
|
+
data: z.string(),
|
|
950
|
+
size: z.number().int().nonnegative(),
|
|
951
|
+
}),
|
|
952
|
+
z.object({
|
|
953
|
+
kind: z.literal("binary"),
|
|
954
|
+
path: z.string(),
|
|
955
|
+
size: z.number().int().nonnegative(),
|
|
956
|
+
}),
|
|
957
|
+
]),
|
|
958
|
+
},
|
|
959
|
+
|
|
960
|
+
/** The workspace's branch, how it stands against its upstream, and its changed files. */
|
|
961
|
+
"git.status": {
|
|
962
|
+
capability: "git",
|
|
963
|
+
params: z.object({ workspaceId: z.string() }),
|
|
964
|
+
result: z.object({
|
|
965
|
+
/** null when no branch is checked out. */
|
|
966
|
+
branch: z.string().nullable(),
|
|
967
|
+
upstream: z.string().optional(),
|
|
968
|
+
ahead: z.number().int().nonnegative(),
|
|
969
|
+
behind: z.number().int().nonnegative(),
|
|
970
|
+
files: z.array(GitFileSchema),
|
|
971
|
+
/** More files than a frame takes: the rest left out. */
|
|
972
|
+
truncated: z.boolean().optional(),
|
|
973
|
+
}),
|
|
974
|
+
},
|
|
975
|
+
/** A file's changes, staged or not, in hunks as an edit's patch has them. */
|
|
976
|
+
"git.diff": {
|
|
977
|
+
capability: "git",
|
|
978
|
+
params: z.object({
|
|
979
|
+
workspaceId: z.string(),
|
|
980
|
+
path: z.string().min(1).max(4096),
|
|
981
|
+
staged: z.boolean().optional(),
|
|
982
|
+
}),
|
|
983
|
+
result: z.object({
|
|
984
|
+
path: z.string(),
|
|
985
|
+
oldPath: z.string().optional(),
|
|
986
|
+
binary: z.boolean().optional(),
|
|
987
|
+
hunks: z.array(DiffHunkSchema),
|
|
988
|
+
/** More than a frame takes: the hunks after left out. */
|
|
989
|
+
truncated: z.boolean().optional(),
|
|
990
|
+
}),
|
|
991
|
+
},
|
|
992
|
+
/** The branch's commits, latest first. */
|
|
993
|
+
"git.log": {
|
|
994
|
+
capability: "git",
|
|
995
|
+
params: z.object({
|
|
996
|
+
workspaceId: z.string(),
|
|
997
|
+
limit: z.number().int().positive().max(200).optional(),
|
|
998
|
+
skip: z.number().int().nonnegative().optional(),
|
|
999
|
+
}),
|
|
1000
|
+
result: z.object({
|
|
1001
|
+
commits: z.array(
|
|
1002
|
+
z.object({
|
|
1003
|
+
hash: z.string(),
|
|
1004
|
+
subject: z.string(),
|
|
1005
|
+
author: z.string(),
|
|
1006
|
+
/** Unix milliseconds. */
|
|
1007
|
+
at: z.number(),
|
|
1008
|
+
refs: z.array(z.string()).optional(),
|
|
1009
|
+
}),
|
|
1010
|
+
),
|
|
1011
|
+
}),
|
|
1012
|
+
},
|
|
258
1013
|
} as const;
|
|
259
1014
|
|
|
260
1015
|
export type RpcMethod = keyof typeof RPC_METHODS;
|
|
@@ -265,6 +1020,7 @@ export type RpcResult<M extends RpcMethod> = z.infer<(typeof RPC_METHODS)[M]["re
|
|
|
265
1020
|
export const RPC_NOTIFICATIONS = {
|
|
266
1021
|
"sessions.update": SessionsUpdateSchema,
|
|
267
1022
|
"chat.update": ChatUpdateSchema,
|
|
1023
|
+
"terminal.update": TerminalUpdateSchema,
|
|
268
1024
|
} as const;
|
|
269
1025
|
|
|
270
1026
|
export type RpcNotificationMethod = keyof typeof RPC_NOTIFICATIONS;
|