@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,425 @@
1
+ /**
2
+ * Pi SDK provider — Node.js variant.
3
+ *
4
+ * Identical to pi-sdk.ts except PiProcess uses child_process.spawn()
5
+ * instead of Bun.spawn(). Everything else (PiSDKProvider, PiSDKSession,
6
+ * mapPiEvent) is re-exported from the Bun version unchanged.
7
+ *
8
+ * Used by the Pi extension which runs under jiti (Node.js).
9
+ */
10
+
11
+ import { spawn, type ChildProcess } from "node:child_process";
12
+ import { BaseSession } from "../base-session.ts";
13
+ import { buildEffectivePrompt, buildSystemPrompt } from "../context.ts";
14
+ import type {
15
+ AIMessage,
16
+ AIProvider,
17
+ AIProviderCapabilities,
18
+ CreateSessionOptions,
19
+ PiSDKConfig,
20
+ } from "../types.ts";
21
+ import { registerProviderFactory } from "../provider.ts";
22
+ import {
23
+ buildWindowsCommandScriptSpawnCommand,
24
+ killWindowsProcessTree,
25
+ resolveWindowsCommandShim,
26
+ } from "./command-path.ts";
27
+
28
+ // Re-export mapPiEvent from shared (runtime-agnostic)
29
+ export { mapPiEvent } from "./pi-events.ts";
30
+
31
+ const PROVIDER_NAME = "pi-sdk";
32
+
33
+ // ---------------------------------------------------------------------------
34
+ // JSONL subprocess wrapper (Node.js)
35
+ // ---------------------------------------------------------------------------
36
+
37
+ type EventListener = (event: Record<string, unknown>) => void;
38
+
39
+ class PiProcessNode {
40
+ private proc: ChildProcess | null = null;
41
+ private listeners: EventListener[] = [];
42
+ private pendingRequests = new Map<
43
+ string,
44
+ {
45
+ resolve: (data: Record<string, unknown>) => void;
46
+ reject: (err: Error) => void;
47
+ }
48
+ >();
49
+ private nextId = 0;
50
+ private buffer = "";
51
+ private _alive = false;
52
+
53
+ async spawn(piPath: string, cwd: string): Promise<void> {
54
+ const commandPath = resolveWindowsCommandShim(piPath);
55
+ const command =
56
+ buildWindowsCommandScriptSpawnCommand(commandPath, ["--mode", "rpc"]) ?? [
57
+ commandPath,
58
+ "--mode",
59
+ "rpc",
60
+ ];
61
+ let proc: ChildProcess;
62
+ try {
63
+ const [file, ...args] = command;
64
+ proc = spawn(file, args, {
65
+ cwd,
66
+ stdio: ["pipe", "pipe", "pipe"],
67
+ });
68
+ } catch (err) {
69
+ const error = err instanceof Error ? err : new Error(String(err));
70
+ this.handleProcessEnd(error);
71
+ throw error;
72
+ }
73
+
74
+ this.proc = proc;
75
+ proc.once("exit", () => {
76
+ this.handleProcessEnd(new Error("Pi process exited unexpectedly"));
77
+ });
78
+
79
+ await new Promise<void>((resolve, reject) => {
80
+ const cleanup = () => {
81
+ proc.off("spawn", onSpawn);
82
+ proc.off("error", onError);
83
+ };
84
+ const onSpawn = () => {
85
+ cleanup();
86
+ this._alive = true;
87
+ this.readStream();
88
+ resolve();
89
+ };
90
+ const onError = (err: Error) => {
91
+ cleanup();
92
+ this.handleProcessEnd(err);
93
+ reject(err);
94
+ };
95
+
96
+ proc.once("spawn", onSpawn);
97
+ proc.once("error", onError);
98
+ });
99
+ }
100
+
101
+ private handleProcessEnd(error: Error): void {
102
+ if (!this.proc && this.pendingRequests.size === 0) return;
103
+
104
+ this._alive = false;
105
+ this.proc = null;
106
+ for (const [, pending] of this.pendingRequests) {
107
+ pending.reject(error);
108
+ }
109
+ this.pendingRequests.clear();
110
+ for (const listener of this.listeners) {
111
+ listener({ type: "process_exited" });
112
+ }
113
+ }
114
+
115
+ private readStream(): void {
116
+ if (!this.proc?.stdout) return;
117
+
118
+ this.proc.stdout.on("data", (chunk: Buffer) => {
119
+ this.buffer += chunk.toString();
120
+ const lines = this.buffer.split("\n");
121
+ this.buffer = lines.pop() ?? "";
122
+
123
+ for (const line of lines) {
124
+ const trimmed = line.replace(/\r$/, "");
125
+ if (!trimmed) continue;
126
+ try {
127
+ const parsed = JSON.parse(trimmed);
128
+ this.routeMessage(parsed);
129
+ } catch {
130
+ // Ignore malformed lines
131
+ }
132
+ }
133
+ });
134
+ }
135
+
136
+ private routeMessage(msg: Record<string, unknown>): void {
137
+ if (msg.type === "response" && typeof msg.id === "string") {
138
+ const pending = this.pendingRequests.get(msg.id);
139
+ if (pending) {
140
+ this.pendingRequests.delete(msg.id);
141
+ if (msg.success === false) {
142
+ pending.reject(new Error((msg.error as string) ?? "RPC error"));
143
+ } else {
144
+ pending.resolve((msg.data as Record<string, unknown>) ?? {});
145
+ }
146
+ return;
147
+ }
148
+ }
149
+
150
+ for (const listener of this.listeners) {
151
+ listener(msg);
152
+ }
153
+ }
154
+
155
+ send(command: Record<string, unknown>): void {
156
+ if (!this.proc?.stdin || this.proc.stdin.destroyed) return;
157
+ this.proc.stdin.write(`${JSON.stringify(command)}\n`);
158
+ }
159
+
160
+ sendAndWait(
161
+ command: Record<string, unknown>,
162
+ ): Promise<Record<string, unknown>> {
163
+ const id = `req_${++this.nextId}`;
164
+ return new Promise((resolve, reject) => {
165
+ this.pendingRequests.set(id, { resolve, reject });
166
+ this.send({ ...command, id });
167
+ });
168
+ }
169
+
170
+ onEvent(listener: EventListener): () => void {
171
+ this.listeners.push(listener);
172
+ return () => {
173
+ const idx = this.listeners.indexOf(listener);
174
+ if (idx >= 0) this.listeners.splice(idx, 1);
175
+ };
176
+ }
177
+
178
+ get alive(): boolean {
179
+ return this._alive;
180
+ }
181
+
182
+ kill(): void {
183
+ this._alive = false;
184
+ const proc = this.proc;
185
+ this.proc = null;
186
+ if (proc) {
187
+ if (!killWindowsProcessTree(proc.pid)) {
188
+ proc.kill();
189
+ }
190
+ }
191
+ this.listeners.length = 0;
192
+ for (const [, pending] of this.pendingRequests) {
193
+ pending.reject(new Error("Process killed"));
194
+ }
195
+ this.pendingRequests.clear();
196
+ }
197
+ }
198
+
199
+ // ---------------------------------------------------------------------------
200
+ // Provider (identical to pi-sdk.ts, using PiProcessNode)
201
+ // ---------------------------------------------------------------------------
202
+
203
+ export class PiSDKNodeProvider implements AIProvider {
204
+ readonly name = PROVIDER_NAME;
205
+ readonly capabilities: AIProviderCapabilities = {
206
+ fork: false,
207
+ resume: false,
208
+ streaming: true,
209
+ tools: true,
210
+ };
211
+ models?: Array<{ id: string; label: string; default?: boolean }>;
212
+
213
+ private config: PiSDKConfig;
214
+ private sessions = new Map<string, PiSDKNodeSession>();
215
+
216
+ constructor(config: PiSDKConfig) {
217
+ this.config = config;
218
+ }
219
+
220
+ async createSession(options: CreateSessionOptions): Promise<PiSDKNodeSession> {
221
+ const session = new PiSDKNodeSession({
222
+ systemPrompt: buildSystemPrompt(options.context),
223
+ cwd: options.cwd ?? this.config.cwd ?? process.cwd(),
224
+ parentSessionId: null,
225
+ piExecutablePath: this.config.piExecutablePath ?? "pi",
226
+ model: options.model ?? this.config.model,
227
+ });
228
+ this.sessions.set(session.id, session);
229
+ return session;
230
+ }
231
+
232
+ async forkSession(): Promise<never> {
233
+ throw new Error(
234
+ "Pi does not support session forking. " +
235
+ "The endpoint layer should fall back to createSession().",
236
+ );
237
+ }
238
+
239
+ async resumeSession(): Promise<never> {
240
+ throw new Error("Pi does not support session resuming.");
241
+ }
242
+
243
+ dispose(): void {
244
+ for (const session of this.sessions.values()) {
245
+ session.killProcess();
246
+ }
247
+ this.sessions.clear();
248
+ }
249
+
250
+ async fetchModels(): Promise<void> {
251
+ const piPath = this.config.piExecutablePath ?? "pi";
252
+ let proc: PiProcessNode | undefined;
253
+ try {
254
+ proc = new PiProcessNode();
255
+ await proc.spawn(piPath, this.config.cwd ?? process.cwd());
256
+ const data = await Promise.race([
257
+ proc.sendAndWait({ type: "get_available_models" }),
258
+ new Promise<never>((_, reject) =>
259
+ setTimeout(() => reject(new Error("Timeout")), 10_000),
260
+ ),
261
+ ]);
262
+ const rawModels = (
263
+ data as { models?: Array<{ provider: string; id: string; name?: string }> }
264
+ ).models;
265
+ if (rawModels && rawModels.length > 0) {
266
+ this.models = rawModels.map((m, i) => ({
267
+ id: `${m.provider}/${m.id}`,
268
+ label: m.name ?? m.id,
269
+ ...(i === 0 && { default: true }),
270
+ }));
271
+ }
272
+ } catch {
273
+ // Pi not configured or no models available
274
+ } finally {
275
+ proc?.kill();
276
+ }
277
+ }
278
+ }
279
+
280
+ // ---------------------------------------------------------------------------
281
+ // Session (identical to pi-sdk.ts, using PiProcessNode)
282
+ // ---------------------------------------------------------------------------
283
+
284
+ interface SessionConfig {
285
+ systemPrompt: string;
286
+ cwd: string;
287
+ parentSessionId: string | null;
288
+ piExecutablePath: string;
289
+ model?: string;
290
+ }
291
+
292
+ class PiSDKNodeSession extends BaseSession {
293
+ private config: SessionConfig;
294
+ private process: PiProcessNode | null = null;
295
+
296
+ constructor(config: SessionConfig) {
297
+ super({ parentSessionId: config.parentSessionId });
298
+ this.config = config;
299
+ }
300
+
301
+ async *query(prompt: string): AsyncIterable<AIMessage> {
302
+ const { mapPiEvent } = await import("./pi-events.ts");
303
+
304
+ const started = this.startQuery();
305
+ if (!started) {
306
+ yield BaseSession.BUSY_ERROR;
307
+ return;
308
+ }
309
+ const { gen } = started;
310
+
311
+ try {
312
+ if (!this.process || !this.process.alive) {
313
+ this.process = new PiProcessNode();
314
+ await this.process.spawn(this.config.piExecutablePath, this.config.cwd);
315
+
316
+ if (this.config.model) {
317
+ const [provider, ...rest] = this.config.model.split("/");
318
+ const modelId = rest.join("/");
319
+ if (provider && modelId) {
320
+ try {
321
+ await this.process.sendAndWait({ type: "set_model", provider, modelId });
322
+ } catch { /* Continue with Pi's default model */ }
323
+ }
324
+ }
325
+
326
+ try {
327
+ const state = await this.process.sendAndWait({ type: "get_state" });
328
+ if (typeof state.sessionId === "string") {
329
+ this.resolveId(state.sessionId);
330
+ }
331
+ } catch { /* Continue with placeholder ID */ }
332
+
333
+ if (!this.process.alive) {
334
+ yield {
335
+ type: "error",
336
+ error: "Pi process exited during startup. Check that Pi is configured correctly (API keys, models).",
337
+ code: "pi_startup_error",
338
+ };
339
+ return;
340
+ }
341
+ }
342
+
343
+ const effectivePrompt = buildEffectivePrompt(
344
+ prompt,
345
+ this.config.systemPrompt,
346
+ this._firstQuerySent,
347
+ );
348
+
349
+ const queue: AIMessage[] = [];
350
+ let resolve: (() => void) | null = null;
351
+ let done = false;
352
+
353
+ const push = (msg: AIMessage) => { queue.push(msg); resolve?.(); };
354
+ const finish = () => { done = true; resolve?.(); };
355
+
356
+ const unsubscribe = this.process.onEvent((event) => {
357
+ const mapped = mapPiEvent(event, this.id);
358
+ for (const msg of mapped) {
359
+ push(msg);
360
+ if (
361
+ msg.type === "result" ||
362
+ (msg.type === "error" && (event.type === "agent_end" || event.type === "process_exited"))
363
+ ) {
364
+ finish();
365
+ }
366
+ }
367
+ });
368
+
369
+ try {
370
+ await this.process.sendAndWait({ type: "prompt", message: effectivePrompt });
371
+ } catch (err) {
372
+ unsubscribe();
373
+ yield {
374
+ type: "error",
375
+ error: `Pi rejected prompt: ${err instanceof Error ? err.message : String(err)}`,
376
+ code: "pi_prompt_rejected",
377
+ };
378
+ return;
379
+ }
380
+ this._firstQuerySent = true;
381
+
382
+ try {
383
+ while (!done || queue.length > 0) {
384
+ if (queue.length > 0) {
385
+ yield queue.shift()!;
386
+ } else {
387
+ await new Promise<void>((r) => { resolve = r; });
388
+ resolve = null;
389
+ }
390
+ }
391
+ } finally {
392
+ unsubscribe();
393
+ }
394
+ } catch (err) {
395
+ yield {
396
+ type: "error",
397
+ error: err instanceof Error ? err.message : String(err),
398
+ code: "provider_error",
399
+ };
400
+ } finally {
401
+ this.endQuery(gen);
402
+ }
403
+ }
404
+
405
+ abort(): void {
406
+ if (this.process?.alive) {
407
+ this.process.send({ type: "abort" });
408
+ }
409
+ super.abort();
410
+ }
411
+
412
+ killProcess(): void {
413
+ this.process?.kill();
414
+ this.process = null;
415
+ }
416
+ }
417
+
418
+ // ---------------------------------------------------------------------------
419
+ // Factory registration
420
+ // ---------------------------------------------------------------------------
421
+
422
+ registerProviderFactory(
423
+ PROVIDER_NAME,
424
+ async (config) => new PiSDKNodeProvider(config as PiSDKConfig),
425
+ );