pi-rg-fd 0.1.0 → 0.2.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 +18 -13
- package/index.js +3 -8
- package/package.json +4 -3
- package/prompt.js +5 -95
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# pi-rg-fd
|
|
2
2
|
|
|
3
|
-
Pi coding agent extension that rewrites the default system prompt's `grep` and `find` advice to `rg` and `fd
|
|
3
|
+
Pi coding agent extension that always rewrites the default system prompt's `grep` and `find` advice to `rg` and `fd`.
|
|
4
4
|
|
|
5
|
-
Pi 1.4's bash tool line names `grep` and `find`, and the default guideline still names `find`, so models reach for those commands
|
|
5
|
+
Pi 1.4's bash tool line names `grep` and `find`, and the default guideline still names `find`, so models reach for those commands. This package replaces those two exact lines in place. The usual prompt gets shorter, and text that is not one of those Pi 1.4 lines is left as Pi wrote it. You confirm that `rg` and `fd` run on your machine.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -30,31 +30,36 @@ Default guideline (bash enabled, and the grep/find/ls tools off), before:
|
|
|
30
30
|
Use bash for file operations like ls, rg, find
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Those lines are always rewritten to:
|
|
34
34
|
|
|
35
35
|
```text
|
|
36
36
|
Execute bash commands (ls, rg, fd, etc.)
|
|
37
37
|
Use bash for file operations like ls, rg, fd
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
`rg` and `fd` are shorter than `grep` and `find`. If neither line is present (a custom system prompt, or a future Pi release that rewords them), the hook returns without changing the prompt. The `before_agent_start` hook is a string replace cached by the prompt text, so the same input always yields the same output.
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
| --- | --- | --- |
|
|
44
|
-
| `rg` and `fd` | `Execute bash commands (ls, rg, fd, etc.)` | `Use bash for file operations like ls, rg, fd` |
|
|
45
|
-
| `rg` only | `Execute bash commands (ls, rg, find, etc.)` | unchanged (it already says `rg`; `find` stays) |
|
|
46
|
-
| `fd` only | `Execute bash commands (ls, grep, fd, etc.)` | `Use bash for file operations like ls, rg, fd` |
|
|
47
|
-
| `fdfind` only | `Execute bash commands (ls, grep, fdfind, etc.)` | `Use bash for file operations like ls, rg, fdfind` |
|
|
48
|
-
| neither | unchanged | unchanged |
|
|
42
|
+
Pi's interactive mode downloads `rg` and `fd` when they are missing, into `~/.pi/agent/bin` (or `$PI_CODING_AGENT_DIR/bin` when that variable is set; a leading `~` is expanded). Bash calls see that directory on `PATH`. The managed files are named `rg` and `fd`, plus `.exe` on Windows.
|
|
49
43
|
|
|
50
|
-
|
|
44
|
+
Debian and Ubuntu's apt package `fd-find` installs the binary as `fdfind`. Alias it so the rewritten prompt matches a command on `PATH`:
|
|
51
45
|
|
|
52
|
-
|
|
46
|
+
```bash
|
|
47
|
+
alias fd=fdfind
|
|
48
|
+
```
|
|
53
49
|
|
|
54
50
|
## Prompt text only
|
|
55
51
|
|
|
56
52
|
`pi-cli-guard` and `pi-prefer-rg` rewrite or block bash commands when the model runs them. `pi-rg-fd` edits the system prompt Pi already built. Commands the model still emits run unchanged.
|
|
57
53
|
|
|
54
|
+
## Compatibility
|
|
55
|
+
|
|
56
|
+
With `@earendil-works/pi-coding-agent` installed, `npm run compat` builds Pi's default system prompt from that package and loads this extension through Pi's extension loader. CI runs the same check on Ubuntu and Windows against the latest Pi release, every day and on manual dispatch.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm install --no-save @earendil-works/pi-coding-agent@latest
|
|
60
|
+
npm run compat
|
|
61
|
+
```
|
|
62
|
+
|
|
58
63
|
## License
|
|
59
64
|
|
|
60
65
|
MIT
|
package/index.js
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { rewritePrompt } from "./prompt.js";
|
|
2
2
|
|
|
3
3
|
const CACHE_LIMIT = 8;
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
* @param {{ rg: boolean, fd: "fd" | "fdfind" | null }} [tools]
|
|
7
|
-
*/
|
|
8
|
-
export function createExtension(tools = detectSearchTools()) {
|
|
5
|
+
export function createExtension() {
|
|
9
6
|
/** @type {Map<string, string>} */
|
|
10
7
|
const cache = new Map();
|
|
11
8
|
|
|
12
9
|
return function piRgFd(pi) {
|
|
13
|
-
if (!tools.rg && !tools.fd) return;
|
|
14
|
-
|
|
15
10
|
pi.on("before_agent_start", (event) => {
|
|
16
11
|
const input = event.systemPrompt;
|
|
17
12
|
if (typeof input !== "string") return;
|
|
@@ -21,7 +16,7 @@ export function createExtension(tools = detectSearchTools()) {
|
|
|
21
16
|
cache.delete(input);
|
|
22
17
|
cache.set(input, output);
|
|
23
18
|
} else {
|
|
24
|
-
output = rewritePrompt(input
|
|
19
|
+
output = rewritePrompt(input);
|
|
25
20
|
cache.set(input, output);
|
|
26
21
|
if (cache.size > CACHE_LIMIT) cache.delete(cache.keys().next().value);
|
|
27
22
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-rg-fd",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Pi extension that rewrites the default grep/find prompt lines to rg and fd
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Pi extension that rewrites the default grep/find prompt lines to rg and fd.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
|
7
7
|
"license": "MIT",
|
|
@@ -31,7 +31,8 @@
|
|
|
31
31
|
"node": ">=22.19.0"
|
|
32
32
|
},
|
|
33
33
|
"scripts": {
|
|
34
|
-
"test": "node --test"
|
|
34
|
+
"test": "node --test",
|
|
35
|
+
"compat": "node scripts/compat.js"
|
|
35
36
|
},
|
|
36
37
|
"pi": {
|
|
37
38
|
"extensions": [
|
package/prompt.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { statSync } from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
|
|
4
1
|
/**
|
|
5
2
|
* Default bash tool line in @earendil-works/pi-coding-agent 1.4.0
|
|
6
3
|
* (`bashToolSystemPromptContribution.snippet`).
|
|
@@ -13,89 +10,8 @@ export const BASH_SNIPPET = "Execute bash commands (ls, grep, find, etc.)";
|
|
|
13
10
|
*/
|
|
14
11
|
export const BASH_RULE = "Use bash for file operations like ls, rg, find";
|
|
15
12
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @param {Record<string, string | undefined>} env
|
|
20
|
-
* @param {string} name
|
|
21
|
-
* @param {string} platform
|
|
22
|
-
*/
|
|
23
|
-
function envValue(env, name, platform) {
|
|
24
|
-
if (platform !== "win32") return env[name] ?? "";
|
|
25
|
-
const lower = name.toLowerCase();
|
|
26
|
-
for (const key of Object.keys(env)) {
|
|
27
|
-
if (key.toLowerCase() === lower) return env[key] ?? "";
|
|
28
|
-
}
|
|
29
|
-
return "";
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* @param {string} name
|
|
34
|
-
* @param {string} platform
|
|
35
|
-
* @param {string} pathext
|
|
36
|
-
*/
|
|
37
|
-
function commandNames(name, platform, pathext) {
|
|
38
|
-
if (platform !== "win32") return [name];
|
|
39
|
-
const extensions = new Set([".exe", ".EXE"]);
|
|
40
|
-
for (const raw of pathext.split(";")) {
|
|
41
|
-
const ext = raw.trim();
|
|
42
|
-
if (ext === "" || ext === ".") {
|
|
43
|
-
extensions.add("");
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
const suffix = ext.startsWith(".") ? ext : `.${ext}`;
|
|
47
|
-
extensions.add(suffix);
|
|
48
|
-
extensions.add(suffix.toLowerCase());
|
|
49
|
-
extensions.add(suffix.toUpperCase());
|
|
50
|
-
}
|
|
51
|
-
return [...extensions].map((ext) => (ext ? name + ext : name));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* @param {string} file
|
|
56
|
-
* @param {string} platform
|
|
57
|
-
*/
|
|
58
|
-
function isRunnableFile(file, platform) {
|
|
59
|
-
try {
|
|
60
|
-
const stat = statSync(file);
|
|
61
|
-
if (!stat.isFile()) return false;
|
|
62
|
-
if (platform === "win32") return true;
|
|
63
|
-
return (stat.mode & 0o111) !== 0;
|
|
64
|
-
} catch {
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Locate `rg` and `fd` by scanning PATH. No processes are spawned.
|
|
71
|
-
* `fd` is `"fd"`, `"fdfind"` (Debian/Ubuntu), or null.
|
|
72
|
-
*
|
|
73
|
-
* @param {{ env?: NodeJS.ProcessEnv, platform?: string }} [options]
|
|
74
|
-
* @returns {{ rg: boolean, fd: "fd" | "fdfind" | null }}
|
|
75
|
-
*/
|
|
76
|
-
export function detectSearchTools(options = {}) {
|
|
77
|
-
const platform = options.platform ?? process.platform;
|
|
78
|
-
const env = options.env ?? process.env;
|
|
79
|
-
const dirs = envValue(env, "PATH", platform)
|
|
80
|
-
.split(platform === "win32" ? ";" : ":")
|
|
81
|
-
.filter((dir) => dir.length > 0);
|
|
82
|
-
const pathext = platform === "win32" ? envValue(env, "PATHEXT", platform) || WINDOWS_PATHEXT : "";
|
|
83
|
-
|
|
84
|
-
const has = (name) => {
|
|
85
|
-
const names = commandNames(name, platform, pathext);
|
|
86
|
-
for (const dir of dirs) {
|
|
87
|
-
for (const candidate of names) {
|
|
88
|
-
if (isRunnableFile(path.join(dir, candidate), platform)) return true;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
return false;
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
return {
|
|
95
|
-
rg: has("rg"),
|
|
96
|
-
fd: has("fd") ? "fd" : has("fdfind") ? "fdfind" : null,
|
|
97
|
-
};
|
|
98
|
-
}
|
|
13
|
+
const REWRITTEN_SNIPPET = "Execute bash commands (ls, rg, fd, etc.)";
|
|
14
|
+
const REWRITTEN_RULE = "Use bash for file operations like ls, rg, fd";
|
|
99
15
|
|
|
100
16
|
/**
|
|
101
17
|
* @param {string} text
|
|
@@ -112,15 +28,9 @@ function replaceExact(text, from, to) {
|
|
|
112
28
|
* unchanged (same string when nothing matches).
|
|
113
29
|
*
|
|
114
30
|
* @param {string} prompt
|
|
115
|
-
* @param {{ rg: boolean, fd: "fd" | "fdfind" | null }} tools
|
|
116
31
|
*/
|
|
117
|
-
export function rewritePrompt(prompt
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const fileTool = tools.fd ?? "find";
|
|
121
|
-
let next = replaceExact(prompt, BASH_SNIPPET, `Execute bash commands (ls, ${contentTool}, ${fileTool}, etc.)`);
|
|
122
|
-
if (tools.fd) {
|
|
123
|
-
next = replaceExact(next, BASH_RULE, `Use bash for file operations like ls, rg, ${tools.fd}`);
|
|
124
|
-
}
|
|
32
|
+
export function rewritePrompt(prompt) {
|
|
33
|
+
let next = replaceExact(prompt, BASH_SNIPPET, REWRITTEN_SNIPPET);
|
|
34
|
+
next = replaceExact(next, BASH_RULE, REWRITTEN_RULE);
|
|
125
35
|
return next;
|
|
126
36
|
}
|