@amirdaraee/namewise 0.8.0 → 0.10.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 (123) hide show
  1. package/.claude/agents/test-writer.md +39 -0
  2. package/.claude/settings.json +41 -0
  3. package/.claude/skills/new-command/SKILL.md +77 -0
  4. package/.claude/skills/release/SKILL.md +48 -0
  5. package/CHANGELOG.md +46 -0
  6. package/README.md +86 -21
  7. package/dist/cli/apply.d.ts.map +1 -1
  8. package/dist/cli/apply.js +10 -4
  9. package/dist/cli/apply.js.map +1 -1
  10. package/dist/cli/clean-empty.d.ts.map +1 -1
  11. package/dist/cli/clean-empty.js +9 -3
  12. package/dist/cli/clean-empty.js.map +1 -1
  13. package/dist/cli/commands.d.ts.map +1 -1
  14. package/dist/cli/commands.js +54 -32
  15. package/dist/cli/commands.js.map +1 -1
  16. package/dist/cli/config-cmd.d.ts.map +1 -1
  17. package/dist/cli/config-cmd.js +6 -5
  18. package/dist/cli/config-cmd.js.map +1 -1
  19. package/dist/cli/dedup.d.ts.map +1 -1
  20. package/dist/cli/dedup.js +8 -7
  21. package/dist/cli/dedup.js.map +1 -1
  22. package/dist/cli/diff.d.ts.map +1 -1
  23. package/dist/cli/diff.js +9 -8
  24. package/dist/cli/diff.js.map +1 -1
  25. package/dist/cli/find.d.ts.map +1 -1
  26. package/dist/cli/find.js +3 -2
  27. package/dist/cli/find.js.map +1 -1
  28. package/dist/cli/flatten.d.ts.map +1 -1
  29. package/dist/cli/flatten.js +9 -3
  30. package/dist/cli/flatten.js.map +1 -1
  31. package/dist/cli/info.d.ts.map +1 -1
  32. package/dist/cli/info.js +3 -2
  33. package/dist/cli/info.js.map +1 -1
  34. package/dist/cli/init.d.ts.map +1 -1
  35. package/dist/cli/init.js +8 -7
  36. package/dist/cli/init.js.map +1 -1
  37. package/dist/cli/organize.d.ts.map +1 -1
  38. package/dist/cli/organize.js +9 -3
  39. package/dist/cli/organize.js.map +1 -1
  40. package/dist/cli/rename.d.ts.map +1 -1
  41. package/dist/cli/rename.js +129 -61
  42. package/dist/cli/rename.js.map +1 -1
  43. package/dist/cli/sanitize.d.ts.map +1 -1
  44. package/dist/cli/sanitize.js +9 -3
  45. package/dist/cli/sanitize.js.map +1 -1
  46. package/dist/cli/stats.d.ts.map +1 -1
  47. package/dist/cli/stats.js +6 -5
  48. package/dist/cli/stats.js.map +1 -1
  49. package/dist/cli/tree.d.ts.map +1 -1
  50. package/dist/cli/tree.js +2 -1
  51. package/dist/cli/tree.js.map +1 -1
  52. package/dist/cli/undo.d.ts.map +1 -1
  53. package/dist/cli/undo.js +13 -12
  54. package/dist/cli/undo.js.map +1 -1
  55. package/dist/cli/watch.d.ts.map +1 -1
  56. package/dist/cli/watch.js +7 -6
  57. package/dist/cli/watch.js.map +1 -1
  58. package/dist/errors.d.ts +35 -0
  59. package/dist/errors.d.ts.map +1 -0
  60. package/dist/errors.js +75 -0
  61. package/dist/errors.js.map +1 -0
  62. package/dist/index.js +3 -1
  63. package/dist/index.js.map +1 -1
  64. package/dist/parsers/excel-parser.d.ts.map +1 -1
  65. package/dist/parsers/excel-parser.js +5 -1
  66. package/dist/parsers/excel-parser.js.map +1 -1
  67. package/dist/parsers/factory.d.ts +1 -1
  68. package/dist/parsers/factory.d.ts.map +1 -1
  69. package/dist/parsers/factory.js +1 -1
  70. package/dist/parsers/factory.js.map +1 -1
  71. package/dist/parsers/pdf-parser.d.ts.map +1 -1
  72. package/dist/parsers/pdf-parser.js +35 -30
  73. package/dist/parsers/pdf-parser.js.map +1 -1
  74. package/dist/parsers/text-parser.d.ts.map +1 -1
  75. package/dist/parsers/text-parser.js +5 -1
  76. package/dist/parsers/text-parser.js.map +1 -1
  77. package/dist/parsers/word-parser.d.ts.map +1 -1
  78. package/dist/parsers/word-parser.js +5 -1
  79. package/dist/parsers/word-parser.js.map +1 -1
  80. package/dist/services/ai-factory.d.ts.map +1 -1
  81. package/dist/services/ai-factory.js +4 -3
  82. package/dist/services/ai-factory.js.map +1 -1
  83. package/dist/services/claude-service.d.ts.map +1 -1
  84. package/dist/services/claude-service.js +14 -3
  85. package/dist/services/claude-service.js.map +1 -1
  86. package/dist/services/file-renamer.d.ts +1 -1
  87. package/dist/services/file-renamer.d.ts.map +1 -1
  88. package/dist/services/file-renamer.js +13 -32
  89. package/dist/services/file-renamer.js.map +1 -1
  90. package/dist/services/lmstudio-service.d.ts.map +1 -1
  91. package/dist/services/lmstudio-service.js +15 -7
  92. package/dist/services/lmstudio-service.js.map +1 -1
  93. package/dist/services/ollama-service.d.ts.map +1 -1
  94. package/dist/services/ollama-service.js +15 -7
  95. package/dist/services/ollama-service.js.map +1 -1
  96. package/dist/services/openai-service.d.ts.map +1 -1
  97. package/dist/services/openai-service.js +14 -3
  98. package/dist/services/openai-service.js.map +1 -1
  99. package/dist/utils/ai-prompts.d.ts.map +1 -1
  100. package/dist/utils/ai-prompts.js +2 -0
  101. package/dist/utils/ai-prompts.js.map +1 -1
  102. package/dist/utils/config-loader.d.ts +1 -0
  103. package/dist/utils/config-loader.d.ts.map +1 -1
  104. package/dist/utils/config-loader.js +1 -1
  105. package/dist/utils/config-loader.js.map +1 -1
  106. package/dist/utils/file-templates.js +1 -1
  107. package/dist/utils/file-templates.js.map +1 -1
  108. package/dist/utils/logger.d.ts +30 -0
  109. package/dist/utils/logger.d.ts.map +1 -0
  110. package/dist/utils/logger.js +99 -0
  111. package/dist/utils/logger.js.map +1 -0
  112. package/dist/utils/pdf-to-image.d.ts.map +1 -1
  113. package/dist/utils/pdf-to-image.js +1 -7
  114. package/dist/utils/pdf-to-image.js.map +1 -1
  115. package/dist/utils/sanitizer.d.ts.map +1 -1
  116. package/dist/utils/sanitizer.js +1 -0
  117. package/dist/utils/sanitizer.js.map +1 -1
  118. package/dist/utils/ui.d.ts +35 -0
  119. package/dist/utils/ui.d.ts.map +1 -0
  120. package/dist/utils/ui.js +125 -0
  121. package/dist/utils/ui.js.map +1 -0
  122. package/eslint.config.js +27 -0
  123. package/package.json +9 -1
@@ -0,0 +1,39 @@
1
+ ---
2
+ name: test-writer
3
+ description: Writes Vitest unit and integration tests for namewise following the project's established mocking conventions. Use proactively after adding or changing CLI commands, parsers, services, or utils, to keep coverage at 100%.
4
+ tools: Read, Glob, Grep, Bash, Write, Edit
5
+ ---
6
+
7
+ You are a test author for namewise, a TypeScript ESM CLI tool tested with Vitest. Your job is to write or extend tests so that coverage stays at 100% across statements, branches, functions, and lines (`npm run test:coverage` enforces 80% thresholds, but the project standard is 100%).
8
+
9
+ ## Project test conventions (follow exactly)
10
+
11
+ - Unit tests live in `tests/unit/<area>/<file>.test.ts`, mirroring `src/<area>/<file>.ts`. Integration tests live in `tests/integration/` and use the harness in `tests/integration/helpers/harness.ts`; fixtures are generated by `tests/integration/helpers/generate-fixtures.ts` (wired as Vitest `globalSetup`).
12
+ - Vitest globals are enabled in the config, but the convention is to import explicitly anyway: `import { describe, it, expect, vi, beforeEach } from 'vitest';`.
13
+ - ESM imports from source require the `.js` suffix: `import { x } from '../../../src/cli/x.js';`.
14
+ - Mock `fs` before importing the module under test:
15
+
16
+ ```ts
17
+ vi.mock('fs', async () => {
18
+ const actual = await vi.importActual('fs');
19
+ return {
20
+ ...actual,
21
+ promises: { ...(actual as any).promises, stat: vi.fn(), readdir: vi.fn() }
22
+ };
23
+ });
24
+ ```
25
+
26
+ - `beforeEach`: `vi.clearAllMocks()` then re-prime default happy-path mock returns (e.g. `vi.mocked(fs.stat).mockResolvedValue({ isDirectory: () => true } as any)`).
27
+ - Assert CLI output by spying: `const spy = vi.spyOn(console, 'log').mockImplementation(() => {});` then join `spy.mock.calls.map(c => c[0])` and use `toContain`. Always `spy.mockRestore()`.
28
+ - AI services (`ClaudeService`, `OpenAIService`, `OllamaService`, `LMStudioService`) are always mocked - tests must never make network calls.
29
+ - For dry-run-capable commands, always include both: dry-run makes no filesystem mutation; real run does.
30
+
31
+ ## Workflow
32
+
33
+ 1. Read the source file under test fully; enumerate every branch (error paths, empty inputs, option combinations).
34
+ 2. Read the nearest existing test file for that area and match its style precisely.
35
+ 3. Write the tests.
36
+ 4. Run `npx vitest run <test-file>` until green, then `npm run test:coverage` and confirm the changed file shows 100%.
37
+ 5. Report which branches are covered and any source lines that are unreachable/untestable.
38
+
39
+ Never modify source files to make tests pass unless you found a genuine bug - report bugs instead.
@@ -0,0 +1,41 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/claude-code-settings.json",
3
+ "permissions": {
4
+ "allow": [
5
+ "Bash(npm run:*)",
6
+ "Bash(npm test:*)",
7
+ "Bash(npx vitest:*)",
8
+ "Bash(npx tsc:*)",
9
+ "Bash(node:*)",
10
+ "Bash(git status:*)",
11
+ "Bash(git diff:*)",
12
+ "Bash(git log:*)"
13
+ ]
14
+ },
15
+ "hooks": {
16
+ "PreToolUse": [
17
+ {
18
+ "matcher": "Edit|Write",
19
+ "hooks": [
20
+ {
21
+ "type": "command",
22
+ "command": "jq -r '.tool_input.file_path // empty' | { read -r f; case \"$f\" in *package-lock.json|*/dist/*) echo \"Blocked: $f is generated (lockfile/build output) - edit package.json or source instead\" >&2; exit 2 ;; esac; }"
23
+ }
24
+ ]
25
+ }
26
+ ],
27
+ "PostToolUse": [
28
+ {
29
+ "matcher": "Edit|Write",
30
+ "hooks": [
31
+ {
32
+ "type": "command",
33
+ "command": "jq -r '.tool_input.file_path // empty' | { read -r f; case \"$f\" in *.ts) out=$(npx tsc --noEmit 2>&1) || { echo \"$out\" | head -30 >&2; exit 2; } ;; esac; }",
34
+ "timeout": 120,
35
+ "statusMessage": "Type-checking with tsc..."
36
+ }
37
+ ]
38
+ }
39
+ ]
40
+ }
41
+ }
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: new-command
3
+ description: Scaffold a new namewise CLI subcommand following the project's established pattern - implementation file in src/cli/, registration in commands.ts, and unit tests with 100% coverage. Use when adding any new subcommand to the CLI.
4
+ ---
5
+
6
+ # Add a New CLI Subcommand
7
+
8
+ Namewise subcommands follow a strict three-file pattern. Follow every step; coverage thresholds fail CI if tests are skipped.
9
+
10
+ ## 1. Implementation: `src/cli/<kebab-name>.ts`
11
+
12
+ - Export one async function named in camelCase (e.g. `cleanEmptyDirs` for `clean-empty`).
13
+ - Signature: `(directory: string, options: { ... } = {}): Promise<void>`.
14
+ - Use `* as ui from '../utils/ui.js'` for output (`ui.info`, `ui.success`, `ui.dim`, `ui.warn`) - never raw `console.log`.
15
+ - Validate the directory first: `const stat = await fs.stat(directory); if (!stat.isDirectory()) throw new Error(...)`.
16
+ - Support `dryRun` if the command mutates the filesystem: print `[dry-run]`-prefixed lines via `ui.dim` and skip the mutation.
17
+ - ESM project: all relative imports MUST end in `.js` even though sources are `.ts`.
18
+ - Throw `NamewiseError` (from `src/errors.ts`) for user-facing failures with guidance; plain `Error` is acceptable for simple validation.
19
+
20
+ Reference example: `src/cli/clean-empty.ts` (68 lines, the cleanest template).
21
+
22
+ ## 2. Registration: `src/cli/commands.ts`
23
+
24
+ Inside `setupCommands(program)`:
25
+
26
+ ```ts
27
+ import { myNewCommand } from './my-new-command.js';
28
+
29
+ program
30
+ .command('my-new-command')
31
+ .description('One-line description')
32
+ .argument('[directory]', 'Directory to scan (default: current directory)', '.')
33
+ .option('--dry-run', 'Preview without changing anything', false)
34
+ .action(async (directory, options) => {
35
+ const log = createLogger('my-new-command', program.opts().log ?? false);
36
+ try { await myNewCommand(directory, { dryRun: options.dryRun }); }
37
+ catch (error) { handleCliError(error, log); }
38
+ });
39
+ ```
40
+
41
+ Every command uses this exact `createLogger` + `try/catch handleCliError` wrapper - do not deviate.
42
+
43
+ ## 3. Tests: `tests/unit/cli/<kebab-name>.test.ts`
44
+
45
+ Conventions (see `tests/unit/cli/clean-empty.test.ts`):
46
+
47
+ - Mock `fs` BEFORE importing the module under test:
48
+
49
+ ```ts
50
+ vi.mock('fs', async () => {
51
+ const actual = await vi.importActual('fs');
52
+ return {
53
+ ...actual,
54
+ promises: { ...(actual as any).promises, stat: vi.fn(), readdir: vi.fn() }
55
+ };
56
+ });
57
+ import { promises as fs } from 'fs';
58
+ import { myNewCommand } from '../../../src/cli/my-new-command.js';
59
+ ```
60
+
61
+ - `beforeEach`: `vi.clearAllMocks()` and re-prime default mock returns.
62
+ - Assert output via `vi.spyOn(console, 'log')` and join the calls; restore the spy after.
63
+ - Cover at minimum: not-a-directory error, empty/no-op case, happy path, dry-run does NOT mutate, real run DOES mutate.
64
+ - Coverage must stay at 100% (statements, branches, functions, lines) - test every branch you add.
65
+
66
+ ## 4. Verify
67
+
68
+ ```bash
69
+ npx tsc --noEmit
70
+ npm run test:run
71
+ npm run test:coverage # confirm thresholds still pass
72
+ ```
73
+
74
+ ## 5. Document
75
+
76
+ - Add the command to the README command list.
77
+ - Add it to the CLAUDE.md architecture section if it introduces a new pattern.
@@ -0,0 +1,48 @@
1
+ ---
2
+ name: release
3
+ description: Build, test, version-bump, and push tags to trigger the npm publish workflow for namewise. Usage - /release [patch|minor|major], defaults to patch.
4
+ disable-model-invocation: true
5
+ ---
6
+
7
+ # Release namewise
8
+
9
+ Releases are driven by `v*` tags: pushing the tag triggers `.github/workflows/release.yml` (test -> build -> npm publish -> GitHub release).
10
+
11
+ ## Pre-flight checks (abort if any fail)
12
+
13
+ 1. On `main` with a clean working tree:
14
+ ```bash
15
+ git status --porcelain # must be empty
16
+ git branch --show-current # must be main
17
+ git pull --ff-only
18
+ ```
19
+ 2. Tests and build pass locally: `npm run test:run && npm run build`
20
+
21
+ ## Release
22
+
23
+ Bump level comes from the argument (default `patch`):
24
+
25
+ ```bash
26
+ npm run release # patch
27
+ npm run release:minor # minor
28
+ npm run release:major # major
29
+ ```
30
+
31
+ This runs build + tests again, then `npm version <level>` which commits and creates the `vX.Y.Z` tag.
32
+
33
+ ## Post-bump
34
+
35
+ 1. Check the hardcoded version string in `src/index.ts` - it can lag behind `package.json`. If it does, update it, amend it into the version commit, and move the tag:
36
+ ```bash
37
+ git add src/index.ts && git commit --amend --no-edit
38
+ git tag -f v<X.Y.Z>
39
+ ```
40
+ 2. Push commit and tag together:
41
+ ```bash
42
+ git push --follow-tags
43
+ ```
44
+ 3. Confirm the release workflow started and succeeded:
45
+ ```bash
46
+ gh run watch $(gh run list --workflow=release.yml --limit 1 --json databaseId -q '.[0].databaseId')
47
+ ```
48
+ 4. Verify the publish: `npm view @amirdaraee/namewise version`
package/CHANGELOG.md CHANGED
@@ -5,6 +5,52 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.10.0] - 2026-06-10
9
+
10
+ ### Added
11
+ - When `dryRun` comes from a config file (rather than an explicit `--dry-run` flag), `rename` now offers to apply the previewed renames immediately after the preview — no second invocation needed; applied renames are recorded in history for `undo`
12
+ - ESLint with typescript-eslint flat config and an `npm run lint` script, run automatically in CI
13
+
14
+ ### Changed
15
+ - AI prompts now instruct the model to keep the filename unchanged when the current name is already similar to what it would generate, avoiding needless near-identical renames
16
+ - Wrapped errors (plan-file read, config JSON parse, PDF-to-image conversion) now preserve the original error as `cause` for better diagnostics with `--log`
17
+ - README badges: stale hardcoded test-count badge replaced with the live GitHub Actions CI badge; npm version badge added
18
+
19
+ ### Fixed
20
+ - `--dry-run` and `--recursive` no longer default to `false` at the CLI layer, so `dryRun` and `recursive` values set in `.namewise.json` config files are respected again
21
+ - `--version` now reads the version from `package.json` at runtime; the previous hardcoded string had drifted (reported 0.8.0 on the 0.9.0 release)
22
+
23
+ ### Tests
24
+ - `src/cli/rename.ts` brought to 100% coverage across all metrics: library noise suppression, config-driven dry-run apply flow, and both error-display branches
25
+ - Extended workflow tests for `language`, `context`, and `--no-ai` mode handling
26
+ - `--version` is now asserted against `package.json` in both unit and e2e tests so it cannot silently drift again
27
+
28
+ ## [0.9.0] - 2026-04-12
29
+
30
+ ### Added
31
+ - **Typed error hierarchy** (`src/errors.ts`): eight subclasses of `NamewiseError` — `AuthError`, `NetworkError`, `RateLimitError`, `ParseError`, `FileSizeError`, `UnsupportedTypeError`, `ConfigError`, `VisionError` — each with a default user-facing `.hint`; replaces all raw `throw new Error(string)` calls throughout parsers, AI services, and CLI commands
32
+ - **Session logger** (`src/utils/logger.ts`): opt-in structured JSON-lines logging to `~/.namewise/logs/YYYY-MM-DDTHH-MM-SS-<command>.log`; enable with `--log` on any command or `"log": true` in config; records session start, per-file errors, and session summary (total, succeeded, failed, token usage, elapsed); auto-prunes to the 20 most recent files
33
+ - `ui.hint()` helper: dim indented suggestion line (` → …`) shown below errors in the terminal
34
+
35
+ ### Changed
36
+ - **Known errors** surface `message` + `hint` in the terminal (e.g. `✗ API key required → Set it with: namewise config set apiKey YOUR_KEY`); no stack traces to stdout/stderr
37
+ - **Unknown errors** show `✗ An unexpected error occurred.` with either the log path (if `--log` is active) or `→ Run with --log for detailed error information.`
38
+ - HTTP status mapping in AI services: 401/403 → `AuthError`, 429 → `RateLimitError`, 5xx → `NetworkError`
39
+ - Progress display replaced with an ASCII bar: `[████████████░░░░░░░░░░░░░░░░] 43% 24/55` — renders correctly even when the event loop is blocked by PDF/canvas processing
40
+ - pdfjs `TT: undefined function` warning fully suppressed: `console.log`, `console.warn`, and `process.stdout.write` are all filtered for the known noise pattern during the rename session
41
+
42
+ ## [0.8.1] - 2026-04-11
43
+
44
+ ### Changed
45
+ - Polished CLI output across all commands using `chalk` (colour) and `ora` (spinner)
46
+ - `rename` command: spinner replaces the interleaved `\r` progress; file list no longer dumped before processing; results displayed with colour-coded ✓/✗ rows and a cleaner stats block
47
+ - Scanned-PDF diagnostic messages (`Detected scanned PDF`, `PDF converted to image successfully`) suppressed — internal implementation details, not user-facing
48
+ - pdfjs `TT: undefined function` stderr noise suppressed via inline stderr intercept during PDF text extraction
49
+ - AI service `console.error` calls removed (redundant — errors are rethrown immediately)
50
+ - Success lines green (✓), warnings yellow (!), errors red (✗); neutral info lines unchanged
51
+ - Stats block: renamed/failed counts, data size, and token usage on clearly labelled lines
52
+ - All commands (`undo`, `init`, `sanitize`, `apply`, `dedup`, `watch`, `organize`, `flatten`, `clean-empty`, `find`, `diff`, `stats`, `tree`, `info`, `config`) use the new shared `src/utils/ui` module
53
+
8
54
  ## [0.8.0] - 2026-04-09
9
55
 
10
56
  ### Added
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Namewise
2
2
 
3
- [![Tests](https://img.shields.io/badge/tests-867%20passing-brightgreen.svg)](#testing--development)
3
+ [![Tests](https://github.com/amirdaraee/namewise/actions/workflows/test.yml/badge.svg)](https://github.com/amirdaraee/namewise/actions/workflows/test.yml)
4
+ [![npm](https://img.shields.io/npm/v/@amirdaraee/namewise.svg)](https://www.npmjs.com/package/@amirdaraee/namewise)
4
5
  [![Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen.svg)](#testing--development)
5
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.9-blue.svg)](https://www.typescriptlang.org/)
6
7
  [![Node.js](https://img.shields.io/badge/Node.js-20+-green.svg)](https://nodejs.org/)
@@ -45,42 +46,32 @@ Automatically rename files based on their content using AI providers (Claude, Op
45
46
  - **Multiple File Types**: Supports PDF, DOCX, DOC, XLSX, XLS, TXT, MD, RTF, JPG, JPEG, PNG, GIF, BMP, TIFF, HEIC, and WEBP files
46
47
  - **Image Renaming**: Vision-capable models analyze image content to generate descriptive filenames
47
48
  - **EXIF Fallback**: `--no-ai` mode extracts EXIF metadata (description, date) from image files when available
48
- - **Dry Run Mode**: Preview changes before renaming files
49
+ - **Dry Run Mode**: Preview changes before renaming files; when `dryRun` is set in config, you're offered to apply the previewed renames right away
49
50
  - **Size Limits**: Configurable maximum file size limits
51
+ - **Session Logs**: Structured JSON logs written to `~/.namewise/logs/` when enabled with `--log` or `"log": true` in config
50
52
 
51
53
  ## Quick Start
52
54
 
53
55
  ```bash
54
- # Clone and setup
55
- git clone https://github.com/amirdaraee/namewise.git
56
- cd namewise
57
- npm install
58
- npm run build
56
+ # Install
57
+ npm install -g @amirdaraee/namewise
59
58
 
60
59
  # Run the interactive setup wizard (recommended for first use)
61
60
  namewise init
62
61
 
63
62
  # Preview renames (recommended first)
64
- npx namewise rename ./my-documents --dry-run --provider claude
63
+ namewise rename ./my-documents --dry-run --provider claude
65
64
 
66
65
  # Actually rename
67
- npx namewise rename ./my-documents --provider claude --api-key your-api-key
66
+ namewise rename ./my-documents --provider claude --api-key your-api-key
68
67
  ```
69
68
 
70
69
  ## Installation
71
70
 
72
- ### Option 1: Clone and Build
73
71
  ```bash
74
- git clone https://github.com/amirdaraee/namewise.git
75
- cd namewise
76
- npm install
77
- npm run build
78
- npm link # Optional: for global usage
72
+ npm install -g @amirdaraee/namewise
79
73
  ```
80
74
 
81
- ### Option 2: Direct Download
82
- Download the latest release from [GitHub Releases](https://github.com/amirdaraee/namewise/releases)
83
-
84
75
  ## Usage
85
76
 
86
77
  ### Command Structure
@@ -576,6 +567,66 @@ For local providers (Ollama, LMStudio), token counts are not available:
576
567
  Tokens: N/A (local provider)
577
568
  ```
578
569
 
570
+ ## Session Logs
571
+
572
+ Session logging is **off by default**. Enable it with `--log` on any command, or set it permanently in your config file.
573
+
574
+ ```bash
575
+ # Enable for a single run
576
+ namewise rename ./docs --dry-run --log
577
+
578
+ # Enable permanently
579
+ namewise config set log true
580
+ ```
581
+
582
+ When enabled, a structured log is written to `~/.namewise/logs/` for every run.
583
+
584
+ **Log file naming:** `YYYY-MM-DDTHH-MM-SS-<command>.log`
585
+ Example: `2026-04-12T10-30-00-rename.log`
586
+
587
+ **Format:** Newline-delimited JSON (one object per line):
588
+
589
+ ```json
590
+ {"ts":"2026-04-12T10:30:00.000Z","level":"info","msg":"session_start","command":"rename","directory":"/Users/amir/docs","provider":"claude","dryRun":false}
591
+ {"ts":"2026-04-12T10:30:02.456Z","level":"warn","msg":"vision_skipped","file":"photo.jpg","reason":"provider does not support vision"}
592
+ {"ts":"2026-04-12T10:30:03.789Z","level":"error","msg":"ParseError","hint":"The file may be corrupt or in an unsupported format","stack":"ParseError: ..."}
593
+ {"ts":"2026-04-12T10:30:04.000Z","level":"info","msg":"session_end","total":55,"succeeded":54,"failed":1,"elapsedMs":4123}
594
+ ```
595
+
596
+ **Auto-pruned** to the 20 most recent files — older logs are deleted automatically at the start of each run.
597
+
598
+ **Reading logs:**
599
+
600
+ ```bash
601
+ # View the latest log
602
+ cat ~/.namewise/logs/$(ls -t ~/.namewise/logs/ | head -1)
603
+
604
+ # Pretty-print with jq
605
+ cat ~/.namewise/logs/2026-04-12T10-30-00-rename.log | jq .
606
+
607
+ # Show only errors
608
+ cat ~/.namewise/logs/2026-04-12T10-30-00-rename.log | jq 'select(.level == "error")'
609
+ ```
610
+
611
+ **Error output:** When a known error occurs, Namewise shows the message and a hint directly in the terminal:
612
+
613
+ ```
614
+ ✗ API key required for Claude
615
+ → Check your API key — ensure ANTHROPIC_API_KEY or OPENAI_API_KEY is set, or run: namewise config set apiKey YOUR_KEY
616
+ ```
617
+
618
+ For unexpected errors, the terminal either points to the log (if `--log` was used) or prompts you to enable it:
619
+
620
+ ```
621
+ # With --log enabled:
622
+ ✗ An unexpected error occurred.
623
+ → See log: ~/.namewise/logs/2026-04-12T10-30-00-rename.log
624
+
625
+ # Without --log:
626
+ ✗ An unexpected error occurred.
627
+ → Run with --log for detailed error information.
628
+ ```
629
+
579
630
  ## Safety Features
580
631
 
581
632
  - **Dry Run Mode**: Always preview changes first with `--dry-run`
@@ -583,7 +634,7 @@ Tokens: N/A (local provider)
583
634
  - **Conflict Auto-Numbering**: Never overwrites an existing file
584
635
  - **File Size Limits**: Skips files above `--max-size`
585
636
  - **Extension Preservation**: Original file extensions are never changed
586
- - **Comprehensive Testing**: 867 tests with 100% coverage
637
+ - **Comprehensive Testing**: 900+ tests with ~100% coverage, run on Node 20/22/24 in CI
587
638
 
588
639
  ## Testing & Development
589
640
 
@@ -621,15 +672,25 @@ npm run test:integration # Integration tests only
621
672
  <details>
622
673
  <summary>Common Issues</summary>
623
674
 
675
+ **Enable session logging for details** — run with `--log` to capture a full structured log in `~/.namewise/logs/`:
676
+ ```bash
677
+ namewise rename ./docs --log
678
+ ```
679
+ When an unexpected error occurs with `--log` enabled, the terminal prints the exact log path:
680
+ ```
681
+ ✗ An unexpected error occurred.
682
+ → See log: ~/.namewise/logs/2026-04-12T10-30-00-rename.log
683
+ ```
684
+
624
685
  **PDF parsing errors:**
625
686
  - Ensure the PDF is not password protected
626
687
  - Check the file is not corrupted
627
688
  - Try reducing the `--max-size` limit
628
689
 
629
690
  **API errors (cloud providers):**
630
- - Verify the API key is valid
691
+ - Verify the API key is valid and has sufficient credits
631
692
  - Check your internet connection
632
- - Ensure sufficient API credits
693
+ - Run again to confirm the error is not transient (rate limits auto-hint wait time)
633
694
 
634
695
  **Local LLM connection errors:**
635
696
  - Ensure Ollama server is running (`ollama serve`)
@@ -644,6 +705,10 @@ npm run test:integration # Integration tests only
644
705
 
645
706
  </details>
646
707
 
708
+ ## Changelog
709
+
710
+ See [CHANGELOG.md](./CHANGELOG.md) for the full release history.
711
+
647
712
  ## License
648
713
 
649
714
  [MIT License](./LICENSE) — Feel free to use, modify, and distribute this project.
@@ -1 +1 @@
1
- {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/cli/apply.ts"],"names":[],"mappings":"AAcA,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAgEnG"}
1
+ {"version":3,"file":"apply.d.ts","sourceRoot":"","sources":["../../src/cli/apply.ts"],"names":[],"mappings":"AAeA,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAoEnG"}
package/dist/cli/apply.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { promises as fs } from 'fs';
2
2
  import path from 'path';
3
3
  import { appendHistory } from '../utils/history.js';
4
+ import * as ui from '../utils/ui.js';
4
5
  export async function applyPlan(planPath, options = {}) {
5
6
  let plan;
6
7
  try {
@@ -8,14 +9,14 @@ export async function applyPlan(planPath, options = {}) {
8
9
  plan = JSON.parse(raw);
9
10
  }
10
11
  catch (error) {
11
- throw new Error(`Could not read plan file: ${error instanceof Error ? error.message : 'Unknown error'}`);
12
+ throw new Error(`Could not read plan file: ${error instanceof Error ? error.message : 'Unknown error'}`, { cause: error });
12
13
  }
13
14
  if (!Array.isArray(plan.results)) {
14
15
  throw new Error('Invalid plan file: missing "results" array');
15
16
  }
16
17
  const pending = plan.results.filter(r => r.success && r.originalPath !== r.newPath);
17
18
  if (pending.length === 0) {
18
- console.log('No renames to apply.');
19
+ ui.info('No renames to apply.');
19
20
  return;
20
21
  }
21
22
  for (const r of pending) {
@@ -42,7 +43,12 @@ export async function applyPlan(planPath, options = {}) {
42
43
  const renames = [];
43
44
  let previewCount = 0;
44
45
  for (const r of pending) {
45
- console.log(`${options.dryRun ? '[dry-run] ' : ''}${path.basename(r.originalPath)} → ${path.basename(r.newPath)}`);
46
+ if (options.dryRun) {
47
+ ui.dim(`[dry-run] ${path.basename(r.originalPath)} → ${path.basename(r.newPath)}`);
48
+ }
49
+ else {
50
+ ui.success(`${path.basename(r.originalPath)} → ${path.basename(r.newPath)}`);
51
+ }
46
52
  if (!options.dryRun) {
47
53
  await fs.rename(r.originalPath, r.newPath);
48
54
  renames.push({ originalPath: r.originalPath, newPath: r.newPath });
@@ -61,6 +67,6 @@ export async function applyPlan(planPath, options = {}) {
61
67
  });
62
68
  }
63
69
  const count = options.dryRun ? previewCount : renames.length;
64
- console.log(`\nApplied${options.dryRun ? ' (dry-run)' : ''}: ${count} rename(s).`);
70
+ ui.info(`\n${options.dryRun ? 'Would apply' : 'Applied'}: ${count} rename(s).`);
65
71
  }
66
72
  //# sourceMappingURL=apply.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/cli/apply.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAYpD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,UAAgC,EAAE;IAClF,IAAI,IAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjD,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,6BAA6B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC,CAAC;IAC3G,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;IAEpF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACpC,OAAO;IACT,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,YAAY,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAC3B,YAAY,GAAG,IAAI,CAAC;QACtB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,KAAK,CAAC;QACtE,CAAC;QACD,IAAI,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,OAAO,GAAqD,EAAE,CAAC;IACrE,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACnH,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;YAC3C,OAAO,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACrE,CAAC;aAAM,CAAC;YACN,YAAY,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,aAAa,CAAC;YAClB,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;YAChD,MAAM,EAAE,KAAK;YACb,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAC7D,OAAO,CAAC,GAAG,CAAC,YAAY,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,aAAa,CAAC,CAAC;AACrF,CAAC"}
1
+ {"version":3,"file":"apply.js","sourceRoot":"","sources":["../../src/cli/apply.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAYrC,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,QAAgB,EAAE,UAAgC,EAAE;IAClF,IAAI,IAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACjD,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,6BAA6B,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC7H,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC;IAEpF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;QAChC,OAAO;IACT,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,YAAY,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;YAC3B,YAAY,GAAG,IAAI,CAAC;QACtB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;gBAAE,MAAM,KAAK,CAAC;QACtE,CAAC;QACD,IAAI,YAAY;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,MAAM,OAAO,GAAqD,EAAE,CAAC;IACrE,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,EAAE,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACrF,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;YAC3C,OAAO,CAAC,IAAI,CAAC,EAAE,YAAY,EAAE,CAAC,CAAC,YAAY,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACrE,CAAC;aAAM,CAAC;YACN,YAAY,EAAE,CAAC;QACjB,CAAC;IACH,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1C,MAAM,aAAa,CAAC;YAClB,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YAC5B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC;YAChD,MAAM,EAAE,KAAK;YACb,OAAO;SACR,CAAC,CAAC;IACL,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;IAC7D,EAAE,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,KAAK,KAAK,aAAa,CAAC,CAAC;AAClF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"clean-empty.d.ts","sourceRoot":"","sources":["../../src/cli/clean-empty.ts"],"names":[],"mappings":"AAGA,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,IAAI,CAAC,CAsBf"}
1
+ {"version":3,"file":"clean-empty.d.ts","sourceRoot":"","sources":["../../src/cli/clean-empty.ts"],"names":[],"mappings":"AAIA,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GACjC,OAAO,CAAC,IAAI,CAAC,CA0Bf"}
@@ -1,5 +1,6 @@
1
1
  import { promises as fs } from 'fs';
2
2
  import path from 'path';
3
+ import * as ui from '../utils/ui.js';
3
4
  export async function cleanEmptyDirs(directory, options = {}) {
4
5
  const stat = await fs.stat(directory);
5
6
  if (!stat.isDirectory())
@@ -7,18 +8,23 @@ export async function cleanEmptyDirs(directory, options = {}) {
7
8
  const dryRun = options.dryRun ?? false;
8
9
  const { emptyDirs } = await scan(directory);
9
10
  if (emptyDirs.length === 0) {
10
- console.log('No empty directories found.');
11
+ ui.info('No empty directories found.');
11
12
  return;
12
13
  }
13
14
  for (const dir of emptyDirs) {
14
15
  const rel = path.relative(directory, dir);
15
- console.log(`${dryRun ? '[dry-run] ' : ''}Remove: ${rel}`);
16
+ if (dryRun) {
17
+ ui.dim(`[dry-run] Remove: ${rel}`);
18
+ }
19
+ else {
20
+ ui.success(`Removed: ${rel}`);
21
+ }
16
22
  if (!dryRun) {
17
23
  await fs.rmdir(dir);
18
24
  }
19
25
  }
20
26
  const count = emptyDirs.length;
21
- console.log(`\n${dryRun ? 'Would remove' : 'Removed'} ${count} empty director${count === 1 ? 'y' : 'ies'}.`);
27
+ ui.info(`\n${dryRun ? 'Would remove' : 'Removed'} ${count} empty director${count === 1 ? 'y' : 'ies'}.`);
22
28
  }
23
29
  async function scan(dir) {
24
30
  const entries = await fs.readdir(dir, { withFileTypes: true });
@@ -1 +1 @@
1
- {"version":3,"file":"clean-empty.js","sourceRoot":"","sources":["../../src/cli/clean-empty.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,SAAiB,EACjB,UAAgC,EAAE;IAElC,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,SAAS,qBAAqB,CAAC,CAAC;IAE5E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC;IACvC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC;IAE5C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;QAC3C,OAAO;IACT,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,WAAW,GAAG,EAAE,CAAC,CAAC;QAC3D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,IAAI,KAAK,kBAAkB,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;AAC/G,CAAC;AAOD,KAAK,UAAU,IAAI,CAAC,GAAW;IAC7B,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAE/D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC1C,CAAC;IAED,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,IAAI,iBAAiB,GAAG,IAAI,CAAC;IAC7B,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACzB,QAAQ,GAAG,IAAI,CAAC;YAChB,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC;QACrC,SAAS,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;QACvC,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;YACtB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,iBAAiB,GAAG,KAAK,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,QAAQ,IAAI,iBAAiB,EAAE,CAAC;AAChE,CAAC"}
1
+ {"version":3,"file":"clean-empty.js","sourceRoot":"","sources":["../../src/cli/clean-empty.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,SAAiB,EACjB,UAAgC,EAAE;IAElC,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,SAAS,qBAAqB,CAAC,CAAC;IAE5E,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC;IACvC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC;IAE5C,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3B,EAAE,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QACvC,OAAO;IACT,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC1C,IAAI,MAAM,EAAE,CAAC;YACX,EAAE,CAAC,GAAG,CAAC,qBAAqB,GAAG,EAAE,CAAC,CAAC;QACrC,CAAC;aAAM,CAAC;YACN,EAAE,CAAC,OAAO,CAAC,YAAY,GAAG,EAAE,CAAC,CAAC;QAChC,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;IAED,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC;IAC/B,EAAE,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,IAAI,KAAK,kBAAkB,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;AAC3G,CAAC;AAOD,KAAK,UAAU,IAAI,CAAC,GAAW;IAC7B,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAE/D,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IAC1C,CAAC;IAED,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,IAAI,iBAAiB,GAAG,IAAI,CAAC;IAC7B,IAAI,QAAQ,GAAG,KAAK,CAAC;IAErB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACzB,QAAQ,GAAG,IAAI,CAAC;YAChB,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1C,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,CAAC;QACrC,SAAS,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;QACvC,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;YACtB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzB,CAAC;aAAM,CAAC;YACN,iBAAiB,GAAG,KAAK,CAAC;QAC5B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,QAAQ,IAAI,iBAAiB,EAAE,CAAC;AAChE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA4UpD"}
1
+ {"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAqBpC,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqUpD"}