@amirdaraee/namewise 0.6.2 → 0.7.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 (131) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +258 -9
  3. package/dist/cli/apply.d.ts +4 -0
  4. package/dist/cli/apply.d.ts.map +1 -0
  5. package/dist/cli/apply.js +66 -0
  6. package/dist/cli/apply.js.map +1 -0
  7. package/dist/cli/clean-empty.d.ts +4 -0
  8. package/dist/cli/clean-empty.d.ts.map +1 -0
  9. package/dist/cli/clean-empty.js +48 -0
  10. package/dist/cli/clean-empty.js.map +1 -0
  11. package/dist/cli/commands.d.ts.map +1 -1
  12. package/dist/cli/commands.js +299 -14
  13. package/dist/cli/commands.js.map +1 -1
  14. package/dist/cli/config-cmd.d.ts +2 -0
  15. package/dist/cli/config-cmd.d.ts.map +1 -0
  16. package/dist/cli/config-cmd.js +71 -0
  17. package/dist/cli/config-cmd.js.map +1 -0
  18. package/dist/cli/dedup.d.ts +5 -0
  19. package/dist/cli/dedup.d.ts.map +1 -0
  20. package/dist/cli/dedup.js +58 -0
  21. package/dist/cli/dedup.js.map +1 -0
  22. package/dist/cli/diff.d.ts +6 -0
  23. package/dist/cli/diff.d.ts.map +1 -0
  24. package/dist/cli/diff.js +75 -0
  25. package/dist/cli/diff.js.map +1 -0
  26. package/dist/cli/find.d.ts +11 -0
  27. package/dist/cli/find.d.ts.map +1 -0
  28. package/dist/cli/find.js +63 -0
  29. package/dist/cli/find.js.map +1 -0
  30. package/dist/cli/flatten.d.ts +4 -0
  31. package/dist/cli/flatten.d.ts.map +1 -0
  32. package/dist/cli/flatten.js +79 -0
  33. package/dist/cli/flatten.js.map +1 -0
  34. package/dist/cli/info.d.ts +2 -0
  35. package/dist/cli/info.d.ts.map +1 -0
  36. package/dist/cli/info.js +65 -0
  37. package/dist/cli/info.js.map +1 -0
  38. package/dist/cli/init.d.ts +2 -0
  39. package/dist/cli/init.d.ts.map +1 -0
  40. package/dist/cli/init.js +139 -0
  41. package/dist/cli/init.js.map +1 -0
  42. package/dist/cli/organize.d.ts +7 -0
  43. package/dist/cli/organize.d.ts.map +1 -0
  44. package/dist/cli/organize.js +39 -0
  45. package/dist/cli/organize.js.map +1 -0
  46. package/dist/cli/rename.d.ts +12 -1
  47. package/dist/cli/rename.d.ts.map +1 -1
  48. package/dist/cli/rename.js +143 -14
  49. package/dist/cli/rename.js.map +1 -1
  50. package/dist/cli/sanitize.d.ts +7 -0
  51. package/dist/cli/sanitize.d.ts.map +1 -0
  52. package/dist/cli/sanitize.js +49 -0
  53. package/dist/cli/sanitize.js.map +1 -0
  54. package/dist/cli/stats.d.ts +4 -0
  55. package/dist/cli/stats.d.ts.map +1 -0
  56. package/dist/cli/stats.js +35 -0
  57. package/dist/cli/stats.js.map +1 -0
  58. package/dist/cli/tree.d.ts +4 -0
  59. package/dist/cli/tree.d.ts.map +1 -0
  60. package/dist/cli/tree.js +65 -0
  61. package/dist/cli/tree.js.map +1 -0
  62. package/dist/cli/undo.d.ts +1 -0
  63. package/dist/cli/undo.d.ts.map +1 -1
  64. package/dist/cli/undo.js +40 -2
  65. package/dist/cli/undo.js.map +1 -1
  66. package/dist/cli/watch.d.ts +2 -0
  67. package/dist/cli/watch.d.ts.map +1 -0
  68. package/dist/cli/watch.js +128 -0
  69. package/dist/cli/watch.js.map +1 -0
  70. package/dist/index.js +14 -10
  71. package/dist/index.js.map +1 -1
  72. package/dist/parsers/pdf-parser.js +2 -2
  73. package/dist/parsers/pdf-parser.js.map +1 -1
  74. package/dist/services/claude-service.d.ts +1 -1
  75. package/dist/services/claude-service.d.ts.map +1 -1
  76. package/dist/services/claude-service.js +5 -3
  77. package/dist/services/claude-service.js.map +1 -1
  78. package/dist/services/file-renamer.d.ts +1 -0
  79. package/dist/services/file-renamer.d.ts.map +1 -1
  80. package/dist/services/file-renamer.js +17 -5
  81. package/dist/services/file-renamer.js.map +1 -1
  82. package/dist/services/lmstudio-service.d.ts +1 -1
  83. package/dist/services/lmstudio-service.d.ts.map +1 -1
  84. package/dist/services/lmstudio-service.js +6 -5
  85. package/dist/services/lmstudio-service.js.map +1 -1
  86. package/dist/services/ollama-service.d.ts +1 -1
  87. package/dist/services/ollama-service.d.ts.map +1 -1
  88. package/dist/services/ollama-service.js +6 -5
  89. package/dist/services/ollama-service.js.map +1 -1
  90. package/dist/services/openai-service.d.ts +1 -1
  91. package/dist/services/openai-service.d.ts.map +1 -1
  92. package/dist/services/openai-service.js +5 -3
  93. package/dist/services/openai-service.js.map +1 -1
  94. package/dist/types/index.d.ts +4 -1
  95. package/dist/types/index.d.ts.map +1 -1
  96. package/dist/utils/ai-prompts.d.ts +1 -0
  97. package/dist/utils/ai-prompts.d.ts.map +1 -1
  98. package/dist/utils/ai-prompts.js +3 -2
  99. package/dist/utils/ai-prompts.js.map +1 -1
  100. package/dist/utils/batch-rename.d.ts +8 -0
  101. package/dist/utils/batch-rename.d.ts.map +1 -0
  102. package/dist/utils/batch-rename.js +36 -0
  103. package/dist/utils/batch-rename.js.map +1 -0
  104. package/dist/utils/config-loader.d.ts +3 -0
  105. package/dist/utils/config-loader.d.ts.map +1 -1
  106. package/dist/utils/config-loader.js.map +1 -1
  107. package/dist/utils/dedup.d.ts +3 -0
  108. package/dist/utils/dedup.d.ts.map +1 -0
  109. package/dist/utils/dedup.js +29 -0
  110. package/dist/utils/dedup.js.map +1 -0
  111. package/dist/utils/fs-collect.d.ts +7 -0
  112. package/dist/utils/fs-collect.d.ts.map +1 -0
  113. package/dist/utils/fs-collect.js +28 -0
  114. package/dist/utils/fs-collect.js.map +1 -0
  115. package/dist/utils/organize.d.ts +8 -0
  116. package/dist/utils/organize.d.ts.map +1 -0
  117. package/dist/utils/organize.js +41 -0
  118. package/dist/utils/organize.js.map +1 -0
  119. package/dist/utils/pattern-rename.d.ts +6 -0
  120. package/dist/utils/pattern-rename.d.ts.map +1 -0
  121. package/dist/utils/pattern-rename.js +23 -0
  122. package/dist/utils/pattern-rename.js.map +1 -0
  123. package/dist/utils/sanitizer.d.ts +3 -0
  124. package/dist/utils/sanitizer.d.ts.map +1 -0
  125. package/dist/utils/sanitizer.js +11 -0
  126. package/dist/utils/sanitizer.js.map +1 -0
  127. package/dist/utils/stats.d.ts +16 -0
  128. package/dist/utils/stats.d.ts.map +1 -0
  129. package/dist/utils/stats.js +26 -0
  130. package/dist/utils/stats.js.map +1 -0
  131. package/package.json +2 -1
@@ -1,9 +1,52 @@
1
1
  import { renameFiles } from './rename.js';
2
2
  import { undoRename } from './undo.js';
3
+ import { configCommand } from './config-cmd.js';
4
+ import { sanitizeFiles } from './sanitize.js';
5
+ import { applyPlan } from './apply.js';
6
+ import { dedupFiles } from './dedup.js';
7
+ import { watchDirectory } from './watch.js';
8
+ import { statsCommand } from './stats.js';
9
+ import { treeCommand } from './tree.js';
10
+ import { infoCommand } from './info.js';
11
+ import { organizeFiles } from './organize.js';
12
+ import { flattenDirectory } from './flatten.js';
13
+ import { cleanEmptyDirs } from './clean-empty.js';
14
+ import { findFiles } from './find.js';
15
+ import { diffDirectories } from './diff.js';
16
+ import { initCommand } from './init.js';
3
17
  export function setupCommands(program) {
18
+ program
19
+ .command('init')
20
+ .description('Set up Namewise for the first time (interactive wizard)')
21
+ .addHelpText('after', `
22
+ What init configures:
23
+ Scope — global (~/.namewise.json) or project (.namewise.json)
24
+ Provider — claude | openai | ollama | lmstudio
25
+ API key — stored in config (cloud providers only)
26
+ Base URL — for local providers (ollama / lmstudio)
27
+ Model — override the provider default
28
+ Convention — kebab-case, snake_case, camelCase, etc.
29
+ Language — language for generated filenames (e.g. English, French)
30
+ Dry-run — always preview before renaming by default
31
+ Your name — used in document and photo templates
32
+
33
+ Example:
34
+ namewise init
35
+ # Then run without any flags — saved settings apply automatically:
36
+ namewise rename ./documents
37
+ `)
38
+ .action(async () => {
39
+ try {
40
+ await initCommand();
41
+ }
42
+ catch (error) {
43
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
44
+ process.exit(1);
45
+ }
46
+ });
4
47
  program
5
48
  .command('rename')
6
- .description('🚀 Rename files in a directory based on their content using AI analysis')
49
+ .description('Rename files in a directory based on their content using AI analysis')
7
50
  .argument('[directory]', 'Directory containing files to rename (default: current directory)', '.')
8
51
  .option('-p, --provider <provider>', 'AI provider: claude|openai|ollama|lmstudio (default: claude)')
9
52
  .option('-k, --api-key <key>', 'API key for cloud providers (or set CLAUDE_API_KEY/ANTHROPIC_API_KEY/OPENAI_API_KEY)')
@@ -19,9 +62,19 @@ export function setupCommands(program) {
19
62
  .option('--depth <n>', 'Maximum recursion depth when using --recursive')
20
63
  .option('--concurrency <n>', 'Files to process in parallel (default: 3)')
21
64
  .option('--output <path>', 'Save rename report as JSON to this path')
65
+ .option('--pattern <pattern>', 'Regex rename pattern (s/find/replace/flags or find:replace); repeatable, skips AI', (val, prev) => [...prev, val], [])
66
+ .option('--no-ai', 'Use file metadata instead of AI (no API call required)')
67
+ .option('--sequence', 'Rename files sequentially: 001.ext, 002.ext, … (skips AI)', false)
68
+ .option('--sequence-prefix <prefix>', 'Prefix for sequential rename: prefix-001.ext')
69
+ .option('--prefix <str>', 'Prepend string to all filenames (skips AI)')
70
+ .option('--suffix <str>', 'Append string to all filenames before extension (skips AI)')
71
+ .option('--date-stamp <field>', 'Prepend date to filename: created|modified (skips AI)')
72
+ .option('--strip <pattern>', 'Remove regex pattern from all filenames (skips AI)')
73
+ .option('--truncate <n>', 'Truncate filenames to N characters (skips AI)')
74
+ .option('--language <lang>', 'Language for generated filenames (e.g. English, French, German)')
22
75
  .addHelpText('after', `
23
76
 
24
- 🔍 How it works:
77
+ How it works:
25
78
  1. Loads settings from ~/.namewise.json and <dir>/.namewise.json (CLI flags override)
26
79
  2. Scans directory for supported files (PDF, DOCX, XLSX, TXT, MD, RTF)
27
80
  3. Extracts content and metadata from each file
@@ -31,18 +84,18 @@ export function setupCommands(program) {
31
84
  7. Renames files (or shows preview with --dry-run)
32
85
  8. Saves session to ~/.namewise/history.json for later undo
33
86
 
34
- 💡 Pro Tips:
35
- Always use --dry-run first to preview changes
36
- Use --recursive to process nested folders
37
- Set common options in ~/.namewise.json to avoid repeating flags
38
- Use namewise undo to reverse the last rename session
39
- Set API keys as environment variables: ANTHROPIC_API_KEY or OPENAI_API_KEY
87
+ Pro Tips:
88
+ - Always use --dry-run first to preview changes
89
+ - Use --recursive to process nested folders
90
+ - Run "namewise init" once to save your API key and preferences
91
+ - Use "namewise undo" to reverse the last rename session
92
+ - Set API keys as environment variables: ANTHROPIC_API_KEY or OPENAI_API_KEY
40
93
 
41
- 🖥️ Local LLM Setup:
42
- Ollama: Start with 'ollama serve' (default: http://localhost:11434)
43
- LMStudio: Enable local server mode (default: http://localhost:1234)
94
+ Local LLM Setup:
95
+ Ollama: start with "ollama serve" (default: http://localhost:11434)
96
+ LMStudio: enable local server mode (default: http://localhost:1234)
44
97
 
45
- 📝 Examples:
98
+ Examples:
46
99
  # Current directory (no directory argument needed)
47
100
  namewise rename --dry-run
48
101
  namewise rename --provider claude --template document --name "alice"
@@ -57,21 +110,253 @@ export function setupCommands(program) {
57
110
  namewise rename ./docs --provider claude --template document --name "alice"
58
111
  namewise rename ./media --provider openai --template auto
59
112
 
113
+ # Force output language regardless of document language
114
+ namewise rename ./farsi-docs --language English --dry-run
115
+ namewise rename ./documents --language French
116
+
60
117
  # Local LLMs (no API key needed)
61
118
  namewise rename --provider ollama --model llama3.1 --dry-run
62
119
  namewise rename ./contracts --provider lmstudio --base-url http://localhost:1234
120
+
121
+ Batch Rename (no AI, no API key):
122
+ namewise rename ./photos --sequence --dry-run
123
+ namewise rename ./photos --sequence --sequence-prefix "holiday"
124
+ namewise rename ./exports --prefix "2024-" --dry-run
125
+ namewise rename ./drafts --suffix "-final"
126
+ namewise rename ./docs --date-stamp modified --dry-run
127
+ namewise rename ./downloads --strip "IMG_" --dry-run
128
+ namewise rename ./downloads --truncate 30 --dry-run
63
129
  `)
64
130
  .action(async (directory, options) => {
65
131
  await renameFiles(directory, options);
66
132
  });
133
+ program
134
+ .command('config')
135
+ .description('Manage persistent config in ~/.namewise.json')
136
+ .argument('<subcommand>', 'list | get | set')
137
+ .argument('[key]', 'Config key name')
138
+ .argument('[value]', 'Value to set (for set subcommand)')
139
+ .action(async (subcommand, key, value) => {
140
+ try {
141
+ await configCommand(subcommand, key, value);
142
+ }
143
+ catch (error) {
144
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
145
+ process.exit(1);
146
+ }
147
+ });
148
+ program
149
+ .command('sanitize')
150
+ .description('Clean filenames by removing unsafe characters and applying naming convention')
151
+ .argument('[directory]', 'Directory to sanitize (default: current directory)', '.')
152
+ .option('--dry-run', 'Preview changes without renaming', false)
153
+ .option('-r, --recursive', 'Process subdirectories', false)
154
+ .option('-c, --case <convention>', 'Naming convention: kebab-case|snake_case|camelCase|PascalCase|lowercase|UPPERCASE', 'kebab-case')
155
+ .action(async (directory, options) => {
156
+ try {
157
+ await sanitizeFiles(directory, { dryRun: options.dryRun, recursive: options.recursive, case: options.case });
158
+ }
159
+ catch (error) {
160
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
161
+ process.exit(1);
162
+ }
163
+ });
164
+ program
165
+ .command('apply')
166
+ .description('Apply a saved rename plan produced by --output')
167
+ .argument('<plan>', 'Path to the plan JSON file')
168
+ .option('--dry-run', 'Validate plan without executing renames', false)
169
+ .action(async (planPath, options) => {
170
+ try {
171
+ await applyPlan(planPath, { dryRun: options.dryRun });
172
+ }
173
+ catch (error) {
174
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
175
+ process.exit(1);
176
+ }
177
+ });
178
+ program
179
+ .command('dedup')
180
+ .description('Find and optionally remove duplicate files by content hash')
181
+ .argument('[directory]', 'Directory to scan (default: current directory)', '.')
182
+ .option('-r, --recursive', 'Scan subdirectories', false)
183
+ .option('--delete', 'Delete duplicates after confirmation', false)
184
+ .action(async (directory, options) => {
185
+ try {
186
+ await dedupFiles(directory, { recursive: options.recursive, delete: options.delete });
187
+ }
188
+ catch (error) {
189
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
190
+ process.exit(1);
191
+ }
192
+ });
193
+ program
194
+ .command('watch')
195
+ .description('Watch a directory for new files and rename them automatically using AI')
196
+ .argument('[directory]', 'Directory to watch (default: current directory)', '.')
197
+ .option('-p, --provider <provider>', 'AI provider: claude|openai|ollama|lmstudio (default: claude)')
198
+ .option('-k, --api-key <key>', 'API key for cloud providers (or set CLAUDE_API_KEY/ANTHROPIC_API_KEY/OPENAI_API_KEY)')
199
+ .option('-c, --case <convention>', 'Naming convention: kebab-case|snake_case|camelCase|PascalCase|lowercase|UPPERCASE (default: kebab-case)')
200
+ .option('-t, --template <category>', 'File category: document|movie|music|series|photo|book|general|auto (default: general)')
201
+ .option('-n, --name <personalName>', 'Personal name for document/photo templates')
202
+ .option('-d, --date <format>', 'Date format: YYYY-MM-DD|YYYY|YYYYMMDD|none (default: none)')
203
+ .option('--dry-run', 'Preview changes without renaming files', false)
204
+ .option('--max-size <size>', 'Maximum file size in MB (default: 10)')
205
+ .option('--base-url <url>', 'Base URL for local LLM providers')
206
+ .option('--model <name>', 'Model name to use (overrides provider default)')
207
+ .option('-r, --recursive', 'Watch subdirectories', false)
208
+ .option('--depth <n>', 'Maximum recursion depth when using --recursive')
209
+ .option('--concurrency <n>', 'Files to process in parallel (default: 1)')
210
+ .option('--output <path>', 'Save rename report as JSON to this path')
211
+ .option('--pattern <pattern>', 'Regex rename pattern (s/find/replace/flags or find:replace); repeatable, skips AI', (val, prev) => [...prev, val], [])
212
+ .option('--no-ai', 'Use file metadata instead of AI (no API call required)')
213
+ .action(async (directory, options) => {
214
+ try {
215
+ await watchDirectory(directory, options);
216
+ }
217
+ catch (error) {
218
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
219
+ process.exit(1);
220
+ }
221
+ });
67
222
  program
68
223
  .command('undo')
69
- .description('↩️ Undo the most recent rename session')
224
+ .description('Undo the most recent rename session')
70
225
  .argument('[session-id]', 'Session ID to undo (use --list to see IDs)')
71
226
  .option('--list', 'List recent rename sessions with their IDs')
227
+ .option('--all', 'Undo all rename sessions')
72
228
  .action(async (sessionId, options) => {
73
229
  try {
74
- await undoRename(sessionId, { list: options.list });
230
+ await undoRename(sessionId, { list: options.list, all: options.all });
231
+ }
232
+ catch (error) {
233
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
234
+ process.exit(1);
235
+ }
236
+ });
237
+ program
238
+ .command('stats')
239
+ .description('Show storage breakdown by file type')
240
+ .argument('[directory]', 'Directory to analyse (default: current directory)', '.')
241
+ .option('-r, --recursive', 'Include subdirectories', false)
242
+ .action(async (directory, options) => {
243
+ try {
244
+ await statsCommand(directory, { recursive: options.recursive });
245
+ }
246
+ catch (error) {
247
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
248
+ process.exit(1);
249
+ }
250
+ });
251
+ program
252
+ .command('tree')
253
+ .description('Show directory tree with file sizes')
254
+ .argument('[directory]', 'Directory to display (default: current directory)', '.')
255
+ .option('--depth <n>', 'Maximum depth to display')
256
+ .action(async (directory, options) => {
257
+ try {
258
+ await treeCommand(directory, { depth: options.depth ? parseInt(options.depth) : undefined });
259
+ }
260
+ catch (error) {
261
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
262
+ process.exit(1);
263
+ }
264
+ });
265
+ program
266
+ .command('info')
267
+ .description('Show metadata for a file or directory')
268
+ .argument('<path>', 'File or directory path')
269
+ .action(async (targetPath) => {
270
+ try {
271
+ await infoCommand(targetPath);
272
+ }
273
+ catch (error) {
274
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
275
+ process.exit(1);
276
+ }
277
+ });
278
+ program
279
+ .command('organize')
280
+ .description('Move files into subfolders by type, date, or size')
281
+ .argument('[directory]', 'Directory to organise (default: current directory)', '.')
282
+ .option('--by <mode>', 'Organisation mode: ext|date|size (default: ext)', 'ext')
283
+ .option('-r, --recursive', 'Include subdirectories', false)
284
+ .option('--dry-run', 'Preview without moving files', false)
285
+ .action(async (directory, options) => {
286
+ try {
287
+ await organizeFiles(directory, { by: options.by, recursive: options.recursive, dryRun: options.dryRun });
288
+ }
289
+ catch (error) {
290
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
291
+ process.exit(1);
292
+ }
293
+ });
294
+ program
295
+ .command('flatten')
296
+ .description('Move all nested files into the root directory')
297
+ .argument('[directory]', 'Directory to flatten (default: current directory)', '.')
298
+ .option('--dry-run', 'Preview without moving files', false)
299
+ .action(async (directory, options) => {
300
+ try {
301
+ await flattenDirectory(directory, { dryRun: options.dryRun });
302
+ }
303
+ catch (error) {
304
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
305
+ process.exit(1);
306
+ }
307
+ });
308
+ program
309
+ .command('clean-empty')
310
+ .description('Find and remove empty directories')
311
+ .argument('[directory]', 'Directory to scan (default: current directory)', '.')
312
+ .option('--dry-run', 'Preview without deleting', false)
313
+ .action(async (directory, options) => {
314
+ try {
315
+ await cleanEmptyDirs(directory, { dryRun: options.dryRun });
316
+ }
317
+ catch (error) {
318
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
319
+ process.exit(1);
320
+ }
321
+ });
322
+ program
323
+ .command('find')
324
+ .description('Search files by name, extension, size, or date')
325
+ .argument('[directory]', 'Directory to search (default: current directory)', '.')
326
+ .option('--ext <ext>', 'Filter by file extension (e.g. pdf)')
327
+ .option('--name <glob>', 'Filter by filename glob (e.g. "*.report*")')
328
+ .option('--larger-than <size>', 'Minimum size (e.g. 5mb, 100kb)')
329
+ .option('--smaller-than <size>', 'Maximum size (e.g. 10mb)')
330
+ .option('--newer-than <date>', 'Modified after date (YYYY-MM-DD)')
331
+ .option('--older-than <date>', 'Modified before date (YYYY-MM-DD)')
332
+ .option('-r, --recursive', 'Search subdirectories', true)
333
+ .action(async (directory, options) => {
334
+ try {
335
+ await findFiles(directory, {
336
+ ext: options.ext,
337
+ name: options.name,
338
+ largerThan: options.largerThan,
339
+ smallerThan: options.smallerThan,
340
+ newerThan: options.newerThan,
341
+ olderThan: options.olderThan,
342
+ recursive: options.recursive
343
+ });
344
+ }
345
+ catch (error) {
346
+ console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
347
+ process.exit(1);
348
+ }
349
+ });
350
+ program
351
+ .command('diff')
352
+ .description('Compare two directories')
353
+ .argument('<dir1>', 'First directory')
354
+ .argument('<dir2>', 'Second directory')
355
+ .option('--by <mode>', 'Compare by: name|hash (default: name)', 'name')
356
+ .option('-r, --recursive', 'Compare subdirectories', true)
357
+ .action(async (dir1, dir2, options) => {
358
+ try {
359
+ await diffDirectories(dir1, dir2, { by: options.by, recursive: options.recursive });
75
360
  }
76
361
  catch (error) {
77
362
  console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
@@ -1 +1 @@
1
- {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,MAAM,UAAU,aAAa,CAAC,OAAgB;IAC5C,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,yEAAyE,CAAC;SACtF,QAAQ,CAAC,aAAa,EAAE,mEAAmE,EAAE,GAAG,CAAC;SACjG,MAAM,CAAC,2BAA2B,EAAE,8DAA8D,CAAC;SACnG,MAAM,CAAC,qBAAqB,EAAE,sFAAsF,CAAC;SACrH,MAAM,CAAC,yBAAyB,EAAE,yGAAyG,CAAC;SAC5I,MAAM,CAAC,2BAA2B,EAAE,uFAAuF,CAAC;SAC5H,MAAM,CAAC,2BAA2B,EAAE,4CAA4C,CAAC;SACjF,MAAM,CAAC,qBAAqB,EAAE,4DAA4D,CAAC;SAC3F,MAAM,CAAC,WAAW,EAAE,6DAA6D,EAAE,KAAK,CAAC;SACzF,MAAM,CAAC,mBAAmB,EAAE,uCAAuC,CAAC;SACpE,MAAM,CAAC,kBAAkB,EAAE,kCAAkC,CAAC;SAC9D,MAAM,CAAC,gBAAgB,EAAE,gDAAgD,CAAC;SAC1E,MAAM,CAAC,iBAAiB,EAAE,iCAAiC,EAAE,KAAK,CAAC;SACnE,MAAM,CAAC,aAAa,EAAE,gDAAgD,CAAC;SACvE,MAAM,CAAC,mBAAmB,EAAE,2CAA2C,CAAC;SACxE,MAAM,CAAC,iBAAiB,EAAE,yCAAyC,CAAC;SACpE,WAAW,CAAC,OAAO,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyCzB,CAAC;SACG,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;QACnC,MAAM,WAAW,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,yCAAyC,CAAC;SACtD,QAAQ,CAAC,cAAc,EAAE,4CAA4C,CAAC;SACtE,MAAM,CAAC,QAAQ,EAAE,4CAA4C,CAAC;SAC9D,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE;QACnC,IAAI,CAAC;YACH,MAAM,UAAU,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC;YAClF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC,CAAC,CAAC;AACP,CAAC"}
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function configCommand(subcommand: string, key?: string, value?: string): Promise<void>;
2
+ //# sourceMappingURL=config-cmd.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-cmd.d.ts","sourceRoot":"","sources":["../../src/cli/config-cmd.ts"],"names":[],"mappings":"AAiCA,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuCnG"}
@@ -0,0 +1,71 @@
1
+ import { promises as fs } from 'fs';
2
+ import path from 'path';
3
+ import os from 'os';
4
+ const CONFIG_PATH = path.join(os.homedir(), '.namewise.json');
5
+ const VALID_KEYS = new Set([
6
+ 'provider', 'apiKey', 'case', 'template', 'name', 'date',
7
+ 'maxSize', 'model', 'baseUrl', 'concurrency', 'recursive', 'depth', 'output', 'dryRun', 'language'
8
+ ]);
9
+ async function readConfig() {
10
+ try {
11
+ const raw = await fs.readFile(CONFIG_PATH, 'utf-8');
12
+ return JSON.parse(raw);
13
+ }
14
+ catch {
15
+ return {};
16
+ }
17
+ }
18
+ async function writeConfig(config) {
19
+ await fs.mkdir(path.dirname(CONFIG_PATH), { recursive: true });
20
+ await fs.writeFile(CONFIG_PATH, JSON.stringify(config, null, 2), 'utf-8');
21
+ }
22
+ function coerceValue(value) {
23
+ if (value === 'true')
24
+ return true;
25
+ if (value === 'false')
26
+ return false;
27
+ const num = Number(value);
28
+ if (!isNaN(num) && value.trim() !== '')
29
+ return num;
30
+ return value;
31
+ }
32
+ export async function configCommand(subcommand, key, value) {
33
+ if (subcommand === 'list') {
34
+ const config = await readConfig();
35
+ const entries = Object.entries(config);
36
+ if (entries.length === 0) {
37
+ console.log('No config found in ~/.namewise.json');
38
+ return;
39
+ }
40
+ console.log('~/.namewise.json:');
41
+ for (const [k, v] of entries) {
42
+ console.log(` ${k}: ${JSON.stringify(v)}`);
43
+ }
44
+ return;
45
+ }
46
+ if (subcommand === 'get') {
47
+ if (!key)
48
+ throw new Error('Usage: namewise config get <key>');
49
+ if (!VALID_KEYS.has(key)) {
50
+ throw new Error(`Unknown config key: ${key}. Valid keys: ${[...VALID_KEYS].join(', ')}`);
51
+ }
52
+ const config = await readConfig();
53
+ const val = config[key];
54
+ console.log(val !== undefined ? String(val) : '(not set)');
55
+ return;
56
+ }
57
+ if (subcommand === 'set') {
58
+ if (!key || value === undefined)
59
+ throw new Error('Usage: namewise config set <key> <value>');
60
+ if (!VALID_KEYS.has(key)) {
61
+ throw new Error(`Unknown config key: ${key}. Valid keys: ${[...VALID_KEYS].join(', ')}`);
62
+ }
63
+ const config = await readConfig();
64
+ config[key] = coerceValue(value);
65
+ await writeConfig(config);
66
+ console.log(`Set ${key} = ${JSON.stringify(config[key])}`);
67
+ return;
68
+ }
69
+ throw new Error(`Unknown subcommand: ${subcommand}. Use: list, get, set`);
70
+ }
71
+ //# sourceMappingURL=config-cmd.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-cmd.js","sourceRoot":"","sources":["../../src/cli/config-cmd.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ export declare function dedupFiles(directory: string, options?: {
2
+ recursive?: boolean;
3
+ delete?: boolean;
4
+ }): Promise<void>;
5
+ //# sourceMappingURL=dedup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedup.d.ts","sourceRoot":"","sources":["../../src/cli/dedup.ts"],"names":[],"mappings":"AAWA,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACtD,OAAO,CAAC,IAAI,CAAC,CAuDf"}
@@ -0,0 +1,58 @@
1
+ import { promises as fs } from 'fs';
2
+ import path from 'path';
3
+ import inquirer from 'inquirer';
4
+ import { findDuplicates } from '../utils/dedup.js';
5
+ function formatBytes(bytes) {
6
+ if (bytes >= 1024 * 1024)
7
+ return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
8
+ if (bytes >= 1024)
9
+ return `${(bytes / 1024).toFixed(1)} KB`;
10
+ return `${bytes} B`;
11
+ }
12
+ export async function dedupFiles(directory, options = {}) {
13
+ const stats = await fs.stat(directory);
14
+ if (!stats.isDirectory()) {
15
+ throw new Error(`${directory} is not a directory`);
16
+ }
17
+ console.log('Scanning for duplicates...');
18
+ const duplicates = await findDuplicates(directory, options.recursive ?? false);
19
+ if (duplicates.size === 0) {
20
+ console.log('No duplicate files found.');
21
+ return;
22
+ }
23
+ const sortedGroups = [...duplicates.entries()].map(([hash, paths]) => ({ hash, sortedPaths: [...paths].sort() }));
24
+ let totalDuplicates = 0;
25
+ for (const { hash, sortedPaths } of sortedGroups) {
26
+ console.log(`\nDuplicate group (${hash.slice(0, 8)}):`);
27
+ for (let i = 0; i < sortedPaths.length; i++) {
28
+ const p = sortedPaths[i];
29
+ const fileStat = await fs.stat(p);
30
+ const sizeStr = formatBytes(fileStat.size);
31
+ console.log(` ${i === 0 ? '[keep]' : '[dupe]'} ${p} (${sizeStr})`);
32
+ }
33
+ totalDuplicates += sortedPaths.length - 1;
34
+ }
35
+ console.log(`\nFound ${duplicates.size} group(s) with ${totalDuplicates} duplicate(s).`);
36
+ if (!options.delete)
37
+ return;
38
+ const { confirm } = await inquirer.prompt([{
39
+ type: 'confirm',
40
+ name: 'confirm',
41
+ message: `Delete ${totalDuplicates} duplicate(s)? This cannot be undone.`,
42
+ default: false
43
+ }]);
44
+ if (!confirm) {
45
+ console.log('Cancelled.');
46
+ return;
47
+ }
48
+ let deleted = 0;
49
+ for (const { sortedPaths } of sortedGroups) {
50
+ for (const filePath of sortedPaths.slice(1)) {
51
+ await fs.unlink(filePath);
52
+ console.log(`Deleted: ${path.basename(filePath)}`);
53
+ deleted++;
54
+ }
55
+ }
56
+ console.log(`\nDeleted ${deleted} file(s).`);
57
+ }
58
+ //# sourceMappingURL=dedup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedup.js","sourceRoot":"","sources":["../../src/cli/dedup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export interface DiffOptions {
2
+ by?: 'name' | 'hash';
3
+ recursive?: boolean;
4
+ }
5
+ export declare function diffDirectories(dir1: string, dir2: string, options: DiffOptions): Promise<void>;
6
+ //# sourceMappingURL=diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../src/cli/diff.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAuBf"}
@@ -0,0 +1,75 @@
1
+ import { promises as fs } from 'fs';
2
+ import path from 'path';
3
+ import { collectFiles } from '../utils/fs-collect.js';
4
+ import { hashFile } from '../utils/dedup.js';
5
+ export async function diffDirectories(dir1, dir2, options) {
6
+ const s1 = await fs.stat(dir1);
7
+ if (!s1.isDirectory())
8
+ throw new Error(`${dir1} is not a directory`);
9
+ const s2 = await fs.stat(dir2);
10
+ if (!s2.isDirectory())
11
+ throw new Error(`${dir2} is not a directory`);
12
+ const recursive = options.recursive ?? true;
13
+ const byHash = options.by === 'hash';
14
+ const files1 = await collectFiles(dir1, { recursive });
15
+ const files2 = await collectFiles(dir2, { recursive });
16
+ const names1 = new Set(files1.map(f => path.relative(dir1, f)));
17
+ const names2 = new Set(files2.map(f => path.relative(dir2, f)));
18
+ const onlyIn1 = [...names1].filter(n => !names2.has(n));
19
+ const onlyIn2 = [...names2].filter(n => !names1.has(n));
20
+ if (byHash && (onlyIn1.length > 0 || onlyIn2.length > 0)) {
21
+ await diffByHash(dir1, dir2, onlyIn1, onlyIn2);
22
+ }
23
+ else {
24
+ printDiff(dir1, dir2, onlyIn1, onlyIn2, []);
25
+ }
26
+ }
27
+ async function diffByHash(dir1, dir2, onlyIn1, onlyIn2) {
28
+ const hashes1 = new Map(); // hash → rel path in dir1
29
+ const hashes2 = new Map(); // hash → rel path in dir2
30
+ for (const rel of onlyIn1) {
31
+ const h = await hashFile(path.join(dir1, rel));
32
+ hashes1.set(h, rel);
33
+ }
34
+ for (const rel of onlyIn2) {
35
+ const h = await hashFile(path.join(dir2, rel));
36
+ hashes2.set(h, rel);
37
+ }
38
+ const moved = [];
39
+ const stillOnlyIn1 = [];
40
+ const stillOnlyIn2 = new Set(hashes2.keys());
41
+ for (const [hash, rel1] of hashes1) {
42
+ if (hashes2.has(hash)) {
43
+ moved.push({ from: rel1, to: hashes2.get(hash) });
44
+ stillOnlyIn2.delete(hash);
45
+ }
46
+ else {
47
+ stillOnlyIn1.push(rel1);
48
+ }
49
+ }
50
+ printDiff(dir1, dir2, stillOnlyIn1, [...stillOnlyIn2].map(h => hashes2.get(h)), moved);
51
+ }
52
+ function printDiff(dir1, dir2, onlyIn1, onlyIn2, moved) {
53
+ if (onlyIn1.length === 0 && onlyIn2.length === 0 && moved.length === 0) {
54
+ console.log('Directories are identical.');
55
+ return;
56
+ }
57
+ if (onlyIn1.length > 0) {
58
+ console.log(`\nOnly in ${dir1}:`);
59
+ for (const f of onlyIn1)
60
+ console.log(` - ${f}`);
61
+ }
62
+ if (onlyIn2.length > 0) {
63
+ console.log(`\nOnly in ${dir2}:`);
64
+ for (const f of onlyIn2)
65
+ console.log(` + ${f}`);
66
+ }
67
+ if (moved.length > 0) {
68
+ console.log('\nMoved/renamed (same content):');
69
+ for (const { from, to } of moved)
70
+ console.log(` ${from} → ${to}`);
71
+ }
72
+ const total = onlyIn1.length + onlyIn2.length + moved.length;
73
+ console.log(`\n${total} difference(s) found.`);
74
+ }
75
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/cli/diff.ts"],"names":[],"mappings":"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"}