@fugood/bricks-project 2.24.7 → 2.24.8

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 CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@fugood/bricks-project",
3
- "version": "2.24.7",
3
+ "version": "2.24.8",
4
4
  "main": "index.ts",
5
5
  "scripts": {
6
6
  "typecheck": "tsc --noEmit",
7
7
  "build": "bun scripts/build.js"
8
8
  },
9
9
  "dependencies": {
10
- "@fugood/bricks-cli": "^2.24.7",
10
+ "@fugood/bricks-cli": "^2.24.8",
11
11
  "@huggingface/gguf": "^0.3.2",
12
12
  "@iarna/toml": "^3.0.0",
13
13
  "@modelcontextprotocol/sdk": "^1.15.0",
@@ -15,7 +15,7 @@ This skill covers advanced BRICKS features not in the main project instructions.
15
15
  | [Animation](references/animation.md) | Animation system for brick transforms and opacity |
16
16
  | [Standby Transition](references/standby-transition.md) | Canvas enter/exit animations |
17
17
  | [Automations](references/automations.md) | E2E testing and scheduled tasks |
18
- | [Data Calculation](references/data-calculation.md) | JS sandbox libraries (25+ available) |
18
+ | [Data Calculation](references/data-calculation.md) | Wiring contract, trigger semantics, JS sandbox (25+ libraries) |
19
19
  | [Local Sync](references/local-sync.md) | LAN device synchronization |
20
20
  | [Remote Data Bank](references/remote-data-bank.md) | Cloud data sync and API access |
21
21
  | [Media Flow](references/media-flow.md) | Media asset management |
@@ -1,13 +1,20 @@
1
1
  # Data Calculation (JS Sandbox)
2
2
 
3
- Transform and compute Data Bank values using JavaScript scripts.
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
4
 
5
- ## DataCalculationScript
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) |
6
12
 
7
- JavaScript code executed in a sandbox with access to inputs and outputs.
13
+ ## Authoring Contract
8
14
 
9
15
  ```typescript
10
16
  import { makeId } from 'bricks-ctor'
17
+ import { readFile } from 'node:fs/promises'
11
18
 
12
19
  const calculation: DataCalculationScript = {
13
20
  __typename: 'DataCalculationScript',
@@ -15,9 +22,9 @@ const calculation: DataCalculationScript = {
15
22
  title: 'Format Price',
16
23
  description: 'Formats price with currency symbol',
17
24
  note: '',
18
- triggerMode: 'auto', // 'auto' | 'manual'
25
+ triggerMode: 'auto', // 'auto' (default) | 'manual'
19
26
  enableAsync: false,
20
- // Inline code
27
+ // Inline code for short scripts...
21
28
  code: `
22
29
  const price = inputs.price || 0
23
30
  const currency = inputs.currency || 'USD'
@@ -26,118 +33,82 @@ const calculation: DataCalculationScript = {
26
33
  currency,
27
34
  }).format(price)
28
35
  `,
29
- // Or load from file (preferred for longer scripts)
30
- // import { readFile } from 'node:fs/promises'
36
+ // ...or load from a file (preferred for longer scripts):
31
37
  // code: await readFile(new URL('./format-price.sandbox.js', import.meta.url), 'utf8'),
32
38
  inputs: [
33
39
  { key: 'price', data: () => priceData, trigger: true },
34
40
  { key: 'currency', data: () => currencyData, trigger: false },
35
41
  ],
36
42
  output: () => formattedPriceData,
37
- outputs: [], // Additional named outputs
43
+ outputs: [], // Additional named outputs (see Multiple Outputs)
38
44
  error: null, // or () => errorData for error handling
39
45
  }
40
46
  ```
41
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
+
42
57
  ## Trigger Modes
43
58
 
44
59
  | Mode | Description |
45
60
  |------|-------------|
46
- | `auto` | Run when input values change (with trigger: true) |
47
- | `manual` | Only run via `PROPERTY_BANK_COMMAND` action |
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
+ ```
48
85
 
49
- Use `manual` to prevent circular dependencies or for explicit control.
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).
50
89
 
51
- ## Script Sandbox Features
90
+ ## Script Sandbox
52
91
 
53
- Scripts run in `use strict` mode with a sandboxed set of globals and libraries.
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.
54
93
 
55
94
  ### Built-in Globals
56
95
 
57
96
  | Global | Description |
58
97
  |--------|-------------|
59
- | `inputs` | Object with input values |
60
- | `console` | `{ log, error, warn, info }` for debugging |
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 |
61
100
  | `Platform` | `{ OS, isTV, isPad, isVision, isElectron }` |
62
101
  | `TextEncoder`, `TextDecoder` | Text encoding/decoding |
63
- | `Buffer` | Node.js Buffer (without `allocUnsafe`) |
102
+ | `Buffer` | Node.js Buffer (without `allocUnsafe`/`allocUnsafeSlow`) |
64
103
  | `btoa`, `atob` | Base64 encoding/decoding |
65
104
 
66
- ### Available Libraries
67
-
68
- **Utility**
69
- | Library | Global | Description |
70
- |---------|--------|-------------|
71
- | [lodash](https://lodash.com) | `_`, `lodash` | Utility (sync: no debounce/delay/defer) |
72
- | [voca](https://vocajs.com) | `voca` | String manipulation |
73
- | [invariant](https://github.com/zertosh/invariant) | `invariant` | Assertions |
74
-
75
- **Data & Encoding**
76
- | Library | Global | Description |
77
- |---------|--------|-------------|
78
- | [json5](https://github.com/json5/json5) | `json5` | JSON5 parsing |
79
- | [qs](https://github.com/ljharb/qs) | `qs` | Query string parsing |
80
- | [url](https://github.com/defunctzombie/node-url) | `url` | URL parsing |
81
- | [bytes](https://github.com/visionmedia/bytes.js) | `bytes` | Byte parsing/formatting |
82
- | [ms](https://github.com/vercel/ms) | `ms` | Millisecond conversion |
83
- | [base45](https://github.com/irony/base45) | `base45` | Base45 encoding |
84
- | [iconv-lite](https://github.com/ashtuchkin/iconv-lite) | `iconv` | Character encoding |
85
-
86
- **Math & Color**
87
- | Library | Global | Description |
88
- |---------|--------|-------------|
89
- | [mathjs](https://mathjs.org) | `math`, `mathjs` | Math library |
90
- | [chroma-js](https://gka.github.io/chroma.js) | `chroma` | Color manipulation |
91
-
92
- **Date/Time**
93
- | Library | Global | Description |
94
- |---------|--------|-------------|
95
- | [moment](https://momentjs.com) | `moment` | Date/time (auto parseFormat) |
96
-
97
- **ID & Hash**
98
- | Library | Global | Description |
99
- |---------|--------|-------------|
100
- | [nanoid](https://github.com/ai/nanoid) | `nanoid` | Unique ID generation |
101
- | [md5](https://github.com/pvorb/node-md5) | `md5` | MD5 hashing |
102
-
103
- **Crypto**
104
- | Library | Global | Description |
105
- |---------|--------|-------------|
106
- | [crypto-browserify](https://github.com/crypto-browserify/crypto-browserify) | `crypto` | Crypto functions |
107
- | [jsrsasign](https://github.com/kjur/jsrsasign) | `kjurJWS` | JWT/JWS signing |
108
- | [cose-js](https://github.com/erdtman/COSE-JS) | `coseVerify` | COSE verification (sync) |
109
-
110
- **Compression**
111
- | Library | Global | Description |
112
- |---------|--------|-------------|
113
- | [fflate](https://github.com/101arrowz/fflate) | `fflate` | `{ zlibSync, unzlibSync, gzipSync, gunzipSync, compressSync, decompressSync, strFromU8 }` |
114
- | [cbor](https://github.com/hildjj/node-cbor) | `cbor` | `{ encode, decode, decodeFirstSync, decodeAllSync }` |
115
-
116
- **File & Document**
117
- | Library | Global | Description |
118
- |---------|--------|-------------|
119
- | fs | `fs` | File system (limited, no download/upload) |
120
- | [officeparser](https://github.com/nicktang) | `parseDocument` | Office document parsing (async) |
121
- | [turndown](https://github.com/mixmark-io/turndown) | `TurndownService` | HTML to Markdown |
122
- | [opencc-js](https://github.com/nk2028/opencc-js) | `OpenCC` | Chinese conversion `{ Converter, ConverterFactory, CustomConverter, Locale }` |
123
- | [toon-format](https://github.com/nicktang) | `TOON` | TOON format parsing |
124
-
125
- ### Runtime Environment
126
-
127
- | Platform | Engine |
128
- |----------|--------|
129
- | Android | Hermes engine sandbox |
130
- | iOS | JavaScriptCore sandbox |
131
-
132
105
  ### Async Mode
133
106
 
134
- Enable `enableAsync: true` to unlock additional capabilities:
107
+ Sync mode (default) has **no `Promise`, timers, or `await`**. Enable `enableAsync: true` to unlock:
135
108
 
136
- **Additional async globals:**
137
- - `Promise`, `setTimeout`, `setInterval`, `setImmediate`
138
- - `clearTimeout`, `clearInterval`, `clearImmediate`
139
- - `requestAnimationFrame`
140
- - Full lodash (including `debounce`, `delay`, `defer`)
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
141
112
 
142
113
  ```typescript
143
114
  code: `
@@ -149,14 +120,63 @@ code: `
149
120
  enableAsync: true,
150
121
  ```
151
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
+
152
168
  ### Multiple Outputs
153
169
 
170
+ Return an object; each `outputs` entry extracts its `key`:
171
+
154
172
  ```typescript
155
173
  outputs: [
156
174
  { key: 'total', data: () => totalData },
157
175
  { key: 'tax', data: () => taxData },
158
176
  { key: 'subtotal', data: () => subtotalData },
159
177
  ],
178
+ output: null,
179
+ error: null,
160
180
  code: `
161
181
  const subtotal = inputs.price * inputs.quantity
162
182
  const tax = subtotal * 0.1
@@ -165,31 +185,51 @@ code: `
165
185
  `,
166
186
  ```
167
187
 
168
- ## Triggering Manually
188
+ ### Manual Self-Referential Update
169
189
 
170
- Use `PROPERTY_BANK_COMMAND` system action to trigger a manual calculation. `input` references a Data that is a trigger input (`trigger: true`) of the target calc the system runs the calc(s) that data feeds into. It does NOT reference the DataCalculation itself.
190
+ When an update is too complex for `PROPERTY_BANK_EXPRESSION` and must read its own previous valuemanual mode allows the same Data as input and output:
171
191
 
172
192
  ```typescript
173
- const triggerCalc: EventAction = {
174
- handler: 'system',
175
- action: {
176
- __actionName: 'PROPERTY_BANK_COMMAND',
177
- parent: 'System',
178
- dataParams: [
179
- { input: () => priceData }, // Reference to a trigger Data input of the calc
180
- ],
181
- },
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,
182
210
  }
211
+ // Run it from an event chain: PROPERTY_BANK writes entryData (waitAsync: true),
212
+ // then PROPERTY_BANK_COMMAND with input: () => entryData.
183
213
  ```
184
214
 
185
- When the same chain writes a calc input (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).
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` |
186
226
 
187
227
  ## Best Practices
188
228
 
189
229
  1. **Avoid circular deps**: Set non-triggering inputs (`trigger: false`) or use `manual` mode
190
230
  2. **Error handling**: Always set `error` output for scripts that might fail
191
231
  3. **Keep scripts pure**: Avoid side effects, return computed values
192
- 4. **Debounce rapid updates**: Use `manual` mode + timer for high-frequency inputs
232
+ 4. **Debounce rapid updates**: Use `manual` mode + timer for high-frequency inputs (auto calcs re-run on every write, even unchanged)
193
233
 
194
234
  ## Anti-Patterns (AVOID)
195
235
 
@@ -197,13 +237,3 @@ See [Architecture Patterns](architecture-patterns.md) for the full pattern selec
197
237
 
198
238
  ### Using Data Calc as an orchestrator
199
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).
200
-
201
- ### Quick reference
202
-
203
- | If you need to... | Use instead |
204
- |---|---|
205
- | Call an LLM / AI model | Generator (Assistant, LLM, HTTP) |
206
- | Sequence multiple actions | Event Action Chain |
207
- | Set a data value directly | PROPERTY_BANK system action |
208
- | Compute a simple expression | PROPERTY_BANK_EXPRESSION |
209
- | Transform/format/parse data | Data Calculation (correct use) |
@@ -1,30 +1,20 @@
1
1
  ---
2
2
  name: bricks-design
3
3
  description: >-
4
- Visual design discipline for Applications and Subspaces — type,
5
- palette, asset acquisition, design language, system commitment,
6
- visual rhythm, brand. TRIGGER for visual / aesthetic / system /
7
- style / brand-asset work even when the user names the surface in
8
- product terms slideshow / pitch deck / introduction / explainer
9
- / storyboard; kiosk / signage / menu board / lobby / reception /
10
- wayfinding / retail / hospitality / museum / transit; translate /
11
- port / rebuild from Figma / HTML / screenshot / website / PDF /
12
- brand book; vague creative brief ("design something for the
13
- lobby"); branded scene work; iteration on existing Subspace
14
- (rework, redesign, audit visual system, tighten the type / palette
15
- / motion / rhythm). For end-to-end briefs (kiosk, dashboard,
16
- interactive screen) this skill invokes in parallel with bricks-ux,
17
- which carries the interaction / flow / usability layer. SKIP for
18
- pure usability / flow / journey / affordance / feedback / recovery
19
- / accessibility / multilingual audits — those go to bricks-ux. SKIP
20
- for single-Brick or Generator template work
21
- (create-brick-or-generator), debugging or refactoring with no
22
- design intent, or non-display deliverables (CLI, server, tooling).
23
- Encodes architecture truths, performance and complexity guardrails,
24
- input-translation rules, visual languages library, Direction
25
- Advisor for vague briefs, Media Flow protocol for branded work.
26
- Verification toolchain (compile, preview tool selection, on-device DevTools,
27
- Path 1/2/3) lives in the bricks-ctor skill.
4
+ Visual design discipline for Applications and Subspaces — type, palette, asset
5
+ acquisition, design language, system commitment, visual rhythm, brand. TRIGGER
6
+ for visual / aesthetic / system / style / brand-asset work even when named in
7
+ product terms slideshow, pitch deck, explainer, kiosk, signage, menu board,
8
+ lobby, wayfinding, retail, museum, transit; translate or rebuild from Figma /
9
+ HTML / screenshot / website / PDF / brand book; vague creative briefs; branded
10
+ scenes; rework or audit of an existing Subspace's type / palette / motion /
11
+ rhythm. For end-to-end briefs invoke in parallel with bricks-ux (interaction /
12
+ flow layer). SKIP for pure usability / flow / accessibility audits (bricks-
13
+ ux), single-Brick or Generator template work (create-brick-or-generator),
14
+ debugging without design intent, or non-display deliverables. Encodes
15
+ architecture truths, performance guardrails, input-translation rules, visual
16
+ languages, Direction Advisor, Media Flow protocol; verification toolchain
17
+ lives in bricks-ctor.
28
18
  ---
29
19
 
30
20
  # BRICKS Design
@@ -1,26 +1,20 @@
1
1
  ---
2
2
  name: bricks-ux
3
3
  description: >-
4
- Interaction design and end-user experience for any Application or
5
- Subspace built on Canvases, Bricks, Generators, Data, DataCalculation.
6
- TRIGGER on usability / flow / interaction / journey / state /
7
- affordance / feedback / recovery / accessibility audits and design
8
- work "audit this flow", "improve usability", "design the wait
9
- state", "fix the error path", "make the kiosk usable", "what does the
10
- user do when X breaks", "design the QR scan UX", "design the payment
11
- flow", "design the mic / listening state", "design the monitor's
12
- alarm state", "design for multilingual", "design for low vision",
13
- "design idle and attractor states". Also triggers in parallel with
14
- visual-design work for end-to-end deliverables (kiosk / signage /
15
- dashboard / interactive screen / pitch deck) where the interaction
16
- shape matters as much as the look. SKIP for purely visual / aesthetic
17
- / system / style / brand-asset / typography / palette work — those
18
- are visual design, not interaction design. Encodes a universal
19
- user-journey spine, interaction archetypes, pressable composition,
20
- monitoring-screen discipline, designed flow states, accessibility,
21
- and a tiered UX critique. Hardware floors are deployment-relative;
22
- web habits (hover affordances, modal-as-default, scroll, page-submit
23
- forms) do not transfer.
4
+ Interaction design and end-user experience for any Application or Subspace
5
+ built on Canvases, Bricks, Generators, Data, DataCalculation. TRIGGER on
6
+ usability / flow / interaction / journey / state / affordance / feedback /
7
+ recovery / accessibility audits and design work — "audit this flow", "improve
8
+ usability", "design the wait state", "make the kiosk usable", "design the
9
+ payment flow", "design idle and attractor states", "design for multilingual /
10
+ low vision". Also triggers in parallel with visual-design work for end-to-end
11
+ deliverables (kiosk, signage, dashboard, interactive screen, pitch deck) where
12
+ interaction shape matters as much as look. SKIP for purely visual / aesthetic
13
+ / style / brand-asset / typography / palette work — that is bricks-design.
14
+ Encodes a universal user-journey spine, interaction archetypes, pressable
15
+ composition, monitoring-screen discipline, designed flow states,
16
+ accessibility, tiered UX critique; hardware floors are deployment-relative and
17
+ web habits do not transfer.
24
18
  ---
25
19
 
26
20
  # BRICKS UX
@@ -69,8 +69,15 @@ const projectMcpServer = {
69
69
  args: [`${cwd}/node_modules/@fugood/bricks-ctor/tools/mcp-server.ts`],
70
70
  }
71
71
 
72
+ // Codex cancels MCP tool calls it cannot prompt approval for (e.g. `codex exec`),
73
+ // so the project-local server's tools must be pre-approved in its config entry.
74
+ const codexProjectMcpServer = {
75
+ ...projectMcpServer,
76
+ default_tools_approval_mode: 'approve',
77
+ }
78
+
72
79
  type CodexMcpConfig = {
73
- mcp_servers: Record<string, typeof projectMcpServer>
80
+ mcp_servers: Record<string, typeof codexProjectMcpServer | typeof projectMcpServer>
74
81
  }
75
82
 
76
83
  // Claude Code and AGENTS.md projects both use the shared project .mcp.json file.
@@ -196,11 +203,81 @@ if (hasClaudeCode || hasAgentsMd) {
196
203
  await setupSkills()
197
204
  }
198
205
 
206
+ type ClaudeSettings = {
207
+ autoMode?: {
208
+ environment?: string[]
209
+ allow?: string[]
210
+ soft_deny?: string[]
211
+ hard_deny?: string[]
212
+ }
213
+ [key: string]: unknown
214
+ }
215
+
216
+ // Trusted infrastructure for auto mode's classifier. `$defaults` keeps the
217
+ // built-in environment (the working repo and its git remotes); the extra
218
+ // entries stop routine syncs to the BRICKS backend from being treated as
219
+ // external exfiltration. See https://code.claude.com/docs/en/auto-mode-config
220
+ const autoModeEnvironment = [
221
+ '$defaults',
222
+ 'Organization: BRICKS (bricks.tools). Primary use: building BRICKS apps/modules with the bricks CLI and the local bricks-ctor MCP server.',
223
+ 'Trusted internal domains: all *.bricks.tools services — api.bricks.tools (project GraphQL API), bank.bricks.tools (config & asset Bank API), cdn.bricks.tools (asset CDN), plus the control/display/activity services. This project syncs its config and assets to these endpoints.',
224
+ ]
225
+
226
+ // `.claude/settings.local.json` is per-developer local config; keep it untracked.
227
+ const ensureSettingsLocalGitignored = async () => {
228
+ const gitignorePath = path.join(cwd, '.gitignore')
229
+ const entry = '.claude/settings.local.json'
230
+ const coveredBy = new Set([entry, '.claude', '.claude/', '.claude/*', '*.local.json'])
231
+
232
+ let content = ''
233
+ if (await exists(gitignorePath)) {
234
+ content = await readFile(gitignorePath, 'utf-8')
235
+ if (content.split('\n').some((line) => coveredBy.has(line.trim()))) return
236
+ }
237
+
238
+ const separator = content.length === 0 ? '' : content.endsWith('\n') ? '\n' : '\n\n'
239
+ await writeFile(gitignorePath, `${content}${separator}# Claude Code local settings\n${entry}\n`)
240
+ console.log(`Added ${entry} to .gitignore`)
241
+ }
242
+
243
+ // Pre-configure auto mode once, on initial setup. We only seed the classifier's
244
+ // trusted infrastructure — not `permissions.defaultMode: 'auto'`, which Claude
245
+ // Code ignores from project/local settings (a repo can't grant itself auto mode;
246
+ // it only takes effect from ~/.claude/settings.json). An existing autoMode block
247
+ // is left untouched so reinstalls never clobber a developer's customizations.
248
+ const setupClaudeAutoMode = async () => {
249
+ const settingsPath = path.join(cwd, '.claude', 'settings.local.json')
250
+
251
+ let settings: ClaudeSettings = {}
252
+ if (await exists(settingsPath)) {
253
+ try {
254
+ settings = JSON.parse(await readFile(settingsPath, 'utf-8'))
255
+ } catch {
256
+ console.warn(`Skipping auto mode setup; ${settingsPath} is not valid JSON`)
257
+ return
258
+ }
259
+ if (settings.autoMode) return
260
+ }
261
+
262
+ settings.autoMode = { environment: autoModeEnvironment }
263
+
264
+ await mkdir(path.dirname(settingsPath), { recursive: true })
265
+ await writeFile(settingsPath, `${JSON.stringify(settings, null, 2)}\n`)
266
+ console.log(`Set up auto mode in ${settingsPath}`)
267
+
268
+ await ensureSettingsLocalGitignored()
269
+ }
270
+
271
+ if (hasClaudeCode) {
272
+ // Pre-configure auto mode's trusted infrastructure for Claude Code projects.
273
+ await setupClaudeAutoMode()
274
+ }
275
+
199
276
  if (hasAgentsMd) {
200
277
  // Codex stores its project-local MCP config in .codex/config.toml.
201
278
  const defaultCodexMcpConfig = {
202
279
  mcp_servers: {
203
- 'bricks-ctor': projectMcpServer,
280
+ 'bricks-ctor': codexProjectMcpServer,
204
281
  },
205
282
  }
206
283
 
@@ -212,7 +289,7 @@ if (hasAgentsMd) {
212
289
  const parsed = TOML.parse(configStr) as Partial<CodexMcpConfig>
213
290
  if (!parsed?.mcp_servers) throw new Error('mcp_servers is not defined')
214
291
  mcpConfig = { mcp_servers: parsed.mcp_servers }
215
- mcpConfig.mcp_servers['bricks-ctor'] = projectMcpServer
292
+ mcpConfig.mcp_servers['bricks-ctor'] = codexProjectMcpServer
216
293
  delete mcpConfig.mcp_servers['bricks-project']
217
294
  } catch {
218
295
  mcpConfig = defaultCodexMcpConfig
@@ -18,7 +18,9 @@ export type DataCommandSandboxGetReturnValue = DataCommand & {
18
18
  /* Run JS — Run JavaScript code
19
19
 
20
20
  - Default `use strict`
21
- - Global functions fetch, XMLHttpRequest, setTimeout, setInterval... are not available.
21
+ - Global functions fetch, XMLHttpRequest are not available.
22
+ - setTimeout, setInterval, Promise... require Enable Async.
23
+ - Built-in globals: Platform, Buffer, btoa/atob, TextEncoder/TextDecoder
22
24
 
23
25
  ##### Available libraries (global)
24
26
 
@@ -43,10 +45,16 @@ export type DataCommandSandboxGetReturnValue = DataCommand & {
43
45
  - fflate (Not support async, callback and stream)
44
46
  - iconv (Use iconv-lite)
45
47
  - OpenCC (Use opencc-js)
48
+ - fs (Limited, no download/upload)
49
+ - parseDocument (Use officeparser, requires Enable Async)
50
+ - TurndownService (Use turndown, HTML to Markdown)
51
+ - TOON (Use toon-format/toon)
46
52
 
47
53
  Android: Running on the sandbox of Hermes engine
48
54
 
49
- iOS: Running on the sandbox of iOS built-in JavaScriptCore */
55
+ iOS: Running on the sandbox of iOS built-in JavaScriptCore
56
+
57
+ Desktop / Web: Running on the sandbox of a Web Worker */
50
58
  export type DataCommandSandboxRunJavascript = DataCommand & {
51
59
  __commandName: 'SANDBOX_RUN_JAVASCRIPT'
52
60
  inputs?: Array<