gaunt-sloth-assistant 0.4.2 → 0.5.0
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 +2 -1
- package/assets/release-notes/v0_5_0.md +10 -0
- package/dist/config.d.ts +4 -5
- package/dist/config.js +3 -4
- package/dist/config.js.map +1 -1
- package/dist/llmUtils.d.ts +2 -2
- package/dist/llmUtils.js +65 -28
- package/dist/llmUtils.js.map +1 -1
- package/dist/modules/questionAnsweringModule.js +8 -6
- package/dist/modules/questionAnsweringModule.js.map +1 -1
- package/dist/modules/reviewModule.js +8 -9
- package/dist/modules/reviewModule.js.map +1 -1
- package/dist/providers/jiraIssueProvider.js +3 -1
- package/dist/providers/jiraIssueProvider.js.map +1 -1
- package/docs/CONFIGURATION.md +60 -26
- package/package.json +3 -1
- package/src/config.ts +7 -9
- package/src/llmUtils.ts +72 -36
- package/src/modules/questionAnsweringModule.ts +9 -7
- package/src/modules/reviewModule.ts +8 -9
- package/src/providers/jiraIssueProvider.ts +5 -1
package/README.md
CHANGED
@@ -31,7 +31,8 @@ While there are many powerful AI assistants available, Gaunt Sloth Assistant sta
|
|
31
31
|
3. **Command-line integration** - Seamless workflow integration with existing developer tools and processes
|
32
32
|
4. **Specialized focus** - Purpose-built for code review and PR analysis rather than general-purpose assistance
|
33
33
|
5. **Extensibility** - GSloth is based on LangChain JS and can be easily extended, configured or augmented in different ways.
|
34
|
-
6. **
|
34
|
+
6. **Model Context Protocol (MCP)** - Support for MCP allows for enhanced context management.
|
35
|
+
7. **Cost Effectiveness** - When agentic tools will send a number of requests to figure out a user's intent burning thousands of tokens, gsloth simply sends your diff prefixed with guidelines for review.
|
35
36
|
|
36
37
|
Unlike proprietary solutions that restrict you to a single AI provider, Gaunt Sloth empowers developers with choice and control while maintaining the specialized capabilities needed for effective code review.
|
37
38
|
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# v0.5.0 Add MCP support
|
2
|
+
|
3
|
+
## New Features
|
4
|
+
|
5
|
+
### Model Context Protocol (MCP) Support
|
6
|
+
- Added support for Model Context Protocol (MCP) for enhanced context management
|
7
|
+
- Included `@modelcontextprotocol/server-filesystem` as a dependency
|
8
|
+
- Added configuration options for MCP servers in `.gsloth.config.json`
|
9
|
+
|
10
|
+
Use at your own risk. Not super-well-tested yet.
|
package/dist/config.d.ts
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
2
|
+
import type { Connection } from '@langchain/mcp-adapters';
|
2
3
|
export interface SlothConfig extends BaseSlothConfig {
|
3
4
|
llm: BaseChatModel;
|
4
5
|
contentProvider: string;
|
5
6
|
requirementsProvider: string;
|
6
7
|
projectGuidelines: string;
|
7
8
|
projectReviewInstructions: string;
|
9
|
+
streamOutput: boolean;
|
8
10
|
commands: {
|
9
11
|
pr: {
|
10
12
|
contentProvider: string;
|
@@ -31,6 +33,7 @@ interface BaseSlothConfig {
|
|
31
33
|
requirementsProvider?: string;
|
32
34
|
projectGuidelines?: string;
|
33
35
|
projectReviewInstructions?: string;
|
36
|
+
streamOutput?: boolean;
|
34
37
|
commands?: {
|
35
38
|
pr: {
|
36
39
|
contentProvider: string;
|
@@ -43,6 +46,7 @@ interface BaseSlothConfig {
|
|
43
46
|
};
|
44
47
|
requirementsProviderConfig?: Record<string, unknown>;
|
45
48
|
contentProviderConfig?: Record<string, unknown>;
|
49
|
+
mcpServers?: Record<string, Connection>;
|
46
50
|
}
|
47
51
|
/**
|
48
52
|
* @deprecated
|
@@ -50,11 +54,6 @@ interface BaseSlothConfig {
|
|
50
54
|
*/
|
51
55
|
export interface SlothContext {
|
52
56
|
config: SlothConfig;
|
53
|
-
session: {
|
54
|
-
configurable: {
|
55
|
-
thread_id: string;
|
56
|
-
};
|
57
|
-
};
|
58
57
|
}
|
59
58
|
export interface LLMConfig extends Record<string, unknown> {
|
60
59
|
type: string;
|
package/dist/config.js
CHANGED
@@ -1,9 +1,8 @@
|
|
1
|
-
import { v4 as uuidv4 } from 'uuid';
|
2
1
|
import { displayDebug, displayError, displayInfo, displayWarning } from '#src/consoleUtils.js';
|
3
2
|
import { importExternalFile, writeFileIfNotExistsWithMessages } from '#src/utils.js';
|
4
3
|
import { existsSync, readFileSync } from 'node:fs';
|
5
4
|
import { error, exit } from '#src/systemUtils.js';
|
6
|
-
import {
|
5
|
+
import { getGslothConfigReadPath, getGslothConfigWritePath } from '#src/filePathUtils.js';
|
7
6
|
export const USER_PROJECT_CONFIG_JS = '.gsloth.config.js';
|
8
7
|
export const USER_PROJECT_CONFIG_JSON = '.gsloth.config.json';
|
9
8
|
export const USER_PROJECT_CONFIG_MJS = '.gsloth.config.mjs';
|
@@ -17,6 +16,7 @@ export const DEFAULT_CONFIG = {
|
|
17
16
|
requirementsProvider: 'file',
|
18
17
|
projectGuidelines: PROJECT_GUIDELINES,
|
19
18
|
projectReviewInstructions: PROJECT_REVIEW_INSTRUCTIONS,
|
19
|
+
streamOutput: true,
|
20
20
|
commands: {
|
21
21
|
pr: {
|
22
22
|
contentProvider: 'github', // gh pr diff NN
|
@@ -31,7 +31,6 @@ export const DEFAULT_CONFIG = {
|
|
31
31
|
*/
|
32
32
|
export const slothContext = {
|
33
33
|
config: DEFAULT_CONFIG,
|
34
|
-
session: { configurable: { thread_id: uuidv4() } },
|
35
34
|
};
|
36
35
|
export async function initConfig() {
|
37
36
|
const jsonConfigPath = getGslothConfigReadPath(USER_PROJECT_CONFIG_JSON);
|
@@ -40,6 +39,7 @@ export async function initConfig() {
|
|
40
39
|
// Try loading JSON config file first
|
41
40
|
if (existsSync(jsonConfigPath)) {
|
42
41
|
try {
|
42
|
+
// TODO makes sense to employ ZOD to validate config
|
43
43
|
const jsonConfig = JSON.parse(readFileSync(jsonConfigPath, 'utf8'));
|
44
44
|
// If the config has an LLM with a type, create the appropriate LLM instance
|
45
45
|
if (jsonConfig.llm && typeof jsonConfig.llm === 'object' && 'type' in jsonConfig.llm) {
|
@@ -203,6 +203,5 @@ export function reset() {
|
|
203
203
|
delete slothContext[key];
|
204
204
|
});
|
205
205
|
slothContext.config = DEFAULT_CONFIG;
|
206
|
-
slothContext.session = { configurable: { thread_id: uuidv4() } };
|
207
206
|
}
|
208
207
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/llmUtils.d.ts
CHANGED
@@ -1,4 +1,4 @@
|
|
1
1
|
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
2
|
-
import {
|
3
|
-
export declare function invoke(llm: BaseChatModel,
|
2
|
+
import { SlothConfig } from '#src/config.js';
|
3
|
+
export declare function invoke(llm: BaseChatModel, systemMessage: string, prompt: string, config: SlothConfig): Promise<string>;
|
4
4
|
export declare function setVerbose(debug: boolean): void;
|
package/dist/llmUtils.js
CHANGED
@@ -1,39 +1,76 @@
|
|
1
|
-
import { HumanMessage, SystemMessage } from '@langchain/core/messages';
|
2
|
-
import {
|
1
|
+
import { HumanMessage, isAIMessageChunk, SystemMessage } from '@langchain/core/messages';
|
2
|
+
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
|
3
|
+
import { display, displayError, displayInfo } from '#src/consoleUtils.js';
|
4
|
+
import { createReactAgent } from '@langchain/langgraph/prebuilt';
|
5
|
+
import { stdout } from '#src/systemUtils.js';
|
3
6
|
const llmGlobalSettings = {
|
4
7
|
verbose: false,
|
5
8
|
};
|
6
|
-
export async function invoke(llm,
|
9
|
+
export async function invoke(llm, systemMessage, prompt, config) {
|
7
10
|
if (llmGlobalSettings.verbose) {
|
8
11
|
llm.verbose = true;
|
9
12
|
}
|
10
|
-
|
11
|
-
const
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
13
|
+
const client = getClient(config);
|
14
|
+
const tools = (await client?.getTools()) ?? [];
|
15
|
+
if (tools && tools.length > 0) {
|
16
|
+
displayInfo(`Loaded ${tools.length} MCP tools.`);
|
17
|
+
}
|
18
|
+
// Create the React agent
|
19
|
+
const agent = createReactAgent({
|
20
|
+
llm,
|
21
|
+
tools,
|
22
|
+
});
|
23
|
+
// Run the agent
|
24
|
+
try {
|
25
|
+
const messages = [new SystemMessage(systemMessage), new HumanMessage(prompt)];
|
26
|
+
display(`Connecting to LLM...`);
|
27
|
+
const stream = await agent.stream({ messages }, { streamMode: 'messages' });
|
28
|
+
const output = { aiMessage: '' };
|
29
|
+
for await (const [chunk, _metadata] of stream) {
|
30
|
+
if (isAIMessageChunk(chunk)) {
|
31
|
+
if (config.streamOutput) {
|
32
|
+
stdout.write(chunk.content, 'utf-8');
|
33
|
+
}
|
34
|
+
output.aiMessage += chunk.content;
|
35
|
+
let toolCalls = chunk.tool_calls;
|
36
|
+
if (toolCalls && toolCalls.length > 0) {
|
37
|
+
const suffix = toolCalls.length > 1 ? 's' : '';
|
38
|
+
const toolCallsString = toolCalls.map((t) => t?.name).join(', ');
|
39
|
+
displayInfo(`Using tool${suffix} ${toolCallsString}`);
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
return output.aiMessage;
|
44
|
+
}
|
45
|
+
catch (error) {
|
46
|
+
if (error instanceof Error) {
|
47
|
+
if (error?.name === 'ToolException') {
|
48
|
+
displayError(`Tool execution failed: ${error.message}`);
|
49
|
+
}
|
50
|
+
}
|
51
|
+
throw error;
|
52
|
+
}
|
53
|
+
finally {
|
54
|
+
if (client) {
|
55
|
+
console.log('closing');
|
56
|
+
await client.close();
|
57
|
+
}
|
58
|
+
}
|
35
59
|
}
|
36
60
|
export function setVerbose(debug) {
|
37
61
|
llmGlobalSettings.verbose = debug;
|
38
62
|
}
|
63
|
+
function getClient(config) {
|
64
|
+
if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
|
65
|
+
return new MultiServerMCPClient({
|
66
|
+
throwOnLoadError: true,
|
67
|
+
prefixToolNameWithServerName: true,
|
68
|
+
additionalToolNamePrefix: 'mcp',
|
69
|
+
mcpServers: config.mcpServers,
|
70
|
+
});
|
71
|
+
}
|
72
|
+
else {
|
73
|
+
return null;
|
74
|
+
}
|
75
|
+
}
|
39
76
|
//# sourceMappingURL=llmUtils.js.map
|
package/dist/llmUtils.js.map
CHANGED
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"llmUtils.js","sourceRoot":"","sources":["../src/llmUtils.ts"],"names":[],"mappings":"AACA,OAAO,
|
1
|
+
{"version":3,"file":"llmUtils.js","sourceRoot":"","sources":["../src/llmUtils.ts"],"names":[],"mappings":"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"}
|
@@ -11,14 +11,16 @@ import { invoke } from '#src/llmUtils.js';
|
|
11
11
|
* @param content - The content of the question
|
12
12
|
*/
|
13
13
|
export async function askQuestion(source, preamble, content) {
|
14
|
-
const progressIndicator =
|
15
|
-
|
16
|
-
|
14
|
+
const progressIndicator = slothContext.config.streamOutput
|
15
|
+
? undefined
|
16
|
+
: new ProgressIndicator('Thinking.');
|
17
|
+
const outputContent = await invoke(slothContext.config.llm, preamble, content, slothContext.config);
|
18
|
+
progressIndicator?.stop();
|
17
19
|
const filename = generateStandardFileName(source);
|
18
20
|
const filePath = getGslothFilePath(filename);
|
19
|
-
|
20
|
-
|
21
|
-
|
21
|
+
if (!slothContext.config.streamOutput) {
|
22
|
+
display('\n' + outputContent);
|
23
|
+
}
|
22
24
|
try {
|
23
25
|
writeFileSync(filePath, outputContent);
|
24
26
|
displaySuccess(`This report can be found in ${filePath}`);
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"questionAnsweringModule.js","sourceRoot":"","sources":["../../src/modules/questionAnsweringModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAc,EACd,QAAgB,EAChB,OAAe;IAEf,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,WAAW,CAAC,CAAC;
|
1
|
+
{"version":3,"file":"questionAnsweringModule.js","sourceRoot":"","sources":["../../src/modules/questionAnsweringModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,MAAc,EACd,QAAgB,EAChB,OAAe;IAEf,MAAM,iBAAiB,GAAG,YAAY,CAAC,MAAM,CAAC,YAAY;QACxD,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,IAAI,iBAAiB,CAAC,WAAW,CAAC,CAAC;IACvC,MAAM,aAAa,GAAG,MAAM,MAAM,CAChC,YAAY,CAAC,MAAM,CAAC,GAAG,EACvB,QAAQ,EACR,OAAO,EACP,YAAY,CAAC,MAAM,CACpB,CAAC;IACF,iBAAiB,EAAE,IAAI,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACtC,OAAO,CAAC,IAAI,GAAG,aAAa,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,CAAC;QACH,aAAa,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACvC,cAAc,CAAC,+BAA+B,QAAQ,EAAE,CAAC,CAAC;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,YAAY,CAAC,mCAAmC,QAAQ,EAAE,CAAC,CAAC;QAC5D,YAAY,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACrE,yDAAyD;QACzD,WAAW;IACb,CAAC;AACH,CAAC"}
|
@@ -1,21 +1,20 @@
|
|
1
1
|
import { slothContext } from '#src/config.js';
|
2
2
|
import { display, displayDebug, displayError, displaySuccess } from '#src/consoleUtils.js';
|
3
|
-
import { stdout } from '#src/systemUtils.js';
|
4
3
|
import { generateStandardFileName, ProgressIndicator } from '#src/utils.js';
|
5
4
|
import { writeFileSync } from 'node:fs';
|
6
5
|
import { invoke } from '#src/llmUtils.js';
|
7
6
|
import { getGslothFilePath } from '#src/filePathUtils.js';
|
8
7
|
export async function review(source, preamble, diff) {
|
9
|
-
const progressIndicator =
|
10
|
-
|
11
|
-
|
8
|
+
const progressIndicator = slothContext.config.streamOutput
|
9
|
+
? undefined
|
10
|
+
: new ProgressIndicator('Reviewing.');
|
11
|
+
const outputContent = await invoke(slothContext.config.llm, preamble, diff, slothContext.config);
|
12
|
+
progressIndicator?.stop();
|
12
13
|
const filename = generateStandardFileName(source);
|
13
14
|
const filePath = getGslothFilePath(filename);
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
// TODO highlight LLM output with something like Prism.JS (maybe system emoj are enough ✅⚠️❌)
|
18
|
-
display(outputContent);
|
15
|
+
if (!slothContext.config.streamOutput) {
|
16
|
+
display('\n' + outputContent);
|
17
|
+
}
|
19
18
|
try {
|
20
19
|
writeFileSync(filePath, outputContent);
|
21
20
|
displaySuccess(`This report can be found in ${filePath}`);
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"reviewModule.js","sourceRoot":"","sources":["../../src/modules/reviewModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAE,
|
1
|
+
{"version":3,"file":"reviewModule.js","sourceRoot":"","sources":["../../src/modules/reviewModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3F,OAAO,EAAE,wBAAwB,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,MAAc,EAAE,QAAgB,EAAE,IAAY;IACzE,MAAM,iBAAiB,GAAG,YAAY,CAAC,MAAM,CAAC,YAAY;QACxD,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,IAAI,iBAAiB,CAAC,YAAY,CAAC,CAAC;IACxC,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;IACjG,iBAAiB,EAAE,IAAI,EAAE,CAAC;IAC1B,MAAM,QAAQ,GAAG,wBAAwB,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,YAAY,EAAE,CAAC;QACtC,OAAO,CAAC,IAAI,GAAG,aAAa,CAAC,CAAC;IAChC,CAAC;IACD,IAAI,CAAC;QACH,aAAa,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;QACvC,cAAc,CAAC,+BAA+B,QAAQ,EAAE,CAAC,CAAC;IAC5D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,YAAY,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC7D,YAAY,CAAC,mCAAmC,QAAQ,EAAE,CAAC,CAAC;QAC5D,qDAAqD;QACrD,WAAW;IACb,CAAC;AACH,CAAC"}
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { display, displayError, displayWarning } from '#src/consoleUtils.js';
|
2
2
|
import { env } from '#src/systemUtils.js';
|
3
|
+
import { ProgressIndicator } from '#src/utils.js';
|
3
4
|
/**
|
4
5
|
* Gets Jira issue using Atlassian REST API v3 with Personal Access Token
|
5
6
|
*
|
@@ -72,7 +73,6 @@ async function getJiraIssue(config, jiraKey) {
|
|
72
73
|
if (config.displayUrl) {
|
73
74
|
display(`Loading Jira issue ${config.displayUrl}${jiraKey}`);
|
74
75
|
}
|
75
|
-
display(`Retrieving jira from api ${apiUrl.replace(/^https?:\/\//, '')}`);
|
76
76
|
// This filter will be necessary for V3: `&expand=renderedFields` to convert ADF to HTML
|
77
77
|
const filters = '?fields=summary,description'; // Limit JSON to summary and description
|
78
78
|
// Encode credentials for Basic Authentication header
|
@@ -85,10 +85,12 @@ async function getJiraIssue(config, jiraKey) {
|
|
85
85
|
Accept: 'application/json; charset=utf-8',
|
86
86
|
'Accept-Language': 'en-US,en;q=0.9', // Prevents errors in other languages
|
87
87
|
};
|
88
|
+
const progressIndicator = new ProgressIndicator(`Retrieving jira from api ${apiUrl.replace(/^https?:\/\//, '')}`);
|
88
89
|
const response = await fetch(apiUrl + filters, {
|
89
90
|
method: 'GET',
|
90
91
|
headers: headers,
|
91
92
|
});
|
93
|
+
progressIndicator.stop();
|
92
94
|
if (!response?.ok) {
|
93
95
|
try {
|
94
96
|
const errorData = await response.json();
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"jiraIssueProvider.js","sourceRoot":"","sources":["../../src/providers/jiraIssueProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;
|
1
|
+
{"version":3,"file":"jiraIssueProvider.js","sourceRoot":"","sources":["../../src/providers/jiraIssueProvider.ts"],"names":[],"mappings":"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"}
|
package/docs/CONFIGURATION.md
CHANGED
@@ -39,35 +39,37 @@ If the `.gsloth` directory doesn't exist, gsloth will continue writing all files
|
|
39
39
|
|
40
40
|
It is always worth checking sourcecode in [config.ts](../src/config.ts) for more insightful information.
|
41
41
|
|
42
|
-
| Parameter | Required | Default Value | Description
|
43
|
-
|
42
|
+
| Parameter | Required | Default Value | Description |
|
43
|
+
|------------------------------------------|-----------------------------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
44
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`.
|
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
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
|
-
| `
|
53
|
-
| `commands
|
54
|
-
| `commands.pr
|
55
|
-
| `commands.pr.
|
56
|
-
| `commands.
|
57
|
-
| `commands.review
|
58
|
-
| `commands.review.
|
59
|
-
| `
|
60
|
-
| `requirementsProviderConfig
|
61
|
-
| `requirementsProviderConfig.jira
|
62
|
-
| `requirementsProviderConfig.jira.
|
63
|
-
| `requirementsProviderConfig.jira.
|
64
|
-
| `requirementsProviderConfig.jira.
|
65
|
-
| `requirementsProviderConfig.jira
|
66
|
-
| `requirementsProviderConfig.jira-legacy
|
67
|
-
| `requirementsProviderConfig.jira-legacy.
|
51
|
+
| `projectReviewInstructions` | Optional | `.gsloth.review.md` | Path to the file containing project review instructions. |
|
52
|
+
| `streamOutput` | Optional | `true` | When set to `true`, AI responses are streamed to the console in real-time. When `false`, responses are displayed only after completion. |
|
53
|
+
| `commands` | Optional | - | Configuration for specific commands. |
|
54
|
+
| `commands.pr` | Optional | - | Configuration for the PR command. |
|
55
|
+
| `commands.pr.contentProvider` | Optional | `github` | Content provider used for PR review (`gsloth pr`). |
|
56
|
+
| `commands.pr.requirementsProvider` | Optional | `github` | Requirements provider used for PR review. If not specified, falls back to the global `requirementsProvider`. |
|
57
|
+
| `commands.review` | Optional | - | Configuration for the review command. |
|
58
|
+
| `commands.review.contentProvider` | Optional | - | Content provider specifically for the review command. If not specified, falls back to the global `contentProvider`. |
|
59
|
+
| `commands.review.requirementsProvider` | Optional | - | Requirements provider specifically for the review command. If not specified, falls back to the global `requirementsProvider`. |
|
60
|
+
| `requirementsProviderConfig` | Optional | - | Configuration for requirements providers. Contains provider-specific configurations. |
|
61
|
+
| `requirementsProviderConfig.jira` | Optional | - | Configuration for the Jira requirements provider (Atlassian REST API v3 with Personal Access Token). |
|
62
|
+
| `requirementsProviderConfig.jira.username` | Optional | - | Jira username (email). Can also be set via JIRA_USERNAME environment variable. |
|
63
|
+
| `requirementsProviderConfig.jira.token` | Optional | - | Jira Personal Access Token. Can also be set via JIRA_API_PAT_TOKEN environment variable. |
|
64
|
+
| `requirementsProviderConfig.jira.cloudId` | Required for `jira` | - | Atlassian Cloud ID. Can also be set via JIRA_CLOUD_ID environment variable. |
|
65
|
+
| `requirementsProviderConfig.jira.displayUrl` | Optional | - | Optional URL for displaying Jira issues (e.g., "https://yourcompany.atlassian.net/browse/"). |
|
66
|
+
| `requirementsProviderConfig.jira-legacy` | Optional | - | Configuration for the Jira Legacy requirements provider (Atlassian REST API v2 with Legacy API Token). |
|
67
|
+
| `requirementsProviderConfig.jira-legacy.username` | Optional | - | Jira username (email). Can also be set via JIRA_USERNAME environment variable. |
|
68
|
+
| `requirementsProviderConfig.jira-legacy.token` | Optional | - | Jira Legacy API Token. Can also be set via JIRA_LEGACY_API_TOKEN environment variable. |
|
68
69
|
| `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.
|
70
|
+
| `requirementsProviderConfig.jira-legacy.displayUrl` | Optional | - | Optional URL for displaying Jira issues (e.g., "https://yourcompany.atlassian.net/browse/"). |
|
71
|
+
| `contentProviderConfig` | Optional | - | Configuration for content providers. Currently, the available content providers (`github`, `file`, and `text`) don't require specific configuration. |
|
72
|
+
| `mcpServers` | Optional | - | Configuration for Model Context Protocol (MCP) servers. This allows for enhanced context management. |
|
71
73
|
|
72
74
|
## Config initialization
|
73
75
|
Configuration can be created with `gsloth init [vendor]` command.
|
@@ -195,6 +197,38 @@ export async function configure(importFunction, global) {
|
|
195
197
|
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).
|
196
198
|
See [Langchain documentation](https://js.langchain.com/docs/tutorials/llm_chain/) for more details.
|
197
199
|
|
200
|
+
## Model Context Protocol (MCP)
|
201
|
+
|
202
|
+
Gaunt Sloth Assistant supports the Model Context Protocol (MCP), which provides enhanced context management.
|
203
|
+
The `@modelcontextprotocol/server-filesystem` package is included as a dependency, allowing you to easily configure file system access for your LLM.
|
204
|
+
|
205
|
+
### MCP Filesystem Server Configuration
|
206
|
+
|
207
|
+
To configure the MCP filesystem server, add the `mcpServers` section to your configuration file:
|
208
|
+
|
209
|
+
```json
|
210
|
+
{
|
211
|
+
"llm": {
|
212
|
+
"type": "vertexai",
|
213
|
+
"model": "gemini-2.5-pro-preview-05-06",
|
214
|
+
"temperature": 0
|
215
|
+
},
|
216
|
+
"mcpServers": {
|
217
|
+
"filesystem": {
|
218
|
+
"transport": "stdio",
|
219
|
+
"command": "npx",
|
220
|
+
"args": [
|
221
|
+
"-y",
|
222
|
+
"@modelcontextprotocol/server-filesystem",
|
223
|
+
"/home/path/to/your/files"
|
224
|
+
]
|
225
|
+
}
|
226
|
+
}
|
227
|
+
}
|
228
|
+
```
|
229
|
+
|
230
|
+
This configuration launches the MCP filesystem server using npx, providing the LLM with access to the specified directory. The server uses stdio for communication with the LLM.
|
231
|
+
|
198
232
|
## Content providers
|
199
233
|
|
200
234
|
### GitHub Issues
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "gaunt-sloth-assistant",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.5.0",
|
4
4
|
"description": "",
|
5
5
|
"license": "MIT",
|
6
6
|
"author": "Andrew Kondratev",
|
@@ -29,6 +29,8 @@
|
|
29
29
|
"@langchain/google-vertexai": "^0.2.8",
|
30
30
|
"@langchain/groq": "^0.2.2",
|
31
31
|
"@langchain/langgraph": "^0.2.71",
|
32
|
+
"@langchain/mcp-adapters": "^0.4.5",
|
33
|
+
"@modelcontextprotocol/server-filesystem": "^2025.3.28",
|
32
34
|
"chalk": "^5.4.1",
|
33
35
|
"commander": "^14.0.0",
|
34
36
|
"uuid": "^11.1.0"
|
package/src/config.ts
CHANGED
@@ -1,10 +1,10 @@
|
|
1
|
-
import { v4 as uuidv4 } from 'uuid';
|
2
1
|
import { displayDebug, displayError, displayInfo, displayWarning } from '#src/consoleUtils.js';
|
3
2
|
import { importExternalFile, writeFileIfNotExistsWithMessages } from '#src/utils.js';
|
4
3
|
import { existsSync, readFileSync } from 'node:fs';
|
5
4
|
import { error, exit } from '#src/systemUtils.js';
|
6
5
|
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
7
|
-
import {
|
6
|
+
import { getGslothConfigReadPath, getGslothConfigWritePath } from '#src/filePathUtils.js';
|
7
|
+
import type { Connection } from '@langchain/mcp-adapters';
|
8
8
|
|
9
9
|
export interface SlothConfig extends BaseSlothConfig {
|
10
10
|
llm: BaseChatModel; // FIXME this is still bad keeping instance in config is probably not best choice
|
@@ -12,6 +12,7 @@ export interface SlothConfig extends BaseSlothConfig {
|
|
12
12
|
requirementsProvider: string;
|
13
13
|
projectGuidelines: string;
|
14
14
|
projectReviewInstructions: string;
|
15
|
+
streamOutput: boolean;
|
15
16
|
commands: {
|
16
17
|
pr: {
|
17
18
|
contentProvider: string;
|
@@ -40,6 +41,7 @@ interface BaseSlothConfig {
|
|
40
41
|
requirementsProvider?: string;
|
41
42
|
projectGuidelines?: string;
|
42
43
|
projectReviewInstructions?: string;
|
44
|
+
streamOutput?: boolean;
|
43
45
|
commands?: {
|
44
46
|
pr: {
|
45
47
|
contentProvider: string;
|
@@ -52,6 +54,7 @@ interface BaseSlothConfig {
|
|
52
54
|
};
|
53
55
|
requirementsProviderConfig?: Record<string, unknown>;
|
54
56
|
contentProviderConfig?: Record<string, unknown>;
|
57
|
+
mcpServers?: Record<string, Connection>;
|
55
58
|
}
|
56
59
|
|
57
60
|
/**
|
@@ -60,11 +63,6 @@ interface BaseSlothConfig {
|
|
60
63
|
*/
|
61
64
|
export interface SlothContext {
|
62
65
|
config: SlothConfig;
|
63
|
-
session: {
|
64
|
-
configurable: {
|
65
|
-
thread_id: string;
|
66
|
-
};
|
67
|
-
};
|
68
66
|
}
|
69
67
|
|
70
68
|
export interface LLMConfig extends Record<string, unknown> {
|
@@ -88,6 +86,7 @@ export const DEFAULT_CONFIG: Partial<SlothConfig> = {
|
|
88
86
|
requirementsProvider: 'file',
|
89
87
|
projectGuidelines: PROJECT_GUIDELINES,
|
90
88
|
projectReviewInstructions: PROJECT_REVIEW_INSTRUCTIONS,
|
89
|
+
streamOutput: true,
|
91
90
|
commands: {
|
92
91
|
pr: {
|
93
92
|
contentProvider: 'github', // gh pr diff NN
|
@@ -103,7 +102,6 @@ export const DEFAULT_CONFIG: Partial<SlothConfig> = {
|
|
103
102
|
*/
|
104
103
|
export const slothContext = {
|
105
104
|
config: DEFAULT_CONFIG,
|
106
|
-
session: { configurable: { thread_id: uuidv4() } },
|
107
105
|
} as Partial<SlothContext> as SlothContext;
|
108
106
|
|
109
107
|
export async function initConfig(): Promise<void> {
|
@@ -114,6 +112,7 @@ export async function initConfig(): Promise<void> {
|
|
114
112
|
// Try loading JSON config file first
|
115
113
|
if (existsSync(jsonConfigPath)) {
|
116
114
|
try {
|
115
|
+
// TODO makes sense to employ ZOD to validate config
|
117
116
|
const jsonConfig = JSON.parse(readFileSync(jsonConfigPath, 'utf8')) as RawSlothConfig;
|
118
117
|
// If the config has an LLM with a type, create the appropriate LLM instance
|
119
118
|
if (jsonConfig.llm && typeof jsonConfig.llm === 'object' && 'type' in jsonConfig.llm) {
|
@@ -296,5 +295,4 @@ export function reset() {
|
|
296
295
|
delete (slothContext as unknown as Record<string, unknown>)[key];
|
297
296
|
});
|
298
297
|
slothContext.config = DEFAULT_CONFIG as SlothConfig;
|
299
|
-
slothContext.session = { configurable: { thread_id: uuidv4() } };
|
300
298
|
}
|
package/src/llmUtils.ts
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
-
import type { Message
|
2
|
-
import {
|
1
|
+
import type { Message } from '#src/modules/types.js';
|
2
|
+
import { HumanMessage, isAIMessageChunk, SystemMessage } from '@langchain/core/messages';
|
3
3
|
import { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
4
|
-
import {
|
5
|
-
import {
|
4
|
+
import { SlothConfig } from '#src/config.js';
|
5
|
+
import { MultiServerMCPClient } from '@langchain/mcp-adapters';
|
6
|
+
import { display, displayError, displayInfo } from '#src/consoleUtils.js';
|
7
|
+
import { createReactAgent } from '@langchain/langgraph/prebuilt';
|
8
|
+
import { stdout } from '#src/systemUtils.js';
|
6
9
|
|
7
10
|
const llmGlobalSettings = {
|
8
11
|
verbose: false,
|
@@ -10,45 +13,78 @@ const llmGlobalSettings = {
|
|
10
13
|
|
11
14
|
export async function invoke(
|
12
15
|
llm: BaseChatModel,
|
13
|
-
options: Partial<BaseLanguageModelCallOptions>,
|
14
16
|
systemMessage: string,
|
15
|
-
prompt: string
|
17
|
+
prompt: string,
|
18
|
+
config: SlothConfig
|
16
19
|
): Promise<string> {
|
17
20
|
if (llmGlobalSettings.verbose) {
|
18
21
|
llm.verbose = true;
|
19
22
|
}
|
20
|
-
|
21
|
-
const
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
23
|
+
|
24
|
+
const client = getClient(config);
|
25
|
+
|
26
|
+
const tools = (await client?.getTools()) ?? [];
|
27
|
+
if (tools && tools.length > 0) {
|
28
|
+
displayInfo(`Loaded ${tools.length} MCP tools.`);
|
29
|
+
}
|
30
|
+
|
31
|
+
// Create the React agent
|
32
|
+
const agent = createReactAgent({
|
33
|
+
llm,
|
34
|
+
tools,
|
35
|
+
});
|
36
|
+
|
37
|
+
// Run the agent
|
38
|
+
try {
|
39
|
+
const messages: Message[] = [new SystemMessage(systemMessage), new HumanMessage(prompt)];
|
40
|
+
display(`Connecting to LLM...`);
|
41
|
+
const stream = await agent.stream({ messages }, { streamMode: 'messages' });
|
42
|
+
|
43
|
+
const output = { aiMessage: '' };
|
44
|
+
for await (const [chunk, _metadata] of stream) {
|
45
|
+
if (isAIMessageChunk(chunk)) {
|
46
|
+
if (config.streamOutput) {
|
47
|
+
stdout.write(chunk.content as string, 'utf-8');
|
48
|
+
}
|
49
|
+
output.aiMessage += chunk.content;
|
50
|
+
let toolCalls = chunk.tool_calls;
|
51
|
+
if (toolCalls && toolCalls.length > 0) {
|
52
|
+
const suffix = toolCalls.length > 1 ? 's' : '';
|
53
|
+
const toolCallsString = toolCalls.map((t) => t?.name).join(', ');
|
54
|
+
displayInfo(`Using tool${suffix} ${toolCallsString}`);
|
55
|
+
}
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
return output.aiMessage;
|
60
|
+
} catch (error) {
|
61
|
+
if (error instanceof Error) {
|
62
|
+
if (error?.name === 'ToolException') {
|
63
|
+
displayError(`Tool execution failed: ${error.message}`);
|
64
|
+
}
|
65
|
+
}
|
66
|
+
throw error;
|
67
|
+
} finally {
|
68
|
+
if (client) {
|
69
|
+
console.log('closing');
|
70
|
+
await client.close();
|
71
|
+
}
|
72
|
+
}
|
50
73
|
}
|
51
74
|
|
52
75
|
export function setVerbose(debug: boolean) {
|
53
76
|
llmGlobalSettings.verbose = debug;
|
54
77
|
}
|
78
|
+
|
79
|
+
function getClient(config: SlothConfig) {
|
80
|
+
if (config.mcpServers && Object.keys(config.mcpServers).length > 0) {
|
81
|
+
return new MultiServerMCPClient({
|
82
|
+
throwOnLoadError: true,
|
83
|
+
prefixToolNameWithServerName: true,
|
84
|
+
additionalToolNamePrefix: 'mcp',
|
85
|
+
mcpServers: config.mcpServers,
|
86
|
+
});
|
87
|
+
} else {
|
88
|
+
return null;
|
89
|
+
}
|
90
|
+
}
|
@@ -16,19 +16,21 @@ export async function askQuestion(
|
|
16
16
|
preamble: string,
|
17
17
|
content: string
|
18
18
|
): Promise<void> {
|
19
|
-
const progressIndicator =
|
19
|
+
const progressIndicator = slothContext.config.streamOutput
|
20
|
+
? undefined
|
21
|
+
: new ProgressIndicator('Thinking.');
|
20
22
|
const outputContent = await invoke(
|
21
23
|
slothContext.config.llm,
|
22
|
-
slothContext.session,
|
23
24
|
preamble,
|
24
|
-
content
|
25
|
+
content,
|
26
|
+
slothContext.config
|
25
27
|
);
|
26
|
-
progressIndicator
|
28
|
+
progressIndicator?.stop();
|
27
29
|
const filename = generateStandardFileName(source);
|
28
30
|
const filePath = getGslothFilePath(filename);
|
29
|
-
|
30
|
-
|
31
|
-
|
31
|
+
if (!slothContext.config.streamOutput) {
|
32
|
+
display('\n' + outputContent);
|
33
|
+
}
|
32
34
|
try {
|
33
35
|
writeFileSync(filePath, outputContent);
|
34
36
|
displaySuccess(`This report can be found in ${filePath}`);
|
@@ -1,22 +1,21 @@
|
|
1
1
|
import { slothContext } from '#src/config.js';
|
2
2
|
import { display, displayDebug, displayError, displaySuccess } from '#src/consoleUtils.js';
|
3
|
-
import { stdout } from '#src/systemUtils.js';
|
4
3
|
import { generateStandardFileName, ProgressIndicator } from '#src/utils.js';
|
5
4
|
import { writeFileSync } from 'node:fs';
|
6
5
|
import { invoke } from '#src/llmUtils.js';
|
7
6
|
import { getGslothFilePath } from '#src/filePathUtils.js';
|
8
7
|
|
9
8
|
export async function review(source: string, preamble: string, diff: string): Promise<void> {
|
10
|
-
const progressIndicator =
|
11
|
-
|
12
|
-
|
9
|
+
const progressIndicator = slothContext.config.streamOutput
|
10
|
+
? undefined
|
11
|
+
: new ProgressIndicator('Reviewing.');
|
12
|
+
const outputContent = await invoke(slothContext.config.llm, preamble, diff, slothContext.config);
|
13
|
+
progressIndicator?.stop();
|
13
14
|
const filename = generateStandardFileName(source);
|
14
15
|
const filePath = getGslothFilePath(filename);
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
// TODO highlight LLM output with something like Prism.JS (maybe system emoj are enough ✅⚠️❌)
|
19
|
-
display(outputContent);
|
16
|
+
if (!slothContext.config.streamOutput) {
|
17
|
+
display('\n' + outputContent);
|
18
|
+
}
|
20
19
|
try {
|
21
20
|
writeFileSync(filePath, outputContent);
|
22
21
|
displaySuccess(`This report can be found in ${filePath}`);
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import { display, displayError, displayWarning } from '#src/consoleUtils.js';
|
2
2
|
import { env } from '#src/systemUtils.js';
|
3
3
|
import type { JiraConfig } from './types.js';
|
4
|
+
import { ProgressIndicator } from '#src/utils.js';
|
4
5
|
|
5
6
|
interface JiraIssueResponse {
|
6
7
|
fields: {
|
@@ -105,7 +106,6 @@ async function getJiraIssue(config: JiraConfig, jiraKey: string): Promise<JiraIs
|
|
105
106
|
if (config.displayUrl) {
|
106
107
|
display(`Loading Jira issue ${config.displayUrl}${jiraKey}`);
|
107
108
|
}
|
108
|
-
display(`Retrieving jira from api ${apiUrl.replace(/^https?:\/\//, '')}`);
|
109
109
|
|
110
110
|
// This filter will be necessary for V3: `&expand=renderedFields` to convert ADF to HTML
|
111
111
|
const filters = '?fields=summary,description'; // Limit JSON to summary and description
|
@@ -122,10 +122,14 @@ async function getJiraIssue(config: JiraConfig, jiraKey: string): Promise<JiraIs
|
|
122
122
|
'Accept-Language': 'en-US,en;q=0.9', // Prevents errors in other languages
|
123
123
|
};
|
124
124
|
|
125
|
+
const progressIndicator = new ProgressIndicator(
|
126
|
+
`Retrieving jira from api ${apiUrl.replace(/^https?:\/\//, '')}`
|
127
|
+
);
|
125
128
|
const response = await fetch(apiUrl + filters, {
|
126
129
|
method: 'GET',
|
127
130
|
headers: headers,
|
128
131
|
});
|
132
|
+
progressIndicator.stop();
|
129
133
|
|
130
134
|
if (!response?.ok) {
|
131
135
|
try {
|