@oh-my-pi/pi-coding-agent 1.340.0 → 2.0.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.
Files changed (153) hide show
  1. package/CHANGELOG.md +115 -1
  2. package/README.md +1 -1
  3. package/examples/custom-tools/subagent/index.ts +1 -1
  4. package/package.json +5 -3
  5. package/src/cli/args.ts +13 -6
  6. package/src/cli/file-processor.ts +3 -3
  7. package/src/cli/list-models.ts +2 -2
  8. package/src/cli/plugin-cli.ts +1 -1
  9. package/src/cli/session-picker.ts +2 -2
  10. package/src/cli.ts +1 -1
  11. package/src/config.ts +3 -3
  12. package/src/core/agent-session.ts +189 -29
  13. package/src/core/bash-executor.ts +50 -10
  14. package/src/core/compaction/branch-summarization.ts +5 -5
  15. package/src/core/compaction/compaction.ts +3 -3
  16. package/src/core/compaction/index.ts +3 -3
  17. package/src/core/custom-commands/bundled/review/index.ts +156 -0
  18. package/src/core/custom-commands/index.ts +15 -0
  19. package/src/core/custom-commands/loader.ts +232 -0
  20. package/src/core/custom-commands/types.ts +112 -0
  21. package/src/core/custom-tools/index.ts +3 -3
  22. package/src/core/custom-tools/loader.ts +10 -8
  23. package/src/core/custom-tools/types.ts +11 -6
  24. package/src/core/custom-tools/wrapper.ts +2 -1
  25. package/src/core/exec.ts +22 -12
  26. package/src/core/export-html/index.ts +5 -5
  27. package/src/core/file-mentions.ts +54 -0
  28. package/src/core/hooks/index.ts +5 -5
  29. package/src/core/hooks/loader.ts +21 -16
  30. package/src/core/hooks/runner.ts +6 -6
  31. package/src/core/hooks/tool-wrapper.ts +2 -2
  32. package/src/core/hooks/types.ts +12 -15
  33. package/src/core/index.ts +6 -6
  34. package/src/core/logger.ts +112 -0
  35. package/src/core/mcp/client.ts +3 -3
  36. package/src/core/mcp/config.ts +1 -1
  37. package/src/core/mcp/index.ts +12 -12
  38. package/src/core/mcp/loader.ts +2 -2
  39. package/src/core/mcp/manager.ts +6 -6
  40. package/src/core/mcp/tool-bridge.ts +3 -3
  41. package/src/core/mcp/transports/http.ts +1 -1
  42. package/src/core/mcp/transports/index.ts +2 -2
  43. package/src/core/mcp/transports/stdio.ts +1 -1
  44. package/src/core/messages.ts +22 -0
  45. package/src/core/model-registry.ts +2 -2
  46. package/src/core/model-resolver.ts +103 -2
  47. package/src/core/plugins/doctor.ts +1 -1
  48. package/src/core/plugins/index.ts +6 -6
  49. package/src/core/plugins/installer.ts +4 -4
  50. package/src/core/plugins/loader.ts +4 -9
  51. package/src/core/plugins/manager.ts +5 -5
  52. package/src/core/plugins/paths.ts +3 -3
  53. package/src/core/sdk.ts +127 -52
  54. package/src/core/session-manager.ts +123 -20
  55. package/src/core/settings-manager.ts +106 -22
  56. package/src/core/skills.ts +5 -5
  57. package/src/core/slash-commands.ts +60 -45
  58. package/src/core/system-prompt.ts +6 -6
  59. package/src/core/title-generator.ts +94 -0
  60. package/src/core/tools/bash.ts +33 -157
  61. package/src/core/tools/context.ts +2 -2
  62. package/src/core/tools/edit-diff.ts +5 -5
  63. package/src/core/tools/edit.ts +60 -9
  64. package/src/core/tools/exa/company.ts +3 -3
  65. package/src/core/tools/exa/index.ts +16 -17
  66. package/src/core/tools/exa/linkedin.ts +3 -3
  67. package/src/core/tools/exa/mcp-client.ts +9 -9
  68. package/src/core/tools/exa/render.ts +5 -5
  69. package/src/core/tools/exa/researcher.ts +3 -3
  70. package/src/core/tools/exa/search.ts +6 -5
  71. package/src/core/tools/exa/types.ts +5 -6
  72. package/src/core/tools/exa/websets.ts +3 -3
  73. package/src/core/tools/find.ts +3 -3
  74. package/src/core/tools/grep.ts +6 -5
  75. package/src/core/tools/index.ts +114 -40
  76. package/src/core/tools/ls.ts +4 -4
  77. package/src/core/tools/lsp/client.ts +204 -108
  78. package/src/core/tools/lsp/config.ts +709 -35
  79. package/src/core/tools/lsp/edits.ts +2 -2
  80. package/src/core/tools/lsp/index.ts +432 -30
  81. package/src/core/tools/lsp/render.ts +2 -2
  82. package/src/core/tools/lsp/rust-analyzer.ts +3 -3
  83. package/src/core/tools/lsp/types.ts +5 -0
  84. package/src/core/tools/lsp/utils.ts +1 -1
  85. package/src/core/tools/notebook.ts +1 -1
  86. package/src/core/tools/output.ts +175 -0
  87. package/src/core/tools/read.ts +7 -7
  88. package/src/core/tools/renderers.ts +92 -13
  89. package/src/core/tools/review.ts +268 -0
  90. package/src/core/tools/task/agents.ts +1 -1
  91. package/src/core/tools/task/bundled-agents/explore.md +1 -1
  92. package/src/core/tools/task/bundled-agents/reviewer.md +53 -38
  93. package/src/core/tools/task/discovery.ts +2 -2
  94. package/src/core/tools/task/executor.ts +145 -28
  95. package/src/core/tools/task/index.ts +78 -30
  96. package/src/core/tools/task/model-resolver.ts +72 -13
  97. package/src/core/tools/task/parallel.ts +1 -1
  98. package/src/core/tools/task/render.ts +219 -30
  99. package/src/core/tools/task/subprocess-tool-registry.ts +89 -0
  100. package/src/core/tools/task/types.ts +36 -2
  101. package/src/core/tools/web-fetch.ts +5 -3
  102. package/src/core/tools/web-search/auth.ts +1 -1
  103. package/src/core/tools/web-search/index.ts +17 -15
  104. package/src/core/tools/web-search/providers/anthropic.ts +2 -2
  105. package/src/core/tools/web-search/providers/exa.ts +3 -5
  106. package/src/core/tools/web-search/providers/perplexity.ts +1 -1
  107. package/src/core/tools/web-search/render.ts +3 -3
  108. package/src/core/tools/write.ts +70 -7
  109. package/src/index.ts +33 -17
  110. package/src/main.ts +60 -34
  111. package/src/migrations.ts +3 -3
  112. package/src/modes/index.ts +5 -5
  113. package/src/modes/interactive/components/armin.ts +1 -1
  114. package/src/modes/interactive/components/assistant-message.ts +1 -1
  115. package/src/modes/interactive/components/bash-execution.ts +4 -4
  116. package/src/modes/interactive/components/bordered-loader.ts +2 -2
  117. package/src/modes/interactive/components/branch-summary-message.ts +2 -2
  118. package/src/modes/interactive/components/compaction-summary-message.ts +2 -2
  119. package/src/modes/interactive/components/diff.ts +1 -1
  120. package/src/modes/interactive/components/dynamic-border.ts +1 -1
  121. package/src/modes/interactive/components/footer.ts +5 -5
  122. package/src/modes/interactive/components/hook-editor.ts +2 -2
  123. package/src/modes/interactive/components/hook-input.ts +2 -2
  124. package/src/modes/interactive/components/hook-message.ts +3 -3
  125. package/src/modes/interactive/components/hook-selector.ts +2 -2
  126. package/src/modes/interactive/components/model-selector.ts +341 -41
  127. package/src/modes/interactive/components/oauth-selector.ts +3 -3
  128. package/src/modes/interactive/components/plugin-settings.ts +4 -4
  129. package/src/modes/interactive/components/queue-mode-selector.ts +2 -2
  130. package/src/modes/interactive/components/session-selector.ts +24 -11
  131. package/src/modes/interactive/components/settings-defs.ts +51 -3
  132. package/src/modes/interactive/components/settings-selector.ts +13 -16
  133. package/src/modes/interactive/components/show-images-selector.ts +2 -2
  134. package/src/modes/interactive/components/theme-selector.ts +2 -2
  135. package/src/modes/interactive/components/thinking-selector.ts +2 -2
  136. package/src/modes/interactive/components/tool-execution.ts +44 -8
  137. package/src/modes/interactive/components/tree-selector.ts +5 -5
  138. package/src/modes/interactive/components/user-message-selector.ts +2 -2
  139. package/src/modes/interactive/components/user-message.ts +1 -1
  140. package/src/modes/interactive/components/welcome.ts +42 -5
  141. package/src/modes/interactive/interactive-mode.ts +169 -48
  142. package/src/modes/interactive/theme/theme.ts +8 -7
  143. package/src/modes/print-mode.ts +4 -3
  144. package/src/modes/rpc/rpc-client.ts +4 -4
  145. package/src/modes/rpc/rpc-mode.ts +21 -11
  146. package/src/modes/rpc/rpc-types.ts +3 -3
  147. package/src/utils/changelog.ts +2 -2
  148. package/src/utils/clipboard.ts +1 -1
  149. package/src/utils/shell-snapshot.ts +218 -0
  150. package/src/utils/shell.ts +93 -13
  151. package/src/utils/tools-manager.ts +1 -1
  152. package/examples/custom-tools/subagent/agents/reviewer.md +0 -35
  153. package/src/core/tools/exa/logger.ts +0 -56
@@ -6,10 +6,10 @@
6
6
 
7
7
  import type { Component } from "@oh-my-pi/pi-tui";
8
8
  import { Text } from "@oh-my-pi/pi-tui";
9
- import type { Theme } from "../../../modes/interactive/theme/theme.js";
10
- import type { RenderResultOptions } from "../../custom-tools/types.js";
11
- import { logViewError } from "./logger.js";
12
- import type { ExaRenderDetails } from "./types.js";
9
+ import type { Theme } from "../../../modes/interactive/theme/theme";
10
+ import type { RenderResultOptions } from "../../custom-tools/types";
11
+ import { logger } from "../../logger";
12
+ import type { ExaRenderDetails } from "./types";
13
13
 
14
14
  // Tree formatting constants
15
15
  const TREE_MID = "├─";
@@ -51,7 +51,7 @@ export function renderExaResult(
51
51
 
52
52
  // Handle error case
53
53
  if (details?.error) {
54
- logViewError("Exa render error", { error: details.error, toolName: details.toolName });
54
+ logger.error("Exa render error", { error: details.error, toolName: details.toolName });
55
55
  return new Text(theme.fg("error", `Error: ${details.error}`), 0, 0);
56
56
  }
57
57
 
@@ -5,9 +5,9 @@
5
5
  */
6
6
 
7
7
  import { Type } from "@sinclair/typebox";
8
- import type { CustomTool } from "../../custom-tools/types.js";
9
- import { callExaTool, findApiKey } from "./mcp-client.js";
10
- import type { ExaRenderDetails } from "./types.js";
8
+ import type { CustomTool } from "../../custom-tools/types";
9
+ import { callExaTool, findApiKey } from "./mcp-client";
10
+ import type { ExaRenderDetails } from "./types";
11
11
 
12
12
  const researcherStartTool: CustomTool<any, ExaRenderDetails> = {
13
13
  name: "exa_researcher_start",
@@ -5,8 +5,8 @@
5
5
  */
6
6
 
7
7
  import { Type } from "@sinclair/typebox";
8
- import type { CustomTool } from "../../custom-tools/types.js";
9
- import type { ExaRenderDetails } from "./types.js";
8
+ import type { CustomTool } from "../../custom-tools/types";
9
+ import type { ExaRenderDetails } from "./types";
10
10
 
11
11
  /** exa_search - Basic neural/keyword search */
12
12
  const exaSearchTool: CustomTool<any, ExaRenderDetails> = {
@@ -91,7 +91,7 @@ Parameters:
91
91
  details: { error: "EXA_API_KEY not found", toolName: "exa_search" },
92
92
  };
93
93
  }
94
- const response = await callExaTool("web_search", params, apiKey);
94
+ const response = await callExaTool("web_search_exa", params, apiKey);
95
95
 
96
96
  if (isSearchResponse(response)) {
97
97
  const formatted = formatSearchResults(response);
@@ -187,7 +187,8 @@ Similar parameters to exa_search, optimized for research depth.`,
187
187
  details: { error: "EXA_API_KEY not found", toolName: "exa_search_deep" },
188
188
  };
189
189
  }
190
- const response = await callExaTool("deep_search_exa", params, apiKey);
190
+ const args = { ...params, type: "deep" };
191
+ const response = await callExaTool("web_search_exa", args, apiKey);
191
192
 
192
193
  if (isSearchResponse(response)) {
193
194
  const formatted = formatSearchResults(response);
@@ -305,7 +306,7 @@ Parameters:
305
306
  details: { error: "EXA_API_KEY not found", toolName: "exa_crawl" },
306
307
  };
307
308
  }
308
- const response = await callExaTool("crawling_exa", params, apiKey);
309
+ const response = await callExaTool("crawling", params, apiKey);
309
310
 
310
311
  if (isSearchResponse(response)) {
311
312
  const formatted = formatSearchResults(response);
@@ -23,7 +23,7 @@ export interface MCPToolWrapperConfig {
23
23
  name: string;
24
24
  /** Display label for UI */
25
25
  label: string;
26
- /** MCP tool name to call (e.g., "web_search") */
26
+ /** MCP tool name to call (e.g., "web_search_exa") */
27
27
  mcpToolName: string;
28
28
  /** Whether this is a websets tool (uses different MCP endpoint) */
29
29
  isWebsetsTool?: boolean;
@@ -121,14 +121,13 @@ export interface WebsetEnrichment {
121
121
  /** Tool name mappings: MCP name -> our tool name */
122
122
  export const EXA_TOOL_MAPPINGS = {
123
123
  // Search tools
124
- web_search: "exa_search",
125
- deep_search_exa: "exa_search_deep",
124
+ web_search_exa: "exa_search",
126
125
  get_code_context_exa: "exa_search_code",
127
- crawling_exa: "exa_crawl",
126
+ crawling: "exa_crawl",
128
127
  // LinkedIn
129
- linkedin_search_exa: "exa_linkedin",
128
+ linkedin_search: "exa_linkedin",
130
129
  // Company
131
- company_research_exa: "exa_company",
130
+ company_research: "exa_company",
132
131
  // Researcher
133
132
  deep_researcher_start: "exa_researcher_start",
134
133
  deep_researcher_check: "exa_researcher_poll",
@@ -5,9 +5,9 @@
5
5
  */
6
6
 
7
7
  import { Type } from "@sinclair/typebox";
8
- import type { CustomTool } from "../../custom-tools/types.js";
9
- import { callWebsetsTool, findApiKey } from "./mcp-client.js";
10
- import type { ExaRenderDetails } from "./types.js";
8
+ import type { CustomTool } from "../../custom-tools/types";
9
+ import { callWebsetsTool, findApiKey } from "./mcp-client";
10
+ import type { ExaRenderDetails } from "./types";
11
11
 
12
12
  /** Helper to create a websets tool with proper execute signature */
13
13
  function createWebsetTool(
@@ -3,9 +3,9 @@ import path from "node:path";
3
3
  import type { AgentTool } from "@oh-my-pi/pi-agent-core";
4
4
  import { Type } from "@sinclair/typebox";
5
5
  import { globSync } from "glob";
6
- import { ensureTool } from "../../utils/tools-manager.js";
7
- import { resolveToCwd } from "./path-utils.js";
8
- import { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from "./truncate.js";
6
+ import { ensureTool } from "../../utils/tools-manager";
7
+ import { resolveToCwd } from "./path-utils";
8
+ import { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from "./truncate";
9
9
 
10
10
  const findSchema = Type.Object({
11
11
  pattern: Type.String({
@@ -3,8 +3,8 @@ import nodePath from "node:path";
3
3
  import type { AgentTool } from "@oh-my-pi/pi-agent-core";
4
4
  import { Type } from "@sinclair/typebox";
5
5
  import type { Subprocess } from "bun";
6
- import { ensureTool } from "../../utils/tools-manager.js";
7
- import { resolveToCwd } from "./path-utils.js";
6
+ import { ensureTool } from "../../utils/tools-manager";
7
+ import { resolveToCwd } from "./path-utils";
8
8
  import {
9
9
  DEFAULT_MAX_BYTES,
10
10
  formatSize,
@@ -12,7 +12,7 @@ import {
12
12
  type TruncationResult,
13
13
  truncateHead,
14
14
  truncateLine,
15
- } from "./truncate.js";
15
+ } from "./truncate";
16
16
 
17
17
  const grepSchema = Type.Object({
18
18
  pattern: Type.String({ description: "Search pattern (regex or literal string)" }),
@@ -68,10 +68,11 @@ export function createGrepTool(cwd: string): AgentTool<typeof grepSchema> {
68
68
 
69
69
  Usage:
70
70
  - ALWAYS use grep for search tasks. NEVER invoke \`grep\` or \`rg\` as a bash command. The grep tool has been optimized for correct permissions and access.
71
+ - Searches recursively by default - no need for -r flag
71
72
  - Supports full regex syntax (e.g., "log.*Error", "function\\s+\\w+")
72
- - Filter files with glob parameter (e.g., "*.js", "**/*.tsx") or type parameter (e.g., "js", "py", "rust")
73
+ - Filter files with glob parameter (e.g., "*.ts", "**/*.spec.ts") or type parameter (e.g., "ts", "py", "rust") - equivalent to grep's --include
73
74
  - Output modes: "content" shows matching lines, "files_with_matches" shows only file paths (default), "count" shows match counts
74
- - Use task tool for open-ended searches requiring multiple rounds
75
+ - Pagination: Use headLimit to limit results (like \`| head -N\`), offset to skip first N results
75
76
  - Pattern syntax: Uses ripgrep (not grep) - literal braces need escaping (use \`interface\\{\\}\` to find \`interface{}\` in Go code)
76
77
  - Multiline matching: By default patterns match within single lines only. For cross-line patterns like \`struct \\{[\\s\\S]*?field\`, use \`multiline: true\``,
77
78
  parameters: grepSchema,
@@ -1,18 +1,32 @@
1
- export { type AskToolDetails, askTool, createAskTool } from "./ask.js";
2
- export { type BashToolDetails, bashTool, createBashTool } from "./bash.js";
3
- export { createEditTool, editTool } from "./edit.js";
1
+ export { type AskToolDetails, askTool, createAskTool } from "./ask";
2
+ export { type BashToolDetails, bashTool, createBashTool } from "./bash";
3
+ export { createEditTool, type EditToolOptions, editTool } from "./edit";
4
4
  // Exa MCP tools (22 tools)
5
- export { exaTools } from "./exa/index.js";
6
- export type { ExaRenderDetails, ExaSearchResponse, ExaSearchResult } from "./exa/types.js";
7
- export { createFindTool, type FindToolDetails, findTool } from "./find.js";
8
- export { createGrepTool, type GrepToolDetails, grepTool } from "./grep.js";
9
- export { createLsTool, type LsToolDetails, lsTool } from "./ls.js";
10
- export { createLspTool, type LspToolDetails, lspTool } from "./lsp/index.js";
11
- export { createNotebookTool, type NotebookToolDetails, notebookTool } from "./notebook.js";
12
- export { createReadTool, type ReadToolDetails, readTool } from "./read.js";
13
- export { BUNDLED_AGENTS, createTaskTool, taskTool } from "./task/index.js";
14
- export type { TruncationResult } from "./truncate.js";
15
- export { createWebFetchTool, type WebFetchToolDetails, webFetchCustomTool, webFetchTool } from "./web-fetch.js";
5
+ export { exaTools } from "./exa/index";
6
+ export type { ExaRenderDetails, ExaSearchResponse, ExaSearchResult } from "./exa/types";
7
+ export { createFindTool, type FindToolDetails, findTool } from "./find";
8
+ export { createGrepTool, type GrepToolDetails, grepTool } from "./grep";
9
+ export { createLsTool, type LsToolDetails, lsTool } from "./ls";
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";
23
+ export { createNotebookTool, type NotebookToolDetails, notebookTool } from "./notebook";
24
+ export { createOutputTool, type OutputToolDetails, outputTool } from "./output";
25
+ export { createReadTool, type ReadToolDetails, readTool } from "./read";
26
+ export { createReportFindingTool, createSubmitReviewTool, reportFindingTool, submitReviewTool } from "./review";
27
+ export { BUNDLED_AGENTS, createTaskTool, taskTool } from "./task/index";
28
+ export type { TruncationResult } from "./truncate";
29
+ export { createWebFetchTool, type WebFetchToolDetails, webFetchCustomTool, webFetchTool } from "./web-fetch";
16
30
  export {
17
31
  companyWebSearchTools,
18
32
  createWebSearchTool,
@@ -30,24 +44,26 @@ export {
30
44
  webSearchDeepTool,
31
45
  webSearchLinkedinTool,
32
46
  webSearchTool,
33
- } from "./web-search/index.js";
34
- export { createWriteTool, writeTool } from "./write.js";
47
+ } from "./web-search/index";
48
+ export { createWriteTool, type WriteToolDetails, type WriteToolOptions, writeTool } from "./write";
35
49
 
36
50
  import type { AgentTool } from "@oh-my-pi/pi-agent-core";
37
- import { askTool, createAskTool } from "./ask.js";
38
- import { bashTool, createBashTool } from "./bash.js";
39
- import { checkBashInterception, checkSimpleLsInterception } from "./bash-interceptor.js";
40
- import { createEditTool, editTool } from "./edit.js";
41
- import { createFindTool, findTool } from "./find.js";
42
- import { createGrepTool, grepTool } from "./grep.js";
43
- import { createLsTool, lsTool } from "./ls.js";
44
- import { createLspTool, lspTool } from "./lsp/index.js";
45
- import { createNotebookTool, notebookTool } from "./notebook.js";
46
- import { createReadTool, readTool } from "./read.js";
47
- import { createTaskTool, taskTool } from "./task/index.js";
48
- import { createWebFetchTool, webFetchTool } from "./web-fetch.js";
49
- import { createWebSearchTool, webSearchTool } from "./web-search/index.js";
50
- import { createWriteTool, writeTool } from "./write.js";
51
+ import { askTool, createAskTool } from "./ask";
52
+ import { bashTool, createBashTool } from "./bash";
53
+ import { checkBashInterception, checkSimpleLsInterception } from "./bash-interceptor";
54
+ import { createEditTool, editTool } from "./edit";
55
+ import { createFindTool, findTool } from "./find";
56
+ import { createGrepTool, grepTool } from "./grep";
57
+ import { createLsTool, lsTool } from "./ls";
58
+ import { createLspTool, formatFile, getDiagnosticsForFile, lspTool } from "./lsp/index";
59
+ import { createNotebookTool, notebookTool } from "./notebook";
60
+ import { createOutputTool, outputTool } from "./output";
61
+ import { createReadTool, readTool } from "./read";
62
+ import { createReportFindingTool, createSubmitReviewTool, reportFindingTool, submitReviewTool } from "./review";
63
+ import { createTaskTool, taskTool } from "./task/index";
64
+ import { createWebFetchTool, webFetchTool } from "./web-fetch";
65
+ import { createWebSearchTool, webSearchTool } from "./web-search/index";
66
+ import { createWriteTool, writeTool } from "./write";
51
67
 
52
68
  /** Tool type (AgentTool from pi-ai) */
53
69
  export type Tool = AgentTool<any, any, any>;
@@ -57,24 +73,60 @@ export interface SessionContext {
57
73
  getSessionFile: () => string | null;
58
74
  }
59
75
 
76
+ /** Options for creating coding tools */
77
+ export interface CodingToolsOptions {
78
+ /** Whether to fetch LSP diagnostics after write tool writes files (default: true) */
79
+ lspDiagnosticsOnWrite?: boolean;
80
+ /** Whether to fetch LSP diagnostics after edit tool edits files (default: false) */
81
+ lspDiagnosticsOnEdit?: boolean;
82
+ /** Whether to format files using LSP after write tool writes (default: true) */
83
+ lspFormatOnWrite?: boolean;
84
+ /** Whether to accept high-confidence fuzzy matches in edit tool (default: true) */
85
+ editFuzzyMatch?: boolean;
86
+ /** Set of tool names available to the agent (for cross-tool awareness) */
87
+ availableTools?: Set<string>;
88
+ }
89
+
60
90
  // Factory function type
61
- type ToolFactory = (cwd: string, sessionContext?: SessionContext) => Tool;
91
+ type ToolFactory = (cwd: string, sessionContext?: SessionContext, options?: CodingToolsOptions) => Tool;
62
92
 
63
93
  // Tool definitions: static tools and their factory functions
64
94
  const toolDefs: Record<string, { tool: Tool; create: ToolFactory }> = {
65
95
  ask: { tool: askTool, create: createAskTool },
66
96
  read: { tool: readTool, create: createReadTool },
67
97
  bash: { tool: bashTool, create: createBashTool },
68
- edit: { tool: editTool, create: createEditTool },
69
- write: { tool: writeTool, create: createWriteTool },
98
+ edit: {
99
+ tool: editTool,
100
+ create: (cwd, _ctx, options) => {
101
+ const enableDiagnostics = options?.lspDiagnosticsOnEdit ?? false;
102
+ return createEditTool(cwd, {
103
+ fuzzyMatch: options?.editFuzzyMatch ?? true,
104
+ getDiagnostics: enableDiagnostics ? (absolutePath) => getDiagnosticsForFile(absolutePath, cwd) : undefined,
105
+ });
106
+ },
107
+ },
108
+ write: {
109
+ tool: writeTool,
110
+ create: (cwd, _ctx, options) => {
111
+ const enableFormat = options?.lspFormatOnWrite ?? true;
112
+ const enableDiagnostics = options?.lspDiagnosticsOnWrite ?? true;
113
+ return createWriteTool(cwd, {
114
+ formatOnWrite: enableFormat ? (absolutePath) => formatFile(absolutePath, cwd) : undefined,
115
+ getDiagnostics: enableDiagnostics ? (absolutePath) => getDiagnosticsForFile(absolutePath, cwd) : undefined,
116
+ });
117
+ },
118
+ },
70
119
  grep: { tool: grepTool, create: createGrepTool },
71
120
  find: { tool: findTool, create: createFindTool },
72
121
  ls: { tool: lsTool, create: createLsTool },
73
122
  lsp: { tool: lspTool, create: createLspTool },
74
123
  notebook: { tool: notebookTool, create: createNotebookTool },
75
- task: { tool: taskTool, create: (cwd, ctx) => createTaskTool(cwd, ctx) },
124
+ output: { tool: outputTool, create: (cwd, ctx) => createOutputTool(cwd, ctx) },
125
+ task: { tool: taskTool, create: (cwd, ctx, opts) => createTaskTool(cwd, ctx, opts) },
76
126
  web_fetch: { tool: webFetchTool, create: createWebFetchTool },
77
127
  web_search: { tool: webSearchTool, create: createWebSearchTool },
128
+ report_finding: { tool: reportFindingTool, create: createReportFindingTool },
129
+ submit_review: { tool: submitReviewTool, create: createSubmitReviewTool },
78
130
  };
79
131
 
80
132
  export type ToolName = keyof typeof toolDefs;
@@ -93,6 +145,7 @@ const baseCodingToolNames: ToolName[] = [
93
145
  "ls",
94
146
  "lsp",
95
147
  "notebook",
148
+ "output",
96
149
  "task",
97
150
  "web_fetch",
98
151
  "web_search",
@@ -116,10 +169,17 @@ export const allTools = Object.fromEntries(Object.entries(toolDefs).map(([name,
116
169
  * @param cwd - Working directory for tools
117
170
  * @param hasUI - Whether UI is available (includes ask tool if true)
118
171
  * @param sessionContext - Optional session context for tools that need it
172
+ * @param options - Options for tool configuration
119
173
  */
120
- export function createCodingTools(cwd: string, hasUI = false, sessionContext?: SessionContext): Tool[] {
174
+ export function createCodingTools(
175
+ cwd: string,
176
+ hasUI = false,
177
+ sessionContext?: SessionContext,
178
+ options?: CodingToolsOptions,
179
+ ): Tool[] {
121
180
  const names = hasUI ? [...baseCodingToolNames, ...uiToolNames] : baseCodingToolNames;
122
- return names.map((name) => toolDefs[name].create(cwd, sessionContext));
181
+ const optionsWithTools = { ...options, availableTools: new Set(names) };
182
+ return names.map((name) => toolDefs[name].create(cwd, sessionContext, optionsWithTools));
123
183
  }
124
184
 
125
185
  /**
@@ -127,20 +187,34 @@ export function createCodingTools(cwd: string, hasUI = false, sessionContext?: S
127
187
  * @param cwd - Working directory for tools
128
188
  * @param hasUI - Whether UI is available (includes ask tool if true)
129
189
  * @param sessionContext - Optional session context for tools that need it
190
+ * @param options - Options for tool configuration
130
191
  */
131
- export function createReadOnlyTools(cwd: string, hasUI = false, sessionContext?: SessionContext): Tool[] {
192
+ export function createReadOnlyTools(
193
+ cwd: string,
194
+ hasUI = false,
195
+ sessionContext?: SessionContext,
196
+ options?: CodingToolsOptions,
197
+ ): Tool[] {
132
198
  const names = hasUI ? [...baseReadOnlyToolNames, ...uiToolNames] : baseReadOnlyToolNames;
133
- return names.map((name) => toolDefs[name].create(cwd, sessionContext));
199
+ const optionsWithTools = { ...options, availableTools: new Set(names) };
200
+ return names.map((name) => toolDefs[name].create(cwd, sessionContext, optionsWithTools));
134
201
  }
135
202
 
136
203
  /**
137
204
  * Create all tools configured for a specific working directory.
138
205
  * @param cwd - Working directory for tools
139
206
  * @param sessionContext - Optional session context for tools that need it
207
+ * @param options - Options for tool configuration
140
208
  */
141
- export function createAllTools(cwd: string, sessionContext?: SessionContext): Record<ToolName, Tool> {
209
+ export function createAllTools(
210
+ cwd: string,
211
+ sessionContext?: SessionContext,
212
+ options?: CodingToolsOptions,
213
+ ): Record<ToolName, Tool> {
214
+ const names = Object.keys(toolDefs);
215
+ const optionsWithTools = { ...options, availableTools: new Set(names) };
142
216
  return Object.fromEntries(
143
- Object.entries(toolDefs).map(([name, def]) => [name, def.create(cwd, sessionContext)]),
217
+ Object.entries(toolDefs).map(([name, def]) => [name, def.create(cwd, sessionContext, optionsWithTools)]),
144
218
  ) as Record<ToolName, Tool>;
145
219
  }
146
220
 
@@ -1,9 +1,9 @@
1
+ import { existsSync, readdirSync, statSync } from "node:fs";
2
+ import nodePath from "node:path";
1
3
  import type { AgentTool } from "@oh-my-pi/pi-agent-core";
2
4
  import { Type } from "@sinclair/typebox";
3
- import { existsSync, readdirSync, statSync } from "fs";
4
- import nodePath from "path";
5
- import { resolveToCwd } from "./path-utils.js";
6
- import { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from "./truncate.js";
5
+ import { resolveToCwd } from "./path-utils";
6
+ import { DEFAULT_MAX_BYTES, formatSize, type TruncationResult, truncateHead } from "./truncate";
7
7
 
8
8
  const lsSchema = Type.Object({
9
9
  path: Type.Optional(Type.String({ description: "Directory to list (default: current directory)" })),