@qazuor/claude-code-config 0.4.0 → 0.5.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 +289 -9
- package/dist/bin.cjs +2203 -40
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +2203 -40
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs +2 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +282 -1
- package/dist/index.d.ts +282 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
- package/templates/docs/_registry.json +54 -0
- package/templates/docs/standards/code-standards.md +20 -0
- package/templates/docs/standards/design-standards.md +13 -0
- package/templates/docs/standards/documentation-standards.md +13 -0
- package/templates/docs/standards/performance-standards.md +524 -0
- package/templates/docs/standards/security-standards.md +496 -0
- package/templates/docs/standards/testing-standards.md +15 -0
package/dist/bin.js
CHANGED
|
@@ -207,7 +207,7 @@ import { createRequire } from "module";
|
|
|
207
207
|
|
|
208
208
|
// src/cli/index.ts
|
|
209
209
|
init_esm_shims();
|
|
210
|
-
import { Command as
|
|
210
|
+
import { Command as Command9 } from "commander";
|
|
211
211
|
|
|
212
212
|
// src/cli/commands/index.ts
|
|
213
213
|
init_esm_shims();
|
|
@@ -2571,7 +2571,7 @@ init_esm_shims();
|
|
|
2571
2571
|
// src/lib/config/reader.ts
|
|
2572
2572
|
init_esm_shims();
|
|
2573
2573
|
init_fs();
|
|
2574
|
-
var CONFIG_FILE = "config.json";
|
|
2574
|
+
var CONFIG_FILE = "qazuor-claude-config.json";
|
|
2575
2575
|
var CLAUDE_DIR = ".claude";
|
|
2576
2576
|
async function readConfig(projectPath) {
|
|
2577
2577
|
const configPath = joinPath(projectPath, CLAUDE_DIR, CONFIG_FILE);
|
|
@@ -2593,7 +2593,7 @@ async function hasClaudeDir(projectPath) {
|
|
|
2593
2593
|
// src/lib/config/writer.ts
|
|
2594
2594
|
init_esm_shims();
|
|
2595
2595
|
init_fs();
|
|
2596
|
-
var CONFIG_FILE2 = "config.json";
|
|
2596
|
+
var CONFIG_FILE2 = "qazuor-claude-config.json";
|
|
2597
2597
|
var CLAUDE_DIR2 = ".claude";
|
|
2598
2598
|
async function writeConfig(projectPath, config, options) {
|
|
2599
2599
|
const claudePath = joinPath(projectPath, CLAUDE_DIR2);
|
|
@@ -3235,21 +3235,333 @@ init_esm_shims();
|
|
|
3235
3235
|
// src/lib/git-hooks/husky-installer.ts
|
|
3236
3236
|
init_esm_shims();
|
|
3237
3237
|
init_fs();
|
|
3238
|
-
|
|
3238
|
+
|
|
3239
|
+
// src/lib/git-hooks/precommit-generator.ts
|
|
3240
|
+
init_esm_shims();
|
|
3241
|
+
function generatePreCommitScript(config) {
|
|
3242
|
+
if (!config.enabled) {
|
|
3243
|
+
return generateDisabledScript();
|
|
3244
|
+
}
|
|
3245
|
+
const sections = [];
|
|
3246
|
+
sections.push(generateHeader());
|
|
3247
|
+
if (config.showTiming) {
|
|
3248
|
+
sections.push(generateTimingSetup());
|
|
3249
|
+
}
|
|
3250
|
+
sections.push(generateErrorHandling(config.continueOnFailure));
|
|
3251
|
+
if (config.lint.enabled) {
|
|
3252
|
+
sections.push(generateLintSection(config));
|
|
3253
|
+
}
|
|
3254
|
+
if (config.typecheck.enabled) {
|
|
3255
|
+
sections.push(generateTypecheckSection(config));
|
|
3256
|
+
}
|
|
3257
|
+
if (config.formatCheck.enabled) {
|
|
3258
|
+
sections.push(generateFormatCheckSection(config));
|
|
3259
|
+
}
|
|
3260
|
+
if (config.tests.enabled && config.tests.mode !== "none") {
|
|
3261
|
+
sections.push(generateTestSection(config));
|
|
3262
|
+
}
|
|
3263
|
+
const sortedCustom = [...config.customCommands].sort(
|
|
3264
|
+
(a, b) => (a.order ?? 100) - (b.order ?? 100)
|
|
3265
|
+
);
|
|
3266
|
+
for (const cmd of sortedCustom) {
|
|
3267
|
+
sections.push(generateCustomCommandSection(cmd, config));
|
|
3268
|
+
}
|
|
3269
|
+
sections.push(generateFooter(config));
|
|
3270
|
+
return sections.join("\n\n");
|
|
3271
|
+
}
|
|
3272
|
+
function generateDisabledScript() {
|
|
3239
3273
|
return `#!/usr/bin/env sh
|
|
3240
3274
|
. "$(dirname -- "$0")/_/husky.sh"
|
|
3241
3275
|
|
|
3242
|
-
|
|
3243
|
-
`;
|
|
3276
|
+
# Pre-commit hook disabled
|
|
3277
|
+
exit 0`;
|
|
3244
3278
|
}
|
|
3245
|
-
function
|
|
3246
|
-
const command = lintCommand || "pnpm lint-staged";
|
|
3279
|
+
function generateHeader() {
|
|
3247
3280
|
return `#!/usr/bin/env sh
|
|
3248
3281
|
. "$(dirname -- "$0")/_/husky.sh"
|
|
3249
3282
|
|
|
3250
|
-
|
|
3283
|
+
# Pre-commit hook - Generated by @qazuor/claude-code-config
|
|
3284
|
+
# Bypass with: git commit --no-verify -m "message"
|
|
3285
|
+
|
|
3286
|
+
echo "\u{1F50D} Running pre-commit checks..."`;
|
|
3287
|
+
}
|
|
3288
|
+
function generateTimingSetup() {
|
|
3289
|
+
return `# Timing setup
|
|
3290
|
+
START_TIME=$(date +%s)
|
|
3291
|
+
step_start() { STEP_START=$(date +%s); }
|
|
3292
|
+
step_end() {
|
|
3293
|
+
STEP_END=$(date +%s)
|
|
3294
|
+
ELAPSED_TIME=$((STEP_END - STEP_START))
|
|
3295
|
+
echo " \u23F1\uFE0F Completed in \${ELAPSED_TIME}s"
|
|
3296
|
+
}`;
|
|
3297
|
+
}
|
|
3298
|
+
function generateErrorHandling(continueOnFailure) {
|
|
3299
|
+
if (continueOnFailure) {
|
|
3300
|
+
return `# Error tracking (continue on failure mode)
|
|
3301
|
+
ERRORS=0
|
|
3302
|
+
track_error() {
|
|
3303
|
+
ERRORS=$((ERRORS + 1))
|
|
3304
|
+
}`;
|
|
3305
|
+
}
|
|
3306
|
+
return `# Fail fast mode - exit on first error
|
|
3307
|
+
set -e`;
|
|
3308
|
+
}
|
|
3309
|
+
function generateLintSection(config) {
|
|
3310
|
+
const lint = config.lint;
|
|
3311
|
+
let command;
|
|
3312
|
+
if (lint.command) {
|
|
3313
|
+
command = lint.command;
|
|
3314
|
+
} else if (lint.stagedOnly) {
|
|
3315
|
+
command = getLintStagedCommand(lint.tool);
|
|
3316
|
+
} else {
|
|
3317
|
+
command = getLintCommand(lint.tool);
|
|
3318
|
+
}
|
|
3319
|
+
const lines = [];
|
|
3320
|
+
lines.push("# Linting");
|
|
3321
|
+
lines.push('echo ""');
|
|
3322
|
+
lines.push('echo "\u{1F4DD} Linting..."');
|
|
3323
|
+
if (config.showTiming) {
|
|
3324
|
+
lines.push("step_start");
|
|
3325
|
+
}
|
|
3326
|
+
if (lint.allowFailure) {
|
|
3327
|
+
lines.push(`if ${command}; then`);
|
|
3328
|
+
lines.push(' echo " \u2705 Lint passed"');
|
|
3329
|
+
lines.push("else");
|
|
3330
|
+
lines.push(' echo " \u26A0\uFE0F Lint warnings (non-blocking)"');
|
|
3331
|
+
lines.push("fi");
|
|
3332
|
+
} else if (config.continueOnFailure) {
|
|
3333
|
+
lines.push(`if ${command}; then`);
|
|
3334
|
+
lines.push(' echo " \u2705 Lint passed"');
|
|
3335
|
+
lines.push("else");
|
|
3336
|
+
lines.push(' echo " \u274C Lint failed"');
|
|
3337
|
+
lines.push(" track_error");
|
|
3338
|
+
lines.push("fi");
|
|
3339
|
+
} else {
|
|
3340
|
+
lines.push(`${command} || { echo " \u274C Lint failed"; exit 1; }`);
|
|
3341
|
+
lines.push('echo " \u2705 Lint passed"');
|
|
3342
|
+
}
|
|
3343
|
+
if (config.showTiming) {
|
|
3344
|
+
lines.push("step_end");
|
|
3345
|
+
}
|
|
3346
|
+
return lines.join("\n");
|
|
3347
|
+
}
|
|
3348
|
+
function getLintStagedCommand(tool) {
|
|
3349
|
+
switch (tool) {
|
|
3350
|
+
case "biome":
|
|
3351
|
+
return "pnpm biome check --staged --no-errors-on-unmatched";
|
|
3352
|
+
case "eslint":
|
|
3353
|
+
return "pnpm lint-staged";
|
|
3354
|
+
default:
|
|
3355
|
+
return "pnpm lint-staged";
|
|
3356
|
+
}
|
|
3357
|
+
}
|
|
3358
|
+
function getLintCommand(tool) {
|
|
3359
|
+
switch (tool) {
|
|
3360
|
+
case "biome":
|
|
3361
|
+
return "pnpm biome check .";
|
|
3362
|
+
case "eslint":
|
|
3363
|
+
return "pnpm eslint .";
|
|
3364
|
+
default:
|
|
3365
|
+
return "pnpm lint";
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
function generateTypecheckSection(config) {
|
|
3369
|
+
const typecheck = config.typecheck;
|
|
3370
|
+
const command = typecheck.command ?? "pnpm typecheck";
|
|
3371
|
+
const lines = [];
|
|
3372
|
+
lines.push("# Type checking");
|
|
3373
|
+
lines.push('echo ""');
|
|
3374
|
+
lines.push('echo "\u{1F537} Type checking..."');
|
|
3375
|
+
if (config.showTiming) {
|
|
3376
|
+
lines.push("step_start");
|
|
3377
|
+
}
|
|
3378
|
+
if (typecheck.allowFailure) {
|
|
3379
|
+
lines.push(`if ${command}; then`);
|
|
3380
|
+
lines.push(' echo " \u2705 Types OK"');
|
|
3381
|
+
lines.push("else");
|
|
3382
|
+
lines.push(' echo " \u26A0\uFE0F Type warnings (non-blocking)"');
|
|
3383
|
+
lines.push("fi");
|
|
3384
|
+
} else if (config.continueOnFailure) {
|
|
3385
|
+
lines.push(`if ${command}; then`);
|
|
3386
|
+
lines.push(' echo " \u2705 Types OK"');
|
|
3387
|
+
lines.push("else");
|
|
3388
|
+
lines.push(' echo " \u274C Type check failed"');
|
|
3389
|
+
lines.push(" track_error");
|
|
3390
|
+
lines.push("fi");
|
|
3391
|
+
} else {
|
|
3392
|
+
lines.push(`${command} || { echo " \u274C Type check failed"; exit 1; }`);
|
|
3393
|
+
lines.push('echo " \u2705 Types OK"');
|
|
3394
|
+
}
|
|
3395
|
+
if (config.showTiming) {
|
|
3396
|
+
lines.push("step_end");
|
|
3397
|
+
}
|
|
3398
|
+
return lines.join("\n");
|
|
3399
|
+
}
|
|
3400
|
+
function generateFormatCheckSection(config) {
|
|
3401
|
+
const format = config.formatCheck;
|
|
3402
|
+
let command;
|
|
3403
|
+
if (format.command) {
|
|
3404
|
+
command = format.command;
|
|
3405
|
+
} else {
|
|
3406
|
+
command = getFormatCheckCommand(format.tool);
|
|
3407
|
+
}
|
|
3408
|
+
const lines = [];
|
|
3409
|
+
lines.push("# Format check");
|
|
3410
|
+
lines.push('echo ""');
|
|
3411
|
+
lines.push('echo "\u2728 Format check..."');
|
|
3412
|
+
if (config.showTiming) {
|
|
3413
|
+
lines.push("step_start");
|
|
3414
|
+
}
|
|
3415
|
+
if (format.allowFailure) {
|
|
3416
|
+
lines.push(`if ${command}; then`);
|
|
3417
|
+
lines.push(' echo " \u2705 Format OK"');
|
|
3418
|
+
lines.push("else");
|
|
3419
|
+
lines.push(' echo " \u26A0\uFE0F Format warnings (non-blocking)"');
|
|
3420
|
+
lines.push("fi");
|
|
3421
|
+
} else if (config.continueOnFailure) {
|
|
3422
|
+
lines.push(`if ${command}; then`);
|
|
3423
|
+
lines.push(' echo " \u2705 Format OK"');
|
|
3424
|
+
lines.push("else");
|
|
3425
|
+
lines.push(' echo " \u274C Format check failed"');
|
|
3426
|
+
lines.push(" track_error");
|
|
3427
|
+
lines.push("fi");
|
|
3428
|
+
} else {
|
|
3429
|
+
lines.push(`${command} || { echo " \u274C Format check failed"; exit 1; }`);
|
|
3430
|
+
lines.push('echo " \u2705 Format OK"');
|
|
3431
|
+
}
|
|
3432
|
+
if (config.showTiming) {
|
|
3433
|
+
lines.push("step_end");
|
|
3434
|
+
}
|
|
3435
|
+
return lines.join("\n");
|
|
3436
|
+
}
|
|
3437
|
+
function getFormatCheckCommand(tool) {
|
|
3438
|
+
switch (tool) {
|
|
3439
|
+
case "biome":
|
|
3440
|
+
return "pnpm biome format --check .";
|
|
3441
|
+
case "prettier":
|
|
3442
|
+
return "pnpm prettier --check .";
|
|
3443
|
+
default:
|
|
3444
|
+
return "pnpm format:check";
|
|
3445
|
+
}
|
|
3446
|
+
}
|
|
3447
|
+
function generateTestSection(config) {
|
|
3448
|
+
const tests = config.tests;
|
|
3449
|
+
let command;
|
|
3450
|
+
if (tests.command) {
|
|
3451
|
+
command = tests.command;
|
|
3452
|
+
} else if (tests.mode === "affected") {
|
|
3453
|
+
command = "pnpm vitest related --run";
|
|
3454
|
+
} else {
|
|
3455
|
+
command = "pnpm test";
|
|
3456
|
+
}
|
|
3457
|
+
if (tests.coverageThreshold > 0) {
|
|
3458
|
+
command = `${command} --coverage --coverage.thresholds.lines=${tests.coverageThreshold}`;
|
|
3459
|
+
}
|
|
3460
|
+
const lines = [];
|
|
3461
|
+
lines.push("# Tests");
|
|
3462
|
+
lines.push('echo ""');
|
|
3463
|
+
lines.push(`echo "\u{1F9EA} Running ${tests.mode === "affected" ? "affected" : "all"} tests..."`);
|
|
3464
|
+
if (config.showTiming) {
|
|
3465
|
+
lines.push("step_start");
|
|
3466
|
+
}
|
|
3467
|
+
if (tests.allowFailure) {
|
|
3468
|
+
lines.push(`if ${command}; then`);
|
|
3469
|
+
lines.push(' echo " \u2705 Tests passed"');
|
|
3470
|
+
lines.push("else");
|
|
3471
|
+
lines.push(' echo " \u26A0\uFE0F Test warnings (non-blocking)"');
|
|
3472
|
+
lines.push("fi");
|
|
3473
|
+
} else if (config.continueOnFailure) {
|
|
3474
|
+
lines.push(`if ${command}; then`);
|
|
3475
|
+
lines.push(' echo " \u2705 Tests passed"');
|
|
3476
|
+
lines.push("else");
|
|
3477
|
+
lines.push(' echo " \u274C Tests failed"');
|
|
3478
|
+
lines.push(" track_error");
|
|
3479
|
+
lines.push("fi");
|
|
3480
|
+
} else {
|
|
3481
|
+
lines.push(`${command} || { echo " \u274C Tests failed"; exit 1; }`);
|
|
3482
|
+
lines.push('echo " \u2705 Tests passed"');
|
|
3483
|
+
}
|
|
3484
|
+
if (config.showTiming) {
|
|
3485
|
+
lines.push("step_end");
|
|
3486
|
+
}
|
|
3487
|
+
return lines.join("\n");
|
|
3488
|
+
}
|
|
3489
|
+
function generateCustomCommandSection(cmd, config) {
|
|
3490
|
+
const lines = [];
|
|
3491
|
+
lines.push(`# Custom: ${cmd.name}`);
|
|
3492
|
+
lines.push('echo ""');
|
|
3493
|
+
lines.push(`echo "\u{1F527} ${cmd.name}..."`);
|
|
3494
|
+
if (config.showTiming) {
|
|
3495
|
+
lines.push("step_start");
|
|
3496
|
+
}
|
|
3497
|
+
if (cmd.allowFailure) {
|
|
3498
|
+
lines.push(`if ${cmd.command}; then`);
|
|
3499
|
+
lines.push(` echo " \u2705 ${cmd.name} passed"`);
|
|
3500
|
+
lines.push("else");
|
|
3501
|
+
lines.push(` echo " \u26A0\uFE0F ${cmd.name} warnings (non-blocking)"`);
|
|
3502
|
+
lines.push("fi");
|
|
3503
|
+
} else if (config.continueOnFailure) {
|
|
3504
|
+
lines.push(`if ${cmd.command}; then`);
|
|
3505
|
+
lines.push(` echo " \u2705 ${cmd.name} passed"`);
|
|
3506
|
+
lines.push("else");
|
|
3507
|
+
lines.push(` echo " \u274C ${cmd.name} failed"`);
|
|
3508
|
+
lines.push(" track_error");
|
|
3509
|
+
lines.push("fi");
|
|
3510
|
+
} else {
|
|
3511
|
+
lines.push(`${cmd.command} || { echo " \u274C ${cmd.name} failed"; exit 1; }`);
|
|
3512
|
+
lines.push(`echo " \u2705 ${cmd.name} passed"`);
|
|
3513
|
+
}
|
|
3514
|
+
if (config.showTiming) {
|
|
3515
|
+
lines.push("step_end");
|
|
3516
|
+
}
|
|
3517
|
+
return lines.join("\n");
|
|
3518
|
+
}
|
|
3519
|
+
function generateFooter(config) {
|
|
3520
|
+
const lines = [];
|
|
3521
|
+
lines.push("# Final status");
|
|
3522
|
+
lines.push('echo ""');
|
|
3523
|
+
if (config.showTiming) {
|
|
3524
|
+
lines.push("END_TIME=$(date +%s)");
|
|
3525
|
+
lines.push("TOTAL_TIME=$((END_TIME - START_TIME))");
|
|
3526
|
+
}
|
|
3527
|
+
if (config.continueOnFailure) {
|
|
3528
|
+
lines.push("if [ $ERRORS -gt 0 ]; then");
|
|
3529
|
+
lines.push(' echo "\u274C Pre-commit failed with $ERRORS error(s)"');
|
|
3530
|
+
if (config.showTiming) {
|
|
3531
|
+
lines.push(' echo "\u23F1\uFE0F Total time: ${TOTAL_TIME}s"');
|
|
3532
|
+
}
|
|
3533
|
+
lines.push(" exit 1");
|
|
3534
|
+
lines.push("fi");
|
|
3535
|
+
}
|
|
3536
|
+
if (config.showTiming) {
|
|
3537
|
+
lines.push('echo "\u2728 All checks passed! (${TOTAL_TIME}s)"');
|
|
3538
|
+
} else {
|
|
3539
|
+
lines.push('echo "\u2728 All checks passed!"');
|
|
3540
|
+
}
|
|
3541
|
+
return lines.join("\n");
|
|
3542
|
+
}
|
|
3543
|
+
function generateSimplePreCommitHook(command) {
|
|
3544
|
+
return `#!/usr/bin/env sh
|
|
3545
|
+
. "$(dirname -- "$0")/_/husky.sh"
|
|
3546
|
+
|
|
3547
|
+
${command}`;
|
|
3548
|
+
}
|
|
3549
|
+
|
|
3550
|
+
// src/lib/git-hooks/husky-installer.ts
|
|
3551
|
+
function generateCommitMsgHook() {
|
|
3552
|
+
return `#!/usr/bin/env sh
|
|
3553
|
+
. "$(dirname -- "$0")/_/husky.sh"
|
|
3554
|
+
|
|
3555
|
+
npx --no -- commitlint --edit "\${1}"
|
|
3251
3556
|
`;
|
|
3252
3557
|
}
|
|
3558
|
+
function generatePreCommitHook(lintCommand, preCommitConfig) {
|
|
3559
|
+
if (preCommitConfig) {
|
|
3560
|
+
return generatePreCommitScript(preCommitConfig);
|
|
3561
|
+
}
|
|
3562
|
+
const command = lintCommand || "pnpm lint-staged";
|
|
3563
|
+
return generateSimplePreCommitHook(command);
|
|
3564
|
+
}
|
|
3253
3565
|
function generatePrePushHook(testCommand) {
|
|
3254
3566
|
const command = testCommand || "pnpm test";
|
|
3255
3567
|
return `#!/usr/bin/env sh
|
|
@@ -3340,7 +3652,10 @@ async function installHusky(projectPath, config, options) {
|
|
|
3340
3652
|
if (config.preCommit) {
|
|
3341
3653
|
const preCommitPath = joinPath(huskyDir, "pre-commit");
|
|
3342
3654
|
if (!await pathExists(preCommitPath) || options?.overwrite) {
|
|
3343
|
-
await writeFile(
|
|
3655
|
+
await writeFile(
|
|
3656
|
+
preCommitPath,
|
|
3657
|
+
generatePreCommitHook(config.lintCommand, config.preCommitConfig)
|
|
3658
|
+
);
|
|
3344
3659
|
await makeExecutable(preCommitPath);
|
|
3345
3660
|
result.created.push("pre-commit");
|
|
3346
3661
|
} else {
|
|
@@ -3572,8 +3887,8 @@ async function getHooksStatus(projectPath) {
|
|
|
3572
3887
|
let executable = false;
|
|
3573
3888
|
if (exists) {
|
|
3574
3889
|
try {
|
|
3575
|
-
const
|
|
3576
|
-
const stats = await
|
|
3890
|
+
const fs9 = await import("fs/promises");
|
|
3891
|
+
const stats = await fs9.stat(filePath);
|
|
3577
3892
|
executable = (stats.mode & 73) !== 0;
|
|
3578
3893
|
} catch {
|
|
3579
3894
|
}
|
|
@@ -10609,27 +10924,27 @@ async function buildConfigContext(projectPath) {
|
|
|
10609
10924
|
values: {}
|
|
10610
10925
|
};
|
|
10611
10926
|
try {
|
|
10612
|
-
const
|
|
10613
|
-
const
|
|
10614
|
-
const pkgPath =
|
|
10615
|
-
const pkgContent = await
|
|
10927
|
+
const fs9 = await import("fs/promises");
|
|
10928
|
+
const path11 = await import("path");
|
|
10929
|
+
const pkgPath = path11.join(projectPath, "package.json");
|
|
10930
|
+
const pkgContent = await fs9.readFile(pkgPath, "utf-8");
|
|
10616
10931
|
const pkg = JSON.parse(pkgContent);
|
|
10617
10932
|
context.scripts = pkg.scripts || {};
|
|
10618
10933
|
context.dependencies = {
|
|
10619
10934
|
...pkg.dependencies || {},
|
|
10620
10935
|
...pkg.devDependencies || {}
|
|
10621
10936
|
};
|
|
10622
|
-
context.hasTypeScript = Boolean(context.dependencies.typescript) || await fileExists(
|
|
10623
|
-
if (await fileExists(
|
|
10937
|
+
context.hasTypeScript = Boolean(context.dependencies.typescript) || await fileExists(path11.join(projectPath, "tsconfig.json"));
|
|
10938
|
+
if (await fileExists(path11.join(projectPath, "pnpm-lock.yaml"))) {
|
|
10624
10939
|
context.packageManager = "pnpm";
|
|
10625
|
-
} else if (await fileExists(
|
|
10940
|
+
} else if (await fileExists(path11.join(projectPath, "yarn.lock"))) {
|
|
10626
10941
|
context.packageManager = "yarn";
|
|
10627
|
-
} else if (await fileExists(
|
|
10942
|
+
} else if (await fileExists(path11.join(projectPath, "bun.lockb"))) {
|
|
10628
10943
|
context.packageManager = "bun";
|
|
10629
10944
|
} else {
|
|
10630
10945
|
context.packageManager = "npm";
|
|
10631
10946
|
}
|
|
10632
|
-
context.isGitRepo = await fileExists(
|
|
10947
|
+
context.isGitRepo = await fileExists(path11.join(projectPath, ".git"));
|
|
10633
10948
|
if (context.isGitRepo) {
|
|
10634
10949
|
try {
|
|
10635
10950
|
const { execSync } = await import("child_process");
|
|
@@ -10648,8 +10963,8 @@ async function buildConfigContext(projectPath) {
|
|
|
10648
10963
|
}
|
|
10649
10964
|
async function fileExists(filePath) {
|
|
10650
10965
|
try {
|
|
10651
|
-
const
|
|
10652
|
-
await
|
|
10966
|
+
const fs9 = await import("fs/promises");
|
|
10967
|
+
await fs9.access(filePath);
|
|
10653
10968
|
return true;
|
|
10654
10969
|
} catch {
|
|
10655
10970
|
return false;
|
|
@@ -11683,8 +11998,8 @@ function createInitCommand() {
|
|
|
11683
11998
|
).option("-t, --template <url>", "Remote git repo for templates").option("--branch <name>", "Branch/tag for remote template").option("-y, --yes", "Accept defaults, skip prompts").option("-f, --force", "Overwrite existing .claude/").option("--dry-run", "Show what would happen without making changes").option("--claude-only", "Only Claude config, no project scaffold").option("--no-placeholders", "Skip placeholder replacement").option("--no-mcp", "Skip MCP configuration").option("-v, --verbose", "Detailed output").action(runInit);
|
|
11684
11999
|
return cmd;
|
|
11685
12000
|
}
|
|
11686
|
-
async function runInit(
|
|
11687
|
-
const projectPath = resolvePath(
|
|
12001
|
+
async function runInit(path11, options) {
|
|
12002
|
+
const projectPath = resolvePath(path11 || ".");
|
|
11688
12003
|
logger.configure({ verbose: options.verbose, silent: false });
|
|
11689
12004
|
logger.title("@qazuor/claude-code-config");
|
|
11690
12005
|
logger.info(`Initializing Claude configuration in ${colors.primary(projectPath)}`);
|
|
@@ -11693,6 +12008,7 @@ async function runInit(path8, options) {
|
|
|
11693
12008
|
showCancelHint();
|
|
11694
12009
|
}
|
|
11695
12010
|
try {
|
|
12011
|
+
let existingConfig = null;
|
|
11696
12012
|
if (await hasExistingClaudeConfig(projectPath)) {
|
|
11697
12013
|
if (!options.force) {
|
|
11698
12014
|
const action = await promptExistingProjectAction();
|
|
@@ -11703,6 +12019,10 @@ async function runInit(path8, options) {
|
|
|
11703
12019
|
if (action !== "overwrite" && action !== "merge") {
|
|
11704
12020
|
return;
|
|
11705
12021
|
}
|
|
12022
|
+
existingConfig = await readConfig(projectPath);
|
|
12023
|
+
if (existingConfig) {
|
|
12024
|
+
logger.info("Using existing configuration as defaults");
|
|
12025
|
+
}
|
|
11706
12026
|
}
|
|
11707
12027
|
}
|
|
11708
12028
|
const detection = await detectProject(projectPath);
|
|
@@ -11719,7 +12039,7 @@ async function runInit(path8, options) {
|
|
|
11719
12039
|
() => loadRegistry(templatesPath),
|
|
11720
12040
|
{ silent: options.dryRun }
|
|
11721
12041
|
);
|
|
11722
|
-
const buildResult = options.yes ? await buildDefaultConfig(projectPath, detection, options) : await buildInteractiveConfig(projectPath, detection, registry, options);
|
|
12042
|
+
const buildResult = options.yes ? await buildDefaultConfig(projectPath, detection, options) : await buildInteractiveConfig(projectPath, detection, registry, options, existingConfig);
|
|
11723
12043
|
if (!buildResult) {
|
|
11724
12044
|
logger.warn("Configuration cancelled");
|
|
11725
12045
|
return;
|
|
@@ -11885,7 +12205,7 @@ async function buildDefaultConfig(projectPath, detection, options) {
|
|
|
11885
12205
|
// No MCP servers in default mode
|
|
11886
12206
|
};
|
|
11887
12207
|
}
|
|
11888
|
-
async function buildInteractiveConfig(projectPath, detection, registry, options) {
|
|
12208
|
+
async function buildInteractiveConfig(projectPath, detection, registry, options, existingConfig) {
|
|
11889
12209
|
const projectName = await getProjectName(projectPath);
|
|
11890
12210
|
const projectDesc = await getProjectDescription(projectPath);
|
|
11891
12211
|
const wizardConfig = createInitWizardConfig(
|
|
@@ -11899,24 +12219,45 @@ async function buildInteractiveConfig(projectPath, detection, registry, options)
|
|
|
11899
12219
|
},
|
|
11900
12220
|
registry
|
|
11901
12221
|
);
|
|
12222
|
+
const existingProject = existingConfig?.project;
|
|
12223
|
+
const existingPrefs = existingConfig?.preferences;
|
|
11902
12224
|
const initialContext = {
|
|
11903
12225
|
projectPath,
|
|
11904
12226
|
registry,
|
|
11905
12227
|
detection: {
|
|
11906
12228
|
detected: detection.detected,
|
|
11907
12229
|
projectType: detection.projectType,
|
|
11908
|
-
packageManager: detection.packageManager,
|
|
12230
|
+
packageManager: existingPrefs?.packageManager || detection.packageManager,
|
|
11909
12231
|
suggestedBundles: detection.suggestedBundles,
|
|
11910
12232
|
detectedTechnologies: detection.detectedTechnologies
|
|
11911
12233
|
},
|
|
12234
|
+
// Use existing project info as defaults, fallback to detected values
|
|
11912
12235
|
projectInfo: {
|
|
11913
|
-
name: projectName || "",
|
|
11914
|
-
description: projectDesc || "",
|
|
11915
|
-
org: "",
|
|
11916
|
-
repo: projectName?.toLowerCase().replace(/\s+/g, "-") || "",
|
|
11917
|
-
entityType: "item",
|
|
11918
|
-
entityTypePlural: "items"
|
|
11919
|
-
|
|
12236
|
+
name: existingProject?.name || projectName || "",
|
|
12237
|
+
description: existingProject?.description || projectDesc || "",
|
|
12238
|
+
org: existingProject?.org || "",
|
|
12239
|
+
repo: existingProject?.repo || projectName?.toLowerCase().replace(/\s+/g, "-") || "",
|
|
12240
|
+
entityType: existingProject?.entityType || "item",
|
|
12241
|
+
entityTypePlural: existingProject?.entityTypePlural || "items",
|
|
12242
|
+
domain: existingProject?.domain,
|
|
12243
|
+
location: existingProject?.location,
|
|
12244
|
+
author: existingProject?.author
|
|
12245
|
+
},
|
|
12246
|
+
// Use existing preferences as defaults
|
|
12247
|
+
preferences: existingPrefs ? {
|
|
12248
|
+
language: existingPrefs.language,
|
|
12249
|
+
responseLanguage: existingPrefs.responseLanguage,
|
|
12250
|
+
includeCoAuthor: existingPrefs.includeCoAuthor,
|
|
12251
|
+
packageManager: existingPrefs.packageManager
|
|
12252
|
+
} : void 0,
|
|
12253
|
+
// Use existing hook config as defaults
|
|
12254
|
+
hookConfig: existingConfig?.extras?.hooks,
|
|
12255
|
+
// Use existing code style config as defaults
|
|
12256
|
+
codeStyleConfig: existingConfig?.extras?.codeStyle,
|
|
12257
|
+
// Use existing folder preferences as defaults
|
|
12258
|
+
folderPreferences: existingConfig?.extras?.folderPreferences,
|
|
12259
|
+
// Use existing permissions config as defaults
|
|
12260
|
+
permissionsConfig: existingConfig?.customizations?.permissions
|
|
11920
12261
|
};
|
|
11921
12262
|
const wizardResult = await runWizard(
|
|
11922
12263
|
wizardConfig,
|
|
@@ -12642,7 +12983,7 @@ async function runStatus(options) {
|
|
|
12642
12983
|
}
|
|
12643
12984
|
const config = await readConfig(projectPath);
|
|
12644
12985
|
if (!config) {
|
|
12645
|
-
logger.warn(".claude directory exists but config.json is missing");
|
|
12986
|
+
logger.warn(".claude directory exists but qazuor-claude-config.json is missing");
|
|
12646
12987
|
logger.info('Run "claude-config init" to initialize properly');
|
|
12647
12988
|
process.exit(0);
|
|
12648
12989
|
}
|
|
@@ -13142,8 +13483,8 @@ function createConfigureCommand() {
|
|
|
13142
13483
|
).option("--preview", "Preview changes without applying").option("--show-defaults", "Show global defaults").option("-v, --verbose", "Detailed output").action(runConfigure);
|
|
13143
13484
|
return cmd;
|
|
13144
13485
|
}
|
|
13145
|
-
async function runConfigure(
|
|
13146
|
-
const projectPath = resolvePath(
|
|
13486
|
+
async function runConfigure(path11, options) {
|
|
13487
|
+
const projectPath = resolvePath(path11 || ".");
|
|
13147
13488
|
const claudePath = joinPath(projectPath, ".claude");
|
|
13148
13489
|
logger.configure({ verbose: options.verbose, silent: false });
|
|
13149
13490
|
logger.title("Template Configuration");
|
|
@@ -13274,16 +13615,1837 @@ async function interactiveMode(claudePath, projectPath, options) {
|
|
|
13274
13615
|
};
|
|
13275
13616
|
existingConfig.customizations.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
13276
13617
|
await writeConfig(projectPath, existingConfig);
|
|
13277
|
-
logger.success("Configuration saved to .claude/config.json");
|
|
13618
|
+
logger.success("Configuration saved to .claude/qazuor-claude-config.json");
|
|
13278
13619
|
}
|
|
13279
13620
|
await promptSaveGlobalDefaults(templateConfig);
|
|
13280
13621
|
logger.newline();
|
|
13281
13622
|
logger.success("Template configuration complete!");
|
|
13282
13623
|
}
|
|
13283
13624
|
|
|
13625
|
+
// src/cli/commands/standards.ts
|
|
13626
|
+
init_esm_shims();
|
|
13627
|
+
import { Command as Command8 } from "commander";
|
|
13628
|
+
|
|
13629
|
+
// src/constants/standards-defaults.ts
|
|
13630
|
+
init_esm_shims();
|
|
13631
|
+
var DEFAULT_CODE_STANDARDS = {
|
|
13632
|
+
indentStyle: "space",
|
|
13633
|
+
indentSize: 2,
|
|
13634
|
+
maxLineLength: 100,
|
|
13635
|
+
maxFileLines: 500,
|
|
13636
|
+
quoteStyle: "single",
|
|
13637
|
+
semicolons: true,
|
|
13638
|
+
trailingCommas: "es5",
|
|
13639
|
+
allowAny: false,
|
|
13640
|
+
namedExportsOnly: true,
|
|
13641
|
+
roroPattern: true,
|
|
13642
|
+
jsDocRequired: true
|
|
13643
|
+
};
|
|
13644
|
+
var DEFAULT_TESTING_STANDARDS = {
|
|
13645
|
+
coverageTarget: 80,
|
|
13646
|
+
tddRequired: true,
|
|
13647
|
+
testPattern: "aaa",
|
|
13648
|
+
testLocation: "separate",
|
|
13649
|
+
unitTestMaxMs: 100,
|
|
13650
|
+
integrationTestMaxMs: 1e3
|
|
13651
|
+
};
|
|
13652
|
+
var DEFAULT_DOCUMENTATION_STANDARDS = {
|
|
13653
|
+
jsDocLevel: "standard",
|
|
13654
|
+
requireExamples: false,
|
|
13655
|
+
changelogFormat: "conventional",
|
|
13656
|
+
inlineCommentPolicy: "why-not-what"
|
|
13657
|
+
};
|
|
13658
|
+
var DEFAULT_DESIGN_STANDARDS = {
|
|
13659
|
+
cssFramework: "tailwind",
|
|
13660
|
+
componentLibrary: "shadcn",
|
|
13661
|
+
accessibilityLevel: "AA",
|
|
13662
|
+
darkModeSupport: true
|
|
13663
|
+
};
|
|
13664
|
+
var DEFAULT_SECURITY_STANDARDS = {
|
|
13665
|
+
authPattern: "jwt",
|
|
13666
|
+
inputValidation: "zod",
|
|
13667
|
+
csrfProtection: true,
|
|
13668
|
+
rateLimiting: true
|
|
13669
|
+
};
|
|
13670
|
+
var DEFAULT_PERFORMANCE_STANDARDS = {
|
|
13671
|
+
lcpTarget: 2500,
|
|
13672
|
+
fidTarget: 100,
|
|
13673
|
+
clsTarget: 0.1,
|
|
13674
|
+
bundleSizeTargetKb: 250,
|
|
13675
|
+
apiResponseTargetMs: 300
|
|
13676
|
+
};
|
|
13677
|
+
var DEFAULT_STANDARDS_CONFIG = {
|
|
13678
|
+
code: DEFAULT_CODE_STANDARDS,
|
|
13679
|
+
testing: DEFAULT_TESTING_STANDARDS,
|
|
13680
|
+
documentation: DEFAULT_DOCUMENTATION_STANDARDS,
|
|
13681
|
+
design: DEFAULT_DESIGN_STANDARDS,
|
|
13682
|
+
security: DEFAULT_SECURITY_STANDARDS,
|
|
13683
|
+
performance: DEFAULT_PERFORMANCE_STANDARDS
|
|
13684
|
+
};
|
|
13685
|
+
var STANDARDS_PRESETS = {
|
|
13686
|
+
strict: {
|
|
13687
|
+
name: "Strict",
|
|
13688
|
+
description: "High quality standards with strict enforcement (90%+ coverage, TDD required)",
|
|
13689
|
+
config: {
|
|
13690
|
+
code: {
|
|
13691
|
+
...DEFAULT_CODE_STANDARDS,
|
|
13692
|
+
allowAny: false,
|
|
13693
|
+
jsDocRequired: true
|
|
13694
|
+
},
|
|
13695
|
+
testing: {
|
|
13696
|
+
...DEFAULT_TESTING_STANDARDS,
|
|
13697
|
+
coverageTarget: 90,
|
|
13698
|
+
tddRequired: true
|
|
13699
|
+
},
|
|
13700
|
+
documentation: {
|
|
13701
|
+
...DEFAULT_DOCUMENTATION_STANDARDS,
|
|
13702
|
+
jsDocLevel: "comprehensive",
|
|
13703
|
+
requireExamples: true
|
|
13704
|
+
},
|
|
13705
|
+
design: {
|
|
13706
|
+
...DEFAULT_DESIGN_STANDARDS,
|
|
13707
|
+
accessibilityLevel: "AAA"
|
|
13708
|
+
},
|
|
13709
|
+
security: {
|
|
13710
|
+
...DEFAULT_SECURITY_STANDARDS,
|
|
13711
|
+
csrfProtection: true,
|
|
13712
|
+
rateLimiting: true
|
|
13713
|
+
},
|
|
13714
|
+
performance: {
|
|
13715
|
+
...DEFAULT_PERFORMANCE_STANDARDS,
|
|
13716
|
+
lcpTarget: 2e3,
|
|
13717
|
+
apiResponseTargetMs: 200
|
|
13718
|
+
}
|
|
13719
|
+
}
|
|
13720
|
+
},
|
|
13721
|
+
balanced: {
|
|
13722
|
+
name: "Balanced",
|
|
13723
|
+
description: "Good balance between quality and pragmatism (80% coverage)",
|
|
13724
|
+
config: DEFAULT_STANDARDS_CONFIG
|
|
13725
|
+
},
|
|
13726
|
+
relaxed: {
|
|
13727
|
+
name: "Relaxed",
|
|
13728
|
+
description: "More flexible standards for rapid development (70% coverage)",
|
|
13729
|
+
config: {
|
|
13730
|
+
code: {
|
|
13731
|
+
...DEFAULT_CODE_STANDARDS,
|
|
13732
|
+
maxFileLines: 800,
|
|
13733
|
+
jsDocRequired: false
|
|
13734
|
+
},
|
|
13735
|
+
testing: {
|
|
13736
|
+
...DEFAULT_TESTING_STANDARDS,
|
|
13737
|
+
coverageTarget: 70,
|
|
13738
|
+
tddRequired: false
|
|
13739
|
+
},
|
|
13740
|
+
documentation: {
|
|
13741
|
+
...DEFAULT_DOCUMENTATION_STANDARDS,
|
|
13742
|
+
jsDocLevel: "minimal",
|
|
13743
|
+
requireExamples: false
|
|
13744
|
+
},
|
|
13745
|
+
design: {
|
|
13746
|
+
...DEFAULT_DESIGN_STANDARDS,
|
|
13747
|
+
accessibilityLevel: "A"
|
|
13748
|
+
},
|
|
13749
|
+
security: {
|
|
13750
|
+
...DEFAULT_SECURITY_STANDARDS
|
|
13751
|
+
},
|
|
13752
|
+
performance: {
|
|
13753
|
+
...DEFAULT_PERFORMANCE_STANDARDS,
|
|
13754
|
+
lcpTarget: 4e3,
|
|
13755
|
+
apiResponseTargetMs: 500
|
|
13756
|
+
}
|
|
13757
|
+
}
|
|
13758
|
+
},
|
|
13759
|
+
startup: {
|
|
13760
|
+
name: "Startup",
|
|
13761
|
+
description: "Fast iteration with minimum viable standards (60% coverage)",
|
|
13762
|
+
config: {
|
|
13763
|
+
code: {
|
|
13764
|
+
...DEFAULT_CODE_STANDARDS,
|
|
13765
|
+
maxFileLines: 1e3,
|
|
13766
|
+
jsDocRequired: false,
|
|
13767
|
+
roroPattern: false
|
|
13768
|
+
},
|
|
13769
|
+
testing: {
|
|
13770
|
+
coverageTarget: 60,
|
|
13771
|
+
tddRequired: false,
|
|
13772
|
+
testPattern: "aaa",
|
|
13773
|
+
testLocation: "colocated",
|
|
13774
|
+
unitTestMaxMs: 200,
|
|
13775
|
+
integrationTestMaxMs: 2e3
|
|
13776
|
+
},
|
|
13777
|
+
documentation: {
|
|
13778
|
+
jsDocLevel: "minimal",
|
|
13779
|
+
requireExamples: false,
|
|
13780
|
+
changelogFormat: "conventional",
|
|
13781
|
+
inlineCommentPolicy: "minimal"
|
|
13782
|
+
},
|
|
13783
|
+
design: {
|
|
13784
|
+
cssFramework: "tailwind",
|
|
13785
|
+
componentLibrary: "shadcn",
|
|
13786
|
+
accessibilityLevel: "A",
|
|
13787
|
+
darkModeSupport: false
|
|
13788
|
+
},
|
|
13789
|
+
security: {
|
|
13790
|
+
authPattern: "jwt",
|
|
13791
|
+
inputValidation: "zod",
|
|
13792
|
+
csrfProtection: false,
|
|
13793
|
+
rateLimiting: false
|
|
13794
|
+
},
|
|
13795
|
+
performance: {
|
|
13796
|
+
lcpTarget: 4e3,
|
|
13797
|
+
fidTarget: 300,
|
|
13798
|
+
clsTarget: 0.25,
|
|
13799
|
+
bundleSizeTargetKb: 500,
|
|
13800
|
+
apiResponseTargetMs: 500
|
|
13801
|
+
}
|
|
13802
|
+
}
|
|
13803
|
+
},
|
|
13804
|
+
enterprise: {
|
|
13805
|
+
name: "Enterprise",
|
|
13806
|
+
description: "Enterprise-grade standards with full compliance (95%+ coverage)",
|
|
13807
|
+
config: {
|
|
13808
|
+
code: {
|
|
13809
|
+
indentStyle: "space",
|
|
13810
|
+
indentSize: 2,
|
|
13811
|
+
maxLineLength: 120,
|
|
13812
|
+
maxFileLines: 400,
|
|
13813
|
+
quoteStyle: "single",
|
|
13814
|
+
semicolons: true,
|
|
13815
|
+
trailingCommas: "all",
|
|
13816
|
+
allowAny: false,
|
|
13817
|
+
namedExportsOnly: true,
|
|
13818
|
+
roroPattern: true,
|
|
13819
|
+
jsDocRequired: true
|
|
13820
|
+
},
|
|
13821
|
+
testing: {
|
|
13822
|
+
coverageTarget: 95,
|
|
13823
|
+
tddRequired: true,
|
|
13824
|
+
testPattern: "aaa",
|
|
13825
|
+
testLocation: "separate",
|
|
13826
|
+
unitTestMaxMs: 50,
|
|
13827
|
+
integrationTestMaxMs: 500
|
|
13828
|
+
},
|
|
13829
|
+
documentation: {
|
|
13830
|
+
jsDocLevel: "comprehensive",
|
|
13831
|
+
requireExamples: true,
|
|
13832
|
+
changelogFormat: "keepachangelog",
|
|
13833
|
+
inlineCommentPolicy: "why-not-what"
|
|
13834
|
+
},
|
|
13835
|
+
design: {
|
|
13836
|
+
cssFramework: "tailwind",
|
|
13837
|
+
componentLibrary: "radix",
|
|
13838
|
+
accessibilityLevel: "AAA",
|
|
13839
|
+
darkModeSupport: true
|
|
13840
|
+
},
|
|
13841
|
+
security: {
|
|
13842
|
+
authPattern: "oauth",
|
|
13843
|
+
inputValidation: "zod",
|
|
13844
|
+
csrfProtection: true,
|
|
13845
|
+
rateLimiting: true
|
|
13846
|
+
},
|
|
13847
|
+
performance: {
|
|
13848
|
+
lcpTarget: 1500,
|
|
13849
|
+
fidTarget: 50,
|
|
13850
|
+
clsTarget: 0.05,
|
|
13851
|
+
bundleSizeTargetKb: 150,
|
|
13852
|
+
apiResponseTargetMs: 150
|
|
13853
|
+
}
|
|
13854
|
+
}
|
|
13855
|
+
},
|
|
13856
|
+
custom: {
|
|
13857
|
+
name: "Custom",
|
|
13858
|
+
description: "Configure each standard manually",
|
|
13859
|
+
config: DEFAULT_STANDARDS_CONFIG
|
|
13860
|
+
}
|
|
13861
|
+
};
|
|
13862
|
+
|
|
13863
|
+
// src/lib/standards/index.ts
|
|
13864
|
+
init_esm_shims();
|
|
13865
|
+
|
|
13866
|
+
// src/lib/standards/definitions.ts
|
|
13867
|
+
init_esm_shims();
|
|
13868
|
+
var CODE_STANDARDS_DEFINITION = {
|
|
13869
|
+
id: "code",
|
|
13870
|
+
name: "Code Standards",
|
|
13871
|
+
description: "Code style, formatting, and TypeScript conventions",
|
|
13872
|
+
icon: "\u{1F4DD}",
|
|
13873
|
+
options: [
|
|
13874
|
+
{
|
|
13875
|
+
id: "indentStyle",
|
|
13876
|
+
label: "Indent Style",
|
|
13877
|
+
description: "Use spaces or tabs for indentation",
|
|
13878
|
+
type: "select",
|
|
13879
|
+
choices: [
|
|
13880
|
+
{ name: "Spaces", value: "space", description: "Standard for most projects" },
|
|
13881
|
+
{ name: "Tabs", value: "tab", description: "Better for accessibility" }
|
|
13882
|
+
],
|
|
13883
|
+
affectsPlaceholders: ["{{INDENT_STYLE}}"]
|
|
13884
|
+
},
|
|
13885
|
+
{
|
|
13886
|
+
id: "indentSize",
|
|
13887
|
+
label: "Indent Size",
|
|
13888
|
+
description: "Number of spaces/tab width",
|
|
13889
|
+
type: "select",
|
|
13890
|
+
choices: [
|
|
13891
|
+
{ name: "2 spaces", value: "2", description: "Most common in JS/TS" },
|
|
13892
|
+
{ name: "4 spaces", value: "4", description: "More readable for some" }
|
|
13893
|
+
],
|
|
13894
|
+
affectsPlaceholders: ["{{INDENT_SIZE}}"]
|
|
13895
|
+
},
|
|
13896
|
+
{
|
|
13897
|
+
id: "maxLineLength",
|
|
13898
|
+
label: "Max Line Length",
|
|
13899
|
+
description: "Maximum characters per line",
|
|
13900
|
+
type: "select",
|
|
13901
|
+
choices: [
|
|
13902
|
+
{ name: "80 characters", value: "80", description: "Classic terminal width" },
|
|
13903
|
+
{ name: "100 characters", value: "100", description: "Modern balance" },
|
|
13904
|
+
{ name: "120 characters", value: "120", description: "Wide screens" }
|
|
13905
|
+
],
|
|
13906
|
+
affectsPlaceholders: ["{{MAX_LINE_LENGTH}}"]
|
|
13907
|
+
},
|
|
13908
|
+
{
|
|
13909
|
+
id: "maxFileLines",
|
|
13910
|
+
label: "Max File Lines",
|
|
13911
|
+
description: "Maximum lines per file (excluding tests, docs, JSON)",
|
|
13912
|
+
type: "select",
|
|
13913
|
+
choices: [
|
|
13914
|
+
{ name: "300 lines", value: "300", description: "Very strict" },
|
|
13915
|
+
{ name: "500 lines", value: "500", description: "Recommended" },
|
|
13916
|
+
{ name: "800 lines", value: "800", description: "Relaxed" },
|
|
13917
|
+
{ name: "1000 lines", value: "1000", description: "Very relaxed" }
|
|
13918
|
+
],
|
|
13919
|
+
affectsPlaceholders: ["{{MAX_FILE_LINES}}"]
|
|
13920
|
+
},
|
|
13921
|
+
{
|
|
13922
|
+
id: "quoteStyle",
|
|
13923
|
+
label: "Quote Style",
|
|
13924
|
+
description: "Single or double quotes for strings",
|
|
13925
|
+
type: "select",
|
|
13926
|
+
choices: [
|
|
13927
|
+
{ name: "Single quotes", value: "single", description: "const x = 'hello'" },
|
|
13928
|
+
{ name: "Double quotes", value: "double", description: 'const x = "hello"' }
|
|
13929
|
+
],
|
|
13930
|
+
affectsPlaceholders: ["{{QUOTE_STYLE}}"]
|
|
13931
|
+
},
|
|
13932
|
+
{
|
|
13933
|
+
id: "semicolons",
|
|
13934
|
+
label: "Semicolons",
|
|
13935
|
+
description: "Use semicolons at end of statements",
|
|
13936
|
+
type: "boolean",
|
|
13937
|
+
affectsPlaceholders: ["{{USE_SEMICOLONS}}"]
|
|
13938
|
+
},
|
|
13939
|
+
{
|
|
13940
|
+
id: "trailingCommas",
|
|
13941
|
+
label: "Trailing Commas",
|
|
13942
|
+
description: "Add trailing commas in multiline constructs",
|
|
13943
|
+
type: "select",
|
|
13944
|
+
choices: [
|
|
13945
|
+
{ name: "ES5", value: "es5", description: "Where valid in ES5 (objects, arrays)" },
|
|
13946
|
+
{ name: "All", value: "all", description: "Everywhere possible" },
|
|
13947
|
+
{ name: "None", value: "none", description: "No trailing commas" }
|
|
13948
|
+
],
|
|
13949
|
+
affectsPlaceholders: ["{{TRAILING_COMMAS}}"]
|
|
13950
|
+
},
|
|
13951
|
+
{
|
|
13952
|
+
id: "allowAny",
|
|
13953
|
+
label: 'Allow "any" Type',
|
|
13954
|
+
description: 'Allow the "any" type in TypeScript',
|
|
13955
|
+
type: "boolean",
|
|
13956
|
+
affectsPlaceholders: ["{{ALLOW_ANY}}"]
|
|
13957
|
+
},
|
|
13958
|
+
{
|
|
13959
|
+
id: "namedExportsOnly",
|
|
13960
|
+
label: "Named Exports Only",
|
|
13961
|
+
description: "Require named exports (no default exports)",
|
|
13962
|
+
type: "boolean",
|
|
13963
|
+
affectsPlaceholders: ["{{NAMED_EXPORTS_ONLY}}"]
|
|
13964
|
+
},
|
|
13965
|
+
{
|
|
13966
|
+
id: "roroPattern",
|
|
13967
|
+
label: "RO-RO Pattern",
|
|
13968
|
+
description: "Require Receive Object, Return Object pattern",
|
|
13969
|
+
type: "boolean",
|
|
13970
|
+
affectsPlaceholders: ["{{RORO_PATTERN}}"]
|
|
13971
|
+
},
|
|
13972
|
+
{
|
|
13973
|
+
id: "jsDocRequired",
|
|
13974
|
+
label: "JSDoc Required",
|
|
13975
|
+
description: "Require JSDoc for all exports",
|
|
13976
|
+
type: "boolean",
|
|
13977
|
+
affectsPlaceholders: ["{{JSDOC_REQUIRED}}"]
|
|
13978
|
+
}
|
|
13979
|
+
],
|
|
13980
|
+
targetFiles: ["code-standards.md", "architecture-patterns.md"]
|
|
13981
|
+
};
|
|
13982
|
+
var TESTING_STANDARDS_DEFINITION = {
|
|
13983
|
+
id: "testing",
|
|
13984
|
+
name: "Testing Standards",
|
|
13985
|
+
description: "Test coverage, TDD, and testing methodology",
|
|
13986
|
+
icon: "\u{1F9EA}",
|
|
13987
|
+
options: [
|
|
13988
|
+
{
|
|
13989
|
+
id: "coverageTarget",
|
|
13990
|
+
label: "Coverage Target",
|
|
13991
|
+
description: "Minimum code coverage percentage",
|
|
13992
|
+
type: "select",
|
|
13993
|
+
choices: [
|
|
13994
|
+
{ name: "60%", value: "60", description: "Minimum viable" },
|
|
13995
|
+
{ name: "70%", value: "70", description: "Relaxed" },
|
|
13996
|
+
{ name: "80%", value: "80", description: "Standard" },
|
|
13997
|
+
{ name: "90%", value: "90", description: "Strict" },
|
|
13998
|
+
{ name: "95%", value: "95", description: "Enterprise" }
|
|
13999
|
+
],
|
|
14000
|
+
affectsPlaceholders: ["{{COVERAGE_TARGET}}"]
|
|
14001
|
+
},
|
|
14002
|
+
{
|
|
14003
|
+
id: "tddRequired",
|
|
14004
|
+
label: "TDD Required",
|
|
14005
|
+
description: "Require Test-Driven Development (Red-Green-Refactor)",
|
|
14006
|
+
type: "boolean",
|
|
14007
|
+
affectsPlaceholders: ["{{TDD_REQUIRED}}"]
|
|
14008
|
+
},
|
|
14009
|
+
{
|
|
14010
|
+
id: "testPattern",
|
|
14011
|
+
label: "Test Pattern",
|
|
14012
|
+
description: "Test structure pattern",
|
|
14013
|
+
type: "select",
|
|
14014
|
+
choices: [
|
|
14015
|
+
{ name: "AAA", value: "aaa", description: "Arrange-Act-Assert" },
|
|
14016
|
+
{ name: "GWT", value: "gwt", description: "Given-When-Then" }
|
|
14017
|
+
],
|
|
14018
|
+
affectsPlaceholders: ["{{TEST_PATTERN}}"]
|
|
14019
|
+
},
|
|
14020
|
+
{
|
|
14021
|
+
id: "testLocation",
|
|
14022
|
+
label: "Test Location",
|
|
14023
|
+
description: "Where to place test files",
|
|
14024
|
+
type: "select",
|
|
14025
|
+
choices: [
|
|
14026
|
+
{ name: "Separate", value: "separate", description: "test/ folder at root" },
|
|
14027
|
+
{ name: "Colocated", value: "colocated", description: "__tests__ near source" }
|
|
14028
|
+
],
|
|
14029
|
+
affectsPlaceholders: ["{{TEST_LOCATION}}"]
|
|
14030
|
+
},
|
|
14031
|
+
{
|
|
14032
|
+
id: "unitTestMaxMs",
|
|
14033
|
+
label: "Unit Test Max (ms)",
|
|
14034
|
+
description: "Maximum milliseconds per unit test",
|
|
14035
|
+
type: "select",
|
|
14036
|
+
choices: [
|
|
14037
|
+
{ name: "50ms", value: "50", description: "Very fast" },
|
|
14038
|
+
{ name: "100ms", value: "100", description: "Standard" },
|
|
14039
|
+
{ name: "200ms", value: "200", description: "Relaxed" }
|
|
14040
|
+
],
|
|
14041
|
+
affectsPlaceholders: ["{{UNIT_TEST_MAX_MS}}"]
|
|
14042
|
+
},
|
|
14043
|
+
{
|
|
14044
|
+
id: "integrationTestMaxMs",
|
|
14045
|
+
label: "Integration Test Max (ms)",
|
|
14046
|
+
description: "Maximum milliseconds per integration test",
|
|
14047
|
+
type: "select",
|
|
14048
|
+
choices: [
|
|
14049
|
+
{ name: "500ms", value: "500", description: "Fast" },
|
|
14050
|
+
{ name: "1000ms", value: "1000", description: "Standard" },
|
|
14051
|
+
{ name: "2000ms", value: "2000", description: "Relaxed" }
|
|
14052
|
+
],
|
|
14053
|
+
affectsPlaceholders: ["{{INTEGRATION_TEST_MAX_MS}}"]
|
|
14054
|
+
}
|
|
14055
|
+
],
|
|
14056
|
+
targetFiles: ["testing-standards.md"]
|
|
14057
|
+
};
|
|
14058
|
+
var DOCUMENTATION_STANDARDS_DEFINITION = {
|
|
14059
|
+
id: "documentation",
|
|
14060
|
+
name: "Documentation Standards",
|
|
14061
|
+
description: "JSDoc, comments, and changelog conventions",
|
|
14062
|
+
icon: "\u{1F4DA}",
|
|
14063
|
+
options: [
|
|
14064
|
+
{
|
|
14065
|
+
id: "jsDocLevel",
|
|
14066
|
+
label: "JSDoc Level",
|
|
14067
|
+
description: "Level of detail in JSDoc comments",
|
|
14068
|
+
type: "select",
|
|
14069
|
+
choices: [
|
|
14070
|
+
{ name: "Minimal", value: "minimal", description: "Brief description only" },
|
|
14071
|
+
{ name: "Standard", value: "standard", description: "Description + params + returns" },
|
|
14072
|
+
{ name: "Comprehensive", value: "comprehensive", description: "Full docs with examples" }
|
|
14073
|
+
],
|
|
14074
|
+
affectsPlaceholders: ["{{JSDOC_LEVEL}}"]
|
|
14075
|
+
},
|
|
14076
|
+
{
|
|
14077
|
+
id: "requireExamples",
|
|
14078
|
+
label: "Require Examples",
|
|
14079
|
+
description: "Require @example in JSDoc",
|
|
14080
|
+
type: "boolean",
|
|
14081
|
+
affectsPlaceholders: ["{{REQUIRE_EXAMPLES}}"]
|
|
14082
|
+
},
|
|
14083
|
+
{
|
|
14084
|
+
id: "changelogFormat",
|
|
14085
|
+
label: "Changelog Format",
|
|
14086
|
+
description: "Changelog format to follow",
|
|
14087
|
+
type: "select",
|
|
14088
|
+
choices: [
|
|
14089
|
+
{ name: "Conventional", value: "conventional", description: "Auto-generated from commits" },
|
|
14090
|
+
{ name: "Keep a Changelog", value: "keepachangelog", description: "Manual, semantic" }
|
|
14091
|
+
],
|
|
14092
|
+
affectsPlaceholders: ["{{CHANGELOG_FORMAT}}"]
|
|
14093
|
+
},
|
|
14094
|
+
{
|
|
14095
|
+
id: "inlineCommentPolicy",
|
|
14096
|
+
label: "Inline Comment Policy",
|
|
14097
|
+
description: "Policy for inline code comments",
|
|
14098
|
+
type: "select",
|
|
14099
|
+
choices: [
|
|
14100
|
+
{
|
|
14101
|
+
name: "Why not What",
|
|
14102
|
+
value: "why-not-what",
|
|
14103
|
+
description: "Explain reasoning, not obvious"
|
|
14104
|
+
},
|
|
14105
|
+
{ name: "Minimal", value: "minimal", description: "Only when necessary" },
|
|
14106
|
+
{ name: "Extensive", value: "extensive", description: "Comment thoroughly" }
|
|
14107
|
+
],
|
|
14108
|
+
affectsPlaceholders: ["{{INLINE_COMMENT_POLICY}}"]
|
|
14109
|
+
}
|
|
14110
|
+
],
|
|
14111
|
+
targetFiles: ["documentation-standards.md"]
|
|
14112
|
+
};
|
|
14113
|
+
var DESIGN_STANDARDS_DEFINITION = {
|
|
14114
|
+
id: "design",
|
|
14115
|
+
name: "Design Standards",
|
|
14116
|
+
description: "UI/UX, CSS, and accessibility standards",
|
|
14117
|
+
icon: "\u{1F3A8}",
|
|
14118
|
+
options: [
|
|
14119
|
+
{
|
|
14120
|
+
id: "cssFramework",
|
|
14121
|
+
label: "CSS Framework",
|
|
14122
|
+
description: "CSS/styling approach",
|
|
14123
|
+
type: "select",
|
|
14124
|
+
choices: [
|
|
14125
|
+
{ name: "Tailwind CSS", value: "tailwind", description: "Utility-first CSS" },
|
|
14126
|
+
{ name: "CSS Modules", value: "css-modules", description: "Scoped CSS" },
|
|
14127
|
+
{ name: "Styled Components", value: "styled-components", description: "CSS-in-JS" },
|
|
14128
|
+
{ name: "Vanilla CSS", value: "vanilla", description: "Plain CSS" }
|
|
14129
|
+
],
|
|
14130
|
+
affectsPlaceholders: ["{{CSS_FRAMEWORK}}"]
|
|
14131
|
+
},
|
|
14132
|
+
{
|
|
14133
|
+
id: "componentLibrary",
|
|
14134
|
+
label: "Component Library",
|
|
14135
|
+
description: "UI component library",
|
|
14136
|
+
type: "select",
|
|
14137
|
+
choices: [
|
|
14138
|
+
{ name: "shadcn/ui", value: "shadcn", description: "Copy-paste components" },
|
|
14139
|
+
{ name: "Radix UI", value: "radix", description: "Unstyled primitives" },
|
|
14140
|
+
{ name: "Headless UI", value: "headless", description: "Unstyled, accessible" },
|
|
14141
|
+
{ name: "None", value: "none", description: "Build from scratch" }
|
|
14142
|
+
],
|
|
14143
|
+
affectsPlaceholders: ["{{COMPONENT_LIBRARY}}"]
|
|
14144
|
+
},
|
|
14145
|
+
{
|
|
14146
|
+
id: "accessibilityLevel",
|
|
14147
|
+
label: "Accessibility Level",
|
|
14148
|
+
description: "WCAG accessibility compliance level",
|
|
14149
|
+
type: "select",
|
|
14150
|
+
choices: [
|
|
14151
|
+
{ name: "Level A", value: "A", description: "Minimum" },
|
|
14152
|
+
{ name: "Level AA", value: "AA", description: "Standard (recommended)" },
|
|
14153
|
+
{ name: "Level AAA", value: "AAA", description: "Highest" }
|
|
14154
|
+
],
|
|
14155
|
+
affectsPlaceholders: ["{{WCAG_LEVEL}}", "{{ACCESSIBILITY_LEVEL}}"]
|
|
14156
|
+
},
|
|
14157
|
+
{
|
|
14158
|
+
id: "darkModeSupport",
|
|
14159
|
+
label: "Dark Mode Support",
|
|
14160
|
+
description: "Support dark mode theme",
|
|
14161
|
+
type: "boolean",
|
|
14162
|
+
affectsPlaceholders: ["{{DARK_MODE_SUPPORT}}"]
|
|
14163
|
+
}
|
|
14164
|
+
],
|
|
14165
|
+
targetFiles: ["design-standards.md"]
|
|
14166
|
+
};
|
|
14167
|
+
var SECURITY_STANDARDS_DEFINITION = {
|
|
14168
|
+
id: "security",
|
|
14169
|
+
name: "Security Standards",
|
|
14170
|
+
description: "Authentication, validation, and security practices",
|
|
14171
|
+
icon: "\u{1F512}",
|
|
14172
|
+
options: [
|
|
14173
|
+
{
|
|
14174
|
+
id: "authPattern",
|
|
14175
|
+
label: "Auth Pattern",
|
|
14176
|
+
description: "Authentication approach",
|
|
14177
|
+
type: "select",
|
|
14178
|
+
choices: [
|
|
14179
|
+
{ name: "JWT", value: "jwt", description: "JSON Web Tokens" },
|
|
14180
|
+
{ name: "Session", value: "session", description: "Server-side sessions" },
|
|
14181
|
+
{ name: "OAuth", value: "oauth", description: "OAuth 2.0 / OIDC" },
|
|
14182
|
+
{ name: "None", value: "none", description: "No authentication" }
|
|
14183
|
+
],
|
|
14184
|
+
affectsPlaceholders: ["{{AUTH_PATTERN}}"]
|
|
14185
|
+
},
|
|
14186
|
+
{
|
|
14187
|
+
id: "inputValidation",
|
|
14188
|
+
label: "Input Validation",
|
|
14189
|
+
description: "Validation library",
|
|
14190
|
+
type: "select",
|
|
14191
|
+
choices: [
|
|
14192
|
+
{ name: "Zod", value: "zod", description: "TypeScript-first validation" },
|
|
14193
|
+
{ name: "Yup", value: "yup", description: "Schema builder" },
|
|
14194
|
+
{ name: "Joi", value: "joi", description: "Data validation" },
|
|
14195
|
+
{ name: "Manual", value: "manual", description: "Custom validation" }
|
|
14196
|
+
],
|
|
14197
|
+
affectsPlaceholders: ["{{VALIDATION_LIBRARY}}", "{{INPUT_VALIDATION}}"]
|
|
14198
|
+
},
|
|
14199
|
+
{
|
|
14200
|
+
id: "csrfProtection",
|
|
14201
|
+
label: "CSRF Protection",
|
|
14202
|
+
description: "Enable Cross-Site Request Forgery protection",
|
|
14203
|
+
type: "boolean",
|
|
14204
|
+
affectsPlaceholders: ["{{CSRF_PROTECTION}}"]
|
|
14205
|
+
},
|
|
14206
|
+
{
|
|
14207
|
+
id: "rateLimiting",
|
|
14208
|
+
label: "Rate Limiting",
|
|
14209
|
+
description: "Enable API rate limiting",
|
|
14210
|
+
type: "boolean",
|
|
14211
|
+
affectsPlaceholders: ["{{RATE_LIMITING}}"]
|
|
14212
|
+
}
|
|
14213
|
+
],
|
|
14214
|
+
targetFiles: ["security-standards.md"]
|
|
14215
|
+
};
|
|
14216
|
+
var PERFORMANCE_STANDARDS_DEFINITION = {
|
|
14217
|
+
id: "performance",
|
|
14218
|
+
name: "Performance Standards",
|
|
14219
|
+
description: "Core Web Vitals and performance targets",
|
|
14220
|
+
icon: "\u26A1",
|
|
14221
|
+
options: [
|
|
14222
|
+
{
|
|
14223
|
+
id: "lcpTarget",
|
|
14224
|
+
label: "LCP Target (ms)",
|
|
14225
|
+
description: "Largest Contentful Paint target",
|
|
14226
|
+
type: "select",
|
|
14227
|
+
choices: [
|
|
14228
|
+
{ name: "1500ms", value: "1500", description: "Excellent" },
|
|
14229
|
+
{ name: "2000ms", value: "2000", description: "Good" },
|
|
14230
|
+
{ name: "2500ms", value: "2500", description: "Standard" },
|
|
14231
|
+
{ name: "4000ms", value: "4000", description: "Needs improvement" }
|
|
14232
|
+
],
|
|
14233
|
+
affectsPlaceholders: ["{{LCP_TARGET}}"]
|
|
14234
|
+
},
|
|
14235
|
+
{
|
|
14236
|
+
id: "fidTarget",
|
|
14237
|
+
label: "FID Target (ms)",
|
|
14238
|
+
description: "First Input Delay target",
|
|
14239
|
+
type: "select",
|
|
14240
|
+
choices: [
|
|
14241
|
+
{ name: "50ms", value: "50", description: "Excellent" },
|
|
14242
|
+
{ name: "100ms", value: "100", description: "Good" },
|
|
14243
|
+
{ name: "200ms", value: "200", description: "Standard" },
|
|
14244
|
+
{ name: "300ms", value: "300", description: "Needs improvement" }
|
|
14245
|
+
],
|
|
14246
|
+
affectsPlaceholders: ["{{FID_TARGET}}"]
|
|
14247
|
+
},
|
|
14248
|
+
{
|
|
14249
|
+
id: "clsTarget",
|
|
14250
|
+
label: "CLS Target",
|
|
14251
|
+
description: "Cumulative Layout Shift target",
|
|
14252
|
+
type: "select",
|
|
14253
|
+
choices: [
|
|
14254
|
+
{ name: "0.05", value: "0.05", description: "Excellent" },
|
|
14255
|
+
{ name: "0.1", value: "0.1", description: "Good" },
|
|
14256
|
+
{ name: "0.15", value: "0.15", description: "Standard" },
|
|
14257
|
+
{ name: "0.25", value: "0.25", description: "Needs improvement" }
|
|
14258
|
+
],
|
|
14259
|
+
affectsPlaceholders: ["{{CLS_TARGET}}"]
|
|
14260
|
+
},
|
|
14261
|
+
{
|
|
14262
|
+
id: "bundleSizeTargetKb",
|
|
14263
|
+
label: "Bundle Size (KB)",
|
|
14264
|
+
description: "Maximum initial bundle size",
|
|
14265
|
+
type: "select",
|
|
14266
|
+
choices: [
|
|
14267
|
+
{ name: "100KB", value: "100", description: "Very strict" },
|
|
14268
|
+
{ name: "150KB", value: "150", description: "Strict" },
|
|
14269
|
+
{ name: "250KB", value: "250", description: "Standard" },
|
|
14270
|
+
{ name: "500KB", value: "500", description: "Relaxed" }
|
|
14271
|
+
],
|
|
14272
|
+
affectsPlaceholders: ["{{BUNDLE_SIZE_TARGET}}"]
|
|
14273
|
+
},
|
|
14274
|
+
{
|
|
14275
|
+
id: "apiResponseTargetMs",
|
|
14276
|
+
label: "API Response (ms)",
|
|
14277
|
+
description: "Maximum API response time",
|
|
14278
|
+
type: "select",
|
|
14279
|
+
choices: [
|
|
14280
|
+
{ name: "100ms", value: "100", description: "Very fast" },
|
|
14281
|
+
{ name: "200ms", value: "200", description: "Fast" },
|
|
14282
|
+
{ name: "300ms", value: "300", description: "Standard" },
|
|
14283
|
+
{ name: "500ms", value: "500", description: "Relaxed" }
|
|
14284
|
+
],
|
|
14285
|
+
affectsPlaceholders: ["{{API_RESPONSE_TARGET}}"]
|
|
14286
|
+
}
|
|
14287
|
+
],
|
|
14288
|
+
targetFiles: ["performance-standards.md"]
|
|
14289
|
+
};
|
|
14290
|
+
var STANDARDS_DEFINITIONS = {
|
|
14291
|
+
code: CODE_STANDARDS_DEFINITION,
|
|
14292
|
+
testing: TESTING_STANDARDS_DEFINITION,
|
|
14293
|
+
documentation: DOCUMENTATION_STANDARDS_DEFINITION,
|
|
14294
|
+
design: DESIGN_STANDARDS_DEFINITION,
|
|
14295
|
+
security: SECURITY_STANDARDS_DEFINITION,
|
|
14296
|
+
performance: PERFORMANCE_STANDARDS_DEFINITION
|
|
14297
|
+
};
|
|
14298
|
+
|
|
14299
|
+
// src/lib/standards/replacer.ts
|
|
14300
|
+
init_esm_shims();
|
|
14301
|
+
import * as fs6 from "fs/promises";
|
|
14302
|
+
import * as path8 from "path";
|
|
14303
|
+
import ora3 from "ora";
|
|
14304
|
+
var PROCESSABLE_EXTENSIONS2 = [".md", ".json", ".yaml", ".yml", ".txt"];
|
|
14305
|
+
var SKIP_DIRECTORIES3 = ["node_modules", ".git", "dist", "build", ".next", ".turbo"];
|
|
14306
|
+
function flattenStandardsConfig(config) {
|
|
14307
|
+
const flattened = {};
|
|
14308
|
+
if (config.code) {
|
|
14309
|
+
flattened["{{INDENT_STYLE}}"] = config.code.indentStyle;
|
|
14310
|
+
flattened["{{INDENT_SIZE}}"] = String(config.code.indentSize);
|
|
14311
|
+
flattened["{{MAX_LINE_LENGTH}}"] = String(config.code.maxLineLength);
|
|
14312
|
+
flattened["{{MAX_FILE_LINES}}"] = String(config.code.maxFileLines);
|
|
14313
|
+
flattened["{{QUOTE_STYLE}}"] = config.code.quoteStyle;
|
|
14314
|
+
flattened["{{USE_SEMICOLONS}}"] = config.code.semicolons ? "yes" : "no";
|
|
14315
|
+
flattened["{{TRAILING_COMMAS}}"] = config.code.trailingCommas;
|
|
14316
|
+
flattened["{{ALLOW_ANY}}"] = config.code.allowAny ? "yes" : "no";
|
|
14317
|
+
flattened["{{NAMED_EXPORTS_ONLY}}"] = config.code.namedExportsOnly ? "yes" : "no";
|
|
14318
|
+
flattened["{{RORO_PATTERN}}"] = config.code.roroPattern ? "yes" : "no";
|
|
14319
|
+
flattened["{{JSDOC_REQUIRED}}"] = config.code.jsDocRequired ? "yes" : "no";
|
|
14320
|
+
}
|
|
14321
|
+
if (config.testing) {
|
|
14322
|
+
flattened["{{COVERAGE_TARGET}}"] = String(config.testing.coverageTarget);
|
|
14323
|
+
flattened["{{TDD_REQUIRED}}"] = config.testing.tddRequired ? "yes" : "no";
|
|
14324
|
+
flattened["{{TEST_PATTERN}}"] = config.testing.testPattern.toUpperCase();
|
|
14325
|
+
flattened["{{TEST_LOCATION}}"] = config.testing.testLocation;
|
|
14326
|
+
flattened["{{UNIT_TEST_MAX_MS}}"] = String(config.testing.unitTestMaxMs);
|
|
14327
|
+
flattened["{{INTEGRATION_TEST_MAX_MS}}"] = String(config.testing.integrationTestMaxMs);
|
|
14328
|
+
}
|
|
14329
|
+
if (config.documentation) {
|
|
14330
|
+
flattened["{{JSDOC_LEVEL}}"] = config.documentation.jsDocLevel;
|
|
14331
|
+
flattened["{{REQUIRE_EXAMPLES}}"] = config.documentation.requireExamples ? "yes" : "no";
|
|
14332
|
+
flattened["{{CHANGELOG_FORMAT}}"] = config.documentation.changelogFormat;
|
|
14333
|
+
flattened["{{INLINE_COMMENT_POLICY}}"] = config.documentation.inlineCommentPolicy;
|
|
14334
|
+
}
|
|
14335
|
+
if (config.design) {
|
|
14336
|
+
flattened["{{CSS_FRAMEWORK}}"] = config.design.cssFramework;
|
|
14337
|
+
flattened["{{COMPONENT_LIBRARY}}"] = config.design.componentLibrary;
|
|
14338
|
+
flattened["{{WCAG_LEVEL}}"] = config.design.accessibilityLevel;
|
|
14339
|
+
flattened["{{ACCESSIBILITY_LEVEL}}"] = config.design.accessibilityLevel;
|
|
14340
|
+
flattened["{{DARK_MODE_SUPPORT}}"] = config.design.darkModeSupport ? "yes" : "no";
|
|
14341
|
+
}
|
|
14342
|
+
if (config.security) {
|
|
14343
|
+
flattened["{{AUTH_PATTERN}}"] = config.security.authPattern;
|
|
14344
|
+
flattened["{{VALIDATION_LIBRARY}}"] = config.security.inputValidation;
|
|
14345
|
+
flattened["{{INPUT_VALIDATION}}"] = config.security.inputValidation;
|
|
14346
|
+
flattened["{{CSRF_PROTECTION}}"] = config.security.csrfProtection ? "yes" : "no";
|
|
14347
|
+
flattened["{{RATE_LIMITING}}"] = config.security.rateLimiting ? "yes" : "no";
|
|
14348
|
+
}
|
|
14349
|
+
if (config.performance) {
|
|
14350
|
+
flattened["{{LCP_TARGET}}"] = String(config.performance.lcpTarget);
|
|
14351
|
+
flattened["{{FID_TARGET}}"] = String(config.performance.fidTarget);
|
|
14352
|
+
flattened["{{CLS_TARGET}}"] = String(config.performance.clsTarget);
|
|
14353
|
+
flattened["{{BUNDLE_SIZE_TARGET}}"] = String(config.performance.bundleSizeTargetKb);
|
|
14354
|
+
flattened["{{API_RESPONSE_TARGET}}"] = String(config.performance.apiResponseTargetMs);
|
|
14355
|
+
}
|
|
14356
|
+
return flattened;
|
|
14357
|
+
}
|
|
14358
|
+
function shouldProcessFile2(filePath) {
|
|
14359
|
+
const ext = path8.extname(filePath).toLowerCase();
|
|
14360
|
+
return PROCESSABLE_EXTENSIONS2.includes(ext);
|
|
14361
|
+
}
|
|
14362
|
+
function shouldSkipDirectory3(dirName) {
|
|
14363
|
+
return SKIP_DIRECTORIES3.includes(dirName) || dirName.startsWith(".");
|
|
14364
|
+
}
|
|
14365
|
+
async function getAllFiles3(dir) {
|
|
14366
|
+
const files = [];
|
|
14367
|
+
try {
|
|
14368
|
+
const entries = await fs6.readdir(dir, { withFileTypes: true });
|
|
14369
|
+
for (const entry of entries) {
|
|
14370
|
+
const fullPath = path8.join(dir, entry.name);
|
|
14371
|
+
if (entry.isDirectory()) {
|
|
14372
|
+
if (!shouldSkipDirectory3(entry.name)) {
|
|
14373
|
+
const subFiles = await getAllFiles3(fullPath);
|
|
14374
|
+
files.push(...subFiles);
|
|
14375
|
+
}
|
|
14376
|
+
} else if (entry.isFile() && shouldProcessFile2(entry.name)) {
|
|
14377
|
+
files.push(fullPath);
|
|
14378
|
+
}
|
|
14379
|
+
}
|
|
14380
|
+
} catch {
|
|
14381
|
+
}
|
|
14382
|
+
return files;
|
|
14383
|
+
}
|
|
14384
|
+
async function replaceInFile3(filePath, replacements) {
|
|
14385
|
+
const changes = [];
|
|
14386
|
+
try {
|
|
14387
|
+
let content = await fs6.readFile(filePath, "utf-8");
|
|
14388
|
+
let modified = false;
|
|
14389
|
+
for (const [placeholder, value] of Object.entries(replacements)) {
|
|
14390
|
+
if (content.includes(placeholder)) {
|
|
14391
|
+
content = content.split(placeholder).join(value);
|
|
14392
|
+
changes.push({ placeholder, value });
|
|
14393
|
+
modified = true;
|
|
14394
|
+
}
|
|
14395
|
+
}
|
|
14396
|
+
if (modified) {
|
|
14397
|
+
await fs6.writeFile(filePath, content, "utf-8");
|
|
14398
|
+
}
|
|
14399
|
+
} catch {
|
|
14400
|
+
}
|
|
14401
|
+
return changes;
|
|
14402
|
+
}
|
|
14403
|
+
async function replaceStandardsPlaceholders(claudePath, config) {
|
|
14404
|
+
const replacements = flattenStandardsConfig(config);
|
|
14405
|
+
const standardsDir = path8.join(claudePath, "docs", "standards");
|
|
14406
|
+
const files = await getAllFiles3(standardsDir);
|
|
14407
|
+
const report = {
|
|
14408
|
+
modifiedFiles: [],
|
|
14409
|
+
replacedPlaceholders: [],
|
|
14410
|
+
unusedPlaceholders: [],
|
|
14411
|
+
errors: []
|
|
14412
|
+
};
|
|
14413
|
+
const usedPlaceholders = /* @__PURE__ */ new Set();
|
|
14414
|
+
for (const file of files) {
|
|
14415
|
+
try {
|
|
14416
|
+
const changes = await replaceInFile3(file, replacements);
|
|
14417
|
+
if (changes.length > 0) {
|
|
14418
|
+
report.modifiedFiles.push(path8.relative(claudePath, file));
|
|
14419
|
+
for (const change of changes) {
|
|
14420
|
+
if (!report.replacedPlaceholders.includes(change.placeholder)) {
|
|
14421
|
+
report.replacedPlaceholders.push(change.placeholder);
|
|
14422
|
+
}
|
|
14423
|
+
usedPlaceholders.add(change.placeholder);
|
|
14424
|
+
}
|
|
14425
|
+
}
|
|
14426
|
+
} catch (error) {
|
|
14427
|
+
report.errors.push(`Error processing ${file}: ${String(error)}`);
|
|
14428
|
+
}
|
|
14429
|
+
}
|
|
14430
|
+
for (const placeholder of Object.keys(replacements)) {
|
|
14431
|
+
if (!usedPlaceholders.has(placeholder)) {
|
|
14432
|
+
report.unusedPlaceholders.push(placeholder);
|
|
14433
|
+
}
|
|
14434
|
+
}
|
|
14435
|
+
return report;
|
|
14436
|
+
}
|
|
14437
|
+
async function replaceStandardsWithSpinner(claudePath, config) {
|
|
14438
|
+
const spinner2 = ora3("Applying standards configuration...").start();
|
|
14439
|
+
try {
|
|
14440
|
+
const report = await replaceStandardsPlaceholders(claudePath, config);
|
|
14441
|
+
if (report.modifiedFiles.length > 0) {
|
|
14442
|
+
spinner2.succeed(
|
|
14443
|
+
`Applied ${report.replacedPlaceholders.length} standards to ${report.modifiedFiles.length} files`
|
|
14444
|
+
);
|
|
14445
|
+
} else {
|
|
14446
|
+
spinner2.info("No standards placeholders found to replace");
|
|
14447
|
+
}
|
|
14448
|
+
return report;
|
|
14449
|
+
} catch (error) {
|
|
14450
|
+
spinner2.fail("Failed to apply standards configuration");
|
|
14451
|
+
throw error;
|
|
14452
|
+
}
|
|
14453
|
+
}
|
|
14454
|
+
async function previewStandardsReplacements(claudePath, config) {
|
|
14455
|
+
const replacements = flattenStandardsConfig(config);
|
|
14456
|
+
const standardsDir = path8.join(claudePath, "docs", "standards");
|
|
14457
|
+
const files = await getAllFiles3(standardsDir);
|
|
14458
|
+
const preview = [];
|
|
14459
|
+
for (const file of files) {
|
|
14460
|
+
try {
|
|
14461
|
+
const content = await fs6.readFile(file, "utf-8");
|
|
14462
|
+
for (const [placeholder, value] of Object.entries(replacements)) {
|
|
14463
|
+
if (content.includes(placeholder)) {
|
|
14464
|
+
preview.push({
|
|
14465
|
+
file: path8.relative(claudePath, file),
|
|
14466
|
+
placeholder,
|
|
14467
|
+
value
|
|
14468
|
+
});
|
|
14469
|
+
}
|
|
14470
|
+
}
|
|
14471
|
+
} catch {
|
|
14472
|
+
}
|
|
14473
|
+
}
|
|
14474
|
+
return preview;
|
|
14475
|
+
}
|
|
14476
|
+
function formatStandardsReport(report) {
|
|
14477
|
+
const lines = [];
|
|
14478
|
+
lines.push("Standards Configuration Applied");
|
|
14479
|
+
lines.push("\u2500".repeat(40));
|
|
14480
|
+
lines.push(`Files modified: ${report.modifiedFiles.length}`);
|
|
14481
|
+
lines.push(`Placeholders replaced: ${report.replacedPlaceholders.length}`);
|
|
14482
|
+
if (report.modifiedFiles.length > 0) {
|
|
14483
|
+
lines.push("");
|
|
14484
|
+
lines.push("Modified files:");
|
|
14485
|
+
for (const file of report.modifiedFiles) {
|
|
14486
|
+
lines.push(` \u2713 ${file}`);
|
|
14487
|
+
}
|
|
14488
|
+
}
|
|
14489
|
+
if (report.unusedPlaceholders.length > 0) {
|
|
14490
|
+
lines.push("");
|
|
14491
|
+
lines.push("Unused placeholders (no matching templates):");
|
|
14492
|
+
for (const p of report.unusedPlaceholders.slice(0, 5)) {
|
|
14493
|
+
lines.push(` - ${p}`);
|
|
14494
|
+
}
|
|
14495
|
+
if (report.unusedPlaceholders.length > 5) {
|
|
14496
|
+
lines.push(` ... and ${report.unusedPlaceholders.length - 5} more`);
|
|
14497
|
+
}
|
|
14498
|
+
}
|
|
14499
|
+
if (report.errors.length > 0) {
|
|
14500
|
+
lines.push("");
|
|
14501
|
+
lines.push("Errors:");
|
|
14502
|
+
for (const error of report.errors) {
|
|
14503
|
+
lines.push(` \u2717 ${error}`);
|
|
14504
|
+
}
|
|
14505
|
+
}
|
|
14506
|
+
return lines.join("\n");
|
|
14507
|
+
}
|
|
14508
|
+
|
|
14509
|
+
// src/lib/standards/scanner.ts
|
|
14510
|
+
init_esm_shims();
|
|
14511
|
+
import * as fs7 from "fs/promises";
|
|
14512
|
+
import * as path9 from "path";
|
|
14513
|
+
var SCANNABLE_EXTENSIONS2 = [".md", ".json", ".yaml", ".yml", ".txt"];
|
|
14514
|
+
var PLACEHOLDER_PATTERN = /\{\{([A-Z_]+)\}\}/g;
|
|
14515
|
+
async function getScanableFiles(dir) {
|
|
14516
|
+
const files = [];
|
|
14517
|
+
try {
|
|
14518
|
+
const entries = await fs7.readdir(dir, { withFileTypes: true });
|
|
14519
|
+
for (const entry of entries) {
|
|
14520
|
+
const fullPath = path9.join(dir, entry.name);
|
|
14521
|
+
if (entry.isDirectory()) {
|
|
14522
|
+
const subFiles = await getScanableFiles(fullPath);
|
|
14523
|
+
files.push(...subFiles);
|
|
14524
|
+
} else if (entry.isFile()) {
|
|
14525
|
+
const ext = path9.extname(entry.name).toLowerCase();
|
|
14526
|
+
if (SCANNABLE_EXTENSIONS2.includes(ext)) {
|
|
14527
|
+
files.push(fullPath);
|
|
14528
|
+
}
|
|
14529
|
+
}
|
|
14530
|
+
}
|
|
14531
|
+
} catch {
|
|
14532
|
+
}
|
|
14533
|
+
return files;
|
|
14534
|
+
}
|
|
14535
|
+
function extractPlaceholders2(content) {
|
|
14536
|
+
const matches = content.match(PLACEHOLDER_PATTERN);
|
|
14537
|
+
return matches ? [...new Set(matches)] : [];
|
|
14538
|
+
}
|
|
14539
|
+
async function scanStandardsPlaceholders(claudePath, config) {
|
|
14540
|
+
const standardsDir = path9.join(claudePath, "docs", "standards");
|
|
14541
|
+
const files = await getScanableFiles(standardsDir);
|
|
14542
|
+
const placeholdersByFile = /* @__PURE__ */ new Map();
|
|
14543
|
+
const allPlaceholders = /* @__PURE__ */ new Set();
|
|
14544
|
+
for (const file of files) {
|
|
14545
|
+
try {
|
|
14546
|
+
const content = await fs7.readFile(file, "utf-8");
|
|
14547
|
+
const placeholders = extractPlaceholders2(content);
|
|
14548
|
+
if (placeholders.length > 0) {
|
|
14549
|
+
const relPath = path9.relative(claudePath, file);
|
|
14550
|
+
placeholdersByFile.set(relPath, placeholders);
|
|
14551
|
+
for (const p of placeholders) {
|
|
14552
|
+
allPlaceholders.add(p);
|
|
14553
|
+
}
|
|
14554
|
+
}
|
|
14555
|
+
} catch {
|
|
14556
|
+
}
|
|
14557
|
+
}
|
|
14558
|
+
const configuredPlaceholders = config ? new Set(Object.keys(flattenStandardsConfig(config))) : /* @__PURE__ */ new Set();
|
|
14559
|
+
const unconfigured = /* @__PURE__ */ new Map();
|
|
14560
|
+
for (const placeholder of allPlaceholders) {
|
|
14561
|
+
if (!configuredPlaceholders.has(placeholder)) {
|
|
14562
|
+
const filesWithPlaceholder = [];
|
|
14563
|
+
for (const [file, placeholders] of placeholdersByFile) {
|
|
14564
|
+
if (placeholders.includes(placeholder)) {
|
|
14565
|
+
filesWithPlaceholder.push(file);
|
|
14566
|
+
}
|
|
14567
|
+
}
|
|
14568
|
+
unconfigured.set(placeholder, filesWithPlaceholder);
|
|
14569
|
+
}
|
|
14570
|
+
}
|
|
14571
|
+
return {
|
|
14572
|
+
unconfiguredPlaceholders: Array.from(unconfigured.entries()).map(([placeholder, files2]) => ({
|
|
14573
|
+
placeholder,
|
|
14574
|
+
files: files2
|
|
14575
|
+
})),
|
|
14576
|
+
totalPlaceholders: allPlaceholders.size,
|
|
14577
|
+
configuredPlaceholders: configuredPlaceholders.size
|
|
14578
|
+
};
|
|
14579
|
+
}
|
|
14580
|
+
function formatScanResult(result) {
|
|
14581
|
+
const lines = [];
|
|
14582
|
+
lines.push("Standards Placeholder Scan");
|
|
14583
|
+
lines.push("\u2500".repeat(40));
|
|
14584
|
+
lines.push(`Total placeholders found: ${result.totalPlaceholders}`);
|
|
14585
|
+
lines.push(`Already configured: ${result.configuredPlaceholders}`);
|
|
14586
|
+
lines.push(`Unconfigured: ${result.unconfiguredPlaceholders.length}`);
|
|
14587
|
+
if (result.unconfiguredPlaceholders.length > 0) {
|
|
14588
|
+
lines.push("");
|
|
14589
|
+
lines.push("Unconfigured placeholders:");
|
|
14590
|
+
for (const { placeholder, files } of result.unconfiguredPlaceholders) {
|
|
14591
|
+
lines.push(` ${placeholder}`);
|
|
14592
|
+
for (const file of files.slice(0, 3)) {
|
|
14593
|
+
lines.push(` \u2514\u2500 ${file}`);
|
|
14594
|
+
}
|
|
14595
|
+
if (files.length > 3) {
|
|
14596
|
+
lines.push(` \u2514\u2500 ... and ${files.length - 3} more files`);
|
|
14597
|
+
}
|
|
14598
|
+
}
|
|
14599
|
+
} else {
|
|
14600
|
+
lines.push("");
|
|
14601
|
+
lines.push("\u2713 All placeholders are configured!");
|
|
14602
|
+
}
|
|
14603
|
+
return lines.join("\n");
|
|
14604
|
+
}
|
|
14605
|
+
|
|
14606
|
+
// src/lib/standards/template-sync.ts
|
|
14607
|
+
init_esm_shims();
|
|
14608
|
+
import * as fs8 from "fs/promises";
|
|
14609
|
+
import * as path10 from "path";
|
|
14610
|
+
import ora4 from "ora";
|
|
14611
|
+
var STANDARDS_TEMPLATES = [
|
|
14612
|
+
"code-standards.md",
|
|
14613
|
+
"testing-standards.md",
|
|
14614
|
+
"documentation-standards.md",
|
|
14615
|
+
"design-standards.md",
|
|
14616
|
+
"security-standards.md",
|
|
14617
|
+
"performance-standards.md"
|
|
14618
|
+
];
|
|
14619
|
+
async function fileExists2(filePath) {
|
|
14620
|
+
try {
|
|
14621
|
+
await fs8.access(filePath);
|
|
14622
|
+
return true;
|
|
14623
|
+
} catch {
|
|
14624
|
+
return false;
|
|
14625
|
+
}
|
|
14626
|
+
}
|
|
14627
|
+
async function createBackup(filePath) {
|
|
14628
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
14629
|
+
const backupPath = `${filePath}.backup-${timestamp}`;
|
|
14630
|
+
await fs8.copyFile(filePath, backupPath);
|
|
14631
|
+
return backupPath;
|
|
14632
|
+
}
|
|
14633
|
+
async function hasPlaceholders(filePath) {
|
|
14634
|
+
try {
|
|
14635
|
+
const content = await fs8.readFile(filePath, "utf-8");
|
|
14636
|
+
return content.includes("AUTO-GENERATED: Configured values") || /\{\{[A-Z_]+\}\}/.test(content);
|
|
14637
|
+
} catch {
|
|
14638
|
+
return false;
|
|
14639
|
+
}
|
|
14640
|
+
}
|
|
14641
|
+
async function syncTemplate(templateName, sourcePath, targetPath, options) {
|
|
14642
|
+
const sourceFile = path10.join(sourcePath, templateName);
|
|
14643
|
+
const targetFile = path10.join(targetPath, templateName);
|
|
14644
|
+
if (!await fileExists2(sourceFile)) {
|
|
14645
|
+
return { status: "skipped" };
|
|
14646
|
+
}
|
|
14647
|
+
const targetExists = await fileExists2(targetFile);
|
|
14648
|
+
if (targetExists) {
|
|
14649
|
+
const alreadyHasPlaceholders = await hasPlaceholders(targetFile);
|
|
14650
|
+
if (alreadyHasPlaceholders && !options.overwrite) {
|
|
14651
|
+
return { status: "skipped" };
|
|
14652
|
+
}
|
|
14653
|
+
let backupPath;
|
|
14654
|
+
if (options.backup) {
|
|
14655
|
+
backupPath = await createBackup(targetFile);
|
|
14656
|
+
}
|
|
14657
|
+
await fs8.copyFile(sourceFile, targetFile);
|
|
14658
|
+
return { status: "updated", backup: backupPath };
|
|
14659
|
+
}
|
|
14660
|
+
await fs8.mkdir(path10.dirname(targetFile), { recursive: true });
|
|
14661
|
+
await fs8.copyFile(sourceFile, targetFile);
|
|
14662
|
+
return { status: "created" };
|
|
14663
|
+
}
|
|
14664
|
+
async function syncStandardsTemplates(claudePath, options = {}) {
|
|
14665
|
+
const result = {
|
|
14666
|
+
created: [],
|
|
14667
|
+
updated: [],
|
|
14668
|
+
skipped: [],
|
|
14669
|
+
errors: []
|
|
14670
|
+
};
|
|
14671
|
+
const packagesTemplatesPath = path10.join(getTemplatesPath(), "docs", "standards");
|
|
14672
|
+
const projectTemplatesPath = path10.join(claudePath, "docs", "standards");
|
|
14673
|
+
await fs8.mkdir(projectTemplatesPath, { recursive: true });
|
|
14674
|
+
for (const template of STANDARDS_TEMPLATES) {
|
|
14675
|
+
try {
|
|
14676
|
+
const syncResult = await syncTemplate(
|
|
14677
|
+
template,
|
|
14678
|
+
packagesTemplatesPath,
|
|
14679
|
+
projectTemplatesPath,
|
|
14680
|
+
options
|
|
14681
|
+
);
|
|
14682
|
+
switch (syncResult.status) {
|
|
14683
|
+
case "created":
|
|
14684
|
+
result.created.push(template);
|
|
14685
|
+
break;
|
|
14686
|
+
case "updated":
|
|
14687
|
+
result.updated.push(template);
|
|
14688
|
+
break;
|
|
14689
|
+
case "skipped":
|
|
14690
|
+
result.skipped.push(template);
|
|
14691
|
+
break;
|
|
14692
|
+
}
|
|
14693
|
+
} catch (error) {
|
|
14694
|
+
result.errors.push(`${template}: ${String(error)}`);
|
|
14695
|
+
}
|
|
14696
|
+
}
|
|
14697
|
+
return result;
|
|
14698
|
+
}
|
|
14699
|
+
async function syncStandardsTemplatesWithSpinner(claudePath, options = {}) {
|
|
14700
|
+
const spinner2 = ora4("Syncing standards templates...").start();
|
|
14701
|
+
try {
|
|
14702
|
+
const result = await syncStandardsTemplates(claudePath, options);
|
|
14703
|
+
const total = result.created.length + result.updated.length;
|
|
14704
|
+
if (total > 0) {
|
|
14705
|
+
spinner2.succeed(
|
|
14706
|
+
`Synced ${total} template${total !== 1 ? "s" : ""} (${result.created.length} created, ${result.updated.length} updated)`
|
|
14707
|
+
);
|
|
14708
|
+
} else if (result.skipped.length > 0) {
|
|
14709
|
+
spinner2.info("All templates already up to date");
|
|
14710
|
+
} else {
|
|
14711
|
+
spinner2.warn("No templates to sync");
|
|
14712
|
+
}
|
|
14713
|
+
return result;
|
|
14714
|
+
} catch (error) {
|
|
14715
|
+
spinner2.fail("Failed to sync templates");
|
|
14716
|
+
throw error;
|
|
14717
|
+
}
|
|
14718
|
+
}
|
|
14719
|
+
async function checkTemplatesNeedUpdate(claudePath) {
|
|
14720
|
+
const projectTemplatesPath = path10.join(claudePath, "docs", "standards");
|
|
14721
|
+
const missing = [];
|
|
14722
|
+
const outdated = [];
|
|
14723
|
+
for (const template of STANDARDS_TEMPLATES) {
|
|
14724
|
+
const targetFile = path10.join(projectTemplatesPath, template);
|
|
14725
|
+
if (!await fileExists2(targetFile)) {
|
|
14726
|
+
missing.push(template);
|
|
14727
|
+
} else if (!await hasPlaceholders(targetFile)) {
|
|
14728
|
+
outdated.push(template);
|
|
14729
|
+
}
|
|
14730
|
+
}
|
|
14731
|
+
return {
|
|
14732
|
+
needsUpdate: missing.length > 0 || outdated.length > 0,
|
|
14733
|
+
missing,
|
|
14734
|
+
outdated
|
|
14735
|
+
};
|
|
14736
|
+
}
|
|
14737
|
+
function formatSyncResult(result) {
|
|
14738
|
+
const lines = [];
|
|
14739
|
+
lines.push("Template Sync Results");
|
|
14740
|
+
lines.push("\u2500".repeat(40));
|
|
14741
|
+
if (result.created.length > 0) {
|
|
14742
|
+
lines.push(`Created: ${result.created.length}`);
|
|
14743
|
+
for (const f of result.created) {
|
|
14744
|
+
lines.push(` \u2713 ${f}`);
|
|
14745
|
+
}
|
|
14746
|
+
}
|
|
14747
|
+
if (result.updated.length > 0) {
|
|
14748
|
+
lines.push(`Updated: ${result.updated.length}`);
|
|
14749
|
+
for (const f of result.updated) {
|
|
14750
|
+
lines.push(` \u2713 ${f}`);
|
|
14751
|
+
}
|
|
14752
|
+
}
|
|
14753
|
+
if (result.skipped.length > 0) {
|
|
14754
|
+
lines.push(`Skipped (already up to date): ${result.skipped.length}`);
|
|
14755
|
+
}
|
|
14756
|
+
if (result.errors.length > 0) {
|
|
14757
|
+
lines.push(`Errors: ${result.errors.length}`);
|
|
14758
|
+
for (const e of result.errors) {
|
|
14759
|
+
lines.push(` \u2717 ${e}`);
|
|
14760
|
+
}
|
|
14761
|
+
}
|
|
14762
|
+
return lines.join("\n");
|
|
14763
|
+
}
|
|
14764
|
+
|
|
14765
|
+
// src/cli/commands/standards.ts
|
|
14766
|
+
init_fs();
|
|
14767
|
+
|
|
14768
|
+
// src/cli/prompts/standards.ts
|
|
14769
|
+
init_esm_shims();
|
|
14770
|
+
async function promptStandardsConfig(options) {
|
|
14771
|
+
logger.section("Project Standards", "\u{1F4D0}");
|
|
14772
|
+
logger.info("Configure quality standards for your project");
|
|
14773
|
+
logger.newline();
|
|
14774
|
+
if (options?.category) {
|
|
14775
|
+
const existingConfig = options.defaults ?? DEFAULT_STANDARDS_CONFIG;
|
|
14776
|
+
const categoryConfig = await promptCategoryConfig(options.category, existingConfig);
|
|
14777
|
+
return {
|
|
14778
|
+
...existingConfig,
|
|
14779
|
+
[options.category]: categoryConfig
|
|
14780
|
+
};
|
|
14781
|
+
}
|
|
14782
|
+
const enableStandards = await confirm({
|
|
14783
|
+
message: "Would you like to configure project standards?",
|
|
14784
|
+
default: true
|
|
14785
|
+
});
|
|
14786
|
+
if (!enableStandards) {
|
|
14787
|
+
return DEFAULT_STANDARDS_CONFIG;
|
|
14788
|
+
}
|
|
14789
|
+
const preset = await promptStandardsPreset();
|
|
14790
|
+
if (preset !== "custom") {
|
|
14791
|
+
const presetConfig = STANDARDS_PRESETS[preset];
|
|
14792
|
+
logger.success(`Using "${presetConfig.name}" preset`);
|
|
14793
|
+
return presetConfig.config;
|
|
14794
|
+
}
|
|
14795
|
+
logger.newline();
|
|
14796
|
+
logger.info("Configure each standards category:");
|
|
14797
|
+
const codeConfig = await promptCodeStandards(options?.defaults?.code);
|
|
14798
|
+
const testingConfig = await promptTestingStandards(options?.defaults?.testing);
|
|
14799
|
+
const documentationConfig = await promptDocumentationStandards(options?.defaults?.documentation);
|
|
14800
|
+
const designConfig = await promptDesignStandards(options?.defaults?.design);
|
|
14801
|
+
const securityConfig = await promptSecurityStandards(options?.defaults?.security);
|
|
14802
|
+
const performanceConfig = await promptPerformanceStandards(options?.defaults?.performance);
|
|
14803
|
+
return {
|
|
14804
|
+
code: codeConfig,
|
|
14805
|
+
testing: testingConfig,
|
|
14806
|
+
documentation: documentationConfig,
|
|
14807
|
+
design: designConfig,
|
|
14808
|
+
security: securityConfig,
|
|
14809
|
+
performance: performanceConfig
|
|
14810
|
+
};
|
|
14811
|
+
}
|
|
14812
|
+
async function promptStandardsPreset() {
|
|
14813
|
+
return select({
|
|
14814
|
+
message: "Choose a standards preset:",
|
|
14815
|
+
choices: Object.entries(STANDARDS_PRESETS).map(([key, preset]) => ({
|
|
14816
|
+
name: `${preset.name} - ${preset.description}`,
|
|
14817
|
+
value: key
|
|
14818
|
+
})),
|
|
14819
|
+
default: "balanced"
|
|
14820
|
+
});
|
|
14821
|
+
}
|
|
14822
|
+
async function promptCategoryConfig(category, existingConfig) {
|
|
14823
|
+
switch (category) {
|
|
14824
|
+
case "code":
|
|
14825
|
+
return promptCodeStandards(existingConfig.code);
|
|
14826
|
+
case "testing":
|
|
14827
|
+
return promptTestingStandards(existingConfig.testing);
|
|
14828
|
+
case "documentation":
|
|
14829
|
+
return promptDocumentationStandards(existingConfig.documentation);
|
|
14830
|
+
case "design":
|
|
14831
|
+
return promptDesignStandards(existingConfig.design);
|
|
14832
|
+
case "security":
|
|
14833
|
+
return promptSecurityStandards(existingConfig.security);
|
|
14834
|
+
case "performance":
|
|
14835
|
+
return promptPerformanceStandards(existingConfig.performance);
|
|
14836
|
+
}
|
|
14837
|
+
}
|
|
14838
|
+
async function promptCodeStandards(defaults) {
|
|
14839
|
+
const def = STANDARDS_DEFINITIONS.code;
|
|
14840
|
+
logger.newline();
|
|
14841
|
+
logger.subtitle(`${def.icon} ${def.name}`);
|
|
14842
|
+
const indentStyle = await select({
|
|
14843
|
+
message: "Indent style:",
|
|
14844
|
+
choices: [
|
|
14845
|
+
{ name: "Spaces", value: "space" },
|
|
14846
|
+
{ name: "Tabs", value: "tab" }
|
|
14847
|
+
],
|
|
14848
|
+
default: defaults?.indentStyle ?? DEFAULT_STANDARDS_CONFIG.code.indentStyle
|
|
14849
|
+
});
|
|
14850
|
+
const indentSize = await select({
|
|
14851
|
+
message: "Indent size:",
|
|
14852
|
+
choices: [
|
|
14853
|
+
{ name: "2 spaces", value: 2 },
|
|
14854
|
+
{ name: "4 spaces", value: 4 }
|
|
14855
|
+
],
|
|
14856
|
+
default: defaults?.indentSize ?? DEFAULT_STANDARDS_CONFIG.code.indentSize
|
|
14857
|
+
});
|
|
14858
|
+
const maxLineLength = await select({
|
|
14859
|
+
message: "Max line length:",
|
|
14860
|
+
choices: [
|
|
14861
|
+
{ name: "80 characters", value: 80 },
|
|
14862
|
+
{ name: "100 characters", value: 100 },
|
|
14863
|
+
{ name: "120 characters", value: 120 }
|
|
14864
|
+
],
|
|
14865
|
+
default: defaults?.maxLineLength ?? DEFAULT_STANDARDS_CONFIG.code.maxLineLength
|
|
14866
|
+
});
|
|
14867
|
+
const maxFileLines = await select({
|
|
14868
|
+
message: "Max file lines:",
|
|
14869
|
+
choices: [
|
|
14870
|
+
{ name: "300 lines (strict)", value: 300 },
|
|
14871
|
+
{ name: "500 lines (standard)", value: 500 },
|
|
14872
|
+
{ name: "800 lines (relaxed)", value: 800 }
|
|
14873
|
+
],
|
|
14874
|
+
default: defaults?.maxFileLines ?? DEFAULT_STANDARDS_CONFIG.code.maxFileLines
|
|
14875
|
+
});
|
|
14876
|
+
const quoteStyle = await select({
|
|
14877
|
+
message: "Quote style:",
|
|
14878
|
+
choices: [
|
|
14879
|
+
{ name: "Single quotes", value: "single" },
|
|
14880
|
+
{ name: "Double quotes", value: "double" }
|
|
14881
|
+
],
|
|
14882
|
+
default: defaults?.quoteStyle ?? DEFAULT_STANDARDS_CONFIG.code.quoteStyle
|
|
14883
|
+
});
|
|
14884
|
+
const semicolons = await confirm({
|
|
14885
|
+
message: "Use semicolons?",
|
|
14886
|
+
default: defaults?.semicolons ?? DEFAULT_STANDARDS_CONFIG.code.semicolons
|
|
14887
|
+
});
|
|
14888
|
+
const trailingCommas = await select({
|
|
14889
|
+
message: "Trailing commas:",
|
|
14890
|
+
choices: [
|
|
14891
|
+
{ name: "ES5 (recommended)", value: "es5" },
|
|
14892
|
+
{ name: "All", value: "all" },
|
|
14893
|
+
{ name: "None", value: "none" }
|
|
14894
|
+
],
|
|
14895
|
+
default: defaults?.trailingCommas ?? DEFAULT_STANDARDS_CONFIG.code.trailingCommas
|
|
14896
|
+
});
|
|
14897
|
+
const allowAny = await confirm({
|
|
14898
|
+
message: 'Allow "any" type in TypeScript?',
|
|
14899
|
+
default: defaults?.allowAny ?? DEFAULT_STANDARDS_CONFIG.code.allowAny
|
|
14900
|
+
});
|
|
14901
|
+
const namedExportsOnly = await confirm({
|
|
14902
|
+
message: "Require named exports only (no default exports)?",
|
|
14903
|
+
default: defaults?.namedExportsOnly ?? DEFAULT_STANDARDS_CONFIG.code.namedExportsOnly
|
|
14904
|
+
});
|
|
14905
|
+
const roroPattern = await confirm({
|
|
14906
|
+
message: "Require RO-RO pattern (Receive Object, Return Object)?",
|
|
14907
|
+
default: defaults?.roroPattern ?? DEFAULT_STANDARDS_CONFIG.code.roroPattern
|
|
14908
|
+
});
|
|
14909
|
+
const jsDocRequired = await confirm({
|
|
14910
|
+
message: "Require JSDoc for all exports?",
|
|
14911
|
+
default: defaults?.jsDocRequired ?? DEFAULT_STANDARDS_CONFIG.code.jsDocRequired
|
|
14912
|
+
});
|
|
14913
|
+
return {
|
|
14914
|
+
indentStyle,
|
|
14915
|
+
indentSize,
|
|
14916
|
+
maxLineLength,
|
|
14917
|
+
maxFileLines,
|
|
14918
|
+
quoteStyle,
|
|
14919
|
+
semicolons,
|
|
14920
|
+
trailingCommas,
|
|
14921
|
+
allowAny,
|
|
14922
|
+
namedExportsOnly,
|
|
14923
|
+
roroPattern,
|
|
14924
|
+
jsDocRequired
|
|
14925
|
+
};
|
|
14926
|
+
}
|
|
14927
|
+
async function promptTestingStandards(defaults) {
|
|
14928
|
+
const def = STANDARDS_DEFINITIONS.testing;
|
|
14929
|
+
logger.newline();
|
|
14930
|
+
logger.subtitle(`${def.icon} ${def.name}`);
|
|
14931
|
+
const coverageTarget = await select({
|
|
14932
|
+
message: "Minimum code coverage:",
|
|
14933
|
+
choices: [
|
|
14934
|
+
{ name: "60% (startup)", value: 60 },
|
|
14935
|
+
{ name: "70% (relaxed)", value: 70 },
|
|
14936
|
+
{ name: "80% (standard)", value: 80 },
|
|
14937
|
+
{ name: "90% (strict)", value: 90 },
|
|
14938
|
+
{ name: "95% (enterprise)", value: 95 }
|
|
14939
|
+
],
|
|
14940
|
+
default: defaults?.coverageTarget ?? DEFAULT_STANDARDS_CONFIG.testing.coverageTarget
|
|
14941
|
+
});
|
|
14942
|
+
const tddRequired = await confirm({
|
|
14943
|
+
message: "Require TDD methodology (Red-Green-Refactor)?",
|
|
14944
|
+
default: defaults?.tddRequired ?? DEFAULT_STANDARDS_CONFIG.testing.tddRequired
|
|
14945
|
+
});
|
|
14946
|
+
const testPattern = await select({
|
|
14947
|
+
message: "Test pattern:",
|
|
14948
|
+
choices: [
|
|
14949
|
+
{ name: "AAA (Arrange-Act-Assert)", value: "aaa" },
|
|
14950
|
+
{ name: "GWT (Given-When-Then)", value: "gwt" }
|
|
14951
|
+
],
|
|
14952
|
+
default: defaults?.testPattern ?? DEFAULT_STANDARDS_CONFIG.testing.testPattern
|
|
14953
|
+
});
|
|
14954
|
+
const testLocation = await select({
|
|
14955
|
+
message: "Test file location:",
|
|
14956
|
+
choices: [
|
|
14957
|
+
{ name: "Separate (test/ folder)", value: "separate" },
|
|
14958
|
+
{ name: "Colocated (__tests__ near source)", value: "colocated" }
|
|
14959
|
+
],
|
|
14960
|
+
default: defaults?.testLocation ?? DEFAULT_STANDARDS_CONFIG.testing.testLocation
|
|
14961
|
+
});
|
|
14962
|
+
const unitTestMaxMs = await select({
|
|
14963
|
+
message: "Max time per unit test:",
|
|
14964
|
+
choices: [
|
|
14965
|
+
{ name: "50ms (fast)", value: 50 },
|
|
14966
|
+
{ name: "100ms (standard)", value: 100 },
|
|
14967
|
+
{ name: "200ms (relaxed)", value: 200 }
|
|
14968
|
+
],
|
|
14969
|
+
default: defaults?.unitTestMaxMs ?? DEFAULT_STANDARDS_CONFIG.testing.unitTestMaxMs
|
|
14970
|
+
});
|
|
14971
|
+
const integrationTestMaxMs = await select({
|
|
14972
|
+
message: "Max time per integration test:",
|
|
14973
|
+
choices: [
|
|
14974
|
+
{ name: "500ms (fast)", value: 500 },
|
|
14975
|
+
{ name: "1000ms (standard)", value: 1e3 },
|
|
14976
|
+
{ name: "2000ms (relaxed)", value: 2e3 }
|
|
14977
|
+
],
|
|
14978
|
+
default: defaults?.integrationTestMaxMs ?? DEFAULT_STANDARDS_CONFIG.testing.integrationTestMaxMs
|
|
14979
|
+
});
|
|
14980
|
+
return {
|
|
14981
|
+
coverageTarget,
|
|
14982
|
+
tddRequired,
|
|
14983
|
+
testPattern,
|
|
14984
|
+
testLocation,
|
|
14985
|
+
unitTestMaxMs,
|
|
14986
|
+
integrationTestMaxMs
|
|
14987
|
+
};
|
|
14988
|
+
}
|
|
14989
|
+
async function promptDocumentationStandards(defaults) {
|
|
14990
|
+
const def = STANDARDS_DEFINITIONS.documentation;
|
|
14991
|
+
logger.newline();
|
|
14992
|
+
logger.subtitle(`${def.icon} ${def.name}`);
|
|
14993
|
+
const jsDocLevel = await select({
|
|
14994
|
+
message: "JSDoc detail level:",
|
|
14995
|
+
choices: [
|
|
14996
|
+
{ name: "Minimal (brief description)", value: "minimal" },
|
|
14997
|
+
{ name: "Standard (description + params + returns)", value: "standard" },
|
|
14998
|
+
{ name: "Comprehensive (full docs with examples)", value: "comprehensive" }
|
|
14999
|
+
],
|
|
15000
|
+
default: defaults?.jsDocLevel ?? DEFAULT_STANDARDS_CONFIG.documentation.jsDocLevel
|
|
15001
|
+
});
|
|
15002
|
+
const requireExamples = await confirm({
|
|
15003
|
+
message: "Require @example in JSDoc?",
|
|
15004
|
+
default: defaults?.requireExamples ?? DEFAULT_STANDARDS_CONFIG.documentation.requireExamples
|
|
15005
|
+
});
|
|
15006
|
+
const changelogFormat = await select({
|
|
15007
|
+
message: "Changelog format:",
|
|
15008
|
+
choices: [
|
|
15009
|
+
{ name: "Conventional (auto-generated from commits)", value: "conventional" },
|
|
15010
|
+
{ name: "Keep a Changelog (manual, semantic)", value: "keepachangelog" }
|
|
15011
|
+
],
|
|
15012
|
+
default: defaults?.changelogFormat ?? DEFAULT_STANDARDS_CONFIG.documentation.changelogFormat
|
|
15013
|
+
});
|
|
15014
|
+
const inlineCommentPolicy = await select({
|
|
15015
|
+
message: "Inline comment policy:",
|
|
15016
|
+
choices: [
|
|
15017
|
+
{ name: "Why not What (explain reasoning)", value: "why-not-what" },
|
|
15018
|
+
{ name: "Minimal (only when necessary)", value: "minimal" },
|
|
15019
|
+
{ name: "Extensive (comment thoroughly)", value: "extensive" }
|
|
15020
|
+
],
|
|
15021
|
+
default: defaults?.inlineCommentPolicy ?? DEFAULT_STANDARDS_CONFIG.documentation.inlineCommentPolicy
|
|
15022
|
+
});
|
|
15023
|
+
return {
|
|
15024
|
+
jsDocLevel,
|
|
15025
|
+
requireExamples,
|
|
15026
|
+
changelogFormat,
|
|
15027
|
+
inlineCommentPolicy
|
|
15028
|
+
};
|
|
15029
|
+
}
|
|
15030
|
+
async function promptDesignStandards(defaults) {
|
|
15031
|
+
const def = STANDARDS_DEFINITIONS.design;
|
|
15032
|
+
logger.newline();
|
|
15033
|
+
logger.subtitle(`${def.icon} ${def.name}`);
|
|
15034
|
+
const cssFramework = await select({
|
|
15035
|
+
message: "CSS framework:",
|
|
15036
|
+
choices: [
|
|
15037
|
+
{ name: "Tailwind CSS", value: "tailwind" },
|
|
15038
|
+
{ name: "CSS Modules", value: "css-modules" },
|
|
15039
|
+
{ name: "Styled Components", value: "styled-components" },
|
|
15040
|
+
{ name: "Vanilla CSS", value: "vanilla" }
|
|
15041
|
+
],
|
|
15042
|
+
default: defaults?.cssFramework ?? DEFAULT_STANDARDS_CONFIG.design.cssFramework
|
|
15043
|
+
});
|
|
15044
|
+
const componentLibrary = await select({
|
|
15045
|
+
message: "Component library:",
|
|
15046
|
+
choices: [
|
|
15047
|
+
{ name: "shadcn/ui", value: "shadcn" },
|
|
15048
|
+
{ name: "Radix UI", value: "radix" },
|
|
15049
|
+
{ name: "Headless UI", value: "headless" },
|
|
15050
|
+
{ name: "None", value: "none" }
|
|
15051
|
+
],
|
|
15052
|
+
default: defaults?.componentLibrary ?? DEFAULT_STANDARDS_CONFIG.design.componentLibrary
|
|
15053
|
+
});
|
|
15054
|
+
const accessibilityLevel = await select({
|
|
15055
|
+
message: "WCAG accessibility level:",
|
|
15056
|
+
choices: [
|
|
15057
|
+
{ name: "Level A (minimum)", value: "A" },
|
|
15058
|
+
{ name: "Level AA (recommended)", value: "AA" },
|
|
15059
|
+
{ name: "Level AAA (highest)", value: "AAA" }
|
|
15060
|
+
],
|
|
15061
|
+
default: defaults?.accessibilityLevel ?? DEFAULT_STANDARDS_CONFIG.design.accessibilityLevel
|
|
15062
|
+
});
|
|
15063
|
+
const darkModeSupport = await confirm({
|
|
15064
|
+
message: "Support dark mode?",
|
|
15065
|
+
default: defaults?.darkModeSupport ?? DEFAULT_STANDARDS_CONFIG.design.darkModeSupport
|
|
15066
|
+
});
|
|
15067
|
+
return {
|
|
15068
|
+
cssFramework,
|
|
15069
|
+
componentLibrary,
|
|
15070
|
+
accessibilityLevel,
|
|
15071
|
+
darkModeSupport
|
|
15072
|
+
};
|
|
15073
|
+
}
|
|
15074
|
+
async function promptSecurityStandards(defaults) {
|
|
15075
|
+
const def = STANDARDS_DEFINITIONS.security;
|
|
15076
|
+
logger.newline();
|
|
15077
|
+
logger.subtitle(`${def.icon} ${def.name}`);
|
|
15078
|
+
const authPattern = await select({
|
|
15079
|
+
message: "Authentication pattern:",
|
|
15080
|
+
choices: [
|
|
15081
|
+
{ name: "JWT (JSON Web Tokens)", value: "jwt" },
|
|
15082
|
+
{ name: "Session (server-side)", value: "session" },
|
|
15083
|
+
{ name: "OAuth 2.0 / OIDC", value: "oauth" },
|
|
15084
|
+
{ name: "None", value: "none" }
|
|
15085
|
+
],
|
|
15086
|
+
default: defaults?.authPattern ?? DEFAULT_STANDARDS_CONFIG.security.authPattern
|
|
15087
|
+
});
|
|
15088
|
+
const inputValidation = await select({
|
|
15089
|
+
message: "Input validation library:",
|
|
15090
|
+
choices: [
|
|
15091
|
+
{ name: "Zod (TypeScript-first)", value: "zod" },
|
|
15092
|
+
{ name: "Yup (schema builder)", value: "yup" },
|
|
15093
|
+
{ name: "Joi (data validation)", value: "joi" },
|
|
15094
|
+
{ name: "Manual (custom)", value: "manual" }
|
|
15095
|
+
],
|
|
15096
|
+
default: defaults?.inputValidation ?? DEFAULT_STANDARDS_CONFIG.security.inputValidation
|
|
15097
|
+
});
|
|
15098
|
+
const csrfProtection = await confirm({
|
|
15099
|
+
message: "Enable CSRF protection?",
|
|
15100
|
+
default: defaults?.csrfProtection ?? DEFAULT_STANDARDS_CONFIG.security.csrfProtection
|
|
15101
|
+
});
|
|
15102
|
+
const rateLimiting = await confirm({
|
|
15103
|
+
message: "Enable rate limiting?",
|
|
15104
|
+
default: defaults?.rateLimiting ?? DEFAULT_STANDARDS_CONFIG.security.rateLimiting
|
|
15105
|
+
});
|
|
15106
|
+
return {
|
|
15107
|
+
authPattern,
|
|
15108
|
+
inputValidation,
|
|
15109
|
+
csrfProtection,
|
|
15110
|
+
rateLimiting
|
|
15111
|
+
};
|
|
15112
|
+
}
|
|
15113
|
+
async function promptPerformanceStandards(defaults) {
|
|
15114
|
+
const def = STANDARDS_DEFINITIONS.performance;
|
|
15115
|
+
logger.newline();
|
|
15116
|
+
logger.subtitle(`${def.icon} ${def.name}`);
|
|
15117
|
+
const lcpTarget = await select({
|
|
15118
|
+
message: "LCP target (Largest Contentful Paint):",
|
|
15119
|
+
choices: [
|
|
15120
|
+
{ name: "1500ms (excellent)", value: 1500 },
|
|
15121
|
+
{ name: "2000ms (good)", value: 2e3 },
|
|
15122
|
+
{ name: "2500ms (standard)", value: 2500 },
|
|
15123
|
+
{ name: "4000ms (needs improvement)", value: 4e3 }
|
|
15124
|
+
],
|
|
15125
|
+
default: defaults?.lcpTarget ?? DEFAULT_STANDARDS_CONFIG.performance.lcpTarget
|
|
15126
|
+
});
|
|
15127
|
+
const fidTarget = await select({
|
|
15128
|
+
message: "FID target (First Input Delay):",
|
|
15129
|
+
choices: [
|
|
15130
|
+
{ name: "50ms (excellent)", value: 50 },
|
|
15131
|
+
{ name: "100ms (good)", value: 100 },
|
|
15132
|
+
{ name: "200ms (standard)", value: 200 },
|
|
15133
|
+
{ name: "300ms (needs improvement)", value: 300 }
|
|
15134
|
+
],
|
|
15135
|
+
default: defaults?.fidTarget ?? DEFAULT_STANDARDS_CONFIG.performance.fidTarget
|
|
15136
|
+
});
|
|
15137
|
+
const clsTarget = await select({
|
|
15138
|
+
message: "CLS target (Cumulative Layout Shift):",
|
|
15139
|
+
choices: [
|
|
15140
|
+
{ name: "0.05 (excellent)", value: 0.05 },
|
|
15141
|
+
{ name: "0.1 (good)", value: 0.1 },
|
|
15142
|
+
{ name: "0.15 (standard)", value: 0.15 },
|
|
15143
|
+
{ name: "0.25 (needs improvement)", value: 0.25 }
|
|
15144
|
+
],
|
|
15145
|
+
default: defaults?.clsTarget ?? DEFAULT_STANDARDS_CONFIG.performance.clsTarget
|
|
15146
|
+
});
|
|
15147
|
+
const bundleSizeTargetKb = await select({
|
|
15148
|
+
message: "Bundle size target (KB):",
|
|
15149
|
+
choices: [
|
|
15150
|
+
{ name: "100KB (strict)", value: 100 },
|
|
15151
|
+
{ name: "150KB (good)", value: 150 },
|
|
15152
|
+
{ name: "250KB (standard)", value: 250 },
|
|
15153
|
+
{ name: "500KB (relaxed)", value: 500 }
|
|
15154
|
+
],
|
|
15155
|
+
default: defaults?.bundleSizeTargetKb ?? DEFAULT_STANDARDS_CONFIG.performance.bundleSizeTargetKb
|
|
15156
|
+
});
|
|
15157
|
+
const apiResponseTargetMs = await select({
|
|
15158
|
+
message: "API response time target (ms):",
|
|
15159
|
+
choices: [
|
|
15160
|
+
{ name: "100ms (fast)", value: 100 },
|
|
15161
|
+
{ name: "200ms (good)", value: 200 },
|
|
15162
|
+
{ name: "300ms (standard)", value: 300 },
|
|
15163
|
+
{ name: "500ms (relaxed)", value: 500 }
|
|
15164
|
+
],
|
|
15165
|
+
default: defaults?.apiResponseTargetMs ?? DEFAULT_STANDARDS_CONFIG.performance.apiResponseTargetMs
|
|
15166
|
+
});
|
|
15167
|
+
return {
|
|
15168
|
+
lcpTarget,
|
|
15169
|
+
fidTarget,
|
|
15170
|
+
clsTarget,
|
|
15171
|
+
bundleSizeTargetKb,
|
|
15172
|
+
apiResponseTargetMs
|
|
15173
|
+
};
|
|
15174
|
+
}
|
|
15175
|
+
function showStandardsSummary(config) {
|
|
15176
|
+
logger.newline();
|
|
15177
|
+
logger.subtitle("Standards Summary");
|
|
15178
|
+
logger.item(
|
|
15179
|
+
`Code: ${config.code.indentSize} ${config.code.indentStyle}s, ${config.code.quoteStyle} quotes`
|
|
15180
|
+
);
|
|
15181
|
+
logger.info(
|
|
15182
|
+
colors.muted(
|
|
15183
|
+
` Max: ${config.code.maxLineLength} chars/line, ${config.code.maxFileLines} lines/file`
|
|
15184
|
+
)
|
|
15185
|
+
);
|
|
15186
|
+
logger.info(
|
|
15187
|
+
colors.muted(
|
|
15188
|
+
` Rules: ${config.code.allowAny ? "any allowed" : "no any"}, ${config.code.namedExportsOnly ? "named exports" : "default exports"}`
|
|
15189
|
+
)
|
|
15190
|
+
);
|
|
15191
|
+
logger.item(
|
|
15192
|
+
`Testing: ${config.testing.coverageTarget}% coverage, ${config.testing.tddRequired ? "TDD required" : "TDD optional"}`
|
|
15193
|
+
);
|
|
15194
|
+
logger.info(
|
|
15195
|
+
colors.muted(
|
|
15196
|
+
` Pattern: ${config.testing.testPattern.toUpperCase()}, Location: ${config.testing.testLocation}`
|
|
15197
|
+
)
|
|
15198
|
+
);
|
|
15199
|
+
logger.item(`Documentation: ${config.documentation.jsDocLevel} JSDoc`);
|
|
15200
|
+
logger.info(colors.muted(` Comments: ${config.documentation.inlineCommentPolicy}`));
|
|
15201
|
+
logger.item(`Design: ${config.design.cssFramework}, ${config.design.componentLibrary}`);
|
|
15202
|
+
logger.info(
|
|
15203
|
+
colors.muted(
|
|
15204
|
+
` A11y: WCAG ${config.design.accessibilityLevel}, ${config.design.darkModeSupport ? "dark mode" : "no dark mode"}`
|
|
15205
|
+
)
|
|
15206
|
+
);
|
|
15207
|
+
logger.item(`Security: ${config.security.authPattern}, ${config.security.inputValidation}`);
|
|
15208
|
+
logger.info(
|
|
15209
|
+
colors.muted(
|
|
15210
|
+
` ${config.security.csrfProtection ? "CSRF" : "no CSRF"}, ${config.security.rateLimiting ? "rate limiting" : "no rate limiting"}`
|
|
15211
|
+
)
|
|
15212
|
+
);
|
|
15213
|
+
logger.item(
|
|
15214
|
+
`Performance: LCP ${config.performance.lcpTarget}ms, FID ${config.performance.fidTarget}ms`
|
|
15215
|
+
);
|
|
15216
|
+
logger.info(
|
|
15217
|
+
colors.muted(
|
|
15218
|
+
` Bundle: ${config.performance.bundleSizeTargetKb}KB, API: ${config.performance.apiResponseTargetMs}ms`
|
|
15219
|
+
)
|
|
15220
|
+
);
|
|
15221
|
+
}
|
|
15222
|
+
async function confirmStandardsConfig(config) {
|
|
15223
|
+
showStandardsSummary(config);
|
|
15224
|
+
logger.newline();
|
|
15225
|
+
return confirm({
|
|
15226
|
+
message: "Apply these standards?",
|
|
15227
|
+
default: true
|
|
15228
|
+
});
|
|
15229
|
+
}
|
|
15230
|
+
|
|
15231
|
+
// src/cli/commands/standards.ts
|
|
15232
|
+
function createStandardsCommand() {
|
|
15233
|
+
const cmd = new Command8("standards").description("Configure project standards interactively").argument("[path]", "Project path (default: current directory)").option("--scan", "Scan for unconfigured standard placeholders").option(
|
|
15234
|
+
"-c, --category <name>",
|
|
15235
|
+
"Configure specific category (code|testing|documentation|design|security|performance)"
|
|
15236
|
+
).option("--preview", "Preview changes without applying").option("-y, --yes", "Accept defaults without prompts").option("-v, --verbose", "Detailed output").option("--update-templates", "Update/sync templates from package to project").action(runStandards);
|
|
15237
|
+
return cmd;
|
|
15238
|
+
}
|
|
15239
|
+
async function runStandards(path11, options) {
|
|
15240
|
+
const projectPath = resolvePath(path11 || ".");
|
|
15241
|
+
const claudePath = joinPath(projectPath, ".claude");
|
|
15242
|
+
logger.configure({ verbose: options.verbose, silent: false });
|
|
15243
|
+
logger.title("Project Standards Configuration");
|
|
15244
|
+
try {
|
|
15245
|
+
if (options.scan) {
|
|
15246
|
+
await scanMode2(claudePath, projectPath);
|
|
15247
|
+
return;
|
|
15248
|
+
}
|
|
15249
|
+
if (options.updateTemplates) {
|
|
15250
|
+
await updateTemplatesMode(claudePath, options);
|
|
15251
|
+
return;
|
|
15252
|
+
}
|
|
15253
|
+
if (options.preview) {
|
|
15254
|
+
await previewMode2(claudePath, projectPath);
|
|
15255
|
+
return;
|
|
15256
|
+
}
|
|
15257
|
+
if (options.yes) {
|
|
15258
|
+
await defaultsMode(claudePath, projectPath, options);
|
|
15259
|
+
return;
|
|
15260
|
+
}
|
|
15261
|
+
await interactiveMode2(claudePath, projectPath, options);
|
|
15262
|
+
} catch (error) {
|
|
15263
|
+
logger.error(
|
|
15264
|
+
`Standards configuration failed: ${error instanceof Error ? error.message : error}`
|
|
15265
|
+
);
|
|
15266
|
+
process.exit(1);
|
|
15267
|
+
}
|
|
15268
|
+
}
|
|
15269
|
+
async function scanMode2(claudePath, projectPath) {
|
|
15270
|
+
logger.info(`Scanning ${colors.primary(claudePath)} for standard placeholders...`);
|
|
15271
|
+
logger.newline();
|
|
15272
|
+
const existingConfig = await readConfig(projectPath);
|
|
15273
|
+
const standardsConfig = existingConfig?.extras?.standards;
|
|
15274
|
+
const scanResult = await scanStandardsPlaceholders(claudePath, standardsConfig);
|
|
15275
|
+
logger.info(formatScanResult(scanResult));
|
|
15276
|
+
if (scanResult.unconfiguredPlaceholders.length > 0) {
|
|
15277
|
+
logger.newline();
|
|
15278
|
+
logger.info("Run `claude-config standards` to configure them");
|
|
15279
|
+
}
|
|
15280
|
+
}
|
|
15281
|
+
async function updateTemplatesMode(claudePath, options) {
|
|
15282
|
+
logger.info("Checking for template updates...");
|
|
15283
|
+
logger.newline();
|
|
15284
|
+
const status = await checkTemplatesNeedUpdate(claudePath);
|
|
15285
|
+
if (!status.needsUpdate) {
|
|
15286
|
+
logger.success("All templates are up to date!");
|
|
15287
|
+
return;
|
|
15288
|
+
}
|
|
15289
|
+
if (status.missing.length > 0) {
|
|
15290
|
+
logger.info(`Missing templates (${status.missing.length}):`);
|
|
15291
|
+
for (const template of status.missing) {
|
|
15292
|
+
logger.info(` ${colors.warning("+")} ${template}`);
|
|
15293
|
+
}
|
|
15294
|
+
logger.newline();
|
|
15295
|
+
}
|
|
15296
|
+
if (status.outdated.length > 0) {
|
|
15297
|
+
logger.info(`Outdated templates (${status.outdated.length}):`);
|
|
15298
|
+
for (const template of status.outdated) {
|
|
15299
|
+
logger.info(` ${colors.primary("~")} ${template}`);
|
|
15300
|
+
}
|
|
15301
|
+
logger.newline();
|
|
15302
|
+
}
|
|
15303
|
+
const result = await syncStandardsTemplatesWithSpinner(claudePath, {
|
|
15304
|
+
overwrite: true,
|
|
15305
|
+
backup: true
|
|
15306
|
+
});
|
|
15307
|
+
if (options.verbose) {
|
|
15308
|
+
logger.newline();
|
|
15309
|
+
logger.info(formatSyncResult(result));
|
|
15310
|
+
}
|
|
15311
|
+
logger.newline();
|
|
15312
|
+
logger.success("Templates updated successfully!");
|
|
15313
|
+
logger.info("Run `claude-config standards` to configure the new placeholders");
|
|
15314
|
+
}
|
|
15315
|
+
async function previewMode2(claudePath, projectPath) {
|
|
15316
|
+
const existingConfig = await readConfig(projectPath);
|
|
15317
|
+
if (!existingConfig?.extras?.standards) {
|
|
15318
|
+
logger.warn("No standards configuration found");
|
|
15319
|
+
logger.info("Run `claude-config standards` first to set up configuration");
|
|
15320
|
+
return;
|
|
15321
|
+
}
|
|
15322
|
+
logger.info("Preview of replacements:");
|
|
15323
|
+
logger.newline();
|
|
15324
|
+
const replacements = await previewStandardsReplacements(
|
|
15325
|
+
claudePath,
|
|
15326
|
+
existingConfig.extras.standards
|
|
15327
|
+
);
|
|
15328
|
+
if (replacements.length === 0) {
|
|
15329
|
+
logger.info("No standard placeholders to replace");
|
|
15330
|
+
return;
|
|
15331
|
+
}
|
|
15332
|
+
const byFile = {};
|
|
15333
|
+
for (const r of replacements) {
|
|
15334
|
+
if (!byFile[r.file]) {
|
|
15335
|
+
byFile[r.file] = [];
|
|
15336
|
+
}
|
|
15337
|
+
byFile[r.file].push({ placeholder: r.placeholder, value: r.value });
|
|
15338
|
+
}
|
|
15339
|
+
for (const [file, changes] of Object.entries(byFile)) {
|
|
15340
|
+
logger.subtitle(file);
|
|
15341
|
+
for (const change of changes) {
|
|
15342
|
+
logger.info(` ${change.placeholder} \u2192 ${colors.primary(change.value)}`);
|
|
15343
|
+
}
|
|
15344
|
+
logger.newline();
|
|
15345
|
+
}
|
|
15346
|
+
logger.success(
|
|
15347
|
+
`Total: ${replacements.length} replacements in ${Object.keys(byFile).length} files`
|
|
15348
|
+
);
|
|
15349
|
+
}
|
|
15350
|
+
async function defaultsMode(claudePath, projectPath, options) {
|
|
15351
|
+
const templateStatus = await checkTemplatesNeedUpdate(claudePath);
|
|
15352
|
+
if (templateStatus.needsUpdate) {
|
|
15353
|
+
logger.warn("Some templates are missing or outdated:");
|
|
15354
|
+
if (templateStatus.missing.length > 0) {
|
|
15355
|
+
logger.info(` Missing: ${templateStatus.missing.length} template(s)`);
|
|
15356
|
+
}
|
|
15357
|
+
if (templateStatus.outdated.length > 0) {
|
|
15358
|
+
logger.info(` Outdated: ${templateStatus.outdated.length} template(s)`);
|
|
15359
|
+
}
|
|
15360
|
+
logger.newline();
|
|
15361
|
+
logger.info(
|
|
15362
|
+
`Run ${colors.primary("qazuor-claude-config standards --update-templates")} first to sync templates`
|
|
15363
|
+
);
|
|
15364
|
+
logger.newline();
|
|
15365
|
+
}
|
|
15366
|
+
logger.info("Applying default standards configuration...");
|
|
15367
|
+
logger.newline();
|
|
15368
|
+
const standardsConfig = DEFAULT_STANDARDS_CONFIG;
|
|
15369
|
+
showStandardsSummary(standardsConfig);
|
|
15370
|
+
logger.newline();
|
|
15371
|
+
const report = await replaceStandardsWithSpinner(claudePath, standardsConfig);
|
|
15372
|
+
if (options.verbose) {
|
|
15373
|
+
logger.newline();
|
|
15374
|
+
logger.info(formatStandardsReport(report));
|
|
15375
|
+
}
|
|
15376
|
+
if (report.modifiedFiles.length === 0 && report.unusedPlaceholders.length > 0) {
|
|
15377
|
+
logger.newline();
|
|
15378
|
+
logger.warn("No placeholders were replaced in templates.");
|
|
15379
|
+
logger.info(
|
|
15380
|
+
`Your templates might be outdated. Run ${colors.primary("--update-templates")} to sync them.`
|
|
15381
|
+
);
|
|
15382
|
+
}
|
|
15383
|
+
await saveStandardsConfig(projectPath, standardsConfig);
|
|
15384
|
+
logger.newline();
|
|
15385
|
+
logger.success("Standards configuration complete!");
|
|
15386
|
+
}
|
|
15387
|
+
async function interactiveMode2(claudePath, projectPath, options) {
|
|
15388
|
+
const templateStatus = await checkTemplatesNeedUpdate(claudePath);
|
|
15389
|
+
if (templateStatus.needsUpdate) {
|
|
15390
|
+
logger.warn("Some templates are missing or outdated:");
|
|
15391
|
+
if (templateStatus.missing.length > 0) {
|
|
15392
|
+
logger.info(` Missing: ${templateStatus.missing.length} template(s)`);
|
|
15393
|
+
}
|
|
15394
|
+
if (templateStatus.outdated.length > 0) {
|
|
15395
|
+
logger.info(` Outdated: ${templateStatus.outdated.length} template(s)`);
|
|
15396
|
+
}
|
|
15397
|
+
logger.newline();
|
|
15398
|
+
logger.info(
|
|
15399
|
+
`Run ${colors.primary("qazuor-claude-config standards --update-templates")} first to sync templates`
|
|
15400
|
+
);
|
|
15401
|
+
logger.newline();
|
|
15402
|
+
}
|
|
15403
|
+
const existingConfig = await readConfig(projectPath);
|
|
15404
|
+
const existingStandards = existingConfig?.extras?.standards;
|
|
15405
|
+
const standardsConfig = await promptStandardsConfig({
|
|
15406
|
+
defaults: existingStandards,
|
|
15407
|
+
category: options.category
|
|
15408
|
+
});
|
|
15409
|
+
const confirmed = await confirmStandardsConfig(standardsConfig);
|
|
15410
|
+
if (!confirmed) {
|
|
15411
|
+
logger.warn("Configuration cancelled");
|
|
15412
|
+
return;
|
|
15413
|
+
}
|
|
15414
|
+
const report = await replaceStandardsWithSpinner(claudePath, standardsConfig);
|
|
15415
|
+
if (options.verbose) {
|
|
15416
|
+
logger.newline();
|
|
15417
|
+
logger.info(formatStandardsReport(report));
|
|
15418
|
+
}
|
|
15419
|
+
if (report.modifiedFiles.length === 0 && report.unusedPlaceholders.length > 0) {
|
|
15420
|
+
logger.newline();
|
|
15421
|
+
logger.warn("No placeholders were replaced in templates.");
|
|
15422
|
+
logger.info(
|
|
15423
|
+
`Your templates might be outdated. Run ${colors.primary("--update-templates")} to sync them.`
|
|
15424
|
+
);
|
|
15425
|
+
}
|
|
15426
|
+
await saveStandardsConfig(projectPath, standardsConfig);
|
|
15427
|
+
logger.newline();
|
|
15428
|
+
logger.success("Standards configuration complete!");
|
|
15429
|
+
}
|
|
15430
|
+
async function saveStandardsConfig(projectPath, standardsConfig) {
|
|
15431
|
+
const existingConfig = await readConfig(projectPath);
|
|
15432
|
+
if (existingConfig) {
|
|
15433
|
+
existingConfig.extras = {
|
|
15434
|
+
...existingConfig.extras,
|
|
15435
|
+
standards: standardsConfig
|
|
15436
|
+
};
|
|
15437
|
+
existingConfig.customizations.lastUpdated = (/* @__PURE__ */ new Date()).toISOString();
|
|
15438
|
+
await writeConfig(projectPath, existingConfig);
|
|
15439
|
+
logger.success("Configuration saved to .claude/qazuor-claude-config.json");
|
|
15440
|
+
} else {
|
|
15441
|
+
logger.warn("No existing config found - standards not saved");
|
|
15442
|
+
logger.info("Run `claude-config init` first to initialize the project");
|
|
15443
|
+
}
|
|
15444
|
+
}
|
|
15445
|
+
|
|
13284
15446
|
// src/cli/index.ts
|
|
13285
15447
|
var VERSION2 = "0.1.0";
|
|
13286
|
-
var program = new
|
|
15448
|
+
var program = new Command9().name("qazuor-claude-config").description("CLI tool to install and manage Claude Code configurations").version(VERSION2);
|
|
13287
15449
|
program.addCommand(createInitCommand());
|
|
13288
15450
|
program.addCommand(createListCommand());
|
|
13289
15451
|
program.addCommand(createAddCommand());
|
|
@@ -13291,6 +15453,7 @@ program.addCommand(createRemoveCommand());
|
|
|
13291
15453
|
program.addCommand(createStatusCommand());
|
|
13292
15454
|
program.addCommand(createUpdateCommand());
|
|
13293
15455
|
program.addCommand(createConfigureCommand());
|
|
15456
|
+
program.addCommand(createStandardsCommand());
|
|
13294
15457
|
|
|
13295
15458
|
// src/lib/utils/banner.ts
|
|
13296
15459
|
init_esm_shims();
|