pan-stack-cli 0.2.1 → 0.2.2

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 (59) hide show
  1. package/README.md +37 -731
  2. package/bin/pan.js +4955 -269
  3. package/package.json +17 -5
  4. package/lib/ai-skills.js +0 -829
  5. package/lib/create.js +0 -105
  6. package/lib/discover.js +0 -294
  7. package/lib/git/git-checkout.js +0 -395
  8. package/lib/git/git-clone.js +0 -206
  9. package/lib/git/git-fetch-all.js +0 -129
  10. package/lib/git/git-grv.js +0 -125
  11. package/lib/git/git-gst.js +0 -165
  12. package/lib/git/git-mr.js +0 -546
  13. package/lib/git/git-pull.js +0 -137
  14. package/lib/git/git-push.js +0 -185
  15. package/lib/git/git-sync-main.js +0 -334
  16. package/lib/git/helpers/bulk-report.js +0 -202
  17. package/lib/git/helpers/cli.js +0 -188
  18. package/lib/git/helpers/colors.js +0 -19
  19. package/lib/git/helpers/git.js +0 -136
  20. package/lib/git/helpers/manifest.js +0 -223
  21. package/lib/git/helpers/repo-select.js +0 -416
  22. package/lib/git/helpers/repo-summary.js +0 -161
  23. package/lib/i18n.js +0 -61
  24. package/lib/inquirer-theme.js +0 -20
  25. package/lib/language.js +0 -121
  26. package/lib/languages.js +0 -14
  27. package/lib/manifest.js +0 -467
  28. package/lib/menu-prompt.js +0 -201
  29. package/lib/menu.js +0 -134
  30. package/lib/messages.js +0 -647
  31. package/lib/platform.js +0 -140
  32. package/lib/run-command.js +0 -334
  33. package/lib/select.js +0 -0
  34. package/lib/serve.js +0 -75
  35. package/lib/skill-registry-client.js +0 -173
  36. package/lib/stats/aggregate.js +0 -51
  37. package/lib/stats/identity.js +0 -20
  38. package/lib/stats/index.js +0 -189
  39. package/lib/stats/parse.js +0 -46
  40. package/lib/stats/range.js +0 -38
  41. package/lib/stats/report.js +0 -264
  42. package/lib/stats/review.js +0 -157
  43. package/lib/stats/scan.js +0 -92
  44. package/lib/stats/serve.js +0 -25
  45. package/lib/ui/api.js +0 -202
  46. package/lib/ui/clone.js +0 -115
  47. package/lib/ui/config.js +0 -182
  48. package/lib/ui/diff.js +0 -128
  49. package/lib/ui/export-gate.js +0 -79
  50. package/lib/ui/gen-react-mobile-code.js +0 -6
  51. package/lib/ui/gen-react-web-code.js +0 -75
  52. package/lib/ui/index.js +0 -89
  53. package/lib/ui/init.js +0 -252
  54. package/lib/ui/login.js +0 -128
  55. package/lib/ui/logout.js +0 -22
  56. package/lib/ui/palettes.js +0 -103
  57. package/lib/ui/published-html.js +0 -24
  58. package/lib/ui/sync.js +0 -137
  59. package/lib/ui/workspace.js +0 -213
package/lib/messages.js DELETED
@@ -1,647 +0,0 @@
1
- // Catalog message theo KEY (SCREAMING_SNAKE_CASE). Quy ước đặt tên:
2
- // TÊN_MÔ_TẢ__BIẾN1_BIẾN2 (2 dấu gạch dưới `__` ngăn phần mô tả và danh sách biến nội suy {biến})
3
- // Thêm ngôn ngữ mới: thêm 1 object con (vd `ja: {...}`) — không cần sửa call site nào.
4
- module.exports = {
5
- en: {
6
- DIRECTORY_NOT_FOUND__DIR:
7
- "Directory not found: {dir} (run 'pan clone' first?)",
8
- COMMAND_MISSING_EXEC_OR_SHELL: "Command is missing 'exec' or 'shell'.",
9
- COMMAND_NOT_FOUND_IN_SOURCE__COMMAND_PATH:
10
- "Command '{command}' not found in {path}",
11
- NOTHING_SELECTED_EXITING: "Nothing selected — exiting.",
12
- COMMAND_MISSING_EXEC_OR_SHELL_IN_SOURCE__COMMAND_PATH:
13
- "Command '{command}' is missing 'exec' or 'shell' in {path}",
14
- COMMAND_MULTIPLE_PLACES_SELECT_PROJECT__COMMAND:
15
- "Command '{command}' is defined in multiple places — select a project:",
16
- COMMAND_NOT_FOUND_ANYWHERE__COMMAND:
17
- "Command '{command}' not found in any .pan.yaml file.",
18
- PROJECT_NOT_FOUND__PROJECT_NAMES:
19
- "Project '{project}' not found. Available: {names}",
20
- COMMAND_MULTIPLE_PROJECTS__COMMAND_LINES:
21
- "Command '{command}' is defined in multiple projects. Use --project <name>.\n{lines}",
22
- SCRIPT_NOT_FOUND__PATH: "Script not found: {path}",
23
- REPO_MISSING_NAME: "Repository entry is missing 'name'.",
24
- REPO_MISSING_URL__NAME: "Repository '{name}' is missing a real url.",
25
- REPO_MISSING_PATH__NAME: "Repository '{name}' is missing 'path'.",
26
- MANIFEST_NOT_FOUND__PATH: "Manifest not found: {path}",
27
- MANIFEST_NOT_FOUND_FALLBACK_SCAN__DIR:
28
- "ℹ️ No .project.yaml found — treating {dir} as project root, scanning for child git repos.",
29
- MANIFEST_NOT_FOUND_NO_GIT_FALLBACK__DIR:
30
- "No .project.yaml found, and no git repo found under {dir} either (scanned {dir} + 2 levels deep).",
31
- CONFIG_NOT_FOUND__PATH: "Config not found: {path}",
32
- VALID_TARGETS__COMMAND_VALID: "Valid targets for '{command}': {valid}",
33
- NO_PAN_YAML_FOUND: "No .pan.yaml found (workspace or child repos).",
34
- LOADED_COMMANDS: "Loaded commands:",
35
- UNKNOWN_BUILTIN_COMMAND__COMMAND: "Unknown built-in command: {command}",
36
- NO_PAN_YAML_WITH_COMMANDS: "No .pan.yaml with commands found.",
37
- NO_PAN_YAML_BUT_GIT_STILL_WORKS:
38
- "Built-in git commands (pull/push/fetch/checkout/...) still work — see usage below.",
39
- MENU_SELECT_PROJECT: "pan · select a project:",
40
- COMMANDS_LABEL: "commands",
41
- HELP_LABEL: "help",
42
- VERSION_LABEL: "version",
43
- EXIT_LABEL: "exit",
44
- MENU_SELECT_COMMAND: "select a command:",
45
- BACK_LABEL: "back",
46
- NO_LABEL: "No",
47
- YES_LABEL: "Yes",
48
- SELECT_TARGET__CMD: "Select target for '{cmd}':",
49
- DEFAULT_LABEL: "(default)",
50
- EXITED: "Exited.",
51
- LANGUAGE_CURRENT__LANG_PATH: "Current language: {lang} ({path})",
52
- LANGUAGE_CURRENT_NO_PROJECT__LANG:
53
- "Current language: {lang} (no .project.yaml found — using default/env)",
54
- LANGUAGE_AVAILABLE__LANGS: "Available: {langs}",
55
- LANGUAGE_USAGE: "Usage: pan language [<code>] (e.g. pan language vi)",
56
- LANGUAGE_UNKNOWN__LANG_AVAILABLE:
57
- "Unknown language '{lang}'. Available: {available}",
58
- LANGUAGE_NO_PROJECT_YAML:
59
- "No .project.yaml found (walked up from cwd). Run 'pan create' first, or cd into a workspace.",
60
- LANGUAGE_SELECT_PROMPT: "Select language:",
61
- LANGUAGE_SET__LANG_PATH: "✓ Language set to '{lang}' in {path}",
62
- AI_NO_WORKSPACE:
63
- "No .project.yaml found (walked up from cwd). Run 'pan create' first, or cd into a PAN Stack workspace.",
64
- AI_NO_SKILLS: "No agent skills found under .claude/.cursor/.codex/skills.",
65
- AI_LIST_FOOTER__COUNT: "{count} skill(s).",
66
- AI_SELECT_ACTION: "pan ai · choose action:",
67
- AI_SELECT_ACTION__ACTIVE_DISABLED_TOTAL:
68
- "pan ai · {active} active · {disabled} disabled · {total} total — choose action:",
69
- AI_CHOICE_DISABLE__COUNT: "Disable skills ({count})",
70
- AI_CHOICE_ENABLE__COUNT: "Enable skills ({count})",
71
- AI_CHOICE_LIST__COUNT: "List skills ({count})",
72
- AI_NONE: "(none)",
73
- AI_SELECT_SKILLS: "Select skill(s):",
74
- AI_EMPTY_SELECTION: "Nothing selected — exiting.",
75
- AI_EMPTY_FOR_ACTION__ACTION: "No skills available to {action}.",
76
- AI_UNKNOWN_SKILL__NAME: "Unknown skill: {name}",
77
- AI_NEED_TTY_OR_FLAGS:
78
- "Interactive mode needs a TTY. Use --list, --disable <name>, or --enable <name>.",
79
- AI_CANCELLED: "Cancelled.",
80
- AI_DISABLE_ENABLE_MUTUAL: "Use either --disable or --enable, not both.",
81
- AI_UNKNOWN_FLAG__FLAG: "Unknown flag: {flag}",
82
- AI_UNEXPECTED_ARG__ARG:
83
- "Unexpected argument '{arg}'. Use --disable/--enable <name> or --list.",
84
-
85
- AI_CHOICE_INSTALL: "Install skills / agents",
86
- AI_CHOICE_UPDATE: "Update skills / agents",
87
- AI_CHECKING_UPDATES: "Checking for updates...",
88
- AI_NO_UPDATES: "✓ Everything is up to date.",
89
- AI_NOTHING_TO_INSTALL: "✓ Already installed, nothing new.",
90
- AI_UPDATE_SELECT: "Select package(s) to update:",
91
- AI_INSTALL_SELECT: "Select package(s) to install:",
92
- AI_UPDATE_ALL__COUNT: "Update all ({count})",
93
- AI_UPDATE_AVAILABLE__COUNT:
94
- "⬆ {count} package(s) have updates — select to update",
95
- AI_UPDATE_DONE__COUNT: "✓ Updated {count} package(s).",
96
- AI_INSTALL_DONE__COUNT: "✓ Installed {count} package(s).",
97
- AI_SELECT_AGENT_DIRS: "Select target agent folder(s):",
98
- AI_INSTALL_USING_AGENTS__AGENTS: "→ Installing into: {agents}",
99
- AI_NO_PROJECT_ASK_CREATE:
100
- "No .project.yaml found — you are not inside a pan-stack project. Create a new project here?",
101
- AI_PROJECT_CREATED__PROJECT_MANAGEDBY:
102
- "✓ Created .project.yaml (project: {project}, managed_by: {managedBy})",
103
-
104
- // ── Bulk git summary (pull/push/fetch/gst) ──
105
- BULK_COL_REPO: "repo",
106
- BULK_COL_BRANCH: "branch",
107
- BULK_COL_RESULT: "result",
108
- BULK_COL_STATE: "state",
109
- BULK_COL_BREAKDOWN: "breakdown",
110
- BULK_COL_CHANGES: "changes",
111
- BULK_COL_CONFLICT: "conflict",
112
- BULK_COL_COMMITS: "commits",
113
- BULK_COL_LINK: "MR / PR",
114
- BULK_COL_SYNC: "behind/ahead",
115
- BULK_COL_NEW_REFS: "new refs",
116
- BULK_COL_NOTE: "note",
117
-
118
- BULK_STATUS_UP_TO_DATE: "up-to-date",
119
- BULK_STATUS_PUSHED: "pushed",
120
- BULK_STATUS_PULLED: "pulled",
121
- BULK_STATUS_OK: "ok",
122
- BULK_STATUS_UPDATED: "updated",
123
- BULK_STATUS_REJECTED: "rejected (pull first)",
124
- BULK_STATUS_FAILED: "failed",
125
- BULK_STATUS_FETCHED: "fetched",
126
- BULK_STATUS_CONFLICT: "conflict",
127
- BULK_STATUS_DRY_RUN: "dry-run",
128
- BULK_STATUS_SKIPPED: "skipped",
129
- BULK_STATUS_IN_SYNC: "in-sync",
130
- BULK_STATUS_NO_UPSTREAM: "no upstream",
131
- BULK_STATUS_CLEAN: "clean",
132
- BULK_STATUS_MERGING: "MERGING",
133
- BULK_STATUS_REBASING: "REBASING",
134
- BULK_STATUS_ERROR: "error",
135
- BULK_MODE_FAST_FORWARD: "fast-forward",
136
- BULK_MODE_MERGE: "merge",
137
- BULK_MODE_REBASE: "rebase",
138
-
139
- BULK_BREAKDOWN_STAGED__N: "{n} staged",
140
- BULK_BREAKDOWN_UNSTAGED__N: "{n} unstaged",
141
- BULK_BREAKDOWN_UNTRACKED__N: "{n} untracked",
142
- BULK_FILES_ONE: "file",
143
- BULK_FILES_MANY: "files",
144
- BULK_REFS_NEW__N: "{n} new",
145
- BULK_REFS_UPD__N: "{n} upd",
146
- BULK_REFS_TAGS__N: "{n} tags",
147
- BULK_REFS_PRUNED__N: "{n} pruned",
148
-
149
- // Pull
150
- PULL_TITLE: "pull summary",
151
- PULL_ALL_UP_TO_DATE__N: "✅ All {n} repos already up-to-date",
152
- PULL_FOOTER_COUNTS__TOTAL_CHANGED_UPTODATE_CONFLICT_FAILED:
153
- " Total {total} repos · {changed} changed · {upToDate} up-to-date · {conflict} conflict · {failed} failed",
154
- PULL_CONFLICT_HEADER: "⚠️ CONFLICT — resolve manually:",
155
-
156
- // Push
157
- PUSH_TITLE: "push summary",
158
- PUSH_ALL_UP_TO_DATE__N:
159
- "✅ All {n} repos already up-to-date, nothing to push",
160
- PUSH_FOOTER_COUNTS__TOTAL_PUSHED_UPTODATE_REJECTED_FAILED:
161
- " Total {total} repos · {pushed} pushed · {upToDate} up-to-date · {rejected} rejected · {failed} failed",
162
- PUSH_FOOTER_LINES__COMMITS_ADD_DEL:
163
- " Lines pushed: {commits} commit(s) · +{add} / −{del}",
164
- PUSH_LINKS_HEADER: "🔗 MR/PR quick links:",
165
- PUSH_REJECTED_HEADER: "⚠️ Rejected — run 'pan pull' first then retry:",
166
-
167
- // Fetch
168
- FETCH_TITLE: "fetch summary",
169
- FETCH_ALL_IN_SYNC__N: "✅ All {n} repos are in sync with remote",
170
- FETCH_FOOTER_COUNTS__TOTAL_CHANGED_INSYNC_BEHIND_FAILED:
171
- " Total {total} repos · {changed} changed · {inSync} in-sync · {behind} behind · {failed} failed",
172
- FETCH_BEHIND_HEADER: "ℹ️ New commits on remote — consider 'pan pull':",
173
-
174
- // Clone
175
- CLONE_TITLE: "clone summary",
176
- CLONE_STATUS_CLONED: "cloned",
177
- CLONE_STATUS_EXISTS: "already exists",
178
- CLONE_STATUS_NO_ACCESS: "no access",
179
- CLONE_STATUS_NOT_FOUND: "not found",
180
- CLONE_ALL_EXIST__N: "✅ All {n} repos already cloned",
181
- CLONE_FOOTER_COUNTS__TOTAL_CLONED_EXISTS_NOACCESS_NOTFOUND_FAILED:
182
- " Total {total} repos · {cloned} cloned · {exists} already exist · {noAccess} no access · {notFound} not found · {failed} failed",
183
- CLONE_NO_ACCESS_HEADER:
184
- "⚠️ No access — check repo permissions / SSH key / token:",
185
-
186
- // Grv (git remote -v)
187
- GRV_TITLE: "grv summary",
188
- GRV_COL_REMOTE: "remote",
189
- GRV_COL_FETCH: "fetch",
190
- GRV_COL_PUSH: "push",
191
- GRV_PUSH_SAME_AS_FETCH: "=",
192
- GRV_NO_REMOTES: "(no remotes)",
193
-
194
- // Gst
195
- GST_TITLE: "gst summary",
196
- GST_ALL_CLEAN__N: "✅ All {n} repos are clean",
197
- GST_FOOTER_COUNTS__TOTAL_DIRTY_FILES_CLEAN_ERRORS:
198
- "repos: {total} · dirty: {dirty} · files: {files} · clean (hidden): {clean} · errors: {errors}",
199
- GST_ERRORS_HEADER: "⚠️ ERRORS",
200
- GST_DETACHED: "(detached)",
201
-
202
- // ── Repo picker ──
203
- REPO_SELECT_CANCELLED: "Repo selection cancelled.",
204
- REPO_SELECT_NO_REPO: "No git repo found.",
205
- REPO_SELECT_NO_REPO_SYNC: "No git repo to sync-main.",
206
- REPO_SELECT_NONE_PICKED: "No repo selected.",
207
- REPO_SELECT_INVALID: "Invalid choice.",
208
- REPO_SELECT_INVALID_INDEX__RAW: "Invalid choice: '{raw}'",
209
- REPO_SELECT_EMPTY_ANSWER: "Nothing selected — exit.",
210
- REPO_SELECT_NEED_NON_INTERACTIVE:
211
- "Non-interactive: pass a repo name, 'all', or a comma-separated list.",
212
- REPO_SELECT_MISSING__MISSING_ALL:
213
- "Repo not in manifest: {missing}. Available: {all}",
214
- REPO_SELECT_ONE_MISSING__PICKED_ALL:
215
- "Repo '{picked}' not in manifest. Available: {all}",
216
- REPO_SELECT_ALL__N: "all ({n} repos)",
217
- REPO_SELECT_SINGLE_PROMPT: "Enter number (1 = all): ",
218
- REPO_SELECT_MULTI_PROMPT: "Choose (e.g. 1 = all · '3 5' = repo 3 & 5): ",
219
- REPO_SELECT_MULTI_HELP__ACTION:
220
- "{action}: enter multiple numbers separated by space/comma, or 'all':",
221
- REPO_SELECT_ACTION_DEFAULT: "select repo",
222
- REPO_SELECT_ACTION_CHOOSE: "choose",
223
- REPO_SELECT_PROMPT_MSG: "Choose repo:",
224
- REPO_SELECT_SYNCMAIN_MSG: "Choose repo for sync-main:",
225
-
226
- // ── Checkout ──
227
- CHECKOUT_MSG_NOT_CLONED: "not cloned",
228
- CHECKOUT_MSG_ON_BRANCH__BRANCH: "already on '{branch}'",
229
- CHECKOUT_MSG_LOCAL_EXISTS__BRANCH:
230
- "branch '{branch}' already exists locally — use -B to reset, or drop -b to switch",
231
- CHECKOUT_MSG_STARTPOINT_MISSING__STARTPOINT:
232
- "start-point '{startPoint}' does not exist",
233
- CHECKOUT_MSG_NO_BRANCH__BRANCH:
234
- "branch '{branch}' does not exist (local or origin)",
235
- CHECKOUT_MSG_FAILED: "checkout failed",
236
- CHECKOUT_MSG_DIRTY__DIRTY: " — commit/stash {dirty} change(s) first",
237
- CHECKOUT_MSG_RESET__BRANCH_FROM: "reset '{branch}' from {from}",
238
- CHECKOUT_MSG_CREATE__BRANCH_FROM: "create '{branch}' from {from}",
239
- CHECKOUT_HEADER__MODE_BRANCH_FROM_N:
240
- "── Checkout — {mode} '{branch}'{fromPart} · {n} repos ──",
241
- CHECKOUT_HEADER_FROM_SUFFIX__START: " (from {start})",
242
- CHECKOUT_RESULT_HEADER__MODE_BRANCH:
243
- "── CHECKOUT RESULT ({mode} '{branch}') ──",
244
- CHECKOUT_LEGEND:
245
- "Legend: ✓=switch/create · ==already on · !=warning · -=skip · ✗=error",
246
- CHECKOUT_SUMMARY__OK_EXISTS_WARN_SKIP_ERR:
247
- "Total: ✓ {ok} · = {exists} · ! {warn} · - {skip} · ✗ {err}",
248
- CHECKOUT_SELECT_ACTION__MODE_BRANCH:
249
- "Select repos to checkout ({mode} '{branch}')",
250
- CHECKOUT_MISSING_BRANCH:
251
- "✗ Missing branch name. E.g.: pan checkout -b feat/#1234",
252
- CHECKOUT_MISSING_BRANCH_HELP: " See 'pan checkout --help' for details.",
253
- CHECKOUT_DETACHED: "(detached)",
254
-
255
- // ── Merge Request ──
256
- MR_MSG_NOT_CLONED: "not cloned",
257
- MR_MSG_NO_ORIGIN: "no origin remote",
258
- MR_MSG_HEAD_DETACHED: "HEAD detached",
259
- MR_MSG_ON_TARGET__TARGET: "already on '{target}'",
260
- MR_MSG_HOST_PARSE__URL: "cannot parse host from origin: {url}",
261
- MR_MSG_ORIGIN_MISSING__TARGET: "origin/{target} does not exist",
262
- MR_MSG_NO_AHEAD__TARGET: "no commit ahead of origin/{target}",
263
- MR_MSG_BRANCH_MISSING_REMOTE__BRANCH:
264
- "branch '{branch}' not on remote — run 'pan push' first",
265
- MR_MSG_HEAD_AHEAD__BRANCH_N:
266
- "HEAD ahead origin/{branch} by {n} commit(s) — run 'pan push' first",
267
- MR_MSG_DRY_RUN_GET__URL: "[dry-run] GET {url}",
268
- MR_MSG_GET_ERROR__MSG: "GET error: {msg}",
269
- MR_MSG_GET_HTTP__STATUS_BODY: "GitLab API GET HTTP {status}: {body}",
270
- MR_MSG_POST_ERROR__MSG: "POST error: {msg}",
271
- MR_MSG_POST_HTTP__STATUS_BODY: "GitLab API POST HTTP {status}: {body}",
272
- MR_MSG_NO_WEB_URL: "response missing web_url",
273
- MR_LABEL_NEW: " (new)",
274
- MR_LABEL_EXISTS: " (exists)",
275
- MR_MISSING_TOKEN: "✗ Missing GITLAB_TOKEN.",
276
- MR_MISSING_TOKEN_1:
277
- " Option 1: export GITLAB_TOKEN=<personal-access-token>",
278
- MR_MISSING_TOKEN_2__PATH:
279
- " Option 2: add 'GITLAB_TOKEN: <token>' to {path}/.pan-env-build.yaml",
280
- MR_MISSING_TOKEN_URL:
281
- " Create token (scope=api): https://gitlab.com/-/user_settings/personal_access_tokens",
282
- MR_SELECT_ACTION__TARGET: "Select repos for MR (target: {target})",
283
- MR_HEADER__TARGET_N: "── Create MR — target: {target} · {n} repos ──",
284
- MR_RESULT_HEADER__TARGET: "── MR RESULT (target: {target}) ──",
285
- MR_LEGEND: "Legend: ✓=new · ==exists · !=not pushed · -=skip · ✗=error",
286
- MR_SUMMARY__OK_EXISTS_WARN_SKIP_ERR:
287
- "Total: ✓ {ok} · = {exists} · ! {warn} · - {skip} · ✗ {err}",
288
-
289
- // ── Checkout arg validation ──
290
- CHECKOUT_ERR_B_AND_BB: "Cannot use both -b and -B.",
291
- CHECKOUT_ERR_STARTPOINT: "--start-point is only valid with -b or -B.",
292
-
293
- // ── Sync-main ──
294
- SYNCMAIN_MSG_NOT_CLONED: "repo missing or not cloned",
295
- SYNCMAIN_MSG_DETACHED: "detached HEAD — skipped",
296
- SYNCMAIN_MSG_IN_PROGRESS__MODE: "in-progress {mode} — resolve first",
297
- SYNCMAIN_MSG_DIRTY__NAME_N:
298
- "[warn] {name}: working tree has {n} uncommitted change(s)",
299
- SYNCMAIN_MSG_FETCH_FAILED: "git fetch origin failed",
300
- SYNCMAIN_MSG_REF_MISSING__REF: "ref {ref} not found (fetch first?)",
301
- SYNCMAIN_MSG_CONFLICT__MODE: "{mode} conflict",
302
- SYNCMAIN_MSG_SEE_STATUS: "(see git status)",
303
- SYNCMAIN_MSG_UPDATED: "updated",
304
- SYNCMAIN_MSG_SYNCED__NAME_BRANCH_REF:
305
- "[ok] {name}: {branch} synced with {ref}",
306
- SYNCMAIN_INTRO__COUNT_MODE_REF:
307
- "sync-main: {count} repo(s) · {mode} ← {ref}",
308
- SYNCMAIN_DETACHED_LABEL: "(detached HEAD)",
309
- SYNCMAIN_CONFLICT_SHORT__MODE_REF_N:
310
- "{mode} {ref} failed — {n} conflict(s)",
311
- SYNCMAIN_MORE_FILES__N: "… and {n} more file(s)",
312
- SYNCMAIN_HEADER: "─── sync-main summary ───",
313
- SYNCMAIN_INFO__REF_MODE_REPOS: "ref: {ref} · mode: {mode} · repos: {repos}",
314
- SYNCMAIN_COUNTS__OK_CONFLICT_ERR_SKIP:
315
- " ok: {ok} · conflict: {conflict} · error: {err} · skip: {skip}",
316
- SYNCMAIN_CONFLICT_HEADER: "CONFLICT — manual resolution required",
317
- SYNCMAIN_HINT_REBASE:
318
- "git add <file>… && git rebase --continue (or git rebase --abort)",
319
- SYNCMAIN_HINT_MERGE: "git add <file>… && git commit",
320
- SYNCMAIN_ERRORS_HEADER: "ERRORS",
321
- SYNCMAIN_END_CONFLICT:
322
- "Finished with conflicts — resolve each repo above then commit/rebase --continue",
323
- SYNCMAIN_END_ERROR: "Finished with errors — see details above",
324
- SYNCMAIN_END_ALL_SYNCED__REF: "All selected repos synced with {ref}",
325
- },
326
- vi: {
327
- DIRECTORY_NOT_FOUND__DIR:
328
- "Không thấy thư mục: {dir} (chạy 'pan clone' trước?)",
329
- COMMAND_MISSING_EXEC_OR_SHELL: "Lệnh thiếu 'exec' hoặc 'shell'.",
330
- COMMAND_NOT_FOUND_IN_SOURCE__COMMAND_PATH:
331
- "Không thấy lệnh '{command}' trong {path}",
332
- NOTHING_SELECTED_EXITING: "Không chọn gì — thoát.",
333
- COMMAND_MISSING_EXEC_OR_SHELL_IN_SOURCE__COMMAND_PATH:
334
- "Lệnh '{command}' thiếu 'exec' hoặc 'shell' trong {path}",
335
- COMMAND_MULTIPLE_PLACES_SELECT_PROJECT__COMMAND:
336
- "Lệnh '{command}' được định nghĩa ở nhiều project — chọn project:",
337
- COMMAND_NOT_FOUND_ANYWHERE__COMMAND:
338
- "Không thấy lệnh '{command}' trong bất kỳ file .pan.yaml nào.",
339
- PROJECT_NOT_FOUND__PROJECT_NAMES:
340
- "Không thấy project '{project}'. Có sẵn: {names}",
341
- COMMAND_MULTIPLE_PROJECTS__COMMAND_LINES:
342
- "Lệnh '{command}' được định nghĩa ở nhiều project. Dùng --project <tên>.\n{lines}",
343
- SCRIPT_NOT_FOUND__PATH: "Không thấy script: {path}",
344
- REPO_MISSING_NAME: "Repository thiếu 'name'.",
345
- REPO_MISSING_URL__NAME: "Repository '{name}' thiếu url thật.",
346
- REPO_MISSING_PATH__NAME: "Repository '{name}' thiếu 'path'.",
347
- MANIFEST_NOT_FOUND__PATH: "Không thấy manifest: {path}",
348
- MANIFEST_NOT_FOUND_FALLBACK_SCAN__DIR:
349
- "ℹ️ Không tìm thấy .project.yaml — coi {dir} là gốc dự án, quét git repo con bên trong.",
350
- MANIFEST_NOT_FOUND_NO_GIT_FALLBACK__DIR:
351
- "Không tìm thấy .project.yaml, cũng không thấy git repo nào dưới {dir} (đã quét {dir} + 2 cấp con).",
352
- CONFIG_NOT_FOUND__PATH: "Không thấy config: {path}",
353
- VALID_TARGETS__COMMAND_VALID: "Target hợp lệ cho '{command}': {valid}",
354
- NO_PAN_YAML_FOUND: "Không thấy .pan.yaml nào (workspace hoặc repo con).",
355
- LOADED_COMMANDS: "Danh sách lệnh đã nạp:",
356
- UNKNOWN_BUILTIN_COMMAND__COMMAND: "Lệnh built-in không xác định: {command}",
357
- NO_PAN_YAML_WITH_COMMANDS: "Không tìm thấy .pan.yaml nào có lệnh.",
358
- NO_PAN_YAML_BUT_GIT_STILL_WORKS:
359
- "Các lệnh git built-in (pull/push/fetch/checkout/...) vẫn dùng được — xem usage dưới đây.",
360
- MENU_SELECT_PROJECT: "pan · chọn dự án:",
361
- COMMANDS_LABEL: "lệnh",
362
- HELP_LABEL: "trợ giúp",
363
- VERSION_LABEL: "phiên bản",
364
- EXIT_LABEL: "thoát",
365
- MENU_SELECT_COMMAND: "chọn lệnh:",
366
- BACK_LABEL: "quay lại",
367
- NO_LABEL: "Không",
368
- YES_LABEL: "Có",
369
- SELECT_TARGET__CMD: "Chọn target cho '{cmd}':",
370
- DEFAULT_LABEL: "(mặc định)",
371
- EXITED: "Đã thoát.",
372
- LANGUAGE_CURRENT__LANG_PATH: "Ngôn ngữ hiện tại: {lang} ({path})",
373
- LANGUAGE_CURRENT_NO_PROJECT__LANG:
374
- "Ngôn ngữ hiện tại: {lang} (không thấy .project.yaml — dùng mặc định/env)",
375
- LANGUAGE_AVAILABLE__LANGS: "Có sẵn: {langs}",
376
- LANGUAGE_USAGE: "Dùng: pan language [<mã>] (vd: pan language vi)",
377
- LANGUAGE_UNKNOWN__LANG_AVAILABLE:
378
- "Ngôn ngữ '{lang}' không hợp lệ. Có sẵn: {available}",
379
- LANGUAGE_NO_PROJECT_YAML:
380
- "Không thấy .project.yaml (đã tìm ngược từ cwd). Chạy 'pan create' trước, hoặc cd vào workspace.",
381
- LANGUAGE_SELECT_PROMPT: "Chọn ngôn ngữ:",
382
- LANGUAGE_SET__LANG_PATH: "✓ Đã đặt ngôn ngữ '{lang}' trong {path}",
383
- AI_NO_WORKSPACE:
384
- "Không thấy .project.yaml (đã tìm ngược từ cwd). Chạy 'pan create' trước, hoặc cd vào workspace PAN Stack.",
385
- AI_NO_SKILLS: "Không thấy skill nào dưới .claude/.cursor/.codex/skills.",
386
- AI_LIST_FOOTER__COUNT: "{count} skill.",
387
- AI_SELECT_ACTION: "pan ai · chọn thao tác:",
388
- AI_SELECT_ACTION__ACTIVE_DISABLED_TOTAL:
389
- "pan ai · {active} active · {disabled} disabled · {total} tổng — chọn thao tác:",
390
- AI_CHOICE_DISABLE__COUNT: "Disable skills ({count})",
391
- AI_CHOICE_ENABLE__COUNT: "Enable skills ({count})",
392
- AI_CHOICE_LIST__COUNT: "List skills ({count})",
393
- AI_NONE: "(không có)",
394
- AI_SELECT_SKILLS: "Chọn skill:",
395
- AI_EMPTY_SELECTION: "Không chọn gì — thoát.",
396
- AI_EMPTY_FOR_ACTION__ACTION: "Không có skill nào để {action}.",
397
- AI_UNKNOWN_SKILL__NAME: "Không thấy skill: {name}",
398
- AI_NEED_TTY_OR_FLAGS:
399
- "Chế độ tương tác cần TTY. Dùng --list, --disable <tên>, hoặc --enable <tên>.",
400
- AI_CANCELLED: "Đã huỷ.",
401
- AI_DISABLE_ENABLE_MUTUAL: "Chỉ dùng một trong --disable hoặc --enable.",
402
- AI_UNKNOWN_FLAG__FLAG: "Cờ không hợp lệ: {flag}",
403
- AI_UNEXPECTED_ARG__ARG:
404
- "Tham số lạ '{arg}'. Dùng --disable/--enable <tên> hoặc --list.",
405
-
406
- AI_CHOICE_INSTALL: "Cài skill / agent",
407
- AI_CHOICE_UPDATE: "Cập nhật skill / agent",
408
- AI_CHECKING_UPDATES: "Đang kiểm tra bản cập nhật...",
409
- AI_NO_UPDATES: "✓ Mọi skill/agent đã cập nhật mới nhất.",
410
- AI_NOTHING_TO_INSTALL: "✓ Đã cài đủ, không có gói mới.",
411
- AI_UPDATE_SELECT: "Chọn gói cần cập nhật:",
412
- AI_INSTALL_SELECT: "Chọn gói cần cài:",
413
- AI_UPDATE_ALL__COUNT: "Cập nhật tất cả ({count})",
414
- AI_UPDATE_AVAILABLE__COUNT:
415
- "⬆ Có {count} gói có bản cập nhật — chọn để update",
416
- AI_UPDATE_DONE__COUNT: "✓ Đã cập nhật {count} package.",
417
- AI_INSTALL_DONE__COUNT: "✓ Đã cài {count} package.",
418
- AI_SELECT_AGENT_DIRS: "Chọn thư mục agent đích:",
419
- AI_INSTALL_USING_AGENTS__AGENTS: "→ Cài vào: {agents}",
420
- AI_NO_PROJECT_ASK_CREATE:
421
- "Không tìm thấy .project.yaml — bạn đang không ở trong 1 dự án pan-stack. Tạo dự án mới ở đây?",
422
- AI_PROJECT_CREATED__PROJECT_MANAGEDBY:
423
- "✓ Đã tạo .project.yaml (project: {project}, managed_by: {managedBy})",
424
-
425
- // ── Bulk git summary (pull/push/fetch/gst) ──
426
- BULK_COL_REPO: "repo",
427
- BULK_COL_BRANCH: "nhánh",
428
- BULK_COL_RESULT: "kết quả",
429
- BULK_COL_STATE: "trạng thái",
430
- BULK_COL_BREAKDOWN: "chi tiết",
431
- BULK_COL_CHANGES: "thay đổi",
432
- BULK_COL_CONFLICT: "conflict",
433
- BULK_COL_COMMITS: "commit",
434
- BULK_COL_LINK: "MR / PR",
435
- BULK_COL_SYNC: "lệch remote",
436
- BULK_COL_NEW_REFS: "ref mới",
437
- BULK_COL_NOTE: "ghi chú",
438
-
439
- BULK_STATUS_UP_TO_DATE: "đã cập nhật",
440
- BULK_STATUS_PUSHED: "đã push",
441
- BULK_STATUS_PULLED: "đã pull",
442
- BULK_STATUS_OK: "ok",
443
- BULK_STATUS_UPDATED: "có cập nhật",
444
- BULK_STATUS_REJECTED: "rejected (pull trước)",
445
- BULK_STATUS_FAILED: "lỗi",
446
- BULK_STATUS_FETCHED: "đã fetch",
447
- BULK_STATUS_CONFLICT: "conflict",
448
- BULK_STATUS_DRY_RUN: "dry-run",
449
- BULK_STATUS_SKIPPED: "bỏ qua",
450
- BULK_STATUS_IN_SYNC: "đồng bộ",
451
- BULK_STATUS_NO_UPSTREAM: "chưa có upstream",
452
- BULK_STATUS_CLEAN: "sạch",
453
- BULK_STATUS_MERGING: "ĐANG MERGE",
454
- BULK_STATUS_REBASING: "ĐANG REBASE",
455
- BULK_STATUS_ERROR: "lỗi",
456
- BULK_MODE_FAST_FORWARD: "tua nhanh",
457
- BULK_MODE_MERGE: "merge",
458
- BULK_MODE_REBASE: "rebase",
459
-
460
- BULK_BREAKDOWN_STAGED__N: "{n} staged",
461
- BULK_BREAKDOWN_UNSTAGED__N: "{n} unstaged",
462
- BULK_BREAKDOWN_UNTRACKED__N: "{n} untracked",
463
- BULK_FILES_ONE: "file",
464
- BULK_FILES_MANY: "file",
465
- BULK_REFS_NEW__N: "{n} mới",
466
- BULK_REFS_UPD__N: "{n} cập nhật",
467
- BULK_REFS_TAGS__N: "{n} tags",
468
- BULK_REFS_PRUNED__N: "{n} pruned",
469
-
470
- // Pull
471
- PULL_TITLE: "tổng hợp pull",
472
- PULL_ALL_UP_TO_DATE__N: "✅ Tất cả {n} repo đã cập nhật",
473
- PULL_FOOTER_COUNTS__TOTAL_CHANGED_UPTODATE_CONFLICT_FAILED:
474
- " Tổng {total} repo · {changed} có thay đổi · {upToDate} đã cập nhật · {conflict} conflict · {failed} lỗi",
475
- PULL_CONFLICT_HEADER: "⚠️ CONFLICT — xử lý thủ công:",
476
-
477
- // Push
478
- PUSH_TITLE: "tổng hợp push",
479
- PUSH_ALL_UP_TO_DATE__N:
480
- "✅ Tất cả {n} repo đã cập nhật, không có gì cần push",
481
- PUSH_FOOTER_COUNTS__TOTAL_PUSHED_UPTODATE_REJECTED_FAILED:
482
- " Tổng {total} repo · {pushed} đã push · {upToDate} đã cập nhật · {rejected} rejected · {failed} lỗi",
483
- PUSH_FOOTER_LINES__COMMITS_ADD_DEL:
484
- " Dòng đã push: {commits} commit · +{add} / −{del}",
485
- PUSH_LINKS_HEADER: "🔗 MR/PR nhanh:",
486
- PUSH_REJECTED_HEADER: "⚠️ Rejected — chạy 'pan pull' trước rồi thử lại:",
487
-
488
- // Fetch
489
- FETCH_TITLE: "tổng hợp fetch",
490
- FETCH_ALL_IN_SYNC__N: "✅ Tất cả {n} repo đã đồng bộ với remote",
491
- FETCH_FOOTER_COUNTS__TOTAL_CHANGED_INSYNC_BEHIND_FAILED:
492
- " Tổng {total} repo · {changed} có thay đổi · {inSync} đồng bộ · {behind} sau remote · {failed} lỗi",
493
- FETCH_BEHIND_HEADER: "ℹ️ Có commit mới ở remote — cân nhắc 'pan pull':",
494
-
495
- // Clone
496
- CLONE_TITLE: "tổng hợp clone",
497
- CLONE_STATUS_CLONED: "đã clone",
498
- CLONE_STATUS_EXISTS: "đã có sẵn",
499
- CLONE_STATUS_NO_ACCESS: "không có quyền",
500
- CLONE_STATUS_NOT_FOUND: "không tìm thấy",
501
- CLONE_ALL_EXIST__N: "✅ Cả {n} repo đã clone sẵn",
502
- CLONE_FOOTER_COUNTS__TOTAL_CLONED_EXISTS_NOACCESS_NOTFOUND_FAILED:
503
- " Tổng {total} repo · {cloned} đã clone · {exists} đã có sẵn · {noAccess} không có quyền · {notFound} không tìm thấy · {failed} lỗi",
504
- CLONE_NO_ACCESS_HEADER:
505
- "⚠️ Không có quyền — kiểm tra quyền repo / SSH key / token:",
506
-
507
- // Grv (git remote -v)
508
- GRV_TITLE: "tổng hợp grv",
509
- GRV_COL_REMOTE: "remote",
510
- GRV_COL_FETCH: "fetch",
511
- GRV_COL_PUSH: "push",
512
- GRV_PUSH_SAME_AS_FETCH: "=",
513
- GRV_NO_REMOTES: "(chưa có remote)",
514
-
515
- // Gst
516
- GST_TITLE: "tổng hợp gst",
517
- GST_ALL_CLEAN__N: "✅ Tất cả {n} repo sạch",
518
- GST_FOOTER_COUNTS__TOTAL_DIRTY_FILES_CLEAN_ERRORS:
519
- "repos: {total} · dirty: {dirty} · files: {files} · clean (ẩn): {clean} · errors: {errors}",
520
- GST_ERRORS_HEADER: "⚠️ LỖI",
521
- GST_DETACHED: "(detached)",
522
-
523
- // ── Repo picker ──
524
- REPO_SELECT_CANCELLED: "Đã huỷ chọn repo.",
525
- REPO_SELECT_NO_REPO: "Không có repo git nào.",
526
- REPO_SELECT_NO_REPO_SYNC: "Không có repo git nào để sync-main.",
527
- REPO_SELECT_NONE_PICKED: "Không có repo nào được chọn.",
528
- REPO_SELECT_INVALID: "Lựa chọn không hợp lệ.",
529
- REPO_SELECT_INVALID_INDEX__RAW: "Lựa chọn không hợp lệ: '{raw}'",
530
- REPO_SELECT_EMPTY_ANSWER: "Không chọn gì — thoát.",
531
- REPO_SELECT_NEED_NON_INTERACTIVE:
532
- "Non-interactive: cần truyền tên repo, 'all', hoặc danh sách phân tách bởi phẩy.",
533
- REPO_SELECT_MISSING__MISSING_ALL:
534
- "Repo không có trong manifest: {missing}. Có: {all}",
535
- REPO_SELECT_ONE_MISSING__PICKED_ALL:
536
- "Repo '{picked}' không có trong manifest. Có: {all}",
537
- REPO_SELECT_ALL__N: "all ({n} repo)",
538
- REPO_SELECT_SINGLE_PROMPT: "Nhập số (1 = all): ",
539
- REPO_SELECT_MULTI_PROMPT: "Chọn (vd: 1 = all · '3 5' = repo 3 & 5): ",
540
- REPO_SELECT_MULTI_HELP__ACTION:
541
- "{action}: nhập nhiều số cách nhau bởi space/phẩy, hoặc 'all':",
542
- REPO_SELECT_ACTION_DEFAULT: "chọn repo",
543
- REPO_SELECT_ACTION_CHOOSE: "chọn",
544
- REPO_SELECT_PROMPT_MSG: "Chọn repo:",
545
- REPO_SELECT_SYNCMAIN_MSG: "Chọn repo để sync-main:",
546
-
547
- // ── Checkout ──
548
- CHECKOUT_MSG_NOT_CLONED: "chưa clone",
549
- CHECKOUT_MSG_ON_BRANCH__BRANCH: "đã ở '{branch}'",
550
- CHECKOUT_MSG_LOCAL_EXISTS__BRANCH:
551
- "branch '{branch}' đã tồn tại local — dùng -B để reset, hoặc bỏ -b để switch",
552
- CHECKOUT_MSG_STARTPOINT_MISSING__STARTPOINT:
553
- "start-point '{startPoint}' không tồn tại",
554
- CHECKOUT_MSG_NO_BRANCH__BRANCH:
555
- "branch '{branch}' không tồn tại (local hoặc origin)",
556
- CHECKOUT_MSG_FAILED: "checkout thất bại",
557
- CHECKOUT_MSG_DIRTY__DIRTY: " — commit/stash {dirty} thay đổi trước",
558
- CHECKOUT_MSG_RESET__BRANCH_FROM: "reset '{branch}' từ {from}",
559
- CHECKOUT_MSG_CREATE__BRANCH_FROM: "tạo '{branch}' từ {from}",
560
- CHECKOUT_HEADER__MODE_BRANCH_FROM_N:
561
- "── Checkout — {mode} '{branch}'{fromPart} · {n} repo ──",
562
- CHECKOUT_HEADER_FROM_SUFFIX__START: " (từ {start})",
563
- CHECKOUT_RESULT_HEADER__MODE_BRANCH:
564
- "── KẾT QUẢ CHECKOUT ({mode} '{branch}') ──",
565
- CHECKOUT_LEGEND:
566
- "Chú giải: ✓=chuyển/tạo · ==đã ở · !=cảnh báo · -=bỏ qua · ✗=lỗi",
567
- CHECKOUT_SUMMARY__OK_EXISTS_WARN_SKIP_ERR:
568
- "Tổng: ✓ {ok} · = {exists} · ! {warn} · - {skip} · ✗ {err}",
569
- CHECKOUT_SELECT_ACTION__MODE_BRANCH:
570
- "Chọn repo checkout ({mode} '{branch}')",
571
- CHECKOUT_MISSING_BRANCH:
572
- "✗ Thiếu tên nhánh. Vd: pan checkout -b feat/#1234",
573
- CHECKOUT_MISSING_BRANCH_HELP:
574
- " Xem 'pan checkout --help' để biết chi tiết.",
575
- CHECKOUT_DETACHED: "(detached)",
576
-
577
- // ── Merge Request ──
578
- MR_MSG_NOT_CLONED: "chưa clone",
579
- MR_MSG_NO_ORIGIN: "không có remote origin",
580
- MR_MSG_HEAD_DETACHED: "HEAD detached",
581
- MR_MSG_ON_TARGET__TARGET: "đang ở '{target}'",
582
- MR_MSG_HOST_PARSE__URL: "không parse được host từ origin: {url}",
583
- MR_MSG_ORIGIN_MISSING__TARGET: "origin/{target} không tồn tại",
584
- MR_MSG_NO_AHEAD__TARGET: "không có commit ahead origin/{target}",
585
- MR_MSG_BRANCH_MISSING_REMOTE__BRANCH:
586
- "branch '{branch}' chưa có trên remote — chạy 'pan push' trước",
587
- MR_MSG_HEAD_AHEAD__BRANCH_N:
588
- "HEAD ahead origin/{branch} {n} commit — chạy 'pan push' trước",
589
- MR_MSG_DRY_RUN_GET__URL: "[dry-run] GET {url}",
590
- MR_MSG_GET_ERROR__MSG: "GET lỗi: {msg}",
591
- MR_MSG_GET_HTTP__STATUS_BODY: "GitLab API GET HTTP {status}: {body}",
592
- MR_MSG_POST_ERROR__MSG: "POST lỗi: {msg}",
593
- MR_MSG_POST_HTTP__STATUS_BODY: "GitLab API POST HTTP {status}: {body}",
594
- MR_MSG_NO_WEB_URL: "response không có web_url",
595
- MR_LABEL_NEW: " (mới)",
596
- MR_LABEL_EXISTS: " (đã tồn tại)",
597
- MR_MISSING_TOKEN: "✗ Thiếu GITLAB_TOKEN.",
598
- MR_MISSING_TOKEN_1: " Cách 1: export GITLAB_TOKEN=<personal-access-token>",
599
- MR_MISSING_TOKEN_2__PATH:
600
- " Cách 2: thêm dòng 'GITLAB_TOKEN: <token>' vào {path}/.pan-env-build.yaml",
601
- MR_MISSING_TOKEN_URL:
602
- " Tạo token (scope=api): https://gitlab.com/-/user_settings/personal_access_tokens",
603
- MR_SELECT_ACTION__TARGET: "Chọn repo tạo MR (target: {target})",
604
- MR_HEADER__TARGET_N: "── Tạo MR — target: {target} · {n} repo ──",
605
- MR_RESULT_HEADER__TARGET: "── KẾT QUẢ TẠO MR (target: {target}) ──",
606
- MR_LEGEND:
607
- "Chú giải: ✓=tạo mới · ==đã tồn tại · !=chưa push · -=bỏ qua · ✗=lỗi",
608
- MR_SUMMARY__OK_EXISTS_WARN_SKIP_ERR:
609
- "Tổng: ✓ {ok} · = {exists} · ! {warn} · - {skip} · ✗ {err}",
610
-
611
- // ── Checkout arg validation ──
612
- CHECKOUT_ERR_B_AND_BB: "Không thể dùng đồng thời -b và -B.",
613
- CHECKOUT_ERR_STARTPOINT: "--start-point chỉ hợp lệ khi có -b hoặc -B.",
614
-
615
- // ── Sync-main ──
616
- SYNCMAIN_MSG_NOT_CLONED: "repo không tồn tại hoặc chưa clone",
617
- SYNCMAIN_MSG_DETACHED: "đang detached HEAD — bỏ qua",
618
- SYNCMAIN_MSG_IN_PROGRESS__MODE: "đang dở {mode} — cần resolve trước",
619
- SYNCMAIN_MSG_DIRTY__NAME_N:
620
- "[warn] {name}: working tree có {n} thay đổi chưa commit",
621
- SYNCMAIN_MSG_FETCH_FAILED: "git fetch origin thất bại",
622
- SYNCMAIN_MSG_REF_MISSING__REF:
623
- "không tìm thấy ref {ref} (chạy fetch trước?)",
624
- SYNCMAIN_MSG_CONFLICT__MODE: "{mode} conflict",
625
- SYNCMAIN_MSG_SEE_STATUS: "(xem git status)",
626
- SYNCMAIN_MSG_UPDATED: "đã cập nhật",
627
- SYNCMAIN_MSG_SYNCED__NAME_BRANCH_REF: "[ok] {name}: {branch} đã sync {ref}",
628
- SYNCMAIN_INTRO__COUNT_MODE_REF: "sync-main: {count} repo · {mode} ← {ref}",
629
- SYNCMAIN_DETACHED_LABEL: "(detached HEAD)",
630
- SYNCMAIN_CONFLICT_SHORT__MODE_REF_N:
631
- "{mode} {ref} thất bại — {n} file conflict",
632
- SYNCMAIN_MORE_FILES__N: "… và {n} file khác",
633
- SYNCMAIN_HEADER: "─── tổng hợp sync-main ───",
634
- SYNCMAIN_INFO__REF_MODE_REPOS: "ref: {ref} · mode: {mode} · repos: {repos}",
635
- SYNCMAIN_COUNTS__OK_CONFLICT_ERR_SKIP:
636
- " ok: {ok} · conflict: {conflict} · lỗi: {err} · bỏ qua: {skip}",
637
- SYNCMAIN_CONFLICT_HEADER: "CONFLICT — cần xử lý thủ công",
638
- SYNCMAIN_HINT_REBASE:
639
- "git add <file>… && git rebase --continue (hoặc git rebase --abort)",
640
- SYNCMAIN_HINT_MERGE: "git add <file>… && git commit",
641
- SYNCMAIN_ERRORS_HEADER: "LỖI",
642
- SYNCMAIN_END_CONFLICT:
643
- "Kết thúc với conflict — resolve từng repo ở trên rồi commit/rebase --continue",
644
- SYNCMAIN_END_ERROR: "Kết thúc với lỗi — xem chi tiết ở trên",
645
- SYNCMAIN_END_ALL_SYNCED__REF: "Tất cả repo đã chọn đã sync {ref}",
646
- },
647
- };