impulso 0.21.0 → 0.21.1

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,8 +1,7 @@
1
1
  # Impulso
2
2
 
3
3
  Plugin bundle for opencode + Claude Code: **Plannotator** (vendored skills) +
4
- **Impulso-DirectSpeech** (terse communication mode) + **Impulso-RTK** (token
5
- savings via `rtk rewrite` for 60-90% LLM token savings on shell commands).
4
+ **Impulso-DirectSpeech** (terse communication mode).
6
5
 
7
6
  Harness-neutral repo. Per-harness glue under `harnesses/`.
8
7
 
@@ -12,7 +11,6 @@ Harness-neutral repo. Per-harness glue under `harnesses/`.
12
11
  | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
13
12
  | Plannotator | 3 vendored skills (annotate/last/review) + 3 commands. Skills invoke the `plannotator` CLI binary directly (user-installed); no npm plugin. |
14
13
  | Impulso-DirectSpeech | Terse communication mode — **always active, enforced by the harness**. Ruleset in `shared/AGENTS.md` + per-turn reinforcement hook on each harness. No toggle. 3 auxiliary skills (compress/stats/help). |
15
- | Impulso-RTK | Rewrites bash tool calls via `rtk rewrite` for 60-90% token savings. `rtk` + `tokensave` hard-required and enforced at runtime — launchers, hooks, and plugin block with install hints when missing. |
16
14
 
17
15
  ## Install routes
18
16
 
@@ -36,7 +34,7 @@ Inside any claude session:
36
34
  /plugin install impulso@impulso
37
35
  ```
38
36
 
39
- Loads the three hooks (preflight, rtk rewrite, DirectSpeech reinforcement — via
37
+ Loads the hooks (preflight, DirectSpeech reinforcement — via
40
38
  `${CLAUDE_PLUGIN_ROOT}`), all skills/commands, and the tokensave MCP server.
41
39
  Update later with `/plugin marketplace update impulso`.
42
40
 
@@ -45,8 +43,8 @@ full ruleset in `shared/AGENTS.md`. DirectSpeech still enforces per turn via the
45
43
  hook; for the complete ruleset add an import line to your `~/.claude/CLAUDE.md`
46
44
  pointing at a checked-out copy, or use the installer route instead.
47
45
 
48
- Requires `rtk` + `tokensave` on PATH — the preflight hook blocks prompts
49
- otherwise (that's the point).
46
+ Requires `tokensave` on PATH — the preflight hook blocks prompts otherwise
47
+ (that's the point).
50
48
 
51
49
  ## Install — opencode plugin (recommended)
52
50
 
@@ -162,7 +160,7 @@ To install into `~/.claude/` directly (shared with your normal Claude Code
162
160
  config): `IMPULSO_CLAUDE_PROFILE="$HOME/.claude" ./harnesses/claude/install.sh`
163
161
 
164
162
  See [`harnesses/claude/README.md`](harnesses/claude/README.md) for Plannotator
165
- upstream plugin setup and RTK install.
163
+ upstream plugin setup.
166
164
 
167
165
  ## Install — isolated profiles
168
166
 
@@ -176,35 +174,16 @@ XDG_CONFIG_HOME=~/.config/impulso-profile opencode
176
174
  CLAUDE_CONFIG_DIR=~/.config/impulso-profile/claude claude
177
175
  ```
178
176
 
179
- ## Token savings via RTK (hard-required)
180
-
181
- `rtk` and `tokensave` are enforced at every layer — no degraded mode:
182
-
183
- - `install.sh` scripts abort when either is missing.
184
- - `run_here.sh` / `run_here_claude.sh` launchers fail fast.
185
- - opencode: the Impulso plugin throws at init.
186
- - Claude Code: a UserPromptSubmit preflight hook blocks prompts, and the rtk
187
- PreToolUse hook blocks Bash calls — both with install hints.
188
-
189
- ```bash
190
- brew install rtk
191
- # or: cargo install --git https://github.com/rtk-ai/rtk
192
- # or: curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh
193
- ```
194
-
195
177
  The tokensave MCP server additionally needs a per-project index — run
196
178
  `tokensave init` once in each repo you work in (`.tokensave/` is gitignored
197
179
  globally by the installer).
198
180
 
199
- See [`harnesses/opencode/rtk/README.md`](harnesses/opencode/rtk/README.md).
200
-
201
181
  ## Usage — everything in one place
202
182
 
203
183
  ### Daily use
204
184
 
205
- DirectSpeech is always on — nothing to activate, no off-switch. RTK rewrites run
206
- automatically on every bash call; write plain commands. tokensave MCP tools are
207
- available once `tokensave init` has been run in the project.
185
+ DirectSpeech is always on — nothing to activate, no off-switch. tokensave MCP
186
+ tools are available once `tokensave init` has been run in the project.
208
187
 
209
188
  | Slash command | What it does |
210
189
  | ---------------------------------------- | --------------------------------------------------- |
@@ -427,11 +406,10 @@ impulso/
427
406
  │ ├── install.sh # isolated profile installer
428
407
  │ ├── uninstall.sh # removes the isolated profile
429
408
  │ ├── directspeech/ # DirectSpeech plugin (always-on reinforcement)
430
- │ └── rtk/ # vendored upstream RTK plugin (rtk.ts + README.md)
431
409
  └── claude/ # Claude Code glue
432
410
  ├── install.sh # profile installer (merge-safe for shared profiles)
433
411
  ├── uninstall.sh # targeted reversal — never touches foreign content
434
412
  ├── merge-settings.cjs # settings.json merge (foreign hooks/keys survive)
435
413
  ├── tests.cjs
436
- └── hooks/ # preflight.cjs, rtk.cjs, directspeech-context.cjs
414
+ └── hooks/ # preflight.cjs, directspeech-context.cjs
437
415
  ```
@@ -8,8 +8,8 @@ Glue for running Impulso on Claude Code.
8
8
  ./harnesses/claude/install.sh
9
9
  ```
10
10
 
11
- Idempotent. Hard-requires `rtk` and `tokensave` on PATH (aborts otherwise).
12
- Creates an isolated profile at `~/.config/impulso-profile/claude/`:
11
+ Idempotent. Hard-requires `tokensave` on PATH (aborts otherwise). Creates an
12
+ isolated profile at `~/.config/impulso-profile/claude/`:
13
13
 
14
14
  - Symlinks `skills/` and `commands/` → repo dirs. If the target already has a
15
15
  real dir (shared profiles), bundled entries are linked individually inside it
@@ -58,22 +58,6 @@ Requires the `plannotator` binary:
58
58
  curl -fsSL https://plannotator.ai/install.sh | bash
59
59
  ```
60
60
 
61
- ## RTK (token savings)
62
-
63
- `install.sh` hard-requires the `rtk` binary:
64
-
65
- ```bash
66
- brew install rtk
67
- ```
68
-
69
- PreToolUse hook rewrites Bash commands through `rtk rewrite` (only when rtk
70
- exits 0). Enforcement is runtime, not just install time:
71
-
72
- - `preflight.cjs` (UserPromptSubmit) blocks every prompt while `rtk` or
73
- `tokensave` is missing from PATH, with install hints.
74
- - `rtk.cjs` (PreToolUse) blocks Bash calls when `rtk` is missing.
75
- - A failed rewrite with rtk present passes the command through unchanged.
76
-
77
61
  ## DirectSpeech
78
62
 
79
63
  Always active — enforced by the harness, no toggle, no flag files.
@@ -104,6 +88,5 @@ impulso/harnesses/claude/
104
88
  ├── tests.cjs
105
89
  └── hooks/
106
90
  ├── preflight.cjs
107
- ├── rtk.cjs
108
91
  └── directspeech-context.cjs
109
92
  ```
@@ -1,8 +1,8 @@
1
1
  // impulso preflight hook — Claude Code
2
2
  //
3
- // UserPromptSubmit handler. Enforces the hard-required binaries (rtk,
4
- // tokensave): if either is missing from PATH, exit 2 blocks the prompt and
5
- // surfaces install instructions. Impulso is opinionated — no degraded mode.
3
+ // UserPromptSubmit handler. Enforces the hard-required binaries (tokensave):
4
+ // if it is missing from PATH, exit 2 blocks the prompt and surfaces install
5
+ // instructions. Impulso is opinionated — no degraded mode.
6
6
  //
7
7
  // Hook: UserPromptSubmit
8
8
  //
@@ -12,7 +12,6 @@
12
12
  const { spawnSync } = require('node:child_process');
13
13
 
14
14
  const REQUIRED = [
15
- { bin: 'rtk', hint: 'brew install rtk-ai/tap/rtk' },
16
15
  { bin: 'tokensave', hint: 'brew install aovestdipaperino/tap/tokensave' },
17
16
  { bin: 'plannotator', hint: 'npm i -g plannotator' },
18
17
  ];
@@ -1,15 +1,12 @@
1
1
  // impulso pretooluse-bash dispatcher — Claude Code
2
2
  //
3
- // PreToolUse(Bash) dispatcher. Reads stdin once, runs rtk rewrite then
4
- // bash-state-guard. rtk's exit-2 (missing binary) short-circuits before the
5
- // guard runs.
3
+ // PreToolUse(Bash) dispatcher. Reads stdin once, runs bash-state-guard.
6
4
  //
7
5
  // Hook: PreToolUse (matcher: Bash)
8
6
 
9
7
  'use strict';
10
8
 
11
9
  const path = require('node:path');
12
- const rtk = require(path.join(__dirname, 'rtk.cjs'));
13
10
  const bashStateGuard = require(path.join(__dirname, 'bash-state-guard.cjs'));
14
11
 
15
12
  const chunks = [];
@@ -23,7 +20,7 @@ process.stdin.on('readable', () => {
23
20
  function finish(raw) {
24
21
  if (done) return;
25
22
  done = true;
26
- clearTimeout(timer); // safe: timer defined below before finish can fire
23
+ clearTimeout(timer);
27
24
 
28
25
  let input;
29
26
  try {
@@ -33,33 +30,14 @@ function finish(raw) {
33
30
  return;
34
31
  }
35
32
 
36
- // Stage 1: rtk rewrite (may process.exit(2) if rtk missing)
37
- const rtkResult = rtk.rewriteResult(input);
38
-
39
- // Stage 2: bash-state-guard on the effective (possibly rewritten) input
40
- const effectiveInput = rtkResult
41
- ? { ...input, tool_input: { ...input.tool_input, command: rtkResult.updatedInput.command } }
42
- : input;
43
-
44
- const guard = bashStateGuard.check(effectiveInput);
33
+ // Stage: bash-state-guard
34
+ const guard = bashStateGuard.check(input);
45
35
  if (guard.block) {
46
36
  if (guard.stderr) process.stderr.write(guard.stderr);
47
37
  process.exit(2);
48
38
  return;
49
39
  }
50
40
 
51
- // Emit rewrite result if rtk changed the command
52
- if (rtkResult) {
53
- process.stdout.write(
54
- JSON.stringify({
55
- hookSpecificOutput: {
56
- hookEventName: 'PreToolUse',
57
- updatedInput: rtkResult.updatedInput,
58
- },
59
- }) + '\n',
60
- );
61
- }
62
-
63
41
  process.exit(0);
64
42
  }
65
43
 
@@ -38,7 +38,6 @@ require_bin() {
38
38
  fi
39
39
  }
40
40
 
41
- require_bin rtk "Install: brew install rtk-ai/tap/rtk (see https://www.rtk-ai.app)"
42
41
  require_bin tokensave "Install: brew install aovestdipaperino/tap/tokensave (or: cargo install tokensave)"
43
42
  require_bin plannotator "Install: curl -fsSL https://plannotator.ai/install.sh | bash"
44
43
 
@@ -13,9 +13,8 @@ echo " Repo: ${REPO}"
13
13
  echo " Profile: ${PROFILE_DIR}"
14
14
 
15
15
  # --- Preflight: hard-required binaries -------------------------------------
16
- # Impulso is opinionated: tokensave (MCP server) and rtk (CLI token-filter
17
- # proxy) must be on PATH. Missing either aborts install before touching
18
- # the filesystem.
16
+ # Impulso is opinionated: tokensave (MCP server) must be on PATH.
17
+ # Missing it aborts install before touching the filesystem.
19
18
 
20
19
  require_bin() {
21
20
  local bin="$1"
@@ -27,22 +26,21 @@ require_bin() {
27
26
  fi
28
27
  }
29
28
 
30
- require_bin rtk "Install: brew install rtk-ai/tap/rtk (see https://www.rtk-ai.app)"
31
29
  require_bin tokensave "Install: brew install aovestdipaperino/tap/tokensave (or: cargo install tokensave)"
32
30
 
33
31
  # --- Global gitignore for tool artifacts ------------------------------------
34
- # .tokensave/ (per-project SQLite code graph) and .rtk/ (cache) must never
35
- # land in a target repo. Write to a global git excludesfile so any repo
36
- # the user touches with Impulso is protected. Prompted; default yes.
32
+ # .tokensave/ (per-project SQLite code graph) must never land in a target
33
+ # repo. Write to a global git excludesfile so any repo the user touches with
34
+ # Impulso is protected. Prompted; default yes.
37
35
 
38
36
  ensure_global_gitignore() {
39
37
  local ignore_file="${HOME}/.config/git/ignore"
40
- local entries=(".tokensave/" ".rtk/")
38
+ local entries=(".tokensave/")
41
39
  local answer="y"
42
40
 
43
41
  echo
44
- echo "Impulso can add .tokensave/ and .rtk/ to a global git excludesfile"
45
- echo "so they are never committed to any target repo."
42
+ echo "Impulso can add .tokensave/ to a global git excludesfile"
43
+ echo "so it is never committed to any target repo."
46
44
  printf "Write to %s? [Y/n] " "${ignore_file}"
47
45
  read -r answer || answer=""
48
46
 
@@ -163,7 +163,7 @@ export const ImpulsoOrchestrationPlugin = async (ctx) => {
163
163
 
164
164
  // Disable opencode built-in subagents that would otherwise compete
165
165
  // with impulso-owned roster agents at dispatch time. Built-ins
166
- // have no impulso rules, no rtk integration, no path-guard. scout is
166
+ // have no impulso rules, no path-guard. scout is
167
167
  // NOT disabled — impulso's own scout registration overrides by name.
168
168
  for (const name of DISABLED_BUILTINS) {
169
169
  config.agent[name] = { disable: true };
@@ -22,12 +22,7 @@ import { installHub } from '../../scripts/install-hub.js';
22
22
  const here = path.dirname(fileURLToPath(import.meta.url));
23
23
  const pkgRoot = path.resolve(here, '..', '..');
24
24
 
25
- // Impulso is opinionated: rtk and tokensave are hard-required at runtime,
26
- // not just at install time. Throw at plugin init so the failure is loud
27
- // ([impulso] in logs — integration tests grep for it) instead of a silently
28
- // degraded session.
29
25
  const REQUIRED_BINARIES = [
30
- { bin: 'rtk', hint: 'brew install rtk-ai/tap/rtk' },
31
26
  { bin: 'tokensave', hint: 'brew install aovestdipaperino/tap/tokensave' },
32
27
  { bin: 'plannotator', hint: 'curl -fsSL https://plannotator.ai/install.sh | bash' },
33
28
  ];
@@ -2,7 +2,7 @@
2
2
  set -euo pipefail
3
3
 
4
4
  # Impulso opencode uninstall — removes the isolated profile created by
5
- # install.sh. Global gitignore entries (.tokensave/, .rtk/) are left in
5
+ # install.sh. Global gitignore entries (.tokensave/) are left in
6
6
  # place — they are protective and harmless; remove manually if unwanted.
7
7
 
8
8
  PROFILE_DIR="${HOME}/.config/impulso-profile/opencode"
@@ -33,4 +33,4 @@ if [[ -f "${OLD_GATE}" || -L "${OLD_GATE}" ]]; then
33
33
  echo " Removed old impulso-gate binary"
34
34
  fi
35
35
 
36
- echo "==> Done. Global gitignore entries (.tokensave/, .rtk/) left in place."
36
+ echo "==> Done. Global gitignore entries (.tokensave/) left in place."
@@ -3,7 +3,7 @@
3
3
  "small_model": "opencode/big-pickle",
4
4
  "model": "proxycli/deepseek-v4-flash",
5
5
  "instructions": ["AGENTS.md"],
6
- "plugin": ["../harnesses/opencode/plugin.js", "../harnesses/opencode/rtk/rtk.ts"],
6
+ "plugin": ["../harnesses/opencode/plugin.js"],
7
7
  "mcp": {
8
8
  "tokensave": {
9
9
  "type": "local",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "impulso",
3
- "version": "0.21.0",
4
- "description": "Impulso — plugin bundle for opencode and Claude Code: Plannotator skills + Impulso-DirectSpeech (rethemed ex-Caveman) + RTK. Harness-neutral repo; per-harness glue under harnesses/.",
3
+ "version": "0.21.1",
4
+ "description": "Impulso — plugin bundle for opencode and Claude Code: Plannotator skills + Impulso-DirectSpeech (rethemed ex-Caveman). Harness-neutral repo; per-harness glue under harnesses/.",
5
5
  "type": "module",
6
6
  "main": "harnesses/opencode/plugin.js",
7
7
  "publishConfig": {
@@ -50,7 +50,6 @@
50
50
  "harnesses/opencode/install.sh",
51
51
  "harnesses/opencode/orchestration",
52
52
  "harnesses/opencode/plugin.js",
53
- "harnesses/opencode/rtk",
54
53
  "harnesses/opencode/session-name",
55
54
  "harnesses/opencode/sync-commands.js",
56
55
  "harnesses/opencode/uninstall.sh",
@@ -88,7 +87,6 @@
88
87
  "plannotator",
89
88
  "impulso",
90
89
  "directspeech",
91
- "rtk",
92
90
  "plugin"
93
91
  ],
94
92
  "license": "MIT",
@@ -85,7 +85,7 @@ const ROSTER = {
85
85
  // -----------------------------------------------------------------------
86
86
  // DISABLED_BUILTINS
87
87
  // opencode built-in subagents impulso disables at config-write time to prevent
88
- // the LLM orchestrator from dispatching a built-in (no impulso rules, no rtk,
88
+ // the LLM orchestrator from dispatching a built-in (no impulso rules,
89
89
  // no path-guard) instead of an impulso-owned roster agent. `scout` is NOT
90
90
  // listed: impulso's own `scout` registration overrides the built-in by name.
91
91
  // -----------------------------------------------------------------------
@@ -1,87 +0,0 @@
1
- // impulso rtk hook — Claude Code
2
- //
3
- // PreToolUse Bash handler. Rewrites bash commands through `rtk rewrite`
4
- // for token savings. Mirrors the opencode rtk.ts plugin behavior.
5
- //
6
- // Hook: PreToolUse (matcher: Bash)
7
- //
8
- // Exported for use by pretooluse-bash.cjs dispatcher:
9
- // rewriteResult(input) -> { updatedInput: {command} } | null
10
- // Returns null when tool is not Bash, command is empty, or rtk exits
11
- // non-zero. May process.exit(2) if rtk is missing from PATH.
12
-
13
- const { spawnSync } = require('node:child_process');
14
-
15
- // Returns the rewritten command, or null to pass through unchanged.
16
- //
17
- // rtk is hard-required: missing from PATH (spawn ENOENT) blocks the Bash
18
- // call — exit 2 makes Claude Code reject the tool use and feeds stderr back
19
- // to the model. Do not fall back to raw commands; fix the install.
20
- //
21
- // A non-zero exit with rtk PRESENT means this particular rewrite failed —
22
- // pass through unchanged (rtk's partial stdout must not be trusted).
23
- function rewrite(command) {
24
- const r = spawnSync('rtk', ['rewrite', command], {
25
- encoding: 'utf8',
26
- stdio: ['ignore', 'pipe', 'pipe'],
27
- timeout: 5000,
28
- });
29
- if (r.error && r.error.code === 'ENOENT') {
30
- process.stderr.write(
31
- 'impulso: rtk is hard-required but missing from PATH. ' +
32
- 'Install: brew install rtk-ai/tap/rtk\n',
33
- );
34
- process.exit(2);
35
- }
36
- if (r.error || r.status !== 0) return null;
37
- return r.stdout.trim();
38
- }
39
-
40
- // Pure function: evaluate rtk rewrite for a hook input payload.
41
- // Returns { updatedInput: { command } } when rtk rewrites the command,
42
- // null otherwise. May process.exit(2) if rtk is missing from PATH.
43
- function rewriteResult(input) {
44
- const toolName = (input.tool_name || '').toLowerCase();
45
- if (toolName !== 'bash' && toolName !== 'shell') return null;
46
- const command = input.tool_input && input.tool_input.command;
47
- if (typeof command !== 'string' || !command) return null;
48
- const rewritten = rewrite(command);
49
- if (rewritten && rewritten !== command) {
50
- return { updatedInput: { command: rewritten } };
51
- }
52
- return null;
53
- }
54
-
55
- module.exports = { rewriteResult };
56
-
57
- function main() {
58
- const chunks = [];
59
- process.stdin.setEncoding('utf8');
60
- process.stdin.on('readable', () => {
61
- let chunk;
62
- while ((chunk = process.stdin.read()) !== null) {
63
- chunks.push(chunk);
64
- }
65
- });
66
-
67
- process.stdin.on('end', () => {
68
- try {
69
- const input = JSON.parse(chunks.join(''));
70
- const result = rewriteResult(input);
71
- if (result) {
72
- process.stdout.write(
73
- JSON.stringify({
74
- hookSpecificOutput: {
75
- hookEventName: 'PreToolUse',
76
- updatedInput: result.updatedInput,
77
- },
78
- }) + '\n',
79
- );
80
- }
81
- } catch (e) {
82
- // Parse / filesystem errors — pass through unchanged
83
- }
84
- });
85
- }
86
-
87
- if (require.main === module) main();
@@ -1,100 +0,0 @@
1
- # Impulso-RTK (opencode harness)
2
-
3
- Vendored OpenCode plugin for [RTK](https://github.com/rtk-ai/rtk) — the Rust CLI
4
- proxy that reduces LLM token consumption 60-90% on common shell commands (`git`,
5
- `cargo`, `pytest`, `tsc`, `docker`, `kubectl`, `aws`, …).
6
-
7
- ## Attribution
8
-
9
- Vendored verbatim from
10
- [`hooks/opencode/rtk.ts`](https://github.com/rtk-ai/rtk/blob/develop/hooks/opencode/rtk.ts)
11
- in the upstream RTK repo (Apache-2.0). All rewrite logic lives in the `rtk`
12
- binary; this file is a thin OpenCode plugin glue that shells out to
13
- `rtk rewrite <command>`.
14
-
15
- To check for upstream changes:
16
-
17
- ```bash
18
- diff harnesses/opencode/rtk/rtk.ts \
19
- <(curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/develop/hooks/opencode/rtk.ts)
20
- ```
21
-
22
- Empty diff = up to date.
23
-
24
- ## Architecture
25
-
26
- Single hook on the opencode plugin system:
27
-
28
- ```
29
- user runs bash tool (e.g. "git status")
30
- ───► tool.execute.before() fires
31
- ───► plugin calls `rtk rewrite "git status"` as subprocess
32
- ───► rtk returns "rtk git status"
33
- ───► plugin mutates args.command in-place
34
- ───► opencode executes "rtk git status"
35
- ───► filtered output reaches LLM (~200 tokens instead of ~2,000)
36
- ```
37
-
38
- If the `rtk` binary is not on `$PATH` at plugin load time, the plugin logs a
39
- warning and returns no hooks — opencode proceeds with raw commands. No crash, no
40
- broken sessions.
41
-
42
- ## Prerequisite — install the rtk binary
43
-
44
- The plugin requires `rtk >= 0.23.0` on `$PATH`. Impulso does not install it for
45
- you. Pick one:
46
-
47
- ### Homebrew (recommended on macOS / Linuxbrew)
48
-
49
- ```bash
50
- brew install rtk
51
- ```
52
-
53
- ### Quick install (Linux / macOS)
54
-
55
- ```bash
56
- curl -fsSL https://raw.githubusercontent.com/rtk-ai/rtk/refs/heads/master/install.sh | sh
57
- ```
58
-
59
- Installs to `~/.local/bin`. Add to PATH if needed:
60
-
61
- ```bash
62
- echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc # or ~/.zshrc
63
- ```
64
-
65
- ### Cargo
66
-
67
- ```bash
68
- cargo install --git https://github.com/rtk-ai/rtk
69
- ```
70
-
71
- ### Verify
72
-
73
- ```bash
74
- rtk --version # should print "rtk 0.23.0" or higher
75
- rtk gain # shows token savings stats
76
- ```
77
-
78
- > Name collision warning: another crates.io package named `rtk` (Rust Type Kit)
79
- > exists. If `rtk gain` fails, you have the wrong package. Use
80
- > `cargo install --git` above instead.
81
-
82
- ## File overview
83
-
84
- ```
85
- harnesses/opencode/rtk/
86
- ├── rtk.ts # opencode plugin (vendored verbatim from upstream)
87
- └── README.md # this file
88
- ```
89
-
90
- ## Disabling
91
-
92
- Three ways to opt out without uninstalling:
93
-
94
- - Per-command: prefix with `RTK_DISABLED=1` (e.g. `RTK_DISABLED=1 git status`
95
- runs raw `git status`).
96
- - Permanent exclusions: list commands in `~/.config/rtk/config.toml` under
97
- `[hooks] exclude_commands = ["curl", "playwright"]`.
98
- - Remove the plugin: delete the `../harnesses/opencode/rtk/rtk.ts` entry from
99
- the `plugin` array in `opencode/opencode.jsonc` (and from
100
- `harnesses/opencode/install.sh` heredoc if using installed profile).
@@ -1,41 +0,0 @@
1
- import type { Plugin } from "@opencode-ai/plugin"
2
-
3
- // RTK OpenCode plugin — rewrites commands to use rtk for token savings.
4
- // Requires: rtk >= 0.23.0 in PATH.
5
- //
6
- // This is a thin delegating plugin: all rewrite logic lives in `rtk rewrite`,
7
- // which is the single source of truth (src/discover/registry.rs).
8
- // To add or change rewrite rules, edit the Rust registry — not this file.
9
-
10
- export const RtkOpenCodePlugin: Plugin = async ({ $ }) => {
11
- try {
12
- await $`which rtk`.quiet()
13
- } catch {
14
- console.warn("[rtk] rtk binary not found in PATH — plugin disabled")
15
- return {}
16
- }
17
-
18
- return {
19
- "tool.execute.before": async (input, output) => {
20
- const tool = String(input?.tool ?? "").toLowerCase()
21
- if (tool !== "bash" && tool !== "shell") return
22
- const args = output?.args
23
- if (!args || typeof args !== "object") return
24
-
25
- const command = (args as Record<string, unknown>).command
26
- if (typeof command !== "string" || !command) return
27
-
28
- try {
29
- const result = await $`rtk rewrite ${command}`.quiet().nothrow()
30
- // Non-zero exit: rtk failed — never trust partial stdout as a command.
31
- if (result.exitCode !== 0) return
32
- const rewritten = String(result.stdout).trim()
33
- if (rewritten && rewritten !== command) {
34
- ;(args as Record<string, unknown>).command = rewritten
35
- }
36
- } catch {
37
- // rtk rewrite failed — pass through unchanged
38
- }
39
- },
40
- }
41
- }