feature-architect-agent 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 (49) hide show
  1. package/README.md +704 -0
  2. package/bin/feature-architect.js +2 -0
  3. package/dist/cli/index.d.ts +3 -0
  4. package/dist/cli/index.d.ts.map +1 -0
  5. package/dist/cli/index.js +63 -0
  6. package/dist/commands/init.d.ts +2 -0
  7. package/dist/commands/init.d.ts.map +1 -0
  8. package/dist/commands/init.js +125 -0
  9. package/dist/commands/plan.d.ts +6 -0
  10. package/dist/commands/plan.d.ts.map +1 -0
  11. package/dist/commands/plan.js +147 -0
  12. package/dist/commands/verify.d.ts +2 -0
  13. package/dist/commands/verify.d.ts.map +1 -0
  14. package/dist/commands/verify.js +101 -0
  15. package/dist/config/api.config.d.ts +49 -0
  16. package/dist/config/api.config.d.ts.map +1 -0
  17. package/dist/config/api.config.js +78 -0
  18. package/dist/llm/Claude.d.ts +8 -0
  19. package/dist/llm/Claude.d.ts.map +1 -0
  20. package/dist/llm/Claude.js +44 -0
  21. package/dist/llm/OpenAI.d.ts +8 -0
  22. package/dist/llm/OpenAI.d.ts.map +1 -0
  23. package/dist/llm/OpenAI.js +43 -0
  24. package/dist/llm/factory.d.ts +9 -0
  25. package/dist/llm/factory.d.ts.map +1 -0
  26. package/dist/llm/factory.js +36 -0
  27. package/dist/llm/types.d.ts +8 -0
  28. package/dist/llm/types.d.ts.map +1 -0
  29. package/dist/llm/types.js +2 -0
  30. package/dist/services/Analyzer.d.ts +18 -0
  31. package/dist/services/Analyzer.d.ts.map +1 -0
  32. package/dist/services/Analyzer.js +235 -0
  33. package/dist/services/ContextManager.d.ts +16 -0
  34. package/dist/services/ContextManager.d.ts.map +1 -0
  35. package/dist/services/ContextManager.js +82 -0
  36. package/dist/services/Planner.d.ts +16 -0
  37. package/dist/services/Planner.d.ts.map +1 -0
  38. package/dist/services/Planner.js +181 -0
  39. package/dist/services/Scanner.d.ts +17 -0
  40. package/dist/services/Scanner.d.ts.map +1 -0
  41. package/dist/services/Scanner.js +75 -0
  42. package/dist/types/index.d.ts +90 -0
  43. package/dist/types/index.d.ts.map +1 -0
  44. package/dist/types/index.js +3 -0
  45. package/dist/utils/logger.d.ts +22 -0
  46. package/dist/utils/logger.d.ts.map +1 -0
  47. package/dist/utils/logger.js +56 -0
  48. package/package.json +48 -0
  49. package/src/config/api.config.ts +79 -0
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const commander_1 = require("commander");
5
+ const init_js_1 = require("../commands/init.js");
6
+ const plan_js_1 = require("../commands/plan.js");
7
+ const verify_js_1 = require("../commands/verify.js");
8
+ const logger_js_1 = require("../utils/logger.js");
9
+ const program = new commander_1.Command();
10
+ program
11
+ .name('feature-architect')
12
+ .description('AI-powered feature planning agent - generate complete technical specifications')
13
+ .version('1.0.0');
14
+ program
15
+ .command('init')
16
+ .description('Initialize in project (analyze codebase)')
17
+ .option('-f, --force', 'Re-initialize even if already initialized')
18
+ .action(async (options) => {
19
+ try {
20
+ await (0, init_js_1.initCommand)(options.force);
21
+ }
22
+ catch (err) {
23
+ console.error(err instanceof Error ? err.message : String(err));
24
+ process.exit(1);
25
+ }
26
+ });
27
+ program
28
+ .command('plan <feature>')
29
+ .description('Plan a new feature')
30
+ .option('-p, --provider <provider>', 'AI provider (claude, openai)', 'claude')
31
+ .option('-o, --output <path>', 'Output file path')
32
+ .option('--no-diagrams', 'Skip diagram generation')
33
+ .action(async (feature, options) => {
34
+ try {
35
+ await (0, plan_js_1.planCommand)(feature, options);
36
+ }
37
+ catch (err) {
38
+ console.error(err instanceof Error ? err.message : String(err));
39
+ process.exit(1);
40
+ }
41
+ });
42
+ program
43
+ .command('verify')
44
+ .description('Verify setup and configuration')
45
+ .action(async () => {
46
+ try {
47
+ await (0, verify_js_1.verifyCommand)();
48
+ }
49
+ catch (err) {
50
+ process.exit(1);
51
+ }
52
+ });
53
+ // Default: show help if no command
54
+ program.on('command:*', () => {
55
+ (0, logger_js_1.header)('Feature Architect Agent v1.0.0');
56
+ (0, logger_js_1.info)('AI-powered feature planning for development teams\n');
57
+ (0, logger_js_1.dim)('Quick start:');
58
+ (0, logger_js_1.dim)(' 1. feature-architect init # Analyze codebase');
59
+ (0, logger_js_1.dim)(' 2. export ANTHROPIC_API_KEY=xxx # Set API key');
60
+ (0, logger_js_1.dim)(' 3. feature-architect plan "feature" # Plan feature');
61
+ console.log('');
62
+ });
63
+ program.parse();
@@ -0,0 +1,2 @@
1
+ export declare function initCommand(force?: boolean): Promise<void>;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAOA,wBAAsB,WAAW,CAAC,KAAK,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA+EvE"}
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.initCommand = initCommand;
7
+ const path_1 = __importDefault(require("path"));
8
+ const Scanner_js_1 = require("../services/Scanner.js");
9
+ const Analyzer_js_1 = require("../services/Analyzer.js");
10
+ const ContextManager_js_1 = require("../services/ContextManager.js");
11
+ const logger_js_1 = require("../utils/logger.js");
12
+ async function initCommand(force = false) {
13
+ (0, logger_js_1.header)('🔍 Feature Architect Agent - Initialization');
14
+ const contextManager = new ContextManager_js_1.ContextManager();
15
+ // Check if already initialized
16
+ if (!force && await contextManager.contextExists()) {
17
+ const context = await contextManager.loadContext();
18
+ (0, logger_js_1.info)(`Already initialized on ${context?.metadata.analyzedAt}`);
19
+ (0, logger_js_1.info)('Use --force to re-initialize');
20
+ return;
21
+ }
22
+ // Scan codebase
23
+ (0, logger_js_1.info)('Scanning codebase...');
24
+ const scanner = new Scanner_js_1.ScannerService();
25
+ const { files, stats } = await scanner.scanWithStats();
26
+ (0, logger_js_1.bullet)(`Found ${stats.total} files`);
27
+ for (const [lang, count] of Object.entries(stats.byLanguage)) {
28
+ (0, logger_js_1.bullet)(` ${lang}: ${count} files`, 1);
29
+ }
30
+ // Analyze patterns
31
+ (0, logger_js_1.info)('\nAnalyzing patterns...');
32
+ const analyzer = new Analyzer_js_1.AnalyzerService();
33
+ const patterns = await analyzer.analyze(files);
34
+ (0, logger_js_1.bullet)(`API Routes: ${patterns.apiRoutes.length}`);
35
+ (0, logger_js_1.bullet)(`Database Tables: ${patterns.databaseSchemas.length}`);
36
+ (0, logger_js_1.bullet)(`Components: ${patterns.components.length}`);
37
+ (0, logger_js_1.bullet)(`Type Definitions: ${patterns.types.length}`);
38
+ // Detect frameworks
39
+ const frameworks = detectFrameworks(patterns);
40
+ // Build context
41
+ (0, logger_js_1.info)('\nBuilding context...');
42
+ const projectName = path_1.default.basename(process.cwd());
43
+ const projectType = detectProjectType(files, patterns);
44
+ const context = {
45
+ project: {
46
+ name: projectName,
47
+ type: projectType,
48
+ root: process.cwd()
49
+ },
50
+ summary: {
51
+ totalFiles: stats.total,
52
+ languages: stats.byLanguage,
53
+ frameworks: Object.values(frameworks).filter(Boolean),
54
+ patterns: patterns.apiRoutes.length +
55
+ patterns.databaseSchemas.length +
56
+ patterns.components.length +
57
+ patterns.types.length
58
+ },
59
+ frameworks: frameworks,
60
+ patterns: patterns,
61
+ metadata: {
62
+ version: '1.0.0',
63
+ analyzedAt: new Date().toISOString(),
64
+ hash: ''
65
+ }
66
+ };
67
+ // Save context
68
+ await contextManager.saveContext(context);
69
+ (0, logger_js_1.success)('\n✅ Initialization complete!');
70
+ (0, logger_js_1.info)(`Project: ${projectName}`);
71
+ (0, logger_js_1.info)(`Type: ${projectType}`);
72
+ (0, logger_js_1.info)(`Frameworks: ${context.summary.frameworks.join(', ') || 'Unknown'}`);
73
+ (0, logger_js_1.info)(`Patterns indexed: ${context.summary.patterns}`);
74
+ const contextPath = await contextManager.getContextPath();
75
+ (0, logger_js_1.dim)(`\nContext saved to: ${contextPath}`);
76
+ (0, logger_js_1.info)('\nYou can now plan features:');
77
+ (0, logger_js_1.info)(' feature-architect plan "your feature here"');
78
+ }
79
+ function detectProjectType(files, patterns) {
80
+ const hasTS = files.some(f => f.endsWith('.ts') || f.endsWith('.tsx'));
81
+ const hasReact = patterns.components.some((c) => c.type === 'Component');
82
+ const hasNext = files.some(f => f.includes('next.config.') || f.includes('/pages/') || f.includes('/app/'));
83
+ if (hasNext && hasTS)
84
+ return 'Next.js + TypeScript';
85
+ if (hasReact && hasTS)
86
+ return 'React + TypeScript';
87
+ if (hasTS)
88
+ return 'TypeScript';
89
+ return 'JavaScript';
90
+ }
91
+ function detectFrameworks(patterns) {
92
+ const frameworks = {};
93
+ // Detect API framework
94
+ if (patterns.apiRoutes.length > 0) {
95
+ const hasExpress = patterns.apiRoutes.some((r) => r.path.includes(':'));
96
+ if (hasExpress) {
97
+ frameworks.backend = 'Express.js';
98
+ }
99
+ else {
100
+ frameworks.backend = 'REST API';
101
+ }
102
+ }
103
+ // Detect frontend framework
104
+ if (patterns.components.length > 0) {
105
+ const hasPages = patterns.components.some((c) => c.file.includes('/pages/'));
106
+ if (hasPages) {
107
+ frameworks.frontend = 'Next.js';
108
+ }
109
+ else {
110
+ frameworks.frontend = 'React';
111
+ }
112
+ }
113
+ // Detect database
114
+ if (patterns.databaseSchemas.length > 0) {
115
+ const hasPrisma = patterns.databaseSchemas.some((s) => s.file.includes('.prisma'));
116
+ if (hasPrisma) {
117
+ frameworks.orm = 'Prisma';
118
+ frameworks.database = 'PostgreSQL';
119
+ }
120
+ else {
121
+ frameworks.database = 'SQL';
122
+ }
123
+ }
124
+ return frameworks;
125
+ }
@@ -0,0 +1,6 @@
1
+ export declare function planCommand(feature: string, options?: {
2
+ provider?: string;
3
+ output?: string;
4
+ noDiagrams?: boolean;
5
+ }): Promise<void>;
6
+ //# sourceMappingURL=plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../src/commands/plan.ts"],"names":[],"mappings":"AAQA,wBAAsB,WAAW,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,GAAE;IACP,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACjB,GACL,OAAO,CAAC,IAAI,CAAC,CAiJf"}
@@ -0,0 +1,147 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.planCommand = planCommand;
7
+ const path_1 = __importDefault(require("path"));
8
+ const promises_1 = __importDefault(require("fs/promises"));
9
+ const ContextManager_js_1 = require("../services/ContextManager.js");
10
+ const Planner_js_1 = require("../services/Planner.js");
11
+ const factory_js_1 = require("../llm/factory.js");
12
+ const logger_js_1 = require("../utils/logger.js");
13
+ const api_config_js_1 = require("../config/api.config.js");
14
+ async function planCommand(feature, options = {}) {
15
+ (0, logger_js_1.header)('🧠 Feature Architect Agent - Plan Feature');
16
+ if (!feature) {
17
+ (0, logger_js_1.error)('Please provide a feature description');
18
+ (0, logger_js_1.info)('Usage: feature-architect plan "your feature description"');
19
+ return;
20
+ }
21
+ // Load context
22
+ const contextManager = new ContextManager_js_1.ContextManager();
23
+ if (!(await contextManager.contextExists())) {
24
+ (0, logger_js_1.error)('Not initialized. Run: feature-architect init');
25
+ return;
26
+ }
27
+ const context = await contextManager.loadContext();
28
+ if (!context) {
29
+ (0, logger_js_1.error)('Failed to load context');
30
+ return;
31
+ }
32
+ (0, logger_js_1.info)(`Feature: ${feature}`);
33
+ (0, logger_js_1.info)(`Project: ${context.project.name}`);
34
+ (0, logger_js_1.info)(`Frameworks: ${context.summary.frameworks.join(', ') || 'Unknown'}`);
35
+ // Auto-detect provider and API key
36
+ let provider = options.provider;
37
+ let apiKey;
38
+ let usingBuiltinKey = false;
39
+ // Auto-detect if not specified
40
+ if (!provider) {
41
+ // Check user environment variables first
42
+ if (process.env.ANTHROPIC_API_KEY) {
43
+ provider = 'anthropic';
44
+ apiKey = process.env.ANTHROPIC_API_KEY;
45
+ }
46
+ else if (process.env.OPENAI_API_KEY) {
47
+ provider = 'openai';
48
+ apiKey = process.env.OPENAI_API_KEY;
49
+ }
50
+ else if (process.env.GOOGLE_API_KEY) {
51
+ provider = 'google';
52
+ apiKey = process.env.GOOGLE_API_KEY;
53
+ }
54
+ else if (process.env.AI_API_KEY) {
55
+ // Generic API key - try OpenAI first (default built-in)
56
+ provider = 'openai';
57
+ apiKey = process.env.AI_API_KEY;
58
+ }
59
+ else {
60
+ // Fall back to built-in team API key
61
+ const builtinOpenAIKey = (0, api_config_js_1.getBuiltinKey)('openai');
62
+ if (builtinOpenAIKey && builtinOpenAIKey !== 'sk-your-team-openai-key-here') {
63
+ provider = 'openai';
64
+ apiKey = builtinOpenAIKey;
65
+ usingBuiltinKey = true;
66
+ }
67
+ else {
68
+ (0, logger_js_1.error)('No API key found');
69
+ (0, logger_js_1.dim)('Set any of these environment variables:');
70
+ (0, logger_js_1.dim)(' export ANTHROPIC_API_KEY=sk-ant-xxx # For Claude');
71
+ (0, logger_js_1.dim)(' export OPENAI_API_KEY=sk-xxx # For OpenAI');
72
+ (0, logger_js_1.dim)(' export GOOGLE_API_KEY=xxx # For Gemini');
73
+ (0, logger_js_1.dim)(' export AI_API_KEY=xxx # Generic');
74
+ (0, logger_js_1.dim)('\nOr contact your team admin to set up the built-in API key.');
75
+ return;
76
+ }
77
+ }
78
+ }
79
+ else {
80
+ // Use specified provider
81
+ const providerLower = provider.toLowerCase();
82
+ if (providerLower === 'claude' || providerLower === 'anthropic') {
83
+ provider = 'anthropic';
84
+ apiKey = (0, api_config_js_1.getApiKey)('anthropic');
85
+ }
86
+ else if (providerLower === 'openai') {
87
+ provider = 'openai';
88
+ apiKey = (0, api_config_js_1.getApiKey)('openai');
89
+ }
90
+ else if (providerLower === 'gemini' || providerLower === 'google') {
91
+ provider = 'google';
92
+ apiKey = (0, api_config_js_1.getApiKey)('google');
93
+ }
94
+ if (!apiKey) {
95
+ (0, logger_js_1.error)(`No API key found for ${provider}`);
96
+ (0, logger_js_1.dim)(`Set it with: export ${provider.toUpperCase()}_API_KEY=xxx`);
97
+ return;
98
+ }
99
+ // Check if using built-in key
100
+ const builtinKey = (0, api_config_js_1.getBuiltinKey)(provider);
101
+ if (builtinKey === apiKey && !process.env[`${provider.toUpperCase()}_API_KEY`]) {
102
+ usingBuiltinKey = true;
103
+ }
104
+ }
105
+ // Create AI provider
106
+ (0, logger_js_1.info)(`\nUsing AI: ${provider}${usingBuiltinKey ? ' (built-in team key)' : ''}...`);
107
+ const llm = (0, factory_js_1.createProvider)({
108
+ provider: provider,
109
+ apiKey
110
+ });
111
+ const planner = new Planner_js_1.PlannerService(llm);
112
+ // Generate plan
113
+ (0, logger_js_1.info)('Generating feature plan...\n');
114
+ try {
115
+ const plan = await planner.planFeature(feature, context, {
116
+ output: options.output,
117
+ includeDiagrams: !options.noDiagrams
118
+ });
119
+ // Ensure output directory exists
120
+ const slug = plan.slug;
121
+ const outputFile = options.output || path_1.default.join('docs', 'features', `${slug}.md`);
122
+ await promises_1.default.mkdir(path_1.default.dirname(outputFile), { recursive: true });
123
+ await promises_1.default.writeFile(outputFile, plan.markdown, 'utf-8');
124
+ (0, logger_js_1.success)('✅ Feature plan generated!');
125
+ (0, logger_js_1.info)(`Saved to: ${outputFile}`);
126
+ // Show preview
127
+ const lines = plan.markdown.split('\n');
128
+ const preview = lines.slice(0, 20).join('\n');
129
+ (0, logger_js_1.dim)('\n--- Preview (first 20 lines) ---\n');
130
+ console.log(preview);
131
+ if (lines.length > 20) {
132
+ (0, logger_js_1.dim)('\n... (truncated)');
133
+ }
134
+ (0, logger_js_1.info)('\n📖 Next steps:');
135
+ (0, logger_js_1.bullet)('Review the generated plan');
136
+ (0, logger_js_1.bullet)('Use it with your AI tool:');
137
+ (0, logger_js_1.dim)(` claude "Implement this feature" < ${outputFile}`);
138
+ (0, logger_js_1.dim)(` # Or paste into ChatGPT/Cursor/Copilot`);
139
+ }
140
+ catch (err) {
141
+ (0, logger_js_1.error)(`Failed to generate plan: ${err instanceof Error ? err.message : String(err)}`);
142
+ (0, logger_js_1.warn)('\nTroubleshooting:');
143
+ (0, logger_js_1.bullet)('Check your API key is set correctly');
144
+ (0, logger_js_1.bullet)('Ensure you have network connectivity');
145
+ (0, logger_js_1.bullet)('Try a shorter feature description');
146
+ }
147
+ }
@@ -0,0 +1,2 @@
1
+ export declare function verifyCommand(): Promise<void>;
2
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/commands/verify.ts"],"names":[],"mappings":"AAKA,wBAAsB,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC,CA0FnD"}
@@ -0,0 +1,101 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.verifyCommand = verifyCommand;
7
+ const path_1 = __importDefault(require("path"));
8
+ const ContextManager_js_1 = require("../services/ContextManager.js");
9
+ const logger_js_1 = require("../utils/logger.js");
10
+ const api_config_js_1 = require("../config/api.config.js");
11
+ async function verifyCommand() {
12
+ (0, logger_js_1.header)('🔍 Feature Architect Agent - Verification');
13
+ const contextManager = new ContextManager_js_1.ContextManager();
14
+ let allGood = true;
15
+ // Check 1: Context exists
16
+ (0, logger_js_1.info)('Configuration:');
17
+ if (await contextManager.contextExists()) {
18
+ const context = await contextManager.loadContext();
19
+ (0, logger_js_1.check)(`Context file found`);
20
+ (0, logger_js_1.bullet)(`Project: ${context?.project.name}`, 1);
21
+ (0, logger_js_1.bullet)(`Type: ${context?.project.type}`, 1);
22
+ (0, logger_js_1.bullet)(`Initialized: ${context?.metadata.analyzedAt}`, 1);
23
+ }
24
+ else {
25
+ (0, logger_js_1.error)('✗ Context file not found');
26
+ (0, logger_js_1.bullet)('Run: feature-architect init', 1);
27
+ allGood = false;
28
+ }
29
+ // Check 2: API key
30
+ (0, logger_js_1.info)('\nAI Provider:');
31
+ // Check for user API keys
32
+ const keysFound = [];
33
+ if (process.env.ANTHROPIC_API_KEY)
34
+ keysFound.push('Claude (ANTHROPIC_API_KEY)');
35
+ if (process.env.OPENAI_API_KEY)
36
+ keysFound.push('OpenAI (OPENAI_API_KEY)');
37
+ if (process.env.GOOGLE_API_KEY)
38
+ keysFound.push('Gemini (GOOGLE_API_KEY)');
39
+ if (process.env.AI_API_KEY)
40
+ keysFound.push('Generic (AI_API_KEY)');
41
+ // Check for built-in team keys
42
+ const builtinOpenAIKey = (0, api_config_js_1.getBuiltinKey)('openai');
43
+ const builtinAnthropicKey = (0, api_config_js_1.getBuiltinKey)('anthropic');
44
+ const builtinGoogleKey = (0, api_config_js_1.getBuiltinKey)('google');
45
+ if (builtinOpenAIKey && builtinOpenAIKey !== 'sk-your-team-openai-key-here') {
46
+ keysFound.push('OpenAI (built-in team key) ✓');
47
+ }
48
+ if (builtinAnthropicKey) {
49
+ keysFound.push('Claude (built-in team key) ✓');
50
+ }
51
+ if (builtinGoogleKey) {
52
+ keysFound.push('Gemini (built-in team key) ✓');
53
+ }
54
+ if (keysFound.length > 0) {
55
+ (0, logger_js_1.check)('API keys found:');
56
+ keysFound.forEach(key => (0, logger_js_1.bullet)(key, 1));
57
+ // Show which will be used
58
+ let defaultProvider = 'openai'; // Default to OpenAI (built-in)
59
+ if (process.env.ANTHROPIC_API_KEY)
60
+ defaultProvider = 'anthropic';
61
+ else if (process.env.OPENAI_API_KEY)
62
+ defaultProvider = 'openai';
63
+ else if (process.env.GOOGLE_API_KEY)
64
+ defaultProvider = 'google';
65
+ else if (builtinOpenAIKey && builtinOpenAIKey !== 'sk-your-team-openai-key-here')
66
+ defaultProvider = 'openai (built-in)';
67
+ (0, logger_js_1.bullet)(`Default provider: ${defaultProvider}`, 1);
68
+ }
69
+ else {
70
+ (0, logger_js_1.error)('✗ No API key found');
71
+ (0, logger_js_1.bullet)('Set any API key:', 1);
72
+ (0, logger_js_1.bullet)('export ANTHROPIC_API_KEY=sk-ant-xxx # Claude', 2);
73
+ (0, logger_js_1.bullet)('export OPENAI_API_KEY=sk-xxx # OpenAI', 2);
74
+ (0, logger_js_1.bullet)('export GOOGLE_API_KEY=xxx # Gemini', 2);
75
+ (0, logger_js_1.bullet)('export AI_API_KEY=xxx # Generic', 2);
76
+ (0, logger_js_1.bullet)('\nOr contact your team admin to set up built-in keys.', 2);
77
+ allGood = false;
78
+ }
79
+ // Check 3: Output directory
80
+ (0, logger_js_1.info)('\nOutput:');
81
+ const docsDir = path_1.default.join(process.cwd(), 'docs', 'features');
82
+ try {
83
+ const { opendir } = await import('fs/promises');
84
+ await opendir(docsDir);
85
+ (0, logger_js_1.check)(`Output directory exists: ${docsDir}`);
86
+ }
87
+ catch {
88
+ (0, logger_js_1.dim)(`Output directory will be created: ${docsDir}`);
89
+ }
90
+ // Summary
91
+ if (allGood) {
92
+ (0, logger_js_1.success)('\n✅ All checks passed!');
93
+ (0, logger_js_1.info)('You can now plan features:');
94
+ (0, logger_js_1.dim)(' feature-architect plan "your feature here"\n');
95
+ }
96
+ else {
97
+ (0, logger_js_1.error)('\n❌ Some checks failed');
98
+ (0, logger_js_1.info)('Fix the issues above before planning features.\n');
99
+ }
100
+ return allGood ? Promise.resolve() : Promise.reject(new Error('Verification failed'));
101
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Built-in API Configuration for Internal Team Use
3
+ *
4
+ * This file contains the pre-configured API key for team use.
5
+ * The package is published to a private registry for internal team access.
6
+ *
7
+ * SECURITY: This file is included in the published package.
8
+ * Only publish to PRIVATE npm registries (GitHub Packages, npm private, etc.)
9
+ */
10
+ export declare const API_CONFIG: {
11
+ /**
12
+ * Built-in OpenAI API Key for team use
13
+ * Replace with your actual team API key
14
+ */
15
+ openai: {
16
+ apiKey: string;
17
+ baseURL: string;
18
+ };
19
+ /**
20
+ * Built-in Anthropic API Key (optional)
21
+ */
22
+ anthropic: {
23
+ apiKey: string;
24
+ baseURL: string;
25
+ };
26
+ /**
27
+ * Built-in Google API Key (optional)
28
+ */
29
+ google: {
30
+ apiKey: string;
31
+ };
32
+ /**
33
+ * Default provider to use when no user key is set
34
+ */
35
+ defaultProvider: "openai";
36
+ };
37
+ /**
38
+ * Get the built-in API key for a provider
39
+ */
40
+ export declare function getBuiltinKey(provider: 'openai' | 'anthropic' | 'google'): string | undefined;
41
+ /**
42
+ * Check if a built-in key is available
43
+ */
44
+ export declare function hasBuiltinKey(provider: 'openai' | 'anthropic' | 'google'): boolean;
45
+ /**
46
+ * Get the best available API key (user env var first, then built-in)
47
+ */
48
+ export declare function getApiKey(provider: 'openai' | 'anthropic' | 'google'): string | undefined;
49
+ //# sourceMappingURL=api.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.config.d.ts","sourceRoot":"","sources":["../../src/config/api.config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,UAAU;IACrB;;;OAGG;;;;;IAMH;;OAEG;;;;;IAMH;;OAEG;;;;IAKH;;OAEG;;CAEJ,CAAC;AAEF;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAW7F;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,CAGlF;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,QAAQ,GAAG,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAUzF"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ /**
3
+ * Built-in API Configuration for Internal Team Use
4
+ *
5
+ * This file contains the pre-configured API key for team use.
6
+ * The package is published to a private registry for internal team access.
7
+ *
8
+ * SECURITY: This file is included in the published package.
9
+ * Only publish to PRIVATE npm registries (GitHub Packages, npm private, etc.)
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.API_CONFIG = void 0;
13
+ exports.getBuiltinKey = getBuiltinKey;
14
+ exports.hasBuiltinKey = hasBuiltinKey;
15
+ exports.getApiKey = getApiKey;
16
+ exports.API_CONFIG = {
17
+ /**
18
+ * Built-in OpenAI API Key for team use
19
+ * Replace with your actual team API key
20
+ */
21
+ openai: {
22
+ apiKey: process.env.TEAM_OPENAI_API_KEY || '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',
23
+ baseURL: 'https://api.openai.com/v1',
24
+ },
25
+ /**
26
+ * Built-in Anthropic API Key (optional)
27
+ */
28
+ anthropic: {
29
+ apiKey: process.env.TEAM_ANTHROPIC_API_KEY || '',
30
+ baseURL: 'https://api.anthropic.com',
31
+ },
32
+ /**
33
+ * Built-in Google API Key (optional)
34
+ */
35
+ google: {
36
+ apiKey: process.env.TEAM_GOOGLE_API_KEY || '',
37
+ },
38
+ /**
39
+ * Default provider to use when no user key is set
40
+ */
41
+ defaultProvider: 'openai',
42
+ };
43
+ /**
44
+ * Get the built-in API key for a provider
45
+ */
46
+ function getBuiltinKey(provider) {
47
+ switch (provider) {
48
+ case 'openai':
49
+ return exports.API_CONFIG.openai.apiKey || undefined;
50
+ case 'anthropic':
51
+ return exports.API_CONFIG.anthropic.apiKey || undefined;
52
+ case 'google':
53
+ return exports.API_CONFIG.google.apiKey || undefined;
54
+ default:
55
+ return undefined;
56
+ }
57
+ }
58
+ /**
59
+ * Check if a built-in key is available
60
+ */
61
+ function hasBuiltinKey(provider) {
62
+ const key = getBuiltinKey(provider);
63
+ return !!key && key !== '' && !key.startsWith('sk-');
64
+ }
65
+ /**
66
+ * Get the best available API key (user env var first, then built-in)
67
+ */
68
+ function getApiKey(provider) {
69
+ // First check user's environment variable
70
+ const userKey = process.env[`${provider.toUpperCase()}_API_KEY`];
71
+ if (userKey)
72
+ return userKey;
73
+ // Then check generic AI_API_KEY
74
+ if (process.env.AI_API_KEY)
75
+ return process.env.AI_API_KEY;
76
+ // Finally fall back to built-in key
77
+ return getBuiltinKey(provider);
78
+ }
@@ -0,0 +1,8 @@
1
+ import type { LLMProvider, GenerateOptions } from './types.js';
2
+ export declare class ClaudeProvider implements LLMProvider {
3
+ private apiKey;
4
+ private model;
5
+ constructor(apiKey: string, model?: string);
6
+ generate(prompt: string, options?: GenerateOptions): Promise<string>;
7
+ }
8
+ //# sourceMappingURL=Claude.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Claude.d.ts","sourceRoot":"","sources":["../../src/llm/Claude.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE/D,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,MAAqC;IAKlE,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,MAAM,CAAC;CAqC/E"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ClaudeProvider = void 0;
4
+ class ClaudeProvider {
5
+ apiKey;
6
+ model;
7
+ constructor(apiKey, model = 'claude-3-5-sonnet-20241022') {
8
+ this.apiKey = apiKey;
9
+ this.model = model;
10
+ }
11
+ async generate(prompt, options = {}) {
12
+ const temperature = options.temperature ?? 0.7;
13
+ const maxTokens = options.maxTokens ?? 8000;
14
+ const response = await fetch('https://api.anthropic.com/v1/messages', {
15
+ method: 'POST',
16
+ headers: {
17
+ 'x-api-key': this.apiKey,
18
+ 'anthropic-version': '2023-06-01',
19
+ 'content-type': 'application/json'
20
+ },
21
+ body: JSON.stringify({
22
+ model: this.model,
23
+ max_tokens: maxTokens,
24
+ temperature,
25
+ messages: [
26
+ {
27
+ role: 'user',
28
+ content: prompt
29
+ }
30
+ ]
31
+ })
32
+ });
33
+ if (!response.ok) {
34
+ const error = await response.text();
35
+ throw new Error(`Claude API error: ${response.status} ${error}`);
36
+ }
37
+ const data = await response.json();
38
+ if (data.error) {
39
+ throw new Error(`Claude API error: ${data.error.message}`);
40
+ }
41
+ return data.content[0].text;
42
+ }
43
+ }
44
+ exports.ClaudeProvider = ClaudeProvider;
@@ -0,0 +1,8 @@
1
+ import type { LLMProvider, GenerateOptions } from './types.js';
2
+ export declare class OpenAIProvider implements LLMProvider {
3
+ private apiKey;
4
+ private model;
5
+ constructor(apiKey: string, model?: string);
6
+ generate(prompt: string, options?: GenerateOptions): Promise<string>;
7
+ }
8
+ //# sourceMappingURL=OpenAI.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OpenAI.d.ts","sourceRoot":"","sources":["../../src/llm/OpenAI.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE/D,qBAAa,cAAe,YAAW,WAAW;IAChD,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE,MAAM,EAAE,KAAK,GAAE,MAAsB;IAKnD,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,MAAM,CAAC;CAoC/E"}