@fugood/bricks-project 2.23.0-beta.5 → 2.23.0-beta.50

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 (99) hide show
  1. package/api/instance.ts +37 -5
  2. package/compile/action-name-map.ts +82 -0
  3. package/compile/index.ts +54 -60
  4. package/compile/util.ts +13 -4
  5. package/package.json +4 -4
  6. package/tools/deploy.ts +33 -2
  7. package/tools/mcp-server.ts +3 -3
  8. package/tools/postinstall.ts +2 -11
  9. package/tools/preview.ts +1 -1
  10. package/tools/pull.ts +2 -2
  11. package/types/brick-base.ts +1 -0
  12. package/types/bricks/Camera.ts +26 -10
  13. package/types/bricks/Chart.ts +1 -0
  14. package/types/bricks/GenerativeMedia.ts +21 -3
  15. package/types/bricks/Icon.ts +1 -0
  16. package/types/bricks/Image.ts +1 -0
  17. package/types/bricks/Items.ts +1 -0
  18. package/types/bricks/Lottie.ts +1 -0
  19. package/types/bricks/Maps.ts +254 -0
  20. package/types/bricks/QrCode.ts +1 -0
  21. package/types/bricks/Rect.ts +1 -0
  22. package/types/bricks/RichText.ts +1 -0
  23. package/types/bricks/Rive.ts +1 -0
  24. package/types/bricks/Slideshow.ts +38 -2
  25. package/types/bricks/Svg.ts +1 -0
  26. package/types/bricks/Text.ts +1 -0
  27. package/types/bricks/TextInput.ts +1 -0
  28. package/types/bricks/Video.ts +1 -0
  29. package/types/bricks/VideoStreaming.ts +1 -0
  30. package/types/bricks/WebRtcStream.ts +1 -0
  31. package/types/bricks/WebView.ts +8 -1
  32. package/types/bricks/index.ts +2 -0
  33. package/types/canvas.ts +1 -0
  34. package/types/data-calc-command.ts +7003 -0
  35. package/types/data-calc-script.ts +21 -0
  36. package/types/data-calc.ts +3 -6977
  37. package/types/data.ts +3 -0
  38. package/types/generators/AlarmClock.ts +2 -0
  39. package/types/generators/Assistant.ts +30 -6
  40. package/types/generators/BleCentral.ts +2 -0
  41. package/types/generators/BlePeripheral.ts +2 -0
  42. package/types/generators/CanvasMap.ts +2 -0
  43. package/types/generators/CastlesPay.ts +2 -0
  44. package/types/generators/DataBank.ts +2 -0
  45. package/types/generators/File.ts +2 -0
  46. package/types/generators/GraphQl.ts +2 -0
  47. package/types/generators/Http.ts +84 -2
  48. package/types/generators/HttpServer.ts +5 -1
  49. package/types/generators/Information.ts +2 -0
  50. package/types/generators/Intent.ts +51 -0
  51. package/types/generators/Iterator.ts +11 -2
  52. package/types/generators/Keyboard.ts +2 -0
  53. package/types/generators/LlmAnthropicCompat.ts +2 -0
  54. package/types/generators/LlmAppleBuiltin.ts +144 -0
  55. package/types/generators/LlmGgml.ts +23 -5
  56. package/types/generators/LlmOnnx.ts +9 -0
  57. package/types/generators/LlmOpenAiCompat.ts +2 -0
  58. package/types/generators/LlmQualcommAiEngine.ts +2 -0
  59. package/types/generators/Mcp.ts +6 -4
  60. package/types/generators/McpServer.ts +8 -6
  61. package/types/generators/MediaFlow.ts +2 -0
  62. package/types/generators/MqttBroker.ts +2 -0
  63. package/types/generators/MqttClient.ts +2 -0
  64. package/types/generators/Question.ts +9 -0
  65. package/types/generators/RealtimeTranscription.ts +4 -2
  66. package/types/generators/RerankerGgml.ts +23 -16
  67. package/types/generators/SerialPort.ts +2 -0
  68. package/types/generators/SoundPlayer.ts +2 -0
  69. package/types/generators/SoundRecorder.ts +2 -0
  70. package/types/generators/SpeechToTextGgml.ts +14 -4
  71. package/types/generators/SpeechToTextOnnx.ts +2 -0
  72. package/types/generators/SpeechToTextPlatform.ts +2 -0
  73. package/types/generators/SqLite.ts +32 -1
  74. package/types/generators/Step.ts +2 -0
  75. package/types/generators/SttAppleBuiltin.ts +117 -0
  76. package/types/generators/Tcp.ts +2 -0
  77. package/types/generators/TcpServer.ts +5 -1
  78. package/types/generators/TextToSpeechApple.ts +113 -0
  79. package/types/generators/TextToSpeechAppleBuiltin.ts +114 -0
  80. package/types/generators/TextToSpeechGgml.ts +24 -3
  81. package/types/generators/TextToSpeechOnnx.ts +2 -0
  82. package/types/generators/TextToSpeechOpenAiLike.ts +2 -0
  83. package/types/generators/ThermalPrinter.ts +2 -0
  84. package/types/generators/Tick.ts +5 -1
  85. package/types/generators/TtsAppleBuiltin.ts +105 -0
  86. package/types/generators/Udp.ts +2 -0
  87. package/types/generators/VadGgml.ts +4 -2
  88. package/types/generators/VectorStore.ts +15 -2
  89. package/types/generators/Watchdog.ts +2 -0
  90. package/types/generators/WebCrawler.ts +2 -0
  91. package/types/generators/WebRtc.ts +4 -2
  92. package/types/generators/WebSocket.ts +2 -0
  93. package/types/generators/index.ts +3 -0
  94. package/types/index.ts +2 -0
  95. package/types/system.ts +43 -6
  96. package/utils/calc.ts +5 -1
  97. package/utils/data.ts +1 -0
  98. package/utils/event-props.ts +90 -2
  99. package/utils/id.ts +3 -1
package/api/instance.ts CHANGED
@@ -66,17 +66,31 @@ export const deployApp = async (
66
66
  appId: string,
67
67
  config: Config,
68
68
  lastCommitId?: string,
69
+ changelogs?: string,
70
+ version?: string,
69
71
  ) => {
70
72
  const app = await pullApp(stage, appId)
71
73
  if (app.config?.bricks_project_last_commit_id === lastCommitId)
72
74
  throw new Error('No changes to deploy')
73
75
 
76
+ const versionName = version || app.name || 'Untitled'
77
+ const releaseNote = changelogs
78
+ ? `${changelogs}\n\nRelease by BRICKS Project`
79
+ : 'Release by BRICKS Project'
80
+
74
81
  const { errors } = await doGQL(
75
82
  stage,
76
- `mutation BRICKS_PROJECT_updateApplication($id: ID!, $config: String) {
83
+ `mutation BRICKS_PROJECT_releaseApplication(
84
+ $id: ID!,
85
+ $config: String,
86
+ $releaseCurrentVersion: String,
87
+ $releaseCurrentVersionNote: String
88
+ ) {
77
89
  updateApplication(
78
90
  id: $id,
79
- config: $config
91
+ config: $config,
92
+ releaseCurrentVersion: $releaseCurrentVersion,
93
+ releaseCurrentVersionNote: $releaseCurrentVersionNote
80
94
  ) {
81
95
  _id
82
96
  name
@@ -86,9 +100,11 @@ export const deployApp = async (
86
100
  id: appId,
87
101
  config: JSON.stringify({
88
102
  ...config,
89
- title: `${config.title || app.name || 'Untitled'} (${Date.now()})`,
103
+ title: versionName,
90
104
  bricks_project_last_commit_id: lastCommitId,
91
105
  }),
106
+ releaseCurrentVersion: versionName,
107
+ releaseCurrentVersionNote: releaseNote,
92
108
  },
93
109
  )
94
110
  if (errors) throw new Error(errors[0].message)
@@ -137,18 +153,32 @@ export const deployModule = async (
137
153
  modId: string,
138
154
  config: Config,
139
155
  lastCommitId?: string,
156
+ changelogs?: string,
157
+ version?: string,
140
158
  ) => {
141
159
  const mod = await pullModule(stage, modId)
142
160
  if (mod.config?.bricks_project_last_commit_id === lastCommitId)
143
161
  throw new Error('No changes to deploy')
144
162
 
163
+ const versionName = version || mod.name || 'Untitled'
164
+ const releaseNote = changelogs
165
+ ? `${changelogs}\n\nRelease by BRICKS Project`
166
+ : 'Release by BRICKS Project'
167
+
145
168
  const { errors } = await doGQL(
146
169
  stage,
147
- `mutation BRICKS_PROJECT_updateModule($id: ID!, $config: String) {
170
+ `mutation BRICKS_PROJECT_releaseModule(
171
+ $id: ID!,
172
+ $config: String,
173
+ $releaseCurrentVersion: String,
174
+ $releaseCurrentVersionNote: String
175
+ ) {
148
176
  updateModule(
149
177
  id: $id
150
178
  config: $config
151
179
  validateConfig: true
180
+ releaseCurrentVersion: $releaseCurrentVersion
181
+ releaseCurrentVersionNote: $releaseCurrentVersionNote
152
182
  ) {
153
183
  _id
154
184
  name
@@ -158,9 +188,11 @@ export const deployModule = async (
158
188
  id: modId,
159
189
  config: JSON.stringify({
160
190
  ...config,
161
- title: `${config.title || mod.name || 'Untitled'} (${Date.now()})`,
191
+ title: versionName,
162
192
  bricks_project_last_commit_id: lastCommitId,
163
193
  }),
194
+ releaseCurrentVersion: versionName,
195
+ releaseCurrentVersionNote: releaseNote,
164
196
  },
165
197
  )
166
198
  if (errors) throw new Error(errors[0].message)
@@ -1,3 +1,5 @@
1
+ /* Auto generated by build script */
2
+
1
3
  // NOTE: The action parameter name convertion is not 1:1 mapping case conversion, so we need to define the mapping here
2
4
  // This may be improved in the future
3
5
  export const templateActionNameMap = {
@@ -302,6 +304,28 @@ export const templateActionNameMap = {
302
304
  maxDuration: 'BRICK_CAMERA_MAX_DURATION',
303
305
  maxFileSize: 'BRICK_CAMERA_MAX_FILE_SIZE',
304
306
  },
307
+ BRICK_CAMERA_FOCUS: {
308
+ focusX: 'BRICK_CAMERA_FOCUS_X',
309
+ focusY: 'BRICK_CAMERA_FOCUS_Y',
310
+ },
311
+ },
312
+
313
+ BRICK_MAPS: {
314
+ BRICK_MAPS_PAN: {
315
+ panDirection: 'BRICK_MAPS_PAN_DIRECTION',
316
+ },
317
+ BRICK_MAPS_NAVIGATE_TO: {
318
+ targetLatitude: 'BRICK_MAPS_TARGET_LATITUDE',
319
+ targetLongitude: 'BRICK_MAPS_TARGET_LONGITUDE',
320
+ targetZoom: 'BRICK_MAPS_TARGET_ZOOM',
321
+ },
322
+ BRICK_MAPS_FOCUS_MARKER: {
323
+ markerId: 'BRICK_MAPS_MARKER_ID',
324
+ },
325
+ BRICK_MAPS_FIT_TO_MARKERS: {
326
+ edgePadding: 'BRICK_MAPS_EDGE_PADDING',
327
+ animated: 'BRICK_MAPS_ANIMATED',
328
+ },
305
329
  },
306
330
 
307
331
  GENERATOR_FILE: {
@@ -357,6 +381,23 @@ export const templateActionNameMap = {
357
381
  variables: 'GENERATOR_GRAPHQL_VARIABLES',
358
382
  },
359
383
  },
384
+ GENERATOR_HTTP: {
385
+ GENERATOR_HTTP_RUN_REQUEST: {
386
+ url: 'GENERATOR_HTTP_URL',
387
+ method: 'GENERATOR_HTTP_METHOD',
388
+ headers: 'GENERATOR_HTTP_HEADERS',
389
+ body: 'GENERATOR_HTTP_BODY',
390
+ timeout: 'GENERATOR_HTTP_TIMEOUT',
391
+ mode: 'GENERATOR_HTTP_MODE',
392
+ credentials: 'GENERATOR_HTTP_CREDENTIALS',
393
+ redirect: 'GENERATOR_HTTP_REDIRECT',
394
+ referrer: 'GENERATOR_HTTP_REFERRER',
395
+ resType: 'GENERATOR_HTTP_RES_TYPE',
396
+ resSelector: 'GENERATOR_HTTP_RES_SELECTOR',
397
+ eventStream: 'GENERATOR_HTTP_EVENT_STREAM',
398
+ eventName: 'GENERATOR_HTTP_EVENT_NAME',
399
+ },
400
+ },
360
401
 
361
402
  GENERATOR_WEB_SOCKET: {
362
403
  GENERATOR_WEB_SOCKET_EMIT: {
@@ -484,6 +525,16 @@ export const templateActionNameMap = {
484
525
  packageName: 'GENERATOR_INTENT_PACKAGE_NAME',
485
526
  category: 'GENERATOR_INTENT_CATEGORY',
486
527
  },
528
+ GENERATOR_INTENT_START_SERVICE: {
529
+ action: 'GENERATOR_INTENT_ACTION',
530
+ data: 'GENERATOR_INTENT_DATA',
531
+ type: 'GENERATOR_INTENT_TYPE',
532
+ extra: 'GENERATOR_INTENT_EXTRA',
533
+ className: 'GENERATOR_INTENT_CLASS_NAME',
534
+ packageName: 'GENERATOR_INTENT_PACKAGE_NAME',
535
+ category: 'GENERATOR_INTENT_CATEGORY',
536
+ foreground: 'GENERATOR_INTENT_FOREGROUND',
537
+ },
487
538
  },
488
539
  GENERATOR_CASTLES_PAY: {
489
540
  GENERATOR_CASTLES_PAY_SALE: {
@@ -512,6 +563,13 @@ export const templateActionNameMap = {
512
563
  params: 'GENERATOR_SQLITE_PARAMS',
513
564
  paramsString: 'GENERATOR_SQLITE_PARAMS_STRING',
514
565
  },
566
+ GENERATOR_SQLITE_TRANSACTION: {
567
+ statements: 'GENERATOR_SQLITE_STATEMENTS',
568
+ },
569
+ GENERATOR_SQLITE_BATCH_EXECUTE: {
570
+ sql: 'GENERATOR_SQLITE_SQL',
571
+ batchParams: 'GENERATOR_SQLITE_BATCH_PARAMS',
572
+ },
515
573
  },
516
574
 
517
575
  GENERATOR_MCP: {
@@ -553,6 +611,7 @@ export const templateActionNameMap = {
553
611
  prompt: 'GENERATOR_ONNX_LLM_PROMPT',
554
612
  chat: 'GENERATOR_ONNX_LLM_CHAT',
555
613
  images: 'GENERATOR_ONNX_LLM_IMAGES',
614
+ audios: 'GENERATOR_ONNX_LLM_AUDIOS',
556
615
  tools: 'GENERATOR_ONNX_LLM_TOOLS',
557
616
  toolChoice: 'GENERATOR_ONNX_LLM_TOOL_CHOICE',
558
617
  },
@@ -746,6 +805,29 @@ export const templateActionNameMap = {
746
805
  toolChoice: 'GENERATOR_ANTHROPIC_LLM_TOOL_CHOICE',
747
806
  },
748
807
  },
808
+ GENERATOR_APPLE_LLM: {
809
+ GENERATOR_APPLE_LLM_COMPLETION: {
810
+ messages: 'GENERATOR_APPLE_LLM_MESSAGES',
811
+ maxTokens: 'GENERATOR_APPLE_LLM_MAX_TOKENS',
812
+ temperature: 'GENERATOR_APPLE_LLM_TEMPERATURE',
813
+ topP: 'GENERATOR_APPLE_LLM_TOP_P',
814
+ },
815
+ },
816
+ GENERATOR_APPLE_STT: {
817
+ GENERATOR_APPLE_STT_TRANSCRIBE_FILE: {
818
+ fileUrl: 'GENERATOR_APPLE_STT_FILE_URL',
819
+ language: 'GENERATOR_APPLE_STT_LANGUAGE',
820
+ },
821
+ GENERATOR_APPLE_STT_TRANSCRIBE_DATA: {
822
+ data: 'GENERATOR_APPLE_STT_DATA',
823
+ language: 'GENERATOR_APPLE_STT_LANGUAGE',
824
+ },
825
+ },
826
+ GENERATOR_APPLE_TTS: {
827
+ GENERATOR_APPLE_TTS_GENERATE: {
828
+ text: 'GENERATOR_APPLE_TTS_TEXT',
829
+ },
830
+ },
749
831
  GENERATOR_ASSISTANT: {
750
832
  GENERATOR_ASSISTANT_ADD_MESSAGE: {
751
833
  role: 'GENERATOR_ASSISTANT_ROLE',
package/compile/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /* eslint-disable no-underscore-dangle -- Uses __typename, __actionName, etc. for type system */
1
2
  import _ from 'lodash'
2
3
  import { parse as parseAST } from 'acorn'
3
4
  import type { ExportNamedDeclaration, FunctionDeclaration } from 'acorn'
@@ -12,7 +13,6 @@ import type {
12
13
  Animation,
13
14
  AnimationDef,
14
15
  AnimationComposeDef,
15
- EventAction,
16
16
  ActionWithDataParams,
17
17
  ActionWithParams,
18
18
  BrickItems,
@@ -24,10 +24,8 @@ import type {
24
24
  DataCalculationData,
25
25
  DataCommand,
26
26
  Brick,
27
- Generator,
28
27
  Canvas,
29
28
  Subspace,
30
- EventActionForItem,
31
29
  } from '../types'
32
30
 
33
31
  const compileProperty = (property, errorReference: string, result = {}) => {
@@ -66,25 +64,22 @@ const compileEventActionValue = (templateKey, eventKey, value, errorReference) =
66
64
  return compileProperty(value, errorReference)
67
65
  }
68
66
 
69
- const convertOutletKey = (templateKey: string, key: string) => {
70
- return `${templateKey}_${_.snakeCase(key).toUpperCase()}`
71
- }
67
+ const convertOutletKey = (templateKey: string, key: string) =>
68
+ `${templateKey}_${_.snakeCase(key).toUpperCase()}`
72
69
 
73
70
  const compileOutlets = (
74
71
  templateKey: string,
75
72
  outlets: { [key: string]: () => Data },
76
73
  errorReference: string,
77
- ) => {
78
- return Object.entries(outlets).reduce((acc, [key, data]) => {
74
+ ) =>
75
+ Object.entries(outlets).reduce((acc, [key, data]) => {
79
76
  if (!data()?.id) throw new Error(`Invalid data reference ${errorReference}`)
80
77
  acc[convertOutletKey(templateKey, key)] = data().id
81
78
  return acc
82
79
  }, {})
83
- }
84
80
 
85
- const convertEventKey = (templateKey: string, key: string) => {
86
- return `${templateKey ? `${templateKey}_` : ''}${_.snakeCase(key).toUpperCase()}`
87
- }
81
+ const convertEventKey = (templateKey: string, key: string) =>
82
+ `${templateKey ? `${templateKey}_` : ''}${_.snakeCase(key).toUpperCase()}`
88
83
 
89
84
  const basicAnimationEvents = ['show', 'standby', 'breatheStart']
90
85
 
@@ -92,14 +87,13 @@ const compileAnimations = (
92
87
  templateKey: string,
93
88
  animations: { [key: string]: Animation },
94
89
  errorReference: string,
95
- ) => {
96
- return Object.entries(animations).reduce((acc, [key, animation]) => {
90
+ ) =>
91
+ Object.entries(animations).reduce((acc, [key, animation]) => {
97
92
  if (!animation?.id) throw new Error(`Invalid animation reference ${errorReference}`)
98
93
  acc[convertEventKey(basicAnimationEvents.includes(key) ? 'BRICK' : templateKey, key)] =
99
94
  `ANIMATION#${animation.id}`
100
95
  return acc
101
96
  }, {})
102
- }
103
97
 
104
98
  const compileActionParam = (templateKey: string, actionName: string, paramName: string) =>
105
99
  templateActionNameMap[templateKey]?.[actionName]?.[paramName] || paramName
@@ -190,7 +184,7 @@ const compileSwitchConds = (templateKey, conds, errorReference) =>
190
184
  result.key = cond.data().id
191
185
  result.value = cond.value
192
186
  } else if (item.cond.__typename === 'SwitchCondInnerStateOutlet') {
193
- const cond = item.cond
187
+ const { cond } = item
194
188
  result.type = 'inner_state'
195
189
  result.key = convertOutletKey(templateKey, cond.outlet)
196
190
  result.value = cond.value
@@ -205,35 +199,33 @@ const compileSwitchConds = (templateKey, conds, errorReference) =>
205
199
  return result
206
200
  })
207
201
 
208
- const compileApplicationSettings = (settings: Application['settings']) => {
209
- return {
210
- internet_reachability_url: settings?.internetReachabilityUrl,
211
- enable_data_lock: settings?.enableDataLock,
212
- show_deprecated_features: settings?.showDeprecatedFeatures,
213
- enable_unstable_bricks: settings?.enableUnstableFeatures,
214
- runtime_cache_options: settings?.runtimeCacheOptions
215
- ? {
216
- disabled: settings.runtimeCacheOptions.disabled,
217
- behavior: settings.runtimeCacheOptions.behavior,
218
- retry_attempt_for_failure: settings.runtimeCacheOptions.retryAttemptForFailure,
219
- }
220
- : undefined,
221
- tv_options: settings?.tvOptions
222
- ? {
223
- disabled_selectable: settings.tvOptions.disabledSelectable,
224
- selectable_color: settings.tvOptions.selectableColor,
225
- selectable_border: settings.tvOptions.selectableBorder,
226
- }
227
- : undefined,
228
- ai: settings?.ai
229
- ? {
230
- use_anthropic_api_key_system_data: settings.ai.useAnthropicApiKeySystemData,
231
- use_openai_api_key_system_data: settings.ai.useOpenAiApiKeySystemData,
232
- use_gemini_api_key_system_data: settings.ai.useGeminiApiKeySystemData,
233
- }
234
- : undefined,
235
- }
236
- }
202
+ const compileApplicationSettings = (settings: Application['settings']) => ({
203
+ internet_reachability_url: settings?.internetReachabilityUrl,
204
+ enable_data_lock: settings?.enableDataLock,
205
+ show_deprecated_features: settings?.showDeprecatedFeatures,
206
+ enable_unstable_bricks: settings?.enableUnstableFeatures,
207
+ runtime_cache_options: settings?.runtimeCacheOptions
208
+ ? {
209
+ disabled: settings.runtimeCacheOptions.disabled,
210
+ behavior: settings.runtimeCacheOptions.behavior,
211
+ retry_attempt_for_failure: settings.runtimeCacheOptions.retryAttemptForFailure,
212
+ }
213
+ : undefined,
214
+ tv_options: settings?.tvOptions
215
+ ? {
216
+ disabled_selectable: settings.tvOptions.disabledSelectable,
217
+ selectable_color: settings.tvOptions.selectableColor,
218
+ selectable_border: settings.tvOptions.selectableBorder,
219
+ }
220
+ : undefined,
221
+ ai: settings?.ai
222
+ ? {
223
+ use_anthropic_api_key_system_data: settings.ai.useAnthropicApiKeySystemData,
224
+ use_openai_api_key_system_data: settings.ai.useOpenAiApiKeySystemData,
225
+ use_gemini_api_key_system_data: settings.ai.useGeminiApiKeySystemData,
226
+ }
227
+ : undefined,
228
+ })
237
229
 
238
230
  const animationTypeMap = {
239
231
  AnimationTimingConfig: 'timing',
@@ -338,7 +330,7 @@ export const compile = async (app: Application) => {
338
330
  brick: !subspace.unexpanded.brick,
339
331
  generator: !subspace.unexpanded.generator,
340
332
  canvas: subspace.unexpanded.canvas?.reduce((acc, canvas) => {
341
- acc[canvas.id] = canvas?.id ? false : true
333
+ acc[canvas.id] = !canvas?.id
342
334
  return acc
343
335
  }, {}),
344
336
  property_bank: !subspace.unexpanded.data,
@@ -377,12 +369,12 @@ export const compile = async (app: Application) => {
377
369
  animationRunType: animationDef.runType,
378
370
  compose_type: animationDef.composeType,
379
371
  item_list: animationDef.items.map((item, index) => {
380
- const animation = item()
381
- if (!animation?.id)
372
+ const innerAnimation = item()
373
+ if (!innerAnimation?.id)
382
374
  throw new Error(
383
- `Invalid animation index: ${index} (animation: ${animation.id}, subspace ${subspace.id})`,
375
+ `Invalid animation index: ${index} (animation: ${innerAnimation.id}, subspace ${subspace.id})`,
384
376
  )
385
- return { animation_id: animation.id }
377
+ return { animation_id: innerAnimation.id }
386
378
  }),
387
379
  }
388
380
  }
@@ -461,7 +453,7 @@ export const compile = async (app: Application) => {
461
453
  property.brickList = brickList
462
454
  } else {
463
455
  // Not supported Data for brickList
464
- throw new Error('Not supported Data for brickList directly')
456
+ throw new TypeError('Not supported Data for brickList directly')
465
457
  }
466
458
  if (Array.isArray(brickItems.brickDetails)) {
467
459
  const brickDetails = (brickItems.brickDetails || []).map((item, index) =>
@@ -470,7 +462,7 @@ export const compile = async (app: Application) => {
470
462
  property.brickDetails = brickDetails
471
463
  } else {
472
464
  // Not supported Data for brickList
473
- throw new Error('Not supported Data for brickList directly')
465
+ throw new TypeError('Not supported Data for brickList directly')
474
466
  }
475
467
  }
476
468
  map[brick.id] = {
@@ -677,6 +669,8 @@ export const compile = async (app: Application) => {
677
669
  camelCase: false,
678
670
  errorReference: `(data: ${data.id}, subspace ${subspace.id})`,
679
671
  }),
672
+ hit_equal: data.hit_equal,
673
+ hit_regex: data.hit_regex,
680
674
  }
681
675
  return map
682
676
  }, {}),
@@ -694,7 +688,7 @@ export const compile = async (app: Application) => {
694
688
  if (!acc[port.key]) acc[port.key] = null
695
689
 
696
690
  let sourceId
697
- let sourceNode = port.source()
691
+ const sourceNode = port.source()
698
692
  if (sourceNode?.__typename === 'DataCalculationData')
699
693
  sourceId = (sourceNode as DataCalculationData).data().id
700
694
  if (sourceNode?.__typename === 'DataCommand') sourceId = sourceNode.id
@@ -715,7 +709,7 @@ export const compile = async (app: Application) => {
715
709
  if (!acc[port.key]) acc[port.key] = null
716
710
 
717
711
  let targetId
718
- let targetNode = port.target()
712
+ const targetNode = port.target()
719
713
  if (targetNode?.__typename === 'DataCalculationData')
720
714
  targetId = (targetNode as DataCalculationData).data().id
721
715
  if (targetNode?.__typename === 'DataCommand') targetId = targetNode.id
@@ -770,9 +764,9 @@ export const compile = async (app: Application) => {
770
764
  type: `command-node-${type}`,
771
765
  properties: {
772
766
  command: commandNode.__commandName,
773
- args: args.reduce((acc, input) => {
774
- acc[input.key] = input.source
775
- return acc
767
+ args: args.reduce((argsAcc, input) => {
768
+ argsAcc[input.key] = input.source
769
+ return argsAcc
776
770
  }, {}),
777
771
  },
778
772
  in: generateInputPorts(inputs),
@@ -784,12 +778,12 @@ export const compile = async (app: Application) => {
784
778
  calc.editor_info = mapCalc.editorInfo.reduce((acc, editorInfo) => {
785
779
  acc[getNodeId(editorInfo.node)] = {
786
780
  position: editorInfo.position,
787
- points: editorInfo.points.reduce((acc, point) => {
781
+ points: editorInfo.points.reduce((pointsAcc, point) => {
788
782
  const sourceId = getNodeId(point.source)
789
783
  const targetId = getNodeId(point.target)
790
784
  const key = `${sourceId}-${point.sourceOutputKey}-${targetId}-${point.targetInputKey}`
791
- acc[key] = point.positions
792
- return acc
785
+ pointsAcc[key] = point.positions
786
+ return pointsAcc
793
787
  }, {}),
794
788
  }
795
789
  return acc
package/compile/util.ts CHANGED
@@ -3,6 +3,7 @@ import { makeId } from '../utils/id'
3
3
  type ScriptConfig = {
4
4
  inputs: Record<string, string>
5
5
  enable_async: boolean
6
+ trigger_mode?: 'auto' | 'manual'
6
7
  disabled_triggers: Record<string, boolean>
7
8
  output: string | null
8
9
  outputs: Record<string, string[]>
@@ -13,6 +14,8 @@ type ScriptConfig = {
13
14
  const errorMsg = 'Not allow duplicate set property id between inputs / outputs / output / error.'
14
15
 
15
16
  export const validateConfig = (config: ScriptConfig) => {
17
+ // Skip input/output overlap validation in manual mode (allows same data node in both)
18
+ if (config.trigger_mode === 'manual') return
16
19
  if (config.error && config.inputs[config.error]) {
17
20
  throw new Error(`${errorMsg}. key: error`)
18
21
  }
@@ -87,7 +90,8 @@ export const generateCalulationMap = (config: ScriptConfig, opts?: { snapshotMod
87
90
  {
88
91
  id: key,
89
92
  port: 'value',
90
- disable_trigger_command: config.disabled_triggers?.[key] ? true : undefined,
93
+ disable_trigger_command:
94
+ config.trigger_mode === 'manual' || config.disabled_triggers?.[key] || undefined,
91
95
  },
92
96
  ],
93
97
  },
@@ -152,6 +156,8 @@ export const generateCalulationMap = (config: ScriptConfig, opts?: { snapshotMod
152
156
  points: {},
153
157
  }
154
158
  pbList.forEach((pb, pbIndex) => {
159
+ // Check if this data node already exists (it might be used as both input and output)
160
+ const existingNode = acc.map[pb] || inputs.map[pb]
155
161
  acc.map[pb] = {
156
162
  type: 'data-node',
157
163
  properties: {},
@@ -164,7 +170,8 @@ export const generateCalulationMap = (config: ScriptConfig, opts?: { snapshotMod
164
170
  ],
165
171
  },
166
172
  out: {
167
- value: null,
173
+ // Preserve existing out.value if node is also used as input
174
+ value: existingNode?.out?.value ?? null,
168
175
  },
169
176
  }
170
177
  acc.editorInfo[pb] = {
@@ -292,7 +299,8 @@ export const generateCalulationMap = (config: ScriptConfig, opts?: { snapshotMod
292
299
  ],
293
300
  },
294
301
  out: {
295
- value: null,
302
+ // Preserve existing out.value if node is also used as input
303
+ value: inputs.map[config.error]?.out?.value ?? null,
296
304
  },
297
305
  },
298
306
  }),
@@ -309,7 +317,8 @@ export const generateCalulationMap = (config: ScriptConfig, opts?: { snapshotMod
309
317
  ],
310
318
  },
311
319
  out: {
312
- value: null,
320
+ // Preserve existing out.value if node is also used as input
321
+ value: inputs.map[config.output]?.out?.value ?? null,
313
322
  },
314
323
  },
315
324
  }),
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@fugood/bricks-project",
3
- "version": "2.23.0-beta.5",
3
+ "version": "2.23.0-beta.50",
4
4
  "main": "index.ts",
5
5
  "scripts": {
6
- "build": "node scripts/build.js"
6
+ "build": "bun scripts/build.js"
7
7
  },
8
8
  "dependencies": {
9
9
  "@modelcontextprotocol/sdk": "^1.15.0",
10
10
  "@types/escodegen": "^0.0.10",
11
11
  "@types/lodash": "^4.17.12",
12
12
  "acorn": "^8.13.0",
13
- "escodegen": "^2.1.0",
13
+ "escodegen": "2.1.0",
14
14
  "lodash": "^4.17.4",
15
15
  "uuid": "^8.3.1"
16
16
  },
17
- "gitHead": "e21c486d1adc6c02aa06847398a5444b21b6c746"
17
+ "gitHead": "947197fafe253e2cca2ec29f3e6f02882924c09e"
18
18
  }
package/tools/deploy.ts CHANGED
@@ -1,8 +1,21 @@
1
1
  import { $ } from 'bun'
2
+ import { parseArgs } from 'util'
2
3
  import { deployApp, deployModule } from '../api'
3
4
 
4
5
  const cwd = process.cwd()
5
6
 
7
+ // Parse command-line arguments
8
+ const {
9
+ values: { changelogs: changelogsArg, 'changelogs-file': changelogsFile },
10
+ } = parseArgs({
11
+ args: Bun.argv.slice(2),
12
+ options: {
13
+ changelogs: { type: 'string' },
14
+ 'changelogs-file': { type: 'string' },
15
+ },
16
+ allowPositionals: true,
17
+ })
18
+
6
19
  const { exitCode } = await $`cd ${cwd} && git status`.nothrow()
7
20
  const isGitRepo = exitCode === 0
8
21
 
@@ -22,14 +35,32 @@ const app = await Bun.file(`${cwd}/application.json`).json()
22
35
  const stage = app.stage || 'production'
23
36
  const config = await Bun.file(`${cwd}/.bricks/build/application-config.json`).json()
24
37
 
38
+ // Get version from project's package.json
39
+ const pkgFile = Bun.file(`${cwd}/package.json`)
40
+ const version = (await pkgFile.exists()) ? (await pkgFile.json()).version : undefined
41
+
42
+ // Get changelog from flag, file, or prompt
43
+ let changelogs = ''
44
+ if (changelogsArg) {
45
+ changelogs = changelogsArg
46
+ } else if (changelogsFile) {
47
+ const file = Bun.file(changelogsFile)
48
+ if (!(await file.exists())) {
49
+ throw new Error(`Changelogs file not found: ${changelogsFile}`)
50
+ }
51
+ changelogs = await file.text()
52
+ } else {
53
+ changelogs = prompt('Enter changelogs (optional, press Enter to skip):') || ''
54
+ }
55
+
25
56
  // ask for confirmation
26
57
  const confirm = prompt('Are you sure you want to deploy? (y/n)')
27
58
  if (confirm !== 'y') throw new Error('Deployment cancelled')
28
59
 
29
60
  if (!app.type || app.type === 'application') {
30
- await deployApp(stage, app.id, config, commitId)
61
+ await deployApp(stage, app.id, config, commitId, changelogs, version)
31
62
  console.log('App deployed')
32
63
  } else if (app.type === 'module') {
33
- await deployModule(stage, app.id, config, commitId)
64
+ await deployModule(stage, app.id, config, commitId, changelogs, version)
34
65
  console.log('Module deployed')
35
66
  }
@@ -8,7 +8,7 @@ const server = new McpServer({
8
8
  version: '1.0.0',
9
9
  })
10
10
 
11
- const dirname = import.meta.dirname
11
+ const { dirname } = import.meta
12
12
  const projectDir = String(dirname).split('/node_modules/')[0]
13
13
 
14
14
  server.tool('compile', {}, async () => {
@@ -16,7 +16,7 @@ server.tool('compile', {}, async () => {
16
16
  try {
17
17
  log = await $`bun compile`.cwd(projectDir).text()
18
18
  } catch (err) {
19
- log = err.stdout.toString() + '\n' + err.stderr.toString()
19
+ log = `${err.stdout.toString()}\n${err.stderr.toString()}`
20
20
  }
21
21
  return {
22
22
  content: [{ type: 'text', text: log || 'Compiled successfully' }],
@@ -61,7 +61,7 @@ server.tool(
61
61
  ]
62
62
  log = await $`bunx --bun electron ${dirname}/preview-main.mjs ${args}`.cwd(projectDir).text()
63
63
  } catch (err) {
64
- log = err.stdout.toString() + '\n' + err.stderr.toString()
64
+ log = `${err.stdout.toString()}\n${err.stderr.toString()}`
65
65
  error = true
66
66
  }
67
67
  let screenshotBase64: any = null
@@ -17,13 +17,10 @@ const skipCopyProject = process.argv.includes('--skip-copy-project')
17
17
  if (skipCopyProject) {
18
18
  console.log('Skipping copy of files to project/')
19
19
  } else {
20
-
21
20
  const libFiles = ['types', 'utils', 'index.ts']
22
-
21
+
23
22
  await $`mkdir -p ${cwd}/project`
24
- for (const file of libFiles) {
25
- await $`cp -r ${__dirname}/../${file} ${cwd}/project`
26
- }
23
+ await Promise.all(libFiles.map((file) => $`cp -r ${__dirname}/../${file} ${cwd}/project`))
27
24
  console.log('Copied files to project/')
28
25
  }
29
26
 
@@ -58,13 +55,7 @@ const handleMcpConfigOverride = async (mcpConfigPath: string) => {
58
55
  console.log(`Updated ${mcpConfigPath}`)
59
56
  }
60
57
 
61
- if (await exists(`${cwd}/.cursor/rules/instructions.mdc`)) {
62
- const cursorMcpConfigPath = `${cwd}/.cursor/mcp.json`
63
- await handleMcpConfigOverride(cursorMcpConfigPath)
64
- }
65
-
66
58
  if (await exists(`${cwd}/CLAUDE.md`)) {
67
- await $`mkdir -p ${cwd}/.cursor`
68
59
  const claudeCodeMcpConfigPath = `${cwd}/.mcp.json`
69
60
  await handleMcpConfigOverride(claudeCodeMcpConfigPath)
70
61
  }
package/tools/preview.ts CHANGED
@@ -25,7 +25,7 @@ const cwd = process.cwd()
25
25
 
26
26
  const app = await Bun.file(`${cwd}/application.json`).json()
27
27
 
28
- let args: string[] = []
28
+ const args: string[] = []
29
29
  if (values['clear-cache']) args.push('--clear-cache')
30
30
 
31
31
  let needWatcher = true