@stfade/pi-read-delegator 1.0.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 ADDED
@@ -0,0 +1,107 @@
1
+ # pi-read-delegator
2
+
3
+ Pi extension that removes read tools (`read`, `grep`, `find`, `ls`) from the main model and delegates all read operations to a local **Reader** subagent.
4
+
5
+ ## How It Works
6
+
7
+ ```
8
+ Main Model Reader Subagent
9
+ ┌──────────┐ ┌──────────┐
10
+ │ write │ │ read │
11
+ │ edit │ ──task──> │ grep │
12
+ │ bash │ <──result── │ find │
13
+ │ (write) │ │ ls │
14
+ └──────────┘ └──────────┘
15
+ ```
16
+
17
+ - **Write tools** (`write`, `edit`) remain with the main model.
18
+ - **Read tools** (`read`, `grep`, `find`, `ls`) are blocked on the main model and routed to the Reader subagent.
19
+ - **Bash commands** are filtered: read commands go to Reader, write commands execute directly, ambiguous commands prompt the user.
20
+
21
+ ## Requirements
22
+
23
+ - [pi-subagents](https://github.com/earendil-works/pi-subagents) installed
24
+ - A local LLM for the Reader subagent (default: `lmstudio/nemotron-mini`)
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ pi install pi-read-delegator
30
+ ```
31
+
32
+ Or manually:
33
+
34
+ ```bash
35
+ npm install -g pi-read-delegator
36
+ ```
37
+
38
+ Then edit `~/.pi/agent/agents/reader.md` to set your preferred Reader model.
39
+
40
+ ## Commands
41
+
42
+ | Command | Description |
43
+ |---|---|
44
+ | `/read-delegator on` | Enable read delegation |
45
+ | `/read-delegator off` | Disable read delegation |
46
+ | `/read-delegator status` | Show current status |
47
+
48
+ ## Configuration
49
+
50
+ Edit `~/.pi/agent/read-delegator.json`:
51
+
52
+ ```json
53
+ {
54
+ "enabled": true,
55
+ "reader_subagent_name": "reader",
56
+ "blocked_tools": ["read", "grep", "find", "ls"],
57
+ "allowed_bash_write_commands": ["mkdir", "echo", "touch", "sed", "rm", "mv", "cp"],
58
+ "orchestrator_prompt": "You are an orchestrator. For any file reading... use the subagent tool...",
59
+ "language": "auto"
60
+ }
61
+ ```
62
+
63
+ | Field | Description |
64
+ |---|---|
65
+ | `enabled` | Enable/disable the extension |
66
+ | `reader_subagent_name` | Name of the Reader subagent (must match `reader.md`) |
67
+ | `blocked_tools` | Tools to block from the main model |
68
+ | `language` | `"auto"`, `"tr"`, or `"en"` |
69
+
70
+ ## Reader Subagent
71
+
72
+ The Reader template is created at `~/.pi/agent/agents/reader.md` on first run. Edit the `model:` line to use your preferred provider:
73
+
74
+ ```yaml
75
+ model: lmstudio/nemotron-mini # LM Studio
76
+ # model: ollama/phi3 # Ollama
77
+ # model: openai/gpt-4o-mini # OpenAI
78
+ # model: anthropic/claude-haiku # Anthropic
79
+ ```
80
+
81
+ ## Error Handling
82
+
83
+ When the Reader fails:
84
+
85
+ - **[R]etry** — resend the same task to Reader
86
+ - **[A]llow once** — temporarily unblock tools for one operation
87
+ - **[C]ancel** — report the failure
88
+
89
+ ## Bash Filter
90
+
91
+ | Read commands → Reader | Write commands → Direct |
92
+ |---|---|
93
+ | `cat`, `grep`, `find`, `ls` | `mkdir`, `touch`, `rm`, `mv` |
94
+ | `head`, `tail`, `less`, `wc` | `cp`, `chmod`, `chown` |
95
+ | `bat`, `rg`, `fd`, `awk` | `npm`, `git`, `docker` |
96
+ | `sed` (without `-i`) | `sed -i` (in-place edit) |
97
+
98
+ ## Supported Languages
99
+
100
+ - **English** (`en`)
101
+ - **Turkish** (`tr`)
102
+
103
+ Language is auto-detected from Pi's settings or the OS locale.
104
+
105
+ ## License
106
+
107
+ MIT
@@ -0,0 +1,37 @@
1
+ /**
2
+ * bash-filter.ts — Bash command classification and Reader forwarding
3
+ *
4
+ * Classifies shell commands as read-only (delegate to Reader subagent),
5
+ * write (execute directly), or ambiguous (prompt user).
6
+ */
7
+ /**
8
+ * Determine if a bash command is read-only and should be forwarded to Reader.
9
+ *
10
+ * Rules:
11
+ * - If the first word is in READ_COMMANDS → true
12
+ * - sed without -i flag → true (read-only stream edit)
13
+ * - sed with -i → false (in-place edit = write)
14
+ */
15
+ export declare function isReadCommand(command: string): boolean;
16
+ /**
17
+ * Determine if a bash command modifies the filesystem and should run directly.
18
+ *
19
+ * Rules:
20
+ * - If the first word is in WRITE_COMMANDS → true
21
+ * - sed with -i flag → true (in-place edit)
22
+ * - Command contains > or >> redirect → true (writes to file)
23
+ * - Command contains tee without -a flag → true (writes to file)
24
+ */
25
+ export declare function isWriteCommand(command: string): boolean;
26
+ /**
27
+ * Wrap a shell command into a Reader subagent task.
28
+ *
29
+ * Returns a formatted string instructing the Reader to execute and report
30
+ * minimal results.
31
+ */
32
+ export declare function wrapForReader(command: string): string;
33
+ /**
34
+ * Wrap a generic task (non-bash) into a Reader subagent task.
35
+ */
36
+ export declare function wrapTaskForReader(task: string): string;
37
+ //# sourceMappingURL=bash-filter.d.ts.map
package/bash-filter.js ADDED
@@ -0,0 +1,242 @@
1
+ "use strict";
2
+ /**
3
+ * bash-filter.ts — Bash command classification and Reader forwarding
4
+ *
5
+ * Classifies shell commands as read-only (delegate to Reader subagent),
6
+ * write (execute directly), or ambiguous (prompt user).
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.isReadCommand = isReadCommand;
10
+ exports.isWriteCommand = isWriteCommand;
11
+ exports.wrapForReader = wrapForReader;
12
+ exports.wrapTaskForReader = wrapTaskForReader;
13
+ // ---------------------------------------------------------------------------
14
+ // Command lists
15
+ // ---------------------------------------------------------------------------
16
+ /**
17
+ * Commands that ONLY read and should be forwarded to the Reader subagent.
18
+ * - sed without -i is read-only (stream editor writing to stdout).
19
+ * - awk is read-only (pattern scanning and processing language).
20
+ */
21
+ const READ_COMMANDS = new Set([
22
+ "cat",
23
+ "grep",
24
+ "find",
25
+ "ls",
26
+ "head",
27
+ "tail",
28
+ "less",
29
+ "wc",
30
+ "nl",
31
+ "more",
32
+ "bat",
33
+ "rg",
34
+ "fd",
35
+ "awk",
36
+ "du",
37
+ "df",
38
+ "stat",
39
+ "file",
40
+ "which",
41
+ "where",
42
+ "type",
43
+ "dir",
44
+ ]);
45
+ /**
46
+ * Commands that write to the filesystem and should execute directly.
47
+ * sed and tee are context-dependent — handled specially in isWriteCommand.
48
+ */
49
+ const WRITE_COMMANDS = new Set([
50
+ "mkdir",
51
+ "touch",
52
+ "echo",
53
+ "rm",
54
+ "mv",
55
+ "cp",
56
+ "chmod",
57
+ "chown",
58
+ "ln",
59
+ "rmdir",
60
+ "npm",
61
+ "pnpm",
62
+ "yarn",
63
+ "pip",
64
+ "cargo",
65
+ "go",
66
+ "npx",
67
+ "node",
68
+ "python",
69
+ "python3",
70
+ "git",
71
+ "docker",
72
+ "kubectl",
73
+ "tsc",
74
+ "make",
75
+ "cmake",
76
+ "dotnet",
77
+ "rustc",
78
+ "gcc",
79
+ "g++",
80
+ ]);
81
+ // ---------------------------------------------------------------------------
82
+ // Public API
83
+ // ---------------------------------------------------------------------------
84
+ /**
85
+ * Determine if a bash command is read-only and should be forwarded to Reader.
86
+ *
87
+ * Rules:
88
+ * - If the first word is in READ_COMMANDS → true
89
+ * - sed without -i flag → true (read-only stream edit)
90
+ * - sed with -i → false (in-place edit = write)
91
+ */
92
+ function isReadCommand(command) {
93
+ const argv = parseArgv(command);
94
+ if (argv.length === 0)
95
+ return false;
96
+ const cmd = argv[0].toLowerCase();
97
+ // sed is special: if -i is present, it's a write; otherwise read-only
98
+ if (cmd === "sed" || cmd === "sed.exe") {
99
+ return !hasInlineFlag(argv);
100
+ }
101
+ return READ_COMMANDS.has(cmd);
102
+ }
103
+ /**
104
+ * Determine if a bash command modifies the filesystem and should run directly.
105
+ *
106
+ * Rules:
107
+ * - If the first word is in WRITE_COMMANDS → true
108
+ * - sed with -i flag → true (in-place edit)
109
+ * - Command contains > or >> redirect → true (writes to file)
110
+ * - Command contains tee without -a flag → true (writes to file)
111
+ */
112
+ function isWriteCommand(command) {
113
+ const argv = parseArgv(command);
114
+ if (argv.length === 0)
115
+ return false;
116
+ const cmd = argv[0].toLowerCase();
117
+ // sed with -i = write
118
+ if (cmd === "sed" || cmd === "sed.exe") {
119
+ return hasInlineFlag(argv);
120
+ }
121
+ if (WRITE_COMMANDS.has(cmd))
122
+ return true;
123
+ // Check for output redirection markers (> or >>)
124
+ // We do a simple string match outside the parsed argv because parseArgv
125
+ // might stop at the redirect operator.
126
+ if (/\b>>?\b/.test(command))
127
+ return true;
128
+ // tee is ambiguous: if -a (append) it's write, otherwise also write
129
+ if (cmd === "tee" || cmd === "tee.exe")
130
+ return true;
131
+ return false;
132
+ }
133
+ /**
134
+ * Wrap a shell command into a Reader subagent task.
135
+ *
136
+ * Returns a formatted string instructing the Reader to execute and report
137
+ * minimal results.
138
+ */
139
+ function wrapForReader(command) {
140
+ return [
141
+ "Execute this shell command and return ONLY the essential result.",
142
+ "Max 5 lines or a single number. Never dump full file contents.",
143
+ `Command: ${command}`,
144
+ ].join("\n");
145
+ }
146
+ /**
147
+ * Wrap a generic task (non-bash) into a Reader subagent task.
148
+ */
149
+ function wrapTaskForReader(task) {
150
+ return [
151
+ "Execute this task and return ONLY the essential result.",
152
+ "Max 5 lines or a single number. Never dump full file contents.",
153
+ `Task: ${task}`,
154
+ ].join("\n");
155
+ }
156
+ // ---------------------------------------------------------------------------
157
+ // Internals
158
+ // ---------------------------------------------------------------------------
159
+ /**
160
+ * Parse a command string into argv tokens, respecting single/double quotes.
161
+ *
162
+ * This is a simplified parser — edge cases like escaped quotes inside
163
+ * opposite-quoted strings are handled on a best-effort basis.
164
+ */
165
+ function parseArgv(command) {
166
+ const tokens = [];
167
+ let current = "";
168
+ let inSingle = false;
169
+ let inDouble = false;
170
+ for (let i = 0; i < command.length; i++) {
171
+ const ch = command[i];
172
+ if (inSingle) {
173
+ if (ch === "'") {
174
+ inSingle = false;
175
+ }
176
+ else {
177
+ current += ch;
178
+ }
179
+ }
180
+ else if (inDouble) {
181
+ if (ch === '"') {
182
+ inDouble = false;
183
+ }
184
+ else if (ch === "\\" && i + 1 < command.length) {
185
+ // Simple escape handling inside double quotes
186
+ const next = command[i + 1];
187
+ if (next === '"' || next === "\\" || next === "$" || next === "`") {
188
+ current += next;
189
+ i++;
190
+ }
191
+ else {
192
+ current += ch;
193
+ }
194
+ }
195
+ else {
196
+ current += ch;
197
+ }
198
+ }
199
+ else {
200
+ if (ch === "'") {
201
+ inSingle = true;
202
+ }
203
+ else if (ch === '"') {
204
+ inDouble = true;
205
+ }
206
+ else if (ch === " " || ch === "\t") {
207
+ if (current.length > 0) {
208
+ tokens.push(current);
209
+ current = "";
210
+ }
211
+ }
212
+ else {
213
+ current += ch;
214
+ }
215
+ }
216
+ }
217
+ // Flush remaining token
218
+ if (current.length > 0) {
219
+ tokens.push(current);
220
+ }
221
+ return tokens;
222
+ }
223
+ /**
224
+ * Check whether `sed` has the -i (in-place) flag.
225
+ */
226
+ function hasInlineFlag(argv) {
227
+ for (let i = 1; i < argv.length; i++) {
228
+ const arg = argv[i];
229
+ // -i, -i.bak, --in-place, --in-place=.bak
230
+ if (arg === "-i" || arg.startsWith("-i.") || arg === "--in-place") {
231
+ return true;
232
+ }
233
+ if (arg.startsWith("--in-place=")) {
234
+ return true;
235
+ }
236
+ // Stop at the expression (s/.../.../ or -e '...') — flags after that
237
+ // might apply to the expression, not sed itself. In practice, -i always
238
+ // comes before the expression.
239
+ }
240
+ return false;
241
+ }
242
+ //# sourceMappingURL=bash-filter.js.map
package/config.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * config.ts — Configuration loader for pi-read-delegator
3
+ *
4
+ * Reads/writes ~/.pi/agent/read-delegator.json with sensible defaults.
5
+ * If the config file doesn't exist, it creates one with defaults.
6
+ * If the config file is corrupted, it overwrites with defaults and logs a warning.
7
+ */
8
+ export interface ReadDelegatorConfig {
9
+ enabled: boolean;
10
+ reader_subagent_name: string;
11
+ blocked_tools: string[];
12
+ allowed_bash_write_commands: string[];
13
+ orchestrator_prompt: string;
14
+ language: string;
15
+ }
16
+ /**
17
+ * Load configuration from disk.
18
+ * - If the file doesn't exist, create it with defaults and return them.
19
+ * - If the file is corrupted, overwrite with defaults, log a warning, return defaults.
20
+ * - Otherwise parse and return the typed config.
21
+ */
22
+ export declare function loadConfig(): ReadDelegatorConfig;
23
+ /**
24
+ * Save configuration to disk.
25
+ * @param config The config object to persist
26
+ * @param options.silent If true, suppress console output
27
+ */
28
+ export declare function saveConfig(config: ReadDelegatorConfig, options?: {
29
+ silent?: boolean;
30
+ }): void;
31
+ //# sourceMappingURL=config.d.ts.map
package/config.js ADDED
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ /**
3
+ * config.ts — Configuration loader for pi-read-delegator
4
+ *
5
+ * Reads/writes ~/.pi/agent/read-delegator.json with sensible defaults.
6
+ * If the config file doesn't exist, it creates one with defaults.
7
+ * If the config file is corrupted, it overwrites with defaults and logs a warning.
8
+ */
9
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ var desc = Object.getOwnPropertyDescriptor(m, k);
12
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
13
+ desc = { enumerable: true, get: function() { return m[k]; } };
14
+ }
15
+ Object.defineProperty(o, k2, desc);
16
+ }) : (function(o, m, k, k2) {
17
+ if (k2 === undefined) k2 = k;
18
+ o[k2] = m[k];
19
+ }));
20
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
21
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
22
+ }) : function(o, v) {
23
+ o["default"] = v;
24
+ });
25
+ var __importStar = (this && this.__importStar) || (function () {
26
+ var ownKeys = function(o) {
27
+ ownKeys = Object.getOwnPropertyNames || function (o) {
28
+ var ar = [];
29
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
30
+ return ar;
31
+ };
32
+ return ownKeys(o);
33
+ };
34
+ return function (mod) {
35
+ if (mod && mod.__esModule) return mod;
36
+ var result = {};
37
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
38
+ __setModuleDefault(result, mod);
39
+ return result;
40
+ };
41
+ })();
42
+ Object.defineProperty(exports, "__esModule", { value: true });
43
+ exports.loadConfig = loadConfig;
44
+ exports.saveConfig = saveConfig;
45
+ const fs = __importStar(require("fs"));
46
+ const os = __importStar(require("os"));
47
+ const path = __importStar(require("path"));
48
+ // ---------------------------------------------------------------------------
49
+ // Defaults
50
+ // ---------------------------------------------------------------------------
51
+ const DEFAULT_CONFIG = {
52
+ enabled: true,
53
+ reader_subagent_name: "reader",
54
+ blocked_tools: ["read", "grep", "find", "ls"],
55
+ allowed_bash_write_commands: [
56
+ "mkdir",
57
+ "echo",
58
+ "touch",
59
+ "sed",
60
+ "rm",
61
+ "mv",
62
+ "cp",
63
+ ],
64
+ orchestrator_prompt: "You are an orchestrator. For any file reading, searching, or listing operation, you MUST use the subagent tool with subagent='reader'. Do not use read/grep/find/ls yourself. If you need to run a shell command that only reads (like cat, grep, find, ls), also delegate it to the reader subagent.",
65
+ language: "auto",
66
+ };
67
+ // ---------------------------------------------------------------------------
68
+ // Path helpers
69
+ // ---------------------------------------------------------------------------
70
+ /** Expand ~ to the user's home directory. */
71
+ function expandTilde(filePath) {
72
+ if (filePath.startsWith("~")) {
73
+ return path.join(os.homedir(), filePath.slice(1));
74
+ }
75
+ return filePath;
76
+ }
77
+ /** Full path to the config file. */
78
+ function configFilePath() {
79
+ return expandTilde("~/.pi/agent/read-delegator.json");
80
+ }
81
+ // ---------------------------------------------------------------------------
82
+ // Public API
83
+ // ---------------------------------------------------------------------------
84
+ /**
85
+ * Load configuration from disk.
86
+ * - If the file doesn't exist, create it with defaults and return them.
87
+ * - If the file is corrupted, overwrite with defaults, log a warning, return defaults.
88
+ * - Otherwise parse and return the typed config.
89
+ */
90
+ function loadConfig() {
91
+ const filePath = configFilePath();
92
+ try {
93
+ if (!fs.existsSync(filePath)) {
94
+ // First run: create the config directory and write defaults
95
+ ensureDir(path.dirname(filePath));
96
+ saveConfig(DEFAULT_CONFIG, { silent: true });
97
+ return { ...DEFAULT_CONFIG };
98
+ }
99
+ const raw = fs.readFileSync(filePath, "utf-8");
100
+ const parsed = JSON.parse(raw);
101
+ // Merge with defaults so missing keys get their default values
102
+ const config = mergeDefaults(parsed, DEFAULT_CONFIG);
103
+ return config;
104
+ }
105
+ catch (err) {
106
+ // File is missing, unreadable, or invalid JSON → overwrite with defaults
107
+ console.warn(`[pi-read-delegator] Corrupted config file at ${filePath}. Overwriting with defaults. Error: ${err}`);
108
+ try {
109
+ ensureDir(path.dirname(filePath));
110
+ fs.writeFileSync(filePath, JSON.stringify(DEFAULT_CONFIG, null, 2), "utf-8");
111
+ }
112
+ catch {
113
+ // Silently fail — we tried our best
114
+ }
115
+ return { ...DEFAULT_CONFIG };
116
+ }
117
+ }
118
+ /**
119
+ * Save configuration to disk.
120
+ * @param config The config object to persist
121
+ * @param options.silent If true, suppress console output
122
+ */
123
+ function saveConfig(config, options) {
124
+ const filePath = configFilePath();
125
+ ensureDir(path.dirname(filePath));
126
+ try {
127
+ fs.writeFileSync(filePath, JSON.stringify(config, null, 2), "utf-8");
128
+ if (!options?.silent) {
129
+ console.log(`[pi-read-delegator] Config saved to ${filePath}`);
130
+ }
131
+ }
132
+ catch (err) {
133
+ console.error(`[pi-read-delegator] Failed to save config: ${err}`);
134
+ throw err;
135
+ }
136
+ }
137
+ // ---------------------------------------------------------------------------
138
+ // Helpers
139
+ // ---------------------------------------------------------------------------
140
+ /** Recursively merge a partial user config on top of the defaults. */
141
+ function mergeDefaults(partial, defaults) {
142
+ if (typeof partial !== "object" || partial === null) {
143
+ return { ...defaults };
144
+ }
145
+ const p = partial;
146
+ return {
147
+ enabled: typeof p.enabled === "boolean" ? p.enabled : defaults.enabled,
148
+ reader_subagent_name: typeof p.reader_subagent_name === "string"
149
+ ? p.reader_subagent_name
150
+ : defaults.reader_subagent_name,
151
+ blocked_tools: Array.isArray(p.blocked_tools)
152
+ ? p.blocked_tools
153
+ : defaults.blocked_tools,
154
+ allowed_bash_write_commands: Array.isArray(p.allowed_bash_write_commands)
155
+ ? p.allowed_bash_write_commands
156
+ : defaults.allowed_bash_write_commands,
157
+ orchestrator_prompt: typeof p.orchestrator_prompt === "string"
158
+ ? p.orchestrator_prompt
159
+ : defaults.orchestrator_prompt,
160
+ language: typeof p.language === "string" ? p.language : defaults.language,
161
+ };
162
+ }
163
+ /** Recursively ensure a directory exists. */
164
+ function ensureDir(dir) {
165
+ if (!fs.existsSync(dir)) {
166
+ fs.mkdirSync(dir, { recursive: true });
167
+ }
168
+ }
169
+ //# sourceMappingURL=config.js.map
package/index.d.ts ADDED
@@ -0,0 +1,61 @@
1
+ /**
2
+ * index.ts — pi-read-delegator extension entry point
3
+ *
4
+ * Lifecycle:
5
+ * init(agent) → load config, check deps, ensure template, enable/disable
6
+ * enable(agent) → block tools, add system prompt, attach bash filter
7
+ * disable(agent) → restore tools, remove prompt, detach bash filter
8
+ *
9
+ * Commands:
10
+ * /read-delegator on → enable the delegator
11
+ * /read-delegator off → disable the delegator
12
+ * /read-delegator status → show current status
13
+ */
14
+ import { type AgentWithSubagent } from "./reader-manager";
15
+ /**
16
+ * The Pi agent interface as consumed by pi-read-delegator.
17
+ * Extends the building-block types from sub-modules.
18
+ */
19
+ export interface PiAgent extends AgentWithSubagent {
20
+ /** Return current tool definitions. */
21
+ getTools(): Array<{
22
+ name: string;
23
+ }>;
24
+ /** Remove a tool by name. */
25
+ removeTool(name: string): void;
26
+ /** Add/re-add a tool definition. */
27
+ addTool(definition: {
28
+ name: string;
29
+ [key: string]: unknown;
30
+ }): void;
31
+ /** Append a persistent system message to the conversation. */
32
+ addSystemMessage(text: string): void;
33
+ /** Remove a previously-added system message by its exact text. */
34
+ removeSystemMessage(text: string): void;
35
+ /** Register a hook that fires BEFORE a tool with the given name is called. */
36
+ onBeforeToolCall(toolName: string, callback: (params: unknown) => Promise<unknown> | unknown): void;
37
+ /** Register a Pi command (like /read-delegator on). */
38
+ registerCommand(name: string, handler: (args: string[]) => Promise<string> | string): void;
39
+ /** Execute a raw shell command directly on the system. */
40
+ executeShellCommand(command: string): Promise<{
41
+ stdout: string;
42
+ stderr: string;
43
+ }>;
44
+ /** Prompt the user for input. */
45
+ promptUser(message: string): Promise<string>;
46
+ /** Display a message to the user. */
47
+ displayMessage(message: string): void;
48
+ /** Set status bar text. */
49
+ setStatusBarText(text: string): void;
50
+ }
51
+ /**
52
+ * Initialize the extension.
53
+ *
54
+ * This is the function Pi calls when loading the extension.
55
+ * It returns a lifecycle object with enable() and disable().
56
+ */
57
+ export declare function init(agent: PiAgent): {
58
+ enable: () => void;
59
+ disable: () => void;
60
+ };
61
+ //# sourceMappingURL=index.d.ts.map