@open-dy/vibecoding-cli 0.0.1-beta.1

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 (54) hide show
  1. package/README.md +47 -0
  2. package/assets/schemas/custom-card-schema.json +102 -0
  3. package/bin/vibecoding +89 -0
  4. package/bin/vibecoding-dev +308 -0
  5. package/bin/vibecoding-interest-card.mjs +35 -0
  6. package/bin/vibecoding.mjs +9 -0
  7. package/package.json +58 -0
  8. package/src/adapters/interest-card/opencard/commands.mjs +62 -0
  9. package/src/adapters/interest-card/opencard/dev-watch.mjs +203 -0
  10. package/src/adapters/interest-card/opencard/dev_run.sh +126 -0
  11. package/src/adapters/interest-card/opencard/eslint-plugin-opencard-taro.mjs +278 -0
  12. package/src/adapters/interest-card/opencard/lint-lynx-css.mjs +676 -0
  13. package/src/adapters/interest-card/opencard/lint.sh +131 -0
  14. package/src/adapters/interest-card/opencard/lynx-css-rules.mjs +508 -0
  15. package/src/adapters/interest-card/opencard/pack.sh +27 -0
  16. package/src/adapters/interest-card/opencard/validate-opencard-structure.mjs +65 -0
  17. package/src/adapters/interest-card/opencard/validate-widget-shell.mjs +902 -0
  18. package/src/adapters/interest-card/opencard/validate.mjs +11 -0
  19. package/src/adapters/interest-card/opencard/write-web-config.mjs +17 -0
  20. package/src/build/opencard-environment.mjs +49 -0
  21. package/src/build/turbo-config.mjs +140 -0
  22. package/src/cli.mjs +104 -0
  23. package/src/commands/build.mjs +138 -0
  24. package/src/commands/db.mjs +14 -0
  25. package/src/commands/dev.mjs +319 -0
  26. package/src/commands/lint.mjs +176 -0
  27. package/src/commands/pack.mjs +169 -0
  28. package/src/commands/turbo.mjs +36 -0
  29. package/src/commands/validate.mjs +26 -0
  30. package/src/commands/verify.mjs +602 -0
  31. package/src/core/args.mjs +101 -0
  32. package/src/core/context.mjs +101 -0
  33. package/src/core/environment.mjs +55 -0
  34. package/src/core/errors.mjs +14 -0
  35. package/src/core/ports.mjs +76 -0
  36. package/src/core/process-output.mjs +25 -0
  37. package/src/core/runner.mjs +90 -0
  38. package/src/core/service-log-context.mjs +27 -0
  39. package/src/core/web-config.mjs +13 -0
  40. package/src/lint/lint-lynx-css.mjs +244 -0
  41. package/src/lint/lynx-css-rules.mjs +138 -0
  42. package/src/preview/dev-watch.mjs +38 -0
  43. package/src/preview/start-preview.mjs +213 -0
  44. package/src/preview/watch-card-routing.mjs +89 -0
  45. package/src/scripts/pack.mjs +15 -0
  46. package/src/validators/dependencies.mjs +34 -0
  47. package/src/validators/empty-project.mjs +29 -0
  48. package/src/validators/feed-card.cjs +156 -0
  49. package/src/validators/feed-card.mjs +32 -0
  50. package/src/validators/opencard-structure.mjs +58 -0
  51. package/src/validators/routes.cjs +470 -0
  52. package/src/validators/routes.mjs +17 -0
  53. package/src/validators/sql.mjs +57 -0
  54. package/src/validators/widget-shell.mjs +107 -0
@@ -0,0 +1,11 @@
1
+ // Internal entry used by both the CLI and the original parallel lint script.
2
+ const [root, name] = process.argv.slice(2)
3
+ const modules = {
4
+ 'opencard-structure': './validate-opencard-structure.mjs',
5
+ 'widget-shell': './validate-widget-shell.mjs',
6
+ 'lynx-css': './lint-lynx-css.mjs',
7
+ }
8
+ if (!root || !Object.hasOwn(modules, name)) throw new Error('Expected project root and validator name')
9
+ process.env.VIBECODING_OPENCARD_ROOT = root
10
+ const { main } = await import(modules[name])
11
+ main()
@@ -0,0 +1,17 @@
1
+ import { writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+
4
+ const outputRoot = process.argv[2]?.trim();
5
+ if (!outputRoot) {
6
+ throw new Error('write-web-config requires an output root');
7
+ }
8
+
9
+ const config = {
10
+ hasAuditDouyinCloud: true,
11
+ };
12
+
13
+ await writeFile(
14
+ path.resolve(outputRoot, 'web.config.json'),
15
+ `${JSON.stringify(config, null, 2)}\n`,
16
+ 'utf8',
17
+ );
@@ -0,0 +1,49 @@
1
+ import fs from 'node:fs'
2
+ import path from 'node:path'
3
+
4
+ /** Locate host routing for standalone preview callers without a resolved CLI context. */
5
+ function findRoutingPath(cardRoot) {
6
+ let root = path.dirname(path.resolve(cardRoot))
7
+ while (true) {
8
+ const file = path.join(root, 'config/card-routing.json')
9
+ if (fs.existsSync(file)) return file
10
+ // Do not borrow configuration from outside the owning project/repository.
11
+ if (fs.existsSync(path.join(root, 'package.json')) || fs.existsSync(path.join(root, '.git'))) return file
12
+ const parent = path.dirname(root)
13
+ if (parent === root) return file
14
+ root = parent
15
+ }
16
+ }
17
+
18
+ /** Read the host configuration; missing routing retains the legacy open-domain default. */
19
+ export function resolveCardRoutingPath(context) {
20
+ return context.taroRoot
21
+ ? path.join(context.taroRoot, 'config/card-routing.json')
22
+ : findRoutingPath(context.root)
23
+ }
24
+
25
+ export function readCardRouting(context) {
26
+ const file = resolveCardRoutingPath(context)
27
+ let raw
28
+ try {
29
+ raw = fs.readFileSync(file, 'utf8')
30
+ } catch (error) {
31
+ if (error.code === 'ENOENT') return {}
32
+ throw error
33
+ }
34
+ let routing
35
+ try {
36
+ routing = JSON.parse(raw)
37
+ } catch (error) {
38
+ throw new Error(`${file} must contain valid JSON: ${error.message}`)
39
+ }
40
+ if (!['closed', 'open', 'none', undefined].includes(routing?.cardData?.serviceDomain)) {
41
+ throw new Error(`${file} cardData.serviceDomain must be none, open, or closed`)
42
+ }
43
+ return routing
44
+ }
45
+
46
+ /** Pass to the compiler child only; never mutate the CLI process environment. */
47
+ export function openCardBuildEnvironment(context) {
48
+ return { IS_CARD_CLOSED_DOMAIN: String(readCardRouting(context)?.cardData?.serviceDomain === 'closed') }
49
+ }
@@ -0,0 +1,140 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
2
+ import path from 'node:path'
3
+ import { CliError } from '../core/errors.mjs'
4
+
5
+ const ARRAY_FIELDS = new Set(['env', 'inputs', 'outputs', 'dependsOn'])
6
+
7
+ // These settings are part of the CLI contract. They are kept here, rather
8
+ // than in generated projects, so all projects receive the same cache key and
9
+ // closed-domain environment behavior as the CLI is upgraded.
10
+ const OPENCARD_DEFAULTS = {
11
+ tasks: {
12
+ 'build:raw': {
13
+ env: ['IS_CARD_CLOSED_DOMAIN'],
14
+ inputs: ['../config/card-routing.json'],
15
+ },
16
+ },
17
+ }
18
+
19
+ const TARO_DEFAULTS = {
20
+ tasks: {
21
+ '//#build:tt:raw': {
22
+ env: ['IS_CARD_CLOSED_DOMAIN'],
23
+ inputs: ['config/card-routing.json'],
24
+ },
25
+ },
26
+ }
27
+
28
+ function clone(value) {
29
+ if (Array.isArray(value)) return value.map(clone)
30
+ if (value && typeof value === 'object') {
31
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, clone(entry)]))
32
+ }
33
+ return value
34
+ }
35
+
36
+ function mergeValues(defaultValue, projectValue, key) {
37
+ if (ARRAY_FIELDS.has(key) && Array.isArray(projectValue)) {
38
+ return [...new Set([...(Array.isArray(defaultValue) ? defaultValue : []), ...projectValue])]
39
+ }
40
+ if (Array.isArray(defaultValue) && Array.isArray(projectValue)) {
41
+ return [...new Set([...defaultValue, ...projectValue])]
42
+ }
43
+ if (
44
+ defaultValue && typeof defaultValue === 'object' &&
45
+ projectValue && typeof projectValue === 'object' &&
46
+ !Array.isArray(defaultValue) && !Array.isArray(projectValue)
47
+ ) {
48
+ return mergeObject(defaultValue, projectValue)
49
+ }
50
+ return clone(projectValue === undefined ? defaultValue : projectValue)
51
+ }
52
+
53
+ function mergeObject(defaultObject, projectObject) {
54
+ const result = clone(defaultObject)
55
+ for (const [key, projectValue] of Object.entries(projectObject ?? {})) {
56
+ result[key] = mergeValues(result[key], projectValue, key)
57
+ }
58
+ return result
59
+ }
60
+
61
+ function ensureRequiredTargetConfig(config, defaults) {
62
+ const taskName = Object.keys(defaults.tasks)[0]
63
+ const tasks = config.tasks && typeof config.tasks === 'object' && !Array.isArray(config.tasks)
64
+ ? config.tasks
65
+ : {}
66
+ const task = tasks[taskName] && typeof tasks[taskName] === 'object' && !Array.isArray(tasks[taskName])
67
+ ? tasks[taskName]
68
+ : {}
69
+ for (const field of ['env', 'inputs']) {
70
+ const required = defaults.tasks[Object.keys(defaults.tasks)[0]][field]
71
+ const project = Array.isArray(task[field]) ? task[field] : []
72
+ task[field] = [...new Set([...required, ...project])]
73
+ }
74
+ tasks[taskName] = task
75
+ config.tasks = tasks
76
+ return config
77
+ }
78
+
79
+ export function mergeTurboConfig(defaultConfig, projectConfig) {
80
+ return mergeObject(defaultConfig, projectConfig)
81
+ }
82
+
83
+ export function readTurboConfig(projectRoot) {
84
+ const file = path.join(projectRoot, 'turbo.json')
85
+ if (!existsSync(file)) return {}
86
+ try {
87
+ const config = JSON.parse(readFileSync(file, 'utf8'))
88
+ if (!config || typeof config !== 'object' || Array.isArray(config)) {
89
+ throw new Error('the root value must be a JSON object')
90
+ }
91
+ if ('tasks' in config && (!config.tasks || typeof config.tasks !== 'object' || Array.isArray(config.tasks))) {
92
+ throw new Error('tasks must be a JSON object')
93
+ }
94
+ for (const [taskName, task] of Object.entries(config.tasks ?? {})) {
95
+ if (!task || typeof task !== 'object' || Array.isArray(task)) {
96
+ throw new Error(`tasks.${taskName} must be a JSON object`)
97
+ }
98
+ for (const field of ARRAY_FIELDS) {
99
+ if (field in task && !Array.isArray(task[field])) {
100
+ throw new Error(`tasks.${taskName}.${field} must be an array`)
101
+ }
102
+ }
103
+ }
104
+ return config
105
+ } catch (error) {
106
+ throw new CliError(`Cannot read ${file}: ${error.message}`)
107
+ }
108
+ }
109
+
110
+ export function resolveTurboDefaults({ target }) {
111
+ if (target === 'opencard') return clone(OPENCARD_DEFAULTS)
112
+ if (target === 'taro') return clone(TARO_DEFAULTS)
113
+ return {}
114
+ }
115
+
116
+ export function resolveTurboConfig({ projectRoot, target }) {
117
+ const config = mergeTurboConfig(resolveTurboDefaults({ target }), readTurboConfig(projectRoot))
118
+ const defaults = resolveTurboDefaults({ target })
119
+ return target === 'opencard' || target === 'taro'
120
+ ? ensureRequiredTargetConfig(config, defaults)
121
+ : config
122
+ }
123
+
124
+ export function writeTurboConfig(projectRoot, config) {
125
+ const directory = path.join(projectRoot, '.vibecoding', 'cache')
126
+ const file = path.join(directory, 'turbo.json')
127
+ mkdirSync(directory, { recursive: true })
128
+ const content = `${JSON.stringify(config, null, 2)}\n`
129
+ try {
130
+ if (readFileSync(file, 'utf8') === content) return file
131
+ } catch (error) {
132
+ if (error.code !== 'ENOENT') throw error
133
+ }
134
+ writeFileSync(file, content)
135
+ return file
136
+ }
137
+
138
+ export function prepareTurboConfig({ projectRoot, target }) {
139
+ return writeTurboConfig(projectRoot, resolveTurboConfig({ projectRoot, target }))
140
+ }
package/src/cli.mjs ADDED
@@ -0,0 +1,104 @@
1
+ import { parseArgs, requireTarget, resolveBuildScope } from './core/args.mjs'
2
+ import { inferProjectTarget, resolveProjectContext } from './core/context.mjs'
3
+ import { UsageError } from './core/errors.mjs'
4
+ import { runBuild } from './commands/build.mjs'
5
+ import { runDatabaseInit } from './commands/db.mjs'
6
+ import { runDevWatch } from './preview/dev-watch.mjs'
7
+ import { runDev } from './commands/dev.mjs'
8
+ import { runLint } from './commands/lint.mjs'
9
+ import { runPack } from './commands/pack.mjs'
10
+ import { runValidate } from './commands/validate.mjs'
11
+ import { runVerify } from './commands/verify.mjs'
12
+ import { runTurbo } from './commands/turbo.mjs'
13
+
14
+ const HELP = `Usage: vibecoding <command> [options]
15
+
16
+ Commands:
17
+ dev Start development services and previews
18
+ dev-watch Start only the frontend preview
19
+ build Build the selected target
20
+ lint Type-check, lint and validate source structure
21
+ verify Run static and/or runtime verification
22
+ validate <name> Run feed-card, routes, empty or opencard-structure
23
+ init-mysql-db Initialize the Taro server database
24
+ pack Build deployment archives
25
+ turbo <args...> Run Turbo with CLI defaults and project config
26
+
27
+ Required:
28
+ --target taro|opencard Required by project commands; turbo can infer it from the project root
29
+
30
+ Options:
31
+ --cwd <path> Project directory (default: current directory)
32
+ --scope tt Build only the Taro TT output
33
+ --skip-install Do not install dependencies before dev
34
+ --skip-root-install Skip the root install but still install nested targets before dev
35
+ --incremental Lint changed files when possible
36
+ --full Verify static and runtime phases
37
+ --runtime-only Verify runtime only
38
+ --static-only Verify static phase only
39
+ --ports-only Verify listening ports only
40
+ --auto-start Start dev once when verify finds missing ports
41
+ --timeout <seconds> Dev startup timeout (default: 90)
42
+ --frontend-url <url> Override the primary runtime-check URL`
43
+
44
+ function assertNoExtra(positionals, count, command) {
45
+ if (positionals.length > count) throw new UsageError(`Unexpected argument for ${command}: ${positionals[count]}`)
46
+ }
47
+
48
+ /**
49
+ * @desc 解析 vibecoding 命令行参数并调度对应的工程操作。
50
+ * @params {string[]} [argv] 命令行参数;默认读取 process.argv。
51
+ * @return {Promise<void>} 命令执行完成的 Promise。
52
+ * @example main(['build', '--target', 'taro'])
53
+ */
54
+ export async function main(argv = process.argv.slice(2)) {
55
+ const { positionals, flags, passthrough } = parseArgs(argv)
56
+ const command = positionals[0]
57
+ if (flags.help || !command) {
58
+ console.log(HELP)
59
+ return
60
+ }
61
+ if (command === 'turbo') {
62
+ const target = flags.target ?? inferProjectTarget({ cwd: flags.cwd })
63
+ const context = resolveProjectContext({ cwd: flags.cwd, target })
64
+ return runTurbo(context, {
65
+ args: [...positionals.slice(1), ...passthrough],
66
+ })
67
+ }
68
+
69
+ const target = requireTarget(flags)
70
+ const scope = resolveBuildScope(command, target, flags)
71
+ const context = resolveProjectContext({ cwd: flags.cwd, target })
72
+ const options = {
73
+ skipInstall: flags['skip-install'],
74
+ skipRootInstall: flags['skip-root-install'],
75
+ incremental: flags.incremental,
76
+ full: flags.full,
77
+ runtimeOnly: flags['runtime-only'],
78
+ staticOnly: flags['static-only'],
79
+ portsOnly: flags['ports-only'],
80
+ autoStart: flags['auto-start'],
81
+ timeoutSeconds: flags.timeout ? Number(flags.timeout) : 90,
82
+ frontendUrl: flags['frontend-url'],
83
+ scope,
84
+ }
85
+ if (!Number.isFinite(options.timeoutSeconds) || options.timeoutSeconds <= 0) {
86
+ throw new UsageError('--timeout must be a positive number')
87
+ }
88
+
89
+ switch (command) {
90
+ case 'dev': assertNoExtra(positionals, 1, command); return runDev(context, options)
91
+ case 'dev-watch':
92
+ assertNoExtra(positionals, 1, command)
93
+ return runDevWatch({ root: context.root, cardMode: target === 'opencard' })
94
+ case 'build': assertNoExtra(positionals, 1, command); return runBuild(context, options)
95
+ case 'lint': assertNoExtra(positionals, 1, command); return runLint(context, options)
96
+ case 'verify': assertNoExtra(positionals, 1, command); return runVerify(context, options)
97
+ case 'pack': assertNoExtra(positionals, 1, command); return runPack(context, options)
98
+ case 'init-mysql-db': assertNoExtra(positionals, 1, command); return runDatabaseInit(context)
99
+ case 'validate':
100
+ assertNoExtra(positionals, 2, command)
101
+ return runValidate(context, positionals[1])
102
+ default: throw new UsageError(`Unknown command: ${command}\n\n${HELP}`)
103
+ }
104
+ }
@@ -0,0 +1,138 @@
1
+ import { openCardBuildEnvironment } from '../build/opencard-environment.mjs'
2
+ import { mkdirSync } from 'node:fs'
3
+ import path from 'node:path'
4
+ import { readEnvFile } from '../core/environment.mjs'
5
+ import { resolveProjectBinary, resolveSdkTaroEntry, runProcess, runTasks } from '../core/runner.mjs'
6
+ import { writeWebConfig } from '../core/web-config.mjs'
7
+ import { validateRoutes } from '../validators/routes.mjs'
8
+
9
+ function taroEnvironment(root, extra = {}) {
10
+ const home = path.join(root, '.home')
11
+ mkdirSync(home, { recursive: true })
12
+ return { HOME: home, ...extra }
13
+ }
14
+
15
+ export function resolveBuildEnvironment(root, explicit = {}) {
16
+ return { ...readEnvFile(root), ...explicit }
17
+ }
18
+
19
+ export async function buildTaroFrontend(context, type, options = {}) {
20
+ const args = ['build', '--type', type]
21
+ if (options.mode) args.push('--mode', options.mode)
22
+ if (options.watch) args.push('--watch')
23
+ await runProcess(resolveProjectBinary(context.taroRoot, 'taro'), args, {
24
+ cwd: context.taroRoot,
25
+ env: taroEnvironment(context.taroRoot, options.env),
26
+ label: `taro ${type} build`,
27
+ })
28
+ if (type === 'tt' && !options.watch) {
29
+ writeWebConfig(path.join(context.taroRoot, 'dist-tt'))
30
+ }
31
+ }
32
+
33
+ export async function buildOpenCard(context, options = {}) {
34
+ const root = context.target === 'opencard' ? context.root : context.opencardRoot
35
+ if (!root) return
36
+ const args = ['build', '--type', 'tt']
37
+ if (options.mode) args.push('--mode', options.mode)
38
+ if (options.watch) args.push('--watch')
39
+ await runProcess(process.execPath, [resolveSdkTaroEntry(root), ...args], {
40
+ cwd: root,
41
+ env: taroEnvironment(root, {
42
+ ...(options.watch ? { TT_OUTPUT_ROOT: 'dist-tt' } : {}),
43
+ ...options.env,
44
+ ...openCardBuildEnvironment(context),
45
+ }),
46
+ label: 'opencard tt build',
47
+ })
48
+ if (!options.watch) {
49
+ writeWebConfig(path.join(root, options.env?.TT_OUTPUT_ROOT?.trim() || 'dist'))
50
+ }
51
+ }
52
+
53
+ export function resolveServerBuildScript(options = {}) {
54
+ return options.production ? 'build:prod' : 'build'
55
+ }
56
+
57
+ export function buildServer(context, options = {}) {
58
+ return runProcess('pnpm', [
59
+ '--filter', 'server', 'run', resolveServerBuildScript(options),
60
+ ], {
61
+ cwd: context.taroRoot,
62
+ env: options.env,
63
+ label: 'server build',
64
+ })
65
+ }
66
+
67
+ export function buildClosedDomainServer(context, options = {}) {
68
+ return runProcess('pnpm', ['--filter', 'closed-domain-server', 'run', 'build'], {
69
+ cwd: context.taroRoot,
70
+ env: options.env,
71
+ label: 'closed-domain-server build',
72
+ })
73
+ }
74
+
75
+ /**
76
+ * Build the inputs consumed by the deployment packer before it creates
77
+ * deployment archives. This stays internal to `pack`; the generic template
78
+ * exposes only the stable `pack.sh` entrypoint.
79
+ */
80
+ export async function buildPackInputs(context, options = {}) {
81
+ const tasks = [
82
+ { name: 'taro-tt', run: () => buildTaroFrontend(context, 'tt', { ...options, mode: 'prod' }) },
83
+ { name: 'server', run: () => buildServer(context, { ...options, production: true }) },
84
+ ]
85
+ if (context.hasClosedDomainServer) {
86
+ tasks.push({ name: 'closed-domain-server', run: () => buildClosedDomainServer(context, options) })
87
+ }
88
+ if (context.hasOpenCard) {
89
+ tasks.push({ name: 'opencard', run: () => buildOpenCard(context, options) })
90
+ }
91
+ await runTasks(tasks, { label: 'pack build' })
92
+ }
93
+
94
+ export async function runBuild(context, options = {}) {
95
+ const buildOptions = {
96
+ ...options,
97
+ env: resolveBuildEnvironment(context.root, options.env),
98
+ }
99
+ if (context.target === 'opencard') {
100
+ await buildOpenCard(context, buildOptions)
101
+ return
102
+ }
103
+
104
+ const scope = buildOptions.scope ?? 'all'
105
+ if (scope === 'tt') {
106
+ await buildTaroFrontend(context, 'tt', {
107
+ ...buildOptions,
108
+ mode: buildOptions.mode ?? 'prod',
109
+ })
110
+ return
111
+ }
112
+ if (scope === 'h5') {
113
+ await buildTaroFrontend(context, 'h5', buildOptions)
114
+ return
115
+ }
116
+ if (scope === 'server') {
117
+ await buildServer(context, buildOptions)
118
+ return
119
+ }
120
+ // Preview Runner consumes TT output. Verification selects that target while
121
+ // the public build command retains its existing standalone H5 default.
122
+ const frontendTarget = buildOptions.frontendTarget ?? 'h5'
123
+ const frontendOptions = frontendTarget === 'tt'
124
+ ? { ...buildOptions, mode: buildOptions.mode ?? 'prod' }
125
+ : buildOptions
126
+ const tasks = [
127
+ { name: `taro-${frontendTarget}`, run: () => buildTaroFrontend(context, frontendTarget, frontendOptions) },
128
+ { name: 'server', run: () => buildServer(context, buildOptions) },
129
+ ]
130
+ if (context.hasClosedDomainServer) {
131
+ tasks.push({ name: 'closed-domain-server', run: () => buildClosedDomainServer(context, buildOptions) })
132
+ }
133
+ if (context.hasOpenCard) {
134
+ tasks.push({ name: 'opencard', run: () => buildOpenCard(context, buildOptions) })
135
+ }
136
+ await runTasks(tasks, { label: 'build' })
137
+ validateRoutes(context)
138
+ }
@@ -0,0 +1,14 @@
1
+ import path from 'node:path'
2
+ import { CliError } from '../core/errors.mjs'
3
+ import { runProcess } from '../core/runner.mjs'
4
+
5
+ export async function runDatabaseInit(context, options = {}) {
6
+ if (context.target !== 'taro') {
7
+ throw new CliError('Database initialization requires --target taro')
8
+ }
9
+ await runProcess(process.execPath, [path.join(context.serverRoot, 'scripts/init-mysql-db.js')], {
10
+ cwd: context.serverRoot,
11
+ env: options.env,
12
+ label: 'database initialization',
13
+ })
14
+ }