@amirdaraee/namewise 0.5.3 → 0.5.4

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 (68) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/index.js +0 -0
  3. package/package.json +2 -2
  4. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -82
  5. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -61
  6. package/.github/workflows/auto-release.yml +0 -81
  7. package/.github/workflows/build.yml +0 -55
  8. package/.github/workflows/publish.yml +0 -134
  9. package/.github/workflows/test.yml +0 -45
  10. package/eng.traineddata +0 -0
  11. package/src/cli/commands.ts +0 -64
  12. package/src/cli/rename.ts +0 -171
  13. package/src/index.ts +0 -54
  14. package/src/parsers/excel-parser.ts +0 -66
  15. package/src/parsers/factory.ts +0 -38
  16. package/src/parsers/pdf-parser.ts +0 -99
  17. package/src/parsers/text-parser.ts +0 -43
  18. package/src/parsers/word-parser.ts +0 -50
  19. package/src/services/ai-factory.ts +0 -39
  20. package/src/services/claude-service.ts +0 -119
  21. package/src/services/file-renamer.ts +0 -141
  22. package/src/services/lmstudio-service.ts +0 -161
  23. package/src/services/ollama-service.ts +0 -191
  24. package/src/services/openai-service.ts +0 -117
  25. package/src/types/index.ts +0 -76
  26. package/src/types/pdf-extraction.d.ts +0 -7
  27. package/src/utils/ai-prompts.ts +0 -76
  28. package/src/utils/file-templates.ts +0 -275
  29. package/src/utils/naming-conventions.ts +0 -67
  30. package/src/utils/pdf-to-image.ts +0 -137
  31. package/tests/data/console-test-1.txt +0 -1
  32. package/tests/data/console-test-2.txt +0 -1
  33. package/tests/data/console-test-long-filename-for-display-testing.txt +0 -1
  34. package/tests/data/empty-file.txt +0 -0
  35. package/tests/data/failure.txt +0 -1
  36. package/tests/data/file1.txt +0 -1
  37. package/tests/data/file2.txt +0 -1
  38. package/tests/data/much-longer-filename-to-test-clearing.txt +0 -1
  39. package/tests/data/sample-markdown.md +0 -9
  40. package/tests/data/sample-pdf.pdf +0 -0
  41. package/tests/data/sample-text.txt +0 -25
  42. package/tests/data/short.txt +0 -1
  43. package/tests/data/single-file.txt +0 -1
  44. package/tests/data/success.txt +0 -1
  45. package/tests/data/this-is-a-very-long-filename-that-should-be-truncated-for-better-display-purposes.txt +0 -1
  46. package/tests/data/very-long-filename-that-should-be-cleared-properly.txt +0 -1
  47. package/tests/data/x.txt +0 -1
  48. package/tests/integration/ai-prompting.test.ts +0 -386
  49. package/tests/integration/end-to-end.test.ts +0 -209
  50. package/tests/integration/person-name-extraction.test.ts +0 -440
  51. package/tests/integration/workflow.test.ts +0 -336
  52. package/tests/mocks/mock-ai-service.ts +0 -58
  53. package/tests/unit/cli/commands.test.ts +0 -169
  54. package/tests/unit/parsers/factory.test.ts +0 -100
  55. package/tests/unit/parsers/pdf-parser.test.ts +0 -63
  56. package/tests/unit/parsers/text-parser.test.ts +0 -85
  57. package/tests/unit/services/ai-factory.test.ts +0 -85
  58. package/tests/unit/services/claude-service.test.ts +0 -188
  59. package/tests/unit/services/file-renamer.test.ts +0 -514
  60. package/tests/unit/services/lmstudio-service.test.ts +0 -326
  61. package/tests/unit/services/ollama-service.test.ts +0 -264
  62. package/tests/unit/services/openai-service.test.ts +0 -196
  63. package/tests/unit/utils/ai-prompts.test.ts +0 -213
  64. package/tests/unit/utils/file-templates.test.ts +0 -199
  65. package/tests/unit/utils/naming-conventions.test.ts +0 -88
  66. package/tests/unit/utils/pdf-to-image.test.ts +0 -127
  67. package/tsconfig.json +0 -20
  68. package/vitest.config.ts +0 -30
@@ -1,326 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import { LMStudioService } from '../../../src/services/lmstudio-service.js';
3
- import { FileInfo } from '../../../src/types/index.js';
4
-
5
- // Mock fetch globally
6
- const mockFetch = vi.fn();
7
- global.fetch = mockFetch;
8
-
9
- describe('LMStudioService', () => {
10
- let lmstudioService: LMStudioService;
11
-
12
- beforeEach(() => {
13
- lmstudioService = new LMStudioService();
14
- vi.clearAllMocks();
15
- });
16
-
17
- describe('generateFileName()', () => {
18
- it('should generate filename using OpenAI-compatible API', async () => {
19
- const mockResponse = {
20
- choices: [{
21
- message: {
22
- content: 'project-requirements-document',
23
- role: 'assistant'
24
- },
25
- finish_reason: 'stop'
26
- }],
27
- usage: {
28
- prompt_tokens: 50,
29
- completion_tokens: 10,
30
- total_tokens: 60
31
- }
32
- };
33
-
34
- mockFetch.mockResolvedValueOnce({
35
- ok: true,
36
- json: async () => mockResponse
37
- });
38
-
39
- const result = await lmstudioService.generateFileName(
40
- 'This document contains project requirements and specifications.',
41
- 'document.txt',
42
- 'kebab-case',
43
- 'document'
44
- );
45
-
46
- expect(result).toBe('project-requirements-document');
47
- expect(mockFetch).toHaveBeenCalledWith(
48
- 'http://localhost:1234/v1/chat/completions',
49
- expect.objectContaining({
50
- method: 'POST',
51
- headers: { 'Content-Type': 'application/json' },
52
- body: expect.stringContaining('"model":"local-model"')
53
- })
54
- );
55
- });
56
-
57
- it('should include file metadata in the prompt', async () => {
58
- const mockFileInfo: FileInfo = {
59
- path: '/test/document.pdf',
60
- name: 'document.pdf',
61
- extension: '.pdf',
62
- size: 1024,
63
- createdAt: new Date(),
64
- modifiedAt: new Date(),
65
- accessedAt: new Date(),
66
- parentFolder: 'contracts',
67
- folderPath: ['home', 'user', 'contracts'],
68
- documentMetadata: {
69
- title: 'Contract Agreement',
70
- author: 'John Doe',
71
- subject: 'Service Contract'
72
- }
73
- };
74
-
75
- const mockResponse = {
76
- choices: [{
77
- message: {
78
- content: 'service-contract-agreement-john-doe',
79
- role: 'assistant'
80
- },
81
- finish_reason: 'stop'
82
- }]
83
- };
84
-
85
- mockFetch.mockResolvedValueOnce({
86
- ok: true,
87
- json: async () => mockResponse
88
- });
89
-
90
- const result = await lmstudioService.generateFileName(
91
- 'Contract content here...',
92
- 'document.pdf',
93
- 'kebab-case',
94
- 'document',
95
- mockFileInfo
96
- );
97
-
98
- expect(result).toBe('service-contract-agreement-john-doe');
99
-
100
- const fetchCall = mockFetch.mock.calls[0];
101
- const requestBody = JSON.parse(fetchCall[1].body);
102
- const userMessage = requestBody.messages.find((m: any) => m.role === 'user');
103
-
104
- expect(userMessage.content).toContain('- Title: Contract Agreement');
105
- expect(userMessage.content).toContain('- Author: John Doe');
106
- expect(userMessage.content).toContain('- Subject: Service Contract');
107
- expect(userMessage.content).toContain('- Parent folder: contracts');
108
- });
109
-
110
- it('should use proper OpenAI API parameters', async () => {
111
- const mockResponse = {
112
- choices: [{
113
- message: {
114
- content: 'test-filename',
115
- role: 'assistant'
116
- },
117
- finish_reason: 'stop'
118
- }]
119
- };
120
-
121
- mockFetch.mockResolvedValueOnce({
122
- ok: true,
123
- json: async () => mockResponse
124
- });
125
-
126
- await lmstudioService.generateFileName('content', 'file.txt');
127
-
128
- const fetchCall = mockFetch.mock.calls[0];
129
- const requestBody = JSON.parse(fetchCall[1].body);
130
-
131
- expect(requestBody).toMatchObject({
132
- model: 'local-model',
133
- temperature: 0.3,
134
- max_tokens: 100,
135
- stream: false
136
- });
137
- expect(requestBody.messages).toHaveLength(2); // system + user
138
- expect(requestBody.messages[0].role).toBe('system');
139
- expect(requestBody.messages[1].role).toBe('user');
140
- });
141
-
142
- it('should sanitize response content', async () => {
143
- const mockResponse = {
144
- choices: [{
145
- message: {
146
- content: '"Project Report.docx"',
147
- role: 'assistant'
148
- },
149
- finish_reason: 'stop'
150
- }]
151
- };
152
-
153
- mockFetch.mockResolvedValueOnce({
154
- ok: true,
155
- json: async () => mockResponse
156
- });
157
-
158
- const result = await lmstudioService.generateFileName(
159
- 'Report content',
160
- 'report.docx',
161
- 'kebab-case'
162
- );
163
-
164
- expect(result).toBe('project-report'); // Should remove quotes and extension
165
- });
166
-
167
- it('should handle API errors', async () => {
168
- mockFetch.mockResolvedValueOnce({
169
- ok: false,
170
- status: 500,
171
- statusText: 'Internal Server Error',
172
- text: async () => 'Server error'
173
- });
174
-
175
- await expect(
176
- lmstudioService.generateFileName('content', 'file.txt')
177
- ).rejects.toThrow('LMStudio service failed');
178
- });
179
-
180
- it('should handle network errors', async () => {
181
- mockFetch.mockRejectedValueOnce(new Error('Network error'));
182
-
183
- await expect(
184
- lmstudioService.generateFileName('content', 'file.txt')
185
- ).rejects.toThrow('LMStudio service failed');
186
- });
187
-
188
- it('should handle empty response', async () => {
189
- const mockResponse = {
190
- choices: [{
191
- message: {
192
- content: '',
193
- role: 'assistant'
194
- },
195
- finish_reason: 'stop'
196
- }]
197
- };
198
-
199
- mockFetch.mockResolvedValueOnce({
200
- ok: true,
201
- json: async () => mockResponse
202
- });
203
-
204
- await expect(
205
- lmstudioService.generateFileName('content', 'file.txt')
206
- ).rejects.toThrow('LMStudio service failed');
207
- });
208
-
209
- it('should handle missing choices in response', async () => {
210
- const mockResponse = {
211
- choices: []
212
- };
213
-
214
- mockFetch.mockResolvedValueOnce({
215
- ok: true,
216
- json: async () => mockResponse
217
- });
218
-
219
- await expect(
220
- lmstudioService.generateFileName('content', 'file.txt')
221
- ).rejects.toThrow('LMStudio service failed');
222
- });
223
-
224
- it('should use custom base URL and model', async () => {
225
- const customService = new LMStudioService('http://custom:8080', 'custom-model');
226
-
227
- const mockResponse = {
228
- choices: [{
229
- message: {
230
- content: 'test-filename',
231
- role: 'assistant'
232
- },
233
- finish_reason: 'stop'
234
- }]
235
- };
236
-
237
- mockFetch.mockResolvedValueOnce({
238
- ok: true,
239
- json: async () => mockResponse
240
- });
241
-
242
- await customService.generateFileName('content', 'file.txt');
243
-
244
- expect(mockFetch).toHaveBeenCalledWith(
245
- 'http://custom:8080/v1/chat/completions',
246
- expect.objectContaining({
247
- body: expect.stringContaining('"model":"custom-model"')
248
- })
249
- );
250
- });
251
- });
252
-
253
- describe('isAvailable()', () => {
254
- it('should return true when service is available', async () => {
255
- mockFetch.mockResolvedValueOnce({
256
- ok: true
257
- });
258
-
259
- const result = await lmstudioService.isAvailable();
260
-
261
- expect(result).toBe(true);
262
- expect(mockFetch).toHaveBeenCalledWith('http://localhost:1234/v1/models');
263
- });
264
-
265
- it('should return false when service is not available', async () => {
266
- mockFetch.mockResolvedValueOnce({
267
- ok: false
268
- });
269
-
270
- const result = await lmstudioService.isAvailable();
271
-
272
- expect(result).toBe(false);
273
- });
274
-
275
- it('should return false on network error', async () => {
276
- mockFetch.mockRejectedValueOnce(new Error('Network error'));
277
-
278
- const result = await lmstudioService.isAvailable();
279
-
280
- expect(result).toBe(false);
281
- });
282
- });
283
-
284
- describe('listModels()', () => {
285
- it('should return list of model IDs', async () => {
286
- const mockResponse = {
287
- data: [
288
- { id: 'local-model-1', object: 'model', created: 123456, owned_by: 'lmstudio' },
289
- { id: 'local-model-2', object: 'model', created: 123457, owned_by: 'lmstudio' },
290
- { id: 'custom-model', object: 'model', created: 123458, owned_by: 'user' }
291
- ]
292
- };
293
-
294
- mockFetch.mockResolvedValueOnce({
295
- ok: true,
296
- json: async () => mockResponse
297
- });
298
-
299
- const result = await lmstudioService.listModels();
300
-
301
- expect(result).toEqual(['local-model-1', 'local-model-2', 'custom-model']);
302
- expect(mockFetch).toHaveBeenCalledWith('http://localhost:1234/v1/models');
303
- });
304
-
305
- it('should return empty array on error', async () => {
306
- mockFetch.mockResolvedValueOnce({
307
- ok: false
308
- });
309
-
310
- const result = await lmstudioService.listModels();
311
-
312
- expect(result).toEqual([]);
313
- });
314
-
315
- it('should handle malformed response', async () => {
316
- mockFetch.mockResolvedValueOnce({
317
- ok: true,
318
- json: async () => ({ invalid: 'response' })
319
- });
320
-
321
- const result = await lmstudioService.listModels();
322
-
323
- expect(result).toEqual([]);
324
- });
325
- });
326
- });
@@ -1,264 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest';
2
- import { OllamaService } from '../../../src/services/ollama-service.js';
3
- import { FileInfo } from '../../../src/types/index.js';
4
-
5
- // Mock fetch globally
6
- const mockFetch = vi.fn();
7
- global.fetch = mockFetch;
8
-
9
- describe('OllamaService', () => {
10
- let ollamaService: OllamaService;
11
-
12
- beforeEach(() => {
13
- ollamaService = new OllamaService();
14
- vi.clearAllMocks();
15
- });
16
-
17
- describe('generateFileName()', () => {
18
- it('should generate filename using Ollama chat API', async () => {
19
- const mockResponse = {
20
- message: {
21
- content: 'project-requirements-document',
22
- role: 'assistant'
23
- },
24
- done: true
25
- };
26
-
27
- mockFetch.mockResolvedValueOnce({
28
- ok: true,
29
- json: async () => mockResponse
30
- });
31
-
32
- const result = await ollamaService.generateFileName(
33
- 'This document contains project requirements and specifications.',
34
- 'document.txt',
35
- 'kebab-case',
36
- 'document'
37
- );
38
-
39
- expect(result).toBe('project-requirements-document');
40
- expect(mockFetch).toHaveBeenCalledWith(
41
- 'http://localhost:11434/api/chat',
42
- expect.objectContaining({
43
- method: 'POST',
44
- headers: { 'Content-Type': 'application/json' },
45
- body: expect.stringContaining('"model":"llama3.1"')
46
- })
47
- );
48
- });
49
-
50
- it('should include file metadata in the prompt', async () => {
51
- const mockFileInfo: FileInfo = {
52
- path: '/test/document.pdf',
53
- name: 'document.pdf',
54
- extension: '.pdf',
55
- size: 1024,
56
- createdAt: new Date(),
57
- modifiedAt: new Date(),
58
- accessedAt: new Date(),
59
- parentFolder: 'contracts',
60
- folderPath: ['home', 'user', 'contracts'],
61
- documentMetadata: {
62
- title: 'Contract Agreement',
63
- author: 'John Doe',
64
- subject: 'Service Contract'
65
- }
66
- };
67
-
68
- const mockResponse = {
69
- message: {
70
- content: 'service-contract-agreement-john-doe',
71
- role: 'assistant'
72
- },
73
- done: true
74
- };
75
-
76
- mockFetch.mockResolvedValueOnce({
77
- ok: true,
78
- json: async () => mockResponse
79
- });
80
-
81
- const result = await ollamaService.generateFileName(
82
- 'Contract content here...',
83
- 'document.pdf',
84
- 'kebab-case',
85
- 'document',
86
- mockFileInfo
87
- );
88
-
89
- expect(result).toBe('service-contract-agreement-john-doe');
90
-
91
- const fetchCall = mockFetch.mock.calls[0];
92
- const requestBody = JSON.parse(fetchCall[1].body);
93
- const userMessage = requestBody.messages.find((m: any) => m.role === 'user');
94
-
95
- expect(userMessage.content).toContain('- Title: Contract Agreement');
96
- expect(userMessage.content).toContain('- Author: John Doe');
97
- expect(userMessage.content).toContain('- Subject: Service Contract');
98
- expect(userMessage.content).toContain('- Parent folder: contracts');
99
- });
100
-
101
- it('should sanitize response content', async () => {
102
- const mockResponse = {
103
- message: {
104
- content: '"Project Report.docx"',
105
- role: 'assistant'
106
- },
107
- done: true
108
- };
109
-
110
- mockFetch.mockResolvedValueOnce({
111
- ok: true,
112
- json: async () => mockResponse
113
- });
114
-
115
- const result = await ollamaService.generateFileName(
116
- 'Report content',
117
- 'report.docx',
118
- 'kebab-case'
119
- );
120
-
121
- expect(result).toBe('project-report'); // Should remove quotes and extension
122
- });
123
-
124
- it('should handle API errors', async () => {
125
- mockFetch.mockResolvedValueOnce({
126
- ok: false,
127
- status: 500,
128
- statusText: 'Internal Server Error',
129
- text: async () => 'Server error'
130
- });
131
-
132
- await expect(
133
- ollamaService.generateFileName('content', 'file.txt')
134
- ).rejects.toThrow('Ollama service failed');
135
- });
136
-
137
- it('should handle network errors', async () => {
138
- mockFetch.mockRejectedValueOnce(new Error('Network error'));
139
-
140
- await expect(
141
- ollamaService.generateFileName('content', 'file.txt')
142
- ).rejects.toThrow('Ollama service failed');
143
- });
144
-
145
- it('should handle empty response', async () => {
146
- const mockResponse = {
147
- message: {
148
- content: '',
149
- role: 'assistant'
150
- },
151
- done: true
152
- };
153
-
154
- mockFetch.mockResolvedValueOnce({
155
- ok: true,
156
- json: async () => mockResponse
157
- });
158
-
159
- await expect(
160
- ollamaService.generateFileName('content', 'file.txt')
161
- ).rejects.toThrow('Ollama service failed');
162
- });
163
-
164
- it('should use custom base URL and model', async () => {
165
- const customService = new OllamaService('http://custom:8080', 'custom-model');
166
-
167
- const mockResponse = {
168
- message: {
169
- content: 'test-filename',
170
- role: 'assistant'
171
- },
172
- done: true
173
- };
174
-
175
- mockFetch.mockResolvedValueOnce({
176
- ok: true,
177
- json: async () => mockResponse
178
- });
179
-
180
- await customService.generateFileName('content', 'file.txt');
181
-
182
- expect(mockFetch).toHaveBeenCalledWith(
183
- 'http://custom:8080/api/chat',
184
- expect.objectContaining({
185
- body: expect.stringContaining('"model":"custom-model"')
186
- })
187
- );
188
- });
189
- });
190
-
191
- describe('isAvailable()', () => {
192
- it('should return true when service is available', async () => {
193
- mockFetch.mockResolvedValueOnce({
194
- ok: true
195
- });
196
-
197
- const result = await ollamaService.isAvailable();
198
-
199
- expect(result).toBe(true);
200
- expect(mockFetch).toHaveBeenCalledWith('http://localhost:11434/api/tags');
201
- });
202
-
203
- it('should return false when service is not available', async () => {
204
- mockFetch.mockResolvedValueOnce({
205
- ok: false
206
- });
207
-
208
- const result = await ollamaService.isAvailable();
209
-
210
- expect(result).toBe(false);
211
- });
212
-
213
- it('should return false on network error', async () => {
214
- mockFetch.mockRejectedValueOnce(new Error('Network error'));
215
-
216
- const result = await ollamaService.isAvailable();
217
-
218
- expect(result).toBe(false);
219
- });
220
- });
221
-
222
- describe('listModels()', () => {
223
- it('should return list of model names', async () => {
224
- const mockResponse = {
225
- models: [
226
- { name: 'llama3.1' },
227
- { name: 'codellama' },
228
- { name: 'mistral' }
229
- ]
230
- };
231
-
232
- mockFetch.mockResolvedValueOnce({
233
- ok: true,
234
- json: async () => mockResponse
235
- });
236
-
237
- const result = await ollamaService.listModels();
238
-
239
- expect(result).toEqual(['llama3.1', 'codellama', 'mistral']);
240
- expect(mockFetch).toHaveBeenCalledWith('http://localhost:11434/api/tags');
241
- });
242
-
243
- it('should return empty array on error', async () => {
244
- mockFetch.mockResolvedValueOnce({
245
- ok: false
246
- });
247
-
248
- const result = await ollamaService.listModels();
249
-
250
- expect(result).toEqual([]);
251
- });
252
-
253
- it('should handle malformed response', async () => {
254
- mockFetch.mockResolvedValueOnce({
255
- ok: true,
256
- json: async () => ({ invalid: 'response' })
257
- });
258
-
259
- const result = await ollamaService.listModels();
260
-
261
- expect(result).toEqual([]);
262
- });
263
- });
264
- });