@fugood/bricks-project 2.25.0-beta.5 → 2.25.0-beta.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compile/action-name-map.ts +64 -0
- package/compile/config-diff.ts +155 -0
- package/compile/index.ts +273 -32
- package/compile/util.ts +26 -7
- package/package.json +8 -3
- package/package.json.bak +8 -3
- package/skills/bricks-ctor/SKILL.md +23 -17
- package/skills/bricks-ctor/{rules → references}/animation.md +3 -2
- package/skills/bricks-ctor/{rules → references}/architecture-patterns.md +18 -0
- package/skills/bricks-ctor/{rules → references}/automations.md +11 -0
- package/skills/bricks-ctor/references/buttress.md +245 -0
- package/skills/bricks-ctor/references/data-calculation.md +239 -0
- package/skills/bricks-ctor/references/simulator.md +132 -0
- package/skills/bricks-ctor/references/source-editing-tools.md +81 -0
- package/skills/bricks-ctor/references/verification-toolchain.md +200 -0
- package/skills/bricks-design/SKILL.md +150 -45
- package/skills/bricks-design/references/architecture-truths.md +132 -0
- package/skills/bricks-design/references/avoiding-complexity.md +91 -0
- package/skills/bricks-design/references/design-critique.md +195 -0
- package/skills/bricks-design/references/design-languages.md +265 -0
- package/skills/bricks-design/references/performance.md +116 -0
- package/skills/bricks-design/references/presentation-and-slideshow.md +137 -0
- package/skills/bricks-design/references/translating-inputs.md +152 -0
- package/skills/bricks-design/references/variations-and-tweaks.md +124 -0
- package/skills/bricks-design/references/when-the-brief-is-branded.md +284 -0
- package/skills/bricks-design/references/when-the-brief-is-vague.md +85 -0
- package/skills/bricks-design/references/workflow.md +134 -0
- package/skills/bricks-ux/SKILL.md +114 -0
- package/skills/bricks-ux/references/accessibility.md +162 -0
- package/skills/bricks-ux/references/flow-states.md +175 -0
- package/skills/bricks-ux/references/interaction-archetypes.md +189 -0
- package/skills/bricks-ux/references/monitoring-screens.md +153 -0
- package/skills/bricks-ux/references/pressable-composition.md +126 -0
- package/skills/bricks-ux/references/user-journey.md +168 -0
- package/skills/bricks-ux/references/ux-critique.md +256 -0
- package/tools/_cli-error.ts +17 -0
- package/tools/_edits-log.ts +41 -0
- package/tools/_git-author.ts +10 -2
- package/tools/_last-pushed-commit.ts +28 -0
- package/tools/_shell.ts +8 -1
- package/tools/deploy.ts +17 -6
- package/tools/mcp-env.ts +13 -0
- package/tools/mcp-server.ts +8 -0
- package/tools/mcp-tools/_editing-helpers.ts +58 -0
- package/tools/mcp-tools/_verify.ts +50 -0
- package/tools/mcp-tools/compile.ts +21 -9
- package/tools/mcp-tools/data-calc-editing.ts +1349 -0
- package/tools/mcp-tools/entry-editing.ts +2336 -0
- package/tools/mcp-tools/huggingface.ts +23 -13
- package/tools/mcp-tools/icons.ts +23 -7
- package/tools/mcp-tools/media.ts +4 -1
- package/tools/postinstall.ts +80 -3
- package/tools/pull.ts +93 -22
- package/tools/push-config.ts +114 -0
- package/tools/{preview-main.mjs → simulator-main.mjs} +207 -12
- package/tools/simulator-preload.cjs +16 -0
- package/tools/{preview.ts → simulator.ts} +4 -4
- package/types/{animation.ts → animation.d.ts} +24 -8
- package/types/{automation.ts → automation.d.ts} +16 -20
- package/types/{brick-base.ts → brick-base.d.ts} +1 -1
- package/types/bricks/{Camera.ts → Camera.d.ts} +8 -8
- package/types/bricks/{Chart.ts → Chart.d.ts} +4 -4
- package/types/bricks/{GenerativeMedia.ts → GenerativeMedia.d.ts} +15 -15
- package/types/bricks/{Icon.ts → Icon.d.ts} +7 -7
- package/types/bricks/{Image.ts → Image.d.ts} +21 -9
- package/types/bricks/{Items.ts → Items.d.ts} +7 -7
- package/types/bricks/{Lottie.ts → Lottie.d.ts} +10 -10
- package/types/bricks/{Maps.ts → Maps.d.ts} +11 -11
- package/types/bricks/{QrCode.ts → QrCode.d.ts} +7 -7
- package/types/bricks/{Rect.ts → Rect.d.ts} +7 -7
- package/types/bricks/{RichText.ts → RichText.d.ts} +12 -9
- package/types/bricks/{Rive.ts → Rive.d.ts} +9 -9
- package/types/bricks/Scene3D.d.ts +676 -0
- package/types/bricks/{Sketch.ts → Sketch.d.ts} +6 -6
- package/types/bricks/{Slideshow.ts → Slideshow.d.ts} +7 -7
- package/types/bricks/{Svg.ts → Svg.d.ts} +7 -7
- package/types/bricks/{Text.ts → Text.d.ts} +9 -9
- package/types/bricks/{TextInput.ts → TextInput.d.ts} +10 -10
- package/types/bricks/{Video.ts → Video.d.ts} +12 -12
- package/types/bricks/{VideoStreaming.ts → VideoStreaming.d.ts} +10 -10
- package/types/bricks/{WebRtcStream.ts → WebRtcStream.d.ts} +1 -1
- package/types/bricks/{WebView.ts → WebView.d.ts} +4 -4
- package/types/bricks/{index.ts → index.d.ts} +1 -0
- package/types/{common.ts → common.d.ts} +3 -6
- package/types/data-calc-command/base.d.ts +57 -0
- package/types/data-calc-command/collection.d.ts +418 -0
- package/types/data-calc-command/color.d.ts +432 -0
- package/types/data-calc-command/constant.d.ts +50 -0
- package/types/data-calc-command/datetime.d.ts +147 -0
- package/types/data-calc-command/file.d.ts +129 -0
- package/types/data-calc-command/index.d.ts +13 -0
- package/types/data-calc-command/iteratee.d.ts +23 -0
- package/types/data-calc-command/logictype.d.ts +190 -0
- package/types/data-calc-command/math.d.ts +275 -0
- package/types/data-calc-command/object.d.ts +119 -0
- package/types/data-calc-command/sandbox.d.ts +66 -0
- package/types/data-calc-command/string.d.ts +407 -0
- package/types/{data-calc.ts → data-calc.d.ts} +1 -0
- package/types/{data.ts → data.d.ts} +4 -2
- package/types/generators/{Assistant.ts → Assistant.d.ts} +19 -0
- package/types/generators/{LlmGgml.ts → LlmGgml.d.ts} +43 -1
- package/types/generators/{LlmMlx.ts → LlmMlx.d.ts} +1 -0
- package/types/generators/{RerankerGgml.ts → RerankerGgml.d.ts} +5 -1
- package/types/generators/{SoundRecorder.ts → SoundRecorder.d.ts} +10 -1
- package/types/generators/{SpeechToTextGgml.ts → SpeechToTextGgml.d.ts} +6 -1
- package/types/generators/{SttAppleBuiltin.ts → SttAppleBuiltin.d.ts} +27 -4
- package/types/generators/{ThermalPrinter.ts → ThermalPrinter.d.ts} +9 -7
- package/types/generators/{VadGgml.ts → VadGgml.d.ts} +12 -2
- package/types/{subspace.ts → subspace.d.ts} +1 -1
- package/utils/calc.ts +5 -1
- package/utils/data.ts +5 -7
- package/utils/event-props.ts +17 -0
- package/utils/id.ts +109 -56
- package/skills/bricks-ctor/rules/buttress.md +0 -156
- package/skills/bricks-ctor/rules/data-calculation.md +0 -209
- package/skills/bricks-design/LICENSE.txt +0 -180
- package/types/data-calc-command.ts +0 -7005
- /package/skills/bricks-ctor/{rules → references}/local-sync.md +0 -0
- /package/skills/bricks-ctor/{rules → references}/media-flow.md +0 -0
- /package/skills/bricks-ctor/{rules → references}/remote-data-bank.md +0 -0
- /package/skills/bricks-ctor/{rules → references}/standby-transition.md +0 -0
- /package/types/{canvas.ts → canvas.d.ts} +0 -0
- /package/types/{data-calc-script.ts → data-calc-script.d.ts} +0 -0
- /package/types/generators/{AlarmClock.ts → AlarmClock.d.ts} +0 -0
- /package/types/generators/{BleCentral.ts → BleCentral.d.ts} +0 -0
- /package/types/generators/{BlePeripheral.ts → BlePeripheral.d.ts} +0 -0
- /package/types/generators/{CanvasMap.ts → CanvasMap.d.ts} +0 -0
- /package/types/generators/{CastlesPay.ts → CastlesPay.d.ts} +0 -0
- /package/types/generators/{DataBank.ts → DataBank.d.ts} +0 -0
- /package/types/generators/{File.ts → File.d.ts} +0 -0
- /package/types/generators/{GraphQl.ts → GraphQl.d.ts} +0 -0
- /package/types/generators/{Http.ts → Http.d.ts} +0 -0
- /package/types/generators/{HttpServer.ts → HttpServer.d.ts} +0 -0
- /package/types/generators/{Information.ts → Information.d.ts} +0 -0
- /package/types/generators/{Intent.ts → Intent.d.ts} +0 -0
- /package/types/generators/{Iterator.ts → Iterator.d.ts} +0 -0
- /package/types/generators/{Keyboard.ts → Keyboard.d.ts} +0 -0
- /package/types/generators/{LlmAnthropicCompat.ts → LlmAnthropicCompat.d.ts} +0 -0
- /package/types/generators/{LlmAppleBuiltin.ts → LlmAppleBuiltin.d.ts} +0 -0
- /package/types/generators/{LlmMediaTekNeuroPilot.ts → LlmMediaTekNeuroPilot.d.ts} +0 -0
- /package/types/generators/{LlmOnnx.ts → LlmOnnx.d.ts} +0 -0
- /package/types/generators/{LlmOpenAiCompat.ts → LlmOpenAiCompat.d.ts} +0 -0
- /package/types/generators/{LlmQualcommAiEngine.ts → LlmQualcommAiEngine.d.ts} +0 -0
- /package/types/generators/{Mcp.ts → Mcp.d.ts} +0 -0
- /package/types/generators/{McpServer.ts → McpServer.d.ts} +0 -0
- /package/types/generators/{MediaFlow.ts → MediaFlow.d.ts} +0 -0
- /package/types/generators/{MqttBroker.ts → MqttBroker.d.ts} +0 -0
- /package/types/generators/{MqttClient.ts → MqttClient.d.ts} +0 -0
- /package/types/generators/{Question.ts → Question.d.ts} +0 -0
- /package/types/generators/{RealtimeTranscription.ts → RealtimeTranscription.d.ts} +0 -0
- /package/types/generators/{SerialPort.ts → SerialPort.d.ts} +0 -0
- /package/types/generators/{SoundPlayer.ts → SoundPlayer.d.ts} +0 -0
- /package/types/generators/{SpeechToTextOnnx.ts → SpeechToTextOnnx.d.ts} +0 -0
- /package/types/generators/{SpeechToTextPlatform.ts → SpeechToTextPlatform.d.ts} +0 -0
- /package/types/generators/{SqLite.ts → SqLite.d.ts} +0 -0
- /package/types/generators/{Step.ts → Step.d.ts} +0 -0
- /package/types/generators/{Tcp.ts → Tcp.d.ts} +0 -0
- /package/types/generators/{TcpServer.ts → TcpServer.d.ts} +0 -0
- /package/types/generators/{TextToSpeechAppleBuiltin.ts → TextToSpeechAppleBuiltin.d.ts} +0 -0
- /package/types/generators/{TextToSpeechGgml.ts → TextToSpeechGgml.d.ts} +0 -0
- /package/types/generators/{TextToSpeechOnnx.ts → TextToSpeechOnnx.d.ts} +0 -0
- /package/types/generators/{TextToSpeechOpenAiLike.ts → TextToSpeechOpenAiLike.d.ts} +0 -0
- /package/types/generators/{Tick.ts → Tick.d.ts} +0 -0
- /package/types/generators/{Udp.ts → Udp.d.ts} +0 -0
- /package/types/generators/{VadOnnx.ts → VadOnnx.d.ts} +0 -0
- /package/types/generators/{VadTraditional.ts → VadTraditional.d.ts} +0 -0
- /package/types/generators/{VectorStore.ts → VectorStore.d.ts} +0 -0
- /package/types/generators/{Watchdog.ts → Watchdog.d.ts} +0 -0
- /package/types/generators/{WebCrawler.ts → WebCrawler.d.ts} +0 -0
- /package/types/generators/{WebRtc.ts → WebRtc.d.ts} +0 -0
- /package/types/generators/{WebSocket.ts → WebSocket.d.ts} +0 -0
- /package/types/generators/{index.ts → index.d.ts} +0 -0
- /package/types/{index.ts → index.d.ts} +0 -0
- /package/types/{switch.ts → switch.d.ts} +0 -0
- /package/types/{system.ts → system.d.ts} +0 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# Data Calculation (JS Sandbox)
|
|
2
|
+
|
|
3
|
+
Transform and compute Data Bank values using JavaScript scripts. Calcs are for **pure data transformation only** — see [Architecture Patterns](architecture-patterns.md) for the pattern selection guide.
|
|
4
|
+
|
|
5
|
+
| If you need to... | Use instead |
|
|
6
|
+
|---|---|
|
|
7
|
+
| Call an LLM / AI model | Generator (Assistant, LLM, HTTP) |
|
|
8
|
+
| Sequence multiple actions | Event Action Chain |
|
|
9
|
+
| Set a data value directly | PROPERTY_BANK system action |
|
|
10
|
+
| Compute a simple expression | PROPERTY_BANK_EXPRESSION |
|
|
11
|
+
| Transform/format/parse data | Data Calculation (correct use) |
|
|
12
|
+
|
|
13
|
+
## Authoring Contract
|
|
14
|
+
|
|
15
|
+
```typescript
|
|
16
|
+
import { makeId } from 'bricks-ctor'
|
|
17
|
+
import { readFile } from 'node:fs/promises'
|
|
18
|
+
|
|
19
|
+
const calculation: DataCalculationScript = {
|
|
20
|
+
__typename: 'DataCalculationScript',
|
|
21
|
+
id: makeId('property_bank_calc'),
|
|
22
|
+
title: 'Format Price',
|
|
23
|
+
description: 'Formats price with currency symbol',
|
|
24
|
+
note: '',
|
|
25
|
+
triggerMode: 'auto', // 'auto' (default) | 'manual'
|
|
26
|
+
enableAsync: false,
|
|
27
|
+
// Inline code for short scripts...
|
|
28
|
+
code: `
|
|
29
|
+
const price = inputs.price || 0
|
|
30
|
+
const currency = inputs.currency || 'USD'
|
|
31
|
+
return new Intl.NumberFormat('en-US', {
|
|
32
|
+
style: 'currency',
|
|
33
|
+
currency,
|
|
34
|
+
}).format(price)
|
|
35
|
+
`,
|
|
36
|
+
// ...or load from a file (preferred for longer scripts):
|
|
37
|
+
// code: await readFile(new URL('./format-price.sandbox.js', import.meta.url), 'utf8'),
|
|
38
|
+
inputs: [
|
|
39
|
+
{ key: 'price', data: () => priceData, trigger: true },
|
|
40
|
+
{ key: 'currency', data: () => currencyData, trigger: false },
|
|
41
|
+
],
|
|
42
|
+
output: () => formattedPriceData,
|
|
43
|
+
outputs: [], // Additional named outputs (see Multiple Outputs)
|
|
44
|
+
error: null, // or () => errorData for error handling
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Field Rules (defaults and constraints)
|
|
49
|
+
|
|
50
|
+
- `trigger` **defaults to `false` when omitted** — always set it explicitly. A calc whose inputs are all non-trigger never auto-runs.
|
|
51
|
+
- `triggerMode` defaults to `'auto'` when omitted.
|
|
52
|
+
- `output` receives the **whole return value**. `outputs` entries extract fields by key from a returned object — `key` is a lodash-get path, so deep paths like `'user.name'` work. `output`, `outputs`, and `error` can be combined.
|
|
53
|
+
- `error` receives the error **message string** when the script throws. Both extraction steps run on every execution: a success overwrites the error Data, a failure overwrites the output Data(s) — don't expect stale values to persist.
|
|
54
|
+
- **Auto mode rejects the same Data in both `inputs` and `output`/`outputs`/`error`** — compile fails with `Not allow duplicate set property id between inputs / outputs / output / error`. Manual mode allows the overlap (self-referential updates, see Recipes).
|
|
55
|
+
- `.sandbox.js` files use an `export function main() { ... }` wrapper — compile unwraps it. Raw statements also work, but the wrapper keeps linters happy since script bodies use top-level `return`.
|
|
56
|
+
|
|
57
|
+
## Trigger Modes
|
|
58
|
+
|
|
59
|
+
| Mode | Description |
|
|
60
|
+
|------|-------------|
|
|
61
|
+
| `auto` | Run on every write to a `trigger: true` input (even if the value is unchanged) |
|
|
62
|
+
| `manual` | Never auto-runs; only via `PROPERTY_BANK_COMMAND` action. Allows the same Data as both input and output |
|
|
63
|
+
|
|
64
|
+
Use `manual` to prevent circular dependencies, for explicit control, or when an output must feed back into an input.
|
|
65
|
+
|
|
66
|
+
## Triggering via PROPERTY_BANK_COMMAND
|
|
67
|
+
|
|
68
|
+
`input` references a Data that is an input of the target calc — the system runs the calc(s) that data feeds into. It does NOT reference the DataCalculation itself.
|
|
69
|
+
|
|
70
|
+
- **Manual calc**: ANY input works — `trigger` flags are ignored for manual-mode calcs.
|
|
71
|
+
- **Auto calc**: only `trigger: true` inputs work; commanding a `trigger: false` input is a silent no-op.
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
const triggerCalc: EventAction = {
|
|
75
|
+
handler: 'system',
|
|
76
|
+
action: {
|
|
77
|
+
__actionName: 'PROPERTY_BANK_COMMAND',
|
|
78
|
+
parent: 'System',
|
|
79
|
+
dataParams: [
|
|
80
|
+
{ input: () => priceData }, // Reference to an input Data of the calc
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
- When the same chain **writes a calc input first** (e.g. `PROPERTY_BANK` setting `dLastButton`) then issues `PROPERTY_BANK_COMMAND`, set `waitAsync: true` on the write so the calc reads the new value rather than the pre-chain snapshot. See [Event Action Chains](architecture-patterns.md#event-action-chains-priority-2).
|
|
87
|
+
- When a **later action reads the calc's outputs**, set `waitAsync: true` on the `PROPERTY_BANK_COMMAND` action itself — it awaits the full calc chain including output writes.
|
|
88
|
+
- A dataParam's `value` acts as an execution gate: `{ input: () => d, value: false }` skips that trigger (combine with `mapping` for conditional runs).
|
|
89
|
+
|
|
90
|
+
## Script Sandbox
|
|
91
|
+
|
|
92
|
+
Scripts run in `use strict` mode as a function body — top-level `return` returns the calc result. No `fetch`, `XMLHttpRequest`, or `require` in any mode: I/O belongs to Generators.
|
|
93
|
+
|
|
94
|
+
### Built-in Globals
|
|
95
|
+
|
|
96
|
+
| Global | Description |
|
|
97
|
+
|--------|-------------|
|
|
98
|
+
| `inputs` | Object with input values (keyed by input `key`) |
|
|
99
|
+
| `console` | `{ log, error, warn, info }` — output is only visible in DevTools debug sessions; production is a no-op |
|
|
100
|
+
| `Platform` | `{ OS, isTV, isPad, isVision, isElectron }` |
|
|
101
|
+
| `TextEncoder`, `TextDecoder` | Text encoding/decoding |
|
|
102
|
+
| `Buffer` | Node.js Buffer (without `allocUnsafe`/`allocUnsafeSlow`) |
|
|
103
|
+
| `btoa`, `atob` | Base64 encoding/decoding |
|
|
104
|
+
|
|
105
|
+
### Async Mode
|
|
106
|
+
|
|
107
|
+
Sync mode (default) has **no `Promise`, timers, or `await`**. Enable `enableAsync: true` to unlock:
|
|
108
|
+
|
|
109
|
+
- `Promise`, `setTimeout`, `setInterval`, `setImmediate`, `clearTimeout`, `clearInterval`, `clearImmediate`, `requestAnimationFrame`
|
|
110
|
+
- Full lodash (sync mode omits `debounce`, `delay`, `defer`)
|
|
111
|
+
- `await` at the top level of the script
|
|
112
|
+
|
|
113
|
+
```typescript
|
|
114
|
+
code: `
|
|
115
|
+
const result = await new Promise((resolve) => {
|
|
116
|
+
setTimeout(() => resolve(inputs.value * 2), 100)
|
|
117
|
+
})
|
|
118
|
+
return result
|
|
119
|
+
`,
|
|
120
|
+
enableAsync: true,
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Runtime Environment
|
|
124
|
+
|
|
125
|
+
| Platform | Engine |
|
|
126
|
+
|----------|--------|
|
|
127
|
+
| Android | Hermes engine sandbox |
|
|
128
|
+
| iOS | JavaScriptCore sandbox |
|
|
129
|
+
| Electron desktop | Web Worker (V8) |
|
|
130
|
+
| Web preview / Simulator | Web Worker (V8) |
|
|
131
|
+
|
|
132
|
+
Simulator (Path 1) runs scripts on V8 while devices run Hermes/JSC — engine-sensitive code (date parsing, Intl, regex features) can pass in the Simulator and fail on device.
|
|
133
|
+
|
|
134
|
+
### Available Libraries
|
|
135
|
+
|
|
136
|
+
All exposed as globals. No network/file-download capability in any of them.
|
|
137
|
+
|
|
138
|
+
| Global | Library | Notes |
|
|
139
|
+
|--------|---------|-------|
|
|
140
|
+
| `_`, `lodash` | lodash | Sync mode omits `debounce`/`delay`/`defer` |
|
|
141
|
+
| `voca` | voca | String manipulation |
|
|
142
|
+
| `invariant` | invariant | Assertions |
|
|
143
|
+
| `json5` | json5 | JSON5 parsing |
|
|
144
|
+
| `qs` | qs | Query string parsing |
|
|
145
|
+
| `url` | node-url | URL parsing |
|
|
146
|
+
| `bytes` | bytes | Byte parsing/formatting |
|
|
147
|
+
| `ms` | ms | Millisecond conversion |
|
|
148
|
+
| `base45` | base45 | Base45 encoding |
|
|
149
|
+
| `iconv` | iconv-lite | Character encoding |
|
|
150
|
+
| `math`, `mathjs` | mathjs | Math library |
|
|
151
|
+
| `chroma` | chroma-js | Color manipulation |
|
|
152
|
+
| `moment` | moment | Date/time; auto parseFormat for string args |
|
|
153
|
+
| `nanoid` | nanoid | Unique ID generation |
|
|
154
|
+
| `md5` | md5 | MD5 hashing |
|
|
155
|
+
| `crypto` | crypto-browserify | Crypto functions |
|
|
156
|
+
| `kjurJWS` | jsrsasign | JWT/JWS signing (`KJUR.jws.JWS`) |
|
|
157
|
+
| `coseVerify` | cose-js | COSE verification (sync) |
|
|
158
|
+
| `fflate` | fflate | `{ zlibSync, unzlibSync, gzipSync, gunzipSync, compressSync, decompressSync, strFromU8 }` |
|
|
159
|
+
| `cbor` | cbor | `{ encode, decode, decodeFirstSync, decodeAllSync, addSemanticType }` |
|
|
160
|
+
| `fs` | (in-repo fs-compat) | File system; no download/upload methods |
|
|
161
|
+
| `parseDocument` | officeparser (in-repo fork) | Office document parsing (async) |
|
|
162
|
+
| `TurndownService` | turndown | HTML to Markdown |
|
|
163
|
+
| `OpenCC` | opencc-js | Chinese conversion `{ Converter, ConverterFactory, CustomConverter, Locale }` |
|
|
164
|
+
| `TOON` | @toon-format/toon | TOON format parsing |
|
|
165
|
+
|
|
166
|
+
## Recipes
|
|
167
|
+
|
|
168
|
+
### Multiple Outputs
|
|
169
|
+
|
|
170
|
+
Return an object; each `outputs` entry extracts its `key`:
|
|
171
|
+
|
|
172
|
+
```typescript
|
|
173
|
+
outputs: [
|
|
174
|
+
{ key: 'total', data: () => totalData },
|
|
175
|
+
{ key: 'tax', data: () => taxData },
|
|
176
|
+
{ key: 'subtotal', data: () => subtotalData },
|
|
177
|
+
],
|
|
178
|
+
output: null,
|
|
179
|
+
error: null,
|
|
180
|
+
code: `
|
|
181
|
+
const subtotal = inputs.price * inputs.quantity
|
|
182
|
+
const tax = subtotal * 0.1
|
|
183
|
+
const total = subtotal + tax
|
|
184
|
+
return { total, tax, subtotal }
|
|
185
|
+
`,
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Manual Self-Referential Update
|
|
189
|
+
|
|
190
|
+
When an update is too complex for `PROPERTY_BANK_EXPRESSION` and must read its own previous value — manual mode allows the same Data as input and output:
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
const appendHistory: DataCalculationScript = {
|
|
194
|
+
__typename: 'DataCalculationScript',
|
|
195
|
+
id: makeId('property_bank_calc'),
|
|
196
|
+
title: 'Append History Entry',
|
|
197
|
+
triggerMode: 'manual',
|
|
198
|
+
enableAsync: false,
|
|
199
|
+
code: `
|
|
200
|
+
const history = Array.isArray(inputs.history) ? inputs.history : []
|
|
201
|
+
return [...history, { entry: inputs.entry, at: moment().toISOString() }].slice(-50)
|
|
202
|
+
`,
|
|
203
|
+
inputs: [
|
|
204
|
+
{ key: 'history', data: () => historyData, trigger: true },
|
|
205
|
+
{ key: 'entry', data: () => entryData, trigger: true },
|
|
206
|
+
],
|
|
207
|
+
output: () => historyData, // same Data as input — manual mode only
|
|
208
|
+
outputs: [],
|
|
209
|
+
error: null,
|
|
210
|
+
}
|
|
211
|
+
// Run it from an event chain: PROPERTY_BANK writes entryData (waitAsync: true),
|
|
212
|
+
// then PROPERTY_BANK_COMMAND with input: () => entryData.
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Failure Modes
|
|
216
|
+
|
|
217
|
+
| Symptom | Cause | Fix |
|
|
218
|
+
|---------|-------|-----|
|
|
219
|
+
| Calc never auto-runs | `trigger` omitted on inputs (defaults to `false`) | Set `trigger: true` explicitly |
|
|
220
|
+
| `PROPERTY_BANK_COMMAND` does nothing | Auto calc + `trigger: false` input, or `input` doesn't reference an input Data of the calc | Command a `trigger: true` input (auto) or any input (manual) |
|
|
221
|
+
| Compile error `Not allow duplicate set property id...` | Auto mode with same Data as input and output | Use `triggerMode: 'manual'`, or split into separate Data |
|
|
222
|
+
| Calc reads stale value written earlier in the same chain | Missing `waitAsync: true` on the preceding write | Set `waitAsync: true` on the write action |
|
|
223
|
+
| Works in Simulator, fails on device | V8 vs Hermes/JSC engine difference | Verify on device (Path 2); avoid engine-sensitive parsing |
|
|
224
|
+
| `console.log` shows nothing | Console only emits during DevTools debug sessions | Attach DevTools, or write debug values to an output Data |
|
|
225
|
+
| `Promise`/`setTimeout` undefined, or `Async mode is required` error | `enableAsync: false` | Set `enableAsync: true` |
|
|
226
|
+
|
|
227
|
+
## Best Practices
|
|
228
|
+
|
|
229
|
+
1. **Avoid circular deps**: Set non-triggering inputs (`trigger: false`) or use `manual` mode
|
|
230
|
+
2. **Error handling**: Always set `error` output for scripts that might fail
|
|
231
|
+
3. **Keep scripts pure**: Avoid side effects, return computed values
|
|
232
|
+
4. **Debounce rapid updates**: Use `manual` mode + timer for high-frequency inputs (auto calcs re-run on every write, even unchanged)
|
|
233
|
+
|
|
234
|
+
## Anti-Patterns (AVOID)
|
|
235
|
+
|
|
236
|
+
See [Architecture Patterns](architecture-patterns.md) for the full pattern selection guide.
|
|
237
|
+
|
|
238
|
+
### Using Data Calc as an orchestrator
|
|
239
|
+
Scripts that manage state machines, control UI flow, or coordinate multi-step processes belong in Event Action Chains. Symptoms: if/else on "what happens next", mirror `dFooResult` outputs that copy back to `dFoo` via `valueChange`, or a `dLastInput` field set-then-cleared to force an auto calc. See the "user-driven state machine" recipe in [Architecture Patterns](architecture-patterns.md).
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Simulator
|
|
2
|
+
|
|
3
|
+
What the Simulator can and can't faithfully reproduce — so a passing Simulator run means what you think it means. This is the fidelity companion to Path 1 in [Verification Toolchain](verification-toolchain.md); read that for how to *drive* the Simulator (compile, screenshot, Automations).
|
|
4
|
+
|
|
5
|
+
## What it is
|
|
6
|
+
|
|
7
|
+
- The default Path 1 target: it renders your compiled project on your computer, with no device required.
|
|
8
|
+
- It runs in Chromium/Electron — a browser-class runtime, not the device runtime. Two consequences to design verification around: it has a browser's capabilities and limits (below), and its JavaScript engine differs from the device's (iOS runs JSC, Android runs Hermes), so engine-specific behavior won't surface here.
|
|
9
|
+
|
|
10
|
+
A Simulator screenshot proves **layout, navigation, Standby Transitions, Data wiring, and generator/Automation wiring**. It does *not* prove anything that depends on real hardware, real models, or capabilities the preview runtime lacks.
|
|
11
|
+
|
|
12
|
+
## Automation screenshots
|
|
13
|
+
|
|
14
|
+
`match_screenshot` stores Simulator automation artifacts at the project level:
|
|
15
|
+
|
|
16
|
+
```text
|
|
17
|
+
.bricks/automation_screenshots/
|
|
18
|
+
last/
|
|
19
|
+
failed/
|
|
20
|
+
diff/
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
There is no application-id subdirectory; in CTOR the project is the application. Generated project `.gitignore` files exclude this directory.
|
|
24
|
+
|
|
25
|
+
When a `match_screenshot` baseline is missing or updated, the baseline goes under `last/`. When a screenshot mismatch occurs, the current capture goes under `failed/` and the pixel diff goes under `diff/`. File names follow `<screenshotName>+local+<timestamp>.png`.
|
|
26
|
+
|
|
27
|
+
In CTOR Desktop, `simulator_invoke` reports any automation screenshot files created or changed by the invocation in an `Automation screenshots:` section. It still separately reports the ordinary preview capture at `.bricks/simulator-screenshot.jpg`.
|
|
28
|
+
|
|
29
|
+
## What the Simulator can't reproduce
|
|
30
|
+
|
|
31
|
+
Because it runs in a browser-class preview rather than on device hardware, the Simulator cannot exercise these — a green run says nothing about them. Verify on a real device (Path 2):
|
|
32
|
+
|
|
33
|
+
| Area | In the Simulator |
|
|
34
|
+
|------|------------------|
|
|
35
|
+
| BLE (Central / Peripheral), Video Streaming | Not available |
|
|
36
|
+
| Raw network sockets — UDP, TCP, TCP Server, MQTT Broker | Not available (also why Buttress LAN discovery is a no-op — see [Buttress](buttress.md)) |
|
|
37
|
+
| Android Intent | Not available (Android-only) |
|
|
38
|
+
| On-device database **persistence** (SQLite / Vector Store) | Not available — both run in-memory in the Simulator (see caveats below), so data never survives a reload |
|
|
39
|
+
| GGML Text-to-Speech | No vocoder in the preview — use an ONNX TTS model to hear speech |
|
|
40
|
+
|
|
41
|
+
These work, but with browser caveats:
|
|
42
|
+
|
|
43
|
+
| Area | Caveat |
|
|
44
|
+
|------|--------|
|
|
45
|
+
| Serial Port | Works via WebSerial — requires browser support and a user gesture |
|
|
46
|
+
| WebView / WebCrawler | Subject to browser CORS — a load/fetch that works on device may be blocked |
|
|
47
|
+
| On-device AI (LLM / STT / VAD / Vector Store / Reranker) | Runs **single-threaded** — far slower than the device, not representative of real latency. Also subject to the model fallbacks below |
|
|
48
|
+
| On-device database (SQLite — `GENERATOR_SQLITE`) | Runs for real on the in-memory WASM `sqlite-vec` build — `execute` / `query` / `transaction` / batch all work. `storageType: file` is transparently treated as in-memory, so nothing persists across reloads (see above) |
|
|
49
|
+
| Scene3D / Sketch / WebRTC | Supported |
|
|
50
|
+
|
|
51
|
+
Feature availability also varies across the device platforms themselves (iOS / tvOS / Android / the desktop OSes). When a deployment targets a specific platform's capability, confirm it on that platform.
|
|
52
|
+
|
|
53
|
+
## Network security
|
|
54
|
+
|
|
55
|
+
The Simulator blocks insecure connections from `applicationPreview` by default: `http://` and `ws://` requests fail, while `https://` and `wss://` are allowed. The Simulator internally allows its own preview host when running the development preview.
|
|
56
|
+
|
|
57
|
+
Generated projects include this project-level setting:
|
|
58
|
+
|
|
59
|
+
```json
|
|
60
|
+
{
|
|
61
|
+
"allowedInsecureHosts": []
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Add explicit entries only when you deliberately need to test an insecure endpoint in the Simulator. A bare `host:port` allows both `http://` and `ws://` for that host:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"allowedInsecureHosts": ["localhost:8080"]
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Use a URL form when only one insecure protocol should be allowed:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"allowedInsecureHosts": ["http://localhost:8080"]
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
In that example, `http://localhost:8080` is allowed and `ws://localhost:8080` remains blocked.
|
|
82
|
+
|
|
83
|
+
Prefer HTTPS/WSS for anything that is not local development.
|
|
84
|
+
|
|
85
|
+
## Feature fallbacks — what the Simulator fakes
|
|
86
|
+
|
|
87
|
+
So that camera and AI features are usable without device permissions, multi-gigabyte downloads, API keys, or a remote inference backend, the Simulator **transparently substitutes a lightweight stand-in** for a few bricks/generators. The config you author is untouched — only the Simulator's runtime behavior differs. **A fallback render proves wiring and layout, not the real feature.**
|
|
88
|
+
|
|
89
|
+
| Brick / Generator | In the Simulator | Does NOT prove |
|
|
90
|
+
|-------------------|------------------|----------------|
|
|
91
|
+
| Camera (`BRICK_CAMERA`) | A 3D mock canvas, no camera permission prompt. `takePicture` snapshots the canvas; recording produces a placeholder clip | Real camera feed, focus, recording, permission flow |
|
|
92
|
+
| Maps (`BRICK_MAPS`) | A real interactive map on free OpenStreetMap-based tiles — no Google Maps API key needed. Markers, path polyline, the six themes / map types (approximated with free tile sets + CSS tints), and the zoom / pan / navigate / focus / reset / fit actions all work | Google / Apple Maps rendering, exact `customMapStyle` / theme styling (approximated), traffic / buildings / indoors layers, real device geolocation |
|
|
93
|
+
| Thermal Printer (`GENERATOR_THERMAL_PRINTER`) | A simulated printer — `init` / `checkStatus` / `scan` fake per-driver status and discovered devices (ESC/POS, Star, TSC, Castles); `print` renders an approximate on-screen receipt. A bottom-left bubble shows live status with a fault toggle to exercise error wiring. Print results can be exported as PNG via `bricks-cli` (see below) | Real device connection, actual paper output, exact native driver status codes |
|
|
94
|
+
| LLM (`GENERATOR_LLM`) | Swapped to a tiny local stand-in model | Output quality / latency of your real model |
|
|
95
|
+
| Reranker — GGML (`GENERATOR_RERANKER`) | Swapped to a small local multilingual reranker model | Ranking quality / latency of your real model |
|
|
96
|
+
| Speech-to-Text — GGML (`GENERATOR_SPEECH_INFERENCE`) | Swapped to a tiny local model | Accuracy / latency of your real model |
|
|
97
|
+
| Speech-to-Text — ONNX (`GENERATOR_ONNX_STT`) | Swapped to a tiny whisper model | Accuracy / latency of your real model |
|
|
98
|
+
| Text-to-Speech — ONNX (`GENERATOR_TTS`) | Swapped to a tiny VITS model (no vocoder or speaker embedding) | Voice / quality / latency of your real model |
|
|
99
|
+
| Vector Store (`GENERATOR_VECTOR_STORE`) | Runs with a tiny local embedding model — an OpenAI-source config works **without a key** | Real embeddings / dimensions / recall (and no persistence — see above) |
|
|
100
|
+
| Buttress (all generators) | **Disabled** — there is no remote inference backend in the Simulator | The Buttress offload path — see [Buttress](buttress.md) |
|
|
101
|
+
| MLX LLM (`GENERATOR_MLX_LLM`) | Runs as authored, except Buttress is disabled | The MLX / Buttress path |
|
|
102
|
+
|
|
103
|
+
These swaps make the AI generators runnable in the Simulator for wiring checks — validate real models, quality, and latency on a device (Path 2).
|
|
104
|
+
|
|
105
|
+
### Inspecting simulated thermal printer print results
|
|
106
|
+
|
|
107
|
+
With the Simulator running (CDP at `localhost:19852`, see [Verification Toolchain](verification-toolchain.md)), `bricks-cli` can read the simulated printers and export a print result as a PNG image — no need to open the bubble popover or screenshot the whole window:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
# Printers + print history (newest first; shows the --index value per result)
|
|
111
|
+
bricks devtools simulator thermal-printer list -p 19852
|
|
112
|
+
bricks devtools simulator thermal-printer list -p 19852 -j --commands # full print payloads as JSON
|
|
113
|
+
|
|
114
|
+
# Render one print result to PNG (defaults: the only printer, --index 0 = latest)
|
|
115
|
+
bricks devtools simulator thermal-printer print-result -p 19852 -o receipt.png
|
|
116
|
+
bricks devtools simulator thermal-printer print-result -p 19852 --index 1 --scale 2 -o older.png
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The PNG is the same approximate receipt the on-screen preview shows (rendered from the print payload). It proves the payload wiring — content, ordering, alignment, barcode/QR/image presence — not pixel-exact native raster output. Print history is in-memory (up to 10 per printer) and clears on preview reload.
|
|
120
|
+
|
|
121
|
+
### Running the real implementation instead
|
|
122
|
+
|
|
123
|
+
Each substituted brick/generator can be switched back to its real implementation per item: open the **gear (Simulator settings)** in the editor's preview toolbar, uncheck the item, and **Apply**. Apply persists the choice and reloads the preview so it takes effect (a plain refresh won't). Use this to, e.g., point a Vector Store at a real API key in the preview, or render the real Google/Apple Maps brick (which needs a Maps API key on web). The browser limits above still apply, and **Buttress stays disabled regardless** — there's no backend for it here.
|
|
124
|
+
|
|
125
|
+
The Thermal Printer is the exception: it has no real web implementation to switch to (the native drivers can't run in a browser), so it is **always simulated** and is not in the gear list.
|
|
126
|
+
|
|
127
|
+
## Enough vs. escalate
|
|
128
|
+
|
|
129
|
+
- **Simulator is enough for:** layout, navigation, Standby Transitions, Data wiring, Automation / state-machine happy paths, and confirming a generator fires and handles its events.
|
|
130
|
+
- **Escalate to a real device for:** anything in the "can't reproduce" tables, real camera / peripherals / payment / identity, real model quality & latency, multi-device Local Sync, on-device persistence, the Buttress offload path, and engine-specific behavior.
|
|
131
|
+
|
|
132
|
+
The full Path 1/2/3 decision rule lives in [Verification Toolchain](verification-toolchain.md).
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# MCP Source-Editing Tools
|
|
2
|
+
|
|
3
|
+
The project-local `bricks-ctor` MCP server exposes tools that edit `subspaces/**` via
|
|
4
|
+
surgical AST edits, keeping files in the standard generated style. Prefer them over
|
|
5
|
+
hand-editing entry files; they validate references, manage imports, compile-verify, and
|
|
6
|
+
record every operation in `.bricks/edits.jsonl`.
|
|
7
|
+
|
|
8
|
+
## Entry tools (bricks.ts / generators.ts / canvases.ts / data.ts / animations.ts)
|
|
9
|
+
|
|
10
|
+
| Tool | Purpose |
|
|
11
|
+
|------|---------|
|
|
12
|
+
| `new_entry` | Create a standard entry skeleton (`file`, `type`, `templateKey`, `alias`, optional initial `set`/`events`) |
|
|
13
|
+
| `edit_entry` | Set/unset dotted paths on an entry: `title`, `property.url`, `outlets.response`, `value`, `switches[0].property.text`, … |
|
|
14
|
+
| `edit_events` | Add/remove/replace/move/clear EventAction items in `events.<eventKey>` |
|
|
15
|
+
| `edit_canvas_items` | Add/replace/remove/move brick items on a Canvas `items` array (frames need numeric x/y/width/height) |
|
|
16
|
+
| `edit_switches` | Add/replace/remove/move switches (id, title, conds, override, disabled, break) |
|
|
17
|
+
| `remove_entry` | Delete an entry; cascades same-subspace references by default, `strict: true` refuses and lists sites |
|
|
18
|
+
|
|
19
|
+
Addressing: `{ file, entry }` (export const name) is primary; `id` works as a global
|
|
20
|
+
fallback (omit `file`). `edit_entry`/`edit_events` accept a `switch` parameter (switch id
|
|
21
|
+
or index) to edit the facets inside one switch — `edit_switches` owns only the array and
|
|
22
|
+
the conds/override shell.
|
|
23
|
+
|
|
24
|
+
### Event actions
|
|
25
|
+
|
|
26
|
+
```jsonc
|
|
27
|
+
{
|
|
28
|
+
"handler": "system", // or { "ref": "brickOrGeneratorRef" } or { "subspace": "SUBSPACE_id" }
|
|
29
|
+
"name": "CHANGE_CANVAS",
|
|
30
|
+
"params": { "canvasId": { "ref": "mainCanvas" } }, // template params, OR:
|
|
31
|
+
"dataParams": { "someData": 5 }, // PROPERTY_BANK-style params
|
|
32
|
+
"waitAsync": false
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
System actions derive their `as SystemAction...` cast automatically; entity-action casts
|
|
37
|
+
are added only when passed via `cast`. The compiled source form
|
|
38
|
+
`{ handler, action: { name, params: [...], dataParams: [...] }, waitAsync }` is also
|
|
39
|
+
accepted, and `{ "expr": "<raw EventAction>" }` is the escape hatch for shapes the
|
|
40
|
+
structured form cannot express. Handler refs must resolve to a brick or generator.
|
|
41
|
+
`PROPERTY_BANK_EXPRESSION` expressions are validated against the runtime fold rules at
|
|
42
|
+
edit time: only expression statements, simple `const`/`let` declarations, and a final
|
|
43
|
+
return inside a zero-arg IIFE evaluate — no `if`/`for`/`while` (use ternaries, or a
|
|
44
|
+
DataCalculationScript for branching logic).
|
|
45
|
+
|
|
46
|
+
## Data-calc tools (DataCalculationScript only)
|
|
47
|
+
|
|
48
|
+
| Tool | Purpose |
|
|
49
|
+
|------|---------|
|
|
50
|
+
| `new_data_calc` | Create `data-calc/data-calculation-{slug}.ts` + `.sandbox.js`, regenerate `data-calc/index.ts`, wire a minimal subspace root |
|
|
51
|
+
| `edit_data_calc` | Set/unset scalar fields, `output`/`error` refs, replace whole `inputs`/`outputs`, or rewrite the sandbox `code` |
|
|
52
|
+
| `edit_data_calc_io` | Add/remove/replace/clear single `inputs`/`outputs` items (input keys unique; output keys may repeat for fan-out) |
|
|
53
|
+
| `remove_data_calc` | Delete the calc `.ts` + its sandbox file and regenerate the index |
|
|
54
|
+
|
|
55
|
+
Addressing: `{ file }` or `{ subspace, calc }` where `calc` is alias, id, or filename
|
|
56
|
+
slug (subspace defaults to `subspace-0`). Code is canonicalized to the sandbox file form
|
|
57
|
+
(`export function main() { ... }` — wrapped automatically, `async` added when the body
|
|
58
|
+
uses top-level `await`). `DataCalculationMap` (visual node graph) is out of scope and
|
|
59
|
+
returns `fallback_recommended`.
|
|
60
|
+
|
|
61
|
+
## Value grammar (everywhere a value appears)
|
|
62
|
+
|
|
63
|
+
| You pass | Emits |
|
|
64
|
+
|----------|-------|
|
|
65
|
+
| JSON scalar/array/object | literal |
|
|
66
|
+
| `{ "link": "dataRefOrAlias" }` | `linkData(() => data.dX)` (property data-links) |
|
|
67
|
+
| `{ "ref": "idOrAliasOrVarName", "subspace"?: 1 }` | `() => namespace.varName` getter |
|
|
68
|
+
| `{ "expr": "raw TypeScript" }` | spliced verbatim |
|
|
69
|
+
|
|
70
|
+
References resolve by var name, id, or alias within the target subspace and fail loudly
|
|
71
|
+
when missing or ambiguous — this doubles as reference validation.
|
|
72
|
+
|
|
73
|
+
## Verification and audit
|
|
74
|
+
|
|
75
|
+
- Every call compile-verifies by default and returns `verify.configChange` — the minimal
|
|
76
|
+
compiled-config delta (path-keyed set/unset ops). Skip with per-call `verify: false`
|
|
77
|
+
or `BRICKS_CTOR_MCP_EDIT_VERIFY=0` when batching, then finish with the `compile` tool.
|
|
78
|
+
- All operations append to `.bricks/edits.jsonl` (gitignored) with inputs, outcomes, and
|
|
79
|
+
touched sites.
|
|
80
|
+
- Non-standard files or entries (hand-written shapes the AST editor cannot safely
|
|
81
|
+
rewrite) return `fallback_recommended` — use plain file edits for those cases only.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Verification Toolchain
|
|
2
|
+
|
|
3
|
+
Three runtime targets, one decision rule. Verify against the cheapest path that proves what you need to prove.
|
|
4
|
+
|
|
5
|
+
## Definition of done — the hard gate
|
|
6
|
+
|
|
7
|
+
Before the agent is allowed to claim work is complete, **all** of the following must be true:
|
|
8
|
+
|
|
9
|
+
1. **Compile clean.** Latest source passes `compile` with no errors.
|
|
10
|
+
2. **Every Canvas screenshot captured.** A rendered screenshot of every Canvas in the deliverable, captured via the available preview tool (`responseImage: true` when the selected model supports vision) at the target hardware resolution and orientation. Canvases gated behind events are reached via Automation runs (`testId` / `testTitleLike` with `brick_press` / `wait_until_canvas_change` cases). Single-Canvas Subspaces still require a captured screenshot.
|
|
11
|
+
3. **Every screenshot reviewed by the agent.** The agent must read each captured screenshot back through the host's image-reading capability — saving the file is not the same as seeing it. The model that produced the Canvas must also have seen the rendered result, or the verification gate has not passed.
|
|
12
|
+
4. **Reference comparison report.** If the user supplied any reference material (Figma / website / HTML / screenshot / PDF / brand book / competitor), produce a short delta report per Canvas:
|
|
13
|
+
- What matches the reference.
|
|
14
|
+
- What intentionally diverges, and why (deployment constraint, BRICKS-runtime semantic, system commitment).
|
|
15
|
+
- What unintentionally diverges, and the planned fix.
|
|
16
|
+
5. **Path appropriate to deployment executed.** Path 1 by default. Path 2 (on-device) when the deployment depends on real hardware behaviour, or whenever the brief touches payment, identity, peripherals, or LocalSync.
|
|
17
|
+
6. **Console clean.** No 404s on media, no Data-key-undefined warnings, no Generator init failures, no React-style warnings — every console line is either zero or accept-with-a-comment.
|
|
18
|
+
|
|
19
|
+
What does **not** count as done:
|
|
20
|
+
|
|
21
|
+
- A single hero-Canvas screenshot.
|
|
22
|
+
- "Looks roughly like the reference" with no per-Canvas comparison.
|
|
23
|
+
- "Compiled successfully" with no rendered preview.
|
|
24
|
+
- A claim of done with no screenshots in evidence.
|
|
25
|
+
- Captured screenshots saved to disk but never read back by the agent.
|
|
26
|
+
|
|
27
|
+
If any item is unmet, the work is mid-iteration. Say so explicitly to the user; offer a precise list of what remains.
|
|
28
|
+
|
|
29
|
+
## Path 1 — Simulator (no device required)
|
|
30
|
+
|
|
31
|
+
The default loop. Always available; deterministic; no device wear; safe for side-effecting flows because nothing real fires.
|
|
32
|
+
|
|
33
|
+
Before trusting a Simulator screenshot, know what it can and can't reproduce: it runs in the Electron preview (a browser-class runtime, not the device — and not the device's JS engine), can't exercise hardware/peripheral features (BLE, printers, raw sockets, SQLite, …), and substitutes fallbacks for Camera and the AI generators (LLM/STT/Vector Store) with Buttress disabled. See [Simulator](simulator.md) for the fidelity boundaries and the per-item gear to run the real implementation — it's what tells you when a green run is enough vs. when to escalate to Path 2.
|
|
34
|
+
|
|
35
|
+
`bun update-app` and `bun deploy-app` publish to the BRICKS portal. The local preview reads `.bricks/build/application-config.json` (produced by `compile`) directly.
|
|
36
|
+
|
|
37
|
+
### Compile tool
|
|
38
|
+
|
|
39
|
+
Typecheck + compile the project. Gate every iteration on this; everything below assumes a clean compile.
|
|
40
|
+
|
|
41
|
+
Agent invocation: call the MCP tool `compile` exposed by the `bricks-ctor` MCP server registered for the project. No arguments.
|
|
42
|
+
|
|
43
|
+
### Simulator tool
|
|
44
|
+
|
|
45
|
+
Use the preview implementation exposed by the current harness:
|
|
46
|
+
|
|
47
|
+
- **CTOR Desktop agent session:** use `simulator_invoke`. CTOR Desktop disables the `bricks-ctor` MCP `simulator` tool and routes screenshots/automation through the desktop preview pane instead. If the user already opened the simulator pane, `simulator_invoke` should reuse it rather than start a separate preview.
|
|
48
|
+
- **Pure `bricks-ctor` project / other agent harness:** use the `bricks-ctor` MCP `simulator` tool when `simulator_invoke` is not available.
|
|
49
|
+
|
|
50
|
+
Both forms are the same verification primitive: launch or reuse Electron preview, take a screenshot, and optionally run a named Automation test by id or partial title. Do not hard-code one tool name into the workflow; choose the available preview tool for the environment.
|
|
51
|
+
|
|
52
|
+
Common arguments:
|
|
53
|
+
- `delay` (ms before screenshot) — default is harness-specific: usually 3000 for a fresh/standalone preview; CTOR Desktop may capture immediately when its preview already has a settled latest config. Increase if Standby Transitions are still in flight.
|
|
54
|
+
- `width`, `height` — screenshot dimensions in px.
|
|
55
|
+
- `responseImage: true` — return the screenshot as image content when the selected model supports vision. If vision is unavailable, save the screenshot and report the path.
|
|
56
|
+
- `testId` or `testTitleLike` — run a project Automation before the screenshot. Use `testTitleLike` for fuzzy matches (case-insensitive partial title).
|
|
57
|
+
|
|
58
|
+
Returns text log + saved screenshot path + image content when supported.
|
|
59
|
+
|
|
60
|
+
### `bun invoke-simulator` (project script)
|
|
61
|
+
|
|
62
|
+
Sustained dev session — watches `subspaces/`, recompiles on save, exposes CDP at `localhost:19852` (configurable via `--cdp-port`), writes `.bricks/devtools.json` with port/pid for downstream tooling.
|
|
63
|
+
|
|
64
|
+
Useful flags:
|
|
65
|
+
- `--screenshot` + `--screenshot-delay/width/height/path` — drive screenshot capture without keeping the window open.
|
|
66
|
+
- `--show-menu` — surface the Electron menu (debugging).
|
|
67
|
+
- `--test-id` / `--test-title-like` — run an Automation in this preview.
|
|
68
|
+
- `--no-keep-open` — exit after one screenshot.
|
|
69
|
+
- `--no-cdp` — disable CDP server (rare; default is to expose it).
|
|
70
|
+
- `--clear-cache` — reset cached state between runs.
|
|
71
|
+
|
|
72
|
+
For ad-hoc CDP inspection against this local preview, connect any CDP client to `localhost:19852` — Chrome DevTools front-end works directly. For an agent-friendly CLI over CDP (screenshot, brick tree/query, input emulation, storage reads, runtime eval, network capture), the `bricks-cli` skill documents the `bricks devtools` command surface — read that skill if it is installed in this workspace. If it is not installed, run `bricks --help` and `bricks devtools --help`; the CLI's own help output is authoritative.
|
|
73
|
+
|
|
74
|
+
To inspect Data / Property Bank or storage state, prefer the dedicated `bricks devtools storage` subcommands — `storage data-bank get <S_xxxx>` (saved Data values), `storage system persist|memory`, `storage system get <key>` — over hand-written `runtime eval`. Reach for `runtime eval` only for *live* store internals that aren't persisted to a data bank (e.g. a current transient value: `runtime eval "system.data.property('S_xxxx', '<alias>')"`); don't reverse-engineer the `system.*` globals.
|
|
75
|
+
|
|
76
|
+
### Project Automations
|
|
77
|
+
|
|
78
|
+
E2E tests authored in TypeScript inside the project (`AutomationTest` / `TestCase`). Test cases include:
|
|
79
|
+
|
|
80
|
+
- `brick_press` — synthesize a press on a Brick.
|
|
81
|
+
- `wait_until_canvas_change` — assert navigation.
|
|
82
|
+
- `assert_property` — assert a Data value equals expected.
|
|
83
|
+
- `wait_property_update` — wait for a Data value to change.
|
|
84
|
+
- `match_screenshot` — visual regression with stored reference image.
|
|
85
|
+
|
|
86
|
+
Trigger types: `launch` (runs on app start), `anytime` (manual), `cron` (scheduled).
|
|
87
|
+
|
|
88
|
+
Important: the automation map id must be `'AUTOMATION_MAP_DEFAULT'` (not a generated id) — the preview test runner reads from `automationMap['AUTOMATION_MAP_DEFAULT']?.map`.
|
|
89
|
+
|
|
90
|
+
Run a single test from the agent: call the available preview tool (`simulator_invoke` in CTOR Desktop, otherwise `bricks-ctor` MCP `preview`) with `testId` or `testTitleLike`.
|
|
91
|
+
|
|
92
|
+
## Path 2 — Real device with DevTools enabled
|
|
93
|
+
|
|
94
|
+
Required when the deployment depends on hardware behaviour the Electron preview cannot reproduce: physical orientation/DPI, real touch hardware (IR overlays, multi-touch), peripherals (camera, BLE, MQTT, NFC, payment, printer, sensors), watchdog cycles on the actual launcher build, fleet-managed reboot semantics, LocalSync across multiple devices, the actual color/luminance of the panel.
|
|
95
|
+
|
|
96
|
+
**Always Path 2** when the brief touches: payment, identity capture, real-time peripheral data, multi-device LocalSync, certified hardware.
|
|
97
|
+
|
|
98
|
+
### One-time manual setup (the agent cannot do this)
|
|
99
|
+
|
|
100
|
+
Ask the user to:
|
|
101
|
+
|
|
102
|
+
1. On the device, open **Settings** → advanced settings.
|
|
103
|
+
2. Toggle **Chrome DevTools** on. The device starts a DevTools server on the local network on port `19851` (auto-increments if taken).
|
|
104
|
+
3. Confirm **Enable LAN Discovery** is on (default) so the device is discoverable.
|
|
105
|
+
4. Note the device passcode if displayed.
|
|
106
|
+
|
|
107
|
+
Requires BRICKS Foundation **≥ 2.24** for CDP commands.
|
|
108
|
+
|
|
109
|
+
### Endpoints exposed once enabled
|
|
110
|
+
|
|
111
|
+
| Endpoint | URL shape | Use |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| Web UI | `http://<ip>:19851` | DevTools landing in a browser |
|
|
114
|
+
| CDP | `http://<ip>:19851/devtools-frontend/inspector.html?ws=<ip>:19851/ws/<passcode>` | Chrome DevTools front-end |
|
|
115
|
+
| MCP | `http://<ip>:19851/mcp` | MCP endpoint (Bearer-token auth with passcode) |
|
|
116
|
+
| MCP SSE | `http://<ip>:19851/sse` | Same, SSE transport |
|
|
117
|
+
| Info | `http://<ip>:19851/devtools/info` | Device / server metadata |
|
|
118
|
+
|
|
119
|
+
### Driving the device
|
|
120
|
+
|
|
121
|
+
Once DevTools is on, ask the user how they want to drive the verification — Chrome DevTools front-end, an MCP client they already run, or screenshot export from their own tooling — and follow their lead. Capture every Canvas screenshot through whichever path the user picks; the verification gate is about the evidence, not the tool.
|
|
122
|
+
|
|
123
|
+
For agent-driven CDP/MCP work against the device (`bricks devtools …` with `-a <ip> --passcode <pc>`, plus bridging the device MCP endpoint into an MCP client), the same `bricks-cli` skill referenced in Path 1 covers the on-device case — read it if installed. If not installed, run `bricks --help` and `bricks devtools --help` for the authoritative command listing.
|
|
124
|
+
|
|
125
|
+
### Running real-device Automations from an agent
|
|
126
|
+
|
|
127
|
+
There is no `bricks devtools automation` subcommand. Use the DevTools runtime helpers exposed inside the app:
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
bricks devtools runtime eval -a <ip> -p 19851 --passcode <pc> "Object.getOwnPropertyNames(automation).sort()" -j
|
|
131
|
+
bricks devtools runtime eval -a <ip> -p 19851 --passcode <pc> "automation.list()" -j
|
|
132
|
+
bricks devtools runtime eval -a <ip> -p 19851 --passcode <pc> "automation.run('<TEST_id>', { updateScreenshot: false })" --await -j
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
`automation.run()` starts the device-side run and may return `null`; treat that as accepted, not as a pass/fail result. Wait for the run timeout/window, then verify completion through the app's own state and a screenshot. For app state, use live runtime reads such as:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
bricks devtools runtime eval -a <ip> -p 19851 --passcode <pc> "JSON.stringify({ result: system.data.property('<S_xxxx>', '<resultAlias>')?.value })" -j
|
|
139
|
+
bricks devtools screenshot -a <ip> -p 19851 --passcode <pc> -o /tmp/device-automation.png
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
In CTOR Desktop sandboxed sessions, keep these as separate simple commands. Avoid multi-line shell scripts, `for` loops, brace expansion, and command substitution around `bricks devtools`; those can stay sandboxed and lose LAN/device access. After `bun update-app` or a device refresh, the DevTools socket may briefly drop, so wait and probe with one screenshot or one `runtime eval` before running the automation.
|
|
143
|
+
|
|
144
|
+
### Real-device side-effects warning
|
|
145
|
+
|
|
146
|
+
Real devices fire real peripherals. Payment terminals charge. MQTT broadcasts on shared topics. BLE advertises to bystanders. Use a **staging** device for verification cycles; never iterate on a production-deployed device unless the user explicitly approves.
|
|
147
|
+
|
|
148
|
+
## Path 3 — Remote debugging via BRICKS Controller (off-LAN)
|
|
149
|
+
|
|
150
|
+
Out of scope for the standard verification loop. It exists for ops scenarios where the device is not on the same network. If the user asks for it, point them at the BRICKS Controller documentation rather than attempting it as part of verification.
|
|
151
|
+
|
|
152
|
+
## Decision rule
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
default Path 1.
|
|
156
|
+
|
|
157
|
+
if deployment depends on:
|
|
158
|
+
physical orientation / DPI / touch HW / peripherals /
|
|
159
|
+
watchdog on real launcher / LocalSync / certified hardware
|
|
160
|
+
→ escalate to Path 2 before declaring done.
|
|
161
|
+
|
|
162
|
+
if brief touches payment, identity, peripherals, LocalSync
|
|
163
|
+
→ Path 2 is mandatory, not optional.
|
|
164
|
+
|
|
165
|
+
if user is off-LAN
|
|
166
|
+
→ Path 3 (out of scope here).
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## What to actually verify (per shape)
|
|
170
|
+
|
|
171
|
+
### Static signage (single-canvas glance loop)
|
|
172
|
+
- Path 1 screenshot captures the loop frame.
|
|
173
|
+
- Watch one full rotation in `bun invoke-simulator` to see all queue items.
|
|
174
|
+
- Cut network mid-loop; confirm cached media plays.
|
|
175
|
+
- Path 2 only if the panel is OLED / has burn-in concerns or specific color profile.
|
|
176
|
+
|
|
177
|
+
### Multi-canvas state machine (kiosk)
|
|
178
|
+
- Path 1: Automation walking the happy path with `brick_press` + `wait_until_canvas_change` + `assert_property` + `match_screenshot` per Canvas.
|
|
179
|
+
- Cancel + inactivity reset paths verified as Automations.
|
|
180
|
+
- Watchdog reset: kill the runtime, restart, confirm boot Canvas resets transient flow Data.
|
|
181
|
+
- Path 2 mandatory if payment / identity is in the flow — fire a real test transaction on staging hardware.
|
|
182
|
+
|
|
183
|
+
### Subspace-driven composition
|
|
184
|
+
- Path 1: open the Subspace standalone if the preview supports it; verify in isolation.
|
|
185
|
+
- Embedded test: walk the host's flow; assert Outlets fire as expected via `wait_property_update`.
|
|
186
|
+
- Re-mount test: cause the host to re-bind the Subspace; confirm internal state resets.
|
|
187
|
+
|
|
188
|
+
### Generator-driven reactive
|
|
189
|
+
- Path 1: drive the source by writing to Data from the runtime (whatever CDP path the user prefers); observe Brick re-render.
|
|
190
|
+
- Throttle / firehose tests: write 100 updates rapidly; confirm the canvas doesn't choke (frame budget intact).
|
|
191
|
+
- Disconnect: simulate source disconnect; confirm UI surfaces stale state, not blank.
|
|
192
|
+
- Threshold transitions: cross every Switch boundary; confirm visual reaction.
|
|
193
|
+
- Path 2 mandatory if the source is a real peripheral — Electron cannot fake the timing or the failure modes.
|
|
194
|
+
|
|
195
|
+
### Multi-device LocalSync
|
|
196
|
+
- Path 2 mandatory. Two devices on the same LAN with DevTools on. Drive one, observe the other.
|
|
197
|
+
|
|
198
|
+
## Browser / runtime log discipline
|
|
199
|
+
|
|
200
|
+
Throughout: the DevTools console must be clean. 404s on media, "Data key not defined" warnings, Generator init failures, React-style warnings — every one is a defect or accept-with-comment. Don't ship around them.
|