@g-abhishek/gitx 0.1.5 → 0.1.6
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 +58 -1
- package/dist/ai/claudeAi.d.ts.map +1 -1
- package/dist/ai/claudeAi.js +4 -30
- package/dist/ai/claudeAi.js.map +1 -1
- package/dist/ai/claudeCliAi.d.ts.map +1 -1
- package/dist/ai/claudeCliAi.js +4 -21
- package/dist/ai/claudeCliAi.js.map +1 -1
- package/dist/ai/openAiAi.d.ts.map +1 -1
- package/dist/ai/openAiAi.js +4 -30
- package/dist/ai/openAiAi.js.map +1 -1
- package/dist/ai/reviewHelpers.d.ts +24 -0
- package/dist/ai/reviewHelpers.d.ts.map +1 -1
- package/dist/ai/reviewHelpers.js +70 -1
- package/dist/ai/reviewHelpers.js.map +1 -1
- package/dist/cli/commands/pr/cherryPick.d.ts +25 -0
- package/dist/cli/commands/pr/cherryPick.d.ts.map +1 -0
- package/dist/cli/commands/pr/cherryPick.js +317 -0
- package/dist/cli/commands/pr/cherryPick.js.map +1 -0
- package/dist/cli/commands/pr/index.d.ts.map +1 -1
- package/dist/cli/commands/pr/index.js +4 -0
- package/dist/cli/commands/pr/index.js.map +1 -1
- package/dist/cli/commands/pr/port.d.ts +34 -0
- package/dist/cli/commands/pr/port.d.ts.map +1 -0
- package/dist/cli/commands/pr/port.js +453 -0
- package/dist/cli/commands/pr/port.js.map +1 -0
- package/dist/cli/commands/sync.d.ts +12 -11
- package/dist/cli/commands/sync.d.ts.map +1 -1
- package/dist/cli/commands/sync.js +13 -101
- package/dist/cli/commands/sync.js.map +1 -1
- package/dist/workflows/pr.d.ts.map +1 -1
- package/dist/workflows/pr.js +71 -14
- package/dist/workflows/pr.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,6 +23,8 @@ gitx wraps your everyday git operations with AI to generate commit messages, wri
|
|
|
23
23
|
- [gitx pr merge](#gitx-pr-merge)
|
|
24
24
|
- [gitx pr list](#gitx-pr-list)
|
|
25
25
|
- [gitx pr close](#gitx-pr-close)
|
|
26
|
+
- [gitx pr cherry-pick](#gitx-pr-cherry-pick)
|
|
27
|
+
- [gitx pr port](#gitx-pr-port)
|
|
26
28
|
- [gitx config](#gitx-config)
|
|
27
29
|
- [Supported Providers](#supported-providers)
|
|
28
30
|
- [Environment Variables](#environment-variables)
|
|
@@ -40,6 +42,8 @@ gitx wraps your everyday git operations with AI to generate commit messages, wri
|
|
|
40
42
|
| **AI conflict resolution** | Tries to auto-resolve merge/rebase conflicts; prompts when unsure |
|
|
41
43
|
| **AI task implementation** | Takes a plain-English task, plans and applies diffs, commits, pushes, opens PR |
|
|
42
44
|
| **gitx ask** | Ask anything about your repo — get answers grounded in live git context |
|
|
45
|
+
| **PR cherry-pick** | Pull all commits from any PR into your current branch in one command (`gitx pr cherry-pick`) |
|
|
46
|
+
| **PR port** | Port a PR's commits onto multiple target branches and open PRs in one command (`gitx pr port`) |
|
|
43
47
|
|
|
44
48
|
---
|
|
45
49
|
|
|
@@ -200,7 +204,7 @@ gitx sync --abort # cancel an in-progress operation
|
|
|
200
204
|
|
|
201
205
|
**AI conflict resolution:** When a merge/rebase conflict is detected, gitx asks the AI to resolve it. High-confidence resolutions are applied automatically; low-confidence ones are shown to you for confirmation.
|
|
202
206
|
|
|
203
|
-
|
|
207
|
+
To address review comments before syncing, run `gitx pr resolve <number>` first.
|
|
204
208
|
|
|
205
209
|
---
|
|
206
210
|
|
|
@@ -345,6 +349,59 @@ gitx pr close 42 --force # skip confirmation prompt
|
|
|
345
349
|
|
|
346
350
|
---
|
|
347
351
|
|
|
352
|
+
### gitx pr cherry-pick
|
|
353
|
+
|
|
354
|
+
Cherry-pick all commits from a PR into the current branch.
|
|
355
|
+
|
|
356
|
+
Useful when you want to pull someone else's PR work (or a PR targeting a different branch) directly onto your own branch — without merging or waiting for the PR to land.
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
gitx pr cherry-pick <number> # cherry-pick all commits of a PR
|
|
360
|
+
gitx pr cherry-pick 42 --dry-run # list commits without applying
|
|
361
|
+
gitx pr cherry-pick 42 --no-confirm # skip confirmation prompt
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
**What it does:**
|
|
365
|
+
1. Fetches the PR's source branch from origin
|
|
366
|
+
2. Lists all commits between the PR's base and head (oldest → newest)
|
|
367
|
+
3. Cherry-picks them onto your current branch with `-x` (records original SHA)
|
|
368
|
+
4. On conflicts: AI attempts resolution — high-confidence fixes are applied automatically; low-confidence ones show a preview and ask for your approval
|
|
369
|
+
5. Leaves you ready to review and push: `gitx push`
|
|
370
|
+
|
|
371
|
+
**Difference from `gitx port`:** `gitx port` moves commits *from* your branch *to* other branches. `gitx pr cherry-pick` pulls commits *from* a PR *into* your current branch.
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
### gitx pr port
|
|
376
|
+
|
|
377
|
+
Port all commits from a PR onto one or more target branches and open PRs — without touching your current working branch.
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
gitx pr port <number> <target1> [target2...]
|
|
381
|
+
|
|
382
|
+
# Examples:
|
|
383
|
+
gitx pr port 12345 release/v1 release/v2
|
|
384
|
+
gitx pr port 12345 hotfix/v1 --draft # create PRs as drafts
|
|
385
|
+
gitx pr port 12345 release/v1 --no-pr # push branch only, skip PR creation
|
|
386
|
+
gitx pr port 12345 release/v1 --dry-run # preview commits without changes
|
|
387
|
+
gitx pr port 12345 release/v1 --no-confirm # skip per-target confirmation
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**What it does per target branch:**
|
|
391
|
+
1. Verifies the target branch exists on origin
|
|
392
|
+
2. Creates `port/pr-<number>-to-<target>` from `origin/<target>`
|
|
393
|
+
3. Cherry-picks all PR commits (oldest → newest) with `-x` flag
|
|
394
|
+
4. AI resolves conflicts automatically where possible
|
|
395
|
+
5. Pushes the port branch
|
|
396
|
+
6. Opens a PR: `port/pr-<number>-to-<target>` → `<target>`
|
|
397
|
+
7. Prints the PR URL
|
|
398
|
+
|
|
399
|
+
**Summary at the end** shows URLs for all created PRs, any branches pushed without PRs, and any targets skipped due to unresolvable conflicts.
|
|
400
|
+
|
|
401
|
+
**Difference from `gitx port`:** `gitx port` ports commits *from your current branch* to other branches. `gitx pr port` ports commits *from a specific PR* (by number) to any targets — your working branch is never touched.
|
|
402
|
+
|
|
403
|
+
---
|
|
404
|
+
|
|
348
405
|
### gitx config
|
|
349
406
|
|
|
350
407
|
Manage your gitx configuration.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claudeAi.d.ts","sourceRoot":"","sources":["../../src/ai/claudeAi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EACV,qBAAqB,EACrB,QAAQ,EACR,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AA+FpB,qBAAa,QAAS,YAAW,QAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B;;;OAGG;gBACS,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAY3C,6EAA6E;IAC7E,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO;IAInC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAqB1D,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IA8C/D,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAuD9D,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAgCpE,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"claudeAi.d.ts","sourceRoot":"","sources":["../../src/ai/claudeAi.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EACV,qBAAqB,EACrB,QAAQ,EACR,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AA+FpB,qBAAa,QAAS,YAAW,QAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B;;;OAGG;gBACS,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAY3C,6EAA6E;IAC7E,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO;IAInC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAqB1D,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IA8C/D,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAuD9D,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAgCpE,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAa/D,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAoDvD,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,mBAAmB,CAAC;IAmCpH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,4BAA4B,CAAC;IA+BtH,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,uBAAuB,CAAC;IA+B1F,gBAAgB,CACpB,OAAO,EAAE,UAAU,CAAC,OAAO,YAAY,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,GACxE,OAAO,CAAC,OAAO,YAAY,EAAE,wBAAwB,CAAC;IAWnD,WAAW,CACf,OAAO,EAAE,UAAU,CAAC,OAAO,YAAY,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,GACnE,OAAO,CAAC,OAAO,YAAY,EAAE,aAAa,CAAC;IAWxC,GAAG,CACP,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,YAAY,EAAE,YAAY,GACzC,OAAO,CAAC,OAAO,YAAY,EAAE,aAAa,CAAC;CAK/C"}
|
package/dist/ai/claudeAi.js
CHANGED
|
@@ -214,36 +214,10 @@ Step Description: ${s.description ?? ""}${fileContentsSection}`;
|
|
|
214
214
|
};
|
|
215
215
|
}
|
|
216
216
|
async suggestFixes(comment) {
|
|
217
|
-
const
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const fileContentsSection = c.fileContents && Object.keys(c.fileContents).length > 0
|
|
222
|
-
? `\n\nCurrent file contents:\n${Object.entries(c.fileContents)
|
|
223
|
-
.map(([p, content]) => `--- ${p} ---\n${content}`)
|
|
224
|
-
.join("\n\n")}`
|
|
225
|
-
: "";
|
|
226
|
-
const system = `You are an expert code reviewer suggesting fixes for pull request review comments. Respond with ONLY valid JSON:
|
|
227
|
-
{
|
|
228
|
-
"suggestedEdits": [
|
|
229
|
-
{
|
|
230
|
-
"path": "<file path>",
|
|
231
|
-
"rationale": "<why this change addresses the comment>",
|
|
232
|
-
"unifiedDiff": "<valid unified diff>"
|
|
233
|
-
}
|
|
234
|
-
]
|
|
235
|
-
}
|
|
236
|
-
If a comment doesn't require a code change, omit it from suggestedEdits.`;
|
|
237
|
-
const userPrompt = `PR Title: ${c.prTitle ?? ""}
|
|
238
|
-
PR Body: ${c.prBody ?? ""}
|
|
239
|
-
|
|
240
|
-
Review Comments:
|
|
241
|
-
${commentsText}${fileContentsSection}`;
|
|
242
|
-
const text = await callClaude(system, userPrompt, this.apiKey, this.model);
|
|
243
|
-
const parsed = parseJson(text, { suggestedEdits: [] });
|
|
244
|
-
return {
|
|
245
|
-
suggestedEdits: Array.isArray(parsed.suggestedEdits) ? parsed.suggestedEdits : [],
|
|
246
|
-
};
|
|
217
|
+
const { buildSuggestFixesSystem, buildSuggestFixesPrompt, parseSuggestFixesResponse } = await import("./reviewHelpers.js");
|
|
218
|
+
const ctx = comment;
|
|
219
|
+
const text = await callClaude(buildSuggestFixesSystem(), buildSuggestFixesPrompt(ctx), this.apiKey, this.model);
|
|
220
|
+
return parseSuggestFixesResponse(text);
|
|
247
221
|
}
|
|
248
222
|
async reviewPR(context) {
|
|
249
223
|
const ctx = context;
|
package/dist/ai/claudeAi.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claudeAi.js","sourceRoot":"","sources":["../../src/ai/claudeAi.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Claude AI integration via the Anthropic Messages API.\n *\n * Authentication: reads ANTHROPIC_API_KEY from the environment.\n * Model: defaults to claude-3-5-haiku-20241022 (fast, affordable).\n * Override via GITX_AI_MODEL env var.\n *\n * All methods send a structured system prompt and parse the JSON response.\n * If parsing fails we fall back gracefully rather than crashing.\n */\n\nimport axios, { isAxiosError } from \"axios\";\nimport { GitxError } from \"../utils/errors.js\";\nimport type {\n AiAnalyzeTaskResponse,\n AiClient,\n AiGenerateDiffsResponse,\n AiGeneratePlanResponse,\n AiReviewPRResponse,\n AiSuggestFixesResponse,\n AiSummarizeChangesResponse,\n} from \"./types.js\";\n\nconst ANTHROPIC_API = \"https://api.anthropic.com/v1/messages\";\nconst DEFAULT_MODEL = \"claude-3-5-haiku-20241022\";\nconst MAX_TOKENS = 4096;\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction getModel(override?: string): string {\n return process.env[\"GITX_AI_MODEL\"] ?? override ?? DEFAULT_MODEL;\n}\n\ninterface ClaudeMessage {\n role: \"user\" | \"assistant\";\n content: string;\n}\n\ninterface ClaudeRequestBody {\n model: string;\n max_tokens: number;\n system: string;\n messages: ClaudeMessage[];\n}\n\ninterface ClaudeResponseBody {\n content: Array<{ type: string; text: string }>;\n}\n\nasync function callClaude(system: string, userPrompt: string, apiKey: string, model: string): Promise<string> {\n const body: ClaudeRequestBody = {\n model,\n max_tokens: MAX_TOKENS,\n system,\n messages: [{ role: \"user\", content: userPrompt }],\n };\n\n try {\n const { data } = await axios.post<ClaudeResponseBody>(ANTHROPIC_API, body, {\n headers: {\n \"x-api-key\": apiKey,\n \"anthropic-version\": \"2023-06-01\",\n \"content-type\": \"application/json\",\n },\n timeout: 60_000,\n });\n\n const text = data.content.find((c) => c.type === \"text\")?.text ?? \"\";\n return text;\n } catch (err) {\n if (isAxiosError(err)) {\n const status = err.response?.status;\n const msg = (err.response?.data as Record<string, unknown> | undefined)?.error ?? err.message;\n if (status === 401) {\n throw new GitxError(\n \"Anthropic API authentication failed. Check ANTHROPIC_API_KEY.\",\n { exitCode: 1, cause: err }\n );\n }\n throw new GitxError(\n `Anthropic API error (${status ?? \"network\"}): ${String(msg)}`,\n { exitCode: 1, cause: err }\n );\n }\n throw new GitxError(`Unexpected AI error: ${String(err)}`, { exitCode: 1, cause: err });\n }\n}\n\n/**\n * Extract JSON from a Claude response that may include markdown code fences.\n * Claude sometimes wraps JSON in ```json ... ``` blocks.\n */\nfunction extractJson(text: string): string {\n const fenced = text.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n if (fenced?.[1]) return fenced[1].trim();\n // Find first { or [ and last } or ]\n const start = text.search(/[{[]/);\n const endBrace = text.lastIndexOf(\"}\");\n const endBracket = text.lastIndexOf(\"]\");\n const end = Math.max(endBrace, endBracket);\n if (start !== -1 && end !== -1 && end > start) {\n return text.slice(start, end + 1);\n }\n return text.trim();\n}\n\nfunction parseJson<T>(text: string, fallback: T): T {\n try {\n return JSON.parse(extractJson(text)) as T;\n } catch {\n return fallback;\n }\n}\n\n// ─── ClaudeAi ─────────────────────────────────────────────────────────────────\n\nexport class ClaudeAi implements AiClient {\n private readonly apiKey: string;\n private readonly model: string;\n\n /**\n * @param apiKey Anthropic API key. Falls back to ANTHROPIC_API_KEY env var.\n * @param model Model override. Falls back to GITX_AI_MODEL env var then default.\n */\n constructor(apiKey?: string, model?: string) {\n const key = apiKey ?? process.env[\"ANTHROPIC_API_KEY\"];\n if (!key) {\n throw new GitxError(\n \"No Anthropic API key available. Run `gitx config setup` or set ANTHROPIC_API_KEY.\",\n { exitCode: 2 }\n );\n }\n this.apiKey = key;\n this.model = getModel(model);\n }\n\n /** Check whether an API key is available without instantiating the class. */\n static isAvailable(key?: string): boolean {\n return Boolean(key ?? process.env[\"ANTHROPIC_API_KEY\"]);\n }\n\n async analyzeTask(input: string): Promise<AiAnalyzeTaskResponse> {\n const system = `You are an expert software engineer. Analyze the given development task and respond with ONLY valid JSON matching this exact structure (no prose, no markdown, just raw JSON):\n{\n \"task\": \"<the original task string>\",\n \"intent\": \"<one of: refactor | bugfix | feature | chore | unknown>\",\n \"summary\": \"<one sentence explaining what needs to be done>\",\n \"assumptions\": [\"<assumption 1>\", \"<assumption 2>\"],\n \"risks\": [\"<risk 1>\", \"<risk 2>\"]\n}`;\n\n const text = await callClaude(system, `Task: ${input}`, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiAnalyzeTaskResponse>>(text, {});\n return {\n task: input,\n intent: (parsed.intent as AiAnalyzeTaskResponse[\"intent\"]) ?? \"unknown\",\n summary: parsed.summary ?? \"Unable to analyze task.\",\n assumptions: Array.isArray(parsed.assumptions) ? parsed.assumptions : [],\n risks: Array.isArray(parsed.risks) ? parsed.risks : [],\n };\n }\n\n async generatePlan(context: unknown): Promise<AiGeneratePlanResponse> {\n const ctx = context as {\n task?: string;\n analysis?: AiAnalyzeTaskResponse;\n repoFiles?: string[];\n fileContents?: Record<string, string>;\n };\n\n const taskDesc = ctx.task ?? \"Unknown task\";\n const analysisSummary = ctx.analysis?.summary ?? \"\";\n const fileList = ctx.repoFiles?.slice(0, 50).join(\"\\n\") ?? \"(not provided)\";\n const fileContentsSection =\n ctx.fileContents && Object.keys(ctx.fileContents).length > 0\n ? `\\n\\nRelevant file contents:\\n${Object.entries(ctx.fileContents)\n .map(([p, c]) => `--- ${p} ---\\n${c}`)\n .join(\"\\n\\n\")}`\n : \"\";\n\n const system = `You are an expert software engineer creating a step-by-step implementation plan. Respond with ONLY valid JSON:\n{\n \"steps\": [\n { \"id\": \"step-1\", \"title\": \"<short title>\", \"description\": \"<detailed description of what to change and why>\" },\n { \"id\": \"step-2\", \"title\": \"<short title>\", \"description\": \"<detailed description>\" }\n ]\n}\nKeep steps atomic and ordered. Each step should touch one logical concern.`;\n\n const userPrompt = `Task: ${taskDesc}\nAnalysis: ${analysisSummary}\nRepo files (top 50):\n${fileList}${fileContentsSection}`;\n\n const text = await callClaude(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiGeneratePlanResponse>>(text, { steps: [] });\n const steps = Array.isArray(parsed.steps) ? parsed.steps : [];\n\n if (steps.length === 0) {\n return {\n steps: [\n { id: \"step-1\", title: \"Analyze & implement\", description: taskDesc },\n ],\n };\n }\n return { steps };\n }\n\n async generateDiffs(step: unknown): Promise<AiGenerateDiffsResponse> {\n const s = step as {\n id?: string;\n title?: string;\n description?: string;\n task?: string;\n analysis?: AiAnalyzeTaskResponse;\n fileContents?: Record<string, string>;\n };\n\n const stepId = s.id ?? \"step-1\";\n const fileContentsSection =\n s.fileContents && Object.keys(s.fileContents).length > 0\n ? `\\n\\nCurrent file contents (apply changes to these):\\n${Object.entries(s.fileContents)\n .map(([p, c]) => `--- ${p} ---\\n${c}`)\n .join(\"\\n\\n\")}`\n : \"\\n\\n(No existing file contents provided — create new files as needed.)\";\n\n const system = `You are an expert software engineer. Generate unified diffs for the given implementation step.\n\nRespond with ONLY valid JSON:\n{\n \"stepId\": \"<step id>\",\n \"diffs\": [\n {\n \"path\": \"<relative file path>\",\n \"unifiedDiff\": \"<valid unified diff content starting with --- a/path and +++ b/path>\"\n }\n ]\n}\n\nRules for unified diffs:\n- Start with: --- a/<path>\\\\n+++ b/<path>\n- Use @@ -<start>,<count> +<start>,<count> @@ context headers\n- Lines starting with ' ' are context (unchanged)\n- Lines starting with '-' are removed\n- Lines starting with '+' are added\n- For new files use: --- /dev/null\\\\n+++ b/<path>\n- For deleted files use: --- a/<path>\\\\n+++ /dev/null\n- Always include 3 lines of context around changes\n- Make minimal, precise changes`;\n\n const userPrompt = `Task: ${s.task ?? \"\"}\nStep ID: ${stepId}\nStep Title: ${s.title ?? \"\"}\nStep Description: ${s.description ?? \"\"}${fileContentsSection}`;\n\n const text = await callClaude(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiGenerateDiffsResponse>>(text, { stepId, diffs: [] });\n return {\n stepId,\n diffs: Array.isArray(parsed.diffs) ? parsed.diffs : [],\n };\n }\n\n async summarizeChanges(diff: unknown): Promise<AiSummarizeChangesResponse> {\n const d = diff as {\n diffs?: AiGenerateDiffsResponse[];\n rawDiff?: string;\n };\n\n const diffContent =\n d.rawDiff ??\n (d.diffs ?? [])\n .flatMap((dr) => dr.diffs.map((f) => `File: ${f.path}\\n${f.unifiedDiff}`))\n .join(\"\\n\\n\") ??\n \"(no diffs)\";\n\n const system = `You are a technical writer. Summarize code changes for a pull request. Respond with ONLY valid JSON:\n{\n \"summary\": \"<2-3 sentence plain-English summary of what changed and why>\",\n \"filesChanged\": [\n { \"path\": \"<file path>\", \"changeType\": \"<add | modify | delete>\" }\n ]\n}`;\n\n const text = await callClaude(system, `Changes:\\n${diffContent}`, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiSummarizeChangesResponse>>(text, {\n summary: \"\",\n filesChanged: [],\n });\n return {\n summary: parsed.summary ?? \"Code changes applied.\",\n filesChanged: Array.isArray(parsed.filesChanged) ? parsed.filesChanged : [],\n };\n }\n\n async suggestFixes(comment: unknown): Promise<AiSuggestFixesResponse> {\n const c = comment as {\n comments?: Array<{ body: string; path?: string; line?: number; author?: string }>;\n prTitle?: string;\n prBody?: string;\n fileContents?: Record<string, string>;\n };\n\n const commentsText = (c.comments ?? [])\n .map(\n (co) =>\n `[${co.author ?? \"reviewer\"}${co.path ? ` on ${co.path}:${co.line ?? \"\"}` : \"\"}]: ${co.body}`\n )\n .join(\"\\n\\n\");\n\n const fileContentsSection =\n c.fileContents && Object.keys(c.fileContents).length > 0\n ? `\\n\\nCurrent file contents:\\n${Object.entries(c.fileContents)\n .map(([p, content]) => `--- ${p} ---\\n${content}`)\n .join(\"\\n\\n\")}`\n : \"\";\n\n const system = `You are an expert code reviewer suggesting fixes for pull request review comments. Respond with ONLY valid JSON:\n{\n \"suggestedEdits\": [\n {\n \"path\": \"<file path>\",\n \"rationale\": \"<why this change addresses the comment>\",\n \"unifiedDiff\": \"<valid unified diff>\"\n }\n ]\n}\nIf a comment doesn't require a code change, omit it from suggestedEdits.`;\n\n const userPrompt = `PR Title: ${c.prTitle ?? \"\"}\nPR Body: ${c.prBody ?? \"\"}\n\nReview Comments:\n${commentsText}${fileContentsSection}`;\n\n const text = await callClaude(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiSuggestFixesResponse>>(text, { suggestedEdits: [] });\n return {\n suggestedEdits: Array.isArray(parsed.suggestedEdits) ? parsed.suggestedEdits : [],\n };\n }\n\n async reviewPR(context: unknown): Promise<AiReviewPRResponse> {\n const ctx = context as {\n prTitle?: string;\n prBody?: string;\n diff?: string;\n comments?: Array<{ body: string; author: string; path?: string }>;\n };\n\n const diffSection = ctx.diff\n ? `\\n\\nDiff (unified):\\n${ctx.diff.slice(0, 8000)}`\n : \"\";\n const commentsSection =\n ctx.comments && ctx.comments.length > 0\n ? `\\n\\nExisting review comments:\\n${ctx.comments.map((c) => `[${c.author}${c.path ? ` @ ${c.path}` : \"\"}]: ${c.body}`).join(\"\\n\")}`\n : \"\";\n\n const system = `You are an expert code reviewer. Review the given pull request thoroughly and respond with ONLY valid JSON:\n{\n \"summary\": \"<2-4 sentence overall assessment>\",\n \"issues\": [\n { \"severity\": \"<critical|warning|suggestion>\", \"description\": \"<specific issue>\", \"file\": \"<optional file>\", \"line\": null }\n ],\n \"positives\": [\"<good thing 1>\", \"<good thing 2>\"],\n \"verdict\": \"<approve|request_changes|comment>\"\n}\n\nSeverity guide:\n- critical: bugs, security issues, data loss risk\n- warning: code quality, performance, missing error handling\n- suggestion: style, naming, minor improvements`;\n\n const userPrompt = `PR Title: ${ctx.prTitle ?? \"\"}\nPR Description: ${ctx.prBody ?? \"\"}${diffSection}${commentsSection}`;\n\n const text = await callClaude(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiReviewPRResponse>>(text, {\n summary: \"\",\n issues: [],\n positives: [],\n verdict: \"comment\",\n });\n\n return {\n summary: parsed.summary ?? \"Review could not be generated.\",\n issues: Array.isArray(parsed.issues) ? parsed.issues : [],\n positives: Array.isArray(parsed.positives) ? parsed.positives : [],\n verdict: ([\"approve\", \"request_changes\", \"comment\"].includes(parsed.verdict ?? \"\"))\n ? (parsed.verdict as AiReviewPRResponse[\"verdict\"])\n : \"comment\",\n };\n }\n\n async generatePrContent(commits: string[], diff: string, stat?: string): Promise<import(\"./types.js\").AiPrContentResponse> {\n const system = `You are an expert software engineer writing pull request descriptions.\nYou are given a list of commits on the branch and the unified diff of all changes.\n\nThe input may contain:\n - \"=== Changed files (complete list) ===\" — the full --stat summary of every file touched\n - \"=== Detailed diff ===\" — the actual patch (may be truncated for large changesets)\n\nWhen a file list is present, use it as the authoritative source of ALL changed files.\nDo not ignore files that appear in the list but are absent from the truncated diff.\n\nProduce a clear, informative PR title and description:\n\nRules:\n- title: short, human-readable, present-tense (e.g. \"Add user authentication flow\")\n No conventional-commit prefix needed. Max 72 chars.\n- body: 2-4 sentences describing WHAT changed and WHY. Cover ALL files from the list.\n Plain English. Do not repeat the title. Do not use bullet points.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"title\":\"<PR title>\",\"body\":\"<PR description>\"}`;\n\n const commitList = commits.slice(0, 20).join(\"\\n\");\n const diffSection = stat\n ? `=== Changed files (complete list) ===\\n${stat}\\n\\n=== Detailed diff ===\\n${diff.slice(0, 16000)}`\n : `Diff:\\n${diff.slice(0, 16000)}`;\n const userPrompt = `Commits on this branch:\\n${commitList}\\n\\n${diffSection}`;\n const text = await callClaude(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<import(\"./types.js\").AiPrContentResponse>>(text, {});\n return {\n title: parsed.title?.trim() ?? \"Update branch\",\n body: parsed.body?.trim() ?? \"\",\n };\n }\n\n async resolveConflict(filePath: string, conflictContent: string): Promise<import(\"./types.js\").AiConflictResolutionResponse> {\n const system = `You are an expert software engineer resolving git merge conflicts.\n\nThe file contains standard git conflict markers:\n <<<<<<< HEAD (or <<<<<<< ours) — changes on the current branch\n ======= — separator\n >>>>>>> branch (or >>>>>>> theirs) — incoming changes being merged/rebased\n\nYour task:\n1. Understand BOTH sides of every conflict in the file.\n2. Produce a single correct version that preserves the intent of BOTH changes where possible.\n3. If the two sides are genuinely contradictory and cannot be safely merged, set confidence to \"low\".\n\nRules:\n- Remove ALL conflict markers (<<<<<<, =======, >>>>>>>) from the output.\n- Do NOT add comments explaining what you did.\n- Keep all non-conflicting code exactly as-is.\n- The output must be syntactically valid for the file type.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"resolved\":\"<full resolved file content>\",\"confidence\":\"high|low\",\"explanation\":\"<one sentence>\"}`;\n\n const userPrompt = `File: ${filePath}\\n\\n${conflictContent.slice(0, 20000)}`;\n const text = await callClaude(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<import(\"./types.js\").AiConflictResolutionResponse>>(text, {});\n return {\n resolved: parsed.resolved ?? conflictContent,\n confidence: parsed.confidence === \"low\" ? \"low\" : \"high\",\n explanation: parsed.explanation?.trim() ?? \"Conflict resolved.\",\n };\n }\n async generateCommitMessage(diff: string): Promise<import(\"./types.js\").AiCommitMessageResponse> {\n const system = `You are an expert software engineer writing git commit messages.\nYou receive either a plain unified diff OR a structured input with:\n - \"=== Changed files (complete list) ===\" — the full --stat summary of every file touched\n - \"=== Detailed diff ===\" — the actual patch (may be truncated for large changesets)\n\nWhen a file list is present, use it as the authoritative source of ALL changes.\nDo not ignore files that appear in the list but are missing from the truncated diff.\n\nProduce ONE CONVENTIONAL COMMIT covering all the changes:\n\nRules:\n- subject: \"<type>(<scope>): <imperative description>\"\n - type: feat | fix | refactor | chore | docs | test | perf | ci | style | build\n - scope: the primary area affected; omit if changes span many unrelated areas\n - description: imperative mood, no period, 72 chars max for the whole subject line\n - if several distinct features or fixes are present, pick the most impactful for the subject\n- body: cover EVERY significant change visible in the file list. For each distinct change,\n one sentence on what was done and why. Plain English, no bullet lists, no repetition of the subject.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"subject\":\"<subject line>\",\"body\":\"<body covering all changes, or empty string>\"}`;\n\n const text = await callClaude(system, `Diff:\\n${diff.slice(0, 20000)}`, this.apiKey, this.model);\n const parsed = parseJson<Partial<import(\"./types.js\").AiCommitMessageResponse>>(text, {});\n return {\n subject: parsed.subject?.trim() ?? \"chore: update files\",\n body: parsed.body?.trim() || undefined,\n };\n }\n\n async reviewPRDetailed(\n context: Parameters<import(\"./types.js\").AiClient[\"reviewPRDetailed\"]>[0]\n ): Promise<import(\"./types.js\").AiDetailedReviewResponse> {\n const { buildSeniorReviewSystem, buildSeniorReviewPrompt, parseSeniorReview } = await import(\"./reviewHelpers.js\");\n const text = await callClaude(\n buildSeniorReviewSystem(),\n buildSeniorReviewPrompt(context),\n this.apiKey,\n this.model\n );\n return parseSeniorReview(text);\n }\n\n async generateFix(\n context: Parameters<import(\"./types.js\").AiClient[\"generateFix\"]>[0]\n ): Promise<import(\"./types.js\").AiFixResponse> {\n const { buildFixSystem, buildFixPrompt, parseFixResponse } = await import(\"./reviewHelpers.js\");\n const text = await callClaude(\n buildFixSystem(),\n buildFixPrompt(context),\n this.apiKey,\n this.model\n );\n return parseFixResponse(text, context.filePath, context.line);\n }\n\n async ask(\n question: string,\n context: import(\"./types.js\").AiAskContext\n ): Promise<import(\"./types.js\").AiAskResponse> {\n const { buildAskSystem, buildAskPrompt, parseAskResponse } = await import(\"./reviewHelpers.js\");\n const text = await callClaude(buildAskSystem(), buildAskPrompt(question, context), this.apiKey, this.model);\n return parseAskResponse(text);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"claudeAi.js","sourceRoot":"","sources":["../../src/ai/claudeAi.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Claude AI integration via the Anthropic Messages API.\n *\n * Authentication: reads ANTHROPIC_API_KEY from the environment.\n * Model: defaults to claude-3-5-haiku-20241022 (fast, affordable).\n * Override via GITX_AI_MODEL env var.\n *\n * All methods send a structured system prompt and parse the JSON response.\n * If parsing fails we fall back gracefully rather than crashing.\n */\n\nimport axios, { isAxiosError } from \"axios\";\nimport { GitxError } from \"../utils/errors.js\";\nimport type {\n AiAnalyzeTaskResponse,\n AiClient,\n AiGenerateDiffsResponse,\n AiGeneratePlanResponse,\n AiReviewPRResponse,\n AiSuggestFixesResponse,\n AiSummarizeChangesResponse,\n} from \"./types.js\";\n\nconst ANTHROPIC_API = \"https://api.anthropic.com/v1/messages\";\nconst DEFAULT_MODEL = \"claude-3-5-haiku-20241022\";\nconst MAX_TOKENS = 4096;\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction getModel(override?: string): string {\n return process.env[\"GITX_AI_MODEL\"] ?? override ?? DEFAULT_MODEL;\n}\n\ninterface ClaudeMessage {\n role: \"user\" | \"assistant\";\n content: string;\n}\n\ninterface ClaudeRequestBody {\n model: string;\n max_tokens: number;\n system: string;\n messages: ClaudeMessage[];\n}\n\ninterface ClaudeResponseBody {\n content: Array<{ type: string; text: string }>;\n}\n\nasync function callClaude(system: string, userPrompt: string, apiKey: string, model: string): Promise<string> {\n const body: ClaudeRequestBody = {\n model,\n max_tokens: MAX_TOKENS,\n system,\n messages: [{ role: \"user\", content: userPrompt }],\n };\n\n try {\n const { data } = await axios.post<ClaudeResponseBody>(ANTHROPIC_API, body, {\n headers: {\n \"x-api-key\": apiKey,\n \"anthropic-version\": \"2023-06-01\",\n \"content-type\": \"application/json\",\n },\n timeout: 60_000,\n });\n\n const text = data.content.find((c) => c.type === \"text\")?.text ?? \"\";\n return text;\n } catch (err) {\n if (isAxiosError(err)) {\n const status = err.response?.status;\n const msg = (err.response?.data as Record<string, unknown> | undefined)?.error ?? err.message;\n if (status === 401) {\n throw new GitxError(\n \"Anthropic API authentication failed. Check ANTHROPIC_API_KEY.\",\n { exitCode: 1, cause: err }\n );\n }\n throw new GitxError(\n `Anthropic API error (${status ?? \"network\"}): ${String(msg)}`,\n { exitCode: 1, cause: err }\n );\n }\n throw new GitxError(`Unexpected AI error: ${String(err)}`, { exitCode: 1, cause: err });\n }\n}\n\n/**\n * Extract JSON from a Claude response that may include markdown code fences.\n * Claude sometimes wraps JSON in ```json ... ``` blocks.\n */\nfunction extractJson(text: string): string {\n const fenced = text.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n if (fenced?.[1]) return fenced[1].trim();\n // Find first { or [ and last } or ]\n const start = text.search(/[{[]/);\n const endBrace = text.lastIndexOf(\"}\");\n const endBracket = text.lastIndexOf(\"]\");\n const end = Math.max(endBrace, endBracket);\n if (start !== -1 && end !== -1 && end > start) {\n return text.slice(start, end + 1);\n }\n return text.trim();\n}\n\nfunction parseJson<T>(text: string, fallback: T): T {\n try {\n return JSON.parse(extractJson(text)) as T;\n } catch {\n return fallback;\n }\n}\n\n// ─── ClaudeAi ─────────────────────────────────────────────────────────────────\n\nexport class ClaudeAi implements AiClient {\n private readonly apiKey: string;\n private readonly model: string;\n\n /**\n * @param apiKey Anthropic API key. Falls back to ANTHROPIC_API_KEY env var.\n * @param model Model override. Falls back to GITX_AI_MODEL env var then default.\n */\n constructor(apiKey?: string, model?: string) {\n const key = apiKey ?? process.env[\"ANTHROPIC_API_KEY\"];\n if (!key) {\n throw new GitxError(\n \"No Anthropic API key available. Run `gitx config setup` or set ANTHROPIC_API_KEY.\",\n { exitCode: 2 }\n );\n }\n this.apiKey = key;\n this.model = getModel(model);\n }\n\n /** Check whether an API key is available without instantiating the class. */\n static isAvailable(key?: string): boolean {\n return Boolean(key ?? process.env[\"ANTHROPIC_API_KEY\"]);\n }\n\n async analyzeTask(input: string): Promise<AiAnalyzeTaskResponse> {\n const system = `You are an expert software engineer. Analyze the given development task and respond with ONLY valid JSON matching this exact structure (no prose, no markdown, just raw JSON):\n{\n \"task\": \"<the original task string>\",\n \"intent\": \"<one of: refactor | bugfix | feature | chore | unknown>\",\n \"summary\": \"<one sentence explaining what needs to be done>\",\n \"assumptions\": [\"<assumption 1>\", \"<assumption 2>\"],\n \"risks\": [\"<risk 1>\", \"<risk 2>\"]\n}`;\n\n const text = await callClaude(system, `Task: ${input}`, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiAnalyzeTaskResponse>>(text, {});\n return {\n task: input,\n intent: (parsed.intent as AiAnalyzeTaskResponse[\"intent\"]) ?? \"unknown\",\n summary: parsed.summary ?? \"Unable to analyze task.\",\n assumptions: Array.isArray(parsed.assumptions) ? parsed.assumptions : [],\n risks: Array.isArray(parsed.risks) ? parsed.risks : [],\n };\n }\n\n async generatePlan(context: unknown): Promise<AiGeneratePlanResponse> {\n const ctx = context as {\n task?: string;\n analysis?: AiAnalyzeTaskResponse;\n repoFiles?: string[];\n fileContents?: Record<string, string>;\n };\n\n const taskDesc = ctx.task ?? \"Unknown task\";\n const analysisSummary = ctx.analysis?.summary ?? \"\";\n const fileList = ctx.repoFiles?.slice(0, 50).join(\"\\n\") ?? \"(not provided)\";\n const fileContentsSection =\n ctx.fileContents && Object.keys(ctx.fileContents).length > 0\n ? `\\n\\nRelevant file contents:\\n${Object.entries(ctx.fileContents)\n .map(([p, c]) => `--- ${p} ---\\n${c}`)\n .join(\"\\n\\n\")}`\n : \"\";\n\n const system = `You are an expert software engineer creating a step-by-step implementation plan. Respond with ONLY valid JSON:\n{\n \"steps\": [\n { \"id\": \"step-1\", \"title\": \"<short title>\", \"description\": \"<detailed description of what to change and why>\" },\n { \"id\": \"step-2\", \"title\": \"<short title>\", \"description\": \"<detailed description>\" }\n ]\n}\nKeep steps atomic and ordered. Each step should touch one logical concern.`;\n\n const userPrompt = `Task: ${taskDesc}\nAnalysis: ${analysisSummary}\nRepo files (top 50):\n${fileList}${fileContentsSection}`;\n\n const text = await callClaude(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiGeneratePlanResponse>>(text, { steps: [] });\n const steps = Array.isArray(parsed.steps) ? parsed.steps : [];\n\n if (steps.length === 0) {\n return {\n steps: [\n { id: \"step-1\", title: \"Analyze & implement\", description: taskDesc },\n ],\n };\n }\n return { steps };\n }\n\n async generateDiffs(step: unknown): Promise<AiGenerateDiffsResponse> {\n const s = step as {\n id?: string;\n title?: string;\n description?: string;\n task?: string;\n analysis?: AiAnalyzeTaskResponse;\n fileContents?: Record<string, string>;\n };\n\n const stepId = s.id ?? \"step-1\";\n const fileContentsSection =\n s.fileContents && Object.keys(s.fileContents).length > 0\n ? `\\n\\nCurrent file contents (apply changes to these):\\n${Object.entries(s.fileContents)\n .map(([p, c]) => `--- ${p} ---\\n${c}`)\n .join(\"\\n\\n\")}`\n : \"\\n\\n(No existing file contents provided — create new files as needed.)\";\n\n const system = `You are an expert software engineer. Generate unified diffs for the given implementation step.\n\nRespond with ONLY valid JSON:\n{\n \"stepId\": \"<step id>\",\n \"diffs\": [\n {\n \"path\": \"<relative file path>\",\n \"unifiedDiff\": \"<valid unified diff content starting with --- a/path and +++ b/path>\"\n }\n ]\n}\n\nRules for unified diffs:\n- Start with: --- a/<path>\\\\n+++ b/<path>\n- Use @@ -<start>,<count> +<start>,<count> @@ context headers\n- Lines starting with ' ' are context (unchanged)\n- Lines starting with '-' are removed\n- Lines starting with '+' are added\n- For new files use: --- /dev/null\\\\n+++ b/<path>\n- For deleted files use: --- a/<path>\\\\n+++ /dev/null\n- Always include 3 lines of context around changes\n- Make minimal, precise changes`;\n\n const userPrompt = `Task: ${s.task ?? \"\"}\nStep ID: ${stepId}\nStep Title: ${s.title ?? \"\"}\nStep Description: ${s.description ?? \"\"}${fileContentsSection}`;\n\n const text = await callClaude(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiGenerateDiffsResponse>>(text, { stepId, diffs: [] });\n return {\n stepId,\n diffs: Array.isArray(parsed.diffs) ? parsed.diffs : [],\n };\n }\n\n async summarizeChanges(diff: unknown): Promise<AiSummarizeChangesResponse> {\n const d = diff as {\n diffs?: AiGenerateDiffsResponse[];\n rawDiff?: string;\n };\n\n const diffContent =\n d.rawDiff ??\n (d.diffs ?? [])\n .flatMap((dr) => dr.diffs.map((f) => `File: ${f.path}\\n${f.unifiedDiff}`))\n .join(\"\\n\\n\") ??\n \"(no diffs)\";\n\n const system = `You are a technical writer. Summarize code changes for a pull request. Respond with ONLY valid JSON:\n{\n \"summary\": \"<2-3 sentence plain-English summary of what changed and why>\",\n \"filesChanged\": [\n { \"path\": \"<file path>\", \"changeType\": \"<add | modify | delete>\" }\n ]\n}`;\n\n const text = await callClaude(system, `Changes:\\n${diffContent}`, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiSummarizeChangesResponse>>(text, {\n summary: \"\",\n filesChanged: [],\n });\n return {\n summary: parsed.summary ?? \"Code changes applied.\",\n filesChanged: Array.isArray(parsed.filesChanged) ? parsed.filesChanged : [],\n };\n }\n\n async suggestFixes(comment: unknown): Promise<AiSuggestFixesResponse> {\n const { buildSuggestFixesSystem, buildSuggestFixesPrompt, parseSuggestFixesResponse } =\n await import(\"./reviewHelpers.js\");\n const ctx = comment as Parameters<typeof buildSuggestFixesPrompt>[0];\n const text = await callClaude(\n buildSuggestFixesSystem(),\n buildSuggestFixesPrompt(ctx),\n this.apiKey,\n this.model\n );\n return parseSuggestFixesResponse(text);\n }\n\n async reviewPR(context: unknown): Promise<AiReviewPRResponse> {\n const ctx = context as {\n prTitle?: string;\n prBody?: string;\n diff?: string;\n comments?: Array<{ body: string; author: string; path?: string }>;\n };\n\n const diffSection = ctx.diff\n ? `\\n\\nDiff (unified):\\n${ctx.diff.slice(0, 8000)}`\n : \"\";\n const commentsSection =\n ctx.comments && ctx.comments.length > 0\n ? `\\n\\nExisting review comments:\\n${ctx.comments.map((c) => `[${c.author}${c.path ? ` @ ${c.path}` : \"\"}]: ${c.body}`).join(\"\\n\")}`\n : \"\";\n\n const system = `You are an expert code reviewer. Review the given pull request thoroughly and respond with ONLY valid JSON:\n{\n \"summary\": \"<2-4 sentence overall assessment>\",\n \"issues\": [\n { \"severity\": \"<critical|warning|suggestion>\", \"description\": \"<specific issue>\", \"file\": \"<optional file>\", \"line\": null }\n ],\n \"positives\": [\"<good thing 1>\", \"<good thing 2>\"],\n \"verdict\": \"<approve|request_changes|comment>\"\n}\n\nSeverity guide:\n- critical: bugs, security issues, data loss risk\n- warning: code quality, performance, missing error handling\n- suggestion: style, naming, minor improvements`;\n\n const userPrompt = `PR Title: ${ctx.prTitle ?? \"\"}\nPR Description: ${ctx.prBody ?? \"\"}${diffSection}${commentsSection}`;\n\n const text = await callClaude(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<AiReviewPRResponse>>(text, {\n summary: \"\",\n issues: [],\n positives: [],\n verdict: \"comment\",\n });\n\n return {\n summary: parsed.summary ?? \"Review could not be generated.\",\n issues: Array.isArray(parsed.issues) ? parsed.issues : [],\n positives: Array.isArray(parsed.positives) ? parsed.positives : [],\n verdict: ([\"approve\", \"request_changes\", \"comment\"].includes(parsed.verdict ?? \"\"))\n ? (parsed.verdict as AiReviewPRResponse[\"verdict\"])\n : \"comment\",\n };\n }\n\n async generatePrContent(commits: string[], diff: string, stat?: string): Promise<import(\"./types.js\").AiPrContentResponse> {\n const system = `You are an expert software engineer writing pull request descriptions.\nYou are given a list of commits on the branch and the unified diff of all changes.\n\nThe input may contain:\n - \"=== Changed files (complete list) ===\" — the full --stat summary of every file touched\n - \"=== Detailed diff ===\" — the actual patch (may be truncated for large changesets)\n\nWhen a file list is present, use it as the authoritative source of ALL changed files.\nDo not ignore files that appear in the list but are absent from the truncated diff.\n\nProduce a clear, informative PR title and description:\n\nRules:\n- title: short, human-readable, present-tense (e.g. \"Add user authentication flow\")\n No conventional-commit prefix needed. Max 72 chars.\n- body: 2-4 sentences describing WHAT changed and WHY. Cover ALL files from the list.\n Plain English. Do not repeat the title. Do not use bullet points.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"title\":\"<PR title>\",\"body\":\"<PR description>\"}`;\n\n const commitList = commits.slice(0, 20).join(\"\\n\");\n const diffSection = stat\n ? `=== Changed files (complete list) ===\\n${stat}\\n\\n=== Detailed diff ===\\n${diff.slice(0, 16000)}`\n : `Diff:\\n${diff.slice(0, 16000)}`;\n const userPrompt = `Commits on this branch:\\n${commitList}\\n\\n${diffSection}`;\n const text = await callClaude(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<import(\"./types.js\").AiPrContentResponse>>(text, {});\n return {\n title: parsed.title?.trim() ?? \"Update branch\",\n body: parsed.body?.trim() ?? \"\",\n };\n }\n\n async resolveConflict(filePath: string, conflictContent: string): Promise<import(\"./types.js\").AiConflictResolutionResponse> {\n const system = `You are an expert software engineer resolving git merge conflicts.\n\nThe file contains standard git conflict markers:\n <<<<<<< HEAD (or <<<<<<< ours) — changes on the current branch\n ======= — separator\n >>>>>>> branch (or >>>>>>> theirs) — incoming changes being merged/rebased\n\nYour task:\n1. Understand BOTH sides of every conflict in the file.\n2. Produce a single correct version that preserves the intent of BOTH changes where possible.\n3. If the two sides are genuinely contradictory and cannot be safely merged, set confidence to \"low\".\n\nRules:\n- Remove ALL conflict markers (<<<<<<, =======, >>>>>>>) from the output.\n- Do NOT add comments explaining what you did.\n- Keep all non-conflicting code exactly as-is.\n- The output must be syntactically valid for the file type.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"resolved\":\"<full resolved file content>\",\"confidence\":\"high|low\",\"explanation\":\"<one sentence>\"}`;\n\n const userPrompt = `File: ${filePath}\\n\\n${conflictContent.slice(0, 20000)}`;\n const text = await callClaude(system, userPrompt, this.apiKey, this.model);\n const parsed = parseJson<Partial<import(\"./types.js\").AiConflictResolutionResponse>>(text, {});\n return {\n resolved: parsed.resolved ?? conflictContent,\n confidence: parsed.confidence === \"low\" ? \"low\" : \"high\",\n explanation: parsed.explanation?.trim() ?? \"Conflict resolved.\",\n };\n }\n async generateCommitMessage(diff: string): Promise<import(\"./types.js\").AiCommitMessageResponse> {\n const system = `You are an expert software engineer writing git commit messages.\nYou receive either a plain unified diff OR a structured input with:\n - \"=== Changed files (complete list) ===\" — the full --stat summary of every file touched\n - \"=== Detailed diff ===\" — the actual patch (may be truncated for large changesets)\n\nWhen a file list is present, use it as the authoritative source of ALL changes.\nDo not ignore files that appear in the list but are missing from the truncated diff.\n\nProduce ONE CONVENTIONAL COMMIT covering all the changes:\n\nRules:\n- subject: \"<type>(<scope>): <imperative description>\"\n - type: feat | fix | refactor | chore | docs | test | perf | ci | style | build\n - scope: the primary area affected; omit if changes span many unrelated areas\n - description: imperative mood, no period, 72 chars max for the whole subject line\n - if several distinct features or fixes are present, pick the most impactful for the subject\n- body: cover EVERY significant change visible in the file list. For each distinct change,\n one sentence on what was done and why. Plain English, no bullet lists, no repetition of the subject.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"subject\":\"<subject line>\",\"body\":\"<body covering all changes, or empty string>\"}`;\n\n const text = await callClaude(system, `Diff:\\n${diff.slice(0, 20000)}`, this.apiKey, this.model);\n const parsed = parseJson<Partial<import(\"./types.js\").AiCommitMessageResponse>>(text, {});\n return {\n subject: parsed.subject?.trim() ?? \"chore: update files\",\n body: parsed.body?.trim() || undefined,\n };\n }\n\n async reviewPRDetailed(\n context: Parameters<import(\"./types.js\").AiClient[\"reviewPRDetailed\"]>[0]\n ): Promise<import(\"./types.js\").AiDetailedReviewResponse> {\n const { buildSeniorReviewSystem, buildSeniorReviewPrompt, parseSeniorReview } = await import(\"./reviewHelpers.js\");\n const text = await callClaude(\n buildSeniorReviewSystem(),\n buildSeniorReviewPrompt(context),\n this.apiKey,\n this.model\n );\n return parseSeniorReview(text);\n }\n\n async generateFix(\n context: Parameters<import(\"./types.js\").AiClient[\"generateFix\"]>[0]\n ): Promise<import(\"./types.js\").AiFixResponse> {\n const { buildFixSystem, buildFixPrompt, parseFixResponse } = await import(\"./reviewHelpers.js\");\n const text = await callClaude(\n buildFixSystem(),\n buildFixPrompt(context),\n this.apiKey,\n this.model\n );\n return parseFixResponse(text, context.filePath, context.line);\n }\n\n async ask(\n question: string,\n context: import(\"./types.js\").AiAskContext\n ): Promise<import(\"./types.js\").AiAskResponse> {\n const { buildAskSystem, buildAskPrompt, parseAskResponse } = await import(\"./reviewHelpers.js\");\n const text = await callClaude(buildAskSystem(), buildAskPrompt(question, context), this.apiKey, this.model);\n return parseAskResponse(text);\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claudeCliAi.d.ts","sourceRoot":"","sources":["../../src/ai/claudeCliAi.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EACV,qBAAqB,EACrB,QAAQ,EACR,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AA6DpB,qBAAa,WAAY,YAAW,QAAQ;IAC1C;;OAEG;WACU,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAUtC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAe1D,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAiC/D,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAuC9D,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAoBpE,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"claudeCliAi.d.ts","sourceRoot":"","sources":["../../src/ai/claudeCliAi.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EACV,qBAAqB,EACrB,QAAQ,EACR,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AA6DpB,qBAAa,WAAY,YAAW,QAAQ;IAC1C;;OAEG;WACU,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAUtC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAe1D,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAiC/D,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAuC9D,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAoBpE,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAQ/D,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA0CvD,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,mBAAmB,CAAC;IAkCpH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,4BAA4B,CAAC;IA+BtH,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,uBAAuB,CAAC;IA+B1F,gBAAgB,CACpB,OAAO,EAAE,UAAU,CAAC,OAAO,YAAY,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,GACxE,OAAO,CAAC,OAAO,YAAY,EAAE,wBAAwB,CAAC;IAUnD,WAAW,CACf,OAAO,EAAE,UAAU,CAAC,OAAO,YAAY,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,GACnE,OAAO,CAAC,OAAO,YAAY,EAAE,aAAa,CAAC;IAUxC,GAAG,CACP,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,YAAY,EAAE,YAAY,GACzC,OAAO,CAAC,OAAO,YAAY,EAAE,aAAa,CAAC;CAK/C"}
|
package/dist/ai/claudeCliAi.js
CHANGED
|
@@ -149,27 +149,10 @@ Description: ${s.description ?? ""}${fileContentsSection}`;
|
|
|
149
149
|
};
|
|
150
150
|
}
|
|
151
151
|
async suggestFixes(comment) {
|
|
152
|
-
const
|
|
153
|
-
const
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
const fileContentsSection = c.fileContents && Object.keys(c.fileContents).length > 0
|
|
157
|
-
? `\n\nCurrent file contents:\n${Object.entries(c.fileContents)
|
|
158
|
-
.map(([p, content]) => `--- ${p} ---\n${content}`)
|
|
159
|
-
.join("\n\n")}`
|
|
160
|
-
: "";
|
|
161
|
-
const system = `You are an expert code reviewer. Suggest fixes for PR review comments. Respond with ONLY valid JSON:
|
|
162
|
-
{"suggestedEdits":[{"path":"<file>","rationale":"<why>","unifiedDiff":"<valid unified diff>"}]}
|
|
163
|
-
Omit comments that need no code change.`;
|
|
164
|
-
const userPrompt = `PR: ${c.prTitle ?? ""}
|
|
165
|
-
${c.prBody ?? ""}
|
|
166
|
-
|
|
167
|
-
Review Comments:\n${commentsText}${fileContentsSection}`;
|
|
168
|
-
const text = await callClaudeCli(system, userPrompt);
|
|
169
|
-
const parsed = parseJson(text, { suggestedEdits: [] });
|
|
170
|
-
return {
|
|
171
|
-
suggestedEdits: Array.isArray(parsed.suggestedEdits) ? parsed.suggestedEdits : [],
|
|
172
|
-
};
|
|
152
|
+
const { buildSuggestFixesSystem, buildSuggestFixesPrompt, parseSuggestFixesResponse } = await import("./reviewHelpers.js");
|
|
153
|
+
const ctx = comment;
|
|
154
|
+
const text = await callClaudeCli(buildSuggestFixesSystem(), buildSuggestFixesPrompt(ctx));
|
|
155
|
+
return parseSuggestFixesResponse(text);
|
|
173
156
|
}
|
|
174
157
|
async reviewPR(context) {
|
|
175
158
|
const ctx = context;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"claudeCliAi.js","sourceRoot":"","sources":["../../src/ai/claudeCliAi.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ClaudeCliAi — uses the locally installed `claude` CLI (Claude Code)\n * as an AI backend. No API key required; uses the user's existing Claude login.\n *\n * Detection: `claude --version`\n * Invocation: `claude -p \"<combined system+user prompt>\"`\n */\n\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { GitxError } from \"../utils/errors.js\";\nimport type {\n AiAnalyzeTaskResponse,\n AiClient,\n AiGenerateDiffsResponse,\n AiGeneratePlanResponse,\n AiReviewPRResponse,\n AiSuggestFixesResponse,\n AiSummarizeChangesResponse,\n} from \"./types.js\";\n\nconst execFileAsync = promisify(execFile);\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\nasync function callClaudeCli(\n systemPrompt: string,\n userPrompt: string,\n opts: { timeoutMs?: number; maxOutputChars?: number } = {}\n): Promise<string> {\n const timeoutMs = opts.timeoutMs ?? 120_000;\n const maxOutputChars = opts.maxOutputChars ?? 12_000;\n const combined = `<system>\\n${systemPrompt}\\n</system>\\n\\n${userPrompt}`;\n\n let stdout: string;\n try {\n const result = await execFileAsync(\"claude\", [\"-p\", combined], {\n timeout: timeoutMs,\n maxBuffer: 20 * 1024 * 1024,\n });\n stdout = result.stdout;\n } catch (err: unknown) {\n const e = err as { code?: string; message?: string; killed?: boolean };\n if (e.code === \"ENOENT\") {\n throw new GitxError(\n \"Claude CLI not found. Install Claude Code from https://claude.ai/download\",\n { exitCode: 2 }\n );\n }\n if (e.killed) {\n const secs = Math.round(timeoutMs / 1000);\n throw new GitxError(`Claude CLI timed out (>${secs}s). Try reducing the number of changed files or use --no-comment.`, { exitCode: 1 });\n }\n throw new GitxError(`Claude CLI error: ${e.message ?? String(err)}`, { exitCode: 1 });\n }\n\n return stdout.trim().slice(0, maxOutputChars);\n}\n\nfunction extractJson(text: string): string {\n const fenced = text.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n if (fenced?.[1]) return fenced[1].trim();\n const start = text.search(/[{[]/);\n const endBrace = text.lastIndexOf(\"}\");\n const endBracket = text.lastIndexOf(\"]\");\n const end = Math.max(endBrace, endBracket);\n if (start !== -1 && end !== -1 && end > start) return text.slice(start, end + 1);\n return text.trim();\n}\n\nfunction parseJson<T>(text: string, fallback: T): T {\n try {\n return JSON.parse(extractJson(text)) as T;\n } catch {\n return fallback;\n }\n}\n\n// ─── ClaudeCliAi ──────────────────────────────────────────────────────────────\n\nexport class ClaudeCliAi implements AiClient {\n /**\n * Returns true if the `claude` CLI binary is installed and accessible.\n */\n static async isAvailable(): Promise<boolean> {\n try {\n await execFileAsync(\"claude\", [\"--version\"], { timeout: 8_000 });\n return true;\n } catch (err: unknown) {\n const e = err as { code?: string };\n return e.code !== \"ENOENT\";\n }\n }\n\n async analyzeTask(input: string): Promise<AiAnalyzeTaskResponse> {\n const system = `You are an expert software engineer. Analyze the development task and respond with ONLY valid JSON:\n{\"task\":\"<original task>\",\"intent\":\"<refactor|bugfix|feature|chore|unknown>\",\"summary\":\"<one sentence>\",\"assumptions\":[\"...\"],\"risks\":[\"...\"]}`;\n\n const text = await callClaudeCli(system, `Task: ${input}`);\n const parsed = parseJson<Partial<AiAnalyzeTaskResponse>>(text, {});\n return {\n task: input,\n intent: (parsed.intent as AiAnalyzeTaskResponse[\"intent\"]) ?? \"unknown\",\n summary: parsed.summary ?? \"Unable to analyze task.\",\n assumptions: Array.isArray(parsed.assumptions) ? parsed.assumptions : [],\n risks: Array.isArray(parsed.risks) ? parsed.risks : [],\n };\n }\n\n async generatePlan(context: unknown): Promise<AiGeneratePlanResponse> {\n const ctx = context as {\n task?: string;\n analysis?: AiAnalyzeTaskResponse;\n repoFiles?: string[];\n fileContents?: Record<string, string>;\n };\n\n const fileList = ctx.repoFiles?.slice(0, 50).join(\"\\n\") ?? \"(not provided)\";\n const fileContentsSection =\n ctx.fileContents && Object.keys(ctx.fileContents).length > 0\n ? `\\n\\nRelevant file contents:\\n${Object.entries(ctx.fileContents)\n .map(([p, c]) => `--- ${p} ---\\n${c}`)\n .join(\"\\n\\n\")}`\n : \"\";\n\n const system = `You are an expert software engineer creating a step-by-step implementation plan. Respond with ONLY valid JSON:\n{\"steps\":[{\"id\":\"step-1\",\"title\":\"<short title>\",\"description\":\"<detailed description>\"}]}\nKeep steps atomic and ordered.`;\n\n const userPrompt = `Task: ${ctx.task ?? \"\"}\nAnalysis: ${ctx.analysis?.summary ?? \"\"}\nRepo files (top 50):\n${fileList}${fileContentsSection}`;\n\n const text = await callClaudeCli(system, userPrompt);\n const parsed = parseJson<Partial<AiGeneratePlanResponse>>(text, { steps: [] });\n const steps = Array.isArray(parsed.steps) ? parsed.steps : [];\n return steps.length > 0\n ? { steps }\n : { steps: [{ id: \"step-1\", title: \"Analyze & implement\", description: ctx.task ?? \"\" }] };\n }\n\n async generateDiffs(step: unknown): Promise<AiGenerateDiffsResponse> {\n const s = step as {\n id?: string;\n title?: string;\n description?: string;\n task?: string;\n fileContents?: Record<string, string>;\n };\n\n const stepId = s.id ?? \"step-1\";\n const fileContentsSection =\n s.fileContents && Object.keys(s.fileContents).length > 0\n ? `\\n\\nCurrent file contents:\\n${Object.entries(s.fileContents)\n .map(([p, c]) => `--- ${p} ---\\n${c}`)\n .join(\"\\n\\n\")}`\n : \"\\n\\n(No existing file contents — create new files as needed.)\";\n\n const system = `You are an expert software engineer. Generate unified diffs. Respond with ONLY valid JSON:\n{\"stepId\":\"<id>\",\"diffs\":[{\"path\":\"<file path>\",\"unifiedDiff\":\"<valid unified diff starting with --- a/path and +++ b/path>\"}]}\n\nUnified diff rules:\n- Start with: --- a/<path>\\\\n+++ b/<path>\n- Use @@ -<start>,<count> +<start>,<count> @@ headers\n- ' ' = context, '-' = removed, '+' = added\n- New files: --- /dev/null\\\\n+++ b/<path>\n- Include 3 lines of context around changes`;\n\n const userPrompt = `Task: ${s.task ?? \"\"}\nStep: ${stepId} — ${s.title ?? \"\"}\nDescription: ${s.description ?? \"\"}${fileContentsSection}`;\n\n const text = await callClaudeCli(system, userPrompt);\n const parsed = parseJson<Partial<AiGenerateDiffsResponse>>(text, { stepId, diffs: [] });\n return {\n stepId,\n diffs: Array.isArray(parsed.diffs) ? parsed.diffs : [],\n };\n }\n\n async summarizeChanges(diff: unknown): Promise<AiSummarizeChangesResponse> {\n const d = diff as { diffs?: AiGenerateDiffsResponse[]; rawDiff?: string };\n const diffContent =\n d.rawDiff ??\n (d.diffs ?? [])\n .flatMap((dr) => dr.diffs.map((f) => `File: ${f.path}\\n${f.unifiedDiff}`))\n .join(\"\\n\\n\") ??\n \"(no diffs)\";\n\n const system = `You are a technical writer. Summarize code changes for a PR. Respond with ONLY valid JSON:\n{\"summary\":\"<2-3 sentence summary>\",\"filesChanged\":[{\"path\":\"<file>\",\"changeType\":\"<add|modify|delete>\"}]}`;\n\n const text = await callClaudeCli(system, `Changes:\\n${diffContent}`);\n const parsed = parseJson<Partial<AiSummarizeChangesResponse>>(text, { summary: \"\", filesChanged: [] });\n return {\n summary: parsed.summary ?? \"Code changes applied.\",\n filesChanged: Array.isArray(parsed.filesChanged) ? parsed.filesChanged : [],\n };\n }\n\n async suggestFixes(comment: unknown): Promise<AiSuggestFixesResponse> {\n const c = comment as {\n comments?: Array<{ body: string; path?: string; line?: number; author?: string }>;\n prTitle?: string;\n prBody?: string;\n fileContents?: Record<string, string>;\n };\n\n const commentsText = (c.comments ?? [])\n .map((co) => `[${co.author ?? \"reviewer\"}${co.path ? ` on ${co.path}:${co.line ?? \"\"}` : \"\"}]: ${co.body}`)\n .join(\"\\n\\n\");\n\n const fileContentsSection =\n c.fileContents && Object.keys(c.fileContents).length > 0\n ? `\\n\\nCurrent file contents:\\n${Object.entries(c.fileContents)\n .map(([p, content]) => `--- ${p} ---\\n${content}`)\n .join(\"\\n\\n\")}`\n : \"\";\n\n const system = `You are an expert code reviewer. Suggest fixes for PR review comments. Respond with ONLY valid JSON:\n{\"suggestedEdits\":[{\"path\":\"<file>\",\"rationale\":\"<why>\",\"unifiedDiff\":\"<valid unified diff>\"}]}\nOmit comments that need no code change.`;\n\n const userPrompt = `PR: ${c.prTitle ?? \"\"}\n${c.prBody ?? \"\"}\n\nReview Comments:\\n${commentsText}${fileContentsSection}`;\n\n const text = await callClaudeCli(system, userPrompt);\n const parsed = parseJson<Partial<AiSuggestFixesResponse>>(text, { suggestedEdits: [] });\n return {\n suggestedEdits: Array.isArray(parsed.suggestedEdits) ? parsed.suggestedEdits : [],\n };\n }\n\n async reviewPR(context: unknown): Promise<AiReviewPRResponse> {\n const ctx = context as {\n prTitle?: string;\n prBody?: string;\n diff?: string;\n comments?: Array<{ body: string; author: string; path?: string }>;\n };\n\n const diffSection = ctx.diff ? `\\n\\nDiff:\\n${ctx.diff.slice(0, 8000)}` : \"\";\n const commentsSection =\n ctx.comments && ctx.comments.length > 0\n ? `\\n\\nExisting review comments:\\n${ctx.comments\n .map((c) => `[${c.author}${c.path ? ` @ ${c.path}` : \"\"}]: ${c.body}`)\n .join(\"\\n\")}`\n : \"\";\n\n const system = `You are an expert code reviewer. Review the PR and respond with ONLY valid JSON:\n{\"summary\":\"<2-4 sentence assessment>\",\"issues\":[{\"severity\":\"<critical|warning|suggestion>\",\"description\":\"<issue>\",\"file\":\"<optional>\",\"line\":null}],\"positives\":[\"<good thing>\"],\"verdict\":\"<approve|request_changes|comment>\"}\n\nSeverity: critical=bugs/security, warning=quality/perf, suggestion=style/naming`;\n\n const userPrompt = `PR Title: ${ctx.prTitle ?? \"\"}\nPR Description: ${ctx.prBody ?? \"\"}${diffSection}${commentsSection}`;\n\n const text = await callClaudeCli(system, userPrompt);\n const parsed = parseJson<Partial<AiReviewPRResponse>>(text, {\n summary: \"\",\n issues: [],\n positives: [],\n verdict: \"comment\",\n });\n\n return {\n summary: parsed.summary ?? \"Review could not be generated.\",\n issues: Array.isArray(parsed.issues) ? parsed.issues : [],\n positives: Array.isArray(parsed.positives) ? parsed.positives : [],\n verdict: ([\"approve\", \"request_changes\", \"comment\"].includes(parsed.verdict ?? \"\"))\n ? (parsed.verdict as AiReviewPRResponse[\"verdict\"])\n : \"comment\",\n };\n }\n\n async generatePrContent(commits: string[], diff: string, stat?: string): Promise<import(\"./types.js\").AiPrContentResponse> {\n const system = `You are an expert software engineer writing pull request descriptions.\nYou are given a list of commits on the branch and the unified diff of all changes.\n\nThe input may contain:\n - \"=== Changed files (complete list) ===\" — the full --stat summary of every file touched\n - \"=== Detailed diff ===\" — the actual patch (may be truncated for large changesets)\n\nWhen a file list is present, use it as the authoritative source of ALL changed files.\nDo not ignore files that appear in the list but are absent from the truncated diff.\n\nProduce a clear, informative PR title and description:\n\nRules:\n- title: short, human-readable, present-tense. No conventional-commit prefix. Max 72 chars.\n- body: 2-4 sentences describing WHAT changed and WHY. Cover ALL files from the list.\n Plain English, no bullet points.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"title\":\"<PR title>\",\"body\":\"<PR description>\"}`;\n\n const commitList = commits.slice(0, 20).join(\"\\n\");\n const diffSection = stat\n ? `=== Changed files (complete list) ===\\n${stat}\\n\\n=== Detailed diff ===\\n${diff.slice(0, 16000)}`\n : `Diff:\\n${diff.slice(0, 16000)}`;\n const userPrompt = `Commits on this branch:\\n${commitList}\\n\\n${diffSection}`;\n const text = await callClaudeCli(system, userPrompt);\n const parsed = parseJson<Partial<import(\"./types.js\").AiPrContentResponse>>(text, {});\n return {\n title: parsed.title?.trim() ?? \"Update branch\",\n body: parsed.body?.trim() ?? \"\",\n };\n }\n\n async resolveConflict(filePath: string, conflictContent: string): Promise<import(\"./types.js\").AiConflictResolutionResponse> {\n const system = `You are an expert software engineer resolving git merge conflicts.\n\nThe file contains standard git conflict markers:\n <<<<<<< HEAD — changes on the current branch\n ======= — separator\n >>>>>>> theirs — incoming changes\n\nYour task:\n1. Understand BOTH sides of every conflict.\n2. Produce a single correct version preserving the intent of BOTH changes where possible.\n3. If the sides are genuinely contradictory, set confidence to \"low\".\n\nRules:\n- Remove ALL conflict markers from the output.\n- Do NOT add explanatory comments.\n- Keep all non-conflicting code exactly as-is.\n- Output must be syntactically valid.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"resolved\":\"<full resolved file content>\",\"confidence\":\"high|low\",\"explanation\":\"<one sentence>\"}`;\n\n const userPrompt = `File: ${filePath}\\n\\n${conflictContent.slice(0, 20000)}`;\n const text = await callClaudeCli(system, userPrompt);\n const parsed = parseJson<Partial<import(\"./types.js\").AiConflictResolutionResponse>>(text, {});\n return {\n resolved: parsed.resolved ?? conflictContent,\n confidence: parsed.confidence === \"low\" ? \"low\" : \"high\",\n explanation: parsed.explanation?.trim() ?? \"Conflict resolved.\",\n };\n }\n async generateCommitMessage(diff: string): Promise<import(\"./types.js\").AiCommitMessageResponse> {\n const system = `You are an expert software engineer writing git commit messages.\nYou receive either a plain unified diff OR a structured input with:\n - \"=== Changed files (complete list) ===\" — the full --stat summary of every file touched\n - \"=== Detailed diff ===\" — the actual patch (may be truncated for large changesets)\n\nWhen a file list is present, use it as the authoritative source of ALL changes.\nDo not ignore files that appear in the list but are missing from the truncated diff.\n\nProduce ONE CONVENTIONAL COMMIT covering all the changes:\n\nRules:\n- subject: \"<type>(<scope>): <imperative description>\"\n - type: feat | fix | refactor | chore | docs | test | perf | ci | style | build\n - scope: the primary area affected; omit if changes span many unrelated areas\n - description: imperative mood, no period, 72 chars max for the whole subject line\n - if several distinct features or fixes are present, pick the most impactful for the subject\n- body: cover EVERY significant change visible in the file list. For each distinct change,\n one sentence on what was done and why. Plain English, no bullet lists, no repetition of the subject.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"subject\":\"<subject line>\",\"body\":\"<body covering all changes, or empty string>\"}`;\n\n const text = await callClaudeCli(system, `Diff:\\n${diff.slice(0, 20000)}`);\n const parsed = parseJson<Partial<import(\"./types.js\").AiCommitMessageResponse>>(text, {});\n return {\n subject: parsed.subject?.trim() ?? \"chore: update files\",\n body: parsed.body?.trim() || undefined,\n };\n }\n\n async reviewPRDetailed(\n context: Parameters<import(\"./types.js\").AiClient[\"reviewPRDetailed\"]>[0]\n ): Promise<import(\"./types.js\").AiDetailedReviewResponse> {\n const { buildSeniorReviewSystem, buildSeniorReviewPrompt, parseSeniorReview } = await import(\"./reviewHelpers.js\");\n const text = await callClaudeCli(\n buildSeniorReviewSystem(),\n buildSeniorReviewPrompt(context),\n { timeoutMs: 300_000, maxOutputChars: 60_000 } // 5 min timeout, large output for full review JSON\n );\n return parseSeniorReview(text);\n }\n\n async generateFix(\n context: Parameters<import(\"./types.js\").AiClient[\"generateFix\"]>[0]\n ): Promise<import(\"./types.js\").AiFixResponse> {\n const { buildFixSystem, buildFixPrompt, parseFixResponse } = await import(\"./reviewHelpers.js\");\n const text = await callClaudeCli(\n buildFixSystem(),\n buildFixPrompt(context),\n { timeoutMs: 120_000, maxOutputChars: 8_000 }\n );\n return parseFixResponse(text, context.filePath, context.line);\n }\n\n async ask(\n question: string,\n context: import(\"./types.js\").AiAskContext\n ): Promise<import(\"./types.js\").AiAskResponse> {\n const { buildAskSystem, buildAskPrompt, parseAskResponse } = await import(\"./reviewHelpers.js\");\n const text = await callClaudeCli(buildAskSystem(), buildAskPrompt(question, context));\n return parseAskResponse(text);\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"claudeCliAi.js","sourceRoot":"","sources":["../../src/ai/claudeCliAi.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * ClaudeCliAi — uses the locally installed `claude` CLI (Claude Code)\n * as an AI backend. No API key required; uses the user's existing Claude login.\n *\n * Detection: `claude --version`\n * Invocation: `claude -p \"<combined system+user prompt>\"`\n */\n\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { GitxError } from \"../utils/errors.js\";\nimport type {\n AiAnalyzeTaskResponse,\n AiClient,\n AiGenerateDiffsResponse,\n AiGeneratePlanResponse,\n AiReviewPRResponse,\n AiSuggestFixesResponse,\n AiSummarizeChangesResponse,\n} from \"./types.js\";\n\nconst execFileAsync = promisify(execFile);\n\n// ─── Internal helpers ─────────────────────────────────────────────────────────\n\nasync function callClaudeCli(\n systemPrompt: string,\n userPrompt: string,\n opts: { timeoutMs?: number; maxOutputChars?: number } = {}\n): Promise<string> {\n const timeoutMs = opts.timeoutMs ?? 120_000;\n const maxOutputChars = opts.maxOutputChars ?? 12_000;\n const combined = `<system>\\n${systemPrompt}\\n</system>\\n\\n${userPrompt}`;\n\n let stdout: string;\n try {\n const result = await execFileAsync(\"claude\", [\"-p\", combined], {\n timeout: timeoutMs,\n maxBuffer: 20 * 1024 * 1024,\n });\n stdout = result.stdout;\n } catch (err: unknown) {\n const e = err as { code?: string; message?: string; killed?: boolean };\n if (e.code === \"ENOENT\") {\n throw new GitxError(\n \"Claude CLI not found. Install Claude Code from https://claude.ai/download\",\n { exitCode: 2 }\n );\n }\n if (e.killed) {\n const secs = Math.round(timeoutMs / 1000);\n throw new GitxError(`Claude CLI timed out (>${secs}s). Try reducing the number of changed files or use --no-comment.`, { exitCode: 1 });\n }\n throw new GitxError(`Claude CLI error: ${e.message ?? String(err)}`, { exitCode: 1 });\n }\n\n return stdout.trim().slice(0, maxOutputChars);\n}\n\nfunction extractJson(text: string): string {\n const fenced = text.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\n if (fenced?.[1]) return fenced[1].trim();\n const start = text.search(/[{[]/);\n const endBrace = text.lastIndexOf(\"}\");\n const endBracket = text.lastIndexOf(\"]\");\n const end = Math.max(endBrace, endBracket);\n if (start !== -1 && end !== -1 && end > start) return text.slice(start, end + 1);\n return text.trim();\n}\n\nfunction parseJson<T>(text: string, fallback: T): T {\n try {\n return JSON.parse(extractJson(text)) as T;\n } catch {\n return fallback;\n }\n}\n\n// ─── ClaudeCliAi ──────────────────────────────────────────────────────────────\n\nexport class ClaudeCliAi implements AiClient {\n /**\n * Returns true if the `claude` CLI binary is installed and accessible.\n */\n static async isAvailable(): Promise<boolean> {\n try {\n await execFileAsync(\"claude\", [\"--version\"], { timeout: 8_000 });\n return true;\n } catch (err: unknown) {\n const e = err as { code?: string };\n return e.code !== \"ENOENT\";\n }\n }\n\n async analyzeTask(input: string): Promise<AiAnalyzeTaskResponse> {\n const system = `You are an expert software engineer. Analyze the development task and respond with ONLY valid JSON:\n{\"task\":\"<original task>\",\"intent\":\"<refactor|bugfix|feature|chore|unknown>\",\"summary\":\"<one sentence>\",\"assumptions\":[\"...\"],\"risks\":[\"...\"]}`;\n\n const text = await callClaudeCli(system, `Task: ${input}`);\n const parsed = parseJson<Partial<AiAnalyzeTaskResponse>>(text, {});\n return {\n task: input,\n intent: (parsed.intent as AiAnalyzeTaskResponse[\"intent\"]) ?? \"unknown\",\n summary: parsed.summary ?? \"Unable to analyze task.\",\n assumptions: Array.isArray(parsed.assumptions) ? parsed.assumptions : [],\n risks: Array.isArray(parsed.risks) ? parsed.risks : [],\n };\n }\n\n async generatePlan(context: unknown): Promise<AiGeneratePlanResponse> {\n const ctx = context as {\n task?: string;\n analysis?: AiAnalyzeTaskResponse;\n repoFiles?: string[];\n fileContents?: Record<string, string>;\n };\n\n const fileList = ctx.repoFiles?.slice(0, 50).join(\"\\n\") ?? \"(not provided)\";\n const fileContentsSection =\n ctx.fileContents && Object.keys(ctx.fileContents).length > 0\n ? `\\n\\nRelevant file contents:\\n${Object.entries(ctx.fileContents)\n .map(([p, c]) => `--- ${p} ---\\n${c}`)\n .join(\"\\n\\n\")}`\n : \"\";\n\n const system = `You are an expert software engineer creating a step-by-step implementation plan. Respond with ONLY valid JSON:\n{\"steps\":[{\"id\":\"step-1\",\"title\":\"<short title>\",\"description\":\"<detailed description>\"}]}\nKeep steps atomic and ordered.`;\n\n const userPrompt = `Task: ${ctx.task ?? \"\"}\nAnalysis: ${ctx.analysis?.summary ?? \"\"}\nRepo files (top 50):\n${fileList}${fileContentsSection}`;\n\n const text = await callClaudeCli(system, userPrompt);\n const parsed = parseJson<Partial<AiGeneratePlanResponse>>(text, { steps: [] });\n const steps = Array.isArray(parsed.steps) ? parsed.steps : [];\n return steps.length > 0\n ? { steps }\n : { steps: [{ id: \"step-1\", title: \"Analyze & implement\", description: ctx.task ?? \"\" }] };\n }\n\n async generateDiffs(step: unknown): Promise<AiGenerateDiffsResponse> {\n const s = step as {\n id?: string;\n title?: string;\n description?: string;\n task?: string;\n fileContents?: Record<string, string>;\n };\n\n const stepId = s.id ?? \"step-1\";\n const fileContentsSection =\n s.fileContents && Object.keys(s.fileContents).length > 0\n ? `\\n\\nCurrent file contents:\\n${Object.entries(s.fileContents)\n .map(([p, c]) => `--- ${p} ---\\n${c}`)\n .join(\"\\n\\n\")}`\n : \"\\n\\n(No existing file contents — create new files as needed.)\";\n\n const system = `You are an expert software engineer. Generate unified diffs. Respond with ONLY valid JSON:\n{\"stepId\":\"<id>\",\"diffs\":[{\"path\":\"<file path>\",\"unifiedDiff\":\"<valid unified diff starting with --- a/path and +++ b/path>\"}]}\n\nUnified diff rules:\n- Start with: --- a/<path>\\\\n+++ b/<path>\n- Use @@ -<start>,<count> +<start>,<count> @@ headers\n- ' ' = context, '-' = removed, '+' = added\n- New files: --- /dev/null\\\\n+++ b/<path>\n- Include 3 lines of context around changes`;\n\n const userPrompt = `Task: ${s.task ?? \"\"}\nStep: ${stepId} — ${s.title ?? \"\"}\nDescription: ${s.description ?? \"\"}${fileContentsSection}`;\n\n const text = await callClaudeCli(system, userPrompt);\n const parsed = parseJson<Partial<AiGenerateDiffsResponse>>(text, { stepId, diffs: [] });\n return {\n stepId,\n diffs: Array.isArray(parsed.diffs) ? parsed.diffs : [],\n };\n }\n\n async summarizeChanges(diff: unknown): Promise<AiSummarizeChangesResponse> {\n const d = diff as { diffs?: AiGenerateDiffsResponse[]; rawDiff?: string };\n const diffContent =\n d.rawDiff ??\n (d.diffs ?? [])\n .flatMap((dr) => dr.diffs.map((f) => `File: ${f.path}\\n${f.unifiedDiff}`))\n .join(\"\\n\\n\") ??\n \"(no diffs)\";\n\n const system = `You are a technical writer. Summarize code changes for a PR. Respond with ONLY valid JSON:\n{\"summary\":\"<2-3 sentence summary>\",\"filesChanged\":[{\"path\":\"<file>\",\"changeType\":\"<add|modify|delete>\"}]}`;\n\n const text = await callClaudeCli(system, `Changes:\\n${diffContent}`);\n const parsed = parseJson<Partial<AiSummarizeChangesResponse>>(text, { summary: \"\", filesChanged: [] });\n return {\n summary: parsed.summary ?? \"Code changes applied.\",\n filesChanged: Array.isArray(parsed.filesChanged) ? parsed.filesChanged : [],\n };\n }\n\n async suggestFixes(comment: unknown): Promise<AiSuggestFixesResponse> {\n const { buildSuggestFixesSystem, buildSuggestFixesPrompt, parseSuggestFixesResponse } =\n await import(\"./reviewHelpers.js\");\n const ctx = comment as Parameters<typeof buildSuggestFixesPrompt>[0];\n const text = await callClaudeCli(buildSuggestFixesSystem(), buildSuggestFixesPrompt(ctx));\n return parseSuggestFixesResponse(text);\n }\n\n async reviewPR(context: unknown): Promise<AiReviewPRResponse> {\n const ctx = context as {\n prTitle?: string;\n prBody?: string;\n diff?: string;\n comments?: Array<{ body: string; author: string; path?: string }>;\n };\n\n const diffSection = ctx.diff ? `\\n\\nDiff:\\n${ctx.diff.slice(0, 8000)}` : \"\";\n const commentsSection =\n ctx.comments && ctx.comments.length > 0\n ? `\\n\\nExisting review comments:\\n${ctx.comments\n .map((c) => `[${c.author}${c.path ? ` @ ${c.path}` : \"\"}]: ${c.body}`)\n .join(\"\\n\")}`\n : \"\";\n\n const system = `You are an expert code reviewer. Review the PR and respond with ONLY valid JSON:\n{\"summary\":\"<2-4 sentence assessment>\",\"issues\":[{\"severity\":\"<critical|warning|suggestion>\",\"description\":\"<issue>\",\"file\":\"<optional>\",\"line\":null}],\"positives\":[\"<good thing>\"],\"verdict\":\"<approve|request_changes|comment>\"}\n\nSeverity: critical=bugs/security, warning=quality/perf, suggestion=style/naming`;\n\n const userPrompt = `PR Title: ${ctx.prTitle ?? \"\"}\nPR Description: ${ctx.prBody ?? \"\"}${diffSection}${commentsSection}`;\n\n const text = await callClaudeCli(system, userPrompt);\n const parsed = parseJson<Partial<AiReviewPRResponse>>(text, {\n summary: \"\",\n issues: [],\n positives: [],\n verdict: \"comment\",\n });\n\n return {\n summary: parsed.summary ?? \"Review could not be generated.\",\n issues: Array.isArray(parsed.issues) ? parsed.issues : [],\n positives: Array.isArray(parsed.positives) ? parsed.positives : [],\n verdict: ([\"approve\", \"request_changes\", \"comment\"].includes(parsed.verdict ?? \"\"))\n ? (parsed.verdict as AiReviewPRResponse[\"verdict\"])\n : \"comment\",\n };\n }\n\n async generatePrContent(commits: string[], diff: string, stat?: string): Promise<import(\"./types.js\").AiPrContentResponse> {\n const system = `You are an expert software engineer writing pull request descriptions.\nYou are given a list of commits on the branch and the unified diff of all changes.\n\nThe input may contain:\n - \"=== Changed files (complete list) ===\" — the full --stat summary of every file touched\n - \"=== Detailed diff ===\" — the actual patch (may be truncated for large changesets)\n\nWhen a file list is present, use it as the authoritative source of ALL changed files.\nDo not ignore files that appear in the list but are absent from the truncated diff.\n\nProduce a clear, informative PR title and description:\n\nRules:\n- title: short, human-readable, present-tense. No conventional-commit prefix. Max 72 chars.\n- body: 2-4 sentences describing WHAT changed and WHY. Cover ALL files from the list.\n Plain English, no bullet points.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"title\":\"<PR title>\",\"body\":\"<PR description>\"}`;\n\n const commitList = commits.slice(0, 20).join(\"\\n\");\n const diffSection = stat\n ? `=== Changed files (complete list) ===\\n${stat}\\n\\n=== Detailed diff ===\\n${diff.slice(0, 16000)}`\n : `Diff:\\n${diff.slice(0, 16000)}`;\n const userPrompt = `Commits on this branch:\\n${commitList}\\n\\n${diffSection}`;\n const text = await callClaudeCli(system, userPrompt);\n const parsed = parseJson<Partial<import(\"./types.js\").AiPrContentResponse>>(text, {});\n return {\n title: parsed.title?.trim() ?? \"Update branch\",\n body: parsed.body?.trim() ?? \"\",\n };\n }\n\n async resolveConflict(filePath: string, conflictContent: string): Promise<import(\"./types.js\").AiConflictResolutionResponse> {\n const system = `You are an expert software engineer resolving git merge conflicts.\n\nThe file contains standard git conflict markers:\n <<<<<<< HEAD — changes on the current branch\n ======= — separator\n >>>>>>> theirs — incoming changes\n\nYour task:\n1. Understand BOTH sides of every conflict.\n2. Produce a single correct version preserving the intent of BOTH changes where possible.\n3. If the sides are genuinely contradictory, set confidence to \"low\".\n\nRules:\n- Remove ALL conflict markers from the output.\n- Do NOT add explanatory comments.\n- Keep all non-conflicting code exactly as-is.\n- Output must be syntactically valid.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"resolved\":\"<full resolved file content>\",\"confidence\":\"high|low\",\"explanation\":\"<one sentence>\"}`;\n\n const userPrompt = `File: ${filePath}\\n\\n${conflictContent.slice(0, 20000)}`;\n const text = await callClaudeCli(system, userPrompt);\n const parsed = parseJson<Partial<import(\"./types.js\").AiConflictResolutionResponse>>(text, {});\n return {\n resolved: parsed.resolved ?? conflictContent,\n confidence: parsed.confidence === \"low\" ? \"low\" : \"high\",\n explanation: parsed.explanation?.trim() ?? \"Conflict resolved.\",\n };\n }\n async generateCommitMessage(diff: string): Promise<import(\"./types.js\").AiCommitMessageResponse> {\n const system = `You are an expert software engineer writing git commit messages.\nYou receive either a plain unified diff OR a structured input with:\n - \"=== Changed files (complete list) ===\" — the full --stat summary of every file touched\n - \"=== Detailed diff ===\" — the actual patch (may be truncated for large changesets)\n\nWhen a file list is present, use it as the authoritative source of ALL changes.\nDo not ignore files that appear in the list but are missing from the truncated diff.\n\nProduce ONE CONVENTIONAL COMMIT covering all the changes:\n\nRules:\n- subject: \"<type>(<scope>): <imperative description>\"\n - type: feat | fix | refactor | chore | docs | test | perf | ci | style | build\n - scope: the primary area affected; omit if changes span many unrelated areas\n - description: imperative mood, no period, 72 chars max for the whole subject line\n - if several distinct features or fixes are present, pick the most impactful for the subject\n- body: cover EVERY significant change visible in the file list. For each distinct change,\n one sentence on what was done and why. Plain English, no bullet lists, no repetition of the subject.\n\nRespond with ONLY valid JSON (no markdown fences):\n{\"subject\":\"<subject line>\",\"body\":\"<body covering all changes, or empty string>\"}`;\n\n const text = await callClaudeCli(system, `Diff:\\n${diff.slice(0, 20000)}`);\n const parsed = parseJson<Partial<import(\"./types.js\").AiCommitMessageResponse>>(text, {});\n return {\n subject: parsed.subject?.trim() ?? \"chore: update files\",\n body: parsed.body?.trim() || undefined,\n };\n }\n\n async reviewPRDetailed(\n context: Parameters<import(\"./types.js\").AiClient[\"reviewPRDetailed\"]>[0]\n ): Promise<import(\"./types.js\").AiDetailedReviewResponse> {\n const { buildSeniorReviewSystem, buildSeniorReviewPrompt, parseSeniorReview } = await import(\"./reviewHelpers.js\");\n const text = await callClaudeCli(\n buildSeniorReviewSystem(),\n buildSeniorReviewPrompt(context),\n { timeoutMs: 300_000, maxOutputChars: 60_000 } // 5 min timeout, large output for full review JSON\n );\n return parseSeniorReview(text);\n }\n\n async generateFix(\n context: Parameters<import(\"./types.js\").AiClient[\"generateFix\"]>[0]\n ): Promise<import(\"./types.js\").AiFixResponse> {\n const { buildFixSystem, buildFixPrompt, parseFixResponse } = await import(\"./reviewHelpers.js\");\n const text = await callClaudeCli(\n buildFixSystem(),\n buildFixPrompt(context),\n { timeoutMs: 120_000, maxOutputChars: 8_000 }\n );\n return parseFixResponse(text, context.filePath, context.line);\n }\n\n async ask(\n question: string,\n context: import(\"./types.js\").AiAskContext\n ): Promise<import(\"./types.js\").AiAskResponse> {\n const { buildAskSystem, buildAskPrompt, parseAskResponse } = await import(\"./reviewHelpers.js\");\n const text = await callClaudeCli(buildAskSystem(), buildAskPrompt(question, context));\n return parseAskResponse(text);\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"openAiAi.d.ts","sourceRoot":"","sources":["../../src/ai/openAiAi.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EACV,qBAAqB,EACrB,QAAQ,EACR,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AA0GpB,qBAAa,QAAS,YAAW,QAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B;;;OAGG;gBACS,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAY3C,0EAA0E;IAC1E,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO;IAInC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAqB1D,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAyC/D,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAmD9D,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,0BAA0B,CAAC;IA4BpE,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"openAiAi.d.ts","sourceRoot":"","sources":["../../src/ai/openAiAi.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EACV,qBAAqB,EACrB,QAAQ,EACR,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AA0GpB,qBAAa,QAAS,YAAW,QAAQ;IACvC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAE/B;;;OAGG;gBACS,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM;IAY3C,0EAA0E;IAC1E,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO;IAInC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAqB1D,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAyC/D,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAmD9D,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,0BAA0B,CAAC;IA4BpE,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAa/D,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAsDvD,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,mBAAmB,CAAC;IAkCpH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,4BAA4B,CAAC;IA+BtH,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,uBAAuB,CAAC;IA+B1F,gBAAgB,CACpB,OAAO,EAAE,UAAU,CAAC,OAAO,YAAY,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,GACxE,OAAO,CAAC,OAAO,YAAY,EAAE,wBAAwB,CAAC;IAWnD,WAAW,CACf,OAAO,EAAE,UAAU,CAAC,OAAO,YAAY,EAAE,QAAQ,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,GACnE,OAAO,CAAC,OAAO,YAAY,EAAE,aAAa,CAAC;IAWxC,GAAG,CACP,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,OAAO,YAAY,EAAE,YAAY,GACzC,OAAO,CAAC,OAAO,YAAY,EAAE,aAAa,CAAC;CAK/C"}
|
package/dist/ai/openAiAi.js
CHANGED
|
@@ -205,36 +205,10 @@ Step Description: ${s.description ?? ""}${fileContentsSection}`;
|
|
|
205
205
|
};
|
|
206
206
|
}
|
|
207
207
|
async suggestFixes(comment) {
|
|
208
|
-
const
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const fileContentsSection = c.fileContents && Object.keys(c.fileContents).length > 0
|
|
213
|
-
? `\n\nCurrent file contents:\n${Object.entries(c.fileContents)
|
|
214
|
-
.map(([p, content]) => `--- ${p} ---\n${content}`)
|
|
215
|
-
.join("\n\n")}`
|
|
216
|
-
: "";
|
|
217
|
-
const system = `You are an expert code reviewer suggesting fixes for pull request review comments. Respond with ONLY valid JSON:
|
|
218
|
-
{
|
|
219
|
-
"suggestedEdits": [
|
|
220
|
-
{
|
|
221
|
-
"path": "<file path>",
|
|
222
|
-
"rationale": "<why this change addresses the comment>",
|
|
223
|
-
"unifiedDiff": "<valid unified diff>"
|
|
224
|
-
}
|
|
225
|
-
]
|
|
226
|
-
}
|
|
227
|
-
If a comment doesn't require a code change, omit it from suggestedEdits.`;
|
|
228
|
-
const userPrompt = `PR Title: ${c.prTitle ?? ""}
|
|
229
|
-
PR Body: ${c.prBody ?? ""}
|
|
230
|
-
|
|
231
|
-
Review Comments:
|
|
232
|
-
${commentsText}${fileContentsSection}`;
|
|
233
|
-
const text = await callOpenAi(system, userPrompt, this.apiKey, this.model);
|
|
234
|
-
const parsed = parseJson(text, { suggestedEdits: [] });
|
|
235
|
-
return {
|
|
236
|
-
suggestedEdits: Array.isArray(parsed.suggestedEdits) ? parsed.suggestedEdits : [],
|
|
237
|
-
};
|
|
208
|
+
const { buildSuggestFixesSystem, buildSuggestFixesPrompt, parseSuggestFixesResponse } = await import("./reviewHelpers.js");
|
|
209
|
+
const ctx = comment;
|
|
210
|
+
const text = await callOpenAi(buildSuggestFixesSystem(), buildSuggestFixesPrompt(ctx), this.apiKey, this.model);
|
|
211
|
+
return parseSuggestFixesResponse(text);
|
|
238
212
|
}
|
|
239
213
|
async reviewPR(context) {
|
|
240
214
|
const ctx = context;
|