@fugood/bricks-ctor 2.25.0-beta.60 → 2.25.0-beta.62

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.
Files changed (192) hide show
  1. package/package.json +4 -28
  2. package/tools/__tests__/legacy-forwarder.test.js +91 -0
  3. package/tools/_forward.ts +26 -0
  4. package/tools/deploy.ts +3 -175
  5. package/tools/mcp-server.ts +3 -35
  6. package/tools/postinstall.ts +3 -291
  7. package/tools/pull.ts +3 -198
  8. package/tools/push-config.ts +3 -113
  9. package/tools/simulator.ts +3 -149
  10. package/compile/__tests__/config-diff.test.js +0 -100
  11. package/compile/__tests__/index.test.js +0 -461
  12. package/compile/__tests__/util.test.js +0 -450
  13. package/compile/action-name-map.ts +0 -1079
  14. package/compile/config-diff.ts +0 -155
  15. package/compile/index.ts +0 -1594
  16. package/compile/util.ts +0 -482
  17. package/index.ts +0 -6
  18. package/skills/bricks-ctor/SKILL.md +0 -38
  19. package/skills/bricks-ctor/references/animation.md +0 -160
  20. package/skills/bricks-ctor/references/architecture-patterns.md +0 -88
  21. package/skills/bricks-ctor/references/automations.md +0 -232
  22. package/skills/bricks-ctor/references/buttress.md +0 -245
  23. package/skills/bricks-ctor/references/data-calculation.md +0 -252
  24. package/skills/bricks-ctor/references/local-sync.md +0 -129
  25. package/skills/bricks-ctor/references/media-flow.md +0 -165
  26. package/skills/bricks-ctor/references/remote-data-bank.md +0 -196
  27. package/skills/bricks-ctor/references/simulator.md +0 -132
  28. package/skills/bricks-ctor/references/source-editing-tools.md +0 -81
  29. package/skills/bricks-ctor/references/standby-transition.md +0 -124
  30. package/skills/bricks-ctor/references/verification-toolchain.md +0 -200
  31. package/skills/bricks-design/SKILL.md +0 -171
  32. package/skills/bricks-design/references/architecture-truths.md +0 -132
  33. package/skills/bricks-design/references/avoiding-complexity.md +0 -91
  34. package/skills/bricks-design/references/design-critique.md +0 -195
  35. package/skills/bricks-design/references/design-languages.md +0 -265
  36. package/skills/bricks-design/references/performance.md +0 -116
  37. package/skills/bricks-design/references/presentation-and-slideshow.md +0 -137
  38. package/skills/bricks-design/references/translating-inputs.md +0 -152
  39. package/skills/bricks-design/references/variations-and-tweaks.md +0 -124
  40. package/skills/bricks-design/references/when-the-brief-is-branded.md +0 -284
  41. package/skills/bricks-design/references/when-the-brief-is-vague.md +0 -85
  42. package/skills/bricks-design/references/workflow.md +0 -134
  43. package/skills/bricks-ux/SKILL.md +0 -114
  44. package/skills/bricks-ux/references/accessibility.md +0 -162
  45. package/skills/bricks-ux/references/flow-states.md +0 -175
  46. package/skills/bricks-ux/references/interaction-archetypes.md +0 -189
  47. package/skills/bricks-ux/references/monitoring-screens.md +0 -153
  48. package/skills/bricks-ux/references/pressable-composition.md +0 -126
  49. package/skills/bricks-ux/references/user-journey.md +0 -168
  50. package/skills/bricks-ux/references/ux-critique.md +0 -256
  51. package/skills/rive-marketplace/SKILL.md +0 -99
  52. package/tools/__tests__/_cli-error.test.ts +0 -35
  53. package/tools/__tests__/_mcp-config.test.ts +0 -67
  54. package/tools/__tests__/pull.test.ts +0 -108
  55. package/tools/_cli-error.ts +0 -17
  56. package/tools/_edits-log.ts +0 -41
  57. package/tools/_git-author.ts +0 -37
  58. package/tools/_last-pushed-commit.ts +0 -28
  59. package/tools/_mcp-config.ts +0 -42
  60. package/tools/_shell.ts +0 -180
  61. package/tools/icons/.gitattributes +0 -1
  62. package/tools/icons/fa6pro-glyphmap.json +0 -4686
  63. package/tools/icons/fa6pro-meta.json +0 -1
  64. package/tools/mcp-env.ts +0 -13
  65. package/tools/mcp-tools/__tests__/data-calc-editing.test.js +0 -516
  66. package/tools/mcp-tools/__tests__/entry-editing.test.js +0 -866
  67. package/tools/mcp-tools/__tests__/huggingface.test.ts +0 -49
  68. package/tools/mcp-tools/__tests__/icons.test.ts +0 -21
  69. package/tools/mcp-tools/__tests__/mcp-env.test.js +0 -19
  70. package/tools/mcp-tools/_editing-helpers.ts +0 -98
  71. package/tools/mcp-tools/_verify.ts +0 -50
  72. package/tools/mcp-tools/compile.ts +0 -104
  73. package/tools/mcp-tools/data-calc-editing.ts +0 -1311
  74. package/tools/mcp-tools/entry-editing.ts +0 -2297
  75. package/tools/mcp-tools/huggingface.ts +0 -772
  76. package/tools/mcp-tools/icons.ts +0 -97
  77. package/tools/mcp-tools/lottie.ts +0 -102
  78. package/tools/mcp-tools/media.ts +0 -113
  79. package/tools/simulator-main.mjs +0 -488
  80. package/tools/simulator-preload.cjs +0 -16
  81. package/types/animation.d.ts +0 -116
  82. package/types/automation.d.ts +0 -231
  83. package/types/brick-base.d.ts +0 -80
  84. package/types/bricks/Camera.d.ts +0 -246
  85. package/types/bricks/Chart.d.ts +0 -372
  86. package/types/bricks/GenerativeMedia.d.ts +0 -290
  87. package/types/bricks/Icon.d.ts +0 -98
  88. package/types/bricks/Image.d.ts +0 -126
  89. package/types/bricks/Items.d.ts +0 -480
  90. package/types/bricks/Lottie.d.ts +0 -168
  91. package/types/bricks/Maps.d.ts +0 -262
  92. package/types/bricks/QrCode.d.ts +0 -117
  93. package/types/bricks/Rect.d.ts +0 -150
  94. package/types/bricks/RichText.d.ts +0 -131
  95. package/types/bricks/Rive.d.ts +0 -220
  96. package/types/bricks/Scene3D.d.ts +0 -676
  97. package/types/bricks/Sketch.d.ts +0 -256
  98. package/types/bricks/Slideshow.d.ts +0 -201
  99. package/types/bricks/Svg.d.ts +0 -99
  100. package/types/bricks/Text.d.ts +0 -148
  101. package/types/bricks/TextInput.d.ts +0 -242
  102. package/types/bricks/Video.d.ts +0 -242
  103. package/types/bricks/VideoStreaming.d.ts +0 -112
  104. package/types/bricks/WebRtcStream.d.ts +0 -65
  105. package/types/bricks/WebView.d.ts +0 -168
  106. package/types/bricks/index.d.ts +0 -23
  107. package/types/canvas.d.ts +0 -82
  108. package/types/common.d.ts +0 -141
  109. package/types/data-calc-command/base.d.ts +0 -57
  110. package/types/data-calc-command/collection.d.ts +0 -418
  111. package/types/data-calc-command/color.d.ts +0 -432
  112. package/types/data-calc-command/constant.d.ts +0 -50
  113. package/types/data-calc-command/datetime.d.ts +0 -147
  114. package/types/data-calc-command/file.d.ts +0 -129
  115. package/types/data-calc-command/index.d.ts +0 -13
  116. package/types/data-calc-command/iteratee.d.ts +0 -23
  117. package/types/data-calc-command/logictype.d.ts +0 -190
  118. package/types/data-calc-command/math.d.ts +0 -275
  119. package/types/data-calc-command/object.d.ts +0 -119
  120. package/types/data-calc-command/sandbox.d.ts +0 -66
  121. package/types/data-calc-command/string.d.ts +0 -407
  122. package/types/data-calc-script.d.ts +0 -21
  123. package/types/data-calc.d.ts +0 -12
  124. package/types/data.d.ts +0 -97
  125. package/types/generators/AlarmClock.d.ts +0 -110
  126. package/types/generators/Assistant.d.ts +0 -640
  127. package/types/generators/BleCentral.d.ts +0 -247
  128. package/types/generators/BlePeripheral.d.ts +0 -208
  129. package/types/generators/CanvasMap.d.ts +0 -74
  130. package/types/generators/CastlesPay.d.ts +0 -87
  131. package/types/generators/DataBank.d.ts +0 -160
  132. package/types/generators/File.d.ts +0 -432
  133. package/types/generators/GraphQl.d.ts +0 -132
  134. package/types/generators/Http.d.ts +0 -222
  135. package/types/generators/HttpServer.d.ts +0 -230
  136. package/types/generators/Information.d.ts +0 -103
  137. package/types/generators/Intent.d.ts +0 -168
  138. package/types/generators/Iterator.d.ts +0 -108
  139. package/types/generators/Keyboard.d.ts +0 -105
  140. package/types/generators/LlmAnthropicCompat.d.ts +0 -212
  141. package/types/generators/LlmAppleBuiltin.d.ts +0 -159
  142. package/types/generators/LlmGgml.d.ts +0 -903
  143. package/types/generators/LlmMediaTekNeuroPilot.d.ts +0 -235
  144. package/types/generators/LlmMlx.d.ts +0 -228
  145. package/types/generators/LlmOnnx.d.ts +0 -213
  146. package/types/generators/LlmOpenAiCompat.d.ts +0 -312
  147. package/types/generators/LlmQualcommAiEngine.d.ts +0 -247
  148. package/types/generators/Mcp.d.ts +0 -637
  149. package/types/generators/McpServer.d.ts +0 -289
  150. package/types/generators/MediaFlow.d.ts +0 -170
  151. package/types/generators/MqttBroker.d.ts +0 -141
  152. package/types/generators/MqttClient.d.ts +0 -141
  153. package/types/generators/Question.d.ts +0 -408
  154. package/types/generators/RealtimeTranscription.d.ts +0 -287
  155. package/types/generators/RerankerGgml.d.ts +0 -195
  156. package/types/generators/SerialPort.d.ts +0 -151
  157. package/types/generators/SoundPlayer.d.ts +0 -94
  158. package/types/generators/SoundRecorder.d.ts +0 -139
  159. package/types/generators/SpeechToTextGgml.d.ts +0 -424
  160. package/types/generators/SpeechToTextOnnx.d.ts +0 -236
  161. package/types/generators/SpeechToTextPlatform.d.ts +0 -85
  162. package/types/generators/SqLite.d.ts +0 -159
  163. package/types/generators/Step.d.ts +0 -107
  164. package/types/generators/SttAppleBuiltin.d.ts +0 -153
  165. package/types/generators/Tcp.d.ts +0 -126
  166. package/types/generators/TcpServer.d.ts +0 -147
  167. package/types/generators/TextToSpeechAppleBuiltin.d.ts +0 -127
  168. package/types/generators/TextToSpeechGgml.d.ts +0 -221
  169. package/types/generators/TextToSpeechOnnx.d.ts +0 -178
  170. package/types/generators/TextToSpeechOpenAiLike.d.ts +0 -121
  171. package/types/generators/ThermalPrinter.d.ts +0 -193
  172. package/types/generators/Tick.d.ts +0 -83
  173. package/types/generators/Udp.d.ts +0 -120
  174. package/types/generators/VadGgml.d.ts +0 -260
  175. package/types/generators/VadOnnx.d.ts +0 -231
  176. package/types/generators/VadTraditional.d.ts +0 -138
  177. package/types/generators/VectorStore.d.ts +0 -257
  178. package/types/generators/Watchdog.d.ts +0 -107
  179. package/types/generators/WebCrawler.d.ts +0 -103
  180. package/types/generators/WebRtc.d.ts +0 -181
  181. package/types/generators/WebSocket.d.ts +0 -148
  182. package/types/generators/index.d.ts +0 -57
  183. package/types/index.d.ts +0 -13
  184. package/types/subspace.d.ts +0 -60
  185. package/types/switch.d.ts +0 -51
  186. package/types/system.d.ts +0 -707
  187. package/utils/__tests__/calc.test.js +0 -25
  188. package/utils/__tests__/id.test.js +0 -154
  189. package/utils/calc.ts +0 -130
  190. package/utils/data.ts +0 -495
  191. package/utils/event-props.ts +0 -912
  192. package/utils/id.ts +0 -133
package/package.json CHANGED
@@ -1,33 +1,9 @@
1
1
  {
2
2
  "name": "@fugood/bricks-ctor",
3
- "version": "2.25.0-beta.60",
4
- "main": "index.ts",
5
- "scripts": {
6
- "typecheck": "tsc --noEmit",
7
- "build": "bun scripts/build.js"
8
- },
3
+ "version": "2.25.0-beta.62",
4
+ "description": "Deprecated: ctor tooling moved to the `bricks ctor` commands in @fugood/bricks-cli. This package now only forwards legacy project scripts and triggers migration.",
9
5
  "dependencies": {
10
- "@babel/generator": "7.28.5",
11
- "@babel/parser": "7.28.5",
12
- "@babel/traverse": "7.28.5",
13
- "@babel/types": "7.28.5",
14
- "@fugood/bricks-cli": "^2.25.0-beta.60",
15
- "@huggingface/gguf": "^0.3.2",
16
- "@iarna/toml": "^3.0.0",
17
- "@modelcontextprotocol/sdk": "^1.15.0",
18
- "@toon-format/toon": "^2.1.0",
19
- "@types/bun": "^1.3.9",
20
- "@types/escodegen": "^0.0.10",
21
- "@types/lodash": "^4.17.12",
22
- "acorn": "^8.13.0",
23
- "escodegen": "2.1.0",
24
- "fuse.js": "^7.0.0",
25
- "json5": "^2.0.1",
26
- "lodash": "^4.17.4",
27
- "uuid": "^8.3.1"
28
- },
29
- "peerDependencies": {
30
- "oxfmt": "^0.36.0"
6
+ "@fugood/bricks-cli": "^2.25.0-beta.62"
31
7
  },
32
- "gitHead": "c0dd2ea071f45382808ad55acfc9837217d683ca"
8
+ "gitHead": "22ea0986230856c59dbf9acccc63bdc4fd97deed"
33
9
  }
@@ -0,0 +1,91 @@
1
+ const mockSpawnSync = jest.fn()
2
+ const mockExistsSync = jest.fn()
3
+
4
+ jest.mock('node:child_process', () => ({
5
+ __esModule: true,
6
+ spawnSync: (...args) => mockSpawnSync(...args),
7
+ }))
8
+
9
+ jest.mock('node:fs', () => ({
10
+ __esModule: true,
11
+ existsSync: (...args) => mockExistsSync(...args),
12
+ }))
13
+
14
+ const loadForwarder = () => require('../_forward.ts')
15
+
16
+ describe('legacy bricks-ctor forwarder', () => {
17
+ let exitSpy
18
+ let errorSpy
19
+
20
+ beforeEach(() => {
21
+ jest.resetModules()
22
+ mockSpawnSync.mockReset()
23
+ mockExistsSync.mockReset()
24
+ exitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {})
25
+ errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {})
26
+ })
27
+
28
+ afterEach(() => {
29
+ exitSpy.mockRestore()
30
+ errorSpy.mockRestore()
31
+ })
32
+
33
+ it('prefers the local bricks CLI next to the legacy package', () => {
34
+ mockExistsSync.mockReturnValue(true)
35
+ mockSpawnSync.mockReturnValue({ status: 0 })
36
+ const { forwardLegacyCtorTool } = loadForwarder()
37
+
38
+ forwardLegacyCtorTool(
39
+ 'deploy',
40
+ 'file:///repo/node_modules/@fugood/bricks-ctor/tools/deploy.ts',
41
+ ['--target', 'device'],
42
+ )
43
+
44
+ expect(mockSpawnSync).toHaveBeenCalledWith(
45
+ '/repo/node_modules/.bin/bricks',
46
+ ['ctor', 'deploy', '--target', 'device'],
47
+ { stdio: 'inherit' },
48
+ )
49
+ expect(exitSpy).toHaveBeenCalledWith(0)
50
+ })
51
+
52
+ it('falls back to PATH when the local bricks CLI is missing', () => {
53
+ mockExistsSync.mockReturnValue(false)
54
+ mockSpawnSync.mockReturnValue({ status: 3 })
55
+ const { forwardLegacyCtorTool } = loadForwarder()
56
+
57
+ forwardLegacyCtorTool('pull', 'file:///repo/node_modules/@fugood/bricks-ctor/tools/pull.ts', [])
58
+
59
+ expect(mockSpawnSync).toHaveBeenCalledWith('bricks', ['ctor', 'pull'], { stdio: 'inherit' })
60
+ expect(exitSpy).toHaveBeenCalledWith(3)
61
+ })
62
+
63
+ it('reports spawn errors and exits with failure', () => {
64
+ mockExistsSync.mockReturnValue(false)
65
+ mockSpawnSync.mockReturnValue({ error: new Error('ENOENT') })
66
+ const { forwardLegacyCtorTool } = loadForwarder()
67
+
68
+ forwardLegacyCtorTool(
69
+ 'mcp',
70
+ 'file:///repo/node_modules/@fugood/bricks-ctor/tools/mcp-server.ts',
71
+ [],
72
+ )
73
+
74
+ expect(errorSpy).toHaveBeenCalledWith('bricks-ctor forwarder failed to run `bricks`: ENOENT')
75
+ expect(exitSpy).toHaveBeenCalledWith(1)
76
+ })
77
+
78
+ it('treats a missing child status as failure', () => {
79
+ mockExistsSync.mockReturnValue(false)
80
+ mockSpawnSync.mockReturnValue({})
81
+ const { forwardLegacyCtorTool } = loadForwarder()
82
+
83
+ forwardLegacyCtorTool(
84
+ 'simulator',
85
+ 'file:///repo/node_modules/@fugood/bricks-ctor/tools/simulator.ts',
86
+ [],
87
+ )
88
+
89
+ expect(exitSpy).toHaveBeenCalledWith(1)
90
+ })
91
+ })
@@ -0,0 +1,26 @@
1
+ import { spawnSync } from 'node:child_process'
2
+ import { existsSync } from 'node:fs'
3
+ import { fileURLToPath } from 'node:url'
4
+
5
+ // @fugood/bricks-ctor is deprecated; all tooling now lives in @fugood/bricks-cli.
6
+ // This shared forwarder keeps legacy project scripts working until postinstall migrates them.
7
+ export function resolveLegacyBricksCommand(baseUrl: string) {
8
+ const localBricks = fileURLToPath(new URL('../../../.bin/bricks', baseUrl))
9
+ return existsSync(localBricks) ? localBricks : 'bricks'
10
+ }
11
+
12
+ export function forwardLegacyCtorTool(
13
+ command: string,
14
+ baseUrl: string,
15
+ args = process.argv.slice(2),
16
+ ) {
17
+ const bricks = resolveLegacyBricksCommand(baseUrl)
18
+ const result = spawnSync(bricks, ['ctor', command, ...args], { stdio: 'inherit' })
19
+
20
+ if (result.error) {
21
+ console.error(`bricks-ctor forwarder failed to run \`${bricks}\`: ${result.error.message}`)
22
+ process.exit(1)
23
+ }
24
+
25
+ process.exit(result.status ?? 1)
26
+ }
package/tools/deploy.ts CHANGED
@@ -1,176 +1,4 @@
1
- import { access, readFile, writeFile } from 'node:fs/promises'
2
- import { parseArgs } from 'util'
3
- import { sh } from './_shell'
4
- import { extractCliErrorMessage } from './_cli-error'
5
- import { buildCommitArgs } from './_git-author'
6
- import { writeLastPushedCommit } from './_last-pushed-commit'
1
+ #!/usr/bin/env bun
2
+ import { forwardLegacyCtorTool } from './_forward.ts'
7
3
 
8
- if (!process.env.BRICKS_RELEASE_SIGN) {
9
- process.env.BRICKS_RELEASE_SIGN = 'CTOR'
10
- }
11
-
12
- const cwd = process.cwd()
13
-
14
- const exists = async (p: string) => {
15
- try {
16
- await access(p)
17
- return true
18
- } catch {
19
- return false
20
- }
21
- }
22
-
23
- const readJson = async (p: string) => JSON.parse(await readFile(p, 'utf8'))
24
-
25
- const {
26
- values: {
27
- changelogs: changelogsArg,
28
- 'changelogs-file': changelogsFile,
29
- 'auto-commit': autoCommit,
30
- 'auto-version': autoVersion,
31
- version: versionArg,
32
- yes,
33
- help,
34
- },
35
- } = parseArgs({
36
- args: process.argv.slice(2),
37
- options: {
38
- changelogs: { type: 'string' },
39
- 'changelogs-file': { type: 'string' },
40
- 'auto-commit': { type: 'boolean' },
41
- 'auto-version': { type: 'boolean' },
42
- version: { type: 'string' },
43
- yes: { type: 'boolean', short: 'y' },
44
- help: { type: 'boolean', short: 'h' },
45
- },
46
- allowPositionals: true,
47
- })
48
-
49
- if (help) {
50
- console.log(`Options:
51
- --changelogs <text> Changelogs text for the release
52
- --changelogs-file <path> Read changelogs from a file
53
- --auto-commit Auto-commit unstaged changes before deploying
54
- --auto-version Auto-bump patch version before deploying
55
- --version <version> Set explicit version for the release
56
- -y, --yes Skip all prompts
57
- -h, --help Show this help message`)
58
- process.exit(0)
59
- }
60
-
61
- // Check git status
62
- const { exitCode } = await sh`cd ${cwd} && git status`.quiet().nothrow()
63
- const isGitRepo = exitCode === 0
64
-
65
- if (!isGitRepo && !yes) {
66
- const confirmContinue = prompt('No git repository found, continue? (y/n)')
67
- if (confirmContinue !== 'y') throw new Error('Deployment cancelled')
68
- }
69
-
70
- // Read application.json
71
- const app = await readJson(`${cwd}/application.json`)
72
- const config = await readJson(`${cwd}/.bricks/build/application-config.json`)
73
-
74
- // Resolve version: explicit flag > auto-bump > package.json
75
- const pkgPath = `${cwd}/package.json`
76
- const pkgExists = await exists(pkgPath)
77
- let version: string | undefined
78
-
79
- if (versionArg) {
80
- version = versionArg
81
- if (pkgExists) {
82
- const pkg = await readJson(pkgPath)
83
- pkg.version = version
84
- await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
85
- }
86
- } else if (autoVersion && pkgExists) {
87
- const pkg = await readJson(pkgPath)
88
- const parts = (pkg.version || '0.0.0').split('.')
89
- parts[2] = String(Number(parts[2] || 0) + 1)
90
- version = parts.join('.')
91
- pkg.version = version
92
- await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
93
- } else {
94
- version = pkgExists ? (await readJson(pkgPath)).version : undefined
95
- }
96
-
97
- // Get changelog from flag or file
98
- let changelogs = ''
99
- if (changelogsArg) {
100
- changelogs = changelogsArg
101
- } else if (changelogsFile) {
102
- if (!(await exists(changelogsFile))) {
103
- throw new Error(`Changelogs file not found: ${changelogsFile}`)
104
- }
105
- changelogs = await readFile(changelogsFile, 'utf8')
106
- } else if (!yes) {
107
- changelogs = prompt('Enter changelogs (optional, press Enter to skip):') || ''
108
- }
109
-
110
- // Handle unstaged changes
111
- let commitId = ''
112
- if (isGitRepo) {
113
- const unstagedChanges = await sh`cd ${cwd} && git diff --name-only --diff-filter=ACMR`.text()
114
- if (unstagedChanges) {
115
- if (autoCommit) {
116
- const commitMsg = `chore: release ${version || 'new version'}`
117
- const commitBody = changelogs || '[no changelogs]'
118
- await sh`cd ${cwd} && git add -A`
119
- const commitArgs = await buildCommitArgs(cwd, [commitMsg, commitBody])
120
- await sh`cd ${cwd} && git ${commitArgs}`
121
- } else {
122
- throw new Error(
123
- 'Unstaged changes found, please commit or stash your changes before deploying',
124
- )
125
- }
126
- }
127
- commitId = (await sh`cd ${cwd} && git rev-parse HEAD`.text()).trim()
128
- }
129
-
130
- // Ask for confirmation
131
- if (!yes) {
132
- const confirm = prompt('Are you sure you want to deploy? (y/n)')
133
- if (confirm !== 'y') throw new Error('Deployment cancelled')
134
- }
135
-
136
- const isModule = app.type === 'module'
137
- const command = isModule ? 'module' : 'app'
138
-
139
- // Add project-specific fields to config and write to temp file
140
- const releaseConfig = {
141
- ...config,
142
- title: version || config.title,
143
- bricks_project_last_commit_id: commitId || undefined,
144
- }
145
- const configPath = `${cwd}/.bricks/build/release-config.json`
146
- await writeFile(configPath, JSON.stringify(releaseConfig))
147
-
148
- const args = ['bricks', command, 'release', app.id, '-c', configPath, '--json']
149
-
150
- if (app.name) {
151
- args.push('--name', app.name)
152
- }
153
-
154
- if (version) {
155
- args.push('--version', version)
156
- }
157
-
158
- if (changelogs) {
159
- args.push('--changelogs', changelogs)
160
- }
161
-
162
- const result = await sh`${args}`.quiet().nothrow()
163
-
164
- if (result.exitCode !== 0) {
165
- const output = result.stderr.toString() || result.stdout.toString()
166
- throw new Error(extractCliErrorMessage(output, 'Release failed'))
167
- }
168
-
169
- const output = JSON.parse(result.stdout.toString())
170
-
171
- // Record the commit we just pushed from so a later pull can use it as the
172
- // merge base regardless of what the server stores in
173
- // bricks_project_last_commit_id.
174
- if (commitId) await writeLastPushedCommit(cwd, commitId)
175
-
176
- console.log(`${isModule ? 'Module' : 'App'} deployed: ${output.name}`)
4
+ forwardLegacyCtorTool('deploy', import.meta.url)
@@ -1,36 +1,4 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
2
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
1
+ #!/usr/bin/env bun
2
+ import { forwardLegacyCtorTool } from './_forward.ts'
3
3
 
4
- import { register as registerCompile } from './mcp-tools/compile'
5
- import { register as registerLottie } from './mcp-tools/lottie'
6
- import { register as registerIcons } from './mcp-tools/icons'
7
- import { register as registerHuggingface } from './mcp-tools/huggingface'
8
- import { register as registerMedia } from './mcp-tools/media'
9
- import { register as registerEntryEditing } from './mcp-tools/entry-editing'
10
- import { register as registerDataCalcEditing } from './mcp-tools/data-calc-editing'
11
- import { shouldRegisterEditingTools } from './mcp-env'
12
-
13
- const server = new McpServer({
14
- name: 'bricks-ctor',
15
- version: '1.0.0',
16
- })
17
-
18
- const { dirname } = import.meta
19
- const projectDir = String(dirname).split('/node_modules/')[0]
20
-
21
- // NOTE: Cursor (Or VSCode) seems set ELECTRON_RUN_AS_NODE to 1, so we need to unset it
22
- process.env.ELECTRON_RUN_AS_NODE = ''
23
-
24
- registerCompile(server, projectDir)
25
- registerLottie(server)
26
- registerIcons(server)
27
- registerHuggingface(server)
28
- registerMedia(server, projectDir)
29
-
30
- if (shouldRegisterEditingTools()) {
31
- registerEntryEditing(server, projectDir)
32
- registerDataCalcEditing(server, projectDir)
33
- }
34
-
35
- const transport = new StdioServerTransport()
36
- await server.connect(transport)
4
+ forwardLegacyCtorTool('mcp', import.meta.url)
@@ -1,292 +1,4 @@
1
- import {
2
- cp,
3
- lstat,
4
- mkdir,
5
- readFile,
6
- readdir,
7
- readlink,
8
- rm,
9
- stat,
10
- symlink,
11
- writeFile,
12
- } from 'fs/promises'
13
- import * as path from 'path'
14
- import TOML from '@iarna/toml'
15
- import { handleMcpConfigOverride } from './_mcp-config'
1
+ #!/usr/bin/env bun
2
+ import { forwardLegacyCtorTool } from './_forward.ts'
16
3
 
17
- const cwd = process.cwd()
18
- const projectSkillsDir = path.join(cwd, '.bricks', 'skills')
19
- const compatibilitySkillLinks = [
20
- path.join(cwd, '.claude', 'skills'),
21
- path.join(cwd, '.codex', 'skills'),
22
- ]
23
-
24
- async function exists(f: string) {
25
- try {
26
- await stat(f)
27
- return true
28
- } catch {
29
- return false
30
- }
31
- }
32
-
33
- async function pathExists(f: string) {
34
- try {
35
- await lstat(f)
36
- return true
37
- } catch {
38
- return false
39
- }
40
- }
41
-
42
- // Migrate old projects: remove legacy project/ directory
43
- const oldProjectDir = path.join(cwd, 'project')
44
- if (await exists(oldProjectDir)) {
45
- await rm(oldProjectDir, { recursive: true, force: true })
46
- console.log('Removed legacy project/ directory')
47
- }
48
-
49
- // handle flag --skip-copy
50
- const skipCopyProject = process.argv.includes('--skip-copy-project')
51
- if (skipCopyProject) {
52
- console.log('Skipping copy of files to ctor/')
53
- } else {
54
- const libFiles = ['types', 'utils', 'index.ts']
55
-
56
- const ctorDir = path.join(cwd, 'ctor')
57
- await mkdir(ctorDir, { recursive: true })
58
- await Promise.all(
59
- libFiles.map((file) =>
60
- cp(path.join(import.meta.dirname, '..', file), path.join(ctorDir, file), {
61
- recursive: true,
62
- }),
63
- ),
64
- )
65
- console.log('Copied files to ctor/')
66
- }
67
-
68
- const projectMcpServer = {
69
- command: 'bun',
70
- args: [`${cwd}/node_modules/@fugood/bricks-ctor/tools/mcp-server.ts`],
71
- }
72
-
73
- // Codex cancels MCP tool calls it cannot prompt approval for (e.g. `codex exec`),
74
- // so the project-local server's tools must be pre-approved in its config entry.
75
- const codexProjectMcpServer = {
76
- ...projectMcpServer,
77
- default_tools_approval_mode: 'approve',
78
- }
79
-
80
- type CodexMcpConfig = {
81
- mcp_servers: Record<string, typeof codexProjectMcpServer | typeof projectMcpServer>
82
- }
83
-
84
- const hasClaudeCode = await exists(`${cwd}/CLAUDE.md`)
85
- const hasAgentsMd = await exists(`${cwd}/AGENTS.md`)
86
-
87
- if (hasClaudeCode || hasAgentsMd) {
88
- // Keep the workspace-level JSON MCP config aligned for tools that read .mcp.json.
89
- const mcpConfigPath = `${cwd}/.mcp.json`
90
- await handleMcpConfigOverride(mcpConfigPath, projectMcpServer)
91
- }
92
-
93
- const copyMissingSkills = async (sourceDir: string, targetDir: string) => {
94
- if (!(await exists(sourceDir))) return
95
-
96
- const packageSkills = await readdir(sourceDir, { withFileTypes: true })
97
- const skillsToInstall = packageSkills.filter(
98
- (entry) => entry.isDirectory() && !entry.name.startsWith('.'),
99
- )
100
-
101
- await mkdir(targetDir, { recursive: true })
102
-
103
- await Promise.all(
104
- skillsToInstall.map(async (entry) => {
105
- const targetSkillDir = path.join(targetDir, entry.name)
106
- if (await exists(targetSkillDir)) {
107
- console.log(`Skill '${entry.name}' already exists, skipping`)
108
- } else {
109
- await cp(path.join(sourceDir, entry.name), targetSkillDir, { recursive: true })
110
- console.log(`Installed skill '${entry.name}' to ${targetDir}/`)
111
- }
112
- }),
113
- )
114
- }
115
-
116
- const migrateSkillsDir = async (legacySkillsDir: string, canonicalSkillsDir: string) => {
117
- if (!(await pathExists(legacySkillsDir))) return
118
-
119
- const legacyStats = await lstat(legacySkillsDir)
120
-
121
- if (legacyStats.isSymbolicLink()) {
122
- const linkTarget = await readlink(legacySkillsDir)
123
- const resolvedTarget = path.resolve(path.dirname(legacySkillsDir), linkTarget)
124
- if (resolvedTarget === canonicalSkillsDir) return
125
-
126
- await copyMissingSkills(resolvedTarget, canonicalSkillsDir)
127
- await rm(legacySkillsDir, { force: true, recursive: true })
128
- return
129
- }
130
-
131
- if (legacyStats.isDirectory()) {
132
- await copyMissingSkills(legacySkillsDir, canonicalSkillsDir)
133
- await rm(legacySkillsDir, { force: true, recursive: true })
134
- return
135
- }
136
-
137
- console.warn(`Skipping skills migration for ${legacySkillsDir}; expected a directory or symlink`)
138
- }
139
-
140
- const ensureCompatibilitySkillLink = async (linkPath: string, targetDir: string) => {
141
- await mkdir(path.dirname(linkPath), { recursive: true })
142
-
143
- if (await pathExists(linkPath)) {
144
- const linkStats = await lstat(linkPath)
145
- if (linkStats.isSymbolicLink()) {
146
- const linkTarget = await readlink(linkPath)
147
- const resolvedTarget = path.resolve(path.dirname(linkPath), linkTarget)
148
- if (resolvedTarget === targetDir) return
149
- } else {
150
- console.warn(
151
- `Skipping skills symlink at ${linkPath}; path already exists and is not a symlink`,
152
- )
153
- return
154
- }
155
- }
156
-
157
- const relativeTarget = path.relative(path.dirname(linkPath), targetDir)
158
- const symlinkType = process.platform === 'win32' ? 'junction' : 'dir'
159
- await symlink(relativeTarget, linkPath, symlinkType)
160
- console.log(`Linked ${linkPath} -> ${relativeTarget}`)
161
- }
162
-
163
- const setupSkills = async () => {
164
- const packageSkillsDir = path.join(import.meta.dirname, '..', 'skills')
165
- await mkdir(projectSkillsDir, { recursive: true })
166
- await copyMissingSkills(packageSkillsDir, projectSkillsDir)
167
-
168
- for (const linkPath of compatibilitySkillLinks) {
169
- await migrateSkillsDir(linkPath, projectSkillsDir)
170
- await ensureCompatibilitySkillLink(linkPath, projectSkillsDir)
171
- }
172
- }
173
-
174
- if (hasClaudeCode || hasAgentsMd) {
175
- // Install project skills once and expose them through compatibility symlinks.
176
- await setupSkills()
177
- }
178
-
179
- type ClaudeSettings = {
180
- autoMode?: {
181
- environment?: string[]
182
- allow?: string[]
183
- soft_deny?: string[]
184
- hard_deny?: string[]
185
- }
186
- [key: string]: unknown
187
- }
188
-
189
- // Trusted infrastructure for auto mode's classifier. `$defaults` keeps the
190
- // built-in environment (the working repo and its git remotes); the extra
191
- // entries stop routine syncs to the BRICKS backend from being treated as
192
- // external exfiltration. See https://code.claude.com/docs/en/auto-mode-config
193
- const autoModeEnvironment = [
194
- '$defaults',
195
- 'Organization: BRICKS (bricks.tools). Primary use: building BRICKS apps/modules with the bricks CLI and the local bricks-ctor MCP server.',
196
- 'Trusted internal domains: all *.bricks.tools services — api.bricks.tools (project GraphQL API), bank.bricks.tools (config & asset Bank API), cdn.bricks.tools (asset CDN), plus the control/display/activity services. This project syncs its config and assets to these endpoints.',
197
- ]
198
-
199
- // `.claude/settings.local.json` is per-developer local config; keep it untracked.
200
- const ensureSettingsLocalGitignored = async () => {
201
- const gitignorePath = path.join(cwd, '.gitignore')
202
- const entry = '.claude/settings.local.json'
203
- const coveredBy = new Set([entry, '.claude', '.claude/', '.claude/*', '*.local.json'])
204
-
205
- let content = ''
206
- if (await exists(gitignorePath)) {
207
- content = await readFile(gitignorePath, 'utf-8')
208
- if (content.split('\n').some((line) => coveredBy.has(line.trim()))) return
209
- }
210
-
211
- const separator = content.length === 0 ? '' : content.endsWith('\n') ? '\n' : '\n\n'
212
- await writeFile(gitignorePath, `${content}${separator}# Claude Code local settings\n${entry}\n`)
213
- console.log(`Added ${entry} to .gitignore`)
214
- }
215
-
216
- // Pre-configure auto mode once, on initial setup. We only seed the classifier's
217
- // trusted infrastructure — not `permissions.defaultMode: 'auto'`, which Claude
218
- // Code ignores from project/local settings (a repo can't grant itself auto mode;
219
- // it only takes effect from ~/.claude/settings.json). An existing autoMode block
220
- // is left untouched so reinstalls never clobber a developer's customizations.
221
- const setupClaudeAutoMode = async () => {
222
- const settingsPath = path.join(cwd, '.claude', 'settings.local.json')
223
-
224
- let settings: ClaudeSettings = {}
225
- if (await exists(settingsPath)) {
226
- try {
227
- settings = JSON.parse(await readFile(settingsPath, 'utf-8'))
228
- } catch {
229
- console.warn(`Skipping auto mode setup; ${settingsPath} is not valid JSON`)
230
- return
231
- }
232
- if (settings.autoMode) return
233
- }
234
-
235
- settings.autoMode = { environment: autoModeEnvironment }
236
-
237
- await mkdir(path.dirname(settingsPath), { recursive: true })
238
- await writeFile(settingsPath, `${JSON.stringify(settings, null, 2)}\n`)
239
- console.log(`Set up auto mode in ${settingsPath}`)
240
-
241
- await ensureSettingsLocalGitignored()
242
- }
243
-
244
- if (hasClaudeCode) {
245
- // Pre-configure auto mode's trusted infrastructure for Claude Code projects.
246
- await setupClaudeAutoMode()
247
- }
248
-
249
- if (hasAgentsMd) {
250
- // Codex stores its project-local MCP config in .codex/config.toml.
251
- const defaultCodexMcpConfig = {
252
- mcp_servers: {
253
- 'bricks-ctor': codexProjectMcpServer,
254
- },
255
- }
256
-
257
- const handleCodexMcpConfigOverride = async (mcpConfigPath: string) => {
258
- let mcpConfig: CodexMcpConfig
259
- if (await exists(mcpConfigPath)) {
260
- let parsed: unknown
261
- try {
262
- parsed = TOML.parse(await readFile(mcpConfigPath, 'utf-8'))
263
- } catch {
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 = {}
274
- }
275
- mcpConfig.mcp_servers['bricks-ctor'] = codexProjectMcpServer
276
- delete mcpConfig.mcp_servers['bricks-project']
277
- } else {
278
- mcpConfig = defaultCodexMcpConfig
279
- }
280
-
281
- await writeFile(mcpConfigPath, `${TOML.stringify(mcpConfig)}\n`)
282
-
283
- console.log(`Updated ${mcpConfigPath}`)
284
- }
285
-
286
- // Keep the Codex TOML MCP config aligned with the same bricks-ctor server entry.
287
- const codexConfigPath = `${cwd}/.codex/config.toml`
288
- await handleCodexMcpConfigOverride(codexConfigPath)
289
- }
290
-
291
- // TODO: .cursor/skills if needed
292
- // TODO: User setting in application.json to avoid unnecessary skills/config setup
4
+ forwardLegacyCtorTool('postinstall', import.meta.url)