gaunt-sloth-assistant 0.1.2 → 0.1.4
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/.github/workflows/ci.yml +33 -0
- package/README.md +59 -33
- package/ROADMAP.md +20 -20
- package/UX-RESEARCH.md +1 -1
- package/docs/CONFIGURATION.md +96 -6
- package/docs/DEVELOPMENT.md +12 -0
- package/eslint.config.js +38 -0
- package/index.js +4 -2
- package/package.json +7 -3
- package/spec/.gsloth.config.js +1 -1
- package/spec/.gsloth.config.json +25 -0
- package/spec/askCommand.spec.js +39 -5
- package/spec/config.spec.js +421 -0
- package/spec/initCommand.spec.js +3 -2
- package/spec/predefinedConfigs.spec.js +100 -0
- package/spec/questionAnsweringModule.spec.js +14 -14
- package/spec/reviewCommand.spec.js +86 -8
- package/spec/reviewModule.spec.js +7 -1
- package/src/commands/askCommand.js +5 -4
- package/src/commands/initCommand.js +2 -1
- package/src/commands/reviewCommand.js +19 -12
- package/src/config.js +139 -25
- package/src/configs/anthropic.js +28 -5
- package/src/configs/fake.js +15 -0
- package/src/configs/groq.js +27 -4
- package/src/configs/vertexai.js +23 -2
- package/src/consoleUtils.js +15 -5
- package/src/modules/questionAnsweringModule.js +9 -14
- package/src/modules/reviewModule.js +11 -16
- package/src/prompt.js +4 -3
- package/src/providers/file.js +19 -0
- package/src/providers/ghPrDiffProvider.js +2 -2
- package/src/providers/jiraIssueLegacyAccessTokenProvider.js +33 -30
- package/src/providers/text.js +1 -1
- package/src/systemUtils.js +32 -0
- package/src/utils.js +49 -13
@@ -0,0 +1,33 @@
|
|
1
|
+
name: Tests and Lint
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ "main" ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ "main" ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test-and-lint:
|
11
|
+
runs-on: ubuntu-latest
|
12
|
+
|
13
|
+
strategy:
|
14
|
+
matrix:
|
15
|
+
node-version: [22.x]
|
16
|
+
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v4
|
19
|
+
|
20
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
21
|
+
uses: actions/setup-node@v4
|
22
|
+
with:
|
23
|
+
node-version: ${{ matrix.node-version }}
|
24
|
+
cache: 'npm'
|
25
|
+
|
26
|
+
- name: Install dependencies
|
27
|
+
run: npm ci
|
28
|
+
|
29
|
+
- name: Run ESLint
|
30
|
+
run: npm run lint
|
31
|
+
|
32
|
+
- name: Run Tests
|
33
|
+
run: npm test
|
package/README.md
CHANGED
@@ -1,7 +1,33 @@
|
|
1
1
|
# Gaunt Sloth Assistant
|
2
|
-
|
3
|
-
|
4
|
-
|
2
|
+
[](https://github.com/andruhon/gaunt-sloth-assistant/actions/workflows/ci.yml)
|
3
|
+
|
4
|
+
Gaunt Sloth Assistant is a Simplistic **command line AI assistant**
|
5
|
+
for software developers,
|
6
|
+
who wish to reduce cognitive load and time spending on **code reviews** (and pull request diff reviews).
|
7
|
+
|
8
|
+
Based on [Langchain.js](https://github.com/langchain-ai/langchainjs)
|
9
|
+
|
10
|
+
## What GSloth does:
|
11
|
+
- Reviews code;
|
12
|
+
- Suggests bug fixes;
|
13
|
+
- Explains provided code
|
14
|
+
- Reviews Diffs provided with pipe (|);
|
15
|
+
- You can ask GSloth to review your own code before committing.
|
16
|
+
- Reviews Pull Requests (PRs);
|
17
|
+
- Fetches descriptions (requirements) from Jira;
|
18
|
+
- Answers questions about provided code;
|
19
|
+
- Writes code;
|
20
|
+
- Saves all responses to the project directory;
|
21
|
+
- Anything else you need, when combined with other command line tools.
|
22
|
+
|
23
|
+
### To make GSloth work, you need an **API key** from some AI provider, such as:
|
24
|
+
- Google Vertex AI;
|
25
|
+
- Anthropic;
|
26
|
+
- Groq.
|
27
|
+
|
28
|
+
## Primary Functions:
|
29
|
+
|
30
|
+
### Review PR (Pull Request)
|
5
31
|
To review PR by PR number:
|
6
32
|
|
7
33
|
First make sure the official [GitHub cli (gh)](https://cli.github.com/) is installed
|
@@ -19,13 +45,8 @@ Review providing markdown file with requirements and notes.
|
|
19
45
|
```shell
|
20
46
|
gsloth pr 42 -f PROJ-1234.md
|
21
47
|
```
|
22
|
-
Jira integration is in [ROADMAP](ROADMAP.md).
|
23
|
-
Currently, the easiest ***meaningful*** way to add jira description is to
|
24
|
-
open Jira XML with "Export XML" in jira and to copy `<description></description>` block.
|
25
|
-
This block contains HTML and AI understands it easily
|
26
|
-
(most importantly it understand nested lists like ul>li).
|
27
48
|
|
28
|
-
|
49
|
+
### JIRA Integration
|
29
50
|
|
30
51
|
When JIRA integration is configured, the JIRA issue text can be included alongside the diff for review.
|
31
52
|
The project review preamble can be modified to reject a pull request immediately
|
@@ -39,31 +60,26 @@ supplies description of JIRA issue with number PP-4242:
|
|
39
60
|
gsloth pr 42 PP-4242
|
40
61
|
```
|
41
62
|
|
42
|
-
Example configuration setting up JIRA integration using a legacy API token.
|
63
|
+
Example configuration setting up JIRA integration using a legacy API token for both `review` and `pr` commands.
|
43
64
|
Make sure you use your actual company domain in `baseUrl` and your personal legacy `token`.
|
44
65
|
|
45
66
|
A legacy token can be acquired from `Atlassian Account Settings -> Security -> Create and manage API tokens`.
|
46
67
|
|
47
|
-
```
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
'jira-legacy': {
|
57
|
-
username: 'user.name@company.com', // Your Jira username/email
|
58
|
-
token: 'YOURSECRETTOKEN', // Replace with your real Jira API token
|
59
|
-
baseUrl: 'https://yourcompany.atlassian.net/rest/api/2/issue/' // Your Jira instance base URL
|
60
|
-
}
|
61
|
-
}
|
68
|
+
```json
|
69
|
+
{
|
70
|
+
"llm": {"type": "vertexai", "model": "gemini-2.5-pro-exp-03-25"},
|
71
|
+
"requirementsProvider": "jira-legacy",
|
72
|
+
"requirementsProviderConfig": {
|
73
|
+
"jira-legacy": {
|
74
|
+
"username": "user@yourcompany.com",
|
75
|
+
"token": "YOUR_JIRA_LEGACY_TOKEN",
|
76
|
+
"baseUrl": "https://yourcompany.atlassian.net/rest/api/2/issue/"
|
62
77
|
}
|
78
|
+
}
|
63
79
|
}
|
64
80
|
```
|
65
81
|
|
66
|
-
|
82
|
+
### Review any Diff
|
67
83
|
```shell
|
68
84
|
git --no-pager diff origin/master...yourgitcommithash | gsloth review
|
69
85
|
```
|
@@ -74,7 +90,7 @@ Review current local changes:
|
|
74
90
|
git --no-pager diff | gsloth review
|
75
91
|
```
|
76
92
|
|
77
|
-
|
93
|
+
### Question Answering
|
78
94
|
```shell
|
79
95
|
gsloth ask "which types of primitives are available in JavaScript?"
|
80
96
|
```
|
@@ -83,19 +99,25 @@ gsloth ask "which types of primitives are available in JavaScript?"
|
|
83
99
|
gsloth ask "Please have a look at this file" -f index.js
|
84
100
|
```
|
85
101
|
|
102
|
+
Multiple files may be provided as well
|
103
|
+
|
104
|
+
```shell
|
105
|
+
gsloth ask "Please have a look at these files" -f index.js test.js
|
106
|
+
```
|
107
|
+
|
86
108
|
## Installation
|
87
109
|
|
88
110
|
Tested with Node 22 LTS.
|
89
111
|
|
90
|
-
|
112
|
+
### NPM
|
91
113
|
```shell
|
92
114
|
npm install gaunt-sloth-assistant -g
|
93
115
|
```
|
94
116
|
|
95
117
|
## Configuration
|
96
118
|
|
97
|
-
> Gaunt Sloth currently only functions from the directory which has `.gsloth.config.js` and `.gsloth.preamble.review.md`.
|
98
|
-
> Global configuration to invoke gsloth anywhere is in [ROADMAP](
|
119
|
+
> Gaunt Sloth currently only functions from the directory which has a configuration file (`.gsloth.config.js`, `.gsloth.config.json`, or `.gsloth.config.mjs`) and `.gsloth.preamble.review.md`.
|
120
|
+
> Global configuration to invoke gsloth anywhere is in [ROADMAP](ROADMAP.md).
|
99
121
|
|
100
122
|
Configuration can be created with `gsloth init [vendor]` command.
|
101
123
|
Currently, vertexai, anthropic and groq can be configured with `gsloth init [vendor]`.
|
@@ -111,22 +133,26 @@ gcloud auth application-default login
|
|
111
133
|
```
|
112
134
|
|
113
135
|
### Anthropic
|
136
|
+
|
114
137
|
```shell
|
115
138
|
cd ./your-project
|
116
139
|
gsloth init anthropic
|
117
140
|
```
|
118
|
-
|
141
|
+
|
142
|
+
Make sure you either define `ANTHROPIC_API_KEY` environment variable or edit your configuration file and set up your key.
|
119
143
|
|
120
144
|
### Groq
|
121
145
|
```shell
|
122
146
|
cd ./your-project
|
123
147
|
gsloth init groq
|
124
148
|
```
|
125
|
-
Make sure you either define `GROQ_API_KEY` environment variable or edit
|
149
|
+
Make sure you either define `GROQ_API_KEY` environment variable or edit your configuration file and set up your key.
|
150
|
+
|
151
|
+
### Other AI providers
|
152
|
+
Any other AI provider supported by Langchain.js can be configured with js [Config](./docs/CONFIGURATION.md).
|
126
153
|
|
127
154
|
## Building from repo
|
128
155
|
See [DEVELOPMENT.md](./docs/DEVELOPMENT.md)
|
129
156
|
|
130
157
|
## License
|
131
158
|
License is [MIT](https://opensource.org/license/mit). See [LICENSE](LICENSE)
|
132
|
-
|
package/ROADMAP.md
CHANGED
@@ -1,28 +1,28 @@
|
|
1
1
|
# Gaunt Sloth Assistant roadmap
|
2
2
|
|
3
|
-
|
4
3
|
## 1.0.0
|
5
4
|
Doing the following below and making it work stably should be sufficient to call it version 1.
|
6
5
|
|
7
|
-
###
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
-[x]
|
16
|
-
-[
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
6
|
+
### Checklist
|
7
|
+
|
8
|
+
- [x] Add tests and gain reasonable coverage
|
9
|
+
- [x] Configure eslint for code quality checks
|
10
|
+
- [ ] Automate release process
|
11
|
+
- [x] Add project init command
|
12
|
+
Add a command to init certain model in certain project, for example `gsloth init gemini`
|
13
|
+
or `gsloth init` and select one of the provided options.
|
14
|
+
-[x] VertexAI
|
15
|
+
-[x] Anthropic
|
16
|
+
-[x] Groq
|
17
|
+
-[ ] Local LLm
|
18
|
+
- [ ] Allow global configuration
|
19
|
+
- [ ] Streamline and stabilize configuration
|
20
|
+
- [ ] Add JIRA legacy token integration plugin
|
21
|
+
- [ ] Teach assistant to identify important files and include their contents into prompt
|
22
|
+
The idea is to ask smaller model like flash to find important files from diff then pick them up and include into prompt.
|
23
|
+
- [ ] Teach assistant to access provided public web links
|
24
|
+
- [ ] Consider adding an option to always include certain source code files into prompt
|
25
|
+
- [ ] Add general chat command
|
26
26
|
|
27
27
|
## Extra stuff for later
|
28
28
|
|
package/UX-RESEARCH.md
CHANGED
@@ -34,7 +34,7 @@ Arguments:
|
|
34
34
|
prNumber PR number to review
|
35
35
|
|
36
36
|
Options:
|
37
|
-
-f, --file <file> Input file.
|
37
|
+
-f, --file <file> Input file. Content of this file will be added BEFORE the
|
38
38
|
diff
|
39
39
|
-h, --help display help for command
|
40
40
|
```
|
package/docs/CONFIGURATION.md
CHANGED
@@ -5,10 +5,13 @@ Proper preamble is a paramount for good inference.
|
|
5
5
|
Check [.gsloth.preamble.review.md](../.gsloth.preamble.review.md) for example.
|
6
6
|
|
7
7
|
Your project should have the following files in order for gsloth to function:
|
8
|
-
-
|
8
|
+
- Configuration file (one of):
|
9
|
+
- `.gsloth.config.js` (JavaScript module)
|
10
|
+
- `.gsloth.config.json` (JSON file)
|
11
|
+
- `.gsloth.config.mjs` (JavaScript module with explicit module extension)
|
9
12
|
- `.gsloth.preamble.review.md`
|
10
13
|
|
11
|
-
> Gaunt Sloth currently only functions from the directory which has
|
14
|
+
> Gaunt Sloth currently only functions from the directory which has one of the configuration files and `.gsloth.preamble.review.md`.
|
12
15
|
> Global configuration to invoke gsloth anywhere is in [ROADMAP](../ROADMAP.md).
|
13
16
|
|
14
17
|
## Config initialization
|
@@ -28,17 +31,56 @@ gcloud auth application-default login
|
|
28
31
|
cd ./your-project
|
29
32
|
gsloth init anthropic
|
30
33
|
```
|
31
|
-
Make sure you either define `ANTHROPIC_API_KEY` environment variable or edit
|
34
|
+
Make sure you either define `ANTHROPIC_API_KEY` environment variable or edit your configuration file and set up your key.
|
32
35
|
|
33
36
|
### Groq
|
34
37
|
```shell
|
35
38
|
cd ./your-project
|
36
39
|
gsloth init groq
|
37
40
|
```
|
38
|
-
Make sure you either define `GROQ_API_KEY` environment variable or edit
|
41
|
+
Make sure you either define `GROQ_API_KEY` environment variable or edit your configuration file and set up your key.
|
39
42
|
|
40
43
|
## Examples of configuration for different providers
|
41
44
|
|
45
|
+
### JSON Configuration (.gsloth.config.json)
|
46
|
+
|
47
|
+
JSON configuration is simpler but less flexible than JavaScript configuration. It should directly contain the configuration object.
|
48
|
+
|
49
|
+
**Example of .gsloth.config.json for Anthropic**
|
50
|
+
```json
|
51
|
+
{
|
52
|
+
"llm": {
|
53
|
+
"type": "anthropic",
|
54
|
+
"apiKey": "your-api-key-here",
|
55
|
+
"model": "claude-3-5-sonnet-20241022"
|
56
|
+
}
|
57
|
+
}
|
58
|
+
```
|
59
|
+
|
60
|
+
**Example of .gsloth.config.json for VertexAI**
|
61
|
+
```json
|
62
|
+
{
|
63
|
+
"llm": {
|
64
|
+
"type": "vertexai",
|
65
|
+
"model": "gemini-2.5-pro-exp-03-25",
|
66
|
+
"temperature": 0
|
67
|
+
}
|
68
|
+
}
|
69
|
+
```
|
70
|
+
|
71
|
+
**Example of .gsloth.config.json for Groq**
|
72
|
+
```json
|
73
|
+
{
|
74
|
+
"llm": {
|
75
|
+
"type": "groq",
|
76
|
+
"model": "deepseek-r1-distill-llama-70b",
|
77
|
+
"apiKey": "your-api-key-here"
|
78
|
+
}
|
79
|
+
}
|
80
|
+
```
|
81
|
+
|
82
|
+
### JavaScript Configuration (.gsloth.config.js or .gsloth.config.mjs)
|
83
|
+
|
42
84
|
**Example of .gsloth.config.js for Anthropic**
|
43
85
|
```javascript
|
44
86
|
export async function configure(importFunction, global) {
|
@@ -68,6 +110,7 @@ export async function configure(importFunction, global) {
|
|
68
110
|
return {
|
69
111
|
llm: new vertexAi.ChatVertexAI({
|
70
112
|
model: "gemini-2.5-pro-exp-03-25", // Consider checking for latest recommended model versions
|
113
|
+
// API Key from AI Studio should also work
|
71
114
|
temperature: 0,
|
72
115
|
//// Other parameters might be relevant depending on Vertex AI API updates.
|
73
116
|
//// The project is not in the interface, but it is in documentation and it seems to work.
|
@@ -94,7 +137,54 @@ export async function configure(importFunction, global) {
|
|
94
137
|
}
|
95
138
|
```
|
96
139
|
|
97
|
-
## Using other providers
|
140
|
+
## Using other AI providers
|
98
141
|
|
99
142
|
The configure function should simply return instance of langchain [chat model](https://v03.api.js.langchain.com/classes/_langchain_core.language_models_chat_models.BaseChatModel.html).
|
100
|
-
See [Langchain documentation](https://js.langchain.com/docs/tutorials/llm_chain/) for more details.
|
143
|
+
See [Langchain documentation](https://js.langchain.com/docs/tutorials/llm_chain/) for more details.
|
144
|
+
|
145
|
+
## Content providers
|
146
|
+
|
147
|
+
### JIRA
|
148
|
+
|
149
|
+
Example configuration setting up JIRA integration using a legacy API token for both `review` and `pr` commands.
|
150
|
+
Make sure you use your actual company domain in `baseUrl` and your personal legacy `token`.
|
151
|
+
|
152
|
+
A legacy token can be acquired from `Atlassian Account Settings -> Security -> Create and manage API tokens`.
|
153
|
+
|
154
|
+
JSON:
|
155
|
+
|
156
|
+
```json
|
157
|
+
{
|
158
|
+
"llm": {"type": "vertexai", "model": "gemini-2.5-pro-exp-03-25"},
|
159
|
+
"requirementsProvider": "jira-legacy",
|
160
|
+
"requirementsProviderConfig": {
|
161
|
+
"jira-legacy": {
|
162
|
+
"username": "username@yourcompany.com",
|
163
|
+
"token": "YOUR_JIRA_LEGACY_TOKEN",
|
164
|
+
"baseUrl": "https://yourcompany.atlassian.net/rest/api/2/issue/"
|
165
|
+
}
|
166
|
+
}
|
167
|
+
}
|
168
|
+
```
|
169
|
+
|
170
|
+
JavaScript:
|
171
|
+
|
172
|
+
```javascript
|
173
|
+
export async function configure(importFunction, global) {
|
174
|
+
const vertexAi = await importFunction('@langchain/google-vertexai');
|
175
|
+
return {
|
176
|
+
llm: new vertexAi.ChatVertexAI({
|
177
|
+
model: "gemini-2.5-pro-exp-03-25"
|
178
|
+
}),
|
179
|
+
requirementsProvider: 'jira-legacy',
|
180
|
+
requirementsProviderConfig: {
|
181
|
+
'jira-legacy': {
|
182
|
+
username: 'username@yourcompany.com', // Your Jira username/email
|
183
|
+
token: 'YOUR_JIRA_LEGACY_TOKEN', // Replace with your real Jira API token
|
184
|
+
baseUrl: 'https://yourcompany.atlassian.net/rest/api/2/issue/' // Your Jira instance base URL
|
185
|
+
}
|
186
|
+
}
|
187
|
+
}
|
188
|
+
}
|
189
|
+
```
|
190
|
+
|
package/docs/DEVELOPMENT.md
CHANGED
@@ -2,8 +2,20 @@
|
|
2
2
|
|
3
3
|
## GitHub (master)
|
4
4
|
|
5
|
+
Install dev version globally
|
6
|
+
|
5
7
|
```shell
|
6
8
|
git clone https://github.com/andruhon/gaunt-sloth.git
|
7
9
|
npm install
|
8
10
|
npm install -g ./
|
9
11
|
```
|
12
|
+
## Testing
|
13
|
+
|
14
|
+
Unit tests are implemented with [Jasmine](https://github.com/jasmine/jasmine)
|
15
|
+
and [testdouble.js](https://github.com/testdouble/testdouble.js).
|
16
|
+
|
17
|
+
Running unit tests:
|
18
|
+
|
19
|
+
```shell
|
20
|
+
npm run test
|
21
|
+
```
|
package/eslint.config.js
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
import js from "@eslint/js";
|
2
|
+
import { defineConfig } from "eslint/config";
|
3
|
+
import jasmine from "eslint-plugin-jasmine"
|
4
|
+
import globals from "globals";
|
5
|
+
|
6
|
+
const { setTimeout, setInterval, clearInterval, Buffer, fetch } = globals.node;
|
7
|
+
|
8
|
+
export default defineConfig([
|
9
|
+
{
|
10
|
+
files: ["src/**/*.js"],
|
11
|
+
plugins: {
|
12
|
+
js,
|
13
|
+
},
|
14
|
+
extends: ["js/recommended"],
|
15
|
+
rules: {
|
16
|
+
semi: "error",
|
17
|
+
"eol-last": "error"
|
18
|
+
},
|
19
|
+
languageOptions: {
|
20
|
+
globals: {
|
21
|
+
setTimeout,
|
22
|
+
setInterval,
|
23
|
+
clearInterval,
|
24
|
+
Buffer,
|
25
|
+
fetch
|
26
|
+
},
|
27
|
+
},
|
28
|
+
},
|
29
|
+
{
|
30
|
+
files: ["spec/**/*.js"],
|
31
|
+
plugins: { jasmine },
|
32
|
+
extends: ["jasmine/recommended"],
|
33
|
+
rules: {
|
34
|
+
semi: "error",
|
35
|
+
"eol-last": "error",
|
36
|
+
}
|
37
|
+
},
|
38
|
+
]);
|
package/index.js
CHANGED
@@ -7,11 +7,13 @@ import { initCommand } from "./src/commands/initCommand.js";
|
|
7
7
|
import { askCommand } from "./src/commands/askCommand.js";
|
8
8
|
import { slothContext } from "./src/config.js";
|
9
9
|
import { getSlothVersion, readStdin } from "./src/utils.js";
|
10
|
+
import {getCurrentDir, getInstallDir, setInstallDir} from "./src/systemUtils.js";
|
10
11
|
|
11
12
|
const program = new Command();
|
12
13
|
|
13
|
-
|
14
|
-
slothContext.
|
14
|
+
setInstallDir(dirname(fileURLToPath(import.meta.url)));
|
15
|
+
slothContext.currentDir = getCurrentDir();
|
16
|
+
slothContext.installDir = getInstallDir();
|
15
17
|
|
16
18
|
program
|
17
19
|
.name('gsloth')
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "gaunt-sloth-assistant",
|
3
|
-
"version": "0.1.
|
3
|
+
"version": "0.1.4",
|
4
4
|
"description": "",
|
5
5
|
"license": "MIT",
|
6
6
|
"author": "Andrew Kondratev",
|
@@ -12,14 +12,14 @@
|
|
12
12
|
"npm": ">=10.9.0"
|
13
13
|
},
|
14
14
|
"scripts": {
|
15
|
-
"test": "jasmine"
|
15
|
+
"test": "jasmine",
|
16
|
+
"lint": "eslint"
|
16
17
|
},
|
17
18
|
"bin": {
|
18
19
|
"gsloth": "index.js",
|
19
20
|
"gth": "index.js"
|
20
21
|
},
|
21
22
|
"dependencies": {
|
22
|
-
"@eslint/js": "^9.25.0",
|
23
23
|
"@langchain/anthropic": "^0.3.18",
|
24
24
|
"@langchain/core": "^0.3.45",
|
25
25
|
"@langchain/google-vertexai": "^0.2.4",
|
@@ -31,6 +31,10 @@
|
|
31
31
|
"uuid": "^11.1.0"
|
32
32
|
},
|
33
33
|
"devDependencies": {
|
34
|
+
"@eslint/js": "^9.25.1",
|
35
|
+
"eslint": "^9.25.1",
|
36
|
+
"eslint-plugin-jasmine": "^4.2.2",
|
37
|
+
"globals": "^16.0.0",
|
34
38
|
"jasmine": "^5.6.0",
|
35
39
|
"testdouble": "^3.20.2"
|
36
40
|
}
|
package/spec/.gsloth.config.js
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
{
|
2
|
+
"llm": {
|
3
|
+
"type": "fake",
|
4
|
+
"responses": ["First LLM message", "Second LLM message"]
|
5
|
+
},
|
6
|
+
"requirementsProviderConfig": {
|
7
|
+
"jira-legacy": {
|
8
|
+
"username": "user.name@company.com",
|
9
|
+
"token": "YoUrToKeN",
|
10
|
+
"baseUrl": "https://company.atlassian.net/rest/api/2/issue/"
|
11
|
+
}
|
12
|
+
},
|
13
|
+
"requirementsProvider": "file",
|
14
|
+
"contentProvider": "somethingSpecial",
|
15
|
+
"contentProviderConfig": {
|
16
|
+
"somethingSpecial": {
|
17
|
+
"test": "example"
|
18
|
+
}
|
19
|
+
},
|
20
|
+
"commands": {
|
21
|
+
"pr": {
|
22
|
+
"requirementsProvider": "jira-legacy"
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
package/spec/askCommand.spec.js
CHANGED
@@ -4,13 +4,36 @@ import * as td from 'testdouble';
|
|
4
4
|
describe('askCommand', function (){
|
5
5
|
|
6
6
|
beforeEach(async function() {
|
7
|
+
td.reset();
|
7
8
|
this.askQuestion = td.function();
|
8
9
|
this.prompt = await td.replaceEsm("../src/prompt.js");
|
9
10
|
td.when(this.prompt.readInternalPreamble()).thenReturn("INTERNAL PREAMBLE");
|
10
11
|
this.questionAnsweringMock = await td.replaceEsm("../src/modules/questionAnsweringModule.js");
|
11
|
-
await td.replaceEsm("../src/config.js"
|
12
|
-
|
13
|
-
|
12
|
+
await td.replaceEsm("../src/config.js", {
|
13
|
+
SLOTH_INTERNAL_PREAMBLE: '.gsloth.preamble.internal.md',
|
14
|
+
USER_PROJECT_REVIEW_PREAMBLE: '.gsloth.preamble.review.md',
|
15
|
+
slothContext: {
|
16
|
+
config: {},
|
17
|
+
currentDir: '/mock/current/dir'
|
18
|
+
},
|
19
|
+
initConfig: td.function()
|
20
|
+
});
|
21
|
+
const readFileFromCurrentDir = td.function();
|
22
|
+
const readMultipleFilesFromCurrentDir = td.function();
|
23
|
+
const extractLastMessageContent = td.function();
|
24
|
+
const toFileSafeString = td.function();
|
25
|
+
const fileSafeLocalDate = td.function();
|
26
|
+
this.utilsMock = {
|
27
|
+
readFileFromCurrentDir,
|
28
|
+
readMultipleFilesFromCurrentDir,
|
29
|
+
ProgressIndicator: td.constructor(),
|
30
|
+
extractLastMessageContent,
|
31
|
+
toFileSafeString,
|
32
|
+
fileSafeLocalDate
|
33
|
+
};
|
34
|
+
await td.replaceEsm("../src/utils.js", this.utilsMock);
|
35
|
+
td.when(this.utilsMock.readFileFromCurrentDir("test.file")).thenReturn("FILE CONTENT");
|
36
|
+
td.when(this.utilsMock.readMultipleFilesFromCurrentDir(["test.file"])).thenReturn("test.file:\n```\nFILE CONTENT\n```");
|
14
37
|
td.when(this.questionAnsweringMock.askQuestion(
|
15
38
|
'sloth-ASK',
|
16
39
|
td.matchers.anything(),
|
@@ -31,7 +54,17 @@ describe('askCommand', function (){
|
|
31
54
|
const program = new Command();
|
32
55
|
await askCommand(program, {});
|
33
56
|
await program.parseAsync(['na', 'na', 'ask', 'test message', '-f', 'test.file']);
|
34
|
-
td.verify(this.askQuestion('sloth-ASK', "INTERNAL PREAMBLE", "test message\nFILE CONTENT"));
|
57
|
+
td.verify(this.askQuestion('sloth-ASK', "INTERNAL PREAMBLE", "test message\ntest.file:\n```\nFILE CONTENT\n```"));
|
58
|
+
});
|
59
|
+
|
60
|
+
it('Should call askQuestion with message and multiple file contents', async function() {
|
61
|
+
const { askCommand } = await import("../src/commands/askCommand.js");
|
62
|
+
const program = new Command();
|
63
|
+
await askCommand(program, {});
|
64
|
+
td.when(this.utilsMock.readMultipleFilesFromCurrentDir(["test.file", "test2.file"]))
|
65
|
+
.thenReturn("test.file:\n```\nFILE CONTENT\n```\n\ntest2.file:\n```\nFILE2 CONTENT\n```");
|
66
|
+
await program.parseAsync(['na', 'na', 'ask', 'test message', '-f', 'test.file', 'test2.file']);
|
67
|
+
td.verify(this.askQuestion('sloth-ASK', "INTERNAL PREAMBLE", "test message\ntest.file:\n```\nFILE CONTENT\n```\n\ntest2.file:\n```\nFILE2 CONTENT\n```"));
|
35
68
|
});
|
36
69
|
|
37
70
|
it('Should display help correctly', async function() {
|
@@ -47,6 +80,7 @@ describe('askCommand', function (){
|
|
47
80
|
await askCommand(program, {});
|
48
81
|
|
49
82
|
const commandUnderTest = program.commands.find(c => c.name() == 'ask');
|
83
|
+
|
50
84
|
expect(commandUnderTest).toBeDefined();
|
51
85
|
commandUnderTest.outputHelp();
|
52
86
|
|
@@ -55,4 +89,4 @@ describe('askCommand', function (){
|
|
55
89
|
expect(testOutput.text).toContain('<message>');
|
56
90
|
expect(testOutput.text).toContain('-f, --file');
|
57
91
|
});
|
58
|
-
});
|
92
|
+
});
|