@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.
- package/{.claude/guidelines → .agent/rules}/api-design.md +5 -1
- package/{.claude/guidelines → .agent/rules}/architecture.md +5 -1
- package/{.claude/guidelines → .agent/rules}/best-practices.md +5 -1
- package/{.claude/guidelines → .agent/rules}/code-style.md +5 -1
- package/{.claude/guidelines → .agent/rules}/design-patterns.md +5 -1
- package/{.claude/guidelines → .agent/rules}/devops.md +5 -1
- package/{.claude/guidelines → .agent/rules}/error-handling.md +5 -1
- package/.agent/rules/instructions.md +28 -0
- package/{.claude/guidelines → .agent/rules}/language.md +5 -1
- package/{.claude/guidelines → .agent/rules}/performance.md +5 -1
- package/{.claude/guidelines → .agent/rules}/security.md +5 -1
- package/{.claude/guidelines → .agent/rules}/testing.md +5 -1
- package/.agent/workflows/add-documentation.md +10 -0
- package/.agent/workflows/generate-integration-tests.md +10 -0
- package/.agent/workflows/generate-unit-tests.md +11 -0
- package/.agent/workflows/performance-audit.md +11 -0
- package/.agent/workflows/refactor-extract-module.md +12 -0
- package/.agent/workflows/security-audit.md +12 -0
- package/.gemini/instructions.md +4843 -0
- package/.vs/ProjectSettings.json +2 -2
- package/.vs/VSWorkspaceState.json +15 -15
- package/.vs/aicgen.slnx/v18/DocumentLayout.json +53 -53
- package/AGENTS.md +9 -11
- package/assets/icon.svg +33 -33
- package/bun.lock +734 -26
- package/{CLAUDE.md → claude.md} +2 -2
- package/config.example.yml +129 -0
- package/config.yml +38 -0
- package/data/architecture/microservices/api-gateway.md +56 -56
- package/data/devops/observability.md +73 -73
- package/data/guideline-mappings.yml +128 -0
- package/data/language/dart/async.md +289 -0
- package/data/language/dart/basics.md +280 -0
- package/data/language/dart/error-handling.md +355 -0
- package/data/language/dart/index.md +10 -0
- package/data/language/dart/testing.md +352 -0
- package/data/language/swift/basics.md +477 -0
- package/data/language/swift/concurrency.md +654 -0
- package/data/language/swift/error-handling.md +679 -0
- package/data/language/swift/swiftui-mvvm.md +795 -0
- package/data/language/swift/testing.md +708 -0
- package/data/version.json +10 -8
- package/dist/index.js +50153 -28959
- package/jest.config.js +46 -0
- package/package.json +14 -3
- package/.claude/agents/architecture-reviewer.md +0 -88
- package/.claude/agents/guideline-checker.md +0 -73
- package/.claude/agents/security-auditor.md +0 -108
- package/.claude/settings.json +0 -98
- package/.claude/settings.local.json +0 -8
- package/.eslintrc.json +0 -28
- package/.github/workflows/release.yml +0 -180
- package/.github/workflows/test.yml +0 -81
- package/CONTRIBUTING.md +0 -821
- package/dist/commands/init.d.ts +0 -8
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js +0 -46
- package/dist/commands/init.js.map +0 -1
- package/dist/config/profiles.d.ts +0 -4
- package/dist/config/profiles.d.ts.map +0 -1
- package/dist/config/profiles.js +0 -30
- package/dist/config/profiles.js.map +0 -1
- package/dist/config/settings.d.ts +0 -7
- package/dist/config/settings.d.ts.map +0 -1
- package/dist/config/settings.js +0 -7
- package/dist/config/settings.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/models/guideline.d.ts +0 -15
- package/dist/models/guideline.d.ts.map +0 -1
- package/dist/models/guideline.js +0 -2
- package/dist/models/guideline.js.map +0 -1
- package/dist/models/preference.d.ts +0 -9
- package/dist/models/preference.d.ts.map +0 -1
- package/dist/models/preference.js +0 -2
- package/dist/models/preference.js.map +0 -1
- package/dist/models/profile.d.ts +0 -9
- package/dist/models/profile.d.ts.map +0 -1
- package/dist/models/profile.js +0 -2
- package/dist/models/profile.js.map +0 -1
- package/dist/models/project.d.ts +0 -13
- package/dist/models/project.d.ts.map +0 -1
- package/dist/models/project.js +0 -2
- package/dist/models/project.js.map +0 -1
- package/dist/services/ai/anthropic.d.ts +0 -7
- package/dist/services/ai/anthropic.d.ts.map +0 -1
- package/dist/services/ai/anthropic.js +0 -39
- package/dist/services/ai/anthropic.js.map +0 -1
- package/dist/services/generator.d.ts +0 -2
- package/dist/services/generator.d.ts.map +0 -1
- package/dist/services/generator.js +0 -4
- package/dist/services/generator.js.map +0 -1
- package/dist/services/learner.d.ts +0 -2
- package/dist/services/learner.d.ts.map +0 -1
- package/dist/services/learner.js +0 -4
- package/dist/services/learner.js.map +0 -1
- package/dist/services/scanner.d.ts +0 -3
- package/dist/services/scanner.d.ts.map +0 -1
- package/dist/services/scanner.js +0 -54
- package/dist/services/scanner.js.map +0 -1
- package/dist/utils/errors.d.ts +0 -15
- package/dist/utils/errors.d.ts.map +0 -1
- package/dist/utils/errors.js +0 -27
- package/dist/utils/errors.js.map +0 -1
- package/dist/utils/file.d.ts +0 -7
- package/dist/utils/file.d.ts.map +0 -1
- package/dist/utils/file.js +0 -32
- package/dist/utils/file.js.map +0 -1
- package/dist/utils/logger.d.ts +0 -6
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js +0 -17
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/path.d.ts +0 -6
- package/dist/utils/path.d.ts.map +0 -1
- package/dist/utils/path.js +0 -14
- package/dist/utils/path.js.map +0 -1
- package/docs/planning/memory-lane.md +0 -83
- package/packaging/linux/aicgen.spec +0 -23
- package/packaging/linux/control +0 -9
- package/packaging/macos/scripts/postinstall +0 -12
- package/packaging/windows/setup.nsi +0 -92
- package/scripts/add-categories.ts +0 -87
- package/scripts/build-binary.ts +0 -46
- package/scripts/embed-data.ts +0 -105
- package/scripts/generate-version.ts +0 -150
- package/scripts/test-decompress.ts +0 -27
- package/scripts/test-extract.ts +0 -31
- package/src/__tests__/services/assistant-file-writer.test.ts +0 -400
- package/src/__tests__/services/guideline-loader.test.ts +0 -281
- package/src/__tests__/services/tarball-extraction.test.ts +0 -125
- package/src/commands/add-guideline.ts +0 -296
- package/src/commands/clear.ts +0 -61
- package/src/commands/guideline-selector.ts +0 -123
- package/src/commands/init.ts +0 -645
- package/src/commands/quick-add.ts +0 -586
- package/src/commands/remove-guideline.ts +0 -152
- package/src/commands/stats.ts +0 -49
- package/src/commands/update.ts +0 -240
- package/src/config.ts +0 -82
- package/src/embedded-data.ts +0 -1492
- package/src/index.ts +0 -67
- package/src/models/profile.ts +0 -24
- package/src/models/project.ts +0 -43
- package/src/services/assistant-file-writer.ts +0 -612
- package/src/services/config-generator.ts +0 -150
- package/src/services/config-manager.ts +0 -70
- package/src/services/data-source.ts +0 -248
- package/src/services/first-run-init.ts +0 -148
- package/src/services/guideline-loader.ts +0 -311
- package/src/services/hook-generator.ts +0 -178
- package/src/services/subagent-generator.ts +0 -310
- package/src/utils/banner.ts +0 -66
- package/src/utils/errors.ts +0 -27
- package/src/utils/file.ts +0 -67
- package/src/utils/formatting.ts +0 -172
- package/src/utils/logger.ts +0 -89
- package/src/utils/path.ts +0 -17
- package/src/utils/wizard-state.ts +0 -132
- package/tsconfig.json +0 -25
|
@@ -1,125 +0,0 @@
|
|
|
1
|
-
import { describe, test, expect } from 'bun:test';
|
|
2
|
-
import { CONFIG } from '../../config.js';
|
|
3
|
-
|
|
4
|
-
describe('Tarball Extraction Configuration', () => {
|
|
5
|
-
describe('CONFIG-based Prefix', () => {
|
|
6
|
-
test('should have correct GitHub owner configured', () => {
|
|
7
|
-
expect(CONFIG.GITHUB_REPO_OWNER).toBe('aicgen');
|
|
8
|
-
});
|
|
9
|
-
|
|
10
|
-
test('should have correct GitHub repo configured', () => {
|
|
11
|
-
expect(CONFIG.GITHUB_REPO_NAME).toBe('aicgen-data');
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
test('should construct correct expected prefix', () => {
|
|
15
|
-
const expectedPrefix = `${CONFIG.GITHUB_REPO_OWNER}-${CONFIG.GITHUB_REPO_NAME}-`;
|
|
16
|
-
expect(expectedPrefix).toBe('aicgen-aicgen-data-');
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test('should not use hardcoded lpsandaruwan prefix', () => {
|
|
20
|
-
const expectedPrefix = `${CONFIG.GITHUB_REPO_OWNER}-${CONFIG.GITHUB_REPO_NAME}-`;
|
|
21
|
-
expect(expectedPrefix).not.toBe('lpsandaruwan-aicgen-docs-');
|
|
22
|
-
});
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
describe('Directory Name Matching', () => {
|
|
26
|
-
test('should match correct tarball directory format', () => {
|
|
27
|
-
const expectedPrefix = `${CONFIG.GITHUB_REPO_OWNER}-${CONFIG.GITHUB_REPO_NAME}-`;
|
|
28
|
-
const sampleDirectories = [
|
|
29
|
-
'aicgen-aicgen-data-abc123',
|
|
30
|
-
'aicgen-aicgen-data-def456',
|
|
31
|
-
'aicgen-aicgen-data-1234567890abcdef'
|
|
32
|
-
];
|
|
33
|
-
|
|
34
|
-
sampleDirectories.forEach(dir => {
|
|
35
|
-
expect(dir.startsWith(expectedPrefix)).toBe(true);
|
|
36
|
-
});
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
test('should not match incorrect directory formats', () => {
|
|
40
|
-
const expectedPrefix = `${CONFIG.GITHUB_REPO_OWNER}-${CONFIG.GITHUB_REPO_NAME}-`;
|
|
41
|
-
const incorrectDirectories = [
|
|
42
|
-
'lpsandaruwan-aicgen-docs-abc123',
|
|
43
|
-
'other-repo-abc123',
|
|
44
|
-
'random-directory'
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
incorrectDirectories.forEach(dir => {
|
|
48
|
-
expect(dir.startsWith(expectedPrefix)).toBe(false);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test('should find correct directory in mixed entries', () => {
|
|
53
|
-
const expectedPrefix = `${CONFIG.GITHUB_REPO_OWNER}-${CONFIG.GITHUB_REPO_NAME}-`;
|
|
54
|
-
const entries = [
|
|
55
|
-
'archive.tar.gz',
|
|
56
|
-
'aicgen-aicgen-data-abc123',
|
|
57
|
-
'other-file.md',
|
|
58
|
-
'.temp'
|
|
59
|
-
];
|
|
60
|
-
|
|
61
|
-
const rootDir = entries.find(entry => entry.startsWith(expectedPrefix));
|
|
62
|
-
expect(rootDir).toBe('aicgen-aicgen-data-abc123');
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
describe('GitHub API URLs', () => {
|
|
67
|
-
test('should construct correct releases URL', () => {
|
|
68
|
-
const repoUrl = `${CONFIG.GITHUB_API_BASE}/repos/${CONFIG.GITHUB_REPO_OWNER}/${CONFIG.GITHUB_REPO_NAME}`;
|
|
69
|
-
expect(repoUrl).toBe('https://api.github.com/repos/aicgen/aicgen-data');
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test('should construct correct releases latest URL', () => {
|
|
73
|
-
const releasesUrl = `${CONFIG.GITHUB_API_BASE}/repos/${CONFIG.GITHUB_REPO_OWNER}/${CONFIG.GITHUB_REPO_NAME}/releases/latest`;
|
|
74
|
-
expect(releasesUrl).toBe('https://api.github.com/repos/aicgen/aicgen-data/releases/latest');
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
describe('Cache Directory Structure', () => {
|
|
79
|
-
test('should have correct cache directory name', () => {
|
|
80
|
-
expect(CONFIG.CACHE_DIR_NAME).toBe('.aicgen');
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
test('should have correct data directory name', () => {
|
|
84
|
-
expect(CONFIG.DATA_DIR).toBe('data');
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test('should have correct cache subdirectory', () => {
|
|
88
|
-
expect(CONFIG.CACHE_DIR).toBe('cache/official');
|
|
89
|
-
});
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
describe('Version Management', () => {
|
|
93
|
-
test('should have valid version format', () => {
|
|
94
|
-
const version = CONFIG.APP_VERSION;
|
|
95
|
-
// Valid version: X.Y.Z-prerelease or X.Y-prerelease (e.g., "1.0.0-beta.1" or "1.0-beta")
|
|
96
|
-
const versionPattern = /^\d+\.\d+(\.\d+)?(-[a-z0-9.]+)?$/i;
|
|
97
|
-
expect(versionPattern.test(version)).toBe(true);
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
test('should not have invalid version patterns', () => {
|
|
101
|
-
const version = CONFIG.APP_VERSION;
|
|
102
|
-
// Should not match invalid patterns like "0.1.0b1" or "0.1b"
|
|
103
|
-
expect(version).not.toMatch(/\d+\.\d+\.\d+b\d*/);
|
|
104
|
-
expect(version).not.toMatch(/\d+b$/);
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
describe('Environment Variable Override', () => {
|
|
109
|
-
test('should allow GitHub owner override via env', () => {
|
|
110
|
-
// This tests that the priority system exists (ENV > Config > Default)
|
|
111
|
-
// Actual override would need to be tested in integration tests
|
|
112
|
-
const hasEnvSupport = CONFIG.GITHUB_REPO_OWNER === (
|
|
113
|
-
process.env.AICGEN_GITHUB_OWNER || 'aicgen'
|
|
114
|
-
);
|
|
115
|
-
expect(hasEnvSupport).toBe(true);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
test('should allow GitHub repo override via env', () => {
|
|
119
|
-
const hasEnvSupport = CONFIG.GITHUB_REPO_NAME === (
|
|
120
|
-
process.env.AICGEN_GITHUB_REPO || 'aicgen-data'
|
|
121
|
-
);
|
|
122
|
-
expect(hasEnvSupport).toBe(true);
|
|
123
|
-
});
|
|
124
|
-
});
|
|
125
|
-
});
|
|
@@ -1,296 +0,0 @@
|
|
|
1
|
-
import { select, input, checkbox, confirm, editor } from '@inquirer/prompts';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import { homedir } from 'os';
|
|
4
|
-
import { join, dirname } from 'path';
|
|
5
|
-
import { mkdir, writeFile, readFile, access } from 'fs/promises';
|
|
6
|
-
import YAML from 'yaml';
|
|
7
|
-
import { GuidelineLoader, GuidelineMapping } from '../services/guideline-loader.js';
|
|
8
|
-
import { showBanner } from '../utils/banner.js';
|
|
9
|
-
import { createSummaryBox } from '../utils/formatting.js';
|
|
10
|
-
import { Language } from '../models/project.js';
|
|
11
|
-
import { InstructionLevel, ArchitectureType } from '../models/profile.js';
|
|
12
|
-
import { CONFIG } from '../config.js';
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const LANGUAGES: { value: Language; name: string }[] = [
|
|
16
|
-
{ value: 'typescript', name: 'TypeScript' },
|
|
17
|
-
{ value: 'javascript', name: 'JavaScript' },
|
|
18
|
-
{ value: 'python', name: 'Python' },
|
|
19
|
-
{ value: 'go', name: 'Go' },
|
|
20
|
-
{ value: 'rust', name: 'Rust' },
|
|
21
|
-
{ value: 'java', name: 'Java' },
|
|
22
|
-
{ value: 'csharp', name: 'C#' },
|
|
23
|
-
{ value: 'ruby', name: 'Ruby' }
|
|
24
|
-
];
|
|
25
|
-
|
|
26
|
-
const LEVELS: { value: InstructionLevel; name: string }[] = [
|
|
27
|
-
{ value: 'basic', name: 'Basic' },
|
|
28
|
-
{ value: 'standard', name: 'Standard' },
|
|
29
|
-
{ value: 'expert', name: 'Expert' },
|
|
30
|
-
{ value: 'full', name: 'Full' }
|
|
31
|
-
];
|
|
32
|
-
|
|
33
|
-
const ARCHITECTURES: { value: ArchitectureType; name: string }[] = [
|
|
34
|
-
{ value: 'layered', name: 'Layered' },
|
|
35
|
-
{ value: 'modular-monolith', name: 'Modular Monolith' },
|
|
36
|
-
{ value: 'microservices', name: 'Microservices' },
|
|
37
|
-
{ value: 'event-driven', name: 'Event-Driven' },
|
|
38
|
-
{ value: 'hexagonal', name: 'Hexagonal' },
|
|
39
|
-
{ value: 'clean-architecture', name: 'Clean Architecture' },
|
|
40
|
-
{ value: 'ddd', name: 'Domain-Driven Design' },
|
|
41
|
-
{ value: 'serverless', name: 'Serverless' },
|
|
42
|
-
{ value: 'other', name: 'Other / None' }
|
|
43
|
-
];
|
|
44
|
-
|
|
45
|
-
export async function addGuidelineCommand() {
|
|
46
|
-
showBanner();
|
|
47
|
-
|
|
48
|
-
console.log(chalk.cyan('\n📝 Add Custom Guideline\n'));
|
|
49
|
-
|
|
50
|
-
try {
|
|
51
|
-
// 1. Load existing guidelines to show categories
|
|
52
|
-
const loader = await GuidelineLoader.create();
|
|
53
|
-
const stats = loader.getStats();
|
|
54
|
-
const existingCategories = Object.keys(stats.byCategory).sort();
|
|
55
|
-
|
|
56
|
-
// 2. Select or create category
|
|
57
|
-
const categoryChoice = await select({
|
|
58
|
-
message: 'Select category:',
|
|
59
|
-
choices: [
|
|
60
|
-
{ value: '__new__', name: chalk.green('+ Create new category') },
|
|
61
|
-
{ value: '__separator__', name: chalk.gray('─'.repeat(50)), disabled: true },
|
|
62
|
-
...existingCategories.map(c => ({ value: c, name: c })),
|
|
63
|
-
{ value: 'cancel', name: 'Cancel', description: 'Exit' }
|
|
64
|
-
]
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
if (categoryChoice === 'cancel') {
|
|
68
|
-
console.log(chalk.gray('\nCancelled.'));
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
let category: string;
|
|
73
|
-
if (categoryChoice === '__new__') {
|
|
74
|
-
category = await input({
|
|
75
|
-
message: 'Category name:',
|
|
76
|
-
validate: (value) => {
|
|
77
|
-
if (!value.trim()) return 'Category name is required';
|
|
78
|
-
if (value.length > 50) return 'Category name too long (max 50 characters)';
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
} else {
|
|
83
|
-
category = categoryChoice;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// 3. Guideline details
|
|
87
|
-
const name = await input({
|
|
88
|
-
message: 'Guideline name:',
|
|
89
|
-
validate: (value) => {
|
|
90
|
-
if (!value.trim()) return 'Name is required';
|
|
91
|
-
if (value.length > 100) return 'Name too long (max 100 characters)';
|
|
92
|
-
return true;
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
const description = await input({
|
|
97
|
-
message: 'Short description (optional):',
|
|
98
|
-
default: ''
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
// 4. Applicability - Languages
|
|
102
|
-
const languageChoice = await select({
|
|
103
|
-
message: 'Applicable to languages:',
|
|
104
|
-
choices: [
|
|
105
|
-
{ value: 'all', name: 'All languages' },
|
|
106
|
-
{ value: 'specific', name: 'Specific languages only' }
|
|
107
|
-
]
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
let languages: Language[] = [];
|
|
111
|
-
if (languageChoice === 'specific') {
|
|
112
|
-
languages = await checkbox({
|
|
113
|
-
message: 'Select languages:',
|
|
114
|
-
choices: LANGUAGES.map(l => ({ value: l.value, name: l.name }))
|
|
115
|
-
}) as Language[];
|
|
116
|
-
|
|
117
|
-
if (languages.length === 0) {
|
|
118
|
-
console.log(chalk.yellow('\n⚠️ No languages selected, applying to all languages'));
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// 5. Applicability - Levels
|
|
123
|
-
const levels = await checkbox({
|
|
124
|
-
message: 'Applicable to instruction levels:',
|
|
125
|
-
choices: LEVELS.map(l => ({ value: l.value, name: l.name, checked: true }))
|
|
126
|
-
}) as InstructionLevel[];
|
|
127
|
-
|
|
128
|
-
if (levels.length === 0) {
|
|
129
|
-
console.log(chalk.yellow('\n⚠️ No levels selected, using all levels'));
|
|
130
|
-
levels.push('basic', 'standard', 'expert', 'full');
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// 6. Applicability - Architectures
|
|
134
|
-
const architectureChoice = await select({
|
|
135
|
-
message: 'Applicable to architectures:',
|
|
136
|
-
choices: [
|
|
137
|
-
{ value: 'all', name: 'All architectures' },
|
|
138
|
-
{ value: 'specific', name: 'Specific architectures only' }
|
|
139
|
-
]
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
let architectures: ArchitectureType[] = [];
|
|
143
|
-
if (architectureChoice === 'specific') {
|
|
144
|
-
architectures = await checkbox({
|
|
145
|
-
message: 'Select architectures:',
|
|
146
|
-
choices: ARCHITECTURES.map(a => ({ value: a.value, name: a.name }))
|
|
147
|
-
}) as ArchitectureType[];
|
|
148
|
-
|
|
149
|
-
if (architectures.length === 0) {
|
|
150
|
-
console.log(chalk.yellow('\n⚠️ No architectures selected, applying to all'));
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// 7. Tags
|
|
155
|
-
const tagsInput = await input({
|
|
156
|
-
message: 'Tags (comma-separated, optional):',
|
|
157
|
-
default: ''
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
const tags = tagsInput
|
|
161
|
-
? tagsInput.split(',').map(t => t.trim()).filter(t => t.length > 0)
|
|
162
|
-
: [];
|
|
163
|
-
|
|
164
|
-
// 8. Content
|
|
165
|
-
console.log(chalk.cyan('\n📄 Guideline Content\n'));
|
|
166
|
-
|
|
167
|
-
const contentChoice = await select({
|
|
168
|
-
message: 'How to provide content?',
|
|
169
|
-
choices: [
|
|
170
|
-
{ value: 'editor', name: 'Open in default editor (recommended)', description: 'Uses $EDITOR or default system editor' },
|
|
171
|
-
{ value: 'file', name: 'Import from file', description: 'Copy content from existing markdown file' },
|
|
172
|
-
{ value: 'inline', name: 'Type inline', description: 'For short content only' }
|
|
173
|
-
]
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
let content: string;
|
|
177
|
-
switch (contentChoice) {
|
|
178
|
-
case 'file': {
|
|
179
|
-
const filePath = await input({
|
|
180
|
-
message: 'File path:',
|
|
181
|
-
validate: async (value) => {
|
|
182
|
-
try {
|
|
183
|
-
await access(value);
|
|
184
|
-
return true;
|
|
185
|
-
} catch {
|
|
186
|
-
return 'File not found';
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
content = await readFile(filePath, 'utf-8');
|
|
191
|
-
break;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
case 'editor':
|
|
195
|
-
content = await editor({
|
|
196
|
-
message: 'Write your guideline (will open in editor):',
|
|
197
|
-
default: `# ${name}\n\n${description ? description + '\n\n' : ''}## Overview\n\nWrite your guideline content here...\n\n## Examples\n\n\`\`\`\n// Code examples\n\`\`\`\n\n## Best Practices\n\n- Point 1\n- Point 2\n`
|
|
198
|
-
});
|
|
199
|
-
break;
|
|
200
|
-
|
|
201
|
-
case 'inline':
|
|
202
|
-
content = await editor({
|
|
203
|
-
message: 'Content (markdown):',
|
|
204
|
-
default: `# ${name}\n\n`
|
|
205
|
-
});
|
|
206
|
-
break;
|
|
207
|
-
|
|
208
|
-
default:
|
|
209
|
-
content = '';
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (!content.trim()) {
|
|
213
|
-
console.log(chalk.red('\n❌ Content cannot be empty'));
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// 9. Generate ID and paths
|
|
218
|
-
const id = generateGuidelineId(category, name);
|
|
219
|
-
const categorySlug = category.toLowerCase().replace(/\s+/g, '-');
|
|
220
|
-
const nameSlug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-');
|
|
221
|
-
const relativePath = `${categorySlug}/${nameSlug}.md`;
|
|
222
|
-
|
|
223
|
-
// 10. Show preview
|
|
224
|
-
console.log('\n' + createSummaryBox('📋 Guideline Preview', [
|
|
225
|
-
{ label: 'ID', value: id },
|
|
226
|
-
{ label: 'Category', value: category },
|
|
227
|
-
{ label: 'Name', value: name },
|
|
228
|
-
{ label: 'Path', value: relativePath },
|
|
229
|
-
{ label: 'Languages', value: languages.length > 0 ? languages.join(', ') : 'All' },
|
|
230
|
-
{ label: 'Levels', value: levels.join(', ') },
|
|
231
|
-
{ label: 'Architectures', value: architectures.length > 0 ? architectures.join(', ') : 'All' },
|
|
232
|
-
{ label: 'Tags', value: tags.length > 0 ? tags.join(', ') : 'None' },
|
|
233
|
-
{ label: 'Size', value: `${content.length} characters, ${content.split('\n').length} lines` }
|
|
234
|
-
]));
|
|
235
|
-
|
|
236
|
-
const shouldAdd = await confirm({
|
|
237
|
-
message: 'Add this guideline?',
|
|
238
|
-
default: true
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
if (!shouldAdd) {
|
|
242
|
-
console.log(chalk.gray('\nCancelled.'));
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
// 11. Write files
|
|
247
|
-
const userDataPath = join(homedir(), CONFIG.CACHE_DIR_NAME, CONFIG.DATA_DIR);
|
|
248
|
-
const guidelinePath = join(userDataPath, 'guidelines', relativePath);
|
|
249
|
-
const mappingsPath = join(userDataPath, 'custom-mappings.yml');
|
|
250
|
-
|
|
251
|
-
// Ensure directories exist
|
|
252
|
-
await mkdir(dirname(guidelinePath), { recursive: true });
|
|
253
|
-
|
|
254
|
-
// Write guideline content
|
|
255
|
-
await writeFile(guidelinePath, content, 'utf-8');
|
|
256
|
-
|
|
257
|
-
// Update mappings
|
|
258
|
-
let mappings: Record<string, GuidelineMapping> = {};
|
|
259
|
-
try {
|
|
260
|
-
const mappingsContent = await readFile(mappingsPath, 'utf-8');
|
|
261
|
-
mappings = YAML.parse(mappingsContent) as Record<string, GuidelineMapping>;
|
|
262
|
-
} catch {
|
|
263
|
-
// File doesn't exist yet, start with empty mappings
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
mappings[id] = {
|
|
267
|
-
path: relativePath,
|
|
268
|
-
category,
|
|
269
|
-
...(languages.length > 0 && { languages }),
|
|
270
|
-
levels,
|
|
271
|
-
...(architectures.length > 0 && { architectures }),
|
|
272
|
-
...(tags.length > 0 && { tags })
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
await writeFile(mappingsPath, YAML.stringify(mappings), 'utf-8');
|
|
276
|
-
|
|
277
|
-
console.log(chalk.green('\n✅ Guideline added successfully!'));
|
|
278
|
-
console.log(chalk.gray(`\n Guideline: ${guidelinePath}`));
|
|
279
|
-
console.log(chalk.gray(` Mapping: ${mappingsPath}`));
|
|
280
|
-
console.log(chalk.cyan(`\n Run ${chalk.white('aicgen init')} to use your custom guideline`));
|
|
281
|
-
|
|
282
|
-
} catch (error) {
|
|
283
|
-
if ((error as Error).message.includes('User force closed')) {
|
|
284
|
-
console.log(chalk.gray('\n\nCancelled.'));
|
|
285
|
-
return;
|
|
286
|
-
}
|
|
287
|
-
console.error(chalk.red(`\n❌ ${(error as Error).message}`));
|
|
288
|
-
process.exit(1);
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function generateGuidelineId(category: string, name: string): string {
|
|
293
|
-
const categorySlug = category.toLowerCase().replace(/\s+/g, '-');
|
|
294
|
-
const nameSlug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-');
|
|
295
|
-
return `custom-${categorySlug}-${nameSlug}`;
|
|
296
|
-
}
|
package/src/commands/clear.ts
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { confirm } from '@inquirer/prompts';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import { rm } from 'fs/promises';
|
|
4
|
-
import { join } from 'path';
|
|
5
|
-
import { existsSync } from 'fs';
|
|
6
|
-
|
|
7
|
-
export async function clearCommand(options: { force?: boolean } = {}) {
|
|
8
|
-
const projectPath = process.cwd();
|
|
9
|
-
|
|
10
|
-
// Define all possible config directories
|
|
11
|
-
const configDirs = [
|
|
12
|
-
{ path: '.claude', name: 'Claude Code' },
|
|
13
|
-
{ path: '.github/copilot-instructions.md', name: 'GitHub Copilot', isFile: true },
|
|
14
|
-
{ path: '.gemini', name: 'Google Gemini' },
|
|
15
|
-
{ path: '.agent', name: 'Google Antigravity' },
|
|
16
|
-
{ path: '.codex', name: 'Codex' },
|
|
17
|
-
{ path: 'AGENTS.md', name: 'Universal AGENTS.md', isFile: true }
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
// Find which configs exist
|
|
21
|
-
const existingConfigs = configDirs.filter(dir =>
|
|
22
|
-
existsSync(join(projectPath, dir.path))
|
|
23
|
-
);
|
|
24
|
-
|
|
25
|
-
if (existingConfigs.length === 0) {
|
|
26
|
-
console.log(chalk.gray('\nNo AI configurations found in this project.'));
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
console.log(chalk.cyan('\n📂 Found AI Configurations:'));
|
|
31
|
-
existingConfigs.forEach(config => {
|
|
32
|
-
console.log(` • ${config.name} (${config.path})`);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
if (!options.force) {
|
|
36
|
-
const shouldDelete = await confirm({
|
|
37
|
-
message: chalk.yellow('\n⚠️ Delete all AI configurations?'),
|
|
38
|
-
default: false
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
if (!shouldDelete) {
|
|
42
|
-
console.log(chalk.gray('\nCancelled.'));
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Delete configs
|
|
48
|
-
let deletedCount = 0;
|
|
49
|
-
for (const config of existingConfigs) {
|
|
50
|
-
try {
|
|
51
|
-
const fullPath = join(projectPath, config.path);
|
|
52
|
-
await rm(fullPath, { recursive: true, force: true });
|
|
53
|
-
console.log(chalk.green(`✓ Removed ${config.name}`));
|
|
54
|
-
deletedCount++;
|
|
55
|
-
} catch (error) {
|
|
56
|
-
console.log(chalk.red(`✗ Failed to remove ${config.name}: ${error}`));
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
console.log(chalk.green(`\n✅ Cleared ${deletedCount} configuration(s)`));
|
|
61
|
-
}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
import { checkbox } from '@inquirer/prompts';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import { Language } from '../models/project.js';
|
|
4
|
-
import { InstructionLevel, ArchitectureType, DatasourceType } from '../models/profile.js';
|
|
5
|
-
import { GuidelineLoader } from '../services/guideline-loader.js';
|
|
6
|
-
import { showCheckboxInstructions } from '../utils/banner.js';
|
|
7
|
-
import { BACK_VALUE } from '../utils/wizard-state.js';
|
|
8
|
-
|
|
9
|
-
interface CheckboxChoice {
|
|
10
|
-
name: string;
|
|
11
|
-
value: string;
|
|
12
|
-
checked?: boolean;
|
|
13
|
-
disabled?: boolean | string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export async function selectGuidelines(
|
|
17
|
-
language: Language,
|
|
18
|
-
level: InstructionLevel,
|
|
19
|
-
architecture: ArchitectureType,
|
|
20
|
-
canGoBack: boolean,
|
|
21
|
-
datasource?: DatasourceType
|
|
22
|
-
): Promise<string[] | typeof BACK_VALUE> {
|
|
23
|
-
const loader = await GuidelineLoader.create();
|
|
24
|
-
const categoryTree = loader.getCategoryTree(language, level, architecture, datasource);
|
|
25
|
-
|
|
26
|
-
console.log(chalk.cyan('\n📚 Select Guidelines'));
|
|
27
|
-
showCheckboxInstructions();
|
|
28
|
-
|
|
29
|
-
const allGuidelineIds: string[] = [];
|
|
30
|
-
const categoryToGuidelines = new Map<string, string[]>();
|
|
31
|
-
const choices: CheckboxChoice[] = [];
|
|
32
|
-
|
|
33
|
-
// Add back option if applicable
|
|
34
|
-
if (canGoBack) {
|
|
35
|
-
choices.push({
|
|
36
|
-
name: chalk.gray('← Back to previous step'),
|
|
37
|
-
value: BACK_VALUE,
|
|
38
|
-
checked: false
|
|
39
|
-
});
|
|
40
|
-
choices.push({
|
|
41
|
-
name: chalk.gray('─'.repeat(50)),
|
|
42
|
-
value: '__SEPARATOR__',
|
|
43
|
-
disabled: true
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// Build choices with categories and guidelines
|
|
48
|
-
for (const category of categoryTree) {
|
|
49
|
-
const categoryKey = `category:${category.name}`;
|
|
50
|
-
const guidelineIds: string[] = [];
|
|
51
|
-
|
|
52
|
-
// Category header
|
|
53
|
-
choices.push({
|
|
54
|
-
name: chalk.bold.cyan(`${category.name} (${category.count} guidelines)`),
|
|
55
|
-
value: categoryKey,
|
|
56
|
-
checked: true
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
// Guidelines under category
|
|
60
|
-
for (const guideline of category.guidelines) {
|
|
61
|
-
allGuidelineIds.push(guideline.id);
|
|
62
|
-
guidelineIds.push(guideline.id);
|
|
63
|
-
choices.push({
|
|
64
|
-
name: ` ${guideline.name}`,
|
|
65
|
-
value: guideline.id,
|
|
66
|
-
checked: true
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
categoryToGuidelines.set(categoryKey, guidelineIds);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
let selected = await checkbox({
|
|
74
|
-
message: 'Select guidelines to include (Space to toggle, Enter to confirm):',
|
|
75
|
-
choices,
|
|
76
|
-
pageSize: 25,
|
|
77
|
-
loop: false
|
|
78
|
-
}) as string[];
|
|
79
|
-
|
|
80
|
-
// Handle back selection
|
|
81
|
-
if (selected.includes(BACK_VALUE)) {
|
|
82
|
-
return BACK_VALUE;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Filter out separator
|
|
86
|
-
selected = selected.filter(s => s !== '__SEPARATOR__');
|
|
87
|
-
|
|
88
|
-
// Smart category-child sync
|
|
89
|
-
const categories = Array.from(categoryToGuidelines.keys());
|
|
90
|
-
const selectedCategories = selected.filter(s => s.startsWith('category:'));
|
|
91
|
-
const selectedGuidelines = selected.filter(s => !s.startsWith('category:'));
|
|
92
|
-
|
|
93
|
-
const finalGuidelines = new Set<string>();
|
|
94
|
-
|
|
95
|
-
for (const category of categories) {
|
|
96
|
-
const guidelinesInCategory = categoryToGuidelines.get(category) || [];
|
|
97
|
-
const isCategorySelected = selectedCategories.includes(category);
|
|
98
|
-
|
|
99
|
-
if (isCategorySelected) {
|
|
100
|
-
// Category is checked → include ALL guidelines in that category
|
|
101
|
-
guidelinesInCategory.forEach(g => finalGuidelines.add(g));
|
|
102
|
-
} else {
|
|
103
|
-
// Category is NOT checked → include only individually selected guidelines
|
|
104
|
-
guidelinesInCategory.forEach(g => {
|
|
105
|
-
if (selectedGuidelines.includes(g)) {
|
|
106
|
-
finalGuidelines.add(g);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const result = Array.from(finalGuidelines);
|
|
113
|
-
|
|
114
|
-
if (result.length === 0) {
|
|
115
|
-
console.log(chalk.yellow('\n⚠️ No guidelines selected. Using all available guidelines.'));
|
|
116
|
-
return allGuidelineIds;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Show selection summary
|
|
120
|
-
console.log(chalk.cyan(`\n✓ Selected ${result.length} of ${allGuidelineIds.length} guidelines`));
|
|
121
|
-
|
|
122
|
-
return result;
|
|
123
|
-
}
|