claudekit-cli 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/.github/workflows/ci.yml +2 -0
  2. package/CHANGELOG.md +19 -0
  3. package/CLAUDE.md +7 -0
  4. package/README.md +61 -3
  5. package/biome.json +3 -0
  6. package/dist/index.js +102 -0
  7. package/package.json +1 -1
  8. package/src/commands/version.ts +135 -0
  9. package/src/index.ts +11 -0
  10. package/src/types.ts +7 -0
  11. package/tests/commands/version.test.ts +297 -0
  12. package/.claude/agents/brainstormer.md +0 -96
  13. package/.claude/agents/code-reviewer.md +0 -141
  14. package/.claude/agents/copywriter.md +0 -108
  15. package/.claude/agents/database-admin.md +0 -86
  16. package/.claude/agents/debugger.md +0 -124
  17. package/.claude/agents/docs-manager.md +0 -115
  18. package/.claude/agents/git-manager.md +0 -60
  19. package/.claude/agents/journal-writer.md +0 -111
  20. package/.claude/agents/planner.md +0 -87
  21. package/.claude/agents/project-manager.md +0 -113
  22. package/.claude/agents/researcher.md +0 -173
  23. package/.claude/agents/scout.md +0 -123
  24. package/.claude/agents/tester.md +0 -95
  25. package/.claude/agents/ui-ux-designer.md +0 -206
  26. package/.claude/commands/bootstrap.md +0 -104
  27. package/.claude/commands/brainstorm.md +0 -67
  28. package/.claude/commands/content/enhance.md +0 -13
  29. package/.claude/commands/content/fast.md +0 -11
  30. package/.claude/commands/content/good.md +0 -13
  31. package/.claude/commands/cook.md +0 -19
  32. package/.claude/commands/debug.md +0 -10
  33. package/.claude/commands/design/3d.md +0 -65
  34. package/.claude/commands/design/describe.md +0 -13
  35. package/.claude/commands/design/fast.md +0 -19
  36. package/.claude/commands/design/good.md +0 -23
  37. package/.claude/commands/design/screenshot.md +0 -23
  38. package/.claude/commands/design/video.md +0 -23
  39. package/.claude/commands/docs/init.md +0 -13
  40. package/.claude/commands/docs/summarize.md +0 -10
  41. package/.claude/commands/docs/update.md +0 -21
  42. package/.claude/commands/fix/ci.md +0 -11
  43. package/.claude/commands/fix/fast.md +0 -12
  44. package/.claude/commands/fix/hard.md +0 -18
  45. package/.claude/commands/fix/logs.md +0 -16
  46. package/.claude/commands/fix/test.md +0 -18
  47. package/.claude/commands/fix/types.md +0 -10
  48. package/.claude/commands/git/cm.md +0 -5
  49. package/.claude/commands/git/cp.md +0 -4
  50. package/.claude/commands/integrate/polar.md +0 -42
  51. package/.claude/commands/plan/ci.md +0 -12
  52. package/.claude/commands/plan/two.md +0 -13
  53. package/.claude/commands/plan.md +0 -10
  54. package/.claude/commands/scout.md +0 -29
  55. package/.claude/commands/test.md +0 -7
  56. package/.claude/commands/watzup.md +0 -8
  57. package/.claude/hooks/telegram_notify.sh +0 -136
  58. package/.claude/send-discord.sh +0 -64
  59. package/.claude/settings.json +0 -7
  60. package/.claude/statusline.sh +0 -143
  61. package/.claude/workflows/development-rules.md +0 -80
  62. package/.claude/workflows/documentation-management.md +0 -28
  63. package/.claude/workflows/orchestration-protocol.md +0 -16
  64. package/.claude/workflows/primary-workflow.md +0 -41
  65. package/.opencode/agent/code-reviewer.md +0 -141
  66. package/.opencode/agent/debugger.md +0 -74
  67. package/.opencode/agent/docs-manager.md +0 -119
  68. package/.opencode/agent/git-manager.md +0 -60
  69. package/.opencode/agent/planner-researcher.md +0 -100
  70. package/.opencode/agent/planner.md +0 -87
  71. package/.opencode/agent/project-manager.md +0 -113
  72. package/.opencode/agent/researcher.md +0 -173
  73. package/.opencode/agent/solution-brainstormer.md +0 -89
  74. package/.opencode/agent/system-architecture.md +0 -192
  75. package/.opencode/agent/tester.md +0 -96
  76. package/.opencode/agent/ui-ux-designer.md +0 -203
  77. package/.opencode/agent/ui-ux-developer.md +0 -97
  78. package/.opencode/command/cook.md +0 -7
  79. package/.opencode/command/debug.md +0 -10
  80. package/.opencode/command/design/3d.md +0 -65
  81. package/.opencode/command/design/fast.md +0 -18
  82. package/.opencode/command/design/good.md +0 -21
  83. package/.opencode/command/design/screenshot.md +0 -22
  84. package/.opencode/command/design/video.md +0 -22
  85. package/.opencode/command/docs/init.md +0 -11
  86. package/.opencode/command/docs/summarize.md +0 -10
  87. package/.opencode/command/docs/update.md +0 -18
  88. package/.opencode/command/fix/ci.md +0 -8
  89. package/.opencode/command/fix/fast.md +0 -11
  90. package/.opencode/command/fix/hard.md +0 -15
  91. package/.opencode/command/fix/logs.md +0 -16
  92. package/.opencode/command/fix/test.md +0 -18
  93. package/.opencode/command/fix/types.md +0 -10
  94. package/.opencode/command/git/cm.md +0 -5
  95. package/.opencode/command/git/cp.md +0 -4
  96. package/.opencode/command/plan/ci.md +0 -12
  97. package/.opencode/command/plan/two.md +0 -13
  98. package/.opencode/command/plan.md +0 -10
  99. package/.opencode/command/test.md +0 -7
  100. package/.opencode/command/watzup.md +0 -8
  101. package/docs/code-standards.md +0 -1128
  102. package/docs/codebase-summary.md +0 -821
  103. package/docs/github-setup.md +0 -176
  104. package/docs/project-pdr.md +0 -739
  105. package/docs/system-architecture.md +0 -950
  106. package/docs/tech-stack.md +0 -290
  107. package/plans/251008-claudekit-cli-implementation-plan.md +0 -1469
  108. package/plans/reports/251008-from-code-reviewer-to-developer-review-report.md +0 -864
  109. package/plans/reports/251008-from-tester-to-developer-test-summary-report.md +0 -409
  110. package/plans/reports/251008-researcher-download-extraction-report.md +0 -1377
  111. package/plans/reports/251008-researcher-github-api-report.md +0 -1339
  112. package/plans/research/251008-cli-frameworks-bun-research.md +0 -1051
  113. package/plans/templates/bug-fix-template.md +0 -69
  114. package/plans/templates/feature-implementation-template.md +0 -84
  115. package/plans/templates/refactor-template.md +0 -82
  116. package/plans/templates/template-usage-guide.md +0 -58
@@ -1,1128 +0,0 @@
1
- # Code Standards and Conventions
2
- # ClaudeKit CLI
3
-
4
- **Version:** 1.0
5
- **Date:** 2025-10-08
6
- **Status:** Active
7
- **Applies to:** TypeScript, Bun runtime
8
-
9
- ---
10
-
11
- ## Table of Contents
12
-
13
- 1. [Core Principles](#core-principles)
14
- 2. [TypeScript Standards](#typescript-standards)
15
- 3. [File Organization](#file-organization)
16
- 4. [Naming Conventions](#naming-conventions)
17
- 5. [Error Handling](#error-handling)
18
- 6. [Security Standards](#security-standards)
19
- 7. [Testing Standards](#testing-standards)
20
- 8. [Documentation Standards](#documentation-standards)
21
- 9. [Git Workflow](#git-workflow)
22
- 10. [Code Review Checklist](#code-review-checklist)
23
-
24
- ---
25
-
26
- ## Core Principles
27
-
28
- ### YAGNI (You Aren't Gonna Need It)
29
-
30
- **Principle:** Only implement features when they are actually needed, not when you anticipate they might be needed.
31
-
32
- **Examples:**
33
-
34
- **❌ Bad - Over-engineering:**
35
- ```typescript
36
- // Unnecessary abstraction for simple config
37
- class ConfigStrategy {
38
- abstract load(): Promise<Config>;
39
- }
40
-
41
- class JsonConfigStrategy extends ConfigStrategy { ... }
42
- class YamlConfigStrategy extends ConfigStrategy { ... }
43
- class TomlConfigStrategy extends ConfigStrategy { ... }
44
- ```
45
-
46
- **✅ Good - Simple and direct:**
47
- ```typescript
48
- // Simple, focused implementation
49
- class ConfigManager {
50
- static async load(): Promise<Config> {
51
- const data = await Bun.file(CONFIG_PATH).json();
52
- return ConfigSchema.parse(data);
53
- }
54
- }
55
- ```
56
-
57
- ---
58
-
59
- ### KISS (Keep It Simple, Stupid)
60
-
61
- **Principle:** Favor simple, straightforward solutions over complex ones.
62
-
63
- **Examples:**
64
-
65
- **❌ Bad - Overly complex:**
66
- ```typescript
67
- const processFiles = pipe(
68
- filter((f: string) => !ig.ignores(f)),
69
- map((f: string) => path.resolve(f)),
70
- tap((f: string) => logger.debug(f)),
71
- toArray()
72
- );
73
- ```
74
-
75
- **✅ Good - Clear and simple:**
76
- ```typescript
77
- const processFiles = (files: string[]) => {
78
- return files
79
- .filter(f => !ig.ignores(f))
80
- .map(f => path.resolve(f));
81
- };
82
- ```
83
-
84
- ---
85
-
86
- ### DRY (Don't Repeat Yourself)
87
-
88
- **Principle:** Avoid duplicating logic; extract common patterns into reusable functions.
89
-
90
- **Examples:**
91
-
92
- **❌ Bad - Repeated logic:**
93
- ```typescript
94
- // In new.ts
95
- logger.info(pc.cyan('Downloading release...'));
96
- const response = await fetch(url);
97
- // handle response...
98
-
99
- // In update.ts
100
- logger.info(pc.cyan('Downloading release...'));
101
- const response = await fetch(url);
102
- // handle response...
103
- ```
104
-
105
- **✅ Good - Extracted to reusable class:**
106
- ```typescript
107
- // In lib/download.ts
108
- class DownloadManager {
109
- async downloadAsset(asset: GitHubReleaseAsset): Promise<string> {
110
- logger.info(pc.cyan('Downloading release...'));
111
- const response = await fetch(asset.browser_download_url);
112
- // centralized download logic
113
- }
114
- }
115
- ```
116
-
117
- ---
118
-
119
- ## TypeScript Standards
120
-
121
- ### Strict Mode Configuration
122
-
123
- **Required `tsconfig.json` settings:**
124
-
125
- ```json
126
- {
127
- "compilerOptions": {
128
- "strict": true,
129
- "noImplicitAny": true,
130
- "strictNullChecks": true,
131
- "strictFunctionTypes": true,
132
- "strictBindCallApply": true,
133
- "strictPropertyInitialization": true,
134
- "noImplicitThis": true,
135
- "alwaysStrict": true,
136
- "noUnusedLocals": true,
137
- "noUnusedParameters": true,
138
- "noImplicitReturns": true,
139
- "noFallthroughCasesInSwitch": true
140
- }
141
- }
142
- ```
143
-
144
- ---
145
-
146
- ### Type Safety
147
-
148
- **1. Use Zod for Runtime Validation:**
149
-
150
- ```typescript
151
- import { z } from 'zod';
152
-
153
- // Define schema
154
- export const NewCommandOptionsSchema = z.object({
155
- dir: z.string().default('.'),
156
- kit: KitType.optional(),
157
- version: z.string().optional(),
158
- });
159
-
160
- // Infer TypeScript type from schema
161
- export type NewCommandOptions = z.infer<typeof NewCommandOptionsSchema>;
162
-
163
- // Validate at runtime
164
- const options = NewCommandOptionsSchema.parse(rawInput);
165
- ```
166
-
167
- **Benefits:**
168
- - Compile-time type checking
169
- - Runtime validation
170
- - Automatic type inference
171
- - Clear error messages
172
-
173
- ---
174
-
175
- **2. Avoid `any` Type:**
176
-
177
- **❌ Bad:**
178
- ```typescript
179
- function processData(data: any) {
180
- return data.map((item: any) => item.value);
181
- }
182
- ```
183
-
184
- **✅ Good:**
185
- ```typescript
186
- interface DataItem {
187
- value: string;
188
- }
189
-
190
- function processData(data: DataItem[]): string[] {
191
- return data.map(item => item.value);
192
- }
193
- ```
194
-
195
- **Exceptions:** Only use `any` when:
196
- - Wrapping external untyped libraries
197
- - Type is truly unknown and needs runtime checking
198
- - Always document why `any` is necessary
199
-
200
- ---
201
-
202
- **3. Use Type Guards:**
203
-
204
- ```typescript
205
- function isGitHubError(error: unknown): error is GitHubError {
206
- return error instanceof GitHubError;
207
- }
208
-
209
- try {
210
- await client.getRelease();
211
- } catch (error) {
212
- if (isGitHubError(error)) {
213
- // TypeScript knows error is GitHubError here
214
- logger.error(`GitHub API error: ${error.statusCode}`);
215
- }
216
- }
217
- ```
218
-
219
- ---
220
-
221
- ### Interface vs Type
222
-
223
- **Use `interface` for:**
224
- - Object shapes that might be extended
225
- - Public APIs
226
- - Class contracts
227
-
228
- ```typescript
229
- interface ConfigManager {
230
- load(): Promise<Config>;
231
- save(config: Config): Promise<void>;
232
- }
233
- ```
234
-
235
- **Use `type` for:**
236
- - Union types
237
- - Intersection types
238
- - Mapped types
239
- - Type inference from Zod
240
-
241
- ```typescript
242
- type KitType = 'engineer' | 'marketing';
243
- type AuthMethod = 'gh-cli' | 'env-var' | 'keychain' | 'prompt';
244
- type NewCommandOptions = z.infer<typeof NewCommandOptionsSchema>;
245
- ```
246
-
247
- ---
248
-
249
- ## File Organization
250
-
251
- ### Directory Structure
252
-
253
- ```
254
- src/
255
- ├── index.ts # CLI entry point
256
- ├── types.ts # Type definitions and schemas
257
- ├── commands/ # Command implementations
258
- │ ├── new.ts
259
- │ └── update.ts
260
- ├── lib/ # Core libraries
261
- │ ├── auth.ts
262
- │ ├── github.ts
263
- │ ├── download.ts
264
- │ ├── merge.ts
265
- │ └── prompts.ts
266
- └── utils/ # Utility functions
267
- ├── config.ts
268
- └── logger.ts
269
-
270
- tests/ # Mirror src structure
271
- ├── types.test.ts
272
- ├── lib/
273
- │ ├── auth.test.ts
274
- │ └── ...
275
- └── utils/
276
- ├── config.test.ts
277
- └── logger.test.ts
278
- ```
279
-
280
- ---
281
-
282
- ### File Size Limits
283
-
284
- **Hard Limit:** 500 lines per file
285
- **Recommended:** < 200 lines per file
286
-
287
- **Why:** Smaller files are:
288
- - Easier to understand
289
- - Easier to test
290
- - Easier to maintain
291
- - Better for code review
292
-
293
- **When to split:**
294
- ```typescript
295
- // If auth.ts gets > 200 lines, split into:
296
- auth/
297
- ├── index.ts // Public API
298
- ├── manager.ts // AuthManager class
299
- ├── providers/
300
- │ ├── gh-cli.ts // GitHub CLI provider
301
- │ ├── env.ts // Environment variable provider
302
- │ └── keychain.ts // Keychain provider
303
- └── types.ts // Auth-specific types
304
- ```
305
-
306
- ---
307
-
308
- ### Import Organization
309
-
310
- **Order:**
311
- 1. External dependencies
312
- 2. Internal absolute imports
313
- 3. Internal relative imports
314
- 4. Type-only imports
315
-
316
- ```typescript
317
- // 1. External dependencies
318
- import { z } from 'zod';
319
- import { Octokit } from '@octokit/rest';
320
-
321
- // 2. Internal absolute imports
322
- import { logger } from '@/utils/logger';
323
- import { ConfigManager } from '@/utils/config';
324
-
325
- // 3. Internal relative imports
326
- import { AuthManager } from './auth';
327
- import { DownloadManager } from './download';
328
-
329
- // 4. Type-only imports
330
- import type { GitHubRelease, KitConfig } from '@/types';
331
- ```
332
-
333
- ---
334
-
335
- ## Naming Conventions
336
-
337
- ### Variables and Functions
338
-
339
- **camelCase for variables and functions:**
340
-
341
- ```typescript
342
- const targetDirectory = './my-app';
343
- const isValid = true;
344
-
345
- function validateToken(token: string): boolean { ... }
346
- async function downloadRelease(url: string): Promise<void> { ... }
347
- ```
348
-
349
- **Descriptive names over short names:**
350
-
351
- **❌ Bad:**
352
- ```typescript
353
- const t = 'ghp_token123';
354
- const d = './dir';
355
- const fn = async (x) => { ... };
356
- ```
357
-
358
- **✅ Good:**
359
- ```typescript
360
- const githubToken = 'ghp_token123';
361
- const targetDirectory = './dir';
362
- const downloadAsset = async (asset: GitHubReleaseAsset) => { ... };
363
- ```
364
-
365
- ---
366
-
367
- ### Classes and Types
368
-
369
- **PascalCase for classes, interfaces, types, and enums:**
370
-
371
- ```typescript
372
- class AuthManager { ... }
373
- class DownloadManager { ... }
374
-
375
- interface GitHubClient { ... }
376
- type KitType = 'engineer' | 'marketing';
377
-
378
- enum LogLevel {
379
- Debug,
380
- Info,
381
- Warning,
382
- Error
383
- }
384
- ```
385
-
386
- ---
387
-
388
- ### Constants
389
-
390
- **UPPER_SNAKE_CASE for constants:**
391
-
392
- ```typescript
393
- const CONFIG_PATH = join(homedir(), '.claudekit', 'config.json');
394
- const GITHUB_API_TIMEOUT = 30_000;
395
- const MAX_RETRY_ATTEMPTS = 3;
396
-
397
- // Exception: Zod schemas use PascalCase
398
- const NewCommandOptionsSchema = z.object({ ... });
399
- ```
400
-
401
- ---
402
-
403
- ### Files and Directories
404
-
405
- **kebab-case for files and directories:**
406
-
407
- ```typescript
408
- // Files
409
- auth-manager.ts
410
- download-manager.ts
411
- file-merger.ts
412
-
413
- // Directories
414
- user-commands/
415
- github-client/
416
- ```
417
-
418
- **Exception:** Test files mirror source file names:
419
- ```typescript
420
- src/lib/auth.ts → tests/lib/auth.test.ts
421
- ```
422
-
423
- ---
424
-
425
- ## Error Handling
426
-
427
- ### Custom Error Classes
428
-
429
- **Define specific error types:**
430
-
431
- ```typescript
432
- export class ClaudeKitError extends Error {
433
- constructor(
434
- message: string,
435
- public code?: string,
436
- public statusCode?: number
437
- ) {
438
- super(message);
439
- this.name = 'ClaudeKitError';
440
- }
441
- }
442
-
443
- export class AuthenticationError extends ClaudeKitError {
444
- constructor(message: string) {
445
- super(message, 'AUTH_ERROR', 401);
446
- this.name = 'AuthenticationError';
447
- }
448
- }
449
- ```
450
-
451
- **Benefits:**
452
- - Type-safe error handling
453
- - Consistent error structure
454
- - Easy to filter and handle specific errors
455
-
456
- ---
457
-
458
- ### Error Handling Patterns
459
-
460
- **1. Try-Catch with Cleanup:**
461
-
462
- ```typescript
463
- async function downloadAndExtract(url: string): Promise<void> {
464
- const tempDir = await createTempDir();
465
-
466
- try {
467
- const archivePath = await downloadFile(url, tempDir);
468
- await extractArchive(archivePath, tempDir);
469
- } catch (error) {
470
- logger.error('Download failed', error);
471
- throw new DownloadError('Failed to download release', error);
472
- } finally {
473
- // Always clean up
474
- await rm(tempDir, { recursive: true, force: true }).catch(() => {});
475
- }
476
- }
477
- ```
478
-
479
- ---
480
-
481
- **2. Type Guards for Error Handling:**
482
-
483
- ```typescript
484
- try {
485
- await githubClient.getRelease(kit);
486
- } catch (error) {
487
- if (error instanceof GitHubError && error.statusCode === 404) {
488
- logger.error('Release not found. Check kit name and version.');
489
- } else if (error instanceof GitHubError && error.statusCode === 401) {
490
- logger.error('Authentication failed. Check your GitHub token.');
491
- } else {
492
- logger.error('Unexpected error', error);
493
- }
494
- throw error;
495
- }
496
- ```
497
-
498
- ---
499
-
500
- **3. Result Type Pattern (Future Enhancement):**
501
-
502
- ```typescript
503
- // Optional: Use for operations that may fail
504
- type Result<T, E = Error> =
505
- | { ok: true; value: T }
506
- | { ok: false; error: E };
507
-
508
- async function tryDownload(url: string): Promise<Result<string>> {
509
- try {
510
- const path = await download(url);
511
- return { ok: true, value: path };
512
- } catch (error) {
513
- return { ok: false, error: error as Error };
514
- }
515
- }
516
- ```
517
-
518
- ---
519
-
520
- ### User-Friendly Error Messages
521
-
522
- **Structure:**
523
- 1. What went wrong
524
- 2. Why it happened (if known)
525
- 3. How to fix it
526
-
527
- **Examples:**
528
-
529
- **❌ Bad:**
530
- ```typescript
531
- throw new Error('Token invalid');
532
- ```
533
-
534
- **✅ Good:**
535
- ```typescript
536
- throw new AuthenticationError(
537
- 'GitHub token is invalid or expired.\n' +
538
- 'Please check your token and try again.\n' +
539
- 'Create a new token at: https://github.com/settings/tokens'
540
- );
541
- ```
542
-
543
- ---
544
-
545
- ## Security Standards
546
-
547
- ### Token Security
548
-
549
- **1. Never Log Tokens:**
550
-
551
- ```typescript
552
- // ❌ NEVER do this
553
- logger.debug(`Using token: ${token}`);
554
- logger.error(`Auth failed with token ${token}`);
555
-
556
- // ✅ Always sanitize
557
- logger.debug('Using token: ***');
558
- logger.error('Authentication failed. Please check your token.');
559
- ```
560
-
561
- ---
562
-
563
- **2. Token Sanitization:**
564
-
565
- ```typescript
566
- const sanitize = (text: string): string => {
567
- return text
568
- .replace(/ghp_[a-zA-Z0-9]{36}/g, 'ghp_***')
569
- .replace(/github_pat_[a-zA-Z0-9_]{82}/g, 'github_pat_***')
570
- .replace(/gho_[a-zA-Z0-9]{36}/g, 'gho_***')
571
- .replace(/ghu_[a-zA-Z0-9]{36}/g, 'ghu_***')
572
- .replace(/ghs_[a-zA-Z0-9]{36}/g, 'ghs_***')
573
- .replace(/ghr_[a-zA-Z0-9]{36}/g, 'ghr_***');
574
- };
575
-
576
- // Use in all logging
577
- logger.error(sanitize(errorMessage));
578
- ```
579
-
580
- ---
581
-
582
- **3. Secure Storage:**
583
-
584
- ```typescript
585
- import keytar from 'keytar';
586
-
587
- const SERVICE_NAME = 'claudekit-cli';
588
- const ACCOUNT_NAME = 'github-token';
589
-
590
- // Store token
591
- await keytar.setPassword(SERVICE_NAME, ACCOUNT_NAME, token);
592
-
593
- // Retrieve token
594
- const token = await keytar.getPassword(SERVICE_NAME, ACCOUNT_NAME);
595
-
596
- // Delete token
597
- await keytar.deletePassword(SERVICE_NAME, ACCOUNT_NAME);
598
- ```
599
-
600
- ---
601
-
602
- ### Input Validation
603
-
604
- **Always validate external input with Zod:**
605
-
606
- ```typescript
607
- // Command line arguments
608
- const options = NewCommandOptionsSchema.parse(rawOptions);
609
-
610
- // API responses
611
- const release = GitHubReleaseSchema.parse(apiResponse);
612
-
613
- // User input
614
- const directory = z.string().min(1).parse(userInput);
615
-
616
- // Environment variables
617
- const token = GitHubTokenSchema.parse(process.env.GITHUB_TOKEN);
618
- ```
619
-
620
- ---
621
-
622
- ### Path Security
623
-
624
- **Prevent path traversal:**
625
-
626
- ```typescript
627
- function isSafePath(basePath: string, targetPath: string): boolean {
628
- const resolvedBase = path.resolve(basePath);
629
- const resolvedTarget = path.resolve(targetPath);
630
-
631
- // Ensure target is within base
632
- return resolvedTarget.startsWith(resolvedBase);
633
- }
634
-
635
- // Use in file operations
636
- if (!isSafePath(outputDir, filePath)) {
637
- throw new Error('Path traversal detected');
638
- }
639
- ```
640
-
641
- ---
642
-
643
- ## Testing Standards
644
-
645
- ### Test Structure
646
-
647
- **Use Bun Test with clear descriptions:**
648
-
649
- ```typescript
650
- import { describe, test, expect, beforeEach, afterEach } from 'bun:test';
651
-
652
- describe('AuthManager', () => {
653
- beforeEach(async () => {
654
- // Setup
655
- });
656
-
657
- afterEach(async () => {
658
- // Cleanup
659
- });
660
-
661
- test('should detect GitHub CLI token', async () => {
662
- // Arrange
663
- const authManager = new AuthManager();
664
-
665
- // Act
666
- const { method, token } = await authManager.getToken();
667
-
668
- // Assert
669
- expect(method).toBe('gh-cli');
670
- expect(token).toMatch(/^ghp_/);
671
- });
672
-
673
- test('should fall back to environment variable', async () => {
674
- // Test implementation
675
- });
676
- });
677
- ```
678
-
679
- ---
680
-
681
- ### Test Coverage Requirements
682
-
683
- **Minimum Coverage:** 80%
684
- **Target Coverage:** 90%+
685
-
686
- **What to test:**
687
- - ✅ All public methods
688
- - ✅ Error scenarios
689
- - ✅ Edge cases
690
- - ✅ Type validation
691
- - ✅ Security features
692
-
693
- **What NOT to test:**
694
- - ❌ External libraries (Octokit, etc.)
695
- - ❌ Trivial getters/setters
696
- - ❌ Type definitions only
697
-
698
- ---
699
-
700
- ### Mocking Best Practices
701
-
702
- ```typescript
703
- import { mock } from 'bun:test';
704
-
705
- test('should handle network errors', async () => {
706
- // Mock fetch to simulate network error
707
- const mockFetch = mock(() => {
708
- throw new Error('Network error');
709
- });
710
-
711
- globalThis.fetch = mockFetch;
712
-
713
- await expect(downloadFile(url)).rejects.toThrow('Network error');
714
-
715
- // Restore original fetch
716
- mockFetch.mockRestore();
717
- });
718
- ```
719
-
720
- ---
721
-
722
- ## Documentation Standards
723
-
724
- ### JSDoc Comments
725
-
726
- **Required for all public APIs:**
727
-
728
- ```typescript
729
- /**
730
- * Downloads a GitHub release asset to the specified directory
731
- *
732
- * @param asset - The GitHub release asset to download
733
- * @param destDir - Destination directory for the downloaded file
734
- * @returns Path to the downloaded file
735
- * @throws {DownloadError} If download fails or is interrupted
736
- *
737
- * @example
738
- * ```typescript
739
- * const path = await downloadManager.downloadAsset(asset, './temp');
740
- * console.log(`Downloaded to: ${path}`);
741
- * ```
742
- */
743
- async downloadAsset(
744
- asset: GitHubReleaseAsset,
745
- destDir: string
746
- ): Promise<string> {
747
- // Implementation
748
- }
749
- ```
750
-
751
- ---
752
-
753
- ### Inline Comments
754
-
755
- **When to comment:**
756
- - Complex algorithms
757
- - Non-obvious business logic
758
- - Security considerations
759
- - Performance optimizations
760
- - Workarounds
761
-
762
- **When NOT to comment:**
763
- - Self-explanatory code
764
- - Trivial operations
765
- - Repeating what code says
766
-
767
- **❌ Bad:**
768
- ```typescript
769
- // Increment counter
770
- counter++;
771
-
772
- // Loop through files
773
- for (const file of files) { ... }
774
- ```
775
-
776
- **✅ Good:**
777
- ```typescript
778
- // Strip top-level directory from archive to avoid nested structure
779
- // GitHub releases include repo name as root dir
780
- const strippedPath = relativePath.split('/').slice(1).join('/');
781
-
782
- // Use exponential backoff to avoid rate limiting
783
- await sleep(Math.pow(2, retryCount) * 1000);
784
- ```
785
-
786
- ---
787
-
788
- ## Git Workflow
789
-
790
- ### Commit Messages
791
-
792
- **Format:** Conventional Commits
793
-
794
- ```
795
- <type>(<scope>): <subject>
796
-
797
- <body>
798
-
799
- <footer>
800
- ```
801
-
802
- **Types:**
803
- - `feat`: New feature
804
- - `fix`: Bug fix
805
- - `docs`: Documentation only
806
- - `style`: Code style (formatting, etc.)
807
- - `refactor`: Code refactoring
808
- - `test`: Adding or updating tests
809
- - `chore`: Maintenance tasks
810
-
811
- **Examples:**
812
-
813
- ```
814
- feat(auth): add GitHub CLI token detection
815
-
816
- Implement automatic token detection from gh CLI when available.
817
- Falls back to environment variables if gh CLI is not found.
818
-
819
- Closes #123
820
- ```
821
-
822
- ```
823
- fix(download): handle network timeouts gracefully
824
-
825
- Add AbortSignal timeout to prevent hanging on slow connections.
826
- Show clear error message when timeout occurs.
827
- ```
828
-
829
- ```
830
- docs(readme): update authentication setup guide
831
-
832
- Add instructions for fine-grained PAT creation.
833
- Include minimum required permissions.
834
- ```
835
-
836
- ---
837
-
838
- ### Branch Naming
839
-
840
- **Format:** `<type>/<short-description>`
841
-
842
- **Examples:**
843
- - `feat/github-cli-auth`
844
- - `fix/download-timeout`
845
- - `docs/update-readme`
846
- - `refactor/split-auth-providers`
847
-
848
- ---
849
-
850
- ### Pull Request Guidelines
851
-
852
- **PR Title:** Same as commit message format
853
-
854
- **PR Description:**
855
- ```markdown
856
- ## Summary
857
- Brief description of changes
858
-
859
- ## Changes
860
- - Added GitHub CLI token detection
861
- - Updated authentication fallback chain
862
- - Added tests for new auth method
863
-
864
- ## Testing
865
- - ✅ All tests passing
866
- - ✅ Manual testing with gh CLI
867
- - ✅ Manual testing without gh CLI
868
-
869
- ## Checklist
870
- - [x] Tests added/updated
871
- - [x] Documentation updated
872
- - [x] Type checking passes
873
- - [x] Linting passes
874
- ```
875
-
876
- ---
877
-
878
- ## Code Review Checklist
879
-
880
- ### Functionality
881
- - [ ] Code implements requirements correctly
882
- - [ ] Edge cases handled
883
- - [ ] Error scenarios covered
884
- - [ ] No regressions introduced
885
-
886
- ### Code Quality
887
- - [ ] Follows YAGNI, KISS, DRY principles
888
- - [ ] Clean, readable code
889
- - [ ] No code duplication
890
- - [ ] Consistent naming conventions
891
- - [ ] Files under 500 lines
892
-
893
- ### Security
894
- - [ ] No token exposure
895
- - [ ] Input validation present
896
- - [ ] Path validation for file operations
897
- - [ ] No hardcoded secrets
898
-
899
- ### Performance
900
- - [ ] Efficient algorithms used
901
- - [ ] Streaming for large files
902
- - [ ] No memory leaks
903
- - [ ] Proper async/await usage
904
-
905
- ### Testing
906
- - [ ] Unit tests added/updated
907
- - [ ] All tests passing
908
- - [ ] Coverage meets requirements
909
- - [ ] Edge cases tested
910
-
911
- ### Documentation
912
- - [ ] JSDoc for public APIs
913
- - [ ] Inline comments for complex logic
914
- - [ ] README updated if needed
915
- - [ ] CHANGELOG updated
916
-
917
- ### TypeScript
918
- - [ ] No type errors
919
- - [ ] Strict mode compliant
920
- - [ ] No `any` without justification
921
- - [ ] Zod schemas for validation
922
-
923
- ---
924
-
925
- ## Code Quality Tools
926
-
927
- ### Linting: Biome
928
-
929
- **Configuration** (`.biome.json`):
930
- ```json
931
- {
932
- "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
933
- "organizeImports": {
934
- "enabled": true
935
- },
936
- "linter": {
937
- "enabled": true,
938
- "rules": {
939
- "recommended": true,
940
- "complexity": {
941
- "noExtraBooleanCast": "error",
942
- "noMultipleSpacesInRegularExpressionLiterals": "error",
943
- "noUselessConstructor": "error",
944
- "noWith": "error"
945
- },
946
- "style": {
947
- "noParameterAssign": "error",
948
- "useConst": "error",
949
- "useTemplate": "error"
950
- },
951
- "suspicious": {
952
- "noExplicitAny": "warn",
953
- "noDebugger": "error",
954
- "noConsoleLog": "warn"
955
- }
956
- }
957
- },
958
- "formatter": {
959
- "enabled": true,
960
- "indentStyle": "space",
961
- "indentWidth": 2,
962
- "lineWidth": 100
963
- }
964
- }
965
- ```
966
-
967
- ---
968
-
969
- ### Type Checking
970
-
971
- **Run before commit:**
972
- ```bash
973
- bun run typecheck
974
- ```
975
-
976
- **Zero tolerance:** No type errors allowed in production code.
977
-
978
- ---
979
-
980
- ### Testing
981
-
982
- **Run before commit:**
983
- ```bash
984
- bun test
985
- ```
986
-
987
- **Requirements:**
988
- - All tests must pass
989
- - Coverage ≥ 80%
990
- - No skipped tests without reason
991
-
992
- ---
993
-
994
- ## Best Practices Summary
995
-
996
- ### DO ✅
997
-
998
- - Use TypeScript strict mode
999
- - Validate all external input with Zod
1000
- - Write comprehensive tests
1001
- - Handle errors gracefully
1002
- - Use descriptive variable names
1003
- - Keep files small (< 500 lines)
1004
- - Document public APIs with JSDoc
1005
- - Sanitize sensitive data in logs
1006
- - Use streaming for large files
1007
- - Follow conventional commits
1008
-
1009
- ### DON'T ❌
1010
-
1011
- - Use `any` type without justification
1012
- - Log sensitive data (tokens, etc.)
1013
- - Ignore error scenarios
1014
- - Write overly complex code
1015
- - Duplicate logic across files
1016
- - Hardcode configuration values
1017
- - Skip input validation
1018
- - Leave TODO comments in production
1019
- - Commit broken tests
1020
- - Push without running tests
1021
-
1022
- ---
1023
-
1024
- ## Performance Guidelines
1025
-
1026
- ### Memory Efficiency
1027
-
1028
- **Use streaming for large operations:**
1029
-
1030
- ```typescript
1031
- // ✅ Good - Streaming
1032
- const stream = createWriteStream(outputPath);
1033
- for await (const chunk of downloadStream) {
1034
- stream.write(chunk);
1035
- }
1036
-
1037
- // ❌ Bad - Loading into memory
1038
- const data = await fetch(url).then(r => r.arrayBuffer());
1039
- await writeFile(outputPath, Buffer.from(data));
1040
- ```
1041
-
1042
- ---
1043
-
1044
- ### Async Best Practices
1045
-
1046
- **Use Promise.all for parallel operations:**
1047
-
1048
- ```typescript
1049
- // ✅ Good - Parallel
1050
- const [user, repos, stars] = await Promise.all([
1051
- client.getUser(),
1052
- client.getRepos(),
1053
- client.getStars(),
1054
- ]);
1055
-
1056
- // ❌ Bad - Sequential
1057
- const user = await client.getUser();
1058
- const repos = await client.getRepos();
1059
- const stars = await client.getStars();
1060
- ```
1061
-
1062
- ---
1063
-
1064
- **Proper error handling in async:**
1065
-
1066
- ```typescript
1067
- async function processFiles(files: string[]): Promise<void> {
1068
- try {
1069
- await Promise.all(files.map(f => processFile(f)));
1070
- } catch (error) {
1071
- logger.error('Failed to process files', error);
1072
- throw new ProcessingError('File processing failed', error);
1073
- }
1074
- }
1075
- ```
1076
-
1077
- ---
1078
-
1079
- ## Maintenance Guidelines
1080
-
1081
- ### Regular Tasks
1082
-
1083
- **Weekly:**
1084
- - Review and update dependencies
1085
- - Run security audit (`bun audit`)
1086
- - Check for deprecated APIs
1087
- - Review and close stale issues
1088
-
1089
- **Monthly:**
1090
- - Review test coverage
1091
- - Update documentation
1092
- - Refactor complex code
1093
- - Performance profiling
1094
-
1095
- **Quarterly:**
1096
- - Major dependency updates
1097
- - Architecture review
1098
- - Security audit
1099
- - Performance benchmarking
1100
-
1101
- ---
1102
-
1103
- ### Deprecation Process
1104
-
1105
- 1. Mark as deprecated with JSDoc
1106
- 2. Provide migration path
1107
- 3. Add console warning
1108
- 4. Update documentation
1109
- 5. Remove after 2 versions
1110
-
1111
- **Example:**
1112
-
1113
- ```typescript
1114
- /**
1115
- * @deprecated Use getToken() instead. Will be removed in v2.0.0
1116
- */
1117
- async function fetchToken(): Promise<string> {
1118
- logger.warning('fetchToken() is deprecated. Use getToken() instead.');
1119
- return this.getToken();
1120
- }
1121
- ```
1122
-
1123
- ---
1124
-
1125
- **Document Version:** 1.0
1126
- **Last Updated:** 2025-10-08
1127
- **Status:** Active
1128
- **Next Review:** 2025-11-08