@fugood/bricks-ctor 2.25.0-beta.60 → 2.25.0-beta.62
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/package.json +4 -28
- package/tools/__tests__/legacy-forwarder.test.js +91 -0
- package/tools/_forward.ts +26 -0
- package/tools/deploy.ts +3 -175
- package/tools/mcp-server.ts +3 -35
- package/tools/postinstall.ts +3 -291
- package/tools/pull.ts +3 -198
- package/tools/push-config.ts +3 -113
- package/tools/simulator.ts +3 -149
- package/compile/__tests__/config-diff.test.js +0 -100
- package/compile/__tests__/index.test.js +0 -461
- package/compile/__tests__/util.test.js +0 -450
- package/compile/action-name-map.ts +0 -1079
- package/compile/config-diff.ts +0 -155
- package/compile/index.ts +0 -1594
- package/compile/util.ts +0 -482
- package/index.ts +0 -6
- package/skills/bricks-ctor/SKILL.md +0 -38
- package/skills/bricks-ctor/references/animation.md +0 -160
- package/skills/bricks-ctor/references/architecture-patterns.md +0 -88
- package/skills/bricks-ctor/references/automations.md +0 -232
- package/skills/bricks-ctor/references/buttress.md +0 -245
- package/skills/bricks-ctor/references/data-calculation.md +0 -252
- package/skills/bricks-ctor/references/local-sync.md +0 -129
- package/skills/bricks-ctor/references/media-flow.md +0 -165
- package/skills/bricks-ctor/references/remote-data-bank.md +0 -196
- package/skills/bricks-ctor/references/simulator.md +0 -132
- package/skills/bricks-ctor/references/source-editing-tools.md +0 -81
- package/skills/bricks-ctor/references/standby-transition.md +0 -124
- package/skills/bricks-ctor/references/verification-toolchain.md +0 -200
- package/skills/bricks-design/SKILL.md +0 -171
- package/skills/bricks-design/references/architecture-truths.md +0 -132
- package/skills/bricks-design/references/avoiding-complexity.md +0 -91
- package/skills/bricks-design/references/design-critique.md +0 -195
- package/skills/bricks-design/references/design-languages.md +0 -265
- package/skills/bricks-design/references/performance.md +0 -116
- package/skills/bricks-design/references/presentation-and-slideshow.md +0 -137
- package/skills/bricks-design/references/translating-inputs.md +0 -152
- package/skills/bricks-design/references/variations-and-tweaks.md +0 -124
- package/skills/bricks-design/references/when-the-brief-is-branded.md +0 -284
- package/skills/bricks-design/references/when-the-brief-is-vague.md +0 -85
- package/skills/bricks-design/references/workflow.md +0 -134
- package/skills/bricks-ux/SKILL.md +0 -114
- package/skills/bricks-ux/references/accessibility.md +0 -162
- package/skills/bricks-ux/references/flow-states.md +0 -175
- package/skills/bricks-ux/references/interaction-archetypes.md +0 -189
- package/skills/bricks-ux/references/monitoring-screens.md +0 -153
- package/skills/bricks-ux/references/pressable-composition.md +0 -126
- package/skills/bricks-ux/references/user-journey.md +0 -168
- package/skills/bricks-ux/references/ux-critique.md +0 -256
- package/skills/rive-marketplace/SKILL.md +0 -99
- package/tools/__tests__/_cli-error.test.ts +0 -35
- package/tools/__tests__/_mcp-config.test.ts +0 -67
- package/tools/__tests__/pull.test.ts +0 -108
- package/tools/_cli-error.ts +0 -17
- package/tools/_edits-log.ts +0 -41
- package/tools/_git-author.ts +0 -37
- package/tools/_last-pushed-commit.ts +0 -28
- package/tools/_mcp-config.ts +0 -42
- package/tools/_shell.ts +0 -180
- package/tools/icons/.gitattributes +0 -1
- package/tools/icons/fa6pro-glyphmap.json +0 -4686
- package/tools/icons/fa6pro-meta.json +0 -1
- package/tools/mcp-env.ts +0 -13
- package/tools/mcp-tools/__tests__/data-calc-editing.test.js +0 -516
- package/tools/mcp-tools/__tests__/entry-editing.test.js +0 -866
- package/tools/mcp-tools/__tests__/huggingface.test.ts +0 -49
- package/tools/mcp-tools/__tests__/icons.test.ts +0 -21
- package/tools/mcp-tools/__tests__/mcp-env.test.js +0 -19
- package/tools/mcp-tools/_editing-helpers.ts +0 -98
- package/tools/mcp-tools/_verify.ts +0 -50
- package/tools/mcp-tools/compile.ts +0 -104
- package/tools/mcp-tools/data-calc-editing.ts +0 -1311
- package/tools/mcp-tools/entry-editing.ts +0 -2297
- package/tools/mcp-tools/huggingface.ts +0 -772
- package/tools/mcp-tools/icons.ts +0 -97
- package/tools/mcp-tools/lottie.ts +0 -102
- package/tools/mcp-tools/media.ts +0 -113
- package/tools/simulator-main.mjs +0 -488
- package/tools/simulator-preload.cjs +0 -16
- package/types/animation.d.ts +0 -116
- package/types/automation.d.ts +0 -231
- package/types/brick-base.d.ts +0 -80
- package/types/bricks/Camera.d.ts +0 -246
- package/types/bricks/Chart.d.ts +0 -372
- package/types/bricks/GenerativeMedia.d.ts +0 -290
- package/types/bricks/Icon.d.ts +0 -98
- package/types/bricks/Image.d.ts +0 -126
- package/types/bricks/Items.d.ts +0 -480
- package/types/bricks/Lottie.d.ts +0 -168
- package/types/bricks/Maps.d.ts +0 -262
- package/types/bricks/QrCode.d.ts +0 -117
- package/types/bricks/Rect.d.ts +0 -150
- package/types/bricks/RichText.d.ts +0 -131
- package/types/bricks/Rive.d.ts +0 -220
- package/types/bricks/Scene3D.d.ts +0 -676
- package/types/bricks/Sketch.d.ts +0 -256
- package/types/bricks/Slideshow.d.ts +0 -201
- package/types/bricks/Svg.d.ts +0 -99
- package/types/bricks/Text.d.ts +0 -148
- package/types/bricks/TextInput.d.ts +0 -242
- package/types/bricks/Video.d.ts +0 -242
- package/types/bricks/VideoStreaming.d.ts +0 -112
- package/types/bricks/WebRtcStream.d.ts +0 -65
- package/types/bricks/WebView.d.ts +0 -168
- package/types/bricks/index.d.ts +0 -23
- package/types/canvas.d.ts +0 -82
- package/types/common.d.ts +0 -141
- package/types/data-calc-command/base.d.ts +0 -57
- package/types/data-calc-command/collection.d.ts +0 -418
- package/types/data-calc-command/color.d.ts +0 -432
- package/types/data-calc-command/constant.d.ts +0 -50
- package/types/data-calc-command/datetime.d.ts +0 -147
- package/types/data-calc-command/file.d.ts +0 -129
- package/types/data-calc-command/index.d.ts +0 -13
- package/types/data-calc-command/iteratee.d.ts +0 -23
- package/types/data-calc-command/logictype.d.ts +0 -190
- package/types/data-calc-command/math.d.ts +0 -275
- package/types/data-calc-command/object.d.ts +0 -119
- package/types/data-calc-command/sandbox.d.ts +0 -66
- package/types/data-calc-command/string.d.ts +0 -407
- package/types/data-calc-script.d.ts +0 -21
- package/types/data-calc.d.ts +0 -12
- package/types/data.d.ts +0 -97
- package/types/generators/AlarmClock.d.ts +0 -110
- package/types/generators/Assistant.d.ts +0 -640
- package/types/generators/BleCentral.d.ts +0 -247
- package/types/generators/BlePeripheral.d.ts +0 -208
- package/types/generators/CanvasMap.d.ts +0 -74
- package/types/generators/CastlesPay.d.ts +0 -87
- package/types/generators/DataBank.d.ts +0 -160
- package/types/generators/File.d.ts +0 -432
- package/types/generators/GraphQl.d.ts +0 -132
- package/types/generators/Http.d.ts +0 -222
- package/types/generators/HttpServer.d.ts +0 -230
- package/types/generators/Information.d.ts +0 -103
- package/types/generators/Intent.d.ts +0 -168
- package/types/generators/Iterator.d.ts +0 -108
- package/types/generators/Keyboard.d.ts +0 -105
- package/types/generators/LlmAnthropicCompat.d.ts +0 -212
- package/types/generators/LlmAppleBuiltin.d.ts +0 -159
- package/types/generators/LlmGgml.d.ts +0 -903
- package/types/generators/LlmMediaTekNeuroPilot.d.ts +0 -235
- package/types/generators/LlmMlx.d.ts +0 -228
- package/types/generators/LlmOnnx.d.ts +0 -213
- package/types/generators/LlmOpenAiCompat.d.ts +0 -312
- package/types/generators/LlmQualcommAiEngine.d.ts +0 -247
- package/types/generators/Mcp.d.ts +0 -637
- package/types/generators/McpServer.d.ts +0 -289
- package/types/generators/MediaFlow.d.ts +0 -170
- package/types/generators/MqttBroker.d.ts +0 -141
- package/types/generators/MqttClient.d.ts +0 -141
- package/types/generators/Question.d.ts +0 -408
- package/types/generators/RealtimeTranscription.d.ts +0 -287
- package/types/generators/RerankerGgml.d.ts +0 -195
- package/types/generators/SerialPort.d.ts +0 -151
- package/types/generators/SoundPlayer.d.ts +0 -94
- package/types/generators/SoundRecorder.d.ts +0 -139
- package/types/generators/SpeechToTextGgml.d.ts +0 -424
- package/types/generators/SpeechToTextOnnx.d.ts +0 -236
- package/types/generators/SpeechToTextPlatform.d.ts +0 -85
- package/types/generators/SqLite.d.ts +0 -159
- package/types/generators/Step.d.ts +0 -107
- package/types/generators/SttAppleBuiltin.d.ts +0 -153
- package/types/generators/Tcp.d.ts +0 -126
- package/types/generators/TcpServer.d.ts +0 -147
- package/types/generators/TextToSpeechAppleBuiltin.d.ts +0 -127
- package/types/generators/TextToSpeechGgml.d.ts +0 -221
- package/types/generators/TextToSpeechOnnx.d.ts +0 -178
- package/types/generators/TextToSpeechOpenAiLike.d.ts +0 -121
- package/types/generators/ThermalPrinter.d.ts +0 -193
- package/types/generators/Tick.d.ts +0 -83
- package/types/generators/Udp.d.ts +0 -120
- package/types/generators/VadGgml.d.ts +0 -260
- package/types/generators/VadOnnx.d.ts +0 -231
- package/types/generators/VadTraditional.d.ts +0 -138
- package/types/generators/VectorStore.d.ts +0 -257
- package/types/generators/Watchdog.d.ts +0 -107
- package/types/generators/WebCrawler.d.ts +0 -103
- package/types/generators/WebRtc.d.ts +0 -181
- package/types/generators/WebSocket.d.ts +0 -148
- package/types/generators/index.d.ts +0 -57
- package/types/index.d.ts +0 -13
- package/types/subspace.d.ts +0 -60
- package/types/switch.d.ts +0 -51
- package/types/system.d.ts +0 -707
- package/utils/__tests__/calc.test.js +0 -25
- package/utils/__tests__/id.test.js +0 -154
- package/utils/calc.ts +0 -130
- package/utils/data.ts +0 -495
- package/utils/event-props.ts +0 -912
- package/utils/id.ts +0 -133
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
# Architecture Patterns
|
|
2
|
-
|
|
3
|
-
How to decompose complex flows into the right combination of BRICKS patterns.
|
|
4
|
-
|
|
5
|
-
## Pattern Selection Priority
|
|
6
|
-
|
|
7
|
-
Prefer higher-priority patterns; only fall to lower when they genuinely can't solve the sub-problem:
|
|
8
|
-
|
|
9
|
-
| Priority | Pattern | Use For |
|
|
10
|
-
|----------|---------|---------|
|
|
11
|
-
| 1 | Generator + Events | I/O, AI inference, external data |
|
|
12
|
-
| 2 | Event Action Chains | Orchestration, sequential steps |
|
|
13
|
-
| 3 | System Actions | State changes, navigation, UI triggers |
|
|
14
|
-
| 4 | Data Calculation | Pure data transformation ONLY |
|
|
15
|
-
|
|
16
|
-
### Generators (Priority 1)
|
|
17
|
-
For all external I/O and AI inference. Each generator emits events that naturally chain into actions.
|
|
18
|
-
- **GeneratorAssistant**: multi-turn LLM conversations, function calling, built-in message history
|
|
19
|
-
- **GeneratorLLM**: single-shot local inference (GGML)
|
|
20
|
-
- **GeneratorHttp**: REST API calls
|
|
21
|
-
- **GeneratorMqtt / GeneratorWebSocket**: real-time messaging
|
|
22
|
-
|
|
23
|
-
### Event Action Chains (Priority 2)
|
|
24
|
-
The primary way to orchestrate multi-step flows. A single event can contain an array of EventActions executed sequentially.
|
|
25
|
-
- Use `waitAsync: true` to await async actions before the next step
|
|
26
|
-
- Use `dataParams` + `mapping` to pass event data downstream
|
|
27
|
-
- This is the "glue" that wires generators, state, and UI together
|
|
28
|
-
- For Generator result UI: await Generator, write done/version Data; route/current Data stays identity.
|
|
29
|
-
|
|
30
|
-
Sequential `PROPERTY_BANK` / `PROPERTY_BANK_EXPRESSION` actions in one chain read the data values that existed when the chain started. If a later action needs to read what an earlier action wrote, set `waitAsync: true` on the earlier action.
|
|
31
|
-
|
|
32
|
-
### System Actions (Priority 3)
|
|
33
|
-
Built-in commands for direct state and UI changes.
|
|
34
|
-
- **PROPERTY_BANK**: set data value
|
|
35
|
-
- **PROPERTY_BANK_EXPRESSION**: inline JS expression for simple compute
|
|
36
|
-
- The expression engine folds statements into a single expression: only expression
|
|
37
|
-
statements, simple `const`/`let` declarations, and a final return/expression are
|
|
38
|
-
supported — **no `if`/`for`/`while`/`switch`** (use ternaries). The same limit
|
|
39
|
-
applies inside a zero-arg IIFE body. Unsupported statements fail at runtime with
|
|
40
|
-
the error visible only in a DevTools session, so prefer ternary chains or move the
|
|
41
|
-
logic to a DataCalculationScript.
|
|
42
|
-
- **CHANGE_CANVAS**: navigate to another canvas
|
|
43
|
-
- **DYNAMIC_ANIMATION**: trigger animation
|
|
44
|
-
- **ALERT / MESSAGE**: system feedback
|
|
45
|
-
|
|
46
|
-
### Data Calculation (Priority 4)
|
|
47
|
-
ONLY for deriving, formatting, or aggregating values from other data. Not for orchestration, side effects, or flow control.
|
|
48
|
-
|
|
49
|
-
## Entity Aliases
|
|
50
|
-
|
|
51
|
-
Set `alias` on entities to give them a stable, human-readable name:
|
|
52
|
-
- Code generation uses alias as the variable name (e.g., `alias: 'submitBtn'` → `export const submitBtn`)
|
|
53
|
-
- At runtime, devtools MCP tools accept alias instead of short ID and selectors can match by alias. Note: bricks-ctor does not directly interact with devtools MCP — aliases here primarily affect code generation
|
|
54
|
-
- Aliases must be unique across the application — duplicates are excluded from resolution
|
|
55
|
-
|
|
56
|
-
## Flow Decomposition
|
|
57
|
-
|
|
58
|
-
When the user describes a complex flow, decompose it BEFORE writing code:
|
|
59
|
-
|
|
60
|
-
### Step 1: Extract I/O boundaries
|
|
61
|
-
Every external interaction maps to a Generator:
|
|
62
|
-
- "call LLM" → GeneratorAssistant or GeneratorLLM
|
|
63
|
-
- "fetch API" → GeneratorHttp
|
|
64
|
-
- "speech to text" → GeneratorSpeechInference
|
|
65
|
-
|
|
66
|
-
### Step 2: Extract state transitions
|
|
67
|
-
Every UI change maps to a System Action in an event chain:
|
|
68
|
-
- "show loading" → PROPERTY_BANK on a boolean data
|
|
69
|
-
- "go to result screen" → CHANGE_CANVAS
|
|
70
|
-
- "animate in" → DYNAMIC_ANIMATION
|
|
71
|
-
|
|
72
|
-
### Step 3: Extract pure transformations
|
|
73
|
-
Only actual data derivation maps to Data Calculation:
|
|
74
|
-
- "format the response" → DataCalculationScript
|
|
75
|
-
- "compute a score" → DataCalculationScript or DataCalculationMap
|
|
76
|
-
|
|
77
|
-
### Step 4: Wire with Event Action Chains
|
|
78
|
-
Connect the pieces through events on generators and bricks.
|
|
79
|
-
|
|
80
|
-
## Recipe: user-driven state machine (calculator, form wizard, picker)
|
|
81
|
-
|
|
82
|
-
A brief like "state vars X, Y, Z; button A updates X from X+Y; button B resets" is a state machine. The shape:
|
|
83
|
-
|
|
84
|
-
- Each state variable is its own `Data` entity. Displays read it via `linkData(() => data.dFoo)`.
|
|
85
|
-
- Each button's `onPress` is an Event Action Chain. For every state var that changes, append one `PROPERTY_BANK_EXPRESSION` whose `expression` reads the current state and returns the new value.
|
|
86
|
-
- Use `Data Calculation` only for reusable pure derivations referenced as inputs to those expressions.
|
|
87
|
-
|
|
88
|
-
A 10-button calculator with 4 state vars is ~10 small chains of 1–4 inline expressions. If you find yourself writing a single auto-mode `DataCalculationScript` that consumes all state vars and emits all-new state through mirror `dFooResult` data — or pinging a `dLastInput` field to force an auto calc to re-run — the chain shape was the right answer.
|
|
@@ -1,232 +0,0 @@
|
|
|
1
|
-
# Automations
|
|
2
|
-
|
|
3
|
-
E2E testing and scheduled execution for BRICKS applications. Simulates user behavior and validates application state.
|
|
4
|
-
|
|
5
|
-
## Automation Types
|
|
6
|
-
|
|
7
|
-
| Type | Description |
|
|
8
|
-
| --------- | ---------------------------------------------------------- |
|
|
9
|
-
| `launch` | Run on application launch (restarts app when run manually) |
|
|
10
|
-
| `anytime` | Execute anytime via manual trigger |
|
|
11
|
-
| `cron` | Scheduled execution using crontab expressions |
|
|
12
|
-
|
|
13
|
-
## Simulation Actions
|
|
14
|
-
|
|
15
|
-
Automations can simulate:
|
|
16
|
-
|
|
17
|
-
- **Brick Press**: Tap/click on bricks
|
|
18
|
-
- **Key Events**: Key up/down for keyboard input
|
|
19
|
-
- **HTTP Request**: API calls
|
|
20
|
-
- **Execute Action**: Trigger system or generator actions
|
|
21
|
-
|
|
22
|
-
## Assertions
|
|
23
|
-
|
|
24
|
-
Automations can validate:
|
|
25
|
-
|
|
26
|
-
- **Brick Exists**: Check if brick is rendered
|
|
27
|
-
- **Event Triggered**: Verify event from Brick/Generator/Canvas
|
|
28
|
-
- **Canvas Changed**: Confirm canvas navigation
|
|
29
|
-
- **Property Assert**: Check Data Bank values
|
|
30
|
-
- **Property Updated**: Wait for property change
|
|
31
|
-
- **Match Screenshot**: Visual regression testing
|
|
32
|
-
|
|
33
|
-
## TypeScript Example
|
|
34
|
-
|
|
35
|
-
```typescript
|
|
36
|
-
const testLoginFlow: AutomationTest = {
|
|
37
|
-
__typename: 'AutomationTest',
|
|
38
|
-
id: makeId('test'),
|
|
39
|
-
title: 'Test Login Flow',
|
|
40
|
-
timeout: 30000,
|
|
41
|
-
trigger_type: 'launch',
|
|
42
|
-
cases: [
|
|
43
|
-
{
|
|
44
|
-
__typename: 'TestCase',
|
|
45
|
-
id: makeId('test_case'),
|
|
46
|
-
name: 'Wait for login canvas',
|
|
47
|
-
run: ['wait_until_canvas_change', () => mainSubspace, () => loginCanvas, 5000],
|
|
48
|
-
exit_on_failed: true,
|
|
49
|
-
commented: false,
|
|
50
|
-
pre_delay: 0,
|
|
51
|
-
post_delay: 0,
|
|
52
|
-
jump_cond: [],
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
__typename: 'TestCase',
|
|
56
|
-
id: makeId('test_case'),
|
|
57
|
-
name: 'Press username input',
|
|
58
|
-
run: ['brick_press', () => mainSubspace, () => usernameInput],
|
|
59
|
-
exit_on_failed: true,
|
|
60
|
-
commented: false,
|
|
61
|
-
pre_delay: 0,
|
|
62
|
-
post_delay: 100,
|
|
63
|
-
jump_cond: [],
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
__typename: 'TestCase',
|
|
67
|
-
id: makeId('test_case'),
|
|
68
|
-
name: 'Assert username value',
|
|
69
|
-
run: ['assert_property', () => mainSubspace, () => usernameData, 'testuser'],
|
|
70
|
-
exit_on_failed: true,
|
|
71
|
-
commented: false,
|
|
72
|
-
pre_delay: 0,
|
|
73
|
-
post_delay: 0,
|
|
74
|
-
jump_cond: [],
|
|
75
|
-
},
|
|
76
|
-
{
|
|
77
|
-
__typename: 'TestCase',
|
|
78
|
-
id: makeId('test_case'),
|
|
79
|
-
name: 'Press login button',
|
|
80
|
-
run: ['brick_press', () => mainSubspace, () => loginButton],
|
|
81
|
-
exit_on_failed: true,
|
|
82
|
-
commented: false,
|
|
83
|
-
pre_delay: 0,
|
|
84
|
-
post_delay: 0,
|
|
85
|
-
jump_cond: [],
|
|
86
|
-
},
|
|
87
|
-
{
|
|
88
|
-
__typename: 'TestCase',
|
|
89
|
-
id: makeId('test_case'),
|
|
90
|
-
name: 'Wait for dashboard',
|
|
91
|
-
run: ['wait_until_canvas_change', () => mainSubspace, () => dashboardCanvas, 10000],
|
|
92
|
-
exit_on_failed: true,
|
|
93
|
-
commented: false,
|
|
94
|
-
pre_delay: 0,
|
|
95
|
-
post_delay: 0,
|
|
96
|
-
jump_cond: [],
|
|
97
|
-
},
|
|
98
|
-
],
|
|
99
|
-
variables: [],
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
## Test Methods
|
|
104
|
-
|
|
105
|
-
| Method | Signature | Description |
|
|
106
|
-
| ---------------------------- | ------------------------------------------------ | -------------------- |
|
|
107
|
-
| `brick_press` | `[subspace, brick, options?]` | Simulate brick press |
|
|
108
|
-
| `brick_exists` | `[subspace, brick, frame?]` | Check brick exists |
|
|
109
|
-
| `wait_until_brick_exists` | `[subspace, brick, timeout?, frame?]` | Wait for brick |
|
|
110
|
-
| `wait_until_event_trigger` | `[subspace, sender, eventKey, timeout?]` | Wait for event |
|
|
111
|
-
| `wait_until_canvas_change` | `[subspace, canvas, timeout?]` | Wait for canvas |
|
|
112
|
-
| `keydown` | `[keyCode, pressedKey?, flags?]` | Key down event |
|
|
113
|
-
| `keyup` | `[keyCode, pressedKey?, flags?]` | Key up event |
|
|
114
|
-
| `http_request` | `[url, options?]` | HTTP request |
|
|
115
|
-
| `assert_property` | `[subspace, property, value]` | Assert data value |
|
|
116
|
-
| `wait_until_property_change` | `[subspace, property, value, timeout?]` | Wait for value |
|
|
117
|
-
| `execute_action` | `[subspace, handler, action, params?, options?]` | Execute action |
|
|
118
|
-
| `match_screenshot` | `[name, threshold?, maxRetry?]` | Screenshot compare |
|
|
119
|
-
| `delay` | `[subspace?, property?, defaultValue?]` | Delay execution |
|
|
120
|
-
|
|
121
|
-
In project TypeScript source, pass entity getters for BRICKS entities:
|
|
122
|
-
|
|
123
|
-
```typescript
|
|
124
|
-
run: ['brick_press', () => mainSubspace, () => bricks.bSubmitButton]
|
|
125
|
-
run: ['wait_until_canvas_change', () => mainSubspace, () => canvases.cDone, 5000]
|
|
126
|
-
run: ['assert_property', () => mainSubspace, () => data.dStep, 'done']
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
The compiler resolves these getters to the current generated IDs.
|
|
130
|
-
|
|
131
|
-
### execute_action Params
|
|
132
|
-
|
|
133
|
-
The `params` object in `execute_action` uses **runtime event property keys** from `event-props.ts`, NOT the action config `input` names from type definitions.
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
// CORRECT — use runtime event property key
|
|
137
|
-
run: ['execute_action', () => subspace0, bricks.bInput.id, 'BRICK_TEXT_INPUT_SET_TEXT',
|
|
138
|
-
{ BRICK_TEXT_INPUT_TEXT: 'hello' }]
|
|
139
|
-
|
|
140
|
-
// WRONG — action config input name doesn't work in automation
|
|
141
|
-
run: ['execute_action', () => subspace0, bricks.bInput.id, 'BRICK_TEXT_INPUT_SET_TEXT',
|
|
142
|
-
{ text: 'hello' }]
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
Reference `event-props.ts` for the correct runtime keys (e.g., `BRICK_TEXT_INPUT_TEXT`, `GENERATOR_MQTT_PAYLOAD`).
|
|
146
|
-
|
|
147
|
-
### Prefer UI Interactions Over Direct Generator Calls
|
|
148
|
-
|
|
149
|
-
For realistic E2E testing, prefer simulating user actions (set text input + press button) over calling generator actions directly:
|
|
150
|
-
|
|
151
|
-
```typescript
|
|
152
|
-
// GOOD — simulates real user behavior
|
|
153
|
-
{ run: ['execute_action', () => sub, bricks.bInput.id, 'BRICK_TEXT_INPUT_SET_TEXT',
|
|
154
|
-
{ BRICK_TEXT_INPUT_TEXT: 'hello' }] },
|
|
155
|
-
{ run: ['brick_press', () => sub, () => bricks.bSendBtn] },
|
|
156
|
-
{ run: ['wait_until_property_change', () => sub, () => data.dPayload, 'hello', 10000] },
|
|
157
|
-
|
|
158
|
-
// AVOID — bypasses UI, doesn't test the full flow
|
|
159
|
-
{ run: ['execute_action', () => sub, generators.gClient.id, 'GENERATOR_MQTT_PUBLISH',
|
|
160
|
-
{ topic: 'test', payload: 'hello', qos: '0' }] },
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
## Recording Automations
|
|
164
|
-
|
|
165
|
-
In BRICKS Editor Preview mode:
|
|
166
|
-
|
|
167
|
-
1. Perform operations normally
|
|
168
|
-
2. Open menu (right-bottom corner)
|
|
169
|
-
3. Select "Record Events as Automation"
|
|
170
|
-
4. Generated automation appears in Automations list
|
|
171
|
-
|
|
172
|
-
## Running Automations
|
|
173
|
-
|
|
174
|
-
### Manual Run
|
|
175
|
-
|
|
176
|
-
`Menu` → `Automations` → Select automation → `Run`
|
|
177
|
-
|
|
178
|
-
### On Launch
|
|
179
|
-
|
|
180
|
-
`Bind Device` → `Select Automation` (only `launch` or `cron` types)
|
|
181
|
-
|
|
182
|
-
### Scheduled (Cron)
|
|
183
|
-
|
|
184
|
-
`Bind Device` → `Cron Automation` (allows multi-select)
|
|
185
|
-
|
|
186
|
-
Use [crontab.guru](https://crontab.guru) to build cron expressions.
|
|
187
|
-
|
|
188
|
-
## Screenshot Testing
|
|
189
|
-
|
|
190
|
-
Visual regression testing with screenshot comparison:
|
|
191
|
-
|
|
192
|
-
```typescript
|
|
193
|
-
{
|
|
194
|
-
__typename: 'TestCase',
|
|
195
|
-
id: makeId('test_case'),
|
|
196
|
-
name: 'Match dashboard screenshot',
|
|
197
|
-
run: ['match_screenshot', 'dashboard-initial-state', 0.01, 3],
|
|
198
|
-
exit_on_failed: true,
|
|
199
|
-
commented: false,
|
|
200
|
-
pre_delay: 500, // Wait for UI to settle
|
|
201
|
-
post_delay: 0,
|
|
202
|
-
jump_cond: [],
|
|
203
|
-
}
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
Screenshots can be stored:
|
|
207
|
-
|
|
208
|
-
- Local file system
|
|
209
|
-
- Media Flow workspace
|
|
210
|
-
|
|
211
|
-
First run captures baseline. Use "Run with Update" to update baseline.
|
|
212
|
-
|
|
213
|
-
## Module Support
|
|
214
|
-
|
|
215
|
-
Automations work with Modules. Use Manual Run in Preview mode for module testing.
|
|
216
|
-
|
|
217
|
-
## Important Notes
|
|
218
|
-
|
|
219
|
-
- **Automation map key**: Always use `'AUTOMATION_MAP_DEFAULT'` as the automation map ID (not `makeId()`). The preview test runner reads from `automationMap['AUTOMATION_MAP_DEFAULT']?.map`.
|
|
220
|
-
- **Valid makeId types**: Use `'test'` for AutomationTest, `'test_case'` for TestCase, `'test_var'` for TestVariable. Do NOT use `'automation_test'` or `'automation_test_map'`.
|
|
221
|
-
- **Entity references in run arrays**: Use getter references (`() => subspace`, `() => bricks.bButton`, `() => data.dValue`) in TypeScript source so compile resolves fresh IDs.
|
|
222
|
-
- **handler in execute_action**: Pass the entity's `.id` string (e.g., `bricks.bInput.id`), not a getter function.
|
|
223
|
-
|
|
224
|
-
## Best Practices
|
|
225
|
-
|
|
226
|
-
1. **Test culture**: Create automations for every significant flow
|
|
227
|
-
2. **CI/CD integration**: Use `launch` automations for deployment validation
|
|
228
|
-
3. **Incremental waits**: Use `wait_until_property_change` with appropriate timeouts
|
|
229
|
-
4. **Visual testing**: Add screenshot comparisons for critical UI states
|
|
230
|
-
5. **Cron monitoring**: Schedule health checks for production displays
|
|
231
|
-
6. **Isolation**: Each automation should be independent and idempotent
|
|
232
|
-
7. **UI-first testing**: Simulate real user interactions (text input, button press) rather than calling generators directly
|
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
# Buttress (Remote Inference)
|
|
2
|
-
|
|
3
|
-
Backend system for offloading compute-intensive AI generator tasks from BRICKS devices to more powerful machines.
|
|
4
|
-
|
|
5
|
-
## Purpose
|
|
6
|
-
|
|
7
|
-
When mobile devices or embedded systems lack hardware for local AI inference (LLM, speech-to-text), Buttress transparently delegates work to a server with appropriate resources (GPU).
|
|
8
|
-
|
|
9
|
-
## How It Works
|
|
10
|
-
|
|
11
|
-
1. **Capability Exchange**: Client and server share hardware capabilities
|
|
12
|
-
2. **Strategy Selection**: System decides local vs. remote execution
|
|
13
|
-
3. **Transparent Offloading**: Generator operates same way, execution happens remotely
|
|
14
|
-
|
|
15
|
-
## Supported Generators
|
|
16
|
-
|
|
17
|
-
- LLM (GGML) (LlmMlx.ts) - Local Large Language Model inference with GGML
|
|
18
|
-
- LLM (MLX) (LlmGgml.ts) - Local Large Language Model inference with MLX
|
|
19
|
-
- Speech-to-Text (GGML) (SpeechToTextGgml.ts) - Local Speech-to-Text inference with GGML
|
|
20
|
-
|
|
21
|
-
## Client Configuration
|
|
22
|
-
|
|
23
|
-
In generator properties, configure `buttressConnectionSettings`:
|
|
24
|
-
|
|
25
|
-
| Setting | Description |
|
|
26
|
-
|---------|-------------|
|
|
27
|
-
| `enabled` | Toggle Buttress offloading |
|
|
28
|
-
| `autoDiscoverType` | `auto` (LAN auto-discovery, recommended) or `manual` (typed URL) |
|
|
29
|
-
| `url` | Server URL (`manual` mode only — leave empty for `auto`) |
|
|
30
|
-
| `fallbackType` | If Buttress is unreachable: `use-local` runs locally, `no-op` blocks the load |
|
|
31
|
-
| `strategy` | Execution preference (see below) |
|
|
32
|
-
|
|
33
|
-
The launcher provides the access token automatically — there is **no user-facing access-token setting**. In `auto` mode the launcher discovers servers bound to the device's workspace and uses its workspace-scoped JWT; in `manual` mode it sends the same JWT only when the typed URL belongs to a server bound to the same workspace (verified against the server's `/buttress/info`).
|
|
34
|
-
|
|
35
|
-
### `autoDiscoverType` options
|
|
36
|
-
|
|
37
|
-
| Mode | When to use | What the device does |
|
|
38
|
-
|------|-------------|----------------------|
|
|
39
|
-
| `auto` | LAN deployment with a workspace-bound buttress-server | Listens for UDP announcements and picks the strongest server bound to its workspace; reconnects automatically when the workspace flips |
|
|
40
|
-
| `manual` | Internet-reachable server, mixed networks, or a public/unbound server | Connects to the typed `url` directly; sends a token only when the server is bound to the same workspace |
|
|
41
|
-
|
|
42
|
-
### Strategy options
|
|
43
|
-
|
|
44
|
-
| Strategy | Description |
|
|
45
|
-
|----------|-------------|
|
|
46
|
-
| `prefer-local` | Use local if capable, fallback to Buttress |
|
|
47
|
-
| `prefer-buttress` | Use Buttress if available, fallback to local |
|
|
48
|
-
| `prefer-best` | Auto-select based on capability comparison |
|
|
49
|
-
|
|
50
|
-
## Generator Configuration Examples
|
|
51
|
-
|
|
52
|
-
### Auto-discovery (recommended)
|
|
53
|
-
|
|
54
|
-
Workspace-bound launcher + workspace-bound buttress-server on the same LAN. No URL needed — discovery picks the highest-scoring server that runs the requested backend.
|
|
55
|
-
|
|
56
|
-
```typescript
|
|
57
|
-
import { makeId } from 'bricks-ctor'
|
|
58
|
-
|
|
59
|
-
const llmGenerator: GeneratorLLM = {
|
|
60
|
-
__typename: 'Generator',
|
|
61
|
-
templateKey: 'GENERATOR_LLM',
|
|
62
|
-
id: makeId('generator'),
|
|
63
|
-
title: 'Chat LLM',
|
|
64
|
-
description: '',
|
|
65
|
-
property: {
|
|
66
|
-
modelUrl: 'https://huggingface.co/ggml-org/gemma-3-12b-it-qat-GGUF/resolve/main/gemma-3-12b-it-qat-q4_0.gguf',
|
|
67
|
-
contextSize: 8192,
|
|
68
|
-
buttressConnectionSettings: {
|
|
69
|
-
enabled: true,
|
|
70
|
-
autoDiscoverType: 'auto',
|
|
71
|
-
fallbackType: 'use-local',
|
|
72
|
-
strategy: 'prefer-best',
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
events: {},
|
|
76
|
-
switches: [],
|
|
77
|
-
}
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
### Manual URL
|
|
81
|
-
|
|
82
|
-
Use when the server isn't on the launcher's broadcast domain (cross-subnet, internet, behind a reverse proxy) or you want to point at a specific public/unbound server.
|
|
83
|
-
|
|
84
|
-
```typescript
|
|
85
|
-
buttressConnectionSettings: {
|
|
86
|
-
enabled: true,
|
|
87
|
-
autoDiscoverType: 'manual',
|
|
88
|
-
url: 'http://192.168.1.100:2080',
|
|
89
|
-
fallbackType: 'use-local',
|
|
90
|
-
strategy: 'prefer-best',
|
|
91
|
-
}
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
> ⚠️ With `fallbackType: 'no-op'` the generator refuses to load locally if Buttress is unreachable. Use `'use-local'` whenever the device can also run the model standalone.
|
|
95
|
-
|
|
96
|
-
## Integrating a discovered buttress-server
|
|
97
|
-
|
|
98
|
-
The ctor-desktop "Local Devices" panel (and the `bricks buttress scan` CLI) can hand you a server's identity, workspace, and announced generator caps. When the user asks to integrate one:
|
|
99
|
-
|
|
100
|
-
1. **Confirm workspace match.** The discovery message says whether the server's workspace matches this project's. If it doesn't, do NOT add the integration — instruct the user to run `bricks buttress unbind && bricks buttress bind` from this workspace's owner CLI on the server host. The launcher won't trust a cross-workspace server.
|
|
101
|
-
|
|
102
|
-
2. **Map announced types to generator templates.** For each `generators[].type` in the announce, target the matching templateKey (create the generator if absent):
|
|
103
|
-
|
|
104
|
-
| Announced type | templateKey | Default model |
|
|
105
|
-
|----------------|------------------------------|---------------|
|
|
106
|
-
| `ggml-llm` | `GENERATOR_LLM` | `ggml-org/gemma-3-12b-it-qat-GGUF` (≥20 GB usable) or `ggml-org/gpt-oss-20b-GGUF` (~12 GB usable) |
|
|
107
|
-
| `mlx-llm` | `GENERATOR_MLX_LLM` | `mlx-community/Qwen3-4B-4bit` (or a larger 4-bit quant if `usableBytes` allows) |
|
|
108
|
-
| `ggml-stt` | `GENERATOR_SPEECH_INFERENCE` | `BricksDisplay/whisper-ggml` (filename `ggml-small-q8_0.bin`) |
|
|
109
|
-
|
|
110
|
-
Pick a model that fits the announced `usableBytes`. Set `contextSize` to match.
|
|
111
|
-
|
|
112
|
-
3. **Use the canonical auto-discovery config** from "Auto-discovery (recommended)" above. Don't switch to manual mode just because the server is on the LAN — auto mode picks the workspace-bound server automatically and rebinds when the device's workspace flips.
|
|
113
|
-
|
|
114
|
-
### Real-device caveat
|
|
115
|
-
|
|
116
|
-
Buttress LAN auto-discovery uses native UDP via `react-native-jsi-udp`. The iOS Simulator silently fails to bind UDP, so auto mode is a no-op there. With `fallbackType: 'use-local'` the generator falls back to local inference in the simulator — dev/test stays functional. **Validate the buttress path itself only when deploying to a real Foundation device; don't gate the build on simulator validation.**
|
|
117
|
-
|
|
118
|
-
## Server Setup
|
|
119
|
-
|
|
120
|
-
### Requirements
|
|
121
|
-
- [Bun](https://bun.sh) v1.3+
|
|
122
|
-
- GPU recommended for LLM/STT
|
|
123
|
-
|
|
124
|
-
### Installation
|
|
125
|
-
|
|
126
|
-
```bash
|
|
127
|
-
bun add -g @fugood/buttress-server
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
### Start Server
|
|
131
|
-
|
|
132
|
-
```bash
|
|
133
|
-
bricks-buttress
|
|
134
|
-
# or with config
|
|
135
|
-
bricks-buttress --config ./config.toml
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### CLI Options
|
|
139
|
-
|
|
140
|
-
| Option | Description |
|
|
141
|
-
|--------|-------------|
|
|
142
|
-
| `-p, --port` | Port (default: 2080) |
|
|
143
|
-
| `-c, --config` | TOML config file path |
|
|
144
|
-
| `-v, --version` | Show version |
|
|
145
|
-
| `-h, --help` | Show help |
|
|
146
|
-
|
|
147
|
-
### Environment Variables
|
|
148
|
-
|
|
149
|
-
| Variable | Description |
|
|
150
|
-
|----------|-------------|
|
|
151
|
-
| `HF_TOKEN` | Hugging Face token for model downloads |
|
|
152
|
-
| `ENABLE_OPENAI_COMPAT_ENDPOINT` | Set to `1` for OpenAI-compatible API |
|
|
153
|
-
| `BRICKS_BUTTRESS_STATE_DIR` | Override the workspace state directory (default `~/.bricks-cli/buttress`) |
|
|
154
|
-
|
|
155
|
-
## Bind the Server to a Workspace
|
|
156
|
-
|
|
157
|
-
To use `autoDiscoverType: 'auto'` — and to require workspace-scoped JWT auth — pair the buttress-server with a BRICKS workspace using the `bricks buttress` CLI commands. An unbound server stays in legacy public mode and accepts any LAN client.
|
|
158
|
-
|
|
159
|
-
### One-time bind
|
|
160
|
-
|
|
161
|
-
```bash
|
|
162
|
-
# Log into the cloud bricks-server with the workspace owner's account
|
|
163
|
-
bricks auth login
|
|
164
|
-
|
|
165
|
-
# Pair the buttress-server running on this machine with the active workspace
|
|
166
|
-
bricks buttress bind
|
|
167
|
-
|
|
168
|
-
# Restart bricks-buttress so it picks up the new state.json
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
`bricks buttress bind` writes `~/.bricks-cli/buttress/state.json` containing the workspace id, the issuer's Ed25519 public key, and a stable `serverId` (defaults to `buttress-<machineId>`). Override location with `--state-dir` or `$BRICKS_BUTTRESS_STATE_DIR`. For headless setups, use `bricks buttress bind --print` to emit state.json to stdout.
|
|
172
|
-
|
|
173
|
-
### Verify and manage
|
|
174
|
-
|
|
175
|
-
```bash
|
|
176
|
-
# Show local binding + workspace-side bound list
|
|
177
|
-
bricks buttress status
|
|
178
|
-
|
|
179
|
-
# Discover buttress-servers on the LAN (with version, auth state, generator caps)
|
|
180
|
-
bricks buttress scan
|
|
181
|
-
|
|
182
|
-
# Issue a long-lived workspace access token (CI / ctor agents that already hold a workspace token)
|
|
183
|
-
bricks buttress issue-token --ttl 86400
|
|
184
|
-
|
|
185
|
-
# Detach this server from the workspace
|
|
186
|
-
bricks buttress unbind
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
After binding, launchers in the same workspace will auto-discover this server; manual-mode generators will only send their access token if the server's reported workspace matches their own.
|
|
190
|
-
|
|
191
|
-
## Server Configuration (TOML)
|
|
192
|
-
|
|
193
|
-
```toml
|
|
194
|
-
[server]
|
|
195
|
-
port = 2080
|
|
196
|
-
|
|
197
|
-
[runtime]
|
|
198
|
-
cache_dir = "./.buttress-cache"
|
|
199
|
-
n_threads = 6
|
|
200
|
-
flash_attn_type = "on"
|
|
201
|
-
cache_type_k = "q8_0"
|
|
202
|
-
cache_type_v = "q8_0"
|
|
203
|
-
|
|
204
|
-
# LLM Generator
|
|
205
|
-
[[generators]]
|
|
206
|
-
type = "ggml-llm"
|
|
207
|
-
[generators.backend]
|
|
208
|
-
variant_preference = ["cuda", "vulkan", "default"]
|
|
209
|
-
gpu_memory_fraction = 0.95
|
|
210
|
-
[generators.model]
|
|
211
|
-
repo_id = "ggml-org/gemma-3-12b-it-qat-GGUF"
|
|
212
|
-
download = true
|
|
213
|
-
n_ctx = 8192
|
|
214
|
-
|
|
215
|
-
# STT Generator
|
|
216
|
-
[[generators]]
|
|
217
|
-
type = "ggml-stt"
|
|
218
|
-
[generators.backend]
|
|
219
|
-
variant_preference = ["cuda", "vulkan", "default"]
|
|
220
|
-
[generators.model]
|
|
221
|
-
repo_id = "BricksDisplay/whisper-ggml"
|
|
222
|
-
filename = "ggml-small-q8_0.bin"
|
|
223
|
-
download = true
|
|
224
|
-
use_gpu = true
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
## Use Cases
|
|
228
|
-
|
|
229
|
-
### Resource-Constrained Devices
|
|
230
|
-
Digital signage with basic hardware offloads LLM to powerful server.
|
|
231
|
-
|
|
232
|
-
### Shared GPU Resources
|
|
233
|
-
Multiple devices share single GPU server for inference.
|
|
234
|
-
|
|
235
|
-
### Development Testing
|
|
236
|
-
Test AI features on lightweight dev machines by connecting to beefy server.
|
|
237
|
-
|
|
238
|
-
## Best Practices
|
|
239
|
-
|
|
240
|
-
1. **Network reliability**: Ensure stable LAN connection to Buttress server
|
|
241
|
-
2. **Fallback strategy**: Configure appropriate fallback for critical features
|
|
242
|
-
3. **Server monitoring**: Monitor Buttress server resource usage
|
|
243
|
-
4. **Model consistency**: Ensure client and server use compatible models
|
|
244
|
-
5. **Security**: Run Buttress on private network, not public internet
|
|
245
|
-
6. **Latency awareness**: Account for network latency in UX design
|