@fugood/bricks-ctor 2.25.0-beta.6 → 2.25.0-beta.60

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 (188) hide show
  1. package/compile/__tests__/config-diff.test.js +100 -0
  2. package/compile/__tests__/index.test.js +461 -0
  3. package/compile/__tests__/util.test.js +450 -0
  4. package/compile/action-name-map.ts +64 -0
  5. package/compile/config-diff.ts +155 -0
  6. package/compile/index.ts +668 -352
  7. package/compile/util.ts +134 -10
  8. package/package.json +7 -3
  9. package/skills/bricks-ctor/SKILL.md +23 -17
  10. package/skills/bricks-ctor/{rules → references}/animation.md +3 -2
  11. package/skills/bricks-ctor/{rules → references}/architecture-patterns.md +19 -0
  12. package/skills/bricks-ctor/{rules → references}/automations.md +11 -0
  13. package/skills/bricks-ctor/references/buttress.md +245 -0
  14. package/skills/bricks-ctor/references/data-calculation.md +252 -0
  15. package/skills/bricks-ctor/{rules → references}/media-flow.md +7 -0
  16. package/skills/bricks-ctor/references/simulator.md +132 -0
  17. package/skills/bricks-ctor/references/source-editing-tools.md +81 -0
  18. package/skills/bricks-ctor/references/verification-toolchain.md +200 -0
  19. package/skills/bricks-design/SKILL.md +150 -45
  20. package/skills/bricks-design/references/architecture-truths.md +132 -0
  21. package/skills/bricks-design/references/avoiding-complexity.md +91 -0
  22. package/skills/bricks-design/references/design-critique.md +195 -0
  23. package/skills/bricks-design/references/design-languages.md +265 -0
  24. package/skills/bricks-design/references/performance.md +116 -0
  25. package/skills/bricks-design/references/presentation-and-slideshow.md +137 -0
  26. package/skills/bricks-design/references/translating-inputs.md +152 -0
  27. package/skills/bricks-design/references/variations-and-tweaks.md +124 -0
  28. package/skills/bricks-design/references/when-the-brief-is-branded.md +284 -0
  29. package/skills/bricks-design/references/when-the-brief-is-vague.md +85 -0
  30. package/skills/bricks-design/references/workflow.md +134 -0
  31. package/skills/bricks-ux/SKILL.md +114 -0
  32. package/skills/bricks-ux/references/accessibility.md +162 -0
  33. package/skills/bricks-ux/references/flow-states.md +175 -0
  34. package/skills/bricks-ux/references/interaction-archetypes.md +189 -0
  35. package/skills/bricks-ux/references/monitoring-screens.md +153 -0
  36. package/skills/bricks-ux/references/pressable-composition.md +126 -0
  37. package/skills/bricks-ux/references/user-journey.md +168 -0
  38. package/skills/bricks-ux/references/ux-critique.md +256 -0
  39. package/tools/__tests__/_cli-error.test.ts +35 -0
  40. package/tools/__tests__/_mcp-config.test.ts +67 -0
  41. package/tools/__tests__/pull.test.ts +108 -0
  42. package/tools/_cli-error.ts +17 -0
  43. package/tools/_edits-log.ts +41 -0
  44. package/tools/_git-author.ts +10 -2
  45. package/tools/_last-pushed-commit.ts +28 -0
  46. package/tools/_mcp-config.ts +42 -0
  47. package/tools/_shell.ts +8 -1
  48. package/tools/deploy.ts +17 -6
  49. package/tools/mcp-env.ts +13 -0
  50. package/tools/mcp-server.ts +8 -0
  51. package/tools/mcp-tools/__tests__/data-calc-editing.test.js +516 -0
  52. package/tools/mcp-tools/__tests__/entry-editing.test.js +866 -0
  53. package/tools/mcp-tools/__tests__/huggingface.test.ts +49 -0
  54. package/tools/mcp-tools/__tests__/icons.test.ts +21 -0
  55. package/tools/mcp-tools/__tests__/mcp-env.test.js +19 -0
  56. package/tools/mcp-tools/_editing-helpers.ts +98 -0
  57. package/tools/mcp-tools/_verify.ts +50 -0
  58. package/tools/mcp-tools/compile.ts +21 -9
  59. package/tools/mcp-tools/data-calc-editing.ts +1311 -0
  60. package/tools/mcp-tools/entry-editing.ts +2297 -0
  61. package/tools/mcp-tools/huggingface.ts +23 -13
  62. package/tools/mcp-tools/icons.ts +23 -7
  63. package/tools/mcp-tools/media.ts +4 -1
  64. package/tools/postinstall.ts +95 -38
  65. package/tools/pull.ts +100 -23
  66. package/tools/push-config.ts +114 -0
  67. package/tools/{preview-main.mjs → simulator-main.mjs} +207 -12
  68. package/tools/simulator-preload.cjs +16 -0
  69. package/tools/{preview.ts → simulator.ts} +4 -4
  70. package/types/{animation.ts → animation.d.ts} +24 -8
  71. package/types/{automation.ts → automation.d.ts} +16 -20
  72. package/types/{brick-base.ts → brick-base.d.ts} +1 -1
  73. package/types/bricks/{Camera.ts → Camera.d.ts} +8 -8
  74. package/types/bricks/{Chart.ts → Chart.d.ts} +4 -4
  75. package/types/bricks/{GenerativeMedia.ts → GenerativeMedia.d.ts} +15 -15
  76. package/types/bricks/{Icon.ts → Icon.d.ts} +7 -7
  77. package/types/bricks/{Image.ts → Image.d.ts} +21 -9
  78. package/types/bricks/{Items.ts → Items.d.ts} +11 -7
  79. package/types/bricks/{Lottie.ts → Lottie.d.ts} +10 -10
  80. package/types/bricks/{Maps.ts → Maps.d.ts} +11 -11
  81. package/types/bricks/{QrCode.ts → QrCode.d.ts} +7 -7
  82. package/types/bricks/{Rect.ts → Rect.d.ts} +7 -7
  83. package/types/bricks/{RichText.ts → RichText.d.ts} +12 -9
  84. package/types/bricks/{Rive.ts → Rive.d.ts} +9 -9
  85. package/types/bricks/Scene3D.d.ts +676 -0
  86. package/types/bricks/{Sketch.ts → Sketch.d.ts} +10 -8
  87. package/types/bricks/{Slideshow.ts → Slideshow.d.ts} +7 -7
  88. package/types/bricks/{Svg.ts → Svg.d.ts} +7 -7
  89. package/types/bricks/{Text.ts → Text.d.ts} +9 -9
  90. package/types/bricks/{TextInput.ts → TextInput.d.ts} +10 -10
  91. package/types/bricks/{Video.ts → Video.d.ts} +80 -13
  92. package/types/bricks/{VideoStreaming.ts → VideoStreaming.d.ts} +10 -10
  93. package/types/bricks/{WebRtcStream.ts → WebRtcStream.d.ts} +1 -1
  94. package/types/bricks/{WebView.ts → WebView.d.ts} +4 -4
  95. package/types/bricks/{index.ts → index.d.ts} +1 -0
  96. package/types/{common.ts → common.d.ts} +3 -6
  97. package/types/data-calc-command/base.d.ts +57 -0
  98. package/types/data-calc-command/collection.d.ts +418 -0
  99. package/types/data-calc-command/color.d.ts +432 -0
  100. package/types/data-calc-command/constant.d.ts +50 -0
  101. package/types/data-calc-command/datetime.d.ts +147 -0
  102. package/types/data-calc-command/file.d.ts +129 -0
  103. package/types/data-calc-command/index.d.ts +13 -0
  104. package/types/data-calc-command/iteratee.d.ts +23 -0
  105. package/types/data-calc-command/logictype.d.ts +190 -0
  106. package/types/data-calc-command/math.d.ts +275 -0
  107. package/types/data-calc-command/object.d.ts +119 -0
  108. package/types/data-calc-command/sandbox.d.ts +66 -0
  109. package/types/data-calc-command/string.d.ts +407 -0
  110. package/types/{data-calc.ts → data-calc.d.ts} +1 -0
  111. package/types/{data.ts → data.d.ts} +4 -2
  112. package/types/generators/{Assistant.ts → Assistant.d.ts} +19 -0
  113. package/types/generators/{HttpServer.ts → HttpServer.d.ts} +56 -2
  114. package/types/generators/{LlmGgml.ts → LlmGgml.d.ts} +43 -1
  115. package/types/generators/{LlmMlx.ts → LlmMlx.d.ts} +1 -0
  116. package/types/generators/{RerankerGgml.ts → RerankerGgml.d.ts} +5 -1
  117. package/types/generators/{SoundRecorder.ts → SoundRecorder.d.ts} +10 -1
  118. package/types/generators/{SpeechToTextGgml.ts → SpeechToTextGgml.d.ts} +6 -1
  119. package/types/generators/{SttAppleBuiltin.ts → SttAppleBuiltin.d.ts} +27 -4
  120. package/types/generators/{ThermalPrinter.ts → ThermalPrinter.d.ts} +9 -7
  121. package/types/generators/{Tick.ts → Tick.d.ts} +1 -1
  122. package/types/generators/{VadGgml.ts → VadGgml.d.ts} +12 -2
  123. package/types/{subspace.ts → subspace.d.ts} +1 -1
  124. package/utils/__tests__/calc.test.js +25 -0
  125. package/utils/__tests__/id.test.js +154 -0
  126. package/utils/calc.ts +5 -1
  127. package/utils/data.ts +5 -7
  128. package/utils/event-props.ts +27 -1
  129. package/utils/id.ts +109 -56
  130. package/skills/bricks-ctor/rules/buttress.md +0 -156
  131. package/skills/bricks-ctor/rules/data-calculation.md +0 -209
  132. package/skills/bricks-design/LICENSE.txt +0 -180
  133. package/types/data-calc-command.ts +0 -7005
  134. /package/skills/bricks-ctor/{rules → references}/local-sync.md +0 -0
  135. /package/skills/bricks-ctor/{rules → references}/remote-data-bank.md +0 -0
  136. /package/skills/bricks-ctor/{rules → references}/standby-transition.md +0 -0
  137. /package/types/{canvas.ts → canvas.d.ts} +0 -0
  138. /package/types/{data-calc-script.ts → data-calc-script.d.ts} +0 -0
  139. /package/types/generators/{AlarmClock.ts → AlarmClock.d.ts} +0 -0
  140. /package/types/generators/{BleCentral.ts → BleCentral.d.ts} +0 -0
  141. /package/types/generators/{BlePeripheral.ts → BlePeripheral.d.ts} +0 -0
  142. /package/types/generators/{CanvasMap.ts → CanvasMap.d.ts} +0 -0
  143. /package/types/generators/{CastlesPay.ts → CastlesPay.d.ts} +0 -0
  144. /package/types/generators/{DataBank.ts → DataBank.d.ts} +0 -0
  145. /package/types/generators/{File.ts → File.d.ts} +0 -0
  146. /package/types/generators/{GraphQl.ts → GraphQl.d.ts} +0 -0
  147. /package/types/generators/{Http.ts → Http.d.ts} +0 -0
  148. /package/types/generators/{Information.ts → Information.d.ts} +0 -0
  149. /package/types/generators/{Intent.ts → Intent.d.ts} +0 -0
  150. /package/types/generators/{Iterator.ts → Iterator.d.ts} +0 -0
  151. /package/types/generators/{Keyboard.ts → Keyboard.d.ts} +0 -0
  152. /package/types/generators/{LlmAnthropicCompat.ts → LlmAnthropicCompat.d.ts} +0 -0
  153. /package/types/generators/{LlmAppleBuiltin.ts → LlmAppleBuiltin.d.ts} +0 -0
  154. /package/types/generators/{LlmMediaTekNeuroPilot.ts → LlmMediaTekNeuroPilot.d.ts} +0 -0
  155. /package/types/generators/{LlmOnnx.ts → LlmOnnx.d.ts} +0 -0
  156. /package/types/generators/{LlmOpenAiCompat.ts → LlmOpenAiCompat.d.ts} +0 -0
  157. /package/types/generators/{LlmQualcommAiEngine.ts → LlmQualcommAiEngine.d.ts} +0 -0
  158. /package/types/generators/{Mcp.ts → Mcp.d.ts} +0 -0
  159. /package/types/generators/{McpServer.ts → McpServer.d.ts} +0 -0
  160. /package/types/generators/{MediaFlow.ts → MediaFlow.d.ts} +0 -0
  161. /package/types/generators/{MqttBroker.ts → MqttBroker.d.ts} +0 -0
  162. /package/types/generators/{MqttClient.ts → MqttClient.d.ts} +0 -0
  163. /package/types/generators/{Question.ts → Question.d.ts} +0 -0
  164. /package/types/generators/{RealtimeTranscription.ts → RealtimeTranscription.d.ts} +0 -0
  165. /package/types/generators/{SerialPort.ts → SerialPort.d.ts} +0 -0
  166. /package/types/generators/{SoundPlayer.ts → SoundPlayer.d.ts} +0 -0
  167. /package/types/generators/{SpeechToTextOnnx.ts → SpeechToTextOnnx.d.ts} +0 -0
  168. /package/types/generators/{SpeechToTextPlatform.ts → SpeechToTextPlatform.d.ts} +0 -0
  169. /package/types/generators/{SqLite.ts → SqLite.d.ts} +0 -0
  170. /package/types/generators/{Step.ts → Step.d.ts} +0 -0
  171. /package/types/generators/{Tcp.ts → Tcp.d.ts} +0 -0
  172. /package/types/generators/{TcpServer.ts → TcpServer.d.ts} +0 -0
  173. /package/types/generators/{TextToSpeechAppleBuiltin.ts → TextToSpeechAppleBuiltin.d.ts} +0 -0
  174. /package/types/generators/{TextToSpeechGgml.ts → TextToSpeechGgml.d.ts} +0 -0
  175. /package/types/generators/{TextToSpeechOnnx.ts → TextToSpeechOnnx.d.ts} +0 -0
  176. /package/types/generators/{TextToSpeechOpenAiLike.ts → TextToSpeechOpenAiLike.d.ts} +0 -0
  177. /package/types/generators/{Udp.ts → Udp.d.ts} +0 -0
  178. /package/types/generators/{VadOnnx.ts → VadOnnx.d.ts} +0 -0
  179. /package/types/generators/{VadTraditional.ts → VadTraditional.d.ts} +0 -0
  180. /package/types/generators/{VectorStore.ts → VectorStore.d.ts} +0 -0
  181. /package/types/generators/{Watchdog.ts → Watchdog.d.ts} +0 -0
  182. /package/types/generators/{WebCrawler.ts → WebCrawler.d.ts} +0 -0
  183. /package/types/generators/{WebRtc.ts → WebRtc.d.ts} +0 -0
  184. /package/types/generators/{WebSocket.ts → WebSocket.d.ts} +0 -0
  185. /package/types/generators/{index.ts → index.d.ts} +0 -0
  186. /package/types/{index.ts → index.d.ts} +0 -0
  187. /package/types/{switch.ts → switch.d.ts} +0 -0
  188. /package/types/{system.ts → system.d.ts} +0 -0
@@ -16,6 +16,13 @@ export const templateEventPropsMap = {
16
16
  Video: {
17
17
  nextVideo: { BRICK_VIDEO_NEXT_INDEX: 'number' },
18
18
  onProgress: { BRICK_VIDEO_CURRENT_TIME: 'number', BRICK_VIDEO_PLAYABLE_DURATION: 'number' },
19
+ subtitleCueEnter: {
20
+ BRICK_VIDEO_SUBTITLE_TEXT: 'string',
21
+ BRICK_VIDEO_SUBTITLE_INDEX: 'number',
22
+ BRICK_VIDEO_SUBTITLE_START: 'number',
23
+ BRICK_VIDEO_SUBTITLE_END: 'number',
24
+ },
25
+ subtitleCueExit: { BRICK_VIDEO_SUBTITLE_TEXT: 'string', BRICK_VIDEO_SUBTITLE_INDEX: 'number' },
19
26
  },
20
27
  VideoStreaming: {},
21
28
  Qrcode: {},
@@ -142,10 +149,29 @@ export const templateEventPropsMap = {
142
149
  },
143
150
  },
144
151
  Sketch: {
145
- onStrokeEnd: { BRICK_SKETCH_STROKE_COUNT: 'number' },
152
+ onStrokeEnd: { BRICK_SKETCH_STROKE_COUNT: 'number', BRICK_SKETCH_STATE: '{}' },
153
+ onClear: { BRICK_SKETCH_STATE: '{}' },
154
+ onStateChange: { BRICK_SKETCH_STATE: '{}' },
146
155
  onToolChange: { BRICK_SKETCH_TOOL: 'string' },
147
156
  onExportImage: { BRICK_SKETCH_IMAGE_URI: 'string' },
148
157
  },
158
+ Scene3D: {
159
+ onLoad: { BRICK_SCENE_3D_OBJECT_ID: 'string', BRICK_SCENE_3D_DURATION_MS: 'number' },
160
+ onLoadError: { BRICK_SCENE_3D_OBJECT_ID: 'string', BRICK_SCENE_3D_ERROR: 'string' },
161
+ onObjectClick: {
162
+ BRICK_SCENE_3D_OBJECT_ID: 'string',
163
+ BRICK_SCENE_3D_HIT_POINT: '{ x?: number y?: number z?: number }',
164
+ BRICK_SCENE_3D_HIT_DISTANCE: 'number',
165
+ },
166
+ onObjectHover: { BRICK_SCENE_3D_OBJECT_ID: 'string', BRICK_SCENE_3D_HOVER_ENTERED: 'boolean' },
167
+ onAnimationEnd: { BRICK_SCENE_3D_OBJECT_ID: 'string', BRICK_SCENE_3D_ANIMATION_NAME: 'string' },
168
+ onFrame: {
169
+ BRICK_SCENE_3D_FRAME_TIME: 'number',
170
+ BRICK_SCENE_3D_FRAME_DT: 'number',
171
+ BRICK_SCENE_3D_FPS: 'number',
172
+ },
173
+ onScriptError: { BRICK_SCENE_3D_ERROR: 'string', BRICK_SCENE_3D_PHASE: 'string' },
174
+ },
149
175
  Tick: {
150
176
  ticking: { GENERATOR_TICK_COUNTDOWN: 'number', GENERATOR_TICK_VALUE: 'any' },
151
177
  completed: { GENERATOR_TICK_COUNTDOWN: 'number', GENERATOR_TICK_VALUE: 'any' },
package/utils/id.ts CHANGED
@@ -1,80 +1,133 @@
1
1
  import { v4 as uuid } from 'uuid'
2
+ import { createHash } from 'node:crypto'
3
+ import { readFileSync } from 'node:fs'
4
+ import { join } from 'node:path'
2
5
 
3
6
  let count = 0
4
7
 
5
- // Used for snapshot mode
6
- const countUUID = () => {
7
- const current = count
8
- count += 1
9
- return `00000000-0000-0000-0000-${current.toString().padStart(12, '0')}`
8
+ type IdType =
9
+ | 'animation'
10
+ | 'brick'
11
+ | 'canvas'
12
+ | 'generator'
13
+ | 'data'
14
+ | 'switch'
15
+ | 'property_bank_command'
16
+ | 'property_bank_calc'
17
+ | 'dynamic-brick'
18
+ | 'automation_map'
19
+ | 'test'
20
+ | 'test_case'
21
+ | 'test_var'
22
+ | 'subspace'
23
+
24
+ type IdOptions = {
25
+ snapshotMode?: boolean
10
26
  }
11
27
 
12
- // Make a random id if not want to use fixed id
13
- export const makeId = (
14
- type:
15
- | 'animation'
16
- | 'brick'
17
- | 'canvas'
18
- | 'generator'
19
- | 'data'
20
- | 'switch'
21
- | 'property_bank_command'
22
- | 'property_bank_calc'
23
- | 'dynamic-brick'
24
- | 'automation_map'
25
- | 'test'
26
- | 'test_case'
27
- | 'test_var'
28
- | 'subspace',
29
- opts?: {
30
- snapshotMode?: boolean
31
- },
32
- ) => {
33
- if (type === 'subspace') {
34
- throw new Error('Currently subspace is not supported for ID generation, please use a fixed ID')
28
+ const APPLICATION_ID_FALLBACK = 'unknown-application'
29
+
30
+ const usedStableAliases = new Set<string>()
31
+ let applicationIdCache: { cwd: string; id: string } | null = null
32
+
33
+ const readApplicationId = () => {
34
+ const cwd = process.cwd()
35
+ if (applicationIdCache?.cwd === cwd) return applicationIdCache.id
36
+
37
+ let id = APPLICATION_ID_FALLBACK
38
+ try {
39
+ const app = JSON.parse(readFileSync(join(cwd, 'application.json'), 'utf8'))
40
+ if (typeof app.id === 'string' && app.id) id = app.id
41
+ } catch {
42
+ // `makeId` is also used from tests and utilities outside project roots.
43
+ }
44
+
45
+ applicationIdCache = { cwd, id }
46
+ return id
47
+ }
48
+
49
+ const hashToRandomBytes = (parts: string[]) => {
50
+ const hash = createHash('sha256').update(JSON.stringify(parts)).digest()
51
+ return new Uint8Array(hash.subarray(0, 16))
52
+ }
53
+
54
+ const makeStableUuid = (type: string, alias?: string) => {
55
+ const applicationId = readApplicationId()
56
+ const seed = alias ?? String(count)
57
+ if (alias === undefined) count += 1
58
+
59
+ if (alias !== undefined) {
60
+ const aliasKey = JSON.stringify([applicationId, type, alias])
61
+ if (usedStableAliases.has(aliasKey)) {
62
+ throw new Error(`Duplicate makeId alias '${alias}' for type '${type}'`)
63
+ }
64
+ usedStableAliases.add(aliasKey)
35
65
  }
36
- let prefix = ''
66
+
67
+ return uuid({
68
+ random: hashToRandomBytes([applicationId, type, seed]),
69
+ })
70
+ }
71
+
72
+ const idPrefix = (type: IdType): string => {
37
73
  switch (type) {
38
74
  case 'animation':
39
- prefix = 'ANIMATION_'
40
- break
75
+ return 'ANIMATION_'
41
76
  case 'brick':
42
- prefix = 'BRICK_'
43
- break
77
+ return 'BRICK_'
44
78
  case 'dynamic-brick':
45
- prefix = 'DYNAMIC_BRICK_'
46
- break
79
+ return 'DYNAMIC_BRICK_'
47
80
  case 'canvas':
48
- prefix = 'CANVAS_'
49
- break
81
+ return 'CANVAS_'
50
82
  case 'generator':
51
- prefix = 'GENERATOR_'
52
- break
83
+ return 'GENERATOR_'
53
84
  case 'data':
54
- prefix = 'PROPERTY_BANK_DATA_NODE_'
55
- break
85
+ return 'PROPERTY_BANK_DATA_NODE_'
56
86
  case 'switch':
57
- prefix = 'BRICK_STATE_GROUP_'
58
- break
87
+ return 'BRICK_STATE_GROUP_'
59
88
  case 'property_bank_command':
60
- prefix = 'PROPERTY_BANK_COMMAND_NODE_'
61
- break
89
+ return 'PROPERTY_BANK_COMMAND_NODE_'
62
90
  case 'property_bank_calc':
63
- prefix = 'PROPERTY_BANK_COMMAND_MAP_'
64
- break
91
+ return 'PROPERTY_BANK_COMMAND_MAP_'
65
92
  case 'automation_map':
66
- prefix = 'AUTOMATION_MAP_'
67
- break
93
+ return 'AUTOMATION_MAP_'
68
94
  case 'test':
69
- prefix = 'TEST_'
70
- break
95
+ return 'TEST_'
71
96
  case 'test_case':
72
- prefix = 'TEST_CASE_'
73
- break
97
+ return 'TEST_CASE_'
74
98
  case 'test_var':
75
- prefix = 'TEST_VAR_'
76
- break
99
+ return 'TEST_VAR_'
77
100
  default:
101
+ return ''
102
+ }
103
+ }
104
+
105
+ // Make stable ids by default; explicit snapshotMode: false preserves the random escape hatch.
106
+ export const makeId = (type: IdType, aliasOrOpts?: string | IdOptions, opts?: IdOptions) => {
107
+ if (type === 'subspace') {
108
+ throw new Error('Currently subspace is not supported for ID generation, please use a fixed ID')
109
+ }
110
+
111
+ const alias = typeof aliasOrOpts === 'string' ? aliasOrOpts : undefined
112
+ const options = typeof aliasOrOpts === 'string' ? opts : (aliasOrOpts ?? opts)
113
+
114
+ const useCountFallback = aliasOrOpts === undefined && opts === undefined
115
+ const id =
116
+ alias !== undefined || options?.snapshotMode || useCountFallback
117
+ ? makeStableUuid(type, alias)
118
+ : uuid()
119
+ return `${idPrefix(type)}${id}`
120
+ }
121
+
122
+ // Deterministic id derived solely from a caller-supplied seed. Unlike makeId it keeps no
123
+ // global state — no incrementing counter, no alias registry — so the same (type, seed)
124
+ // always maps to the same id on every compile and in any process. Compiled artifacts seed
125
+ // their ids this way (e.g. generateCalulationMap's command nodes, seeded by their calc id +
126
+ // structural role) so unchanged source recompiles byte-identically and editing one calc
127
+ // never shifts another's ids. The seed must be unique within a single config.
128
+ export const makeSeededId = (type: IdType, seed: string) => {
129
+ if (type === 'subspace') {
130
+ throw new Error('Currently subspace is not supported for ID generation, please use a fixed ID')
78
131
  }
79
- return `${prefix}${opts?.snapshotMode ? countUUID() : uuid()}`
132
+ return `${idPrefix(type)}${uuid({ random: hashToRandomBytes([readApplicationId(), type, seed]) })}`
80
133
  }
@@ -1,156 +0,0 @@
1
- # Buttress (Remote Inference)
2
-
3
- Backend system for offloading compute-intensive AI generator tasks from BRICKS devices to more powerful machines.
4
-
5
- ## Purpose
6
-
7
- When mobile devices or embedded systems lack hardware for local AI inference (LLM, speech-to-text), Buttress transparently delegates work to a server with appropriate resources (GPU).
8
-
9
- ## How It Works
10
-
11
- 1. **Capability Exchange**: Client and server share hardware capabilities
12
- 2. **Strategy Selection**: System decides local vs. remote execution
13
- 3. **Transparent Offloading**: Generator operates same way, execution happens remotely
14
-
15
- ## Supported Generators
16
-
17
- - LLM (GGML) (LlmMlx.ts) - Local Large Language Model inference with GGML
18
- - LLM (MLX) (LlmGgml.ts) - Local Large Language Model inference with MLX
19
- - Speech-to-Text (GGML) (SpeechToTextGgml.ts) - Local Speech-to-Text inference with GGML
20
-
21
- ## Client Configuration
22
-
23
- In generator properties, configure Buttress settings:
24
-
25
- | Setting | Description |
26
- |---------|-------------|
27
- | `Enabled` | Toggle Buttress offloading |
28
- | `URL` | Buttress server URL (e.g., `http://192.168.1.100:2080`) |
29
- | `Fallback Type` | Action if Buttress unavailable: `use-local` or `no-op` |
30
- | `Strategy` | Execution preference |
31
-
32
- ### Strategy Options
33
-
34
- | Strategy | Description |
35
- |----------|-------------|
36
- | `prefer-local` | Use local if capable, fallback to Buttress |
37
- | `prefer-buttress` | Use Buttress if available, fallback to local |
38
- | `prefer-best` | Auto-select based on capability comparison |
39
-
40
- ## Generator Configuration Example
41
-
42
- ```typescript
43
- import { makeId } from 'bricks-ctor'
44
-
45
- const llmGenerator: GeneratorLLM = {
46
- __typename: 'Generator',
47
- templateKey: 'GENERATOR_LLM',
48
- id: makeId('generator'),
49
- title: 'Chat LLM',
50
- description: '',
51
- property: {
52
- modelUrl: 'https://huggingface.co/ggml-org/gemma-3-12b-it-qat-GGUF/resolve/main/gemma-3-12b-it-qat-q4_0.gguf',
53
- contextSize: 8192,
54
- buttressConnectionSettings: {
55
- enabled: true,
56
- url: 'http://192.168.1.100:2080',
57
- fallbackType: 'use-local',
58
- strategy: 'prefer-best',
59
- },
60
- },
61
- events: {},
62
- switches: [],
63
- }
64
- ```
65
-
66
- ## Server Setup
67
-
68
- ### Requirements
69
- - [Bun](https://bun.sh) v1.3+
70
- - GPU recommended for LLM/STT
71
-
72
- ### Installation
73
-
74
- ```bash
75
- bun add -g @fugood/buttress-server
76
- ```
77
-
78
- ### Start Server
79
-
80
- ```bash
81
- bricks-buttress
82
- # or with config
83
- bricks-buttress --config ./config.toml
84
- ```
85
-
86
- ### CLI Options
87
-
88
- | Option | Description |
89
- |--------|-------------|
90
- | `-p, --port` | Port (default: 2080) |
91
- | `-c, --config` | TOML config file path |
92
- | `-v, --version` | Show version |
93
- | `-h, --help` | Show help |
94
-
95
- ### Environment Variables
96
-
97
- | Variable | Description |
98
- |----------|-------------|
99
- | `HF_TOKEN` | Hugging Face token for model downloads |
100
- | `ENABLE_OPENAI_COMPAT_ENDPOINT` | Set to `1` for OpenAI-compatible API |
101
-
102
- ## Server Configuration (TOML)
103
-
104
- ```toml
105
- [server]
106
- port = 2080
107
-
108
- [runtime]
109
- cache_dir = "./.buttress-cache"
110
- n_threads = 6
111
- flash_attn_type = "on"
112
- cache_type_k = "q8_0"
113
- cache_type_v = "q8_0"
114
-
115
- # LLM Generator
116
- [[generators]]
117
- type = "ggml-llm"
118
- [generators.backend]
119
- variant_preference = ["cuda", "vulkan", "default"]
120
- gpu_memory_fraction = 0.95
121
- [generators.model]
122
- repo_id = "ggml-org/gemma-3-12b-it-qat-GGUF"
123
- download = true
124
- n_ctx = 8192
125
-
126
- # STT Generator
127
- [[generators]]
128
- type = "ggml-stt"
129
- [generators.backend]
130
- variant_preference = ["cuda", "vulkan", "default"]
131
- [generators.model]
132
- repo_id = "BricksDisplay/whisper-ggml"
133
- filename = "ggml-small-q8_0.bin"
134
- download = true
135
- use_gpu = true
136
- ```
137
-
138
- ## Use Cases
139
-
140
- ### Resource-Constrained Devices
141
- Digital signage with basic hardware offloads LLM to powerful server.
142
-
143
- ### Shared GPU Resources
144
- Multiple devices share single GPU server for inference.
145
-
146
- ### Development Testing
147
- Test AI features on lightweight dev machines by connecting to beefy server.
148
-
149
- ## Best Practices
150
-
151
- 1. **Network reliability**: Ensure stable LAN connection to Buttress server
152
- 2. **Fallback strategy**: Configure appropriate fallback for critical features
153
- 3. **Server monitoring**: Monitor Buttress server resource usage
154
- 4. **Model consistency**: Ensure client and server use compatible models
155
- 5. **Security**: Run Buttress on private network, not public internet
156
- 6. **Latency awareness**: Account for network latency in UX design
@@ -1,209 +0,0 @@
1
- # Data Calculation (JS Sandbox)
2
-
3
- Transform and compute Data Bank values using JavaScript scripts.
4
-
5
- ## DataCalculationScript
6
-
7
- JavaScript code executed in a sandbox with access to inputs and outputs.
8
-
9
- ```typescript
10
- import { makeId } from 'bricks-ctor'
11
-
12
- const calculation: DataCalculationScript = {
13
- __typename: 'DataCalculationScript',
14
- id: makeId('property_bank_calc'),
15
- title: 'Format Price',
16
- description: 'Formats price with currency symbol',
17
- note: '',
18
- triggerMode: 'auto', // 'auto' | 'manual'
19
- enableAsync: false,
20
- // Inline code
21
- code: `
22
- const price = inputs.price || 0
23
- const currency = inputs.currency || 'USD'
24
- return new Intl.NumberFormat('en-US', {
25
- style: 'currency',
26
- currency,
27
- }).format(price)
28
- `,
29
- // Or load from file (preferred for longer scripts)
30
- // import { readFile } from 'node:fs/promises'
31
- // code: await readFile(new URL('./format-price.sandbox.js', import.meta.url), 'utf8'),
32
- inputs: [
33
- { key: 'price', data: () => priceData, trigger: true },
34
- { key: 'currency', data: () => currencyData, trigger: false },
35
- ],
36
- output: () => formattedPriceData,
37
- outputs: [], // Additional named outputs
38
- error: null, // or () => errorData for error handling
39
- }
40
- ```
41
-
42
- ## Trigger Modes
43
-
44
- | Mode | Description |
45
- |------|-------------|
46
- | `auto` | Run when input values change (with trigger: true) |
47
- | `manual` | Only run via `PROPERTY_BANK_COMMAND` action |
48
-
49
- Use `manual` to prevent circular dependencies or for explicit control.
50
-
51
- ## Script Sandbox Features
52
-
53
- Scripts run in `use strict` mode with a sandboxed set of globals and libraries.
54
-
55
- ### Built-in Globals
56
-
57
- | Global | Description |
58
- |--------|-------------|
59
- | `inputs` | Object with input values |
60
- | `console` | `{ log, error, warn, info }` for debugging |
61
- | `Platform` | `{ OS, isTV, isPad, isVision, isElectron }` |
62
- | `TextEncoder`, `TextDecoder` | Text encoding/decoding |
63
- | `Buffer` | Node.js Buffer (without `allocUnsafe`) |
64
- | `btoa`, `atob` | Base64 encoding/decoding |
65
-
66
- ### Available Libraries
67
-
68
- **Utility**
69
- | Library | Global | Description |
70
- |---------|--------|-------------|
71
- | [lodash](https://lodash.com) | `_`, `lodash` | Utility (sync: no debounce/delay/defer) |
72
- | [voca](https://vocajs.com) | `voca` | String manipulation |
73
- | [invariant](https://github.com/zertosh/invariant) | `invariant` | Assertions |
74
-
75
- **Data & Encoding**
76
- | Library | Global | Description |
77
- |---------|--------|-------------|
78
- | [json5](https://github.com/json5/json5) | `json5` | JSON5 parsing |
79
- | [qs](https://github.com/ljharb/qs) | `qs` | Query string parsing |
80
- | [url](https://github.com/defunctzombie/node-url) | `url` | URL parsing |
81
- | [bytes](https://github.com/visionmedia/bytes.js) | `bytes` | Byte parsing/formatting |
82
- | [ms](https://github.com/vercel/ms) | `ms` | Millisecond conversion |
83
- | [base45](https://github.com/irony/base45) | `base45` | Base45 encoding |
84
- | [iconv-lite](https://github.com/ashtuchkin/iconv-lite) | `iconv` | Character encoding |
85
-
86
- **Math & Color**
87
- | Library | Global | Description |
88
- |---------|--------|-------------|
89
- | [mathjs](https://mathjs.org) | `math`, `mathjs` | Math library |
90
- | [chroma-js](https://gka.github.io/chroma.js) | `chroma` | Color manipulation |
91
-
92
- **Date/Time**
93
- | Library | Global | Description |
94
- |---------|--------|-------------|
95
- | [moment](https://momentjs.com) | `moment` | Date/time (auto parseFormat) |
96
-
97
- **ID & Hash**
98
- | Library | Global | Description |
99
- |---------|--------|-------------|
100
- | [nanoid](https://github.com/ai/nanoid) | `nanoid` | Unique ID generation |
101
- | [md5](https://github.com/pvorb/node-md5) | `md5` | MD5 hashing |
102
-
103
- **Crypto**
104
- | Library | Global | Description |
105
- |---------|--------|-------------|
106
- | [crypto-browserify](https://github.com/crypto-browserify/crypto-browserify) | `crypto` | Crypto functions |
107
- | [jsrsasign](https://github.com/kjur/jsrsasign) | `kjurJWS` | JWT/JWS signing |
108
- | [cose-js](https://github.com/erdtman/COSE-JS) | `coseVerify` | COSE verification (sync) |
109
-
110
- **Compression**
111
- | Library | Global | Description |
112
- |---------|--------|-------------|
113
- | [fflate](https://github.com/101arrowz/fflate) | `fflate` | `{ zlibSync, unzlibSync, gzipSync, gunzipSync, compressSync, decompressSync, strFromU8 }` |
114
- | [cbor](https://github.com/hildjj/node-cbor) | `cbor` | `{ encode, decode, decodeFirstSync, decodeAllSync }` |
115
-
116
- **File & Document**
117
- | Library | Global | Description |
118
- |---------|--------|-------------|
119
- | fs | `fs` | File system (limited, no download/upload) |
120
- | [officeparser](https://github.com/nicktang) | `parseDocument` | Office document parsing (async) |
121
- | [turndown](https://github.com/mixmark-io/turndown) | `TurndownService` | HTML to Markdown |
122
- | [opencc-js](https://github.com/nk2028/opencc-js) | `OpenCC` | Chinese conversion `{ Converter, ConverterFactory, CustomConverter, Locale }` |
123
- | [toon-format](https://github.com/nicktang) | `TOON` | TOON format parsing |
124
-
125
- ### Runtime Environment
126
-
127
- | Platform | Engine |
128
- |----------|--------|
129
- | Android | Hermes engine sandbox |
130
- | iOS | JavaScriptCore sandbox |
131
-
132
- ### Async Mode
133
-
134
- Enable `enableAsync: true` to unlock additional capabilities:
135
-
136
- **Additional async globals:**
137
- - `Promise`, `setTimeout`, `setInterval`, `setImmediate`
138
- - `clearTimeout`, `clearInterval`, `clearImmediate`
139
- - `requestAnimationFrame`
140
- - Full lodash (including `debounce`, `delay`, `defer`)
141
-
142
- ```typescript
143
- code: `
144
- const result = await new Promise((resolve) => {
145
- setTimeout(() => resolve(inputs.value * 2), 100)
146
- })
147
- return result
148
- `,
149
- enableAsync: true,
150
- ```
151
-
152
- ### Multiple Outputs
153
-
154
- ```typescript
155
- outputs: [
156
- { key: 'total', data: () => totalData },
157
- { key: 'tax', data: () => taxData },
158
- { key: 'subtotal', data: () => subtotalData },
159
- ],
160
- code: `
161
- const subtotal = inputs.price * inputs.quantity
162
- const tax = subtotal * 0.1
163
- const total = subtotal + tax
164
- return { total, tax, subtotal }
165
- `,
166
- ```
167
-
168
- ## Triggering Manually
169
-
170
- Use `PROPERTY_BANK_COMMAND` system action to trigger a manual calculation:
171
-
172
- ```typescript
173
- const triggerCalc: EventAction = {
174
- handler: 'system',
175
- action: {
176
- __actionName: 'PROPERTY_BANK_COMMAND',
177
- parent: 'System',
178
- dataParams: [
179
- { input: () => computeTotalCalc }, // Reference to DataCalculation
180
- ],
181
- },
182
- }
183
- ```
184
-
185
- ## Best Practices
186
-
187
- 1. **Avoid circular deps**: Set non-triggering inputs (`trigger: false`) or use `manual` mode
188
- 2. **Error handling**: Always set `error` output for scripts that might fail
189
- 3. **Keep scripts pure**: Avoid side effects, return computed values
190
- 4. **Debounce rapid updates**: Use `manual` mode + timer for high-frequency inputs
191
-
192
- ## Anti-Patterns (AVOID)
193
-
194
- See [Architecture Patterns](architecture-patterns.md) for the full pattern selection guide.
195
-
196
- ### Using Data Calc as an orchestrator
197
- Scripts that manage state machines, control UI flow, or coordinate multi-step processes belong in Event Action Chains, not here.
198
-
199
- **Symptom**: Script has if/else branches deciding "what happens next" or tracks "current step".
200
-
201
- ### Quick reference
202
-
203
- | If you need to... | Use instead |
204
- |---|---|
205
- | Call an LLM / AI model | Generator (Assistant, LLM, HTTP) |
206
- | Sequence multiple actions | Event Action Chain |
207
- | Set a data value directly | PROPERTY_BANK system action |
208
- | Compute a simple expression | PROPERTY_BANK_EXPRESSION |
209
- | Transform/format/parse data | Data Calculation (correct use) |