@fugood/bricks-project 2.25.0-beta.45 → 2.25.0-beta.46
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/config-diff.ts
CHANGED
|
@@ -27,17 +27,60 @@ export type ConfigChange =
|
|
|
27
27
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
28
28
|
typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
29
29
|
|
|
30
|
+
const isJsonDroppedValue = (value: unknown) =>
|
|
31
|
+
value === undefined || typeof value === 'function' || typeof value === 'symbol'
|
|
32
|
+
|
|
33
|
+
const toJsonComparableScalar = (value: unknown) => {
|
|
34
|
+
if (typeof value === 'number' && !Number.isFinite(value)) return null
|
|
35
|
+
return value
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const toJsonCompatibleValue = (value: unknown): unknown => {
|
|
39
|
+
if (isJsonDroppedValue(value)) return undefined
|
|
40
|
+
if (Array.isArray(value)) {
|
|
41
|
+
return value.map((item) => (isJsonDroppedValue(item) ? null : toJsonCompatibleValue(item)))
|
|
42
|
+
}
|
|
43
|
+
if (isRecord(value)) {
|
|
44
|
+
return Object.entries(value).reduce((acc, [key, item]) => {
|
|
45
|
+
if (!isJsonDroppedValue(item)) acc[key] = toJsonCompatibleValue(item)
|
|
46
|
+
return acc
|
|
47
|
+
}, {})
|
|
48
|
+
}
|
|
49
|
+
return toJsonComparableScalar(value)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const hasJsonObjectKey = (value: Record<string, unknown>, key: string) =>
|
|
53
|
+
Object.prototype.hasOwnProperty.call(value, key) && !isJsonDroppedValue(value[key])
|
|
54
|
+
|
|
55
|
+
const getJsonArrayItem = (value: unknown[], index: number) => {
|
|
56
|
+
const item = value[index]
|
|
57
|
+
return isJsonDroppedValue(item) ? null : item
|
|
58
|
+
}
|
|
59
|
+
|
|
30
60
|
const deepEqual = (a: unknown, b: unknown): boolean => {
|
|
61
|
+
a = toJsonComparableScalar(a)
|
|
62
|
+
b = toJsonComparableScalar(b)
|
|
31
63
|
if (a === b) return true
|
|
32
64
|
if (Array.isArray(a) && Array.isArray(b)) {
|
|
33
|
-
|
|
65
|
+
if (a.length !== b.length) return false
|
|
66
|
+
for (let index = 0; index < a.length; index += 1) {
|
|
67
|
+
if (!deepEqual(getJsonArrayItem(a, index), getJsonArrayItem(b, index))) return false
|
|
68
|
+
}
|
|
69
|
+
return true
|
|
34
70
|
}
|
|
35
71
|
if (isRecord(a) && isRecord(b)) {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
72
|
+
let comparableAKeys = 0
|
|
73
|
+
for (const key of Object.keys(a)) {
|
|
74
|
+
if (isJsonDroppedValue(a[key])) continue
|
|
75
|
+
comparableAKeys += 1
|
|
76
|
+
if (!hasJsonObjectKey(b, key) || !deepEqual(a[key], b[key])) return false
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let comparableBKeys = 0
|
|
80
|
+
for (const key of Object.keys(b)) {
|
|
81
|
+
if (!isJsonDroppedValue(b[key])) comparableBKeys += 1
|
|
82
|
+
}
|
|
83
|
+
return comparableAKeys === comparableBKeys
|
|
41
84
|
}
|
|
42
85
|
return false
|
|
43
86
|
}
|
|
@@ -64,22 +107,32 @@ const diffInto = (
|
|
|
64
107
|
if (isRecord(before) && isRecord(after)) {
|
|
65
108
|
const keys = new Set([...Object.keys(before), ...Object.keys(after)])
|
|
66
109
|
for (const key of keys) {
|
|
110
|
+
const beforeHasKey = hasJsonObjectKey(before, key)
|
|
111
|
+
const afterHasKey = hasJsonObjectKey(after, key)
|
|
112
|
+
if (!beforeHasKey && !afterHasKey) continue
|
|
113
|
+
|
|
67
114
|
const nextPath = [...currentPath, key]
|
|
68
|
-
if (!
|
|
69
|
-
else if (!
|
|
70
|
-
|
|
115
|
+
if (!afterHasKey) ops.push({ op: 'unset', path: nextPath })
|
|
116
|
+
else if (!beforeHasKey) {
|
|
117
|
+
ops.push({ op: 'set', path: nextPath, value: toJsonCompatibleValue(after[key]) })
|
|
118
|
+
} else diffInto(before[key], after[key], nextPath, ops)
|
|
71
119
|
}
|
|
72
120
|
return
|
|
73
121
|
}
|
|
74
122
|
|
|
75
123
|
if (Array.isArray(before) && Array.isArray(after) && before.length === after.length) {
|
|
76
124
|
for (let index = 0; index < after.length; index += 1) {
|
|
77
|
-
diffInto(
|
|
125
|
+
diffInto(
|
|
126
|
+
getJsonArrayItem(before, index),
|
|
127
|
+
getJsonArrayItem(after, index),
|
|
128
|
+
[...currentPath, index],
|
|
129
|
+
ops,
|
|
130
|
+
)
|
|
78
131
|
}
|
|
79
132
|
return
|
|
80
133
|
}
|
|
81
134
|
|
|
82
|
-
ops.push({ op: 'set', path: currentPath, value: after })
|
|
135
|
+
ops.push({ op: 'set', path: currentPath, value: toJsonCompatibleValue(after) })
|
|
83
136
|
}
|
|
84
137
|
|
|
85
138
|
// Diff two compiled configs. `before == null` means there was no prior build to compare
|
package/compile/index.ts
CHANGED
|
@@ -714,9 +714,9 @@ const compileAutomation = (automationMap: AutomationMap) =>
|
|
|
714
714
|
const recordConfigChange = async (previousConfig: unknown, config: unknown) => {
|
|
715
715
|
if (previousConfig == null) return
|
|
716
716
|
if (!isTruthyEnv(process.env.BRICKS_CTOR_ENABLE_EDITING_TOOLS)) return
|
|
717
|
-
// The baseline was parsed from JSON;
|
|
718
|
-
//
|
|
719
|
-
const change = computeConfigChange(previousConfig,
|
|
717
|
+
// The baseline was parsed from JSON; `computeConfigChange` applies the same
|
|
718
|
+
// JSON-omitted-field rules lazily so compile avoids cloning the full config.
|
|
719
|
+
const change = computeConfigChange(previousConfig, config)
|
|
720
720
|
if (change.status !== 'ok') return
|
|
721
721
|
await appendEditRecord(process.cwd(), {
|
|
722
722
|
ts: new Date().toISOString(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fugood/bricks-project",
|
|
3
|
-
"version": "2.25.0-beta.
|
|
3
|
+
"version": "2.25.0-beta.46",
|
|
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.
|
|
14
|
+
"@fugood/bricks-cli": "^2.25.0-beta.46",
|
|
15
15
|
"@huggingface/gguf": "^0.3.2",
|
|
16
16
|
"@iarna/toml": "^3.0.0",
|
|
17
17
|
"@modelcontextprotocol/sdk": "^1.15.0",
|
package/package.json.bak
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fugood/bricks-ctor",
|
|
3
|
-
"version": "2.25.0-beta.
|
|
3
|
+
"version": "2.25.0-beta.46",
|
|
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.
|
|
14
|
+
"@fugood/bricks-cli": "^2.25.0-beta.46",
|
|
15
15
|
"@huggingface/gguf": "^0.3.2",
|
|
16
16
|
"@iarna/toml": "^3.0.0",
|
|
17
17
|
"@modelcontextprotocol/sdk": "^1.15.0",
|
|
@@ -46,7 +46,7 @@ These work, but with browser caveats:
|
|
|
46
46
|
| WebView / WebCrawler | Subject to browser CORS — a load/fetch that works on device may be blocked |
|
|
47
47
|
| On-device AI (LLM / STT / VAD / Vector Store / Reranker) | Runs **single-threaded** — far slower than the device, not representative of real latency. Also subject to the model fallbacks below |
|
|
48
48
|
| On-device database (SQLite — `GENERATOR_SQLITE`) | Runs for real on the in-memory WASM `sqlite-vec` build — `execute` / `query` / `transaction` / batch all work. `storageType: file` is transparently treated as in-memory, so nothing persists across reloads (see above) |
|
|
49
|
-
| Scene3D /
|
|
49
|
+
| Scene3D / Sketch / WebRTC | Supported |
|
|
50
50
|
|
|
51
51
|
Feature availability also varies across the device platforms themselves (iOS / tvOS / Android / the desktop OSes). When a deployment targets a specific platform's capability, confirm it on that platform.
|
|
52
52
|
|
|
@@ -89,6 +89,7 @@ So that camera and AI features are usable without device permissions, multi-giga
|
|
|
89
89
|
| Brick / Generator | In the Simulator | Does NOT prove |
|
|
90
90
|
|-------------------|------------------|----------------|
|
|
91
91
|
| Camera (`BRICK_CAMERA`) | A 3D mock canvas, no camera permission prompt. `takePicture` snapshots the canvas; recording produces a placeholder clip | Real camera feed, focus, recording, permission flow |
|
|
92
|
+
| Maps (`BRICK_MAPS`) | A real interactive map on free OpenStreetMap-based tiles — no Google Maps API key needed. Markers, path polyline, the six themes / map types (approximated with free tile sets + CSS tints), and the zoom / pan / navigate / focus / reset / fit actions all work | Google / Apple Maps rendering, exact `customMapStyle` / theme styling (approximated), traffic / buildings / indoors layers, real device geolocation |
|
|
92
93
|
| Thermal Printer (`GENERATOR_THERMAL_PRINTER`) | A simulated printer — `init` / `checkStatus` / `scan` fake per-driver status and discovered devices (ESC/POS, Star, TSC, Castles); `print` renders an approximate on-screen receipt. A bottom-left bubble shows live status with a fault toggle to exercise error wiring. Print results can be exported as PNG via `bricks-cli` (see below) | Real device connection, actual paper output, exact native driver status codes |
|
|
93
94
|
| LLM (`GENERATOR_LLM`) | Swapped to a tiny local stand-in model | Output quality / latency of your real model |
|
|
94
95
|
| Reranker — GGML (`GENERATOR_RERANKER`) | Swapped to a small local multilingual reranker model | Ranking quality / latency of your real model |
|
|
@@ -119,7 +120,7 @@ The PNG is the same approximate receipt the on-screen preview shows (rendered fr
|
|
|
119
120
|
|
|
120
121
|
### Running the real implementation instead
|
|
121
122
|
|
|
122
|
-
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.
|
|
123
|
+
Each substituted brick/generator can be switched back to its real implementation per item: open the **gear (Simulator settings)** in the editor's preview toolbar, uncheck the item, and **Apply**. Apply persists the choice and reloads the preview so it takes effect (a plain refresh won't). Use this to, e.g., point a Vector Store at a real API key in the preview, or render the real Google/Apple Maps brick (which needs a Maps API key on web). The browser limits above still apply, and **Buttress stays disabled regardless** — there's no backend for it here.
|
|
123
124
|
|
|
124
125
|
The Thermal Printer is the exception: it has no real web implementation to switch to (the native drivers can't run in a browser), so it is **always simulated** and is not in the gear list.
|
|
125
126
|
|