@fugood/bricks-project 2.24.0-beta.9 → 2.24.1-beta.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 (125) hide show
  1. package/compile/action-name-map.ts +38 -0
  2. package/compile/index.ts +460 -158
  3. package/compile/util.ts +2 -0
  4. package/package.json +8 -3
  5. package/package.json.bak +28 -0
  6. package/skills/{bricks-project → bricks-ctor}/SKILL.md +2 -2
  7. package/skills/{bricks-project → bricks-ctor}/rules/animation.md +1 -1
  8. package/skills/{bricks-project → bricks-ctor}/rules/architecture-patterns.md +7 -0
  9. package/skills/{bricks-project → bricks-ctor}/rules/buttress.md +10 -7
  10. package/skills/{bricks-project → bricks-ctor}/rules/data-calculation.md +3 -2
  11. package/skills/{bricks-project → bricks-ctor}/rules/local-sync.md +2 -2
  12. package/skills/{bricks-project → bricks-ctor}/rules/media-flow.md +3 -3
  13. package/skills/{bricks-project → bricks-ctor}/rules/remote-data-bank.md +6 -6
  14. package/skills/{bricks-project → bricks-ctor}/rules/standby-transition.md +1 -1
  15. package/skills/bricks-design/LICENSE.txt +180 -0
  16. package/skills/bricks-design/SKILL.md +66 -0
  17. package/tools/_git-author.ts +29 -0
  18. package/tools/_shell.ts +173 -0
  19. package/tools/deploy.ts +91 -23
  20. package/tools/icons/fa6pro-meta.json +3669 -26125
  21. package/tools/mcp-server.ts +11 -878
  22. package/tools/mcp-tools/compile.ts +92 -0
  23. package/tools/mcp-tools/huggingface.ts +762 -0
  24. package/tools/mcp-tools/icons.ts +70 -0
  25. package/tools/mcp-tools/lottie.ts +102 -0
  26. package/tools/mcp-tools/media.ts +110 -0
  27. package/tools/postinstall.ts +143 -40
  28. package/tools/preview-main.mjs +135 -2
  29. package/tools/preview.ts +68 -33
  30. package/tools/pull.ts +56 -32
  31. package/tsconfig.json +16 -0
  32. package/types/animation.ts +4 -0
  33. package/types/automation.ts +4 -1
  34. package/types/brick-base.ts +1 -1
  35. package/types/bricks/Camera.ts +47 -12
  36. package/types/bricks/Chart.ts +9 -3
  37. package/types/bricks/GenerativeMedia.ts +29 -13
  38. package/types/bricks/Icon.ts +8 -4
  39. package/types/bricks/Image.ts +9 -5
  40. package/types/bricks/Items.ts +28 -14
  41. package/types/bricks/Lottie.ts +14 -6
  42. package/types/bricks/Maps.ts +15 -7
  43. package/types/bricks/QrCode.ts +8 -4
  44. package/types/bricks/Rect.ts +44 -5
  45. package/types/bricks/RichText.ts +8 -4
  46. package/types/bricks/Rive.ts +20 -10
  47. package/types/bricks/Slideshow.ts +19 -9
  48. package/types/bricks/Svg.ts +7 -3
  49. package/types/bricks/Text.ts +8 -4
  50. package/types/bricks/TextInput.ts +22 -12
  51. package/types/bricks/Video.ts +10 -6
  52. package/types/bricks/VideoStreaming.ts +7 -3
  53. package/types/bricks/WebRtcStream.ts +6 -2
  54. package/types/bricks/WebView.ts +11 -7
  55. package/types/canvas.ts +2 -0
  56. package/types/common.ts +15 -8
  57. package/types/data-calc-command.ts +2 -0
  58. package/types/data-calc.ts +1 -0
  59. package/types/data.ts +2 -0
  60. package/types/generators/AlarmClock.ts +16 -10
  61. package/types/generators/Assistant.ts +68 -17
  62. package/types/generators/BleCentral.ts +30 -10
  63. package/types/generators/BlePeripheral.ts +10 -6
  64. package/types/generators/CanvasMap.ts +9 -5
  65. package/types/generators/CastlesPay.ts +14 -6
  66. package/types/generators/DataBank.ts +43 -8
  67. package/types/generators/File.ts +108 -29
  68. package/types/generators/GraphQl.ts +11 -5
  69. package/types/generators/Http.ts +32 -9
  70. package/types/generators/HttpServer.ts +22 -14
  71. package/types/generators/Information.ts +8 -4
  72. package/types/generators/Intent.ts +14 -4
  73. package/types/generators/Iterator.ts +14 -10
  74. package/types/generators/Keyboard.ts +26 -12
  75. package/types/generators/LlmAnthropicCompat.ts +32 -10
  76. package/types/generators/LlmAppleBuiltin.ts +24 -9
  77. package/types/generators/LlmGgml.ts +139 -30
  78. package/types/generators/LlmMediaTekNeuroPilot.ts +235 -0
  79. package/types/generators/LlmMlx.ts +227 -0
  80. package/types/generators/LlmOnnx.ts +33 -13
  81. package/types/generators/LlmOpenAiCompat.ts +46 -10
  82. package/types/generators/LlmQualcommAiEngine.ts +44 -12
  83. package/types/generators/Mcp.ts +374 -33
  84. package/types/generators/McpServer.ts +57 -18
  85. package/types/generators/MediaFlow.ts +37 -11
  86. package/types/generators/MqttBroker.ts +28 -10
  87. package/types/generators/MqttClient.ts +18 -8
  88. package/types/generators/Question.ts +12 -8
  89. package/types/generators/RealtimeTranscription.ts +107 -18
  90. package/types/generators/RerankerGgml.ts +42 -11
  91. package/types/generators/SerialPort.ts +17 -9
  92. package/types/generators/SoundPlayer.ts +9 -3
  93. package/types/generators/SoundRecorder.ts +23 -8
  94. package/types/generators/SpeechToTextGgml.ts +51 -17
  95. package/types/generators/SpeechToTextOnnx.ts +17 -10
  96. package/types/generators/SpeechToTextPlatform.ts +14 -6
  97. package/types/generators/SqLite.ts +19 -9
  98. package/types/generators/Step.ts +8 -4
  99. package/types/generators/SttAppleBuiltin.ts +21 -8
  100. package/types/generators/Tcp.ts +12 -8
  101. package/types/generators/TcpServer.ts +19 -13
  102. package/types/generators/TextToSpeechAppleBuiltin.ts +20 -7
  103. package/types/generators/TextToSpeechGgml.ts +28 -10
  104. package/types/generators/TextToSpeechOnnx.ts +18 -11
  105. package/types/generators/TextToSpeechOpenAiLike.ts +13 -7
  106. package/types/generators/ThermalPrinter.ts +12 -8
  107. package/types/generators/Tick.ts +10 -6
  108. package/types/generators/Udp.ts +16 -7
  109. package/types/generators/VadGgml.ts +50 -13
  110. package/types/generators/VadOnnx.ts +41 -11
  111. package/types/generators/VadTraditional.ts +27 -12
  112. package/types/generators/VectorStore.ts +32 -11
  113. package/types/generators/Watchdog.ts +18 -9
  114. package/types/generators/WebCrawler.ts +10 -6
  115. package/types/generators/WebRtc.ts +29 -15
  116. package/types/generators/WebSocket.ts +10 -6
  117. package/types/generators/index.ts +2 -0
  118. package/types/subspace.ts +4 -0
  119. package/types/system.ts +1 -1
  120. package/utils/event-props.ts +833 -1022
  121. package/api/index.ts +0 -1
  122. package/api/instance.ts +0 -213
  123. package/types/generators/TextToSpeechApple.ts +0 -113
  124. package/types/generators/TtsAppleBuiltin.ts +0 -105
  125. /package/skills/{bricks-project → bricks-ctor}/rules/automations.md +0 -0
@@ -2,6 +2,7 @@
2
2
  import { app, BrowserWindow } from 'electron'
3
3
  import { readFile, writeFile } from 'fs/promises'
4
4
  import { watchFile } from 'fs'
5
+ import { createServer } from 'http'
5
6
  import { parseArgs } from 'util'
6
7
  import * as TOON from '@toon-format/toon'
7
8
 
@@ -14,6 +15,7 @@ const { values } = parseArgs({
14
15
  'test-id': { type: 'string' },
15
16
  'test-title-like': { type: 'string' },
16
17
  'no-keep-open': { type: 'boolean' },
18
+ 'cdp-port': { type: 'string' },
17
19
  },
18
20
  strict: true,
19
21
  allowPositionals: true,
@@ -70,6 +72,133 @@ const previewUrlMap = {
70
72
  const previewUrl = previewUrlMap[stage]
71
73
  if (!previewUrl) throw new Error(`Invalid BRICKS_STAGE: ${stage}`)
72
74
 
75
+ // --- CDP WebSocket Server ---
76
+ // Bridges external CDP clients to the preview's postMessage-based CDP bridge.
77
+ // Usage: --cdp-port 9222
78
+
79
+ const startCdpServer = async (mainWindow, port) => {
80
+ const { WebSocketServer } = await import('ws')
81
+ const clients = new Set()
82
+
83
+ // Inject a listener in the preview that forwards CDP responses/events via console
84
+ const injectCdpRelay = () =>
85
+ mainWindow.webContents.executeJavaScript(`
86
+ if (!window.__cdpRelayInstalled) {
87
+ window.__cdpRelayInstalled = true
88
+ window.addEventListener('message', (evt) => {
89
+ try {
90
+ const d = typeof evt.data === 'string' ? JSON.parse(evt.data) : evt.data
91
+ if (d && (d.type === 'cdp-response' || d.type === 'cdp-event'))
92
+ console.log('[CDP]' + JSON.stringify(d))
93
+ } catch {}
94
+ })
95
+ }
96
+ `)
97
+
98
+ // Capture CDP messages from the preview's console output
99
+ mainWindow.webContents.on('console-message', (_event, ...rest) => {
100
+ const message = typeof rest[0] === 'object' ? rest[0].message : rest[1]
101
+ if (!message?.startsWith('[CDP]')) return
102
+ try {
103
+ const data = JSON.parse(message.slice(5))
104
+ // Translate to standard CDP wire format (strip internal type field)
105
+ const wireMsg =
106
+ data.type === 'cdp-response'
107
+ ? { id: data.id, result: data.result, error: data.error }
108
+ : { method: data.method, params: data.params }
109
+ if (data.sessionId) wireMsg.sessionId = data.sessionId
110
+ const payload = JSON.stringify(wireMsg)
111
+ for (const c of clients) if (c.readyState === 1) c.send(payload)
112
+ } catch {}
113
+ })
114
+
115
+ // Find an available port before binding
116
+ const findPort = (p) =>
117
+ new Promise((resolve) => {
118
+ const probe = createServer()
119
+ probe.once('error', () => {
120
+ if (p < port + 100) resolve(findPort(p + 1))
121
+ else resolve(null)
122
+ })
123
+ probe.listen(p, () => probe.close(() => resolve(p)))
124
+ })
125
+
126
+ const actualPort = await findPort(port)
127
+ if (!actualPort) {
128
+ console.warn(`CDP server: no available port in range ${port}-${port + 99}`)
129
+ return
130
+ }
131
+
132
+ // HTTP discovery endpoints (chrome://inspect, Playwright, etc.)
133
+ const httpServer = createServer((req, res) => {
134
+ if (req.url === '/json/list' || req.url === '/json') {
135
+ res.writeHead(200, { 'Content-Type': 'application/json' })
136
+ res.end(
137
+ JSON.stringify([
138
+ {
139
+ description: 'BRICKS Preview (CTOR Preview)',
140
+ id: 'bricks-preview',
141
+ title: 'BRICKS Preview',
142
+ type: 'page',
143
+ url: previewUrl,
144
+ webSocketDebuggerUrl: `ws://localhost:${actualPort}/ws`,
145
+ },
146
+ ]),
147
+ )
148
+ return
149
+ }
150
+ if (req.url === '/json/version') {
151
+ res.writeHead(200, { 'Content-Type': 'application/json' })
152
+ res.end(JSON.stringify({ Browser: 'BRICKS Preview', 'Protocol-Version': '1.3' }))
153
+ return
154
+ }
155
+ // bricks-cli discovery endpoint
156
+ if (req.url === '/devtools/info') {
157
+ res.writeHead(200, { 'Content-Type': 'application/json' })
158
+ res.end(
159
+ JSON.stringify({
160
+ name: 'BRICKS Preview',
161
+ port: actualPort,
162
+ protocols: ['cdp'],
163
+ hasPasscode: false,
164
+ }),
165
+ )
166
+ return
167
+ }
168
+ res.writeHead(404)
169
+ res.end()
170
+ })
171
+
172
+ const wss = new WebSocketServer({ server: httpServer, path: '/ws' })
173
+ wss.on('connection', (ws) => {
174
+ clients.add(ws)
175
+ injectCdpRelay()
176
+
177
+ ws.on('message', (raw) => {
178
+ try {
179
+ const req = JSON.parse(raw.toString())
180
+ const cdpReq = JSON.stringify({
181
+ type: 'cdp-request',
182
+ id: req.id,
183
+ method: req.method,
184
+ params: req.params || {},
185
+ sessionId: req.sessionId,
186
+ })
187
+ mainWindow.webContents.executeJavaScript(`window.postMessage(${JSON.stringify(cdpReq)})`)
188
+ } catch {}
189
+ })
190
+
191
+ ws.on('close', () => clients.delete(ws))
192
+ })
193
+
194
+ httpServer.listen(actualPort, () => {
195
+ console.log(`CDP server: ws://localhost:${actualPort}/ws`)
196
+ console.log(
197
+ `Inspect: devtools://devtools/bundled/inspector.html?ws=localhost:${actualPort}/ws`,
198
+ )
199
+ })
200
+ }
201
+
73
202
  app.on('ready', () => {
74
203
  let show = true
75
204
  if (takeScreenshotConfig && !takeScreenshotConfig.noHeadless) show = false
@@ -124,12 +253,16 @@ app.on('ready', () => {
124
253
  })
125
254
  `)
126
255
  }
256
+ // Start CDP WebSocket server if requested
257
+ const cdpPort = values['cdp-port'] ? parseInt(values['cdp-port'], 10) : null
258
+ if (cdpPort) startCdpServer(mainWindow, cdpPort)
127
259
  })
128
260
 
129
261
  // Capture console messages from the preview
130
262
  if (testId) {
131
- mainWindow.webContents.on('console-message', (_, __, message) => {
132
- if (message.startsWith('[TEST_RESULT]')) {
263
+ mainWindow.webContents.on('console-message', (_event, ...rest) => {
264
+ const message = typeof rest[0] === 'object' ? rest[0].message : rest[1]
265
+ if (message?.startsWith('[TEST_RESULT]')) {
133
266
  const data = JSON.parse(message.replace('[TEST_RESULT]', ''))
134
267
  console.log(`[TEST_RESULT_TOON]${TOON.encode(data.result)}`)
135
268
  if (!takeScreenshotConfig && noKeepOpen) app.quit()
package/tools/preview.ts CHANGED
@@ -1,11 +1,14 @@
1
- import { $ } from 'bun'
2
- import { watch } from 'fs'
1
+ import { spawn } from 'node:child_process'
2
+ import { readFile, writeFile } from 'node:fs/promises'
3
+ import { watch, unlinkSync } from 'fs'
3
4
  import type { FSWatcher } from 'fs'
5
+ import { createInterface } from 'node:readline'
4
6
  import { parseArgs } from 'util'
5
7
  import debounce from 'lodash/debounce'
8
+ import { sh } from './_shell'
6
9
 
7
10
  const { values } = parseArgs({
8
- args: Bun.argv,
11
+ args: process.argv,
9
12
  options: {
10
13
  'skip-typecheck': { type: 'boolean' },
11
14
  'clear-cache': { type: 'boolean' },
@@ -19,6 +22,8 @@ const { values } = parseArgs({
19
22
  'test-id': { type: 'string' },
20
23
  'test-title-like': { type: 'string' },
21
24
  'no-keep-open': { type: 'boolean' },
25
+ 'cdp-port': { type: 'string' },
26
+ 'no-cdp': { type: 'boolean' },
22
27
  },
23
28
  strict: true,
24
29
  allowPositionals: true,
@@ -26,7 +31,7 @@ const { values } = parseArgs({
26
31
 
27
32
  const cwd = process.cwd()
28
33
 
29
- const app = await Bun.file(`${cwd}/application.json`).json()
34
+ const app = JSON.parse(await readFile(`${cwd}/application.json`, 'utf8'))
30
35
 
31
36
  const args: string[] = []
32
37
  if (values['clear-cache']) args.push('--clear-cache')
@@ -62,11 +67,16 @@ if (values['no-keep-open']) {
62
67
  args.push('--no-keep-open')
63
68
  }
64
69
 
70
+ if (!values['no-cdp']) {
71
+ const cdpPort = parseInt(values['cdp-port'] || '', 10) || 19852
72
+ args.push('--cdp-port', String(cdpPort))
73
+ }
74
+
65
75
  const useTypecheck = !values['skip-typecheck']
66
76
 
67
77
  const compile = async () => {
68
- if (useTypecheck) await $`bun typecheck`
69
- await $`bun compile`
78
+ if (useTypecheck) await sh`bun typecheck`
79
+ await sh`bun compile.ts`
70
80
  }
71
81
 
72
82
  await compile()
@@ -80,36 +90,61 @@ if (needWatcher) {
80
90
  })
81
91
  }
82
92
 
83
- const proc = Bun.spawn(['bunx', '--bun', 'electron', `${__dirname}/preview-main.mjs`, ...args], {
84
- env: { ...process.env, BRICKS_STAGE: app.stage || 'production' },
85
- stdout: 'pipe',
86
- stderr: 'inherit',
87
- })
93
+ const devtoolsInfoPath = `${cwd}/.bricks/devtools.json`
88
94
 
89
- const reader = proc.stdout.getReader()
90
- const decoder = new TextDecoder()
91
-
92
- const processOutput = async () => {
93
- let done = false
94
- while (!done) {
95
- // eslint-disable-next-line no-await-in-loop
96
- const result = await reader.read()
97
- ;({ done } = result)
98
- if (!done) {
99
- const text = decoder.decode(result.value)
100
- text.split('\n').forEach((line) => {
101
- if (line.startsWith('[TEST_RESULT_TOON]')) {
102
- const toonData = line.replace('[TEST_RESULT_TOON]', '')
103
- console.log(toonData)
104
- } else if (line) {
105
- console.log(line)
106
- }
107
- })
95
+ const cleanupDevtoolsInfo = () => {
96
+ try {
97
+ unlinkSync(devtoolsInfoPath)
98
+ } catch {}
99
+ }
100
+
101
+ // Kill existing preview process if devtools.json contains a stale pid
102
+ try {
103
+ const devtoolsInfo = JSON.parse(await readFile(devtoolsInfoPath, 'utf8'))
104
+ if (devtoolsInfo.pid) {
105
+ try {
106
+ process.kill(devtoolsInfo.pid)
107
+ } catch {}
108
+ cleanupDevtoolsInfo()
109
+ }
110
+ } catch {}
111
+
112
+ const proc = spawn(
113
+ 'bunx',
114
+ ['--bun', 'electron', `${import.meta.dirname}/preview-main.mjs`, ...args],
115
+ {
116
+ env: { ...process.env, BRICKS_STAGE: app.stage || 'production' },
117
+ stdio: ['inherit', 'pipe', 'inherit'],
118
+ },
119
+ )
120
+
121
+ const rl = createInterface({ input: proc.stdout! })
122
+
123
+ rl.on('line', (line) => {
124
+ if (line.startsWith('[TEST_RESULT_TOON]')) {
125
+ const toonData = line.replace('[TEST_RESULT_TOON]', '')
126
+ console.log(toonData)
127
+ return
128
+ }
129
+ if (!line) return
130
+ // Detect CDP server startup from preview-main output
131
+ const cdpMatch = line.match(/^CDP server: ws:\/\/localhost:(\d+)/)
132
+ if (cdpMatch) {
133
+ const info = {
134
+ port: parseInt(cdpMatch[1], 10),
135
+ pid: proc.pid,
136
+ address: 'localhost',
137
+ name: `${app.name || 'Unnamed'} (CTOR Preview)`,
138
+ startedAt: new Date().toISOString(),
108
139
  }
140
+ writeFile(devtoolsInfoPath, JSON.stringify(info, null, 2))
109
141
  }
110
- }
142
+ console.log(line)
143
+ })
111
144
 
112
- await processOutput()
113
- await proc.exited
145
+ await new Promise<void>((resolve) => {
146
+ proc.on('close', () => resolve())
147
+ })
114
148
 
149
+ cleanupDevtoolsInfo()
115
150
  if (watcher) watcher.close()
package/tools/pull.ts CHANGED
@@ -1,16 +1,30 @@
1
- import { $ } from 'bun'
2
- import { format } from 'prettier'
1
+ import { readFile, writeFile } from 'node:fs/promises'
2
+ import { format } from 'oxfmt'
3
+ import { sh } from './_shell'
4
+ import { buildCommitArgs } from './_git-author'
3
5
 
4
6
  const cwd = process.cwd()
7
+ const args = process.argv.slice(2)
8
+ const force = args.includes('--force') || args.includes('-f')
5
9
 
6
10
  // Check git status
7
- const { exitCode } = await $`cd ${cwd} && git status`.nothrow()
11
+ const { exitCode } = await sh`cd ${cwd} && git status`.nothrow()
8
12
  const isGitRepo = exitCode === 0
9
13
 
10
14
  if (isGitRepo) {
11
- const unstagedChanges = await $`cd ${cwd} && git diff --name-only --diff-filter=ACMR`.text()
12
- if (unstagedChanges)
13
- throw new Error('Unstaged changes found, please commit or stash your changes before pulling')
15
+ const unstagedChanges = await sh`cd ${cwd} && git diff --name-only --diff-filter=ACMR`.text()
16
+ if (unstagedChanges) {
17
+ if (force) {
18
+ console.log('Force mode: committing unstaged changes before pull...')
19
+ await sh`cd ${cwd} && git add .`
20
+ const preCommitArgs = await buildCommitArgs(cwd, [
21
+ 'chore(force-pull): saved unstaged changes before pull',
22
+ ])
23
+ await sh`cd ${cwd} && git ${preCommitArgs}`
24
+ } else {
25
+ throw new Error('Unstaged changes found, please commit or stash your changes before pulling')
26
+ }
27
+ }
14
28
  } else {
15
29
  const confirmContinue = prompt(
16
30
  'No git repository found, so it will not be safe to pull, continue? (y/n)',
@@ -19,13 +33,14 @@ if (isGitRepo) {
19
33
  }
20
34
 
21
35
  // Read application.json
22
- const app = await Bun.file(`${cwd}/application.json`).json()
36
+ const app = JSON.parse(await readFile(`${cwd}/application.json`, 'utf8'))
23
37
 
24
38
  const isModule = app.type === 'module'
25
39
  const command = isModule ? 'module' : 'app'
26
40
 
27
41
  // Fetch project files using CLI
28
- const result = await $`bricks ${command} project-pull ${app.id} --json`.quiet().nothrow()
42
+ console.log(`Pulling ${command} project (${app.id})...`)
43
+ const result = await sh`bricks ${command} project-pull ${app.id} --json`.quiet().nothrow()
29
44
 
30
45
  if (result.exitCode !== 0) {
31
46
  const output = result.stderr.toString() || result.stdout.toString()
@@ -40,12 +55,13 @@ if (result.exitCode !== 0) {
40
55
  const { files, lastCommitId } = JSON.parse(result.stdout.toString())
41
56
 
42
57
  let useMain = false
43
- if (isGitRepo) {
44
- const found = (await $`cd ${cwd} && git rev-list -1 ${lastCommitId}`.nothrow().text())
58
+ if (isGitRepo && !force) {
59
+ console.log(`Checking commit ${lastCommitId}...`)
60
+ const found = (await sh`cd ${cwd} && git rev-list -1 ${lastCommitId}`.nothrow().text())
45
61
  .trim()
46
62
  .match(/^[\da-f]{40}$/)
47
63
 
48
- const commitId = (await $`cd ${cwd} && git rev-parse HEAD`.text()).trim()
64
+ const commitId = (await sh`cd ${cwd} && git rev-parse HEAD`.text()).trim()
49
65
 
50
66
  if (commitId === lastCommitId) throw new Error('Commit not changed')
51
67
 
@@ -53,18 +69,18 @@ if (isGitRepo) {
53
69
  ? 'BRICKS_PROJECT_try-pull-module'
54
70
  : 'BRICKS_PROJECT_try-pull-application'
55
71
 
56
- await $`cd ${cwd} && git branch -D ${branchName}`.nothrow()
72
+ await sh`cd ${cwd} && git branch -D ${branchName}`.nothrow()
57
73
 
58
74
  if (found) {
59
- await $`cd ${cwd} && git checkout -b ${branchName} ${lastCommitId}`.nothrow()
75
+ await sh`cd ${cwd} && git checkout -b ${branchName} ${lastCommitId}`.nothrow()
60
76
  } else {
61
- await $`cd ${cwd} && git checkout -b ${branchName}`
77
+ await sh`cd ${cwd} && git checkout -b ${branchName}`
62
78
  useMain = true
63
79
  }
64
80
  }
65
81
 
66
- const prettierConfig = await Bun.file(`${cwd}/.prettierrc`)
67
- .json()
82
+ const oxfmtConfig = await readFile(`${cwd}/.oxfmtrc.json`, 'utf8')
83
+ .then(JSON.parse)
68
84
  .catch(() => ({
69
85
  trailingComma: 'all',
70
86
  tabWidth: 2,
@@ -74,25 +90,33 @@ const prettierConfig = await Bun.file(`${cwd}/.prettierrc`)
74
90
  }))
75
91
 
76
92
  await Promise.all(
77
- files.map(async (file: { name: string; input: string; formatable?: boolean }) =>
78
- Bun.write(
79
- `${cwd}/${file.name}`,
80
- file.formatable
81
- ? await format(file.input, { parser: 'typescript', ...prettierConfig })
82
- : file.input,
83
- ),
84
- ),
93
+ files.map(async (file: { name: string; input: string; formatable?: boolean }) => {
94
+ let content = file.input
95
+ if (file.formatable) {
96
+ const result = await format(file.name, file.input, oxfmtConfig)
97
+ content = result.code
98
+ }
99
+ return writeFile(`${cwd}/${file.name}`, content)
100
+ }),
85
101
  )
86
102
 
87
103
  if (isGitRepo) {
88
- await $`cd ${cwd} && git add .`
89
- const commitMsg = isModule
90
- ? 'chore(project): apply file changes from BRICKS module'
91
- : 'chore(project): apply file changes from BRICKS application'
92
- await $`cd ${cwd} && git commit -m ${commitMsg}`
93
- if (!useMain) {
94
- await $`cd ${cwd} && git merge main`
104
+ await sh`cd ${cwd} && git add .`
105
+ const hasChanges = !!(await sh`cd ${cwd} && git diff --cached --name-only`.text()).trim()
106
+ if (hasChanges) {
107
+ const commitMsg = force
108
+ ? `chore(force-pull): apply force pull-${command}`
109
+ : isModule
110
+ ? 'chore(project): apply file changes from BRICKS module'
111
+ : 'chore(project): apply file changes from BRICKS application'
112
+ const commitArgs = await buildCommitArgs(cwd, [commitMsg])
113
+ await sh`cd ${cwd} && git ${commitArgs}`
114
+ }
115
+ if (!force && !useMain) {
116
+ await sh`cd ${cwd} && git merge main`
95
117
  }
96
118
  }
97
119
 
98
- console.log(`${isModule ? 'Module' : 'App'} project pulled: ${files.length} files`)
120
+ console.log(
121
+ `${isModule ? 'Module' : 'App'} project pulled: ${files.length} files${force ? ' (force)' : ''}`,
122
+ )
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "lib": ["ESNext"],
4
+ "target": "ESNext",
5
+ "module": "ESNext",
6
+ "moduleDetection": "force",
7
+ "allowJs": true,
8
+ "resolveJsonModule": true,
9
+ "moduleResolution": "bundler",
10
+ "allowImportingTsExtensions": true,
11
+ "verbatimModuleSyntax": true,
12
+ "noEmit": true,
13
+ "skipLibCheck": true,
14
+ },
15
+ "exclude": ["node_modules"],
16
+ }
@@ -61,8 +61,10 @@ export interface AnimationDecayConfig {
61
61
  export interface AnimationDef {
62
62
  __typename: 'Animation'
63
63
  id: string
64
+ alias?: string
64
65
  title: string
65
66
  description?: string
67
+ hideShortRef?: boolean
66
68
  runType?: 'once' | 'loop'
67
69
  property:
68
70
  | 'transform.translateX'
@@ -80,8 +82,10 @@ export interface AnimationDef {
80
82
  export interface AnimationComposeDef {
81
83
  __typename: 'AnimationCompose'
82
84
  id: string
85
+ alias?: string
83
86
  title: string
84
87
  description?: string
88
+ hideShortRef?: boolean
85
89
  runType?: 'once' | 'loop'
86
90
  composeType: 'parallel' | 'sequence'
87
91
  items: Array<() => Animation>
@@ -45,7 +45,7 @@ export interface TestCaseJumpCondition {
45
45
  operator?: JumpConditionOperator
46
46
  value?: any
47
47
  // The test case to jump to (getter function for dynamic IDs or string for static IDs)
48
- jump_to: string | (() => TestCase)
48
+ jump_to?: string | (() => TestCase)
49
49
  }
50
50
 
51
51
  /**
@@ -182,6 +182,7 @@ export interface TestCase {
182
182
  __typename: 'TestCase'
183
183
  id: string
184
184
  name: string
185
+ hideShortRef?: boolean
185
186
  run: TestMethodRun
186
187
  exit_on_failed: boolean
187
188
  commented: boolean
@@ -203,6 +204,7 @@ export interface AutomationTest {
203
204
  __typename: 'AutomationTest'
204
205
  id: string
205
206
  title: string
207
+ hideShortRef?: boolean
206
208
  timeout: number
207
209
  trigger_type?: TestTriggerType
208
210
  cron?: string // Cron expression when trigger_type is 'cron'
@@ -220,6 +222,7 @@ export interface AutomationTestMap {
220
222
  __typename: 'AutomationTestMap'
221
223
  id: string
222
224
  title: string
225
+ hideShortRef?: boolean
223
226
  createdAt: number
224
227
  tests: AutomationTest[]
225
228
  }
@@ -59,7 +59,7 @@ export interface BrickBasicProperty {
59
59
  shadowOffsetWidth?: number | DataLink
60
60
  /* The brick shadow offset height */
61
61
  shadowOffsetHeight?: number | DataLink
62
- /* Brick pressable.
62
+ /* Brick pressable.
63
63
  Disabled: Disabled even if event or animation is set.
64
64
  Bypass: Disable and bypass the touch event on the brick. */
65
65
  pressable?: 'enabled' | 'disabled' | 'bypass' | DataLink
@@ -1,4 +1,7 @@
1
- /* Auto generated by build script */
1
+ /* Auto generated by build script
2
+ *
3
+ * Camera view with photo capture and barcode scanning capabilities
4
+ */
2
5
  import type { SwitchCondInnerStateCurrentCanvas, SwitchCondData, SwitchDef } from '../switch'
3
6
  import type { Data, DataLink } from '../data'
4
7
  import type { Animation, AnimationBasicEvents } from '../animation'
@@ -12,6 +15,7 @@ import type {
12
15
  EventProperty,
13
16
  } from '../common'
14
17
  import type { BrickBasicProperty, BrickBasicEvents, BrickBasicEventsForItem } from '../brick-base'
18
+ import type { TemplateEventPropsMap } from '../../utils/event-props'
15
19
 
16
20
  /* Take picture on the Camera */
17
21
  export type BrickCameraActionTakePicture = ActionWithParams & {
@@ -151,31 +155,62 @@ Default property:
151
155
  }
152
156
  events?: BrickBasicEvents & {
153
157
  /* Event of the Camera state change */
154
- stateChange?: Array<EventAction>
158
+ stateChange?: Array<EventAction<string & keyof TemplateEventPropsMap['Camera']['stateChange']>>
155
159
  /* Event of the Camera record start */
156
160
  recordStart?: Array<EventAction>
157
161
  /* Event of the Camera record end */
158
162
  recordEnd?: Array<EventAction>
159
163
  /* Event of the Camera barcode read */
160
- barcodeRead?: Array<EventAction>
164
+ barcodeRead?: Array<EventAction<string & keyof TemplateEventPropsMap['Camera']['barcodeRead']>>
161
165
  /* Event of the Camera picture taken */
162
- pictureTaken?: Array<EventAction>
166
+ pictureTaken?: Array<
167
+ EventAction<string & keyof TemplateEventPropsMap['Camera']['pictureTaken']>
168
+ >
163
169
  /* Event of the Camera record finished */
164
- recordFinish?: Array<EventAction>
170
+ recordFinish?: Array<
171
+ EventAction<string & keyof TemplateEventPropsMap['Camera']['recordFinish']>
172
+ >
165
173
  /* Event of the Camera mount error */
166
- mountError?: Array<EventAction>
174
+ mountError?: Array<EventAction<string & keyof TemplateEventPropsMap['Camera']['mountError']>>
167
175
  }
168
176
  outlets?: {
169
177
  /* Camera device and format information */
170
- info?: () => Data
178
+ info?: () => Data<{ [key: string]: any }>
171
179
  /* Picture taken result */
172
- pictureTaken?: () => Data
180
+ pictureTaken?: () => Data<{
181
+ width?: number
182
+ height?: number
183
+ uri?: string
184
+ base64?: string
185
+ [key: string]: any
186
+ }>
173
187
  /* Record video result */
174
- recordVideo?: () => Data
188
+ recordVideo?: () => Data<{
189
+ uri?: string
190
+ [key: string]: any
191
+ }>
175
192
  /* Barcode read result */
176
- barcodeRead?: () => Data
193
+ barcodeRead?: () => Data<{
194
+ type?: string
195
+ data?: string
196
+ rawData?: string
197
+ bounds?: {
198
+ origin?: {
199
+ x?: number
200
+ y?: number
201
+ [key: string]: any
202
+ }
203
+ size?: {
204
+ width?: number
205
+ height?: number
206
+ [key: string]: any
207
+ }
208
+ [key: string]: any
209
+ }
210
+ [key: string]: any
211
+ }>
177
212
  /* Faces detected result */
178
- faceDetected?: () => Data
213
+ faceDetected?: () => Data<Array<{ [key: string]: any }>>
179
214
  }
180
215
  animation?: AnimationBasicEvents & {
181
216
  stateChange?: Animation
@@ -188,7 +223,7 @@ Default property:
188
223
  }
189
224
  }
190
225
 
191
- /* Camera view brick ([Tutorial](https://intercom.help/bricks-dag-inc/articles/5378589-camera)) */
226
+ /* Camera view with photo capture and barcode scanning capabilities */
192
227
  export type BrickCamera = Brick &
193
228
  BrickCameraDef & {
194
229
  templateKey: 'BRICK_CAMERA'
@@ -1,4 +1,7 @@
1
- /* Auto generated by build script */
1
+ /* Auto generated by build script
2
+ *
3
+ * Chart brick, based on [Apache ECharts](https://echarts.apache.org/en/index.html).
4
+ */
2
5
  import type { SwitchCondInnerStateCurrentCanvas, SwitchCondData, SwitchDef } from '../switch'
3
6
  import type { Data, DataLink } from '../data'
4
7
  import type { Animation, AnimationBasicEvents } from '../animation'
@@ -12,6 +15,7 @@ import type {
12
15
  EventProperty,
13
16
  } from '../common'
14
17
  import type { BrickBasicProperty, BrickBasicEvents, BrickBasicEventsForItem } from '../brick-base'
18
+ import type { TemplateEventPropsMap } from '../../utils/event-props'
15
19
 
16
20
  /* Data highlight */
17
21
  export type BrickChartActionDataHighlight = ActionWithParams & {
@@ -332,9 +336,11 @@ Default property:
332
336
  /* Event of chart render */
333
337
  onRender?: Array<EventAction>
334
338
  /* Event of data point on press */
335
- onPress?: Array<EventAction>
339
+ onPress?: Array<EventAction<string & keyof TemplateEventPropsMap['Chart']['onPress']>>
336
340
  /* Event of legend select changed */
337
- onLegendSelectChanged?: Array<EventAction>
341
+ onLegendSelectChanged?: Array<
342
+ EventAction<string & keyof TemplateEventPropsMap['Chart']['onLegendSelectChanged']>
343
+ >
338
344
  }
339
345
  animation?: AnimationBasicEvents & {
340
346
  onRender?: Animation