gaunt-sloth-assistant 0.4.2 → 0.5.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 (135) hide show
  1. package/.claude/settings.local.json +15 -0
  2. package/.gsloth.backstory.md +0 -0
  3. package/.gsloth.guidelines.md +0 -0
  4. package/.gsloth.review.md +0 -0
  5. package/.gsloth.system.md +10 -0
  6. package/.prettierrc.json +0 -0
  7. package/CLAUDE.md +1 -0
  8. package/LICENSE +0 -0
  9. package/README.md +11 -1
  10. package/ROADMAP.md +0 -0
  11. package/assets/gaunt-sloth-logo.png +0 -0
  12. package/assets/release-notes/v0_4_0.md +0 -0
  13. package/assets/release-notes/v0_5_0.md +10 -0
  14. package/assets/release-notes/v0_5_1.md +47 -0
  15. package/dist/commands/askCommand.d.ts +0 -0
  16. package/dist/commands/askCommand.js +9 -5
  17. package/dist/commands/askCommand.js.map +1 -1
  18. package/dist/commands/commandUtils.d.ts +25 -0
  19. package/dist/commands/commandUtils.js +48 -0
  20. package/dist/commands/commandUtils.js.map +1 -0
  21. package/dist/commands/initCommand.d.ts +0 -0
  22. package/dist/commands/initCommand.js +0 -0
  23. package/dist/commands/initCommand.js.map +0 -0
  24. package/dist/commands/prCommand.d.ts +2 -0
  25. package/dist/commands/prCommand.js +52 -0
  26. package/dist/commands/prCommand.js.map +1 -0
  27. package/dist/commands/reviewCommand.d.ts +1 -2
  28. package/dist/commands/reviewCommand.js +17 -98
  29. package/dist/commands/reviewCommand.js.map +1 -1
  30. package/dist/config.d.ts +22 -41
  31. package/dist/config.js +107 -88
  32. package/dist/config.js.map +1 -1
  33. package/dist/configs/anthropic.d.ts +0 -0
  34. package/dist/configs/anthropic.js +0 -0
  35. package/dist/configs/anthropic.js.map +0 -0
  36. package/dist/configs/fake.d.ts +0 -0
  37. package/dist/configs/fake.js +0 -0
  38. package/dist/configs/fake.js.map +0 -0
  39. package/dist/configs/groq.d.ts +0 -0
  40. package/dist/configs/groq.js +0 -0
  41. package/dist/configs/groq.js.map +0 -0
  42. package/dist/configs/vertexai.d.ts +0 -0
  43. package/dist/configs/vertexai.js +0 -0
  44. package/dist/configs/vertexai.js.map +0 -0
  45. package/dist/consoleUtils.d.ts +0 -0
  46. package/dist/consoleUtils.js +0 -0
  47. package/dist/consoleUtils.js.map +0 -0
  48. package/dist/constants.d.ts +7 -0
  49. package/dist/constants.js +8 -0
  50. package/dist/constants.js.map +1 -0
  51. package/dist/filePathUtils.d.ts +0 -0
  52. package/dist/filePathUtils.js +0 -0
  53. package/dist/filePathUtils.js.map +0 -0
  54. package/dist/index.d.ts +0 -0
  55. package/dist/index.js +4 -2
  56. package/dist/index.js.map +1 -1
  57. package/dist/llmUtils.d.ts +2 -2
  58. package/dist/llmUtils.js +128 -28
  59. package/dist/llmUtils.js.map +1 -1
  60. package/dist/modules/questionAnsweringModule.d.ts +2 -1
  61. package/dist/modules/questionAnsweringModule.js +7 -8
  62. package/dist/modules/questionAnsweringModule.js.map +1 -1
  63. package/dist/modules/reviewModule.d.ts +2 -1
  64. package/dist/modules/reviewModule.js +7 -11
  65. package/dist/modules/reviewModule.js.map +1 -1
  66. package/dist/modules/types.d.ts +0 -0
  67. package/dist/modules/types.js +0 -0
  68. package/dist/modules/types.js.map +0 -0
  69. package/dist/prompt.d.ts +1 -0
  70. package/dist/prompt.js +4 -1
  71. package/dist/prompt.js.map +1 -1
  72. package/dist/providers/file.d.ts +0 -0
  73. package/dist/providers/file.js +0 -0
  74. package/dist/providers/file.js.map +0 -0
  75. package/dist/providers/ghIssueProvider.d.ts +0 -0
  76. package/dist/providers/ghIssueProvider.js +3 -1
  77. package/dist/providers/ghIssueProvider.js.map +1 -1
  78. package/dist/providers/ghPrDiffProvider.d.ts +0 -0
  79. package/dist/providers/ghPrDiffProvider.js +3 -1
  80. package/dist/providers/ghPrDiffProvider.js.map +1 -1
  81. package/dist/providers/jiraIssueLegacyProvider.d.ts +0 -0
  82. package/dist/providers/jiraIssueLegacyProvider.js +0 -0
  83. package/dist/providers/jiraIssueLegacyProvider.js.map +0 -0
  84. package/dist/providers/jiraIssueProvider.d.ts +0 -0
  85. package/dist/providers/jiraIssueProvider.js +3 -1
  86. package/dist/providers/jiraIssueProvider.js.map +1 -1
  87. package/dist/providers/text.d.ts +0 -0
  88. package/dist/providers/text.js +0 -0
  89. package/dist/providers/text.js.map +0 -0
  90. package/dist/providers/types.d.ts +0 -0
  91. package/dist/providers/types.js +0 -0
  92. package/dist/providers/types.js.map +0 -0
  93. package/dist/systemUtils.d.ts +0 -0
  94. package/dist/systemUtils.js +0 -0
  95. package/dist/systemUtils.js.map +0 -0
  96. package/dist/utils.d.ts +0 -0
  97. package/dist/utils.js +0 -0
  98. package/dist/utils.js.map +0 -0
  99. package/docs/CONFIGURATION.md +60 -26
  100. package/docs/DEVELOPMENT.md +0 -0
  101. package/docs/RELEASE-HOWTO.md +0 -0
  102. package/eslint.config.js +0 -0
  103. package/maintenance/doc-maintenance.md +0 -0
  104. package/package.json +11 -7
  105. package/src/commands/askCommand.ts +9 -5
  106. package/src/commands/commandUtils.ts +77 -0
  107. package/src/commands/initCommand.ts +0 -0
  108. package/src/commands/prCommand.ts +93 -0
  109. package/src/commands/reviewCommand.ts +33 -155
  110. package/src/config.ts +128 -128
  111. package/src/configs/anthropic.ts +0 -0
  112. package/src/configs/fake.ts +0 -0
  113. package/src/configs/groq.ts +0 -0
  114. package/src/configs/vertexai.ts +0 -0
  115. package/src/consoleUtils.ts +0 -0
  116. package/src/constants.ts +7 -0
  117. package/src/filePathUtils.ts +0 -0
  118. package/src/index.ts +4 -2
  119. package/src/llmUtils.ts +149 -36
  120. package/src/modules/questionAnsweringModule.ts +9 -13
  121. package/src/modules/reviewModule.ts +14 -11
  122. package/src/modules/types.ts +0 -0
  123. package/src/prompt.ts +5 -1
  124. package/src/providers/file.ts +0 -0
  125. package/src/providers/ghIssueProvider.ts +3 -1
  126. package/src/providers/ghPrDiffProvider.ts +3 -1
  127. package/src/providers/jiraIssueLegacyProvider.ts +0 -0
  128. package/src/providers/jiraIssueProvider.ts +5 -1
  129. package/src/providers/text.ts +0 -0
  130. package/src/providers/types.ts +0 -0
  131. package/src/systemUtils.ts +0 -0
  132. package/src/utils.ts +0 -0
  133. package/tsconfig.json +0 -0
  134. package/vitest-it.config.ts +0 -0
  135. package/vitest.config.ts +0 -0
@@ -0,0 +1,93 @@
1
+ import { Command, Option } from 'commander';
2
+ import {
3
+ readBackstory,
4
+ readGuidelines,
5
+ readReviewInstructions,
6
+ readSystemPrompt,
7
+ } from '#src/prompt.js';
8
+ import { readMultipleFilesFromCurrentDir } from '#src/utils.js';
9
+ import {
10
+ REQUIREMENTS_PROVIDERS,
11
+ CONTENT_PROVIDERS,
12
+ type RequirementsProviderType,
13
+ getRequirementsFromProvider,
14
+ type ContentProviderType,
15
+ } from './commandUtils.js';
16
+
17
+ interface PrCommandOptions {
18
+ file?: string[];
19
+ requirementsProvider?: RequirementsProviderType;
20
+ }
21
+
22
+ export function prCommand(program: Command): void {
23
+ program
24
+ .command('pr')
25
+ .description(
26
+ 'Review provided Pull Request in current directory. ' +
27
+ 'This command is similar to `review`, but default content provider is `github`. ' +
28
+ '(assuming that GitHub CLI is installed and authenticated for current project'
29
+ )
30
+ .argument('<prId>', 'Pull request ID to review.')
31
+ .argument(
32
+ '[requirementsId]',
33
+ 'Optional requirements ID argument to retrieve requirements with requirements provider'
34
+ )
35
+ .addOption(
36
+ new Option(
37
+ '-p, --requirements-provider <requirementsProvider>',
38
+ 'Requirements provider for this review.'
39
+ ).choices(Object.keys(REQUIREMENTS_PROVIDERS))
40
+ )
41
+ .option(
42
+ '-f, --file [files...]',
43
+ 'Input files. Content of these files will be added BEFORE the diff, but after requirements'
44
+ )
45
+ .action(async (prId: string, requirementsId: string | undefined, options: PrCommandOptions) => {
46
+ const { initConfig } = await import('#src/config.js');
47
+ const config = await initConfig(); // Initialize and get config
48
+
49
+ const systemPrompt = readSystemPrompt();
50
+ const systemMessage = [
51
+ readBackstory(),
52
+ readGuidelines(config.projectGuidelines),
53
+ readReviewInstructions(config.projectReviewInstructions),
54
+ ];
55
+ if (systemPrompt) {
56
+ systemMessage.push(systemPrompt);
57
+ }
58
+ const content: string[] = [];
59
+ const requirementsProvider =
60
+ options.requirementsProvider ??
61
+ (config?.commands?.pr?.requirementsProvider as RequirementsProviderType | undefined) ??
62
+ (config?.requirementsProvider as RequirementsProviderType | undefined);
63
+
64
+ const contentProvider =
65
+ (config?.commands?.pr?.contentProvider as ContentProviderType | undefined) ??
66
+ (config?.contentProvider as ContentProviderType | undefined) ??
67
+ 'github';
68
+
69
+ // Handle requirements
70
+ const requirements = await getRequirementsFromProvider(
71
+ requirementsProvider,
72
+ requirementsId,
73
+ config
74
+ );
75
+ if (requirements) {
76
+ content.push(requirements);
77
+ }
78
+
79
+ if (options.file) {
80
+ content.push(readMultipleFilesFromCurrentDir(options.file));
81
+ }
82
+
83
+ // Get PR diff using the provider
84
+ const providerPath = `#src/providers/${CONTENT_PROVIDERS[contentProvider]}`;
85
+ const { get } = await import(providerPath);
86
+ content.push(await get(null, prId));
87
+
88
+ const { review } = await import('#src/modules/reviewModule.js');
89
+ // TODO consider including requirements id
90
+ // TODO sanitize prId
91
+ await review(`PR-${prId}`, systemMessage.join('\n'), content.join('\n'), config, 'pr');
92
+ });
93
+ }
@@ -1,36 +1,20 @@
1
1
  import { Command, Option } from 'commander';
2
- import type { SlothContext } from '#src/config.js';
3
- import { slothContext } from '#src/config.js';
4
- import { readBackstory, readGuidelines, readReviewInstructions } from '#src/prompt.js';
2
+ import {
3
+ readBackstory,
4
+ readGuidelines,
5
+ readReviewInstructions,
6
+ readSystemPrompt,
7
+ } from '#src/prompt.js';
5
8
  import { readMultipleFilesFromCurrentDir } from '#src/utils.js';
6
- import { displayError } from '#src/consoleUtils.js';
7
9
  import { getStringFromStdin } from '#src/systemUtils.js';
8
-
9
- /**
10
- * Requirements providers. Expected to be in `.providers/` dir.
11
- * Aliases are mapped to actual providers in this file
12
- */
13
- const REQUIREMENTS_PROVIDERS = {
14
- 'jira-legacy': 'jiraIssueLegacyProvider.js',
15
- jira: 'jiraIssueProvider.js',
16
- github: 'ghIssueProvider.js',
17
- text: 'text.js',
18
- file: 'file.js',
19
- } as const;
20
-
21
- type RequirementsProviderType = keyof typeof REQUIREMENTS_PROVIDERS;
22
-
23
- /**
24
- * Content providers. Expected to be in `.providers/` dir.
25
- * Aliases are mapped to actual providers in this file
26
- */
27
- const CONTENT_PROVIDERS = {
28
- github: 'ghPrDiffProvider.js',
29
- text: 'text.js',
30
- file: 'file.js',
31
- } as const;
32
-
33
- type ContentProviderType = keyof typeof CONTENT_PROVIDERS;
10
+ import {
11
+ REQUIREMENTS_PROVIDERS,
12
+ CONTENT_PROVIDERS,
13
+ type RequirementsProviderType,
14
+ type ContentProviderType,
15
+ getRequirementsFromProvider,
16
+ getContentFromProvider,
17
+ } from './commandUtils.js';
34
18
 
35
19
  interface ReviewCommandOptions {
36
20
  file?: string[];
@@ -40,12 +24,7 @@ interface ReviewCommandOptions {
40
24
  message?: string;
41
25
  }
42
26
 
43
- interface PrCommandOptions {
44
- file?: string[];
45
- requirementsProvider?: RequirementsProviderType;
46
- }
47
-
48
- export function reviewCommand(program: Command, context: SlothContext): void {
27
+ export function reviewCommand(program: Command): void {
49
28
  program
50
29
  .command('review')
51
30
  .description('Review provided diff or other content')
@@ -75,32 +54,38 @@ export function reviewCommand(program: Command, context: SlothContext): void {
75
54
  .option('-m, --message <message>', 'Extra message to provide just before the content')
76
55
  .action(async (contentId: string | undefined, options: ReviewCommandOptions) => {
77
56
  const { initConfig } = await import('#src/config.js');
78
- await initConfig();
57
+ const config = await initConfig(); // Initialize and get config
58
+ const systemPrompt = readSystemPrompt();
79
59
  const systemMessage = [
80
60
  readBackstory(),
81
- readGuidelines(slothContext.config.projectGuidelines),
82
- readReviewInstructions(slothContext.config.projectReviewInstructions),
61
+ readGuidelines(config.projectGuidelines),
62
+ readReviewInstructions(config.projectReviewInstructions),
83
63
  ];
64
+ if (systemPrompt) {
65
+ systemMessage.push(systemPrompt);
66
+ }
84
67
  const content: string[] = [];
85
68
  const requirementsId = options.requirements;
86
69
  const requirementsProvider =
87
70
  options.requirementsProvider ??
88
- (context.config?.commands?.review?.requirementsProvider as
89
- | RequirementsProviderType
90
- | undefined) ??
91
- (context.config?.requirementsProvider as RequirementsProviderType | undefined);
71
+ (config?.commands?.review?.requirementsProvider as RequirementsProviderType | undefined) ??
72
+ (config?.requirementsProvider as RequirementsProviderType | undefined);
92
73
  const contentProvider =
93
74
  options.contentProvider ??
94
- (context.config?.commands?.review?.contentProvider as ContentProviderType | undefined) ??
95
- (context.config?.contentProvider as ContentProviderType | undefined);
75
+ (config?.commands?.review?.contentProvider as ContentProviderType | undefined) ??
76
+ (config?.contentProvider as ContentProviderType | undefined);
96
77
 
97
78
  // TODO consider calling these in parallel
98
- const requirements = await getRequirementsFromProvider(requirementsProvider, requirementsId);
79
+ const requirements = await getRequirementsFromProvider(
80
+ requirementsProvider,
81
+ requirementsId,
82
+ config
83
+ );
99
84
  if (requirements) {
100
85
  content.push(requirements);
101
86
  }
102
87
 
103
- const providedContent = await getContentFromProvider(contentProvider, contentId);
88
+ const providedContent = await getContentFromProvider(contentProvider, contentId, config);
104
89
  if (providedContent) {
105
90
  content.push(providedContent);
106
91
  }
@@ -116,113 +101,6 @@ export function reviewCommand(program: Command, context: SlothContext): void {
116
101
  content.push(options.message);
117
102
  }
118
103
  const { review } = await import('#src/modules/reviewModule.js');
119
- await review('REVIEW', systemMessage.join('\n'), content.join('\n'));
120
- });
121
-
122
- program
123
- .command('pr')
124
- .description(
125
- 'Review provided Pull Request in current directory. ' +
126
- 'This command is similar to `review`, but default content provider is `github`. ' +
127
- '(assuming that GitHub CLI is installed and authenticated for current project'
128
- )
129
- .argument('<prId>', 'Pull request ID to review.')
130
- .argument(
131
- '[requirementsId]',
132
- 'Optional requirements ID argument to retrieve requirements with requirements provider'
133
- )
134
- .addOption(
135
- new Option(
136
- '-p, --requirements-provider <requirementsProvider>',
137
- 'Requirements provider for this review.'
138
- ).choices(Object.keys(REQUIREMENTS_PROVIDERS))
139
- )
140
- .option(
141
- '-f, --file [files...]',
142
- 'Input files. Content of these files will be added BEFORE the diff, but after requirements'
143
- )
144
- .action(async (prId: string, requirementsId: string | undefined, options: PrCommandOptions) => {
145
- const { initConfig } = await import('#src/config.js');
146
- await initConfig();
147
-
148
- const systemMessage = [
149
- readBackstory(),
150
- readGuidelines(slothContext.config.projectGuidelines),
151
- readReviewInstructions(slothContext.config.projectReviewInstructions),
152
- ];
153
- const content: string[] = [];
154
- const requirementsProvider =
155
- options.requirementsProvider ??
156
- (context.config?.commands?.pr?.requirementsProvider as
157
- | RequirementsProviderType
158
- | undefined) ??
159
- (context.config?.requirementsProvider as RequirementsProviderType | undefined);
160
-
161
- // Handle requirements
162
- const requirements = await getRequirementsFromProvider(requirementsProvider, requirementsId);
163
- if (requirements) {
164
- content.push(requirements);
165
- }
166
-
167
- if (options.file) {
168
- content.push(readMultipleFilesFromCurrentDir(options.file));
169
- }
170
-
171
- // Get PR diff using the 'github' provider
172
- const providerPath = `#src/providers/${CONTENT_PROVIDERS['github']}`;
173
- const { get } = await import(providerPath);
174
- content.push(await get(null, prId));
175
-
176
- const { review } = await import('#src/modules/reviewModule.js');
177
- // TODO consider including requirements id
178
- // TODO sanitize prId
179
- await review(`PR-${prId}`, systemMessage.join('\n'), content.join('\n'));
104
+ await review('REVIEW', systemMessage.join('\n'), content.join('\n'), config);
180
105
  });
181
-
182
- async function getRequirementsFromProvider(
183
- requirementsProvider: RequirementsProviderType | undefined,
184
- requirementsId: string | undefined
185
- ): Promise<string> {
186
- return getFromProvider(
187
- requirementsProvider,
188
- requirementsId,
189
- (context.config?.requirementsProviderConfig ?? {})[requirementsProvider as string],
190
- REQUIREMENTS_PROVIDERS
191
- );
192
- }
193
-
194
- async function getContentFromProvider(
195
- contentProvider: ContentProviderType | undefined,
196
- contentId: string | undefined
197
- ): Promise<string> {
198
- return getFromProvider(
199
- contentProvider,
200
- contentId,
201
- (context.config?.contentProviderConfig ?? {})[contentProvider as string],
202
- CONTENT_PROVIDERS
203
- );
204
- }
205
-
206
- async function getFromProvider(
207
- provider: RequirementsProviderType | ContentProviderType | undefined,
208
- id: string | undefined,
209
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
210
- config: any,
211
- legitPredefinedProviders: typeof REQUIREMENTS_PROVIDERS | typeof CONTENT_PROVIDERS
212
- ): Promise<string> {
213
- if (typeof provider === 'string') {
214
- // Use one of the predefined providers
215
- if (legitPredefinedProviders[provider as keyof typeof legitPredefinedProviders]) {
216
- const providerPath = `#src/providers/${legitPredefinedProviders[provider as keyof typeof legitPredefinedProviders]}`;
217
- const { get } = await import(providerPath);
218
- return await get(config, id);
219
- } else {
220
- displayError(`Unknown provider: ${provider}. Continuing without it.`);
221
- }
222
- } else if (typeof provider === 'function') {
223
- // Type assertion to handle function call
224
- return await (provider as (id: string | undefined) => Promise<string>)(id);
225
- }
226
- return '';
227
- }
228
106
  }