@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.
- package/README.md +47 -0
- package/assets/schemas/custom-card-schema.json +102 -0
- package/bin/vibecoding +89 -0
- package/bin/vibecoding-dev +308 -0
- package/bin/vibecoding-interest-card.mjs +35 -0
- package/bin/vibecoding.mjs +9 -0
- package/package.json +58 -0
- package/src/adapters/interest-card/opencard/commands.mjs +62 -0
- package/src/adapters/interest-card/opencard/dev-watch.mjs +203 -0
- package/src/adapters/interest-card/opencard/dev_run.sh +126 -0
- package/src/adapters/interest-card/opencard/eslint-plugin-opencard-taro.mjs +278 -0
- package/src/adapters/interest-card/opencard/lint-lynx-css.mjs +676 -0
- package/src/adapters/interest-card/opencard/lint.sh +131 -0
- package/src/adapters/interest-card/opencard/lynx-css-rules.mjs +508 -0
- package/src/adapters/interest-card/opencard/pack.sh +27 -0
- package/src/adapters/interest-card/opencard/validate-opencard-structure.mjs +65 -0
- package/src/adapters/interest-card/opencard/validate-widget-shell.mjs +902 -0
- package/src/adapters/interest-card/opencard/validate.mjs +11 -0
- package/src/adapters/interest-card/opencard/write-web-config.mjs +17 -0
- package/src/build/opencard-environment.mjs +49 -0
- package/src/build/turbo-config.mjs +140 -0
- package/src/cli.mjs +104 -0
- package/src/commands/build.mjs +138 -0
- package/src/commands/db.mjs +14 -0
- package/src/commands/dev.mjs +319 -0
- package/src/commands/lint.mjs +176 -0
- package/src/commands/pack.mjs +169 -0
- package/src/commands/turbo.mjs +36 -0
- package/src/commands/validate.mjs +26 -0
- package/src/commands/verify.mjs +602 -0
- package/src/core/args.mjs +101 -0
- package/src/core/context.mjs +101 -0
- package/src/core/environment.mjs +55 -0
- package/src/core/errors.mjs +14 -0
- package/src/core/ports.mjs +76 -0
- package/src/core/process-output.mjs +25 -0
- package/src/core/runner.mjs +90 -0
- package/src/core/service-log-context.mjs +27 -0
- package/src/core/web-config.mjs +13 -0
- package/src/lint/lint-lynx-css.mjs +244 -0
- package/src/lint/lynx-css-rules.mjs +138 -0
- package/src/preview/dev-watch.mjs +38 -0
- package/src/preview/start-preview.mjs +213 -0
- package/src/preview/watch-card-routing.mjs +89 -0
- package/src/scripts/pack.mjs +15 -0
- package/src/validators/dependencies.mjs +34 -0
- package/src/validators/empty-project.mjs +29 -0
- package/src/validators/feed-card.cjs +156 -0
- package/src/validators/feed-card.mjs +32 -0
- package/src/validators/opencard-structure.mjs +58 -0
- package/src/validators/routes.cjs +470 -0
- package/src/validators/routes.mjs +17 -0
- package/src/validators/sql.mjs +57 -0
- 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
|
+
}
|