@bagelink/workspace 1.10.7 → 1.10.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.
- package/README.md +214 -9
- package/bin/bgl.ts +88 -2
- package/dist/bin/bgl.cjs +854 -14
- package/dist/bin/bgl.mjs +845 -6
- package/dist/composable.cjs +22 -0
- package/dist/composable.d.cts +52 -0
- package/dist/composable.d.mts +52 -0
- package/dist/composable.d.ts +52 -0
- package/dist/composable.mjs +19 -0
- package/dist/index.cjs +3 -160
- package/dist/index.d.cts +4 -160
- package/dist/index.d.mts +4 -160
- package/dist/index.d.ts +4 -160
- package/dist/index.mjs +2 -139
- package/dist/shared/workspace.Bc_dpzhA.mjs +500 -0
- package/dist/shared/workspace.BzlV5kcN.d.cts +50 -0
- package/dist/shared/workspace.BzlV5kcN.d.mts +50 -0
- package/dist/shared/workspace.BzlV5kcN.d.ts +50 -0
- package/dist/shared/workspace.DRlDHdPw.cjs +512 -0
- package/dist/vite.cjs +135 -0
- package/dist/vite.d.cts +98 -0
- package/dist/vite.d.mts +98 -0
- package/dist/vite.d.ts +98 -0
- package/dist/vite.mjs +125 -0
- package/env.d.ts +30 -0
- package/package.json +24 -3
- package/src/build.ts +45 -0
- package/src/composable.ts +70 -0
- package/src/dev.ts +171 -0
- package/src/index.ts +4 -78
- package/src/init.ts +72 -14
- package/src/lint.ts +90 -2
- package/src/netlify.ts +54 -3
- package/src/proxy.ts +23 -3
- package/src/sdk.ts +80 -44
- package/src/types.ts +10 -4
- package/src/vite.ts +166 -0
- package/src/workspace.ts +121 -16
- package/templates/dev-runner.ts +61 -0
- package/templates/tsconfig.app.json +23 -0
- package/dist/shared/workspace.BPEOymAx.cjs +0 -926
- package/dist/shared/workspace.DfYoqH33.mjs +0 -906
package/src/sdk.ts
CHANGED
|
@@ -69,6 +69,9 @@ export async function generateSDK(
|
|
|
69
69
|
try {
|
|
70
70
|
// Dynamic import of @bagelink/sdk
|
|
71
71
|
const { openAPI } = await import('@bagelink/sdk')
|
|
72
|
+
const { readFileSync } = await import('node:fs')
|
|
73
|
+
const { dirname, join } = await import('node:path')
|
|
74
|
+
const { fileURLToPath } = await import('node:url')
|
|
72
75
|
|
|
73
76
|
const { types, code } = await openAPI(finalUrl, '/api')
|
|
74
77
|
|
|
@@ -86,14 +89,7 @@ export async function generateSDK(
|
|
|
86
89
|
const apiPath = resolve(outputPath, 'api.ts')
|
|
87
90
|
writeFileSync(apiPath, code)
|
|
88
91
|
console.log('✅ Generated api.ts')
|
|
89
|
-
|
|
90
|
-
// Write index
|
|
91
|
-
const indexPath = resolve(outputPath, 'index.ts')
|
|
92
|
-
writeFileSync(
|
|
93
|
-
indexPath,
|
|
94
|
-
'export * from \'./api\'\nexport * from \'./types.d\'\n',
|
|
95
|
-
)
|
|
96
|
-
console.log('✅ Generated index.ts')
|
|
92
|
+
console.log('ℹ️ Stream utilities are imported from @bagelink/sdk')
|
|
97
93
|
|
|
98
94
|
if (splitFiles) {
|
|
99
95
|
console.log('\n🔀 Splitting into organized files...')
|
|
@@ -104,8 +100,9 @@ export async function generateSDK(
|
|
|
104
100
|
}
|
|
105
101
|
|
|
106
102
|
console.log('\n✅ SDK generated successfully!')
|
|
107
|
-
console.log(`\nImport
|
|
108
|
-
console.log(` import {
|
|
103
|
+
console.log(`\nImport directly in your code:`)
|
|
104
|
+
console.log(` import { agents } from '${outputDir.replace('./src/', './')}/api'`)
|
|
105
|
+
console.log(` import type { SendMessageRequest } from '${outputDir.replace('./src/', './')}/types.d'`)
|
|
109
106
|
console.log('')
|
|
110
107
|
}
|
|
111
108
|
catch (error: unknown) {
|
|
@@ -128,48 +125,87 @@ export async function generateSDK(
|
|
|
128
125
|
* Generate SDK for all projects in workspace
|
|
129
126
|
*/
|
|
130
127
|
export async function generateSDKForWorkspace(root: string = process.cwd()): Promise<void> {
|
|
131
|
-
console.log('\n🏢 Generating SDK for workspace
|
|
132
|
-
|
|
133
|
-
//
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
128
|
+
console.log('\n🏢 Generating SDK for workspace...\n')
|
|
129
|
+
|
|
130
|
+
// Try to load config
|
|
131
|
+
let config: WorkspaceConfig | null = null
|
|
132
|
+
let openApiUrl: string | undefined
|
|
133
|
+
|
|
134
|
+
try {
|
|
135
|
+
const configPath = resolve(root, 'bgl.config.ts')
|
|
136
|
+
if (existsSync(configPath)) {
|
|
137
|
+
const module = await import(`file://${configPath}`)
|
|
138
|
+
const workspace = module.default
|
|
139
|
+
if (typeof workspace === 'function') {
|
|
140
|
+
config = workspace('development')
|
|
141
|
+
if (config?.openapi_url) {
|
|
142
|
+
openApiUrl = config.openapi_url
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// Ignore config load errors
|
|
149
149
|
}
|
|
150
150
|
|
|
151
|
+
// Prompt for OpenAPI URL if not in config
|
|
151
152
|
const response = await prompts({
|
|
152
|
-
type: '
|
|
153
|
-
name: '
|
|
154
|
-
message: '
|
|
155
|
-
|
|
153
|
+
type: openApiUrl !== undefined ? null : 'text',
|
|
154
|
+
name: 'openApiUrl',
|
|
155
|
+
message: 'OpenAPI spec URL:',
|
|
156
|
+
initial: openApiUrl ?? 'http://localhost:8000/openapi.json',
|
|
156
157
|
})
|
|
157
158
|
|
|
158
|
-
if (
|
|
159
|
-
console.log('\n❌
|
|
160
|
-
|
|
159
|
+
if (response === undefined || (openApiUrl === undefined && !response.openApiUrl)) {
|
|
160
|
+
console.log('\n❌ SDK generation cancelled.\n')
|
|
161
|
+
process.exit(1)
|
|
161
162
|
}
|
|
162
163
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
164
|
+
const finalUrl = openApiUrl ?? response.openApiUrl
|
|
165
|
+
const outputDir = './shared'
|
|
166
|
+
|
|
167
|
+
console.log(`\n📡 Fetching OpenAPI spec from: ${finalUrl}`)
|
|
168
|
+
console.log(`📁 Output directory: ${outputDir}\n`)
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
// Dynamic import of @bagelink/sdk
|
|
172
|
+
const { openAPI } = await import('@bagelink/sdk')
|
|
173
|
+
|
|
174
|
+
const { types, code } = await openAPI(finalUrl, '/api')
|
|
175
|
+
|
|
176
|
+
const outputPath = resolve(root, outputDir)
|
|
177
|
+
if (!existsSync(outputPath)) {
|
|
178
|
+
mkdirSync(outputPath, { recursive: true })
|
|
168
179
|
}
|
|
169
|
-
|
|
170
|
-
|
|
180
|
+
|
|
181
|
+
// Write types
|
|
182
|
+
const typesPath = resolve(outputPath, 'types.d.ts')
|
|
183
|
+
writeFileSync(typesPath, types)
|
|
184
|
+
console.log('✅ Generated types.d.ts')
|
|
185
|
+
|
|
186
|
+
// Write API client
|
|
187
|
+
const apiPath = resolve(outputPath, 'api.ts')
|
|
188
|
+
writeFileSync(apiPath, code)
|
|
189
|
+
console.log('✅ Generated api.ts')
|
|
190
|
+
|
|
191
|
+
console.log('\n✅ SDK generated successfully in shared folder!')
|
|
192
|
+
console.log(`\nImport from shared in your projects:`)
|
|
193
|
+
console.log(` import { agents } from '../shared/api'`)
|
|
194
|
+
console.log(` import type { SendMessageRequest } from '../shared/types'`)
|
|
195
|
+
console.log('')
|
|
196
|
+
}
|
|
197
|
+
catch (error: unknown) {
|
|
198
|
+
console.error('\n❌ Failed to generate SDK:')
|
|
199
|
+
if (error instanceof Error) {
|
|
200
|
+
console.error(error.message)
|
|
171
201
|
}
|
|
202
|
+
else {
|
|
203
|
+
console.error(error)
|
|
204
|
+
}
|
|
205
|
+
console.log('\nMake sure:')
|
|
206
|
+
console.log(' 1. @bagelink/sdk is installed: bun add -D @bagelink/sdk')
|
|
207
|
+
console.log(' 2. OpenAPI URL is accessible')
|
|
208
|
+
console.log(' 3. API server is running (if using localhost)')
|
|
209
|
+
process.exit(1)
|
|
172
210
|
}
|
|
173
|
-
|
|
174
|
-
console.log('\n✅ All SDKs generated!')
|
|
175
211
|
}
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type WorkspaceEnvironment =
|
|
1
|
+
export type WorkspaceEnvironment = string
|
|
2
2
|
|
|
3
3
|
export interface WorkspaceConfig {
|
|
4
4
|
/**
|
|
@@ -8,10 +8,11 @@ export interface WorkspaceConfig {
|
|
|
8
8
|
host: string
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
12
|
-
*
|
|
11
|
+
* Optional proxy path to use for API requests
|
|
12
|
+
* If not set, no proxy will be configured for this environment
|
|
13
|
+
* @example '/api'
|
|
13
14
|
*/
|
|
14
|
-
proxy
|
|
15
|
+
proxy?: string
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* Optional OpenAPI specification URL for SDK generation
|
|
@@ -45,5 +46,10 @@ export interface ProxyConfig {
|
|
|
45
46
|
changeOrigin: boolean
|
|
46
47
|
rewrite?: (path: string) => string
|
|
47
48
|
secure: boolean
|
|
49
|
+
ws?: boolean
|
|
50
|
+
followRedirects?: boolean
|
|
51
|
+
autoRewrite?: boolean
|
|
52
|
+
protocolRewrite?: string
|
|
53
|
+
configure?: (proxy: any, options: any) => void
|
|
48
54
|
}
|
|
49
55
|
}
|
package/src/vite.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { Plugin, ResolvedConfig } from 'vite'
|
|
2
|
+
import type { WorkspaceConfig, WorkspaceEnvironment } from './types'
|
|
3
|
+
import { basename } from 'node:path'
|
|
4
|
+
import process from 'node:process'
|
|
5
|
+
import { fileURLToPath } from 'node:url'
|
|
6
|
+
import { createViteProxy } from './proxy'
|
|
7
|
+
import { listProjects } from './workspace.js'
|
|
8
|
+
|
|
9
|
+
export { generateNetlifyConfig, setBuildEnvVars, writeNetlifyConfig } from './netlify'
|
|
10
|
+
// Re-export proxy utilities for convenience
|
|
11
|
+
export { createCustomProxy, createViteProxy } from './proxy'
|
|
12
|
+
|
|
13
|
+
export interface BagelinkPluginOptions {
|
|
14
|
+
/**
|
|
15
|
+
* Path to shared package relative to project
|
|
16
|
+
* @default '../shared'
|
|
17
|
+
*/
|
|
18
|
+
sharedPath?: string
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Whether to include @shared alias
|
|
22
|
+
* @default true
|
|
23
|
+
*/
|
|
24
|
+
includeSharedAlias?: boolean
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Additional path aliases beyond @ and @shared
|
|
28
|
+
*/
|
|
29
|
+
additionalAliases?: Record<string, string>
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Whether to auto-configure proxy
|
|
33
|
+
* @default true
|
|
34
|
+
*/
|
|
35
|
+
configureProxy?: boolean
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Vite plugin for Bagelink workspace integration
|
|
40
|
+
* Automatically configures proxy and path aliases based on bgl.config.ts
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* import { defineConfig } from 'vite'
|
|
45
|
+
* import vue from '@vitejs/plugin-vue'
|
|
46
|
+
* import { bagelink } from '@bagelink/workspace/vite'
|
|
47
|
+
* import workspace from './bgl.config'
|
|
48
|
+
*
|
|
49
|
+
* export default defineConfig({
|
|
50
|
+
* plugins: [
|
|
51
|
+
* vue(),
|
|
52
|
+
* bagelink({ workspace })
|
|
53
|
+
* ]
|
|
54
|
+
* })
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @example With custom options
|
|
58
|
+
* ```ts
|
|
59
|
+
* import { defineConfig } from 'vite'
|
|
60
|
+
* import vue from '@vitejs/plugin-vue'
|
|
61
|
+
* import { bagelink } from '@bagelink/workspace/vite'
|
|
62
|
+
* import workspace from './bgl.config'
|
|
63
|
+
*
|
|
64
|
+
* export default defineConfig({
|
|
65
|
+
* plugins: [
|
|
66
|
+
* vue(),
|
|
67
|
+
* bagelink({
|
|
68
|
+
* workspace,
|
|
69
|
+
* sharedPath: '../packages/shared',
|
|
70
|
+
* additionalAliases: {
|
|
71
|
+
* '@utils': fileURLToPath(new URL('./src/utils', import.meta.url))
|
|
72
|
+
* }
|
|
73
|
+
* })
|
|
74
|
+
* ]
|
|
75
|
+
* })
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export function bagelink(options: {
|
|
79
|
+
workspace: (mode: WorkspaceEnvironment) => WorkspaceConfig
|
|
80
|
+
config?: BagelinkPluginOptions
|
|
81
|
+
}): Plugin {
|
|
82
|
+
const { workspace, config = {} } = options
|
|
83
|
+
let resolvedConfig: ResolvedConfig
|
|
84
|
+
let workspaceConfig: WorkspaceConfig
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
name: 'vite-plugin-bagelink',
|
|
88
|
+
enforce: 'pre',
|
|
89
|
+
|
|
90
|
+
configResolved(resolved) {
|
|
91
|
+
resolvedConfig = resolved
|
|
92
|
+
workspaceConfig = workspace(resolved.mode as WorkspaceEnvironment)
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
config(userConfig, { mode }) {
|
|
96
|
+
workspaceConfig = workspace(mode as WorkspaceEnvironment)
|
|
97
|
+
|
|
98
|
+
// Build alias configuration
|
|
99
|
+
const alias: Record<string, string> = {}
|
|
100
|
+
|
|
101
|
+
// Add @shared alias if enabled
|
|
102
|
+
if (config.includeSharedAlias !== false) {
|
|
103
|
+
const sharedPath = config.sharedPath ?? '../shared'
|
|
104
|
+
// Resolve relative to the project root
|
|
105
|
+
alias['@shared'] = fileURLToPath(new URL(sharedPath, `file://${process.cwd()}/`))
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Add @ alias pointing to src
|
|
109
|
+
alias['@'] = fileURLToPath(new URL('./src', `file://${process.cwd()}/`))
|
|
110
|
+
|
|
111
|
+
// Add any additional aliases
|
|
112
|
+
if (config.additionalAliases) {
|
|
113
|
+
Object.assign(alias, config.additionalAliases)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Compute port based on alphabetical order in workspace
|
|
117
|
+
let port: number | undefined
|
|
118
|
+
try {
|
|
119
|
+
const currentDir = process.cwd()
|
|
120
|
+
const projectName = basename(currentDir)
|
|
121
|
+
const parentDir = fileURLToPath(new URL('..', `file://${currentDir}/`))
|
|
122
|
+
const allProjects = listProjects(parentDir) // Already sorted alphabetically
|
|
123
|
+
const projectIndex = allProjects.indexOf(projectName)
|
|
124
|
+
|
|
125
|
+
if (projectIndex !== -1) {
|
|
126
|
+
port = 5173 + projectIndex
|
|
127
|
+
}
|
|
128
|
+
} catch {
|
|
129
|
+
// If we can't determine the workspace, don't set a port
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Build server config with proxy and consistent port
|
|
133
|
+
const server = {
|
|
134
|
+
...(config.configureProxy !== false && {
|
|
135
|
+
proxy: createViteProxy(workspaceConfig),
|
|
136
|
+
}),
|
|
137
|
+
...(port !== undefined && {
|
|
138
|
+
port,
|
|
139
|
+
strictPort: false, // use next available port if preferred is taken
|
|
140
|
+
}),
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Inject workspace config as environment variables
|
|
144
|
+
const define = {
|
|
145
|
+
...(workspaceConfig.proxy && {
|
|
146
|
+
'import.meta.env.VITE_BGL_PROXY': JSON.stringify(workspaceConfig.proxy),
|
|
147
|
+
}),
|
|
148
|
+
'import.meta.env.VITE_BGL_HOST': JSON.stringify(workspaceConfig.host),
|
|
149
|
+
...(workspaceConfig.openapi_url && {
|
|
150
|
+
'import.meta.env.VITE_BGL_OPENAPI_URL': JSON.stringify(workspaceConfig.openapi_url),
|
|
151
|
+
}),
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
resolve: {
|
|
156
|
+
alias,
|
|
157
|
+
},
|
|
158
|
+
define,
|
|
159
|
+
server,
|
|
160
|
+
optimizeDeps: {
|
|
161
|
+
exclude: ['@bagelink/workspace'],
|
|
162
|
+
},
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
}
|
|
166
|
+
}
|
package/src/workspace.ts
CHANGED
|
@@ -87,12 +87,27 @@ function createWorkspaceRoot(root: string, name: string, projectId: string): voi
|
|
|
87
87
|
private: true,
|
|
88
88
|
workspaces: ['*', '!node_modules'],
|
|
89
89
|
scripts: {
|
|
90
|
-
dev: '
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
'dev': 'bgl dev',
|
|
91
|
+
'dev:local': 'bgl dev --mode localhost',
|
|
92
|
+
'dev:verbose': 'bun run --filter \'./!shared*\' dev',
|
|
93
|
+
'build': 'bgl build',
|
|
94
|
+
'typecheck': 'tsc --noEmit',
|
|
95
|
+
'lint': 'eslint . --cache',
|
|
96
|
+
'lint:fix': 'eslint . --cache --fix',
|
|
97
|
+
},
|
|
98
|
+
dependencies: {
|
|
99
|
+
'@bagelink/auth': 'latest',
|
|
100
|
+
'@bagelink/sdk': 'latest',
|
|
101
|
+
'@bagelink/vue': 'latest',
|
|
102
|
+
'pinia': 'latest',
|
|
103
|
+
'vue': 'latest',
|
|
104
|
+
'vue-router': 'latest',
|
|
93
105
|
},
|
|
94
106
|
devDependencies: {
|
|
107
|
+
'@bagelink/lint-config': 'latest',
|
|
95
108
|
'@bagelink/workspace': 'latest',
|
|
109
|
+
'@vitejs/plugin-vue': 'latest',
|
|
110
|
+
'eslint': 'latest',
|
|
96
111
|
'typescript': '^5.0.0',
|
|
97
112
|
'vite': 'latest',
|
|
98
113
|
},
|
|
@@ -106,10 +121,15 @@ function createWorkspaceRoot(root: string, name: string, projectId: string): voi
|
|
|
106
121
|
// bgl.config.ts (shared)
|
|
107
122
|
const bglConfig = `import { defineWorkspace } from '@bagelink/workspace'
|
|
108
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Define your workspace environments
|
|
126
|
+
* You can add as many custom environments as needed (e.g., 'staging', 'preview')
|
|
127
|
+
* Use --mode flag to switch: bgl dev --mode <env_name>
|
|
128
|
+
*/
|
|
109
129
|
export default defineWorkspace({
|
|
110
130
|
localhost: {
|
|
111
131
|
host: 'http://localhost:8000',
|
|
112
|
-
proxy: '/api',
|
|
132
|
+
proxy: '/api', // Optional: remove to skip proxy setup
|
|
113
133
|
openapi_url: 'http://localhost:8000/openapi.json',
|
|
114
134
|
},
|
|
115
135
|
development: {
|
|
@@ -168,6 +188,77 @@ dist
|
|
|
168
188
|
|
|
169
189
|
writeFileSync(resolve(workspaceDir, '.gitignore'), gitignore)
|
|
170
190
|
|
|
191
|
+
// Create scripts directory
|
|
192
|
+
const scriptsDir = resolve(workspaceDir, 'scripts')
|
|
193
|
+
mkdirSync(scriptsDir, { recursive: true })
|
|
194
|
+
|
|
195
|
+
// Copy dev runner script
|
|
196
|
+
const devRunnerContent = `#!/usr/bin/env bun
|
|
197
|
+
import { spawn } from 'bun'
|
|
198
|
+
import { readdir } from 'fs/promises'
|
|
199
|
+
import { resolve } from 'path'
|
|
200
|
+
|
|
201
|
+
const projectsRoot = process.cwd()
|
|
202
|
+
const projects = (await readdir(projectsRoot, { withFileTypes: true }))
|
|
203
|
+
.filter(
|
|
204
|
+
item =>
|
|
205
|
+
item.isDirectory()
|
|
206
|
+
&& item.name !== 'node_modules'
|
|
207
|
+
&& item.name !== 'shared'
|
|
208
|
+
&& item.name !== 'scripts'
|
|
209
|
+
&& item.name !== '.git'
|
|
210
|
+
&& !item.name.startsWith('.'),
|
|
211
|
+
)
|
|
212
|
+
.map(item => item.name)
|
|
213
|
+
|
|
214
|
+
console.log(\`\\n🚀 Starting \${projects.length} project\${projects.length > 1 ? 's' : ''}...\\n\`)
|
|
215
|
+
|
|
216
|
+
const urlPattern = /Local:\\s+(http:\\/\\/localhost:\\d+)/
|
|
217
|
+
|
|
218
|
+
projects.forEach((project) => {
|
|
219
|
+
const proc = spawn({
|
|
220
|
+
cmd: ['bun', 'run', 'dev'],
|
|
221
|
+
cwd: resolve(projectsRoot, project),
|
|
222
|
+
stdout: 'pipe',
|
|
223
|
+
stderr: 'pipe',
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
const decoder = new TextDecoder()
|
|
227
|
+
|
|
228
|
+
proc.stdout.pipeTo(
|
|
229
|
+
new WritableStream({
|
|
230
|
+
write(chunk) {
|
|
231
|
+
const text = decoder.decode(chunk)
|
|
232
|
+
const match = text.match(urlPattern)
|
|
233
|
+
if (match) {
|
|
234
|
+
console.log(\` ✓ \${project.padEnd(15)} → \${match[1]}\`)
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
}),
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
proc.stderr.pipeTo(
|
|
241
|
+
new WritableStream({
|
|
242
|
+
write(chunk) {
|
|
243
|
+
const text = decoder.decode(chunk)
|
|
244
|
+
if (text.includes('error') || text.includes('Error')) {
|
|
245
|
+
console.error(\` ✗ \${project}: \${text.trim()}\`)
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
}),
|
|
249
|
+
)
|
|
250
|
+
})
|
|
251
|
+
|
|
252
|
+
console.log('\\n💡 Press Ctrl+C to stop all servers\\n')
|
|
253
|
+
|
|
254
|
+
process.on('SIGINT', () => {
|
|
255
|
+
console.log('\\n\\n👋 Stopping all servers...\\n')
|
|
256
|
+
process.exit()
|
|
257
|
+
})
|
|
258
|
+
`
|
|
259
|
+
|
|
260
|
+
writeFileSync(resolve(scriptsDir, 'dev.ts'), devRunnerContent)
|
|
261
|
+
|
|
171
262
|
console.log(`✅ Created workspace: ${name}`)
|
|
172
263
|
}
|
|
173
264
|
|
|
@@ -300,18 +391,14 @@ export default defineWorkspace({
|
|
|
300
391
|
// vite.config.ts
|
|
301
392
|
const viteConfig = `import { defineConfig } from 'vite'
|
|
302
393
|
import vue from '@vitejs/plugin-vue'
|
|
303
|
-
import {
|
|
394
|
+
import { bagelink } from '@bagelink/workspace/vite'
|
|
304
395
|
import workspace from './bgl.config'
|
|
305
396
|
|
|
306
|
-
export default defineConfig(
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
server: {
|
|
312
|
-
proxy: createViteProxy(config),
|
|
313
|
-
},
|
|
314
|
-
}
|
|
397
|
+
export default defineConfig({
|
|
398
|
+
plugins: [
|
|
399
|
+
vue(),
|
|
400
|
+
bagelink({ workspace }),
|
|
401
|
+
],
|
|
315
402
|
})
|
|
316
403
|
`
|
|
317
404
|
|
|
@@ -340,9 +427,12 @@ export default defineConfig(({ mode }) => {
|
|
|
340
427
|
|
|
341
428
|
// main.ts
|
|
342
429
|
const mainTs = `import { createApp } from 'vue'
|
|
430
|
+
import { BagelVue } from '@bagelink/vue'
|
|
343
431
|
import App from './App.vue'
|
|
344
432
|
|
|
345
|
-
createApp(App)
|
|
433
|
+
createApp(App)
|
|
434
|
+
.use(BagelVue)
|
|
435
|
+
.mount('#app')
|
|
346
436
|
`
|
|
347
437
|
|
|
348
438
|
writeFileSync(resolve(srcDir, 'main.ts'), mainTs)
|
|
@@ -412,7 +502,7 @@ function updateWorkspaceScripts(root: string, projectName: string): void {
|
|
|
412
502
|
}
|
|
413
503
|
|
|
414
504
|
/**
|
|
415
|
-
* List all projects in workspace
|
|
505
|
+
* List all projects in workspace (sorted alphabetically for consistent ordering)
|
|
416
506
|
*/
|
|
417
507
|
export function listProjects(root: string = process.cwd()): string[] {
|
|
418
508
|
try {
|
|
@@ -422,10 +512,25 @@ export function listProjects(root: string = process.cwd()): string[] {
|
|
|
422
512
|
item => item.isDirectory()
|
|
423
513
|
&& item.name !== 'node_modules'
|
|
424
514
|
&& item.name !== 'shared'
|
|
515
|
+
&& item.name !== 'scripts'
|
|
425
516
|
&& item.name !== '.git'
|
|
426
517
|
&& !item.name.startsWith('.'),
|
|
427
518
|
)
|
|
519
|
+
.filter((item) => {
|
|
520
|
+
// Only include directories with package.json that has a dev script
|
|
521
|
+
const packageJsonPath = resolve(root, item.name, 'package.json')
|
|
522
|
+
if (!existsSync(packageJsonPath)) return false
|
|
523
|
+
|
|
524
|
+
try {
|
|
525
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'))
|
|
526
|
+
return packageJson.scripts?.dev !== undefined
|
|
527
|
+
}
|
|
528
|
+
catch {
|
|
529
|
+
return false
|
|
530
|
+
}
|
|
531
|
+
})
|
|
428
532
|
.map(item => item.name)
|
|
533
|
+
.sort() // Sort alphabetically for consistent port assignment
|
|
429
534
|
}
|
|
430
535
|
catch {
|
|
431
536
|
return []
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import { spawn } from 'bun'
|
|
3
|
+
import { readdir } from 'fs/promises'
|
|
4
|
+
import { resolve } from 'path'
|
|
5
|
+
|
|
6
|
+
const projectsRoot = process.cwd()
|
|
7
|
+
const projects = (await readdir(projectsRoot, { withFileTypes: true }))
|
|
8
|
+
.filter(
|
|
9
|
+
item =>
|
|
10
|
+
item.isDirectory()
|
|
11
|
+
&& item.name !== 'node_modules'
|
|
12
|
+
&& item.name !== 'shared'
|
|
13
|
+
&& item.name !== '.git'
|
|
14
|
+
&& !item.name.startsWith('.'),
|
|
15
|
+
)
|
|
16
|
+
.map(item => item.name)
|
|
17
|
+
|
|
18
|
+
console.log(`\n🚀 Starting ${projects.length} project${projects.length > 1 ? 's' : ''}...\n`)
|
|
19
|
+
|
|
20
|
+
const urlPattern = /Local:\s+(http:\/\/localhost:\d+)/
|
|
21
|
+
|
|
22
|
+
projects.forEach((project) => {
|
|
23
|
+
const proc = spawn({
|
|
24
|
+
cmd: ['bun', 'run', 'dev'],
|
|
25
|
+
cwd: resolve(projectsRoot, project),
|
|
26
|
+
stdout: 'pipe',
|
|
27
|
+
stderr: 'pipe',
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
const decoder = new TextDecoder()
|
|
31
|
+
|
|
32
|
+
proc.stdout.pipeTo(
|
|
33
|
+
new WritableStream({
|
|
34
|
+
write(chunk) {
|
|
35
|
+
const text = decoder.decode(chunk)
|
|
36
|
+
const match = text.match(urlPattern)
|
|
37
|
+
if (match) {
|
|
38
|
+
console.log(` ✓ ${project.padEnd(15)} → ${match[1]}`)
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
}),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
proc.stderr.pipeTo(
|
|
45
|
+
new WritableStream({
|
|
46
|
+
write(chunk) {
|
|
47
|
+
const text = decoder.decode(chunk)
|
|
48
|
+
if (text.includes('error') || text.includes('Error')) {
|
|
49
|
+
console.error(` ✗ ${project}: ${text.trim()}`)
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
}),
|
|
53
|
+
)
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
console.log('\n💡 Press Ctrl+C to stop all servers\n')
|
|
57
|
+
|
|
58
|
+
process.on('SIGINT', () => {
|
|
59
|
+
console.log('\n\n👋 Stopping all servers...\n')
|
|
60
|
+
process.exit()
|
|
61
|
+
})
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"composite": true,
|
|
5
|
+
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
6
|
+
"baseUrl": ".",
|
|
7
|
+
"paths": {
|
|
8
|
+
"@/*": [
|
|
9
|
+
"./src/*"
|
|
10
|
+
],
|
|
11
|
+
"@shared/*": [
|
|
12
|
+
"../shared/*"
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"include": [
|
|
17
|
+
"src/**/*",
|
|
18
|
+
"src/**/*.vue"
|
|
19
|
+
],
|
|
20
|
+
"exclude": [
|
|
21
|
+
"node_modules"
|
|
22
|
+
]
|
|
23
|
+
}
|