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
@@ -0,0 +1,292 @@
1
+ Okay, let's examine this diff.
2
+
3
+ ## Code Review
4
+
5
+ ### `.gitignore`
6
+ * `+ /gth-*`
7
+ * ✅ **Suggestion:** Adding `gth-*` to `.gitignore` is a good practice if these are generated files (e.g., output from the tool, which seems to be the case with the prefix change from `sloth-*` to `gth-*`). This prevents accidental commits of transient data.
8
+
9
+ ### `.gsloth.guidelines.md` & `.gsloth.review.md`
10
+ * The changes in `.gsloth.guidelines.md` remove instructions for *me* (the reviewer bot) from the guidelines file.
11
+ * The new file `.gsloth.review.md` now contains these instructions.
12
+ * ✅ **Observation:** This is a sensible refactoring to separate the project's code review guidelines from the instructions for the AI reviewer.
13
+
14
+ ### `README.md` & `docs/CONFIGURATION.md`
15
+ * `s/.gsloth.preamble.review.md/.gsloth.guidelines.md/g`
16
+ * ✅ **Documentation:** The documentation has been updated to reflect the renaming of the primary user-provided guidelines file from `.gsloth.preamble.review.md` to `.gsloth.guidelines.md`. This is consistent with other changes.
17
+
18
+ ### `spec/askCommand.spec.ts`
19
+ * **Mocking Strategy:**
20
+ * The mocking strategy has been changed from using `vi.hoisted()` and a `ctx` object to defining mocks at the top level and using `vi.mock()`.
21
+ * ✅ **Suggestion:** This is generally a cleaner and more standard way to handle mocks in Vitest. It improves readability.
22
+ * **Preamble/Guideline Handling:**
23
+ * `ctx.prompt.readInternalPreamble.mockReturnValue('INTERNAL PREAMBLE');` changed to:
24
+ ```typescript
25
+ prompt.readBackstory.mockReturnValue('INTERNAL PREAMBLE');
26
+ prompt.readGuidelines.mockReturnValue('PROJECT GUIDELINES');
27
+ ```
28
+ * The `askQuestion` mock is now expected to be called with a combined preamble: `'INTERNAL PREAMBLE\nPROJECT GUIDELINES'`.
29
+ * ✅ **Correctness:** This aligns with the changes in `src/commands/askCommand.ts` where both backstory and project guidelines are now read and combined.
30
+ * **Output File Prefix:**
31
+ * `expect(ctx.questionAnsweringModule.askQuestion).toHaveBeenCalledWith('sloth-ASK', ...)` changed to `expect(askQuestion).toHaveBeenCalledWith('gth-ASK', ...)`.
32
+ * ✅ **Correctness:** Reflects the change in the default output file prefix.
33
+ * **General Test Logic:**
34
+ * The tests correctly adapt to the new way preambles are constructed and the new output prefix.
35
+ * ✅ **Test Coverage:** The tests cover cases with a message only, with a single file, and with multiple files.
36
+
37
+ ### `spec/config.spec.ts`
38
+ * **New Default Config Values:**
39
+ * Tests now expect `projectGuidelines: '.gsloth.guidelines.md'` and `projectReviewInstructions: '.gsloth.review.md'` in the default configuration.
40
+ * ✅ **Correctness:** This is consistent with the introduction of these new configuration options and their default file names.
41
+ * **Type Safety:**
42
+ * The tests for various LLM configurations (`vertexai`, `anthropic`, `groq`) correctly include these new default string properties.
43
+ * ✅ **Consistency:** Ensures that all configuration paths are tested with the new defaults.
44
+
45
+ ### `spec/initCommand.spec.ts`
46
+ * `USER_PROJECT_REVIEW_PREAMBLE: '.gsloth.preamble.review.md'` changed to `USER_PROJECT_REVIEW_PREAMBLE: '.gsloth.guidelines.md'`.
47
+ * ✅ **Correctness:** The test mock for `config.js` now uses the updated constant name for the project guidelines file, aligning with the changes in `src/config.ts`.
48
+
49
+ ### `spec/llmUtils.spec.ts`
50
+ * This is a new test file for the new `src/llmUtils.ts`.
51
+ * **`invoke` Function Test:**
52
+ * It tests the `invoke` function with a `FakeListChatModel`.
53
+ * It correctly mocks the `SlothContext` (though it's simplified for this test, which is acceptable for a unit test of `invoke`).
54
+ * The test verifies that the `invoke` function returns the content of the first LLM message.
55
+ * ⚠️ **Suggestion:** The test for `invoke` is quite basic. It checks if *a* message is returned. It might be beneficial to also assert:
56
+ * That the `llm.invoke` method was called with the correct `SystemMessage` and `HumanMessage` constructed from the input `systemMessage` and `prompt`.
57
+ * That the `options` (like `configurable: { thread_id: ... }`) are passed through to the LangGraph app invocation.
58
+ * If `llm.verbose` is set when `llmGlobalSettings.verbose` is true (though this might be better as a separate test for `setVerbose`'s effect).
59
+ * The removal of `SlothContext` type import is fine as the test constructs a minimal context.
60
+ * ✅ **Unit Test:** A good starting point for testing the core LLM invocation logic.
61
+
62
+ ### `spec/questionAnsweringModule.spec.ts`
63
+ * **Refactoring:**
64
+ * The test for `askQuestionInner` has been removed, which is correct as this function was inlined/refactored into `llmUtils.invoke`.
65
+ * **`ProgressIndicator` Mocking:**
66
+ * `utilsMock.ProgressIndicator.prototype.stop = vi.fn();`
67
+ * `utilsMock.ProgressIndicator.prototype.indicate = vi.fn();`
68
+ * ✅ **Correctness:** Mocks the new `stop()` method and the existing `indicate()` method of the `ProgressIndicator`.
69
+ * **Output File Prefix:**
70
+ * `utilsMock.toFileSafeString.mockReturnValue('sloth-ASK');` changed to `utilsMock.toFileSafeString.mockReturnValue('gth-ASK');`.
71
+ * `pathMock.resolve` mock adapted accordingly.
72
+ * ✅ **Correctness:** Aligns with the prefix change.
73
+ * **`invoke` Call:**
74
+ * The tests now implicitly test the `invoke` function via `askQuestion`.
75
+ * **Error Handling:**
76
+ * The test for file write errors remains and is still relevant.
77
+ * ✅ **Test Coverage:** Ensures that `displayError` is called and `ProgressIndicator.stop()` is called in error scenarios.
78
+
79
+ ### `spec/reviewCommand.spec.ts`
80
+ * **Preamble/Guideline Handling:**
81
+ * Mocks for `prompt.readInternalPreamble` and `prompt.readPreamble` are replaced with mocks for `prompt.readBackstory`, `prompt.readGuidelines`, and `prompt.readReviewInstructions`.
82
+ * The expected combined preamble string reflects this change: `'INTERNAL BACKSTORY\nPROJECT GUIDELINES\nREVIEW INSTRUCTIONS'`.
83
+ * ✅ **Correctness:** Aligns with changes in `src/commands/reviewCommand.ts`.
84
+ * **Output File Prefix:**
85
+ * `sloth-DIFF-review` to `gth-DIFF-review`.
86
+ * `sloth-PR-123-review` to `gth-PR-123-review`.
87
+ * ✅ **Correctness:** Reflects the prefix change.
88
+ * **`stdin` Handling:**
89
+ * The tests involving `stdin` (e.g., "Should call review with stdin content") have been updated. The way `slothContext` is mocked for these tests has changed slightly (e.g., removing `stdin: ''` from the direct mock of `slothContext` as it's now handled by `systemUtils.getStringFromStdin`).
90
+ * ⚠️ **Attention:** The tests for `stdin` now rely on the global `slothContext` from `#src/config.js`. While this works, it makes the tests less isolated. It might be cleaner to mock `getStringFromStdin` from `#src/systemUtils.js` directly within these specific tests if the goal is to unit test the command's logic independent of the `systemUtils` implementation. However, given the current structure, this is functional.
91
+ * **`SlothContext` Mocking:**
92
+ * The way `SlothContext` is constructed for tests involving specific providers (like Jira) has been updated. It now casts a partial `SlothConfig` to `SlothConfig`. This is a common pattern in testing.
93
+ * ✅ **Test Setup:** The setup for different content/requirements providers seems correct and adapted to the changes.
94
+
95
+ ### `spec/reviewModule.spec.ts`
96
+ * **Refactoring:**
97
+ * The test for `reviewInner` is removed, consistent with its refactoring.
98
+ * **New Mocks:**
99
+ * Extensive mocking for `fs`, `path`, `systemUtils`, `consoleUtils`, `utils`, and the new `llmUtils`.
100
+ * ✅ **Thoroughness:** Good setup for testing the `review` function in isolation.
101
+ * **`llmUtils.invoke` Mocking:**
102
+ * `llmUtilsMock.invoke.mockResolvedValue('LLM Review Response');`
103
+ * The test verifies that `llmUtils.invoke` is called with the correct parameters.
104
+ * ✅ **Correctness:** This is the primary integration point with the new LLM utility.
105
+ * **File Operations:**
106
+ * Verifies `fs.writeFileSync` is called with the correct path and content.
107
+ * Tests error handling for `writeFileSync`.
108
+ * ✅ **Robustness:** Covers success and failure paths for file writing.
109
+ * **`ProgressIndicator`:**
110
+ * Verifies `ProgressIndicator.prototype.stop` is called.
111
+ * ✅ **Correctness:** Ensures progress indication is properly managed.
112
+ * **Output File Prefix:**
113
+ * `utilsMock.toFileSafeString.mockReturnValue('gth-REVIEW');`
114
+ * ✅ **Correctness:** Aligns with prefix change.
115
+
116
+ ### `src/commands/askCommand.ts`
117
+ * **Preamble/Guideline Reading:**
118
+ * `readInternalPreamble()` changed to `readBackstory()` and `readGuidelines(slothContext.config.projectGuidelines)`.
119
+ * The preamble is now a combination of these two.
120
+ * ✅ **Logic Change:** Correctly implements the new way of constructing the system message for the LLM.
121
+ * **Output File Prefix:**
122
+ * `sloth-ASK` changed to `gth-ASK`.
123
+ * `// TODO make the prefix configurable`
124
+ * ✅ **Enhancement Noted:** Good that this is marked as a TODO.
125
+ * **`slothContext` Usage:**
126
+ * Uses `slothContext.config.projectGuidelines` to fetch the guidelines file path.
127
+ * ✅ **Configuration:** Correctly uses the configured path.
128
+
129
+ ### `src/commands/reviewCommand.ts`
130
+ * **Preamble/Guideline Reading:**
131
+ * Similar to `askCommand`, it now uses `readBackstory()`, `readGuidelines(slothContext.config.projectGuidelines)`, and `readReviewInstructions(slothContext.config.projectReviewInstructions)`.
132
+ * ✅ **Logic Change:** Correctly implements the new system message construction.
133
+ * **`stdin` Handling:**
134
+ * `if (context.stdin)` changed to `let stringFromStdin = getStringFromStdin(); if (stringFromStdin)`.
135
+ * ✅ **Refactoring:** Uses the new centralized way to get stdin content via `getStringFromStdin` from `systemUtils.ts`. This is a good separation of concerns.
136
+ * **Output File Prefix:**
137
+ * `sloth-DIFF-review` to `gth-DIFF-review`.
138
+ * `sloth-PR-${prId}-review` to `gth-PR-${prId}-review`.
139
+ * `// TODO make the prefix configurable`
140
+ * `// TODO consider including requirements id`
141
+ * `// TODO sanitize prId`
142
+ * ✅ **Enhancements Noted:** Important TODOs, especially sanitizing `prId` for file system safety.
143
+ * **`SlothContext` Usage:**
144
+ * The command no longer takes `context: SlothContext` as a direct argument to the main action but uses the global `slothContext` for config values. The `program.command().action()` still receives `context` from Commander, but it's not the `SlothContext` we define. This is a subtle but important change. The `reviewCommand` function signature itself still takes `context: SlothContext` but it's the global one.
145
+ * ⚠️ **Clarity/Potential Confusion:** The `context` parameter in `reviewCommand(program: Command, context: SlothContext)` refers to the global `slothContext`. Inside the `.action(async (contentId: string | undefined, options: ReviewCommandOptions) => { ... })`, if `context` were used, it would be Commander's context. The code correctly uses the global `slothContext` from import. This is fine, but worth noting the distinction.
146
+
147
+ ### `src/config.ts`
148
+ * **New Config Properties:**
149
+ * `projectGuidelines: string;`
150
+ * `projectReviewInstructions: string;`
151
+ * ✅ **Feature:** Adds new configurable paths for different types of prompt files.
152
+ * **Type Change for `llm`:**
153
+ * `LanguageModelLike` to `BaseChatModel`.
154
+ * ✅ **Type Safety:** `BaseChatModel` is more specific and appropriate for chat-based interactions, which LangChain.js is heavily geared towards. This is a good refinement.
155
+ * **Removal of `stdin` from `SlothContext`:**
156
+ * `stdin: string;` removed.
157
+ * ✅ **Refactoring:** `stdin` is now handled by `systemUtils.ts`, which is a better place for system-level input.
158
+ * **New Constants and Default Values:**
159
+ * `PROJECT_GUIDELINES = '.gsloth.guidelines.md';`
160
+ * `PROJECT_REVIEW_INSTRUCTIONS = '.gsloth.review.md';`
161
+ * `USER_PROJECT_REVIEW_PREAMBLE` constant renamed/replaced by `PROJECT_GUIDELINES`.
162
+ * `DEFAULT_CONFIG` updated with these new properties.
163
+ * ✅ **Consistency:** All changes align with the new file naming and configuration structure.
164
+ * **`writeProjectReviewPreamble` function:**
165
+ * Now writes to `PROJECT_GUIDELINES` (formerly `USER_PROJECT_REVIEW_PREAMBLE`).
166
+ * The default content and warning messages are updated to reflect the new file name.
167
+ * ✅ **Correctness:** Updates initialization logic.
168
+ * **`reset` function:**
169
+ * `slothContext.stdin = '';` removed.
170
+ * ✅ **Correctness:** Consistent with `stdin` removal from context.
171
+
172
+ ### `src/configs/anthropic.ts` & `src/configs/vertexai.ts`
173
+ * **Type Change:**
174
+ * Return type of `processJsonConfig` changed from `Promise<LanguageModelLike>` to `Promise<BaseChatModel>`.
175
+ * ✅ **Type Safety:** Consistent with the type change in `SlothConfig`.
176
+
177
+ ### `src/index.ts`
178
+ * **New Global Option `--verbose`:**
179
+ * `program.option('--verbose', 'Print entire prompt sent to LLM.');`
180
+ * `program.parseOptions(argv);`
181
+ * `if (program.getOptionValue('verbose')) { setVerbose(true); }`
182
+ * ✅ **Feature:** Adds a useful debugging feature. Parsing options before command binding is correct for global options.
183
+ * **`readStdin` Import:**
184
+ * Imported from `systemUtils.js` instead of `utils.js`.
185
+ * ✅ **Refactoring:** Correctly reflects the move of this utility.
186
+
187
+ ### `src/llmUtils.ts`
188
+ * This is a new, crucial file.
189
+ * **`invoke` function:**
190
+ * Uses LangGraph (`StateGraph`, `MessagesAnnotation`, `MemorySaver`, `START`, `END`) to structure the LLM call.
191
+ * ✅ **Architecture:** Using LangGraph provides a structured way to manage conversations, even if it's a single turn for now. It allows for easier extension to multi-turn conversations or more complex flows later.
192
+ * Constructs `SystemMessage` and `HumanMessage`.
193
+ * Handles LLM invocation and extracts the content from the last `AIMessageChunk`.
194
+ * `llm.verbose = true;` if `llmGlobalSettings.verbose` is set.
195
+ * ✅ **Debugging:** Integrates the verbose option.
196
+ * ⚠️ **Error Handling:** The `invoke` function itself doesn't have explicit try-catch blocks for the `app.invoke` call. Errors from the LLM or graph execution would propagate up. This might be acceptable if handled by the callers (`askQuestion`, `review`), which they seem to do for file writing but not explicitly for the LLM call itself (though the `ProgressIndicator` might implicitly handle some visual feedback). Consider if more specific error handling or logging is needed directly within `invoke`.
197
+ * ⚠️ **MemorySaver:** `const memory = new MemorySaver();` is created for each `invoke` call. If the `thread_id` in `options` is intended to persist memory across calls *within the same command execution but different logical invocations* (which is not the current pattern but could be a future one), this `MemorySaver` instance would be new each time. For the current single-call-per-command structure, this is fine. If true multi-turn state persistence across separate CLI executions is desired, `MemorySaver` would need to be configured with a persistent checkpointer.
198
+ * **`setVerbose` function:**
199
+ * Sets a global flag for verbose LLM logging.
200
+ * ✅ **Utility:** Simple and effective.
201
+
202
+ ### `src/modules/questionAnsweringModule.ts`
203
+ * **Refactoring:**
204
+ * `askQuestionInner` removed.
205
+ * Now calls `invoke` from `llmUtils.ts`.
206
+ * ✅ **Abstraction:** Good use of the new utility function.
207
+ * **`ProgressIndicator` Usage:**
208
+ * `progressIndicator.stop();` is called after `invoke` completes.
209
+ * ✅ **Correctness:** Ensures the indicator is stopped.
210
+ * **Error Handling:**
211
+ * The existing `try-catch` for `writeFileSync` remains. Errors from `invoke` would propagate and potentially lead to an unhandled rejection if not caught by a higher-level mechanism (e.g., Node.js default behavior).
212
+ * ⚠️ **Robustness:** While file write errors are handled, consider if errors from the `invoke` call itself (e.g., API errors from the LLM) should be caught and presented more gracefully to the user, perhaps with a specific message before falling into the file write error or generic exit.
213
+
214
+ ### `src/modules/reviewModule.ts`
215
+ * **Refactoring:**
216
+ * `reviewInner` removed.
217
+ * Now calls `invoke` from `llmUtils.ts`.
218
+ * ✅ **Abstraction:** Good use of the new utility function.
219
+ * **`ProgressIndicator` Usage:**
220
+ * `progressIndicator.stop();` is called after `invoke` completes.
221
+ * ✅ **Correctness:** Ensures the indicator is stopped.
222
+ * **Error Handling:**
223
+ * Similar to `questionAnsweringModule`, file write errors are handled. Errors from `invoke` might not be specifically caught here.
224
+ * ⚠️ **Robustness:** Same consideration as for `questionAnsweringModule` regarding errors from `invoke`.
225
+
226
+ ### `src/prompt.ts`
227
+ * **Function Renaming and Logic Changes:**
228
+ * `readInternalPreamble` -> `readBackstory`. Now uses `readFileFromCurrentOrInstallDir`.
229
+ * `readPreamble` -> `readGuidelines`. Now uses `readFileFromCurrentDir` and has more specific error messaging.
230
+ * New `readReviewInstructions` function, uses `readConfigPromptFile` (which is `readFileFromCurrentOrInstallDir`).
231
+ * ✅ **Clarity & Flexibility:** The new function names are more descriptive. The use of `readFileFromCurrentOrInstallDir` for `readBackstory` and `readReviewInstructions` allows users to override these if needed, while `readGuidelines` enforces it from the current project directory. This seems like a reasonable design.
232
+ * **Error Handling:**
233
+ * The error messages are more specific and guide the user towards `gsloth init`.
234
+ * ✅ **User Experience:** Improved error guidance.
235
+
236
+ ### `src/systemUtils.ts`
237
+ * **New `getStringFromStdin()`:**
238
+ * Returns the cached `innerState.stringFromStdin`.
239
+ * ✅ **Utility:** Provides a clean way to access stdin content after it has been read.
240
+ * **`readStdin()` function:**
241
+ * Moved from `utils.ts`.
242
+ * Logic updated: `ProgressIndicator` is now instantiated with `manual = true` when reading stdin, and `indicate()` is called inside the `readable` event.
243
+ * It now populates `innerState.stringFromStdin` instead of `slothContext.stdin`.
244
+ * ✅ **Refactoring & Correctness:** This is a much cleaner way to handle stdin. The progress indication is more accurate. Storing it in `innerState` is good for encapsulation within this module.
245
+ * **`ProgressIndicator` in `readStdin`:**
246
+ * `const progressIndicator = new ProgressIndicator('reading STDIN', true);`
247
+ * `progressIndicator.indicate();`
248
+ * ⚠️ **Nitpick/Minor:** The `ProgressIndicator` in `readStdin` is not explicitly `stop()`-ed. Since `readStdin` resolves its promise after `program.parseAsync()` which happens on `stdin.on('end')`, the "reading STDIN" message with dots might remain on the screen if other operations are quick. It might be cleaner to call `progressIndicator.stop()` right before `resolvePromise()` in the `end` event handler. However, subsequent output will likely overwrite it, so it's a minor visual point.
249
+
250
+ ### `src/utils.ts`
251
+ * **Removal of `readStdin`:**
252
+ * Correctly removed as it's now in `systemUtils.ts`.
253
+ * **New `readFileFromCurrentOrInstallDir()`:**
254
+ * Tries to read from the current directory first, then falls back to the install directory.
255
+ * Includes logging about which path it's trying.
256
+ * ✅ **Utility & Robustness:** Useful function for accessing configuration/template files that can be overridden by the user.
257
+ * **`ProgressIndicator` Class Changes:**
258
+ * Constructor now takes an optional `manual` flag. If not manual, it starts an interval timer to print dots.
259
+ * `indicate()` method now throws an error if called in non-manual mode.
260
+ * New `stop()` method to clear the interval and print a newline.
261
+ * ✅ **Enhancement:** This makes the `ProgressIndicator` more versatile. The automatic dot printing is convenient for long-running async tasks where manual indication is cumbersome. The `stop()` method is crucial for cleaning up and ensuring the prompt is clean.
262
+ * **`spawnCommand` `ProgressIndicator`:**
263
+ * `const progressIndicator = new ProgressIndicator(progressMessage, true);`
264
+ * The `indicate()` calls within `spawnCommand` are now correct for the manual mode.
265
+ * `progressIndicator.stop()` is called in both `close` and `error` handlers.
266
+ * ✅ **Correctness:** Proper usage of the updated `ProgressIndicator`.
267
+
268
+ ## Overall Assessment
269
+
270
+ This is a substantial refactoring and feature addition. The changes are largely positive:
271
+
272
+ * **Improved Configuration:** More granular control over prompt files (`.gsloth.guidelines.md`, `.gsloth.review.md`).
273
+ * **Centralized LLM Logic:** The new `llmUtils.ts` with the `invoke` function using LangGraph is a significant architectural improvement. It centralizes LLM interaction and makes it easier to manage and extend.
274
+ * **Refined `stdin` Handling:** Moving `stdin` processing to `systemUtils.ts` and caching the result is cleaner.
275
+ * **Enhanced `ProgressIndicator`:** The utility is now more flexible.
276
+ * **Code Clarity:** Renaming of functions and constants (e.g., `readBackstory`, `PROJECT_GUIDELINES`) improves readability.
277
+ * **Type Safety:** Consistent use of `BaseChatModel` is good.
278
+ * **Test Updates:** Tests have been diligently updated to reflect the changes, and new tests for `llmUtils.ts` and `reviewModule.ts` have been added.
279
+
280
+ **Minor areas for consideration/improvement:**
281
+ * More detailed unit tests for `llmUtils.invoke` to assert message construction.
282
+ * Explicit error handling for LLM API calls within `invoke` or its callers (`reviewModule`, `questionAnsweringModule`) for more user-friendly error messages.
283
+ * Nitpick about `ProgressIndicator.stop()` in `systemUtils.readStdin`.
284
+ * The TODOs noted in the code (configurable prefix, sanitizing `prId`) are important for future work.
285
+
286
+ The developer has demonstrated a good understanding of the LangChain.js/LangGraph.js ecosystem and has applied it effectively. The code quality is high, and the changes are well-reasoned.
287
+
288
+ ## Recommendation
289
+
290
+ ✅ **Approve**
291
+
292
+ This PR introduces significant improvements to the tool's architecture, configurability, and maintainability. The changes are well-implemented and tested. The minor points raised are suggestions for further refinement rather than blocking issues.
package/index.js CHANGED
@@ -1,31 +1,14 @@
1
1
  #!/usr/bin/env node
2
- import { Command } from 'commander';
3
- import { dirname } from 'node:path';
4
- import { fileURLToPath } from "url";
5
- import { reviewCommand } from "./src/commands/reviewCommand.js";
6
- import { initCommand } from "./src/commands/initCommand.js";
7
- import { askCommand } from "./src/commands/askCommand.js";
8
- import { slothContext } from "./src/config.js";
9
- import { getSlothVersion, readStdin } from "./src/utils.js";
10
- import {getCurrentDir, getInstallDir, setInstallDir} from "./src/systemUtils.js";
11
2
 
12
- const program = new Command();
3
+ // This is a minimalistic entry point that sets the installDir in systemUtils
4
+ // and delegates to the compiled TypeScript code in dist/index.js
5
+ import { setEntryPoint } from './dist/systemUtils.js';
13
6
 
14
- setInstallDir(dirname(fileURLToPath(import.meta.url)));
15
- slothContext.currentDir = getCurrentDir();
16
- slothContext.installDir = getInstallDir();
7
+ // Set the installation directory in systemUtils
8
+ setEntryPoint(import.meta.url);
17
9
 
18
- program
19
- .name('gsloth')
20
- .description('Gaunt Sloth Assistant reviewing your PRs')
21
- .version(getSlothVersion());
22
-
23
- initCommand(program, slothContext);
24
-
25
- reviewCommand(program, slothContext)
26
-
27
- askCommand(program, slothContext);
28
-
29
- // TODO add general interactive chat command
30
-
31
- await readStdin(program);
10
+ // Import and run the compiled TypeScript code
11
+ import('./dist/index.js').catch((err) => {
12
+ console.error('Failed to load application:', err);
13
+ process.exit(1);
14
+ });
package/package.json CHANGED
@@ -1,41 +1,52 @@
1
1
  {
2
2
  "name": "gaunt-sloth-assistant",
3
- "version": "0.1.5",
3
+ "version": "0.3.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "author": "Andrew Kondratev",
7
7
  "type": "module",
8
- "main": "index.js",
8
+ "main": "dist/index.js",
9
9
  "repository": "github:andruhon/gaunt-sloth-assistant",
10
10
  "engines": {
11
11
  "node": ">=22.0.0",
12
12
  "npm": ">=10.9.0"
13
13
  },
14
14
  "scripts": {
15
- "test": "jasmine",
16
- "lint": "eslint"
15
+ "build": "tsc",
16
+ "test": "npm run build &&vitest run",
17
+ "lint": "eslint . --ext .js,.ts",
18
+ "format": "prettier --write 'src/**/*.{js,ts}'",
19
+ "prepare": "npm run build"
17
20
  },
18
21
  "bin": {
19
22
  "gsloth": "index.js",
20
23
  "gth": "index.js"
21
24
  },
22
25
  "dependencies": {
23
- "@langchain/anthropic": "^0.3.18",
24
- "@langchain/core": "^0.3.45",
25
- "@langchain/google-vertexai": "^0.2.4",
26
+ "@langchain/anthropic": "^0.3.20",
27
+ "@langchain/core": "^0.3.55",
28
+ "@langchain/google-vertexai": "^0.2.8",
26
29
  "@langchain/groq": "^0.2.2",
27
- "@langchain/langgraph": "^0.2.65",
28
- "@types/node": "^22.14.1",
30
+ "@langchain/langgraph": "^0.2.71",
29
31
  "chalk": "^5.4.1",
30
32
  "commander": "^13.1.0",
31
33
  "uuid": "^11.1.0"
32
34
  },
33
35
  "devDependencies": {
34
- "@eslint/js": "^9.25.1",
35
- "eslint": "^9.25.1",
36
- "eslint-plugin-jasmine": "^4.2.2",
37
- "globals": "^16.0.0",
38
- "jasmine": "^5.6.0",
39
- "testdouble": "^3.20.2"
36
+ "@eslint/js": "^9.26.0",
37
+ "@types/node": "^22.15.17",
38
+ "@types/uuid": "^10.0.0",
39
+ "@typescript-eslint/eslint-plugin": "^8.32.0",
40
+ "@typescript-eslint/parser": "^8.32.0",
41
+ "eslint": "^9.26.0",
42
+ "eslint-config-prettier": "^9.1.0",
43
+ "eslint-plugin-prettier": "^5.1.3",
44
+ "globals": "^16.1.0",
45
+ "prettier": "3.5.3",
46
+ "typescript": "^5.4.2",
47
+ "vitest": "^3.1.3"
48
+ },
49
+ "imports": {
50
+ "#src/*.js": "./dist/*.js"
40
51
  }
41
52
  }
@@ -0,0 +1,35 @@
1
+ import { Command } from 'commander';
2
+ import { readBackstory, readGuidelines } from '#src/prompt.js';
3
+ import { readMultipleFilesFromCurrentDir } from '#src/utils.js';
4
+ import { initConfig, slothContext } from '#src/config.js';
5
+
6
+ interface AskCommandOptions {
7
+ file?: string[];
8
+ }
9
+
10
+ /**
11
+ * Adds the ask command to the program
12
+ * @param program - The commander program
13
+ */
14
+ export function askCommand(program: Command): void {
15
+ program
16
+ .command('ask')
17
+ .description('Ask a question')
18
+ .argument('<message>', 'A message')
19
+ .option(
20
+ '-f, --file [files...]',
21
+ 'Input files. Content of these files will be added BEFORE the message'
22
+ )
23
+ // TODO add option consuming extra message as argument
24
+ .action(async (message: string, options: AskCommandOptions) => {
25
+ const preamble = [readBackstory(), readGuidelines(slothContext.config.projectGuidelines)];
26
+ const content = [message];
27
+ if (options.file) {
28
+ content.push(readMultipleFilesFromCurrentDir(options.file));
29
+ }
30
+ await initConfig();
31
+ const { askQuestion } = await import('#src/modules/questionAnsweringModule.js');
32
+ // TODO make the prefix configurable
33
+ await askQuestion('gth-ASK', preamble.join('\n'), content.join('\n'));
34
+ });
35
+ }
@@ -0,0 +1,19 @@
1
+ import type { ConfigType } from '#src/config.js';
2
+ import { availableDefaultConfigs, createProjectConfig } from '#src/config.js';
3
+ import { Argument, Command } from 'commander';
4
+
5
+ /**
6
+ * Adds the init command to the program
7
+ * @param program - The commander program
8
+ */
9
+ export function initCommand(program: Command): void {
10
+ program
11
+ .command('init')
12
+ .description(
13
+ 'Initialize the Gaunt Sloth Assistant in your project. This will write necessary config files.'
14
+ )
15
+ .addArgument(new Argument('<type>', 'Config type').choices(availableDefaultConfigs))
16
+ .action(async (config: ConfigType) => {
17
+ await createProjectConfig(config);
18
+ });
19
+ }