@fugood/bricks-ctor 2.25.0-beta.6 → 2.25.0-beta.61

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 (133) hide show
  1. package/package.json +4 -24
  2. package/tools/deploy.ts +19 -165
  3. package/tools/mcp-server.ts +17 -26
  4. package/tools/postinstall.ts +21 -235
  5. package/tools/pull.ts +18 -121
  6. package/tools/push-config.ts +19 -0
  7. package/tools/simulator.ts +21 -0
  8. package/compile/action-name-map.ts +0 -1015
  9. package/compile/index.ts +0 -1278
  10. package/compile/util.ts +0 -358
  11. package/index.ts +0 -6
  12. package/skills/bricks-ctor/SKILL.md +0 -32
  13. package/skills/bricks-ctor/rules/animation.md +0 -159
  14. package/skills/bricks-ctor/rules/architecture-patterns.md +0 -69
  15. package/skills/bricks-ctor/rules/automations.md +0 -221
  16. package/skills/bricks-ctor/rules/buttress.md +0 -156
  17. package/skills/bricks-ctor/rules/data-calculation.md +0 -209
  18. package/skills/bricks-ctor/rules/local-sync.md +0 -129
  19. package/skills/bricks-ctor/rules/media-flow.md +0 -158
  20. package/skills/bricks-ctor/rules/remote-data-bank.md +0 -196
  21. package/skills/bricks-ctor/rules/standby-transition.md +0 -124
  22. package/skills/bricks-design/LICENSE.txt +0 -180
  23. package/skills/bricks-design/SKILL.md +0 -66
  24. package/skills/rive-marketplace/SKILL.md +0 -99
  25. package/tools/_git-author.ts +0 -29
  26. package/tools/_shell.ts +0 -173
  27. package/tools/icons/.gitattributes +0 -1
  28. package/tools/icons/fa6pro-glyphmap.json +0 -4686
  29. package/tools/icons/fa6pro-meta.json +0 -1
  30. package/tools/mcp-tools/compile.ts +0 -92
  31. package/tools/mcp-tools/huggingface.ts +0 -762
  32. package/tools/mcp-tools/icons.ts +0 -81
  33. package/tools/mcp-tools/lottie.ts +0 -102
  34. package/tools/mcp-tools/media.ts +0 -110
  35. package/tools/preview-main.mjs +0 -293
  36. package/tools/preview.ts +0 -150
  37. package/types/animation.ts +0 -100
  38. package/types/automation.ts +0 -235
  39. package/types/brick-base.ts +0 -80
  40. package/types/bricks/Camera.ts +0 -246
  41. package/types/bricks/Chart.ts +0 -372
  42. package/types/bricks/GenerativeMedia.ts +0 -290
  43. package/types/bricks/Icon.ts +0 -98
  44. package/types/bricks/Image.ts +0 -114
  45. package/types/bricks/Items.ts +0 -476
  46. package/types/bricks/Lottie.ts +0 -168
  47. package/types/bricks/Maps.ts +0 -262
  48. package/types/bricks/QrCode.ts +0 -117
  49. package/types/bricks/Rect.ts +0 -150
  50. package/types/bricks/RichText.ts +0 -128
  51. package/types/bricks/Rive.ts +0 -220
  52. package/types/bricks/Sketch.ts +0 -254
  53. package/types/bricks/Slideshow.ts +0 -201
  54. package/types/bricks/Svg.ts +0 -99
  55. package/types/bricks/Text.ts +0 -148
  56. package/types/bricks/TextInput.ts +0 -242
  57. package/types/bricks/Video.ts +0 -175
  58. package/types/bricks/VideoStreaming.ts +0 -112
  59. package/types/bricks/WebRtcStream.ts +0 -65
  60. package/types/bricks/WebView.ts +0 -168
  61. package/types/bricks/index.ts +0 -22
  62. package/types/canvas.ts +0 -82
  63. package/types/common.ts +0 -144
  64. package/types/data-calc-command.ts +0 -7005
  65. package/types/data-calc-script.ts +0 -21
  66. package/types/data-calc.ts +0 -11
  67. package/types/data.ts +0 -95
  68. package/types/generators/AlarmClock.ts +0 -110
  69. package/types/generators/Assistant.ts +0 -621
  70. package/types/generators/BleCentral.ts +0 -247
  71. package/types/generators/BlePeripheral.ts +0 -208
  72. package/types/generators/CanvasMap.ts +0 -74
  73. package/types/generators/CastlesPay.ts +0 -87
  74. package/types/generators/DataBank.ts +0 -160
  75. package/types/generators/File.ts +0 -432
  76. package/types/generators/GraphQl.ts +0 -132
  77. package/types/generators/Http.ts +0 -222
  78. package/types/generators/HttpServer.ts +0 -176
  79. package/types/generators/Information.ts +0 -103
  80. package/types/generators/Intent.ts +0 -168
  81. package/types/generators/Iterator.ts +0 -108
  82. package/types/generators/Keyboard.ts +0 -105
  83. package/types/generators/LlmAnthropicCompat.ts +0 -212
  84. package/types/generators/LlmAppleBuiltin.ts +0 -159
  85. package/types/generators/LlmGgml.ts +0 -861
  86. package/types/generators/LlmMediaTekNeuroPilot.ts +0 -235
  87. package/types/generators/LlmMlx.ts +0 -227
  88. package/types/generators/LlmOnnx.ts +0 -213
  89. package/types/generators/LlmOpenAiCompat.ts +0 -312
  90. package/types/generators/LlmQualcommAiEngine.ts +0 -247
  91. package/types/generators/Mcp.ts +0 -637
  92. package/types/generators/McpServer.ts +0 -289
  93. package/types/generators/MediaFlow.ts +0 -170
  94. package/types/generators/MqttBroker.ts +0 -141
  95. package/types/generators/MqttClient.ts +0 -141
  96. package/types/generators/Question.ts +0 -408
  97. package/types/generators/RealtimeTranscription.ts +0 -287
  98. package/types/generators/RerankerGgml.ts +0 -191
  99. package/types/generators/SerialPort.ts +0 -151
  100. package/types/generators/SoundPlayer.ts +0 -94
  101. package/types/generators/SoundRecorder.ts +0 -130
  102. package/types/generators/SpeechToTextGgml.ts +0 -419
  103. package/types/generators/SpeechToTextOnnx.ts +0 -236
  104. package/types/generators/SpeechToTextPlatform.ts +0 -85
  105. package/types/generators/SqLite.ts +0 -159
  106. package/types/generators/Step.ts +0 -107
  107. package/types/generators/SttAppleBuiltin.ts +0 -130
  108. package/types/generators/Tcp.ts +0 -126
  109. package/types/generators/TcpServer.ts +0 -147
  110. package/types/generators/TextToSpeechAppleBuiltin.ts +0 -127
  111. package/types/generators/TextToSpeechGgml.ts +0 -221
  112. package/types/generators/TextToSpeechOnnx.ts +0 -178
  113. package/types/generators/TextToSpeechOpenAiLike.ts +0 -121
  114. package/types/generators/ThermalPrinter.ts +0 -191
  115. package/types/generators/Tick.ts +0 -83
  116. package/types/generators/Udp.ts +0 -120
  117. package/types/generators/VadGgml.ts +0 -250
  118. package/types/generators/VadOnnx.ts +0 -231
  119. package/types/generators/VadTraditional.ts +0 -138
  120. package/types/generators/VectorStore.ts +0 -257
  121. package/types/generators/Watchdog.ts +0 -107
  122. package/types/generators/WebCrawler.ts +0 -103
  123. package/types/generators/WebRtc.ts +0 -181
  124. package/types/generators/WebSocket.ts +0 -148
  125. package/types/generators/index.ts +0 -57
  126. package/types/index.ts +0 -13
  127. package/types/subspace.ts +0 -60
  128. package/types/switch.ts +0 -51
  129. package/types/system.ts +0 -707
  130. package/utils/calc.ts +0 -126
  131. package/utils/data.ts +0 -497
  132. package/utils/event-props.ts +0 -886
  133. package/utils/id.ts +0 -80
package/package.json CHANGED
@@ -1,29 +1,9 @@
1
1
  {
2
2
  "name": "@fugood/bricks-ctor",
3
- "version": "2.25.0-beta.6",
4
- "main": "index.ts",
5
- "scripts": {
6
- "typecheck": "tsc --noEmit",
7
- "build": "bun scripts/build.js"
8
- },
3
+ "version": "2.25.0-beta.61",
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
- "@fugood/bricks-cli": "^2.25.0-beta.6",
11
- "@huggingface/gguf": "^0.3.2",
12
- "@iarna/toml": "^3.0.0",
13
- "@modelcontextprotocol/sdk": "^1.15.0",
14
- "@toon-format/toon": "^2.1.0",
15
- "@types/bun": "^1.3.9",
16
- "@types/escodegen": "^0.0.10",
17
- "@types/lodash": "^4.17.12",
18
- "acorn": "^8.13.0",
19
- "escodegen": "2.1.0",
20
- "fuse.js": "^7.0.0",
21
- "json5": "^2.0.1",
22
- "lodash": "^4.17.4",
23
- "uuid": "^8.3.1"
24
- },
25
- "peerDependencies": {
26
- "oxfmt": "^0.36.0"
6
+ "@fugood/bricks-cli": "^2.25.0-beta.61"
27
7
  },
28
- "gitHead": "d8a3bbd695e9118cf725b7226866d804bbe56bbe"
8
+ "gitHead": "342701683311c7e0dc295bac19a2f9a9517d3160"
29
9
  }
package/tools/deploy.ts CHANGED
@@ -1,165 +1,19 @@
1
- import { access, readFile, writeFile } from 'node:fs/promises'
2
- import { parseArgs } from 'util'
3
- import { sh } from './_shell'
4
- import { buildCommitArgs } from './_git-author'
5
-
6
- const cwd = process.cwd()
7
-
8
- const exists = async (p: string) => {
9
- try {
10
- await access(p)
11
- return true
12
- } catch {
13
- return false
14
- }
15
- }
16
-
17
- const readJson = async (p: string) => JSON.parse(await readFile(p, 'utf8'))
18
-
19
- const {
20
- values: {
21
- changelogs: changelogsArg,
22
- 'changelogs-file': changelogsFile,
23
- 'auto-commit': autoCommit,
24
- 'auto-version': autoVersion,
25
- version: versionArg,
26
- yes,
27
- help,
28
- },
29
- } = parseArgs({
30
- args: process.argv.slice(2),
31
- options: {
32
- changelogs: { type: 'string' },
33
- 'changelogs-file': { type: 'string' },
34
- 'auto-commit': { type: 'boolean' },
35
- 'auto-version': { type: 'boolean' },
36
- version: { type: 'string' },
37
- yes: { type: 'boolean', short: 'y' },
38
- help: { type: 'boolean', short: 'h' },
39
- },
40
- allowPositionals: true,
41
- })
42
-
43
- if (help) {
44
- console.log(`Options:
45
- --changelogs <text> Changelogs text for the release
46
- --changelogs-file <path> Read changelogs from a file
47
- --auto-commit Auto-commit unstaged changes before deploying
48
- --auto-version Auto-bump patch version before deploying
49
- --version <version> Set explicit version for the release
50
- -y, --yes Skip all prompts
51
- -h, --help Show this help message`)
52
- process.exit(0)
53
- }
54
-
55
- // Check git status
56
- const { exitCode } = await sh`cd ${cwd} && git status`.quiet().nothrow()
57
- const isGitRepo = exitCode === 0
58
-
59
- if (!isGitRepo && !yes) {
60
- const confirmContinue = prompt('No git repository found, continue? (y/n)')
61
- if (confirmContinue !== 'y') throw new Error('Deployment cancelled')
62
- }
63
-
64
- // Read application.json
65
- const app = await readJson(`${cwd}/application.json`)
66
- const config = await readJson(`${cwd}/.bricks/build/application-config.json`)
67
-
68
- // Resolve version: explicit flag > auto-bump > package.json
69
- const pkgPath = `${cwd}/package.json`
70
- const pkgExists = await exists(pkgPath)
71
- let version: string | undefined
72
-
73
- if (versionArg) {
74
- version = versionArg
75
- if (pkgExists) {
76
- const pkg = await readJson(pkgPath)
77
- pkg.version = version
78
- await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
79
- }
80
- } else if (autoVersion && pkgExists) {
81
- const pkg = await readJson(pkgPath)
82
- const parts = (pkg.version || '0.0.0').split('.')
83
- parts[2] = String(Number(parts[2] || 0) + 1)
84
- version = parts.join('.')
85
- pkg.version = version
86
- await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + '\n')
87
- } else {
88
- version = pkgExists ? (await readJson(pkgPath)).version : undefined
89
- }
90
-
91
- // Get changelog from flag or file
92
- let changelogs = ''
93
- if (changelogsArg) {
94
- changelogs = changelogsArg
95
- } else if (changelogsFile) {
96
- if (!(await exists(changelogsFile))) {
97
- throw new Error(`Changelogs file not found: ${changelogsFile}`)
98
- }
99
- changelogs = await readFile(changelogsFile, 'utf8')
100
- } else if (!yes) {
101
- changelogs = prompt('Enter changelogs (optional, press Enter to skip):') || ''
102
- }
103
-
104
- // Handle unstaged changes
105
- let commitId = ''
106
- if (isGitRepo) {
107
- const unstagedChanges = await sh`cd ${cwd} && git diff --name-only --diff-filter=ACMR`.text()
108
- if (unstagedChanges) {
109
- if (autoCommit) {
110
- const commitMsg = `chore: release ${version || 'new version'}`
111
- const commitBody = changelogs || '[no changelogs]'
112
- await sh`cd ${cwd} && git add -A`
113
- const commitArgs = await buildCommitArgs(cwd, [commitMsg, commitBody])
114
- await sh`cd ${cwd} && git ${commitArgs}`
115
- } else {
116
- throw new Error(
117
- 'Unstaged changes found, please commit or stash your changes before deploying',
118
- )
119
- }
120
- }
121
- commitId = (await sh`cd ${cwd} && git rev-parse HEAD`.text()).trim()
122
- }
123
-
124
- // Ask for confirmation
125
- if (!yes) {
126
- const confirm = prompt('Are you sure you want to deploy? (y/n)')
127
- if (confirm !== 'y') throw new Error('Deployment cancelled')
128
- }
129
-
130
- const isModule = app.type === 'module'
131
- const command = isModule ? 'module' : 'app'
132
-
133
- // Add project-specific fields to config and write to temp file
134
- const releaseConfig = {
135
- ...config,
136
- title: version || config.title,
137
- bricks_project_last_commit_id: commitId || undefined,
138
- }
139
- const configPath = `${cwd}/.bricks/build/release-config.json`
140
- await writeFile(configPath, JSON.stringify(releaseConfig))
141
-
142
- const args = ['bricks', command, 'release', app.id, '-c', configPath, '--json']
143
-
144
- if (version) {
145
- args.push('--version', version)
146
- }
147
-
148
- if (changelogs) {
149
- args.push('--changelogs', changelogs)
150
- }
151
-
152
- const result = await sh`${args}`.quiet().nothrow()
153
-
154
- if (result.exitCode !== 0) {
155
- const output = result.stderr.toString() || result.stdout.toString()
156
- try {
157
- const json = JSON.parse(output)
158
- throw new Error(json.error || 'Release failed')
159
- } catch {
160
- throw new Error(output || 'Release failed')
161
- }
162
- }
163
-
164
- const output = JSON.parse(result.stdout.toString())
165
- console.log(`${isModule ? 'Module' : 'App'} deployed: ${output.name}`)
1
+ #!/usr/bin/env bun
2
+ // @fugood/bricks-ctor is deprecated all tooling now lives in the `bricks ctor *` commands
3
+ // (the @fugood/bricks-cli package). This thin forwarder keeps legacy project scripts working
4
+ // and lets `bricks ctor postinstall` migrate the project onto the new commands.
5
+ import { spawnSync } from 'node:child_process'
6
+ import { existsSync } from 'node:fs'
7
+ import { fileURLToPath } from 'node:url'
8
+
9
+ // Prefer the CLI installed next to this shim (@fugood/bricks-cli is our only dependency)
10
+ // over a PATH lookup, so the forwarder works without a global install.
11
+ const localBricks = fileURLToPath(new URL('../../../.bin/bricks', import.meta.url))
12
+ const bricks = existsSync(localBricks) ? localBricks : 'bricks'
13
+
14
+ const result = spawnSync(bricks, ['ctor', 'deploy', ...process.argv.slice(2)], { stdio: 'inherit' })
15
+ if (result.error) {
16
+ console.error(`bricks-ctor forwarder failed to run \`${bricks}\`: ${result.error.message}`)
17
+ process.exit(1)
18
+ }
19
+ process.exit(result.status ?? 1)
@@ -1,28 +1,19 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'
2
- import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
1
+ #!/usr/bin/env bun
2
+ // @fugood/bricks-ctor is deprecated all tooling now lives in the `bricks ctor *` commands
3
+ // (the @fugood/bricks-cli package). This thin forwarder keeps legacy project scripts working
4
+ // and lets `bricks ctor postinstall` migrate the project onto the new commands.
5
+ import { spawnSync } from 'node:child_process'
6
+ import { existsSync } from 'node:fs'
7
+ import { fileURLToPath } from 'node:url'
3
8
 
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
+ // Prefer the CLI installed next to this shim (@fugood/bricks-cli is our only dependency)
10
+ // over a PATH lookup, so the forwarder works without a global install.
11
+ const localBricks = fileURLToPath(new URL('../../../.bin/bricks', import.meta.url))
12
+ const bricks = existsSync(localBricks) ? localBricks : 'bricks'
9
13
 
10
- const server = new McpServer({
11
- name: 'bricks-ctor',
12
- version: '1.0.0',
13
- })
14
-
15
- const { dirname } = import.meta
16
- const projectDir = String(dirname).split('/node_modules/')[0]
17
-
18
- // NOTE: Cursor (Or VSCode) seems set ELECTRON_RUN_AS_NODE to 1, so we need to unset it
19
- process.env.ELECTRON_RUN_AS_NODE = ''
20
-
21
- registerCompile(server, projectDir)
22
- registerLottie(server)
23
- registerIcons(server)
24
- registerHuggingface(server)
25
- registerMedia(server, projectDir)
26
-
27
- const transport = new StdioServerTransport()
28
- await server.connect(transport)
14
+ const result = spawnSync(bricks, ['ctor', 'mcp', ...process.argv.slice(2)], { stdio: 'inherit' })
15
+ if (result.error) {
16
+ console.error(`bricks-ctor forwarder failed to run \`${bricks}\`: ${result.error.message}`)
17
+ process.exit(1)
18
+ }
19
+ process.exit(result.status ?? 1)
@@ -1,235 +1,21 @@
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
-
16
- const cwd = process.cwd()
17
- const projectSkillsDir = path.join(cwd, '.bricks', 'skills')
18
- const compatibilitySkillLinks = [
19
- path.join(cwd, '.claude', 'skills'),
20
- path.join(cwd, '.codex', 'skills'),
21
- ]
22
-
23
- async function exists(f: string) {
24
- try {
25
- await stat(f)
26
- return true
27
- } catch {
28
- return false
29
- }
30
- }
31
-
32
- async function pathExists(f: string) {
33
- try {
34
- await lstat(f)
35
- return true
36
- } catch {
37
- return false
38
- }
39
- }
40
-
41
- // Migrate old projects: remove legacy project/ directory
42
- const oldProjectDir = path.join(cwd, 'project')
43
- if (await exists(oldProjectDir)) {
44
- await rm(oldProjectDir, { recursive: true, force: true })
45
- console.log('Removed legacy project/ directory')
46
- }
47
-
48
- // handle flag --skip-copy
49
- const skipCopyProject = process.argv.includes('--skip-copy-project')
50
- if (skipCopyProject) {
51
- console.log('Skipping copy of files to ctor/')
52
- } else {
53
- const libFiles = ['types', 'utils', 'index.ts']
54
-
55
- const ctorDir = path.join(cwd, 'ctor')
56
- await mkdir(ctorDir, { recursive: true })
57
- await Promise.all(
58
- libFiles.map((file) =>
59
- cp(path.join(import.meta.dirname, '..', file), path.join(ctorDir, file), {
60
- recursive: true,
61
- }),
62
- ),
63
- )
64
- console.log('Copied files to ctor/')
65
- }
66
-
67
- const projectMcpServer = {
68
- command: 'bun',
69
- args: [`${cwd}/node_modules/@fugood/bricks-ctor/tools/mcp-server.ts`],
70
- }
71
-
72
- type CodexMcpConfig = {
73
- mcp_servers: Record<string, typeof projectMcpServer>
74
- }
75
-
76
- // Claude Code and AGENTS.md projects both use the shared project .mcp.json file.
77
- const defaultMcpConfig = {
78
- mcpServers: {
79
- 'bricks-ctor': projectMcpServer,
80
- },
81
- }
82
-
83
- const handleMcpConfigOverride = async (mcpConfigPath: string) => {
84
- let mcpConfig: { mcpServers: Record<string, typeof projectMcpServer> } | null = null
85
- if (await exists(mcpConfigPath)) {
86
- const configStr = await readFile(mcpConfigPath, 'utf-8')
87
- try {
88
- mcpConfig = JSON.parse(configStr)
89
- if (!mcpConfig?.mcpServers) throw new Error('mcpServers is not defined')
90
- mcpConfig.mcpServers['bricks-ctor'] = projectMcpServer
91
- delete mcpConfig.mcpServers['bricks-project']
92
- } catch {
93
- mcpConfig = defaultMcpConfig
94
- }
95
- } else {
96
- mcpConfig = defaultMcpConfig
97
- }
98
-
99
- await writeFile(mcpConfigPath, `${JSON.stringify(mcpConfig, null, 2)}\n`)
100
-
101
- console.log(`Updated ${mcpConfigPath}`)
102
- }
103
-
104
- const hasClaudeCode = await exists(`${cwd}/CLAUDE.md`)
105
- const hasAgentsMd = await exists(`${cwd}/AGENTS.md`)
106
-
107
- if (hasClaudeCode || hasAgentsMd) {
108
- // Keep the workspace-level JSON MCP config aligned for tools that read .mcp.json.
109
- const mcpConfigPath = `${cwd}/.mcp.json`
110
- await handleMcpConfigOverride(mcpConfigPath)
111
- }
112
-
113
- const copyMissingSkills = async (sourceDir: string, targetDir: string) => {
114
- if (!(await exists(sourceDir))) return
115
-
116
- const packageSkills = await readdir(sourceDir, { withFileTypes: true })
117
- const skillsToInstall = packageSkills.filter(
118
- (entry) => entry.isDirectory() && !entry.name.startsWith('.'),
119
- )
120
-
121
- await mkdir(targetDir, { recursive: true })
122
-
123
- await Promise.all(
124
- skillsToInstall.map(async (entry) => {
125
- const targetSkillDir = path.join(targetDir, entry.name)
126
- if (await exists(targetSkillDir)) {
127
- console.log(`Skill '${entry.name}' already exists, skipping`)
128
- } else {
129
- await cp(path.join(sourceDir, entry.name), targetSkillDir, { recursive: true })
130
- console.log(`Installed skill '${entry.name}' to ${targetDir}/`)
131
- }
132
- }),
133
- )
134
- }
135
-
136
- const migrateSkillsDir = async (legacySkillsDir: string, canonicalSkillsDir: string) => {
137
- if (!(await pathExists(legacySkillsDir))) return
138
-
139
- const legacyStats = await lstat(legacySkillsDir)
140
-
141
- if (legacyStats.isSymbolicLink()) {
142
- const linkTarget = await readlink(legacySkillsDir)
143
- const resolvedTarget = path.resolve(path.dirname(legacySkillsDir), linkTarget)
144
- if (resolvedTarget === canonicalSkillsDir) return
145
-
146
- await copyMissingSkills(resolvedTarget, canonicalSkillsDir)
147
- await rm(legacySkillsDir, { force: true, recursive: true })
148
- return
149
- }
150
-
151
- if (legacyStats.isDirectory()) {
152
- await copyMissingSkills(legacySkillsDir, canonicalSkillsDir)
153
- await rm(legacySkillsDir, { force: true, recursive: true })
154
- return
155
- }
156
-
157
- console.warn(`Skipping skills migration for ${legacySkillsDir}; expected a directory or symlink`)
158
- }
159
-
160
- const ensureCompatibilitySkillLink = async (linkPath: string, targetDir: string) => {
161
- await mkdir(path.dirname(linkPath), { recursive: true })
162
-
163
- if (await pathExists(linkPath)) {
164
- const linkStats = await lstat(linkPath)
165
- if (linkStats.isSymbolicLink()) {
166
- const linkTarget = await readlink(linkPath)
167
- const resolvedTarget = path.resolve(path.dirname(linkPath), linkTarget)
168
- if (resolvedTarget === targetDir) return
169
- } else {
170
- console.warn(
171
- `Skipping skills symlink at ${linkPath}; path already exists and is not a symlink`,
172
- )
173
- return
174
- }
175
- }
176
-
177
- const relativeTarget = path.relative(path.dirname(linkPath), targetDir)
178
- const symlinkType = process.platform === 'win32' ? 'junction' : 'dir'
179
- await symlink(relativeTarget, linkPath, symlinkType)
180
- console.log(`Linked ${linkPath} -> ${relativeTarget}`)
181
- }
182
-
183
- const setupSkills = async () => {
184
- const packageSkillsDir = path.join(import.meta.dirname, '..', 'skills')
185
- await mkdir(projectSkillsDir, { recursive: true })
186
- await copyMissingSkills(packageSkillsDir, projectSkillsDir)
187
-
188
- for (const linkPath of compatibilitySkillLinks) {
189
- await migrateSkillsDir(linkPath, projectSkillsDir)
190
- await ensureCompatibilitySkillLink(linkPath, projectSkillsDir)
191
- }
192
- }
193
-
194
- if (hasClaudeCode || hasAgentsMd) {
195
- // Install project skills once and expose them through compatibility symlinks.
196
- await setupSkills()
197
- }
198
-
199
- if (hasAgentsMd) {
200
- // Codex stores its project-local MCP config in .codex/config.toml.
201
- const defaultCodexMcpConfig = {
202
- mcp_servers: {
203
- 'bricks-ctor': projectMcpServer,
204
- },
205
- }
206
-
207
- const handleCodexMcpConfigOverride = async (mcpConfigPath: string) => {
208
- let mcpConfig: CodexMcpConfig | null = null
209
- if (await exists(mcpConfigPath)) {
210
- const configStr = await readFile(mcpConfigPath, 'utf-8')
211
- try {
212
- const parsed = TOML.parse(configStr) as Partial<CodexMcpConfig>
213
- if (!parsed?.mcp_servers) throw new Error('mcp_servers is not defined')
214
- mcpConfig = { mcp_servers: parsed.mcp_servers }
215
- mcpConfig.mcp_servers['bricks-ctor'] = projectMcpServer
216
- delete mcpConfig.mcp_servers['bricks-project']
217
- } catch {
218
- mcpConfig = defaultCodexMcpConfig
219
- }
220
- } else {
221
- mcpConfig = defaultCodexMcpConfig
222
- }
223
-
224
- await writeFile(mcpConfigPath, `${TOML.stringify(mcpConfig)}\n`)
225
-
226
- console.log(`Updated ${mcpConfigPath}`)
227
- }
228
-
229
- // Keep the Codex TOML MCP config aligned with the same bricks-ctor server entry.
230
- const codexConfigPath = `${cwd}/.codex/config.toml`
231
- await handleCodexMcpConfigOverride(codexConfigPath)
232
- }
233
-
234
- // TODO: .cursor/skills if needed
235
- // TODO: User setting in application.json to avoid unnecessary skills/config setup
1
+ #!/usr/bin/env bun
2
+ // @fugood/bricks-ctor is deprecated — all tooling now lives in the `bricks ctor *` commands
3
+ // (the @fugood/bricks-cli package). This thin forwarder keeps legacy project scripts working
4
+ // and lets `bricks ctor postinstall` migrate the project onto the new commands.
5
+ import { spawnSync } from 'node:child_process'
6
+ import { existsSync } from 'node:fs'
7
+ import { fileURLToPath } from 'node:url'
8
+
9
+ // Prefer the CLI installed next to this shim (@fugood/bricks-cli is our only dependency)
10
+ // over a PATH lookup, so the forwarder works without a global install.
11
+ const localBricks = fileURLToPath(new URL('../../../.bin/bricks', import.meta.url))
12
+ const bricks = existsSync(localBricks) ? localBricks : 'bricks'
13
+
14
+ const result = spawnSync(bricks, ['ctor', 'postinstall', ...process.argv.slice(2)], {
15
+ stdio: 'inherit',
16
+ })
17
+ if (result.error) {
18
+ console.error(`bricks-ctor forwarder failed to run \`${bricks}\`: ${result.error.message}`)
19
+ process.exit(1)
20
+ }
21
+ process.exit(result.status ?? 1)
package/tools/pull.ts CHANGED
@@ -1,122 +1,19 @@
1
- import { readFile, writeFile } from 'node:fs/promises'
2
- import { format } from 'oxfmt'
3
- import { sh } from './_shell'
4
- import { buildCommitArgs } from './_git-author'
5
-
6
- const cwd = process.cwd()
7
- const args = process.argv.slice(2)
8
- const force = args.includes('--force') || args.includes('-f')
9
-
10
- // Check git status
11
- const { exitCode } = await sh`cd ${cwd} && git status`.nothrow()
12
- const isGitRepo = exitCode === 0
13
-
14
- if (isGitRepo) {
15
- const unstagedChanges = await sh`cd ${cwd} && git diff --name-only --diff-filter=ACMR`.text()
16
- if (unstagedChanges) {
17
- if (force) {
18
- console.log('Force mode: committing unstaged changes before pull...')
19
- await sh`cd ${cwd} && git add .`
20
- const preCommitArgs = await buildCommitArgs(cwd, [
21
- 'chore(force-pull): saved unstaged changes before pull',
22
- ])
23
- await sh`cd ${cwd} && git ${preCommitArgs}`
24
- } else {
25
- throw new Error('Unstaged changes found, please commit or stash your changes before pulling')
26
- }
27
- }
28
- } else {
29
- const confirmContinue = prompt(
30
- 'No git repository found, so it will not be safe to pull, continue? (y/n)',
31
- )
32
- if (confirmContinue !== 'y') throw new Error('Pull cancelled')
1
+ #!/usr/bin/env bun
2
+ // @fugood/bricks-ctor is deprecated all tooling now lives in the `bricks ctor *` commands
3
+ // (the @fugood/bricks-cli package). This thin forwarder keeps legacy project scripts working
4
+ // and lets `bricks ctor postinstall` migrate the project onto the new commands.
5
+ import { spawnSync } from 'node:child_process'
6
+ import { existsSync } from 'node:fs'
7
+ import { fileURLToPath } from 'node:url'
8
+
9
+ // Prefer the CLI installed next to this shim (@fugood/bricks-cli is our only dependency)
10
+ // over a PATH lookup, so the forwarder works without a global install.
11
+ const localBricks = fileURLToPath(new URL('../../../.bin/bricks', import.meta.url))
12
+ const bricks = existsSync(localBricks) ? localBricks : 'bricks'
13
+
14
+ const result = spawnSync(bricks, ['ctor', 'pull', ...process.argv.slice(2)], { stdio: 'inherit' })
15
+ if (result.error) {
16
+ console.error(`bricks-ctor forwarder failed to run \`${bricks}\`: ${result.error.message}`)
17
+ process.exit(1)
33
18
  }
34
-
35
- // Read application.json
36
- const app = JSON.parse(await readFile(`${cwd}/application.json`, 'utf8'))
37
-
38
- const isModule = app.type === 'module'
39
- const command = isModule ? 'module' : 'app'
40
-
41
- // Fetch project files using CLI
42
- console.log(`Pulling ${command} project (${app.id})...`)
43
- const result = await sh`bricks ${command} project-pull ${app.id} --json`.quiet().nothrow()
44
-
45
- if (result.exitCode !== 0) {
46
- const output = result.stderr.toString() || result.stdout.toString()
47
- try {
48
- const json = JSON.parse(output)
49
- throw new Error(json.error || 'Pull failed')
50
- } catch {
51
- throw new Error(output || 'Pull failed')
52
- }
53
- }
54
-
55
- const { files, lastCommitId } = JSON.parse(result.stdout.toString())
56
-
57
- let useMain = false
58
- if (isGitRepo && !force) {
59
- console.log(`Checking commit ${lastCommitId}...`)
60
- const found = (await sh`cd ${cwd} && git rev-list -1 ${lastCommitId}`.nothrow().text())
61
- .trim()
62
- .match(/^[\da-f]{40}$/)
63
-
64
- const commitId = (await sh`cd ${cwd} && git rev-parse HEAD`.text()).trim()
65
-
66
- if (commitId === lastCommitId) throw new Error('Commit not changed')
67
-
68
- const branchName = isModule
69
- ? 'BRICKS_PROJECT_try-pull-module'
70
- : 'BRICKS_PROJECT_try-pull-application'
71
-
72
- await sh`cd ${cwd} && git branch -D ${branchName}`.nothrow()
73
-
74
- if (found) {
75
- await sh`cd ${cwd} && git checkout -b ${branchName} ${lastCommitId}`.nothrow()
76
- } else {
77
- await sh`cd ${cwd} && git checkout -b ${branchName}`
78
- useMain = true
79
- }
80
- }
81
-
82
- const oxfmtConfig = await readFile(`${cwd}/.oxfmtrc.json`, 'utf8')
83
- .then(JSON.parse)
84
- .catch(() => ({
85
- trailingComma: 'all',
86
- tabWidth: 2,
87
- semi: false,
88
- singleQuote: true,
89
- printWidth: 100,
90
- }))
91
-
92
- await Promise.all(
93
- files.map(async (file: { name: string; input: string; formatable?: boolean }) => {
94
- let content = file.input
95
- if (file.formatable) {
96
- const result = await format(file.name, file.input, oxfmtConfig)
97
- content = result.code
98
- }
99
- return writeFile(`${cwd}/${file.name}`, content)
100
- }),
101
- )
102
-
103
- if (isGitRepo) {
104
- await sh`cd ${cwd} && git add .`
105
- const hasChanges = !!(await sh`cd ${cwd} && git diff --cached --name-only`.text()).trim()
106
- if (hasChanges) {
107
- const commitMsg = force
108
- ? `chore(force-pull): apply force pull-${command}`
109
- : isModule
110
- ? 'chore(project): apply file changes from BRICKS module'
111
- : 'chore(project): apply file changes from BRICKS application'
112
- const commitArgs = await buildCommitArgs(cwd, [commitMsg])
113
- await sh`cd ${cwd} && git ${commitArgs}`
114
- }
115
- if (!force && !useMain) {
116
- await sh`cd ${cwd} && git merge main`
117
- }
118
- }
119
-
120
- console.log(
121
- `${isModule ? 'Module' : 'App'} project pulled: ${files.length} files${force ? ' (force)' : ''}`,
122
- )
19
+ process.exit(result.status ?? 1)