@gaunt-sloth/review 2.0.0-alpha.22 → 2.0.0-alpha.24
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 +77 -36
- package/cli.js +8 -7
- package/dist/commands/commandUtils.d.ts +8 -0
- package/dist/commands/commandUtils.js +19 -2
- package/dist/commands/commandUtils.js.map +1 -1
- package/dist/sources/gitDiffSource.d.ts +12 -0
- package/dist/sources/gitDiffSource.js +75 -0
- package/dist/sources/gitDiffSource.js.map +1 -0
- package/dist/sources/jiraIssueSource.d.ts +2 -1
- package/dist/sources/jiraIssueSource.js +2 -1
- package/dist/sources/jiraIssueSource.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,78 +1,119 @@
|
|
|
1
1
|
# @gaunt-sloth/review
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The review engine behind `gth review` / `gth pr`, packaged for embedding: run an AI code review
|
|
4
|
+
programmatically from your own tool or pipeline, or via the standalone `gaunt-sloth-review`
|
|
5
|
+
binary. Also contains the content/requirement sources (GitHub, local git diff, Jira, file, text) that feed it.
|
|
6
|
+
|
|
7
|
+
**When to depend on this package** — you want review results inside your own process or a
|
|
8
|
+
minimal CI job. It has no dependency on `commander`, MCP, or A2A, so the install stays small.
|
|
9
|
+
If you want the interactive CLI (chat/code sessions, TUI, MCP tools), install the fat
|
|
10
|
+
[`gaunt-sloth`](https://www.npmjs.com/package/gaunt-sloth) app instead — it wires this same
|
|
11
|
+
module into `gth review` and `gth pr`.
|
|
4
12
|
|
|
5
13
|
## Installation
|
|
6
14
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
15
|
+
AI providers are not bundled (they are optional peer dependencies of
|
|
16
|
+
[`@gaunt-sloth/core`](https://www.npmjs.com/package/@gaunt-sloth/core)); install the one your
|
|
17
|
+
config uses:
|
|
10
18
|
|
|
11
19
|
```bash
|
|
12
20
|
# OpenRouter / OpenAI
|
|
13
|
-
npm install
|
|
21
|
+
npm install @gaunt-sloth/review @langchain/openai
|
|
14
22
|
|
|
15
23
|
# Google (Vertex AI / AI Studio)
|
|
16
|
-
npm install
|
|
24
|
+
npm install @gaunt-sloth/review @langchain/google
|
|
17
25
|
|
|
18
26
|
# Anthropic
|
|
19
|
-
npm install
|
|
27
|
+
npm install @gaunt-sloth/review @langchain/anthropic
|
|
20
28
|
|
|
21
29
|
# Groq
|
|
22
|
-
npm install
|
|
30
|
+
npm install @gaunt-sloth/review @langchain/groq
|
|
23
31
|
```
|
|
24
32
|
|
|
25
|
-
|
|
33
|
+
## Embedding: review a diff programmatically
|
|
34
|
+
|
|
35
|
+
I want to run a Gaunt Sloth review over a diff from my own Node script and fail the build on a
|
|
36
|
+
bad rating. Create `.gsloth.config.json` next to the script:
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"llm": { "type": "anthropic", "model": "claude-sonnet-4-5" },
|
|
41
|
+
"commands": {
|
|
42
|
+
"review": { "rating": { "enabled": true, "passThreshold": 6 } }
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
26
46
|
|
|
27
|
-
|
|
47
|
+
Then run a review over a diff (`node review-diff.mjs change.diff`):
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
// review-diff.mjs
|
|
51
|
+
import { readFileSync } from 'node:fs';
|
|
52
|
+
import { initConfig } from '@gaunt-sloth/core/config.js';
|
|
53
|
+
import {
|
|
54
|
+
readBackstory,
|
|
55
|
+
readGuidelines,
|
|
56
|
+
readReviewInstructions,
|
|
57
|
+
} from '@gaunt-sloth/core/utils/llmUtils.js';
|
|
58
|
+
import { review } from '@gaunt-sloth/review';
|
|
59
|
+
|
|
60
|
+
const config = await initConfig({}); // loads .gsloth.config.* from the working directory
|
|
61
|
+
const preamble = [readBackstory(config), readGuidelines(config), readReviewInstructions(config)]
|
|
62
|
+
.filter(Boolean)
|
|
63
|
+
.join('\n');
|
|
64
|
+
const diff = readFileSync(process.argv[2], 'utf8');
|
|
65
|
+
|
|
66
|
+
await review('embedded-review', preamble, diff, config);
|
|
67
|
+
process.exit(process.exitCode ?? 0);
|
|
68
|
+
```
|
|
28
69
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
-
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
- Review rate middleware
|
|
70
|
+
The review text is written to stdout. With rating enabled, `review()` sets `process.exitCode = 1`
|
|
71
|
+
when the rating comes back below `passThreshold` (or when the model fails to produce a rating),
|
|
72
|
+
so the script exits non-zero exactly when `gth review` would — that is the whole embed contract.
|
|
73
|
+
Configuration (provider, prompts, rating thresholds) is the standard Gaunt Sloth config, see
|
|
74
|
+
[docs/CONFIGURATION.md](https://github.com/pukeko-robotics/gaunt-sloth/blob/main/docs/CONFIGURATION.md).
|
|
35
75
|
|
|
36
|
-
|
|
76
|
+
This exact flow is verified by the workspace embed e2e (`pnpm run test:embed`), which packs the
|
|
77
|
+
published tarballs and runs the snippet above from a temp-dir consumer against a stub model.
|
|
37
78
|
|
|
38
|
-
|
|
79
|
+
## Standalone CLI: `gaunt-sloth-review`
|
|
80
|
+
|
|
81
|
+
The package's one binary, for CI-friendly reviews with a minimal footprint:
|
|
39
82
|
|
|
40
83
|
```bash
|
|
41
|
-
gaunt-sloth-review
|
|
84
|
+
gaunt-sloth-review 123 # review PR 123 (uses the configured content source, GitHub by default)
|
|
85
|
+
gaunt-sloth-review 123 45 # ...with requirements from issue 45
|
|
42
86
|
gaunt-sloth-review --version
|
|
43
87
|
```
|
|
44
88
|
|
|
45
89
|
### Identity profiles
|
|
46
90
|
|
|
47
|
-
To use a different config profile (e.g. separate provider/auth for CI vs local),
|
|
48
|
-
|
|
91
|
+
To use a different config profile (e.g. separate provider/auth for CI vs local), set the
|
|
92
|
+
`GSLOTH_IDENTITY_PROFILE` environment variable:
|
|
49
93
|
|
|
50
94
|
```bash
|
|
51
95
|
GSLOTH_IDENTITY_PROFILE=review gaunt-sloth-review 123
|
|
52
96
|
```
|
|
53
97
|
|
|
54
|
-
This loads config from `.gsloth-settings/review/` instead of the default
|
|
55
|
-
|
|
56
|
-
LLM provider than local development.
|
|
57
|
-
|
|
58
|
-
## Dependencies
|
|
59
|
-
|
|
60
|
-
- `@gaunt-sloth/core` (required)
|
|
61
|
-
|
|
62
|
-
No MCP, no A2A, no commander. This is intentional to keep the package lightweight for CI use.
|
|
98
|
+
This loads config from `.gsloth-settings/review/` instead of the default `.gsloth/` directory.
|
|
99
|
+
Useful when CI uses different credentials or a different LLM provider than local development.
|
|
63
100
|
|
|
64
101
|
## Exports
|
|
65
102
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
103
|
+
- `@gaunt-sloth/review` (the root export) is the public API: the review module (`review`,
|
|
104
|
+
`ReviewContext`), `commandUtils`, and the `gh` read-file tool — plus, deliberately, the whole
|
|
105
|
+
`@gaunt-sloth/core` config barrel (`initConfig`, `GthConfig`, `DEFAULT_CONFIG`, …), re-exported
|
|
106
|
+
so an embedder can resolve config from the review root without importing core directly.
|
|
107
|
+
This surface is what the embed example above and the fat CLI use.
|
|
108
|
+
- `@gaunt-sloth/review/<path>.js` deep paths (e.g.
|
|
109
|
+
`@gaunt-sloth/review/modules/reviewModule.js`) mirror the package's internal `dist/` layout
|
|
110
|
+
1:1 and are deliberately kept open for reach-in. They are supported at your own risk: internal
|
|
111
|
+
files can move between alpha/minor versions without a deprecation cycle. Prefer the root
|
|
112
|
+
export where it suffices.
|
|
71
113
|
|
|
72
114
|
## Related packages
|
|
73
115
|
|
|
74
116
|
- [`@gaunt-sloth/core`](https://www.npmjs.com/package/@gaunt-sloth/core) — Core utilities, config, and agent infrastructure ([source](https://github.com/pukeko-robotics/gaunt-sloth/tree/main/packages/core))
|
|
75
117
|
- [`@gaunt-sloth/agent`](https://www.npmjs.com/package/@gaunt-sloth/agent) — Agent runtime: built-in tools, filesystem toolkit, middleware registry, API server, AG-UI, MCP, and A2A integration ([source](https://github.com/pukeko-robotics/gaunt-sloth/tree/main/packages/agent))
|
|
76
|
-
- [`@gaunt-sloth/review`](https://www.npmjs.com/package/@gaunt-sloth/review) — Review and Q&A modules with standalone CLI (this package) ([source](https://github.com/pukeko-robotics/gaunt-sloth/tree/main/packages/review))
|
|
77
118
|
- [`@gaunt-sloth/batch`](https://www.npmjs.com/package/@gaunt-sloth/batch) — Batch / eval / workflow runtime ([source](https://github.com/pukeko-robotics/gaunt-sloth/tree/main/packages/batch))
|
|
78
119
|
- [`gaunt-sloth`](https://www.npmjs.com/package/gaunt-sloth) — Main CLI application ([source](https://github.com/pukeko-robotics/gaunt-sloth/tree/main/packages/app))
|
package/cli.js
CHANGED
|
@@ -25,8 +25,11 @@ setEntryPoint(import.meta.url);
|
|
|
25
25
|
import { initConfig } from '@gaunt-sloth/core/config.js';
|
|
26
26
|
import { review } from '#src/modules/reviewModule.js';
|
|
27
27
|
import { displayError } from '@gaunt-sloth/core/utils/consoleUtils.js';
|
|
28
|
-
import {
|
|
29
|
-
|
|
28
|
+
import {
|
|
29
|
+
getContentFromSource,
|
|
30
|
+
getRequirementsFromSource,
|
|
31
|
+
getReviewPreamble,
|
|
32
|
+
} from '#src/commands/commandUtils.js';
|
|
30
33
|
|
|
31
34
|
async function main() {
|
|
32
35
|
try {
|
|
@@ -53,11 +56,9 @@ async function main() {
|
|
|
53
56
|
}
|
|
54
57
|
}
|
|
55
58
|
|
|
56
|
-
// Build preamble
|
|
57
|
-
|
|
58
|
-
const preambleText =
|
|
59
|
-
.map((m) => (typeof m.content === 'string' ? m.content : ''))
|
|
60
|
-
.join('\n');
|
|
59
|
+
// Build the review preamble (backstory + guidelines + review instructions + optional
|
|
60
|
+
// system prompt), the same composition `gth review` / `gth pr` use.
|
|
61
|
+
const preambleText = getReviewPreamble(config);
|
|
61
62
|
|
|
62
63
|
// Combine requirements and content for the review
|
|
63
64
|
const diffWithReqs = requirements
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import type { GthConfig } from '@gaunt-sloth/core/config.js';
|
|
2
|
+
/**
|
|
3
|
+
* Compose the review system preamble the way the fat CLI's `gth review` / `gth pr` do:
|
|
4
|
+
* backstory + guidelines + review instructions + the optional project system prompt, each
|
|
5
|
+
* segment honouring the GS2-43 `prompts.*` config. Empty segments are dropped rather than
|
|
6
|
+
* left as blank lines (the shape the README embed example documents).
|
|
7
|
+
*/
|
|
8
|
+
export declare function getReviewPreamble(config: GthConfig): string;
|
|
2
9
|
/**
|
|
3
10
|
* Requirement sources. Expected to be in `.sources/` dir.
|
|
4
11
|
* Aliases are mapped to actual sources in this file
|
|
@@ -17,6 +24,7 @@ export type RequirementSourceType = keyof typeof REQUIREMENTS_SOURCES;
|
|
|
17
24
|
*/
|
|
18
25
|
export declare const CONTENT_SOURCES: {
|
|
19
26
|
readonly github: 'ghPrDiffSource.js';
|
|
27
|
+
readonly git: 'gitDiffSource.js';
|
|
20
28
|
readonly text: 'textSource.js';
|
|
21
29
|
readonly file: 'fileSource.js';
|
|
22
30
|
};
|
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
import { displayError } from '@gaunt-sloth/core/utils/consoleUtils.js';
|
|
2
|
-
import { wrapContent } from '@gaunt-sloth/core/utils/llmUtils.js';
|
|
2
|
+
import { readBackstory, readGuidelines, readReviewInstructions, readSystemPrompt, wrapContent, } from '@gaunt-sloth/core/utils/llmUtils.js';
|
|
3
|
+
/**
|
|
4
|
+
* Compose the review system preamble the way the fat CLI's `gth review` / `gth pr` do:
|
|
5
|
+
* backstory + guidelines + review instructions + the optional project system prompt, each
|
|
6
|
+
* segment honouring the GS2-43 `prompts.*` config. Empty segments are dropped rather than
|
|
7
|
+
* left as blank lines (the shape the README embed example documents).
|
|
8
|
+
*/
|
|
9
|
+
export function getReviewPreamble(config) {
|
|
10
|
+
return [
|
|
11
|
+
readBackstory(config),
|
|
12
|
+
readGuidelines(config),
|
|
13
|
+
readReviewInstructions(config),
|
|
14
|
+
readSystemPrompt(config),
|
|
15
|
+
]
|
|
16
|
+
.filter(Boolean)
|
|
17
|
+
.join('\n');
|
|
18
|
+
}
|
|
3
19
|
/**
|
|
4
20
|
* Requirement sources. Expected to be in `.sources/` dir.
|
|
5
21
|
* Aliases are mapped to actual sources in this file
|
|
@@ -17,6 +33,7 @@ export const REQUIREMENTS_SOURCES = {
|
|
|
17
33
|
*/
|
|
18
34
|
export const CONTENT_SOURCES = {
|
|
19
35
|
github: 'ghPrDiffSource.js',
|
|
36
|
+
git: 'gitDiffSource.js',
|
|
20
37
|
text: 'textSource.js',
|
|
21
38
|
file: 'fileSource.js',
|
|
22
39
|
};
|
|
@@ -26,7 +43,7 @@ export async function getRequirementsFromSource(requirementSource, requirementsI
|
|
|
26
43
|
}
|
|
27
44
|
export async function getContentFromSource(contentSource, contentId, config) {
|
|
28
45
|
const content = await getFromSource(contentSource, contentId, (config?.contentSourceConfig ?? {})[contentSource], CONTENT_SOURCES);
|
|
29
|
-
return wrapContent(content, contentSource, contentSource === 'github' ? 'GitHub diff' : 'content');
|
|
46
|
+
return wrapContent(content, contentSource, contentSource === 'github' ? 'GitHub diff' : contentSource === 'git' ? 'git diff' : 'content');
|
|
30
47
|
}
|
|
31
48
|
async function getFromSource(source, id,
|
|
32
49
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"commandUtils.js","sourceRoot":"","sources":["../../src/commands/commandUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAEvE,OAAO,
|
|
1
|
+
{"version":3,"file":"commandUtils.js","sourceRoot":"","sources":["../../src/commands/commandUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AAEvE,OAAO,EACL,aAAa,EACb,cAAc,EACd,sBAAsB,EACtB,gBAAgB,EAChB,WAAW,GACZ,MAAM,qCAAqC,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAAiB;IACjD,OAAO;QACL,aAAa,CAAC,MAAM,CAAC;QACrB,cAAc,CAAC,MAAM,CAAC;QACtB,sBAAsB,CAAC,MAAM,CAAC;QAC9B,gBAAgB,CAAC,MAAM,CAAC;KACzB;SACE,MAAM,CAAC,OAAO,CAAC;SACf,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,aAAa,EAAE,0BAA0B;IACzC,IAAI,EAAE,oBAAoB;IAC1B,MAAM,EAAE,kBAAkB;IAC1B,IAAI,EAAE,eAAe;IACrB,IAAI,EAAE,eAAe;CACb,CAAC;AAIX;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,MAAM,EAAE,mBAAmB;IAC3B,GAAG,EAAE,kBAAkB;IACvB,IAAI,EAAE,eAAe;IACrB,IAAI,EAAE,eAAe;CACb,CAAC;AAIX,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,iBAAoD,EACpD,cAAkC,EAClC,MAAiB;IAEjB,MAAM,YAAY,GAAG,MAAM,aAAa,CACtC,iBAAiB,EACjB,cAAc,EACd,CAAC,MAAM,EAAE,uBAAuB,IAAI,EAAE,CAAC,CAAC,iBAA2B,CAAC,EACpE,oBAAoB,CACrB,CAAC;IACF,OAAO,WAAW,CAAC,YAAY,EAAE,iBAAiB,EAAE,cAAc,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,aAA4C,EAC5C,SAA6B,EAC7B,MAAiB;IAEjB,MAAM,OAAO,GAAG,MAAM,aAAa,CACjC,aAAa,EACb,SAAS,EACT,CAAC,MAAM,EAAE,mBAAmB,IAAI,EAAE,CAAC,CAAC,aAAuB,CAAC,EAC5D,eAAe,CAChB,CAAC;IACF,OAAO,WAAW,CAChB,OAAO,EACP,aAAa,EACb,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,aAAa,KAAK,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAC9F,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,MAA6D,EAC7D,EAAsB;AACtB,8DAA8D;AAC9D,MAAW,EACX,sBAA4E;IAE5E,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,oCAAoC;QACpC,IAAI,sBAAsB,CAAC,MAA6C,CAAC,EAAE,CAAC;YAC1E,MAAM,UAAU,GAAG,gBAAgB,sBAAsB,CAAC,MAA6C,CAAC,EAAE,CAAC;YAC3G,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;YACzC,OAAO,MAAM,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC/B,CAAC;aAAM,CAAC;YACN,YAAY,CAAC,mBAAmB,MAAM,0BAA0B,CAAC,CAAC;QACpE,CAAC;IACH,CAAC;SAAM,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;QACxC,yCAAyC;QACzC,OAAO,MAAO,MAAsD,CAAC,EAAE,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ProviderConfig } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Gets a local diff via `git --no-pager diff [refRange]` — review the working tree (or a
|
|
4
|
+
* ref range) without GitHub and without piping a diff through stdin.
|
|
5
|
+
*
|
|
6
|
+
* @param _ config (unused in this source)
|
|
7
|
+
* @param refRange optional revision selection passed to `git diff`, e.g. `origin/main...HEAD`
|
|
8
|
+
* or `HEAD~3`. When omitted, diffs the working tree against the index (plain `git diff`).
|
|
9
|
+
* @returns the diff content; throws with a clear message outside a git repository, on a bad
|
|
10
|
+
* ref, or when the diff is empty (an empty review would otherwise run against no content).
|
|
11
|
+
*/
|
|
12
|
+
export declare function get(_: ProviderConfig | null, refRange: string | undefined): Promise<string | null>;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ProgressIndicator } from '@gaunt-sloth/core/utils/ProgressIndicator.js';
|
|
2
|
+
/**
|
|
3
|
+
* `git diff` can emit multi-megabyte output for large changes; the node default (1 MiB)
|
|
4
|
+
* would truncate-and-fail such runs.
|
|
5
|
+
*/
|
|
6
|
+
const MAX_DIFF_BUFFER = 32 * 1024 * 1024;
|
|
7
|
+
/**
|
|
8
|
+
* Gets a local diff via `git --no-pager diff [refRange]` — review the working tree (or a
|
|
9
|
+
* ref range) without GitHub and without piping a diff through stdin.
|
|
10
|
+
*
|
|
11
|
+
* @param _ config (unused in this source)
|
|
12
|
+
* @param refRange optional revision selection passed to `git diff`, e.g. `origin/main...HEAD`
|
|
13
|
+
* or `HEAD~3`. When omitted, diffs the working tree against the index (plain `git diff`).
|
|
14
|
+
* @returns the diff content; throws with a clear message outside a git repository, on a bad
|
|
15
|
+
* ref, or when the diff is empty (an empty review would otherwise run against no content).
|
|
16
|
+
*/
|
|
17
|
+
export async function get(_, refRange) {
|
|
18
|
+
// Args go to execFile (no shell), so shell metacharacters are inert; still reject
|
|
19
|
+
// option-shaped input so an id can never become a git flag (e.g. `--output=<file>`).
|
|
20
|
+
if (refRange && refRange.startsWith('-')) {
|
|
21
|
+
throw new Error(`Invalid git diff argument "${refRange}"; expected a ref or ref range (e.g. "origin/main...HEAD"), not an option.`);
|
|
22
|
+
}
|
|
23
|
+
const label = refRange ? `for "${refRange}"` : 'for the working tree';
|
|
24
|
+
const gitArgs = ['--no-pager', 'diff', ...(refRange ? [refRange] : [])];
|
|
25
|
+
const progress = new ProgressIndicator(`Getting local git diff ${label}`);
|
|
26
|
+
try {
|
|
27
|
+
const diffContent = await runGit(gitArgs);
|
|
28
|
+
progress.stop();
|
|
29
|
+
if (!diffContent.trim()) {
|
|
30
|
+
throw new Error(`No changes found in git diff ${label}; nothing to review.`);
|
|
31
|
+
}
|
|
32
|
+
return `Local git diff ${label}\n\n${diffContent}`;
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
progress.stop();
|
|
36
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
37
|
+
if (reason.startsWith('No changes found')) {
|
|
38
|
+
throw new Error(reason);
|
|
39
|
+
}
|
|
40
|
+
throw new Error(`Failed to get git diff ${label}: ${reason}\nConsider checking that you are inside a git repository and the ref range is valid.`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Run git with an args array (execFile, no shell). Rejects on a non-zero exit or spawn
|
|
45
|
+
* failure with git's stderr as the reason; benign stderr chatter on a zero exit is ignored
|
|
46
|
+
* (unlike systemUtils.execAsync, which rejects on any stderr output).
|
|
47
|
+
*/
|
|
48
|
+
async function runGit(args) {
|
|
49
|
+
const { execFile } = await import('node:child_process');
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
execFile('git', args, { maxBuffer: MAX_DIFF_BUFFER }, (error, stdout, stderr) => {
|
|
52
|
+
if (error) {
|
|
53
|
+
reject(new Error(extractGitError(stderr ?? '', error.message)));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
resolve(stdout);
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Reduce git's stderr to the one meaningful line. Outside a repository `git diff` appends
|
|
62
|
+
* its entire `--no-index` usage screen after the warning line; that wall of text is noise
|
|
63
|
+
* in a CLI error. Prefer the `fatal:` line when present, else the first non-empty line.
|
|
64
|
+
*/
|
|
65
|
+
function extractGitError(stderr, fallback) {
|
|
66
|
+
const lines = stderr
|
|
67
|
+
.split('\n')
|
|
68
|
+
.map((line) => line.trim())
|
|
69
|
+
.filter(Boolean);
|
|
70
|
+
if (lines.length === 0) {
|
|
71
|
+
return fallback;
|
|
72
|
+
}
|
|
73
|
+
return lines.find((line) => line.startsWith('fatal:')) ?? lines[0];
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=gitDiffSource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gitDiffSource.js","sourceRoot":"","sources":["../../src/sources/gitDiffSource.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,8 @@ import type { JiraConfig } from './types.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Gets Jira issue using Atlassian REST API v3 with Personal Access Token
|
|
4
4
|
*
|
|
5
|
-
*
|
|
5
|
+
* Requires an authenticated Atlassian Cloud instance (Cloud ID + API token); anonymous
|
|
6
|
+
* access to a public Jira instance is not supported.
|
|
6
7
|
*
|
|
7
8
|
* @param config Jira configuration
|
|
8
9
|
* @param issueId Jira issue ID
|
|
@@ -3,7 +3,8 @@ import { getJiraCredentials, jiraRequest, } from '#src/helpers/jira/jiraClient.j
|
|
|
3
3
|
/**
|
|
4
4
|
* Gets Jira issue using Atlassian REST API v3 with Personal Access Token
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* Requires an authenticated Atlassian Cloud instance (Cloud ID + API token); anonymous
|
|
7
|
+
* access to a public Jira instance is not supported.
|
|
7
8
|
*
|
|
8
9
|
* @param config Jira configuration
|
|
9
10
|
* @param issueId Jira issue ID
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jiraIssueSource.js","sourceRoot":"","sources":["../../src/sources/jiraIssueSource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAEhG,OAAO,EACL,kBAAkB,EAClB,WAAW,GAEZ,MAAM,iCAAiC,CAAC;AAYzC
|
|
1
|
+
{"version":3,"file":"jiraIssueSource.js","sourceRoot":"","sources":["../../src/sources/jiraIssueSource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAEhG,OAAO,EACL,kBAAkB,EAClB,WAAW,GAEZ,MAAM,iCAAiC,CAAC;AAYzC;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CACvB,MAAkC,EAClC,OAA2B;IAE3B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,cAAc,CAAC,yBAAyB,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,cAAc,CAAC,sBAAsB,CAAC,CAAC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,WAAW,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAC;IAE/C,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC;QACd,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;IACvF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,YAAY,CACV,6BAA6B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACtF,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,KAAK,UAAU,YAAY,CACzB,WAAoC,EACpC,OAAe;IAEf,sGAAsG;IAEtG,0KAA0K;IAC1K,sHAAsH;IACtH,8CAA8C;IAC9C,qHAAqH;IACrH,qGAAqG;IAErG,IAAI,WAAW,CAAC,UAAU,EAAE,CAAC;QAC3B,OAAO,CAAC,sBAAsB,WAAW,CAAC,UAAU,GAAG,OAAO,EAAE,CAAC,CAAC;IACpE,CAAC;IAED,wFAAwF;IACxF,MAAM,OAAO,GAAG,6BAA6B,CAAC,CAAC,wCAAwC;IAEvF,OAAO,WAAW,CAAoB,WAAW,EAAE,qBAAqB,OAAO,GAAG,OAAO,EAAE,EAAE;QAC3F,MAAM,EAAE,KAAK;KACd,CAAC,CAAC;AACL,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gaunt-sloth/review",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.24",
|
|
4
4
|
"description": "Review functionality for Gaunt Sloth",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Andrew Kondratev",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"@langchain/langgraph": "^1.4.8",
|
|
39
39
|
"langchain": "^1.5.3",
|
|
40
40
|
"zod": "^4.4.3",
|
|
41
|
-
"@gaunt-sloth/core": "2.0.0-alpha.
|
|
41
|
+
"@gaunt-sloth/core": "2.0.0-alpha.24"
|
|
42
42
|
},
|
|
43
43
|
"files": [
|
|
44
44
|
"./dist/*",
|