claude-tidy 0.1.6

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 (43) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +39 -0
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -0
  5. package/dist/cli.js +80 -0
  6. package/dist/cli.js.map +1 -0
  7. package/dist/flows/delete.d.ts +5 -0
  8. package/dist/flows/delete.d.ts.map +1 -0
  9. package/dist/flows/delete.js +91 -0
  10. package/dist/flows/delete.js.map +1 -0
  11. package/dist/flows/diff.d.ts +6 -0
  12. package/dist/flows/diff.d.ts.map +1 -0
  13. package/dist/flows/diff.js +138 -0
  14. package/dist/flows/diff.js.map +1 -0
  15. package/dist/flows/list.d.ts +2 -0
  16. package/dist/flows/list.d.ts.map +1 -0
  17. package/dist/flows/list.js +83 -0
  18. package/dist/flows/list.js.map +1 -0
  19. package/dist/flows/move.d.ts +5 -0
  20. package/dist/flows/move.d.ts.map +1 -0
  21. package/dist/flows/move.js +157 -0
  22. package/dist/flows/move.js.map +1 -0
  23. package/dist/types.d.ts +53 -0
  24. package/dist/types.d.ts.map +1 -0
  25. package/dist/types.js +2 -0
  26. package/dist/types.js.map +1 -0
  27. package/dist/utils/display.d.ts +18 -0
  28. package/dist/utils/display.d.ts.map +1 -0
  29. package/dist/utils/display.js +110 -0
  30. package/dist/utils/display.js.map +1 -0
  31. package/dist/utils/parser.d.ts +11 -0
  32. package/dist/utils/parser.d.ts.map +1 -0
  33. package/dist/utils/parser.js +47 -0
  34. package/dist/utils/parser.js.map +1 -0
  35. package/dist/utils/paths.d.ts +14 -0
  36. package/dist/utils/paths.d.ts.map +1 -0
  37. package/dist/utils/paths.js +27 -0
  38. package/dist/utils/paths.js.map +1 -0
  39. package/dist/utils/scanner.d.ts +16 -0
  40. package/dist/utils/scanner.d.ts.map +1 -0
  41. package/dist/utils/scanner.js +119 -0
  42. package/dist/utils/scanner.js.map +1 -0
  43. package/package.json +43 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Line
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # claude-tidy
2
+
3
+ Claude Code 的 skills 和 rules 管理工具。查看、比对、移动、删除,一个命令搞定。
4
+
5
+ ## 使用
6
+
7
+ ```bash
8
+ npx claude-tidy
9
+ ```
10
+
11
+ 纯交互式,运行后按提示操作:
12
+
13
+ 1. 选择管理对象:skills / rules
14
+ 2. 选择操作:list / diff / move / delete
15
+ 3. 跟随交互引导完成(多选列表按 `a` 全选)
16
+
17
+ ```bash
18
+ claude-tidy --help # 帮助信息
19
+ claude-tidy --version # 版本号
20
+ ```
21
+
22
+ ## 功能
23
+
24
+ | 操作 | 说明 |
25
+ |------|------|
26
+ | **list** | 查看 rules/skills,支持全局/项目/全部,全部时分开展示 |
27
+ | **diff** | 对比全局和项目的同名 rules/skills,标注最新版本,选择保留哪个 |
28
+ | **move** | 在全局和项目之间移动 rules/skills,symlink 保持链接方式 |
29
+ | **delete** | 删除 rules(直接删除)或 skills(确认后整目录删除) |
30
+
31
+ ## 特性
32
+
33
+ - 支持 symlink(软链接)skills,list 标注 `[链接]`,move 保持链接
34
+ - 时间比较取创建时间和修改时间中较晚的,解决复制文件时间不准的问题
35
+ - 日期精确到秒
36
+
37
+ ## 许可证
38
+
39
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,80 @@
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { select } from '@inquirer/prompts';
6
+ import chalk from 'chalk';
7
+ import { listFlow } from './flows/list.js';
8
+ import { diffFlow } from './flows/diff.js';
9
+ import { moveFlow } from './flows/move.js';
10
+ import { deleteFlow } from './flows/delete.js';
11
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
+ /** 从 package.json 读取版本号 */
13
+ function getVersion() {
14
+ const pkgPath = path.resolve(__dirname, '..', 'package.json');
15
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
16
+ return pkg.version;
17
+ }
18
+ const HELP_TEXT = `
19
+ claude-tidy — Claude Code 的 skills 和 rules 管理工具
20
+
21
+ 用法:
22
+ claude-tidy 进入交互式管理流程
23
+ claude-tidy --help 显示帮助信息
24
+ claude-tidy --version 显示版本号
25
+ `;
26
+ async function main() {
27
+ const args = process.argv.slice(2);
28
+ if (args.includes('--help') || args.includes('-h')) {
29
+ console.log(HELP_TEXT.trim());
30
+ return;
31
+ }
32
+ if (args.includes('--version') || args.includes('-v')) {
33
+ console.log(getVersion());
34
+ return;
35
+ }
36
+ if (args.length > 0) {
37
+ console.log(HELP_TEXT.trim());
38
+ return;
39
+ }
40
+ console.log(`
41
+ ${chalk.bold.cyan('claude-tidy')} ${chalk.dim('v' + getVersion())}
42
+ ${chalk.dim('Claude Code skills & rules 管理工具')}
43
+ `);
44
+ const target = await select({
45
+ message: '管理什么?',
46
+ choices: [
47
+ { value: 'skills', name: 'skills' },
48
+ { value: 'rules', name: 'rules' },
49
+ ],
50
+ });
51
+ const action = await select({
52
+ message: '要做什么?',
53
+ choices: [
54
+ { value: 'list', name: 'list — 查看' },
55
+ { value: 'diff', name: 'diff — 比对差异' },
56
+ { value: 'move', name: 'move — 移动' },
57
+ { value: 'delete', name: 'delete — 删除' },
58
+ ],
59
+ });
60
+ switch (action) {
61
+ case 'list':
62
+ await listFlow(target);
63
+ break;
64
+ case 'diff':
65
+ await diffFlow(target);
66
+ break;
67
+ case 'move':
68
+ await moveFlow(target);
69
+ break;
70
+ case 'delete':
71
+ await deleteFlow(target);
72
+ break;
73
+ }
74
+ console.log(chalk.green('\n 完成\n'));
75
+ }
76
+ main().catch((error) => {
77
+ console.error('执行出错:', error instanceof Error ? error.message : error);
78
+ process.exit(1);
79
+ });
80
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * delete 交互流程(多选,a 键全选)
3
+ */
4
+ export declare function deleteFlow(target: string): Promise<void>;
5
+ //# sourceMappingURL=delete.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.d.ts","sourceRoot":"","sources":["../../src/flows/delete.ts"],"names":[],"mappings":"AAOA;;GAEG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM9D"}
@@ -0,0 +1,91 @@
1
+ import fs from 'node:fs';
2
+ import { select, checkbox, confirm } from '@inquirer/prompts';
3
+ import chalk from 'chalk';
4
+ import { getGlobalRulesDir, getProjectRulesDir, getGlobalSkillsDir, getProjectSkillsDir } from '../utils/paths.js';
5
+ import { scanRules, scanSkills } from '../utils/scanner.js';
6
+ import { formatDate } from '../utils/display.js';
7
+ /**
8
+ * delete 交互流程(多选,a 键全选)
9
+ */
10
+ export async function deleteFlow(target) {
11
+ if (target === 'rules') {
12
+ await deleteRulesFlow();
13
+ }
14
+ else {
15
+ await deleteSkillsFlow();
16
+ }
17
+ }
18
+ async function deleteRulesFlow() {
19
+ const scope = await select({
20
+ message: '从哪里删除?',
21
+ choices: [
22
+ { value: 'global', name: '全局' },
23
+ { value: 'project', name: '项目' },
24
+ ],
25
+ });
26
+ const rulesDir = scope === 'global' ? getGlobalRulesDir() : getProjectRulesDir();
27
+ const rules = scanRules(rulesDir, scope);
28
+ if (rules.length === 0) {
29
+ console.log(chalk.dim(` ${scope === 'global' ? '全局' : '项目'}中没有 rules`));
30
+ return;
31
+ }
32
+ const selected = await checkbox({
33
+ message: '选择要删除的 rules(a 全选,空格选择,回车确认):',
34
+ choices: rules
35
+ .sort((a, b) => a.id.localeCompare(b.id))
36
+ .map((rule) => ({
37
+ value: rule.absolutePath,
38
+ name: `${rule.id} ${chalk.dim(formatDate(rule.mtime))}`,
39
+ })),
40
+ });
41
+ if (selected.length === 0)
42
+ return;
43
+ for (const filePath of selected) {
44
+ fs.unlinkSync(filePath);
45
+ }
46
+ console.log(chalk.green(` ✓ 已删除 ${selected.length} 条 rules`));
47
+ }
48
+ async function deleteSkillsFlow() {
49
+ const scope = await select({
50
+ message: '从哪里删除?',
51
+ choices: [
52
+ { value: 'global', name: '全局' },
53
+ { value: 'project', name: '项目' },
54
+ ],
55
+ });
56
+ const skillsDir = scope === 'global' ? getGlobalSkillsDir() : getProjectSkillsDir();
57
+ const skills = scanSkills(skillsDir, scope);
58
+ if (skills.length === 0) {
59
+ console.log(chalk.dim(` ${scope === 'global' ? '全局' : '项目'}中没有 skills`));
60
+ return;
61
+ }
62
+ const selected = await checkbox({
63
+ message: '选择要删除的 skills(a 全选,空格选择,回车确认):',
64
+ choices: skills
65
+ .sort((a, b) => a.name.localeCompare(b.name))
66
+ .map((skill) => ({
67
+ value: skill.absolutePath,
68
+ name: `${skill.name} ${chalk.dim(`${skill.fileCount} 个文件`)}`,
69
+ })),
70
+ });
71
+ if (selected.length === 0)
72
+ return;
73
+ const selectedSkills = selected.map((sp) => skills.find((s) => s.absolutePath === sp));
74
+ console.log(chalk.yellow('\n 将删除以下 skills:'));
75
+ for (const skill of selectedSkills) {
76
+ console.log(` ${chalk.bold(skill.name)} ${chalk.dim(skill.absolutePath)} (${skill.fileCount} 个文件)`);
77
+ }
78
+ const confirmed = await confirm({
79
+ message: `确认删除 ${selectedSkills.length} 个 skills?`,
80
+ default: false,
81
+ });
82
+ if (!confirmed) {
83
+ console.log(chalk.dim(' 已取消'));
84
+ return;
85
+ }
86
+ for (const skillPath of selected) {
87
+ fs.rmSync(skillPath, { recursive: true, force: true });
88
+ }
89
+ console.log(chalk.green(` ✓ 已删除 ${selected.length} 个 skills`));
90
+ }
91
+ //# sourceMappingURL=delete.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"delete.js","sourceRoot":"","sources":["../../src/flows/delete.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * diff 交互流程
3
+ * 多选要处理的(a 键全选)→ 逐个选保留哪个
4
+ */
5
+ export declare function diffFlow(target: string): Promise<void>;
6
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/flows/diff.ts"],"names":[],"mappings":"AAcA;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM5D"}
@@ -0,0 +1,138 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { select, checkbox } from '@inquirer/prompts';
4
+ import chalk from 'chalk';
5
+ import { getGlobalRulesDir, getProjectRulesDir, getGlobalSkillsDir, getProjectSkillsDir, } from '../utils/paths.js';
6
+ import { scanRules, scanSkills, getLatestTime } from '../utils/scanner.js';
7
+ import { formatDate } from '../utils/display.js';
8
+ /**
9
+ * diff 交互流程
10
+ * 多选要处理的(a 键全选)→ 逐个选保留哪个
11
+ */
12
+ export async function diffFlow(target) {
13
+ if (target === 'rules') {
14
+ await diffRulesFlow();
15
+ }
16
+ else {
17
+ await diffSkillsFlow();
18
+ }
19
+ }
20
+ // ─── Rules diff ───
21
+ async function diffRulesFlow() {
22
+ const globalRules = scanRules(getGlobalRulesDir(), 'global');
23
+ const projectRules = scanRules(getProjectRulesDir(), 'project');
24
+ const globalMap = new Map(globalRules.map((r) => [r.id, r]));
25
+ const projectMap = new Map(projectRules.map((r) => [r.id, r]));
26
+ const duplicates = [];
27
+ for (const [id, globalRule] of globalMap) {
28
+ const projectRule = projectMap.get(id);
29
+ if (projectRule) {
30
+ duplicates.push({ id, global: globalRule, project: projectRule });
31
+ }
32
+ }
33
+ if (duplicates.length === 0) {
34
+ console.log(chalk.dim(' 全局和项目没有同名 rules'));
35
+ return;
36
+ }
37
+ console.log(chalk.bold(`\n 发现 ${duplicates.length} 条同名 rules\n`));
38
+ const selected = await checkbox({
39
+ message: '选择要处理的 rules(a 全选,空格选择,回车确认):',
40
+ choices: duplicates.map(({ id, global: globalRule, project: projectRule }) => {
41
+ const globalNewer = globalRule.mtime.getTime() > projectRule.mtime.getTime();
42
+ const projectNewer = projectRule.mtime.getTime() > globalRule.mtime.getTime();
43
+ const hint = globalNewer ? ' (全局最新)' : projectNewer ? ' (项目最新)' : '';
44
+ return { value: id, name: `${id}${chalk.dim(hint)}` };
45
+ }),
46
+ });
47
+ if (selected.length === 0)
48
+ return;
49
+ for (const id of selected) {
50
+ const dup = duplicates.find((d) => d.id === id);
51
+ const globalNewer = dup.global.mtime.getTime() > dup.project.mtime.getTime();
52
+ const projectNewer = dup.project.mtime.getTime() > dup.global.mtime.getTime();
53
+ const choice = await select({
54
+ message: `${id} — 保留哪个?`,
55
+ choices: [
56
+ {
57
+ value: 'global',
58
+ name: `全局 (${formatDate(dup.global.mtime)})${globalNewer ? ' ← 最新' : ''}`,
59
+ },
60
+ {
61
+ value: 'project',
62
+ name: `项目 (${formatDate(dup.project.mtime)})${projectNewer ? ' ← 最新' : ''}`,
63
+ },
64
+ { value: 'skip', name: '跳过' },
65
+ ],
66
+ });
67
+ if (choice === 'global') {
68
+ fs.unlinkSync(dup.project.absolutePath);
69
+ console.log(chalk.green(` ✓ ${id} → 已删除项目版本`));
70
+ }
71
+ else if (choice === 'project') {
72
+ fs.unlinkSync(dup.global.absolutePath);
73
+ console.log(chalk.green(` ✓ ${id} → 已删除全局版本`));
74
+ }
75
+ }
76
+ }
77
+ // ─── Skills diff ───
78
+ async function diffSkillsFlow() {
79
+ const globalSkills = scanSkills(getGlobalSkillsDir(), 'global');
80
+ const projectSkills = scanSkills(getProjectSkillsDir(), 'project');
81
+ const globalMap = new Map(globalSkills.map((s) => [s.name, s]));
82
+ const projectMap = new Map(projectSkills.map((s) => [s.name, s]));
83
+ const duplicates = [];
84
+ for (const [name, globalSkill] of globalMap) {
85
+ const projectSkill = projectMap.get(name);
86
+ if (projectSkill) {
87
+ duplicates.push({ name, global: globalSkill, project: projectSkill });
88
+ }
89
+ }
90
+ if (duplicates.length === 0) {
91
+ console.log(chalk.dim(' 全局和项目没有同名 skills'));
92
+ return;
93
+ }
94
+ console.log(chalk.bold(`\n 发现 ${duplicates.length} 个同名 skills\n`));
95
+ const selected = await checkbox({
96
+ message: '选择要处理的 skills(a 全选,空格选择,回车确认):',
97
+ choices: duplicates.map(({ name, global: globalSkill, project: projectSkill }) => {
98
+ const globalMtime = getLatestTime(path.join(globalSkill.absolutePath, 'SKILL.md'));
99
+ const projectMtime = getLatestTime(path.join(projectSkill.absolutePath, 'SKILL.md'));
100
+ const globalNewer = globalMtime.getTime() > projectMtime.getTime();
101
+ const projectNewer = projectMtime.getTime() > globalMtime.getTime();
102
+ const hint = globalNewer ? ' (全局最新)' : projectNewer ? ' (项目最新)' : '';
103
+ return { value: name, name: `${name}${chalk.dim(hint)}` };
104
+ }),
105
+ });
106
+ if (selected.length === 0)
107
+ return;
108
+ for (const name of selected) {
109
+ const dup = duplicates.find((d) => d.name === name);
110
+ const globalMtime = getLatestTime(path.join(dup.global.absolutePath, 'SKILL.md'));
111
+ const projectMtime = getLatestTime(path.join(dup.project.absolutePath, 'SKILL.md'));
112
+ const globalNewer = globalMtime.getTime() > projectMtime.getTime();
113
+ const projectNewer = projectMtime.getTime() > globalMtime.getTime();
114
+ const choice = await select({
115
+ message: `${name} — 保留哪个?`,
116
+ choices: [
117
+ {
118
+ value: 'global',
119
+ name: `全局 (${formatDate(globalMtime)})${globalNewer ? ' ← 最新' : ''}`,
120
+ },
121
+ {
122
+ value: 'project',
123
+ name: `项目 (${formatDate(projectMtime)})${projectNewer ? ' ← 最新' : ''}`,
124
+ },
125
+ { value: 'skip', name: '跳过' },
126
+ ],
127
+ });
128
+ if (choice === 'global') {
129
+ fs.rmSync(dup.project.absolutePath, { recursive: true, force: true });
130
+ console.log(chalk.green(` ✓ ${name} → 已删除项目版本`));
131
+ }
132
+ else if (choice === 'project') {
133
+ fs.rmSync(dup.global.absolutePath, { recursive: true, force: true });
134
+ console.log(chalk.green(` ✓ ${name} → 已删除全局版本`));
135
+ }
136
+ }
137
+ }
138
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/flows/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function listFlow(target: string): Promise<void>;
2
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/flows/list.ts"],"names":[],"mappings":"AAMA,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM5D"}
@@ -0,0 +1,83 @@
1
+ import { select } from '@inquirer/prompts';
2
+ import { getGlobalRulesDir, getProjectRulesDir, getGlobalSkillsDir, getProjectSkillsDir } from '../utils/paths.js';
3
+ import { scanRules, scanSkills } from '../utils/scanner.js';
4
+ import { printRules, printSkills } from '../utils/display.js';
5
+ export async function listFlow(target) {
6
+ if (target === 'rules') {
7
+ await listRulesFlow();
8
+ }
9
+ else {
10
+ await listSkillsFlow();
11
+ }
12
+ }
13
+ async function listRulesFlow() {
14
+ const scope = await select({
15
+ message: '查看哪些 rules?',
16
+ choices: [
17
+ { value: 'all', name: '全部' },
18
+ { value: 'global', name: '全局' },
19
+ { value: 'project', name: '项目' },
20
+ ],
21
+ });
22
+ let rules = [];
23
+ if (scope === 'global') {
24
+ rules = scanRules(getGlobalRulesDir(), 'global');
25
+ rules.sort((a, b) => a.id.localeCompare(b.id));
26
+ console.log();
27
+ printRules(rules, false);
28
+ }
29
+ else if (scope === 'project') {
30
+ rules = scanRules(getProjectRulesDir(), 'project');
31
+ rules.sort((a, b) => a.id.localeCompare(b.id));
32
+ console.log();
33
+ printRules(rules, false);
34
+ }
35
+ else {
36
+ const globalRules = scanRules(getGlobalRulesDir(), 'global');
37
+ const projectRules = scanRules(getProjectRulesDir(), 'project');
38
+ globalRules.sort((a, b) => a.id.localeCompare(b.id));
39
+ projectRules.sort((a, b) => a.id.localeCompare(b.id));
40
+ console.log();
41
+ console.log(' 全局 rules');
42
+ printRules(globalRules, false);
43
+ console.log();
44
+ console.log(' 项目 rules');
45
+ printRules(projectRules, false);
46
+ }
47
+ }
48
+ async function listSkillsFlow() {
49
+ const scope = await select({
50
+ message: '查看哪些 skills?',
51
+ choices: [
52
+ { value: 'all', name: '全部' },
53
+ { value: 'global', name: '全局' },
54
+ { value: 'project', name: '项目' },
55
+ ],
56
+ });
57
+ let skills = [];
58
+ if (scope === 'global') {
59
+ skills = scanSkills(getGlobalSkillsDir(), 'global');
60
+ skills.sort((a, b) => a.name.localeCompare(b.name));
61
+ console.log();
62
+ printSkills(skills, false);
63
+ }
64
+ else if (scope === 'project') {
65
+ skills = scanSkills(getProjectSkillsDir(), 'project');
66
+ skills.sort((a, b) => a.name.localeCompare(b.name));
67
+ console.log();
68
+ printSkills(skills, false);
69
+ }
70
+ else {
71
+ const globalSkills = scanSkills(getGlobalSkillsDir(), 'global');
72
+ const projectSkills = scanSkills(getProjectSkillsDir(), 'project');
73
+ globalSkills.sort((a, b) => a.name.localeCompare(b.name));
74
+ projectSkills.sort((a, b) => a.name.localeCompare(b.name));
75
+ console.log();
76
+ console.log(' 全局 skills');
77
+ printSkills(globalSkills, false);
78
+ console.log();
79
+ console.log(' 项目 skills');
80
+ printSkills(projectSkills, false);
81
+ }
82
+ }
83
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/flows/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACnH,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAG9D,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAc;IAC3C,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,MAAM,aAAa,EAAE,CAAC;IACxB,CAAC;SAAM,CAAC;QACN,MAAM,cAAc,EAAE,CAAC;IACzB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,aAAa;IAC1B,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC;QACzB,OAAO,EAAE,aAAa;QACtB,OAAO,EAAE;YACP,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE;YAC5B,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE;YAC/B,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE;SACjC;KACF,CAAC,CAAC;IAEH,IAAI,KAAK,GAAW,EAAE,CAAC;IAEvB,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvB,KAAK,GAAG,SAAS,CAAC,iBAAiB,EAAE,EAAE,QAAQ,CAAC,CAAC;QACjD,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC;SAAM,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,KAAK,GAAG,SAAS,CAAC,kBAAkB,EAAE,EAAE,SAAS,CAAC,CAAC;QACnD,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/C,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC;SAAM,CAAC;QACN,MAAM,WAAW,GAAG,SAAS,CAAC,iBAAiB,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC7D,MAAM,YAAY,GAAG,SAAS,CAAC,kBAAkB,EAAE,EAAE,SAAS,CAAC,CAAC;QAChE,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACrD,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACtD,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAC1B,UAAU,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;QAC/B,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;QAC1B,UAAU,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IAClC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,cAAc;IAC3B,MAAM,KAAK,GAAG,MAAM,MAAM,CAAC;QACzB,OAAO,EAAE,cAAc;QACvB,OAAO,EAAE;YACP,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE;YAC5B,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE;YAC/B,EAAE,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE;SACjC;KACF,CAAC,CAAC;IAEH,IAAI,MAAM,GAAY,EAAE,CAAC;IAEzB,IAAI,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvB,MAAM,GAAG,UAAU,CAAC,kBAAkB,EAAE,EAAE,QAAQ,CAAC,CAAC;QACpD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;SAAM,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,GAAG,UAAU,CAAC,mBAAmB,EAAE,EAAE,SAAS,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACpD,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;SAAM,CAAC;QACN,MAAM,YAAY,GAAG,UAAU,CAAC,kBAAkB,EAAE,EAAE,QAAQ,CAAC,CAAC;QAChE,MAAM,aAAa,GAAG,UAAU,CAAC,mBAAmB,EAAE,EAAE,SAAS,CAAC,CAAC;QACnE,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1D,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAC3B,WAAW,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC;QACjC,OAAO,CAAC,GAAG,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;QAC3B,WAAW,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;IACpC,CAAC;AACH,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * move 交互流程(多选,a 键全选)
3
+ */
4
+ export declare function moveFlow(target: string): Promise<void>;
5
+ //# sourceMappingURL=move.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"move.d.ts","sourceRoot":"","sources":["../../src/flows/move.ts"],"names":[],"mappings":"AAQA;;GAEG;AACH,wBAAsB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM5D"}
@@ -0,0 +1,157 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { select, checkbox, confirm } from '@inquirer/prompts';
4
+ import chalk from 'chalk';
5
+ import { getGlobalRulesDir, getProjectRulesDir, getGlobalSkillsDir, getProjectSkillsDir } from '../utils/paths.js';
6
+ import { scanRules, scanSkills } from '../utils/scanner.js';
7
+ import { formatDate } from '../utils/display.js';
8
+ /**
9
+ * move 交互流程(多选,a 键全选)
10
+ */
11
+ export async function moveFlow(target) {
12
+ if (target === 'rules') {
13
+ await moveRulesFlow();
14
+ }
15
+ else {
16
+ await moveSkillsFlow();
17
+ }
18
+ }
19
+ async function moveRulesFlow() {
20
+ const direction = await select({
21
+ message: '移动方向:',
22
+ choices: [
23
+ { value: 'to-project', name: '全局 → 项目' },
24
+ { value: 'to-global', name: '项目 → 全局' },
25
+ ],
26
+ });
27
+ const isToProject = direction === 'to-project';
28
+ const sourceDir = isToProject ? getGlobalRulesDir() : getProjectRulesDir();
29
+ const destDir = isToProject ? getProjectRulesDir() : getGlobalRulesDir();
30
+ const sourceScope = isToProject ? 'global' : 'project';
31
+ const rules = scanRules(sourceDir, sourceScope);
32
+ if (rules.length === 0) {
33
+ console.log(chalk.dim(` ${isToProject ? '全局' : '项目'}中没有 rules`));
34
+ return;
35
+ }
36
+ const selected = await checkbox({
37
+ message: '选择要移动的 rules(a 全选,空格选择,回车确认):',
38
+ choices: rules
39
+ .sort((a, b) => a.id.localeCompare(b.id))
40
+ .map((rule) => ({
41
+ value: rule.id,
42
+ name: `${rule.id} ${chalk.dim(formatDate(rule.mtime))}`,
43
+ })),
44
+ });
45
+ if (selected.length === 0)
46
+ return;
47
+ for (const ruleId of selected) {
48
+ const sourcePath = path.join(sourceDir, ruleId);
49
+ const destPath = path.join(destDir, ruleId);
50
+ if (fs.existsSync(destPath)) {
51
+ const sourceStat = fs.statSync(sourcePath);
52
+ const destStat = fs.statSync(destPath);
53
+ console.log(chalk.yellow(`\n ⚠ 目标已存在 ${chalk.bold(ruleId)}`));
54
+ console.log(` 源 ${formatDate(sourceStat.mtime)}`);
55
+ console.log(` 目标 ${formatDate(destStat.mtime)}`);
56
+ const action = await select({
57
+ message: `${ruleId} 如何处理?`,
58
+ choices: [
59
+ { value: 'overwrite', name: '覆盖' },
60
+ { value: 'skip', name: '跳过' },
61
+ ],
62
+ });
63
+ if (action === 'skip')
64
+ continue;
65
+ }
66
+ const destDirPath = path.dirname(destPath);
67
+ if (!fs.existsSync(destDirPath)) {
68
+ fs.mkdirSync(destDirPath, { recursive: true });
69
+ }
70
+ fs.copyFileSync(sourcePath, destPath);
71
+ console.log(chalk.green(` ✓ 已复制 ${ruleId} → ${isToProject ? '项目' : '全局'}`));
72
+ }
73
+ const shouldDelete = await confirm({
74
+ message: '是否删除源文件?',
75
+ default: false,
76
+ });
77
+ if (shouldDelete) {
78
+ for (const ruleId of selected) {
79
+ const sourcePath = path.join(sourceDir, ruleId);
80
+ if (fs.existsSync(sourcePath)) {
81
+ fs.unlinkSync(sourcePath);
82
+ }
83
+ }
84
+ console.log(chalk.green(` ✓ 已删除 ${selected.length} 个源文件`));
85
+ }
86
+ }
87
+ async function moveSkillsFlow() {
88
+ const direction = await select({
89
+ message: '移动方向:',
90
+ choices: [
91
+ { value: 'to-project', name: '全局 → 项目' },
92
+ { value: 'to-global', name: '项目 → 全局' },
93
+ ],
94
+ });
95
+ const isToProject = direction === 'to-project';
96
+ const sourceDir = isToProject ? getGlobalSkillsDir() : getProjectSkillsDir();
97
+ const destBaseDir = isToProject ? getProjectSkillsDir() : getGlobalSkillsDir();
98
+ const sourceScope = isToProject ? 'global' : 'project';
99
+ const skills = scanSkills(sourceDir, sourceScope);
100
+ if (skills.length === 0) {
101
+ console.log(chalk.dim(` ${isToProject ? '全局' : '项目'}中没有 skills`));
102
+ return;
103
+ }
104
+ const selected = await checkbox({
105
+ message: '选择要移动的 skills(a 全选,空格选择,回车确认):',
106
+ choices: skills
107
+ .sort((a, b) => a.name.localeCompare(b.name))
108
+ .map((skill) => ({
109
+ value: skill.absolutePath,
110
+ name: `${skill.name} ${chalk.dim(`${skill.fileCount} 个文件`)}`,
111
+ })),
112
+ });
113
+ if (selected.length === 0)
114
+ return;
115
+ for (const sourcePath of selected) {
116
+ const skill = skills.find((s) => s.absolutePath === sourcePath);
117
+ const destPath = path.join(destBaseDir, skill.name);
118
+ if (fs.existsSync(destPath)) {
119
+ console.log(chalk.yellow(`\n ⚠ 目标已存在 ${chalk.bold(skill.name)}`));
120
+ const action = await select({
121
+ message: `${skill.name} 如何处理?`,
122
+ choices: [
123
+ { value: 'overwrite', name: '覆盖' },
124
+ { value: 'skip', name: '跳过' },
125
+ ],
126
+ });
127
+ if (action === 'skip')
128
+ continue;
129
+ fs.rmSync(destPath, { recursive: true, force: true });
130
+ }
131
+ if (!fs.existsSync(destBaseDir)) {
132
+ fs.mkdirSync(destBaseDir, { recursive: true });
133
+ }
134
+ // symlink 源创建 symlink 目标,普通目录复制
135
+ if (skill.isSymlink && skill.symlinkTarget) {
136
+ fs.symlinkSync(skill.symlinkTarget, destPath, 'junction');
137
+ console.log(chalk.green(` ✓ 已创建软链 ${skill.name} → ${isToProject ? '项目' : '全局'}`));
138
+ }
139
+ else {
140
+ fs.cpSync(sourcePath, destPath, { recursive: true });
141
+ console.log(chalk.green(` ✓ 已复制 ${skill.name} → ${isToProject ? '项目' : '全局'}`));
142
+ }
143
+ }
144
+ const shouldDelete = await confirm({
145
+ message: '是否删除源目录?',
146
+ default: false,
147
+ });
148
+ if (shouldDelete) {
149
+ for (const sourcePath of selected) {
150
+ if (fs.existsSync(sourcePath)) {
151
+ fs.rmSync(sourcePath, { recursive: true, force: true });
152
+ }
153
+ }
154
+ console.log(chalk.green(` ✓ 已删除 ${selected.length} 个源目录`));
155
+ }
156
+ }
157
+ //# sourceMappingURL=move.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"move.js","sourceRoot":"","sources":["../../src/flows/move.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /** rule 的作用域 */
2
+ export type RuleScope = 'global' | 'project';
3
+ /** rule frontmatter 中的触发方式 */
4
+ export type RuleTrigger = {
5
+ type: 'alwaysApply';
6
+ } | {
7
+ type: 'globs';
8
+ patterns: string;
9
+ } | {
10
+ type: 'none';
11
+ };
12
+ /** 解析后的 rule 信息 */
13
+ export interface Rule {
14
+ /** 相对路径标识符,如 react/core.md */
15
+ id: string;
16
+ /** 文件绝对路径 */
17
+ absolutePath: string;
18
+ /** 作用域 */
19
+ scope: RuleScope;
20
+ /** frontmatter 中的 description */
21
+ description: string | undefined;
22
+ /** 触发方式 */
23
+ trigger: RuleTrigger;
24
+ /** 文件修改时间 */
25
+ mtime: Date;
26
+ }
27
+ /** skill 信息 */
28
+ export interface Skill {
29
+ /** skill 名称(目录名) */
30
+ name: string;
31
+ /** skill 根目录绝对路径 */
32
+ absolutePath: string;
33
+ /** 包含的文件总数 */
34
+ fileCount: number;
35
+ /** 作用域 */
36
+ scope: RuleScope;
37
+ /** 是否是 symlink */
38
+ isSymlink: boolean;
39
+ /** symlink 目标路径(仅 isSymlink 为 true 时有值) */
40
+ symlinkTarget: string | undefined;
41
+ }
42
+ /** diff 总览表中的一行 */
43
+ export interface DiffSummaryItem {
44
+ /** rule 相对路径标识符 */
45
+ id: string;
46
+ /** 全局版本修改时间(不存在则为 undefined) */
47
+ globalMtime: Date | undefined;
48
+ /** 项目版本修改时间(不存在则为 undefined) */
49
+ projectMtime: Date | undefined;
50
+ /** 状态描述 */
51
+ status: '全局更新' | '项目更新' | '仅全局' | '仅项目' | '时间相同';
52
+ }
53
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,gBAAgB;AAChB,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE7C,8BAA8B;AAC9B,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAErB,mBAAmB;AACnB,MAAM,WAAW,IAAI;IACnB,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,aAAa;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU;IACV,KAAK,EAAE,SAAS,CAAC;IACjB,iCAAiC;IACjC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,WAAW;IACX,OAAO,EAAE,WAAW,CAAC;IACrB,aAAa;IACb,KAAK,EAAE,IAAI,CAAC;CACb;AAED,eAAe;AACf,MAAM,WAAW,KAAK;IACpB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU;IACV,KAAK,EAAE,SAAS,CAAC;IACjB,kBAAkB;IAClB,SAAS,EAAE,OAAO,CAAC;IACnB,2CAA2C;IAC3C,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;CACnC;AAED,mBAAmB;AACnB,MAAM,WAAW,eAAe;IAC9B,mBAAmB;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,gCAAgC;IAChC,WAAW,EAAE,IAAI,GAAG,SAAS,CAAC;IAC9B,gCAAgC;IAChC,YAAY,EAAE,IAAI,GAAG,SAAS,CAAC;IAC/B,WAAW;IACX,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;CAClD"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ import type { Rule, Skill, DiffSummaryItem } from '../types.js';
2
+ /**
3
+ * 格式化日期为简短格式(精确到秒)
4
+ */
5
+ export declare function formatDate(date: Date): string;
6
+ /**
7
+ * 打印 rules 列表
8
+ */
9
+ export declare function printRules(rules: Rule[], showScope: boolean): void;
10
+ /**
11
+ * 打印 skills 列表
12
+ */
13
+ export declare function printSkills(skills: Skill[], showScope: boolean): void;
14
+ /**
15
+ * 打印 diff 总览表
16
+ */
17
+ export declare function printDiffSummary(items: DiffSummaryItem[]): void;
18
+ //# sourceMappingURL=display.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.d.ts","sourceRoot":"","sources":["../../src/utils/display.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEhE;;GAEG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAO7C;AAyBD;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAsBlE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,OAAO,GAAG,IAAI,CAmBrE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,IAAI,CAkC/D"}
@@ -0,0 +1,110 @@
1
+ import chalk from 'chalk';
2
+ /**
3
+ * 格式化日期为简短格式(精确到秒)
4
+ */
5
+ export function formatDate(date) {
6
+ const month = date.getMonth() + 1;
7
+ const day = date.getDate();
8
+ const hours = String(date.getHours()).padStart(2, '0');
9
+ const minutes = String(date.getMinutes()).padStart(2, '0');
10
+ const seconds = String(date.getSeconds()).padStart(2, '0');
11
+ return `${month}月${day}日 ${hours}:${minutes}:${seconds}`;
12
+ }
13
+ /**
14
+ * 格式化触发方式
15
+ */
16
+ function formatTrigger(rule) {
17
+ switch (rule.trigger.type) {
18
+ case 'alwaysApply':
19
+ return chalk.green('alwaysApply');
20
+ case 'globs':
21
+ return chalk.yellow(`globs: ${rule.trigger.patterns}`);
22
+ case 'none':
23
+ return chalk.dim('无');
24
+ }
25
+ }
26
+ /**
27
+ * 格式化作用域标签
28
+ */
29
+ function formatScope(scope) {
30
+ return scope === 'global'
31
+ ? chalk.blue('全局')
32
+ : chalk.magenta('项目');
33
+ }
34
+ /**
35
+ * 打印 rules 列表
36
+ */
37
+ export function printRules(rules, showScope) {
38
+ if (rules.length === 0) {
39
+ console.log(chalk.dim('未找到 rules'));
40
+ return;
41
+ }
42
+ // 表头
43
+ const headers = showScope
44
+ ? ['标识符', '作用域', '触发方式', '修改时间']
45
+ : ['标识符', '触发方式', '修改时间'];
46
+ console.log(chalk.bold(headers.join('\t')));
47
+ console.log(chalk.dim('─'.repeat(80)));
48
+ for (const rule of rules) {
49
+ const cols = showScope
50
+ ? [rule.id, formatScope(rule.scope), formatTrigger(rule), formatDate(rule.mtime)]
51
+ : [rule.id, formatTrigger(rule), formatDate(rule.mtime)];
52
+ console.log(cols.join('\t'));
53
+ }
54
+ console.log(chalk.dim(`\n共 ${rules.length} 条 rules`));
55
+ }
56
+ /**
57
+ * 打印 skills 列表
58
+ */
59
+ export function printSkills(skills, showScope) {
60
+ if (skills.length === 0) {
61
+ console.log(chalk.dim('未找到 skills'));
62
+ return;
63
+ }
64
+ const headers = showScope ? ['名称', '作用域', '路径', '文件数'] : ['名称', '路径', '文件数'];
65
+ console.log(chalk.bold(headers.join('\t')));
66
+ console.log(chalk.dim('─'.repeat(80)));
67
+ for (const skill of skills) {
68
+ const linkTag = skill.isSymlink ? chalk.cyan(' [链接]') : '';
69
+ const cols = showScope
70
+ ? [skill.name + linkTag, formatScope(skill.scope), chalk.dim(skill.absolutePath), String(skill.fileCount)]
71
+ : [skill.name + linkTag, chalk.dim(skill.absolutePath), String(skill.fileCount)];
72
+ console.log(cols.join('\t'));
73
+ }
74
+ console.log(chalk.dim(`\n共 ${skills.length} 个 skills`));
75
+ }
76
+ /**
77
+ * 打印 diff 总览表
78
+ */
79
+ export function printDiffSummary(items) {
80
+ if (items.length === 0) {
81
+ console.log(chalk.dim('全局和项目之间没有同名 rules'));
82
+ return;
83
+ }
84
+ console.log(chalk.bold('标识符\t全局 mtime\t项目 mtime\t状态'));
85
+ console.log(chalk.dim('─'.repeat(80)));
86
+ for (const item of items) {
87
+ const globalTime = item.globalMtime ? formatDate(item.globalMtime) : chalk.dim('—');
88
+ const projectTime = item.projectMtime ? formatDate(item.projectMtime) : chalk.dim('—');
89
+ let statusText;
90
+ switch (item.status) {
91
+ case '全局更新':
92
+ statusText = chalk.blue('全局更新 ↑');
93
+ break;
94
+ case '项目更新':
95
+ statusText = chalk.magenta('项目更新 ↑');
96
+ break;
97
+ case '仅全局':
98
+ statusText = chalk.dim('仅全局');
99
+ break;
100
+ case '仅项目':
101
+ statusText = chalk.dim('仅项目');
102
+ break;
103
+ case '时间相同':
104
+ statusText = chalk.green('时间相同');
105
+ break;
106
+ }
107
+ console.log(`${item.id}\t${globalTime}\t${projectTime}\t${statusText}`);
108
+ }
109
+ }
110
+ //# sourceMappingURL=display.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"display.js","sourceRoot":"","sources":["../../src/utils/display.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { RuleTrigger } from '../types.js';
2
+ export interface ParsedFrontmatter {
3
+ description: string | undefined;
4
+ trigger: RuleTrigger;
5
+ }
6
+ /**
7
+ * 解析 rule 文件的 YAML frontmatter
8
+ * 手写解析避免 js-yaml 对 glob 模式(*)的 alias 误判
9
+ */
10
+ export declare function parseRuleFrontmatter(content: string): ParsedFrontmatter;
11
+ //# sourceMappingURL=parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/utils/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,OAAO,EAAE,WAAW,CAAC;CACtB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CA0BvE"}
@@ -0,0 +1,47 @@
1
+ /**
2
+ * 解析 rule 文件的 YAML frontmatter
3
+ * 手写解析避免 js-yaml 对 glob 模式(*)的 alias 误判
4
+ */
5
+ export function parseRuleFrontmatter(content) {
6
+ // 检查是否有 frontmatter
7
+ if (!content.startsWith('---')) {
8
+ return { description: undefined, trigger: { type: 'none' } };
9
+ }
10
+ const endIdx = content.indexOf('---', 3);
11
+ if (endIdx === -1) {
12
+ return { description: undefined, trigger: { type: 'none' } };
13
+ }
14
+ const frontmatterBlock = content.slice(3, endIdx).trim();
15
+ const fields = parseFrontmatterFields(frontmatterBlock);
16
+ const description = fields.get('description');
17
+ let trigger;
18
+ if (fields.get('alwaysApply') === 'true') {
19
+ trigger = { type: 'alwaysApply' };
20
+ }
21
+ else if (fields.has('globs') && fields.get('globs').length > 0) {
22
+ trigger = { type: 'globs', patterns: fields.get('globs') };
23
+ }
24
+ else {
25
+ trigger = { type: 'none' };
26
+ }
27
+ return { description, trigger };
28
+ }
29
+ /**
30
+ * 简单解析 frontmatter 字段(key: value 行)
31
+ * 不处理多行值、嵌套对象等复杂 YAML 特性
32
+ */
33
+ function parseFrontmatterFields(block) {
34
+ const fields = new Map();
35
+ for (const line of block.split('\n')) {
36
+ const colonIdx = line.indexOf(':');
37
+ if (colonIdx === -1)
38
+ continue;
39
+ const key = line.slice(0, colonIdx).trim();
40
+ const value = line.slice(colonIdx + 1).trim();
41
+ if (key.length > 0) {
42
+ fields.set(key, value);
43
+ }
44
+ }
45
+ return fields;
46
+ }
47
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/utils/parser.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,oBAAoB;IACpB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IAC/D,CAAC;IAED,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACzC,IAAI,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;QAClB,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IAC/D,CAAC;IAED,MAAM,gBAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACzD,MAAM,MAAM,GAAG,sBAAsB,CAAC,gBAAgB,CAAC,CAAC;IAExD,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAE9C,IAAI,OAAoB,CAAC;IACzB,IAAI,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,KAAK,MAAM,EAAE,CAAC;QACzC,OAAO,GAAG,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;IACpC,CAAC;SAAM,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,OAAO,CAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClE,OAAO,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,OAAO,CAAE,EAAE,CAAC;IAC9D,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC7B,CAAC;IAED,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;AAClC,CAAC;AAED;;;GAGG;AACH,SAAS,sBAAsB,CAAC,KAAa;IAC3C,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEzC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,QAAQ,KAAK,CAAC,CAAC;YAAE,SAAS;QAE9B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAE9C,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACnB,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,14 @@
1
+ /** 全局 rules 目录:~/.claude/rules/ */
2
+ export declare function getGlobalRulesDir(): string;
3
+ /** 项目 rules 目录:.claude/rules/ (基于 cwd) */
4
+ export declare function getProjectRulesDir(): string;
5
+ /** 全局 skills 目录:~/.claude/skills/ */
6
+ export declare function getGlobalSkillsDir(): string;
7
+ /** 项目 skills 目录:.claude/skills/ (基于 cwd) */
8
+ export declare function getProjectSkillsDir(): string;
9
+ /**
10
+ * 从绝对路径计算相对于 rules 根目录的标识符
11
+ * 例如:~/.claude/rules/react/core.md → react/core.md
12
+ */
13
+ export declare function toRuleId(absolutePath: string, rulesDir: string): string;
14
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAGA,mCAAmC;AACnC,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,0CAA0C;AAC1C,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,qCAAqC;AACrC,wBAAgB,kBAAkB,IAAI,MAAM,CAE3C;AAED,4CAA4C;AAC5C,wBAAgB,mBAAmB,IAAI,MAAM,CAE5C;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGvE"}
@@ -0,0 +1,27 @@
1
+ import path from 'node:path';
2
+ import os from 'node:os';
3
+ /** 全局 rules 目录:~/.claude/rules/ */
4
+ export function getGlobalRulesDir() {
5
+ return path.join(os.homedir(), '.claude', 'rules');
6
+ }
7
+ /** 项目 rules 目录:.claude/rules/ (基于 cwd) */
8
+ export function getProjectRulesDir() {
9
+ return path.join(process.cwd(), '.claude', 'rules');
10
+ }
11
+ /** 全局 skills 目录:~/.claude/skills/ */
12
+ export function getGlobalSkillsDir() {
13
+ return path.join(os.homedir(), '.claude', 'skills');
14
+ }
15
+ /** 项目 skills 目录:.claude/skills/ (基于 cwd) */
16
+ export function getProjectSkillsDir() {
17
+ return path.join(process.cwd(), '.claude', 'skills');
18
+ }
19
+ /**
20
+ * 从绝对路径计算相对于 rules 根目录的标识符
21
+ * 例如:~/.claude/rules/react/core.md → react/core.md
22
+ */
23
+ export function toRuleId(absolutePath, rulesDir) {
24
+ // 统一使用正斜杠,保证跨平台一致性
25
+ return path.relative(rulesDir, absolutePath).replace(/\\/g, '/');
26
+ }
27
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/utils/paths.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AAEzB,mCAAmC;AACnC,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AACrD,CAAC;AAED,0CAA0C;AAC1C,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;AACtD,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,kBAAkB;IAChC,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AACtD,CAAC;AAED,4CAA4C;AAC5C,MAAM,UAAU,mBAAmB;IACjC,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AACvD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,YAAoB,EAAE,QAAgB;IAC7D,mBAAmB;IACnB,OAAO,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AACnE,CAAC"}
@@ -0,0 +1,16 @@
1
+ import type { Rule, RuleScope, Skill } from '../types.js';
2
+ /**
3
+ * 取文件的实际最新时间(创建时间和修改时间中较晚的)
4
+ * 解决复制文件时 mtime 被保留但 birthtime 是新的问题
5
+ */
6
+ export declare function getLatestTime(filePath: string): Date;
7
+ /**
8
+ * 扫描指定目录下的所有 rules
9
+ */
10
+ export declare function scanRules(rulesDir: string, scope: RuleScope): Rule[];
11
+ /**
12
+ * 递归扫描 skills 目录
13
+ * 以 SKILL.md 存在作为 skill 根目录的标志
14
+ */
15
+ export declare function scanSkills(skillsDir: string, scope: RuleScope): Skill[];
16
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/utils/scanner.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAI1D;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAGpD;AAuBD;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,IAAI,EAAE,CAgBpE;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,KAAK,EAAE,CAMvE"}
@@ -0,0 +1,119 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { toRuleId } from './paths.js';
4
+ import { parseRuleFrontmatter } from './parser.js';
5
+ /**
6
+ * 取文件的实际最新时间(创建时间和修改时间中较晚的)
7
+ * 解决复制文件时 mtime 被保留但 birthtime 是新的问题
8
+ */
9
+ export function getLatestTime(filePath) {
10
+ const stat = fs.statSync(filePath);
11
+ return stat.birthtime.getTime() > stat.mtime.getTime() ? stat.birthtime : stat.mtime;
12
+ }
13
+ /**
14
+ * 递归扫描目录下所有 .md 文件
15
+ */
16
+ function walkMdFiles(dir) {
17
+ if (!fs.existsSync(dir))
18
+ return [];
19
+ const results = [];
20
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
21
+ for (const entry of entries) {
22
+ const fullPath = path.join(dir, entry.name);
23
+ if (entry.isDirectory()) {
24
+ results.push(...walkMdFiles(fullPath));
25
+ }
26
+ else if (entry.isFile() && entry.name.endsWith('.md')) {
27
+ results.push(fullPath);
28
+ }
29
+ }
30
+ return results;
31
+ }
32
+ /**
33
+ * 扫描指定目录下的所有 rules
34
+ */
35
+ export function scanRules(rulesDir, scope) {
36
+ const files = walkMdFiles(rulesDir);
37
+ return files.map((filePath) => {
38
+ const content = fs.readFileSync(filePath, 'utf-8');
39
+ const { description, trigger } = parseRuleFrontmatter(content);
40
+ return {
41
+ id: toRuleId(filePath, rulesDir),
42
+ absolutePath: filePath,
43
+ scope,
44
+ description,
45
+ trigger,
46
+ mtime: getLatestTime(filePath),
47
+ };
48
+ });
49
+ }
50
+ /**
51
+ * 递归扫描 skills 目录
52
+ * 以 SKILL.md 存在作为 skill 根目录的标志
53
+ */
54
+ export function scanSkills(skillsDir, scope) {
55
+ if (!fs.existsSync(skillsDir))
56
+ return [];
57
+ const skills = [];
58
+ scanSkillsRecursive(skillsDir, scope, skills);
59
+ return skills;
60
+ }
61
+ function scanSkillsRecursive(dir, scope, results) {
62
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
63
+ for (const entry of entries) {
64
+ const fullPath = path.join(dir, entry.name);
65
+ // 用 statSync 跟踪 symlink,判断目标是否是目录
66
+ let isDir;
67
+ try {
68
+ isDir = fs.statSync(fullPath).isDirectory();
69
+ }
70
+ catch {
71
+ continue;
72
+ }
73
+ if (!isDir)
74
+ continue;
75
+ const skillMdPath = path.join(fullPath, 'SKILL.md');
76
+ if (fs.existsSync(skillMdPath)) {
77
+ const fileCount = countFiles(fullPath);
78
+ const isSymlink = fs.lstatSync(fullPath).isSymbolicLink();
79
+ const symlinkTarget = isSymlink ? fs.readlinkSync(fullPath) : undefined;
80
+ results.push({
81
+ name: entry.name,
82
+ absolutePath: fullPath,
83
+ fileCount,
84
+ scope,
85
+ isSymlink,
86
+ symlinkTarget,
87
+ });
88
+ }
89
+ else {
90
+ // 不是 skill 根目录,继续递归(处理 skills/skills/ 嵌套)
91
+ scanSkillsRecursive(fullPath, scope, results);
92
+ }
93
+ }
94
+ }
95
+ /**
96
+ * 递归计算目录下的文件总数
97
+ */
98
+ function countFiles(dir) {
99
+ let count = 0;
100
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
101
+ for (const entry of entries) {
102
+ const fullPath = path.join(dir, entry.name);
103
+ let stat;
104
+ try {
105
+ stat = fs.statSync(fullPath);
106
+ }
107
+ catch {
108
+ continue;
109
+ }
110
+ if (stat.isDirectory()) {
111
+ count += countFiles(fullPath);
112
+ }
113
+ else if (stat.isFile()) {
114
+ count++;
115
+ }
116
+ }
117
+ return count;
118
+ }
119
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/utils/scanner.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "claude-tidy",
3
+ "version": "0.1.6",
4
+ "description": "Claude Code 的 skills 和 rules 管理工具",
5
+ "type": "module",
6
+ "bin": {
7
+ "claude-tidy": "./dist/cli.js"
8
+ },
9
+ "files": [
10
+ "dist"
11
+ ],
12
+ "scripts": {
13
+ "dev": "tsc && node dist/cli.js",
14
+ "build": "tsc",
15
+ "test": "echo \"No tests yet\"",
16
+ "start": "node dist/cli.js",
17
+ "release": "bash ./scripts/release.sh"
18
+ },
19
+ "engines": {
20
+ "node": ">=18.0.0"
21
+ },
22
+ "keywords": [
23
+ "claude",
24
+ "claude-code",
25
+ "rules",
26
+ "skills",
27
+ "cli",
28
+ "management"
29
+ ],
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "https://github.com/FE-runner/claude-tidy.git"
34
+ },
35
+ "dependencies": {
36
+ "@inquirer/prompts": "8.3.2",
37
+ "chalk": "5.6.2"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "25.5.0",
41
+ "typescript": "5.9.3"
42
+ }
43
+ }