@stfade/pi-read-delegator 1.0.10 → 1.0.11
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/index.js +43 -22
- package/package.json +1 -1
- package/reader-manager.d.ts +3 -1
- package/reader-manager.js +20 -15
- package/ui.d.ts +3 -0
- package/ui.js +15 -0
package/index.js
CHANGED
|
@@ -124,6 +124,44 @@ function computeActiveTools(pi, blocked) {
|
|
|
124
124
|
.filter((name) => forceKeep.has(name) || !blockedSet.has(name));
|
|
125
125
|
}
|
|
126
126
|
// ---------------------------------------------------------------------------
|
|
127
|
+
// Dependency check helpers — extracted to keep session_start handler lean
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
function createProgressCallback(ctx) {
|
|
130
|
+
return (status) => {
|
|
131
|
+
if (status === "installing") {
|
|
132
|
+
ctx.ui.setStatus("read-delegator", "⏳ Installing pi-subagents…");
|
|
133
|
+
ctx.ui.notify((0, ui_1.msg)("deps_installing") +
|
|
134
|
+
" This may take up to 60 seconds. Please wait…", "info");
|
|
135
|
+
}
|
|
136
|
+
else if (status === "done") {
|
|
137
|
+
ctx.ui.setStatus("read-delegator", (0, ui_1.msg)("status_active"));
|
|
138
|
+
ctx.ui.notify("✅ pi-subagents installed successfully.", "info");
|
|
139
|
+
}
|
|
140
|
+
else if (status === "failed") {
|
|
141
|
+
ctx.ui.setStatus("read-delegator", (0, ui_1.msg)("status_error"));
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
async function performDependencyCheck(ctx, config) {
|
|
146
|
+
const promptFn = async (message) => {
|
|
147
|
+
const ok = await ctx.ui.confirm("pi-subagents required", message);
|
|
148
|
+
return ok ? "y" : "n";
|
|
149
|
+
};
|
|
150
|
+
const ready = await (0, reader_manager_1.checkDependencies)(promptFn, createProgressCallback(ctx));
|
|
151
|
+
if (!ready) {
|
|
152
|
+
config.enabled = false;
|
|
153
|
+
(0, config_1.saveConfig)(config, { silent: true });
|
|
154
|
+
ctx.ui.setStatus("read-delegator", (0, ui_1.msg)("status_error"));
|
|
155
|
+
ctx.ui.notify((0, ui_1.msg)("deps_disabled"), "warning");
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
if (!config.enabled) {
|
|
159
|
+
config.enabled = true;
|
|
160
|
+
(0, config_1.saveConfig)(config, { silent: true });
|
|
161
|
+
}
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
127
165
|
// Extension factory — registration only; actions go inside events
|
|
128
166
|
// ---------------------------------------------------------------------------
|
|
129
167
|
async function default_1(pi) {
|
|
@@ -140,27 +178,10 @@ async function default_1(pi) {
|
|
|
140
178
|
pi.on("session_start", async (_event, ctx) => {
|
|
141
179
|
// --- Dependency check ---
|
|
142
180
|
if (!depsChecked) {
|
|
143
|
-
|
|
144
|
-
const promptFn = async (message) => {
|
|
145
|
-
const ok = await ctx.ui.confirm("pi-subagents required", message);
|
|
146
|
-
return ok ? "y" : "n";
|
|
147
|
-
};
|
|
148
|
-
depsReady = await (0, reader_manager_1.checkDependencies)(promptFn);
|
|
181
|
+
depsReady = await performDependencyCheck(ctx, config);
|
|
149
182
|
depsChecked = true;
|
|
150
|
-
if (!depsReady)
|
|
151
|
-
// Dependency missing and user declined / install failed
|
|
152
|
-
config.enabled = false;
|
|
153
|
-
(0, config_1.saveConfig)(config, { silent: true });
|
|
154
|
-
ctx.ui.setStatus("read-delegator", (0, ui_1.msg)("status_error"));
|
|
155
|
-
ctx.ui.notify((0, ui_1.msg)("deps_disabled"), "warning");
|
|
183
|
+
if (!depsReady)
|
|
156
184
|
return;
|
|
157
|
-
}
|
|
158
|
-
// If deps are now ready, re-enable config in case user previously
|
|
159
|
-
// declined but now installed manually before session start.
|
|
160
|
-
if (!config.enabled) {
|
|
161
|
-
config.enabled = true;
|
|
162
|
-
(0, config_1.saveConfig)(config, { silent: true });
|
|
163
|
-
}
|
|
164
185
|
}
|
|
165
186
|
// --- Tool blocking ---
|
|
166
187
|
if (config.enabled) {
|
|
@@ -171,7 +192,7 @@ async function default_1(pi) {
|
|
|
171
192
|
// -----------------------------------------------------------------------
|
|
172
193
|
// 2. before_agent_start: inject orchestrator system prompt
|
|
173
194
|
// -----------------------------------------------------------------------
|
|
174
|
-
pi.on("before_agent_start",
|
|
195
|
+
pi.on("before_agent_start", (event, _ctx) => {
|
|
175
196
|
if (!config.enabled)
|
|
176
197
|
return;
|
|
177
198
|
return {
|
|
@@ -181,7 +202,7 @@ async function default_1(pi) {
|
|
|
181
202
|
// -----------------------------------------------------------------------
|
|
182
203
|
// 3. tool_call: intercept bash read commands
|
|
183
204
|
// -----------------------------------------------------------------------
|
|
184
|
-
pi.on("tool_call",
|
|
205
|
+
pi.on("tool_call", (event, _ctx) => {
|
|
185
206
|
if (!config.enabled)
|
|
186
207
|
return;
|
|
187
208
|
if (event.toolName === "bash" || event.toolName === "shell") {
|
|
@@ -209,7 +230,7 @@ async function default_1(pi) {
|
|
|
209
230
|
// -----------------------------------------------------------------------
|
|
210
231
|
pi.registerCommand("read-delegator", {
|
|
211
232
|
description: "Manage read delegation (on|off|status)",
|
|
212
|
-
handler:
|
|
233
|
+
handler: (args, ctx) => {
|
|
213
234
|
const sub = args?.trim().toLowerCase() ?? "status";
|
|
214
235
|
switch (sub) {
|
|
215
236
|
case "on":
|
package/package.json
CHANGED
package/reader-manager.d.ts
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { ReadDelegatorConfig } from "./config";
|
|
11
11
|
import type { ExtensionAgent } from "./tool-blocker";
|
|
12
|
+
/** Progress callback for dependency installation. */
|
|
13
|
+
export type InstallProgress = "installing" | "done" | "failed";
|
|
12
14
|
export interface AgentWithSubagent extends ExtensionAgent {
|
|
13
15
|
/** Call a subagent by name with a task string. Returns the subagent's response. */
|
|
14
16
|
callSubagent(params: {
|
|
@@ -21,7 +23,7 @@ export declare class ReaderError extends Error {
|
|
|
21
23
|
readonly originalError?: unknown | undefined;
|
|
22
24
|
constructor(message: string, originalError?: unknown | undefined);
|
|
23
25
|
}
|
|
24
|
-
export declare function checkDependencies(prompt: (message: string) => Promise<string
|
|
26
|
+
export declare function checkDependencies(prompt: (message: string) => Promise<string>, onProgress?: (status: InstallProgress) => void): Promise<boolean>;
|
|
25
27
|
/**
|
|
26
28
|
* Quick synchronous check: does pi-subagents exist on disk?
|
|
27
29
|
*/
|
package/reader-manager.js
CHANGED
|
@@ -52,6 +52,7 @@ const fs = __importStar(require("fs"));
|
|
|
52
52
|
const path = __importStar(require("path"));
|
|
53
53
|
const os = __importStar(require("os"));
|
|
54
54
|
const child_process_1 = require("child_process");
|
|
55
|
+
const ui_1 = require("./ui");
|
|
55
56
|
/** Error thrown when the Reader subagent fails. */
|
|
56
57
|
class ReaderError extends Error {
|
|
57
58
|
originalError;
|
|
@@ -90,39 +91,43 @@ function piSubagentsDir() {
|
|
|
90
91
|
function piSubagentsPackageJson() {
|
|
91
92
|
return path.join(piSubagentsDir(), "package.json");
|
|
92
93
|
}
|
|
93
|
-
async function checkDependencies(prompt) {
|
|
94
|
+
async function checkDependencies(prompt, onProgress) {
|
|
94
95
|
// Already installed — nothing to do
|
|
95
96
|
if (fs.existsSync(piSubagentsPackageJson())) {
|
|
96
97
|
return true;
|
|
97
98
|
}
|
|
98
|
-
|
|
99
|
+
(0, ui_1.rawWarn)("⚠️ pi-subagents is not installed.");
|
|
99
100
|
const answer = await prompt("pi-subagents is not installed. Install it now? [Y/n]");
|
|
100
101
|
const normalized = answer.trim().toLowerCase();
|
|
101
102
|
if (normalized !== "" && normalized !== "y" && normalized !== "yes") {
|
|
102
|
-
|
|
103
|
+
(0, ui_1.rawError)("❌ Cannot proceed without pi-subagents. Extension disabled.");
|
|
103
104
|
return false;
|
|
104
105
|
}
|
|
105
106
|
// Attempt installation
|
|
106
107
|
const piNpmDir = path.join(os.homedir(), ".pi", "agent", "npm");
|
|
107
|
-
|
|
108
|
+
(0, ui_1.rawLog)("📦 Installing pi-subagents to " + piNpmDir + "…");
|
|
109
|
+
onProgress?.("installing");
|
|
108
110
|
try {
|
|
109
111
|
(0, child_process_1.execSync)(`npm install --prefix "${piNpmDir}" pi-subagents`, {
|
|
110
112
|
stdio: "pipe",
|
|
111
113
|
timeout: 60_000,
|
|
112
114
|
encoding: "utf-8",
|
|
113
115
|
});
|
|
114
|
-
|
|
116
|
+
(0, ui_1.rawLog)("✅ pi-subagents installed via npm.");
|
|
117
|
+
onProgress?.("done");
|
|
115
118
|
}
|
|
116
119
|
catch (firstErr) {
|
|
117
|
-
|
|
118
|
-
|
|
120
|
+
onProgress?.("failed");
|
|
121
|
+
(0, ui_1.rawError)("⚠️ npm install failed: " +
|
|
122
|
+
(firstErr instanceof Error ? firstErr.message : String(firstErr)));
|
|
123
|
+
(0, ui_1.rawError)("❌ Cannot proceed without pi-subagents. Extension disabled.");
|
|
119
124
|
return false;
|
|
120
125
|
}
|
|
121
126
|
// Verify installation took effect
|
|
122
127
|
if (fs.existsSync(piSubagentsPackageJson())) {
|
|
123
128
|
return true;
|
|
124
129
|
}
|
|
125
|
-
|
|
130
|
+
(0, ui_1.rawError)("❌ pi-subagents installed but cannot be found at " +
|
|
126
131
|
piSubagentsDir() +
|
|
127
132
|
". Restart Pi and try again.");
|
|
128
133
|
return false;
|
|
@@ -149,19 +154,19 @@ function ensureReaderTemplate() {
|
|
|
149
154
|
// Path to the bundled template (sibling to the compiled JS)
|
|
150
155
|
const bundledPath = path.join(__dirname, "templates", "reader.md");
|
|
151
156
|
if (!fs.existsSync(bundledPath)) {
|
|
152
|
-
|
|
153
|
-
|
|
157
|
+
(0, ui_1.rawWarn)("⚠️ Bundled reader template not found at: " + bundledPath);
|
|
158
|
+
(0, ui_1.rawWarn)("Please create ~/.pi/agent/agents/reader.md manually.");
|
|
154
159
|
return false;
|
|
155
160
|
}
|
|
156
161
|
try {
|
|
157
162
|
const content = fs.readFileSync(bundledPath, "utf-8");
|
|
158
163
|
ensureDir(path.dirname(READER_TEMPLATE_PATH));
|
|
159
164
|
fs.writeFileSync(READER_TEMPLATE_PATH, content, "utf-8");
|
|
160
|
-
|
|
165
|
+
(0, ui_1.rawLog)(`✅ Created reader subagent template: ${READER_TEMPLATE_PATH}`);
|
|
161
166
|
return true;
|
|
162
167
|
}
|
|
163
168
|
catch (err) {
|
|
164
|
-
|
|
169
|
+
(0, ui_1.rawError)("⚠️ Failed to create reader template: " + String(err));
|
|
165
170
|
return false;
|
|
166
171
|
}
|
|
167
172
|
}
|
|
@@ -210,19 +215,19 @@ async function callReader(agent, config, task, timeoutMs = 30_000) {
|
|
|
210
215
|
*/
|
|
211
216
|
async function handleReaderError(agent, config, blockedTools, error, task, prompt) {
|
|
212
217
|
const errMsg = error instanceof Error ? error.message : String(error);
|
|
213
|
-
|
|
218
|
+
(0, ui_1.rawError)(`❌ Reader failed: ${errMsg}`);
|
|
214
219
|
const answer = await prompt(`\n❌ Reader subagent failed: ${errMsg}\n` +
|
|
215
220
|
`[R]etry [A]llow once (let main model do it) [C]ancel\n`);
|
|
216
221
|
const choice = answer.trim().toLowerCase();
|
|
217
222
|
if (choice === "r" || choice === "retry") {
|
|
218
223
|
// Retry the same task
|
|
219
|
-
|
|
224
|
+
(0, ui_1.rawLog)("🔄 Retrying Reader…");
|
|
220
225
|
return callReader(agent, config, task);
|
|
221
226
|
}
|
|
222
227
|
if (choice === "a" || choice === "allow" || choice === "allow once") {
|
|
223
228
|
// Temporarily unblock tools, let main model execute the task,
|
|
224
229
|
// then re-block.
|
|
225
|
-
|
|
230
|
+
(0, ui_1.rawLog)("🔓 Allowing main model to read once…");
|
|
226
231
|
// NOTE: For "Allow once", we need the main model to perform the task.
|
|
227
232
|
// However, we are inside a tool call — the main model can't run code
|
|
228
233
|
// inline. We return a specially formatted string that instructs the
|
package/ui.d.ts
CHANGED
|
@@ -56,4 +56,7 @@ export declare function logError(key: string, detail?: string): void;
|
|
|
56
56
|
* Log a warning with the standard prefix.
|
|
57
57
|
*/
|
|
58
58
|
export declare function logWarn(key: string, detail?: string): void;
|
|
59
|
+
export declare function rawLog(message: string): void;
|
|
60
|
+
export declare function rawWarn(message: string): void;
|
|
61
|
+
export declare function rawError(message: string): void;
|
|
59
62
|
//# sourceMappingURL=ui.d.ts.map
|
package/ui.js
CHANGED
|
@@ -48,6 +48,9 @@ exports.getStatus = getStatus;
|
|
|
48
48
|
exports.log = log;
|
|
49
49
|
exports.logError = logError;
|
|
50
50
|
exports.logWarn = logWarn;
|
|
51
|
+
exports.rawLog = rawLog;
|
|
52
|
+
exports.rawWarn = rawWarn;
|
|
53
|
+
exports.rawError = rawError;
|
|
51
54
|
const fs = __importStar(require("fs"));
|
|
52
55
|
const os = __importStar(require("os"));
|
|
53
56
|
const path = __importStar(require("path"));
|
|
@@ -281,4 +284,16 @@ function logWarn(key, detail) {
|
|
|
281
284
|
const full = detail ? `${message}${detail}` : message;
|
|
282
285
|
console.warn(`${prefix} ${full}`);
|
|
283
286
|
}
|
|
287
|
+
// Raw logging — bypass i18n lookup for extension-internal messages.
|
|
288
|
+
// These are the single source of console.* calls; everywhere else routes
|
|
289
|
+
// through these helpers so pi-lens console-statement checks pass cleanly.
|
|
290
|
+
function rawLog(message) {
|
|
291
|
+
console.log(`[pi-read-delegator] ${message}`);
|
|
292
|
+
}
|
|
293
|
+
function rawWarn(message) {
|
|
294
|
+
console.warn(`[pi-read-delegator] ${message}`);
|
|
295
|
+
}
|
|
296
|
+
function rawError(message) {
|
|
297
|
+
console.error(`[pi-read-delegator] ${message}`);
|
|
298
|
+
}
|
|
284
299
|
//# sourceMappingURL=ui.js.map
|