gaunt-sloth-assistant 0.3.2 → 0.4.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/README.md +39 -53
- package/assets/gaunt-sloth-logo.png +0 -0
- package/assets/release-notes/v0_4_0.md +39 -0
- package/dist/commands/askCommand.js +14 -3
- package/dist/commands/askCommand.js.map +1 -1
- package/dist/commands/reviewCommand.js +13 -10
- package/dist/commands/reviewCommand.js.map +1 -1
- package/dist/config.d.ts +10 -7
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/configs/anthropic.js +3 -4
- package/dist/configs/anthropic.js.map +1 -1
- package/dist/providers/ghIssueProvider.d.ts +8 -0
- package/dist/providers/ghIssueProvider.js +31 -0
- package/dist/providers/ghIssueProvider.js.map +1 -0
- package/dist/providers/ghPrDiffProvider.d.ts +4 -4
- package/dist/providers/ghPrDiffProvider.js +22 -7
- package/dist/providers/ghPrDiffProvider.js.map +1 -1
- package/dist/providers/jiraIssueProvider.js +11 -3
- package/dist/providers/jiraIssueProvider.js.map +1 -1
- package/docs/CONFIGURATION.md +76 -4
- package/docs/DEVELOPMENT.md +1 -2
- package/docs/RELEASE-HOWTO.md +4 -0
- package/eslint.config.js +1 -1
- package/maintenance/doc-maintenance.md +8 -0
- package/package.json +6 -5
- package/report.txt +43 -0
- package/src/commands/askCommand.ts +16 -3
- package/src/commands/reviewCommand.ts +17 -10
- package/src/config.ts +12 -9
- package/src/configs/anthropic.ts +3 -4
- package/src/providers/ghIssueProvider.ts +37 -0
- package/src/providers/ghPrDiffProvider.ts +24 -7
- package/src/providers/jiraIssueProvider.ts +14 -3
- package/tsconfig.json +1 -1
- package/vitest-it.config.ts +14 -0
- package/dist/configs/types.d.ts +0 -14
- package/dist/configs/types.js +0 -2
- package/dist/configs/types.js.map +0 -1
- package/dist/providers/jiraIssueLegacyAccessTokenProvider.d.ts +0 -8
- package/dist/providers/jiraIssueLegacyAccessTokenProvider.js +0 -62
- package/dist/providers/jiraIssueLegacyAccessTokenProvider.js.map +0 -1
package/docs/CONFIGURATION.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# Configuration
|
2
2
|
|
3
3
|
Populate `.gsloth.guidelines.md` with your project details and quality requirements.
|
4
|
-
|
4
|
+
A proper preamble is paramount for good inference.
|
5
5
|
Check [.gsloth.guidelines.md](../.gsloth.guidelines.md) for example.
|
6
6
|
|
7
7
|
Your project should have the following files in order for gsloth to function:
|
@@ -35,6 +35,40 @@ If the `.gsloth` directory doesn't exist, gsloth will continue writing all files
|
|
35
35
|
|
36
36
|
**Note:** When initializing a project with an existing `.gsloth` directory, the configuration files will be created in the `.gsloth/.gsloth-settings` directory automatically. There is no automated migration for existing configurations - if you create a `.gsloth` directory after initialization, you'll need to manually move your configuration files into the `.gsloth/.gsloth-settings` directory.
|
37
37
|
|
38
|
+
## Configuration Object
|
39
|
+
|
40
|
+
It is always worth checking sourcecode in [config.ts](../src/config.ts) for more insightful information.
|
41
|
+
|
42
|
+
| Parameter | Required | Default Value | Description |
|
43
|
+
|------------------------------------------|-----------------------------------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
44
|
+
| `llm` | Required | - | An object configuring LLM. In JS config could be actual instance of LangChainJS [BaseChatModel](https://v03.api.js.langchain.com/classes/_langchain_core.language_models_chat_models.BaseChatModel.html), allowing to use LLMs which do not have a preset. |
|
45
|
+
| `llm.type` | Required (when using JSON config) | - | LLM type or provider. Options currently available are `anthropic`, `groq` and `vertexai`. To use other models supported by LangChainJS, please use JavaScript config. |
|
46
|
+
| `llm.model` | Optional | - | Particular LLM model string (Check in your provider documentation). |
|
47
|
+
| `llm.apiKey` | Optional | - | API key for the LLM provider. You can either use this parameter or use environment variable. |
|
48
|
+
| `contentProvider` | Optional | `file` | Default content provider used to get content for review. Options available are `github`, `file` and `text` (`text` provides text as it is). |
|
49
|
+
| `requirementsProvider` | Optional | `file` | Default requirements provider used to get requirements for review. Options available are `jira`, `jira-legacy`, `github`, `file` and `text`. |
|
50
|
+
| `projectGuidelines` | Optional | `.gsloth.guidelines.md` | Path to the file containing project guidelines. |
|
51
|
+
| `projectReviewInstructions` | Optional | `.gsloth.review.md` | Path to the file containing project review instructions. |
|
52
|
+
| `commands` | Optional | - | Configuration for specific commands. |
|
53
|
+
| `commands.pr` | Optional | - | Configuration for the PR command. |
|
54
|
+
| `commands.pr.contentProvider` | Optional | `github` | Content provider used for PR review (`gsloth pr`). |
|
55
|
+
| `commands.pr.requirementsProvider` | Optional | `github` | Requirements provider used for PR review. If not specified, falls back to the global `requirementsProvider`. |
|
56
|
+
| `commands.review` | Optional | - | Configuration for the review command. |
|
57
|
+
| `commands.review.contentProvider` | Optional | - | Content provider specifically for the review command. If not specified, falls back to the global `contentProvider`. |
|
58
|
+
| `commands.review.requirementsProvider` | Optional | - | Requirements provider specifically for the review command. If not specified, falls back to the global `requirementsProvider`. |
|
59
|
+
| `requirementsProviderConfig` | Optional | - | Configuration for requirements providers. Contains provider-specific configurations. |
|
60
|
+
| `requirementsProviderConfig.jira` | Optional | - | Configuration for the Jira requirements provider (Atlassian REST API v3 with Personal Access Token). |
|
61
|
+
| `requirementsProviderConfig.jira.username` | Optional | - | Jira username (email). Can also be set via JIRA_USERNAME environment variable. |
|
62
|
+
| `requirementsProviderConfig.jira.token` | Optional | - | Jira Personal Access Token. Can also be set via JIRA_API_PAT_TOKEN environment variable. |
|
63
|
+
| `requirementsProviderConfig.jira.cloudId` | Required for `jira` | - | Atlassian Cloud ID. Can also be set via JIRA_CLOUD_ID environment variable. |
|
64
|
+
| `requirementsProviderConfig.jira.displayUrl` | Optional | - | Optional URL for displaying Jira issues (e.g., "https://yourcompany.atlassian.net/browse/"). |
|
65
|
+
| `requirementsProviderConfig.jira-legacy` | Optional | - | Configuration for the Jira Legacy requirements provider (Atlassian REST API v2 with Legacy API Token). |
|
66
|
+
| `requirementsProviderConfig.jira-legacy.username` | Optional | - | Jira username (email). Can also be set via JIRA_USERNAME environment variable. |
|
67
|
+
| `requirementsProviderConfig.jira-legacy.token` | Optional | - | Jira Legacy API Token. Can also be set via JIRA_LEGACY_API_TOKEN environment variable. |
|
68
|
+
| `requirementsProviderConfig.jira-legacy.baseUrl` | Required for `jira-legacy` | - | Base URL for the Jira API (e.g., "https://yourcompany.atlassian.net/rest/api/2/issue/"). |
|
69
|
+
| `requirementsProviderConfig.jira-legacy.displayUrl` | Optional | - | Optional URL for displaying Jira issues (e.g., "https://yourcompany.atlassian.net/browse/"). |
|
70
|
+
| `contentProviderConfig` | Optional | - | Configuration for content providers. Currently, the available content providers (`github`, `file`, and `text`) don't require specific configuration. |
|
71
|
+
|
38
72
|
## Config initialization
|
39
73
|
Configuration can be created with `gsloth init [vendor]` command.
|
40
74
|
Currently, vertexai, anthropic and groq can be configured with `gsloth init [vendor]`.
|
@@ -141,9 +175,7 @@ export async function configure(importFunction, global) {
|
|
141
175
|
}
|
142
176
|
```
|
143
177
|
|
144
|
-
**Example of .gsloth.config.js for Groq**
|
145
|
-
VertexAI usually needs `gcloud auth application-default login`
|
146
|
-
(or both `gcloud auth login` and `gcloud auth application-default login`) and does not need any separate API keys.
|
178
|
+
**Example of .gsloth.config.js for Groq**
|
147
179
|
```javascript
|
148
180
|
export async function configure(importFunction, global) {
|
149
181
|
// this is going to be imported from sloth dependencies,
|
@@ -165,6 +197,46 @@ See [Langchain documentation](https://js.langchain.com/docs/tutorials/llm_chain/
|
|
165
197
|
|
166
198
|
## Content providers
|
167
199
|
|
200
|
+
### GitHub Issues
|
201
|
+
|
202
|
+
Gaunt Sloth supports GitHub issues as a requirements provider using the GitHub CLI. This integration is simple to use and requires minimal setup.
|
203
|
+
|
204
|
+
**Prerequisites:**
|
205
|
+
|
206
|
+
1. **GitHub CLI**: Make sure the official [GitHub CLI (gh)](https://cli.github.com/) is installed and authenticated
|
207
|
+
2. **Repository Access**: Ensure you have access to the repository's issues
|
208
|
+
|
209
|
+
**Usage:**
|
210
|
+
|
211
|
+
The command syntax is `gsloth pr <prId> [githubIssueId]`. For example:
|
212
|
+
|
213
|
+
```shell
|
214
|
+
gsloth pr 42 23
|
215
|
+
```
|
216
|
+
|
217
|
+
This will review PR #42 and include GitHub issue #23 as requirements.
|
218
|
+
|
219
|
+
To explicitly specify the GitHub issue provider:
|
220
|
+
|
221
|
+
```shell
|
222
|
+
gsloth pr 42 23 -p github
|
223
|
+
```
|
224
|
+
|
225
|
+
**Configuration:**
|
226
|
+
|
227
|
+
To set GitHub as your default requirements provider, add this to your configuration file:
|
228
|
+
|
229
|
+
```json
|
230
|
+
{
|
231
|
+
"llm": {"type": "vertexai", "model": "gemini-2.5-pro-preview-05-06"},
|
232
|
+
"commands": {
|
233
|
+
"pr": {
|
234
|
+
"requirementsProvider": "github"
|
235
|
+
}
|
236
|
+
}
|
237
|
+
}
|
238
|
+
```
|
239
|
+
|
168
240
|
### JIRA
|
169
241
|
|
170
242
|
Gaunt Sloth supports two methods to integrate with JIRA:
|
package/docs/DEVELOPMENT.md
CHANGED
@@ -11,8 +11,7 @@ npm install -g ./
|
|
11
11
|
```
|
12
12
|
## Testing
|
13
13
|
|
14
|
-
Unit tests are implemented with [
|
15
|
-
and [testdouble.js](https://github.com/testdouble/testdouble.js).
|
14
|
+
Unit tests are implemented with [Vitest](https://vitest.dev/).
|
16
15
|
|
17
16
|
Running unit tests:
|
18
17
|
|
package/docs/RELEASE-HOWTO.md
CHANGED
package/eslint.config.js
CHANGED
@@ -76,7 +76,7 @@ export default defineConfig([
|
|
76
76
|
},
|
77
77
|
// Test TypeScript files with separate project reference
|
78
78
|
{
|
79
|
-
files: ['spec/**/*.ts', 'vitest.config.ts'],
|
79
|
+
files: ['spec/**/*.ts', 'integration-tests/**/*.ts', 'vitest.config.ts', 'vitest-it.config.ts'],
|
80
80
|
languageOptions: {
|
81
81
|
parser: tsParser,
|
82
82
|
parserOptions: {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "gaunt-sloth-assistant",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.4.1",
|
4
4
|
"description": "",
|
5
5
|
"license": "MIT",
|
6
6
|
"author": "Andrew Kondratev",
|
@@ -13,7 +13,8 @@
|
|
13
13
|
},
|
14
14
|
"scripts": {
|
15
15
|
"build": "tsc",
|
16
|
-
"test": "npm run build &&vitest run",
|
16
|
+
"test": "npm run build && vitest run",
|
17
|
+
"it": "npm run build && vitest run --config vitest-it.config.ts",
|
17
18
|
"lint": "eslint . --ext .js,.ts",
|
18
19
|
"format": "prettier --write 'src/**/*.{js,ts}'",
|
19
20
|
"prepare": "npm run build"
|
@@ -23,13 +24,13 @@
|
|
23
24
|
"gth": "index.js"
|
24
25
|
},
|
25
26
|
"dependencies": {
|
26
|
-
"@langchain/anthropic": "^0.3.
|
27
|
+
"@langchain/anthropic": "^0.3.21",
|
27
28
|
"@langchain/core": "^0.3.55",
|
28
29
|
"@langchain/google-vertexai": "^0.2.8",
|
29
30
|
"@langchain/groq": "^0.2.2",
|
30
31
|
"@langchain/langgraph": "^0.2.71",
|
31
32
|
"chalk": "^5.4.1",
|
32
|
-
"commander": "^
|
33
|
+
"commander": "^14.0.0",
|
33
34
|
"uuid": "^11.1.0"
|
34
35
|
},
|
35
36
|
"devDependencies": {
|
@@ -39,7 +40,7 @@
|
|
39
40
|
"@typescript-eslint/eslint-plugin": "^8.32.0",
|
40
41
|
"@typescript-eslint/parser": "^8.32.0",
|
41
42
|
"eslint": "^9.26.0",
|
42
|
-
"eslint-config-prettier": "^
|
43
|
+
"eslint-config-prettier": "^10.1.5",
|
43
44
|
"eslint-plugin-prettier": "^5.1.3",
|
44
45
|
"globals": "^16.1.0",
|
45
46
|
"prettier": "3.5.3",
|
package/report.txt
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
Summary of package.json:
|
2
|
+
|
3
|
+
* **Name**: `gaunt-sloth-assistant`
|
4
|
+
* **Version**: `0.4.0`
|
5
|
+
* **Description**: Not specified.
|
6
|
+
* **Author**: Andrew Kondratev
|
7
|
+
* **License**: MIT
|
8
|
+
* **Main entry point**: `dist/index.js`
|
9
|
+
* **Type**: `module`
|
10
|
+
* **Binaries/Commands**: `gsloth` and `gth` (both point to `index.js`)
|
11
|
+
* **Repository**: `github:andruhon/gaunt-sloth-assistant`
|
12
|
+
* **Node Engine Requirement**: `>=22.0.0`
|
13
|
+
* **NPM Engine Requirement**: `>=10.9.0`
|
14
|
+
* **Imports alias**: `#src/*.js` maps to `./dist/*.js`
|
15
|
+
|
16
|
+
**Key Dependencies**:
|
17
|
+
* `@langchain/anthropic`
|
18
|
+
* `@langchain/core`
|
19
|
+
* `@langchain/google-vertexai`
|
20
|
+
* `@langchain/groq`
|
21
|
+
* `@langchain/langgraph`
|
22
|
+
* `@langchain/mcp-adapters`
|
23
|
+
* `@modelcontextprotocol/server-filesystem`
|
24
|
+
* `chalk`
|
25
|
+
* `commander`
|
26
|
+
* `uuid`
|
27
|
+
|
28
|
+
**Key Dev Dependencies**:
|
29
|
+
* `eslint` and related plugins (for linting)
|
30
|
+
* `prettier` (for code formatting)
|
31
|
+
* `typescript`
|
32
|
+
* `vitest` (for testing)
|
33
|
+
* `@types/node`, `@types/uuid`
|
34
|
+
|
35
|
+
**Scripts**:
|
36
|
+
* `build`: `tsc` (compiles TypeScript)
|
37
|
+
* `format`: `prettier --write 'src/**/*.{js,ts}'` (formats code)
|
38
|
+
* `it`: `npm run build && vitest run --config vitest-it.config.ts` (runs integration tests)
|
39
|
+
* `lint`: `eslint . --ext .js,.ts` (lints code)
|
40
|
+
* `prepare`: `npm run build` (runs build on prepare, e.g., before publishing)
|
41
|
+
* `test`: `npm run build && vitest run` (runs tests)
|
42
|
+
|
43
|
+
This `package.json` defines a Node.js module written in TypeScript, utilizing LangChain and various other libraries for its functionality. It includes scripts for building, testing, linting, and formatting the code. It also specifies engine requirements and defines custom import paths.
|
@@ -2,6 +2,7 @@ import { Command } from 'commander';
|
|
2
2
|
import { readBackstory, readGuidelines } from '#src/prompt.js';
|
3
3
|
import { readMultipleFilesFromCurrentDir } from '#src/utils.js';
|
4
4
|
import { initConfig, slothContext } from '#src/config.js';
|
5
|
+
import { getStringFromStdin } from '#src/systemUtils.js';
|
5
6
|
|
6
7
|
interface AskCommandOptions {
|
7
8
|
file?: string[];
|
@@ -15,19 +16,31 @@ export function askCommand(program: Command): void {
|
|
15
16
|
program
|
16
17
|
.command('ask')
|
17
18
|
.description('Ask a question')
|
18
|
-
.argument('
|
19
|
+
.argument('[message]', 'A message')
|
19
20
|
.option(
|
20
21
|
'-f, --file [files...]',
|
21
22
|
'Input files. Content of these files will be added BEFORE the message'
|
22
23
|
)
|
23
|
-
// TODO add option consuming extra message as argument
|
24
24
|
.action(async (message: string, options: AskCommandOptions) => {
|
25
25
|
await initConfig();
|
26
26
|
const preamble = [readBackstory(), readGuidelines(slothContext.config.projectGuidelines)];
|
27
|
-
const content = [
|
27
|
+
const content = [];
|
28
28
|
if (options.file) {
|
29
29
|
content.push(readMultipleFilesFromCurrentDir(options.file));
|
30
30
|
}
|
31
|
+
let stringFromStdin = getStringFromStdin();
|
32
|
+
if (stringFromStdin) {
|
33
|
+
content.push(stringFromStdin);
|
34
|
+
}
|
35
|
+
if (message) {
|
36
|
+
content.push(message);
|
37
|
+
}
|
38
|
+
|
39
|
+
// Validate that at least one input source is provided
|
40
|
+
if (content.length === 0) {
|
41
|
+
throw new Error('At least one of the following is required: file, stdin, or message');
|
42
|
+
}
|
43
|
+
|
31
44
|
const { askQuestion } = await import('#src/modules/questionAnsweringModule.js');
|
32
45
|
await askQuestion('ASK', preamble.join('\n'), content.join('\n'));
|
33
46
|
});
|
@@ -7,11 +7,13 @@ import { displayError } from '#src/consoleUtils.js';
|
|
7
7
|
import { getStringFromStdin } from '#src/systemUtils.js';
|
8
8
|
|
9
9
|
/**
|
10
|
-
* Requirements providers. Expected to be in `.providers/` dir
|
10
|
+
* Requirements providers. Expected to be in `.providers/` dir.
|
11
|
+
* Aliases are mapped to actual providers in this file
|
11
12
|
*/
|
12
13
|
const REQUIREMENTS_PROVIDERS = {
|
13
14
|
'jira-legacy': 'jiraIssueLegacyProvider.js',
|
14
15
|
jira: 'jiraIssueProvider.js',
|
16
|
+
github: 'ghIssueProvider.js',
|
15
17
|
text: 'text.js',
|
16
18
|
file: 'file.js',
|
17
19
|
} as const;
|
@@ -19,10 +21,11 @@ const REQUIREMENTS_PROVIDERS = {
|
|
19
21
|
type RequirementsProviderType = keyof typeof REQUIREMENTS_PROVIDERS;
|
20
22
|
|
21
23
|
/**
|
22
|
-
* Content providers. Expected to be in `.providers/` dir
|
24
|
+
* Content providers. Expected to be in `.providers/` dir.
|
25
|
+
* Aliases are mapped to actual providers in this file
|
23
26
|
*/
|
24
27
|
const CONTENT_PROVIDERS = {
|
25
|
-
|
28
|
+
github: 'ghPrDiffProvider.js',
|
26
29
|
text: 'text.js',
|
27
30
|
file: 'file.js',
|
28
31
|
} as const;
|
@@ -82,11 +85,13 @@ export function reviewCommand(program: Command, context: SlothContext): void {
|
|
82
85
|
const requirementsId = options.requirements;
|
83
86
|
const requirementsProvider =
|
84
87
|
options.requirementsProvider ??
|
85
|
-
(context.config?.review?.requirementsProvider as
|
88
|
+
(context.config?.commands?.review?.requirementsProvider as
|
89
|
+
| RequirementsProviderType
|
90
|
+
| undefined) ??
|
86
91
|
(context.config?.requirementsProvider as RequirementsProviderType | undefined);
|
87
92
|
const contentProvider =
|
88
93
|
options.contentProvider ??
|
89
|
-
(context.config?.review?.contentProvider as ContentProviderType | undefined) ??
|
94
|
+
(context.config?.commands?.review?.contentProvider as ContentProviderType | undefined) ??
|
90
95
|
(context.config?.contentProvider as ContentProviderType | undefined);
|
91
96
|
|
92
97
|
// TODO consider calling these in parallel
|
@@ -118,8 +123,8 @@ export function reviewCommand(program: Command, context: SlothContext): void {
|
|
118
123
|
.command('pr')
|
119
124
|
.description(
|
120
125
|
'Review provided Pull Request in current directory. ' +
|
121
|
-
'This command is similar to `review`, but default content provider is `
|
122
|
-
'(assuming that
|
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'
|
123
128
|
)
|
124
129
|
.argument('<prId>', 'Pull request ID to review.')
|
125
130
|
.argument(
|
@@ -148,7 +153,9 @@ export function reviewCommand(program: Command, context: SlothContext): void {
|
|
148
153
|
const content: string[] = [];
|
149
154
|
const requirementsProvider =
|
150
155
|
options.requirementsProvider ??
|
151
|
-
(context.config?.pr?.requirementsProvider as
|
156
|
+
(context.config?.commands?.pr?.requirementsProvider as
|
157
|
+
| RequirementsProviderType
|
158
|
+
| undefined) ??
|
152
159
|
(context.config?.requirementsProvider as RequirementsProviderType | undefined);
|
153
160
|
|
154
161
|
// Handle requirements
|
@@ -161,8 +168,8 @@ export function reviewCommand(program: Command, context: SlothContext): void {
|
|
161
168
|
content.push(readMultipleFilesFromCurrentDir(options.file));
|
162
169
|
}
|
163
170
|
|
164
|
-
// Get PR diff using the '
|
165
|
-
const providerPath = `#src/providers/${CONTENT_PROVIDERS['
|
171
|
+
// Get PR diff using the 'github' provider
|
172
|
+
const providerPath = `#src/providers/${CONTENT_PROVIDERS['github']}`;
|
166
173
|
const { get } = await import(providerPath);
|
167
174
|
content.push(await get(null, prId));
|
168
175
|
|
package/src/config.ts
CHANGED
@@ -15,6 +15,11 @@ export interface SlothConfig extends BaseSlothConfig {
|
|
15
15
|
commands: {
|
16
16
|
pr: {
|
17
17
|
contentProvider: string;
|
18
|
+
requirementsProvider?: string;
|
19
|
+
};
|
20
|
+
review?: {
|
21
|
+
requirementsProvider?: string;
|
22
|
+
contentProvider?: string;
|
18
23
|
};
|
19
24
|
};
|
20
25
|
}
|
@@ -38,14 +43,12 @@ interface BaseSlothConfig {
|
|
38
43
|
commands?: {
|
39
44
|
pr: {
|
40
45
|
contentProvider: string;
|
46
|
+
requirementsProvider?: string;
|
47
|
+
};
|
48
|
+
review?: {
|
49
|
+
requirementsProvider?: string;
|
50
|
+
contentProvider?: string;
|
41
51
|
};
|
42
|
-
};
|
43
|
-
review?: {
|
44
|
-
requirementsProvider?: string;
|
45
|
-
contentProvider?: string;
|
46
|
-
};
|
47
|
-
pr?: {
|
48
|
-
requirementsProvider?: string;
|
49
52
|
};
|
50
53
|
requirementsProviderConfig?: Record<string, unknown>;
|
51
54
|
contentProviderConfig?: Record<string, unknown>;
|
@@ -87,7 +90,8 @@ export const DEFAULT_CONFIG: Partial<SlothConfig> = {
|
|
87
90
|
projectReviewInstructions: PROJECT_REVIEW_INSTRUCTIONS,
|
88
91
|
commands: {
|
89
92
|
pr: {
|
90
|
-
contentProvider: '
|
93
|
+
contentProvider: 'github', // gh pr diff NN
|
94
|
+
requirementsProvider: 'github', // gh issue view NN
|
91
95
|
},
|
92
96
|
},
|
93
97
|
};
|
@@ -99,7 +103,6 @@ export const DEFAULT_CONFIG: Partial<SlothConfig> = {
|
|
99
103
|
*/
|
100
104
|
export const slothContext = {
|
101
105
|
config: DEFAULT_CONFIG,
|
102
|
-
stdin: '',
|
103
106
|
session: { configurable: { thread_id: uuidv4() } },
|
104
107
|
} as Partial<SlothContext> as SlothContext;
|
105
108
|
|
package/src/configs/anthropic.ts
CHANGED
@@ -18,7 +18,7 @@ export async function processJsonConfig(
|
|
18
18
|
return new anthropic.ChatAnthropic({
|
19
19
|
...llmConfig,
|
20
20
|
apiKey: anthropicApiKey,
|
21
|
-
model: llmConfig.model || 'claude-
|
21
|
+
model: llmConfig.model || 'claude-sonnet-4-20250514',
|
22
22
|
});
|
23
23
|
}
|
24
24
|
|
@@ -31,7 +31,7 @@ export async function configure(importFunction, global) {
|
|
31
31
|
return {
|
32
32
|
llm: new anthropic.ChatAnthropic({
|
33
33
|
apiKey: process.env.ANTHROPIC_API_KEY, // Default value, but you can provide the key in many different ways, even as literal
|
34
|
-
model: "claude-
|
34
|
+
model: "claude-sonnet-4-20250514" // Don't forget to check new models availability.
|
35
35
|
})
|
36
36
|
};
|
37
37
|
}
|
@@ -40,8 +40,7 @@ export async function configure(importFunction, global) {
|
|
40
40
|
const jsonContent = `{
|
41
41
|
"llm": {
|
42
42
|
"type": "anthropic",
|
43
|
-
"
|
44
|
-
"model": "claude-3-7-sonnet-20250219"
|
43
|
+
"model": "claude-sonnet-4-20250514"
|
45
44
|
}
|
46
45
|
}`;
|
47
46
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import { displayWarning } from '#src/consoleUtils.js';
|
2
|
+
import { execAsync } from '#src/utils.js';
|
3
|
+
import type { ProviderConfig } from './types.js';
|
4
|
+
|
5
|
+
/**
|
6
|
+
* Gets GitHub issue using GitHub CLI
|
7
|
+
* @param _ config (unused in this provider)
|
8
|
+
* @param issueId GitHub issue number
|
9
|
+
* @returns GitHub issue content or null if not found
|
10
|
+
*/
|
11
|
+
export async function get(
|
12
|
+
_: ProviderConfig | null,
|
13
|
+
issueId: string | undefined
|
14
|
+
): Promise<string | null> {
|
15
|
+
if (!issueId) {
|
16
|
+
displayWarning('No GitHub issue number provided');
|
17
|
+
return null;
|
18
|
+
}
|
19
|
+
|
20
|
+
try {
|
21
|
+
// Use the GitHub CLI to fetch issue details
|
22
|
+
const issueContent = await execAsync(`gh issue view ${issueId}`);
|
23
|
+
|
24
|
+
if (!issueContent) {
|
25
|
+
displayWarning(`No content found for GitHub issue #${issueId}`);
|
26
|
+
return null;
|
27
|
+
}
|
28
|
+
|
29
|
+
return `GitHub Issue: #${issueId}\n\n${issueContent}`;
|
30
|
+
} catch (error) {
|
31
|
+
displayWarning(`
|
32
|
+
Failed to get GitHub issue #${issueId}: ${error instanceof Error ? error.message : String(error)}
|
33
|
+
Consider checking if gh cli (https://cli.github.com/) is installed and authenticated.
|
34
|
+
`);
|
35
|
+
return null;
|
36
|
+
}
|
37
|
+
}
|
@@ -3,18 +3,35 @@ import { execAsync } from '#src/utils.js';
|
|
3
3
|
import type { ProviderConfig } from './types.js';
|
4
4
|
|
5
5
|
/**
|
6
|
-
* Gets PR diff using
|
6
|
+
* Gets PR diff using GitHub CLI
|
7
7
|
* @param _ config (unused in this provider)
|
8
|
-
* @param
|
9
|
-
* @returns PR diff
|
8
|
+
* @param prId GitHub PR number
|
9
|
+
* @returns GitHub PR diff content or null if not found
|
10
10
|
*/
|
11
11
|
export async function get(
|
12
12
|
_: ProviderConfig | null,
|
13
|
-
|
13
|
+
prId: string | undefined
|
14
14
|
): Promise<string | null> {
|
15
|
-
if (!
|
16
|
-
displayWarning('No PR provided');
|
15
|
+
if (!prId) {
|
16
|
+
displayWarning('No GitHub PR number provided');
|
17
|
+
return null;
|
18
|
+
}
|
19
|
+
|
20
|
+
try {
|
21
|
+
// Use the GitHub CLI to fetch PR diff
|
22
|
+
const prDiffContent = await execAsync(`gh pr diff ${prId}`);
|
23
|
+
|
24
|
+
if (!prDiffContent) {
|
25
|
+
displayWarning(`No diff content found for GitHub PR #${prId}`);
|
26
|
+
return null;
|
27
|
+
}
|
28
|
+
|
29
|
+
return `GitHub PR Diff: #${prId}\n\n${prDiffContent}`;
|
30
|
+
} catch (error) {
|
31
|
+
displayWarning(`
|
32
|
+
Failed to get GitHub PR diff #${prId}: ${error instanceof Error ? error.message : String(error)}
|
33
|
+
Consider checking if gh cli (https://cli.github.com/) is installed and authenticated.
|
34
|
+
`);
|
17
35
|
return null;
|
18
36
|
}
|
19
|
-
return execAsync(`gh pr diff ${pr}`);
|
20
37
|
}
|
@@ -8,6 +8,7 @@ interface JiraIssueResponse {
|
|
8
8
|
description: string;
|
9
9
|
[key: string]: unknown;
|
10
10
|
};
|
11
|
+
|
11
12
|
[key: string]: unknown;
|
12
13
|
}
|
13
14
|
|
@@ -74,6 +75,8 @@ export async function get(
|
|
74
75
|
const summary = issue.fields.summary;
|
75
76
|
const description = issue.fields.description;
|
76
77
|
|
78
|
+
console.log(JSON.stringify(issue, null, 2));
|
79
|
+
|
77
80
|
return `Jira Issue: ${issueId}\nSummary: ${summary}\n\nDescription:\n${description}`;
|
78
81
|
} catch (error) {
|
79
82
|
displayError(
|
@@ -84,7 +87,11 @@ export async function get(
|
|
84
87
|
}
|
85
88
|
|
86
89
|
/**
|
87
|
-
* Helper function to get Jira issue details using Atlassian REST API
|
90
|
+
* Helper function to get Jira issue details using Atlassian REST API v2.
|
91
|
+
*
|
92
|
+
* The feature was initially developed to use Atlassian REST API v3, which by
|
93
|
+
* default returns the ADF JSON format for description, which is not very useful for us.
|
94
|
+
*
|
88
95
|
* @param config Jira configuration
|
89
96
|
* @param jiraKey Jira issue ID
|
90
97
|
* @returns Jira issue response
|
@@ -93,14 +100,18 @@ async function getJiraIssue(config: JiraConfig, jiraKey: string): Promise<JiraIs
|
|
93
100
|
// Jira Cloud ID can be found by authenticated user at https://company.atlassian.net/_edge/tenant_info
|
94
101
|
|
95
102
|
// According to doc https://developer.atlassian.com/cloud/jira/platform/rest/v3/api-group-issues/#api-rest-api-3-issue-issueidorkey-get permissions to read this resource:
|
103
|
+
// https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issues/#api-rest-api-2-issue-issueidorkey-get
|
96
104
|
// either Classic (RECOMMENDED) read:jira-work
|
97
105
|
// or Granular read:issue-meta:jira, read:issue-security-level:jira, read:issue.vote:jira, read:issue.changelog:jira, read:avatar:jira, read:issue:jira, read:status:jira, read:user:jira, read:field-configuration:jira
|
98
|
-
const apiUrl = `https://api.atlassian.com/ex/jira/${config.cloudId}/rest/api/
|
106
|
+
const apiUrl = `https://api.atlassian.com/ex/jira/${config.cloudId}/rest/api/2/issue/${jiraKey}`;
|
99
107
|
if (config.displayUrl) {
|
100
108
|
display(`Loading Jira issue ${config.displayUrl}${jiraKey}`);
|
101
109
|
}
|
102
110
|
display(`Retrieving jira from api ${apiUrl.replace(/^https?:\/\//, '')}`);
|
103
111
|
|
112
|
+
// This filter will be necessary for V3: `&expand=renderedFields` to convert ADF to HTML
|
113
|
+
const filters = '?fields=summary,description'; // Limit JSON to summary and description
|
114
|
+
|
104
115
|
// Encode credentials for Basic Authentication header
|
105
116
|
const credentials = `${config.username}:${config.token}`;
|
106
117
|
const encodedCredentials = Buffer.from(credentials).toString('base64');
|
@@ -113,7 +124,7 @@ async function getJiraIssue(config: JiraConfig, jiraKey: string): Promise<JiraIs
|
|
113
124
|
'Accept-Language': 'en-US,en;q=0.9', // Prevents errors in other languages
|
114
125
|
};
|
115
126
|
|
116
|
-
const response = await fetch(apiUrl, {
|
127
|
+
const response = await fetch(apiUrl + filters, {
|
117
128
|
method: 'GET',
|
118
129
|
headers: headers,
|
119
130
|
});
|
package/tsconfig.json
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
import { defineConfig } from 'vitest/config';
|
2
|
+
|
3
|
+
export default defineConfig({
|
4
|
+
test: {
|
5
|
+
include: ['integration-tests/**/*.it.ts'],
|
6
|
+
environment: 'node',
|
7
|
+
coverage: {
|
8
|
+
provider: 'v8',
|
9
|
+
reporter: ['text', 'json', 'html'],
|
10
|
+
},
|
11
|
+
globals: true,
|
12
|
+
testTimeout: 100000,
|
13
|
+
},
|
14
|
+
});
|
package/dist/configs/types.d.ts
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
import type { SlothContext } from '#src/config.js';
|
2
|
-
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
3
|
-
export interface LLMConfig {
|
4
|
-
type: string;
|
5
|
-
model?: string;
|
6
|
-
apiKey?: string;
|
7
|
-
temperature?: number;
|
8
|
-
responses?: string[];
|
9
|
-
[key: string]: unknown;
|
10
|
-
}
|
11
|
-
export interface ConfigModule {
|
12
|
-
init: (configFileName: string, context: SlothContext) => void;
|
13
|
-
processJsonConfig: (llmConfig: LLMConfig) => Promise<BaseChatModel | null>;
|
14
|
-
}
|
package/dist/configs/types.js
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/configs/types.ts"],"names":[],"mappings":""}
|
@@ -1,8 +0,0 @@
|
|
1
|
-
import type { JiraConfig } from "./types.js";
|
2
|
-
/**
|
3
|
-
* Gets Jira issue using Atlassian REST API v2
|
4
|
-
* @param config Jira configuration
|
5
|
-
* @param issueId Jira issue ID
|
6
|
-
* @returns Jira issue content
|
7
|
-
*/
|
8
|
-
export declare function get(config: JiraConfig | null, issueId: string | undefined): Promise<string | null>;
|