opencode-rtk-plugin 0.1.3 → 1.0.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.
- package/index.js +18 -68
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -4,74 +4,28 @@
|
|
|
4
4
|
// model in a token-efficient form. All rewrite logic lives in rtk itself; this
|
|
5
5
|
// plugin is a thin delegating adapter for OpenCode's shell hook.
|
|
6
6
|
//
|
|
7
|
-
// Requires: rtk (https://github.com/rtk-ai/rtk)
|
|
7
|
+
// Requires: rtk >= 0.23.0 on PATH (https://github.com/rtk-ai/rtk)
|
|
8
8
|
|
|
9
9
|
import { execFile } from "node:child_process";
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
const MAX_TIMEOUT_MS = 600_000;
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Run `rtk rewrite <command>` and resolve to the rewritten command, or null.
|
|
16
|
-
*
|
|
17
|
-
* rtk signals the result on STDOUT, not via exit status: since v0.34.0
|
|
18
|
-
* `rtk rewrite` exits 3 with the rewritten command on stdout (its
|
|
19
|
-
* permission-verdict protocol). So the exit code must be ignored and the
|
|
20
|
-
* decision made on stdout alone.
|
|
21
|
-
*
|
|
22
|
-
* Never rejects and never hangs: a spawn failure, timeout, or empty/unchanged
|
|
23
|
-
* output resolves to null so the original command runs.
|
|
24
|
-
*/
|
|
11
|
+
/** Run `rtk rewrite <command>`; resolve to the rewritten command or null. */
|
|
25
12
|
function rewriteCommand(binary, command, timeoutMs) {
|
|
26
13
|
return new Promise((resolve) => {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
let child;
|
|
37
|
-
try {
|
|
38
|
-
// timeout: 0 disables execFile's own SIGTERM-only timeout; we enforce a
|
|
39
|
-
// hard SIGKILL deadline below so a SIGTERM-ignoring rtk cannot hang.
|
|
40
|
-
child = execFile(
|
|
41
|
-
binary,
|
|
42
|
-
["rewrite", command],
|
|
43
|
-
{ timeout: 0, encoding: "utf8" },
|
|
44
|
-
(_err, stdout) => {
|
|
45
|
-
const out = String(stdout ?? "").trim();
|
|
46
|
-
done(out && out !== command ? out : null);
|
|
47
|
-
}
|
|
48
|
-
);
|
|
49
|
-
} catch {
|
|
50
|
-
return done(null);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
child.on("error", () => done(null));
|
|
54
|
-
|
|
55
|
-
timer = setTimeout(() => {
|
|
56
|
-
try {
|
|
57
|
-
child.kill("SIGKILL");
|
|
58
|
-
} catch {
|
|
59
|
-
/* already gone */
|
|
14
|
+
const child = execFile(
|
|
15
|
+
binary,
|
|
16
|
+
["rewrite", command],
|
|
17
|
+
{ timeout: timeoutMs },
|
|
18
|
+
(err, stdout) => {
|
|
19
|
+
if (err) return resolve(null);
|
|
20
|
+
const rewritten = String(stdout).trim();
|
|
21
|
+
resolve(rewritten && rewritten !== command ? rewritten : null);
|
|
60
22
|
}
|
|
61
|
-
|
|
62
|
-
|
|
23
|
+
);
|
|
24
|
+
// execFile can emit before the callback; never let it surface.
|
|
25
|
+
child.on("error", () => resolve(null));
|
|
63
26
|
});
|
|
64
27
|
}
|
|
65
28
|
|
|
66
|
-
function resolveBinary(value) {
|
|
67
|
-
return typeof value === "string" && value.trim() !== "" ? value : "rtk";
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function resolveTimeout(value) {
|
|
71
|
-
if (Number.isInteger(value) && value >= 1 && value <= MAX_TIMEOUT_MS) return value;
|
|
72
|
-
return DEFAULT_TIMEOUT_MS;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
29
|
export default {
|
|
76
30
|
id: "rtk",
|
|
77
31
|
|
|
@@ -79,17 +33,13 @@ export default {
|
|
|
79
33
|
const options = ctx.options ?? {};
|
|
80
34
|
if (options.enabled === false) return;
|
|
81
35
|
|
|
82
|
-
const binary =
|
|
83
|
-
const timeoutMs =
|
|
36
|
+
const binary = typeof options.binary === "string" ? options.binary : "rtk";
|
|
37
|
+
const timeoutMs = Number.isFinite(options.timeoutMs) ? options.timeoutMs : 5000;
|
|
84
38
|
|
|
85
39
|
await ctx.shell.hook("create.before", async (event) => {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if (rewritten) event.command = rewritten;
|
|
90
|
-
} catch {
|
|
91
|
-
// Never fail the shell call: any error leaves the command unchanged.
|
|
92
|
-
}
|
|
40
|
+
if (!event || typeof event.command !== "string" || !event.command) return;
|
|
41
|
+
const rewritten = await rewriteCommand(binary, event.command, timeoutMs);
|
|
42
|
+
if (rewritten) event.command = rewritten;
|
|
93
43
|
});
|
|
94
44
|
},
|
|
95
45
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencode-rtk-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "OpenCode v2 plugin that rewrites shell commands through rtk to cut LLM token usage by 60-90%.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
44
|
"lint": "markdownlint-cli2 \"**/*.md\"",
|
|
45
|
-
"test": "node --check index.js && node
|
|
45
|
+
"test": "node --check index.js && node -e \"import('./index.js').then(m => { if (!m.default?.id || typeof m.default.setup !== 'function') { console.error('invalid plugin export'); process.exit(1) } console.log('plugin id:', m.default.id) })\"",
|
|
46
46
|
"check": "npm run lint && npm test"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|