vibeman 0.0.1 → 0.0.2

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 (71) hide show
  1. package/dist/index.js +5 -7
  2. package/dist/runtime/api/.tsbuildinfo +1 -1
  3. package/dist/runtime/api/agent/agent-service.d.ts +11 -13
  4. package/dist/runtime/api/agent/agent-service.js +25 -31
  5. package/dist/runtime/api/agent/ai-providers/claude-code-adapter.d.ts +2 -2
  6. package/dist/runtime/api/agent/ai-providers/claude-code-adapter.js +25 -36
  7. package/dist/runtime/api/agent/ai-providers/codex-cli-provider.js +48 -14
  8. package/dist/runtime/api/agent/ai-providers/types.d.ts +2 -0
  9. package/dist/runtime/api/agent/codex-cli-provider.test.js +37 -0
  10. package/dist/runtime/api/agent/parsers.d.ts +1 -0
  11. package/dist/runtime/api/agent/parsers.js +75 -8
  12. package/dist/runtime/api/agent/prompt-service.d.ts +14 -1
  13. package/dist/runtime/api/agent/prompt-service.js +123 -14
  14. package/dist/runtime/api/agent/prompt-service.test.d.ts +1 -0
  15. package/dist/runtime/api/agent/prompt-service.test.js +230 -0
  16. package/dist/runtime/api/agent/routing-policy.d.ts +14 -14
  17. package/dist/runtime/api/api/routers/ai.d.ts +6 -6
  18. package/dist/runtime/api/api/routers/ai.js +2 -17
  19. package/dist/runtime/api/api/routers/executions.d.ts +5 -5
  20. package/dist/runtime/api/api/routers/executions.js +12 -21
  21. package/dist/runtime/api/api/routers/provider-config.d.ts +165 -0
  22. package/dist/runtime/api/api/routers/provider-config.js +252 -0
  23. package/dist/runtime/api/api/routers/tasks.d.ts +10 -10
  24. package/dist/runtime/api/api/routers/workflows.d.ts +15 -16
  25. package/dist/runtime/api/api/routers/workflows.js +28 -26
  26. package/dist/runtime/api/api/routers/worktrees.d.ts +4 -5
  27. package/dist/runtime/api/api/routers/worktrees.js +11 -11
  28. package/dist/runtime/api/api/trpc.d.ts +18 -18
  29. package/dist/runtime/api/index.js +2 -10
  30. package/dist/runtime/api/lib/local-config.d.ts +245 -0
  31. package/dist/runtime/api/lib/local-config.js +288 -0
  32. package/dist/runtime/api/lib/provider-detection.d.ts +59 -0
  33. package/dist/runtime/api/lib/provider-detection.js +244 -0
  34. package/dist/runtime/api/lib/server/bootstrap.d.ts +38 -0
  35. package/dist/runtime/api/lib/server/bootstrap.js +197 -0
  36. package/dist/runtime/api/lib/server/project-root.js +24 -1
  37. package/dist/runtime/api/lib/trpc/server.d.ts +124 -31
  38. package/dist/runtime/api/lib/trpc/server.js +8 -8
  39. package/dist/runtime/api/lib/trpc/ws-server.js +2 -2
  40. package/dist/runtime/api/router.d.ts +125 -32
  41. package/dist/runtime/api/router.js +9 -31
  42. package/dist/runtime/api/settings-service.js +2 -0
  43. package/dist/runtime/api/workflows/vibing-orchestrator.d.ts +8 -3
  44. package/dist/runtime/api/workflows/vibing-orchestrator.js +182 -183
  45. package/dist/runtime/web/.next/BUILD_ID +1 -1
  46. package/dist/runtime/web/.next/app-build-manifest.json +2 -2
  47. package/dist/runtime/web/.next/build-manifest.json +2 -2
  48. package/dist/runtime/web/.next/prerender-manifest.json +3 -3
  49. package/dist/runtime/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  50. package/dist/runtime/web/.next/server/app/_not-found.html +2 -2
  51. package/dist/runtime/web/.next/server/app/_not-found.rsc +5 -5
  52. package/dist/runtime/web/.next/server/app/api/health/route.js +1 -1
  53. package/dist/runtime/web/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
  54. package/dist/runtime/web/.next/server/app/api/images/[...path]/route_client-reference-manifest.js +1 -1
  55. package/dist/runtime/web/.next/server/app/api/upload/route_client-reference-manifest.js +1 -1
  56. package/dist/runtime/web/.next/server/app/index.html +2 -2
  57. package/dist/runtime/web/.next/server/app/index.rsc +6 -6
  58. package/dist/runtime/web/.next/server/app/page.js +3 -3
  59. package/dist/runtime/web/.next/server/app/page_client-reference-manifest.js +1 -1
  60. package/dist/runtime/web/.next/server/chunks/458.js +1 -1
  61. package/dist/runtime/web/.next/server/pages/404.html +2 -2
  62. package/dist/runtime/web/.next/server/pages/500.html +1 -1
  63. package/dist/runtime/web/.next/server/pages-manifest.json +1 -1
  64. package/dist/runtime/web/.next/server/server-reference-manifest.json +1 -1
  65. package/dist/runtime/web/.next/static/chunks/app/{layout-dc0cfd29075b2160.js → layout-8435322f09fd0975.js} +1 -1
  66. package/dist/runtime/web/.next/static/chunks/app/page-8c3ba579efc6f918.js +1 -0
  67. package/dist/tsconfig.tsbuildinfo +1 -1
  68. package/package.json +5 -1
  69. package/dist/runtime/web/.next/static/chunks/app/page-f34a8b196b18850b.js +0 -1
  70. /package/dist/runtime/web/.next/static/{1HR8N0rJkCvFRtbTPJMyH → mRpNgPfbYR_0wrODzlg_4}/_buildManifest.js +0 -0
  71. /package/dist/runtime/web/.next/static/{1HR8N0rJkCvFRtbTPJMyH → mRpNgPfbYR_0wrODzlg_4}/_ssgManifest.js +0 -0
@@ -0,0 +1,245 @@
1
+ /**
2
+ * Local Configuration Manager
3
+ * Handles machine-specific configuration that should not be committed to git
4
+ */
5
+ import { EventEmitter } from 'events';
6
+ import { z } from 'zod';
7
+ declare const LocalConfigSchema: z.ZodObject<{
8
+ providers: z.ZodOptional<z.ZodObject<{
9
+ 'claude-code': z.ZodOptional<z.ZodObject<{
10
+ binPath: z.ZodOptional<z.ZodString>;
11
+ detectedPath: z.ZodOptional<z.ZodString>;
12
+ lastDetected: z.ZodOptional<z.ZodString>;
13
+ detectionMethod: z.ZodOptional<z.ZodEnum<["explicit", "PATH", "common-location"]>>;
14
+ }, "strip", z.ZodTypeAny, {
15
+ binPath?: string | undefined;
16
+ detectedPath?: string | undefined;
17
+ lastDetected?: string | undefined;
18
+ detectionMethod?: "explicit" | "PATH" | "common-location" | undefined;
19
+ }, {
20
+ binPath?: string | undefined;
21
+ detectedPath?: string | undefined;
22
+ lastDetected?: string | undefined;
23
+ detectionMethod?: "explicit" | "PATH" | "common-location" | undefined;
24
+ }>>;
25
+ codex: z.ZodOptional<z.ZodObject<{
26
+ binPath: z.ZodOptional<z.ZodString>;
27
+ detectedPath: z.ZodOptional<z.ZodString>;
28
+ lastDetected: z.ZodOptional<z.ZodString>;
29
+ detectionMethod: z.ZodOptional<z.ZodEnum<["explicit", "PATH", "common-location"]>>;
30
+ }, "strip", z.ZodTypeAny, {
31
+ binPath?: string | undefined;
32
+ detectedPath?: string | undefined;
33
+ lastDetected?: string | undefined;
34
+ detectionMethod?: "explicit" | "PATH" | "common-location" | undefined;
35
+ }, {
36
+ binPath?: string | undefined;
37
+ detectedPath?: string | undefined;
38
+ lastDetected?: string | undefined;
39
+ detectionMethod?: "explicit" | "PATH" | "common-location" | undefined;
40
+ }>>;
41
+ }, "strip", z.ZodTypeAny, {
42
+ 'claude-code'?: {
43
+ binPath?: string | undefined;
44
+ detectedPath?: string | undefined;
45
+ lastDetected?: string | undefined;
46
+ detectionMethod?: "explicit" | "PATH" | "common-location" | undefined;
47
+ } | undefined;
48
+ codex?: {
49
+ binPath?: string | undefined;
50
+ detectedPath?: string | undefined;
51
+ lastDetected?: string | undefined;
52
+ detectionMethod?: "explicit" | "PATH" | "common-location" | undefined;
53
+ } | undefined;
54
+ }, {
55
+ 'claude-code'?: {
56
+ binPath?: string | undefined;
57
+ detectedPath?: string | undefined;
58
+ lastDetected?: string | undefined;
59
+ detectionMethod?: "explicit" | "PATH" | "common-location" | undefined;
60
+ } | undefined;
61
+ codex?: {
62
+ binPath?: string | undefined;
63
+ detectedPath?: string | undefined;
64
+ lastDetected?: string | undefined;
65
+ detectionMethod?: "explicit" | "PATH" | "common-location" | undefined;
66
+ } | undefined;
67
+ }>>;
68
+ cache: z.ZodOptional<z.ZodObject<{
69
+ lastProviderValidation: z.ZodOptional<z.ZodString>;
70
+ validationResults: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
71
+ available: z.ZodBoolean;
72
+ error: z.ZodOptional<z.ZodString>;
73
+ version: z.ZodOptional<z.ZodString>;
74
+ checkedAt: z.ZodString;
75
+ }, "strip", z.ZodTypeAny, {
76
+ available: boolean;
77
+ checkedAt: string;
78
+ error?: string | undefined;
79
+ version?: string | undefined;
80
+ }, {
81
+ available: boolean;
82
+ checkedAt: string;
83
+ error?: string | undefined;
84
+ version?: string | undefined;
85
+ }>>>;
86
+ }, "strip", z.ZodTypeAny, {
87
+ lastProviderValidation?: string | undefined;
88
+ validationResults?: Record<string, {
89
+ available: boolean;
90
+ checkedAt: string;
91
+ error?: string | undefined;
92
+ version?: string | undefined;
93
+ }> | undefined;
94
+ }, {
95
+ lastProviderValidation?: string | undefined;
96
+ validationResults?: Record<string, {
97
+ available: boolean;
98
+ checkedAt: string;
99
+ error?: string | undefined;
100
+ version?: string | undefined;
101
+ }> | undefined;
102
+ }>>;
103
+ }, "strip", z.ZodTypeAny, {
104
+ providers?: {
105
+ 'claude-code'?: {
106
+ binPath?: string | undefined;
107
+ detectedPath?: string | undefined;
108
+ lastDetected?: string | undefined;
109
+ detectionMethod?: "explicit" | "PATH" | "common-location" | undefined;
110
+ } | undefined;
111
+ codex?: {
112
+ binPath?: string | undefined;
113
+ detectedPath?: string | undefined;
114
+ lastDetected?: string | undefined;
115
+ detectionMethod?: "explicit" | "PATH" | "common-location" | undefined;
116
+ } | undefined;
117
+ } | undefined;
118
+ cache?: {
119
+ lastProviderValidation?: string | undefined;
120
+ validationResults?: Record<string, {
121
+ available: boolean;
122
+ checkedAt: string;
123
+ error?: string | undefined;
124
+ version?: string | undefined;
125
+ }> | undefined;
126
+ } | undefined;
127
+ }, {
128
+ providers?: {
129
+ 'claude-code'?: {
130
+ binPath?: string | undefined;
131
+ detectedPath?: string | undefined;
132
+ lastDetected?: string | undefined;
133
+ detectionMethod?: "explicit" | "PATH" | "common-location" | undefined;
134
+ } | undefined;
135
+ codex?: {
136
+ binPath?: string | undefined;
137
+ detectedPath?: string | undefined;
138
+ lastDetected?: string | undefined;
139
+ detectionMethod?: "explicit" | "PATH" | "common-location" | undefined;
140
+ } | undefined;
141
+ } | undefined;
142
+ cache?: {
143
+ lastProviderValidation?: string | undefined;
144
+ validationResults?: Record<string, {
145
+ available: boolean;
146
+ checkedAt: string;
147
+ error?: string | undefined;
148
+ version?: string | undefined;
149
+ }> | undefined;
150
+ } | undefined;
151
+ }>;
152
+ export type LocalConfig = z.infer<typeof LocalConfigSchema>;
153
+ export interface LocalConfigServiceConfig {
154
+ configDir?: string;
155
+ configFileName?: string;
156
+ }
157
+ /**
158
+ * Local Configuration Service
159
+ * Manages machine-specific configuration stored in local-only directory
160
+ */
161
+ export declare class LocalConfigService extends EventEmitter {
162
+ private config;
163
+ private configPath;
164
+ private initialized;
165
+ constructor(options?: LocalConfigServiceConfig);
166
+ /**
167
+ * Initialize the local config service
168
+ */
169
+ initialize(): Promise<void>;
170
+ /**
171
+ * Get the full local configuration
172
+ */
173
+ getConfig(): LocalConfig;
174
+ /**
175
+ * Get provider-specific configuration
176
+ */
177
+ getProviderConfig(provider: 'claude-code' | 'codex'): {
178
+ binPath?: string | undefined;
179
+ detectedPath?: string | undefined;
180
+ lastDetected?: string | undefined;
181
+ detectionMethod?: "explicit" | "PATH" | "common-location" | undefined;
182
+ } | {
183
+ binPath?: string | undefined;
184
+ detectedPath?: string | undefined;
185
+ lastDetected?: string | undefined;
186
+ detectionMethod?: "explicit" | "PATH" | "common-location" | undefined;
187
+ } | undefined;
188
+ /**
189
+ * Set provider binary path and detection info
190
+ */
191
+ setProviderPath(provider: 'claude-code' | 'codex', binPath: string, detectionMethod?: 'explicit' | 'PATH' | 'common-location'): Promise<void>;
192
+ updateDetectedProvider(provider: 'claude-code' | 'codex', detectedPath: string, detectionMethod?: 'PATH' | 'common-location'): Promise<void>;
193
+ /**
194
+ * Clear provider configuration
195
+ */
196
+ clearProviderPath(provider: 'claude-code' | 'codex'): Promise<void>;
197
+ /**
198
+ * Cache provider validation results
199
+ */
200
+ cacheValidationResult(provider: string, result: {
201
+ available: boolean;
202
+ error?: string;
203
+ version?: string;
204
+ }): Promise<void>;
205
+ /**
206
+ * Get cached validation result
207
+ */
208
+ getCachedValidationResult(provider: string): {
209
+ available: boolean;
210
+ error?: string;
211
+ version?: string;
212
+ checkedAt: string;
213
+ } | undefined;
214
+ /**
215
+ * Check if cached validation is still fresh (within last 5 minutes)
216
+ */
217
+ isCachedValidationFresh(provider: string): boolean;
218
+ /**
219
+ * Clear all cached validation results
220
+ */
221
+ clearValidationCache(): Promise<void>;
222
+ /**
223
+ * Get configuration file information
224
+ */
225
+ getConfigInfo(): Promise<{
226
+ path: string;
227
+ exists: boolean;
228
+ size?: number;
229
+ }>;
230
+ /**
231
+ * Export configuration for debugging/backup
232
+ */
233
+ exportConfig(): Promise<string>;
234
+ /**
235
+ * Import configuration from JSON string
236
+ */
237
+ importConfig(configJson: string): Promise<void>;
238
+ private ensureConfigDirectory;
239
+ private loadConfig;
240
+ private saveConfig;
241
+ private fileExists;
242
+ private mergeWithDefaults;
243
+ }
244
+ export declare function getLocalConfigService(config?: LocalConfigServiceConfig): LocalConfigService;
245
+ export {};
@@ -0,0 +1,288 @@
1
+ /**
2
+ * Local Configuration Manager
3
+ * Handles machine-specific configuration that should not be committed to git
4
+ */
5
+ import { EventEmitter } from 'events';
6
+ import fs from 'fs/promises';
7
+ import path from 'path';
8
+ import { z } from 'zod';
9
+ import { log } from './logger.js';
10
+ import { getProjectRoot } from './server/project-root.js';
11
+ // Schema for local configuration
12
+ const LocalConfigSchema = z.object({
13
+ providers: z
14
+ .object({
15
+ 'claude-code': z
16
+ .object({
17
+ binPath: z.string().optional(),
18
+ detectedPath: z.string().optional(),
19
+ lastDetected: z.string().optional(), // ISO date
20
+ detectionMethod: z.enum(['explicit', 'PATH', 'common-location']).optional(),
21
+ })
22
+ .optional(),
23
+ codex: z
24
+ .object({
25
+ binPath: z.string().optional(),
26
+ detectedPath: z.string().optional(),
27
+ lastDetected: z.string().optional(),
28
+ detectionMethod: z.enum(['explicit', 'PATH', 'common-location']).optional(),
29
+ })
30
+ .optional(),
31
+ })
32
+ .optional(),
33
+ cache: z
34
+ .object({
35
+ lastProviderValidation: z.string().optional(), // ISO date
36
+ validationResults: z
37
+ .record(z.object({
38
+ available: z.boolean(),
39
+ error: z.string().optional(),
40
+ version: z.string().optional(),
41
+ checkedAt: z.string(), // ISO date
42
+ }))
43
+ .optional(),
44
+ })
45
+ .optional(),
46
+ });
47
+ // Default local configuration
48
+ const DEFAULT_LOCAL_CONFIG = {
49
+ providers: {},
50
+ cache: {},
51
+ };
52
+ /**
53
+ * Local Configuration Service
54
+ * Manages machine-specific configuration stored in local-only directory
55
+ */
56
+ export class LocalConfigService extends EventEmitter {
57
+ constructor(options = {}) {
58
+ super();
59
+ this.config = { ...DEFAULT_LOCAL_CONFIG };
60
+ this.initialized = false;
61
+ const configDir = options.configDir ?? '.vibeman/.local';
62
+ const configFileName = options.configFileName ?? 'local-config.json';
63
+ // Store in project-local directory that should be gitignored
64
+ const projectRoot = getProjectRoot();
65
+ this.configPath = path.join(projectRoot, configDir, configFileName);
66
+ }
67
+ /**
68
+ * Initialize the local config service
69
+ */
70
+ async initialize() {
71
+ if (this.initialized)
72
+ return;
73
+ try {
74
+ await this.ensureConfigDirectory();
75
+ await this.loadConfig();
76
+ this.initialized = true;
77
+ log.info('Local config service initialized', { configPath: this.configPath }, 'local-config');
78
+ }
79
+ catch (error) {
80
+ log.error('Failed to initialize local config service', error, 'local-config');
81
+ throw error;
82
+ }
83
+ }
84
+ /**
85
+ * Get the full local configuration
86
+ */
87
+ getConfig() {
88
+ return { ...this.config };
89
+ }
90
+ /**
91
+ * Get provider-specific configuration
92
+ */
93
+ getProviderConfig(provider) {
94
+ return this.config.providers?.[provider];
95
+ }
96
+ /**
97
+ * Set provider binary path and detection info
98
+ */
99
+ async setProviderPath(provider, binPath, detectionMethod = 'explicit') {
100
+ if (!this.config.providers) {
101
+ this.config.providers = {};
102
+ }
103
+ if (!this.config.providers[provider]) {
104
+ this.config.providers[provider] = {};
105
+ }
106
+ this.config.providers[provider].binPath = binPath;
107
+ this.config.providers[provider].detectedPath = binPath;
108
+ this.config.providers[provider].lastDetected = new Date().toISOString();
109
+ this.config.providers[provider].detectionMethod = detectionMethod;
110
+ await this.saveConfig();
111
+ this.emit('providerPathChanged', { provider, binPath, detectionMethod });
112
+ }
113
+ async updateDetectedProvider(provider, detectedPath, detectionMethod = 'PATH') {
114
+ if (!this.config.providers) {
115
+ this.config.providers = {};
116
+ }
117
+ if (!this.config.providers[provider]) {
118
+ this.config.providers[provider] = {};
119
+ }
120
+ this.config.providers[provider].detectedPath = detectedPath;
121
+ this.config.providers[provider].lastDetected = new Date().toISOString();
122
+ this.config.providers[provider].detectionMethod = detectionMethod;
123
+ await this.saveConfig();
124
+ this.emit('providerPathDetected', { provider, detectedPath, detectionMethod });
125
+ }
126
+ /**
127
+ * Clear provider configuration
128
+ */
129
+ async clearProviderPath(provider) {
130
+ if (this.config.providers?.[provider]) {
131
+ delete this.config.providers[provider];
132
+ await this.saveConfig();
133
+ this.emit('providerPathCleared', { provider });
134
+ }
135
+ }
136
+ /**
137
+ * Cache provider validation results
138
+ */
139
+ async cacheValidationResult(provider, result) {
140
+ if (!this.config.cache) {
141
+ this.config.cache = {};
142
+ }
143
+ if (!this.config.cache.validationResults) {
144
+ this.config.cache.validationResults = {};
145
+ }
146
+ this.config.cache.validationResults[provider] = {
147
+ ...result,
148
+ checkedAt: new Date().toISOString(),
149
+ };
150
+ this.config.cache.lastProviderValidation = new Date().toISOString();
151
+ await this.saveConfig();
152
+ }
153
+ /**
154
+ * Get cached validation result
155
+ */
156
+ getCachedValidationResult(provider) {
157
+ return this.config.cache?.validationResults?.[provider];
158
+ }
159
+ /**
160
+ * Check if cached validation is still fresh (within last 5 minutes)
161
+ */
162
+ isCachedValidationFresh(provider) {
163
+ const cached = this.getCachedValidationResult(provider);
164
+ if (!cached)
165
+ return false;
166
+ const cacheAge = Date.now() - new Date(cached.checkedAt).getTime();
167
+ const CACHE_TTL = 5 * 60 * 1000; // 5 minutes
168
+ return cacheAge < CACHE_TTL;
169
+ }
170
+ /**
171
+ * Clear all cached validation results
172
+ */
173
+ async clearValidationCache() {
174
+ if (this.config.cache) {
175
+ this.config.cache.validationResults = {};
176
+ this.config.cache.lastProviderValidation = undefined;
177
+ await this.saveConfig();
178
+ this.emit('validationCacheCleared');
179
+ }
180
+ }
181
+ /**
182
+ * Get configuration file information
183
+ */
184
+ async getConfigInfo() {
185
+ const exists = await this.fileExists(this.configPath);
186
+ let size;
187
+ if (exists) {
188
+ try {
189
+ const stats = await fs.stat(this.configPath);
190
+ size = stats.size;
191
+ }
192
+ catch {
193
+ // Ignore errors getting file size
194
+ }
195
+ }
196
+ return { path: this.configPath, exists, size };
197
+ }
198
+ /**
199
+ * Export configuration for debugging/backup
200
+ */
201
+ async exportConfig() {
202
+ return JSON.stringify(this.config, null, 2);
203
+ }
204
+ /**
205
+ * Import configuration from JSON string
206
+ */
207
+ async importConfig(configJson) {
208
+ try {
209
+ const parsed = JSON.parse(configJson);
210
+ const validated = LocalConfigSchema.parse(parsed);
211
+ this.config = validated;
212
+ await this.saveConfig();
213
+ this.emit('configImported', this.config);
214
+ }
215
+ catch (error) {
216
+ throw new Error(`Invalid config format: ${error instanceof Error ? error.message : String(error)}`);
217
+ }
218
+ }
219
+ // Private methods
220
+ async ensureConfigDirectory() {
221
+ const configDir = path.dirname(this.configPath);
222
+ try {
223
+ await fs.access(configDir);
224
+ }
225
+ catch {
226
+ await fs.mkdir(configDir, { recursive: true });
227
+ log.info('Created local config directory', { configDir }, 'local-config');
228
+ // Create .gitignore to ensure this directory is not committed
229
+ const gitignorePath = path.join(configDir, '.gitignore');
230
+ try {
231
+ await fs.writeFile(gitignorePath, '# Local configuration - do not commit\n*\n!.gitignore\n');
232
+ }
233
+ catch (error) {
234
+ log.warn('Failed to create .gitignore in local config directory', error, 'local-config');
235
+ }
236
+ }
237
+ }
238
+ async loadConfig() {
239
+ try {
240
+ await fs.access(this.configPath);
241
+ const data = await fs.readFile(this.configPath, 'utf-8');
242
+ const parsed = JSON.parse(data);
243
+ // Validate and use parsed config
244
+ const validated = LocalConfigSchema.parse(parsed);
245
+ this.config = this.mergeWithDefaults(validated);
246
+ log.debug('Local config loaded from file', { configPath: this.configPath }, 'local-config');
247
+ }
248
+ catch (error) {
249
+ log.debug('Local config file not found or invalid, using defaults', { error: String(error) }, 'local-config');
250
+ this.config = { ...DEFAULT_LOCAL_CONFIG };
251
+ await this.saveConfig();
252
+ }
253
+ }
254
+ async saveConfig() {
255
+ const data = JSON.stringify(this.config, null, 2);
256
+ await fs.writeFile(this.configPath, data, 'utf-8');
257
+ log.debug('Local config saved to file', { configPath: this.configPath }, 'local-config');
258
+ }
259
+ async fileExists(filePath) {
260
+ try {
261
+ await fs.access(filePath);
262
+ return true;
263
+ }
264
+ catch {
265
+ return false;
266
+ }
267
+ }
268
+ mergeWithDefaults(config) {
269
+ return {
270
+ ...DEFAULT_LOCAL_CONFIG,
271
+ ...config,
272
+ providers: {
273
+ ...DEFAULT_LOCAL_CONFIG.providers,
274
+ ...config.providers,
275
+ },
276
+ cache: {
277
+ ...DEFAULT_LOCAL_CONFIG.cache,
278
+ ...config.cache,
279
+ },
280
+ };
281
+ }
282
+ }
283
+ // Singleton instance
284
+ let localConfigService = null;
285
+ export function getLocalConfigService(config) {
286
+ localConfigService ?? (localConfigService = new LocalConfigService(config));
287
+ return localConfigService;
288
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Enhanced Provider Detection Service
3
+ * Robust detection logic for AI provider CLI tools with multiple fallback strategies
4
+ */
5
+ export interface DetectionResult {
6
+ found: boolean;
7
+ path?: string;
8
+ version?: string;
9
+ method?: 'explicit' | 'PATH' | 'common-location';
10
+ error?: string;
11
+ }
12
+ export interface ProviderInfo {
13
+ name: string;
14
+ command: string;
15
+ versionArgsList?: string[][];
16
+ versionRegex: RegExp;
17
+ }
18
+ /**
19
+ * Provider definitions for detection
20
+ */
21
+ export declare const PROVIDER_DEFINITIONS: Record<string, ProviderInfo>;
22
+ /**
23
+ * Enhanced Provider Detection Service
24
+ */
25
+ export declare class ProviderDetectionService {
26
+ private localConfig;
27
+ constructor();
28
+ /**
29
+ * Detect a specific provider with all fallback strategies
30
+ */
31
+ detectProvider(providerId: string): Promise<DetectionResult>;
32
+ /**
33
+ * Detect all configured providers
34
+ */
35
+ detectAllProviders(): Promise<Record<string, DetectionResult>>;
36
+ /**
37
+ * Validate a specific binary path
38
+ */
39
+ validateBinaryPath(binPath: string, provider: ProviderInfo, method?: DetectionResult['method']): Promise<DetectionResult>;
40
+ /**
41
+ * Set explicit provider path and cache it
42
+ */
43
+ setProviderPath(providerId: string, binPath: string): Promise<DetectionResult>;
44
+ /**
45
+ * Clear cached provider configuration
46
+ */
47
+ clearProviderPath(providerId: string): Promise<void>;
48
+ /**
49
+ * Get cached detection results if still fresh
50
+ */
51
+ getCachedResult(providerId: string): Promise<DetectionResult | null>;
52
+ private checkExplicitConfig;
53
+ private checkSystemCommand;
54
+ private getVersion;
55
+ private resolveCommand;
56
+ private toLocalConfigKey;
57
+ private cacheDetectionResult;
58
+ }
59
+ export declare function getProviderDetectionService(): ProviderDetectionService;