@oh-my-pi/pi-coding-agent 1.341.0 → 2.1.1337
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 +86 -0
- package/README.md +1 -1
- package/examples/custom-tools/subagent/index.ts +1 -1
- package/package.json +10 -9
- package/src/bun-imports.d.ts +16 -0
- package/src/cli/args.ts +5 -6
- package/src/cli/file-processor.ts +3 -3
- package/src/cli/list-models.ts +2 -2
- package/src/cli/plugin-cli.ts +1 -1
- package/src/cli/session-picker.ts +2 -2
- package/src/cli/update-cli.ts +273 -0
- package/src/cli.ts +1 -1
- package/src/config.ts +23 -75
- package/src/core/agent-session.ts +158 -16
- package/src/core/auth-storage.ts +2 -3
- package/src/core/bash-executor.ts +50 -10
- package/src/core/compaction/branch-summarization.ts +5 -5
- package/src/core/compaction/compaction.ts +3 -3
- package/src/core/compaction/index.ts +3 -3
- package/src/core/custom-commands/bundled/review/index.ts +156 -0
- package/src/core/custom-commands/index.ts +15 -0
- package/src/core/custom-commands/loader.ts +232 -0
- package/src/core/custom-commands/types.ts +112 -0
- package/src/core/custom-tools/index.ts +3 -3
- package/src/core/custom-tools/loader.ts +10 -8
- package/src/core/custom-tools/types.ts +11 -6
- package/src/core/custom-tools/wrapper.ts +2 -1
- package/src/core/exec.ts +22 -12
- package/src/core/export-html/index.ts +38 -123
- package/src/core/export-html/template.css +0 -7
- package/src/core/export-html/template.html +3 -4
- package/src/core/export-html/template.macro.ts +24 -0
- package/src/core/file-mentions.ts +54 -0
- package/src/core/hooks/index.ts +5 -5
- package/src/core/hooks/loader.ts +21 -16
- package/src/core/hooks/runner.ts +6 -6
- package/src/core/hooks/tool-wrapper.ts +2 -2
- package/src/core/hooks/types.ts +12 -15
- package/src/core/index.ts +6 -6
- package/src/core/logger.ts +112 -0
- package/src/core/mcp/client.ts +3 -3
- package/src/core/mcp/config.ts +1 -1
- package/src/core/mcp/index.ts +12 -12
- package/src/core/mcp/loader.ts +2 -2
- package/src/core/mcp/manager.ts +6 -6
- package/src/core/mcp/tool-bridge.ts +3 -3
- package/src/core/mcp/transports/http.ts +1 -1
- package/src/core/mcp/transports/index.ts +2 -2
- package/src/core/mcp/transports/stdio.ts +1 -1
- package/src/core/messages.ts +22 -0
- package/src/core/model-registry.ts +2 -2
- package/src/core/model-resolver.ts +2 -2
- package/src/core/plugins/doctor.ts +1 -1
- package/src/core/plugins/index.ts +6 -6
- package/src/core/plugins/installer.ts +4 -4
- package/src/core/plugins/loader.ts +4 -9
- package/src/core/plugins/manager.ts +5 -5
- package/src/core/plugins/paths.ts +3 -3
- package/src/core/sdk.ts +77 -35
- package/src/core/session-manager.ts +6 -6
- package/src/core/settings-manager.ts +16 -3
- package/src/core/skills.ts +5 -5
- package/src/core/slash-commands.ts +60 -45
- package/src/core/system-prompt.ts +6 -6
- package/src/core/title-generator.ts +2 -2
- package/src/core/tools/bash.ts +32 -155
- package/src/core/tools/context.ts +2 -2
- package/src/core/tools/edit-diff.ts +3 -3
- package/src/core/tools/edit.ts +18 -5
- package/src/core/tools/exa/company.ts +3 -3
- package/src/core/tools/exa/index.ts +16 -17
- package/src/core/tools/exa/linkedin.ts +3 -3
- package/src/core/tools/exa/mcp-client.ts +9 -9
- package/src/core/tools/exa/render.ts +5 -5
- package/src/core/tools/exa/researcher.ts +3 -3
- package/src/core/tools/exa/search.ts +6 -5
- package/src/core/tools/exa/types.ts +5 -6
- package/src/core/tools/exa/websets.ts +3 -3
- package/src/core/tools/find.ts +3 -3
- package/src/core/tools/grep.ts +3 -3
- package/src/core/tools/index.ts +48 -34
- package/src/core/tools/ls.ts +4 -4
- package/src/core/tools/lsp/client.ts +161 -90
- package/src/core/tools/lsp/config.ts +1 -1
- package/src/core/tools/lsp/edits.ts +2 -2
- package/src/core/tools/lsp/index.ts +15 -13
- package/src/core/tools/lsp/render.ts +2 -2
- package/src/core/tools/lsp/rust-analyzer.ts +3 -3
- package/src/core/tools/lsp/utils.ts +1 -1
- package/src/core/tools/notebook.ts +1 -1
- package/src/core/tools/output.ts +175 -0
- package/src/core/tools/read.ts +7 -7
- package/src/core/tools/renderers.ts +92 -13
- package/src/core/tools/review.ts +268 -0
- package/src/core/tools/task/agents.ts +22 -38
- package/src/core/tools/task/bundled-agents/reviewer.md +52 -37
- package/src/core/tools/task/commands.ts +31 -10
- package/src/core/tools/task/discovery.ts +2 -2
- package/src/core/tools/task/executor.ts +145 -28
- package/src/core/tools/task/index.ts +78 -30
- package/src/core/tools/task/model-resolver.ts +30 -20
- package/src/core/tools/task/parallel.ts +1 -1
- package/src/core/tools/task/render.ts +219 -30
- package/src/core/tools/task/subprocess-tool-registry.ts +89 -0
- package/src/core/tools/task/types.ts +36 -2
- package/src/core/tools/web-fetch.ts +5 -3
- package/src/core/tools/web-search/auth.ts +1 -1
- package/src/core/tools/web-search/index.ts +17 -15
- package/src/core/tools/web-search/providers/anthropic.ts +2 -2
- package/src/core/tools/web-search/providers/exa.ts +3 -5
- package/src/core/tools/web-search/providers/perplexity.ts +1 -1
- package/src/core/tools/web-search/render.ts +3 -3
- package/src/core/tools/write.ts +4 -4
- package/src/index.ts +29 -18
- package/src/main.ts +50 -33
- package/src/migrations.ts +3 -3
- package/src/modes/index.ts +5 -5
- package/src/modes/interactive/components/armin.ts +1 -1
- package/src/modes/interactive/components/assistant-message.ts +1 -1
- package/src/modes/interactive/components/bash-execution.ts +4 -4
- package/src/modes/interactive/components/bordered-loader.ts +2 -2
- package/src/modes/interactive/components/branch-summary-message.ts +2 -2
- package/src/modes/interactive/components/compaction-summary-message.ts +2 -2
- package/src/modes/interactive/components/diff.ts +1 -1
- package/src/modes/interactive/components/dynamic-border.ts +1 -1
- package/src/modes/interactive/components/footer.ts +5 -5
- package/src/modes/interactive/components/hook-editor.ts +2 -2
- package/src/modes/interactive/components/hook-input.ts +2 -2
- package/src/modes/interactive/components/hook-message.ts +3 -3
- package/src/modes/interactive/components/hook-selector.ts +2 -2
- package/src/modes/interactive/components/model-selector.ts +281 -59
- package/src/modes/interactive/components/oauth-selector.ts +3 -3
- package/src/modes/interactive/components/plugin-settings.ts +4 -4
- package/src/modes/interactive/components/queue-mode-selector.ts +2 -2
- package/src/modes/interactive/components/session-selector.ts +4 -4
- package/src/modes/interactive/components/settings-defs.ts +1 -1
- package/src/modes/interactive/components/settings-selector.ts +5 -5
- package/src/modes/interactive/components/show-images-selector.ts +2 -2
- package/src/modes/interactive/components/theme-selector.ts +2 -2
- package/src/modes/interactive/components/thinking-selector.ts +2 -2
- package/src/modes/interactive/components/tool-execution.ts +26 -8
- package/src/modes/interactive/components/tree-selector.ts +3 -3
- package/src/modes/interactive/components/user-message-selector.ts +2 -2
- package/src/modes/interactive/components/user-message.ts +1 -1
- package/src/modes/interactive/components/welcome.ts +2 -2
- package/src/modes/interactive/interactive-mode.ts +86 -42
- package/src/modes/interactive/theme/theme.ts +15 -17
- package/src/modes/print-mode.ts +4 -3
- package/src/modes/rpc/rpc-client.ts +4 -4
- package/src/modes/rpc/rpc-mode.ts +22 -12
- package/src/modes/rpc/rpc-types.ts +3 -3
- package/src/utils/changelog.ts +2 -2
- package/src/utils/clipboard.ts +1 -1
- package/src/utils/shell-snapshot.ts +218 -0
- package/src/utils/shell.ts +93 -13
- package/src/utils/tools-manager.ts +1 -1
- package/examples/custom-tools/subagent/agents/reviewer.md +0 -35
- package/src/core/tools/exa/logger.ts +0 -56
|
@@ -1,44 +1,19 @@
|
|
|
1
|
+
import { existsSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { basename } from "node:path";
|
|
1
3
|
import type { AgentState } from "@oh-my-pi/pi-agent-core";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { getResolvedThemeColors, getThemeExportColors } from "../../modes/interactive/theme/theme.js";
|
|
6
|
-
import { SessionManager } from "../session-manager.js";
|
|
7
|
-
|
|
8
|
-
// Cached minified assets (populated on first use)
|
|
9
|
-
let cachedTemplate: string | null = null;
|
|
10
|
-
let cachedJs: string | null = null;
|
|
11
|
-
|
|
12
|
-
/** Minify CSS by removing comments, unnecessary whitespace, and newlines. */
|
|
13
|
-
function minifyCss(css: string): string {
|
|
14
|
-
return css
|
|
15
|
-
.replace(/\/\*[\s\S]*?\*\//g, "") // Remove comments
|
|
16
|
-
.replace(/\s+/g, " ") // Collapse whitespace
|
|
17
|
-
.replace(/\s*([{}:;,>+~])\s*/g, "$1") // Remove space around punctuation
|
|
18
|
-
.replace(/;}/g, "}") // Remove trailing semicolons
|
|
19
|
-
.trim();
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/** Minify JS using Bun's transpiler. */
|
|
23
|
-
function minifyJs(js: string): string {
|
|
24
|
-
const transpiler = new Bun.Transpiler({ loader: "js", minifyWhitespace: true });
|
|
25
|
-
return transpiler.transformSync(js);
|
|
26
|
-
}
|
|
4
|
+
import { APP_NAME } from "../../config";
|
|
5
|
+
import { getResolvedThemeColors, getThemeExportColors } from "../../modes/interactive/theme/theme";
|
|
6
|
+
import { SessionManager } from "../session-manager";
|
|
27
7
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
return html
|
|
31
|
-
.replace(/>\s+</g, "><") // Remove whitespace between tags
|
|
32
|
-
.replace(/\s{2,}/g, " ") // Collapse multiple spaces
|
|
33
|
-
.trim();
|
|
34
|
-
}
|
|
8
|
+
// Bun macro: bundles HTML+CSS+JS at compile time, evaluated at bundle time
|
|
9
|
+
import { getTemplate } from "./template.macro" with { type: "macro" };
|
|
35
10
|
|
|
36
11
|
export interface ExportOptions {
|
|
37
12
|
outputPath?: string;
|
|
38
13
|
themeName?: string;
|
|
39
14
|
}
|
|
40
15
|
|
|
41
|
-
/** Parse a color string to RGB values.
|
|
16
|
+
/** Parse a color string to RGB values. */
|
|
42
17
|
function parseColor(color: string): { r: number; g: number; b: number } | undefined {
|
|
43
18
|
const hexMatch = color.match(/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/);
|
|
44
19
|
if (hexMatch) {
|
|
@@ -68,7 +43,7 @@ function getLuminance(r: number, g: number, b: number): number {
|
|
|
68
43
|
return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
|
|
69
44
|
}
|
|
70
45
|
|
|
71
|
-
/** Adjust color brightness.
|
|
46
|
+
/** Adjust color brightness. */
|
|
72
47
|
function adjustBrightness(color: string, factor: number): string {
|
|
73
48
|
const parsed = parseColor(color);
|
|
74
49
|
if (!parsed) return color;
|
|
@@ -76,21 +51,15 @@ function adjustBrightness(color: string, factor: number): string {
|
|
|
76
51
|
return `rgb(${adjust(parsed.r)}, ${adjust(parsed.g)}, ${adjust(parsed.b)})`;
|
|
77
52
|
}
|
|
78
53
|
|
|
79
|
-
/** Derive export background colors from a base color
|
|
54
|
+
/** Derive export background colors from a base color. */
|
|
80
55
|
function deriveExportColors(baseColor: string): { pageBg: string; cardBg: string; infoBg: string } {
|
|
81
56
|
const parsed = parseColor(baseColor);
|
|
82
57
|
if (!parsed) {
|
|
83
|
-
return {
|
|
84
|
-
pageBg: "rgb(24, 24, 30)",
|
|
85
|
-
cardBg: "rgb(30, 30, 36)",
|
|
86
|
-
infoBg: "rgb(60, 55, 40)",
|
|
87
|
-
};
|
|
58
|
+
return { pageBg: "rgb(24, 24, 30)", cardBg: "rgb(30, 30, 36)", infoBg: "rgb(60, 55, 40)" };
|
|
88
59
|
}
|
|
89
60
|
|
|
90
61
|
const luminance = getLuminance(parsed.r, parsed.g, parsed.b);
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (isLight) {
|
|
62
|
+
if (luminance > 0.5) {
|
|
94
63
|
return {
|
|
95
64
|
pageBg: adjustBrightness(baseColor, 0.96),
|
|
96
65
|
cardBg: baseColor,
|
|
@@ -104,9 +73,7 @@ function deriveExportColors(baseColor: string): { pageBg: string; cardBg: string
|
|
|
104
73
|
};
|
|
105
74
|
}
|
|
106
75
|
|
|
107
|
-
/**
|
|
108
|
-
* Generate CSS custom property declarations from theme colors.
|
|
109
|
-
*/
|
|
76
|
+
/** Generate CSS custom properties for theme. */
|
|
110
77
|
function generateThemeVars(themeName?: string): string {
|
|
111
78
|
const colors = getResolvedThemeColors(themeName);
|
|
112
79
|
const lines: string[] = [];
|
|
@@ -114,16 +81,15 @@ function generateThemeVars(themeName?: string): string {
|
|
|
114
81
|
lines.push(`--${key}: ${value};`);
|
|
115
82
|
}
|
|
116
83
|
|
|
117
|
-
// Use explicit theme export colors if available, otherwise derive from userMessageBg
|
|
118
84
|
const themeExport = getThemeExportColors(themeName);
|
|
119
85
|
const userMessageBg = colors.userMessageBg || "#343541";
|
|
120
|
-
const
|
|
86
|
+
const derived = deriveExportColors(userMessageBg);
|
|
121
87
|
|
|
122
|
-
lines.push(`--
|
|
123
|
-
lines.push(`--
|
|
124
|
-
lines.push(`--
|
|
88
|
+
lines.push(`--body-bg: ${themeExport.pageBg ?? derived.pageBg};`);
|
|
89
|
+
lines.push(`--container-bg: ${themeExport.cardBg ?? derived.cardBg};`);
|
|
90
|
+
lines.push(`--info-bg: ${themeExport.infoBg ?? derived.infoBg};`);
|
|
125
91
|
|
|
126
|
-
return lines.join("
|
|
92
|
+
return lines.join(" ");
|
|
127
93
|
}
|
|
128
94
|
|
|
129
95
|
interface SessionData {
|
|
@@ -134,61 +100,28 @@ interface SessionData {
|
|
|
134
100
|
tools?: { name: string; description: string }[];
|
|
135
101
|
}
|
|
136
102
|
|
|
137
|
-
/**
|
|
138
|
-
|
|
139
|
-
*/
|
|
140
|
-
function generateHtml(sessionData: SessionData, themeName?: string): string {
|
|
141
|
-
const templateDir = getExportTemplateDir();
|
|
142
|
-
|
|
143
|
-
// Load and minify assets on first use
|
|
144
|
-
if (!cachedTemplate) {
|
|
145
|
-
cachedTemplate = minifyHtml(readFileSync(join(templateDir, "template.html"), "utf-8"));
|
|
146
|
-
}
|
|
147
|
-
if (!cachedJs) {
|
|
148
|
-
cachedJs = minifyJs(readFileSync(join(templateDir, "template.js"), "utf-8"));
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
const templateCss = readFileSync(join(templateDir, "template.css"), "utf-8");
|
|
152
|
-
|
|
103
|
+
/** Generate HTML from bundled template with runtime substitutions. */
|
|
104
|
+
async function generateHtml(sessionData: SessionData, themeName?: string): Promise<string> {
|
|
153
105
|
const themeVars = generateThemeVars(themeName);
|
|
154
|
-
const colors = getResolvedThemeColors(themeName);
|
|
155
|
-
const exportColors = deriveExportColors(colors.userMessageBg || "#343541");
|
|
156
|
-
const bodyBg = exportColors.pageBg;
|
|
157
|
-
const containerBg = exportColors.cardBg;
|
|
158
|
-
const infoBg = exportColors.infoBg;
|
|
159
|
-
|
|
160
|
-
// Base64 encode session data to avoid escaping issues
|
|
161
106
|
const sessionDataBase64 = Buffer.from(JSON.stringify(sessionData)).toString("base64");
|
|
107
|
+
const template = await getTemplate();
|
|
162
108
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
templateCss
|
|
166
|
-
.replace("{{THEME_VARS}}", themeVars)
|
|
167
|
-
.replace("{{BODY_BG}}", bodyBg)
|
|
168
|
-
.replace("{{CONTAINER_BG}}", containerBg)
|
|
169
|
-
.replace("{{INFO_BG}}", infoBg),
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
return cachedTemplate
|
|
173
|
-
.replace("{{CSS}}", css)
|
|
174
|
-
.replace("{{JS}}", cachedJs)
|
|
109
|
+
return template
|
|
110
|
+
.replace("<theme-vars/>", `<style>:root { ${themeVars} }</style>`)
|
|
175
111
|
.replace("{{SESSION_DATA}}", sessionDataBase64);
|
|
176
112
|
}
|
|
177
113
|
|
|
178
|
-
/**
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
114
|
+
/** Export session to HTML using SessionManager and AgentState. */
|
|
115
|
+
export async function exportSessionToHtml(
|
|
116
|
+
sm: SessionManager,
|
|
117
|
+
state?: AgentState,
|
|
118
|
+
options?: ExportOptions | string,
|
|
119
|
+
): Promise<string> {
|
|
183
120
|
const opts: ExportOptions = typeof options === "string" ? { outputPath: options } : options || {};
|
|
184
121
|
|
|
185
122
|
const sessionFile = sm.getSessionFile();
|
|
186
|
-
if (!sessionFile)
|
|
187
|
-
|
|
188
|
-
}
|
|
189
|
-
if (!existsSync(sessionFile)) {
|
|
190
|
-
throw new Error("Nothing to export yet - start a conversation first");
|
|
191
|
-
}
|
|
123
|
+
if (!sessionFile) throw new Error("Cannot export in-memory session to HTML");
|
|
124
|
+
if (!existsSync(sessionFile)) throw new Error("Nothing to export yet - start a conversation first");
|
|
192
125
|
|
|
193
126
|
const sessionData: SessionData = {
|
|
194
127
|
header: sm.getHeader(),
|
|
@@ -198,46 +131,28 @@ export function exportSessionToHtml(sm: SessionManager, state?: AgentState, opti
|
|
|
198
131
|
tools: state?.tools?.map((t) => ({ name: t.name, description: t.description })),
|
|
199
132
|
};
|
|
200
133
|
|
|
201
|
-
const html = generateHtml(sessionData, opts.themeName);
|
|
202
|
-
|
|
203
|
-
let outputPath = opts.outputPath;
|
|
204
|
-
if (!outputPath) {
|
|
205
|
-
const sessionBasename = basename(sessionFile, ".jsonl");
|
|
206
|
-
outputPath = `${APP_NAME}-session-${sessionBasename}.html`;
|
|
207
|
-
}
|
|
134
|
+
const html = await generateHtml(sessionData, opts.themeName);
|
|
135
|
+
const outputPath = opts.outputPath || `${APP_NAME}-session-${basename(sessionFile, ".jsonl")}.html`;
|
|
208
136
|
|
|
209
137
|
writeFileSync(outputPath, html, "utf8");
|
|
210
138
|
return outputPath;
|
|
211
139
|
}
|
|
212
140
|
|
|
213
|
-
/**
|
|
214
|
-
|
|
215
|
-
* Used by CLI for exporting arbitrary session files.
|
|
216
|
-
*/
|
|
217
|
-
export function exportFromFile(inputPath: string, options?: ExportOptions | string): string {
|
|
141
|
+
/** Export session file to HTML (standalone). */
|
|
142
|
+
export async function exportFromFile(inputPath: string, options?: ExportOptions | string): Promise<string> {
|
|
218
143
|
const opts: ExportOptions = typeof options === "string" ? { outputPath: options } : options || {};
|
|
219
144
|
|
|
220
|
-
if (!existsSync(inputPath)) {
|
|
221
|
-
throw new Error(`File not found: ${inputPath}`);
|
|
222
|
-
}
|
|
145
|
+
if (!existsSync(inputPath)) throw new Error(`File not found: ${inputPath}`);
|
|
223
146
|
|
|
224
147
|
const sm = SessionManager.open(inputPath);
|
|
225
|
-
|
|
226
148
|
const sessionData: SessionData = {
|
|
227
149
|
header: sm.getHeader(),
|
|
228
150
|
entries: sm.getEntries(),
|
|
229
151
|
leafId: sm.getLeafId(),
|
|
230
|
-
systemPrompt: undefined,
|
|
231
|
-
tools: undefined,
|
|
232
152
|
};
|
|
233
153
|
|
|
234
|
-
const html = generateHtml(sessionData, opts.themeName);
|
|
235
|
-
|
|
236
|
-
let outputPath = opts.outputPath;
|
|
237
|
-
if (!outputPath) {
|
|
238
|
-
const inputBasename = basename(inputPath, ".jsonl");
|
|
239
|
-
outputPath = `${APP_NAME}-session-${inputBasename}.html`;
|
|
240
|
-
}
|
|
154
|
+
const html = await generateHtml(sessionData, opts.themeName);
|
|
155
|
+
const outputPath = opts.outputPath || `${APP_NAME}-session-${basename(inputPath, ".jsonl")}.html`;
|
|
241
156
|
|
|
242
157
|
writeFileSync(outputPath, html, "utf8");
|
|
243
158
|
return outputPath;
|
|
@@ -4,9 +4,8 @@
|
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<title>Session Export</title>
|
|
7
|
-
<
|
|
8
|
-
|
|
9
|
-
</style>
|
|
7
|
+
<template-css/>
|
|
8
|
+
<theme-vars/>
|
|
10
9
|
</head>
|
|
11
10
|
<body>
|
|
12
11
|
<button id="hamburger" title="Open sidebar"><svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor" stroke="none"><circle cx="6" cy="6" r="2.5"/><circle cx="6" cy="18" r="2.5"/><circle cx="18" cy="12" r="2.5"/><rect x="5" y="6" width="2" height="12"/><path d="M6 12h10c1 0 2 0 2-2V8"/></svg></button>
|
|
@@ -41,6 +40,6 @@
|
|
|
41
40
|
<script id="session-data" type="application/json">{{SESSION_DATA}}</script>
|
|
42
41
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/15.0.4/marked.min.js" integrity="sha512-VmLxPVdDGeR+F0DzUHVqzHwaR4ZSSh1g/7aYXwKT1PAGVxunOEcysta+4H5Utvmpr2xExEPybZ8q+iM9F1tGdw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
|
43
42
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js" integrity="sha512-D9gUyxqja7hBtkWpPWGt9wfbfaMGVt9gnyCvYa+jojwwPHLCzUm5i8rpk7vD7wNee9bA35eYIjobYPaQuKS1MQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
|
|
44
|
-
<
|
|
43
|
+
<template-js/>
|
|
45
44
|
</body>
|
|
46
45
|
</html>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bun macro that inlines HTML template with CSS/JS at compile time.
|
|
3
|
+
* This runs during `bun build` and embeds the result as a string.
|
|
4
|
+
*/
|
|
5
|
+
export async function getTemplate(): Promise<string> {
|
|
6
|
+
const dir = new URL(".", import.meta.url).pathname;
|
|
7
|
+
|
|
8
|
+
// Read all files
|
|
9
|
+
const html = await Bun.file(`${dir}template.html`).text();
|
|
10
|
+
const css = await Bun.file(`${dir}template.css`).text();
|
|
11
|
+
const js = await Bun.file(`${dir}template.js`).text();
|
|
12
|
+
|
|
13
|
+
// Minify CSS
|
|
14
|
+
const minifiedCss = css
|
|
15
|
+
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
16
|
+
.replace(/\s+/g, " ")
|
|
17
|
+
.replace(/\s*([{}:;,])\s*/g, "$1")
|
|
18
|
+
.trim();
|
|
19
|
+
|
|
20
|
+
// Inline everything
|
|
21
|
+
return html
|
|
22
|
+
.replace("<template-css/>", `<style>${minifiedCss}</style>`)
|
|
23
|
+
.replace("<template-js/>", `<script>${js}</script>`);
|
|
24
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auto-read file mentions from user prompts.
|
|
3
|
+
*
|
|
4
|
+
* When users reference files with @path syntax (e.g., "@src/foo.ts"),
|
|
5
|
+
* we automatically inject the file contents as a FileMentionMessage
|
|
6
|
+
* so the agent doesn't need to read them manually.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
10
|
+
import type { FileMentionMessage } from "./messages";
|
|
11
|
+
import { createReadTool } from "./tools/read";
|
|
12
|
+
|
|
13
|
+
/** Regex to match @filepath patterns in text */
|
|
14
|
+
const FILE_MENTION_REGEX = /@((?:[^\s@]+\/)*[^\s@]+\.[a-zA-Z0-9]+)/g;
|
|
15
|
+
|
|
16
|
+
/** Extract all @filepath mentions from text */
|
|
17
|
+
export function extractFileMentions(text: string): string[] {
|
|
18
|
+
const matches = [...text.matchAll(FILE_MENTION_REGEX)];
|
|
19
|
+
return [...new Set(matches.map((m) => m[1]))];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Generate a FileMentionMessage containing the contents of mentioned files.
|
|
24
|
+
* Returns empty array if no files could be read.
|
|
25
|
+
*/
|
|
26
|
+
export async function generateFileMentionMessages(filePaths: string[], cwd: string): Promise<AgentMessage[]> {
|
|
27
|
+
if (filePaths.length === 0) return [];
|
|
28
|
+
|
|
29
|
+
const readTool = createReadTool(cwd);
|
|
30
|
+
const files: FileMentionMessage["files"] = [];
|
|
31
|
+
|
|
32
|
+
for (const filePath of filePaths) {
|
|
33
|
+
try {
|
|
34
|
+
const result = await readTool.execute("auto-read", { path: filePath });
|
|
35
|
+
const textContent = result.content.find((c) => c.type === "text");
|
|
36
|
+
if (textContent && textContent.type === "text") {
|
|
37
|
+
const lineCount = textContent.text.split("\n").length;
|
|
38
|
+
files.push({ path: filePath, content: textContent.text, lineCount });
|
|
39
|
+
}
|
|
40
|
+
} catch {
|
|
41
|
+
// File doesn't exist or isn't readable - skip silently
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (files.length === 0) return [];
|
|
46
|
+
|
|
47
|
+
const message: FileMentionMessage = {
|
|
48
|
+
role: "fileMention",
|
|
49
|
+
files,
|
|
50
|
+
timestamp: Date.now(),
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
return [message];
|
|
54
|
+
}
|
package/src/core/hooks/index.ts
CHANGED
|
@@ -9,8 +9,8 @@ export {
|
|
|
9
9
|
type NavigateTreeHandler,
|
|
10
10
|
type NewSessionHandler,
|
|
11
11
|
type SendMessageHandler,
|
|
12
|
-
} from "./loader
|
|
13
|
-
export { execCommand, HookRunner, type HookErrorListener } from "./runner
|
|
14
|
-
export { wrapToolsWithHooks, wrapToolWithHooks } from "./tool-wrapper
|
|
15
|
-
export * from "./types
|
|
16
|
-
export type { ReadonlySessionManager } from "../session-manager
|
|
12
|
+
} from "./loader";
|
|
13
|
+
export { execCommand, HookRunner, type HookErrorListener } from "./runner";
|
|
14
|
+
export { wrapToolsWithHooks, wrapToolWithHooks } from "./tool-wrapper";
|
|
15
|
+
export * from "./types";
|
|
16
|
+
export type { ReadonlySessionManager } from "../session-manager";
|
package/src/core/hooks/loader.ts
CHANGED
|
@@ -6,13 +6,14 @@ import * as fs from "node:fs";
|
|
|
6
6
|
import * as os from "node:os";
|
|
7
7
|
import * as path from "node:path";
|
|
8
8
|
import * as typebox from "@sinclair/typebox";
|
|
9
|
-
import { getAgentDir } from "../../config
|
|
10
|
-
import * as piCodingAgent from "../../index
|
|
11
|
-
import
|
|
12
|
-
import {
|
|
13
|
-
import
|
|
14
|
-
import {
|
|
15
|
-
import
|
|
9
|
+
import { getAgentDir } from "../../config";
|
|
10
|
+
import * as piCodingAgent from "../../index";
|
|
11
|
+
import { logger } from "../logger";
|
|
12
|
+
import type { HookMessage } from "../messages";
|
|
13
|
+
import { getAllPluginHookPaths } from "../plugins/loader";
|
|
14
|
+
import type { SessionManager } from "../session-manager";
|
|
15
|
+
import { execCommand } from "./runner";
|
|
16
|
+
import type { ExecOptions, HookAPI, HookFactory, HookMessageRenderer, RegisteredCommand } from "./types";
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Generic handler function type.
|
|
@@ -131,12 +132,8 @@ function createHookAPI(
|
|
|
131
132
|
setSendMessageHandler: (handler: SendMessageHandler) => void;
|
|
132
133
|
setAppendEntryHandler: (handler: AppendEntryHandler) => void;
|
|
133
134
|
} {
|
|
134
|
-
let sendMessageHandler: SendMessageHandler
|
|
135
|
-
|
|
136
|
-
};
|
|
137
|
-
let appendEntryHandler: AppendEntryHandler = () => {
|
|
138
|
-
// Default no-op until mode sets the handler
|
|
139
|
-
};
|
|
135
|
+
let sendMessageHandler: SendMessageHandler | null = null;
|
|
136
|
+
let appendEntryHandler: AppendEntryHandler | null = null;
|
|
140
137
|
const messageRenderers = new Map<string, HookMessageRenderer>();
|
|
141
138
|
const commands = new Map<string, RegisteredCommand>();
|
|
142
139
|
|
|
@@ -144,14 +141,21 @@ function createHookAPI(
|
|
|
144
141
|
// but the interface has specific overloads for type safety in hooks
|
|
145
142
|
const api = {
|
|
146
143
|
on(event: string, handler: HandlerFn): void {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
144
|
+
if (!handlers.has(event)) {
|
|
145
|
+
handlers.set(event, []);
|
|
146
|
+
}
|
|
147
|
+
handlers.get(event)!.push(handler);
|
|
150
148
|
},
|
|
151
149
|
sendMessage<T = unknown>(message: HookMessage<T>, triggerTurn?: boolean): void {
|
|
150
|
+
if (!sendMessageHandler) {
|
|
151
|
+
throw new Error("sendMessage handler not initialized");
|
|
152
|
+
}
|
|
152
153
|
sendMessageHandler(message, triggerTurn);
|
|
153
154
|
},
|
|
154
155
|
appendEntry<T = unknown>(customType: string, data?: T): void {
|
|
156
|
+
if (!appendEntryHandler) {
|
|
157
|
+
throw new Error("appendEntry handler not initialized");
|
|
158
|
+
}
|
|
155
159
|
appendEntryHandler(customType, data);
|
|
156
160
|
},
|
|
157
161
|
registerMessageRenderer<T = unknown>(customType: string, renderer: HookMessageRenderer<T>): void {
|
|
@@ -163,6 +167,7 @@ function createHookAPI(
|
|
|
163
167
|
exec(command: string, args: string[], options?: ExecOptions) {
|
|
164
168
|
return execCommand(command, args, options?.cwd ?? cwd, options);
|
|
165
169
|
},
|
|
170
|
+
logger,
|
|
166
171
|
typebox,
|
|
167
172
|
pi: piCodingAgent,
|
|
168
173
|
} as HookAPI;
|
package/src/core/hooks/runner.ts
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
6
6
|
import type { Model } from "@oh-my-pi/pi-ai";
|
|
7
|
-
import { theme } from "../../modes/interactive/theme/theme
|
|
8
|
-
import type { ModelRegistry } from "../model-registry
|
|
9
|
-
import type { SessionManager } from "../session-manager
|
|
7
|
+
import { theme } from "../../modes/interactive/theme/theme";
|
|
8
|
+
import type { ModelRegistry } from "../model-registry";
|
|
9
|
+
import type { SessionManager } from "../session-manager";
|
|
10
10
|
import type {
|
|
11
11
|
AppendEntryHandler,
|
|
12
12
|
BranchHandler,
|
|
@@ -14,7 +14,7 @@ import type {
|
|
|
14
14
|
NavigateTreeHandler,
|
|
15
15
|
NewSessionHandler,
|
|
16
16
|
SendMessageHandler,
|
|
17
|
-
} from "./loader
|
|
17
|
+
} from "./loader";
|
|
18
18
|
import type {
|
|
19
19
|
BeforeAgentStartEvent,
|
|
20
20
|
BeforeAgentStartEventResult,
|
|
@@ -32,7 +32,7 @@ import type {
|
|
|
32
32
|
ToolCallEvent,
|
|
33
33
|
ToolCallEventResult,
|
|
34
34
|
ToolResultEventResult,
|
|
35
|
-
} from "./types
|
|
35
|
+
} from "./types";
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
38
|
* Listener for hook errors.
|
|
@@ -40,7 +40,7 @@ import type {
|
|
|
40
40
|
export type HookErrorListener = (error: HookError) => void;
|
|
41
41
|
|
|
42
42
|
// Re-export execCommand for backward compatibility
|
|
43
|
-
export { execCommand } from "../exec
|
|
43
|
+
export { execCommand } from "../exec";
|
|
44
44
|
|
|
45
45
|
/** No-op UI context used when no UI is available */
|
|
46
46
|
const noOpUIContext: HookUIContext = {
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import type { AgentTool, AgentToolContext, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
6
|
-
import type { HookRunner } from "./runner
|
|
7
|
-
import type { ToolCallEventResult, ToolResultEventResult } from "./types
|
|
6
|
+
import type { HookRunner } from "./runner";
|
|
7
|
+
import type { ToolCallEventResult, ToolResultEventResult } from "./types";
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Wrap a tool with hook callbacks.
|
package/src/core/hooks/types.ts
CHANGED
|
@@ -8,30 +8,25 @@
|
|
|
8
8
|
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
9
9
|
import type { ImageContent, Message, Model, TextContent, ToolResultMessage } from "@oh-my-pi/pi-ai";
|
|
10
10
|
import type { Component, TUI } from "@oh-my-pi/pi-tui";
|
|
11
|
-
import type { Theme } from "../../modes/interactive/theme/theme
|
|
12
|
-
import type { CompactionPreparation, CompactionResult } from "../compaction/index
|
|
13
|
-
import type { ExecOptions, ExecResult } from "../exec
|
|
14
|
-
import type {
|
|
15
|
-
import type {
|
|
11
|
+
import type { Theme } from "../../modes/interactive/theme/theme";
|
|
12
|
+
import type { CompactionPreparation, CompactionResult } from "../compaction/index";
|
|
13
|
+
import type { ExecOptions, ExecResult } from "../exec";
|
|
14
|
+
import type { Logger } from "../logger";
|
|
15
|
+
import type { HookMessage } from "../messages";
|
|
16
|
+
import type { ModelRegistry } from "../model-registry";
|
|
16
17
|
import type {
|
|
17
18
|
BranchSummaryEntry,
|
|
18
19
|
CompactionEntry,
|
|
19
20
|
ReadonlySessionManager,
|
|
20
21
|
SessionEntry,
|
|
21
22
|
SessionManager,
|
|
22
|
-
} from "../session-manager
|
|
23
|
+
} from "../session-manager";
|
|
23
24
|
|
|
24
|
-
import type { EditToolDetails } from "../tools/edit
|
|
25
|
-
import type {
|
|
26
|
-
BashToolDetails,
|
|
27
|
-
FindToolDetails,
|
|
28
|
-
GrepToolDetails,
|
|
29
|
-
LsToolDetails,
|
|
30
|
-
ReadToolDetails,
|
|
31
|
-
} from "../tools/index.js";
|
|
25
|
+
import type { EditToolDetails } from "../tools/edit";
|
|
26
|
+
import type { BashToolDetails, FindToolDetails, GrepToolDetails, LsToolDetails, ReadToolDetails } from "../tools/index";
|
|
32
27
|
|
|
33
28
|
// Re-export for backward compatibility
|
|
34
|
-
export type { ExecOptions, ExecResult } from "../exec
|
|
29
|
+
export type { ExecOptions, ExecResult } from "../exec";
|
|
35
30
|
|
|
36
31
|
/**
|
|
37
32
|
* UI context for hooks to request interactive UI from the harness.
|
|
@@ -747,6 +742,8 @@ export interface HookAPI {
|
|
|
747
742
|
*/
|
|
748
743
|
exec(command: string, args: string[], options?: ExecOptions): Promise<ExecResult>;
|
|
749
744
|
|
|
745
|
+
/** File logger for error/warning/debug messages */
|
|
746
|
+
logger: Logger;
|
|
750
747
|
/** Injected @sinclair/typebox module */
|
|
751
748
|
typebox: typeof import("@sinclair/typebox");
|
|
752
749
|
/** Injected pi-coding-agent exports */
|
package/src/core/index.ts
CHANGED
|
@@ -10,9 +10,9 @@ export {
|
|
|
10
10
|
type ModelCycleResult,
|
|
11
11
|
type PromptOptions,
|
|
12
12
|
type SessionStats,
|
|
13
|
-
} from "./agent-session
|
|
14
|
-
export { type BashExecutorOptions, type BashResult, executeBash } from "./bash-executor
|
|
15
|
-
export type { CompactionResult } from "./compaction/index
|
|
13
|
+
} from "./agent-session";
|
|
14
|
+
export { type BashExecutorOptions, type BashResult, executeBash } from "./bash-executor";
|
|
15
|
+
export type { CompactionResult } from "./compaction/index";
|
|
16
16
|
export {
|
|
17
17
|
type CustomTool,
|
|
18
18
|
type CustomToolAPI,
|
|
@@ -24,7 +24,7 @@ export {
|
|
|
24
24
|
type LoadedCustomTool,
|
|
25
25
|
loadCustomTools,
|
|
26
26
|
type RenderResultOptions,
|
|
27
|
-
} from "./custom-tools/index
|
|
27
|
+
} from "./custom-tools/index";
|
|
28
28
|
export {
|
|
29
29
|
type HookAPI,
|
|
30
30
|
type HookContext,
|
|
@@ -34,7 +34,7 @@ export {
|
|
|
34
34
|
HookRunner,
|
|
35
35
|
type HookUIContext,
|
|
36
36
|
loadHooks,
|
|
37
|
-
} from "./hooks/index
|
|
37
|
+
} from "./hooks/index";
|
|
38
38
|
export {
|
|
39
39
|
createMCPManager,
|
|
40
40
|
discoverAndLoadMCPTools,
|
|
@@ -49,4 +49,4 @@ export {
|
|
|
49
49
|
type MCPToolDetails,
|
|
50
50
|
type MCPToolsLoadResult,
|
|
51
51
|
type MCPTransport,
|
|
52
|
-
} from "./mcp/index
|
|
52
|
+
} from "./mcp/index";
|