@oh-my-pi/pi-coding-agent 14.5.3 → 14.5.5
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/CHANGELOG.md +44 -0
- package/examples/extensions/plan-mode.ts +1 -1
- package/examples/sdk/README.md +1 -1
- package/package.json +7 -7
- package/src/config/prompt-templates.ts +103 -8
- package/src/config/settings-schema.ts +14 -13
- package/src/config/settings.ts +1 -1
- package/src/cursor.ts +4 -4
- package/src/edit/index.ts +111 -109
- package/src/edit/line-hash.ts +33 -3
- package/src/edit/modes/apply-patch.ts +6 -4
- package/src/edit/modes/atom.lark +27 -0
- package/src/edit/modes/atom.ts +1057 -841
- package/src/edit/modes/hashline.ts +9 -10
- package/src/edit/modes/patch.ts +23 -19
- package/src/edit/modes/replace.ts +19 -15
- package/src/edit/renderer.ts +65 -8
- package/src/edit/streaming.ts +47 -77
- package/src/extensibility/extensions/types.ts +11 -11
- package/src/extensibility/hooks/types.ts +6 -6
- package/src/lsp/edits.ts +8 -5
- package/src/lsp/index.ts +4 -4
- package/src/lsp/utils.ts +7 -7
- package/src/mcp/discoverable-tool-metadata.ts +1 -1
- package/src/mcp/manager.ts +3 -3
- package/src/mcp/tool-bridge.ts +4 -4
- package/src/memories/index.ts +1 -1
- package/src/modes/acp/acp-event-mapper.ts +1 -1
- package/src/modes/components/session-observer-overlay.ts +1 -1
- package/src/modes/components/settings-defs.ts +3 -3
- package/src/modes/components/tree-selector.ts +2 -2
- package/src/modes/utils/ui-helpers.ts +31 -7
- package/src/prompts/agents/explore.md +1 -1
- package/src/prompts/agents/librarian.md +2 -2
- package/src/prompts/agents/plan.md +2 -2
- package/src/prompts/agents/reviewer.md +1 -1
- package/src/prompts/agents/task.md +2 -2
- package/src/prompts/system/plan-mode-active.md +1 -1
- package/src/prompts/system/system-prompt.md +34 -31
- package/src/prompts/tools/apply-patch.md +0 -2
- package/src/prompts/tools/atom.md +81 -63
- package/src/prompts/tools/bash.md +7 -4
- package/src/prompts/tools/checkpoint.md +1 -1
- package/src/prompts/tools/find.md +6 -1
- package/src/prompts/tools/hashline.md +10 -11
- package/src/prompts/tools/patch.md +13 -13
- package/src/prompts/tools/read.md +4 -4
- package/src/prompts/tools/replace.md +3 -3
- package/src/prompts/tools/{grep.md → search.md} +4 -4
- package/src/sdk.ts +19 -9
- package/src/session/agent-session.ts +65 -0
- package/src/system-prompt.ts +15 -5
- package/src/task/executor.ts +5 -0
- package/src/task/index.ts +10 -1
- package/src/tools/ast-edit.ts +4 -6
- package/src/tools/ast-grep.ts +4 -6
- package/src/tools/bash.ts +1 -1
- package/src/tools/file-recorder.ts +6 -6
- package/src/tools/find.ts +11 -13
- package/src/tools/index.ts +7 -7
- package/src/tools/path-utils.ts +31 -4
- package/src/tools/read.ts +12 -6
- package/src/tools/renderers.ts +2 -2
- package/src/tools/{grep.ts → search.ts} +32 -40
- package/src/tools/write.ts +8 -4
- package/src/web/search/index.ts +1 -1
- package/src/edit/block.ts +0 -308
- package/src/edit/indent.ts +0 -150
package/src/lsp/edits.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as fs from "node:fs/promises";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { formatPathRelativeToCwd } from "../tools/path-utils";
|
|
3
4
|
import type { CreateFile, DeleteFile, RenameFile, TextDocumentEdit, TextEdit, WorkspaceEdit } from "./types";
|
|
4
5
|
import { uriToFile } from "./utils";
|
|
5
6
|
|
|
@@ -67,7 +68,7 @@ export async function applyWorkspaceEdit(edit: WorkspaceEdit, cwd: string): Prom
|
|
|
67
68
|
for (const [uri, textEdits] of Object.entries(edit.changes)) {
|
|
68
69
|
const filePath = uriToFile(uri);
|
|
69
70
|
await applyTextEdits(filePath, textEdits);
|
|
70
|
-
applied.push(`Applied ${textEdits.length} edit(s) to ${
|
|
71
|
+
applied.push(`Applied ${textEdits.length} edit(s) to ${formatPathRelativeToCwd(filePath, cwd)}`);
|
|
71
72
|
}
|
|
72
73
|
}
|
|
73
74
|
|
|
@@ -80,26 +81,28 @@ export async function applyWorkspaceEdit(edit: WorkspaceEdit, cwd: string): Prom
|
|
|
80
81
|
const filePath = uriToFile(docChange.textDocument.uri);
|
|
81
82
|
const textEdits = docChange.edits.filter((e): e is TextEdit => "range" in e && "newText" in e);
|
|
82
83
|
await applyTextEdits(filePath, textEdits);
|
|
83
|
-
applied.push(`Applied ${textEdits.length} edit(s) to ${
|
|
84
|
+
applied.push(`Applied ${textEdits.length} edit(s) to ${formatPathRelativeToCwd(filePath, cwd)}`);
|
|
84
85
|
} else if ("kind" in change && change.kind) {
|
|
85
86
|
// Resource operations
|
|
86
87
|
if (change.kind === "create") {
|
|
87
88
|
const createOp = change as CreateFile;
|
|
88
89
|
const filePath = uriToFile(createOp.uri);
|
|
89
90
|
await Bun.write(filePath, "");
|
|
90
|
-
applied.push(`Created ${
|
|
91
|
+
applied.push(`Created ${formatPathRelativeToCwd(filePath, cwd)}`);
|
|
91
92
|
} else if (change.kind === "rename") {
|
|
92
93
|
const renameOp = change as RenameFile;
|
|
93
94
|
const oldPath = uriToFile(renameOp.oldUri);
|
|
94
95
|
const newPath = uriToFile(renameOp.newUri);
|
|
95
96
|
await fs.mkdir(path.dirname(newPath), { recursive: true });
|
|
96
97
|
await fs.rename(oldPath, newPath);
|
|
97
|
-
applied.push(
|
|
98
|
+
applied.push(
|
|
99
|
+
`Renamed ${formatPathRelativeToCwd(oldPath, cwd)} → ${formatPathRelativeToCwd(newPath, cwd)}`,
|
|
100
|
+
);
|
|
98
101
|
} else if (change.kind === "delete") {
|
|
99
102
|
const deleteOp = change as DeleteFile;
|
|
100
103
|
const filePath = uriToFile(deleteOp.uri);
|
|
101
104
|
await fs.rm(filePath, { recursive: true });
|
|
102
|
-
applied.push(`Deleted ${
|
|
105
|
+
applied.push(`Deleted ${formatPathRelativeToCwd(filePath, cwd)}`);
|
|
103
106
|
}
|
|
104
107
|
}
|
|
105
108
|
}
|
package/src/lsp/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { BunFile } from "bun";
|
|
|
6
6
|
import { type Theme, theme } from "../modes/theme/theme";
|
|
7
7
|
import lspDescription from "../prompts/tools/lsp.md" with { type: "text" };
|
|
8
8
|
import type { ToolSession } from "../tools";
|
|
9
|
-
import { resolveToCwd } from "../tools/path-utils";
|
|
9
|
+
import { formatPathRelativeToCwd, resolveToCwd } from "../tools/path-utils";
|
|
10
10
|
import { ToolAbortError, throwIfAborted } from "../tools/tool-errors";
|
|
11
11
|
import { clampTimeout } from "../tools/tool-timeouts";
|
|
12
12
|
import {
|
|
@@ -562,7 +562,7 @@ async function getDiagnosticsForFile(
|
|
|
562
562
|
}
|
|
563
563
|
|
|
564
564
|
const uri = fileToUri(absolutePath);
|
|
565
|
-
const relPath =
|
|
565
|
+
const relPath = formatPathRelativeToCwd(absolutePath, cwd);
|
|
566
566
|
const allDiagnostics: Diagnostic[] = [];
|
|
567
567
|
const serverNames: string[] = [];
|
|
568
568
|
|
|
@@ -1229,7 +1229,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1229
1229
|
}
|
|
1230
1230
|
|
|
1231
1231
|
const uri = fileToUri(resolved);
|
|
1232
|
-
const relPath =
|
|
1232
|
+
const relPath = formatPathRelativeToCwd(resolved, this.session.cwd);
|
|
1233
1233
|
const allDiagnostics: Diagnostic[] = [];
|
|
1234
1234
|
|
|
1235
1235
|
// Query all applicable servers for this file
|
|
@@ -1707,7 +1707,7 @@ export class LspTool implements AgentTool<typeof lspSchema, LspToolDetails, Them
|
|
|
1707
1707
|
if (!result || result.length === 0) {
|
|
1708
1708
|
output = "No symbols found";
|
|
1709
1709
|
} else {
|
|
1710
|
-
const relPath =
|
|
1710
|
+
const relPath = formatPathRelativeToCwd(targetFile, this.session.cwd);
|
|
1711
1711
|
if ("selectionRange" in result[0]) {
|
|
1712
1712
|
const lines = (result as DocumentSymbol[]).flatMap(s => formatDocumentSymbol(s));
|
|
1713
1713
|
output = `Symbols in ${relPath}:\n${lines.join("\n")}`;
|
package/src/lsp/utils.ts
CHANGED
|
@@ -5,7 +5,7 @@ import path from "node:path";
|
|
|
5
5
|
import { isEnoent } from "@oh-my-pi/pi-utils";
|
|
6
6
|
import { type Theme, theme } from "../modes/theme/theme";
|
|
7
7
|
import { formatGroupedFiles } from "../tools/grouped-file-output";
|
|
8
|
-
import { resolveToCwd } from "../tools/path-utils";
|
|
8
|
+
import { formatPathRelativeToCwd, resolveToCwd } from "../tools/path-utils";
|
|
9
9
|
import type {
|
|
10
10
|
CodeAction,
|
|
11
11
|
Command,
|
|
@@ -229,7 +229,7 @@ export function formatDiagnosticsSummary(diagnostics: Diagnostic[]): string {
|
|
|
229
229
|
* Format a location as file:line:col relative to cwd.
|
|
230
230
|
*/
|
|
231
231
|
export function formatLocation(location: Location, cwd: string): string {
|
|
232
|
-
const file =
|
|
232
|
+
const file = formatPathRelativeToCwd(uriToFile(location.uri), cwd);
|
|
233
233
|
const line = location.range.start.line + 1;
|
|
234
234
|
const col = location.range.start.character + 1;
|
|
235
235
|
return `${file}:${line}:${col}`;
|
|
@@ -255,7 +255,7 @@ export function formatWorkspaceEdit(edit: WorkspaceEdit, cwd: string): string[]
|
|
|
255
255
|
// Handle changes map (legacy format)
|
|
256
256
|
if (edit.changes) {
|
|
257
257
|
for (const [uri, textEdits] of Object.entries(edit.changes)) {
|
|
258
|
-
const file =
|
|
258
|
+
const file = formatPathRelativeToCwd(uriToFile(uri), cwd);
|
|
259
259
|
results.push(`${file}: ${textEdits.length} edit${textEdits.length > 1 ? "s" : ""}`);
|
|
260
260
|
}
|
|
261
261
|
}
|
|
@@ -264,20 +264,20 @@ export function formatWorkspaceEdit(edit: WorkspaceEdit, cwd: string): string[]
|
|
|
264
264
|
if (edit.documentChanges) {
|
|
265
265
|
for (const change of edit.documentChanges) {
|
|
266
266
|
if ("edits" in change && change.textDocument) {
|
|
267
|
-
const file =
|
|
267
|
+
const file = formatPathRelativeToCwd(uriToFile(change.textDocument.uri), cwd);
|
|
268
268
|
results.push(`${file}: ${change.edits.length} edit${change.edits.length > 1 ? "s" : ""}`);
|
|
269
269
|
} else if ("kind" in change) {
|
|
270
270
|
switch (change.kind) {
|
|
271
271
|
case "create":
|
|
272
|
-
results.push(`CREATE: ${
|
|
272
|
+
results.push(`CREATE: ${formatPathRelativeToCwd(uriToFile(change.uri), cwd)}`);
|
|
273
273
|
break;
|
|
274
274
|
case "rename":
|
|
275
275
|
results.push(
|
|
276
|
-
`RENAME: ${
|
|
276
|
+
`RENAME: ${formatPathRelativeToCwd(uriToFile(change.oldUri), cwd)} ${theme.nav.cursor} ${formatPathRelativeToCwd(uriToFile(change.newUri), cwd)}`,
|
|
277
277
|
);
|
|
278
278
|
break;
|
|
279
279
|
case "delete":
|
|
280
|
-
results.push(`DELETE: ${
|
|
280
|
+
results.push(`DELETE: ${formatPathRelativeToCwd(uriToFile(change.uri), cwd)}`);
|
|
281
281
|
break;
|
|
282
282
|
}
|
|
283
283
|
}
|
package/src/mcp/manager.ts
CHANGED
|
@@ -472,7 +472,7 @@ export class MCPManager {
|
|
|
472
472
|
}
|
|
473
473
|
|
|
474
474
|
#replaceServerTools(name: string, tools: CustomTool<TSchema, MCPToolDetails>[]): void {
|
|
475
|
-
this.#tools = this.#tools.filter(t => !t.name.startsWith(`
|
|
475
|
+
this.#tools = this.#tools.filter(t => !t.name.startsWith(`mcp__${name}_`));
|
|
476
476
|
this.#tools.push(...tools);
|
|
477
477
|
}
|
|
478
478
|
|
|
@@ -644,8 +644,8 @@ export class MCPManager {
|
|
|
644
644
|
}
|
|
645
645
|
|
|
646
646
|
// Remove tools from this server and notify consumers
|
|
647
|
-
const hadTools = this.#tools.some(t => t.name.startsWith(`
|
|
648
|
-
this.#tools = this.#tools.filter(t => !t.name.startsWith(`
|
|
647
|
+
const hadTools = this.#tools.some(t => t.name.startsWith(`mcp__${name}_`));
|
|
648
|
+
this.#tools = this.#tools.filter(t => !t.name.startsWith(`mcp__${name}_`));
|
|
649
649
|
if (hadTools) this.#onToolsChanged?.(this.#tools);
|
|
650
650
|
|
|
651
651
|
// Notify prompt consumers so stale commands are cleared
|
package/src/mcp/tool-bridge.ts
CHANGED
|
@@ -159,7 +159,7 @@ async function reconnectWithAbort(reconnect: MCPReconnect, signal?: AbortSignal)
|
|
|
159
159
|
* Prefixes with server name to avoid conflicts. If the tool name already
|
|
160
160
|
* starts with the server name (e.g., server "puppeteer" with tool
|
|
161
161
|
* "puppeteer_screenshot"), strips the redundant prefix to produce
|
|
162
|
-
* "
|
|
162
|
+
* "mcp__puppeteer_screenshot" instead of "mcp__puppeteer_puppeteer_screenshot".
|
|
163
163
|
*/
|
|
164
164
|
function sanitizeMCPToolNamePart(value: string, fallback: string): string {
|
|
165
165
|
const sanitized = value
|
|
@@ -183,7 +183,7 @@ export function createMCPToolName(serverName: string, toolName: string): string
|
|
|
183
183
|
normalizedToolName = sanitizedToolName.slice(prefixWithUnderscore.length);
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
return `
|
|
186
|
+
return `mcp__${sanitizedServerName}_${normalizedToolName}`;
|
|
187
187
|
}
|
|
188
188
|
|
|
189
189
|
/**
|
|
@@ -193,9 +193,9 @@ export function createMCPToolName(serverName: string, toolName: string): string
|
|
|
193
193
|
* The original MCP tool name may have had the server name as a prefix.
|
|
194
194
|
*/
|
|
195
195
|
export function parseMCPToolName(name: string): { serverName: string; toolName: string } | null {
|
|
196
|
-
if (!name.startsWith("
|
|
196
|
+
if (!name.startsWith("mcp__")) return null;
|
|
197
197
|
|
|
198
|
-
const rest = name.slice(
|
|
198
|
+
const rest = name.slice(5);
|
|
199
199
|
const underscoreIdx = rest.indexOf("_");
|
|
200
200
|
if (underscoreIdx === -1) return null;
|
|
201
201
|
|
package/src/memories/index.ts
CHANGED
|
@@ -539,7 +539,7 @@ function shouldPersistResponseItemForMemories(message: AgentMessage): boolean {
|
|
|
539
539
|
}
|
|
540
540
|
if (role !== "toolResult") return false;
|
|
541
541
|
const toolName = (message as { toolName?: string }).toolName;
|
|
542
|
-
if (toolName === "bash" || toolName === "python" || toolName === "read" || toolName === "
|
|
542
|
+
if (toolName === "bash" || toolName === "python" || toolName === "read" || toolName === "search") {
|
|
543
543
|
const text = extractMessageText(message);
|
|
544
544
|
return text.length > 0 && text.length <= 32_000;
|
|
545
545
|
}
|
|
@@ -518,7 +518,7 @@ export class SessionObserverOverlayComponent extends Container {
|
|
|
518
518
|
case "write":
|
|
519
519
|
case "edit":
|
|
520
520
|
return args.path ? `path: ${args.path}` : "";
|
|
521
|
-
case "
|
|
521
|
+
case "search":
|
|
522
522
|
return [args.pattern ? `pattern: ${args.pattern}` : "", args.path ? `path: ${args.path}` : ""]
|
|
523
523
|
.filter(Boolean)
|
|
524
524
|
.join(", ");
|
|
@@ -214,15 +214,15 @@ const OPTION_PROVIDERS: Partial<Record<SettingPath, OptionProvider>> = {
|
|
|
214
214
|
{ value: "3", label: "3 reminders" },
|
|
215
215
|
{ value: "5", label: "5 reminders" },
|
|
216
216
|
],
|
|
217
|
-
//
|
|
218
|
-
"
|
|
217
|
+
// Search context
|
|
218
|
+
"search.contextBefore": [
|
|
219
219
|
{ value: "0", label: "0 lines" },
|
|
220
220
|
{ value: "1", label: "1 line" },
|
|
221
221
|
{ value: "2", label: "2 lines" },
|
|
222
222
|
{ value: "3", label: "3 lines" },
|
|
223
223
|
{ value: "5", label: "5 lines" },
|
|
224
224
|
],
|
|
225
|
-
"
|
|
225
|
+
"search.contextAfter": [
|
|
226
226
|
{ value: "0", label: "0 lines" },
|
|
227
227
|
{ value: "1", label: "1 line" },
|
|
228
228
|
{ value: "2", label: "2 lines" },
|
|
@@ -665,10 +665,10 @@ class TreeList implements Component {
|
|
|
665
665
|
.slice(0, 50);
|
|
666
666
|
return `[bash: ${cmd}${rawCmd.length > 50 ? "..." : ""}]`;
|
|
667
667
|
}
|
|
668
|
-
case "
|
|
668
|
+
case "search": {
|
|
669
669
|
const pattern = String(args.pattern || "");
|
|
670
670
|
const path = shortenPath(String(args.path || "."));
|
|
671
|
-
return `[
|
|
671
|
+
return `[search: /${pattern}/ in ${path}]`;
|
|
672
672
|
}
|
|
673
673
|
case "find": {
|
|
674
674
|
const pattern = String(args.pattern || "");
|
|
@@ -127,14 +127,38 @@ export class UiHelpers {
|
|
|
127
127
|
this.ctx.chatContainer.addChild(component);
|
|
128
128
|
break;
|
|
129
129
|
}
|
|
130
|
-
if (
|
|
130
|
+
if (
|
|
131
|
+
message.customType === "irc:incoming" ||
|
|
132
|
+
message.customType === "irc:autoreply" ||
|
|
133
|
+
message.customType === "irc:relay"
|
|
134
|
+
) {
|
|
131
135
|
const details = (
|
|
132
|
-
message as CustomMessage<{
|
|
136
|
+
message as CustomMessage<{
|
|
137
|
+
from?: string;
|
|
138
|
+
to?: string;
|
|
139
|
+
message?: string;
|
|
140
|
+
reply?: string;
|
|
141
|
+
body?: string;
|
|
142
|
+
kind?: "message" | "reply";
|
|
143
|
+
}>
|
|
133
144
|
).details;
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
145
|
+
let arrow: string;
|
|
146
|
+
let body: string;
|
|
147
|
+
if (message.customType === "irc:incoming") {
|
|
148
|
+
const peer = details?.from ?? "?";
|
|
149
|
+
body = details?.message ?? "";
|
|
150
|
+
arrow = `\u21e6 ${peer}`;
|
|
151
|
+
} else if (message.customType === "irc:autoreply") {
|
|
152
|
+
const peer = details?.to ?? "?";
|
|
153
|
+
body = details?.reply ?? "";
|
|
154
|
+
arrow = `\u21e8 ${peer} (auto)`;
|
|
155
|
+
} else {
|
|
156
|
+
const from = details?.from ?? "?";
|
|
157
|
+
const to = details?.to ?? "?";
|
|
158
|
+
body = details?.body ?? "";
|
|
159
|
+
const suffix = details?.kind === "reply" ? " (auto)" : "";
|
|
160
|
+
arrow = `${from} \u21e8 ${to}${suffix}`;
|
|
161
|
+
}
|
|
138
162
|
const header = `${theme.fg("accent", `[IRC] ${arrow}`)}`;
|
|
139
163
|
this.ctx.chatContainer.addChild(new Text(header, 1, 0));
|
|
140
164
|
if (body) {
|
|
@@ -226,7 +250,7 @@ export class UiHelpers {
|
|
|
226
250
|
sessionContext: SessionContext,
|
|
227
251
|
options: { updateFooter?: boolean; populateHistory?: boolean } = {},
|
|
228
252
|
): void {
|
|
229
|
-
this
|
|
253
|
+
// Preserved: message_start handler owns this lifecycle (see #783)
|
|
230
254
|
this.ctx.pendingTools.clear();
|
|
231
255
|
|
|
232
256
|
if (options.updateFooter) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: librarian
|
|
3
3
|
description: Researches external libraries and APIs by reading source code. Returns definitive, source-verified answers.
|
|
4
|
-
tools: read,
|
|
4
|
+
tools: read, search, find, bash, lsp, web_search, ast_grep
|
|
5
5
|
model: pi/smol
|
|
6
6
|
thinking-level: minimal
|
|
7
7
|
output:
|
|
@@ -87,7 +87,7 @@ Before acting, determine what kind of question this is:
|
|
|
87
87
|
|
|
88
88
|
## 3. Investigate
|
|
89
89
|
- Read `package.json`, `Cargo.toml`, or equivalent for version info and entry points.
|
|
90
|
-
- Use `
|
|
90
|
+
- Use `search`, `find`, and `ast_grep` to locate relevant source, type definitions, and docs. Parallelize searches.
|
|
91
91
|
- Read the actual implementation — not just README examples. READMEs are aspirational; source code is truth.
|
|
92
92
|
- For behavior questions: trace through the implementation. Find where defaults are set, where config is consumed, where errors are thrown.
|
|
93
93
|
- Check tests for usage examples and edge case behavior — tests are the most honest documentation.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: plan
|
|
3
3
|
description: Software architect for complex multi-file architectural decisions. NOT for simple tasks, single-file changes, or tasks completable in <5 tool calls.
|
|
4
|
-
tools: read,
|
|
4
|
+
tools: read, search, find, bash, lsp, web_search, ast_grep
|
|
5
5
|
spawns: explore
|
|
6
6
|
model: pi/plan, pi/slow
|
|
7
7
|
thinking-level: high
|
|
@@ -14,7 +14,7 @@ You are an expert software architect analyzing the codebase and the user's reque
|
|
|
14
14
|
2. Identify ambiguities; list assumptions
|
|
15
15
|
|
|
16
16
|
## Phase 2: Explore
|
|
17
|
-
1. Find existing patterns via
|
|
17
|
+
1. Find existing patterns via `search`/`find`
|
|
18
18
|
2. Read key files; understand architecture
|
|
19
19
|
3. Trace data flow through relevant paths
|
|
20
20
|
4. Identify types, interfaces, contracts
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: reviewer
|
|
3
3
|
description: "Code review specialist for quality/security analysis"
|
|
4
|
-
tools: read,
|
|
4
|
+
tools: read, search, find, bash, lsp, web_search, ast_grep, report_finding
|
|
5
5
|
spawns: explore
|
|
6
6
|
model: pi/slow
|
|
7
7
|
thinking-level: high
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
You are a worker agent for delegated tasks.
|
|
2
2
|
|
|
3
|
-
You have FULL access to all tools (edit, write, bash,
|
|
3
|
+
You have FULL access to all tools (edit, write, bash, search, read, etc.) and you **MUST** use them as needed to complete your task.
|
|
4
4
|
|
|
5
5
|
You **MUST** maintain hyperfocus on the task at hand, do not deviate from what was assigned to you.
|
|
6
6
|
|
|
@@ -8,7 +8,7 @@ You **MUST** maintain hyperfocus on the task at hand, do not deviate from what w
|
|
|
8
8
|
- You **MUST** finish only the assigned work and return the minimum useful result. Do not repeat what you have written to the filesystem.
|
|
9
9
|
- You **MAY** make file edits, run commands, and create files when your task requires it—and **SHOULD** do so.
|
|
10
10
|
- You **MUST** be concise. You **MUST NOT** include filler, repetition, or tool transcripts. User cannot even see you. Your result is just the notes you are leaving for yourself.
|
|
11
|
-
- You **SHOULD** prefer narrow
|
|
11
|
+
- You **SHOULD** prefer narrow lookups (`search`/`find`) then read only needed ranges. Do not bother yourself with anything beyond your current scope.
|
|
12
12
|
- You **SHOULD NOT** do full-file reads unless necessary.
|
|
13
13
|
- You **SHOULD** prefer edits to existing files over creating new ones.
|
|
14
14
|
- You **MUST NOT** create documentation files (*.md) unless explicitly requested.
|
|
@@ -42,7 +42,7 @@ Plan execution runs in fresh context (session cleared). You **MUST** make the pl
|
|
|
42
42
|
|
|
43
43
|
<procedure>
|
|
44
44
|
### 1. Explore
|
|
45
|
-
You **MUST** use `find`, `
|
|
45
|
+
You **MUST** use `find`, `search`, `read` to understand the codebase.
|
|
46
46
|
### 2. Interview
|
|
47
47
|
You **MUST** use `{{askToolName}}` to clarify:
|
|
48
48
|
- Ambiguous requirements
|
|
@@ -78,10 +78,13 @@ If any check fails, continue or mark [blocked]. Do **NOT** reframe partial work
|
|
|
78
78
|
- Prefer concise, information-dense writing.
|
|
79
79
|
- Avoid repeating the user's request or narrating routine tool calls.
|
|
80
80
|
- Do not give time estimates or predictions.
|
|
81
|
+
- Do not emit closing summaries, recap paragraphs, or "what I did" wrap-ups. Final messages state the result and any blockers; the trace already shows the work.
|
|
81
82
|
</communication>
|
|
82
83
|
|
|
83
84
|
<output-contract>
|
|
84
85
|
- Brief preambles are allowed when they improve orientation, but they **MUST** stay short and **MUST NOT** be treated as completion.
|
|
86
|
+
- A phase boundary, todo flip, or completed sub-step is **NOT** a yield point. Continue directly to the next step in the same turn — do **NOT** stop to summarize, ask for acknowledgement, or wait for the user to say "go".
|
|
87
|
+
- Yield only when (a) the whole deliverable is complete, (b) you are [blocked], or (c) the user asked a question that requires their input.
|
|
85
88
|
- Claims about code, tools, tests, docs, or external sources **MUST** be grounded in what was actually observed.
|
|
86
89
|
- If a statement is an inference, label it as such.
|
|
87
90
|
- Be brief in prose, not in evidence, verification, or blocking details.
|
|
@@ -175,44 +178,45 @@ Most tools have a `{{intentField}}` parameter. Fill it with a concise intent in
|
|
|
175
178
|
{{#if mcpDiscoveryMode}}
|
|
176
179
|
### MCP tool discovery
|
|
177
180
|
{{#if hasMCPDiscoveryServers}}Discoverable MCP servers in this session: {{#list mcpDiscoveryServerSummaries join=", "}}{{this}}{{/list}}.{{/if}}
|
|
178
|
-
If the task may involve external systems, SaaS APIs, chat, tickets, databases, deployments, or other non-local integrations, you **SHOULD** call `search_tool_bm25` before concluding no such tool exists.
|
|
181
|
+
If the task may involve external systems, SaaS APIs, chat, tickets, databases, deployments, or other non-local integrations, you **SHOULD** call `{{toolRefs.search_tool_bm25}}` before concluding no such tool exists.
|
|
179
182
|
{{/if}}
|
|
180
183
|
|
|
181
184
|
{{#ifAny (includes tools "python") (includes tools "bash")}}
|
|
182
185
|
### Tool priority
|
|
183
|
-
1. Use specialized tools first{{#ifAny (includes tools "read") (includes tools "
|
|
186
|
+
1. Use specialized tools first{{#ifAny (includes tools "read") (includes tools "search") (includes tools "find") (includes tools "edit") (includes tools "lsp")}}: {{#has tools "read"}}`{{toolRefs.read}}`, {{/has}}{{#has tools "search"}}`{{toolRefs.search}}`, {{/has}}{{#has tools "find"}}`{{toolRefs.find}}`, {{/has}}{{#has tools "edit"}}`{{toolRefs.edit}}`, {{/has}}{{#has tools "lsp"}}`{{toolRefs.lsp}}`{{/has}}{{/ifAny}}
|
|
184
187
|
2. Python: logic, loops, processing, display
|
|
185
188
|
3. Bash: simple one-liners only
|
|
186
189
|
You **MUST NOT** use Python or Bash when a specialized tool exists.
|
|
187
190
|
{{/ifAny}}
|
|
188
191
|
|
|
189
|
-
{{#ifAny (includes tools "read") (includes tools "write") (includes tools "
|
|
190
|
-
{{#has tools "read"}}- Use `read`, not `cat`.{{/has}}
|
|
191
|
-
{{#has tools "write"}}- Use `write`, not shell redirection.{{/has}}
|
|
192
|
-
{{#has tools "
|
|
193
|
-
{{#has tools "find"}}- Use `find`, not shell file globbing.{{/has}}
|
|
194
|
-
{{#has tools "edit"}}- Use `edit` for surgical text changes, not `sed`.{{/has}}
|
|
192
|
+
{{#ifAny (includes tools "read") (includes tools "write") (includes tools "search") (includes tools "find") (includes tools "edit")}}
|
|
193
|
+
{{#has tools "read"}}- Use `{{toolRefs.read}}`, not `cat` or `ls`. `{{toolRefs.read}}` on a directory path lists its entries.{{/has}}
|
|
194
|
+
{{#has tools "write"}}- Use `{{toolRefs.write}}`, not shell redirection.{{/has}}
|
|
195
|
+
{{#has tools "search"}}- Use `{{toolRefs.search}}`, not shell regex search.{{/has}}
|
|
196
|
+
{{#has tools "find"}}- Use `{{toolRefs.find}}`, not shell file globbing.{{/has}}
|
|
197
|
+
{{#has tools "edit"}}- Use `{{toolRefs.edit}}` for surgical text changes, not `sed`.{{/has}}
|
|
195
198
|
{{/ifAny}}
|
|
196
199
|
|
|
197
200
|
### Paths
|
|
198
|
-
- For tools that take a `path`
|
|
201
|
+
- For tools that take a `path` or path-like field, you **MUST** use cwd-relative paths for files inside the current working directory.
|
|
202
|
+
- You **MUST** use absolute paths only when targeting files outside the current working directory or when expanding `~`.
|
|
199
203
|
|
|
200
204
|
{{#has tools "lsp"}}
|
|
201
205
|
### LSP guidance
|
|
202
206
|
Use semantic tools for semantic questions:
|
|
203
|
-
- Definition → `lsp definition`
|
|
204
|
-
- Type → `lsp type_definition`
|
|
205
|
-
- Implementations → `lsp implementation`
|
|
206
|
-
- References → `lsp references`
|
|
207
|
-
- What is this? → `lsp hover`
|
|
208
|
-
- Refactors/imports/fixes → `lsp code_actions` (list first, then apply with `apply: true` + `query`)
|
|
207
|
+
- Definition → `{{toolRefs.lsp}} definition`
|
|
208
|
+
- Type → `{{toolRefs.lsp}} type_definition`
|
|
209
|
+
- Implementations → `{{toolRefs.lsp}} implementation`
|
|
210
|
+
- References → `{{toolRefs.lsp}} references`
|
|
211
|
+
- What is this? → `{{toolRefs.lsp}} hover`
|
|
212
|
+
- Refactors/imports/fixes → `{{toolRefs.lsp}} code_actions` (list first, then apply with `apply: true` + `query`)
|
|
209
213
|
{{/has}}
|
|
210
214
|
|
|
211
215
|
{{#ifAny (includes tools "ast_grep") (includes tools "ast_edit")}}
|
|
212
216
|
### AST guidance
|
|
213
217
|
Use syntax-aware tools before text hacks:
|
|
214
|
-
{{#has tools "ast_grep"}}- `ast_grep` for structural discovery{{/has}}
|
|
215
|
-
{{#has tools "ast_edit"}}- `ast_edit` for codemods{{/has}}
|
|
218
|
+
{{#has tools "ast_grep"}}- `{{toolRefs.ast_grep}}` for structural discovery{{/has}}
|
|
219
|
+
{{#has tools "ast_edit"}}- `{{toolRefs.ast_edit}}` for codemods{{/has}}
|
|
216
220
|
- Use `grep` only for plain text lookup when structure is irrelevant
|
|
217
221
|
{{/ifAny}}
|
|
218
222
|
|
|
@@ -233,10 +237,10 @@ Match commands to the host shell: linux/bash and macos/zsh use Unix commands; wi
|
|
|
233
237
|
{{/has}}
|
|
234
238
|
|
|
235
239
|
### Search before you read
|
|
236
|
-
{{#has tools "grep"}}- Use `grep` to locate targets.{{/has}}
|
|
237
|
-
{{#has tools "find"}}- Use `find` to map structure.{{/has}}
|
|
238
|
-
{{#has tools "read"}}- Use `read` with offset or limit rather than whole-file reads when practical.{{/has}}
|
|
239
|
-
{{#has tools "task"}}- Use `task` for investigate+edit when available.{{/has}}
|
|
240
|
+
{{#has tools "grep"}}- Use `{{toolRefs.grep}}` to locate targets.{{/has}}
|
|
241
|
+
{{#has tools "find"}}- Use `{{toolRefs.find}}` to map structure.{{/has}}
|
|
242
|
+
{{#has tools "read"}}- Use `{{toolRefs.read}}` with offset or limit rather than whole-file reads when practical.{{/has}}
|
|
243
|
+
{{#has tools "task"}}- Use `{{toolRefs.task}}` for investigate+edit when available.{{/has}}
|
|
240
244
|
- Do not read a file hoping to find the right thing.
|
|
241
245
|
|
|
242
246
|
<tool-persistence>
|
|
@@ -250,8 +254,8 @@ Match commands to the host shell: linux/bash and macos/zsh use Unix commands; wi
|
|
|
250
254
|
|
|
251
255
|
{{#if (includes tools "inspect_image")}}
|
|
252
256
|
### Image inspection
|
|
253
|
-
- For image understanding tasks you **MUST** use `inspect_image` over `read` to avoid overloading session context.
|
|
254
|
-
- Write a specific `question` for `inspect_image`: what to inspect, constraints, and desired output format.
|
|
257
|
+
- For image understanding tasks you **MUST** use `{{toolRefs.inspect_image}}` over `{{toolRefs.read}}` to avoid overloading session context.
|
|
258
|
+
- Write a specific `question` for `{{toolRefs.inspect_image}}`: what to inspect, constraints, and desired output format.
|
|
255
259
|
{{/if}}
|
|
256
260
|
|
|
257
261
|
{{SECTION_SEPARATOR "Rules"}}
|
|
@@ -285,7 +289,7 @@ These are inviolable.
|
|
|
285
289
|
## 1. Scope
|
|
286
290
|
{{#if skills.length}}- You **MUST** read skills that match the task domain before starting.{{/if}}
|
|
287
291
|
{{#if rules.length}}- You **MUST** read rules that match the file paths you are touching before starting.{{/if}}
|
|
288
|
-
{{#has tools "task"}}- Determine whether the task can be parallelized with `task`.{{/has}}
|
|
292
|
+
{{#has tools "task"}}- Determine whether the task can be parallelized with `{{toolRefs.task}}`.{{/has}}
|
|
289
293
|
- If the task is multi-file or imprecisely scoped, write a step-by-step plan before editing.
|
|
290
294
|
- For new or unfamiliar work, think about architecture, review the codebase, consult authoritative docs when needed, then implement the best fit or surface tradeoffs.
|
|
291
295
|
- If context is missing, use tools first; ask a minimal question only when necessary.
|
|
@@ -293,17 +297,18 @@ These are inviolable.
|
|
|
293
297
|
## 2. Before you edit
|
|
294
298
|
- Read the relevant section of any file before editing.
|
|
295
299
|
- You **MUST** search for existing examples before implementing a new pattern, utility, or abstraction. If the codebase already solves it, **MUST** reuse it; inventing a parallel convention is **PROHIBITED**.
|
|
296
|
-
{{#has tools "lsp"}}- Before modifying a function, type, or exported symbol, run `lsp references` to find its consumers.{{/has}}
|
|
300
|
+
{{#has tools "lsp"}}- Before modifying a function, type, or exported symbol, run `{{toolRefs.lsp}} references` to find its consumers.{{/has}}
|
|
297
301
|
- If a file changed since you last read it, re-read before editing.
|
|
298
302
|
|
|
299
303
|
## 3. Parallelization
|
|
300
304
|
- Prefer parallel work whenever the pieces are independent.
|
|
301
305
|
{{#has tools "task"}}- Use tasks or subagents when independent investigations or edits can be split safely.{{/has}}
|
|
302
306
|
- If you cannot explain why one piece depends on another, they are probably independent.
|
|
303
|
-
|
|
307
|
+
{{#has tools "task"}}- When a plan feels too large for a single turn, parallelize aggressively — do **NOT** abandon phases, silently drop them, or narrate scope cuts. Scope pressure is a signal to delegate, not to shrink the work.{{/has}}
|
|
304
308
|
## 4. Task tracking
|
|
305
309
|
- Update todos as you progress.
|
|
306
310
|
- Skip task tracking only for trivial requests.
|
|
311
|
+
- Marking a todo done is a transition, not a stop: in the same turn, start the next pending todo. Acceptable inter-phase text is one short line ("phase 1 done, starting phase 2") — not a recap, not a question.
|
|
307
312
|
|
|
308
313
|
## 5. While working
|
|
309
314
|
- Keep one job per level of abstraction.
|
|
@@ -318,11 +323,9 @@ These are inviolable.
|
|
|
318
323
|
- If blocked, exhaust tools and context first.
|
|
319
324
|
|
|
320
325
|
## 6. Verification
|
|
321
|
-
- Test rigorously. Prefer unit or end-to-end tests.
|
|
322
|
-
- You **MUST NOT** rely on mocks for behavior the production system owns — they invent behaviors that never happen in production and hide real bugs. Use mocks or fakes only for genuinely external, unstable, slow, or costly boundaries.
|
|
326
|
+
- Test rigorously. Prefer unit or end-to-end tests, you **MUST NOT** rely on mocks.
|
|
323
327
|
- Run only tests you added or modified unless asked otherwise.
|
|
324
|
-
- You **MUST NOT** yield non-trivial work without proof: tests,
|
|
325
|
-
- High-impact actions **MUST** be verified or explicitly held for permission before yielding.
|
|
328
|
+
- You **MUST NOT** yield non-trivial work without proof: tests, e2e run, browsing and QA testing, etc.
|
|
326
329
|
|
|
327
330
|
{{#if secretsEnabled}}
|
|
328
331
|
<redacted-content>
|
|
@@ -332,7 +335,7 @@ Some values in tool output are intentionally redacted as `#XXXX#` tokens. Treat
|
|
|
332
335
|
|
|
333
336
|
{{SECTION_SEPARATOR "Now"}}
|
|
334
337
|
|
|
335
|
-
The current working directory is '{{cwd}}'.
|
|
338
|
+
The current working directory is '{{cwd}}'. Paths inside this directory **MUST** be passed to tools as relative paths.
|
|
336
339
|
Today is '{{date}}'. Begin now.
|
|
337
340
|
|
|
338
341
|
<critical>
|