@a-t-h-i/bot-lobby 0.6.12 → 0.6.13

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 (62) hide show
  1. package/README.md +11 -3
  2. package/package.json +31 -4
  3. package/src/ask/tool.ts +2 -1
  4. package/src/lobby/keys.ts +14 -1
  5. package/src/lobby/mini.ts +9 -1
  6. package/src/lobby/models/metrics.ts +14 -0
  7. package/src/lobby/planner.ts +1 -1
  8. package/src/lobby/prompt-hub.ts +161 -0
  9. package/src/lobby/prompts.ts +35 -0
  10. package/src/lobby/runtime.ts +115 -566
  11. package/src/lobby/service.ts +655 -0
  12. package/src/lobby/tabs/home.ts +1 -1
  13. package/src/lobby/tabs/metrics.ts +4 -6
  14. package/src/lobby/topics.ts +78 -0
  15. package/src/lobby/view.ts +29 -24
  16. package/src/pi/commands.ts +8 -2
  17. package/src/pi/owner.ts +2 -0
  18. package/src/pi/settings-ui.ts +52 -1
  19. package/src/pi/tools.ts +4 -3
  20. package/src/schemas/configuration.ts +33 -1
  21. package/src/state/changes.ts +1 -1
  22. package/src/state/persistence.ts +1 -1
  23. package/src/state/presence.ts +2 -0
  24. package/src/webui/api/excalidraw.ts +105 -0
  25. package/src/webui/api/gh-error.ts +17 -0
  26. package/src/webui/api/git.ts +98 -0
  27. package/src/webui/api/index.ts +379 -0
  28. package/src/webui/api/issues.ts +50 -0
  29. package/src/webui/api/knowledge.ts +79 -0
  30. package/src/webui/api/lobby.ts +91 -0
  31. package/src/webui/api/metrics.ts +63 -0
  32. package/src/webui/api/plan-facts.ts +29 -0
  33. package/src/webui/api/planner.ts +98 -0
  34. package/src/webui/api/plans.ts +44 -0
  35. package/src/webui/api/prompts.ts +35 -0
  36. package/src/webui/api/quickfix.ts +48 -0
  37. package/src/webui/api/sessions.ts +114 -0
  38. package/src/webui/api/settings.ts +93 -0
  39. package/src/webui/api/status.ts +55 -0
  40. package/src/webui/api/tasks.ts +204 -0
  41. package/src/webui/auth.ts +153 -0
  42. package/src/webui/command.ts +152 -0
  43. package/src/webui/dev/fake-service.ts +546 -0
  44. package/src/webui/dev/fixtures.ts +180 -0
  45. package/src/webui/dev/serve.ts +54 -0
  46. package/src/webui/events.ts +207 -0
  47. package/src/webui/files.ts +88 -0
  48. package/src/webui/notices.ts +61 -0
  49. package/src/webui/open.ts +35 -0
  50. package/src/webui/protocol.ts +565 -0
  51. package/src/webui/server.ts +315 -0
  52. package/src/webui/static.ts +125 -0
  53. package/webui/dist/assets/index-Bk-lpAGm.css +2 -0
  54. package/webui/dist/assets/index-E6MPcbdC.js +80 -0
  55. package/webui/dist/build.json +494 -0
  56. package/webui/dist/icon-192.png +0 -0
  57. package/webui/dist/icon-512.png +0 -0
  58. package/webui/dist/index.html +18 -0
  59. package/webui/dist/manifest.webmanifest +36 -0
  60. package/webui/dist/offline.html +57 -0
  61. package/webui/dist/sw.js +88 -0
  62. package/webui/dist/vite.svg +1 -0
@@ -0,0 +1,565 @@
1
+ /**
2
+ * What crosses the wire between the lobby's loopback server and its page.
3
+ * The page imports this file with `import type` only, so nothing from the
4
+ * server is ever bundled into it.
5
+ */
6
+ import type { LobbyTopic } from "../lobby/topics.ts";
7
+ import type { WebPrompt } from "../lobby/prompt-hub.ts";
8
+ import type { DialogAnswer, SessionDialog } from "../lobby/sessions.ts";
9
+ import type { LiveSession } from "../lobby/view.ts";
10
+ import type { TaskRow } from "../lobby/tabs/tasks.ts";
11
+ import type { PlanComment } from "../state/comments.ts";
12
+ import type { BotLobbyConfig, PanelMember } from "../schemas/configuration.ts";
13
+ import type { MemberState, PanelNote, PanelQuestion, PlannerMessage } from "../lobby/planner.ts";
14
+ import type { QuickFixJob } from "../lobby/quickfix.ts";
15
+
16
+ export type { WebPrompt };
17
+ export type { LobbyTopic };
18
+ export type { DialogAnswer, SessionDialog, TaskRow, PlanComment };
19
+ export type { LiveSession };
20
+ export type { PanelMember, MemberState, PanelNote, PanelQuestion, PlannerMessage, QuickFixJob, BotLobbyConfig };
21
+
22
+ /** Every API answer: the result, or why not. */
23
+ export type ApiReply<T> = { ok: true; result: T } | { ok: false; error: string; code: ErrorCode };
24
+
25
+ /** Machine codes for API failures, each with its own HTTP status. */
26
+ export type ErrorCode =
27
+ | "bad_request"
28
+ | "unauthorized"
29
+ | "forbidden"
30
+ | "not_found"
31
+ | "unsupported"
32
+ | "too_large"
33
+ | "conflict"
34
+ | "question_withdrawn"
35
+ | "rate_limited"
36
+ | "failed";
37
+
38
+ /** HTTP status for an error code. */
39
+ export function statusFor(code: ErrorCode): number {
40
+ switch (code) {
41
+ case "bad_request":
42
+ return 400;
43
+ case "unauthorized":
44
+ return 401;
45
+ case "forbidden":
46
+ return 403;
47
+ case "not_found":
48
+ return 404;
49
+ case "conflict":
50
+ case "question_withdrawn":
51
+ return 409;
52
+ case "too_large":
53
+ return 413;
54
+ case "unsupported":
55
+ return 415;
56
+ case "rate_limited":
57
+ return 429;
58
+ case "failed":
59
+ return 500;
60
+ }
61
+ }
62
+
63
+ /** One tab as the status call describes it. */
64
+ export interface TabInfo {
65
+ id: string;
66
+ label: string;
67
+ key: string;
68
+ }
69
+
70
+ /** One shortcut as the status call describes it. */
71
+ export interface KeyInfo {
72
+ action: string;
73
+ key: string;
74
+ label: string;
75
+ help: string;
76
+ }
77
+
78
+ /** `status.get`: everything the page shell needs before it reads a tab. */
79
+ export interface StatusInfo {
80
+ workspace: { name: string; branch?: string };
81
+ branch?: string;
82
+ sessionId?: string;
83
+ sessionName?: string;
84
+ busy: boolean;
85
+ /** Pi itself is asking in the terminal; the page waits. */
86
+ terminalDialog: boolean;
87
+ port: number;
88
+ issuesEnabled: boolean;
89
+ tabs: TabInfo[];
90
+ keys: KeyInfo[];
91
+ windows: Array<{ name: string; url: string }>;
92
+ }
93
+
94
+ /** One task header as the lobby snapshot carries it. */
95
+ export interface SnapshotTask {
96
+ id: string;
97
+ title: string;
98
+ state: string;
99
+ track?: { path: "fast" | "full"; size: string };
100
+ domains: string[];
101
+ git?: { branch: string; from?: string };
102
+ progress?: { done: number; total: number };
103
+ currentStep?: string;
104
+ }
105
+
106
+ /** What the Lobby tab shows, read in one call. */
107
+ export interface LobbySnapshot {
108
+ task?: SnapshotTask;
109
+ runs: unknown[];
110
+ /** Newest chat messages (at most 100), oldest first. */
111
+ chat: Array<{ id: number; at: number; role: string; text: string }>;
112
+ /** The oracle's reply while it streams; absent between replies. */
113
+ reply?: string;
114
+ /** Newest activity entries (at most 400), oldest first. */
115
+ activity: Array<{ id: number; at: number; source: string; text: string; kind: string; pending: boolean }>;
116
+ /** Newest thoughts (at most 40), oldest first. */
117
+ thoughts: Array<{ id: number; at: number; source: string; text: string; live: boolean }>;
118
+ /** Earlier chat exists in the session (loaded through `lobby.history`). */
119
+ hasOlderChat: boolean;
120
+ }
121
+
122
+ /** One background session as `sessions.list` describes it. */
123
+ export interface BackgroundSessionInfo {
124
+ key: string;
125
+ name: string;
126
+ status: string;
127
+ busy: boolean;
128
+ alive: boolean;
129
+ sessionId?: string;
130
+ planId?: string;
131
+ /** Questions it waits on you for. */
132
+ waiting: number;
133
+ dialogs: SessionDialog[];
134
+ }
135
+
136
+ /** How loud a lobby notice is (sonner's levels). */
137
+ export type NoticeLevel = "info" | "success" | "warning" | "error";
138
+
139
+ /** One model Pi offers, for the settings page's picker. */
140
+ export interface SettingsModelInfo {
141
+ /** `provider/id`, the form settings store. */
142
+ id: string;
143
+ label: string;
144
+ thinkingLevels: string[];
145
+ }
146
+
147
+ /** `settings.get`: the effective config (never a secret) and the models Pi offers. */
148
+ export interface SettingsInfo {
149
+ config: BotLobbyConfig;
150
+ models: SettingsModelInfo[];
151
+ }
152
+
153
+ /** One message on the event stream (`GET /api/events`, server-sent events). */
154
+ export type StreamEvent =
155
+ | { type: "hello"; versions: Partial<Record<LobbyTopic, number>> }
156
+ | { type: "changed"; topic: LobbyTopic; version: number }
157
+ | { type: "feed"; activity: unknown[]; thoughts: unknown[]; chat: unknown[] }
158
+ | { type: "reply"; text: string }
159
+ | { type: "notice"; text: string; level: NoticeLevel };
160
+
161
+ /** The planning session as `planner.get` describes it. */
162
+ export interface PlannerSnapshot {
163
+ /** Seats on the panel next round. */
164
+ seats: PanelMember[];
165
+ /** What each seat of the latest round did. */
166
+ members: MemberState[];
167
+ /** The whole conversation, oldest first. */
168
+ messages: PlannerMessage[];
169
+ /** The oracle's current draft plan, when it wrote one. */
170
+ draft?: string;
171
+ /** The latest round's questions, attributed. */
172
+ questions: PanelQuestion[];
173
+ /** What each seat said the plan must respect. */
174
+ notes: PanelNote[];
175
+ /** Rounds run so far. */
176
+ round: number;
177
+ /** Rounds before the oracle finalizes alone; 0 = unlimited. */
178
+ limit: number;
179
+ /** Whether `planner.retry` has something to redo. */
180
+ retryable: boolean;
181
+ /** Whether the panel is thinking now. */
182
+ busy: boolean;
183
+ }
184
+
185
+ /** One issue a planning session can start from. */
186
+ export interface PlannerSeedInfo {
187
+ issue: { number: number; title: string; url?: string };
188
+ body: string;
189
+ }
190
+
191
+ /** The Metrics tab's KPI row as data: runs, success, average run, cost, tasks. */
192
+ export interface MetricsTiles {
193
+ runs: number;
194
+ successes: number;
195
+ stalls: number;
196
+ avgMs: number;
197
+ p90Ms: number;
198
+ cost: number;
199
+ completed: number;
200
+ active: number;
201
+ avgCompleteMs: number;
202
+ }
203
+
204
+ /** One per-model group as `metrics.get` carries it. */
205
+ export interface MetricGroupInfo {
206
+ model: string;
207
+ thinking: string;
208
+ kinds: string[];
209
+ runs: number;
210
+ successes: number;
211
+ timeouts: number;
212
+ avgMs: number;
213
+ p50Ms: number;
214
+ p90Ms: number;
215
+ avgTurns: number;
216
+ avgTools: number;
217
+ avgTokens: number;
218
+ avgCost: number;
219
+ totalCost: number;
220
+ tokensPerSecond: number;
221
+ }
222
+
223
+ /** One agent's share of all run time. */
224
+ export interface MetricsAgentShare {
225
+ agent: string;
226
+ runs: number;
227
+ ms: number;
228
+ share: number;
229
+ }
230
+
231
+ /** Completed tasks' request-to-done time by the oracle's model and thinking. */
232
+ export interface MetricsTaskTime {
233
+ model: string;
234
+ thinking: string;
235
+ tasks: number;
236
+ avgMs: number;
237
+ }
238
+
239
+ /** What the classifier did and spared, when it has run. */
240
+ export interface MetricsClassifier {
241
+ calls: number;
242
+ ok: number;
243
+ p50Ms: number;
244
+ p90Ms: number;
245
+ input: number;
246
+ byPurpose: Record<string, number>;
247
+ seatRunsSkipped: number;
248
+ questionsAnswered: number;
249
+ quickFixesHeld: number;
250
+ routed: number;
251
+ routedOk: number;
252
+ }
253
+
254
+ /** `metrics.get`: the dashboard figures for one grouping and search. */
255
+ export interface MetricsData {
256
+ tiles: MetricsTiles;
257
+ groups: MetricGroupInfo[];
258
+ timeShare: { byAgent: MetricsAgentShare[]; taskTimes: MetricsTaskTime[] };
259
+ classifier?: MetricsClassifier;
260
+ }
261
+
262
+ /** Who a knowledge file belongs to. */
263
+ export type KnowledgeAgentName = "master" | "designer" | "backend" | "qa";
264
+
265
+ /** One knowledge file with its size and note count, in tab order. */
266
+ export interface KnowledgeFileInfo {
267
+ agent: KnowledgeAgentName;
268
+ file: string;
269
+ label: string;
270
+ chars: number;
271
+ over: boolean;
272
+ notes: number;
273
+ }
274
+
275
+ /** One entry of a knowledge file, as the tab picks it. */
276
+ export interface KnowledgeEntryInfo {
277
+ text: string;
278
+ kind: "heading" | "bullet" | "text";
279
+ occurrence: number;
280
+ }
281
+
282
+ /** One note on a knowledge entry. */
283
+ export interface KnowledgeNoteInfo {
284
+ id: string;
285
+ agent: KnowledgeAgentName;
286
+ file: string;
287
+ entry: string;
288
+ text: string;
289
+ createdAt: string;
290
+ by?: string;
291
+ }
292
+
293
+ /** One file read as entries with their notes. */
294
+ export interface KnowledgeViewData extends KnowledgeFileInfo {
295
+ content: string;
296
+ entries: KnowledgeEntryInfo[];
297
+ attached: KnowledgeNoteInfo[];
298
+ detached: KnowledgeNoteInfo[];
299
+ }
300
+
301
+ /** An entry picked in the tab: its text, and which of several identical ones it is. */
302
+ export interface EntryRefInfo {
303
+ text: string;
304
+ occurrence: number;
305
+ }
306
+
307
+ /** Who an Excalidraw session can be assigned to. */
308
+ export type ExcalidrawAgentName = "master" | "designer" | "backend" | "qa" | "scout" | "researcher" | "quickfix" | "planner";
309
+
310
+ /** One shared session with its key hidden (`room <id>`). */
311
+ export interface ExcalidrawSessionInfo {
312
+ id: string;
313
+ name: string;
314
+ masked: string;
315
+ agents: ExcalidrawAgentName[];
316
+ contribute: boolean;
317
+ addedAt: string;
318
+ }
319
+
320
+ /** What the last check of a session found. */
321
+ export interface ExcalidrawCheck {
322
+ ok: boolean;
323
+ text: string;
324
+ }
325
+
326
+ /** `tasks.get`: one task read whole, in the terminal's wording. */
327
+ export interface TaskDetail {
328
+ /** The full request, when it says more than the title. */
329
+ request?: string;
330
+ /** The oracle's proposal, while the task has no approved plan yet. */
331
+ proposal?: string;
332
+ /** The approved plan in Markdown. */
333
+ plan?: string;
334
+ /** The plan as a checklist, in order; `current` is the step under way. */
335
+ steps: Array<{ text: string; status: "done" | "current" | "open" }>;
336
+ amendments: string[];
337
+ /** Approvals waiting on you: `kind` plus `for <domain>: <detail>`. */
338
+ waiting: Array<{ kind: string; detail: string }>;
339
+ blockers: Array<{ reason: string; need: string }>;
340
+ /** The last six runs, one line each (`✓ DEV worker · 3m 12s · …`). */
341
+ runs: string[];
342
+ }
343
+
344
+ /** `plans.get`: one saved plan. */
345
+ export interface PlanDetail {
346
+ id: string;
347
+ title: string;
348
+ status: "pending" | "started";
349
+ createdAt: string;
350
+ /** The agreed plan in Markdown. */
351
+ brief: string;
352
+ issue?: { number: number; title: string; url?: string };
353
+ /** Set when the plan was split: this is `part` of `of`, with every part's title. */
354
+ split?: { part: number; of: number; titles: string[]; after: number[] };
355
+ startedTaskId?: string;
356
+ }
357
+
358
+ /** The checks of a pull request as one state. */
359
+ export type PullChecks = "passing" | "failing" | "pending";
360
+
361
+ /** How a pull request's review stands, for the list's marks. */
362
+ export interface PullReviewMark {
363
+ status: "running" | "done" | "failed" | "cancelled" | "timeout";
364
+ verdict?: "approve" | "changes" | "comment";
365
+ /** The pull request has commits the review did not see. */
366
+ stale: boolean;
367
+ }
368
+
369
+ /** One open pull request in the Git list. */
370
+ export interface PullInfo {
371
+ number: number;
372
+ title: string;
373
+ author?: string;
374
+ headRef: string;
375
+ baseRef: string;
376
+ draft: boolean;
377
+ updatedAt?: string;
378
+ url?: string;
379
+ additions: number;
380
+ deletions: number;
381
+ changedFiles: number;
382
+ decision?: string;
383
+ checks?: PullChecks;
384
+ checkCount: number;
385
+ labels: string[];
386
+ review?: PullReviewMark;
387
+ }
388
+
389
+ /** One changed file. */
390
+ export interface PullFileInfo {
391
+ path: string;
392
+ additions: number;
393
+ deletions: number;
394
+ }
395
+
396
+ /** A review or a comment on a pull request. */
397
+ export interface PullNoteInfo {
398
+ author?: string;
399
+ body: string;
400
+ at?: string;
401
+ state?: string;
402
+ }
403
+
404
+ /** A pull request with its description, files and discussion. */
405
+ export interface PullDetailInfo extends PullInfo {
406
+ body: string;
407
+ state?: string;
408
+ mergeable?: string;
409
+ files: PullFileInfo[];
410
+ notes: PullNoteInfo[];
411
+ }
412
+
413
+ /** The agent's review of a pull request (never posted to GitHub). */
414
+ export interface PullReviewInfo {
415
+ number: number;
416
+ status: "running" | "done" | "failed" | "cancelled" | "timeout";
417
+ focus?: string;
418
+ startedAt: number;
419
+ finishedAt?: number;
420
+ steps: string[];
421
+ text?: string;
422
+ verdict?: "approve" | "changes" | "comment";
423
+ error?: string;
424
+ model?: string;
425
+ thinking?: string;
426
+ stale: boolean;
427
+ /** Kept from an earlier session rather than run now. */
428
+ saved?: boolean;
429
+ }
430
+
431
+ /** Jev's quick read of a pull request. */
432
+ export interface PullReadInfo {
433
+ number: number;
434
+ status: "running" | "done" | "failed";
435
+ line?: string;
436
+ error?: string;
437
+ read?: {
438
+ size: string;
439
+ sizeConfidence: number;
440
+ risky: number;
441
+ breaking: number;
442
+ security: number;
443
+ testsMissing: number;
444
+ kind?: string;
445
+ kindProbability?: number;
446
+ model: string;
447
+ ms: number;
448
+ };
449
+ }
450
+
451
+ /** `git.pulls`: the open pull requests, or why they could not be read. */
452
+ export interface GitPulls {
453
+ pulls: PullInfo[];
454
+ loading: boolean;
455
+ loaded: boolean;
456
+ error?: string;
457
+ }
458
+
459
+ /** `git.pull`: one pull request with our review and Jev's read of it. */
460
+ export interface GitPull {
461
+ pull: PullDetailInfo;
462
+ review?: PullReviewInfo;
463
+ read?: PullReadInfo;
464
+ }
465
+
466
+ /** One open issue in the Issues list. */
467
+ export interface IssueInfo {
468
+ number: number;
469
+ title: string;
470
+ labels: string[];
471
+ author?: string;
472
+ updatedAt?: string;
473
+ url?: string;
474
+ }
475
+
476
+ /** An issue with its description and comments. */
477
+ export interface IssueDetailInfo extends IssueInfo {
478
+ body: string;
479
+ state?: string;
480
+ comments: Array<{ author?: string; body: string; createdAt?: string }>;
481
+ }
482
+
483
+ /** `issues.list`: the open issues, or why they could not be read. */
484
+ export interface IssuesList {
485
+ issues: IssueInfo[];
486
+ loading: boolean;
487
+ loaded: boolean;
488
+ error?: string;
489
+ }
490
+
491
+ /** The calls the server answers: `POST /api/<name>` with the request as the JSON body. */
492
+ export interface Api {
493
+ "status.get": { request: Record<string, never>; result: StatusInfo };
494
+ "lobby.snapshot": { request: Record<string, never>; result: LobbySnapshot };
495
+ "lobby.history": { request: { before?: number }; result: { entries: unknown[]; hasOlder: boolean } };
496
+ "lobby.send": { request: { text: string }; result: { notice?: string } };
497
+ "lobby.abort": { request: Record<string, never>; result: Record<string, never> };
498
+ "tasks.list": { request: Record<string, never>; result: { rows: TaskRow[] } };
499
+ "tasks.archived": { request: Record<string, never>; result: { rows: TaskRow[] } };
500
+ "tasks.comments": { request: { taskId: string }; result: { comments: PlanComment[] } };
501
+ "tasks.comment": { request: { taskId: string; text: string }; result: { notice?: string } };
502
+ "tasks.archive": { request: { taskId: string }; result: { notice: string } };
503
+ "tasks.restore": { request: { taskId: string }; result: { notice: string } };
504
+ "tasks.delete": { request: { taskId: string; where: "list" | "archive" }; result: { notice: string } };
505
+ "tasks.auto": { request: { taskId: string; on: boolean }; result: { notice: string; on: boolean } };
506
+ "tasks.message": { request: { taskId: string; text: string }; result: { notice: string } };
507
+ "tasks.get": { request: { taskId: string }; result: TaskDetail };
508
+ "plans.get": { request: { planId: string }; result: PlanDetail };
509
+ "plans.start": { request: { planId: string; where: "here" | "session"; auto?: boolean }; result: { notice: string; key?: string } };
510
+ "plans.discard": { request: { planId: string }; result: { notice: string } };
511
+ "sessions.list": { request: Record<string, never>; result: { background: BackgroundSessionInfo[]; live: LiveSession[] } };
512
+ "sessions.chat": { request: { key?: string; sessionId?: string; before?: number }; result: { entries: unknown[]; hasOlder: boolean } };
513
+ "sessions.start": { request: { request?: string; planId?: string; auto?: boolean }; result: { notice: string; key?: string } };
514
+ "sessions.stop": { request: { key: string }; result: { notice: string } };
515
+ "sessions.message": { request: { key?: string; sessionId?: string; text: string }; result: { notice?: string } };
516
+ "sessions.switch": { request: { key?: string; sessionId?: string; claimTaskId?: string }; result: { notice: string } };
517
+ "sessions.answer": { request: { key: string; dialogId: string; answer: DialogAnswer }; result: { notice: string } };
518
+ "prompts.list": { request: Record<string, never>; result: { prompts: WebPrompt[] } };
519
+ "prompts.answer": { request: { id: string; answer: unknown }; result: { notice?: string } };
520
+ "prompts.dismiss": { request: { id: string }; result: Record<string, never> };
521
+ "planner.get": { request: Record<string, never>; result: PlannerSnapshot };
522
+ "planner.new": { request: { seed?: PlannerSeedInfo; seats?: PanelMember[] }; result: { notice: string } };
523
+ "planner.send": { request: { text: string }; result: { notice: string } };
524
+ "planner.toggleSeat": { request: { member: PanelMember }; result: { notice: string; seated: boolean } };
525
+ "planner.retry": { request: Record<string, never>; result: { notice: string } };
526
+ "planner.commentLine": { request: { line: string; text: string }; result: { notice: string } };
527
+ "planner.answer": { request: Record<string, never>; result: { notice: string } };
528
+ "planner.save": { request: Record<string, never>; result: { notice: string } };
529
+ "quickfix.list": { request: Record<string, never>; result: { jobs: QuickFixJob[] } };
530
+ "quickfix.submit": { request: { text: string }; result: { notice: string; id: string } };
531
+ "quickfix.cancel": { request: { id: string }; result: { notice: string } };
532
+ "quickfix.runAnyway": { request: { id: string }; result: { notice: string } };
533
+ "quickfix.movedToTask": { request: { id: string }; result: { notice: string; key?: string } };
534
+ "metrics.get": { request: { groupBy: "model" | "model-kind"; query?: string }; result: MetricsData };
535
+ "knowledge.files": { request: Record<string, never>; result: { files: KnowledgeFileInfo[] } };
536
+ "knowledge.open": { request: { agent: KnowledgeAgentName; file: string }; result: { view: KnowledgeViewData } };
537
+ "knowledge.edit": { request: { agent: KnowledgeAgentName; file: string; ref: EntryRefInfo; text: string }; result: { notice: string } };
538
+ "knowledge.add": { request: { agent: KnowledgeAgentName; file: string; ref?: EntryRefInfo; text: string }; result: { notice: string } };
539
+ "knowledge.remove": { request: { agent: KnowledgeAgentName; file: string; ref: EntryRefInfo }; result: { notice: string } };
540
+ "knowledge.replaceFile": { request: { agent: KnowledgeAgentName; file: string; text: string }; result: { notice: string } };
541
+ "knowledge.comment": { request: { agent: KnowledgeAgentName; file: string; ref: EntryRefInfo; text: string }; result: { notice: string } };
542
+ "knowledge.unnote": { request: { id: string }; result: { notice: string } };
543
+ "excalidraw.list": { request: Record<string, never>; result: { sessions: ExcalidrawSessionInfo[] } };
544
+ "excalidraw.add": { request: { link: string; name?: string }; result: { notice: string; id?: string } };
545
+ "excalidraw.create": { request: { name?: string }; result: { notice: string; id?: string } };
546
+ "excalidraw.remove": { request: { id: string }; result: { notice: string } };
547
+ "excalidraw.rename": { request: { id: string; name: string }; result: { notice: string } };
548
+ "excalidraw.toggleAgent": { request: { id: string; agent: ExcalidrawAgentName }; result: { notice: string } };
549
+ "excalidraw.toggleAll": { request: { id: string }; result: { notice: string } };
550
+ "excalidraw.toggleContribute": { request: { id: string }; result: { notice: string } };
551
+ "excalidraw.check": { request: { id: string }; result: ExcalidrawCheck };
552
+ "excalidraw.reveal": { request: { id: string }; result: { link: string } };
553
+ "git.pulls": { request: { refresh?: boolean }; result: GitPulls };
554
+ "git.pull": { request: { number: number }; result: GitPull };
555
+ "git.review": { request: { number: number; focus?: string }; result: { notice: string } };
556
+ "git.cancelReview": { request: { number: number }; result: { notice: string } };
557
+ "git.jev": { request: { number: number }; result: { notice: string } };
558
+ "issues.list": { request: { refresh?: boolean }; result: IssuesList };
559
+ "issues.get": { request: { number: number }; result: { issue: IssueDetailInfo } };
560
+ "issues.create": { request: { text: string }; result: { notice: string } };
561
+ "settings.get": { request: Record<string, never>; result: SettingsInfo };
562
+ "settings.set": { request: { patch: Record<string, unknown> }; result: { config: BotLobbyConfig } };
563
+ }
564
+
565
+ export type ApiName = keyof Api;