@oh-my-pi/pi-coding-agent 3.25.0 → 3.30.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.
Files changed (85) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/package.json +4 -4
  3. package/src/core/tools/complete.ts +2 -4
  4. package/src/core/tools/jtd-to-json-schema.ts +174 -196
  5. package/src/core/tools/read.ts +4 -4
  6. package/src/core/tools/task/executor.ts +146 -20
  7. package/src/core/tools/task/name-generator.ts +1544 -214
  8. package/src/core/tools/task/types.ts +19 -5
  9. package/src/core/tools/task/worker.ts +103 -13
  10. package/src/core/tools/web-fetch-handlers/academic.test.ts +239 -0
  11. package/src/core/tools/web-fetch-handlers/artifacthub.ts +210 -0
  12. package/src/core/tools/web-fetch-handlers/arxiv.ts +84 -0
  13. package/src/core/tools/web-fetch-handlers/aur.ts +171 -0
  14. package/src/core/tools/web-fetch-handlers/biorxiv.ts +136 -0
  15. package/src/core/tools/web-fetch-handlers/bluesky.ts +277 -0
  16. package/src/core/tools/web-fetch-handlers/brew.ts +173 -0
  17. package/src/core/tools/web-fetch-handlers/business.test.ts +82 -0
  18. package/src/core/tools/web-fetch-handlers/cheatsh.ts +73 -0
  19. package/src/core/tools/web-fetch-handlers/chocolatey.ts +153 -0
  20. package/src/core/tools/web-fetch-handlers/coingecko.ts +179 -0
  21. package/src/core/tools/web-fetch-handlers/crates-io.ts +123 -0
  22. package/src/core/tools/web-fetch-handlers/dev-platforms.test.ts +254 -0
  23. package/src/core/tools/web-fetch-handlers/devto.ts +173 -0
  24. package/src/core/tools/web-fetch-handlers/discogs.ts +303 -0
  25. package/src/core/tools/web-fetch-handlers/dockerhub.ts +156 -0
  26. package/src/core/tools/web-fetch-handlers/documentation.test.ts +85 -0
  27. package/src/core/tools/web-fetch-handlers/finance-media.test.ts +144 -0
  28. package/src/core/tools/web-fetch-handlers/git-hosting.test.ts +272 -0
  29. package/src/core/tools/web-fetch-handlers/github-gist.ts +64 -0
  30. package/src/core/tools/web-fetch-handlers/github.ts +424 -0
  31. package/src/core/tools/web-fetch-handlers/gitlab.ts +444 -0
  32. package/src/core/tools/web-fetch-handlers/go-pkg.ts +271 -0
  33. package/src/core/tools/web-fetch-handlers/hackage.ts +89 -0
  34. package/src/core/tools/web-fetch-handlers/hackernews.ts +208 -0
  35. package/src/core/tools/web-fetch-handlers/hex.ts +121 -0
  36. package/src/core/tools/web-fetch-handlers/huggingface.ts +385 -0
  37. package/src/core/tools/web-fetch-handlers/iacr.ts +82 -0
  38. package/src/core/tools/web-fetch-handlers/index.ts +69 -0
  39. package/src/core/tools/web-fetch-handlers/lobsters.ts +186 -0
  40. package/src/core/tools/web-fetch-handlers/mastodon.ts +302 -0
  41. package/src/core/tools/web-fetch-handlers/maven.ts +147 -0
  42. package/src/core/tools/web-fetch-handlers/mdn.ts +174 -0
  43. package/src/core/tools/web-fetch-handlers/media.test.ts +138 -0
  44. package/src/core/tools/web-fetch-handlers/metacpan.ts +247 -0
  45. package/src/core/tools/web-fetch-handlers/npm.ts +107 -0
  46. package/src/core/tools/web-fetch-handlers/nuget.ts +201 -0
  47. package/src/core/tools/web-fetch-handlers/nvd.ts +238 -0
  48. package/src/core/tools/web-fetch-handlers/opencorporates.ts +273 -0
  49. package/src/core/tools/web-fetch-handlers/openlibrary.ts +313 -0
  50. package/src/core/tools/web-fetch-handlers/osv.ts +184 -0
  51. package/src/core/tools/web-fetch-handlers/package-managers-2.test.ts +199 -0
  52. package/src/core/tools/web-fetch-handlers/package-managers.test.ts +171 -0
  53. package/src/core/tools/web-fetch-handlers/package-registries.test.ts +259 -0
  54. package/src/core/tools/web-fetch-handlers/packagist.ts +170 -0
  55. package/src/core/tools/web-fetch-handlers/pub-dev.ts +185 -0
  56. package/src/core/tools/web-fetch-handlers/pubmed.ts +174 -0
  57. package/src/core/tools/web-fetch-handlers/pypi.ts +125 -0
  58. package/src/core/tools/web-fetch-handlers/readthedocs.ts +122 -0
  59. package/src/core/tools/web-fetch-handlers/reddit.ts +100 -0
  60. package/src/core/tools/web-fetch-handlers/repology.ts +257 -0
  61. package/src/core/tools/web-fetch-handlers/research.test.ts +107 -0
  62. package/src/core/tools/web-fetch-handlers/rfc.ts +205 -0
  63. package/src/core/tools/web-fetch-handlers/rubygems.ts +112 -0
  64. package/src/core/tools/web-fetch-handlers/sec-edgar.ts +269 -0
  65. package/src/core/tools/web-fetch-handlers/security.test.ts +103 -0
  66. package/src/core/tools/web-fetch-handlers/semantic-scholar.ts +190 -0
  67. package/src/core/tools/web-fetch-handlers/social-extended.test.ts +192 -0
  68. package/src/core/tools/web-fetch-handlers/social.test.ts +259 -0
  69. package/src/core/tools/web-fetch-handlers/spotify.ts +218 -0
  70. package/src/core/tools/web-fetch-handlers/stackexchange.test.ts +120 -0
  71. package/src/core/tools/web-fetch-handlers/stackoverflow.ts +123 -0
  72. package/src/core/tools/web-fetch-handlers/standards.test.ts +122 -0
  73. package/src/core/tools/web-fetch-handlers/terraform.ts +296 -0
  74. package/src/core/tools/web-fetch-handlers/tldr.ts +47 -0
  75. package/src/core/tools/web-fetch-handlers/twitter.ts +84 -0
  76. package/src/core/tools/web-fetch-handlers/types.ts +163 -0
  77. package/src/core/tools/web-fetch-handlers/utils.ts +91 -0
  78. package/src/core/tools/web-fetch-handlers/vimeo.ts +152 -0
  79. package/src/core/tools/web-fetch-handlers/wikidata.ts +349 -0
  80. package/src/core/tools/web-fetch-handlers/wikipedia.test.ts +73 -0
  81. package/src/core/tools/web-fetch-handlers/wikipedia.ts +91 -0
  82. package/src/core/tools/web-fetch-handlers/youtube.test.ts +198 -0
  83. package/src/core/tools/web-fetch-handlers/youtube.ts +319 -0
  84. package/src/core/tools/web-fetch.ts +152 -1324
  85. package/src/utils/tools-manager.ts +110 -8
@@ -11,6 +11,7 @@ interface ToolConfig {
11
11
  repo: string; // GitHub repo (e.g., "sharkdp/fd")
12
12
  binaryName: string; // Name of the binary inside the archive
13
13
  tagPrefix: string; // Prefix for tags (e.g., "v" for v1.0.0, "" for 1.0.0)
14
+ isDirectBinary?: boolean; // If true, asset is a direct binary (not an archive)
14
15
  getAssetName: (version: string, plat: string, architecture: string) => string | null;
15
16
  }
16
17
 
@@ -93,6 +94,43 @@ const TOOLS: Record<string, ToolConfig> = {
93
94
  return null;
94
95
  },
95
96
  },
97
+ "yt-dlp": {
98
+ name: "yt-dlp",
99
+ repo: "yt-dlp/yt-dlp",
100
+ binaryName: "yt-dlp",
101
+ tagPrefix: "",
102
+ isDirectBinary: true,
103
+ getAssetName: (_version, plat, architecture) => {
104
+ if (plat === "darwin") {
105
+ return "yt-dlp_macos"; // Universal binary
106
+ } else if (plat === "linux") {
107
+ return architecture === "arm64" ? "yt-dlp_linux_aarch64" : "yt-dlp_linux";
108
+ } else if (plat === "win32") {
109
+ return architecture === "arm64" ? "yt-dlp_arm64.exe" : "yt-dlp.exe";
110
+ }
111
+ return null;
112
+ },
113
+ },
114
+ };
115
+
116
+ // Python packages installed via uv/pip
117
+ interface PythonToolConfig {
118
+ name: string;
119
+ package: string; // PyPI package name
120
+ binaryName: string; // CLI command name after install
121
+ }
122
+
123
+ const PYTHON_TOOLS: Record<string, PythonToolConfig> = {
124
+ markitdown: {
125
+ name: "markitdown",
126
+ package: "markitdown",
127
+ binaryName: "markitdown",
128
+ },
129
+ html2text: {
130
+ name: "html2text",
131
+ package: "html2text",
132
+ binaryName: "html2text",
133
+ },
96
134
  };
97
135
 
98
136
  // Check if a command exists in PATH
@@ -100,8 +138,16 @@ function commandExists(cmd: string): string | null {
100
138
  return Bun.which(cmd);
101
139
  }
102
140
 
141
+ export type ToolName = "fd" | "rg" | "sd" | "sg" | "yt-dlp" | "markitdown" | "html2text";
142
+
103
143
  // Get the path to a tool (system-wide or in our tools dir)
104
- export function getToolPath(tool: "fd" | "rg" | "sd" | "sg"): string | null {
144
+ export function getToolPath(tool: ToolName): string | null {
145
+ // Check Python tools first
146
+ const pythonConfig = PYTHON_TOOLS[tool];
147
+ if (pythonConfig) {
148
+ return commandExists(pythonConfig.binaryName);
149
+ }
150
+
105
151
  const config = TOOLS[tool];
106
152
  if (!config) return null;
107
153
 
@@ -156,7 +202,7 @@ async function downloadFile(url: string, dest: string): Promise<void> {
156
202
  }
157
203
 
158
204
  // Download and install a tool
159
- async function downloadTool(tool: "fd" | "rg" | "sd" | "sg"): Promise<string> {
205
+ async function downloadTool(tool: ToolName): Promise<string> {
160
206
  const config = TOOLS[tool];
161
207
  if (!config) throw new Error(`Unknown tool: ${tool}`);
162
208
 
@@ -176,11 +222,20 @@ async function downloadTool(tool: "fd" | "rg" | "sd" | "sg"): Promise<string> {
176
222
  mkdirSync(TOOLS_DIR, { recursive: true });
177
223
 
178
224
  const downloadUrl = `https://github.com/${config.repo}/releases/download/${config.tagPrefix}${version}/${assetName}`;
179
- const archivePath = join(TOOLS_DIR, assetName);
180
225
  const binaryExt = plat === "win32" ? ".exe" : "";
181
226
  const binaryPath = join(TOOLS_DIR, config.binaryName + binaryExt);
182
227
 
183
- // Download
228
+ // Handle direct binary downloads (no archive extraction needed)
229
+ if (config.isDirectBinary) {
230
+ await downloadFile(downloadUrl, binaryPath);
231
+ if (plat !== "win32") {
232
+ chmodSync(binaryPath, 0o755);
233
+ }
234
+ return binaryPath;
235
+ }
236
+
237
+ // Download archive
238
+ const archivePath = join(TOOLS_DIR, assetName);
184
239
  await downloadFile(downloadUrl, archivePath);
185
240
 
186
241
  // Extract
@@ -231,17 +286,64 @@ async function downloadTool(tool: "fd" | "rg" | "sd" | "sg"): Promise<string> {
231
286
  return binaryPath;
232
287
  }
233
288
 
289
+ // Install a Python package via uv (preferred) or pip
290
+ function installPythonPackage(pkg: string): boolean {
291
+ // Try uv first (faster, better isolation)
292
+ const uv = commandExists("uv");
293
+ if (uv) {
294
+ const result = Bun.spawnSync([uv, "tool", "install", pkg], {
295
+ stdin: "ignore",
296
+ stdout: "pipe",
297
+ stderr: "pipe",
298
+ });
299
+ if (result.exitCode === 0) return true;
300
+ }
301
+
302
+ // Fall back to pip
303
+ const pip = commandExists("pip3") || commandExists("pip");
304
+ if (pip) {
305
+ const result = Bun.spawnSync([pip, "install", "--user", pkg], {
306
+ stdin: "ignore",
307
+ stdout: "pipe",
308
+ stderr: "pipe",
309
+ });
310
+ return result.exitCode === 0;
311
+ }
312
+
313
+ return false;
314
+ }
315
+
234
316
  // Ensure a tool is available, downloading if necessary
235
317
  // Returns the path to the tool, or null if unavailable
236
- export async function ensureTool(
237
- tool: "fd" | "rg" | "sd" | "sg",
238
- silent: boolean = false,
239
- ): Promise<string | undefined> {
318
+ export async function ensureTool(tool: ToolName, silent: boolean = false): Promise<string | undefined> {
240
319
  const existingPath = getToolPath(tool);
241
320
  if (existingPath) {
242
321
  return existingPath;
243
322
  }
244
323
 
324
+ // Handle Python tools
325
+ const pythonConfig = PYTHON_TOOLS[tool];
326
+ if (pythonConfig) {
327
+ if (!silent) {
328
+ console.log(chalk.dim(`${pythonConfig.name} not found. Installing via uv/pip...`));
329
+ }
330
+ const success = installPythonPackage(pythonConfig.package);
331
+ if (success) {
332
+ // Re-check for the command after installation
333
+ const path = commandExists(pythonConfig.binaryName);
334
+ if (path) {
335
+ if (!silent) {
336
+ console.log(chalk.dim(`${pythonConfig.name} installed successfully`));
337
+ }
338
+ return path;
339
+ }
340
+ }
341
+ if (!silent) {
342
+ console.log(chalk.yellow(`Failed to install ${pythonConfig.name}`));
343
+ }
344
+ return undefined;
345
+ }
346
+
245
347
  const config = TOOLS[tool];
246
348
  if (!config) return undefined;
247
349