@allbluecn/web-app 0.18.2 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (761) hide show
  1. package/package.json +66 -51
  2. package/src/__tests__/components/auth/auth-layout.test.tsx +13 -1
  3. package/src/__tests__/{knowledge-public → knowledge/public}/canonical-id.test.ts +1 -1
  4. package/src/__tests__/{knowledge-public → knowledge/public}/favicon.test.ts +1 -1
  5. package/src/__tests__/{knowledge-public → knowledge/public}/github-sync.test.ts +1 -1
  6. package/src/__tests__/{knowledge-public → knowledge/public}/share-merge.test.ts +7 -7
  7. package/src/__tests__/security/xss-sanitize.test.ts +9 -8
  8. package/src/components/ai/__tests__/chat-thread-id-stability.test.tsx +125 -0
  9. package/src/components/ai/ai-chat-prompt.tsx +8 -2
  10. package/src/components/ai/ai-prompt-input/index.tsx +2 -1
  11. package/src/components/ai/global-harness-sidebar/__tests__/global-ai-prompts.test.ts +1 -2
  12. package/src/components/ai/global-harness-sidebar/index.tsx +22 -10
  13. package/src/components/bug/__tests__/board-subgroups.test.tsx +512 -0
  14. package/src/components/bug/__tests__/board-view.test.tsx +350 -0
  15. package/src/components/bug/__tests__/bug-list-loading-defer.test.tsx +85 -0
  16. package/src/components/bug/__tests__/bug-toolbar.test.tsx +7 -1
  17. package/src/components/bug/__tests__/comment-reactions.test.tsx +182 -0
  18. package/src/components/bug/__tests__/date-and-lightbox.test.tsx +96 -0
  19. package/src/components/bug/__tests__/export-entry.test.tsx +217 -0
  20. package/src/components/bug/__tests__/filters-compat.test.tsx +157 -0
  21. package/src/components/bug/__tests__/fix-request-race.test.tsx +396 -0
  22. package/src/components/bug/__tests__/peek-modes.test.tsx +365 -0
  23. package/src/components/bug/__tests__/saved-views.test.tsx +309 -0
  24. package/src/components/bug/__tests__/story-bugs-panel.test.tsx +146 -0
  25. package/src/components/bug/__tests__/subgroup-header.test.tsx +150 -0
  26. package/src/components/bug/__tests__/toolbar-shell.test.tsx +369 -0
  27. package/src/components/bug/__tests__/use-paged-bug-groups.test.tsx +58 -0
  28. package/src/components/bug/__tests__/view-type.test.tsx +247 -0
  29. package/src/components/bug/bug-list-view.tsx +310 -13
  30. package/src/components/bug/bug-panel-header.tsx +84 -8
  31. package/src/components/bug/bug-toolbar.tsx +268 -116
  32. package/src/components/bug/create-bug-dialog.tsx +1 -1
  33. package/src/components/bug/detail/__tests__/activity-timeline.test.tsx +1 -0
  34. package/src/components/bug/detail/__tests__/bug-detail-collab.test.tsx +236 -0
  35. package/src/components/bug/detail/__tests__/repro-report-card.test.tsx +2 -1
  36. package/src/components/bug/detail/activity-timeline.tsx +1 -1
  37. package/src/components/bug/detail/bug-detail-body.tsx +316 -18
  38. package/src/components/bug/detail/comment-item.tsx +7 -2
  39. package/src/components/bug/detail/comment-reactions.tsx +138 -0
  40. package/src/components/bug/detail/error-context.tsx +29 -9
  41. package/src/components/bug/detail/props-section.tsx +31 -3
  42. package/src/components/bug/detail/repro-report-card.tsx +1 -1
  43. package/src/components/bug/display/constants.ts +4 -2
  44. package/src/components/bug/display/display-dropdown.tsx +76 -280
  45. package/src/components/bug/display/types.ts +24 -8
  46. package/src/components/bug/display/use-paged-bug-groups.ts +183 -32
  47. package/src/components/bug/filters/{filter-value-input.tsx → field-configs.tsx} +218 -106
  48. package/src/components/bug/filters/index.tsx +14 -5
  49. package/src/components/bug/inline-editors/assignee-editor.tsx +2 -2
  50. package/src/components/bug/inline-editors/labels-editor.tsx +1 -1
  51. package/src/components/bug/inline-editors/severity-editor.tsx +37 -18
  52. package/src/components/bug/inline-editors/state-editor.tsx +1 -1
  53. package/src/components/bug/peek-panel.tsx +153 -35
  54. package/src/components/bug/select-bug-dialog.tsx +500 -0
  55. package/src/components/bug/story-bugs-panel.tsx +1090 -0
  56. package/src/components/bug/types.ts +9 -2
  57. package/src/components/bug/views/board-view.tsx +661 -0
  58. package/src/components/bug/views/bug-list/batch-toolbar.tsx +25 -34
  59. package/src/components/bug/views/bug-list/group.tsx +28 -13
  60. package/src/components/bug/views/bug-list/index.tsx +223 -59
  61. package/src/components/bug/views/bug-list/row.tsx +7 -1
  62. package/src/components/bug/views/create-view-dialog.tsx +160 -0
  63. package/src/components/bug/views/view-list-section.tsx +140 -0
  64. package/src/components/bug/views/view-selector-button.tsx +145 -0
  65. package/src/components/bug/views/view-switcher.tsx +8 -6
  66. package/src/components/bug/views/view-types.ts +162 -0
  67. package/src/components/collab/__tests__/activity-attribution.test.tsx +211 -0
  68. package/src/components/collab/__tests__/canvas-collab-panel.test.tsx +118 -0
  69. package/src/components/collab/__tests__/collab-presence-header.test.tsx +335 -0
  70. package/src/components/collab/__tests__/entity-presence-badge.test.tsx +226 -0
  71. package/src/components/collab/activity-attribution.tsx +221 -0
  72. package/src/components/collab/canvas-collab-panel.tsx +104 -0
  73. package/src/components/collab/collab-presence-header.tsx +220 -0
  74. package/src/components/collab/entity-presence-badge.tsx +130 -0
  75. package/src/components/collab/field-editing-pill.tsx +137 -0
  76. package/src/components/command/command-palette.tsx +6 -6
  77. package/src/components/design/canvas/document/__tests__/canvas-tree-fixture-snapshot.ts +589 -0
  78. package/src/components/design/canvas/document/__tests__/canvas-tree-reconcile.test.ts +159 -0
  79. package/src/components/design/canvas/panels/toolbar.tsx +3 -2
  80. package/src/components/design/canvas/plugins/presence/__tests__/canvas-collab-wiring.test.tsx +660 -0
  81. package/src/components/design/canvas/plugins/presence/__tests__/layout.test.ts +292 -0
  82. package/src/components/design/canvas/plugins/presence/__tests__/presence-overlay.test.tsx +139 -0
  83. package/src/components/design/canvas/plugins/presence/layout.ts +222 -0
  84. package/src/components/design/canvas/plugins/presence/presence-layer.tsx +353 -0
  85. package/src/components/design/canvas/plugins/presence/presence-overlay.tsx +155 -0
  86. package/src/components/design/canvas/plugins/presence/viewer-badge.tsx +80 -0
  87. package/src/components/design/canvas/react/__tests__/hooks.test.tsx +4 -4
  88. package/src/components/design/editor/collaboration/__tests__/design-agent-panel-regenerate.test.tsx +3 -1
  89. package/src/components/design/editor/collaboration/__tests__/design-agent-panel-stream.test.tsx +3 -1
  90. package/src/components/design/editor/collaboration/design-agent-panel.tsx +3 -0
  91. package/src/components/design/editor/collaboration/design-comment-review-panel.tsx +5 -5
  92. package/src/components/design/editor/dashboard/create-design-dialog.tsx +1 -1
  93. package/src/components/design/editor/dashboard/design-dashboard.tsx +1 -10
  94. package/src/components/design/editor/layout/__tests__/collab-param-wiring.test.tsx +153 -0
  95. package/src/components/design/editor/layout/__tests__/no-page-save-toast.test.tsx +8 -0
  96. package/src/components/design/editor/layout/design-editor-layout.tsx +28 -1
  97. package/src/components/design/editor/layout/design-navigation.tsx +0 -4
  98. package/src/components/design/editor/layout/hooks/__tests__/use-design-auto-save-collab.test.tsx +130 -0
  99. package/src/components/design/editor/layout/hooks/use-design-auto-save.ts +18 -1
  100. package/src/components/design/editor/share/share-comment-panel.tsx +37 -20
  101. package/src/components/design/editor/share/share-layout.tsx +3 -0
  102. package/src/components/design/editor/share/share-nav-bar.tsx +7 -1
  103. package/src/components/design/editor/share/share-theme-toggle.tsx +10 -15
  104. package/src/components/design/editor/tiptap/node/paragraph-node/paragraph-node.scss +1 -1
  105. package/src/components/harness/__tests__/composer-draft.test.ts +126 -0
  106. package/src/components/harness/composer/composer-editor.tsx +64 -6
  107. package/src/components/harness/composer/harness-composer.tsx +1 -1
  108. package/src/components/harness/harness-layout.tsx +1 -1
  109. package/src/components/harness/harness-workbench-page.tsx +6 -1
  110. package/src/components/harness/turn-group.tsx +1 -1
  111. package/src/components/hotkeys/shortcut-badge.tsx +4 -4
  112. package/src/components/knowledge/dialog/knowledge-form-dialog.tsx +1 -1
  113. package/src/components/knowledge/editor/__tests__/knowledge-doc-editor-collab.test.tsx +542 -0
  114. package/src/components/knowledge/editor/doc-header.tsx +7 -49
  115. package/src/components/knowledge/editor/knowledge-doc-editor.tsx +264 -51
  116. package/src/components/knowledge/editor/mindmap-doc-editor.tsx +3 -19
  117. package/src/components/knowledge/knowledge-homepage.tsx +3 -3
  118. package/src/components/knowledge/knowledge-toolbar.tsx +8 -8
  119. package/src/components/{knowledge-public → knowledge/public}/bookmark-form-dialog.tsx +4 -4
  120. package/src/components/{knowledge-public → knowledge/public}/knowledge-card.tsx +1 -15
  121. package/src/components/{knowledge-public → knowledge/public}/knowledge-form-dialog.tsx +9 -9
  122. package/src/components/{knowledge-public → knowledge/public}/legal-compliance-editor.tsx +35 -28
  123. package/src/components/{knowledge-public → knowledge/public}/sharers-avatar-group.tsx +3 -2
  124. package/src/components/layout/layout-responsive-provider.tsx +79 -0
  125. package/src/components/layout/sidebar-03/__tests__/presence-avatar-stack.test.tsx +148 -0
  126. package/src/components/layout/sidebar-03/app-sidebar.tsx +9 -3
  127. package/src/components/layout/sidebar-03/index.tsx +19 -4
  128. package/src/components/layout/sidebar-03/nav-main.tsx +28 -10
  129. package/src/components/layout/sidebar-03/presence-avatar-stack.tsx +112 -0
  130. package/src/components/layout/sidebar-03/user-menu.tsx +3 -3
  131. package/src/components/project/create-project-dialog.tsx +1 -1
  132. package/src/components/project/invite-member-dialog.tsx +1 -1
  133. package/src/components/project/project-activity-list.tsx +2 -2
  134. package/src/components/project/project-member-manager.tsx +2 -2
  135. package/src/components/reui/__tests__/kanban-drop-indicator.test.ts +88 -0
  136. package/src/components/reui/__tests__/kanban-keyboard.test.ts +262 -0
  137. package/src/components/reui/event-calendar/event-calendar-agenda-view.tsx +236 -0
  138. package/src/components/reui/event-calendar/event-calendar-content.tsx +80 -0
  139. package/src/components/reui/event-calendar/event-calendar-dnd.tsx +1062 -0
  140. package/src/components/reui/event-calendar/event-calendar-event.tsx +555 -0
  141. package/src/components/reui/event-calendar/event-calendar-i18n.tsx +291 -0
  142. package/src/components/reui/event-calendar/event-calendar-lib.tsx +677 -0
  143. package/src/components/reui/event-calendar/event-calendar-month-view.tsx +1287 -0
  144. package/src/components/reui/event-calendar/event-calendar-nav.tsx +615 -0
  145. package/src/components/reui/event-calendar/event-calendar-recurrence.tsx +592 -0
  146. package/src/components/reui/event-calendar/event-calendar-resource-view.tsx +810 -0
  147. package/src/components/reui/event-calendar/event-calendar-time-grid.tsx +1366 -0
  148. package/src/components/reui/event-calendar/event-calendar-types.tsx +240 -0
  149. package/src/components/reui/event-calendar/event-calendar.tsx +1916 -0
  150. package/src/components/reui/gantt/__tests__/gantt-row-window.test.ts +243 -0
  151. package/src/components/reui/gantt/__tests__/gantt-view-virtualize.test.tsx +243 -0
  152. package/src/components/reui/gantt/gantt-bar.tsx +439 -0
  153. package/src/components/reui/gantt/gantt-dnd.tsx +1000 -0
  154. package/src/components/reui/gantt/gantt-i18n.tsx +287 -0
  155. package/src/components/reui/gantt/gantt-lib.tsx +695 -0
  156. package/src/components/reui/gantt/gantt-nav.tsx +446 -0
  157. package/src/components/reui/gantt/gantt-recurrence.tsx +402 -0
  158. package/src/components/reui/gantt/gantt-row-window.ts +119 -0
  159. package/src/components/reui/gantt/gantt-types.tsx +283 -0
  160. package/src/components/reui/gantt/gantt-view.tsx +4466 -0
  161. package/src/components/reui/gantt/gantt.tsx +1822 -0
  162. package/src/components/reui/gantt/use-gantt-row-window.ts +159 -0
  163. package/src/components/reui/icon-stack.tsx +90 -0
  164. package/src/components/reui/kanban-keyboard.ts +268 -0
  165. package/src/components/reui/kanban.tsx +1227 -0
  166. package/src/components/settings/personal-team/account/account-client.tsx +3 -2
  167. package/src/components/settings/personal-team/team/invitation-cards/invitation-history-list.tsx +5 -5
  168. package/src/components/settings/personal-team/team/team-client.tsx +2 -1
  169. package/src/components/settings/personal-team/team/team-member-list.tsx +4 -4
  170. package/src/components/share/share-presence-bar.tsx +182 -0
  171. package/src/components/shared-kit/auth/auth-client.ts +5 -0
  172. package/src/components/shared-kit/avatars/__tests__/avatar-shape.test.ts +44 -0
  173. package/src/components/shared-kit/avatars/__tests__/user-avatar.test.tsx +46 -0
  174. package/src/components/{tags/tags-collection.ts → shared-kit/avatars/avatar-shape.ts} +14 -20
  175. package/src/components/shared-kit/avatars/notion-avatar.tsx +62 -11
  176. package/src/components/shared-kit/avatars/user-avatar.tsx +7 -4
  177. package/src/components/shared-kit/list-kit/__tests__/batch-toolbar-shell.test.tsx +133 -0
  178. package/src/components/shared-kit/list-kit/__tests__/frozen-header.test.ts +89 -0
  179. package/src/components/shared-kit/list-kit/__tests__/level-badge.test.tsx +85 -0
  180. package/src/components/shared-kit/list-kit/__tests__/toolbar-shell.test.tsx +178 -0
  181. package/src/components/shared-kit/list-kit/batch-toolbar-shell.tsx +111 -0
  182. package/src/components/shared-kit/list-kit/csv-download.ts +46 -0
  183. package/src/components/shared-kit/list-kit/display/__tests__/dropdown.test.tsx +215 -0
  184. package/src/components/shared-kit/list-kit/display/dropdown.tsx +582 -0
  185. package/src/components/shared-kit/list-kit/display/types.ts +64 -0
  186. package/src/components/shared-kit/list-kit/display/values.ts +60 -0
  187. package/src/components/shared-kit/list-kit/filters/__tests__/create-filters-module.test.tsx +181 -0
  188. package/src/components/shared-kit/list-kit/filters/__tests__/types.test.ts +133 -0
  189. package/src/components/shared-kit/list-kit/filters/index.tsx +757 -0
  190. package/src/components/shared-kit/list-kit/filters/types.ts +68 -0
  191. package/src/components/shared-kit/list-kit/frozen-header.ts +45 -0
  192. package/src/components/shared-kit/list-kit/icon-semantics.ts +50 -0
  193. package/src/components/shared-kit/list-kit/kanban/__tests__/drop-layout.test.ts +139 -0
  194. package/src/components/shared-kit/list-kit/kanban/__tests__/frozen-header.test.ts +111 -0
  195. package/src/components/shared-kit/list-kit/kanban/__tests__/instance-key.test.ts +130 -0
  196. package/src/components/shared-kit/list-kit/kanban/__tests__/kanban-board-view.test.tsx +901 -0
  197. package/src/components/shared-kit/list-kit/kanban/__tests__/manual-order.test.ts +35 -0
  198. package/src/components/shared-kit/list-kit/kanban/drop-commit.ts +212 -0
  199. package/src/components/shared-kit/list-kit/kanban/drop-layout.ts +98 -0
  200. package/src/components/shared-kit/list-kit/kanban/frozen-header.ts +88 -0
  201. package/src/components/shared-kit/list-kit/kanban/instance-key.ts +83 -0
  202. package/src/components/shared-kit/list-kit/kanban/kanban-board-view.tsx +1414 -0
  203. package/src/components/shared-kit/list-kit/kanban/manual-order.ts +39 -0
  204. package/src/components/shared-kit/list-kit/level-badge.tsx +71 -0
  205. package/src/components/shared-kit/list-kit/toolbar-shell.tsx +103 -0
  206. package/src/components/shared-kit/loading/__tests__/use-deferred-flag.test.tsx +115 -0
  207. package/src/components/shared-kit/loading/use-deferred-flag.ts +35 -0
  208. package/src/components/shared-kit/peek/dock-slot.ts +62 -0
  209. package/src/components/shared-kit/peek/peek-mode.ts +34 -0
  210. package/src/components/shared-kit/theme/animated-theme-toggler.tsx +13 -7
  211. package/src/components/shared-kit/theme/theme-toggle.tsx +7 -18
  212. package/src/components/shared-kit/views/view-icon.tsx +49 -0
  213. package/src/components/story/__tests__/peek-panel-patch-sync.test.tsx +215 -0
  214. package/src/components/story/__tests__/story-list-loading-defer.test.tsx +88 -0
  215. package/src/components/story/__tests__/story-list-view-peek-sync.test.tsx +242 -0
  216. package/src/components/story/__tests__/story-list-view-restore.test.tsx +45 -3
  217. package/src/components/story/__tests__/story-list-view-ssr.test.tsx +0 -1
  218. package/src/components/story/ai/__tests__/action-registry.test.ts +11 -11
  219. package/src/components/story/ai/action-registry.ts +5 -7
  220. package/src/components/story/ai/handlers/stream-text.ts +1 -3
  221. package/src/components/story/ai/story-ai-toolbar.tsx +58 -16
  222. package/src/components/story/ai/use-toolbar-overflow.ts +4 -7
  223. package/src/components/story/columns.tsx +2 -2
  224. package/src/components/story/constants.ts +17 -1
  225. package/src/components/story/create-story-dialog.tsx +8 -7
  226. package/src/components/story/detail/__tests__/associated-attachments-panel.test.tsx +38 -4
  227. package/src/components/story/detail/__tests__/categories.test.tsx +52 -26
  228. package/src/components/story/detail/__tests__/story-collab.test.tsx +897 -0
  229. package/src/components/story/detail/activity-tabs.tsx +5 -4
  230. package/src/components/story/detail/activity-timeline.tsx +15 -3
  231. package/src/components/story/detail/comment-input.tsx +2 -2
  232. package/src/components/story/detail/comment-item.tsx +6 -3
  233. package/src/components/story/detail/comment-thread.tsx +1 -0
  234. package/src/components/story/detail/reaction-bar.tsx +1 -1
  235. package/src/components/story/detail/story-detail-body.tsx +501 -76
  236. package/src/components/story/detail/story-detail-toolbar/__tests__/related-test-cases.test.tsx +173 -10
  237. package/src/components/story/detail/story-detail-toolbar/associated-attachments-panel.tsx +144 -8
  238. package/src/components/story/detail/story-detail-toolbar/categories.tsx +82 -38
  239. package/src/components/story/detail/story-detail-toolbar/children.tsx +254 -174
  240. package/src/components/story/detail/story-detail-toolbar/dependency-panel.tsx +140 -58
  241. package/src/components/story/detail/story-detail-toolbar/index.tsx +613 -0
  242. package/src/components/story/detail/story-detail-toolbar/related-test-cases.tsx +1010 -87
  243. package/src/components/story/detail/story-detail-toolbar/scroll-hint.tsx +57 -0
  244. package/src/components/story/detail/story-detail-toolbar/use-panel-frozen-groups.ts +97 -0
  245. package/src/components/story/detail/story-properties.tsx +9 -5
  246. package/src/components/story/display/__tests__/display-dropdown-helpers.test.ts +17 -1
  247. package/src/components/story/display/__tests__/display-dropdown.test.tsx +9 -0
  248. package/src/components/story/display/__tests__/flatten-story-groups.test.ts +42 -0
  249. package/src/components/story/display/__tests__/group-fields.test.ts +81 -1
  250. package/src/components/story/display/__tests__/group-resolver.test.ts +153 -1
  251. package/src/components/story/display/__tests__/use-collapsed-subgroups.test.ts +158 -0
  252. package/src/components/story/display/__tests__/use-display-options.test.ts +32 -3
  253. package/src/components/story/display/__tests__/use-fit-count.test.ts +198 -0
  254. package/src/components/story/display/__tests__/use-paged-story-groups.test.ts +77 -3
  255. package/src/components/story/display/constants.ts +23 -2
  256. package/src/components/story/display/display-dropdown.tsx +95 -397
  257. package/src/components/story/display/flatten-story-groups.ts +39 -0
  258. package/src/components/story/display/group-fields.ts +32 -1
  259. package/src/components/story/display/group-resolver.tsx +128 -5
  260. package/src/components/story/display/types.ts +23 -42
  261. package/src/components/story/display/use-collapsed-subgroups.ts +109 -0
  262. package/src/components/story/display/use-display-options.ts +21 -5
  263. package/src/components/story/display/use-fit-count.ts +124 -0
  264. package/src/components/story/display/use-paged-story-groups.ts +174 -31
  265. package/src/components/story/filters/field-configs.tsx +263 -0
  266. package/src/components/story/filters/index.tsx +14 -5
  267. package/src/components/story/inline-editors/__tests__/labels-editor.test.tsx +2 -0
  268. package/src/components/story/inline-editors/__tests__/priority-editor.test.tsx +15 -0
  269. package/src/components/story/inline-editors/assignee-editor.tsx +7 -5
  270. package/src/components/story/inline-editors/date-editor.tsx +7 -2
  271. package/src/components/story/inline-editors/inline-trigger.tsx +17 -4
  272. package/src/components/story/inline-editors/labels-editor.tsx +243 -35
  273. package/src/components/story/inline-editors/parent-story-editor.tsx +1 -1
  274. package/src/components/story/inline-editors/priority-editor.tsx +6 -4
  275. package/src/components/story/inline-editors/state-editor.tsx +6 -4
  276. package/src/components/story/inline-editors/story-select-dialog.tsx +56 -19
  277. package/src/components/story/peek-panel.tsx +234 -51
  278. package/src/components/story/relations/__tests__/design-select-dialog.test.tsx +131 -0
  279. package/src/components/story/relations/attachment-manage-dialog.tsx +1 -1
  280. package/src/components/story/relations/design-select-dialog.tsx +285 -0
  281. package/src/components/story/relations/knowledge-select-dialog.tsx +3 -3
  282. package/src/components/story/relations/link-manage-dialog.tsx +2 -2
  283. package/src/components/story/story-list-view.tsx +175 -17
  284. package/src/components/story/story-panel-header.tsx +18 -11
  285. package/src/components/story/story-toolbar.tsx +177 -126
  286. package/src/components/story/transfer-story-popover.tsx +1 -1
  287. package/src/components/story/types.ts +11 -2
  288. package/src/components/story/views/__tests__/calendar-view.test.tsx +262 -0
  289. package/src/components/story/views/__tests__/kanban-drop-subgroup.test.ts +68 -0
  290. package/src/components/story/views/__tests__/kanban-peek-sync.test.tsx +184 -0
  291. package/src/components/story/views/__tests__/kanban-view-membership-sync.test.tsx +179 -0
  292. package/src/components/story/views/__tests__/timeline-view.test.tsx +453 -0
  293. package/src/components/story/views/__tests__/view-icon.test.tsx +45 -0
  294. package/src/components/story/views/__tests__/view-types.test.ts +0 -8
  295. package/src/components/story/views/calendar/__tests__/mappers.test.ts +201 -0
  296. package/src/components/story/views/calendar/__tests__/slot-draft.test.ts +78 -0
  297. package/src/components/story/views/calendar/drag-blocked.ts +41 -0
  298. package/src/components/story/views/calendar/i18n.ts +91 -0
  299. package/src/components/story/views/calendar/mappers.ts +119 -0
  300. package/src/components/story/views/calendar/slot-draft.ts +48 -0
  301. package/src/components/story/views/calendar-view.tsx +490 -223
  302. package/src/components/story/views/create-view-dialog.tsx +6 -6
  303. package/src/components/story/views/kanban-view.tsx +618 -0
  304. package/src/components/story/views/{__tests__ → story-list/__tests__}/use-flat-rows.test.ts +1 -1
  305. package/src/components/story/views/story-list/batch-preview-dialog.tsx +3 -3
  306. package/src/components/story/views/story-list/batch-toolbar.tsx +17 -34
  307. package/src/components/story/views/story-list/group.tsx +4 -2
  308. package/src/components/story/views/story-list/index.tsx +142 -34
  309. package/src/components/story/views/story-list/row.tsx +4 -0
  310. package/src/components/story/views/{use-flat-rows.ts → story-list/use-flat-rows.ts} +2 -2
  311. package/src/components/story/views/timeline/__tests__/mappers.test.ts +742 -0
  312. package/src/components/story/views/timeline/__tests__/sentinel-geometry.test.ts +76 -0
  313. package/src/components/story/views/timeline/__tests__/use-date-commit.test.tsx +372 -0
  314. package/src/components/story/views/timeline/i18n.ts +96 -0
  315. package/src/components/story/views/timeline/mappers.ts +506 -0
  316. package/src/components/story/views/timeline/sentinel-geometry.ts +43 -0
  317. package/src/components/story/views/timeline/use-date-commit.ts +169 -0
  318. package/src/components/story/views/timeline-view.tsx +593 -222
  319. package/src/components/story/views/view-list-section.tsx +4 -4
  320. package/src/components/story/views/view-selector-button.tsx +9 -10
  321. package/src/components/story/views/view-switcher.tsx +7 -1
  322. package/src/components/story/views/view-types.ts +1 -5
  323. package/src/components/testcase/__tests__/batch-toolbar.test.tsx +245 -0
  324. package/src/components/testcase/__tests__/board-view.test.tsx +241 -0
  325. package/src/components/testcase/__tests__/case-row.test.tsx +24 -10
  326. package/src/components/testcase/__tests__/constants.test.ts +151 -0
  327. package/src/components/testcase/__tests__/create-dialog-scope.test.tsx +173 -0
  328. package/src/components/testcase/__tests__/detail-properties.test.tsx +19 -0
  329. package/src/components/testcase/__tests__/display-options.test.tsx +154 -0
  330. package/src/components/testcase/__tests__/export-entry.test.tsx +279 -0
  331. package/src/components/testcase/__tests__/filters.test.tsx +280 -0
  332. package/src/components/testcase/__tests__/list-view-scope.test.tsx +290 -0
  333. package/src/components/testcase/__tests__/list-view.test.tsx +552 -7
  334. package/src/components/testcase/__tests__/manual-move.test.ts +69 -0
  335. package/src/components/testcase/__tests__/peek-panel.test.tsx +89 -8
  336. package/src/components/testcase/__tests__/toolbar.test.tsx +302 -0
  337. package/src/components/testcase/__tests__/view-fallback.test.tsx +272 -0
  338. package/src/components/testcase/__tests__/view-management.test.tsx +179 -0
  339. package/src/components/testcase/ai/generate-dialog.tsx +1 -1
  340. package/src/components/testcase/constants.ts +83 -0
  341. package/src/components/testcase/create-testcase-dialog.tsx +76 -8
  342. package/src/components/testcase/detail/__tests__/select-cases-dialog.test.tsx +163 -0
  343. package/src/components/testcase/detail/case-detail-body.tsx +311 -30
  344. package/src/components/testcase/detail/select-cases-dialog.tsx +465 -0
  345. package/src/components/testcase/detail/story-link-editor.tsx +1 -1
  346. package/src/components/testcase/display/display-dropdown.tsx +147 -0
  347. package/src/components/testcase/display/field-configs.ts +80 -0
  348. package/src/components/testcase/display/use-testcase-display-options.ts +59 -0
  349. package/src/components/testcase/filters/field-configs.tsx +748 -0
  350. package/src/components/testcase/filters/index.tsx +35 -127
  351. package/src/components/testcase/inline-editors/assignee-editor.tsx +6 -6
  352. package/src/components/testcase/inline-editors/folder-editor.tsx +9 -9
  353. package/src/components/testcase/inline-editors/priority-editor.tsx +47 -31
  354. package/src/components/testcase/inline-editors/state-editor.tsx +14 -12
  355. package/src/components/testcase/inline-editors/type-editor.tsx +31 -20
  356. package/src/components/testcase/list/case-row.tsx +60 -2
  357. package/src/components/testcase/list/grouped-list.tsx +3 -2
  358. package/src/components/testcase/list-view.tsx +633 -137
  359. package/src/components/testcase/peek-panel.tsx +69 -11
  360. package/src/components/testcase/plans/plan-list.tsx +6 -1
  361. package/src/components/testcase/step-editor.tsx +34 -3
  362. package/src/components/testcase/testcase-toolbar.tsx +349 -94
  363. package/src/components/testcase/views/batch-toolbar.tsx +203 -0
  364. package/src/components/testcase/views/board-view.tsx +546 -0
  365. package/src/components/testcase/views/create-view-dialog.tsx +26 -14
  366. package/src/components/testcase/views/move.ts +56 -0
  367. package/src/components/testcase/views/view-selector-button.tsx +82 -30
  368. package/src/components/testcase/views/view-switcher.tsx +12 -5
  369. package/src/components/testcase/views/view-types.ts +50 -27
  370. package/src/components/tiptap/mindmap/lib/__tests__/shortcuts.test.ts +5 -4
  371. package/src/components/tiptap/mindmap/lib/shortcuts.ts +4 -3
  372. package/src/components/tiptap/node/doc-card-node-view.tsx +2 -1
  373. package/src/components/tiptap/notion-like/editor-extensions.ts +231 -0
  374. package/src/components/tiptap/notion-like/notion-like-editor.tsx +29 -156
  375. package/src/components/tiptap/ui/ai-menu/ai-menu.tsx +6 -1
  376. package/src/components/tiptap/ui/doc-reference-interaction/doc-reference-interaction.tsx +2 -1
  377. package/src/components/ui/checkbox.tsx +4 -4
  378. package/src/components/ui/popover.tsx +1 -1
  379. package/src/components/workspace/dialogs/edit-workspace-dialog.tsx +1 -1
  380. package/src/components/workspace/kb/workspace-kb-manage-dialog.tsx +1 -1
  381. package/src/components/workspace/kb/workspace-quick-doc-dialog.tsx +1 -1
  382. package/src/components/workspace/members/workspace-member-item.tsx +2 -2
  383. package/src/components/workspace/members/workspace-members-manager.tsx +2 -2
  384. package/src/config/sidebar-routes.tsx +11 -13
  385. package/src/design-engine/document/serialize-leafer-json.ts +2 -1
  386. package/src/design-engine/engine/__tests__/engine-split.test.ts +1 -1
  387. package/src/design-engine/engine/__tests__/engine.test.ts +20 -0
  388. package/src/design-engine/engine/app.ts +5 -0
  389. package/src/design-engine/engine/engine-base.ts +17 -0
  390. package/src/design-engine/engine/engine-doc.ts +32 -0
  391. package/src/hooks/__tests__/use-commands.test.tsx +17 -5
  392. package/src/hooks/use-commands.ts +4 -4
  393. package/src/hooks/use-toolbar-search.ts +7 -2
  394. package/src/lib/__tests__/datetime-local.test.ts +46 -0
  395. package/src/lib/__tests__/datetime.test.ts +7 -0
  396. package/src/lib/__tests__/layout-responsive.test.ts +123 -0
  397. package/src/lib/__tests__/sidebar-utils.test.ts +4 -4
  398. package/src/lib/ai/story-ai-stream.ts +1 -1
  399. package/src/lib/ai/use-selected-model.ts +15 -5
  400. package/src/lib/changelog/sdk-versions.ts +22 -22
  401. package/src/lib/collab/__tests__/bindings-fields.test.ts +496 -0
  402. package/src/lib/collab/__tests__/bindings-steps.test.ts +332 -0
  403. package/src/lib/collab/__tests__/presence-store.test.ts +414 -0
  404. package/src/lib/collab/__tests__/provider-handle-contract.test.ts +89 -0
  405. package/src/lib/collab/__tests__/provider.test.ts +504 -0
  406. package/src/lib/collab/__tests__/use-presence-list-refresh.test.tsx +309 -0
  407. package/src/lib/collab/__tests__/use-presence-report.test.ts +356 -0
  408. package/src/lib/collab/__tests__/use-share-presence.test.ts +555 -0
  409. package/src/lib/collab/__tests__/user-color.test.ts +53 -0
  410. package/src/lib/collab/bindings/__tests__/canvas-local.test.ts +583 -0
  411. package/src/lib/collab/bindings/__tests__/canvas-presence.test.ts +378 -0
  412. package/src/lib/collab/bindings/__tests__/canvas-remote.test.ts +454 -0
  413. package/src/lib/collab/bindings/__tests__/canvas-tree-perf.test.ts +134 -0
  414. package/src/lib/collab/bindings/canvas-local.ts +415 -0
  415. package/src/lib/collab/bindings/canvas-presence.ts +420 -0
  416. package/src/lib/collab/bindings/canvas-remote.ts +226 -0
  417. package/src/lib/collab/bindings/fields.ts +463 -0
  418. package/src/lib/collab/bindings/steps.ts +332 -0
  419. package/src/lib/collab/env.ts +33 -0
  420. package/src/lib/collab/module-map.ts +131 -0
  421. package/src/lib/collab/presence-store.ts +350 -0
  422. package/src/lib/collab/provider.ts +378 -0
  423. package/src/lib/collab/use-collab-doc.ts +100 -0
  424. package/src/lib/collab/use-presence-list-refresh.ts +142 -0
  425. package/src/lib/collab/use-presence-report.ts +176 -0
  426. package/src/lib/collab/use-self-profile-broadcast.ts +113 -0
  427. package/src/lib/collab/use-share-presence.ts +561 -0
  428. package/src/lib/collab/user-color.ts +40 -0
  429. package/src/lib/collections/index.ts +0 -1
  430. package/src/lib/collections/reference/bookmark-categories-collection.ts +1 -1
  431. package/src/lib/commands/__tests__/registry.test.ts +2 -5
  432. package/src/lib/commands/registry.ts +0 -3
  433. package/src/lib/commands/types.ts +1 -1
  434. package/src/lib/datetime.ts +20 -3
  435. package/src/lib/hooks/__tests__/use-synced-state.test.tsx +54 -0
  436. package/src/lib/hooks/use-story-panel-open.ts +134 -0
  437. package/src/lib/hooks/use-synced-state.ts +17 -0
  438. package/src/lib/hotkeys/__tests__/registry.test.ts +1 -1
  439. package/src/lib/hotkeys/registry.ts +0 -3
  440. package/src/lib/layout-responsive.ts +140 -0
  441. package/src/lib/pacer.ts +10 -1
  442. package/src/lib/peek-dock.ts +32 -0
  443. package/src/lib/plugin-runtime/__tests__/plugin-tool-schema-parity.test.ts +140 -0
  444. package/src/lib/plugin-runtime/plugin-client-tools.ts +28 -46
  445. package/src/lib/plugin-runtime/plugin-tool-defs.ts +152 -0
  446. package/src/lib/project-module-meta.ts +1 -8
  447. package/src/lib/rate-limit.ts +15 -6
  448. package/src/lib/sanitize.ts +122 -10
  449. package/src/lib/share-events.ts +20 -11
  450. package/src/lib/sidebar-utils.ts +1 -1
  451. package/src/lib/theme/__tests__/theme-mode.test.ts +96 -0
  452. package/src/lib/theme/theme-mode.ts +77 -0
  453. package/src/paraglide/messages/_index.js +5312 -1591
  454. package/src/paraglide/messages/en.js +1880 -685
  455. package/src/paraglide/messages/zh.js +1877 -682
  456. package/src/providers/index.tsx +4 -1
  457. package/src/providers/theme-mode-provider.tsx +135 -0
  458. package/src/routeTree.gen.ts +78 -101
  459. package/src/routes/$lang/docs/$/route.lazy.tsx +7 -2
  460. package/src/routes/-tests/chat-body-validation.test.ts +61 -3
  461. package/src/routes/__tests__/-edition-routing.test.tsx +12 -8
  462. package/src/routes/_nav/-components/nav-not-found.tsx +2 -2
  463. package/src/routes/_nav/bugs/$bugId/route.lazy.tsx +16 -2
  464. package/src/routes/_nav/bugs/$bugId/route.tsx +11 -2
  465. package/src/routes/_nav/dashboard/-components/avatar-group.tsx +2 -2
  466. package/src/routes/_nav/knowledge/$kbId/doc/$docId/route.lazy.tsx +31 -17
  467. package/src/routes/_nav/knowledge/$kbId/doc/$docId/route.tsx +12 -1
  468. package/src/routes/_nav/knowledge/$kbId/index.lazy.tsx +4 -2
  469. package/src/routes/_nav/knowledge/$kbId/route.lazy.tsx +7 -3
  470. package/src/routes/_nav/knowledge/bookmarks/$id.lazy.tsx +6 -6
  471. package/src/routes/_nav/knowledge/bookmarks/index.lazy.tsx +10 -10
  472. package/src/routes/_nav/knowledge/compliance/$id.lazy.tsx +9 -9
  473. package/src/routes/_nav/knowledge/compliance/edit/$id.lazy.tsx +1 -1
  474. package/src/routes/_nav/knowledge/compliance/index.lazy.tsx +8 -8
  475. package/src/routes/_nav/knowledge/dictionaries/$id.lazy.tsx +4 -4
  476. package/src/routes/_nav/knowledge/dictionaries/index.lazy.tsx +6 -6
  477. package/src/routes/_nav/knowledge/index.lazy.tsx +1 -1
  478. package/src/routes/_nav/knowledge/laws/$id.lazy.tsx +9 -9
  479. package/src/routes/_nav/knowledge/laws/edit/$id.lazy.tsx +1 -1
  480. package/src/routes/_nav/knowledge/laws/index.lazy.tsx +11 -11
  481. package/src/routes/_nav/knowledge/summary/index.lazy.tsx +1 -1
  482. package/src/routes/_nav/projects/$projectId/index.lazy.tsx +14 -6
  483. package/src/routes/_nav/route.lazy.tsx +11 -6
  484. package/src/routes/_nav/settings/account/route.tsx +3 -2
  485. package/src/routes/_nav/stories/$storyId/route.lazy.tsx +52 -8
  486. package/src/routes/_nav/stories/$storyId/route.tsx +11 -0
  487. package/src/routes/_nav/stories/-components/story-detail-skeleton.tsx +1 -1
  488. package/src/{components/tags/pages/tag-detail-page.tsx → routes/_nav/tasks/$taskId/route.lazy.tsx} +20 -10
  489. package/src/routes/_nav/tasks/$taskId/route.tsx +43 -0
  490. package/src/routes/_nav/tasks/-components/ai-task-detail.tsx +307 -0
  491. package/src/routes/_nav/tasks/-components/ai-task-list.tsx +217 -0
  492. package/src/routes/_nav/tasks/-components/ai-task-status-badge.tsx +46 -0
  493. package/src/routes/_nav/tasks/-components/assigned-list.tsx +157 -0
  494. package/src/routes/_nav/tasks/-components/create-ai-task-dialog.tsx +228 -0
  495. package/src/routes/_nav/tasks/-components/source-ai-exec-dialog.tsx +175 -0
  496. package/src/routes/_nav/tasks/-components/task-constants.ts +115 -0
  497. package/src/routes/_nav/tasks/-components/use-task-filter.ts +64 -0
  498. package/src/routes/_nav/tasks/-tests/create-ai-task-dialog.test.tsx +175 -0
  499. package/src/routes/_nav/tasks/-tests/task-filter.test.ts +134 -0
  500. package/src/routes/_nav/tasks/-tests/task-styles.test.tsx +119 -0
  501. package/src/routes/_nav/tasks/index.lazy.tsx +114 -0
  502. package/src/routes/_nav/tasks/index.tsx +47 -0
  503. package/src/routes/_nav/{tags → tasks}/route.tsx +3 -3
  504. package/src/routes/_nav/test-cases/$caseId/route.lazy.tsx +3 -1
  505. package/src/routes/_nav/test-cases/$caseId/route.tsx +11 -2
  506. package/src/routes/api/chat.ts +23 -19
  507. package/src/routes/api/design/prototype/route.ts +2 -4
  508. package/src/routes/{_nav/acceptance-criteria/route.tsx → api/internal/collab-reindex.ts} +11 -8
  509. package/src/routes/api/knowledge/sync-github.ts +1 -1
  510. package/src/routes/design-files/$projectId/$artboardId/$filename.ts +9 -0
  511. package/src/routes/invite/$token/route.lazy.tsx +2 -2
  512. package/src/routes/share/$versionId/route.lazy.tsx +8 -0
  513. package/src/routes/share/compliance/$id/route.lazy.tsx +2 -2
  514. package/src/routes/share/compliance/$id/route.tsx +1 -1
  515. package/src/routes/share/law/$id/route.lazy.tsx +2 -2
  516. package/src/routes/share/law/$id/route.tsx +1 -1
  517. package/src/server/__tests__/bug-groups-two-level.test.ts +263 -0
  518. package/src/server/__tests__/builtin-project.test.ts +45 -1
  519. package/src/server/__tests__/csv-export.test.ts +319 -0
  520. package/src/server/__tests__/share-version.test.ts +7 -2
  521. package/src/server/__tests__/task-assigned-query.test.ts +232 -0
  522. package/src/server/__tests__/task-context-builder.test.ts +175 -0
  523. package/src/server/__tests__/task-executor.test.ts +349 -0
  524. package/src/server/__tests__/task-priority-map.test.ts +41 -0
  525. package/src/server/__tests__/task-serverfn-crud.test.ts +639 -0
  526. package/src/server/__tests__/task-serverfn-queries.test.ts +403 -0
  527. package/src/server/__tests__/testcase-board.test.ts +301 -0
  528. package/src/server/__tests__/testcase-bulk.test.ts +155 -0
  529. package/src/server/__tests__/testcase-list-scope.test.ts +215 -0
  530. package/src/server/ai-gateway/__tests__/chat-handler-prompt-key.test.ts +106 -0
  531. package/src/server/ai-gateway/__tests__/chat-stream-builder-sandbox.test.ts +9 -3
  532. package/src/server/ai-gateway/__tests__/conformance.test.ts +4 -3
  533. package/src/server/ai-gateway/adapter.ts +4 -2
  534. package/src/server/ai-gateway/chat-handler.ts +13 -5
  535. package/src/server/ai-gateway/chat-stream-builder.ts +12 -7
  536. package/src/server/ai-gateway/sandbox/__tests__/harness-sandbox.test.ts +88 -0
  537. package/src/server/ai-gateway/sandbox/harness-sandbox.ts +1 -1
  538. package/src/server/ai-gateway/story-handler.ts +7 -2
  539. package/src/server/ai-gateway/tools/plugin-lifecycle-defs.ts +8 -99
  540. package/src/server/ai-gateway/tools/plugin-tools.ts +6 -10
  541. package/src/server/ai-task/assigned-query.ts +167 -0
  542. package/src/server/ai-task/context-builder.ts +182 -0
  543. package/src/server/ai-task/executor.ts +296 -0
  544. package/src/server/ai-task/priority-map.ts +37 -0
  545. package/src/server/ai-task/types.ts +15 -0
  546. package/src/server/bug-report/__tests__/report-handler.test.ts +55 -4
  547. package/src/server/bug-report/report-handler.ts +54 -8
  548. package/src/server/builtin-project.ts +24 -0
  549. package/src/server/cloudflare/prisma-wasm-base64-stub.ts +5 -0
  550. package/src/server/collab/__tests__/collab-permissions.test.ts +412 -0
  551. package/src/server/collab/__tests__/knowledge-additions.test.ts +121 -0
  552. package/src/server/collab/__tests__/reindex-endpoint.test.ts +168 -0
  553. package/src/server/collab/__tests__/resolve.test.ts +249 -0
  554. package/src/server/collab/__tests__/touch-snapshot.test.ts +58 -0
  555. package/src/server/collab/__tests__/write-guard-sdk.test.ts +501 -0
  556. package/src/server/collab/__tests__/write-guard.test.ts +373 -0
  557. package/src/server/collab/knowledge-additions.ts +37 -0
  558. package/src/server/collab/reindex-endpoint.ts +75 -0
  559. package/src/server/collab/resolve.ts +122 -0
  560. package/src/server/collab/seed.ts +408 -0
  561. package/src/server/collab/ticket-utils.ts +107 -0
  562. package/src/server/collab/touch-snapshot.ts +55 -0
  563. package/src/server/collab/write-guard.ts +258 -0
  564. package/src/server/collab-permissions.ts +248 -0
  565. package/src/server/csv.ts +61 -0
  566. package/src/server/{knowledge-public → knowledge/public}/github-sync.ts +12 -2
  567. package/src/server/{knowledge-public → knowledge/public}/share-merge.ts +31 -8
  568. package/src/server/lib/__tests__/sequence-number-retry.test.ts +160 -0
  569. package/src/server/lib/rate-limit.ts +13 -2
  570. package/src/server/lib/sequence-number-retry.ts +85 -0
  571. package/src/server/mcp/__tests__/tools.test.ts +10 -0
  572. package/src/server/mcp/tools.ts +26 -2
  573. package/src/server/middlewares/auth-rate-limit.ts +18 -9
  574. package/src/server/notifications/event-bus.ts +3 -0
  575. package/src/server/serverFns/__tests__/collab-snapshot.test.ts +665 -0
  576. package/src/server/serverFns/__tests__/collab.test.ts +459 -0
  577. package/src/server/serverFns/__tests__/knowledge-delete.test.ts +167 -0
  578. package/src/server/serverFns/__tests__/ownership-merge.test.ts +34 -2
  579. package/src/server/serverFns/__tests__/read-write-merge.test.ts +2 -2
  580. package/src/server/serverFns/__tests__/story-crud-archive-detail.test.ts +12 -2
  581. package/src/server/serverFns/__tests__/story-crud.test.ts +51 -11
  582. package/src/server/serverFns/__tests__/story-tree.test.ts +66 -34
  583. package/src/server/serverFns/__tests__/story-types.test.ts +14 -9
  584. package/src/server/serverFns/__tests__/update-bug-guard.test.ts +325 -0
  585. package/src/server/serverFns/__tests__/update-document-guard.test.ts +285 -0
  586. package/src/server/serverFns/__tests__/update-page-guard.test.ts +276 -0
  587. package/src/server/serverFns/__tests__/update-story-guard.test.ts +436 -0
  588. package/src/server/serverFns/__tests__/update-testcase-guard.test.ts +293 -0
  589. package/src/server/serverFns/bug/__tests__/bug-comments.test.ts +25 -0
  590. package/src/server/serverFns/bug/__tests__/bug-crud.test.ts +315 -15
  591. package/src/server/serverFns/bug/__tests__/bug-groups.test.ts +36 -18
  592. package/src/server/serverFns/bug/__tests__/bug-list-query.test.ts +21 -0
  593. package/src/server/serverFns/bug/__tests__/bug-reactions.test.ts +335 -0
  594. package/src/server/serverFns/bug/__tests__/bug-reorder.test.ts +165 -0
  595. package/src/server/serverFns/bug/__tests__/bug-story.test.ts +4 -1
  596. package/src/server/serverFns/bug/bug-comments.ts +5 -0
  597. package/src/server/serverFns/bug/bug-crud.ts +321 -72
  598. package/src/server/serverFns/bug/bug-display-options.ts +11 -0
  599. package/src/server/serverFns/bug/bug-export.ts +137 -0
  600. package/src/server/serverFns/bug/bug-group-query.ts +16 -5
  601. package/src/server/serverFns/bug/bug-groups.ts +39 -15
  602. package/src/server/serverFns/bug/bug-list-query.ts +8 -1
  603. package/src/server/serverFns/bug/bug-reactions.ts +123 -0
  604. package/src/server/serverFns/bug/bug-reorder.ts +64 -0
  605. package/src/server/serverFns/bug/bug-story-bulk.ts +280 -0
  606. package/src/server/serverFns/bug/bug-story.ts +47 -39
  607. package/src/server/serverFns/bug/index.ts +6 -0
  608. package/src/server/serverFns/collab-presence.ts +119 -0
  609. package/src/server/serverFns/collab-snapshot.ts +201 -0
  610. package/src/server/serverFns/collab.ts +153 -0
  611. package/src/server/serverFns/design/__tests__/designs.test.ts +0 -2
  612. package/src/server/serverFns/design/designs.ts +0 -64
  613. package/src/server/serverFns/design/detail.ts +36 -2
  614. package/src/server/serverFns/design/pages.ts +73 -10
  615. package/src/server/serverFns/iteration/iteration-crud.ts +25 -1
  616. package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/create.ts +3 -3
  617. package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/detail.ts +2 -2
  618. package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/list.ts +3 -2
  619. package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/refresh-favicon.ts +1 -1
  620. package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/share.ts +1 -1
  621. package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/sync-github.ts +1 -1
  622. package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/update.ts +5 -4
  623. package/src/server/serverFns/{knowledge-public → knowledge/public}/compliance/create.ts +1 -1
  624. package/src/server/serverFns/{knowledge-public → knowledge/public}/compliance/detail.ts +2 -2
  625. package/src/server/serverFns/{knowledge-public → knowledge/public}/compliance/list.ts +3 -2
  626. package/src/server/serverFns/{knowledge-public → knowledge/public}/compliance/share.ts +1 -1
  627. package/src/server/serverFns/{knowledge-public → knowledge/public}/compliance/update.ts +3 -2
  628. package/src/server/serverFns/{knowledge-public → knowledge/public}/dictionary/create.ts +1 -1
  629. package/src/server/serverFns/{knowledge-public → knowledge/public}/dictionary/detail.ts +2 -2
  630. package/src/server/serverFns/{knowledge-public → knowledge/public}/dictionary/list.ts +3 -2
  631. package/src/server/serverFns/{knowledge-public → knowledge/public}/dictionary/share.ts +1 -1
  632. package/src/server/serverFns/{knowledge-public → knowledge/public}/dictionary/update.ts +3 -2
  633. package/src/server/serverFns/{knowledge-public → knowledge/public}/legal/create.ts +1 -1
  634. package/src/server/serverFns/{knowledge-public → knowledge/public}/legal/detail.ts +2 -2
  635. package/src/server/serverFns/{knowledge-public → knowledge/public}/legal/list.ts +3 -2
  636. package/src/server/serverFns/{knowledge-public → knowledge/public}/legal/share.ts +1 -1
  637. package/src/server/serverFns/{knowledge-public → knowledge/public}/legal/update.ts +3 -2
  638. package/src/server/serverFns/knowledge.ts +135 -19
  639. package/src/server/serverFns/project/module-overview.ts +1 -2
  640. package/src/server/serverFns/share/version.ts +7 -1
  641. package/src/server/serverFns/story/__tests__/bulk.test.ts +6 -0
  642. package/src/server/serverFns/story/__tests__/create-story-internal.test.ts +112 -3
  643. package/src/server/serverFns/story/__tests__/story-assoc.test.ts +77 -6
  644. package/src/server/serverFns/story/__tests__/story-crud-date-key.test.ts +187 -0
  645. package/src/server/serverFns/story/__tests__/story-gantt-deps.test.ts +163 -0
  646. package/src/server/serverFns/story/__tests__/story-groups.test.ts +4 -0
  647. package/src/server/serverFns/story/__tests__/story-list-query.test.ts +20 -0
  648. package/src/server/serverFns/story/__tests__/story-search.test.ts +5 -0
  649. package/src/server/serverFns/story/__tests__/story-transfer.test.ts +64 -1
  650. package/src/server/serverFns/story/index.ts +2 -2
  651. package/src/server/serverFns/story/story-assoc.ts +44 -14
  652. package/src/server/serverFns/story/story-crud/archive.ts +52 -28
  653. package/src/server/serverFns/story/story-crud/bulk.ts +14 -4
  654. package/src/server/serverFns/story/story-crud/create-story-internal.ts +39 -21
  655. package/src/server/serverFns/story/story-crud.ts +283 -116
  656. package/src/server/serverFns/story/story-dependencies.ts +31 -0
  657. package/src/server/serverFns/story/story-groups.ts +15 -11
  658. package/src/server/serverFns/story/story-list-query.ts +16 -4
  659. package/src/server/serverFns/story/story-search.ts +9 -6
  660. package/src/server/serverFns/story/story-transfer.ts +99 -42
  661. package/src/server/serverFns/story/story-tree.ts +70 -48
  662. package/src/server/serverFns/story-display-options.ts +21 -10
  663. package/src/server/serverFns/story-view.ts +2 -2
  664. package/src/server/serverFns/tasks/task-crud.ts +264 -0
  665. package/src/server/serverFns/tasks/task-queries.ts +172 -0
  666. package/src/server/serverFns/testcase/__tests__/generation.test.ts +3 -0
  667. package/src/server/serverFns/testcase/__tests__/stats.test.ts +18 -4
  668. package/src/server/serverFns/testcase/__tests__/testcase-board.test.ts +113 -0
  669. package/src/server/serverFns/testcase/__tests__/testcase-crud.test.ts +62 -14
  670. package/src/server/serverFns/testcase/__tests__/testcase-groups.test.ts +32 -10
  671. package/src/server/serverFns/testcase/bulk.ts +195 -0
  672. package/src/server/serverFns/testcase/generation.ts +10 -0
  673. package/src/server/serverFns/testcase/stats.ts +22 -8
  674. package/src/server/serverFns/testcase/testcase-board.ts +198 -0
  675. package/src/server/serverFns/testcase/testcase-crud.ts +165 -33
  676. package/src/server/serverFns/testcase/testcase-display-options.ts +166 -0
  677. package/src/server/serverFns/testcase/testcase-export.ts +125 -0
  678. package/src/server/serverFns/testcase/testcase-filter-views.ts +36 -9
  679. package/src/server/serverFns/testcase/testcase-groups.ts +27 -23
  680. package/src/server/serverFns/testcase/testcase-reorder.ts +66 -0
  681. package/src/server/story/__tests__/date-key.test.ts +57 -0
  682. package/src/server/story/date-key.ts +36 -0
  683. package/src/server/story/types.ts +3 -7
  684. package/src/server/testcase/__tests__/list-query.test.ts +269 -0
  685. package/src/server/testcase/list-query.ts +145 -0
  686. package/src/server-entry.ts +32 -0
  687. package/src/shared/bug/__tests__/constants.test.ts +44 -0
  688. package/src/shared/bug/constants.ts +37 -1
  689. package/src/start.ts +7 -2
  690. package/src/styles/globals.css +24 -3
  691. package/src/types/project.ts +2 -3
  692. package/vite.shared.ts +110 -3
  693. package/src/__tests__/tag-badge.test.tsx +0 -41
  694. package/src/components/bug/__tests__/bug-list-table.test.tsx +0 -289
  695. package/src/components/bug/bug-list-table.tsx +0 -187
  696. package/src/components/bug/columns.tsx +0 -193
  697. package/src/components/bug/filters/add-filter-dropdown.tsx +0 -70
  698. package/src/components/bug/filters/applied-filters.tsx +0 -214
  699. package/src/components/bug/filters/filter-condition.tsx +0 -151
  700. package/src/components/bug/filters/filter-row.tsx +0 -104
  701. package/src/components/bug/filters/filter-toggle.tsx +0 -61
  702. package/src/components/bug/filters/filter-types.ts +0 -146
  703. package/src/components/story/detail/story-detail-toolbar.tsx +0 -382
  704. package/src/components/story/filters/add-filter-dropdown.tsx +0 -70
  705. package/src/components/story/filters/applied-filters.tsx +0 -225
  706. package/src/components/story/filters/filter-condition.tsx +0 -152
  707. package/src/components/story/filters/filter-row.tsx +0 -116
  708. package/src/components/story/filters/filter-toggle.tsx +0 -60
  709. package/src/components/story/filters/filter-types.ts +0 -120
  710. package/src/components/story/filters/filter-value-input.tsx +0 -182
  711. package/src/components/story/views/kanban-board.tsx +0 -464
  712. package/src/components/story/views/kanban-card.tsx +0 -100
  713. package/src/components/tags/__tests__/tags.test.ts +0 -388
  714. package/src/components/tags/nav-tag.tsx +0 -121
  715. package/src/components/tags/pages/tag-settings-page.tsx +0 -32
  716. package/src/components/tags/pages/tags-index-page.tsx +0 -32
  717. package/src/components/tags/tag-badge.tsx +0 -56
  718. package/src/components/tags/tag-color-classes.ts +0 -61
  719. package/src/components/tags/tag-color-picker.tsx +0 -54
  720. package/src/components/tags/tag-components-index.ts +0 -23
  721. package/src/components/tags/tag-manager.tsx +0 -208
  722. package/src/components/tags/tag-selector.tsx +0 -164
  723. package/src/components/testcase/__tests__/table-view.test.tsx +0 -328
  724. package/src/components/testcase/plans/add-to-plan-bar.tsx +0 -64
  725. package/src/components/testcase/table/columns.tsx +0 -170
  726. package/src/components/testcase/table/table-view.tsx +0 -152
  727. package/src/lib/tag-colors.ts +0 -35
  728. package/src/routes/_nav/tags/$id/route.lazy.tsx +0 -23
  729. package/src/routes/_nav/tags/$id/route.tsx +0 -20
  730. package/src/routes/_nav/tags/index.lazy.tsx +0 -23
  731. package/src/routes/_nav/tags/index.tsx +0 -20
  732. package/src/routes/_nav/tags/settings/route.lazy.tsx +0 -23
  733. package/src/routes/_nav/tags/settings/route.tsx +0 -23
  734. package/src/server/serverFns/tags.ts +0 -138
  735. /package/src/components/{knowledge-public → knowledge/public}/bookmark-card.tsx +0 -0
  736. /package/src/components/{knowledge-public → knowledge/public}/category-icon.tsx +0 -0
  737. /package/src/components/{knowledge-public → knowledge/public}/chip-utils.ts +0 -0
  738. /package/src/components/{knowledge-public → knowledge/public}/knowledge-card-grid.tsx +0 -0
  739. /package/src/components/{knowledge-public → knowledge/public}/knowledge-filters.tsx +0 -0
  740. /package/src/components/{knowledge-public → knowledge/public}/knowledge-search-bar.tsx +0 -0
  741. /package/src/components/{knowledge-public → knowledge/public}/markdown-editor.tsx +0 -0
  742. /package/src/components/{knowledge-public → knowledge/public}/markdown-view.tsx +0 -0
  743. /package/src/components/{knowledge-public → knowledge/public}/tag-filter.tsx +0 -0
  744. /package/src/components/{story/detail → shared-kit/comments}/emoji-picker.tsx +0 -0
  745. /package/src/components/story/{schemas/story-create.ts → story-create-schema.ts} +0 -0
  746. /package/src/server/{knowledge-public → knowledge/public}/canonical-id.ts +0 -0
  747. /package/src/server/{knowledge-public → knowledge/public}/favicon.ts +0 -0
  748. /package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/categories.ts +0 -0
  749. /package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/delete.ts +0 -0
  750. /package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/favorite.ts +0 -0
  751. /package/src/server/serverFns/{knowledge-public → knowledge/public}/bookmarks/unshare.ts +0 -0
  752. /package/src/server/serverFns/{knowledge-public → knowledge/public}/compliance/delete.ts +0 -0
  753. /package/src/server/serverFns/{knowledge-public → knowledge/public}/compliance/public.ts +0 -0
  754. /package/src/server/serverFns/{knowledge-public → knowledge/public}/compliance/unshare.ts +0 -0
  755. /package/src/server/serverFns/{knowledge-public → knowledge/public}/dictionary/delete.ts +0 -0
  756. /package/src/server/serverFns/{knowledge-public → knowledge/public}/dictionary/unshare.ts +0 -0
  757. /package/src/server/serverFns/{knowledge-public → knowledge/public}/entity-tags.ts +0 -0
  758. /package/src/server/serverFns/{knowledge-public → knowledge/public}/favorite.ts +0 -0
  759. /package/src/server/serverFns/{knowledge-public → knowledge/public}/legal/delete.ts +0 -0
  760. /package/src/server/serverFns/{knowledge-public → knowledge/public}/legal/public.ts +0 -0
  761. /package/src/server/serverFns/{knowledge-public → knowledge/public}/legal/unshare.ts +0 -0
@@ -55,7 +55,10 @@ export function formatDate(
55
55
  /**
56
56
  * 确定性时间戳格式化:固定时区 + date-fns 数字格式,不依赖运行环境 locale/时区。
57
57
  * SSR 与客户端输出字节级一致,专治 toLocaleString() 引发的 hydration mismatch。
58
- * @param date Date 对象或 ISO 字符串
58
+ * @param date Date 对象或 ISO 字符串(Date | string 均为绝对时刻;string 经
59
+ * new Date(iso) 解析后与 Date 同路径转换,两条入口输出字节级一致——任务 11
60
+ * 详情页「创建时间」(createdAt: string) 与「运行历史」(startedAt: string|Date)
61
+ * 即经此函数统一口径,同页不存在两种时区)
59
62
  * @param fmt date-fns 格式,默认 "yyyy-MM-dd HH:mm"
60
63
  */
61
64
  export function formatTimestamp(
@@ -132,11 +135,25 @@ export function formatChatDate(date: Date, timezone: string): string {
132
135
 
133
136
  // ---- 本地日历工具(自 lib/date-utils.ts 并入:按本地时区做日历网格/日键计算,无时区转换) ----
134
137
 
135
- /** 解析 "yyyy-MM-dd" 前缀为本地 Date(避免 UTC 偏移) */
138
+ /**
139
+ * 解析 "yyyy-MM-dd" 前缀为本地 Date(避免 UTC 偏移)。
140
+ * 分量越界或非数字返回 Invalid Date(不滚动);调用方用 `Number.isNaN(d.getTime())` 判定。
141
+ */
136
142
  export function parseDate(s: string): Date {
137
143
  const datePart = s.slice(0, 10)
138
144
  const [y, m, d] = datePart.split('-').map(Number)
139
- return new Date(y, m - 1, d)
145
+ const date = new Date(y, m - 1, d)
146
+ if (
147
+ !Number.isFinite(y) ||
148
+ !Number.isFinite(m) ||
149
+ !Number.isFinite(d) ||
150
+ date.getFullYear() !== y ||
151
+ date.getMonth() !== m - 1 ||
152
+ date.getDate() !== d
153
+ ) {
154
+ return new Date(NaN)
155
+ }
156
+ return date
140
157
  }
141
158
 
142
159
  /** 本地时区 yyyy-MM-dd 日键(与 timezone 版 formatDate 区分) */
@@ -0,0 +1,54 @@
1
+ import { useLayoutEffect } from "react";
2
+ import { act, render, renderHook } from "@testing-library/react";
3
+ import { describe, expect, it } from "vitest";
4
+ import { useSyncedState } from "../use-synced-state";
5
+
6
+ type Source = { n: number };
7
+
8
+ describe("useSyncedState", () => {
9
+ it("初值取源值", () => {
10
+ const { result } = renderHook(() => useSyncedState<Source>({ n: 1 }));
11
+ expect(result.current[0]).toEqual({ n: 1 });
12
+ });
13
+
14
+ it("源值引用不变时保留本地更新(拖拽乐观更新不被重置)", () => {
15
+ const source: Source = { n: 1 };
16
+ const { result, rerender } = renderHook(({ s }: { s: Source }) => useSyncedState(s), {
17
+ initialProps: { s: source },
18
+ });
19
+
20
+ act(() => result.current[1]({ n: 2 }));
21
+ expect(result.current[0]).toEqual({ n: 2 });
22
+
23
+ rerender({ s: source });
24
+ expect(result.current[0]).toEqual({ n: 2 });
25
+ });
26
+
27
+ it("源值引用变化时在提交前同步,不露出陈旧值", () => {
28
+ const committed: number[] = [];
29
+
30
+ function Probe({ source }: { source: Source }) {
31
+ const [value] = useSyncedState(source);
32
+ // 不带依赖:记录每一次「提交」(不是每次值变化)——正是要抓出多提交的陈旧帧
33
+ useLayoutEffect(() => {
34
+ committed.push(value.n);
35
+ });
36
+ return null;
37
+ }
38
+
39
+ const { rerender } = render(<Probe source={{ n: 1 }} />);
40
+ rerender(<Probe source={{ n: 9 }} />);
41
+
42
+ expect(committed).toEqual([1, 9]);
43
+ });
44
+
45
+ it("函数式更新可用,且不因自身更新触发重置", () => {
46
+ const source: Source = { n: 1 };
47
+ const { result } = renderHook(({ s }: { s: Source }) => useSyncedState(s), {
48
+ initialProps: { s: source },
49
+ });
50
+
51
+ act(() => result.current[1]((prev) => ({ n: prev.n + 10 })));
52
+ expect(result.current[0]).toEqual({ n: 11 });
53
+ });
54
+ });
@@ -0,0 +1,134 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ // 需求详情各子面板折叠状态持久化(localStorage,按 storyId 分桶)。
19
+ // peek 面板与详情路由共享同一状态(同一 story 打开处即可见上次折叠态)。
20
+ import { useEffect, useState, type Dispatch, type SetStateAction } from "react";
21
+
22
+ const storageKey = (storyId: string) => `allblue.story-panels.${storyId}`;
23
+
24
+ type PanelState = Record<string, boolean>;
25
+
26
+ function readState(storyId: string): PanelState {
27
+ try {
28
+ const raw = window.localStorage.getItem(storageKey(storyId));
29
+ return raw ? (JSON.parse(raw) as PanelState) : {};
30
+ } catch {
31
+ return {};
32
+ }
33
+ }
34
+
35
+ export function useStoryPanelOpen(storyId: string, panelKey: string, defaultOpen = true) {
36
+ const [open, setOpen] = useState(() => {
37
+ try {
38
+ return readState(storyId)[panelKey] ?? defaultOpen;
39
+ } catch {
40
+ return defaultOpen;
41
+ }
42
+ });
43
+
44
+ useEffect(() => {
45
+ try {
46
+ const state = readState(storyId);
47
+ if (state[panelKey] === open) return;
48
+ const next = { ...state, [panelKey]: open };
49
+ window.localStorage.setItem(storageKey(storyId), JSON.stringify(next));
50
+ } catch {
51
+ // 存储不可用(隐私模式等):状态仅本次会话内生效
52
+ }
53
+ }, [storyId, panelKey, open]);
54
+
55
+ return [open, setOpen] as const;
56
+ }
57
+
58
+ /** 读取某 story 的整桶状态(含 groups/filters 命名空间) */
59
+ function readBucket(storyId: string): {
60
+ groups?: Record<string, Record<string, boolean>>;
61
+ filters?: Record<string, Record<string, unknown>>;
62
+ } & PanelState {
63
+ try {
64
+ const raw = window.localStorage.getItem(storageKey(storyId));
65
+ return raw ? (JSON.parse(raw) as ReturnType<typeof readBucket>) : {};
66
+ } catch {
67
+ return {};
68
+ }
69
+ }
70
+
71
+ /**
72
+ * 列表内分组标题行的折叠状态持久化(同桶 groups.{panelKey} 命名空间)。
73
+ * 键为分组 key(含子分组复合键),维度切换后遗留键自然失效。
74
+ */
75
+ export function useStoryPanelGroupCollapsed(storyId: string, panelKey: string) {
76
+ const [collapsed, setCollapsed] = useState<Record<string, boolean>>(() => {
77
+ try {
78
+ return readBucket(storyId).groups?.[panelKey] ?? {};
79
+ } catch {
80
+ return {};
81
+ }
82
+ });
83
+
84
+ useEffect(() => {
85
+ try {
86
+ const bucket = readBucket(storyId);
87
+ const groups = bucket.groups ?? {};
88
+ if (JSON.stringify(groups[panelKey]) === JSON.stringify(collapsed)) return;
89
+ window.localStorage.setItem(
90
+ storageKey(storyId),
91
+ JSON.stringify({ ...bucket, groups: { ...groups, [panelKey]: collapsed } }),
92
+ );
93
+ } catch {
94
+ // 存储不可用:状态仅本次会话内生效
95
+ }
96
+ }, [storyId, panelKey, collapsed]);
97
+
98
+ return [collapsed, setCollapsed] as const;
99
+ }
100
+
101
+ /**
102
+ * 列表显示选项持久化(分组/子分组/排序方向,同桶 filters.{panelKey})。
103
+ * 读取时与 defaults 合并——存储缺字段/结构漂移自动回退默认值。
104
+ */
105
+ export function useStoryPanelFilters<T extends object>(
106
+ storyId: string,
107
+ panelKey: string,
108
+ defaults: T,
109
+ ): [T, Dispatch<SetStateAction<T>>] {
110
+ const [filters, setFilters] = useState<T>(() => {
111
+ try {
112
+ const stored = readBucket(storyId).filters?.[panelKey] as Partial<T> | undefined;
113
+ return stored ? { ...defaults, ...stored } : defaults;
114
+ } catch {
115
+ return defaults;
116
+ }
117
+ });
118
+
119
+ useEffect(() => {
120
+ try {
121
+ const bucket = readBucket(storyId);
122
+ const stored = bucket.filters?.[panelKey];
123
+ if (JSON.stringify(stored) === JSON.stringify(filters)) return;
124
+ window.localStorage.setItem(
125
+ storageKey(storyId),
126
+ JSON.stringify({ ...bucket, filters: { ...bucket.filters, [panelKey]: filters } }),
127
+ );
128
+ } catch {
129
+ // 存储不可用:状态仅本次会话内生效
130
+ }
131
+ }, [storyId, panelKey, filters]);
132
+
133
+ return [filters, setFilters] as const;
134
+ }
@@ -0,0 +1,17 @@
1
+ import { useState, type Dispatch, type SetStateAction } from "react";
2
+
3
+ /**
4
+ * 受控值的「渲染期同步」版 useState:
5
+ * 源值(通常来自 loader/服务端)引用变化时,在**同一次渲染提交前**同步本地值,
6
+ * 不会像 useEffect 那样先提交一帧陈旧值(切换分组维度时列头会回落显示原始 key)。
7
+ * 源值引用不变时保留本地乐观更新(拖拽中途不被重置)。
8
+ */
9
+ export function useSyncedState<T>(source: T): [T, Dispatch<SetStateAction<T>>] {
10
+ const [value, setValue] = useState(source);
11
+ const [syncedSource, setSyncedSource] = useState(source);
12
+ if (source !== syncedSource) {
13
+ setSyncedSource(source);
14
+ setValue(source);
15
+ }
16
+ return [value, setValue];
17
+ }
@@ -26,7 +26,7 @@ describe("HOTKEY_REGISTRY", () => {
26
26
 
27
27
  it("序列键条目 keys 为空格分隔的两键(如 'G D')", () => {
28
28
  const seqKeys = HOTKEY_REGISTRY.filter((h) => h.keys.includes(" "))
29
- expect(seqKeys.length).toBeGreaterThanOrEqual(19)
29
+ expect(seqKeys.length).toBeGreaterThanOrEqual(16)
30
30
  for (const h of seqKeys) {
31
31
  expect(h.keys.split(" ")).toHaveLength(2)
32
32
  }
@@ -90,11 +90,8 @@ export const HOTKEY_REGISTRY: HotkeyDefinition[] = [
90
90
  { id: "goto-design", keys: "G E", scope: "global", description: "前往设计", category: "导航" },
91
91
  { id: "goto-test-cases", keys: "G T", scope: "global", description: "前往测试用例", category: "导航" },
92
92
  { id: "goto-bugs", keys: "G B", scope: "global", description: "前往缺陷", category: "导航" },
93
- { id: "goto-acceptance", keys: "G Q", scope: "global", description: "前往验收标准", category: "导航" },
94
- { id: "goto-debrief", keys: "G R", scope: "global", description: "前往汇报", category: "导航" },
95
93
  { id: "goto-knowledge", keys: "G K", scope: "global", description: "前往知识库", category: "导航" },
96
94
  { id: "goto-anyhub", keys: "G H", scope: "global", description: "前往应用中心", category: "导航" },
97
- { id: "goto-tags", keys: "G L", scope: "global", description: "前往标签", category: "导航" },
98
95
  { id: "goto-workspaces", keys: "G W", scope: "global", description: "前往工作空间", category: "导航" },
99
96
  { id: "goto-settings", keys: "G M", scope: "global", description: "前往设置", category: "导航" },
100
97
  { id: "create-prd-hk", keys: "N P", scope: "global", description: "新建 PRD", category: "操作" },
@@ -0,0 +1,140 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ // 布局窄屏渐进降级(全局 _nav 布局)。
19
+ //
20
+ // **面板宽度由 CSS flex 计算**(内容区 `min-w-120`=480、面板槽 `basis-300`=1200 /
21
+ // shrink / min-w-120):浏览器同帧布局,避免 JS 用上一帧行宽算 px 造成的逐帧抖动。
22
+ // 本模块只负责**开关判定**(侧栏收起 / 面板转浮层 / AI 转浮层),且一律基于
23
+ // **外层宽度 + 侧栏目标状态预测**的行宽——不读侧栏收放动画的中间态,避免收起过程
24
+ // 中「先浮层后停靠」的状态翻转。
25
+
26
+ import { createContext, useContext, useEffect } from "react";
27
+
28
+ /** 内容区(SidebarInset)最小宽度 */
29
+ export const CONTENT_MIN_WIDTH = 480;
30
+ /** 侧边面板(dock)最小宽度 */
31
+ export const DOCK_MIN_WIDTH = 480;
32
+ /** 行内间隙/边距(gap-2 ×2 + pr-2) */
33
+ export const LAYOUT_CHROME_WIDTH = 24;
34
+ /** AI 助手 full 态停靠宽度(对应 w-120 = 30rem) */
35
+ export const AI_DOCKED_WIDTH = 480;
36
+ /** 侧栏展开宽度(16rem) */
37
+ export const SIDEBAR_EXPANDED_WIDTH = 256;
38
+ /** 侧栏收起到图标态宽度(3rem) */
39
+ export const SIDEBAR_ICON_WIDTH = 48;
40
+ /** 阈值回差:已在某态时,需比进入阈值多出该宽度才切回,避免边界反复抖动 */
41
+ export const HYSTERESIS_WIDTH = 48;
42
+
43
+ export interface LayoutState {
44
+ /** 侧栏是否因窄屏自动收起到图标态 */
45
+ sidebarCollapsed: boolean;
46
+ /** 侧边面板是否转浮层(盖在内容区上) */
47
+ dockOverlay: boolean;
48
+ /** AI 助手是否转浮层(盖在侧边面板上) */
49
+ aiOverlay: boolean;
50
+ }
51
+
52
+ export const DEFAULT_LAYOUT_STATE: LayoutState = {
53
+ sidebarCollapsed: false,
54
+ dockOverlay: false,
55
+ aiOverlay: false,
56
+ };
57
+
58
+ export interface ComputeLayoutInput {
59
+ /** 最外层容器宽度(= 视口宽度)。唯一测量基准:不随侧栏收放动画变化。 */
60
+ outerWidth: number;
61
+ /** 当前是否存在侧边面板(dock 形态) */
62
+ dockPresent: boolean;
63
+ /** AI 助手是否处于停靠(full 且展开)状态 */
64
+ aiDocked: boolean;
65
+ }
66
+
67
+ /** 由外层宽度推导布局状态。纯函数(除 prev 回差外无外部依赖),便于单测。 */
68
+ export function computeLayout(
69
+ { outerWidth, dockPresent, aiDocked }: ComputeLayoutInput,
70
+ prev: LayoutState = DEFAULT_LAYOUT_STATE,
71
+ ): LayoutState {
72
+ if (outerWidth <= 0) return DEFAULT_LAYOUT_STATE;
73
+
74
+ const ai = aiDocked ? AI_DOCKED_WIDTH : 0;
75
+ const dockMin = dockPresent ? DOCK_MIN_WIDTH : 0;
76
+
77
+ // 侧栏收起:外层放不下「展开侧栏 + 内容最小 + 面板最小 + AI」时收起(已收起需多出回差才展开)
78
+ const needExpanded = SIDEBAR_EXPANDED_WIDTH + CONTENT_MIN_WIDTH + dockMin + ai + LAYOUT_CHROME_WIDTH;
79
+ const sidebarThreshold = prev.sidebarCollapsed ? needExpanded + HYSTERESIS_WIDTH : needExpanded;
80
+ const sidebarCollapsed = outerWidth < sidebarThreshold;
81
+
82
+ // 预测可用宽:外层 − 侧栏目标宽 − 行内 chrome(不读侧栏动画中间态)
83
+ const sidebarWidth = sidebarCollapsed ? SIDEBAR_ICON_WIDTH : SIDEBAR_EXPANDED_WIDTH;
84
+ const usable = Math.max(0, outerWidth - sidebarWidth - LAYOUT_CHROME_WIDTH);
85
+
86
+ // AI 浮层阈值:仅在「连 AI 自身停靠宽度都放不下」的最窄处才转浮层(已浮层时需多出回差才切回)。
87
+ // 此前用 CONTENT_MIN + ai 会让 AI 在面板刚覆盖内容(内容被盖住、无需再保最小宽)时就过早浮层居中。
88
+ const aiThreshold = prev.aiOverlay ? ai + HYSTERESIS_WIDTH : ai;
89
+
90
+ if (!dockPresent) {
91
+ return { sidebarCollapsed, dockOverlay: false, aiOverlay: usable < aiThreshold };
92
+ }
93
+
94
+ // 面板可停靠的最小可用宽;低于则转浮层(已浮层时需多出回差才切回)
95
+ const dockFitWidth = CONTENT_MIN_WIDTH + dockMin + ai;
96
+ const dockOverlayThreshold = prev.dockOverlay ? dockFitWidth + HYSTERESIS_WIDTH : dockFitWidth;
97
+ if (usable < dockOverlayThreshold) {
98
+ return { sidebarCollapsed, dockOverlay: true, aiOverlay: usable < aiThreshold };
99
+ }
100
+ return { sidebarCollapsed, dockOverlay: false, aiOverlay: false };
101
+ }
102
+
103
+ export interface LayoutResponsiveContextValue {
104
+ layout: LayoutState;
105
+ setOuterEl: (el: HTMLElement | null) => void;
106
+ setDockPresent: (v: boolean) => void;
107
+ setAiDocked: (v: boolean) => void;
108
+ }
109
+
110
+ export const LayoutResponsiveContext = createContext<LayoutResponsiveContextValue | null>(null);
111
+
112
+ /** 读取当前布局状态;无 Provider(如单测)时返回默认态(保持旧行为)。 */
113
+ export function useLayoutResponsive(): LayoutState {
114
+ return useContext(LayoutResponsiveContext)?.layout ?? DEFAULT_LAYOUT_STATE;
115
+ }
116
+
117
+ /** 读取注册器(挂载测量点 / 上报面板存在性);无 Provider 时为 null。 */
118
+ export function useLayoutResponsiveSetters(): LayoutResponsiveContextValue | null {
119
+ return useContext(LayoutResponsiveContext);
120
+ }
121
+
122
+ /** 侧边面板(dock)挂载时上报「面板存在」,供布局判定。 */
123
+ export function useDockPresence(active: boolean): void {
124
+ const ctx = useContext(LayoutResponsiveContext);
125
+ useEffect(() => {
126
+ if (!ctx) return;
127
+ ctx.setDockPresent(active);
128
+ return () => ctx.setDockPresent(false);
129
+ }, [ctx, active]);
130
+ }
131
+
132
+ /** AI 助手停靠(full 且展开)时上报,供布局判定。 */
133
+ export function useAiDocked(active: boolean): void {
134
+ const ctx = useContext(LayoutResponsiveContext);
135
+ useEffect(() => {
136
+ if (!ctx) return;
137
+ ctx.setAiDocked(active);
138
+ return () => ctx.setAiDocked(false);
139
+ }, [ctx, active]);
140
+ }
package/src/lib/pacer.ts CHANGED
@@ -63,12 +63,21 @@ function purgeStaleEntries() {
63
63
  }
64
64
  }
65
65
 
66
- setInterval(purgeStaleEntries, 60_000)
66
+ // 清扫定时器懒启动:workerd 禁止 global scope(模块顶层)设定时器,
67
+ // 首次 getRateLimiter() 调用时才开启(浏览器/Node 行为不变)。
68
+ let purgeTimerStarted = false
69
+ function ensurePurgeTimer() {
70
+ if (purgeTimerStarted) return
71
+ purgeTimerStarted = true
72
+ const timer = setInterval(purgeStaleEntries, 60_000)
73
+ timer.unref?.()
74
+ }
67
75
 
68
76
  export function getRateLimiter(
69
77
  key: string,
70
78
  config: RateLimitConfig
71
79
  ): RateLimiter<(...args: unknown[]) => boolean> {
80
+ ensurePurgeTimer()
72
81
  const existing = limiterCache.get(key)
73
82
  if (existing) {
74
83
  existing.lastAccess = Date.now()
@@ -0,0 +1,32 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ // 侧边面板(side-dock)布局槽的共享常量。
19
+ //
20
+ // 单独放在 lib 下(无 React / 无业务依赖),供布局壳 sidebar-03 直接引用:
21
+ // 布局壳不应依赖任何业务组件目录(story/testcase/shared-kit 均不引入)。
22
+
23
+ /** 侧边面板(dock)态的布局级挂载点 id,与 sidebar-03 中的挂载点一致。 */
24
+ export const PEEK_DOCK_SLOT_ID = "peek-dock-panel-slot";
25
+
26
+ /**
27
+ * 侧边面板宽度。放在挂载点上(相对外层已确定宽度的一行解析百分比),面板本体
28
+ * `w-full` 填充——若把该百分比宽度放在面板上,其 `100%` 会相对宽度 auto 的挂载点
29
+ * 解析,退化为内容宽度(宽度与 side-peek 不一致、且随内容变化而漂移)。
30
+ * 口径与侧边浮窗(side-peek)保持一致。
31
+ */
32
+ export const PEEK_SIDE_PANEL_WIDTH_CLASS = "w-[min(100%,max(85vw,560px),1200px)]";
@@ -0,0 +1,140 @@
1
+ // SPDX-License-Identifier: AGPL-3.0-or-later
2
+ // AllBlue - 理想之海
3
+ // Copyright (C) 2026 AllBlue Contributors
4
+ //
5
+ // This program is free software: you can redistribute it and/or modify
6
+ // it under the terms of the GNU Affero General Public License as published by
7
+ // the Free Software Foundation, either version 3 of the License, or
8
+ // (at your option) any later version.
9
+ //
10
+ // This program is distributed in the hope that it will be useful,
11
+ // but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ // GNU Affero General Public License for more details.
14
+ //
15
+ // You should have received a copy of the GNU Affero General Public License
16
+ // along with this program. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ // 审查重点 #2:客户端工具 schema 不一致 → 工具静默退化为 generic interrupt
19
+ // (无报错、工具不执行)。本测试钉住「单源定义」:客户端工厂返回的每个工具
20
+ // 的 inputSchema / outputSchema 必须与服务端注册表(plugin-lifecycle-defs)
21
+ // 中同名工具**引用同一 schema 对象**(toolDefinition().client() 按引用复制
22
+ // schema,同引用 ⟺ 同一 toolDefinition 导出)。
23
+ //
24
+ // 服务端动态插件工具(plugin__<id>__<name>)经由共享 builder 单源,见
25
+ // 「动态插件工具 builder」块。测试落点:jsdom/vitest unit(lib/**/__tests__),
26
+ // 不 import plugin-tools.ts / plugin-lifecycle-server.ts(它们顶层 import
27
+ // prisma);服务端注册表侧以纯净的 plugin-lifecycle-defs 导出为对照基准。
28
+
29
+ import { describe, expect, it } from "vitest";
30
+ import { buildPluginClientTools } from "@/lib/plugin-runtime/plugin-client-tools";
31
+ import {
32
+ buildPluginDynamicToolDef,
33
+ pluginDefineDef as sharedPluginDefineDef,
34
+ pluginInspectListDef as sharedPluginInspectListDef,
35
+ pluginRunDef as sharedPluginRunDef,
36
+ pluginStopDef as sharedPluginStopDef,
37
+ pluginUndefineDef as sharedPluginUndefineDef,
38
+ } from "@/lib/plugin-runtime/plugin-tool-defs";
39
+ import {
40
+ pluginDefineDef,
41
+ pluginInspectListDef,
42
+ pluginLifecycleDefs,
43
+ pluginRunDef,
44
+ pluginStopDef,
45
+ pluginUndefineDef,
46
+ } from "@/server/ai-gateway/tools/plugin-lifecycle-defs";
47
+
48
+ // 客户端执行的三件生命周期工具(plugin_define 走审批 interrupt、
49
+ // plugin_inspect_list 纯服务端执行,都不进客户端工厂)
50
+ const CLIENT_EXECUTED_DEFS = [pluginRunDef, pluginStopDef, pluginUndefineDef] as const;
51
+
52
+ describe("plugin tool schema parity(客户端工具单源 toolDefinition)", () => {
53
+ it("服务端注册表包含全部 5 件生命周期工具", () => {
54
+ expect(pluginLifecycleDefs).toHaveLength(5);
55
+ expect(pluginLifecycleDefs.map((d) => d.name)).toEqual([
56
+ "plugin_define",
57
+ "plugin_run",
58
+ "plugin_stop",
59
+ "plugin_undefine",
60
+ "plugin_inspect_list",
61
+ ]);
62
+ });
63
+
64
+ it("客户端工厂三件工具与同名服务端 def 引用同一 inputSchema / outputSchema", () => {
65
+ const clientTools = buildPluginClientTools();
66
+ const byName = new Map(clientTools.map((t) => [t.name, t]));
67
+
68
+ for (const def of CLIENT_EXECUTED_DEFS) {
69
+ const clientTool = byName.get(def.name);
70
+ expect(clientTool, `客户端工厂缺少工具 ${def.name}`).toBeDefined();
71
+ // inputSchema 同引用 ⟺ 同一 toolDefinition 导出(单源实锤)
72
+ expect(clientTool!.inputSchema, `${def.name} inputSchema 必须同引用`).toBe(
73
+ def.inputSchema
74
+ );
75
+ // outputSchema 双侧同在且同引用(1.0 一致性硬约束:缺失/不一致即
76
+ // 静默退化为 generic interrupt)
77
+ expect(clientTool!.outputSchema, `${def.name} outputSchema 必须同引用`).toBe(
78
+ def.outputSchema
79
+ );
80
+ // client 半必须挂执行体(0.x 起 execute 缺失 = 工具永不执行)
81
+ expect(typeof clientTool!.execute).toBe("function");
82
+ expect(clientTool!.__toolSide).toBe("client");
83
+ // needsApproval 字面量透传(审批 interrupt 门控依赖)
84
+ expect(clientTool!.needsApproval).toBe(def.needsApproval);
85
+ }
86
+ });
87
+
88
+ it("plugin_define / plugin_inspect_list 不进客户端工厂", () => {
89
+ const names = buildPluginClientTools().map((t) => t.name);
90
+ expect(names).toEqual(["plugin_run", "plugin_stop", "plugin_undefine"]);
91
+ });
92
+
93
+ it("服务端 def 文件与共享模块是同一批导出(re-export 单源实锤)", () => {
94
+ expect(pluginDefineDef).toBe(sharedPluginDefineDef);
95
+ expect(pluginRunDef).toBe(sharedPluginRunDef);
96
+ expect(pluginStopDef).toBe(sharedPluginStopDef);
97
+ expect(pluginUndefineDef).toBe(sharedPluginUndefineDef);
98
+ expect(pluginInspectListDef).toBe(sharedPluginInspectListDef);
99
+ });
100
+
101
+ it("动态插件工具 builder:三段式名称 + inputSchema 同引用 + 双侧同缺 outputSchema", () => {
102
+ const inputSchema = {
103
+ type: "object",
104
+ properties: { q: { type: "string" } },
105
+ required: ["q"],
106
+ };
107
+ const def = buildPluginDynamicToolDef("weather", {
108
+ name: "lookup",
109
+ description: "查天气",
110
+ inputSchema,
111
+ });
112
+ expect(def.name).toBe("plugin__weather__lookup");
113
+ expect(def.description).toBe("[weather] 查天气");
114
+ // 插件声明的 schema 对象原样同引用进定义(服务端注册同一 builder 同一对象)
115
+ expect(def.inputSchema).toBe(inputSchema);
116
+ // outputSchema 双侧同为 undefined(动态工具无输出校验,双侧一致)
117
+ expect(def.outputSchema).toBeUndefined();
118
+ expect(def.__toolSide).toBe("definition");
119
+ });
120
+
121
+ it("动态插件工具缺 inputSchema 时回落空对象 schema(与服务端注册口径一致)", () => {
122
+ const def = buildPluginDynamicToolDef("weather", {
123
+ name: "ping",
124
+ description: "探活",
125
+ });
126
+ expect(def.inputSchema).toEqual({ type: "object", properties: {} });
127
+ });
128
+
129
+ it("动态插件工具的 client 半挂执行体并沿用名称分派", async () => {
130
+ const def = buildPluginDynamicToolDef("weather", {
131
+ name: "lookup",
132
+ description: "查天气",
133
+ });
134
+ const clientTool = def.client(() => Promise.resolve({ ok: true }));
135
+ expect(clientTool.__toolSide).toBe("client");
136
+ expect(clientTool.inputSchema).toBe(def.inputSchema);
137
+ expect(clientTool.outputSchema).toBe(def.outputSchema);
138
+ expect(typeof clientTool.execute).toBe("function");
139
+ });
140
+ });