@linkshell/wire 0.1.2 → 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/dist/direct.d.ts +22 -0
- package/dist/direct.js +37 -0
- package/dist/direct.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/model.d.ts +387 -6
- package/dist/model.js +74 -0
- package/dist/model.js.map +1 -1
- package/dist/rpc.d.ts +3901 -1618
- package/dist/rpc.js +56 -4
- package/dist/rpc.js.map +1 -1
- package/dist/updates.d.ts +871 -515
- package/dist/updates.js +11 -1
- package/dist/updates.js.map +1 -1
- package/package.json +1 -1
- package/src/direct.ts +44 -0
- package/src/index.ts +1 -0
- package/src/model.ts +82 -0
- package/src/rpc.ts +58 -3
- package/src/updates.ts +11 -1
package/dist/updates.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { permissionOptionSchema, sessionDriverSchema, sessionStateSchema, toolKindSchema } from "./model.js";
|
|
2
|
+
import { permissionOptionSchema, questionAnswerSchema, questionSchema, sessionDriverSchema, sessionStateSchema, toolKindSchema } from "./model.js";
|
|
3
3
|
// Session updates mirror ACP's `SessionUpdate` shapes (discriminated by
|
|
4
4
|
// `sessionUpdate`) so one renderer works for every agent. LinkShell-specific
|
|
5
5
|
// updates use the `ls_` prefix.
|
|
@@ -64,6 +64,8 @@ export const toolDetailSchema = z.discriminatedUnion("type", [
|
|
|
64
64
|
z.object({ type: z.literal("image_generation"), prompt: z.string().optional() }),
|
|
65
65
|
z.object({ type: z.literal("compaction") }),
|
|
66
66
|
z.object({ type: z.literal("review"), phase: z.enum(["started", "finished"]) }),
|
|
67
|
+
/** The agent asked the user something (the first question, when there were several). */
|
|
68
|
+
z.object({ type: z.literal("question"), text: z.string(), more: z.number().int().optional() }),
|
|
67
69
|
]);
|
|
68
70
|
export const planEntrySchema = z.object({
|
|
69
71
|
content: z.string(),
|
|
@@ -178,11 +180,19 @@ export const sessionUpdateSchema = z.discriminatedUnion("sessionUpdate", [
|
|
|
178
180
|
title: z.string(),
|
|
179
181
|
detail: z.string().optional(),
|
|
180
182
|
options: z.array(permissionOptionSchema).min(1),
|
|
183
|
+
/**
|
|
184
|
+
* The agent is asking the user something: answer with `sessions.answer`.
|
|
185
|
+
* `options` then hold what else can be done (skip the questions, stop),
|
|
186
|
+
* which is also all an app that predates questions can offer.
|
|
187
|
+
*/
|
|
188
|
+
questions: z.array(questionSchema).optional(),
|
|
181
189
|
}),
|
|
182
190
|
z.object({
|
|
183
191
|
sessionUpdate: z.literal("ls_permission_resolved"),
|
|
184
192
|
requestId: z.string(),
|
|
185
193
|
optionId: z.string().optional(),
|
|
194
|
+
/** How questions were answered, for the record. */
|
|
195
|
+
answers: z.array(questionAnswerSchema).optional(),
|
|
186
196
|
}),
|
|
187
197
|
z.object({
|
|
188
198
|
sessionUpdate: z.literal("ls_driver"),
|
package/dist/updates.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updates.js","sourceRoot":"","sources":["../src/updates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"updates.js","sourceRoot":"","sources":["../src/updates.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/direct.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// The direct channel: bulk streams (the screen, port previews) go from the
|
|
2
|
+
// computer to the device peer to peer, over a WebRTC data channel, instead of
|
|
3
|
+
// through the gateway. The offer and answer travel over the end-to-end
|
|
4
|
+
// encrypted RPC channel, so the gateway can neither read them nor stand in for
|
|
5
|
+
// either side; it carries only what little sets the connection up. When no
|
|
6
|
+
// direct path can be made, the streams stay on the RPC channel as before.
|
|
7
|
+
|
|
8
|
+
/** The data channel both sides use. */
|
|
9
|
+
export const DIRECT_LABEL = "linkshell-bulk";
|
|
10
|
+
|
|
11
|
+
/** The most stream bytes in one message: every WebRTC stack takes this size. */
|
|
12
|
+
export const DIRECT_CHUNK = 16 * 1024;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* STUN servers used when a host names none: they only tell each side its
|
|
16
|
+
* public address. (Several, because none of them is reachable everywhere.)
|
|
17
|
+
*/
|
|
18
|
+
export const DEFAULT_ICE_SERVERS = ["stun:stun.cloudflare.com:3478", "stun:stun.chat.bilibili.com:3478", "stun:stun.l.google.com:19302"];
|
|
19
|
+
|
|
20
|
+
export type DirectFrame =
|
|
21
|
+
| { type: "data"; stream: number; data: Uint8Array }
|
|
22
|
+
/** The sender's end of the stream is finished (`error`: why, when it broke). */
|
|
23
|
+
| { type: "close"; stream: number; error?: string };
|
|
24
|
+
|
|
25
|
+
const DATA = 1;
|
|
26
|
+
const CLOSE = 2;
|
|
27
|
+
|
|
28
|
+
export function encodeDirectFrame(frame: DirectFrame): Uint8Array {
|
|
29
|
+
const payload = frame.type === "data" ? frame.data : new TextEncoder().encode(frame.error ?? "");
|
|
30
|
+
const bytes = new Uint8Array(5 + payload.length);
|
|
31
|
+
bytes[0] = frame.type === "data" ? DATA : CLOSE;
|
|
32
|
+
new DataView(bytes.buffer).setUint32(1, frame.stream);
|
|
33
|
+
bytes.set(payload, 5);
|
|
34
|
+
return bytes;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function decodeDirectFrame(bytes: Uint8Array): DirectFrame | undefined {
|
|
38
|
+
if (bytes.length < 5) return undefined;
|
|
39
|
+
const stream = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(1);
|
|
40
|
+
const payload = bytes.subarray(5);
|
|
41
|
+
if (bytes[0] === DATA) return { type: "data", stream, data: payload };
|
|
42
|
+
if (bytes[0] === CLOSE) return { type: "close", stream, error: payload.length ? new TextDecoder().decode(payload) : undefined };
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
package/src/index.ts
CHANGED
package/src/model.ts
CHANGED
|
@@ -19,6 +19,12 @@ export const agentCapabilitiesSchema = z.object({
|
|
|
19
19
|
steer: z.boolean(),
|
|
20
20
|
permissions: z.boolean(),
|
|
21
21
|
images: z.boolean(),
|
|
22
|
+
/**
|
|
23
|
+
* The agent forks sessions itself, keeping everything it knew. Every agent's
|
|
24
|
+
* sessions can be forked: without this (or from a single reply, where the
|
|
25
|
+
* agent only forks whole sessions) LinkShell makes the fork — the new session
|
|
26
|
+
* shows the conversation and its agent is told it as text.
|
|
27
|
+
*/
|
|
22
28
|
fork: z.boolean(),
|
|
23
29
|
models: z.boolean(),
|
|
24
30
|
modes: z.boolean(),
|
|
@@ -91,12 +97,44 @@ export const sessionActivitySchema = z.object({
|
|
|
91
97
|
export type SessionActivity = z.infer<typeof sessionActivitySchema>;
|
|
92
98
|
|
|
93
99
|
/** The oldest unanswered permission request, so lists can offer approval inline. Live only. */
|
|
100
|
+
/**
|
|
101
|
+
* Something the agent asks the user rather than asks permission for: a choice
|
|
102
|
+
* among options, several of them, or something to type (Claude's
|
|
103
|
+
* AskUserQuestion, Codex's request_user_input, an MCP server's form).
|
|
104
|
+
*/
|
|
105
|
+
export const questionSchema = z.object({
|
|
106
|
+
id: z.string(),
|
|
107
|
+
/** A short label for the question ("Auth method"). */
|
|
108
|
+
header: z.string().optional(),
|
|
109
|
+
text: z.string(),
|
|
110
|
+
/** `choice`: one of `options`; `choices`: any number of them; `text`: typed. */
|
|
111
|
+
kind: z.enum(["choice", "choices", "text"]),
|
|
112
|
+
options: z.array(z.object({ value: z.string(), label: z.string(), description: z.string().optional() })).optional(),
|
|
113
|
+
/** With options: an answer of the user's own can be typed instead of, or beside, a pick. */
|
|
114
|
+
other: z.boolean().optional(),
|
|
115
|
+
/** What is typed shouldn't be shown (a token). */
|
|
116
|
+
secret: z.boolean().optional(),
|
|
117
|
+
required: z.boolean().optional(),
|
|
118
|
+
});
|
|
119
|
+
export type Question = z.infer<typeof questionSchema>;
|
|
120
|
+
|
|
121
|
+
export const questionAnswerSchema = z.object({
|
|
122
|
+
id: z.string(),
|
|
123
|
+
/** The values picked (`choice`: at most one), or what was typed for a `text` question. */
|
|
124
|
+
values: z.array(z.string().max(20_000)).max(50),
|
|
125
|
+
/** The user's own answer beside the options. */
|
|
126
|
+
other: z.string().max(20_000).optional(),
|
|
127
|
+
});
|
|
128
|
+
export type QuestionAnswer = z.infer<typeof questionAnswerSchema>;
|
|
129
|
+
|
|
94
130
|
export const pendingPermissionSchema = z.object({
|
|
95
131
|
requestId: z.string(),
|
|
96
132
|
toolCallId: z.string().optional(),
|
|
97
133
|
title: z.string(),
|
|
98
134
|
detail: z.string().optional(),
|
|
99
135
|
options: z.array(permissionOptionSchema).min(1),
|
|
136
|
+
/** Set when this is a question to answer (`sessions.answer`) rather than a permission to give. */
|
|
137
|
+
questions: z.array(questionSchema).optional(),
|
|
100
138
|
});
|
|
101
139
|
export type PendingPermissionSummary = z.infer<typeof pendingPermissionSchema>;
|
|
102
140
|
|
|
@@ -145,6 +183,13 @@ export const sessionSummarySchema = z.object({
|
|
|
145
183
|
* holds them (agents that can't take input mid-turn). Oldest first.
|
|
146
184
|
*/
|
|
147
185
|
queue: z.array(queuedMessageSchema).optional(),
|
|
186
|
+
/**
|
|
187
|
+
* The session works in a git worktree LinkShell made for it: its own
|
|
188
|
+
* checkout and branch, so it can't disturb the project's working directory.
|
|
189
|
+
* `cwd` is inside the worktree; `source` is the directory it was made from
|
|
190
|
+
* (the project the session belongs to).
|
|
191
|
+
*/
|
|
192
|
+
worktree: z.object({ branch: z.string(), source: z.string() }).optional(),
|
|
148
193
|
/** Live only, for sessions that started sub-agents: how many, and how many are working now (`sessions.subagents` lists them). */
|
|
149
194
|
subagents: z.object({ total: z.number().int(), running: z.number().int() }).optional(),
|
|
150
195
|
});
|
|
@@ -160,11 +205,43 @@ export function parseSessionId(id: string): { agent: string; nativeId: string }
|
|
|
160
205
|
return { agent: id.slice(0, index), nativeId: id.slice(index + 1) };
|
|
161
206
|
}
|
|
162
207
|
|
|
208
|
+
/** What git says about a directory, to offer starting a session in a worktree of it. */
|
|
209
|
+
export const gitInfoSchema = z.object({
|
|
210
|
+
/** The repository's top directory. */
|
|
211
|
+
root: z.string(),
|
|
212
|
+
/** The branch checked out; absent on a detached HEAD. */
|
|
213
|
+
branch: z.string().optional(),
|
|
214
|
+
/** The commit checked out, abbreviated; absent before the first commit. */
|
|
215
|
+
head: z.string().optional(),
|
|
216
|
+
/** Uncommitted changes in the working directory (a new worktree starts from the last commit, without them). */
|
|
217
|
+
dirty: z.boolean(),
|
|
218
|
+
});
|
|
219
|
+
export type GitInfo = z.infer<typeof gitInfoSchema>;
|
|
220
|
+
|
|
221
|
+
/** A worktree LinkShell made for sessions. */
|
|
222
|
+
export const worktreeEntrySchema = z.object({
|
|
223
|
+
/** The worktree's top directory. */
|
|
224
|
+
path: z.string(),
|
|
225
|
+
branch: z.string(),
|
|
226
|
+
/** The repository it belongs to. */
|
|
227
|
+
source: z.string(),
|
|
228
|
+
createdAt: z.number(),
|
|
229
|
+
/** Sessions working in it. */
|
|
230
|
+
sessions: z.array(z.string()),
|
|
231
|
+
/** Uncommitted changes in it. */
|
|
232
|
+
dirty: z.boolean(),
|
|
233
|
+
/** Commits made in it since it was created. */
|
|
234
|
+
ahead: z.number().int().nonnegative(),
|
|
235
|
+
});
|
|
236
|
+
export type WorktreeEntry = z.infer<typeof worktreeEntrySchema>;
|
|
237
|
+
|
|
163
238
|
export const projectSummarySchema = z.object({
|
|
164
239
|
cwd: z.string(),
|
|
165
240
|
name: z.string(),
|
|
166
241
|
lastActiveAt: z.number(),
|
|
167
242
|
sessionCount: z.number().int().nonnegative(),
|
|
243
|
+
/** For a git repository: the branch checked out there now (or the abbreviated commit, on a detached HEAD). */
|
|
244
|
+
branch: z.string().optional(),
|
|
168
245
|
});
|
|
169
246
|
export type ProjectSummary = z.infer<typeof projectSummarySchema>;
|
|
170
247
|
|
|
@@ -176,6 +253,11 @@ export const machineInfoSchema = z.object({
|
|
|
176
253
|
/** The host user's home directory, so apps can show paths as `~/…`. */
|
|
177
254
|
home: z.string().optional(),
|
|
178
255
|
agents: z.array(agentInfoSchema),
|
|
256
|
+
/**
|
|
257
|
+
* The host can send bulk streams peer to peer (`direct.offer`); `iceServers`
|
|
258
|
+
* are the STUN servers both sides use to find a path.
|
|
259
|
+
*/
|
|
260
|
+
direct: z.object({ iceServers: z.array(z.string()) }).optional(),
|
|
179
261
|
});
|
|
180
262
|
export type MachineInfo = z.infer<typeof machineInfoSchema>;
|
|
181
263
|
|
package/src/rpc.ts
CHANGED
|
@@ -8,6 +8,9 @@ import {
|
|
|
8
8
|
sessionDriverSchema,
|
|
9
9
|
sessionSummarySchema,
|
|
10
10
|
subagentInfoSchema,
|
|
11
|
+
gitInfoSchema,
|
|
12
|
+
worktreeEntrySchema,
|
|
13
|
+
questionAnswerSchema,
|
|
11
14
|
} from "./model.js";
|
|
12
15
|
import { contentBlockSchema, sessionEventSchema } from "./updates.js";
|
|
13
16
|
|
|
@@ -95,9 +98,25 @@ export const methods = {
|
|
|
95
98
|
prompt: z.array(contentBlockSchema).optional(),
|
|
96
99
|
clientMessageId: z.string().optional(),
|
|
97
100
|
model: z.string().optional(),
|
|
101
|
+
/**
|
|
102
|
+
* Start in a new git worktree of `cwd`'s repository (its own branch, from
|
|
103
|
+
* the last commit) instead of in `cwd` itself. Refused with `not_a_repo`
|
|
104
|
+
* outside a git repository.
|
|
105
|
+
*/
|
|
106
|
+
worktree: z.boolean().optional(),
|
|
98
107
|
}),
|
|
99
108
|
result: z.object({ session: sessionSummarySchema }),
|
|
100
109
|
},
|
|
110
|
+
/**
|
|
111
|
+
* A new session that starts with this one's conversation: all of it, or up
|
|
112
|
+
* to and including the turn of `itemId` (a message in it). The original is
|
|
113
|
+
* untouched. With `worktree` the new session works in a new git worktree of
|
|
114
|
+
* the project instead of the same directory.
|
|
115
|
+
*/
|
|
116
|
+
"sessions.fork": {
|
|
117
|
+
params: z.object({ sessionId: z.string().min(1), itemId: z.string().min(1).optional(), worktree: z.boolean().optional() }),
|
|
118
|
+
result: z.object({ session: sessionSummarySchema }),
|
|
119
|
+
},
|
|
101
120
|
"sessions.subscribe": {
|
|
102
121
|
params: z.object({
|
|
103
122
|
sessionId: z.string().min(1),
|
|
@@ -178,6 +197,15 @@ export const methods = {
|
|
|
178
197
|
}),
|
|
179
198
|
result: empty,
|
|
180
199
|
},
|
|
200
|
+
/**
|
|
201
|
+
* Answers the questions of a pending request (an `ls_permission` with
|
|
202
|
+
* `questions`). Skipping or stopping instead is `sessions.permission` with
|
|
203
|
+
* one of the request's options.
|
|
204
|
+
*/
|
|
205
|
+
"sessions.answer": {
|
|
206
|
+
params: z.object({ sessionId: z.string().min(1), requestId: z.string().min(1), answers: z.array(questionAnswerSchema).max(50) }),
|
|
207
|
+
result: empty,
|
|
208
|
+
},
|
|
181
209
|
"sessions.setConfig": {
|
|
182
210
|
params: z.object({
|
|
183
211
|
sessionId: z.string().min(1),
|
|
@@ -219,8 +247,13 @@ export const methods = {
|
|
|
219
247
|
* Deletes a session: the agent's own record where it has one (Codex thread,
|
|
220
248
|
* Claude transcript), and LinkShell's copy either way. Not while it runs.
|
|
221
249
|
*/
|
|
250
|
+
/**
|
|
251
|
+
* Deletes a session. Its worktree (when it has one that no other session
|
|
252
|
+
* uses) goes with it if nothing in it would be lost; `worktree: "remove"`
|
|
253
|
+
* removes it even with uncommitted changes or new commits, "keep" never.
|
|
254
|
+
*/
|
|
222
255
|
"sessions.delete": {
|
|
223
|
-
params: z.object({ sessionId: z.string().min(1) }),
|
|
256
|
+
params: z.object({ sessionId: z.string().min(1), worktree: z.enum(["keep", "remove"]).optional() }),
|
|
224
257
|
result: empty,
|
|
225
258
|
},
|
|
226
259
|
"sessions.takeover": {
|
|
@@ -285,6 +318,13 @@ export const methods = {
|
|
|
285
318
|
result: z.object({ link: z.string(), code: z.string(), expiresAt: z.number(), gateway: z.string() }),
|
|
286
319
|
},
|
|
287
320
|
"devices.revoke": { params: z.object({ deviceId: z.string().min(1) }), result: empty },
|
|
321
|
+
// ── Git: sessions in worktrees ──
|
|
322
|
+
/** What git says about `path`; no `git` when it isn't in a repository. */
|
|
323
|
+
"git.info": { params: z.object({ path: z.string().min(1) }), result: z.object({ git: gitInfoSchema.optional() }) },
|
|
324
|
+
/** The worktrees LinkShell made, newest first. */
|
|
325
|
+
"worktrees.list": { params: empty, result: z.object({ worktrees: z.array(worktreeEntrySchema) }) },
|
|
326
|
+
/** Removes a worktree and its branch. Refused (`busy`) while a session uses it, or (`dirty`) when work in it would be lost, unless `force`. */
|
|
327
|
+
"worktrees.remove": { params: z.object({ path: z.string().min(1), force: z.boolean().optional() }), result: empty },
|
|
288
328
|
// ── Directories: pick where a new session runs ──
|
|
289
329
|
/** Subdirectories of `path` (default: the home directory). */
|
|
290
330
|
"fs.list": {
|
|
@@ -418,8 +458,23 @@ export const methods = {
|
|
|
418
458
|
* host's bytes arrive as `proxy.data`; the stream ends with `proxy.closed`.
|
|
419
459
|
*/
|
|
420
460
|
"proxy.open": {
|
|
421
|
-
params: z.object({
|
|
422
|
-
|
|
461
|
+
params: z.object({
|
|
462
|
+
port: z.number().int().min(1).max(65535),
|
|
463
|
+
/** Carry the stream on the direct channel, if this connection has one open. */
|
|
464
|
+
direct: z.boolean().optional(),
|
|
465
|
+
}),
|
|
466
|
+
/** `channel`: the stream's number on the direct channel, when it goes there instead of over `proxy.*`. */
|
|
467
|
+
result: z.object({ streamId: z.string(), channel: z.number().int().nonnegative().optional() }),
|
|
468
|
+
},
|
|
469
|
+
/**
|
|
470
|
+
* Sets up the direct channel (see `direct.ts`): the device's WebRTC offer,
|
|
471
|
+
* holding the `linkshell-bulk` data channel, answered by the host. Each side
|
|
472
|
+
* has gathered its addresses before sending. A new offer replaces the
|
|
473
|
+
* connection made by an earlier one.
|
|
474
|
+
*/
|
|
475
|
+
"direct.offer": {
|
|
476
|
+
params: z.object({ sdp: z.string().min(1).max(200_000) }),
|
|
477
|
+
result: z.object({ sdp: z.string() }),
|
|
423
478
|
},
|
|
424
479
|
/**
|
|
425
480
|
* Starts the host's screen viewer: a page plus H.264 stream on a loopback
|
package/src/updates.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { permissionOptionSchema, sessionDriverSchema, sessionStateSchema, toolKindSchema } from "./model.js";
|
|
2
|
+
import { permissionOptionSchema, questionAnswerSchema, questionSchema, sessionDriverSchema, sessionStateSchema, toolKindSchema } from "./model.js";
|
|
3
3
|
|
|
4
4
|
// Session updates mirror ACP's `SessionUpdate` shapes (discriminated by
|
|
5
5
|
// `sessionUpdate`) so one renderer works for every agent. LinkShell-specific
|
|
@@ -74,6 +74,8 @@ export const toolDetailSchema = z.discriminatedUnion("type", [
|
|
|
74
74
|
z.object({ type: z.literal("image_generation"), prompt: z.string().optional() }),
|
|
75
75
|
z.object({ type: z.literal("compaction") }),
|
|
76
76
|
z.object({ type: z.literal("review"), phase: z.enum(["started", "finished"]) }),
|
|
77
|
+
/** The agent asked the user something (the first question, when there were several). */
|
|
78
|
+
z.object({ type: z.literal("question"), text: z.string(), more: z.number().int().optional() }),
|
|
77
79
|
]);
|
|
78
80
|
export type ToolDetail = z.infer<typeof toolDetailSchema>;
|
|
79
81
|
|
|
@@ -198,11 +200,19 @@ export const sessionUpdateSchema = z.discriminatedUnion("sessionUpdate", [
|
|
|
198
200
|
title: z.string(),
|
|
199
201
|
detail: z.string().optional(),
|
|
200
202
|
options: z.array(permissionOptionSchema).min(1),
|
|
203
|
+
/**
|
|
204
|
+
* The agent is asking the user something: answer with `sessions.answer`.
|
|
205
|
+
* `options` then hold what else can be done (skip the questions, stop),
|
|
206
|
+
* which is also all an app that predates questions can offer.
|
|
207
|
+
*/
|
|
208
|
+
questions: z.array(questionSchema).optional(),
|
|
201
209
|
}),
|
|
202
210
|
z.object({
|
|
203
211
|
sessionUpdate: z.literal("ls_permission_resolved"),
|
|
204
212
|
requestId: z.string(),
|
|
205
213
|
optionId: z.string().optional(),
|
|
214
|
+
/** How questions were answered, for the record. */
|
|
215
|
+
answers: z.array(questionAnswerSchema).optional(),
|
|
206
216
|
}),
|
|
207
217
|
z.object({
|
|
208
218
|
sessionUpdate: z.literal("ls_driver"),
|