@wingsbutterfly/dsh-rtk 0.1.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/CHANGELOG.md +52 -0
- package/LICENSE +21 -0
- package/README.md +214 -0
- package/README.zh.md +211 -0
- package/THIRD_PARTY_NOTICES.md +51 -0
- package/docs/assets/how-it-works.svg +47 -0
- package/docs/verification.md +279 -0
- package/lib/command.d.ts +41 -0
- package/lib/command.d.ts.map +1 -0
- package/lib/command.js +137 -0
- package/lib/command.js.map +1 -0
- package/lib/compact/build.d.ts +15 -0
- package/lib/compact/build.d.ts.map +1 -0
- package/lib/compact/build.js +140 -0
- package/lib/compact/build.js.map +1 -0
- package/lib/compact/detect.d.ts +22 -0
- package/lib/compact/detect.d.ts.map +1 -0
- package/lib/compact/detect.js +54 -0
- package/lib/compact/detect.js.map +1 -0
- package/lib/compact/dsh-result.d.ts +49 -0
- package/lib/compact/dsh-result.d.ts.map +1 -0
- package/lib/compact/dsh-result.js +84 -0
- package/lib/compact/dsh-result.js.map +1 -0
- package/lib/compact/git.d.ts +21 -0
- package/lib/compact/git.d.ts.map +1 -0
- package/lib/compact/git.js +197 -0
- package/lib/compact/git.js.map +1 -0
- package/lib/compact/index.d.ts +39 -0
- package/lib/compact/index.d.ts.map +1 -0
- package/lib/compact/index.js +236 -0
- package/lib/compact/index.js.map +1 -0
- package/lib/compact/linter.d.ts +12 -0
- package/lib/compact/linter.d.ts.map +1 -0
- package/lib/compact/linter.js +118 -0
- package/lib/compact/linter.js.map +1 -0
- package/lib/compact/search.d.ts +16 -0
- package/lib/compact/search.d.ts.map +1 -0
- package/lib/compact/search.js +67 -0
- package/lib/compact/search.js.map +1 -0
- package/lib/compact/source.d.ts +22 -0
- package/lib/compact/source.d.ts.map +1 -0
- package/lib/compact/source.js +224 -0
- package/lib/compact/source.js.map +1 -0
- package/lib/compact/test-output.d.ts +12 -0
- package/lib/compact/test-output.d.ts.map +1 -0
- package/lib/compact/test-output.js +168 -0
- package/lib/compact/test-output.js.map +1 -0
- package/lib/compact/text.d.ts +22 -0
- package/lib/compact/text.d.ts.map +1 -0
- package/lib/compact/text.js +87 -0
- package/lib/compact/text.js.map +1 -0
- package/lib/config.d.ts +243 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +183 -0
- package/lib/config.js.map +1 -0
- package/lib/index.d.ts +46 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +405 -0
- package/lib/index.js.map +1 -0
- package/lib/metrics.d.ts +35 -0
- package/lib/metrics.d.ts.map +1 -0
- package/lib/metrics.js +51 -0
- package/lib/metrics.js.map +1 -0
- package/lib/rtk-executable.d.ts +51 -0
- package/lib/rtk-executable.d.ts.map +1 -0
- package/lib/rtk-executable.js +75 -0
- package/lib/rtk-executable.js.map +1 -0
- package/lib/rtk-rewrite.d.ts +88 -0
- package/lib/rtk-rewrite.d.ts.map +1 -0
- package/lib/rtk-rewrite.js +150 -0
- package/lib/rtk-rewrite.js.map +1 -0
- package/lib/runtime-guard.d.ts +31 -0
- package/lib/runtime-guard.d.ts.map +1 -0
- package/lib/runtime-guard.js +32 -0
- package/lib/runtime-guard.js.map +1 -0
- package/package.json +82 -0
- package/scripts/link-dsh.mjs +135 -0
- package/src/command.ts +174 -0
- package/src/compact/build.ts +154 -0
- package/src/compact/detect.ts +54 -0
- package/src/compact/dsh-result.ts +99 -0
- package/src/compact/git.ts +209 -0
- package/src/compact/index.ts +284 -0
- package/src/compact/linter.ts +126 -0
- package/src/compact/search.ts +73 -0
- package/src/compact/source.ts +244 -0
- package/src/compact/test-output.ts +184 -0
- package/src/compact/text.ts +86 -0
- package/src/config.ts +263 -0
- package/src/index.ts +431 -0
- package/src/metrics.ts +84 -0
- package/src/rtk-executable.ts +117 -0
- package/src/rtk-rewrite.ts +179 -0
- package/src/runtime-guard.ts +44 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
Initial release — a port of `pi-rtk-optimizer` to the DeepSeek Harness plugin
|
|
6
|
+
model.
|
|
7
|
+
|
|
8
|
+
### Command rewriting
|
|
9
|
+
|
|
10
|
+
- Rewrites `bash`/`pwsh` commands to their rtk equivalents by delegating to
|
|
11
|
+
`rtk rewrite`; rtk remains the only source of rewrite rules.
|
|
12
|
+
- Honors rtk's exit-code contract: `0`/`3` carry a rewrite on stdout, `1` means
|
|
13
|
+
no equivalent, `2` means rtk refused and stderr explains why.
|
|
14
|
+
- `rewrite` and `suggest` modes, plus a runtime guard that runs the original
|
|
15
|
+
command whenever rtk cannot be proven available.
|
|
16
|
+
- Scopes an isolated `RTK_DB_PATH` onto rewritten commands so rtk's usage
|
|
17
|
+
history does not reach the working tree.
|
|
18
|
+
- Restores the original arguments as soon as dispatch returns, so the session
|
|
19
|
+
log and later pipeline stages keep seeing the call the model made.
|
|
20
|
+
|
|
21
|
+
### Output compaction
|
|
22
|
+
|
|
23
|
+
- Multi-stage pipeline over `bash`, `read`, and `grep` results: ANSI stripping,
|
|
24
|
+
build filtering, test aggregation, git compaction, linter aggregation, search
|
|
25
|
+
grouping, source filtering, smart truncation, and hard truncation.
|
|
26
|
+
- Preserves the harness result contract: `[exit code: N]`, `[stderr]`,
|
|
27
|
+
`[timed out after …]`, `[sandbox: …]`, and truncation markers are lifted out
|
|
28
|
+
before the body is rewritten and restored verbatim afterwards.
|
|
29
|
+
- Never inflates a result — a technique that would not shrink the text is
|
|
30
|
+
discarded and reported as no change.
|
|
31
|
+
- Lossy `read` compaction and source filtering are off by default, and every
|
|
32
|
+
numeric bound is clamped on load.
|
|
33
|
+
|
|
34
|
+
### Configuration and commands
|
|
35
|
+
|
|
36
|
+
- Full configuration surface mirroring `pi-rtk-optimizer`'s documented
|
|
37
|
+
defaults, registered as the `dsh-rtk` settings namespace with the
|
|
38
|
+
composition's `config:` block as its base layer.
|
|
39
|
+
- `/rtk`, `/rtk show`, `/rtk path`, `/rtk verify`, `/rtk stats`,
|
|
40
|
+
`/rtk clear-stats`, `/rtk reset`, and `/rtk help`.
|
|
41
|
+
- Session savings metrics by tool and by technique.
|
|
42
|
+
|
|
43
|
+
### Notes on the port
|
|
44
|
+
|
|
45
|
+
- Streamed bash output is not sanitized: the harness has no equivalent of Pi's
|
|
46
|
+
`tool_execution_*` hooks.
|
|
47
|
+
- The Windows-specific shell fixups and the hashline/anchor-safe read handling
|
|
48
|
+
are not ported; the target deployment is POSIX with the harness's own `read`
|
|
49
|
+
format.
|
|
50
|
+
- A host-plane row and a preset row both want the same process-global settings
|
|
51
|
+
namespace. The second instance to mount now follows the first through the
|
|
52
|
+
settings event instead of failing the mount.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 wings1848
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# dsh-rtk
|
|
2
|
+
|
|
3
|
+
[](https://github.com/wings1848/dsh-rtk/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/wings1848/dsh-rtk/actions/workflows/codeql.yml)
|
|
5
|
+
[](https://github.com/wings1848/dsh-rtk/actions/workflows/secrets.yml)
|
|
6
|
+
[](https://github.com/wings1848/dsh-rtk/blob/main/LICENSE)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
[](https://github.com/wings1848/dsh-rtk/blob/main/README.zh.md)
|
|
9
|
+
|
|
10
|
+
RTK command rewriting and tool-output compaction for the [DeepSeek Harness](https://github.com/deepseek-ai/dsh).
|
|
11
|
+
|
|
12
|
+
`dsh-rtk` rewrites `bash` commands to their [rtk](https://github.com/rtk-ai/rtk) equivalents before they run, and compacts noisy tool output before it reaches the model. It is a port of [`pi-rtk-optimizer`](https://github.com/MasuRii/pi-rtk-optimizer) to the harness's plugin model.
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
model asks: git status
|
|
16
|
+
runs: rtk git status
|
|
17
|
+
model sees: Branch: main
|
|
18
|
+
Modified: 2 files
|
|
19
|
+
src/a.ts
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+
|
|
24
|
+
## Features
|
|
25
|
+
|
|
26
|
+
### Command rewriting
|
|
27
|
+
|
|
28
|
+
- Every command with an rtk equivalent is rewritten before dispatch; commands rtk does not support run untouched.
|
|
29
|
+
- **rtk stays the source of truth.** The plugin carries no rewrite table of its own — it asks the installed binary via `rtk rewrite`, so support tracks whatever rtk version is installed.
|
|
30
|
+
- **`rewrite` and `suggest` modes.** `rewrite` replaces the command; `suggest` runs it unchanged and reports the equivalent it would have used.
|
|
31
|
+
- **Runtime guard.** With `guardWhenRtkMissing` on (the default), a call that cannot prove rtk is available runs the original command. A missing optimizer never blocks work.
|
|
32
|
+
- Rewritten commands get an isolated `RTK_DB_PATH`, so rtk's usage history does not land in the working tree.
|
|
33
|
+
|
|
34
|
+
### Output compaction
|
|
35
|
+
|
|
36
|
+
A multi-stage pipeline over `bash`, `read`, and `grep` results:
|
|
37
|
+
|
|
38
|
+
| Stage | What it does |
|
|
39
|
+
|---|---|
|
|
40
|
+
| ANSI stripping | Removes terminal color and formatting sequences |
|
|
41
|
+
| Build filtering | Extracts compiler errors and warnings, drops progress chatter |
|
|
42
|
+
| Test aggregation | Collapses runner output to pass/fail/skip plus failure excerpts |
|
|
43
|
+
| Git compaction | Summarizes `git status`, `git diff`, and `git log` |
|
|
44
|
+
| Linter aggregation | Counts issues and ranks them by rule and file |
|
|
45
|
+
| Search grouping | Groups `grep`-style matches by file |
|
|
46
|
+
| Source filtering | `none`, `minimal`, or `aggressive` comment/whitespace removal (off by default) |
|
|
47
|
+
| Smart truncation | Keeps signatures and imports when dropping lines (off by default) |
|
|
48
|
+
| Hard truncation | Final character budget |
|
|
49
|
+
|
|
50
|
+
Two properties are load-bearing:
|
|
51
|
+
|
|
52
|
+
- **The harness contract survives.** A `bash` result ends with status markers — `[exit code: N]`, `[stderr]`, `[timed out after …]`, `[sandbox: …]`. Compaction lifts those out before rewriting the body and puts them back afterwards; the model is told to check `[exit code: N]` on every call, and the Web UI parses that same line for its exit-status pill.
|
|
53
|
+
- **Compaction never inflates a result.** If a technique would not actually shrink the text, the original is kept and nothing is reported.
|
|
54
|
+
|
|
55
|
+
### Oversized output belongs to the harness
|
|
56
|
+
|
|
57
|
+
When `dsh-spill-policy` is mounted, it writes a full result to disk and keeps a head/tail preview inline — that truncation is **recoverable**. This plugin's own hard truncation is not, and it runs first: at its 12 000-character default it fires far below spill's 50 000-byte threshold, so spill never sees a large result at all and the file that would have let a reader see the rest is never written.
|
|
58
|
+
|
|
59
|
+
With `deferToHarnessSpill` on (the default) the plugin turns its own truncation off whenever the spill service is present, so a runaway command's output stays readable. Set it to `false` to keep the plugin's bound regardless.
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
### Session metrics
|
|
63
|
+
|
|
64
|
+
`/rtk stats` reports how many characters compaction saved, per tool and per technique.
|
|
65
|
+
|
|
66
|
+
## Install
|
|
67
|
+
|
|
68
|
+
### 1. Install the package
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
dsh plugin --profile web add @wingsbutterfly/dsh-rtk
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Working from a checkout instead? Link it where the composition resolves bare
|
|
75
|
+
specifiers:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
mkdir -p ~/.dsh/node_modules/@wingsbutterfly
|
|
79
|
+
ln -s /path/to/dsh-rtk ~/.dsh/node_modules/@wingsbutterfly/dsh-rtk
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. Add one row to an agent preset
|
|
83
|
+
|
|
84
|
+
`dsh-rtk` is an **agent-plane** row: it registers listeners into the tool pipeline and contributes no service, so it needs no `isolate` realm. Add it to the preset whose sessions should be optimized:
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
- id: rtk
|
|
88
|
+
name: '@wingsbutterfly/dsh-rtk'
|
|
89
|
+
config:
|
|
90
|
+
enabled: true
|
|
91
|
+
mode: rewrite
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
To try it without touching an existing preset, copy one and add the row:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
# ask a cordis-preset agent to run this
|
|
98
|
+
agentPresets.copy('standard', 'rtk', 'RTK 优化')
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
The row works at the host plane too (add it to `~/.dsh/cordis.patch.yml` instead), which covers every session in the deployment — but that needs a host restart, and a host row plus a preset row would both want the same process-global settings namespace. Pick one plane.
|
|
102
|
+
|
|
103
|
+
## Configuration
|
|
104
|
+
|
|
105
|
+
Every field is optional; defaults are shown.
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
- id: rtk
|
|
109
|
+
name: '@wingsbutterfly/dsh-rtk'
|
|
110
|
+
config:
|
|
111
|
+
enabled: true # master switch
|
|
112
|
+
mode: rewrite # rewrite | suggest
|
|
113
|
+
guardWhenRtkMissing: true # run the original when rtk is unavailable
|
|
114
|
+
showRewriteNotifications: false # append a one-line rewrite note to the result
|
|
115
|
+
rtkExecutable: rtk # name or absolute path
|
|
116
|
+
rewriteTimeoutMs: 3000 # deadline for one `rtk rewrite` call
|
|
117
|
+
compactedTools: [bash, read, grep]
|
|
118
|
+
outputCompaction:
|
|
119
|
+
enabled: true
|
|
120
|
+
stripAnsi: true
|
|
121
|
+
readCompaction:
|
|
122
|
+
enabled: false # lossy read compaction; off so code reads stay exact
|
|
123
|
+
sourceCodeFilteringEnabled: false
|
|
124
|
+
preserveExactSkillReads: false
|
|
125
|
+
sourceCodeFiltering: none # none | minimal | aggressive
|
|
126
|
+
aggregateTestOutput: true
|
|
127
|
+
filterBuildOutput: true
|
|
128
|
+
compactGitOutput: true
|
|
129
|
+
aggregateLinterOutput: true
|
|
130
|
+
groupSearchOutput: true
|
|
131
|
+
trackSavings: true
|
|
132
|
+
deferToHarnessSpill: true # let the harness spill policy own oversized output
|
|
133
|
+
smartTruncate:
|
|
134
|
+
enabled: false
|
|
135
|
+
maxLines: 220 # 40–4000
|
|
136
|
+
truncate:
|
|
137
|
+
enabled: true
|
|
138
|
+
maxChars: 12000 # 1000–200000
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The configuration is also registered as the `dsh-rtk` namespace in the harness settings document, so it can be edited there and takes effect without a restart. A composition `config:` block supplies the `base` layer; the settings document supplies the user layer on top.
|
|
142
|
+
|
|
143
|
+
> **Why `readCompaction` is off by default.** Filtering or truncating a `read` result can leave the model editing against text that no longer matches the file. Everything on by default is lossless for the body text it summarizes, or only fires on outputs whose whole shape is being replaced.
|
|
144
|
+
|
|
145
|
+
## Commands
|
|
146
|
+
|
|
147
|
+
| Command | Description |
|
|
148
|
+
|---|---|
|
|
149
|
+
| `/rtk` | Show configuration and runtime status |
|
|
150
|
+
| `/rtk show` | Same as `/rtk` |
|
|
151
|
+
| `/rtk path` | Where the configuration is stored |
|
|
152
|
+
| `/rtk verify` | Check whether the rtk executable is usable |
|
|
153
|
+
| `/rtk stats` | Compaction savings for this session |
|
|
154
|
+
| `/rtk clear-stats` | Reset the savings counters |
|
|
155
|
+
| `/rtk reset` | Restore configuration defaults |
|
|
156
|
+
| `/rtk help` | Usage text |
|
|
157
|
+
|
|
158
|
+
## How it works
|
|
159
|
+
|
|
160
|
+
Both halves ride the tool pipeline rather than wrapping a tool, because the harness offers exactly two seams that fit:
|
|
161
|
+
|
|
162
|
+
- **Rewriting rides `tools/execute`.** `tools/pre-execute` deliberately may not mutate arguments — they are logged and presented before dispatch, so a rewrite there would desync the recorded call from the one that ran. The around-dispatch stage is the only place the executing command may differ, and `dsh-rtk` scopes the change to a single call: the original arguments are restored as soon as dispatch returns, so later pipeline stages and the session log still see what the model asked for.
|
|
163
|
+
|
|
164
|
+
- **Compaction rides `tools/post-execute`**, the stage that may replace result content.
|
|
165
|
+
|
|
166
|
+
Both listeners register in the scope the row was mounted into. A preset row therefore covers exactly its own agent (the preset's standing scope is an ancestor of every session that joins it), and a host row covers every agent in the process.
|
|
167
|
+
|
|
168
|
+
Only the `tools` service is a hard dependency. `settings`, `commands`, and `systemPrompt` are resolved with `ctx.get`, so a composition that omits any of them still gets the optimization.
|
|
169
|
+
|
|
170
|
+
### Caveat: the rewriting seam is not a sanctioned extension point
|
|
171
|
+
|
|
172
|
+
The harness documents `tools/execute` wrappers as wrappers that "may change only `exec.signal`". Replacing `arguments` is **not a supported extension point** — it works because the execution object is not frozen until its result is notified, and the failed alternative is worse: `tools/pre-execute` deliberately may not rewrite input (arguments are logged and presented before dispatch), and a tool cannot be re-registered over one in the same layer.
|
|
173
|
+
|
|
174
|
+
`dsh-rtk` takes that seam knowingly, and pays for it where it can: the replacement is scoped to a single call and restored in `finally`, and every failure path falls back to the command the model sent. If a future harness version freezes the execution object earlier, rewriting goes quiet rather than breaking — commands run unrewritten and compaction is unaffected, because `tools/post-execute` *is* a documented content-replacement stage.
|
|
175
|
+
|
|
176
|
+
## Differences from pi-rtk-optimizer
|
|
177
|
+
|
|
178
|
+
| pi-rtk-optimizer | dsh-rtk |
|
|
179
|
+
|---|---|
|
|
180
|
+
| Rewrites `event.input.command` in the `tool_call` hook | Replaces `exec.arguments` for the duration of one dispatch, then restores it |
|
|
181
|
+
| Compacts in the `tool_result` hook | Compacts in the `tools/post-execute` waterfall |
|
|
182
|
+
| `/rtk` opens a TUI settings modal | `/rtk` prints status text; configuration lives in the harness settings document |
|
|
183
|
+
| Config is a JSON file it owns | Config is a harness settings namespace layered over the composition's `config:` block |
|
|
184
|
+
| Streams are sanitized through `tool_execution_*` hooks | No equivalent hook exists, so streamed output is not sanitized |
|
|
185
|
+
| Windows-specific shell fixups | Not ported; the target deployment is POSIX |
|
|
186
|
+
|
|
187
|
+
Everything else — the rewrite delegation to `rtk rewrite`, the exit-code contract, the guard when rtk is missing, the documented default for every compaction switch, and each technique's algorithm — is ported as-is.
|
|
188
|
+
|
|
189
|
+
## Development
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
pnpm install # or link the peer packages manually
|
|
193
|
+
pnpm run typecheck # tsc --noEmit against the real harness types
|
|
194
|
+
pnpm test # builds first, then runs node --test test/
|
|
195
|
+
pnpm run build # emit lib/
|
|
196
|
+
pnpm run check # typecheck + test
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The tests import `lib/`, so `pnpm test` builds before it runs; a `src/` edit that is never built would otherwise pass the suite unnoticed.
|
|
200
|
+
|
|
201
|
+
The port's acceptance evidence, including the eight defects later reviews and live testing surfaced, is in [https://github.com/wings1848/dsh-rtk/blob/main/docs/verification.md](https://github.com/wings1848/dsh-rtk/blob/main/docs/verification.md).
|
|
202
|
+
|
|
203
|
+
`test/integration.test.ts` drives the real `apply()` through a stand-in context and calls the real `rtk` binary, so it fails on a machine without rtk installed — that is intentional: the rewrite path is the feature.
|
|
204
|
+
|
|
205
|
+
## Star history
|
|
206
|
+
|
|
207
|
+
<picture>
|
|
208
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wings1848/dsh-rtk/output/star-history-dark.svg">
|
|
209
|
+
<img alt="Star history chart" src="https://raw.githubusercontent.com/wings1848/dsh-rtk/output/star-history-light.svg">
|
|
210
|
+
</picture>
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
MIT
|
package/README.zh.md
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# dsh-rtk
|
|
2
|
+
|
|
3
|
+
[](https://github.com/wings1848/dsh-rtk/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/wings1848/dsh-rtk/actions/workflows/codeql.yml)
|
|
5
|
+
[](https://github.com/wings1848/dsh-rtk/actions/workflows/secrets.yml)
|
|
6
|
+
[](https://github.com/wings1848/dsh-rtk/blob/main/LICENSE)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
[](https://github.com/wings1848/dsh-rtk/blob/main/README.md)
|
|
9
|
+
|
|
10
|
+
给 [DeepSeek Harness](https://github.com/deepseek-ai/dsh) 用的 RTK 命令重写 + 工具输出压缩插件。
|
|
11
|
+
|
|
12
|
+
`dsh-rtk` 会在 `bash` 命令执行前把它改写成等价的 [rtk](https://github.com/rtk-ai/rtk) 命令,并在工具输出进入模型上下文前压缩它。它是 [`pi-rtk-optimizer`](https://github.com/MasuRii/pi-rtk-optimizer) 在 harness 插件模型上的移植。
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
模型发出: git status
|
|
16
|
+
实际执行: rtk git status
|
|
17
|
+
模型看到: Branch: main
|
|
18
|
+
Modified: 2 files
|
|
19
|
+
src/a.ts
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+
|
|
24
|
+
## 功能
|
|
25
|
+
|
|
26
|
+
### 命令重写
|
|
27
|
+
|
|
28
|
+
- 有 rtk 等价命令的调用会在派发前被改写;rtk 不支持的命令原样执行。
|
|
29
|
+
- **rtk 始终是唯一事实来源。** 插件不带自己的重写表,而是通过 `rtk rewrite` 询问已安装的二进制,所以支持范围跟随你装的 rtk 版本。
|
|
30
|
+
- **`rewrite` 与 `suggest` 两种模式。** `rewrite` 替换命令;`suggest` 原样执行并报告本可使用的等价命令。
|
|
31
|
+
- **运行时守卫。** `guardWhenRtkMissing`(默认开)下,无法确认 rtk 可用的调用会执行原命令——缺少优化器永远不会挡住工作。
|
|
32
|
+
- 被改写的命令会带上隔离的 `RTK_DB_PATH`,rtk 的使用历史不会落进工作目录。
|
|
33
|
+
|
|
34
|
+
### 输出压缩
|
|
35
|
+
|
|
36
|
+
针对 `bash`、`read`、`grep` 结果的多阶段管线:
|
|
37
|
+
|
|
38
|
+
| 阶段 | 作用 |
|
|
39
|
+
|---|---|
|
|
40
|
+
| ANSI 剥离 | 去掉终端颜色与格式转义序列 |
|
|
41
|
+
| 构建过滤 | 提取编译错误与警告,丢弃进度噪音 |
|
|
42
|
+
| 测试聚合 | 折叠为 通过/失败/跳过 计数加失败摘录 |
|
|
43
|
+
| Git 压缩 | 归纳 `git status`、`git diff`、`git log` |
|
|
44
|
+
| Linter 聚合 | 统计问题数并按规则与文件排名 |
|
|
45
|
+
| 搜索分组 | 按文件归组 `grep` 风格匹配 |
|
|
46
|
+
| 源码过滤 | `none` / `minimal` / `aggressive` 注释与空白处理(默认关) |
|
|
47
|
+
| 智能截断 | 丢行时保留签名与 import(默认关) |
|
|
48
|
+
| 硬截断 | 最终字符预算 |
|
|
49
|
+
|
|
50
|
+
有两条性质是**硬性不变量**:
|
|
51
|
+
|
|
52
|
+
- **harness 的结果契约必须存活。** `bash` 结果以状态标记结尾——`[exit code: N]`、`[stderr]`、`[timed out after …]`、`[sandbox: …]`。压缩会先把这些标记摘出来,重写正文后再原样接回;模型被要求在每次调用后检查 `[exit code: N]`,Web UI 也解析同一行来画退出状态。
|
|
53
|
+
|
|
54
|
+
- **压缩绝不把结果变大。** 如果某个技术不能真正缩短文本,就保留原文并且不上报。
|
|
55
|
+
|
|
56
|
+
### 超大输出归 harness 管
|
|
57
|
+
|
|
58
|
+
`dsh-spill-policy` 挂载时,它会把完整结果落盘、上下文里只留头尾预览——这种截断是**可恢复的**。而本插件的硬截断不可恢复,且**跑在前面**:默认 12000 字符的阈值远低于 spill 的 50000 字节阈值,于是 spill 根本看不到大结果,那个本可以让读者看到剩余内容的落盘文件也就永远不会产生。
|
|
59
|
+
|
|
60
|
+
`deferToHarnessSpill` 开启时(默认),只要 spill 服务在场,插件就关掉自己的截断,让失控命令的输出保持可读。设为 `false` 则无论 spill 是否挂载都保留插件自己的上限。
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
### 会话统计
|
|
64
|
+
|
|
65
|
+
`/rtk stats` 报告本次会话省下多少字符,按工具与按技术两个维度。
|
|
66
|
+
|
|
67
|
+
## 安装
|
|
68
|
+
|
|
69
|
+
### 1. 安装包
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
dsh plugin --profile web add @wingsbutterfly/dsh-rtk
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
想从本地检出直接用?软链到组合能解析裸模块名的位置:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
mkdir -p ~/.dsh/node_modules/@wingsbutterfly
|
|
79
|
+
ln -s /path/to/dsh-rtk ~/.dsh/node_modules/@wingsbutterfly/dsh-rtk
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. 给一个 agent preset 加一行
|
|
83
|
+
|
|
84
|
+
`dsh-rtk` 是 **agent 平面**的行:它只往工具管线里注册监听器、不发布任何服务,所以不需要 `isolate` realm。把它加到你希望被优化的 preset:
|
|
85
|
+
|
|
86
|
+
```yaml
|
|
87
|
+
- id: rtk
|
|
88
|
+
name: '@wingsbutterfly/dsh-rtk'
|
|
89
|
+
config:
|
|
90
|
+
enabled: true
|
|
91
|
+
mode: rewrite
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
不想动现有 preset,就复制一个再加行:
|
|
95
|
+
|
|
96
|
+
```
|
|
97
|
+
# 让 cordis preset 的 agent 执行
|
|
98
|
+
agentPresets.copy('standard', 'rtk', 'RTK 优化')
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
这一行挂在 **host 平面**同样有效(写进 `~/.dsh/cordis.patch.yml`),会覆盖该部署下的所有会话——但需要重启宿主,而且 host 行与 preset 行会同时想要同一个进程级 settings 命名空间。**两个平面只选一个。**
|
|
102
|
+
|
|
103
|
+
## 配置
|
|
104
|
+
|
|
105
|
+
所有字段可选,下列为默认值。
|
|
106
|
+
|
|
107
|
+
```yaml
|
|
108
|
+
- id: rtk
|
|
109
|
+
name: '@wingsbutterfly/dsh-rtk'
|
|
110
|
+
config:
|
|
111
|
+
enabled: true # 总开关
|
|
112
|
+
mode: rewrite # rewrite | suggest
|
|
113
|
+
guardWhenRtkMissing: true # rtk 不可用时执行原命令
|
|
114
|
+
showRewriteNotifications: false # 在结果末尾附加一行改写说明
|
|
115
|
+
rtkExecutable: rtk # 名字或绝对路径
|
|
116
|
+
rewriteTimeoutMs: 3000 # 单次 `rtk rewrite` 的截止时间
|
|
117
|
+
compactedTools: [bash, read, grep]
|
|
118
|
+
outputCompaction:
|
|
119
|
+
enabled: true
|
|
120
|
+
stripAnsi: true
|
|
121
|
+
readCompaction:
|
|
122
|
+
enabled: false # 有损 read 压缩;默认关,保证读到的代码是精确的
|
|
123
|
+
sourceCodeFilteringEnabled: false
|
|
124
|
+
preserveExactSkillReads: false
|
|
125
|
+
sourceCodeFiltering: none # none | minimal | aggressive
|
|
126
|
+
aggregateTestOutput: true
|
|
127
|
+
filterBuildOutput: true
|
|
128
|
+
compactGitOutput: true
|
|
129
|
+
aggregateLinterOutput: true
|
|
130
|
+
groupSearchOutput: true
|
|
131
|
+
trackSavings: true
|
|
132
|
+
deferToHarnessSpill: true # 把超大输出让给 harness 的 spill 策略
|
|
133
|
+
smartTruncate:
|
|
134
|
+
enabled: false
|
|
135
|
+
maxLines: 220 # 40–4000
|
|
136
|
+
truncate:
|
|
137
|
+
enabled: true
|
|
138
|
+
maxChars: 12000 # 1000–200000
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
配置同时注册为 harness 设置文档里的 `dsh-rtk` 命名空间,可以在那里编辑并即时生效、无需重启。组合里的 `config:` 块提供 `base` 层,设置文档在其上叠加用户层。
|
|
142
|
+
|
|
143
|
+
> **为什么 `readCompaction` 默认关。** 过滤或截断 `read` 结果,可能让模型拿到的文本与文件不再一致,编辑就会失配。默认开启的每一项,要么对它归纳的正文是无损的,要么只作用于整个形态都会被替换掉的输出。
|
|
144
|
+
|
|
145
|
+
## 命令
|
|
146
|
+
|
|
147
|
+
| 命令 | 说明 |
|
|
148
|
+
|---|---|
|
|
149
|
+
| `/rtk` | 显示配置与运行时状态 |
|
|
150
|
+
| `/rtk show` | 同 `/rtk` |
|
|
151
|
+
| `/rtk path` | 配置存放位置 |
|
|
152
|
+
| `/rtk verify` | 检查 rtk 可执行文件是否可用 |
|
|
153
|
+
| `/rtk stats` | 本次会话的压缩收益 |
|
|
154
|
+
| `/rtk clear-stats` | 重置收益计数 |
|
|
155
|
+
| `/rtk reset` | 恢复配置默认值 |
|
|
156
|
+
| `/rtk help` | 用法说明 |
|
|
157
|
+
|
|
158
|
+
## 工作原理
|
|
159
|
+
|
|
160
|
+
两部分都挂在工具管线上,而不是包装某个工具,因为 harness 恰好提供两个合适的接缝:
|
|
161
|
+
|
|
162
|
+
- **重写走 `tools/execute`。** `tools/pre-execute` 被刻意设计为不能修改参数——参数在派发前就已记入日志并呈现,在那里改写会让记录下来的调用与实际执行的不一致。around-dispatch 阶段是唯一能让「执行的命令」与「记录的命令」不同的地方,而 `dsh-rtk` 把改动限制在单次调用内:派发一返回就恢复原始参数,后续管线阶段与会话日志看到的仍是模型发出的调用。
|
|
163
|
+
|
|
164
|
+
- **压缩走 `tools/post-execute`**,这是允许替换结果内容的阶段。
|
|
165
|
+
|
|
166
|
+
两个监听器都注册在该行被挂载的 scope 里。因此 preset 行恰好覆盖它自己的 agent(preset 的 standing scope 是每个加入它的会话的祖先),而 host 行覆盖进程内所有 agent。
|
|
167
|
+
|
|
168
|
+
硬依赖只有 `tools` 服务。`settings`、`commands`、`systemPrompt` 都用 `ctx.get` 解析,缺少其中任何一个的组合仍然能获得优化。
|
|
169
|
+
|
|
170
|
+
### 注意:改写所用的接缝不是官方扩展点
|
|
171
|
+
|
|
172
|
+
harness 对 `tools/execute` wrapper 的文档原话是「may change only `exec.signal`」。替换 `arguments` **不是受支持的扩展点**——它能生效,只是因为执行对象要等到结果被通知时才被冻结。而失败的替代方案更糟:`tools/pre-execute` 被刻意设计为不能重写输入(参数在派发前就已记入日志并呈现),同一 layer 内也无法用新工具覆盖已有工具。
|
|
173
|
+
|
|
174
|
+
`dsh-rtk` 是**知情地**用了这条接缝,并在力所能及处做了对冲:替换只作用于单次调用、在 `finally` 里恢复,任何失败路径都退回模型发出的原命令。若未来的 harness 提前冻结执行对象,改写会**静默失效**而不是报错——命令按原样执行,压缩不受影响,因为 `tools/post-execute` 是**有文档记载的内容替换阶段**。
|
|
175
|
+
|
|
176
|
+
## 与 pi-rtk-optimizer 的差异
|
|
177
|
+
|
|
178
|
+
| pi-rtk-optimizer | dsh-rtk |
|
|
179
|
+
|---|---|
|
|
180
|
+
| 在 `tool_call` 钩子里改 `event.input.command` | 在一次派发期间替换 `exec.arguments`,随后恢复 |
|
|
181
|
+
| 在 `tool_result` 钩子里压缩 | 在 `tools/post-execute` waterfall 里压缩 |
|
|
182
|
+
| `/rtk` 打开 TUI 设置面板 | `/rtk` 输出文本状态;配置存在 harness 设置文档里 |
|
|
183
|
+
| 配置是它自己管的 JSON 文件 | 配置是 harness 设置命名空间,叠加在组合的 `config:` 块之上 |
|
|
184
|
+
| 通过 `tool_execution_*` 钩子清洗流式输出 | harness 没有对应钩子,故不清洗流式输出 |
|
|
185
|
+
| Windows 专用 shell 修正 | 未移植;目标部署是 POSIX |
|
|
186
|
+
|
|
187
|
+
其余部分——把重写委托给 `rtk rewrite`、退出码契约、rtk 缺失时的守卫、每个压缩开关的默认值、以及各项技术的算法——都是原样移植。
|
|
188
|
+
|
|
189
|
+
## 开发
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
pnpm run typecheck # 用真实 harness 类型跑 tsc --noEmit
|
|
193
|
+
pnpm test # 先构建,再跑 node --test test/
|
|
194
|
+
pnpm run build # 产出 lib/
|
|
195
|
+
pnpm run check # typecheck + test
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
测试 import 的是 `lib/`,所以 `pnpm test` 会先构建;否则只改 `src/` 而没构建的回归会静默通过。
|
|
199
|
+
|
|
200
|
+
`test/integration.test.ts` 用替身上下文驱动真实的 `apply()`,并调用真实的 `rtk` 二进制,所以在没装 rtk 的机器上会失败——这是有意的:重写路径就是这个功能本身。
|
|
201
|
+
|
|
202
|
+
## Star history
|
|
203
|
+
|
|
204
|
+
<picture>
|
|
205
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/wings1848/dsh-rtk/output/star-history-dark.svg">
|
|
206
|
+
<img alt="Star history chart" src="https://raw.githubusercontent.com/wings1848/dsh-rtk/output/star-history-light.svg">
|
|
207
|
+
</picture>
|
|
208
|
+
|
|
209
|
+
## 许可证
|
|
210
|
+
|
|
211
|
+
MIT
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
`dsh-rtk` is MIT licensed (see [LICENSE](LICENSE)). It is a derivative of an
|
|
4
|
+
MIT-licensed project, whose notice is reproduced below as that license requires.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## pi-rtk-optimizer
|
|
9
|
+
|
|
10
|
+
Copyright (c) 2026 MasuRii
|
|
11
|
+
|
|
12
|
+
Licensed under the MIT License.
|
|
13
|
+
|
|
14
|
+
Derived from <https://github.com/MasuRii/pi-rtk-optimizer>, version 0.9.0.
|
|
15
|
+
|
|
16
|
+
What came from it: the decision to delegate rewriting to `rtk rewrite` instead of
|
|
17
|
+
maintaining a rule table; rtk's exit-code contract (`0`/`3` carry a rewrite on
|
|
18
|
+
stdout, `1` means no equivalent, `2` means rtk refused); the runtime guard that
|
|
19
|
+
runs the original command when rtk is unavailable; the output-compaction pipeline
|
|
20
|
+
and each of its techniques (ANSI stripping, build filtering, test aggregation, git
|
|
21
|
+
compaction, linter aggregation, search grouping, source filtering, and both
|
|
22
|
+
truncation stages); the documented default of every configuration field; and the
|
|
23
|
+
`/rtk` command surface.
|
|
24
|
+
|
|
25
|
+
What did not: the seam it hooks (Pi's `tool_call`/`tool_result` events rather than
|
|
26
|
+
this harness's `tools/execute` and `tools/post-execute`), the TUI settings modal,
|
|
27
|
+
streamed-output sanitization, and the Windows-specific shell fixups. Each is
|
|
28
|
+
recorded under "Differences from pi-rtk-optimizer" in [README.md](README.md), and
|
|
29
|
+
[docs/verification.md](docs/verification.md) holds this port's acceptance evidence.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## MIT License, as it applies to the project above
|
|
34
|
+
|
|
35
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
36
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
37
|
+
in the Software without restriction, including without limitation the rights
|
|
38
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
39
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
40
|
+
furnished to do so, subject to the following conditions:
|
|
41
|
+
|
|
42
|
+
The above copyright notice and this permission notice shall be included in all
|
|
43
|
+
copies or substantial portions of the Software.
|
|
44
|
+
|
|
45
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
46
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
47
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
48
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
49
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
50
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
51
|
+
SOFTWARE.
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 840 500" width="840" height="500" role="img" aria-label="dsh-rtk rewrites bash commands to rtk and compacts the result before the model sees it">
|
|
2
|
+
<title>How dsh-rtk works</title>
|
|
3
|
+
<desc>A command flows from the model through a rewrite stage to rtk, then through a compaction stage back to the model. Measured on git status: 1050 characters become 215, an 80% reduction.</desc>
|
|
4
|
+
|
|
5
|
+
<!-- Opaque background: GitHub and npm render on both light and dark themes, so
|
|
6
|
+
a transparent plate designed for one of them smears on the other. -->
|
|
7
|
+
<rect width="840" height="500" fill="#f8fafc"/>
|
|
8
|
+
<rect x="0.5" y="0.5" width="839" height="499" fill="none" stroke="#e2e8f0"/>
|
|
9
|
+
|
|
10
|
+
<text x="32" y="52" font-family="system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif" font-size="25" font-weight="700" fill="#0f172a">dsh-rtk</text>
|
|
11
|
+
<text x="32" y="78" font-family="system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif" font-size="14" fill="#64748b">rewrites bash commands to rtk, then compacts what comes back</text>
|
|
12
|
+
|
|
13
|
+
<!-- Stage 1: what the model asked for -->
|
|
14
|
+
<rect x="32" y="104" width="776" height="72" rx="10" fill="#ffffff" stroke="#cbd5e1"/>
|
|
15
|
+
<text x="52" y="132" font-family="system-ui, -apple-system, sans-serif" font-size="12" font-weight="600" fill="#94a3b8" letter-spacing="0.6">THE MODEL ASKS FOR</text>
|
|
16
|
+
<text x="52" y="160" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="17" fill="#0f172a">git status</text>
|
|
17
|
+
|
|
18
|
+
<!-- connector -->
|
|
19
|
+
<line x1="120" y1="176" x2="120" y2="212" stroke="#0ea5e9" stroke-width="2"/>
|
|
20
|
+
<path d="M120 220 L115 210 L125 210 Z" fill="#0ea5e9"/>
|
|
21
|
+
<text x="140" y="203" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="#0284c7">tools/execute</text>
|
|
22
|
+
<text x="258" y="203" font-family="system-ui, -apple-system, sans-serif" font-size="13" fill="#64748b">— argument replaced for this call only</text>
|
|
23
|
+
|
|
24
|
+
<!-- Stage 2: what actually runs -->
|
|
25
|
+
<rect x="32" y="228" width="776" height="72" rx="10" fill="#ffffff" stroke="#cbd5e1"/>
|
|
26
|
+
<text x="52" y="256" font-family="system-ui, -apple-system, sans-serif" font-size="12" font-weight="600" fill="#94a3b8" letter-spacing="0.6">WHAT ACTUALLY RUNS</text>
|
|
27
|
+
<text x="52" y="284" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="17" fill="#0f172a">rtk git status</text>
|
|
28
|
+
<text x="330" y="284" font-family="system-ui, -apple-system, sans-serif" font-size="12.5" fill="#94a3b8">rtk stays the source of truth — it decides what it supports</text>
|
|
29
|
+
|
|
30
|
+
<!-- connector -->
|
|
31
|
+
<line x1="120" y1="300" x2="120" y2="336" stroke="#10b981" stroke-width="2"/>
|
|
32
|
+
<path d="M120 344 L115 334 L125 334 Z" fill="#10b981"/>
|
|
33
|
+
<text x="140" y="327" font-family="system-ui, -apple-system, sans-serif" font-size="13" font-weight="600" fill="#059669">tools/post-execute</text>
|
|
34
|
+
<text x="290" y="327" font-family="system-ui, -apple-system, sans-serif" font-size="13" fill="#64748b">— body summarized, status markers kept</text>
|
|
35
|
+
|
|
36
|
+
<!-- Stage 3: what the model sees -->
|
|
37
|
+
<rect x="32" y="352" width="776" height="116" rx="10" fill="#ffffff" stroke="#cbd5e1"/>
|
|
38
|
+
<text x="52" y="380" font-family="system-ui, -apple-system, sans-serif" font-size="12" font-weight="600" fill="#94a3b8" letter-spacing="0.6">THE MODEL SEES</text>
|
|
39
|
+
<text x="52" y="412" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="15" fill="#0f172a">Branch: main</text>
|
|
40
|
+
<text x="52" y="434" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="15" fill="#0f172a">Modified: 2 files</text>
|
|
41
|
+
<text x="52" y="456" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="15" fill="#0f172a">[exit code: 0]</text>
|
|
42
|
+
|
|
43
|
+
<!-- measured outcome -->
|
|
44
|
+
<rect x="470" y="394" width="318" height="56" rx="8" fill="#ecfdf5" stroke="#a7f3d0"/>
|
|
45
|
+
<text x="490" y="418" font-family="system-ui, -apple-system, sans-serif" font-size="13" fill="#065f46">measured on a 40-file repo</text>
|
|
46
|
+
<text x="490" y="440" font-family="system-ui, -apple-system, sans-serif" font-size="15" font-weight="700" fill="#047857">1050 → 215 chars (−80%)</text>
|
|
47
|
+
</svg>
|