@fugood/bricks-ctor 2.25.0-beta.47 → 2.25.0-beta.48

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.
@@ -1,7 +1,14 @@
1
1
  jest.mock('../../tools/_shell', () => ({
2
- sh: jest.fn(() => Promise.resolve({})),
2
+ sh: jest.fn(),
3
3
  }))
4
4
 
5
+ // Mirrors the chainable `sh` result (supports `.nothrow()` like the real helper).
6
+ const shResult = (over = {}) => {
7
+ const result = Promise.resolve({ exitCode: 0, stdout: '', stderr: '', ...over })
8
+ result.nothrow = () => result
9
+ return result
10
+ }
11
+
5
12
  import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
6
13
  import os from 'node:os'
7
14
  import path from 'node:path'
@@ -57,7 +64,8 @@ const commandOf = ([strings, ...values]) =>
57
64
 
58
65
  describe('checkConfig', () => {
59
66
  beforeEach(() => {
60
- sh.mockClear()
67
+ sh.mockReset()
68
+ sh.mockImplementation(() => shResult())
61
69
  })
62
70
 
63
71
  test('runs doctor after check-config', async () => {
@@ -68,6 +76,20 @@ describe('checkConfig', () => {
68
76
  'bricks app doctor --validate-automation .bricks/build/application-config.json',
69
77
  ])
70
78
  })
79
+
80
+ test('skips doctor when the CLI lacks the command', async () => {
81
+ sh.mockReturnValueOnce(shResult()) // check-config
82
+ sh.mockReturnValueOnce(shResult({ exitCode: 1, stderr: "error: unknown command 'doctor'" }))
83
+
84
+ await expect(checkConfig('config.json')).resolves.toBeUndefined()
85
+ })
86
+
87
+ test('throws when doctor reports config errors', async () => {
88
+ sh.mockReturnValueOnce(shResult()) // check-config
89
+ sh.mockReturnValueOnce(shResult({ exitCode: 1, stderr: 'DATA_RACE: conflicting writes' }))
90
+
91
+ await expect(checkConfig('config.json')).rejects.toThrow()
92
+ })
71
93
  })
72
94
 
73
95
  describe('compile animations', () => {
package/compile/index.ts CHANGED
@@ -1494,6 +1494,11 @@ export const checkConfig = async (configPath: string) => {
1494
1494
  // which catches agent-authored automations that reference deleted bricks.
1495
1495
  await sh`bricks app check-config --validate-automation ${configPath}`
1496
1496
  // Doctor adds semantic lint checks after structural validation. Warnings are
1497
- // surfaced in the compile log, but only errors fail by default.
1498
- await sh`bricks app doctor --validate-automation ${configPath}`
1497
+ // surfaced in the compile log, but only errors fail by default. Older published
1498
+ // bricks-cli builds lack `app doctor` skip rather than fail the compile.
1499
+ const doctor = await sh`bricks app doctor --validate-automation ${configPath}`.nothrow()
1500
+ if (doctor.exitCode !== 0) {
1501
+ if (/unknown command/i.test(doctor.stderr?.toString() ?? '')) return
1502
+ throw new Error(`bricks app doctor failed with exit ${doctor.exitCode}`)
1503
+ }
1499
1504
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fugood/bricks-ctor",
3
- "version": "2.25.0-beta.47",
3
+ "version": "2.25.0-beta.48",
4
4
  "main": "index.ts",
5
5
  "scripts": {
6
6
  "typecheck": "tsc --noEmit",
@@ -11,7 +11,7 @@
11
11
  "@babel/parser": "7.28.5",
12
12
  "@babel/traverse": "7.28.5",
13
13
  "@babel/types": "7.28.5",
14
- "@fugood/bricks-cli": "^2.25.0-beta.46",
14
+ "@fugood/bricks-cli": "^2.25.0-beta.48",
15
15
  "@huggingface/gguf": "^0.3.2",
16
16
  "@iarna/toml": "^3.0.0",
17
17
  "@modelcontextprotocol/sdk": "^1.15.0",
@@ -29,5 +29,5 @@
29
29
  "peerDependencies": {
30
30
  "oxfmt": "^0.36.0"
31
31
  },
32
- "gitHead": "95f194a3fb6331c0f25a879e55675e3ff331a412"
32
+ "gitHead": "6403fb9aece6b9ee45a72a963ddc75aec5ae3e04"
33
33
  }
@@ -122,6 +122,25 @@ Once DevTools is on, ask the user how they want to drive the verification — Ch
122
122
 
123
123
  For agent-driven CDP/MCP work against the device (`bricks devtools …` with `-a <ip> --passcode <pc>`, plus bridging the device MCP endpoint into an MCP client), the same `bricks-cli` skill referenced in Path 1 covers the on-device case — read it if installed. If not installed, run `bricks --help` and `bricks devtools --help` for the authoritative command listing.
124
124
 
125
+ ### Running real-device Automations from an agent
126
+
127
+ There is no `bricks devtools automation` subcommand. Use the DevTools runtime helpers exposed inside the app:
128
+
129
+ ```bash
130
+ bricks devtools runtime eval -a <ip> -p 19851 --passcode <pc> "Object.getOwnPropertyNames(automation).sort()" -j
131
+ bricks devtools runtime eval -a <ip> -p 19851 --passcode <pc> "automation.list()" -j
132
+ bricks devtools runtime eval -a <ip> -p 19851 --passcode <pc> "automation.run('<TEST_id>', { updateScreenshot: false })" --await -j
133
+ ```
134
+
135
+ `automation.run()` starts the device-side run and may return `null`; treat that as accepted, not as a pass/fail result. Wait for the run timeout/window, then verify completion through the app's own state and a screenshot. For app state, use live runtime reads such as:
136
+
137
+ ```bash
138
+ bricks devtools runtime eval -a <ip> -p 19851 --passcode <pc> "JSON.stringify({ result: system.data.property('<S_xxxx>', '<resultAlias>')?.value })" -j
139
+ bricks devtools screenshot -a <ip> -p 19851 --passcode <pc> -o /tmp/device-automation.png
140
+ ```
141
+
142
+ In CTOR Desktop sandboxed sessions, keep these as separate simple commands. Avoid multi-line shell scripts, `for` loops, brace expansion, and command substitution around `bricks devtools`; those can stay sandboxed and lose LAN/device access. After `bun update-app` or a device refresh, the DevTools socket may briefly drop, so wait and probe with one screenshot or one `runtime eval` before running the automation.
143
+
125
144
  ### Real-device side-effects warning
126
145
 
127
146
  Real devices fire real peripherals. Payment terminals charge. MQTT broadcasts on shared topics. BLE advertises to bystanders. Use a **staging** device for verification cycles; never iterate on a production-deployed device unless the user explicitly approves.