create-dwy 0.6.5 → 0.6.7
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/bin/index.js +3 -2
- package/package.json +1 -1
- package/src/sync.js +49 -11
package/bin/index.js
CHANGED
|
@@ -22,8 +22,9 @@ program
|
|
|
22
22
|
|
|
23
23
|
program
|
|
24
24
|
.command('sync')
|
|
25
|
-
.description('
|
|
26
|
-
.
|
|
25
|
+
.description('同步 Claude Code 配置到项目 .claude/(默认覆盖已选项;CLAUDE.md → 全局 ~/.claude/)')
|
|
26
|
+
.option('--no-cache', '忽略已选缓存,重新交互式选择(已选项默认勾选)')
|
|
27
|
+
.action((opts) => syncClaude(opts))
|
|
27
28
|
|
|
28
29
|
program
|
|
29
30
|
.command('sync-claude-md')
|
package/package.json
CHANGED
package/src/sync.js
CHANGED
|
@@ -119,7 +119,7 @@ async function scanHooks(sourceDir) {
|
|
|
119
119
|
/**
|
|
120
120
|
* 用 inquirer 做交互式多选
|
|
121
121
|
*/
|
|
122
|
-
async function promptSelection(items, category) {
|
|
122
|
+
async function promptSelection(items, category, existingNames = new Set()) {
|
|
123
123
|
if (items.length === 0) return []
|
|
124
124
|
|
|
125
125
|
const { selected } = await inquirer.prompt([
|
|
@@ -131,6 +131,7 @@ async function promptSelection(items, category) {
|
|
|
131
131
|
name: `${chalk.cyan(item.name)} ${chalk.gray('- ' + item.description.slice(0, 60))}${item.description.length > 60 ? '...' : ''}`,
|
|
132
132
|
value: item,
|
|
133
133
|
short: item.name,
|
|
134
|
+
checked: existingNames.has(item.name),
|
|
134
135
|
})),
|
|
135
136
|
pageSize: 15,
|
|
136
137
|
},
|
|
@@ -139,6 +140,16 @@ async function promptSelection(items, category) {
|
|
|
139
140
|
return selected
|
|
140
141
|
}
|
|
141
142
|
|
|
143
|
+
/**
|
|
144
|
+
* 扫描项目已选过的项(.claude/<type>s/ 下的子项名),返回 Set
|
|
145
|
+
*/
|
|
146
|
+
async function scanExisting(projectTargetDir, typePlural) {
|
|
147
|
+
const dir = path.join(projectTargetDir, typePlural)
|
|
148
|
+
if (!await fs.pathExists(dir)) return new Set()
|
|
149
|
+
const entries = await fs.readdir(dir)
|
|
150
|
+
return new Set(entries.filter(name => name !== '.gitkeep' && name !== '.DS_Store'))
|
|
151
|
+
}
|
|
152
|
+
|
|
142
153
|
/**
|
|
143
154
|
* 同步选中的文件到目标目录
|
|
144
155
|
*/
|
|
@@ -213,10 +224,12 @@ async function resolveSourceDir() {
|
|
|
213
224
|
}
|
|
214
225
|
|
|
215
226
|
/**
|
|
216
|
-
*
|
|
217
|
-
*
|
|
227
|
+
* 主同步函数:默认基于已选缓存覆盖同步,--no-cache 走交互式选择
|
|
228
|
+
* 项目级 .claude/ 接收 skills/rules/commands/hooks/settings.json
|
|
229
|
+
* 全局 ~/.claude/ 接收 CLAUDE.md
|
|
218
230
|
*/
|
|
219
|
-
export async function syncClaude() {
|
|
231
|
+
export async function syncClaude(opts = {}) {
|
|
232
|
+
const useCache = opts.cache !== false
|
|
220
233
|
console.log(chalk.blue('\nScanning available Claude configuration...\n'))
|
|
221
234
|
|
|
222
235
|
const sourceDir = await resolveSourceDir()
|
|
@@ -244,7 +257,7 @@ export async function syncClaude() {
|
|
|
244
257
|
}
|
|
245
258
|
}
|
|
246
259
|
|
|
247
|
-
//
|
|
260
|
+
// 扫描模板资源
|
|
248
261
|
const skills = await scanSkills(sourceDir)
|
|
249
262
|
const rules = await scanRules(sourceDir)
|
|
250
263
|
const commands = await scanCommands(sourceDir)
|
|
@@ -252,15 +265,40 @@ export async function syncClaude() {
|
|
|
252
265
|
|
|
253
266
|
console.log(chalk.yellow(`Found ${skills.length} skills, ${rules.length} rules, ${commands.length} commands, ${hooks.length} hooks\n`))
|
|
254
267
|
|
|
255
|
-
//
|
|
256
|
-
const
|
|
257
|
-
const
|
|
258
|
-
const
|
|
259
|
-
const
|
|
268
|
+
// 扫描项目已选过的项
|
|
269
|
+
const existingSkills = await scanExisting(projectTargetDir, 'skills')
|
|
270
|
+
const existingRules = await scanExisting(projectTargetDir, 'rules')
|
|
271
|
+
const existingCommands = await scanExisting(projectTargetDir, 'commands')
|
|
272
|
+
const existingHooks = await scanExisting(projectTargetDir, 'hooks')
|
|
273
|
+
const hasAnyExisting = existingSkills.size + existingRules.size + existingCommands.size + existingHooks.size > 0
|
|
274
|
+
|
|
275
|
+
let selectedSkills, selectedRules, selectedCommands, selectedHooks
|
|
276
|
+
|
|
277
|
+
if (useCache && hasAnyExisting) {
|
|
278
|
+
// 缓存模式:模板 ∩ 已选 覆盖同步
|
|
279
|
+
selectedSkills = skills.filter(s => existingSkills.has(s.name))
|
|
280
|
+
selectedRules = rules.filter(r => existingRules.has(r.name))
|
|
281
|
+
selectedCommands = commands.filter(c => existingCommands.has(c.name))
|
|
282
|
+
// hooks 与 settings.json 引用配套:从未装过则装全部模板 hooks,已装过则按已选覆盖
|
|
283
|
+
selectedHooks = existingHooks.size > 0
|
|
284
|
+
? hooks.filter(h => existingHooks.has(h.name))
|
|
285
|
+
: hooks
|
|
286
|
+
console.log(chalk.gray(`使用已选缓存覆盖同步(如需调整请加 --no-cache):`))
|
|
287
|
+
console.log(chalk.gray(` ${selectedSkills.length} skills, ${selectedRules.length} rules, ${selectedCommands.length} commands, ${selectedHooks.length} hooks\n`))
|
|
288
|
+
} else {
|
|
289
|
+
// 交互模式:已选项默认勾选
|
|
290
|
+
if (useCache && !hasAnyExisting) {
|
|
291
|
+
console.log(chalk.gray('首次同步,进入交互式选择...\n'))
|
|
292
|
+
}
|
|
293
|
+
selectedSkills = await promptSelection(skills, 'Skills', existingSkills)
|
|
294
|
+
selectedRules = await promptSelection(rules, 'Rules', existingRules)
|
|
295
|
+
selectedCommands = await promptSelection(commands, 'Commands', existingCommands)
|
|
296
|
+
selectedHooks = await promptSelection(hooks, 'Hooks', existingHooks)
|
|
297
|
+
}
|
|
260
298
|
|
|
261
299
|
const totalSelected = selectedSkills.length + selectedRules.length + selectedCommands.length + selectedHooks.length
|
|
262
300
|
if (totalSelected === 0) {
|
|
263
|
-
console.log(chalk.yellow('\nNo skills/rules/commands selected.'))
|
|
301
|
+
console.log(chalk.yellow('\nNo skills/rules/commands/hooks selected.'))
|
|
264
302
|
}
|
|
265
303
|
|
|
266
304
|
console.log(chalk.blue(`\nSyncing to ${projectTargetDir}...\n`))
|