ccjk 9.5.6 → 9.7.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 (103) hide show
  1. package/dist/chunks/agent.mjs +1 -1
  2. package/dist/chunks/api-providers.mjs +1 -1
  3. package/dist/chunks/api.mjs +3 -3
  4. package/dist/chunks/auto-bootstrap.mjs +1 -1
  5. package/dist/chunks/auto-updater.mjs +1 -1
  6. package/dist/chunks/boost.mjs +160 -0
  7. package/dist/chunks/ccjk-agents.mjs +1 -1
  8. package/dist/chunks/ccjk-all.mjs +1 -1
  9. package/dist/chunks/ccjk-config.mjs +1 -1
  10. package/dist/chunks/ccjk-hooks.mjs +1 -1
  11. package/dist/chunks/ccjk-mcp.mjs +2 -2
  12. package/dist/chunks/ccjk-setup.mjs +1 -1
  13. package/dist/chunks/ccjk-skills.mjs +1 -1
  14. package/dist/chunks/ccr.mjs +25 -30
  15. package/dist/chunks/ccu.mjs +1 -1
  16. package/dist/chunks/check-updates.mjs +3 -4
  17. package/dist/chunks/claude-code-config-manager.mjs +7 -7
  18. package/dist/chunks/claude-code-incremental-manager.mjs +2 -2
  19. package/dist/chunks/claude-config.mjs +4 -4
  20. package/dist/chunks/claude-wrapper.mjs +2 -2
  21. package/dist/chunks/codex-config-switch.mjs +4 -5
  22. package/dist/chunks/codex-provider-manager.mjs +2 -3
  23. package/dist/chunks/codex-uninstaller.mjs +2 -2
  24. package/dist/chunks/codex.mjs +207 -6
  25. package/dist/chunks/commands.mjs +391 -88
  26. package/dist/chunks/commands2.mjs +88 -391
  27. package/dist/chunks/completion.mjs +1 -1
  28. package/dist/chunks/config-consolidator.mjs +2 -2
  29. package/dist/chunks/config-switch.mjs +3 -4
  30. package/dist/chunks/config.mjs +78 -7
  31. package/dist/chunks/config2.mjs +400 -410
  32. package/dist/chunks/config3.mjs +410 -400
  33. package/dist/chunks/constants.mjs +1 -1
  34. package/dist/chunks/doctor.mjs +4 -4
  35. package/dist/chunks/features.mjs +24 -17
  36. package/dist/chunks/index.mjs +178 -7
  37. package/dist/chunks/index2.mjs +1162 -169
  38. package/dist/chunks/index3.mjs +910 -1076
  39. package/dist/chunks/index4.mjs +137 -947
  40. package/dist/chunks/index5.mjs +635 -167
  41. package/dist/chunks/init.mjs +141 -99
  42. package/dist/chunks/installer.mjs +147 -649
  43. package/dist/chunks/installer2.mjs +649 -147
  44. package/dist/chunks/interview.mjs +2 -2
  45. package/dist/chunks/marketplace.mjs +1 -1
  46. package/dist/chunks/mcp.mjs +1058 -17
  47. package/dist/chunks/menu.mjs +147 -56
  48. package/dist/chunks/monitor.mjs +2 -2
  49. package/dist/chunks/notification.mjs +1 -1
  50. package/dist/chunks/onboarding.mjs +2 -2
  51. package/dist/chunks/package.mjs +2 -210
  52. package/dist/chunks/permission-manager.mjs +2 -2
  53. package/dist/chunks/permissions.mjs +1 -1
  54. package/dist/chunks/platform.mjs +1 -1
  55. package/dist/chunks/plugin.mjs +1 -1
  56. package/dist/chunks/prompts.mjs +1 -1
  57. package/dist/chunks/providers.mjs +1 -1
  58. package/dist/chunks/quick-setup.mjs +16 -20
  59. package/dist/chunks/silent-updater.mjs +1 -1
  60. package/dist/chunks/simple-config.mjs +2 -2
  61. package/dist/chunks/skill.mjs +1 -1
  62. package/dist/chunks/skills-sync.mjs +1 -1
  63. package/dist/chunks/skills.mjs +1 -1
  64. package/dist/chunks/startup.mjs +1 -1
  65. package/dist/chunks/stats.mjs +1 -1
  66. package/dist/chunks/status.mjs +159 -0
  67. package/dist/chunks/team.mjs +1 -1
  68. package/dist/chunks/thinking.mjs +2 -2
  69. package/dist/chunks/uninstall.mjs +6 -6
  70. package/dist/chunks/update.mjs +6 -9
  71. package/dist/chunks/upgrade-manager.mjs +2 -2
  72. package/dist/chunks/version-checker.mjs +3 -3
  73. package/dist/chunks/vim.mjs +1 -1
  74. package/dist/chunks/workflows.mjs +616 -215
  75. package/dist/cli.mjs +70 -121
  76. package/dist/index.d.mts +17 -1482
  77. package/dist/index.d.ts +17 -1482
  78. package/dist/index.mjs +950 -4740
  79. package/dist/shared/{ccjk.zCqdxT2Y.mjs → ccjk.Br91zBIG.mjs} +2 -2
  80. package/dist/shared/ccjk.CSkyCZIM.mjs +638 -0
  81. package/dist/shared/{ccjk.BKoi8-Hy.mjs → ccjk.DE91nClQ.mjs} +1 -1
  82. package/dist/shared/{ccjk.f40us0yY.mjs → ccjk.DvIrK0wz.mjs} +2 -2
  83. package/dist/shared/ccjk.LsPZ2PYo.mjs +1048 -0
  84. package/dist/shared/{ccjk.DRweXU5F.mjs → ccjk.q1koQxEE.mjs} +2 -2
  85. package/package.json +1 -1
  86. package/templates/claude-code/common/settings.json +15 -111
  87. package/dist/chunks/api-adapter.mjs +0 -180
  88. package/dist/chunks/cli.mjs +0 -2227
  89. package/dist/chunks/context-menu.mjs +0 -913
  90. package/dist/chunks/hooks-sync.mjs +0 -1627
  91. package/dist/chunks/index6.mjs +0 -663
  92. package/dist/chunks/mcp-market.mjs +0 -1077
  93. package/dist/chunks/mcp-server.mjs +0 -776
  94. package/dist/chunks/project-detector.mjs +0 -131
  95. package/dist/chunks/provider-registry.mjs +0 -92
  96. package/dist/chunks/setup-wizard.mjs +0 -362
  97. package/dist/chunks/tools.mjs +0 -143
  98. package/dist/chunks/workflows2.mjs +0 -633
  99. package/dist/shared/ccjk.BM_HZogn.mjs +0 -347
  100. package/dist/shared/ccjk.BaEp4UHQ.mjs +0 -75
  101. package/dist/shared/ccjk.CS0ybJCf.mjs +0 -490
  102. package/dist/shared/ccjk.CZgIwikC.mjs +0 -209
  103. package/dist/shared/ccjk.tO8zeFh1.mjs +0 -397
@@ -1,913 +0,0 @@
1
- import ansis from 'ansis';
2
- import inquirer from 'inquirer';
3
- import { i18n } from './index2.mjs';
4
- import { existsSync, readdirSync, statSync } from 'node:fs';
5
- import { homedir } from 'node:os';
6
- import process__default from 'node:process';
7
- import { join, dirname } from 'pathe';
8
- import { readFile, writeFileAtomic } from './fs-operations.mjs';
9
- import 'node:url';
10
- import 'i18next';
11
- import 'i18next-fs-backend';
12
- import 'node:crypto';
13
- import 'node:fs/promises';
14
-
15
- function detectProjectContext(projectPath = process__default.cwd()) {
16
- const context = {
17
- type: "unknown",
18
- language: "unknown",
19
- hasTests: false,
20
- hasDocker: false,
21
- hasCi: false,
22
- monorepo: false,
23
- detectedPatterns: []
24
- };
25
- if (!existsSync(projectPath)) {
26
- return context;
27
- }
28
- const files = safeReadDir(projectPath);
29
- if (files.includes("package.json")) {
30
- context.type = "nodejs";
31
- context.language = files.includes("tsconfig.json") ? "typescript" : "javascript";
32
- context.detectedPatterns.push("package.json");
33
- if (files.includes("pnpm-lock.yaml")) {
34
- context.packageManager = "pnpm";
35
- } else if (files.includes("yarn.lock")) {
36
- context.packageManager = "yarn";
37
- } else if (files.includes("bun.lockb")) {
38
- context.packageManager = "bun";
39
- } else if (files.includes("package-lock.json")) {
40
- context.packageManager = "npm";
41
- }
42
- const packageJson = readPackageJson(projectPath);
43
- if (packageJson) {
44
- context.framework = detectNodeFramework(packageJson);
45
- }
46
- if (files.includes("pnpm-workspace.yaml") || files.includes("lerna.json")) {
47
- context.monorepo = true;
48
- context.detectedPatterns.push("monorepo");
49
- }
50
- }
51
- if (files.includes("pyproject.toml") || files.includes("setup.py") || files.includes("requirements.txt")) {
52
- context.type = "python";
53
- context.language = "python";
54
- context.detectedPatterns.push(files.includes("pyproject.toml") ? "pyproject.toml" : "requirements.txt");
55
- if (files.includes("poetry.lock")) {
56
- context.packageManager = "poetry";
57
- } else if (files.includes("Pipfile.lock")) {
58
- context.packageManager = "pipenv";
59
- } else if (files.includes("uv.lock")) {
60
- context.packageManager = "uv";
61
- }
62
- context.framework = detectPythonFramework(projectPath);
63
- }
64
- if (files.includes("Cargo.toml")) {
65
- context.type = "rust";
66
- context.language = "rust";
67
- context.packageManager = "cargo";
68
- context.detectedPatterns.push("Cargo.toml");
69
- const cargoContent = readFile(join(projectPath, "Cargo.toml"));
70
- if (cargoContent?.includes("[workspace]")) {
71
- context.monorepo = true;
72
- context.detectedPatterns.push("cargo-workspace");
73
- }
74
- }
75
- if (files.includes("go.mod")) {
76
- context.type = "go";
77
- context.language = "go";
78
- context.packageManager = "go";
79
- context.detectedPatterns.push("go.mod");
80
- }
81
- if (files.includes("pom.xml") || files.includes("build.gradle") || files.includes("build.gradle.kts")) {
82
- context.type = "java";
83
- context.language = "java";
84
- context.packageManager = files.includes("pom.xml") ? "maven" : "gradle";
85
- context.detectedPatterns.push(files.includes("pom.xml") ? "pom.xml" : "build.gradle");
86
- }
87
- if (files.some((f) => f.endsWith(".csproj") || f.endsWith(".fsproj") || f.endsWith(".sln"))) {
88
- context.type = "dotnet";
89
- context.language = files.some((f) => f.endsWith(".fsproj")) ? "fsharp" : "csharp";
90
- context.packageManager = "dotnet";
91
- context.detectedPatterns.push(".NET project");
92
- }
93
- if (files.includes("Gemfile")) {
94
- context.type = "ruby";
95
- context.language = "ruby";
96
- context.packageManager = "bundler";
97
- context.detectedPatterns.push("Gemfile");
98
- if (files.includes("config") && existsSync(join(projectPath, "config", "routes.rb"))) {
99
- context.framework = "rails";
100
- }
101
- }
102
- if (files.includes("composer.json")) {
103
- context.type = "php";
104
- context.language = "php";
105
- context.packageManager = "composer";
106
- context.detectedPatterns.push("composer.json");
107
- if (files.includes("artisan")) {
108
- context.framework = "laravel";
109
- }
110
- }
111
- context.hasDocker = files.includes("Dockerfile") || files.includes("docker-compose.yml") || files.includes("docker-compose.yaml");
112
- context.hasCi = files.includes(".github") || files.includes(".gitlab-ci.yml") || files.includes(".circleci");
113
- context.hasTests = files.includes("tests") || files.includes("test") || files.includes("__tests__") || files.includes("spec");
114
- if (context.hasDocker)
115
- context.detectedPatterns.push("docker");
116
- if (context.hasCi)
117
- context.detectedPatterns.push("ci/cd");
118
- if (context.hasTests)
119
- context.detectedPatterns.push("tests");
120
- return context;
121
- }
122
- function safeReadDir(dirPath) {
123
- try {
124
- return readdirSync(dirPath);
125
- } catch {
126
- return [];
127
- }
128
- }
129
- function readPackageJson(projectPath) {
130
- try {
131
- const content = readFile(join(projectPath, "package.json"));
132
- if (content) {
133
- return JSON.parse(content);
134
- }
135
- } catch {
136
- }
137
- return null;
138
- }
139
- function detectNodeFramework(packageJson) {
140
- const deps = {
141
- ...packageJson.dependencies || {},
142
- ...packageJson.devDependencies || {}
143
- };
144
- if (deps.next)
145
- return "nextjs";
146
- if (deps.nuxt)
147
- return "nuxt";
148
- if (deps["@angular/core"])
149
- return "angular";
150
- if (deps.vue)
151
- return "vue";
152
- if (deps.react)
153
- return "react";
154
- if (deps.svelte)
155
- return "svelte";
156
- if (deps.express)
157
- return "express";
158
- if (deps.fastify)
159
- return "fastify";
160
- if (deps.nestjs || deps["@nestjs/core"])
161
- return "nestjs";
162
- if (deps.hono)
163
- return "hono";
164
- if (deps.elysia)
165
- return "elysia";
166
- return void 0;
167
- }
168
- function detectPythonFramework(projectPath) {
169
- const files = safeReadDir(projectPath);
170
- if (files.includes("manage.py"))
171
- return "django";
172
- if (files.includes("app.py") || files.includes("main.py")) {
173
- const content = readFile(join(projectPath, files.includes("app.py") ? "app.py" : "main.py"));
174
- if (content) {
175
- if (content.includes("FastAPI"))
176
- return "fastapi";
177
- if (content.includes("Flask"))
178
- return "flask";
179
- }
180
- }
181
- return void 0;
182
- }
183
- function getContextRules() {
184
- return [
185
- // Coding Style Rules
186
- {
187
- id: "prefer-functional",
188
- name: "Prefer Functional Style",
189
- nameZh: "\u4F18\u5148\u51FD\u6570\u5F0F\u98CE\u683C",
190
- description: "Prefer functional programming patterns over imperative",
191
- descriptionZh: "\u4F18\u5148\u4F7F\u7528\u51FD\u6570\u5F0F\u7F16\u7A0B\u6A21\u5F0F\u800C\u975E\u547D\u4EE4\u5F0F",
192
- content: `## Coding Style
193
- - Prefer functional programming patterns (map, filter, reduce) over imperative loops
194
- - Use pure functions where possible
195
- - Avoid side effects in functions`,
196
- contentZh: `## \u7F16\u7801\u98CE\u683C
197
- - \u4F18\u5148\u4F7F\u7528\u51FD\u6570\u5F0F\u7F16\u7A0B\u6A21\u5F0F\uFF08map\u3001filter\u3001reduce\uFF09\u800C\u975E\u547D\u4EE4\u5F0F\u5FAA\u73AF
198
- - \u5C3D\u53EF\u80FD\u4F7F\u7528\u7EAF\u51FD\u6570
199
- - \u907F\u514D\u51FD\u6570\u4E2D\u7684\u526F\u4F5C\u7528`,
200
- category: "coding",
201
- applicableTo: ["nodejs", "python", "rust", "go", "java", "dotnet", "ruby", "php", "unknown"]
202
- },
203
- {
204
- id: "explicit-types",
205
- name: "Explicit Type Annotations",
206
- nameZh: "\u663E\u5F0F\u7C7B\u578B\u6CE8\u89E3",
207
- description: "Always use explicit type annotations",
208
- descriptionZh: "\u59CB\u7EC8\u4F7F\u7528\u663E\u5F0F\u7C7B\u578B\u6CE8\u89E3",
209
- content: `## Type Safety
210
- - Always use explicit type annotations for function parameters and return types
211
- - Avoid using 'any' type
212
- - Use strict null checks`,
213
- contentZh: `## \u7C7B\u578B\u5B89\u5168
214
- - \u59CB\u7EC8\u4E3A\u51FD\u6570\u53C2\u6570\u548C\u8FD4\u56DE\u7C7B\u578B\u4F7F\u7528\u663E\u5F0F\u7C7B\u578B\u6CE8\u89E3
215
- - \u907F\u514D\u4F7F\u7528 'any' \u7C7B\u578B
216
- - \u4F7F\u7528\u4E25\u683C\u7684\u7A7A\u503C\u68C0\u67E5`,
217
- category: "coding",
218
- applicableTo: ["nodejs", "python", "rust", "java", "dotnet"]
219
- },
220
- {
221
- id: "error-handling",
222
- name: "Comprehensive Error Handling",
223
- nameZh: "\u5168\u9762\u7684\u9519\u8BEF\u5904\u7406",
224
- description: "Always handle errors explicitly",
225
- descriptionZh: "\u59CB\u7EC8\u663E\u5F0F\u5904\u7406\u9519\u8BEF",
226
- content: `## Error Handling
227
- - Always handle errors explicitly, never ignore them
228
- - Use try-catch blocks for async operations
229
- - Provide meaningful error messages
230
- - Log errors with context information`,
231
- contentZh: `## \u9519\u8BEF\u5904\u7406
232
- - \u59CB\u7EC8\u663E\u5F0F\u5904\u7406\u9519\u8BEF\uFF0C\u4E0D\u8981\u5FFD\u7565
233
- - \u5BF9\u5F02\u6B65\u64CD\u4F5C\u4F7F\u7528 try-catch \u5757
234
- - \u63D0\u4F9B\u6709\u610F\u4E49\u7684\u9519\u8BEF\u6D88\u606F
235
- - \u8BB0\u5F55\u5E26\u6709\u4E0A\u4E0B\u6587\u4FE1\u606F\u7684\u9519\u8BEF`,
236
- category: "coding",
237
- applicableTo: ["nodejs", "python", "rust", "go", "java", "dotnet", "ruby", "php", "unknown"]
238
- },
239
- // Testing Rules
240
- {
241
- id: "test-first",
242
- name: "Test-First Development",
243
- nameZh: "\u6D4B\u8BD5\u4F18\u5148\u5F00\u53D1",
244
- description: "Write tests before implementation",
245
- descriptionZh: "\u5728\u5B9E\u73B0\u4E4B\u524D\u7F16\u5199\u6D4B\u8BD5",
246
- content: `## Testing
247
- - Write tests before implementing features (TDD)
248
- - Each function should have corresponding unit tests
249
- - Use descriptive test names that explain the expected behavior`,
250
- contentZh: `## \u6D4B\u8BD5
251
- - \u5728\u5B9E\u73B0\u529F\u80FD\u4E4B\u524D\u7F16\u5199\u6D4B\u8BD5\uFF08TDD\uFF09
252
- - \u6BCF\u4E2A\u51FD\u6570\u90FD\u5E94\u6709\u5BF9\u5E94\u7684\u5355\u5143\u6D4B\u8BD5
253
- - \u4F7F\u7528\u63CF\u8FF0\u6027\u7684\u6D4B\u8BD5\u540D\u79F0\u6765\u89E3\u91CA\u9884\u671F\u884C\u4E3A`,
254
- category: "testing",
255
- applicableTo: ["nodejs", "python", "rust", "go", "java", "dotnet", "ruby", "php", "unknown"]
256
- },
257
- {
258
- id: "high-coverage",
259
- name: "High Test Coverage",
260
- nameZh: "\u9AD8\u6D4B\u8BD5\u8986\u76D6\u7387",
261
- description: "Maintain high test coverage",
262
- descriptionZh: "\u4FDD\u6301\u9AD8\u6D4B\u8BD5\u8986\u76D6\u7387",
263
- content: `## Test Coverage
264
- - Maintain at least 80% code coverage
265
- - Cover edge cases and error scenarios
266
- - Include integration tests for critical paths`,
267
- contentZh: `## \u6D4B\u8BD5\u8986\u76D6\u7387
268
- - \u4FDD\u6301\u81F3\u5C11 80% \u7684\u4EE3\u7801\u8986\u76D6\u7387
269
- - \u8986\u76D6\u8FB9\u754C\u60C5\u51B5\u548C\u9519\u8BEF\u573A\u666F
270
- - \u4E3A\u5173\u952E\u8DEF\u5F84\u5305\u542B\u96C6\u6210\u6D4B\u8BD5`,
271
- category: "testing",
272
- applicableTo: ["nodejs", "python", "rust", "go", "java", "dotnet", "ruby", "php", "unknown"]
273
- },
274
- // Documentation Rules
275
- {
276
- id: "doc-comments",
277
- name: "Documentation Comments",
278
- nameZh: "\u6587\u6863\u6CE8\u91CA",
279
- description: "Add documentation comments to all public APIs",
280
- descriptionZh: "\u4E3A\u6240\u6709\u516C\u5171 API \u6DFB\u52A0\u6587\u6863\u6CE8\u91CA",
281
- content: `## Documentation
282
- - Add JSDoc/docstring comments to all public functions and classes
283
- - Include parameter descriptions and return value documentation
284
- - Add usage examples for complex functions`,
285
- contentZh: `## \u6587\u6863
286
- - \u4E3A\u6240\u6709\u516C\u5171\u51FD\u6570\u548C\u7C7B\u6DFB\u52A0 JSDoc/docstring \u6CE8\u91CA
287
- - \u5305\u542B\u53C2\u6570\u63CF\u8FF0\u548C\u8FD4\u56DE\u503C\u6587\u6863
288
- - \u4E3A\u590D\u6742\u51FD\u6570\u6DFB\u52A0\u4F7F\u7528\u793A\u4F8B`,
289
- category: "docs",
290
- applicableTo: ["nodejs", "python", "rust", "go", "java", "dotnet", "ruby", "php", "unknown"]
291
- },
292
- // Workflow Rules
293
- {
294
- id: "conventional-commits",
295
- name: "Conventional Commits",
296
- nameZh: "\u7EA6\u5B9A\u5F0F\u63D0\u4EA4",
297
- description: "Use conventional commit messages",
298
- descriptionZh: "\u4F7F\u7528\u7EA6\u5B9A\u5F0F\u63D0\u4EA4\u6D88\u606F",
299
- content: `## Git Workflow
300
- - Use conventional commit format: type(scope): description
301
- - Types: feat, fix, docs, style, refactor, test, chore
302
- - Keep commits atomic and focused`,
303
- contentZh: `## Git \u5DE5\u4F5C\u6D41
304
- - \u4F7F\u7528\u7EA6\u5B9A\u5F0F\u63D0\u4EA4\u683C\u5F0F\uFF1Atype(scope): description
305
- - \u7C7B\u578B\uFF1Afeat\u3001fix\u3001docs\u3001style\u3001refactor\u3001test\u3001chore
306
- - \u4FDD\u6301\u63D0\u4EA4\u539F\u5B50\u5316\u548C\u4E13\u6CE8`,
307
- category: "workflow",
308
- applicableTo: ["nodejs", "python", "rust", "go", "java", "dotnet", "ruby", "php", "unknown"]
309
- },
310
- {
311
- id: "pr-guidelines",
312
- name: "PR Guidelines",
313
- nameZh: "PR \u6307\u5357",
314
- description: "Follow PR best practices",
315
- descriptionZh: "\u9075\u5FAA PR \u6700\u4F73\u5B9E\u8DF5",
316
- content: `## Pull Requests
317
- - Keep PRs small and focused (< 400 lines)
318
- - Include clear description of changes
319
- - Add screenshots for UI changes
320
- - Request reviews from relevant team members`,
321
- contentZh: `## Pull Requests
322
- - \u4FDD\u6301 PR \u5C0F\u800C\u4E13\u6CE8\uFF08< 400 \u884C\uFF09
323
- - \u5305\u542B\u6E05\u6670\u7684\u53D8\u66F4\u63CF\u8FF0
324
- - \u4E3A UI \u53D8\u66F4\u6DFB\u52A0\u622A\u56FE
325
- - \u5411\u76F8\u5173\u56E2\u961F\u6210\u5458\u8BF7\u6C42\u5BA1\u67E5`,
326
- category: "workflow",
327
- applicableTo: ["nodejs", "python", "rust", "go", "java", "dotnet", "ruby", "php", "unknown"]
328
- },
329
- // Security Rules
330
- {
331
- id: "security-basics",
332
- name: "Security Best Practices",
333
- nameZh: "\u5B89\u5168\u6700\u4F73\u5B9E\u8DF5",
334
- description: "Follow security best practices",
335
- descriptionZh: "\u9075\u5FAA\u5B89\u5168\u6700\u4F73\u5B9E\u8DF5",
336
- content: `## Security
337
- - Never commit secrets or credentials
338
- - Validate and sanitize all user inputs
339
- - Use parameterized queries for database operations
340
- - Keep dependencies updated`,
341
- contentZh: `## \u5B89\u5168
342
- - \u6C38\u8FDC\u4E0D\u8981\u63D0\u4EA4\u5BC6\u94A5\u6216\u51ED\u8BC1
343
- - \u9A8C\u8BC1\u548C\u6E05\u7406\u6240\u6709\u7528\u6237\u8F93\u5165
344
- - \u5BF9\u6570\u636E\u5E93\u64CD\u4F5C\u4F7F\u7528\u53C2\u6570\u5316\u67E5\u8BE2
345
- - \u4FDD\u6301\u4F9D\u8D56\u9879\u66F4\u65B0`,
346
- category: "security",
347
- applicableTo: ["nodejs", "python", "rust", "go", "java", "dotnet", "ruby", "php", "unknown"]
348
- }
349
- ];
350
- }
351
- function getApplicableRules(projectType) {
352
- return getContextRules().filter(
353
- (rule) => rule.applicableTo.includes(projectType) || rule.applicableTo.includes("unknown")
354
- );
355
- }
356
- function getContextFiles(projectPath = process__default.cwd()) {
357
- const home = homedir();
358
- const files = [];
359
- const globalPath = join(home, ".claude", "CLAUDE.md");
360
- files.push({
361
- path: globalPath,
362
- type: "global",
363
- exists: existsSync(globalPath),
364
- ...getFileStats(globalPath)
365
- });
366
- const projectClaudeMd = join(projectPath, "CLAUDE.md");
367
- files.push({
368
- path: projectClaudeMd,
369
- type: "project",
370
- exists: existsSync(projectClaudeMd),
371
- ...getFileStats(projectClaudeMd)
372
- });
373
- const localPath = join(projectPath, ".claude", "CLAUDE.md");
374
- files.push({
375
- path: localPath,
376
- type: "local",
377
- exists: existsSync(localPath),
378
- ...getFileStats(localPath)
379
- });
380
- return files;
381
- }
382
- function getFileStats(filePath) {
383
- try {
384
- if (existsSync(filePath)) {
385
- const stats = statSync(filePath);
386
- return {
387
- size: stats.size,
388
- lastModified: stats.mtime
389
- };
390
- }
391
- } catch {
392
- }
393
- return {};
394
- }
395
- function readContextFile(filePath) {
396
- return readFile(filePath);
397
- }
398
- async function writeContextFile(filePath, content) {
399
- try {
400
- const dir = dirname(filePath);
401
- if (!existsSync(dir)) {
402
- const { mkdirSync } = await import('node:fs');
403
- mkdirSync(dir, { recursive: true });
404
- }
405
- await writeFileAtomic(filePath, content);
406
- return true;
407
- } catch {
408
- return false;
409
- }
410
- }
411
- function generateContextContent(context, selectedRules, lang = "en") {
412
- const isZh = lang === "zh-CN";
413
- const rules = getContextRules().filter((r) => selectedRules.includes(r.id));
414
- const lines = [];
415
- lines.push(isZh ? "# \u9879\u76EE\u89C4\u5219" : "# Project Rules");
416
- lines.push("");
417
- lines.push(isZh ? "## \u9879\u76EE\u4FE1\u606F" : "## Project Information");
418
- lines.push(`- ${isZh ? "\u7C7B\u578B" : "Type"}: ${context.type}`);
419
- lines.push(`- ${isZh ? "\u8BED\u8A00" : "Language"}: ${context.language}`);
420
- if (context.framework) {
421
- lines.push(`- ${isZh ? "\u6846\u67B6" : "Framework"}: ${context.framework}`);
422
- }
423
- if (context.packageManager) {
424
- lines.push(`- ${isZh ? "\u5305\u7BA1\u7406\u5668" : "Package Manager"}: ${context.packageManager}`);
425
- }
426
- lines.push("");
427
- for (const rule of rules) {
428
- lines.push(isZh ? rule.contentZh : rule.content);
429
- lines.push("");
430
- }
431
- lines.push("---");
432
- lines.push(isZh ? `*\u7531 CCJK \u81EA\u52A8\u751F\u6210\u4E8E ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}*` : `*Auto-generated by CCJK on ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}*`);
433
- return lines.join("\n");
434
- }
435
- function getRecommendedRules(context) {
436
- const recommended = [];
437
- recommended.push("error-handling", "security-basics");
438
- if (["nodejs", "python", "rust", "java", "dotnet"].includes(context.type)) {
439
- if (context.language === "typescript" || context.type === "rust" || context.type === "java") {
440
- recommended.push("explicit-types");
441
- }
442
- }
443
- if (context.hasTests) {
444
- recommended.push("test-first", "high-coverage");
445
- }
446
- if (context.hasCi) {
447
- recommended.push("conventional-commits", "pr-guidelines");
448
- }
449
- recommended.push("doc-comments");
450
- return recommended;
451
- }
452
- function mergeContextContent(existingContent, newRules, lang = "en") {
453
- const isZh = lang === "zh-CN";
454
- const rules = getContextRules().filter((r) => newRules.includes(r.id));
455
- const existingRuleIds = [];
456
- for (const rule of getContextRules()) {
457
- const marker = isZh ? rule.contentZh.split("\n")[0] : rule.content.split("\n")[0];
458
- if (existingContent.includes(marker)) {
459
- existingRuleIds.push(rule.id);
460
- }
461
- }
462
- const newRulesToAdd = rules.filter((r) => !existingRuleIds.includes(r.id));
463
- if (newRulesToAdd.length === 0) {
464
- return existingContent;
465
- }
466
- const footerMarker = "---";
467
- const footerIndex = existingContent.lastIndexOf(footerMarker);
468
- let content = existingContent;
469
- const newContent = newRulesToAdd.map((r) => isZh ? r.contentZh : r.content).join("\n\n");
470
- if (footerIndex > 0) {
471
- content = `${existingContent.slice(0, footerIndex) + newContent}
472
-
473
- ${existingContent.slice(footerIndex)}`;
474
- } else {
475
- content = `${existingContent}
476
-
477
- ${newContent}`;
478
- }
479
- return content;
480
- }
481
- function getProjectTypeLabel(type, lang = "en") {
482
- const labels = {
483
- nodejs: { en: "Node.js", zh: "Node.js" },
484
- python: { en: "Python", zh: "Python" },
485
- rust: { en: "Rust", zh: "Rust" },
486
- go: { en: "Go", zh: "Go" },
487
- java: { en: "Java", zh: "Java" },
488
- dotnet: { en: ".NET", zh: ".NET" },
489
- ruby: { en: "Ruby", zh: "Ruby" },
490
- php: { en: "PHP", zh: "PHP" },
491
- unknown: { en: "Unknown", zh: "\u672A\u77E5" }
492
- };
493
- return lang === "zh-CN" ? labels[type].zh : labels[type].en;
494
- }
495
- function getContextFileTypeLabel(type, lang = "en") {
496
- const labels = {
497
- global: { en: "Global", zh: "\u5168\u5C40" },
498
- project: { en: "Project", zh: "\u9879\u76EE" },
499
- local: { en: "Local", zh: "\u672C\u5730" }
500
- };
501
- return lang === "zh-CN" ? labels[type].zh : labels[type].en;
502
- }
503
- function formatFileSize(bytes) {
504
- if (bytes < 1024)
505
- return `${bytes} B`;
506
- if (bytes < 1024 * 1024)
507
- return `${(bytes / 1024).toFixed(1)} KB`;
508
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
509
- }
510
-
511
- async function showContextMenu() {
512
- const lang = i18n.language;
513
- const isZh = lang === "zh-CN";
514
- console.log(ansis.green.bold(`
515
- \u{1F4CB} ${isZh ? "\u4E0A\u4E0B\u6587\u7BA1\u7406" : "Context Management"}
516
- `));
517
- const context = detectProjectContext();
518
- displayProjectInfo(context, lang);
519
- const { action } = await inquirer.prompt([
520
- {
521
- type: "list",
522
- name: "action",
523
- message: isZh ? "\u9009\u62E9\u64CD\u4F5C" : "Select action",
524
- choices: [
525
- {
526
- name: `\u{1F50D} ${isZh ? "\u67E5\u770B\u4E0A\u4E0B\u6587\u6587\u4EF6" : "View Context Files"}`,
527
- value: "view"
528
- },
529
- {
530
- name: `\u2728 ${isZh ? "\u81EA\u52A8\u751F\u6210\u89C4\u5219" : "Auto-generate Rules"}`,
531
- value: "generate"
532
- },
533
- {
534
- name: `\u{1F4DD} ${isZh ? "\u6DFB\u52A0\u89C4\u5219" : "Add Rules"}`,
535
- value: "add"
536
- },
537
- {
538
- name: `\u{1F4D6} ${isZh ? "\u67E5\u770B\u53EF\u7528\u89C4\u5219" : "Browse Available Rules"}`,
539
- value: "browse"
540
- },
541
- {
542
- name: `\u{1F519} ${isZh ? "\u8FD4\u56DE" : "Back"}`,
543
- value: "back"
544
- }
545
- ]
546
- }
547
- ]);
548
- switch (action) {
549
- case "view":
550
- await viewContextFiles(lang);
551
- break;
552
- case "generate":
553
- await generateContextRules(context, lang);
554
- break;
555
- case "add":
556
- await addRulesToContext(context, lang);
557
- break;
558
- case "browse":
559
- await browseRules(context, lang);
560
- break;
561
- case "back":
562
- return;
563
- }
564
- if (action !== "back") {
565
- await showContextMenu();
566
- }
567
- }
568
- function displayProjectInfo(context, lang) {
569
- const isZh = lang === "zh-CN";
570
- console.log(ansis.dim("\u2500".repeat(50)));
571
- console.log(ansis.bold(isZh ? "\u68C0\u6D4B\u5230\u7684\u9879\u76EE\u4FE1\u606F\uFF1A" : "Detected Project Info:"));
572
- const typeLabel = getProjectTypeLabel(context.type, lang);
573
- console.log(` ${isZh ? "\u7C7B\u578B" : "Type"}: ${ansis.green(typeLabel)}`);
574
- console.log(` ${isZh ? "\u8BED\u8A00" : "Language"}: ${ansis.green(context.language)}`);
575
- if (context.framework) {
576
- console.log(` ${isZh ? "\u6846\u67B6" : "Framework"}: ${ansis.green(context.framework)}`);
577
- }
578
- if (context.packageManager) {
579
- console.log(` ${isZh ? "\u5305\u7BA1\u7406\u5668" : "Package Manager"}: ${ansis.green(context.packageManager)}`);
580
- }
581
- const features = [];
582
- if (context.hasTests)
583
- features.push(isZh ? "\u6D4B\u8BD5" : "Tests");
584
- if (context.hasDocker)
585
- features.push("Docker");
586
- if (context.hasCi)
587
- features.push("CI/CD");
588
- if (context.monorepo)
589
- features.push("Monorepo");
590
- if (features.length > 0) {
591
- console.log(` ${isZh ? "\u7279\u6027" : "Features"}: ${ansis.green(features.join(", "))}`);
592
- }
593
- console.log(ansis.dim("\u2500".repeat(50)));
594
- console.log("");
595
- }
596
- function displayContextFile(file, lang) {
597
- const isZh = lang === "zh-CN";
598
- const typeLabel = getContextFileTypeLabel(file.type, lang);
599
- const statusIcon = file.exists ? ansis.green("\u2713") : ansis.dim("\u25CB");
600
- console.log(` ${statusIcon} ${ansis.bold(typeLabel)}`);
601
- console.log(` ${ansis.dim(file.path)}`);
602
- if (file.exists && file.size !== void 0) {
603
- const sizeStr = formatFileSize(file.size);
604
- const dateStr = file.lastModified ? file.lastModified.toLocaleDateString() : isZh ? "\u672A\u77E5" : "Unknown";
605
- console.log(` ${ansis.dim(`${sizeStr} | ${isZh ? "\u4FEE\u6539\u4E8E" : "Modified"}: ${dateStr}`)}`);
606
- } else if (!file.exists) {
607
- console.log(` ${ansis.dim(isZh ? "(\u4E0D\u5B58\u5728)" : "(not exists)")}`);
608
- }
609
- }
610
- async function viewContextFiles(lang) {
611
- const isZh = lang === "zh-CN";
612
- const files = getContextFiles();
613
- console.log(ansis.green.bold(`
614
- \u{1F4C1} ${isZh ? "\u4E0A\u4E0B\u6587\u6587\u4EF6" : "Context Files"}
615
- `));
616
- for (const file of files) {
617
- displayContextFile(file, lang);
618
- console.log("");
619
- }
620
- const existingFiles = files.filter((f) => f.exists);
621
- if (existingFiles.length > 0) {
622
- const { viewFile } = await inquirer.prompt([
623
- {
624
- type: "list",
625
- name: "viewFile",
626
- message: isZh ? "\u67E5\u770B\u6587\u4EF6\u5185\u5BB9\uFF1F" : "View file content?",
627
- choices: [
628
- ...existingFiles.map((f) => ({
629
- name: `${getContextFileTypeLabel(f.type, lang)} - ${f.path}`,
630
- value: f.path
631
- })),
632
- {
633
- name: isZh ? "\u8DF3\u8FC7" : "Skip",
634
- value: "skip"
635
- }
636
- ]
637
- }
638
- ]);
639
- if (viewFile !== "skip") {
640
- const content = readContextFile(viewFile);
641
- if (content) {
642
- console.log(ansis.dim(`
643
- ${"\u2500".repeat(50)}`));
644
- console.log(content);
645
- console.log(ansis.dim(`${"\u2500".repeat(50)}
646
- `));
647
- } else {
648
- console.log(ansis.yellow(isZh ? "\u65E0\u6CD5\u8BFB\u53D6\u6587\u4EF6\u5185\u5BB9" : "Unable to read file content"));
649
- }
650
- }
651
- }
652
- }
653
- async function generateContextRules(context, lang) {
654
- const isZh = lang === "zh-CN";
655
- console.log(ansis.green.bold(`
656
- \u2728 ${isZh ? "\u81EA\u52A8\u751F\u6210\u89C4\u5219" : "Auto-generate Rules"}
657
- `));
658
- const recommendedIds = getRecommendedRules(context);
659
- const applicableRules = getApplicableRules(context.type);
660
- const { selectedRules } = await inquirer.prompt([
661
- {
662
- type: "checkbox",
663
- name: "selectedRules",
664
- message: isZh ? "\u9009\u62E9\u8981\u5E94\u7528\u7684\u89C4\u5219\uFF08\u63A8\u8350\u89C4\u5219\u5DF2\u9884\u9009\uFF09" : "Select rules to apply (recommended rules pre-selected)",
665
- choices: applicableRules.map((rule) => ({
666
- name: `${recommendedIds.includes(rule.id) ? ansis.green("\u2605") : " "} ${isZh ? rule.nameZh : rule.name} - ${ansis.dim(isZh ? rule.descriptionZh : rule.description)}`,
667
- value: rule.id,
668
- checked: recommendedIds.includes(rule.id)
669
- }))
670
- }
671
- ]);
672
- if (selectedRules.length === 0) {
673
- console.log(ansis.yellow(isZh ? "\u672A\u9009\u62E9\u4EFB\u4F55\u89C4\u5219" : "No rules selected"));
674
- return;
675
- }
676
- const { location } = await inquirer.prompt([
677
- {
678
- type: "list",
679
- name: "location",
680
- message: isZh ? "\u4FDD\u5B58\u4F4D\u7F6E" : "Save location",
681
- choices: [
682
- {
683
- name: `${isZh ? "\u9879\u76EE\u6839\u76EE\u5F55" : "Project root"} (CLAUDE.md)`,
684
- value: "project"
685
- },
686
- {
687
- name: `${isZh ? "\u672C\u5730\u76EE\u5F55" : "Local directory"} (.claude/CLAUDE.md)`,
688
- value: "local"
689
- },
690
- {
691
- name: `${isZh ? "\u5168\u5C40\u76EE\u5F55" : "Global directory"} (~/.claude/CLAUDE.md)`,
692
- value: "global"
693
- }
694
- ],
695
- default: "project"
696
- }
697
- ]);
698
- const files = getContextFiles();
699
- const targetFile = files.find((f) => f.type === location);
700
- if (!targetFile) {
701
- console.log(ansis.red(isZh ? "\u65E0\u6CD5\u786E\u5B9A\u76EE\u6807\u8DEF\u5F84" : "Unable to determine target path"));
702
- return;
703
- }
704
- if (targetFile.exists) {
705
- const { overwrite } = await inquirer.prompt([
706
- {
707
- type: "list",
708
- name: "overwrite",
709
- message: isZh ? "\u6587\u4EF6\u5DF2\u5B58\u5728\uFF0C\u5982\u4F55\u5904\u7406\uFF1F" : "File exists, how to proceed?",
710
- choices: [
711
- {
712
- name: isZh ? "\u5408\u5E76\uFF08\u6DFB\u52A0\u65B0\u89C4\u5219\uFF09" : "Merge (add new rules)",
713
- value: "merge"
714
- },
715
- {
716
- name: isZh ? "\u8986\u76D6" : "Overwrite",
717
- value: "overwrite"
718
- },
719
- {
720
- name: isZh ? "\u53D6\u6D88" : "Cancel",
721
- value: "cancel"
722
- }
723
- ]
724
- }
725
- ]);
726
- if (overwrite === "cancel") {
727
- return;
728
- }
729
- if (overwrite === "merge") {
730
- const existingContent = readContextFile(targetFile.path);
731
- if (existingContent) {
732
- const mergedContent = mergeContextContent(existingContent, selectedRules, lang);
733
- const success2 = await writeContextFile(targetFile.path, mergedContent);
734
- if (success2) {
735
- console.log(ansis.green(`
736
- \u2705 ${isZh ? "\u89C4\u5219\u5DF2\u5408\u5E76\u5230" : "Rules merged to"}: ${targetFile.path}`));
737
- } else {
738
- console.log(ansis.red(`
739
- \u274C ${isZh ? "\u5199\u5165\u5931\u8D25" : "Write failed"}`));
740
- }
741
- return;
742
- }
743
- }
744
- }
745
- const content = generateContextContent(context, selectedRules, lang);
746
- const success = await writeContextFile(targetFile.path, content);
747
- if (success) {
748
- console.log(ansis.green(`
749
- \u2705 ${isZh ? "\u5DF2\u751F\u6210" : "Generated"}: ${targetFile.path}`));
750
- } else {
751
- console.log(ansis.red(`
752
- \u274C ${isZh ? "\u5199\u5165\u5931\u8D25" : "Write failed"}`));
753
- }
754
- }
755
- async function addRulesToContext(context, lang) {
756
- const isZh = lang === "zh-CN";
757
- console.log(ansis.green.bold(`
758
- \u{1F4DD} ${isZh ? "\u6DFB\u52A0\u89C4\u5219" : "Add Rules"}
759
- `));
760
- const applicableRules = getApplicableRules(context.type);
761
- const { selectedRules } = await inquirer.prompt([
762
- {
763
- type: "checkbox",
764
- name: "selectedRules",
765
- message: isZh ? "\u9009\u62E9\u8981\u6DFB\u52A0\u7684\u89C4\u5219" : "Select rules to add",
766
- choices: applicableRules.map((rule) => ({
767
- name: `${isZh ? rule.nameZh : rule.name} - ${ansis.dim(isZh ? rule.descriptionZh : rule.description)}`,
768
- value: rule.id
769
- }))
770
- }
771
- ]);
772
- if (selectedRules.length === 0) {
773
- console.log(ansis.yellow(isZh ? "\u672A\u9009\u62E9\u4EFB\u4F55\u89C4\u5219" : "No rules selected"));
774
- return;
775
- }
776
- const files = getContextFiles();
777
- const existingFiles = files.filter((f) => f.exists);
778
- let targetPath;
779
- if (existingFiles.length > 0) {
780
- const { target } = await inquirer.prompt([
781
- {
782
- type: "list",
783
- name: "target",
784
- message: isZh ? "\u6DFB\u52A0\u5230\u54EA\u4E2A\u6587\u4EF6\uFF1F" : "Add to which file?",
785
- choices: [
786
- ...existingFiles.map((f) => ({
787
- name: `${getContextFileTypeLabel(f.type, lang)} - ${f.path}`,
788
- value: f.path
789
- })),
790
- {
791
- name: isZh ? "\u521B\u5EFA\u65B0\u6587\u4EF6" : "Create new file",
792
- value: "new"
793
- }
794
- ]
795
- }
796
- ]);
797
- if (target === "new") {
798
- const { location } = await inquirer.prompt([
799
- {
800
- type: "list",
801
- name: "location",
802
- message: isZh ? "\u4FDD\u5B58\u4F4D\u7F6E" : "Save location",
803
- choices: [
804
- { name: `${isZh ? "\u9879\u76EE\u6839\u76EE\u5F55" : "Project root"} (CLAUDE.md)`, value: "project" },
805
- { name: `${isZh ? "\u672C\u5730\u76EE\u5F55" : "Local directory"} (.claude/CLAUDE.md)`, value: "local" },
806
- { name: `${isZh ? "\u5168\u5C40\u76EE\u5F55" : "Global directory"} (~/.claude/CLAUDE.md)`, value: "global" }
807
- ]
808
- }
809
- ]);
810
- targetPath = files.find((f) => f.type === location)?.path || "";
811
- } else {
812
- targetPath = target;
813
- }
814
- } else {
815
- const { location } = await inquirer.prompt([
816
- {
817
- type: "list",
818
- name: "location",
819
- message: isZh ? "\u4FDD\u5B58\u4F4D\u7F6E" : "Save location",
820
- choices: [
821
- { name: `${isZh ? "\u9879\u76EE\u6839\u76EE\u5F55" : "Project root"} (CLAUDE.md)`, value: "project" },
822
- { name: `${isZh ? "\u672C\u5730\u76EE\u5F55" : "Local directory"} (.claude/CLAUDE.md)`, value: "local" },
823
- { name: `${isZh ? "\u5168\u5C40\u76EE\u5F55" : "Global directory"} (~/.claude/CLAUDE.md)`, value: "global" }
824
- ]
825
- }
826
- ]);
827
- targetPath = files.find((f) => f.type === location)?.path || "";
828
- }
829
- if (!targetPath) {
830
- console.log(ansis.red(isZh ? "\u65E0\u6CD5\u786E\u5B9A\u76EE\u6807\u8DEF\u5F84" : "Unable to determine target path"));
831
- return;
832
- }
833
- const existingContent = readContextFile(targetPath);
834
- let finalContent;
835
- if (existingContent) {
836
- finalContent = mergeContextContent(existingContent, selectedRules, lang);
837
- } else {
838
- finalContent = generateContextContent(context, selectedRules, lang);
839
- }
840
- const success = await writeContextFile(targetPath, finalContent);
841
- if (success) {
842
- console.log(ansis.green(`
843
- \u2705 ${isZh ? "\u89C4\u5219\u5DF2\u6DFB\u52A0\u5230" : "Rules added to"}: ${targetPath}`));
844
- } else {
845
- console.log(ansis.red(`
846
- \u274C ${isZh ? "\u5199\u5165\u5931\u8D25" : "Write failed"}`));
847
- }
848
- }
849
- async function browseRules(context, lang) {
850
- const isZh = lang === "zh-CN";
851
- console.log(ansis.green.bold(`
852
- \u{1F4D6} ${isZh ? "\u53EF\u7528\u89C4\u5219" : "Available Rules"}
853
- `));
854
- const applicableRules = getApplicableRules(context.type);
855
- const categories = {};
856
- for (const rule of applicableRules) {
857
- if (!categories[rule.category]) {
858
- categories[rule.category] = [];
859
- }
860
- categories[rule.category].push(rule);
861
- }
862
- const categoryLabels = {
863
- coding: { en: "Coding Style", zh: "\u7F16\u7801\u98CE\u683C" },
864
- testing: { en: "Testing", zh: "\u6D4B\u8BD5" },
865
- docs: { en: "Documentation", zh: "\u6587\u6863" },
866
- workflow: { en: "Workflow", zh: "\u5DE5\u4F5C\u6D41" },
867
- security: { en: "Security", zh: "\u5B89\u5168" }
868
- };
869
- for (const [category, rules] of Object.entries(categories)) {
870
- const label = isZh ? categoryLabels[category]?.zh : categoryLabels[category]?.en;
871
- console.log(ansis.bold(`
872
- ${label || category}:`));
873
- for (const rule of rules) {
874
- const name = isZh ? rule.nameZh : rule.name;
875
- const desc = isZh ? rule.descriptionZh : rule.description;
876
- console.log(` ${ansis.green("\u2022")} ${ansis.bold(name)}`);
877
- console.log(` ${ansis.dim(desc)}`);
878
- }
879
- }
880
- console.log("");
881
- const { viewRule } = await inquirer.prompt([
882
- {
883
- type: "list",
884
- name: "viewRule",
885
- message: isZh ? "\u67E5\u770B\u89C4\u5219\u8BE6\u60C5\uFF1F" : "View rule details?",
886
- choices: [
887
- ...applicableRules.map((r) => ({
888
- name: isZh ? r.nameZh : r.name,
889
- value: r.id
890
- })),
891
- {
892
- name: isZh ? "\u8DF3\u8FC7" : "Skip",
893
- value: "skip"
894
- }
895
- ]
896
- }
897
- ]);
898
- if (viewRule !== "skip") {
899
- const rule = applicableRules.find((r) => r.id === viewRule);
900
- if (rule) {
901
- console.log(ansis.dim(`
902
- ${"\u2500".repeat(50)}`));
903
- console.log(ansis.bold(isZh ? rule.nameZh : rule.name));
904
- console.log(ansis.dim(isZh ? rule.descriptionZh : rule.description));
905
- console.log("");
906
- console.log(isZh ? rule.contentZh : rule.content);
907
- console.log(ansis.dim(`${"\u2500".repeat(50)}
908
- `));
909
- }
910
- }
911
- }
912
-
913
- export { showContextMenu };