@oh-my-pi/pi-coding-agent 3.25.0 → 3.31.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 (157) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/package.json +5 -5
  3. package/src/cli/args.ts +4 -0
  4. package/src/core/agent-session.ts +29 -2
  5. package/src/core/bash-executor.ts +2 -1
  6. package/src/core/custom-commands/bundled/review/index.ts +369 -14
  7. package/src/core/custom-commands/bundled/wt/index.ts +1 -1
  8. package/src/core/session-manager.ts +158 -246
  9. package/src/core/session-storage.ts +379 -0
  10. package/src/core/settings-manager.ts +155 -4
  11. package/src/core/system-prompt.ts +62 -64
  12. package/src/core/tools/ask.ts +5 -4
  13. package/src/core/tools/bash-interceptor.ts +26 -61
  14. package/src/core/tools/bash.ts +13 -8
  15. package/src/core/tools/complete.ts +2 -4
  16. package/src/core/tools/edit-diff.ts +11 -4
  17. package/src/core/tools/edit.ts +7 -13
  18. package/src/core/tools/find.ts +111 -50
  19. package/src/core/tools/gemini-image.ts +128 -147
  20. package/src/core/tools/grep.ts +397 -415
  21. package/src/core/tools/index.test.ts +5 -1
  22. package/src/core/tools/index.ts +6 -8
  23. package/src/core/tools/jtd-to-json-schema.ts +174 -196
  24. package/src/core/tools/ls.ts +12 -10
  25. package/src/core/tools/lsp/client.ts +58 -9
  26. package/src/core/tools/lsp/config.ts +205 -656
  27. package/src/core/tools/lsp/defaults.json +465 -0
  28. package/src/core/tools/lsp/index.ts +55 -32
  29. package/src/core/tools/lsp/rust-analyzer.ts +49 -10
  30. package/src/core/tools/lsp/types.ts +1 -0
  31. package/src/core/tools/lsp/utils.ts +1 -1
  32. package/src/core/tools/read.ts +152 -76
  33. package/src/core/tools/render-utils.ts +70 -10
  34. package/src/core/tools/review.ts +38 -126
  35. package/src/core/tools/task/artifacts.ts +5 -4
  36. package/src/core/tools/task/executor.ts +204 -67
  37. package/src/core/tools/task/index.ts +129 -92
  38. package/src/core/tools/task/name-generator.ts +1544 -214
  39. package/src/core/tools/task/parallel.ts +30 -3
  40. package/src/core/tools/task/render.ts +85 -39
  41. package/src/core/tools/task/types.ts +34 -11
  42. package/src/core/tools/task/worker.ts +152 -27
  43. package/src/core/tools/web-fetch.ts +220 -1657
  44. package/src/core/tools/web-scrapers/academic.test.ts +239 -0
  45. package/src/core/tools/web-scrapers/artifacthub.ts +215 -0
  46. package/src/core/tools/web-scrapers/arxiv.ts +88 -0
  47. package/src/core/tools/web-scrapers/aur.ts +175 -0
  48. package/src/core/tools/web-scrapers/biorxiv.ts +141 -0
  49. package/src/core/tools/web-scrapers/bluesky.ts +284 -0
  50. package/src/core/tools/web-scrapers/brew.ts +177 -0
  51. package/src/core/tools/web-scrapers/business.test.ts +82 -0
  52. package/src/core/tools/web-scrapers/cheatsh.ts +78 -0
  53. package/src/core/tools/web-scrapers/chocolatey.ts +158 -0
  54. package/src/core/tools/web-scrapers/choosealicense.ts +110 -0
  55. package/src/core/tools/web-scrapers/cisa-kev.ts +100 -0
  56. package/src/core/tools/web-scrapers/clojars.ts +180 -0
  57. package/src/core/tools/web-scrapers/coingecko.ts +184 -0
  58. package/src/core/tools/web-scrapers/crates-io.ts +128 -0
  59. package/src/core/tools/web-scrapers/crossref.ts +149 -0
  60. package/src/core/tools/web-scrapers/dev-platforms.test.ts +254 -0
  61. package/src/core/tools/web-scrapers/devto.ts +177 -0
  62. package/src/core/tools/web-scrapers/discogs.ts +308 -0
  63. package/src/core/tools/web-scrapers/discourse.ts +221 -0
  64. package/src/core/tools/web-scrapers/dockerhub.ts +160 -0
  65. package/src/core/tools/web-scrapers/documentation.test.ts +85 -0
  66. package/src/core/tools/web-scrapers/fdroid.ts +158 -0
  67. package/src/core/tools/web-scrapers/finance-media.test.ts +144 -0
  68. package/src/core/tools/web-scrapers/firefox-addons.ts +214 -0
  69. package/src/core/tools/web-scrapers/flathub.ts +239 -0
  70. package/src/core/tools/web-scrapers/git-hosting.test.ts +272 -0
  71. package/src/core/tools/web-scrapers/github-gist.ts +68 -0
  72. package/src/core/tools/web-scrapers/github.ts +455 -0
  73. package/src/core/tools/web-scrapers/gitlab.ts +456 -0
  74. package/src/core/tools/web-scrapers/go-pkg.ts +275 -0
  75. package/src/core/tools/web-scrapers/hackage.ts +94 -0
  76. package/src/core/tools/web-scrapers/hackernews.ts +208 -0
  77. package/src/core/tools/web-scrapers/hex.ts +121 -0
  78. package/src/core/tools/web-scrapers/huggingface.ts +385 -0
  79. package/src/core/tools/web-scrapers/iacr.ts +86 -0
  80. package/src/core/tools/web-scrapers/index.ts +250 -0
  81. package/src/core/tools/web-scrapers/jetbrains-marketplace.ts +169 -0
  82. package/src/core/tools/web-scrapers/lemmy.ts +220 -0
  83. package/src/core/tools/web-scrapers/lobsters.ts +186 -0
  84. package/src/core/tools/web-scrapers/mastodon.ts +310 -0
  85. package/src/core/tools/web-scrapers/maven.ts +152 -0
  86. package/src/core/tools/web-scrapers/mdn.ts +174 -0
  87. package/src/core/tools/web-scrapers/media.test.ts +138 -0
  88. package/src/core/tools/web-scrapers/metacpan.ts +253 -0
  89. package/src/core/tools/web-scrapers/musicbrainz.ts +273 -0
  90. package/src/core/tools/web-scrapers/npm.ts +114 -0
  91. package/src/core/tools/web-scrapers/nuget.ts +205 -0
  92. package/src/core/tools/web-scrapers/nvd.ts +243 -0
  93. package/src/core/tools/web-scrapers/ollama.ts +267 -0
  94. package/src/core/tools/web-scrapers/open-vsx.ts +119 -0
  95. package/src/core/tools/web-scrapers/opencorporates.ts +275 -0
  96. package/src/core/tools/web-scrapers/openlibrary.ts +319 -0
  97. package/src/core/tools/web-scrapers/orcid.ts +299 -0
  98. package/src/core/tools/web-scrapers/osv.ts +189 -0
  99. package/src/core/tools/web-scrapers/package-managers-2.test.ts +199 -0
  100. package/src/core/tools/web-scrapers/package-managers.test.ts +171 -0
  101. package/src/core/tools/web-scrapers/package-registries.test.ts +259 -0
  102. package/src/core/tools/web-scrapers/packagist.ts +174 -0
  103. package/src/core/tools/web-scrapers/pub-dev.ts +185 -0
  104. package/src/core/tools/web-scrapers/pubmed.ts +178 -0
  105. package/src/core/tools/web-scrapers/pypi.ts +129 -0
  106. package/src/core/tools/web-scrapers/rawg.ts +124 -0
  107. package/src/core/tools/web-scrapers/readthedocs.ts +126 -0
  108. package/src/core/tools/web-scrapers/reddit.ts +104 -0
  109. package/src/core/tools/web-scrapers/repology.ts +262 -0
  110. package/src/core/tools/web-scrapers/research.test.ts +107 -0
  111. package/src/core/tools/web-scrapers/rfc.ts +209 -0
  112. package/src/core/tools/web-scrapers/rubygems.ts +117 -0
  113. package/src/core/tools/web-scrapers/searchcode.ts +217 -0
  114. package/src/core/tools/web-scrapers/sec-edgar.ts +274 -0
  115. package/src/core/tools/web-scrapers/security.test.ts +103 -0
  116. package/src/core/tools/web-scrapers/semantic-scholar.ts +190 -0
  117. package/src/core/tools/web-scrapers/snapcraft.ts +200 -0
  118. package/src/core/tools/web-scrapers/social-extended.test.ts +192 -0
  119. package/src/core/tools/web-scrapers/social.test.ts +259 -0
  120. package/src/core/tools/web-scrapers/sourcegraph.ts +373 -0
  121. package/src/core/tools/web-scrapers/spdx.ts +121 -0
  122. package/src/core/tools/web-scrapers/spotify.ts +218 -0
  123. package/src/core/tools/web-scrapers/stackexchange.test.ts +120 -0
  124. package/src/core/tools/web-scrapers/stackoverflow.ts +124 -0
  125. package/src/core/tools/web-scrapers/standards.test.ts +122 -0
  126. package/src/core/tools/web-scrapers/terraform.ts +304 -0
  127. package/src/core/tools/web-scrapers/tldr.ts +51 -0
  128. package/src/core/tools/web-scrapers/twitter.ts +96 -0
  129. package/src/core/tools/web-scrapers/types.ts +234 -0
  130. package/src/core/tools/web-scrapers/utils.ts +162 -0
  131. package/src/core/tools/web-scrapers/vimeo.ts +152 -0
  132. package/src/core/tools/web-scrapers/vscode-marketplace.ts +195 -0
  133. package/src/core/tools/web-scrapers/w3c.ts +163 -0
  134. package/src/core/tools/web-scrapers/wikidata.ts +357 -0
  135. package/src/core/tools/web-scrapers/wikipedia.test.ts +73 -0
  136. package/src/core/tools/web-scrapers/wikipedia.ts +95 -0
  137. package/src/core/tools/web-scrapers/youtube.test.ts +198 -0
  138. package/src/core/tools/web-scrapers/youtube.ts +371 -0
  139. package/src/core/tools/write.ts +21 -18
  140. package/src/core/voice.ts +3 -2
  141. package/src/lib/worktree/collapse.ts +2 -1
  142. package/src/lib/worktree/git.ts +2 -18
  143. package/src/main.ts +59 -3
  144. package/src/modes/interactive/components/extensions/extension-dashboard.ts +33 -19
  145. package/src/modes/interactive/components/extensions/extension-list.ts +15 -8
  146. package/src/modes/interactive/components/hook-editor.ts +2 -1
  147. package/src/modes/interactive/components/model-selector.ts +19 -4
  148. package/src/modes/interactive/interactive-mode.ts +41 -38
  149. package/src/modes/interactive/theme/theme.ts +58 -58
  150. package/src/modes/rpc/rpc-mode.ts +10 -9
  151. package/src/prompts/review-request.md +27 -0
  152. package/src/prompts/reviewer.md +64 -68
  153. package/src/prompts/tools/output.md +22 -3
  154. package/src/prompts/tools/task.md +32 -33
  155. package/src/utils/clipboard.ts +2 -1
  156. package/src/utils/tools-manager.ts +110 -8
  157. package/examples/extensions/subagent/agents/reviewer.md +0 -35
@@ -1,4 +1,5 @@
1
1
  import * as fs from "node:fs";
2
+ import { logger } from "../../logger";
2
3
  import { applyWorkspaceEdit } from "./edits";
3
4
  import type {
4
5
  Diagnostic,
@@ -266,6 +267,7 @@ async function startMessageReader(client: LspClient): Promise<void> {
266
267
  if (message.method === "textDocument/publishDiagnostics" && message.params) {
267
268
  const params = message.params as { uri: string; diagnostics: Diagnostic[] };
268
269
  client.diagnostics.set(params.uri, params.diagnostics);
270
+ client.diagnosticsVersion += 1;
269
271
  }
270
272
  }
271
273
 
@@ -363,7 +365,7 @@ async function sendResponse(
363
365
  try {
364
366
  await writeMessage(client.process.stdin as import("bun").FileSink, response);
365
367
  } catch (err) {
366
- console.error(`[LSP] Failed to respond to ${method}: ${err}`);
368
+ logger.error("LSP failed to respond.", { method, error: String(err) });
367
369
  }
368
370
  }
369
371
 
@@ -408,6 +410,7 @@ export async function getOrCreateClient(config: ServerConfig, cwd: string): Prom
408
410
  config,
409
411
  requestId: 0,
410
412
  diagnostics: new Map(),
413
+ diagnosticsVersion: 0,
411
414
  openFiles: new Map(),
412
415
  pendingRequests: new Map(),
413
416
  messageBuffer: new Uint8Array(0),
@@ -516,9 +519,15 @@ export async function ensureFileOpen(client: LspClient, filePath: string): Promi
516
519
  * Sync in-memory content to the LSP client without reading from disk.
517
520
  * Use this to provide instant feedback during edits before the file is saved.
518
521
  */
519
- export async function syncContent(client: LspClient, filePath: string, content: string): Promise<void> {
522
+ export async function syncContent(
523
+ client: LspClient,
524
+ filePath: string,
525
+ content: string,
526
+ signal?: AbortSignal,
527
+ ): Promise<void> {
520
528
  const uri = fileToUri(filePath);
521
529
  const lockKey = `${client.name}:${uri}`;
530
+ signal?.throwIfAborted();
522
531
 
523
532
  const existingLock = fileOperationLocks.get(lockKey);
524
533
  if (existingLock) {
@@ -534,6 +543,7 @@ export async function syncContent(client: LspClient, filePath: string, content:
534
543
  if (!info) {
535
544
  // Open file with provided content instead of reading from disk
536
545
  const languageId = detectLanguageId(filePath);
546
+ signal?.throwIfAborted();
537
547
  await sendNotification(client, "textDocument/didOpen", {
538
548
  textDocument: {
539
549
  uri,
@@ -548,6 +558,7 @@ export async function syncContent(client: LspClient, filePath: string, content:
548
558
  }
549
559
 
550
560
  const version = ++info.version;
561
+ signal?.throwIfAborted();
551
562
  await sendNotification(client, "textDocument/didChange", {
552
563
  textDocument: { uri, version },
553
564
  contentChanges: [{ text: content }],
@@ -567,11 +578,12 @@ export async function syncContent(client: LspClient, filePath: string, content:
567
578
  * Notify LSP that a file was saved.
568
579
  * Assumes content was already synced via syncContent - just sends didSave.
569
580
  */
570
- export async function notifySaved(client: LspClient, filePath: string): Promise<void> {
581
+ export async function notifySaved(client: LspClient, filePath: string, signal?: AbortSignal): Promise<void> {
571
582
  const uri = fileToUri(filePath);
572
583
  const info = client.openFiles.get(uri);
573
584
  if (!info) return; // File not open, nothing to notify
574
585
 
586
+ signal?.throwIfAborted();
575
587
  await sendNotification(client, "textDocument/didSave", {
576
588
  textDocument: { uri },
577
589
  });
@@ -653,9 +665,18 @@ export function shutdownClient(key: string): void {
653
665
  /**
654
666
  * Send an LSP request and wait for response.
655
667
  */
656
- export async function sendRequest(client: LspClient, method: string, params: unknown): Promise<unknown> {
668
+ export async function sendRequest(
669
+ client: LspClient,
670
+ method: string,
671
+ params: unknown,
672
+ signal?: AbortSignal,
673
+ ): Promise<unknown> {
657
674
  // Atomically increment and capture request ID
658
675
  const id = ++client.requestId;
676
+ if (signal?.aborted) {
677
+ const reason = signal.reason instanceof Error ? signal.reason : new Error("Operation aborted");
678
+ return Promise.reject(reason);
679
+ }
659
680
 
660
681
  const request: LspJsonRpcRequest = {
661
682
  jsonrpc: "2.0",
@@ -667,22 +688,49 @@ export async function sendRequest(client: LspClient, method: string, params: unk
667
688
  client.lastActivity = Date.now();
668
689
 
669
690
  return new Promise((resolve, reject) => {
691
+ let timeout: ReturnType<typeof setTimeout> | undefined;
692
+ const cleanup = () => {
693
+ if (signal) {
694
+ signal.removeEventListener("abort", abortHandler);
695
+ }
696
+ };
697
+ const abortHandler = () => {
698
+ if (client.pendingRequests.has(id)) {
699
+ client.pendingRequests.delete(id);
700
+ }
701
+ if (timeout) clearTimeout(timeout);
702
+ cleanup();
703
+ const reason = signal?.reason instanceof Error ? signal.reason : new Error("Operation aborted");
704
+ reject(reason);
705
+ };
706
+
670
707
  // Set timeout
671
- const timeout = setTimeout(() => {
708
+ timeout = setTimeout(() => {
672
709
  if (client.pendingRequests.has(id)) {
673
710
  client.pendingRequests.delete(id);
674
- reject(new Error(`LSP request ${method} timed out`));
711
+ const err = new Error(`LSP request ${method} timed out`);
712
+ cleanup();
713
+ reject(err);
675
714
  }
676
715
  }, 30000);
716
+ if (signal) {
717
+ signal.addEventListener("abort", abortHandler, { once: true });
718
+ if (signal.aborted) {
719
+ abortHandler();
720
+ return;
721
+ }
722
+ }
677
723
 
678
724
  // Register pending request with timeout wrapper
679
725
  client.pendingRequests.set(id, {
680
726
  resolve: (result) => {
681
- clearTimeout(timeout);
727
+ if (timeout) clearTimeout(timeout);
728
+ cleanup();
682
729
  resolve(result);
683
730
  },
684
731
  reject: (err) => {
685
- clearTimeout(timeout);
732
+ if (timeout) clearTimeout(timeout);
733
+ cleanup();
686
734
  reject(err);
687
735
  },
688
736
  method,
@@ -690,8 +738,9 @@ export async function sendRequest(client: LspClient, method: string, params: unk
690
738
 
691
739
  // Write request
692
740
  writeMessage(client.process.stdin as import("bun").FileSink, request).catch((err) => {
693
- clearTimeout(timeout);
741
+ if (timeout) clearTimeout(timeout);
694
742
  client.pendingRequests.delete(id);
743
+ cleanup();
695
744
  reject(err);
696
745
  });
697
746
  });