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.
- package/README.md +144 -145
- package/package.json +2 -2
- package/src/cli/args.js +65 -29
- package/src/cli/errors.js +9 -7
- package/src/cli/help.js +51 -3
- package/src/commands/doctor.js +80 -78
- package/src/commands/full.js +11 -2
- package/src/commands/interactive.js +71 -49
- package/src/commands/issues.js +4 -0
- package/src/commands/skills.js +8 -7
- package/src/commands/version.js +4 -2
- package/src/commands/workflows.js +3 -1
- package/src/context.js +4 -0
- package/src/core/breaking-check.js +6 -5
- package/src/core/copy/simple.js +4 -0
- package/src/core/copy/workflows.js +10 -5
- package/src/core/exclusions.js +8 -0
- package/src/core/ide/adapters/claude.js +18 -17
- package/src/core/ide/adapters/codex.js +12 -11
- package/src/core/ide/adapters/cursor.js +11 -10
- package/src/core/ide/adapters/gemini.js +11 -10
- package/src/core/ide/adapters/pi-common.js +2 -1
- package/src/core/ide/adapters/pi-harness.js +13 -16
- package/src/core/ide/adapters/pi.js +12 -11
- package/src/core/label-style.js +78 -0
- package/src/core/migration-guide.js +38 -38
- package/src/core/migrations/index.js +19 -15
- package/src/core/migrations/registry.js +70 -55
- package/src/core/options-ask.js +65 -64
- package/src/core/orphan-workflows.js +2 -1
- package/src/core/paths-resolve.js +31 -30
- package/src/core/repo-language.js +47 -0
- package/src/core/run-trace.js +10 -0
- package/src/core/version-yml.js +68 -36
- package/src/i18n/core.en.js +31 -0
- package/src/i18n/core.ko.js +31 -0
- package/src/i18n/doctor.en.js +89 -0
- package/src/i18n/doctor.ko.js +89 -0
- package/src/i18n/en.js +141 -0
- package/src/i18n/ide.en.js +102 -0
- package/src/i18n/ide.ko.js +102 -0
- package/src/i18n/index.js +73 -0
- package/src/i18n/ko.js +134 -0
- package/src/i18n/migrate.en.js +66 -0
- package/src/i18n/migrate.ko.js +66 -0
- package/src/i18n/options.en.js +104 -0
- package/src/i18n/options.ko.js +104 -0
- package/src/i18n/summary.en.js +70 -0
- package/src/i18n/summary.ko.js +70 -0
- package/src/index.js +46 -28
- package/src/ui/banner.js +8 -6
- package/src/ui/env-plan.js +19 -18
- package/src/ui/prompts.js +25 -24
- package/src/ui/readline-engine.js +18 -10
- package/src/ui/skills-prompts.js +8 -7
- package/src/ui/status-cards.js +38 -38
- package/src/ui/summary.js +103 -111
package/src/core/version-yml.js
CHANGED
|
@@ -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
|
|
15
|
-
# 3. project_types:
|
|
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:
|
|
20
|
-
# -
|
|
21
|
-
# semver_auto: true ->
|
|
22
|
-
# "
|
|
23
|
-
# "
|
|
24
|
-
#
|
|
25
|
-
#
|
|
26
|
-
# -
|
|
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
|
|
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
|
|
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}"] #
|
|
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} #
|
|
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: #
|
|
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}" #
|
|
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}" #
|
|
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} #
|
|
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} #
|
|
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: #
|
|
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
|
+
};
|