gaunt-sloth-assistant 0.1.5 → 0.3.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.
Files changed (145) hide show
  1. package/{.gsloth.preamble.review.md → .gsloth.guidelines.md} +0 -8
  2. package/.gsloth.review.md +7 -0
  3. package/.prettierrc.json +9 -0
  4. package/README.md +177 -158
  5. package/ROADMAP.md +1 -1
  6. package/dist/commands/askCommand.d.ts +6 -0
  7. package/dist/commands/askCommand.js +27 -0
  8. package/dist/commands/askCommand.js.map +1 -0
  9. package/dist/commands/initCommand.d.ts +6 -0
  10. package/dist/commands/initCommand.js +16 -0
  11. package/dist/commands/initCommand.js.map +1 -0
  12. package/dist/commands/reviewCommand.d.ts +3 -0
  13. package/dist/commands/reviewCommand.js +142 -0
  14. package/dist/commands/reviewCommand.js.map +1 -0
  15. package/dist/config.d.ts +84 -0
  16. package/dist/config.js +180 -0
  17. package/dist/config.js.map +1 -0
  18. package/dist/configs/anthropic.d.ts +4 -0
  19. package/{src → dist}/configs/anthropic.js +45 -48
  20. package/dist/configs/anthropic.js.map +1 -0
  21. package/dist/configs/fake.d.ts +3 -0
  22. package/{src → dist}/configs/fake.js +11 -14
  23. package/dist/configs/fake.js.map +1 -0
  24. package/dist/configs/groq.d.ts +4 -0
  25. package/{src → dist}/configs/groq.js +10 -13
  26. package/dist/configs/groq.js.map +1 -0
  27. package/dist/configs/types.d.ts +14 -0
  28. package/dist/configs/types.js +2 -0
  29. package/dist/configs/types.js.map +1 -0
  30. package/dist/configs/vertexai.d.ts +4 -0
  31. package/{src → dist}/configs/vertexai.js +44 -47
  32. package/dist/configs/vertexai.js.map +1 -0
  33. package/dist/consoleUtils.d.ts +6 -0
  34. package/{src → dist}/consoleUtils.js +10 -15
  35. package/dist/consoleUtils.js.map +1 -0
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.js +26 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/llmUtils.d.ts +4 -0
  40. package/dist/llmUtils.js +39 -0
  41. package/dist/llmUtils.js.map +1 -0
  42. package/dist/modules/questionAnsweringModule.d.ts +7 -0
  43. package/dist/modules/questionAnsweringModule.js +33 -0
  44. package/dist/modules/questionAnsweringModule.js.map +1 -0
  45. package/dist/modules/reviewModule.d.ts +1 -0
  46. package/dist/modules/reviewModule.js +29 -0
  47. package/dist/modules/reviewModule.js.map +1 -0
  48. package/dist/modules/types.d.ts +18 -0
  49. package/dist/modules/types.js +2 -0
  50. package/dist/modules/types.js.map +1 -0
  51. package/dist/prompt.d.ts +8 -0
  52. package/dist/prompt.js +45 -0
  53. package/dist/prompt.js.map +1 -0
  54. package/dist/providers/file.d.ts +8 -0
  55. package/dist/providers/file.js +20 -0
  56. package/dist/providers/file.js.map +1 -0
  57. package/dist/providers/ghPrDiffProvider.d.ts +8 -0
  58. package/dist/providers/ghPrDiffProvider.js +16 -0
  59. package/dist/providers/ghPrDiffProvider.js.map +1 -0
  60. package/dist/providers/jiraIssueLegacyAccessTokenProvider.d.ts +8 -0
  61. package/dist/providers/jiraIssueLegacyAccessTokenProvider.js +62 -0
  62. package/dist/providers/jiraIssueLegacyAccessTokenProvider.js.map +1 -0
  63. package/dist/providers/jiraIssueLegacyProvider.d.ts +8 -0
  64. package/dist/providers/jiraIssueLegacyProvider.js +74 -0
  65. package/dist/providers/jiraIssueLegacyProvider.js.map +1 -0
  66. package/dist/providers/jiraIssueProvider.d.ts +11 -0
  67. package/dist/providers/jiraIssueProvider.js +96 -0
  68. package/dist/providers/jiraIssueProvider.js.map +1 -0
  69. package/dist/providers/text.d.ts +8 -0
  70. package/dist/providers/text.js +10 -0
  71. package/dist/providers/text.js.map +1 -0
  72. package/dist/providers/types.d.ts +21 -0
  73. package/dist/providers/types.js +2 -0
  74. package/dist/providers/types.js.map +1 -0
  75. package/dist/systemUtils.d.ts +32 -0
  76. package/dist/systemUtils.js +70 -0
  77. package/dist/systemUtils.js.map +1 -0
  78. package/dist/utils.d.ts +49 -0
  79. package/dist/utils.js +192 -0
  80. package/dist/utils.js.map +1 -0
  81. package/docs/CONFIGURATION.md +99 -10
  82. package/docs/RELEASE-HOWTO.md +7 -1
  83. package/eslint.config.js +99 -21
  84. package/gth-ASK-2025-05-16T14-11-39.md +3 -0
  85. package/gth-ASK-2025-05-16T14-18-27.md +3 -0
  86. package/gth-ASK-2025-05-16T14-18-56.md +1 -0
  87. package/gth-ASK-2025-05-16T14-41-20.md +3 -0
  88. package/gth-ASK-2025-05-16T14-43-31.md +51 -0
  89. package/gth-ASK-2025-05-16T16-05-52.md +62 -0
  90. package/gth-DIFF-review-2025-05-16T16-07-53.md +56 -0
  91. package/gth-DIFF-review-2025-05-16T16-18-55.md +292 -0
  92. package/index.js +10 -27
  93. package/package.json +26 -15
  94. package/src/commands/askCommand.ts +35 -0
  95. package/src/commands/initCommand.ts +19 -0
  96. package/src/commands/reviewCommand.ts +223 -0
  97. package/src/config.ts +269 -0
  98. package/src/configs/anthropic.ts +57 -0
  99. package/src/configs/fake.ts +15 -0
  100. package/src/configs/groq.ts +54 -0
  101. package/src/configs/vertexai.ts +53 -0
  102. package/src/consoleUtils.ts +33 -0
  103. package/src/index.ts +30 -0
  104. package/src/llmUtils.ts +54 -0
  105. package/src/modules/questionAnsweringModule.ts +44 -0
  106. package/src/modules/reviewModule.ts +31 -0
  107. package/src/modules/types.ts +23 -0
  108. package/src/prompt.ts +54 -0
  109. package/src/providers/file.ts +24 -0
  110. package/src/providers/ghPrDiffProvider.ts +20 -0
  111. package/src/providers/jiraIssueLegacyProvider.ts +103 -0
  112. package/src/providers/jiraIssueProvider.ts +133 -0
  113. package/src/providers/text.ts +14 -0
  114. package/src/providers/types.ts +24 -0
  115. package/src/systemUtils.ts +90 -0
  116. package/src/utils.ts +232 -0
  117. package/tsconfig.json +24 -0
  118. package/vitest.config.ts +13 -0
  119. package/.eslint.config.mjs +0 -72
  120. package/.github/dependabot.yml +0 -11
  121. package/.github/workflows/ci.yml +0 -33
  122. package/spec/.gsloth.config.js +0 -22
  123. package/spec/.gsloth.config.json +0 -25
  124. package/spec/askCommand.spec.js +0 -92
  125. package/spec/config.spec.js +0 -421
  126. package/spec/initCommand.spec.js +0 -55
  127. package/spec/predefinedConfigs.spec.js +0 -100
  128. package/spec/questionAnsweringModule.spec.js +0 -137
  129. package/spec/reviewCommand.spec.js +0 -222
  130. package/spec/reviewModule.spec.js +0 -28
  131. package/spec/support/jasmine.mjs +0 -14
  132. package/src/commands/askCommand.js +0 -27
  133. package/src/commands/initCommand.js +0 -17
  134. package/src/commands/reviewCommand.js +0 -154
  135. package/src/config.js +0 -177
  136. package/src/modules/questionAnsweringModule.js +0 -82
  137. package/src/modules/reviewModule.js +0 -70
  138. package/src/prompt.js +0 -34
  139. package/src/providers/file.js +0 -19
  140. package/src/providers/ghPrDiffProvider.js +0 -11
  141. package/src/providers/jiraIssueLegacyAccessTokenProvider.js +0 -84
  142. package/src/providers/text.js +0 -6
  143. package/src/systemUtils.js +0 -32
  144. package/src/utils.js +0 -173
  145. /package/{.gsloth.preamble.internal.md → .gsloth.backstory.md} +0 -0
@@ -1,33 +1,28 @@
1
1
  import chalk from 'chalk';
2
- import {debug as systemDebug, error as systemError, log} from './systemUtils.js';
3
-
2
+ import { debug as systemDebug, error as systemError, log } from '#src/systemUtils.js';
4
3
  // TODO it seems like commander supports coloured output, maybe dependency to chalk can be removed
5
-
6
- export function displayError (message) {
4
+ export function displayError(message) {
7
5
  systemError(chalk.red(message));
8
6
  }
9
-
10
- export function displayWarning (message) {
7
+ export function displayWarning(message) {
11
8
  systemError(chalk.yellow(message));
12
9
  }
13
-
14
- export function displaySuccess (message) {
10
+ export function displaySuccess(message) {
15
11
  systemError(chalk.green(message));
16
12
  }
17
-
18
- export function displayInfo (message) {
13
+ export function displayInfo(message) {
19
14
  systemError(chalk.blue(message));
20
15
  }
21
-
22
16
  export function display(message) {
23
17
  log(message);
24
18
  }
25
-
26
19
  export function displayDebug(message) {
27
20
  // TODO make it controlled by config
28
- if (message?.stack) {
29
- systemDebug(message.stack);
30
- } else {
21
+ if (message instanceof Error) {
22
+ systemDebug(message.stack || '');
23
+ }
24
+ else if (message !== undefined) {
31
25
  systemDebug(message);
32
26
  }
33
27
  }
28
+ //# sourceMappingURL=consoleUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consoleUtils.js","sourceRoot":"","sources":["../src/consoleUtils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,KAAK,IAAI,WAAW,EAAE,KAAK,IAAI,WAAW,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;AAEtF,kGAAkG;AAElG,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,WAAW,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe;IACzC,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,OAAe;IACrC,GAAG,CAAC,OAAO,CAAC,CAAC;AACf,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAmC;IAC9D,oCAAoC;IACpC,IAAI,OAAO,YAAY,KAAK,EAAE,CAAC;QAC7B,WAAW,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IACnC,CAAC;SAAM,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QACjC,WAAW,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,26 @@
1
+ import { Command } from 'commander';
2
+ import { askCommand } from '#src/commands/askCommand.js';
3
+ import { initCommand } from '#src/commands/initCommand.js';
4
+ import { reviewCommand } from '#src/commands/reviewCommand.js';
5
+ import { slothContext } from '#src/config.js';
6
+ import { getSlothVersion } from '#src/utils.js';
7
+ import { argv, readStdin } from '#src/systemUtils.js';
8
+ import { setVerbose } from '#src/llmUtils.js';
9
+ const program = new Command();
10
+ program
11
+ .name('gsloth')
12
+ .description('Gaunt Sloth Assistant reviewing your PRs')
13
+ .version(getSlothVersion())
14
+ .option('--verbose', 'Print entire prompt sent to LLM.');
15
+ // Parse global options before binding any commands
16
+ program.parseOptions(argv);
17
+ if (program.getOptionValue('verbose')) {
18
+ // Set global prompt debug
19
+ setVerbose(true);
20
+ }
21
+ initCommand(program);
22
+ reviewCommand(program, slothContext);
23
+ askCommand(program);
24
+ // TODO add general interactive chat command
25
+ await readStdin(program);
26
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE9C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,QAAQ,CAAC;KACd,WAAW,CAAC,0CAA0C,CAAC;KACvD,OAAO,CAAC,eAAe,EAAE,CAAC;KAC1B,MAAM,CAAC,WAAW,EAAE,kCAAkC,CAAC,CAAC;AAE3D,mDAAmD;AACnD,OAAO,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;AAC3B,IAAI,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,EAAE,CAAC;IACtC,0BAA0B;IAC1B,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC;AAED,WAAW,CAAC,OAAO,CAAC,CAAC;AACrB,aAAa,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;AACrC,UAAU,CAAC,OAAO,CAAC,CAAC;AACpB,4CAA4C;AAE5C,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { BaseChatModel } from '@langchain/core/language_models/chat_models';
2
+ import { BaseLanguageModelCallOptions } from '@langchain/core/language_models/base';
3
+ export declare function invoke(llm: BaseChatModel, options: Partial<BaseLanguageModelCallOptions>, systemMessage: string, prompt: string): Promise<string>;
4
+ export declare function setVerbose(debug: boolean): void;
@@ -0,0 +1,39 @@
1
+ import { HumanMessage, SystemMessage } from '@langchain/core/messages';
2
+ import { END, MemorySaver, MessagesAnnotation, START, StateGraph } from '@langchain/langgraph';
3
+ const llmGlobalSettings = {
4
+ verbose: false,
5
+ };
6
+ export async function invoke(llm, options, systemMessage, prompt) {
7
+ if (llmGlobalSettings.verbose) {
8
+ llm.verbose = true;
9
+ }
10
+ // This node receives the current state (messages) and invokes the LLM
11
+ const callModel = async (state) => {
12
+ // state.messages will contain the list including the system systemMessage and user diff
13
+ const response = await llm.invoke(state.messages);
14
+ // MessagesAnnotation expects the node to return the new message(s) to be added to the state.
15
+ // Wrap the response in an array if it's a single message object.
16
+ return { messages: response };
17
+ };
18
+ // Define the graph structure with MessagesAnnotation state
19
+ const workflow = new StateGraph(MessagesAnnotation)
20
+ // Define the node and edge
21
+ .addNode('model', callModel)
22
+ .addEdge(START, 'model') // Start at the 'model' node
23
+ .addEdge('model', END); // End after the 'model' node completes
24
+ // Set up memory (optional but good practice for potential future multi-turn interactions)
25
+ const memory = new MemorySaver();
26
+ // Compile the workflow into a runnable app
27
+ const app = workflow.compile({ checkpointer: memory });
28
+ // Construct the initial the messages including the systemMessage as a system message
29
+ const messages = [new SystemMessage(systemMessage), new HumanMessage(prompt)];
30
+ const output = await app.invoke({ messages }, options);
31
+ const lastMessage = output.messages[output.messages.length - 1];
32
+ return typeof lastMessage.content === 'string'
33
+ ? lastMessage.content
34
+ : JSON.stringify(lastMessage.content);
35
+ }
36
+ export function setVerbose(debug) {
37
+ llmGlobalSettings.verbose = debug;
38
+ }
39
+ //# sourceMappingURL=llmUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"llmUtils.js","sourceRoot":"","sources":["../src/llmUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAkB,YAAY,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAEvF,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,kBAAkB,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAG/F,MAAM,iBAAiB,GAAG;IACxB,OAAO,EAAE,KAAK;CACf,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,GAAkB,EAClB,OAA8C,EAC9C,aAAqB,EACrB,MAAc;IAEd,IAAI,iBAAiB,CAAC,OAAO,EAAE,CAAC;QAC9B,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC;IACrB,CAAC;IACD,sEAAsE;IACtE,MAAM,SAAS,GAAG,KAAK,EAAE,KAAY,EAAyC,EAAE;QAC9E,wFAAwF;QACxF,MAAM,QAAQ,GAAG,MAAO,GAAqB,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACrE,6FAA6F;QAC7F,iEAAiE;QACjE,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;IAChC,CAAC,CAAC;IAEF,2DAA2D;IAC3D,MAAM,QAAQ,GAAG,IAAI,UAAU,CAAC,kBAAkB,CAAC;QACjD,2BAA2B;SAC1B,OAAO,CAAC,OAAO,EAAE,SAAS,CAAC;SAC3B,OAAO,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,4BAA4B;SACpD,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,uCAAuC;IAEjE,0FAA0F;IAC1F,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;IAEjC,2CAA2C;IAC3C,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAAC;IAEvD,qFAAqF;IACrF,MAAM,QAAQ,GAAc,CAAC,IAAI,aAAa,CAAC,aAAa,CAAC,EAAE,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IAEzF,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,OAAO,CAAC,CAAC;IACvD,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAChE,OAAO,OAAO,WAAW,CAAC,OAAO,KAAK,QAAQ;QAC5C,CAAC,CAAC,WAAW,CAAC,OAAO;QACrB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,iBAAiB,CAAC,OAAO,GAAG,KAAK,CAAC;AACpC,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Ask a question and get an answer from the LLM
3
+ * @param source - The source of the question (used for file naming)
4
+ * @param preamble - The preamble to send to the LLM
5
+ * @param content - The content of the question
6
+ */
7
+ export declare function askQuestion(source: string, preamble: string, content: string): Promise<void>;
@@ -0,0 +1,33 @@
1
+ import { slothContext } from '#src/config.js';
2
+ import { display, displayError, displaySuccess } from '#src/consoleUtils.js';
3
+ import { getCurrentDir } from '#src/systemUtils.js';
4
+ import { fileSafeLocalDate, ProgressIndicator, toFileSafeString } from '#src/utils.js';
5
+ import { writeFileSync } from 'node:fs';
6
+ import * as path from 'node:path';
7
+ import { invoke } from '#src/llmUtils.js';
8
+ /**
9
+ * Ask a question and get an answer from the LLM
10
+ * @param source - The source of the question (used for file naming)
11
+ * @param preamble - The preamble to send to the LLM
12
+ * @param content - The content of the question
13
+ */
14
+ export async function askQuestion(source, preamble, content) {
15
+ const progressIndicator = new ProgressIndicator('Thinking.');
16
+ const outputContent = await invoke(slothContext.config.llm, slothContext.session, preamble, content);
17
+ progressIndicator.stop();
18
+ const filePath = path.resolve(getCurrentDir(), toFileSafeString(source) + '-' + fileSafeLocalDate() + '.md');
19
+ display(`\nwriting ${filePath}`);
20
+ // TODO highlight LLM output with something like Prism.JS (maybe system emoj are enough ✅⚠️❌)
21
+ display('\n' + outputContent);
22
+ try {
23
+ writeFileSync(filePath, outputContent);
24
+ displaySuccess(`This report can be found in ${filePath}`);
25
+ }
26
+ catch (error) {
27
+ displayError(`Failed to write answer to file: ${filePath}`);
28
+ displayError(error instanceof Error ? error.message : String(error));
29
+ // TODO Consider if we want to exit or just log the error
30
+ // exit(1);
31
+ }
32
+ }
33
+ //# sourceMappingURL=questionAnsweringModule.js.map
@@ -0,0 +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,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,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;IAC7D,MAAM,aAAa,GAAG,MAAM,MAAM,CAChC,YAAY,CAAC,MAAM,CAAC,GAAG,EACvB,YAAY,CAAC,OAAO,EACpB,QAAQ,EACR,OAAO,CACR,CAAC;IACF,iBAAiB,CAAC,IAAI,EAAE,CAAC;IACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAC3B,aAAa,EAAE,EACf,gBAAgB,CAAC,MAAM,CAAC,GAAG,GAAG,GAAG,iBAAiB,EAAE,GAAG,KAAK,CAC7D,CAAC;IACF,OAAO,CAAC,aAAa,QAAQ,EAAE,CAAC,CAAC;IACjC,6FAA6F;IAC7F,OAAO,CAAC,IAAI,GAAG,aAAa,CAAC,CAAC;IAC9B,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"}
@@ -0,0 +1 @@
1
+ export declare function review(source: string, preamble: string, diff: string): Promise<void>;
@@ -0,0 +1,29 @@
1
+ import { slothContext } from '#src/config.js';
2
+ import { display, displayDebug, displayError, displaySuccess } from '#src/consoleUtils.js';
3
+ import { getCurrentDir, stdout } from '#src/systemUtils.js';
4
+ import { fileSafeLocalDate, ProgressIndicator, toFileSafeString } from '#src/utils.js';
5
+ import { writeFileSync } from 'node:fs';
6
+ import path from 'node:path';
7
+ import { invoke } from '#src/llmUtils.js';
8
+ export async function review(source, preamble, diff) {
9
+ const progressIndicator = new ProgressIndicator('Reviewing.');
10
+ const outputContent = await invoke(slothContext.config.llm, slothContext.session, preamble, diff);
11
+ progressIndicator.stop();
12
+ const filePath = path.resolve(getCurrentDir(), toFileSafeString(source) + '-' + fileSafeLocalDate() + '.md');
13
+ stdout.write('\n');
14
+ display(`writing ${filePath}`);
15
+ stdout.write('\n');
16
+ // TODO highlight LLM output with something like Prism.JS (maybe system emoj are enough ✅⚠️❌)
17
+ display(outputContent);
18
+ try {
19
+ writeFileSync(filePath, outputContent);
20
+ displaySuccess(`This report can be found in ${filePath}`);
21
+ }
22
+ catch (error) {
23
+ displayDebug(error instanceof Error ? error : String(error));
24
+ displayError(`Failed to write review to file: ${filePath}`);
25
+ // Consider if you want to exit or just log the error
26
+ // exit(1);
27
+ }
28
+ }
29
+ //# sourceMappingURL=reviewModule.js.map
@@ -0,0 +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,aAAa,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACvF,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,MAAc,EAAE,QAAgB,EAAE,IAAY;IACzE,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAC9D,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IAClG,iBAAiB,CAAC,IAAI,EAAE,CAAC;IACzB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAC3B,aAAa,EAAE,EACf,gBAAgB,CAAC,MAAM,CAAC,GAAG,GAAG,GAAG,iBAAiB,EAAE,GAAG,KAAK,CAC7D,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnB,OAAO,CAAC,WAAW,QAAQ,EAAE,CAAC,CAAC;IAC/B,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnB,6FAA6F;IAC7F,OAAO,CAAC,aAAa,CAAC,CAAC;IACvB,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"}
@@ -0,0 +1,18 @@
1
+ import type { BaseMessage } from '@langchain/core/messages';
2
+ export type Message = BaseMessage;
3
+ export interface State {
4
+ messages: Message[];
5
+ }
6
+ export interface ProgressCallback {
7
+ (): void;
8
+ }
9
+ export interface ReviewOptions {
10
+ source: string;
11
+ preamble: string;
12
+ diff: string;
13
+ }
14
+ export interface QuestionOptions {
15
+ source: string;
16
+ preamble: string;
17
+ content: string;
18
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/modules/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,8 @@
1
+ export declare function readBackstory(): string;
2
+ export declare function readGuidelines(guidelinesFilename: string): string;
3
+ export declare function readReviewInstructions(reviewInstructions: string): string;
4
+ /**
5
+ * This function expects https://cli.github.com/ to be installed and authenticated.
6
+ * It does something like `gh pr diff 42`
7
+ */
8
+ export declare function getPrDiff(pr: string): Promise<string>;
package/dist/prompt.js ADDED
@@ -0,0 +1,45 @@
1
+ import { readFileFromCurrentDir, readFileFromCurrentOrInstallDir, spawnCommand, } from '#src/utils.js';
2
+ import { displayError } from '#src/consoleUtils.js';
3
+ import { exit } from '#src/systemUtils.js';
4
+ import { GSLOTH_BACKSTORY } from '#src/config.js';
5
+ export function readBackstory() {
6
+ return readFileFromCurrentOrInstallDir(GSLOTH_BACKSTORY, true);
7
+ }
8
+ export function readGuidelines(guidelinesFilename) {
9
+ try {
10
+ return readFileFromCurrentDir(guidelinesFilename);
11
+ }
12
+ catch (error) {
13
+ displayError('Consider running `gsloth init` to set up your project. Check `gsloth init --help` to see options.');
14
+ throw error;
15
+ }
16
+ }
17
+ export function readReviewInstructions(reviewInstructions) {
18
+ return readConfigPromptFile(reviewInstructions);
19
+ }
20
+ function readConfigPromptFile(guidelinesFilename) {
21
+ try {
22
+ return readFileFromCurrentOrInstallDir(guidelinesFilename);
23
+ }
24
+ catch (error) {
25
+ displayError('Consider running `gsloth init` to set up your project. Check `gsloth init --help` to see options.');
26
+ throw error;
27
+ }
28
+ }
29
+ /**
30
+ * This function expects https://cli.github.com/ to be installed and authenticated.
31
+ * It does something like `gh pr diff 42`
32
+ */
33
+ export async function getPrDiff(pr) {
34
+ // TODO makes sense to check if gh is available and authenticated
35
+ try {
36
+ return await spawnCommand('gh', ['pr', 'diff', pr], 'Loading PR diff...', 'Loaded PR diff.');
37
+ }
38
+ catch (e) {
39
+ displayError(e instanceof Error ? e.toString() : String(e));
40
+ displayError(`Failed to call "gh pr diff ${pr}", see message above for details.`);
41
+ exit();
42
+ return ''; // This line will never be reached due to exit()
43
+ }
44
+ }
45
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,+BAA+B,EAC/B,YAAY,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,UAAU,aAAa;IAC3B,OAAO,+BAA+B,CAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,kBAA0B;IACvD,IAAI,CAAC;QACH,OAAO,sBAAsB,CAAC,kBAAkB,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,YAAY,CACV,mGAAmG,CACpG,CAAC;QACF,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,kBAA0B;IAC/D,OAAO,oBAAoB,CAAC,kBAAkB,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,oBAAoB,CAAC,kBAA0B;IACtD,IAAI,CAAC;QACH,OAAO,+BAA+B,CAAC,kBAAkB,CAAC,CAAC;IAC7D,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,YAAY,CACV,mGAAmG,CACpG,CAAC;QACF,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,EAAU;IACxC,iEAAiE;IACjE,IAAI,CAAC;QACH,OAAO,MAAM,YAAY,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,oBAAoB,EAAE,iBAAiB,CAAC,CAAC;IAC/F,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,YAAY,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5D,YAAY,CAAC,8BAA8B,EAAE,mCAAmC,CAAC,CAAC;QAClF,IAAI,EAAE,CAAC;QACP,OAAO,EAAE,CAAC,CAAC,gDAAgD;IAC7D,CAAC;AACH,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ProviderConfig } from './types.js';
2
+ /**
3
+ * Reads the text file from current dir
4
+ * @param _ config (unused in this provider)
5
+ * @param fileName
6
+ * @returns file contents
7
+ */
8
+ export declare function get(_: ProviderConfig | null, fileName: string | undefined): Promise<string | null>;
@@ -0,0 +1,20 @@
1
+ import { resolve } from 'node:path';
2
+ import { display } from '#src/consoleUtils.js';
3
+ import { readFileSyncWithMessages } from '#src/utils.js';
4
+ import { getCurrentDir } from '#src/systemUtils.js';
5
+ /**
6
+ * Reads the text file from current dir
7
+ * @param _ config (unused in this provider)
8
+ * @param fileName
9
+ * @returns file contents
10
+ */
11
+ export async function get(_, fileName) {
12
+ if (!fileName) {
13
+ return null;
14
+ }
15
+ const currentDir = getCurrentDir();
16
+ const filePath = resolve(currentDir, fileName);
17
+ display(`Reading file ${fileName}...`);
18
+ return readFileSyncWithMessages(filePath);
19
+ }
20
+ //# sourceMappingURL=file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.js","sourceRoot":"","sources":["../../src/providers/file.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGpD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,CAAwB,EACxB,QAA4B;IAE5B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;IACnC,MAAM,QAAQ,GAAG,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAC/C,OAAO,CAAC,gBAAgB,QAAQ,KAAK,CAAC,CAAC;IACvC,OAAO,wBAAwB,CAAC,QAAQ,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ProviderConfig } from './types.js';
2
+ /**
3
+ * Gets PR diff using gh command line tool
4
+ * @param _ config (unused in this provider)
5
+ * @param pr PR number
6
+ * @returns PR diff
7
+ */
8
+ export declare function get(_: ProviderConfig | null, pr: string | undefined): Promise<string | null>;
@@ -0,0 +1,16 @@
1
+ import { displayWarning } from '#src/consoleUtils.js';
2
+ import { execAsync } from '#src/utils.js';
3
+ /**
4
+ * Gets PR diff using gh command line tool
5
+ * @param _ config (unused in this provider)
6
+ * @param pr PR number
7
+ * @returns PR diff
8
+ */
9
+ export async function get(_, pr) {
10
+ if (!pr) {
11
+ displayWarning('No PR provided');
12
+ return null;
13
+ }
14
+ return execAsync(`gh pr diff ${pr}`);
15
+ }
16
+ //# sourceMappingURL=ghPrDiffProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ghPrDiffProvider.js","sourceRoot":"","sources":["../../src/providers/ghPrDiffProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAG1C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,CAAwB,EACxB,EAAsB;IAEtB,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,cAAc,CAAC,gBAAgB,CAAC,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,SAAS,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;AACvC,CAAC"}
@@ -0,0 +1,8 @@
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>;
@@ -0,0 +1,62 @@
1
+ import { displayError, displayWarning } from "#src/consoleUtils.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 async function get(config, issueId) {
9
+ if (!config) {
10
+ displayWarning("No Jira config provided");
11
+ return null;
12
+ }
13
+ if (!issueId) {
14
+ displayWarning("No issue ID provided");
15
+ return null;
16
+ }
17
+ if (!config.username) {
18
+ displayWarning("No Jira username provided");
19
+ return null;
20
+ }
21
+ if (!config.baseUrl) {
22
+ displayWarning("No Jira base URL provided");
23
+ return null;
24
+ }
25
+ if (!config.token) {
26
+ displayWarning("No Jira token provided");
27
+ return null;
28
+ }
29
+ try {
30
+ const issue = await getJiraIssue(config, issueId);
31
+ if (!issue) {
32
+ return null;
33
+ }
34
+ const summary = issue.fields.summary;
35
+ const description = issue.fields.description;
36
+ return `Jira Issue: ${issueId}\nSummary: ${summary}\n\nDescription:\n${description}`;
37
+ }
38
+ catch (error) {
39
+ displayError(`Failed to get Jira issue: ${error instanceof Error ? error.message : String(error)}`);
40
+ return null;
41
+ }
42
+ }
43
+ /**
44
+ * Helper function to get Jira issue details
45
+ * @param config Jira configuration
46
+ * @param issueId Jira issue ID
47
+ * @returns Jira issue response
48
+ */
49
+ async function getJiraIssue(config, issueId) {
50
+ const auth = Buffer.from(`${config.username}:${config.token}`).toString('base64');
51
+ const response = await fetch(`${config.baseUrl}/rest/api/2/issue/${issueId}`, {
52
+ headers: {
53
+ 'Authorization': `Basic ${auth}`,
54
+ 'Accept': 'application/json'
55
+ }
56
+ });
57
+ if (!response.ok) {
58
+ throw new Error(`Failed to fetch Jira issue: ${response.statusText}`);
59
+ }
60
+ return response.json();
61
+ }
62
+ //# sourceMappingURL=jiraIssueLegacyAccessTokenProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jiraIssueLegacyAccessTokenProvider.js","sourceRoot":"","sources":["../../src/providers/jiraIssueLegacyAccessTokenProvider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAYpE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,MAAyB,EAAE,OAA2B;IAC5E,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,cAAc,CAAC,yBAAyB,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,cAAc,CAAC,sBAAsB,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACnB,cAAc,CAAC,2BAA2B,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QAClB,cAAc,CAAC,2BAA2B,CAAC,CAAC;QAC5C,OAAO,IAAI,CAAC;IAChB,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAChB,cAAc,CAAC,wBAAwB,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,CAAC,KAAK,EAAE,CAAC;YACT,OAAO,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC;QACrC,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC;QAE7C,OAAO,eAAe,OAAO,cAAc,OAAO,qBAAqB,WAAW,EAAE,CAAC;IACzF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,YAAY,CAAC,6BAA6B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACpG,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,YAAY,CAAC,MAAkB,EAAE,OAAe;IAC3D,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAClF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,OAAO,qBAAqB,OAAO,EAAE,EAAE;QAC1E,OAAO,EAAE;YACL,eAAe,EAAE,SAAS,IAAI,EAAE;YAChC,QAAQ,EAAE,kBAAkB;SAC/B;KACJ,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,+BAA+B,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IAC1E,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { JiraLegacyConfig } from '#src/providers/types.js';
2
+ /**
3
+ * Gets Jira issue using Atlassian REST API v2 with unscoped API token (aka Legacy Token)
4
+ * @param config Jira configuration
5
+ * @param issueId Jira issue ID
6
+ * @returns Jira issue content
7
+ */
8
+ export declare function get(config: Partial<JiraLegacyConfig>, issueId: string | undefined): Promise<string | null>;
@@ -0,0 +1,74 @@
1
+ import { display, displayError, displayWarning } from '#src/consoleUtils.js';
2
+ import { env } from '#src/systemUtils.js';
3
+ /**
4
+ * Gets Jira issue using Atlassian REST API v2 with unscoped API token (aka Legacy Token)
5
+ * @param config Jira configuration
6
+ * @param issueId Jira issue ID
7
+ * @returns Jira issue content
8
+ */
9
+ export async function get(config, issueId) {
10
+ if (!config) {
11
+ displayWarning('No Jira config provided');
12
+ return null;
13
+ }
14
+ if (!issueId) {
15
+ displayWarning('No issue ID provided');
16
+ return null;
17
+ }
18
+ if (!config.baseUrl) {
19
+ displayWarning('No Jira base URL provided');
20
+ return null;
21
+ }
22
+ // Get username from environment variable or config
23
+ const username = env.JIRA_USERNAME || config.username;
24
+ if (!username) {
25
+ throw new Error('Missing JIRA username. The username can be defined as JIRA_USERNAME environment variable or as "username" in config.');
26
+ }
27
+ // Get token from environment variable or config
28
+ const token = env.JIRA_LEGACY_API_TOKEN || config.token;
29
+ if (!token) {
30
+ throw new Error('Missing JIRA Legacy API token. The legacy token can be defined as JIRA_LEGACY_API_TOKEN environment variable or as "token" in config.');
31
+ }
32
+ try {
33
+ const issue = await getJiraIssue({
34
+ ...config,
35
+ username,
36
+ token,
37
+ }, issueId);
38
+ if (!issue) {
39
+ return null;
40
+ }
41
+ const summary = issue.fields.summary;
42
+ const description = issue.fields.description;
43
+ return `Jira Issue: ${issueId}\nSummary: ${summary}\n\nDescription:\n${description}`;
44
+ }
45
+ catch (error) {
46
+ displayError(`Failed to get Jira issue: ${error instanceof Error ? error.message : String(error)}`);
47
+ return null;
48
+ }
49
+ }
50
+ /**
51
+ * Helper function to get Jira issue details
52
+ * @param config Jira configuration
53
+ * @param issueId Jira issue ID
54
+ * @returns Jira issue response
55
+ */
56
+ async function getJiraIssue(config, issueId) {
57
+ const auth = Buffer.from(`${config.username}:${config.token}`).toString('base64');
58
+ const url = `${config.baseUrl}${issueId}`;
59
+ if (config.displayUrl) {
60
+ display(`Loading Jira issue ${config.displayUrl}${issueId}`);
61
+ }
62
+ display(`Retrieving jira from api ${url.replace(/^https?:\/\//, '')}`);
63
+ const response = await fetch(url, {
64
+ headers: {
65
+ Authorization: `Basic ${auth}`,
66
+ Accept: 'application/json',
67
+ },
68
+ });
69
+ if (!response.ok) {
70
+ throw new Error(`Failed to fetch Jira issue from ${url} with status: ${response.statusText}`);
71
+ }
72
+ return response.json();
73
+ }
74
+ //# sourceMappingURL=jiraIssueLegacyProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jiraIssueLegacyProvider.js","sourceRoot":"","sources":["../../src/providers/jiraIssueLegacyProvider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { JiraConfig } from './types.js';
2
+ /**
3
+ * Gets Jira issue using Atlassian REST API v3 with Personal Access Token
4
+ *
5
+ * TODO we need to figure out how would this work with public jira.
6
+ *
7
+ * @param config Jira configuration
8
+ * @param issueId Jira issue ID
9
+ * @returns Jira issue content
10
+ */
11
+ export declare function get(config: Partial<JiraConfig> | null, issueId: string | undefined): Promise<string | null>;