@newsails/veil-studio 1.0.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 (87) hide show
  1. package/README.md +181 -0
  2. package/bin/veil-studio.js +142 -0
  3. package/nuxt-app/.output/public/200.html +13 -0
  4. package/nuxt-app/.output/public/404.html +13 -0
  5. package/nuxt-app/.output/public/_nuxt/builds/latest.json +1 -0
  6. package/nuxt-app/.output/public/_nuxt/builds/meta/6b28df26-54af-4fad-a1f0-38808960d9fe.json +1 -0
  7. package/nuxt-app/.output/public/_nuxt/entry.BrrOeBSX.js +120 -0
  8. package/nuxt-app/.output/public/_nuxt/entry.CYnp7zY5.css +1 -0
  9. package/nuxt-app/.output/public/_nuxt/error-404.BbdzCaXe.js +1 -0
  10. package/nuxt-app/.output/public/_nuxt/error-404.JekaaCis.css +1 -0
  11. package/nuxt-app/.output/public/_nuxt/error-500.CNP9nqm1.css +1 -0
  12. package/nuxt-app/.output/public/_nuxt/error-500.DbOlBIIY.js +1 -0
  13. package/nuxt-app/.output/public/_nuxt/index.BEoXSIOu.css +1 -0
  14. package/nuxt-app/.output/public/_nuxt/index.CNms2yAq.js +1 -0
  15. package/nuxt-app/.output/public/_nuxt/materialdesignicons-webfont.B7mPwVP_.ttf +0 -0
  16. package/nuxt-app/.output/public/_nuxt/materialdesignicons-webfont.CSr8KVlo.eot +0 -0
  17. package/nuxt-app/.output/public/_nuxt/materialdesignicons-webfont.Dp5v-WZN.woff2 +0 -0
  18. package/nuxt-app/.output/public/_nuxt/materialdesignicons-webfont.PXm3-2wK.woff +0 -0
  19. package/nuxt-app/.output/public/_nuxt/vue.-sixQ7xP.BlWffD__.js +1 -0
  20. package/nuxt-app/.output/public/index.html +13 -0
  21. package/package.json +37 -0
  22. package/server/index.js +184 -0
  23. package/server/routes/files.js +80 -0
  24. package/server/socket.js +507 -0
  25. package/server/utils/board-state.js +357 -0
  26. package/server/utils/config.js +51 -0
  27. package/server/utils/db.js +484 -0
  28. package/server/utils/element-instances.js +104 -0
  29. package/server/utils/element-registry.js +127 -0
  30. package/server/utils/elements/agent-instance.js +62 -0
  31. package/server/utils/elements/agent.js +93 -0
  32. package/server/utils/elements/annotation.js +30 -0
  33. package/server/utils/elements/approval-gate.js +49 -0
  34. package/server/utils/elements/assumption.js +32 -0
  35. package/server/utils/elements/blocker.js +36 -0
  36. package/server/utils/elements/chat-room.js +47 -0
  37. package/server/utils/elements/chat-view.js +33 -0
  38. package/server/utils/elements/code-block.js +39 -0
  39. package/server/utils/elements/collapsible-group.js +37 -0
  40. package/server/utils/elements/comparison-table.js +38 -0
  41. package/server/utils/elements/constraint.js +32 -0
  42. package/server/utils/elements/decision.js +39 -0
  43. package/server/utils/elements/diff-patch.js +38 -0
  44. package/server/utils/elements/divider.js +30 -0
  45. package/server/utils/elements/document-draft.js +35 -0
  46. package/server/utils/elements/fact-claim.js +36 -0
  47. package/server/utils/elements/feedback-request.js +43 -0
  48. package/server/utils/elements/file-reference.js +31 -0
  49. package/server/utils/elements/filter.js +48 -0
  50. package/server/utils/elements/generator.js +51 -0
  51. package/server/utils/elements/goal.js +36 -0
  52. package/server/utils/elements/html.js +35 -0
  53. package/server/utils/elements/idea.js +32 -0
  54. package/server/utils/elements/image-local.js +21 -0
  55. package/server/utils/elements/image.js +34 -0
  56. package/server/utils/elements/json-object.js +47 -0
  57. package/server/utils/elements/label-tag.js +30 -0
  58. package/server/utils/elements/markdown.js +37 -0
  59. package/server/utils/elements/merger.js +36 -0
  60. package/server/utils/elements/message.js +40 -0
  61. package/server/utils/elements/milestone.js +44 -0
  62. package/server/utils/elements/notification.js +34 -0
  63. package/server/utils/elements/outline.js +35 -0
  64. package/server/utils/elements/primitive.js +36 -0
  65. package/server/utils/elements/pro-con-list.js +39 -0
  66. package/server/utils/elements/processor.js +54 -0
  67. package/server/utils/elements/project.js +40 -0
  68. package/server/utils/elements/question.js +42 -0
  69. package/server/utils/elements/queue.js +85 -0
  70. package/server/utils/elements/research-note.js +41 -0
  71. package/server/utils/elements/section.js +35 -0
  72. package/server/utils/elements/source-collection.js +45 -0
  73. package/server/utils/elements/splitter.js +42 -0
  74. package/server/utils/elements/status-update.js +38 -0
  75. package/server/utils/elements/task.js +72 -0
  76. package/server/utils/elements/template.js +46 -0
  77. package/server/utils/elements/test-case.js +42 -0
  78. package/server/utils/elements/text.js +29 -0
  79. package/server/utils/elements/todo-list.js +57 -0
  80. package/server/utils/elements/url-card.js +37 -0
  81. package/server/utils/elements/web-search-query.js +46 -0
  82. package/server/utils/elements/web-snapshot.js +37 -0
  83. package/server/utils/file-utils.js +88 -0
  84. package/server/utils/session-watcher.js +108 -0
  85. package/server/utils/socket-io.js +14 -0
  86. package/server/utils/veil-client.js +185 -0
  87. package/server/utils/veil-ws.js +207 -0
@@ -0,0 +1,207 @@
1
+ 'use strict'
2
+
3
+ const WebSocket = require('ws')
4
+ const { VEIL_WS_URL, VEIL_SECRET } = require('./config.js')
5
+ const { getIO } = require('./socket-io.js')
6
+ const boardState = require('./board-state.js')
7
+ const { initSessionStates } = require('./session-watcher.js')
8
+
9
+ let _activeStreams = null
10
+ let _setElementStreamingFn = null
11
+
12
+ // Sessions that received iteration.start but not yet session.stream done
13
+ // Used to detect sse=false sessions (agent_message tool) and emit chat:done fallback
14
+ const _typingSessions = new Set()
15
+
16
+ function setActiveStreamsRef(ref) {
17
+ _activeStreams = ref
18
+ }
19
+
20
+ function setElementStreamingRef(fn) {
21
+ _setElementStreamingFn = fn
22
+ }
23
+
24
+ let _ws = null
25
+ let _connected = false
26
+ let _retryDelay = 2000
27
+ const MAX_RETRY_DELAY = 60000
28
+
29
+ function isVeilConnected() {
30
+ return _connected
31
+ }
32
+
33
+ function connectVeilWS() {
34
+ const wsUrl = `${VEIL_WS_URL}/ws`
35
+ const headers = {}
36
+ if (VEIL_SECRET) headers['X-Veil-Secret'] = VEIL_SECRET
37
+
38
+ try {
39
+ _ws = new WebSocket(wsUrl, { headers })
40
+ } catch (err) {
41
+ console.warn(`[veil-ws] Could not connect to ${wsUrl}: ${err.message}`)
42
+ _scheduleReconnect()
43
+ return
44
+ }
45
+
46
+ _ws.on('open', () => {
47
+ _connected = true
48
+ _retryDelay = 2000
49
+ console.log(`[veil-ws] Connected to ${wsUrl}`)
50
+ try {
51
+ getIO().emit('veil:status', { connected: true })
52
+ } catch (_) {}
53
+ initSessionStates().catch(e => console.warn('[veil-ws] initSessionStates:', e.message))
54
+ })
55
+
56
+ _ws.on('message', (data) => {
57
+ try {
58
+ const event = JSON.parse(data.toString())
59
+ try { getIO().emit('veil:event', event) } catch (_) {}
60
+
61
+ // Update element state from task/session events
62
+ _handleVeilEvent(event)
63
+ } catch (err) {
64
+ console.error('[veil-ws] Failed to parse message:', err.message)
65
+ }
66
+ })
67
+
68
+ _ws.on('close', () => {
69
+ _connected = false
70
+ console.log('[veil-ws] Disconnected. Reconnecting...')
71
+ try { getIO().emit('veil:status', { connected: false }) } catch (_) {}
72
+ _scheduleReconnect()
73
+ })
74
+
75
+ _ws.on('error', (err) => {
76
+ console.error('[veil-ws] Error:', err.message)
77
+ // close event will fire next
78
+ })
79
+ }
80
+
81
+ function _scheduleReconnect() {
82
+ setTimeout(() => {
83
+ connectVeilWS()
84
+ _retryDelay = Math.min(_retryDelay * 2, MAX_RETRY_DELAY)
85
+ }, _retryDelay)
86
+ }
87
+
88
+ function _isExternalSession(sessionId) {
89
+ return !_activeStreams || !_activeStreams.has(sessionId)
90
+ }
91
+
92
+ function _handleVeilEvent(event) {
93
+ if (!event || !event.type) return
94
+
95
+ const io = getIO()
96
+
97
+ // ── session.stream — mirrors SSE stream for every session in real-time ──────
98
+ if (event.type === 'session.stream' && event.sessionId) {
99
+ if (!_isExternalSession(event.sessionId)) return // Studio's chat:send owns this
100
+
101
+ const { sessionId, eventType, data } = event
102
+
103
+ if (eventType === 'error') {
104
+ try { io.to('board').emit('chat:error', { sessionId, error: data?.error ?? 'Unknown error' }) } catch (_) {}
105
+ } else if (eventType === 'done') {
106
+ _typingSessions.delete(sessionId)
107
+ try {
108
+ io.to('board').emit('chat:stream', { sessionId, eventType: 'done', data })
109
+ io.to('board').emit('chat:done', { sessionId })
110
+ } catch (_) {}
111
+ // Clear element streaming indicator
112
+ if (_setElementStreamingFn) _setElementStreamingFn(sessionId, false)
113
+ } else {
114
+ // inference.chunk, inference.tool, message (assistant/tool)
115
+ try { io.to('board').emit('chat:stream', { sessionId, eventType, data }) } catch (_) {}
116
+ }
117
+ return
118
+ }
119
+
120
+ // ── chat.user_message — user message before AI starts ───────────────────────
121
+ if (event.type === 'chat.user_message' && event.sessionId) {
122
+ if (!_isExternalSession(event.sessionId)) return
123
+ try {
124
+ io.to('board').emit('chat:user-message', {
125
+ sessionId: event.sessionId,
126
+ agentName: event.agentName || '',
127
+ message: event.event?.content ?? '',
128
+ })
129
+ } catch (_) {}
130
+ return
131
+ }
132
+
133
+ // ── chat.event — iteration start → typing indicator + element streaming ─────
134
+ if (event.type === 'chat.event' && event.sessionId) {
135
+ if (event.event?.type === 'iteration.start' && _isExternalSession(event.sessionId)) {
136
+ _typingSessions.add(event.sessionId)
137
+ try { io.to('board').emit('chat:typing', { sessionId: event.sessionId }) } catch (_) {}
138
+ if (_setElementStreamingFn) _setElementStreamingFn(event.sessionId, true)
139
+ }
140
+ return
141
+ }
142
+
143
+ // ── chat.inference_tool — tool indicator for non-SSE sessions ───────────────
144
+ // Equivalent of session.stream eventType inference.tool for HTTP/agent_message paths
145
+ if (event.type === 'chat.inference_tool' && event.sessionId) {
146
+ if (_isExternalSession(event.sessionId)) {
147
+ try {
148
+ io.to('board').emit('chat:stream', {
149
+ sessionId: event.sessionId,
150
+ eventType: 'inference.tool',
151
+ data: { name: event.event?.name ?? '' },
152
+ })
153
+ } catch (_) {}
154
+ }
155
+ return
156
+ }
157
+
158
+ // ── chat.message — sse=false final message (agent_message tool invocation) ────
159
+ // Emitted instead of session.stream events when the session was called with sse=false
160
+ if (event.type === 'chat.message' && event.sessionId) {
161
+ if (_isExternalSession(event.sessionId)) {
162
+ try {
163
+ io.to('board').emit('chat:stream', {
164
+ sessionId: event.sessionId,
165
+ eventType: 'message',
166
+ data: event.event,
167
+ })
168
+ } catch (_) {}
169
+ }
170
+ return
171
+ }
172
+
173
+ // ── chat.response — fallback: stop streaming if session.stream done never fired ─
174
+ if (event.type === 'chat.response' && event.sessionId) {
175
+ const sessionId = event.sessionId
176
+ if (_isExternalSession(sessionId) && _typingSessions.has(sessionId)) {
177
+ _typingSessions.delete(sessionId)
178
+ try {
179
+ io.to('board').emit('chat:done', { sessionId })
180
+ } catch (_) {}
181
+ if (_setElementStreamingFn) _setElementStreamingFn(sessionId, false)
182
+ }
183
+ return
184
+ }
185
+
186
+ // ── task.status — update task element state on board ────────────────────────
187
+ if (event.type === 'task.status' && event.taskId && event.event) {
188
+ const status = event.event.status
189
+ if (!status) return
190
+ const stateMap = {
191
+ running: 'running',
192
+ finished: 'completed',
193
+ failed: 'error',
194
+ cancelled: 'default',
195
+ }
196
+ const elementState = stateMap[status]
197
+ if (!elementState) return
198
+
199
+ for (const el of boardState.getElements()) {
200
+ if (el.type === 'task' && el.data && el.data.taskId === event.taskId) {
201
+ boardState.updateElementState(el.id, elementState)
202
+ }
203
+ }
204
+ }
205
+ }
206
+
207
+ module.exports = { connectVeilWS, isVeilConnected, setActiveStreamsRef, setElementStreamingRef }