codeep 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 (103) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +576 -0
  3. package/dist/api/index.d.ts +8 -0
  4. package/dist/api/index.js +421 -0
  5. package/dist/app.d.ts +2 -0
  6. package/dist/app.js +1406 -0
  7. package/dist/components/AgentProgress.d.ts +33 -0
  8. package/dist/components/AgentProgress.js +97 -0
  9. package/dist/components/Export.d.ts +8 -0
  10. package/dist/components/Export.js +27 -0
  11. package/dist/components/Help.d.ts +2 -0
  12. package/dist/components/Help.js +3 -0
  13. package/dist/components/Input.d.ts +9 -0
  14. package/dist/components/Input.js +89 -0
  15. package/dist/components/Loading.d.ts +9 -0
  16. package/dist/components/Loading.js +31 -0
  17. package/dist/components/Login.d.ts +7 -0
  18. package/dist/components/Login.js +77 -0
  19. package/dist/components/Logo.d.ts +8 -0
  20. package/dist/components/Logo.js +89 -0
  21. package/dist/components/LogoutPicker.d.ts +8 -0
  22. package/dist/components/LogoutPicker.js +61 -0
  23. package/dist/components/Message.d.ts +10 -0
  24. package/dist/components/Message.js +234 -0
  25. package/dist/components/MessageList.d.ts +10 -0
  26. package/dist/components/MessageList.js +8 -0
  27. package/dist/components/ProjectPermission.d.ts +7 -0
  28. package/dist/components/ProjectPermission.js +52 -0
  29. package/dist/components/Search.d.ts +10 -0
  30. package/dist/components/Search.js +30 -0
  31. package/dist/components/SessionPicker.d.ts +9 -0
  32. package/dist/components/SessionPicker.js +88 -0
  33. package/dist/components/Sessions.d.ts +12 -0
  34. package/dist/components/Sessions.js +102 -0
  35. package/dist/components/Settings.d.ts +7 -0
  36. package/dist/components/Settings.js +162 -0
  37. package/dist/components/Status.d.ts +2 -0
  38. package/dist/components/Status.js +12 -0
  39. package/dist/config/config.test.d.ts +1 -0
  40. package/dist/config/config.test.js +157 -0
  41. package/dist/config/index.d.ts +121 -0
  42. package/dist/config/index.js +555 -0
  43. package/dist/config/providers.d.ts +43 -0
  44. package/dist/config/providers.js +82 -0
  45. package/dist/config/providers.test.d.ts +1 -0
  46. package/dist/config/providers.test.js +132 -0
  47. package/dist/index.d.ts +2 -0
  48. package/dist/index.js +38 -0
  49. package/dist/utils/agent.d.ts +37 -0
  50. package/dist/utils/agent.js +627 -0
  51. package/dist/utils/codeReview.d.ts +36 -0
  52. package/dist/utils/codeReview.js +390 -0
  53. package/dist/utils/context.d.ts +49 -0
  54. package/dist/utils/context.js +216 -0
  55. package/dist/utils/diffPreview.d.ts +57 -0
  56. package/dist/utils/diffPreview.js +335 -0
  57. package/dist/utils/export.d.ts +19 -0
  58. package/dist/utils/export.js +94 -0
  59. package/dist/utils/git.d.ts +85 -0
  60. package/dist/utils/git.js +399 -0
  61. package/dist/utils/git.test.d.ts +1 -0
  62. package/dist/utils/git.test.js +193 -0
  63. package/dist/utils/history.d.ts +93 -0
  64. package/dist/utils/history.js +348 -0
  65. package/dist/utils/interactive.d.ts +34 -0
  66. package/dist/utils/interactive.js +206 -0
  67. package/dist/utils/keychain.d.ts +17 -0
  68. package/dist/utils/keychain.js +160 -0
  69. package/dist/utils/learning.d.ts +89 -0
  70. package/dist/utils/learning.js +330 -0
  71. package/dist/utils/logger.d.ts +33 -0
  72. package/dist/utils/logger.js +130 -0
  73. package/dist/utils/project.d.ts +86 -0
  74. package/dist/utils/project.js +415 -0
  75. package/dist/utils/project.test.d.ts +1 -0
  76. package/dist/utils/project.test.js +212 -0
  77. package/dist/utils/ratelimit.d.ts +26 -0
  78. package/dist/utils/ratelimit.js +132 -0
  79. package/dist/utils/ratelimit.test.d.ts +1 -0
  80. package/dist/utils/ratelimit.test.js +131 -0
  81. package/dist/utils/retry.d.ts +28 -0
  82. package/dist/utils/retry.js +109 -0
  83. package/dist/utils/retry.test.d.ts +1 -0
  84. package/dist/utils/retry.test.js +163 -0
  85. package/dist/utils/search.d.ts +11 -0
  86. package/dist/utils/search.js +29 -0
  87. package/dist/utils/shell.d.ts +45 -0
  88. package/dist/utils/shell.js +242 -0
  89. package/dist/utils/skills.d.ts +144 -0
  90. package/dist/utils/skills.js +1137 -0
  91. package/dist/utils/smartContext.d.ts +29 -0
  92. package/dist/utils/smartContext.js +441 -0
  93. package/dist/utils/tools.d.ts +224 -0
  94. package/dist/utils/tools.js +731 -0
  95. package/dist/utils/update.d.ts +22 -0
  96. package/dist/utils/update.js +128 -0
  97. package/dist/utils/validation.d.ts +28 -0
  98. package/dist/utils/validation.js +141 -0
  99. package/dist/utils/validation.test.d.ts +1 -0
  100. package/dist/utils/validation.test.js +164 -0
  101. package/dist/utils/verify.d.ts +78 -0
  102. package/dist/utils/verify.js +464 -0
  103. package/package.json +68 -0
@@ -0,0 +1,555 @@
1
+ import Conf from 'conf';
2
+ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync, unlinkSync, statSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { homedir } from 'os';
5
+ import { PROVIDERS, getProvider } from './providers';
6
+ import { logSession } from '../utils/logger';
7
+ // Global sessions directory (fallback when not in a project)
8
+ const GLOBAL_SESSIONS_DIR = join(homedir(), '.codeep', 'sessions');
9
+ // Ensure global sessions directory exists
10
+ if (!existsSync(GLOBAL_SESSIONS_DIR)) {
11
+ mkdirSync(GLOBAL_SESSIONS_DIR, { recursive: true });
12
+ }
13
+ /**
14
+ * Get sessions directory - local .codeep/sessions/ if in project, otherwise global
15
+ */
16
+ function getSessionsDir(projectPath) {
17
+ if (projectPath && isProjectDirectory(projectPath)) {
18
+ const localDir = join(projectPath, '.codeep', 'sessions');
19
+ if (!existsSync(localDir)) {
20
+ mkdirSync(localDir, { recursive: true });
21
+ }
22
+ return localDir;
23
+ }
24
+ return GLOBAL_SESSIONS_DIR;
25
+ }
26
+ /**
27
+ * Get local project config path
28
+ */
29
+ function getLocalConfigPath(projectPath) {
30
+ if (!isProjectDirectory(projectPath))
31
+ return null;
32
+ const configDir = join(projectPath, '.codeep');
33
+ if (!existsSync(configDir)) {
34
+ mkdirSync(configDir, { recursive: true });
35
+ }
36
+ return join(configDir, 'config.json');
37
+ }
38
+ /**
39
+ * Check if directory is a project (has package.json)
40
+ */
41
+ function isProjectDirectory(path) {
42
+ return existsSync(join(path, 'package.json'));
43
+ }
44
+ export const config = new Conf({
45
+ projectName: 'codeep',
46
+ defaults: {
47
+ apiKey: '',
48
+ provider: 'z.ai',
49
+ model: 'glm-4.7',
50
+ agentMode: 'auto',
51
+ agentConfirmation: 'dangerous', // Confirm only dangerous actions by default
52
+ agentAutoCommit: false,
53
+ agentAutoCommitBranch: false,
54
+ agentAutoVerify: true, // Auto-verify by default
55
+ agentMaxFixAttempts: 3,
56
+ protocol: 'openai',
57
+ plan: 'lite',
58
+ language: 'en',
59
+ autoSave: true,
60
+ currentSessionId: '',
61
+ temperature: 0.7,
62
+ maxTokens: 4096,
63
+ apiTimeout: 30000,
64
+ rateLimitApi: 30, // 30 requests per minute
65
+ rateLimitCommands: 100, // 100 commands per minute
66
+ projectPermissions: [],
67
+ providerApiKeys: [],
68
+ },
69
+ });
70
+ // In-memory cache for API keys (populated on first access)
71
+ const apiKeyCache = new Map();
72
+ export const LANGUAGES = {
73
+ 'auto': 'Auto-detect',
74
+ 'en': 'English',
75
+ 'zh': 'Chinese (中文)',
76
+ 'es': 'Spanish (Español)',
77
+ 'hi': 'Hindi (हिन्दी)',
78
+ 'ar': 'Arabic (العربية)',
79
+ 'pt': 'Portuguese (Português)',
80
+ 'fr': 'French (Français)',
81
+ 'de': 'German (Deutsch)',
82
+ 'ja': 'Japanese (日本語)',
83
+ 'ru': 'Russian (Русский)',
84
+ 'hr': 'Croatian (Hrvatski)',
85
+ };
86
+ export const PROTOCOLS = {
87
+ 'openai': 'OpenAI Compatible',
88
+ 'anthropic': 'Anthropic Protocol',
89
+ };
90
+ // Get API key for current or specified provider
91
+ /**
92
+ * Load API key from config into cache
93
+ */
94
+ export async function loadApiKey(providerId) {
95
+ const provider = providerId || config.get('provider');
96
+ const providerConfig = getProvider(provider);
97
+ // Check environment variable first
98
+ if (providerConfig?.envKey) {
99
+ const envKey = process.env[providerConfig.envKey];
100
+ if (envKey) {
101
+ apiKeyCache.set(provider, envKey);
102
+ return envKey;
103
+ }
104
+ }
105
+ // Legacy env vars for z.ai
106
+ if (provider === 'z.ai') {
107
+ if (process.env.ZAI_API_KEY) {
108
+ apiKeyCache.set(provider, process.env.ZAI_API_KEY);
109
+ return process.env.ZAI_API_KEY;
110
+ }
111
+ if (process.env.ZHIPUAI_API_KEY) {
112
+ apiKeyCache.set(provider, process.env.ZHIPUAI_API_KEY);
113
+ return process.env.ZHIPUAI_API_KEY;
114
+ }
115
+ }
116
+ // Check config file
117
+ const providerKeys = config.get('providerApiKeys') || [];
118
+ const stored = providerKeys.find(k => k.providerId === provider);
119
+ if (stored?.apiKey) {
120
+ apiKeyCache.set(provider, stored.apiKey);
121
+ return stored.apiKey;
122
+ }
123
+ // Fallback to legacy apiKey field (for z.ai)
124
+ if (provider === 'z.ai') {
125
+ const legacyKey = config.get('apiKey') || '';
126
+ if (legacyKey) {
127
+ apiKeyCache.set(provider, legacyKey);
128
+ return legacyKey;
129
+ }
130
+ }
131
+ return '';
132
+ }
133
+ /**
134
+ * Load API keys for ALL providers into cache
135
+ * Should be called at app startup
136
+ */
137
+ export async function loadAllApiKeys() {
138
+ // Load keys for all configured providers from providerApiKeys
139
+ const providerKeys = config.get('providerApiKeys') || [];
140
+ for (const { providerId, apiKey } of providerKeys) {
141
+ if (apiKey) {
142
+ apiKeyCache.set(providerId, apiKey);
143
+ }
144
+ }
145
+ // Also check environment variables for each provider
146
+ for (const [providerId, providerConfig] of Object.entries(PROVIDERS)) {
147
+ if (providerConfig.envKey) {
148
+ const envKey = process.env[providerConfig.envKey];
149
+ if (envKey) {
150
+ apiKeyCache.set(providerId, envKey);
151
+ }
152
+ }
153
+ }
154
+ // Legacy env vars for z.ai
155
+ if (!apiKeyCache.get('z.ai')) {
156
+ if (process.env.ZAI_API_KEY) {
157
+ apiKeyCache.set('z.ai', process.env.ZAI_API_KEY);
158
+ }
159
+ else if (process.env.ZHIPUAI_API_KEY) {
160
+ apiKeyCache.set('z.ai', process.env.ZHIPUAI_API_KEY);
161
+ }
162
+ else {
163
+ // Fallback to legacy apiKey field
164
+ const legacyKey = config.get('apiKey') || '';
165
+ if (legacyKey) {
166
+ apiKeyCache.set('z.ai', legacyKey);
167
+ }
168
+ }
169
+ }
170
+ }
171
+ /**
172
+ * Get API key synchronously from cache (must call loadAllApiKeys first)
173
+ */
174
+ export function getApiKey(providerId) {
175
+ const provider = providerId || config.get('provider');
176
+ return apiKeyCache.get(provider) || '';
177
+ }
178
+ /**
179
+ * Set API key - stores in config file
180
+ */
181
+ export function setApiKey(key, providerId) {
182
+ const provider = providerId || config.get('provider');
183
+ // Update cache immediately
184
+ apiKeyCache.set(provider, key);
185
+ // Store in config
186
+ const providerKeys = config.get('providerApiKeys') || [];
187
+ const existing = providerKeys.findIndex(k => k.providerId === provider);
188
+ if (existing >= 0) {
189
+ providerKeys[existing].apiKey = key;
190
+ }
191
+ else {
192
+ providerKeys.push({ providerId: provider, apiKey: key });
193
+ }
194
+ config.set('providerApiKeys', providerKeys);
195
+ // Also set legacy field for backwards compatibility (z.ai only)
196
+ if (provider === 'z.ai') {
197
+ config.set('apiKey', key);
198
+ }
199
+ }
200
+ export function getMaskedApiKey(providerId) {
201
+ const key = getApiKey(providerId);
202
+ if (key.length > 4) {
203
+ return '*'.repeat(key.length - 4) + key.slice(-4);
204
+ }
205
+ return key;
206
+ }
207
+ /**
208
+ * Get list of providers that have API keys configured
209
+ */
210
+ export function getConfiguredProviders() {
211
+ const providerKeys = config.get('providerApiKeys') || [];
212
+ const configured = [];
213
+ for (const pk of providerKeys) {
214
+ if (pk.apiKey && pk.apiKey.length > 0) {
215
+ const provider = getProvider(pk.providerId);
216
+ configured.push({
217
+ id: pk.providerId,
218
+ name: provider?.name || pk.providerId,
219
+ });
220
+ }
221
+ }
222
+ return configured;
223
+ }
224
+ /**
225
+ * Clear API key for a specific provider
226
+ */
227
+ export function clearApiKey(providerId) {
228
+ // Clear from cache
229
+ apiKeyCache.delete(providerId);
230
+ // Clear from config
231
+ const providerKeys = config.get('providerApiKeys') || [];
232
+ const filtered = providerKeys.filter(k => k.providerId !== providerId);
233
+ config.set('providerApiKeys', filtered);
234
+ // Clear legacy field if z.ai
235
+ if (providerId === 'z.ai') {
236
+ config.set('apiKey', '');
237
+ }
238
+ }
239
+ export async function isConfiguredAsync(providerId) {
240
+ const key = await loadApiKey(providerId);
241
+ return Boolean(key);
242
+ }
243
+ export function isConfigured(providerId) {
244
+ return Boolean(getApiKey(providerId));
245
+ }
246
+ // Get current provider info
247
+ export function getCurrentProvider() {
248
+ const providerId = config.get('provider');
249
+ const provider = getProvider(providerId);
250
+ return {
251
+ id: providerId,
252
+ name: provider?.name || providerId,
253
+ };
254
+ }
255
+ // Set provider and update model/protocol to defaults
256
+ export function setProvider(providerId) {
257
+ const provider = getProvider(providerId);
258
+ if (!provider)
259
+ return false;
260
+ config.set('provider', providerId);
261
+ config.set('model', provider.defaultModel);
262
+ config.set('protocol', provider.defaultProtocol);
263
+ // Load API key for the new provider into cache
264
+ // This is async but we fire-and-forget since the key will be loaded before next API call
265
+ loadApiKey(providerId);
266
+ return true;
267
+ }
268
+ // Get models for current provider
269
+ export function getModelsForCurrentProvider() {
270
+ const providerId = config.get('provider');
271
+ const provider = getProvider(providerId);
272
+ if (!provider)
273
+ return {};
274
+ const models = {};
275
+ for (const model of provider.models) {
276
+ models[model.id] = `${model.name} - ${model.description}`;
277
+ }
278
+ return models;
279
+ }
280
+ // Re-export PROVIDERS for convenience
281
+ export { PROVIDERS } from './providers';
282
+ // Generate unique session ID
283
+ function generateSessionId() {
284
+ const now = new Date();
285
+ const date = now.toISOString().split('T')[0];
286
+ const time = now.toTimeString().split(' ')[0].replace(/:/g, '-');
287
+ return `session-${date}-${time}`;
288
+ }
289
+ // Get or create current session ID
290
+ export function getCurrentSessionId() {
291
+ let sessionId = config.get('currentSessionId');
292
+ if (!sessionId) {
293
+ sessionId = generateSessionId();
294
+ config.set('currentSessionId', sessionId);
295
+ }
296
+ return sessionId;
297
+ }
298
+ // Start new session
299
+ export function startNewSession() {
300
+ const sessionId = generateSessionId();
301
+ config.set('currentSessionId', sessionId);
302
+ return sessionId;
303
+ }
304
+ // Auto-save debounce state
305
+ let autoSaveTimeout = null;
306
+ let pendingAutoSave = null;
307
+ // Auto-save current session (debounced - saves max every 5 seconds)
308
+ export function autoSaveSession(history, projectPath) {
309
+ if (!config.get('autoSave') || history.length === 0) {
310
+ return false;
311
+ }
312
+ // Store pending save data
313
+ pendingAutoSave = { history, projectPath };
314
+ // If already scheduled, don't reschedule
315
+ if (autoSaveTimeout) {
316
+ return true;
317
+ }
318
+ // Schedule save after 5 seconds
319
+ autoSaveTimeout = setTimeout(() => {
320
+ if (pendingAutoSave) {
321
+ const sessionId = getCurrentSessionId();
322
+ saveSession(sessionId, pendingAutoSave.history, pendingAutoSave.projectPath);
323
+ pendingAutoSave = null;
324
+ }
325
+ autoSaveTimeout = null;
326
+ }, 5000);
327
+ return true;
328
+ }
329
+ // Force immediate save (for explicit save commands)
330
+ export function flushAutoSave() {
331
+ if (autoSaveTimeout) {
332
+ clearTimeout(autoSaveTimeout);
333
+ autoSaveTimeout = null;
334
+ }
335
+ if (pendingAutoSave) {
336
+ const sessionId = getCurrentSessionId();
337
+ const result = saveSession(sessionId, pendingAutoSave.history, pendingAutoSave.projectPath);
338
+ pendingAutoSave = null;
339
+ return result;
340
+ }
341
+ return false;
342
+ }
343
+ // Session management
344
+ export function saveSession(name, history, projectPath) {
345
+ try {
346
+ const session = {
347
+ name,
348
+ history,
349
+ createdAt: new Date().toISOString(),
350
+ };
351
+ const sessionsDir = getSessionsDir(projectPath);
352
+ const filePath = join(sessionsDir, `${name}.json`);
353
+ writeFileSync(filePath, JSON.stringify(session, null, 2));
354
+ logSession('save', name, true);
355
+ return true;
356
+ }
357
+ catch (error) {
358
+ logSession('save', name, false);
359
+ return false;
360
+ }
361
+ }
362
+ export function loadSession(name, projectPath) {
363
+ try {
364
+ const sessionsDir = getSessionsDir(projectPath);
365
+ const filePath = join(sessionsDir, `${name}.json`);
366
+ if (existsSync(filePath)) {
367
+ const data = JSON.parse(readFileSync(filePath, 'utf-8'));
368
+ logSession('load', name, true);
369
+ return data.history;
370
+ }
371
+ logSession('load', name, false);
372
+ return null;
373
+ }
374
+ catch (error) {
375
+ logSession('load', name, false);
376
+ return null;
377
+ }
378
+ }
379
+ export function listSessions(projectPath) {
380
+ try {
381
+ const sessionsDir = getSessionsDir(projectPath);
382
+ return readdirSync(sessionsDir)
383
+ .filter(f => f.endsWith('.json'))
384
+ .map(f => f.replace('.json', ''))
385
+ .sort();
386
+ }
387
+ catch {
388
+ return [];
389
+ }
390
+ }
391
+ export function deleteSession(name, projectPath) {
392
+ try {
393
+ const sessionsDir = getSessionsDir(projectPath);
394
+ const filePath = join(sessionsDir, `${name}.json`);
395
+ if (existsSync(filePath)) {
396
+ unlinkSync(filePath);
397
+ logSession('delete', name, true);
398
+ return true;
399
+ }
400
+ logSession('delete', name, false);
401
+ return false;
402
+ }
403
+ catch (error) {
404
+ logSession('delete', name, false);
405
+ return false;
406
+ }
407
+ }
408
+ export function renameSession(oldName, newName, projectPath) {
409
+ try {
410
+ const sessionsDir = getSessionsDir(projectPath);
411
+ const oldPath = join(sessionsDir, `${oldName}.json`);
412
+ const newPath = join(sessionsDir, `${newName}.json`);
413
+ if (!existsSync(oldPath)) {
414
+ logSession('rename', `${oldName} -> ${newName}`, false);
415
+ return false;
416
+ }
417
+ // Read existing session
418
+ const data = JSON.parse(readFileSync(oldPath, 'utf-8'));
419
+ // Update name and save to new path
420
+ data.name = newName;
421
+ writeFileSync(newPath, JSON.stringify(data, null, 2));
422
+ // Delete old file
423
+ unlinkSync(oldPath);
424
+ // Update current session ID if it was the renamed one
425
+ if (config.get('currentSessionId') === oldName) {
426
+ config.set('currentSessionId', newName);
427
+ }
428
+ logSession('rename', `${oldName} -> ${newName}`, true);
429
+ return true;
430
+ }
431
+ catch (error) {
432
+ logSession('rename', `${oldName} -> ${newName}`, false);
433
+ return false;
434
+ }
435
+ }
436
+ export function getSessionInfo(name, projectPath) {
437
+ try {
438
+ const sessionsDir = getSessionsDir(projectPath);
439
+ const filePath = join(sessionsDir, `${name}.json`);
440
+ if (existsSync(filePath)) {
441
+ const data = JSON.parse(readFileSync(filePath, 'utf-8'));
442
+ return {
443
+ name: data.name,
444
+ createdAt: data.createdAt,
445
+ messageCount: data.history.length,
446
+ };
447
+ }
448
+ return null;
449
+ }
450
+ catch {
451
+ return null;
452
+ }
453
+ }
454
+ /**
455
+ * List all sessions with metadata, sorted by date (newest first)
456
+ */
457
+ export function listSessionsWithInfo(projectPath) {
458
+ try {
459
+ const sessionsDir = getSessionsDir(projectPath);
460
+ const files = readdirSync(sessionsDir).filter(f => f.endsWith('.json'));
461
+ const sessions = [];
462
+ for (const file of files) {
463
+ const filePath = join(sessionsDir, file);
464
+ try {
465
+ const stat = statSync(filePath);
466
+ const data = JSON.parse(readFileSync(filePath, 'utf-8'));
467
+ sessions.push({
468
+ name: data.name || file.replace('.json', ''),
469
+ createdAt: data.createdAt || stat.mtime.toISOString(),
470
+ messageCount: data.history?.length || 0,
471
+ fileSize: stat.size,
472
+ });
473
+ }
474
+ catch {
475
+ // Skip invalid session files
476
+ }
477
+ }
478
+ // Sort by date, newest first
479
+ return sessions.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());
480
+ }
481
+ catch {
482
+ return [];
483
+ }
484
+ }
485
+ // Project permission management
486
+ /**
487
+ * Get project permission from local .codeep/config.json
488
+ */
489
+ export function getProjectPermission(projectPath) {
490
+ const configPath = getLocalConfigPath(projectPath);
491
+ if (!configPath || !existsSync(configPath)) {
492
+ return null;
493
+ }
494
+ try {
495
+ const data = JSON.parse(readFileSync(configPath, 'utf-8'));
496
+ return data.permission || null;
497
+ }
498
+ catch {
499
+ return null;
500
+ }
501
+ }
502
+ /**
503
+ * Set project permission in local .codeep/config.json
504
+ */
505
+ export function setProjectPermission(projectPath, read, write) {
506
+ const configPath = getLocalConfigPath(projectPath);
507
+ if (!configPath)
508
+ return;
509
+ const permission = {
510
+ path: projectPath,
511
+ readPermission: read,
512
+ writePermission: write,
513
+ grantedAt: new Date().toISOString(),
514
+ };
515
+ let data = {};
516
+ if (existsSync(configPath)) {
517
+ try {
518
+ data = JSON.parse(readFileSync(configPath, 'utf-8'));
519
+ }
520
+ catch {
521
+ // Invalid JSON, start fresh
522
+ }
523
+ }
524
+ data.permission = permission;
525
+ writeFileSync(configPath, JSON.stringify(data, null, 2));
526
+ }
527
+ /**
528
+ * Remove project permission from local .codeep/config.json
529
+ */
530
+ export function removeProjectPermission(projectPath) {
531
+ const configPath = getLocalConfigPath(projectPath);
532
+ if (!configPath || !existsSync(configPath)) {
533
+ return false;
534
+ }
535
+ try {
536
+ const data = JSON.parse(readFileSync(configPath, 'utf-8'));
537
+ if (data.permission) {
538
+ delete data.permission;
539
+ writeFileSync(configPath, JSON.stringify(data, null, 2));
540
+ return true;
541
+ }
542
+ }
543
+ catch {
544
+ // Ignore errors
545
+ }
546
+ return false;
547
+ }
548
+ export function hasReadPermission(projectPath) {
549
+ const perm = getProjectPermission(projectPath);
550
+ return perm?.readPermission === true;
551
+ }
552
+ export function hasWritePermission(projectPath) {
553
+ const perm = getProjectPermission(projectPath);
554
+ return perm?.writePermission === true;
555
+ }
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Provider configurations for different AI services
3
+ */
4
+ export interface ProviderConfig {
5
+ name: string;
6
+ description: string;
7
+ protocols: {
8
+ openai?: {
9
+ baseUrl: string;
10
+ authHeader: 'Bearer' | 'x-api-key';
11
+ supportsNativeTools?: boolean;
12
+ };
13
+ anthropic?: {
14
+ baseUrl: string;
15
+ authHeader: 'Bearer' | 'x-api-key';
16
+ supportsNativeTools?: boolean;
17
+ };
18
+ };
19
+ models: {
20
+ id: string;
21
+ name: string;
22
+ description: string;
23
+ }[];
24
+ defaultModel: string;
25
+ defaultProtocol: 'openai' | 'anthropic';
26
+ envKey?: string;
27
+ }
28
+ export declare const PROVIDERS: Record<string, ProviderConfig>;
29
+ export type ProviderId = keyof typeof PROVIDERS;
30
+ export declare function getProvider(id: string): ProviderConfig | null;
31
+ export declare function getProviderList(): {
32
+ id: string;
33
+ name: string;
34
+ description: string;
35
+ }[];
36
+ export declare function getProviderModels(providerId: string): {
37
+ id: string;
38
+ name: string;
39
+ description: string;
40
+ }[];
41
+ export declare function getProviderBaseUrl(providerId: string, protocol: 'openai' | 'anthropic'): string | null;
42
+ export declare function getProviderAuthHeader(providerId: string, protocol: 'openai' | 'anthropic'): 'Bearer' | 'x-api-key';
43
+ export declare function supportsNativeTools(providerId: string, protocol: 'openai' | 'anthropic'): boolean;
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Provider configurations for different AI services
3
+ */
4
+ export const PROVIDERS = {
5
+ 'z.ai': {
6
+ name: 'Z.AI (ZhipuAI)',
7
+ description: 'GLM Coding Plan',
8
+ protocols: {
9
+ openai: {
10
+ baseUrl: 'https://api.z.ai/api/coding/paas/v4',
11
+ authHeader: 'Bearer',
12
+ supportsNativeTools: true,
13
+ },
14
+ anthropic: {
15
+ baseUrl: 'https://api.z.ai/api/anthropic',
16
+ authHeader: 'x-api-key',
17
+ supportsNativeTools: true,
18
+ },
19
+ },
20
+ models: [
21
+ { id: 'glm-4.7', name: 'GLM-4.7', description: 'Latest GLM model' },
22
+ { id: 'glm-4.7-flash', name: 'GLM-4.7 Flash', description: 'Faster, lighter version' },
23
+ ],
24
+ defaultModel: 'glm-4.7',
25
+ defaultProtocol: 'openai',
26
+ envKey: 'ZAI_API_KEY',
27
+ },
28
+ 'minimax': {
29
+ name: 'MiniMax',
30
+ description: 'MiniMax Coding Plan',
31
+ protocols: {
32
+ openai: {
33
+ baseUrl: 'https://api.minimax.io/v1',
34
+ authHeader: 'Bearer',
35
+ supportsNativeTools: true,
36
+ },
37
+ anthropic: {
38
+ baseUrl: 'https://api.minimax.io/anthropic',
39
+ authHeader: 'x-api-key',
40
+ supportsNativeTools: false, // MiniMax Anthropic doesn't support native tools properly
41
+ },
42
+ },
43
+ models: [
44
+ { id: 'MiniMax-M2.1', name: 'MiniMax M2.1', description: 'Latest MiniMax coding model' },
45
+ ],
46
+ defaultModel: 'MiniMax-M2.1',
47
+ defaultProtocol: 'anthropic',
48
+ envKey: 'MINIMAX_API_KEY',
49
+ },
50
+ };
51
+ export function getProvider(id) {
52
+ return PROVIDERS[id] || null;
53
+ }
54
+ export function getProviderList() {
55
+ return Object.entries(PROVIDERS).map(([id, config]) => ({
56
+ id,
57
+ name: config.name,
58
+ description: config.description,
59
+ }));
60
+ }
61
+ export function getProviderModels(providerId) {
62
+ const provider = PROVIDERS[providerId];
63
+ return provider ? provider.models : [];
64
+ }
65
+ export function getProviderBaseUrl(providerId, protocol) {
66
+ const provider = PROVIDERS[providerId];
67
+ if (!provider)
68
+ return null;
69
+ return provider.protocols[protocol]?.baseUrl || null;
70
+ }
71
+ export function getProviderAuthHeader(providerId, protocol) {
72
+ const provider = PROVIDERS[providerId];
73
+ if (!provider)
74
+ return 'Bearer';
75
+ return provider.protocols[protocol]?.authHeader || 'Bearer';
76
+ }
77
+ export function supportsNativeTools(providerId, protocol) {
78
+ const provider = PROVIDERS[providerId];
79
+ if (!provider)
80
+ return false;
81
+ return provider.protocols[protocol]?.supportsNativeTools ?? true; // Default to true
82
+ }
@@ -0,0 +1 @@
1
+ export {};