@tleblancureta/proto 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.
Files changed (231) hide show
  1. package/core-web/src/ProtoApp.tsx +163 -0
  2. package/core-web/src/components/Shell.tsx +276 -0
  3. package/core-web/src/components/shell/EmptyState.tsx +33 -0
  4. package/core-web/src/components/shell/FocusView.tsx +55 -0
  5. package/core-web/src/components/shell/Toolbar.tsx +233 -0
  6. package/core-web/src/components/shell/persistence.ts +20 -0
  7. package/core-web/src/components/shell/types.ts +14 -0
  8. package/core-web/src/components/ui/avatar.tsx +18 -0
  9. package/core-web/src/components/ui/badge.tsx +28 -0
  10. package/core-web/src/components/ui/button.tsx +40 -0
  11. package/core-web/src/components/ui/card.tsx +32 -0
  12. package/core-web/src/components/ui/inline-edit.tsx +120 -0
  13. package/core-web/src/components/ui/input.tsx +18 -0
  14. package/core-web/src/components/ui/scroll-area.tsx +12 -0
  15. package/core-web/src/components/ui/separator.tsx +23 -0
  16. package/core-web/src/components/ui/shell-dialog.tsx +79 -0
  17. package/core-web/src/components/ui/skeleton.tsx +9 -0
  18. package/core-web/src/components/ui/textarea.tsx +17 -0
  19. package/core-web/src/components/widgets/agent/Generative.tsx +74 -0
  20. package/core-web/src/components/widgets/agent/Primitives.tsx +225 -0
  21. package/core-web/src/components/widgets/agent/actions.ts +52 -0
  22. package/core-web/src/hooks/useAuth.ts +80 -0
  23. package/core-web/src/hooks/useData.ts +44 -0
  24. package/core-web/src/hooks/useMountEffect.ts +10 -0
  25. package/core-web/src/hooks/useTheme.ts +37 -0
  26. package/core-web/src/index.ts +52 -0
  27. package/core-web/src/lib/api.ts +231 -0
  28. package/core-web/src/lib/config.ts +14 -0
  29. package/core-web/src/lib/define-widget.ts +71 -0
  30. package/core-web/src/lib/drag.ts +45 -0
  31. package/core-web/src/lib/supabase.ts +6 -0
  32. package/core-web/src/lib/utils.ts +6 -0
  33. package/core-web/src/lib/widgetCache.ts +29 -0
  34. package/core-web/src/vite-env.d.ts +1 -0
  35. package/dist/core-mcp/src/app.d.ts +40 -0
  36. package/dist/core-mcp/src/app.d.ts.map +1 -0
  37. package/dist/core-mcp/src/app.js +141 -0
  38. package/dist/core-mcp/src/app.js.map +1 -0
  39. package/dist/core-mcp/src/define-tool.d.ts +70 -0
  40. package/dist/core-mcp/src/define-tool.d.ts.map +1 -0
  41. package/dist/core-mcp/src/define-tool.js +38 -0
  42. package/dist/core-mcp/src/define-tool.js.map +1 -0
  43. package/dist/core-mcp/src/entity-tools.d.ts +27 -0
  44. package/dist/core-mcp/src/entity-tools.d.ts.map +1 -0
  45. package/dist/core-mcp/src/entity-tools.js +99 -0
  46. package/dist/core-mcp/src/entity-tools.js.map +1 -0
  47. package/dist/core-mcp/src/index.d.ts +36 -0
  48. package/dist/core-mcp/src/index.d.ts.map +1 -0
  49. package/dist/core-mcp/src/index.js +116 -0
  50. package/dist/core-mcp/src/index.js.map +1 -0
  51. package/dist/core-mcp/src/supabase.d.ts +7 -0
  52. package/dist/core-mcp/src/supabase.d.ts.map +1 -0
  53. package/dist/core-mcp/src/supabase.js +18 -0
  54. package/dist/core-mcp/src/supabase.js.map +1 -0
  55. package/dist/core-mcp/src/tools/_helpers.d.ts +44 -0
  56. package/dist/core-mcp/src/tools/_helpers.d.ts.map +1 -0
  57. package/dist/core-mcp/src/tools/_helpers.js +23 -0
  58. package/dist/core-mcp/src/tools/_helpers.js.map +1 -0
  59. package/dist/core-mcp/src/tools/ui.d.ts +9 -0
  60. package/dist/core-mcp/src/tools/ui.d.ts.map +1 -0
  61. package/dist/core-mcp/src/tools/ui.js +100 -0
  62. package/dist/core-mcp/src/tools/ui.js.map +1 -0
  63. package/dist/core-mcp/src/workflow-tools.d.ts +41 -0
  64. package/dist/core-mcp/src/workflow-tools.d.ts.map +1 -0
  65. package/dist/core-mcp/src/workflow-tools.js +382 -0
  66. package/dist/core-mcp/src/workflow-tools.js.map +1 -0
  67. package/dist/core-shared/src/define-entity.d.ts +73 -0
  68. package/dist/core-shared/src/define-entity.d.ts.map +1 -0
  69. package/dist/core-shared/src/define-entity.js +47 -0
  70. package/dist/core-shared/src/define-entity.js.map +1 -0
  71. package/dist/core-shared/src/define-workflow.d.ts +111 -0
  72. package/dist/core-shared/src/define-workflow.d.ts.map +1 -0
  73. package/dist/core-shared/src/define-workflow.js +92 -0
  74. package/dist/core-shared/src/define-workflow.js.map +1 -0
  75. package/dist/core-shared/src/index.d.ts +5 -0
  76. package/dist/core-shared/src/index.d.ts.map +1 -0
  77. package/dist/core-shared/src/index.js +7 -0
  78. package/dist/core-shared/src/index.js.map +1 -0
  79. package/dist/core-shared/src/scheduling.d.ts +69 -0
  80. package/dist/core-shared/src/scheduling.d.ts.map +1 -0
  81. package/dist/core-shared/src/scheduling.js +39 -0
  82. package/dist/core-shared/src/scheduling.js.map +1 -0
  83. package/dist/core-shared/src/schemas.d.ts +51 -0
  84. package/dist/core-shared/src/schemas.d.ts.map +1 -0
  85. package/dist/core-shared/src/schemas.js +18 -0
  86. package/dist/core-shared/src/schemas.js.map +1 -0
  87. package/dist/core-web/src/ProtoApp.d.ts +19 -0
  88. package/dist/core-web/src/ProtoApp.d.ts.map +1 -0
  89. package/dist/core-web/src/ProtoApp.js +92 -0
  90. package/dist/core-web/src/ProtoApp.js.map +1 -0
  91. package/dist/core-web/src/components/Shell.d.ts +46 -0
  92. package/dist/core-web/src/components/Shell.d.ts.map +1 -0
  93. package/dist/core-web/src/components/Shell.js +104 -0
  94. package/dist/core-web/src/components/Shell.js.map +1 -0
  95. package/dist/core-web/src/components/shell/EmptyState.d.ts +13 -0
  96. package/dist/core-web/src/components/shell/EmptyState.d.ts.map +1 -0
  97. package/dist/core-web/src/components/shell/EmptyState.js +7 -0
  98. package/dist/core-web/src/components/shell/EmptyState.js.map +1 -0
  99. package/dist/core-web/src/components/shell/FocusView.d.ts +16 -0
  100. package/dist/core-web/src/components/shell/FocusView.d.ts.map +1 -0
  101. package/dist/core-web/src/components/shell/FocusView.js +12 -0
  102. package/dist/core-web/src/components/shell/FocusView.js.map +1 -0
  103. package/dist/core-web/src/components/shell/Toolbar.d.ts +35 -0
  104. package/dist/core-web/src/components/shell/Toolbar.d.ts.map +1 -0
  105. package/dist/core-web/src/components/shell/Toolbar.js +42 -0
  106. package/dist/core-web/src/components/shell/Toolbar.js.map +1 -0
  107. package/dist/core-web/src/components/shell/persistence.d.ts +8 -0
  108. package/dist/core-web/src/components/shell/persistence.d.ts.map +1 -0
  109. package/dist/core-web/src/components/shell/persistence.js +20 -0
  110. package/dist/core-web/src/components/shell/persistence.js.map +1 -0
  111. package/dist/core-web/src/components/shell/types.d.ts +13 -0
  112. package/dist/core-web/src/components/shell/types.d.ts.map +1 -0
  113. package/dist/core-web/src/components/shell/types.js +2 -0
  114. package/dist/core-web/src/components/shell/types.js.map +1 -0
  115. package/dist/core-web/src/components/ui/avatar.d.ts +5 -0
  116. package/dist/core-web/src/components/ui/avatar.d.ts.map +1 -0
  117. package/dist/core-web/src/components/ui/avatar.js +9 -0
  118. package/dist/core-web/src/components/ui/avatar.js.map +1 -0
  119. package/dist/core-web/src/components/ui/badge.d.ts +13 -0
  120. package/dist/core-web/src/components/ui/badge.d.ts.map +1 -0
  121. package/dist/core-web/src/components/ui/badge.js +13 -0
  122. package/dist/core-web/src/components/ui/badge.js.map +1 -0
  123. package/dist/core-web/src/components/ui/button.d.ts +22 -0
  124. package/dist/core-web/src/components/ui/button.d.ts.map +1 -0
  125. package/dist/core-web/src/components/ui/button.js +21 -0
  126. package/dist/core-web/src/components/ui/button.js.map +1 -0
  127. package/dist/core-web/src/components/ui/card.d.ts +7 -0
  128. package/dist/core-web/src/components/ui/card.d.ts.map +1 -0
  129. package/dist/core-web/src/components/ui/card.js +13 -0
  130. package/dist/core-web/src/components/ui/card.js.map +1 -0
  131. package/dist/core-web/src/components/ui/inline-edit.d.ts +20 -0
  132. package/dist/core-web/src/components/ui/inline-edit.d.ts.map +1 -0
  133. package/dist/core-web/src/components/ui/inline-edit.js +63 -0
  134. package/dist/core-web/src/components/ui/inline-edit.js.map +1 -0
  135. package/dist/core-web/src/components/ui/input.d.ts +4 -0
  136. package/dist/core-web/src/components/ui/input.d.ts.map +1 -0
  137. package/dist/core-web/src/components/ui/input.js +7 -0
  138. package/dist/core-web/src/components/ui/input.js.map +1 -0
  139. package/dist/core-web/src/components/ui/scroll-area.d.ts +4 -0
  140. package/dist/core-web/src/components/ui/scroll-area.d.ts.map +1 -0
  141. package/dist/core-web/src/components/ui/scroll-area.js +7 -0
  142. package/dist/core-web/src/components/ui/scroll-area.js.map +1 -0
  143. package/dist/core-web/src/components/ui/separator.d.ts +7 -0
  144. package/dist/core-web/src/components/ui/separator.d.ts.map +1 -0
  145. package/dist/core-web/src/components/ui/separator.js +7 -0
  146. package/dist/core-web/src/components/ui/separator.js.map +1 -0
  147. package/dist/core-web/src/components/ui/shell-dialog.d.ts +16 -0
  148. package/dist/core-web/src/components/ui/shell-dialog.d.ts.map +1 -0
  149. package/dist/core-web/src/components/ui/shell-dialog.js +36 -0
  150. package/dist/core-web/src/components/ui/shell-dialog.js.map +1 -0
  151. package/dist/core-web/src/components/ui/skeleton.d.ts +3 -0
  152. package/dist/core-web/src/components/ui/skeleton.d.ts.map +1 -0
  153. package/dist/core-web/src/components/ui/skeleton.js +7 -0
  154. package/dist/core-web/src/components/ui/skeleton.js.map +1 -0
  155. package/dist/core-web/src/components/ui/textarea.d.ts +4 -0
  156. package/dist/core-web/src/components/ui/textarea.d.ts.map +1 -0
  157. package/dist/core-web/src/components/ui/textarea.js +7 -0
  158. package/dist/core-web/src/components/ui/textarea.js.map +1 -0
  159. package/dist/core-web/src/components/widgets/agent/Generative.d.ts +13 -0
  160. package/dist/core-web/src/components/widgets/agent/Generative.d.ts.map +1 -0
  161. package/dist/core-web/src/components/widgets/agent/Generative.js +42 -0
  162. package/dist/core-web/src/components/widgets/agent/Generative.js.map +1 -0
  163. package/dist/core-web/src/components/widgets/agent/Primitives.d.ts +79 -0
  164. package/dist/core-web/src/components/widgets/agent/Primitives.d.ts.map +1 -0
  165. package/dist/core-web/src/components/widgets/agent/Primitives.js +116 -0
  166. package/dist/core-web/src/components/widgets/agent/Primitives.js.map +1 -0
  167. package/dist/core-web/src/components/widgets/agent/actions.d.ts +3 -0
  168. package/dist/core-web/src/components/widgets/agent/actions.d.ts.map +1 -0
  169. package/dist/core-web/src/components/widgets/agent/actions.js +33 -0
  170. package/dist/core-web/src/components/widgets/agent/actions.js.map +1 -0
  171. package/dist/core-web/src/hooks/useAuth.d.ts +25 -0
  172. package/dist/core-web/src/hooks/useAuth.d.ts.map +1 -0
  173. package/dist/core-web/src/hooks/useAuth.js +53 -0
  174. package/dist/core-web/src/hooks/useAuth.js.map +1 -0
  175. package/dist/core-web/src/hooks/useData.d.ts +10 -0
  176. package/dist/core-web/src/hooks/useData.d.ts.map +1 -0
  177. package/dist/core-web/src/hooks/useData.js +37 -0
  178. package/dist/core-web/src/hooks/useData.js.map +1 -0
  179. package/dist/core-web/src/hooks/useMountEffect.d.ts +6 -0
  180. package/dist/core-web/src/hooks/useMountEffect.d.ts.map +1 -0
  181. package/dist/core-web/src/hooks/useMountEffect.js +10 -0
  182. package/dist/core-web/src/hooks/useMountEffect.js.map +1 -0
  183. package/dist/core-web/src/hooks/useTheme.d.ts +6 -0
  184. package/dist/core-web/src/hooks/useTheme.d.ts.map +1 -0
  185. package/dist/core-web/src/hooks/useTheme.js +31 -0
  186. package/dist/core-web/src/hooks/useTheme.js.map +1 -0
  187. package/dist/core-web/src/index.d.ts +33 -0
  188. package/dist/core-web/src/index.d.ts.map +1 -0
  189. package/dist/core-web/src/index.js +38 -0
  190. package/dist/core-web/src/index.js.map +1 -0
  191. package/dist/core-web/src/lib/api.d.ts +60 -0
  192. package/dist/core-web/src/lib/api.d.ts.map +1 -0
  193. package/dist/core-web/src/lib/api.js +204 -0
  194. package/dist/core-web/src/lib/api.js.map +1 -0
  195. package/dist/core-web/src/lib/config.d.ts +10 -0
  196. package/dist/core-web/src/lib/config.d.ts.map +1 -0
  197. package/dist/core-web/src/lib/config.js +10 -0
  198. package/dist/core-web/src/lib/config.js.map +1 -0
  199. package/dist/core-web/src/lib/define-widget.d.ts +52 -0
  200. package/dist/core-web/src/lib/define-widget.d.ts.map +1 -0
  201. package/dist/core-web/src/lib/define-widget.js +14 -0
  202. package/dist/core-web/src/lib/define-widget.js.map +1 -0
  203. package/dist/core-web/src/lib/drag.d.ts +20 -0
  204. package/dist/core-web/src/lib/drag.d.ts.map +1 -0
  205. package/dist/core-web/src/lib/drag.js +33 -0
  206. package/dist/core-web/src/lib/drag.js.map +1 -0
  207. package/dist/core-web/src/lib/supabase.d.ts +2 -0
  208. package/dist/core-web/src/lib/supabase.d.ts.map +1 -0
  209. package/dist/core-web/src/lib/supabase.js +5 -0
  210. package/dist/core-web/src/lib/supabase.js.map +1 -0
  211. package/dist/core-web/src/lib/utils.d.ts +3 -0
  212. package/dist/core-web/src/lib/utils.d.ts.map +1 -0
  213. package/dist/core-web/src/lib/utils.js +6 -0
  214. package/dist/core-web/src/lib/utils.js.map +1 -0
  215. package/dist/core-web/src/lib/widgetCache.d.ts +18 -0
  216. package/dist/core-web/src/lib/widgetCache.d.ts.map +1 -0
  217. package/dist/core-web/src/lib/widgetCache.js +28 -0
  218. package/dist/core-web/src/lib/widgetCache.js.map +1 -0
  219. package/dist/mcp.d.ts +2 -0
  220. package/dist/mcp.d.ts.map +1 -0
  221. package/dist/mcp.js +2 -0
  222. package/dist/mcp.js.map +1 -0
  223. package/dist/shared.d.ts +2 -0
  224. package/dist/shared.d.ts.map +1 -0
  225. package/dist/shared.js +2 -0
  226. package/dist/shared.js.map +1 -0
  227. package/dist/web.d.ts +2 -0
  228. package/dist/web.d.ts.map +1 -0
  229. package/dist/web.js +2 -0
  230. package/dist/web.js.map +1 -0
  231. package/package.json +62 -0
@@ -0,0 +1,231 @@
1
+ import { GATEWAY_URL, INTERNAL_SECRET as SECRET, WS_URL } from './config'
2
+
3
+ export interface StreamEvent {
4
+ type: 'init' | 'text' | 'tool_use' | 'tool_result' | 'result' | 'error' | 'thinking' | 'auth' | 'pong' | 'shell_refresh'
5
+ text?: string
6
+ tool?: string
7
+ args?: Record<string, unknown>
8
+ content?: string
9
+ message?: string
10
+ session_id?: string
11
+ duration_ms?: number
12
+ cost_usd?: number
13
+ status?: string
14
+ }
15
+
16
+ type EventHandler = (event: StreamEvent) => void
17
+
18
+ class ProtoSocket {
19
+ private ws: WebSocket | null = null
20
+ private authenticated = false
21
+ private messageHandler: EventHandler | null = null
22
+ private shellRefreshHandler: (() => void) | null = null
23
+ private connectPromise: Promise<void> | null = null
24
+ private reconnectTimer: ReturnType<typeof setTimeout> | null = null
25
+ private pingTimer: ReturnType<typeof setInterval> | null = null
26
+ private reconnectDelay = 3000
27
+ private static readonly MAX_RECONNECT_DELAY = 60000
28
+
29
+ connect(): Promise<void> {
30
+ if (this.ws?.readyState === WebSocket.OPEN && this.authenticated) {
31
+ return Promise.resolve()
32
+ }
33
+
34
+ if (this.connectPromise) return this.connectPromise
35
+
36
+ this.connectPromise = new Promise((resolve, reject) => {
37
+ this.ws = new WebSocket(WS_URL)
38
+
39
+ this.ws.onopen = () => {
40
+ // Authenticate
41
+ this.ws!.send(JSON.stringify({ type: 'auth', secret: SECRET }))
42
+ }
43
+
44
+ this.ws.onmessage = (e) => {
45
+ try {
46
+ const event: StreamEvent = JSON.parse(e.data)
47
+
48
+ if (event.type === 'auth' && event.status === 'ok') {
49
+ this.authenticated = true
50
+ this.connectPromise = null
51
+ this.reconnectDelay = 3000 // reset on successful auth
52
+ // Start keepalive ping every 25s to prevent idle disconnects
53
+ if (this.pingTimer) clearInterval(this.pingTimer)
54
+ this.pingTimer = setInterval(() => {
55
+ if (this.ws?.readyState === WebSocket.OPEN) {
56
+ try { this.ws.send(JSON.stringify({ type: 'ping' })) } catch {}
57
+ }
58
+ }, 25000)
59
+ resolve()
60
+ return
61
+ }
62
+
63
+ if (event.type === 'shell_refresh') {
64
+ this.shellRefreshHandler?.()
65
+ return
66
+ }
67
+
68
+ if (event.type === 'pong') return
69
+
70
+ this.messageHandler?.(event)
71
+ } catch {}
72
+ }
73
+
74
+ this.ws.onclose = () => {
75
+ this.authenticated = false
76
+ this.connectPromise = null
77
+ if (this.pingTimer) { clearInterval(this.pingTimer); this.pingTimer = null }
78
+ // Synthesize an error event ONLY if a stream is in flight (handler set)
79
+ // so the chat turn can reset. Fire only once then clear.
80
+ if (this.messageHandler) {
81
+ try { this.messageHandler({ type: 'error', message: 'Conexion perdida. Reintenta.' }) } catch {}
82
+ this.messageHandler = null
83
+ }
84
+ // Auto-reconnect with exponential backoff (3s → 6s → 12s → ... → 60s max)
85
+ if (!this.reconnectTimer) {
86
+ this.reconnectTimer = setTimeout(() => {
87
+ this.reconnectTimer = null
88
+ this.connect().catch(() => {})
89
+ }, this.reconnectDelay)
90
+ this.reconnectDelay = Math.min(this.reconnectDelay * 2, ProtoSocket.MAX_RECONNECT_DELAY)
91
+ }
92
+ }
93
+
94
+ this.ws.onerror = () => {
95
+ this.connectPromise = null
96
+ try { this.messageHandler?.({ type: 'error', message: 'Error de conexion WebSocket' }) } catch {}
97
+ reject(new Error('WebSocket connection failed'))
98
+ }
99
+
100
+ // Timeout
101
+ setTimeout(() => {
102
+ if (!this.authenticated) {
103
+ this.connectPromise = null
104
+ reject(new Error('WebSocket auth timeout'))
105
+ }
106
+ }, 10000)
107
+ })
108
+
109
+ return this.connectPromise
110
+ }
111
+
112
+ onMessage(handler: EventHandler) {
113
+ this.messageHandler = handler
114
+ }
115
+
116
+ onShellRefresh(handler: () => void) {
117
+ this.shellRefreshHandler = handler
118
+ }
119
+
120
+ async send(data: any) {
121
+ await this.connect()
122
+ this.ws?.send(JSON.stringify(data))
123
+ }
124
+
125
+ isConnected(): boolean {
126
+ return this.ws?.readyState === WebSocket.OPEN && this.authenticated
127
+ }
128
+
129
+ disconnect() {
130
+ if (this.reconnectTimer) clearTimeout(this.reconnectTimer)
131
+ this.ws?.close()
132
+ this.ws = null
133
+ this.authenticated = false
134
+ }
135
+ }
136
+
137
+ // Singleton
138
+ export const protoSocket = new ProtoSocket()
139
+
140
+ /** @deprecated Use protoSocket instead. */
141
+ export const hermesSocket = protoSocket
142
+
143
+ // Chat request params
144
+ interface ChatParams {
145
+ company_id: string
146
+ user_id: string
147
+ message: string
148
+ session_key?: string
149
+ enabled_skills?: string[]
150
+ company_context?: string
151
+ }
152
+
153
+ /**
154
+ * Send a chat message via WebSocket. Events come through protoSocket.onMessage().
155
+ */
156
+ export async function sendChatWs(params: ChatParams) {
157
+ await protoSocket.send({ type: 'chat', channel: 'web', ...params })
158
+ }
159
+
160
+ /**
161
+ * Reset the Claude CLI session for a company so the next message starts
162
+ * a fresh conversation (no --resume history).
163
+ */
164
+ export async function resetSession(companyId: string, sessionKey = 'web') {
165
+ try {
166
+ await fetch(`${GATEWAY_URL}/reset`, {
167
+ method: 'POST',
168
+ headers: { 'Content-Type': 'application/json', 'X-Internal-Secret': SECRET },
169
+ body: JSON.stringify({ company_id: companyId, session_key: sessionKey }),
170
+ })
171
+ } catch {}
172
+ }
173
+
174
+ /**
175
+ * Legacy: Send chat via REST (blocking).
176
+ */
177
+ export async function sendChat(params: ChatParams) {
178
+ const res = await fetch(`${GATEWAY_URL}/chat`, {
179
+ method: 'POST',
180
+ headers: { 'Content-Type': 'application/json', 'X-Internal-Secret': SECRET },
181
+ body: JSON.stringify({ channel: 'web', ...params }),
182
+ })
183
+ if (!res.ok) throw new Error(`Error ${res.status}`)
184
+ return res.json()
185
+ }
186
+
187
+ /**
188
+ * Legacy: SSE stream (kept for fallback).
189
+ */
190
+ export function streamChat(
191
+ params: ChatParams,
192
+ onEvent: (event: StreamEvent) => void,
193
+ ): AbortController {
194
+ const controller = new AbortController()
195
+
196
+ fetch(`${GATEWAY_URL}/chat/stream`, {
197
+ method: 'POST',
198
+ headers: { 'Content-Type': 'application/json', 'X-Internal-Secret': SECRET },
199
+ body: JSON.stringify({ channel: 'web', ...params }),
200
+ signal: controller.signal,
201
+ }).then(async (res) => {
202
+ if (!res.ok) { onEvent({ type: 'error', message: `Error ${res.status}` }); return }
203
+ const reader = res.body?.getReader()
204
+ if (!reader) return
205
+ const decoder = new TextDecoder()
206
+ let buffer = ''
207
+ let gotResult = false
208
+
209
+ while (true) {
210
+ const { done, value } = await reader.read()
211
+ if (done) break
212
+ buffer += decoder.decode(value, { stream: true })
213
+ const lines = buffer.split('\n')
214
+ buffer = lines.pop() || ''
215
+ for (const line of lines) {
216
+ if (line.startsWith('data: ')) {
217
+ try {
218
+ const event = JSON.parse(line.slice(6))
219
+ if (event.type === 'result' || event.type === 'error') gotResult = true
220
+ onEvent(event)
221
+ } catch {}
222
+ }
223
+ }
224
+ }
225
+ if (!gotResult) onEvent({ type: 'result', text: '' })
226
+ }).catch((err) => {
227
+ if (err.name !== 'AbortError') onEvent({ type: 'error', message: err.message })
228
+ })
229
+
230
+ return controller
231
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Centralized frontend config. Every module that needs the gateway URL or
3
+ * the internal secret should import from here — do NOT read
4
+ * `import.meta.env.VITE_*` directly, so the default values stay in sync.
5
+ */
6
+
7
+ export const GATEWAY_URL: string =
8
+ (import.meta.env.VITE_GATEWAY_URL as string) || 'http://localhost:8092'
9
+
10
+ export const INTERNAL_SECRET: string =
11
+ (import.meta.env.VITE_INTERNAL_SECRET as string) || ''
12
+
13
+ /** WebSocket endpoint, derived from GATEWAY_URL. */
14
+ export const WS_URL: string = GATEWAY_URL.replace(/^http/, 'ws') + '/ws'
@@ -0,0 +1,71 @@
1
+ /**
2
+ * defineWidget — declarative shell widget definition.
3
+ *
4
+ * App code declares widgets as data instead of hardcoding a switch in Shell.
5
+ * Each widget provides a `render(instance, ctx)` function that returns the
6
+ * React node, pulling whatever it needs from the shared ShellContext.
7
+ *
8
+ * The `ShellContext` interface below contains the framework-level fields every
9
+ * widget receives. Apps extend it via TypeScript module augmentation to add
10
+ * their own fields (cart state, app-specific callbacks, etc).
11
+ *
12
+ * Example augmentation in an app:
13
+ *
14
+ * declare module 'proto/web' {
15
+ * interface ShellContext {
16
+ * cartItems: CartItem[]
17
+ * addToCart: (item: CartItem) => void
18
+ * }
19
+ * }
20
+ */
21
+ import type { ReactNode } from 'react'
22
+ import type { ActiveEntity, WidgetInstance } from '../components/shell/types'
23
+
24
+ export interface ShellContext {
25
+ companyId: string
26
+ refreshKey: number
27
+ activeEntity: ActiveEntity | null
28
+
29
+ onSendToChat: (message: string) => void
30
+ onActivateEntity?: (e: ActiveEntity) => void
31
+ onDeactivateEntity?: () => void
32
+ onCloseTab?: (e: ActiveEntity) => void
33
+
34
+ /** Force widgets to re-fetch without a full shell reload. */
35
+ triggerLocalRefresh: () => void
36
+ }
37
+
38
+ export type WidgetCategory = 'general' | 'cockpit'
39
+
40
+ export interface WidgetSize {
41
+ w: number
42
+ h: number
43
+ minW: number
44
+ minH: number
45
+ }
46
+
47
+ export interface WidgetDefinition {
48
+ type: string
49
+ title: string
50
+ icon?: string
51
+ category: WidgetCategory
52
+ defaultSize?: WidgetSize
53
+ render: (instance: WidgetInstance, ctx: ShellContext) => ReactNode
54
+ }
55
+
56
+ export function defineWidget(def: WidgetDefinition): WidgetDefinition {
57
+ return def
58
+ }
59
+
60
+ export type WidgetRegistry = Map<string, WidgetDefinition>
61
+
62
+ export function buildWidgetRegistry(defs: readonly WidgetDefinition[]): WidgetRegistry {
63
+ const map: WidgetRegistry = new Map()
64
+ for (const def of defs) {
65
+ if (map.has(def.type)) {
66
+ console.warn(`[defineWidget] duplicate widget type: ${def.type}`)
67
+ }
68
+ map.set(def.type, def)
69
+ }
70
+ return map
71
+ }
@@ -0,0 +1,45 @@
1
+ export interface DragContext {
2
+ type: string
3
+ id: string
4
+ label: string
5
+ meta?: string
6
+ agentContext: {
7
+ entity: string
8
+ id: string
9
+ summary: Record<string, any>
10
+ }
11
+ }
12
+
13
+ export function setDragData(e: React.DragEvent, ctx: DragContext) {
14
+ e.dataTransfer.setData('application/proto', JSON.stringify(ctx))
15
+ e.dataTransfer.effectAllowed = 'copy'
16
+ }
17
+
18
+ export function getDragData(e: React.DragEvent): DragContext | null {
19
+ try {
20
+ const raw = e.dataTransfer.getData('application/proto')
21
+ return raw ? JSON.parse(raw) : null
22
+ } catch { return null }
23
+ }
24
+
25
+ export function hasDragData(e: React.DragEvent): boolean {
26
+ return e.dataTransfer.types.includes('application/proto')
27
+ }
28
+
29
+ /**
30
+ * Build structured context for the agent.
31
+ * Injected as context prefix, not as user message text.
32
+ */
33
+ export function buildAgentPrompt(ctx: DragContext): string {
34
+ const { entity, id, summary } = ctx.agentContext
35
+ const lines = Object.entries(summary)
36
+ .filter(([_, v]) => v != null && v !== '')
37
+ .map(([k, v]) => ` ${k}: ${typeof v === 'object' ? JSON.stringify(v) : v}`)
38
+
39
+ return [
40
+ `[CONTEXTO: El usuario selecciono un ${entity}]`,
41
+ `ID: ${id}`,
42
+ ...lines,
43
+ `[Consulta datos actualizados con los tools MCP si necesitas mas detalle. No repitas info que ya tienes.]`,
44
+ ].join('\n')
45
+ }
@@ -0,0 +1,6 @@
1
+ import { createClient } from '@supabase/supabase-js'
2
+
3
+ const url = import.meta.env.VITE_SUPABASE_URL as string
4
+ const anonKey = import.meta.env.VITE_SUPABASE_ANON_KEY as string
5
+
6
+ export const supabase = createClient(url, anonKey)
@@ -0,0 +1,6 @@
1
+ import { clsx, type ClassValue } from "clsx"
2
+ import { twMerge } from "tailwind-merge"
3
+
4
+ export function cn(...inputs: ClassValue[]) {
5
+ return twMerge(clsx(inputs))
6
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Tiny in-memory cache for cockpit widget data.
3
+ *
4
+ * Keyed by `${widgetName}:${entityId}`. Lives for the page session.
5
+ *
6
+ * Usage pattern in widgets:
7
+ * const [data, setData] = useState(() => cacheGet(key))
8
+ * useEffect(() => {
9
+ * fetch().then(d => { cacheSet(key, d); setData(d) })
10
+ * }, [id, refreshKey])
11
+ *
12
+ * If cached, the widget renders instantly with stale data, then silently
13
+ * swaps to fresh data when the fetch resolves. No skeleton on re-visits.
14
+ */
15
+
16
+ const store = new Map<string, unknown>()
17
+
18
+ export function cacheGet<T>(key: string): T | undefined {
19
+ return store.get(key) as T | undefined
20
+ }
21
+
22
+ export function cacheSet<T>(key: string, value: T): void {
23
+ store.set(key, value)
24
+ }
25
+
26
+ export function cacheClear(key?: string): void {
27
+ if (key) store.delete(key)
28
+ else store.clear()
29
+ }
@@ -0,0 +1 @@
1
+ /// <reference types="vite/client" />
@@ -0,0 +1,40 @@
1
+ import { type ToolDefinition } from './define-tool.js';
2
+ import type { EntityDefinition } from '../../core-shared/src/index.js';
3
+ import type { WorkflowDefinition } from '../../core-shared/src/index.js';
4
+ export interface ProtoMcpOptions {
5
+ /** App name (used in MCP server metadata). */
6
+ name: string;
7
+ version?: string;
8
+ /**
9
+ * Directory containing tool files. Each .ts/.js file should export
10
+ * default an array of ToolDefinition objects.
11
+ * Defaults to ./tools (relative to the calling file).
12
+ */
13
+ toolsDir?: string;
14
+ /**
15
+ * Path to entities barrel (e.g. ./entities/index.ts).
16
+ * Should export `ENTITIES` as an array of EntityDefinition.
17
+ * If omitted, auto-detected from ./entities/index.
18
+ */
19
+ entitiesPath?: string;
20
+ /**
21
+ * Path to workflow definition file, or an already-imported WorkflowDefinition.
22
+ * If omitted, auto-detected from ./workflows/*.
23
+ */
24
+ workflow?: string | WorkflowDefinition;
25
+ /** Extra tools to register alongside auto-discovered ones. */
26
+ extraTools?: ToolDefinition[];
27
+ /** Extra entities to register alongside auto-discovered ones. */
28
+ extraEntities?: EntityDefinition[];
29
+ }
30
+ export declare function createProtoMcp(opts: ProtoMcpOptions): Promise<{
31
+ /** Run as stdio subprocess (for Claude Code CLI). */
32
+ stdio(): Promise<void>;
33
+ /** Run as HTTP server (for Docker / standalone). */
34
+ http(httpOpts?: {
35
+ port?: number;
36
+ }): Promise<void>;
37
+ /** Get tool count (for smoke tests). */
38
+ readonly toolCount: number;
39
+ }>;
40
+ //# sourceMappingURL=app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../../../core-mcp/src/app.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAiB,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAKrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA;AACtE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AAExE,MAAM,WAAW,eAAe;IAC9B,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAEhB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IAEjB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAAA;IAEtC,8DAA8D;IAC9D,UAAU,CAAC,EAAE,cAAc,EAAE,CAAA;IAE7B,iEAAiE;IACjE,aAAa,CAAC,EAAE,gBAAgB,EAAE,CAAA;CACnC;AAwED,wBAAsB,cAAc,CAAC,IAAI,EAAE,eAAe;IAyCtD,qDAAqD;;IAMrD,oDAAoD;oBAC9B;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE;IASvC,wCAAwC;;GAM3C"}
@@ -0,0 +1,141 @@
1
+ /**
2
+ * createProtoMcp — single-call factory that builds a fully-wired MCP app.
3
+ *
4
+ * Auto-discovers tools, entities, and workflows from the app directory.
5
+ * The developer only writes tool files (export default [...]) and optionally
6
+ * entities/index + workflows — everything else is handled by the framework.
7
+ *
8
+ * Usage:
9
+ *
10
+ * // app/mcp.ts (stdio)
11
+ * import { createProtoMcp } from 'proto/mcp'
12
+ * const app = await createProtoMcp({ name: 'my-app' })
13
+ * await app.stdio()
14
+ *
15
+ * // app/mcp-http.ts (HTTP)
16
+ * import { createProtoMcp } from 'proto/mcp'
17
+ * const app = await createProtoMcp({ name: 'my-app' })
18
+ * await app.http({ port: 8093 })
19
+ */
20
+ import { readdirSync, existsSync } from 'node:fs';
21
+ import { resolve, dirname, join } from 'node:path';
22
+ import { pathToFileURL } from 'node:url';
23
+ import { createMcpServer, runStdio, runHttp } from './index.js';
24
+ import { registerTools } from './define-tool.js';
25
+ import { registerUiTools } from './tools/ui.js';
26
+ import { registerEntityTools } from './entity-tools.js';
27
+ import { registerWorkflowTools } from './workflow-tools.js';
28
+ async function loadToolsFromDir(dir) {
29
+ if (!existsSync(dir))
30
+ return [];
31
+ const files = readdirSync(dir).filter(f => (f.endsWith('.ts') || f.endsWith('.js')) && f !== 'index.ts' && f !== 'index.js');
32
+ const allTools = [];
33
+ for (const file of files) {
34
+ const fullPath = join(dir, file);
35
+ const mod = await import(pathToFileURL(fullPath).href);
36
+ const tools = mod.default;
37
+ if (Array.isArray(tools)) {
38
+ allTools.push(...tools);
39
+ }
40
+ }
41
+ return allTools;
42
+ }
43
+ async function loadEntities(dirOrBarrel) {
44
+ // Try barrel file first (index.ts/index.js)
45
+ for (const ext of ['.ts', '.js']) {
46
+ const p = dirOrBarrel + ext;
47
+ if (existsSync(p)) {
48
+ const mod = await import(pathToFileURL(p).href);
49
+ return mod.ENTITIES || mod.default || [];
50
+ }
51
+ }
52
+ // Auto-discover individual entity files from the directory
53
+ const dir = dirname(dirOrBarrel);
54
+ if (!existsSync(dir))
55
+ return [];
56
+ const files = readdirSync(dir).filter(f => (f.endsWith('.ts') || f.endsWith('.js')) && f !== 'index.ts' && f !== 'index.js');
57
+ const entities = [];
58
+ for (const file of files) {
59
+ const mod = await import(pathToFileURL(join(dir, file)).href);
60
+ if (mod.default && typeof mod.default === 'object' && 'name' in mod.default) {
61
+ entities.push(mod.default);
62
+ }
63
+ }
64
+ return entities;
65
+ }
66
+ async function loadWorkflow(basePath) {
67
+ if (!existsSync(basePath))
68
+ return null;
69
+ const files = readdirSync(basePath).filter(f => (f.endsWith('.ts') || f.endsWith('.js')) && !f.startsWith('_'));
70
+ if (files.length === 0)
71
+ return null;
72
+ // Load the first workflow file found
73
+ const mod = await import(pathToFileURL(join(basePath, files[0])).href);
74
+ return mod.default || null;
75
+ }
76
+ function resolveAppDir(callerUrl) {
77
+ if (callerUrl) {
78
+ return dirname(callerUrl.replace('file://', ''));
79
+ }
80
+ return process.cwd();
81
+ }
82
+ export async function createProtoMcp(opts) {
83
+ // Resolve paths relative to cwd (app root)
84
+ const appDir = process.cwd();
85
+ const toolsDir = opts.toolsDir
86
+ ? resolve(appDir, opts.toolsDir)
87
+ : resolve(appDir, 'app', 'tools');
88
+ const entitiesPath = opts.entitiesPath
89
+ ? resolve(appDir, opts.entitiesPath)
90
+ : resolve(appDir, 'app', 'entities', 'index');
91
+ const workflowsDir = resolve(appDir, 'app', 'workflows');
92
+ // Load everything
93
+ const tools = await loadToolsFromDir(toolsDir);
94
+ const entities = await loadEntities(entitiesPath);
95
+ const extraTools = opts.extraTools || [];
96
+ const extraEntities = opts.extraEntities || [];
97
+ const allTools = [...tools, ...extraTools];
98
+ const allEntities = [...entities, ...extraEntities];
99
+ let workflow = null;
100
+ if (opts.workflow) {
101
+ workflow = typeof opts.workflow === 'string'
102
+ ? await loadWorkflow(resolve(appDir, opts.workflow)).then(w => w)
103
+ : opts.workflow;
104
+ }
105
+ else {
106
+ workflow = await loadWorkflow(workflowsDir);
107
+ }
108
+ function buildServer() {
109
+ const server = createMcpServer({ name: opts.name, version: opts.version });
110
+ registerUiTools(server);
111
+ if (allTools.length > 0)
112
+ registerTools(server, allTools);
113
+ if (allEntities.length > 0)
114
+ registerEntityTools(server, allEntities);
115
+ if (workflow)
116
+ registerWorkflowTools(server, workflow);
117
+ return server;
118
+ }
119
+ return {
120
+ /** Run as stdio subprocess (for Claude Code CLI). */
121
+ async stdio() {
122
+ const server = buildServer();
123
+ await runStdio(server);
124
+ },
125
+ /** Run as HTTP server (for Docker / standalone). */
126
+ async http(httpOpts) {
127
+ const port = httpOpts?.port || parseInt(process.env.MCP_PORT || '8093', 10);
128
+ await runHttp({
129
+ port,
130
+ displayName: opts.name,
131
+ buildServer,
132
+ });
133
+ },
134
+ /** Get tool count (for smoke tests). */
135
+ get toolCount() {
136
+ const server = buildServer();
137
+ return Object.keys(server._registeredTools).length;
138
+ },
139
+ };
140
+ }
141
+ //# sourceMappingURL=app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../../core-mcp/src/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * defineTool — declarative MCP tool definition.
3
+ *
4
+ * App code declares tools as data instead of calling server.tool() directly.
5
+ * The framework later registers them via registerTools(), giving us a
6
+ * single place to wrap handlers with context injection, error normalization,
7
+ * logging, metrics, etc.
8
+ *
9
+ * Example (app-space):
10
+ *
11
+ * import { defineTool } from 'proto/mcp'
12
+ * import { z } from 'zod'
13
+ *
14
+ * export default [
15
+ * defineTool({
16
+ * name: 'create_thing',
17
+ * description: 'Creates a thing.',
18
+ * schema: { name: z.string() },
19
+ * handler: async (args) => {
20
+ * // ... do work ...
21
+ * return { content: [{ type: 'text', text: 'ok' }] }
22
+ * },
23
+ * }),
24
+ * ]
25
+ */
26
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
27
+ import type { z } from 'zod';
28
+ /**
29
+ * Minimal MCP tool response shape. Tools that need structured agent responses
30
+ * should use the `agent()` / `agentErr()` helpers from @proto/core-mcp and
31
+ * return their output. Index signature matches the MCP SDK's tool callback
32
+ * return type (allows fields like `_meta`, `isError`, etc.).
33
+ */
34
+ export interface ToolResult {
35
+ content: Array<{
36
+ type: 'text';
37
+ text: string;
38
+ }>;
39
+ [key: string]: unknown;
40
+ }
41
+ /**
42
+ * Handler signature. Receives validated args (inferred from the Zod schema)
43
+ * and must return an MCP-shaped result. Throwing is allowed — the framework
44
+ * wraps the handler in try/catch and returns a normalized error response.
45
+ */
46
+ export type ToolHandler<S extends z.ZodRawShape> = (args: z.infer<z.ZodObject<S>>) => Promise<ToolResult> | ToolResult;
47
+ /**
48
+ * Declarative tool definition. `schema` is a Zod raw shape (the same object
49
+ * you'd pass as the third argument to `server.tool()` today).
50
+ */
51
+ export interface ToolDefinition<S extends z.ZodRawShape = z.ZodRawShape> {
52
+ name: string;
53
+ description: string;
54
+ schema: S;
55
+ handler: ToolHandler<S>;
56
+ }
57
+ /**
58
+ * Identity helper with type inference. Pass a definition object, get it back
59
+ * unchanged. Use in default exports of app/tools files:
60
+ *
61
+ * export default [defineTool({ ... }), defineTool({ ... })]
62
+ */
63
+ export declare function defineTool<S extends z.ZodRawShape>(def: ToolDefinition<S>): ToolDefinition<S>;
64
+ /**
65
+ * Register an array of tool definitions on a server instance. Wraps each
66
+ * handler in a try/catch that emits a normalized error response if the tool
67
+ * throws.
68
+ */
69
+ export declare function registerTools(server: McpServer, defs: readonly ToolDefinition[]): void;
70
+ //# sourceMappingURL=define-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-tool.d.ts","sourceRoot":"","sources":["../../../core-mcp/src/define-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AACxE,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAE5B;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC9C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED;;;;GAIG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,IAAI,CACjD,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAC1B,OAAO,CAAC,UAAU,CAAC,GAAG,UAAU,CAAA;AAErC;;;GAGG;AACH,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,GAAG,CAAC,CAAC,WAAW;IACrE,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,CAAC,CAAA;IACT,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,CAAA;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAChD,GAAG,EAAE,cAAc,CAAC,CAAC,CAAC,GACrB,cAAc,CAAC,CAAC,CAAC,CAEnB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,SAAS,EACjB,IAAI,EAAE,SAAS,cAAc,EAAE,GAC9B,IAAI,CA0BN"}