返回 DeepSeek-Reasonix
types.ts
根目录 / desktop / frontend / src / lib / types.ts
1 // Wire contract — mirrors desktop/wire.go (itself mirroring internal/serve/wire.go).
2 // One event channel carries every kind; `kind` discriminates the payload.
3
4 import type { Todo } from "./tools";
5
6 export type EventKind =
7 | "turn_started"
8 | "reasoning"
9 | "text"
10 | "message"
11 | "tool_dispatch"
12 | "tool_result"
13 | "tool_progress"
14 | "usage"
15 | "notice"
16 | "phase"
17 | "approval_request"
18 | "ask_request"
19 | "turn_done"
20 | "compaction_started"
21 | "compaction_done"
22 | "mcp_surface_ready"
23 | "retrying"
24 | "steer"
25 | "guardian_assessment"
26 | "extension_surface"
27 | "extension_status"
28 | "stream_attempt";
29
30 export type StreamAttemptAction = "begin" | "discard" | "commit";
31
32 export interface WireStreamAttempt {
33 id: string;
34 action: StreamAttemptAction;
35 attempt?: number;
36 max?: number;
37 /** Fixed enum only: connection_reset | premature_eof | idle_timeout */
38 reason?: string;
39 }
40
41 export interface WireCompaction {
42 trigger?: string; // "auto" | "manual"
43 messages?: number; // done: how many messages were folded into the summary
44 summary?: string; // done: the briefing (empty on an aborted pass)
45 archive?: string; // done: archive path, if any
46 }
47
48 export interface WireProfile {
49 model?: string;
50 effort?: string;
51 }
52
53 export interface WireShellExecution {
54 kind?: string;
55 shell?: string;
56 shellVersion?: string;
57 platform?: string;
58 supportsAndAnd?: boolean;
59 state?: string;
60 failurePhase?: string;
61 exitCode?: number;
62 outputTail?: string;
63 mutationRisk?: string;
64 verification?: string;
65 durationMs?: number;
66 }
67
68 export interface WireTool {
69 id?: string;
70 name: string;
71 args?: string;
72 resolvedName?: string;
73 capabilityId?: string;
74 output?: string;
75 err?: string;
76 readOnly: boolean;
77 truncated?: boolean;
78 durationMs?: number;
79 partial?: boolean; // an early dispatch (name only) — a full one with args follows
80 argChars?: number; // partial only: cumulative argument chars streamed so far
81 refreshed?: boolean; // same-ID full dispatch with a preview recomputed after an earlier write
82 parentId?: string; // set on a sub-agent's calls — the parent `task` call's id
83 /** Host-local stream_attempt id for speculative parent partials only. */
84 attemptId?: string;
85 diff?: string;
86 added?: number;
87 removed?: number;
88 profile?: WireProfile; // subagent model/effort resolved for this call
89 execution?: WireShellExecution; // local shell metadata; never provider-visible
90 }
91
92 export interface WireCacheDiagnostics {
93 prefixHash: string;
94 prefixChanged: boolean;
95 prefixChangeReasons?: string[];
96 systemHash: string;
97 toolsHash: string;
98 logRewriteVersion: number;
99 toolSchemaTokens: number;
100 cacheMissTokens: number;
101 cacheHitTokens: number;
102 }
103
104 export interface WireUsage {
105 promptTokens: number;
106 completionTokens: number;
107 totalTokens: number;
108 cacheHitTokens: number;
109 cacheMissTokens: number;
110 reasoningTokens?: number;
111 estimated?: boolean;
112 source?: string;
113 cacheDiagnostics?: WireCacheDiagnostics;
114 // Session-cumulative cache tokens — the status bar shows the aggregate
115 // hit-rate (Σhit/Σ(hit+miss)), steadier than the single-turn cacheHitTokens.
116 sessionCacheHitTokens: number;
117 sessionCacheMissTokens: number;
118 /** Latest single-request shape for context gauges; omit → use billable totals. */
119 contextPromptTokens?: number;
120 contextCompletionTokens?: number;
121 contextReasoningTokens?: number;
122 contextCacheHitTokens?: number;
123 contextCacheMissTokens?: number;
124 cost?: number;
125 currency?: string;
126 // Deprecated compatibility alias. Prefer cost + currency.
127 costUsd?: number;
128 }
129
130 export interface WireRecoveryApproval {
131 source_agent?: string;
132 failed_tool?: string;
133 failed_summary?: string;
134 diagnosis?: string;
135 next_tool?: string;
136 next_action?: string;
137 change_kind?: string;
138 change_rationale?: string;
139 review_rationale?: string;
140 plan_before?: string;
141 plan_after?: string;
142 can_grant_task?: boolean;
143 task_grant_scope?: string;
144 }
145
146 export interface WireApproval {
147 id: string;
148 tool: string;
149 subject: string;
150 reason?: string;
151 fresh?: boolean;
152 kind?: "tool" | "plan" | "recovery" | string;
153 recovery?: WireRecoveryApproval;
154 }
155
156 export interface WireGuardian {
157 id: string;
158 tool: string;
159 subject: string;
160 outcome: string;
161 risk_level?: string;
162 user_authorization?: string;
163 rationale?: string;
164 duration_ms?: number;
165 usage?: WireUsage;
166 }
167
168 export interface WireDecisionReceipt {
169 id: string;
170 kind: string;
171 tool?: string;
172 subject?: string;
173 outcome: string;
174 }
175
176 export interface WireAskOption {
177 label: string;
178 description?: string;
179 }
180
181 export interface WireAskQuestion {
182 id: string;
183 header?: string;
184 prompt: string;
185 options: WireAskOption[];
186 multi?: boolean;
187 }
188
189 export interface WireAsk {
190 id: string;
191 questions: WireAskQuestion[];
192 }
193
194 // Extension UI surfaces (stage 8a) — structured-only documents published by
195 // extension sidecars through the host UI hub. Exactly one sub-struct is set,
196 // selected by `kind`.
197 export interface WireExtensionStatus {
198 label: string;
199 detail?: string;
200 severity?: string; // "info" | "warn" | "error"
201 progress?: number;
202 }
203
204 export interface WireExtensionKeyValue {
205 key: string;
206 value: string;
207 }
208
209 export interface WireExtensionActionRef {
210 actionId: string;
211 label: string;
212 }
213
214 export interface WireExtensionCard {
215 title?: string;
216 markdown?: string;
217 text?: string;
218 fields?: WireExtensionKeyValue[];
219 progress?: number;
220 actions?: WireExtensionActionRef[];
221 }
222
223 export interface WireExtensionFormField {
224 key: string;
225 label?: string;
226 kind?: string; // "confirm" | "input" | "select" | "multiselect"
227 options?: string[];
228 default?: unknown;
229 required?: boolean;
230 }
231
232 export interface WireExtensionForm {
233 title?: string;
234 message?: string;
235 fields: WireExtensionFormField[];
236 }
237
238 export interface WireExtensionNotification {
239 title: string;
240 body?: string;
241 severity?: string; // "info" | "warn" | "error"
242 }
243
244 export interface WireExtensionSurface {
245 pluginId: string;
246 surfaceId: string;
247 sessionId?: string;
248 generation?: number;
249 kind: string; // "status" | "card" | "form" | "notification"
250 status?: WireExtensionStatus;
251 card?: WireExtensionCard;
252 form?: WireExtensionForm;
253 notification?: WireExtensionNotification;
254 }
255
256 // ExtensionActionView is one handshake-declared extension UI action, the JSON
257 // twin of desktop's ExtensionActionView (stage 8b2). Slash is the public
258 // invocation name, "/<plugin>:<action>".
259 export interface ExtensionActionView {
260 plugin: string;
261 action: string;
262 slash: string;
263 description?: string;
264 }
265
266 // QuestionAnswer is the reply for one question, sent back via AnswerQuestion.
267 export interface QuestionAnswer {
268 questionId: string;
269 selected: string[];
270 }
271
272 export interface MemoryCitation {
273 id?: string;
274 source: string;
275 lineStart?: number;
276 lineEnd?: number;
277 note?: string;
278 kind?: string;
279 }
280
281 export interface WireEvent {
282 kind: EventKind;
283 text?: string;
284 detail?: string;
285 // Stable notice id for localization; empty/absent = localize by text match.
286 code?: string;
287 reasoning?: string;
288 memoryCitations?: MemoryCitation[];
289 level?: "info" | "warn";
290 tool?: WireTool;
291 usage?: WireUsage;
292 approval?: WireApproval;
293 ask?: WireAsk;
294 compaction?: WireCompaction;
295 guardian?: WireGuardian;
296 decisionReceipt?: WireDecisionReceipt;
297 extension?: WireExtensionSurface;
298 err?: string;
299 outcome?: "final_readiness" | "recovery_paused";
300 readiness?: WireFinalReadiness;
301 retryAttempt?: number;
302 retryMax?: number;
303 /** Optional: "headers" | "stream". Older clients ignore unknown fields. */
304 retryScope?: "headers" | "stream";
305 streamAttempt?: WireStreamAttempt;
306 // Tab routing: set by the Go-side tabEventSink so multi-tab frontends
307 // route each event to the correct per-tab reducer.
308 tabId?: string;
309 runtimeEpoch?: string;
310 sessionHitTokens?: number;
311 sessionMissTokens?: number;
312 sessionCost?: number;
313 sessionCurrency?: string;
314 // Deprecated compatibility alias. Prefer sessionCost + sessionCurrency.
315 sessionCostUsd?: number;
316 }
317
318 export type SessionRuntimePhase = "starting" | "ready" | "lease_blocked" | "failed" | "closing";
319
320 export interface SessionRuntimeIssue {
321 code: "session_lease_held" | "startup_failed";
322 message: string;
323 retryable: boolean;
324 holderPid?: number;
325 holderHost?: string;
326 acquiredAt?: string;
327 }
328
329 export interface SessionRuntimeView {
330 phase: SessionRuntimePhase;
331 epoch: string;
332 issue?: SessionRuntimeIssue;
333 }
334
335 export interface WireFinalReadiness {
336 attempts?: number;
337 missing?: string[];
338 }
339
340 // Tab management types (desktop/tabs.go).
341 export interface TabMeta {
342 id: string;
343 tabType?: "session" | "file";
344 scope: string;
345 workspaceRoot: string;
346 workspaceName: string;
347 workspacePath?: string;
348 gitBranch?: string;
349 isolatedWorktree?: boolean;
350 topicId: string;
351 topicTitle: string;
352 sessionPath?: string;
353 readOnly?: boolean;
354 filePath?: string;
355 projectColor?: string;
356 label: string;
357 ready: boolean;
358 runtime?: SessionRuntimeView;
359 running: boolean;
360 pendingPrompt?: boolean;
361 backgroundJobs?: number;
362 cancelRequested?: boolean;
363 cancellable?: boolean;
364 mode: Mode;
365 collaborationMode?: CollaborationMode;
366 toolApprovalMode?: ToolApprovalMode;
367 tokenMode?: TokenMode;
368 goal?: string;
369 goalStatus?: GoalStatus;
370 autoResearch?: AutoResearchCompactView;
371 recovered?: boolean;
372 recoveryReason?: string;
373 recoveryDigest?: string;
374 recoveryParentId?: string;
375 startupErr?: string;
376 active: boolean;
377 cwd: string;
378 }
379
380 export interface TerminalSessionView {
381 id: string;
382 title: string;
383 shell: string;
384 cwd: string;
385 createdAt: number;
386 exitCode?: number;
387 running: boolean;
388 }
389
390 export interface TerminalShellView {
391 id: string;
392 label: string;
393 }
394
395 export interface TerminalWorkspaceView {
396 available: boolean;
397 readOnly: boolean;
398 reason?: string;
399 sessions: TerminalSessionView[];
400 shells: TerminalShellView[];
401 }
402
403 export interface ProjectNode {
404 key: string;
405 kind: "project" | "topic" | "session" | "global_folder" | "global_topic" | "global_session";
406 label: string;
407 root?: string;
408 topicId?: string;
409 sessionPath?: string;
410 projectColor?: string;
411 turns?: number;
412 createdAt?: number;
413 lastActivityAt?: number;
414 open?: boolean;
415 running?: boolean;
416 status?: ProjectTopicStatus;
417 pinned?: boolean;
418 recovered?: boolean;
419 recoveryReason?: string;
420 recoveryDigest?: string;
421 recoveryParentId?: string;
422 isolatedWorktree?: boolean;
423 children?: ProjectNode[];
424 }
425
426 export interface DeliveryWorktreeAvailability {
427 available: boolean;
428 reason?: string;
429 repoRoot?: string;
430 branch?: string;
431 sourceDirty?: boolean;
432 }
433
434 export interface DeliveryWorktreeOpenResult {
435 workspaceRoot: string;
436 worktreeRoot: string;
437 sourceRoot: string;
438 branch: string;
439 sourceDirty: boolean;
440 tab: TabMeta;
441 }
442
443 export type ProjectTopicStatus = "thinking" | "streaming" | "waiting_confirmation" | "background_job" | "paused" | "error";
444
445 export interface TopicMeta {
446 id: string;
447 title: string;
448 createdAt: number;
449 }
450
451 export interface SessionRecoveryEvent {
452 originalPath?: string;
453 recoveryPath: string;
454 scope?: string;
455 workspaceRoot?: string;
456 topicId?: string;
457 topicTitle?: string;
458 recoveryReason?: string;
459 recoveryDigest?: string;
460 recoveryParentId?: string;
461 existing?: boolean;
462 }
463
464 export interface SessionRecoveryFailedEvent {
465 reason?: "lease_held" | "lease_unavailable" | string;
466 }
467
468 export interface ContextPanelInfo {
469 usedTokens: number;
470 windowTokens: number;
471 promptTokens: number;
472 completionTokens: number;
473 totalTokens: number;
474 reasoningTokens: number;
475 cacheHitTokens: number;
476 cacheMissTokens: number;
477 estimated?: boolean;
478 sessionCacheHitTokens: number;
479 sessionCacheMissTokens: number;
480 sessionCompletionTokens: number;
481 sessionEstimated?: boolean;
482 requestCount?: number;
483 elapsedMs?: number;
484 sessionCost?: number;
485 sessionCurrency?: string;
486 // Deprecated compatibility alias. Prefer sessionCost + sessionCurrency.
487 sessionCostUsd?: number;
488 sources?: Record<string, UsageSourceStats>;
489 mock?: boolean;
490 readFiles: ReadFileRecord[];
491 changedFiles: ChangedFileInfo[];
492 }
493
494 export interface UsageSourceStats {
495 promptTokens: number;
496 completionTokens: number;
497 totalTokens: number;
498 reasoningTokens: number;
499 cacheHitTokens: number;
500 cacheMissTokens: number;
501 estimated?: boolean;
502 requestCount: number;
503 sessionCost?: number;
504 sessionCurrency?: string;
505 sessionCostUsd?: number;
506 }
507
508 export interface ReadFileRecord {
509 path: string;
510 turn: number;
511 time: number;
512 offset?: number;
513 limit?: number;
514 truncated?: boolean;
515 }
516
517 export interface ChangedFileInfo {
518 path: string;
519 oldPath?: string;
520 sources: string[];
521 gitStatus?: string;
522 turns: number[];
523 latestPrompt?: string;
524 latestTime?: number;
525 }
526
527 // Bound-method payloads (desktop/app.go).
528 export interface HistoryMessage {
529 role: string;
530 content: string;
531 detail?: string;
532 code?: string;
533 submitText?: string;
534 checkpointTurn?: number;
535 createdAt?: number;
536 reasoning?: string;
537 workDurationMs?: number;
538 memoryCitations?: MemoryCitation[];
539 level?: "info" | "warn";
540 toolCalls?: HistoryToolCall[];
541 toolCallId?: string;
542 toolName?: string;
543 toolResultArchived?: boolean;
544 toolResultError?: string;
545 execution?: WireShellExecution;
546 pending?: boolean;
547 trigger?: string;
548 messages?: number;
549 summary?: string;
550 archive?: string;
551 decisionReceipt?: WireDecisionReceipt;
552 }
553
554 export interface HistoryToolCall {
555 id: string;
556 name: string;
557 arguments: string;
558 resolvedName?: string;
559 capabilityId?: string;
560 resolvedReadOnly?: boolean;
561 subject?: string;
562 summary?: string;
563 diff?: string;
564 added?: number;
565 removed?: number;
566 argumentsArchived?: boolean;
567 }
568
569 export interface HistoryPage {
570 messages: HistoryMessage[];
571 startTurn: number;
572 endTurn: number;
573 totalTurns: number;
574 hasOlder: boolean;
575 }
576
577 export interface PromptHistoryEntry {
578 text: string;
579 at: number; // unix ms
580 sessionPath: string;
581 turn: number;
582 }
583
584 export interface PromptHistoryResult {
585 entries: PromptHistoryEntry[] | null;
586 nonce: string;
587 olderCursor?: string;
588 hasOlder?: boolean;
589 }
590
591 // CheckpointMeta is one rewind point (a user turn) for the rewind UI.
592 export interface CheckpointMeta {
593 turn: number;
594 prompt: string;
595 files: string[];
596 fileCount?: number;
597 filesTruncated?: boolean;
598 turnFileCount?: number;
599 time: number; // unix ms
600 canCode?: boolean;
601 canConversation?: boolean;
602 coverage?: string;
603 coverageGaps?: string[];
604 expiredFilePayload?: boolean;
605 activeWriters?: number;
606 legacy?: boolean;
607 canUndoFiles?: boolean;
608 disabledReason?: string;
609 }
610
611 export interface RewindPlanView {
612 planId?: string;
613 turn?: number;
614 scope?: string;
615 coverage?: string;
616 coverageGaps?: string[];
617 legacy?: boolean;
618 expiredFilePayload?: boolean;
619 canFiles?: boolean;
620 canConversation?: boolean;
621 disabledReason?: string;
622 conflicts?: string[];
623 files?: string[];
624 fileCount?: number;
625 activeWriters?: number;
626 path?: string;
627 ok?: boolean;
628 error?: string;
629 }
630
631 export interface RewindResultView {
632 ok?: boolean;
633 transactionId?: string;
634 undoAvailable?: boolean;
635 written?: string[];
636 deleted?: string[];
637 conversationOk?: boolean;
638 error?: string;
639 conflicts?: string[];
640 coverage?: string;
641 }
642
643 // SessionMeta is one saved session for the history panel.
644 export interface SessionMeta {
645 path: string;
646 preview: string;
647 title?: string; // user-chosen name; falls back to preview when empty
648 turns: number;
649 createdAt: number; // unix milliseconds
650 lastActivityAt: number; // unix milliseconds
651 modTime: number; // compatibility alias for lastActivityAt
652 deletedAt?: number; // unix milliseconds, present for trashed sessions
653 current: boolean;
654 open: boolean;
655 scope?: string; // "project" | "global"; empty for legacy → treated as "global"
656 workspaceRoot?: string;
657 topicId?: string;
658 topicTitle?: string;
659 kind?: "session" | "channel" | string;
660 channel?: string;
661 channelLabel?: string;
662 remoteId?: string;
663 chatType?: string;
664 userId?: string;
665 threadId?: string;
666 sessionSource?: string;
667 recovered?: boolean; // created by conflict recovery, including a continued branch
668 recoveryCopy?: boolean; // actual branch content is unchanged and covered by its parent
669 }
670
671 // SessionReference is a session selected via @ past:chats for context injection.
672 export interface SessionReference {
673 path: string;
674 title: string;
675 preview?: string;
676 turns?: number;
677 createdAt?: number;
678 lastActivityAt?: number;
679 }
680
681 export interface WorkspaceView {
682 path: string;
683 name: string;
684 current: boolean;
685 }
686
687 export interface ContextInfo {
688 used: number;
689 window: number;
690 sessionTokens: number;
691 compactRatio?: number;
692 sessionCost?: number;
693 sessionCurrency?: string;
694 cacheHitTokens?: number;
695 cacheMissTokens?: number;
696 estimated?: boolean;
697 sources?: Record<string, UsageSourceStats>;
698 }
699
700 export interface Meta {
701 label: string;
702 ready: boolean;
703 runtime?: SessionRuntimeView;
704 startupErr?: string;
705 eventChannel: string;
706 cwd: string;
707 workspaceRoot?: string;
708 workspaceName?: string;
709 workspacePath?: string;
710 sessionPath?: string;
711 gitBranch?: string;
712 imageInputEnabled?: boolean;
713 autoApproveTools?: boolean;
714 bypass?: boolean; // legacy JSON key for YOLO/full-access tool auto-approval
715 collaborationMode?: CollaborationMode;
716 toolApprovalMode?: ToolApprovalMode;
717 tokenMode?: TokenMode;
718 goal?: string;
719 goalStatus?: GoalStatus;
720 goalRuntime?: GoalRuntime;
721 autoResearch?: AutoResearchCompactView;
722 canonicalTodos?: Todo[];
723 }
724
725 export type CollaborationMode = "normal" | "plan" | "goal";
726 export type ToolApprovalMode = "ask" | "auto" | "yolo";
727 // "full" is the persisted compatibility value for the Balanced runtime profile.
728 export type TokenMode = "full" | "economy" | "delivery";
729 export type GoalStatus = "running" | "complete" | "blocked" | "stopped";
730
731 // GoalRuntime is the optional Goal budget/runtime summary the backend attaches
732 // to Meta. Absent for old hosts or when no goal is active.
733 export interface GoalRuntime {
734 turnsUsed: number;
735 turnsLimit: number;
736 tokensUsed: number;
737 /** @deprecated Goal has no hard token limit; retained as 0 for old hosts/clients. */
738 tokensLimit: number;
739 noProgressTurns: number;
740 noProgressLimit: number;
741 lastReason?: string;
742 stopCause?: string;
743 budgetExtensions: number;
744 }
745
746 export interface AutoResearchCompactView {
747 taskId: string;
748 status: "running" | "blocked" | "complete" | "stopped" | "invalid";
749 iteration: number;
750 pivotRequired: boolean;
751 staleCount: number;
752 }
753
754 export interface AutoResearchCriterionView {
755 id: string;
756 description: string;
757 required: boolean;
758 evidenceCount: number;
759 status: string;
760 }
761
762 export interface AutoResearchStatusView extends AutoResearchCompactView {
763 goal: string;
764 currentDirection: string;
765 pivotCount: number;
766 lastHeartbeatAt: string;
767 findingCount: number;
768 openCriteria: AutoResearchCriterionView[];
769 blocker: string;
770 taskPath: string;
771 nextRequiredAction: string;
772 }
773
774 export interface AutoResearchFindingView {
775 id: string;
776 kind: string;
777 summary: string;
778 source: string;
779 command?: string;
780 paths?: string[];
781 accepted: boolean;
782 createdAt: string;
783 }
784
785 export interface AutoResearchEvidenceView {
786 id: string;
787 kind: string;
788 summary: string;
789 source: string;
790 command?: string;
791 paths?: string[];
792 accepted: boolean;
793 }
794
795 export function normalizeCollaborationMode(mode?: string, goal?: string, legacyMode?: Mode): CollaborationMode {
796 if (mode === "plan" || mode === "goal" || mode === "normal") return mode;
797 if (legacyMode && modeHasPlan(legacyMode)) return "plan";
798 if ((goal ?? "").trim()) return "goal";
799 return "normal";
800 }
801
802 export function normalizeToolApprovalMode(
803 mode?: string,
804 legacyMode?: Mode,
805 legacyAutoApproveTools?: boolean,
806 fallbackMode?: ToolApprovalMode,
807 ): ToolApprovalMode {
808 const normalized = typeof mode === "string" ? mode.trim().toLowerCase() : "";
809 if (normalized === "auto" || normalized === "yolo" || normalized === "ask") return normalized as ToolApprovalMode;
810 if (legacyAutoApproveTools || (legacyMode && modeHasAutoApproveTools(legacyMode))) return "yolo";
811 if (fallbackMode === "auto" && normalized === "") return "auto";
812 return "ask";
813 }
814
815 export function normalizeTokenMode(mode?: string): TokenMode {
816 if (mode === "economy") return "economy";
817 if (mode === "delivery") return "delivery";
818 return "full";
819 }
820
821 // Mode is the compatibility string for two independent composer axes:
822 // plan (plan-first workflow) and yolo (tool auto-approval).
823 export type Mode = "normal" | "plan" | "yolo" | "plan-yolo";
824
825 export function normalizeMode(mode?: string): Mode {
826 if (mode === "plan" || mode === "yolo" || mode === "plan-yolo" || mode === "yolo-plan") {
827 return mode === "yolo-plan" ? "plan-yolo" : mode;
828 }
829 return "normal";
830 }
831
832 export function modeHasPlan(mode: Mode): boolean {
833 return mode === "plan" || mode === "plan-yolo";
834 }
835
836 export function modeHasAutoApproveTools(mode: Mode): boolean {
837 return mode === "yolo" || mode === "plan-yolo";
838 }
839
840 export function modeFromAxes(plan: boolean, autoApproveTools: boolean): Mode {
841 if (plan && autoApproveTools) return "plan-yolo";
842 if (plan) return "plan";
843 if (autoApproveTools) return "yolo";
844 return "normal";
845 }
846
847 export function modeWithPlan(mode: Mode, plan: boolean): Mode {
848 return modeFromAxes(plan, modeHasAutoApproveTools(mode));
849 }
850
851 export function modeWithAutoApproveTools(mode: Mode, autoApproveTools: boolean): Mode {
852 return modeFromAxes(modeHasPlan(mode), autoApproveTools);
853 }
854
855 export interface CommandInfo {
856 name: string; // without the leading slash
857 description: string;
858 hint?: string;
859 kind: "builtin" | "custom" | "mcp" | "skill" | "subagent";
860 group?: "actions" | "management" | "subagents" | "skills" | "integrations";
861 plugin?: string;
862 color?: string;
863 }
864
865 export interface DirEntry {
866 name: string;
867 path?: string;
868 isDir: boolean;
869 displayName?: string;
870 displayPath?: string;
871 }
872
873 export interface DroppedItem {
874 kind: "workspace" | "attachment";
875 path: string;
876 isDir?: boolean;
877 displayPath?: string;
878 previewUrl?: string;
879 }
880
881 export interface FilePreview {
882 path: string;
883 body: string;
884 size: number;
885 truncated: boolean;
886 binary: boolean;
887 kind?: "image" | "pdf";
888 mime?: string;
889 url?: string;
890 err?: string;
891 }
892
893 export interface WorkspaceChangeView {
894 path: string;
895 oldPath?: string;
896 sources: string[];
897 gitStatus?: string;
898 turns?: number[];
899 latestPrompt?: string;
900 latestTime?: number;
901 canSessionRevert?: boolean;
902 }
903
904 export interface WorkspaceChangesView {
905 files: WorkspaceChangeView[];
906 gitAvailable: boolean;
907 gitErr?: string;
908 gitBranch?: string;
909 }
910
911 export interface WorkspaceChangeDetailView {
912 diff?: string;
913 source?: "git" | "session";
914 added?: number;
915 removed?: number;
916 binary?: boolean;
917 truncated?: boolean;
918 }
919
920 export interface GitCommitView {
921 hash: string;
922 author: string;
923 date: string;
924 message: string;
925 }
926
927 export interface GitCommitDetailView {
928 diff?: string;
929 files?: string[];
930 }
931
932 export interface ComposerInsertRequest {
933 id: number;
934 text: string;
935 mode?: "insert" | "replace" | "prefix";
936 }
937
938 // MCP & Skills drawer (desktop/app.go Capabilities) — the GUI counterpart to
939 // /mcp + /skill: connected/failed servers and discoverable skills.
940 export interface ServerView {
941 name: string;
942 transport: string;
943 status: "connected" | "deferred" | "failed" | "initializing" | "disabled";
944 /** @deprecated derived from enabled */
945 startIntent?: "off" | "automatic" | string;
946 runtimeState?: "idle" | "connecting" | "ready" | "issue" | string;
947 /** Product availability: available_on_demand | starting | connected | auth_required | project_auth_changed | start_failed | disabled */
948 availability?: string;
949 enabled?: boolean;
950 installed?: boolean;
951 action?: "none" | "authenticate" | "authorize" | "retry" | string;
952 source?: "project" | "user" | "plugin" | "builtin" | string;
953 configSource?: string;
954 builtIn?: boolean;
955 configured?: boolean;
956 /** @deprecated same as enabled */
957 autoStart: boolean;
958 /** @deprecated ignored by runtime */
959 tier?: "background" | "eager" | string;
960 command?: string;
961 args?: string[];
962 url?: string;
963 envKeys?: string[];
964 headerKeys?: string[];
965 tools: number;
966 toolCount?: number;
967 prompts: number;
968 resources: number;
969 hasTools?: boolean;
970 error?: string;
971 toolList?: MCPToolView[];
972 callTimeoutSeconds?: number;
973 toolTimeoutSeconds?: Record<string, number>;
974 requiresLaunchApproval?: boolean;
975 authStatus?: "none" | "possible" | "required" | string;
976 authUrl?: string;
977 authConfigured?: boolean;
978 managedByPlugin?: string;
979 }
980 export interface MCPToolView {
981 name: string;
982 description: string;
983 readOnlyHint?: boolean;
984 destructiveHint?: boolean;
985 schemaError?: string;
986 }
987 export interface SkillView {
988 name: string;
989 description: string;
990 scope: string;
991 runAs: string;
992 enabled: boolean;
993 plugin?: string;
994 model?: string;
995 effort?: string;
996 allowedTools?: string[];
997 readOnly?: boolean;
998 color?: string;
999 invocation?: string;
1000 invocationMode?: string;
1001 body?: string;
1002 configuredModel?: string;
1003 configuredEffort?: string;
1004 }
1005 export interface SkillRootSkillView {
1006 name: string;
1007 description: string;
1008 scope: string;
1009 runAs: string;
1010 plugin?: string;
1011 model?: string;
1012 effort?: string;
1013 allowedTools?: string[];
1014 color?: string;
1015 invocation?: string;
1016 }
1017 export interface SkillRootView {
1018 dir: string;
1019 scope: string;
1020 priority: number;
1021 status: string;
1022 configured: boolean;
1023 removable: boolean;
1024 skills: number;
1025 skillItems?: SkillRootSkillView[];
1026 warning?: string;
1027 }
1028 export interface CapabilitiesView {
1029 servers: ServerView[];
1030 skills: SkillView[];
1031 skillRoots: SkillRootView[];
1032 plugins: PluginView[];
1033 }
1034 export interface SkillsSettingsView {
1035 skills: SkillView[];
1036 skillRoots: SkillRootView[];
1037 }
1038 export interface SubagentProfileInput {
1039 name: string;
1040 description: string;
1041 systemPrompt: string;
1042 color?: string;
1043 model?: string;
1044 effort?: string;
1045 allowedTools?: string[];
1046 readOnly?: boolean;
1047 scope?: "project" | "global";
1048 }
1049 export interface PluginView {
1050 name: string;
1051 version?: string;
1052 description?: string;
1053 source?: string;
1054 root: string;
1055 manifestKind?: string;
1056 enabled: boolean;
1057 skills: number;
1058 commands?: number;
1059 hooks: number;
1060 mcpServers: number;
1061 agents?: number;
1062 compatibility?: "full" | "partial" | "none" | string;
1063 mappedCapabilities?: string[];
1064 skippedCapabilities?: PluginCompatibilityIssue[];
1065 skillDetails?: PluginSkillView[];
1066 agentDetails?: PluginAgentView[];
1067 commandDetails?: PluginCommandView[];
1068 hookDetails?: PluginHookView[];
1069 mcpServerDetails?: PluginMCPServerView[];
1070 warnings?: string[];
1071 error?: string;
1072 }
1073 export interface PluginCompatibilityIssue {
1074 capability: string;
1075 path?: string;
1076 reason: string;
1077 }
1078 export interface PluginAgentView {
1079 name: string;
1080 description?: string;
1081 path?: string;
1082 invocation?: string;
1083 model?: string;
1084 allowedTools?: string[];
1085 }
1086 export interface PluginSkillView {
1087 name: string;
1088 description?: string;
1089 path?: string;
1090 invocation?: string;
1091 runAs?: string;
1092 }
1093 export interface PluginCommandView {
1094 name: string;
1095 description?: string;
1096 argHint?: string;
1097 path?: string;
1098 invocation?: string;
1099 shadowed?: boolean;
1100 shadowedByPlugin?: string;
1101 }
1102 export interface PluginHookView {
1103 event: string;
1104 match?: string;
1105 command?: string;
1106 contextFile?: string;
1107 description?: string;
1108 }
1109 export interface PluginMCPServerView {
1110 name: string;
1111 displayName?: string;
1112 description?: string;
1113 transport?: string;
1114 command?: string;
1115 url?: string;
1116 autoStart?: boolean;
1117 }
1118 export interface PluginInstallOptions {
1119 dryRun?: boolean;
1120 link?: boolean;
1121 replace?: boolean;
1122 name?: string;
1123 }
1124 export interface MCPServerInput {
1125 name: string;
1126 transport: string; // stdio | http | sse
1127 command: string;
1128 args: string[];
1129 url: string;
1130 env?: Record<string, string> | null;
1131 headers?: Record<string, string> | null;
1132 autoStart?: boolean | null;
1133 callTimeoutSeconds?: number | null;
1134 toolTimeoutSeconds?: Record<string, number> | null;
1135 }
1136
1137 export interface MCPInstallResult {
1138 name: string;
1139 state: "ready" | "action_required" | "issue";
1140 toolCount: number;
1141 action: "none" | "authenticate" | "authorize" | "retry";
1142 message: string;
1143 }
1144
1145 export interface MCPMarketplaceEntry {
1146 name: string;
1147 suggestedName: string;
1148 title?: string;
1149 description?: string;
1150 version?: string;
1151 repositoryUrl?: string;
1152 installable: boolean;
1153 unavailableReason?: string;
1154 transport?: "stdio" | "http" | "sse" | string;
1155 command?: string;
1156 args: string[];
1157 url?: string;
1158 }
1159
1160 export interface MCPMarketplaceView {
1161 servers: MCPMarketplaceEntry[];
1162 cached: boolean;
1163 warning?: string;
1164 }
1165
1166 export interface ModelInfo {
1167 ref: string; // "provider/model" — pass to SetModel
1168 provider: string;
1169 model: string;
1170 current: boolean;
1171 }
1172
1173 export interface EffortInfo {
1174 supported: boolean;
1175 current: string; // "auto" | "low" | "medium" | "high" | "xhigh" | "max"
1176 default: string;
1177 levels: string[];
1178 }
1179
1180 // Slash sub-command / argument completion (desktop/app.go SlashArgs). Mirrors the
1181 // CLI's arg hints so the composer can suggest e.g. /skill → list/show/new/paths.
1182 export interface SlashArgItem {
1183 label: string;
1184 insert: string; // token to place at the current position
1185 hint: string;
1186 descend: boolean; // re-open the menu one level deeper after accepting
1187 }
1188 export interface SlashArgsResult {
1189 items: SlashArgItem[];
1190 from: number; // byte offset where the current token begins
1191 }
1192
1193 // Memory panel payloads (desktop/app.go MemoryView).
1194 export interface MemoryDoc {
1195 path: string;
1196 scope: string; // "user" | "ancestor" | "project" | "local"
1197 directory?: string;
1198 body: string;
1199 imports: Array<{ path: string; sourcePath: string }>;
1200 depth: number;
1201 order: number;
1202 precedence: number;
1203 }
1204
1205 export interface InstructionDiagnostic {
1206 code: string;
1207 path: string;
1208 sourcePath?: string;
1209 line?: number;
1210 message: string;
1211 }
1212
1213 export interface MemoryFact {
1214 id?: string;
1215 revision?: number;
1216 createdAt?: string;
1217 updatedAt?: string;
1218 name: string;
1219 title?: string;
1220 description: string;
1221 type: string; // "user" | "feedback" | "project" | "reference"
1222 scope: string; // "project" | "global"
1223 body: string;
1224 freshness: string; // "fresh" | "current" | "stale"
1225 }
1226
1227 export interface MemoryConflict {
1228 key: string;
1229 projectId: string;
1230 projectName: string;
1231 globalId: string;
1232 globalName: string;
1233 resolution: "project_over_global";
1234 }
1235
1236 export interface MemoryRecallHit {
1237 id: string;
1238 revision: number;
1239 name: string;
1240 title?: string;
1241 type: string;
1242 scope: string;
1243 score: number;
1244 freshness: string;
1245 reason: string;
1246 snippet: string;
1247 }
1248
1249 export interface MemoryRecallTrace {
1250 query: string;
1251 hits: MemoryRecallHit[];
1252 omitted: number;
1253 charBudget: number;
1254 usedChars: number;
1255 suppressed?: string;
1256 }
1257
1258 export interface MemoryArchive extends MemoryFact {
1259 path: string;
1260 archivedAt?: string;
1261 }
1262
1263 export interface MemoryScope {
1264 scope: string; // "user" | "project" | "local"
1265 path: string;
1266 }
1267
1268 export interface MemorySuggestion {
1269 id: string;
1270 name: string;
1271 title: string;
1272 description: string;
1273 type: string;
1274 scope: string; // "project" | "global"
1275 body: string;
1276 reason: string;
1277 evidence: string[];
1278 }
1279
1280 export interface SkillSuggestion {
1281 id: string;
1282 name: string;
1283 description: string;
1284 scope: string;
1285 body: string;
1286 reason: string;
1287 evidence: string[];
1288 }
1289
1290 export interface MemorySuggestionsView {
1291 memories: MemorySuggestion[];
1292 skills: SkillSuggestion[];
1293 generatedAt: string;
1294 available: boolean;
1295 source: string;
1296 }
1297
1298 export interface MemoryView {
1299 docs: MemoryDoc[];
1300 facts: MemoryFact[];
1301 archives: MemoryArchive[];
1302 scopes: MemoryScope[];
1303 instructionDiagnostics: InstructionDiagnostic[];
1304 conflicts: MemoryConflict[];
1305 lastRecall: MemoryRecallTrace;
1306 storeDir: string;
1307 storeGlobalDir?: string;
1308 available: boolean;
1309 }
1310
1311 // SettingsTab is the top-level navigation item in the Settings Centre modal.
1312 export type SettingsTab = "general" | "models" | "providers" | "bots" | "mcp" | "remote" | "skills" | "subagents" | "plugins" | "memory" | "hooks" | "diagnostics" | "shortcuts" | "permissions" | "sandbox" | "network" | "appearance" | "updates";
1313
1314 // ── Remote SSH module (mirrors desktop/remote_app.go view structs) ──
1315
1316 export type RemoteConnState =
1317 | "connecting"
1318 | "connected"
1319 | "reconnecting"
1320 | "degraded"
1321 | "pending_hostkey"
1322 | "pending_secret"
1323 | "stopped";
1324
1325 export type RemoteServerState =
1326 | "starting"
1327 | "detect"
1328 | "install"
1329 | "waiting_lock"
1330 | "launch"
1331 | "health_check"
1332 | "ready"
1333 | "error"
1334 | "stopped"
1335 | "reuse";
1336
1337 export interface RemoteHostView {
1338 id: string;
1339 label: string;
1340 host: string;
1341 port: number;
1342 user: string;
1343 identityFile: string;
1344 proxyJump: string;
1345 defaultWorkspace: string;
1346 serveInstall: string;
1347 useSSHConfig: boolean;
1348 passwordSet?: boolean;
1349 keyPassphraseSet?: boolean;
1350 }
1351
1352 export interface RemoteHostInput {
1353 label: string;
1354 host: string;
1355 port: number;
1356 user: string;
1357 identityFile: string;
1358 proxyJump: string;
1359 defaultWorkspace: string;
1360 serveInstall: string;
1361 useSSHConfig: boolean;
1362 password?: string;
1363 keyPassphrase?: string;
1364 clearPassword?: boolean;
1365 clearPassphrase?: boolean;
1366 preserveExistingSettings?: boolean;
1367 }
1368
1369 export interface RemoteFingerprintView {
1370 hostId: string;
1371 address: string;
1372 keyType: string;
1373 sha256: string;
1374 }
1375
1376 export interface RemoteSecretPromptView {
1377 promptId: string;
1378 hostId: string;
1379 host: string;
1380 kind: "password" | "passphrase";
1381 identity?: string;
1382 }
1383
1384 export interface RemoteKnownHostLocation {
1385 path: string;
1386 line: number;
1387 }
1388
1389 export interface RemoteConnectionErrorDetails {
1390 code: "connection_failed" | "auth_failed" | "host_key_rejected" | "host_key_mismatch";
1391 presentedSha256?: string;
1392 knownHostRecords?: RemoteKnownHostLocation[];
1393 }
1394
1395 export interface RemoteConnectionStatus {
1396 hostId: string;
1397 state: RemoteConnState;
1398 error?: string;
1399 errorDetails?: RemoteConnectionErrorDetails;
1400 fingerprint?: RemoteFingerprintView;
1401 secretPrompt?: RemoteSecretPromptView;
1402 attempt?: number;
1403 }
1404
1405 export interface RemoteDirEntry {
1406 name: string;
1407 path: string;
1408 isDir: boolean;
1409 size: number;
1410 mtimeUnix: number;
1411 symlink: boolean;
1412 }
1413
1414 export interface RemoteFilePreview {
1415 path: string;
1416 body: string;
1417 size: number;
1418 mtimeUnix: number;
1419 truncated: boolean;
1420 binary: boolean;
1421 err?: string;
1422 }
1423
1424 export interface RemoteWriteResult {
1425 ok: boolean;
1426 conflict: boolean;
1427 newMtimeUnix: number;
1428 }
1429
1430 export interface RemoteForwardInput {
1431 localPort: number;
1432 remoteHost: string;
1433 remotePort: number;
1434 label: string;
1435 }
1436
1437 export interface RemoteForwardView {
1438 id: string;
1439 hostId: string;
1440 localPort: number;
1441 remoteHost: string;
1442 remotePort: number;
1443 label: string;
1444 state: string;
1445 error?: string;
1446 }
1447
1448 export interface RemoteServerView {
1449 hostId: string;
1450 workspace: string;
1451 state: RemoteServerState;
1452 message?: string;
1453 localUrl?: string;
1454 error?: string;
1455 }
1456
1457 /** Path-free summary of files left behind by the removed Remote Workbench. */
1458 export interface RemoteLegacyWorkbenchData {
1459 mirrorCount: number;
1460 mirrorBytes: number;
1461 trustFile: boolean;
1462 }
1463
1464 export interface RemoteForwardsEvent {
1465 hostId: string;
1466 forwards: RemoteForwardView[];
1467 }
1468
1469 /** Capability diagnostics report from App.CapabilityDiagnostics (capdiag.Report). */
1470 export interface CapabilityDiagnosticsReport {
1471 schema_version: number;
1472 root: string;
1473 live: boolean;
1474 summary: {
1475 errors: number;
1476 warnings: number;
1477 infos: number;
1478 instructions: number;
1479 skills: number;
1480 commands: number;
1481 hooks: number;
1482 plugins: number;
1483 mcp_servers: number;
1484 };
1485 instructions: { docs: Array<{ path: string; scope: string; directory?: string; depth: number; order: number }> };
1486 skills: CapabilityAssetReport;
1487 commands: CapabilityAssetReport;
1488 hooks: {
1489 trusted_project: boolean;
1490 project_defines_hooks: boolean;
1491 sources: Array<{ scope: string; path: string; status: string; hook_count: number; parse_error?: string }>;
1492 entries: Array<{
1493 event: string;
1494 match?: string;
1495 command?: string;
1496 context_file?: string;
1497 description?: string;
1498 timeout_ms?: number;
1499 scope: string;
1500 source: string;
1501 blocking: boolean;
1502 }>;
1503 };
1504 plugins: {
1505 state_path?: string;
1506 packages: Array<{
1507 name: string;
1508 enabled: boolean;
1509 version?: string;
1510 root: string;
1511 manifest_kind?: string;
1512 skills: number;
1513 commands: number;
1514 hooks: number;
1515 mcp_servers: number;
1516 warnings?: string[];
1517 status: string;
1518 }>;
1519 };
1520 mcp: {
1521 servers: Array<{
1522 name: string;
1523 source?: string;
1524 package_owner?: string;
1525 transport: string;
1526 start_intent: string;
1527 command?: string;
1528 url_host?: string;
1529 env_keys?: string[];
1530 header_keys?: string[];
1531 runtime_status?: string;
1532 tool_count?: number;
1533 tools?: Array<{ name: string; read_only_hint?: boolean }>;
1534 error?: string;
1535 }>;
1536 };
1537 issues: CapabilityIssue[];
1538 }
1539
1540 export interface CapabilityAssetReport {
1541 roots: Array<{ path: string; scope?: string; status: string }>;
1542 entries: Array<{
1543 name: string;
1544 description?: string;
1545 scope?: string;
1546 path: string;
1547 status: string;
1548 winner_path?: string;
1549 error?: string;
1550 run_as?: string;
1551 }>;
1552 winners: number;
1553 shadowed: number;
1554 disabled?: number;
1555 parse_errors?: number;
1556 }
1557
1558 export interface CapabilityIssue {
1559 severity: "error" | "warning" | "info" | string;
1560 code: string;
1561 subsystem: string;
1562 name?: string;
1563 source?: string;
1564 message: string;
1565 remediation?: string;
1566 settings_tab?: string;
1567 }
1568 // Settings panel payloads (desktop/settings_app.go).
1569 export interface ProviderView {
1570 name: string;
1571 builtIn: boolean;
1572 added: boolean;
1573 kind: string;
1574 baseUrl: string;
1575 chatUrl?: string; // optional full chat completions URL; empty derives from baseUrl
1576 models: string[];
1577 visionModels: string[]; // subset of models that accepts image input
1578 visionModelsConfigured: boolean; // true when an empty list is an explicit choice
1579 modelsUrl: string; // optional override for model discovery; empty derives from baseUrl
1580 default: string;
1581 apiKeyEnv: string;
1582 headers?: Record<string, string> | null; // optional extra request headers for compatible gateways
1583 extraBody?: Record<string, unknown> | null; // optional extra top-level request body fields for compatible gateways
1584 authHeader?: boolean; // Anthropic-compatible: send Authorization: Bearer instead of x-api-key
1585 keySet: boolean; // the env var currently resolves to a value
1586 requiresKey?: boolean; // false for explicit no-auth providers
1587 configured?: boolean; // selectable: key is set or no key is required
1588 keySource?: string;
1589 keySourcePath?: string;
1590 balanceUrl: string; // optional wallet-balance endpoint; "" disables the readout
1591 contextWindow: number;
1592 reasoningProtocol: string; // auto|deepseek|glm|openai|none; empty = auto/model registry
1593 thinking: string; // provider-specific thinking override: ""|enabled|disabled|adaptive
1594 webSearch?: boolean; // expose a provider-executed web search tool when supported
1595 supportedEfforts: string[]; // custom /effort levels; empty = use built-in Kind/BaseURL default
1596 defaultEffort: string; // /effort level when user picks "auto" or unset; "" = supportedEfforts[0]
1597 modelOverrides?: ProviderModelOverrideView[] | null;
1598 modelCatalogFingerprint?: string; // opaque compare-and-apply token for background model discovery
1599 }
1600
1601 export interface ProviderModelCatalogUpdate {
1602 name: string;
1603 expectedFingerprint: string;
1604 models: string[];
1605 default: string;
1606 visionModels: string[];
1607 }
1608
1609 export interface ProviderPresetView {
1610 id: string;
1611 label: string;
1612 description: string;
1613 keyEnv: string;
1614 providerNames: string[];
1615 models: string[];
1616 added: boolean;
1617 status?: "available" | "installed" | "installed_modified" | "name_conflict" | "similar_existing";
1618 statusProviderNames?: string[];
1619 keySet: boolean;
1620 requiresKey?: boolean;
1621 configured?: boolean;
1622 keySource?: string;
1623 keySourcePath?: string;
1624 }
1625
1626 export interface ProviderModelOverrideView {
1627 model: string;
1628 reasoningProtocol: string;
1629 supportedEfforts: string[];
1630 defaultEffort: string;
1631 vision?: boolean | null;
1632 contextWindow?: number;
1633 }
1634
1635 // BalanceInfo is the wallet-balance readout (desktop/app.go Balance). available
1636 // is false when the provider declares no balanceUrl or a fetch failed; display is
1637 // the formatted amount (e.g. "¥110.00").
1638 export interface BalanceInfo {
1639 available: boolean;
1640 display: string;
1641 err?: string;
1642 }
1643
1644 // ── Usage statistics (desktop/stats_app.go) ────────────────────────────────
1645
1646 // UsageStatsRequest selects the aggregation range and optional entry-point
1647 // filter for the usage statistics panel. Range is "7" | "14" | "30" | "90" |
1648 // "custom"; custom requires from/to as "2006-01-02" (inclusive, local dates).
1649 // Source "" or "all" aggregates every entry point; "desktop" | "cli" | "serve"
1650 // | "bot" | "remote" filters to that source's records.
1651 export interface UsageStatsRequest {
1652 range: string;
1653 from?: string;
1654 to?: string;
1655 source?: string;
1656 }
1657
1658 // DailyTokenUsage is one day's token total, per-model split and turn count in
1659 // the daily trend series.
1660 export interface DailyTokenUsage {
1661 day: string; // "2006-01-02"
1662 total: number;
1663 byModel: Record<string, number>; // model ref -> tokens
1664 byProvider: Record<string, number>; // provider name -> tokens
1665 requests: number; // API calls that day
1666 turns: number;
1667 cacheHit: number; // cached input tokens that day
1668 cacheMiss: number; // uncached input tokens that day
1669 }
1670
1671 // ModelTokenUsage is one model's aggregate within the range.
1672 export interface ModelTokenUsage {
1673 model: string; // canonical "provider/model"
1674 provider: string;
1675 tokens: number;
1676 percent: number; // 0..100
1677 }
1678
1679 // ProviderTokenUsage is one provider's aggregate within the range.
1680 export interface ProviderTokenUsage {
1681 provider: string;
1682 tokens: number;
1683 percent: number;
1684 }
1685
1686 // UsageStatsRange is the full aggregate the settings panel renders.
1687 export interface UsageStatsRange {
1688 from: string;
1689 to: string;
1690 tokens: number;
1691 requests: number; // API calls
1692 turns: number; // completed turns
1693 cacheHit: number;
1694 cacheMiss: number;
1695 activeDays: number;
1696 topModel: string;
1697 topProvider: string;
1698 daily: DailyTokenUsage[];
1699 models: ModelTokenUsage[];
1700 providers: ProviderTokenUsage[];
1701 }
1702
1703 // JobView is one running background job (desktop/app.go Jobs) for the status bar.
1704 export interface JobView {
1705 id: string;
1706 kind: string; // "bash" | "task"
1707 label: string;
1708 status: string; // "running"
1709 startedAt: number; // unix milliseconds
1710 }
1711
1712 export interface ActiveWorkView {
1713 running: boolean;
1714 pendingPrompt: boolean;
1715 cancellable: boolean;
1716 jobs: JobView[];
1717 }
1718
1719 export interface JobCancelBatchView {
1720 cancelled: string[];
1721 notRunning: string[];
1722 }
1723
1724 export interface BackgroundRuntimeView {
1725 tabId: string;
1726 title: string;
1727 detached: boolean;
1728 running: boolean;
1729 pendingPrompt: boolean;
1730 jobs: JobView[];
1731 }
1732
1733 export interface WorkspaceConflictView {
1734 state: "none" | "local" | "external";
1735 ownerTabId?: string;
1736 ownerTitle?: string;
1737 ownerWork: ActiveWorkView;
1738 canReveal: boolean;
1739 canCreateWorktree: boolean;
1740 }
1741
1742 export interface PermissionsView {
1743 mode: string; // "ask" | "allow" | "deny"
1744 allow: string[];
1745 ask: string[];
1746 deny: string[];
1747 }
1748
1749 export interface SandboxView {
1750 bash: string; // "enforce" | "off"
1751 network: boolean;
1752 workspaceRoot: string;
1753 allowWrite: string[];
1754 effectiveWorkspaceRoot: string;
1755 effectiveWriteRoots: string[];
1756 shell: string; // "auto" | "bash" | "powershell" | "pwsh"
1757 effectiveShell?: string; // "bash" | "git-bash" | "powershell" | "pwsh"
1758 }
1759
1760 export interface NetworkProxyView {
1761 type: string;
1762 server: string;
1763 port: number;
1764 username: string;
1765 password: string;
1766 }
1767
1768 export interface NetworkView {
1769 proxyMode: string; // "auto" | "custom" | "off" (backend may still return legacy "env")
1770 proxyUrl: string;
1771 noProxy: string;
1772 proxy: NetworkProxyView;
1773 }
1774
1775 export interface AgentView {
1776 temperature: number;
1777 maxSteps: number;
1778 plannerMaxSteps: number;
1779 maxSubagentDepth: number;
1780 maxSubagentConcurrency: number;
1781 maxParallelWriters: number;
1782 systemPrompt: string;
1783 coldResumePrune: boolean;
1784 reasoningLanguage: string; // "auto" | "zh" | "en"
1785 compactRatio?: number; // Advanced global default; older backends omit it.
1786 effectiveCompactRatio?: number; // Active local session after project overrides.
1787 compactRatioOverridden?: boolean;
1788 }
1789
1790 export interface BotAllowlistView {
1791 enabled: boolean;
1792 allowAll: boolean;
1793 qqUsers: string[];
1794 feishuUsers: string[];
1795 weixinUsers: string[];
1796 qqApprovers: string[];
1797 feishuApprovers: string[];
1798 weixinApprovers: string[];
1799 qqAdmins: string[];
1800 feishuAdmins: string[];
1801 weixinAdmins: string[];
1802 qqGroups: string[];
1803 feishuGroups: string[];
1804 weixinGroups: string[];
1805 }
1806
1807 export interface BotAccessView {
1808 enabled: boolean;
1809 allowAll: boolean;
1810 pairingEnabled: boolean;
1811 users: string[];
1812 groups: string[];
1813 approvers: string[];
1814 admins: string[];
1815 }
1816
1817 export interface BotSelfUserIDsView {
1818 qq: string[];
1819 feishu: string[];
1820 weixin: string[];
1821 }
1822
1823 export interface BotPairingView {
1824 enabled: boolean;
1825 requestTtlMinutes: number;
1826 maxPendingPerPlatform: number;
1827 }
1828
1829 export interface BotControlView {
1830 enabled: boolean;
1831 addr: string;
1832 tokenEnv: string;
1833 }
1834
1835 export interface BotRouteView {
1836 connectionId: string;
1837 platform: string;
1838 chatType: string;
1839 chatId: string;
1840 userId: string;
1841 threadId: string;
1842 model: string;
1843 toolApprovalMode: ToolApprovalMode | "" | string;
1844 workspaceRoot: string;
1845 }
1846
1847 export interface QQBotView {
1848 enabled: boolean;
1849 appId: string;
1850 appSecretEnv: string;
1851 secretSet: boolean;
1852 sandbox: boolean;
1853 model: string;
1854 toolApprovalMode: ToolApprovalMode | "" | string;
1855 workspaceRoot: string;
1856 access: BotAccessView;
1857 }
1858
1859 export interface FeishuBotView {
1860 enabled: boolean;
1861 domain: string;
1862 appId: string;
1863 appSecretEnv: string;
1864 secretSet: boolean;
1865 verificationToken: string;
1866 mode: string;
1867 webhookPort: number;
1868 requireMention: boolean;
1869 }
1870
1871 export interface WeixinBotView {
1872 enabled: boolean;
1873 accountId: string;
1874 tokenEnv: string;
1875 tokenSet: boolean;
1876 apiBase: string;
1877 }
1878
1879 export interface BotConnectionCredentialView {
1880 appId: string;
1881 appSecretEnv: string;
1882 accountId: string;
1883 tokenEnv: string;
1884 secretSet: boolean;
1885 }
1886
1887 export interface BotConnectionSessionMappingView {
1888 remoteId: string;
1889 sessionId: string;
1890 sessionSource: string;
1891 chatType: string;
1892 userId: string;
1893 threadId: string;
1894 scope: "global" | "project" | string;
1895 workspaceRoot: string;
1896 updatedAt: string;
1897 }
1898
1899 export interface BotConnectionView {
1900 id: string;
1901 provider: "qq" | "feishu" | "weixin" | string;
1902 domain: "qq" | "feishu" | "lark" | "weixin" | string;
1903 label: string;
1904 enabled: boolean;
1905 status: "disconnected" | "pending" | "connected" | "error" | string;
1906 model: string;
1907 toolApprovalMode: ToolApprovalMode | "" | string;
1908 workspaceRoot: string;
1909 access: BotAccessView;
1910 credential: BotConnectionCredentialView;
1911 sessionMappings: BotConnectionSessionMappingView[];
1912 lastError: string;
1913 createdAt: string;
1914 updatedAt: string;
1915 }
1916
1917 export interface BotSettingsView {
1918 enabled: boolean;
1919 model: string;
1920 toolApprovalMode: ToolApprovalMode | "" | string;
1921 maxSteps: number;
1922 debounceMs: number;
1923 queueMode: string;
1924 queueCap: number;
1925 queueDrop: string;
1926 ignoreSelfMessages: boolean;
1927 selfUserIds: BotSelfUserIDsView;
1928 control: BotControlView;
1929 pairing: BotPairingView;
1930 routes: BotRouteView[];
1931 allowlist: BotAllowlistView;
1932 qq: QQBotView;
1933 feishu: FeishuBotView;
1934 weixin: WeixinBotView;
1935 connections: BotConnectionView[];
1936 }
1937
1938 export interface BotRuntimeStatusView {
1939 running: boolean;
1940 status: string;
1941 message: string;
1942 connections: number;
1943 startedAt: string;
1944 }
1945
1946 export interface BotInstallStartResult {
1947 ok: boolean;
1948 provider: string;
1949 domain: string;
1950 installId: string;
1951 url: string;
1952 deviceCode: string;
1953 userCode: string;
1954 interval: number;
1955 expireIn: number;
1956 message: string;
1957 }
1958
1959 export interface BotInstallPollResult {
1960 done: boolean;
1961 connection: BotConnectionView;
1962 status: string;
1963 message: string;
1964 error: string;
1965 }
1966
1967 export interface HookConfigView {
1968 event: string;
1969 match?: string;
1970 command: string;
1971 description?: string;
1972 timeout?: number;
1973 cwd?: string;
1974 }
1975
1976 export interface HooksSettingsView {
1977 scope: string;
1978 path: string;
1979 projectRoot: string;
1980 trusted: boolean;
1981 hooks: HookConfigView[];
1982 events: string[];
1983 }
1984
1985 export interface BotConnectionDiagnostic {
1986 id: string;
1987 label: string;
1988 status: string;
1989 message: string;
1990 messageId: string;
1991 phase: string;
1992 code: string;
1993 reportKind: string;
1994 reportDetail: string;
1995 occurredAt: string;
1996 }
1997
1998 export interface SettingsView {
1999 defaultModel: string;
2000 plannerModel: string;
2001 subagentModel: string;
2002 subagentEffort: string;
2003 autoPlan: string;
2004 providers: ProviderView[];
2005 officialProviders: ProviderView[];
2006 providerPresets: ProviderPresetView[];
2007 permissions: PermissionsView;
2008 sandbox: SandboxView;
2009 network: NetworkView;
2010 agent: AgentView;
2011 bot: BotSettingsView;
2012 desktopLanguage: string; // "" | "en" | "zh"; empty = auto
2013 desktopCurrency?: string; // "" | "CNY" | "USD"; absent/empty = follow language
2014 desktopLayoutStyle: string; // "classic" | "workbench" | "creation"
2015 desktopTheme: string; // "auto" | "dark" | "light"
2016 desktopThemeStyle: string;
2017 desktopTerminalTheme: string; // "auto" follows app | "dark" | "light"
2018 closeBehavior: string; // "background" | "quit"
2019 displayMode: string; // "standard" | "compact"
2020 statusBarStyle: string; // "icon" | "text"
2021 statusBarItems: string[]; // ordered visible status bar item ids
2022 defaultToolApprovalMode: ToolApprovalMode | string; // default for newly-created sessions
2023 checkUpdates: boolean; // check for new versions on startup
2024 updateChannel: string; // compatibility field; always "stable"
2025 telemetry: boolean; // anonymous launch ping + scrubbed next-launch native crash diagnostics
2026 metrics: boolean; // aggregate quality/lifecycle metrics (anonymous signal/bucket counts)
2027 configPath: string;
2028 shadowedByPath?: string; // workspace reasonix.toml that outranks configPath, when one exists
2029 providerKinds: string[]; // provider implementations the kernel registered (for the kind picker)
2030 autoApproveTools: boolean;
2031 bypass: boolean; // legacy JSON key for live YOLO/full-access tool auto-approval
2032 conversationWidth?: string; // "standard" | "full"; absent from older Wails payloads
2033 }
2034
2035 export interface DesktopStartupSettingsView {
2036 bot: BotSettingsView;
2037 desktopLanguage: string; // "" | "en" | "zh"; empty = auto
2038 desktopLayoutStyle: string; // "classic" | "workbench"
2039 desktopTheme: string; // "auto" | "dark" | "light"
2040 desktopThemeStyle: string;
2041 desktopTerminalTheme: string; // "auto" follows app | "dark" | "light"
2042 displayMode: string; // "standard" | "compact"
2043 statusBarStyle: string; // "icon" | "text"
2044 statusBarItems: string[]; // ordered visible status bar item ids
2045 checkUpdates: boolean; // check for new versions on startup
2046 updateChannel: string; // compatibility field; always "stable"
2047 conversationWidth?: string; // "standard" | "full"; absent from older Wails payloads
2048 configWarnings?: string[]; // non-blocking load recovery notices
2049 configPath?: string;
2050 }
2051
2052 export type ExternalOpenerKind = "file-manager" | "editor" | "terminal";
2053
2054 export interface ExternalOpenerView {
2055 id: string;
2056 name: string;
2057 kind: ExternalOpenerKind;
2058 iconDataUrl?: string;
2059 }
2060
2061 export interface ExternalOpenersView {
2062 openers: ExternalOpenerView[];
2063 preferred: string;
2064 }
2065
2066 // Auto-updater payloads (desktop/updater.go). UpdateInfo drives the update banner;
2067 // UpdateProgress streams on the "updater:progress" event during download/install.
2068 export interface UpdateInfo {
2069 available: boolean;
2070 current: string;
2071 latest: string;
2072 notes: string;
2073 channel: string;
2074 canSelfUpdate: boolean; // macOS true only for signed/notarized builds
2075 manualOnly?: boolean;
2076 manualReason?: string;
2077 installMode?: "portable" | "deb" | "manual" | string;
2078 requiresElevation?: boolean;
2079 downloaded: boolean;
2080 downloadUrl: string; // human-facing releases page (macOS path / fallback link)
2081 assetSize: number; // running platform's artifact size, for the progress bar
2082 err?: string; // set when the check itself failed (both endpoints down)
2083 }
2084
2085 export interface UpdateDownloadResult {
2086 requestId: string;
2087 version: string;
2088 channel: string;
2089 path: string;
2090 size: number;
2091 sha256: string;
2092 }
2093
2094 export interface UpdateProgress {
2095 requestId: string;
2096 version: string;
2097 channel: "stable" | "preview" | string;
2098 phase: "downloading" | "verifying" | "downloaded" | "authorizing" | "recovering" | "installing" | "relaunching" | "done" | "error";
2099 received: number;
2100 total: number;
2101 err?: string;
2102 }
2103
2104 // Task Monitor panel types (internal/taskmonitor).
2105
2106 export type TaskState =
2107 | "queued"
2108 | "running"
2109 | "waiting"
2110 | "succeeded"
2111 | "failed"
2112 | "cancelled"
2113 | "stale"
2114 | string; // forward-compat
2115
2116 export type RuntimeState = "unknown" | "alive" | "exited" | string;
2117
2118 export interface TaskSnapshot {
2119 schema_version: number;
2120 task_id: string;
2121 job_id?: string; // jobs.Manager-local runtime identifier
2122 session_id: string;
2123 state: TaskState;
2124 runtime_state?: RuntimeState; // absent in snapshots written before this field existed
2125 version: number;
2126 created_at: string; // ISO 8601
2127 updated_at: string; // ISO 8601
2128 error_code?: string;
2129 error_summary?: string;
2130 }
2131
2132 export interface ControlResult {
2133 schema_version: number;
2134 command: string;
2135 task_id: string;
2136 session_id?: string;
2137 state?: TaskState;
2138 runtime_state?: RuntimeState;
2139 version?: number;
2140 accepted: boolean;
2141 idempotent: boolean;
2142 error?: { code: string; message: string };
2143 }
2144
2145 export interface TaskEvent {
2146 sequence: number;
2147 timestamp: string; // ISO 8601
2148 event_type: string;
2149 task_id: string;
2150 session_id: string;
2151 state: TaskState;
2152 runtime_state?: RuntimeState;
2153 error_code?: string;
2154 error_summary?: string;
2155 }
2156
2156 lines TYPESCRIPT