@fugood/bricks-project 2.23.0-beta.7 → 2.23.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 (116) hide show
  1. package/api/instance.ts +37 -5
  2. package/compile/action-name-map.ts +81 -0
  3. package/compile/index.ts +164 -63
  4. package/compile/util.ts +13 -4
  5. package/package.json +8 -4
  6. package/skills/bricks-project/SKILL.md +32 -0
  7. package/skills/bricks-project/rules/animation.md +159 -0
  8. package/skills/bricks-project/rules/architecture-patterns.md +62 -0
  9. package/skills/bricks-project/rules/automations.md +175 -0
  10. package/skills/bricks-project/rules/buttress.md +153 -0
  11. package/skills/bricks-project/rules/data-calculation.md +208 -0
  12. package/skills/bricks-project/rules/local-sync.md +129 -0
  13. package/skills/bricks-project/rules/media-flow.md +158 -0
  14. package/skills/bricks-project/rules/remote-data-bank.md +196 -0
  15. package/skills/bricks-project/rules/standby-transition.md +124 -0
  16. package/skills/rive-marketplace/SKILL.md +99 -0
  17. package/tools/deploy.ts +74 -12
  18. package/tools/icons/.gitattributes +1 -0
  19. package/tools/icons/fa6pro-glyphmap.json +4686 -0
  20. package/tools/icons/fa6pro-meta.json +26127 -0
  21. package/tools/mcp-server.ts +812 -8
  22. package/tools/postinstall.ts +33 -13
  23. package/tools/preview-main.mjs +53 -4
  24. package/tools/preview.ts +53 -6
  25. package/tools/pull.ts +37 -16
  26. package/types/automation.ts +232 -0
  27. package/types/brick-base.ts +1 -0
  28. package/types/bricks/Camera.ts +26 -10
  29. package/types/bricks/Chart.ts +1 -0
  30. package/types/bricks/GenerativeMedia.ts +21 -3
  31. package/types/bricks/Icon.ts +1 -0
  32. package/types/bricks/Image.ts +6 -0
  33. package/types/bricks/Items.ts +1 -0
  34. package/types/bricks/Lottie.ts +1 -0
  35. package/types/bricks/Maps.ts +254 -0
  36. package/types/bricks/QrCode.ts +1 -0
  37. package/types/bricks/Rect.ts +1 -0
  38. package/types/bricks/RichText.ts +1 -0
  39. package/types/bricks/Rive.ts +1 -0
  40. package/types/bricks/Slideshow.ts +1 -0
  41. package/types/bricks/Svg.ts +1 -0
  42. package/types/bricks/Text.ts +1 -0
  43. package/types/bricks/TextInput.ts +1 -0
  44. package/types/bricks/Video.ts +1 -0
  45. package/types/bricks/VideoStreaming.ts +1 -0
  46. package/types/bricks/WebRtcStream.ts +1 -0
  47. package/types/bricks/WebView.ts +8 -1
  48. package/types/bricks/index.ts +2 -0
  49. package/types/canvas.ts +1 -0
  50. package/types/common.ts +2 -0
  51. package/types/data-calc-command.ts +7003 -0
  52. package/types/data-calc-script.ts +21 -0
  53. package/types/data-calc.ts +3 -6977
  54. package/types/data.ts +3 -0
  55. package/types/generators/AlarmClock.ts +2 -0
  56. package/types/generators/Assistant.ts +30 -6
  57. package/types/generators/BleCentral.ts +2 -0
  58. package/types/generators/BlePeripheral.ts +2 -0
  59. package/types/generators/CanvasMap.ts +2 -0
  60. package/types/generators/CastlesPay.ts +2 -0
  61. package/types/generators/DataBank.ts +2 -0
  62. package/types/generators/File.ts +2 -0
  63. package/types/generators/GraphQl.ts +2 -0
  64. package/types/generators/Http.ts +84 -2
  65. package/types/generators/HttpServer.ts +5 -1
  66. package/types/generators/Information.ts +2 -0
  67. package/types/generators/Intent.ts +51 -0
  68. package/types/generators/Iterator.ts +11 -2
  69. package/types/generators/Keyboard.ts +2 -0
  70. package/types/generators/LlmAnthropicCompat.ts +2 -0
  71. package/types/generators/LlmAppleBuiltin.ts +144 -0
  72. package/types/generators/LlmGgml.ts +29 -5
  73. package/types/generators/LlmOnnx.ts +2 -0
  74. package/types/generators/LlmOpenAiCompat.ts +2 -0
  75. package/types/generators/LlmQualcommAiEngine.ts +2 -0
  76. package/types/generators/Mcp.ts +6 -4
  77. package/types/generators/McpServer.ts +8 -6
  78. package/types/generators/MediaFlow.ts +2 -0
  79. package/types/generators/MqttBroker.ts +2 -0
  80. package/types/generators/MqttClient.ts +2 -0
  81. package/types/generators/Question.ts +9 -0
  82. package/types/generators/RealtimeTranscription.ts +4 -2
  83. package/types/generators/RerankerGgml.ts +23 -16
  84. package/types/generators/SerialPort.ts +2 -0
  85. package/types/generators/SoundPlayer.ts +2 -0
  86. package/types/generators/SoundRecorder.ts +2 -0
  87. package/types/generators/SpeechToTextGgml.ts +14 -4
  88. package/types/generators/SpeechToTextOnnx.ts +2 -0
  89. package/types/generators/SpeechToTextPlatform.ts +2 -0
  90. package/types/generators/SqLite.ts +32 -1
  91. package/types/generators/Step.ts +2 -0
  92. package/types/generators/SttAppleBuiltin.ts +117 -0
  93. package/types/generators/Tcp.ts +2 -0
  94. package/types/generators/TcpServer.ts +5 -1
  95. package/types/generators/TextToSpeechApple.ts +113 -0
  96. package/types/generators/TextToSpeechAppleBuiltin.ts +114 -0
  97. package/types/generators/TextToSpeechGgml.ts +24 -3
  98. package/types/generators/TextToSpeechOnnx.ts +2 -0
  99. package/types/generators/TextToSpeechOpenAiLike.ts +2 -0
  100. package/types/generators/ThermalPrinter.ts +2 -0
  101. package/types/generators/Tick.ts +5 -1
  102. package/types/generators/TtsAppleBuiltin.ts +105 -0
  103. package/types/generators/Udp.ts +2 -0
  104. package/types/generators/VadGgml.ts +4 -2
  105. package/types/generators/VectorStore.ts +15 -2
  106. package/types/generators/Watchdog.ts +2 -0
  107. package/types/generators/WebCrawler.ts +2 -0
  108. package/types/generators/WebRtc.ts +4 -2
  109. package/types/generators/WebSocket.ts +2 -0
  110. package/types/generators/index.ts +3 -0
  111. package/types/index.ts +3 -0
  112. package/types/system.ts +48 -6
  113. package/utils/calc.ts +5 -1
  114. package/utils/data.ts +1 -0
  115. package/utils/event-props.ts +85 -2
  116. 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: {
@@ -747,6 +805,29 @@ export const templateActionNameMap = {
747
805
  toolChoice: 'GENERATOR_ANTHROPIC_LLM_TOOL_CHOICE',
748
806
  },
749
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
+ },
750
831
  GENERATOR_ASSISTANT: {
751
832
  GENERATOR_ASSISTANT_ADD_MESSAGE: {
752
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,13 @@ import type {
24
24
  DataCalculationData,
25
25
  DataCommand,
26
26
  Brick,
27
- Generator,
28
27
  Canvas,
29
28
  Subspace,
30
- EventActionForItem,
29
+ AutomationMap,
30
+ AutomationTestMap,
31
+ AutomationTest,
32
+ TestCase,
33
+ TestVariable,
31
34
  } from '../types'
32
35
 
33
36
  const compileProperty = (property, errorReference: string, result = {}) => {
@@ -58,7 +61,7 @@ const compileEventActionValue = (templateKey, eventKey, value, errorReference) =
58
61
  const props = tmplEventProperties?.[eventKey]
59
62
  if (!props) return compileProperty(value, errorReference)
60
63
  if (props.includes(value)) return value
61
- if (value?.startsWith(templateKey)) {
64
+ if (typeof value === 'string' && value?.startsWith(templateKey)) {
62
65
  console.warn(
63
66
  `[Warning] Value start with template key but there is no event property: ${value} ${errorReference}`,
64
67
  )
@@ -66,25 +69,22 @@ const compileEventActionValue = (templateKey, eventKey, value, errorReference) =
66
69
  return compileProperty(value, errorReference)
67
70
  }
68
71
 
69
- const convertOutletKey = (templateKey: string, key: string) => {
70
- return `${templateKey}_${_.snakeCase(key).toUpperCase()}`
71
- }
72
+ const convertOutletKey = (templateKey: string, key: string) =>
73
+ `${templateKey}_${_.snakeCase(key).toUpperCase()}`
72
74
 
73
75
  const compileOutlets = (
74
76
  templateKey: string,
75
77
  outlets: { [key: string]: () => Data },
76
78
  errorReference: string,
77
- ) => {
78
- return Object.entries(outlets).reduce((acc, [key, data]) => {
79
+ ) =>
80
+ Object.entries(outlets).reduce((acc, [key, data]) => {
79
81
  if (!data()?.id) throw new Error(`Invalid data reference ${errorReference}`)
80
82
  acc[convertOutletKey(templateKey, key)] = data().id
81
83
  return acc
82
84
  }, {})
83
- }
84
85
 
85
- const convertEventKey = (templateKey: string, key: string) => {
86
- return `${templateKey ? `${templateKey}_` : ''}${_.snakeCase(key).toUpperCase()}`
87
- }
86
+ const convertEventKey = (templateKey: string, key: string) =>
87
+ `${templateKey ? `${templateKey}_` : ''}${_.snakeCase(key).toUpperCase()}`
88
88
 
89
89
  const basicAnimationEvents = ['show', 'standby', 'breatheStart']
90
90
 
@@ -92,14 +92,13 @@ const compileAnimations = (
92
92
  templateKey: string,
93
93
  animations: { [key: string]: Animation },
94
94
  errorReference: string,
95
- ) => {
96
- return Object.entries(animations).reduce((acc, [key, animation]) => {
95
+ ) =>
96
+ Object.entries(animations).reduce((acc, [key, animation]) => {
97
97
  if (!animation?.id) throw new Error(`Invalid animation reference ${errorReference}`)
98
98
  acc[convertEventKey(basicAnimationEvents.includes(key) ? 'BRICK' : templateKey, key)] =
99
99
  `ANIMATION#${animation.id}`
100
100
  return acc
101
101
  }, {})
102
- }
103
102
 
104
103
  const compileActionParam = (templateKey: string, actionName: string, paramName: string) =>
105
104
  templateActionNameMap[templateKey]?.[actionName]?.[paramName] || paramName
@@ -190,7 +189,7 @@ const compileSwitchConds = (templateKey, conds, errorReference) =>
190
189
  result.key = cond.data().id
191
190
  result.value = cond.value
192
191
  } else if (item.cond.__typename === 'SwitchCondInnerStateOutlet') {
193
- const cond = item.cond
192
+ const { cond } = item
194
193
  result.type = 'inner_state'
195
194
  result.key = convertOutletKey(templateKey, cond.outlet)
196
195
  result.value = cond.value
@@ -205,35 +204,33 @@ const compileSwitchConds = (templateKey, conds, errorReference) =>
205
204
  return result
206
205
  })
207
206
 
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
- }
207
+ const compileApplicationSettings = (settings: Application['settings']) => ({
208
+ internet_reachability_url: settings?.internetReachabilityUrl,
209
+ enable_data_lock: settings?.enableDataLock,
210
+ show_deprecated_features: settings?.showDeprecatedFeatures,
211
+ enable_unstable_bricks: settings?.enableUnstableFeatures,
212
+ runtime_cache_options: settings?.runtimeCacheOptions
213
+ ? {
214
+ disabled: settings.runtimeCacheOptions.disabled,
215
+ behavior: settings.runtimeCacheOptions.behavior,
216
+ retry_attempt_for_failure: settings.runtimeCacheOptions.retryAttemptForFailure,
217
+ }
218
+ : undefined,
219
+ tv_options: settings?.tvOptions
220
+ ? {
221
+ disabled_selectable: settings.tvOptions.disabledSelectable,
222
+ selectable_color: settings.tvOptions.selectableColor,
223
+ selectable_border: settings.tvOptions.selectableBorder,
224
+ }
225
+ : undefined,
226
+ ai: settings?.ai
227
+ ? {
228
+ use_anthropic_api_key_system_data: settings.ai.useAnthropicApiKeySystemData,
229
+ use_openai_api_key_system_data: settings.ai.useOpenAiApiKeySystemData,
230
+ use_gemini_api_key_system_data: settings.ai.useGeminiApiKeySystemData,
231
+ }
232
+ : undefined,
233
+ })
237
234
 
238
235
  const animationTypeMap = {
239
236
  AnimationTimingConfig: 'timing',
@@ -325,6 +322,103 @@ const compileModule = (subspace: Subspace) => {
325
322
  }
326
323
  }
327
324
 
325
+ /**
326
+ * Compile a run array element - if it's a getter function, call it and extract the id
327
+ * Note: All entity ids already include their prefix (e.g., SUBSPACE_xxx, BRICK_xxx, PROPERTY_BANK_DATA_NODE_xxx)
328
+ */
329
+ function compileRunElement(element: unknown): unknown {
330
+ if (typeof element !== 'function') return element
331
+
332
+ const result = element()
333
+ if (result && typeof result === 'object' && 'id' in result) {
334
+ return (result as { id: string }).id
335
+ }
336
+ return result
337
+ }
338
+
339
+ /**
340
+ * Compile a run array - resolve getter functions and extract ids with prefixes
341
+ */
342
+ function compileRunArray(run: unknown[]): unknown[] {
343
+ return run.map(compileRunElement)
344
+ }
345
+
346
+ /**
347
+ * Compile typed TestCase to raw format (strips __typename)
348
+ */
349
+ const compileTestCase = (testCase: TestCase) => ({
350
+ id: testCase.id,
351
+ name: testCase.name,
352
+ run: compileRunArray(testCase.run),
353
+ exit_on_failed: testCase.exit_on_failed,
354
+ commented: testCase.commented,
355
+ pre_delay: testCase.pre_delay,
356
+ post_delay: testCase.post_delay,
357
+ post_delay_rule: testCase.post_delay_rule,
358
+ jump_cond: testCase.jump_cond.map((cond) => ({
359
+ type: cond.type,
360
+ status: cond.status,
361
+ variable: cond.variable,
362
+ operator: cond.operator,
363
+ value: cond.value,
364
+ jump_to: cond.jump_to,
365
+ })),
366
+ })
367
+
368
+ /**
369
+ * Compile typed TestVariable to raw format (strips __typename)
370
+ */
371
+ const compileTestVariable = (variable: TestVariable) => ({
372
+ id: variable.id,
373
+ name: variable.name,
374
+ type: variable.type,
375
+ value: variable.value,
376
+ })
377
+
378
+ /**
379
+ * Convert an array of items with id property to an id-keyed record
380
+ */
381
+ const arrayToIdMap = <T extends { id: string }, R>(
382
+ items: T[],
383
+ transform: (item: T) => R,
384
+ ): Record<string, R> => Object.fromEntries(items.map((item) => [item.id, transform(item)]))
385
+
386
+ /**
387
+ * Compile typed AutomationTest to raw format
388
+ */
389
+ const compileAutomationTest = (test: AutomationTest) => ({
390
+ id: test.id,
391
+ title: test.title,
392
+ timeout: test.timeout,
393
+ trigger_type: test.trigger_type,
394
+ cron: test.cron,
395
+ skip_trigger_type_check: test.skip_trigger_type_check,
396
+ local_sync: test.local_sync,
397
+ meta: test.meta,
398
+ case_map: arrayToIdMap(test.cases, compileTestCase),
399
+ var_map: arrayToIdMap(test.variables, compileTestVariable),
400
+ })
401
+
402
+ /**
403
+ * Compile typed AutomationTestMap to raw format
404
+ */
405
+ const compileAutomationTestMap = (testMap: AutomationTestMap) => ({
406
+ title: testMap.title,
407
+ createdAt: testMap.createdAt,
408
+ map: arrayToIdMap(testMap.tests, compileAutomationTest),
409
+ })
410
+
411
+ /**
412
+ * Compile typed AutomationMap to raw automation_map format
413
+ */
414
+ const compileAutomation = (automationMap: AutomationMap) =>
415
+ Object.fromEntries(
416
+ Object.entries(automationMap).map(([mapId, testMap]) => [
417
+ mapId,
418
+ compileAutomationTestMap(testMap),
419
+ ]),
420
+ )
421
+
328
422
  export const compile = async (app: Application) => {
329
423
  await new Promise((resolve) => setImmediate(resolve, 0))
330
424
  const config = {
@@ -338,7 +432,7 @@ export const compile = async (app: Application) => {
338
432
  brick: !subspace.unexpanded.brick,
339
433
  generator: !subspace.unexpanded.generator,
340
434
  canvas: subspace.unexpanded.canvas?.reduce((acc, canvas) => {
341
- acc[canvas.id] = canvas?.id ? false : true
435
+ acc[canvas.id] = !canvas?.id
342
436
  return acc
343
437
  }, {}),
344
438
  property_bank: !subspace.unexpanded.data,
@@ -377,12 +471,12 @@ export const compile = async (app: Application) => {
377
471
  animationRunType: animationDef.runType,
378
472
  compose_type: animationDef.composeType,
379
473
  item_list: animationDef.items.map((item, index) => {
380
- const animation = item()
381
- if (!animation?.id)
474
+ const innerAnimation = item()
475
+ if (!innerAnimation?.id)
382
476
  throw new Error(
383
- `Invalid animation index: ${index} (animation: ${animation.id}, subspace ${subspace.id})`,
477
+ `Invalid animation index: ${index} (animation: ${innerAnimation.id}, subspace ${subspace.id})`,
384
478
  )
385
- return { animation_id: animation.id }
479
+ return { animation_id: innerAnimation.id }
386
480
  }),
387
481
  }
388
482
  }
@@ -461,7 +555,7 @@ export const compile = async (app: Application) => {
461
555
  property.brickList = brickList
462
556
  } else {
463
557
  // Not supported Data for brickList
464
- throw new Error('Not supported Data for brickList directly')
558
+ throw new TypeError('Not supported Data for brickList directly')
465
559
  }
466
560
  if (Array.isArray(brickItems.brickDetails)) {
467
561
  const brickDetails = (brickItems.brickDetails || []).map((item, index) =>
@@ -470,7 +564,7 @@ export const compile = async (app: Application) => {
470
564
  property.brickDetails = brickDetails
471
565
  } else {
472
566
  // Not supported Data for brickList
473
- throw new Error('Not supported Data for brickList directly')
567
+ throw new TypeError('Not supported Data for brickList directly')
474
568
  }
475
569
  }
476
570
  map[brick.id] = {
@@ -677,6 +771,8 @@ export const compile = async (app: Application) => {
677
771
  camelCase: false,
678
772
  errorReference: `(data: ${data.id}, subspace ${subspace.id})`,
679
773
  }),
774
+ hit_equal: data.hit_equal,
775
+ hit_regex: data.hit_regex,
680
776
  }
681
777
  return map
682
778
  }, {}),
@@ -694,7 +790,7 @@ export const compile = async (app: Application) => {
694
790
  if (!acc[port.key]) acc[port.key] = null
695
791
 
696
792
  let sourceId
697
- let sourceNode = port.source()
793
+ const sourceNode = port.source()
698
794
  if (sourceNode?.__typename === 'DataCalculationData')
699
795
  sourceId = (sourceNode as DataCalculationData).data().id
700
796
  if (sourceNode?.__typename === 'DataCommand') sourceId = sourceNode.id
@@ -715,7 +811,7 @@ export const compile = async (app: Application) => {
715
811
  if (!acc[port.key]) acc[port.key] = null
716
812
 
717
813
  let targetId
718
- let targetNode = port.target()
814
+ const targetNode = port.target()
719
815
  if (targetNode?.__typename === 'DataCalculationData')
720
816
  targetId = (targetNode as DataCalculationData).data().id
721
817
  if (targetNode?.__typename === 'DataCommand') targetId = targetNode.id
@@ -770,9 +866,9 @@ export const compile = async (app: Application) => {
770
866
  type: `command-node-${type}`,
771
867
  properties: {
772
868
  command: commandNode.__commandName,
773
- args: args.reduce((acc, input) => {
774
- acc[input.key] = input.source
775
- return acc
869
+ args: args.reduce((argsAcc, input) => {
870
+ argsAcc[input.key] = input.source
871
+ return argsAcc
776
872
  }, {}),
777
873
  },
778
874
  in: generateInputPorts(inputs),
@@ -784,12 +880,12 @@ export const compile = async (app: Application) => {
784
880
  calc.editor_info = mapCalc.editorInfo.reduce((acc, editorInfo) => {
785
881
  acc[getNodeId(editorInfo.node)] = {
786
882
  position: editorInfo.position,
787
- points: editorInfo.points.reduce((acc, point) => {
883
+ points: editorInfo.points.reduce((pointsAcc, point) => {
788
884
  const sourceId = getNodeId(point.source)
789
885
  const targetId = getNodeId(point.target)
790
886
  const key = `${sourceId}-${point.sourceOutputKey}-${targetId}-${point.targetInputKey}`
791
- acc[key] = point.positions
792
- return acc
887
+ pointsAcc[key] = point.positions
888
+ return pointsAcc
793
889
  }, {}),
794
890
  }
795
891
  return acc
@@ -864,8 +960,13 @@ export const compile = async (app: Application) => {
864
960
  root_subspace_id: app.rootSubspace.id,
865
961
  fonts: app.fonts,
866
962
  ...compileApplicationSettings(app.settings),
867
- test_map: app.metadata?.TEMP_test_map || {},
868
- automation_map: app.metadata?.TEMP_automation_map || {},
963
+ // Use typed automationMap if available, otherwise fall back to TEMP metadata
964
+ test_map: app.automationMap
965
+ ? compileAutomation(app.automationMap)['AUTOMATION_MAP_DEFAULT']?.map || {}
966
+ : app.metadata?.TEMP_test_map || {},
967
+ automation_map: app.automationMap
968
+ ? compileAutomation(app.automationMap)
969
+ : app.metadata?.TEMP_automation_map || {},
869
970
  }
870
971
  return config
871
972
  }
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,22 @@
1
1
  {
2
2
  "name": "@fugood/bricks-project",
3
- "version": "2.23.0-beta.7",
3
+ "version": "2.23.0",
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
+ "@fugood/bricks-cli": "^2.23.0",
10
+ "@huggingface/gguf": "^0.3.2",
9
11
  "@modelcontextprotocol/sdk": "^1.15.0",
12
+ "@toon-format/toon": "^2.1.0",
10
13
  "@types/escodegen": "^0.0.10",
11
14
  "@types/lodash": "^4.17.12",
12
15
  "acorn": "^8.13.0",
13
- "escodegen": "^2.1.0",
16
+ "escodegen": "2.1.0",
17
+ "fuse.js": "^7.0.0",
14
18
  "lodash": "^4.17.4",
15
19
  "uuid": "^8.3.1"
16
20
  },
17
- "gitHead": "7c3be998ca35559d375190e3fd29e9aea9eb4293"
21
+ "gitHead": "398352b9923f97e914ac60acab519ca014aa6fb8"
18
22
  }