@open-dy/vibecoding-cli 0.1.5 → 0.1.6-beta.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-dy/vibecoding-cli",
3
- "version": "0.1.5",
3
+ "version": "0.1.6-beta.0",
4
4
  "description": "Command orchestration, validation and packaging for Douyin vibecoding Taro and OpenCard projects.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -24,7 +24,8 @@
24
24
  "bin",
25
25
  "src",
26
26
  "assets",
27
- "README.md"
27
+ "README.md",
28
+ "release-provenance.json"
28
29
  ],
29
30
  "scripts": {
30
31
  "ci:check": "pnpm run build && pnpm run test",
@@ -42,8 +43,8 @@
42
43
  "ajv": "^8.18.0"
43
44
  },
44
45
  "peerDependencies": {
45
- "@open-dy/vibecoding-sdk-taro": "^0.1.0",
46
- "@open-dy/vibecoding-sdk-opencard": "0.1.4"
46
+ "@open-dy/vibecoding-sdk-taro": "0.1.1-beta.0",
47
+ "@open-dy/vibecoding-sdk-opencard": "0.1.5-beta.0"
47
48
  },
48
49
  "peerDependenciesMeta": {
49
50
  "@open-dy/vibecoding-sdk-taro": {
@@ -59,7 +60,7 @@
59
60
  "license": "UNLICENSED",
60
61
  "publishConfig": {
61
62
  "registry": "https://registry.npmjs.org/",
62
- "tag": "latest",
63
+ "tag": "beta",
63
64
  "access": "public"
64
65
  }
65
66
  }
@@ -0,0 +1,15 @@
1
+ {
2
+ "schema": 1,
3
+ "producer": "vibecoding-cli",
4
+ "packageName": "@open-dy/vibecoding-cli",
5
+ "version": "0.1.6-beta.0",
6
+ "source": {
7
+ "digest": "sha256-f2018ad1f7d7656392315c81128e717ce478aeb75dedecdec706fe0035cb026d",
8
+ "files": 87
9
+ },
10
+ "payload": "sha256-e85c65882947a652f0d0ec0b05ad00afe0a9106143ff44467c80bb045b86879c",
11
+ "toolchain": {
12
+ "node": "v22.23.1",
13
+ "packageManager": null
14
+ }
15
+ }
@@ -24,6 +24,7 @@ export async function buildTaroFrontend(context, type, options = {}) {
24
24
  cwd: context.taroRoot,
25
25
  env: taroEnvironment(context.taroRoot, options.env),
26
26
  label: `taro ${type} build`,
27
+ quiet: options.quiet,
27
28
  })
28
29
  if (type === 'tt' && !options.watch) {
29
30
  writeWebConfig(path.join(context.taroRoot, 'dist-tt'))
@@ -45,6 +46,7 @@ export async function buildOpenCard(context, options = {}) {
45
46
  ...cardEnvironment,
46
47
  }),
47
48
  label: 'opencard tt build',
49
+ quiet: options.quiet,
48
50
  })
49
51
  if (!options.watch) {
50
52
  writeWebConfig(path.join(root, options.env?.TT_OUTPUT_ROOT?.trim() || 'dist'))
@@ -62,6 +64,7 @@ export function buildServer(context, options = {}) {
62
64
  cwd: context.taroRoot,
63
65
  env: options.env,
64
66
  label: 'server build',
67
+ quiet: options.quiet,
65
68
  })
66
69
  }
67
70
 
@@ -70,6 +73,7 @@ export function buildClosedDomainServer(context, options = {}) {
70
73
  cwd: context.taroRoot,
71
74
  env: options.env,
72
75
  label: 'closed-domain-server build',
76
+ quiet: options.quiet,
73
77
  })
74
78
  }
75
79
 
@@ -90,7 +94,7 @@ export async function buildPackInputs(context, options = {}) {
90
94
  if (context.hasOpenCard) {
91
95
  tasks.push({ name: 'opencard', run: () => buildOpenCard(context, options) })
92
96
  }
93
- await runTasks(tasks, { label: 'pack build' })
97
+ await runTasks(tasks, { label: 'pack build', quiet: options.quiet })
94
98
  }
95
99
 
96
100
  export async function runBuild(context, options = {}) {
@@ -136,6 +140,6 @@ export async function runBuild(context, options = {}) {
136
140
  if (context.hasOpenCard) {
137
141
  tasks.push({ name: 'opencard', run: () => buildOpenCard(context, buildOptions) })
138
142
  }
139
- await runTasks(tasks, { label: 'build' })
140
- validateRoutes(context)
143
+ await runTasks(tasks, { label: 'build', quiet: buildOptions.quiet })
144
+ validateRoutes(context, { quiet: buildOptions.quiet })
141
145
  }
@@ -10,5 +10,6 @@ export async function runDatabaseInit(context, options = {}) {
10
10
  cwd: context.serverRoot,
11
11
  env: options.env,
12
12
  label: 'database initialization',
13
+ quiet: options.quiet,
13
14
  })
14
15
  }
@@ -106,21 +106,21 @@ export async function lintOpenCard(context, options = {}) {
106
106
  { name: 'opencard-structure', run: async () => validateOpenCardStructure(validationContext) },
107
107
  { name: 'opencard-widget-shell', run: async () => validateWidgetShell(validationContext) },
108
108
  { name: 'opencard-lynx-css', run: () => runLynxCss(root, options.lintProject) },
109
- { name: 'opencard-tsc', run: () => runProcess(tsc, ['--noEmit'], { cwd: root }) },
109
+ { name: 'opencard-tsc', run: () => runProcess(tsc, ['--noEmit'], { cwd: root, quiet: options.quiet }) },
110
110
  ]
111
111
  if (eslintSelection.runEslint) {
112
112
  tasks.push({
113
113
  name: 'opencard-eslint',
114
- run: () => runProcess(eslint, eslintArgs, { cwd: root }),
114
+ run: () => runProcess(eslint, eslintArgs, { cwd: root, quiet: options.quiet }),
115
115
  })
116
116
  }
117
- await runTasks(tasks, { label: 'opencard lint' })
117
+ await runTasks(tasks, { label: 'opencard lint', quiet: options.quiet })
118
118
  }
119
119
 
120
120
  export async function runLint(context, options = {}) {
121
121
  const incremental = options.incremental || process.env.LINT_INCREMENTAL === '1'
122
122
  if (context.target === 'opencard') {
123
- await lintOpenCard(context, { incremental })
123
+ await lintOpenCard(context, { incremental, quiet: options.quiet })
124
124
  return
125
125
  }
126
126
 
@@ -142,8 +142,8 @@ export async function runLint(context, options = {}) {
142
142
  const tasks = []
143
143
  if (full || changed.some((file) => file.startsWith('src/'))) {
144
144
  tasks.push(
145
- { name: 'taro-tsc', run: () => runProcess(tsc, ['--noEmit'], { cwd: context.root }) },
146
- { name: 'taro-eslint', run: () => runProcess(eslint, eslintArgs, { cwd: context.root }) },
145
+ { name: 'taro-tsc', run: () => runProcess(tsc, ['--noEmit'], { cwd: context.root, quiet: options.quiet }) },
146
+ { name: 'taro-eslint', run: () => runProcess(eslint, eslintArgs, { cwd: context.root, quiet: options.quiet }) },
147
147
  )
148
148
  }
149
149
  if (full || serverChanged || closedDomainChanged) {
@@ -156,7 +156,7 @@ export async function runLint(context, options = {}) {
156
156
  tasks.push({
157
157
  name: 'server-lint',
158
158
  run: () => runTasks([
159
- { name: 'server-tsc', run: () => runProcess(tsc, ['--noEmit'], { cwd: context.serverRoot }) },
159
+ { name: 'server-tsc', run: () => runProcess(tsc, ['--noEmit'], { cwd: context.serverRoot, quiet: options.quiet }) },
160
160
  {
161
161
  name: 'server-eslint',
162
162
  run: () => runProcess(eslint, [
@@ -164,13 +164,16 @@ export async function runLint(context, options = {}) {
164
164
  '--cache-location',
165
165
  'node_modules/.cache/eslint/server-src',
166
166
  'src/**/*.{js,jsx,ts,tsx}',
167
- ], { cwd: context.serverRoot }),
167
+ ], { cwd: context.serverRoot, quiet: options.quiet }),
168
168
  },
169
- ], { label: 'server lint' }),
169
+ ], { label: 'server lint', quiet: options.quiet }),
170
170
  })
171
171
  }
172
172
  if (context.hasOpenCard && (full || changed.some((file) => file.startsWith('opencard/')))) {
173
- tasks.push({ name: 'opencard-lint', run: () => lintOpenCard(context, { incremental: !full }) })
173
+ tasks.push({
174
+ name: 'opencard-lint',
175
+ run: () => lintOpenCard(context, { incremental: !full, quiet: options.quiet }),
176
+ })
174
177
  }
175
- await runTasks(tasks, { label: 'lint' })
178
+ await runTasks(tasks, { label: 'lint', quiet: options.quiet })
176
179
  }
@@ -33,21 +33,23 @@ async function runStatic(context) {
33
33
  validateDependencies(context)
34
34
  const env = await readRuntimeEnvironment(context.root)
35
35
  const tasks = [
36
- { name: 'lint', run: () => runLint(context) },
37
- { name: 'build', run: () => runBuild(context, { frontendTarget: 'tt' }) },
36
+ { name: 'lint', run: () => runLint(context, { quiet: true }) },
37
+ { name: 'build', run: () => runBuild(context, { frontendTarget: 'tt', quiet: true }) },
38
38
  ]
39
39
  if (context.target === 'taro') {
40
40
  tasks.push(
41
- { name: 'database', run: () => runDatabaseInit(context, { env }) },
42
- { name: 'feed-card', run: async () => validateFeedCard(context) },
41
+ { name: 'database', run: () => runDatabaseInit(context, { env, quiet: true }) },
42
+ { name: 'feed-card', run: async () => validateFeedCard(context, { quiet: true }) },
43
43
  )
44
44
  }
45
- await runTasks(tasks, { label: 'static verification' })
45
+ await runTasks(tasks, { label: 'static verification', quiet: true })
46
46
  if (context.target === 'taro') {
47
47
  validateServerArtifactFileCount(context.serverRoot ?? path.join(context.root, 'server'), {
48
48
  packScriptPath: path.join(context.root, 'scripts/pack.sh'),
49
+ quiet: true,
49
50
  })
50
51
  }
52
+ console.log('[verify] Static phase passed (all parallel tasks OK).')
51
53
  }
52
54
 
53
55
  export function startDevDetached(context, spawnProcess = spawn) {
@@ -623,19 +625,31 @@ export async function runVerify(context, options = {}) {
623
625
  options = { timeoutSeconds: 90, ...options, full }
624
626
  const frontendUrl = resolveFrontendUrl(context, options)
625
627
  parseHttpUrl(frontendUrl, 'frontend')
626
- if (full || options.staticOnly) await runStatic(context)
627
- if (options.staticOnly) return
628
+ if (full || options.staticOnly) {
629
+ await runStatic(context)
630
+ }
631
+ if (options.staticOnly) {
632
+ console.log('[verify] --static-only: done.')
633
+ return
634
+ }
628
635
 
629
636
  await verifyPorts(context, options, frontendUrl)
630
- if (options.portsOnly) return
631
- if (full && context.target === 'taro') await verifyFeedApi(context)
637
+ if (options.portsOnly) {
638
+ console.log('[verify] --ports-only: done.')
639
+ return
640
+ }
641
+ if (full && context.target === 'taro') {
642
+ await verifyFeedApi(context)
643
+ }
632
644
  if (context.target === 'taro' &&
633
645
  existsSync(path.resolve(context.root, '../sar_game/package.json'))) {
634
646
  console.log('[vibecoding:verify] SAR game project detected; skipping browser runtime checks')
647
+ console.log('[verify] All checks passed.')
635
648
  return
636
649
  }
637
650
  await browserCheck(context.root, frontendUrl, context.target)
638
651
  if (context.target === 'taro' && context.hasOpenCard) {
639
652
  await browserCheck(context.opencardRoot, 'http://localhost:10087/', 'opencard')
640
653
  }
654
+ console.log('[verify] All checks passed.')
641
655
  }
@@ -12,28 +12,49 @@ export function resolveSdkTaroEntry(root) {
12
12
  return createRequire(path.join(root, 'package.json')).resolve('@open-dy/vibecoding-sdk-opencard/build/taro-toolchain')
13
13
  }
14
14
 
15
+ function withCapturedOutput(message, stdout, stderr) {
16
+ if (!stdout && !stderr) return message
17
+ const separator = stdout && stderr && !stdout.endsWith('\n') ? '\n' : ''
18
+ return `${message}\n${stdout}${separator}${stderr}`
19
+ }
20
+
15
21
  export function runProcess(command, args = [], options = {}) {
16
22
  const label = options.label ?? path.basename(command)
17
23
  return new Promise((resolve, reject) => {
24
+ const captureOutput = options.quiet && options.stdio === undefined
18
25
  const child = spawn(command, args, {
19
26
  cwd: options.cwd,
20
27
  env: { ...process.env, ...options.env },
21
- stdio: options.stdio ?? 'inherit',
28
+ stdio: captureOutput ? ['ignore', 'pipe', 'pipe'] : (options.stdio ?? 'inherit'),
22
29
  detached: options.detached ?? false,
23
30
  shell: options.shell ?? false,
24
31
  })
32
+ let stdout = ''
33
+ let stderr = ''
34
+ if (captureOutput) {
35
+ child.stdout.setEncoding('utf8')
36
+ child.stderr.setEncoding('utf8')
37
+ child.stdout.on('data', (chunk) => { stdout += chunk })
38
+ child.stderr.on('data', (chunk) => { stderr += chunk })
39
+ }
25
40
 
26
41
  child.on('error', (error) => {
27
- reject(new CliError(`${label} failed to start: ${error.message}`))
42
+ reject(new CliError(withCapturedOutput(
43
+ `${label} failed to start: ${error.message}`,
44
+ stdout,
45
+ stderr,
46
+ )))
28
47
  })
29
48
  child.on('exit', (code, signal) => {
30
49
  if (code === 0) {
31
50
  resolve({ code: 0, signal, child })
32
51
  return
33
52
  }
34
- reject(new CliError(
53
+ reject(new CliError(withCapturedOutput(
35
54
  `${label} failed${signal ? ` with signal ${signal}` : ` with exit code ${code}`}`,
36
- ))
55
+ stdout,
56
+ stderr,
57
+ )))
37
58
  })
38
59
  })
39
60
  }
@@ -78,9 +99,9 @@ export function runCaptured(command, args = [], options = {}) {
78
99
  export async function runTasks(tasks, options = {}) {
79
100
  const results = await Promise.allSettled(
80
101
  tasks.map(async ({ name, run }) => {
81
- console.log(`[vibecoding] starting ${name}`)
102
+ if (!options.quiet) console.log(`[vibecoding] starting ${name}`)
82
103
  await run()
83
- console.log(`[vibecoding] completed ${name}`)
104
+ if (!options.quiet) console.log(`[vibecoding] completed ${name}`)
84
105
  return name
85
106
  }),
86
107
  )
@@ -149,7 +149,7 @@ function validateFeedCard(context, options = {}) {
149
149
  }
150
150
  }
151
151
 
152
- console.log("All validations passed!");
152
+ if (!options.quiet) console.log("All validations passed!");
153
153
  return { skipped: false };
154
154
  }
155
155
 
@@ -3,6 +3,7 @@ const path = require('path');
3
3
 
4
4
  function validateRoutes(context, options = {}) {
5
5
  if (context.target !== 'taro') return;
6
+ const quiet = Boolean(options.quiet);
6
7
  const ROOT = context.root;
7
8
  const routesDir = options.routesDir || '/tmp/routes';
8
9
  const CLIENT_FILE = path.join(routesDir, 'client-routes.json');
@@ -402,7 +403,7 @@ function main() {
402
403
  const closedDomainServerRoutes = loadClosedDomainServerRoutes();
403
404
  const cardRoutingConfig = loadCardRoutingConfig();
404
405
 
405
- console.log('=== 前后端路由一致性检测报告 ===\n');
406
+ if (!quiet) console.log('=== 前后端路由一致性检测报告 ===\n');
406
407
 
407
408
  assertOpenDomainServerDoesNotCallClosedDomainOpenAPI();
408
409
 
@@ -451,7 +452,7 @@ function main() {
451
452
  }
452
453
  }
453
454
 
454
- console.log('--- 检测结果 ---\n');
455
+ if (!quiet) console.log('--- 检测结果 ---\n');
455
456
 
456
457
  if (mismatched.length > 0) {
457
458
  console.error(`未匹配(${mismatched.length} 条):以下前端请求路径未匹配到所选服务域的服务端路由,请检查前端请求路径、服务域配置,或确认服务端已注册对应路由`);
@@ -460,7 +461,7 @@ function main() {
460
461
  }
461
462
  throw new Error('前后端路由一致性检测失败');
462
463
  } else {
463
- console.log('所有前端静态请求路径均已在服务端注册对应路由,检测通过。');
464
+ if (!quiet) console.log('所有前端静态请求路径均已在服务端注册对应路由,检测通过。');
464
465
  }
465
466
  }
466
467
 
@@ -63,7 +63,7 @@ function countFiles(target, policy) {
63
63
  (policy.excludes && isServerPackExcluded(name, policy) ? 0 : countFiles(path.join(target, name), policy)), 0)
64
64
  }
65
65
 
66
- export function validateServerArtifactFileCount(serverRoot, { packScriptPath } = {}) {
66
+ export function validateServerArtifactFileCount(serverRoot, { packScriptPath, quiet = false } = {}) {
67
67
  if (!existsSync(serverRoot)) throw new CliError(`Server directory is missing: ${serverRoot}`)
68
68
  let policy = DEFAULT_POLICY
69
69
  if (packScriptPath) {
@@ -84,6 +84,8 @@ export function validateServerArtifactFileCount(serverRoot, { packScriptPath } =
84
84
  if (count > MAX_FILE_COUNT) {
85
85
  throw new CliError(`Packed server artifact ${serverRoot} would contain ${count} files, exceeding the limit ${MAX_FILE_COUNT}. This count follows the server pack policy. Reduce files included by pack before submission.`)
86
86
  }
87
- console.log(`[verify] static:server-artifact-file-count → OK (${count}/${MAX_FILE_COUNT}, ${serverRoot}).`)
87
+ if (!quiet) {
88
+ console.log(`[verify] static:server-artifact-file-count → OK (${count}/${MAX_FILE_COUNT}, ${serverRoot}).`)
89
+ }
88
90
  return { skipped: false, count, missing: [] }
89
91
  }