@oh-my-pi/pi-coding-agent 13.1.2 → 13.2.1

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 (235) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/package.json +7 -7
  3. package/scripts/format-prompts.ts +33 -14
  4. package/src/async/job-manager.ts +43 -1
  5. package/src/capability/index.ts +1 -2
  6. package/src/capability/tool.ts +1 -1
  7. package/src/cli/args.ts +1 -2
  8. package/src/cli/config-cli.ts +1 -1
  9. package/src/cli/file-processor.ts +1 -2
  10. package/src/cli/grep-cli.ts +1 -1
  11. package/src/cli/jupyter-cli.ts +1 -1
  12. package/src/cli/plugin-cli.ts +1 -1
  13. package/src/cli/setup-cli.ts +1 -1
  14. package/src/cli/shell-cli.ts +1 -1
  15. package/src/cli/ssh-cli.ts +1 -1
  16. package/src/cli/stats-cli.ts +1 -2
  17. package/src/cli/update-cli.ts +1 -2
  18. package/src/cli/web-search-cli.ts +1 -1
  19. package/src/cli.ts +1 -1
  20. package/src/commands/launch.ts +2 -1
  21. package/src/commit/agentic/agent.ts +2 -1
  22. package/src/commit/agentic/index.ts +1 -2
  23. package/src/commit/agentic/prompts/system.md +3 -3
  24. package/src/commit/agentic/tools/propose-changelog.ts +30 -19
  25. package/src/commit/changelog/generate.ts +16 -6
  26. package/src/commit/changelog/index.ts +2 -1
  27. package/src/commit/pipeline.ts +1 -2
  28. package/src/commit/prompts/reduce-system.md +1 -1
  29. package/src/commit/types.ts +10 -1
  30. package/src/config/keybindings.ts +1 -2
  31. package/src/config/model-registry.ts +1 -1
  32. package/src/config/prompt-templates.ts +14 -2
  33. package/src/config/settings-schema.ts +10 -0
  34. package/src/config/settings.ts +25 -2
  35. package/src/config.ts +1 -2
  36. package/src/debug/index.ts +1 -1
  37. package/src/debug/report-bundle.ts +1 -2
  38. package/src/debug/system-info.ts +1 -2
  39. package/src/discovery/agents.ts +2 -2
  40. package/src/discovery/builtin.ts +24 -14
  41. package/src/discovery/claude-plugins.ts +3 -2
  42. package/src/discovery/claude.ts +9 -9
  43. package/src/discovery/codex.ts +3 -3
  44. package/src/discovery/cursor.ts +5 -4
  45. package/src/discovery/gemini.ts +5 -5
  46. package/src/discovery/helpers.ts +47 -69
  47. package/src/discovery/mcp-json.ts +3 -3
  48. package/src/discovery/opencode.ts +7 -8
  49. package/src/discovery/ssh.ts +3 -3
  50. package/src/discovery/vscode.ts +3 -2
  51. package/src/discovery/windsurf.ts +3 -2
  52. package/src/exa/company.ts +1 -1
  53. package/src/exa/factory.ts +1 -6
  54. package/src/exa/linkedin.ts +1 -1
  55. package/src/exa/mcp-client.ts +19 -8
  56. package/src/exa/search.ts +2 -2
  57. package/src/exa/types.ts +3 -3
  58. package/src/exec/bash-executor.ts +2 -1
  59. package/src/exec/non-interactive-env.ts +43 -0
  60. package/src/export/custom-share.ts +1 -1
  61. package/src/export/html/index.ts +1 -2
  62. package/src/extensibility/custom-commands/loader.ts +1 -2
  63. package/src/extensibility/plugins/installer.ts +1 -2
  64. package/src/extensibility/plugins/loader.ts +1 -2
  65. package/src/extensibility/plugins/manager.ts +3 -2
  66. package/src/extensibility/skills.ts +59 -115
  67. package/src/index.ts +1 -3
  68. package/src/internal-urls/docs-index.generated.ts +1 -1
  69. package/src/ipy/executor.ts +1 -2
  70. package/src/ipy/gateway-coordinator.ts +1 -2
  71. package/src/ipy/modules.ts +1 -1
  72. package/src/ipy/runtime.ts +1 -3
  73. package/src/main.ts +1 -2
  74. package/src/mcp/config.ts +1 -1
  75. package/src/mcp/transports/stdio.ts +1 -2
  76. package/src/memories/index.ts +1 -2
  77. package/src/modes/components/diff.ts +49 -19
  78. package/src/modes/components/extensions/extension-dashboard.ts +1 -1
  79. package/src/modes/components/extensions/inspector-panel.ts +8 -2
  80. package/src/modes/components/footer.ts +1 -2
  81. package/src/modes/components/status-line/segments.ts +1 -2
  82. package/src/modes/components/tool-execution.ts +3 -10
  83. package/src/modes/components/welcome.ts +1 -1
  84. package/src/modes/controllers/command-controller.ts +1 -2
  85. package/src/modes/controllers/mcp-command-controller.ts +1 -1
  86. package/src/modes/controllers/selector-controller.ts +1 -1
  87. package/src/modes/controllers/ssh-command-controller.ts +1 -1
  88. package/src/modes/interactive-mode.ts +2 -3
  89. package/src/modes/shared.ts +1 -2
  90. package/src/modes/theme/theme.ts +1 -2
  91. package/src/patch/index.ts +1 -25
  92. package/src/prompts/agents/designer.md +7 -10
  93. package/src/prompts/agents/explore.md +15 -23
  94. package/src/prompts/agents/init.md +23 -23
  95. package/src/prompts/agents/plan.md +14 -77
  96. package/src/prompts/agents/reviewer.md +6 -5
  97. package/src/prompts/agents/task.md +13 -11
  98. package/src/prompts/compaction/branch-summary.md +3 -3
  99. package/src/prompts/compaction/compaction-short-summary.md +7 -7
  100. package/src/prompts/compaction/compaction-summary-context.md +1 -1
  101. package/src/prompts/compaction/compaction-summary.md +5 -5
  102. package/src/prompts/compaction/compaction-turn-prefix.md +3 -3
  103. package/src/prompts/compaction/compaction-update-summary.md +11 -11
  104. package/src/prompts/memories/consolidation.md +5 -5
  105. package/src/prompts/memories/read-path.md +6 -6
  106. package/src/prompts/memories/stage_one_input.md +1 -1
  107. package/src/prompts/memories/stage_one_system.md +5 -5
  108. package/src/prompts/review-request.md +4 -4
  109. package/src/prompts/system/agent-creation-architect.md +17 -17
  110. package/src/prompts/system/agent-creation-user.md +2 -2
  111. package/src/prompts/system/custom-system-prompt.md +4 -4
  112. package/src/prompts/system/plan-mode-active.md +20 -20
  113. package/src/prompts/system/plan-mode-approved.md +7 -7
  114. package/src/prompts/system/plan-mode-reference.md +2 -2
  115. package/src/prompts/system/plan-mode-subagent.md +8 -8
  116. package/src/prompts/system/subagent-submit-reminder.md +5 -5
  117. package/src/prompts/system/subagent-system-prompt.md +29 -22
  118. package/src/prompts/system/subagent-user-prompt.md +7 -3
  119. package/src/prompts/system/summarization-system.md +1 -1
  120. package/src/prompts/system/system-prompt.md +201 -226
  121. package/src/prompts/system/title-system.md +2 -2
  122. package/src/prompts/system/ttsr-interrupt.md +1 -1
  123. package/src/prompts/system/web-search.md +16 -16
  124. package/src/prompts/tools/ask.md +1 -3
  125. package/src/prompts/tools/await.md +2 -4
  126. package/src/prompts/tools/bash.md +5 -7
  127. package/src/prompts/tools/browser.md +4 -6
  128. package/src/prompts/tools/calculator.md +1 -3
  129. package/src/prompts/tools/cancel-job.md +2 -4
  130. package/src/prompts/tools/exit-plan-mode.md +7 -7
  131. package/src/prompts/tools/fetch.md +0 -2
  132. package/src/prompts/tools/find.md +3 -5
  133. package/src/prompts/tools/gemini-image.md +6 -22
  134. package/src/prompts/tools/grep.md +4 -6
  135. package/src/prompts/tools/hashline.md +12 -15
  136. package/src/prompts/tools/lsp.md +1 -3
  137. package/src/prompts/tools/patch.md +7 -9
  138. package/src/prompts/tools/python.md +10 -14
  139. package/src/prompts/tools/read.md +0 -2
  140. package/src/prompts/tools/replace.md +5 -7
  141. package/src/prompts/tools/ssh.md +3 -5
  142. package/src/prompts/tools/task.md +6 -8
  143. package/src/prompts/tools/todo-write.md +7 -9
  144. package/src/prompts/tools/web-search.md +3 -5
  145. package/src/prompts/tools/write.md +3 -5
  146. package/src/sdk.ts +1 -2
  147. package/src/session/agent-session.ts +10 -26
  148. package/src/session/agent-storage.ts +1 -2
  149. package/src/session/history-storage.ts +1 -2
  150. package/src/session/session-manager.ts +10 -2
  151. package/src/ssh/connection-manager.ts +11 -2
  152. package/src/ssh/sshfs-mount.ts +7 -1
  153. package/src/system-prompt.ts +25 -103
  154. package/src/task/agents.ts +1 -1
  155. package/src/task/worktree.ts +1 -2
  156. package/src/tools/ask.ts +0 -1
  157. package/src/tools/await-tool.ts +6 -3
  158. package/src/tools/bash-interactive.ts +2 -45
  159. package/src/tools/bash.ts +5 -5
  160. package/src/tools/browser.ts +1 -2
  161. package/src/tools/gemini-image.ts +8 -28
  162. package/src/tools/json-tree.ts +2 -1
  163. package/src/tools/python.ts +1 -1
  164. package/src/tools/read.ts +1 -2
  165. package/src/tools/render-utils.ts +5 -2
  166. package/src/tools/todo-write.ts +11 -9
  167. package/src/utils/tools-manager.ts +1 -2
  168. package/src/web/scrapers/artifacthub.ts +2 -1
  169. package/src/web/scrapers/aur.ts +2 -1
  170. package/src/web/scrapers/biorxiv.ts +2 -1
  171. package/src/web/scrapers/bluesky.ts +2 -1
  172. package/src/web/scrapers/chocolatey.ts +2 -1
  173. package/src/web/scrapers/cisa-kev.ts +2 -1
  174. package/src/web/scrapers/clojars.ts +2 -1
  175. package/src/web/scrapers/coingecko.ts +2 -1
  176. package/src/web/scrapers/crates-io.ts +2 -1
  177. package/src/web/scrapers/crossref.ts +2 -1
  178. package/src/web/scrapers/discogs.ts +3 -1
  179. package/src/web/scrapers/discourse.ts +2 -1
  180. package/src/web/scrapers/dockerhub.ts +2 -1
  181. package/src/web/scrapers/fdroid.ts +2 -1
  182. package/src/web/scrapers/firefox-addons.ts +2 -1
  183. package/src/web/scrapers/flathub.ts +2 -1
  184. package/src/web/scrapers/gitlab.ts +1 -1
  185. package/src/web/scrapers/go-pkg.ts +2 -1
  186. package/src/web/scrapers/hackage.ts +2 -1
  187. package/src/web/scrapers/hackernews.ts +2 -1
  188. package/src/web/scrapers/hex.ts +2 -1
  189. package/src/web/scrapers/huggingface.ts +2 -1
  190. package/src/web/scrapers/jetbrains-marketplace.ts +2 -1
  191. package/src/web/scrapers/lemmy.ts +2 -1
  192. package/src/web/scrapers/lobsters.ts +2 -1
  193. package/src/web/scrapers/mastodon.ts +2 -1
  194. package/src/web/scrapers/maven.ts +2 -1
  195. package/src/web/scrapers/mdn.ts +2 -1
  196. package/src/web/scrapers/metacpan.ts +2 -1
  197. package/src/web/scrapers/musicbrainz.ts +3 -1
  198. package/src/web/scrapers/npm.ts +2 -1
  199. package/src/web/scrapers/nuget.ts +2 -1
  200. package/src/web/scrapers/nvd.ts +2 -1
  201. package/src/web/scrapers/ollama.ts +2 -1
  202. package/src/web/scrapers/open-vsx.ts +2 -1
  203. package/src/web/scrapers/opencorporates.ts +2 -1
  204. package/src/web/scrapers/openlibrary.ts +2 -1
  205. package/src/web/scrapers/orcid.ts +3 -1
  206. package/src/web/scrapers/osv.ts +2 -1
  207. package/src/web/scrapers/packagist.ts +2 -1
  208. package/src/web/scrapers/pub-dev.ts +2 -1
  209. package/src/web/scrapers/pubmed.ts +2 -1
  210. package/src/web/scrapers/pypi.ts +2 -1
  211. package/src/web/scrapers/rawg.ts +2 -8
  212. package/src/web/scrapers/reddit.ts +2 -1
  213. package/src/web/scrapers/repology.ts +2 -1
  214. package/src/web/scrapers/rfc.ts +2 -1
  215. package/src/web/scrapers/rubygems.ts +2 -1
  216. package/src/web/scrapers/searchcode.ts +2 -1
  217. package/src/web/scrapers/sec-edgar.ts +2 -1
  218. package/src/web/scrapers/semantic-scholar.ts +2 -1
  219. package/src/web/scrapers/snapcraft.ts +2 -1
  220. package/src/web/scrapers/sourcegraph.ts +2 -1
  221. package/src/web/scrapers/spdx.ts +2 -1
  222. package/src/web/scrapers/stackoverflow.ts +2 -1
  223. package/src/web/scrapers/terraform.ts +2 -1
  224. package/src/web/scrapers/types.ts +0 -11
  225. package/src/web/scrapers/vimeo.ts +2 -1
  226. package/src/web/scrapers/vscode-marketplace.ts +2 -1
  227. package/src/web/scrapers/w3c.ts +2 -1
  228. package/src/web/scrapers/wikidata.ts +2 -1
  229. package/src/web/search/index.ts +10 -14
  230. package/src/web/search/provider.ts +2 -2
  231. package/src/web/search/providers/codex.ts +1 -2
  232. package/src/web/search/providers/exa.ts +1 -6
  233. package/src/web/search/providers/gemini.ts +1 -1
  234. package/src/web/search/providers/perplexity.ts +1 -2
  235. package/src/web/search/providers/utils.ts +1 -1
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, loadPage } from "./types";
3
4
 
4
5
  interface KevEntry {
5
6
  cveID: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, loadPage } from "./types";
3
4
  import { asNumber, asString, isRecord } from "./utils";
4
5
 
5
6
  function formatLicenses(licenses: unknown): string[] {
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, loadPage } from "./types";
3
4
 
4
5
  interface CoinGeckoResponse {
5
6
  id: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, loadPage } from "./types";
3
4
 
4
5
  /**
5
6
  * Check if content looks like HTML
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, htmlToBasicMarkdown, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, htmlToBasicMarkdown, loadPage } from "./types";
3
4
 
4
5
  interface CrossrefAuthor {
5
6
  given?: string;
@@ -4,8 +4,10 @@
4
4
  * Uses the Discogs API to extract structured metadata about releases.
5
5
  * API docs: https://www.discogs.com/developers
6
6
  */
7
+
8
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
7
9
  import type { RenderResult, SpecialHandler } from "./types";
8
- import { buildResult, loadPage, tryParseJson } from "./types";
10
+ import { buildResult, loadPage } from "./types";
9
11
 
10
12
  interface DiscogsArtist {
11
13
  name: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatIsoDate, htmlToBasicMarkdown, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatIsoDate, htmlToBasicMarkdown, loadPage } from "./types";
3
4
 
4
5
  interface DiscourseUser {
5
6
  username?: string;
@@ -1,6 +1,7 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import { formatBytes } from "../../tools/render-utils";
2
3
  import type { RenderResult, SpecialHandler } from "./types";
3
- import { buildResult, formatIsoDate, formatNumber, loadPage, tryParseJson } from "./types";
4
+ import { buildResult, formatIsoDate, formatNumber, loadPage } from "./types";
4
5
 
5
6
  interface DockerHubRepo {
6
7
  name: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { LocalizedText, RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, getLocalizedText, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, getLocalizedText, loadPage } from "./types";
3
4
 
4
5
  type FdroidPackage = {
5
6
  packageName?: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { LocalizedText, RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, getLocalizedText, htmlToBasicMarkdown, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, getLocalizedText, htmlToBasicMarkdown, loadPage } from "./types";
3
4
 
4
5
  type AddonFile = {
5
6
  permissions?: string[];
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatIsoDate, formatNumber, htmlToBasicMarkdown, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatIsoDate, formatNumber, htmlToBasicMarkdown, loadPage } from "./types";
3
4
 
4
5
  interface FlathubScreenshotSize {
5
6
  src?: string;
@@ -1,3 +1,4 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import {
2
3
  buildResult,
3
4
  formatIsoDate,
@@ -6,7 +7,6 @@ import {
6
7
  loadPage,
7
8
  type RenderResult,
8
9
  type SpecialHandler,
9
- tryParseJson,
10
10
  } from "./types";
11
11
 
12
12
  interface GitLabUrl {
@@ -1,6 +1,7 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import { parse as parseHtml } from "node-html-parser";
2
3
  import type { RenderResult, SpecialHandler } from "./types";
3
- import { buildResult, htmlToBasicMarkdown, loadPage, tryParseJson } from "./types";
4
+ import { buildResult, htmlToBasicMarkdown, loadPage } from "./types";
4
5
 
5
6
  interface GoModuleInfo {
6
7
  Version: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, loadPage } from "./types";
3
4
 
4
5
  interface HackageVersionMap {
5
6
  [version: string]: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { SpecialHandler } from "./types";
2
- import { buildResult, decodeHtmlEntities, formatIsoDate, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, decodeHtmlEntities, formatIsoDate, loadPage } from "./types";
3
4
 
4
5
  interface HNItem {
5
6
  id: number;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { SpecialHandler } from "./types";
2
- import { buildResult, formatIsoDate, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatIsoDate, formatNumber, loadPage } from "./types";
3
4
 
4
5
  /**
5
6
  * Handle Hex.pm (Elixir package registry) URLs via API
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, loadPage } from "./types";
3
4
 
4
5
  interface HfModelData {
5
6
  modelId: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, htmlToBasicMarkdown, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, htmlToBasicMarkdown, loadPage } from "./types";
3
4
 
4
5
  interface PluginVendor {
5
6
  name?: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, loadPage } from "./types";
3
4
 
4
5
  interface LemmyCreator {
5
6
  name: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { SpecialHandler } from "./types";
2
- import { buildResult, formatIsoDate, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatIsoDate, loadPage } from "./types";
3
4
 
4
5
  // =============================================================================
5
6
  // Lobste.rs Types
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, htmlToBasicMarkdown, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, htmlToBasicMarkdown, loadPage } from "./types";
3
4
 
4
5
  interface MastodonAccount {
5
6
  id: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatIsoDate, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatIsoDate, formatNumber, loadPage } from "./types";
3
4
 
4
5
  interface MavenDoc {
5
6
  id: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { SpecialHandler } from "./types";
2
- import { buildResult, htmlToBasicMarkdown, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, htmlToBasicMarkdown, loadPage } from "./types";
3
4
 
4
5
  interface MDNSection {
5
6
  type: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatIsoDate, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatIsoDate, loadPage } from "./types";
3
4
 
4
5
  interface ModuleResponse {
5
6
  name: string;
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * MusicBrainz URL handler for artists, releases, and recordings
3
3
  */
4
+
5
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
4
6
  import type { RenderResult, SpecialHandler } from "./types";
5
- import { buildResult, formatMediaDuration, loadPage, tryParseJson } from "./types";
7
+ import { buildResult, formatMediaDuration, loadPage } from "./types";
6
8
 
7
9
  type MusicBrainzEntity = "artist" | "release" | "recording";
8
10
 
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, loadPage } from "./types";
3
4
 
4
5
  /**
5
6
  * Handle npm URLs via registry API
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatIsoDate, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatIsoDate, formatNumber, loadPage } from "./types";
3
4
 
4
5
  interface NuGetCatalogEntry {
5
6
  id: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatIsoDate, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatIsoDate, loadPage } from "./types";
3
4
 
4
5
  interface CvssV31 {
5
6
  baseScore: number;
@@ -1,6 +1,7 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import { formatBytes } from "../../tools/render-utils";
2
3
  import type { RenderResult, SpecialHandler } from "./types";
3
- import { buildResult, decodeHtmlEntities, loadPage, tryParseJson } from "./types";
4
+ import { buildResult, decodeHtmlEntities, loadPage } from "./types";
4
5
 
5
6
  interface OllamaTagDetails {
6
7
  parent_model?: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, loadPage } from "./types";
3
4
 
4
5
  interface OpenVsxFileLinks {
5
6
  readme?: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, loadPage } from "./types";
3
4
 
4
5
  interface Officer {
5
6
  id: number;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, loadPage } from "./types";
3
4
 
4
5
  interface OpenLibraryAuthor {
5
6
  name?: string;
@@ -1,8 +1,10 @@
1
1
  /**
2
2
  * ORCID handler for web-fetch
3
3
  */
4
+
5
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
4
6
  import type { RenderResult, SpecialHandler } from "./types";
5
- import { buildResult, loadPage, tryParseJson } from "./types";
7
+ import { buildResult, loadPage } from "./types";
6
8
 
7
9
  const MAX_WORKS = 50;
8
10
  const ORCID_PATTERN = /\/(\d{4}-\d{4}-\d{4}-\d{3}[\dXx])(?:\/|$)/;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatIsoDate, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatIsoDate, loadPage } from "./types";
3
4
 
4
5
  interface OsvSeverity {
5
6
  type: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, loadPage } from "./types";
3
4
 
4
5
  /**
5
6
  * Handle Packagist URLs via JSON API
@@ -1,4 +1,5 @@
1
- import { buildResult, formatNumber, htmlToBasicMarkdown, loadPage, type SpecialHandler, tryParseJson } from "./types";
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
2
+ import { buildResult, formatNumber, htmlToBasicMarkdown, loadPage, type SpecialHandler } from "./types";
2
3
 
3
4
  /**
4
5
  * Handle pub.dev URLs via API
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * PubMed handler for web-fetch
3
3
  */
4
- import { buildResult, loadPage, type RenderResult, type SpecialHandler, tryParseJson } from "./types";
4
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
5
+ import { buildResult, loadPage, type RenderResult, type SpecialHandler } from "./types";
5
6
 
6
7
  const NCBI_HEADERS = {
7
8
  Accept: "application/json, text/plain;q=0.9, */*;q=0.8",
@@ -1,4 +1,5 @@
1
- import { buildResult, formatNumber, loadPage, type RenderResult, type SpecialHandler, tryParseJson } from "./types";
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
2
+ import { buildResult, formatNumber, loadPage, type RenderResult, type SpecialHandler } from "./types";
2
3
 
3
4
  /**
4
5
  * Handle PyPI URLs via JSON API
@@ -1,11 +1,5 @@
1
- import {
2
- buildResult,
3
- htmlToBasicMarkdown,
4
- loadPage,
5
- type RenderResult,
6
- type SpecialHandler,
7
- tryParseJson,
8
- } from "./types";
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
2
+ import { buildResult, htmlToBasicMarkdown, loadPage, type RenderResult, type SpecialHandler } from "./types";
9
3
 
10
4
  interface RawgPlatformEntry {
11
5
  platform?: {
@@ -1,4 +1,5 @@
1
- import { buildResult, formatIsoDate, loadPage, type RenderResult, type SpecialHandler, tryParseJson } from "./types";
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
2
+ import { buildResult, formatIsoDate, loadPage, type RenderResult, type SpecialHandler } from "./types";
2
3
 
3
4
  interface RedditPost {
4
5
  title: string;
@@ -1,4 +1,5 @@
1
- import { buildResult, loadPage, type RenderResult, type SpecialHandler, tryParseJson } from "./types";
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
2
+ import { buildResult, loadPage, type RenderResult, type SpecialHandler } from "./types";
2
3
 
3
4
  interface RepologyPackage {
4
5
  repo: string;
@@ -1,4 +1,5 @@
1
- import { buildResult, loadPage, type RenderResult, type SpecialHandler, tryParseJson } from "./types";
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
2
+ import { buildResult, loadPage, type RenderResult, type SpecialHandler } from "./types";
2
3
 
3
4
  interface RfcMetadata {
4
5
  doc_id: string;
@@ -1,4 +1,5 @@
1
- import { buildResult, formatNumber, loadPage, type RenderResult, type SpecialHandler, tryParseJson } from "./types";
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
2
+ import { buildResult, formatNumber, loadPage, type RenderResult, type SpecialHandler } from "./types";
2
3
 
3
4
  interface RubyGemsDependency {
4
5
  name: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, loadPage } from "./types";
3
4
 
4
5
  interface SearchcodeResult {
5
6
  id?: number | string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, loadPage } from "./types";
3
4
 
4
5
  interface SecFiling {
5
6
  accessionNumber: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, loadPage } from "./types";
3
4
 
4
5
  interface SemanticScholarAuthor {
5
6
  name: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, loadPage } from "./types";
3
4
 
4
5
  interface SnapcraftPublisher {
5
6
  "display-name"?: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, loadPage } from "./types";
3
4
 
4
5
  const GRAPHQL_ENDPOINT = "https://sourcegraph.com/.api/graphql";
5
6
  const GRAPHQL_HEADERS = {
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, htmlToBasicMarkdown, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, htmlToBasicMarkdown, loadPage } from "./types";
3
4
 
4
5
  interface SpdxCrossRef {
5
6
  url?: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatIsoDate, htmlToBasicMarkdown, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatIsoDate, htmlToBasicMarkdown, loadPage } from "./types";
3
4
 
4
5
  interface SOQuestion {
5
6
  title: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, loadPage } from "./types";
3
4
 
4
5
  interface TerraformModule {
5
6
  id: string;
@@ -190,17 +190,6 @@ export function htmlToBasicMarkdown(html: string): string {
190
190
  return decodeHtmlEntities(stripped);
191
191
  }
192
192
 
193
- /**
194
- * Try to parse JSON, returning null on failure.
195
- */
196
- export function tryParseJson<T = unknown>(content: string): T | null {
197
- try {
198
- return JSON.parse(content) as T;
199
- } catch {
200
- return null;
201
- }
202
- }
203
-
204
193
  /**
205
194
  * Build a RenderResult from markdown content. Calls finalizeOutput internally.
206
195
  */
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { SpecialHandler } from "./types";
2
- import { buildResult, formatMediaDuration, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatMediaDuration, loadPage } from "./types";
3
4
 
4
5
  interface VimeoOEmbed {
5
6
  title: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, loadPage } from "./types";
3
4
 
4
5
  interface MarketplaceProperty {
5
6
  key?: string;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, htmlToBasicMarkdown, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, htmlToBasicMarkdown, loadPage } from "./types";
3
4
  import { asRecord } from "./utils";
4
5
 
5
6
  type JsonRecord = Record<string, unknown>;
@@ -1,5 +1,6 @@
1
+ import { tryParseJson } from "@oh-my-pi/pi-utils";
1
2
  import type { RenderResult, SpecialHandler } from "./types";
2
- import { buildResult, formatNumber, loadPage, tryParseJson } from "./types";
3
+ import { buildResult, formatNumber, loadPage } from "./types";
3
4
 
4
5
  /**
5
6
  * Common Wikidata property IDs mapped to human-readable names
@@ -353,13 +353,6 @@ async function executeExaTool(
353
353
  ): Promise<{ content: Array<{ type: "text"; text: string }>; details: ExaRenderDetails }> {
354
354
  try {
355
355
  const apiKey = await findExaKey();
356
- if (!apiKey) {
357
- return {
358
- content: [{ type: "text" as const, text: "Error: EXA_API_KEY not found" }],
359
- details: { error: "EXA_API_KEY not found", toolName },
360
- };
361
- }
362
-
363
356
  const response = await callExaTool(mcpToolName, params, apiKey);
364
357
 
365
358
  if (isSearchResponse(response)) {
@@ -402,7 +395,7 @@ Parameters:
402
395
 
403
396
  async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
404
397
  const { num_results, ...rest } = params as Record<string, unknown>;
405
- const args = { ...rest, type: "deep", numResults: num_results ?? 10 };
398
+ const args = { ...rest, type: "auto", numResults: num_results ?? 10 };
406
399
  return executeExaTool("web_search_exa", args, "web_search_deep");
407
400
  },
408
401
 
@@ -462,7 +455,7 @@ Parameters:
462
455
  parameters: webSearchCrawlSchema,
463
456
 
464
457
  async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
465
- return executeExaTool("crawling", params as Record<string, unknown>, "web_search_crawl");
458
+ return executeExaTool("crawling_exa", params as Record<string, unknown>, "web_search_crawl");
466
459
  },
467
460
 
468
461
  renderCall(args, _options, theme) {
@@ -493,7 +486,7 @@ Parameters:
493
486
  parameters: webSearchLinkedinSchema,
494
487
 
495
488
  async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
496
- return executeExaTool("linkedin_search", params as Record<string, unknown>, "web_search_linkedin");
489
+ return executeExaTool("linkedin_search_exa", params as Record<string, unknown>, "web_search_linkedin");
497
490
  },
498
491
 
499
492
  renderCall(args, _options, theme) {
@@ -523,7 +516,7 @@ Parameters:
523
516
  parameters: webSearchCompanySchema,
524
517
 
525
518
  async execute(_toolCallId, params, _onUpdate, _ctx, _signal) {
526
- return executeExaTool("company_research", params as Record<string, unknown>, "web_search_company");
519
+ return executeExaTool("company_research_exa", params as Record<string, unknown>, "web_search_company");
527
520
  },
528
521
 
529
522
  renderCall(args, _options, theme) {
@@ -561,17 +554,20 @@ export interface SearchToolsOptions {
561
554
  *
562
555
  * Returns:
563
556
  * - Always: web_search (unified, works with Anthropic/Perplexity/Exa)
564
- * - With EXA_API_KEY: web_search_deep, web_search_code_context, web_search_crawl
557
+ * - Always: web_search_deep, web_search_code_context (public Exa MCP tools)
558
+ * - With EXA_API_KEY: web_search_crawl
565
559
  * - With EXA_API_KEY + options.enableLinkedin: web_search_linkedin
566
560
  * - With EXA_API_KEY + options.enableCompany: web_search_company
567
561
  */
568
562
  export async function getSearchTools(options: SearchToolsOptions = {}): Promise<CustomTool<any, any>[]> {
569
563
  const tools: CustomTool<any, any>[] = [webSearchCustomTool];
570
564
 
571
- // Check for Exa API key
565
+ tools.push(webSearchDeepTool, webSearchCodeContextTool);
566
+
567
+ // Advanced/add-on tools remain key-gated to avoid exposing known unauthenticated failures
572
568
  const exaKey = await findExaKey();
573
569
  if (exaKey) {
574
- tools.push(...exaSearchTools);
570
+ tools.push(webSearchCrawlTool);
575
571
 
576
572
  if (options.enableLinkedin) {
577
573
  tools.push(...linkedinSearchTools);