@fugood/bricks-project 2.23.0-beta.9 → 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 +28 -4
  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
@@ -1,5 +1,5 @@
1
1
  import { $ } from 'bun'
2
- import { stat, readFile, writeFile } from 'fs/promises'
2
+ import { stat, readFile, writeFile, readdir } from 'fs/promises'
3
3
 
4
4
  const cwd = process.cwd()
5
5
 
@@ -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,36 @@ 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)
58
+ const hasClaudeCode = await exists(`${cwd}/CLAUDE.md`)
59
+ const hasAgentsMd = await exists(`${cwd}/AGENTS.md`)
60
+
61
+ if (hasClaudeCode || hasAgentsMd) {
62
+ const mcpConfigPath = `${cwd}/.mcp.json`
63
+ await handleMcpConfigOverride(mcpConfigPath)
64
64
  }
65
65
 
66
- if (await exists(`${cwd}/CLAUDE.md`)) {
67
- await $`mkdir -p ${cwd}/.cursor`
68
- const claudeCodeMcpConfigPath = `${cwd}/.mcp.json`
69
- await handleMcpConfigOverride(claudeCodeMcpConfigPath)
66
+ if (hasClaudeCode) {
67
+ // Install skills that don't already exist in the project
68
+ const skillsDir = `${cwd}/.claude/skills`
69
+ const packageSkillsDir = `${__dirname}/../skills`
70
+
71
+ if (await exists(packageSkillsDir)) {
72
+ const packageSkills = await readdir(packageSkillsDir)
73
+ const skillsToInstall = packageSkills.filter((skill) => !skill.startsWith('.'))
74
+
75
+ await $`mkdir -p ${skillsDir}`
76
+
77
+ await Promise.all(
78
+ skillsToInstall.map(async (skill) => {
79
+ const targetSkillDir = `${skillsDir}/${skill}`
80
+ if (await exists(targetSkillDir)) {
81
+ console.log(`Skill '${skill}' already exists, skipping`)
82
+ } else {
83
+ await $`cp -r ${packageSkillsDir}/${skill} ${targetSkillDir}`
84
+ console.log(`Installed skill '${skill}' to .claude/skills/`)
85
+ }
86
+ }),
87
+ )
88
+ }
89
+ // TODO: .codex/skills, .cursor/skills if needed
70
90
  }
@@ -3,12 +3,17 @@ import { app, BrowserWindow } from 'electron'
3
3
  import { readFile, writeFile } from 'fs/promises'
4
4
  import { watchFile } from 'fs'
5
5
  import { parseArgs } from 'util'
6
+ import * as TOON from '@toon-format/toon'
6
7
 
7
8
  const { values } = parseArgs({
8
9
  args: process.argv,
9
10
  options: {
10
11
  'clear-cache': { type: 'boolean' },
11
12
  'take-screenshot': { type: 'string' },
13
+ 'show-menu': { type: 'boolean' },
14
+ 'test-id': { type: 'string' },
15
+ 'test-title-like': { type: 'string' },
16
+ 'no-keep-open': { type: 'boolean' },
12
17
  },
13
18
  strict: true,
14
19
  allowPositionals: true,
@@ -33,6 +38,23 @@ try {
33
38
 
34
39
  let config = JSON.parse(await readFile(`${cwd}/.bricks/build/application-config.json`))
35
40
 
41
+ // Resolve testId from testTitleLike
42
+ let testId = values['test-id'] || null
43
+ if (!testId && values['test-title-like']) {
44
+ const titleLike = values['test-title-like'].toLowerCase()
45
+ const testMap = config.test_map || {}
46
+ const found = Object.entries(testMap).find(([, test]) =>
47
+ test.title?.toLowerCase().includes(titleLike),
48
+ )
49
+ if (found) {
50
+ ;[testId] = found
51
+ } else {
52
+ throw new Error(`No automation found matching title: ${values['test-title-like']}`)
53
+ }
54
+ }
55
+
56
+ const noKeepOpen = values['no-keep-open'] ?? false
57
+
36
58
  const stage = process.env.BRICKS_STAGE || 'production'
37
59
 
38
60
  const previewUrlMap = {
@@ -61,19 +83,20 @@ app.on('ready', () => {
61
83
  type: 'config',
62
84
  configFile: { _originTitle: 'Test', ...config, title: Math.random().toString() },
63
85
  workspace: { billing: { lock: {}, plan: 'free' } },
64
- showMenu: false,
86
+ showMenu: values['show-menu'] || false,
87
+ testId,
65
88
  }
66
89
  mainWindow.webContents.executeJavaScript(
67
90
  `window.postMessage(JSON.stringify(${JSON.stringify(payload)}))`,
68
91
  )
69
92
  if (takeScreenshotConfig) {
70
- const { delay, width, height, path, keepOpen = false } = takeScreenshotConfig
93
+ const { delay, width, height, path } = takeScreenshotConfig
71
94
  setTimeout(() => {
72
95
  console.log('Taking screenshot')
73
96
  mainWindow.webContents.capturePage().then((image) => {
74
97
  console.log('Writing screenshot to', path)
75
98
  writeFile(path, image.resize({ width, height }).toJPEG(75))
76
- if (!keepOpen) {
99
+ if (noKeepOpen) {
77
100
  console.log('Closing app')
78
101
  app.quit()
79
102
  }
@@ -82,7 +105,33 @@ app.on('ready', () => {
82
105
  }
83
106
  }
84
107
 
85
- mainWindow.webContents.once('dom-ready', sendConfig)
108
+ mainWindow.webContents.once('dom-ready', () => {
109
+ sendConfig()
110
+ // Listen for test result messages from the preview
111
+ if (testId) {
112
+ mainWindow.webContents.executeJavaScript(`
113
+ window.addEventListener('message', (evt) => {
114
+ try {
115
+ const data = JSON.parse(evt.data)
116
+ if (data.type === 'bricks-preview-test-result') {
117
+ console.log('[TEST_RESULT]' + JSON.stringify(data))
118
+ }
119
+ } catch (e) {}
120
+ })
121
+ `)
122
+ }
123
+ })
124
+
125
+ // Capture console messages from the preview
126
+ if (testId) {
127
+ mainWindow.webContents.on('console-message', (_, __, message) => {
128
+ if (message.startsWith('[TEST_RESULT]')) {
129
+ const data = JSON.parse(message.replace('[TEST_RESULT]', ''))
130
+ console.log(`[TEST_RESULT_TOON]${TOON.encode(data.result)}`)
131
+ if (!takeScreenshotConfig && noKeepOpen) app.quit()
132
+ }
133
+ })
134
+ }
86
135
 
87
136
  if (values['clear-cache']) {
88
137
  console.log('Clearing cache')
package/tools/preview.ts CHANGED
@@ -14,8 +14,11 @@ const { values } = parseArgs({
14
14
  'screenshot-width': { type: 'string' },
15
15
  'screenshot-height': { type: 'string' },
16
16
  'screenshot-path': { type: 'string' },
17
- 'screenshot-keep-open': { type: 'boolean' },
18
17
  'screenshot-no-headless': { type: 'boolean' },
18
+ 'show-menu': { type: 'boolean' },
19
+ 'test-id': { type: 'string' },
20
+ 'test-title-like': { type: 'string' },
21
+ 'no-keep-open': { type: 'boolean' },
19
22
  },
20
23
  strict: true,
21
24
  allowPositionals: true,
@@ -25,24 +28,38 @@ const cwd = process.cwd()
25
28
 
26
29
  const app = await Bun.file(`${cwd}/application.json`).json()
27
30
 
28
- let args: string[] = []
31
+ const args: string[] = []
29
32
  if (values['clear-cache']) args.push('--clear-cache')
30
33
 
31
34
  let needWatcher = true
32
35
  if (values['screenshot']) {
33
36
  args.push(`--take-screenshot`)
34
- const keepOpen = values['screenshot-keep-open'] ?? false
35
37
  args.push(
36
38
  JSON.stringify({
37
39
  delay: Number(values['screenshot-delay']) || 1000,
38
40
  width: Number(values['screenshot-width']) || 600,
39
41
  height: Number(values['screenshot-height']) || 480,
40
42
  path: values['screenshot-path'] || `${cwd}/screenshot.jpg`,
41
- keepOpen,
42
43
  noHeadless: values['screenshot-no-headless'] ?? false,
43
44
  }),
44
45
  )
45
- needWatcher = keepOpen
46
+ needWatcher = !values['no-keep-open']
47
+ }
48
+
49
+ if (values['show-menu']) {
50
+ args.push('--show-menu')
51
+ }
52
+
53
+ if (values['test-id']) {
54
+ args.push('--test-id', values['test-id'])
55
+ }
56
+
57
+ if (values['test-title-like']) {
58
+ args.push('--test-title-like', values['test-title-like'])
59
+ }
60
+
61
+ if (values['no-keep-open']) {
62
+ args.push('--no-keep-open')
46
63
  }
47
64
 
48
65
  const useTypecheck = !values['skip-typecheck']
@@ -63,6 +80,36 @@ if (needWatcher) {
63
80
  })
64
81
  }
65
82
 
66
- await $`BRICKS_STAGE=${app.stage || 'production'} bunx --bun electron ${__dirname}/preview-main.mjs ${args}`
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
+ })
88
+
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
+ })
108
+ }
109
+ }
110
+ }
111
+
112
+ await processOutput()
113
+ await proc.exited
67
114
 
68
115
  if (watcher) watcher.close()
package/tools/pull.ts CHANGED
@@ -1,36 +1,57 @@
1
1
  import { $ } from 'bun'
2
2
  import { format } from 'prettier'
3
- import { pullApplicationProject, pullModuleProject } from '../api'
4
3
 
5
4
  const cwd = process.cwd()
6
5
 
6
+ // Check git status
7
7
  const { exitCode } = await $`cd ${cwd} && git status`.nothrow()
8
8
  const isGitRepo = exitCode === 0
9
9
 
10
10
  if (isGitRepo) {
11
11
  const unstagedChanges = await $`cd ${cwd} && git diff --name-only --diff-filter=ACMR`.text()
12
12
  if (unstagedChanges)
13
- throw new Error('Unstaged changes found, please commit or stash your changes before deploying')
13
+ throw new Error('Unstaged changes found, please commit or stash your changes before pulling')
14
+ } else {
15
+ const confirmContinue = prompt(
16
+ 'No git repository found, so it will not be safe to pull, continue? (y/n)',
17
+ )
18
+ if (confirmContinue !== 'y') throw new Error('Pull cancelled')
14
19
  }
15
20
 
21
+ // Read application.json
16
22
  const app = await Bun.file(`${cwd}/application.json`).json()
17
- const stage = app.stage || 'production'
18
- const { files, lastCommitId } =
19
- app.type === 'module'
20
- ? await pullModuleProject(stage, app.id)
21
- : await pullApplicationProject(stage, app.id)
23
+
24
+ const isModule = app.type === 'module'
25
+ const command = isModule ? 'module' : 'app'
26
+
27
+ // Fetch project files using CLI
28
+ const result = await $`bricks ${command} project-pull ${app.id} --json`.quiet().nothrow()
29
+
30
+ if (result.exitCode !== 0) {
31
+ const output = result.stderr.toString() || result.stdout.toString()
32
+ try {
33
+ const json = JSON.parse(output)
34
+ throw new Error(json.error || 'Pull failed')
35
+ } catch {
36
+ throw new Error(output || 'Pull failed')
37
+ }
38
+ }
39
+
40
+ const { files, lastCommitId } = JSON.parse(result.stdout.toString())
22
41
 
23
42
  let useMain = false
24
43
  if (isGitRepo) {
25
44
  const found = (await $`cd ${cwd} && git rev-list -1 ${lastCommitId}`.nothrow().text())
26
45
  .trim()
27
- .match(/^[a-f0-9]{40}$/)
46
+ .match(/^[\da-f]{40}$/)
28
47
 
29
48
  const commitId = (await $`cd ${cwd} && git rev-parse HEAD`.text()).trim()
30
49
 
31
50
  if (commitId === lastCommitId) throw new Error('Commit not changed')
32
51
 
33
- const branchName = 'BRICKS_PROJECT_try-pull-application'
52
+ const branchName = isModule
53
+ ? 'BRICKS_PROJECT_try-pull-module'
54
+ : 'BRICKS_PROJECT_try-pull-application'
34
55
 
35
56
  await $`cd ${cwd} && git branch -D ${branchName}`.nothrow()
36
57
 
@@ -40,11 +61,6 @@ if (isGitRepo) {
40
61
  await $`cd ${cwd} && git checkout -b ${branchName}`
41
62
  useMain = true
42
63
  }
43
- } else {
44
- const confirmContinue = prompt(
45
- 'No git repository found, so it will not be safe to pull, continue? (y/n)',
46
- )
47
- if (confirmContinue !== 'y') throw new Error('Pull cancelled')
48
64
  }
49
65
 
50
66
  const prettierConfig = await Bun.file(`${cwd}/.prettierrc`)
@@ -58,7 +74,7 @@ const prettierConfig = await Bun.file(`${cwd}/.prettierrc`)
58
74
  }))
59
75
 
60
76
  await Promise.all(
61
- files.map(async (file) =>
77
+ files.map(async (file: { name: string; input: string; formatable?: boolean }) =>
62
78
  Bun.write(
63
79
  `${cwd}/${file.name}`,
64
80
  file.formatable
@@ -70,8 +86,13 @@ await Promise.all(
70
86
 
71
87
  if (isGitRepo) {
72
88
  await $`cd ${cwd} && git add .`
73
- await $`cd ${cwd} && git commit -m 'Apply ${app.name} file changes'`
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}`
74
93
  if (!useMain) {
75
94
  await $`cd ${cwd} && git merge main`
76
95
  }
77
96
  }
97
+
98
+ console.log(`${isModule ? 'Module' : 'App'} project pulled: ${files.length} files`)
@@ -0,0 +1,232 @@
1
+ /**
2
+ * Automation (Test) System Types
3
+ *
4
+ * This module defines TypeScript types for the BRICKS automation/testing system.
5
+ * The automation system allows defining automated test sequences that can be
6
+ * triggered on launch, anytime, or via cron schedules.
7
+ */
8
+
9
+ import type { Subspace } from './subspace'
10
+ import type { Brick, Generator } from './common'
11
+ import type { Canvas } from './canvas'
12
+ import type { Data } from './data'
13
+
14
+ // Entity reference types - can be string ID or getter function
15
+ export type SubspaceRef = string | (() => Subspace)
16
+ export type BrickRef = string | (() => Brick)
17
+ export type GeneratorRef = string | (() => Generator)
18
+ export type CanvasRef = string | (() => Canvas)
19
+ export type DataRef = string | (() => Data)
20
+
21
+ // Variable types for test variables
22
+ export type TestVariableType = 'string' | 'number' | 'array' | 'object' | 'bool' | 'any'
23
+
24
+ // Trigger types for when tests should run
25
+ export type TestTriggerType = 'launch' | 'anytime' | 'cron'
26
+
27
+ // Jump condition operators for conditional test flow
28
+ export type JumpConditionOperator = '==' | '!=' | '>' | '>=' | '<' | '<='
29
+
30
+ // Jump condition status types
31
+ export type JumpConditionStatus = 'finished' | 'failed'
32
+
33
+ // Jump condition types
34
+ export type JumpConditionType = 'status' | 'variable'
35
+
36
+ /**
37
+ * Jump condition for controlling test case flow
38
+ */
39
+ export interface TestCaseJumpCondition {
40
+ type: JumpConditionType
41
+ // For status-based conditions
42
+ status?: JumpConditionStatus
43
+ // For variable-based conditions
44
+ variable?: string
45
+ operator?: JumpConditionOperator
46
+ value?: any
47
+ // The test case to jump to (getter function for dynamic IDs or string for static IDs)
48
+ jump_to: string | (() => TestCase)
49
+ }
50
+
51
+ /**
52
+ * Test variable definition
53
+ */
54
+ export interface TestVariable {
55
+ __typename: 'TestVariable'
56
+ id: string
57
+ name: string
58
+ type: TestVariableType
59
+ value: any
60
+ }
61
+
62
+ /**
63
+ * Post delay rules for test cases
64
+ */
65
+ export type PostDelayRule = 'include-action-time' | 'exclude-action-time'
66
+
67
+ /**
68
+ * Test method names (13 methods)
69
+ */
70
+ export type TestMethodName =
71
+ | 'brick_press'
72
+ | 'brick_exists'
73
+ | 'wait_until_brick_exists'
74
+ | 'wait_until_event_trigger'
75
+ | 'wait_until_canvas_change'
76
+ | 'keydown'
77
+ | 'keyup'
78
+ | 'http_request'
79
+ | 'assert_property'
80
+ | 'wait_until_property_change'
81
+ | 'execute_action'
82
+ | 'match_screenshot'
83
+ | 'delay'
84
+
85
+ /**
86
+ * Run array types for each test method
87
+ * Each method has a specific signature: [methodName, ...args]
88
+ */
89
+
90
+ // [methodName, subspaceId, brickId, options?]
91
+ export type TestMethodRunBrickPress = ['brick_press', SubspaceRef, BrickRef, Record<string, any>?]
92
+
93
+ // [methodName, subspaceId, brickId, frame?]
94
+ export type TestMethodRunBrickExists = ['brick_exists', SubspaceRef, BrickRef, Record<string, any>?]
95
+
96
+ // [methodName, subspaceId, brickId, timeout?, frame?]
97
+ export type TestMethodRunWaitUntilBrickExists = [
98
+ 'wait_until_brick_exists',
99
+ SubspaceRef,
100
+ BrickRef,
101
+ number?,
102
+ Record<string, any>?,
103
+ ]
104
+
105
+ // [methodName, subspaceId, senderId, eventKey, timeout?]
106
+ // senderId can be brick or generator
107
+ export type TestMethodRunWaitUntilEventTrigger = [
108
+ 'wait_until_event_trigger',
109
+ SubspaceRef,
110
+ BrickRef | GeneratorRef,
111
+ string,
112
+ number?,
113
+ ]
114
+
115
+ // [methodName, subspaceId, canvasId, timeout?]
116
+ export type TestMethodRunWaitUntilCanvasChange = [
117
+ 'wait_until_canvas_change',
118
+ SubspaceRef,
119
+ CanvasRef,
120
+ number?,
121
+ ]
122
+
123
+ // [methodName, keyCode, pressedKey?, flags?]
124
+ export type TestMethodRunKeydown = ['keydown', number, string?, number?]
125
+
126
+ // [methodName, keyCode, pressedKey?, flags?]
127
+ export type TestMethodRunKeyup = ['keyup', number, string?, number?]
128
+
129
+ // [methodName, url, options?]
130
+ export type TestMethodRunHttpRequest = ['http_request', string, Record<string, any>?]
131
+
132
+ // [methodName, subspaceId, propertyId, value]
133
+ export type TestMethodRunAssertProperty = ['assert_property', SubspaceRef, DataRef, any]
134
+
135
+ // [methodName, subspaceId, propertyId, value, timeout?]
136
+ export type TestMethodRunWaitUntilPropertyChange = [
137
+ 'wait_until_property_change',
138
+ SubspaceRef,
139
+ DataRef,
140
+ any,
141
+ number?,
142
+ ]
143
+
144
+ // [methodName, subspaceId, handler, action, params?, options?]
145
+ export type TestMethodRunExecuteAction = [
146
+ 'execute_action',
147
+ SubspaceRef,
148
+ string,
149
+ string,
150
+ Record<string, any>?,
151
+ Record<string, any>?,
152
+ ]
153
+
154
+ // [methodName, screenshotName, threshold?, maxRetry?]
155
+ export type TestMethodRunMatchScreenshot = ['match_screenshot', string, number?, number?]
156
+
157
+ // [methodName, subspaceId?, propertyId?, defaultValue?]
158
+ export type TestMethodRunDelay = ['delay', SubspaceRef?, DataRef?, number?]
159
+
160
+ /**
161
+ * Union type for all test method run arrays
162
+ */
163
+ export type TestMethodRun =
164
+ | TestMethodRunBrickPress
165
+ | TestMethodRunBrickExists
166
+ | TestMethodRunWaitUntilBrickExists
167
+ | TestMethodRunWaitUntilEventTrigger
168
+ | TestMethodRunWaitUntilCanvasChange
169
+ | TestMethodRunKeydown
170
+ | TestMethodRunKeyup
171
+ | TestMethodRunHttpRequest
172
+ | TestMethodRunAssertProperty
173
+ | TestMethodRunWaitUntilPropertyChange
174
+ | TestMethodRunExecuteAction
175
+ | TestMethodRunMatchScreenshot
176
+ | TestMethodRunDelay
177
+
178
+ /**
179
+ * Test case definition
180
+ */
181
+ export interface TestCase {
182
+ __typename: 'TestCase'
183
+ id: string
184
+ name: string
185
+ run: TestMethodRun
186
+ exit_on_failed: boolean
187
+ commented: boolean
188
+ pre_delay: number
189
+ post_delay: number
190
+ post_delay_rule?: PostDelayRule
191
+ jump_cond: TestCaseJumpCondition[]
192
+ }
193
+
194
+ /**
195
+ * Local sync mode for tests
196
+ */
197
+ export type LocalSyncMode = 'main-only' | 'minor-only'
198
+
199
+ /**
200
+ * Automation test definition
201
+ */
202
+ export interface AutomationTest {
203
+ __typename: 'AutomationTest'
204
+ id: string
205
+ title: string
206
+ timeout: number
207
+ trigger_type?: TestTriggerType
208
+ cron?: string // Cron expression when trigger_type is 'cron'
209
+ skip_trigger_type_check?: boolean
210
+ local_sync?: LocalSyncMode
211
+ cases: TestCase[]
212
+ variables: TestVariable[]
213
+ meta?: Record<string, any>
214
+ }
215
+
216
+ /**
217
+ * Automation test map (a collection of tests)
218
+ */
219
+ export interface AutomationTestMap {
220
+ __typename: 'AutomationTestMap'
221
+ id: string
222
+ title: string
223
+ createdAt: number
224
+ tests: AutomationTest[]
225
+ }
226
+
227
+ /**
228
+ * Root automation map type (record of automation test maps by ID)
229
+ */
230
+ export type AutomationMap = {
231
+ [mapId: string]: AutomationTestMap
232
+ }
@@ -1,3 +1,4 @@
1
+ /* Auto generated by build script */
1
2
  import type { SwitchCondInnerStateCurrentCanvas, SwitchCondData, SwitchDef } from './switch'
2
3
  import type { Data, DataLink } from './data'
3
4
  import type { Animation, AnimationBasicEvents } from './animation'
@@ -1,3 +1,4 @@
1
+ /* Auto generated by build script */
1
2
  import type { SwitchCondInnerStateCurrentCanvas, SwitchCondData, SwitchDef } from '../switch'
2
3
  import type { Data, DataLink } from '../data'
3
4
  import type { Animation, AnimationBasicEvents } from '../animation'
@@ -76,12 +77,27 @@ export type BrickCameraActionStopRecord = Action & {
76
77
  __actionName: 'BRICK_CAMERA_STOP_RECORD'
77
78
  }
78
79
 
80
+ /* Focus the Camera at a specific point */
81
+ export type BrickCameraActionFocus = ActionWithParams & {
82
+ __actionName: 'BRICK_CAMERA_FOCUS'
83
+ params?: Array<
84
+ | {
85
+ input: 'focusX'
86
+ value?: number | DataLink | EventProperty
87
+ mapping?: string
88
+ }
89
+ | {
90
+ input: 'focusY'
91
+ value?: number | DataLink | EventProperty
92
+ mapping?: string
93
+ }
94
+ >
95
+ }
96
+
79
97
  interface BrickCameraDef {
80
98
  /*
81
99
  Default property:
82
100
  {
83
- "autoFocusEnabled": false,
84
- "focusDepth": 0.5,
85
101
  "type": "back",
86
102
  "flashMode": "off",
87
103
  "captureAudio": false,
@@ -91,12 +107,10 @@ Default property:
91
107
  }
92
108
  */
93
109
  property?: BrickBasicProperty & {
94
- /* Camera auto focus */
95
- autoFocusEnabled?: boolean | DataLink
96
- /* The auto focus feature of the camera to attempt to focus on the part of the image at this coordinate. */
97
- focusDepth?: number | DataLink
98
- /* Camera type (Ignore it if you are using external camera) */
99
- type?: 'back' | 'front' | DataLink
110
+ /* Camera type */
111
+ type?: 'back' | 'front' | 'external' | DataLink
112
+ /* Enable or disable camera */
113
+ isActive?: boolean | DataLink
100
114
  /* Camera zoom */
101
115
  zoom?: number | DataLink
102
116
  /* Camera flash mode */
@@ -114,7 +128,7 @@ Default property:
114
128
  | 'incandescent'
115
129
  | 'fluorescent'
116
130
  | DataLink
117
- /* Enable face detection */
131
+ /* Enable face detection (Note: Barcode detection will be disabled when enabled) */
118
132
  faceDetectionEnabled?: boolean | DataLink
119
133
  /* Face detection event mode */
120
134
  faceDetectionEventMode?: 'when-detected' | 'interval' | DataLink
@@ -152,6 +166,8 @@ Default property:
152
166
  mountError?: Array<EventAction>
153
167
  }
154
168
  outlets?: {
169
+ /* Camera device and format information */
170
+ info?: () => Data
155
171
  /* Picture taken result */
156
172
  pictureTaken?: () => Data
157
173
  /* Record video result */
@@ -186,7 +202,7 @@ export type BrickCamera = Brick &
186
202
  | SwitchCondData
187
203
  | {
188
204
  __typename: 'SwitchCondInnerStateOutlet'
189
- outlet: 'pictureTaken' | 'recordVideo' | 'barcodeRead' | 'faceDetected'
205
+ outlet: 'info' | 'pictureTaken' | 'recordVideo' | 'barcodeRead' | 'faceDetected'
190
206
  value: any
191
207
  }
192
208
  }>
@@ -1,3 +1,4 @@
1
+ /* Auto generated by build script */
1
2
  import type { SwitchCondInnerStateCurrentCanvas, SwitchCondData, SwitchDef } from '../switch'
2
3
  import type { Data, DataLink } from '../data'
3
4
  import type { Animation, AnimationBasicEvents } from '../animation'