projectops 4.31.5 → 4.33.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 (57) hide show
  1. package/README.md +144 -145
  2. package/package.json +2 -2
  3. package/src/cli/args.js +65 -29
  4. package/src/cli/errors.js +9 -7
  5. package/src/cli/help.js +51 -3
  6. package/src/commands/doctor.js +80 -78
  7. package/src/commands/full.js +11 -2
  8. package/src/commands/interactive.js +71 -49
  9. package/src/commands/issues.js +4 -0
  10. package/src/commands/skills.js +8 -7
  11. package/src/commands/version.js +4 -2
  12. package/src/commands/workflows.js +3 -1
  13. package/src/context.js +4 -0
  14. package/src/core/breaking-check.js +6 -5
  15. package/src/core/copy/simple.js +4 -0
  16. package/src/core/copy/workflows.js +10 -5
  17. package/src/core/exclusions.js +8 -0
  18. package/src/core/ide/adapters/claude.js +18 -17
  19. package/src/core/ide/adapters/codex.js +12 -11
  20. package/src/core/ide/adapters/cursor.js +11 -10
  21. package/src/core/ide/adapters/gemini.js +11 -10
  22. package/src/core/ide/adapters/pi-common.js +2 -1
  23. package/src/core/ide/adapters/pi-harness.js +13 -16
  24. package/src/core/ide/adapters/pi.js +12 -11
  25. package/src/core/label-style.js +78 -0
  26. package/src/core/migration-guide.js +38 -38
  27. package/src/core/migrations/index.js +19 -15
  28. package/src/core/migrations/registry.js +70 -55
  29. package/src/core/options-ask.js +65 -64
  30. package/src/core/orphan-workflows.js +2 -1
  31. package/src/core/paths-resolve.js +31 -30
  32. package/src/core/repo-language.js +47 -0
  33. package/src/core/run-trace.js +10 -0
  34. package/src/core/version-yml.js +68 -36
  35. package/src/i18n/core.en.js +31 -0
  36. package/src/i18n/core.ko.js +31 -0
  37. package/src/i18n/doctor.en.js +89 -0
  38. package/src/i18n/doctor.ko.js +89 -0
  39. package/src/i18n/en.js +141 -0
  40. package/src/i18n/ide.en.js +102 -0
  41. package/src/i18n/ide.ko.js +102 -0
  42. package/src/i18n/index.js +73 -0
  43. package/src/i18n/ko.js +134 -0
  44. package/src/i18n/migrate.en.js +66 -0
  45. package/src/i18n/migrate.ko.js +66 -0
  46. package/src/i18n/options.en.js +104 -0
  47. package/src/i18n/options.ko.js +104 -0
  48. package/src/i18n/summary.en.js +70 -0
  49. package/src/i18n/summary.ko.js +70 -0
  50. package/src/index.js +46 -28
  51. package/src/ui/banner.js +8 -6
  52. package/src/ui/env-plan.js +19 -18
  53. package/src/ui/prompts.js +25 -24
  54. package/src/ui/readline-engine.js +18 -10
  55. package/src/ui/skills-prompts.js +8 -7
  56. package/src/ui/status-cards.js +38 -38
  57. package/src/ui/summary.js +103 -111
@@ -3,45 +3,45 @@
3
3
  // 실측 기준: template_integrator.sh 2184~2354.
4
4
 
5
5
  const HEADER = `# ===================================================================
6
- # 프로젝트 버전 관리 파일
6
+ # Project version management file
7
7
  # ===================================================================
8
8
  #
9
- # 이 파일은 다양한 프로젝트 타입에서 버전 정보를 중앙 관리하기 위한 파일입니다.
10
- # GitHub Actions 워크플로우가 이 파일을 읽어 자동으로 버전을 관리합니다.
9
+ # This file keeps version information in one place for every project type.
10
+ # GitHub Actions workflows read this file and manage the version automatically.
11
11
  #
12
- # 사용법:
13
- # 1. version: "1.0.0" - 사용자에게 표시되는 버전
14
- # 2. version_code: 1 - Play Store/App Store 빌드 번호 (1부터 자동 증가)
15
- # 3. project_types: 프로젝트 타입 배열 — 첫 항목이 primary
16
- # 4. project_paths: 타입별 프로젝트 폴더 (레포 루트 기준 상대경로, 모노레포용)
12
+ # Usage:
13
+ # 1. version: "1.0.0" - the version shown to users
14
+ # 2. version_code: 1 - Play Store/App Store build number (auto-incremented from 1)
15
+ # 3. project_types: array of project types, the first entry is the primary one
16
+ # 4. project_paths: project folder per type (relative to the repo root, for monorepos)
17
17
  #
18
- # 자동 버전 업데이트:
19
- # - version_code: 매 빌드마다 자동으로 1씩 증가 (아래 판정과 무관)
20
- # - 버전 승격 폭은 metadata.template.options.semver_auto 가 정합니다
21
- # semver_auto: true -> 릴리스 구간 커밋 제목으로 판정
22
- # "제목 : feat! : 내용" 또는 "feat!:" -> major (x+1.0.0)
23
- # "제목 : feat : 내용" 또는 "feat:" -> minor (x.y+1.0)
24
- # 그 외(fix/docs/chore/refactor/test) -> patch (x.y.z+1)
25
- # 키 없음 / false -> 항상 patch +1
26
- # - 위 판정과 무관하게 version 값을 직접 수정해도 됩니다
18
+ # Automatic version updates:
19
+ # - version_code: incremented by 1 on every build (independent of the rules below)
20
+ # - How far the version is bumped is decided by metadata.template.options.semver_auto
21
+ # semver_auto: true -> decided by the commit titles in the release range
22
+ # "title : feat! : body" or "feat!:" -> major (x+1.0.0)
23
+ # "title : feat : body" or "feat:" -> minor (x.y+1.0)
24
+ # anything else (fix/docs/chore/refactor/test) -> patch (x.y.z+1)
25
+ # key missing / false -> always patch +1
26
+ # - You may edit the version value by hand regardless of the rules above
27
27
  #
28
- # 프로젝트 타입별 동기화 파일:
28
+ # Files synced per project type:
29
29
  # - spring: build.gradle (version = "x.y.z")
30
- # - flutter: pubspec.yaml (version: x.y.z+i, buildNumber 포함)
30
+ # - flutter: pubspec.yaml (version: x.y.z+i, includes buildNumber)
31
31
  # - react/node: package.json ("version": "x.y.z")
32
- # - react-native: iOS Info.plist 또는 Android build.gradle
32
+ # - react-native: iOS Info.plist or Android build.gradle
33
33
  # - react-native-expo: app.json (expo.version)
34
34
  # - python: pyproject.toml (version = "x.y.z")
35
- # - basic/기타: version.yml 파일만 사용
35
+ # - basic/other: only this version.yml file is used
36
36
  #
37
- # 연관된 워크플로우:
37
+ # Related workflows:
38
38
  # - .github/workflows/PROJECT-VERSION-CONTROL.yaml
39
39
  # - .github/workflows/PROJECT-README-VERSION-UPDATE.yaml
40
40
  # - .github/workflows/PROJECT-RELEASE-CHANGELOG.yaml
41
41
  #
42
- # 주의사항:
43
- # - project_types는 최초 설정 후 변경하지 마세요
44
- # - 버전은 항상 높은 버전으로 자동 동기화됩니다
42
+ # Notes:
43
+ # - Do not change project_types after the initial setup
44
+ # - The version is always synced automatically to the highest one
45
45
  # ===================================================================
46
46
  `;
47
47
 
@@ -56,8 +56,8 @@ const HEADER = `# ==============================================================
56
56
  // (options-ask.js가 이 함수를 import한다 — 순환 방지 위해 여기(version-yml)에 정의.)
57
57
  export function parseTemplateOptions(content) {
58
58
  const out = { deploy: null, publish: null, secretBackup: null,
59
- changelogProvider: null, changelogBaseUrl: null, codeReviewCoderabbit: null, aiPrSummary: null,
60
- deployBranch: null, intent: null, semverAuto: null, appRelease: null };
59
+ changelogProvider: null, changelogBaseUrl: null, codeReviewCoderabbit: null, aiPrSummary: null, projectsSync: null,
60
+ deployBranch: null, intent: null, semverAuto: null, appRelease: null, labelStyle: null, closeOnRelease: null, language: null };
61
61
  // deploy_branch는 metadata 직속(#456) — template.options 밖이라 별도로 스캔한다.
62
62
  for (const line of String(content || "").split("\n")) {
63
63
  if (line.startsWith("#")) continue;
@@ -135,6 +135,30 @@ export function parseTemplateOptions(content) {
135
135
  out.semverAuto = m[1] === "true";
136
136
  continue;
137
137
  }
138
+ // 레포 문구 언어(#769) — en | ko. 미기재는 "기존 통합 레포" 신호라 호출부가 ko 로 해석한다.
139
+ m = line.match(/^\s+language:\s*["']?(en|ko)["']?/);
140
+ if (m) {
141
+ out.language = m[1];
142
+ continue;
143
+ }
144
+ // 상태 라벨 표기(#776) — en(영문 표준) | ko(기존 한글). 미기재는 "기존 통합 레포" 신호라 호출부가 ko로 해석한다.
145
+ m = line.match(/^\s+label_style:\s*["']?(en|ko)["']?/);
146
+ if (m) {
147
+ out.labelStyle = m[1];
148
+ continue;
149
+ }
150
+ // Projects 보드 동기화(#716). null(미기재)이면 호출부가 "이미 설치돼 있으면 유지, 아니면 제외"로 해석한다.
151
+ m = line.match(/^\s+projects_sync:\s*["']?(true|false)["']?/);
152
+ if (m) {
153
+ out.projectsSync = m[1] === "true";
154
+ continue;
155
+ }
156
+ // 릴리스 시 완료 이슈 닫기(#771). null(미기재)은 "기존 통합 레포" 신호 — 워크플로우가 아무것도 하지 않는다.
157
+ m = line.match(/^\s+close_on_release:\s*["']?(true|false)["']?/);
158
+ if (m) {
159
+ out.closeOnRelease = m[1] === "true";
160
+ continue;
161
+ }
138
162
  // 프로젝트 성격(#553) — 앱 심사로 이어지는 레포인가. 워크플로우와 스킬이 같은 값을 본다.
139
163
  m = line.match(/^\s+app_release:\s*["']?(true|false)["']?/);
140
164
  if (m) {
@@ -210,7 +234,7 @@ export function convertLegacySingularType(content) {
210
234
  return lines.join("\n");
211
235
  }
212
236
  const type = value === "next" ? "react" : value; // next 타입은 4.1.0에서 react로 흡수
213
- lines[idx] = `project_types: ["${type}"] # 멀티타입 배열 — 첫 항목이 primary, 직접 편집 가능`;
237
+ lines[idx] = `project_types: ["${type}"] # array of types, first entry is primary, safe to edit by hand`;
214
238
  return lines.join("\n");
215
239
  }
216
240
 
@@ -311,11 +335,11 @@ export function buildVersionYml({ version, types = [], paths = new Map(), pathMa
311
335
  let out = HEADER + "\n";
312
336
  out += `version: "${version}"\n`;
313
337
  out += `version_code: ${versionCode} # app build number\n`;
314
- out += `project_types: ${typesJson} # 멀티타입 배열 — 첫 항목이 primary, 직접 편집 가능\n`;
338
+ out += `project_types: ${typesJson} # array of types, first entry is primary, safe to edit by hand\n`;
315
339
 
316
340
  // project_paths 블록. pathMarkers: Map<type, markerFilename> (있으면 " type: "path" # path/marker" 주석).
317
341
  if (paths.size) {
318
- out += `project_paths: # 타입별 프로젝트 폴더 (레포 루트 기준 상대경로)\n`;
342
+ out += `project_paths: # project folder per type (relative to the repo root)\n`;
319
343
  for (const [t, p] of paths) {
320
344
  const marker = pathMarkers.get(t) || "";
321
345
  const pf = p === "." ? marker : (marker ? `${p}/${marker}` : p);
@@ -337,7 +361,7 @@ export function buildVersionYml({ version, types = [], paths = new Map(), pathMa
337
361
  if (templateOptions) {
338
362
  const { templateVersion = "unknown", deployTarget = "docker-ssh", publishTargets = [], includeSecretBackup = false, optionsDate = today,
339
363
  changelogProvider = "commit", changelogBaseUrl = "", codeReviewCoderabbit = true, aiPrSummary = true, intent = null, mode = null,
340
- semverAuto = true, appRelease = null } = templateOptions;
364
+ semverAuto = true, appRelease = null, labelStyle = null, closeOnRelease = null, projectsSync = null, language = null } = templateOptions;
341
365
  const publishJson = `[${publishTargets.map((t) => `"${t}"`).join(",")}]`;
342
366
  // intent(프로젝트 성격, #485) — 미지정이면 deploy/publish에서 역추론해 기록 (재통합 시 진입 질문 생략용)
343
367
  const intentVal = intent || inferIntent(deployTarget, publishTargets) || "manual";
@@ -345,19 +369,27 @@ export function buildVersionYml({ version, types = [], paths = new Map(), pathMa
345
369
  out += ` source: "projectops"\n`;
346
370
  out += ` version: "${templateVersion}"\n`;
347
371
  // mode(#502) — 이 레포에 통합된 범위. 업데이트 모드가 같은 범위를 재실행하는 기준.
348
- if (mode) out += ` mode: "${mode}" # 통합 범위(full/version/workflows) — 업데이트 모드 재실행 기준\n`;
372
+ if (mode) out += ` mode: "${mode}" # install scope (full/version/workflows), used when re-running update mode\n`;
349
373
  out += ` integrated_date: "${optionsDate}"\n`;
350
374
  out += ` last_update_date: "${optionsDate}"\n`;
351
375
  out += ` options:\n`;
352
- out += ` intent: "${intentVal}" # 프로젝트 성격(app/library/both/none/manual) — 배포 질문 유도 기준\n`;
376
+ out += ` intent: "${intentVal}" # project kind (app/library/both/none/manual), drives the deploy questions\n`;
353
377
  out += ` deploy: "${deployTarget}"\n`;
354
378
  out += ` publish: ${publishJson}\n`;
355
379
  out += ` secret_backup: ${includeSecretBackup}\n`;
356
380
  // semver 자동 승격(#546) — 릴리스 시 커밋 제목으로 major/minor/patch 결정. false면 항상 patch.
357
- out += ` semver_auto: ${semverAuto} # 커밋 제목으로 버전 승격 폭 결정 (false면 항상 patch)\n`;
381
+ out += ` semver_auto: ${semverAuto} # decide the version bump from commit titles (false means always patch)\n`;
382
+ // Projects 보드 동기화(#716) — 미지정이면 키를 쓰지 않는다.
383
+ if (projectsSync !== null) out += ` projects_sync: ${projectsSync} # GitHub Projects 상태 동기화 워크플로우 포함 여부\n`;
384
+ // 릴리스 시 완료 이슈 닫기(#771) — 미지정이면 키를 쓰지 않는다(기존 레포는 현행 유지).
385
+ if (closeOnRelease !== null) out += ` close_on_release: ${closeOnRelease} # close issues labelled done when a release is merged (false or missing means do not close)\n`;
386
+ // 상태 라벨 표기(#776) — 미지정이면 키를 쓰지 않는다(기존 레포 무변화).
387
+ // 레포 문구 언어(#769) — 미지정이면 키를 쓰지 않는다(기존 레포 무변화).
388
+ if (language) out += ` language: ${language} # issue/PR template language (en | ko)\n`;
389
+ if (labelStyle) out += ` label_style: ${labelStyle} # status label style (en: status: todo / ko: Korean names)\n`;
358
390
  // 앱 심사 배포 레포 여부(#553) — 미지정이면 키를 쓰지 않는다(기존 레포 무변화).
359
391
  if (appRelease !== null) {
360
- out += ` app_release: ${appRelease} # 앱스토어·플레이스토어 심사로 이어지는 배포인가\n`;
392
+ out += ` app_release: ${appRelease} # whether releases go through App Store / Play Store review\n`;
361
393
  }
362
394
  out += ` code_review:\n`;
363
395
  out += ` coderabbit: ${codeReviewCoderabbit}\n`;
@@ -373,7 +405,7 @@ export function buildVersionYml({ version, types = [], paths = new Map(), pathMa
373
405
  const deployTypes = [...deployValues.keys()].filter((t) => deployValues.get(t) && deployValues.get(t).size > 0);
374
406
  if (deployTypes.length) {
375
407
  out += `\n`;
376
- out += `deploy: # 마법사가 기억하는 배포 설정 (비민감 / 직접 수정 가능)\n`;
408
+ out += `deploy: # deploy settings remembered by the wizard (non-sensitive, safe to edit by hand)\n`;
377
409
  for (const t of deployTypes) {
378
410
  out += ` ${t}:\n`;
379
411
  for (const [k, v] of deployValues.get(t)) out += ` ${k}: "${v}"\n`;
@@ -0,0 +1,31 @@
1
+ // core 영역 메시지 (en). 키는 <영역>.<의미> 형식.
2
+ export default {
3
+ "args.mode": "--mode must be one of {values}: '{v}'",
4
+ "args.projectVersion": "--project-version must look like x.y.z (e.g. 1.0.0): '{v}'",
5
+ "args.unsupportedType": "Unsupported type: '{type}'\nSupported types: {valid}",
6
+ "args.typeEmpty": "--type is empty",
7
+ "args.deploy": "--deploy must be one of {values}: '{v}'",
8
+ "args.publish": "--publish must be a csv of {values}: '{v}'",
9
+ "args.deployBranch": "--deploy-branch must be a branch name made of letters, digits, . _ - /: '{v}'",
10
+ "args.intent": "--intent must be one of {values}: '{v}'",
11
+ "args.nexusDeprecated": "⚠️ --nexus is deprecated. Use --publish nexus --deploy none.",
12
+ "args.npmPublishDeprecated": "⚠️ --npm-publish is deprecated. Use --publish npm.",
13
+ "args.unknownOption": "Unknown option: {opt}",
14
+ "args.paths.unselected": "--paths contains a type that was not selected: '{type}' (selected types: {types})",
15
+ "args.paths.none": "none",
16
+ "args.paths.relative": "--paths {type}={path} : must be a path relative to the repository root (no absolute paths, no '..')",
17
+ "args.paths.missing": "--paths {type}={path} : folder does not exist",
18
+ "args.paths.outside": "--paths {type}={path} : points outside the repository",
19
+ "args.paths.badType": "--paths has an unsupported type: '{type}'",
20
+ "errors.git.message": "Cannot run git.",
21
+ "errors.git.hint": "Check that git is installed and on your PATH.",
22
+ "errors.clone.message": "Could not download the template.",
23
+ "errors.clone.hint": "Check your network, proxy settings and GitHub access, then run again.",
24
+ "errors.write.message": "Cannot write the file{where}.",
25
+ "errors.write.hint": "Check write permission (and read-only status) of the project folder and the .github folder.",
26
+ "errors.disk.message": "Not enough disk space.",
27
+ "errors.disk.hint": "Free up some space and run again.",
28
+ "errors.unexpected.message": "Unexpected error: {msg}",
29
+ "errors.unexpected.hint": "Run again with DEBUG=1 for details.",
30
+ "run.orphanNotice": "⚠️ Workflow of an unselected type ({type}) is left behind: {file}. You can clean it up in the interactive wizard (npx projectops).",
31
+ };
@@ -0,0 +1,31 @@
1
+ // core 영역 메시지 (ko). 키는 <영역>.<의미> 형식.
2
+ export default {
3
+ "args.mode": "--mode 값은 {values} 중 하나여야 합니다: '{v}'",
4
+ "args.projectVersion": "--project-version 값은 x.y.z (예: 1.0.0) 형식이어야 합니다: '{v}'",
5
+ "args.unsupportedType": "지원하지 않는 타입: '{type}'\n지원 타입: {valid}",
6
+ "args.typeEmpty": "--type 인자가 비어 있습니다",
7
+ "args.deploy": "--deploy 값은 {values} 중 하나여야 합니다: '{v}'",
8
+ "args.publish": "--publish 값은 {values} csv여야 합니다: '{v}'",
9
+ "args.deployBranch": "--deploy-branch 값은 글자·숫자·. _ - / 로 이루어진 브랜치명이어야 합니다: '{v}'",
10
+ "args.intent": "--intent 값은 {values} 중 하나여야 합니다: '{v}'",
11
+ "args.nexusDeprecated": "⚠️ --nexus는 deprecated입니다. --publish nexus --deploy none 을 사용하세요.",
12
+ "args.npmPublishDeprecated": "⚠️ --npm-publish는 deprecated입니다. --publish npm 을 사용하세요.",
13
+ "args.unknownOption": "알 수 없는 옵션: {opt}",
14
+ "args.paths.unselected": "--paths 에 선택하지 않은 타입이 있습니다: '{type}' (선택한 타입: {types})",
15
+ "args.paths.none": "없음",
16
+ "args.paths.relative": "--paths {type}={path} : 저장소 루트 기준 상대 경로여야 합니다 (절대경로, '..' 불가)",
17
+ "args.paths.missing": "--paths {type}={path} : 존재하지 않는 폴더입니다",
18
+ "args.paths.outside": "--paths {type}={path} : 저장소 밖을 가리킵니다",
19
+ "args.paths.badType": "--paths에 지원하지 않는 타입: '{type}'",
20
+ "errors.git.message": "git 을 실행할 수 없습니다.",
21
+ "errors.git.hint": "git 이 설치되어 있고 PATH 에 있는지 확인하세요.",
22
+ "errors.clone.message": "템플릿을 내려받지 못했습니다.",
23
+ "errors.clone.hint": "네트워크·프록시 설정과 GitHub 접근 가능 여부를 확인한 뒤 다시 실행하세요.",
24
+ "errors.write.message": "파일을 쓸 수 없습니다{where}.",
25
+ "errors.write.hint": "프로젝트 폴더와 .github 폴더의 쓰기 권한(읽기 전용 여부)을 확인하세요.",
26
+ "errors.disk.message": "디스크 공간이 부족합니다.",
27
+ "errors.disk.hint": "공간을 확보한 뒤 다시 실행하세요.",
28
+ "errors.unexpected.message": "예기치 못한 오류: {msg}",
29
+ "errors.unexpected.hint": "자세한 내용은 DEBUG=1 로 다시 실행하면 볼 수 있습니다.",
30
+ "run.orphanNotice": "⚠️ 선택되지 않은 타입({type})의 워크플로우가 남아있습니다: {file} — 대화형 마법사(npx projectops)에서 정리할 수 있습니다.",
31
+ };
@@ -0,0 +1,89 @@
1
+ // doctor 영역 메시지 (en). 키는 doctor.* 형식.
2
+ export default {
3
+ "doctor.perm.purpose": "Automatic commits, tags and downstream workflow runs",
4
+ "doctor.integ.name": "Integration status",
5
+ "doctor.integ.purpose": "Whether the template is installed in this folder",
6
+ "doctor.integ.noVersionYml": "version.yml not found",
7
+ "doctor.integ.notIntegrated": "The template is not integrated in this folder.",
8
+ "doctor.integ.howTo": "To integrate: npx projectops",
9
+ "doctor.integ.versions": "Template v{tpl} / Project v{proj}",
10
+ "doctor.wf.name": "Installed workflows",
11
+ "doctor.wf.purpose": "Automation running in this repository",
12
+ "doctor.count": "{n}",
13
+ "doctor.wf.none": "No workflows are installed.",
14
+ "doctor.wf.noneHint": "Try running again with the workflows or full mode.",
15
+ "doctor.unres.name": "Unresolved values",
16
+ "doctor.unres.purpose": "Places that will fail at deploy time",
17
+ "doctor.none": "None",
18
+ "doctor.cases": "{n} found",
19
+ "doctor.unres.intro": "Template values are still present at the locations below.",
20
+ "doctor.unres.more": " ... and {n} more",
21
+ "doctor.unres.outro": "If left as is, those workflows fail at the deploy step. Fill in the values yourself.",
22
+ "doctor.sec.name": "Required secrets",
23
+ "doctor.sec.purpose": "Values the installed workflows require",
24
+ "doctor.sec.line": " {name} <- {n} workflow(s)",
25
+ "doctor.sec.skipUnused": "You do not need to register values for workflows you do not use.",
26
+ "doctor.ai.name": "AI summary key",
27
+ "doctor.ai.purpose": "Whether to polish release notes with AI (optional)",
28
+ "doctor.ai.optional": "Optional",
29
+ "doctor.ai.l1": "Release notes are produced even without it. They are built by analyzing commits.",
30
+ "doctor.ai.l2": "For AI-polished text, register one of these as a repository Secret.",
31
+ "doctor.ai.gemini": " GEMINI_API_KEY free: https://aistudio.google.com/apikey",
32
+ "doctor.ai.groq": " GROQ_API_KEY free",
33
+ "doctor.ai.mistral": " MISTRAL_API_KEY free",
34
+ "doctor.ai.paid": " OPENAI_API_KEY / ANTHROPIC_API_KEY paid",
35
+ "doctor.ai.l3": "Whatever you register is used automatically. No other setup is needed.",
36
+ "doctor.pd.name": "Workflow permission declarations",
37
+ "doctor.pd.purpose": "Permission to run other workflows",
38
+ "doctor.pd.missing": "{n} missing",
39
+ "doctor.ok": "OK",
40
+ "doctor.pd.l1": "These run other workflows but permissions has no 'actions: write'.",
41
+ "doctor.pd.l2": "Even if the repository setting is Read and write, the API returns 403 without this declaration.",
42
+ "doctor.pd.l3": "Fix: add 'actions: write' to the permissions block of each file",
43
+ "doctor.bl.name": "Update baseline",
44
+ "doctor.bl.purpose": "Basis for telling your edits apart on the next update",
45
+ "doctor.bl.recorded": "{n} files recorded",
46
+ "doctor.bl.l1": "Without a baseline, the next update asks about every changed file.",
47
+ "doctor.bl.l2": "Running the integration once records it; from the next update on, your edits and template improvements are told apart.",
48
+ "doctor.rm.noAccess": "No permission to query",
49
+ "doctor.rm.failed": "Query failed",
50
+ "doctor.rm.permNoAdmin": "The token lacks repository admin permission, so this could not be checked.",
51
+ "doctor.rm.permCheck": "Check it yourself at Settings > Actions > General > Workflow permissions.",
52
+ "doctor.rm.roOk": "Read-only (no effect because workflows declare permissions themselves)",
53
+ "doctor.rm.roOkDetail": "Installed workflows all declare permissions, so they work fine even when the default is read-only.",
54
+ "doctor.rm.roWarn": "Read repository contents permission (read-only)",
55
+ "doctor.rm.l1": "Workflows without a permissions declaration cannot write to the repository or run other workflows.",
56
+ "doctor.rm.fix1": "Fix: add a permissions block to those files, or",
57
+ "doctor.rm.fix2": " choose 'Read and write permissions' at Settings > Actions > General > Workflow permissions",
58
+ "doctor.mc.name": "Merge commits allowed",
59
+ "doctor.mc.purpose": "Condition for automatic release PR merge",
60
+ "doctor.mc.on": "Allowed",
61
+ "doctor.mc.off": "Disabled",
62
+ "doctor.mc.l1": "Automatic release PR merge uses the merge commit method.",
63
+ "doctor.mc.l2": "If disabled, the automatic merge fails and the PR stays open.",
64
+ "doctor.mc.fix": "Fix: check 'Allow merge commits' at Settings > General > Pull Requests",
65
+ "doctor.sr.name": "Secret registration",
66
+ "doctor.sr.purpose": "Values needed for deployment",
67
+ "doctor.sr.noAccess": "The token lacks permission to read Secrets, so this could not be checked.",
68
+ "doctor.air.legacy": "legacy name (service auto-detected)",
69
+ "doctor.air.name": "AI summary key registration",
70
+ "doctor.air.none": "None (runs on commit analysis)",
71
+ "doctor.air.l1": "Release notes are produced normally even without it.",
72
+ "doctor.air.l2": "To use AI, register GEMINI_API_KEY (free): https://aistudio.google.com/apikey",
73
+ "doctor.sr.missing": "{n} not registered",
74
+ "doctor.sr.all": "All registered",
75
+ "doctor.sr.l1": "If you do not use those workflows, you do not need to register them.",
76
+ "doctor.sr.fix": "Fix: Settings > Secrets and variables > Actions > New repository secret",
77
+ "doctor.render.clean": "No problems found.",
78
+ "doctor.render.warn": "{n} item(s) to review. See the fixes above (skip them if you do not use that feature).",
79
+ "doctor.title": "projectops doctor: integration status and repository settings check",
80
+ "doctor.gh.name": "GitHub remote",
81
+ "doctor.gh.purpose": "Repository being checked",
82
+ "doctor.gh.noOrigin": "No origin{folder}",
83
+ "doctor.gh.folder": " (folder name: {name})",
84
+ "doctor.gh.noRemote": "No remote repository was found, so repository settings are not checked.",
85
+ "doctor.skip.name": "Repository settings check",
86
+ "doctor.skip.purpose": "Permissions, merge method, Secrets",
87
+ "doctor.skip.value": "Skipped (no token)",
88
+ "doctor.skip.l1": "Set the GITHUB_TOKEN environment variable to check repository settings too.",
89
+ };
@@ -0,0 +1,89 @@
1
+ // doctor 영역 메시지 (ko). 키는 doctor.* 형식.
2
+ export default {
3
+ "doctor.perm.purpose": "자동 커밋·태그·후속 워크플로우 실행",
4
+ "doctor.integ.name": "통합 상태",
5
+ "doctor.integ.purpose": "이 폴더의 템플릿 설치 여부",
6
+ "doctor.integ.noVersionYml": "version.yml 없음",
7
+ "doctor.integ.notIntegrated": "이 폴더에는 템플릿이 통합되어 있지 않습니다.",
8
+ "doctor.integ.howTo": "통합하려면: npx projectops",
9
+ "doctor.integ.versions": "템플릿 v{tpl} / 프로젝트 v{proj}",
10
+ "doctor.wf.name": "설치된 워크플로우",
11
+ "doctor.wf.purpose": "이 저장소에서 도는 자동화",
12
+ "doctor.count": "{n}개",
13
+ "doctor.wf.none": "워크플로우가 하나도 없습니다.",
14
+ "doctor.wf.noneHint": "통합 모드를 workflows 또는 full로 다시 실행해 보세요.",
15
+ "doctor.unres.name": "치환되지 않은 값",
16
+ "doctor.unres.purpose": "배포 시점에 실패할 자리",
17
+ "doctor.none": "없음",
18
+ "doctor.cases": "{n}건",
19
+ "doctor.unres.intro": "아래 위치에 템플릿 값이 그대로 남아 있습니다.",
20
+ "doctor.unres.more": " … 외 {n}건",
21
+ "doctor.unres.outro": "그대로 두면 해당 워크플로우가 배포 단계에서 실패합니다. 직접 값을 채워주세요.",
22
+ "doctor.sec.name": "필요한 Secret",
23
+ "doctor.sec.purpose": "설치된 워크플로우가 요구하는 값",
24
+ "doctor.sec.line": " {name} ← {n}개 워크플로우",
25
+ "doctor.sec.skipUnused": "쓰지 않는 워크플로우의 값은 등록하지 않아도 됩니다.",
26
+ "doctor.ai.name": "AI 요약 키",
27
+ "doctor.ai.purpose": "릴리스 노트를 AI로 다듬을지 (선택)",
28
+ "doctor.ai.optional": "선택 사항",
29
+ "doctor.ai.l1": "등록하지 않아도 릴리스 노트는 나옵니다 — 커밋 내용을 분석해 만듭니다.",
30
+ "doctor.ai.l2": "AI가 다듬은 문장을 원하면 아래 중 하나를 저장소 Secret에 등록하세요.",
31
+ "doctor.ai.gemini": " GEMINI_API_KEY 무료 · https://aistudio.google.com/apikey",
32
+ "doctor.ai.groq": " GROQ_API_KEY 무료",
33
+ "doctor.ai.mistral": " MISTRAL_API_KEY 무료",
34
+ "doctor.ai.paid": " OPENAI_API_KEY / ANTHROPIC_API_KEY 유료",
35
+ "doctor.ai.l3": "등록한 것이 자동으로 쓰입니다. 별도 설정은 필요 없습니다.",
36
+ "doctor.pd.name": "워크플로우 권한 선언",
37
+ "doctor.pd.purpose": "다른 워크플로우를 실행할 권한",
38
+ "doctor.pd.missing": "{n}건 누락",
39
+ "doctor.ok": "정상",
40
+ "doctor.pd.l1": "다른 워크플로우를 실행하는데 permissions에 'actions: write'가 없습니다.",
41
+ "doctor.pd.l2": "저장소 설정이 Read and write여도 이 선언이 없으면 API가 403을 반환합니다.",
42
+ "doctor.pd.l3": "조치: 해당 파일의 permissions 블록에 'actions: write' 추가",
43
+ "doctor.bl.name": "업데이트 기준점",
44
+ "doctor.bl.purpose": "다음 업데이트가 내 수정을 구분할 근거",
45
+ "doctor.bl.recorded": "{n}개 파일 기록됨",
46
+ "doctor.bl.l1": "기준점이 없어 다음 업데이트는 변경된 파일을 모두 물어봅니다.",
47
+ "doctor.bl.l2": "통합을 한 번 실행하면 기록되고, 그 다음 업데이트부터 내 수정과 템플릿 개선을 구분합니다.",
48
+ "doctor.rm.noAccess": "조회 권한 없음",
49
+ "doctor.rm.failed": "조회 실패",
50
+ "doctor.rm.permNoAdmin": "토큰에 저장소 관리 권한이 없어 확인하지 못했습니다.",
51
+ "doctor.rm.permCheck": "Settings > Actions > General > Workflow permissions 에서 직접 확인하세요.",
52
+ "doctor.rm.roOk": "읽기 전용 (워크플로우가 권한을 직접 선언해 영향 없음)",
53
+ "doctor.rm.roOkDetail": "설치된 워크플로우가 permissions 를 모두 선언하고 있어 기본값이 읽기 전용이어도 정상 동작합니다.",
54
+ "doctor.rm.roWarn": "Read repository contents permission (읽기 전용)",
55
+ "doctor.rm.l1": "permissions 선언이 없는 워크플로우는 저장소에 쓰거나 다른 워크플로우를 실행할 수 없습니다.",
56
+ "doctor.rm.fix1": "조치: 해당 파일에 permissions 블록을 추가하거나",
57
+ "doctor.rm.fix2": " Settings > Actions > General > Workflow permissions → 'Read and write permissions' 선택",
58
+ "doctor.mc.name": "merge commit 허용",
59
+ "doctor.mc.purpose": "릴리스 PR 자동 머지 조건",
60
+ "doctor.mc.on": "허용됨",
61
+ "doctor.mc.off": "꺼져 있음",
62
+ "doctor.mc.l1": "릴리스 PR 자동 머지는 merge commit 방식을 사용합니다.",
63
+ "doctor.mc.l2": "꺼져 있으면 자동 머지가 실패하고 PR이 열린 채 남습니다.",
64
+ "doctor.mc.fix": "조치: Settings > General > Pull Requests → 'Allow merge commits' 체크",
65
+ "doctor.sr.name": "Secret 등록 여부",
66
+ "doctor.sr.purpose": "배포에 필요한 값",
67
+ "doctor.sr.noAccess": "토큰에 Secret 조회 권한이 없어 확인하지 못했습니다.",
68
+ "doctor.air.legacy": "구 이름(서비스 자동 추정)",
69
+ "doctor.air.name": "AI 요약 키 등록",
70
+ "doctor.air.none": "없음 — 커밋 분석으로 동작",
71
+ "doctor.air.l1": "등록하지 않아도 릴리스 노트는 정상적으로 나옵니다.",
72
+ "doctor.air.l2": "AI를 쓰려면 GEMINI_API_KEY(무료)를 등록하세요 — https://aistudio.google.com/apikey",
73
+ "doctor.sr.missing": "{n}개 미등록",
74
+ "doctor.sr.all": "전부 등록됨",
75
+ "doctor.sr.l1": "해당 워크플로우를 쓰지 않는다면 등록하지 않아도 됩니다.",
76
+ "doctor.sr.fix": "조치: Settings > Secrets and variables > Actions > New repository secret",
77
+ "doctor.render.clean": "확인된 문제 없음.",
78
+ "doctor.render.warn": "살펴볼 항목 {n}건. 위 조치를 참고하세요 (쓰지 않는 기능이라면 넘어가도 됩니다).",
79
+ "doctor.title": "projectops doctor — 통합 상태 및 저장소 설정 진단",
80
+ "doctor.gh.name": "GitHub 원격",
81
+ "doctor.gh.purpose": "점검 대상 저장소",
82
+ "doctor.gh.noOrigin": "origin 없음{folder}",
83
+ "doctor.gh.folder": " (폴더명: {name})",
84
+ "doctor.gh.noRemote": "원격 저장소를 찾지 못해 저장소 설정은 점검하지 않습니다.",
85
+ "doctor.skip.name": "저장소 설정 점검",
86
+ "doctor.skip.purpose": "권한·머지 방식·Secret",
87
+ "doctor.skip.value": "건너뜀 (토큰 없음)",
88
+ "doctor.skip.l1": "GITHUB_TOKEN 환경변수를 주면 저장소 설정까지 점검합니다.",
89
+ };
package/src/i18n/en.js ADDED
@@ -0,0 +1,141 @@
1
+ // English messages (source of truth). Keys are grouped by area: <area>.<name>.
2
+ import summary from "./summary.en.js";
3
+ import doctor from "./doctor.en.js";
4
+ import options from "./options.en.js";
5
+ import migrate from "./migrate.en.js";
6
+ import core from "./core.en.js";
7
+ import ide from "./ide.en.js";
8
+
9
+ export default {
10
+ ...summary,
11
+ ...doctor,
12
+ ...options,
13
+ ...migrate,
14
+ ...core,
15
+ ...ide,
16
+ // prompt engine hints
17
+ "engine.hint.select": "↑/↓ move, Enter confirm, ESC cancel",
18
+ "engine.hint.multiselect": "↑/↓ move, Space toggle, a all, Enter confirm, ESC cancel",
19
+ "engine.hint.confirm": "←/→ or y/n, Enter confirm, ESC cancel",
20
+ "engine.yes": "Yes",
21
+ "engine.no": "No",
22
+ "engine.none": "(none)",
23
+ "engine.disabled": "This item cannot be selected.",
24
+ "engine.required": "Select at least one.",
25
+ "engine.cancelled": "Cancelled.",
26
+
27
+ // main menu
28
+ "mode.prompt": "What would you like to install?",
29
+ "mode.update": "Update ({range})",
30
+ "mode.full": "Full install (versioning + workflows + templates)",
31
+ "mode.version": "Versioning only (automation system)",
32
+ "mode.workflows": "Workflows only (GitHub Actions build and deploy)",
33
+ "mode.issues": "Issue/PR templates only",
34
+ "mode.skills": "AI skills only (Claude, Cursor, Gemini, Codex, PI)",
35
+
36
+ // confirm and edit menus
37
+ "confirm.prompt": "Continue with these settings?",
38
+ "confirm.continue": "Yes, continue",
39
+ "confirm.edit": "Edit",
40
+ "confirm.cancel": "No, cancel",
41
+ "edit.prompt": "Which setting do you want to change?",
42
+ "edit.type": "Project type",
43
+ "edit.version": "Version",
44
+ "edit.branch": "Default branch",
45
+ "language.propose": "Switch the issue and PR templates in this repo to English? They are Korean now. Answer no to keep them as they are.",
46
+ "labelStyle.propose": "Rename Korean status labels (작업전, 작업중, ...) to English (status: todo, ...)? Issues keep their labels; Projects sync accepts both.",
47
+ "edit.intent": "Project kind (deployment style)",
48
+ "edit.deploy": "Deployment (server artifact)",
49
+ "edit.publish": "Library publish targets",
50
+ "edit.codeReview": "CodeRabbit code review",
51
+ "edit.changelog": "Release notes (changelog) generator",
52
+ "edit.releaseBranch": "Release source (development) branch",
53
+ "edit.secret": "Include secret backup",
54
+ "edit.done": "All correct, continue",
55
+ "types.prompt": "Select project types (Space to toggle, Enter to confirm)",
56
+
57
+ // help and errors
58
+ "cli.nonTty": "Interactive input is not available. Pass --mode <full|version|workflows|issues> and --force.",
59
+ "cli.needForce": "The --force option is required in a non-interactive environment.",
60
+ "cli.langInvalid": "--lang must be one of: {values} (got '{value}')",
61
+ "cli.langSource.flag": "--lang",
62
+ "cli.langSource.env": "PROJECTOPS_LANG",
63
+ "cli.langSource.ci": "fixed for CI/--force",
64
+ "cli.langSource.system": "system",
65
+ "cli.langSource.default": "default",
66
+
67
+ // banner
68
+ "banner.interactive": "Interactive installer",
69
+ "banner.compactMode": "({mode} mode, --force)",
70
+
71
+ // detection log and summary card
72
+ "detect.title": "Inspecting the project...",
73
+ "detect.found": "{marker} found, {type} detected",
74
+ "detect.foundNoMarker": "{type} detected",
75
+ "detect.none": "no marker files, using basic (you can change it)",
76
+ "detect.versionBranch": "version: v{version}, branch: {branch}",
77
+ "card.title": "Summary",
78
+ "card.type": "Type",
79
+ "card.typeMulti": "Types (multi)",
80
+ "card.version": "Version",
81
+ "card.branch": "Branch",
82
+ "card.mode": "Install mode",
83
+ "card.deploy": "Deploy",
84
+ "card.publish": "Publish",
85
+ "card.secret": "Secret backup",
86
+ "card.paths": "Paths",
87
+ "card.none": "none",
88
+ "card.included": "included",
89
+ "card.excluded": "excluded",
90
+
91
+ // ide status and install kind
92
+ "ide.title": "AI agent skills",
93
+ "ide.installed": "installed",
94
+ "ide.notInstalled": "not installed",
95
+ "ide.cliMissing": "CLI not found",
96
+ "ide.detectFailed": "detection failed",
97
+ "kind.update": "Update",
98
+ "kind.updateFrom": "template v{from} to v{to}",
99
+ "kind.updateWhy": "version.yml has a previous install record. 'Update' at the top of the menu re-applies your saved settings",
100
+ "kind.new": "New install",
101
+ "kind.newTemplate": "first install in this project (template v{to})",
102
+ "kind.newWhy": "version.yml has no previous install record, so this is treated as a new install",
103
+
104
+ // interactive flow
105
+ "flow.cancelInstall": "Installation cancelled.",
106
+ "flow.cancelBreaking": "Cancelled safely, nothing was changed.",
107
+ "flow.doneSkills": "AI skills installed.",
108
+ "flow.doneIssues": "Issue and PR templates installed.",
109
+ "flow.title.update": "Update, using saved settings",
110
+ "flow.title.summary": "Summary",
111
+ "flow.askVersion": "New version (e.g. 1.0.0)",
112
+ "flow.askBranch": "Default branch",
113
+ "flow.badVersion": "Invalid version format (use x.y.z). Keeping the current value.",
114
+ "flow.badVersionTitle": "Version",
115
+ "flow.askSkills": "Also install or update AI agent skills (Claude, Cursor, Gemini, Codex, PI)?",
116
+ "flow.done": "Done. Installed in {mode} mode.",
117
+ "flow.updateScope": "Update ({scope} scope)",
118
+ "flow.conflictsTitle": "{count} workflows changed in the new template",
119
+ "flow.conflictsAsk": "Back up these {count} as .bak and replace them with the new version? (your settings are kept)",
120
+ "flow.conflictType": "Some files differ from the existing workflows ({type}). What should happen?",
121
+ "flow.opt.skip": "Skip, keep the existing file (default)",
122
+ "flow.opt.backup": "Back up as .bak and replace with the new version",
123
+ "flow.opt.template": "Keep the existing file and add the new version as .template.yaml for reference",
124
+ "flow.orphanLine": "{file} ({type} type, not selected now)",
125
+ "flow.orphanTitle": "{count} workflows of unselected types found",
126
+ "flow.orphanAsk": "Clean up these {count}? (neutralized as .bak, restorable)",
127
+ "flow.orphanDone": "Orphan workflows cleaned: {ok}{failed}",
128
+ "flow.orphanFailed": " ({count} failed)",
129
+ "flow.orphanDoneTitle": "Cleanup done",
130
+ "sum.mode": "Install mode",
131
+ "sum.types": "Project types",
132
+ "sum.multi": " (multi)",
133
+ "sum.deploy": "Deploy",
134
+ "sum.publish": "Publish",
135
+ "sum.secret": "Secret backup",
136
+ "sum.changelog": "Changelog",
137
+ "sum.coderabbit": "CodeRabbit review",
138
+ "sum.on": "enabled",
139
+ "sum.off": "disabled",
140
+ "mode.update.short": "Update",
141
+ };