@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,62 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'agent-instance',
5
+ name: 'Agent Instance',
6
+ description: 'An active chat session with a VeilCLI agent.',
7
+ icon: 'message-circle',
8
+ defaultWidth: 180,
9
+ defaultHeight: 90,
10
+ expansionMode: 'sidebar',
11
+ tags: ['cli', 'agent', 'chat'],
12
+ isBuiltIn: true,
13
+ hiddenFromPalette: true,
14
+
15
+ createInstance(context) {
16
+ const { element, log } = context
17
+ let _isStreaming = false
18
+
19
+ return {
20
+ getViewData() {
21
+ return {
22
+ agentName: element.data.agentName || null,
23
+ sessionId: element.data.sessionId || null,
24
+ isStreaming: _isStreaming,
25
+ }
26
+ },
27
+
28
+ getPorts() {
29
+ return [
30
+ { key: 'msg-in', direction: 'input', dataType: 'text', label: 'Message In' },
31
+ { key: 'msg-out', direction: 'output', dataType: 'text', label: 'Message Out' },
32
+ ]
33
+ },
34
+
35
+ actions: {
36
+ setStreaming({ streaming }) {
37
+ _isStreaming = !!streaming
38
+ },
39
+
40
+ openChat(_params) {
41
+ // Handled client-side by useChat.ts
42
+ log('openChat action (client-side)')
43
+ },
44
+
45
+ async ensureSession(_params) {
46
+ if (element.data.sessionId) return
47
+ const { veil } = context
48
+ const agentName = element.data.agentName
49
+ if (!agentName) throw new Error('No agent name set')
50
+ try {
51
+ const session = await veil.post('/sessions', { agent: agentName })
52
+ const { updateElement } = require('../board-state.js')
53
+ updateElement(element.id, { data: { ...element.data, sessionId: session.id } })
54
+ } catch (err) {
55
+ log(`Failed to create session: ${err.message}`)
56
+ throw err
57
+ }
58
+ },
59
+ },
60
+ }
61
+ },
62
+ }
@@ -0,0 +1,93 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'agent',
5
+ name: 'Agent',
6
+ description: 'A VeilCLI agent definition. Open a session to start chatting.',
7
+ icon: 'bot',
8
+ defaultWidth: 240,
9
+ defaultHeight: 130,
10
+ expansionMode: 'popup',
11
+ tags: ['cli', 'agent'],
12
+ isBuiltIn: true,
13
+ hiddenFromPalette: true,
14
+
15
+ createInstance(context) {
16
+ const { element, veil, emit, log } = context
17
+
18
+ return {
19
+ getViewData() {
20
+ const name = element.data.name || element.data.agentName || null
21
+ const agentInfo = element.data.agentInfo || {}
22
+ return {
23
+ name,
24
+ agentName: name,
25
+ model: element.data.model || agentInfo.model || null,
26
+ description: element.data.description || agentInfo.description || null,
27
+ modes: element.data.modes || agentInfo.modes || null,
28
+ source: element.data.source || agentInfo.source || null,
29
+ }
30
+ },
31
+
32
+ getPorts() {
33
+ return [
34
+ { key: 'instances', direction: 'output', dataType: 'agent', label: 'Instances' },
35
+ ]
36
+ },
37
+
38
+ actions: {
39
+ async openSession(_params) {
40
+ const { createElement } = require('../board-state.js')
41
+ const { createInstance, getViewData, getPorts } = require('../element-instances.js')
42
+ const { getIO } = require('../socket-io.js')
43
+
44
+ const agentName = element.data.name || element.data.agentName
45
+ if (!agentName) throw new Error('No agent name set on this element')
46
+
47
+ log(`Creating Veil session for agent "${agentName}"`)
48
+ let sessionId = null
49
+ try {
50
+ const res = await veil.post('/sessions', { agentName })
51
+ sessionId = res.sessionId
52
+ log(`Session created: ${sessionId}`)
53
+ } catch (err) {
54
+ log(`Failed to create session: ${err.message}`)
55
+ throw new Error(`Could not create session: ${err.message}`)
56
+ }
57
+
58
+ const newEl = createElement({
59
+ type: 'agent-instance',
60
+ x: element.x + 200,
61
+ y: element.y,
62
+ width: 180,
63
+ height: 110,
64
+ data: { agentName, sessionId },
65
+ })
66
+
67
+ createInstance(newEl)
68
+ const viewData = getViewData(newEl.id)
69
+ const ports = getPorts(newEl.id)
70
+ getIO().to('board').emit('board:delta', {
71
+ type: 'element:view',
72
+ id: newEl.id,
73
+ viewData: { ...viewData, ports },
74
+ })
75
+
76
+ return { sessionId, elementId: newEl.id }
77
+ },
78
+
79
+ async refreshAgent(_params) {
80
+ const agentName = element.data.agentName
81
+ if (!agentName) return
82
+ try {
83
+ const agent = await veil.get(`/agents/${encodeURIComponent(agentName)}`)
84
+ const { updateElement } = require('../board-state.js')
85
+ updateElement(element.id, { data: { ...element.data, agentInfo: agent } })
86
+ } catch (err) {
87
+ log(`Failed to refresh agent: ${err.message}`)
88
+ }
89
+ },
90
+ },
91
+ }
92
+ },
93
+ }
@@ -0,0 +1,30 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'annotation',
5
+ name: 'Annotation',
6
+ description: 'A floating note that follows its target element.',
7
+ icon: 'sticky-note',
8
+ defaultWidth: 180,
9
+ defaultHeight: 80,
10
+ expansionMode: 'inline',
11
+ tags: ['org'],
12
+ isBuiltIn: true,
13
+ hiddenFromPalette: true,
14
+
15
+ createInstance(context) {
16
+ const { element } = context
17
+ return {
18
+ getViewData() {
19
+ return { text: element.data.text || '', targetId: element.data.targetId || null }
20
+ },
21
+ getPorts() { return [] },
22
+ actions: {
23
+ update(data = {}) {
24
+ const { updateElement } = require('../board-state.js')
25
+ updateElement(element.id, { data: { ...element.data, ...data } })
26
+ },
27
+ },
28
+ }
29
+ },
30
+ }
@@ -0,0 +1,49 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'approval-gate',
5
+ name: 'Approval Gate',
6
+ description: 'Gate flow on an approve/reject decision.',
7
+ icon: 'shield-check',
8
+ defaultWidth: 220,
9
+ defaultHeight: 90,
10
+ expansionMode: 'inline',
11
+ tags: ['comm', 'flow'],
12
+ isBuiltIn: true,
13
+ hiddenFromPalette: true,
14
+
15
+ createInstance(context) {
16
+ const { element } = context
17
+ return {
18
+ getViewData() {
19
+ return {
20
+ title: element.data.title || '',
21
+ description: element.data.description || '',
22
+ status: element.data.status || 'pending',
23
+ reason: element.data.reason || null,
24
+ }
25
+ },
26
+ getPorts() {
27
+ return [
28
+ { key: 'item-in', direction: 'input', dataType: 'any', label: 'Item In' },
29
+ { key: 'approved-out', direction: 'output', dataType: 'any', label: 'Approved' },
30
+ { key: 'rejected-out', direction: 'output', dataType: 'any', label: 'Rejected' },
31
+ ]
32
+ },
33
+ actions: {
34
+ approve(_params) {
35
+ const { updateElement } = require('../board-state.js')
36
+ updateElement(element.id, { data: { ...element.data, status: 'approved', reason: null } })
37
+ },
38
+ reject({ reason } = {}) {
39
+ const { updateElement } = require('../board-state.js')
40
+ updateElement(element.id, { data: { ...element.data, status: 'rejected', reason: reason || null } })
41
+ },
42
+ reset(_params) {
43
+ const { updateElement } = require('../board-state.js')
44
+ updateElement(element.id, { data: { ...element.data, status: 'pending', reason: null } })
45
+ },
46
+ },
47
+ }
48
+ },
49
+ }
@@ -0,0 +1,32 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'assumption',
5
+ name: 'Assumption',
6
+ description: 'An assumption that underlies a decision or plan.',
7
+ icon: 'quote',
8
+ defaultWidth: 180,
9
+ defaultHeight: 70,
10
+ expansionMode: 'inline',
11
+ tags: ['thinking'],
12
+ isBuiltIn: true,
13
+ hiddenFromPalette: true,
14
+
15
+ createInstance(context) {
16
+ const { element } = context
17
+ return {
18
+ getViewData() {
19
+ return { text: element.data.text || '', challenged: element.data.challenged || false }
20
+ },
21
+ getPorts() {
22
+ return [{ key: 'assumption-out', direction: 'output', dataType: 'text', label: 'Assumption Out' }]
23
+ },
24
+ actions: {
25
+ update(data = {}) {
26
+ const { updateElement } = require('../board-state.js')
27
+ updateElement(element.id, { data: { ...element.data, ...data } })
28
+ },
29
+ },
30
+ }
31
+ },
32
+ }
@@ -0,0 +1,36 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'blocker',
5
+ name: 'Blocker',
6
+ description: 'Track a blocker or impediment.',
7
+ icon: 'octagon',
8
+ defaultWidth: 200,
9
+ defaultHeight: 80,
10
+ expansionMode: 'inline',
11
+ tags: ['thinking', 'pm'],
12
+ isBuiltIn: true,
13
+ hiddenFromPalette: true,
14
+
15
+ createInstance(context) {
16
+ const { element } = context
17
+ return {
18
+ getViewData() {
19
+ return {
20
+ title: element.data.title || '',
21
+ description: element.data.description || '',
22
+ severity: element.data.severity || 'medium',
23
+ }
24
+ },
25
+ getPorts() {
26
+ return [{ key: 'blocker-out', direction: 'output', dataType: 'text', label: 'Blocker Out' }]
27
+ },
28
+ actions: {
29
+ update(data = {}) {
30
+ const { updateElement } = require('../board-state.js')
31
+ updateElement(element.id, { data: { ...element.data, ...data } })
32
+ },
33
+ },
34
+ }
35
+ },
36
+ }
@@ -0,0 +1,47 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'chat-room',
5
+ name: 'Chat Room',
6
+ description: 'A multi-agent chat room.',
7
+ icon: 'messages-square',
8
+ defaultWidth: 240,
9
+ defaultHeight: 150,
10
+ expansionMode: 'popup',
11
+ tags: ['comm'],
12
+ isBuiltIn: true,
13
+ hiddenFromPalette: true,
14
+
15
+ createInstance(context) {
16
+ const { element, emit } = context
17
+ return {
18
+ getViewData() {
19
+ return {
20
+ name: element.data.name || '',
21
+ messages: element.data.messages || [],
22
+ }
23
+ },
24
+ getPorts() {
25
+ return [
26
+ { key: 'agents-in', direction: 'input', dataType: 'agent', label: 'Agents In' },
27
+ { key: 'messages-out', direction: 'output', dataType: 'json', label: 'Messages Out' },
28
+ ]
29
+ },
30
+ actions: {
31
+ postMessage({ role, content } = {}) {
32
+ const { updateElement } = require('../board-state.js')
33
+ const messages = [
34
+ ...(element.data.messages || []),
35
+ { role, content, timestamp: Date.now() },
36
+ ]
37
+ updateElement(element.id, { data: { ...element.data, messages } })
38
+ emit('element:view', { id: element.id, viewData: { messages } })
39
+ },
40
+ update(data = {}) {
41
+ const { updateElement } = require('../board-state.js')
42
+ updateElement(element.id, { data: { ...element.data, ...data } })
43
+ },
44
+ },
45
+ }
46
+ },
47
+ }
@@ -0,0 +1,33 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'chat-view',
5
+ name: 'Chat View',
6
+ description: 'Inline chat panel for an agent session. Created automatically from an agent instance.',
7
+ icon: '💬',
8
+ defaultWidth: 320,
9
+ defaultHeight: 440,
10
+ hiddenFromPalette: true,
11
+ tags: ['cli'],
12
+ isBuiltIn: true,
13
+
14
+ createInstance(context) {
15
+ const { element } = context
16
+ let _isStreaming = false
17
+ return {
18
+ getViewData() {
19
+ return {
20
+ agentName: element.data.agentName || null,
21
+ sessionId: element.data.sessionId || null,
22
+ isStreaming: _isStreaming,
23
+ }
24
+ },
25
+ getPorts() { return [] },
26
+ actions: {
27
+ setStreaming({ streaming }) {
28
+ _isStreaming = !!streaming
29
+ },
30
+ },
31
+ }
32
+ },
33
+ }
@@ -0,0 +1,39 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'code-block',
5
+ name: 'Code Block',
6
+ description: 'A syntax-highlighted code snippet.',
7
+ icon: 'code',
8
+ defaultWidth: 240,
9
+ defaultHeight: 120,
10
+ expansionMode: 'popup',
11
+ tags: ['data', 'dev'],
12
+ isBuiltIn: true,
13
+
14
+ createInstance(context) {
15
+ const { element } = context
16
+ return {
17
+ getViewData() {
18
+ return {
19
+ code: element.data.code || '',
20
+ language: element.data.language || 'text',
21
+ title: element.data.title || '',
22
+ }
23
+ },
24
+ getPorts() {
25
+ return [{ key: 'code-out', direction: 'output', dataType: 'text', label: 'Code Out' }]
26
+ },
27
+ actions: {
28
+ update({ code, language, title } = {}) {
29
+ const { updateElement } = require('../board-state.js')
30
+ const data = { ...element.data }
31
+ if (code !== undefined) data.code = code
32
+ if (language !== undefined) data.language = language
33
+ if (title !== undefined) data.title = title
34
+ updateElement(element.id, { data })
35
+ },
36
+ },
37
+ }
38
+ },
39
+ }
@@ -0,0 +1,37 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'collapsible-group',
5
+ name: 'Collapsible Group',
6
+ description: 'A group that contains other elements and can be collapsed.',
7
+ icon: 'group',
8
+ defaultWidth: 300,
9
+ defaultHeight: 200,
10
+ expansionMode: 'inline',
11
+ tags: ['org'],
12
+ isBuiltIn: true,
13
+ hiddenFromPalette: true,
14
+
15
+ createInstance(context) {
16
+ const { element } = context
17
+ return {
18
+ getViewData() {
19
+ return {
20
+ label: element.data.label || '',
21
+ collapsed: element.data.collapsed || false,
22
+ }
23
+ },
24
+ getPorts() { return [] },
25
+ actions: {
26
+ toggle(_params) {
27
+ const { updateElement } = require('../board-state.js')
28
+ updateElement(element.id, { data: { ...element.data, collapsed: !element.data.collapsed } })
29
+ },
30
+ update(data = {}) {
31
+ const { updateElement } = require('../board-state.js')
32
+ updateElement(element.id, { data: { ...element.data, ...data } })
33
+ },
34
+ },
35
+ }
36
+ },
37
+ }
@@ -0,0 +1,38 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'comparison-table',
5
+ name: 'Comparison Table',
6
+ description: 'Compare items across multiple dimensions.',
7
+ icon: 'table',
8
+ defaultWidth: 280,
9
+ defaultHeight: 150,
10
+ expansionMode: 'popup',
11
+ tags: ['research', 'data'],
12
+ isBuiltIn: true,
13
+ hiddenFromPalette: true,
14
+
15
+ createInstance(context) {
16
+ const { element } = context
17
+ return {
18
+ getViewData() {
19
+ return {
20
+ headers: element.data.headers || [],
21
+ rows: element.data.rows || [],
22
+ }
23
+ },
24
+ getPorts() {
25
+ return [
26
+ { key: 'items-in', direction: 'input', dataType: 'any', label: 'Items In' },
27
+ { key: 'table-out', direction: 'output', dataType: 'json', label: 'Table Out' },
28
+ ]
29
+ },
30
+ actions: {
31
+ update(data = {}) {
32
+ const { updateElement } = require('../board-state.js')
33
+ updateElement(element.id, { data: { ...element.data, ...data } })
34
+ },
35
+ },
36
+ }
37
+ },
38
+ }
@@ -0,0 +1,32 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'constraint',
5
+ name: 'Constraint',
6
+ description: 'A hard or soft constraint on a solution.',
7
+ icon: 'lock',
8
+ defaultWidth: 180,
9
+ defaultHeight: 70,
10
+ expansionMode: 'inline',
11
+ tags: ['thinking'],
12
+ isBuiltIn: true,
13
+ hiddenFromPalette: true,
14
+
15
+ createInstance(context) {
16
+ const { element } = context
17
+ return {
18
+ getViewData() {
19
+ return { text: element.data.text || '', severity: element.data.severity || 'hard' }
20
+ },
21
+ getPorts() {
22
+ return [{ key: 'constraint-out', direction: 'output', dataType: 'text', label: 'Constraint Out' }]
23
+ },
24
+ actions: {
25
+ update(data = {}) {
26
+ const { updateElement } = require('../board-state.js')
27
+ updateElement(element.id, { data: { ...element.data, ...data } })
28
+ },
29
+ },
30
+ }
31
+ },
32
+ }
@@ -0,0 +1,39 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'decision',
5
+ name: 'Decision',
6
+ description: 'Record a decision with rationale.',
7
+ icon: 'git-branch',
8
+ defaultWidth: 200,
9
+ defaultHeight: 90,
10
+ expansionMode: 'inline',
11
+ tags: ['thinking'],
12
+ isBuiltIn: true,
13
+ hiddenFromPalette: true,
14
+
15
+ createInstance(context) {
16
+ const { element } = context
17
+ return {
18
+ getViewData() {
19
+ return {
20
+ title: element.data.title || '',
21
+ chosen: element.data.chosen || '',
22
+ rationale: element.data.rationale || '',
23
+ }
24
+ },
25
+ getPorts() {
26
+ return [
27
+ { key: 'options-in', direction: 'input', dataType: 'any', label: 'Options In' },
28
+ { key: 'decision-out', direction: 'output', dataType: 'text', label: 'Decision Out' },
29
+ ]
30
+ },
31
+ actions: {
32
+ update(data = {}) {
33
+ const { updateElement } = require('../board-state.js')
34
+ updateElement(element.id, { data: { ...element.data, ...data } })
35
+ },
36
+ },
37
+ }
38
+ },
39
+ }
@@ -0,0 +1,38 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'diff-patch',
5
+ name: 'Diff / Patch',
6
+ description: 'Show the diff between original and modified text.',
7
+ icon: 'git-diff',
8
+ defaultWidth: 280,
9
+ defaultHeight: 150,
10
+ expansionMode: 'popup',
11
+ tags: ['dev'],
12
+ isBuiltIn: true,
13
+
14
+ createInstance(context) {
15
+ const { element } = context
16
+ return {
17
+ getViewData() {
18
+ return {
19
+ source: element.data.source || '',
20
+ change: element.data.change || '',
21
+ }
22
+ },
23
+ getPorts() {
24
+ return [
25
+ { key: 'source-in', direction: 'input', dataType: 'text', label: 'Source In' },
26
+ { key: 'change-in', direction: 'input', dataType: 'text', label: 'Change In' },
27
+ { key: 'change-out', direction: 'output', dataType: 'text', label: 'Change Out' },
28
+ ]
29
+ },
30
+ actions: {
31
+ update(data = {}) {
32
+ const { updateElement } = require('../board-state.js')
33
+ updateElement(element.id, { data: { ...element.data, ...data } })
34
+ },
35
+ },
36
+ }
37
+ },
38
+ }
@@ -0,0 +1,30 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'divider',
5
+ name: 'Divider',
6
+ description: 'A visual separator line.',
7
+ icon: 'minus',
8
+ defaultWidth: 300,
9
+ defaultHeight: 4,
10
+ expansionMode: 'inline',
11
+ tags: ['org'],
12
+ isBuiltIn: true,
13
+ hiddenFromPalette: true,
14
+
15
+ createInstance(context) {
16
+ const { element } = context
17
+ return {
18
+ getViewData() {
19
+ return { color: element.data.color || '#475569', thickness: element.data.thickness || 1 }
20
+ },
21
+ getPorts() { return [] },
22
+ actions: {
23
+ update(data = {}) {
24
+ const { updateElement } = require('../board-state.js')
25
+ updateElement(element.id, { data: { ...element.data, ...data } })
26
+ },
27
+ },
28
+ }
29
+ },
30
+ }
@@ -0,0 +1,35 @@
1
+ 'use strict'
2
+
3
+ module.exports = {
4
+ type: 'document-draft',
5
+ name: 'Document Draft',
6
+ description: 'A document draft with title and content.',
7
+ icon: 'file-edit',
8
+ defaultWidth: 200,
9
+ defaultHeight: 100,
10
+ expansionMode: 'sidebar',
11
+ tags: ['docs'],
12
+ isBuiltIn: true,
13
+ hiddenFromPalette: true,
14
+
15
+ createInstance(context) {
16
+ const { element } = context
17
+ return {
18
+ getViewData() {
19
+ return { title: element.data.title || '', content: element.data.content || '' }
20
+ },
21
+ getPorts() {
22
+ return [
23
+ { key: 'sections-in', direction: 'input', dataType: 'text', label: 'Sections In' },
24
+ { key: 'doc-out', direction: 'output', dataType: 'text', label: 'Doc Out' },
25
+ ]
26
+ },
27
+ actions: {
28
+ update(data = {}) {
29
+ const { updateElement } = require('../board-state.js')
30
+ updateElement(element.id, { data: { ...element.data, ...data } })
31
+ },
32
+ },
33
+ }
34
+ },
35
+ }