fix-smart-quotes 1.0.0 → 1.0.2

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.
package/README.md CHANGED
@@ -4,26 +4,28 @@ Convert straight quotes to proper typographic ("smart") quotes in Markdown files
4
4
 
5
5
  | Language | Before | After |
6
6
  |----------|--------|-------|
7
- | German | `"text"` | `„text"` (U+201E / U+201C) |
8
- | English | `"text"` | `"text"` (U+201C / U+201D) |
7
+ | German | `"text"` | `„text“` (U+201E / U+201C) |
8
+ | English | `"text"` | `“text”` (U+201C / U+201D) |
9
9
 
10
10
  ## Why?
11
11
 
12
- When AI coding assistants edit Markdown files, they often replace typographic quotes with straight quotes. This is intentional—straight quotes are safer for code and avoid encoding issues.
12
+ Claude (including Claude.ai, Claude Desktop, and Claude Code) consistently uses straight quotes (`"`) instead of typographic quotes. This applies to both generated text and edits to existing content. The reason: straight quotes are universally compatible. They work in code, terminals, and forms, avoiding encoding issues that can turn smart quotes into question marks.
13
13
 
14
- But for prose text, proper typography matters.
14
+ Other AI assistants behave differently: ChatGPT and DeepSeek typically output smart quotes, while Claude and Gemini use straight quotes.
15
15
 
16
- **Example - before AI edit:**
16
+ For prose and documentation, proper typography matters. German and English have distinct quote styles that convey professionalism and readability.
17
+
18
+ **Example - text with proper German quotes:**
17
19
  ```
18
- Sie sagte: „Das ist wichtig."
20
+ Sie sagte: „Das ist wichtig.“
19
21
  ```
20
22
 
21
- **After AI edit:**
23
+ **After Claude edits or generates text:**
22
24
  ```
23
25
  Sie sagte: "Das ist wichtig."
24
26
  ```
25
27
 
26
- This tool restores the correct quoteseither manually via CLI, or automatically after each Claude Code edit via hook.
28
+ This tool restores the correct quotes: either manually via CLI or automatically after each Claude edit via hook.
27
29
 
28
30
  ## Installation
29
31
 
@@ -49,26 +51,37 @@ fix-smart-quotes docs/*.md
49
51
 
50
52
  ## Claude Code Hook
51
53
 
52
- The primary use case: automatically fix quotes in files that Claude Code just edited. The hook runs **only** on files modified by Claude's Write or Edit tools—not on your entire project.
54
+ Automatically fix quotes after Claude edits Markdown files.
55
+
56
+ **1. Create wrapper script** at `~/.claude/hooks/fix-smart-quotes-wrapper.sh`:
57
+
58
+ ```bash
59
+ #!/bin/bash
60
+ INPUT=$(cat)
61
+ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')
62
+ [ -z "$FILE_PATH" ] && exit 0
63
+ [[ ! "$FILE_PATH" =~ \.md$ ]] && exit 0
64
+ [ ! -f "$FILE_PATH" ] && exit 0
65
+ npx fix-smart-quotes "$FILE_PATH"
66
+ exit 0
67
+ ```
68
+
69
+ **2. Make executable:** `chmod +x ~/.claude/hooks/fix-smart-quotes-wrapper.sh`
53
70
 
54
- Add to `~/.claude/settings.json`:
71
+ **3. Add to** `~/.claude/settings.json`:
55
72
 
56
73
  ```json
57
74
  {
58
75
  "hooks": {
59
76
  "PostToolUse": [{
60
77
  "matcher": "Write|Edit",
61
- "hooks": [{
62
- "type": "command",
63
- "command": "npx fix-smart-quotes \"$FILE_PATH\"",
64
- "timeout": 30
65
- }]
78
+ "hooks": [{"type": "command", "command": "~/.claude/hooks/fix-smart-quotes-wrapper.sh", "timeout": 30}]
66
79
  }]
67
80
  }
68
81
  }
69
82
  ```
70
83
 
71
- This means: After Claude writes or edits a file, immediately run the quote fixer on that specific file.
84
+ > **Note:** Claude Code passes file paths via stdin JSON, not environment variables. The wrapper script handles this.
72
85
 
73
86
  ## Features
74
87
 
@@ -0,0 +1,160 @@
1
+ # Hook Wrapper Fix Implementation Plan
2
+
3
+ > **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
4
+
5
+ **Goal:** Fix the PostToolUse hook to correctly receive file paths via stdin JSON instead of environment variables.
6
+
7
+ **Architecture:** Create a wrapper shell script that parses JSON from stdin, extracts the file path, filters for markdown files only, and calls fix-smart-quotes. Update settings.json to use the wrapper.
8
+
9
+ **Tech Stack:** Bash, jq, Node.js (fix-smart-quotes)
10
+
11
+ ---
12
+
13
+ ## Task 1: Create Wrapper Script
14
+
15
+ **Files:**
16
+ - Create: `~/.claude/hooks/fix-smart-quotes-wrapper.sh`
17
+
18
+ **Step 1: Create the wrapper script**
19
+
20
+ ```bash
21
+ #!/bin/bash
22
+ # fix-smart-quotes-wrapper.sh
23
+ # Wrapper for fix-smart-quotes that parses Claude Code hook stdin JSON
24
+
25
+ # Read JSON from stdin
26
+ INPUT=$(cat)
27
+
28
+ # Extract file_path from JSON using jq
29
+ FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // .tool_input.filePath // empty')
30
+
31
+ # Exit 0 if no file path found (non-blocking)
32
+ if [ -z "$FILE_PATH" ]; then
33
+ exit 0
34
+ fi
35
+
36
+ # Only process markdown files
37
+ if [[ ! "$FILE_PATH" =~ \.(md|markdown)$ ]]; then
38
+ exit 0
39
+ fi
40
+
41
+ # Check if file exists
42
+ if [ ! -f "$FILE_PATH" ]; then
43
+ exit 0
44
+ fi
45
+
46
+ # Run fix-smart-quotes
47
+ npx fix-smart-quotes "$FILE_PATH"
48
+
49
+ # Always exit 0 to not block Claude Code
50
+ exit 0
51
+ ```
52
+
53
+ **Step 2: Make script executable**
54
+
55
+ Run: `chmod +x ~/.claude/hooks/fix-smart-quotes-wrapper.sh`
56
+
57
+ **Step 3: Verify script is executable**
58
+
59
+ Run: `ls -la ~/.claude/hooks/fix-smart-quotes-wrapper.sh`
60
+ Expected: `-rwxr-xr-x` permissions
61
+
62
+ ---
63
+
64
+ ## Task 2: Test Wrapper Script Manually
65
+
66
+ **Step 1: Test with valid markdown file path**
67
+
68
+ Run:
69
+ ```bash
70
+ echo '{"tool_input": {"file_path": "/tmp/test.md"}}' > /tmp/test.md
71
+ echo 'This is a "test" file.' >> /tmp/test.md
72
+ echo '{"tool_input": {"file_path": "/tmp/test.md"}}' | ~/.claude/hooks/fix-smart-quotes-wrapper.sh
73
+ echo "Exit code: $?"
74
+ cat /tmp/test.md
75
+ ```
76
+
77
+ Expected: Exit code 0, file contains smart quotes
78
+
79
+ **Step 2: Test with non-markdown file**
80
+
81
+ Run:
82
+ ```bash
83
+ echo '{"tool_input": {"file_path": "/tmp/test.json"}}' | ~/.claude/hooks/fix-smart-quotes-wrapper.sh
84
+ echo "Exit code: $?"
85
+ ```
86
+
87
+ Expected: Exit code 0 (non-blocking)
88
+
89
+ **Step 3: Test with missing file_path**
90
+
91
+ Run:
92
+ ```bash
93
+ echo '{"tool_input": {}}' | ~/.claude/hooks/fix-smart-quotes-wrapper.sh
94
+ echo "Exit code: $?"
95
+ ```
96
+
97
+ Expected: Exit code 0 (non-blocking)
98
+
99
+ **Step 4: Cleanup test files**
100
+
101
+ Run: `rm -f /tmp/test.md /tmp/test.json`
102
+
103
+ ---
104
+
105
+ ## Task 3: Update settings.json
106
+
107
+ **Files:**
108
+ - Modify: `~/.claude/settings.json`
109
+
110
+ **Step 1: Update hook command**
111
+
112
+ Change from:
113
+ ```json
114
+ "command": "npx fix-smart-quotes \"$FILE_PATH\""
115
+ ```
116
+
117
+ To:
118
+ ```json
119
+ "command": "~/.claude/hooks/fix-smart-quotes-wrapper.sh"
120
+ ```
121
+
122
+ **Step 2: Verify settings.json is valid JSON**
123
+
124
+ Run: `jq . ~/.claude/settings.json > /dev/null && echo "Valid JSON"`
125
+ Expected: "Valid JSON"
126
+
127
+ ---
128
+
129
+ ## Task 4: End-to-End Test
130
+
131
+ **Step 1: Create a test markdown file**
132
+
133
+ Run:
134
+ ```bash
135
+ echo 'Test "quotes" here.' > /tmp/hook-test.md
136
+ ```
137
+
138
+ **Step 2: Simulate hook invocation**
139
+
140
+ Run:
141
+ ```bash
142
+ echo '{"tool_input": {"file_path": "/tmp/hook-test.md"}}' | ~/.claude/hooks/fix-smart-quotes-wrapper.sh
143
+ cat /tmp/hook-test.md
144
+ ```
145
+
146
+ Expected: File contains smart quotes (German style since no lang specified)
147
+
148
+ **Step 3: Cleanup**
149
+
150
+ Run: `rm /tmp/hook-test.md`
151
+
152
+ ---
153
+
154
+ ## Summary
155
+
156
+ After completing all tasks:
157
+ - [x] Wrapper script created at `~/.claude/hooks/fix-smart-quotes-wrapper.sh`
158
+ - [x] Wrapper parses stdin JSON, filters for .md files, exits 0 on non-matches
159
+ - [x] settings.json updated to use wrapper
160
+ - [x] Hook no longer causes errors on non-markdown files
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "fix-smart-quotes",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Fix straight quotes to smart quotes in Markdown (DE/EN)",
5
5
  "main": "index.js",
6
6
  "bin": {