@fugood/bricks-project 2.24.4 → 2.24.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/compile/action-name-map.ts +5 -0
- package/compile/index.ts +8 -4
- package/package.json +2 -2
- package/package.json.bak +2 -2
- package/skills/bricks-ctor/SKILL.md +2 -2
- package/skills/bricks-ctor/rules/architecture-patterns.md +12 -0
- package/skills/bricks-ctor/rules/automations.md +11 -0
- package/skills/bricks-ctor/rules/data-calculation.md +5 -5
- package/skills/bricks-ctor/rules/verification-toolchain.md +16 -9
- package/skills/bricks-design/SKILL.md +2 -2
- package/skills/bricks-design/references/architecture-truths.md +10 -3
- package/skills/bricks-design/references/variations-and-tweaks.md +1 -1
- package/tools/_shell.ts +8 -1
- package/tools/mcp-tools/compile.ts +17 -7
- package/tools/mcp-tools/media.ts +4 -1
- package/types/animation.ts +8 -3
- package/types/brick-base.ts +1 -1
- package/types/bricks/Camera.ts +8 -8
- package/types/bricks/Chart.ts +4 -4
- package/types/bricks/GenerativeMedia.ts +15 -15
- package/types/bricks/Icon.ts +7 -7
- package/types/bricks/Image.ts +9 -9
- package/types/bricks/Items.ts +7 -7
- package/types/bricks/Lottie.ts +10 -10
- package/types/bricks/Maps.ts +11 -11
- package/types/bricks/QrCode.ts +7 -7
- package/types/bricks/Rect.ts +7 -7
- package/types/bricks/RichText.ts +12 -9
- package/types/bricks/Rive.ts +9 -9
- package/types/bricks/Sketch.ts +6 -6
- package/types/bricks/Slideshow.ts +7 -7
- package/types/bricks/Svg.ts +7 -7
- package/types/bricks/Text.ts +9 -9
- package/types/bricks/TextInput.ts +10 -10
- package/types/bricks/Video.ts +12 -12
- package/types/bricks/VideoStreaming.ts +10 -10
- package/types/bricks/WebRtcStream.ts +1 -1
- package/types/bricks/WebView.ts +4 -4
- package/types/common.ts +2 -2
- package/types/data-calc-command/base.ts +57 -0
- package/types/data-calc-command/collection.ts +418 -0
- package/types/data-calc-command/color.ts +432 -0
- package/types/data-calc-command/constant.ts +50 -0
- package/types/data-calc-command/datetime.ts +147 -0
- package/types/data-calc-command/file.ts +129 -0
- package/types/data-calc-command/index.ts +13 -0
- package/types/data-calc-command/iteratee.ts +23 -0
- package/types/data-calc-command/logictype.ts +190 -0
- package/types/data-calc-command/math.ts +275 -0
- package/types/data-calc-command/object.ts +119 -0
- package/types/data-calc-command/sandbox.ts +58 -0
- package/types/data-calc-command/string.ts +407 -0
- package/types/data.ts +1 -1
- package/types/generators/LlmGgml.ts +37 -0
- package/utils/data.ts +1 -1
- package/utils/id.ts +78 -27
- package/types/data-calc-command.ts +0 -7005
|
@@ -782,6 +782,11 @@ export const templateActionNameMap = {
|
|
|
782
782
|
seed: 'GENERATOR_LLM_SEED',
|
|
783
783
|
typicalP: 'GENERATOR_LLM_TYPICAL_P',
|
|
784
784
|
ignoreEos: 'GENERATOR_LLM_IGNORE_EOS',
|
|
785
|
+
mtpSpeculativeDecoding: 'GENERATOR_LLM_MTP_SPECULATIVE_DECODING',
|
|
786
|
+
mtpDraftTokens: 'GENERATOR_LLM_MTP_DRAFT_TOKENS',
|
|
787
|
+
mtpDraftMinTokens: 'GENERATOR_LLM_MTP_DRAFT_MIN_TOKENS',
|
|
788
|
+
mtpDraftMinProbability: 'GENERATOR_LLM_MTP_DRAFT_MIN_PROBABILITY',
|
|
789
|
+
mtpDraftSplitProbability: 'GENERATOR_LLM_MTP_DRAFT_SPLIT_PROBABILITY',
|
|
785
790
|
functionCallEnabled: 'GENERATOR_LLM_FUNCTION_CALL_ENABLED',
|
|
786
791
|
functionCallSchema: 'GENERATOR_LLM_FUNCTION_CALL_SCHEMA',
|
|
787
792
|
},
|
package/compile/index.ts
CHANGED
|
@@ -154,11 +154,13 @@ const basicAnimationEvents = ['show', 'standby', 'breatheStart']
|
|
|
154
154
|
|
|
155
155
|
const compileAnimations = (
|
|
156
156
|
templateKey: string,
|
|
157
|
-
animations: { [key: string]: Animation },
|
|
157
|
+
animations: { [key: string]: Animation | (() => Animation) },
|
|
158
158
|
errorReference: string,
|
|
159
159
|
) =>
|
|
160
160
|
Object.entries(animations).reduce((acc, [key, animation]) => {
|
|
161
|
-
|
|
161
|
+
// Animation events accept either a direct Animation or a getter; unwrap.
|
|
162
|
+
const resolved = typeof animation === 'function' ? animation() : animation
|
|
163
|
+
const animationId = assertEntryId(resolved?.id, 'ANIMATION', errorReference)
|
|
162
164
|
acc[convertEventKey(basicAnimationEvents.includes(key) ? 'BRICK' : templateKey, key)] =
|
|
163
165
|
`ANIMATION#${animationId}`
|
|
164
166
|
return acc
|
|
@@ -1190,7 +1192,7 @@ export const compile = async (app: Application) => {
|
|
|
1190
1192
|
...compileRemoteUpdate(data.remoteUpdate),
|
|
1191
1193
|
routing: data.routing,
|
|
1192
1194
|
schema: data.schema,
|
|
1193
|
-
type: data.type,
|
|
1195
|
+
type: data.type === 'boolean' ? 'bool' : data.type,
|
|
1194
1196
|
...compileKind(data.kind),
|
|
1195
1197
|
value: compileProperty(data.value, `(data: ${dataId}, subspace ${subspaceId})`),
|
|
1196
1198
|
event_map: compileEvents('PROPERTY_BANK', data.events || {}, {
|
|
@@ -1456,5 +1458,7 @@ export const compile = async (app: Application) => {
|
|
|
1456
1458
|
|
|
1457
1459
|
export const checkConfig = async (configPath: string) => {
|
|
1458
1460
|
const { sh } = await import('../tools/_shell')
|
|
1459
|
-
|
|
1461
|
+
// --validate-automation surfaces broken automation_map / test_map refs early,
|
|
1462
|
+
// which catches agent-authored automations that reference deleted bricks.
|
|
1463
|
+
await sh`bricks app check-config --validate-automation ${configPath}`
|
|
1460
1464
|
}
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fugood/bricks-project",
|
|
3
|
-
"version": "2.24.
|
|
3
|
+
"version": "2.24.5",
|
|
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.
|
|
10
|
+
"@fugood/bricks-cli": "^2.24.5",
|
|
11
11
|
"@huggingface/gguf": "^0.3.2",
|
|
12
12
|
"@iarna/toml": "^3.0.0",
|
|
13
13
|
"@modelcontextprotocol/sdk": "^1.15.0",
|
package/package.json.bak
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fugood/bricks-ctor",
|
|
3
|
-
"version": "2.24.
|
|
3
|
+
"version": "2.24.5",
|
|
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.
|
|
10
|
+
"@fugood/bricks-cli": "^2.24.5",
|
|
11
11
|
"@huggingface/gguf": "^0.3.2",
|
|
12
12
|
"@iarna/toml": "^3.0.0",
|
|
13
13
|
"@modelcontextprotocol/sdk": "^1.15.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bricks-ctor
|
|
3
|
-
description: Advanced BRICKS configuration knowledge. Covers Standby Transition, Automations (E2E testing), Data Calculation (JS sandbox libraries), Local Sync, Remote Data Bank, Media Flow, Buttress (remote inference), and the verification toolchain (compile
|
|
3
|
+
description: Advanced BRICKS configuration knowledge. Covers Standby Transition, Automations (E2E testing), Data Calculation (JS sandbox libraries), Local Sync, Remote Data Bank, Media Flow, Buttress (remote inference), and the verification toolchain (compile, harness-specific preview tool, on-device DevTools, definition-of-done gate). Triggers on multi-device sync, cloud data, media assets, AI offloading, E2E testing, canvas transitions, or verifying project work before declaring done.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# BRICKS Ctor - Advanced Features
|
|
@@ -20,7 +20,7 @@ This skill covers advanced BRICKS features not in the main project instructions.
|
|
|
20
20
|
| [Remote Data Bank](rules/remote-data-bank.md) | Cloud data sync and API access |
|
|
21
21
|
| [Media Flow](rules/media-flow.md) | Media asset management |
|
|
22
22
|
| [Buttress](rules/buttress.md) | Remote inference for AI generators |
|
|
23
|
-
| [Verification Toolchain](rules/verification-toolchain.md) | Definition of done, compile
|
|
23
|
+
| [Verification Toolchain](rules/verification-toolchain.md) | Definition of done, compile, preview tool selection, on-device DevTools, Path 1/2/3 decision rule |
|
|
24
24
|
|
|
25
25
|
## Quick Reference
|
|
26
26
|
|
|
@@ -26,6 +26,8 @@ The primary way to orchestrate multi-step flows. A single event can contain an a
|
|
|
26
26
|
- Use `dataParams` + `mapping` to pass event data downstream
|
|
27
27
|
- This is the "glue" that wires generators, state, and UI together
|
|
28
28
|
|
|
29
|
+
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.
|
|
30
|
+
|
|
29
31
|
### System Actions (Priority 3)
|
|
30
32
|
Built-in commands for direct state and UI changes.
|
|
31
33
|
- **PROPERTY_BANK**: set data value
|
|
@@ -67,3 +69,13 @@ Only actual data derivation maps to Data Calculation:
|
|
|
67
69
|
|
|
68
70
|
### Step 4: Wire with Event Action Chains
|
|
69
71
|
Connect the pieces through events on generators and bricks.
|
|
72
|
+
|
|
73
|
+
## Recipe: user-driven state machine (calculator, form wizard, picker)
|
|
74
|
+
|
|
75
|
+
A brief like "state vars X, Y, Z; button A updates X from X+Y; button B resets" is a state machine. The shape:
|
|
76
|
+
|
|
77
|
+
- Each state variable is its own `Data` entity. Displays read it via `linkData(() => data.dFoo)`.
|
|
78
|
+
- 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.
|
|
79
|
+
- Use `Data Calculation` only for reusable pure derivations referenced as inputs to those expressions.
|
|
80
|
+
|
|
81
|
+
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.
|
|
@@ -118,6 +118,16 @@ const testLoginFlow: AutomationTest = {
|
|
|
118
118
|
| `match_screenshot` | `[name, threshold?, maxRetry?]` | Screenshot compare |
|
|
119
119
|
| `delay` | `[subspace?, property?, defaultValue?]` | Delay execution |
|
|
120
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
|
+
|
|
121
131
|
### execute_action Params
|
|
122
132
|
|
|
123
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.
|
|
@@ -208,6 +218,7 @@ Automations work with Modules. Use Manual Run in Preview mode for module testing
|
|
|
208
218
|
|
|
209
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`.
|
|
210
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.
|
|
211
222
|
- **handler in execute_action**: Pass the entity's `.id` string (e.g., `bricks.bInput.id`), not a getter function.
|
|
212
223
|
|
|
213
224
|
## Best Practices
|
|
@@ -167,7 +167,7 @@ code: `
|
|
|
167
167
|
|
|
168
168
|
## Triggering Manually
|
|
169
169
|
|
|
170
|
-
Use `PROPERTY_BANK_COMMAND` system action to trigger a manual calculation:
|
|
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.
|
|
171
171
|
|
|
172
172
|
```typescript
|
|
173
173
|
const triggerCalc: EventAction = {
|
|
@@ -176,12 +176,14 @@ const triggerCalc: EventAction = {
|
|
|
176
176
|
__actionName: 'PROPERTY_BANK_COMMAND',
|
|
177
177
|
parent: 'System',
|
|
178
178
|
dataParams: [
|
|
179
|
-
{ input: () =>
|
|
179
|
+
{ input: () => priceData }, // Reference to a trigger Data input of the calc
|
|
180
180
|
],
|
|
181
181
|
},
|
|
182
182
|
}
|
|
183
183
|
```
|
|
184
184
|
|
|
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).
|
|
186
|
+
|
|
185
187
|
## Best Practices
|
|
186
188
|
|
|
187
189
|
1. **Avoid circular deps**: Set non-triggering inputs (`trigger: false`) or use `manual` mode
|
|
@@ -194,9 +196,7 @@ const triggerCalc: EventAction = {
|
|
|
194
196
|
See [Architecture Patterns](architecture-patterns.md) for the full pattern selection guide.
|
|
195
197
|
|
|
196
198
|
### Using Data Calc as an orchestrator
|
|
197
|
-
Scripts that manage state machines, control UI flow, or coordinate multi-step processes belong in Event Action Chains,
|
|
198
|
-
|
|
199
|
-
**Symptom**: Script has if/else branches deciding "what happens next" or tracks "current step".
|
|
199
|
+
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
200
|
|
|
201
201
|
### Quick reference
|
|
202
202
|
|
|
@@ -7,7 +7,7 @@ Three runtime targets, one decision rule. Verify against the cheapest path that
|
|
|
7
7
|
Before the agent is allowed to claim work is complete, **all** of the following must be true:
|
|
8
8
|
|
|
9
9
|
1. **Compile clean.** Latest source passes `compile` with no errors.
|
|
10
|
-
2. **Every Canvas screenshot captured.** A rendered screenshot of every Canvas in the deliverable, captured via
|
|
10
|
+
2. **Every Canvas screenshot captured.** A rendered screenshot of every Canvas in the deliverable, captured via the available preview tool (`responseImage: true` when the selected model supports vision) at the target hardware resolution and orientation. Canvases gated behind events are reached via Automation runs (`testId` / `testTitleLike` with `brick_press` / `wait_until_canvas_change` cases). Single-Canvas Subspaces still require a captured screenshot.
|
|
11
11
|
3. **Every screenshot reviewed by the agent.** The agent must read each captured screenshot back through the host's image-reading capability — saving the file is not the same as seeing it. The model that produced the Canvas must also have seen the rendered result, or the verification gate has not passed.
|
|
12
12
|
4. **Reference comparison report.** If the user supplied any reference material (Figma / website / HTML / screenshot / PDF / brand book / competitor), produce a short delta report per Canvas:
|
|
13
13
|
- What matches the reference.
|
|
@@ -30,23 +30,30 @@ If any item is unmet, the work is mid-iteration. Say so explicitly to the user;
|
|
|
30
30
|
|
|
31
31
|
The default loop. Always available; deterministic; no device wear; safe for side-effecting flows because nothing real fires.
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
`bun update-app` and `bun deploy-app` publish to the BRICKS portal. The local preview reads `.bricks/build/application-config.json` (produced by `compile`) directly.
|
|
34
|
+
|
|
35
|
+
### Compile tool
|
|
34
36
|
|
|
35
37
|
Typecheck + compile the project. Gate every iteration on this; everything below assumes a clean compile.
|
|
36
38
|
|
|
37
39
|
Agent invocation: call the MCP tool `compile` exposed by the `bricks-ctor` MCP server registered for the project. No arguments.
|
|
38
40
|
|
|
39
|
-
###
|
|
41
|
+
### Preview tool
|
|
42
|
+
|
|
43
|
+
Use the preview implementation exposed by the current harness:
|
|
44
|
+
|
|
45
|
+
- **CTOR Desktop agent session:** use `preview_invoke`. CTOR Desktop disables the `bricks-ctor` MCP `preview` tool and routes screenshots/automation through the desktop preview pane instead. If the user already opened the simulator pane, `preview_invoke` should reuse it rather than start a separate preview.
|
|
46
|
+
- **Pure `bricks-ctor` project / other agent harness:** use the `bricks-ctor` MCP `preview` tool when `preview_invoke` is not available.
|
|
40
47
|
|
|
41
|
-
|
|
48
|
+
Both forms are the same verification primitive: launch or reuse Electron preview, take a screenshot, and optionally run a named Automation test by id or partial title. Do not hard-code one tool name into the workflow; choose the available preview tool for the environment.
|
|
42
49
|
|
|
43
|
-
|
|
44
|
-
- `delay` (ms before screenshot) — default 3000. Increase if Standby Transitions are still in flight.
|
|
50
|
+
Common arguments:
|
|
51
|
+
- `delay` (ms before screenshot) — default is harness-specific: usually 3000 for a fresh/standalone preview; CTOR Desktop may capture immediately when its preview already has a settled latest config. Increase if Standby Transitions are still in flight.
|
|
45
52
|
- `width`, `height` — screenshot dimensions in px.
|
|
46
|
-
- `responseImage: true` — return
|
|
53
|
+
- `responseImage: true` — return the screenshot as image content when the selected model supports vision. If vision is unavailable, save the screenshot and report the path.
|
|
47
54
|
- `testId` or `testTitleLike` — run a project Automation before the screenshot. Use `testTitleLike` for fuzzy matches (case-insensitive partial title).
|
|
48
55
|
|
|
49
|
-
Returns text log +
|
|
56
|
+
Returns text log + saved screenshot path + image content when supported.
|
|
50
57
|
|
|
51
58
|
### `bun preview` (project script)
|
|
52
59
|
|
|
@@ -76,7 +83,7 @@ Trigger types: `launch` (runs on app start), `anytime` (manual), `cron` (schedul
|
|
|
76
83
|
|
|
77
84
|
Important: the automation map id must be `'AUTOMATION_MAP_DEFAULT'` (not a generated id) — the preview test runner reads from `automationMap['AUTOMATION_MAP_DEFAULT']?.map`.
|
|
78
85
|
|
|
79
|
-
Run a single test from the agent: `bricks-ctor` MCP `preview` with `testId` or `testTitleLike`.
|
|
86
|
+
Run a single test from the agent: call the available preview tool (`preview_invoke` in CTOR Desktop, otherwise `bricks-ctor` MCP `preview`) with `testId` or `testTitleLike`.
|
|
80
87
|
|
|
81
88
|
## Path 2 — Real device with DevTools enabled
|
|
82
89
|
|
|
@@ -23,7 +23,7 @@ description: >-
|
|
|
23
23
|
Encodes architecture truths, performance and complexity guardrails,
|
|
24
24
|
input-translation rules, visual languages library, Direction
|
|
25
25
|
Advisor for vague briefs, Media Flow protocol for branded work.
|
|
26
|
-
Verification toolchain (compile
|
|
26
|
+
Verification toolchain (compile, preview tool selection, on-device DevTools,
|
|
27
27
|
Path 1/2/3) lives in the bricks-ctor skill.
|
|
28
28
|
---
|
|
29
29
|
|
|
@@ -84,7 +84,7 @@ The load-bearing laws. Each is unpacked in [`references/architecture-truths.md`]
|
|
|
84
84
|
6. **Frames are grid units.** Off-grid placement is legal but only ever intentional (overflow effects, anchor-at-origin tricks). It is never a nudge to escape the grid. Bricks fully outside the grid are auto-culled.
|
|
85
85
|
7. **Standby Transition is part of the design language.** Every visible Brick gets an entrance offset (`standbyMode` + `standbyOpacity` + `standbyDelay`); the runtime's auto-tween handles in-flight motion. Snap-cuts are reserved for emphasis (alarm states), never for routine navigation.
|
|
86
86
|
8. **Subspace is a typed module.** Inputs are call-by-value-on-host-change; outlets emit update + value-change events on the host. Extract a Subspace only when the same flow appears 2+ times or when the boundary scopes Data meaningfully — never as a "tidy up" tactic.
|
|
87
|
-
9. **DataCalculation is for derivation
|
|
87
|
+
9. **DataCalculation is for derivation, not orchestration.** Inputs → outputs via DataCalculationScript or DataCalculationMap. Keep scripts pure by default; `enableAsync: true` (Promise / timers / async libs) and Map `FILE_*` commands are available when derivation genuinely needs them. Network calls, navigation, and DataCalc-triggers-DataCalc fanout belong in Event Action chains or Generators.
|
|
88
88
|
10. **No scroll, no overflow, no responsive reflow.** Frames are fixed; what doesn't fit doesn't show. Design within the Canvas; don't import web habits.
|
|
89
89
|
|
|
90
90
|
## Commit to a design language
|
|
@@ -96,19 +96,26 @@ A Subspace is a self-contained mini-Application: own Canvases, own Bricks, own G
|
|
|
96
96
|
|
|
97
97
|
**Failure mode:** Subspaces with leaky contracts (every host Data exposed as a Prop). Tighten the contract; if you can't, the boundary is wrong.
|
|
98
98
|
|
|
99
|
-
## 9. DataCalculation is for derivation
|
|
99
|
+
## 9. DataCalculation is for derivation, not orchestration
|
|
100
100
|
|
|
101
|
-
Two flavours:
|
|
101
|
+
Two flavours:
|
|
102
|
+
|
|
103
|
+
- **`DataCalculationScript`** — a sandboxed JS function with named inputs / outputs. Default is sync + pure; opt into async with `enableAsync: true`, which unlocks `Promise`, `setTimeout` / `setInterval` / `setImmediate`, `requestAnimationFrame`, and the full lodash surface (`debounce`, `delay`, `defer`). Bundled libraries include lodash, voca, mathjs, chroma, moment, json5, qs, url, bytes, ms, base45, iconv, nanoid, md5, crypto-browserify, jsrsasign (JWS), cose-js, fflate (gzip/zlib), cbor, fs (limited; no download/upload), officeparser, turndown, opencc-js, toon-format. Runs on Hermes (Android) and JavaScriptCore (iOS) — keep that in mind for engine pitfalls.
|
|
104
|
+
- **`DataCalculationMap`** — a node-graph of `DataCommand`s spanning these categories: `COLLECTION`, `COLOR`, `CONSTANT`, `DATETIME`, `FILE` (file-system ops: `READ` / `WRITE` / `APPEND` / `MKDIR` / `COPY_FILE` / `MOVE_FILE` / `UNLINK` / `EXISTS` / `STAT` / etc.), `ITERATEE`, `LOGICTYPE`, `MATH`, `OBJECT`, `SANDBOX` (`SANDBOX_RUN_JAVASCRIPT` runs a script node inside the graph), `STRING`.
|
|
105
|
+
|
|
106
|
+
Derivation is the intent. Purity is a strong default and the right framing for the common case, but it is a best practice — not a hard runtime restriction. `enableAsync` and `FILE_*` exist because some derivation work (document parsing, decompression, signing, reading a cached file) genuinely needs them.
|
|
102
107
|
|
|
103
108
|
**Use it for**:
|
|
104
109
|
- Format conversion (date → human-readable, currency → localized string).
|
|
105
110
|
- Combining Data values into a derived display value.
|
|
106
111
|
- Reductions / iterations over a collection.
|
|
107
112
|
- Boolean conditions feeding a Switch.
|
|
113
|
+
- Async derivation pipelines: decode → decompress → parse → verify (cbor, fflate, cose-js, officeparser, turndown).
|
|
114
|
+
- Reading cached files written earlier in the flow (Map `FILE_*` commands or Script `fs`).
|
|
108
115
|
|
|
109
116
|
**Triggering**: `triggerMode: 'auto'` re-runs on input change (watch for circular dependencies); `'manual'` only runs on `PROPERTY_BANK_COMMAND` action.
|
|
110
117
|
|
|
111
|
-
**Do not use** for orchestration,
|
|
118
|
+
**Do not use** for orchestration, navigation, network calls (no `fetch` / XHR in the sandbox — that's a Generator's job), or anything that should be in an Event Action chain or a Generator. A DataCalc that triggers DataCalc that triggers DataCalc is an orchestration system in the wrong primitive — promote to event chains. `enableAsync` and `FILE_*` are tools for derivation, not a licence to smuggle flow control into the calc layer.
|
|
112
119
|
|
|
113
120
|
**Failure mode:** spinning up a Generator just to do a string concat or unit conversion. That's a DataCalc job; the inverse misuse is just as common.
|
|
114
121
|
|
|
@@ -57,7 +57,7 @@ Use when variations share most of the Brick tree but differ on a chunk that can'
|
|
|
57
57
|
- Each variant Subspace imports the shared module and overrides only the variant-specific chunk.
|
|
58
58
|
- Bricks reused by reference, not duplicated.
|
|
59
59
|
|
|
60
|
-
**Comparison surface:** screenshot per variant via preview
|
|
60
|
+
**Comparison surface:** screenshot per variant via the available preview tool, assembled in chat.
|
|
61
61
|
|
|
62
62
|
**Token cost:** 1 shared module + N small variant Subspaces.
|
|
63
63
|
|
package/tools/_shell.ts
CHANGED
|
@@ -29,6 +29,7 @@ class Sh implements PromiseLike<ShResult> {
|
|
|
29
29
|
private _cwd: string | undefined
|
|
30
30
|
private _mode: Mode = 'default'
|
|
31
31
|
private _throw = true
|
|
32
|
+
private _env: NodeJS.ProcessEnv | undefined
|
|
32
33
|
private _promise: Promise<ShResult> | null = null
|
|
33
34
|
|
|
34
35
|
constructor(private readonly args: string[]) {}
|
|
@@ -48,6 +49,11 @@ class Sh implements PromiseLike<ShResult> {
|
|
|
48
49
|
return this
|
|
49
50
|
}
|
|
50
51
|
|
|
52
|
+
env(extra: NodeJS.ProcessEnv): this {
|
|
53
|
+
this._env = { ...this._env, ...extra }
|
|
54
|
+
return this
|
|
55
|
+
}
|
|
56
|
+
|
|
51
57
|
async text(): Promise<string> {
|
|
52
58
|
// If no explicit quiet was requested, capture stdout/stderr without
|
|
53
59
|
// forwarding them to the parent's streams (matches Bun's `.text()`).
|
|
@@ -79,7 +85,8 @@ class Sh implements PromiseLike<ShResult> {
|
|
|
79
85
|
? ['ignore', 'pipe', 'pipe']
|
|
80
86
|
: ['inherit', 'pipe', 'pipe']
|
|
81
87
|
|
|
82
|
-
const
|
|
88
|
+
const env = this._env ? { ...process.env, ...this._env } : undefined
|
|
89
|
+
const proc = spawn(cmd, rest, { cwd: this._cwd, stdio, env })
|
|
83
90
|
|
|
84
91
|
const outChunks: Buffer[] = []
|
|
85
92
|
const errChunks: Buffer[] = []
|
|
@@ -3,22 +3,29 @@ import { readFile } from 'node:fs/promises'
|
|
|
3
3
|
import { z } from 'zod'
|
|
4
4
|
import { sh } from '../_shell'
|
|
5
5
|
|
|
6
|
+
// Disable ANSI color codes from spawned tools so MCP text output stays readable
|
|
7
|
+
// (the host renders raw text; escape sequences leak into the result otherwise).
|
|
8
|
+
const noColorEnv = { FORCE_COLOR: '0', NO_COLOR: '1' }
|
|
9
|
+
|
|
6
10
|
export function register(server: McpServer, projectDir: string) {
|
|
7
11
|
const { dirname } = import.meta
|
|
8
12
|
|
|
9
13
|
server.tool('compile', {}, async () => {
|
|
10
|
-
let log = ''
|
|
14
|
+
let log = 'Type checking & Compiling...\n'
|
|
11
15
|
try {
|
|
12
|
-
log +=
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
log += await sh`bun compile`.cwd(projectDir).env(noColorEnv).text()
|
|
17
|
+
} catch (err: any) {
|
|
18
|
+
const stdout = err.stdout?.toString() ?? ''
|
|
19
|
+
const stderr = err.stderr?.toString() ?? ''
|
|
20
|
+
log += [stdout, stderr].filter(Boolean).join('\n')
|
|
16
21
|
}
|
|
17
22
|
return {
|
|
18
23
|
content: [{ type: 'text', text: log }],
|
|
19
24
|
}
|
|
20
25
|
})
|
|
21
26
|
|
|
27
|
+
if (process.env.BRICKS_CTOR_MCP_DISABLE_PREVIEW === '1') return
|
|
28
|
+
|
|
22
29
|
server.tool(
|
|
23
30
|
'preview',
|
|
24
31
|
{
|
|
@@ -63,9 +70,12 @@ export function register(server: McpServer, projectDir: string) {
|
|
|
63
70
|
if (testTitleLike) args.push('--test-title-like', testTitleLike)
|
|
64
71
|
log = await sh`bunx --bun electron ${toolsDir}/preview-main.mjs ${args}`
|
|
65
72
|
.cwd(projectDir)
|
|
73
|
+
.env(noColorEnv)
|
|
66
74
|
.text()
|
|
67
|
-
} catch (err) {
|
|
68
|
-
|
|
75
|
+
} catch (err: any) {
|
|
76
|
+
const stdout = err.stdout?.toString() ?? ''
|
|
77
|
+
const stderr = err.stderr?.toString() ?? ''
|
|
78
|
+
log = [stdout, stderr].filter(Boolean).join('\n')
|
|
69
79
|
error = true
|
|
70
80
|
}
|
|
71
81
|
let screenshotBase64: string | null = null
|
package/tools/mcp-tools/media.ts
CHANGED
|
@@ -2,9 +2,12 @@ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
|
|
|
2
2
|
import { z } from 'zod'
|
|
3
3
|
import { sh } from '../_shell'
|
|
4
4
|
|
|
5
|
+
// MCP results are rendered as raw text — disable ANSI colors from the child.
|
|
6
|
+
const noColorEnv = { FORCE_COLOR: '0', NO_COLOR: '1' }
|
|
7
|
+
|
|
5
8
|
const runBricks = async (projectDir: string, ...args: string[]) => {
|
|
6
9
|
try {
|
|
7
|
-
return await sh`bunx bricks ${args}`.cwd(projectDir).text()
|
|
10
|
+
return await sh`bunx bricks ${args}`.cwd(projectDir).env(noColorEnv).text()
|
|
8
11
|
} catch (err: any) {
|
|
9
12
|
throw new Error(err.stderr?.toString() || err.message)
|
|
10
13
|
}
|
package/types/animation.ts
CHANGED
|
@@ -104,8 +104,13 @@ export interface AnimationComposeDef {
|
|
|
104
104
|
|
|
105
105
|
export type Animation = AnimationDef | AnimationComposeDef
|
|
106
106
|
|
|
107
|
+
// Animation event handlers accept either a direct Animation or a getter that
|
|
108
|
+
// returns one. The getter form is useful for lazy/forward references between
|
|
109
|
+
// animations defined across files.
|
|
110
|
+
export type AnimationOrGetter = Animation | (() => Animation)
|
|
111
|
+
|
|
107
112
|
export interface AnimationBasicEvents {
|
|
108
|
-
showStart?:
|
|
109
|
-
standby?:
|
|
110
|
-
breatheStart?:
|
|
113
|
+
showStart?: AnimationOrGetter
|
|
114
|
+
standby?: AnimationOrGetter
|
|
115
|
+
breatheStart?: AnimationOrGetter
|
|
111
116
|
}
|
package/types/brick-base.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/* Auto generated by build script */
|
|
2
2
|
import type { SwitchCondInnerStateCurrentCanvas, SwitchCondData, SwitchDef } from './switch'
|
|
3
3
|
import type { Data, DataLink } from './data'
|
|
4
|
-
import type { Animation, AnimationBasicEvents } from './animation'
|
|
4
|
+
import type { Animation, AnimationBasicEvents, AnimationOrGetter } from './animation'
|
|
5
5
|
import type {
|
|
6
6
|
Brick,
|
|
7
7
|
EventAction,
|
package/types/bricks/Camera.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { SwitchCondInnerStateCurrentCanvas, SwitchCondData, SwitchDef } from '../switch'
|
|
6
6
|
import type { Data, DataLink } from '../data'
|
|
7
|
-
import type { Animation, AnimationBasicEvents } from '../animation'
|
|
7
|
+
import type { Animation, AnimationBasicEvents, AnimationOrGetter } from '../animation'
|
|
8
8
|
import type {
|
|
9
9
|
Brick,
|
|
10
10
|
EventAction,
|
|
@@ -213,13 +213,13 @@ Default property:
|
|
|
213
213
|
faceDetected?: () => Data<Array<{ [key: string]: any }>>
|
|
214
214
|
}
|
|
215
215
|
animation?: AnimationBasicEvents & {
|
|
216
|
-
stateChange?:
|
|
217
|
-
recordStart?:
|
|
218
|
-
recordEnd?:
|
|
219
|
-
barcodeRead?:
|
|
220
|
-
pictureTaken?:
|
|
221
|
-
recordFinish?:
|
|
222
|
-
mountError?:
|
|
216
|
+
stateChange?: AnimationOrGetter
|
|
217
|
+
recordStart?: AnimationOrGetter
|
|
218
|
+
recordEnd?: AnimationOrGetter
|
|
219
|
+
barcodeRead?: AnimationOrGetter
|
|
220
|
+
pictureTaken?: AnimationOrGetter
|
|
221
|
+
recordFinish?: AnimationOrGetter
|
|
222
|
+
mountError?: AnimationOrGetter
|
|
223
223
|
}
|
|
224
224
|
}
|
|
225
225
|
|
package/types/bricks/Chart.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { SwitchCondInnerStateCurrentCanvas, SwitchCondData, SwitchDef } from '../switch'
|
|
6
6
|
import type { Data, DataLink } from '../data'
|
|
7
|
-
import type { Animation, AnimationBasicEvents } from '../animation'
|
|
7
|
+
import type { Animation, AnimationBasicEvents, AnimationOrGetter } from '../animation'
|
|
8
8
|
import type {
|
|
9
9
|
Brick,
|
|
10
10
|
EventAction,
|
|
@@ -343,9 +343,9 @@ Default property:
|
|
|
343
343
|
>
|
|
344
344
|
}
|
|
345
345
|
animation?: AnimationBasicEvents & {
|
|
346
|
-
onRender?:
|
|
347
|
-
onPress?:
|
|
348
|
-
onLegendSelectChanged?:
|
|
346
|
+
onRender?: AnimationOrGetter
|
|
347
|
+
onPress?: AnimationOrGetter
|
|
348
|
+
onLegendSelectChanged?: AnimationOrGetter
|
|
349
349
|
}
|
|
350
350
|
}
|
|
351
351
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { SwitchCondInnerStateCurrentCanvas, SwitchCondData, SwitchDef } from '../switch'
|
|
6
6
|
import type { Data, DataLink } from '../data'
|
|
7
|
-
import type { Animation, AnimationBasicEvents } from '../animation'
|
|
7
|
+
import type { Animation, AnimationBasicEvents, AnimationOrGetter } from '../animation'
|
|
8
8
|
import type {
|
|
9
9
|
Brick,
|
|
10
10
|
EventAction,
|
|
@@ -250,20 +250,20 @@ Default property:
|
|
|
250
250
|
loading?: () => Data<boolean>
|
|
251
251
|
}
|
|
252
252
|
animation?: AnimationBasicEvents & {
|
|
253
|
-
generativeMediaOnPress?:
|
|
254
|
-
generativeMediaOnPressIn?:
|
|
255
|
-
generativeMediaOnPressOut?:
|
|
256
|
-
generativeMediaOnLongPress?:
|
|
257
|
-
generativeMediaOnFocus?:
|
|
258
|
-
generativeMediaOnBlur?:
|
|
259
|
-
onSuccess?:
|
|
260
|
-
onError?:
|
|
261
|
-
promptStart?:
|
|
262
|
-
promptSuccess?:
|
|
263
|
-
promptError?:
|
|
264
|
-
loadStart?:
|
|
265
|
-
loadSuccess?:
|
|
266
|
-
loadError?:
|
|
253
|
+
generativeMediaOnPress?: AnimationOrGetter
|
|
254
|
+
generativeMediaOnPressIn?: AnimationOrGetter
|
|
255
|
+
generativeMediaOnPressOut?: AnimationOrGetter
|
|
256
|
+
generativeMediaOnLongPress?: AnimationOrGetter
|
|
257
|
+
generativeMediaOnFocus?: AnimationOrGetter
|
|
258
|
+
generativeMediaOnBlur?: AnimationOrGetter
|
|
259
|
+
onSuccess?: AnimationOrGetter
|
|
260
|
+
onError?: AnimationOrGetter
|
|
261
|
+
promptStart?: AnimationOrGetter
|
|
262
|
+
promptSuccess?: AnimationOrGetter
|
|
263
|
+
promptError?: AnimationOrGetter
|
|
264
|
+
loadStart?: AnimationOrGetter
|
|
265
|
+
loadSuccess?: AnimationOrGetter
|
|
266
|
+
loadError?: AnimationOrGetter
|
|
267
267
|
}
|
|
268
268
|
}
|
|
269
269
|
|
package/types/bricks/Icon.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { SwitchCondInnerStateCurrentCanvas, SwitchCondData, SwitchDef } from '../switch'
|
|
6
6
|
import type { Data, DataLink } from '../data'
|
|
7
|
-
import type { Animation, AnimationBasicEvents } from '../animation'
|
|
7
|
+
import type { Animation, AnimationBasicEvents, AnimationOrGetter } from '../animation'
|
|
8
8
|
import type {
|
|
9
9
|
Brick,
|
|
10
10
|
EventAction,
|
|
@@ -66,12 +66,12 @@ Default property:
|
|
|
66
66
|
brickFocusing?: () => Data<boolean>
|
|
67
67
|
}
|
|
68
68
|
animation?: AnimationBasicEvents & {
|
|
69
|
-
onPress?:
|
|
70
|
-
onPressIn?:
|
|
71
|
-
onPressOut?:
|
|
72
|
-
onLongPress?:
|
|
73
|
-
onFocus?:
|
|
74
|
-
onBlur?:
|
|
69
|
+
onPress?: AnimationOrGetter
|
|
70
|
+
onPressIn?: AnimationOrGetter
|
|
71
|
+
onPressOut?: AnimationOrGetter
|
|
72
|
+
onLongPress?: AnimationOrGetter
|
|
73
|
+
onFocus?: AnimationOrGetter
|
|
74
|
+
onBlur?: AnimationOrGetter
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
package/types/bricks/Image.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { SwitchCondInnerStateCurrentCanvas, SwitchCondData, SwitchDef } from '../switch'
|
|
6
6
|
import type { Data, DataLink } from '../data'
|
|
7
|
-
import type { Animation, AnimationBasicEvents } from '../animation'
|
|
7
|
+
import type { Animation, AnimationBasicEvents, AnimationOrGetter } from '../animation'
|
|
8
8
|
import type {
|
|
9
9
|
Brick,
|
|
10
10
|
EventAction,
|
|
@@ -92,14 +92,14 @@ Default property:
|
|
|
92
92
|
brickFocusing?: () => Data<boolean>
|
|
93
93
|
}
|
|
94
94
|
animation?: AnimationBasicEvents & {
|
|
95
|
-
onPress?:
|
|
96
|
-
onPressIn?:
|
|
97
|
-
onPressOut?:
|
|
98
|
-
onLongPress?:
|
|
99
|
-
onFocus?:
|
|
100
|
-
onBlur?:
|
|
101
|
-
onLoad?:
|
|
102
|
-
onError?:
|
|
95
|
+
onPress?: AnimationOrGetter
|
|
96
|
+
onPressIn?: AnimationOrGetter
|
|
97
|
+
onPressOut?: AnimationOrGetter
|
|
98
|
+
onLongPress?: AnimationOrGetter
|
|
99
|
+
onFocus?: AnimationOrGetter
|
|
100
|
+
onBlur?: AnimationOrGetter
|
|
101
|
+
onLoad?: AnimationOrGetter
|
|
102
|
+
onError?: AnimationOrGetter
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
|
package/types/bricks/Items.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { SwitchCondInnerStateCurrentCanvas, SwitchCondData, SwitchDef } from '../switch'
|
|
6
6
|
import type { Data, DataLink } from '../data'
|
|
7
|
-
import type { Animation, AnimationBasicEvents } from '../animation'
|
|
7
|
+
import type { Animation, AnimationBasicEvents, AnimationOrGetter } from '../animation'
|
|
8
8
|
import type {
|
|
9
9
|
Brick,
|
|
10
10
|
EventAction,
|
|
@@ -438,12 +438,12 @@ Default property:
|
|
|
438
438
|
pageIsOutOfBound?: () => Data<boolean>
|
|
439
439
|
}
|
|
440
440
|
animation?: AnimationBasicEvents & {
|
|
441
|
-
onPageRender?:
|
|
442
|
-
onPageChange?:
|
|
443
|
-
onPageOutOfBound?:
|
|
444
|
-
onIntoDetailMode?:
|
|
445
|
-
onIntoListMode?:
|
|
446
|
-
onError?:
|
|
441
|
+
onPageRender?: AnimationOrGetter
|
|
442
|
+
onPageChange?: AnimationOrGetter
|
|
443
|
+
onPageOutOfBound?: AnimationOrGetter
|
|
444
|
+
onIntoDetailMode?: AnimationOrGetter
|
|
445
|
+
onIntoListMode?: AnimationOrGetter
|
|
446
|
+
onError?: AnimationOrGetter
|
|
447
447
|
}
|
|
448
448
|
}
|
|
449
449
|
|