difit 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +3 -1
  2. package/dist/cli/index.js +0 -0
  3. package/dist/client/assets/index-W2UC55JC.css +1 -0
  4. package/dist/client/assets/index-hiGBtmpa.js +142 -0
  5. package/dist/client/index.html +2 -2
  6. package/dist/server/comment-store.js +85 -8
  7. package/dist/server/git-diff.js +3 -1
  8. package/dist/server/server.js +10 -0
  9. package/package.json +4 -4
  10. package/dist/cli/index.d.ts +0 -2
  11. package/dist/cli/index.test.d.ts +0 -1
  12. package/dist/cli/index.test.js +0 -676
  13. package/dist/cli/utils.d.ts +0 -1
  14. package/dist/cli/utils.test.d.ts +0 -1
  15. package/dist/cli/utils.test.js +0 -214
  16. package/dist/client/assets/index-CSJzfcU-.css +0 -1
  17. package/dist/client/assets/index-IxkylgHX.js +0 -53
  18. package/dist/client/assets/prism-css-Bpx-unsJ.js +0 -1
  19. package/dist/client/assets/prism-json-xwnKirkR.js +0 -1
  20. package/dist/client/assets/prism-typescript-B2PMeEx1.js +0 -1
  21. package/dist/server/comment-store.d.ts +0 -13
  22. package/dist/server/git-diff-tui.d.ts +0 -2
  23. package/dist/server/git-diff-tui.js +0 -95
  24. package/dist/server/git-diff.d.ts +0 -10
  25. package/dist/server/git-diff.test.d.ts +0 -1
  26. package/dist/server/git-diff.test.js +0 -292
  27. package/dist/server/server.d.ts +0 -11
  28. package/dist/server/server.test.d.ts +0 -1
  29. package/dist/server/server.test.js +0 -382
  30. package/dist/tui/App.d.ts +0 -8
  31. package/dist/tui/App.js +0 -92
  32. package/dist/tui/App.test.d.ts +0 -1
  33. package/dist/tui/App.test.js +0 -31
  34. package/dist/tui/components/DiffViewer.d.ts +0 -9
  35. package/dist/tui/components/DiffViewer.js +0 -88
  36. package/dist/tui/components/FileList.d.ts +0 -8
  37. package/dist/tui/components/FileList.js +0 -48
  38. package/dist/tui/components/SideBySideDiffViewer.d.ts +0 -9
  39. package/dist/tui/components/SideBySideDiffViewer.js +0 -237
  40. package/dist/tui/components/StatusBar.d.ts +0 -8
  41. package/dist/tui/components/StatusBar.js +0 -23
  42. package/dist/tui/utils/parseDiff.d.ts +0 -2
  43. package/dist/tui/utils/parseDiff.js +0 -68
  44. package/dist/types/diff.d.ts +0 -33
  45. package/dist/utils/fileUtils.d.ts +0 -12
  46. package/dist/utils/fileUtils.js +0 -21
@@ -1 +0,0 @@
1
- (function(s){var e=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;s.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:"+/[^;{\s"']|\s+(?!\s)/.source+"|"+e.source+")*?"+/(?:;|(?=\s*\{))/.source),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+e.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+e.source+"$"),alias:"url"}}},selector:{pattern:RegExp(`(^|[{}\\s])[^{}\\s](?:[^{};"'\\s]|\\s+(?![\\s{])|`+e.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:e,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},s.languages.css.atrule.inside.rest=s.languages.css;var t=s.languages.markup;t&&(t.tag.addInlined("style","css"),t.tag.addAttribute("style","css"))})(Prism);
@@ -1 +0,0 @@
1
- Prism.languages.json={property:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?=\s*:)/,lookbehind:!0,greedy:!0},string:{pattern:/(^|[^\\])"(?:\\.|[^\\"\r\n])*"(?!\s*:)/,lookbehind:!0,greedy:!0},comment:{pattern:/\/\/.*|\/\*[\s\S]*?(?:\*\/|$)/,greedy:!0},number:/-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/i,punctuation:/[{}[\],]/,operator:/:/,boolean:/\b(?:false|true)\b/,null:{pattern:/\bnull\b/,alias:"keyword"}};Prism.languages.webmanifest=Prism.languages.json;
@@ -1 +0,0 @@
1
- (function(e){e.languages.typescript=e.languages.extend("javascript",{"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|type)\s+)(?!keyof\b)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?:\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var a=e.languages.extend("typescript",{});delete a["class-name"],e.languages.typescript["class-name"].inside=a,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:a}}}}),e.languages.ts=e.languages.typescript})(Prism);
@@ -1,13 +0,0 @@
1
- import { Comment } from '../types/diff.js';
2
- export declare class CommentStore {
3
- private sessionId;
4
- private filePath;
5
- private comments;
6
- constructor(sessionId?: string);
7
- addComment(file: string, line: number, body: string): Promise<Comment>;
8
- getComments(): Promise<Comment[]>;
9
- getCommentsForFile(file: string): Promise<Comment[]>;
10
- generatePrompt(comment: Comment, diffContent: string): string;
11
- private saveToFile;
12
- loadFromFile(): Promise<void>;
13
- }
@@ -1,2 +0,0 @@
1
- import type { FileDiff } from '../types/diff.js';
2
- export declare function loadGitDiff(targetCommitish: string, baseCommitish: string): Promise<FileDiff[]>;
@@ -1,95 +0,0 @@
1
- import simpleGit from 'simple-git';
2
- import { validateDiffArguments, createCommitRangeString } from '../cli/utils.js';
3
- export async function loadGitDiff(targetCommitish, baseCommitish) {
4
- // Validate arguments
5
- const validation = validateDiffArguments(targetCommitish, baseCommitish);
6
- if (!validation.valid) {
7
- throw new Error(validation.error);
8
- }
9
- const git = simpleGit();
10
- let diff;
11
- // Handle target special chars (base is always a regular commit)
12
- if (targetCommitish === 'working') {
13
- // Show unstaged changes (working vs staged)
14
- diff = await git.diff(['--name-status']);
15
- }
16
- else if (targetCommitish === 'staged') {
17
- // Show staged changes against base commit
18
- diff = await git.diff(['--cached', baseCommitish, '--name-status']);
19
- }
20
- else if (targetCommitish === '.') {
21
- // Show all uncommitted changes against base commit
22
- diff = await git.diff([baseCommitish, '--name-status']);
23
- }
24
- else {
25
- // Both are regular commits: standard commit-to-commit comparison
26
- diff = await git.diff([
27
- createCommitRangeString(baseCommitish, targetCommitish),
28
- '--name-status',
29
- ]);
30
- if (!diff.trim()) {
31
- // Try without parent (for initial commit)
32
- const diffInitial = await git.diff([targetCommitish, '--name-status']);
33
- if (!diffInitial.trim()) {
34
- throw new Error('No changes found in this commit');
35
- }
36
- diff = diffInitial;
37
- }
38
- }
39
- const fileChanges = diff
40
- .split('\n')
41
- .filter((line) => line.trim())
42
- .map((line) => {
43
- const [status, ...pathParts] = line.split('\t');
44
- const path = pathParts.join('\t');
45
- return { status, path };
46
- });
47
- // Get diff for each file individually
48
- const fileDiffs = await Promise.all(fileChanges.map(async ({ status, path }) => {
49
- let fileDiff = '';
50
- // Handle individual file diffs (base is always a regular commit)
51
- if (targetCommitish === 'working') {
52
- // Show unstaged changes (working vs staged)
53
- fileDiff = await git.diff(['--', path]);
54
- }
55
- else if (targetCommitish === 'staged') {
56
- // Show staged changes against base commit
57
- fileDiff = await git.diff(['--cached', baseCommitish, '--', path]);
58
- }
59
- else if (targetCommitish === '.') {
60
- // Show all uncommitted changes against base commit
61
- fileDiff = await git.diff([baseCommitish, '--', path]);
62
- }
63
- else {
64
- try {
65
- // Both are regular commits: standard commit-to-commit comparison
66
- fileDiff = await git.diff([
67
- createCommitRangeString(baseCommitish, targetCommitish),
68
- '--',
69
- path,
70
- ]);
71
- }
72
- catch {
73
- // For new files or if parent doesn't exist
74
- fileDiff = await git.diff([targetCommitish, '--', path]);
75
- }
76
- }
77
- const lines = fileDiff.split('\n');
78
- let additions = 0;
79
- let deletions = 0;
80
- lines.forEach((line) => {
81
- if (line.startsWith('+') && !line.startsWith('+++'))
82
- additions++;
83
- if (line.startsWith('-') && !line.startsWith('---'))
84
- deletions++;
85
- });
86
- return {
87
- path,
88
- status: status,
89
- diff: fileDiff,
90
- additions,
91
- deletions,
92
- };
93
- }));
94
- return fileDiffs;
95
- }
@@ -1,10 +0,0 @@
1
- import { DiffResponse } from '../types/diff.js';
2
- export declare class GitDiffParser {
3
- private git;
4
- constructor(repoPath?: string);
5
- parseDiff(commitish: string): Promise<DiffResponse>;
6
- private parseUnifiedDiff;
7
- private parseFileBlock;
8
- private parseChunks;
9
- validateCommit(commitish: string): Promise<boolean>;
10
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,292 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import { GitDiffParser } from './git-diff';
3
- // Mock simple-git
4
- vi.mock('simple-git', () => ({
5
- simpleGit: vi.fn(() => ({
6
- revparse: vi.fn(),
7
- diffSummary: vi.fn(),
8
- diff: vi.fn(),
9
- })),
10
- }));
11
- // Mock child_process
12
- vi.mock('child_process', async (importOriginal) => {
13
- const actual = (await importOriginal());
14
- return {
15
- ...actual,
16
- execSync: vi.fn(),
17
- execFileSync: vi.fn(),
18
- };
19
- });
20
- // Mock fs
21
- vi.mock('fs', async (importOriginal) => {
22
- const actual = (await importOriginal());
23
- return {
24
- ...actual,
25
- readFileSync: vi.fn(),
26
- };
27
- });
28
- describe('GitDiffParser', () => {
29
- let parser;
30
- let mockExecFileSync;
31
- let mockReadFileSync;
32
- beforeEach(async () => {
33
- parser = new GitDiffParser('/test/repo');
34
- vi.clearAllMocks();
35
- // Get mocked functions
36
- const childProcess = await import('child_process');
37
- const fs = await import('fs');
38
- mockExecFileSync = childProcess.execFileSync;
39
- mockReadFileSync = fs.readFileSync;
40
- });
41
- afterEach(() => {
42
- vi.restoreAllMocks();
43
- });
44
- describe('getBlobContent', () => {
45
- it('reads from filesystem for working directory', async () => {
46
- const mockBuffer = Buffer.from('test content');
47
- mockReadFileSync.mockReturnValue(mockBuffer);
48
- const result = await parser.getBlobContent('test.txt', 'working');
49
- expect(mockReadFileSync).toHaveBeenCalledWith('test.txt');
50
- expect(result).toBe(mockBuffer);
51
- });
52
- it('reads from filesystem for "." ref', async () => {
53
- const mockBuffer = Buffer.from('test content');
54
- mockReadFileSync.mockReturnValue(mockBuffer);
55
- const result = await parser.getBlobContent('test.txt', '.');
56
- expect(mockReadFileSync).toHaveBeenCalledWith('test.txt');
57
- expect(result).toBe(mockBuffer);
58
- });
59
- it('uses git show for staged files', async () => {
60
- const mockBuffer = Buffer.from('staged content');
61
- mockExecFileSync.mockReturnValue(mockBuffer);
62
- const result = await parser.getBlobContent('test.txt', 'staged');
63
- expect(mockExecFileSync).toHaveBeenCalledWith('git', ['show', ':test.txt'], {
64
- maxBuffer: 10 * 1024 * 1024,
65
- });
66
- expect(result).toBe(mockBuffer);
67
- });
68
- it('uses git cat-file for git refs', async () => {
69
- const blobHash = 'abc123def456';
70
- const mockBuffer = Buffer.from('git content');
71
- mockExecFileSync
72
- .mockReturnValueOnce(blobHash + '\n') // First call for rev-parse
73
- .mockReturnValueOnce(mockBuffer); // Second call for cat-file
74
- const result = await parser.getBlobContent('test.txt', 'HEAD');
75
- expect(mockExecFileSync).toHaveBeenCalledWith('git', ['rev-parse', 'HEAD:test.txt'], {
76
- encoding: 'utf8',
77
- maxBuffer: 10 * 1024 * 1024,
78
- });
79
- expect(mockExecFileSync).toHaveBeenCalledWith('git', ['cat-file', 'blob', blobHash], {
80
- maxBuffer: 10 * 1024 * 1024,
81
- });
82
- expect(result).toBe(mockBuffer);
83
- });
84
- it('handles file size limit errors', async () => {
85
- const error = new Error('maxBuffer exceeded');
86
- mockExecFileSync.mockImplementation(() => {
87
- throw error;
88
- });
89
- await expect(parser.getBlobContent('large-file.jpg', 'HEAD')).rejects.toThrow('Image file large-file.jpg is too large to display (over 10MB limit)');
90
- });
91
- it('handles ENOBUFS errors', async () => {
92
- const error = new Error('ENOBUFS: buffer overflow');
93
- mockExecFileSync.mockImplementation(() => {
94
- throw error;
95
- });
96
- await expect(parser.getBlobContent('large-file.jpg', 'HEAD')).rejects.toThrow('Image file large-file.jpg is too large to display (over 10MB limit)');
97
- });
98
- it('handles general git errors', async () => {
99
- const error = new Error('fatal: Path does not exist');
100
- mockExecFileSync.mockImplementation(() => {
101
- throw error;
102
- });
103
- await expect(parser.getBlobContent('missing.txt', 'HEAD')).rejects.toThrow('Failed to get blob content for missing.txt at HEAD: fatal: Path does not exist');
104
- });
105
- });
106
- describe('parseFileBlock with binary files', () => {
107
- it('parses added binary file correctly', () => {
108
- const diffLines = [
109
- 'diff --git a/image.jpg b/image.jpg',
110
- 'new file mode 100644',
111
- 'index 0000000..abc123',
112
- '--- /dev/null',
113
- '+++ b/image.jpg',
114
- 'Binary files /dev/null and b/image.jpg differ',
115
- ];
116
- const summary = {
117
- insertions: 0,
118
- deletions: 0,
119
- };
120
- // Access private method for testing
121
- const result = parser.parseFileBlock(diffLines.join('\n'), summary);
122
- expect(result).toEqual({
123
- path: 'image.jpg',
124
- oldPath: undefined,
125
- status: 'added',
126
- additions: 0,
127
- deletions: 0,
128
- chunks: [], // Binary files should have empty chunks
129
- });
130
- });
131
- it('parses deleted binary file correctly', () => {
132
- const diffLines = [
133
- 'diff --git a/old-image.png b/old-image.png',
134
- 'deleted file mode 100644',
135
- 'index abc123..0000000',
136
- '--- a/old-image.png',
137
- '+++ /dev/null',
138
- 'Binary files a/old-image.png and /dev/null differ',
139
- ];
140
- const summary = {
141
- insertions: 0,
142
- deletions: 0,
143
- };
144
- const result = parser.parseFileBlock(diffLines.join('\n'), summary);
145
- expect(result).toEqual({
146
- path: 'old-image.png',
147
- oldPath: undefined,
148
- status: 'deleted',
149
- additions: 0,
150
- deletions: 0,
151
- chunks: [],
152
- });
153
- });
154
- it('parses modified binary file correctly', () => {
155
- const diffLines = [
156
- 'diff --git a/photo.jpg b/photo.jpg',
157
- 'index abc123..def456 100644',
158
- '--- a/photo.jpg',
159
- '+++ b/photo.jpg',
160
- 'Binary files a/photo.jpg and b/photo.jpg differ',
161
- ];
162
- const summary = {
163
- insertions: 0,
164
- deletions: 0,
165
- };
166
- const result = parser.parseFileBlock(diffLines.join('\n'), summary);
167
- expect(result).toEqual({
168
- path: 'photo.jpg',
169
- oldPath: undefined,
170
- status: 'modified',
171
- additions: 0,
172
- deletions: 0,
173
- chunks: [],
174
- });
175
- });
176
- it('parses renamed binary file correctly', () => {
177
- const diffLines = [
178
- 'diff --git a/old-name.gif b/new-name.gif',
179
- 'similarity index 100%',
180
- 'rename from old-name.gif',
181
- 'rename to new-name.gif',
182
- ];
183
- const summary = {
184
- insertions: 0,
185
- deletions: 0,
186
- };
187
- const result = parser.parseFileBlock(diffLines.join('\n'), summary);
188
- expect(result).toEqual({
189
- path: 'new-name.gif',
190
- oldPath: 'old-name.gif',
191
- status: 'renamed',
192
- additions: 0,
193
- deletions: 0,
194
- chunks: [],
195
- });
196
- });
197
- it('handles non-binary files normally', () => {
198
- const diffLines = [
199
- 'diff --git a/script.js b/script.js',
200
- 'index abc123..def456 100644',
201
- '--- a/script.js',
202
- '+++ b/script.js',
203
- '@@ -1,3 +1,4 @@',
204
- ' console.log("hello");',
205
- '+console.log("world");',
206
- ' // end',
207
- ];
208
- const summary = {
209
- insertions: 1,
210
- deletions: 0,
211
- };
212
- const result = parser.parseFileBlock(diffLines.join('\n'), summary);
213
- expect(result).toEqual({
214
- path: 'script.js',
215
- oldPath: undefined,
216
- status: 'added',
217
- additions: 1,
218
- deletions: 0,
219
- chunks: expect.any(Array), // Should have parsed chunks
220
- });
221
- // Verify chunks were parsed
222
- expect(result.chunks).toHaveLength(1);
223
- expect(result.chunks[0].header).toBe('@@ -1,3 +1,4 @@');
224
- });
225
- it('detects added files using /dev/null indicator', () => {
226
- const diffLines = [
227
- 'diff --git a/new-file.txt b/new-file.txt',
228
- 'index 0000000..abc123 100644',
229
- '--- /dev/null',
230
- '+++ b/new-file.txt',
231
- '@@ -0,0 +1,2 @@',
232
- '+line 1',
233
- '+line 2',
234
- ];
235
- const summary = {
236
- insertions: 2,
237
- deletions: 0,
238
- };
239
- const result = parser.parseFileBlock(diffLines.join('\n'), summary);
240
- expect(result.status).toBe('added');
241
- });
242
- it('detects deleted files using /dev/null indicator', () => {
243
- const diffLines = [
244
- 'diff --git a/deleted-file.txt b/deleted-file.txt',
245
- 'index abc123..0000000 100644',
246
- '--- a/deleted-file.txt',
247
- '+++ /dev/null',
248
- '@@ -1,2 +0,0 @@',
249
- '-line 1',
250
- '-line 2',
251
- ];
252
- const summary = {
253
- insertions: 0,
254
- deletions: 2,
255
- };
256
- const result = parser.parseFileBlock(diffLines.join('\n'), summary);
257
- expect(result.status).toBe('deleted');
258
- });
259
- });
260
- describe('File status detection improvements', () => {
261
- it('prioritizes new file mode over other indicators', () => {
262
- const diffLines = [
263
- 'diff --git a/test.txt b/test.txt',
264
- 'new file mode 100644',
265
- 'index 0000000..abc123',
266
- '--- a/test.txt', // This might confuse simple parsers
267
- '+++ b/test.txt',
268
- ];
269
- const summary = {
270
- insertions: 5,
271
- deletions: 0,
272
- };
273
- const result = parser.parseFileBlock(diffLines.join('\n'), summary);
274
- expect(result.status).toBe('added');
275
- });
276
- it('prioritizes deleted file mode over other indicators', () => {
277
- const diffLines = [
278
- 'diff --git a/test.txt b/test.txt',
279
- 'deleted file mode 100644',
280
- 'index abc123..0000000',
281
- '--- a/test.txt',
282
- '+++ b/test.txt', // This might confuse simple parsers
283
- ];
284
- const summary = {
285
- insertions: 0,
286
- deletions: 5,
287
- };
288
- const result = parser.parseFileBlock(diffLines.join('\n'), summary);
289
- expect(result.status).toBe('deleted');
290
- });
291
- });
292
- });
@@ -1,11 +0,0 @@
1
- interface ServerOptions {
2
- commitish: string;
3
- preferredPort?: number;
4
- openBrowser?: boolean;
5
- mode?: string;
6
- }
7
- export declare function startServer(options: ServerOptions): Promise<{
8
- port: number;
9
- url: string;
10
- }>;
11
- export {};
@@ -1 +0,0 @@
1
- export {};