@mrclrchtr/supi-rtk 1.3.1 → 1.4.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @mrclrchtr/supi-rtk
2
2
 
3
- Transparent RTK-backed bash rewriting for the [pi coding agent](https://github.com/earendil-works/pi).
3
+ Adds RTK-backed bash rewriting to the [pi coding agent](https://github.com/earendil-works/pi).
4
4
 
5
5
  ## Install
6
6
 
@@ -8,48 +8,74 @@ Transparent RTK-backed bash rewriting for the [pi coding agent](https://github.c
8
8
  pi install npm:@mrclrchtr/supi-rtk
9
9
  ```
10
10
 
11
- > **🧪 Beta package** not included in the `@mrclrchtr/supi` meta-package.
12
- > Install directly when you want RTK-backed bash rewriting.
11
+ This is a **beta** package. It is not bundled in `@mrclrchtr/supi`.
13
12
 
14
- ## What it adds
13
+ For local development:
15
14
 
16
- This extension wraps the `bash` tool and tries to rewrite commands through the [RTK CLI](https://github.com/joshcho/RTK) before execution.
15
+ ```bash
16
+ pi install ./packages/supi-rtk
17
+ ```
17
18
 
18
- The goal is lower token usage for repetitive shell commands while preserving the original command when rewriting is unsafe or unavailable.
19
+ After editing the source, run `/reload`.
19
20
 
20
- ## Rewrite flow
21
+ ## What you get
21
22
 
22
- ```text
23
- bash tool call
24
-
25
- guards.ts checks known lossy collisions
26
-
27
- rewrite.ts runs `rtk rewrite <command>`
28
-
29
- rewritten command or original fallback executes
30
-
31
- tracking.ts records rewrite/fallback stats
32
- ```
23
+ After install, the package intercepts bash execution in two places:
33
24
 
34
- ## Safety guards
25
+ - model `bash` tool calls
26
+ - `user_bash` execution paths
35
27
 
36
- Known lossy rewrites are passed through without RTK mediation, including current Biome and ripgrep collision cases.
28
+ For each command, it tries to run `rtk rewrite <command>` first. If RTK returns a usable rewrite, the rewritten command is executed. If not, the original command runs unchanged.
37
29
 
38
- ## Requirements
30
+ ## Fallback and guard behavior
39
31
 
40
- - `@earendil-works/pi-coding-agent`
41
- - `@earendil-works/pi-tui`
42
- - `@mrclrchtr/supi-core`
43
- - RTK CLI available on `PATH`
32
+ The package falls back to normal bash execution when:
44
33
 
45
- ## Development
34
+ - RTK is disabled in settings
35
+ - the `rtk` binary is not available on `PATH`
36
+ - the rewrite times out
37
+ - RTK exits without usable output
38
+ - a guard rule decides the command should bypass rewriting
46
39
 
47
- ```bash
48
- pnpm vitest run packages/supi-rtk/
49
- pnpm exec tsc --noEmit -p packages/supi-rtk/tsconfig.json
50
- pnpm exec biome check packages/supi-rtk/
40
+ Current bypass rules include:
41
+
42
+ - commands prefixed with `RTK_DISABLED=1` or `env RTK_DISABLED=1`
43
+ - commands that invoke `biome`
44
+ - `rg` commands
45
+ - package-manager `lint` commands in projects that use Biome
46
+
47
+ These guards exist because the current RTK rewrite path can be lossy for those command shapes.
48
+
49
+ ## Settings
50
+
51
+ This package registers an **RTK** section in `/supi-settings`.
52
+
53
+ Available settings:
54
+
55
+ - `enabled` — turn RTK rewriting on or off
56
+ - `rewriteTimeout` — timeout in milliseconds for `rtk rewrite`
57
+
58
+ Defaults:
59
+
60
+ ```json
61
+ {
62
+ "rtk": {
63
+ "enabled": true,
64
+ "rewriteTimeout": 5000
65
+ }
66
+ }
51
67
  ```
52
68
 
53
- ## License
69
+ ## Extra integration
70
+
71
+ - registers an **RTK** provider section for `/supi-context`
72
+ - tracks successful rewrites, fallbacks, and estimated token savings for the current session
73
+ - records debug events through `supi-core`'s debug registry, so `supi-debug` can inspect rewrite and fallback activity when installed
74
+ - warns once per session when RTK is enabled but the `rtk` binary is missing
75
+
76
+ ## Source
54
77
 
55
- MIT
78
+ - `src/rtk.ts` — extension wiring, bash interception, settings, and context-provider registration
79
+ - `src/rewrite.ts` — `rtk rewrite` execution and result classification
80
+ - `src/guards.ts` — bypass rules for known lossy rewrites
81
+ - `src/tracking.ts` — per-session rewrite statistics
@@ -1,65 +1,78 @@
1
1
  # @mrclrchtr/supi-core
2
2
 
3
- Shared infrastructure for SuPi packages.
3
+ Shared infrastructure for SuPi extensions.
4
+
5
+ This package is mainly for extension authors. It gives you a common config system, settings plumbing, context helpers, registries, and a small extension surface that registers `/supi-settings`.
4
6
 
5
7
  ## Install
6
8
 
7
- Use it as a dependency in another extension package:
9
+ ### As a dependency for another extension
8
10
 
9
11
  ```bash
10
12
  pnpm add @mrclrchtr/supi-core
11
13
  ```
12
14
 
13
- ## Package role
14
-
15
- `@mrclrchtr/supi-core` now has two explicit surfaces:
15
+ ### As a pi package
16
16
 
17
- - `@mrclrchtr/supi-core/api` — shared library helpers for other SuPi packages
18
- - `@mrclrchtr/supi-core/extension` — a minimal pi extension that registers `/supi-settings`
19
-
20
- `pi.extensions` still points at the real file path `./src/extension.ts` inside the package. The `/api` and `/extension` paths are consumer-facing package exports, not manifest aliases.
17
+ ```bash
18
+ pi install npm:@mrclrchtr/supi-core
19
+ ```
21
20
 
22
- ## What it provides
21
+ Installing it as a pi package adds the minimal `/supi-settings` extension surface.
23
22
 
24
- Current exports cover:
23
+ ## Package surfaces
25
24
 
26
- - shared config loading, scoped reads, writes, and key removal
27
- - config-backed settings registration helpers for `/supi-settings`
28
- - the shared settings registry, overlay UI, and `registerSettingsCommand()` helper
29
- - XML `<extension-context>` wrapping plus context-message utilities
30
- - context-provider and debug-event registries reused across SuPi packages
31
- - project root and path helpers reused by packages such as `supi-lsp`
25
+ - `@mrclrchtr/supi-core/api` reusable helpers for other packages and extensions
26
+ - `@mrclrchtr/supi-core/extension` minimal pi extension that registers `/supi-settings`
32
27
 
33
- ## Config system
28
+ ## What you get from the API
34
29
 
35
- Config resolution order:
30
+ ### Config helpers
36
31
 
37
- ```text
38
- defaults <- global <- project
39
- ```
32
+ - `loadSupiConfig()` — merged config with resolution order `defaults <- global <- project`
33
+ - `loadSupiConfigForScope()` load one scope at a time for settings UIs
34
+ - `writeSupiConfig()` — persist values
35
+ - `removeSupiConfigKey()` — remove a key or override
40
36
 
41
37
  Config file locations:
42
38
 
43
39
  - global: `~/.pi/agent/supi/config.json`
44
40
  - project: `.pi/supi/config.json`
45
41
 
46
- Main helpers:
42
+ ### Settings helpers
43
+
44
+ - `registerSettings()` — register an arbitrary settings section
45
+ - `registerConfigSettings()` — register a config-backed settings section with scoped persistence helpers
46
+ - `registerSettingsCommand()` — register `/supi-settings`
47
+ - `openSettingsOverlay()` — open the shared settings UI directly
48
+ - `createInputSubmenu()` — helper for simple text-entry submenus
49
+
50
+ The built-in settings UI supports:
47
51
 
48
- - `loadSupiConfig()` — effective merged config (`defaults <- global <- project`)
49
- - `loadSupiConfigForScope()` raw single-scope config for settings UIs (`defaults <- selected scope`)
50
- - `writeSupiConfig()`
51
- - `removeSupiConfigKey()`
52
- - `registerConfigSettings()`
52
+ - project/global scope toggle
53
+ - grouped extension sections
54
+ - searchable setting lists
53
55
 
54
- ## Context and settings helpers
56
+ ### Context helpers
55
57
 
56
- - `wrapExtensionContext()`
58
+ - `wrapExtensionContext()` — wrap injected text in SuPi's `<extension-context>` tag
57
59
  - `findLastUserMessageIndex()`
58
60
  - `getContextToken()`
61
+ - `getPromptContent()`
59
62
  - `pruneAndReorderContextMessages()`
60
- - `registerSettings()`
61
- - `registerSettingsCommand()`
62
- - `openSettingsOverlay()`
63
+ - `restorePromptContent()`
64
+
65
+ ### Shared registries
66
+
67
+ - context-provider registry for `/supi-context`
68
+ - debug-event registry for producers that want shared debug capture
69
+ - settings registry used by `/supi-settings`
70
+
71
+ ### Project and session helpers
72
+
73
+ - project-root detection and directory walking helpers such as `findProjectRoot()` and `walkProject()`
74
+ - active-branch session helper: `getActiveBranchEntries()`
75
+ - terminal helpers such as `formatTitle()`, `signalWaiting()`, and `signalDone()`
63
76
 
64
77
  ## Example
65
78
 
@@ -80,17 +93,15 @@ registerConfigSettings({
80
93
  });
81
94
 
82
95
  const message = wrapExtensionContext("my-extension", "hello", {
83
- turn: 1,
84
96
  file: "CLAUDE.md",
97
+ turn: 1,
85
98
  });
86
99
  ```
87
100
 
88
- ## Requirements
89
-
90
- - `@earendil-works/pi-coding-agent`
91
- - `@earendil-works/pi-tui`
92
-
93
101
  ## Source
94
102
 
95
- - Library surface: `src/api.ts`
96
- - Extension surface: `src/extension.ts`
103
+ - `src/api.ts` — exported library surface
104
+ - `src/extension.ts` — minimal `/supi-settings` entrypoint
105
+ - `src/config.ts` — shared config loading and writing
106
+ - `src/config-settings.ts` — config-backed settings registration helper
107
+ - `src/settings-ui.ts` — shared settings overlay
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-core",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "description": "SuPi core — shared infrastructure for SuPi extensions (XML context tags, config system)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -2,30 +2,30 @@
2
2
  // Provides XML context tag wrapping, unified config system, context-message utilities,
3
3
  // and settings registry for supi-wide TUI settings.
4
4
 
5
- export type { SupiConfigLocation, SupiConfigOptions } from "./config.ts";
5
+ export type { SupiConfigLocation, SupiConfigOptions } from "./config/config.ts";
6
6
  export {
7
7
  loadSupiConfig,
8
8
  loadSupiConfigForScope,
9
9
  removeSupiConfigKey,
10
10
  writeSupiConfig,
11
- } from "./config.ts";
12
- export type { ConfigSettingsHelpers, ConfigSettingsOptions } from "./config-settings.ts";
13
- export { registerConfigSettings } from "./config-settings.ts";
14
- export type { ContextMessageLike } from "./context-messages.ts";
11
+ } from "./config/config.ts";
12
+ export type { ConfigSettingsHelpers, ConfigSettingsOptions } from "./config/config-settings.ts";
13
+ export { registerConfigSettings } from "./config/config-settings.ts";
14
+ export type { ContextMessageLike } from "./context/context-messages.ts";
15
15
  export {
16
16
  findLastUserMessageIndex,
17
17
  getContextToken,
18
18
  getPromptContent,
19
19
  pruneAndReorderContextMessages,
20
20
  restorePromptContent,
21
- } from "./context-messages.ts";
22
- export type { ContextProvider } from "./context-provider-registry.ts";
21
+ } from "./context/context-messages.ts";
22
+ export type { ContextProvider } from "./context/context-provider-registry.ts";
23
23
  export {
24
24
  clearRegisteredContextProviders,
25
25
  getRegisteredContextProviders,
26
26
  registerContextProvider,
27
- } from "./context-provider-registry.ts";
28
- export { wrapExtensionContext } from "./context-tag.ts";
27
+ } from "./context/context-provider-registry.ts";
28
+ export { wrapExtensionContext } from "./context/context-tag.ts";
29
29
  export type {
30
30
  DebugAgentAccess,
31
31
  DebugEvent,
@@ -64,14 +64,14 @@ export {
64
64
  walkProject,
65
65
  } from "./project-roots.ts";
66
66
  export { getActiveBranchEntries } from "./session-utils.ts";
67
- export { registerSettingsCommand } from "./settings-command.ts";
68
- export type { SettingsScope, SettingsSection } from "./settings-registry.ts";
67
+ export { registerSettingsCommand } from "./settings/settings-command.ts";
68
+ export type { SettingsScope, SettingsSection } from "./settings/settings-registry.ts";
69
69
  export {
70
70
  clearRegisteredSettings,
71
71
  getRegisteredSettings,
72
72
  registerSettings,
73
- } from "./settings-registry.ts";
74
- export { createInputSubmenu, openSettingsOverlay } from "./settings-ui.ts";
73
+ } from "./settings/settings-registry.ts";
74
+ export { createInputSubmenu, openSettingsOverlay } from "./settings/settings-ui.ts";
75
75
  export type { TitleTarget } from "./terminal.ts";
76
76
  export {
77
77
  DONE_SYMBOL,
@@ -2,9 +2,9 @@
2
2
  // Wraps registerSettings() and centralizes selected-scope loading + scoped persistence.
3
3
 
4
4
  import type { SettingItem } from "@earendil-works/pi-tui";
5
+ import type { SettingsScope } from "../settings/settings-registry.ts";
6
+ import { registerSettings } from "../settings/settings-registry.ts";
5
7
  import { loadSupiConfigForScope, removeSupiConfigKey, writeSupiConfig } from "./config.ts";
6
- import type { SettingsScope } from "./settings-registry.ts";
7
- import { registerSettings } from "./settings-registry.ts";
8
8
 
9
9
  export interface ConfigSettingsHelpers {
10
10
  /** Write a key to the selected scope's config section. */
@@ -3,7 +3,7 @@
3
3
  // Extensions declare context data providers via `registerContextProvider()` during their
4
4
  // factory function. The `/supi-context` command reads them via `getRegisteredContextProviders()`.
5
5
 
6
- import { createRegistry } from "./registry-utils.ts";
6
+ import { createRegistry } from "../registry-utils.ts";
7
7
 
8
8
  export interface ContextProvider {
9
9
  /** Unique identifier — e.g. "rtk" */
@@ -1 +1 @@
1
- export { registerSettingsCommand as default } from "./settings-command.ts";
1
+ export { registerSettingsCommand as default } from "./settings/settings-command.ts";
@@ -2,30 +2,30 @@
2
2
  // Provides XML context tag wrapping, unified config system, context-message utilities,
3
3
  // and settings registry for supi-wide TUI settings.
4
4
 
5
- export type { SupiConfigLocation, SupiConfigOptions } from "./config.ts";
5
+ export type { SupiConfigLocation, SupiConfigOptions } from "./config/config.ts";
6
6
  export {
7
7
  loadSupiConfig,
8
8
  loadSupiConfigForScope,
9
9
  removeSupiConfigKey,
10
10
  writeSupiConfig,
11
- } from "./config.ts";
12
- export type { ConfigSettingsHelpers, ConfigSettingsOptions } from "./config-settings.ts";
13
- export { registerConfigSettings } from "./config-settings.ts";
14
- export type { ContextMessageLike } from "./context-messages.ts";
11
+ } from "./config/config.ts";
12
+ export type { ConfigSettingsHelpers, ConfigSettingsOptions } from "./config/config-settings.ts";
13
+ export { registerConfigSettings } from "./config/config-settings.ts";
14
+ export type { ContextMessageLike } from "./context/context-messages.ts";
15
15
  export {
16
16
  findLastUserMessageIndex,
17
17
  getContextToken,
18
18
  getPromptContent,
19
19
  pruneAndReorderContextMessages,
20
20
  restorePromptContent,
21
- } from "./context-messages.ts";
22
- export type { ContextProvider } from "./context-provider-registry.ts";
21
+ } from "./context/context-messages.ts";
22
+ export type { ContextProvider } from "./context/context-provider-registry.ts";
23
23
  export {
24
24
  clearRegisteredContextProviders,
25
25
  getRegisteredContextProviders,
26
26
  registerContextProvider,
27
- } from "./context-provider-registry.ts";
28
- export { wrapExtensionContext } from "./context-tag.ts";
27
+ } from "./context/context-provider-registry.ts";
28
+ export { wrapExtensionContext } from "./context/context-tag.ts";
29
29
  export type {
30
30
  DebugAgentAccess,
31
31
  DebugEvent,
@@ -64,14 +64,14 @@ export {
64
64
  walkProject,
65
65
  } from "./project-roots.ts";
66
66
  export { getActiveBranchEntries } from "./session-utils.ts";
67
- export { registerSettingsCommand } from "./settings-command.ts";
68
- export type { SettingsScope, SettingsSection } from "./settings-registry.ts";
67
+ export { registerSettingsCommand } from "./settings/settings-command.ts";
68
+ export type { SettingsScope, SettingsSection } from "./settings/settings-registry.ts";
69
69
  export {
70
70
  clearRegisteredSettings,
71
71
  getRegisteredSettings,
72
72
  registerSettings,
73
- } from "./settings-registry.ts";
74
- export { createInputSubmenu, openSettingsOverlay } from "./settings-ui.ts";
73
+ } from "./settings/settings-registry.ts";
74
+ export { createInputSubmenu, openSettingsOverlay } from "./settings/settings-ui.ts";
75
75
  export type { TitleTarget } from "./terminal.ts";
76
76
  export {
77
77
  DONE_SYMBOL,
@@ -4,7 +4,7 @@
4
4
  // factory function. The generic settings UI reads them via `getRegisteredSettings()`.
5
5
 
6
6
  import type { SettingItem } from "@earendil-works/pi-tui";
7
- import { createRegistry } from "./registry-utils.ts";
7
+ import { createRegistry } from "../registry-utils.ts";
8
8
 
9
9
  export type SettingsScope = "project" | "global";
10
10
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mrclrchtr/supi-rtk",
3
- "version": "1.3.1",
3
+ "version": "1.4.0",
4
4
  "description": "SuPi RTK extension — transparent bash command rewriting via RTK for token savings",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -20,7 +20,7 @@
20
20
  "README.md"
21
21
  ],
22
22
  "dependencies": {
23
- "@mrclrchtr/supi-core": "1.3.1"
23
+ "@mrclrchtr/supi-core": "1.4.0"
24
24
  },
25
25
  "bundledDependencies": [
26
26
  "@mrclrchtr/supi-core"
package/src/rtk.ts CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  } from "@mrclrchtr/supi-core/api";
14
14
  import { shouldBypassRtkRewrite } from "./guards.ts";
15
15
  import { type RtkRewriteFailureReason, rtkRewriteDetailed } from "./rewrite.ts";
16
+ import { promptGuidelines } from "./tool/guidance.ts";
16
17
  import { getStats, recordFallback, recordRewrite, resetTracking } from "./tracking.ts";
17
18
 
18
19
  const RTK_SECTION = "rtk";
@@ -244,13 +245,7 @@ export default function rtkExtension(pi: ExtensionAPI) {
244
245
 
245
246
  pi.registerTool({
246
247
  ...baseBashTool,
247
- // TODO(rtk-ai/rtk#1813): Remove these promptGuidelines once the upstream issue
248
- // "vitest run output truncates failures" is fixed in a released RTK version.
249
- // After that, default compact output will list all failing tests and this
250
- // guidance will no longer be necessary.
251
- promptGuidelines: [
252
- "When running test commands (vitest, jest, pytest, cargo test, etc.), RTK may intercept and compact the output. To see all test failures without truncation, pass `-v` to the command (e.g. `pnpm vitest -v run`). To bypass RTK entirely and get raw output, prefix with `RTK_DISABLED=1`.",
253
- ],
248
+ promptGuidelines,
254
249
  // biome-ignore lint/complexity/useMaxParams: pi tool execute signature
255
250
  async execute(toolCallId, params, signal, onUpdate, ctx) {
256
251
  const bashTool = createRtkAwareBashTool(ctx.cwd, ctx);
@@ -0,0 +1,10 @@
1
+ // Prompt guidance for the RTK bash override.
2
+ //
3
+ // TODO(rtk-ai/rtk#1813): Remove this promptGuidelines entry once the upstream
4
+ // issue "vitest run output truncates failures" is fixed in a released RTK
5
+ // version. After that, default compact output should list all failing tests and
6
+ // this guidance will no longer be necessary.
7
+
8
+ export const promptGuidelines = [
9
+ "Use bash with `-v` when running test commands (vitest, jest, pytest, cargo test, etc.) because the RTK bash override may compact failure output. Prefix a bash command with `RTK_DISABLED=1` to bypass the RTK bash override entirely and get raw output.",
10
+ ];