universal-dev-standards 5.0.0 → 5.1.0-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 (63) hide show
  1. package/bin/uds.js +34 -11
  2. package/bundled/ai/standards/ai-response-navigation.ai.yaml +70 -0
  3. package/bundled/ai/standards/context-aware-loading.ai.yaml +5 -4
  4. package/bundled/core/ai-response-navigation.md +289 -0
  5. package/bundled/locales/zh-CN/README.md +1 -1
  6. package/bundled/locales/zh-CN/core/ai-response-navigation.md +297 -0
  7. package/bundled/locales/zh-TW/README.md +1 -1
  8. package/bundled/locales/zh-TW/core/ai-response-navigation.md +297 -0
  9. package/bundled/skills/ac-coverage-assistant/SKILL.md +1 -1
  10. package/bundled/skills/ai-collaboration-standards/SKILL.md +11 -0
  11. package/bundled/skills/ai-friendly-architecture/SKILL.md +11 -0
  12. package/bundled/skills/ai-instruction-standards/SKILL.md +11 -0
  13. package/bundled/skills/api-design-assistant/SKILL.md +1 -1
  14. package/bundled/skills/atdd-assistant/SKILL.md +1 -1
  15. package/bundled/skills/audit-assistant/SKILL.md +1 -1
  16. package/bundled/skills/bdd-assistant/SKILL.md +1 -1
  17. package/bundled/skills/brainstorm-assistant/SKILL.md +1 -1
  18. package/bundled/skills/changelog-guide/SKILL.md +1 -1
  19. package/bundled/skills/checkin-assistant/SKILL.md +1 -1
  20. package/bundled/skills/ci-cd-assistant/SKILL.md +1 -1
  21. package/bundled/skills/code-review-assistant/SKILL.md +1 -1
  22. package/bundled/skills/commands/release.md +27 -7
  23. package/bundled/skills/commit-standards/SKILL.md +1 -1
  24. package/bundled/skills/database-assistant/SKILL.md +1 -1
  25. package/bundled/skills/dev-workflow-guide/SKILL.md +1 -1
  26. package/bundled/skills/docs-generator/SKILL.md +1 -1
  27. package/bundled/skills/documentation-guide/SKILL.md +11 -0
  28. package/bundled/skills/durable-execution-assistant/SKILL.md +1 -1
  29. package/bundled/skills/error-code-guide/SKILL.md +11 -0
  30. package/bundled/skills/forward-derivation/SKILL.md +1 -1
  31. package/bundled/skills/git-workflow-guide/SKILL.md +11 -0
  32. package/bundled/skills/incident-response-assistant/SKILL.md +1 -1
  33. package/bundled/skills/logging-guide/SKILL.md +11 -0
  34. package/bundled/skills/methodology-system/SKILL.md +1 -1
  35. package/bundled/skills/metrics-dashboard-assistant/SKILL.md +1 -1
  36. package/bundled/skills/migration-assistant/SKILL.md +1 -1
  37. package/bundled/skills/pr-automation-assistant/SKILL.md +1 -1
  38. package/bundled/skills/project-discovery/SKILL.md +1 -1
  39. package/bundled/skills/project-structure-guide/SKILL.md +11 -0
  40. package/bundled/skills/refactoring-assistant/SKILL.md +1 -1
  41. package/bundled/skills/release-standards/SKILL.md +31 -7
  42. package/bundled/skills/requirement-assistant/SKILL.md +1 -1
  43. package/bundled/skills/reverse-engineer/SKILL.md +1 -1
  44. package/bundled/skills/security-assistant/SKILL.md +1 -1
  45. package/bundled/skills/security-scan-assistant/SKILL.md +1 -1
  46. package/bundled/skills/spec-driven-dev/SKILL.md +1 -1
  47. package/bundled/skills/tdd-assistant/SKILL.md +1 -1
  48. package/bundled/skills/test-coverage-assistant/SKILL.md +1 -1
  49. package/bundled/skills/testing-guide/SKILL.md +11 -0
  50. package/package.json +3 -3
  51. package/src/commands/config.js +35 -2
  52. package/src/commands/init.js +17 -1
  53. package/src/commands/release.js +378 -0
  54. package/src/flows/init-flow.js +7 -2
  55. package/src/i18n/messages.js +87 -0
  56. package/src/installers/manifest-installer.js +2 -1
  57. package/src/prompts/init.js +52 -0
  58. package/src/utils/build-manifest.js +46 -0
  59. package/src/utils/deployment-tracker.js +73 -0
  60. package/src/utils/release-config.js +94 -0
  61. package/src/utils/update-checker.js +17 -0
  62. package/src/utils/version-promote.js +73 -0
  63. package/standards-registry.json +14 -3
@@ -21,6 +21,7 @@ import {
21
21
  getAgentDisplayName
22
22
  } from '../utils/github.js';
23
23
  import { displayLanguageToLocale } from '../utils/locale.js';
24
+ import { generateReleaseConfig, RELEASE_MODE_LABELS } from '../utils/release-config.js';
24
25
 
25
26
  /**
26
27
  * Init command - initialize standards in current project
@@ -91,6 +92,16 @@ export async function initCommand(options) {
91
92
  const standardsResults = await installStandards(config, projectPath);
92
93
  config.installedStandards = standardsResults.standards.map(s => basename(s));
93
94
 
95
+ // 1.5. Generate release-config.yaml if non-default mode selected
96
+ if (config.releaseMode && config.releaseMode !== 'ci-cd') {
97
+ const releaseConfigData = generateReleaseConfig(config.releaseMode);
98
+ const releaseConfigPath = join(projectPath, '.standards', 'release-config.yaml');
99
+ const yaml = (await import('js-yaml')).default;
100
+ mkdirSync(join(projectPath, '.standards'), { recursive: true });
101
+ writeFileSync(releaseConfigPath, yaml.dump(releaseConfigData), 'utf-8');
102
+ console.log(chalk.green(` ✓ release-config.yaml (${config.releaseMode})`));
103
+ }
104
+
94
105
  // 2. Install Integrations
95
106
  const integrationResults = await installIntegrations(config, projectPath);
96
107
 
@@ -324,7 +335,8 @@ function buildNonInteractiveConfig(options, detected, projectPath) {
324
335
  integrations: [...aiToolsNormalized],
325
336
  contentMode: skillsConfig.contentMode || 'minimal',
326
337
  methodology: null,
327
- generateAgentsMd
338
+ generateAgentsMd,
339
+ releaseMode: options.releaseMode || 'ci-cd'
328
340
  };
329
341
  }
330
342
 
@@ -397,6 +409,10 @@ function displaySummary(config, msg, common) {
397
409
  if (config.standardOptions.workflow) {
398
410
  console.log(chalk.gray(` ${msg.gitWorkflow}: ${getValueLabel('gitWorkflow', config.standardOptions.workflow)}`));
399
411
  }
412
+ if (config.releaseMode) {
413
+ const releaseModeLabels = RELEASE_MODE_LABELS;
414
+ console.log(chalk.gray(` ${msg.releaseMode || 'Release Mode'}: ${releaseModeLabels[config.releaseMode] || config.releaseMode}`));
415
+ }
400
416
  if (config.standardOptions.merge_strategy) {
401
417
  console.log(chalk.gray(` ${msg.mergeStrategy}: ${getValueLabel('mergeStrategy', config.standardOptions.merge_strategy)}`));
402
418
  }
@@ -0,0 +1,378 @@
1
+ /**
2
+ * Release command — manage release process with mode-aware behavior.
3
+ * SPEC-RELEASE-01: Manual Deployment Release Mode
4
+ *
5
+ * Subcommands:
6
+ * promote — RC → Stable promotion (manual/hybrid mode)
7
+ * deploy — Record deployment to environment (manual/hybrid mode)
8
+ * manifest — Generate build-manifest.json (manual/hybrid mode)
9
+ * verify — Verify manifest against git state (manual/hybrid mode)
10
+ */
11
+
12
+ import chalk from 'chalk';
13
+ import yaml from 'js-yaml';
14
+ import { existsSync, readFileSync, writeFileSync } from 'fs';
15
+ import { join } from 'path';
16
+ import { execSync } from 'child_process';
17
+ import { resolveReleaseWorkflow } from '../utils/release-config.js';
18
+ import { formatGitTag, createPromotionRecord, parseRCVersion } from '../utils/version-promote.js';
19
+ import { createManifest, verifyManifest } from '../utils/build-manifest.js';
20
+ import { recordDeployment, updateDeploymentResult, checkDeploymentReadiness } from '../utils/deployment-tracker.js';
21
+
22
+ /**
23
+ * Load release config from .standards/release-config.yaml
24
+ */
25
+ function loadReleaseConfig(projectPath) {
26
+ const configPath = join(projectPath, '.standards', 'release-config.yaml');
27
+ if (!existsSync(configPath)) {
28
+ return null;
29
+ }
30
+ try {
31
+ return yaml.load(readFileSync(configPath, 'utf-8'));
32
+ } catch (err) {
33
+ console.log(chalk.yellow(`⚠ release-config.yaml 解析失敗: ${err.message}`));
34
+ return null;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * Load deployments.yaml
40
+ */
41
+ function loadDeployments(projectPath) {
42
+ const deployPath = join(projectPath, 'deployments.yaml');
43
+ if (!existsSync(deployPath)) {
44
+ return [];
45
+ }
46
+ try {
47
+ const data = yaml.load(readFileSync(deployPath, 'utf-8'));
48
+ return data?.deployments || [];
49
+ } catch {
50
+ return [];
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Save deployments.yaml
56
+ */
57
+ function saveDeployments(projectPath, deployments) {
58
+ const deployPath = join(projectPath, 'deployments.yaml');
59
+ writeFileSync(deployPath, yaml.dump({ deployments }), 'utf-8');
60
+ }
61
+
62
+ /**
63
+ * Get current git user name
64
+ */
65
+ function getGitUser() {
66
+ try {
67
+ return execSync('git config user.name', { encoding: 'utf-8' }).trim();
68
+ } catch {
69
+ return 'unknown';
70
+ }
71
+ }
72
+
73
+ /**
74
+ * Get current git commit hash (short)
75
+ */
76
+ function getGitCommit() {
77
+ try {
78
+ return execSync('git rev-parse --short HEAD', { encoding: 'utf-8' }).trim();
79
+ } catch {
80
+ return 'unknown';
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Get current git branch
86
+ */
87
+ function getGitBranch() {
88
+ try {
89
+ return execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim();
90
+ } catch {
91
+ return 'unknown';
92
+ }
93
+ }
94
+
95
+ /**
96
+ * Get current version from package.json
97
+ */
98
+ function getPackageVersion(projectPath) {
99
+ const pkgPath = join(projectPath, 'package.json');
100
+ if (!existsSync(pkgPath)) {
101
+ // Try cli/package.json
102
+ const cliPkgPath = join(projectPath, 'cli', 'package.json');
103
+ if (existsSync(cliPkgPath)) {
104
+ return JSON.parse(readFileSync(cliPkgPath, 'utf-8')).version;
105
+ }
106
+ return null;
107
+ }
108
+ return JSON.parse(readFileSync(pkgPath, 'utf-8')).version;
109
+ }
110
+
111
+ /**
112
+ * Main release command entry point
113
+ */
114
+ export async function releaseCommand(subcommand, args, options) {
115
+ const projectPath = process.cwd();
116
+ const releaseConfig = loadReleaseConfig(projectPath);
117
+ const workflow = resolveReleaseWorkflow(releaseConfig);
118
+
119
+ switch (subcommand) {
120
+ case 'promote':
121
+ if (!workflow.hasPromote) {
122
+ console.log(chalk.red('promote 子命令僅在 manual 或 hybrid 模式下可用。'));
123
+ console.log(chalk.gray(' 目前模式: ' + workflow.type));
124
+ console.log(chalk.gray(' 使用 `uds config --type release_mode` 切換模式'));
125
+ return;
126
+ }
127
+ await handlePromote(args, projectPath);
128
+ break;
129
+
130
+ case 'deploy':
131
+ if (!workflow.hasDeploy) {
132
+ console.log(chalk.red('deploy 子命令僅在 manual 或 hybrid 模式下可用。'));
133
+ console.log(chalk.gray(' 目前模式: ' + workflow.type));
134
+ return;
135
+ }
136
+ await handleDeploy(args, options, projectPath);
137
+ break;
138
+
139
+ case 'manifest':
140
+ if (!workflow.hasManifest) {
141
+ console.log(chalk.red('manifest 子命令僅在 manual 或 hybrid 模式下可用。'));
142
+ return;
143
+ }
144
+ await handleManifest(args, options, projectPath);
145
+ break;
146
+
147
+ case 'verify':
148
+ if (!workflow.hasManifest) {
149
+ console.log(chalk.red('verify 子命令僅在 manual 或 hybrid 模式下可用。'));
150
+ return;
151
+ }
152
+ await handleVerify(projectPath);
153
+ break;
154
+
155
+ default:
156
+ showReleaseHelp(workflow);
157
+ break;
158
+ }
159
+ }
160
+
161
+ /**
162
+ * /release promote <version>
163
+ * Promote RC to stable version
164
+ */
165
+ async function handlePromote(targetVersion, projectPath) {
166
+
167
+ if (!targetVersion) {
168
+ console.log(chalk.red('請指定目標 stable 版本號。'));
169
+ console.log(chalk.gray(' 用法: uds release promote 1.2.0'));
170
+ return;
171
+ }
172
+
173
+ // Verify this is a valid stable version (no pre-release suffix)
174
+ if (targetVersion.includes('-')) {
175
+ console.log(chalk.red('目標版本不應包含 pre-release 後綴。'));
176
+ console.log(chalk.gray(` 請使用: uds release promote ${targetVersion.split('-')[0]}`));
177
+ return;
178
+ }
179
+
180
+ // Find the latest RC for this version
181
+ const currentVersion = getPackageVersion(projectPath);
182
+ const parsed = currentVersion ? parseRCVersion(currentVersion) : null;
183
+
184
+ console.log();
185
+ console.log(chalk.bold('Release Promote: RC → Stable'));
186
+ console.log(chalk.gray('─'.repeat(40)));
187
+
188
+ if (parsed) {
189
+ console.log(chalk.gray(` 目前版本: ${currentVersion}`));
190
+ console.log(chalk.gray(` 晉升目標: ${targetVersion}`));
191
+ } else {
192
+ console.log(chalk.gray(` 晉升目標: ${targetVersion}`));
193
+ }
194
+
195
+ // Create promotion record
196
+ const record = createPromotionRecord(currentVersion || 'unknown', targetVersion);
197
+ console.log();
198
+ console.log(chalk.green(` ✓ 晉升紀錄建立: ${record.promoted_from} → ${record.version}`));
199
+
200
+ // Create git tag
201
+ const tag = formatGitTag(targetVersion);
202
+ console.log(chalk.green(` ✓ Git tag: ${tag}`));
203
+ console.log();
204
+ console.log(chalk.cyan('後續步驟:'));
205
+ console.log(chalk.gray(` 1. 更新版本檔案為 ${targetVersion}`));
206
+ console.log(chalk.gray(` 2. git tag ${tag}`));
207
+ console.log(chalk.gray(' 3. 從此 commit 重新打包'));
208
+ console.log(chalk.gray(' 4. 執行 uds release deploy production 記錄部署'));
209
+ }
210
+
211
+ /**
212
+ * /release deploy <environment> [--result <result>]
213
+ */
214
+ async function handleDeploy(environment, options, projectPath) {
215
+
216
+ if (!environment) {
217
+ console.log(chalk.red('請指定部署環境。'));
218
+ console.log(chalk.gray(' 用法: uds release deploy staging'));
219
+ console.log(chalk.gray(' 用法: uds release deploy staging --result passed'));
220
+ console.log(chalk.gray(' 用法: uds release deploy production'));
221
+ return;
222
+ }
223
+
224
+ const currentVersion = getPackageVersion(projectPath) || 'unknown';
225
+ const deployments = loadDeployments(projectPath);
226
+
227
+ // If --result flag: update existing deployment
228
+ if (options.result) {
229
+ const { deployments: updated, updatedCount } = updateDeploymentResult(deployments, {
230
+ version: currentVersion,
231
+ environment,
232
+ result: options.result,
233
+ });
234
+ if (updatedCount === 0) {
235
+ console.log(chalk.yellow(`⚠ 找不到 ${currentVersion} 在 ${environment} 的部署紀錄`));
236
+ return;
237
+ }
238
+ saveDeployments(projectPath, updated);
239
+ console.log(chalk.green(`✓ 已更新 ${currentVersion} 在 ${environment} 的結果: ${options.result}`));
240
+ return;
241
+ }
242
+
243
+ // Check readiness for production
244
+ if (environment === 'production') {
245
+ const warnings = checkDeploymentReadiness(deployments, {
246
+ version: currentVersion,
247
+ environment: 'production',
248
+ });
249
+ if (warnings.length > 0) {
250
+ console.log();
251
+ console.log(chalk.yellow('⚠ 警告:'));
252
+ for (const w of warnings) {
253
+ console.log(chalk.yellow(` - ${w}`));
254
+ }
255
+ console.log();
256
+ }
257
+ }
258
+
259
+ // Record deployment
260
+ const record = recordDeployment({
261
+ version: currentVersion,
262
+ environment,
263
+ deployer: getGitUser(),
264
+ });
265
+
266
+ deployments.push(record);
267
+ saveDeployments(projectPath, deployments);
268
+
269
+ console.log(chalk.green(`✓ 已記錄部署: ${currentVersion} → ${environment}`));
270
+ console.log(chalk.gray(` 部署者: ${record.deployer}`));
271
+ console.log(chalk.gray(` 時間: ${record.date}`));
272
+
273
+ if (environment === 'staging') {
274
+ console.log();
275
+ console.log(chalk.cyan('後續步驟:'));
276
+ console.log(chalk.gray(' 測試完成後執行:'));
277
+ console.log(chalk.gray(' uds release deploy staging --result passed'));
278
+ }
279
+ }
280
+
281
+ /**
282
+ * /release manifest [--checksum <hash>]
283
+ */
284
+ async function handleManifest(versionArg, options, projectPath) {
285
+ const version = getPackageVersion(projectPath) || versionArg || 'unknown';
286
+ const commit = getGitCommit();
287
+ const branch = getGitBranch();
288
+ const builder = getGitUser();
289
+
290
+ const manifest = createManifest({
291
+ version,
292
+ commit,
293
+ branch,
294
+ builder,
295
+ checksum: options.checksum || null,
296
+ });
297
+
298
+ const manifestPath = join(projectPath, 'build-manifest.json');
299
+ writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf-8');
300
+
301
+ console.log(chalk.green('✓ build-manifest.json 已產生'));
302
+ console.log(chalk.gray(` 版本: ${manifest.version}`));
303
+ console.log(chalk.gray(` Commit: ${manifest.commit}`));
304
+ console.log(chalk.gray(` 分支: ${manifest.branch}`));
305
+ console.log(chalk.gray(` 建置者: ${manifest.builder}`));
306
+ console.log(chalk.gray(` 時間: ${manifest.build_date}`));
307
+ }
308
+
309
+ /**
310
+ * /release verify
311
+ */
312
+ async function handleVerify(projectPath) {
313
+ const manifestPath = join(projectPath, 'build-manifest.json');
314
+
315
+ if (!existsSync(manifestPath)) {
316
+ console.log(chalk.red('找不到 build-manifest.json'));
317
+ console.log(chalk.gray(' 請先執行 uds release manifest'));
318
+ return;
319
+ }
320
+
321
+ let manifest;
322
+ try {
323
+ manifest = JSON.parse(readFileSync(manifestPath, 'utf-8'));
324
+ } catch {
325
+ console.log(chalk.red('build-manifest.json 格式不正確'));
326
+ return;
327
+ }
328
+ const currentCommit = getGitCommit();
329
+
330
+ const result = verifyManifest(manifest, currentCommit);
331
+
332
+ if (result.valid) {
333
+ console.log(chalk.green('✓ Manifest 驗證通過'));
334
+ console.log(chalk.gray(` 版本: ${manifest.version}`));
335
+ console.log(chalk.gray(` Commit: ${manifest.commit} (一致)`));
336
+ } else {
337
+ console.log(chalk.red('✗ Manifest 驗證失敗'));
338
+ for (const err of result.errors) {
339
+ console.log(chalk.red(` - ${err}`));
340
+ }
341
+ }
342
+
343
+ // Show staging status
344
+ const deployments = loadDeployments(projectPath);
345
+ const stagingPassed = deployments.some(
346
+ (d) => d.environment === 'staging' && d.result === 'passed'
347
+ );
348
+
349
+ if (stagingPassed) {
350
+ console.log(chalk.green(' Staging: 已通過 ✓'));
351
+ } else {
352
+ console.log(chalk.yellow(' Staging: 未通過或無紀錄'));
353
+ }
354
+ }
355
+
356
+ /**
357
+ * Show help for release command
358
+ */
359
+ function showReleaseHelp(workflow) {
360
+ console.log();
361
+ console.log(chalk.bold('uds release — 版本發布管理'));
362
+ console.log(chalk.gray('─'.repeat(40)));
363
+ console.log(chalk.gray(` 目前模式: ${workflow.type}`));
364
+ console.log();
365
+
366
+ if (workflow.hasPromote) {
367
+ console.log(chalk.cyan(' 可用子命令:'));
368
+ console.log(chalk.gray(' promote <version> RC → Stable 晉升'));
369
+ console.log(chalk.gray(' deploy <env> 記錄部署紀錄'));
370
+ console.log(chalk.gray(' deploy <env> --result 更新測試結果'));
371
+ console.log(chalk.gray(' manifest 產生 build-manifest.json'));
372
+ console.log(chalk.gray(' verify 驗證 manifest 一致性'));
373
+ } else {
374
+ console.log(chalk.gray(' CI/CD 模式下,請使用 /release start 和 /release finish'));
375
+ console.log(chalk.gray(' 切換到手動模式: uds config --type release_mode'));
376
+ }
377
+ console.log();
378
+ }
@@ -12,7 +12,8 @@ import {
12
12
  promptMethodology,
13
13
  promptCommandsInstallation,
14
14
  handleAgentsMdSharing,
15
- promptAgentsMd
15
+ promptAgentsMd,
16
+ promptReleaseMode
16
17
  } from '../prompts/init.js';
17
18
  import {
18
19
  promptIntegrationConfig
@@ -181,6 +182,9 @@ export async function runInitFlow(options, detected, projectPath) {
181
182
  // === STEP 7: Standard Options ===
182
183
  standardOptions = await promptStandardOptions(3, displayLanguage, { experimental: options.experimental });
183
184
 
185
+ // === STEP 7.5: Release Mode ===
186
+ const releaseMode = await promptReleaseMode();
187
+
184
188
  // === STEP 8: Language Extensions ===
185
189
  if (!languages) {
186
190
  languages = await promptLanguage(detected.languages) || [];
@@ -243,6 +247,7 @@ export async function runInitFlow(options, detected, projectPath) {
243
247
  aiTools,
244
248
  integrations,
245
249
  contentMode,
246
- generateAgentsMd
250
+ generateAgentsMd,
251
+ releaseMode
247
252
  };
248
253
  }
@@ -269,6 +269,32 @@ export const messages = {
269
269
  }
270
270
  },
271
271
 
272
+ // Release Mode
273
+ releaseMode: {
274
+ title: 'Release Mode:',
275
+ description: 'Choose release mode, affects how versions are published',
276
+ question: 'Select release mode:',
277
+ choices: {
278
+ 'ci-cd': 'CI/CD automatic publishing (GitHub Actions, GitLab CI, etc.)',
279
+ manual: 'Manual packaging and deployment (RC workflow)',
280
+ hybrid: 'CI builds + manual deployment'
281
+ },
282
+ details: {
283
+ 'ci-cd': [
284
+ ' → Automatic: push tag → CI builds → publishes',
285
+ ' → Best for: open source, npm/PyPI packages, SaaS'
286
+ ],
287
+ manual: [
288
+ ' → Package → deploy to staging → test → promote to production',
289
+ ' → Best for: on-premise, air-gapped environments, manual QA'
290
+ ],
291
+ hybrid: [
292
+ ' → CI builds artifact, but deployment is manual',
293
+ ' → Best for: regulated industries, multi-stage approval'
294
+ ]
295
+ }
296
+ },
297
+
272
298
  // Merge Strategy
273
299
  mergeStrategy: {
274
300
  title: 'Merge Strategy:',
@@ -953,6 +979,7 @@ export const messages = {
953
979
  integrationConfigLabel: 'Integration Config',
954
980
  ruleCategoriesLabel: 'Rule Categories',
955
981
  gitWorkflow: 'Git Workflow',
982
+ releaseMode: 'Release Mode',
956
983
  mergeStrategy: 'Merge Strategy',
957
984
  commitLanguage: 'Commit Language',
958
985
  testLevels: 'Test Levels',
@@ -1137,10 +1164,12 @@ export const messages = {
1137
1164
  optionLevel: 'Adoption Level - Change Level 1/2/3',
1138
1165
  optionContentMode: 'Content Mode - Change full/index/minimal',
1139
1166
  optionMethodology: 'Methodology - Change development methodology',
1167
+ optionReleaseMode: 'Release Mode - CI/CD, Manual, or Hybrid',
1140
1168
  optionAll: 'All Options',
1141
1169
  experimental: '[Experimental]',
1142
1170
  // Labels
1143
1171
  gitWorkflow: 'Git Workflow',
1172
+ releaseMode: 'Release Mode',
1144
1173
  mergeStrategy: 'Merge Strategy',
1145
1174
  commitLanguage: 'Commit Language',
1146
1175
  testLevels: 'Test Levels',
@@ -1499,6 +1528,32 @@ export const messages = {
1499
1528
  }
1500
1529
  },
1501
1530
 
1531
+ // Release Mode
1532
+ releaseMode: {
1533
+ title: '發布模式:',
1534
+ description: '選擇發布模式,影響版本如何發布',
1535
+ question: '選擇發布模式:',
1536
+ choices: {
1537
+ 'ci-cd': 'CI/CD 自動發布(GitHub Actions、GitLab CI 等)',
1538
+ manual: '手動打包部署(RC 工作流程)',
1539
+ hybrid: 'CI 建置 + 手動部署'
1540
+ },
1541
+ details: {
1542
+ 'ci-cd': [
1543
+ ' → 自動化:推送 tag → CI 建置 → 發布',
1544
+ ' → 適合:開源專案、npm/PyPI 套件、SaaS'
1545
+ ],
1546
+ manual: [
1547
+ ' → 打包 → 部署到測試機 → 測試 → 晉升到正式機',
1548
+ ' → 適合:地端部署、隔離環境、手動 QA'
1549
+ ],
1550
+ hybrid: [
1551
+ ' → CI 建置產物,但部署是手動的',
1552
+ ' → 適合:受監管產業、多階段審核'
1553
+ ]
1554
+ }
1555
+ },
1556
+
1502
1557
  // Merge Strategy
1503
1558
  mergeStrategy: {
1504
1559
  title: '合併策略:',
@@ -2183,6 +2238,7 @@ export const messages = {
2183
2238
  integrationConfigLabel: '整合設定',
2184
2239
  ruleCategoriesLabel: '規則類別',
2185
2240
  gitWorkflow: 'Git 工作流程',
2241
+ releaseMode: '發布模式',
2186
2242
  mergeStrategy: '合併策略',
2187
2243
  commitLanguage: '提交訊息語言',
2188
2244
  testLevels: '測試層級',
@@ -2367,10 +2423,12 @@ export const messages = {
2367
2423
  optionLevel: '採用等級 - 變更等級 1/2/3',
2368
2424
  optionContentMode: '內容模式 - 變更 full/index/minimal',
2369
2425
  optionMethodology: '方法論 - 變更開發方法論',
2426
+ optionReleaseMode: '發布模式 - CI/CD、手動或混合',
2370
2427
  optionAll: '全部選項',
2371
2428
  experimental: '[實驗性]',
2372
2429
  // Labels
2373
2430
  gitWorkflow: 'Git 工作流程',
2431
+ releaseMode: '發布模式',
2374
2432
  mergeStrategy: '合併策略',
2375
2433
  commitLanguage: '提交訊息語言',
2376
2434
  testLevels: '測試層級',
@@ -2729,6 +2787,32 @@ export const messages = {
2729
2787
  }
2730
2788
  },
2731
2789
 
2790
+ // Release Mode
2791
+ releaseMode: {
2792
+ title: '发布模式:',
2793
+ description: '选择发布模式,影响版本如何发布',
2794
+ question: '选择发布模式:',
2795
+ choices: {
2796
+ 'ci-cd': 'CI/CD 自动发布(GitHub Actions、GitLab CI 等)',
2797
+ manual: '手动打包部署(RC 工作流程)',
2798
+ hybrid: 'CI 构建 + 手动部署'
2799
+ },
2800
+ details: {
2801
+ 'ci-cd': [
2802
+ ' → 自动化:推送 tag → CI 构建 → 发布',
2803
+ ' → 适合:开源项目、npm/PyPI 包、SaaS'
2804
+ ],
2805
+ manual: [
2806
+ ' → 打包 → 部署到测试机 → 测试 → 晋升到正式机',
2807
+ ' → 适合:本地部署、隔离环境、手动 QA'
2808
+ ],
2809
+ hybrid: [
2810
+ ' → CI 构建产物,但部署是手动的',
2811
+ ' → 适合:受监管行业、多阶段审批'
2812
+ ]
2813
+ }
2814
+ },
2815
+
2732
2816
  // Merge Strategy
2733
2817
  mergeStrategy: {
2734
2818
  title: '合并策略:',
@@ -3159,6 +3243,7 @@ export const messages = {
3159
3243
  integrationConfigLabel: '集成配置',
3160
3244
  ruleCategoriesLabel: '规则类别',
3161
3245
  gitWorkflow: 'Git 工作流',
3246
+ releaseMode: '发布模式',
3162
3247
  mergeStrategy: '合并策略',
3163
3248
  commitLanguage: '提交消息语言',
3164
3249
  testLevels: '测试级别',
@@ -3526,10 +3611,12 @@ export const messages = {
3526
3611
  optionLevel: '采用级别 - 更改级别 1/2/3',
3527
3612
  optionContentMode: '内容模式 - 更改 full/index/minimal',
3528
3613
  optionMethodology: '方法论 - 更改开发方法论',
3614
+ optionReleaseMode: '发布模式 - CI/CD、手动或混合',
3529
3615
  optionAll: '所有选项',
3530
3616
  experimental: '[实验性]',
3531
3617
  // Labels
3532
3618
  gitWorkflow: 'Git 工作流',
3619
+ releaseMode: '发布模式',
3533
3620
  mergeStrategy: '合并策略',
3534
3621
  commitLanguage: 'Commit 消息语言',
3535
3622
  testLevels: '测试级别',
@@ -35,7 +35,8 @@ export function writeFinalManifest(config, results, projectPath) {
35
35
  workflow: config.standardOptions?.workflow || null,
36
36
  merge_strategy: config.standardOptions?.merge_strategy || null,
37
37
  commit_language: config.standardOptions?.commit_language || null,
38
- test_levels: config.standardOptions?.test_levels || []
38
+ test_levels: config.standardOptions?.test_levels || [],
39
+ release_mode: config.releaseMode || 'ci-cd'
39
40
  },
40
41
  generateAgentsMd: config.generateAgentsMd || false,
41
42
  aiTools: config.aiTools || [],
@@ -643,6 +643,58 @@ export async function promptGitWorkflow() {
643
643
  return workflow;
644
644
  }
645
645
 
646
+ /**
647
+ * Prompt for release mode
648
+ *
649
+ * Release modes determine how versions are published:
650
+ * - ci-cd: Automatic publishing via CI/CD pipeline
651
+ * - manual: Manual packaging and deployment with RC workflow
652
+ * - hybrid: CI builds artifact, manual deployment
653
+ *
654
+ * @returns {Promise<string>} Selected release mode ID
655
+ */
656
+ export async function promptReleaseMode() {
657
+ const msg = t().releaseMode;
658
+
659
+ console.log();
660
+ console.log(chalk.cyan(msg.title));
661
+ console.log(chalk.gray(` ${msg.description}`));
662
+ console.log();
663
+
664
+ const { mode } = await inquirer.prompt([
665
+ {
666
+ type: 'list',
667
+ name: 'mode',
668
+ message: msg.question,
669
+ suffix: ' ',
670
+ choices: [
671
+ {
672
+ name: `${chalk.green('CI/CD')} ${chalk.gray(`(${t().recommended})`)} - ${msg.choices['ci-cd']}`,
673
+ value: 'ci-cd'
674
+ },
675
+ {
676
+ name: `${chalk.blue('Manual')} - ${msg.choices.manual}`,
677
+ value: 'manual'
678
+ },
679
+ {
680
+ name: `${chalk.yellow('Hybrid')} - ${msg.choices.hybrid}`,
681
+ value: 'hybrid'
682
+ }
683
+ ],
684
+ default: 'ci-cd'
685
+ }
686
+ ]);
687
+
688
+ // Show mode details
689
+ console.log();
690
+ for (const line of msg.details[mode]) {
691
+ console.log(chalk.gray(line));
692
+ }
693
+ console.log();
694
+
695
+ return mode;
696
+ }
697
+
646
698
  /**
647
699
  * Prompt for merge strategy
648
700
  *