git-coco 0.5.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/dist/index.d.ts +263 -2
  2. package/dist/index.esm.mjs +427 -52
  3. package/dist/index.js +428 -51
  4. package/package.json +12 -5
  5. package/dist/commands/changelog/handler.d.ts +0 -3
  6. package/dist/commands/changelog/index.d.ts +0 -10
  7. package/dist/commands/changelog/options.d.ts +0 -16
  8. package/dist/commands/commit/handler.d.ts +0 -3
  9. package/dist/commands/commit/index.d.ts +0 -10
  10. package/dist/commands/commit/options.d.ts +0 -15
  11. package/dist/commands/types.d.ts +0 -14
  12. package/dist/index.esm.mjs.map +0 -1
  13. package/dist/lib/config/loadConfig.d.ts +0 -25
  14. package/dist/lib/config/services/env.d.ts +0 -8
  15. package/dist/lib/config/services/git.d.ts +0 -8
  16. package/dist/lib/config/services/ignore.d.ts +0 -15
  17. package/dist/lib/config/services/project.d.ts +0 -8
  18. package/dist/lib/config/services/xdg.d.ts +0 -8
  19. package/dist/lib/config/types.d.ts +0 -83
  20. package/dist/lib/langchain/chains/summarize.d.ts +0 -11
  21. package/dist/lib/langchain/executeChain.d.ts +0 -6
  22. package/dist/lib/langchain/prompts/changelog.d.ts +0 -3
  23. package/dist/lib/langchain/prompts/commitDefault.d.ts +0 -3
  24. package/dist/lib/langchain/prompts/summarize.d.ts +0 -3
  25. package/dist/lib/langchain/utils.d.ts +0 -48
  26. package/dist/lib/parsers/default/index.d.ts +0 -2
  27. package/dist/lib/parsers/default/utils/collectDiffs.d.ts +0 -8
  28. package/dist/lib/parsers/default/utils/createDiffTree.d.ts +0 -13
  29. package/dist/lib/parsers/default/utils/summarizeDiffs.d.ts +0 -26
  30. package/dist/lib/parsers/noResult.d.ts +0 -8
  31. package/dist/lib/simple-git/createCommit.d.ts +0 -2
  32. package/dist/lib/simple-git/getChanges.d.ts +0 -15
  33. package/dist/lib/simple-git/getChangesByCommit.d.ts +0 -13
  34. package/dist/lib/simple-git/getCommitLogCurrentBranch.d.ts +0 -9
  35. package/dist/lib/simple-git/getCommitLogRange.d.ts +0 -7
  36. package/dist/lib/simple-git/getCurrentBranchName.d.ts +0 -5
  37. package/dist/lib/simple-git/getDiff.d.ts +0 -7
  38. package/dist/lib/simple-git/getDiffFromCommmit.d.ts +0 -10
  39. package/dist/lib/simple-git/getRepo.d.ts +0 -2
  40. package/dist/lib/simple-git/getStatus.d.ts +0 -3
  41. package/dist/lib/simple-git/getSummaryText.d.ts +0 -3
  42. package/dist/lib/simple-git/helpers.d.ts +0 -6
  43. package/dist/lib/types.d.ts +0 -47
  44. package/dist/lib/ui/editPrompt.d.ts +0 -2
  45. package/dist/lib/ui/editResult.d.ts +0 -2
  46. package/dist/lib/ui/generateAndReviewLoop.d.ts +0 -16
  47. package/dist/lib/ui/getUserReviewDecision.d.ts +0 -2
  48. package/dist/lib/ui/handleResult.d.ts +0 -5
  49. package/dist/lib/ui/helpers.d.ts +0 -3
  50. package/dist/lib/ui/logResult.d.ts +0 -1
  51. package/dist/lib/ui/logSuccess.d.ts +0 -1
  52. package/dist/lib/utils/getPathFromFilePath.d.ts +0 -6
  53. package/dist/lib/utils/getTokenizer.d.ts +0 -9
  54. package/dist/lib/utils/logger.d.ts +0 -23
  55. package/dist/lib/utils/removeUndefined.d.ts +0 -9
  56. package/dist/stats.html +0 -5305
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
- model: process.env.COCO_MODEL || undefined,
618
- openAIApiKey: process.env.OPENAI_API_KEY || undefined,
619
- huggingFaceHubApiKey: process.env.HUGGINGFACE_HUB_API_KEY || undefined,
620
- tokenLimit: process.env.COCO_TOKEN_LIMIT
621
- ? parseInt(process.env.COCO_TOKEN_LIMIT)
622
- : undefined,
623
- prompt: process.env.COCO_PROMPT,
624
- mode: process.env.COCO_MODE,
625
- summarizePrompt: process.env.COCO_SUMMARIZE_PROMPT,
626
- ignoredFiles: process.env.COCO_IGNORED_FILES
627
- ? process.env.COCO_IGNORED_FILES.split(',')
628
- : undefined,
629
- ignoredExtensions: process.env.COCO_IGNORED_EXTENSIONS
630
- ? process.env.COCO_IGNORED_EXTENSIONS.split(',')
631
- : undefined,
632
- defaultBranch: process.env.COCO_DEFAULT_BRANCH || undefined,
633
- };
634
- config = { ...config, ...removeUndefined(envConfig) };
635
- return config;
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('Proposed Commit:'))}\n${SEPERATOR}\n${result}\n${SEPERATOR}\n`);
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$1(argv) {
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$1 = {
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$1 = (yargs) => {
1168
- return yargs.options(options$1);
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$1,
1175
- handler: handler$1,
1176
- options: options$1,
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,18 +1502,249 @@ 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,
1379
1742
  };
1380
1743
 
1744
+ var types = /*#__PURE__*/Object.freeze({
1745
+ __proto__: null
1746
+ });
1747
+
1381
1748
  yargs
1382
1749
  .scriptName('coco')
1383
1750
  .usage('$0 <cmd> [args]')
@@ -1391,5 +1758,15 @@ commit.builder, commit.handler)
1391
1758
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1392
1759
  // @ts-ignore
1393
1760
  changelog.builder, changelog.handler)
1761
+ .command(init.command, init.desc,
1762
+ // TODO: fix type on builder
1763
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1764
+ // @ts-ignore
1765
+ init.builder, init.handler)
1394
1766
  .demandCommand()
1395
1767
  .help().argv;
1768
+
1769
+ exports.changelog = changelog;
1770
+ exports.commit = commit;
1771
+ exports.init = init;
1772
+ exports.types = types;
package/package.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "name": "git-coco",
3
- "version": "0.5.0",
3
+ "version": "0.6.1",
4
4
  "description": "zero-effort git commits with coco.",
5
5
  "author": "gfargo <ghfargo@gmail.com>",
6
6
  "license": "MIT",
7
7
  "main": "dist/index.js",
8
8
  "module": "dist/index.esm.mjs",
9
9
  "files": [
10
- "dist"
10
+ "dist",
11
+ "!dist/dts"
11
12
  ],
13
+ "types": "dist/index.d.ts",
12
14
  "homepage": "https://github.com/gfargo/coco#readme",
13
15
  "bugs": {
14
16
  "url": "https://github.com/gfargo/coco/issues"
@@ -21,15 +23,19 @@
21
23
  "url": "git+https://github.com/gfargo/coco.git"
22
24
  },
23
25
  "scripts": {
24
- "test": "jest",
25
26
  "start": "npm run dev",
26
27
  "dev": "tsx watch src/index.ts",
27
28
  "build": "rollup -c",
28
29
  "build:watch": "rollup -c -w",
30
+ "clean": "rimraf dist && rimraf coverage",
29
31
  "lint": "eslint src",
30
32
  "lint:fix": "eslint --fix src",
33
+ "format": "prettier --write src",
34
+ "test": "npm run test:jest && npm run test:publish",
35
+ "test:publish": "npm run lint && npm publish --dry-run",
36
+ "test:jest": "jest",
31
37
  "release": "release-it",
32
- "prepublishOnly": "rimraf dist && npm run build",
38
+ "prepublishOnly": "npm run clean && npm run build",
33
39
  "coco": "npm run coco:ts",
34
40
  "coco:ts": "tsx src/index.ts",
35
41
  "coco:cjs": "node dist/index.js",
@@ -47,7 +53,7 @@
47
53
  "@types/diff": "^5.0.3",
48
54
  "@types/ini": "^1.3.31",
49
55
  "@types/inquirer": "^9.0.3",
50
- "@types/jest": "^29.5.2",
56
+ "@types/jest": "^29.5.10",
51
57
  "@types/yargs": "^17.0.24",
52
58
  "@typescript-eslint/eslint-plugin": "^5.61.0",
53
59
  "@typescript-eslint/parser": "^5.61.0",
@@ -60,6 +66,7 @@
60
66
  "rollup": "^3.26.1",
61
67
  "rollup-plugin-banner2": "^1.2.2",
62
68
  "rollup-plugin-bin": "^1.0.0",
69
+ "rollup-plugin-dts": "^6.1.0",
63
70
  "rollup-plugin-executable": "^1.6.3",
64
71
  "rollup-plugin-peer-deps-external": "^2.2.4",
65
72
  "rollup-plugin-preserve-shebangs": "^0.2.0",
@@ -1,3 +0,0 @@
1
- import { Argv } from 'yargs';
2
- import { ChangelogOptions } from './options';
3
- export declare function handler(argv: Argv<ChangelogOptions>['argv']): Promise<void>;
@@ -1,10 +0,0 @@
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;
@@ -1,16 +0,0 @@
1
- import { Options, Argv } from 'yargs';
2
- import { BaseCommandOptions } from '../types';
3
- export interface ChangelogOptions extends BaseCommandOptions {
4
- range: string;
5
- prompt: string;
6
- commit: boolean;
7
- summarizePrompt: string;
8
- openInEditor: boolean;
9
- ignoredFiles: string[];
10
- ignoredExtensions: string[];
11
- }
12
- /**
13
- * Command line options via yargs
14
- */
15
- export declare const options: Record<string, Options>;
16
- export declare const builder: (yargs: Argv) => Argv<import("yargs").Omit<{}, string> & import("yargs").InferredOptionTypes<Record<string, Options>>>;
@@ -1,3 +0,0 @@
1
- import { CommitOptions } from './options';
2
- import { Argv } from 'yargs';
3
- export declare function handler(argv: Argv<CommitOptions>['argv']): Promise<void>;