@baique/pi-web-sky 0.1.35 → 0.1.37

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 (483) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +11 -11
  3. package/.next/build-manifest.json +4 -4
  4. package/.next/next-server.js.nft.json +1 -1
  5. package/.next/prerender-manifest.json +3 -3
  6. package/.next/react-loadable-manifest.json +2 -2
  7. package/.next/required-server-files.js +6 -6
  8. package/.next/required-server-files.json +6 -6
  9. package/.next/server/app/_global-error/page.js +2 -2
  10. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  11. package/.next/server/app/_global-error.html +1 -1
  12. package/.next/server/app/_global-error.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/.next/server/app/_not-found/page.js +1 -1
  17. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/server/app/_not-found.html +1 -1
  19. package/.next/server/app/_not-found.rsc +3 -3
  20. package/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  21. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +3 -3
  22. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  23. package/.next/server/app/api/agent/[id]/bash-output/route.js +2 -2
  24. package/.next/server/app/api/agent/[id]/bash-output/route_client-reference-manifest.js +1 -1
  25. package/.next/server/app/api/agent/[id]/events/route.js +3 -3
  26. package/.next/server/app/api/agent/[id]/events/route_client-reference-manifest.js +1 -1
  27. package/.next/server/app/api/agent/[id]/route.js +2 -2
  28. package/.next/server/app/api/agent/[id]/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/agent/new/route.js +1 -1
  30. package/.next/server/app/api/agent/new/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/agent/running/route.js +1 -1
  32. package/.next/server/app/api/agent/running/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/app-update/route.js +1 -1
  34. package/.next/server/app/api/app-update/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/auth/all-providers/route.js +1 -1
  36. package/.next/server/app/api/auth/all-providers/route_client-reference-manifest.js +1 -1
  37. package/.next/server/app/api/auth/api-key/[provider]/route.js +1 -1
  38. package/.next/server/app/api/auth/api-key/[provider]/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/auth/login/[provider]/route.js +3 -3
  40. package/.next/server/app/api/auth/login/[provider]/route_client-reference-manifest.js +1 -1
  41. package/.next/server/app/api/auth/logout/[provider]/route.js +1 -1
  42. package/.next/server/app/api/auth/logout/[provider]/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/auth/providers/route.js +1 -1
  44. package/.next/server/app/api/auth/providers/route_client-reference-manifest.js +1 -1
  45. package/.next/server/app/api/boards/[id]/canvas/route.js +1 -1
  46. package/.next/server/app/api/boards/[id]/canvas/route_client-reference-manifest.js +1 -1
  47. package/.next/server/app/api/boards/[id]/edges/[eid]/route.js +1 -1
  48. package/.next/server/app/api/boards/[id]/edges/[eid]/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/boards/[id]/edges/route.js +1 -1
  50. package/.next/server/app/api/boards/[id]/edges/route_client-reference-manifest.js +1 -1
  51. package/.next/server/app/api/boards/[id]/nodes/[nid]/route.js +1 -1
  52. package/.next/server/app/api/boards/[id]/nodes/[nid]/route_client-reference-manifest.js +1 -1
  53. package/.next/server/app/api/boards/[id]/nodes/route.js +1 -1
  54. package/.next/server/app/api/boards/[id]/nodes/route_client-reference-manifest.js +1 -1
  55. package/.next/server/app/api/boards/[id]/reconcile-task-edges/route.js +1 -1
  56. package/.next/server/app/api/boards/[id]/reconcile-task-edges/route_client-reference-manifest.js +1 -1
  57. package/.next/server/app/api/boards/[id]/route.js +1 -1
  58. package/.next/server/app/api/boards/[id]/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/boards/purge-orphans/route.js +1 -1
  60. package/.next/server/app/api/boards/purge-orphans/route_client-reference-manifest.js +1 -1
  61. package/.next/server/app/api/boards/reorder/route.js +1 -1
  62. package/.next/server/app/api/boards/reorder/route_client-reference-manifest.js +1 -1
  63. package/.next/server/app/api/boards/route.js +1 -1
  64. package/.next/server/app/api/boards/route_client-reference-manifest.js +1 -1
  65. package/.next/server/app/api/cwd/browse/route.js +1 -1
  66. package/.next/server/app/api/cwd/browse/route_client-reference-manifest.js +1 -1
  67. package/.next/server/app/api/cwd/validate/route.js +2 -2
  68. package/.next/server/app/api/cwd/validate/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/default-cwd/route.js +2 -2
  70. package/.next/server/app/api/default-cwd/route_client-reference-manifest.js +1 -1
  71. package/.next/server/app/api/file-index/route.js +2 -2
  72. package/.next/server/app/api/file-index/route_client-reference-manifest.js +1 -1
  73. package/.next/server/app/api/files/[...path]/route.js +2 -2
  74. package/.next/server/app/api/files/[...path]/route_client-reference-manifest.js +1 -1
  75. package/.next/server/app/api/git/diff/route.js +1 -1
  76. package/.next/server/app/api/git/diff/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/git/status/route.js +1 -1
  78. package/.next/server/app/api/git/status/route_client-reference-manifest.js +1 -1
  79. package/.next/server/app/api/home/route.js +1 -1
  80. package/.next/server/app/api/home/route_client-reference-manifest.js +1 -1
  81. package/.next/server/app/api/mcp/route.js +2 -2
  82. package/.next/server/app/api/mcp/route_client-reference-manifest.js +1 -1
  83. package/.next/server/app/api/models/route.js +2 -2
  84. package/.next/server/app/api/models/route_client-reference-manifest.js +1 -1
  85. package/.next/server/app/api/models-config/catalog/route.js +1 -1
  86. package/.next/server/app/api/models-config/catalog/route_client-reference-manifest.js +1 -1
  87. package/.next/server/app/api/models-config/discover/route.js +1 -1
  88. package/.next/server/app/api/models-config/discover/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/models-config/route.js +1 -1
  90. package/.next/server/app/api/models-config/route_client-reference-manifest.js +1 -1
  91. package/.next/server/app/api/models-config/test/route.js +1 -1
  92. package/.next/server/app/api/models-config/test/route_client-reference-manifest.js +1 -1
  93. package/.next/server/app/api/plugins/route.js +2 -2
  94. package/.next/server/app/api/plugins/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/project-trust/route.js +2 -2
  96. package/.next/server/app/api/project-trust/route_client-reference-manifest.js +1 -1
  97. package/.next/server/app/api/quota/route.js +1 -1
  98. package/.next/server/app/api/quota/route_client-reference-manifest.js +1 -1
  99. package/.next/server/app/api/search/route.js +2 -2
  100. package/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
  101. package/.next/server/app/api/sessions/[id]/auto-name/route.js +3 -3
  102. package/.next/server/app/api/sessions/[id]/auto-name/route_client-reference-manifest.js +1 -1
  103. package/.next/server/app/api/sessions/[id]/context/route.js +2 -2
  104. package/.next/server/app/api/sessions/[id]/context/route_client-reference-manifest.js +1 -1
  105. package/.next/server/app/api/sessions/[id]/entries/[entryId]/thinking/route.js +2 -2
  106. package/.next/server/app/api/sessions/[id]/entries/[entryId]/thinking/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/sessions/[id]/export/route.js +2 -2
  108. package/.next/server/app/api/sessions/[id]/export/route_client-reference-manifest.js +1 -1
  109. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  110. package/.next/server/app/api/sessions/[id]/route_client-reference-manifest.js +1 -1
  111. package/.next/server/app/api/sessions/[id]/state/route.js +2 -2
  112. package/.next/server/app/api/sessions/[id]/state/route_client-reference-manifest.js +1 -1
  113. package/.next/server/app/api/sessions/[id]/todos/route.js +2 -2
  114. package/.next/server/app/api/sessions/[id]/todos/route_client-reference-manifest.js +1 -1
  115. package/.next/server/app/api/sessions/route.js +2 -2
  116. package/.next/server/app/api/sessions/route_client-reference-manifest.js +1 -1
  117. package/.next/server/app/api/skills/check/route.js +1 -1
  118. package/.next/server/app/api/skills/check/route.js.nft.json +1 -1
  119. package/.next/server/app/api/skills/check/route_client-reference-manifest.js +1 -1
  120. package/.next/server/app/api/skills/install/route.js +2 -2
  121. package/.next/server/app/api/skills/install/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/skills/route.js +2 -31
  123. package/.next/server/app/api/skills/route.js.nft.json +1 -1
  124. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
  125. package/.next/server/app/api/skills/search/route.js +1 -1
  126. package/.next/server/app/api/skills/search/route_client-reference-manifest.js +1 -1
  127. package/.next/server/app/api/skills/update/route.js +1 -1
  128. package/.next/server/app/api/skills/update/route.js.nft.json +1 -1
  129. package/.next/server/app/api/skills/update/route_client-reference-manifest.js +1 -1
  130. package/.next/server/app/api/task-card-questions/[id]/answer/route.js +1 -1
  131. package/.next/server/app/api/task-card-questions/[id]/answer/route_client-reference-manifest.js +1 -1
  132. package/.next/server/app/api/task-card-questions/route.js +1 -1
  133. package/.next/server/app/api/task-card-questions/route_client-reference-manifest.js +1 -1
  134. package/.next/server/app/api/task-cards/[id]/route.js +1 -1
  135. package/.next/server/app/api/task-cards/[id]/route_client-reference-manifest.js +1 -1
  136. package/.next/server/app/api/task-cards/route.js +1 -1
  137. package/.next/server/app/api/task-cards/route_client-reference-manifest.js +1 -1
  138. package/.next/server/app/api/task-scheduler/status/route.js +1 -1
  139. package/.next/server/app/api/task-scheduler/status/route_client-reference-manifest.js +1 -1
  140. package/.next/server/app/api/tasks/[id]/board/route.js +1 -1
  141. package/.next/server/app/api/tasks/[id]/board/route_client-reference-manifest.js +1 -1
  142. package/.next/server/app/api/tasks/[id]/route.js +1 -1
  143. package/.next/server/app/api/tasks/[id]/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/tasks/reorder/route.js +1 -1
  145. package/.next/server/app/api/tasks/reorder/route_client-reference-manifest.js +1 -1
  146. package/.next/server/app/api/tasks/route.js +1 -1
  147. package/.next/server/app/api/tasks/route_client-reference-manifest.js +1 -1
  148. package/.next/server/app/api/terminal/[id]/events/route.js +3 -3
  149. package/.next/server/app/api/terminal/[id]/events/route_client-reference-manifest.js +1 -1
  150. package/.next/server/app/api/terminal/[id]/route.js +2 -2
  151. package/.next/server/app/api/terminal/[id]/route_client-reference-manifest.js +1 -1
  152. package/.next/server/app/api/terminal/route.js +2 -2
  153. package/.next/server/app/api/terminal/route_client-reference-manifest.js +1 -1
  154. package/.next/server/app/api/worktrees/route.js +2 -2
  155. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  156. package/.next/server/app/favicon.ico/route.js +1 -1
  157. package/.next/server/app/index.html +1 -1
  158. package/.next/server/app/index.rsc +5 -5
  159. package/.next/server/app/index.segments/__PAGE__.segment.rsc +5 -5
  160. package/.next/server/app/index.segments/_full.segment.rsc +5 -5
  161. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  162. package/.next/server/app/manifest.webmanifest/route.js +2 -2
  163. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  164. package/.next/server/app/page.js +3 -3
  165. package/.next/server/app/page_client-reference-manifest.js +1 -1
  166. package/.next/server/app-paths-manifest.json +11 -11
  167. package/.next/server/chunks/2404.js +2 -2
  168. package/.next/server/chunks/2430.js +4 -4
  169. package/.next/server/chunks/3500.js +30 -0
  170. package/.next/server/chunks/4226.js +2 -2
  171. package/.next/server/chunks/542.js +11 -6
  172. package/.next/server/chunks/5794.js +2 -2
  173. package/.next/server/chunks/6429.js +1 -1
  174. package/.next/server/chunks/898.js +2 -2
  175. package/.next/server/instrumentation.js +1 -1
  176. package/.next/server/middleware-build-manifest.js +1 -1
  177. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  178. package/.next/server/middleware.js +3 -3
  179. package/.next/server/next-font-manifest.js +1 -1
  180. package/.next/server/next-font-manifest.json +1 -1
  181. package/.next/server/pages/404.html +1 -1
  182. package/.next/server/pages/500.html +1 -1
  183. package/.next/server/server-reference-manifest.json +1 -1
  184. package/.next/static/chunks/5315.dba7515ae6e139ae.js +4 -0
  185. package/.next/static/chunks/{7999.f4ab221861378788.js → 7999.879d5a20e8641752.js} +1 -1
  186. package/.next/static/chunks/app/_not-found/{page-af4fe23994cb3d66.js → page-8cea8d8de35f4da4.js} +1 -1
  187. package/.next/static/chunks/app/{layout-1d9a7a44fbc92d2e.js → layout-c4ca28ccc08bc975.js} +1 -1
  188. package/.next/static/chunks/app/{page-6d6779a81a0a7639.js → page-c9ead38525a85686.js} +3 -3
  189. package/.next/static/chunks/{main-app-b3e8a8d15d83e1f0.js → main-app-dd2385a1a5a588df.js} +1 -1
  190. package/.next/static/chunks/next/dist/client/components/builtin/global-error-be943dcb89867ab9.js +1 -0
  191. package/.next/static/chunks/{webpack-fa4f40085b1ec1ac.js → webpack-4bbf04891e910713.js} +1 -1
  192. package/.next/static/css/422c7dc0faa04d89.css +1 -0
  193. package/.next/trace +8 -9
  194. package/.next/trace-build +1 -1
  195. package/.next/types/app/api/agent/[id]/bash-output/route.ts +1 -1
  196. package/.next/types/app/api/agent/[id]/events/route.ts +1 -1
  197. package/.next/types/app/api/agent/[id]/route.ts +1 -1
  198. package/.next/types/app/api/agent/new/route.ts +1 -1
  199. package/.next/types/app/api/agent/running/route.ts +1 -1
  200. package/.next/types/app/api/app-update/route.ts +1 -1
  201. package/.next/types/app/api/auth/all-providers/route.ts +1 -1
  202. package/.next/types/app/api/auth/api-key/[provider]/route.ts +1 -1
  203. package/.next/types/app/api/auth/login/[provider]/route.ts +1 -1
  204. package/.next/types/app/api/auth/logout/[provider]/route.ts +1 -1
  205. package/.next/types/app/api/auth/providers/route.ts +1 -1
  206. package/.next/types/app/api/boards/[id]/canvas/route.ts +1 -1
  207. package/.next/types/app/api/boards/[id]/edges/[eid]/route.ts +1 -1
  208. package/.next/types/app/api/boards/[id]/edges/route.ts +1 -1
  209. package/.next/types/app/api/boards/[id]/nodes/[nid]/route.ts +1 -1
  210. package/.next/types/app/api/boards/[id]/nodes/route.ts +1 -1
  211. package/.next/types/app/api/boards/[id]/reconcile-task-edges/route.ts +1 -1
  212. package/.next/types/app/api/boards/[id]/route.ts +1 -1
  213. package/.next/types/app/api/boards/purge-orphans/route.ts +1 -1
  214. package/.next/types/app/api/boards/reorder/route.ts +1 -1
  215. package/.next/types/app/api/boards/route.ts +1 -1
  216. package/.next/types/app/api/cwd/browse/route.ts +1 -1
  217. package/.next/types/app/api/cwd/validate/route.ts +1 -1
  218. package/.next/types/app/api/default-cwd/route.ts +1 -1
  219. package/.next/types/app/api/file-index/route.ts +1 -1
  220. package/.next/types/app/api/files/[...path]/route.ts +1 -1
  221. package/.next/types/app/api/git/diff/route.ts +1 -1
  222. package/.next/types/app/api/git/status/route.ts +1 -1
  223. package/.next/types/app/api/home/route.ts +1 -1
  224. package/.next/types/app/api/mcp/route.ts +1 -1
  225. package/.next/types/app/api/models/route.ts +1 -1
  226. package/.next/types/app/api/models-config/catalog/route.ts +1 -1
  227. package/.next/types/app/api/models-config/discover/route.ts +1 -1
  228. package/.next/types/app/api/models-config/route.ts +1 -1
  229. package/.next/types/app/api/models-config/test/route.ts +1 -1
  230. package/.next/types/app/api/plugins/route.ts +1 -1
  231. package/.next/types/app/api/project-trust/route.ts +1 -1
  232. package/.next/types/app/api/quota/route.ts +1 -1
  233. package/.next/types/app/api/search/route.ts +1 -1
  234. package/.next/types/app/api/sessions/[id]/auto-name/route.ts +1 -1
  235. package/.next/types/app/api/sessions/[id]/context/route.ts +1 -1
  236. package/.next/types/app/api/sessions/[id]/entries/[entryId]/thinking/route.ts +1 -1
  237. package/.next/types/app/api/sessions/[id]/export/route.ts +1 -1
  238. package/.next/types/app/api/sessions/[id]/route.ts +1 -1
  239. package/.next/types/app/api/sessions/[id]/state/route.ts +1 -1
  240. package/.next/types/app/api/sessions/[id]/todos/route.ts +1 -1
  241. package/.next/types/app/api/sessions/route.ts +1 -1
  242. package/.next/types/app/api/skills/check/route.ts +1 -1
  243. package/.next/types/app/api/skills/install/route.ts +1 -1
  244. package/.next/types/app/api/skills/route.ts +1 -1
  245. package/.next/types/app/api/skills/search/route.ts +1 -1
  246. package/.next/types/app/api/skills/update/route.ts +1 -1
  247. package/.next/types/app/api/task-card-questions/[id]/answer/route.ts +1 -1
  248. package/.next/types/app/api/task-card-questions/route.ts +1 -1
  249. package/.next/types/app/api/task-cards/[id]/route.ts +1 -1
  250. package/.next/types/app/api/task-cards/route.ts +1 -1
  251. package/.next/types/app/api/task-scheduler/status/route.ts +1 -1
  252. package/.next/types/app/api/tasks/[id]/board/route.ts +1 -1
  253. package/.next/types/app/api/tasks/[id]/route.ts +1 -1
  254. package/.next/types/app/api/tasks/reorder/route.ts +1 -1
  255. package/.next/types/app/api/tasks/route.ts +1 -1
  256. package/.next/types/app/api/terminal/[id]/events/route.ts +1 -1
  257. package/.next/types/app/api/terminal/[id]/route.ts +1 -1
  258. package/.next/types/app/api/terminal/route.ts +1 -1
  259. package/.next/types/app/api/worktrees/route.ts +1 -1
  260. package/.next/types/app/layout.ts +1 -1
  261. package/.next/types/app/page.ts +1 -1
  262. package/bin/pi-web-sky.js +15 -20
  263. package/lib/agent-client.test.mjs +64 -0
  264. package/lib/agent-client.ts +53 -0
  265. package/lib/agent-event-connection.test.mjs +193 -0
  266. package/lib/agent-event-connection.ts +202 -0
  267. package/lib/agent-event-stream.test.mjs +155 -0
  268. package/lib/agent-event-stream.ts +132 -0
  269. package/lib/agent-event-wire.test.mjs +278 -0
  270. package/lib/agent-event-wire.ts +107 -0
  271. package/lib/agent-phase.ts +24 -0
  272. package/lib/allowed-roots.ts +31 -0
  273. package/lib/ansi.test.mjs +52 -0
  274. package/lib/ansi.ts +211 -0
  275. package/lib/api-types.ts +139 -0
  276. package/lib/app-update.test.mjs +27 -0
  277. package/lib/app-update.ts +28 -0
  278. package/lib/atomic-file.test.mjs +37 -0
  279. package/lib/atomic-file.ts +34 -0
  280. package/lib/audit-session.ts +235 -0
  281. package/lib/bash-output.test.mjs +63 -0
  282. package/lib/bash-output.ts +53 -0
  283. package/lib/bg-image.ts +129 -0
  284. package/lib/board-events.ts +83 -0
  285. package/lib/board-purge.test.mjs +66 -0
  286. package/lib/board-purge.ts +65 -0
  287. package/lib/board-search.test.mjs +110 -0
  288. package/lib/board-search.ts +63 -0
  289. package/lib/board-store.test.mjs +542 -0
  290. package/lib/board-store.ts +794 -0
  291. package/lib/board-types.ts +96 -0
  292. package/lib/board-utils.ts +17 -0
  293. package/lib/bounded-form-data.test.mjs +54 -0
  294. package/lib/bounded-form-data.ts +49 -0
  295. package/lib/browser-notifications.test.mjs +167 -0
  296. package/lib/browser-notifications.ts +104 -0
  297. package/lib/chat-lazy-load.test.mjs +140 -0
  298. package/lib/chat-lazy-load.ts +64 -0
  299. package/lib/clipboard-paths.test.mjs +140 -0
  300. package/lib/clipboard-paths.ts +192 -0
  301. package/lib/clipboard.ts +18 -0
  302. package/lib/compaction-summary.test.mjs +44 -0
  303. package/lib/compaction-summary.ts +34 -0
  304. package/lib/custom-ui-terminal.test.mjs +32 -0
  305. package/lib/custom-ui-terminal.ts +27 -0
  306. package/lib/deepseek-pricing.test.mjs +120 -0
  307. package/lib/deepseek-pricing.ts +71 -0
  308. package/lib/directory-browser.test.mjs +60 -0
  309. package/lib/directory-browser.ts +83 -0
  310. package/lib/draft-stash.test.mjs +91 -0
  311. package/lib/draft-stash.ts +102 -0
  312. package/lib/draft-store.ts +105 -0
  313. package/lib/dropdown-direction.ts +27 -0
  314. package/lib/extension-command.test.mjs +63 -0
  315. package/lib/extension-command.ts +81 -0
  316. package/lib/file-access.test.mjs +31 -0
  317. package/lib/file-access.ts +59 -0
  318. package/lib/file-dirent.test.mjs +56 -0
  319. package/lib/file-dirent.ts +17 -0
  320. package/lib/file-explorer-state.test.mjs +63 -0
  321. package/lib/file-explorer-state.ts +36 -0
  322. package/lib/file-fuzzy.test.mjs +29 -0
  323. package/lib/file-fuzzy.ts +189 -0
  324. package/lib/file-links.test.mjs +92 -0
  325. package/lib/file-links.ts +148 -0
  326. package/lib/file-paths.ts +43 -0
  327. package/lib/file-types.test.mjs +34 -0
  328. package/lib/file-types.ts +73 -0
  329. package/lib/file-upload.test.mjs +70 -0
  330. package/lib/file-upload.ts +59 -0
  331. package/lib/file-viewer-state.test.mjs +20 -0
  332. package/lib/file-viewer-state.ts +15 -0
  333. package/lib/frontmatter.test.mjs +55 -0
  334. package/lib/frontmatter.ts +87 -0
  335. package/lib/git-changes.test.mjs +52 -0
  336. package/lib/git-changes.ts +232 -0
  337. package/lib/git-status.ts +47 -0
  338. package/lib/git-types.ts +29 -0
  339. package/lib/http-dispatcher.test.mjs +83 -0
  340. package/lib/http-dispatcher.ts +86 -0
  341. package/lib/i18n/format.test.mjs +19 -0
  342. package/lib/i18n/format.ts +60 -0
  343. package/lib/i18n/messages/en.ts +662 -0
  344. package/lib/i18n/messages/zh-CN.ts +661 -0
  345. package/lib/i18n/registry.test.mjs +32 -0
  346. package/lib/i18n/registry.ts +43 -0
  347. package/lib/i18n/types.ts +15 -0
  348. package/lib/image-attachments.test.mjs +27 -0
  349. package/lib/image-attachments.ts +56 -0
  350. package/lib/initial-navigation.test.mjs +65 -0
  351. package/lib/initial-navigation.ts +15 -0
  352. package/lib/markdown.test.mjs +104 -0
  353. package/lib/markdown.ts +347 -0
  354. package/lib/message-display.test.mjs +130 -0
  355. package/lib/message-display.ts +47 -0
  356. package/lib/model-catalog.test.mjs +327 -0
  357. package/lib/model-catalog.ts +414 -0
  358. package/lib/model-discovery-auth.ts +58 -0
  359. package/lib/model-discovery.test.mjs +50 -0
  360. package/lib/model-discovery.ts +75 -0
  361. package/lib/model-id-preference.ts +46 -0
  362. package/lib/model-scope.test.mjs +193 -0
  363. package/lib/model-scope.ts +198 -0
  364. package/lib/models-cache.test.mjs +122 -0
  365. package/lib/models-cache.ts +90 -0
  366. package/lib/models-config-store.test.mjs +200 -0
  367. package/lib/models-config-store.ts +84 -0
  368. package/lib/next-config-esm.test.mjs +14 -0
  369. package/lib/next-config.test.mjs +13 -0
  370. package/lib/node-version.test.mjs +33 -0
  371. package/lib/normalize.test.mjs +54 -0
  372. package/lib/normalize.ts +63 -0
  373. package/lib/npx.ts +62 -0
  374. package/lib/panel-layout.test.mjs +56 -0
  375. package/lib/panel-layout.ts +52 -0
  376. package/lib/patch.test.mjs +110 -0
  377. package/lib/patch.ts +134 -0
  378. package/lib/path-security.ts +42 -0
  379. package/lib/paths.test.mjs +58 -0
  380. package/lib/paths.ts +71 -0
  381. package/lib/pi-types.ts +183 -0
  382. package/lib/pi-web-options.test.mjs +63 -0
  383. package/lib/process-lifecycle.test.mjs +83 -0
  384. package/lib/project-command-env.test.mjs +298 -0
  385. package/lib/project-command-env.ts +129 -0
  386. package/lib/project-groups.test.mjs +60 -0
  387. package/lib/project-groups.ts +53 -0
  388. package/lib/project-identity.test.mjs +37 -0
  389. package/lib/project-identity.ts +26 -0
  390. package/lib/project-tree.test.mjs +115 -0
  391. package/lib/project-tree.ts +176 -0
  392. package/lib/project-trust.test.mjs +117 -0
  393. package/lib/project-trust.ts +48 -0
  394. package/lib/prompt-recovery.test.mjs +33 -0
  395. package/lib/prompt-recovery.ts +47 -0
  396. package/lib/provider-api-key-route.test.mjs +12 -0
  397. package/lib/provider-credential-store.test.mjs +126 -0
  398. package/lib/provider-credential-store.ts +114 -0
  399. package/lib/provider-listing-runtime.ts +37 -0
  400. package/lib/provider-listing.test.mjs +114 -0
  401. package/lib/provider-listing.ts +118 -0
  402. package/lib/provider-services.ts +64 -0
  403. package/lib/request-security.test.mjs +256 -0
  404. package/lib/request-security.ts +136 -0
  405. package/lib/rpc-manager-shutdown.test.mjs +372 -0
  406. package/lib/rpc-manager-widgets.test.mjs +342 -0
  407. package/lib/rpc-manager.test.mjs +139 -0
  408. package/lib/rpc-manager.ts +1703 -0
  409. package/lib/rpc-session-info.test.mjs +93 -0
  410. package/lib/session-delete.test.mjs +53 -0
  411. package/lib/session-delete.ts +86 -0
  412. package/lib/session-file-references-core.ts +82 -0
  413. package/lib/session-file-references.test.mjs +91 -0
  414. package/lib/session-file-references.ts +29 -0
  415. package/lib/session-path.test.mjs +24 -0
  416. package/lib/session-path.ts +11 -0
  417. package/lib/session-reader.pagination.test.mjs +115 -0
  418. package/lib/session-reader.test.mjs +446 -0
  419. package/lib/session-reader.ts +548 -0
  420. package/lib/session-resolve.test.mjs +65 -0
  421. package/lib/session-row-context-menu.test.mjs +46 -0
  422. package/lib/session-row-context-menu.ts +29 -0
  423. package/lib/session-scanner.test.mjs +151 -0
  424. package/lib/session-scanner.ts +238 -0
  425. package/lib/session-search.test.mjs +173 -0
  426. package/lib/session-search.ts +284 -0
  427. package/lib/session-stats.ts +26 -0
  428. package/lib/session-timing.test.mjs +107 -0
  429. package/lib/session-timing.ts +45 -0
  430. package/lib/session-title.test.mjs +284 -0
  431. package/lib/session-title.ts +255 -0
  432. package/lib/skill-frontmatter.test.mjs +75 -0
  433. package/lib/skill-frontmatter.ts +40 -0
  434. package/lib/skill-lock.test.mjs +182 -0
  435. package/lib/skill-lock.ts +146 -0
  436. package/lib/skill-updates.test.mjs +182 -0
  437. package/lib/skill-updates.ts +263 -0
  438. package/lib/skills-service.ts +16 -0
  439. package/lib/slash-display.test.mjs +122 -0
  440. package/lib/slash-display.ts +30 -0
  441. package/lib/sqlite-db.test.mjs +140 -0
  442. package/lib/sqlite-db.ts +205 -0
  443. package/lib/startup-preferences.test.mjs +130 -0
  444. package/lib/startup-preferences.ts +65 -0
  445. package/lib/streaming-message.test.mjs +212 -0
  446. package/lib/streaming-message.ts +151 -0
  447. package/lib/subagent-widget.test.mjs +87 -0
  448. package/lib/subagent-widget.ts +109 -0
  449. package/lib/sync-room-server.mjs +137 -0
  450. package/lib/task-card-store.test.mjs +309 -0
  451. package/lib/task-card-store.ts +559 -0
  452. package/lib/task-scheduler.ts +498 -0
  453. package/lib/task-store.test.mjs +216 -0
  454. package/lib/task-store.ts +271 -0
  455. package/lib/terminal-input.test.mjs +46 -0
  456. package/lib/terminal-input.ts +63 -0
  457. package/lib/terminal-manager.test.mjs +71 -0
  458. package/lib/terminal-manager.ts +245 -0
  459. package/lib/tool-execution-progress.test.mjs +32 -0
  460. package/lib/tool-execution-progress.ts +29 -0
  461. package/lib/tool-names.ts +25 -0
  462. package/lib/tool-preset-preference.test.mjs +72 -0
  463. package/lib/tool-preset-preference.ts +41 -0
  464. package/lib/tool-presets.test.mjs +56 -0
  465. package/lib/tool-presets.ts +42 -0
  466. package/lib/turn-written-files.test.mjs +137 -0
  467. package/lib/turn-written-files.ts +60 -0
  468. package/lib/types.ts +349 -0
  469. package/lib/wallpaper-settings.ts +191 -0
  470. package/lib/web-auth.test.mjs +50 -0
  471. package/lib/web-auth.ts +45 -0
  472. package/lib/workspace-memory.test.mjs +129 -0
  473. package/lib/workspace-memory.ts +98 -0
  474. package/lib/worktree.test.mjs +50 -0
  475. package/lib/worktree.ts +250 -0
  476. package/package.json +3 -1
  477. package/server.mjs +34 -0
  478. package/.next/server/chunks/7513.js +0 -30
  479. package/.next/static/chunks/5315.03de3c6abd8b283e.js +0 -4
  480. package/.next/static/chunks/next/dist/client/components/builtin/global-error-00a4badaccb388e6.js +0 -1
  481. package/.next/static/css/cf25164cb7c04d95.css +0 -1
  482. /package/.next/static/{Ud6Y2ONkGuPVFbo1xZQvk → 7sDSz-wW-RWYnxh1l6-fD}/_buildManifest.js +0 -0
  483. /package/.next/static/{Ud6Y2ONkGuPVFbo1xZQvk → 7sDSz-wW-RWYnxh1l6-fD}/_ssgManifest.js +0 -0
@@ -0,0 +1,151 @@
1
+ import type { ClientAssistantMessageEvent } from "./agent-event-wire";
2
+ import { normalizeStreamingToolCalls } from "./normalize";
3
+ import type {
4
+ AgentMessage,
5
+ AssistantContentBlock,
6
+ AssistantMessage,
7
+ } from "./types";
8
+
9
+ export type { ClientAssistantMessageEvent } from "./agent-event-wire";
10
+
11
+ export interface StreamingState {
12
+ isStreaming: boolean;
13
+ streamingMessage: AssistantMessage | null;
14
+ }
15
+
16
+ export type StreamAction =
17
+ | { type: "start" }
18
+ | { type: "snapshot"; message: AgentMessage }
19
+ | { type: "delta"; event: ClientAssistantMessageEvent }
20
+ | { type: "end" };
21
+
22
+ export const INITIAL_STREAMING_STATE: StreamingState = {
23
+ isStreaming: false,
24
+ streamingMessage: null,
25
+ };
26
+
27
+ function updateContentBlock(
28
+ state: StreamingState,
29
+ contentIndex: number,
30
+ update: (current: AssistantContentBlock | undefined) => AssistantContentBlock | null,
31
+ ): StreamingState {
32
+ const message = state.streamingMessage;
33
+ if (!message || !Number.isInteger(contentIndex) || contentIndex < 0) return state;
34
+
35
+ const content = [...message.content];
36
+ const nextBlock = update(content[contentIndex]);
37
+ if (!nextBlock) return state;
38
+ content[contentIndex] = nextBlock;
39
+ return {
40
+ isStreaming: true,
41
+ streamingMessage: { ...message, content },
42
+ };
43
+ }
44
+
45
+ function applyDelta(
46
+ state: StreamingState,
47
+ event: ClientAssistantMessageEvent,
48
+ ): StreamingState {
49
+ switch (event.type) {
50
+ case "text_start":
51
+ return updateContentBlock(state, event.contentIndex, (current) => (
52
+ current?.type === "text" ? current : { type: "text", text: "" }
53
+ ));
54
+ case "text_delta":
55
+ return updateContentBlock(state, event.contentIndex, (current) => (
56
+ current?.type === "text"
57
+ ? { ...current, text: current.text + event.delta }
58
+ : null
59
+ ));
60
+ case "text_end":
61
+ return updateContentBlock(state, event.contentIndex, (current) => ({
62
+ ...(current?.type === "text" ? current : {}),
63
+ type: "text",
64
+ text: event.content,
65
+ }));
66
+ case "thinking_start":
67
+ return updateContentBlock(state, event.contentIndex, (current) => (
68
+ current?.type === "thinking" ? current : { type: "thinking", thinking: "" }
69
+ ));
70
+ case "thinking_delta":
71
+ return updateContentBlock(state, event.contentIndex, (current) => (
72
+ current?.type === "thinking"
73
+ ? { ...current, thinking: current.thinking + event.delta }
74
+ : null
75
+ ));
76
+ case "thinking_end":
77
+ return updateContentBlock(state, event.contentIndex, (current) => ({
78
+ ...(current?.type === "thinking" ? current : {}),
79
+ type: "thinking",
80
+ thinking: event.content,
81
+ }));
82
+ case "toolcall_start":
83
+ return updateContentBlock(state, event.contentIndex, (current) => {
84
+ if (current?.type === "toolCall") {
85
+ return {
86
+ ...current,
87
+ toolCallId: event.id ?? current.toolCallId,
88
+ toolName: event.toolName ?? current.toolName,
89
+ rawInput: current.rawInput ?? "",
90
+ };
91
+ }
92
+ if (typeof event.toolName !== "string") return null;
93
+ return {
94
+ type: "toolCall",
95
+ toolCallId: event.id ?? "",
96
+ toolName: event.toolName,
97
+ input: {},
98
+ rawInput: "",
99
+ };
100
+ });
101
+ case "toolcall_delta":
102
+ return updateContentBlock(state, event.contentIndex, (current) => (
103
+ current?.type === "toolCall"
104
+ ? {
105
+ ...current,
106
+ toolCallId: event.id || current.toolCallId,
107
+ toolName: event.toolName || current.toolName,
108
+ rawInput: (current.rawInput ?? "") + event.delta,
109
+ }
110
+ : null
111
+ ));
112
+ case "toolcall_end":
113
+ return updateContentBlock(state, event.contentIndex, () => ({
114
+ type: "toolCall",
115
+ toolCallId: event.toolCall.id,
116
+ toolName: event.toolCall.name,
117
+ input: event.toolCall.arguments,
118
+ }));
119
+ default:
120
+ return state;
121
+ }
122
+ }
123
+
124
+ export function streamReducer(
125
+ state: StreamingState,
126
+ action: StreamAction,
127
+ ): StreamingState {
128
+ switch (action.type) {
129
+ case "start":
130
+ // A late `start` (e.g. the mount-time state restore finishing after the
131
+ // SSE reconnect already replayed the partial message via `snapshot`)
132
+ // must not wipe an in-flight streaming message. Clearing it here would
133
+ // drop every subsequent text delta (applyDelta needs an existing block)
134
+ // and freeze the typewriter until the whole message lands at message_end.
135
+ return state.streamingMessage
136
+ ? { ...state, isStreaming: true }
137
+ : { isStreaming: true, streamingMessage: null };
138
+ case "snapshot": {
139
+ const message = normalizeStreamingToolCalls(action.message);
140
+ return message.role === "assistant"
141
+ ? { isStreaming: true, streamingMessage: message }
142
+ : state;
143
+ }
144
+ case "delta":
145
+ return applyDelta(state, action.event);
146
+ case "end":
147
+ return INITIAL_STREAMING_STATE;
148
+ default:
149
+ return state;
150
+ }
151
+ }
@@ -0,0 +1,87 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+
4
+ async function loadSubject() {
5
+ try {
6
+ const { createJiti } = await import("jiti");
7
+ return createJiti(import.meta.url).import("./subagent-widget.ts");
8
+ } catch {
9
+ return import("./subagent-widget.ts");
10
+ }
11
+ }
12
+
13
+ const {
14
+ parseSubagentSnapshot,
15
+ parseSubagentInspectReply,
16
+ widgetParsers,
17
+ SUBAGENT_ASYNC_JSON_PREFIX,
18
+ SUBAGENT_INSPECT_JSON_PREFIX,
19
+ } = await loadSubject();
20
+
21
+ const SNAPSHOT = {
22
+ kind: "pi-subagents.async-status-snapshot",
23
+ version: 1,
24
+ generatedAt: 1787999999000,
25
+ caps: { maxRuns: 20, maxChildrenPerNode: 8, maxDepth: 3, maxStringLength: 160, maxSerializedBytes: 32768 },
26
+ omitted: { runs: 0, children: 0, byteLimitExceeded: false },
27
+ runs: [
28
+ {
29
+ id: "run-1",
30
+ kind: "subagent",
31
+ label: "worker",
32
+ state: "running",
33
+ startedAt: 1787999998000,
34
+ activity: { currentTool: "read", toolCount: 3 },
35
+ },
36
+ ],
37
+ };
38
+
39
+ test("解析正常快照,字段映射正确", () => {
40
+ const lines = [`${SUBAGENT_ASYNC_JSON_PREFIX}${JSON.stringify(SNAPSHOT)}`];
41
+ const parsed = parseSubagentSnapshot(lines);
42
+ assert.ok(parsed);
43
+ assert.equal(parsed.kind, "pi-subagents.async-status-snapshot");
44
+ assert.equal(parsed.runs.length, 1);
45
+ assert.equal(parsed.runs[0].label, "worker");
46
+ assert.equal(parsed.runs[0].state, "running");
47
+ assert.equal(parsed.runs[0].activity?.currentTool, "read");
48
+ });
49
+
50
+ test("非 JSON 前缀返回 null", () => {
51
+ assert.equal(parseSubagentSnapshot(["plain text line"]), null);
52
+ });
53
+
54
+ test("前缀对但 JSON 非法返回 null", () => {
55
+ assert.equal(parseSubagentSnapshot([`${SUBAGENT_ASYNC_JSON_PREFIX}{not-json`]), null);
56
+ });
57
+
58
+ test("前缀对但 kind 不符返回 null", () => {
59
+ const lines = [`${SUBAGENT_ASYNC_JSON_PREFIX}${JSON.stringify({ kind: "other.kind", runs: [] })}`];
60
+ assert.equal(parseSubagentSnapshot(lines), null);
61
+ });
62
+
63
+ test("runs 非数组返回 null", () => {
64
+ const lines = [
65
+ `${SUBAGENT_ASYNC_JSON_PREFIX}${JSON.stringify({ kind: "pi-subagents.async-status-snapshot", runs: "nope" })}`,
66
+ ];
67
+ assert.equal(parseSubagentSnapshot(lines), null);
68
+ });
69
+
70
+ test("解析 inspect 回包", () => {
71
+ const reply = {
72
+ kind: "pi-subagents.inspect-reply",
73
+ version: 1,
74
+ requestId: "req-1",
75
+ asyncId: "run-1",
76
+ status: "running",
77
+ messages: [{ role: "assistant", kind: "toolCall", name: "read", text: "read src/a.ts" }],
78
+ };
79
+ const parsed = parseSubagentInspectReply([`${SUBAGENT_INSPECT_JSON_PREFIX}${JSON.stringify(reply)}`]);
80
+ assert.ok(parsed);
81
+ assert.equal(parsed.requestId, "req-1");
82
+ assert.equal(parsed.messages?.[0].kind, "toolCall");
83
+ });
84
+
85
+ test("注册表骨架含 subagent-async 解析器", () => {
86
+ assert.equal(typeof widgetParsers["subagent-async"], "function");
87
+ });
@@ -0,0 +1,109 @@
1
+ /**
2
+ * subagent widget 快照解析 + 注册表骨架。
3
+ *
4
+ * pi-subagents 在 RPC 模式下把异步子任务状态压成单行 JSON 推给 pi-web:
5
+ * widget key: "subagent-async"
6
+ * 首行前缀: "PI_SUBAGENT_ASYNC_JSON:" + JSON.stringify(AsyncStatusSnapshotV1)
7
+ *
8
+ * 这里只做「识别 + 解析」,渲染在 components/subagent/*。
9
+ * 注册表骨架:未来其他插件若也用「带标记的 JSON 行」推结构化内容,
10
+ * 在 widgetParsers 里加一条即可,pi-web 无需改渲染主流程。
11
+ */
12
+
13
+ export const SUBAGENT_ASYNC_WIDGET_KEY = "subagent-async";
14
+ export const SUBAGENT_INSPECT_WIDGET_KEY = "subagent-inspect";
15
+ export const SUBAGENT_FLEET_STATUS_WIDGET_KEY = "subagent-fleet-status";
16
+ export const SUBAGENT_ASYNC_JSON_PREFIX = "PI_SUBAGENT_ASYNC_JSON:";
17
+ export const SUBAGENT_INSPECT_JSON_PREFIX = "PI_SUBAGENT_INSPECT_JSON:";
18
+
19
+ /** pi-subagents 推的、在 pi-web 里不应作为可见 widget 渲染的 key(纯数据传输 / TUI 专属) */
20
+ export const SUBAGENT_HIDDEN_WIDGET_KEYS = new Set([
21
+ SUBAGENT_ASYNC_WIDGET_KEY,
22
+ SUBAGENT_INSPECT_WIDGET_KEY,
23
+ SUBAGENT_FLEET_STATUS_WIDGET_KEY,
24
+ ]);
25
+
26
+ /** pi-subagents AsyncStatusSnapshotV1 的节点结构(对齐插件侧,只取展示所需字段) */
27
+ export interface SubagentSnapshotNode {
28
+ id: string;
29
+ kind: "subagent" | "workflow" | "step" | "host-step";
30
+ label: string;
31
+ state:
32
+ | "queued"
33
+ | "running"
34
+ | "complete"
35
+ | "failed"
36
+ | "partial"
37
+ | "paused"
38
+ | "stopped"
39
+ | "rejected";
40
+ startedAt?: number;
41
+ endedAt?: number;
42
+ activity?: {
43
+ state?: string;
44
+ currentTool?: string;
45
+ turnCount?: number;
46
+ toolCount?: number;
47
+ };
48
+ children?: SubagentSnapshotNode[];
49
+ }
50
+
51
+ export interface SubagentSnapshot {
52
+ kind: string;
53
+ version: number;
54
+ generatedAt: number;
55
+ runs: SubagentSnapshotNode[];
56
+ }
57
+
58
+ export interface SubagentInspectMessage {
59
+ role: string;
60
+ kind: "text" | "toolCall" | "toolResult";
61
+ text: string;
62
+ name?: string;
63
+ isError?: boolean;
64
+ }
65
+
66
+ /** pi-subagents.inspect-reply v1 */
67
+ export interface SubagentInspectReply {
68
+ kind: string;
69
+ version: number;
70
+ requestId: string;
71
+ asyncId?: string;
72
+ childId?: string;
73
+ status?: string;
74
+ label?: string;
75
+ task?: string;
76
+ messages?: SubagentInspectMessage[];
77
+ finalOutput?: string;
78
+ error?: { code: string; message: string };
79
+ }
80
+
81
+ function parsePrefixedJson<T>(line: string | undefined, prefix: string): T | null {
82
+ if (!line || !line.startsWith(prefix)) return null;
83
+ try {
84
+ return JSON.parse(line.slice(prefix.length)) as T;
85
+ } catch {
86
+ return null;
87
+ }
88
+ }
89
+
90
+ /** 解析 subagent-async widget 快照;非本插件内容或解析失败返回 null */
91
+ export function parseSubagentSnapshot(lines: string[]): SubagentSnapshot | null {
92
+ const raw = parsePrefixedJson<SubagentSnapshot>(lines[0], SUBAGENT_ASYNC_JSON_PREFIX);
93
+ if (!raw || raw.kind !== "pi-subagents.async-status-snapshot" || !Array.isArray(raw.runs)) {
94
+ return null;
95
+ }
96
+ return raw;
97
+ }
98
+
99
+ /** 解析 subagent-inspect 回包(emit-then-retract 的 emit 帧) */
100
+ export function parseSubagentInspectReply(lines: string[]): SubagentInspectReply | null {
101
+ const raw = parsePrefixedJson<SubagentInspectReply>(lines[0], SUBAGENT_INSPECT_JSON_PREFIX);
102
+ if (!raw || raw.kind !== "pi-subagents.inspect-reply") return null;
103
+ return raw;
104
+ }
105
+
106
+ /** 注册表骨架:widget key → 解析器。现在只注册 subagent,未来插件加条目即可。 */
107
+ export const widgetParsers: Record<string, (lines: string[]) => unknown | null> = {
108
+ [SUBAGENT_ASYNC_WIDGET_KEY]: parseSubagentSnapshot,
109
+ };
@@ -0,0 +1,137 @@
1
+ // ============================================================================
2
+ // tldraw sync 房间服务器核心(可内嵌 Next.js server,也可独立进程)
3
+ // - 每看板一个 TLSocketRoom + SQLiteSyncStorage(sync.db,tablePrefix 按 board 隔离)
4
+ // - 纯文档同步:不懂业务,派生边/补卡由前端 reconcile(读业务数据 → CRDT 写文档)
5
+ // - 自定义 shape(session-card / task-card / sticky-note)两端注册
6
+ //
7
+ // 用法(内嵌):server.on("upgrade", handleSyncUpgrade) —— 返回 false 表示未处理,调用方转交 Next
8
+ // 用法(独立):见 scripts/sync-server.mjs
9
+ // ============================================================================
10
+ import { createRequire } from "node:module";
11
+ const require = createRequire(import.meta.url);
12
+ import { randomUUID } from "node:crypto";
13
+ import { homedir } from "node:os";
14
+ import { join, normalize } from "node:path";
15
+
16
+ const { DatabaseSync } = require("node:sqlite");
17
+ const { WebSocketServer } = require("ws");
18
+ const core = require("@tldraw/sync-core");
19
+ const tlschema = require("@tldraw/tlschema");
20
+ const T = require("@tldraw/validate").T;
21
+
22
+ // ---- agent dir(与 lib/sqlite-db.ts 同语义)----
23
+ export function getAgentDir() {
24
+ const envDir = process.env.PI_CODING_AGENT_DIR;
25
+ if (envDir) {
26
+ const expanded = envDir.startsWith("~") ? join(homedir(), envDir.slice(1)) : envDir;
27
+ return normalize(expanded);
28
+ }
29
+ return join(homedir(), ".pi", "agent");
30
+ }
31
+ export const SYNC_DB_FILE = join(getAgentDir(), "sync.db");
32
+
33
+ // ---- 自定义 shape props 校验器(与 components/canvas/{SessionCardShape,StickyNoteShape,TaskCardShape}.tsx 保持一致)----
34
+ const sessionCardProps = {
35
+ sessionId: T.string, title: T.string, projectName: T.string,
36
+ messageCount: T.number, lastReply: T.string, phase: T.string,
37
+ runningMs: T.number, endedAt: T.number, lastActivityAt: T.number,
38
+ stale: T.boolean, expanded: T.boolean, cwd: T.string, taskId: T.string,
39
+ w: T.number, h: T.number, expandedW: T.number, expandedH: T.number,
40
+ collapsedW: T.number, collapsedH: T.number,
41
+ };
42
+ const stickyNoteProps = {
43
+ text: T.string, w: T.number, h: T.number,
44
+ badge: T.string.optional(), createdAt: T.number.optional(),
45
+ };
46
+ const taskCardProps = {
47
+ cardId: T.string, number: T.number, name: T.string,
48
+ description: T.string.optional(), readyStatus: T.string, execStatus: T.string, priority: T.number,
49
+ // due:业务层允许 number | null(无截止=null)。shape 写入可能带 null(草稿初始化/API 回读),
50
+ // 必须 nullable 否则 sync 校验失败 → INVALID_RECORD → 画布永远 loading(派发后看板死掉根因)
51
+ due: T.number.nullable().optional(), expanded: T.boolean,
52
+ w: T.number, h: T.number, expandedW: T.number, expandedH: T.number,
53
+ collapsedW: T.number, collapsedH: T.number,
54
+ };
55
+
56
+ export const syncSchema = tlschema.createTLSchema({
57
+ shapes: {
58
+ ...tlschema.defaultShapeSchemas,
59
+ "session-card": { props: sessionCardProps },
60
+ "sticky-note": { props: stickyNoteProps },
61
+ "task-card": { props: taskCardProps },
62
+ },
63
+ bindings: { ...tlschema.defaultBindingSchemas },
64
+ assets: { ...tlschema.defaultAssetSchemas },
65
+ });
66
+
67
+ // ---- 房间管理:每 boardId 一个 TLSocketRoom;SQLite 持久化(同一 sync.db,tablePrefix 隔离)----
68
+ // 单一 DatabaseSync 连接(node:sqlite 同步,单连接线程安全)
69
+ const db = new DatabaseSync(SYNC_DB_FILE);
70
+ const rooms = new Map();
71
+
72
+ function safePrefix(boardId) {
73
+ return `board_${boardId.replace(/[^a-zA-Z0-9_]/g, "_")}_`;
74
+ }
75
+
76
+ export function getSyncRoom(boardId) {
77
+ let room = rooms.get(boardId);
78
+ if (room) return room;
79
+ const storage = new core.SQLiteSyncStorage({
80
+ sql: new core.NodeSqliteWrapper(db, { tablePrefix: safePrefix(boardId) }),
81
+ });
82
+ room = new core.TLSocketRoom({
83
+ // clientTimeout 不能传 0:0 会让 pruneSessions 把所有 Connected 会话当超时踢掉
84
+ // (timeSince > 0 恒真)→ 客户端重连风暴。传 undefined 用默认 20s 空闲超时,
85
+ // ping 每 5s 保活,正常不会触发。
86
+ storage, schema: syncSchema, clientTimeout: undefined,
87
+ // INVALID_RECORD 等致命错误会走 log.error(带 TLSyncError 对象)——hook 它打印详情
88
+ log: {
89
+ warn: (...a) => console.warn("[sync:room]", ...a),
90
+ error: (...a) => {
91
+ const err = a[0];
92
+ const detail = err instanceof Error ? `${err.message}${err.reason ? ` [reason=${err.reason}]` : ""}` : JSON.stringify(a).slice(0, 500);
93
+ console.error("[sync:room]", detail);
94
+ },
95
+ },
96
+ });
97
+ rooms.set(boardId, room);
98
+ return room;
99
+ }
100
+
101
+ export function getSyncRoomCount() {
102
+ return rooms.size;
103
+ }
104
+
105
+ // noServer WSS:不做端口监听,只负责把 upgrade 的 net.Socket 握手成 ws 实例
106
+ const wss = new WebSocketServer({ noServer: true });
107
+
108
+ /**
109
+ * 处理一条 WebSocket upgrade 请求(挂在 Node http server 的 "upgrade" 事件)。
110
+ * 路径匹配 /connect/:boardId → 房间接管;否则返回 false(调用方转交 Next 自身 handler,如 HMR)。
111
+ * @returns {boolean} 是否已处理
112
+ */
113
+ export function handleSyncUpgrade(req, socket, head) {
114
+ let url;
115
+ try {
116
+ url = new URL(req.url, "http://localhost");
117
+ } catch {
118
+ return false;
119
+ }
120
+ const m = url.pathname.match(/^\/connect\/([^/]+)$/);
121
+ if (!m) return false;
122
+
123
+ const boardId = decodeURIComponent(m[1]);
124
+ const room = getSyncRoom(boardId);
125
+ // sessionId 必须复用客户端提供的(useSync 每次重连带固定 TAB_ID)——
126
+ // 若随机生成,重连被当成新会话,服务器端 session 堆积、协议错乱。
127
+ const sessionId = url.searchParams.get("sessionId") ?? randomUUID();
128
+
129
+ // 握手成功后 ws 即为 EventTarget 兼容实例;handleSocketConnect 自动挂
130
+ // message/close/error 监听。绝不手动再 ws.on("message")——否则每条消息处理
131
+ // 两次 → push_result 双发 → 重连死循环。
132
+ wss.handleUpgrade(req, socket, head, (ws) => {
133
+ room.handleSocketConnect({ sessionId, socket: ws, isReadonly: false });
134
+ console.log(`[sync] ${boardId}: client ${sessionId.slice(0, 8)} connected (${room.getNumActiveSessions()})`);
135
+ });
136
+ return true;
137
+ }