@fugood/bricks-project 2.25.0-beta.50 → 2.25.0-beta.52
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/index.ts +5 -2
- package/compile/util.ts +8 -3
- package/package.json +2 -2
- package/package.json.bak +2 -2
- package/tools/_mcp-config.ts +42 -0
- package/tools/postinstall.ts +17 -37
- package/types/bricks/Sketch.d.ts +4 -2
- package/types/generators/Tick.d.ts +1 -1
- package/utils/event-props.ts +3 -1
package/compile/index.ts
CHANGED
|
@@ -584,7 +584,7 @@ function compileRunArray(run: unknown[]): unknown[] {
|
|
|
584
584
|
/**
|
|
585
585
|
* Compile typed TestCase to raw format (strips __typename)
|
|
586
586
|
*/
|
|
587
|
-
const compileTestCase = (testCase: TestCase) => ({
|
|
587
|
+
export const compileTestCase = (testCase: TestCase) => ({
|
|
588
588
|
id: testCase.id,
|
|
589
589
|
name: testCase.name,
|
|
590
590
|
hide_short_ref: testCase.hideShortRef,
|
|
@@ -606,7 +606,10 @@ const compileTestCase = (testCase: TestCase) => ({
|
|
|
606
606
|
variable: cond.variable,
|
|
607
607
|
operator: cond.operator,
|
|
608
608
|
value: cond.value,
|
|
609
|
-
jump_to
|
|
609
|
+
// `jump_to` may be a getter (() => TestCase) for dynamic case ids (the project generator
|
|
610
|
+
// emits this form). Resolve it to its id like the `run` array does — otherwise the function
|
|
611
|
+
// is JSON-serialized to nothing and the conditional jump silently vanishes from the config.
|
|
612
|
+
jump_to: compileRunElement(cond.jump_to),
|
|
610
613
|
}
|
|
611
614
|
}),
|
|
612
615
|
})
|
package/compile/util.ts
CHANGED
|
@@ -18,13 +18,18 @@ const errorMsg = 'Not allow duplicate set property id between inputs / outputs /
|
|
|
18
18
|
export const validateConfig = (config: ScriptConfig) => {
|
|
19
19
|
// Skip input/output overlap validation in manual mode (allows same data node in both)
|
|
20
20
|
if (config.trigger_mode === 'manual') return
|
|
21
|
-
|
|
21
|
+
// `inputs` is keyed by data-node id with the OBJECT_SET path as the *value*. The overlap
|
|
22
|
+
// check is "is this id also an input?" — a key-existence question — so test key presence,
|
|
23
|
+
// not the path's truthiness. An empty path ('' = OBJECT_SET's default "set whole object")
|
|
24
|
+
// is a legitimate input value that would otherwise slip the overlap guard.
|
|
25
|
+
const isInput = (id: string) => Object.prototype.hasOwnProperty.call(config.inputs, id)
|
|
26
|
+
if (config.error && isInput(config.error)) {
|
|
22
27
|
throw new Error(`${errorMsg}. key: error`)
|
|
23
28
|
}
|
|
24
|
-
if (config.output && config.
|
|
29
|
+
if (config.output && isInput(config.output)) {
|
|
25
30
|
throw new Error(`${errorMsg}. key: output`)
|
|
26
31
|
}
|
|
27
|
-
if (Object.values(config.outputs).some((value) => value.some(
|
|
32
|
+
if (Object.values(config.outputs).some((value) => value.some(isInput))) {
|
|
28
33
|
throw new Error(`${errorMsg}. key: outputs`)
|
|
29
34
|
}
|
|
30
35
|
// The same data-node id reused across the output-side targets (output / error / outputs)
|
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.52",
|
|
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.52",
|
|
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.52",
|
|
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.52",
|
|
15
15
|
"@huggingface/gguf": "^0.3.2",
|
|
16
16
|
"@iarna/toml": "^3.0.0",
|
|
17
17
|
"@modelcontextprotocol/sdk": "^1.15.0",
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { readFile, writeFile, stat } from 'fs/promises'
|
|
2
|
+
|
|
3
|
+
const exists = async (f: string) => {
|
|
4
|
+
try {
|
|
5
|
+
await stat(f)
|
|
6
|
+
return true
|
|
7
|
+
} catch {
|
|
8
|
+
return false
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// Refresh the `bricks-ctor` entry in a project's `.mcp.json` while preserving every other MCP
|
|
13
|
+
// server the user configured. A malformed `.mcp.json` is left untouched (with a warning)
|
|
14
|
+
// rather than overwritten with the default — clobbering it would silently delete the user's
|
|
15
|
+
// other server entries. This mirrors `setupClaudeAutoMode`'s handling of a malformed
|
|
16
|
+
// `settings.local.json` in postinstall.ts.
|
|
17
|
+
export const handleMcpConfigOverride = async (mcpConfigPath: string, projectMcpServer: object) => {
|
|
18
|
+
let mcpConfig: { mcpServers: Record<string, unknown> }
|
|
19
|
+
if (await exists(mcpConfigPath)) {
|
|
20
|
+
let parsed: unknown
|
|
21
|
+
try {
|
|
22
|
+
parsed = JSON.parse(await readFile(mcpConfigPath, 'utf-8'))
|
|
23
|
+
} catch {
|
|
24
|
+
console.warn(`Skipping .mcp.json update; ${mcpConfigPath} is not valid JSON`)
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
mcpConfig =
|
|
28
|
+
parsed && typeof parsed === 'object'
|
|
29
|
+
? (parsed as { mcpServers: Record<string, unknown> })
|
|
30
|
+
: { mcpServers: {} }
|
|
31
|
+
if (!mcpConfig.mcpServers || typeof mcpConfig.mcpServers !== 'object') {
|
|
32
|
+
mcpConfig.mcpServers = {}
|
|
33
|
+
}
|
|
34
|
+
mcpConfig.mcpServers['bricks-ctor'] = projectMcpServer
|
|
35
|
+
delete mcpConfig.mcpServers['bricks-project']
|
|
36
|
+
} else {
|
|
37
|
+
mcpConfig = { mcpServers: { 'bricks-ctor': projectMcpServer } }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
await writeFile(mcpConfigPath, `${JSON.stringify(mcpConfig, null, 2)}\n`)
|
|
41
|
+
console.log(`Updated ${mcpConfigPath}`)
|
|
42
|
+
}
|
package/tools/postinstall.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from 'fs/promises'
|
|
13
13
|
import * as path from 'path'
|
|
14
14
|
import TOML from '@iarna/toml'
|
|
15
|
+
import { handleMcpConfigOverride } from './_mcp-config'
|
|
15
16
|
|
|
16
17
|
const cwd = process.cwd()
|
|
17
18
|
const projectSkillsDir = path.join(cwd, '.bricks', 'skills')
|
|
@@ -80,41 +81,13 @@ type CodexMcpConfig = {
|
|
|
80
81
|
mcp_servers: Record<string, typeof codexProjectMcpServer | typeof projectMcpServer>
|
|
81
82
|
}
|
|
82
83
|
|
|
83
|
-
// Claude Code and AGENTS.md projects both use the shared project .mcp.json file.
|
|
84
|
-
const defaultMcpConfig = {
|
|
85
|
-
mcpServers: {
|
|
86
|
-
'bricks-ctor': projectMcpServer,
|
|
87
|
-
},
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const handleMcpConfigOverride = async (mcpConfigPath: string) => {
|
|
91
|
-
let mcpConfig: { mcpServers: Record<string, typeof projectMcpServer> } | null = null
|
|
92
|
-
if (await exists(mcpConfigPath)) {
|
|
93
|
-
const configStr = await readFile(mcpConfigPath, 'utf-8')
|
|
94
|
-
try {
|
|
95
|
-
mcpConfig = JSON.parse(configStr)
|
|
96
|
-
if (!mcpConfig?.mcpServers) throw new Error('mcpServers is not defined')
|
|
97
|
-
mcpConfig.mcpServers['bricks-ctor'] = projectMcpServer
|
|
98
|
-
delete mcpConfig.mcpServers['bricks-project']
|
|
99
|
-
} catch {
|
|
100
|
-
mcpConfig = defaultMcpConfig
|
|
101
|
-
}
|
|
102
|
-
} else {
|
|
103
|
-
mcpConfig = defaultMcpConfig
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
await writeFile(mcpConfigPath, `${JSON.stringify(mcpConfig, null, 2)}\n`)
|
|
107
|
-
|
|
108
|
-
console.log(`Updated ${mcpConfigPath}`)
|
|
109
|
-
}
|
|
110
|
-
|
|
111
84
|
const hasClaudeCode = await exists(`${cwd}/CLAUDE.md`)
|
|
112
85
|
const hasAgentsMd = await exists(`${cwd}/AGENTS.md`)
|
|
113
86
|
|
|
114
87
|
if (hasClaudeCode || hasAgentsMd) {
|
|
115
88
|
// Keep the workspace-level JSON MCP config aligned for tools that read .mcp.json.
|
|
116
89
|
const mcpConfigPath = `${cwd}/.mcp.json`
|
|
117
|
-
await handleMcpConfigOverride(mcpConfigPath)
|
|
90
|
+
await handleMcpConfigOverride(mcpConfigPath, projectMcpServer)
|
|
118
91
|
}
|
|
119
92
|
|
|
120
93
|
const copyMissingSkills = async (sourceDir: string, targetDir: string) => {
|
|
@@ -282,18 +255,25 @@ if (hasAgentsMd) {
|
|
|
282
255
|
}
|
|
283
256
|
|
|
284
257
|
const handleCodexMcpConfigOverride = async (mcpConfigPath: string) => {
|
|
285
|
-
let mcpConfig: CodexMcpConfig
|
|
258
|
+
let mcpConfig: CodexMcpConfig
|
|
286
259
|
if (await exists(mcpConfigPath)) {
|
|
287
|
-
|
|
260
|
+
let parsed: unknown
|
|
288
261
|
try {
|
|
289
|
-
|
|
290
|
-
if (!parsed?.mcp_servers) throw new Error('mcp_servers is not defined')
|
|
291
|
-
mcpConfig = { mcp_servers: parsed.mcp_servers }
|
|
292
|
-
mcpConfig.mcp_servers['bricks-ctor'] = codexProjectMcpServer
|
|
293
|
-
delete mcpConfig.mcp_servers['bricks-project']
|
|
262
|
+
parsed = TOML.parse(await readFile(mcpConfigPath, 'utf-8'))
|
|
294
263
|
} catch {
|
|
295
|
-
|
|
264
|
+
// A malformed config is left untouched (with a warning) rather than overwritten with
|
|
265
|
+
// the default — clobbering it would silently delete the user's other server entries.
|
|
266
|
+
// Mirrors handleMcpConfigOverride's handling of a malformed .mcp.json.
|
|
267
|
+
console.warn(`Skipping .codex/config.toml update; ${mcpConfigPath} is not valid TOML`)
|
|
268
|
+
return
|
|
269
|
+
}
|
|
270
|
+
mcpConfig =
|
|
271
|
+
parsed && typeof parsed === 'object' ? (parsed as CodexMcpConfig) : { mcp_servers: {} }
|
|
272
|
+
if (!mcpConfig.mcp_servers || typeof mcpConfig.mcp_servers !== 'object') {
|
|
273
|
+
mcpConfig.mcp_servers = {}
|
|
296
274
|
}
|
|
275
|
+
mcpConfig.mcp_servers['bricks-ctor'] = codexProjectMcpServer
|
|
276
|
+
delete mcpConfig.mcp_servers['bricks-project']
|
|
297
277
|
} else {
|
|
298
278
|
mcpConfig = defaultCodexMcpConfig
|
|
299
279
|
}
|
package/types/bricks/Sketch.d.ts
CHANGED
|
@@ -191,9 +191,11 @@ Default property:
|
|
|
191
191
|
/* A stroke was just committed (drawn or added programmatically) */
|
|
192
192
|
onStrokeEnd?: Array<EventAction<string & keyof TemplateEventPropsMap['Sketch']['onStrokeEnd']>>
|
|
193
193
|
/* The canvas was cleared */
|
|
194
|
-
onClear?: Array<EventAction
|
|
194
|
+
onClear?: Array<EventAction<string & keyof TemplateEventPropsMap['Sketch']['onClear']>>
|
|
195
195
|
/* Sketch state changed (any commit, undo, redo, clear, or import) */
|
|
196
|
-
onStateChange?: Array<
|
|
196
|
+
onStateChange?: Array<
|
|
197
|
+
EventAction<string & keyof TemplateEventPropsMap['Sketch']['onStateChange']>
|
|
198
|
+
>
|
|
197
199
|
/* Active tool changed */
|
|
198
200
|
onToolChange?: Array<
|
|
199
201
|
EventAction<string & keyof TemplateEventPropsMap['Sketch']['onToolChange']>
|
|
@@ -33,7 +33,7 @@ Default property:
|
|
|
33
33
|
property?: {
|
|
34
34
|
/* Start tick on generator initialized */
|
|
35
35
|
init?: boolean | DataLink
|
|
36
|
-
/*
|
|
36
|
+
/* Tick interval in milliseconds for countdown */
|
|
37
37
|
interval?: number | DataLink
|
|
38
38
|
/* Initial value of countdown */
|
|
39
39
|
countdownStartValue?: number | DataLink
|
package/utils/event-props.ts
CHANGED
|
@@ -142,7 +142,9 @@ export const templateEventPropsMap = {
|
|
|
142
142
|
},
|
|
143
143
|
},
|
|
144
144
|
Sketch: {
|
|
145
|
-
onStrokeEnd: { BRICK_SKETCH_STROKE_COUNT: 'number' },
|
|
145
|
+
onStrokeEnd: { BRICK_SKETCH_STROKE_COUNT: 'number', BRICK_SKETCH_STATE: '{}' },
|
|
146
|
+
onClear: { BRICK_SKETCH_STATE: '{}' },
|
|
147
|
+
onStateChange: { BRICK_SKETCH_STATE: '{}' },
|
|
146
148
|
onToolChange: { BRICK_SKETCH_TOOL: 'string' },
|
|
147
149
|
onExportImage: { BRICK_SKETCH_IMAGE_URI: 'string' },
|
|
148
150
|
},
|