@oh-my-pi/pi-coding-agent 3.20.1 → 3.24.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/CHANGELOG.md +107 -8
- package/docs/custom-tools.md +3 -3
- package/docs/extensions.md +226 -220
- package/docs/hooks.md +2 -2
- package/docs/sdk.md +50 -53
- package/examples/custom-tools/README.md +2 -17
- package/examples/extensions/README.md +76 -74
- package/examples/extensions/todo.ts +2 -5
- package/examples/hooks/custom-compaction.ts +2 -4
- package/examples/hooks/handoff.ts +1 -1
- package/examples/hooks/qna.ts +1 -1
- package/examples/sdk/02-custom-model.ts +1 -1
- package/examples/sdk/README.md +7 -11
- package/package.json +6 -6
- package/src/cli/args.ts +9 -6
- package/src/cli/file-processor.ts +1 -1
- package/src/cli/list-models.ts +1 -1
- package/src/core/agent-session.ts +16 -5
- package/src/core/auth-storage.ts +1 -1
- package/src/core/compaction/branch-summarization.ts +2 -2
- package/src/core/compaction/compaction.ts +2 -2
- package/src/core/compaction/utils.ts +1 -1
- package/src/core/custom-tools/types.ts +1 -1
- package/src/core/custom-tools/wrapper.ts +0 -1
- package/src/core/extensions/index.ts +1 -6
- package/src/core/extensions/runner.ts +1 -1
- package/src/core/extensions/types.ts +1 -1
- package/src/core/extensions/wrapper.ts +1 -8
- package/src/core/file-mentions.ts +5 -8
- package/src/core/hooks/runner.ts +2 -2
- package/src/core/hooks/types.ts +1 -1
- package/src/core/messages.ts +1 -1
- package/src/core/model-registry.ts +1 -1
- package/src/core/model-resolver.ts +1 -1
- package/src/core/sdk.ts +64 -105
- package/src/core/session-manager.ts +18 -22
- package/src/core/settings-manager.ts +66 -1
- package/src/core/slash-commands.ts +12 -5
- package/src/core/system-prompt.ts +49 -36
- package/src/core/title-generator.ts +2 -2
- package/src/core/tools/ask.ts +98 -4
- package/src/core/tools/bash-interceptor.ts +11 -4
- package/src/core/tools/bash.ts +121 -5
- package/src/core/tools/context.ts +7 -0
- package/src/core/tools/edit-diff.ts +73 -24
- package/src/core/tools/edit.ts +221 -34
- package/src/core/tools/exa/render.ts +4 -16
- package/src/core/tools/find.ts +149 -5
- package/src/core/tools/gemini-image.ts +279 -56
- package/src/core/tools/git.ts +17 -3
- package/src/core/tools/grep.ts +185 -5
- package/src/core/tools/index.test.ts +180 -0
- package/src/core/tools/index.ts +96 -242
- package/src/core/tools/ls.ts +133 -5
- package/src/core/tools/lsp/index.ts +32 -29
- package/src/core/tools/lsp/render.ts +21 -22
- package/src/core/tools/notebook.ts +112 -4
- package/src/core/tools/output.ts +175 -15
- package/src/core/tools/read.ts +127 -25
- package/src/core/tools/render-utils.ts +241 -0
- package/src/core/tools/renderers.ts +40 -828
- package/src/core/tools/review.ts +26 -25
- package/src/core/tools/rulebook.ts +11 -3
- package/src/core/tools/task/agents.ts +28 -7
- package/src/core/tools/task/discovery.ts +0 -6
- package/src/core/tools/task/executor.ts +264 -254
- package/src/core/tools/task/index.ts +48 -208
- package/src/core/tools/task/render.ts +26 -11
- package/src/core/tools/task/types.ts +7 -12
- package/src/core/tools/task/worker-protocol.ts +17 -0
- package/src/core/tools/task/worker.ts +238 -0
- package/src/core/tools/truncate.ts +27 -1
- package/src/core/tools/web-fetch.ts +25 -49
- package/src/core/tools/web-search/index.ts +132 -46
- package/src/core/tools/web-search/providers/anthropic.ts +7 -2
- package/src/core/tools/web-search/providers/exa.ts +2 -1
- package/src/core/tools/web-search/providers/perplexity.ts +6 -1
- package/src/core/tools/web-search/render.ts +6 -4
- package/src/core/tools/web-search/types.ts +13 -0
- package/src/core/tools/write.ts +96 -14
- package/src/core/voice.ts +1 -1
- package/src/discovery/helpers.test.ts +1 -1
- package/src/index.ts +5 -16
- package/src/main.ts +5 -5
- package/src/modes/interactive/components/assistant-message.ts +1 -1
- package/src/modes/interactive/components/custom-message.ts +1 -1
- package/src/modes/interactive/components/extensions/inspector-panel.ts +25 -22
- package/src/modes/interactive/components/extensions/state-manager.ts +12 -0
- package/src/modes/interactive/components/footer.ts +1 -1
- package/src/modes/interactive/components/hook-message.ts +1 -1
- package/src/modes/interactive/components/model-selector.ts +1 -1
- package/src/modes/interactive/components/oauth-selector.ts +1 -1
- package/src/modes/interactive/components/settings-defs.ts +49 -0
- package/src/modes/interactive/components/status-line.ts +1 -1
- package/src/modes/interactive/components/tool-execution.ts +93 -538
- package/src/modes/interactive/interactive-mode.ts +19 -7
- package/src/modes/interactive/theme/theme.ts +4 -4
- package/src/modes/print-mode.ts +1 -1
- package/src/modes/rpc/rpc-client.ts +1 -1
- package/src/modes/rpc/rpc-types.ts +1 -1
- package/src/prompts/system-prompt.md +4 -0
- package/src/prompts/task.md +0 -7
- package/src/prompts/tools/gemini-image.md +5 -1
- package/src/prompts/tools/output.md +6 -2
- package/src/prompts/tools/task.md +68 -0
- package/src/prompts/tools/web-fetch.md +1 -0
- package/src/prompts/tools/web-search.md +2 -0
- package/src/utils/image-convert.ts +8 -2
- package/src/utils/image-magick.ts +247 -0
- package/src/utils/image-resize.ts +53 -13
- package/examples/custom-tools/question/index.ts +0 -84
- package/examples/custom-tools/subagent/README.md +0 -172
- package/examples/custom-tools/subagent/agents/planner.md +0 -37
- package/examples/custom-tools/subagent/agents/scout.md +0 -50
- package/examples/custom-tools/subagent/agents/worker.md +0 -24
- package/examples/custom-tools/subagent/agents.ts +0 -156
- package/examples/custom-tools/subagent/commands/implement-and-review.md +0 -10
- package/examples/custom-tools/subagent/commands/implement.md +0 -10
- package/examples/custom-tools/subagent/commands/scout-and-plan.md +0 -9
- package/examples/custom-tools/subagent/index.ts +0 -1002
- package/examples/sdk/05-tools.ts +0 -94
- package/examples/sdk/12-full-control.ts +0 -95
- package/src/prompts/browser.md +0 -71
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
WebSearchResponse,
|
|
14
14
|
WebSearchSource,
|
|
15
15
|
} from "../types";
|
|
16
|
+
import { WebSearchProviderError } from "../types";
|
|
16
17
|
|
|
17
18
|
const PERPLEXITY_API_URL = "https://api.perplexity.ai/chat/completions";
|
|
18
19
|
|
|
@@ -92,7 +93,11 @@ async function callPerplexity(apiKey: string, request: PerplexityRequest): Promi
|
|
|
92
93
|
|
|
93
94
|
if (!response.ok) {
|
|
94
95
|
const errorText = await response.text();
|
|
95
|
-
throw new
|
|
96
|
+
throw new WebSearchProviderError(
|
|
97
|
+
"perplexity",
|
|
98
|
+
`Perplexity API error (${response.status}): ${errorText}`,
|
|
99
|
+
response.status,
|
|
100
|
+
);
|
|
96
101
|
}
|
|
97
102
|
|
|
98
103
|
return response.json() as Promise<PerplexityResponse>;
|
|
@@ -257,10 +257,7 @@ export function renderWebSearchResult(
|
|
|
257
257
|
}
|
|
258
258
|
if (response.requestId) {
|
|
259
259
|
metaLines.push(
|
|
260
|
-
`${theme.fg("muted", "Request:")} ${theme.fg(
|
|
261
|
-
"text",
|
|
262
|
-
truncate(response.requestId, MAX_REQUEST_ID_LEN, theme.format.ellipsis),
|
|
263
|
-
)}`,
|
|
260
|
+
`${theme.fg("muted", "Request:")} ${theme.fg("text", truncate(response.requestId, MAX_REQUEST_ID_LEN, theme.format.ellipsis))}`,
|
|
264
261
|
);
|
|
265
262
|
}
|
|
266
263
|
if (searchQueries.length > 0) {
|
|
@@ -325,3 +322,8 @@ export function renderWebSearchCall(
|
|
|
325
322
|
const text = `${theme.fg("toolTitle", "Web Search")} ${theme.fg("dim", `(${provider})`)} ${theme.fg("muted", query)}`;
|
|
326
323
|
return new Text(text, 0, 0);
|
|
327
324
|
}
|
|
325
|
+
|
|
326
|
+
export const webSearchToolRenderer = {
|
|
327
|
+
renderCall: renderWebSearchCall,
|
|
328
|
+
renderResult: renderWebSearchResult,
|
|
329
|
+
};
|
|
@@ -57,6 +57,19 @@ export interface WebSearchResponse {
|
|
|
57
57
|
requestId?: string;
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
/** Provider-specific error with optional HTTP status */
|
|
61
|
+
export class WebSearchProviderError extends Error {
|
|
62
|
+
provider: WebSearchProvider;
|
|
63
|
+
status?: number;
|
|
64
|
+
|
|
65
|
+
constructor(provider: WebSearchProvider, message: string, status?: number) {
|
|
66
|
+
super(message);
|
|
67
|
+
this.name = "WebSearchProviderError";
|
|
68
|
+
this.provider = provider;
|
|
69
|
+
this.status = status;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
60
73
|
/** Auth configuration for Anthropic */
|
|
61
74
|
export interface AnthropicAuthConfig {
|
|
62
75
|
apiKey: string;
|
package/src/core/tools/write.ts
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import type { Component } from "@oh-my-pi/pi-tui";
|
|
3
|
+
import { Text } from "@oh-my-pi/pi-tui";
|
|
2
4
|
import { Type } from "@sinclair/typebox";
|
|
5
|
+
import { getLanguageFromPath, highlightCode, type Theme } from "../../modes/interactive/theme/theme";
|
|
3
6
|
import writeDescription from "../../prompts/tools/write.md" with { type: "text" };
|
|
4
|
-
import
|
|
7
|
+
import type { RenderResultOptions } from "../custom-tools/types";
|
|
8
|
+
import type { ToolSession } from "../sdk";
|
|
9
|
+
import { createLspWritethrough, type FileDiagnosticsResult } from "./lsp/index";
|
|
5
10
|
import { resolveToCwd } from "./path-utils";
|
|
11
|
+
import { formatDiagnostics, replaceTabs, shortenPath } from "./render-utils";
|
|
6
12
|
|
|
7
13
|
const writeSchema = Type.Object({
|
|
8
14
|
path: Type.String({ description: "Path to the file to write (relative or absolute)" }),
|
|
9
15
|
content: Type.String({ description: "Content to write to the file" }),
|
|
10
16
|
});
|
|
11
17
|
|
|
12
|
-
/** Options for creating the write tool */
|
|
13
|
-
export interface WriteToolOptions {
|
|
14
|
-
writethrough?: WritethroughCallback;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
18
|
/** Details returned by the write tool for TUI rendering */
|
|
18
19
|
export interface WriteToolDetails {
|
|
19
20
|
diagnostics?: FileDiagnosticsResult;
|
|
20
21
|
}
|
|
21
22
|
|
|
22
|
-
export function createWriteTool(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const writethrough = options.writethrough ?? writethroughNoop;
|
|
23
|
+
export function createWriteTool(session: ToolSession): AgentTool<typeof writeSchema, WriteToolDetails> {
|
|
24
|
+
const enableFormat = session.settings?.getLspFormatOnWrite() ?? true;
|
|
25
|
+
const enableDiagnostics = session.settings?.getLspDiagnosticsOnWrite() ?? true;
|
|
26
|
+
const writethrough = createLspWritethrough(session.cwd, { enableFormat, enableDiagnostics });
|
|
27
27
|
return {
|
|
28
28
|
name: "write",
|
|
29
29
|
label: "Write",
|
|
@@ -34,7 +34,7 @@ export function createWriteTool(
|
|
|
34
34
|
{ path, content }: { path: string; content: string },
|
|
35
35
|
signal?: AbortSignal,
|
|
36
36
|
) => {
|
|
37
|
-
const absolutePath = resolveToCwd(path, cwd);
|
|
37
|
+
const absolutePath = resolveToCwd(path, session.cwd);
|
|
38
38
|
|
|
39
39
|
const diagnostics = await writethrough(absolutePath, content, signal);
|
|
40
40
|
|
|
@@ -59,5 +59,87 @@ export function createWriteTool(
|
|
|
59
59
|
};
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
// =============================================================================
|
|
63
|
+
// TUI Renderer
|
|
64
|
+
// =============================================================================
|
|
65
|
+
|
|
66
|
+
interface WriteRenderArgs {
|
|
67
|
+
path?: string;
|
|
68
|
+
file_path?: string;
|
|
69
|
+
content?: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function countLines(text: string): number {
|
|
73
|
+
if (!text) return 0;
|
|
74
|
+
return text.split("\n").length;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function formatMetadataLine(lineCount: number | null, language: string | undefined, uiTheme: Theme): string {
|
|
78
|
+
const icon = uiTheme.getLangIcon(language);
|
|
79
|
+
if (lineCount !== null) {
|
|
80
|
+
return uiTheme.fg("dim", `${icon} ${lineCount} lines`);
|
|
81
|
+
}
|
|
82
|
+
return uiTheme.fg("dim", `${icon}`);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export const writeToolRenderer = {
|
|
86
|
+
renderCall(args: WriteRenderArgs, uiTheme: Theme): Component {
|
|
87
|
+
const rawPath = args.file_path || args.path || "";
|
|
88
|
+
const filePath = shortenPath(rawPath);
|
|
89
|
+
const pathDisplay = filePath ? uiTheme.fg("accent", filePath) : uiTheme.fg("toolOutput", uiTheme.format.ellipsis);
|
|
90
|
+
const text = `${uiTheme.fg("toolTitle", uiTheme.bold("Write"))} ${pathDisplay}`;
|
|
91
|
+
return new Text(text, 0, 0);
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
renderResult(
|
|
95
|
+
result: { content: Array<{ type: string; text?: string }>; details?: WriteToolDetails },
|
|
96
|
+
{ expanded }: RenderResultOptions,
|
|
97
|
+
uiTheme: Theme,
|
|
98
|
+
args?: WriteRenderArgs,
|
|
99
|
+
): Component {
|
|
100
|
+
const rawPath = args?.file_path || args?.path || "";
|
|
101
|
+
const fileContent = args?.content || "";
|
|
102
|
+
const lang = getLanguageFromPath(rawPath);
|
|
103
|
+
const contentLines = fileContent
|
|
104
|
+
? lang
|
|
105
|
+
? highlightCode(replaceTabs(fileContent), lang)
|
|
106
|
+
: fileContent.split("\n")
|
|
107
|
+
: [];
|
|
108
|
+
const totalLines = contentLines.length;
|
|
109
|
+
const outputLines: string[] = [];
|
|
110
|
+
|
|
111
|
+
outputLines.push(formatMetadataLine(countLines(fileContent), lang ?? "text", uiTheme));
|
|
112
|
+
|
|
113
|
+
if (fileContent) {
|
|
114
|
+
const maxLines = expanded ? contentLines.length : 10;
|
|
115
|
+
const displayLines = contentLines.slice(0, maxLines);
|
|
116
|
+
const remaining = contentLines.length - maxLines;
|
|
117
|
+
|
|
118
|
+
outputLines.push(
|
|
119
|
+
"",
|
|
120
|
+
...displayLines.map((line: string) =>
|
|
121
|
+
lang ? replaceTabs(line) : uiTheme.fg("toolOutput", replaceTabs(line)),
|
|
122
|
+
),
|
|
123
|
+
);
|
|
124
|
+
if (remaining > 0) {
|
|
125
|
+
outputLines.push(
|
|
126
|
+
uiTheme.fg(
|
|
127
|
+
"toolOutput",
|
|
128
|
+
`${uiTheme.format.ellipsis} (${remaining} more lines, ${totalLines} total) ${uiTheme.format.bracketLeft}Ctrl+O to expand${uiTheme.format.bracketRight}`,
|
|
129
|
+
),
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Show LSP diagnostics if available
|
|
135
|
+
if (result.details?.diagnostics) {
|
|
136
|
+
outputLines.push(
|
|
137
|
+
formatDiagnostics(result.details.diagnostics, expanded, uiTheme, (fp) =>
|
|
138
|
+
uiTheme.getLangIcon(getLanguageFromPath(fp)),
|
|
139
|
+
),
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return new Text(outputLines.join("\n"), 0, 0);
|
|
144
|
+
},
|
|
145
|
+
};
|
package/src/core/voice.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { unlinkSync } from "node:fs";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { completeSimple, type Model } from "@
|
|
4
|
+
import { completeSimple, type Model } from "@mariozechner/pi-ai";
|
|
5
5
|
import voiceSummaryPrompt from "../prompts/voice-summary.md" with { type: "text" };
|
|
6
6
|
import { logger } from "./logger";
|
|
7
7
|
import type { ModelRegistry } from "./model-registry";
|
package/src/index.ts
CHANGED
|
@@ -81,6 +81,8 @@ export { ModelRegistry } from "./core/model-registry";
|
|
|
81
81
|
export type { PromptTemplate } from "./core/prompt-templates";
|
|
82
82
|
// SDK for programmatic usage
|
|
83
83
|
export {
|
|
84
|
+
// Tool factories
|
|
85
|
+
BUILTIN_TOOLS,
|
|
84
86
|
type BuildSystemPromptOptions,
|
|
85
87
|
buildSystemPrompt,
|
|
86
88
|
type CreateAgentSessionOptions,
|
|
@@ -88,14 +90,12 @@ export {
|
|
|
88
90
|
// Factory
|
|
89
91
|
createAgentSession,
|
|
90
92
|
createBashTool,
|
|
91
|
-
// Tool factories (for custom cwd)
|
|
92
|
-
createCodingTools,
|
|
93
93
|
createEditTool,
|
|
94
94
|
createFindTool,
|
|
95
95
|
createGrepTool,
|
|
96
96
|
createLsTool,
|
|
97
|
-
createReadOnlyTools,
|
|
98
97
|
createReadTool,
|
|
98
|
+
createTools,
|
|
99
99
|
createWriteTool,
|
|
100
100
|
// Discovery
|
|
101
101
|
discoverAuthStorage,
|
|
@@ -107,8 +107,7 @@ export {
|
|
|
107
107
|
discoverPromptTemplates,
|
|
108
108
|
discoverSkills,
|
|
109
109
|
loadSettings,
|
|
110
|
-
|
|
111
|
-
readOnlyTools,
|
|
110
|
+
type ToolSession,
|
|
112
111
|
} from "./core/sdk";
|
|
113
112
|
export {
|
|
114
113
|
type BranchSummaryEntry,
|
|
@@ -154,27 +153,17 @@ export {
|
|
|
154
153
|
} from "./core/skills";
|
|
155
154
|
// Slash commands
|
|
156
155
|
export { type FileSlashCommand, loadSlashCommands as discoverSlashCommands } from "./core/slash-commands";
|
|
157
|
-
// Tools
|
|
156
|
+
// Tools (detail types only - factories exported from sdk)
|
|
158
157
|
export {
|
|
159
158
|
type BashToolDetails,
|
|
160
|
-
bashTool,
|
|
161
|
-
type CodingToolsOptions,
|
|
162
|
-
codingTools,
|
|
163
|
-
editTool,
|
|
164
159
|
type FindToolDetails,
|
|
165
|
-
findTool,
|
|
166
160
|
type GitToolDetails,
|
|
167
161
|
type GrepToolDetails,
|
|
168
162
|
gitTool,
|
|
169
|
-
grepTool,
|
|
170
163
|
type LsToolDetails,
|
|
171
|
-
lsTool,
|
|
172
164
|
type ReadToolDetails,
|
|
173
|
-
readTool,
|
|
174
165
|
type TruncationResult,
|
|
175
166
|
type WriteToolDetails,
|
|
176
|
-
type WriteToolOptions,
|
|
177
|
-
writeTool,
|
|
178
167
|
} from "./core/tools/index";
|
|
179
168
|
export type { FileDiagnosticsResult } from "./core/tools/lsp/index";
|
|
180
169
|
// Main entry point
|
package/src/main.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* createAgentSession() options. The SDK does the heavy lifting.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { type ImageContent, supportsXhigh } from "@
|
|
8
|
+
import { type ImageContent, supportsXhigh } from "@mariozechner/pi-ai";
|
|
9
9
|
import chalk from "chalk";
|
|
10
10
|
import { type Args, parseArgs, printHelp } from "./cli/args";
|
|
11
11
|
import { processFileArguments } from "./cli/file-processor";
|
|
@@ -24,7 +24,6 @@ import { SessionManager } from "./core/session-manager";
|
|
|
24
24
|
import { SettingsManager } from "./core/settings-manager";
|
|
25
25
|
import { resolvePromptInput } from "./core/system-prompt";
|
|
26
26
|
import { printTimings, time } from "./core/timings";
|
|
27
|
-
import { allTools } from "./core/tools/index";
|
|
28
27
|
import { runMigrations, showDeprecationWarnings } from "./migrations";
|
|
29
28
|
import { InteractiveMode, installTerminalCrashHandlers, runPrintMode, runRpcMode } from "./modes/index";
|
|
30
29
|
import { initTheme, stopThemeWatcher } from "./modes/interactive/theme/theme";
|
|
@@ -210,7 +209,9 @@ async function buildSessionOptions(
|
|
|
210
209
|
modelRegistry: ModelRegistry,
|
|
211
210
|
settingsManager: SettingsManager,
|
|
212
211
|
): Promise<CreateAgentSessionOptions> {
|
|
213
|
-
const options: CreateAgentSessionOptions = {
|
|
212
|
+
const options: CreateAgentSessionOptions = {
|
|
213
|
+
cwd: parsed.cwd ?? process.cwd(),
|
|
214
|
+
};
|
|
214
215
|
|
|
215
216
|
// Auto-discover SYSTEM.md if no CLI system prompt provided
|
|
216
217
|
const systemPromptSource = parsed.systemPrompt ?? discoverSystemPromptFile();
|
|
@@ -263,8 +264,7 @@ async function buildSessionOptions(
|
|
|
263
264
|
|
|
264
265
|
// Tools
|
|
265
266
|
if (parsed.tools) {
|
|
266
|
-
options.
|
|
267
|
-
options.explicitTools = parsed.tools;
|
|
267
|
+
options.toolNames = parsed.tools;
|
|
268
268
|
}
|
|
269
269
|
|
|
270
270
|
// Skills
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TextContent } from "@
|
|
1
|
+
import type { TextContent } from "@mariozechner/pi-ai";
|
|
2
2
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
3
3
|
import { Box, Container, Markdown, Spacer, Text } from "@oh-my-pi/pi-tui";
|
|
4
4
|
import type { MessageRenderer } from "../../../core/extensions/types";
|
|
@@ -68,7 +68,7 @@ export class InspectorPanel implements Component {
|
|
|
68
68
|
|
|
69
69
|
switch (ext.kind) {
|
|
70
70
|
case "context-file":
|
|
71
|
-
content = this.renderFilePreview(ext.
|
|
71
|
+
content = this.renderFilePreview(ext.raw, width);
|
|
72
72
|
break;
|
|
73
73
|
case "tool":
|
|
74
74
|
content = this.renderToolArgs(ext.raw, width);
|
|
@@ -91,37 +91,40 @@ export class InspectorPanel implements Component {
|
|
|
91
91
|
return lines;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
private renderFilePreview(
|
|
94
|
+
private renderFilePreview(raw: unknown, width: number): string[] {
|
|
95
95
|
const lines: string[] = [];
|
|
96
96
|
lines.push(theme.fg("muted", "Preview:"));
|
|
97
97
|
lines.push(theme.fg("dim", theme.boxSharp.horizontal.repeat(Math.min(width - 2, 40))));
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
}
|
|
117
|
-
} catch (err) {
|
|
118
|
-
lines.push(theme.fg("error", `Failed to read file: ${err instanceof Error ? err.message : String(err)}`));
|
|
99
|
+
const content = this.getContextFileContent(raw);
|
|
100
|
+
if (!content) {
|
|
101
|
+
lines.push(theme.fg("dim", " (no content)"));
|
|
102
|
+
lines.push("");
|
|
103
|
+
return lines;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const fileLines = content.split("\n");
|
|
107
|
+
for (const line of fileLines.slice(0, 20)) {
|
|
108
|
+
const highlighted = this.highlightMarkdown(line);
|
|
109
|
+
lines.push(truncateToWidth(highlighted, width - 2));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (fileLines.length > 20) {
|
|
113
|
+
lines.push(theme.fg("dim", "(truncated at line 20)"));
|
|
119
114
|
}
|
|
120
115
|
|
|
121
116
|
lines.push("");
|
|
122
117
|
return lines;
|
|
123
118
|
}
|
|
124
119
|
|
|
120
|
+
private getContextFileContent(raw: unknown): string | null {
|
|
121
|
+
if (raw && typeof raw === "object" && "content" in raw) {
|
|
122
|
+
const content = (raw as { content?: unknown }).content;
|
|
123
|
+
return typeof content === "string" ? content : null;
|
|
124
|
+
}
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
|
|
125
128
|
private highlightMarkdown(line: string): string {
|
|
126
129
|
// Basic markdown syntax highlighting
|
|
127
130
|
let highlighted = line;
|
|
@@ -10,6 +10,7 @@ import type { MCPServer } from "../../../../capability/mcp";
|
|
|
10
10
|
import type { Prompt } from "../../../../capability/prompt";
|
|
11
11
|
import type { Rule } from "../../../../capability/rule";
|
|
12
12
|
import type { Skill } from "../../../../capability/skill";
|
|
13
|
+
import type { SlashCommand } from "../../../../capability/slash-command";
|
|
13
14
|
import type { CustomTool } from "../../../../capability/tool";
|
|
14
15
|
import type { SourceMeta } from "../../../../capability/types";
|
|
15
16
|
import {
|
|
@@ -192,6 +193,17 @@ export function loadAllExtensions(cwd?: string, disabledIds?: string[]): Extensi
|
|
|
192
193
|
// Capability may not be registered
|
|
193
194
|
}
|
|
194
195
|
|
|
196
|
+
// Load slash commands
|
|
197
|
+
try {
|
|
198
|
+
const commands = loadSync<SlashCommand>("slash-commands", loadOpts);
|
|
199
|
+
addItems(commands.all, "slash-command", {
|
|
200
|
+
getDescription: () => undefined,
|
|
201
|
+
getTrigger: (c) => `/${c.name}`,
|
|
202
|
+
});
|
|
203
|
+
} catch {
|
|
204
|
+
// Capability may not be registered
|
|
205
|
+
}
|
|
206
|
+
|
|
195
207
|
// Load hooks
|
|
196
208
|
try {
|
|
197
209
|
const hooks = loadSync<Hook>("hooks", loadOpts);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { existsSync, type FSWatcher, readFileSync, watch } from "node:fs";
|
|
2
|
-
import type { AssistantMessage } from "@
|
|
2
|
+
import type { AssistantMessage } from "@mariozechner/pi-ai";
|
|
3
3
|
import { type Component, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
|
4
4
|
import { dirname, join } from "path";
|
|
5
5
|
import type { AgentSession } from "../../../core/agent-session";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TextContent } from "@
|
|
1
|
+
import type { TextContent } from "@mariozechner/pi-ai";
|
|
2
2
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
3
3
|
import { Box, Container, Markdown, Spacer, Text } from "@oh-my-pi/pi-tui";
|
|
4
4
|
import type { HookMessageRenderer } from "../../../core/hooks/types";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getOAuthProviders, type OAuthProviderInfo } from "@
|
|
1
|
+
import { getOAuthProviders, type OAuthProviderInfo } from "@mariozechner/pi-ai";
|
|
2
2
|
import { Container, isArrowDown, isArrowUp, isCtrlC, isEnter, isEscape, Spacer, TruncatedText } from "@oh-my-pi/pi-tui";
|
|
3
3
|
import type { AuthStorage } from "../../../core/auth-storage";
|
|
4
4
|
import { theme } from "../theme/theme";
|
|
@@ -11,11 +11,13 @@
|
|
|
11
11
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
12
12
|
import { getCapabilities } from "@oh-my-pi/pi-tui";
|
|
13
13
|
import type {
|
|
14
|
+
ImageProviderOption,
|
|
14
15
|
NotificationMethod,
|
|
15
16
|
SettingsManager,
|
|
16
17
|
StatusLinePreset,
|
|
17
18
|
StatusLineSeparatorStyle,
|
|
18
19
|
SymbolPreset,
|
|
20
|
+
WebSearchProviderOption,
|
|
19
21
|
} from "../../../core/settings-manager";
|
|
20
22
|
import { getPreset } from "./status-line/presets";
|
|
21
23
|
|
|
@@ -86,6 +88,15 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
86
88
|
get: (sm) => sm.getCompactionEnabled(),
|
|
87
89
|
set: (sm, v) => sm.setCompactionEnabled(v), // Also handled in session
|
|
88
90
|
},
|
|
91
|
+
{
|
|
92
|
+
id: "branchSummaries",
|
|
93
|
+
tab: "config",
|
|
94
|
+
type: "boolean",
|
|
95
|
+
label: "Branch summaries",
|
|
96
|
+
description: "Prompt to summarize when leaving a branch",
|
|
97
|
+
get: (sm) => sm.getBranchSummaryEnabled(),
|
|
98
|
+
set: (sm, v) => sm.setBranchSummaryEnabled(v),
|
|
99
|
+
},
|
|
89
100
|
{
|
|
90
101
|
id: "showImages",
|
|
91
102
|
tab: "config",
|
|
@@ -191,6 +202,15 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
191
202
|
get: (sm) => sm.getBashInterceptorEnabled(),
|
|
192
203
|
set: (sm, v) => sm.setBashInterceptorEnabled(v),
|
|
193
204
|
},
|
|
205
|
+
{
|
|
206
|
+
id: "gitTool",
|
|
207
|
+
tab: "config",
|
|
208
|
+
type: "boolean",
|
|
209
|
+
label: "Git tool",
|
|
210
|
+
description: "Enable structured Git tool",
|
|
211
|
+
get: (sm) => sm.getGitToolEnabled(),
|
|
212
|
+
set: (sm, v) => sm.setGitToolEnabled(v),
|
|
213
|
+
},
|
|
194
214
|
{
|
|
195
215
|
id: "mcpProjectConfig",
|
|
196
216
|
tab: "config",
|
|
@@ -277,6 +297,35 @@ export const SETTINGS_DEFS: SettingDef[] = [
|
|
|
277
297
|
{ value: "ascii", label: "ASCII", description: "ASCII-only characters (maximum compatibility)" },
|
|
278
298
|
],
|
|
279
299
|
},
|
|
300
|
+
{
|
|
301
|
+
id: "webSearchProvider",
|
|
302
|
+
tab: "config",
|
|
303
|
+
type: "submenu",
|
|
304
|
+
label: "Web search provider",
|
|
305
|
+
description: "Provider for web search tool",
|
|
306
|
+
get: (sm) => sm.getWebSearchProvider(),
|
|
307
|
+
set: (sm, v) => sm.setWebSearchProvider(v as WebSearchProviderOption),
|
|
308
|
+
getOptions: () => [
|
|
309
|
+
{ value: "auto", label: "Auto", description: "Priority: Exa > Perplexity > Anthropic" },
|
|
310
|
+
{ value: "exa", label: "Exa", description: "Use Exa (requires EXA_API_KEY)" },
|
|
311
|
+
{ value: "perplexity", label: "Perplexity", description: "Use Perplexity (requires PERPLEXITY_API_KEY)" },
|
|
312
|
+
{ value: "anthropic", label: "Anthropic", description: "Use Anthropic web search" },
|
|
313
|
+
],
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
id: "imageProvider",
|
|
317
|
+
tab: "config",
|
|
318
|
+
type: "submenu",
|
|
319
|
+
label: "Image provider",
|
|
320
|
+
description: "Provider for image generation tool",
|
|
321
|
+
get: (sm) => sm.getImageProvider(),
|
|
322
|
+
set: (sm, v) => sm.setImageProvider(v as ImageProviderOption),
|
|
323
|
+
getOptions: () => [
|
|
324
|
+
{ value: "auto", label: "Auto", description: "Priority: OpenRouter > Gemini" },
|
|
325
|
+
{ value: "gemini", label: "Gemini", description: "Use Gemini API directly (requires GEMINI_API_KEY)" },
|
|
326
|
+
{ value: "openrouter", label: "OpenRouter", description: "Use OpenRouter (requires OPENROUTER_API_KEY)" },
|
|
327
|
+
],
|
|
328
|
+
},
|
|
280
329
|
|
|
281
330
|
// LSP tab
|
|
282
331
|
{
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AssistantMessage } from "@
|
|
1
|
+
import type { AssistantMessage } from "@mariozechner/pi-ai";
|
|
2
2
|
import { type Component, truncateToWidth, visibleWidth } from "@oh-my-pi/pi-tui";
|
|
3
3
|
import { type FSWatcher, watch } from "fs";
|
|
4
4
|
import { dirname, join } from "path";
|