git-coco 0.14.2 → 0.14.4

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 (3) hide show
  1. package/dist/index.esm.mjs +1448 -1441
  2. package/dist/index.js +1448 -1441
  3. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -74,987 +74,589 @@ var readline__namespace = /*#__PURE__*/_interopNamespaceDefault(readline$1);
74
74
 
75
75
  // This file is auto-generated - DO NOT EDIT
76
76
  /* eslint-disable */
77
- /**
78
- * Schema ID for JSON validation
79
- */
80
- const SCHEMA_PUBLIC_URL = "http://git-co.co/schema.json";
81
77
  /**
82
78
  * Current build version from package.json
83
79
  */
84
- const BUILD_VERSION = "0.14.2";
80
+ const BUILD_VERSION = "0.14.4";
81
+
82
+ const isInteractive = (config) => {
83
+ return config?.mode === 'interactive' || !!config?.interactive;
84
+ };
85
+ const SEPERATOR = chalk.blue('─────────────');
86
+ const DIVIDER = chalk.dim(`\\`);
87
+ const LOGO = chalk.green(`┌──────┐
88
+ │┏┏┓┏┏┓│
89
+ │┗┗┛┗┗┛│
90
+ └──────┘`);
91
+ chalk.green(`┌────┐
92
+ │coco│
93
+ └────┘`);
94
+ const bannerWithHeader = (banner) => {
95
+ return chalk.green(`┌────┐
96
+ │coco│ ${banner}
97
+ └────┘`);
98
+ };
99
+ const USAGE_BANNER = chalk.green(`${LOGO}
100
+ ${chalk.bgGreen(`\xa0v${BUILD_VERSION}\xa0`) }
101
+ `);
102
+ const getCommandUsageHeader = (command) => {
103
+ return chalk.green(`${USAGE_BANNER}\n${chalk.white('Command:')}\n\xa0\xa0\xa0\xa0\xa0 $0 ${chalk.greenBright(command)} [options]`);
104
+ };
105
+ const CONFIG_ALREADY_EXISTS = (path) => {
106
+ return `existing config found in '${path}', do you want to override it?`;
107
+ };
108
+ const severityColors = [
109
+ chalk.greenBright, // 1
110
+ chalk.green, // 2
111
+ chalk.cyan, // 3
112
+ chalk.yellowBright, // 4
113
+ chalk.yellow, // 5
114
+ chalk.bgYellow, // 6
115
+ chalk.red, // 7
116
+ chalk.redBright, // 8
117
+ chalk.bgRed, // 9
118
+ chalk.bgRedBright, // 10
119
+ ];
120
+ const severityColor = (severity) => {
121
+ return severityColors[Math.min(severity - 1, severityColors.length - 1)];
122
+ };
123
+ const statusColor = (status) => {
124
+ switch (status) {
125
+ case 'completed':
126
+ return chalk.green;
127
+ case 'skipped':
128
+ return chalk.yellow;
129
+ case 'omitted':
130
+ return chalk.red;
131
+ default:
132
+ return chalk.blue;
133
+ }
134
+ };
135
+ const hotKey = (key) => chalk.dim(`(${key})`);
136
+
85
137
  /**
86
- * Generated JSON schema
138
+ * Returns a new object with all undefined keys removed
139
+ *
140
+ * @param obj Object to remove undefined keys from
141
+ * @returns
87
142
  */
88
- const schema$1 = {
89
- "$id": "http://git-co.co/schema.json",
90
- "$schema": "http://json-schema.org/draft-07/schema#",
91
- "$ref": "#/definitions/ConfigWithServiceObject",
92
- "definitions": {
93
- "ConfigWithServiceObject": {
94
- "type": "object",
95
- "additionalProperties": false,
96
- "properties": {
97
- "service": {
98
- "$ref": "#/definitions/LLMService"
99
- },
100
- "interactive": {
101
- "type": "boolean"
102
- },
103
- "verbose": {
104
- "type": "boolean",
105
- "description": "Enable verbose logging.",
106
- "default": false
107
- },
108
- "version": {
109
- "type": "boolean"
110
- },
111
- "help": {
112
- "type": "boolean"
113
- },
114
- "mode": {
115
- "type": "string",
116
- "enum": [
117
- "stdout",
118
- "interactive"
119
- ],
120
- "description": "The output destination for the generated result.\n- 'stdout': Prints the result to the standard output. This is the default behavior.\n- 'interactive': Provides an interactive prompt for editing the result & committing the changes.",
121
- "default": "stdout"
122
- },
123
- "openInEditor": {
124
- "type": "boolean",
125
- "description": "Open the commit message in an editor for editing before proceeding.",
126
- "default": false
127
- },
128
- "prompt": {
129
- "type": "string",
130
- "description": "The prompt text used for generating results."
131
- },
132
- "summarizePrompt": {
133
- "type": "string",
134
- "description": "The prompt text used specifically for generating summaries of large files."
135
- },
136
- "ignoredFiles": {
137
- "type": "array",
138
- "items": {
139
- "type": "string"
140
- },
141
- "description": "An array of file paths or patterns to be ignored during processing.\n\nNote: This is a list of patterns interpreted by the `minimatch` library.",
142
- "examples": [
143
- [
144
- "package-lock.json",
145
- "node_modules"
146
- ]
147
- ],
148
- "default": "['package-lock.json', contents of .gitignore, contents of .ignore]"
149
- },
150
- "ignoredExtensions": {
151
- "type": "array",
152
- "items": {
153
- "type": "string"
154
- },
155
- "description": "An array of file extensions to be ignored during processing.",
156
- "default": [
157
- ".map",
158
- ".lock"
159
- ]
160
- },
161
- "defaultBranch": {
162
- "type": "string",
163
- "description": "Default git branch for the repository.",
164
- "default": "main"
165
- }
166
- },
167
- "required": [
168
- "defaultBranch",
169
- "mode",
170
- "service"
171
- ]
172
- },
173
- "LLMService": {
174
- "anyOf": [
175
- {
176
- "$ref": "#/definitions/OpenAILLMService"
177
- },
178
- {
179
- "$ref": "#/definitions/OllamaLLMService"
180
- },
181
- {
182
- "$ref": "#/definitions/AnthropicLLMService"
143
+ function removeUndefined(obj) {
144
+ return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined));
145
+ }
146
+
147
+ async function updateFileSection({ filePath, startComment, endComment, getNewContent, confirmUpdate = true, confirmMessage = (path) => `A section already exists in ${path}, do you want to override it?`, }) {
148
+ const lines = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8').split(/\r?\n/) : [];
149
+ const newLines = [];
150
+ let foundSection = false;
151
+ for (let i = 0; i < lines.length; i++) {
152
+ if (lines[i].trim() === startComment) {
153
+ foundSection = true;
154
+ if (confirmUpdate) {
155
+ const confirmOverwrite = await prompts.confirm({
156
+ message: typeof confirmMessage === 'function' ? confirmMessage(filePath) : confirmMessage,
157
+ default: false,
158
+ });
159
+ if (!confirmOverwrite) {
160
+ // keep all lines until the end comment
161
+ while (i < lines.length && lines[i].trim() !== endComment) {
162
+ newLines.push(lines[i]);
163
+ i++;
164
+ }
165
+ newLines.push(endComment);
166
+ continue;
183
167
  }
184
- ]
185
- },
186
- "OpenAILLMService": {
187
- "type": "object",
188
- "additionalProperties": false,
189
- "properties": {
190
- "provider": {
191
- "$ref": "#/definitions/LLMProvider"
192
- },
193
- "model": {
194
- "$ref": "#/definitions/LLMModel"
195
- },
196
- "fields": {
197
- "type": "object",
198
- "additionalProperties": false,
199
- "properties": {
200
- "verbose": {
201
- "type": "boolean"
202
- },
203
- "callbacks": {
204
- "$ref": "#/definitions/Callbacks"
205
- },
206
- "tags": {
207
- "type": "array",
208
- "items": {
209
- "type": "string"
210
- }
211
- },
212
- "metadata": {
213
- "type": "object",
214
- "additionalProperties": {}
215
- },
216
- "maxConcurrency": {
217
- "type": "number",
218
- "description": "The maximum number of concurrent calls that can be made. Defaults to `Infinity`, which means no limit."
219
- },
220
- "maxRetries": {
221
- "type": "number",
222
- "description": "The maximum number of retries that can be made for a single call, with an exponential backoff between each attempt. Defaults to 6."
223
- },
224
- "onFailedAttempt": {
225
- "$ref": "#/definitions/FailedAttemptHandler",
226
- "description": "Custom handler to handle failed attempts. Takes the originally thrown error object as input, and should itself throw an error if the input error is not retryable."
227
- },
228
- "callbackManager": {
229
- "$ref": "#/definitions/CallbackManager",
230
- "deprecated": "Use `callbacks` instead"
231
- },
232
- "cache": {
233
- "anyOf": [
234
- {
235
- "$ref": "#/definitions/BaseCache"
236
- },
237
- {
238
- "type": "boolean"
239
- }
240
- ]
241
- },
242
- "concurrency": {
243
- "type": "number",
244
- "deprecated": "Use `maxConcurrency` instead"
245
- },
246
- "bestOf": {
247
- "type": "number",
248
- "description": "Generates `bestOf` completions server side and returns the \"best\""
249
- },
250
- "batchSize": {
251
- "type": "number",
252
- "description": "Batch size to use when passing multiple documents to generate"
253
- },
254
- "temperature": {
255
- "type": "number",
256
- "description": "Sampling temperature to use"
257
- },
258
- "maxTokens": {
259
- "type": "number",
260
- "description": "Maximum number of tokens to generate in the completion. -1 returns as many tokens as possible given the prompt and the model's maximum context size."
261
- },
262
- "topP": {
263
- "type": "number",
264
- "description": "Total probability mass of tokens to consider at each step"
265
- },
266
- "frequencyPenalty": {
267
- "type": "number",
268
- "description": "Penalizes repeated tokens according to frequency"
269
- },
270
- "presencePenalty": {
271
- "type": "number",
272
- "description": "Penalizes repeated tokens"
273
- },
274
- "n": {
275
- "type": "number",
276
- "description": "Number of completions to generate for each prompt"
277
- },
278
- "logitBias": {
279
- "type": "object",
280
- "additionalProperties": {
281
- "type": "number"
282
- },
283
- "description": "Dictionary used to adjust the probability of specific tokens being generated"
284
- },
285
- "user": {
286
- "type": "string",
287
- "description": "Unique string identifier representing your end-user, which can help OpenAI to monitor and detect abuse."
288
- },
289
- "streaming": {
290
- "type": "boolean",
291
- "description": "Whether to stream the results or not. Enabling disables tokenUsage reporting"
292
- },
293
- "streamUsage": {
294
- "type": "boolean",
295
- "description": "Whether or not to include token usage data in streamed chunks.",
296
- "default": true
297
- },
298
- "modelName": {
299
- "type": "string",
300
- "description": "Model name to use Alias for `model`"
301
- },
302
- "model": {
303
- "type": "string",
304
- "description": "Model name to use"
305
- },
306
- "modelKwargs": {
307
- "type": "object",
308
- "description": "Holds any additional parameters that are valid to pass to {@link * https://platform.openai.com/docs/api-reference/completions/create | } * `openai.createCompletion`} that are not explicitly specified on this class."
309
- },
310
- "stop": {
311
- "type": "array",
312
- "items": {
313
- "type": "string"
314
- },
315
- "description": "List of stop words to use when generating Alias for `stopSequences`"
316
- },
317
- "stopSequences": {
318
- "type": "array",
319
- "items": {
320
- "type": "string"
321
- },
322
- "description": "List of stop words to use when generating"
323
- },
324
- "timeout": {
325
- "type": "number",
326
- "description": "Timeout to use when making requests to OpenAI."
327
- },
328
- "openAIApiKey": {
329
- "type": "string",
330
- "description": "API key to use when making requests to OpenAI. Defaults to the value of `OPENAI_API_KEY` environment variable. Alias for `apiKey`"
331
- },
332
- "apiKey": {
333
- "type": "string",
334
- "description": "API key to use when making requests to OpenAI. Defaults to the value of `OPENAI_API_KEY` environment variable."
335
- }
336
- }
337
- },
338
- "tokenLimit": {
339
- "type": "number",
340
- "description": "The maximum number of tokens per request.",
341
- "default": 2048
342
- },
343
- "temperature": {
344
- "type": "number",
345
- "description": "The temperature value controls the randomness of the generated output. Higher values (e.g., 0.8) make the output more random, while lower values (e.g., 0.2) make it more deterministic.",
346
- "default": 0.4
347
- },
348
- "maxConcurrent": {
349
- "type": "number",
350
- "description": "The maximum number of requests to make concurrently.",
351
- "default": 6
352
- },
353
- "authentication": {
354
- "anyOf": [
355
- {
356
- "type": "object",
357
- "properties": {
358
- "type": {
359
- "type": "string",
360
- "const": "None"
361
- },
362
- "credentials": {
363
- "not": {}
364
- }
365
- },
366
- "required": [
367
- "type"
368
- ],
369
- "additionalProperties": false
370
- },
371
- {
372
- "type": "object",
373
- "properties": {
374
- "type": {
375
- "type": "string",
376
- "const": "OAuth"
377
- },
378
- "credentials": {
379
- "type": "object",
380
- "properties": {
381
- "clientId": {
382
- "type": "string"
383
- },
384
- "clientSecret": {
385
- "type": "string"
386
- },
387
- "token": {
388
- "type": "string"
389
- }
390
- },
391
- "additionalProperties": false
392
- }
393
- },
394
- "required": [
395
- "type",
396
- "credentials"
397
- ],
398
- "additionalProperties": false
399
- },
400
- {
401
- "type": "object",
402
- "properties": {
403
- "type": {
404
- "type": "string",
405
- "const": "APIKey"
406
- },
407
- "credentials": {
408
- "type": "object",
409
- "properties": {
410
- "apiKey": {
411
- "type": "string"
412
- }
413
- },
414
- "required": [
415
- "apiKey"
416
- ],
417
- "additionalProperties": false
418
- }
419
- },
420
- "required": [
421
- "type",
422
- "credentials"
423
- ],
424
- "additionalProperties": false
425
- }
426
- ]
427
- },
428
- "requestOptions": {
429
- "type": "object",
430
- "properties": {
431
- "timeout": {
432
- "type": "number"
433
- },
434
- "maxRetries": {
435
- "type": "number"
436
- }
437
- },
438
- "additionalProperties": false
439
- }
440
- },
441
- "required": [
442
- "authentication",
443
- "model",
444
- "provider"
445
- ]
446
- },
447
- "LLMProvider": {
448
- "type": "string",
449
- "enum": [
450
- "openai",
451
- "ollama",
452
- "anthropic"
453
- ]
454
- },
455
- "LLMModel": {
456
- "anyOf": [
457
- {
458
- "type": "string",
459
- "enum": [
460
- "davinci-002",
461
- "babbage-002",
462
- "text-davinci-003",
463
- "text-davinci-002",
464
- "text-davinci-001",
465
- "text-curie-001",
466
- "text-babbage-001",
467
- "text-ada-001",
468
- "davinci",
469
- "curie",
470
- "babbage",
471
- "ada",
472
- "code-davinci-002",
473
- "code-davinci-001",
474
- "code-cushman-002",
475
- "code-cushman-001",
476
- "davinci-codex",
477
- "cushman-codex",
478
- "text-davinci-edit-001",
479
- "code-davinci-edit-001",
480
- "text-embedding-ada-002",
481
- "text-similarity-davinci-001",
482
- "text-similarity-curie-001",
483
- "text-similarity-babbage-001",
484
- "text-similarity-ada-001",
485
- "text-search-davinci-doc-001",
486
- "text-search-curie-doc-001",
487
- "text-search-babbage-doc-001",
488
- "text-search-ada-doc-001",
489
- "code-search-babbage-code-001",
490
- "code-search-ada-code-001",
491
- "gpt2",
492
- "gpt-3.5-turbo",
493
- "gpt-35-turbo",
494
- "gpt-3.5-turbo-0301",
495
- "gpt-3.5-turbo-0613",
496
- "gpt-3.5-turbo-1106",
497
- "gpt-3.5-turbo-0125",
498
- "gpt-3.5-turbo-16k",
499
- "gpt-3.5-turbo-16k-0613",
500
- "gpt-3.5-turbo-instruct",
501
- "gpt-3.5-turbo-instruct-0914",
502
- "gpt-4",
503
- "gpt-4-0314",
504
- "gpt-4-0613",
505
- "gpt-4-32k",
506
- "gpt-4-32k-0314",
507
- "gpt-4-32k-0613",
508
- "gpt-4-turbo",
509
- "gpt-4-turbo-2024-04-09",
510
- "gpt-4-turbo-preview",
511
- "gpt-4-1106-preview",
512
- "gpt-4-0125-preview",
513
- "gpt-4-vision-preview",
514
- "gpt-4o",
515
- "gpt-4o-2024-05-13"
516
- ]
517
- },
518
- {
519
- "$ref": "#/definitions/OllamaModel"
520
- },
521
- {
522
- "$ref": "#/definitions/AnthropicModel"
523
- }
524
- ]
525
- },
526
- "OllamaModel": {
527
- "type": "string",
528
- "enum": [
529
- "codegemma:2b",
530
- "codegemma:7b-code",
531
- "codegemma",
532
- "codellama:13b",
533
- "codellama:34b",
534
- "codellama:70b",
535
- "codellama:7b",
536
- "codellama:instruct",
537
- "codellama:latest",
538
- "codellama",
539
- "gemma:2b",
540
- "gemma:7b",
541
- "gemma:latest",
542
- "gemma",
543
- "llama2:13b",
544
- "llama2:70b",
545
- "llama2:chat",
546
- "llama2:latest",
547
- "llama2:text",
548
- "llama2",
549
- "llama3:70b-text",
550
- "llama3:70b",
551
- "llama3:latest",
552
- "llama3:text",
553
- "llama3.1:70b",
554
- "llama3.1:8b",
555
- "llama3.1:latest",
556
- "llama3.2",
557
- "llama3.2:latest",
558
- "llama3.2:1b",
559
- "llama3.2:3b",
560
- "llama3.2:1b-instruct-fp16",
561
- "llama3.2:1b-instruct-q3_K_M",
562
- "llama3",
563
- "mistral:7b",
564
- "mistral:latest",
565
- "mistral:text",
566
- "mistral",
567
- "phi3:14b",
568
- "phi3:3.8b",
569
- "phi3:instruct",
570
- "phi3:medium-128k",
571
- "phi3:medium-4k",
572
- "phi3:medium",
573
- "phi3",
574
- "qwen2:0.5b",
575
- "qwen2:1.5b",
576
- "qwen2:72b-text",
577
- "qwen2:72b",
578
- "qwen2"
579
- ]
580
- },
581
- "AnthropicModel": {
582
- "type": "string",
583
- "enum": [
584
- "claude-3-5-sonnet-20240620",
585
- "claude-3-opus-20240229",
586
- "claude-3-sonnet-20240229",
587
- "claude-3-haiku-20240307",
588
- "claude-2.1",
589
- "claude-2.0"
590
- ]
591
- },
592
- "Callbacks": {
593
- "anyOf": [
594
- {
595
- "$ref": "#/definitions/CallbackManager"
596
- },
597
- {
598
- "type": "array",
599
- "items": {
600
- "anyOf": [
601
- {
602
- "$ref": "#/definitions/BaseCallbackHandler"
603
- },
604
- {
605
- "$ref": "#/definitions/CallbackHandlerMethods"
606
- }
607
- ]
608
- }
609
- }
610
- ]
611
- },
612
- "CallbackManager": {
613
- "type": "object",
614
- "properties": {
615
- "handlers": {
616
- "type": "array",
617
- "items": {
618
- "$ref": "#/definitions/BaseCallbackHandler"
619
- }
620
- },
621
- "inheritableHandlers": {
622
- "type": "array",
623
- "items": {
624
- "$ref": "#/definitions/BaseCallbackHandler"
625
- }
626
- },
627
- "tags": {
628
- "type": "array",
629
- "items": {
630
- "type": "string"
631
- }
632
- },
633
- "inheritableTags": {
634
- "type": "array",
635
- "items": {
636
- "type": "string"
637
- }
638
- },
639
- "metadata": {
640
- "type": "object",
641
- "additionalProperties": {}
642
- },
643
- "inheritableMetadata": {
644
- "type": "object",
645
- "additionalProperties": {}
646
- },
647
- "name": {
648
- "type": "string"
649
- },
650
- "_parentRunId": {
651
- "type": "string"
652
- }
653
- },
654
- "required": [
655
- "handlers",
656
- "inheritableHandlers",
657
- "tags",
658
- "inheritableTags",
659
- "metadata",
660
- "inheritableMetadata",
661
- "name"
662
- ],
663
- "additionalProperties": false
168
+ }
169
+ newLines.push(startComment);
170
+ // Insert the new content
171
+ const newContent = await getNewContent();
172
+ newLines.push(newContent);
173
+ // Skip the existing content of the section
174
+ while (i < lines.length && lines[i].trim() !== endComment) {
175
+ i++;
176
+ }
177
+ newLines.push(endComment);
178
+ continue;
179
+ }
180
+ if (!foundSection || lines[i].trim() !== endComment) {
181
+ newLines.push(lines[i]);
182
+ }
183
+ }
184
+ // If section wasn't found, append it at the end
185
+ if (!foundSection) {
186
+ newLines.push('\n' + startComment);
187
+ const newContent = await getNewContent();
188
+ newLines.push(newContent);
189
+ newLines.push(endComment);
190
+ }
191
+ // Write the updated contents back to the file
192
+ fs.writeFileSync(filePath, newLines.join('\n'));
193
+ }
194
+
195
+ const template$5 = `GOAL: Use functional abstractions to summarize the following text
196
+
197
+ RULES: Avoid phrases like "this change", "this code", or "this function" etc. Instead refer to the function, variable, or class by name.
198
+
199
+ TEXT:"""{text}"""
200
+ `;
201
+ const inputVariables$4 = ['text'];
202
+ const SUMMARIZE_PROMPT = new prompts$1.PromptTemplate({
203
+ inputVariables: inputVariables$4,
204
+ template: template$5,
205
+ });
206
+
207
+ /**
208
+ * Retrieves the provider and model from the given configuration object.
209
+ * @param config The configuration object.
210
+ * @returns An object containing the provider and model.
211
+ * @throws Error if the configuration is invalid or missing required properties.
212
+ */
213
+ function getModelAndProviderFromConfig(config) {
214
+ if (!config.service) {
215
+ throw new Error('Invalid service: undefined');
216
+ }
217
+ const { provider, model } = config.service;
218
+ if (!model || !provider) {
219
+ throw new Error(`Invalid service: ${config.service}`);
220
+ }
221
+ return { provider, model };
222
+ }
223
+ /**
224
+ * Retrieve appropriate API key based on selected model
225
+ * @param service
226
+ * @param options
227
+ * @returns API Key
228
+ */
229
+ function getApiKeyForModel(config) {
230
+ const { provider } = getModelAndProviderFromConfig(config);
231
+ switch (provider) {
232
+ case 'openai':
233
+ return getDefaultServiceApiKey(config);
234
+ default:
235
+ return getDefaultServiceApiKey(config);
236
+ }
237
+ }
238
+ /**
239
+ * Retrieves the default service API key from the given configuration.
240
+ * @param config The configuration object.
241
+ * @returns The default service API key.
242
+ */
243
+ function getDefaultServiceApiKey(config) {
244
+ const service = config.service;
245
+ if (service.authentication.type === 'APIKey') {
246
+ return service.authentication.credentials?.apiKey;
247
+ }
248
+ else if (service.authentication.type === 'OAuth') {
249
+ return service.authentication.credentials?.token;
250
+ }
251
+ return '';
252
+ }
253
+ const DEFAULT_OPENAI_LLM_SERVICE = {
254
+ provider: 'openai',
255
+ model: 'gpt-4',
256
+ tokenLimit: 2024,
257
+ temperature: 0.32,
258
+ authentication: {
259
+ type: 'APIKey',
260
+ credentials: {
261
+ apiKey: '',
664
262
  },
665
- "BaseCallbackHandler": {
666
- "type": "object",
667
- "properties": {
668
- "lc_serializable": {
669
- "type": "boolean"
670
- },
671
- "lc_kwargs": {
672
- "$ref": "#/definitions/SerializedFields"
673
- },
674
- "lc_namespace": {
675
- "type": "array",
676
- "items": {
677
- "type": "string"
678
- },
679
- "description": "A path to the module that contains the class, eg. [\"langchain\", \"llms\"] Usually should be the same as the entrypoint the class is exported from."
680
- },
681
- "ignoreLLM": {
682
- "type": "boolean"
683
- },
684
- "ignoreChain": {
685
- "type": "boolean"
686
- },
687
- "ignoreAgent": {
688
- "type": "boolean"
689
- },
690
- "ignoreRetriever": {
691
- "type": "boolean"
263
+ },
264
+ };
265
+ const DEFAULT_OLLAMA_LLM_SERVICE = {
266
+ provider: 'ollama',
267
+ model: 'llama3',
268
+ endpoint: 'http://localhost:11434',
269
+ maxConcurrent: 1,
270
+ tokenLimit: 2024,
271
+ temperature: 0.4,
272
+ authentication: {
273
+ type: 'None',
274
+ credentials: undefined,
275
+ },
276
+ };
277
+ /**
278
+ * Retrieves the default service configuration based on the provided alias and optional model.
279
+ * @param provider - The alias of the service.
280
+ * @param model - The optional model to be used.
281
+ * @returns The default service configuration.
282
+ * @throws Error if the alias is invalid or undefined.
283
+ */
284
+ function getDefaultServiceConfigFromAlias(provider, model) {
285
+ switch (provider) {
286
+ case 'anthropic':
287
+ return {
288
+ ...DEFAULT_OPENAI_LLM_SERVICE,
289
+ model: model || DEFAULT_OPENAI_LLM_SERVICE.model,
290
+ };
291
+ case 'ollama':
292
+ return {
293
+ ...DEFAULT_OLLAMA_LLM_SERVICE,
294
+ model: model || DEFAULT_OLLAMA_LLM_SERVICE.model,
295
+ };
296
+ case 'openai':
297
+ default:
298
+ return {
299
+ ...DEFAULT_OPENAI_LLM_SERVICE,
300
+ model: model || DEFAULT_OPENAI_LLM_SERVICE.model,
301
+ };
302
+ }
303
+ }
304
+
305
+ const DEFAULT_IGNORED_FILES = ['package-lock.json', 'yarn.lock', 'node_modules'];
306
+ const DEFAULT_IGNORED_EXTENSIONS = ['.map', '.lock'];
307
+ const COCO_CONFIG_START_COMMENT = '# -- start coco config --';
308
+ const COCO_CONFIG_END_COMMENT = '# -- end coco config --';
309
+ /**
310
+ * Default Config
311
+ *
312
+ * @type {Config}
313
+ */
314
+ const DEFAULT_CONFIG$1 = {
315
+ mode: 'stdout',
316
+ verbose: false,
317
+ defaultBranch: 'main',
318
+ service: getDefaultServiceConfigFromAlias('openai'),
319
+ summarizePrompt: SUMMARIZE_PROMPT.template,
320
+ ignoredFiles: DEFAULT_IGNORED_FILES,
321
+ ignoredExtensions: DEFAULT_IGNORED_EXTENSIONS,
322
+ };
323
+ /**
324
+ * Create a named export of all config keys for use in other modules.
325
+ *
326
+ * @see Used in `src/lib/config/services/env.ts` to validate all env vars.
327
+ *
328
+ * @type {string[]}
329
+ */
330
+ const CONFIG_KEYS = Object.keys({
331
+ ...DEFAULT_CONFIG$1,
332
+ prompt: '',
333
+ });
334
+
335
+ /**
336
+ * Load environment variables
337
+ *
338
+ * @param {Config} config
339
+ * @returns {Config} Updated config
340
+ **/
341
+ function loadEnvConfig(config) {
342
+ const envConfig = {};
343
+ const envKeys = [...CONFIG_KEYS, 'COCO_SERVICE_PROVIDER', 'COCO_SERVICE_MODEL', 'OPEN_AI_KEY'];
344
+ envKeys.forEach((key) => {
345
+ const envVarName = toEnvVarName(key);
346
+ const envValue = parseEnvValue(key, process.env[envVarName]);
347
+ if (envValue === undefined) {
348
+ return;
349
+ }
350
+ if (key === 'COCO_SERVICE_PROVIDER' || key === 'COCO_SERVICE_MODEL' || key === 'OPEN_AI_KEY') {
351
+ // NOTE: We want to ensure that the service object is always defined
352
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
353
+ // @ts-ignore
354
+ envConfig.service = envConfig.service || {};
355
+ handleServiceEnvVar(envConfig.service, key, envValue);
356
+ }
357
+ else {
358
+ if (key === 'service' || !envValue) {
359
+ return;
360
+ }
361
+ envConfig[key] = envValue;
362
+ }
363
+ });
364
+ return { ...config, ...removeUndefined(envConfig) };
365
+ }
366
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
367
+ function handleServiceEnvVar(service, key, value) {
368
+ switch (key) {
369
+ case 'COCO_SERVICE_PROVIDER':
370
+ service.provider = value;
371
+ break;
372
+ case 'COCO_SERVICE_MODEL':
373
+ service.model = value;
374
+ break;
375
+ case 'OPEN_AI_KEY':
376
+ if (service.provider === 'openai') {
377
+ service.fields = { apiKey: value };
378
+ }
379
+ break;
380
+ }
381
+ }
382
+ function parseEnvValue(key, value) {
383
+ switch (true) {
384
+ // Handle undefined values
385
+ case value === undefined:
386
+ return undefined;
387
+ // Handle comma separated strings for ignoredFiles and ignoredExtensions arrays
388
+ case (key === 'ignoredFiles' || key === 'ignoredExtensions') &&
389
+ typeof value === 'string' &&
390
+ value.includes(','):
391
+ return value.split(',');
392
+ // Handle boolean values
393
+ case typeof value === 'string' && (value === 'false' || value === 'true'):
394
+ return value === 'true';
395
+ // Handle number values
396
+ case typeof value === 'string' && !isNaN(Number(value)):
397
+ return Number(value);
398
+ default:
399
+ return value;
400
+ }
401
+ }
402
+ function toEnvVarName(key) {
403
+ if (key === 'service') {
404
+ return key;
405
+ }
406
+ if (key.includes('COCO_')) {
407
+ return key;
408
+ }
409
+ return `COCO_${key.replace(/([A-Z])/g, '_$1').toLocaleUpperCase()}`;
410
+ }
411
+ function formatEnvValue(value) {
412
+ if (typeof value === 'number') {
413
+ return `${value}`;
414
+ }
415
+ else if (Array.isArray(value)) {
416
+ return `${value.join(',')}`;
417
+ }
418
+ else if (typeof value === 'string') {
419
+ // Escape newlines and tabs in strings
420
+ return `${value.replace(/\n/g, '\\n').replace(/\t/g, '\\t')}`;
421
+ }
422
+ return `${value}`;
423
+ }
424
+ const appendToEnvFile = async (filePath, config) => {
425
+ const getNewContent = async () => {
426
+ return Object.entries(config)
427
+ .map(([key, value]) => {
428
+ if (key === 'service') {
429
+ const service = value;
430
+ return `${service.provider ? `COCO_SERVICE_PROVIDER=${service.provider}` : ''}\n${service.model ? `COCO_SERVICE_MODEL=${service.model}` : ''}\n${service.authentication.type === 'APIKey'
431
+ ? `OPEN_AI_KEY=${service.authentication.credentials.apiKey}`
432
+ : ''}`;
433
+ }
434
+ const envVarName = toEnvVarName(key);
435
+ const envValue = formatEnvValue(value);
436
+ return `${envVarName}=${envValue}`;
437
+ })
438
+ .join('\n');
439
+ };
440
+ await updateFileSection({
441
+ filePath,
442
+ startComment: COCO_CONFIG_START_COMMENT,
443
+ endComment: COCO_CONFIG_END_COMMENT,
444
+ getNewContent,
445
+ confirmMessage: CONFIG_ALREADY_EXISTS,
446
+ });
447
+ };
448
+
449
+ /**
450
+ * Load git profile config (from ~/.gitconfig)
451
+ *
452
+ * @param {Config} config
453
+ * @returns {Config} Updated config
454
+ **/
455
+ function loadGitConfig(config) {
456
+ const gitConfigPath = path__namespace.join(os__namespace.homedir(), '.gitconfig');
457
+ if (fs__namespace.existsSync(gitConfigPath)) {
458
+ const gitConfigRaw = fs__namespace.readFileSync(gitConfigPath, 'utf-8');
459
+ const gitConfigParsed = ini__namespace.parse(gitConfigRaw);
460
+ const gitConfigServiceObject = gitConfigParsed.coco?.service;
461
+ let service = config.service;
462
+ if (gitConfigServiceObject) {
463
+ const gitServiceConfig = JSON.parse(gitConfigServiceObject);
464
+ service = gitServiceConfig || config?.service;
465
+ }
466
+ config = {
467
+ ...config,
468
+ service: service,
469
+ prompt: gitConfigParsed.coco?.prompt || config.prompt,
470
+ mode: gitConfigParsed.coco?.mode || config.mode,
471
+ summarizePrompt: gitConfigParsed.coco?.summarizePrompt || config.summarizePrompt,
472
+ ignoredFiles: gitConfigParsed.coco?.ignoredFiles || config.ignoredFiles,
473
+ ignoredExtensions: gitConfigParsed.coco?.ignoredExtensions || config.ignoredExtensions,
474
+ defaultBranch: gitConfigParsed.coco?.defaultBranch || config.defaultBranch,
475
+ verbose: gitConfigParsed.coco?.verbose || config.verbose,
476
+ };
477
+ }
478
+ return removeUndefined(config);
479
+ }
480
+ /**
481
+ * Appends the provided configuration to a git config file.
482
+ *
483
+ * @param filePath - The path to the .gitconfig
484
+ * @param config - The configuration object to append.
485
+ */
486
+ const appendToGitConfig = async (filePath, config) => {
487
+ if (!fs__namespace.existsSync(filePath)) {
488
+ throw new Error(`File ${filePath} does not exist.`);
489
+ }
490
+ const header = '[coco]';
491
+ const getNewContent = async () => {
492
+ const contentLines = [header];
493
+ for (const key in config) {
494
+ const value = config[key];
495
+ if (typeof value === 'object') {
496
+ // Serialize object to JSON string
497
+ contentLines.push(`\t${key} = ${JSON.stringify(value)}`);
498
+ }
499
+ else if (typeof value === 'string' && value.includes('\n')) {
500
+ // Wrap strings with new lines in quotes
501
+ contentLines.push(`\t${key} = ${JSON.stringify(value)}`);
502
+ }
503
+ else {
504
+ contentLines.push(`\t${key} = ${value}`);
505
+ }
506
+ }
507
+ return contentLines.join('\n');
508
+ };
509
+ await updateFileSection({
510
+ filePath,
511
+ startComment: COCO_CONFIG_START_COMMENT,
512
+ endComment: COCO_CONFIG_END_COMMENT,
513
+ getNewContent,
514
+ confirmUpdate: true,
515
+ confirmMessage: CONFIG_ALREADY_EXISTS,
516
+ });
517
+ };
518
+
519
+ /**
520
+ * Load .gitignore in project root
521
+ *
522
+ * @param {Config} config
523
+ * @returns
524
+ */
525
+ function loadGitignore(config) {
526
+ if (fs__namespace.existsSync('.gitignore')) {
527
+ const gitignoreContent = fs__namespace.readFileSync('.gitignore', 'utf-8');
528
+ config.ignoredFiles = [
529
+ ...(config?.ignoredFiles || []),
530
+ ...gitignoreContent.split('\n').filter((line) => line.trim() !== '' && !line.startsWith('#')),
531
+ ];
532
+ }
533
+ return config;
534
+ }
535
+ /**
536
+ * Load .ignore in project root
537
+ *
538
+ * @param {Config} config
539
+ * @returns
540
+ */
541
+ function loadIgnore(config) {
542
+ if (fs__namespace.existsSync('.ignore')) {
543
+ const ignoreContent = fs__namespace.readFileSync('.ignore', 'utf-8');
544
+ config.ignoredFiles = [
545
+ ...(config?.ignoredFiles || []),
546
+ ...ignoreContent.split('\n').filter((line) => line.trim() !== '' && !line.startsWith('#')),
547
+ ];
548
+ }
549
+ return config;
550
+ }
551
+
552
+ // This file is auto-generated - DO NOT EDIT
553
+ /* eslint-disable */
554
+ /**
555
+ * Schema ID for JSON validation
556
+ */
557
+ const SCHEMA_PUBLIC_URL = "http://git-co.co/schema.json";
558
+ /**
559
+ * Generated JSON schema
560
+ */
561
+ const schema$1 = {
562
+ "$id": "http://git-co.co/schema.json",
563
+ "$schema": "http://json-schema.org/draft-07/schema#",
564
+ "$ref": "#/definitions/ConfigWithServiceObject",
565
+ "definitions": {
566
+ "ConfigWithServiceObject": {
567
+ "type": "object",
568
+ "additionalProperties": false,
569
+ "properties": {
570
+ "service": {
571
+ "$ref": "#/definitions/LLMService"
692
572
  },
693
- "ignoreCustomEvent": {
573
+ "interactive": {
694
574
  "type": "boolean"
695
575
  },
696
- "_awaitHandler": {
697
- "type": "boolean"
576
+ "verbose": {
577
+ "type": "boolean",
578
+ "description": "Enable verbose logging.",
579
+ "default": false
698
580
  },
699
- "raiseError": {
581
+ "version": {
700
582
  "type": "boolean"
701
583
  },
702
- "name": {
703
- "type": "string"
704
- },
705
- "awaitHandlers": {
584
+ "help": {
706
585
  "type": "boolean"
707
- }
708
- },
709
- "required": [
710
- "awaitHandlers",
711
- "ignoreAgent",
712
- "ignoreChain",
713
- "ignoreCustomEvent",
714
- "ignoreLLM",
715
- "ignoreRetriever",
716
- "lc_kwargs",
717
- "lc_namespace",
718
- "lc_serializable",
719
- "name",
720
- "raiseError"
721
- ],
722
- "additionalProperties": false,
723
- "description": "Abstract base class for creating callback handlers in the LangChain framework. It provides a set of optional methods that can be overridden in derived classes to handle various events during the execution of a LangChain application."
724
- },
725
- "SerializedFields": {
726
- "type": "object"
727
- },
728
- "CallbackHandlerMethods": {
729
- "type": "object",
730
- "additionalProperties": false,
731
- "description": "Base interface for callbacks. All methods are optional. If a method is not implemented, it will be ignored. If a method is implemented, it will be called at the appropriate time. All methods are called with the run ID of the LLM/ChatModel/Chain that is running, which is generated by the CallbackManager."
732
- },
733
- "FailedAttemptHandler": {
734
- "$comment": "(error: any) => any",
735
- "type": "object",
736
- "properties": {
737
- "namedArgs": {
738
- "type": "object",
739
- "properties": {
740
- "error": {}
741
- },
742
- "required": [
743
- "error"
744
- ],
745
- "additionalProperties": false
746
- }
747
- }
748
- },
749
- "BaseCache": {
750
- "type": "object",
751
- "additionalProperties": false,
752
- "description": "Base class for all caches. All caches should extend this class."
753
- },
754
- "OllamaLLMService": {
755
- "type": "object",
756
- "additionalProperties": false,
757
- "properties": {
758
- "provider": {
759
- "$ref": "#/definitions/LLMProvider"
760
- },
761
- "model": {
762
- "$ref": "#/definitions/LLMModel"
763
- },
764
- "endpoint": {
765
- "type": "string"
766
586
  },
767
- "fields": {
768
- "type": "object",
769
- "additionalProperties": false,
770
- "properties": {
771
- "verbose": {
772
- "type": "boolean"
773
- },
774
- "callbacks": {
775
- "$ref": "#/definitions/Callbacks"
776
- },
777
- "tags": {
778
- "type": "array",
779
- "items": {
780
- "type": "string"
781
- }
782
- },
783
- "metadata": {
784
- "type": "object",
785
- "additionalProperties": {}
786
- },
787
- "maxConcurrency": {
788
- "type": "number",
789
- "description": "The maximum number of concurrent calls that can be made. Defaults to `Infinity`, which means no limit."
790
- },
791
- "maxRetries": {
792
- "type": "number",
793
- "description": "The maximum number of retries that can be made for a single call, with an exponential backoff between each attempt. Defaults to 6."
794
- },
795
- "onFailedAttempt": {
796
- "$ref": "#/definitions/FailedAttemptHandler",
797
- "description": "Custom handler to handle failed attempts. Takes the originally thrown error object as input, and should itself throw an error if the input error is not retryable."
798
- },
799
- "callbackManager": {
800
- "$ref": "#/definitions/CallbackManager",
801
- "deprecated": "Use `callbacks` instead"
802
- },
803
- "cache": {
804
- "anyOf": [
805
- {
806
- "$ref": "#/definitions/BaseCache"
807
- },
808
- {
809
- "type": "boolean"
810
- }
811
- ]
812
- },
813
- "concurrency": {
814
- "type": "number",
815
- "deprecated": "Use `maxConcurrency` instead"
816
- },
817
- "embeddingOnly": {
818
- "type": "boolean"
819
- },
820
- "f16KV": {
821
- "type": "boolean"
822
- },
823
- "frequencyPenalty": {
824
- "type": "number"
825
- },
826
- "headers": {
827
- "type": "object",
828
- "additionalProperties": {
829
- "type": "string"
830
- }
831
- },
832
- "keepAlive": {
833
- "type": "string"
834
- },
835
- "logitsAll": {
836
- "type": "boolean"
837
- },
838
- "lowVram": {
839
- "type": "boolean"
840
- },
841
- "mainGpu": {
842
- "type": "number"
843
- },
844
- "model": {
845
- "type": "string"
846
- },
847
- "baseUrl": {
848
- "type": "string"
849
- },
850
- "mirostat": {
851
- "type": "number"
852
- },
853
- "mirostatEta": {
854
- "type": "number"
855
- },
856
- "mirostatTau": {
857
- "type": "number"
858
- },
859
- "numBatch": {
860
- "type": "number"
861
- },
862
- "numCtx": {
863
- "type": "number"
864
- },
865
- "numGpu": {
866
- "type": "number"
867
- },
868
- "numGqa": {
869
- "type": "number"
870
- },
871
- "numKeep": {
872
- "type": "number"
873
- },
874
- "numPredict": {
875
- "type": "number"
876
- },
877
- "numThread": {
878
- "type": "number"
879
- },
880
- "penalizeNewline": {
881
- "type": "boolean"
882
- },
883
- "presencePenalty": {
884
- "type": "number"
885
- },
886
- "repeatLastN": {
887
- "type": "number"
888
- },
889
- "repeatPenalty": {
890
- "type": "number"
891
- },
892
- "ropeFrequencyBase": {
893
- "type": "number"
894
- },
895
- "ropeFrequencyScale": {
896
- "type": "number"
897
- },
898
- "temperature": {
899
- "type": "number"
900
- },
901
- "stop": {
902
- "type": "array",
903
- "items": {
904
- "type": "string"
905
- }
906
- },
907
- "tfsZ": {
908
- "type": "number"
909
- },
910
- "topK": {
911
- "type": "number"
912
- },
913
- "topP": {
914
- "type": "number"
915
- },
916
- "typicalP": {
917
- "type": "number"
918
- },
919
- "useMLock": {
920
- "type": "boolean"
921
- },
922
- "useMMap": {
923
- "type": "boolean"
924
- },
925
- "vocabOnly": {
926
- "type": "boolean"
927
- },
928
- "format": {
929
- "$ref": "#/definitions/StringWithAutocomplete%3C%22json%22%3E"
930
- }
931
- }
587
+ "mode": {
588
+ "type": "string",
589
+ "enum": [
590
+ "stdout",
591
+ "interactive"
592
+ ],
593
+ "description": "The output destination for the generated result.\n- 'stdout': Prints the result to the standard output. This is the default behavior.\n- 'interactive': Provides an interactive prompt for editing the result & committing the changes.",
594
+ "default": "stdout"
932
595
  },
933
- "tokenLimit": {
934
- "type": "number",
935
- "description": "The maximum number of tokens per request.",
936
- "default": 2048
596
+ "openInEditor": {
597
+ "type": "boolean",
598
+ "description": "Open the commit message in an editor for editing before proceeding.",
599
+ "default": false
937
600
  },
938
- "temperature": {
939
- "type": "number",
940
- "description": "The temperature value controls the randomness of the generated output. Higher values (e.g., 0.8) make the output more random, while lower values (e.g., 0.2) make it more deterministic.",
941
- "default": 0.4
601
+ "prompt": {
602
+ "type": "string",
603
+ "description": "The prompt text used for generating results."
942
604
  },
943
- "maxConcurrent": {
944
- "type": "number",
945
- "description": "The maximum number of requests to make concurrently.",
946
- "default": 6
605
+ "summarizePrompt": {
606
+ "type": "string",
607
+ "description": "The prompt text used specifically for generating summaries of large files."
947
608
  },
948
- "authentication": {
949
- "anyOf": [
950
- {
951
- "type": "object",
952
- "properties": {
953
- "type": {
954
- "type": "string",
955
- "const": "None"
956
- },
957
- "credentials": {
958
- "not": {}
959
- }
960
- },
961
- "required": [
962
- "type"
963
- ],
964
- "additionalProperties": false
965
- },
966
- {
967
- "type": "object",
968
- "properties": {
969
- "type": {
970
- "type": "string",
971
- "const": "OAuth"
972
- },
973
- "credentials": {
974
- "type": "object",
975
- "properties": {
976
- "clientId": {
977
- "type": "string"
978
- },
979
- "clientSecret": {
980
- "type": "string"
981
- },
982
- "token": {
983
- "type": "string"
984
- }
985
- },
986
- "additionalProperties": false
987
- }
988
- },
989
- "required": [
990
- "type",
991
- "credentials"
992
- ],
993
- "additionalProperties": false
994
- },
995
- {
996
- "type": "object",
997
- "properties": {
998
- "type": {
999
- "type": "string",
1000
- "const": "APIKey"
1001
- },
1002
- "credentials": {
1003
- "type": "object",
1004
- "properties": {
1005
- "apiKey": {
1006
- "type": "string"
1007
- }
1008
- },
1009
- "required": [
1010
- "apiKey"
1011
- ],
1012
- "additionalProperties": false
1013
- }
1014
- },
1015
- "required": [
1016
- "type",
1017
- "credentials"
1018
- ],
1019
- "additionalProperties": false
1020
- }
1021
- ]
609
+ "ignoredFiles": {
610
+ "type": "array",
611
+ "items": {
612
+ "type": "string"
613
+ },
614
+ "description": "An array of file paths or patterns to be ignored during processing.\n\nNote: This is a list of patterns interpreted by the `minimatch` library.",
615
+ "examples": [
616
+ [
617
+ "package-lock.json",
618
+ "node_modules"
619
+ ]
620
+ ],
621
+ "default": "['package-lock.json', contents of .gitignore, contents of .ignore]"
1022
622
  },
1023
- "requestOptions": {
1024
- "type": "object",
1025
- "properties": {
1026
- "timeout": {
1027
- "type": "number"
1028
- },
1029
- "maxRetries": {
1030
- "type": "number"
1031
- }
623
+ "ignoredExtensions": {
624
+ "type": "array",
625
+ "items": {
626
+ "type": "string"
1032
627
  },
1033
- "additionalProperties": false
628
+ "description": "An array of file extensions to be ignored during processing.",
629
+ "default": [
630
+ ".map",
631
+ ".lock"
632
+ ]
633
+ },
634
+ "defaultBranch": {
635
+ "type": "string",
636
+ "description": "Default git branch for the repository.",
637
+ "default": "main"
1034
638
  }
1035
639
  },
1036
640
  "required": [
1037
- "authentication",
1038
- "endpoint",
1039
- "model",
1040
- "provider"
641
+ "defaultBranch",
642
+ "mode",
643
+ "service"
1041
644
  ]
1042
645
  },
1043
- "StringWithAutocomplete<\"json\">": {
646
+ "LLMService": {
1044
647
  "anyOf": [
1045
648
  {
1046
- "type": "string"
649
+ "$ref": "#/definitions/OpenAILLMService"
1047
650
  },
1048
651
  {
1049
- "type": "string",
1050
- "enum": [
1051
- "json"
1052
- ]
652
+ "$ref": "#/definitions/OllamaLLMService"
653
+ },
654
+ {
655
+ "$ref": "#/definitions/AnthropicLLMService"
1053
656
  }
1054
- ],
1055
- "description": "Represents a string value with autocompleted, but not required, suggestions."
657
+ ]
1056
658
  },
1057
- "AnthropicLLMService": {
659
+ "OpenAILLMService": {
1058
660
  "type": "object",
1059
661
  "additionalProperties": false,
1060
662
  "properties": {
@@ -1066,15 +668,145 @@ const schema$1 = {
1066
668
  },
1067
669
  "fields": {
1068
670
  "type": "object",
671
+ "additionalProperties": false,
1069
672
  "properties": {
673
+ "verbose": {
674
+ "type": "boolean"
675
+ },
676
+ "callbacks": {
677
+ "$ref": "#/definitions/Callbacks"
678
+ },
679
+ "tags": {
680
+ "type": "array",
681
+ "items": {
682
+ "type": "string"
683
+ }
684
+ },
685
+ "metadata": {
686
+ "type": "object",
687
+ "additionalProperties": {}
688
+ },
689
+ "maxConcurrency": {
690
+ "type": "number",
691
+ "description": "The maximum number of concurrent calls that can be made. Defaults to `Infinity`, which means no limit."
692
+ },
693
+ "maxRetries": {
694
+ "type": "number",
695
+ "description": "The maximum number of retries that can be made for a single call, with an exponential backoff between each attempt. Defaults to 6."
696
+ },
697
+ "onFailedAttempt": {
698
+ "$ref": "#/definitions/FailedAttemptHandler",
699
+ "description": "Custom handler to handle failed attempts. Takes the originally thrown error object as input, and should itself throw an error if the input error is not retryable."
700
+ },
701
+ "callbackManager": {
702
+ "$ref": "#/definitions/CallbackManager",
703
+ "deprecated": "Use `callbacks` instead"
704
+ },
705
+ "cache": {
706
+ "anyOf": [
707
+ {
708
+ "$ref": "#/definitions/BaseCache"
709
+ },
710
+ {
711
+ "type": "boolean"
712
+ }
713
+ ]
714
+ },
715
+ "concurrency": {
716
+ "type": "number",
717
+ "deprecated": "Use `maxConcurrency` instead"
718
+ },
719
+ "bestOf": {
720
+ "type": "number",
721
+ "description": "Generates `bestOf` completions server side and returns the \"best\""
722
+ },
723
+ "batchSize": {
724
+ "type": "number",
725
+ "description": "Batch size to use when passing multiple documents to generate"
726
+ },
1070
727
  "temperature": {
1071
- "type": "number"
728
+ "type": "number",
729
+ "description": "Sampling temperature to use"
730
+ },
731
+ "maxTokens": {
732
+ "type": "number",
733
+ "description": "Maximum number of tokens to generate in the completion. -1 returns as many tokens as possible given the prompt and the model's maximum context size."
734
+ },
735
+ "topP": {
736
+ "type": "number",
737
+ "description": "Total probability mass of tokens to consider at each step"
738
+ },
739
+ "frequencyPenalty": {
740
+ "type": "number",
741
+ "description": "Penalizes repeated tokens according to frequency"
742
+ },
743
+ "presencePenalty": {
744
+ "type": "number",
745
+ "description": "Penalizes repeated tokens"
746
+ },
747
+ "n": {
748
+ "type": "number",
749
+ "description": "Number of completions to generate for each prompt"
750
+ },
751
+ "logitBias": {
752
+ "type": "object",
753
+ "additionalProperties": {
754
+ "type": "number"
755
+ },
756
+ "description": "Dictionary used to adjust the probability of specific tokens being generated"
757
+ },
758
+ "user": {
759
+ "type": "string",
760
+ "description": "Unique string identifier representing your end-user, which can help OpenAI to monitor and detect abuse."
761
+ },
762
+ "streaming": {
763
+ "type": "boolean",
764
+ "description": "Whether to stream the results or not. Enabling disables tokenUsage reporting"
765
+ },
766
+ "streamUsage": {
767
+ "type": "boolean",
768
+ "description": "Whether or not to include token usage data in streamed chunks.",
769
+ "default": true
1072
770
  },
1073
- "maxTokens": {
1074
- "type": "number"
771
+ "modelName": {
772
+ "type": "string",
773
+ "description": "Model name to use Alias for `model`"
774
+ },
775
+ "model": {
776
+ "type": "string",
777
+ "description": "Model name to use"
778
+ },
779
+ "modelKwargs": {
780
+ "type": "object",
781
+ "description": "Holds any additional parameters that are valid to pass to {@link * https://platform.openai.com/docs/api-reference/completions/create | } * `openai.createCompletion`} that are not explicitly specified on this class."
782
+ },
783
+ "stop": {
784
+ "type": "array",
785
+ "items": {
786
+ "type": "string"
787
+ },
788
+ "description": "List of stop words to use when generating Alias for `stopSequences`"
789
+ },
790
+ "stopSequences": {
791
+ "type": "array",
792
+ "items": {
793
+ "type": "string"
794
+ },
795
+ "description": "List of stop words to use when generating"
796
+ },
797
+ "timeout": {
798
+ "type": "number",
799
+ "description": "Timeout to use when making requests to OpenAI."
800
+ },
801
+ "openAIApiKey": {
802
+ "type": "string",
803
+ "description": "API key to use when making requests to OpenAI. Defaults to the value of `OPENAI_API_KEY` environment variable. Alias for `apiKey`"
804
+ },
805
+ "apiKey": {
806
+ "type": "string",
807
+ "description": "API key to use when making requests to OpenAI. Defaults to the value of `OPENAI_API_KEY` environment variable."
1075
808
  }
1076
- },
1077
- "additionalProperties": false
809
+ }
1078
810
  },
1079
811
  "tokenLimit": {
1080
812
  "type": "number",
@@ -1166,498 +898,769 @@ const schema$1 = {
1166
898
  }
1167
899
  ]
1168
900
  },
1169
- "requestOptions": {
901
+ "requestOptions": {
902
+ "type": "object",
903
+ "properties": {
904
+ "timeout": {
905
+ "type": "number"
906
+ },
907
+ "maxRetries": {
908
+ "type": "number"
909
+ }
910
+ },
911
+ "additionalProperties": false
912
+ }
913
+ },
914
+ "required": [
915
+ "authentication",
916
+ "model",
917
+ "provider"
918
+ ]
919
+ },
920
+ "LLMProvider": {
921
+ "type": "string",
922
+ "enum": [
923
+ "openai",
924
+ "ollama",
925
+ "anthropic"
926
+ ]
927
+ },
928
+ "LLMModel": {
929
+ "anyOf": [
930
+ {
931
+ "type": "string",
932
+ "enum": [
933
+ "davinci-002",
934
+ "babbage-002",
935
+ "text-davinci-003",
936
+ "text-davinci-002",
937
+ "text-davinci-001",
938
+ "text-curie-001",
939
+ "text-babbage-001",
940
+ "text-ada-001",
941
+ "davinci",
942
+ "curie",
943
+ "babbage",
944
+ "ada",
945
+ "code-davinci-002",
946
+ "code-davinci-001",
947
+ "code-cushman-002",
948
+ "code-cushman-001",
949
+ "davinci-codex",
950
+ "cushman-codex",
951
+ "text-davinci-edit-001",
952
+ "code-davinci-edit-001",
953
+ "text-embedding-ada-002",
954
+ "text-similarity-davinci-001",
955
+ "text-similarity-curie-001",
956
+ "text-similarity-babbage-001",
957
+ "text-similarity-ada-001",
958
+ "text-search-davinci-doc-001",
959
+ "text-search-curie-doc-001",
960
+ "text-search-babbage-doc-001",
961
+ "text-search-ada-doc-001",
962
+ "code-search-babbage-code-001",
963
+ "code-search-ada-code-001",
964
+ "gpt2",
965
+ "gpt-3.5-turbo",
966
+ "gpt-35-turbo",
967
+ "gpt-3.5-turbo-0301",
968
+ "gpt-3.5-turbo-0613",
969
+ "gpt-3.5-turbo-1106",
970
+ "gpt-3.5-turbo-0125",
971
+ "gpt-3.5-turbo-16k",
972
+ "gpt-3.5-turbo-16k-0613",
973
+ "gpt-3.5-turbo-instruct",
974
+ "gpt-3.5-turbo-instruct-0914",
975
+ "gpt-4",
976
+ "gpt-4-0314",
977
+ "gpt-4-0613",
978
+ "gpt-4-32k",
979
+ "gpt-4-32k-0314",
980
+ "gpt-4-32k-0613",
981
+ "gpt-4-turbo",
982
+ "gpt-4-turbo-2024-04-09",
983
+ "gpt-4-turbo-preview",
984
+ "gpt-4-1106-preview",
985
+ "gpt-4-0125-preview",
986
+ "gpt-4-vision-preview",
987
+ "gpt-4o",
988
+ "gpt-4o-2024-05-13"
989
+ ]
990
+ },
991
+ {
992
+ "$ref": "#/definitions/OllamaModel"
993
+ },
994
+ {
995
+ "$ref": "#/definitions/AnthropicModel"
996
+ }
997
+ ]
998
+ },
999
+ "OllamaModel": {
1000
+ "type": "string",
1001
+ "enum": [
1002
+ "codegemma:2b",
1003
+ "codegemma:7b-code",
1004
+ "codegemma",
1005
+ "codellama:13b",
1006
+ "codellama:34b",
1007
+ "codellama:70b",
1008
+ "codellama:7b",
1009
+ "codellama:instruct",
1010
+ "codellama:latest",
1011
+ "codellama",
1012
+ "gemma:2b",
1013
+ "gemma:7b",
1014
+ "gemma:latest",
1015
+ "gemma",
1016
+ "llama2:13b",
1017
+ "llama2:70b",
1018
+ "llama2:chat",
1019
+ "llama2:latest",
1020
+ "llama2:text",
1021
+ "llama2",
1022
+ "llama3:70b-text",
1023
+ "llama3:70b",
1024
+ "llama3:latest",
1025
+ "llama3:text",
1026
+ "llama3.1:70b",
1027
+ "llama3.1:8b",
1028
+ "llama3.1:latest",
1029
+ "llama3.2",
1030
+ "llama3.2:latest",
1031
+ "llama3.2:1b",
1032
+ "llama3.2:3b",
1033
+ "llama3.2:1b-instruct-fp16",
1034
+ "llama3.2:1b-instruct-q3_K_M",
1035
+ "llama3",
1036
+ "mistral:7b",
1037
+ "mistral:latest",
1038
+ "mistral:text",
1039
+ "mistral",
1040
+ "phi3:14b",
1041
+ "phi3:3.8b",
1042
+ "phi3:instruct",
1043
+ "phi3:medium-128k",
1044
+ "phi3:medium-4k",
1045
+ "phi3:medium",
1046
+ "phi3",
1047
+ "qwen2:0.5b",
1048
+ "qwen2:1.5b",
1049
+ "qwen2:72b-text",
1050
+ "qwen2:72b",
1051
+ "qwen2"
1052
+ ]
1053
+ },
1054
+ "AnthropicModel": {
1055
+ "type": "string",
1056
+ "enum": [
1057
+ "claude-3-5-sonnet-20240620",
1058
+ "claude-3-opus-20240229",
1059
+ "claude-3-sonnet-20240229",
1060
+ "claude-3-haiku-20240307",
1061
+ "claude-2.1",
1062
+ "claude-2.0"
1063
+ ]
1064
+ },
1065
+ "Callbacks": {
1066
+ "anyOf": [
1067
+ {
1068
+ "$ref": "#/definitions/CallbackManager"
1069
+ },
1070
+ {
1071
+ "type": "array",
1072
+ "items": {
1073
+ "anyOf": [
1074
+ {
1075
+ "$ref": "#/definitions/BaseCallbackHandler"
1076
+ },
1077
+ {
1078
+ "$ref": "#/definitions/CallbackHandlerMethods"
1079
+ }
1080
+ ]
1081
+ }
1082
+ }
1083
+ ]
1084
+ },
1085
+ "CallbackManager": {
1086
+ "type": "object",
1087
+ "properties": {
1088
+ "handlers": {
1089
+ "type": "array",
1090
+ "items": {
1091
+ "$ref": "#/definitions/BaseCallbackHandler"
1092
+ }
1093
+ },
1094
+ "inheritableHandlers": {
1095
+ "type": "array",
1096
+ "items": {
1097
+ "$ref": "#/definitions/BaseCallbackHandler"
1098
+ }
1099
+ },
1100
+ "tags": {
1101
+ "type": "array",
1102
+ "items": {
1103
+ "type": "string"
1104
+ }
1105
+ },
1106
+ "inheritableTags": {
1107
+ "type": "array",
1108
+ "items": {
1109
+ "type": "string"
1110
+ }
1111
+ },
1112
+ "metadata": {
1170
1113
  "type": "object",
1171
- "properties": {
1172
- "timeout": {
1173
- "type": "number"
1174
- },
1175
- "maxRetries": {
1176
- "type": "number"
1177
- }
1178
- },
1179
- "additionalProperties": false
1114
+ "additionalProperties": {}
1115
+ },
1116
+ "inheritableMetadata": {
1117
+ "type": "object",
1118
+ "additionalProperties": {}
1119
+ },
1120
+ "name": {
1121
+ "type": "string"
1122
+ },
1123
+ "_parentRunId": {
1124
+ "type": "string"
1180
1125
  }
1181
1126
  },
1182
1127
  "required": [
1183
- "authentication",
1184
- "model",
1185
- "provider"
1186
- ]
1187
- }
1188
- }
1189
- };
1190
-
1191
- const isInteractive = (config) => {
1192
- return config?.mode === 'interactive' || !!config?.interactive;
1193
- };
1194
- const SEPERATOR = chalk.blue('─────────────');
1195
- const DIVIDER = chalk.dim(`\\`);
1196
- const LOGO = chalk.green(`┌──────┐
1197
- │┏┏┓┏┏┓│
1198
- │┗┗┛┗┗┛│
1199
- └──────┘`);
1200
- chalk.green(`┌────┐
1201
- │coco│
1202
- └────┘`);
1203
- const bannerWithHeader = (banner) => {
1204
- return chalk.green(`┌────┐
1205
- │coco│ ${banner}
1206
- └────┘`);
1207
- };
1208
- const USAGE_BANNER = chalk.green(`${LOGO}
1209
- ${chalk.bgGreen(`\xa0v${BUILD_VERSION}\xa0`)}
1210
- `);
1211
- const getCommandUsageHeader = (command) => {
1212
- return chalk.green(`${USAGE_BANNER}\n${chalk.white('Command:')}\n\xa0\xa0\xa0\xa0\xa0 $0 ${chalk.greenBright(command)} [options]`);
1213
- };
1214
- const CONFIG_ALREADY_EXISTS = (path) => {
1215
- return `existing config found in '${path}', do you want to override it?`;
1216
- };
1217
- const severityColors = [
1218
- chalk.greenBright, // 1
1219
- chalk.green, // 2
1220
- chalk.cyan, // 3
1221
- chalk.yellowBright, // 4
1222
- chalk.yellow, // 5
1223
- chalk.bgYellow, // 6
1224
- chalk.red, // 7
1225
- chalk.redBright, // 8
1226
- chalk.bgRed, // 9
1227
- chalk.bgRedBright, // 10
1228
- ];
1229
- const severityColor = (severity) => {
1230
- return severityColors[Math.min(severity - 1, severityColors.length - 1)];
1231
- };
1232
- const statusColor = (status) => {
1233
- switch (status) {
1234
- case 'completed':
1235
- return chalk.green;
1236
- case 'skipped':
1237
- return chalk.yellow;
1238
- case 'omitted':
1239
- return chalk.red;
1240
- default:
1241
- return chalk.blue;
1242
- }
1243
- };
1244
- const hotKey = (key) => chalk.dim(`(${key})`);
1245
-
1246
- /**
1247
- * Returns a new object with all undefined keys removed
1248
- *
1249
- * @param obj Object to remove undefined keys from
1250
- * @returns
1251
- */
1252
- function removeUndefined(obj) {
1253
- return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined));
1254
- }
1255
-
1256
- async function updateFileSection({ filePath, startComment, endComment, getNewContent, confirmUpdate = true, confirmMessage = (path) => `A section already exists in ${path}, do you want to override it?`, }) {
1257
- const lines = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8').split(/\r?\n/) : [];
1258
- const newLines = [];
1259
- let foundSection = false;
1260
- for (let i = 0; i < lines.length; i++) {
1261
- if (lines[i].trim() === startComment) {
1262
- foundSection = true;
1263
- if (confirmUpdate) {
1264
- const confirmOverwrite = await prompts.confirm({
1265
- message: typeof confirmMessage === 'function' ? confirmMessage(filePath) : confirmMessage,
1266
- default: false,
1267
- });
1268
- if (!confirmOverwrite) {
1269
- // keep all lines until the end comment
1270
- while (i < lines.length && lines[i].trim() !== endComment) {
1271
- newLines.push(lines[i]);
1272
- i++;
1273
- }
1274
- newLines.push(endComment);
1275
- continue;
1276
- }
1277
- }
1278
- newLines.push(startComment);
1279
- // Insert the new content
1280
- const newContent = await getNewContent();
1281
- newLines.push(newContent);
1282
- // Skip the existing content of the section
1283
- while (i < lines.length && lines[i].trim() !== endComment) {
1284
- i++;
1285
- }
1286
- newLines.push(endComment);
1287
- continue;
1288
- }
1289
- if (!foundSection || lines[i].trim() !== endComment) {
1290
- newLines.push(lines[i]);
1291
- }
1292
- }
1293
- // If section wasn't found, append it at the end
1294
- if (!foundSection) {
1295
- newLines.push('\n' + startComment);
1296
- const newContent = await getNewContent();
1297
- newLines.push(newContent);
1298
- newLines.push(endComment);
1299
- }
1300
- // Write the updated contents back to the file
1301
- fs.writeFileSync(filePath, newLines.join('\n'));
1302
- }
1303
-
1304
- const template$5 = `GOAL: Use functional abstractions to summarize the following text
1305
-
1306
- RULES: Avoid phrases like "this change", "this code", or "this function" etc. Instead refer to the function, variable, or class by name.
1307
-
1308
- TEXT:"""{text}"""
1309
- `;
1310
- const inputVariables$4 = ['text'];
1311
- const SUMMARIZE_PROMPT = new prompts$1.PromptTemplate({
1312
- inputVariables: inputVariables$4,
1313
- template: template$5,
1314
- });
1315
-
1316
- /**
1317
- * Retrieves the provider and model from the given configuration object.
1318
- * @param config The configuration object.
1319
- * @returns An object containing the provider and model.
1320
- * @throws Error if the configuration is invalid or missing required properties.
1321
- */
1322
- function getModelAndProviderFromConfig(config) {
1323
- if (!config.service) {
1324
- throw new Error('Invalid service: undefined');
1325
- }
1326
- const { provider, model } = config.service;
1327
- if (!model || !provider) {
1328
- throw new Error(`Invalid service: ${config.service}`);
1329
- }
1330
- return { provider, model };
1331
- }
1332
- /**
1333
- * Retrieve appropriate API key based on selected model
1334
- * @param service
1335
- * @param options
1336
- * @returns API Key
1337
- */
1338
- function getApiKeyForModel(config) {
1339
- const { provider } = getModelAndProviderFromConfig(config);
1340
- switch (provider) {
1341
- case 'openai':
1342
- return getDefaultServiceApiKey(config);
1343
- default:
1344
- return getDefaultServiceApiKey(config);
1345
- }
1346
- }
1347
- /**
1348
- * Retrieves the default service API key from the given configuration.
1349
- * @param config The configuration object.
1350
- * @returns The default service API key.
1351
- */
1352
- function getDefaultServiceApiKey(config) {
1353
- const service = config.service;
1354
- if (service.authentication.type === 'APIKey') {
1355
- return service.authentication.credentials?.apiKey;
1356
- }
1357
- else if (service.authentication.type === 'OAuth') {
1358
- return service.authentication.credentials?.token;
1359
- }
1360
- return '';
1361
- }
1362
- const DEFAULT_OPENAI_LLM_SERVICE = {
1363
- provider: 'openai',
1364
- model: 'gpt-4',
1365
- tokenLimit: 2024,
1366
- temperature: 0.32,
1367
- authentication: {
1368
- type: 'APIKey',
1369
- credentials: {
1370
- apiKey: '',
1128
+ "handlers",
1129
+ "inheritableHandlers",
1130
+ "tags",
1131
+ "inheritableTags",
1132
+ "metadata",
1133
+ "inheritableMetadata",
1134
+ "name"
1135
+ ],
1136
+ "additionalProperties": false
1137
+ },
1138
+ "BaseCallbackHandler": {
1139
+ "type": "object",
1140
+ "properties": {
1141
+ "lc_serializable": {
1142
+ "type": "boolean"
1143
+ },
1144
+ "lc_kwargs": {
1145
+ "$ref": "#/definitions/SerializedFields"
1146
+ },
1147
+ "lc_namespace": {
1148
+ "type": "array",
1149
+ "items": {
1150
+ "type": "string"
1151
+ },
1152
+ "description": "A path to the module that contains the class, eg. [\"langchain\", \"llms\"] Usually should be the same as the entrypoint the class is exported from."
1153
+ },
1154
+ "ignoreLLM": {
1155
+ "type": "boolean"
1156
+ },
1157
+ "ignoreChain": {
1158
+ "type": "boolean"
1159
+ },
1160
+ "ignoreAgent": {
1161
+ "type": "boolean"
1162
+ },
1163
+ "ignoreRetriever": {
1164
+ "type": "boolean"
1165
+ },
1166
+ "ignoreCustomEvent": {
1167
+ "type": "boolean"
1168
+ },
1169
+ "_awaitHandler": {
1170
+ "type": "boolean"
1171
+ },
1172
+ "raiseError": {
1173
+ "type": "boolean"
1174
+ },
1175
+ "name": {
1176
+ "type": "string"
1177
+ },
1178
+ "awaitHandlers": {
1179
+ "type": "boolean"
1180
+ }
1181
+ },
1182
+ "required": [
1183
+ "awaitHandlers",
1184
+ "ignoreAgent",
1185
+ "ignoreChain",
1186
+ "ignoreCustomEvent",
1187
+ "ignoreLLM",
1188
+ "ignoreRetriever",
1189
+ "lc_kwargs",
1190
+ "lc_namespace",
1191
+ "lc_serializable",
1192
+ "name",
1193
+ "raiseError"
1194
+ ],
1195
+ "additionalProperties": false,
1196
+ "description": "Abstract base class for creating callback handlers in the LangChain framework. It provides a set of optional methods that can be overridden in derived classes to handle various events during the execution of a LangChain application."
1371
1197
  },
1372
- },
1373
- };
1374
- const DEFAULT_OLLAMA_LLM_SERVICE = {
1375
- provider: 'ollama',
1376
- model: 'llama3',
1377
- endpoint: 'http://localhost:11434',
1378
- maxConcurrent: 1,
1379
- tokenLimit: 2024,
1380
- temperature: 0.4,
1381
- authentication: {
1382
- type: 'None',
1383
- credentials: undefined,
1384
- },
1385
- };
1386
- /**
1387
- * Retrieves the default service configuration based on the provided alias and optional model.
1388
- * @param provider - The alias of the service.
1389
- * @param model - The optional model to be used.
1390
- * @returns The default service configuration.
1391
- * @throws Error if the alias is invalid or undefined.
1392
- */
1393
- function getDefaultServiceConfigFromAlias(provider, model) {
1394
- switch (provider) {
1395
- case 'anthropic':
1396
- return {
1397
- ...DEFAULT_OPENAI_LLM_SERVICE,
1398
- model: model || DEFAULT_OPENAI_LLM_SERVICE.model,
1399
- };
1400
- case 'ollama':
1401
- return {
1402
- ...DEFAULT_OLLAMA_LLM_SERVICE,
1403
- model: model || DEFAULT_OLLAMA_LLM_SERVICE.model,
1404
- };
1405
- case 'openai':
1406
- default:
1407
- return {
1408
- ...DEFAULT_OPENAI_LLM_SERVICE,
1409
- model: model || DEFAULT_OPENAI_LLM_SERVICE.model,
1410
- };
1411
- }
1412
- }
1413
-
1414
- const DEFAULT_IGNORED_FILES = ['package-lock.json', 'yarn.lock', 'node_modules'];
1415
- const DEFAULT_IGNORED_EXTENSIONS = ['.map', '.lock'];
1416
- const COCO_CONFIG_START_COMMENT = '# -- start coco config --';
1417
- const COCO_CONFIG_END_COMMENT = '# -- end coco config --';
1418
- /**
1419
- * Default Config
1420
- *
1421
- * @type {Config}
1422
- */
1423
- const DEFAULT_CONFIG$1 = {
1424
- mode: 'stdout',
1425
- verbose: false,
1426
- defaultBranch: 'main',
1427
- service: getDefaultServiceConfigFromAlias('openai'),
1428
- summarizePrompt: SUMMARIZE_PROMPT.template,
1429
- ignoredFiles: DEFAULT_IGNORED_FILES,
1430
- ignoredExtensions: DEFAULT_IGNORED_EXTENSIONS,
1431
- };
1432
- /**
1433
- * Create a named export of all config keys for use in other modules.
1434
- *
1435
- * @see Used in `src/lib/config/services/env.ts` to validate all env vars.
1436
- *
1437
- * @type {string[]}
1438
- */
1439
- const CONFIG_KEYS = Object.keys({
1440
- ...DEFAULT_CONFIG$1,
1441
- prompt: '',
1442
- });
1443
-
1444
- /**
1445
- * Load environment variables
1446
- *
1447
- * @param {Config} config
1448
- * @returns {Config} Updated config
1449
- **/
1450
- function loadEnvConfig(config) {
1451
- const envConfig = {};
1452
- const envKeys = [...CONFIG_KEYS, 'COCO_SERVICE_PROVIDER', 'COCO_SERVICE_MODEL', 'OPEN_AI_KEY'];
1453
- envKeys.forEach((key) => {
1454
- const envVarName = toEnvVarName(key);
1455
- const envValue = parseEnvValue(key, process.env[envVarName]);
1456
- if (envValue === undefined) {
1457
- return;
1458
- }
1459
- if (key === 'COCO_SERVICE_PROVIDER' || key === 'COCO_SERVICE_MODEL' || key === 'OPEN_AI_KEY') {
1460
- // NOTE: We want to ensure that the service object is always defined
1461
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1462
- // @ts-ignore
1463
- envConfig.service = envConfig.service || {};
1464
- handleServiceEnvVar(envConfig.service, key, envValue);
1465
- }
1466
- else {
1467
- if (key === 'service' || !envValue) {
1468
- return;
1469
- }
1470
- envConfig[key] = envValue;
1471
- }
1472
- });
1473
- return { ...config, ...removeUndefined(envConfig) };
1474
- }
1475
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1476
- function handleServiceEnvVar(service, key, value) {
1477
- switch (key) {
1478
- case 'COCO_SERVICE_PROVIDER':
1479
- service.provider = value;
1480
- break;
1481
- case 'COCO_SERVICE_MODEL':
1482
- service.model = value;
1483
- break;
1484
- case 'OPEN_AI_KEY':
1485
- if (service.provider === 'openai') {
1486
- service.fields = { apiKey: value };
1487
- }
1488
- break;
1489
- }
1490
- }
1491
- function parseEnvValue(key, value) {
1492
- switch (true) {
1493
- // Handle undefined values
1494
- case value === undefined:
1495
- return undefined;
1496
- // Handle comma separated strings for ignoredFiles and ignoredExtensions arrays
1497
- case (key === 'ignoredFiles' || key === 'ignoredExtensions') &&
1498
- typeof value === 'string' &&
1499
- value.includes(','):
1500
- return value.split(',');
1501
- // Handle boolean values
1502
- case typeof value === 'string' && (value === 'false' || value === 'true'):
1503
- return value === 'true';
1504
- // Handle number values
1505
- case typeof value === 'string' && !isNaN(Number(value)):
1506
- return Number(value);
1507
- default:
1508
- return value;
1509
- }
1510
- }
1511
- function toEnvVarName(key) {
1512
- if (key === 'service') {
1513
- return key;
1514
- }
1515
- if (key.includes('COCO_')) {
1516
- return key;
1517
- }
1518
- return `COCO_${key.replace(/([A-Z])/g, '_$1').toLocaleUpperCase()}`;
1519
- }
1520
- function formatEnvValue(value) {
1521
- if (typeof value === 'number') {
1522
- return `${value}`;
1523
- }
1524
- else if (Array.isArray(value)) {
1525
- return `${value.join(',')}`;
1526
- }
1527
- else if (typeof value === 'string') {
1528
- // Escape newlines and tabs in strings
1529
- return `${value.replace(/\n/g, '\\n').replace(/\t/g, '\\t')}`;
1530
- }
1531
- return `${value}`;
1532
- }
1533
- const appendToEnvFile = async (filePath, config) => {
1534
- const getNewContent = async () => {
1535
- return Object.entries(config)
1536
- .map(([key, value]) => {
1537
- if (key === 'service') {
1538
- const service = value;
1539
- return `${service.provider ? `COCO_SERVICE_PROVIDER=${service.provider}` : ''}\n${service.model ? `COCO_SERVICE_MODEL=${service.model}` : ''}\n${service.authentication.type === 'APIKey'
1540
- ? `OPEN_AI_KEY=${service.authentication.credentials.apiKey}`
1541
- : ''}`;
1198
+ "SerializedFields": {
1199
+ "type": "object"
1200
+ },
1201
+ "CallbackHandlerMethods": {
1202
+ "type": "object",
1203
+ "additionalProperties": false,
1204
+ "description": "Base interface for callbacks. All methods are optional. If a method is not implemented, it will be ignored. If a method is implemented, it will be called at the appropriate time. All methods are called with the run ID of the LLM/ChatModel/Chain that is running, which is generated by the CallbackManager."
1205
+ },
1206
+ "FailedAttemptHandler": {
1207
+ "$comment": "(error: any) => any",
1208
+ "type": "object",
1209
+ "properties": {
1210
+ "namedArgs": {
1211
+ "type": "object",
1212
+ "properties": {
1213
+ "error": {}
1214
+ },
1215
+ "required": [
1216
+ "error"
1217
+ ],
1218
+ "additionalProperties": false
1219
+ }
1542
1220
  }
1543
- const envVarName = toEnvVarName(key);
1544
- const envValue = formatEnvValue(value);
1545
- return `${envVarName}=${envValue}`;
1546
- })
1547
- .join('\n');
1548
- };
1549
- await updateFileSection({
1550
- filePath,
1551
- startComment: COCO_CONFIG_START_COMMENT,
1552
- endComment: COCO_CONFIG_END_COMMENT,
1553
- getNewContent,
1554
- confirmMessage: CONFIG_ALREADY_EXISTS,
1555
- });
1556
- };
1557
-
1558
- /**
1559
- * Load git profile config (from ~/.gitconfig)
1560
- *
1561
- * @param {Config} config
1562
- * @returns {Config} Updated config
1563
- **/
1564
- function loadGitConfig(config) {
1565
- const gitConfigPath = path__namespace.join(os__namespace.homedir(), '.gitconfig');
1566
- if (fs__namespace.existsSync(gitConfigPath)) {
1567
- const gitConfigRaw = fs__namespace.readFileSync(gitConfigPath, 'utf-8');
1568
- const gitConfigParsed = ini__namespace.parse(gitConfigRaw);
1569
- const gitConfigServiceObject = gitConfigParsed.coco?.service;
1570
- let service = config.service;
1571
- if (gitConfigServiceObject) {
1572
- const gitServiceConfig = JSON.parse(gitConfigServiceObject);
1573
- service = gitServiceConfig || config?.service;
1221
+ },
1222
+ "BaseCache": {
1223
+ "type": "object",
1224
+ "additionalProperties": false,
1225
+ "description": "Base class for all caches. All caches should extend this class."
1226
+ },
1227
+ "OllamaLLMService": {
1228
+ "type": "object",
1229
+ "additionalProperties": false,
1230
+ "properties": {
1231
+ "provider": {
1232
+ "$ref": "#/definitions/LLMProvider"
1233
+ },
1234
+ "model": {
1235
+ "$ref": "#/definitions/LLMModel"
1236
+ },
1237
+ "endpoint": {
1238
+ "type": "string"
1239
+ },
1240
+ "fields": {
1241
+ "type": "object",
1242
+ "additionalProperties": false,
1243
+ "properties": {
1244
+ "verbose": {
1245
+ "type": "boolean"
1246
+ },
1247
+ "callbacks": {
1248
+ "$ref": "#/definitions/Callbacks"
1249
+ },
1250
+ "tags": {
1251
+ "type": "array",
1252
+ "items": {
1253
+ "type": "string"
1254
+ }
1255
+ },
1256
+ "metadata": {
1257
+ "type": "object",
1258
+ "additionalProperties": {}
1259
+ },
1260
+ "maxConcurrency": {
1261
+ "type": "number",
1262
+ "description": "The maximum number of concurrent calls that can be made. Defaults to `Infinity`, which means no limit."
1263
+ },
1264
+ "maxRetries": {
1265
+ "type": "number",
1266
+ "description": "The maximum number of retries that can be made for a single call, with an exponential backoff between each attempt. Defaults to 6."
1267
+ },
1268
+ "onFailedAttempt": {
1269
+ "$ref": "#/definitions/FailedAttemptHandler",
1270
+ "description": "Custom handler to handle failed attempts. Takes the originally thrown error object as input, and should itself throw an error if the input error is not retryable."
1271
+ },
1272
+ "callbackManager": {
1273
+ "$ref": "#/definitions/CallbackManager",
1274
+ "deprecated": "Use `callbacks` instead"
1275
+ },
1276
+ "cache": {
1277
+ "anyOf": [
1278
+ {
1279
+ "$ref": "#/definitions/BaseCache"
1280
+ },
1281
+ {
1282
+ "type": "boolean"
1283
+ }
1284
+ ]
1285
+ },
1286
+ "concurrency": {
1287
+ "type": "number",
1288
+ "deprecated": "Use `maxConcurrency` instead"
1289
+ },
1290
+ "embeddingOnly": {
1291
+ "type": "boolean"
1292
+ },
1293
+ "f16KV": {
1294
+ "type": "boolean"
1295
+ },
1296
+ "frequencyPenalty": {
1297
+ "type": "number"
1298
+ },
1299
+ "headers": {
1300
+ "type": "object",
1301
+ "additionalProperties": {
1302
+ "type": "string"
1303
+ }
1304
+ },
1305
+ "keepAlive": {
1306
+ "type": "string"
1307
+ },
1308
+ "logitsAll": {
1309
+ "type": "boolean"
1310
+ },
1311
+ "lowVram": {
1312
+ "type": "boolean"
1313
+ },
1314
+ "mainGpu": {
1315
+ "type": "number"
1316
+ },
1317
+ "model": {
1318
+ "type": "string"
1319
+ },
1320
+ "baseUrl": {
1321
+ "type": "string"
1322
+ },
1323
+ "mirostat": {
1324
+ "type": "number"
1325
+ },
1326
+ "mirostatEta": {
1327
+ "type": "number"
1328
+ },
1329
+ "mirostatTau": {
1330
+ "type": "number"
1331
+ },
1332
+ "numBatch": {
1333
+ "type": "number"
1334
+ },
1335
+ "numCtx": {
1336
+ "type": "number"
1337
+ },
1338
+ "numGpu": {
1339
+ "type": "number"
1340
+ },
1341
+ "numGqa": {
1342
+ "type": "number"
1343
+ },
1344
+ "numKeep": {
1345
+ "type": "number"
1346
+ },
1347
+ "numPredict": {
1348
+ "type": "number"
1349
+ },
1350
+ "numThread": {
1351
+ "type": "number"
1352
+ },
1353
+ "penalizeNewline": {
1354
+ "type": "boolean"
1355
+ },
1356
+ "presencePenalty": {
1357
+ "type": "number"
1358
+ },
1359
+ "repeatLastN": {
1360
+ "type": "number"
1361
+ },
1362
+ "repeatPenalty": {
1363
+ "type": "number"
1364
+ },
1365
+ "ropeFrequencyBase": {
1366
+ "type": "number"
1367
+ },
1368
+ "ropeFrequencyScale": {
1369
+ "type": "number"
1370
+ },
1371
+ "temperature": {
1372
+ "type": "number"
1373
+ },
1374
+ "stop": {
1375
+ "type": "array",
1376
+ "items": {
1377
+ "type": "string"
1378
+ }
1379
+ },
1380
+ "tfsZ": {
1381
+ "type": "number"
1382
+ },
1383
+ "topK": {
1384
+ "type": "number"
1385
+ },
1386
+ "topP": {
1387
+ "type": "number"
1388
+ },
1389
+ "typicalP": {
1390
+ "type": "number"
1391
+ },
1392
+ "useMLock": {
1393
+ "type": "boolean"
1394
+ },
1395
+ "useMMap": {
1396
+ "type": "boolean"
1397
+ },
1398
+ "vocabOnly": {
1399
+ "type": "boolean"
1400
+ },
1401
+ "format": {
1402
+ "$ref": "#/definitions/StringWithAutocomplete%3C%22json%22%3E"
1403
+ }
1404
+ }
1405
+ },
1406
+ "tokenLimit": {
1407
+ "type": "number",
1408
+ "description": "The maximum number of tokens per request.",
1409
+ "default": 2048
1410
+ },
1411
+ "temperature": {
1412
+ "type": "number",
1413
+ "description": "The temperature value controls the randomness of the generated output. Higher values (e.g., 0.8) make the output more random, while lower values (e.g., 0.2) make it more deterministic.",
1414
+ "default": 0.4
1415
+ },
1416
+ "maxConcurrent": {
1417
+ "type": "number",
1418
+ "description": "The maximum number of requests to make concurrently.",
1419
+ "default": 6
1420
+ },
1421
+ "authentication": {
1422
+ "anyOf": [
1423
+ {
1424
+ "type": "object",
1425
+ "properties": {
1426
+ "type": {
1427
+ "type": "string",
1428
+ "const": "None"
1429
+ },
1430
+ "credentials": {
1431
+ "not": {}
1432
+ }
1433
+ },
1434
+ "required": [
1435
+ "type"
1436
+ ],
1437
+ "additionalProperties": false
1438
+ },
1439
+ {
1440
+ "type": "object",
1441
+ "properties": {
1442
+ "type": {
1443
+ "type": "string",
1444
+ "const": "OAuth"
1445
+ },
1446
+ "credentials": {
1447
+ "type": "object",
1448
+ "properties": {
1449
+ "clientId": {
1450
+ "type": "string"
1451
+ },
1452
+ "clientSecret": {
1453
+ "type": "string"
1454
+ },
1455
+ "token": {
1456
+ "type": "string"
1457
+ }
1458
+ },
1459
+ "additionalProperties": false
1460
+ }
1461
+ },
1462
+ "required": [
1463
+ "type",
1464
+ "credentials"
1465
+ ],
1466
+ "additionalProperties": false
1467
+ },
1468
+ {
1469
+ "type": "object",
1470
+ "properties": {
1471
+ "type": {
1472
+ "type": "string",
1473
+ "const": "APIKey"
1474
+ },
1475
+ "credentials": {
1476
+ "type": "object",
1477
+ "properties": {
1478
+ "apiKey": {
1479
+ "type": "string"
1480
+ }
1481
+ },
1482
+ "required": [
1483
+ "apiKey"
1484
+ ],
1485
+ "additionalProperties": false
1486
+ }
1487
+ },
1488
+ "required": [
1489
+ "type",
1490
+ "credentials"
1491
+ ],
1492
+ "additionalProperties": false
1493
+ }
1494
+ ]
1495
+ },
1496
+ "requestOptions": {
1497
+ "type": "object",
1498
+ "properties": {
1499
+ "timeout": {
1500
+ "type": "number"
1501
+ },
1502
+ "maxRetries": {
1503
+ "type": "number"
1504
+ }
1505
+ },
1506
+ "additionalProperties": false
1507
+ }
1508
+ },
1509
+ "required": [
1510
+ "authentication",
1511
+ "endpoint",
1512
+ "model",
1513
+ "provider"
1514
+ ]
1515
+ },
1516
+ "StringWithAutocomplete<\"json\">": {
1517
+ "anyOf": [
1518
+ {
1519
+ "type": "string"
1520
+ },
1521
+ {
1522
+ "type": "string",
1523
+ "enum": [
1524
+ "json"
1525
+ ]
1526
+ }
1527
+ ],
1528
+ "description": "Represents a string value with autocompleted, but not required, suggestions."
1529
+ },
1530
+ "AnthropicLLMService": {
1531
+ "type": "object",
1532
+ "additionalProperties": false,
1533
+ "properties": {
1534
+ "provider": {
1535
+ "$ref": "#/definitions/LLMProvider"
1536
+ },
1537
+ "model": {
1538
+ "$ref": "#/definitions/LLMModel"
1539
+ },
1540
+ "fields": {
1541
+ "type": "object",
1542
+ "properties": {
1543
+ "temperature": {
1544
+ "type": "number"
1545
+ },
1546
+ "maxTokens": {
1547
+ "type": "number"
1548
+ }
1549
+ },
1550
+ "additionalProperties": false
1551
+ },
1552
+ "tokenLimit": {
1553
+ "type": "number",
1554
+ "description": "The maximum number of tokens per request.",
1555
+ "default": 2048
1556
+ },
1557
+ "temperature": {
1558
+ "type": "number",
1559
+ "description": "The temperature value controls the randomness of the generated output. Higher values (e.g., 0.8) make the output more random, while lower values (e.g., 0.2) make it more deterministic.",
1560
+ "default": 0.4
1561
+ },
1562
+ "maxConcurrent": {
1563
+ "type": "number",
1564
+ "description": "The maximum number of requests to make concurrently.",
1565
+ "default": 6
1566
+ },
1567
+ "authentication": {
1568
+ "anyOf": [
1569
+ {
1570
+ "type": "object",
1571
+ "properties": {
1572
+ "type": {
1573
+ "type": "string",
1574
+ "const": "None"
1575
+ },
1576
+ "credentials": {
1577
+ "not": {}
1578
+ }
1579
+ },
1580
+ "required": [
1581
+ "type"
1582
+ ],
1583
+ "additionalProperties": false
1584
+ },
1585
+ {
1586
+ "type": "object",
1587
+ "properties": {
1588
+ "type": {
1589
+ "type": "string",
1590
+ "const": "OAuth"
1591
+ },
1592
+ "credentials": {
1593
+ "type": "object",
1594
+ "properties": {
1595
+ "clientId": {
1596
+ "type": "string"
1597
+ },
1598
+ "clientSecret": {
1599
+ "type": "string"
1600
+ },
1601
+ "token": {
1602
+ "type": "string"
1603
+ }
1604
+ },
1605
+ "additionalProperties": false
1606
+ }
1607
+ },
1608
+ "required": [
1609
+ "type",
1610
+ "credentials"
1611
+ ],
1612
+ "additionalProperties": false
1613
+ },
1614
+ {
1615
+ "type": "object",
1616
+ "properties": {
1617
+ "type": {
1618
+ "type": "string",
1619
+ "const": "APIKey"
1620
+ },
1621
+ "credentials": {
1622
+ "type": "object",
1623
+ "properties": {
1624
+ "apiKey": {
1625
+ "type": "string"
1626
+ }
1627
+ },
1628
+ "required": [
1629
+ "apiKey"
1630
+ ],
1631
+ "additionalProperties": false
1632
+ }
1633
+ },
1634
+ "required": [
1635
+ "type",
1636
+ "credentials"
1637
+ ],
1638
+ "additionalProperties": false
1639
+ }
1640
+ ]
1641
+ },
1642
+ "requestOptions": {
1643
+ "type": "object",
1644
+ "properties": {
1645
+ "timeout": {
1646
+ "type": "number"
1647
+ },
1648
+ "maxRetries": {
1649
+ "type": "number"
1650
+ }
1651
+ },
1652
+ "additionalProperties": false
1653
+ }
1654
+ },
1655
+ "required": [
1656
+ "authentication",
1657
+ "model",
1658
+ "provider"
1659
+ ]
1574
1660
  }
1575
- config = {
1576
- ...config,
1577
- service: service,
1578
- prompt: gitConfigParsed.coco?.prompt || config.prompt,
1579
- mode: gitConfigParsed.coco?.mode || config.mode,
1580
- summarizePrompt: gitConfigParsed.coco?.summarizePrompt || config.summarizePrompt,
1581
- ignoredFiles: gitConfigParsed.coco?.ignoredFiles || config.ignoredFiles,
1582
- ignoredExtensions: gitConfigParsed.coco?.ignoredExtensions || config.ignoredExtensions,
1583
- defaultBranch: gitConfigParsed.coco?.defaultBranch || config.defaultBranch,
1584
- verbose: gitConfigParsed.coco?.verbose || config.verbose,
1585
- };
1586
- }
1587
- return removeUndefined(config);
1588
- }
1589
- /**
1590
- * Appends the provided configuration to a git config file.
1591
- *
1592
- * @param filePath - The path to the .gitconfig
1593
- * @param config - The configuration object to append.
1594
- */
1595
- const appendToGitConfig = async (filePath, config) => {
1596
- if (!fs__namespace.existsSync(filePath)) {
1597
- throw new Error(`File ${filePath} does not exist.`);
1598
1661
  }
1599
- const header = '[coco]';
1600
- const getNewContent = async () => {
1601
- const contentLines = [header];
1602
- for (const key in config) {
1603
- const value = config[key];
1604
- if (typeof value === 'object') {
1605
- // Serialize object to JSON string
1606
- contentLines.push(`\t${key} = ${JSON.stringify(value)}`);
1607
- }
1608
- else if (typeof value === 'string' && value.includes('\n')) {
1609
- // Wrap strings with new lines in quotes
1610
- contentLines.push(`\t${key} = ${JSON.stringify(value)}`);
1611
- }
1612
- else {
1613
- contentLines.push(`\t${key} = ${value}`);
1614
- }
1615
- }
1616
- return contentLines.join('\n');
1617
- };
1618
- await updateFileSection({
1619
- filePath,
1620
- startComment: COCO_CONFIG_START_COMMENT,
1621
- endComment: COCO_CONFIG_END_COMMENT,
1622
- getNewContent,
1623
- confirmUpdate: true,
1624
- confirmMessage: CONFIG_ALREADY_EXISTS,
1625
- });
1626
1662
  };
1627
1663
 
1628
- /**
1629
- * Load .gitignore in project root
1630
- *
1631
- * @param {Config} config
1632
- * @returns
1633
- */
1634
- function loadGitignore(config) {
1635
- if (fs__namespace.existsSync('.gitignore')) {
1636
- const gitignoreContent = fs__namespace.readFileSync('.gitignore', 'utf-8');
1637
- config.ignoredFiles = [
1638
- ...(config?.ignoredFiles || []),
1639
- ...gitignoreContent.split('\n').filter((line) => line.trim() !== '' && !line.startsWith('#')),
1640
- ];
1641
- }
1642
- return config;
1643
- }
1644
- /**
1645
- * Load .ignore in project root
1646
- *
1647
- * @param {Config} config
1648
- * @returns
1649
- */
1650
- function loadIgnore(config) {
1651
- if (fs__namespace.existsSync('.ignore')) {
1652
- const ignoreContent = fs__namespace.readFileSync('.ignore', 'utf-8');
1653
- config.ignoredFiles = [
1654
- ...(config?.ignoredFiles || []),
1655
- ...ignoreContent.split('\n').filter((line) => line.trim() !== '' && !line.startsWith('#')),
1656
- ];
1657
- }
1658
- return config;
1659
- }
1660
-
1661
1664
  const ajv = new Ajv({
1662
1665
  allErrors: true,
1663
1666
  verbose: true,
@@ -1889,6 +1892,7 @@ function getLlm(provider, model, config) {
1889
1892
  switch (provider) {
1890
1893
  case 'anthropic':
1891
1894
  return new anthropic.ChatAnthropic({
1895
+ anthropicApiKey: getApiKeyForModel(config),
1892
1896
  maxConcurrency: config.service.maxConcurrent,
1893
1897
  model,
1894
1898
  });
@@ -2297,8 +2301,11 @@ async function handleResult({ result, mode, interactiveModeCallback }) {
2297
2301
 
2298
2302
  const template$3 = `Write informative git changelog, in the imperative, based on a series of individual messages.
2299
2303
 
2300
- - Include the git commit hash as reference for each change, including just the first 7 characters
2304
+ - Annotate each change with the git commit hash as reference, including just the first 7 characters
2301
2305
  - Logically group changes, and if necessary, summarize dependency updates
2306
+ - Include a descriptive title for the changelog, to give a high-level overview of the changes
2307
+ - Depending on the size of the changes, consider breaking the changelog into sections
2308
+ - Avoid generlizations like "various bug fixes" or "improvements" or "enhancements"
2302
2309
 
2303
2310
  {format_instructions}
2304
2311
 
@@ -2379,7 +2386,7 @@ const handler$4 = async (argv, logger) => {
2379
2386
  variables: CHANGELOG_PROMPT.inputVariables,
2380
2387
  fallback: CHANGELOG_PROMPT,
2381
2388
  });
2382
- const formatInstructions = "Respond with a valid JSON object, containing two fields: 'header' and 'content', both strings.";
2389
+ const formatInstructions = "Respond with a valid JSON object, containing two fields: 'title' a string, no more than 65 characters, and 'content' a string.";
2383
2390
  const changelog = await executeChain({
2384
2391
  llm,
2385
2392
  prompt,
@@ -2392,7 +2399,7 @@ const handler$4 = async (argv, logger) => {
2392
2399
  const branchName = await getCurrentBranchName({ git });
2393
2400
  const ticketId = extractTicketIdFromBranchName(branchName);
2394
2401
  const footer = ticketId ? `\n\nPart of **${ticketId}**` : '';
2395
- return `${changelog.header}\n\n${changelog.content}${footer}`;
2402
+ return `${changelog.title}\n\n${changelog.content}${footer}`;
2396
2403
  },
2397
2404
  noResult: async () => {
2398
2405
  if (config.range) {
@@ -7025,7 +7032,7 @@ const options = {
7025
7032
  alias: 'interactive',
7026
7033
  description: 'Toggle interactive mode',
7027
7034
  },
7028
- 'b': {
7035
+ b: {
7029
7036
  type: 'string',
7030
7037
  alias: 'branch',
7031
7038
  description: 'Branch to review',
@@ -28351,7 +28358,7 @@ const handler = async (argv, logger) => {
28351
28358
 
28352
28359
  var review = {
28353
28360
  command,
28354
- desc: 'Review the staged changes',
28361
+ desc: 'Perform a code review on your changes',
28355
28362
  builder,
28356
28363
  handler: commandExecutor(handler),
28357
28364
  options,