@fugood/bricks-project 2.22.0-beta.1 → 2.22.0-beta.11

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.
@@ -512,6 +512,36 @@ export const templateActionNameMap = {
512
512
  paramsString: 'GENERATOR_SQLITE_PARAMS_STRING',
513
513
  },
514
514
  },
515
+
516
+ GENERATOR_MCP: {
517
+ GENERATOR_MCP_LIST_RESOURCES: {
518
+ requestId: 'GENERATOR_MCP_REQUEST_ID',
519
+ },
520
+ GENERATOR_MCP_LIST_RESOURCE_TEMPLATES: {
521
+ requestId: 'GENERATOR_MCP_REQUEST_ID',
522
+ },
523
+ GENERATOR_MCP_READ_RESOURCE: {
524
+ requestId: 'GENERATOR_MCP_REQUEST_ID',
525
+ uri: 'GENERATOR_MCP_URI',
526
+ variables: 'GENERATOR_MCP_VARIABLES',
527
+ },
528
+ GENERATOR_MCP_LIST_TOOLS: {
529
+ requestId: 'GENERATOR_MCP_REQUEST_ID',
530
+ },
531
+ GENERATOR_MCP_CALL_TOOL: {
532
+ requestId: 'GENERATOR_MCP_REQUEST_ID',
533
+ name: 'GENERATOR_MCP_NAME',
534
+ variables: 'GENERATOR_MCP_VARIABLES',
535
+ },
536
+ GENERATOR_MCP_LIST_PROMPTS: {
537
+ requestId: 'GENERATOR_MCP_REQUEST_ID',
538
+ },
539
+ GENERATOR_MCP_GET_PROMPT: {
540
+ requestId: 'GENERATOR_MCP_REQUEST_ID',
541
+ name: 'GENERATOR_MCP_NAME',
542
+ variables: 'GENERATOR_MCP_VARIABLES',
543
+ },
544
+ },
515
545
  GENERATOR_TTS: {
516
546
  GENERATOR_TTS_GENERATE: {
517
547
  text: 'GENERATOR_TTS_TEXT',
@@ -521,6 +551,7 @@ export const templateActionNameMap = {
521
551
  GENERATOR_ONNX_LLM_INFER: {
522
552
  prompt: 'GENERATOR_ONNX_LLM_PROMPT',
523
553
  chat: 'GENERATOR_ONNX_LLM_CHAT',
554
+ images: 'GENERATOR_ONNX_LLM_IMAGES',
524
555
  },
525
556
  },
526
557
  GENERATOR_ONNX_STT: {
@@ -615,6 +646,12 @@ export const templateActionNameMap = {
615
646
  sessionCustomKey: 'GENERATOR_LLM_SESSION_CUSTOM_KEY',
616
647
  },
617
648
  },
649
+ GENERATOR_QNN_LLM: {
650
+ GENERATOR_QNN_LLM_GENERATE: {
651
+ prompt: 'GENERATOR_QNN_LLM_PROMPT',
652
+ messages: 'GENERATOR_QNN_LLM_MESSAGES',
653
+ },
654
+ },
618
655
  GENERATOR_OPENAI_LLM: {
619
656
  GENERATOR_OPENAI_LLM_COMPLETION: {
620
657
  messages: 'GENERATOR_OPENAI_LLM_MESSAGES',
@@ -630,6 +667,11 @@ export const templateActionNameMap = {
630
667
  responseFormat: 'GENERATOR_OPENAI_LLM_RESPONSE_FORMAT',
631
668
  },
632
669
  },
670
+ GENERATOR_OPENAI_TTS: {
671
+ GENERATOR_OPENAI_TTS_GENERATE: {
672
+ text: 'GENERATOR_OPENAI_TTS_TEXT',
673
+ },
674
+ },
633
675
  GENERATOR_ASSISTANT: {
634
676
  GENERATOR_ASSISTANT_ADD_MESSAGE: {
635
677
  role: 'GENERATOR_ASSISTANT_ROLE',
@@ -643,6 +685,17 @@ export const templateActionNameMap = {
643
685
  fileSearchCitationCount: 'GENERATOR_ASSISTANT_FILE_SEARCH_CITATION_COUNT',
644
686
  fileSearchInsertMethod: 'GENERATOR_ASSISTANT_FILE_SEARCH_INSERT_METHOD',
645
687
  },
688
+ GENERATOR_ASSISTANT_INIT_MCP_PROMPT: {
689
+ mcpClientName: 'GENERATOR_ASSISTANT_MCP_CLIENT_NAME',
690
+ mcpPromptName: 'GENERATOR_ASSISTANT_MCP_PROMPT_NAME',
691
+ mcpArguments: 'GENERATOR_ASSISTANT_MCP_ARGUMENTS',
692
+ firstMessageAsSystem: 'GENERATOR_ASSISTANT_FIRST_MESSAGE_AS_SYSTEM',
693
+ },
694
+ GENERATOR_ASSISTANT_ADD_MCP_PROMPT_MESSAGE: {
695
+ mcpClientName: 'GENERATOR_ASSISTANT_MCP_CLIENT_NAME',
696
+ mcpPromptName: 'GENERATOR_ASSISTANT_MCP_PROMPT_NAME',
697
+ mcpArguments: 'GENERATOR_ASSISTANT_MCP_ARGUMENTS',
698
+ },
646
699
  GENERATOR_ASSISTANT_UPDATE_MESSAGE_AT_INDEX: {
647
700
  index: 'GENERATOR_ASSISTANT_INDEX',
648
701
  content: 'GENERATOR_ASSISTANT_CONTENT',
@@ -679,6 +732,21 @@ export const templateActionNameMap = {
679
732
  GENERATOR_ASSISTANT_REMOVE_MESSAGE_AT_INDEX: {
680
733
  index: 'GENERATOR_ASSISTANT_INDEX',
681
734
  },
735
+ GENERATOR_ASSISTANT_SUBMIT: {
736
+ continueOnToolCallConfirm: 'GENERATOR_ASSISTANT_CONTINUE_ON_TOOL_CALL_CONFIRM',
737
+ continueOnToolCallStrategy: 'GENERATOR_ASSISTANT_CONTINUE_ON_TOOL_CALL_STRATEGY',
738
+ continueOnToolCallLimit: 'GENERATOR_ASSISTANT_CONTINUE_ON_TOOL_CALL_LIMIT',
739
+ },
740
+ GENERATOR_ASSISTANT_INSERT_MCP_RESOURCE: {
741
+ mcpClientName: 'GENERATOR_ASSISTANT_MCP_CLIENT_NAME',
742
+ mcpResourceUri: 'GENERATOR_ASSISTANT_MCP_RESOURCE_URI',
743
+ mcpVariables: 'GENERATOR_ASSISTANT_MCP_VARIABLES',
744
+ role: 'GENERATOR_ASSISTANT_ROLE',
745
+ },
746
+ GENERATOR_ASSISTANT_SUMMARY_MESSAGES: {
747
+ summaryMessages: 'GENERATOR_ASSISTANT_SUMMARY_MESSAGES',
748
+ summarySessionKey: 'GENERATOR_ASSISTANT_SUMMARY_SESSION_KEY',
749
+ },
682
750
  },
683
751
  GENERATOR_VECTOR_STORE: {
684
752
  GENERATOR_VECTOR_STORE_RESET: {
package/compile/index.ts CHANGED
@@ -856,6 +856,7 @@ export const compile = async (app: Application) => {
856
856
  fonts: app.fonts,
857
857
  ...compileApplicationSettings(app.settings),
858
858
  test_map: app.metadata?.TEMP_test_map || {},
859
+ automation_map: app.metadata?.TEMP_automation_map || {},
859
860
  }
860
861
  return config
861
862
  }
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@fugood/bricks-project",
3
- "version": "2.22.0-beta.1",
3
+ "version": "2.22.0-beta.11",
4
4
  "main": "index.ts",
5
5
  "scripts": {
6
6
  "build": "node scripts/build.js"
7
7
  },
8
8
  "dependencies": {
9
+ "@modelcontextprotocol/sdk": "^1.11.1",
9
10
  "@types/escodegen": "^0.0.10",
10
11
  "@types/lodash": "^4.17.12",
11
12
  "acorn": "^8.13.0",
@@ -13,5 +14,5 @@
13
14
  "lodash": "^4.17.4",
14
15
  "uuid": "^8.3.1"
15
16
  },
16
- "gitHead": "c55f6effe15a6c481e6fc1147f8bff0c747169ef"
17
+ "gitHead": "a6ee3595eab6b78d68c51effdeac7224e666134c"
17
18
  }
@@ -0,0 +1,86 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
3
+ import { z } from 'zod'
4
+ import { $ } from 'bun'
5
+
6
+ const server = new McpServer({
7
+ name: 'bricks-project',
8
+ version: '1.0.0',
9
+ })
10
+
11
+ const dirname = import.meta.dirname
12
+ const projectDir = String(dirname).split('/node_modules/')[0]
13
+
14
+ server.tool('compile', {}, async () => {
15
+ let log
16
+ try {
17
+ log = await $`bun compile`.cwd(projectDir).text()
18
+ } catch (err) {
19
+ log = err.stdout.toString() + '\n' + err.stderr.toString()
20
+ }
21
+ return {
22
+ content: [{ type: 'text', text: log || 'Compiled successfully' }],
23
+ }
24
+ })
25
+
26
+ // NOTE: Cursor (Or VSCode) seems set ELECTRON_RUN_AS_NODE to 1, so we need to unset it
27
+ process.env.ELECTRON_RUN_AS_NODE = ''
28
+
29
+ server.tool(
30
+ 'take-preview-screenshot',
31
+ {
32
+ delay: z
33
+ .number()
34
+ .describe('Delay in milliseconds before taking screenshot')
35
+ .optional()
36
+ .default(3000),
37
+ width: z.number().describe('Width of the screenshot').optional().default(600),
38
+ height: z.number().optional().default(480),
39
+ responseImage: z
40
+ .boolean()
41
+ .describe(
42
+ 'Whether to response image content (base64 encoded jpeg). If false, only saved path will be responded as text.',
43
+ )
44
+ .optional()
45
+ .default(false),
46
+ } as any,
47
+ async ({ delay, width, height, responseImage }: any) => {
48
+ let log = ''
49
+ let error = false
50
+ try {
51
+ const args = [
52
+ '--take-screenshot',
53
+ JSON.stringify({
54
+ delay,
55
+ width,
56
+ height,
57
+ path: `${dirname}/screenshot.jpg`,
58
+ closeAfter: true,
59
+ headless: true,
60
+ }),
61
+ ]
62
+ log = await $`bunx --bun electron ${dirname}/preview-main.mjs ${args}`.cwd(projectDir).text()
63
+ } catch (err) {
64
+ log = err.stdout.toString() + '\n' + err.stderr.toString()
65
+ error = true
66
+ }
67
+ let screenshotBase64: any = null
68
+ if (!error && responseImage) {
69
+ const screenshot = await Bun.file(`${dirname}/screenshot.jpg`).arrayBuffer()
70
+ screenshotBase64 = Buffer.from(screenshot).toString('base64')
71
+ }
72
+ return {
73
+ content: [
74
+ { type: 'text', text: log },
75
+ screenshotBase64 && {
76
+ type: 'image',
77
+ data: screenshotBase64,
78
+ mimeType: 'image/jpeg',
79
+ },
80
+ ].filter(Boolean),
81
+ }
82
+ },
83
+ )
84
+
85
+ const transport = new StdioServerTransport()
86
+ await server.connect(transport)
@@ -1,5 +1,5 @@
1
1
  import { $ } from 'bun'
2
-
2
+ import { stat, readFile, writeFile } from 'fs/promises'
3
3
  const cwd = process.cwd()
4
4
 
5
5
  const libFiles = ['types', 'utils', 'index.ts']
@@ -9,4 +9,55 @@ for (const file of libFiles) {
9
9
  await $`cp -r ${__dirname}/../${file} ${cwd}/project`
10
10
  }
11
11
 
12
- console.log('Copied files to project/')
12
+ console.log('Copied files to project/')
13
+
14
+ async function exists(f: string) {
15
+ try {
16
+ await stat(f)
17
+ return true
18
+ } catch {
19
+ return false
20
+ }
21
+ }
22
+
23
+ const projectMcpServer = {
24
+ command: 'bun',
25
+ args: [`${cwd}/node_modules/@fugood/bricks-project/tools/mcp-server.ts`],
26
+ }
27
+
28
+ const defaultMcpConfig = {
29
+ mcpServers: {
30
+ 'bricks-project': projectMcpServer,
31
+ },
32
+ }
33
+
34
+ const handleMcpConfigOverride = async (mcpConfigPath: string) => {
35
+ let mcpConfig: { mcpServers: Record<string, typeof projectMcpServer> } | null = null
36
+ if (await exists(mcpConfigPath)) {
37
+ const configStr = await readFile(mcpConfigPath, 'utf-8')
38
+ try {
39
+ mcpConfig = JSON.parse(configStr)
40
+ if (!mcpConfig?.mcpServers) throw new Error('mcpServers is not defined')
41
+ mcpConfig.mcpServers['bricks-project'] = projectMcpServer
42
+ } catch (e) {
43
+ mcpConfig = defaultMcpConfig
44
+ }
45
+ } else {
46
+ mcpConfig = defaultMcpConfig
47
+ }
48
+
49
+ await writeFile(mcpConfigPath, `${JSON.stringify(mcpConfig, null, 2)}\n`)
50
+
51
+ console.log(`Updated ${mcpConfigPath}`)
52
+ }
53
+
54
+ if (await exists(`${cwd}/.cursor/rules/instructions.mdc`)) {
55
+ const cursorMcpConfigPath = `${cwd}/.cursor/mcp.json`
56
+ await handleMcpConfigOverride(cursorMcpConfigPath)
57
+ }
58
+
59
+ if (await exists(`${cwd}/CLAUDE.md`)) {
60
+ await $`mkdir -p ${cwd}/.cursor`
61
+ const claudeCodeMcpConfigPath = `${cwd}/.mcp.json`
62
+ await handleMcpConfigOverride(claudeCodeMcpConfigPath)
63
+ }
@@ -20,7 +20,7 @@ let takeScreenshotConfig = null
20
20
  try {
21
21
  if (values['take-screenshot']) {
22
22
  takeScreenshotConfig = JSON.parse(values['take-screenshot'])
23
- if (!takeScreenshotConfig.path) takeScreenshotConfig.path = `${cwd}/screenshot.png`
23
+ if (!takeScreenshotConfig.path) takeScreenshotConfig.path = `${cwd}/screenshot.jpg`
24
24
  if (!takeScreenshotConfig.width) takeScreenshotConfig.width = 1280
25
25
  if (!takeScreenshotConfig.height) takeScreenshotConfig.height = 768
26
26
  if (!takeScreenshotConfig.delay) takeScreenshotConfig.delay = 1000
@@ -45,7 +45,14 @@ const previewUrl = previewUrlMap[stage]
45
45
  if (!previewUrl) throw new Error(`Invalid BRICKS_STAGE: ${stage}`)
46
46
 
47
47
  app.on('ready', () => {
48
- const mainWindow = new BrowserWindow({ width: 1280, height: 768 })
48
+ let show = true
49
+ if (takeScreenshotConfig && !takeScreenshotConfig.noHeadless) show = false
50
+ const mainWindow = new BrowserWindow({
51
+ width: takeScreenshotConfig?.width || 1280,
52
+ height: takeScreenshotConfig?.height || 768,
53
+ frame: !takeScreenshotConfig,
54
+ show,
55
+ })
49
56
  mainWindow.setBackgroundColor('#333')
50
57
  mainWindow.loadURL(previewUrl)
51
58
 
@@ -54,18 +61,19 @@ app.on('ready', () => {
54
61
  type: 'config',
55
62
  configFile: { _originTitle: 'Test', ...config, title: Math.random().toString() },
56
63
  workspace: { billing: { lock: {}, plan: 'free' } },
64
+ showMenu: false,
57
65
  }
58
66
  mainWindow.webContents.executeJavaScript(
59
67
  `window.postMessage(JSON.stringify(${JSON.stringify(payload)}))`,
60
68
  )
61
69
  if (takeScreenshotConfig) {
62
- const { delay, width, height, path, closeAfter } = takeScreenshotConfig
70
+ const { delay, width, height, path, keepOpen = false } = takeScreenshotConfig
63
71
  setTimeout(() => {
64
72
  console.log('Taking screenshot')
65
- mainWindow.webContents.capturePage({ width, height }).then((image) => {
73
+ mainWindow.webContents.capturePage().then((image) => {
66
74
  console.log('Writing screenshot to', path)
67
- writeFile(path, image.toPNG())
68
- if (closeAfter) {
75
+ writeFile(path, image.resize({ width, height }).toJPEG(75))
76
+ if (!keepOpen) {
69
77
  console.log('Closing app')
70
78
  app.quit()
71
79
  }
package/tools/preview.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { $ } from 'bun'
2
2
  import { watch } from 'fs'
3
+ import type { FSWatcher } from 'fs'
3
4
  import { parseArgs } from 'util'
4
5
  import { debounce } from 'lodash'
5
6
 
@@ -8,52 +9,60 @@ const { values } = parseArgs({
8
9
  options: {
9
10
  'skip-typecheck': { type: 'boolean' },
10
11
  'clear-cache': { type: 'boolean' },
12
+ screenshot: { type: 'boolean' },
11
13
  'screenshot-delay': { type: 'string' },
12
14
  'screenshot-width': { type: 'string' },
13
15
  'screenshot-height': { type: 'string' },
14
16
  'screenshot-path': { type: 'string' },
15
- 'screenshot-close-after': { type: 'boolean' },
17
+ 'screenshot-keep-open': { type: 'boolean' },
18
+ 'screenshot-no-headless': { type: 'boolean' },
16
19
  },
17
20
  strict: true,
18
21
  allowPositionals: true,
19
22
  })
20
23
 
21
- const useTypecheck = !values['skip-typecheck']
22
-
23
- const compile = async () => {
24
- if (useTypecheck) await $`bun typecheck`
25
- await $`bun compile`
26
- }
27
-
28
- await compile()
29
-
30
- const compileDebounced = debounce(compile, 500)
31
-
32
24
  const cwd = process.cwd()
33
25
 
34
- const watcher = watch(`${cwd}/subspaces`, { recursive: true }, async (event, filename) => {
35
- console.log(`Detected ${event} in ${filename}`)
36
- compileDebounced()
37
- })
38
-
39
26
  const app = await Bun.file(`${cwd}/application.json`).json()
40
27
 
41
28
  let args: string[] = []
42
29
  if (values['clear-cache']) args.push('--clear-cache')
43
30
 
44
- if (values['screenshot-delay'] || values['screenshot-close-after']) {
31
+ let needWatcher = true
32
+ if (values['screenshot']) {
45
33
  args.push(`--take-screenshot`)
34
+ const keepOpen = values['screenshot-keep-open'] ?? false
46
35
  args.push(
47
36
  JSON.stringify({
48
- delay: Number(values['take-screenshot-delay']) || 1000,
49
- width: Number(values['screenshot-width']) || 1920,
50
- height: Number(values['screenshot-height']) || 1080,
51
- path: values['screenshot-path'] || `${cwd}/screenshot.png`,
52
- closeAfter: values['take-screenshot-close-after'] ?? true,
37
+ delay: Number(values['screenshot-delay']) || 1000,
38
+ width: Number(values['screenshot-width']) || 600,
39
+ height: Number(values['screenshot-height']) || 480,
40
+ path: values['screenshot-path'] || `${cwd}/screenshot.jpg`,
41
+ keepOpen,
42
+ noHeadless: values['screenshot-no-headless'] ?? false,
53
43
  }),
54
44
  )
45
+ needWatcher = keepOpen
46
+ }
47
+
48
+ const useTypecheck = !values['skip-typecheck']
49
+
50
+ const compile = async () => {
51
+ if (useTypecheck) await $`bun typecheck`
52
+ await $`bun compile`
53
+ }
54
+
55
+ await compile()
56
+
57
+ let watcher: FSWatcher | null = null
58
+ if (needWatcher) {
59
+ const compileDebounced = debounce(compile, 500)
60
+ watcher = watch(`${cwd}/subspaces`, { recursive: true }, async (event, filename) => {
61
+ console.log(`Detected ${event} in ${filename}`)
62
+ compileDebounced()
63
+ })
55
64
  }
56
65
 
57
66
  await $`BRICKS_STAGE=${app.stage || 'production'} bunx --bun electron ${__dirname}/preview-main.mjs ${args}`
58
67
 
59
- watcher.close()
68
+ if (watcher) watcher.close()
package/types/bricks.ts CHANGED
@@ -1227,6 +1227,8 @@ Default property:
1227
1227
  }
1228
1228
  >
1229
1229
  | DataLink
1230
+ /* Multiple slideshow media path lists to combine (Array of path arrays) */
1231
+ pathsList?: Array<Array<any> | DataLink | DataLink> | DataLink
1230
1232
  /* Loop the slideshow */
1231
1233
  loop?: boolean | DataLink
1232
1234
  /* Shuffle the slideshow */
@@ -1868,7 +1870,7 @@ Default property:
1868
1870
  verticalMaxQuantity?: number | DataLink
1869
1871
  /* Resize mode */
1870
1872
  resizeMode?: 'auto' | 'fix' | DataLink
1871
- /* Align Content */
1873
+ /* Justify Content */
1872
1874
  justifyContent?: 'start' | 'end' | 'center' | 'space-between' | 'space-around' | DataLink
1873
1875
  /* Align Content */
1874
1876
  alignContent?:
package/types/canvas.ts CHANGED
@@ -14,7 +14,7 @@ interface CanvasDef {
14
14
  showingTimeout?: number | DataLink
15
15
  /* Canvas ID for change next canvas on showing timeout */
16
16
  nextCanvasId?: string | DataLink | (() => Canvas)
17
- /* Canvas's background color */
17
+ /* Background color of Canvas */
18
18
  backgroundColor?: string | DataLink
19
19
  /* Dismiss keyboard on press */
20
20
  dismissKeyboardOnPress?: boolean | DataLink