gitreviewpilot 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +234 -0
  3. package/dist/commands/ask.d.ts +3 -0
  4. package/dist/commands/ask.d.ts.map +1 -0
  5. package/dist/commands/ask.js +32 -0
  6. package/dist/commands/ask.js.map +1 -0
  7. package/dist/commands/changes.d.ts +3 -0
  8. package/dist/commands/changes.d.ts.map +1 -0
  9. package/dist/commands/changes.js +57 -0
  10. package/dist/commands/changes.js.map +1 -0
  11. package/dist/commands/install.d.ts +3 -0
  12. package/dist/commands/install.d.ts.map +1 -0
  13. package/dist/commands/install.js +86 -0
  14. package/dist/commands/install.js.map +1 -0
  15. package/dist/commands/pr.d.ts +3 -0
  16. package/dist/commands/pr.d.ts.map +1 -0
  17. package/dist/commands/pr.js +53 -0
  18. package/dist/commands/pr.js.map +1 -0
  19. package/dist/commands/review.d.ts +3 -0
  20. package/dist/commands/review.d.ts.map +1 -0
  21. package/dist/commands/review.js +45 -0
  22. package/dist/commands/review.js.map +1 -0
  23. package/dist/commands/version.d.ts +3 -0
  24. package/dist/commands/version.d.ts.map +1 -0
  25. package/dist/commands/version.js +16 -0
  26. package/dist/commands/version.js.map +1 -0
  27. package/dist/config/env.d.ts +3 -0
  28. package/dist/config/env.d.ts.map +1 -0
  29. package/dist/config/env.js +20 -0
  30. package/dist/config/env.js.map +1 -0
  31. package/dist/config/gitreviewpilotConfig.d.ts +16 -0
  32. package/dist/config/gitreviewpilotConfig.d.ts.map +1 -0
  33. package/dist/config/gitreviewpilotConfig.js +78 -0
  34. package/dist/config/gitreviewpilotConfig.js.map +1 -0
  35. package/dist/index.d.ts +3 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +56 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/services/ai.service.d.ts +60 -0
  40. package/dist/services/ai.service.d.ts.map +1 -0
  41. package/dist/services/ai.service.js +396 -0
  42. package/dist/services/ai.service.js.map +1 -0
  43. package/dist/services/askService.d.ts +12 -0
  44. package/dist/services/askService.d.ts.map +1 -0
  45. package/dist/services/askService.js +68 -0
  46. package/dist/services/askService.js.map +1 -0
  47. package/dist/services/git.service.d.ts +12 -0
  48. package/dist/services/git.service.d.ts.map +1 -0
  49. package/dist/services/git.service.js +61 -0
  50. package/dist/services/git.service.js.map +1 -0
  51. package/dist/services/github.service.d.ts +46 -0
  52. package/dist/services/github.service.d.ts.map +1 -0
  53. package/dist/services/github.service.js +169 -0
  54. package/dist/services/github.service.js.map +1 -0
  55. package/dist/services/prReviewService.d.ts +29 -0
  56. package/dist/services/prReviewService.d.ts.map +1 -0
  57. package/dist/services/prReviewService.js +107 -0
  58. package/dist/services/prReviewService.js.map +1 -0
  59. package/dist/services/prService.d.ts +12 -0
  60. package/dist/services/prService.d.ts.map +1 -0
  61. package/dist/services/prService.js +8 -0
  62. package/dist/services/prService.js.map +1 -0
  63. package/dist/services/reviewErrors.d.ts +7 -0
  64. package/dist/services/reviewErrors.d.ts.map +1 -0
  65. package/dist/services/reviewErrors.js +13 -0
  66. package/dist/services/reviewErrors.js.map +1 -0
  67. package/dist/services/reviewService.d.ts +16 -0
  68. package/dist/services/reviewService.d.ts.map +1 -0
  69. package/dist/services/reviewService.js +109 -0
  70. package/dist/services/reviewService.js.map +1 -0
  71. package/dist/utils/cli.d.ts +16 -0
  72. package/dist/utils/cli.d.ts.map +1 -0
  73. package/dist/utils/cli.js +108 -0
  74. package/dist/utils/cli.js.map +1 -0
  75. package/dist/utils/diff.d.ts +21 -0
  76. package/dist/utils/diff.d.ts.map +1 -0
  77. package/dist/utils/diff.js +105 -0
  78. package/dist/utils/diff.js.map +1 -0
  79. package/dist/utils/formatter.d.ts +11 -0
  80. package/dist/utils/formatter.d.ts.map +1 -0
  81. package/dist/utils/formatter.js +186 -0
  82. package/dist/utils/formatter.js.map +1 -0
  83. package/dist/utils/logger.d.ts +7 -0
  84. package/dist/utils/logger.d.ts.map +1 -0
  85. package/dist/utils/logger.js +35 -0
  86. package/dist/utils/logger.js.map +1 -0
  87. package/dist/utils/repoContext.d.ts +26 -0
  88. package/dist/utils/repoContext.d.ts.map +1 -0
  89. package/dist/utils/repoContext.js +136 -0
  90. package/dist/utils/repoContext.js.map +1 -0
  91. package/dist/utils/spinner.d.ts +3 -0
  92. package/dist/utils/spinner.d.ts.map +1 -0
  93. package/dist/utils/spinner.js +5 -0
  94. package/dist/utils/spinner.js.map +1 -0
  95. package/dist/utils/structuredReview.d.ts +21 -0
  96. package/dist/utils/structuredReview.d.ts.map +1 -0
  97. package/dist/utils/structuredReview.js +59 -0
  98. package/dist/utils/structuredReview.js.map +1 -0
  99. package/gitreviewpilot.config.json +3 -0
  100. package/package.json +37 -0
@@ -0,0 +1,7 @@
1
+ export declare const logger: {
2
+ debug(message: string): void;
3
+ info(message: string): void;
4
+ warn(message: string): void;
5
+ error(message: string): void;
6
+ };
7
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,MAAM;mBACF,MAAM;kBAIP,MAAM;kBAIN,MAAM;mBAIL,MAAM;CAItB,CAAC"}
@@ -0,0 +1,35 @@
1
+ import chalk from "chalk";
2
+ function levelEnabled(level) {
3
+ const raw = (process.env.GITREVIEWPILOT_LOG_LEVEL ?? "info").toLowerCase();
4
+ const order = { debug: 10, info: 20, warn: 30, error: 40 };
5
+ const current = Object.keys(order).includes(raw)
6
+ ? raw
7
+ : "info";
8
+ return order[level] >= order[current];
9
+ }
10
+ function ts() {
11
+ return new Date().toISOString();
12
+ }
13
+ export const logger = {
14
+ debug(message) {
15
+ if (!levelEnabled("debug"))
16
+ return;
17
+ console.log(`${chalk.gray(ts())} ${chalk.gray("DEBUG")} ${message}`);
18
+ },
19
+ info(message) {
20
+ if (!levelEnabled("info"))
21
+ return;
22
+ console.log(`${chalk.gray(ts())} ${chalk.cyan("INFO")} ${message}`);
23
+ },
24
+ warn(message) {
25
+ if (!levelEnabled("warn"))
26
+ return;
27
+ console.warn(`${chalk.gray(ts())} ${chalk.yellow("WARN")} ${message}`);
28
+ },
29
+ error(message) {
30
+ if (!levelEnabled("error"))
31
+ return;
32
+ console.error(`${chalk.gray(ts())} ${chalk.red("ERROR")} ${message}`);
33
+ }
34
+ };
35
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,SAAS,YAAY,CAAC,KAAe;IACnC,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,IAAI,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;IAC3E,MAAM,KAAK,GAA6B,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;IACrF,MAAM,OAAO,GAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAgB,CAAC,QAAQ,CAAC,GAAe,CAAC;QAC1E,CAAC,CAAE,GAAgB;QACnB,CAAC,CAAC,MAAM,CAAC;IACX,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;AACxC,CAAC;AAED,SAAS,EAAE;IACT,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,KAAK,CAAC,OAAe;QACnB,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;YAAE,OAAO;QACnC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,CAAC,OAAe;QAClB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;YAAE,OAAO;QAClC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,CAAC,OAAe;QAClB,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;YAAE,OAAO;QAClC,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,KAAK,CAAC,OAAe;QACnB,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;YAAE,OAAO;QACnC,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC;IACxE,CAAC;CACF,CAAC"}
@@ -0,0 +1,26 @@
1
+ export type RepoContextOptions = {
2
+ /**
3
+ * Maximum number of files to include in the context.
4
+ */
5
+ maxFiles?: number;
6
+ /**
7
+ * Maximum characters per file (UTF-8 decoded). Files are truncated.
8
+ */
9
+ maxCharsPerFile?: number;
10
+ /**
11
+ * Maximum total characters across all included files.
12
+ */
13
+ maxTotalChars?: number;
14
+ /**
15
+ * Skip individual files larger than this many bytes.
16
+ */
17
+ maxFileBytes?: number;
18
+ };
19
+ export type RepoContextResult = {
20
+ context: string;
21
+ includedFiles: string[];
22
+ scannedFiles: number;
23
+ truncatedFiles: string[];
24
+ };
25
+ export declare function buildRepoContext(question: string, options?: RepoContextOptions): Promise<RepoContextResult>;
26
+ //# sourceMappingURL=repoContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repoContext.d.ts","sourceRoot":"","sources":["../../src/utils/repoContext.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,CAAC;AA4EF,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,iBAAiB,CAAC,CAiE5B"}
@@ -0,0 +1,136 @@
1
+ import { readdir, stat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ const INCLUDED_EXTS = new Set([".js", ".ts", ".jsx", ".tsx"]);
4
+ const EXCLUDED_DIRS = new Set(["node_modules", "dist", ".git"]);
5
+ function toRepoRelative(p) {
6
+ const rel = path.relative(process.cwd(), p);
7
+ return rel.split(path.sep).join("/");
8
+ }
9
+ function tokenizeQuestion(question) {
10
+ return question
11
+ .toLowerCase()
12
+ .split(/[^a-z0-9_]+/g)
13
+ .map((t) => t.trim())
14
+ .filter((t) => t.length >= 3 && t.length <= 40)
15
+ .slice(0, 20);
16
+ }
17
+ function scorePath(fileRel, tokens) {
18
+ if (tokens.length === 0)
19
+ return 0;
20
+ const s = fileRel.toLowerCase();
21
+ let score = 0;
22
+ for (const t of tokens) {
23
+ if (s.includes(t))
24
+ score += 2;
25
+ }
26
+ // Prefer "src" and shorter paths slightly.
27
+ if (s.includes("/src/"))
28
+ score += 1;
29
+ score += Math.max(0, 4 - Math.floor(s.length / 40));
30
+ return score;
31
+ }
32
+ async function readUtf8UpToChars(filePath, maxChars) {
33
+ // Avoid loading huge files fully into memory: read as buffer up to an upper bound,
34
+ // then decode and truncate. Since we cap bytes separately, this stays cheap.
35
+ const buf = await (await import("node:fs/promises")).readFile(filePath);
36
+ const text = buf.toString("utf8");
37
+ if (text.length <= maxChars)
38
+ return { text, truncated: false };
39
+ return { text: text.slice(0, maxChars), truncated: true };
40
+ }
41
+ async function walkFiles(rootDir) {
42
+ const out = [];
43
+ const stack = [rootDir];
44
+ while (stack.length) {
45
+ const dir = stack.pop();
46
+ let entries;
47
+ try {
48
+ // Keep this un-annotated so TS picks the string-encoding overload.
49
+ entries = await readdir(dir, { withFileTypes: true, encoding: "utf8" });
50
+ }
51
+ catch {
52
+ continue;
53
+ }
54
+ for (const ent of entries) {
55
+ const name = ent.name;
56
+ const full = path.join(dir, name);
57
+ if (ent.isDirectory()) {
58
+ if (EXCLUDED_DIRS.has(name))
59
+ continue;
60
+ stack.push(full);
61
+ continue;
62
+ }
63
+ if (!ent.isFile())
64
+ continue;
65
+ const ext = path.extname(name).toLowerCase();
66
+ if (!INCLUDED_EXTS.has(ext))
67
+ continue;
68
+ out.push(full);
69
+ }
70
+ }
71
+ return out;
72
+ }
73
+ export async function buildRepoContext(question, options = {}) {
74
+ const maxFiles = Number.isFinite(options.maxFiles) && options.maxFiles > 0 ? Math.floor(options.maxFiles) : 20;
75
+ const maxCharsPerFile = Number.isFinite(options.maxCharsPerFile) && options.maxCharsPerFile > 0
76
+ ? Math.floor(options.maxCharsPerFile)
77
+ : 4_000;
78
+ const maxTotalChars = Number.isFinite(options.maxTotalChars) && options.maxTotalChars > 0
79
+ ? Math.floor(options.maxTotalChars)
80
+ : 24_000;
81
+ const maxFileBytes = Number.isFinite(options.maxFileBytes) && options.maxFileBytes > 0
82
+ ? Math.floor(options.maxFileBytes)
83
+ : 200_000;
84
+ const tokens = tokenizeQuestion(question);
85
+ const all = await walkFiles(process.cwd());
86
+ const scored = all
87
+ .map((abs) => {
88
+ const rel = toRepoRelative(abs);
89
+ return { abs, rel, score: scorePath(rel, tokens) };
90
+ })
91
+ .sort((a, b) => b.score - a.score || a.rel.localeCompare(b.rel));
92
+ let totalChars = 0;
93
+ let scannedFiles = 0;
94
+ const includedFiles = [];
95
+ const truncatedFiles = [];
96
+ const parts = [];
97
+ for (const f of scored) {
98
+ if (includedFiles.length >= maxFiles)
99
+ break;
100
+ if (totalChars >= maxTotalChars)
101
+ break;
102
+ scannedFiles++;
103
+ let st;
104
+ try {
105
+ st = await stat(f.abs);
106
+ }
107
+ catch {
108
+ continue;
109
+ }
110
+ if (!st.isFile())
111
+ continue;
112
+ if (st.size > maxFileBytes)
113
+ continue;
114
+ const remaining = maxTotalChars - totalChars;
115
+ const perFileBudget = Math.max(200, Math.min(maxCharsPerFile, remaining));
116
+ try {
117
+ const r = await readUtf8UpToChars(f.abs, perFileBudget);
118
+ const header = `--- file: ${f.rel} ---\n`;
119
+ parts.push(header + r.text.trimEnd() + "\n");
120
+ includedFiles.push(f.rel);
121
+ totalChars += header.length + r.text.length + 1;
122
+ if (r.truncated)
123
+ truncatedFiles.push(f.rel);
124
+ }
125
+ catch {
126
+ continue;
127
+ }
128
+ }
129
+ return {
130
+ context: parts.join("\n").trim(),
131
+ includedFiles,
132
+ scannedFiles,
133
+ truncatedFiles
134
+ };
135
+ }
136
+ //# sourceMappingURL=repoContext.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repoContext.js","sourceRoot":"","sources":["../../src/utils/repoContext.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type Ora } from "ora";
2
+ export declare function createSpinner(text: string): Ora;
3
+ //# sourceMappingURL=spinner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../src/utils/spinner.ts"],"names":[],"mappings":"AAAA,OAAY,EAAE,KAAK,GAAG,EAAE,MAAM,KAAK,CAAC;AAEpC,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAE/C"}
@@ -0,0 +1,5 @@
1
+ import ora from "ora";
2
+ export function createSpinner(text) {
3
+ return ora({ text, spinner: "dots" });
4
+ }
5
+ //# sourceMappingURL=spinner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spinner.js","sourceRoot":"","sources":["../../src/utils/spinner.ts"],"names":[],"mappings":"AAAA,OAAO,GAAiB,MAAM,KAAK,CAAC;AAEpC,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,21 @@
1
+ export type NumberedSection = {
2
+ /** e.g. "Critical Issues" */
3
+ title: string;
4
+ /** Section body, trimmed, may be empty string */
5
+ body: string;
6
+ };
7
+ export type ParsedNumberedOutput = {
8
+ sections: NumberedSection[];
9
+ raw: string;
10
+ };
11
+ /**
12
+ * Parses output that follows the format:
13
+ * 1. Critical Issues
14
+ * <text>
15
+ * 2. Improvements
16
+ * <text>
17
+ * ...
18
+ */
19
+ export declare function parseNumberedHeadings(raw: string): ParsedNumberedOutput;
20
+ export declare function formatStructuredReview(parsed: ParsedNumberedOutput): string;
21
+ //# sourceMappingURL=structuredReview.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structuredReview.d.ts","sourceRoot":"","sources":["../../src/utils/structuredReview.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,eAAe,GAAG;IAC5B,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,CAwCvE;AAED,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAW3E"}
@@ -0,0 +1,59 @@
1
+ import chalk from "chalk";
2
+ /**
3
+ * Parses output that follows the format:
4
+ * 1. Critical Issues
5
+ * <text>
6
+ * 2. Improvements
7
+ * <text>
8
+ * ...
9
+ */
10
+ export function parseNumberedHeadings(raw) {
11
+ const text = (raw ?? "").trim();
12
+ if (!text)
13
+ return { sections: [], raw: "" };
14
+ const collect = (re, titleGroup) => {
15
+ const matches = [];
16
+ for (const m of text.matchAll(re)) {
17
+ matches.push({ index: m.index ?? 0, title: (m[titleGroup] ?? "").trim() });
18
+ }
19
+ return matches;
20
+ };
21
+ // Prefer the explicitly requested format first.
22
+ let matches = collect(/^(\d+)\.\s+(.+)\s*$/gm, 2);
23
+ // Fallback: common markdown variants.
24
+ if (matches.length === 0)
25
+ matches = collect(/^\*\*(.+?)\*\*\s*$/gm, 1);
26
+ if (matches.length === 0)
27
+ matches = collect(/^#{2,6}\s+(.+?)\s*$/gm, 1);
28
+ if (matches.length === 0)
29
+ return { sections: [], raw: text };
30
+ const sections = [];
31
+ for (let i = 0; i < matches.length; i++) {
32
+ const start = matches[i].index;
33
+ const end = i + 1 < matches.length ? matches[i + 1].index : text.length;
34
+ const chunk = text.slice(start, end).trimEnd();
35
+ const firstNl = chunk.indexOf("\n");
36
+ const titleLine = firstNl === -1 ? chunk : chunk.slice(0, firstNl);
37
+ const body = firstNl === -1 ? "" : chunk.slice(firstNl + 1).trim();
38
+ const title = titleLine
39
+ .replace(/^\d+\.\s+/, "")
40
+ .replace(/^\*\*(.+)\*\*$/, "$1")
41
+ .replace(/^#{2,6}\s+/, "")
42
+ .trim() || matches[i].title || `Section ${i + 1}`;
43
+ sections.push({ title, body });
44
+ }
45
+ return { sections, raw: text };
46
+ }
47
+ export function formatStructuredReview(parsed) {
48
+ const { sections, raw } = parsed;
49
+ if (sections.length === 0)
50
+ return raw;
51
+ const out = [];
52
+ for (const s of sections) {
53
+ out.push(chalk.bold(s.title));
54
+ out.push(s.body ? s.body : chalk.gray("(none)"));
55
+ out.push("");
56
+ }
57
+ return out.join("\n").trimEnd();
58
+ }
59
+ //# sourceMappingURL=structuredReview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structuredReview.js","sourceRoot":"","sources":["../../src/utils/structuredReview.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ {
2
+ "focus": ["performance", "readability"]
3
+ }
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "gitreviewpilot",
3
+ "version": "0.1.0",
4
+ "description": "GitReviewPilot — AI-powered CLI for reviewing pull requests and understanding codebases.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "bin": {
8
+ "gitreviewpilot": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist/",
12
+ "gitreviewpilot.config.json",
13
+ "README.md",
14
+ "LICENSE"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsc -p tsconfig.json",
18
+ "start": "node dist/index.js",
19
+ "dev": "node --enable-source-maps --watch dist/index.js",
20
+ "clean": "rimraf dist",
21
+ "prepublishOnly": "npm run clean && npm run build"
22
+ },
23
+ "dependencies": {
24
+ "chalk": "^5.4.1",
25
+ "commander": "^14.0.1",
26
+ "dotenv": "^17.2.2",
27
+ "ora": "^8.2.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^24.0.0",
31
+ "rimraf": "^6.0.1",
32
+ "typescript": "^5.9.2"
33
+ },
34
+ "engines": {
35
+ "node": ">=20"
36
+ }
37
+ }