opencode-ascii 0.1.3 → 0.1.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.
package/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  # opencode-ascii
2
2
 
3
- An [OpenCode](https://opencode.ai) plugin that automatically substitutes unicode characters with ASCII equivalents in AI responses and file edits.
3
+ An [OpenCode](https://opencode.ai) plugin that automatically substitutes unicode characters with ASCII-safe equivalents in AI responses and file edits.
4
4
 
5
5
  ## Why?
6
6
 
7
7
  LLMs love to reach for typographic characters — em-dashes, curly quotes, arrows, emoji — that look great in a browser but cause friction in terminals, code, config files, and plain-text tooling. This plugin intercepts output at two points:
8
8
 
9
9
  - **AI text responses** (`experimental.text.complete`) — rewrites text parts before they are stored.
10
- - **File write/edit tool calls** (`tool.execute.before`) — rewrites `write`, `edit`, and `patch` tool arguments before execution.
10
+ - **File write/edit tool calls** (`tool.execute.before`) — rewrites `write`, `edit`, `multiedit`, and `apply_patch` tool arguments before execution.
11
11
 
12
12
  ## Installation
13
13
 
@@ -45,7 +45,7 @@ All four substitution categories are **enabled by default**. Disable any categor
45
45
  | `punctuation` | boolean | `true` | Em/en dashes, ellipsis, curly/smart quotes |
46
46
  | `arrows` | boolean | `true` | `→` → `->`, `←` → `<-`, `⇒` → `=>`, etc. |
47
47
  | `math` | boolean | `true` | `≠` → `!=`, `≤` → `<=`, `×` → `*`, etc. |
48
- | `emojis` | boolean | `true` | Common emoji short ASCII labels |
48
+ | `emojis` | boolean | `true` | Common emoji -> `:shortcode:` labels |
49
49
 
50
50
  ## Substitution reference
51
51
 
@@ -96,21 +96,23 @@ All four substitution categories are **enabled by default**. Disable any categor
96
96
 
97
97
  | Unicode | Character | ASCII |
98
98
  |---------|-----------|-------|
99
- | U+2713 | ✓ | `[x]` |
100
- | U+274C | | `[!]` |
101
- | U+26A0 | | `[!]` |
102
- | U+2139 | | `[i]` |
103
- | U+2B50 | | `[*]` |
104
- | U+1F525 | | `[fire]` |
105
- | U+1F680 | | `[>>]` |
106
- | U+1F41B | | `[bug]` |
107
- | U+1F4DD | | `[note]` |
108
- | U+1F512 | | `[lock]` |
109
- | U+1F513 | | `[open]` |
110
- | U+1F4C1 | | `[dir]` |
111
- | U+1F4C4 | | `[file]` |
112
- | U+1F44D | | `[+1]` |
113
- | U+1F44E | | `[-1]` |
99
+ | U+2713 | ✓ | `:white_check_mark:` |
100
+ | U+274C || `:x:` |
101
+ | U+26A0 || `:warning:` |
102
+ | U+2139 || `:information_source:` |
103
+ | U+2B50 || `:star:` |
104
+ | U+1F525 | 🔥 | `:fire:` |
105
+ | U+1F680 | 🚀 | `:rocket:` |
106
+ | U+1F41B | 🐛 | `:bug:` |
107
+ | U+1F4DD | 📝 | `:memo:` |
108
+ | U+1F512 | 🔒 | `:lock:` |
109
+ | U+1F513 | 🔓 | `:unlock:` |
110
+ | U+1F4C1 | 📁 | `:file_folder:` |
111
+ | U+1F4C4 | 📄 | `:page_facing_up:` |
112
+ | U+1F44D | 👍 | `:+1:` |
113
+ | U+1F44E | 👎 | `:-1:` |
114
+
115
+ and many more!
114
116
 
115
117
  See [`src/substitutions.ts`](src/substitutions.ts) for the full list.
116
118
 
@@ -123,7 +125,8 @@ The plugin uses two hooks:
123
125
  2. **`tool.execute.before`** — fired before any tool executes. The plugin rewrites:
124
126
  - `output.args.content` for the `write` tool
125
127
  - `output.args.newString` for the `edit` tool (never `oldString` — it must match existing file content exactly)
126
- - `output.args.patch` for the `patch` tool
128
+ - each `output.args.edits[].newString` for the `multiedit` tool
129
+ - `output.args.patchText` for the `apply_patch` tool
127
130
 
128
131
  Substitution uses a single compiled regex built from all active mappings, so there is no O(n) string-replace loop per character.
129
132
 
@@ -82,71 +82,70 @@ export const MATH = [
82
82
  ];
83
83
  export const EMOJIS = [
84
84
  // Checkmarks / cross marks
85
- ["\u2713", "[x]"], // check mark ()
86
- ["\u2714", "[x]"], // heavy check mark ()
87
- ["\u2611", "[x]"], // ballot box with check ()
88
- ["\u2705", "[x]"], // white heavy check mark ()
89
- ["\u2717", "[!]"], // ballot x ()
90
- ["\u2718", "[!]"], // heavy ballot x ()
91
- ["\u274C", "[!]"], // cross mark ()
92
- ["\u274E", "[!]"], // cross mark button ()
85
+ ["\u2713", ":white_check_mark:"], // check mark ([x])
86
+ ["\u2714", ":white_check_mark:"], // heavy check mark ([x])
87
+ ["\u2611", ":ballot_box_with_check:"], // ballot box with check ([x])
88
+ ["\u2705", ":white_check_mark:"], // white heavy check mark ([done])
89
+ ["\u2717", ":x:"], // ballot x ([!])
90
+ ["\u2718", ":x:"], // heavy ballot x ([!])
91
+ ["\u274C", ":x:"], // cross mark ([!])
92
+ ["\u274E", ":x:"], // cross mark button ([!])
93
93
  // Warnings / alerts
94
- ["\u26A0", "[!]"], // warning sign ()
95
- ["\u2757", "[!]"], // heavy exclamation mark ornament ()
96
- ["\u2755", "[!]"], // white exclamation mark ornament ()
97
- ["\u26A1", "[!]"], // high voltage sign ()
94
+ ["\u26A0", ":warning:"], // warning sign ([!])
95
+ ["\u2757", ":exclamation:"], // heavy exclamation mark ornament ([!])
96
+ ["\u2755", ":grey_exclamation:"], // white exclamation mark ornament ([!])
97
+ ["\u26A1", ":zap:"], // high voltage sign ([!])
98
98
  // Info / ideas
99
- ["\u2139", "[i]"], // information source ([i])
100
- ["\u{1F4A1}", "[i]"], // light bulb (💡)
99
+ ["\u2139", ":information_source:"], // information source ([i])
100
+ ["\u{1F4A1}", ":bulb:"], // light bulb ([i])
101
101
  // Stars / rating
102
- ["\u2B50", "[*]"], // white medium star ([*])
103
- ["\u{1F31F}", "[*]"], // glowing star (🌟)
104
- ["\u2605", "[*]"], // black star ([*])
105
- ["\u2606", "[*]"], // white star ([*])
102
+ ["\u2B50", ":star:"], // white medium star ([*])
103
+ ["\u{1F31F}", ":star2:"], // glowing star ([*])
104
+ ["\u2605", ":star:"], // black star ([*])
105
+ ["\u2606", ":star:"], // white star ([*])
106
106
  // Common emoji sequences
107
- ["\u{1F525}", "[fire]"], // fire (🔥)
108
- ["\u{1F680}", "[>>]"], // rocket (🚀)
109
- ["\u{1F41B}", "[bug]"], // bug (🐛)
110
- ["\u{1F41E}", "[bug]"], // lady beetle (🐞)
111
- ["\u{1F4DD}", "[note]"], // memo (📝)
112
- ["\u270F", "[note]"], // pencil ([note])
113
- ["\u{1F512}", "[lock]"], // lock (🔒)
114
- ["\u{1F513}", "[open]"], // open lock (🔓)
115
- ["\u{1F4C1}", "[dir]"], // file folder (📁)
116
- ["\u{1F4C2}", "[dir]"], // open file folder (📂)
117
- ["\u{1F4C4}", "[file]"], // page facing up (📄)
118
- ["\u{1F4C3}", "[file]"], // page with curl (📃)
119
- ["\u{1F44D}", "[+1]"], // thumbs up (👍)
120
- ["\u{1F44E}", "[-1]"], // thumbs down (👎)
121
- ["\u{1F4AC}", "[comment]"], // speech balloon (💬)
122
- ["\u{1F4E6}", "[pkg]"], // package (📦)
123
- ["\u{1F517}", "[link]"], // link (🔗)
124
- ["\u{1F6A7}", "[wip]"], // construction sign (🚧)
125
- ["\u2699", "[config]"], // gear ([config])
126
- ["\u{1F527}", "[fix]"], // wrench (🔧)
127
- ["\u{1F5D1}", "[del]"], // wastebasket (🗑)
128
- ["\u{1F310}", "[web]"], // globe with meridians (🌐)
129
- ["\u{1F4BB}", "[pc]"], // personal computer (💻)
130
- ["\u{1F4F1}", "[phone]"], // mobile phone (📱)
131
- ["\u{1F4E7}", "[email]"], // e-mail (📧)
132
- ["\u{1F4CA}", "[chart]"], // bar chart (📊)
133
- ["\u{1F4C8}", "[up]"], // chart with upwards trend (📈)
134
- ["\u{1F4C9}", "[down]"], // chart with downwards trend (📉)
135
- ["\u2764", "[<3]"], // heavy black heart ([<3])
136
- ["\u{1F4AF}", "[100]"], // hundred points (💯)
137
- ["\u{1F44B}", "[wave]"], // waving hand (👋)
138
- ["\u{1F91D}", "[deal]"], // handshake (🤝)
139
- ["\u{1F4AA}", "[strong]"], // flexed biceps (💪)
140
- ["\u{1F914}", "[?]"], // thinking face (🤔)
141
- ["\u{1F644}", "[eye-roll]"], // face with rolling eyes (🙄)
142
- ["\u{1F4A5}", "[boom]"], // collision (💥)
143
- ["\u{1F389}", "[party]"], // party popper (🎉)
144
- ["\u{1F3C6}", "[trophy]"], // trophy (🏆)
145
- ["\u{1F4B0}", "[money]"], // money bag (💰)
146
- ["\u231B", "[wait]"], // hourglass ([wait])
147
- ["\u23F3", "[wait]"], // hourglass with flowing sand ([wait])
148
- ["\u{1F504}", "[refresh]"], // counterclockwise arrows button (🔄)
149
- ["\u2705", "[done]"], // white heavy check mark ([done]) -- already above, kept for completeness
107
+ ["\u{1F525}", ":fire:"], // fire ([fire])
108
+ ["\u{1F680}", ":rocket:"], // rocket ([>>])
109
+ ["\u{1F41B}", ":bug:"], // bug ([bug])
110
+ ["\u{1F41E}", ":beetle:"], // lady beetle ([bug])
111
+ ["\u{1F4DD}", ":memo:"], // memo ([note])
112
+ ["\u270F", ":pencil2:"], // pencil ([note])
113
+ ["\u{1F512}", ":lock:"], // lock ([lock])
114
+ ["\u{1F513}", ":unlock:"], // open lock ([open])
115
+ ["\u{1F4C1}", ":file_folder:"], // file folder ([dir])
116
+ ["\u{1F4C2}", ":open_file_folder:"], // open file folder ([dir])
117
+ ["\u{1F4C4}", ":page_facing_up:"], // page facing up ([file])
118
+ ["\u{1F4C3}", ":page_with_curl:"], // page with curl ([file])
119
+ ["\u{1F44D}", ":+1:"], // thumbs up ([+1])
120
+ ["\u{1F44E}", ":-1:"], // thumbs down ([-1])
121
+ ["\u{1F4AC}", ":speech_balloon:"], // speech balloon ([comment])
122
+ ["\u{1F4E6}", ":package:"], // package ([pkg])
123
+ ["\u{1F517}", ":link:"], // link ([link])
124
+ ["\u{1F6A7}", ":construction:"], // construction sign ([wip])
125
+ ["\u2699", ":gear:"], // gear ([config])
126
+ ["\u{1F527}", ":wrench:"], // wrench ([fix])
127
+ ["\u{1F5D1}", ":wastebasket:"], // wastebasket ([del])
128
+ ["\u{1F310}", ":globe_with_meridians:"], // globe with meridians ([web])
129
+ ["\u{1F4BB}", ":computer:"], // personal computer ([pc])
130
+ ["\u{1F4F1}", ":iphone:"], // mobile phone ([phone])
131
+ ["\u{1F4E7}", ":e-mail:"], // e-mail ([email])
132
+ ["\u{1F4CA}", ":bar_chart:"], // bar chart ([chart])
133
+ ["\u{1F4C8}", ":chart_with_upwards_trend:"], // chart with upwards trend ([up])
134
+ ["\u{1F4C9}", ":chart_with_downwards_trend:"], // chart with downwards trend ([down])
135
+ ["\u2764", ":heart:"], // heavy black heart ([<3])
136
+ ["\u{1F4AF}", ":100:"], // hundred points ([100])
137
+ ["\u{1F44B}", ":wave:"], // waving hand ([wave])
138
+ ["\u{1F91D}", ":handshake:"], // handshake ([deal])
139
+ ["\u{1F4AA}", ":muscle:"], // flexed biceps ([strong])
140
+ ["\u{1F914}", ":thinking:"], // thinking face ([?])
141
+ ["\u{1F644}", ":roll_eyes:"], // face with rolling eyes ([eye-roll])
142
+ ["\u{1F4A5}", ":boom:"], // collision ([boom])
143
+ ["\u{1F389}", ":tada:"], // party popper ([party])
144
+ ["\u{1F3C6}", ":trophy:"], // trophy ([trophy])
145
+ ["\u{1F4B0}", ":moneybag:"], // money bag ([money])
146
+ ["\u231B", ":hourglass:"], // hourglass ([wait])
147
+ ["\u23F3", ":hourglass_flowing_sand:"], // hourglass with flowing sand ([wait])
148
+ ["\u{1F504}", ":arrows_counterclockwise:"], // counterclockwise arrows button ([refresh])
150
149
  ];
151
150
  const DEFAULT_CONFIG = {
152
151
  punctuation: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-ascii",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "OpenCode plugin that substitutes unicode characters with ASCII equivalents in AI responses and file edits",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",