@skrupellose/code-helper 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -0
- package/dist/archive.d.ts +26 -0
- package/dist/archive.js +289 -0
- package/dist/archive.js.map +1 -0
- package/dist/checks.d.ts +6 -0
- package/dist/checks.js +351 -0
- package/dist/checks.js.map +1 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +651 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +26 -0
- package/dist/config.js +84 -0
- package/dist/config.js.map +1 -0
- package/dist/constants.d.ts +27 -0
- package/dist/constants.js +68 -0
- package/dist/constants.js.map +1 -0
- package/dist/fs-utils.d.ts +46 -0
- package/dist/fs-utils.js +188 -0
- package/dist/fs-utils.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/init.d.ts +21 -0
- package/dist/init.js +279 -0
- package/dist/init.js.map +1 -0
- package/dist/input-utils.d.ts +5 -0
- package/dist/input-utils.js +94 -0
- package/dist/input-utils.js.map +1 -0
- package/dist/skills.d.ts +41 -0
- package/dist/skills.js +201 -0
- package/dist/skills.js.map +1 -0
- package/dist/templates.d.ts +35 -0
- package/dist/templates.js +750 -0
- package/dist/templates.js.map +1 -0
- package/dist/terminal-ui.d.ts +44 -0
- package/dist/terminal-ui.js +189 -0
- package/dist/terminal-ui.js.map +1 -0
- package/dist/types.d.ts +56 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/workflows.d.ts +46 -0
- package/dist/workflows.js +284 -0
- package/dist/workflows.js.map +1 -0
- package/package.json +34 -0
package/dist/init.js
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { mkdir, readdir, rename, rmdir, stat } from "node:fs/promises";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { FEATURE_KEYS } from "./constants.js";
|
|
4
|
+
import { loadConfig, saveConfig } from "./config.js";
|
|
5
|
+
import { ensureDirectory, projectPath, upsertManagedMarkdownBlock, upsertMarkdownSection, readTextIfExists, writeText } from "./fs-utils.js";
|
|
6
|
+
import { listProjectSkillRegistrations, registerProjectSkills, resolveSkillRegistrationTargets } from "./skills.js";
|
|
7
|
+
import { getHookTemplates, getRuleTemplates, getSkillTemplates, renderEntryBlock } from "./templates.js";
|
|
8
|
+
/**
|
|
9
|
+
* 初始化项目中的 code-helper 工作区和协作规则。
|
|
10
|
+
* 该流程默认是非破坏性的:已有专题文档只跳过,入口文档只更新受控区块。
|
|
11
|
+
*/
|
|
12
|
+
export async function initializeProject(options) {
|
|
13
|
+
const config = await loadConfig(options.projectRoot);
|
|
14
|
+
const operations = [];
|
|
15
|
+
await detectEntryFiles(options.projectRoot, config);
|
|
16
|
+
const skillRegistrationTargets = await resolveSkillRegistrationTargets(options.projectRoot);
|
|
17
|
+
operations.push(...(await migrateLegacyAgentWorkspace(options.projectRoot, config)));
|
|
18
|
+
await createDirectories(options.projectRoot, config, operations);
|
|
19
|
+
await saveConfig(options.projectRoot, config);
|
|
20
|
+
operations.push({
|
|
21
|
+
path: projectPath(options.projectRoot, `${config.directories.workspace}/config.json`),
|
|
22
|
+
action: "updated",
|
|
23
|
+
message: "已写入或刷新 code-helper 配置"
|
|
24
|
+
});
|
|
25
|
+
operations.push(...(await installEntryDocuments(options.projectRoot, config)));
|
|
26
|
+
operations.push(...(await installRuleTemplates(options.projectRoot, config)));
|
|
27
|
+
operations.push(...(await installSkillTemplates(options.projectRoot, config)));
|
|
28
|
+
operations.push(...(await installProjectSkillRegistrations(options.projectRoot, config, skillRegistrationTargets)));
|
|
29
|
+
operations.push(...(await installHookTemplates(options.projectRoot, config)));
|
|
30
|
+
operations.push(await writeStateFile(options.projectRoot, config));
|
|
31
|
+
return { config, operations };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 注册项目级 skills。
|
|
35
|
+
* 初始化按当前项目入口文件注册对应 agent;关闭功能开关时只展示跳过结果,便于用户理解 init 行为。
|
|
36
|
+
*/
|
|
37
|
+
async function installProjectSkillRegistrations(projectRoot, config, targets) {
|
|
38
|
+
const operations = [];
|
|
39
|
+
if (!config.features.skillRegistration.enabled) {
|
|
40
|
+
const statuses = (await Promise.all(targets.map((target) => listProjectSkillRegistrations(projectRoot, target)))).flat();
|
|
41
|
+
return statuses.map((status) => ({
|
|
42
|
+
path: status.path,
|
|
43
|
+
action: "skipped",
|
|
44
|
+
message: "Skills 管理功能已关闭,跳过项目级注册"
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
47
|
+
for (const target of targets) {
|
|
48
|
+
operations.push(...(await registerProjectSkills(projectRoot, target)));
|
|
49
|
+
}
|
|
50
|
+
return operations;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 迁移旧版工作区到新版布局。
|
|
54
|
+
* 内部状态保留在 `.code-helper`,可读协作文档迁移到 `code-helper-docs`。
|
|
55
|
+
*/
|
|
56
|
+
async function migrateLegacyAgentWorkspace(projectRoot, config) {
|
|
57
|
+
const migrations = [
|
|
58
|
+
{ from: ".agent/code-helper", to: config.directories.workspace },
|
|
59
|
+
{ from: ".agent/user-rules", to: config.directories.userRules },
|
|
60
|
+
{ from: ".agent/plan-doc", to: config.directories.planDoc },
|
|
61
|
+
{ from: ".agent/result-doc", to: config.directories.resultDoc },
|
|
62
|
+
{ from: ".agent/status-doc", to: config.directories.statusDoc },
|
|
63
|
+
{ from: ".code-helper/user-rules", to: config.directories.userRules },
|
|
64
|
+
{ from: ".code-helper/plan-doc", to: config.directories.planDoc },
|
|
65
|
+
{ from: ".code-helper/result-doc", to: config.directories.resultDoc },
|
|
66
|
+
{ from: ".code-helper/status-doc", to: config.directories.statusDoc }
|
|
67
|
+
];
|
|
68
|
+
const operations = [];
|
|
69
|
+
for (const migration of migrations) {
|
|
70
|
+
operations.push(...(await migratePath(projectRoot, migration.from, migration.to)));
|
|
71
|
+
}
|
|
72
|
+
await removeEmptyDirectoryIfPossible(projectPath(projectRoot, ".agent"));
|
|
73
|
+
return operations;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 迁移一个文件或目录。
|
|
77
|
+
* 目标不存在时直接 rename;目标存在时递归合并,且遇到同名目标不覆盖。
|
|
78
|
+
*/
|
|
79
|
+
async function migratePath(projectRoot, fromRelativePath, toRelativePath) {
|
|
80
|
+
const fromPath = projectPath(projectRoot, fromRelativePath);
|
|
81
|
+
const toPath = projectPath(projectRoot, toRelativePath);
|
|
82
|
+
const sourceStat = await statIfExists(fromPath);
|
|
83
|
+
const operations = [];
|
|
84
|
+
if (sourceStat === undefined) {
|
|
85
|
+
return operations;
|
|
86
|
+
}
|
|
87
|
+
const targetStat = await statIfExists(toPath);
|
|
88
|
+
if (targetStat === undefined) {
|
|
89
|
+
await mkdir(dirname(toPath), { recursive: true });
|
|
90
|
+
await rename(fromPath, toPath);
|
|
91
|
+
operations.push({
|
|
92
|
+
path: toPath,
|
|
93
|
+
action: "updated",
|
|
94
|
+
message: `已从旧路径迁移:${fromRelativePath}`
|
|
95
|
+
});
|
|
96
|
+
return operations;
|
|
97
|
+
}
|
|
98
|
+
if (sourceStat.isDirectory() && targetStat.isDirectory()) {
|
|
99
|
+
const entries = await readdir(fromPath);
|
|
100
|
+
for (const entry of entries) {
|
|
101
|
+
operations.push(...(await migratePath(projectRoot, join(fromRelativePath, entry), join(toRelativePath, entry))));
|
|
102
|
+
}
|
|
103
|
+
await removeEmptyDirectoryIfPossible(fromPath);
|
|
104
|
+
return operations;
|
|
105
|
+
}
|
|
106
|
+
operations.push({
|
|
107
|
+
path: fromPath,
|
|
108
|
+
action: "skipped",
|
|
109
|
+
message: `迁移目标已存在,为避免覆盖已保留旧路径:${toRelativePath}`
|
|
110
|
+
});
|
|
111
|
+
return operations;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 安全读取路径状态。
|
|
115
|
+
* 不存在时返回 undefined,其他错误继续抛出。
|
|
116
|
+
*/
|
|
117
|
+
async function statIfExists(path) {
|
|
118
|
+
try {
|
|
119
|
+
return await stat(path);
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* 尝试删除空目录。
|
|
130
|
+
* 如果目录不存在或非空,保持现状,避免误删用户未知内容。
|
|
131
|
+
*/
|
|
132
|
+
async function removeEmptyDirectoryIfPossible(path) {
|
|
133
|
+
try {
|
|
134
|
+
await rmdir(path);
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// 目录不存在、非空或被系统占用时都不处理,迁移逻辑不应破坏用户文件。
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 创建所有固定目录。
|
|
142
|
+
* 目录创建本身幂等,因此统一标记为 updated,表示已确保存在。
|
|
143
|
+
*/
|
|
144
|
+
async function createDirectories(projectRoot, config, operations) {
|
|
145
|
+
const directories = [
|
|
146
|
+
config.directories.workspace,
|
|
147
|
+
`${config.directories.workspace}/templates`,
|
|
148
|
+
`${config.directories.workspace}/skills`,
|
|
149
|
+
`${config.directories.workspace}/hooks`,
|
|
150
|
+
`${config.directories.workspace}/checks`,
|
|
151
|
+
`${config.directories.workspace}/archives`,
|
|
152
|
+
config.directories.userRules,
|
|
153
|
+
config.directories.planDoc,
|
|
154
|
+
`${config.directories.planDoc}/archive`,
|
|
155
|
+
config.directories.resultDoc,
|
|
156
|
+
`${config.directories.resultDoc}/archive`,
|
|
157
|
+
config.directories.statusDoc,
|
|
158
|
+
`${config.directories.statusDoc}/archive`
|
|
159
|
+
];
|
|
160
|
+
for (const directory of directories) {
|
|
161
|
+
const absolutePath = projectPath(projectRoot, directory);
|
|
162
|
+
await ensureDirectory(absolutePath);
|
|
163
|
+
operations.push({
|
|
164
|
+
path: absolutePath,
|
|
165
|
+
action: "updated",
|
|
166
|
+
message: "已确保目录存在"
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* 安装或更新 AGENTS.md / CLAUDE.md 入口文档。
|
|
172
|
+
* 已存在文档只替换 code-helper 管理区块,不触碰用户其他内容。
|
|
173
|
+
*/
|
|
174
|
+
async function installEntryDocuments(projectRoot, config) {
|
|
175
|
+
const operations = [];
|
|
176
|
+
const entryBlock = renderEntryBlock(config);
|
|
177
|
+
if (config.entryFiles.agents) {
|
|
178
|
+
operations.push(await upsertManagedMarkdownBlock(projectPath(projectRoot, "AGENTS.md"), entryBlock));
|
|
179
|
+
}
|
|
180
|
+
if (config.entryFiles.claude) {
|
|
181
|
+
operations.push(await upsertManagedMarkdownBlock(projectPath(projectRoot, "CLAUDE.md"), entryBlock));
|
|
182
|
+
}
|
|
183
|
+
return operations;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* 安装专题规则模板。
|
|
187
|
+
* 老项目已有同名规则时不会覆盖,避免丢失用户维护的规则。
|
|
188
|
+
*/
|
|
189
|
+
async function installRuleTemplates(projectRoot, config) {
|
|
190
|
+
const operations = [];
|
|
191
|
+
for (const template of getRuleTemplates(config)) {
|
|
192
|
+
const targetPath = projectPath(projectRoot, join(config.directories.userRules, template.fileName));
|
|
193
|
+
operations.push(await upsertMarkdownSection(targetPath, "## 调用入口文件", renderEntryFileList(config), template.content));
|
|
194
|
+
}
|
|
195
|
+
return operations;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* 检测用户已经手动创建的入口文件。
|
|
199
|
+
* 已有入口文件优先代表当前项目实际使用的 agent;完全没有入口文件的新项目才默认维护 AGENTS.md。
|
|
200
|
+
*/
|
|
201
|
+
async function detectEntryFiles(projectRoot, config) {
|
|
202
|
+
const agentsExists = (await readTextIfExists(projectPath(projectRoot, "AGENTS.md"))) !== undefined;
|
|
203
|
+
const claudeExists = (await readTextIfExists(projectPath(projectRoot, "CLAUDE.md"))) !== undefined;
|
|
204
|
+
if (agentsExists || claudeExists) {
|
|
205
|
+
config.entryFiles.agents = agentsExists;
|
|
206
|
+
config.entryFiles.claude = claudeExists;
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (!config.entryFiles.agents && !config.entryFiles.claude) {
|
|
210
|
+
config.entryFiles.agents = true;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* 渲染专题规则中的调用入口文件列表。
|
|
215
|
+
* 该段会在 init 时同步到已有规则文件,确保手动新增 CLAUDE.md 后规则入口也一致。
|
|
216
|
+
*/
|
|
217
|
+
function renderEntryFileList(config) {
|
|
218
|
+
const entries = [
|
|
219
|
+
config.entryFiles.agents ? "- `AGENTS.md`" : undefined,
|
|
220
|
+
config.entryFiles.claude ? "- `CLAUDE.md`" : undefined
|
|
221
|
+
].filter((entry) => entry !== undefined);
|
|
222
|
+
return entries.join("\n");
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* 安装内置 skill 模板副本。
|
|
226
|
+
* 这些文件是 code-helper 工作区资产,可以在新版本初始化时安全刷新。
|
|
227
|
+
*/
|
|
228
|
+
async function installSkillTemplates(projectRoot, config) {
|
|
229
|
+
const operations = [];
|
|
230
|
+
for (const template of getSkillTemplates()) {
|
|
231
|
+
const targetPath = projectPath(projectRoot, join(config.directories.workspace, "skills", template.fileName));
|
|
232
|
+
await writeText(targetPath, template.content);
|
|
233
|
+
operations.push({
|
|
234
|
+
path: targetPath,
|
|
235
|
+
action: "updated",
|
|
236
|
+
message: "已刷新内置 skill 模板"
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
return operations;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* 安装可选 hook 模板。
|
|
243
|
+
* 即使 gitHooks 功能关闭,也只生成 sample 文件,不写入 .git/hooks。
|
|
244
|
+
*/
|
|
245
|
+
async function installHookTemplates(projectRoot, config) {
|
|
246
|
+
const operations = [];
|
|
247
|
+
for (const template of getHookTemplates()) {
|
|
248
|
+
const targetPath = projectPath(projectRoot, join(config.directories.workspace, "hooks", template.fileName));
|
|
249
|
+
await writeText(targetPath, template.content);
|
|
250
|
+
operations.push({
|
|
251
|
+
path: targetPath,
|
|
252
|
+
action: config.features.gitHooks.enabled ? "updated" : "skipped",
|
|
253
|
+
message: config.features.gitHooks.enabled
|
|
254
|
+
? "已刷新可选 Git hook 模板"
|
|
255
|
+
: "Git hooks 默认关闭,仅保留 sample 模板"
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
return operations;
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* 写入 code-helper 状态文件。
|
|
262
|
+
* 该文件记录工具自身最近一次初始化状态,不替代业务项目 status-doc。
|
|
263
|
+
*/
|
|
264
|
+
async function writeStateFile(projectRoot, config) {
|
|
265
|
+
const enabledFeatures = FEATURE_KEYS.filter((feature) => config.features[feature].enabled);
|
|
266
|
+
const targetPath = projectPath(projectRoot, `${config.directories.workspace}/state.json`);
|
|
267
|
+
const state = {
|
|
268
|
+
initializedAt: new Date().toISOString(),
|
|
269
|
+
enabledFeatures,
|
|
270
|
+
note: "此文件由 code-helper 维护,仅记录工具状态,不承载业务项目状态。"
|
|
271
|
+
};
|
|
272
|
+
await writeText(targetPath, `${JSON.stringify(state, null, 2)}\n`);
|
|
273
|
+
return {
|
|
274
|
+
path: targetPath,
|
|
275
|
+
action: "updated",
|
|
276
|
+
message: "已刷新 code-helper 运行状态"
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=init.js.map
|
package/dist/init.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { isAbsolute, relative, resolve, win32 } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
/**
|
|
4
|
+
* 解析用户输入或终端拖拽产生的文件路径。
|
|
5
|
+
* 终端拖拽通常会粘贴引号、反斜杠转义空格或 file:// URL,这里统一归一化。
|
|
6
|
+
*/
|
|
7
|
+
export function normalizeDroppedPath(input, projectRoot) {
|
|
8
|
+
const cleanedInput = stripWrappingQuotes(input.trim());
|
|
9
|
+
const decodedPath = cleanedInput.startsWith("file://")
|
|
10
|
+
? decodeFileUrlPath(cleanedInput)
|
|
11
|
+
: decodePlainPath(cleanedInput);
|
|
12
|
+
const normalizedPath = decodedPath.trim();
|
|
13
|
+
if (isWindowsAbsolutePath(normalizedPath)) {
|
|
14
|
+
const relativePath = win32.relative(win32.resolve(projectRoot), win32.normalize(normalizedPath));
|
|
15
|
+
if (isProjectRelativePath(relativePath, "\\")) {
|
|
16
|
+
return relativePath;
|
|
17
|
+
}
|
|
18
|
+
return normalizedPath;
|
|
19
|
+
}
|
|
20
|
+
if (isWindowsAbsolutePath(projectRoot) && isWindowsPathLike(normalizedPath)) {
|
|
21
|
+
return normalizedPath;
|
|
22
|
+
}
|
|
23
|
+
if (isAbsolute(normalizedPath)) {
|
|
24
|
+
const relativePath = relative(resolve(projectRoot), normalizedPath);
|
|
25
|
+
if (isProjectRelativePath(relativePath, "/")) {
|
|
26
|
+
return relativePath;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return normalizedPath;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 去掉拖拽路径外层可能出现的单引号或双引号。
|
|
33
|
+
*/
|
|
34
|
+
function stripWrappingQuotes(value) {
|
|
35
|
+
if ((value.startsWith("'") && value.endsWith("'")) ||
|
|
36
|
+
(value.startsWith("\"") && value.endsWith("\""))) {
|
|
37
|
+
return value.slice(1, -1);
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 解析 file:// URL。
|
|
43
|
+
* Windows 终端可能粘贴 file:///C:/...,在非 Windows 测试环境下需要保留 C: 盘符形态,避免变成 /C:/...。
|
|
44
|
+
*/
|
|
45
|
+
function decodeFileUrlPath(value) {
|
|
46
|
+
const url = new URL(value);
|
|
47
|
+
const decodedPath = decodeURIComponent(url.pathname);
|
|
48
|
+
if (/^\/[A-Za-z]:\//u.test(decodedPath)) {
|
|
49
|
+
return decodedPath.slice(1).replace(/\//gu, "\\");
|
|
50
|
+
}
|
|
51
|
+
return fileURLToPath(value);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 解析普通路径输入。
|
|
55
|
+
* Windows 路径中的反斜杠是路径分隔符,不能按 POSIX shell 转义处理。
|
|
56
|
+
*/
|
|
57
|
+
function decodePlainPath(value) {
|
|
58
|
+
if (isWindowsPathLike(value)) {
|
|
59
|
+
return value;
|
|
60
|
+
}
|
|
61
|
+
return unescapeShellPath(value);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* 处理 shell 风格反斜杠转义。
|
|
65
|
+
* 只移除反斜杠本身,保留被转义字符,例如 a\ b.md -> a b.md。
|
|
66
|
+
*/
|
|
67
|
+
function unescapeShellPath(value) {
|
|
68
|
+
return value.replace(/\\(.)/gu, "$1");
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* 判断是否是 Windows 绝对路径。
|
|
72
|
+
* 同时支持盘符路径和 UNC 网络路径。
|
|
73
|
+
*/
|
|
74
|
+
function isWindowsAbsolutePath(value) {
|
|
75
|
+
return /^[A-Za-z]:[\\/]/u.test(value) || /^\\\\/u.test(value);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 判断是否看起来像 Windows 路径。
|
|
79
|
+
* 相对路径 docs\需求.md 也要保留反斜杠,不能当成 shell 转义。
|
|
80
|
+
*/
|
|
81
|
+
function isWindowsPathLike(value) {
|
|
82
|
+
if (value.startsWith("/")) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return /^[A-Za-z]:[\\/]/u.test(value) || /^\\\\/u.test(value) || /\\\S/u.test(value);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* 判断绝对路径是否位于项目目录下。
|
|
89
|
+
* 空字符串表示就是项目根目录,不能作为需求文档路径返回。
|
|
90
|
+
*/
|
|
91
|
+
function isProjectRelativePath(value, separator) {
|
|
92
|
+
return value !== "" && value !== ".." && !value.startsWith(`..${separator}`);
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=input-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"input-utils.js","sourceRoot":"","sources":["../src/input-utils.ts"],"names":[],"mappings":"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"}
|
package/dist/skills.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { OperationResult } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* 当前支持的项目级 skill 注册目标。
|
|
4
|
+
* codex 写入 `.agents/skills`,claudecode 写入 `.claude/skills`。
|
|
5
|
+
*/
|
|
6
|
+
export type SkillRegistrationTarget = "codex" | "claudecode";
|
|
7
|
+
/**
|
|
8
|
+
* 单个项目级 skill 的注册状态。
|
|
9
|
+
* CLI 用它展示当前项目是否已经注册 code-helper skills。
|
|
10
|
+
*/
|
|
11
|
+
export interface SkillRegistrationStatus {
|
|
12
|
+
target: SkillRegistrationTarget;
|
|
13
|
+
name: string;
|
|
14
|
+
path: string;
|
|
15
|
+
registered: boolean;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 注册 code-helper 内置 skills 到当前项目。
|
|
19
|
+
* 注册结果按目标写入 `.agents/skills` 或 `.claude/skills`,只影响当前项目。
|
|
20
|
+
*/
|
|
21
|
+
export declare function registerProjectSkills(projectRoot: string, target?: SkillRegistrationTarget): Promise<OperationResult[]>;
|
|
22
|
+
/**
|
|
23
|
+
* 取消注册 code-helper 项目级 skills。
|
|
24
|
+
* 只删除 `.agents/skills/code-helper-*` 或 `.claude/skills/code-helper-*` 受控目录,不触碰用户自己的 skills。
|
|
25
|
+
*/
|
|
26
|
+
export declare function unregisterProjectSkills(projectRoot: string, target?: SkillRegistrationTarget): Promise<OperationResult[]>;
|
|
27
|
+
/**
|
|
28
|
+
* 查看 code-helper 项目级 skills 注册状态。
|
|
29
|
+
* 该函数只检查 code-helper 管理的 skill 名称,不扫描用户自定义 skills。
|
|
30
|
+
*/
|
|
31
|
+
export declare function listProjectSkillRegistrations(projectRoot: string, target?: SkillRegistrationTarget): Promise<SkillRegistrationStatus[]>;
|
|
32
|
+
/**
|
|
33
|
+
* 解析 CLI 输入中的注册目标。
|
|
34
|
+
* 不带值时只返回 Codex;交互命令的“按当前项目注册”会使用 resolveSkillRegistrationTargets 单独推断。
|
|
35
|
+
*/
|
|
36
|
+
export declare function parseSkillRegistrationTargets(value: string | undefined): SkillRegistrationTarget[];
|
|
37
|
+
/**
|
|
38
|
+
* 根据当前项目实际入口文件推断需要注册的 agent 工具。
|
|
39
|
+
* 根目录已有 AGENTS.md 或 CLAUDE.md 时,以这些文件作为实际使用状态;完全没有入口文件的新项目默认注册全部。
|
|
40
|
+
*/
|
|
41
|
+
export declare function resolveSkillRegistrationTargets(projectRoot: string): Promise<SkillRegistrationTarget[]>;
|
package/dist/skills.js
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { readdir, rm } from "node:fs/promises";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import { loadConfig } from "./config.js";
|
|
4
|
+
import { projectPath, readTextIfExists, writeText } from "./fs-utils.js";
|
|
5
|
+
import { getSkillTemplates } from "./templates.js";
|
|
6
|
+
/**
|
|
7
|
+
* 所有支持的注册目标。
|
|
8
|
+
* 显式传入 all 时才会使用完整列表,避免默认行为误注册未使用的 agent 工具。
|
|
9
|
+
*/
|
|
10
|
+
const ALL_SKILL_REGISTRATION_TARGETS = ["codex", "claudecode"];
|
|
11
|
+
/**
|
|
12
|
+
* code-helper 内置 skill 到项目级目录的映射。
|
|
13
|
+
* directoryName 使用 skill frontmatter 中的 name,便于不同 agent 工具直接识别。
|
|
14
|
+
*/
|
|
15
|
+
const CODE_HELPER_SKILL_REGISTRATIONS = [
|
|
16
|
+
{
|
|
17
|
+
templateFileName: "memory-tuning.SKILL.md",
|
|
18
|
+
directoryName: "code-helper-memory-tuning"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
templateFileName: "plan-workbench.SKILL.md",
|
|
22
|
+
directoryName: "code-helper-plan-workbench"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
templateFileName: "document-archive.SKILL.md",
|
|
26
|
+
directoryName: "code-helper-document-archive"
|
|
27
|
+
}
|
|
28
|
+
];
|
|
29
|
+
/**
|
|
30
|
+
* Codex 项目级 skills 根目录。
|
|
31
|
+
* 该目录只影响当前项目,不会注册到用户全局 skills。
|
|
32
|
+
*/
|
|
33
|
+
const CODEX_PROJECT_SKILLS_DIRECTORY = ".agents/skills";
|
|
34
|
+
/**
|
|
35
|
+
* Claude Code 项目级 skills 根目录。
|
|
36
|
+
* 该目录只影响当前项目,不会注册到用户全局 `~/.claude/skills`。
|
|
37
|
+
*/
|
|
38
|
+
const CLAUDE_CODE_PROJECT_SKILLS_DIRECTORY = ".claude/skills";
|
|
39
|
+
/**
|
|
40
|
+
* 注册 code-helper 内置 skills 到当前项目。
|
|
41
|
+
* 注册结果按目标写入 `.agents/skills` 或 `.claude/skills`,只影响当前项目。
|
|
42
|
+
*/
|
|
43
|
+
export async function registerProjectSkills(projectRoot, target = "codex") {
|
|
44
|
+
assertSupportedTarget(target);
|
|
45
|
+
const config = await loadConfig(projectRoot);
|
|
46
|
+
if (!config.features.skillRegistration.enabled) {
|
|
47
|
+
throw new Error("Skills 管理功能已关闭,请先执行 `code-helper features enable skillRegistration`。");
|
|
48
|
+
}
|
|
49
|
+
const operations = [];
|
|
50
|
+
const templates = getSkillTemplates();
|
|
51
|
+
for (const registration of CODE_HELPER_SKILL_REGISTRATIONS) {
|
|
52
|
+
const template = templates.find((item) => item.fileName === registration.templateFileName);
|
|
53
|
+
if (template === undefined) {
|
|
54
|
+
throw new Error(`缺少内置 skill 模板:${registration.templateFileName}`);
|
|
55
|
+
}
|
|
56
|
+
const targetPath = getSkillFilePath(projectRoot, target, registration.directoryName);
|
|
57
|
+
const existing = await readTextIfExists(targetPath);
|
|
58
|
+
if (existing === template.content) {
|
|
59
|
+
operations.push({
|
|
60
|
+
path: targetPath,
|
|
61
|
+
action: "skipped",
|
|
62
|
+
message: "项目级 skill 已是最新内容"
|
|
63
|
+
});
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
await writeText(targetPath, template.content);
|
|
67
|
+
operations.push({
|
|
68
|
+
path: targetPath,
|
|
69
|
+
action: existing === undefined ? "created" : "updated",
|
|
70
|
+
message: `已注册 ${formatTargetName(target)} 项目级 skill`
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return operations;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* 取消注册 code-helper 项目级 skills。
|
|
77
|
+
* 只删除 `.agents/skills/code-helper-*` 或 `.claude/skills/code-helper-*` 受控目录,不触碰用户自己的 skills。
|
|
78
|
+
*/
|
|
79
|
+
export async function unregisterProjectSkills(projectRoot, target = "codex") {
|
|
80
|
+
assertSupportedTarget(target);
|
|
81
|
+
const operations = [];
|
|
82
|
+
for (const registration of CODE_HELPER_SKILL_REGISTRATIONS) {
|
|
83
|
+
const targetDirectory = projectPath(projectRoot, join(getProjectSkillsDirectory(target), registration.directoryName));
|
|
84
|
+
const targetPath = join(targetDirectory, "SKILL.md");
|
|
85
|
+
const existing = await readTextIfExists(targetPath);
|
|
86
|
+
if (existing === undefined) {
|
|
87
|
+
operations.push({
|
|
88
|
+
path: targetPath,
|
|
89
|
+
action: "skipped",
|
|
90
|
+
message: "项目级 skill 未注册"
|
|
91
|
+
});
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
await rm(targetDirectory, { recursive: true, force: true });
|
|
95
|
+
operations.push({
|
|
96
|
+
path: targetDirectory,
|
|
97
|
+
action: "updated",
|
|
98
|
+
message: `已取消注册 ${formatTargetName(target)} 项目级 skill`
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
const targetRoot = getProjectSkillsDirectory(target);
|
|
102
|
+
await removeEmptyDirectory(projectPath(projectRoot, targetRoot));
|
|
103
|
+
await removeEmptyDirectory(projectPath(projectRoot, dirname(targetRoot)));
|
|
104
|
+
return operations;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 查看 code-helper 项目级 skills 注册状态。
|
|
108
|
+
* 该函数只检查 code-helper 管理的 skill 名称,不扫描用户自定义 skills。
|
|
109
|
+
*/
|
|
110
|
+
export async function listProjectSkillRegistrations(projectRoot, target = "codex") {
|
|
111
|
+
assertSupportedTarget(target);
|
|
112
|
+
const statuses = [];
|
|
113
|
+
for (const registration of CODE_HELPER_SKILL_REGISTRATIONS) {
|
|
114
|
+
const targetPath = getSkillFilePath(projectRoot, target, registration.directoryName);
|
|
115
|
+
statuses.push({
|
|
116
|
+
target,
|
|
117
|
+
name: registration.directoryName,
|
|
118
|
+
path: targetPath,
|
|
119
|
+
registered: (await readTextIfExists(targetPath)) !== undefined
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
return statuses;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* 解析 CLI 输入中的注册目标。
|
|
126
|
+
* 不带值时只返回 Codex;交互命令的“按当前项目注册”会使用 resolveSkillRegistrationTargets 单独推断。
|
|
127
|
+
*/
|
|
128
|
+
export function parseSkillRegistrationTargets(value) {
|
|
129
|
+
if (value === undefined || value === "" || value === "codex") {
|
|
130
|
+
return ["codex"];
|
|
131
|
+
}
|
|
132
|
+
if (value === "claudecode" || value === "claude-code" || value === "claude") {
|
|
133
|
+
return ["claudecode"];
|
|
134
|
+
}
|
|
135
|
+
if (value === "all") {
|
|
136
|
+
return [...ALL_SKILL_REGISTRATION_TARGETS];
|
|
137
|
+
}
|
|
138
|
+
throw new Error(`不支持的 skills 注册目标:${value}。当前支持 codex、claudecode 或 all。`);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* 根据当前项目实际入口文件推断需要注册的 agent 工具。
|
|
142
|
+
* 根目录已有 AGENTS.md 或 CLAUDE.md 时,以这些文件作为实际使用状态;完全没有入口文件的新项目默认注册全部。
|
|
143
|
+
*/
|
|
144
|
+
export async function resolveSkillRegistrationTargets(projectRoot) {
|
|
145
|
+
const agentsExists = (await readTextIfExists(projectPath(projectRoot, "AGENTS.md"))) !== undefined;
|
|
146
|
+
const claudeExists = (await readTextIfExists(projectPath(projectRoot, "CLAUDE.md"))) !== undefined;
|
|
147
|
+
const targets = [];
|
|
148
|
+
if (agentsExists || claudeExists) {
|
|
149
|
+
if (agentsExists) {
|
|
150
|
+
targets.push("codex");
|
|
151
|
+
}
|
|
152
|
+
if (claudeExists) {
|
|
153
|
+
targets.push("claudecode");
|
|
154
|
+
}
|
|
155
|
+
return targets;
|
|
156
|
+
}
|
|
157
|
+
return [...ALL_SKILL_REGISTRATION_TARGETS];
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* 返回项目级 SKILL.md 绝对路径。
|
|
161
|
+
*/
|
|
162
|
+
function getSkillFilePath(projectRoot, target, directoryName) {
|
|
163
|
+
return projectPath(projectRoot, join(getProjectSkillsDirectory(target), directoryName, "SKILL.md"));
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* 校验注册目标。
|
|
167
|
+
* 这个函数让公开 API 即使传入非字面量字符串也能得到明确错误。
|
|
168
|
+
*/
|
|
169
|
+
function assertSupportedTarget(target) {
|
|
170
|
+
if (target !== "codex" && target !== "claudecode") {
|
|
171
|
+
throw new Error(`不支持的 skills 注册目标:${target}。当前支持 codex 或 claudecode。`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* 返回不同 agent 工具的项目级 skills 目录。
|
|
176
|
+
*/
|
|
177
|
+
function getProjectSkillsDirectory(target) {
|
|
178
|
+
return target === "codex" ? CODEX_PROJECT_SKILLS_DIRECTORY : CLAUDE_CODE_PROJECT_SKILLS_DIRECTORY;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* 返回面向用户展示的 agent 工具名称。
|
|
182
|
+
*/
|
|
183
|
+
function formatTargetName(target) {
|
|
184
|
+
return target === "codex" ? "Codex" : "Claude Code";
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* 删除空目录。
|
|
188
|
+
* 目录不存在或非空时保持现状,避免误删用户自定义 skills。
|
|
189
|
+
*/
|
|
190
|
+
async function removeEmptyDirectory(path) {
|
|
191
|
+
try {
|
|
192
|
+
const entries = await readdir(path);
|
|
193
|
+
if (entries.length === 0) {
|
|
194
|
+
await rm(path, { recursive: false, force: true });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
// 目录不存在或不可删除时不处理,取消注册不应影响用户文件。
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"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"}
|