project-auto-wizard 0.13.3 → 0.14.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.
Files changed (112) hide show
  1. package/README.md +1 -1
  2. package/bin/project-auto-wizard.js +18 -4
  3. package/package.json +2 -2
  4. package/payload/config/breaking-changes.json +28 -14
  5. package/payload/config/wizard-prompts.yml +102 -46
  6. package/payload/flutter-app/android/fastlane/Fastfile.playstore +44 -32
  7. package/payload/flutter-app/ios/ExportOptions.plist +8 -8
  8. package/payload/flutter-app/ios/fastlane/Fastfile +57 -43
  9. package/payload/scripts/changelog_manager.py +296 -257
  10. package/payload/scripts/issue_helper.py +54 -50
  11. package/payload/scripts/messages.py +2279 -0
  12. package/payload/scripts/truncate_release_notes.py +7 -6
  13. package/payload/scripts/version_manager.py +64 -61
  14. package/payload/version.yml.template +2 -1
  15. package/payload/workflows/common/PROJECT-COMMON-AI-PR-SUMMARY.yaml +17 -12
  16. package/payload/workflows/common/PROJECT-COMMON-AUTO-CHANGELOG-CONTROL.yaml +59 -34
  17. package/payload/workflows/common/PROJECT-COMMON-ISSUE-HELPER.yaml +17 -15
  18. package/payload/workflows/common/PROJECT-COMMON-README-VERSION-UPDATE.yaml +17 -10
  19. package/payload/workflows/common/PROJECT-COMMON-RELEASE-PUBLISH.yaml +54 -44
  20. package/payload/workflows/common/PROJECT-COMMON-VERSION-CONTROL.yaml +24 -17
  21. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +194 -184
  22. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +226 -213
  23. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +46 -42
  24. package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +334 -241
  25. package/payload/workflows/flutter/PROJECT-FLUTTER-APP-BUILD-TRIGGER.yaml +152 -128
  26. package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +246 -188
  27. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +353 -238
  28. package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +96 -85
  29. package/payload/workflows/go/PROJECT-GO-CI.yaml +47 -36
  30. package/payload/workflows/go/PROJECT-GO-PR-PREVIEW.yaml +945 -508
  31. package/payload/workflows/go/PROJECT-GO-SIMPLE-CICD.yaml +155 -133
  32. package/payload/workflows/next/PROJECT-NEXT-CI.yaml +76 -60
  33. package/payload/workflows/next/PROJECT-NEXT-CICD.yaml +97 -77
  34. package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +62 -47
  35. package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +942 -505
  36. package/payload/workflows/python/PROJECT-PYTHON-SIMPLE-CICD.yaml +148 -126
  37. package/payload/workflows/react/PROJECT-REACT-CI.yaml +86 -70
  38. package/payload/workflows/react/PROJECT-REACT-CICD.yaml +112 -92
  39. package/payload/workflows/spring/PROJECT-SPRING-CI.yml +112 -82
  40. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-NGINX-CICD.yaml +180 -150
  41. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-NONSTOP-TRAEFIK-CICD.yaml +161 -131
  42. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +970 -549
  43. package/payload/workflows/spring/server-deploy/PROJECT-SPRING-SIMPLE-CICD.yaml +193 -162
  44. package/src/cli/args.js +98 -52
  45. package/src/cli/help.js +8 -41
  46. package/src/commands/doctor.js +85 -89
  47. package/src/commands/dry-run.js +63 -43
  48. package/src/commands/full.js +79 -77
  49. package/src/commands/install-settings.js +16 -15
  50. package/src/commands/interactive-flutter.js +20 -19
  51. package/src/commands/interactive.js +135 -132
  52. package/src/commands/purge.js +47 -42
  53. package/src/commands/status.js +36 -36
  54. package/src/commands/uninstall.js +43 -41
  55. package/src/context.js +12 -11
  56. package/src/core/assets.js +12 -11
  57. package/src/core/baseline.js +27 -27
  58. package/src/core/branches.js +29 -27
  59. package/src/core/branding.js +7 -6
  60. package/src/core/breaking-check.js +22 -21
  61. package/src/core/breaking.js +15 -8
  62. package/src/core/copy/app-files.js +5 -4
  63. package/src/core/copy/flutter-app.js +8 -8
  64. package/src/core/copy/gitignore.js +58 -50
  65. package/src/core/copy/readme.js +45 -35
  66. package/src/core/copy/simple.js +16 -15
  67. package/src/core/copy/workflows.js +131 -124
  68. package/src/core/deploy-style.js +51 -48
  69. package/src/core/detect-fs.js +57 -57
  70. package/src/core/detect.js +67 -65
  71. package/src/core/errors.js +2 -2
  72. package/src/core/flutter-doctor.js +17 -16
  73. package/src/core/flutter-hooks.js +33 -32
  74. package/src/core/flutter-options.js +34 -33
  75. package/src/core/fsutil.js +12 -12
  76. package/src/core/installed-stores.js +4 -4
  77. package/src/core/logger.js +42 -40
  78. package/src/core/paths-resolve.js +88 -86
  79. package/src/core/paths.js +10 -10
  80. package/src/core/release-options.js +8 -8
  81. package/src/core/removal-exec.js +14 -13
  82. package/src/core/removal-plan.js +37 -37
  83. package/src/core/types.js +47 -47
  84. package/src/core/verify.js +44 -38
  85. package/src/core/version-yml.js +76 -68
  86. package/src/core/wizard-env.js +46 -46
  87. package/src/core/wizard-labels.js +63 -41
  88. package/src/i18n/catalog/en/cli.js +50 -0
  89. package/src/i18n/catalog/en/commands.js +187 -0
  90. package/src/i18n/catalog/en/copy.js +19 -0
  91. package/src/i18n/catalog/en/core.js +74 -0
  92. package/src/i18n/catalog/en/core2.js +15 -0
  93. package/src/i18n/catalog/en/ui.js +221 -0
  94. package/src/i18n/catalog/en.js +12 -0
  95. package/src/i18n/catalog/index.js +5 -0
  96. package/src/i18n/catalog/ko/cli.js +50 -0
  97. package/src/i18n/catalog/ko/commands.js +187 -0
  98. package/src/i18n/catalog/ko/copy.js +19 -0
  99. package/src/i18n/catalog/ko/core.js +74 -0
  100. package/src/i18n/catalog/ko/core2.js +15 -0
  101. package/src/i18n/catalog/ko/ui.js +221 -0
  102. package/src/i18n/catalog/ko.js +10 -0
  103. package/src/i18n/index.js +44 -0
  104. package/src/i18n/languages.js +9 -0
  105. package/src/index.js +128 -94
  106. package/src/ui/ansi.js +7 -7
  107. package/src/ui/banner.js +7 -6
  108. package/src/ui/env-plan.js +82 -81
  109. package/src/ui/prompts.js +97 -122
  110. package/src/ui/readline-engine.js +59 -58
  111. package/src/ui/status-cards.js +37 -31
  112. package/src/ui/summary.js +89 -88
package/src/cli/args.js CHANGED
@@ -1,52 +1,87 @@
1
- // CLI 인자 파싱.
1
+ // CLI argument parsing.
2
2
  import { VALID_TYPES, VALID_MODES } from "../context.js";
3
3
  import { DEPLOY_STYLES, isDeployStyle, NO_DEPLOY_STYLE } from "../core/deploy-style.js";
4
4
  import { isValidBranchName } from "../core/branches.js";
5
5
  import { TYPES } from "../core/types.js";
6
6
  import { CliError } from "../core/errors.js";
7
7
  import { normalizePath, isRepoRelativePath } from "../core/paths.js";
8
+ import { t, DEFAULT_LANGUAGE, SUPPORTED_LANGUAGES, isSupportedLanguage, normalizeLanguage } from "../i18n/index.js";
8
9
 
9
- // 기존 import 경로(cli/args.js) 호환 — 정의는 core에 있다.
10
+ // Kept for the existing import path (cli/args.js); the definitions live in core.
10
11
  export { CliError, normalizePath, isRepoRelativePath };
11
12
 
12
- // 타입 전용 CLI 플래그(타입 훅 cliFlags) — 플래그 이름 → { field, initial, parse }. 훅은 타입 표 순서대로 모은다.
13
+ // Type-specific CLI flags (type hook cliFlags): flag name -> { field, initial, parse }. Hooks are collected in type-table order.
13
14
  export const TYPE_CLI_FLAGS = TYPES.flatMap((t) => t.hooks?.cliFlags ?? []);
14
15
  const TYPE_CLI_FLAG_BY_NAME = new Map(TYPE_CLI_FLAGS.map((f) => [f.flag, f]));
15
16
 
16
- // argv(process.argv.slice(2)) → 파싱 결과. 오류 시 throw(호출부에서 exit 1).
17
+ // Options that consume a value, and options that are plain switches. Needed to expand `--name=value`.
18
+ const VALUE_FLAGS = new Set([
19
+ "--mode", "--project-version", "--type", "--lang", "--deploy-style", "--paths", "--main-branch", "--develop-branch",
20
+ ...TYPE_CLI_FLAGS.map((f) => f.flag),
21
+ ]);
22
+ const SWITCH_FLAGS = new Set([
23
+ "--version", "--help", "--force", "--dry-run", "--purge-readme", "--purge-gitignore", "--purge-version", "--yes", "--allow-dirty",
24
+ "--delete-develop-branch", "--keep-version-yml", "--keep-readme", "--keep-changelog", "--keep-workflows", "--keep-scripts",
25
+ "--semver-auto", "--no-semver-auto", "--copilot", "--no-copilot",
26
+ ]);
27
+
28
+ // `--name=value` -> `--name`, `value`, so the parser below only sees the space-separated form.
29
+ // Only the first "=" splits, so `--paths=flutter=app` keeps its value intact. A switch given a value is an error
30
+ // (silently ignoring it would hide a typo); an unknown name is left as-is and reported by the parser.
31
+ // The token after a value option is that option's value and is never expanded.
32
+ function expandInlineValues(argv) {
33
+ const out = [];
34
+ for (let i = 0; i < argv.length; i++) {
35
+ const a = argv[i];
36
+ const eq = a.startsWith("--") ? a.indexOf("=") : -1;
37
+ if (eq < 0) {
38
+ out.push(a);
39
+ if (VALUE_FLAGS.has(a) && i + 1 < argv.length) out.push(argv[++i]);
40
+ continue;
41
+ }
42
+ const name = a.slice(0, eq);
43
+ if (VALUE_FLAGS.has(name)) out.push(name, a.slice(eq + 1));
44
+ else if (SWITCH_FLAGS.has(name)) throw new CliError(t("cli.args.flagNoValue", { flag: name, value: a.slice(eq + 1) }));
45
+ else out.push(a);
46
+ }
47
+ return out;
48
+ }
49
+
50
+ // argv (process.argv.slice(2)) -> parse result. Throws on error (the caller exits with 1).
17
51
  export function parseArgs(argv) {
18
52
  const result = {
19
53
  mode: "interactive",
20
- version: "", // 통합 대상 프로젝트의 초기 버전 (--project-version)
54
+ version: "", // initial version of the target project (--project-version)
21
55
  types: [],
22
56
  primaryType: "",
23
- includeSemverAuto: null, // --semver-auto / --no-semver-auto (기본 true — 미지정 시 다운스트림에서 해석)
24
- includeCopilotAi: null, // --copilot / --no-copilot (기본 false — AI Credits를 소비하는 opt-in)
25
- pathsCsv: "", // "flutter=app,react=client" 원문 (정규화는 resolve 단계)
26
- mainBranch: "", // 릴리스 브랜치 (--main-branch). 빈값=감지된 default branch
27
- developBranch: "", // 개발 브랜치 (--develop-branch). 빈값=develop
28
- deployStyle: "", // 서버 배포 방식 (--deploy-style). 빈값=version.yml 저장값 → simple
29
- // 타입 전용 플래그 필드(예: Flutter 환경변수 방식·스토어 대상·배포 모드) — 미지정 값은 타입 훅이 정한다.
57
+ includeSemverAuto: null, // --semver-auto / --no-semver-auto (default true; resolved downstream when unset)
58
+ includeCopilotAi: null, // --copilot / --no-copilot (default false; opt-in because it consumes AI Credits)
59
+ pathsCsv: "", // raw "flutter=app,react=client" (normalized in the resolve step)
60
+ mainBranch: "", // release branch (--main-branch). empty = detected default branch
61
+ developBranch: "", // development branch (--develop-branch). empty = develop
62
+ deployStyle: "", // server deploy style (--deploy-style). empty = saved version.yml value -> simple
63
+ // Type-specific flag fields (e.g. Flutter env mode, store targets, deploy mode); unset values are decided by the type hook.
30
64
  ...Object.fromEntries(TYPE_CLI_FLAGS.map((f) => [f.field, f.initial])),
65
+ lang: "", // message language (--lang). empty = env var -> saved version.yml value -> en
31
66
  force: false,
32
67
  help: false,
33
- showVersion: false, // -v/--version → 패키지 버전 출력 (npm 관례)
34
- dryRun: false, // --dry-run: 실제 변경 없이 미리보기만 (full/uninstall)
35
- purgeReadme: false, // --purge-readme: uninstall --force 시 README 버전 섹션도 제거
36
- purgeGitignore: false, // --purge-gitignore: uninstall --force 시 .gitignore 자동 추가 항목도 제거
37
- purgeVersion: false, // --purge-version: uninstall --force 시 version.yml도 제거
38
- // purge 전용 플래그 (숨김 모드 — HELP_TEXT에는 노출하지 않는다).
39
- yes: false, // --yes: purge 실행 확인 (필수, --force로 대체 불가)
40
- allowDirty: false, // --allow-dirty: git 작업트리 dirty 상태에서도 강행
41
- deleteDevelopBranch: false, // --delete-develop-branch: 로컬 develop 브랜치까지 삭제
68
+ showVersion: false, // -v/--version -> print the package version (npm convention)
69
+ dryRun: false, // --dry-run: preview only, no changes (full/uninstall)
70
+ purgeReadme: false, // --purge-readme: also remove the README version section on uninstall --force
71
+ purgeGitignore: false, // --purge-gitignore: also remove auto-added .gitignore entries on uninstall --force
72
+ purgeVersion: false, // --purge-version: also remove version.yml on uninstall --force
73
+ // purge-only flags (hidden mode; not shown in the help text).
74
+ yes: false, // --yes: confirms purge (required; --force cannot replace it)
75
+ allowDirty: false, // --allow-dirty: proceed even with a dirty git working tree
76
+ deleteDevelopBranch: false, // --delete-develop-branch: also delete the local develop branch
42
77
  keepVersionYml: false,
43
78
  keepReadme: false,
44
79
  keepChangelog: false,
45
80
  keepWorkflows: false,
46
81
  keepScripts: false,
47
82
  };
48
- const args = [...argv];
49
- const seenFlags = new Set(); // --semver-auto/--copilot류 상호 모순 플래그 검증용
83
+ const args = expandInlineValues(argv);
84
+ const seenFlags = new Set(); // for validating mutually exclusive flags such as --semver-auto/--copilot
50
85
  while (args.length > 0) {
51
86
  const a = args.shift();
52
87
  const typeFlag = TYPE_CLI_FLAG_BY_NAME.get(a);
@@ -55,14 +90,14 @@ export function parseArgs(argv) {
55
90
  case "-m": case "--mode":
56
91
  result.mode = args.shift() ?? ""; break;
57
92
  case "-v": case "--version":
58
- // npm 관례: -v/--version 은 패키지 버전 출력. (초기 버전 지정은 --project-version)
93
+ // npm convention: -v/--version prints the package version (use --project-version for the initial version).
59
94
  result.showVersion = true; break;
60
95
  case "--project-version": {
61
- // 릴리스 워크플로우(version_manager)는 x.y.z만 올릴 수 있다 — 흔한 v 접두사는 떼고 받는다.
96
+ // The release workflow (version_manager) can only bump x.y.z, so accept the common v prefix and strip it.
62
97
  const raw = (args.shift() ?? "").trim();
63
98
  const v = raw.replace(/^v/i, "");
64
99
  if (!/^\d+\.\d+\.\d+$/.test(v)) {
65
- throw new CliError(`--project-version 값이 올바르지 않습니다: '${raw}' (x.y.z 형식, 예: 1.0.0)`);
100
+ throw new CliError(t("cli.args.projectVersionInvalid", { raw }));
66
101
  }
67
102
  result.version = v; break;
68
103
  }
@@ -70,21 +105,32 @@ export function parseArgs(argv) {
70
105
  const csv = args.shift() ?? "";
71
106
  const seen = new Set();
72
107
  const types = [];
73
- for (let t of csv.split(",")) {
74
- t = t.replace(/\s/g, "");
75
- if (t === "") continue;
76
- if (seen.has(t)) continue; // dedup
77
- if (!VALID_TYPES.includes(t)) {
78
- throw new CliError(`지원하지 않는 타입: '${t}'\n지원 타입: ${VALID_TYPES.join(" ")}`);
108
+ for (let name of csv.split(",")) {
109
+ name = name.replace(/\s/g, "");
110
+ if (name === "") continue;
111
+ if (seen.has(name)) continue; // dedup
112
+ if (!VALID_TYPES.includes(name)) {
113
+ throw new CliError(t("cli.args.typeUnsupported", { type: name, valid: VALID_TYPES.join(" ") }));
79
114
  }
80
- seen.add(t);
81
- types.push(t);
115
+ seen.add(name);
116
+ types.push(name);
82
117
  }
83
- if (types.length === 0) throw new CliError("--type 인자가 비어 있습니다");
118
+ if (types.length === 0) throw new CliError(t("cli.args.typeEmpty"));
84
119
  result.types = types;
85
120
  result.primaryType = types[0];
86
121
  break;
87
122
  }
123
+ case "--lang": {
124
+ // Errors here always use the default language (en) so they stay stable regardless of the provisional language.
125
+ const supported = SUPPORTED_LANGUAGES.join(", ");
126
+ const raw = args.shift();
127
+ const v = normalizeLanguage(raw);
128
+ if (!v) throw new CliError(t("cli.lang.missing", { supported }, DEFAULT_LANGUAGE));
129
+ if (!isSupportedLanguage(v)) {
130
+ throw new CliError(t("cli.lang.invalid", { value: String(raw).trim(), source: "--lang", supported }, DEFAULT_LANGUAGE));
131
+ }
132
+ result.lang = v; break;
133
+ }
88
134
  case "--force": result.force = true; break;
89
135
  case "--dry-run": result.dryRun = true; break;
90
136
  case "--purge-readme": result.purgeReadme = true; break;
@@ -101,50 +147,50 @@ export function parseArgs(argv) {
101
147
  case "--deploy-style": {
102
148
  const v = args.shift();
103
149
  if (!isDeployStyle(v)) {
104
- throw new CliError(`--deploy-style 값이 올바르지 않습니다: ${v ?? "(없음)"} (${[...DEPLOY_STYLES.map((s) => s.value), NO_DEPLOY_STYLE].join(" | ")})`);
150
+ throw new CliError(t("cli.args.deployStyleInvalid", {
151
+ value: v ?? t("cli.args.noValue"), choices: [...DEPLOY_STYLES.map((s) => s.value), NO_DEPLOY_STYLE].join(" | "),
152
+ }));
105
153
  }
106
154
  result.deployStyle = v; break;
107
155
  }
108
156
  case "--semver-auto":
109
- if (seenFlags.has("--no-semver-auto")) throw new CliError("--semver-auto와 --no-semver-auto는 동시에 지정할 수 없습니다");
157
+ if (seenFlags.has("--no-semver-auto")) throw new CliError(t("cli.args.semverConflict"));
110
158
  seenFlags.add("--semver-auto"); result.includeSemverAuto = true; break;
111
159
  case "--no-semver-auto":
112
- if (seenFlags.has("--semver-auto")) throw new CliError("--semver-auto와 --no-semver-auto는 동시에 지정할 수 없습니다");
160
+ if (seenFlags.has("--semver-auto")) throw new CliError(t("cli.args.semverConflict"));
113
161
  seenFlags.add("--no-semver-auto"); result.includeSemverAuto = false; break;
114
162
  case "--copilot":
115
- if (seenFlags.has("--no-copilot")) throw new CliError("--copilot과 --no-copilot은 동시에 지정할 수 없습니다");
163
+ if (seenFlags.has("--no-copilot")) throw new CliError(t("cli.args.copilotConflict"));
116
164
  seenFlags.add("--copilot"); result.includeCopilotAi = true; break;
117
165
  case "--no-copilot":
118
- if (seenFlags.has("--copilot")) throw new CliError("--copilot과 --no-copilot은 동시에 지정할 수 없습니다");
166
+ if (seenFlags.has("--copilot")) throw new CliError(t("cli.args.copilotConflict"));
119
167
  seenFlags.add("--no-copilot"); result.includeCopilotAi = false; break;
120
168
  case "--paths": {
121
- // 값이 없는데 조용히 자동 감지로 넘어가면 사용자가 지정했다고 믿은 경로와 다르게 설치된다.
169
+ // Silently falling back to auto-detection would install to paths other than the ones the user thinks they set.
122
170
  const v = (args.shift() ?? "").trim();
123
- if (!v) throw new CliError("--paths 인자가 비어 있습니다 (예: --paths flutter=app,react=client)");
171
+ if (!v) throw new CliError(t("cli.args.pathsEmpty"));
124
172
  result.pathsCsv = v; break;
125
173
  }
126
174
  case "--main-branch": case "--develop-branch": {
127
175
  const v = (args.shift() ?? "").trim();
128
- if (!v) throw new CliError(`${a}에 빈 값을 지정할 수 없습니다`);
129
- // 워크플로우 트리거·셸 명령에 그대로 치환되는 값이라 쓸 수 없는 이름은 설치 전에 거부한다.
130
- if (!isValidBranchName(v)) throw new CliError(`${a} 값이 브랜치 이름으로 올바르지 않습니다: '${v}'`);
176
+ if (!v) throw new CliError(t("cli.args.branchEmpty", { flag: a }));
177
+ // The value is substituted into workflow triggers and shell commands, so reject unusable names before installing.
178
+ if (!isValidBranchName(v)) throw new CliError(t("cli.args.branchInvalid", { flag: a, value: v }));
131
179
  if (a === "--main-branch") result.mainBranch = v; else result.developBranch = v;
132
180
  break;
133
181
  }
134
182
  case "-h": case "--help": result.help = true; break;
135
183
  default:
136
- throw new CliError(`알 수 없는 옵션: ${a}`);
184
+ throw new CliError(t("cli.args.unknownOption", { option: a }));
137
185
  }
138
186
  }
139
187
  if (!VALID_MODES.includes(result.mode)) {
140
- throw new CliError(
141
- `지원하지 않는 모드: '${result.mode}'\n지원 모드: interactive full uninstall status doctor`
142
- );
188
+ throw new CliError(t("cli.args.modeUnsupported", { mode: result.mode }));
143
189
  }
144
190
  return result;
145
191
  }
146
192
 
147
- // "flutter=app,react=client" → Map<type, normalizedPath>. 타입 검증(무효 → throw).
193
+ // "flutter=app,react=client" -> Map<type, normalizedPath>. Validates types (invalid -> throw).
148
194
  export function parsePathsCsv(csv) {
149
195
  const map = new Map();
150
196
  if (!csv) return map;
@@ -154,11 +200,11 @@ export function parsePathsCsv(csv) {
154
200
  const type = (eq >= 0 ? pair.slice(0, eq) : pair).replace(/\s/g, "");
155
201
  const rawPath = eq >= 0 ? pair.slice(eq + 1) : "";
156
202
  if (!VALID_TYPES.includes(type)) {
157
- throw new CliError(`--paths에 지원하지 않는 타입: '${type}'`);
203
+ throw new CliError(t("cli.args.pathsTypeUnsupported", { type }));
158
204
  }
159
205
  const path = normalizePath(rawPath);
160
206
  if (!isRepoRelativePath(path)) {
161
- throw new CliError(`--paths는 레포 안의 상대경로만 지정할 수 있습니다: '${type}=${rawPath.trim()}'`);
207
+ throw new CliError(t("cli.args.pathsRelativeOnly", { pair: `${type}=${rawPath.trim()}` }));
162
208
  }
163
209
  map.set(type, path);
164
210
  }
package/src/cli/help.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { TYPE_IDS } from "../core/types.js";
2
+ import { t, getLanguage, SUPPORTED_LANGUAGES } from "../i18n/index.js";
2
3
 
3
- // 지원 타입 목록 — 레지스트리 순서대로 한 줄 40자 안쪽에서 줄바꿈하고, 이어지는 줄은 "지원: " 뒤에 맞춘다.
4
+ // Supported type list: wrapped at 40 characters per line in registry order; continuation lines align after the "Supported:" label.
4
5
  function typeListLines(width = 40) {
5
6
  const lines = [];
6
7
  for (const id of TYPE_IDS) {
@@ -11,43 +12,9 @@ function typeListLines(width = 40) {
11
12
  return lines.join(`\n${" ".repeat(33)}`);
12
13
  }
13
14
 
14
- // --help 텍스트.
15
- export const HELP_TEXT = `project-auto-wizard — One command DevOps: GitHub-native 릴리스 자동화 설치 마법사
16
-
17
- 사용법:
18
- npx project-auto-wizard [옵션]
19
-
20
- 옵션:
21
- -m, --mode MODE 통합 모드 (full | uninstall | status | doctor)
22
- 기본: interactive (대화형). full = 설치 및 업데이트
23
- uninstall = 완전 삭제(대화형 체크리스트, --force 시 --purge-*로 opt-in)
24
- status = 설치 상태·드리프트 확인(읽기 전용). doctor = 환경 진단(읽기 전용)
25
- -t, --type CSV 프로젝트 타입 csv (예: spring,react,python)
26
- 지원: ${typeListLines()}
27
- --project-version V 통합 대상의 초기 버전 (예: 1.0.0). 미지정 시 자동 감지
28
- --paths "t=p,..." 타입별 프로젝트 경로 (모노레포). 예: flutter=app,react=client
29
- --main-branch B 릴리스 브랜치 (기본: 감지된 default branch)
30
- --develop-branch B 개발 브랜치 (기본: develop). 릴리스 브랜치와 같으면 trunk-based 모드
31
- --deploy-style STYLE 서버 배포 방식: simple | nginx | traefik | none (기본: simple)
32
- --flutter-env-mode MODE Flutter 환경변수 방식: dart-define | dotenv (기본: 신규 설치 dart-define, 기존 설치는 저장값·dotenv 유지)
33
- --flutter-store CSV Flutter 스토어 배포 대상: android,ios | android | ios | none (기본: 둘 다 설치)
34
- --android-deploy-mode MODE Play Store 배포 모드: store_only | store_prepare | store_submit (기본: store_only)
35
- --ios-deploy-mode MODE iOS 배포 모드: store_only | store_prepare | store_submit (기본: store_only)
36
- --semver-auto / --no-semver-auto 커밋 타입 기반 자동 major/minor/patch 승격 (기본: 사용함)
37
- --copilot / --no-copilot Copilot으로 AI 요약 생성 (기본: 사용 안 함, GitHub Copilot AI Credits 소비)
38
- --force full 실행에 필수, uninstall은 비대화형 삭제 (모든 확인 생략, 기본값 사용)
39
- --dry-run 실제 파일 변경 없이 무엇이 바뀔지만 미리 보여줌 (full/uninstall 지원)
40
- --purge-readme --mode uninstall --force 시 README.md 버전 섹션도 제거
41
- --purge-gitignore --mode uninstall --force 시 .gitignore 자동 추가 항목도 제거
42
- --purge-version --mode uninstall --force 시 version.yml도 제거
43
- -v, --version project-auto-wizard 버전 출력
44
- -h, --help 이 도움말 표시
45
-
46
- 예시:
47
- npx project-auto-wizard --mode full --force --type spring,react
48
- npx project-auto-wizard --mode full --force --type flutter --paths "flutter=app"
49
- npx project-auto-wizard --mode status
50
- npx project-auto-wizard --mode doctor
51
- npx project-auto-wizard --mode full --force --type node --dry-run
52
- npx project-auto-wizard --mode uninstall --force --purge-readme --purge-gitignore --purge-version
53
- `;
15
+ // --help text. Built lazily because the language is only resolved after import time;
16
+ // `lang` lets callers (docs checks) render a specific language regardless of the current one.
17
+ export const helpText = (lang = getLanguage()) => t("cli.help.text", {
18
+ types: typeListLines(),
19
+ langHelp: t("cli.lang.help", { supported: SUPPORTED_LANGUAGES.join(" | ") }, lang),
20
+ }, lang);