@ilya-lesikov/pi-pi 0.1.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 (271) hide show
  1. package/3p/pi-ask-user/index.ts +1835 -0
  2. package/3p/pi-ask-user/package.json +50 -0
  3. package/3p/pi-ask-user/single-select-layout.ts +203 -0
  4. package/3p/pi-lsp/extensions/lsp/client.ts +542 -0
  5. package/3p/pi-lsp/extensions/lsp/config.ts +135 -0
  6. package/3p/pi-lsp/extensions/lsp/effects/command.ts +42 -0
  7. package/3p/pi-lsp/extensions/lsp/effects/filesystem.ts +50 -0
  8. package/3p/pi-lsp/extensions/lsp/effects/runtime.ts +21 -0
  9. package/3p/pi-lsp/extensions/lsp/errors.ts +113 -0
  10. package/3p/pi-lsp/extensions/lsp/formatting.ts +315 -0
  11. package/3p/pi-lsp/extensions/lsp/index.ts +231 -0
  12. package/3p/pi-lsp/extensions/lsp/protocol.ts +209 -0
  13. package/3p/pi-lsp/extensions/lsp/retry.ts +39 -0
  14. package/3p/pi-lsp/extensions/lsp/tools/programs.ts +293 -0
  15. package/3p/pi-lsp/extensions/lsp/tools.ts +89 -0
  16. package/3p/pi-lsp/extensions/lsp/types.ts +243 -0
  17. package/3p/pi-lsp/package.json +54 -0
  18. package/3p/pi-plannotator/AGENTS.md +583 -0
  19. package/3p/pi-plannotator/apps/pi-extension/README.md +228 -0
  20. package/3p/pi-plannotator/apps/pi-extension/assistant-message.ts +128 -0
  21. package/3p/pi-plannotator/apps/pi-extension/config.test.ts +166 -0
  22. package/3p/pi-plannotator/apps/pi-extension/config.ts +318 -0
  23. package/3p/pi-plannotator/apps/pi-extension/current-pi-session.ts +147 -0
  24. package/3p/pi-plannotator/apps/pi-extension/index.ts +1279 -0
  25. package/3p/pi-plannotator/apps/pi-extension/package.json +56 -0
  26. package/3p/pi-plannotator/apps/pi-extension/plannotator-browser.test.ts +13 -0
  27. package/3p/pi-plannotator/apps/pi-extension/plannotator-browser.ts +616 -0
  28. package/3p/pi-plannotator/apps/pi-extension/plannotator-events.ts +342 -0
  29. package/3p/pi-plannotator/apps/pi-extension/plannotator.json +12 -0
  30. package/3p/pi-plannotator/apps/pi-extension/server/agent-jobs.ts +515 -0
  31. package/3p/pi-plannotator/apps/pi-extension/server/ai-runtime.ts +169 -0
  32. package/3p/pi-plannotator/apps/pi-extension/server/annotations.ts +85 -0
  33. package/3p/pi-plannotator/apps/pi-extension/server/external-annotations.ts +189 -0
  34. package/3p/pi-plannotator/apps/pi-extension/server/handlers.ts +210 -0
  35. package/3p/pi-plannotator/apps/pi-extension/server/helpers.ts +78 -0
  36. package/3p/pi-plannotator/apps/pi-extension/server/ide.ts +46 -0
  37. package/3p/pi-plannotator/apps/pi-extension/server/integrations.ts +195 -0
  38. package/3p/pi-plannotator/apps/pi-extension/server/network.test.ts +158 -0
  39. package/3p/pi-plannotator/apps/pi-extension/server/network.ts +268 -0
  40. package/3p/pi-plannotator/apps/pi-extension/server/pr.ts +126 -0
  41. package/3p/pi-plannotator/apps/pi-extension/server/project.ts +64 -0
  42. package/3p/pi-plannotator/apps/pi-extension/server/reference.ts +362 -0
  43. package/3p/pi-plannotator/apps/pi-extension/server/serverAnnotate.ts +199 -0
  44. package/3p/pi-plannotator/apps/pi-extension/server/serverPlan.ts +505 -0
  45. package/3p/pi-plannotator/apps/pi-extension/server/serverReview.ts +1229 -0
  46. package/3p/pi-plannotator/apps/pi-extension/server/vcs.ts +121 -0
  47. package/3p/pi-plannotator/apps/pi-extension/server.test.ts +966 -0
  48. package/3p/pi-plannotator/apps/pi-extension/server.ts +44 -0
  49. package/3p/pi-plannotator/apps/pi-extension/tool-scope.test.ts +88 -0
  50. package/3p/pi-plannotator/apps/pi-extension/tool-scope.ts +39 -0
  51. package/3p/pi-plannotator/apps/pi-extension/tsconfig.json +16 -0
  52. package/3p/pi-plannotator/apps/pi-extension/vendor.sh +48 -0
  53. package/3p/pi-plannotator/package.json +53 -0
  54. package/3p/pi-plannotator/packages/ai/ai.test.ts +1407 -0
  55. package/3p/pi-plannotator/packages/ai/base-session.ts +94 -0
  56. package/3p/pi-plannotator/packages/ai/context.ts +250 -0
  57. package/3p/pi-plannotator/packages/ai/endpoints.ts +326 -0
  58. package/3p/pi-plannotator/packages/ai/index.ts +105 -0
  59. package/3p/pi-plannotator/packages/ai/package.json +21 -0
  60. package/3p/pi-plannotator/packages/ai/provider.ts +103 -0
  61. package/3p/pi-plannotator/packages/ai/providers/claude-agent-sdk.ts +447 -0
  62. package/3p/pi-plannotator/packages/ai/providers/codex-sdk.ts +430 -0
  63. package/3p/pi-plannotator/packages/ai/providers/command-path.ts +115 -0
  64. package/3p/pi-plannotator/packages/ai/providers/opencode-sdk.ts +546 -0
  65. package/3p/pi-plannotator/packages/ai/providers/pi-events.ts +110 -0
  66. package/3p/pi-plannotator/packages/ai/providers/pi-sdk-node.ts +425 -0
  67. package/3p/pi-plannotator/packages/ai/providers/pi-sdk.ts +469 -0
  68. package/3p/pi-plannotator/packages/ai/session-manager.ts +195 -0
  69. package/3p/pi-plannotator/packages/ai/tsconfig.json +15 -0
  70. package/3p/pi-plannotator/packages/ai/types.ts +379 -0
  71. package/3p/pi-plannotator/packages/server/agent-jobs.ts +538 -0
  72. package/3p/pi-plannotator/packages/server/agent-review-message.test.ts +135 -0
  73. package/3p/pi-plannotator/packages/server/agent-review-message.ts +243 -0
  74. package/3p/pi-plannotator/packages/server/ai-runtime.ts +108 -0
  75. package/3p/pi-plannotator/packages/server/annotate.ts +401 -0
  76. package/3p/pi-plannotator/packages/server/browser.test.ts +87 -0
  77. package/3p/pi-plannotator/packages/server/browser.ts +245 -0
  78. package/3p/pi-plannotator/packages/server/claude-review.ts +352 -0
  79. package/3p/pi-plannotator/packages/server/code-nav.ts +73 -0
  80. package/3p/pi-plannotator/packages/server/codex-review-schema.json +41 -0
  81. package/3p/pi-plannotator/packages/server/codex-review.ts +330 -0
  82. package/3p/pi-plannotator/packages/server/config.ts +8 -0
  83. package/3p/pi-plannotator/packages/server/draft.ts +1 -0
  84. package/3p/pi-plannotator/packages/server/editor-annotations.ts +76 -0
  85. package/3p/pi-plannotator/packages/server/external-annotations.test.ts +18 -0
  86. package/3p/pi-plannotator/packages/server/external-annotations.ts +207 -0
  87. package/3p/pi-plannotator/packages/server/git.ts +141 -0
  88. package/3p/pi-plannotator/packages/server/goal-setup.test.ts +55 -0
  89. package/3p/pi-plannotator/packages/server/goal-setup.ts +248 -0
  90. package/3p/pi-plannotator/packages/server/ide.ts +43 -0
  91. package/3p/pi-plannotator/packages/server/image.test.ts +63 -0
  92. package/3p/pi-plannotator/packages/server/image.ts +66 -0
  93. package/3p/pi-plannotator/packages/server/index.ts +648 -0
  94. package/3p/pi-plannotator/packages/server/integrations.test.ts +172 -0
  95. package/3p/pi-plannotator/packages/server/integrations.ts +214 -0
  96. package/3p/pi-plannotator/packages/server/jj.test.ts +69 -0
  97. package/3p/pi-plannotator/packages/server/jj.ts +86 -0
  98. package/3p/pi-plannotator/packages/server/p4.ts +417 -0
  99. package/3p/pi-plannotator/packages/server/package.json +40 -0
  100. package/3p/pi-plannotator/packages/server/path-utils.ts +18 -0
  101. package/3p/pi-plannotator/packages/server/pr.ts +146 -0
  102. package/3p/pi-plannotator/packages/server/project.test.ts +115 -0
  103. package/3p/pi-plannotator/packages/server/project.ts +45 -0
  104. package/3p/pi-plannotator/packages/server/reference-handlers.ts +404 -0
  105. package/3p/pi-plannotator/packages/server/remote.test.ts +150 -0
  106. package/3p/pi-plannotator/packages/server/remote.ts +74 -0
  107. package/3p/pi-plannotator/packages/server/repo.ts +80 -0
  108. package/3p/pi-plannotator/packages/server/resolve-file.test.ts +310 -0
  109. package/3p/pi-plannotator/packages/server/review-workspace.test.ts +1032 -0
  110. package/3p/pi-plannotator/packages/server/review-workspace.ts +48 -0
  111. package/3p/pi-plannotator/packages/server/review.ts +1318 -0
  112. package/3p/pi-plannotator/packages/server/sessions.ts +111 -0
  113. package/3p/pi-plannotator/packages/server/share-url.ts +53 -0
  114. package/3p/pi-plannotator/packages/server/shared-handlers.test.ts +43 -0
  115. package/3p/pi-plannotator/packages/server/shared-handlers.ts +177 -0
  116. package/3p/pi-plannotator/packages/server/storage.test.ts +176 -0
  117. package/3p/pi-plannotator/packages/server/storage.ts +17 -0
  118. package/3p/pi-plannotator/packages/server/tour/tour-review.test.ts +146 -0
  119. package/3p/pi-plannotator/packages/server/tour/tour-review.ts +604 -0
  120. package/3p/pi-plannotator/packages/server/tsconfig.json +15 -0
  121. package/3p/pi-plannotator/packages/server/vcs.test.ts +48 -0
  122. package/3p/pi-plannotator/packages/server/vcs.ts +80 -0
  123. package/3p/pi-plannotator/packages/shared/agent-jobs.ts +132 -0
  124. package/3p/pi-plannotator/packages/shared/agents.ts +53 -0
  125. package/3p/pi-plannotator/packages/shared/annotate-args.test.ts +386 -0
  126. package/3p/pi-plannotator/packages/shared/annotate-args.ts +107 -0
  127. package/3p/pi-plannotator/packages/shared/at-reference.test.ts +99 -0
  128. package/3p/pi-plannotator/packages/shared/at-reference.ts +52 -0
  129. package/3p/pi-plannotator/packages/shared/checklist.ts +52 -0
  130. package/3p/pi-plannotator/packages/shared/code-file.test.ts +112 -0
  131. package/3p/pi-plannotator/packages/shared/code-file.ts +41 -0
  132. package/3p/pi-plannotator/packages/shared/code-nav.test.ts +515 -0
  133. package/3p/pi-plannotator/packages/shared/code-nav.ts +436 -0
  134. package/3p/pi-plannotator/packages/shared/compress.ts +51 -0
  135. package/3p/pi-plannotator/packages/shared/config.ts +262 -0
  136. package/3p/pi-plannotator/packages/shared/crypto.test.ts +172 -0
  137. package/3p/pi-plannotator/packages/shared/crypto.ts +97 -0
  138. package/3p/pi-plannotator/packages/shared/data-dir.ts +42 -0
  139. package/3p/pi-plannotator/packages/shared/diff-paths.test.ts +30 -0
  140. package/3p/pi-plannotator/packages/shared/diff-paths.ts +137 -0
  141. package/3p/pi-plannotator/packages/shared/draft.ts +64 -0
  142. package/3p/pi-plannotator/packages/shared/external-annotation.ts +397 -0
  143. package/3p/pi-plannotator/packages/shared/extract-code-paths.test.ts +59 -0
  144. package/3p/pi-plannotator/packages/shared/extract-code-paths.ts +66 -0
  145. package/3p/pi-plannotator/packages/shared/favicon.ts +5 -0
  146. package/3p/pi-plannotator/packages/shared/feedback-templates.test.ts +65 -0
  147. package/3p/pi-plannotator/packages/shared/feedback-templates.ts +29 -0
  148. package/3p/pi-plannotator/packages/shared/goal-setup.test.ts +231 -0
  149. package/3p/pi-plannotator/packages/shared/goal-setup.ts +336 -0
  150. package/3p/pi-plannotator/packages/shared/html-to-markdown.test.ts +62 -0
  151. package/3p/pi-plannotator/packages/shared/html-to-markdown.ts +32 -0
  152. package/3p/pi-plannotator/packages/shared/improvement-hooks.test.ts +135 -0
  153. package/3p/pi-plannotator/packages/shared/improvement-hooks.ts +115 -0
  154. package/3p/pi-plannotator/packages/shared/integrations-common.ts +243 -0
  155. package/3p/pi-plannotator/packages/shared/jj-core.test.ts +236 -0
  156. package/3p/pi-plannotator/packages/shared/jj-core.ts +433 -0
  157. package/3p/pi-plannotator/packages/shared/package.json +55 -0
  158. package/3p/pi-plannotator/packages/shared/pfm-reminder.test.ts +88 -0
  159. package/3p/pi-plannotator/packages/shared/pfm-reminder.ts +80 -0
  160. package/3p/pi-plannotator/packages/shared/pr-github.ts +661 -0
  161. package/3p/pi-plannotator/packages/shared/pr-gitlab.test.ts +202 -0
  162. package/3p/pi-plannotator/packages/shared/pr-gitlab.ts +620 -0
  163. package/3p/pi-plannotator/packages/shared/pr-provider.test.ts +266 -0
  164. package/3p/pi-plannotator/packages/shared/pr-provider.ts +123 -0
  165. package/3p/pi-plannotator/packages/shared/pr-stack.test.ts +104 -0
  166. package/3p/pi-plannotator/packages/shared/pr-stack.ts +194 -0
  167. package/3p/pi-plannotator/packages/shared/pr-types.ts +326 -0
  168. package/3p/pi-plannotator/packages/shared/project.ts +71 -0
  169. package/3p/pi-plannotator/packages/shared/prompts-integration.test.ts +421 -0
  170. package/3p/pi-plannotator/packages/shared/prompts.test.ts +504 -0
  171. package/3p/pi-plannotator/packages/shared/prompts.ts +247 -0
  172. package/3p/pi-plannotator/packages/shared/reference-common.ts +87 -0
  173. package/3p/pi-plannotator/packages/shared/repo.ts +71 -0
  174. package/3p/pi-plannotator/packages/shared/resolve-file.test.ts +113 -0
  175. package/3p/pi-plannotator/packages/shared/resolve-file.ts +509 -0
  176. package/3p/pi-plannotator/packages/shared/review-args.test.ts +64 -0
  177. package/3p/pi-plannotator/packages/shared/review-args.ts +85 -0
  178. package/3p/pi-plannotator/packages/shared/review-core.test.ts +286 -0
  179. package/3p/pi-plannotator/packages/shared/review-core.ts +895 -0
  180. package/3p/pi-plannotator/packages/shared/review-workspace-node.ts +230 -0
  181. package/3p/pi-plannotator/packages/shared/review-workspace.ts +436 -0
  182. package/3p/pi-plannotator/packages/shared/semantic-diff-types.ts +76 -0
  183. package/3p/pi-plannotator/packages/shared/semantic-diff.test.ts +322 -0
  184. package/3p/pi-plannotator/packages/shared/semantic-diff.ts +520 -0
  185. package/3p/pi-plannotator/packages/shared/storage.ts +378 -0
  186. package/3p/pi-plannotator/packages/shared/tour.ts +61 -0
  187. package/3p/pi-plannotator/packages/shared/tsconfig.json +15 -0
  188. package/3p/pi-plannotator/packages/shared/types.ts +29 -0
  189. package/3p/pi-plannotator/packages/shared/url-to-markdown.test.ts +177 -0
  190. package/3p/pi-plannotator/packages/shared/url-to-markdown.ts +351 -0
  191. package/3p/pi-plannotator/packages/shared/vcs-core.test.ts +332 -0
  192. package/3p/pi-plannotator/packages/shared/vcs-core.ts +482 -0
  193. package/3p/pi-plannotator/packages/shared/worktree-pool.test.ts +162 -0
  194. package/3p/pi-plannotator/packages/shared/worktree-pool.ts +103 -0
  195. package/3p/pi-plannotator/packages/shared/worktree.ts +119 -0
  196. package/3p/pi-subagents/package.json +50 -0
  197. package/3p/pi-subagents/src/agent-manager.ts +413 -0
  198. package/3p/pi-subagents/src/agent-runner.ts +502 -0
  199. package/3p/pi-subagents/src/agent-types.ts +248 -0
  200. package/3p/pi-subagents/src/context.ts +58 -0
  201. package/3p/pi-subagents/src/cross-extension-rpc.ts +135 -0
  202. package/3p/pi-subagents/src/custom-agents.ts +137 -0
  203. package/3p/pi-subagents/src/default-agents.ts +144 -0
  204. package/3p/pi-subagents/src/env.ts +33 -0
  205. package/3p/pi-subagents/src/group-join.ts +141 -0
  206. package/3p/pi-subagents/src/index.ts +1811 -0
  207. package/3p/pi-subagents/src/invocation-config.ts +40 -0
  208. package/3p/pi-subagents/src/memory.ts +165 -0
  209. package/3p/pi-subagents/src/model-resolver.ts +81 -0
  210. package/3p/pi-subagents/src/output-file.ts +77 -0
  211. package/3p/pi-subagents/src/prompts.ts +85 -0
  212. package/3p/pi-subagents/src/skill-loader.ts +79 -0
  213. package/3p/pi-subagents/src/types.ts +111 -0
  214. package/3p/pi-subagents/src/ui/agent-widget.ts +496 -0
  215. package/3p/pi-subagents/src/ui/conversation-viewer.ts +250 -0
  216. package/3p/pi-subagents/src/worktree.ts +162 -0
  217. package/3p/pi-tasks/package.json +52 -0
  218. package/3p/pi-tasks/src/auto-clear.ts +91 -0
  219. package/3p/pi-tasks/src/index.ts +1150 -0
  220. package/3p/pi-tasks/src/process-tracker.ts +140 -0
  221. package/3p/pi-tasks/src/reminder-cadence.ts +90 -0
  222. package/3p/pi-tasks/src/task-store.ts +324 -0
  223. package/3p/pi-tasks/src/tasks-config.ts +27 -0
  224. package/3p/pi-tasks/src/types.ts +40 -0
  225. package/3p/pi-tasks/src/ui/settings-menu.ts +152 -0
  226. package/3p/pi-tasks/src/ui/task-widget.ts +296 -0
  227. package/AGENTS.md +28 -0
  228. package/LICENSE +201 -0
  229. package/extensions/orchestrator/agents/brainstorm-reviewer.ts +77 -0
  230. package/extensions/orchestrator/agents/code-reviewer.ts +89 -0
  231. package/extensions/orchestrator/agents/explore.ts +33 -0
  232. package/extensions/orchestrator/agents/librarian.ts +43 -0
  233. package/extensions/orchestrator/agents/plan-reviewer.ts +75 -0
  234. package/extensions/orchestrator/agents/planner.ts +61 -0
  235. package/extensions/orchestrator/agents/registry.ts +156 -0
  236. package/extensions/orchestrator/agents/task.ts +50 -0
  237. package/extensions/orchestrator/agents/tool-routing.ts +84 -0
  238. package/extensions/orchestrator/ast-search.ts +85 -0
  239. package/extensions/orchestrator/cbm.ts +330 -0
  240. package/extensions/orchestrator/command-handlers.test.ts +163 -0
  241. package/extensions/orchestrator/command-handlers.ts +116 -0
  242. package/extensions/orchestrator/commands.test.ts +81 -0
  243. package/extensions/orchestrator/commands.ts +75 -0
  244. package/extensions/orchestrator/config.test.ts +221 -0
  245. package/extensions/orchestrator/config.ts +230 -0
  246. package/extensions/orchestrator/context.test.ts +293 -0
  247. package/extensions/orchestrator/context.ts +206 -0
  248. package/extensions/orchestrator/event-handlers.test.ts +190 -0
  249. package/extensions/orchestrator/event-handlers.ts +1416 -0
  250. package/extensions/orchestrator/exa.ts +104 -0
  251. package/extensions/orchestrator/flant-infra.ts +486 -0
  252. package/extensions/orchestrator/index.ts +80 -0
  253. package/extensions/orchestrator/integration.test.ts +1214 -0
  254. package/extensions/orchestrator/orchestrator.test.ts +252 -0
  255. package/extensions/orchestrator/orchestrator.ts +538 -0
  256. package/extensions/orchestrator/phases/brainstorm.test.ts +15 -0
  257. package/extensions/orchestrator/phases/brainstorm.ts +273 -0
  258. package/extensions/orchestrator/phases/implementation.ts +40 -0
  259. package/extensions/orchestrator/phases/machine.test.ts +293 -0
  260. package/extensions/orchestrator/phases/machine.ts +209 -0
  261. package/extensions/orchestrator/phases/planning.ts +255 -0
  262. package/extensions/orchestrator/phases/review.ts +193 -0
  263. package/extensions/orchestrator/plannotator.ts +56 -0
  264. package/extensions/orchestrator/pp-menu.ts +866 -0
  265. package/extensions/orchestrator/state.test.ts +343 -0
  266. package/extensions/orchestrator/state.ts +237 -0
  267. package/extensions/orchestrator/validate-artifacts.test.ts +88 -0
  268. package/extensions/orchestrator/validate-artifacts.ts +272 -0
  269. package/extensions/orchestrator/vendor.d.ts +26 -0
  270. package/package.json +73 -0
  271. package/scripts/postinstall.sh +18 -0
@@ -0,0 +1,293 @@
1
+ /**
2
+ * Effect programs backing the unified `lsp` tool.
3
+ *
4
+ * Each operation is an Effect that depends on the `ServerManager` service to
5
+ * locate the right client, then wraps the client's async LSP calls in
6
+ * `Effect.tryPromise` so transport failures surface as typed
7
+ * `LspOperationError`s. Routing/validation failures are typed too
8
+ * (`LspValidationError`, `NoCapableServerError`, `NoServerAvailableError`).
9
+ */
10
+
11
+ import { Context, Effect } from 'effect';
12
+
13
+ import type { LspClient } from '../client';
14
+ import {
15
+ LspOperationError,
16
+ LspValidationError,
17
+ NoCapableServerError,
18
+ NoServerAvailableError,
19
+ type LspExtensionError,
20
+ } from '../errors';
21
+ import {
22
+ formatCallHierarchy,
23
+ formatCodeActions,
24
+ formatDiagnostics,
25
+ formatDocumentSymbols,
26
+ formatHover,
27
+ formatIncomingCalls,
28
+ formatLocations,
29
+ formatOutgoingCalls,
30
+ formatWorkspaceSymbols,
31
+ } from '../formatting';
32
+ import type { Diagnostic } from '../types';
33
+ import {
34
+ FILE_ONLY_OPERATIONS,
35
+ type LspOperation,
36
+ POSITION_OPERATIONS,
37
+ QUERY_OPERATIONS,
38
+ } from '../types';
39
+
40
+ // ── ServerManager service ─────────────────────────────────────────────────────
41
+
42
+ export interface ServerManagerService {
43
+ /** Get all LSP clients that handle a given file extension. */
44
+ clientsForFile: (filePath: string) => LspClient[];
45
+ /** Get the first LSP client that handles a file and has a capability. */
46
+ clientForFileWithCapability: (filePath: string, capability: string) => LspClient | null;
47
+ /** Get any initialized client (for workspace-wide ops). */
48
+ anyClient: () => LspClient | null;
49
+ /** Current root path. */
50
+ getRootPath: () => string;
51
+ }
52
+
53
+ export class ServerManager extends Context.Tag('Lsp/ServerManager')<
54
+ ServerManager,
55
+ ServerManagerService
56
+ >() {}
57
+
58
+ export interface ToolResult {
59
+ content: { type: 'text'; text: string }[];
60
+ details: Record<string, unknown>;
61
+ }
62
+
63
+ export interface LspToolParams {
64
+ operation: LspOperation;
65
+ filePath?: string;
66
+ line?: number;
67
+ character?: number;
68
+ query?: string;
69
+ }
70
+
71
+ // ── Capability map ────────────────────────────────────────────────────────────
72
+
73
+ const CAPABILITY_MAP: Record<LspOperation, string> = {
74
+ diagnostics: 'textDocumentSync',
75
+ hover: 'hoverProvider',
76
+ goToDefinition: 'definitionProvider',
77
+ findReferences: 'referencesProvider',
78
+ goToImplementation: 'implementationProvider',
79
+ documentSymbol: 'documentSymbolProvider',
80
+ workspaceSymbol: 'workspaceSymbolProvider',
81
+ prepareCallHierarchy: 'callHierarchyProvider',
82
+ incomingCalls: 'callHierarchyProvider',
83
+ outgoingCalls: 'callHierarchyProvider',
84
+ codeActions: 'codeActionProvider',
85
+ };
86
+
87
+ // ── Helpers ────────────────────────────────────────────────────────────────────
88
+
89
+ function cleanPath(path: string): string {
90
+ return path.replace(/^@/, '');
91
+ }
92
+
93
+ function toZeroIndexed(oneIndexed: number): number {
94
+ return Math.max(0, oneIndexed - 1);
95
+ }
96
+
97
+ function ok(text: string): ToolResult {
98
+ return { content: [{ type: 'text', text }], details: {} };
99
+ }
100
+
101
+ /** Server name for error context — tolerates partially-shaped clients. */
102
+ function serverName(client: LspClient): string {
103
+ return client.config?.name ?? 'lsp';
104
+ }
105
+
106
+ /** Wrap an async LSP client call as a typed Effect. */
107
+ function call<A>(
108
+ operation: string,
109
+ server: string,
110
+ thunk: () => Promise<A>,
111
+ ): Effect.Effect<A, LspOperationError> {
112
+ return Effect.tryPromise({
113
+ try: thunk,
114
+ catch: (cause) => new LspOperationError({ operation, server, cause }),
115
+ });
116
+ }
117
+
118
+ function validate(params: LspToolParams): Effect.Effect<void, LspValidationError> {
119
+ const { operation, filePath, line, character, query } = params;
120
+ const fail = (reason: string) => Effect.fail(new LspValidationError({ reason }));
121
+
122
+ if (POSITION_OPERATIONS.includes(operation)) {
123
+ if (!filePath) return fail(`Operation '${operation}' requires filePath`);
124
+ if (line === undefined) return fail(`Operation '${operation}' requires line`);
125
+ if (character === undefined) return fail(`Operation '${operation}' requires character`);
126
+ }
127
+ if (FILE_ONLY_OPERATIONS.includes(operation)) {
128
+ if (!filePath) return fail(`Operation '${operation}' requires filePath`);
129
+ }
130
+ if (QUERY_OPERATIONS.includes(operation)) {
131
+ if (!query) return fail(`Operation '${operation}' requires query`);
132
+ }
133
+ return Effect.void;
134
+ }
135
+
136
+ // ── Program ────────────────────────────────────────────────────────────────────
137
+
138
+ export function lspToolProgram(
139
+ raw: LspToolParams,
140
+ ): Effect.Effect<ToolResult, LspExtensionError, ServerManager> {
141
+ return Effect.gen(function* () {
142
+ yield* validate(raw);
143
+
144
+ const mgr = yield* ServerManager;
145
+ const operation = raw.operation;
146
+ const filePath = raw.filePath ? cleanPath(raw.filePath) : undefined;
147
+ const rootPath = mgr.getRootPath();
148
+
149
+ if (operation === 'diagnostics') {
150
+ return yield* diagnosticsProgram(mgr, filePath!);
151
+ }
152
+
153
+ if (operation === 'workspaceSymbol') {
154
+ return yield* workspaceSymbolProgram(mgr, raw.query!, rootPath);
155
+ }
156
+
157
+ const capability = CAPABILITY_MAP[operation];
158
+ const client = mgr.clientForFileWithCapability(filePath!, capability);
159
+ if (!client) {
160
+ return yield* new NoCapableServerError({ operation, filePath: filePath! });
161
+ }
162
+
163
+ const server = serverName(client);
164
+ const line = raw.line!;
165
+ const character = raw.character!;
166
+ const pos = { line: toZeroIndexed(line), character: toZeroIndexed(character) };
167
+
168
+ switch (operation) {
169
+ case 'hover': {
170
+ const result = yield* call(operation, server, () => client.hover(filePath!, pos));
171
+ return ok(formatHover(result, filePath!, pos.line, pos.character));
172
+ }
173
+ case 'goToDefinition': {
174
+ const locs = yield* call(operation, server, () => client.definition(filePath!, pos));
175
+ return ok(
176
+ formatLocations(locs, 'Definition', filePath!, pos.line, pos.character, rootPath),
177
+ );
178
+ }
179
+ case 'findReferences': {
180
+ const locs = yield* call(operation, server, () => client.references(filePath!, pos));
181
+ return ok(
182
+ formatLocations(locs, 'References', filePath!, pos.line, pos.character, rootPath),
183
+ );
184
+ }
185
+ case 'goToImplementation': {
186
+ const locs = yield* call(operation, server, () => client.implementation(filePath!, pos));
187
+ return ok(
188
+ formatLocations(locs, 'Implementation', filePath!, pos.line, pos.character, rootPath),
189
+ );
190
+ }
191
+ case 'documentSymbol': {
192
+ const symbols = yield* call(operation, server, () => client.documentSymbol(filePath!));
193
+ return ok(formatDocumentSymbols(symbols, filePath!, rootPath));
194
+ }
195
+ case 'prepareCallHierarchy': {
196
+ const items = yield* call(operation, server, () =>
197
+ client.prepareCallHierarchy(filePath!, pos),
198
+ );
199
+ return ok(formatCallHierarchy(items, filePath!, pos.line, pos.character, rootPath));
200
+ }
201
+ case 'incomingCalls': {
202
+ const items = yield* call(operation, server, () =>
203
+ client.prepareCallHierarchy(filePath!, pos),
204
+ );
205
+ if (items.length === 0) {
206
+ return ok(`No call hierarchy item at ${filePath!}:${line}:${character}`);
207
+ }
208
+ const calls = yield* call(operation, server, () => client.incomingCalls(items[0]));
209
+ return ok(formatIncomingCalls(calls, items[0], rootPath));
210
+ }
211
+ case 'outgoingCalls': {
212
+ const items = yield* call(operation, server, () =>
213
+ client.prepareCallHierarchy(filePath!, pos),
214
+ );
215
+ if (items.length === 0) {
216
+ return ok(`No call hierarchy item at ${filePath!}:${line}:${character}`);
217
+ }
218
+ const calls = yield* call(operation, server, () => client.outgoingCalls(items[0]));
219
+ return ok(formatOutgoingCalls(calls, items[0], rootPath));
220
+ }
221
+ case 'codeActions': {
222
+ const diagsForFile = yield* call(operation, server, () => client.getDiagnostics(filePath!));
223
+ const zeroLine = toZeroIndexed(line);
224
+ const lineDiags = diagsForFile.filter(
225
+ (d) => d.range.start.line <= zeroLine && d.range.end.line >= zeroLine,
226
+ );
227
+ const range = {
228
+ start: { line: zeroLine, character: 0 },
229
+ end: { line: zeroLine, character: Number.MAX_SAFE_INTEGER },
230
+ };
231
+ const actions = yield* call(operation, server, () =>
232
+ client.codeActions(filePath!, range, { diagnostics: lineDiags }),
233
+ );
234
+ return ok(formatCodeActions(actions, filePath!, zeroLine));
235
+ }
236
+ default:
237
+ return yield* new LspValidationError({ reason: `Unknown operation: ${operation}` });
238
+ }
239
+ });
240
+ }
241
+
242
+ function diagnosticsProgram(
243
+ mgr: ServerManagerService,
244
+ filePath: string,
245
+ ): Effect.Effect<ToolResult, never> {
246
+ return Effect.gen(function* () {
247
+ const groups: { source: string; diagnostics: Diagnostic[] }[] = [];
248
+ const errors: string[] = [];
249
+
250
+ for (const client of mgr.clientsForFile(filePath)) {
251
+ const name = serverName(client);
252
+ const result = yield* call('diagnostics', name, () => client.getDiagnostics(filePath)).pipe(
253
+ Effect.either,
254
+ );
255
+
256
+ if (result._tag === 'Right') {
257
+ if (result.right.length > 0) {
258
+ groups.push({ source: name, diagnostics: result.right });
259
+ }
260
+ } else {
261
+ errors.push(`${name}: ${result.left.message}`);
262
+ }
263
+ }
264
+
265
+ const text = formatDiagnostics(filePath, groups);
266
+ const errorNote = errors.length > 0 ? `\n\nNote: ${errors.join('; ')}` : '';
267
+
268
+ return {
269
+ content: [{ type: 'text' as const, text: text + errorNote }],
270
+ details: {
271
+ groups: groups.map((g) => ({ source: g.source, count: g.diagnostics.length })),
272
+ errors,
273
+ },
274
+ };
275
+ });
276
+ }
277
+
278
+ function workspaceSymbolProgram(
279
+ mgr: ServerManagerService,
280
+ query: string,
281
+ rootPath: string,
282
+ ): Effect.Effect<ToolResult, LspExtensionError> {
283
+ return Effect.gen(function* () {
284
+ const client = mgr.anyClient();
285
+ if (!client) {
286
+ return yield* new NoServerAvailableError({ operation: 'workspace symbol search' });
287
+ }
288
+ const symbols = yield* call('workspaceSymbol', serverName(client), () =>
289
+ client.workspaceSymbol(query),
290
+ );
291
+ return ok(formatWorkspaceSymbols(symbols, query, rootPath));
292
+ });
293
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Single unified `lsp` tool registration.
3
+ *
4
+ * 11 operations routed to the right server by file extension. The execution
5
+ * logic lives in `tools/programs.ts` as Effect programs; this module owns the
6
+ * tool schema/description and runs the program with the live `ServerManager`.
7
+ */
8
+
9
+ import type { ExtensionAPI } from '@earendil-works/pi-coding-agent';
10
+ import { Effect } from 'effect';
11
+ import { Type } from 'typebox';
12
+ import { StringEnum } from '@earendil-works/pi-ai';
13
+
14
+ import { toNativeError } from './errors';
15
+ import {
16
+ lspToolProgram,
17
+ ServerManager,
18
+ type LspToolParams,
19
+ type ServerManagerService,
20
+ } from './tools/programs';
21
+ import { LSP_OPERATIONS, type LspOperation } from './types';
22
+
23
+ export type { ServerManagerService } from './tools/programs';
24
+ export { ServerManager } from './tools/programs';
25
+
26
+ // ── Registration ────────────────────────────────────────────────────────────
27
+
28
+ export function registerLspTool(pi: ExtensionAPI, mgr: ServerManagerService) {
29
+ pi.registerTool({
30
+ name: 'lsp',
31
+ label: 'LSP',
32
+ description: [
33
+ 'Interact with Language Server Protocol servers for code intelligence.',
34
+ '',
35
+ 'Supported operations:',
36
+ ' goToDefinition — find where a symbol is defined',
37
+ ' findReferences — find all references to a symbol',
38
+ ' hover — get type info and documentation for a symbol',
39
+ ' diagnostics — get type errors and lint warnings for a file',
40
+ ' documentSymbol — get all symbols in a file (with line:column positions)',
41
+ ' workspaceSymbol — search for symbols across the workspace',
42
+ ' goToImplementation — find implementations of an interface/abstract method',
43
+ ' prepareCallHierarchy — get call hierarchy item at a position',
44
+ ' incomingCalls — find callers of a function/method (auto-prepares hierarchy)',
45
+ ' outgoingCalls — find callees of a function/method (auto-prepares hierarchy)',
46
+ ' codeActions — get quick fixes and refactoring suggestions',
47
+ '',
48
+ 'Parameters:',
49
+ ' operation (required) — one of the operations above',
50
+ ' filePath — file path relative to project root (required for most operations)',
51
+ ' line — line number, 1-indexed (required for position-based operations)',
52
+ ' character — column number, 1-indexed (required for position-based operations)',
53
+ ' query — search string (required for workspaceSymbol)',
54
+ '',
55
+ 'Tips:',
56
+ ' — Position the character in the middle of the symbol name for best results.',
57
+ ' — Use hover before goToDefinition to quickly check signatures and docs.',
58
+ ' — workspaceSymbol may need a retry if the server is still indexing.',
59
+ ].join('\n'),
60
+ promptSnippet:
61
+ 'Interact with LSP servers for code intelligence: definitions, references, hover, diagnostics, symbols, call hierarchy, code actions',
62
+ promptGuidelines: [
63
+ 'lsp line and character params are 1-indexed — use the values from the read tool or rg output directly.',
64
+ 'lsp `hover` is the fastest way to get a function signature, type params, and doc comment — prefer it over `goToDefinition` for quick type inspection.',
65
+ 'lsp `documentSymbol` returns line:column positions for each symbol — use those values directly for follow-up lsp operations.',
66
+ 'For lsp position-based operations, place the character in the **middle** of the symbol name, not at the first character.',
67
+ 'lsp `incomingCalls` and `outgoingCalls` automatically prepare the call hierarchy — no need to call `prepareCallHierarchy` first.',
68
+ 'lsp `workspaceSymbol` may return empty results while the LSP server is still indexing. If it returns nothing, wait a few seconds and retry.',
69
+ 'lsp `diagnostics` relies on server-pushed notifications which may be slow for some servers. For compiled languages (Rust, Go, C++), prefer running the compiler directly (e.g. `cargo check`, `go build`) for reliable error checking.',
70
+ 'Use lsp for type info, macro-generated symbols, and cross-module navigation. Use rg for simple text search and file discovery — it is faster and needs no server.',
71
+ 'lsp servers are auto-detected by file extension. Use /lsp to check status.',
72
+ ],
73
+ parameters: Type.Object({
74
+ operation: StringEnum(LSP_OPERATIONS),
75
+ filePath: Type.Optional(Type.String({ description: 'File path relative to project root' })),
76
+ line: Type.Optional(Type.Number({ description: 'Line number (1-indexed)' })),
77
+ character: Type.Optional(Type.Number({ description: 'Column number (1-indexed)' })),
78
+ query: Type.Optional(Type.String({ description: 'Search query (for workspaceSymbol)' })),
79
+ }),
80
+ async execute(_toolCallId, params) {
81
+ const program = lspToolProgram(params as LspToolParams);
82
+ return Effect.runPromise(
83
+ program.pipe(Effect.provideService(ServerManager, mgr), Effect.mapError(toNativeError)),
84
+ );
85
+ },
86
+ });
87
+ }
88
+
89
+ export type { LspOperation };
@@ -0,0 +1,243 @@
1
+ // ── LSP protocol types (minimal subset) ─────────────────────────────────────
2
+
3
+ /** 0-indexed line/character position. */
4
+ export interface Position {
5
+ line: number;
6
+ character: number;
7
+ }
8
+
9
+ export interface Range {
10
+ start: Position;
11
+ end: Position;
12
+ }
13
+
14
+ export interface Location {
15
+ uri: string;
16
+ range: Range;
17
+ }
18
+
19
+ export const enum DiagnosticSeverity {
20
+ Error = 1,
21
+ Warning = 2,
22
+ Information = 3,
23
+ Hint = 4,
24
+ }
25
+
26
+ export interface DiagnosticRelatedInformation {
27
+ location: Location;
28
+ message: string;
29
+ }
30
+
31
+ export interface Diagnostic {
32
+ range: Range;
33
+ severity?: DiagnosticSeverity;
34
+ code?: number | string;
35
+ codeDescription?: { href: string };
36
+ source?: string;
37
+ message: string;
38
+ relatedInformation?: DiagnosticRelatedInformation[];
39
+ }
40
+
41
+ export interface MarkupContent {
42
+ kind: 'plaintext' | 'markdown';
43
+ value: string;
44
+ }
45
+
46
+ export interface Hover {
47
+ contents: MarkupContent | string | Array<string | { language: string; value: string }>;
48
+ range?: Range;
49
+ }
50
+
51
+ export interface CodeActionContext {
52
+ diagnostics: Diagnostic[];
53
+ only?: string[];
54
+ }
55
+
56
+ export interface CodeAction {
57
+ title: string;
58
+ kind?: string;
59
+ diagnostics?: Diagnostic[];
60
+ isPreferred?: boolean;
61
+ edit?: WorkspaceEdit;
62
+ }
63
+
64
+ export interface TextEdit {
65
+ range: Range;
66
+ newText: string;
67
+ }
68
+
69
+ export interface WorkspaceEdit {
70
+ changes?: Record<string, TextEdit[]>;
71
+ }
72
+
73
+ export interface PublishDiagnosticsParams {
74
+ uri: string;
75
+ diagnostics: Diagnostic[];
76
+ version?: number;
77
+ }
78
+
79
+ // ── Symbol types ────────────────────────────────────────────────────────────
80
+
81
+ export const enum SymbolKind {
82
+ File = 1,
83
+ Module = 2,
84
+ Namespace = 3,
85
+ Package = 4,
86
+ Class = 5,
87
+ Method = 6,
88
+ Property = 7,
89
+ Field = 8,
90
+ Constructor = 9,
91
+ Enum = 10,
92
+ Interface = 11,
93
+ Function = 12,
94
+ Variable = 13,
95
+ Constant = 14,
96
+ String = 15,
97
+ Number = 16,
98
+ Boolean = 17,
99
+ Array = 18,
100
+ Object = 19,
101
+ Key = 20,
102
+ Null = 21,
103
+ EnumMember = 22,
104
+ Struct = 23,
105
+ Event = 24,
106
+ Operator = 25,
107
+ TypeParameter = 26,
108
+ }
109
+
110
+ export interface DocumentSymbol {
111
+ name: string;
112
+ detail?: string;
113
+ kind: SymbolKind;
114
+ range: Range;
115
+ selectionRange: Range;
116
+ children?: DocumentSymbol[];
117
+ }
118
+
119
+ export interface SymbolInformation {
120
+ name: string;
121
+ kind: SymbolKind;
122
+ location: Location;
123
+ containerName?: string;
124
+ }
125
+
126
+ // ── Call hierarchy types ────────────────────────────────────────────────────
127
+
128
+ export interface CallHierarchyItem {
129
+ name: string;
130
+ kind: SymbolKind;
131
+ detail?: string;
132
+ uri: string;
133
+ range: Range;
134
+ selectionRange: Range;
135
+ }
136
+
137
+ export interface CallHierarchyIncomingCall {
138
+ from: CallHierarchyItem;
139
+ fromRanges: Range[];
140
+ }
141
+
142
+ export interface CallHierarchyOutgoingCall {
143
+ to: CallHierarchyItem;
144
+ fromRanges: Range[];
145
+ }
146
+
147
+ // ── JSON-RPC types ──────────────────────────────────────────────────────────
148
+
149
+ export interface JsonRpcRequest {
150
+ jsonrpc: '2.0';
151
+ id: number;
152
+ method: string;
153
+ params?: unknown;
154
+ }
155
+
156
+ export interface JsonRpcNotification {
157
+ jsonrpc: '2.0';
158
+ method: string;
159
+ params?: unknown;
160
+ }
161
+
162
+ export interface JsonRpcResponse {
163
+ jsonrpc: '2.0';
164
+ id: number;
165
+ result?: unknown;
166
+ error?: { code: number; message: string; data?: unknown };
167
+ }
168
+
169
+ export type JsonRpcMessage = JsonRpcRequest | JsonRpcNotification | JsonRpcResponse;
170
+
171
+ // ── Server configuration ────────────────────────────────────────────────────
172
+
173
+ /** Config for a single LSP server as written in config files. */
174
+ export interface LspServerUserConfig {
175
+ /** Command + args to spawn the server. e.g. ["typescript-language-server", "--stdio"] */
176
+ command?: string[];
177
+ /** File extensions this server handles (with leading dot). */
178
+ extensions?: string[];
179
+ /** Disable this server. */
180
+ disabled?: boolean;
181
+ /** Environment variables for the server process. */
182
+ env?: Record<string, string>;
183
+ /** Initialization options sent during LSP initialize. */
184
+ initialization?: Record<string, unknown>;
185
+ }
186
+
187
+ /** Top-level config file shape. */
188
+ export interface LspConfigFile {
189
+ /** Set to false to disable all LSP servers. */
190
+ lsp?: false | Record<string, LspServerUserConfig>;
191
+ }
192
+
193
+ /** Resolved server config ready to use. */
194
+ export interface ResolvedServerConfig {
195
+ /** Server name (key from config). */
196
+ name: string;
197
+ /** Command to spawn. */
198
+ command: string;
199
+ /** Command arguments. */
200
+ args: string[];
201
+ /** File extensions this server handles (with leading dot). */
202
+ extensions: string[];
203
+ /** Environment variables for the server process. */
204
+ env: Record<string, string>;
205
+ /** Initialization options. */
206
+ initializationOptions: Record<string, unknown>;
207
+ }
208
+
209
+ // ── Operations ──────────────────────────────────────────────────────────────
210
+
211
+ export const LSP_OPERATIONS = [
212
+ 'diagnostics',
213
+ 'hover',
214
+ 'goToDefinition',
215
+ 'findReferences',
216
+ 'goToImplementation',
217
+ 'documentSymbol',
218
+ 'workspaceSymbol',
219
+ 'prepareCallHierarchy',
220
+ 'incomingCalls',
221
+ 'outgoingCalls',
222
+ 'codeActions',
223
+ ] as const;
224
+
225
+ export type LspOperation = (typeof LSP_OPERATIONS)[number];
226
+
227
+ /** Operations that require filePath + line + character. */
228
+ export const POSITION_OPERATIONS: LspOperation[] = [
229
+ 'hover',
230
+ 'goToDefinition',
231
+ 'findReferences',
232
+ 'goToImplementation',
233
+ 'prepareCallHierarchy',
234
+ 'incomingCalls',
235
+ 'outgoingCalls',
236
+ 'codeActions',
237
+ ];
238
+
239
+ /** Operations that require filePath only. */
240
+ export const FILE_ONLY_OPERATIONS: LspOperation[] = ['diagnostics', 'documentSymbol'];
241
+
242
+ /** Operations that require query only. */
243
+ export const QUERY_OPERATIONS: LspOperation[] = ['workspaceSymbol'];
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@dreki-gg/pi-lsp",
3
+ "version": "0.4.0",
4
+ "description": "Language-agnostic LSP code intelligence for pi — diagnostics, hover, definitions, references, symbols, and call hierarchy",
5
+ "keywords": [],
6
+ "author": "Juan Albarran <jalbarrandev@gmail.com>",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/dreki-gg/pi-extensions",
11
+ "directory": "packages/lsp"
12
+ },
13
+ "type": "module",
14
+ "scripts": {
15
+ "typecheck": "tsc --noEmit",
16
+ "test": "bun test",
17
+ "lint": "oxlint extensions test",
18
+ "format": "oxfmt --write extensions test",
19
+ "format:check": "oxfmt --check extensions test"
20
+ },
21
+ "pi": {
22
+ "extensions": [
23
+ "./extensions/lsp"
24
+ ]
25
+ },
26
+ "dependencies": {
27
+ "effect": "^3.21.2"
28
+ },
29
+ "devDependencies": {
30
+ "@earendil-works/pi-ai": "^0.74.0",
31
+ "@types/node": "24",
32
+ "bun-types": "latest",
33
+ "oxfmt": "^0.43.0",
34
+ "oxlint": "^1.58.0",
35
+ "typescript": "^6.0.0",
36
+ "typescript-language-server": "^5.1.3"
37
+ },
38
+ "peerDependencies": {
39
+ "@earendil-works/pi-ai": "*",
40
+ "@earendil-works/pi-coding-agent": "*",
41
+ "typebox": "*"
42
+ },
43
+ "peerDependenciesMeta": {
44
+ "@earendil-works/pi-ai": {
45
+ "optional": true
46
+ },
47
+ "@earendil-works/pi-coding-agent": {
48
+ "optional": true
49
+ },
50
+ "typebox": {
51
+ "optional": true
52
+ }
53
+ }
54
+ }