@baique/pi-web-sky 0.1.39 → 0.1.41

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 (381) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +7 -12
  3. package/.next/build-manifest.json +3 -3
  4. package/.next/prerender-manifest.json +3 -3
  5. package/.next/react-loadable-manifest.json +51 -51
  6. package/.next/required-server-files.js +1 -1
  7. package/.next/required-server-files.json +1 -1
  8. package/.next/routes-manifest.json +3 -45
  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]/events/route.js +2 -2
  25. package/.next/server/app/api/agent/[id]/route.js +2 -2
  26. package/.next/server/app/api/agent/new/route.js +1 -1
  27. package/.next/server/app/api/agent/new/route.js.nft.json +1 -1
  28. package/.next/server/app/api/agent/running/route.js +1 -1
  29. package/.next/server/app/api/app-update/route.js +1 -1
  30. package/.next/server/app/api/auth/all-providers/route.js +1 -1
  31. package/.next/server/app/api/auth/api-key/[provider]/route.js +1 -1
  32. package/.next/server/app/api/auth/login/[provider]/route.js +1 -1
  33. package/.next/server/app/api/auth/logout/[provider]/route.js +1 -1
  34. package/.next/server/app/api/auth/providers/route.js +1 -1
  35. package/.next/server/app/api/boards/[id]/reconcile/route.js +1 -0
  36. package/.next/server/app/api/boards/[id]/reconcile/route_client-reference-manifest.js +1 -0
  37. package/.next/server/app/api/boards/[id]/route.js +1 -1
  38. package/.next/server/app/api/boards/purge-orphans/route.js +1 -1
  39. package/.next/server/app/api/boards/reorder/route.js +1 -1
  40. package/.next/server/app/api/boards/route.js +1 -1
  41. package/.next/server/app/api/cwd/browse/route.js +1 -1
  42. package/.next/server/app/api/cwd/validate/route.js +2 -2
  43. package/.next/server/app/api/default-cwd/route.js +2 -2
  44. package/.next/server/app/api/file-index/route.js +2 -2
  45. package/.next/server/app/api/files/[...path]/route.js +3 -3
  46. package/.next/server/app/api/files/[...path]/route.js.nft.json +1 -1
  47. package/.next/server/app/api/git/diff/route.js +1 -1
  48. package/.next/server/app/api/git/status/route.js +1 -1
  49. package/.next/server/app/api/home/route.js +1 -1
  50. package/.next/server/app/api/mcp/route.js +1 -1
  51. package/.next/server/app/api/models/route.js +2 -2
  52. package/.next/server/app/api/models-config/catalog/route.js +1 -1
  53. package/.next/server/app/api/models-config/discover/route.js +1 -1
  54. package/.next/server/app/api/models-config/route.js +1 -1
  55. package/.next/server/app/api/models-config/test/route.js +1 -1
  56. package/.next/server/app/api/plugins/route.js +2 -2
  57. package/.next/server/app/api/project-trust/route.js +2 -2
  58. package/.next/server/app/api/quota/route.js +1 -1
  59. package/.next/server/app/api/search/route.js +2 -2
  60. package/.next/server/app/api/sessions/[id]/auto-name/route.js +3 -3
  61. package/.next/server/app/api/sessions/[id]/context/route.js +2 -2
  62. package/.next/server/app/api/sessions/[id]/entries/[entryId]/thinking/route.js +2 -2
  63. package/.next/server/app/api/sessions/[id]/export/route.js +2 -2
  64. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  65. package/.next/server/app/api/sessions/[id]/state/route.js +2 -2
  66. package/.next/server/app/api/sessions/[id]/todos/route.js +2 -2
  67. package/.next/server/app/api/sessions/route.js +2 -2
  68. package/.next/server/app/api/skills/check/route.js +1 -1
  69. package/.next/server/app/api/skills/install/route.js +2 -2
  70. package/.next/server/app/api/skills/route.js +1 -1
  71. package/.next/server/app/api/skills/search/route.js +1 -1
  72. package/.next/server/app/api/skills/update/route.js +1 -1
  73. package/.next/server/app/api/task-card-questions/[id]/answer/route.js +1 -1
  74. package/.next/server/app/api/task-card-questions/route.js +1 -1
  75. package/.next/server/app/api/task-cards/[id]/route.js +1 -1
  76. package/.next/server/app/api/task-cards/route.js +1 -1
  77. package/.next/server/app/api/task-scheduler/status/route.js +1 -1
  78. package/.next/server/app/api/tasks/[id]/board/route.js +1 -1
  79. package/.next/server/app/api/tasks/[id]/route.js +1 -1
  80. package/.next/server/app/api/tasks/reorder/route.js +1 -1
  81. package/.next/server/app/api/tasks/route.js +1 -1
  82. package/.next/server/app/api/terminal/[id]/events/route.js +2 -2
  83. package/.next/server/app/api/terminal/[id]/route.js +2 -2
  84. package/.next/server/app/api/terminal/route.js +2 -2
  85. package/.next/server/app/api/worktrees/route.js +2 -2
  86. package/.next/server/app/favicon.ico/route.js +1 -1
  87. package/.next/server/app/index.html +1 -1
  88. package/.next/server/app/index.rsc +5 -5
  89. package/.next/server/app/index.segments/__PAGE__.segment.rsc +5 -5
  90. package/.next/server/app/index.segments/_full.segment.rsc +5 -5
  91. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  92. package/.next/server/app/manifest.webmanifest/route.js +2 -2
  93. package/.next/server/app/page.js +7 -7
  94. package/.next/server/app/page_client-reference-manifest.js +1 -1
  95. package/.next/server/app-paths-manifest.json +7 -12
  96. package/.next/server/chunks/1094.js +2 -2
  97. package/.next/server/chunks/1601.js +1 -1
  98. package/.next/server/chunks/1860.js +1 -1
  99. package/.next/server/chunks/2075.js +1 -1
  100. package/.next/server/chunks/2169.js +1 -1
  101. package/.next/server/chunks/2404.js +1 -1
  102. package/.next/server/chunks/2524.js +1 -0
  103. package/.next/server/chunks/3012.js +1 -1
  104. package/.next/server/chunks/{5760.js → 3379.js} +1 -1
  105. package/.next/server/chunks/3500.js +1 -1
  106. package/.next/server/chunks/4226.js +5 -2
  107. package/.next/server/chunks/4267.js +1 -1
  108. package/.next/server/chunks/4563.js +1 -1
  109. package/.next/server/chunks/5318.js +1 -1
  110. package/.next/server/chunks/542.js +3 -44
  111. package/.next/server/chunks/5794.js +1 -1
  112. package/.next/server/chunks/6052.js +1 -1
  113. package/.next/server/chunks/6253.js +1 -1
  114. package/.next/server/chunks/6288.js +1 -1
  115. package/.next/server/chunks/6366.js +1 -1
  116. package/.next/server/chunks/673.js +1 -1
  117. package/.next/server/chunks/6916.js +2 -2
  118. package/.next/server/chunks/7128.js +43 -0
  119. package/.next/server/chunks/7265.js +2 -2
  120. package/.next/server/chunks/7799.js +1 -1
  121. package/.next/server/chunks/8106.js +1 -1
  122. package/.next/server/chunks/8333.js +1 -1
  123. package/.next/server/chunks/8604.js +1 -1
  124. package/.next/server/chunks/861.js +1 -0
  125. package/.next/server/chunks/8713.js +1 -1
  126. package/.next/server/chunks/8782.js +2 -2
  127. package/.next/server/chunks/898.js +1 -1
  128. package/.next/server/chunks/922.js +2 -2
  129. package/.next/server/chunks/9280.js +6 -6
  130. package/.next/server/chunks/9510.js +1 -1
  131. package/.next/server/instrumentation.js +1 -1
  132. package/.next/server/instrumentation.js.nft.json +1 -1
  133. package/.next/server/middleware-build-manifest.js +1 -1
  134. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  135. package/.next/server/pages/404.html +1 -1
  136. package/.next/server/pages/500.html +1 -1
  137. package/.next/server/server-reference-manifest.json +1 -1
  138. package/.next/static/chunks/{103.23142a67b02246a8.js → 103.6c91a059aa01d92c.js} +2 -2
  139. package/.next/static/chunks/{1032.12b382a9096ab2a4.js → 1032.9e8f793d46f463f8.js} +1 -1
  140. package/.next/static/chunks/{1063.775c442bdbeef08b.js → 1063.470df8a037dc8409.js} +1 -1
  141. package/.next/static/chunks/1a258343.f4fc2c133917ded8.js +2 -0
  142. package/.next/static/chunks/{1ba63609.b2ae90f43319a29e.js → 1ba63609.569928c7234f832c.js} +1 -1
  143. package/.next/static/chunks/{2181.ba21239d3ac39f81.js → 2181.b8dda21843ef5e74.js} +1 -1
  144. package/.next/static/chunks/{2325.23caf22075e51aa5.js → 2325.23e538886331cf64.js} +1 -1
  145. package/.next/static/chunks/{2356.523277bb8c6bf72a.js → 2356.b7312589c345edec.js} +1 -1
  146. package/.next/static/chunks/{268.72794ee2773c2060.js → 268.a1d90aca268be18a.js} +1 -1
  147. package/.next/static/chunks/{2695.6f49435bae1e6f33.js → 2695.5624aa3aae540e87.js} +1 -1
  148. package/.next/static/chunks/{2703.495a65ed14b2f094.js → 2703.097bc88286733740.js} +1 -1
  149. package/.next/static/chunks/{2821.934bcf60fbdc28c6.js → 2821.d2392a93d192fe92.js} +1 -1
  150. package/.next/static/chunks/3308.2cd6f20e6c0f4e92.js +73 -0
  151. package/.next/static/chunks/{3336.a76f9485fe7cb762.js → 3336.9b1dc9ec3507d64f.js} +1 -1
  152. package/.next/static/chunks/3546.779d2c7646aa77cc.js +1 -0
  153. package/.next/static/chunks/{370.8e8f3cf8eb0e29dd.js → 370.cde2a84caa84054f.js} +1 -1
  154. package/.next/static/chunks/{3716.72bf4c9d7325debd.js → 3716.5bac496cea32ca8f.js} +1 -1
  155. package/.next/static/chunks/{3995.eca0f5bef1fc3ae5.js → 3995.cd112debcd64c610.js} +1 -1
  156. package/.next/static/chunks/{4004.74b9bcf5478b1663.js → 4004.a8f79ef62f32aa30.js} +2 -2
  157. package/.next/static/chunks/{4202.8440832386f023c7.js → 4202.96f5b1beb8b3e3f5.js} +1 -1
  158. package/.next/static/chunks/{4238.6f102dcbcf2ae339.js → 4238.28efbf9aa0c82d90.js} +1 -1
  159. package/.next/static/chunks/{4405.7a19458960a1058e.js → 4405.cda46a596a02aef7.js} +1 -1
  160. package/.next/static/chunks/54a60aa6.5e4421e7afde4de8.js +78 -0
  161. package/.next/static/chunks/{6121.eb9023b1cbc78ee2.js → 6121.5e650e714b402b6f.js} +1 -1
  162. package/.next/static/chunks/{6195.1153369f5f8b13a2.js → 6195.1b7f9dc127381bbc.js} +1 -1
  163. package/.next/static/chunks/6380.d148a8e2c701ad78.js +68 -0
  164. package/.next/static/chunks/6582.fb2c709abc2c5981.js +1 -0
  165. package/.next/static/chunks/6be7e44c.00d0163f409986f0.js +1 -0
  166. package/.next/static/chunks/{7331.2add3c4e125a2dba.js → 7331.4afa66d6353c8e07.js} +1 -1
  167. package/.next/static/chunks/752.a05a2904b96af4d0.js +1 -0
  168. package/.next/static/chunks/{8200.a36b9f8c983c6b9e.js → 8200.350d650649b977eb.js} +1 -1
  169. package/.next/static/chunks/{8885.cf60cac98bf8b70c.js → 8885.2c060cb45c85547b.js} +1 -1
  170. package/.next/static/chunks/{918.6a9bbe564e4a2d0f.js → 918.593eb466d35cb8ad.js} +1 -1
  171. package/.next/static/chunks/{9698.4d09a99b9d99f3e5.js → 9698.758755d0387e0e22.js} +2 -2
  172. package/.next/static/chunks/97.fb73c551e14b3612.js +2 -0
  173. package/.next/static/chunks/{993e5495.8797001fcfcf2889.js → 993e5495.12cdfbc3af5c79e9.js} +1 -1
  174. package/.next/static/chunks/{9974.9a0f79beca65e8c4.js → 9974.5ee982e074ad047e.js} +1 -1
  175. package/.next/static/chunks/app/_global-error/page-bb8f79f321e26750.js +1 -0
  176. package/.next/static/chunks/app/api/agent/[id]/bash-output/route-bb8f79f321e26750.js +1 -0
  177. package/.next/static/chunks/app/api/agent/[id]/events/route-bb8f79f321e26750.js +1 -0
  178. package/.next/static/chunks/app/api/agent/[id]/route-bb8f79f321e26750.js +1 -0
  179. package/.next/static/chunks/app/api/agent/new/route-bb8f79f321e26750.js +1 -0
  180. package/.next/static/chunks/app/api/agent/running/route-bb8f79f321e26750.js +1 -0
  181. package/.next/static/chunks/app/api/app-update/route-bb8f79f321e26750.js +1 -0
  182. package/.next/static/chunks/app/api/auth/all-providers/route-bb8f79f321e26750.js +1 -0
  183. package/.next/static/chunks/app/api/auth/api-key/[provider]/route-bb8f79f321e26750.js +1 -0
  184. package/.next/static/chunks/app/api/auth/login/[provider]/route-bb8f79f321e26750.js +1 -0
  185. package/.next/static/chunks/app/api/auth/logout/[provider]/route-bb8f79f321e26750.js +1 -0
  186. package/.next/static/chunks/app/api/auth/providers/route-bb8f79f321e26750.js +1 -0
  187. package/.next/static/chunks/app/api/boards/[id]/reconcile/route-bb8f79f321e26750.js +1 -0
  188. package/.next/static/chunks/app/api/boards/[id]/route-bb8f79f321e26750.js +1 -0
  189. package/.next/static/chunks/app/api/boards/purge-orphans/route-bb8f79f321e26750.js +1 -0
  190. package/.next/static/chunks/app/api/boards/reorder/route-bb8f79f321e26750.js +1 -0
  191. package/.next/static/chunks/app/api/boards/route-bb8f79f321e26750.js +1 -0
  192. package/.next/static/chunks/app/api/cwd/browse/route-bb8f79f321e26750.js +1 -0
  193. package/.next/static/chunks/app/api/cwd/validate/route-bb8f79f321e26750.js +1 -0
  194. package/.next/static/chunks/app/api/default-cwd/route-bb8f79f321e26750.js +1 -0
  195. package/.next/static/chunks/app/api/file-index/route-bb8f79f321e26750.js +1 -0
  196. package/.next/static/chunks/app/api/files/[...path]/route-bb8f79f321e26750.js +1 -0
  197. package/.next/static/chunks/app/api/git/diff/route-bb8f79f321e26750.js +1 -0
  198. package/.next/static/chunks/app/api/git/status/route-bb8f79f321e26750.js +1 -0
  199. package/.next/static/chunks/app/api/home/route-bb8f79f321e26750.js +1 -0
  200. package/.next/static/chunks/app/api/mcp/route-bb8f79f321e26750.js +1 -0
  201. package/.next/static/chunks/app/api/models/route-bb8f79f321e26750.js +1 -0
  202. package/.next/static/chunks/app/api/models-config/catalog/route-bb8f79f321e26750.js +1 -0
  203. package/.next/static/chunks/app/api/models-config/discover/route-bb8f79f321e26750.js +1 -0
  204. package/.next/static/chunks/app/api/models-config/route-bb8f79f321e26750.js +1 -0
  205. package/.next/static/chunks/app/api/models-config/test/route-bb8f79f321e26750.js +1 -0
  206. package/.next/static/chunks/app/api/plugins/route-bb8f79f321e26750.js +1 -0
  207. package/.next/static/chunks/app/api/project-trust/route-bb8f79f321e26750.js +1 -0
  208. package/.next/static/chunks/app/api/quota/route-bb8f79f321e26750.js +1 -0
  209. package/.next/static/chunks/app/api/search/route-bb8f79f321e26750.js +1 -0
  210. package/.next/static/chunks/app/api/sessions/[id]/auto-name/route-bb8f79f321e26750.js +1 -0
  211. package/.next/static/chunks/app/api/sessions/[id]/context/route-bb8f79f321e26750.js +1 -0
  212. package/.next/static/chunks/app/api/sessions/[id]/entries/[entryId]/thinking/route-bb8f79f321e26750.js +1 -0
  213. package/.next/static/chunks/app/api/sessions/[id]/export/route-bb8f79f321e26750.js +1 -0
  214. package/.next/static/chunks/app/api/sessions/[id]/route-bb8f79f321e26750.js +1 -0
  215. package/.next/static/chunks/app/api/sessions/[id]/state/route-bb8f79f321e26750.js +1 -0
  216. package/.next/static/chunks/app/api/sessions/[id]/todos/route-bb8f79f321e26750.js +1 -0
  217. package/.next/static/chunks/app/api/sessions/route-bb8f79f321e26750.js +1 -0
  218. package/.next/static/chunks/app/api/skills/check/route-bb8f79f321e26750.js +1 -0
  219. package/.next/static/chunks/app/api/skills/install/route-bb8f79f321e26750.js +1 -0
  220. package/.next/static/chunks/app/api/skills/route-bb8f79f321e26750.js +1 -0
  221. package/.next/static/chunks/app/api/skills/search/route-bb8f79f321e26750.js +1 -0
  222. package/.next/static/chunks/app/api/skills/update/route-bb8f79f321e26750.js +1 -0
  223. package/.next/static/chunks/app/api/task-card-questions/[id]/answer/route-bb8f79f321e26750.js +1 -0
  224. package/.next/static/chunks/app/api/task-card-questions/route-bb8f79f321e26750.js +1 -0
  225. package/.next/static/chunks/app/api/task-cards/[id]/route-bb8f79f321e26750.js +1 -0
  226. package/.next/static/chunks/app/api/task-cards/route-bb8f79f321e26750.js +1 -0
  227. package/.next/static/chunks/app/api/task-scheduler/status/route-bb8f79f321e26750.js +1 -0
  228. package/.next/static/chunks/app/api/tasks/[id]/board/route-bb8f79f321e26750.js +1 -0
  229. package/.next/static/chunks/app/api/tasks/[id]/route-bb8f79f321e26750.js +1 -0
  230. package/.next/static/chunks/app/api/tasks/reorder/route-bb8f79f321e26750.js +1 -0
  231. package/.next/static/chunks/app/api/tasks/route-bb8f79f321e26750.js +1 -0
  232. package/.next/static/chunks/app/api/terminal/[id]/events/route-bb8f79f321e26750.js +1 -0
  233. package/.next/static/chunks/app/api/terminal/[id]/route-bb8f79f321e26750.js +1 -0
  234. package/.next/static/chunks/app/api/terminal/route-bb8f79f321e26750.js +1 -0
  235. package/.next/static/chunks/app/api/worktrees/route-bb8f79f321e26750.js +1 -0
  236. package/.next/static/chunks/app/{layout-7761e430ed68b347.js → layout-2bec2662143a3d1b.js} +1 -1
  237. package/.next/static/chunks/app/manifest.webmanifest/route-bb8f79f321e26750.js +1 -0
  238. package/.next/static/chunks/app/page-e38c6cf3174fa143.js +89 -0
  239. package/.next/static/chunks/next/dist/client/components/builtin/app-error-bb8f79f321e26750.js +1 -0
  240. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-bb8f79f321e26750.js +1 -0
  241. package/.next/static/chunks/next/dist/client/components/builtin/not-found-bb8f79f321e26750.js +1 -0
  242. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-bb8f79f321e26750.js +1 -0
  243. package/.next/static/chunks/webpack-b4924d2a22ad3650.js +1 -0
  244. package/.next/static/css/0c7244f7214af81f.css +1 -0
  245. package/.next/static/css/12456255969ac8de.css +31 -0
  246. package/.next/trace +8 -49
  247. package/.next/trace-build +1 -1
  248. package/.next/types/app/api/boards/[id]/{reconcile-task-edges → reconcile}/route.ts +3 -3
  249. package/.next/types/routes.d.ts +2 -7
  250. package/.next/types/validator.ts +3 -48
  251. package/README.md +6 -9
  252. package/THIRD_PARTY_NOTICES.md +10 -82
  253. package/bin/pi-web-sky.js +3 -3
  254. package/lib/board-reconcile-scheduler.ts +56 -0
  255. package/lib/board-reconcile.test.mjs +252 -0
  256. package/lib/board-reconcile.ts +421 -0
  257. package/lib/board-store.test.mjs +26 -4
  258. package/lib/board-store.ts +44 -6
  259. package/lib/board-types.ts +7 -2
  260. package/lib/i18n/messages/en.ts +1 -1
  261. package/lib/i18n/messages/zh-CN.ts +1 -1
  262. package/lib/session-delete.ts +5 -0
  263. package/lib/sqlite-db.ts +13 -1
  264. package/lib/task-card-store.test.mjs +16 -1
  265. package/lib/task-card-store.ts +37 -1
  266. package/lib/task-scheduler.test.mjs +79 -0
  267. package/lib/task-scheduler.ts +195 -21
  268. package/lib/yjs-room-server.mjs +139 -0
  269. package/package.json +12 -9
  270. package/server.mjs +7 -7
  271. package/.next/server/app/api/boards/[id]/canvas/route.js +0 -1
  272. package/.next/server/app/api/boards/[id]/canvas/route_client-reference-manifest.js +0 -1
  273. package/.next/server/app/api/boards/[id]/edges/[eid]/route.js +0 -1
  274. package/.next/server/app/api/boards/[id]/edges/[eid]/route.js.nft.json +0 -1
  275. package/.next/server/app/api/boards/[id]/edges/[eid]/route_client-reference-manifest.js +0 -1
  276. package/.next/server/app/api/boards/[id]/edges/route.js +0 -1
  277. package/.next/server/app/api/boards/[id]/edges/route.js.nft.json +0 -1
  278. package/.next/server/app/api/boards/[id]/edges/route_client-reference-manifest.js +0 -1
  279. package/.next/server/app/api/boards/[id]/nodes/[nid]/route.js +0 -1
  280. package/.next/server/app/api/boards/[id]/nodes/[nid]/route.js.nft.json +0 -1
  281. package/.next/server/app/api/boards/[id]/nodes/[nid]/route_client-reference-manifest.js +0 -1
  282. package/.next/server/app/api/boards/[id]/nodes/route.js +0 -1
  283. package/.next/server/app/api/boards/[id]/nodes/route.js.nft.json +0 -1
  284. package/.next/server/app/api/boards/[id]/nodes/route_client-reference-manifest.js +0 -1
  285. package/.next/server/app/api/boards/[id]/reconcile-task-edges/route.js +0 -1
  286. package/.next/server/app/api/boards/[id]/reconcile-task-edges/route.js.nft.json +0 -1
  287. package/.next/server/app/api/boards/[id]/reconcile-task-edges/route_client-reference-manifest.js +0 -1
  288. package/.next/static/chunks/3308.857c554428b3294e.js +0 -73
  289. package/.next/static/chunks/333.bf0651c789b2eb33.js +0 -1
  290. package/.next/static/chunks/5315.dba7515ae6e139ae.js +0 -4
  291. package/.next/static/chunks/54a60aa6.0e43cde7298ebcb7.js +0 -78
  292. package/.next/static/chunks/7999.879d5a20e8641752.js +0 -259
  293. package/.next/static/chunks/app/_global-error/page-d6f52627eddf9119.js +0 -1
  294. package/.next/static/chunks/app/api/agent/[id]/bash-output/route-d6f52627eddf9119.js +0 -1
  295. package/.next/static/chunks/app/api/agent/[id]/events/route-d6f52627eddf9119.js +0 -1
  296. package/.next/static/chunks/app/api/agent/[id]/route-d6f52627eddf9119.js +0 -1
  297. package/.next/static/chunks/app/api/agent/new/route-d6f52627eddf9119.js +0 -1
  298. package/.next/static/chunks/app/api/agent/running/route-d6f52627eddf9119.js +0 -1
  299. package/.next/static/chunks/app/api/app-update/route-d6f52627eddf9119.js +0 -1
  300. package/.next/static/chunks/app/api/auth/all-providers/route-d6f52627eddf9119.js +0 -1
  301. package/.next/static/chunks/app/api/auth/api-key/[provider]/route-d6f52627eddf9119.js +0 -1
  302. package/.next/static/chunks/app/api/auth/login/[provider]/route-d6f52627eddf9119.js +0 -1
  303. package/.next/static/chunks/app/api/auth/logout/[provider]/route-d6f52627eddf9119.js +0 -1
  304. package/.next/static/chunks/app/api/auth/providers/route-d6f52627eddf9119.js +0 -1
  305. package/.next/static/chunks/app/api/boards/[id]/canvas/route-d6f52627eddf9119.js +0 -1
  306. package/.next/static/chunks/app/api/boards/[id]/edges/[eid]/route-d6f52627eddf9119.js +0 -1
  307. package/.next/static/chunks/app/api/boards/[id]/edges/route-d6f52627eddf9119.js +0 -1
  308. package/.next/static/chunks/app/api/boards/[id]/nodes/[nid]/route-d6f52627eddf9119.js +0 -1
  309. package/.next/static/chunks/app/api/boards/[id]/nodes/route-d6f52627eddf9119.js +0 -1
  310. package/.next/static/chunks/app/api/boards/[id]/reconcile-task-edges/route-d6f52627eddf9119.js +0 -1
  311. package/.next/static/chunks/app/api/boards/[id]/route-d6f52627eddf9119.js +0 -1
  312. package/.next/static/chunks/app/api/boards/purge-orphans/route-d6f52627eddf9119.js +0 -1
  313. package/.next/static/chunks/app/api/boards/reorder/route-d6f52627eddf9119.js +0 -1
  314. package/.next/static/chunks/app/api/boards/route-d6f52627eddf9119.js +0 -1
  315. package/.next/static/chunks/app/api/cwd/browse/route-d6f52627eddf9119.js +0 -1
  316. package/.next/static/chunks/app/api/cwd/validate/route-d6f52627eddf9119.js +0 -1
  317. package/.next/static/chunks/app/api/default-cwd/route-d6f52627eddf9119.js +0 -1
  318. package/.next/static/chunks/app/api/file-index/route-d6f52627eddf9119.js +0 -1
  319. package/.next/static/chunks/app/api/files/[...path]/route-d6f52627eddf9119.js +0 -1
  320. package/.next/static/chunks/app/api/git/diff/route-d6f52627eddf9119.js +0 -1
  321. package/.next/static/chunks/app/api/git/status/route-d6f52627eddf9119.js +0 -1
  322. package/.next/static/chunks/app/api/home/route-d6f52627eddf9119.js +0 -1
  323. package/.next/static/chunks/app/api/mcp/route-d6f52627eddf9119.js +0 -1
  324. package/.next/static/chunks/app/api/models/route-d6f52627eddf9119.js +0 -1
  325. package/.next/static/chunks/app/api/models-config/catalog/route-d6f52627eddf9119.js +0 -1
  326. package/.next/static/chunks/app/api/models-config/discover/route-d6f52627eddf9119.js +0 -1
  327. package/.next/static/chunks/app/api/models-config/route-d6f52627eddf9119.js +0 -1
  328. package/.next/static/chunks/app/api/models-config/test/route-d6f52627eddf9119.js +0 -1
  329. package/.next/static/chunks/app/api/plugins/route-d6f52627eddf9119.js +0 -1
  330. package/.next/static/chunks/app/api/project-trust/route-d6f52627eddf9119.js +0 -1
  331. package/.next/static/chunks/app/api/quota/route-d6f52627eddf9119.js +0 -1
  332. package/.next/static/chunks/app/api/search/route-d6f52627eddf9119.js +0 -1
  333. package/.next/static/chunks/app/api/sessions/[id]/auto-name/route-d6f52627eddf9119.js +0 -1
  334. package/.next/static/chunks/app/api/sessions/[id]/context/route-d6f52627eddf9119.js +0 -1
  335. package/.next/static/chunks/app/api/sessions/[id]/entries/[entryId]/thinking/route-d6f52627eddf9119.js +0 -1
  336. package/.next/static/chunks/app/api/sessions/[id]/export/route-d6f52627eddf9119.js +0 -1
  337. package/.next/static/chunks/app/api/sessions/[id]/route-d6f52627eddf9119.js +0 -1
  338. package/.next/static/chunks/app/api/sessions/[id]/state/route-d6f52627eddf9119.js +0 -1
  339. package/.next/static/chunks/app/api/sessions/[id]/todos/route-d6f52627eddf9119.js +0 -1
  340. package/.next/static/chunks/app/api/sessions/route-d6f52627eddf9119.js +0 -1
  341. package/.next/static/chunks/app/api/skills/check/route-d6f52627eddf9119.js +0 -1
  342. package/.next/static/chunks/app/api/skills/install/route-d6f52627eddf9119.js +0 -1
  343. package/.next/static/chunks/app/api/skills/route-d6f52627eddf9119.js +0 -1
  344. package/.next/static/chunks/app/api/skills/search/route-d6f52627eddf9119.js +0 -1
  345. package/.next/static/chunks/app/api/skills/update/route-d6f52627eddf9119.js +0 -1
  346. package/.next/static/chunks/app/api/task-card-questions/[id]/answer/route-d6f52627eddf9119.js +0 -1
  347. package/.next/static/chunks/app/api/task-card-questions/route-d6f52627eddf9119.js +0 -1
  348. package/.next/static/chunks/app/api/task-cards/[id]/route-d6f52627eddf9119.js +0 -1
  349. package/.next/static/chunks/app/api/task-cards/route-d6f52627eddf9119.js +0 -1
  350. package/.next/static/chunks/app/api/task-scheduler/status/route-d6f52627eddf9119.js +0 -1
  351. package/.next/static/chunks/app/api/tasks/[id]/board/route-d6f52627eddf9119.js +0 -1
  352. package/.next/static/chunks/app/api/tasks/[id]/route-d6f52627eddf9119.js +0 -1
  353. package/.next/static/chunks/app/api/tasks/reorder/route-d6f52627eddf9119.js +0 -1
  354. package/.next/static/chunks/app/api/tasks/route-d6f52627eddf9119.js +0 -1
  355. package/.next/static/chunks/app/api/terminal/[id]/events/route-d6f52627eddf9119.js +0 -1
  356. package/.next/static/chunks/app/api/terminal/[id]/route-d6f52627eddf9119.js +0 -1
  357. package/.next/static/chunks/app/api/terminal/route-d6f52627eddf9119.js +0 -1
  358. package/.next/static/chunks/app/api/worktrees/route-d6f52627eddf9119.js +0 -1
  359. package/.next/static/chunks/app/manifest.webmanifest/route-d6f52627eddf9119.js +0 -1
  360. package/.next/static/chunks/app/page-2c87c41e7f848f45.js +0 -89
  361. package/.next/static/chunks/e3e7ddb2.a35db430b3564999.js +0 -1
  362. package/.next/static/chunks/next/dist/client/components/builtin/app-error-d6f52627eddf9119.js +0 -1
  363. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-d6f52627eddf9119.js +0 -1
  364. package/.next/static/chunks/next/dist/client/components/builtin/not-found-d6f52627eddf9119.js +0 -1
  365. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d6f52627eddf9119.js +0 -1
  366. package/.next/static/chunks/webpack-4bbf04891e910713.js +0 -1
  367. package/.next/static/css/80c818c5781fbadc.css +0 -4
  368. package/.next/static/css/d3a2b5077b52c727.css +0 -1
  369. package/.next/types/app/api/boards/[id]/canvas/route.ts +0 -353
  370. package/.next/types/app/api/boards/[id]/edges/[eid]/route.ts +0 -353
  371. package/.next/types/app/api/boards/[id]/edges/route.ts +0 -353
  372. package/.next/types/app/api/boards/[id]/nodes/[nid]/route.ts +0 -353
  373. package/.next/types/app/api/boards/[id]/nodes/route.ts +0 -353
  374. package/lib/board-search.test.mjs +0 -110
  375. package/lib/board-search.ts +0 -63
  376. package/lib/file-explorer-state.test.mjs +0 -63
  377. package/lib/file-explorer-state.ts +0 -36
  378. package/lib/sync-room-server.mjs +0 -137
  379. /package/.next/server/app/api/boards/[id]/{canvas → reconcile}/route.js.nft.json +0 -0
  380. /package/.next/static/{IzmOG04jJst1VpUvr_fr5 → 8V884w_cp5HEp_rRpjnCR}/_buildManifest.js +0 -0
  381. /package/.next/static/{IzmOG04jJst1VpUvr_fr5 → 8V884w_cp5HEp_rRpjnCR}/_ssgManifest.js +0 -0
@@ -1,110 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import { createJiti } from "jiti";
4
-
5
- const jiti = createJiti(import.meta.url, { interopDefault: true, moduleCache: false });
6
- const { collectSearchable, filterMatches, makeSnippet } = await jiti.import("./board-search.ts");
7
-
8
- /** 构造 fake tldraw editor(单测只依赖 getCurrentPageShapes/getShape/getShapePageBounds) */
9
- function fakeEditor(shapes) {
10
- return {
11
- getCurrentPageShapes: () => shapes,
12
- getShape: (id) => shapes.find((s) => s.id === id),
13
- getShapePageBounds: (id) => {
14
- const s = shapes.find((x) => x.id === id);
15
- return s ? { x: s.x ?? 0, y: s.y ?? 0, w: s.w ?? 100, h: s.h ?? 100 } : undefined;
16
- },
17
- };
18
- }
19
-
20
- const shape = (id, type, props) => ({ id, type, props });
21
-
22
- test("collectSearchable 收集会话卡标题 + 便笺正文,跳过空文本与无关 shape", () => {
23
- const editor = fakeEditor([
24
- shape("shape:a", "session-card", { title: "登录重构", sessionId: "s1" }),
25
- shape("shape:b", "session-card", { title: " ", sessionId: "s2" }), // 空标题跳过
26
- shape("shape:c", "sticky-note", { text: "便笺:token 校验" }),
27
- shape("shape:d", "sticky-note", { text: "" }), // 空便笺跳过
28
- shape("shape:e", "arrow", { label: "不能搜连线" }), // 无关 type 跳过
29
- shape("shape:f", "text", { text: "普通文本不搜" }), // 无关 type 跳过
30
- ]);
31
- const items = collectSearchable(editor);
32
- assert.deepEqual(items.map((i) => i.text), ["登录重构", "便笺:token 校验"]);
33
- assert.deepEqual(items.map((i) => i.kind), ["session-card", "sticky-note"]);
34
- });
35
-
36
- test("filterMatches 中文子串命中", () => {
37
- const editor = fakeEditor([
38
- shape("a", "session-card", { title: "修复登录接口的 bug" }),
39
- shape("b", "sticky-note", { text: "记录 token 过期逻辑" }),
40
- ]);
41
- const items = collectSearchable(editor);
42
- const hits = filterMatches(items, "登录");
43
- assert.equal(hits.length, 1);
44
- assert.equal(hits[0].item.shapeId, "a");
45
- });
46
-
47
- test("filterMatches 大小写不敏感(英文)", () => {
48
- const editor = fakeEditor([
49
- shape("a", "session-card", { title: "Refactor Token Logic" }),
50
- shape("b", "sticky-note", { text: "another note" }),
51
- ]);
52
- const items = collectSearchable(editor);
53
- assert.equal(filterMatches(items, "token").length, 1);
54
- assert.equal(filterMatches(items, "TOKEN").length, 1);
55
- assert.equal(filterMatches(items, "Token").length, 1);
56
- assert.equal(filterMatches(items, "tokenz").length, 0);
57
- });
58
-
59
- test("filterMatches 空 query 返回空", () => {
60
- const editor = fakeEditor([shape("a", "session-card", { title: "anything" })]);
61
- const items = collectSearchable(editor);
62
- assert.equal(filterMatches(items, "").length, 0);
63
- assert.equal(filterMatches(items, " ").length, 0);
64
- });
65
-
66
- test("filterMatches 多命中保持画布遍历顺序", () => {
67
- const editor = fakeEditor([
68
- shape("a", "sticky-note", { text: "zzz 搜索 zzz" }),
69
- shape("b", "session-card", { title: "aaa 搜索 bbb" }),
70
- shape("c", "sticky-note", { text: "搜索收尾" }),
71
- ]);
72
- const items = collectSearchable(editor);
73
- const hits = filterMatches(items, "搜索");
74
- assert.deepEqual(hits.map((h) => h.item.shapeId), ["a", "b", "c"]);
75
- });
76
-
77
- test("filterMatches 多关键字空格分隔 AND 关系", () => {
78
- const editor = fakeEditor([
79
- shape("a", "session-card", { title: "修复登录接口 token 过期" }),
80
- shape("b", "sticky-note", { text: "登录流程重构" }),
81
- shape("c", "session-card", { title: "部署配置调整" }),
82
- shape("d", "session-card", { title: "登录接口优化" }),
83
- ]);
84
- const items = collectSearchable(editor);
85
- // 两个词都在同一节点文本里才命中(AND)
86
- assert.deepEqual(filterMatches(items, "登录 token").map((h) => h.item.shapeId), ["a"]);
87
- assert.deepEqual(filterMatches(items, "登录 重构").map((h) => h.item.shapeId), ["b"]);
88
- assert.deepEqual(filterMatches(items, "登录 接口").map((h) => h.item.shapeId), ["a", "d"]);
89
- // 缺任一词不命中
90
- assert.equal(filterMatches(items, "登录 不存在词").length, 0);
91
- // 多个空格/首尾空格容忍
92
- assert.deepEqual(filterMatches(items, " 登录 接口 ").map((h) => h.item.shapeId), ["a", "d"]);
93
- });
94
-
95
- test("makeSnippet 命中居中截断 + 两端省略号", () => {
96
- const long = "这是一段很长的便笺文本,中间藏着关键词,后面还有更多内容需要被截断显示以便下拉列表保持整洁。";
97
- const s = makeSnippet(long, "关键词", 20);
98
- assert.ok(s.includes("关键词"), `snippet should contain the hit: ${s}`);
99
- assert.ok(s.startsWith("…"), "head ellipsis");
100
- assert.ok(s.endsWith("…"), "tail ellipsis");
101
- assert.ok(s.length <= 24, `bounded length: ${s.length}`);
102
- });
103
-
104
- test("makeSnippet 无命中时首段截断", () => {
105
- const short = "hello";
106
- assert.equal(makeSnippet(short, "zzz"), "hello");
107
- const long = "x".repeat(100);
108
- const s = makeSnippet(long, "zzz");
109
- assert.equal(s, `${"x".repeat(44)}…`);
110
- });
@@ -1,63 +0,0 @@
1
- /**
2
- * 看板内搜索定位(Ctrl+F)的纯函数。
3
- *
4
- * 只遍历当前画布上的 shape(session-card 标题 + sticky-note 便笺文字),
5
- * 不做会话正文索引(正文搜索属另一需求,见 .agent/spec/2026-08-30-board-search.md 不做项)。
6
- * 画布节点量级小(几十个),includes 子串匹配足够,无需索引。
7
- */
8
-
9
- import type { Editor, TLShapeId } from "tldraw";
10
-
11
- export type SearchableKind = "session-card" | "sticky-note";
12
-
13
- export interface SearchableItem {
14
- shapeId: TLShapeId;
15
- kind: SearchableKind;
16
- /** 完整原文(匹配用全文) */
17
- text: string;
18
- }
19
-
20
- export interface SearchMatch {
21
- item: SearchableItem;
22
- /** 命中片段(下拉展示用,前后截断) */
23
- snippet: string;
24
- }
25
-
26
- /** 收集当前画布上可搜索的节点。空文本节点跳过(无搜索价值)。 */
27
- export function collectSearchable(editor: Editor): SearchableItem[] {
28
- const out: SearchableItem[] = [];
29
- for (const shape of editor.getCurrentPageShapes()) {
30
- if (shape.type === "session-card") {
31
- const title = String((shape.props as { title?: unknown }).title ?? "").trim();
32
- if (title) out.push({ shapeId: shape.id, kind: "session-card", text: title });
33
- } else if (shape.type === "sticky-note") {
34
- const text = String((shape.props as { text?: unknown }).text ?? "").trim();
35
- if (text) out.push({ shapeId: shape.id, kind: "sticky-note", text });
36
- }
37
- }
38
- return out;
39
- }
40
-
41
- /** 按 query 过滤:空格分隔多个关键字,全部命中(AND)才算匹配。空 query 返回空结果。 */
42
- export function filterMatches(items: SearchableItem[], query: string): SearchMatch[] {
43
- const terms = query.trim().toLowerCase().split(/\s+/).filter(Boolean);
44
- if (terms.length === 0) return [];
45
- return items
46
- .filter((it) => {
47
- const text = it.text.toLowerCase();
48
- return terms.every((term) => text.includes(term));
49
- })
50
- .map((it) => ({ item: it, snippet: makeSnippet(it.text, terms[0]) }));
51
- }
52
-
53
- /** 命中片段:以首个命中位置为中心截取 ~44 字符,两端加省略号。 */
54
- export function makeSnippet(text: string, query: string, maxLen = 44): string {
55
- const q = query.trim().toLowerCase();
56
- const idx = text.toLowerCase().indexOf(q);
57
- if (idx < 0) return text.length > maxLen ? `${text.slice(0, maxLen)}…` : text;
58
- const start = Math.max(0, idx - Math.floor((maxLen - q.length) / 2));
59
- const end = Math.min(text.length, start + maxLen);
60
- const head = start > 0 ? "…" : "";
61
- const tail = end < text.length ? "…" : "";
62
- return `${head}${text.slice(start, end)}${tail}`;
63
- }
@@ -1,63 +0,0 @@
1
- import assert from "node:assert/strict";
2
- import test from "node:test";
3
- import { createJiti } from "jiti";
4
-
5
- const jiti = createJiti(import.meta.url);
6
- const { loadExplorerOpen, saveExplorerOpen } = await jiti.import("./file-explorer-state.ts");
7
-
8
- function createStorage(initial = {}) {
9
- const values = new Map(Object.entries(initial));
10
- return {
11
- values,
12
- getItem(key) {
13
- return values.get(key) ?? null;
14
- },
15
- setItem(key, value) {
16
- values.set(key, value);
17
- },
18
- };
19
- }
20
-
21
- test("defaults to an open file explorer", () => {
22
- assert.equal(loadExplorerOpen(createStorage()), true);
23
- });
24
-
25
- test("saves and restores the file explorer panel state", () => {
26
- const storage = createStorage();
27
-
28
- saveExplorerOpen(false, storage);
29
- assert.equal(loadExplorerOpen(storage), false);
30
-
31
- saveExplorerOpen(true, storage);
32
- assert.equal(loadExplorerOpen(storage), true);
33
- });
34
-
35
- test("falls back to open when browser storage is unavailable", () => {
36
- const unavailable = {
37
- getItem() { throw new Error("blocked"); },
38
- setItem() { throw new Error("blocked"); },
39
- };
40
-
41
- assert.equal(loadExplorerOpen(unavailable), true);
42
- assert.doesNotThrow(() => saveExplorerOpen(false, unavailable));
43
- });
44
-
45
- test("falls back when accessing browser storage throws", () => {
46
- const previousWindow = Object.getOwnPropertyDescriptor(globalThis, "window");
47
- const blockedWindow = {};
48
- Object.defineProperty(blockedWindow, "localStorage", {
49
- get() { throw new DOMException("blocked", "SecurityError"); },
50
- });
51
- Object.defineProperty(globalThis, "window", {
52
- configurable: true,
53
- value: blockedWindow,
54
- });
55
-
56
- try {
57
- assert.equal(loadExplorerOpen(), true);
58
- assert.doesNotThrow(() => saveExplorerOpen(false));
59
- } finally {
60
- if (previousWindow) Object.defineProperty(globalThis, "window", previousWindow);
61
- else delete globalThis.window;
62
- }
63
- });
@@ -1,36 +0,0 @@
1
- const EXPLORER_OPEN_STORAGE_KEY = "pi-web:file-explorer:open";
2
-
3
- interface StorageLike {
4
- getItem(key: string): string | null;
5
- setItem(key: string, value: string): void;
6
- }
7
-
8
- function getBrowserStorage(): StorageLike | null {
9
- if (typeof window === "undefined") return null;
10
- try {
11
- return window.localStorage;
12
- } catch {
13
- return null;
14
- }
15
- }
16
-
17
- export function loadExplorerOpen(storage: StorageLike | null = getBrowserStorage()): boolean {
18
- if (!storage) return true;
19
- try {
20
- return storage.getItem(EXPLORER_OPEN_STORAGE_KEY) !== "false";
21
- } catch {
22
- return true;
23
- }
24
- }
25
-
26
- export function saveExplorerOpen(
27
- open: boolean,
28
- storage: StorageLike | null = getBrowserStorage(),
29
- ): void {
30
- if (!storage) return;
31
- try {
32
- storage.setItem(EXPLORER_OPEN_STORAGE_KEY, String(open));
33
- } catch {
34
- // Persistence is best-effort; privacy mode and storage quotas must not break the explorer.
35
- }
36
- }
@@ -1,137 +0,0 @@
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
- }