git-smart-flow 0.3.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 (190) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/LICENSE +21 -0
  3. package/README.md +130 -0
  4. package/bin/git-smart-flow.js +2 -0
  5. package/bin/gsf.js +2 -0
  6. package/bin/gsfc.js +3 -0
  7. package/bin/gsfm.js +3 -0
  8. package/bin/gsfp.js +3 -0
  9. package/bin/gsfpr.js +3 -0
  10. package/dist/cli.d.ts +2 -0
  11. package/dist/cli.js +214 -0
  12. package/dist/cli.js.map +1 -0
  13. package/dist/commands/aliases.d.ts +2 -0
  14. package/dist/commands/aliases.js +37 -0
  15. package/dist/commands/aliases.js.map +1 -0
  16. package/dist/commands/branch.d.ts +2 -0
  17. package/dist/commands/branch.js +414 -0
  18. package/dist/commands/branch.js.map +1 -0
  19. package/dist/commands/commit-message.d.ts +7 -0
  20. package/dist/commands/commit-message.js +95 -0
  21. package/dist/commands/commit-message.js.map +1 -0
  22. package/dist/commands/commit.d.ts +3 -0
  23. package/dist/commands/commit.js +597 -0
  24. package/dist/commands/commit.js.map +1 -0
  25. package/dist/commands/config.d.ts +2 -0
  26. package/dist/commands/config.js +88 -0
  27. package/dist/commands/config.js.map +1 -0
  28. package/dist/commands/doctor.d.ts +2 -0
  29. package/dist/commands/doctor.js +246 -0
  30. package/dist/commands/doctor.js.map +1 -0
  31. package/dist/commands/info.d.ts +2 -0
  32. package/dist/commands/info.js +155 -0
  33. package/dist/commands/info.js.map +1 -0
  34. package/dist/commands/install-hooks.d.ts +2 -0
  35. package/dist/commands/install-hooks.js +66 -0
  36. package/dist/commands/install-hooks.js.map +1 -0
  37. package/dist/commands/log.d.ts +2 -0
  38. package/dist/commands/log.js +101 -0
  39. package/dist/commands/log.js.map +1 -0
  40. package/dist/commands/menu.d.ts +2 -0
  41. package/dist/commands/menu.js +297 -0
  42. package/dist/commands/menu.js.map +1 -0
  43. package/dist/commands/merge.d.ts +6 -0
  44. package/dist/commands/merge.js +128 -0
  45. package/dist/commands/merge.js.map +1 -0
  46. package/dist/commands/pr.d.ts +2 -0
  47. package/dist/commands/pr.js +731 -0
  48. package/dist/commands/pr.js.map +1 -0
  49. package/dist/commands/push.d.ts +7 -0
  50. package/dist/commands/push.js +225 -0
  51. package/dist/commands/push.js.map +1 -0
  52. package/dist/commands/reflog.d.ts +2 -0
  53. package/dist/commands/reflog.js +162 -0
  54. package/dist/commands/reflog.js.map +1 -0
  55. package/dist/commands/repo-init.d.ts +2 -0
  56. package/dist/commands/repo-init.js +466 -0
  57. package/dist/commands/repo-init.js.map +1 -0
  58. package/dist/commands/revert.d.ts +7 -0
  59. package/dist/commands/revert.js +694 -0
  60. package/dist/commands/revert.js.map +1 -0
  61. package/dist/commands/setup.d.ts +2 -0
  62. package/dist/commands/setup.js +86 -0
  63. package/dist/commands/setup.js.map +1 -0
  64. package/dist/commands/stash.d.ts +2 -0
  65. package/dist/commands/stash.js +130 -0
  66. package/dist/commands/stash.js.map +1 -0
  67. package/dist/commands/sync.d.ts +2 -0
  68. package/dist/commands/sync.js +335 -0
  69. package/dist/commands/sync.js.map +1 -0
  70. package/dist/commands/tag.d.ts +2 -0
  71. package/dist/commands/tag.js +163 -0
  72. package/dist/commands/tag.js.map +1 -0
  73. package/dist/commands/validate.d.ts +2 -0
  74. package/dist/commands/validate.js +203 -0
  75. package/dist/commands/validate.js.map +1 -0
  76. package/dist/config/config.d.ts +10 -0
  77. package/dist/config/config.js +126 -0
  78. package/dist/config/config.js.map +1 -0
  79. package/dist/git/ai-context-builder.d.ts +11 -0
  80. package/dist/git/ai-context-builder.js +112 -0
  81. package/dist/git/ai-context-builder.js.map +1 -0
  82. package/dist/git/convention-detector.d.ts +3 -0
  83. package/dist/git/convention-detector.js +211 -0
  84. package/dist/git/convention-detector.js.map +1 -0
  85. package/dist/git/ensure-repo.d.ts +7 -0
  86. package/dist/git/ensure-repo.js +141 -0
  87. package/dist/git/ensure-repo.js.map +1 -0
  88. package/dist/git/gitignore.d.ts +8 -0
  89. package/dist/git/gitignore.js +261 -0
  90. package/dist/git/gitignore.js.map +1 -0
  91. package/dist/git/remote-setup.d.ts +2 -0
  92. package/dist/git/remote-setup.js +129 -0
  93. package/dist/git/remote-setup.js.map +1 -0
  94. package/dist/git/repo.d.ts +73 -0
  95. package/dist/git/repo.js +308 -0
  96. package/dist/git/repo.js.map +1 -0
  97. package/dist/git/validate.d.ts +36 -0
  98. package/dist/git/validate.js +113 -0
  99. package/dist/git/validate.js.map +1 -0
  100. package/dist/providers/base.provider.d.ts +10 -0
  101. package/dist/providers/base.provider.js +40 -0
  102. package/dist/providers/base.provider.js.map +1 -0
  103. package/dist/providers/claude.provider.d.ts +14 -0
  104. package/dist/providers/claude.provider.js +85 -0
  105. package/dist/providers/claude.provider.js.map +1 -0
  106. package/dist/providers/copilot.provider.d.ts +12 -0
  107. package/dist/providers/copilot.provider.js +88 -0
  108. package/dist/providers/copilot.provider.js.map +1 -0
  109. package/dist/providers/heuristic.provider.d.ts +9 -0
  110. package/dist/providers/heuristic.provider.js +163 -0
  111. package/dist/providers/heuristic.provider.js.map +1 -0
  112. package/dist/providers/ollama.provider.d.ts +14 -0
  113. package/dist/providers/ollama.provider.js +83 -0
  114. package/dist/providers/ollama.provider.js.map +1 -0
  115. package/dist/providers/openai.provider.d.ts +14 -0
  116. package/dist/providers/openai.provider.js +84 -0
  117. package/dist/providers/openai.provider.js.map +1 -0
  118. package/dist/providers/provider.factory.d.ts +5 -0
  119. package/dist/providers/provider.factory.js +51 -0
  120. package/dist/providers/provider.factory.js.map +1 -0
  121. package/dist/security/scanner.d.ts +13 -0
  122. package/dist/security/scanner.js +138 -0
  123. package/dist/security/scanner.js.map +1 -0
  124. package/dist/types/index.d.ts +146 -0
  125. package/dist/types/index.js +2 -0
  126. package/dist/types/index.js.map +1 -0
  127. package/dist/ux/components/BranchTree.d.ts +8 -0
  128. package/dist/ux/components/BranchTree.js +57 -0
  129. package/dist/ux/components/BranchTree.js.map +1 -0
  130. package/dist/ux/components/CommitProposal.d.ts +13 -0
  131. package/dist/ux/components/CommitProposal.js +127 -0
  132. package/dist/ux/components/CommitProposal.js.map +1 -0
  133. package/dist/ux/components/DiagnosticReport.d.ts +18 -0
  134. package/dist/ux/components/DiagnosticReport.js +19 -0
  135. package/dist/ux/components/DiagnosticReport.js.map +1 -0
  136. package/dist/ux/components/ErrorBox.d.ts +7 -0
  137. package/dist/ux/components/ErrorBox.js +9 -0
  138. package/dist/ux/components/ErrorBox.js.map +1 -0
  139. package/dist/ux/components/FileSelector.d.ts +14 -0
  140. package/dist/ux/components/FileSelector.js +87 -0
  141. package/dist/ux/components/FileSelector.js.map +1 -0
  142. package/dist/ux/components/Logo.d.ts +6 -0
  143. package/dist/ux/components/Logo.js +21 -0
  144. package/dist/ux/components/Logo.js.map +1 -0
  145. package/dist/ux/components/RepoContext.d.ts +8 -0
  146. package/dist/ux/components/RepoContext.js +17 -0
  147. package/dist/ux/components/RepoContext.js.map +1 -0
  148. package/dist/ux/components/SecurityAlert.d.ts +9 -0
  149. package/dist/ux/components/SecurityAlert.js +16 -0
  150. package/dist/ux/components/SecurityAlert.js.map +1 -0
  151. package/dist/ux/components/StatusDashboard.d.ts +14 -0
  152. package/dist/ux/components/StatusDashboard.js +36 -0
  153. package/dist/ux/components/StatusDashboard.js.map +1 -0
  154. package/dist/ux/components/SuccessBox.d.ts +7 -0
  155. package/dist/ux/components/SuccessBox.js +9 -0
  156. package/dist/ux/components/SuccessBox.js.map +1 -0
  157. package/dist/ux/components/ValidationReport.d.ts +16 -0
  158. package/dist/ux/components/ValidationReport.js +19 -0
  159. package/dist/ux/components/ValidationReport.js.map +1 -0
  160. package/dist/ux/components/WarningBox.d.ts +7 -0
  161. package/dist/ux/components/WarningBox.js +9 -0
  162. package/dist/ux/components/WarningBox.js.map +1 -0
  163. package/dist/ux/display.d.ts +21 -0
  164. package/dist/ux/display.js +96 -0
  165. package/dist/ux/display.js.map +1 -0
  166. package/dist/ux/hooks/useActivation.d.ts +8 -0
  167. package/dist/ux/hooks/useActivation.js +16 -0
  168. package/dist/ux/hooks/useActivation.js.map +1 -0
  169. package/dist/ux/hooks/useSpinner.d.ts +2 -0
  170. package/dist/ux/hooks/useSpinner.js +13 -0
  171. package/dist/ux/hooks/useSpinner.js.map +1 -0
  172. package/dist/ux/menu.d.ts +7 -0
  173. package/dist/ux/menu.js +56 -0
  174. package/dist/ux/menu.js.map +1 -0
  175. package/dist/ux/prompt.d.ts +7 -0
  176. package/dist/ux/prompt.js +361 -0
  177. package/dist/ux/prompt.js.map +1 -0
  178. package/dist/ux/renderer.d.ts +9 -0
  179. package/dist/ux/renderer.js +45 -0
  180. package/dist/ux/renderer.js.map +1 -0
  181. package/dist/ux/spinner.d.ts +6 -0
  182. package/dist/ux/spinner.js +42 -0
  183. package/dist/ux/spinner.js.map +1 -0
  184. package/dist/ux/statusbar.d.ts +2 -0
  185. package/dist/ux/statusbar.js +44 -0
  186. package/dist/ux/statusbar.js.map +1 -0
  187. package/dist/ux/theme.d.ts +37 -0
  188. package/dist/ux/theme.js +55 -0
  189. package/dist/ux/theme.js.map +1 -0
  190. package/package.json +125 -0
@@ -0,0 +1,12 @@
1
+ import type { AIContext, PRProposal, ProviderName } from '../types/index.js';
2
+ import { BaseProvider } from './base.provider.js';
3
+ export declare class CopilotProvider extends BaseProvider {
4
+ name: ProviderName;
5
+ private command;
6
+ private fallback;
7
+ constructor(command?: string);
8
+ isAvailable(): Promise<boolean>;
9
+ generateCommitMessage(context: AIContext): Promise<string>;
10
+ generatePRDescription(context: AIContext): Promise<PRProposal>;
11
+ }
12
+ //# sourceMappingURL=copilot.provider.d.ts.map
@@ -0,0 +1,88 @@
1
+ import { spawnSync } from 'child_process';
2
+ import { BaseProvider } from './base.provider.js';
3
+ import { HeuristicProvider } from './heuristic.provider.js';
4
+ const COPILOT_CANDIDATES = ['gh copilot suggest', 'copilot'];
5
+ export class CopilotProvider extends BaseProvider {
6
+ name = 'copilot';
7
+ command;
8
+ fallback = new HeuristicProvider();
9
+ constructor(command) {
10
+ super();
11
+ this.command = command ?? '';
12
+ }
13
+ // eslint-disable-next-line @typescript-eslint/require-await
14
+ async isAvailable() {
15
+ if (this.command)
16
+ return testCommand(this.command);
17
+ for (const candidate of COPILOT_CANDIDATES) {
18
+ if (testCommand(candidate)) {
19
+ this.command = candidate;
20
+ return true;
21
+ }
22
+ }
23
+ return false;
24
+ }
25
+ async generateCommitMessage(context) {
26
+ if (!(await this.isAvailable())) {
27
+ return this.fallback.generateCommitMessage(context);
28
+ }
29
+ try {
30
+ const prompt = this.buildCommitPrompt(context);
31
+ const result = runCopilot(this.command, prompt);
32
+ if (result)
33
+ return result.trim();
34
+ }
35
+ catch {
36
+ /* */
37
+ }
38
+ return this.fallback.generateCommitMessage(context);
39
+ }
40
+ async generatePRDescription(context) {
41
+ if (!(await this.isAvailable())) {
42
+ return this.fallback.generatePRDescription(context);
43
+ }
44
+ try {
45
+ const prompt = this.buildPRPrompt(context);
46
+ const result = runCopilot(this.command, prompt);
47
+ if (result)
48
+ return parsePRJSON(result) ?? this.fallback.generatePRDescription(context);
49
+ }
50
+ catch {
51
+ /* */
52
+ }
53
+ return this.fallback.generatePRDescription(context);
54
+ }
55
+ }
56
+ function testCommand(cmd) {
57
+ const parts = cmd.split(' ');
58
+ const result = spawnSync(parts[0] ?? cmd, [...parts.slice(1), '--version'], {
59
+ encoding: 'utf-8',
60
+ timeout: 3000,
61
+ });
62
+ return result.status === 0;
63
+ }
64
+ function runCopilot(cmd, prompt) {
65
+ const parts = cmd.split(' ');
66
+ const result = spawnSync(parts[0] ?? cmd, [...parts.slice(1), '-t', 'shell', prompt], {
67
+ encoding: 'utf-8',
68
+ timeout: 30000,
69
+ });
70
+ if (result.status !== 0)
71
+ return null;
72
+ return result.stdout?.trim() ?? null;
73
+ }
74
+ function parsePRJSON(raw) {
75
+ try {
76
+ const match = raw.match(/\{[\s\S]+\}/);
77
+ if (!match)
78
+ return null;
79
+ const parsed = JSON.parse(match[0]);
80
+ if (parsed.title && parsed.body)
81
+ return { title: parsed.title, body: parsed.body };
82
+ }
83
+ catch {
84
+ /* */
85
+ }
86
+ return null;
87
+ }
88
+ //# sourceMappingURL=copilot.provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copilot.provider.js","sourceRoot":"","sources":["../../src/providers/copilot.provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { AIContext, PRProposal, ProviderName } from '../types/index.js';
2
+ import { BaseProvider } from './base.provider.js';
3
+ export declare class HeuristicProvider extends BaseProvider {
4
+ name: ProviderName;
5
+ isAvailable(): Promise<boolean>;
6
+ generateCommitMessage(context: AIContext): Promise<string>;
7
+ generatePRDescription(context: AIContext): Promise<PRProposal>;
8
+ }
9
+ //# sourceMappingURL=heuristic.provider.d.ts.map
@@ -0,0 +1,163 @@
1
+ import { extname } from 'path';
2
+ import { BaseProvider } from './base.provider.js';
3
+ const DIR_TYPE_MAP = {
4
+ test: 'test',
5
+ tests: 'test',
6
+ __tests__: 'test',
7
+ spec: 'test',
8
+ docs: 'docs',
9
+ doc: 'docs',
10
+ '.github': 'ci',
11
+ '.husky': 'chore',
12
+ ci: 'ci',
13
+ scripts: 'chore',
14
+ migrations: 'chore',
15
+ config: 'chore',
16
+ configs: 'chore',
17
+ types: 'refactor',
18
+ interfaces: 'refactor',
19
+ styles: 'style',
20
+ css: 'style',
21
+ scss: 'style',
22
+ };
23
+ const EXT_TYPE_MAP = {
24
+ md: 'docs',
25
+ mdx: 'docs',
26
+ yml: 'ci',
27
+ yaml: 'ci',
28
+ sh: 'chore',
29
+ ps1: 'chore',
30
+ sql: 'chore',
31
+ css: 'style',
32
+ scss: 'style',
33
+ less: 'style',
34
+ test: 'test',
35
+ spec: 'test',
36
+ };
37
+ export class HeuristicProvider extends BaseProvider {
38
+ name = 'heuristic';
39
+ // eslint-disable-next-line @typescript-eslint/require-await
40
+ async isAvailable() {
41
+ return true;
42
+ }
43
+ // eslint-disable-next-line @typescript-eslint/require-await
44
+ async generateCommitMessage(context) {
45
+ const { changedFiles, detectedCommitConvention: conv, ticket } = context;
46
+ if (changedFiles.length === 0) {
47
+ return `chore: update files`;
48
+ }
49
+ const type = inferType(changedFiles.map((f) => f.path));
50
+ const scope = inferScope(changedFiles.map((f) => f.path), conv.allowedScopes);
51
+ const subject = inferSubject(changedFiles.map((f) => f.path));
52
+ const ticketSuffix = ticket ? ` (${ticket})` : '';
53
+ const scopePart = scope ? `(${scope})` : '';
54
+ const message = `${type}${scopePart}: ${subject}${ticketSuffix}`;
55
+ return message.length <= conv.maxHeaderLength
56
+ ? message
57
+ : message.substring(0, conv.maxHeaderLength - 3) + '...';
58
+ }
59
+ // eslint-disable-next-line @typescript-eslint/require-await
60
+ async generatePRDescription(context) {
61
+ const { changedFiles, branch, ticket } = context;
62
+ const files = changedFiles.map((f) => `- \`${f.path}\` (${f.status})`).join('\n');
63
+ const ticketLine = ticket ? `\n\nRelated to: ${ticket}` : '';
64
+ const title = buildPRTitle(branch, changedFiles.map((f) => f.path));
65
+ const body = [
66
+ `## Context`,
67
+ `Changes from branch \`${branch}\`.${ticketLine}`,
68
+ ``,
69
+ `## Changes`,
70
+ files,
71
+ ``,
72
+ `## Testing`,
73
+ `- [ ] Manual testing performed`,
74
+ `- [ ] Automated tests pass`,
75
+ ``,
76
+ `## Risks / Impact`,
77
+ `_No known risks identified._`,
78
+ ``,
79
+ `## Additional Notes`,
80
+ `_Generated by git-smart-flow heuristic provider._`,
81
+ ].join('\n');
82
+ return { title, body };
83
+ }
84
+ }
85
+ function inferType(paths) {
86
+ const votes = {};
87
+ for (const p of paths) {
88
+ const parts = p.split('/');
89
+ for (const part of parts) {
90
+ const mapped = DIR_TYPE_MAP[part.toLowerCase()];
91
+ if (mapped)
92
+ votes[mapped] = (votes[mapped] ?? 0) + 1;
93
+ }
94
+ const ext = extname(p).slice(1).toLowerCase();
95
+ const extMapped = EXT_TYPE_MAP[ext];
96
+ if (extMapped)
97
+ votes[extMapped] = (votes[extMapped] ?? 0) + 0.5;
98
+ }
99
+ if (Object.keys(votes).length === 0)
100
+ return 'feat';
101
+ return Object.entries(votes).sort(([, a], [, b]) => b - a)[0]?.[0] ?? 'feat';
102
+ }
103
+ function inferScope(paths, allowedScopes) {
104
+ if (paths.length === 0)
105
+ return undefined;
106
+ const firstParts = paths.map((p) => p.split('/')[0] ?? '').filter((p) => !p.startsWith('.'));
107
+ const common = mostCommon(firstParts);
108
+ if (!common || common === 'src') {
109
+ const secondParts = paths
110
+ .filter((p) => p.includes('/'))
111
+ .map((p) => p.split('/')[1] ?? '')
112
+ .filter(Boolean);
113
+ const commonSecond = mostCommon(secondParts);
114
+ if (commonSecond && (!allowedScopes || allowedScopes.includes(commonSecond))) {
115
+ return commonSecond;
116
+ }
117
+ return undefined;
118
+ }
119
+ if (!allowedScopes || allowedScopes.includes(common))
120
+ return common;
121
+ return undefined;
122
+ }
123
+ function inferSubject(paths) {
124
+ if (paths.length === 1) {
125
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
126
+ const parts = paths[0].split('/');
127
+ const filename = (parts[parts.length - 1] ?? '').replace(/\.[^.]+$/, '');
128
+ return `update ${toKebab(filename)}`;
129
+ }
130
+ if (paths.length <= 3) {
131
+ const parts = paths.map((p) => {
132
+ const segs = p.split('/');
133
+ return (segs[segs.length - 1] ?? '').replace(/\.[^.]+$/, '');
134
+ });
135
+ return `update ${parts.join(', ')}`;
136
+ }
137
+ const dirs = [...new Set(paths.map((p) => p.split('/')[0] ?? ''))];
138
+ return `update ${dirs.slice(0, 2).join(', ')} files`;
139
+ }
140
+ function buildPRTitle(branch, _paths) {
141
+ const cleaned = branch
142
+ .replace(/^(feat|fix|feature|hotfix|chore|release)\//, '')
143
+ .replace(/^[A-Z][A-Z0-9]+-\d+-/, '')
144
+ .replace(/[-_]/g, ' ')
145
+ .trim();
146
+ return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
147
+ }
148
+ function mostCommon(arr) {
149
+ if (arr.length === 0)
150
+ return undefined;
151
+ const counts = {};
152
+ for (const item of arr)
153
+ counts[item] = (counts[item] ?? 0) + 1;
154
+ const sorted = Object.entries(counts).sort(([, a], [, b]) => b - a);
155
+ return sorted[0]?.[0];
156
+ }
157
+ function toKebab(str) {
158
+ return str
159
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
160
+ .replace(/[_\s]+/g, '-')
161
+ .toLowerCase();
162
+ }
163
+ //# sourceMappingURL=heuristic.provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heuristic.provider.js","sourceRoot":"","sources":["../../src/providers/heuristic.provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { AIContext, PRProposal, ProviderName } from '../types/index.js';
2
+ import { BaseProvider } from './base.provider.js';
3
+ export declare class OllamaProvider extends BaseProvider {
4
+ name: ProviderName;
5
+ private baseUrl;
6
+ private model;
7
+ private fallback;
8
+ constructor(baseUrl?: string, model?: string);
9
+ isAvailable(): Promise<boolean>;
10
+ generateCommitMessage(context: AIContext): Promise<string>;
11
+ generatePRDescription(context: AIContext): Promise<PRProposal>;
12
+ private generate;
13
+ }
14
+ //# sourceMappingURL=ollama.provider.d.ts.map
@@ -0,0 +1,83 @@
1
+ import { BaseProvider } from './base.provider.js';
2
+ import { HeuristicProvider } from './heuristic.provider.js';
3
+ const DEFAULT_OLLAMA_URL = 'http://localhost:11434';
4
+ const DEFAULT_MODEL = 'llama3.2';
5
+ const OLLAMA_GENERATE_PATH = '/api/generate';
6
+ export class OllamaProvider extends BaseProvider {
7
+ name = 'ollama';
8
+ baseUrl;
9
+ model;
10
+ fallback = new HeuristicProvider();
11
+ constructor(baseUrl, model) {
12
+ super();
13
+ this.baseUrl = baseUrl ?? DEFAULT_OLLAMA_URL;
14
+ this.model = model ?? DEFAULT_MODEL;
15
+ }
16
+ async isAvailable() {
17
+ try {
18
+ const res = await fetch(`${this.baseUrl}/api/tags`, { signal: AbortSignal.timeout(2000) });
19
+ return res.ok;
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ }
25
+ async generateCommitMessage(context) {
26
+ if (!(await this.isAvailable()))
27
+ return this.fallback.generateCommitMessage(context);
28
+ try {
29
+ const prompt = this.buildCommitPrompt(context);
30
+ const response = await this.generate(prompt);
31
+ if (response)
32
+ return response.trim();
33
+ }
34
+ catch {
35
+ /* */
36
+ }
37
+ return this.fallback.generateCommitMessage(context);
38
+ }
39
+ async generatePRDescription(context) {
40
+ if (!(await this.isAvailable()))
41
+ return this.fallback.generatePRDescription(context);
42
+ try {
43
+ const prompt = this.buildPRPrompt(context);
44
+ const response = await this.generate(prompt);
45
+ if (response) {
46
+ const parsed = parsePRJSON(response);
47
+ if (parsed)
48
+ return parsed;
49
+ }
50
+ }
51
+ catch {
52
+ /* */
53
+ }
54
+ return this.fallback.generatePRDescription(context);
55
+ }
56
+ async generate(prompt) {
57
+ const res = await fetch(`${this.baseUrl}${OLLAMA_GENERATE_PATH}`, {
58
+ method: 'POST',
59
+ headers: { 'Content-Type': 'application/json' },
60
+ body: JSON.stringify({ model: this.model, prompt, stream: false }),
61
+ signal: AbortSignal.timeout(60000),
62
+ });
63
+ if (!res.ok)
64
+ return null;
65
+ const data = (await res.json());
66
+ return data.response ?? null;
67
+ }
68
+ }
69
+ function parsePRJSON(raw) {
70
+ try {
71
+ const match = raw.match(/\{[\s\S]+\}/);
72
+ if (!match)
73
+ return null;
74
+ const parsed = JSON.parse(match[0]);
75
+ if (parsed.title && parsed.body)
76
+ return { title: parsed.title, body: parsed.body };
77
+ }
78
+ catch {
79
+ /* */
80
+ }
81
+ return null;
82
+ }
83
+ //# sourceMappingURL=ollama.provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama.provider.js","sourceRoot":"","sources":["../../src/providers/ollama.provider.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { AIContext, PRProposal, ProviderName } from '../types/index.js';
2
+ import { BaseProvider } from './base.provider.js';
3
+ export declare class OpenAIProvider extends BaseProvider {
4
+ name: ProviderName;
5
+ private apiKey;
6
+ private model;
7
+ private fallback;
8
+ constructor(apiKey?: string, model?: string);
9
+ isAvailable(): Promise<boolean>;
10
+ generateCommitMessage(context: AIContext): Promise<string>;
11
+ generatePRDescription(context: AIContext): Promise<PRProposal>;
12
+ private chat;
13
+ }
14
+ //# sourceMappingURL=openai.provider.d.ts.map
@@ -0,0 +1,84 @@
1
+ import { BaseProvider } from './base.provider.js';
2
+ import { HeuristicProvider } from './heuristic.provider.js';
3
+ const OPENAI_API_URL = 'https://api.openai.com/v1/chat/completions';
4
+ const DEFAULT_MODEL = 'gpt-4o-mini';
5
+ export class OpenAIProvider extends BaseProvider {
6
+ name = 'openai';
7
+ apiKey;
8
+ model;
9
+ fallback = new HeuristicProvider();
10
+ constructor(apiKey, model) {
11
+ super();
12
+ this.apiKey = apiKey ?? process.env.OPENAI_API_KEY ?? '';
13
+ this.model = model ?? DEFAULT_MODEL;
14
+ }
15
+ // eslint-disable-next-line @typescript-eslint/require-await
16
+ async isAvailable() {
17
+ return this.apiKey.length > 0;
18
+ }
19
+ async generateCommitMessage(context) {
20
+ if (!(await this.isAvailable()))
21
+ return this.fallback.generateCommitMessage(context);
22
+ try {
23
+ const prompt = this.buildCommitPrompt(context);
24
+ const response = await this.chat(prompt);
25
+ if (response)
26
+ return response.trim();
27
+ }
28
+ catch {
29
+ /* */
30
+ }
31
+ return this.fallback.generateCommitMessage(context);
32
+ }
33
+ async generatePRDescription(context) {
34
+ if (!(await this.isAvailable()))
35
+ return this.fallback.generatePRDescription(context);
36
+ try {
37
+ const prompt = this.buildPRPrompt(context);
38
+ const response = await this.chat(prompt);
39
+ if (response) {
40
+ const parsed = parsePRJSON(response);
41
+ if (parsed)
42
+ return parsed;
43
+ }
44
+ }
45
+ catch {
46
+ /* */
47
+ }
48
+ return this.fallback.generatePRDescription(context);
49
+ }
50
+ async chat(prompt) {
51
+ const res = await fetch(OPENAI_API_URL, {
52
+ method: 'POST',
53
+ headers: {
54
+ 'Content-Type': 'application/json',
55
+ Authorization: `Bearer ${this.apiKey}`,
56
+ },
57
+ body: JSON.stringify({
58
+ model: this.model,
59
+ messages: [{ role: 'user', content: prompt }],
60
+ temperature: 0.3,
61
+ max_tokens: 512,
62
+ }),
63
+ });
64
+ if (!res.ok)
65
+ return null;
66
+ const data = (await res.json());
67
+ return data.choices?.[0]?.message?.content ?? null;
68
+ }
69
+ }
70
+ function parsePRJSON(raw) {
71
+ try {
72
+ const match = raw.match(/\{[\s\S]+\}/);
73
+ if (!match)
74
+ return null;
75
+ const parsed = JSON.parse(match[0]);
76
+ if (parsed.title && parsed.body)
77
+ return { title: parsed.title, body: parsed.body };
78
+ }
79
+ catch {
80
+ /* */
81
+ }
82
+ return null;
83
+ }
84
+ //# sourceMappingURL=openai.provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai.provider.js","sourceRoot":"","sources":["../../src/providers/openai.provider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAE5D,MAAM,cAAc,GAAG,4CAA4C,CAAC;AACpE,MAAM,aAAa,GAAG,aAAa,CAAC;AAEpC,MAAM,OAAO,cAAe,SAAQ,YAAY;IAC9C,IAAI,GAAiB,QAAQ,CAAC;IACtB,MAAM,CAAS;IACf,KAAK,CAAS;IACd,QAAQ,GAAG,IAAI,iBAAiB,EAAE,CAAC;IAE3C,YAAY,MAAe,EAAE,KAAc;QACzC,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC;QACzD,IAAI,CAAC,KAAK,GAAG,KAAK,IAAI,aAAa,CAAC;IACtC,CAAC;IAED,4DAA4D;IAC5D,KAAK,CAAC,WAAW;QACf,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IAChC,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,OAAkB;QAC5C,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC;QACrF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;YAC/C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,QAAQ;gBAAE,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;QACvC,CAAC;QAAC,MAAM,CAAC;YACP,KAAK;QACP,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,qBAAqB,CAAC,OAAkB;QAC5C,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YAAE,OAAO,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC;QACrF,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAC3C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,MAAM,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC;gBACrC,IAAI,MAAM;oBAAE,OAAO,MAAM,CAAC;YAC5B,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,KAAK;QACP,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC,qBAAqB,CAAC,OAAO,CAAC,CAAC;IACtD,CAAC;IAEO,KAAK,CAAC,IAAI,CAAC,MAAc;QAC/B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,cAAc,EAAE;YACtC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;aACvC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;gBAC7C,WAAW,EAAE,GAAG;gBAChB,UAAU,EAAE,GAAG;aAChB,CAAC;SACH,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAE7B,CAAC;QACF,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,IAAI,CAAC;IACrD,CAAC;CACF;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAsC,CAAC;QACzE,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI;YAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,CAAC;IACrF,CAAC;IAAC,MAAM,CAAC;QACP,KAAK;IACP,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { AIProvider, MergedConfig, ProviderName } from '../types/index.js';
2
+ export declare function createProvider(config: MergedConfig): AIProvider;
3
+ export declare function createProviderWithFallback(config: MergedConfig): Promise<AIProvider>;
4
+ export declare function detectAvailableProviders(): Promise<ProviderName[]>;
5
+ //# sourceMappingURL=provider.factory.d.ts.map
@@ -0,0 +1,51 @@
1
+ import { ClaudeProvider } from './claude.provider.js';
2
+ import { CopilotProvider } from './copilot.provider.js';
3
+ import { HeuristicProvider } from './heuristic.provider.js';
4
+ import { OllamaProvider } from './ollama.provider.js';
5
+ import { OpenAIProvider } from './openai.provider.js';
6
+ export function createProvider(config) {
7
+ if (!config.ai.enabled)
8
+ return new HeuristicProvider();
9
+ const provider = buildProvider(config.ai.provider, config);
10
+ return provider;
11
+ }
12
+ function buildProvider(name, config) {
13
+ switch (name) {
14
+ case 'openai':
15
+ return new OpenAIProvider(config.ai.apiKey, config.ai.model);
16
+ case 'claude':
17
+ return new ClaudeProvider(config.ai.apiKey, config.ai.model);
18
+ case 'ollama':
19
+ return new OllamaProvider(config.ai.ollamaUrl, config.ai.ollamaModel);
20
+ case 'copilot':
21
+ return new CopilotProvider(config.ai.copilotCommand);
22
+ case 'heuristic':
23
+ default:
24
+ return new HeuristicProvider();
25
+ }
26
+ }
27
+ export async function createProviderWithFallback(config) {
28
+ const primary = createProvider(config);
29
+ if (await primary.isAvailable())
30
+ return primary;
31
+ // Auto-detect Ollama if primary is unavailable
32
+ const ollama = new OllamaProvider(config.ai.ollamaUrl, config.ai.ollamaModel);
33
+ if (await ollama.isAvailable())
34
+ return ollama;
35
+ return new HeuristicProvider();
36
+ }
37
+ export async function detectAvailableProviders() {
38
+ const available = ['heuristic'];
39
+ const ollama = new OllamaProvider();
40
+ if (await ollama.isAvailable())
41
+ available.push('ollama');
42
+ const copilot = new CopilotProvider();
43
+ if (await copilot.isAvailable())
44
+ available.push('copilot');
45
+ if (process.env.OPENAI_API_KEY)
46
+ available.push('openai');
47
+ if (process.env.ANTHROPIC_API_KEY)
48
+ available.push('claude');
49
+ return available;
50
+ }
51
+ //# sourceMappingURL=provider.factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.factory.js","sourceRoot":"","sources":["../../src/providers/provider.factory.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,MAAM,UAAU,cAAc,CAAC,MAAoB;IACjD,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,OAAO;QAAE,OAAO,IAAI,iBAAiB,EAAE,CAAC;IAEvD,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC3D,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,aAAa,CAAC,IAAkB,EAAE,MAAoB;IAC7D,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ;YACX,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;QAC/D,KAAK,QAAQ;YACX,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;QAC/D,KAAK,QAAQ;YACX,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC;QACxE,KAAK,SAAS;YACZ,OAAO,IAAI,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC;QACvD,KAAK,WAAW,CAAC;QACjB;YACE,OAAO,IAAI,iBAAiB,EAAE,CAAC;IACnC,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAC,MAAoB;IACnE,MAAM,OAAO,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;IACvC,IAAI,MAAM,OAAO,CAAC,WAAW,EAAE;QAAE,OAAO,OAAO,CAAC;IAEhD,+CAA+C;IAC/C,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC;IAC9E,IAAI,MAAM,MAAM,CAAC,WAAW,EAAE;QAAE,OAAO,MAAM,CAAC;IAE9C,OAAO,IAAI,iBAAiB,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,wBAAwB;IAC5C,MAAM,SAAS,GAAmB,CAAC,WAAW,CAAC,CAAC;IAEhD,MAAM,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;IACpC,IAAI,MAAM,MAAM,CAAC,WAAW,EAAE;QAAE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAEzD,MAAM,OAAO,GAAG,IAAI,eAAe,EAAE,CAAC;IACtC,IAAI,MAAM,OAAO,CAAC,WAAW,EAAE;QAAE,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAE3D,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzD,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAAE,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAE5D,OAAO,SAAS,CAAC;AACnB,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { SecurityScanResult } from '../types/index.js';
2
+ export interface ScanTarget {
3
+ path: string;
4
+ content?: string;
5
+ }
6
+ export declare function scanFiles(targets: ScanTarget[], blockedFilePatterns: string[]): SecurityScanResult;
7
+ export declare function scanDiff(diff: string, filePaths: string[], blockedFilePatterns: string[]): SecurityScanResult;
8
+ export declare function redactContent(content: string): {
9
+ redacted: string;
10
+ count: number;
11
+ };
12
+ export declare function isSensitiveFile(filename: string, extraPatterns?: string[]): boolean;
13
+ //# sourceMappingURL=scanner.d.ts.map