@fugood/bricks-project 2.25.0-beta.37 → 2.25.0-beta.39

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.25.0-beta.37",
3
+ "version": "2.25.0-beta.39",
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.25.0-beta.35",
10
+ "@fugood/bricks-cli": "^2.25.0-beta.38",
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.25.0-beta.37",
3
+ "version": "2.25.0-beta.39",
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.25.0-beta.35",
10
+ "@fugood/bricks-cli": "^2.25.0-beta.38",
11
11
  "@huggingface/gguf": "^0.3.2",
12
12
  "@iarna/toml": "^3.0.0",
13
13
  "@modelcontextprotocol/sdk": "^1.15.0",
@@ -11,24 +11,26 @@ This skill covers advanced BRICKS features not in the main project instructions.
11
11
 
12
12
  | Rule | Description |
13
13
  |------|-------------|
14
- | [Architecture Patterns](rules/architecture-patterns.md) | **Read first** — decompose flows and select patterns |
15
- | [Animation](rules/animation.md) | Animation system for brick transforms and opacity |
16
- | [Standby Transition](rules/standby-transition.md) | Canvas enter/exit animations |
17
- | [Automations](rules/automations.md) | E2E testing and scheduled tasks |
18
- | [Data Calculation](rules/data-calculation.md) | JS sandbox libraries (25+ available) |
19
- | [Local Sync](rules/local-sync.md) | LAN device synchronization |
20
- | [Remote Data Bank](rules/remote-data-bank.md) | Cloud data sync and API access |
21
- | [Media Flow](rules/media-flow.md) | Media asset management |
22
- | [Buttress](rules/buttress.md) | Remote inference for AI generators |
23
- | [Verification Toolchain](rules/verification-toolchain.md) | Definition of done, compile, preview tool selection, on-device DevTools, Path 1/2/3 decision rule |
14
+ | [Architecture Patterns](references/architecture-patterns.md) | **Read first** — decompose flows and select patterns |
15
+ | [Animation](references/animation.md) | Animation system for brick transforms and opacity |
16
+ | [Standby Transition](references/standby-transition.md) | Canvas enter/exit animations |
17
+ | [Automations](references/automations.md) | E2E testing and scheduled tasks |
18
+ | [Data Calculation](references/data-calculation.md) | JS sandbox libraries (25+ available) |
19
+ | [Local Sync](references/local-sync.md) | LAN device synchronization |
20
+ | [Remote Data Bank](references/remote-data-bank.md) | Cloud data sync and API access |
21
+ | [Media Flow](references/media-flow.md) | Media asset management |
22
+ | [Buttress](references/buttress.md) | Remote inference for AI generators |
23
+ | [Verification Toolchain](references/verification-toolchain.md) | Definition of done, compile, preview tool selection, on-device DevTools, Path 1/2/3 decision rule |
24
+ | [Simulator](references/simulator.md) | Path 1 fidelity — Simulator feature support, fallbacks (Camera/LLM/STT/Vector Store, Buttress disabled), when a green run is enough vs. Path 2 |
24
25
 
25
26
  ## Quick Reference
26
27
 
27
- - **Complex flows**: See [Architecture Patterns](rules/architecture-patterns.md) for decomposing multi-step workflows
28
- - **Multi-device**: See [Local Sync](rules/local-sync.md) for LAN coordination
29
- - **Cloud data**: See [Remote Data Bank](rules/remote-data-bank.md) for sync and API access
30
- - **Media assets**: See [Media Flow](rules/media-flow.md) for centralized asset management
31
- - **AI offloading**: See [Buttress](rules/buttress.md) for GPU server delegation
32
- - **E2E testing**: See [Automations](rules/automations.md) for test automation
33
- - **Enter animations**: See [Standby Transition](rules/standby-transition.md) for canvas transitions
34
- - **Verification before done**: See [Verification Toolchain](rules/verification-toolchain.md) for the definition-of-done gate and Path 1/2/3 decision rule
28
+ - **Complex flows**: See [Architecture Patterns](references/architecture-patterns.md) for decomposing multi-step workflows
29
+ - **Multi-device**: See [Local Sync](references/local-sync.md) for LAN coordination
30
+ - **Cloud data**: See [Remote Data Bank](references/remote-data-bank.md) for sync and API access
31
+ - **Media assets**: See [Media Flow](references/media-flow.md) for centralized asset management
32
+ - **AI offloading**: See [Buttress](references/buttress.md) for GPU server delegation
33
+ - **E2E testing**: See [Automations](references/automations.md) for test automation
34
+ - **Enter animations**: See [Standby Transition](references/standby-transition.md) for canvas transitions
35
+ - **Verification before done**: See [Verification Toolchain](references/verification-toolchain.md) for the definition-of-done gate and Path 1/2/3 decision rule
36
+ - **Simulator fidelity**: See [Simulator](references/simulator.md) for what the Simulator fakes (Camera, AI generators, Buttress) and when to escalate to a real device
@@ -0,0 +1,98 @@
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
+ ## What the Simulator can't reproduce
13
+
14
+ 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):
15
+
16
+ | Area | In the Simulator |
17
+ |------|------------------|
18
+ | BLE (Central / Peripheral), Video Streaming | Not available |
19
+ | Raw network sockets — UDP, TCP, TCP Server, MQTT Broker | Not available (also why Buttress LAN discovery is a no-op — see [Buttress](buttress.md)) |
20
+ | Android Intent | Not available (Android-only) |
21
+ | 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 |
22
+ | GGML Text-to-Speech | No vocoder in the preview — use an ONNX TTS model to hear speech |
23
+
24
+ These work, but with browser caveats:
25
+
26
+ | Area | Caveat |
27
+ |------|--------|
28
+ | Serial Port | Works via WebSerial — requires browser support and a user gesture |
29
+ | WebView / WebCrawler | Subject to browser CORS — a load/fetch that works on device may be blocked |
30
+ | 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 |
31
+ | 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) |
32
+ | Scene3D / Maps / Sketch / WebRTC | Supported |
33
+
34
+ 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.
35
+
36
+ ## Network security
37
+
38
+ 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.
39
+
40
+ Generated projects include this project-level setting:
41
+
42
+ ```json
43
+ {
44
+ "allowedInsecureHosts": []
45
+ }
46
+ ```
47
+
48
+ 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:
49
+
50
+ ```json
51
+ {
52
+ "allowedInsecureHosts": ["localhost:8080"]
53
+ }
54
+ ```
55
+
56
+ Use a URL form when only one insecure protocol should be allowed:
57
+
58
+ ```json
59
+ {
60
+ "allowedInsecureHosts": ["http://localhost:8080"]
61
+ }
62
+ ```
63
+
64
+ In that example, `http://localhost:8080` is allowed and `ws://localhost:8080` remains blocked.
65
+
66
+ Prefer HTTPS/WSS for anything that is not local development.
67
+
68
+ ## Feature fallbacks — what the Simulator fakes
69
+
70
+ 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.**
71
+
72
+ | Brick / Generator | In the Simulator | Does NOT prove |
73
+ |-------------------|------------------|----------------|
74
+ | 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 |
75
+ | 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 | Real device connection, actual paper output, exact native driver status codes |
76
+ | LLM (`GENERATOR_LLM`) | Swapped to a tiny local stand-in model | Output quality / latency of your real model |
77
+ | Reranker — GGML (`GENERATOR_RERANKER`) | Swapped to a small local multilingual reranker model | Ranking quality / latency of your real model |
78
+ | Speech-to-Text — GGML (`GENERATOR_SPEECH_INFERENCE`) | Swapped to a tiny local model | Accuracy / latency of your real model |
79
+ | Speech-to-Text — ONNX (`GENERATOR_ONNX_STT`) | Swapped to a tiny whisper model | Accuracy / latency of your real model |
80
+ | Text-to-Speech — ONNX (`GENERATOR_TTS`) | Swapped to a tiny VITS model (no vocoder or speaker embedding) | Voice / quality / latency of your real model |
81
+ | 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) |
82
+ | Buttress (all generators) | **Disabled** — there is no remote inference backend in the Simulator | The Buttress offload path — see [Buttress](buttress.md) |
83
+ | MLX LLM (`GENERATOR_MLX_LLM`) | Runs as authored, except Buttress is disabled | The MLX / Buttress path |
84
+
85
+ These swaps make the AI generators runnable in the Simulator for wiring checks — validate real models, quality, and latency on a device (Path 2).
86
+
87
+ ### Running the real implementation instead
88
+
89
+ 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. The browser limits above still apply, and **Buttress stays disabled regardless** — there's no backend for it here.
90
+
91
+ 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.
92
+
93
+ ## Enough vs. escalate
94
+
95
+ - **Simulator is enough for:** layout, navigation, Standby Transitions, Data wiring, Automation / state-machine happy paths, and confirming a generator fires and handles its events.
96
+ - **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.
97
+
98
+ The full Path 1/2/3 decision rule lives in [Verification Toolchain](verification-toolchain.md).
@@ -26,10 +26,12 @@ What does **not** count as done:
26
26
 
27
27
  If any item is unmet, the work is mid-iteration. Say so explicitly to the user; offer a precise list of what remains.
28
28
 
29
- ## Path 1 — Electron preview (no device required)
29
+ ## Path 1 — Simulator (no device required)
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
+ Before trusting a Simulator screenshot, know what it can and can't reproduce: it runs in the Electron preview (a browser-class runtime, not the device — and not the device's JS engine), can't exercise hardware/peripheral features (BLE, printers, raw sockets, SQLite, …), and substitutes fallbacks for Camera and the AI generators (LLM/STT/Vector Store) with Buttress disabled. See [Simulator](simulator.md) for the fidelity boundaries and the per-item gear to run the real implementation — it's what tells you when a green run is enough vs. when to escalate to Path 2.
34
+
33
35
  `bun update-app` and `bun deploy-app` publish to the BRICKS portal. The local preview reads `.bricks/build/application-config.json` (produced by `compile`) directly.
34
36
 
35
37
  ### Compile tool
@@ -38,12 +40,12 @@ Typecheck + compile the project. Gate every iteration on this; everything below
38
40
 
39
41
  Agent invocation: call the MCP tool `compile` exposed by the `bricks-ctor` MCP server registered for the project. No arguments.
40
42
 
41
- ### Preview tool
43
+ ### Simulator tool
42
44
 
43
45
  Use the preview implementation exposed by the current harness:
44
46
 
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.
47
+ - **CTOR Desktop agent session:** use `simulator_invoke`. CTOR Desktop disables the `bricks-ctor` MCP `simulator` tool and routes screenshots/automation through the desktop preview pane instead. If the user already opened the simulator pane, `simulator_invoke` should reuse it rather than start a separate preview.
48
+ - **Pure `bricks-ctor` project / other agent harness:** use the `bricks-ctor` MCP `simulator` tool when `simulator_invoke` is not available.
47
49
 
48
50
  Both forms are the same verification primitive: launch or reuse Electron preview, take a screenshot, and optionally run a named Automation test by id or partial title. Do not hard-code one tool name into the workflow; choose the available preview tool for the environment.
49
51
 
@@ -55,7 +57,7 @@ Common arguments:
55
57
 
56
58
  Returns text log + saved screenshot path + image content when supported.
57
59
 
58
- ### `bun preview` (project script)
60
+ ### `bun invoke-simulator` (project script)
59
61
 
60
62
  Sustained dev session — watches `subspaces/`, recompiles on save, exposes CDP at `localhost:19852` (configurable via `--cdp-port`), writes `.bricks/devtools.json` with port/pid for downstream tooling.
61
63
 
@@ -83,7 +85,7 @@ Trigger types: `launch` (runs on app start), `anytime` (manual), `cron` (schedul
83
85
 
84
86
  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`.
85
87
 
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`.
88
+ Run a single test from the agent: call the available preview tool (`simulator_invoke` in CTOR Desktop, otherwise `bricks-ctor` MCP `preview`) with `testId` or `testTitleLike`.
87
89
 
88
90
  ## Path 2 — Real device with DevTools enabled
89
91
 
@@ -147,7 +149,7 @@ if user is off-LAN
147
149
 
148
150
  ### Static signage (single-canvas glance loop)
149
151
  - Path 1 screenshot captures the loop frame.
150
- - Watch one full rotation in `bun preview` to see all queue items.
152
+ - Watch one full rotation in `bun invoke-simulator` to see all queue items.
151
153
  - Cut network mid-loop; confirm cached media plays.
152
154
  - Path 2 only if the panel is OLED / has burn-in concerns or specific color profile.
153
155
 
@@ -142,7 +142,7 @@ A single hero-Canvas screenshot is **not** done. A "looks roughly like the refer
142
142
 
143
143
  **Self-critique pass before declaring done** — every Canvas scored on 5 dimensions (system commitment / visual hierarchy / craft / functional fit / originality), anti-slop top-10 swept clean, < 8 scores either fixed or surfaced as accepted trade-offs. See [`references/design-critique.md`](references/design-critique.md). Verification proves it runs; critique proves it's good — both required.
144
144
 
145
- For the toolchain itself — `compile` / `preview` MCP usage, `bun preview` flags, Project Automation cases, on-device DevTools setup, the Path 1/2/3 decision rule, and per-deployment-shape verification checklists — see the `bricks-ctor` skill's `rules/verification-toolchain.md`.
145
+ For the toolchain itself — `compile` / `simulator` MCP usage, `bun invoke-simulator` flags, Project Automation cases, on-device DevTools setup, the Path 1/2/3 decision rule, and per-deployment-shape verification checklists — see the `bricks-ctor` skill's `rules/verification-toolchain.md`.
146
146
 
147
147
  ## Boundaries
148
148
 
@@ -27,7 +27,7 @@ export function register(server: McpServer, projectDir: string) {
27
27
  if (process.env.BRICKS_CTOR_MCP_DISABLE_PREVIEW === '1') return
28
28
 
29
29
  server.tool(
30
- 'preview',
30
+ 'simulator',
31
31
  {
32
32
  delay: z
33
33
  .number()
@@ -68,7 +68,7 @@ export function register(server: McpServer, projectDir: string) {
68
68
  ]
69
69
  if (testId) args.push('--test-id', testId)
70
70
  if (testTitleLike) args.push('--test-title-like', testTitleLike)
71
- log = await sh`bunx --bun electron ${toolsDir}/preview-main.mjs ${args}`
71
+ log = await sh`bunx --bun electron ${toolsDir}/simulator-main.mjs ${args}`
72
72
  .cwd(projectDir)
73
73
  .env(noColorEnv)
74
74
  .text()
@@ -28,6 +28,81 @@ const { values } = parseArgs({
28
28
  })
29
29
 
30
30
  const cwd = process.cwd()
31
+ const DEFAULT_SIMULATOR_SECURITY_SETTINGS = Object.freeze({
32
+ allowedInsecureHosts: [],
33
+ })
34
+
35
+ const isObject = (value) => !!value && typeof value === 'object' && !Array.isArray(value)
36
+
37
+ const normalizeSimulatorSecuritySettings = (settings = {}) => {
38
+ const source = isObject(settings) ? settings : {}
39
+ const allowedHosts = Array.isArray(source.allowedInsecureHosts)
40
+ ? source.allowedInsecureHosts
41
+ : DEFAULT_SIMULATOR_SECURITY_SETTINGS.allowedInsecureHosts
42
+
43
+ return {
44
+ allowedInsecureHosts: allowedHosts
45
+ .filter((host) => typeof host === 'string')
46
+ .map((host) => host.trim().toLowerCase())
47
+ .filter(Boolean),
48
+ }
49
+ }
50
+
51
+ const normalizeAllowedConnection = (value) => {
52
+ const raw = String(value || '')
53
+ .trim()
54
+ .toLowerCase()
55
+ if (!raw) return null
56
+ if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(raw)) return { host: raw, protocol: null }
57
+ try {
58
+ const url = new URL(raw)
59
+ return {
60
+ host: url.host.toLowerCase(),
61
+ protocol: url.protocol,
62
+ }
63
+ } catch {
64
+ return null
65
+ }
66
+ }
67
+
68
+ const shouldBlockInsecureConnection = (rawUrl, settings = {}) => {
69
+ const normalized = normalizeSimulatorSecuritySettings(settings)
70
+
71
+ try {
72
+ const url = new URL(String(rawUrl || ''))
73
+ if (url.protocol !== 'http:' && url.protocol !== 'ws:') return false
74
+ const host = url.host.toLowerCase()
75
+ const hostname = url.hostname.toLowerCase().replace(/^\[|\]$/g, '')
76
+ return !normalized.allowedInsecureHosts.some((allowedHost) => {
77
+ const allowed = normalizeAllowedConnection(allowedHost)
78
+ if (!allowed) return false
79
+ if (allowed.protocol && allowed.protocol !== url.protocol) return false
80
+ return allowed.host === host || allowed.host === hostname
81
+ })
82
+ } catch {
83
+ return false
84
+ }
85
+ }
86
+
87
+ const getUnsecureConnectionHost = (rawUrl) => {
88
+ try {
89
+ const url = new URL(String(rawUrl || ''))
90
+ if (url.protocol !== 'http:' && url.protocol !== 'ws:') return null
91
+ return url.host.toLowerCase()
92
+ } catch {
93
+ return null
94
+ }
95
+ }
96
+
97
+ const readSimulatorProjectSettings = async () => {
98
+ try {
99
+ return normalizeSimulatorSecuritySettings(
100
+ JSON.parse(await readFile(`${cwd}/simulator.json`, 'utf8')),
101
+ )
102
+ } catch {
103
+ return normalizeSimulatorSecuritySettings()
104
+ }
105
+ }
31
106
 
32
107
  let takeScreenshotConfig = null
33
108
  try {
@@ -45,6 +120,7 @@ try {
45
120
  }
46
121
 
47
122
  let config = JSON.parse(await readFile(`${cwd}/.bricks/build/application-config.json`))
123
+ let simulatorSettings = await readSimulatorProjectSettings()
48
124
 
49
125
  // Resolve testId from testTitleLike
50
126
  let testId = values['test-id'] || null
@@ -77,6 +153,13 @@ const previewUrlMap = {
77
153
 
78
154
  const previewUrl = previewUrlMap[stage]
79
155
  if (!previewUrl) throw new Error(`Invalid BRICKS_STAGE: ${stage}`)
156
+ simulatorSettings = normalizeSimulatorSecuritySettings({
157
+ ...simulatorSettings,
158
+ allowedInsecureHosts: [
159
+ ...simulatorSettings.allowedInsecureHosts,
160
+ getUnsecureConnectionHost(previewUrl),
161
+ ].filter(Boolean),
162
+ })
80
163
 
81
164
  // --- CDP WebSocket Server ---
82
165
  // Bridges external CDP clients to the preview's postMessage-based CDP bridge.
@@ -142,9 +225,9 @@ const startCdpServer = async (mainWindow, port) => {
142
225
  res.end(
143
226
  JSON.stringify([
144
227
  {
145
- description: 'BRICKS Preview (CTOR Preview)',
146
- id: 'bricks-preview',
147
- title: 'BRICKS Preview',
228
+ description: 'BRICKS Simulator',
229
+ id: 'bricks-simulator',
230
+ title: 'BRICKS Simulator',
148
231
  type: 'page',
149
232
  url: previewUrl,
150
233
  webSocketDebuggerUrl: `ws://localhost:${actualPort}/ws`,
@@ -155,7 +238,7 @@ const startCdpServer = async (mainWindow, port) => {
155
238
  }
156
239
  if (req.url === '/json/version') {
157
240
  res.writeHead(200, { 'Content-Type': 'application/json' })
158
- res.end(JSON.stringify({ Browser: 'BRICKS Preview', 'Protocol-Version': '1.3' }))
241
+ res.end(JSON.stringify({ Browser: 'BRICKS Simulator', 'Protocol-Version': '1.3' }))
159
242
  return
160
243
  }
161
244
  // bricks-cli discovery endpoint
@@ -163,7 +246,7 @@ const startCdpServer = async (mainWindow, port) => {
163
246
  res.writeHead(200, { 'Content-Type': 'application/json' })
164
247
  res.end(
165
248
  JSON.stringify({
166
- name: 'BRICKS Preview',
249
+ name: 'BRICKS Simulator',
167
250
  port: actualPort,
168
251
  protocols: ['cdp'],
169
252
  hasPasscode: false,
@@ -215,6 +298,12 @@ app.on('ready', () => {
215
298
  show,
216
299
  })
217
300
  mainWindow.setBackgroundColor('#333')
301
+ mainWindow.webContents.session.webRequest.onBeforeRequest(
302
+ { urls: ['http://*/*', 'ws://*/*'] },
303
+ (details, callback) => {
304
+ callback({ cancel: shouldBlockInsecureConnection(details.url, simulatorSettings) })
305
+ },
306
+ )
218
307
  mainWindow.loadURL(previewUrl)
219
308
 
220
309
  const sendConfig = () => {
@@ -300,7 +389,34 @@ app.on('ready', () => {
300
389
  async () => {
301
390
  console.log('Detected config changed')
302
391
  config = JSON.parse(await readFile(`${cwd}/.bricks/build/application-config.json`))
392
+ const nextSimulatorSettings = await readSimulatorProjectSettings()
393
+ simulatorSettings = normalizeSimulatorSecuritySettings({
394
+ ...nextSimulatorSettings,
395
+ allowedInsecureHosts: [
396
+ ...nextSimulatorSettings.allowedInsecureHosts,
397
+ getUnsecureConnectionHost(previewUrl),
398
+ ].filter(Boolean),
399
+ })
303
400
  sendConfig()
304
401
  },
305
402
  )
403
+ watchFile(
404
+ `${cwd}/simulator.json`,
405
+ {
406
+ bigint: false,
407
+ persistent: true,
408
+ interval: 1000,
409
+ },
410
+ async () => {
411
+ console.log('Detected simulator settings changed')
412
+ const nextSimulatorSettings = await readSimulatorProjectSettings()
413
+ simulatorSettings = normalizeSimulatorSecuritySettings({
414
+ ...nextSimulatorSettings,
415
+ allowedInsecureHosts: [
416
+ ...nextSimulatorSettings.allowedInsecureHosts,
417
+ getUnsecureConnectionHost(previewUrl),
418
+ ].filter(Boolean),
419
+ })
420
+ },
421
+ )
306
422
  })
@@ -98,7 +98,7 @@ const cleanupDevtoolsInfo = () => {
98
98
  } catch {}
99
99
  }
100
100
 
101
- // Kill existing preview process if devtools.json contains a stale pid
101
+ // Kill existing simulator process if devtools.json contains a stale pid
102
102
  try {
103
103
  const devtoolsInfo = JSON.parse(await readFile(devtoolsInfoPath, 'utf8'))
104
104
  if (devtoolsInfo.pid) {
@@ -111,7 +111,7 @@ try {
111
111
 
112
112
  const proc = spawn(
113
113
  'bunx',
114
- ['--bun', 'electron', `${import.meta.dirname}/preview-main.mjs`, ...args],
114
+ ['--bun', 'electron', `${import.meta.dirname}/simulator-main.mjs`, ...args],
115
115
  {
116
116
  env: { ...process.env, BRICKS_STAGE: app.stage || 'production' },
117
117
  stdio: ['inherit', 'pipe', 'inherit'],
@@ -127,14 +127,14 @@ rl.on('line', (line) => {
127
127
  return
128
128
  }
129
129
  if (!line) return
130
- // Detect CDP server startup from preview-main output
130
+ // Detect CDP server startup from simulator-main output
131
131
  const cdpMatch = line.match(/^CDP server: ws:\/\/localhost:(\d+)/)
132
132
  if (cdpMatch) {
133
133
  const info = {
134
134
  port: parseInt(cdpMatch[1], 10),
135
135
  pid: proc.pid,
136
136
  address: 'localhost',
137
- name: `${app.name || 'Unnamed'} (CTOR Preview)`,
137
+ name: `${app.name || 'Unnamed'} (CTOR Simulator)`,
138
138
  startedAt: new Date().toISOString(),
139
139
  }
140
140
  writeFile(devtoolsInfoPath, JSON.stringify(info, null, 2))