@ebowwa/coder 0.7.64 → 0.7.66

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 (101) hide show
  1. package/dist/index.js +36233 -32
  2. package/dist/interfaces/ui/terminal/cli/index.js +34318 -158
  3. package/dist/interfaces/ui/terminal/native/README.md +53 -0
  4. package/dist/interfaces/ui/terminal/native/claude_code_native.darwin-x64.node +0 -0
  5. package/dist/interfaces/ui/terminal/native/claude_code_native.dylib +0 -0
  6. package/dist/interfaces/ui/terminal/native/index.d.ts +0 -0
  7. package/dist/interfaces/ui/terminal/native/index.darwin-arm64.node +0 -0
  8. package/dist/interfaces/ui/terminal/native/index.js +43 -0
  9. package/dist/interfaces/ui/terminal/native/index.node +0 -0
  10. package/dist/interfaces/ui/terminal/native/package.json +34 -0
  11. package/dist/native/README.md +53 -0
  12. package/dist/native/claude_code_native.darwin-x64.node +0 -0
  13. package/dist/native/claude_code_native.dylib +0 -0
  14. package/dist/native/index.d.ts +0 -480
  15. package/dist/native/index.darwin-arm64.node +0 -0
  16. package/dist/native/index.js +43 -1625
  17. package/dist/native/index.node +0 -0
  18. package/dist/native/package.json +34 -0
  19. package/native/index.darwin-arm64.node +0 -0
  20. package/native/index.js +33 -19
  21. package/package.json +3 -2
  22. package/packages/src/core/agent-loop/__tests__/compaction.test.ts +17 -14
  23. package/packages/src/core/agent-loop/compaction.ts +6 -2
  24. package/packages/src/core/agent-loop/index.ts +2 -0
  25. package/packages/src/core/agent-loop/loop-state.ts +1 -1
  26. package/packages/src/core/agent-loop/turn-executor.ts +4 -0
  27. package/packages/src/core/agent-loop/types.ts +4 -0
  28. package/packages/src/core/api-client-impl.ts +377 -176
  29. package/packages/src/core/cognitive-security/hooks.ts +2 -1
  30. package/packages/src/core/config/todo +7 -0
  31. package/packages/src/core/context/__tests__/integration.test.ts +334 -0
  32. package/packages/src/core/context/compaction.ts +170 -0
  33. package/packages/src/core/context/constants.ts +58 -0
  34. package/packages/src/core/context/extraction.ts +85 -0
  35. package/packages/src/core/context/index.ts +66 -0
  36. package/packages/src/core/context/summarization.ts +251 -0
  37. package/packages/src/core/context/token-estimation.ts +98 -0
  38. package/packages/src/core/context/types.ts +59 -0
  39. package/packages/src/core/models.ts +81 -4
  40. package/packages/src/core/normalizers/todo +5 -1
  41. package/packages/src/core/providers/README.md +230 -0
  42. package/packages/src/core/providers/__tests__/providers.test.ts +135 -0
  43. package/packages/src/core/providers/index.ts +419 -0
  44. package/packages/src/core/providers/types.ts +132 -0
  45. package/packages/src/core/retry.ts +10 -0
  46. package/packages/src/ecosystem/tools/index.ts +174 -0
  47. package/packages/src/index.ts +23 -2
  48. package/packages/src/interfaces/ui/index.ts +17 -20
  49. package/packages/src/interfaces/ui/spinner.ts +2 -2
  50. package/packages/src/interfaces/ui/terminal/bridge/index.ts +370 -0
  51. package/packages/src/interfaces/ui/terminal/bridge/ipc.ts +829 -0
  52. package/packages/src/interfaces/ui/terminal/bridge/screen-export.ts +968 -0
  53. package/packages/src/interfaces/ui/terminal/bridge/types.ts +226 -0
  54. package/packages/src/interfaces/ui/terminal/bridge/useBridge.ts +210 -0
  55. package/packages/src/interfaces/ui/terminal/cli/bootstrap.ts +132 -0
  56. package/packages/src/interfaces/ui/terminal/cli/index.ts +200 -13
  57. package/packages/src/interfaces/ui/terminal/cli/interactive/index.ts +110 -0
  58. package/packages/src/interfaces/ui/terminal/cli/interactive/input-handler.ts +402 -0
  59. package/packages/src/interfaces/ui/terminal/cli/interactive/interactive-runner.ts +820 -0
  60. package/packages/src/interfaces/ui/terminal/cli/interactive/message-store.ts +299 -0
  61. package/packages/src/interfaces/ui/terminal/cli/interactive/types.ts +274 -0
  62. package/packages/src/interfaces/ui/terminal/shared/index.ts +13 -0
  63. package/packages/src/interfaces/ui/terminal/shared/query.ts +9 -3
  64. package/packages/src/interfaces/ui/terminal/shared/setup.ts +5 -1
  65. package/packages/src/interfaces/ui/terminal/shared/spinner-frames.ts +73 -0
  66. package/packages/src/interfaces/ui/terminal/shared/status-line.ts +10 -2
  67. package/packages/src/native/index.ts +404 -27
  68. package/packages/src/native/tui_v2_types.ts +39 -0
  69. package/packages/src/teammates/coordination.test.ts +279 -0
  70. package/packages/src/teammates/coordination.ts +646 -0
  71. package/packages/src/teammates/index.ts +95 -25
  72. package/packages/src/teammates/integration.test.ts +272 -0
  73. package/packages/src/teammates/runner.test.ts +235 -0
  74. package/packages/src/teammates/runner.ts +750 -0
  75. package/packages/src/teammates/schemas.ts +673 -0
  76. package/packages/src/types/index.ts +1 -0
  77. package/packages/src/core/context-compaction.ts +0 -578
  78. package/packages/src/interfaces/ui/Screenshot 2026-03-02 at 9.23.10/342/200/257PM.png +0 -0
  79. package/packages/src/interfaces/ui/Screenshot 2026-03-03 at 10.55.11/342/200/257AM.png +0 -0
  80. package/packages/src/interfaces/ui/terminal/tui/HelpPanel.tsx +0 -262
  81. package/packages/src/interfaces/ui/terminal/tui/InputContext.tsx +0 -232
  82. package/packages/src/interfaces/ui/terminal/tui/InputField.tsx +0 -62
  83. package/packages/src/interfaces/ui/terminal/tui/InteractiveTUI.tsx +0 -537
  84. package/packages/src/interfaces/ui/terminal/tui/MessageArea.tsx +0 -107
  85. package/packages/src/interfaces/ui/terminal/tui/MessageStore.tsx +0 -240
  86. package/packages/src/interfaces/ui/terminal/tui/StatusBar.tsx +0 -54
  87. package/packages/src/interfaces/ui/terminal/tui/commands.ts +0 -438
  88. package/packages/src/interfaces/ui/terminal/tui/components/InteractiveElements.tsx +0 -584
  89. package/packages/src/interfaces/ui/terminal/tui/components/MultilineInput.tsx +0 -614
  90. package/packages/src/interfaces/ui/terminal/tui/components/PaneManager.tsx +0 -333
  91. package/packages/src/interfaces/ui/terminal/tui/components/Sidebar.tsx +0 -604
  92. package/packages/src/interfaces/ui/terminal/tui/components/index.ts +0 -118
  93. package/packages/src/interfaces/ui/terminal/tui/console.ts +0 -49
  94. package/packages/src/interfaces/ui/terminal/tui/index.ts +0 -90
  95. package/packages/src/interfaces/ui/terminal/tui/run.tsx +0 -42
  96. package/packages/src/interfaces/ui/terminal/tui/spinner.ts +0 -69
  97. package/packages/src/interfaces/ui/terminal/tui/tui-app.tsx +0 -390
  98. package/packages/src/interfaces/ui/terminal/tui/tui-footer.ts +0 -422
  99. package/packages/src/interfaces/ui/terminal/tui/types.ts +0 -186
  100. package/packages/src/interfaces/ui/terminal/tui/useInputHandler.ts +0 -104
  101. package/packages/src/interfaces/ui/terminal/tui/useNativeInput.ts +0 -239
@@ -1852,6 +1852,175 @@ export const AnalyzeImageTool: ToolDefinition = {
1852
1852
  },
1853
1853
  };
1854
1854
 
1855
+ // ============================================
1856
+ // TEAMMATE COORDINATION TOOLS
1857
+ // ============================================
1858
+
1859
+ /**
1860
+ * Check for new messages from teammates
1861
+ */
1862
+ const TeammateCheckMessagesTool: ToolDefinition = {
1863
+ name: "teammate_check_messages",
1864
+ description:
1865
+ "Check for new messages from other teammates in your team. Returns pending messages and clears the inbox. Use this periodically when in teammate mode to receive tasks and coordination messages.",
1866
+ input_schema: {
1867
+ type: "object",
1868
+ properties: {},
1869
+ },
1870
+ handler: async (_args, _context: ToolContext): Promise<ToolResult> => {
1871
+ const { getTeammateRunner } = await import("../../teammates/runner.js");
1872
+ const runner = getTeammateRunner();
1873
+ if (!runner) {
1874
+ return {
1875
+ content: "Teammate mode is not active. Start with --teammate-mode flag.",
1876
+ is_error: true,
1877
+ };
1878
+ }
1879
+
1880
+ const messages = runner.getPendingMessages();
1881
+ if (messages.length === 0) {
1882
+ return { content: "No pending messages." };
1883
+ }
1884
+
1885
+ const formatted = messages
1886
+ .map((m) => `[${m.type}] From: ${m.from}\n${m.content}`)
1887
+ .join("\n\n---\n\n");
1888
+
1889
+ return { content: `Received ${messages.length} message(s):\n\n${formatted}` };
1890
+ },
1891
+ };
1892
+
1893
+ /**
1894
+ * Send a direct message to another teammate
1895
+ */
1896
+ const TeammateSendMessageTool: ToolDefinition = {
1897
+ name: "teammate_send_message",
1898
+ description:
1899
+ "Send a direct message to a specific teammate or broadcast to all teammates. Use this for coordination, sharing results, or requesting help.",
1900
+ input_schema: {
1901
+ type: "object",
1902
+ properties: {
1903
+ to: {
1904
+ type: "string",
1905
+ description:
1906
+ "Teammate ID to send to, or 'broadcast' to send to all teammates",
1907
+ },
1908
+ message: {
1909
+ type: "string",
1910
+ description: "The message content to send",
1911
+ },
1912
+ },
1913
+ required: ["to", "message"],
1914
+ },
1915
+ handler: async (args, _context: ToolContext): Promise<ToolResult> => {
1916
+ const { getTeammateRunner } = await import("../../teammates/runner.js");
1917
+ const runner = getTeammateRunner();
1918
+ if (!runner) {
1919
+ return {
1920
+ content: "Teammate mode is not active. Start with --teammate-mode flag.",
1921
+ is_error: true,
1922
+ };
1923
+ }
1924
+
1925
+ const to = args.to as string;
1926
+ const message = args.message as string;
1927
+
1928
+ if (to === "broadcast") {
1929
+ runner.broadcast(message);
1930
+ return { content: `Broadcast message sent to team.` };
1931
+ } else {
1932
+ runner.sendDirectMessage(to, message);
1933
+ return { content: `Direct message sent to ${to}.` };
1934
+ }
1935
+ },
1936
+ };
1937
+
1938
+ /**
1939
+ * Report idle status to team
1940
+ */
1941
+ const TeammateReportIdleTool: ToolDefinition = {
1942
+ name: "teammate_report_idle",
1943
+ description:
1944
+ "Report that you are now idle and ready for new tasks. Use this when you complete your current work and are available for assignment.",
1945
+ input_schema: {
1946
+ type: "object",
1947
+ properties: {
1948
+ message: {
1949
+ type: "string",
1950
+ description: "Optional status message",
1951
+ },
1952
+ },
1953
+ },
1954
+ handler: async (args, _context: ToolContext): Promise<ToolResult> => {
1955
+ const { getTeammateRunner } = await import("../../teammates/runner.js");
1956
+ const runner = getTeammateRunner();
1957
+ if (!runner) {
1958
+ return {
1959
+ content: "Teammate mode is not active. Start with --teammate-mode flag.",
1960
+ is_error: true,
1961
+ };
1962
+ }
1963
+
1964
+ const message = args.message as string | undefined;
1965
+ runner.updateStatus("idle");
1966
+ runner.broadcast(message || "Now idle and ready for tasks.");
1967
+ return { content: "Status updated to idle. Team notified." };
1968
+ },
1969
+ };
1970
+
1971
+ /**
1972
+ * Get teammate status information
1973
+ */
1974
+ const TeammateGetStatusTool: ToolDefinition = {
1975
+ name: "teammate_get_status",
1976
+ description:
1977
+ "Get current teammate mode status including your info, team members, and inbox stats. Use this to check your state and team coordination.",
1978
+ input_schema: {
1979
+ type: "object",
1980
+ properties: {},
1981
+ },
1982
+ handler: async (_args, _context: ToolContext): Promise<ToolResult> => {
1983
+ const { getTeammateRunner } = await import("../../teammates/runner.js");
1984
+ const runner = getTeammateRunner();
1985
+ if (!runner) {
1986
+ return {
1987
+ content: "Teammate mode is not active. Start with --teammate-mode flag.",
1988
+ is_error: true,
1989
+ };
1990
+ }
1991
+
1992
+ const teammate = runner.getTeammate();
1993
+ const team = runner.getTeam();
1994
+ const status = runner.getStatus();
1995
+ const inbox = runner.getInboxStats();
1996
+
1997
+ const info = {
1998
+ teammate: teammate
1999
+ ? {
2000
+ id: teammate.teammateId,
2001
+ name: teammate.name,
2002
+ color: teammate.color,
2003
+ }
2004
+ : null,
2005
+ team: team
2006
+ ? {
2007
+ name: team.name,
2008
+ memberCount: team.teammates.length,
2009
+ members: team.teammates.map((t) => ({
2010
+ id: t.teammateId,
2011
+ name: t.name,
2012
+ status: t.status,
2013
+ })),
2014
+ }
2015
+ : null,
2016
+ status,
2017
+ inbox,
2018
+ };
2019
+
2020
+ return { content: JSON.stringify(info, null, 2) };
2021
+ },
2022
+ };
2023
+
1855
2024
  export const builtInTools: ToolDefinition[] = [
1856
2025
  ReadTool,
1857
2026
  WriteTool,
@@ -1870,6 +2039,11 @@ export const builtInTools: ToolDefinition[] = [
1870
2039
  NotebookEditTool,
1871
2040
  AnalyzeImageTool,
1872
2041
  TempGlmVisionTool,
2042
+ // Teammate coordination tools
2043
+ TeammateCheckMessagesTool,
2044
+ TeammateSendMessageTool,
2045
+ TeammateReportIdleTool,
2046
+ TeammateGetStatusTool,
1873
2047
  ];
1874
2048
 
1875
2049
  export function getToolByName(name: string): ToolDefinition | undefined {
@@ -71,6 +71,27 @@ export * from "./teammates/index.js";
71
71
  // Cognitive Security
72
72
  export * from "./core/cognitive-security/index.js";
73
73
 
74
+ // Providers
75
+ export {
76
+ PROVIDERS,
77
+ getProvider,
78
+ getProviderForModel,
79
+ resolveProvider,
80
+ isProviderHealthy,
81
+ getHealthyProviders,
82
+ getNextHealthyProvider,
83
+ recordProviderSuccess,
84
+ recordProviderFailure,
85
+ getProviderHealth,
86
+ } from "./core/providers/index.js";
87
+ export type {
88
+ ProviderName,
89
+ ProviderConfig,
90
+ ProviderHealth,
91
+ ResolvedProvider,
92
+ ProviderRoutingConfig,
93
+ } from "./core/providers/index.js";
94
+
74
95
  // UI Components (exclude types that are already in types/index.js)
75
96
  export {
76
97
  Spinner,
@@ -112,9 +133,9 @@ export {
112
133
  summarizeMessages,
113
134
  summarizeWithLLM,
114
135
  getCompactionStats,
115
- } from "./core/context-compaction.js";
136
+ } from "./core/context/index.js";
116
137
  export type {
117
138
  CompactionOptions,
118
139
  CompactionResult,
119
140
  LLMSummarizationOptions,
120
- } from "./core/context-compaction.js";
141
+ } from "./core/context/index.js";
@@ -53,27 +53,24 @@ export {
53
53
  type ContextInfo,
54
54
  } from "./terminal/shared/status-line.js";
55
55
 
56
- // TUI Footer (from tui)
56
+ // Interactive CLI (non-React, from interactive module)
57
57
  export {
58
- TUIFooter,
59
- getTUIFooter,
60
- enableTUIFooter,
61
- disableTUIFooter,
62
- renderTUIFooter,
63
- clearTUIFooter,
64
- ANSI,
65
- type TUIFooterOptions,
66
- type TUIFooterState,
67
- } from "./terminal/tui/tui-footer.js";
68
-
69
- // TUI App (Ink-based, from tui)
70
- export {
71
- createTUIApp,
72
- type TUIAppProps,
73
- type TUIAppHandle,
74
- type Message as TUIMessage,
75
- } from "./terminal/tui/tui-app.js";
76
- export { default as TUIApp } from "./terminal/tui/tui-app.js";
58
+ InteractiveRunner,
59
+ runInteractiveMode,
60
+ MessageStoreImpl,
61
+ InputManagerImpl,
62
+ KeyEvents,
63
+ InputPriority,
64
+ type InteractiveRunnerProps,
65
+ type InteractiveState,
66
+ type UIMessage,
67
+ type MessageSubType,
68
+ type MessageStore,
69
+ type InputManager,
70
+ type InputHandler,
71
+ type InputHandlerOptions,
72
+ type NativeKeyEvent,
73
+ } from "./terminal/cli/interactive/index.js";
77
74
 
78
75
  // ============================================
79
76
  // PROGRESS CALLBACK TYPES
@@ -7,14 +7,14 @@
7
7
  import ora, { type Ora } from "ora";
8
8
  import chalk from "chalk";
9
9
 
10
- // Import spinner frames from the single source of truth
10
+ // Import spinner frames from the single source of truth (shared)
11
11
  import {
12
12
  spinnerFrames,
13
13
  dotSpinnerFrames,
14
14
  asciiSpinnerFrames,
15
15
  arrowSpinnerFrames,
16
16
  simpleDotFrames,
17
- } from "./terminal/tui/spinner.js";
17
+ } from "./terminal/shared/spinner-frames.js";
18
18
 
19
19
  // Re-export for external use
20
20
  export {
@@ -0,0 +1,370 @@
1
+ /**
2
+ * TUI Bridge Module
3
+ * Enables external control of coder via TUI Bridge MCP
4
+ *
5
+ * This module provides:
6
+ * 1. State export for external parsing
7
+ * 2. Command execution from external sources
8
+ * 3. Event emission for external listeners
9
+ * 4. Screen capture and export utilities
10
+ */
11
+
12
+ import { EventEmitter } from "events";
13
+ import type {
14
+ BridgeState,
15
+ BridgeEvent,
16
+ BridgeCommand,
17
+ BridgeCommandResult,
18
+ TUIBridgeConfig,
19
+ ParsedScreen,
20
+ ScreenBuffer,
21
+ ScreenCell,
22
+ UIElement,
23
+ UIElementType,
24
+ BridgeEventType,
25
+ } from "./types.js";
26
+
27
+ // Re-export screen-export utilities
28
+ export {
29
+ DEFAULT_CELL,
30
+ parseANSIText,
31
+ stripANSI,
32
+ createScreenBuffer,
33
+ renderToScreenBuffer,
34
+ captureScreen,
35
+ detectUIElements,
36
+ exportToText,
37
+ exportToJSON,
38
+ exportToHTML,
39
+ exportToMarkdown,
40
+ exportScreen,
41
+ parseScreen,
42
+ createScreenExportAPI,
43
+ type ExportFormat,
44
+ type ExportOptions,
45
+ type ScreenExportAPI,
46
+ } from "./screen-export.js";
47
+
48
+ // Import for use in TUIBridge
49
+ import {
50
+ createScreenBuffer as createBuffer,
51
+ parseANSIText,
52
+ renderToScreenBuffer,
53
+ detectUIElements,
54
+ exportScreen as doExport,
55
+ parseScreen,
56
+ } from "./screen-export.js";
57
+ import type { ExportFormat, ExportOptions } from "./screen-export.js";
58
+
59
+ /**
60
+ * TUI Bridge singleton for external control
61
+ */
62
+ export class TUIBridge extends EventEmitter {
63
+ private static instance: TUIBridge | null = null;
64
+ private config: TUIBridgeConfig;
65
+ private state: BridgeState | null = null;
66
+ private subscribers: Set<string> = new Set();
67
+ private commandQueue: Array<{ command: BridgeCommand; resolve: (result: BridgeCommandResult) => void }> = [];
68
+ private isProcessing: boolean = false;
69
+ private screenBuffer: ScreenBuffer | null = null;
70
+ private terminalDimensions: { width: number; height: number } = { width: 80, height: 24 };
71
+
72
+ private constructor(config: TUIBridgeConfig) {
73
+ super();
74
+ this.config = config;
75
+ }
76
+
77
+ /**
78
+ * Get singleton instance
79
+ */
80
+ static getInstance(config?: TUIBridgeConfig): TUIBridge | null {
81
+ if (!TUIBridge.instance && config) {
82
+ TUIBridge.instance = new TUIBridge(config);
83
+ }
84
+ return TUIBridge.instance;
85
+ }
86
+
87
+ /**
88
+ * Initialize bridge with config
89
+ */
90
+ static init(config: TUIBridgeConfig): TUIBridge {
91
+ if (!TUIBridge.instance) {
92
+ TUIBridge.instance = new TUIBridge(config);
93
+ }
94
+ return TUIBridge.instance;
95
+ }
96
+
97
+ /**
98
+ * Update internal state and emit event
99
+ */
100
+ updateState(newState: Partial<BridgeState>): void {
101
+ if (!this.state) {
102
+ return;
103
+ }
104
+ this.state = { ...this.state, ...newState, timestamp: Date.now() };
105
+ this.emitEvent("state_update", this.state);
106
+ }
107
+
108
+ /**
109
+ * Initialize state (called once at startup)
110
+ */
111
+ initState(initialState: BridgeState): void {
112
+ this.state = { ...initialState, timestamp: Date.now() };
113
+ }
114
+
115
+ /**
116
+ * Get current state
117
+ */
118
+ getState(): BridgeState | null {
119
+ return this.state ? { ...this.state } : null;
120
+ }
121
+
122
+ /**
123
+ * Emit event to subscribers
124
+ */
125
+ emitEvent<T>(type: BridgeEventType, payload: T): void {
126
+ const event: BridgeEvent<T> = {
127
+ type,
128
+ payload,
129
+ timestamp: Date.now(),
130
+ };
131
+
132
+ // Emit to local listeners
133
+ this.emit("event", event);
134
+
135
+ // Call config callback if provided
136
+ if (this.config.onEvent) {
137
+ this.config.onEvent(event as BridgeEvent);
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Execute a command from external source
143
+ */
144
+ async executeCommand(command: BridgeCommand): Promise<BridgeCommandResult> {
145
+ return new Promise((resolve) => {
146
+ this.commandQueue.push({ command, resolve });
147
+ this.processQueue();
148
+ });
149
+ }
150
+
151
+ /**
152
+ * Process command queue
153
+ */
154
+ private async processQueue(): Promise<void> {
155
+ if (this.isProcessing || this.commandQueue.length === 0) {
156
+ return;
157
+ }
158
+
159
+ this.isProcessing = true;
160
+ const { command, resolve } = this.commandQueue.shift()!;
161
+
162
+ try {
163
+ const result = await this.handleCommand(command);
164
+ resolve(result);
165
+ } catch (error) {
166
+ resolve({
167
+ success: false,
168
+ error: error instanceof Error ? error.message : String(error),
169
+ });
170
+ } finally {
171
+ this.isProcessing = false;
172
+ this.processQueue();
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Handle individual command
178
+ */
179
+ private async handleCommand(command: BridgeCommand): Promise<BridgeCommandResult> {
180
+ // Most commands are handled by the TUI component itself
181
+ // This just validates and queues them
182
+ switch (command.type) {
183
+ case "get_state":
184
+ return {
185
+ success: true,
186
+ data: this.getState(),
187
+ };
188
+
189
+ case "get_screen":
190
+ // Screen capture is handled by TUI Bridge MCP directly via tmux
191
+ return {
192
+ success: true,
193
+ data: {
194
+ note: "Screen capture is handled by TUI Bridge MCP via tmux. Use tui_capture tool.",
195
+ state: this.getState(),
196
+ },
197
+ };
198
+
199
+ case "get_screen":
200
+ // Screen capture is handled by TUI Bridge MCP directly via tmux
201
+ return {
202
+ success: true,
203
+ data: {
204
+ note: "Screen capture is handled by TUI Bridge MCP via tmux. Use tui_capture tool.",
205
+ state: this.getState(),
206
+ },
207
+ };
208
+
209
+ default:
210
+ // Queue command for TUI to handle
211
+ this.emitEvent("command_executed", command);
212
+ return {
213
+ success: true,
214
+ data: { queued: true, command },
215
+ };
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Subscribe to events
221
+ */
222
+ subscribe(subscriberId: string): boolean {
223
+ this.subscribers.add(subscriberId);
224
+ return true;
225
+ }
226
+
227
+ /**
228
+ * Unsubscribe from events
229
+ */
230
+ unsubscribe(subscriberId: string): boolean {
231
+ return this.subscribers.delete(subscriberId);
232
+ }
233
+
234
+ /**
235
+ * Get subscriber count
236
+ */
237
+ getSubscriberCount(): number {
238
+ return this.subscribers.size;
239
+ }
240
+
241
+ /**
242
+ * Check if bridge is enabled
243
+ */
244
+ isEnabled(): boolean {
245
+ return this.config.enabled;
246
+ }
247
+
248
+ // ============================================
249
+ // SCREEN BUFFER API
250
+ // ============================================
251
+
252
+ /**
253
+ * Set terminal dimensions
254
+ */
255
+ setDimensions(width: number, height: number): void {
256
+ this.terminalDimensions = { width, height };
257
+ }
258
+
259
+ /**
260
+ * Get terminal dimensions
261
+ */
262
+ getDimensions(): { width: number; height: number } {
263
+ return { ...this.terminalDimensions };
264
+ }
265
+
266
+ /**
267
+ * Get screen buffer
268
+ * Returns the current screen buffer if available, or creates an empty one
269
+ */
270
+ getScreenBuffer(): ScreenBuffer {
271
+ if (this.screenBuffer) {
272
+ return this.screenBuffer;
273
+ }
274
+ return createBuffer(this.terminalDimensions.width, this.terminalDimensions.height);
275
+ }
276
+
277
+ /**
278
+ * Update screen buffer with raw terminal content
279
+ * @param rawContent - Raw terminal output with ANSI codes
280
+ */
281
+ updateScreenBuffer(rawContent: string): ScreenBuffer {
282
+ const chars = parseANSIText(rawContent);
283
+ this.screenBuffer = renderToScreenBuffer(
284
+ chars,
285
+ this.terminalDimensions.width,
286
+ this.terminalDimensions.height
287
+ );
288
+ return this.screenBuffer;
289
+ }
290
+
291
+ /**
292
+ * Export screen to specified format
293
+ * @param format - Export format (text, json, html, markdown)
294
+ * @param options - Export options
295
+ */
296
+ exportScreen(format: ExportFormat, options?: ExportOptions): string {
297
+ const buffer = this.getScreenBuffer();
298
+ return doExport(buffer, format, options);
299
+ }
300
+
301
+ /**
302
+ * Parse raw terminal content into a full ParsedScreen
303
+ * @param rawContent - Raw terminal output with ANSI codes
304
+ */
305
+ parseRawScreen(rawContent: string): ParsedScreen {
306
+ return parseScreen(
307
+ rawContent,
308
+ this.terminalDimensions.width,
309
+ this.terminalDimensions.height
310
+ );
311
+ }
312
+
313
+ /**
314
+ * Get detected UI elements from current screen buffer
315
+ */
316
+ getUIElements(): UIElement[] {
317
+ const buffer = this.getScreenBuffer();
318
+ return detectUIElements(buffer);
319
+ }
320
+
321
+ /**
322
+ * Clear screen buffer
323
+ */
324
+ clearScreenBuffer(): void {
325
+ this.screenBuffer = null;
326
+ }
327
+
328
+ /**
329
+ * Cleanup
330
+ */
331
+ destroy(): void {
332
+ this.removeAllListeners();
333
+ this.subscribers.clear();
334
+ this.commandQueue = [];
335
+ TUIBridge.instance = null;
336
+ }
337
+ }
338
+
339
+ // Re-export types
340
+ export type {
341
+ BridgeState,
342
+ BridgeEvent,
343
+ BridgeCommand,
344
+ BridgeCommandResult,
345
+ TUIBridgeConfig,
346
+ ParsedScreen,
347
+ ScreenBuffer,
348
+ ScreenCell,
349
+ UIElement,
350
+ UIElementType,
351
+ BridgeEventType,
352
+ };
353
+
354
+ // Re-export IPC Server
355
+ export {
356
+ IPCServer,
357
+ createIPCServer,
358
+ JSONRPCRequestSchema,
359
+ JSONRPCNotificationSchema,
360
+ IPCServerConfigSchema,
361
+ type JSONRPCRequest,
362
+ type JSONRPCSuccessResponse,
363
+ type JSONRPCErrorResponse,
364
+ type JSONRPCResponse,
365
+ type JSONRPCNotification,
366
+ type IPCServerConfig,
367
+ type IPCServerEventType,
368
+ type IPCServerEvent,
369
+ type ClientConnection,
370
+ } from "./ipc.js";