@fugood/bricks-ctor 2.25.0-beta.6 → 2.25.0-beta.60
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/__tests__/config-diff.test.js +100 -0
- package/compile/__tests__/index.test.js +461 -0
- package/compile/__tests__/util.test.js +450 -0
- package/compile/action-name-map.ts +64 -0
- package/compile/config-diff.ts +155 -0
- package/compile/index.ts +668 -352
- package/compile/util.ts +134 -10
- package/package.json +7 -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 +19 -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 +252 -0
- package/skills/bricks-ctor/{rules → references}/media-flow.md +7 -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/__tests__/_cli-error.test.ts +35 -0
- package/tools/__tests__/_mcp-config.test.ts +67 -0
- package/tools/__tests__/pull.test.ts +108 -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/_mcp-config.ts +42 -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/__tests__/data-calc-editing.test.js +516 -0
- package/tools/mcp-tools/__tests__/entry-editing.test.js +866 -0
- package/tools/mcp-tools/__tests__/huggingface.test.ts +49 -0
- package/tools/mcp-tools/__tests__/icons.test.ts +21 -0
- package/tools/mcp-tools/__tests__/mcp-env.test.js +19 -0
- package/tools/mcp-tools/_editing-helpers.ts +98 -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 +1311 -0
- package/tools/mcp-tools/entry-editing.ts +2297 -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 +95 -38
- package/tools/pull.ts +100 -23
- 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} +11 -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} +10 -8
- 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} +80 -13
- 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/{HttpServer.ts → HttpServer.d.ts} +56 -2
- 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/{Tick.ts → Tick.d.ts} +1 -1
- package/types/generators/{VadGgml.ts → VadGgml.d.ts} +12 -2
- package/types/{subspace.ts → subspace.d.ts} +1 -1
- package/utils/__tests__/calc.test.js +25 -0
- package/utils/__tests__/id.test.js +154 -0
- package/utils/calc.ts +5 -1
- package/utils/data.ts +5 -7
- package/utils/event-props.ts +27 -1
- 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}/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/{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/{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,252 @@
|
|
|
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
|
+
## One trigger source per result panel
|
|
91
|
+
|
|
92
|
+
A panel that shows the result of an async action (Generator HTTP/LLM response, request telemetry) reads from a calc whose **trigger should come from a single source**: either the live async outlet, or a completion marker the action chain writes — not both.
|
|
93
|
+
|
|
94
|
+
- **Outlet-triggered** (`{ data: () => dResponse, trigger: true }`): the calc reruns as outlets land. Use when each outlet is only written once its value is final.
|
|
95
|
+
- **Marker-triggered**: run the generator with `waitAsync: true`, then write a `done` Data the calc triggers on. Use when several outlets settle separately and the panel must wait for all of them.
|
|
96
|
+
|
|
97
|
+
Wiring both at once — triggering on the live outlet _and_ gating on a separately-written marker — lets the calc run before the outlets have settled (it renders `undefined`/stale) while the marker path masks it intermittently. A panel that updates "sometimes" usually has two competing triggers: pick one, and order it with `waitAsync` so the trigger fires after the values it reads are written.
|
|
98
|
+
|
|
99
|
+
Scope the panel's calc to the **single value it derives** (the formatted display string), and write sibling status labels — running/done, progress, selected route — imperatively in the event chain with `PROPERTY_BANK`. A calc rewrites _every_ one of its outputs on each run, so a return that omits a key writes `undefined` to that output Data (see [Field Rules](#field-rules-defaults-and-constraints)): folding status labels into a multi-output result calc resets them to `undefined` on any run that returns only the derived value. If a calc genuinely must drive several outputs, return all of their keys every run.
|
|
100
|
+
|
|
101
|
+
## Script Sandbox
|
|
102
|
+
|
|
103
|
+
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.
|
|
104
|
+
|
|
105
|
+
### Built-in Globals
|
|
106
|
+
|
|
107
|
+
| Global | Description |
|
|
108
|
+
|--------|-------------|
|
|
109
|
+
| `inputs` | Object with input values (keyed by input `key`) |
|
|
110
|
+
| `console` | `{ log, error, warn, info }` — output is only visible in DevTools debug sessions; production is a no-op |
|
|
111
|
+
| `Platform` | `{ OS, isTV, isPad, isVision, isElectron }` |
|
|
112
|
+
| `TextEncoder`, `TextDecoder` | Text encoding/decoding |
|
|
113
|
+
| `Buffer` | Node.js Buffer (without `allocUnsafe`/`allocUnsafeSlow`) |
|
|
114
|
+
| `btoa`, `atob` | Base64 encoding/decoding |
|
|
115
|
+
|
|
116
|
+
### Async Mode
|
|
117
|
+
|
|
118
|
+
Sync mode (default) has **no `Promise`, timers, or `await`**. Enable `enableAsync: true` to unlock:
|
|
119
|
+
|
|
120
|
+
- `Promise`, `setTimeout`, `setInterval`, `setImmediate`, `clearTimeout`, `clearInterval`, `clearImmediate`, `requestAnimationFrame`
|
|
121
|
+
- Full lodash (sync mode omits `debounce`, `delay`, `defer`)
|
|
122
|
+
- `await` at the top level of the script
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
code: `
|
|
126
|
+
const result = await new Promise((resolve) => {
|
|
127
|
+
setTimeout(() => resolve(inputs.value * 2), 100)
|
|
128
|
+
})
|
|
129
|
+
return result
|
|
130
|
+
`,
|
|
131
|
+
enableAsync: true,
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Runtime Environment
|
|
135
|
+
|
|
136
|
+
| Platform | Engine |
|
|
137
|
+
|----------|--------|
|
|
138
|
+
| Android | Hermes engine sandbox |
|
|
139
|
+
| iOS | JavaScriptCore sandbox |
|
|
140
|
+
| Electron desktop | Web Worker (V8) |
|
|
141
|
+
| Web preview / Simulator | Web Worker (V8) |
|
|
142
|
+
|
|
143
|
+
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.
|
|
144
|
+
|
|
145
|
+
### Available Libraries
|
|
146
|
+
|
|
147
|
+
All exposed as globals. No network/file-download capability in any of them.
|
|
148
|
+
|
|
149
|
+
| Global | Library | Notes |
|
|
150
|
+
|--------|---------|-------|
|
|
151
|
+
| `_`, `lodash` | lodash | Sync mode omits `debounce`/`delay`/`defer` |
|
|
152
|
+
| `voca` | voca | String manipulation |
|
|
153
|
+
| `invariant` | invariant | Assertions |
|
|
154
|
+
| `json5` | json5 | JSON5 parsing |
|
|
155
|
+
| `qs` | qs | Query string parsing |
|
|
156
|
+
| `url` | node-url | URL parsing |
|
|
157
|
+
| `bytes` | bytes | Byte parsing/formatting |
|
|
158
|
+
| `ms` | ms | Millisecond conversion |
|
|
159
|
+
| `base45` | base45 | Base45 encoding |
|
|
160
|
+
| `iconv` | iconv-lite | Character encoding |
|
|
161
|
+
| `math`, `mathjs` | mathjs | Math library |
|
|
162
|
+
| `chroma` | chroma-js | Color manipulation |
|
|
163
|
+
| `moment` | moment | Date/time; auto parseFormat for string args |
|
|
164
|
+
| `nanoid` | nanoid | Unique ID generation |
|
|
165
|
+
| `md5` | md5 | MD5 hashing |
|
|
166
|
+
| `crypto` | crypto-browserify | Crypto functions |
|
|
167
|
+
| `kjurJWS` | jsrsasign | JWT/JWS signing (`KJUR.jws.JWS`) |
|
|
168
|
+
| `coseVerify` | cose-js | COSE verification (sync) |
|
|
169
|
+
| `fflate` | fflate | `{ zlibSync, unzlibSync, gzipSync, gunzipSync, compressSync, decompressSync, strFromU8 }` |
|
|
170
|
+
| `cbor` | cbor | `{ encode, decode, decodeFirstSync, decodeAllSync, addSemanticType }` |
|
|
171
|
+
| `fs` | (in-repo fs-compat) | File system; no download/upload methods |
|
|
172
|
+
| `parseDocument` | officeparser (in-repo fork) | Office document parsing (async) |
|
|
173
|
+
| `TurndownService` | turndown | HTML to Markdown |
|
|
174
|
+
| `OpenCC` | opencc-js | Chinese conversion `{ Converter, ConverterFactory, CustomConverter, Locale }` |
|
|
175
|
+
| `TOON` | @toon-format/toon | TOON format parsing |
|
|
176
|
+
|
|
177
|
+
## Recipes
|
|
178
|
+
|
|
179
|
+
### Multiple Outputs
|
|
180
|
+
|
|
181
|
+
Return an object; each `outputs` entry extracts its `key`:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
outputs: [
|
|
185
|
+
{ key: 'total', data: () => totalData },
|
|
186
|
+
{ key: 'tax', data: () => taxData },
|
|
187
|
+
{ key: 'subtotal', data: () => subtotalData },
|
|
188
|
+
],
|
|
189
|
+
output: null,
|
|
190
|
+
error: null,
|
|
191
|
+
code: `
|
|
192
|
+
const subtotal = inputs.price * inputs.quantity
|
|
193
|
+
const tax = subtotal * 0.1
|
|
194
|
+
const total = subtotal + tax
|
|
195
|
+
return { total, tax, subtotal }
|
|
196
|
+
`,
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Manual Self-Referential Update
|
|
200
|
+
|
|
201
|
+
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:
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
const appendHistory: DataCalculationScript = {
|
|
205
|
+
__typename: 'DataCalculationScript',
|
|
206
|
+
id: makeId('property_bank_calc'),
|
|
207
|
+
title: 'Append History Entry',
|
|
208
|
+
triggerMode: 'manual',
|
|
209
|
+
enableAsync: false,
|
|
210
|
+
code: `
|
|
211
|
+
const history = Array.isArray(inputs.history) ? inputs.history : []
|
|
212
|
+
return [...history, { entry: inputs.entry, at: moment().toISOString() }].slice(-50)
|
|
213
|
+
`,
|
|
214
|
+
inputs: [
|
|
215
|
+
{ key: 'history', data: () => historyData, trigger: true },
|
|
216
|
+
{ key: 'entry', data: () => entryData, trigger: true },
|
|
217
|
+
],
|
|
218
|
+
output: () => historyData, // same Data as input — manual mode only
|
|
219
|
+
outputs: [],
|
|
220
|
+
error: null,
|
|
221
|
+
}
|
|
222
|
+
// Run it from an event chain: PROPERTY_BANK writes entryData (waitAsync: true),
|
|
223
|
+
// then PROPERTY_BANK_COMMAND with input: () => entryData.
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Failure Modes
|
|
227
|
+
|
|
228
|
+
| Symptom | Cause | Fix |
|
|
229
|
+
|---------|-------|-----|
|
|
230
|
+
| Calc never auto-runs | `trigger` omitted on inputs (defaults to `false`) | Set `trigger: true` explicitly |
|
|
231
|
+
| `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) |
|
|
232
|
+
| 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 |
|
|
233
|
+
| Calc reads stale value written earlier in the same chain | Missing `waitAsync: true` on the preceding write | Set `waitAsync: true` on the write action |
|
|
234
|
+
| Result/telemetry panel shows `undefined` or stale data intermittently | Calc triggered by two sources at once (live outlet + a separately-written marker) | Trigger from one source — see [One trigger source per result panel](#one-trigger-source-per-result-panel) |
|
|
235
|
+
| Sibling status Data (selected/progress) resets to `undefined` after a calc runs | Multi-output result calc whose return omitted those keys on that run | Scope the calc to one output and write status labels imperatively, or return every output key each run — see [One trigger source per result panel](#one-trigger-source-per-result-panel) |
|
|
236
|
+
| Works in Simulator, fails on device | V8 vs Hermes/JSC engine difference | Verify on device (Path 2); avoid engine-sensitive parsing |
|
|
237
|
+
| `console.log` shows nothing | Console only emits during DevTools debug sessions | Attach DevTools, or write debug values to an output Data |
|
|
238
|
+
| `Promise`/`setTimeout` undefined, or `Async mode is required` error | `enableAsync: false` | Set `enableAsync: true` |
|
|
239
|
+
|
|
240
|
+
## Best Practices
|
|
241
|
+
|
|
242
|
+
1. **Avoid circular deps**: Set non-triggering inputs (`trigger: false`) or use `manual` mode
|
|
243
|
+
2. **Error handling**: Always set `error` output for scripts that might fail
|
|
244
|
+
3. **Keep scripts pure**: Avoid side effects, return computed values
|
|
245
|
+
4. **Debounce rapid updates**: Use `manual` mode + timer for high-frequency inputs (auto calcs re-run on every write, even unchanged)
|
|
246
|
+
|
|
247
|
+
## Anti-Patterns (AVOID)
|
|
248
|
+
|
|
249
|
+
See [Architecture Patterns](architecture-patterns.md) for the full pattern selection guide.
|
|
250
|
+
|
|
251
|
+
### Using Data Calc as an orchestrator
|
|
252
|
+
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).
|
|
@@ -31,6 +31,7 @@ const mediaListGenerator: GeneratorMediaFlow = {
|
|
|
31
31
|
description: '',
|
|
32
32
|
property: {
|
|
33
33
|
boxId: 'promo-box-id',
|
|
34
|
+
passcode: 'box-read-only-passcode',
|
|
34
35
|
},
|
|
35
36
|
outlets: {
|
|
36
37
|
files: () => promoFilesData, // Array of file objects
|
|
@@ -40,6 +41,12 @@ const mediaListGenerator: GeneratorMediaFlow = {
|
|
|
40
41
|
}
|
|
41
42
|
```
|
|
42
43
|
|
|
44
|
+
When hand-writing `GENERATOR_MEDIA_FLOW`, do not use a bare `boxId`. The editor
|
|
45
|
+
flow creates the required authorization, but manual config must include either
|
|
46
|
+
`property.passcode` from a Media Box passcode or `property.accessToken`.
|
|
47
|
+
Without one, devices cannot read the box and the generator will report an
|
|
48
|
+
authorization error.
|
|
49
|
+
|
|
43
50
|
## Property Kinds for Media
|
|
44
51
|
|
|
45
52
|
Link Data properties to Media Flow for asset selection:
|
|
@@ -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.
|