@fugood/bricks-project 2.21.0 → 2.21.2
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/action-name-map.ts +64 -0
- package/compile/index.ts +14 -2
- package/index.ts +1 -0
- package/package.json +3 -3
- package/tools/mcp-server.ts +86 -0
- package/tools/postinstall.ts +54 -2
- package/tools/preview-main.mjs +40 -2
- package/tools/preview.ts +44 -23
- package/types/bricks.ts +136 -746
- package/types/common.ts +5 -6
- package/types/generators.ts +1067 -1684
- package/types/system.ts +169 -70
- package/utils/event-props.ts +823 -0
|
@@ -62,6 +62,26 @@ export const templateActionNameMap = {
|
|
|
62
62
|
height: 'TAKE_SCREENSHOT_HEIGHT',
|
|
63
63
|
saveProperty: 'TAKE_SCREENSHOT_SAVE_PROPERTY',
|
|
64
64
|
},
|
|
65
|
+
STORAGE_SET: {
|
|
66
|
+
storageType: 'STORAGE_TYPE',
|
|
67
|
+
storageScope: 'STORAGE_SCOPE',
|
|
68
|
+
storageKey: 'STORAGE_KEY',
|
|
69
|
+
storageValue: 'STORAGE_VALUE',
|
|
70
|
+
},
|
|
71
|
+
STORAGE_RETRIEVE: {
|
|
72
|
+
storageType: 'STORAGE_TYPE',
|
|
73
|
+
storageScope: 'STORAGE_SCOPE',
|
|
74
|
+
storageKey: 'STORAGE_KEY',
|
|
75
|
+
result: 'STORAGE_RETRIEVE_RESULT',
|
|
76
|
+
defaultValue: 'STORAGE_RETRIEVE_DEFAULT_VALUE',
|
|
77
|
+
skipIfNotFound: 'STORAGE_RETRIEVE_SKIP_IF_NOT_FOUND',
|
|
78
|
+
},
|
|
79
|
+
STORAGE_DELETE: {
|
|
80
|
+
storageType: 'STORAGE_TYPE',
|
|
81
|
+
storageScope: 'STORAGE_SCOPE',
|
|
82
|
+
storageKey: 'STORAGE_KEY',
|
|
83
|
+
all: 'STORAGE_DELETE_ALL',
|
|
84
|
+
},
|
|
65
85
|
CHANNEL_SUBSCRIBE: {
|
|
66
86
|
key: 'CHANNEL_SUBSCRIBE_KEY',
|
|
67
87
|
type: 'CHANNEL_SUBSCRIBE_TYPE',
|
|
@@ -492,6 +512,28 @@ export const templateActionNameMap = {
|
|
|
492
512
|
paramsString: 'GENERATOR_SQLITE_PARAMS_STRING',
|
|
493
513
|
},
|
|
494
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
|
+
},
|
|
495
537
|
GENERATOR_TTS: {
|
|
496
538
|
GENERATOR_TTS_GENERATE: {
|
|
497
539
|
text: 'GENERATOR_TTS_TEXT',
|
|
@@ -595,6 +637,12 @@ export const templateActionNameMap = {
|
|
|
595
637
|
sessionCustomKey: 'GENERATOR_LLM_SESSION_CUSTOM_KEY',
|
|
596
638
|
},
|
|
597
639
|
},
|
|
640
|
+
GENERATOR_QNN_LLM: {
|
|
641
|
+
GENERATOR_QNN_LLM_GENERATE: {
|
|
642
|
+
prompt: 'GENERATOR_QNN_LLM_PROMPT',
|
|
643
|
+
messages: 'GENERATOR_QNN_LLM_MESSAGES',
|
|
644
|
+
},
|
|
645
|
+
},
|
|
598
646
|
GENERATOR_OPENAI_LLM: {
|
|
599
647
|
GENERATOR_OPENAI_LLM_COMPLETION: {
|
|
600
648
|
messages: 'GENERATOR_OPENAI_LLM_MESSAGES',
|
|
@@ -610,6 +658,11 @@ export const templateActionNameMap = {
|
|
|
610
658
|
responseFormat: 'GENERATOR_OPENAI_LLM_RESPONSE_FORMAT',
|
|
611
659
|
},
|
|
612
660
|
},
|
|
661
|
+
GENERATOR_OPENAI_TTS: {
|
|
662
|
+
GENERATOR_OPENAI_TTS_GENERATE: {
|
|
663
|
+
text: 'GENERATOR_OPENAI_TTS_TEXT',
|
|
664
|
+
},
|
|
665
|
+
},
|
|
613
666
|
GENERATOR_ASSISTANT: {
|
|
614
667
|
GENERATOR_ASSISTANT_ADD_MESSAGE: {
|
|
615
668
|
role: 'GENERATOR_ASSISTANT_ROLE',
|
|
@@ -659,6 +712,17 @@ export const templateActionNameMap = {
|
|
|
659
712
|
GENERATOR_ASSISTANT_REMOVE_MESSAGE_AT_INDEX: {
|
|
660
713
|
index: 'GENERATOR_ASSISTANT_INDEX',
|
|
661
714
|
},
|
|
715
|
+
GENERATOR_ASSISTANT_SUBMIT: {
|
|
716
|
+
continueOnToolCallConfirm: 'GENERATOR_ASSISTANT_CONTINUE_ON_TOOL_CALL_CONFIRM',
|
|
717
|
+
continueOnToolCallStrategy: 'GENERATOR_ASSISTANT_CONTINUE_ON_TOOL_CALL_STRATEGY',
|
|
718
|
+
continueOnToolCallLimit: 'GENERATOR_ASSISTANT_CONTINUE_ON_TOOL_CALL_LIMIT',
|
|
719
|
+
},
|
|
720
|
+
GENERATOR_ASSISTANT_INSERT_MCP_RESOURCE: {
|
|
721
|
+
mcpClientName: 'GENERATOR_ASSISTANT_MCP_CLIENT_NAME',
|
|
722
|
+
mcpResourceUri: 'GENERATOR_ASSISTANT_MCP_RESOURCE_URI',
|
|
723
|
+
mcpVariables: 'GENERATOR_ASSISTANT_MCP_VARIABLES',
|
|
724
|
+
role: 'GENERATOR_ASSISTANT_ROLE',
|
|
725
|
+
},
|
|
662
726
|
},
|
|
663
727
|
GENERATOR_VECTOR_STORE: {
|
|
664
728
|
GENERATOR_VECTOR_STORE_RESET: {
|
package/compile/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { ExportNamedDeclaration, FunctionDeclaration } from 'acorn'
|
|
|
4
4
|
import escodegen from 'escodegen'
|
|
5
5
|
import { generateCalulationMap } from './util'
|
|
6
6
|
import { templateActionNameMap } from './action-name-map'
|
|
7
|
+
import { templateEventPropsMap } from '../utils/event-props'
|
|
7
8
|
import type {
|
|
8
9
|
Application,
|
|
9
10
|
Data,
|
|
@@ -52,6 +53,17 @@ const compileProperty = (property, errorReference: string, result = {}) => {
|
|
|
52
53
|
return property
|
|
53
54
|
}
|
|
54
55
|
|
|
56
|
+
const compileEventActionValue = (templateKey, eventKey, value, errorReference) => {
|
|
57
|
+
const tmplEventProperties = templateEventPropsMap[templateKey]
|
|
58
|
+
const props = tmplEventProperties?.[eventKey]
|
|
59
|
+
if (!props) return compileProperty(value, errorReference)
|
|
60
|
+
if (props.includes(value)) return value
|
|
61
|
+
if (value?.startsWith(templateKey)) {
|
|
62
|
+
console.warn(`[Warning] Value start with template key but there is no event property: ${value} ${errorReference}`)
|
|
63
|
+
}
|
|
64
|
+
return compileProperty(value, errorReference)
|
|
65
|
+
}
|
|
66
|
+
|
|
55
67
|
const convertOutletKey = (templateKey: string, key: string) => {
|
|
56
68
|
return `${templateKey}_${_.snakeCase(key).toUpperCase()}`
|
|
57
69
|
}
|
|
@@ -128,7 +140,7 @@ const compileEvents = (
|
|
|
128
140
|
? compileActionParam(handlerTemplateKey, action.__actionName, input)
|
|
129
141
|
: input,
|
|
130
142
|
[camelCase ? 'resultFromSender' : 'result_from_sender']:
|
|
131
|
-
mapping ||
|
|
143
|
+
mapping || compileEventActionValue(handlerTemplateKey, key, value, errorReference),
|
|
132
144
|
}
|
|
133
145
|
if (mapping) param[camelCase ? 'resultDataMapping' : 'result_data_mapping'] = true
|
|
134
146
|
parameterList.push(param)
|
|
@@ -140,7 +152,7 @@ const compileEvents = (
|
|
|
140
152
|
const param = {
|
|
141
153
|
[camelCase ? 'inputToReceiver' : 'input_to_receiver']: input().id,
|
|
142
154
|
[camelCase ? 'resultFromSender' : 'result_from_sender']:
|
|
143
|
-
mapping ||
|
|
155
|
+
mapping || compileEventActionValue(handlerTemplateKey, key, value, errorReference),
|
|
144
156
|
}
|
|
145
157
|
if (mapping) param[camelCase ? 'resultDataMapping' : 'result_data_mapping'] = true
|
|
146
158
|
parameterList.push(param)
|
package/index.ts
CHANGED
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fugood/bricks-project",
|
|
3
|
-
"version": "2.21.
|
|
3
|
+
"version": "2.21.2",
|
|
4
4
|
"main": "index.ts",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"build": "node scripts/build.js"
|
|
7
7
|
},
|
|
8
8
|
"dependencies": {
|
|
9
|
+
"@modelcontextprotocol/sdk": "^1.7.0",
|
|
9
10
|
"@types/escodegen": "^0.0.10",
|
|
10
11
|
"@types/lodash": "^4.17.12",
|
|
11
12
|
"acorn": "^8.13.0",
|
|
12
13
|
"escodegen": "^2.1.0",
|
|
13
14
|
"lodash": "^4.17.4",
|
|
14
15
|
"uuid": "^8.3.1"
|
|
15
|
-
}
|
|
16
|
-
"gitHead": "7198652cb0d8217f36d88a755542300321dd2d74"
|
|
16
|
+
}
|
|
17
17
|
}
|
|
@@ -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)
|
package/tools/postinstall.ts
CHANGED
|
@@ -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,56 @@ 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}/.cursorrules`)) {
|
|
55
|
+
await $`mkdir -p ${cwd}/.cursor`
|
|
56
|
+
const cursorMcpConfigPath = `${cwd}/.cursor/mcp.json`
|
|
57
|
+
await handleMcpConfigOverride(cursorMcpConfigPath)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (await exists(`${cwd}/CLAUDE.md`)) {
|
|
61
|
+
await $`mkdir -p ${cwd}/.cursor`
|
|
62
|
+
const claudeCodeMcpConfigPath = `${cwd}/.mcp.json`
|
|
63
|
+
await handleMcpConfigOverride(claudeCodeMcpConfigPath)
|
|
64
|
+
}
|
package/tools/preview-main.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
2
|
import { app, BrowserWindow } from 'electron'
|
|
3
|
-
import { readFile } from 'fs/promises'
|
|
3
|
+
import { readFile, writeFile } from 'fs/promises'
|
|
4
4
|
import { watchFile } from 'fs'
|
|
5
5
|
import { parseArgs } from 'util'
|
|
6
6
|
|
|
@@ -8,6 +8,7 @@ const { values } = parseArgs({
|
|
|
8
8
|
args: process.argv,
|
|
9
9
|
options: {
|
|
10
10
|
'clear-cache': { type: 'boolean' },
|
|
11
|
+
'take-screenshot': { type: 'string' },
|
|
11
12
|
},
|
|
12
13
|
strict: true,
|
|
13
14
|
allowPositionals: true,
|
|
@@ -15,6 +16,21 @@ const { values } = parseArgs({
|
|
|
15
16
|
|
|
16
17
|
const cwd = process.cwd()
|
|
17
18
|
|
|
19
|
+
let takeScreenshotConfig = null
|
|
20
|
+
try {
|
|
21
|
+
if (values['take-screenshot']) {
|
|
22
|
+
takeScreenshotConfig = JSON.parse(values['take-screenshot'])
|
|
23
|
+
if (!takeScreenshotConfig.path) takeScreenshotConfig.path = `${cwd}/screenshot.jpg`
|
|
24
|
+
if (!takeScreenshotConfig.width) takeScreenshotConfig.width = 1280
|
|
25
|
+
if (!takeScreenshotConfig.height) takeScreenshotConfig.height = 768
|
|
26
|
+
if (!takeScreenshotConfig.delay) takeScreenshotConfig.delay = 1000
|
|
27
|
+
}
|
|
28
|
+
} catch (e) {
|
|
29
|
+
console.error('Invalid take-screenshot config', e)
|
|
30
|
+
// eslint-disable-next-line unicorn/no-process-exit
|
|
31
|
+
process.exit(1)
|
|
32
|
+
}
|
|
33
|
+
|
|
18
34
|
let config = JSON.parse(await readFile(`${cwd}/.bricks/build/application-config.json`))
|
|
19
35
|
|
|
20
36
|
const stage = process.env.BRICKS_STAGE || 'production'
|
|
@@ -29,7 +45,14 @@ const previewUrl = previewUrlMap[stage]
|
|
|
29
45
|
if (!previewUrl) throw new Error(`Invalid BRICKS_STAGE: ${stage}`)
|
|
30
46
|
|
|
31
47
|
app.on('ready', () => {
|
|
32
|
-
|
|
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
|
+
})
|
|
33
56
|
mainWindow.setBackgroundColor('#333')
|
|
34
57
|
mainWindow.loadURL(previewUrl)
|
|
35
58
|
|
|
@@ -38,10 +61,25 @@ app.on('ready', () => {
|
|
|
38
61
|
type: 'config',
|
|
39
62
|
configFile: { _originTitle: 'Test', ...config, title: Math.random().toString() },
|
|
40
63
|
workspace: { billing: { lock: {}, plan: 'free' } },
|
|
64
|
+
showMenu: false,
|
|
41
65
|
}
|
|
42
66
|
mainWindow.webContents.executeJavaScript(
|
|
43
67
|
`window.postMessage(JSON.stringify(${JSON.stringify(payload)}))`,
|
|
44
68
|
)
|
|
69
|
+
if (takeScreenshotConfig) {
|
|
70
|
+
const { delay, width, height, path, keepOpen = false } = takeScreenshotConfig
|
|
71
|
+
setTimeout(() => {
|
|
72
|
+
console.log('Taking screenshot')
|
|
73
|
+
mainWindow.webContents.capturePage().then((image) => {
|
|
74
|
+
console.log('Writing screenshot to', path)
|
|
75
|
+
writeFile(path, image.resize({ width, height }).toJPEG(75))
|
|
76
|
+
if (!keepOpen) {
|
|
77
|
+
console.log('Closing app')
|
|
78
|
+
app.quit()
|
|
79
|
+
}
|
|
80
|
+
})
|
|
81
|
+
}, delay)
|
|
82
|
+
}
|
|
45
83
|
}
|
|
46
84
|
|
|
47
85
|
mainWindow.webContents.once('dom-ready', sendConfig)
|
package/tools/preview.ts
CHANGED
|
@@ -1,22 +1,50 @@
|
|
|
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
|
|
|
6
7
|
const { values } = parseArgs({
|
|
7
8
|
args: Bun.argv,
|
|
8
9
|
options: {
|
|
9
|
-
'skip-typecheck': {
|
|
10
|
-
|
|
11
|
-
},
|
|
12
|
-
'
|
|
13
|
-
|
|
14
|
-
},
|
|
10
|
+
'skip-typecheck': { type: 'boolean' },
|
|
11
|
+
'clear-cache': { type: 'boolean' },
|
|
12
|
+
screenshot: { type: 'boolean' },
|
|
13
|
+
'screenshot-delay': { type: 'string' },
|
|
14
|
+
'screenshot-width': { type: 'string' },
|
|
15
|
+
'screenshot-height': { type: 'string' },
|
|
16
|
+
'screenshot-path': { type: 'string' },
|
|
17
|
+
'screenshot-keep-open': { type: 'boolean' },
|
|
18
|
+
'screenshot-no-headless': { type: 'boolean' },
|
|
15
19
|
},
|
|
16
20
|
strict: true,
|
|
17
21
|
allowPositionals: true,
|
|
18
22
|
})
|
|
19
23
|
|
|
24
|
+
const cwd = process.cwd()
|
|
25
|
+
|
|
26
|
+
const app = await Bun.file(`${cwd}/application.json`).json()
|
|
27
|
+
|
|
28
|
+
let args: string[] = []
|
|
29
|
+
if (values['clear-cache']) args.push('--clear-cache')
|
|
30
|
+
|
|
31
|
+
let needWatcher = true
|
|
32
|
+
if (values['screenshot']) {
|
|
33
|
+
args.push(`--take-screenshot`)
|
|
34
|
+
const keepOpen = values['screenshot-keep-open'] ?? false
|
|
35
|
+
args.push(
|
|
36
|
+
JSON.stringify({
|
|
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,
|
|
43
|
+
}),
|
|
44
|
+
)
|
|
45
|
+
needWatcher = keepOpen
|
|
46
|
+
}
|
|
47
|
+
|
|
20
48
|
const useTypecheck = !values['skip-typecheck']
|
|
21
49
|
|
|
22
50
|
const compile = async () => {
|
|
@@ -26,22 +54,15 @@ const compile = async () => {
|
|
|
26
54
|
|
|
27
55
|
await compile()
|
|
28
56
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
const app = await Bun.file(`${cwd}/application.json`).json()
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (values['clear-cache']) {
|
|
42
|
-
await $`BRICKS_STAGE=${app.stage || 'production'} bunx --bun electron ${__dirname}/preview-main.mjs --clear-cache`
|
|
43
|
-
} else {
|
|
44
|
-
await $`BRICKS_STAGE=${app.stage || 'production'} bunx --bun electron ${__dirname}/preview-main.mjs`
|
|
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
|
+
})
|
|
45
64
|
}
|
|
46
65
|
|
|
47
|
-
|
|
66
|
+
await $`BRICKS_STAGE=${app.stage || 'production'} bunx --bun electron ${__dirname}/preview-main.mjs ${args}`
|
|
67
|
+
|
|
68
|
+
if (watcher) watcher.close()
|