claude-autopm 1.30.1 ā 2.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.
- package/autopm/.claude/mcp/test-server.md +10 -0
- package/autopm/.claude/scripts/github/dependency-tracker.js +554 -0
- package/autopm/.claude/scripts/github/dependency-validator.js +545 -0
- package/autopm/.claude/scripts/github/dependency-visualizer.js +477 -0
- package/autopm/.claude/scripts/pm/lib/epic-discovery.js +119 -0
- package/autopm/.claude/scripts/pm/next.js +56 -58
- package/bin/autopm-poc.js +348 -0
- package/bin/autopm.js +6 -0
- package/lib/ai-providers/AbstractAIProvider.js +524 -0
- package/lib/ai-providers/ClaudeProvider.js +423 -0
- package/lib/ai-providers/TemplateProvider.js +432 -0
- package/lib/cli/commands/agent.js +206 -0
- package/lib/cli/commands/config.js +488 -0
- package/lib/cli/commands/prd.js +345 -0
- package/lib/cli/commands/task.js +206 -0
- package/lib/config/ConfigManager.js +531 -0
- package/lib/errors/AIProviderError.js +164 -0
- package/lib/services/AgentService.js +557 -0
- package/lib/services/EpicService.js +609 -0
- package/lib/services/PRDService.js +1003 -0
- package/lib/services/TaskService.js +760 -0
- package/lib/services/interfaces.js +753 -0
- package/lib/utils/CircuitBreaker.js +165 -0
- package/lib/utils/Encryption.js +201 -0
- package/lib/utils/RateLimiter.js +241 -0
- package/lib/utils/ServiceFactory.js +165 -0
- package/package.json +9 -5
- package/scripts/config/get.js +108 -0
- package/scripts/config/init.js +100 -0
- package/scripts/config/list-providers.js +93 -0
- package/scripts/config/set-api-key.js +107 -0
- package/scripts/config/set-provider.js +201 -0
- package/scripts/config/set.js +139 -0
- package/scripts/config/show.js +181 -0
- package/autopm/.claude/.env +0 -158
- package/autopm/.claude/settings.local.json +0 -9
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Config command: set-provider
|
|
4
|
+
* Configure a provider with interactive prompts
|
|
5
|
+
*
|
|
6
|
+
* Usage: autopm config:set-provider [provider-name]
|
|
7
|
+
* Example: autopm config:set-provider claude
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const os = require('os');
|
|
12
|
+
const { input, number, select, confirm } = require('@inquirer/prompts');
|
|
13
|
+
const ConfigManager = require('../../lib/config/ConfigManager');
|
|
14
|
+
|
|
15
|
+
// Default config path
|
|
16
|
+
const DEFAULT_CONFIG_PATH = path.join(os.homedir(), '.autopm', 'config.json');
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Main function
|
|
20
|
+
*/
|
|
21
|
+
async function main() {
|
|
22
|
+
try {
|
|
23
|
+
const configPath = process.env.AUTOPM_CONFIG_PATH || DEFAULT_CONFIG_PATH;
|
|
24
|
+
|
|
25
|
+
// Check if config exists
|
|
26
|
+
const fs = require('fs');
|
|
27
|
+
if (!fs.existsSync(configPath)) {
|
|
28
|
+
console.error('\nError: Configuration not found');
|
|
29
|
+
console.error('Run: autopm config:init\n');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Load configuration
|
|
34
|
+
const manager = new ConfigManager(configPath);
|
|
35
|
+
|
|
36
|
+
console.log('\nš§ Provider Configuration');
|
|
37
|
+
console.log('========================\n');
|
|
38
|
+
|
|
39
|
+
// Get provider name from argument or prompt
|
|
40
|
+
let providerName = process.argv[2];
|
|
41
|
+
|
|
42
|
+
if (!providerName) {
|
|
43
|
+
providerName = await input({
|
|
44
|
+
message: 'Provider name:',
|
|
45
|
+
validate: (value) => {
|
|
46
|
+
if (!value || value.trim().length === 0) {
|
|
47
|
+
return 'Provider name is required';
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Get existing configuration (if any)
|
|
55
|
+
const existingConfig = manager.getProvider(providerName) || {};
|
|
56
|
+
|
|
57
|
+
// Prompt for model
|
|
58
|
+
const model = await input({
|
|
59
|
+
message: 'Model name:',
|
|
60
|
+
default: existingConfig.model || ''
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// Prompt for temperature
|
|
64
|
+
const temperature = await number({
|
|
65
|
+
message: 'Temperature (0-1):',
|
|
66
|
+
default: existingConfig.temperature !== undefined ? existingConfig.temperature : 0.7
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Validate temperature
|
|
70
|
+
if (temperature < 0 || temperature > 1) {
|
|
71
|
+
console.error('\nError: Temperature must be between 0 and 1');
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Prompt for maxTokens
|
|
76
|
+
const maxTokens = await number({
|
|
77
|
+
message: 'Max tokens:',
|
|
78
|
+
default: existingConfig.maxTokens || 4096
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Validate maxTokens
|
|
82
|
+
if (maxTokens <= 0) {
|
|
83
|
+
console.error('\nError: maxTokens must be positive');
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Build provider config
|
|
88
|
+
const providerConfig = {
|
|
89
|
+
model,
|
|
90
|
+
temperature,
|
|
91
|
+
maxTokens
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// Optional: Rate limiting
|
|
95
|
+
const configureRateLimit = await confirm({
|
|
96
|
+
message: 'Configure rate limiting?',
|
|
97
|
+
default: false
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if (configureRateLimit) {
|
|
101
|
+
const tokensPerInterval = await number({
|
|
102
|
+
message: 'Tokens per interval:',
|
|
103
|
+
default: existingConfig.rateLimit?.tokensPerInterval || 60
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const interval = await select({
|
|
107
|
+
message: 'Interval:',
|
|
108
|
+
choices: [
|
|
109
|
+
{ name: 'Second', value: 'second' },
|
|
110
|
+
{ name: 'Minute', value: 'minute' },
|
|
111
|
+
{ name: 'Hour', value: 'hour' }
|
|
112
|
+
],
|
|
113
|
+
default: existingConfig.rateLimit?.interval || 'minute'
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// Validate interval
|
|
117
|
+
const validIntervals = ['second', 'minute', 'hour'];
|
|
118
|
+
if (!validIntervals.includes(interval)) {
|
|
119
|
+
console.error('\nError: Rate limit interval must be one of: second, minute, hour');
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
providerConfig.rateLimit = {
|
|
124
|
+
tokensPerInterval,
|
|
125
|
+
interval
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Optional: Circuit breaker
|
|
130
|
+
const configureCircuitBreaker = await confirm({
|
|
131
|
+
message: 'Configure circuit breaker?',
|
|
132
|
+
default: false
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
if (configureCircuitBreaker) {
|
|
136
|
+
const failureThreshold = await number({
|
|
137
|
+
message: 'Failure threshold:',
|
|
138
|
+
default: existingConfig.circuitBreaker?.failureThreshold || 5
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const successThreshold = await number({
|
|
142
|
+
message: 'Success threshold:',
|
|
143
|
+
default: existingConfig.circuitBreaker?.successThreshold || 2
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
const timeout = await number({
|
|
147
|
+
message: 'Timeout (milliseconds):',
|
|
148
|
+
default: existingConfig.circuitBreaker?.timeout || 60000
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
providerConfig.circuitBreaker = {
|
|
152
|
+
failureThreshold,
|
|
153
|
+
successThreshold,
|
|
154
|
+
timeout
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Set provider configuration
|
|
159
|
+
manager.setProvider(providerName, providerConfig);
|
|
160
|
+
|
|
161
|
+
// Optional: Set as default
|
|
162
|
+
const setAsDefault = await confirm({
|
|
163
|
+
message: 'Set as default provider?',
|
|
164
|
+
default: manager.getDefaultProvider() === providerName
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
if (setAsDefault) {
|
|
168
|
+
manager.setDefaultProvider(providerName);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Validate and save
|
|
172
|
+
manager.validateConfig();
|
|
173
|
+
manager.save();
|
|
174
|
+
|
|
175
|
+
console.log(`\nā Provider '${providerName}' configured successfully`);
|
|
176
|
+
|
|
177
|
+
if (setAsDefault) {
|
|
178
|
+
console.log(`ā Set as default provider`);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
console.log('\nNext step:');
|
|
182
|
+
console.log(` - Set API key: autopm config:set-api-key\n`);
|
|
183
|
+
|
|
184
|
+
} catch (error) {
|
|
185
|
+
if (error.message.includes('cancelled') || error.message.includes('User force closed')) {
|
|
186
|
+
console.error('\nError: Configuration cancelled by user\n');
|
|
187
|
+
} else if (error.message.includes('Temperature') || error.message.includes('maxTokens') || error.message.includes('interval')) {
|
|
188
|
+
console.error('\nError:', error.message, '\n');
|
|
189
|
+
} else {
|
|
190
|
+
console.error('\nError:', error.message, '\n');
|
|
191
|
+
}
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Run if called directly
|
|
197
|
+
if (require.main === module) {
|
|
198
|
+
main();
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
module.exports = main;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Config command: set
|
|
4
|
+
* Set configuration value with validation
|
|
5
|
+
*
|
|
6
|
+
* Usage: autopm config:set <key> <value>
|
|
7
|
+
* Example: autopm config:set providers.claude.temperature 0.9
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
const path = require('path');
|
|
11
|
+
const os = require('os');
|
|
12
|
+
const ConfigManager = require('../../lib/config/ConfigManager');
|
|
13
|
+
|
|
14
|
+
// Default config path
|
|
15
|
+
const DEFAULT_CONFIG_PATH = path.join(os.homedir(), '.autopm', 'config.json');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Parse value from string
|
|
19
|
+
* Converts numeric strings to numbers, "true"/"false" to booleans, JSON objects
|
|
20
|
+
* @param {string} valueStr - String value to parse
|
|
21
|
+
* @returns {*} Parsed value
|
|
22
|
+
*/
|
|
23
|
+
function parseValue(valueStr) {
|
|
24
|
+
// Try to parse as JSON first (handles objects, arrays, etc.)
|
|
25
|
+
if (valueStr.startsWith('{') || valueStr.startsWith('[')) {
|
|
26
|
+
try {
|
|
27
|
+
return JSON.parse(valueStr);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
throw new Error('Invalid JSON value');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Parse boolean
|
|
34
|
+
if (valueStr === 'true') return true;
|
|
35
|
+
if (valueStr === 'false') return false;
|
|
36
|
+
|
|
37
|
+
// Parse number
|
|
38
|
+
if (/^-?\d+(\.\d+)?$/.test(valueStr)) {
|
|
39
|
+
return Number(valueStr);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Return as string
|
|
43
|
+
return valueStr;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Validate specific configuration keys
|
|
48
|
+
* @param {string} key - Configuration key
|
|
49
|
+
* @param {*} value - Value to validate
|
|
50
|
+
* @throws {Error} If validation fails
|
|
51
|
+
*/
|
|
52
|
+
function validateValue(key, value) {
|
|
53
|
+
// Temperature validation
|
|
54
|
+
if (key.includes('temperature')) {
|
|
55
|
+
if (typeof value !== 'number' || value < 0 || value > 1) {
|
|
56
|
+
throw new Error('Temperature must be between 0 and 1');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// maxTokens validation
|
|
61
|
+
if (key.includes('maxTokens')) {
|
|
62
|
+
if (typeof value !== 'number' || value <= 0) {
|
|
63
|
+
throw new Error('maxTokens must be positive');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Rate limit interval validation
|
|
68
|
+
if (key.includes('rateLimit.interval')) {
|
|
69
|
+
const validIntervals = ['second', 'minute', 'hour'];
|
|
70
|
+
if (!validIntervals.includes(value)) {
|
|
71
|
+
throw new Error('Rate limit interval must be one of: second, minute, hour');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Main function
|
|
78
|
+
*/
|
|
79
|
+
async function main() {
|
|
80
|
+
try {
|
|
81
|
+
const configPath = process.env.AUTOPM_CONFIG_PATH || DEFAULT_CONFIG_PATH;
|
|
82
|
+
|
|
83
|
+
// Get key and value from command line arguments
|
|
84
|
+
const key = process.argv[2];
|
|
85
|
+
const valueStr = process.argv[3];
|
|
86
|
+
|
|
87
|
+
if (!key || valueStr === undefined) {
|
|
88
|
+
console.error('Error: Both key and value are required');
|
|
89
|
+
console.error('Usage: autopm config:set <key> <value>');
|
|
90
|
+
console.error('Example: autopm config:set providers.claude.temperature 0.9');
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Check if config exists
|
|
95
|
+
const fs = require('fs');
|
|
96
|
+
if (!fs.existsSync(configPath)) {
|
|
97
|
+
console.error('Error: Configuration not found');
|
|
98
|
+
console.error('Run: autopm config:init');
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Load configuration
|
|
103
|
+
const manager = new ConfigManager(configPath);
|
|
104
|
+
|
|
105
|
+
// Parse value
|
|
106
|
+
const value = parseValue(valueStr);
|
|
107
|
+
|
|
108
|
+
// Validate value
|
|
109
|
+
validateValue(key, value);
|
|
110
|
+
|
|
111
|
+
// Set value
|
|
112
|
+
manager.setConfig(key, value);
|
|
113
|
+
|
|
114
|
+
// Validate entire config before saving
|
|
115
|
+
manager.validateConfig();
|
|
116
|
+
|
|
117
|
+
// Save configuration
|
|
118
|
+
manager.save();
|
|
119
|
+
|
|
120
|
+
console.log(`ā Configuration updated: ${key} set to: ${JSON.stringify(value)}\n`);
|
|
121
|
+
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (error.message.includes('JSON')) {
|
|
124
|
+
console.error('Error:', error.message);
|
|
125
|
+
} else if (error.message.includes('Temperature') || error.message.includes('maxTokens') || error.message.includes('interval')) {
|
|
126
|
+
console.error('Error:', error.message);
|
|
127
|
+
} else {
|
|
128
|
+
console.error('Error:', error.message);
|
|
129
|
+
}
|
|
130
|
+
process.exit(1);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Run if called directly
|
|
135
|
+
if (require.main === module) {
|
|
136
|
+
main();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
module.exports = main;
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Config command: show
|
|
4
|
+
* Show full configuration with masked sensitive data
|
|
5
|
+
*
|
|
6
|
+
* Usage: autopm config:show [--json]
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const os = require('os');
|
|
11
|
+
const ConfigManager = require('../../lib/config/ConfigManager');
|
|
12
|
+
|
|
13
|
+
// Default config path
|
|
14
|
+
const DEFAULT_CONFIG_PATH = path.join(os.homedir(), '.autopm', 'config.json');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Mask sensitive API key data recursively
|
|
18
|
+
* @param {*} obj - Object to mask
|
|
19
|
+
* @returns {*} Masked object
|
|
20
|
+
*/
|
|
21
|
+
function maskApiKeys(obj) {
|
|
22
|
+
if (!obj || typeof obj !== 'object') {
|
|
23
|
+
return obj;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (Array.isArray(obj)) {
|
|
27
|
+
return obj.map(item => maskApiKeys(item));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Check if this is an encrypted API key object
|
|
31
|
+
if ('iv' in obj && 'encryptedData' in obj) {
|
|
32
|
+
return '***encrypted***';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Recursively mask nested objects
|
|
36
|
+
const masked = {};
|
|
37
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
38
|
+
masked[key] = maskApiKeys(value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return masked;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Display configuration in human-readable format
|
|
46
|
+
* @param {Object} config - Configuration object
|
|
47
|
+
* @param {ConfigManager} manager - ConfigManager instance
|
|
48
|
+
*/
|
|
49
|
+
function displayHumanReadable(config, manager) {
|
|
50
|
+
const configPath = manager.configPath;
|
|
51
|
+
|
|
52
|
+
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
53
|
+
console.log('ā AutoPM Configuration ā');
|
|
54
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤');
|
|
55
|
+
console.log('ā ā');
|
|
56
|
+
|
|
57
|
+
// Config path
|
|
58
|
+
console.log(`ā Config path: ā`);
|
|
59
|
+
console.log(`ā ${configPath.substring(0, 36).padEnd(36)} ā`);
|
|
60
|
+
|
|
61
|
+
console.log('ā ā');
|
|
62
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤');
|
|
63
|
+
|
|
64
|
+
// Basic info
|
|
65
|
+
console.log(`ā Version: ${String(config.version || 'not set').padEnd(21)} ā`);
|
|
66
|
+
console.log(`ā Environment: ${String(config.environment || 'development').padEnd(21)} ā`);
|
|
67
|
+
console.log(`ā Default: ${String(config.defaultProvider || 'not set').padEnd(21)} ā`);
|
|
68
|
+
|
|
69
|
+
console.log('ā ā');
|
|
70
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤');
|
|
71
|
+
console.log('ā Providers ā');
|
|
72
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤');
|
|
73
|
+
|
|
74
|
+
const providers = manager.listProviders();
|
|
75
|
+
|
|
76
|
+
if (providers.length === 0) {
|
|
77
|
+
console.log('ā No providers configured ā');
|
|
78
|
+
} else {
|
|
79
|
+
for (const providerName of providers.sort()) {
|
|
80
|
+
const provider = manager.getProvider(providerName);
|
|
81
|
+
const hasApiKey = manager.hasApiKey(providerName);
|
|
82
|
+
const isDefault = providerName === config.defaultProvider;
|
|
83
|
+
|
|
84
|
+
const marker = isDefault ? '*' : ' ';
|
|
85
|
+
const keyStatus = hasApiKey ? 'ā' : 'ā';
|
|
86
|
+
|
|
87
|
+
console.log(`ā ${marker} ${providerName.padEnd(16)} ${keyStatus} ā`);
|
|
88
|
+
console.log(`ā Model: ${(provider.model || 'not set').substring(0, 26).padEnd(26)} ā`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
console.log('ā ā');
|
|
93
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤');
|
|
94
|
+
console.log('ā Summary ā');
|
|
95
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤');
|
|
96
|
+
|
|
97
|
+
const apiKeysSet = providers.filter(p => manager.hasApiKey(p)).length;
|
|
98
|
+
|
|
99
|
+
console.log(`ā Total providers: ${String(providers.length).padEnd(15)} ā`);
|
|
100
|
+
console.log(`ā API keys set: ${String(apiKeysSet).padEnd(15)} ā`);
|
|
101
|
+
|
|
102
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
103
|
+
|
|
104
|
+
// Warnings
|
|
105
|
+
const warnings = [];
|
|
106
|
+
|
|
107
|
+
if (config.defaultProvider && !manager.hasApiKey(config.defaultProvider)) {
|
|
108
|
+
warnings.push(`ā ļø Warning: Default provider '${config.defaultProvider}' has no API key`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const providersWithoutKeys = providers.filter(p => !manager.hasApiKey(p));
|
|
112
|
+
if (providersWithoutKeys.length > 0) {
|
|
113
|
+
warnings.push(`ā¹ļø ${providersWithoutKeys.length} provider(s) without API keys: ${providersWithoutKeys.join(', ')}`);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (warnings.length > 0) {
|
|
117
|
+
console.log('Notifications:\n');
|
|
118
|
+
warnings.forEach(w => console.log(w));
|
|
119
|
+
console.log();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Help
|
|
123
|
+
console.log('To modify configuration:');
|
|
124
|
+
console.log(' autopm config:set <key> <value> - Set config value');
|
|
125
|
+
console.log(' autopm config:set-provider <name> - Configure provider');
|
|
126
|
+
console.log(' autopm config:set-api-key - Set API key\n');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Display configuration as JSON
|
|
131
|
+
* @param {Object} config - Configuration object
|
|
132
|
+
*/
|
|
133
|
+
function displayJson(config) {
|
|
134
|
+
const masked = maskApiKeys(config);
|
|
135
|
+
console.log(JSON.stringify(masked, null, 2));
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Main function
|
|
140
|
+
*/
|
|
141
|
+
async function main() {
|
|
142
|
+
try {
|
|
143
|
+
const configPath = process.env.AUTOPM_CONFIG_PATH || DEFAULT_CONFIG_PATH;
|
|
144
|
+
|
|
145
|
+
// Check if config exists
|
|
146
|
+
const fs = require('fs');
|
|
147
|
+
if (!fs.existsSync(configPath)) {
|
|
148
|
+
console.error('\nError: Configuration not found');
|
|
149
|
+
console.error('Run: autopm config:init\n');
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Load configuration
|
|
154
|
+
const manager = new ConfigManager(configPath);
|
|
155
|
+
const config = manager.getConfig();
|
|
156
|
+
|
|
157
|
+
// Check for --json flag
|
|
158
|
+
const jsonOutput = process.argv.includes('--json');
|
|
159
|
+
|
|
160
|
+
if (jsonOutput) {
|
|
161
|
+
displayJson(config);
|
|
162
|
+
} else {
|
|
163
|
+
displayHumanReadable(config, manager);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
} catch (error) {
|
|
167
|
+
if (error.message.includes('Unexpected token') || error.message.includes('JSON')) {
|
|
168
|
+
console.error('\nError reading config: Invalid JSON format\n');
|
|
169
|
+
} else {
|
|
170
|
+
console.error('\nError:', error.message, '\n');
|
|
171
|
+
}
|
|
172
|
+
process.exit(1);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Run if called directly
|
|
177
|
+
if (require.main === module) {
|
|
178
|
+
main();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
module.exports = main;
|
package/autopm/.claude/.env
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
# ============================================
|
|
2
|
-
# MCP (Model Context Protocol) Configuration
|
|
3
|
-
# ============================================
|
|
4
|
-
|
|
5
|
-
# Context7 MCP Server Configuration
|
|
6
|
-
# ------------------------------------------
|
|
7
|
-
# Get your API key from https://context7.com/account
|
|
8
|
-
CONTEXT7_API_KEY=your-context7-api-key-here
|
|
9
|
-
|
|
10
|
-
# MCP endpoint URL (default: mcp.context7.com/mcp)
|
|
11
|
-
CONTEXT7_MCP_URL=mcp.context7.com/mcp
|
|
12
|
-
|
|
13
|
-
# Context7 API URL (default: context7.com/api/v1)
|
|
14
|
-
CONTEXT7_API_URL=context7.com/api/v1
|
|
15
|
-
|
|
16
|
-
# Your Context7 workspace ID or name
|
|
17
|
-
CONTEXT7_WORKSPACE=your-workspace-id-or-name
|
|
18
|
-
|
|
19
|
-
# Context mode: documentation or codebase
|
|
20
|
-
# documentation = for accessing docs, codebase = for code context
|
|
21
|
-
CONTEXT7_MODE=documentation
|
|
22
|
-
|
|
23
|
-
# Cache TTL in seconds (optional, default: 3600)
|
|
24
|
-
CONTEXT7_CACHE_TTL=3600
|
|
25
|
-
|
|
26
|
-
# ============================================
|
|
27
|
-
# GitHub MCP Server Configuration
|
|
28
|
-
# ============================================
|
|
29
|
-
|
|
30
|
-
# GitHub Personal Access Token
|
|
31
|
-
# Create at: https://github.com/settings/tokens
|
|
32
|
-
# Required scopes: repo, workflow, read:org
|
|
33
|
-
GITHUB_TOKEN=your-github-personal-access-token
|
|
34
|
-
|
|
35
|
-
# GitHub API URL (default for public GitHub)
|
|
36
|
-
GITHUB_API_URL=https://api.github.com
|
|
37
|
-
|
|
38
|
-
# ============================================
|
|
39
|
-
# Playwright MCP Server Configuration
|
|
40
|
-
# ============================================
|
|
41
|
-
|
|
42
|
-
# Browser to use for Playwright tests (chromium, firefox, webkit)
|
|
43
|
-
PLAYWRIGHT_BROWSER=chromium
|
|
44
|
-
|
|
45
|
-
# Run browser in headless mode (true/false)
|
|
46
|
-
PLAYWRIGHT_HEADLESS=true
|
|
47
|
-
|
|
48
|
-
# ============================================
|
|
49
|
-
# Azure DevOps Configuration (Optional)
|
|
50
|
-
# ============================================
|
|
51
|
-
|
|
52
|
-
# Azure DevOps Personal Access Token
|
|
53
|
-
# Create at: https://dev.azure.com/{yourorganization}/_usersSettings/tokens
|
|
54
|
-
AZURE_DEVOPS_PAT=your-azure-devops-pat
|
|
55
|
-
|
|
56
|
-
# Azure DevOps Organization
|
|
57
|
-
AZURE_DEVOPS_ORG=your-organization
|
|
58
|
-
|
|
59
|
-
# Azure DevOps Project
|
|
60
|
-
AZURE_DEVOPS_PROJECT=your-project
|
|
61
|
-
|
|
62
|
-
# Azure DevOps API URL (optional, for Azure DevOps Server)
|
|
63
|
-
# AZURE_DEVOPS_API_URL=https://dev.azure.com
|
|
64
|
-
|
|
65
|
-
# ============================================
|
|
66
|
-
# Cloud Provider Credentials (Optional)
|
|
67
|
-
# ============================================
|
|
68
|
-
|
|
69
|
-
# AWS Configuration
|
|
70
|
-
# ------------------------------------------
|
|
71
|
-
AWS_ACCESS_KEY_ID=your-aws-access-key
|
|
72
|
-
AWS_SECRET_ACCESS_KEY=your-aws-secret-key
|
|
73
|
-
AWS_DEFAULT_REGION=us-east-1
|
|
74
|
-
# Optional: AWS profile to use
|
|
75
|
-
# AWS_PROFILE=default
|
|
76
|
-
|
|
77
|
-
# Azure Cloud Configuration
|
|
78
|
-
# ------------------------------------------
|
|
79
|
-
AZURE_SUBSCRIPTION_ID=your-azure-subscription-id
|
|
80
|
-
AZURE_TENANT_ID=your-azure-tenant-id
|
|
81
|
-
AZURE_CLIENT_ID=your-azure-client-id
|
|
82
|
-
AZURE_CLIENT_SECRET=your-azure-client-secret
|
|
83
|
-
# Optional: Azure Cloud environment (AzureCloud, AzureChinaCloud, AzureUSGovernment, AzureGermanCloud)
|
|
84
|
-
# AZURE_CLOUD_ENVIRONMENT=AzureCloud
|
|
85
|
-
|
|
86
|
-
# Google Cloud Platform Configuration
|
|
87
|
-
# ------------------------------------------
|
|
88
|
-
GCP_PROJECT_ID=your-gcp-project-id
|
|
89
|
-
# Path to service account key JSON file
|
|
90
|
-
GCP_SERVICE_ACCOUNT_KEY=path/to/service-account-key.json
|
|
91
|
-
# Optional: GCP region
|
|
92
|
-
# GCP_REGION=us-central1
|
|
93
|
-
|
|
94
|
-
# ============================================
|
|
95
|
-
# AI Provider API Keys (Optional)
|
|
96
|
-
# ============================================
|
|
97
|
-
|
|
98
|
-
# OpenAI Configuration
|
|
99
|
-
# ------------------------------------------
|
|
100
|
-
OPENAI_API_KEY=your-openai-api-key
|
|
101
|
-
# Optional: OpenAI organization ID
|
|
102
|
-
# OPENAI_ORG_ID=your-org-id
|
|
103
|
-
# Optional: API base URL for custom endpoints
|
|
104
|
-
# OPENAI_API_BASE=https://api.openai.com/v1
|
|
105
|
-
|
|
106
|
-
# Google Gemini Configuration
|
|
107
|
-
# ------------------------------------------
|
|
108
|
-
GEMINI_API_KEY=your-gemini-api-key
|
|
109
|
-
# Optional: Gemini model to use
|
|
110
|
-
# GEMINI_MODEL=gemini-pro
|
|
111
|
-
|
|
112
|
-
# ============================================
|
|
113
|
-
# Additional MCP Servers (Optional)
|
|
114
|
-
# ============================================
|
|
115
|
-
|
|
116
|
-
# Database MCP Server
|
|
117
|
-
# ------------------------------------------
|
|
118
|
-
# DATABASE_MCP_URL=your-database-mcp-url
|
|
119
|
-
# DATABASE_MCP_TOKEN=your-database-token
|
|
120
|
-
|
|
121
|
-
# Custom MCP Server
|
|
122
|
-
# ------------------------------------------
|
|
123
|
-
# CUSTOM_MCP_URL=your-custom-mcp-url
|
|
124
|
-
# CUSTOM_MCP_API_KEY=your-custom-api-key
|
|
125
|
-
|
|
126
|
-
# ============================================
|
|
127
|
-
# MCP Context Pool Settings
|
|
128
|
-
# ============================================
|
|
129
|
-
|
|
130
|
-
# Maximum context pool size for shared contexts
|
|
131
|
-
MCP_CONTEXT_POOL_MAX_SIZE=100MB
|
|
132
|
-
|
|
133
|
-
# Context retention period (e.g., 7d, 24h, 1w)
|
|
134
|
-
MCP_CONTEXT_RETENTION=7d
|
|
135
|
-
|
|
136
|
-
# Context refresh interval (daily, hourly, on-change)
|
|
137
|
-
MCP_CONTEXT_REFRESH=daily
|
|
138
|
-
|
|
139
|
-
# ============================================
|
|
140
|
-
# Development & Testing
|
|
141
|
-
# ============================================
|
|
142
|
-
|
|
143
|
-
# Enable MCP debug logging (true/false)
|
|
144
|
-
MCP_DEBUG=false
|
|
145
|
-
|
|
146
|
-
# MCP log level (error, warn, info, debug, trace)
|
|
147
|
-
MCP_LOG_LEVEL=info
|
|
148
|
-
|
|
149
|
-
# ============================================
|
|
150
|
-
# IMPORTANT SECURITY NOTES
|
|
151
|
-
# ============================================
|
|
152
|
-
# 1. NEVER commit this file to version control
|
|
153
|
-
# 2. This file is already in .gitignore
|
|
154
|
-
# 3. Keep this file secure with proper permissions
|
|
155
|
-
# 4. Rotate API keys regularly
|
|
156
|
-
# 5. Use environment-specific .env files for different environments
|
|
157
|
-
# 6. Consider using a secrets management service for production
|
|
158
|
-
# ============================================
|