git-coco 0.1.1 → 0.2.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.
package/dist/index.js CHANGED
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
- var nodegit = require('nodegit');
5
4
  var prompts$1 = require('@inquirer/prompts');
6
5
  var fs = require('fs');
7
6
  var os = require('os');
@@ -16,13 +15,13 @@ var ora = require('ora');
16
15
  var now = require('performance-now');
17
16
  var prettyMilliseconds = require('pretty-ms');
18
17
  var document = require('langchain/document');
19
- var diff = require('diff');
20
- var util = require('util');
21
18
  var chains = require('langchain/chains');
22
19
  var openai = require('langchain/llms/openai');
23
20
  var text_splitter = require('langchain/text_splitter');
21
+ var diff = require('diff');
24
22
  var GPT3NodeTokenizer = require('gpt3-tokenizer');
25
23
  var minimatch = require('minimatch');
24
+ var simpleGit = require('simple-git');
26
25
 
27
26
  function _interopNamespaceDefault(e) {
28
27
  var n = Object.create(null);
@@ -41,12 +40,10 @@ function _interopNamespaceDefault(e) {
41
40
  return Object.freeze(n);
42
41
  }
43
42
 
44
- var nodegit__namespace = /*#__PURE__*/_interopNamespaceDefault(nodegit);
45
43
  var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
46
44
  var os__namespace = /*#__PURE__*/_interopNamespaceDefault(os);
47
45
  var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
48
46
  var ini__namespace = /*#__PURE__*/_interopNamespaceDefault(ini);
49
- var util__namespace = /*#__PURE__*/_interopNamespaceDefault(util);
50
47
 
51
48
  /**
52
49
  * Returns a new object with all undefined keys removed
@@ -444,7 +441,7 @@ const defaultOutputCallback = (group) => {
444
441
  let output = `
445
442
  -------\n* changes in "/${group.path}"\n\n`;
446
443
  if (group.summary) {
447
- output += `${group.diffs.map((diff) => ` • ${diff.summary}`).join('\n')}\n\nSummary:${group.summary}\n\n`;
444
+ output += `${group.diffs.map((diff) => ` • ${diff.summary}`).join('\n')}\n\nSummary:\n\n${group.summary}\n\n`;
448
445
  }
449
446
  else {
450
447
  output += `${group.diffs.map((diff) => ` • ${diff.summary}\n\n${diff.diff}`).join('\n\n')}\n\n`;
@@ -568,61 +565,6 @@ async function collectDiffs(node, getFileDiff, tokenizer, logger = new Logger(co
568
565
  };
569
566
  }
570
567
 
571
- const readFile = util__namespace.promisify(fs__namespace.readFile);
572
-
573
- const parseDefaultFileDiff = async (nodeFile, repo, headTree, index) => {
574
- let result = '';
575
- const diff = await nodegit.Diff.treeToIndex(repo, headTree, index, {
576
- flags: 33554432 /* Diff.OPTION.SHOW_UNTRACKED_CONTENT */ | 16 /* Diff.OPTION.RECURSE_UNTRACKED_DIRS */,
577
- pathspec: nodeFile.filepath,
578
- });
579
- const patches = await diff.patches();
580
- for (const patch of patches) {
581
- const hunks = await patch.hunks();
582
- for (const hunk of hunks) {
583
- const lines = await hunk.lines();
584
- result += lines.map((line) => String.fromCharCode(line.origin()) + line.content()).join('');
585
- }
586
- }
587
- return result;
588
- };
589
- const parseRenamedFileDiff = async (nodeFile, repo, headTree, index, logger) => {
590
- let result = '';
591
- const oldFilepath = nodeFile?.oldFilepath || nodeFile.filepath;
592
- try {
593
- const headEntry = await headTree.entryByPath(oldFilepath); // use old name to look up in latest commit
594
- const indexEntry = index.getByPath(nodeFile.filepath); // use new name to look up in index
595
- // Compare the file contents in the latest commit and index
596
- const headBlob = await nodegit.Blob.lookup(repo, headEntry.sha());
597
- const indexBlobContent = await readFile(indexEntry.path); // read file from filesystem
598
- const headContent = headBlob.content().toString();
599
- const indexContent = indexBlobContent.toString();
600
- if (headContent !== indexContent) {
601
- result = diff.createTwoFilesPatch(oldFilepath, nodeFile.filepath, headContent, indexContent, '', '', { context: 3 });
602
- // remove the first 4 lines of the patch (they contain the old and new file names)
603
- result = result.split('\n').slice(4).join('\n');
604
- }
605
- else {
606
- result = 'File contents are unchanged.';
607
- }
608
- }
609
- catch (err) {
610
- logger.verbose(`Error comparing file contents for ${nodeFile.filepath}`, { color: 'red' });
611
- result = 'Error comparing file contents.';
612
- }
613
- return result;
614
- };
615
- const parseFileDiff = async (nodeFile, repo, headTree, index, logger) => {
616
- if (nodeFile.status === 'deleted') {
617
- return 'This file has been deleted.';
618
- }
619
- if (nodeFile.status === 'renamed' && nodeFile.oldFilepath) {
620
- return parseRenamedFileDiff(nodeFile, repo, headTree, index, logger);
621
- }
622
- // If not deleted or renamed, get the diff from the index
623
- return parseDefaultFileDiff(nodeFile, repo, headTree, index);
624
- };
625
-
626
568
  // TODO: Extend this to support other models! 🎉
627
569
  function getModel(fields, configuration) {
628
570
  return new openai.OpenAI(fields, configuration);
@@ -663,12 +605,50 @@ function validatePromptTemplate(text, inputVariables) {
663
605
  return true;
664
606
  }
665
607
 
608
+ const parseDefaultFileDiff = async (nodeFile, git) => {
609
+ return await git.diff(['--staged', nodeFile.filepath]);
610
+ };
611
+ const parseRenamedFileDiff = async (nodeFile, git, logger) => {
612
+ let result = '';
613
+ const oldFilepath = nodeFile?.oldFilepath || nodeFile.filepath;
614
+ try {
615
+ const [headContent, indexContent] = await Promise.all([
616
+ git.show([`HEAD:${oldFilepath}`]),
617
+ git.show([`:${nodeFile.filepath}`]),
618
+ ]);
619
+ if (headContent !== indexContent) {
620
+ result = diff.createTwoFilesPatch(oldFilepath, nodeFile.filepath, headContent, indexContent, '', '', {
621
+ context: 3,
622
+ });
623
+ // remove the first 4 lines of the patch (they contain the old and new file names)
624
+ result = result.split('\n').slice(4).join('\n');
625
+ }
626
+ else {
627
+ result = 'File contents are unchanged.';
628
+ }
629
+ }
630
+ catch (err) {
631
+ logger.verbose(`Error comparing file contents for ${nodeFile.filepath}`, { color: 'red' });
632
+ result = 'Error comparing file contents.';
633
+ }
634
+ return result;
635
+ };
636
+ const getDiff = async (nodeFile, { git, logger, }) => {
637
+ if (nodeFile.status === 'deleted') {
638
+ return 'This file has been deleted.';
639
+ }
640
+ if (nodeFile.status === 'renamed' && nodeFile.oldFilepath) {
641
+ const renamedDiff = await parseRenamedFileDiff(nodeFile, git, logger);
642
+ return renamedDiff;
643
+ }
644
+ // If not deleted or renamed, get the diff from the index
645
+ const defaultDiff = await parseDefaultFileDiff(nodeFile, git);
646
+ return defaultDiff;
647
+ };
648
+
666
649
  const MAX_TOKENS_PER_SUMMARY = 2048;
667
- const fileChangeParser = async (changes, { tokenizer, repo, model }) => {
650
+ const fileChangeParser = async (changes, { tokenizer, git, model }) => {
668
651
  const logger = new Logger(config);
669
- const head = await repo.getHeadCommit();
670
- const headTree = await head.getTree();
671
- const index = await repo.refreshIndex();
672
652
  const textSplitter = getTextSplitter({ chunkSize: 2000, chunkOverlap: 125, });
673
653
  const summarizationChain = getChain(model, {
674
654
  type: 'map_reduce',
@@ -680,7 +660,7 @@ const fileChangeParser = async (changes, { tokenizer, repo, model }) => {
680
660
  logger.stopTimer('Created file hierarchy');
681
661
  // Collect diffs
682
662
  logger.startTimer().startSpinner(`Collecting Diffs...\n`, { color: 'blue' });
683
- const diffs = await collectDiffs(rootTreeNode, (path) => parseFileDiff(path, repo, headTree, index, logger), tokenizer, logger);
663
+ const diffs = await collectDiffs(rootTreeNode, (path) => getDiff(path, { git, logger }), tokenizer, logger);
684
664
  logger.stopSpinner('Diffs Collected').stopTimer();
685
665
  // Summarize diffs
686
666
  logger.startTimer();
@@ -724,197 +704,102 @@ const getTokenizer = () => {
724
704
  return tokenizer;
725
705
  };
726
706
 
727
- const EMPTY_GIT_TREE_HASH = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
728
-
729
- const getSummaryText = (patch) => {
730
- const oldFilePath = patch.oldFile().path();
731
- const newFilePath = patch.newFile().path();
732
- let summary;
733
- if (patch.isAdded()) {
734
- summary = `added: ${newFilePath}`;
735
- }
736
- else if (patch.isDeleted()) {
737
- summary = `deleted: ${oldFilePath}`;
738
- }
739
- else if (patch.isModified()) {
740
- summary = `modified: ${newFilePath}`;
741
- }
742
- else if (patch.isRenamed()) {
743
- summary = `renamed: ${oldFilePath} -> ${newFilePath}`;
744
- }
745
- else if (patch.isUntracked()) {
746
- summary = `untracked: ${newFilePath}`;
747
- }
748
- else {
749
- summary = `unknown: ${newFilePath}`;
750
- }
751
- return summary;
707
+ const llm = async ({ llm, prompt, variables }) => {
708
+ const chain = new chains.LLMChain({ llm, prompt });
709
+ const res = await chain.call(variables);
710
+ if (res.error)
711
+ throw new Error(res.error);
712
+ return res.text.trim();
752
713
  };
753
714
 
754
- const getStatus = (patch) => {
715
+ const getStatus = (file, location = 'index') => {
716
+ const statusCode = file[location] ? file[location] : file.index;
755
717
  let status;
756
- if (patch.isAdded()) {
757
- status = 'added';
758
- }
759
- else if (patch.isDeleted()) {
760
- status = 'deleted';
761
- }
762
- else if (patch.isModified()) {
763
- status = 'modified';
764
- }
765
- else if (patch.isRenamed()) {
766
- status = 'renamed';
767
- }
768
- else if (patch.isUntracked()) {
769
- status = 'untracked';
770
- }
771
- else if (patch.newFile()) {
772
- status = 'new file';
773
- }
774
- else {
775
- status = 'unknown';
718
+ switch (statusCode) {
719
+ case 'A':
720
+ status = 'added';
721
+ break;
722
+ case 'D':
723
+ status = 'deleted';
724
+ break;
725
+ case 'M':
726
+ status = 'modified';
727
+ break;
728
+ case 'R':
729
+ status = 'renamed';
730
+ break;
731
+ case '?':
732
+ status = 'untracked';
733
+ break;
734
+ default:
735
+ status = 'unknown';
736
+ break;
776
737
  }
777
738
  return status;
778
739
  };
779
740
 
780
- const DEFAULT_IGNORED_FILES$1 = [
781
- ...(config?.ignoredFiles?.length && config?.ignoredFiles?.length > 0 ? config.ignoredFiles : []),
782
- ];
783
- const DEFAULT_IGNORED_EXTENSIONS$1 = [
784
- ...(config?.ignoredExtensions?.length && config?.ignoredExtensions?.length > 0
785
- ? config.ignoredExtensions
786
- : []),
787
- ];
788
- /**
789
- * Parse patches from a git diff.
790
- *
791
- * @param {ConvenientPatch[]} patches - An array of git patches.
792
- * @param {string[]} [options.ignoredFiles] - An optional array of file patterns to ignore.
793
- * If not provided, it defaults to the `ignoredFiles` configuration value from the app's config.
794
- * @param {string[]} [options.ignoredExtensions] - An optional array of file extensions to ignore.
795
- * If not provided, it defaults to the `ignoredExtensions` configuration value from the app's config.
796
- * @returns {Promise<FileChange[]>} A Promise that resolves to an array of file changes.
797
- **/
798
- const parsePatches = async (patches, { ignoredFiles = DEFAULT_IGNORED_FILES$1, ignoredExtensions = DEFAULT_IGNORED_EXTENSIONS$1, }) => patches
799
- .map((patch) => {
800
- const summary = getSummaryText(patch);
801
- const status = getStatus(patch);
802
- return {
803
- filepath: patch.newFile().path(),
804
- oldFilepath: status === 'renamed' ? patch.oldFile().path() : undefined,
805
- summary,
806
- status,
807
- };
808
- })
809
- .filter(Boolean)
810
- // Filter out ignored files & extensions...
811
- .filter(({ filepath }) => {
812
- if (!filepath)
813
- return false;
814
- const extension = filepath.split('.').pop();
815
- // Remove ignored extensions
816
- if (extension && ignoredExtensions.includes(extension))
817
- return false;
818
- // Remove ignored files
819
- if (ignoredFiles.some((pattern) => minimatch.minimatch(filepath, pattern)))
820
- return false;
821
- return true;
822
- });
823
-
824
- const DEFAULT_IGNORED_FILES = [
825
- ...(config?.ignoredFiles?.length && config?.ignoredFiles?.length > 0 ? config.ignoredFiles : []),
826
- ];
827
- const DEFAULT_IGNORED_EXTENSIONS = [
828
- ...(config?.ignoredExtensions?.length && config?.ignoredExtensions?.length > 0
829
- ? config.ignoredExtensions
830
- : []),
831
- ];
832
- /**
833
- * The 'git status' for coco
834
- *
835
- * Get paths of changed files in the Git repository, excluding ignored files and extensions.
836
- *
837
- * @param {string[]} [options.ignoredFiles] - An optional array of file patterns to ignore.
838
- * If not provided, it defaults to the `ignoredFiles` configuration value from the app's config.
839
- * @param {string[]} [options.ignoredExtensions] - An optional array of file extensions to ignore.
840
- * If not provided, it defaults to the `ignoredExtensions` configuration value from the app's config.
841
- * @returns {Promise<GetChangesResult>} A Promise that resolves to an array of changed file paths.
842
- *
843
- * @example
844
- * const changes = await getStagedChanges()
845
- * console.log(changes)
846
- * // {
847
- * // staged: [
848
- * // {
849
- * // filepath: 'src/index.ts',
850
- * // action: 'modified'
851
- * // },
852
- * // ],
853
- * // unstaged: [
854
- * // {
855
- * // filepath: 'src/index.test.ts',
856
- * // action: 'added'
857
- * // }
858
- * // ]
859
- * // }
860
- */
861
- async function getChanges(repo, options = {}) {
862
- const { ignoredFiles = DEFAULT_IGNORED_FILES, ignoredExtensions = DEFAULT_IGNORED_EXTENSIONS, ignoreUnstaged, ignoreUntracked, } = options;
863
- const head = await repo.getHeadCommit();
864
- const index = await repo.refreshIndex();
865
- const tree = await (head ? await head.getTree() : nodegit.Tree.lookup(repo, EMPTY_GIT_TREE_HASH));
866
- let unstaged = [];
867
- let untracked = [];
868
- if (!ignoreUnstaged) {
869
- const unstagedDiff = await nodegit.Diff.indexToWorkdir(repo, index, {
870
- flags: 16 /* Diff.OPTION.RECURSE_UNTRACKED_DIRS */,
871
- });
872
- const unstagedPatches = await unstagedDiff.patches();
873
- unstaged = await parsePatches(unstagedPatches, { ignoredFiles, ignoredExtensions });
874
- }
875
- if (!ignoreUntracked) {
876
- const untrackedDiff = await nodegit.Diff.treeToWorkdirWithIndex(repo, tree, {
877
- flags: 33554432 /* Diff.OPTION.SHOW_UNTRACKED_CONTENT */,
878
- });
879
- const untrackedPatches = await untrackedDiff.patches();
880
- untracked = (await parsePatches(untrackedPatches, { ignoredFiles, ignoredExtensions })).filter(({ status }) => status === 'untracked');
741
+ const getSummaryText = (file, change) => {
742
+ const status = change.status || getStatus(file);
743
+ if (change.oldFilepath) {
744
+ return `${status}: ${change.oldFilepath} -> ${file.path}`;
881
745
  }
882
- const diff = await nodegit.Diff.treeToIndex(repo, tree, index);
883
- await diff.findSimilar({
884
- flags: 1 /* Diff.FIND.RENAMES */,
746
+ return `${status}: ${file.path}`;
747
+ };
748
+
749
+ const DEFAULT_IGNORED_FILES = config?.ignoredFiles?.length ? config.ignoredFiles : [];
750
+ const DEFAULT_IGNORED_EXTENSIONS = config?.ignoredExtensions?.length ? config.ignoredExtensions : [];
751
+ async function getChanges(git, options = {}) {
752
+ const { ignoredFiles = DEFAULT_IGNORED_FILES, ignoredExtensions = DEFAULT_IGNORED_EXTENSIONS } = options;
753
+ const staged = [];
754
+ const unstaged = [];
755
+ const untracked = [];
756
+ const status = await git.status();
757
+ status.files.forEach((file) => {
758
+ const fileChange = {
759
+ filepath: file.path,
760
+ oldFilepath: status.renamed.filter((renamed) => renamed.to === file.path)[0]?.from,
761
+ };
762
+ // Unstaged files
763
+ if (file.working_dir !== '?' && file.working_dir !== ' ') {
764
+ fileChange.status = getStatus(file, 'working_dir');
765
+ fileChange.summary = getSummaryText(file, fileChange);
766
+ unstaged.push(fileChange);
767
+ }
768
+ // Staged files
769
+ if (file.index !== ' ' && file.index !== '?') {
770
+ fileChange.status = getStatus(file);
771
+ fileChange.summary = getSummaryText(file, fileChange);
772
+ staged.push(fileChange);
773
+ }
774
+ // Untracked files
775
+ if (file.working_dir === '?' && file.index === '?') {
776
+ fileChange.status = 'added';
777
+ fileChange.summary = getSummaryText(file, fileChange);
778
+ untracked.push(fileChange);
779
+ }
780
+ });
781
+ const ignoredExtensionsSet = new Set(ignoredExtensions.map((extension) => extension.toLowerCase()));
782
+ const filteredStaged = staged.filter((file) => {
783
+ const extension = path.extname(file.filepath).toLowerCase();
784
+ return !ignoredExtensionsSet.has(extension) && !ignoredFiles.some(ignoredPattern => minimatch.minimatch(file.filepath, ignoredPattern));
785
+ });
786
+ const filteredUnstaged = unstaged.filter((file) => {
787
+ const extension = path.extname(file.filepath).toLowerCase();
788
+ return !ignoredExtensionsSet.has(extension) && !ignoredFiles.some(ignoredPattern => minimatch.minimatch(file.filepath, ignoredPattern));
789
+ });
790
+ const filteredUntracked = untracked.filter((file) => {
791
+ const extension = path.extname(file.filepath).toLowerCase();
792
+ return !ignoredExtensionsSet.has(extension) && !ignoredFiles.some(ignoredPattern => minimatch.minimatch(file.filepath, ignoredPattern));
885
793
  });
886
- const patches = await diff.patches();
887
794
  return {
888
- staged: await parsePatches(patches, { ignoredFiles, ignoredExtensions }),
889
- unstaged,
890
- untracked,
795
+ staged: filteredStaged,
796
+ unstaged: filteredUnstaged,
797
+ untracked: filteredUntracked,
891
798
  };
892
799
  }
893
800
 
894
- async function createCommit(commitMsg, repo) {
895
- const author = await nodegit__namespace.Signature.default(repo);
896
- const index = await repo.refreshIndex();
897
- await index.addAll();
898
- await index.write();
899
- const oid = await index.writeTree();
900
- const head = await nodegit__namespace.Reference.nameToId(repo, "HEAD");
901
- const parent = await repo.getCommit(head);
902
- return await repo.createCommit("HEAD", author, author, commitMsg, oid, [parent]);
903
- }
904
-
905
- const llm = async ({ llm, prompt, variables }) => {
906
- const chain = new chains.LLMChain({ llm, prompt });
907
- const res = await chain.call(variables);
908
- if (res.error)
909
- throw new Error(res.error);
910
- return res.text.trim();
911
- };
912
-
913
- const noResult = async ({ repo, logger }) => {
914
- const { staged, unstaged, untracked } = await getChanges(repo, {
915
- ignoreUnstaged: false,
916
- ignoreUntracked: false,
917
- });
801
+ const noResult = async ({ git, logger }) => {
802
+ const { staged, unstaged, untracked } = await getChanges(git);
918
803
  if (staged.length > 0) {
919
804
  logger.log(`Staged files detected, but no summary generated...`, { color: 'red' });
920
805
  logger.log(`Files are likely either:\n • changed files are ignored\n • file diff is too large.`, { color: 'yellow' });
@@ -937,25 +822,26 @@ const noResult = async ({ repo, logger }) => {
937
822
  process.exit(0);
938
823
  };
939
824
 
825
+ async function createCommit(commitMsg, git) {
826
+ return await git.commit(commitMsg);
827
+ }
828
+
940
829
  const argv = loadArgv();
941
830
  const tokenizer = getTokenizer();
831
+ const git = simpleGit.simpleGit();
942
832
  async function main(options) {
943
833
  const logger = new Logger(config);
944
834
  if (!config.openAIApiKey) {
945
835
  logger.log(`No API Key found. 🗝️🚪`, { color: 'red' });
946
836
  process.exit(1);
947
837
  }
948
- const repo = await nodegit.Repository.open('.');
949
838
  const model = getModel({
950
839
  temperature: 0.4,
951
840
  maxConcurrency: 10,
952
841
  openAIApiKey: config.openAIApiKey,
953
842
  });
954
843
  const INTERACTIVE = config?.mode === 'interactive' || options.interactive;
955
- const { staged: changes } = await getChanges(repo, {
956
- ignoreUnstaged: true,
957
- ignoreUntracked: true,
958
- });
844
+ const { staged: changes } = await getChanges(git);
959
845
  let summary = '';
960
846
  let commitMsg = '';
961
847
  let promptTemplate = config?.prompt || '';
@@ -965,11 +851,11 @@ async function main(options) {
965
851
  logger.verbose(`\nChanged Files: \n ${changes.map(({ summary }) => summary).join('\n ')}`, {
966
852
  color: 'blue',
967
853
  });
968
- summary = await fileChangeParser(changes, { tokenizer, repo, model });
854
+ summary = await fileChangeParser(changes, { tokenizer, git, model });
969
855
  }
970
856
  // Handle empty summary
971
857
  if (!summary.length) {
972
- noResult({ repo, logger });
858
+ noResult({ git, logger });
973
859
  }
974
860
  // Prompt user for commit template prompt, if necessary
975
861
  if (modifyPrompt) {
@@ -1084,7 +970,7 @@ async function main(options) {
1084
970
  // Handle resulting commit message
1085
971
  switch (MODE) {
1086
972
  case 'interactive':
1087
- await createCommit(commitMsg, repo);
973
+ await createCommit(commitMsg, git);
1088
974
  logSuccess();
1089
975
  break;
1090
976
  case 'stdout':
@@ -1,8 +1,6 @@
1
- import { Repository } from 'nodegit';
2
1
  import { Logger } from '../utils/logger';
3
- type NoResultInput = {
4
- repo: Repository;
2
+ import { SimpleGit } from 'simple-git';
3
+ export declare const noResult: ({ git, logger }: {
4
+ git: SimpleGit;
5
5
  logger: Logger;
6
- };
7
- export declare const noResult: ({ repo, logger }: NoResultInput) => Promise<never>;
8
- export {};
6
+ }) => Promise<never>;
@@ -0,0 +1,2 @@
1
+ import { CommitResult, SimpleGit } from 'simple-git';
2
+ export declare function createCommit(commitMsg: string, git: SimpleGit): Promise<CommitResult>;
@@ -0,0 +1,12 @@
1
+ import { SimpleGit } from 'simple-git';
2
+ import { FileChange } from '../types';
3
+ export type GetChangesArgs = {
4
+ ignoredFiles?: string[];
5
+ ignoredExtensions?: string[];
6
+ };
7
+ export type GetChangesResult = {
8
+ staged: FileChange[];
9
+ unstaged?: FileChange[];
10
+ untracked?: FileChange[];
11
+ };
12
+ export declare function getChanges(git: SimpleGit, options?: GetChangesArgs): Promise<GetChangesResult>;
@@ -0,0 +1,7 @@
1
+ import { SimpleGit } from 'simple-git';
2
+ import { FileChange } from '../types';
3
+ import { Logger } from '../utils/logger';
4
+ export declare const getDiff: (nodeFile: FileChange, { git, logger, }: {
5
+ git: SimpleGit;
6
+ logger: Logger;
7
+ }) => Promise<string>;
@@ -0,0 +1,3 @@
1
+ import { FileChangeStatus } from '../types';
2
+ import { FileStatusResult } from 'simple-git';
3
+ export declare const getStatus: (file: FileStatusResult, location?: 'index' | 'working_dir') => FileChangeStatus;
@@ -0,0 +1,3 @@
1
+ import { FileStatusResult } from 'simple-git';
2
+ import { FileChange } from '../types';
3
+ export declare const getSummaryText: (file: FileStatusResult, change: Partial<FileChange>) => string;
@@ -1,7 +1,7 @@
1
1
  import GPT3Tokenizer from 'gpt3-tokenizer';
2
- import { Repository } from 'nodegit';
3
2
  import { getModel } from './langchain/utils';
4
- export type FileChangeStatus = 'modified' | 'renamed' | 'added' | 'new file' | 'deleted' | 'untracked' | 'unknown';
3
+ import { SimpleGit } from 'simple-git';
4
+ export type FileChangeStatus = 'modified' | 'renamed' | 'added' | 'deleted' | 'untracked' | 'unknown';
5
5
  export interface FileChange {
6
6
  summary: string;
7
7
  filepath: string;
@@ -29,6 +29,6 @@ export interface BaseParser {
29
29
  (changes: FileChange[], options: {
30
30
  tokenizer: GPT3Tokenizer;
31
31
  model: ReturnType<typeof getModel>;
32
- repo: Repository;
32
+ git: SimpleGit;
33
33
  }): Promise<string>;
34
34
  }