@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.
@@ -2,36 +2,35 @@
2
2
  * gitx sync
3
3
  *
4
4
  * Bring the current branch up to date with its base branch so a PR can be
5
- * merged cleanly. Uses rebase by default (keeps a linear history).
5
+ * merged cleanly.
6
6
  *
7
7
  * Flow:
8
- * 1. Detect base branch (same logic as `gitx pr create`)
8
+ * 1. Auto-detect base branch (same logic as `gitx pr create`)
9
9
  * 2. git fetch origin
10
- * 3. git rebase origin/<base> (or --merge: git merge origin/<base>)
11
- * 4a. No conflicts → git push --force-with-lease → "ready to merge"
12
- * 4b. Conflicts list conflicting files, instruct user how to resolve,
13
- * then run `gitx sync --continue` to finish
10
+ * 3. git merge origin/<base> (default) or git rebase origin/<base>
11
+ * 4a. No conflicts → push → "ready to merge"
12
+ * 4b. Conflicts AI attempts resolution; unresolvable ones pause for manual fix
14
13
  *
15
14
  * Usage:
16
- * gitx sync # rebase onto auto-detected base
17
- * gitx sync --base main # rebase onto a specific base
18
- * gitx sync --strategy merge # merge base into branch instead of rebase
19
- * gitx sync --continue # after manually resolving conflicts
20
- * gitx sync --abort # abort an in-progress rebase/merge
15
+ * gitx sync # auto-detect base, merge (default)
16
+ * gitx sync --base main # target a specific base branch
17
+ * gitx sync --strategy rebase # rebase instead of merge
18
+ * gitx sync --continue # after manually resolving conflicts
19
+ * gitx sync --abort # abort an in-progress rebase/merge
20
+ *
21
+ * To resolve PR review comments before syncing, run `gitx pr resolve <number>` first.
21
22
  */
22
23
  import ora from "ora";
23
24
  import { execFile } from "node:child_process";
24
25
  import { promisify } from "node:util";
25
26
  import { readFile, writeFile } from "node:fs/promises";
26
27
  import { resolve as resolvePath } from "node:path";
27
- import { confirm, select } from "@inquirer/prompts";
28
+ import { confirm } from "@inquirer/prompts";
28
29
  import { logger } from "../../logger/logger.js";
29
30
  import { getCurrentBranch, detectBaseBranch } from "../../utils/gitOps.js";
30
31
  import { isInsideGitRepo } from "../../utils/git.js";
31
32
  import { GitxError } from "../../utils/errors.js";
32
33
  import { Gitx } from "../../core/gitx.js";
33
- import { createProvider } from "../../providers/factory.js";
34
- import { runAddressWorkflow, filterUnresolvedInlineComments } from "../../workflows/prAddress.js";
35
34
  const execFileAsync = promisify(execFile);
36
35
  async function git(args, cwd) {
37
36
  try {
@@ -151,11 +150,6 @@ export function registerSyncCommand(program) {
151
150
  logger.info(`✨ Already on the base branch "${base}" — nothing to sync.`);
152
151
  return;
153
152
  }
154
- // ── Check for unresolved PR review comments BEFORE syncing ────────────
155
- // If the current branch has an open PR with unresolved inline comments,
156
- // offer to resolve them now. Fixes are committed onto the branch; the
157
- // sync then rebases/merges and pushes everything together.
158
- await checkAndOfferAddressComments(cwd, head);
159
153
  logger.info(`\n🔄 Syncing ${head} onto origin/${base}\n`);
160
154
  // Fetch latest
161
155
  const fetchSpinner = ora("Fetching latest from origin…").start();
@@ -310,88 +304,6 @@ export function registerSyncCommand(program) {
310
304
  await pushAfterSync(cwd, strategy === "rebase");
311
305
  });
312
306
  }
313
- /**
314
- * Before syncing, look up any open PR for the current branch.
315
- * If it has unresolved inline review comments, ask the user:
316
- * - "Resolve comments first, then sync" → address + commit, sync continues
317
- * - "Sync normally" → proceed immediately
318
- *
319
- * Fixes are committed using "commit-no-push" mode so the sync rebase/merge
320
- * picks them up and pushes everything together in a single push.
321
- */
322
- async function checkAndOfferAddressComments(cwd, currentBranch) {
323
- let gitx = null;
324
- try {
325
- gitx = await Gitx.fromCwd(cwd);
326
- if (!await Gitx.isAiAvailable(gitx.config))
327
- return;
328
- }
329
- catch {
330
- return; // no gitx config — skip silently
331
- }
332
- let prNumber = null;
333
- let unresolvedCount = 0;
334
- try {
335
- const ctx = await gitx.getRepoContext();
336
- const provider = createProvider(ctx);
337
- // Find the open PR for the current branch
338
- const prs = await provider.listPRs(ctx.repoSlug);
339
- const openPr = prs.find((p) => p.head === currentBranch && p.state === "open");
340
- if (!openPr)
341
- return;
342
- prNumber = openPr.number;
343
- // Use the shared helper: root inline comments with no "✅ Addressed" reply yet
344
- const allComments = await provider.getPRComments(ctx.repoSlug, prNumber);
345
- unresolvedCount = filterUnresolvedInlineComments(allComments).length;
346
- if (unresolvedCount === 0)
347
- return;
348
- }
349
- catch {
350
- return; // provider error — don't block the sync
351
- }
352
- // ── Surface the choice ──────────────────────────────────────────────────────
353
- logger.info(`\n💬 PR #${prNumber} has ${unresolvedCount} unresolved review comment(s).\n`);
354
- let choice;
355
- try {
356
- choice = await select({
357
- message: "How would you like to proceed?",
358
- choices: [
359
- {
360
- name: `Resolve comments first, then sync (AI generates fixes → you approve → commit → sync)`,
361
- value: "resolve",
362
- },
363
- {
364
- name: `Sync normally (skip comment resolution, proceed with merge)`,
365
- value: "skip",
366
- },
367
- ],
368
- });
369
- }
370
- catch {
371
- return; // Ctrl-C → skip
372
- }
373
- if (choice === "skip") {
374
- logger.info("⏭️ Skipping comment resolution — proceeding with sync.\n");
375
- return;
376
- }
377
- // ── Resolve comments (commit but don't push — sync handles the push) ───────
378
- logger.info(`\n🔧 Resolving ${unresolvedCount} review comment(s) on PR #${prNumber}…\n`);
379
- try {
380
- const result = await runAddressWorkflow(gitx, prNumber, { mode: "commit-no-push" });
381
- const applied = result.addressed.filter((a) => a.applied).length;
382
- const skipped = result.addressed.filter((a) => a.skipped).length;
383
- if (applied > 0) {
384
- logger.success(`✅ ${applied} fix(es) committed.${skipped > 0 ? ` (${skipped} skipped)` : ""}`);
385
- logger.info(" Sync will rebase these commits and push everything together.\n");
386
- }
387
- else {
388
- logger.info(" No fixes applied — continuing with normal sync.\n");
389
- }
390
- }
391
- catch (err) {
392
- logger.warn(`⚠️ Comment resolution error: ${err.message}\n Continuing with sync.\n`);
393
- }
394
- }
395
307
  async function pushAfterSync(cwd, forceWithLease = false) {
396
308
  // Rebase rewrites history → requires --force-with-lease.
397
309
  // Merge does not rewrite history → plain push is fine.
@@ -1 +1 @@
1
- {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../../src/cli/commands/sync.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gitx sync\n *\n * Bring the current branch up to date with its base branch so a PR can be\n * merged cleanly. Uses rebase by default (keeps a linear history).\n *\n * Flow:\n * 1. Detect base branch (same logic as `gitx pr create`)\n * 2. git fetch origin\n * 3. git rebase origin/<base> (or --merge: git merge origin/<base>)\n * 4a. No conflicts → git push --force-with-lease → \"ready to merge\"\n * 4b. Conflicts → list conflicting files, instruct user how to resolve,\n * then run `gitx sync --continue` to finish\n *\n * Usage:\n * gitx sync # rebase onto auto-detected base\n * gitx sync --base main # rebase onto a specific base\n * gitx sync --strategy merge # merge base into branch instead of rebase\n * gitx sync --continue # after manually resolving conflicts\n * gitx sync --abort # abort an in-progress rebase/merge\n */\n\nimport type { Command } from \"commander\";\nimport ora from \"ora\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { resolve as resolvePath } from \"node:path\";\nimport { confirm, select } from \"@inquirer/prompts\";\nimport { logger } from \"../../logger/logger.js\";\nimport { getCurrentBranch, detectBaseBranch } from \"../../utils/gitOps.js\";\nimport { isInsideGitRepo } from \"../../utils/git.js\";\nimport { GitxError } from \"../../utils/errors.js\";\nimport { Gitx } from \"../../core/gitx.js\";\nimport { createProvider } from \"../../providers/factory.js\";\nimport { runAddressWorkflow, filterUnresolvedInlineComments } from \"../../workflows/prAddress.js\";\n\nconst execFileAsync = promisify(execFile);\n\nasync function git(\n args: string[],\n cwd: string\n): Promise<{ stdout: string; stderr: string }> {\n try {\n const result = await execFileAsync(\"git\", args, { cwd });\n return { stdout: result.stdout.trim(), stderr: \"\" };\n } catch (err: unknown) {\n const e = err as { stdout?: string; stderr?: string; message?: string };\n return {\n stdout: e.stdout?.trim() ?? \"\",\n stderr: (e.stderr ?? e.message ?? String(err)).trim(),\n };\n }\n}\n\n/** Returns list of files that currently have conflict markers. */\nasync function getConflictingFiles(cwd: string): Promise<string[]> {\n const { stdout } = await git(\n [\"diff\", \"--name-only\", \"--diff-filter=U\"],\n cwd\n );\n return stdout.split(\"\\n\").map((l) => l.trim()).filter(Boolean);\n}\n\n/** Check whether a rebase or merge is currently in progress. */\nasync function getInProgressOperation(\n cwd: string\n): Promise<\"rebase\" | \"merge\" | null> {\n const { stdout: gitDir } = await git([\"rev-parse\", \"--git-dir\"], cwd);\n const base = gitDir || \".git\";\n\n const { stdout: rebaseDir } = await git(\n [\"rev-parse\", \"--git-path\", \"rebase-merge\"],\n cwd\n );\n const { stdout: rebaseApply } = await git(\n [\"rev-parse\", \"--git-path\", \"rebase-apply\"],\n cwd\n );\n const { stdout: mergeHead } = await git(\n [\"rev-parse\", \"--git-path\", \"MERGE_HEAD\"],\n cwd\n );\n\n // Check if the paths actually exist on disk\n const { existsSync } = await import(\"node:fs\");\n if (existsSync(rebaseDir) || existsSync(rebaseApply)) return \"rebase\";\n if (existsSync(mergeHead) || existsSync(`${base}/MERGE_HEAD`)) return \"merge\";\n return null;\n}\n\nexport function registerSyncCommand(program: Command): void {\n program\n .command(\"sync\")\n .description(\"🔄 Sync current branch with its base branch (merge by default, or --strategy rebase)\")\n .option(\"--base <branch>\", \"Base branch to sync with (auto-detected if omitted)\")\n .option(\n \"--strategy <strategy>\",\n \"Sync strategy: merge (default) | rebase\",\n \"merge\"\n )\n .option(\"--continue\", \"Continue after manually resolving conflicts\")\n .option(\"--abort\", \"Abort an in-progress rebase or merge\")\n .action(async (opts: {\n base?: string;\n strategy: string;\n continue?: boolean;\n abort?: boolean;\n }) => {\n const cwd = process.cwd();\n\n if (!(await isInsideGitRepo(cwd))) {\n throw new GitxError(\"Not inside a git repository. cd into your project folder first.\", { exitCode: 2 });\n }\n\n const strategy = opts.strategy === \"rebase\" ? \"rebase\" : \"merge\";\n\n // ── Handle --abort ─────────────────────────────────────────────────────\n if (opts.abort) {\n const op = await getInProgressOperation(cwd);\n if (!op) {\n logger.info(\"No rebase or merge in progress.\");\n return;\n }\n const abortSpinner = ora(`Aborting ${op}…`).start();\n const { stderr } = await git([op, \"--abort\"], cwd);\n if (stderr) {\n abortSpinner.fail(`Abort failed: ${stderr}`);\n process.exitCode = 1;\n return;\n }\n abortSpinner.succeed(`${op.charAt(0).toUpperCase() + op.slice(1)} aborted. Branch restored to its previous state.`);\n return;\n }\n\n // ── Handle --continue ──────────────────────────────────────────────────\n if (opts.continue) {\n const op = await getInProgressOperation(cwd);\n if (!op) {\n logger.info(\"No rebase or merge in progress — nothing to continue.\");\n return;\n }\n\n // Check if all conflicts are resolved\n const conflicts = await getConflictingFiles(cwd);\n if (conflicts.length > 0) {\n logger.error(`\\n❌ There are still unresolved conflicts:\\n`);\n for (const f of conflicts) logger.info(` • ${f}`);\n logger.info(`\\n Fix the conflicts above, then:\\n`);\n logger.info(` git add <file> # mark each file as resolved`);\n logger.info(` gitx sync --continue # resume\\n`);\n process.exitCode = 1;\n return;\n }\n\n // Stage all resolved files and continue\n await git([\"add\", \"-A\"], cwd);\n const continueSpinner = ora(`Continuing ${op}…`).start();\n\n const env = { ...process.env, GIT_EDITOR: \"true\" }; // skip editor for commit msg\n const { stderr } = await execFileAsync(\n \"git\",\n [op, \"--continue\"],\n { cwd, env }\n ).then(\n (r) => ({ stdout: r.stdout, stderr: \"\" }),\n (e: { stderr?: string; message?: string }) => ({\n stdout: \"\",\n stderr: (e.stderr ?? e.message ?? \"\").trim(),\n })\n );\n\n if (stderr && !stderr.includes(\"Successfully\")) {\n continueSpinner.fail(`Could not continue ${op}: ${stderr}`);\n process.exitCode = 1;\n return;\n }\n continueSpinner.succeed(`${op.charAt(0).toUpperCase() + op.slice(1)} completed ✓`);\n\n // Rebase rewrites history; merge does not\n await pushAfterSync(cwd, op === \"rebase\");\n return;\n }\n\n // ── Normal sync flow ───────────────────────────────────────────────────\n const head = await getCurrentBranch(cwd);\n\n // Resolve base\n let base: string;\n if (opts.base) {\n base = opts.base;\n logger.info(`📌 Base branch (provided): ${base}`);\n } else {\n const detectSpinner = ora(\"Detecting base branch…\").start();\n base = await detectBaseBranch(cwd);\n detectSpinner.succeed(`Base branch: ${base}`);\n }\n\n if (head === base) {\n logger.info(`✨ Already on the base branch \"${base}\" — nothing to sync.`);\n return;\n }\n\n // ── Check for unresolved PR review comments BEFORE syncing ────────────\n // If the current branch has an open PR with unresolved inline comments,\n // offer to resolve them now. Fixes are committed onto the branch; the\n // sync then rebases/merges and pushes everything together.\n await checkAndOfferAddressComments(cwd, head);\n\n logger.info(`\\n🔄 Syncing ${head} onto origin/${base}\\n`);\n\n // Fetch latest\n const fetchSpinner = ora(\"Fetching latest from origin…\").start();\n const { stderr: fetchErr } = await git([\"fetch\", \"origin\"], cwd);\n if (fetchErr && !fetchErr.includes(\"->\")) {\n fetchSpinner.fail(`Fetch failed: ${fetchErr}`);\n process.exitCode = 1;\n return;\n }\n fetchSpinner.succeed(\"Fetched latest.\");\n\n // Check if we're already up to date\n const { stdout: behindCount } = await git(\n [\"rev-list\", \"--count\", `HEAD..origin/${base}`],\n cwd\n );\n if (behindCount === \"0\") {\n logger.success(`✅ \"${head}\" is already up to date with origin/${base}. Ready to merge!`);\n return;\n }\n\n // Run rebase or merge\n const syncSpinner = ora(\n strategy === \"rebase\"\n ? `Rebasing ${head} onto origin/${base}…`\n : `Merging origin/${base} into ${head}…`\n ).start();\n\n const syncArgs =\n strategy === \"rebase\"\n ? [\"rebase\", `origin/${base}`]\n : [\"merge\", `origin/${base}`, \"--no-edit\"];\n\n const { stderr: syncErr } = await git(syncArgs, cwd);\n\n // Detect conflict — try AI resolution first\n const conflicts = await getConflictingFiles(cwd);\n if (conflicts.length > 0) {\n syncSpinner.fail(`Conflicts detected in ${conflicts.length} file(s) — attempting AI resolution…`);\n\n // Try to load an AI client\n let gitx: Gitx | null = null;\n try {\n gitx = await Gitx.fromCwd(cwd);\n } catch {\n // No AI available; fall through to manual instructions\n }\n\n if (gitx && await Gitx.isAiAvailable(gitx.config)) {\n const resolved: string[] = [];\n const needsManual: string[] = [];\n\n for (const filePath of conflicts) {\n const absPath = resolvePath(cwd, filePath);\n let content: string;\n try {\n content = await readFile(absPath, \"utf8\");\n } catch {\n needsManual.push(filePath);\n continue;\n }\n\n // Skip binary files (no conflict markers)\n if (!content.includes(\"<<<<<<<\")) {\n needsManual.push(filePath);\n continue;\n }\n\n const resolveSpinner = ora(` 🤖 AI resolving: ${filePath}`).start();\n try {\n const result = await gitx.ai.resolveConflict(filePath, content);\n\n if (result.confidence === \"high\") {\n await writeFile(absPath, result.resolved, \"utf8\");\n resolveSpinner.succeed(` ✅ Auto-resolved: ${filePath} — ${result.explanation}`);\n resolved.push(filePath);\n } else {\n resolveSpinner.warn(` ⚠️ Low confidence: ${filePath} — ${result.explanation}`);\n logger.info(`\\n AI proposed resolution (low confidence). Preview:\\n`);\n // Show first 40 lines of the resolved content as a preview\n const preview = result.resolved.split(\"\\n\").slice(0, 40).join(\"\\n\");\n logger.info(preview);\n if (result.resolved.split(\"\\n\").length > 40) {\n logger.info(` … (${result.resolved.split(\"\\n\").length - 40} more lines)`);\n }\n logger.info(\"\");\n\n let apply = false;\n try {\n apply = await confirm({\n message: `Apply AI resolution for ${filePath}?`,\n default: true,\n });\n } catch {\n apply = false;\n }\n\n if (apply) {\n await writeFile(absPath, result.resolved, \"utf8\");\n logger.success(` ✅ Applied: ${filePath}`);\n resolved.push(filePath);\n } else {\n logger.info(` ⏭️ Skipped: ${filePath} — resolve manually`);\n needsManual.push(filePath);\n }\n }\n } catch {\n resolveSpinner.fail(` ❌ AI resolution failed for: ${filePath}`);\n needsManual.push(filePath);\n }\n }\n\n if (needsManual.length > 0) {\n logger.error(`\\n⚠️ ${needsManual.length} file(s) still need manual resolution:\\n`);\n for (const f of needsManual) logger.info(` • ${f}`);\n logger.info(`\\n Steps to finish:\\n`);\n logger.info(` 1. Open each file and fix the conflict markers (<<<<, ====, >>>>)`);\n logger.info(` 2. Mark resolved: git add <file>`);\n logger.info(` 3. Finish sync: gitx sync --continue`);\n logger.info(` 4. Retry merge: gitx pr merge <number>\\n`);\n logger.info(` To give up and go back: gitx sync --abort\\n`);\n process.exitCode = 1;\n return;\n }\n\n // All resolved — stage and continue\n if (resolved.length > 0) {\n logger.success(`\\n✅ AI resolved all ${resolved.length} conflict(s). Staging and continuing…\\n`);\n await git([\"add\", \"-A\"], cwd);\n\n const env = { ...process.env, GIT_EDITOR: \"true\" };\n const { stderr: contErr } = await execFileAsync(\n \"git\",\n [strategy === \"rebase\" ? \"rebase\" : \"merge\", \"--continue\"],\n { cwd, env }\n ).then(\n (r) => ({ stdout: r.stdout, stderr: \"\" }),\n (e: { stderr?: string; message?: string }) => ({\n stdout: \"\",\n stderr: (e.stderr ?? e.message ?? \"\").trim(),\n })\n );\n\n if (contErr && !contErr.toLowerCase().includes(\"successfully\")) {\n logger.error(`Could not continue ${strategy}: ${contErr}`);\n process.exitCode = 1;\n return;\n }\n }\n } else {\n // No AI — fall back to manual instructions\n logger.error(`\\n⚠️ Merge conflicts in ${conflicts.length} file(s):\\n`);\n for (const f of conflicts) logger.info(` • ${f}`);\n logger.info(`\\n Steps to resolve:\\n`);\n logger.info(` 1. Open each file and fix the conflict markers (<<<<, ====, >>>>)`);\n logger.info(` 2. Mark resolved: git add <file>`);\n logger.info(` 3. Finish sync: gitx sync --continue`);\n logger.info(` 4. Retry merge: gitx pr merge <number>\\n`);\n logger.info(` To give up and go back: gitx sync --abort\\n`);\n process.exitCode = 1;\n return;\n }\n }\n\n if (syncErr && !syncErr.toLowerCase().includes(\"successfully\")) {\n syncSpinner.fail(`Sync failed: ${syncErr}`);\n process.exitCode = 1;\n return;\n }\n\n syncSpinner.succeed(\n strategy === \"rebase\"\n ? `Rebased ${head} onto origin/${base} ✓`\n : `Merged origin/${base} into ${head} ✓`\n );\n\n // Rebase rewrites history → force-with-lease; merge → plain push\n await pushAfterSync(cwd, strategy === \"rebase\");\n });\n}\n\n/**\n * Before syncing, look up any open PR for the current branch.\n * If it has unresolved inline review comments, ask the user:\n * - \"Resolve comments first, then sync\" → address + commit, sync continues\n * - \"Sync normally\" → proceed immediately\n *\n * Fixes are committed using \"commit-no-push\" mode so the sync rebase/merge\n * picks them up and pushes everything together in a single push.\n */\nasync function checkAndOfferAddressComments(cwd: string, currentBranch: string): Promise<void> {\n let gitx: Gitx | null = null;\n try {\n gitx = await Gitx.fromCwd(cwd);\n if (!await Gitx.isAiAvailable(gitx.config)) return;\n } catch {\n return; // no gitx config — skip silently\n }\n\n let prNumber: number | null = null;\n let unresolvedCount = 0;\n\n try {\n const ctx = await gitx.getRepoContext();\n const provider = createProvider(ctx);\n\n // Find the open PR for the current branch\n const prs = await provider.listPRs(ctx.repoSlug);\n const openPr = prs.find((p) => p.head === currentBranch && p.state === \"open\");\n if (!openPr) return;\n\n prNumber = openPr.number;\n\n // Use the shared helper: root inline comments with no \"✅ Addressed\" reply yet\n const allComments = await provider.getPRComments(ctx.repoSlug, prNumber);\n unresolvedCount = filterUnresolvedInlineComments(allComments).length;\n\n if (unresolvedCount === 0) return;\n } catch {\n return; // provider error — don't block the sync\n }\n\n // ── Surface the choice ──────────────────────────────────────────────────────\n logger.info(`\\n💬 PR #${prNumber} has ${unresolvedCount} unresolved review comment(s).\\n`);\n\n let choice: string;\n try {\n choice = await select({\n message: \"How would you like to proceed?\",\n choices: [\n {\n name: `Resolve comments first, then sync (AI generates fixes → you approve → commit → sync)`,\n value: \"resolve\",\n },\n {\n name: `Sync normally (skip comment resolution, proceed with merge)`,\n value: \"skip\",\n },\n ],\n });\n } catch {\n return; // Ctrl-C → skip\n }\n\n if (choice === \"skip\") {\n logger.info(\"⏭️ Skipping comment resolution — proceeding with sync.\\n\");\n return;\n }\n\n // ── Resolve comments (commit but don't push — sync handles the push) ───────\n logger.info(`\\n🔧 Resolving ${unresolvedCount} review comment(s) on PR #${prNumber}…\\n`);\n try {\n const result = await runAddressWorkflow(gitx!, prNumber, { mode: \"commit-no-push\" });\n const applied = result.addressed.filter((a) => a.applied).length;\n const skipped = result.addressed.filter((a) => a.skipped).length;\n\n if (applied > 0) {\n logger.success(`✅ ${applied} fix(es) committed.${skipped > 0 ? ` (${skipped} skipped)` : \"\"}`);\n logger.info(\" Sync will rebase these commits and push everything together.\\n\");\n } else {\n logger.info(\" No fixes applied — continuing with normal sync.\\n\");\n }\n } catch (err) {\n logger.warn(`⚠️ Comment resolution error: ${(err as Error).message}\\n Continuing with sync.\\n`);\n }\n}\n\nasync function pushAfterSync(cwd: string, forceWithLease = false): Promise<void> {\n // Rebase rewrites history → requires --force-with-lease.\n // Merge does not rewrite history → plain push is fine.\n const pushArgs = forceWithLease\n ? [\"push\", \"--force-with-lease\"]\n : [\"push\"];\n\n const label = forceWithLease ? \"Pushing (force-with-lease)…\" : \"Pushing…\";\n const pushSpinner = ora(label).start();\n const { stderr } = await git(pushArgs, cwd);\n if (stderr && stderr.includes(\"error\")) {\n pushSpinner.fail(`Push failed: ${stderr}`);\n const hint = forceWithLease ? \"git push --force-with-lease\" : \"git push\";\n logger.info(` Try: ${hint}`);\n process.exitCode = 1;\n return;\n }\n pushSpinner.succeed(\"Pushed ✓\");\n logger.success(`\\n✅ Branch is now up to date. Run \\`gitx pr merge <number>\\` to merge.\\n`);\n}\n"]}
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../../src/cli/commands/sync.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * gitx sync\n *\n * Bring the current branch up to date with its base branch so a PR can be\n * merged cleanly.\n *\n * Flow:\n * 1. Auto-detect base branch (same logic as `gitx pr create`)\n * 2. git fetch origin\n * 3. git merge origin/<base> (default) or git rebase origin/<base>\n * 4a. No conflicts → push → \"ready to merge\"\n * 4b. Conflicts → AI attempts resolution; unresolvable ones pause for manual fix\n *\n * Usage:\n * gitx sync # auto-detect base, merge (default)\n * gitx sync --base main # target a specific base branch\n * gitx sync --strategy rebase # rebase instead of merge\n * gitx sync --continue # after manually resolving conflicts\n * gitx sync --abort # abort an in-progress rebase/merge\n *\n * To resolve PR review comments before syncing, run `gitx pr resolve <number>` first.\n */\n\nimport type { Command } from \"commander\";\nimport ora from \"ora\";\nimport { execFile } from \"node:child_process\";\nimport { promisify } from \"node:util\";\nimport { readFile, writeFile } from \"node:fs/promises\";\nimport { resolve as resolvePath } from \"node:path\";\nimport { confirm } from \"@inquirer/prompts\";\nimport { logger } from \"../../logger/logger.js\";\nimport { getCurrentBranch, detectBaseBranch } from \"../../utils/gitOps.js\";\nimport { isInsideGitRepo } from \"../../utils/git.js\";\nimport { GitxError } from \"../../utils/errors.js\";\nimport { Gitx } from \"../../core/gitx.js\";\n\nconst execFileAsync = promisify(execFile);\n\nasync function git(\n args: string[],\n cwd: string\n): Promise<{ stdout: string; stderr: string }> {\n try {\n const result = await execFileAsync(\"git\", args, { cwd });\n return { stdout: result.stdout.trim(), stderr: \"\" };\n } catch (err: unknown) {\n const e = err as { stdout?: string; stderr?: string; message?: string };\n return {\n stdout: e.stdout?.trim() ?? \"\",\n stderr: (e.stderr ?? e.message ?? String(err)).trim(),\n };\n }\n}\n\n/** Returns list of files that currently have conflict markers. */\nasync function getConflictingFiles(cwd: string): Promise<string[]> {\n const { stdout } = await git(\n [\"diff\", \"--name-only\", \"--diff-filter=U\"],\n cwd\n );\n return stdout.split(\"\\n\").map((l) => l.trim()).filter(Boolean);\n}\n\n/** Check whether a rebase or merge is currently in progress. */\nasync function getInProgressOperation(\n cwd: string\n): Promise<\"rebase\" | \"merge\" | null> {\n const { stdout: gitDir } = await git([\"rev-parse\", \"--git-dir\"], cwd);\n const base = gitDir || \".git\";\n\n const { stdout: rebaseDir } = await git(\n [\"rev-parse\", \"--git-path\", \"rebase-merge\"],\n cwd\n );\n const { stdout: rebaseApply } = await git(\n [\"rev-parse\", \"--git-path\", \"rebase-apply\"],\n cwd\n );\n const { stdout: mergeHead } = await git(\n [\"rev-parse\", \"--git-path\", \"MERGE_HEAD\"],\n cwd\n );\n\n // Check if the paths actually exist on disk\n const { existsSync } = await import(\"node:fs\");\n if (existsSync(rebaseDir) || existsSync(rebaseApply)) return \"rebase\";\n if (existsSync(mergeHead) || existsSync(`${base}/MERGE_HEAD`)) return \"merge\";\n return null;\n}\n\nexport function registerSyncCommand(program: Command): void {\n program\n .command(\"sync\")\n .description(\"🔄 Sync current branch with its base branch (merge by default, or --strategy rebase)\")\n .option(\"--base <branch>\", \"Base branch to sync with (auto-detected if omitted)\")\n .option(\n \"--strategy <strategy>\",\n \"Sync strategy: merge (default) | rebase\",\n \"merge\"\n )\n .option(\"--continue\", \"Continue after manually resolving conflicts\")\n .option(\"--abort\", \"Abort an in-progress rebase or merge\")\n .action(async (opts: {\n base?: string;\n strategy: string;\n continue?: boolean;\n abort?: boolean;\n }) => {\n const cwd = process.cwd();\n\n if (!(await isInsideGitRepo(cwd))) {\n throw new GitxError(\"Not inside a git repository. cd into your project folder first.\", { exitCode: 2 });\n }\n\n const strategy = opts.strategy === \"rebase\" ? \"rebase\" : \"merge\";\n\n // ── Handle --abort ─────────────────────────────────────────────────────\n if (opts.abort) {\n const op = await getInProgressOperation(cwd);\n if (!op) {\n logger.info(\"No rebase or merge in progress.\");\n return;\n }\n const abortSpinner = ora(`Aborting ${op}…`).start();\n const { stderr } = await git([op, \"--abort\"], cwd);\n if (stderr) {\n abortSpinner.fail(`Abort failed: ${stderr}`);\n process.exitCode = 1;\n return;\n }\n abortSpinner.succeed(`${op.charAt(0).toUpperCase() + op.slice(1)} aborted. Branch restored to its previous state.`);\n return;\n }\n\n // ── Handle --continue ──────────────────────────────────────────────────\n if (opts.continue) {\n const op = await getInProgressOperation(cwd);\n if (!op) {\n logger.info(\"No rebase or merge in progress — nothing to continue.\");\n return;\n }\n\n // Check if all conflicts are resolved\n const conflicts = await getConflictingFiles(cwd);\n if (conflicts.length > 0) {\n logger.error(`\\n❌ There are still unresolved conflicts:\\n`);\n for (const f of conflicts) logger.info(` • ${f}`);\n logger.info(`\\n Fix the conflicts above, then:\\n`);\n logger.info(` git add <file> # mark each file as resolved`);\n logger.info(` gitx sync --continue # resume\\n`);\n process.exitCode = 1;\n return;\n }\n\n // Stage all resolved files and continue\n await git([\"add\", \"-A\"], cwd);\n const continueSpinner = ora(`Continuing ${op}…`).start();\n\n const env = { ...process.env, GIT_EDITOR: \"true\" }; // skip editor for commit msg\n const { stderr } = await execFileAsync(\n \"git\",\n [op, \"--continue\"],\n { cwd, env }\n ).then(\n (r) => ({ stdout: r.stdout, stderr: \"\" }),\n (e: { stderr?: string; message?: string }) => ({\n stdout: \"\",\n stderr: (e.stderr ?? e.message ?? \"\").trim(),\n })\n );\n\n if (stderr && !stderr.includes(\"Successfully\")) {\n continueSpinner.fail(`Could not continue ${op}: ${stderr}`);\n process.exitCode = 1;\n return;\n }\n continueSpinner.succeed(`${op.charAt(0).toUpperCase() + op.slice(1)} completed ✓`);\n\n // Rebase rewrites history; merge does not\n await pushAfterSync(cwd, op === \"rebase\");\n return;\n }\n\n // ── Normal sync flow ───────────────────────────────────────────────────\n const head = await getCurrentBranch(cwd);\n\n // Resolve base\n let base: string;\n if (opts.base) {\n base = opts.base;\n logger.info(`📌 Base branch (provided): ${base}`);\n } else {\n const detectSpinner = ora(\"Detecting base branch…\").start();\n base = await detectBaseBranch(cwd);\n detectSpinner.succeed(`Base branch: ${base}`);\n }\n\n if (head === base) {\n logger.info(`✨ Already on the base branch \"${base}\" — nothing to sync.`);\n return;\n }\n\n logger.info(`\\n🔄 Syncing ${head} onto origin/${base}\\n`);\n\n // Fetch latest\n const fetchSpinner = ora(\"Fetching latest from origin…\").start();\n const { stderr: fetchErr } = await git([\"fetch\", \"origin\"], cwd);\n if (fetchErr && !fetchErr.includes(\"->\")) {\n fetchSpinner.fail(`Fetch failed: ${fetchErr}`);\n process.exitCode = 1;\n return;\n }\n fetchSpinner.succeed(\"Fetched latest.\");\n\n // Check if we're already up to date\n const { stdout: behindCount } = await git(\n [\"rev-list\", \"--count\", `HEAD..origin/${base}`],\n cwd\n );\n if (behindCount === \"0\") {\n logger.success(`✅ \"${head}\" is already up to date with origin/${base}. Ready to merge!`);\n return;\n }\n\n // Run rebase or merge\n const syncSpinner = ora(\n strategy === \"rebase\"\n ? `Rebasing ${head} onto origin/${base}…`\n : `Merging origin/${base} into ${head}…`\n ).start();\n\n const syncArgs =\n strategy === \"rebase\"\n ? [\"rebase\", `origin/${base}`]\n : [\"merge\", `origin/${base}`, \"--no-edit\"];\n\n const { stderr: syncErr } = await git(syncArgs, cwd);\n\n // Detect conflict — try AI resolution first\n const conflicts = await getConflictingFiles(cwd);\n if (conflicts.length > 0) {\n syncSpinner.fail(`Conflicts detected in ${conflicts.length} file(s) — attempting AI resolution…`);\n\n // Try to load an AI client\n let gitx: Gitx | null = null;\n try {\n gitx = await Gitx.fromCwd(cwd);\n } catch {\n // No AI available; fall through to manual instructions\n }\n\n if (gitx && await Gitx.isAiAvailable(gitx.config)) {\n const resolved: string[] = [];\n const needsManual: string[] = [];\n\n for (const filePath of conflicts) {\n const absPath = resolvePath(cwd, filePath);\n let content: string;\n try {\n content = await readFile(absPath, \"utf8\");\n } catch {\n needsManual.push(filePath);\n continue;\n }\n\n // Skip binary files (no conflict markers)\n if (!content.includes(\"<<<<<<<\")) {\n needsManual.push(filePath);\n continue;\n }\n\n const resolveSpinner = ora(` 🤖 AI resolving: ${filePath}`).start();\n try {\n const result = await gitx.ai.resolveConflict(filePath, content);\n\n if (result.confidence === \"high\") {\n await writeFile(absPath, result.resolved, \"utf8\");\n resolveSpinner.succeed(` ✅ Auto-resolved: ${filePath} — ${result.explanation}`);\n resolved.push(filePath);\n } else {\n resolveSpinner.warn(` ⚠️ Low confidence: ${filePath} — ${result.explanation}`);\n logger.info(`\\n AI proposed resolution (low confidence). Preview:\\n`);\n // Show first 40 lines of the resolved content as a preview\n const preview = result.resolved.split(\"\\n\").slice(0, 40).join(\"\\n\");\n logger.info(preview);\n if (result.resolved.split(\"\\n\").length > 40) {\n logger.info(` … (${result.resolved.split(\"\\n\").length - 40} more lines)`);\n }\n logger.info(\"\");\n\n let apply = false;\n try {\n apply = await confirm({\n message: `Apply AI resolution for ${filePath}?`,\n default: true,\n });\n } catch {\n apply = false;\n }\n\n if (apply) {\n await writeFile(absPath, result.resolved, \"utf8\");\n logger.success(` ✅ Applied: ${filePath}`);\n resolved.push(filePath);\n } else {\n logger.info(` ⏭️ Skipped: ${filePath} — resolve manually`);\n needsManual.push(filePath);\n }\n }\n } catch {\n resolveSpinner.fail(` ❌ AI resolution failed for: ${filePath}`);\n needsManual.push(filePath);\n }\n }\n\n if (needsManual.length > 0) {\n logger.error(`\\n⚠️ ${needsManual.length} file(s) still need manual resolution:\\n`);\n for (const f of needsManual) logger.info(` • ${f}`);\n logger.info(`\\n Steps to finish:\\n`);\n logger.info(` 1. Open each file and fix the conflict markers (<<<<, ====, >>>>)`);\n logger.info(` 2. Mark resolved: git add <file>`);\n logger.info(` 3. Finish sync: gitx sync --continue`);\n logger.info(` 4. Retry merge: gitx pr merge <number>\\n`);\n logger.info(` To give up and go back: gitx sync --abort\\n`);\n process.exitCode = 1;\n return;\n }\n\n // All resolved — stage and continue\n if (resolved.length > 0) {\n logger.success(`\\n✅ AI resolved all ${resolved.length} conflict(s). Staging and continuing…\\n`);\n await git([\"add\", \"-A\"], cwd);\n\n const env = { ...process.env, GIT_EDITOR: \"true\" };\n const { stderr: contErr } = await execFileAsync(\n \"git\",\n [strategy === \"rebase\" ? \"rebase\" : \"merge\", \"--continue\"],\n { cwd, env }\n ).then(\n (r) => ({ stdout: r.stdout, stderr: \"\" }),\n (e: { stderr?: string; message?: string }) => ({\n stdout: \"\",\n stderr: (e.stderr ?? e.message ?? \"\").trim(),\n })\n );\n\n if (contErr && !contErr.toLowerCase().includes(\"successfully\")) {\n logger.error(`Could not continue ${strategy}: ${contErr}`);\n process.exitCode = 1;\n return;\n }\n }\n } else {\n // No AI — fall back to manual instructions\n logger.error(`\\n⚠️ Merge conflicts in ${conflicts.length} file(s):\\n`);\n for (const f of conflicts) logger.info(` • ${f}`);\n logger.info(`\\n Steps to resolve:\\n`);\n logger.info(` 1. Open each file and fix the conflict markers (<<<<, ====, >>>>)`);\n logger.info(` 2. Mark resolved: git add <file>`);\n logger.info(` 3. Finish sync: gitx sync --continue`);\n logger.info(` 4. Retry merge: gitx pr merge <number>\\n`);\n logger.info(` To give up and go back: gitx sync --abort\\n`);\n process.exitCode = 1;\n return;\n }\n }\n\n if (syncErr && !syncErr.toLowerCase().includes(\"successfully\")) {\n syncSpinner.fail(`Sync failed: ${syncErr}`);\n process.exitCode = 1;\n return;\n }\n\n syncSpinner.succeed(\n strategy === \"rebase\"\n ? `Rebased ${head} onto origin/${base} ✓`\n : `Merged origin/${base} into ${head} ✓`\n );\n\n // Rebase rewrites history → force-with-lease; merge → plain push\n await pushAfterSync(cwd, strategy === \"rebase\");\n });\n}\n\n\nasync function pushAfterSync(cwd: string, forceWithLease = false): Promise<void> {\n // Rebase rewrites history → requires --force-with-lease.\n // Merge does not rewrite history → plain push is fine.\n const pushArgs = forceWithLease\n ? [\"push\", \"--force-with-lease\"]\n : [\"push\"];\n\n const label = forceWithLease ? \"Pushing (force-with-lease)…\" : \"Pushing…\";\n const pushSpinner = ora(label).start();\n const { stderr } = await git(pushArgs, cwd);\n if (stderr && stderr.includes(\"error\")) {\n pushSpinner.fail(`Push failed: ${stderr}`);\n const hint = forceWithLease ? \"git push --force-with-lease\" : \"git push\";\n logger.info(` Try: ${hint}`);\n process.exitCode = 1;\n return;\n }\n pushSpinner.succeed(\"Pushed ✓\");\n logger.success(`\\n✅ Branch is now up to date. Run \\`gitx pr merge <number>\\` to merge.\\n`);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"pr.d.ts","sourceRoot":"","sources":["../../src/workflows/pr.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AA4B5E,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,WAAW,CAAC;IAChB,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,gBAAgB,EAAE,wBAAwB,CAAC;IAC3D,gEAAgE;IAChE,YAAY,EAAE,OAAO,CAAC;IACtB,uFAAuF;IACvF,cAAc,EAAE,QAAQ,GAAG,gBAAgB,GAAG,MAAM,CAAC;CACtD;AA6DD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,WAAW,UAAO,GACjB,OAAO,CAAC,YAAY,CAAC,CAoJvB;AAID,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,WAAW,CAAC;IAChB,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,YAAY,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzD,YAAY,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvD;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,MAAM,UAAQ,EACd,QAAQ,UAAQ,GACf,OAAO,CAAC,iBAAiB,CAAC,CA8F5B"}
1
+ {"version":3,"file":"pr.d.ts","sourceRoot":"","sources":["../../src/workflows/pr.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AA4B5E,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,WAAW,CAAC;IAChB,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,gBAAgB,EAAE,wBAAwB,CAAC;IAC3D,gEAAgE;IAChE,YAAY,EAAE,OAAO,CAAC;IACtB,uFAAuF;IACvF,cAAc,EAAE,QAAQ,GAAG,gBAAgB,GAAG,MAAM,CAAC;CACtD;AA6DD;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,WAAW,UAAO,GACjB,OAAO,CAAC,YAAY,CAAC,CAoJvB;AAID,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,WAAW,CAAC;IAChB,QAAQ,EAAE,kBAAkB,EAAE,CAAC;IAC/B,YAAY,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzD,YAAY,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACvD;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,MAAM,UAAQ,EACd,QAAQ,UAAQ,GACf,OAAO,CAAC,iBAAiB,CAAC,CA0J5B"}
@@ -216,29 +216,84 @@ export async function runFixCommentsWorkflow(gitx, prNumber, dryRun = false, noC
216
216
  const cwd = gitx.cwd;
217
217
  const ctx = await gitx.getRepoContext();
218
218
  const provider = createProvider(ctx);
219
- logger.info(`🔍 Fetching PR #${prNumber}…`);
219
+ const fetchSpinner = ora("Fetching PR, comments and diff…").start();
220
220
  const pr = await provider.getPR(ctx.repoSlug, prNumber);
221
- logger.info("💬 Fetching review comments…");
222
- const comments = await provider.getPRComments(ctx.repoSlug, prNumber);
221
+ const [comments, diff] = await Promise.all([
222
+ provider.getPRComments(ctx.repoSlug, prNumber),
223
+ provider.getPRDiff(ctx.repoSlug, prNumber),
224
+ ]);
225
+ fetchSpinner.succeed(`PR #${prNumber}: "${pr.title}" — ${comments.length} comment(s)`);
223
226
  if (comments.length === 0) {
224
227
  logger.info("No review comments found.");
225
228
  return { pr, comments, appliedFixes: [], skippedFixes: [] };
226
229
  }
227
- // Gather file contents for files mentioned in comments
230
+ // ── Build file context ────────────────────────────────────────────────────
231
+ // Only load files directly mentioned in comments + their close imports.
232
+ // Random repo source files are irrelevant — the AI is fixing specific lines.
233
+ const ctxSpinner = ora("Building file context for commented files…").start();
228
234
  const mentionedPaths = [...new Set(comments.map((c) => c.path).filter(Boolean))];
229
235
  const trackedFiles = await listTrackedFiles(cwd);
230
- // Also include files mentioned in the PR body / title
231
- const allSourceFiles = trackedFiles
232
- .filter((f) => /\.(ts|js|tsx|jsx|py|go|rs|java|rb|cs|cpp|c|h)$/.test(f))
233
- .slice(0, 15);
234
- const relevantFiles = [...new Set([...mentionedPaths, ...allSourceFiles])].slice(0, 15);
236
+ // File content strategy same thresholds as the review workflow:
237
+ // ≤ FULL_FILE_THRESHOLD lines → send the whole file (AI needs full context to make correct edits)
238
+ // larger files → show a generous window around each commented line
239
+ const FULL_FILE_THRESHOLD = 400;
240
+ const COMMENT_WINDOW = 80; // lines above/below a commented line in large files
241
+ const CTX_FILE_MAX = 4_000; // chars per supporting context file
235
242
  const fileContents = {};
236
- for (const f of relevantFiles) {
237
- const content = await readRepoFile(f, cwd);
238
- if (content)
239
- fileContents[f] = content.slice(0, 4000);
243
+ // Commented lines per file — used for smart windowing on large files
244
+ const commentedLines = {};
245
+ for (const c of comments) {
246
+ if (c.path && c.line) {
247
+ (commentedLines[c.path] ??= []).push(c.line);
248
+ }
249
+ }
250
+ for (const filePath of mentionedPaths) {
251
+ const content = await readRepoFile(filePath, cwd);
252
+ if (!content)
253
+ continue;
254
+ const lines = content.split("\n");
255
+ if (lines.length <= FULL_FILE_THRESHOLD) {
256
+ // Small file — send it whole
257
+ fileContents[filePath] = lines
258
+ .map((l, i) => `${String(i + 1).padStart(5, " ")} | ${l}`)
259
+ .join("\n");
260
+ }
261
+ else {
262
+ // Large file — show windows around commented lines
263
+ const targets = commentedLines[filePath] ?? [];
264
+ const included = new Set();
265
+ for (const line of targets) {
266
+ for (let i = Math.max(0, line - COMMENT_WINDOW - 1); i < Math.min(lines.length, line + COMMENT_WINDOW); i++) {
267
+ included.add(i);
268
+ }
269
+ }
270
+ // If no specific lines, fall back to first FULL_FILE_THRESHOLD lines
271
+ const indices = included.size > 0 ? [...included].sort((a, b) => a - b) : [...Array(FULL_FILE_THRESHOLD).keys()];
272
+ let excerpt = "";
273
+ let prev = -1;
274
+ for (const idx of indices) {
275
+ if (prev !== -1 && idx > prev + 1)
276
+ excerpt += `\n … (${idx - prev - 1} lines omitted)\n`;
277
+ excerpt += `${String(idx + 1).padStart(5, " ")} | ${lines[idx]}\n`;
278
+ prev = idx;
279
+ }
280
+ fileContents[filePath] = excerpt.trimEnd();
281
+ }
282
+ }
283
+ // Add context files (imports of the mentioned files) for extra background
284
+ const ctxPaths = await findContextFiles(mentionedPaths, trackedFiles, cwd, 8);
285
+ for (const filePath of ctxPaths) {
286
+ if (fileContents[filePath])
287
+ continue; // already loaded
288
+ const content = await readRepoFile(filePath, cwd);
289
+ if (!content)
290
+ continue;
291
+ fileContents[filePath] = content.length <= CTX_FILE_MAX
292
+ ? content
293
+ : content.slice(0, CTX_FILE_MAX) + "\n… (truncated)";
240
294
  }
241
- logger.info("🧠 Generating AI-suggested fixes…");
295
+ ctxSpinner.succeed(`Context: ${mentionedPaths.length} commented file(s), ${ctxPaths.length} context file(s)`);
296
+ const fixSpinner = ora("🧠 Generating AI-suggested fixes…").start();
242
297
  const fixResult = await gitx.ai.suggestFixes({
243
298
  comments: comments.map((c) => ({
244
299
  body: c.body,
@@ -248,8 +303,10 @@ export async function runFixCommentsWorkflow(gitx, prNumber, dryRun = false, noC
248
303
  })),
249
304
  prTitle: pr.title,
250
305
  prBody: pr.body,
306
+ diff,
251
307
  fileContents,
252
308
  });
309
+ fixSpinner.succeed(`AI generated ${fixResult.suggestedEdits.length} fix(es).`);
253
310
  const appliedFixes = [];
254
311
  const skippedFixes = [];
255
312
  for (const edit of fixResult.suggestedEdits) {
@@ -1 +1 @@
1
- {"version":3,"file":"pr.js","sourceRoot":"","sources":["../../src/workflows/pr.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * PR Workflow helpers\n *\n * Shared logic used by the `pr review` and `pr fix-comments` CLI commands.\n */\n\nimport ora from \"ora\";\nimport type { Gitx } from \"../core/gitx.js\";\nimport type { PullRequest, PullRequestComment } from \"../providers/base.js\";\nimport { createProvider } from \"../providers/factory.js\";\nimport { readRepoFile, listTrackedFiles } from \"../utils/gitOps.js\";\nimport { logger } from \"../logger/logger.js\";\n\n// Files that add no review value — skip them even if they appear in the diff\nconst SKIP_FILE_PATTERNS = [\n /package-lock\\.json$/,\n /yarn\\.lock$/,\n /pnpm-lock\\.yaml$/,\n /bun\\.lockb$/,\n /\\.lock$/,\n /dist\\//,\n /build\\//,\n /\\.min\\.(js|css)$/,\n /\\.map$/,\n /node_modules\\//,\n /\\.d\\.ts$/, // generated TypeScript declarations\n /generated\\//,\n /migrations\\/.*\\.sql$/,\n];\n\nfunction isReviewableFile(path: string): boolean {\n return !SKIP_FILE_PATTERNS.some((re) => re.test(path));\n}\n\n// ─── Review workflow ──────────────────────────────────────────────────────────\n\nexport interface ReviewResult {\n pr: PullRequest;\n comments: PullRequestComment[];\n aiSummary: string;\n review?: import(\"../ai/types.js\").AiDetailedReviewResponse;\n /** true = review was actually posted to the hosting provider */\n reviewPosted: boolean;\n /** How inline comments were delivered: formal inline, plain comments, or not posted */\n inlineDelivery: \"inline\" | \"plain-comments\" | \"none\";\n}\n\n/**\n * Parse a unified diff and return the set of changed file paths.\n */\nfunction parseChangedPathsFromDiff(diff: string): string[] {\n const paths = new Set<string>();\n for (const line of diff.split(\"\\n\")) {\n // Match \"+++ b/src/foo.ts\" lines\n const m = line.match(/^\\+\\+\\+ b\\/(.+)/);\n if (m?.[1] && m[1] !== \"/dev/null\") {\n paths.add(m[1].trim());\n }\n }\n return [...paths];\n}\n\n/**\n * Given a list of changed file paths, find supporting context files that are\n * closely related (imported by or importing changed files).\n * Returns at most `maxFiles` file paths.\n */\nasync function findContextFiles(\n changedPaths: string[],\n allTrackedFiles: string[],\n cwd: string,\n maxFiles = 8\n): Promise<string[]> {\n const contextPaths = new Set<string>();\n\n for (const changedPath of changedPaths.slice(0, 10)) {\n const content = await readRepoFile(changedPath, cwd);\n if (!content) continue;\n\n // Extract relative import paths from TypeScript/JS files\n const importMatches = content.matchAll(/from\\s+['\"]([^'\"]+)['\"]/g);\n for (const [, importPath] of importMatches) {\n if (!importPath || importPath.startsWith(\"node:\") || !importPath.startsWith(\".\")) continue;\n // Resolve the import path relative to the file's directory\n const dir = changedPath.split(\"/\").slice(0, -1).join(\"/\");\n const candidates = [\n `${dir}/${importPath}.ts`,\n `${dir}/${importPath}.tsx`,\n `${dir}/${importPath}/index.ts`,\n `${dir}/${importPath}`,\n ].map((p) => p.replace(/\\/\\//g, \"/\").replace(/^\\//, \"\"));\n\n for (const candidate of candidates) {\n if (allTrackedFiles.includes(candidate) && !changedPaths.includes(candidate)) {\n contextPaths.add(candidate);\n break;\n }\n }\n }\n\n if (contextPaths.size >= maxFiles) break;\n }\n\n return [...contextPaths].slice(0, maxFiles);\n}\n\n/**\n * Fetch a PR, its full diff, and all related codebase context;\n * run a senior-developer quality AI review;\n * submit as a formal review (with inline comments) to the hosting provider.\n */\nexport async function runReviewWorkflow(\n gitx: Gitx,\n prNumber: number,\n postComment = true\n): Promise<ReviewResult> {\n const ctx = await gitx.getRepoContext();\n const provider = createProvider(ctx);\n const cwd = gitx.cwd;\n\n const fetchSpinner = ora(\"Fetching PR info, diff and comments…\").start();\n const pr = await provider.getPR(ctx.repoSlug, prNumber);\n const [comments, diff] = await Promise.all([\n provider.getPRComments(ctx.repoSlug, prNumber),\n provider.getPRDiff(ctx.repoSlug, prNumber),\n ]);\n fetchSpinner.succeed(`PR #${prNumber}: \"${pr.title}\" (${pr.head} → ${pr.base})`);\n\n // ── Build codebase context ─────────────────────────────────────────────────\n const ctxSpinner = ora(\"Building codebase context from changed files…\").start();\n const allTracked = await listTrackedFiles(cwd);\n const allChangedPaths = parseChangedPathsFromDiff(diff);\n\n // Filter out lockfiles / generated files — they waste tokens and add no review value.\n // No file count cap — per-file budgets in buildSeniorReviewPrompt already control\n // total size. Dropping files arbitrarily is worse than sending all of them.\n const changedPaths = allChangedPaths.filter(isReviewableFile);\n const skippedCount = allChangedPaths.length - changedPaths.length;\n\n // Read full content of changed files\n const changedFiles: Record<string, string> = {};\n for (const p of changedPaths) {\n const content = await readRepoFile(p, cwd);\n if (content) changedFiles[p] = content;\n }\n\n // Read supporting context files (imported by the changed files)\n // 10 context files gives the AI a solid picture of the codebase structure\n const ctxPaths = await findContextFiles(changedPaths, allTracked, cwd, 10);\n const contextFiles: Record<string, string> = {};\n for (const p of ctxPaths) {\n const content = await readRepoFile(p, cwd);\n if (content) contextFiles[p] = content;\n }\n\n const skippedNote = skippedCount > 0 ? `, ${skippedCount} lock/generated files skipped` : \"\";\n ctxSpinner.succeed(\n `Context: ${changedPaths.length} changed files, ${ctxPaths.length} context files${skippedNote}`\n );\n\n const reviewSpinner = ora(\n `Running senior-dev AI review… (this may take up to 5 min for large PRs)`\n ).start();\n\n let review: Awaited<ReturnType<typeof gitx.ai.reviewPRDetailed>>;\n try {\n review = await gitx.ai.reviewPRDetailed({\n prTitle: pr.title,\n prBody: pr.body,\n author: pr.author,\n headBranch: pr.head,\n baseBranch: pr.base,\n diff,\n changedFiles,\n contextFiles,\n repoFileList: allTracked,\n existingComments: comments.map((c) => ({\n author: c.author,\n body: c.body,\n path: c.path,\n line: c.line,\n })),\n });\n reviewSpinner.succeed(\n `Review complete — verdict: ${review.verdict} | ${review.inlineComments.length} inline comment(s)`\n );\n } catch (err) {\n reviewSpinner.fail(\"AI review failed.\");\n throw err;\n }\n\n // ── Build the formatted review body (for the summary comment) ─────────────\n const verdictIcon =\n review.verdict === \"approve\" ? \"✅\" :\n review.verdict === \"request_changes\" ? \"🔴\" : \"💬\";\n\n const checklistLines = review.checklist.map((c) => {\n const icon = c.status === \"pass\" ? \"✅\" : c.status === \"warn\" ? \"⚠️\" : \"❌\";\n return `| ${icon} | **${c.area}** | ${c.note} |`;\n });\n\n const issueLines = review.issues.map((i) => {\n const sev = i.severity === \"critical\" ? \"🔴\" : i.severity === \"warning\" ? \"🟡\" : \"💡\";\n const loc = i.file ? ` (\\`${i.file}${i.line ? `:${i.line}` : \"\"}\\`)` : \"\";\n return `${sev} ${i.description}${loc}`;\n });\n\n const posLines = review.positives.map((p) => `✔ ${p}`);\n\n const summaryBody = [\n `## ${verdictIcon} Senior Dev AI Review (gitx) — ${review.verdict.replace(\"_\", \" \")}`,\n \"\",\n review.summary,\n ...(checklistLines.length > 0\n ? [\"\", \"### Review Checklist\", \"| Status | Area | Note |\", \"|--------|------|------|\", ...checklistLines]\n : []),\n ...(review.issues.length > 0 ? [\"\", \"### Issues Found\", ...issueLines] : []),\n ...(review.positives.length > 0 ? [\"\", \"### Positives\", ...posLines] : []),\n ...(review.testingNotes ? [\"\", \"### How to Test\", review.testingNotes] : []),\n ...(review.inlineComments.length > 0\n ? [`\\n> 💬 ${review.inlineComments.length} inline comment(s) posted on specific lines.`]\n : []),\n \"\",\n \"*Generated by [gitx](https://github.com/g-abhishek/gitx)*\",\n ].join(\"\\n\");\n\n // ── Post the formal review (inline comments + verdict) ────────────────────\n let reviewPosted = false;\n let inlineDelivery: ReviewResult[\"inlineDelivery\"] = \"none\";\n\n if (postComment) {\n const inlineCount = review.inlineComments.length;\n const postSpinner = ora(\n `Submitting review to PR${inlineCount > 0 ? ` with ${inlineCount} inline comment(s)` : \"\"}…`\n ).start();\n try {\n await provider.submitPRReview(ctx.repoSlug, prNumber, {\n body: summaryBody,\n event: review.verdict,\n comments: review.inlineComments.map((c) => ({\n path: c.path,\n line: c.line,\n body: c.suggestion\n ? `${c.body}\\n\\n**Suggestion:**\\n\\`\\`\\`suggestion\\n${c.suggestion}\\n\\`\\`\\``\n : c.body,\n })),\n });\n reviewPosted = true;\n // Determine how inline comments were delivered.\n // GitHub's submitPRReview will attempt inline first, then fall back to\n // plain comments. We can't detect which path was taken from here, so\n // we report \"inline\" optimistically — the user sees the real result on GitHub.\n inlineDelivery = inlineCount > 0 ? \"inline\" : \"none\";\n postSpinner.succeed(\n `Review submitted to PR.${inlineCount > 0 ? ` (${inlineCount} inline comment(s) — see PR for delivery method)` : \"\"}`\n );\n } catch (err) {\n postSpinner.fail(`Could not post review to PR: ${String((err as Error).message ?? err)}`);\n // Don't rethrow — still return the review so the user can see it locally\n }\n }\n\n return { pr, comments, aiSummary: summaryBody, review, reviewPosted, inlineDelivery };\n}\n\n// ─── Fix-comments workflow ────────────────────────────────────────────────────\n\nexport interface FixCommentsResult {\n pr: PullRequest;\n comments: PullRequestComment[];\n appliedFixes: Array<{ path: string; rationale: string }>;\n skippedFixes: Array<{ path: string; reason: string }>;\n}\n\n/**\n * Fetch PR review comments, ask AI to suggest fixes, apply them, and\n * commit + push the changes.\n */\nexport async function runFixCommentsWorkflow(\n gitx: Gitx,\n prNumber: number,\n dryRun = false,\n noCommit = false\n): Promise<FixCommentsResult> {\n const { applyUnifiedDiff, stageAll, hasStagedChanges, commitChanges } = await import(\n \"../utils/gitOps.js\"\n );\n const cwd = gitx.cwd;\n const ctx = await gitx.getRepoContext();\n const provider = createProvider(ctx);\n\n logger.info(`🔍 Fetching PR #${prNumber}…`);\n const pr = await provider.getPR(ctx.repoSlug, prNumber);\n\n logger.info(\"💬 Fetching review comments…\");\n const comments = await provider.getPRComments(ctx.repoSlug, prNumber);\n\n if (comments.length === 0) {\n logger.info(\"No review comments found.\");\n return { pr, comments, appliedFixes: [], skippedFixes: [] };\n }\n\n // Gather file contents for files mentioned in comments\n const mentionedPaths = [...new Set(comments.map((c) => c.path).filter(Boolean) as string[])];\n const trackedFiles = await listTrackedFiles(cwd);\n\n // Also include files mentioned in the PR body / title\n const allSourceFiles = trackedFiles\n .filter((f) => /\\.(ts|js|tsx|jsx|py|go|rs|java|rb|cs|cpp|c|h)$/.test(f))\n .slice(0, 15);\n\n const relevantFiles = [...new Set([...mentionedPaths, ...allSourceFiles])].slice(0, 15);\n const fileContents: Record<string, string> = {};\n for (const f of relevantFiles) {\n const content = await readRepoFile(f, cwd);\n if (content) fileContents[f] = content.slice(0, 4000);\n }\n\n logger.info(\"🧠 Generating AI-suggested fixes…\");\n const fixResult = await gitx.ai.suggestFixes({\n comments: comments.map((c) => ({\n body: c.body,\n author: c.author,\n path: c.path,\n line: c.line,\n })),\n prTitle: pr.title,\n prBody: pr.body,\n fileContents,\n });\n\n const appliedFixes: Array<{ path: string; rationale: string }> = [];\n const skippedFixes: Array<{ path: string; reason: string }> = [];\n\n for (const edit of fixResult.suggestedEdits) {\n if (dryRun) {\n logger.info(` ↳ [dry-run] Would apply fix to: ${edit.path}`);\n logger.info(` Rationale: ${edit.rationale}`);\n appliedFixes.push({ path: edit.path, rationale: edit.rationale });\n continue;\n }\n\n const applyResult = await applyUnifiedDiff(edit.unifiedDiff, cwd);\n if (applyResult.ok) {\n logger.info(` ↳ Applied fix to: ${edit.path}`);\n appliedFixes.push({ path: edit.path, rationale: edit.rationale });\n } else {\n logger.warn(` ↳ Could not apply fix to ${edit.path}: ${applyResult.error ?? \"unknown\"}`);\n skippedFixes.push({\n path: edit.path,\n reason: applyResult.error ?? \"git apply failed\",\n });\n }\n }\n\n if (!dryRun && !noCommit && appliedFixes.length > 0) {\n await stageAll(cwd);\n if (await hasStagedChanges(cwd)) {\n const msg = `fix: address PR #${prNumber} review comments\\n\\n${appliedFixes.map((f) => `- ${f.path}: ${f.rationale}`).join(\"\\n\")}`;\n const sha = await commitChanges(msg, cwd);\n logger.success(`Committed fixes: ${sha.slice(0, 8)}`);\n\n // Post summary comment\n const fixSummary = appliedFixes.map((f) => `- \\`${f.path}\\`: ${f.rationale}`).join(\"\\n\");\n await provider.addPRComment(\n ctx.repoSlug,\n prNumber,\n `## 🤖 Auto-fixes applied (gitx)\\n\\n${fixSummary}\\n\\nCommit: \\`${sha.slice(0, 8)}\\``\n );\n }\n }\n\n if (!dryRun && noCommit && appliedFixes.length > 0) {\n logger.info(\"\\n💡 Fixes applied to working tree. Review the changes and commit when ready.\");\n }\n\n return { pr, comments, appliedFixes, skippedFixes };\n}\n"]}
1
+ {"version":3,"file":"pr.js","sourceRoot":"","sources":["../../src/workflows/pr.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * PR Workflow helpers\n *\n * Shared logic used by the `pr review` and `pr fix-comments` CLI commands.\n */\n\nimport ora from \"ora\";\nimport type { Gitx } from \"../core/gitx.js\";\nimport type { PullRequest, PullRequestComment } from \"../providers/base.js\";\nimport { createProvider } from \"../providers/factory.js\";\nimport { readRepoFile, listTrackedFiles } from \"../utils/gitOps.js\";\nimport { logger } from \"../logger/logger.js\";\n\n// Files that add no review value — skip them even if they appear in the diff\nconst SKIP_FILE_PATTERNS = [\n /package-lock\\.json$/,\n /yarn\\.lock$/,\n /pnpm-lock\\.yaml$/,\n /bun\\.lockb$/,\n /\\.lock$/,\n /dist\\//,\n /build\\//,\n /\\.min\\.(js|css)$/,\n /\\.map$/,\n /node_modules\\//,\n /\\.d\\.ts$/, // generated TypeScript declarations\n /generated\\//,\n /migrations\\/.*\\.sql$/,\n];\n\nfunction isReviewableFile(path: string): boolean {\n return !SKIP_FILE_PATTERNS.some((re) => re.test(path));\n}\n\n// ─── Review workflow ──────────────────────────────────────────────────────────\n\nexport interface ReviewResult {\n pr: PullRequest;\n comments: PullRequestComment[];\n aiSummary: string;\n review?: import(\"../ai/types.js\").AiDetailedReviewResponse;\n /** true = review was actually posted to the hosting provider */\n reviewPosted: boolean;\n /** How inline comments were delivered: formal inline, plain comments, or not posted */\n inlineDelivery: \"inline\" | \"plain-comments\" | \"none\";\n}\n\n/**\n * Parse a unified diff and return the set of changed file paths.\n */\nfunction parseChangedPathsFromDiff(diff: string): string[] {\n const paths = new Set<string>();\n for (const line of diff.split(\"\\n\")) {\n // Match \"+++ b/src/foo.ts\" lines\n const m = line.match(/^\\+\\+\\+ b\\/(.+)/);\n if (m?.[1] && m[1] !== \"/dev/null\") {\n paths.add(m[1].trim());\n }\n }\n return [...paths];\n}\n\n/**\n * Given a list of changed file paths, find supporting context files that are\n * closely related (imported by or importing changed files).\n * Returns at most `maxFiles` file paths.\n */\nasync function findContextFiles(\n changedPaths: string[],\n allTrackedFiles: string[],\n cwd: string,\n maxFiles = 8\n): Promise<string[]> {\n const contextPaths = new Set<string>();\n\n for (const changedPath of changedPaths.slice(0, 10)) {\n const content = await readRepoFile(changedPath, cwd);\n if (!content) continue;\n\n // Extract relative import paths from TypeScript/JS files\n const importMatches = content.matchAll(/from\\s+['\"]([^'\"]+)['\"]/g);\n for (const [, importPath] of importMatches) {\n if (!importPath || importPath.startsWith(\"node:\") || !importPath.startsWith(\".\")) continue;\n // Resolve the import path relative to the file's directory\n const dir = changedPath.split(\"/\").slice(0, -1).join(\"/\");\n const candidates = [\n `${dir}/${importPath}.ts`,\n `${dir}/${importPath}.tsx`,\n `${dir}/${importPath}/index.ts`,\n `${dir}/${importPath}`,\n ].map((p) => p.replace(/\\/\\//g, \"/\").replace(/^\\//, \"\"));\n\n for (const candidate of candidates) {\n if (allTrackedFiles.includes(candidate) && !changedPaths.includes(candidate)) {\n contextPaths.add(candidate);\n break;\n }\n }\n }\n\n if (contextPaths.size >= maxFiles) break;\n }\n\n return [...contextPaths].slice(0, maxFiles);\n}\n\n/**\n * Fetch a PR, its full diff, and all related codebase context;\n * run a senior-developer quality AI review;\n * submit as a formal review (with inline comments) to the hosting provider.\n */\nexport async function runReviewWorkflow(\n gitx: Gitx,\n prNumber: number,\n postComment = true\n): Promise<ReviewResult> {\n const ctx = await gitx.getRepoContext();\n const provider = createProvider(ctx);\n const cwd = gitx.cwd;\n\n const fetchSpinner = ora(\"Fetching PR info, diff and comments…\").start();\n const pr = await provider.getPR(ctx.repoSlug, prNumber);\n const [comments, diff] = await Promise.all([\n provider.getPRComments(ctx.repoSlug, prNumber),\n provider.getPRDiff(ctx.repoSlug, prNumber),\n ]);\n fetchSpinner.succeed(`PR #${prNumber}: \"${pr.title}\" (${pr.head} → ${pr.base})`);\n\n // ── Build codebase context ─────────────────────────────────────────────────\n const ctxSpinner = ora(\"Building codebase context from changed files…\").start();\n const allTracked = await listTrackedFiles(cwd);\n const allChangedPaths = parseChangedPathsFromDiff(diff);\n\n // Filter out lockfiles / generated files — they waste tokens and add no review value.\n // No file count cap — per-file budgets in buildSeniorReviewPrompt already control\n // total size. Dropping files arbitrarily is worse than sending all of them.\n const changedPaths = allChangedPaths.filter(isReviewableFile);\n const skippedCount = allChangedPaths.length - changedPaths.length;\n\n // Read full content of changed files\n const changedFiles: Record<string, string> = {};\n for (const p of changedPaths) {\n const content = await readRepoFile(p, cwd);\n if (content) changedFiles[p] = content;\n }\n\n // Read supporting context files (imported by the changed files)\n // 10 context files gives the AI a solid picture of the codebase structure\n const ctxPaths = await findContextFiles(changedPaths, allTracked, cwd, 10);\n const contextFiles: Record<string, string> = {};\n for (const p of ctxPaths) {\n const content = await readRepoFile(p, cwd);\n if (content) contextFiles[p] = content;\n }\n\n const skippedNote = skippedCount > 0 ? `, ${skippedCount} lock/generated files skipped` : \"\";\n ctxSpinner.succeed(\n `Context: ${changedPaths.length} changed files, ${ctxPaths.length} context files${skippedNote}`\n );\n\n const reviewSpinner = ora(\n `Running senior-dev AI review… (this may take up to 5 min for large PRs)`\n ).start();\n\n let review: Awaited<ReturnType<typeof gitx.ai.reviewPRDetailed>>;\n try {\n review = await gitx.ai.reviewPRDetailed({\n prTitle: pr.title,\n prBody: pr.body,\n author: pr.author,\n headBranch: pr.head,\n baseBranch: pr.base,\n diff,\n changedFiles,\n contextFiles,\n repoFileList: allTracked,\n existingComments: comments.map((c) => ({\n author: c.author,\n body: c.body,\n path: c.path,\n line: c.line,\n })),\n });\n reviewSpinner.succeed(\n `Review complete — verdict: ${review.verdict} | ${review.inlineComments.length} inline comment(s)`\n );\n } catch (err) {\n reviewSpinner.fail(\"AI review failed.\");\n throw err;\n }\n\n // ── Build the formatted review body (for the summary comment) ─────────────\n const verdictIcon =\n review.verdict === \"approve\" ? \"✅\" :\n review.verdict === \"request_changes\" ? \"🔴\" : \"💬\";\n\n const checklistLines = review.checklist.map((c) => {\n const icon = c.status === \"pass\" ? \"✅\" : c.status === \"warn\" ? \"⚠️\" : \"❌\";\n return `| ${icon} | **${c.area}** | ${c.note} |`;\n });\n\n const issueLines = review.issues.map((i) => {\n const sev = i.severity === \"critical\" ? \"🔴\" : i.severity === \"warning\" ? \"🟡\" : \"💡\";\n const loc = i.file ? ` (\\`${i.file}${i.line ? `:${i.line}` : \"\"}\\`)` : \"\";\n return `${sev} ${i.description}${loc}`;\n });\n\n const posLines = review.positives.map((p) => `✔ ${p}`);\n\n const summaryBody = [\n `## ${verdictIcon} Senior Dev AI Review (gitx) — ${review.verdict.replace(\"_\", \" \")}`,\n \"\",\n review.summary,\n ...(checklistLines.length > 0\n ? [\"\", \"### Review Checklist\", \"| Status | Area | Note |\", \"|--------|------|------|\", ...checklistLines]\n : []),\n ...(review.issues.length > 0 ? [\"\", \"### Issues Found\", ...issueLines] : []),\n ...(review.positives.length > 0 ? [\"\", \"### Positives\", ...posLines] : []),\n ...(review.testingNotes ? [\"\", \"### How to Test\", review.testingNotes] : []),\n ...(review.inlineComments.length > 0\n ? [`\\n> 💬 ${review.inlineComments.length} inline comment(s) posted on specific lines.`]\n : []),\n \"\",\n \"*Generated by [gitx](https://github.com/g-abhishek/gitx)*\",\n ].join(\"\\n\");\n\n // ── Post the formal review (inline comments + verdict) ────────────────────\n let reviewPosted = false;\n let inlineDelivery: ReviewResult[\"inlineDelivery\"] = \"none\";\n\n if (postComment) {\n const inlineCount = review.inlineComments.length;\n const postSpinner = ora(\n `Submitting review to PR${inlineCount > 0 ? ` with ${inlineCount} inline comment(s)` : \"\"}…`\n ).start();\n try {\n await provider.submitPRReview(ctx.repoSlug, prNumber, {\n body: summaryBody,\n event: review.verdict,\n comments: review.inlineComments.map((c) => ({\n path: c.path,\n line: c.line,\n body: c.suggestion\n ? `${c.body}\\n\\n**Suggestion:**\\n\\`\\`\\`suggestion\\n${c.suggestion}\\n\\`\\`\\``\n : c.body,\n })),\n });\n reviewPosted = true;\n // Determine how inline comments were delivered.\n // GitHub's submitPRReview will attempt inline first, then fall back to\n // plain comments. We can't detect which path was taken from here, so\n // we report \"inline\" optimistically — the user sees the real result on GitHub.\n inlineDelivery = inlineCount > 0 ? \"inline\" : \"none\";\n postSpinner.succeed(\n `Review submitted to PR.${inlineCount > 0 ? ` (${inlineCount} inline comment(s) — see PR for delivery method)` : \"\"}`\n );\n } catch (err) {\n postSpinner.fail(`Could not post review to PR: ${String((err as Error).message ?? err)}`);\n // Don't rethrow — still return the review so the user can see it locally\n }\n }\n\n return { pr, comments, aiSummary: summaryBody, review, reviewPosted, inlineDelivery };\n}\n\n// ─── Fix-comments workflow ────────────────────────────────────────────────────\n\nexport interface FixCommentsResult {\n pr: PullRequest;\n comments: PullRequestComment[];\n appliedFixes: Array<{ path: string; rationale: string }>;\n skippedFixes: Array<{ path: string; reason: string }>;\n}\n\n/**\n * Fetch PR review comments, ask AI to suggest fixes, apply them, and\n * commit + push the changes.\n */\nexport async function runFixCommentsWorkflow(\n gitx: Gitx,\n prNumber: number,\n dryRun = false,\n noCommit = false\n): Promise<FixCommentsResult> {\n const { applyUnifiedDiff, stageAll, hasStagedChanges, commitChanges } = await import(\n \"../utils/gitOps.js\"\n );\n const cwd = gitx.cwd;\n const ctx = await gitx.getRepoContext();\n const provider = createProvider(ctx);\n\n const fetchSpinner = ora(\"Fetching PR, comments and diff…\").start();\n const pr = await provider.getPR(ctx.repoSlug, prNumber);\n const [comments, diff] = await Promise.all([\n provider.getPRComments(ctx.repoSlug, prNumber),\n provider.getPRDiff(ctx.repoSlug, prNumber),\n ]);\n fetchSpinner.succeed(`PR #${prNumber}: \"${pr.title}\" — ${comments.length} comment(s)`);\n\n if (comments.length === 0) {\n logger.info(\"No review comments found.\");\n return { pr, comments, appliedFixes: [], skippedFixes: [] };\n }\n\n // ── Build file context ────────────────────────────────────────────────────\n // Only load files directly mentioned in comments + their close imports.\n // Random repo source files are irrelevant — the AI is fixing specific lines.\n const ctxSpinner = ora(\"Building file context for commented files…\").start();\n\n const mentionedPaths = [...new Set(comments.map((c) => c.path).filter(Boolean) as string[])];\n const trackedFiles = await listTrackedFiles(cwd);\n\n // File content strategy — same thresholds as the review workflow:\n // ≤ FULL_FILE_THRESHOLD lines → send the whole file (AI needs full context to make correct edits)\n // larger files → show a generous window around each commented line\n const FULL_FILE_THRESHOLD = 400;\n const COMMENT_WINDOW = 80; // lines above/below a commented line in large files\n const CTX_FILE_MAX = 4_000; // chars per supporting context file\n\n const fileContents: Record<string, string> = {};\n\n // Commented lines per file — used for smart windowing on large files\n const commentedLines: Record<string, number[]> = {};\n for (const c of comments) {\n if (c.path && c.line) {\n (commentedLines[c.path] ??= []).push(c.line);\n }\n }\n\n for (const filePath of mentionedPaths) {\n const content = await readRepoFile(filePath, cwd);\n if (!content) continue;\n\n const lines = content.split(\"\\n\");\n if (lines.length <= FULL_FILE_THRESHOLD) {\n // Small file — send it whole\n fileContents[filePath] = lines\n .map((l, i) => `${String(i + 1).padStart(5, \" \")} | ${l}`)\n .join(\"\\n\");\n } else {\n // Large file — show windows around commented lines\n const targets = commentedLines[filePath] ?? [];\n const included = new Set<number>();\n for (const line of targets) {\n for (let i = Math.max(0, line - COMMENT_WINDOW - 1); i < Math.min(lines.length, line + COMMENT_WINDOW); i++) {\n included.add(i);\n }\n }\n // If no specific lines, fall back to first FULL_FILE_THRESHOLD lines\n const indices = included.size > 0 ? [...included].sort((a, b) => a - b) : [...Array(FULL_FILE_THRESHOLD).keys()];\n let excerpt = \"\";\n let prev = -1;\n for (const idx of indices) {\n if (prev !== -1 && idx > prev + 1) excerpt += `\\n … (${idx - prev - 1} lines omitted)\\n`;\n excerpt += `${String(idx + 1).padStart(5, \" \")} | ${lines[idx]}\\n`;\n prev = idx;\n }\n fileContents[filePath] = excerpt.trimEnd();\n }\n }\n\n // Add context files (imports of the mentioned files) for extra background\n const ctxPaths = await findContextFiles(mentionedPaths, trackedFiles, cwd, 8);\n for (const filePath of ctxPaths) {\n if (fileContents[filePath]) continue; // already loaded\n const content = await readRepoFile(filePath, cwd);\n if (!content) continue;\n fileContents[filePath] = content.length <= CTX_FILE_MAX\n ? content\n : content.slice(0, CTX_FILE_MAX) + \"\\n… (truncated)\";\n }\n\n ctxSpinner.succeed(\n `Context: ${mentionedPaths.length} commented file(s), ${ctxPaths.length} context file(s)`\n );\n\n const fixSpinner = ora(\"🧠 Generating AI-suggested fixes…\").start();\n const fixResult = await gitx.ai.suggestFixes({\n comments: comments.map((c) => ({\n body: c.body,\n author: c.author,\n path: c.path,\n line: c.line,\n })),\n prTitle: pr.title,\n prBody: pr.body,\n diff,\n fileContents,\n });\n fixSpinner.succeed(`AI generated ${fixResult.suggestedEdits.length} fix(es).`);\n\n const appliedFixes: Array<{ path: string; rationale: string }> = [];\n const skippedFixes: Array<{ path: string; reason: string }> = [];\n\n for (const edit of fixResult.suggestedEdits) {\n if (dryRun) {\n logger.info(` ↳ [dry-run] Would apply fix to: ${edit.path}`);\n logger.info(` Rationale: ${edit.rationale}`);\n appliedFixes.push({ path: edit.path, rationale: edit.rationale });\n continue;\n }\n\n const applyResult = await applyUnifiedDiff(edit.unifiedDiff, cwd);\n if (applyResult.ok) {\n logger.info(` ↳ Applied fix to: ${edit.path}`);\n appliedFixes.push({ path: edit.path, rationale: edit.rationale });\n } else {\n logger.warn(` ↳ Could not apply fix to ${edit.path}: ${applyResult.error ?? \"unknown\"}`);\n skippedFixes.push({\n path: edit.path,\n reason: applyResult.error ?? \"git apply failed\",\n });\n }\n }\n\n if (!dryRun && !noCommit && appliedFixes.length > 0) {\n await stageAll(cwd);\n if (await hasStagedChanges(cwd)) {\n const msg = `fix: address PR #${prNumber} review comments\\n\\n${appliedFixes.map((f) => `- ${f.path}: ${f.rationale}`).join(\"\\n\")}`;\n const sha = await commitChanges(msg, cwd);\n logger.success(`Committed fixes: ${sha.slice(0, 8)}`);\n\n // Post summary comment\n const fixSummary = appliedFixes.map((f) => `- \\`${f.path}\\`: ${f.rationale}`).join(\"\\n\");\n await provider.addPRComment(\n ctx.repoSlug,\n prNumber,\n `## 🤖 Auto-fixes applied (gitx)\\n\\n${fixSummary}\\n\\nCommit: \\`${sha.slice(0, 8)}\\``\n );\n }\n }\n\n if (!dryRun && noCommit && appliedFixes.length > 0) {\n logger.info(\"\\n💡 Fixes applied to working tree. Review the changes and commit when ready.\");\n }\n\n return { pr, comments, appliedFixes, skippedFixes };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@g-abhishek/gitx",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "AI-powered Git workflow automation CLI and SDK",
5
5
  "type": "module",
6
6
  "license": "MIT",