opencode-ascii 0.1.1 → 0.1.3
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/dist/index.d.ts +3 -2
- package/dist/index.js +24 -16
- package/dist/substitutions.js +60 -66
- package/package.json +15 -4
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Plugin } from "@opencode-ai/plugin";
|
|
2
|
-
import { type SubstitutionConfig } from "./substitutions
|
|
2
|
+
import { type SubstitutionConfig } from "./substitutions";
|
|
3
3
|
/**
|
|
4
4
|
* Options accepted by AsciiPlugin.
|
|
5
5
|
*
|
|
@@ -19,6 +19,7 @@ export type AsciiPluginOptions = SubstitutionConfig;
|
|
|
19
19
|
*
|
|
20
20
|
* Covered hooks:
|
|
21
21
|
* - `experimental.text.complete` : rewrites completed AI text parts
|
|
22
|
-
* - `tool.execute.before` : rewrites `write` and `
|
|
22
|
+
* - `tool.execute.before` : rewrites `write`, `edit`, `multiedit`, and `apply_patch` tool arguments
|
|
23
23
|
*/
|
|
24
24
|
export declare const AsciiPlugin: Plugin;
|
|
25
|
+
export default AsciiPlugin;
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AsciiPlugin = void 0;
|
|
4
|
-
const substitutions_js_1 = require("./substitutions.js");
|
|
1
|
+
import { buildSubstitutions, buildRegex, applySubstitutions, } from "./substitutions";
|
|
5
2
|
function resolveConfig(options) {
|
|
6
3
|
if (!options)
|
|
7
4
|
return {};
|
|
@@ -22,11 +19,11 @@ function resolveConfig(options) {
|
|
|
22
19
|
*
|
|
23
20
|
* Covered hooks:
|
|
24
21
|
* - `experimental.text.complete` : rewrites completed AI text parts
|
|
25
|
-
* - `tool.execute.before` : rewrites `write` and `
|
|
22
|
+
* - `tool.execute.before` : rewrites `write`, `edit`, `multiedit`, and `apply_patch` tool arguments
|
|
26
23
|
*/
|
|
27
|
-
const AsciiPlugin = async (_ctx, options) => {
|
|
24
|
+
export const AsciiPlugin = async (_ctx, options) => {
|
|
28
25
|
const config = resolveConfig(options);
|
|
29
|
-
const substitutions =
|
|
26
|
+
const substitutions = buildSubstitutions(config);
|
|
30
27
|
if (substitutions.length === 0) {
|
|
31
28
|
// All categories disabled — nothing to do.
|
|
32
29
|
return {};
|
|
@@ -35,11 +32,11 @@ const AsciiPlugin = async (_ctx, options) => {
|
|
|
35
32
|
// Reset regex lastIndex before reuse by always using a fresh call to
|
|
36
33
|
// buildRegex; the 'g' flag is stateful so we rebuild per call or use
|
|
37
34
|
// a factory. We build once and rely on String.prototype.replace resetting it.
|
|
38
|
-
const regex =
|
|
35
|
+
const regex = buildRegex(substitutions);
|
|
39
36
|
function substitute(text) {
|
|
40
37
|
// Reset the regex state (stateful with /g flag)
|
|
41
38
|
regex.lastIndex = 0;
|
|
42
|
-
return
|
|
39
|
+
return applySubstitutions(text, regex, map);
|
|
43
40
|
}
|
|
44
41
|
return {
|
|
45
42
|
/**
|
|
@@ -56,9 +53,10 @@ const AsciiPlugin = async (_ctx, options) => {
|
|
|
56
53
|
* Rewrite file-writing tool arguments before execution.
|
|
57
54
|
*
|
|
58
55
|
* Tools handled:
|
|
59
|
-
* - `write`
|
|
60
|
-
* - `edit`
|
|
61
|
-
* - `
|
|
56
|
+
* - `write` : `args.content`
|
|
57
|
+
* - `edit` : `args.newString` (NOT `oldString` -- it must match existing file content)
|
|
58
|
+
* - `multiedit` : each `args.edits[].newString`
|
|
59
|
+
* - `apply_patch` : `args.patchText` (unified diff content)
|
|
62
60
|
*/
|
|
63
61
|
"tool.execute.before": async (input, output) => {
|
|
64
62
|
switch (input.tool) {
|
|
@@ -74,9 +72,19 @@ const AsciiPlugin = async (_ctx, options) => {
|
|
|
74
72
|
}
|
|
75
73
|
break;
|
|
76
74
|
}
|
|
77
|
-
case "
|
|
78
|
-
if (
|
|
79
|
-
|
|
75
|
+
case "multiedit": {
|
|
76
|
+
if (Array.isArray(output.args?.edits)) {
|
|
77
|
+
for (const edit of output.args.edits) {
|
|
78
|
+
if (typeof edit?.newString === "string") {
|
|
79
|
+
edit.newString = substitute(edit.newString);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
case "apply_patch": {
|
|
86
|
+
if (typeof output.args?.patchText === "string") {
|
|
87
|
+
output.args.patchText = substitute(output.args.patchText);
|
|
80
88
|
}
|
|
81
89
|
break;
|
|
82
90
|
}
|
|
@@ -84,4 +92,4 @@ const AsciiPlugin = async (_ctx, options) => {
|
|
|
84
92
|
},
|
|
85
93
|
};
|
|
86
94
|
};
|
|
87
|
-
|
|
95
|
+
export default AsciiPlugin;
|
package/dist/substitutions.js
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
|
-
"use strict";
|
|
2
1
|
/**
|
|
3
2
|
* Unicode → ASCII substitution mappings, organised by category.
|
|
4
3
|
* Each entry is a tuple of [unicode, ascii].
|
|
5
4
|
*/
|
|
6
|
-
|
|
7
|
-
exports.EMOJIS = exports.MATH = exports.ARROWS = exports.PUNCTUATION = void 0;
|
|
8
|
-
exports.buildSubstitutions = buildSubstitutions;
|
|
9
|
-
exports.buildRegex = buildRegex;
|
|
10
|
-
exports.applySubstitutions = applySubstitutions;
|
|
11
|
-
exports.PUNCTUATION = [
|
|
5
|
+
export const PUNCTUATION = [
|
|
12
6
|
// Dashes
|
|
13
7
|
["\u2014", "--"], // em dash (—)
|
|
14
8
|
["\u2013", "-"], // en dash (–)
|
|
@@ -39,7 +33,7 @@ exports.PUNCTUATION = [
|
|
|
39
33
|
["\u2032", "'"], // prime (′)
|
|
40
34
|
["\u2033", '"'], // double prime (″)
|
|
41
35
|
];
|
|
42
|
-
|
|
36
|
+
export const ARROWS = [
|
|
43
37
|
["\u2192", "->"], // rightwards arrow (→)
|
|
44
38
|
["\u2190", "<-"], // leftwards arrow (←)
|
|
45
39
|
["\u2191", "^"], // upwards arrow (↑)
|
|
@@ -58,7 +52,7 @@ exports.ARROWS = [
|
|
|
58
52
|
["\u2B06", "^"], // upwards black arrow (⬆)
|
|
59
53
|
["\u2B07", "v"], // downwards black arrow (⬇)
|
|
60
54
|
];
|
|
61
|
-
|
|
55
|
+
export const MATH = [
|
|
62
56
|
["\u2260", "!="], // not equal to (≠)
|
|
63
57
|
["\u2264", "<="], // less-than or equal to (≤)
|
|
64
58
|
["\u2265", ">="], // greater-than or equal to (≥)
|
|
@@ -86,7 +80,7 @@ exports.MATH = [
|
|
|
86
80
|
["\u2234", ":."], // therefore (∴)
|
|
87
81
|
["\u2235", ":'"], // because (∵)
|
|
88
82
|
];
|
|
89
|
-
|
|
83
|
+
export const EMOJIS = [
|
|
90
84
|
// Checkmarks / cross marks
|
|
91
85
|
["\u2713", "[x]"], // check mark (✓)
|
|
92
86
|
["\u2714", "[x]"], // heavy check mark (✔)
|
|
@@ -102,57 +96,57 @@ exports.EMOJIS = [
|
|
|
102
96
|
["\u2755", "[!]"], // white exclamation mark ornament (❕)
|
|
103
97
|
["\u26A1", "[!]"], // high voltage sign (⚡)
|
|
104
98
|
// Info / ideas
|
|
105
|
-
["\u2139", "[i]"], // information source (
|
|
106
|
-
["\
|
|
99
|
+
["\u2139", "[i]"], // information source ([i])
|
|
100
|
+
["\u{1F4A1}", "[i]"], // light bulb (💡)
|
|
107
101
|
// Stars / rating
|
|
108
|
-
["\u2B50", "[*]"], // white medium star (
|
|
109
|
-
["\
|
|
110
|
-
["\u2605", "[*]"], // black star (
|
|
111
|
-
["\u2606", "[*]"], // white star (
|
|
102
|
+
["\u2B50", "[*]"], // white medium star ([*])
|
|
103
|
+
["\u{1F31F}", "[*]"], // glowing star (🌟)
|
|
104
|
+
["\u2605", "[*]"], // black star ([*])
|
|
105
|
+
["\u2606", "[*]"], // white star ([*])
|
|
112
106
|
// Common emoji sequences
|
|
113
|
-
["\
|
|
114
|
-
["\
|
|
115
|
-
["\
|
|
116
|
-
["\
|
|
117
|
-
["\
|
|
118
|
-
["\u270F", "[note]"], // pencil (
|
|
119
|
-
["\
|
|
120
|
-
["\
|
|
121
|
-
["\
|
|
122
|
-
["\
|
|
123
|
-
["\
|
|
124
|
-
["\
|
|
125
|
-
["\
|
|
126
|
-
["\
|
|
127
|
-
["\
|
|
128
|
-
["\
|
|
129
|
-
["\
|
|
130
|
-
["\
|
|
131
|
-
["\u2699", "[config]"], // gear (
|
|
132
|
-
["\
|
|
133
|
-
["\
|
|
134
|
-
["\
|
|
135
|
-
["\
|
|
136
|
-
["\
|
|
137
|
-
["\
|
|
138
|
-
["\
|
|
139
|
-
["\
|
|
140
|
-
["\
|
|
141
|
-
["\u2764", "[<3]"], // heavy black heart (
|
|
142
|
-
["\
|
|
143
|
-
["\
|
|
144
|
-
["\
|
|
145
|
-
["\
|
|
146
|
-
["\
|
|
147
|
-
["\
|
|
148
|
-
["\
|
|
149
|
-
["\
|
|
150
|
-
["\
|
|
151
|
-
["\
|
|
152
|
-
["\u231B", "[wait]"], // hourglass (
|
|
153
|
-
["\u23F3", "[wait]"], // hourglass with flowing sand (
|
|
154
|
-
["\
|
|
155
|
-
["\u2705", "[done]"], // white heavy check mark (
|
|
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
|
|
156
150
|
];
|
|
157
151
|
const DEFAULT_CONFIG = {
|
|
158
152
|
punctuation: true,
|
|
@@ -163,24 +157,24 @@ const DEFAULT_CONFIG = {
|
|
|
163
157
|
/**
|
|
164
158
|
* Build a combined substitution map from enabled categories.
|
|
165
159
|
*/
|
|
166
|
-
function buildSubstitutions(config = {}) {
|
|
160
|
+
export function buildSubstitutions(config = {}) {
|
|
167
161
|
const resolved = { ...DEFAULT_CONFIG, ...config };
|
|
168
162
|
const entries = [];
|
|
169
163
|
if (resolved.punctuation)
|
|
170
|
-
entries.push(...
|
|
164
|
+
entries.push(...PUNCTUATION);
|
|
171
165
|
if (resolved.arrows)
|
|
172
|
-
entries.push(...
|
|
166
|
+
entries.push(...ARROWS);
|
|
173
167
|
if (resolved.math)
|
|
174
|
-
entries.push(...
|
|
168
|
+
entries.push(...MATH);
|
|
175
169
|
if (resolved.emojis)
|
|
176
|
-
entries.push(...
|
|
170
|
+
entries.push(...EMOJIS);
|
|
177
171
|
return entries;
|
|
178
172
|
}
|
|
179
173
|
/**
|
|
180
174
|
* Build a compiled RegExp that matches all active unicode characters at once.
|
|
181
175
|
* This is much faster than running replace() N times.
|
|
182
176
|
*/
|
|
183
|
-
function buildRegex(substitutions) {
|
|
177
|
+
export function buildRegex(substitutions) {
|
|
184
178
|
const pattern = substitutions
|
|
185
179
|
.map(([ch]) => ch.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
|
|
186
180
|
.join("|");
|
|
@@ -189,6 +183,6 @@ function buildRegex(substitutions) {
|
|
|
189
183
|
/**
|
|
190
184
|
* Apply substitutions to a string using a pre-built map and regex.
|
|
191
185
|
*/
|
|
192
|
-
function applySubstitutions(text, regex, map) {
|
|
186
|
+
export function applySubstitutions(text, regex, map) {
|
|
193
187
|
return text.replace(regex, (match) => map.get(match) ?? match);
|
|
194
188
|
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-ascii",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "OpenCode plugin that substitutes unicode characters with ASCII equivalents in AI responses and file edits",
|
|
5
|
-
"
|
|
6
|
-
"
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
7
15
|
"files": [
|
|
8
16
|
"dist"
|
|
9
17
|
],
|
|
10
18
|
"scripts": {
|
|
11
19
|
"build": "tsc",
|
|
20
|
+
"test": "vitest run",
|
|
21
|
+
"test:watch": "vitest",
|
|
12
22
|
"prepublishOnly": "npm run build"
|
|
13
23
|
},
|
|
14
24
|
"peerDependencies": {
|
|
@@ -16,7 +26,8 @@
|
|
|
16
26
|
},
|
|
17
27
|
"devDependencies": {
|
|
18
28
|
"@opencode-ai/plugin": "latest",
|
|
19
|
-
"typescript": "^5"
|
|
29
|
+
"typescript": "^5",
|
|
30
|
+
"vitest": "^4.1.2"
|
|
20
31
|
},
|
|
21
32
|
"keywords": [
|
|
22
33
|
"opencode",
|