create-dwy 0.6.5 → 0.6.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.
package/bin/index.js CHANGED
@@ -22,8 +22,9 @@ program
22
22
 
23
23
  program
24
24
  .command('sync')
25
- .description('交互式选择并同步 Claude Code 配置(skills/rules/commands/settings.json → 项目 .claude/;CLAUDE.md → 全局 ~/.claude/)')
26
- .action(syncClaude)
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-dwy",
3
- "version": "0.6.5",
3
+ "version": "0.6.6",
4
4
  "description": "项目脚手架与 Claude Code 配置同步工具",
5
5
  "type": "module",
6
6
  "bin": {
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
- * 主同步函数:交互式选择 + 同步到当前目录 .claude/(不含 CLAUDE.md)
217
- * CLAUDE.md 同步到全局 ~/.claude/
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,37 @@ 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 selectedSkills = await promptSelection(skills, 'Skills')
257
- const selectedRules = await promptSelection(rules, 'Rules')
258
- const selectedCommands = await promptSelection(commands, 'Commands')
259
- const selectedHooks = await promptSelection(hooks, 'Hooks')
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
+ selectedHooks = hooks.filter(h => existingHooks.has(h.name))
283
+ console.log(chalk.gray(`使用已选缓存覆盖同步(如需调整请加 --no-cache):`))
284
+ console.log(chalk.gray(` ${selectedSkills.length} skills, ${selectedRules.length} rules, ${selectedCommands.length} commands, ${selectedHooks.length} hooks\n`))
285
+ } else {
286
+ // 交互模式:已选项默认勾选
287
+ if (useCache && !hasAnyExisting) {
288
+ console.log(chalk.gray('首次同步,进入交互式选择...\n'))
289
+ }
290
+ selectedSkills = await promptSelection(skills, 'Skills', existingSkills)
291
+ selectedRules = await promptSelection(rules, 'Rules', existingRules)
292
+ selectedCommands = await promptSelection(commands, 'Commands', existingCommands)
293
+ selectedHooks = await promptSelection(hooks, 'Hooks', existingHooks)
294
+ }
260
295
 
261
296
  const totalSelected = selectedSkills.length + selectedRules.length + selectedCommands.length + selectedHooks.length
262
297
  if (totalSelected === 0) {
263
- console.log(chalk.yellow('\nNo skills/rules/commands selected.'))
298
+ console.log(chalk.yellow('\nNo skills/rules/commands/hooks selected.'))
264
299
  }
265
300
 
266
301
  console.log(chalk.blue(`\nSyncing to ${projectTargetDir}...\n`))