@claude-code-hooks/cli 0.1.16 → 0.1.18
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/package.json +2 -2
- package/src/cli.js +54 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@claude-code-hooks/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"description": "Wizard CLI to set up and manage @claude-code-hooks packages for Claude Code.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/beefiker/claude-code-hooks/tree/main/packages/cli",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@clack/prompts": "^1.0.0",
|
|
30
|
-
"@claude-code-hooks/core": "^0.1.
|
|
30
|
+
"@claude-code-hooks/core": "^0.1.10",
|
|
31
31
|
"@claude-code-hooks/security": "^0.1.8",
|
|
32
32
|
"@claude-code-hooks/secrets": "^0.1.9",
|
|
33
33
|
"@claude-code-hooks/sound": "^0.2.12",
|
package/src/cli.js
CHANGED
|
@@ -97,7 +97,7 @@ function showWelcome() {
|
|
|
97
97
|
process.stdout.write(particleLine(0));
|
|
98
98
|
process.stdout.write(line + pad);
|
|
99
99
|
process.stdout.write(pad);
|
|
100
|
-
process.stdout.write(` ${icon} ${pc.blue(pc.bold('
|
|
100
|
+
process.stdout.write(` ${icon} ${pc.blue(pc.bold(t('cli.welcomeTitle')))}${version ? pc.gray(version) : ''}\n`);
|
|
101
101
|
process.stdout.write(pad);
|
|
102
102
|
process.stdout.write(` ${pc.brightCyan('Customize Claude Code with zero dependencies')}\n`);
|
|
103
103
|
process.stdout.write(pad);
|
|
@@ -206,9 +206,12 @@ async function main() {
|
|
|
206
206
|
const projectDir = process.cwd();
|
|
207
207
|
|
|
208
208
|
showWelcome();
|
|
209
|
-
note(t('cli.navHint'), t('cli.navTitle'));
|
|
210
209
|
|
|
211
|
-
|
|
210
|
+
/** Build step header: "Step N/5 — <title> (ESC exit · Backspace back)" */
|
|
211
|
+
const stepHeader = (n, title) =>
|
|
212
|
+
pc.dim(t('cli.stepHeader', { n, title, suffix: t('cli.stepHeaderSuffix') }));
|
|
213
|
+
|
|
214
|
+
// ── Step 1–5: action, target, packages, configure, review (Backspace = go to previous step) ──
|
|
212
215
|
let action;
|
|
213
216
|
let target;
|
|
214
217
|
let selected;
|
|
@@ -226,7 +229,7 @@ async function main() {
|
|
|
226
229
|
while (true) {
|
|
227
230
|
if (step === 1) {
|
|
228
231
|
action = await select({
|
|
229
|
-
message:
|
|
232
|
+
message: stepHeader(1, t('cli.step1ChooseAction')),
|
|
230
233
|
options: [
|
|
231
234
|
{ value: 'setup', label: t('cli.actionSetup') },
|
|
232
235
|
{ value: 'uninstall', label: t('cli.actionUninstall') },
|
|
@@ -241,7 +244,7 @@ async function main() {
|
|
|
241
244
|
const targetCtrl = new AbortController();
|
|
242
245
|
const { result: targetResult, wentBack: targetBack } = await withBackspaceBack(targetCtrl, () =>
|
|
243
246
|
select({
|
|
244
|
-
message:
|
|
247
|
+
message: stepHeader(2, t('cli.step2ChooseTarget')),
|
|
245
248
|
options: [
|
|
246
249
|
{ value: 'global', label: t('cli.targetGlobal') },
|
|
247
250
|
{ value: 'project', label: t('common.scopeProject') },
|
|
@@ -263,7 +266,7 @@ async function main() {
|
|
|
263
266
|
const pkgsCtrl = new AbortController();
|
|
264
267
|
const { result: pkgsResult, wentBack: pkgsBack } = await withBackspaceBack(pkgsCtrl, () =>
|
|
265
268
|
multiselect({
|
|
266
|
-
message:
|
|
269
|
+
message: stepHeader(3, t('cli.step3SelectPackages')),
|
|
267
270
|
options: packageOptions,
|
|
268
271
|
required: true,
|
|
269
272
|
validate: (v) => (!v || v.length === 0) ? t('common.selectAtLeastOne') : true,
|
|
@@ -282,7 +285,7 @@ async function main() {
|
|
|
282
285
|
if (step === 4) {
|
|
283
286
|
const proceedCtrl = new AbortController();
|
|
284
287
|
const { result: proceedResult, wentBack: proceedBack } = await withBackspaceBack(proceedCtrl, () =>
|
|
285
|
-
confirm({ message: t('cli.configureNow'), initialValue: true, active: t('common.yes'), inactive: t('common.no'), signal: proceedCtrl.signal })
|
|
288
|
+
confirm({ message: stepHeader(4, t('cli.configureNow')), initialValue: true, active: t('common.yes'), inactive: t('common.no'), signal: proceedCtrl.signal })
|
|
286
289
|
);
|
|
287
290
|
if (proceedBack) {
|
|
288
291
|
step = 3;
|
|
@@ -321,19 +324,19 @@ async function main() {
|
|
|
321
324
|
|
|
322
325
|
// ── Step 4/5: configure (highlight current package) ──
|
|
323
326
|
if (selected.includes('security')) {
|
|
324
|
-
note(formatPackageList('security'),
|
|
327
|
+
note(formatPackageList('security'), stepHeader(4, t('cli.step4Configure')));
|
|
325
328
|
perPackage.security = await planSecuritySetup({ action, projectDir, ui: 'umbrella' });
|
|
326
329
|
}
|
|
327
330
|
if (selected.includes('secrets')) {
|
|
328
|
-
note(formatPackageList('secrets'),
|
|
331
|
+
note(formatPackageList('secrets'), stepHeader(4, t('cli.step4Configure')));
|
|
329
332
|
perPackage.secrets = await planSecretsSetup({ action, projectDir, ui: 'umbrella' });
|
|
330
333
|
}
|
|
331
334
|
if (selected.includes('sound')) {
|
|
332
|
-
note(formatPackageList('sound'),
|
|
335
|
+
note(formatPackageList('sound'), stepHeader(4, t('cli.step4Configure')));
|
|
333
336
|
perPackage.sound = await planSoundSetup({ action, projectDir, ui: 'umbrella' });
|
|
334
337
|
}
|
|
335
338
|
if (selected.includes('notification')) {
|
|
336
|
-
note(formatPackageList('notification'),
|
|
339
|
+
note(formatPackageList('notification'), stepHeader(4, t('cli.step4Configure')));
|
|
337
340
|
perPackage.notification = await planNotificationSetup({ action, projectDir, ui: 'umbrella' });
|
|
338
341
|
}
|
|
339
342
|
|
|
@@ -355,10 +358,11 @@ async function main() {
|
|
|
355
358
|
|
|
356
359
|
note(
|
|
357
360
|
[
|
|
358
|
-
|
|
361
|
+
stepHeader(5, t('cli.step5Review')),
|
|
359
362
|
'',
|
|
360
|
-
`${t('cli.
|
|
361
|
-
|
|
363
|
+
`${pc.bold(t('cli.reviewSectionActionTarget'))}`,
|
|
364
|
+
` ${t('cli.reviewAction')}: ${pc.bold(action)}`,
|
|
365
|
+
` ${t('cli.reviewTarget')}: ${pc.bold(
|
|
362
366
|
target === 'global' ? t('cli.reviewTargetGlobal') :
|
|
363
367
|
target === 'project' ? t('cli.reviewTargetProject') :
|
|
364
368
|
t('cli.reviewTargetProjectLocal')
|
|
@@ -373,10 +377,10 @@ async function main() {
|
|
|
373
377
|
t('cli.step5Review')
|
|
374
378
|
);
|
|
375
379
|
|
|
376
|
-
|
|
380
|
+
const applyCtrl = new AbortController();
|
|
377
381
|
const { result: applyResult, wentBack: applyBack } = await withBackspaceBack(applyCtrl, () =>
|
|
378
382
|
select({
|
|
379
|
-
message: t('cli.applyChanges'),
|
|
383
|
+
message: stepHeader(5, t('cli.applyChanges')),
|
|
380
384
|
options: [
|
|
381
385
|
{ value: 'yes', label: t('cli.applyYes') },
|
|
382
386
|
{ value: 'cancel', label: t('cli.applyCancel') }
|
|
@@ -395,34 +399,40 @@ async function main() {
|
|
|
395
399
|
|
|
396
400
|
// Global / project / projectLocal apply: read settings.json, apply transforms, write once.
|
|
397
401
|
const settingsPath = configPathForScope(target, projectDir);
|
|
402
|
+
const pkgLabels = {
|
|
403
|
+
security: t('cli.pkgSecurity'),
|
|
404
|
+
secrets: t('cli.pkgSecrets'),
|
|
405
|
+
sound: t('cli.pkgSound'),
|
|
406
|
+
notification: t('cli.pkgNotification')
|
|
407
|
+
};
|
|
408
|
+
const s = spinner();
|
|
409
|
+
s.start(t('cli.applyingChanges'));
|
|
410
|
+
|
|
398
411
|
const res = await readJsonIfExists(settingsPath);
|
|
399
412
|
if (!res.ok) {
|
|
413
|
+
s.stop(t('cli.done'));
|
|
400
414
|
cancel(t('cli.couldNotReadJson', { path: settingsPath }));
|
|
401
415
|
process.exit(1);
|
|
402
416
|
}
|
|
403
|
-
|
|
404
417
|
let settings = res.value;
|
|
405
418
|
|
|
406
|
-
const s = spinner();
|
|
407
|
-
s.start(t('cli.applyingChanges'));
|
|
408
|
-
|
|
409
419
|
for (const key of selected) {
|
|
410
420
|
const plan = perPackage[key];
|
|
411
421
|
if (!plan) continue;
|
|
422
|
+
const pkgName = pkgLabels[key] ?? key;
|
|
423
|
+
s.message(t('cli.applyStepApplyPackage', { packageName: pkgName }));
|
|
412
424
|
settings = await plan.applyToSettings(settings);
|
|
413
425
|
}
|
|
414
426
|
|
|
415
|
-
|
|
427
|
+
s.message(t('cli.applyStepWriteSettings'));
|
|
416
428
|
settings = removeLegacyClaudeSoundHooks(settings);
|
|
417
|
-
|
|
418
429
|
await writeJson(settingsPath, settings);
|
|
419
|
-
|
|
420
430
|
if (target === 'projectLocal') {
|
|
421
431
|
await ensureGitignoreLocalEntry(projectDir);
|
|
422
432
|
}
|
|
423
433
|
|
|
424
|
-
// Update project config only on setup.
|
|
425
434
|
if (action === 'setup') {
|
|
435
|
+
s.message(t('cli.applyStepWriteProjectConfig'));
|
|
426
436
|
await ensureProjectOnlyConfig(projectDir, selected, {
|
|
427
437
|
security: perPackage.security?.projectConfigSection,
|
|
428
438
|
secrets: perPackage.secrets?.projectConfigSection,
|
|
@@ -430,9 +440,27 @@ async function main() {
|
|
|
430
440
|
notification: perPackage.notification?.projectConfigSection
|
|
431
441
|
});
|
|
432
442
|
}
|
|
443
|
+
s.stop('');
|
|
444
|
+
|
|
445
|
+
// Build contextual completion note
|
|
446
|
+
const traits = [];
|
|
447
|
+
if (selected.includes('security') || selected.includes('secrets')) traits.push(t('cli.doneTraitSafer'));
|
|
448
|
+
if (selected.includes('sound')) traits.push(t('cli.doneTraitLouder'));
|
|
449
|
+
if (selected.includes('notification')) traits.push(t('cli.doneTraitAttentive'));
|
|
450
|
+
|
|
451
|
+
const lines = [];
|
|
452
|
+
lines.push(`${t('cli.saved')}: ${pc.cyan(settingsPath)}`);
|
|
453
|
+
lines.push(`${t('cli.reviewPackages')}: ${selected.map((k) => pc.green(pkgLabels[k] ?? k)).join(', ')}`);
|
|
454
|
+
|
|
455
|
+
if (traits.length > 0) {
|
|
456
|
+
const joined = traits.length === 1
|
|
457
|
+
? traits[0]
|
|
458
|
+
: traits.slice(0, -1).join(', ') + ' & ' + traits[traits.length - 1];
|
|
459
|
+
lines.push('');
|
|
460
|
+
lines.push(pc.bold(t('cli.doneWithTraits', { traits: joined })));
|
|
461
|
+
}
|
|
433
462
|
|
|
434
|
-
|
|
435
|
-
outro(`${t('cli.saved')}: ${pc.bold(settingsPath)}`);
|
|
463
|
+
note(lines.join('\n'), t('cli.doneNoteTitle'));
|
|
436
464
|
}
|
|
437
465
|
|
|
438
466
|
main().catch((err) => {
|