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
package/dist/index.js
CHANGED
|
@@ -18,9 +18,9 @@ var prettyMilliseconds = require('pretty-ms');
|
|
|
18
18
|
var path = require('path');
|
|
19
19
|
var minimatch = require('minimatch');
|
|
20
20
|
var fs = require('fs');
|
|
21
|
+
var prompts$1 = require('@inquirer/prompts');
|
|
21
22
|
var os = require('os');
|
|
22
23
|
var ini = require('ini');
|
|
23
|
-
var prompts$1 = require('@inquirer/prompts');
|
|
24
24
|
var simpleGit = require('simple-git');
|
|
25
25
|
|
|
26
26
|
function _interopNamespaceDefault(e) {
|
|
@@ -606,6 +606,82 @@ function removeUndefined(obj) {
|
|
|
606
606
|
return Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== undefined));
|
|
607
607
|
}
|
|
608
608
|
|
|
609
|
+
/**
|
|
610
|
+
* Default Config
|
|
611
|
+
*
|
|
612
|
+
* @type {Config}
|
|
613
|
+
*/
|
|
614
|
+
const DEFAULT_CONFIG = {
|
|
615
|
+
model: 'openai/gpt-4',
|
|
616
|
+
verbose: false,
|
|
617
|
+
tokenLimit: 1024,
|
|
618
|
+
summarizePrompt: SUMMARIZE_PROMPT.template,
|
|
619
|
+
temperature: 0.4,
|
|
620
|
+
mode: 'stdout',
|
|
621
|
+
ignoredFiles: ['package-lock.json'],
|
|
622
|
+
ignoredExtensions: ['.map', '.lock'],
|
|
623
|
+
defaultBranch: 'main',
|
|
624
|
+
};
|
|
625
|
+
/**
|
|
626
|
+
* Config keys
|
|
627
|
+
*
|
|
628
|
+
* @type {string[]}
|
|
629
|
+
*/
|
|
630
|
+
const CONFIG_KEYS = Object.keys({
|
|
631
|
+
...DEFAULT_CONFIG,
|
|
632
|
+
huggingFaceHubApiKey: '',
|
|
633
|
+
openAIApiKey: '',
|
|
634
|
+
prompt: '',
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
async function updateFileSection(filePath, startComment, endComment, getNewContent, confirmUpdate = true) {
|
|
638
|
+
const lines = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8').split(/\r?\n/) : [];
|
|
639
|
+
const newLines = [];
|
|
640
|
+
let foundSection = false;
|
|
641
|
+
for (let i = 0; i < lines.length; i++) {
|
|
642
|
+
if (lines[i].trim() === startComment) {
|
|
643
|
+
foundSection = true;
|
|
644
|
+
if (confirmUpdate) {
|
|
645
|
+
const confirmOverwrite = await prompts$1.confirm({
|
|
646
|
+
message: `A section already exists in ${filePath}, do you want to override it?`,
|
|
647
|
+
default: false,
|
|
648
|
+
});
|
|
649
|
+
if (!confirmOverwrite) {
|
|
650
|
+
// keep all lines until the end comment
|
|
651
|
+
while (i < lines.length && lines[i].trim() !== endComment) {
|
|
652
|
+
newLines.push(lines[i]);
|
|
653
|
+
i++;
|
|
654
|
+
}
|
|
655
|
+
newLines.push(endComment);
|
|
656
|
+
continue;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
newLines.push(startComment);
|
|
660
|
+
// Insert the new content
|
|
661
|
+
const newContent = await getNewContent();
|
|
662
|
+
newLines.push(newContent);
|
|
663
|
+
// Skip the existing content of the section
|
|
664
|
+
while (i < lines.length && lines[i].trim() !== endComment) {
|
|
665
|
+
i++;
|
|
666
|
+
}
|
|
667
|
+
newLines.push(endComment);
|
|
668
|
+
continue;
|
|
669
|
+
}
|
|
670
|
+
if (!foundSection || lines[i].trim() !== endComment) {
|
|
671
|
+
newLines.push(lines[i]);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
// If section wasn't found, append it at the end
|
|
675
|
+
if (!foundSection) {
|
|
676
|
+
newLines.push('\n' + startComment);
|
|
677
|
+
const newContent = await getNewContent();
|
|
678
|
+
newLines.push(newContent);
|
|
679
|
+
newLines.push(endComment);
|
|
680
|
+
}
|
|
681
|
+
// Write the updated contents back to the file
|
|
682
|
+
fs.writeFileSync(filePath, newLines.join('\n'));
|
|
683
|
+
}
|
|
684
|
+
|
|
609
685
|
/**
|
|
610
686
|
* Load environment variables
|
|
611
687
|
*
|
|
@@ -613,27 +689,65 @@ function removeUndefined(obj) {
|
|
|
613
689
|
* @returns {Config} Updated config
|
|
614
690
|
**/
|
|
615
691
|
function loadEnvConfig(config) {
|
|
616
|
-
const envConfig = {
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
692
|
+
const envConfig = {};
|
|
693
|
+
CONFIG_KEYS.forEach((key) => {
|
|
694
|
+
const envVarName = toEnvVarName(key);
|
|
695
|
+
const envValue = parseEnvValue(key, process.env[envVarName]);
|
|
696
|
+
if (envValue === undefined)
|
|
697
|
+
return;
|
|
698
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
699
|
+
// @ts-ignore
|
|
700
|
+
envConfig[key] = envValue;
|
|
701
|
+
});
|
|
702
|
+
return { ...config, ...removeUndefined(envConfig) };
|
|
703
|
+
}
|
|
704
|
+
function parseEnvValue(key, value) {
|
|
705
|
+
if (value === undefined) {
|
|
706
|
+
return undefined;
|
|
707
|
+
}
|
|
708
|
+
else if (key === 'tokenLimit' && typeof value === 'string') {
|
|
709
|
+
return parseInt(value);
|
|
710
|
+
}
|
|
711
|
+
else if ((key === 'ignoredFiles' || key === 'ignoredExtensions') &&
|
|
712
|
+
typeof value === 'string' &&
|
|
713
|
+
value.includes(',')) {
|
|
714
|
+
return value.split(',');
|
|
715
|
+
}
|
|
716
|
+
return value;
|
|
636
717
|
}
|
|
718
|
+
function toEnvVarName(key) {
|
|
719
|
+
switch (key) {
|
|
720
|
+
case 'openAIApiKey':
|
|
721
|
+
return 'OPENAI_API_KEY';
|
|
722
|
+
case 'huggingFaceHubApiKey':
|
|
723
|
+
return 'HUGGINGFACE_HUB_API_KEY';
|
|
724
|
+
default:
|
|
725
|
+
return 'COCO_' + key.replace(/([A-Z])/g, '_$1').toUpperCase();
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
function formatEnvValue(value) {
|
|
729
|
+
if (typeof value === 'number') {
|
|
730
|
+
return `${value}`;
|
|
731
|
+
}
|
|
732
|
+
else if (Array.isArray(value)) {
|
|
733
|
+
return `${value.join(',')}`;
|
|
734
|
+
}
|
|
735
|
+
else if (typeof value === 'string') {
|
|
736
|
+
// Escape newlines and tabs in strings
|
|
737
|
+
return `${value.replace(/\n/g, '\\n').replace(/\t/g, '\\t')}`;
|
|
738
|
+
}
|
|
739
|
+
return `${value}`;
|
|
740
|
+
}
|
|
741
|
+
const appendToEnvFile = async (filePath, config) => {
|
|
742
|
+
const startComment = '# -- Start coco config --';
|
|
743
|
+
const endComment = '# -- End coco config --';
|
|
744
|
+
const getNewContent = async () => {
|
|
745
|
+
return Object.entries(config)
|
|
746
|
+
.map(([key, value]) => `${toEnvVarName(key)}=${formatEnvValue(value)}`)
|
|
747
|
+
.join('\n');
|
|
748
|
+
};
|
|
749
|
+
await updateFileSection(filePath, startComment, endComment, getNewContent);
|
|
750
|
+
};
|
|
637
751
|
|
|
638
752
|
/**
|
|
639
753
|
* Load git profile config (from ~/.gitconfig)
|
|
@@ -663,6 +777,38 @@ function loadGitConfig(config) {
|
|
|
663
777
|
}
|
|
664
778
|
return config;
|
|
665
779
|
}
|
|
780
|
+
/**
|
|
781
|
+
* Appends the provided configuration to a git config file.
|
|
782
|
+
*
|
|
783
|
+
* @param filePath - The path to the .gitconfig
|
|
784
|
+
* @param config - The configuration object to append.
|
|
785
|
+
*/
|
|
786
|
+
const appendToGitConfig = async (filePath, config) => {
|
|
787
|
+
if (!fs__namespace.existsSync(filePath)) {
|
|
788
|
+
throw new Error(`File ${filePath} does not exist.`);
|
|
789
|
+
}
|
|
790
|
+
const startComment = '# -- Start coco config --';
|
|
791
|
+
const endComment = '# -- End coco config --';
|
|
792
|
+
const header = '[coco]';
|
|
793
|
+
// Function to generate new content for the coco section
|
|
794
|
+
const getNewContent = async () => {
|
|
795
|
+
const contentLines = [header];
|
|
796
|
+
for (const key in config) {
|
|
797
|
+
// check if string has new lines, if so, wrap in quotes
|
|
798
|
+
if (typeof config[key] === 'string') {
|
|
799
|
+
const value = config[key];
|
|
800
|
+
if (value.includes('\n')) {
|
|
801
|
+
contentLines.push(`\t${key} = ${JSON.stringify(value)}`);
|
|
802
|
+
continue;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
contentLines.push(`\t${key} = ${config[key]}`);
|
|
806
|
+
}
|
|
807
|
+
return contentLines.join('\n');
|
|
808
|
+
};
|
|
809
|
+
// Use the updateFileSection utility
|
|
810
|
+
await updateFileSection(filePath, startComment, endComment, getNewContent);
|
|
811
|
+
};
|
|
666
812
|
|
|
667
813
|
/**
|
|
668
814
|
* Load .gitignore in project root
|
|
@@ -712,6 +858,12 @@ function loadProjectConfig(config) {
|
|
|
712
858
|
}
|
|
713
859
|
return config;
|
|
714
860
|
}
|
|
861
|
+
const appendToProjectConfig = (filePath, config) => {
|
|
862
|
+
fs__namespace.writeFileSync(filePath, JSON.stringify({
|
|
863
|
+
$schema: 'https://git-co.co/schema.json',
|
|
864
|
+
...config,
|
|
865
|
+
}, null, 2));
|
|
866
|
+
};
|
|
715
867
|
|
|
716
868
|
/**
|
|
717
869
|
* Load XDG config
|
|
@@ -729,22 +881,6 @@ function loadXDGConfig(config) {
|
|
|
729
881
|
return config;
|
|
730
882
|
}
|
|
731
883
|
|
|
732
|
-
/**
|
|
733
|
-
* Default Config
|
|
734
|
-
*
|
|
735
|
-
* @type {Config}
|
|
736
|
-
*/
|
|
737
|
-
const DEFAULT_CONFIG = {
|
|
738
|
-
model: 'openai/gpt-4',
|
|
739
|
-
verbose: false,
|
|
740
|
-
tokenLimit: 1024,
|
|
741
|
-
summarizePrompt: SUMMARIZE_PROMPT.template,
|
|
742
|
-
temperature: 0.4,
|
|
743
|
-
mode: 'stdout',
|
|
744
|
-
ignoredFiles: ['package-lock.json'],
|
|
745
|
-
ignoredExtensions: ['.map', '.lock'],
|
|
746
|
-
defaultBranch: 'main',
|
|
747
|
-
};
|
|
748
884
|
/**
|
|
749
885
|
* Load application config
|
|
750
886
|
*
|
|
@@ -864,8 +1000,8 @@ const isInteractive = (argv) => {
|
|
|
864
1000
|
};
|
|
865
1001
|
const SEPERATOR = chalk.blue('----------------');
|
|
866
1002
|
|
|
867
|
-
function logResult(result) {
|
|
868
|
-
console.log(`\n${chalk.bgBlue(chalk.bold(
|
|
1003
|
+
function logResult(label, result) {
|
|
1004
|
+
console.log(`\n${chalk.bgBlue(chalk.bold(`Proposed ${label}:`))}\n${SEPERATOR}\n${result}\n${SEPERATOR}\n`);
|
|
869
1005
|
}
|
|
870
1006
|
|
|
871
1007
|
async function editResult(result, options) {
|
|
@@ -966,7 +1102,7 @@ async function generateAndReviewLoop({ label, factory, parser, noResult, agent,
|
|
|
966
1102
|
})
|
|
967
1103
|
.stopTimer();
|
|
968
1104
|
if (options?.interactive) {
|
|
969
|
-
logResult(result);
|
|
1105
|
+
logResult(label, result);
|
|
970
1106
|
const reviewAnswer = await getUserReviewDecision();
|
|
971
1107
|
if (reviewAnswer === 'cancel') {
|
|
972
1108
|
process.exit(0);
|
|
@@ -1056,7 +1192,7 @@ const getRepo = () => {
|
|
|
1056
1192
|
return git;
|
|
1057
1193
|
};
|
|
1058
1194
|
|
|
1059
|
-
async function handler$
|
|
1195
|
+
async function handler$2(argv) {
|
|
1060
1196
|
const tokenizer = getTokenizer();
|
|
1061
1197
|
const git = getRepo();
|
|
1062
1198
|
const options = loadConfig(argv);
|
|
@@ -1118,7 +1254,7 @@ async function handler$1(argv) {
|
|
|
1118
1254
|
/**
|
|
1119
1255
|
* Command line options via yargs
|
|
1120
1256
|
*/
|
|
1121
|
-
const options$
|
|
1257
|
+
const options$2 = {
|
|
1122
1258
|
model: { type: 'string', description: 'LLM/Model-Name' },
|
|
1123
1259
|
openAIApiKey: {
|
|
1124
1260
|
type: 'string',
|
|
@@ -1164,16 +1300,16 @@ const options$1 = {
|
|
|
1164
1300
|
description: 'Ignored extensions',
|
|
1165
1301
|
},
|
|
1166
1302
|
};
|
|
1167
|
-
const builder$
|
|
1168
|
-
return yargs.options(options$
|
|
1303
|
+
const builder$2 = (yargs) => {
|
|
1304
|
+
return yargs.options(options$2);
|
|
1169
1305
|
};
|
|
1170
1306
|
|
|
1171
1307
|
var commit = {
|
|
1172
1308
|
command: 'commit',
|
|
1173
1309
|
desc: 'Generate commit message',
|
|
1174
|
-
builder: builder$
|
|
1175
|
-
handler: handler$
|
|
1176
|
-
options: options$
|
|
1310
|
+
builder: builder$2,
|
|
1311
|
+
handler: handler$2,
|
|
1312
|
+
options: options$2,
|
|
1177
1313
|
};
|
|
1178
1314
|
|
|
1179
1315
|
const template = `Write informative git changelog, in the imperative, based on a series of individual messages.
|
|
@@ -1249,7 +1385,7 @@ async function getCommitLogCurrentBranch({ git, logger, comparisonBranch = 'main
|
|
|
1249
1385
|
return [];
|
|
1250
1386
|
}
|
|
1251
1387
|
|
|
1252
|
-
async function handler(argv) {
|
|
1388
|
+
async function handler$1(argv) {
|
|
1253
1389
|
const options = loadConfig(argv);
|
|
1254
1390
|
const logger = new Logger(options);
|
|
1255
1391
|
const git = getRepo();
|
|
@@ -1320,7 +1456,7 @@ async function handler(argv) {
|
|
|
1320
1456
|
/**
|
|
1321
1457
|
* Command line options via yargs
|
|
1322
1458
|
*/
|
|
1323
|
-
const options = {
|
|
1459
|
+
const options$1 = {
|
|
1324
1460
|
range: {
|
|
1325
1461
|
type: 'string',
|
|
1326
1462
|
alias: 'r',
|
|
@@ -1366,13 +1502,240 @@ const options = {
|
|
|
1366
1502
|
description: 'Ignored extensions',
|
|
1367
1503
|
},
|
|
1368
1504
|
};
|
|
1369
|
-
const builder = (yargs) => {
|
|
1370
|
-
return yargs.options(options);
|
|
1505
|
+
const builder$1 = (yargs) => {
|
|
1506
|
+
return yargs.options(options$1);
|
|
1371
1507
|
};
|
|
1372
1508
|
|
|
1373
1509
|
var changelog = {
|
|
1374
1510
|
command: 'changelog',
|
|
1375
1511
|
desc: 'Generate a changelog from a commit range',
|
|
1512
|
+
builder: builder$1,
|
|
1513
|
+
handler: handler$1,
|
|
1514
|
+
options: options$1,
|
|
1515
|
+
};
|
|
1516
|
+
|
|
1517
|
+
const handleProjectLevelConfig = async () => {
|
|
1518
|
+
const projectConfiguration = await prompts$1.select({
|
|
1519
|
+
message: 'select type project level configuration:',
|
|
1520
|
+
choices: [
|
|
1521
|
+
{
|
|
1522
|
+
name: '.coco.config.json',
|
|
1523
|
+
value: '.coco.config.json',
|
|
1524
|
+
},
|
|
1525
|
+
{
|
|
1526
|
+
name: '.env',
|
|
1527
|
+
value: '.env',
|
|
1528
|
+
},
|
|
1529
|
+
],
|
|
1530
|
+
});
|
|
1531
|
+
let configFile = '.coco.config.json';
|
|
1532
|
+
if (projectConfiguration === '.env') {
|
|
1533
|
+
configFile = '.env';
|
|
1534
|
+
if (!fs.existsSync('.env')) {
|
|
1535
|
+
fs.writeFileSync('.env', '');
|
|
1536
|
+
}
|
|
1537
|
+
}
|
|
1538
|
+
return configFile;
|
|
1539
|
+
};
|
|
1540
|
+
const handleSystemLevelConfig = () => {
|
|
1541
|
+
return path.join(os.homedir(), '.gitconfig');
|
|
1542
|
+
};
|
|
1543
|
+
async function handler(argv) {
|
|
1544
|
+
const options = loadConfig(argv);
|
|
1545
|
+
const logger = new Logger(options);
|
|
1546
|
+
const level = await prompts$1.select({
|
|
1547
|
+
message: 'configure coco at the system or project level:',
|
|
1548
|
+
choices: [
|
|
1549
|
+
{
|
|
1550
|
+
name: 'system',
|
|
1551
|
+
value: 'system',
|
|
1552
|
+
description: 'add coco config to your global git config',
|
|
1553
|
+
},
|
|
1554
|
+
{
|
|
1555
|
+
name: 'project',
|
|
1556
|
+
value: 'project',
|
|
1557
|
+
description: 'add coco config to existing git project',
|
|
1558
|
+
},
|
|
1559
|
+
],
|
|
1560
|
+
});
|
|
1561
|
+
let configFilePath = '';
|
|
1562
|
+
switch (level) {
|
|
1563
|
+
case 'system':
|
|
1564
|
+
configFilePath = await handleSystemLevelConfig();
|
|
1565
|
+
break;
|
|
1566
|
+
case 'project':
|
|
1567
|
+
configFilePath = await handleProjectLevelConfig();
|
|
1568
|
+
break;
|
|
1569
|
+
}
|
|
1570
|
+
// interactive v.s stdout mode
|
|
1571
|
+
const mode = (await prompts$1.select({
|
|
1572
|
+
message: 'select mode:',
|
|
1573
|
+
choices: [
|
|
1574
|
+
{
|
|
1575
|
+
name: 'interactive',
|
|
1576
|
+
value: 'interactive',
|
|
1577
|
+
description: 'interactive prompt for creating, reviewing, and committing',
|
|
1578
|
+
},
|
|
1579
|
+
{
|
|
1580
|
+
name: 'stdout',
|
|
1581
|
+
value: 'stdout',
|
|
1582
|
+
description: 'print results to stdout',
|
|
1583
|
+
},
|
|
1584
|
+
],
|
|
1585
|
+
}));
|
|
1586
|
+
const apiKey = await prompts$1.password({
|
|
1587
|
+
message: `enter your OpenAI API key:`,
|
|
1588
|
+
validate(input) {
|
|
1589
|
+
return input.length > 0 ? true : 'API key cannot be empty';
|
|
1590
|
+
},
|
|
1591
|
+
});
|
|
1592
|
+
const tokenLimit = await prompts$1.input({
|
|
1593
|
+
message: 'maximum number of tokens for the commit message:',
|
|
1594
|
+
default: '500',
|
|
1595
|
+
});
|
|
1596
|
+
const defaultBranch = await prompts$1.input({
|
|
1597
|
+
message: 'default branch for the repository:',
|
|
1598
|
+
default: 'main',
|
|
1599
|
+
});
|
|
1600
|
+
const advOptions = await prompts$1.confirm({
|
|
1601
|
+
message: 'would you like to configure advanced options?',
|
|
1602
|
+
default: false,
|
|
1603
|
+
});
|
|
1604
|
+
const config = {
|
|
1605
|
+
openAIApiKey: 'β’β’β’β’β’β’β’β’β’β’β’β’β’β’β’',
|
|
1606
|
+
tokenLimit: parseInt(tokenLimit),
|
|
1607
|
+
defaultBranch,
|
|
1608
|
+
mode,
|
|
1609
|
+
};
|
|
1610
|
+
/**
|
|
1611
|
+
* Prompt for advanced options
|
|
1612
|
+
*
|
|
1613
|
+
* e.g.
|
|
1614
|
+
* - temperature
|
|
1615
|
+
* - verbose logging
|
|
1616
|
+
* - ignored files
|
|
1617
|
+
* - ignored extensions
|
|
1618
|
+
* - commit message prompt
|
|
1619
|
+
*/
|
|
1620
|
+
if (advOptions) {
|
|
1621
|
+
const temperature = await prompts$1.input({
|
|
1622
|
+
message: 'temperature for the model:',
|
|
1623
|
+
default: '0.4',
|
|
1624
|
+
});
|
|
1625
|
+
config.temperature = parseFloat(temperature);
|
|
1626
|
+
config.verbose = await prompts$1.confirm({
|
|
1627
|
+
message: 'enable verbose logging:',
|
|
1628
|
+
default: false,
|
|
1629
|
+
});
|
|
1630
|
+
const promptForIgnores = await prompts$1.confirm({
|
|
1631
|
+
message: 'would you like to configure ignored files and extensions?',
|
|
1632
|
+
default: false,
|
|
1633
|
+
});
|
|
1634
|
+
if (promptForIgnores) {
|
|
1635
|
+
const ignoredFiles = await prompts$1.input({
|
|
1636
|
+
message: 'paths of files to be excluded when generating commit messages (comma-separated):',
|
|
1637
|
+
default: 'package-lock.json',
|
|
1638
|
+
});
|
|
1639
|
+
const ignoredExtensions = await prompts$1.input({
|
|
1640
|
+
message: 'file extensions to be excluded when generating commit messages (comma-separated):',
|
|
1641
|
+
default: '.map, .lock',
|
|
1642
|
+
});
|
|
1643
|
+
config.ignoredFiles =
|
|
1644
|
+
(ignoredFiles && ignoredFiles.split(',').map((file) => file.trim())) || [];
|
|
1645
|
+
config.ignoredExtensions =
|
|
1646
|
+
(ignoredExtensions && ignoredExtensions.split(',').map((ext) => ext.trim())) || [];
|
|
1647
|
+
}
|
|
1648
|
+
const promptForCommitPrompt = await prompts$1.confirm({
|
|
1649
|
+
message: 'would you like to configure the commit message prompt?',
|
|
1650
|
+
default: false,
|
|
1651
|
+
});
|
|
1652
|
+
if (promptForCommitPrompt) {
|
|
1653
|
+
const commitPrompt = await prompts$1.editor({
|
|
1654
|
+
message: 'modify default commit message prompt:',
|
|
1655
|
+
default: COMMIT_PROMPT.template,
|
|
1656
|
+
});
|
|
1657
|
+
config.prompt = commitPrompt;
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
logResult('Config', JSON.stringify(config, null, 2));
|
|
1661
|
+
// add to config after logging, so that the API key is not logged
|
|
1662
|
+
config.openAIApiKey = apiKey;
|
|
1663
|
+
const isApproved = await prompts$1.confirm({
|
|
1664
|
+
message: 'look good? (hiding API key for security)',
|
|
1665
|
+
});
|
|
1666
|
+
if (isApproved) {
|
|
1667
|
+
if (configFilePath.endsWith('.gitconfig')) {
|
|
1668
|
+
await appendToGitConfig(configFilePath, config);
|
|
1669
|
+
}
|
|
1670
|
+
else if (configFilePath === '.env') {
|
|
1671
|
+
await appendToEnvFile(configFilePath, config);
|
|
1672
|
+
}
|
|
1673
|
+
else if (configFilePath === '.coco.config.json') {
|
|
1674
|
+
await appendToProjectConfig(configFilePath, config);
|
|
1675
|
+
}
|
|
1676
|
+
logger.log(`init successful! π¦Ύπ€π`, { color: 'green' });
|
|
1677
|
+
}
|
|
1678
|
+
else {
|
|
1679
|
+
logger.log('init cancelled.', { color: 'yellow' });
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
|
|
1683
|
+
/**
|
|
1684
|
+
* Command line options via yargs
|
|
1685
|
+
*/
|
|
1686
|
+
const options = {
|
|
1687
|
+
model: { type: 'string', description: 'LLM/Model-Name' },
|
|
1688
|
+
openAIApiKey: {
|
|
1689
|
+
type: 'string',
|
|
1690
|
+
description: 'OpenAI API Key',
|
|
1691
|
+
conflicts: 'huggingFaceHubApiKey',
|
|
1692
|
+
},
|
|
1693
|
+
huggingFaceHubApiKey: {
|
|
1694
|
+
type: 'string',
|
|
1695
|
+
description: 'HuggingFace Hub API Key',
|
|
1696
|
+
conflicts: 'openAIApiKey',
|
|
1697
|
+
},
|
|
1698
|
+
tokenLimit: { type: 'number', description: 'Token limit' },
|
|
1699
|
+
prompt: {
|
|
1700
|
+
type: 'string',
|
|
1701
|
+
alias: 'p',
|
|
1702
|
+
description: 'Commit message prompt',
|
|
1703
|
+
},
|
|
1704
|
+
i: {
|
|
1705
|
+
type: 'boolean',
|
|
1706
|
+
alias: 'interactive',
|
|
1707
|
+
description: 'Toggle interactive mode',
|
|
1708
|
+
},
|
|
1709
|
+
s: {
|
|
1710
|
+
type: 'boolean',
|
|
1711
|
+
description: 'Automatically commit staged changes with generated commit message',
|
|
1712
|
+
default: false,
|
|
1713
|
+
},
|
|
1714
|
+
e: {
|
|
1715
|
+
type: 'boolean',
|
|
1716
|
+
alias: 'edit',
|
|
1717
|
+
description: 'Open commit message in editor before proceeding',
|
|
1718
|
+
},
|
|
1719
|
+
summarizePrompt: {
|
|
1720
|
+
type: 'string',
|
|
1721
|
+
description: 'Large file summary prompt',
|
|
1722
|
+
},
|
|
1723
|
+
ignoredFiles: {
|
|
1724
|
+
type: 'array',
|
|
1725
|
+
description: 'Ignored files',
|
|
1726
|
+
},
|
|
1727
|
+
ignoredExtensions: {
|
|
1728
|
+
type: 'array',
|
|
1729
|
+
description: 'Ignored extensions',
|
|
1730
|
+
},
|
|
1731
|
+
};
|
|
1732
|
+
const builder = (yargs) => {
|
|
1733
|
+
return yargs.options(options);
|
|
1734
|
+
};
|
|
1735
|
+
|
|
1736
|
+
var init = {
|
|
1737
|
+
command: 'init',
|
|
1738
|
+
desc: 'Setup coco for a new project or system',
|
|
1376
1739
|
builder,
|
|
1377
1740
|
handler,
|
|
1378
1741
|
options,
|
|
@@ -1391,5 +1754,10 @@ commit.builder, commit.handler)
|
|
|
1391
1754
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1392
1755
|
// @ts-ignore
|
|
1393
1756
|
changelog.builder, changelog.handler)
|
|
1757
|
+
.command(init.command, init.desc,
|
|
1758
|
+
// TODO: fix type on builder
|
|
1759
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1760
|
+
// @ts-ignore
|
|
1761
|
+
init.builder, init.handler)
|
|
1394
1762
|
.demandCommand()
|
|
1395
1763
|
.help().argv;
|
|
@@ -6,3 +6,10 @@ import { Config } from '../types';
|
|
|
6
6
|
* @returns {Config} Updated config
|
|
7
7
|
**/
|
|
8
8
|
export declare function loadGitConfig(config: Config): Config;
|
|
9
|
+
/**
|
|
10
|
+
* Appends the provided configuration to a git config file.
|
|
11
|
+
*
|
|
12
|
+
* @param filePath - The path to the .gitconfig
|
|
13
|
+
* @param config - The configuration object to append.
|
|
14
|
+
*/
|
|
15
|
+
export declare const appendToGitConfig: (filePath: string, config: Partial<Config>) => Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function logResult(result: string): void;
|
|
1
|
+
export declare function logResult(label: string, result: string): void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function updateFileSection(filePath: string, startComment: string, endComment: string, getNewContent: () => Promise<string>, confirmUpdate?: boolean): Promise<void>;
|