@oh-my-pi/pi-coding-agent 1.338.0 → 1.341.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 +60 -1
- package/package.json +3 -3
- package/src/cli/args.ts +8 -0
- package/src/core/agent-session.ts +32 -14
- package/src/core/export-html/index.ts +48 -15
- package/src/core/export-html/template.html +3 -11
- package/src/core/mcp/client.ts +43 -16
- package/src/core/mcp/config.ts +152 -6
- package/src/core/mcp/index.ts +6 -2
- package/src/core/mcp/loader.ts +30 -3
- package/src/core/mcp/manager.ts +69 -10
- package/src/core/mcp/types.ts +9 -3
- package/src/core/model-resolver.ts +101 -0
- package/src/core/sdk.ts +65 -18
- package/src/core/session-manager.ts +117 -14
- package/src/core/settings-manager.ts +107 -19
- package/src/core/title-generator.ts +94 -0
- package/src/core/tools/bash.ts +1 -2
- package/src/core/tools/edit-diff.ts +2 -2
- package/src/core/tools/edit.ts +43 -5
- package/src/core/tools/grep.ts +3 -2
- package/src/core/tools/index.ts +73 -13
- package/src/core/tools/lsp/client.ts +45 -20
- package/src/core/tools/lsp/config.ts +708 -34
- package/src/core/tools/lsp/index.ts +423 -23
- package/src/core/tools/lsp/types.ts +5 -0
- package/src/core/tools/task/bundled-agents/explore.md +1 -1
- package/src/core/tools/task/bundled-agents/reviewer.md +1 -1
- package/src/core/tools/task/model-resolver.ts +52 -3
- package/src/core/tools/write.ts +67 -4
- package/src/index.ts +5 -0
- package/src/main.ts +23 -2
- package/src/modes/interactive/components/model-selector.ts +96 -18
- package/src/modes/interactive/components/session-selector.ts +20 -7
- package/src/modes/interactive/components/settings-defs.ts +59 -2
- package/src/modes/interactive/components/settings-selector.ts +8 -11
- package/src/modes/interactive/components/tool-execution.ts +18 -0
- package/src/modes/interactive/components/tree-selector.ts +2 -2
- package/src/modes/interactive/components/welcome.ts +40 -3
- package/src/modes/interactive/interactive-mode.ts +87 -10
- package/src/core/export-html/vendor/highlight.min.js +0 -1213
- package/src/core/export-html/vendor/marked.min.js +0 -6
package/src/core/tools/index.ts
CHANGED
|
@@ -1,13 +1,25 @@
|
|
|
1
1
|
export { type AskToolDetails, askTool, createAskTool } from "./ask.js";
|
|
2
2
|
export { type BashToolDetails, bashTool, createBashTool } from "./bash.js";
|
|
3
|
-
export { createEditTool, editTool } from "./edit.js";
|
|
3
|
+
export { createEditTool, type EditToolOptions, editTool } from "./edit.js";
|
|
4
4
|
// Exa MCP tools (22 tools)
|
|
5
5
|
export { exaTools } from "./exa/index.js";
|
|
6
6
|
export type { ExaRenderDetails, ExaSearchResponse, ExaSearchResult } from "./exa/types.js";
|
|
7
7
|
export { createFindTool, type FindToolDetails, findTool } from "./find.js";
|
|
8
8
|
export { createGrepTool, type GrepToolDetails, grepTool } from "./grep.js";
|
|
9
9
|
export { createLsTool, type LsToolDetails, lsTool } from "./ls.js";
|
|
10
|
-
export {
|
|
10
|
+
export {
|
|
11
|
+
createLspTool,
|
|
12
|
+
type FileDiagnosticsResult,
|
|
13
|
+
type FileFormatResult,
|
|
14
|
+
formatFile,
|
|
15
|
+
getDiagnosticsForFile,
|
|
16
|
+
getLspStatus,
|
|
17
|
+
type LspServerStatus,
|
|
18
|
+
type LspToolDetails,
|
|
19
|
+
type LspWarmupResult,
|
|
20
|
+
lspTool,
|
|
21
|
+
warmupLspServers,
|
|
22
|
+
} from "./lsp/index.js";
|
|
11
23
|
export { createNotebookTool, type NotebookToolDetails, notebookTool } from "./notebook.js";
|
|
12
24
|
export { createReadTool, type ReadToolDetails, readTool } from "./read.js";
|
|
13
25
|
export { BUNDLED_AGENTS, createTaskTool, taskTool } from "./task/index.js";
|
|
@@ -31,7 +43,7 @@ export {
|
|
|
31
43
|
webSearchLinkedinTool,
|
|
32
44
|
webSearchTool,
|
|
33
45
|
} from "./web-search/index.js";
|
|
34
|
-
export { createWriteTool, writeTool } from "./write.js";
|
|
46
|
+
export { createWriteTool, type WriteToolDetails, type WriteToolOptions, writeTool } from "./write.js";
|
|
35
47
|
|
|
36
48
|
import type { AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
37
49
|
import { askTool, createAskTool } from "./ask.js";
|
|
@@ -41,7 +53,7 @@ import { createEditTool, editTool } from "./edit.js";
|
|
|
41
53
|
import { createFindTool, findTool } from "./find.js";
|
|
42
54
|
import { createGrepTool, grepTool } from "./grep.js";
|
|
43
55
|
import { createLsTool, lsTool } from "./ls.js";
|
|
44
|
-
import { createLspTool, lspTool } from "./lsp/index.js";
|
|
56
|
+
import { createLspTool, formatFile, getDiagnosticsForFile, lspTool } from "./lsp/index.js";
|
|
45
57
|
import { createNotebookTool, notebookTool } from "./notebook.js";
|
|
46
58
|
import { createReadTool, readTool } from "./read.js";
|
|
47
59
|
import { createTaskTool, taskTool } from "./task/index.js";
|
|
@@ -57,16 +69,47 @@ export interface SessionContext {
|
|
|
57
69
|
getSessionFile: () => string | null;
|
|
58
70
|
}
|
|
59
71
|
|
|
72
|
+
/** Options for creating coding tools */
|
|
73
|
+
export interface CodingToolsOptions {
|
|
74
|
+
/** Whether to fetch LSP diagnostics after write tool writes files (default: true) */
|
|
75
|
+
lspDiagnosticsOnWrite?: boolean;
|
|
76
|
+
/** Whether to fetch LSP diagnostics after edit tool edits files (default: false) */
|
|
77
|
+
lspDiagnosticsOnEdit?: boolean;
|
|
78
|
+
/** Whether to format files using LSP after write tool writes (default: true) */
|
|
79
|
+
lspFormatOnWrite?: boolean;
|
|
80
|
+
/** Whether to accept high-confidence fuzzy matches in edit tool (default: true) */
|
|
81
|
+
editFuzzyMatch?: boolean;
|
|
82
|
+
}
|
|
83
|
+
|
|
60
84
|
// Factory function type
|
|
61
|
-
type ToolFactory = (cwd: string, sessionContext?: SessionContext) => Tool;
|
|
85
|
+
type ToolFactory = (cwd: string, sessionContext?: SessionContext, options?: CodingToolsOptions) => Tool;
|
|
62
86
|
|
|
63
87
|
// Tool definitions: static tools and their factory functions
|
|
64
88
|
const toolDefs: Record<string, { tool: Tool; create: ToolFactory }> = {
|
|
65
89
|
ask: { tool: askTool, create: createAskTool },
|
|
66
90
|
read: { tool: readTool, create: createReadTool },
|
|
67
91
|
bash: { tool: bashTool, create: createBashTool },
|
|
68
|
-
edit: {
|
|
69
|
-
|
|
92
|
+
edit: {
|
|
93
|
+
tool: editTool,
|
|
94
|
+
create: (cwd, _ctx, options) => {
|
|
95
|
+
const enableDiagnostics = options?.lspDiagnosticsOnEdit ?? false;
|
|
96
|
+
return createEditTool(cwd, {
|
|
97
|
+
fuzzyMatch: options?.editFuzzyMatch ?? true,
|
|
98
|
+
getDiagnostics: enableDiagnostics ? (absolutePath) => getDiagnosticsForFile(absolutePath, cwd) : undefined,
|
|
99
|
+
});
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
write: {
|
|
103
|
+
tool: writeTool,
|
|
104
|
+
create: (cwd, _ctx, options) => {
|
|
105
|
+
const enableFormat = options?.lspFormatOnWrite ?? true;
|
|
106
|
+
const enableDiagnostics = options?.lspDiagnosticsOnWrite ?? true;
|
|
107
|
+
return createWriteTool(cwd, {
|
|
108
|
+
formatOnWrite: enableFormat ? (absolutePath) => formatFile(absolutePath, cwd) : undefined,
|
|
109
|
+
getDiagnostics: enableDiagnostics ? (absolutePath) => getDiagnosticsForFile(absolutePath, cwd) : undefined,
|
|
110
|
+
});
|
|
111
|
+
},
|
|
112
|
+
},
|
|
70
113
|
grep: { tool: grepTool, create: createGrepTool },
|
|
71
114
|
find: { tool: findTool, create: createFindTool },
|
|
72
115
|
ls: { tool: lsTool, create: createLsTool },
|
|
@@ -116,10 +159,16 @@ export const allTools = Object.fromEntries(Object.entries(toolDefs).map(([name,
|
|
|
116
159
|
* @param cwd - Working directory for tools
|
|
117
160
|
* @param hasUI - Whether UI is available (includes ask tool if true)
|
|
118
161
|
* @param sessionContext - Optional session context for tools that need it
|
|
162
|
+
* @param options - Options for tool configuration
|
|
119
163
|
*/
|
|
120
|
-
export function createCodingTools(
|
|
164
|
+
export function createCodingTools(
|
|
165
|
+
cwd: string,
|
|
166
|
+
hasUI = false,
|
|
167
|
+
sessionContext?: SessionContext,
|
|
168
|
+
options?: CodingToolsOptions,
|
|
169
|
+
): Tool[] {
|
|
121
170
|
const names = hasUI ? [...baseCodingToolNames, ...uiToolNames] : baseCodingToolNames;
|
|
122
|
-
return names.map((name) => toolDefs[name].create(cwd, sessionContext));
|
|
171
|
+
return names.map((name) => toolDefs[name].create(cwd, sessionContext, options));
|
|
123
172
|
}
|
|
124
173
|
|
|
125
174
|
/**
|
|
@@ -127,20 +176,31 @@ export function createCodingTools(cwd: string, hasUI = false, sessionContext?: S
|
|
|
127
176
|
* @param cwd - Working directory for tools
|
|
128
177
|
* @param hasUI - Whether UI is available (includes ask tool if true)
|
|
129
178
|
* @param sessionContext - Optional session context for tools that need it
|
|
179
|
+
* @param options - Options for tool configuration
|
|
130
180
|
*/
|
|
131
|
-
export function createReadOnlyTools(
|
|
181
|
+
export function createReadOnlyTools(
|
|
182
|
+
cwd: string,
|
|
183
|
+
hasUI = false,
|
|
184
|
+
sessionContext?: SessionContext,
|
|
185
|
+
options?: CodingToolsOptions,
|
|
186
|
+
): Tool[] {
|
|
132
187
|
const names = hasUI ? [...baseReadOnlyToolNames, ...uiToolNames] : baseReadOnlyToolNames;
|
|
133
|
-
return names.map((name) => toolDefs[name].create(cwd, sessionContext));
|
|
188
|
+
return names.map((name) => toolDefs[name].create(cwd, sessionContext, options));
|
|
134
189
|
}
|
|
135
190
|
|
|
136
191
|
/**
|
|
137
192
|
* Create all tools configured for a specific working directory.
|
|
138
193
|
* @param cwd - Working directory for tools
|
|
139
194
|
* @param sessionContext - Optional session context for tools that need it
|
|
195
|
+
* @param options - Options for tool configuration
|
|
140
196
|
*/
|
|
141
|
-
export function createAllTools(
|
|
197
|
+
export function createAllTools(
|
|
198
|
+
cwd: string,
|
|
199
|
+
sessionContext?: SessionContext,
|
|
200
|
+
options?: CodingToolsOptions,
|
|
201
|
+
): Record<ToolName, Tool> {
|
|
142
202
|
return Object.fromEntries(
|
|
143
|
-
Object.entries(toolDefs).map(([name, def]) => [name, def.create(cwd, sessionContext)]),
|
|
203
|
+
Object.entries(toolDefs).map(([name, def]) => [name, def.create(cwd, sessionContext, options)]),
|
|
144
204
|
) as Record<ToolName, Tool>;
|
|
145
205
|
}
|
|
146
206
|
|
|
@@ -17,20 +17,32 @@ import { detectLanguageId, fileToUri } from "./utils.js";
|
|
|
17
17
|
|
|
18
18
|
const clients = new Map<string, LspClient>();
|
|
19
19
|
|
|
20
|
-
// Idle timeout
|
|
21
|
-
|
|
20
|
+
// Idle timeout configuration (disabled by default)
|
|
21
|
+
let idleTimeoutMs: number | null = null;
|
|
22
|
+
let idleCheckInterval: Timer | null = null;
|
|
22
23
|
const IDLE_CHECK_INTERVAL_MS = 60 * 1000;
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Configure the idle timeout for LSP clients.
|
|
27
|
+
* @param ms - Timeout in milliseconds, or null/undefined to disable
|
|
28
|
+
*/
|
|
29
|
+
export function setIdleTimeout(ms: number | null | undefined): void {
|
|
30
|
+
idleTimeoutMs = ms ?? null;
|
|
31
|
+
|
|
32
|
+
if (idleTimeoutMs && idleTimeoutMs > 0) {
|
|
33
|
+
startIdleChecker();
|
|
34
|
+
} else {
|
|
35
|
+
stopIdleChecker();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
26
38
|
|
|
27
39
|
function startIdleChecker(): void {
|
|
28
40
|
if (idleCheckInterval) return;
|
|
29
41
|
idleCheckInterval = setInterval(() => {
|
|
42
|
+
if (!idleTimeoutMs) return;
|
|
30
43
|
const now = Date.now();
|
|
31
44
|
for (const [key, client] of Array.from(clients.entries())) {
|
|
32
|
-
if (now - client.lastActivity >
|
|
33
|
-
console.log(`[LSP] Shutting down idle client: ${key}`);
|
|
45
|
+
if (now - client.lastActivity > idleTimeoutMs) {
|
|
34
46
|
shutdownClient(key);
|
|
35
47
|
}
|
|
36
48
|
}
|
|
@@ -98,6 +110,12 @@ const CLIENT_CAPABILITIES = {
|
|
|
98
110
|
properties: ["edit"],
|
|
99
111
|
},
|
|
100
112
|
},
|
|
113
|
+
formatting: {
|
|
114
|
+
dynamicRegistration: false,
|
|
115
|
+
},
|
|
116
|
+
rangeFormatting: {
|
|
117
|
+
dynamicRegistration: false,
|
|
118
|
+
},
|
|
101
119
|
publishDiagnostics: {
|
|
102
120
|
relatedInformation: true,
|
|
103
121
|
versionSupport: false,
|
|
@@ -357,7 +375,8 @@ export async function getOrCreateClient(config: ServerConfig, cwd: string): Prom
|
|
|
357
375
|
}
|
|
358
376
|
|
|
359
377
|
const args = config.args ?? [];
|
|
360
|
-
const
|
|
378
|
+
const command = config.resolvedCommand ?? config.command;
|
|
379
|
+
const proc = Bun.spawn([command, ...args], {
|
|
361
380
|
cwd,
|
|
362
381
|
stdin: "pipe",
|
|
363
382
|
stdout: "pipe",
|
|
@@ -379,16 +398,9 @@ export async function getOrCreateClient(config: ServerConfig, cwd: string): Prom
|
|
|
379
398
|
};
|
|
380
399
|
clients.set(key, client);
|
|
381
400
|
|
|
382
|
-
// Start idle checker if not already running
|
|
383
|
-
startIdleChecker();
|
|
384
|
-
|
|
385
401
|
// Register crash recovery - remove client on process exit
|
|
386
402
|
proc.exited.then(() => {
|
|
387
|
-
console.log(`[LSP] Process exited: ${key}`);
|
|
388
403
|
clients.delete(key);
|
|
389
|
-
if (clients.size === 0) {
|
|
390
|
-
stopIdleChecker();
|
|
391
|
-
}
|
|
392
404
|
});
|
|
393
405
|
|
|
394
406
|
// Start background message reader
|
|
@@ -497,10 +509,6 @@ export function shutdownClient(key: string): void {
|
|
|
497
509
|
// Kill process
|
|
498
510
|
client.process.kill();
|
|
499
511
|
clients.delete(key);
|
|
500
|
-
|
|
501
|
-
if (clients.size === 0) {
|
|
502
|
-
stopIdleChecker();
|
|
503
|
-
}
|
|
504
512
|
}
|
|
505
513
|
|
|
506
514
|
// =============================================================================
|
|
@@ -570,8 +578,6 @@ export async function sendNotification(client: LspClient, method: string, params
|
|
|
570
578
|
* Shutdown all LSP clients.
|
|
571
579
|
*/
|
|
572
580
|
export function shutdownAll(): void {
|
|
573
|
-
stopIdleChecker();
|
|
574
|
-
|
|
575
581
|
for (const client of Array.from(clients.values())) {
|
|
576
582
|
// Reject all pending requests
|
|
577
583
|
for (const pending of Array.from(client.pendingRequests.values())) {
|
|
@@ -587,6 +593,25 @@ export function shutdownAll(): void {
|
|
|
587
593
|
clients.clear();
|
|
588
594
|
}
|
|
589
595
|
|
|
596
|
+
/** Status of an LSP server */
|
|
597
|
+
export interface LspServerStatus {
|
|
598
|
+
name: string;
|
|
599
|
+
status: "connecting" | "ready" | "error";
|
|
600
|
+
fileTypes: string[];
|
|
601
|
+
error?: string;
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
/**
|
|
605
|
+
* Get status of all active LSP clients.
|
|
606
|
+
*/
|
|
607
|
+
export function getActiveClients(): LspServerStatus[] {
|
|
608
|
+
return Array.from(clients.values()).map((client) => ({
|
|
609
|
+
name: client.config.command,
|
|
610
|
+
status: "ready" as const,
|
|
611
|
+
fileTypes: client.config.fileTypes,
|
|
612
|
+
}));
|
|
613
|
+
}
|
|
614
|
+
|
|
590
615
|
// =============================================================================
|
|
591
616
|
// Process Cleanup
|
|
592
617
|
// =============================================================================
|