@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.
- package/api/instance.ts +37 -5
- package/compile/action-name-map.ts +81 -0
- package/compile/index.ts +164 -63
- package/compile/util.ts +13 -4
- package/package.json +8 -4
- package/skills/bricks-project/SKILL.md +32 -0
- package/skills/bricks-project/rules/animation.md +159 -0
- package/skills/bricks-project/rules/architecture-patterns.md +62 -0
- package/skills/bricks-project/rules/automations.md +175 -0
- package/skills/bricks-project/rules/buttress.md +153 -0
- package/skills/bricks-project/rules/data-calculation.md +208 -0
- package/skills/bricks-project/rules/local-sync.md +129 -0
- package/skills/bricks-project/rules/media-flow.md +158 -0
- package/skills/bricks-project/rules/remote-data-bank.md +196 -0
- package/skills/bricks-project/rules/standby-transition.md +124 -0
- package/skills/rive-marketplace/SKILL.md +99 -0
- package/tools/deploy.ts +74 -12
- package/tools/icons/.gitattributes +1 -0
- package/tools/icons/fa6pro-glyphmap.json +4686 -0
- package/tools/icons/fa6pro-meta.json +26127 -0
- package/tools/mcp-server.ts +812 -8
- package/tools/postinstall.ts +33 -13
- package/tools/preview-main.mjs +53 -4
- package/tools/preview.ts +53 -6
- package/tools/pull.ts +37 -16
- package/types/automation.ts +232 -0
- package/types/brick-base.ts +1 -0
- package/types/bricks/Camera.ts +26 -10
- package/types/bricks/Chart.ts +1 -0
- package/types/bricks/GenerativeMedia.ts +21 -3
- package/types/bricks/Icon.ts +1 -0
- package/types/bricks/Image.ts +6 -0
- package/types/bricks/Items.ts +1 -0
- package/types/bricks/Lottie.ts +1 -0
- package/types/bricks/Maps.ts +254 -0
- package/types/bricks/QrCode.ts +1 -0
- package/types/bricks/Rect.ts +1 -0
- package/types/bricks/RichText.ts +1 -0
- package/types/bricks/Rive.ts +1 -0
- package/types/bricks/Slideshow.ts +1 -0
- package/types/bricks/Svg.ts +1 -0
- package/types/bricks/Text.ts +1 -0
- package/types/bricks/TextInput.ts +1 -0
- package/types/bricks/Video.ts +1 -0
- package/types/bricks/VideoStreaming.ts +1 -0
- package/types/bricks/WebRtcStream.ts +1 -0
- package/types/bricks/WebView.ts +8 -1
- package/types/bricks/index.ts +2 -0
- package/types/canvas.ts +1 -0
- package/types/common.ts +2 -0
- package/types/data-calc-command.ts +7003 -0
- package/types/data-calc-script.ts +21 -0
- package/types/data-calc.ts +3 -6977
- package/types/data.ts +3 -0
- package/types/generators/AlarmClock.ts +2 -0
- package/types/generators/Assistant.ts +30 -6
- package/types/generators/BleCentral.ts +2 -0
- package/types/generators/BlePeripheral.ts +2 -0
- package/types/generators/CanvasMap.ts +2 -0
- package/types/generators/CastlesPay.ts +2 -0
- package/types/generators/DataBank.ts +2 -0
- package/types/generators/File.ts +2 -0
- package/types/generators/GraphQl.ts +2 -0
- package/types/generators/Http.ts +84 -2
- package/types/generators/HttpServer.ts +5 -1
- package/types/generators/Information.ts +2 -0
- package/types/generators/Intent.ts +51 -0
- package/types/generators/Iterator.ts +11 -2
- package/types/generators/Keyboard.ts +2 -0
- package/types/generators/LlmAnthropicCompat.ts +2 -0
- package/types/generators/LlmAppleBuiltin.ts +144 -0
- package/types/generators/LlmGgml.ts +28 -4
- package/types/generators/LlmOnnx.ts +2 -0
- package/types/generators/LlmOpenAiCompat.ts +2 -0
- package/types/generators/LlmQualcommAiEngine.ts +2 -0
- package/types/generators/Mcp.ts +6 -4
- package/types/generators/McpServer.ts +8 -6
- package/types/generators/MediaFlow.ts +2 -0
- package/types/generators/MqttBroker.ts +2 -0
- package/types/generators/MqttClient.ts +2 -0
- package/types/generators/Question.ts +9 -0
- package/types/generators/RealtimeTranscription.ts +4 -2
- package/types/generators/RerankerGgml.ts +23 -16
- package/types/generators/SerialPort.ts +2 -0
- package/types/generators/SoundPlayer.ts +2 -0
- package/types/generators/SoundRecorder.ts +2 -0
- package/types/generators/SpeechToTextGgml.ts +14 -4
- package/types/generators/SpeechToTextOnnx.ts +2 -0
- package/types/generators/SpeechToTextPlatform.ts +2 -0
- package/types/generators/SqLite.ts +32 -1
- package/types/generators/Step.ts +2 -0
- package/types/generators/SttAppleBuiltin.ts +117 -0
- package/types/generators/Tcp.ts +2 -0
- package/types/generators/TcpServer.ts +5 -1
- package/types/generators/TextToSpeechApple.ts +113 -0
- package/types/generators/TextToSpeechAppleBuiltin.ts +114 -0
- package/types/generators/TextToSpeechGgml.ts +24 -3
- package/types/generators/TextToSpeechOnnx.ts +2 -0
- package/types/generators/TextToSpeechOpenAiLike.ts +2 -0
- package/types/generators/ThermalPrinter.ts +2 -0
- package/types/generators/Tick.ts +5 -1
- package/types/generators/TtsAppleBuiltin.ts +105 -0
- package/types/generators/Udp.ts +2 -0
- package/types/generators/VadGgml.ts +4 -2
- package/types/generators/VectorStore.ts +15 -2
- package/types/generators/Watchdog.ts +2 -0
- package/types/generators/WebCrawler.ts +2 -0
- package/types/generators/WebRtc.ts +4 -2
- package/types/generators/WebSocket.ts +2 -0
- package/types/generators/index.ts +3 -0
- package/types/index.ts +3 -0
- package/types/system.ts +48 -6
- package/utils/calc.ts +5 -1
- package/utils/data.ts +1 -0
- package/utils/event-props.ts +85 -2
- package/utils/id.ts +3 -1
package/tools/postinstall.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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 (
|
|
67
|
-
|
|
68
|
-
const
|
|
69
|
-
|
|
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
|
}
|
package/tools/preview-main.mjs
CHANGED
|
@@ -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
|
|
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 (
|
|
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',
|
|
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
|
-
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
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(/^[
|
|
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 =
|
|
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
|
-
|
|
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
|
+
}
|
package/types/brick-base.ts
CHANGED
package/types/bricks/Camera.ts
CHANGED
|
@@ -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
|
|
95
|
-
|
|
96
|
-
/*
|
|
97
|
-
|
|
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
|
}>
|
package/types/bricks/Chart.ts
CHANGED