nova-terminal-assistant 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of nova-terminal-assistant might be problematic. Click here for more details.

Files changed (192) hide show
  1. package/README.md +358 -0
  2. package/bin/nova +38 -0
  3. package/bin/nova.js +12 -0
  4. package/package.json +67 -0
  5. package/src/cli/commands/SmartCompletion.ts +458 -0
  6. package/src/cli/index.ts +5 -0
  7. package/src/cli/startup/IFlowRepl.ts +212 -0
  8. package/src/cli/startup/InkBasedRepl.ts +1056 -0
  9. package/src/cli/startup/InteractiveRepl.ts +2833 -0
  10. package/src/cli/startup/NovaApp.ts +1861 -0
  11. package/src/cli/startup/index.ts +4 -0
  12. package/src/cli/startup/parseArgs.ts +293 -0
  13. package/src/cli/test-modules.ts +27 -0
  14. package/src/cli/ui/IFlowDropdown.ts +425 -0
  15. package/src/cli/ui/ModernReplUI.ts +276 -0
  16. package/src/cli/ui/SimpleSelector2.ts +215 -0
  17. package/src/cli/ui/components/ConfirmDialog.ts +176 -0
  18. package/src/cli/ui/components/ErrorPanel.ts +364 -0
  19. package/src/cli/ui/components/InkAppRunner.tsx +67 -0
  20. package/src/cli/ui/components/InkComponents.tsx +613 -0
  21. package/src/cli/ui/components/NovaInkApp.tsx +312 -0
  22. package/src/cli/ui/components/ProgressBar.ts +177 -0
  23. package/src/cli/ui/components/ProgressIndicator.ts +298 -0
  24. package/src/cli/ui/components/QuickActions.ts +396 -0
  25. package/src/cli/ui/components/SimpleErrorPanel.ts +231 -0
  26. package/src/cli/ui/components/StatusBar.ts +194 -0
  27. package/src/cli/ui/components/ThinkingBlockRenderer.ts +401 -0
  28. package/src/cli/ui/components/index.ts +27 -0
  29. package/src/cli/ui/ink-prototype.tsx +347 -0
  30. package/src/cli/utils/CliUI.ts +336 -0
  31. package/src/cli/utils/CompletionHelper.ts +388 -0
  32. package/src/cli/utils/EnhancedCompleter.test.ts +226 -0
  33. package/src/cli/utils/EnhancedCompleter.ts +513 -0
  34. package/src/cli/utils/ErrorEnhancer.ts +429 -0
  35. package/src/cli/utils/OutputFormatter.ts +193 -0
  36. package/src/cli/utils/index.ts +9 -0
  37. package/src/core/agents/AgentOrchestrator.ts +515 -0
  38. package/src/core/agents/index.ts +17 -0
  39. package/src/core/audit/AuditLogger.ts +509 -0
  40. package/src/core/audit/index.ts +11 -0
  41. package/src/core/auth/AuthManager.d.ts.map +1 -0
  42. package/src/core/auth/AuthManager.ts +138 -0
  43. package/src/core/auth/index.d.ts.map +1 -0
  44. package/src/core/auth/index.ts +2 -0
  45. package/src/core/config/ConfigManager.d.ts.map +1 -0
  46. package/src/core/config/ConfigManager.test.ts +183 -0
  47. package/src/core/config/ConfigManager.ts +1219 -0
  48. package/src/core/config/index.d.ts.map +1 -0
  49. package/src/core/config/index.ts +1 -0
  50. package/src/core/context/ContextBuilder.d.ts.map +1 -0
  51. package/src/core/context/ContextBuilder.ts +171 -0
  52. package/src/core/context/ContextCompressor.d.ts.map +1 -0
  53. package/src/core/context/ContextCompressor.ts +642 -0
  54. package/src/core/context/LayeredMemoryManager.ts +657 -0
  55. package/src/core/context/MemoryDiscovery.d.ts.map +1 -0
  56. package/src/core/context/MemoryDiscovery.ts +175 -0
  57. package/src/core/context/defaultSystemPrompt.d.ts.map +1 -0
  58. package/src/core/context/defaultSystemPrompt.ts +35 -0
  59. package/src/core/context/index.d.ts.map +1 -0
  60. package/src/core/context/index.ts +22 -0
  61. package/src/core/extensions/SkillGenerator.ts +421 -0
  62. package/src/core/extensions/SkillInstaller.d.ts.map +1 -0
  63. package/src/core/extensions/SkillInstaller.ts +257 -0
  64. package/src/core/extensions/SkillRegistry.d.ts.map +1 -0
  65. package/src/core/extensions/SkillRegistry.ts +361 -0
  66. package/src/core/extensions/SkillValidator.ts +525 -0
  67. package/src/core/extensions/index.ts +15 -0
  68. package/src/core/index.d.ts.map +1 -0
  69. package/src/core/index.ts +42 -0
  70. package/src/core/mcp/McpManager.d.ts.map +1 -0
  71. package/src/core/mcp/McpManager.ts +632 -0
  72. package/src/core/mcp/index.d.ts.map +1 -0
  73. package/src/core/mcp/index.ts +2 -0
  74. package/src/core/model/ModelClient.d.ts.map +1 -0
  75. package/src/core/model/ModelClient.ts +217 -0
  76. package/src/core/model/ModelConnectionTester.ts +363 -0
  77. package/src/core/model/ModelValidator.ts +348 -0
  78. package/src/core/model/index.d.ts.map +1 -0
  79. package/src/core/model/index.ts +6 -0
  80. package/src/core/model/providers/AnthropicProvider.d.ts.map +1 -0
  81. package/src/core/model/providers/AnthropicProvider.ts +279 -0
  82. package/src/core/model/providers/CodingPlanProvider.d.ts.map +1 -0
  83. package/src/core/model/providers/CodingPlanProvider.ts +210 -0
  84. package/src/core/model/providers/OllamaCloudProvider.d.ts.map +1 -0
  85. package/src/core/model/providers/OllamaCloudProvider.ts +405 -0
  86. package/src/core/model/providers/OllamaManager.d.ts.map +1 -0
  87. package/src/core/model/providers/OllamaManager.ts +201 -0
  88. package/src/core/model/providers/OllamaProvider.d.ts.map +1 -0
  89. package/src/core/model/providers/OllamaProvider.ts +73 -0
  90. package/src/core/model/providers/OpenAICompatibleProvider.d.ts.map +1 -0
  91. package/src/core/model/providers/OpenAICompatibleProvider.ts +327 -0
  92. package/src/core/model/providers/OpenAIProvider.d.ts.map +1 -0
  93. package/src/core/model/providers/OpenAIProvider.ts +29 -0
  94. package/src/core/model/providers/index.d.ts.map +1 -0
  95. package/src/core/model/providers/index.ts +12 -0
  96. package/src/core/model/types.d.ts.map +1 -0
  97. package/src/core/model/types.ts +77 -0
  98. package/src/core/security/ApprovalManager.d.ts.map +1 -0
  99. package/src/core/security/ApprovalManager.ts +174 -0
  100. package/src/core/security/FileFilter.d.ts.map +1 -0
  101. package/src/core/security/FileFilter.ts +141 -0
  102. package/src/core/security/HookExecutor.d.ts.map +1 -0
  103. package/src/core/security/HookExecutor.ts +178 -0
  104. package/src/core/security/SandboxExecutor.ts +447 -0
  105. package/src/core/security/index.d.ts.map +1 -0
  106. package/src/core/security/index.ts +8 -0
  107. package/src/core/session/AgentLoop.d.ts.map +1 -0
  108. package/src/core/session/AgentLoop.ts +501 -0
  109. package/src/core/session/SessionManager.d.ts.map +1 -0
  110. package/src/core/session/SessionManager.test.ts +183 -0
  111. package/src/core/session/SessionManager.ts +460 -0
  112. package/src/core/session/index.d.ts.map +1 -0
  113. package/src/core/session/index.ts +3 -0
  114. package/src/core/telemetry/Telemetry.d.ts.map +1 -0
  115. package/src/core/telemetry/Telemetry.ts +90 -0
  116. package/src/core/telemetry/TelemetryService.ts +531 -0
  117. package/src/core/telemetry/index.d.ts.map +1 -0
  118. package/src/core/telemetry/index.ts +12 -0
  119. package/src/core/testing/AutoFixer.ts +385 -0
  120. package/src/core/testing/ErrorAnalyzer.ts +499 -0
  121. package/src/core/testing/TestRunner.ts +265 -0
  122. package/src/core/testing/agent-cli-tests.ts +538 -0
  123. package/src/core/testing/index.ts +11 -0
  124. package/src/core/tools/ToolRegistry.d.ts.map +1 -0
  125. package/src/core/tools/ToolRegistry.test.ts +206 -0
  126. package/src/core/tools/ToolRegistry.ts +260 -0
  127. package/src/core/tools/impl/EditFileTool.d.ts.map +1 -0
  128. package/src/core/tools/impl/EditFileTool.ts +97 -0
  129. package/src/core/tools/impl/ListDirectoryTool.d.ts.map +1 -0
  130. package/src/core/tools/impl/ListDirectoryTool.ts +142 -0
  131. package/src/core/tools/impl/MemoryTool.d.ts.map +1 -0
  132. package/src/core/tools/impl/MemoryTool.ts +102 -0
  133. package/src/core/tools/impl/ReadFileTool.d.ts.map +1 -0
  134. package/src/core/tools/impl/ReadFileTool.ts +58 -0
  135. package/src/core/tools/impl/SearchContentTool.d.ts.map +1 -0
  136. package/src/core/tools/impl/SearchContentTool.ts +94 -0
  137. package/src/core/tools/impl/SearchFileTool.d.ts.map +1 -0
  138. package/src/core/tools/impl/SearchFileTool.ts +61 -0
  139. package/src/core/tools/impl/ShellTool.d.ts.map +1 -0
  140. package/src/core/tools/impl/ShellTool.ts +118 -0
  141. package/src/core/tools/impl/TaskTool.d.ts.map +1 -0
  142. package/src/core/tools/impl/TaskTool.ts +207 -0
  143. package/src/core/tools/impl/TodoTool.d.ts.map +1 -0
  144. package/src/core/tools/impl/TodoTool.ts +122 -0
  145. package/src/core/tools/impl/WebFetchTool.d.ts.map +1 -0
  146. package/src/core/tools/impl/WebFetchTool.ts +103 -0
  147. package/src/core/tools/impl/WebSearchTool.d.ts.map +1 -0
  148. package/src/core/tools/impl/WebSearchTool.ts +89 -0
  149. package/src/core/tools/impl/WriteFileTool.d.ts.map +1 -0
  150. package/src/core/tools/impl/WriteFileTool.ts +49 -0
  151. package/src/core/tools/impl/index.d.ts.map +1 -0
  152. package/src/core/tools/impl/index.ts +16 -0
  153. package/src/core/tools/index.d.ts.map +1 -0
  154. package/src/core/tools/index.ts +7 -0
  155. package/src/core/tools/schemas/execution.d.ts.map +1 -0
  156. package/src/core/tools/schemas/execution.ts +42 -0
  157. package/src/core/tools/schemas/file.d.ts.map +1 -0
  158. package/src/core/tools/schemas/file.ts +119 -0
  159. package/src/core/tools/schemas/index.d.ts.map +1 -0
  160. package/src/core/tools/schemas/index.ts +11 -0
  161. package/src/core/tools/schemas/memory.d.ts.map +1 -0
  162. package/src/core/tools/schemas/memory.ts +52 -0
  163. package/src/core/tools/schemas/orchestration.d.ts.map +1 -0
  164. package/src/core/tools/schemas/orchestration.ts +44 -0
  165. package/src/core/tools/schemas/search.d.ts.map +1 -0
  166. package/src/core/tools/schemas/search.ts +112 -0
  167. package/src/core/tools/schemas/todo.d.ts.map +1 -0
  168. package/src/core/tools/schemas/todo.ts +32 -0
  169. package/src/core/tools/schemas/web.d.ts.map +1 -0
  170. package/src/core/tools/schemas/web.ts +86 -0
  171. package/src/core/types/config.d.ts.map +1 -0
  172. package/src/core/types/config.ts +200 -0
  173. package/src/core/types/errors.d.ts.map +1 -0
  174. package/src/core/types/errors.ts +204 -0
  175. package/src/core/types/index.d.ts.map +1 -0
  176. package/src/core/types/index.ts +8 -0
  177. package/src/core/types/session.d.ts.map +1 -0
  178. package/src/core/types/session.ts +216 -0
  179. package/src/core/types/tools.d.ts.map +1 -0
  180. package/src/core/types/tools.ts +157 -0
  181. package/src/core/utils/CheckpointManager.d.ts.map +1 -0
  182. package/src/core/utils/CheckpointManager.ts +327 -0
  183. package/src/core/utils/Logger.d.ts.map +1 -0
  184. package/src/core/utils/Logger.ts +98 -0
  185. package/src/core/utils/RetryManager.ts +471 -0
  186. package/src/core/utils/TokenCounter.d.ts.map +1 -0
  187. package/src/core/utils/TokenCounter.ts +414 -0
  188. package/src/core/utils/VectorMemoryStore.ts +440 -0
  189. package/src/core/utils/helpers.d.ts.map +1 -0
  190. package/src/core/utils/helpers.ts +89 -0
  191. package/src/core/utils/index.d.ts.map +1 -0
  192. package/src/core/utils/index.ts +19 -0
@@ -0,0 +1,364 @@
1
+ // ============================================================================
2
+ // ErrorPanel - Modern error display component for Nova CLI
3
+ // ============================================================================
4
+
5
+ import chalk from 'chalk';
6
+ // import type { NovaError } from '../../../core/types/errors.js';
7
+
8
+ export interface ErrorPanelOptions {
9
+ showStack?: boolean;
10
+ showSuggestions?: boolean;
11
+ maxLines?: number;
12
+ compact?: boolean;
13
+ }
14
+
15
+ export class ErrorPanel {
16
+ private options: ErrorPanelOptions = {};
17
+
18
+ constructor(options: ErrorPanelOptions = {}) {
19
+ this.options = {
20
+ showStack: false,
21
+ showSuggestions: true,
22
+ maxLines: 20,
23
+ compact: false,
24
+ ...options
25
+ };
26
+ }
27
+
28
+ display(error: Error | string, context?: any): void {
29
+ const errorInfo = this.parseError(error);
30
+
31
+ if (this.options.compact) {
32
+ this.displayCompact(errorInfo);
33
+ } else {
34
+ this.displayFull(errorInfo, context);
35
+ }
36
+ }
37
+
38
+ private parseError(error: Error | string): ErrorInfo {
39
+ const errorObj = typeof error === 'string' ? new Error(error) : error;
40
+
41
+ // Try to identify Nova-specific errors
42
+ let code: string | undefined;
43
+ let category: ErrorCategory = 'unknown';
44
+ let suggestion: string[] = [];
45
+
46
+ // Check for API key related errors
47
+ if (error.message.includes('API key') ||
48
+ (error as any).name === 'AUTH_ERROR' ||
49
+ (error as any).code === 'AUTH_ERROR') {
50
+ category = 'auth';
51
+ code = 'AUTH_ERROR';
52
+ suggestion = ['Check your API key configuration', 'Verify provider settings'];
53
+ } else if (error.message.includes('config') ||
54
+ error.message.includes('yaml')) {
55
+ category = 'config';
56
+ code = 'CONFIG_ERROR';
57
+ suggestion = ['Validate your config file syntax', 'Run nova config edit to fix'];
58
+ } else if (error.message.includes('network') ||
59
+ error.message.includes('connection')) {
60
+ category = 'network';
61
+ code = 'NETWORK_ERROR';
62
+ suggestion = ['Check internet connection', 'Verify proxy settings', 'Try again later'];
63
+ } else if (error.message.includes('model')) {
64
+ category = 'model';
65
+ code = 'MODEL_ERROR';
66
+ suggestion = ['Use nova model list to see available models', 'Check provider configuration'];
67
+ } else if (error.message.includes('timeout')) {
68
+ category = 'timeout';
69
+ code = 'TIMEOUT_ERROR';
70
+ suggestion = ['Request timed out', 'Try again with a simpler request'];
71
+ } else if (error.message.includes('quota') ||
72
+ error.message.includes('billing')) {
73
+ category = 'quota';
74
+ code = 'QUOTA_EXCEEDED';
75
+ suggestion = ['Check your account billing status', 'Contact support for quota increase'];
76
+ } else if (error.message.includes('file') ||
77
+ error.message.includes('permission')) {
78
+ category = 'permission';
79
+ code = 'PERMISSION_ERROR';
80
+ suggestion = ['Check file permissions', 'Verify you have access to the requested resource'];
81
+ } else if (error.message.includes('rate limit') ||
82
+ error.message.includes('too many requests')) {
83
+ category = 'validation';
84
+ code = 'RATE_LIMIT_EXCEEDED';
85
+ suggestion = ['Wait a few minutes before trying again', 'Consider upgrading your plan for higher limits'];
86
+ } else {
87
+ // Generic error handling
88
+ category = 'unknown';
89
+ code = 'UNKNOWN_ERROR';
90
+ suggestion = ['Check the Nova CLI documentation', 'Search for your error online', 'Contact support if issue persists'];
91
+ }
92
+ category = 'auth';
93
+ code = 'AUTH_ERROR';
94
+ suggestion = ['Check your API key configuration', 'Verify provider settings'];
95
+ } else if (error.message.includes('network') || error.message.includes('connection')) {
96
+ category = 'network';
97
+ code = 'NETWORK_ERROR';
98
+ suggestion = ['Check internet connection', 'Verify proxy settings', 'Try again later'];
99
+ } else if (error.message.includes('config') || error.message.includes('yaml')) {
100
+ category = 'config';
101
+ code = 'CONFIG_ERROR';
102
+ suggestion = ['Check config file syntax', 'Run nova config edit to fix'];
103
+ }
104
+
105
+ return {
106
+ name: errorObj.name,
107
+ message: errorObj.message,
108
+ code,
109
+ category,
110
+ suggestion,
111
+ stack: this.options.showStack ? errorObj.stack : undefined
112
+ };
113
+ }
114
+
115
+ private displayCompact(errorInfo: ErrorInfo): void {
116
+ const icon = this.getIcon(errorInfo.category);
117
+ const color = this.getColor(errorInfo.category);
118
+
119
+ console.log(
120
+ chalk[color](`${icon} ${errorInfo.message}`)
121
+ );
122
+ }
123
+
124
+ private displayFull(errorInfo: ErrorInfo, context?: any): void {
125
+ console.log('\n');
126
+ console.log(chalk.bgRed.white.bold(' ERROR '));
127
+ console.log(chalk.red('-'.repeat(50)));
128
+
129
+ // Error header with category
130
+ const categoryLabel = this.formatCategory(errorInfo.category);
131
+ const codeLabel = errorInfo.code ? ` [${errorInfo.code}]` : '';
132
+
133
+ console.log(chalk.red(` ${categoryLabel}${codeLabel}`));
134
+
135
+ // Error message
136
+ console.log('');
137
+ console.log(chalk.white('Message:'));
138
+ console.log(chalk.yellow(` ${errorInfo.message}`));
139
+
140
+ // Context info
141
+ if (context) {
142
+ console.log('');
143
+ console.log(chalk.white('Context:'));
144
+ if (typeof context === 'object') {
145
+ Object.entries(context).forEach(([key, value]) => {
146
+ console.log(chalk.gray(` ${key}: ${String(value)}`));
147
+ });
148
+ } else {
149
+ console.log(chalk.gray(` ${context}`));
150
+ }
151
+ }
152
+
153
+ // Suggestions
154
+ if (errorInfo.suggestion.length > 0 && this.options.showSuggestions) {
155
+ console.log('');
156
+ console.log(chalk.white('Suggested actions:'));
157
+ errorInfo.suggestion.forEach((s, i) => {
158
+ console.log(chalk.green(` ${i + 1}. ${s}`));
159
+ });
160
+
161
+ // Quick commands
162
+ console.log('');
163
+ console.log(chalk.cyan('Quick commands:'));
164
+ switch (errorInfo.category) {
165
+ case 'auth':
166
+ console.log(chalk.cyan(' • nova auth set <provider>'));
167
+ console.log(chalk.cyan(' • Check environment variables'));
168
+ break;
169
+ case 'config':
170
+ console.log(chalk.cyan(' • nova config edit'));
171
+ console.log(chalk.cyan(' • Check ~/.nova/config.yaml'));
172
+ break;
173
+ case 'network':
174
+ console.log(chalk.cyan(' • Check internet connection'));
175
+ console.log(chalk.cyan(' • Try nova ollama status'));
176
+ break;
177
+ case 'model':
178
+ console.log(chalk.cyan(' • nova model list'));
179
+ console.log(chalk.cyan(' • Check provider configuration'));
180
+ break;
181
+ }
182
+ }
183
+
184
+ // Stack trace (if enabled and not too long)
185
+ if (errorInfo.stack && this.options.showStack && errorInfo.stack.split('\n').length <= this.options.maxLines) {
186
+ console.log('');
187
+ console.log(chalk.white('Stack trace:'));
188
+ console.log(chalk.gray(errorInfo.stack));
189
+ } else if (errorInfo.stack) {
190
+ console.log('');
191
+ console.log(chalk.gray('(Stack trace truncated. Use --verbose for full trace.)'));
192
+ }
193
+
194
+ console.log('');
195
+ console.log(chalk.red('-'.repeat(50)));
196
+ console.log('');
197
+ }
198
+
199
+ private getIcon(category: ErrorCategory): string {
200
+ const icons = {
201
+ auth: '🔑',
202
+ config: '⚙️',
203
+ network: '🌐',
204
+ model: '🤖',
205
+ file: '📁',
206
+ execution: '⚡',
207
+ validation: '⚠️',
208
+ permission: '🚫',
209
+ timeout: '⏰',
210
+ quota: '💰',
211
+ unknown: '❌'
212
+ };
213
+
214
+ return icons[category] || icons.unknown;
215
+ }
216
+
217
+ private getColor(category: ErrorCategory): keyof typeof chalk {
218
+ const colors = {
219
+ auth: 'red',
220
+ config: 'yellow',
221
+ network: 'blue',
222
+ model: 'cyan',
223
+ file: 'green',
224
+ execution: 'magenta',
225
+ validation: 'yellow',
226
+ permission: 'red',
227
+ timeout: 'yellow',
228
+ quota: 'red',
229
+ unknown: 'red'
230
+ };
231
+
232
+ return colors[category] || colors.unknown;
233
+ }
234
+
235
+ private formatCategory(category: ErrorCategory): string {
236
+ const labels = {
237
+ auth: 'Authentication Error',
238
+ config: 'Configuration Error',
239
+ network: 'Network Error',
240
+ model: 'Model Error',
241
+ file: 'File System Error',
242
+ execution: 'Execution Error',
243
+ validation: 'Validation Error',
244
+ permission: 'Permission Error',
245
+ timeout: 'Timeout Error',
246
+ quota: 'Quota Exceeded',
247
+ unknown: 'Unknown Error'
248
+ };
249
+
250
+ return labels[category] || labels.unknown;
251
+ }
252
+
253
+ private getErrorSuggestions(category: ErrorCategory, code?: string): string[] {
254
+ const suggestions: string[] = [];
255
+
256
+ // Generic suggestions based on category
257
+ switch (category) {
258
+ case 'auth':
259
+ suggestions.push('Check your API key in nova auth status');
260
+ suggestions.push('Verify the provider supports your selected model');
261
+ break;
262
+
263
+ case 'config':
264
+ suggestions.push('Validate your config.yaml file syntax');
265
+ suggestions.push('Run nova config edit to fix configuration');
266
+ break;
267
+
268
+ case 'model':
269
+ suggestions.push('Use nova model list to see available models');
270
+ suggestions.push('Check model alias configuration');
271
+ break;
272
+
273
+ case 'network':
274
+ suggestions.push('Check internet connection');
275
+ suggestions.push('Verify proxy settings');
276
+ break;
277
+
278
+ case 'timeout':
279
+ suggestions.push('Request timed out');
280
+ suggestions.push('Try again with a simpler request');
281
+ break;
282
+
283
+ case 'quota':
284
+ suggestions.push('Check your account billing status');
285
+ suggestions.push('Contact support for quota increase');
286
+ break;
287
+
288
+ default:
289
+ suggestions.push('Check the Nova CLI documentation');
290
+ suggestions.push('Search for your error code online');
291
+ break;
292
+ }
293
+
294
+ return suggestions;
295
+ }
296
+
297
+ // Static utility methods
298
+ static async handleAsyncError<T>(
299
+ promise: Promise<T>,
300
+ context?: any
301
+ ): Promise<T> {
302
+ try {
303
+ return await promise;
304
+ } catch (error) {
305
+ const panel = new ErrorPanel();
306
+ panel.display(error, context);
307
+ throw error; // Re-throw after display
308
+ }
309
+ }
310
+
311
+ static formatErrorForLogging(error: Error): LoggableError {
312
+ return {
313
+ timestamp: new Date().toISOString(),
314
+ name: error.name,
315
+ message: error.message,
316
+ stack: error.stack,
317
+ category: this.inferCategory(error),
318
+ code: this.extractErrorCode(error)
319
+ };
320
+ }
321
+
322
+ private static inferCategory(error: Error): ErrorCategory {
323
+ const msg = error.message.toLowerCase();
324
+
325
+ if (msg.includes('api key') || msg.includes('authentication')) return 'auth';
326
+ if (msg.includes('config') || msg.includes('yaml')) return 'config';
327
+ if (msg.includes('network') || msg.includes('connection')) return 'network';
328
+ if (msg.includes('model')) return 'model';
329
+ if (msg.includes('file') || msg.includes('permission')) return 'file';
330
+ if (msg.includes('timeout')) return 'timeout';
331
+ if (msg.includes('quota') || msg.includes('billing')) return 'quota';
332
+
333
+ return 'unknown';
334
+ }
335
+
336
+ private static extractErrorCode(error: Error): string | undefined {
337
+ const match = error.message.match(/\[(\w+)\]/);
338
+ return match ? match[1] : undefined;
339
+ }
340
+ }
341
+
342
+ // Type definitions
343
+ interface ErrorInfo {
344
+ name: string;
345
+ message: string;
346
+ code?: string;
347
+ category: ErrorCategory;
348
+ suggestion: string[];
349
+ stack?: string;
350
+ }
351
+
352
+ type ErrorCategory =
353
+ | 'auth' | 'config' | 'network' | 'model' | 'file'
354
+ | 'execution' | 'validation' | 'permission'
355
+ | 'timeout' | 'quota' | 'unknown';
356
+
357
+ interface LoggableError {
358
+ timestamp: string;
359
+ name: string;
360
+ message: string;
361
+ stack?: string;
362
+ category: ErrorCategory;
363
+ code?: string;
364
+ }
@@ -0,0 +1,67 @@
1
+ // ============================================================================
2
+ // InkAppRunner - Simple Ink UI entry point
3
+ // This is a lightweight bridge that only handles UI rendering.
4
+ // Business logic is handled by the caller (NovaApp/InteractiveRepl)
5
+ // ============================================================================
6
+
7
+ import React from 'react';
8
+ import { render, RenderOptions } from 'ink';
9
+ import { NovaInkApp } from './NovaInkApp.js';
10
+
11
+ // ============================================================================
12
+ // Types
13
+ // ============================================================================
14
+
15
+ export interface InkAppOptions {
16
+ initialModel?: string;
17
+ initialMode?: 'auto' | 'plan' | 'ask';
18
+ sessionId?: string;
19
+ onSubmit?: (input: string) => Promise<void>;
20
+ onCommand?: (command: string) => Promise<void>;
21
+ }
22
+
23
+ // ============================================================================
24
+ // InkAppRunner Class
25
+ // ============================================================================
26
+
27
+ export class InkAppRunner {
28
+ private options: InkAppOptions;
29
+
30
+ constructor(options: InkAppOptions) {
31
+ this.options = options;
32
+ }
33
+
34
+ /**
35
+ * Start the Ink UI application
36
+ */
37
+ async start(): Promise<void> {
38
+ const { waitUntilExit } = render(
39
+ <NovaInkApp
40
+ initialModel={this.options.initialModel || 'claude-3-sonnet'}
41
+ initialMode={this.options.initialMode || 'auto'}
42
+ sessionId={this.options.sessionId}
43
+ onSubmit={this.options.onSubmit}
44
+ onCommand={this.options.onCommand}
45
+ />
46
+ );
47
+
48
+ await waitUntilExit();
49
+ }
50
+ }
51
+
52
+ // ============================================================================
53
+ // Factory Function
54
+ // ============================================================================
55
+
56
+ export function createInkApp(options: InkAppOptions): InkAppRunner {
57
+ return new InkAppRunner(options);
58
+ }
59
+
60
+ // ============================================================================
61
+ // Standalone Run (for testing)
62
+ // ============================================================================
63
+
64
+ export async function runInkApp(options: InkAppOptions = {}): Promise<void> {
65
+ const app = createInkApp(options);
66
+ await app.start();
67
+ }