pi-repoprompt-cli 0.2.5 → 0.2.7
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
|
@@ -7,6 +7,7 @@ Provides two tools:
|
|
|
7
7
|
- `rp_exec` — run `rp-cli -e <cmd>` against that binding (quiet defaults + output truncation)
|
|
8
8
|
|
|
9
9
|
Optional:
|
|
10
|
+
- Diff blocks in `rp_exec` output use `delta` when installed (honoring the user's global git/delta color config), with graceful fallback otherwise
|
|
10
11
|
- [Gurpartap/pi-readcache](https://github.com/Gurpartap/pi-readcache)-like caching for `rp_exec` calls that read files (`read` / `cat` / `read_file`) to save on tokens
|
|
11
12
|
- returns unchanged markers and diffs on repeat reads
|
|
12
13
|
|
|
@@ -7,6 +7,8 @@ It provides two Pi tools:
|
|
|
7
7
|
- `rp_bind` — bind to a specific RepoPrompt **window id** + **compose tab** (routing)
|
|
8
8
|
- `rp_exec` — run `rp-cli -e <cmd>` against that binding
|
|
9
9
|
|
|
10
|
+
Diff blocks in `rp_exec` output use `delta` when installed (honoring the user's global git/delta color config), with graceful fallback otherwise
|
|
11
|
+
|
|
10
12
|
## Optional: readcache for `rp_exec read`
|
|
11
13
|
|
|
12
14
|
If enabled, `rp_exec` will apply [Gurpartap/pi-readcache](https://github.com/Gurpartap/pi-readcache)-like token savings for single-command file reads, returning:
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
|
|
1
3
|
import type { ExtensionAPI, ExtensionContext, ToolRenderResultOptions } from "@mariozechner/pi-coding-agent";
|
|
2
4
|
import { highlightCode, Theme } from "@mariozechner/pi-coding-agent";
|
|
3
5
|
import { Text } from "@mariozechner/pi-tui";
|
|
@@ -239,7 +241,7 @@ function hasPipeOutsideQuotes(script: string): boolean {
|
|
|
239
241
|
* - Provide actionable error messages when blocked
|
|
240
242
|
* - For best command parsing (AST-based), install `just-bash` >= 2; otherwise it falls back to a legacy splitter
|
|
241
243
|
* - Syntax-highlight fenced code blocks in output (read, structure, etc.)
|
|
242
|
-
* -
|
|
244
|
+
* - Delta-powered diff highlighting (with graceful fallback when delta is unavailable)
|
|
243
245
|
*/
|
|
244
246
|
|
|
245
247
|
const DEFAULT_TIMEOUT_MS = 15 * 60 * 1000;
|
|
@@ -954,6 +956,88 @@ function parseFencedBlocks(text: string): FencedBlock[] {
|
|
|
954
956
|
return blocks;
|
|
955
957
|
}
|
|
956
958
|
|
|
959
|
+
const ANSI_ESCAPE_RE = /\x1b\[[0-9;]*m/g;
|
|
960
|
+
const DELTA_TIMEOUT_MS = 5000;
|
|
961
|
+
const DELTA_MAX_BUFFER = 8 * 1024 * 1024;
|
|
962
|
+
const DELTA_CACHE_MAX_ENTRIES = 200;
|
|
963
|
+
|
|
964
|
+
let deltaAvailable: boolean | null = null;
|
|
965
|
+
const deltaDiffCache = new Map<string, string | null>();
|
|
966
|
+
|
|
967
|
+
function isDeltaInstalled(): boolean {
|
|
968
|
+
if (deltaAvailable !== null) {
|
|
969
|
+
return deltaAvailable;
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
const check = spawnSync("delta", ["--version"], {
|
|
973
|
+
stdio: "ignore",
|
|
974
|
+
timeout: 1000,
|
|
975
|
+
});
|
|
976
|
+
|
|
977
|
+
deltaAvailable = !check.error && check.status === 0;
|
|
978
|
+
return deltaAvailable;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
function runDelta(diffText: string): string | null {
|
|
982
|
+
const result = spawnSync("delta", ["--color-only", "--paging=never"], {
|
|
983
|
+
encoding: "utf-8",
|
|
984
|
+
input: diffText,
|
|
985
|
+
timeout: DELTA_TIMEOUT_MS,
|
|
986
|
+
maxBuffer: DELTA_MAX_BUFFER,
|
|
987
|
+
});
|
|
988
|
+
|
|
989
|
+
if (result.error || result.status !== 0) {
|
|
990
|
+
return null;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
return typeof result.stdout === "string" ? result.stdout : null;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
function stripSyntheticHeader(deltaOutput: string): string {
|
|
997
|
+
const outputLines = deltaOutput.split("\n");
|
|
998
|
+
const bodyStart = outputLines.findIndex((line) => line.replace(ANSI_ESCAPE_RE, "").startsWith("@@"));
|
|
999
|
+
|
|
1000
|
+
if (bodyStart >= 0) {
|
|
1001
|
+
return outputLines.slice(bodyStart + 1).join("\n");
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
return deltaOutput;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
function renderDiffBlockWithDelta(code: string): string | null {
|
|
1008
|
+
if (!isDeltaInstalled()) {
|
|
1009
|
+
return null;
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
const cached = deltaDiffCache.get(code);
|
|
1013
|
+
if (cached !== undefined) {
|
|
1014
|
+
return cached;
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
let rendered = runDelta(code);
|
|
1018
|
+
|
|
1019
|
+
if (!rendered) {
|
|
1020
|
+
const syntheticDiff = [
|
|
1021
|
+
"--- a/file",
|
|
1022
|
+
"+++ b/file",
|
|
1023
|
+
"@@ -1,1 +1,1 @@",
|
|
1024
|
+
code,
|
|
1025
|
+
].join("\n");
|
|
1026
|
+
|
|
1027
|
+
const syntheticRendered = runDelta(syntheticDiff);
|
|
1028
|
+
if (syntheticRendered) {
|
|
1029
|
+
rendered = stripSyntheticHeader(syntheticRendered);
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
if (deltaDiffCache.size >= DELTA_CACHE_MAX_ENTRIES) {
|
|
1034
|
+
deltaDiffCache.clear();
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
deltaDiffCache.set(code, rendered);
|
|
1038
|
+
return rendered;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
957
1041
|
/**
|
|
958
1042
|
* Compute word-level diff with inverse highlighting on changed parts
|
|
959
1043
|
*/
|
|
@@ -1005,6 +1089,11 @@ function renderIntraLineDiff(
|
|
|
1005
1089
|
* Render diff lines with syntax highlighting (red/green, word-level inverse)
|
|
1006
1090
|
*/
|
|
1007
1091
|
function renderDiffBlock(code: string, theme: Theme): string {
|
|
1092
|
+
const deltaRendered = renderDiffBlockWithDelta(code);
|
|
1093
|
+
if (deltaRendered !== null) {
|
|
1094
|
+
return deltaRendered;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1008
1097
|
const lines = code.split("\n");
|
|
1009
1098
|
const result: string[] = [];
|
|
1010
1099
|
|
|
@@ -1094,7 +1183,7 @@ function renderDiffBlock(code: string, theme: Theme): string {
|
|
|
1094
1183
|
|
|
1095
1184
|
/**
|
|
1096
1185
|
* Render rp_exec output with syntax highlighting for fenced code blocks.
|
|
1097
|
-
* - ```diff blocks
|
|
1186
|
+
* - ```diff blocks use delta when available, with word-level fallback
|
|
1098
1187
|
* - Other fenced blocks get syntax highlighting via Pi's highlightCode
|
|
1099
1188
|
* - Non-fenced content is rendered dim (no markdown parsing)
|
|
1100
1189
|
*/
|
|
@@ -1458,8 +1547,11 @@ export default function (pi: ExtensionAPI) {
|
|
|
1458
1547
|
};
|
|
1459
1548
|
}
|
|
1460
1549
|
|
|
1461
|
-
|
|
1462
|
-
|
|
1550
|
+
// Parse read-like commands to:
|
|
1551
|
+
// - detect cacheable reads (when enabled)
|
|
1552
|
+
// - strip wrapper-only args like bypass_cache=true even when caching is disabled
|
|
1553
|
+
// (so agents can safely use bypass_cache in instructions regardless of config)
|
|
1554
|
+
const readRequest = parseReadFileRequest(params.cmd);
|
|
1463
1555
|
|
|
1464
1556
|
const cmdToRun = readRequest ? readRequest.cmdToRun : params.cmd;
|
|
1465
1557
|
|
package/package.json
CHANGED