@g-abhishek/gitx 0.1.2 → 0.1.5
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 +386 -3
- package/dist/ai/claudeAi.d.ts +35 -0
- package/dist/ai/claudeAi.d.ts.map +1 -0
- package/dist/ai/claudeAi.js +396 -0
- package/dist/ai/claudeAi.js.map +1 -0
- package/dist/ai/claudeCliAi.d.ts +27 -0
- package/dist/ai/claudeCliAi.d.ts.map +1 -0
- package/dist/ai/claudeCliAi.js +312 -0
- package/dist/ai/claudeCliAi.js.map +1 -0
- package/dist/ai/localClaudeAi.d.ts +2 -0
- package/dist/ai/localClaudeAi.d.ts.map +1 -0
- package/dist/ai/localClaudeAi.js +4 -0
- package/dist/ai/localClaudeAi.js.map +1 -0
- package/dist/ai/mockAi.d.ts +8 -1
- package/dist/ai/mockAi.d.ts.map +1 -1
- package/dist/ai/mockAi.js +57 -0
- package/dist/ai/mockAi.js.map +1 -1
- package/dist/ai/openAiAi.d.ts +33 -0
- package/dist/ai/openAiAi.d.ts.map +1 -0
- package/dist/ai/openAiAi.js +388 -0
- package/dist/ai/openAiAi.js.map +1 -0
- package/dist/ai/reviewHelpers.d.ts +66 -0
- package/dist/ai/reviewHelpers.d.ts.map +1 -0
- package/dist/ai/reviewHelpers.js +574 -0
- package/dist/ai/reviewHelpers.js.map +1 -0
- package/dist/ai/types.d.ts +247 -0
- package/dist/ai/types.d.ts.map +1 -1
- package/dist/ai/types.js.map +1 -1
- package/dist/cli/commands/ask.d.ts +27 -0
- package/dist/cli/commands/ask.d.ts.map +1 -0
- package/dist/cli/commands/ask.js +230 -0
- package/dist/cli/commands/ask.js.map +1 -0
- package/dist/cli/commands/commit.d.ts +16 -0
- package/dist/cli/commands/commit.d.ts.map +1 -0
- package/dist/cli/commands/commit.js +163 -0
- package/dist/cli/commands/commit.js.map +1 -0
- package/dist/cli/commands/config.d.ts +4 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +666 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/implement.d.ts.map +1 -1
- package/dist/cli/commands/implement.js +149 -31
- package/dist/cli/commands/implement.js.map +1 -1
- package/dist/cli/commands/init.d.ts +4 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +7 -69
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/port.d.ts +32 -0
- package/dist/cli/commands/port.d.ts.map +1 -0
- package/dist/cli/commands/port.js +554 -0
- package/dist/cli/commands/port.js.map +1 -0
- package/dist/cli/commands/pr/close.d.ts +15 -0
- package/dist/cli/commands/pr/close.d.ts.map +1 -0
- package/dist/cli/commands/pr/close.js +71 -0
- package/dist/cli/commands/pr/close.js.map +1 -0
- package/dist/cli/commands/pr/create.d.ts +17 -0
- package/dist/cli/commands/pr/create.d.ts.map +1 -1
- package/dist/cli/commands/pr/create.js +208 -7
- package/dist/cli/commands/pr/create.js.map +1 -1
- package/dist/cli/commands/pr/fixComments.d.ts +5 -2
- package/dist/cli/commands/pr/fixComments.d.ts.map +1 -1
- package/dist/cli/commands/pr/fixComments.js +5 -13
- package/dist/cli/commands/pr/fixComments.js.map +1 -1
- package/dist/cli/commands/pr/index.d.ts.map +1 -1
- package/dist/cli/commands/pr/index.js +6 -2
- package/dist/cli/commands/pr/index.js.map +1 -1
- package/dist/cli/commands/pr/list.d.ts.map +1 -1
- package/dist/cli/commands/pr/list.js +24 -4
- package/dist/cli/commands/pr/list.js.map +1 -1
- package/dist/cli/commands/pr/merge.d.ts +23 -0
- package/dist/cli/commands/pr/merge.d.ts.map +1 -0
- package/dist/cli/commands/pr/merge.js +191 -0
- package/dist/cli/commands/pr/merge.js.map +1 -0
- package/dist/cli/commands/pr/resolve.d.ts +3 -0
- package/dist/cli/commands/pr/resolve.d.ts.map +1 -0
- package/dist/cli/commands/pr/resolve.js +92 -0
- package/dist/cli/commands/pr/resolve.js.map +1 -0
- package/dist/cli/commands/pr/review.d.ts.map +1 -1
- package/dist/cli/commands/pr/review.js +121 -6
- package/dist/cli/commands/pr/review.js.map +1 -1
- package/dist/cli/commands/push.d.ts +16 -0
- package/dist/cli/commands/push.d.ts.map +1 -0
- package/dist/cli/commands/push.js +166 -0
- package/dist/cli/commands/push.js.map +1 -0
- package/dist/cli/commands/sync.d.ts +24 -0
- package/dist/cli/commands/sync.d.ts.map +1 -0
- package/dist/cli/commands/sync.js +414 -0
- package/dist/cli/commands/sync.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +34 -6
- package/dist/cli/index.js.map +1 -1
- package/dist/config/config.d.ts +20 -3
- package/dist/config/config.d.ts.map +1 -1
- package/dist/config/config.js +98 -45
- package/dist/config/config.js.map +1 -1
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +61 -6
- package/dist/config/schema.js.map +1 -1
- package/dist/core/context.d.ts +6 -0
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/context.js.map +1 -1
- package/dist/core/gitx.d.ts +43 -0
- package/dist/core/gitx.d.ts.map +1 -1
- package/dist/core/gitx.js +187 -20
- package/dist/core/gitx.js.map +1 -1
- package/dist/index.d.ts +1 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/providers/azure.d.ts +26 -0
- package/dist/providers/azure.d.ts.map +1 -0
- package/dist/providers/azure.js +256 -0
- package/dist/providers/azure.js.map +1 -0
- package/dist/providers/base.d.ts +104 -0
- package/dist/providers/base.d.ts.map +1 -0
- package/dist/providers/base.js +5 -0
- package/dist/providers/base.js.map +1 -0
- package/dist/providers/factory.d.ts +8 -0
- package/dist/providers/factory.d.ts.map +1 -0
- package/dist/providers/factory.js +25 -0
- package/dist/providers/factory.js.map +1 -0
- package/dist/providers/github.d.ts +19 -0
- package/dist/providers/github.d.ts.map +1 -0
- package/dist/providers/github.js +291 -0
- package/dist/providers/github.js.map +1 -0
- package/dist/providers/gitlab.d.ts +19 -0
- package/dist/providers/gitlab.d.ts.map +1 -0
- package/dist/providers/gitlab.js +186 -0
- package/dist/providers/gitlab.js.map +1 -0
- package/dist/types/config.d.ts +50 -7
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js.map +1 -1
- package/dist/utils/azureAuth.d.ts +51 -0
- package/dist/utils/azureAuth.d.ts.map +1 -0
- package/dist/utils/azureAuth.js +172 -0
- package/dist/utils/azureAuth.js.map +1 -0
- package/dist/utils/git.d.ts +19 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +45 -8
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/gitOps.d.ts +125 -0
- package/dist/utils/gitOps.d.ts.map +1 -0
- package/dist/utils/gitOps.js +396 -0
- package/dist/utils/gitOps.js.map +1 -0
- package/dist/utils/lockFile.d.ts +13 -0
- package/dist/utils/lockFile.d.ts.map +1 -0
- package/dist/utils/lockFile.js +54 -0
- package/dist/utils/lockFile.js.map +1 -0
- package/dist/utils/retry.d.ts +10 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +31 -0
- package/dist/utils/retry.js.map +1 -0
- package/dist/workflows/implement.d.ts +41 -0
- package/dist/workflows/implement.d.ts.map +1 -0
- package/dist/workflows/implement.js +219 -0
- package/dist/workflows/implement.js.map +1 -0
- package/dist/workflows/pr.d.ts +41 -0
- package/dist/workflows/pr.d.ts.map +1 -0
- package/dist/workflows/pr.js +291 -0
- package/dist/workflows/pr.js.map +1 -0
- package/dist/workflows/prAddress.d.ts +55 -0
- package/dist/workflows/prAddress.d.ts.map +1 -0
- package/dist/workflows/prAddress.js +349 -0
- package/dist/workflows/prAddress.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClaudeCliAi — uses the locally installed `claude` CLI (Claude Code)
|
|
3
|
+
* as an AI backend. No API key required; uses the user's existing Claude login.
|
|
4
|
+
*
|
|
5
|
+
* Detection: `claude --version`
|
|
6
|
+
* Invocation: `claude -p "<combined system+user prompt>"`
|
|
7
|
+
*/
|
|
8
|
+
import { execFile } from "node:child_process";
|
|
9
|
+
import { promisify } from "node:util";
|
|
10
|
+
import { GitxError } from "../utils/errors.js";
|
|
11
|
+
const execFileAsync = promisify(execFile);
|
|
12
|
+
// ─── Internal helpers ─────────────────────────────────────────────────────────
|
|
13
|
+
async function callClaudeCli(systemPrompt, userPrompt, opts = {}) {
|
|
14
|
+
const timeoutMs = opts.timeoutMs ?? 120_000;
|
|
15
|
+
const maxOutputChars = opts.maxOutputChars ?? 12_000;
|
|
16
|
+
const combined = `<system>\n${systemPrompt}\n</system>\n\n${userPrompt}`;
|
|
17
|
+
let stdout;
|
|
18
|
+
try {
|
|
19
|
+
const result = await execFileAsync("claude", ["-p", combined], {
|
|
20
|
+
timeout: timeoutMs,
|
|
21
|
+
maxBuffer: 20 * 1024 * 1024,
|
|
22
|
+
});
|
|
23
|
+
stdout = result.stdout;
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
const e = err;
|
|
27
|
+
if (e.code === "ENOENT") {
|
|
28
|
+
throw new GitxError("Claude CLI not found. Install Claude Code from https://claude.ai/download", { exitCode: 2 });
|
|
29
|
+
}
|
|
30
|
+
if (e.killed) {
|
|
31
|
+
const secs = Math.round(timeoutMs / 1000);
|
|
32
|
+
throw new GitxError(`Claude CLI timed out (>${secs}s). Try reducing the number of changed files or use --no-comment.`, { exitCode: 1 });
|
|
33
|
+
}
|
|
34
|
+
throw new GitxError(`Claude CLI error: ${e.message ?? String(err)}`, { exitCode: 1 });
|
|
35
|
+
}
|
|
36
|
+
return stdout.trim().slice(0, maxOutputChars);
|
|
37
|
+
}
|
|
38
|
+
function extractJson(text) {
|
|
39
|
+
const fenced = text.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
40
|
+
if (fenced?.[1])
|
|
41
|
+
return fenced[1].trim();
|
|
42
|
+
const start = text.search(/[{[]/);
|
|
43
|
+
const endBrace = text.lastIndexOf("}");
|
|
44
|
+
const endBracket = text.lastIndexOf("]");
|
|
45
|
+
const end = Math.max(endBrace, endBracket);
|
|
46
|
+
if (start !== -1 && end !== -1 && end > start)
|
|
47
|
+
return text.slice(start, end + 1);
|
|
48
|
+
return text.trim();
|
|
49
|
+
}
|
|
50
|
+
function parseJson(text, fallback) {
|
|
51
|
+
try {
|
|
52
|
+
return JSON.parse(extractJson(text));
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return fallback;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// ─── ClaudeCliAi ──────────────────────────────────────────────────────────────
|
|
59
|
+
export class ClaudeCliAi {
|
|
60
|
+
/**
|
|
61
|
+
* Returns true if the `claude` CLI binary is installed and accessible.
|
|
62
|
+
*/
|
|
63
|
+
static async isAvailable() {
|
|
64
|
+
try {
|
|
65
|
+
await execFileAsync("claude", ["--version"], { timeout: 8_000 });
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
const e = err;
|
|
70
|
+
return e.code !== "ENOENT";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async analyzeTask(input) {
|
|
74
|
+
const system = `You are an expert software engineer. Analyze the development task and respond with ONLY valid JSON:
|
|
75
|
+
{"task":"<original task>","intent":"<refactor|bugfix|feature|chore|unknown>","summary":"<one sentence>","assumptions":["..."],"risks":["..."]}`;
|
|
76
|
+
const text = await callClaudeCli(system, `Task: ${input}`);
|
|
77
|
+
const parsed = parseJson(text, {});
|
|
78
|
+
return {
|
|
79
|
+
task: input,
|
|
80
|
+
intent: parsed.intent ?? "unknown",
|
|
81
|
+
summary: parsed.summary ?? "Unable to analyze task.",
|
|
82
|
+
assumptions: Array.isArray(parsed.assumptions) ? parsed.assumptions : [],
|
|
83
|
+
risks: Array.isArray(parsed.risks) ? parsed.risks : [],
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async generatePlan(context) {
|
|
87
|
+
const ctx = context;
|
|
88
|
+
const fileList = ctx.repoFiles?.slice(0, 50).join("\n") ?? "(not provided)";
|
|
89
|
+
const fileContentsSection = ctx.fileContents && Object.keys(ctx.fileContents).length > 0
|
|
90
|
+
? `\n\nRelevant file contents:\n${Object.entries(ctx.fileContents)
|
|
91
|
+
.map(([p, c]) => `--- ${p} ---\n${c}`)
|
|
92
|
+
.join("\n\n")}`
|
|
93
|
+
: "";
|
|
94
|
+
const system = `You are an expert software engineer creating a step-by-step implementation plan. Respond with ONLY valid JSON:
|
|
95
|
+
{"steps":[{"id":"step-1","title":"<short title>","description":"<detailed description>"}]}
|
|
96
|
+
Keep steps atomic and ordered.`;
|
|
97
|
+
const userPrompt = `Task: ${ctx.task ?? ""}
|
|
98
|
+
Analysis: ${ctx.analysis?.summary ?? ""}
|
|
99
|
+
Repo files (top 50):
|
|
100
|
+
${fileList}${fileContentsSection}`;
|
|
101
|
+
const text = await callClaudeCli(system, userPrompt);
|
|
102
|
+
const parsed = parseJson(text, { steps: [] });
|
|
103
|
+
const steps = Array.isArray(parsed.steps) ? parsed.steps : [];
|
|
104
|
+
return steps.length > 0
|
|
105
|
+
? { steps }
|
|
106
|
+
: { steps: [{ id: "step-1", title: "Analyze & implement", description: ctx.task ?? "" }] };
|
|
107
|
+
}
|
|
108
|
+
async generateDiffs(step) {
|
|
109
|
+
const s = step;
|
|
110
|
+
const stepId = s.id ?? "step-1";
|
|
111
|
+
const fileContentsSection = s.fileContents && Object.keys(s.fileContents).length > 0
|
|
112
|
+
? `\n\nCurrent file contents:\n${Object.entries(s.fileContents)
|
|
113
|
+
.map(([p, c]) => `--- ${p} ---\n${c}`)
|
|
114
|
+
.join("\n\n")}`
|
|
115
|
+
: "\n\n(No existing file contents — create new files as needed.)";
|
|
116
|
+
const system = `You are an expert software engineer. Generate unified diffs. Respond with ONLY valid JSON:
|
|
117
|
+
{"stepId":"<id>","diffs":[{"path":"<file path>","unifiedDiff":"<valid unified diff starting with --- a/path and +++ b/path>"}]}
|
|
118
|
+
|
|
119
|
+
Unified diff rules:
|
|
120
|
+
- Start with: --- a/<path>\\n+++ b/<path>
|
|
121
|
+
- Use @@ -<start>,<count> +<start>,<count> @@ headers
|
|
122
|
+
- ' ' = context, '-' = removed, '+' = added
|
|
123
|
+
- New files: --- /dev/null\\n+++ b/<path>
|
|
124
|
+
- Include 3 lines of context around changes`;
|
|
125
|
+
const userPrompt = `Task: ${s.task ?? ""}
|
|
126
|
+
Step: ${stepId} — ${s.title ?? ""}
|
|
127
|
+
Description: ${s.description ?? ""}${fileContentsSection}`;
|
|
128
|
+
const text = await callClaudeCli(system, userPrompt);
|
|
129
|
+
const parsed = parseJson(text, { stepId, diffs: [] });
|
|
130
|
+
return {
|
|
131
|
+
stepId,
|
|
132
|
+
diffs: Array.isArray(parsed.diffs) ? parsed.diffs : [],
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
async summarizeChanges(diff) {
|
|
136
|
+
const d = diff;
|
|
137
|
+
const diffContent = d.rawDiff ??
|
|
138
|
+
(d.diffs ?? [])
|
|
139
|
+
.flatMap((dr) => dr.diffs.map((f) => `File: ${f.path}\n${f.unifiedDiff}`))
|
|
140
|
+
.join("\n\n") ??
|
|
141
|
+
"(no diffs)";
|
|
142
|
+
const system = `You are a technical writer. Summarize code changes for a PR. Respond with ONLY valid JSON:
|
|
143
|
+
{"summary":"<2-3 sentence summary>","filesChanged":[{"path":"<file>","changeType":"<add|modify|delete>"}]}`;
|
|
144
|
+
const text = await callClaudeCli(system, `Changes:\n${diffContent}`);
|
|
145
|
+
const parsed = parseJson(text, { summary: "", filesChanged: [] });
|
|
146
|
+
return {
|
|
147
|
+
summary: parsed.summary ?? "Code changes applied.",
|
|
148
|
+
filesChanged: Array.isArray(parsed.filesChanged) ? parsed.filesChanged : [],
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
async suggestFixes(comment) {
|
|
152
|
+
const c = comment;
|
|
153
|
+
const commentsText = (c.comments ?? [])
|
|
154
|
+
.map((co) => `[${co.author ?? "reviewer"}${co.path ? ` on ${co.path}:${co.line ?? ""}` : ""}]: ${co.body}`)
|
|
155
|
+
.join("\n\n");
|
|
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
|
+
};
|
|
173
|
+
}
|
|
174
|
+
async reviewPR(context) {
|
|
175
|
+
const ctx = context;
|
|
176
|
+
const diffSection = ctx.diff ? `\n\nDiff:\n${ctx.diff.slice(0, 8000)}` : "";
|
|
177
|
+
const commentsSection = ctx.comments && ctx.comments.length > 0
|
|
178
|
+
? `\n\nExisting review comments:\n${ctx.comments
|
|
179
|
+
.map((c) => `[${c.author}${c.path ? ` @ ${c.path}` : ""}]: ${c.body}`)
|
|
180
|
+
.join("\n")}`
|
|
181
|
+
: "";
|
|
182
|
+
const system = `You are an expert code reviewer. Review the PR and respond with ONLY valid JSON:
|
|
183
|
+
{"summary":"<2-4 sentence assessment>","issues":[{"severity":"<critical|warning|suggestion>","description":"<issue>","file":"<optional>","line":null}],"positives":["<good thing>"],"verdict":"<approve|request_changes|comment>"}
|
|
184
|
+
|
|
185
|
+
Severity: critical=bugs/security, warning=quality/perf, suggestion=style/naming`;
|
|
186
|
+
const userPrompt = `PR Title: ${ctx.prTitle ?? ""}
|
|
187
|
+
PR Description: ${ctx.prBody ?? ""}${diffSection}${commentsSection}`;
|
|
188
|
+
const text = await callClaudeCli(system, userPrompt);
|
|
189
|
+
const parsed = parseJson(text, {
|
|
190
|
+
summary: "",
|
|
191
|
+
issues: [],
|
|
192
|
+
positives: [],
|
|
193
|
+
verdict: "comment",
|
|
194
|
+
});
|
|
195
|
+
return {
|
|
196
|
+
summary: parsed.summary ?? "Review could not be generated.",
|
|
197
|
+
issues: Array.isArray(parsed.issues) ? parsed.issues : [],
|
|
198
|
+
positives: Array.isArray(parsed.positives) ? parsed.positives : [],
|
|
199
|
+
verdict: (["approve", "request_changes", "comment"].includes(parsed.verdict ?? ""))
|
|
200
|
+
? parsed.verdict
|
|
201
|
+
: "comment",
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
async generatePrContent(commits, diff, stat) {
|
|
205
|
+
const system = `You are an expert software engineer writing pull request descriptions.
|
|
206
|
+
You are given a list of commits on the branch and the unified diff of all changes.
|
|
207
|
+
|
|
208
|
+
The input may contain:
|
|
209
|
+
- "=== Changed files (complete list) ===" — the full --stat summary of every file touched
|
|
210
|
+
- "=== Detailed diff ===" — the actual patch (may be truncated for large changesets)
|
|
211
|
+
|
|
212
|
+
When a file list is present, use it as the authoritative source of ALL changed files.
|
|
213
|
+
Do not ignore files that appear in the list but are absent from the truncated diff.
|
|
214
|
+
|
|
215
|
+
Produce a clear, informative PR title and description:
|
|
216
|
+
|
|
217
|
+
Rules:
|
|
218
|
+
- title: short, human-readable, present-tense. No conventional-commit prefix. Max 72 chars.
|
|
219
|
+
- body: 2-4 sentences describing WHAT changed and WHY. Cover ALL files from the list.
|
|
220
|
+
Plain English, no bullet points.
|
|
221
|
+
|
|
222
|
+
Respond with ONLY valid JSON (no markdown fences):
|
|
223
|
+
{"title":"<PR title>","body":"<PR description>"}`;
|
|
224
|
+
const commitList = commits.slice(0, 20).join("\n");
|
|
225
|
+
const diffSection = stat
|
|
226
|
+
? `=== Changed files (complete list) ===\n${stat}\n\n=== Detailed diff ===\n${diff.slice(0, 16000)}`
|
|
227
|
+
: `Diff:\n${diff.slice(0, 16000)}`;
|
|
228
|
+
const userPrompt = `Commits on this branch:\n${commitList}\n\n${diffSection}`;
|
|
229
|
+
const text = await callClaudeCli(system, userPrompt);
|
|
230
|
+
const parsed = parseJson(text, {});
|
|
231
|
+
return {
|
|
232
|
+
title: parsed.title?.trim() ?? "Update branch",
|
|
233
|
+
body: parsed.body?.trim() ?? "",
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
async resolveConflict(filePath, conflictContent) {
|
|
237
|
+
const system = `You are an expert software engineer resolving git merge conflicts.
|
|
238
|
+
|
|
239
|
+
The file contains standard git conflict markers:
|
|
240
|
+
<<<<<<< HEAD — changes on the current branch
|
|
241
|
+
======= — separator
|
|
242
|
+
>>>>>>> theirs — incoming changes
|
|
243
|
+
|
|
244
|
+
Your task:
|
|
245
|
+
1. Understand BOTH sides of every conflict.
|
|
246
|
+
2. Produce a single correct version preserving the intent of BOTH changes where possible.
|
|
247
|
+
3. If the sides are genuinely contradictory, set confidence to "low".
|
|
248
|
+
|
|
249
|
+
Rules:
|
|
250
|
+
- Remove ALL conflict markers from the output.
|
|
251
|
+
- Do NOT add explanatory comments.
|
|
252
|
+
- Keep all non-conflicting code exactly as-is.
|
|
253
|
+
- Output must be syntactically valid.
|
|
254
|
+
|
|
255
|
+
Respond with ONLY valid JSON (no markdown fences):
|
|
256
|
+
{"resolved":"<full resolved file content>","confidence":"high|low","explanation":"<one sentence>"}`;
|
|
257
|
+
const userPrompt = `File: ${filePath}\n\n${conflictContent.slice(0, 20000)}`;
|
|
258
|
+
const text = await callClaudeCli(system, userPrompt);
|
|
259
|
+
const parsed = parseJson(text, {});
|
|
260
|
+
return {
|
|
261
|
+
resolved: parsed.resolved ?? conflictContent,
|
|
262
|
+
confidence: parsed.confidence === "low" ? "low" : "high",
|
|
263
|
+
explanation: parsed.explanation?.trim() ?? "Conflict resolved.",
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
async generateCommitMessage(diff) {
|
|
267
|
+
const system = `You are an expert software engineer writing git commit messages.
|
|
268
|
+
You receive either a plain unified diff OR a structured input with:
|
|
269
|
+
- "=== Changed files (complete list) ===" — the full --stat summary of every file touched
|
|
270
|
+
- "=== Detailed diff ===" — the actual patch (may be truncated for large changesets)
|
|
271
|
+
|
|
272
|
+
When a file list is present, use it as the authoritative source of ALL changes.
|
|
273
|
+
Do not ignore files that appear in the list but are missing from the truncated diff.
|
|
274
|
+
|
|
275
|
+
Produce ONE CONVENTIONAL COMMIT covering all the changes:
|
|
276
|
+
|
|
277
|
+
Rules:
|
|
278
|
+
- subject: "<type>(<scope>): <imperative description>"
|
|
279
|
+
- type: feat | fix | refactor | chore | docs | test | perf | ci | style | build
|
|
280
|
+
- scope: the primary area affected; omit if changes span many unrelated areas
|
|
281
|
+
- description: imperative mood, no period, 72 chars max for the whole subject line
|
|
282
|
+
- if several distinct features or fixes are present, pick the most impactful for the subject
|
|
283
|
+
- body: cover EVERY significant change visible in the file list. For each distinct change,
|
|
284
|
+
one sentence on what was done and why. Plain English, no bullet lists, no repetition of the subject.
|
|
285
|
+
|
|
286
|
+
Respond with ONLY valid JSON (no markdown fences):
|
|
287
|
+
{"subject":"<subject line>","body":"<body covering all changes, or empty string>"}`;
|
|
288
|
+
const text = await callClaudeCli(system, `Diff:\n${diff.slice(0, 20000)}`);
|
|
289
|
+
const parsed = parseJson(text, {});
|
|
290
|
+
return {
|
|
291
|
+
subject: parsed.subject?.trim() ?? "chore: update files",
|
|
292
|
+
body: parsed.body?.trim() || undefined,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
async reviewPRDetailed(context) {
|
|
296
|
+
const { buildSeniorReviewSystem, buildSeniorReviewPrompt, parseSeniorReview } = await import("./reviewHelpers.js");
|
|
297
|
+
const text = await callClaudeCli(buildSeniorReviewSystem(), buildSeniorReviewPrompt(context), { timeoutMs: 300_000, maxOutputChars: 60_000 } // 5 min timeout, large output for full review JSON
|
|
298
|
+
);
|
|
299
|
+
return parseSeniorReview(text);
|
|
300
|
+
}
|
|
301
|
+
async generateFix(context) {
|
|
302
|
+
const { buildFixSystem, buildFixPrompt, parseFixResponse } = await import("./reviewHelpers.js");
|
|
303
|
+
const text = await callClaudeCli(buildFixSystem(), buildFixPrompt(context), { timeoutMs: 120_000, maxOutputChars: 8_000 });
|
|
304
|
+
return parseFixResponse(text, context.filePath, context.line);
|
|
305
|
+
}
|
|
306
|
+
async ask(question, context) {
|
|
307
|
+
const { buildAskSystem, buildAskPrompt, parseAskResponse } = await import("./reviewHelpers.js");
|
|
308
|
+
const text = await callClaudeCli(buildAskSystem(), buildAskPrompt(question, context));
|
|
309
|
+
return parseAskResponse(text);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
//# sourceMappingURL=claudeCliAi.js.map
|
|
@@ -0,0 +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"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localClaudeAi.d.ts","sourceRoot":"","sources":["../../src/ai/localClaudeAi.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"localClaudeAi.js","sourceRoot":"","sources":["../../src/ai/localClaudeAi.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,0CAA0C;AAC1C,OAAO,EAAE,WAAW,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC","sourcesContent":["// Renamed to claudeCliAi.ts — this file is intentionally empty.\n// Import from \"./claudeCliAi.js\" instead.\nexport { ClaudeCliAi as LocalClaudeAi } from \"./claudeCliAi.js\";\n"]}
|
package/dist/ai/mockAi.d.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
|
-
import type { AiAnalyzeTaskResponse, AiClient, AiGenerateDiffsResponse, AiGeneratePlanResponse, AiSuggestFixesResponse, AiSummarizeChangesResponse } from "./types.js";
|
|
1
|
+
import type { AiAnalyzeTaskResponse, AiClient, AiCommitMessageResponse, AiGenerateDiffsResponse, AiGeneratePlanResponse, AiReviewPRResponse, AiSuggestFixesResponse, AiSummarizeChangesResponse } from "./types.js";
|
|
2
2
|
export declare class MockAi implements AiClient {
|
|
3
3
|
analyzeTask(input: string): Promise<AiAnalyzeTaskResponse>;
|
|
4
4
|
generatePlan(_context: unknown): Promise<AiGeneratePlanResponse>;
|
|
5
5
|
generateDiffs(step: unknown): Promise<AiGenerateDiffsResponse>;
|
|
6
6
|
summarizeChanges(_diff: unknown): Promise<AiSummarizeChangesResponse>;
|
|
7
7
|
suggestFixes(_comment: unknown): Promise<AiSuggestFixesResponse>;
|
|
8
|
+
reviewPR(_context: unknown): Promise<AiReviewPRResponse>;
|
|
9
|
+
generateCommitMessage(_diff: string): Promise<AiCommitMessageResponse>;
|
|
10
|
+
generatePrContent(_commits: string[], _diff: string, _stat?: string): Promise<import("./types.js").AiPrContentResponse>;
|
|
11
|
+
resolveConflict(filePath: string, conflictContent: string): Promise<import("./types.js").AiConflictResolutionResponse>;
|
|
12
|
+
reviewPRDetailed(_context: Parameters<import("./types.js").AiClient["reviewPRDetailed"]>[0]): Promise<import("./types.js").AiDetailedReviewResponse>;
|
|
13
|
+
generateFix(context: Parameters<import("./types.js").AiClient["generateFix"]>[0]): Promise<import("./types.js").AiFixResponse>;
|
|
14
|
+
ask(_question: string, _context: import("./types.js").AiAskContext): Promise<import("./types.js").AiAskResponse>;
|
|
8
15
|
}
|
|
9
16
|
//# sourceMappingURL=mockAi.d.ts.map
|
package/dist/ai/mockAi.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockAi.d.ts","sourceRoot":"","sources":["../../src/ai/mockAi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,QAAQ,EACR,uBAAuB,EACvB,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AAEpB,qBAAa,MAAO,YAAW,QAAQ;IAC/B,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAU1D,YAAY,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAiBhE,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAI9D,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAIrE,YAAY,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"mockAi.d.ts","sourceRoot":"","sources":["../../src/ai/mockAi.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,qBAAqB,EACrB,QAAQ,EACR,uBAAuB,EACvB,uBAAuB,EACvB,sBAAsB,EACtB,kBAAkB,EAClB,sBAAsB,EACtB,0BAA0B,EAC3B,MAAM,YAAY,CAAC;AAEpB,qBAAa,MAAO,YAAW,QAAQ;IAC/B,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAU1D,YAAY,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAiBhE,aAAa,CAAC,IAAI,EAAE,OAAO,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAI9D,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,0BAA0B,CAAC;IAIrE,YAAY,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAIhE,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC;IASxD,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAOtE,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,mBAAmB,CAAC;IAOvH,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,4BAA4B,CAAC;IAQtH,gBAAgB,CACpB,QAAQ,EAAE,UAAU,CAAC,OAAO,YAAY,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,GACzE,OAAO,CAAC,OAAO,YAAY,EAAE,wBAAwB,CAAC;IAYnD,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;IAaxC,GAAG,CACP,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,OAAO,YAAY,EAAE,YAAY,GAC1C,OAAO,CAAC,OAAO,YAAY,EAAE,aAAa,CAAC;CAQ/C"}
|
package/dist/ai/mockAi.js
CHANGED
|
@@ -33,5 +33,62 @@ export class MockAi {
|
|
|
33
33
|
async suggestFixes(_comment) {
|
|
34
34
|
return { suggestedEdits: [] };
|
|
35
35
|
}
|
|
36
|
+
async reviewPR(_context) {
|
|
37
|
+
return {
|
|
38
|
+
summary: "AI review is not available (ANTHROPIC_API_KEY not set). Set the key and retry.",
|
|
39
|
+
issues: [],
|
|
40
|
+
positives: [],
|
|
41
|
+
verdict: "comment",
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
async generateCommitMessage(_diff) {
|
|
45
|
+
return {
|
|
46
|
+
subject: "chore: update files",
|
|
47
|
+
body: undefined,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
async generatePrContent(_commits, _diff, _stat) {
|
|
51
|
+
return {
|
|
52
|
+
title: "Update branch",
|
|
53
|
+
body: "",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async resolveConflict(filePath, conflictContent) {
|
|
57
|
+
return {
|
|
58
|
+
resolved: conflictContent,
|
|
59
|
+
confidence: "low",
|
|
60
|
+
explanation: `AI conflict resolution is not available (no AI provider configured). Please resolve ${filePath} manually.`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async reviewPRDetailed(_context) {
|
|
64
|
+
return {
|
|
65
|
+
summary: "AI PR review is not available (no AI provider configured). Set ANTHROPIC_API_KEY and retry.",
|
|
66
|
+
verdict: "comment",
|
|
67
|
+
issues: [],
|
|
68
|
+
inlineComments: [],
|
|
69
|
+
positives: [],
|
|
70
|
+
testingNotes: "Test the changes manually.",
|
|
71
|
+
checklist: [],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
async generateFix(context) {
|
|
75
|
+
return {
|
|
76
|
+
file: context.filePath,
|
|
77
|
+
startLine: context.line,
|
|
78
|
+
endLine: context.line,
|
|
79
|
+
replacement: "",
|
|
80
|
+
explanation: "AI fix generation is not available (no AI provider configured).",
|
|
81
|
+
confidence: "low",
|
|
82
|
+
resolves: false,
|
|
83
|
+
isDiscussion: true,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async ask(_question, _context) {
|
|
87
|
+
return {
|
|
88
|
+
answer: "AI is not available (no provider configured). " +
|
|
89
|
+
"Run `gitx config setup` to configure an AI provider (Claude, OpenAI, or local Claude CLI).",
|
|
90
|
+
suggestedCommands: ["gitx config setup"],
|
|
91
|
+
};
|
|
92
|
+
}
|
|
36
93
|
}
|
|
37
94
|
//# sourceMappingURL=mockAi.js.map
|
package/dist/ai/mockAi.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mockAi.js","sourceRoot":"","sources":["../../src/ai/mockAi.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mockAi.js","sourceRoot":"","sources":["../../src/ai/mockAi.ts"],"names":[],"mappings":"AAWA,MAAM,OAAO,MAAM;IACjB,KAAK,CAAC,WAAW,CAAC,KAAa;QAC7B,OAAO;YACL,IAAI,EAAE,KAAK;YACX,MAAM,EAAE,SAAS;YACjB,OAAO,EAAE,6CAA6C;YACtD,WAAW,EAAE,CAAC,0CAA0C,CAAC;YACzD,KAAK,EAAE,CAAC,iEAAiE,CAAC;SAC3E,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,QAAiB;QAClC,OAAO;YACL,KAAK,EAAE;gBACL;oBACE,EAAE,EAAE,QAAQ;oBACZ,KAAK,EAAE,cAAc;oBACrB,WAAW,EAAE,gDAAgD;iBAC9D;gBACD;oBACE,EAAE,EAAE,QAAQ;oBACZ,KAAK,EAAE,kBAAkB;oBACzB,WAAW,EAAE,wDAAwD;iBACtE;aACF;SACF,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,IAAa;QAC/B,OAAO,EAAE,MAAM,EAAE,MAAM,CAAE,IAA+B,EAAE,EAAE,IAAI,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IAC1F,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,KAAc;QACnC,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,QAAiB;QAClC,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,QAAiB;QAC9B,OAAO;YACL,OAAO,EAAE,gFAAgF;YACzF,MAAM,EAAE,EAAE;YACV,SAAS,EAAE,EAAE;YACb,OAAO,EAAE,SAAS;SACnB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,KAAa;QACvC,OAAO;YACL,OAAO,EAAE,qBAAqB;YAC9B,IAAI,EAAE,SAAS;SAChB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,iBAAiB,CAAC,QAAkB,EAAE,KAAa,EAAE,KAAc;QACvE,OAAO;YACL,KAAK,EAAE,eAAe;YACtB,IAAI,EAAE,EAAE;SACT,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,QAAgB,EAAE,eAAuB;QAC7D,OAAO;YACL,QAAQ,EAAE,eAAe;YACzB,UAAU,EAAE,KAAK;YACjB,WAAW,EAAE,uFAAuF,QAAQ,YAAY;SACzH,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,gBAAgB,CACpB,QAA0E;QAE1E,OAAO;YACL,OAAO,EAAE,6FAA6F;YACtG,OAAO,EAAE,SAAS;YAClB,MAAM,EAAE,EAAE;YACV,cAAc,EAAE,EAAE;YAClB,SAAS,EAAE,EAAE;YACb,YAAY,EAAE,4BAA4B;YAC1C,SAAS,EAAE,EAAE;SACd,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,WAAW,CACf,OAAoE;QAEpE,OAAO;YACL,IAAI,EAAE,OAAO,CAAC,QAAQ;YACtB,SAAS,EAAE,OAAO,CAAC,IAAI;YACvB,OAAO,EAAE,OAAO,CAAC,IAAI;YACrB,WAAW,EAAE,EAAE;YACf,WAAW,EAAE,iEAAiE;YAC9E,UAAU,EAAE,KAAK;YACjB,QAAQ,EAAE,KAAK;YACf,YAAY,EAAE,IAAI;SACnB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,GAAG,CACP,SAAiB,EACjB,QAA2C;QAE3C,OAAO;YACL,MAAM,EACJ,gDAAgD;gBAChD,4FAA4F;YAC9F,iBAAiB,EAAE,CAAC,mBAAmB,CAAC;SACzC,CAAC;IACJ,CAAC;CACF","sourcesContent":["import type {\n AiAnalyzeTaskResponse,\n AiClient,\n AiCommitMessageResponse,\n AiGenerateDiffsResponse,\n AiGeneratePlanResponse,\n AiReviewPRResponse,\n AiSuggestFixesResponse,\n AiSummarizeChangesResponse\n} from \"./types.js\";\n\nexport class MockAi implements AiClient {\n async analyzeTask(input: string): Promise<AiAnalyzeTaskResponse> {\n return {\n task: input,\n intent: \"unknown\",\n summary: \"Mock analysis (AI integration coming next).\",\n assumptions: [\"Repository is a Node/TypeScript project.\"],\n risks: [\"AI is currently mocked; no real code changes will be generated.\"]\n };\n }\n\n async generatePlan(_context: unknown): Promise<AiGeneratePlanResponse> {\n return {\n steps: [\n {\n id: \"step-1\",\n title: \"Inspect repo\",\n description: \"Scan structure, dependencies, and constraints.\"\n },\n {\n id: \"step-2\",\n title: \"Implement change\",\n description: \"Apply minimal changes and add/update tests if present.\"\n }\n ]\n };\n }\n\n async generateDiffs(step: unknown): Promise<AiGenerateDiffsResponse> {\n return { stepId: String((step as { id?: string } | null)?.id ?? \"unknown\"), diffs: [] };\n }\n\n async summarizeChanges(_diff: unknown): Promise<AiSummarizeChangesResponse> {\n return { summary: \"No changes (mock).\", filesChanged: [] };\n }\n\n async suggestFixes(_comment: unknown): Promise<AiSuggestFixesResponse> {\n return { suggestedEdits: [] };\n }\n\n async reviewPR(_context: unknown): Promise<AiReviewPRResponse> {\n return {\n summary: \"AI review is not available (ANTHROPIC_API_KEY not set). Set the key and retry.\",\n issues: [],\n positives: [],\n verdict: \"comment\",\n };\n }\n\n async generateCommitMessage(_diff: string): Promise<AiCommitMessageResponse> {\n return {\n subject: \"chore: update files\",\n body: undefined,\n };\n }\n\n async generatePrContent(_commits: string[], _diff: string, _stat?: string): Promise<import(\"./types.js\").AiPrContentResponse> {\n return {\n title: \"Update branch\",\n body: \"\",\n };\n }\n\n async resolveConflict(filePath: string, conflictContent: string): Promise<import(\"./types.js\").AiConflictResolutionResponse> {\n return {\n resolved: conflictContent,\n confidence: \"low\",\n explanation: `AI conflict resolution is not available (no AI provider configured). Please resolve ${filePath} manually.`,\n };\n }\n\n async reviewPRDetailed(\n _context: Parameters<import(\"./types.js\").AiClient[\"reviewPRDetailed\"]>[0]\n ): Promise<import(\"./types.js\").AiDetailedReviewResponse> {\n return {\n summary: \"AI PR review is not available (no AI provider configured). Set ANTHROPIC_API_KEY and retry.\",\n verdict: \"comment\",\n issues: [],\n inlineComments: [],\n positives: [],\n testingNotes: \"Test the changes manually.\",\n checklist: [],\n };\n }\n\n async generateFix(\n context: Parameters<import(\"./types.js\").AiClient[\"generateFix\"]>[0]\n ): Promise<import(\"./types.js\").AiFixResponse> {\n return {\n file: context.filePath,\n startLine: context.line,\n endLine: context.line,\n replacement: \"\",\n explanation: \"AI fix generation is not available (no AI provider configured).\",\n confidence: \"low\",\n resolves: false,\n isDiscussion: true,\n };\n }\n\n async ask(\n _question: string,\n _context: import(\"./types.js\").AiAskContext\n ): Promise<import(\"./types.js\").AiAskResponse> {\n return {\n answer:\n \"AI is not available (no provider configured). \" +\n \"Run `gitx config setup` to configure an AI provider (Claude, OpenAI, or local Claude CLI).\",\n suggestedCommands: [\"gitx config setup\"],\n };\n }\n}\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAiAi — OpenAI Chat Completions API integration.
|
|
3
|
+
*
|
|
4
|
+
* Authentication: OPENAI_API_KEY env var or stored config key.
|
|
5
|
+
* Model: defaults to gpt-4o. Override via GITX_AI_MODEL env var.
|
|
6
|
+
*
|
|
7
|
+
* All methods use the same structured JSON prompt pattern as ClaudeAi.
|
|
8
|
+
*/
|
|
9
|
+
import type { AiAnalyzeTaskResponse, AiClient, AiGenerateDiffsResponse, AiGeneratePlanResponse, AiReviewPRResponse, AiSuggestFixesResponse, AiSummarizeChangesResponse } from "./types.js";
|
|
10
|
+
export declare class OpenAiAi implements AiClient {
|
|
11
|
+
private readonly apiKey;
|
|
12
|
+
private readonly model;
|
|
13
|
+
/**
|
|
14
|
+
* @param apiKey OpenAI API key. Falls back to OPENAI_API_KEY env var.
|
|
15
|
+
* @param model Model override. Falls back to GITX_AI_MODEL then gpt-4o.
|
|
16
|
+
*/
|
|
17
|
+
constructor(apiKey?: string, model?: string);
|
|
18
|
+
/** Check whether an OpenAI API key is available without instantiating. */
|
|
19
|
+
static isAvailable(key?: string): boolean;
|
|
20
|
+
analyzeTask(input: string): Promise<AiAnalyzeTaskResponse>;
|
|
21
|
+
generatePlan(context: unknown): Promise<AiGeneratePlanResponse>;
|
|
22
|
+
generateDiffs(step: unknown): Promise<AiGenerateDiffsResponse>;
|
|
23
|
+
summarizeChanges(diff: unknown): Promise<AiSummarizeChangesResponse>;
|
|
24
|
+
suggestFixes(comment: unknown): Promise<AiSuggestFixesResponse>;
|
|
25
|
+
reviewPR(context: unknown): Promise<AiReviewPRResponse>;
|
|
26
|
+
generatePrContent(commits: string[], diff: string, stat?: string): Promise<import("./types.js").AiPrContentResponse>;
|
|
27
|
+
resolveConflict(filePath: string, conflictContent: string): Promise<import("./types.js").AiConflictResolutionResponse>;
|
|
28
|
+
generateCommitMessage(diff: string): Promise<import("./types.js").AiCommitMessageResponse>;
|
|
29
|
+
reviewPRDetailed(context: Parameters<import("./types.js").AiClient["reviewPRDetailed"]>[0]): Promise<import("./types.js").AiDetailedReviewResponse>;
|
|
30
|
+
generateFix(context: Parameters<import("./types.js").AiClient["generateFix"]>[0]): Promise<import("./types.js").AiFixResponse>;
|
|
31
|
+
ask(question: string, context: import("./types.js").AiAskContext): Promise<import("./types.js").AiAskResponse>;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=openAiAi.d.ts.map
|
|
@@ -0,0 +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;IA+C/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"}
|