@pimote/pimote 0.2.0 → 0.3.1

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 (54) hide show
  1. package/README.md +43 -16
  2. package/client/build/_app/immutable/assets/0.C7loWTOC.css +2 -0
  3. package/client/build/_app/immutable/assets/2.DwPXxSa-.css +1 -0
  4. package/client/build/_app/immutable/chunks/-Lc-U-GJ.js +1 -0
  5. package/client/build/_app/immutable/chunks/{CT6ckxpD.js → CO_BwWGt.js} +1 -1
  6. package/client/build/_app/immutable/chunks/CklMSqcv.js +1 -0
  7. package/client/build/_app/immutable/chunks/D1INvMB9.js +1 -0
  8. package/client/build/_app/immutable/chunks/D1vhgXpq.js +5 -0
  9. package/client/build/_app/immutable/entry/{app.CNzpBgAg.js → app.B-HFVtpC.js} +2 -2
  10. package/client/build/_app/immutable/entry/start.DJTQ8-sD.js +1 -0
  11. package/client/build/_app/immutable/nodes/0.CepAO4xf.js +10 -0
  12. package/client/build/_app/immutable/nodes/{1.B8zmHMre.js → 1.CmxFYjRm.js} +1 -1
  13. package/client/build/_app/immutable/nodes/2.DAtqfmki.js +54 -0
  14. package/client/build/_app/version.json +1 -1
  15. package/client/build/index.html +7 -7
  16. package/package.json +7 -3
  17. package/server/dist/auto-drain-on-abort.js +49 -0
  18. package/server/dist/config.js +21 -0
  19. package/server/dist/extension-ui-bridge.js +14 -1
  20. package/server/dist/index.js +36 -1
  21. package/server/dist/message-mapper.js +38 -6
  22. package/server/dist/push-notification.js +11 -0
  23. package/server/dist/server.js +2 -2
  24. package/server/dist/session-manager.js +72 -4
  25. package/server/dist/voice/fsm/actions.js +6 -0
  26. package/server/dist/voice/fsm/events.js +7 -0
  27. package/server/dist/voice/fsm/reducer.js +74 -0
  28. package/server/dist/voice/fsm/reducers/lifecycle.js +158 -0
  29. package/server/dist/voice/fsm/reducers/streaming.js +220 -0
  30. package/server/dist/voice/fsm/reducers/walkback.js +73 -0
  31. package/server/dist/voice/fsm/state.js +21 -0
  32. package/server/dist/voice/fsm/text-extractor.js +128 -0
  33. package/server/dist/voice/index.js +336 -0
  34. package/server/dist/voice/interpreter-prompt.js +115 -0
  35. package/server/dist/voice/speechmux-client.js +153 -0
  36. package/server/dist/voice/state-machine.js +14 -0
  37. package/server/dist/voice/wait-for-idle.js +67 -0
  38. package/server/dist/voice/walk-back.js +198 -0
  39. package/server/dist/voice-orchestrator-boot.js +90 -0
  40. package/server/dist/voice-orchestrator.js +91 -0
  41. package/server/dist/ws-handler.js +112 -7
  42. package/shared/dist/index.d.ts +1 -0
  43. package/shared/dist/index.js +2 -0
  44. package/shared/dist/protocol.d.ts +614 -0
  45. package/shared/dist/protocol.js +30 -0
  46. package/client/build/_app/immutable/assets/0.DBrr7n4n.css +0 -2
  47. package/client/build/_app/immutable/assets/2.DE6k3bQj.css +0 -1
  48. package/client/build/_app/immutable/chunks/5vSSf6qG.js +0 -5
  49. package/client/build/_app/immutable/chunks/DlJOVoUQ.js +0 -1
  50. package/client/build/_app/immutable/chunks/YxmLwfhj.js +0 -1
  51. package/client/build/_app/immutable/chunks/yWVx3W2o.js +0 -1
  52. package/client/build/_app/immutable/entry/start.DYkTAHh1.js +0 -1
  53. package/client/build/_app/immutable/nodes/0.DNlQhEb_.js +0 -10
  54. package/client/build/_app/immutable/nodes/2.W9yV4-x2.js +0 -54
@@ -0,0 +1,614 @@
1
+ export interface FolderInfo {
2
+ path: string;
3
+ name: string;
4
+ activeSessionCount: number;
5
+ externalProcessCount: number;
6
+ /** @deprecated Client derives status from per-session data. Will be removed. */
7
+ activeStatus?: 'working' | 'idle' | 'attention' | null;
8
+ }
9
+ export interface SessionInfo {
10
+ id: string;
11
+ name?: string;
12
+ /** ISO 8601 date string */
13
+ created: string;
14
+ /** ISO 8601 date string */
15
+ modified: string;
16
+ messageCount: number;
17
+ firstMessage?: string;
18
+ archived?: boolean;
19
+ /** Whether this session is owned by the requesting client */
20
+ isOwnedByMe?: boolean;
21
+ /** Live status if this is an active in-memory session, null otherwise */
22
+ liveStatus?: 'working' | 'idle' | null;
23
+ /** Session working directory (may differ from the parent folder path) */
24
+ cwd?: string;
25
+ }
26
+ export interface SessionState {
27
+ model: {
28
+ provider: string;
29
+ id: string;
30
+ name: string;
31
+ } | null;
32
+ thinkingLevel: string;
33
+ /**
34
+ * Thinking levels supported by the current model, in display order.
35
+ * Server-authoritative (derived from pi-ai's per-model capabilities), so
36
+ * adding new levels (e.g. "xhigh") Just Works without client changes.
37
+ * May be missing when talking to older servers — clients should fall back.
38
+ */
39
+ availableThinkingLevels?: string[];
40
+ isStreaming: boolean;
41
+ isCompacting: boolean;
42
+ sessionFile: string | undefined;
43
+ sessionId: string;
44
+ sessionName?: string;
45
+ autoCompactionEnabled: boolean;
46
+ messageCount: number;
47
+ }
48
+ export interface PimoteMessageContent {
49
+ type: 'text' | 'thinking' | 'tool_call' | 'tool_result';
50
+ text?: string;
51
+ toolCallId?: string;
52
+ toolName?: string;
53
+ args?: unknown;
54
+ result?: unknown;
55
+ isError?: boolean;
56
+ /** True while this content block is still receiving streaming deltas. Only set on StreamingMessage blocks. */
57
+ streaming?: boolean;
58
+ }
59
+ export interface PimoteAgentMessage {
60
+ role: string;
61
+ content: PimoteMessageContent[];
62
+ /** Stable session entry ID from the pi SDK, used for targeting specific messages (e.g. fork). */
63
+ entryId?: string;
64
+ /** Present when role === 'custom' — the extension-defined message type (e.g. 'agent-complete') */
65
+ customType?: string;
66
+ /** For custom messages: if false, the message should be hidden from the UI */
67
+ display?: boolean;
68
+ /**
69
+ * True for assistant messages whose turn ended with `stopReason: 'aborted'`.
70
+ * Common in voice sessions (every barge-in produces one) — the UI renders
71
+ * these with an "interrupted" indicator rather than as empty bubbles.
72
+ */
73
+ aborted?: boolean;
74
+ [key: string]: unknown;
75
+ }
76
+ export type CardColor = 'accent' | 'success' | 'warning' | 'error' | 'muted';
77
+ export type BodySectionStyle = 'text' | 'code' | 'secondary';
78
+ export interface BodySection {
79
+ content: string;
80
+ style: BodySectionStyle;
81
+ }
82
+ export interface Card {
83
+ id: string;
84
+ color?: CardColor;
85
+ header: {
86
+ title: string;
87
+ tag?: string;
88
+ };
89
+ body?: BodySection[];
90
+ footer?: string[];
91
+ }
92
+ /** Session tree node transferred over the wire (preview-only, no full message content). */
93
+ export interface PimoteTreeNode {
94
+ id: string;
95
+ type: string;
96
+ role?: string;
97
+ customType?: string;
98
+ preview: string;
99
+ /** ISO 8601 */
100
+ timestamp: string;
101
+ label?: string;
102
+ /** ISO 8601 */
103
+ labelTimestamp?: string;
104
+ children: PimoteTreeNode[];
105
+ }
106
+ interface CommandBase {
107
+ /** Correlation ID for request/response matching */
108
+ id?: string;
109
+ /** Target session (required for session-scoped commands) */
110
+ sessionId?: string;
111
+ }
112
+ export interface PromptCommand extends CommandBase {
113
+ type: 'prompt';
114
+ message: string;
115
+ images?: string[];
116
+ streamingBehavior?: 'streaming' | 'blocking';
117
+ }
118
+ export interface SteerCommand extends CommandBase {
119
+ type: 'steer';
120
+ message: string;
121
+ }
122
+ export interface FollowUpCommand extends CommandBase {
123
+ type: 'follow_up';
124
+ message: string;
125
+ }
126
+ export interface AbortCommand extends CommandBase {
127
+ type: 'abort';
128
+ }
129
+ /**
130
+ * Diagnostic log entry from the client. The server forwards each entry to its
131
+ * own logger so client-side voice/call tracing merges into the same
132
+ * journalctl/log stream as the server-side voice extension. Fire-and-forget
133
+ * (no response). Strictly for debugging — not part of the persisted
134
+ * conversation state.
135
+ */
136
+ export interface ClientLogCommand extends CommandBase {
137
+ type: 'client_log';
138
+ /** Log severity. */
139
+ level: 'debug' | 'info' | 'warn' | 'error';
140
+ /** Free-form tag, e.g. 'voice_call', 'webrtc', 'signaling'. */
141
+ tag: string;
142
+ /** Short message. */
143
+ message: string;
144
+ /** Client wall-clock at the moment of logging (ms since epoch). */
145
+ clientTimestampMs: number;
146
+ /** Optional structured data; must be JSON-serializable. */
147
+ data?: Record<string, unknown>;
148
+ }
149
+ export interface SetModelCommand extends CommandBase {
150
+ type: 'set_model';
151
+ provider: string;
152
+ modelId: string;
153
+ }
154
+ export interface CycleModelCommand extends CommandBase {
155
+ type: 'cycle_model';
156
+ }
157
+ export interface GetAvailableModelsCommand extends CommandBase {
158
+ type: 'get_available_models';
159
+ }
160
+ export interface SetThinkingLevelCommand extends CommandBase {
161
+ type: 'set_thinking_level';
162
+ level: string;
163
+ }
164
+ export interface CycleThinkingLevelCommand extends CommandBase {
165
+ type: 'cycle_thinking_level';
166
+ }
167
+ export interface CompactCommand extends CommandBase {
168
+ type: 'compact';
169
+ customInstructions?: string;
170
+ }
171
+ export interface SetAutoCompactionCommand extends CommandBase {
172
+ type: 'set_auto_compaction';
173
+ enabled: boolean;
174
+ }
175
+ export interface GetStateCommand extends CommandBase {
176
+ type: 'get_state';
177
+ }
178
+ export interface GetMessagesCommand extends CommandBase {
179
+ type: 'get_messages';
180
+ }
181
+ export interface NewSessionCommand extends CommandBase {
182
+ type: 'new_session';
183
+ }
184
+ export interface GetSessionStatsCommand extends CommandBase {
185
+ type: 'get_session_stats';
186
+ }
187
+ export interface GetSessionMetaCommand extends CommandBase {
188
+ type: 'get_session_meta';
189
+ }
190
+ export interface SessionMeta {
191
+ gitBranch: string | null;
192
+ contextUsage: {
193
+ percent: number | null;
194
+ contextWindow: number;
195
+ } | null;
196
+ }
197
+ export interface GetCommandsCommand extends CommandBase {
198
+ type: 'get_commands';
199
+ }
200
+ export interface CompleteArgsCommand extends CommandBase {
201
+ type: 'complete_args';
202
+ commandName: string;
203
+ prefix: string;
204
+ }
205
+ export interface CommandInfo {
206
+ name: string;
207
+ description: string;
208
+ hasArgCompletions: boolean;
209
+ }
210
+ export interface AutocompleteResponseItem {
211
+ value: string;
212
+ label: string;
213
+ description?: string;
214
+ }
215
+ export interface SetSessionNameCommand extends CommandBase {
216
+ type: 'set_session_name';
217
+ name: string;
218
+ }
219
+ export interface RenameSessionCommand extends CommandBase {
220
+ type: 'rename_session';
221
+ folderPath: string;
222
+ sessionId: string;
223
+ name: string;
224
+ }
225
+ export interface DequeueSteeringCommand extends CommandBase {
226
+ type: 'dequeue_steering';
227
+ }
228
+ export interface ForkCommand extends CommandBase {
229
+ type: 'fork';
230
+ entryId: string;
231
+ }
232
+ export interface NavigateTreeCommand extends CommandBase {
233
+ type: 'navigate_tree';
234
+ targetId: string;
235
+ summarize?: boolean;
236
+ customInstructions?: string;
237
+ replaceInstructions?: boolean;
238
+ label?: string;
239
+ }
240
+ export interface SetTreeLabelCommand extends CommandBase {
241
+ type: 'set_tree_label';
242
+ entryId: string;
243
+ /** Empty string or undefined clears the label. */
244
+ label?: string;
245
+ }
246
+ export interface CreateProjectCommand extends CommandBase {
247
+ type: 'create_project';
248
+ /** Must be one of the configured roots */
249
+ root: string;
250
+ /** Folder name — no slashes, non-empty */
251
+ name: string;
252
+ }
253
+ export interface ListFoldersCommand extends CommandBase {
254
+ type: 'list_folders';
255
+ }
256
+ export interface ListSessionsCommand extends CommandBase {
257
+ type: 'list_sessions';
258
+ folderPath: string;
259
+ includeArchived?: boolean;
260
+ }
261
+ export interface OpenSessionCommand extends CommandBase {
262
+ type: 'open_session';
263
+ folderPath: string;
264
+ sessionId?: string;
265
+ /** Last cursor seen by the client; when present the server may attempt incremental replay. */
266
+ lastCursor?: number;
267
+ /** Force takeover if the session is owned by another client */
268
+ force?: boolean;
269
+ }
270
+ export type RestoreMode = 'incremental_replay' | 'full_resync_no_cursor' | 'full_resync_cursor_stale' | 'disk_full_resync';
271
+ export interface OpenSessionResponseData {
272
+ sessionId: string;
273
+ folderPath?: string;
274
+ restoreMode?: RestoreMode;
275
+ }
276
+ export interface CloseSessionCommand extends CommandBase {
277
+ type: 'close_session';
278
+ }
279
+ export interface DeleteSessionCommand extends CommandBase {
280
+ type: 'delete_session';
281
+ folderPath: string;
282
+ sessionId: string;
283
+ }
284
+ export interface ArchiveSessionCommand extends CommandBase {
285
+ type: 'archive_session';
286
+ folderPath: string;
287
+ sessionIds: string[];
288
+ archived: boolean;
289
+ }
290
+ export interface TakeoverFolderCommand extends CommandBase {
291
+ type: 'takeover_folder';
292
+ folderPath: string;
293
+ }
294
+ export interface ViewSessionCommand extends CommandBase {
295
+ type: 'view_session';
296
+ sessionId: string;
297
+ }
298
+ export interface RegisterPushCommand extends CommandBase {
299
+ type: 'register_push';
300
+ subscription: {
301
+ endpoint: string;
302
+ keys: {
303
+ p256dh: string;
304
+ auth: string;
305
+ };
306
+ };
307
+ }
308
+ export interface UnregisterPushCommand extends CommandBase {
309
+ type: 'unregister_push';
310
+ endpoint: string;
311
+ }
312
+ export interface KillConflictingProcessesCommand extends CommandBase {
313
+ type: 'kill_conflicting_processes';
314
+ sessionId: string;
315
+ pids: number[];
316
+ }
317
+ export interface KillConflictingSessionsCommand extends CommandBase {
318
+ type: 'kill_conflicting_sessions';
319
+ sessionIds: string[];
320
+ }
321
+ export interface CallBindCommand extends CommandBase {
322
+ type: 'call_bind';
323
+ id: string;
324
+ sessionId: string;
325
+ /** If true, displace an existing call owner on this session. */
326
+ force?: boolean;
327
+ }
328
+ export interface CallEndCommand extends CommandBase {
329
+ type: 'call_end';
330
+ id: string;
331
+ sessionId: string;
332
+ }
333
+ /** Reason codes returned in PimoteResponse.error for a failed call_bind. */
334
+ export type CallBindErrorCode = 'call_bind_failed_session_not_found' | 'call_bind_failed_owned' | 'call_bind_failed_internal';
335
+ /** Reason code returned when an extension attempts a UI bridge call during a voice call. */
336
+ export declare const UI_BRIDGE_DISABLED_IN_VOICE_MODE = "ui_bridge_disabled_in_voice_mode";
337
+ export interface ExtensionUiResponseCommand extends CommandBase {
338
+ type: 'extension_ui_response';
339
+ requestId: string;
340
+ value?: string;
341
+ confirmed?: boolean;
342
+ cancelled?: boolean;
343
+ }
344
+ export type PimoteCommand = PromptCommand | SteerCommand | FollowUpCommand | AbortCommand | ClientLogCommand | SetModelCommand | CycleModelCommand | GetAvailableModelsCommand | SetThinkingLevelCommand | CycleThinkingLevelCommand | CompactCommand | SetAutoCompactionCommand | GetStateCommand | GetMessagesCommand | NewSessionCommand | GetSessionStatsCommand | GetSessionMetaCommand | GetCommandsCommand | CompleteArgsCommand | SetSessionNameCommand | DequeueSteeringCommand | ForkCommand | NavigateTreeCommand | SetTreeLabelCommand | CreateProjectCommand | RenameSessionCommand | ListFoldersCommand | ListSessionsCommand | OpenSessionCommand | CloseSessionCommand | DeleteSessionCommand | ArchiveSessionCommand | TakeoverFolderCommand | ViewSessionCommand | RegisterPushCommand | UnregisterPushCommand | KillConflictingProcessesCommand | KillConflictingSessionsCommand | ExtensionUiResponseCommand | CallBindCommand | CallEndCommand;
345
+ interface SessionEventBase {
346
+ /** Which session produced this event */
347
+ sessionId: string;
348
+ /** Monotonically increasing cursor for reconnect replay */
349
+ cursor: number;
350
+ /** ISO 8601 server-side timestamp */
351
+ timestamp?: string;
352
+ }
353
+ export interface AgentStartEvent extends SessionEventBase {
354
+ type: 'agent_start';
355
+ }
356
+ export interface AgentEndEvent extends SessionEventBase {
357
+ type: 'agent_end';
358
+ error?: string;
359
+ /** Entry IDs for all messages, zipped 1:1 with the session message list.
360
+ * Sent so the client can enable fork targets on messages received via
361
+ * streaming events (which don't carry entry IDs individually). */
362
+ messageEntryIds?: string[];
363
+ }
364
+ export interface TurnStartEvent extends SessionEventBase {
365
+ type: 'turn_start';
366
+ }
367
+ export interface TurnEndEvent extends SessionEventBase {
368
+ type: 'turn_end';
369
+ }
370
+ export interface MessageStartEvent extends SessionEventBase {
371
+ type: 'message_start';
372
+ role: string;
373
+ }
374
+ export interface MessageUpdateEvent extends SessionEventBase {
375
+ type: 'message_update';
376
+ contentIndex: number;
377
+ subtype: 'start' | 'delta' | 'end';
378
+ content: {
379
+ type: 'text' | 'thinking' | 'tool_call';
380
+ text: string;
381
+ };
382
+ /** Present only on tool_call start */
383
+ toolCallId?: string;
384
+ /** Present only on tool_call start */
385
+ toolName?: string;
386
+ }
387
+ /**
388
+ * Shape shared by both streaming (in-progress) and finalized messages.
389
+ * The streaming message uses this during accumulation; on message_end
390
+ * the finalized PimoteAgentMessage replaces it.
391
+ */
392
+ export interface StreamingMessage {
393
+ role: string;
394
+ content: PimoteMessageContent[];
395
+ customType?: string;
396
+ }
397
+ export interface MessageEndEvent extends SessionEventBase {
398
+ type: 'message_end';
399
+ message: PimoteAgentMessage;
400
+ }
401
+ export interface ToolExecutionStartEvent extends SessionEventBase {
402
+ type: 'tool_execution_start';
403
+ toolName: string;
404
+ toolCallId: string;
405
+ args: unknown;
406
+ }
407
+ export interface ToolExecutionUpdateEvent extends SessionEventBase {
408
+ type: 'tool_execution_update';
409
+ toolCallId: string;
410
+ content: string;
411
+ }
412
+ export interface ToolExecutionEndEvent extends SessionEventBase {
413
+ type: 'tool_execution_end';
414
+ toolCallId: string;
415
+ result: unknown;
416
+ isError?: boolean;
417
+ }
418
+ export interface AutoCompactionStartEvent extends SessionEventBase {
419
+ type: 'auto_compaction_start';
420
+ reason: 'threshold' | 'overflow';
421
+ }
422
+ export interface AutoCompactionEndEvent extends SessionEventBase {
423
+ type: 'auto_compaction_end';
424
+ result: unknown;
425
+ aborted: boolean;
426
+ willRetry: boolean;
427
+ errorMessage?: string;
428
+ }
429
+ export interface AutoRetryStartEvent extends SessionEventBase {
430
+ type: 'auto_retry_start';
431
+ attempt: number;
432
+ maxAttempts: number;
433
+ delayMs: number;
434
+ errorMessage: string;
435
+ }
436
+ export interface AutoRetryEndEvent extends SessionEventBase {
437
+ type: 'auto_retry_end';
438
+ success: boolean;
439
+ attempt: number;
440
+ finalError?: string;
441
+ }
442
+ export interface ExtensionErrorEvent extends SessionEventBase {
443
+ type: 'extension_error';
444
+ error: string;
445
+ extensionName?: string;
446
+ }
447
+ export interface TreeNavigationStartEvent extends SessionEventBase {
448
+ type: 'tree_navigation_start';
449
+ targetId: string;
450
+ summarizing: boolean;
451
+ }
452
+ export interface TreeNavigationEndEvent extends SessionEventBase {
453
+ type: 'tree_navigation_end';
454
+ }
455
+ /** All session-scoped events (mirror of pi SDK's AgentSessionEvent) */
456
+ export type PimoteSessionEvent = AgentStartEvent | AgentEndEvent | TurnStartEvent | TurnEndEvent | MessageStartEvent | MessageUpdateEvent | MessageEndEvent | ToolExecutionStartEvent | ToolExecutionUpdateEvent | ToolExecutionEndEvent | AutoCompactionStartEvent | AutoCompactionEndEvent | AutoRetryStartEvent | AutoRetryEndEvent | ExtensionErrorEvent | TreeNavigationStartEvent | TreeNavigationEndEvent;
457
+ export interface SessionConflictEvent {
458
+ type: 'session_conflict';
459
+ sessionId: string;
460
+ processes: Array<{
461
+ pid: number;
462
+ command: string;
463
+ }>;
464
+ remoteSessions?: Array<{
465
+ sessionId: string;
466
+ status: 'working' | 'idle';
467
+ }>;
468
+ }
469
+ export interface ExtensionUiRequestEvent {
470
+ type: 'extension_ui_request';
471
+ sessionId: string;
472
+ requestId: string;
473
+ method: string;
474
+ /** Method-specific fields (e.g., prompt text, options, etc.) */
475
+ [key: string]: unknown;
476
+ }
477
+ export interface SessionOpenedEvent {
478
+ type: 'session_opened';
479
+ sessionId: string;
480
+ folder: FolderInfo;
481
+ }
482
+ export interface SessionClosedEvent {
483
+ type: 'session_closed';
484
+ sessionId: string;
485
+ reason?: 'displaced' | 'killed' | 'replaced';
486
+ }
487
+ export interface SessionDeletedEvent {
488
+ type: 'session_deleted';
489
+ sessionId: string;
490
+ folderPath: string;
491
+ }
492
+ export interface SessionRenamedEvent {
493
+ type: 'session_renamed';
494
+ sessionId: string;
495
+ folderPath: string;
496
+ name: string;
497
+ }
498
+ export interface SessionArchivedEvent {
499
+ type: 'session_archived';
500
+ sessionId: string;
501
+ folderPath: string;
502
+ archived: boolean;
503
+ }
504
+ export interface SessionReplacedEvent {
505
+ type: 'session_replaced';
506
+ oldSessionId: string;
507
+ newSessionId: string;
508
+ folder: FolderInfo;
509
+ }
510
+ export interface SessionStateChangedEvent {
511
+ type: 'session_state_changed';
512
+ sessionId: string;
513
+ folderPath: string;
514
+ liveStatus: 'working' | 'idle' | null;
515
+ connectedClientId: string | null;
516
+ folderActiveSessionCount: number;
517
+ folderActiveStatus: 'working' | 'idle' | 'attention' | null;
518
+ /** Current git branch for the session folder (null when unavailable). */
519
+ gitBranch?: string | null;
520
+ /** Session display name (from setSessionName). */
521
+ sessionName?: string;
522
+ /** First user message text, for sidebar display. */
523
+ firstMessage?: string;
524
+ /** Total message count. */
525
+ messageCount?: number;
526
+ }
527
+ export interface ConnectionRestoredEvent {
528
+ type: 'connection_restored';
529
+ sessionId: string;
530
+ }
531
+ export interface SessionRestoreEvent {
532
+ type: 'session_restore';
533
+ sessionId: string;
534
+ mode: RestoreMode;
535
+ status: 'started' | 'completed';
536
+ }
537
+ export interface BufferedEventsEvent {
538
+ type: 'buffered_events';
539
+ sessionId: string;
540
+ events: PimoteSessionEvent[];
541
+ }
542
+ export interface FullResyncEvent {
543
+ type: 'full_resync';
544
+ sessionId: string;
545
+ state: SessionState;
546
+ messages: PimoteAgentMessage[];
547
+ }
548
+ export interface PanelUpdateEvent {
549
+ type: 'panel_update';
550
+ sessionId: string;
551
+ cards: Card[];
552
+ }
553
+ /**
554
+ * Success response to a CallBindCommand. Carries the per-call WebRTC
555
+ * signalling endpoint the client should connect to. The PWA obtains
556
+ * Cloudflare Realtime TURN credentials directly from speechmux in its
557
+ * `/signal` `session` response; pimote no longer mints or proxies either
558
+ * the per-call auth token (Cloudflare Access is the auth boundary on
559
+ * `/signal`) or TURN creds.
560
+ *
561
+ * Failed binds return a standard PimoteResponse with `success: false` and an
562
+ * error string that is one of CallBindErrorCode.
563
+ */
564
+ export interface CallBindResponse {
565
+ type: 'call_bind_response';
566
+ /** Correlates with the originating CallBindCommand.id */
567
+ id: string;
568
+ sessionId: string;
569
+ webrtcSignalUrl: string;
570
+ }
571
+ /** The peer connection to speechmux has been established. */
572
+ export interface CallReadyEvent {
573
+ type: 'call_ready';
574
+ sessionId: string;
575
+ }
576
+ export type CallEndReason = 'user_hangup' | 'displaced' | 'server_ended' | 'error';
577
+ export interface CallEndedEvent {
578
+ type: 'call_ended';
579
+ sessionId: string;
580
+ reason: CallEndReason;
581
+ }
582
+ export type CallStatus = 'binding' | 'ringing' | 'connected' | 'ended';
583
+ export interface CallStatusEvent {
584
+ type: 'call_status';
585
+ sessionId: string;
586
+ status: CallStatus;
587
+ }
588
+ /**
589
+ * Custom entry customType appended by the voice extension when it observes a
590
+ * speechmux rollback/abort frame. The payload records the user-heard watermark
591
+ * so persisted scrollback carries evidence of the interrupt even though pi
592
+ * itself leaves no assistant entry for an aborted turn.
593
+ */
594
+ export declare const VOICE_INTERRUPT_CUSTOM_TYPE = "pimote:voice:interrupt";
595
+ export interface VoiceInterruptEntryData {
596
+ /** Characters the user actually heard before the cutoff. Empty for pure abort. */
597
+ heard_text: string;
598
+ kind: 'abort' | 'rollback';
599
+ }
600
+ export interface VersionMismatchEvent {
601
+ type: 'version_mismatch';
602
+ serverVersion: string;
603
+ }
604
+ export type PimoteEvent = PimoteSessionEvent | ExtensionUiRequestEvent | SessionConflictEvent | SessionOpenedEvent | SessionClosedEvent | SessionDeletedEvent | SessionRenamedEvent | SessionArchivedEvent | SessionReplacedEvent | SessionStateChangedEvent | ConnectionRestoredEvent | SessionRestoreEvent | BufferedEventsEvent | FullResyncEvent | PanelUpdateEvent | CallBindResponse | CallReadyEvent | CallEndedEvent | CallStatusEvent | VersionMismatchEvent;
605
+ export interface PimoteResponse<T = unknown> {
606
+ /** Matches the `id` from the originating PimoteCommand */
607
+ id: string;
608
+ success: boolean;
609
+ data?: T;
610
+ error?: string;
611
+ }
612
+ export type PimoteServerMessage = PimoteEvent | PimoteResponse;
613
+ export type PimoteClientMessage = PimoteCommand;
614
+ export {};
@@ -0,0 +1,30 @@
1
+ // ============================================================================
2
+ // Pimote Wire Protocol Types
3
+ // All WebSocket messages between client and server.
4
+ // Self-contained — no imports from the pi SDK.
5
+ //
6
+ // KEEP IN SYNC WITH: mobile/android/app/src/main/kotlin/com/pimote/android/protocol/Protocol.kt
7
+ //
8
+ // The native Android client hand-mirrors a subset of these types as Kotlin
9
+ // data classes. Any change to the following types MUST be reflected on the
10
+ // Kotlin side (no codegen):
11
+ // - CallBindCommand / CallEndCommand / CallBindResponse
12
+ // - CallReadyEvent / CallEndedEvent / CallStatusEvent / CallEndReason / CallStatus
13
+ // - CallBindErrorCode
14
+ // - OpenSessionCommand / OpenSessionResponseData
15
+ // - ListFoldersCommand / ListSessionsCommand
16
+ // - FolderInfo / SessionInfo
17
+ // - SessionOpenedEvent / SessionRenamedEvent / SessionArchivedEvent /
18
+ // SessionDeletedEvent / SessionReplacedEvent
19
+ // See docs/plans/native-android-client.md §Protocol DTOs.
20
+ // ============================================================================
21
+ /** Reason code returned when an extension attempts a UI bridge call during a voice call. */
22
+ export const UI_BRIDGE_DISABLED_IN_VOICE_MODE = 'ui_bridge_disabled_in_voice_mode';
23
+ // -- Voice persisted custom entries --
24
+ /**
25
+ * Custom entry customType appended by the voice extension when it observes a
26
+ * speechmux rollback/abort frame. The payload records the user-heard watermark
27
+ * so persisted scrollback carries evidence of the interrupt even though pi
28
+ * itself leaves no assistant entry for an aborted turn.
29
+ */
30
+ export const VOICE_INTERRUPT_CUSTOM_TYPE = 'pimote:voice:interrupt';