git-coco 0.27.0 → 0.27.1

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.
@@ -46,7 +46,7 @@ import { pathToFileURL } from 'url';
46
46
  /**
47
47
  * Current build version from package.json
48
48
  */
49
- const BUILD_VERSION = "0.27.0";
49
+ const BUILD_VERSION = "0.27.1";
50
50
 
51
51
  const isInteractive = (config) => {
52
52
  return config?.mode === 'interactive' || !!config?.interactive;
@@ -226,6 +226,16 @@ class LangChainAuthenticationError extends LangChainError {
226
226
  super(message, context);
227
227
  }
228
228
  }
229
+ /**
230
+ * Network/connection errors (service unreachable, DNS failures, etc.)
231
+ */
232
+ class LangChainNetworkError extends LangChainError {
233
+ constructor(message, endpoint, provider, context) {
234
+ super(message, { ...context, endpoint, provider });
235
+ this.endpoint = endpoint;
236
+ this.provider = provider;
237
+ }
238
+ }
229
239
 
230
240
  /**
231
241
  * Validates that a required parameter is not null or undefined
@@ -2351,6 +2361,59 @@ class Logger {
2351
2361
  }
2352
2362
  }
2353
2363
 
2364
+ /**
2365
+ * Formats a network error with helpful troubleshooting information
2366
+ */
2367
+ function formatNetworkError(error, logger) {
2368
+ const endpoint = error.endpoint || 'unknown endpoint';
2369
+ const provider = error.provider || 'LLM service';
2370
+ logger.log('\nFailed to execute command', { color: 'yellow' });
2371
+ logger.log(`\nError: Unable to connect to ${provider}`, { color: 'red' });
2372
+ if (error.endpoint) {
2373
+ logger.log(` Endpoint: ${endpoint}`, { color: 'red' });
2374
+ }
2375
+ logger.log('\nTroubleshooting:', { color: 'cyan' });
2376
+ // Provider-specific troubleshooting
2377
+ if (provider === 'ollama' || endpoint.includes('11434')) {
2378
+ logger.log(' • Is Ollama running? Try: ollama serve', { color: 'white' });
2379
+ logger.log(' • Check if the endpoint is correct in your config', { color: 'white' });
2380
+ logger.log(` • Verify Ollama is accessible: curl ${endpoint}/api/version`, { color: 'white' });
2381
+ }
2382
+ else if (provider === 'openai' || endpoint.includes('openai')) {
2383
+ logger.log(' • Check your internet connection', { color: 'white' });
2384
+ logger.log(' • Verify the API endpoint is accessible', { color: 'white' });
2385
+ logger.log(' • If using a custom baseURL, verify it is correct', { color: 'white' });
2386
+ }
2387
+ else if (provider === 'anthropic') {
2388
+ logger.log(' • Check your internet connection', { color: 'white' });
2389
+ logger.log(' • Verify the Anthropic API is accessible', { color: 'white' });
2390
+ }
2391
+ else {
2392
+ logger.log(' • Check your internet connection', { color: 'white' });
2393
+ logger.log(' • Verify the service endpoint is correct', { color: 'white' });
2394
+ logger.log(' • Ensure the LLM service is running and accessible', { color: 'white' });
2395
+ }
2396
+ logger.verbose(`\nOriginal error: ${error.message}`, { color: 'gray' });
2397
+ }
2398
+ /**
2399
+ * Formats an authentication error with helpful information
2400
+ */
2401
+ function formatAuthenticationError(error, logger) {
2402
+ logger.log('\nFailed to execute command', { color: 'yellow' });
2403
+ logger.log('\nError: Authentication failed', { color: 'red' });
2404
+ logger.log('\nTroubleshooting:', { color: 'cyan' });
2405
+ logger.log(' • Verify your API key is correct', { color: 'white' });
2406
+ logger.log(' • Check that your API key has not expired', { color: 'white' });
2407
+ logger.log(' • Ensure the API key is set in your environment or config', { color: 'white' });
2408
+ logger.verbose(`\nOriginal error: ${error.message}`, { color: 'gray' });
2409
+ }
2410
+ /**
2411
+ * Formats a generic error
2412
+ */
2413
+ function formatGenericError(error, logger) {
2414
+ logger.log('\nFailed to execute command', { color: 'yellow' });
2415
+ logger.verbose(`\nError: "${error.message}"`, { color: 'red' });
2416
+ }
2354
2417
  function commandExecutor(handler) {
2355
2418
  return async (argv) => {
2356
2419
  const options = loadConfig(argv);
@@ -2359,8 +2422,16 @@ function commandExecutor(handler) {
2359
2422
  await handler(argv, logger);
2360
2423
  }
2361
2424
  catch (error) {
2362
- logger.log('\nFailed to execute command', { color: 'yellow' });
2363
- logger.verbose(`\nError: "${error.message}"`, { color: 'red' });
2425
+ // Handle specific error types with helpful messages
2426
+ if (error instanceof LangChainNetworkError) {
2427
+ formatNetworkError(error, logger);
2428
+ }
2429
+ else if (error instanceof LangChainAuthenticationError) {
2430
+ formatAuthenticationError(error, logger);
2431
+ }
2432
+ else {
2433
+ formatGenericError(error, logger);
2434
+ }
2364
2435
  logger.log('\nThanks for using coco, make it a great day! 👋🤖', { color: 'blue' });
2365
2436
  process.exit(0);
2366
2437
  }
@@ -6252,10 +6323,50 @@ async function withRetry(operation, options = {}) {
6252
6323
  throw new Error(`Operation failed after ${maxAttempts} attempts. Last error: ${lastError.message}`);
6253
6324
  }
6254
6325
 
6326
+ /**
6327
+ * Network error patterns to detect connection failures
6328
+ */
6329
+ const NETWORK_ERROR_PATTERNS = [
6330
+ 'fetch failed',
6331
+ 'ECONNREFUSED',
6332
+ 'ENOTFOUND',
6333
+ 'ETIMEDOUT',
6334
+ 'ECONNRESET',
6335
+ 'ENETUNREACH',
6336
+ 'EHOSTUNREACH',
6337
+ 'socket hang up',
6338
+ 'network request failed',
6339
+ 'Failed to fetch',
6340
+ 'getaddrinfo',
6341
+ 'connect ECONNREFUSED',
6342
+ ];
6343
+ /**
6344
+ * Checks if an error message indicates a network/connection failure
6345
+ */
6346
+ function isNetworkError(error) {
6347
+ if (!(error instanceof Error))
6348
+ return false;
6349
+ const message = error.message.toLowerCase();
6350
+ const errorCause = error?.cause?.message?.toLowerCase() || '';
6351
+ return NETWORK_ERROR_PATTERNS.some(pattern => message.includes(pattern.toLowerCase()) ||
6352
+ errorCause.includes(pattern.toLowerCase()));
6353
+ }
6255
6354
  /**
6256
6355
  * Wraps errors with additional context and converts them to LangChain errors
6257
6356
  */
6258
6357
  function handleLangChainError(error, context, additionalContext) {
6358
+ // Check for network errors first
6359
+ if (error instanceof Error && isNetworkError(error)) {
6360
+ const endpoint = additionalContext?.endpoint;
6361
+ const provider = additionalContext?.provider;
6362
+ throw new LangChainNetworkError(error.message, endpoint, provider, {
6363
+ originalError: error.name,
6364
+ originalMessage: error.message,
6365
+ stack: error.stack,
6366
+ context,
6367
+ ...additionalContext
6368
+ });
6369
+ }
6259
6370
  // If it's already a LangChain error, re-throw with additional context
6260
6371
  if (error instanceof LangChainError) {
6261
6372
  throw new LangChainExecutionError(`${context}: ${error.message}`, {
@@ -7039,21 +7150,55 @@ You must return ONLY valid JSON that matches the schema exactly. Do not include
7039
7150
  }
7040
7151
  }
7041
7152
 
7153
+ /**
7154
+ * Extracts provider and endpoint info from LLM instance if available
7155
+ */
7156
+ function extractLlmInfo(llm) {
7157
+ const info = {};
7158
+ // Try to extract provider from class name
7159
+ const className = llm?.constructor?.name || '';
7160
+ if (className.includes('Ollama')) {
7161
+ info.provider = 'ollama';
7162
+ // Try to get baseUrl from ollama instance
7163
+ if ('lc_kwargs' in llm && typeof llm.lc_kwargs === 'object' && llm.lc_kwargs !== null) {
7164
+ const kwargs = llm.lc_kwargs;
7165
+ if (typeof kwargs.baseUrl === 'string') {
7166
+ info.endpoint = kwargs.baseUrl;
7167
+ }
7168
+ }
7169
+ }
7170
+ else if (className.includes('OpenAI')) {
7171
+ info.provider = 'openai';
7172
+ }
7173
+ else if (className.includes('Anthropic')) {
7174
+ info.provider = 'anthropic';
7175
+ }
7176
+ return info;
7177
+ }
7042
7178
  /**
7043
7179
  * Executes a LangChain pipeline with the provided LLM, prompt, variables, and parser.
7044
7180
  * @param params - The execution parameters
7045
7181
  * @returns The parsed result from the LLM chain
7046
7182
  * @throws LangChainExecutionError if the chain execution fails or returns empty results
7183
+ * @throws LangChainNetworkError if a network/connection error occurs
7047
7184
  */
7048
- const executeChain = async ({ llm, prompt, variables, parser }) => {
7185
+ const executeChain = async ({ llm, prompt, variables, parser, provider, endpoint, }) => {
7049
7186
  validateRequired(llm, 'llm', 'executeChain');
7050
7187
  validateRequired(prompt, 'prompt', 'executeChain');
7051
7188
  validateRequired(variables, 'variables', 'executeChain');
7052
7189
  validateRequired(parser, 'parser', 'executeChain');
7053
7190
  // Validate that variables is an object
7054
7191
  if (typeof variables !== 'object' || Array.isArray(variables)) {
7055
- throw new LangChainExecutionError('executeChain: Variables must be a non-array object', { variables, type: typeof variables, isArray: Array.isArray(variables) });
7192
+ throw new LangChainExecutionError('executeChain: Variables must be a non-array object', {
7193
+ variables,
7194
+ type: typeof variables,
7195
+ isArray: Array.isArray(variables),
7196
+ });
7056
7197
  }
7198
+ // Extract LLM info for error reporting if not provided
7199
+ const llmInfo = extractLlmInfo(llm);
7200
+ const effectiveProvider = provider || llmInfo.provider;
7201
+ const effectiveEndpoint = endpoint || llmInfo.endpoint;
7057
7202
  try {
7058
7203
  const chain = prompt.pipe(llm).pipe(parser);
7059
7204
  const result = await chain.invoke(variables);
@@ -7064,14 +7209,27 @@ const executeChain = async ({ llm, prompt, variables, parser }) => {
7064
7209
  }
7065
7210
  catch (error) {
7066
7211
  // Re-throw LangChain errors as-is
7067
- if (error instanceof LangChainExecutionError) {
7212
+ if (error instanceof LangChainExecutionError || error instanceof LangChainNetworkError) {
7068
7213
  throw error;
7069
7214
  }
7215
+ // Check for network errors and throw specific error type
7216
+ if (error instanceof Error && isNetworkError(error)) {
7217
+ throw new LangChainNetworkError(error.message, effectiveEndpoint, effectiveProvider, {
7218
+ originalError: error.name,
7219
+ originalMessage: error.message,
7220
+ stack: error.stack,
7221
+ promptInputVariables: prompt.inputVariables,
7222
+ variableKeys: Object.keys(variables),
7223
+ parserType: parser.constructor.name,
7224
+ });
7225
+ }
7070
7226
  // Wrap other errors with context
7071
7227
  handleLangChainError(error, 'executeChain: Chain execution failed', {
7072
7228
  promptInputVariables: prompt.inputVariables,
7073
7229
  variableKeys: Object.keys(variables),
7074
- parserType: parser.constructor.name
7230
+ parserType: parser.constructor.name,
7231
+ provider: effectiveProvider,
7232
+ endpoint: effectiveEndpoint,
7075
7233
  });
7076
7234
  }
7077
7235
  };
package/dist/index.js CHANGED
@@ -68,7 +68,7 @@ var readline__namespace = /*#__PURE__*/_interopNamespaceDefault(readline);
68
68
  /**
69
69
  * Current build version from package.json
70
70
  */
71
- const BUILD_VERSION = "0.27.0";
71
+ const BUILD_VERSION = "0.27.1";
72
72
 
73
73
  const isInteractive = (config) => {
74
74
  return config?.mode === 'interactive' || !!config?.interactive;
@@ -248,6 +248,16 @@ class LangChainAuthenticationError extends LangChainError {
248
248
  super(message, context);
249
249
  }
250
250
  }
251
+ /**
252
+ * Network/connection errors (service unreachable, DNS failures, etc.)
253
+ */
254
+ class LangChainNetworkError extends LangChainError {
255
+ constructor(message, endpoint, provider, context) {
256
+ super(message, { ...context, endpoint, provider });
257
+ this.endpoint = endpoint;
258
+ this.provider = provider;
259
+ }
260
+ }
251
261
 
252
262
  /**
253
263
  * Validates that a required parameter is not null or undefined
@@ -2373,6 +2383,59 @@ class Logger {
2373
2383
  }
2374
2384
  }
2375
2385
 
2386
+ /**
2387
+ * Formats a network error with helpful troubleshooting information
2388
+ */
2389
+ function formatNetworkError(error, logger) {
2390
+ const endpoint = error.endpoint || 'unknown endpoint';
2391
+ const provider = error.provider || 'LLM service';
2392
+ logger.log('\nFailed to execute command', { color: 'yellow' });
2393
+ logger.log(`\nError: Unable to connect to ${provider}`, { color: 'red' });
2394
+ if (error.endpoint) {
2395
+ logger.log(` Endpoint: ${endpoint}`, { color: 'red' });
2396
+ }
2397
+ logger.log('\nTroubleshooting:', { color: 'cyan' });
2398
+ // Provider-specific troubleshooting
2399
+ if (provider === 'ollama' || endpoint.includes('11434')) {
2400
+ logger.log(' • Is Ollama running? Try: ollama serve', { color: 'white' });
2401
+ logger.log(' • Check if the endpoint is correct in your config', { color: 'white' });
2402
+ logger.log(` • Verify Ollama is accessible: curl ${endpoint}/api/version`, { color: 'white' });
2403
+ }
2404
+ else if (provider === 'openai' || endpoint.includes('openai')) {
2405
+ logger.log(' • Check your internet connection', { color: 'white' });
2406
+ logger.log(' • Verify the API endpoint is accessible', { color: 'white' });
2407
+ logger.log(' • If using a custom baseURL, verify it is correct', { color: 'white' });
2408
+ }
2409
+ else if (provider === 'anthropic') {
2410
+ logger.log(' • Check your internet connection', { color: 'white' });
2411
+ logger.log(' • Verify the Anthropic API is accessible', { color: 'white' });
2412
+ }
2413
+ else {
2414
+ logger.log(' • Check your internet connection', { color: 'white' });
2415
+ logger.log(' • Verify the service endpoint is correct', { color: 'white' });
2416
+ logger.log(' • Ensure the LLM service is running and accessible', { color: 'white' });
2417
+ }
2418
+ logger.verbose(`\nOriginal error: ${error.message}`, { color: 'gray' });
2419
+ }
2420
+ /**
2421
+ * Formats an authentication error with helpful information
2422
+ */
2423
+ function formatAuthenticationError(error, logger) {
2424
+ logger.log('\nFailed to execute command', { color: 'yellow' });
2425
+ logger.log('\nError: Authentication failed', { color: 'red' });
2426
+ logger.log('\nTroubleshooting:', { color: 'cyan' });
2427
+ logger.log(' • Verify your API key is correct', { color: 'white' });
2428
+ logger.log(' • Check that your API key has not expired', { color: 'white' });
2429
+ logger.log(' • Ensure the API key is set in your environment or config', { color: 'white' });
2430
+ logger.verbose(`\nOriginal error: ${error.message}`, { color: 'gray' });
2431
+ }
2432
+ /**
2433
+ * Formats a generic error
2434
+ */
2435
+ function formatGenericError(error, logger) {
2436
+ logger.log('\nFailed to execute command', { color: 'yellow' });
2437
+ logger.verbose(`\nError: "${error.message}"`, { color: 'red' });
2438
+ }
2376
2439
  function commandExecutor(handler) {
2377
2440
  return async (argv) => {
2378
2441
  const options = loadConfig(argv);
@@ -2381,8 +2444,16 @@ function commandExecutor(handler) {
2381
2444
  await handler(argv, logger);
2382
2445
  }
2383
2446
  catch (error) {
2384
- logger.log('\nFailed to execute command', { color: 'yellow' });
2385
- logger.verbose(`\nError: "${error.message}"`, { color: 'red' });
2447
+ // Handle specific error types with helpful messages
2448
+ if (error instanceof LangChainNetworkError) {
2449
+ formatNetworkError(error, logger);
2450
+ }
2451
+ else if (error instanceof LangChainAuthenticationError) {
2452
+ formatAuthenticationError(error, logger);
2453
+ }
2454
+ else {
2455
+ formatGenericError(error, logger);
2456
+ }
2386
2457
  logger.log('\nThanks for using coco, make it a great day! 👋🤖', { color: 'blue' });
2387
2458
  process.exit(0);
2388
2459
  }
@@ -6274,10 +6345,50 @@ async function withRetry(operation, options = {}) {
6274
6345
  throw new Error(`Operation failed after ${maxAttempts} attempts. Last error: ${lastError.message}`);
6275
6346
  }
6276
6347
 
6348
+ /**
6349
+ * Network error patterns to detect connection failures
6350
+ */
6351
+ const NETWORK_ERROR_PATTERNS = [
6352
+ 'fetch failed',
6353
+ 'ECONNREFUSED',
6354
+ 'ENOTFOUND',
6355
+ 'ETIMEDOUT',
6356
+ 'ECONNRESET',
6357
+ 'ENETUNREACH',
6358
+ 'EHOSTUNREACH',
6359
+ 'socket hang up',
6360
+ 'network request failed',
6361
+ 'Failed to fetch',
6362
+ 'getaddrinfo',
6363
+ 'connect ECONNREFUSED',
6364
+ ];
6365
+ /**
6366
+ * Checks if an error message indicates a network/connection failure
6367
+ */
6368
+ function isNetworkError(error) {
6369
+ if (!(error instanceof Error))
6370
+ return false;
6371
+ const message = error.message.toLowerCase();
6372
+ const errorCause = error?.cause?.message?.toLowerCase() || '';
6373
+ return NETWORK_ERROR_PATTERNS.some(pattern => message.includes(pattern.toLowerCase()) ||
6374
+ errorCause.includes(pattern.toLowerCase()));
6375
+ }
6277
6376
  /**
6278
6377
  * Wraps errors with additional context and converts them to LangChain errors
6279
6378
  */
6280
6379
  function handleLangChainError(error, context, additionalContext) {
6380
+ // Check for network errors first
6381
+ if (error instanceof Error && isNetworkError(error)) {
6382
+ const endpoint = additionalContext?.endpoint;
6383
+ const provider = additionalContext?.provider;
6384
+ throw new LangChainNetworkError(error.message, endpoint, provider, {
6385
+ originalError: error.name,
6386
+ originalMessage: error.message,
6387
+ stack: error.stack,
6388
+ context,
6389
+ ...additionalContext
6390
+ });
6391
+ }
6281
6392
  // If it's already a LangChain error, re-throw with additional context
6282
6393
  if (error instanceof LangChainError) {
6283
6394
  throw new LangChainExecutionError(`${context}: ${error.message}`, {
@@ -7061,21 +7172,55 @@ You must return ONLY valid JSON that matches the schema exactly. Do not include
7061
7172
  }
7062
7173
  }
7063
7174
 
7175
+ /**
7176
+ * Extracts provider and endpoint info from LLM instance if available
7177
+ */
7178
+ function extractLlmInfo(llm) {
7179
+ const info = {};
7180
+ // Try to extract provider from class name
7181
+ const className = llm?.constructor?.name || '';
7182
+ if (className.includes('Ollama')) {
7183
+ info.provider = 'ollama';
7184
+ // Try to get baseUrl from ollama instance
7185
+ if ('lc_kwargs' in llm && typeof llm.lc_kwargs === 'object' && llm.lc_kwargs !== null) {
7186
+ const kwargs = llm.lc_kwargs;
7187
+ if (typeof kwargs.baseUrl === 'string') {
7188
+ info.endpoint = kwargs.baseUrl;
7189
+ }
7190
+ }
7191
+ }
7192
+ else if (className.includes('OpenAI')) {
7193
+ info.provider = 'openai';
7194
+ }
7195
+ else if (className.includes('Anthropic')) {
7196
+ info.provider = 'anthropic';
7197
+ }
7198
+ return info;
7199
+ }
7064
7200
  /**
7065
7201
  * Executes a LangChain pipeline with the provided LLM, prompt, variables, and parser.
7066
7202
  * @param params - The execution parameters
7067
7203
  * @returns The parsed result from the LLM chain
7068
7204
  * @throws LangChainExecutionError if the chain execution fails or returns empty results
7205
+ * @throws LangChainNetworkError if a network/connection error occurs
7069
7206
  */
7070
- const executeChain = async ({ llm, prompt, variables, parser }) => {
7207
+ const executeChain = async ({ llm, prompt, variables, parser, provider, endpoint, }) => {
7071
7208
  validateRequired(llm, 'llm', 'executeChain');
7072
7209
  validateRequired(prompt, 'prompt', 'executeChain');
7073
7210
  validateRequired(variables, 'variables', 'executeChain');
7074
7211
  validateRequired(parser, 'parser', 'executeChain');
7075
7212
  // Validate that variables is an object
7076
7213
  if (typeof variables !== 'object' || Array.isArray(variables)) {
7077
- throw new LangChainExecutionError('executeChain: Variables must be a non-array object', { variables, type: typeof variables, isArray: Array.isArray(variables) });
7214
+ throw new LangChainExecutionError('executeChain: Variables must be a non-array object', {
7215
+ variables,
7216
+ type: typeof variables,
7217
+ isArray: Array.isArray(variables),
7218
+ });
7078
7219
  }
7220
+ // Extract LLM info for error reporting if not provided
7221
+ const llmInfo = extractLlmInfo(llm);
7222
+ const effectiveProvider = provider || llmInfo.provider;
7223
+ const effectiveEndpoint = endpoint || llmInfo.endpoint;
7079
7224
  try {
7080
7225
  const chain = prompt.pipe(llm).pipe(parser);
7081
7226
  const result = await chain.invoke(variables);
@@ -7086,14 +7231,27 @@ const executeChain = async ({ llm, prompt, variables, parser }) => {
7086
7231
  }
7087
7232
  catch (error) {
7088
7233
  // Re-throw LangChain errors as-is
7089
- if (error instanceof LangChainExecutionError) {
7234
+ if (error instanceof LangChainExecutionError || error instanceof LangChainNetworkError) {
7090
7235
  throw error;
7091
7236
  }
7237
+ // Check for network errors and throw specific error type
7238
+ if (error instanceof Error && isNetworkError(error)) {
7239
+ throw new LangChainNetworkError(error.message, effectiveEndpoint, effectiveProvider, {
7240
+ originalError: error.name,
7241
+ originalMessage: error.message,
7242
+ stack: error.stack,
7243
+ promptInputVariables: prompt.inputVariables,
7244
+ variableKeys: Object.keys(variables),
7245
+ parserType: parser.constructor.name,
7246
+ });
7247
+ }
7092
7248
  // Wrap other errors with context
7093
7249
  handleLangChainError(error, 'executeChain: Chain execution failed', {
7094
7250
  promptInputVariables: prompt.inputVariables,
7095
7251
  variableKeys: Object.keys(variables),
7096
- parserType: parser.constructor.name
7252
+ parserType: parser.constructor.name,
7253
+ provider: effectiveProvider,
7254
+ endpoint: effectiveEndpoint,
7097
7255
  });
7098
7256
  }
7099
7257
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-coco",
3
- "version": "0.27.0",
3
+ "version": "0.27.1",
4
4
  "description": "zero-effort git commits with coco.",
5
5
  "author": "gfargo <ghfargo@gmail.com>",
6
6
  "license": "MIT",