nitrostack 1.0.57 → 1.0.59

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 (65) hide show
  1. package/dist/widgets/index.d.ts +4 -4
  2. package/dist/widgets/index.d.ts.map +1 -1
  3. package/dist/widgets/index.js +3 -3
  4. package/dist/widgets/index.js.map +1 -1
  5. package/package.json +8 -2
  6. package/ARCHITECTURE.md +0 -302
  7. package/CHANGELOG.md +0 -49
  8. package/CONTRIBUTING.md +0 -182
  9. package/NOTICE +0 -153
  10. package/jest.config.js +0 -21
  11. package/src/assets/nitrocloud.png +0 -0
  12. package/src/studio/README.md +0 -140
  13. package/src/studio/app/api/auth/fetch-metadata/route.ts +0 -71
  14. package/src/studio/app/api/auth/register-client/route.ts +0 -67
  15. package/src/studio/app/api/chat/route.ts +0 -250
  16. package/src/studio/app/api/health/checks/route.ts +0 -42
  17. package/src/studio/app/api/health/route.ts +0 -13
  18. package/src/studio/app/api/init/route.ts +0 -109
  19. package/src/studio/app/api/ping/route.ts +0 -13
  20. package/src/studio/app/api/prompts/[name]/route.ts +0 -21
  21. package/src/studio/app/api/prompts/route.ts +0 -13
  22. package/src/studio/app/api/resources/[...uri]/route.ts +0 -18
  23. package/src/studio/app/api/resources/route.ts +0 -13
  24. package/src/studio/app/api/roots/route.ts +0 -13
  25. package/src/studio/app/api/sampling/route.ts +0 -14
  26. package/src/studio/app/api/tools/[name]/call/route.ts +0 -41
  27. package/src/studio/app/api/tools/route.ts +0 -23
  28. package/src/studio/app/api/widget-examples/route.ts +0 -44
  29. package/src/studio/app/auth/callback/page.tsx +0 -175
  30. package/src/studio/app/auth/page.tsx +0 -560
  31. package/src/studio/app/chat/page.tsx +0 -1133
  32. package/src/studio/app/chat/page.tsx.backup +0 -390
  33. package/src/studio/app/globals.css +0 -486
  34. package/src/studio/app/health/page.tsx +0 -179
  35. package/src/studio/app/layout.tsx +0 -68
  36. package/src/studio/app/logs/page.tsx +0 -279
  37. package/src/studio/app/page.tsx +0 -351
  38. package/src/studio/app/page.tsx.backup +0 -346
  39. package/src/studio/app/ping/page.tsx +0 -209
  40. package/src/studio/app/prompts/page.tsx +0 -230
  41. package/src/studio/app/resources/page.tsx +0 -315
  42. package/src/studio/app/settings/page.tsx +0 -199
  43. package/src/studio/branding.md +0 -807
  44. package/src/studio/components/EnlargeModal.tsx +0 -138
  45. package/src/studio/components/LogMessage.tsx +0 -153
  46. package/src/studio/components/MarkdownRenderer.tsx +0 -410
  47. package/src/studio/components/Sidebar.tsx +0 -295
  48. package/src/studio/components/ToolCard.tsx +0 -139
  49. package/src/studio/components/WidgetRenderer.tsx +0 -346
  50. package/src/studio/lib/api.ts +0 -207
  51. package/src/studio/lib/http-client-transport.ts +0 -222
  52. package/src/studio/lib/llm-service.ts +0 -480
  53. package/src/studio/lib/log-manager.ts +0 -76
  54. package/src/studio/lib/mcp-client.ts +0 -258
  55. package/src/studio/lib/store.ts +0 -192
  56. package/src/studio/lib/theme-provider.tsx +0 -50
  57. package/src/studio/lib/types.ts +0 -107
  58. package/src/studio/lib/widget-loader.ts +0 -90
  59. package/src/studio/middleware.ts +0 -27
  60. package/src/studio/next.config.js +0 -38
  61. package/src/studio/package.json +0 -35
  62. package/src/studio/postcss.config.mjs +0 -10
  63. package/src/studio/public/nitrocloud.png +0 -0
  64. package/src/studio/tailwind.config.ts +0 -67
  65. package/src/studio/tsconfig.json +0 -42
@@ -1,68 +0,0 @@
1
- import type { Metadata } from 'next';
2
- import './globals.css';
3
- import '@fontsource/inter/400.css';
4
- import '@fontsource/inter/500.css';
5
- import '@fontsource/inter/600.css';
6
- import '@fontsource/inter/700.css';
7
- import '@fontsource/jetbrains-mono/400.css';
8
- import '@fontsource/jetbrains-mono/500.css';
9
- import { Sidebar } from '@/components/Sidebar';
10
- import { EnlargeModal } from '@/components/EnlargeModal';
11
-
12
- export const metadata: Metadata = {
13
- title: 'NitroStudio - MCP Development Suite',
14
- description: 'Professional AI-powered development environment for Model Context Protocol (MCP) servers. Built with NitroStack.',
15
- keywords: ['MCP', 'Model Context Protocol', 'AI Development', 'NitroStack', 'NitroStudio'],
16
- authors: [{ name: 'NitroStack Team' }],
17
- icons: {
18
- icon: '/favicon.ico',
19
- },
20
- };
21
-
22
- export default function RootLayout({
23
- children,
24
- }: {
25
- children: React.ReactNode;
26
- }) {
27
- return (
28
- <html lang="en" suppressHydrationWarning className="antialiased">
29
- <head>
30
- <script
31
- dangerouslySetInnerHTML={{
32
- __html: `
33
- // Force dark mode
34
- document.documentElement.className = 'dark antialiased';
35
- `,
36
- }}
37
- />
38
- </head>
39
- <body className="min-h-screen font-sans">
40
- <div className="flex min-h-screen bg-gradient-to-br from-background via-background to-muted/20">
41
- <Sidebar />
42
- <main className="flex-1 transition-all duration-300 ease-in-out" style={{ marginLeft: 'var(--sidebar-width, 15rem)' }}>
43
- <div className="min-h-screen p-3 sm:p-6 md:p-8">
44
- {children}
45
- </div>
46
- </main>
47
- </div>
48
- {/* Global Modal - Available on all pages */}
49
- <EnlargeModal />
50
- {/* CSS Variable for sidebar width */}
51
- <script
52
- dangerouslySetInnerHTML={{
53
- __html: `
54
- function updateSidebarWidth() {
55
- const isCollapsed = localStorage.getItem('sidebar_collapsed') === 'true';
56
- document.documentElement.style.setProperty('--sidebar-width', isCollapsed ? '4rem' : '15rem');
57
- }
58
- updateSidebarWidth();
59
- window.addEventListener('storage', updateSidebarWidth);
60
- // Update on custom event
61
- window.addEventListener('sidebar-toggle', updateSidebarWidth);
62
- `,
63
- }}
64
- />
65
- </body>
66
- </html>
67
- );
68
- }
@@ -1,279 +0,0 @@
1
- 'use client';
2
-
3
- import { useEffect, useState, useRef } from 'react';
4
- import { Terminal, Download, Copy, Trash2, Play, Pause, Filter } from 'lucide-react';
5
-
6
- interface LogEntry {
7
- timestamp: string;
8
- level: 'info' | 'error' | 'warn' | 'debug';
9
- message: string;
10
- data?: any;
11
- }
12
-
13
- export default function LogsPage() {
14
- const [logs, setLogs] = useState<LogEntry[]>([]);
15
- const [isStreaming, setIsStreaming] = useState(true);
16
- const [autoScroll, setAutoScroll] = useState(true);
17
- const [filter, setFilter] = useState<string>('all');
18
- const [error, setError] = useState<string | null>(null);
19
- const logsEndRef = useRef<HTMLDivElement>(null);
20
- const eventSourceRef = useRef<EventSource | null>(null);
21
-
22
- // Auto-scroll to bottom
23
- useEffect(() => {
24
- if (autoScroll && logsEndRef.current) {
25
- logsEndRef.current.scrollIntoView({ behavior: 'smooth' });
26
- }
27
- }, [logs, autoScroll]);
28
-
29
- // Connect to SSE stream
30
- useEffect(() => {
31
- if (!isStreaming) return;
32
-
33
- const eventSource = new EventSource('http://localhost:3004/mcp-logs');
34
- eventSourceRef.current = eventSource;
35
-
36
- eventSource.onopen = () => {
37
- setError(null);
38
- };
39
-
40
- eventSource.onmessage = (event) => {
41
- try {
42
- const { level, message, timestamp, ...data } = JSON.parse(event.data);
43
- const log: LogEntry = { level, message, timestamp, data };
44
- setLogs((prev) => [...prev, log]);
45
- } catch (error) {
46
- console.error('Failed to parse log:', error);
47
- }
48
- };
49
-
50
- eventSource.onerror = (error) => {
51
- console.error('SSE error:', error);
52
- setError('Failed to connect to log stream. Is the MCP server running?');
53
- // Don't close the event source here, it will try to reconnect automatically
54
- };
55
-
56
- return () => {
57
- eventSource.close();
58
- };
59
- }, [isStreaming]);
60
-
61
- const clearLogs = () => {
62
- setLogs([]);
63
- };
64
-
65
- const downloadLogs = () => {
66
- const logsText = logs.map(log =>
67
- `[${log.timestamp}] [${log.level.toUpperCase()}] ${log.message}${log.data ? '\n' + JSON.stringify(log.data, null, 2) : ''}`
68
- ).join('\n\n');
69
-
70
- const blob = new Blob([logsText], { type: 'text/plain' });
71
- const url = URL.createObjectURL(blob);
72
- const a = document.createElement('a');
73
- a.href = url;
74
- a.download = `nitrostack-logs-${new Date().toISOString()}.txt`;
75
- a.click();
76
- URL.revokeObjectURL(url);
77
- };
78
-
79
- const copyLogs = async () => {
80
- const logsText = logs.map(log =>
81
- `[${log.timestamp}] [${log.level.toUpperCase()}] ${log.message}${log.data ? '\n' + JSON.stringify(log.data, null, 2) : ''}`
82
- ).join('\n\n');
83
-
84
- await navigator.clipboard.writeText(logsText);
85
- // Could add a toast notification here
86
- };
87
-
88
- const toggleStreaming = () => {
89
- setIsStreaming(!isStreaming);
90
- };
91
-
92
- const filteredLogs = filter === 'all'
93
- ? logs
94
- : logs.filter(log => log.level === filter);
95
-
96
- const getLevelColor = (level: string) => {
97
- switch (level) {
98
- case 'error': return 'text-red-400';
99
- case 'warn': return 'text-yellow-400';
100
- case 'debug': return 'text-blue-400';
101
- default: return 'text-emerald-400';
102
- }
103
- };
104
-
105
- const getLevelBg = (level: string) => {
106
- switch (level) {
107
- case 'error': return 'bg-red-500/10 border-red-500/20';
108
- case 'warn': return 'bg-yellow-500/10 border-yellow-500/20';
109
- case 'debug': return 'bg-blue-500/10 border-blue-500/20';
110
- default: return 'bg-emerald-500/10 border-emerald-500/20';
111
- }
112
- };
113
-
114
- const formatData = (data: any) => {
115
- try {
116
- return JSON.stringify(data, null, 2);
117
- } catch {
118
- return String(data);
119
- }
120
- };
121
-
122
- return (
123
- <div className="flex flex-col h-screen bg-black">
124
- {/* Header */}
125
- <div className="flex items-center justify-between px-6 py-4 bg-gradient-to-r from-slate-900 via-slate-800 to-slate-900 border-b border-slate-700">
126
- <div className="flex items-center gap-3">
127
- <div className="p-2 rounded-lg bg-emerald-500/10 border border-emerald-500/20">
128
- <Terminal className="w-5 h-5 text-emerald-400" />
129
- </div>
130
- <div>
131
- <h1 className="text-xl font-bold text-white">Server Logs</h1>
132
- <p className="text-sm text-slate-400">Real-time MCP server logging</p>
133
- </div>
134
- </div>
135
-
136
- <div className="flex items-center gap-2">
137
- {/* Filter */}
138
- <select
139
- value={filter}
140
- onChange={(e) => setFilter(e.target.value)}
141
- className="px-3 py-2 bg-slate-800 border border-slate-700 rounded-lg text-sm text-white focus:outline-none focus:ring-2 focus:ring-emerald-500"
142
- >
143
- <option value="all">All Levels</option>
144
- <option value="info">Info</option>
145
- <option value="warn">Warnings</option>
146
- <option value="error">Errors</option>
147
- <option value="debug">Debug</option>
148
- </select>
149
-
150
- {/* Auto-scroll toggle */}
151
- <button
152
- onClick={() => setAutoScroll(!autoScroll)}
153
- className={`px-3 py-2 rounded-lg text-sm font-medium transition-colors ${
154
- autoScroll
155
- ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30'
156
- : 'bg-slate-800 text-slate-400 border border-slate-700 hover:bg-slate-700'
157
- }`}
158
- >
159
- Auto-scroll
160
- </button>
161
-
162
- {/* Streaming toggle */}
163
- <button
164
- onClick={toggleStreaming}
165
- className={`p-2 rounded-lg transition-colors ${
166
- isStreaming
167
- ? 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/30'
168
- : 'bg-slate-800 text-slate-400 border border-slate-700 hover:bg-slate-700'
169
- }`}
170
- title={isStreaming ? 'Pause streaming' : 'Resume streaming'}
171
- >
172
- {isStreaming ? <Pause className="w-4 h-4" /> : <Play className="w-4 h-4" />}
173
- </button>
174
-
175
- {/* Copy */}
176
- <button
177
- onClick={copyLogs}
178
- className="p-2 bg-slate-800 border border-slate-700 rounded-lg text-slate-400 hover:bg-slate-700 hover:text-white transition-colors"
179
- title="Copy logs"
180
- >
181
- <Copy className="w-4 h-4" />
182
- </button>
183
-
184
- {/* Download */}
185
- <button
186
- onClick={downloadLogs}
187
- className="p-2 bg-slate-800 border border-slate-700 rounded-lg text-slate-400 hover:bg-slate-700 hover:text-white transition-colors"
188
- title="Download logs"
189
- >
190
- <Download className="w-4 h-4" />
191
- </button>
192
-
193
- {/* Clear */}
194
- <button
195
- onClick={clearLogs}
196
- className="p-2 bg-slate-800 border border-slate-700 rounded-lg text-slate-400 hover:bg-red-900/50 hover:text-red-400 hover:border-red-500/30 transition-colors"
197
- title="Clear logs"
198
- >
199
- <Trash2 className="w-4 h-4" />
200
- </button>
201
- </div>
202
- </div>
203
-
204
- {/* Error Display */}
205
- {error && (
206
- <div className="bg-red-500/10 text-red-400 px-6 py-3 border-b border-red-500/20 text-sm">
207
- <strong>Connection Error:</strong> {error}
208
- </div>
209
- )}
210
-
211
- {/* Stats Bar */}
212
- <div className="flex items-center gap-4 px-6 py-3 bg-slate-900/50 border-b border-slate-800">
213
- <div className="flex items-center gap-2 text-sm">
214
- <span className="text-slate-400">Total:</span>
215
- <span className="font-mono font-bold text-white">{logs.length}</span>
216
- </div>
217
- <div className="flex items-center gap-2 text-sm">
218
- <span className="text-slate-400">Filtered:</span>
219
- <span className="font-mono font-bold text-white">{filteredLogs.length}</span>
220
- </div>
221
- <div className="flex items-center gap-2 text-sm">
222
- <div className="w-2 h-2 rounded-full bg-emerald-500 animate-pulse" />
223
- <span className="text-slate-400">
224
- {isStreaming ? 'Streaming' : 'Paused'}
225
- </span>
226
- </div>
227
- </div>
228
-
229
- {/* Logs Container */}
230
- <div className="flex-1 overflow-y-auto bg-black font-mono text-sm">
231
- {filteredLogs.length === 0 ? (
232
- <div className="flex flex-col items-center justify-center h-full text-slate-600">
233
- <Terminal className="w-16 h-16 mb-4 opacity-20" />
234
- <p className="text-lg font-medium">No logs yet</p>
235
- <p className="text-sm">Logs will appear here as they are generated</p>
236
- </div>
237
- ) : (
238
- <div className="p-4 space-y-2">
239
- {filteredLogs.map((log, index) => (
240
- <div
241
- key={index}
242
- className={`p-3 rounded-lg border ${getLevelBg(log.level)} hover:border-opacity-50 transition-all`}
243
- >
244
- <div className="flex items-start gap-3">
245
- {/* Timestamp */}
246
- <span className="text-slate-500 text-xs whitespace-nowrap">
247
- {log.timestamp}
248
- </span>
249
-
250
- {/* Level Badge */}
251
- <span
252
- className={`px-2 py-0.5 rounded text-xs font-bold uppercase ${getLevelColor(log.level)}`}
253
- >
254
- {log.level}
255
- </span>
256
-
257
- {/* Message */}
258
- <div className="flex-1">
259
- <p className="text-white break-words">{log.message}</p>
260
-
261
- {/* Data (if present) */}
262
- {log.data && (
263
- <pre className="mt-2 p-3 bg-black/50 rounded border border-slate-800 overflow-x-auto">
264
- <code className="text-xs text-slate-300">
265
- {formatData(log.data)}
266
- </code>
267
- </pre>
268
- )}
269
- </div>
270
- </div>
271
- </div>
272
- ))}
273
- <div ref={logsEndRef} />
274
- </div>
275
- )}
276
- </div>
277
- </div>
278
- );
279
- }