@diegopetrucci/pi-extensions 0.1.74 → 0.1.78
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/LICENSE +2 -0
- package/README.md +17 -12
- package/extensions/agent-workflow-audit/README.md +1 -1
- package/extensions/agent-workflow-audit/index.ts +1631 -1009
- package/extensions/agent-workflow-audit/package.json +1 -1
- package/extensions/annotate-git-diff/README.md +3 -1
- package/extensions/annotate-git-diff/clipboard.ts +109 -100
- package/extensions/annotate-git-diff/git.ts +846 -768
- package/extensions/annotate-git-diff/glimpseui.d.ts +87 -78
- package/extensions/annotate-git-diff/index.ts +712 -671
- package/extensions/annotate-git-diff/package.json +1 -1
- package/extensions/annotate-git-diff/prompt.ts +45 -45
- package/extensions/annotate-git-diff/quiet-glimpse.ts +161 -155
- package/extensions/annotate-git-diff/review-server.ts +337 -311
- package/extensions/annotate-git-diff/types.ts +132 -132
- package/extensions/annotate-git-diff/ui.ts +27 -27
- package/extensions/annotate-git-diff/watch.ts +74 -74
- package/extensions/annotate-git-diff/web/app.js +1947 -1884
- package/extensions/annotate-git-diff/web/index.html +5 -6
- package/extensions/annotate-last-message/README.md +1 -1
- package/extensions/annotate-last-message/glimpseui.d.ts +87 -78
- package/extensions/annotate-last-message/index.ts +210 -206
- package/extensions/annotate-last-message/package.json +1 -1
- package/extensions/annotate-last-message/prompt.ts +87 -66
- package/extensions/annotate-last-message/quiet-glimpse.ts +161 -155
- package/extensions/annotate-last-message/session.ts +94 -89
- package/extensions/annotate-last-message/theme.ts +199 -193
- package/extensions/annotate-last-message/types.ts +23 -23
- package/extensions/annotate-last-message/ui.ts +27 -25
- package/extensions/annotate-last-message/web/app.js +4 -7
- package/extensions/annotate-last-message/web/index.html +3 -3
- package/extensions/annotate-last-message/web/md-renderer.js +1 -1
- package/extensions/brrr/README.md +1 -1
- package/extensions/brrr/index.ts +213 -191
- package/extensions/brrr/package.json +1 -1
- package/extensions/claude-fast/README.md +5 -79
- package/extensions/claude-fast/index.ts +31 -289
- package/extensions/claude-fast/package.json +2 -3
- package/extensions/code-reviewer/README.md +6 -6
- package/extensions/code-reviewer/index.ts +1825 -1373
- package/extensions/code-reviewer/package.json +1 -1
- package/extensions/confirm-destructive/README.md +1 -1
- package/extensions/confirm-destructive/index.ts +50 -52
- package/extensions/confirm-destructive/package.json +1 -1
- package/extensions/context-cap/README.md +9 -9
- package/extensions/context-cap/index.ts +313 -305
- package/extensions/context-cap/package.json +2 -2
- package/extensions/context-inspector/index.ts +1211 -1064
- package/extensions/context-inspector/package.json +1 -1
- package/extensions/contrarian/README.md +4 -3
- package/extensions/contrarian/index.ts +1863 -1737
- package/extensions/contrarian/package.json +1 -1
- package/extensions/dirty-repo-guard/index.ts +37 -41
- package/extensions/dirty-repo-guard/package.json +1 -1
- package/extensions/dynamic-context-pruning/README.md +11 -43
- package/extensions/dynamic-context-pruning/index.ts +2131 -2105
- package/extensions/dynamic-context-pruning/package.json +1 -1
- package/extensions/fast/README.md +52 -14
- package/extensions/fast/index.ts +513 -317
- package/extensions/fast/package.json +1 -1
- package/extensions/git-footer/README.md +1 -1
- package/extensions/git-footer/index.ts +458 -411
- package/extensions/git-footer/package.json +2 -3
- package/extensions/gnosis/index.ts +180 -130
- package/extensions/gnosis/package.json +1 -1
- package/extensions/inline-bash/index.ts +87 -103
- package/extensions/inline-bash/package.json +1 -1
- package/extensions/librarian/README.md +1 -1
- package/extensions/librarian/index.ts +1877 -1419
- package/extensions/librarian/package.json +1 -1
- package/extensions/minimal-footer/README.md +5 -5
- package/extensions/minimal-footer/index.ts +987 -1012
- package/extensions/minimal-footer/minimal-footer.example.json +1 -1
- package/extensions/minimal-footer/openai-usage.ts +195 -190
- package/extensions/minimal-footer/package.json +1 -1
- package/extensions/notify/index.ts +222 -230
- package/extensions/notify/package.json +1 -1
- package/extensions/openai-fast/README.md +5 -73
- package/extensions/openai-fast/index.ts +32 -272
- package/extensions/openai-fast/package.json +2 -3
- package/extensions/oracle/README.md +4 -3
- package/extensions/oracle/index.ts +1740 -1627
- package/extensions/oracle/package.json +1 -1
- package/extensions/permission-gate/README.md +3 -0
- package/extensions/permission-gate/index.ts +785 -612
- package/extensions/permission-gate/package.json +1 -1
- package/extensions/permission-gate/powershell-safety.ts +840 -793
- package/extensions/project-mcp-json/.pi-fleet-tested-version +1 -0
- package/extensions/project-mcp-json/README.md +199 -0
- package/extensions/project-mcp-json/config.ts +564 -0
- package/extensions/project-mcp-json/index.ts +119 -0
- package/extensions/project-mcp-json/package.json +38 -0
- package/extensions/quiet-tools/.pi-fleet-tested-version +1 -1
- package/extensions/quiet-tools/README.md +30 -19
- package/extensions/quiet-tools/index.ts +376 -291
- package/extensions/quiet-tools/package.json +2 -2
- package/extensions/review/README.md +2 -2
- package/extensions/review/index.ts +1745 -1872
- package/extensions/review/package.json +1 -1
- package/extensions/todo/index.ts +280 -280
- package/extensions/todo/package.json +1 -1
- package/extensions/triage-comments/README.md +6 -4
- package/extensions/triage-comments/index.ts +2620 -1888
- package/extensions/triage-comments/package.json +1 -1
- package/package.json +9 -6
- package/assets/social-preview.png +0 -0
- package/extensions/claude-fast/claude-fast.example.json +0 -4
- package/extensions/openai-fast/openai-fast.example.json +0 -4
|
@@ -1,293 +1,35 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
CONFIG_DIR_NAME,
|
|
5
|
-
getAgentDir,
|
|
6
|
-
type ExtensionAPI,
|
|
7
|
-
type ExtensionContext,
|
|
8
|
-
} from "@earendil-works/pi-coding-agent";
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
9
2
|
|
|
10
3
|
const EXTENSION_ID = "claude-fast";
|
|
11
|
-
const PROVIDER_ID = "anthropic";
|
|
12
|
-
const API_ID = "anthropic-messages";
|
|
13
|
-
const FAST_SPEED = "fast";
|
|
14
4
|
const FAST_BETA = "fast-mode-2026-02-01";
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
[P in keyof T]?: T[P] extends object ? RecursivePartial<T[P]> : T[P];
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
type PayloadRecord = Record<string, unknown>;
|
|
49
|
-
|
|
50
|
-
type Eligibility = {
|
|
51
|
-
eligible: boolean;
|
|
52
|
-
modelKey: string;
|
|
53
|
-
reason?: string;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
type HeaderModel = {
|
|
57
|
-
headers?: Record<string, string>;
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
function readConfigFile(path: string): RecursivePartial<ClaudeFastConfig> {
|
|
61
|
-
if (!existsSync(path)) return {};
|
|
62
|
-
|
|
63
|
-
try {
|
|
64
|
-
const parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
65
|
-
return isPayloadRecord(parsed) ? (parsed as RecursivePartial<ClaudeFastConfig>) : {};
|
|
66
|
-
} catch (error) {
|
|
67
|
-
console.error(`Warning: Could not parse ${path}: ${error}`);
|
|
68
|
-
return {};
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function normalizeBoolean(value: unknown, fallback: boolean): boolean {
|
|
73
|
-
return typeof value === "boolean" ? value : fallback;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function mergeConfig(
|
|
77
|
-
base: ClaudeFastConfig,
|
|
78
|
-
overrides: RecursivePartial<ClaudeFastConfig>,
|
|
79
|
-
): ClaudeFastConfig {
|
|
80
|
-
return {
|
|
81
|
-
enabled: normalizeBoolean(overrides.enabled, base.enabled),
|
|
82
|
-
showStatus: normalizeBoolean(overrides.showStatus, base.showStatus),
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function canReadProjectConfig(ctx: ProjectConfigContext): boolean {
|
|
87
|
-
return typeof ctx.isProjectTrusted === "function" && ctx.isProjectTrusted();
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function findProjectConfigPath(cwd: string): string {
|
|
91
|
-
let current = cwd;
|
|
92
|
-
while (true) {
|
|
93
|
-
const candidate = join(current, CONFIG_DIR_NAME, "claude-fast.json");
|
|
94
|
-
if (existsSync(candidate)) return candidate;
|
|
95
|
-
|
|
96
|
-
const parent = dirname(current);
|
|
97
|
-
if (parent === current) return join(cwd, CONFIG_DIR_NAME, "claude-fast.json");
|
|
98
|
-
current = parent;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function loadConfig(ctx: ProjectConfigContext): ClaudeFastConfig {
|
|
103
|
-
const globalConfig = readConfigFile(join(getAgentDir(), "extensions", "claude-fast.json"));
|
|
104
|
-
const projectConfig = canReadProjectConfig(ctx) ? readConfigFile(findProjectConfigPath(ctx.cwd)) : {};
|
|
105
|
-
return mergeConfig(mergeConfig(DEFAULT_CONFIG, globalConfig), projectConfig);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function isPayloadRecord(payload: unknown): payload is PayloadRecord {
|
|
109
|
-
return typeof payload === "object" && payload !== null && !Array.isArray(payload);
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function modelKey(ctx: ExtensionContext): string {
|
|
113
|
-
const model = ctx.model;
|
|
114
|
-
return model ? `${model.provider}/${model.id}` : "no-model";
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function isFastEnabled(state: SessionState): boolean {
|
|
118
|
-
if (state.override === "on") return true;
|
|
119
|
-
if (state.override === "off") return false;
|
|
120
|
-
return state.config.enabled;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function describeMode(state: SessionState): string {
|
|
124
|
-
if (state.override === "on") return "on (session override)";
|
|
125
|
-
if (state.override === "off") return "off (session override)";
|
|
126
|
-
return state.config.enabled ? "on (config default)" : "off (config default)";
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
function getEligibility(ctx: ExtensionContext): Eligibility {
|
|
130
|
-
const model = ctx.model;
|
|
131
|
-
if (!model) {
|
|
132
|
-
return { eligible: false, modelKey: "no-model", reason: "no model is selected" };
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const key = `${model.provider}/${model.id}`;
|
|
136
|
-
if (model.provider !== PROVIDER_ID) {
|
|
137
|
-
return {
|
|
138
|
-
eligible: false,
|
|
139
|
-
modelKey: key,
|
|
140
|
-
reason: `current provider is ${model.provider}, not ${PROVIDER_ID}`,
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
if (model.api !== API_ID) {
|
|
145
|
-
return {
|
|
146
|
-
eligible: false,
|
|
147
|
-
modelKey: key,
|
|
148
|
-
reason: `current API is ${model.api}, not ${API_ID}`,
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
if (!SUPPORTED_MODELS.has(model.id)) {
|
|
153
|
-
return {
|
|
154
|
-
eligible: false,
|
|
155
|
-
modelKey: key,
|
|
156
|
-
reason: "Fast mode is only enabled for Claude Opus 4.8 and Claude Opus 5",
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return { eligible: true, modelKey: key };
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function splitBetaHeader(value: string | undefined): string[] {
|
|
164
|
-
return (value ?? "")
|
|
165
|
-
.split(",")
|
|
166
|
-
.map((part) => part.trim())
|
|
167
|
-
.filter(Boolean);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function syncModelBetaHeader(ctx: ExtensionContext, state: SessionState): void {
|
|
171
|
-
const model = ctx.model as (typeof ctx.model & HeaderModel) | undefined;
|
|
172
|
-
if (!model || model.provider !== PROVIDER_ID || model.api !== API_ID) return;
|
|
173
|
-
|
|
174
|
-
const shouldEnable = isFastEnabled(state) && getEligibility(ctx).eligible;
|
|
175
|
-
const headers = { ...(model.headers ?? {}) };
|
|
176
|
-
const existing = splitBetaHeader(headers["anthropic-beta"] ?? headers["Anthropic-Beta"]);
|
|
177
|
-
const requiredBase = ctx.modelRegistry.isUsingOAuth(model) ? CLAUDE_CODE_OAUTH_BETAS : [];
|
|
178
|
-
const next = shouldEnable
|
|
179
|
-
? Array.from(new Set([...existing, ...requiredBase, FAST_BETA]))
|
|
180
|
-
: existing.filter((beta) => beta !== FAST_BETA);
|
|
181
|
-
|
|
182
|
-
delete headers["Anthropic-Beta"];
|
|
183
|
-
if (next.length > 0) headers["anthropic-beta"] = next.join(",");
|
|
184
|
-
else delete headers["anthropic-beta"];
|
|
185
|
-
model.headers = headers;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function updateStatus(ctx: ExtensionContext, state: SessionState): void {
|
|
189
|
-
syncModelBetaHeader(ctx, state);
|
|
190
|
-
if (!ctx.hasUI) return;
|
|
191
|
-
if (!state.config.showStatus) {
|
|
192
|
-
ctx.ui.setStatus(EXTENSION_ID, undefined);
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const eligibility = getEligibility(ctx);
|
|
197
|
-
ctx.ui.setStatus(
|
|
198
|
-
EXTENSION_ID,
|
|
199
|
-
isFastEnabled(state) && eligibility.eligible ? "fast" : undefined,
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
function getStatusMessage(ctx: ExtensionContext, state: SessionState): string {
|
|
204
|
-
const enabled = isFastEnabled(state);
|
|
205
|
-
const eligibility = getEligibility(ctx);
|
|
206
|
-
const active = enabled && eligibility.eligible;
|
|
207
|
-
const injected = state.lastInjectedAt
|
|
208
|
-
? ` Last injected for ${state.lastInjectedModel ?? "unknown model"} ${Math.max(0, Math.round((Date.now() - state.lastInjectedAt) / 1000))}s ago.`
|
|
209
|
-
: "";
|
|
210
|
-
|
|
211
|
-
if (active) {
|
|
212
|
-
return `Claude Fast mode is ${describeMode(state)} and active for ${eligibility.modelKey}; requests will use speed=${FAST_SPEED}.${injected}`;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if (enabled) {
|
|
216
|
-
return `Claude Fast mode is ${describeMode(state)}, but inactive for ${eligibility.modelKey}: ${eligibility.reason}.${injected}`;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return `Claude Fast mode is ${describeMode(state)}. Current model: ${eligibility.modelKey}.${injected}`;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
function injectFastSpeed(
|
|
223
|
-
payload: unknown,
|
|
224
|
-
ctx: ExtensionContext,
|
|
225
|
-
state: SessionState,
|
|
226
|
-
): PayloadRecord | undefined {
|
|
227
|
-
if (!isFastEnabled(state)) return undefined;
|
|
228
|
-
if (!getEligibility(ctx).eligible) return undefined;
|
|
229
|
-
if (!isPayloadRecord(payload)) return undefined;
|
|
230
|
-
if (payload.model !== ctx.model?.id) return undefined;
|
|
231
|
-
if ("speed" in payload) return undefined;
|
|
232
|
-
|
|
233
|
-
state.lastInjectedAt = Date.now();
|
|
234
|
-
state.lastInjectedModel = modelKey(ctx);
|
|
235
|
-
return {
|
|
236
|
-
...payload,
|
|
237
|
-
speed: FAST_SPEED,
|
|
238
|
-
};
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
export default function claudeFastExtension(pi: ExtensionAPI) {
|
|
242
|
-
const states = new WeakMap<object, SessionState>();
|
|
243
|
-
|
|
244
|
-
function getState(ctx: ExtensionContext): SessionState {
|
|
245
|
-
let state = states.get(ctx.sessionManager);
|
|
246
|
-
if (!state) {
|
|
247
|
-
state = {
|
|
248
|
-
config: loadConfig(ctx),
|
|
249
|
-
override: "auto",
|
|
250
|
-
};
|
|
251
|
-
states.set(ctx.sessionManager, state);
|
|
252
|
-
}
|
|
253
|
-
return state;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
pi.on("session_start", (_event, ctx) => {
|
|
257
|
-
const state: SessionState = {
|
|
258
|
-
config: loadConfig(ctx),
|
|
259
|
-
override: "auto",
|
|
260
|
-
};
|
|
261
|
-
states.set(ctx.sessionManager, state);
|
|
262
|
-
updateStatus(ctx, state);
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
pi.on("model_select", (_event, ctx) => {
|
|
266
|
-
updateStatus(ctx, getState(ctx));
|
|
267
|
-
});
|
|
268
|
-
|
|
269
|
-
pi.on("before_provider_request", (event, ctx) => {
|
|
270
|
-
const state = getState(ctx);
|
|
271
|
-
const nextPayload = injectFastSpeed(event.payload, ctx, state);
|
|
272
|
-
updateStatus(ctx, state);
|
|
273
|
-
return nextPayload;
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
pi.registerCommand("claude-fast", {
|
|
277
|
-
description: "Toggle Claude Fast mode for supported Anthropic Claude Opus models",
|
|
278
|
-
getArgumentCompletions: () => null,
|
|
279
|
-
handler: async (args, ctx) => {
|
|
280
|
-
const state = getState(ctx);
|
|
281
|
-
const action = args.trim();
|
|
282
|
-
|
|
283
|
-
if (!action) {
|
|
284
|
-
state.override = isFastEnabled(state) ? "off" : "on";
|
|
285
|
-
updateStatus(ctx, state);
|
|
286
|
-
ctx.ui.notify(getStatusMessage(ctx, state), "info");
|
|
287
|
-
return;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
ctx.ui.notify("Usage: /claude-fast", "warning");
|
|
291
|
-
},
|
|
292
|
-
});
|
|
5
|
+
const DEPRECATION_NOTICE =
|
|
6
|
+
"claude-fast is deprecated and no longer changes provider requests. Use the unified fast extension (/fast) instead.";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Deprecated leftover of the provider-specific Fast stack.
|
|
10
|
+
* The collection loads extensions/fast only. This package keeps the published
|
|
11
|
+
* npm name working. It does not read config, register commands, or inject Fast
|
|
12
|
+
* fields. Startup only clears leftover footer status and the Fast beta header,
|
|
13
|
+
* which /reload otherwise keeps from the previous extension runtime.
|
|
14
|
+
*/
|
|
15
|
+
function stripFastBeta(headers: Record<string, string> | undefined): void {
|
|
16
|
+
if (!headers) return;
|
|
17
|
+
for (const key of Object.keys(headers)) {
|
|
18
|
+
if (key.toLowerCase() !== "anthropic-beta") continue;
|
|
19
|
+
const next = headers[key]
|
|
20
|
+
.split(",")
|
|
21
|
+
.map((part) => part.trim())
|
|
22
|
+
.filter((part) => part && part !== FAST_BETA);
|
|
23
|
+
if (next.length === 0) delete headers[key];
|
|
24
|
+
else headers[key] = next.join(",");
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default function claudeFastExtension(pi: ExtensionAPI): void {
|
|
29
|
+
pi.on("session_start", (_event, ctx) => {
|
|
30
|
+
stripFastBeta(ctx.model?.headers);
|
|
31
|
+
if (!ctx.hasUI) return;
|
|
32
|
+
ctx.ui.setStatus(EXTENSION_ID, undefined);
|
|
33
|
+
ctx.ui.notify(DEPRECATION_NOTICE, "warning");
|
|
34
|
+
});
|
|
293
35
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@diegopetrucci/pi-claude-fast",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.1.16",
|
|
4
|
+
"description": "Deprecated standalone leftover. Does not change provider requests; use @diegopetrucci/pi-fast.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
7
7
|
"pi",
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"index.ts",
|
|
20
|
-
"claude-fast.example.json",
|
|
21
20
|
"README.md",
|
|
22
21
|
".pi-fleet-tested-version"
|
|
23
22
|
],
|
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
# code-reviewer
|
|
2
2
|
|
|
3
|
-
Adds a
|
|
3
|
+
Adds a `code_reviewer` subagent tool that adapts The Last Harness [`code-reviewer`](https://github.com/diegopetrucci/the-last-harness/blob/main/agents/subagents/code-reviewer.md) prompt into a standalone pi extension.
|
|
4
4
|
|
|
5
|
-
Use it when you want an isolated second-pass review of a proposed change against the local checkout. The
|
|
6
|
-
|
|
7
|
-
This package is adapted from the TLH code-reviewer workflow for use as a standalone pi extension.
|
|
5
|
+
Use it when you want an isolated second-pass review of a proposed change against the local checkout. The subagent uses read-only built-in tools plus any configured MCP tools, checks ticket fit and scope first, then looks for diff mismatches, correctness bugs, security/safety issues, unnecessary complexity, and missing validation.
|
|
8
6
|
|
|
9
7
|
## Install
|
|
10
8
|
|
|
@@ -46,7 +44,8 @@ When called, it launches an isolated in-memory child agent with:
|
|
|
46
44
|
- an auto-selected review model that prefers contrarian-style opposite-provider and opposite-family candidates before same-provider fallbacks;
|
|
47
45
|
- automatic model candidates constrained to the current Pi session's model scope when that scope is non-empty;
|
|
48
46
|
- requested thinking taken from the active session when available, otherwise defaulting to `high` for reasoning models and `off` for non-reasoning models, then clamped to the selected model's supported level;
|
|
49
|
-
- read-only tools
|
|
47
|
+
- read-only built-in tools: `read`, `grep`, `find`, `ls`, and guarded `bash`;
|
|
48
|
+
- configured MCP tools (run without confirmation in the subagent; may have side effects; use for evidence gathering only; requires host Pi >=1.0.4; older hosts degrade to no MCP, no error); the global `mcp.json` always applies; a project `.pi/mcp.json` is loaded only when the host session has already trusted the project;
|
|
50
49
|
- a local-checkout path guard for file inspection;
|
|
51
50
|
- a bash guard that allows only direct read-only `git`, `gh`, or `pwd` invocations.
|
|
52
51
|
|
|
@@ -59,12 +58,13 @@ The review prompt prioritizes:
|
|
|
59
58
|
5. simplicity and maintainability
|
|
60
59
|
6. tests and validation gaps
|
|
61
60
|
|
|
62
|
-
The
|
|
61
|
+
The model report is concise and includes a verdict, findings, validation notes, and a scope check. The tool appends a run-details suffix with the final selected model, effective thinking level, turn count, tool calls, duration, working directory, and tools used.
|
|
63
62
|
|
|
64
63
|
## Read-only guarantees
|
|
65
64
|
|
|
66
65
|
- The subagent is explicitly instructed not to implement changes.
|
|
67
66
|
- Runtime guards block write/edit tools, shell control operators, pipelines, redirection, path traversal outside the checkout, mutating `git`/`gh` commands, `npm`/publish commands, and other filesystem mutation.
|
|
67
|
+
- Runtime guards apply to built-in tools only; configured MCP tools pass the guard, run without confirmation, and are limited only by prompt guidance.
|
|
68
68
|
- Built-in file-inspection tools are preferred over shell commands for local files.
|
|
69
69
|
|
|
70
70
|
## Example
|