@aicgen/aicgen 1.0.0-beta.1 → 1.0.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 (160) hide show
  1. package/{.claude/guidelines → .agent/rules}/api-design.md +5 -1
  2. package/{.claude/guidelines → .agent/rules}/architecture.md +5 -1
  3. package/{.claude/guidelines → .agent/rules}/best-practices.md +5 -1
  4. package/{.claude/guidelines → .agent/rules}/code-style.md +5 -1
  5. package/{.claude/guidelines → .agent/rules}/design-patterns.md +5 -1
  6. package/{.claude/guidelines → .agent/rules}/devops.md +5 -1
  7. package/{.claude/guidelines → .agent/rules}/error-handling.md +5 -1
  8. package/.agent/rules/instructions.md +28 -0
  9. package/{.claude/guidelines → .agent/rules}/language.md +5 -1
  10. package/{.claude/guidelines → .agent/rules}/performance.md +5 -1
  11. package/{.claude/guidelines → .agent/rules}/security.md +5 -1
  12. package/{.claude/guidelines → .agent/rules}/testing.md +5 -1
  13. package/.agent/workflows/add-documentation.md +10 -0
  14. package/.agent/workflows/generate-integration-tests.md +10 -0
  15. package/.agent/workflows/generate-unit-tests.md +11 -0
  16. package/.agent/workflows/performance-audit.md +11 -0
  17. package/.agent/workflows/refactor-extract-module.md +12 -0
  18. package/.agent/workflows/security-audit.md +12 -0
  19. package/.gemini/instructions.md +4843 -0
  20. package/.vs/ProjectSettings.json +2 -2
  21. package/.vs/VSWorkspaceState.json +15 -15
  22. package/.vs/aicgen.slnx/v18/DocumentLayout.json +53 -53
  23. package/AGENTS.md +9 -11
  24. package/assets/icon.svg +33 -33
  25. package/bun.lock +734 -26
  26. package/{CLAUDE.md → claude.md} +2 -2
  27. package/config.example.yml +129 -0
  28. package/config.yml +38 -0
  29. package/data/architecture/microservices/api-gateway.md +56 -56
  30. package/data/devops/observability.md +73 -73
  31. package/data/guideline-mappings.yml +128 -0
  32. package/data/language/dart/async.md +289 -0
  33. package/data/language/dart/basics.md +280 -0
  34. package/data/language/dart/error-handling.md +355 -0
  35. package/data/language/dart/index.md +10 -0
  36. package/data/language/dart/testing.md +352 -0
  37. package/data/language/swift/basics.md +477 -0
  38. package/data/language/swift/concurrency.md +654 -0
  39. package/data/language/swift/error-handling.md +679 -0
  40. package/data/language/swift/swiftui-mvvm.md +795 -0
  41. package/data/language/swift/testing.md +708 -0
  42. package/data/version.json +10 -8
  43. package/dist/index.js +50153 -28959
  44. package/jest.config.js +46 -0
  45. package/package.json +14 -3
  46. package/.claude/agents/architecture-reviewer.md +0 -88
  47. package/.claude/agents/guideline-checker.md +0 -73
  48. package/.claude/agents/security-auditor.md +0 -108
  49. package/.claude/settings.json +0 -98
  50. package/.claude/settings.local.json +0 -8
  51. package/.eslintrc.json +0 -28
  52. package/.github/workflows/release.yml +0 -180
  53. package/.github/workflows/test.yml +0 -81
  54. package/CONTRIBUTING.md +0 -821
  55. package/dist/commands/init.d.ts +0 -8
  56. package/dist/commands/init.d.ts.map +0 -1
  57. package/dist/commands/init.js +0 -46
  58. package/dist/commands/init.js.map +0 -1
  59. package/dist/config/profiles.d.ts +0 -4
  60. package/dist/config/profiles.d.ts.map +0 -1
  61. package/dist/config/profiles.js +0 -30
  62. package/dist/config/profiles.js.map +0 -1
  63. package/dist/config/settings.d.ts +0 -7
  64. package/dist/config/settings.d.ts.map +0 -1
  65. package/dist/config/settings.js +0 -7
  66. package/dist/config/settings.js.map +0 -1
  67. package/dist/index.d.ts +0 -3
  68. package/dist/index.d.ts.map +0 -1
  69. package/dist/index.js.map +0 -1
  70. package/dist/models/guideline.d.ts +0 -15
  71. package/dist/models/guideline.d.ts.map +0 -1
  72. package/dist/models/guideline.js +0 -2
  73. package/dist/models/guideline.js.map +0 -1
  74. package/dist/models/preference.d.ts +0 -9
  75. package/dist/models/preference.d.ts.map +0 -1
  76. package/dist/models/preference.js +0 -2
  77. package/dist/models/preference.js.map +0 -1
  78. package/dist/models/profile.d.ts +0 -9
  79. package/dist/models/profile.d.ts.map +0 -1
  80. package/dist/models/profile.js +0 -2
  81. package/dist/models/profile.js.map +0 -1
  82. package/dist/models/project.d.ts +0 -13
  83. package/dist/models/project.d.ts.map +0 -1
  84. package/dist/models/project.js +0 -2
  85. package/dist/models/project.js.map +0 -1
  86. package/dist/services/ai/anthropic.d.ts +0 -7
  87. package/dist/services/ai/anthropic.d.ts.map +0 -1
  88. package/dist/services/ai/anthropic.js +0 -39
  89. package/dist/services/ai/anthropic.js.map +0 -1
  90. package/dist/services/generator.d.ts +0 -2
  91. package/dist/services/generator.d.ts.map +0 -1
  92. package/dist/services/generator.js +0 -4
  93. package/dist/services/generator.js.map +0 -1
  94. package/dist/services/learner.d.ts +0 -2
  95. package/dist/services/learner.d.ts.map +0 -1
  96. package/dist/services/learner.js +0 -4
  97. package/dist/services/learner.js.map +0 -1
  98. package/dist/services/scanner.d.ts +0 -3
  99. package/dist/services/scanner.d.ts.map +0 -1
  100. package/dist/services/scanner.js +0 -54
  101. package/dist/services/scanner.js.map +0 -1
  102. package/dist/utils/errors.d.ts +0 -15
  103. package/dist/utils/errors.d.ts.map +0 -1
  104. package/dist/utils/errors.js +0 -27
  105. package/dist/utils/errors.js.map +0 -1
  106. package/dist/utils/file.d.ts +0 -7
  107. package/dist/utils/file.d.ts.map +0 -1
  108. package/dist/utils/file.js +0 -32
  109. package/dist/utils/file.js.map +0 -1
  110. package/dist/utils/logger.d.ts +0 -6
  111. package/dist/utils/logger.d.ts.map +0 -1
  112. package/dist/utils/logger.js +0 -17
  113. package/dist/utils/logger.js.map +0 -1
  114. package/dist/utils/path.d.ts +0 -6
  115. package/dist/utils/path.d.ts.map +0 -1
  116. package/dist/utils/path.js +0 -14
  117. package/dist/utils/path.js.map +0 -1
  118. package/docs/planning/memory-lane.md +0 -83
  119. package/packaging/linux/aicgen.spec +0 -23
  120. package/packaging/linux/control +0 -9
  121. package/packaging/macos/scripts/postinstall +0 -12
  122. package/packaging/windows/setup.nsi +0 -92
  123. package/scripts/add-categories.ts +0 -87
  124. package/scripts/build-binary.ts +0 -46
  125. package/scripts/embed-data.ts +0 -105
  126. package/scripts/generate-version.ts +0 -150
  127. package/scripts/test-decompress.ts +0 -27
  128. package/scripts/test-extract.ts +0 -31
  129. package/src/__tests__/services/assistant-file-writer.test.ts +0 -400
  130. package/src/__tests__/services/guideline-loader.test.ts +0 -281
  131. package/src/__tests__/services/tarball-extraction.test.ts +0 -125
  132. package/src/commands/add-guideline.ts +0 -296
  133. package/src/commands/clear.ts +0 -61
  134. package/src/commands/guideline-selector.ts +0 -123
  135. package/src/commands/init.ts +0 -645
  136. package/src/commands/quick-add.ts +0 -586
  137. package/src/commands/remove-guideline.ts +0 -152
  138. package/src/commands/stats.ts +0 -49
  139. package/src/commands/update.ts +0 -240
  140. package/src/config.ts +0 -82
  141. package/src/embedded-data.ts +0 -1492
  142. package/src/index.ts +0 -67
  143. package/src/models/profile.ts +0 -24
  144. package/src/models/project.ts +0 -43
  145. package/src/services/assistant-file-writer.ts +0 -612
  146. package/src/services/config-generator.ts +0 -150
  147. package/src/services/config-manager.ts +0 -70
  148. package/src/services/data-source.ts +0 -248
  149. package/src/services/first-run-init.ts +0 -148
  150. package/src/services/guideline-loader.ts +0 -311
  151. package/src/services/hook-generator.ts +0 -178
  152. package/src/services/subagent-generator.ts +0 -310
  153. package/src/utils/banner.ts +0 -66
  154. package/src/utils/errors.ts +0 -27
  155. package/src/utils/file.ts +0 -67
  156. package/src/utils/formatting.ts +0 -172
  157. package/src/utils/logger.ts +0 -89
  158. package/src/utils/path.ts +0 -17
  159. package/src/utils/wizard-state.ts +0 -132
  160. package/tsconfig.json +0 -25
@@ -1,310 +0,0 @@
1
- export interface SubAgentTemplate {
2
- name: string;
3
- content: string;
4
- }
5
-
6
- const EMBEDDED_AGENTS: Record<string, string> = {
7
- 'guideline-checker': `---
8
- model: "claude-opus-4-5"
9
- description: "Verifies code changes comply with project guidelines"
10
- ---
11
-
12
- # Guideline Compliance Checker
13
-
14
- You are an automated code review agent that verifies code changes follow the project's established guidelines.
15
-
16
- ## Your Responsibilities
17
-
18
- When code changes are made, automatically verify:
19
-
20
- ### Code Style Compliance
21
- - Naming conventions match project standards
22
- - File organization follows project structure
23
- - No redundant or commented-out code
24
- - Proper indentation and formatting
25
-
26
- ### TypeScript/JavaScript Standards
27
- - TypeScript strict mode compliance
28
- - No \`any\` types (use \`unknown\` with type guards)
29
- - Proper interface/type definitions
30
- - Async/await patterns used correctly
31
-
32
- ### Best Practices
33
- - Functions under 50 lines
34
- - Maximum 3 levels of nesting
35
- - Complex conditionals extracted to named functions
36
- - Error handling implemented properly
37
- - No magic numbers (use named constants)
38
-
39
- ### Testing Requirements
40
- - New functions have corresponding tests
41
- - Test coverage maintained or improved
42
- - Tests follow AAA pattern (Arrange, Act, Assert)
43
-
44
- ## Output Format
45
-
46
- Report findings in this format:
47
-
48
- \`\`\`
49
- ✅ Guideline Compliance Report
50
-
51
- Files checked: X
52
-
53
- ⚠️ Issues Found:
54
-
55
- src/services/example.ts:45
56
- - Uses \`any\` type instead of \`unknown\`
57
- - Function exceeds 50 lines (65 lines)
58
-
59
- src/utils/helper.ts:12
60
- - Magic number 3600 should be named constant
61
-
62
- src/commands/init.ts:120
63
- - Missing error handling for async operation
64
-
65
- 📋 Recommendations:
66
- 1. Replace \`any\` with \`unknown\` and add type guard
67
- 2. Extract SECONDS_IN_HOUR = 3600 as constant
68
- 3. Add try-catch block for async operation
69
-
70
- Overall: 3 issues require attention
71
- \`\`\`
72
-
73
- ## Guidelines
74
-
75
- - Be specific with file paths and line numbers
76
- - Explain WHY each issue matters
77
- - Provide actionable recommendations
78
- - Prioritize by severity (critical, important, minor)
79
- - Acknowledge good practices when found
80
- `,
81
-
82
- 'architecture-reviewer': `---
83
- model: "claude-sonnet-4-5"
84
- description: "Reviews architectural decisions and patterns"
85
- ---
86
-
87
- # Architecture Reviewer
88
-
89
- You are an architecture review agent ensuring code changes align with the project's architectural principles and patterns.
90
-
91
- ## Your Responsibilities
92
-
93
- ### Architectural Compliance
94
- - Verify changes follow established architecture pattern (layered, hexagonal, microservices, etc.)
95
- - Check dependency directions are correct
96
- - Ensure proper separation of concerns
97
- - Validate module boundaries
98
-
99
- ### Design Patterns
100
- - Identify appropriate use of design patterns
101
- - Flag anti-patterns (God objects, tight coupling, etc.)
102
- - Suggest pattern improvements when beneficial
103
- - Verify SOLID principles adherence
104
-
105
- ### Technical Debt
106
- - Identify potential technical debt introduced
107
- - Flag shortcuts that may cause future issues
108
- - Suggest refactoring opportunities
109
- - Assess long-term maintainability impact
110
-
111
- ## Review Checklist
112
-
113
- - [ ] Does this change respect the existing architecture?
114
- - [ ] Are dependencies pointing in the correct direction?
115
- - [ ] Is there proper separation between layers/modules?
116
- - [ ] Are interfaces/contracts well-defined?
117
- - [ ] Is the change introducing tight coupling?
118
- - [ ] Could this be simplified using existing patterns?
119
- - [ ] Does this create technical debt?
120
- - [ ] Is this scalable and maintainable?
121
-
122
- ## Output Format
123
-
124
- \`\`\`
125
- 🏗️ Architecture Review
126
-
127
- Files reviewed: X
128
- Architecture: [Layered/Hexagonal/Microservices/etc.]
129
-
130
- ✅ Strengths:
131
- - Proper dependency injection in ServiceFactory
132
- - Clean interface boundaries in API layer
133
-
134
- ⚠️ Concerns:
135
-
136
- 1. Dependency Violation (Critical)
137
- - File: src/ui/components/UserForm.tsx:23
138
- - Issue: Direct database access from UI layer
139
- - Impact: Violates layered architecture
140
- - Solution: Access data through service layer
141
-
142
- 2. Tight Coupling (Important)
143
- - File: src/services/email-service.ts:45
144
- - Issue: Hard-coded dependency on specific SMTP library
145
- - Impact: Difficult to swap email providers
146
- - Solution: Use adapter pattern with EmailProvider interface
147
-
148
- 3. Potential Debt (Minor)
149
- - File: src/utils/cache.ts:12
150
- - Issue: In-memory cache without eviction strategy
151
- - Impact: May cause memory issues at scale
152
- - Solution: Implement LRU eviction or use Redis
153
-
154
- 📊 Summary:
155
- - Critical issues: 1
156
- - Important issues: 1
157
- - Minor issues: 1
158
- - Technical debt score: Medium
159
-
160
- Recommendation: Address critical dependency violation before merging
161
- \`\`\`
162
-
163
- ## Guidelines
164
-
165
- - Focus on architectural implications, not minor style issues
166
- - Consider both immediate and long-term impacts
167
- - Provide specific, actionable solutions
168
- - Explain the "why" behind each concern
169
- - Balance idealism with pragmatism
170
- `,
171
-
172
- 'security-auditor': `---
173
- model: "claude-opus-4-5"
174
- temperature: 0.3
175
- description: "Identifies security vulnerabilities and risks"
176
- ---
177
-
178
- # Security Auditor
179
-
180
- You are a security-focused code review agent that identifies vulnerabilities, security risks, and unsafe practices.
181
-
182
- ## Your Responsibilities
183
-
184
- ### OWASP Top 10 Checks
185
- - SQL Injection vulnerabilities
186
- - Cross-Site Scripting (XSS)
187
- - Authentication and session management flaws
188
- - Insecure direct object references
189
- - Security misconfiguration
190
- - Sensitive data exposure
191
- - Missing access control
192
- - Cross-Site Request Forgery (CSRF)
193
- - Using components with known vulnerabilities
194
- - Insufficient logging and monitoring
195
-
196
- ### Code Security
197
- - Input validation and sanitization
198
- - Output encoding
199
- - Parameterized queries
200
- - Secure random number generation
201
- - Cryptographic best practices
202
- - Secrets and credential management
203
- - API key and token handling
204
-
205
- ### Common Vulnerabilities
206
- - Path traversal attacks
207
- - Command injection
208
- - XML/XXE injection
209
- - Deserialization vulnerabilities
210
- - Race conditions
211
- - Buffer overflows (in applicable languages)
212
-
213
- ## Review Process
214
-
215
- 1. Scan for obvious security issues
216
- 2. Check data flow from user input to storage/output
217
- 3. Verify authentication and authorization
218
- 4. Review cryptographic usage
219
- 5. Check dependency versions for known vulnerabilities
220
- 6. Assess error handling and information disclosure
221
-
222
- ## Output Format
223
-
224
- \`\`\`
225
- 🔒 Security Audit Report
226
-
227
- Files audited: X
228
- Risk Level: [Low/Medium/High/Critical]
229
-
230
- 🚨 Critical Vulnerabilities:
231
-
232
- 1. SQL Injection Risk
233
- - File: src/database/user-repository.ts:34
234
- - Code: \`db.query(\\\`SELECT * FROM users WHERE id = \${userId}\\\`)\`
235
- - Risk: Allows arbitrary SQL execution
236
- - Fix: Use parameterized query: \`db.query('SELECT * FROM users WHERE id = ?', [userId])\`
237
- - CWE: CWE-89
238
-
239
- ⚠️ High Risk Issues:
240
-
241
- 2. Sensitive Data Exposure
242
- - File: src/api/auth-controller.ts:89
243
- - Code: User password returned in API response
244
- - Risk: Password hash exposed to clients
245
- - Fix: Remove password from response object
246
-
247
- 🔔 Medium Risk Issues:
248
-
249
- 3. Missing Input Validation
250
- - File: src/api/upload-controller.ts:12
251
- - Code: File upload without type validation
252
- - Risk: Malicious file upload
253
- - Fix: Validate file type and size before processing
254
-
255
- 💡 Security Recommendations:
256
-
257
- - Enable Content Security Policy headers
258
- - Implement rate limiting on authentication endpoints
259
- - Add CSRF tokens to state-changing operations
260
- - Use secure HTTP-only cookies for sessions
261
- - Enable security headers (X-Frame-Options, etc.)
262
-
263
- 📊 Summary:
264
- - Critical: 1
265
- - High: 1
266
- - Medium: 1
267
- - Low: 0
268
-
269
- ⚠️ Action Required: Fix critical SQL injection before deployment
270
- \`\`\`
271
-
272
- ## Guidelines
273
-
274
- - Prioritize by actual risk, not theoretical scenarios
275
- - Provide clear, actionable fixes with code examples
276
- - Reference CWE/CVE numbers when applicable
277
- - Consider the application's threat model
278
- - Balance security with usability
279
- - Don't create false positives unnecessarily
280
- `
281
- };
282
-
283
- export class SubAgentGenerator {
284
- async generateSubAgents(guidelineIds: string[]): Promise<SubAgentTemplate[]> {
285
- const agents: SubAgentTemplate[] = [];
286
-
287
- agents.push({
288
- name: 'guideline-checker',
289
- content: EMBEDDED_AGENTS['guideline-checker']
290
- });
291
-
292
- const hasArchitecture = guidelineIds.some((id) => id.includes('architecture'));
293
- if (hasArchitecture) {
294
- agents.push({
295
- name: 'architecture-reviewer',
296
- content: EMBEDDED_AGENTS['architecture-reviewer']
297
- });
298
- }
299
-
300
- const hasSecurity = guidelineIds.some((id) => id.includes('security'));
301
- if (hasSecurity) {
302
- agents.push({
303
- name: 'security-auditor',
304
- content: EMBEDDED_AGENTS['security-auditor']
305
- });
306
- }
307
-
308
- return agents;
309
- }
310
- }
@@ -1,66 +0,0 @@
1
- import chalk from 'chalk';
2
- import { CONFIG } from '../config.js';
3
-
4
- // Color palette matching logo.svg
5
- const colors = {
6
- cyan: chalk.hex('#06b6d4'), // Neural nodes
7
- purple: chalk.hex('#8b5cf6'), // Box and flow end
8
- green: chalk.hex('#10b981'), // Success indicator
9
- gray: chalk.hex('#94a3b8'), // Subtitle
10
- white: chalk.white.bold, // Title
11
- };
12
-
13
- export function showBanner() {
14
- // ASCII art matching the new logo design with exact SVG colors
15
- const logo = `
16
- ${colors.cyan('(●)')}
17
- ${colors.cyan('╲')}
18
- ${colors.cyan('(●)')} ${colors.cyan('───')}${colors.purple('▶')} ${colors.purple('╔═════════════════════════════╗')}
19
- ${colors.cyan('╱')} ${colors.purple('║')} ${colors.white('AI CONFIG GENERATOR')} ${colors.purple('║')}
20
- ${colors.cyan('(●)')} ${colors.purple('║')} ${colors.gray('for better coding')} ${colors.purple('║')}
21
- ${colors.purple('╚═════════════════════════════╝')}
22
- `;
23
-
24
- console.log(logo);
25
- console.log(colors.gray(` v${CONFIG.APP_VERSION} · MIT License\n`));
26
- }
27
-
28
- export function showInstructions() {
29
- console.log(chalk.gray(' Navigation:'));
30
- console.log(chalk.gray(' ↑↓ arrows - Navigate options'));
31
- console.log(chalk.gray(' Space - Select/deselect (checkboxes)'));
32
- console.log(chalk.gray(' Enter - Confirm selection'));
33
- console.log(chalk.gray(' Ctrl+C - Cancel anytime\n'));
34
- }
35
-
36
- export function showCheckboxInstructions() {
37
- console.log(chalk.gray('\n 💡 Tip: Uncheck a category to uncheck all items in that category'));
38
- console.log(chalk.gray(' Use Space to toggle, Enter to confirm\n'));
39
- }
40
-
41
- export function getLogoPrefix(animated: boolean = false): string {
42
- if (!animated) {
43
- return `${colors.cyan('(●)')} ${colors.cyan('─')}${colors.purple('▶')} ${colors.purple('▢')}`;
44
- }
45
-
46
- const frames = [
47
- `${colors.cyan('(●)')} ${colors.cyan('─')}${colors.purple('▶')} ${colors.gray('▢')}`,
48
- `${colors.cyan('(●)')} ${colors.cyan('──')}${colors.purple('▶')} ${colors.gray('▢')}`,
49
- `${colors.cyan('(●)')} ${colors.cyan('───')}${colors.purple('▶')} ${colors.gray('▢')}`,
50
- `${colors.cyan('(●)')} ${colors.cyan('───')}${colors.purple('▶')} ${colors.purple('▣')}`,
51
- `${colors.cyan('(●)')} ${colors.cyan('───')}${colors.purple('▶')} ${colors.green('✓')}`
52
- ];
53
-
54
- const index = Math.floor(Date.now() / 200) % frames.length;
55
- return frames[index];
56
- }
57
-
58
- export function showSmallLogo() {
59
- console.log(`
60
- ${colors.cyan('(●)')}
61
- ${colors.cyan('╲')}
62
- ${colors.cyan('(●)')} ${colors.cyan('─')}${colors.purple('▶')} ${colors.purple('╔═══════╗')}
63
- ${colors.cyan('╱')} ${colors.purple('║')} ${colors.white('aicgen')} ${colors.purple('║')}
64
- ${colors.cyan('(●)')} ${colors.purple('╚═══════╝')}
65
- `);
66
- }
@@ -1,27 +0,0 @@
1
- export class AicgenError extends Error {
2
- constructor(
3
- message: string,
4
- public code: string,
5
- public details?: unknown
6
- ) {
7
- super(message);
8
- this.name = this.constructor.name;
9
- Error.captureStackTrace(this, this.constructor);
10
- }
11
- }
12
-
13
- export class ProjectNotFoundError extends AicgenError {
14
- constructor(path: string) {
15
- super(`Project not found at: ${path}`, 'PROJECT_NOT_FOUND', { path });
16
- }
17
- }
18
-
19
- export class ConfigExistsError extends AicgenError {
20
- constructor(path: string) {
21
- super(
22
- `Configuration already exists at: ${path}. Use --force to overwrite.`,
23
- 'CONFIG_EXISTS',
24
- { path }
25
- );
26
- }
27
- }
package/src/utils/file.ts DELETED
@@ -1,67 +0,0 @@
1
- import { promises as fs } from 'fs';
2
- import { dirname } from 'path';
3
-
4
- export async function exists(path: string): Promise<boolean> {
5
- try {
6
- await fs.access(path);
7
- return true;
8
- } catch {
9
- return false;
10
- }
11
- }
12
-
13
- export async function readFile(path: string): Promise<string> {
14
- return fs.readFile(path, 'utf-8');
15
- }
16
-
17
- export async function writeFile(path: string, content: string): Promise<void> {
18
- await ensureDir(dirname(path));
19
- const tempPath = `${path}.tmp`;
20
- await fs.writeFile(tempPath, content, 'utf-8');
21
- await fs.rename(tempPath, path);
22
- }
23
-
24
- export async function ensureDir(path: string): Promise<void> {
25
- await fs.mkdir(path, { recursive: true });
26
- }
27
-
28
- export async function readJSON<T>(path: string): Promise<T> {
29
- const content = await readFile(path);
30
- return JSON.parse(content);
31
- }
32
-
33
- export async function writeJSON<T>(path: string, data: T): Promise<void> {
34
- const content = JSON.stringify(data, null, 2);
35
- await writeFile(path, content);
36
- }
37
-
38
- export interface FileToWrite {
39
- path: string;
40
- content: string;
41
- }
42
-
43
- export async function writeFiles(files: FileToWrite[]): Promise<void> {
44
- const tempFiles: string[] = [];
45
-
46
- try {
47
- for (const file of files) {
48
- await ensureDir(dirname(file.path));
49
- const tempPath = `${file.path}.tmp`;
50
- await fs.writeFile(tempPath, file.content, 'utf-8');
51
- tempFiles.push(tempPath);
52
- }
53
-
54
- for (let i = 0; i < files.length; i++) {
55
- await fs.rename(tempFiles[i], files[i].path);
56
- }
57
- } catch (error) {
58
- for (const tempPath of tempFiles) {
59
- try {
60
- await fs.unlink(tempPath);
61
- } catch {
62
- // Ignore cleanup errors
63
- }
64
- }
65
- throw error;
66
- }
67
- }
@@ -1,172 +0,0 @@
1
- import chalk from 'chalk';
2
-
3
- export interface BoxOptions {
4
- title?: string;
5
- padding?: number;
6
- width?: number;
7
- borderColor?: 'cyan' | 'magenta' | 'gray' | 'white';
8
- }
9
-
10
- export function drawBox(content: string[], options: BoxOptions = {}): string {
11
- const {
12
- title,
13
- padding = 1,
14
- width = 60,
15
- borderColor = 'cyan'
16
- } = options;
17
-
18
- const color = {
19
- cyan: chalk.cyan,
20
- magenta: chalk.magenta,
21
- gray: chalk.gray,
22
- white: chalk.white
23
- }[borderColor];
24
-
25
- const lines: string[] = [];
26
- const contentWidth = width - 2;
27
-
28
- // Top border
29
- if (title) {
30
- const titleText = ` ${title} `;
31
- const leftPad = Math.floor((width - titleText.length - 2) / 2);
32
- const rightPad = width - titleText.length - leftPad - 2;
33
- lines.push(color('╭' + '─'.repeat(leftPad) + titleText + '─'.repeat(rightPad) + '╮'));
34
- } else {
35
- lines.push(color('╭' + '─'.repeat(contentWidth) + '╮'));
36
- }
37
-
38
- // Padding top
39
- for (let i = 0; i < padding; i++) {
40
- lines.push(color('│') + ' '.repeat(contentWidth) + color('│'));
41
- }
42
-
43
- // Content
44
- for (const line of content) {
45
- const stripped = stripAnsi(line);
46
- const lineWidth = stripped.length;
47
- const spacesNeeded = contentWidth - lineWidth;
48
- lines.push(color('│') + line + ' '.repeat(Math.max(0, spacesNeeded)) + color('│'));
49
- }
50
-
51
- // Padding bottom
52
- for (let i = 0; i < padding; i++) {
53
- lines.push(color('│') + ' '.repeat(contentWidth) + color('│'));
54
- }
55
-
56
- // Bottom border
57
- lines.push(color('╰' + '─'.repeat(contentWidth) + '╯'));
58
-
59
- return lines.join('\n');
60
- }
61
-
62
- export function drawSeparator(width: number = 60, char: string = '─', color: 'cyan' | 'magenta' | 'gray' = 'gray'): string {
63
- const colorFn = {
64
- cyan: chalk.cyan,
65
- magenta: chalk.magenta,
66
- gray: chalk.gray
67
- }[color];
68
-
69
- return colorFn(char.repeat(width));
70
- }
71
-
72
- export function drawTable(headers: string[], rows: string[][], options: { borderColor?: 'cyan' | 'magenta' | 'gray' } = {}): string {
73
- const borderColor = options.borderColor || 'cyan';
74
- const color = {
75
- cyan: chalk.cyan,
76
- magenta: chalk.magenta,
77
- gray: chalk.gray
78
- }[borderColor];
79
-
80
- // Calculate column widths
81
- const colWidths = headers.map((header, i) => {
82
- const headerWidth = stripAnsi(header).length;
83
- const maxRowWidth = Math.max(...rows.map(row => stripAnsi(row[i] || '').length));
84
- return Math.max(headerWidth, maxRowWidth) + 2;
85
- });
86
-
87
- const lines: string[] = [];
88
- // const totalWidth = colWidths.reduce((sum, w) => sum + w, 0) + colWidths.length + 1;
89
-
90
- // Top border
91
- lines.push(color('╭' + colWidths.map(w => '─'.repeat(w)).join('┬') + '╮'));
92
-
93
- // Headers
94
- const headerLine = color('│') + headers.map((h, i) => {
95
- const stripped = stripAnsi(h);
96
- const padding = colWidths[i] - stripped.length;
97
- return h + ' '.repeat(padding);
98
- }).join(color('│')) + color('│');
99
- lines.push(headerLine);
100
-
101
- // Header separator
102
- lines.push(color('├' + colWidths.map(w => '─'.repeat(w)).join('┼') + '┤'));
103
-
104
- // Rows
105
- for (const row of rows) {
106
- const rowLine = color('│') + row.map((cell, i) => {
107
- const stripped = stripAnsi(cell);
108
- const padding = colWidths[i] - stripped.length;
109
- return cell + ' '.repeat(padding);
110
- }).join(color('│')) + color('│');
111
- lines.push(rowLine);
112
- }
113
-
114
- // Bottom border
115
- lines.push(color('╰' + colWidths.map(w => '─'.repeat(w)).join('┴') + '╯'));
116
-
117
- return lines.join('\n');
118
- }
119
-
120
- export function padLeft(text: string, width: number, char: string = ' '): string {
121
- const stripped = stripAnsi(text);
122
- const padding = Math.max(0, width - stripped.length);
123
- return char.repeat(padding) + text;
124
- }
125
-
126
- export function padRight(text: string, width: number, char: string = ' '): string {
127
- const stripped = stripAnsi(text);
128
- const padding = Math.max(0, width - stripped.length);
129
- return text + char.repeat(padding);
130
- }
131
-
132
- export function center(text: string, width: number): string {
133
- const stripped = stripAnsi(text);
134
- const padding = Math.max(0, width - stripped.length);
135
- const leftPad = Math.floor(padding / 2);
136
- const rightPad = padding - leftPad;
137
- return ' '.repeat(leftPad) + text + ' '.repeat(rightPad);
138
- }
139
-
140
- // Simple ANSI strip function (basic implementation)
141
- function stripAnsi(str: string): string {
142
- // eslint-disable-next-line no-control-regex
143
- return str.replace(/\x1b\[[0-9;]*m/g, '');
144
- }
145
-
146
- export function createSummaryBox(title: string, items: { label: string; value: string }[]): string {
147
- const maxLabelWidth = Math.max(...items.map(i => i.label.length));
148
- const content = items.map(({ label, value }) => {
149
- const paddedLabel = padRight(chalk.gray(label + ':'), maxLabelWidth + 2);
150
- return ` ${paddedLabel} ${chalk.white(value)}`;
151
- });
152
-
153
- return drawBox(content, {
154
- title,
155
- padding: 1,
156
- width: 60,
157
- borderColor: 'cyan'
158
- });
159
- }
160
-
161
- export function createMetricsBox(metrics: { label: string; value: string | number }[]): string {
162
- const content = metrics.map(({ label, value }) => {
163
- return ` ${chalk.gray('•')} ${chalk.white(value)} ${chalk.gray(label)}`;
164
- });
165
-
166
- return drawBox(content, {
167
- title: '📊 Configuration Preview',
168
- padding: 1,
169
- width: 50,
170
- borderColor: 'magenta'
171
- });
172
- }