git-coco 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/init/handler.d.ts +3 -0
- package/dist/commands/init/index.d.ts +10 -0
- package/dist/commands/init/options.d.ts +15 -0
- package/dist/index.esm.mjs +421 -51
- package/dist/index.esm.mjs.map +1 -1
- package/dist/index.js +419 -51
- package/dist/lib/config/constants.d.ts +13 -0
- package/dist/lib/config/loadConfig.d.ts +0 -6
- package/dist/lib/config/services/env.d.ts +1 -0
- package/dist/lib/config/services/git.d.ts +7 -0
- package/dist/lib/config/services/project.d.ts +1 -0
- package/dist/lib/ui/logResult.d.ts +1 -1
- package/dist/lib/utils/updateFileSection.d.ts +1 -0
- package/dist/stats.html +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/// <reference types="yargs" />
|
|
2
|
+
import { handler } from './handler';
|
|
3
|
+
declare const _default: {
|
|
4
|
+
command: string;
|
|
5
|
+
desc: string;
|
|
6
|
+
builder: (yargs: import("yargs").Argv<{}>) => import("yargs").Argv<import("yargs").Omit<{}, string> & import("yargs").InferredOptionTypes<Record<string, import("yargs").Options>>>;
|
|
7
|
+
handler: typeof handler;
|
|
8
|
+
options: Record<string, import("yargs").Options>;
|
|
9
|
+
};
|
|
10
|
+
export default _default;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Options, Argv } from 'yargs';
|
|
2
|
+
import { BaseCommandOptions } from '../types';
|
|
3
|
+
export interface CommitOptions extends BaseCommandOptions {
|
|
4
|
+
prompt: string;
|
|
5
|
+
commit: boolean;
|
|
6
|
+
summarizePrompt: string;
|
|
7
|
+
openInEditor: boolean;
|
|
8
|
+
ignoredFiles: string[];
|
|
9
|
+
ignoredExtensions: string[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Command line options via yargs
|
|
13
|
+
*/
|
|
14
|
+
export declare const options: Record<string, Options>;
|
|
15
|
+
export declare const builder: (yargs: Argv) => Argv<import("yargs").Omit<{}, string> & import("yargs").InferredOptionTypes<Record<string, Options>>>;
|
package/dist/index.esm.mjs
CHANGED
|
@@ -17,9 +17,11 @@ import * as path from 'path';
|
|
|
17
17
|
import path__default from 'path';
|
|
18
18
|
import { minimatch } from 'minimatch';
|
|
19
19
|
import * as fs from 'fs';
|
|
20
|
+
import fs__default from 'fs';
|
|
21
|
+
import { confirm, editor, select, password, input } from '@inquirer/prompts';
|
|
20
22
|
import * as os from 'os';
|
|
23
|
+
import os__default from 'os';
|
|
21
24
|
import * as ini from 'ini';
|
|
22
|
-
import { editor, select } from '@inquirer/prompts';
|
|
23
25
|
import { simpleGit } from 'simple-git';
|
|
24
26
|
|
|
25
27
|
/**
|
|
@@ -583,6 +585,82 @@ function removeUndefined(obj) {
|
|
|
583
585
|
return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined));
|
|
584
586
|
}
|
|
585
587
|
|
|
588
|
+
/**
|
|
589
|
+
* Default Config
|
|
590
|
+
*
|
|
591
|
+
* @type {Config}
|
|
592
|
+
*/
|
|
593
|
+
const DEFAULT_CONFIG = {
|
|
594
|
+
model: 'openai/gpt-4',
|
|
595
|
+
verbose: false,
|
|
596
|
+
tokenLimit: 1024,
|
|
597
|
+
summarizePrompt: SUMMARIZE_PROMPT.template,
|
|
598
|
+
temperature: 0.4,
|
|
599
|
+
mode: 'stdout',
|
|
600
|
+
ignoredFiles: ['package-lock.json'],
|
|
601
|
+
ignoredExtensions: ['.map', '.lock'],
|
|
602
|
+
defaultBranch: 'main',
|
|
603
|
+
};
|
|
604
|
+
/**
|
|
605
|
+
* Config keys
|
|
606
|
+
*
|
|
607
|
+
* @type {string[]}
|
|
608
|
+
*/
|
|
609
|
+
const CONFIG_KEYS = Object.keys({
|
|
610
|
+
...DEFAULT_CONFIG,
|
|
611
|
+
huggingFaceHubApiKey: '',
|
|
612
|
+
openAIApiKey: '',
|
|
613
|
+
prompt: '',
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
async function updateFileSection(filePath, startComment, endComment, getNewContent, confirmUpdate = true) {
|
|
617
|
+
const lines = fs__default.existsSync(filePath) ? fs__default.readFileSync(filePath, 'utf-8').split(/\r?\n/) : [];
|
|
618
|
+
const newLines = [];
|
|
619
|
+
let foundSection = false;
|
|
620
|
+
for (let i = 0; i < lines.length; i++) {
|
|
621
|
+
if (lines[i].trim() === startComment) {
|
|
622
|
+
foundSection = true;
|
|
623
|
+
if (confirmUpdate) {
|
|
624
|
+
const confirmOverwrite = await confirm({
|
|
625
|
+
message: `A section already exists in ${filePath}, do you want to override it?`,
|
|
626
|
+
default: false,
|
|
627
|
+
});
|
|
628
|
+
if (!confirmOverwrite) {
|
|
629
|
+
// keep all lines until the end comment
|
|
630
|
+
while (i < lines.length && lines[i].trim() !== endComment) {
|
|
631
|
+
newLines.push(lines[i]);
|
|
632
|
+
i++;
|
|
633
|
+
}
|
|
634
|
+
newLines.push(endComment);
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
newLines.push(startComment);
|
|
639
|
+
// Insert the new content
|
|
640
|
+
const newContent = await getNewContent();
|
|
641
|
+
newLines.push(newContent);
|
|
642
|
+
// Skip the existing content of the section
|
|
643
|
+
while (i < lines.length && lines[i].trim() !== endComment) {
|
|
644
|
+
i++;
|
|
645
|
+
}
|
|
646
|
+
newLines.push(endComment);
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
649
|
+
if (!foundSection || lines[i].trim() !== endComment) {
|
|
650
|
+
newLines.push(lines[i]);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
// If section wasn't found, append it at the end
|
|
654
|
+
if (!foundSection) {
|
|
655
|
+
newLines.push('\n' + startComment);
|
|
656
|
+
const newContent = await getNewContent();
|
|
657
|
+
newLines.push(newContent);
|
|
658
|
+
newLines.push(endComment);
|
|
659
|
+
}
|
|
660
|
+
// Write the updated contents back to the file
|
|
661
|
+
fs__default.writeFileSync(filePath, newLines.join('\n'));
|
|
662
|
+
}
|
|
663
|
+
|
|
586
664
|
/**
|
|
587
665
|
* Load environment variables
|
|
588
666
|
*
|
|
@@ -590,27 +668,65 @@ function removeUndefined(obj) {
|
|
|
590
668
|
* @returns {Config} Updated config
|
|
591
669
|
**/
|
|
592
670
|
function loadEnvConfig(config) {
|
|
593
|
-
const envConfig = {
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
? process.env.COCO_IGNORED_FILES.split(',')
|
|
605
|
-
: undefined,
|
|
606
|
-
ignoredExtensions: process.env.COCO_IGNORED_EXTENSIONS
|
|
607
|
-
? process.env.COCO_IGNORED_EXTENSIONS.split(',')
|
|
608
|
-
: undefined,
|
|
609
|
-
defaultBranch: process.env.COCO_DEFAULT_BRANCH || undefined,
|
|
610
|
-
};
|
|
611
|
-
config = { ...config, ...removeUndefined(envConfig) };
|
|
612
|
-
return config;
|
|
671
|
+
const envConfig = {};
|
|
672
|
+
CONFIG_KEYS.forEach((key) => {
|
|
673
|
+
const envVarName = toEnvVarName(key);
|
|
674
|
+
const envValue = parseEnvValue(key, process.env[envVarName]);
|
|
675
|
+
if (envValue === undefined)
|
|
676
|
+
return;
|
|
677
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
678
|
+
// @ts-ignore
|
|
679
|
+
envConfig[key] = envValue;
|
|
680
|
+
});
|
|
681
|
+
return { ...config, ...removeUndefined(envConfig) };
|
|
613
682
|
}
|
|
683
|
+
function parseEnvValue(key, value) {
|
|
684
|
+
if (value === undefined) {
|
|
685
|
+
return undefined;
|
|
686
|
+
}
|
|
687
|
+
else if (key === 'tokenLimit' && typeof value === 'string') {
|
|
688
|
+
return parseInt(value);
|
|
689
|
+
}
|
|
690
|
+
else if ((key === 'ignoredFiles' || key === 'ignoredExtensions') &&
|
|
691
|
+
typeof value === 'string' &&
|
|
692
|
+
value.includes(',')) {
|
|
693
|
+
return value.split(',');
|
|
694
|
+
}
|
|
695
|
+
return value;
|
|
696
|
+
}
|
|
697
|
+
function toEnvVarName(key) {
|
|
698
|
+
switch (key) {
|
|
699
|
+
case 'openAIApiKey':
|
|
700
|
+
return 'OPENAI_API_KEY';
|
|
701
|
+
case 'huggingFaceHubApiKey':
|
|
702
|
+
return 'HUGGINGFACE_HUB_API_KEY';
|
|
703
|
+
default:
|
|
704
|
+
return 'COCO_' + key.replace(/([A-Z])/g, '_$1').toUpperCase();
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
function formatEnvValue(value) {
|
|
708
|
+
if (typeof value === 'number') {
|
|
709
|
+
return `${value}`;
|
|
710
|
+
}
|
|
711
|
+
else if (Array.isArray(value)) {
|
|
712
|
+
return `${value.join(',')}`;
|
|
713
|
+
}
|
|
714
|
+
else if (typeof value === 'string') {
|
|
715
|
+
// Escape newlines and tabs in strings
|
|
716
|
+
return `${value.replace(/\n/g, '\\n').replace(/\t/g, '\\t')}`;
|
|
717
|
+
}
|
|
718
|
+
return `${value}`;
|
|
719
|
+
}
|
|
720
|
+
const appendToEnvFile = async (filePath, config) => {
|
|
721
|
+
const startComment = '# -- Start coco config --';
|
|
722
|
+
const endComment = '# -- End coco config --';
|
|
723
|
+
const getNewContent = async () => {
|
|
724
|
+
return Object.entries(config)
|
|
725
|
+
.map(([key, value]) => `${toEnvVarName(key)}=${formatEnvValue(value)}`)
|
|
726
|
+
.join('\n');
|
|
727
|
+
};
|
|
728
|
+
await updateFileSection(filePath, startComment, endComment, getNewContent);
|
|
729
|
+
};
|
|
614
730
|
|
|
615
731
|
/**
|
|
616
732
|
* Load git profile config (from ~/.gitconfig)
|
|
@@ -640,6 +756,38 @@ function loadGitConfig(config) {
|
|
|
640
756
|
}
|
|
641
757
|
return config;
|
|
642
758
|
}
|
|
759
|
+
/**
|
|
760
|
+
* Appends the provided configuration to a git config file.
|
|
761
|
+
*
|
|
762
|
+
* @param filePath - The path to the .gitconfig
|
|
763
|
+
* @param config - The configuration object to append.
|
|
764
|
+
*/
|
|
765
|
+
const appendToGitConfig = async (filePath, config) => {
|
|
766
|
+
if (!fs.existsSync(filePath)) {
|
|
767
|
+
throw new Error(`File ${filePath} does not exist.`);
|
|
768
|
+
}
|
|
769
|
+
const startComment = '# -- Start coco config --';
|
|
770
|
+
const endComment = '# -- End coco config --';
|
|
771
|
+
const header = '[coco]';
|
|
772
|
+
// Function to generate new content for the coco section
|
|
773
|
+
const getNewContent = async () => {
|
|
774
|
+
const contentLines = [header];
|
|
775
|
+
for (const key in config) {
|
|
776
|
+
// check if string has new lines, if so, wrap in quotes
|
|
777
|
+
if (typeof config[key] === 'string') {
|
|
778
|
+
const value = config[key];
|
|
779
|
+
if (value.includes('\n')) {
|
|
780
|
+
contentLines.push(`\t${key} = ${JSON.stringify(value)}`);
|
|
781
|
+
continue;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
contentLines.push(`\t${key} = ${config[key]}`);
|
|
785
|
+
}
|
|
786
|
+
return contentLines.join('\n');
|
|
787
|
+
};
|
|
788
|
+
// Use the updateFileSection utility
|
|
789
|
+
await updateFileSection(filePath, startComment, endComment, getNewContent);
|
|
790
|
+
};
|
|
643
791
|
|
|
644
792
|
/**
|
|
645
793
|
* Load .gitignore in project root
|
|
@@ -689,6 +837,12 @@ function loadProjectConfig(config) {
|
|
|
689
837
|
}
|
|
690
838
|
return config;
|
|
691
839
|
}
|
|
840
|
+
const appendToProjectConfig = (filePath, config) => {
|
|
841
|
+
fs.writeFileSync(filePath, JSON.stringify({
|
|
842
|
+
$schema: 'https://git-co.co/schema.json',
|
|
843
|
+
...config,
|
|
844
|
+
}, null, 2));
|
|
845
|
+
};
|
|
692
846
|
|
|
693
847
|
/**
|
|
694
848
|
* Load XDG config
|
|
@@ -706,22 +860,6 @@ function loadXDGConfig(config) {
|
|
|
706
860
|
return config;
|
|
707
861
|
}
|
|
708
862
|
|
|
709
|
-
/**
|
|
710
|
-
* Default Config
|
|
711
|
-
*
|
|
712
|
-
* @type {Config}
|
|
713
|
-
*/
|
|
714
|
-
const DEFAULT_CONFIG = {
|
|
715
|
-
model: 'openai/gpt-4',
|
|
716
|
-
verbose: false,
|
|
717
|
-
tokenLimit: 1024,
|
|
718
|
-
summarizePrompt: SUMMARIZE_PROMPT.template,
|
|
719
|
-
temperature: 0.4,
|
|
720
|
-
mode: 'stdout',
|
|
721
|
-
ignoredFiles: ['package-lock.json'],
|
|
722
|
-
ignoredExtensions: ['.map', '.lock'],
|
|
723
|
-
defaultBranch: 'main',
|
|
724
|
-
};
|
|
725
863
|
/**
|
|
726
864
|
* Load application config
|
|
727
865
|
*
|
|
@@ -841,8 +979,8 @@ const isInteractive = (argv) => {
|
|
|
841
979
|
};
|
|
842
980
|
const SEPERATOR = chalk.blue('----------------');
|
|
843
981
|
|
|
844
|
-
function logResult(result) {
|
|
845
|
-
console.log(`\n${chalk.bgBlue(chalk.bold(
|
|
982
|
+
function logResult(label, result) {
|
|
983
|
+
console.log(`\n${chalk.bgBlue(chalk.bold(`Proposed ${label}:`))}\n${SEPERATOR}\n${result}\n${SEPERATOR}\n`);
|
|
846
984
|
}
|
|
847
985
|
|
|
848
986
|
async function editResult(result, options) {
|
|
@@ -943,7 +1081,7 @@ async function generateAndReviewLoop({ label, factory, parser, noResult, agent,
|
|
|
943
1081
|
})
|
|
944
1082
|
.stopTimer();
|
|
945
1083
|
if (options?.interactive) {
|
|
946
|
-
logResult(result);
|
|
1084
|
+
logResult(label, result);
|
|
947
1085
|
const reviewAnswer = await getUserReviewDecision();
|
|
948
1086
|
if (reviewAnswer === 'cancel') {
|
|
949
1087
|
process.exit(0);
|
|
@@ -1033,7 +1171,7 @@ const getRepo = () => {
|
|
|
1033
1171
|
return git;
|
|
1034
1172
|
};
|
|
1035
1173
|
|
|
1036
|
-
async function handler$
|
|
1174
|
+
async function handler$2(argv) {
|
|
1037
1175
|
const tokenizer = getTokenizer();
|
|
1038
1176
|
const git = getRepo();
|
|
1039
1177
|
const options = loadConfig(argv);
|
|
@@ -1095,7 +1233,7 @@ async function handler$1(argv) {
|
|
|
1095
1233
|
/**
|
|
1096
1234
|
* Command line options via yargs
|
|
1097
1235
|
*/
|
|
1098
|
-
const options$
|
|
1236
|
+
const options$2 = {
|
|
1099
1237
|
model: { type: 'string', description: 'LLM/Model-Name' },
|
|
1100
1238
|
openAIApiKey: {
|
|
1101
1239
|
type: 'string',
|
|
@@ -1141,16 +1279,16 @@ const options$1 = {
|
|
|
1141
1279
|
description: 'Ignored extensions',
|
|
1142
1280
|
},
|
|
1143
1281
|
};
|
|
1144
|
-
const builder$
|
|
1145
|
-
return yargs.options(options$
|
|
1282
|
+
const builder$2 = (yargs) => {
|
|
1283
|
+
return yargs.options(options$2);
|
|
1146
1284
|
};
|
|
1147
1285
|
|
|
1148
1286
|
var commit = {
|
|
1149
1287
|
command: 'commit',
|
|
1150
1288
|
desc: 'Generate commit message',
|
|
1151
|
-
builder: builder$
|
|
1152
|
-
handler: handler$
|
|
1153
|
-
options: options$
|
|
1289
|
+
builder: builder$2,
|
|
1290
|
+
handler: handler$2,
|
|
1291
|
+
options: options$2,
|
|
1154
1292
|
};
|
|
1155
1293
|
|
|
1156
1294
|
const template = `Write informative git changelog, in the imperative, based on a series of individual messages.
|
|
@@ -1226,7 +1364,7 @@ async function getCommitLogCurrentBranch({ git, logger, comparisonBranch = 'main
|
|
|
1226
1364
|
return [];
|
|
1227
1365
|
}
|
|
1228
1366
|
|
|
1229
|
-
async function handler(argv) {
|
|
1367
|
+
async function handler$1(argv) {
|
|
1230
1368
|
const options = loadConfig(argv);
|
|
1231
1369
|
const logger = new Logger(options);
|
|
1232
1370
|
const git = getRepo();
|
|
@@ -1297,7 +1435,7 @@ async function handler(argv) {
|
|
|
1297
1435
|
/**
|
|
1298
1436
|
* Command line options via yargs
|
|
1299
1437
|
*/
|
|
1300
|
-
const options = {
|
|
1438
|
+
const options$1 = {
|
|
1301
1439
|
range: {
|
|
1302
1440
|
type: 'string',
|
|
1303
1441
|
alias: 'r',
|
|
@@ -1343,13 +1481,240 @@ const options = {
|
|
|
1343
1481
|
description: 'Ignored extensions',
|
|
1344
1482
|
},
|
|
1345
1483
|
};
|
|
1346
|
-
const builder = (yargs) => {
|
|
1347
|
-
return yargs.options(options);
|
|
1484
|
+
const builder$1 = (yargs) => {
|
|
1485
|
+
return yargs.options(options$1);
|
|
1348
1486
|
};
|
|
1349
1487
|
|
|
1350
1488
|
var changelog = {
|
|
1351
1489
|
command: 'changelog',
|
|
1352
1490
|
desc: 'Generate a changelog from a commit range',
|
|
1491
|
+
builder: builder$1,
|
|
1492
|
+
handler: handler$1,
|
|
1493
|
+
options: options$1,
|
|
1494
|
+
};
|
|
1495
|
+
|
|
1496
|
+
const handleProjectLevelConfig = async () => {
|
|
1497
|
+
const projectConfiguration = await select({
|
|
1498
|
+
message: 'select type project level configuration:',
|
|
1499
|
+
choices: [
|
|
1500
|
+
{
|
|
1501
|
+
name: '.coco.config.json',
|
|
1502
|
+
value: '.coco.config.json',
|
|
1503
|
+
},
|
|
1504
|
+
{
|
|
1505
|
+
name: '.env',
|
|
1506
|
+
value: '.env',
|
|
1507
|
+
},
|
|
1508
|
+
],
|
|
1509
|
+
});
|
|
1510
|
+
let configFile = '.coco.config.json';
|
|
1511
|
+
if (projectConfiguration === '.env') {
|
|
1512
|
+
configFile = '.env';
|
|
1513
|
+
if (!fs__default.existsSync('.env')) {
|
|
1514
|
+
fs__default.writeFileSync('.env', '');
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
return configFile;
|
|
1518
|
+
};
|
|
1519
|
+
const handleSystemLevelConfig = () => {
|
|
1520
|
+
return path__default.join(os__default.homedir(), '.gitconfig');
|
|
1521
|
+
};
|
|
1522
|
+
async function handler(argv) {
|
|
1523
|
+
const options = loadConfig(argv);
|
|
1524
|
+
const logger = new Logger(options);
|
|
1525
|
+
const level = await select({
|
|
1526
|
+
message: 'configure coco at the system or project level:',
|
|
1527
|
+
choices: [
|
|
1528
|
+
{
|
|
1529
|
+
name: 'system',
|
|
1530
|
+
value: 'system',
|
|
1531
|
+
description: 'add coco config to your global git config',
|
|
1532
|
+
},
|
|
1533
|
+
{
|
|
1534
|
+
name: 'project',
|
|
1535
|
+
value: 'project',
|
|
1536
|
+
description: 'add coco config to existing git project',
|
|
1537
|
+
},
|
|
1538
|
+
],
|
|
1539
|
+
});
|
|
1540
|
+
let configFilePath = '';
|
|
1541
|
+
switch (level) {
|
|
1542
|
+
case 'system':
|
|
1543
|
+
configFilePath = await handleSystemLevelConfig();
|
|
1544
|
+
break;
|
|
1545
|
+
case 'project':
|
|
1546
|
+
configFilePath = await handleProjectLevelConfig();
|
|
1547
|
+
break;
|
|
1548
|
+
}
|
|
1549
|
+
// interactive v.s stdout mode
|
|
1550
|
+
const mode = (await select({
|
|
1551
|
+
message: 'select mode:',
|
|
1552
|
+
choices: [
|
|
1553
|
+
{
|
|
1554
|
+
name: 'interactive',
|
|
1555
|
+
value: 'interactive',
|
|
1556
|
+
description: 'interactive prompt for creating, reviewing, and committing',
|
|
1557
|
+
},
|
|
1558
|
+
{
|
|
1559
|
+
name: 'stdout',
|
|
1560
|
+
value: 'stdout',
|
|
1561
|
+
description: 'print results to stdout',
|
|
1562
|
+
},
|
|
1563
|
+
],
|
|
1564
|
+
}));
|
|
1565
|
+
const apiKey = await password({
|
|
1566
|
+
message: `enter your OpenAI API key:`,
|
|
1567
|
+
validate(input) {
|
|
1568
|
+
return input.length > 0 ? true : 'API key cannot be empty';
|
|
1569
|
+
},
|
|
1570
|
+
});
|
|
1571
|
+
const tokenLimit = await input({
|
|
1572
|
+
message: 'maximum number of tokens for the commit message:',
|
|
1573
|
+
default: '500',
|
|
1574
|
+
});
|
|
1575
|
+
const defaultBranch = await input({
|
|
1576
|
+
message: 'default branch for the repository:',
|
|
1577
|
+
default: 'main',
|
|
1578
|
+
});
|
|
1579
|
+
const advOptions = await confirm({
|
|
1580
|
+
message: 'would you like to configure advanced options?',
|
|
1581
|
+
default: false,
|
|
1582
|
+
});
|
|
1583
|
+
const config = {
|
|
1584
|
+
openAIApiKey: '•••••••••••••••',
|
|
1585
|
+
tokenLimit: parseInt(tokenLimit),
|
|
1586
|
+
defaultBranch,
|
|
1587
|
+
mode,
|
|
1588
|
+
};
|
|
1589
|
+
/**
|
|
1590
|
+
* Prompt for advanced options
|
|
1591
|
+
*
|
|
1592
|
+
* e.g.
|
|
1593
|
+
* - temperature
|
|
1594
|
+
* - verbose logging
|
|
1595
|
+
* - ignored files
|
|
1596
|
+
* - ignored extensions
|
|
1597
|
+
* - commit message prompt
|
|
1598
|
+
*/
|
|
1599
|
+
if (advOptions) {
|
|
1600
|
+
const temperature = await input({
|
|
1601
|
+
message: 'temperature for the model:',
|
|
1602
|
+
default: '0.4',
|
|
1603
|
+
});
|
|
1604
|
+
config.temperature = parseFloat(temperature);
|
|
1605
|
+
config.verbose = await confirm({
|
|
1606
|
+
message: 'enable verbose logging:',
|
|
1607
|
+
default: false,
|
|
1608
|
+
});
|
|
1609
|
+
const promptForIgnores = await confirm({
|
|
1610
|
+
message: 'would you like to configure ignored files and extensions?',
|
|
1611
|
+
default: false,
|
|
1612
|
+
});
|
|
1613
|
+
if (promptForIgnores) {
|
|
1614
|
+
const ignoredFiles = await input({
|
|
1615
|
+
message: 'paths of files to be excluded when generating commit messages (comma-separated):',
|
|
1616
|
+
default: 'package-lock.json',
|
|
1617
|
+
});
|
|
1618
|
+
const ignoredExtensions = await input({
|
|
1619
|
+
message: 'file extensions to be excluded when generating commit messages (comma-separated):',
|
|
1620
|
+
default: '.map, .lock',
|
|
1621
|
+
});
|
|
1622
|
+
config.ignoredFiles =
|
|
1623
|
+
(ignoredFiles && ignoredFiles.split(',').map((file) => file.trim())) || [];
|
|
1624
|
+
config.ignoredExtensions =
|
|
1625
|
+
(ignoredExtensions && ignoredExtensions.split(',').map((ext) => ext.trim())) || [];
|
|
1626
|
+
}
|
|
1627
|
+
const promptForCommitPrompt = await confirm({
|
|
1628
|
+
message: 'would you like to configure the commit message prompt?',
|
|
1629
|
+
default: false,
|
|
1630
|
+
});
|
|
1631
|
+
if (promptForCommitPrompt) {
|
|
1632
|
+
const commitPrompt = await editor({
|
|
1633
|
+
message: 'modify default commit message prompt:',
|
|
1634
|
+
default: COMMIT_PROMPT.template,
|
|
1635
|
+
});
|
|
1636
|
+
config.prompt = commitPrompt;
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
logResult('Config', JSON.stringify(config, null, 2));
|
|
1640
|
+
// add to config after logging, so that the API key is not logged
|
|
1641
|
+
config.openAIApiKey = apiKey;
|
|
1642
|
+
const isApproved = await confirm({
|
|
1643
|
+
message: 'look good? (hiding API key for security)',
|
|
1644
|
+
});
|
|
1645
|
+
if (isApproved) {
|
|
1646
|
+
if (configFilePath.endsWith('.gitconfig')) {
|
|
1647
|
+
await appendToGitConfig(configFilePath, config);
|
|
1648
|
+
}
|
|
1649
|
+
else if (configFilePath === '.env') {
|
|
1650
|
+
await appendToEnvFile(configFilePath, config);
|
|
1651
|
+
}
|
|
1652
|
+
else if (configFilePath === '.coco.config.json') {
|
|
1653
|
+
await appendToProjectConfig(configFilePath, config);
|
|
1654
|
+
}
|
|
1655
|
+
logger.log(`init successful! 🦾🤖🎉`, { color: 'green' });
|
|
1656
|
+
}
|
|
1657
|
+
else {
|
|
1658
|
+
logger.log('init cancelled.', { color: 'yellow' });
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
|
|
1662
|
+
/**
|
|
1663
|
+
* Command line options via yargs
|
|
1664
|
+
*/
|
|
1665
|
+
const options = {
|
|
1666
|
+
model: { type: 'string', description: 'LLM/Model-Name' },
|
|
1667
|
+
openAIApiKey: {
|
|
1668
|
+
type: 'string',
|
|
1669
|
+
description: 'OpenAI API Key',
|
|
1670
|
+
conflicts: 'huggingFaceHubApiKey',
|
|
1671
|
+
},
|
|
1672
|
+
huggingFaceHubApiKey: {
|
|
1673
|
+
type: 'string',
|
|
1674
|
+
description: 'HuggingFace Hub API Key',
|
|
1675
|
+
conflicts: 'openAIApiKey',
|
|
1676
|
+
},
|
|
1677
|
+
tokenLimit: { type: 'number', description: 'Token limit' },
|
|
1678
|
+
prompt: {
|
|
1679
|
+
type: 'string',
|
|
1680
|
+
alias: 'p',
|
|
1681
|
+
description: 'Commit message prompt',
|
|
1682
|
+
},
|
|
1683
|
+
i: {
|
|
1684
|
+
type: 'boolean',
|
|
1685
|
+
alias: 'interactive',
|
|
1686
|
+
description: 'Toggle interactive mode',
|
|
1687
|
+
},
|
|
1688
|
+
s: {
|
|
1689
|
+
type: 'boolean',
|
|
1690
|
+
description: 'Automatically commit staged changes with generated commit message',
|
|
1691
|
+
default: false,
|
|
1692
|
+
},
|
|
1693
|
+
e: {
|
|
1694
|
+
type: 'boolean',
|
|
1695
|
+
alias: 'edit',
|
|
1696
|
+
description: 'Open commit message in editor before proceeding',
|
|
1697
|
+
},
|
|
1698
|
+
summarizePrompt: {
|
|
1699
|
+
type: 'string',
|
|
1700
|
+
description: 'Large file summary prompt',
|
|
1701
|
+
},
|
|
1702
|
+
ignoredFiles: {
|
|
1703
|
+
type: 'array',
|
|
1704
|
+
description: 'Ignored files',
|
|
1705
|
+
},
|
|
1706
|
+
ignoredExtensions: {
|
|
1707
|
+
type: 'array',
|
|
1708
|
+
description: 'Ignored extensions',
|
|
1709
|
+
},
|
|
1710
|
+
};
|
|
1711
|
+
const builder = (yargs) => {
|
|
1712
|
+
return yargs.options(options);
|
|
1713
|
+
};
|
|
1714
|
+
|
|
1715
|
+
var init = {
|
|
1716
|
+
command: 'init',
|
|
1717
|
+
desc: 'Setup coco for a new project or system',
|
|
1353
1718
|
builder,
|
|
1354
1719
|
handler,
|
|
1355
1720
|
options,
|
|
@@ -1368,6 +1733,11 @@ commit.builder, commit.handler)
|
|
|
1368
1733
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1369
1734
|
// @ts-ignore
|
|
1370
1735
|
changelog.builder, changelog.handler)
|
|
1736
|
+
.command(init.command, init.desc,
|
|
1737
|
+
// TODO: fix type on builder
|
|
1738
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1739
|
+
// @ts-ignore
|
|
1740
|
+
init.builder, init.handler)
|
|
1371
1741
|
.demandCommand()
|
|
1372
1742
|
.help().argv;
|
|
1373
1743
|
//# sourceMappingURL=index.esm.mjs.map
|