zyflow 0.6.4

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 (705) hide show
  1. package/.claude-flow/metrics/agent-metrics.json +1 -0
  2. package/.claude-flow/metrics/performance.json +87 -0
  3. package/.claude-flow/metrics/system-metrics.json +4370 -0
  4. package/.claude-flow/metrics/task-metrics.json +10 -0
  5. package/.claude-plugin/marketplace.json +18 -0
  6. package/.claude-plugin/plugin.json +17 -0
  7. package/.gitleaks.toml +69 -0
  8. package/.hive-mind/config/queens.json +59 -0
  9. package/.hive-mind/config/workers.json +72 -0
  10. package/.hive-mind/config.json +111 -0
  11. package/.hive-mind/hive.db +0 -0
  12. package/.hive-mind/hive.db-shm +0 -0
  13. package/.hive-mind/hive.db-wal +0 -0
  14. package/.leann/indexes/zyflow/documents.ids.txt +2078 -0
  15. package/.leann/indexes/zyflow/documents.index +0 -0
  16. package/.leann/indexes/zyflow/documents.leann.meta.json +25 -0
  17. package/.leann/indexes/zyflow/documents.leann.passages.idx +0 -0
  18. package/.leann/indexes/zyflow/documents.leann.passages.jsonl +2078 -0
  19. package/.mcp.json +41 -0
  20. package/.moai-backups/20260126_231508/.mcp.json +11 -0
  21. package/.moai-backups/20260126_231508/backup_metadata.json +34 -0
  22. package/.moai-backups/20260129_145438/.mcp.json +41 -0
  23. package/.moai-backups/20260129_145438/backup_metadata.json +53 -0
  24. package/.moai-backups/20260129_145504/.mcp.json +41 -0
  25. package/.moai-backups/20260129_145504/backup_metadata.json +20 -0
  26. package/.moai-backups/20260201_140004/.mcp.json +41 -0
  27. package/.moai-backups/20260201_140004/backup_metadata.json +51 -0
  28. package/.moai-backups/backup/.mcp.json +12 -0
  29. package/.moai-backups/settings-backup/settings.local.json +61 -0
  30. package/.pre-commit-config.yaml +74 -0
  31. package/.prettierignore +3 -0
  32. package/.prettierrc +7 -0
  33. package/.scannerwork/.sonar_lock +0 -0
  34. package/.scannerwork/report-task.txt +6 -0
  35. package/.serena/project.yml +105 -0
  36. package/.shadcn-admin-ref/.env.example +1 -0
  37. package/.shadcn-admin-ref/.prettierignore +18 -0
  38. package/.shadcn-admin-ref/.prettierrc +50 -0
  39. package/.shadcn-admin-ref/LICENSE +21 -0
  40. package/.shadcn-admin-ref/components.json +21 -0
  41. package/.shadcn-admin-ref/cz.yaml +7 -0
  42. package/.shadcn-admin-ref/eslint.config.js +59 -0
  43. package/.shadcn-admin-ref/index.html +80 -0
  44. package/.shadcn-admin-ref/knip.config.ts +8 -0
  45. package/.shadcn-admin-ref/netlify.toml +4 -0
  46. package/.shadcn-admin-ref/package.json +83 -0
  47. package/.shadcn-admin-ref/public/images/favicon.png +0 -0
  48. package/.shadcn-admin-ref/public/images/favicon.svg +4 -0
  49. package/.shadcn-admin-ref/public/images/favicon_light.png +0 -0
  50. package/.shadcn-admin-ref/public/images/favicon_light.svg +1 -0
  51. package/.shadcn-admin-ref/public/images/shadcn-admin.png +0 -0
  52. package/.shadcn-admin-ref/src/assets/brand-icons/icon-discord.tsx +28 -0
  53. package/.shadcn-admin-ref/src/assets/brand-icons/icon-docker.tsx +33 -0
  54. package/.shadcn-admin-ref/src/assets/brand-icons/icon-facebook.tsx +25 -0
  55. package/.shadcn-admin-ref/src/assets/brand-icons/icon-figma.tsx +27 -0
  56. package/.shadcn-admin-ref/src/assets/brand-icons/icon-github.tsx +25 -0
  57. package/.shadcn-admin-ref/src/assets/brand-icons/icon-gitlab.tsx +25 -0
  58. package/.shadcn-admin-ref/src/assets/brand-icons/icon-gmail.tsx +28 -0
  59. package/.shadcn-admin-ref/src/assets/brand-icons/icon-medium.tsx +30 -0
  60. package/.shadcn-admin-ref/src/assets/brand-icons/icon-notion.tsx +28 -0
  61. package/.shadcn-admin-ref/src/assets/brand-icons/icon-skype.tsx +26 -0
  62. package/.shadcn-admin-ref/src/assets/brand-icons/icon-slack.tsx +28 -0
  63. package/.shadcn-admin-ref/src/assets/brand-icons/icon-stripe.tsx +25 -0
  64. package/.shadcn-admin-ref/src/assets/brand-icons/icon-telegram.tsx +25 -0
  65. package/.shadcn-admin-ref/src/assets/brand-icons/icon-trello.tsx +27 -0
  66. package/.shadcn-admin-ref/src/assets/brand-icons/icon-whatsapp.tsx +26 -0
  67. package/.shadcn-admin-ref/src/assets/brand-icons/icon-zoom.tsx +26 -0
  68. package/.shadcn-admin-ref/src/assets/brand-icons/index.ts +16 -0
  69. package/.shadcn-admin-ref/src/assets/clerk-full-logo.tsx +41 -0
  70. package/.shadcn-admin-ref/src/assets/clerk-logo.tsx +23 -0
  71. package/.shadcn-admin-ref/src/assets/custom/icon-dir.tsx +110 -0
  72. package/.shadcn-admin-ref/src/assets/custom/icon-layout-compact.tsx +131 -0
  73. package/.shadcn-admin-ref/src/assets/custom/icon-layout-default.tsx +124 -0
  74. package/.shadcn-admin-ref/src/assets/custom/icon-layout-full.tsx +100 -0
  75. package/.shadcn-admin-ref/src/assets/custom/icon-sidebar-floating.tsx +82 -0
  76. package/.shadcn-admin-ref/src/assets/custom/icon-sidebar-inset.tsx +58 -0
  77. package/.shadcn-admin-ref/src/assets/custom/icon-sidebar-sidebar.tsx +53 -0
  78. package/.shadcn-admin-ref/src/assets/custom/icon-theme-dark.tsx +79 -0
  79. package/.shadcn-admin-ref/src/assets/custom/icon-theme-light.tsx +78 -0
  80. package/.shadcn-admin-ref/src/assets/custom/icon-theme-system.tsx +116 -0
  81. package/.shadcn-admin-ref/src/assets/logo.tsx +24 -0
  82. package/.shadcn-admin-ref/src/components/coming-soon.tsx +16 -0
  83. package/.shadcn-admin-ref/src/components/command-menu.tsx +91 -0
  84. package/.shadcn-admin-ref/src/components/config-drawer.tsx +354 -0
  85. package/.shadcn-admin-ref/src/components/confirm-dialog.tsx +67 -0
  86. package/.shadcn-admin-ref/src/components/data-table/bulk-actions.tsx +213 -0
  87. package/.shadcn-admin-ref/src/components/data-table/column-header.tsx +74 -0
  88. package/.shadcn-admin-ref/src/components/data-table/faceted-filter.tsx +146 -0
  89. package/.shadcn-admin-ref/src/components/data-table/index.ts +6 -0
  90. package/.shadcn-admin-ref/src/components/data-table/pagination.tsx +130 -0
  91. package/.shadcn-admin-ref/src/components/data-table/toolbar.tsx +85 -0
  92. package/.shadcn-admin-ref/src/components/data-table/view-options.tsx +56 -0
  93. package/.shadcn-admin-ref/src/components/date-picker.tsx +51 -0
  94. package/.shadcn-admin-ref/src/components/layout/app-sidebar.tsx +37 -0
  95. package/.shadcn-admin-ref/src/components/layout/app-title.tsx +64 -0
  96. package/.shadcn-admin-ref/src/components/layout/authenticated-layout.tsx +42 -0
  97. package/.shadcn-admin-ref/src/components/layout/data/sidebar-data.ts +205 -0
  98. package/.shadcn-admin-ref/src/components/layout/header.tsx +50 -0
  99. package/.shadcn-admin-ref/src/components/layout/main.tsx +27 -0
  100. package/.shadcn-admin-ref/src/components/layout/nav-group.tsx +185 -0
  101. package/.shadcn-admin-ref/src/components/layout/nav-user.tsx +124 -0
  102. package/.shadcn-admin-ref/src/components/layout/team-switcher.tsx +86 -0
  103. package/.shadcn-admin-ref/src/components/layout/top-nav.tsx +67 -0
  104. package/.shadcn-admin-ref/src/components/layout/types.ts +44 -0
  105. package/.shadcn-admin-ref/src/components/learn-more.tsx +44 -0
  106. package/.shadcn-admin-ref/src/components/long-text.tsx +84 -0
  107. package/.shadcn-admin-ref/src/components/navigation-progress.tsx +25 -0
  108. package/.shadcn-admin-ref/src/components/password-input.tsx +42 -0
  109. package/.shadcn-admin-ref/src/components/profile-dropdown.tsx +75 -0
  110. package/.shadcn-admin-ref/src/components/search.tsx +37 -0
  111. package/.shadcn-admin-ref/src/components/select-dropdown.tsx +62 -0
  112. package/.shadcn-admin-ref/src/components/sign-out-dialog.tsx +38 -0
  113. package/.shadcn-admin-ref/src/components/skip-to-main.tsx +10 -0
  114. package/.shadcn-admin-ref/src/components/theme-switch.tsx +58 -0
  115. package/.shadcn-admin-ref/src/components/ui/alert-dialog.tsx +154 -0
  116. package/.shadcn-admin-ref/src/components/ui/alert.tsx +65 -0
  117. package/.shadcn-admin-ref/src/components/ui/avatar.tsx +50 -0
  118. package/.shadcn-admin-ref/src/components/ui/badge.tsx +45 -0
  119. package/.shadcn-admin-ref/src/components/ui/button.tsx +58 -0
  120. package/.shadcn-admin-ref/src/components/ui/calendar.tsx +210 -0
  121. package/.shadcn-admin-ref/src/components/ui/card.tsx +91 -0
  122. package/.shadcn-admin-ref/src/components/ui/checkbox.tsx +29 -0
  123. package/.shadcn-admin-ref/src/components/ui/collapsible.tsx +31 -0
  124. package/.shadcn-admin-ref/src/components/ui/command.tsx +181 -0
  125. package/.shadcn-admin-ref/src/components/ui/dialog.tsx +142 -0
  126. package/.shadcn-admin-ref/src/components/ui/dropdown-menu.tsx +254 -0
  127. package/.shadcn-admin-ref/src/components/ui/form.tsx +164 -0
  128. package/.shadcn-admin-ref/src/components/ui/input-otp.tsx +74 -0
  129. package/.shadcn-admin-ref/src/components/ui/input.tsx +20 -0
  130. package/.shadcn-admin-ref/src/components/ui/label.tsx +23 -0
  131. package/.shadcn-admin-ref/src/components/ui/popover.tsx +45 -0
  132. package/.shadcn-admin-ref/src/components/ui/radio-group.tsx +42 -0
  133. package/.shadcn-admin-ref/src/components/ui/scroll-area.tsx +65 -0
  134. package/.shadcn-admin-ref/src/components/ui/select.tsx +182 -0
  135. package/.shadcn-admin-ref/src/components/ui/separator.tsx +25 -0
  136. package/.shadcn-admin-ref/src/components/ui/sheet.tsx +136 -0
  137. package/.shadcn-admin-ref/src/components/ui/sidebar.tsx +728 -0
  138. package/.shadcn-admin-ref/src/components/ui/skeleton.tsx +13 -0
  139. package/.shadcn-admin-ref/src/components/ui/sonner.tsx +21 -0
  140. package/.shadcn-admin-ref/src/components/ui/switch.tsx +28 -0
  141. package/.shadcn-admin-ref/src/components/ui/table.tsx +113 -0
  142. package/.shadcn-admin-ref/src/components/ui/tabs.tsx +63 -0
  143. package/.shadcn-admin-ref/src/components/ui/textarea.tsx +17 -0
  144. package/.shadcn-admin-ref/src/components/ui/tooltip.tsx +60 -0
  145. package/.shadcn-admin-ref/src/config/fonts.ts +19 -0
  146. package/.shadcn-admin-ref/src/context/direction-provider.tsx +61 -0
  147. package/.shadcn-admin-ref/src/context/font-provider.tsx +58 -0
  148. package/.shadcn-admin-ref/src/context/layout-provider.tsx +85 -0
  149. package/.shadcn-admin-ref/src/context/search-provider.tsx +46 -0
  150. package/.shadcn-admin-ref/src/context/theme-provider.tsx +110 -0
  151. package/.shadcn-admin-ref/src/features/apps/data/apps.tsx +110 -0
  152. package/.shadcn-admin-ref/src/features/apps/index.tsx +179 -0
  153. package/.shadcn-admin-ref/src/features/auth/auth-layout.tsx +19 -0
  154. package/.shadcn-admin-ref/src/features/auth/forgot-password/components/forgot-password-form.tsx +82 -0
  155. package/.shadcn-admin-ref/src/features/auth/forgot-password/index.tsx +44 -0
  156. package/.shadcn-admin-ref/src/features/auth/otp/components/otp-form.tsx +100 -0
  157. package/.shadcn-admin-ref/src/features/auth/otp/index.tsx +44 -0
  158. package/.shadcn-admin-ref/src/features/auth/sign-in/assets/dashboard-dark.png +0 -0
  159. package/.shadcn-admin-ref/src/features/auth/sign-in/assets/dashboard-light.png +0 -0
  160. package/.shadcn-admin-ref/src/features/auth/sign-in/components/user-auth-form.tsx +150 -0
  161. package/.shadcn-admin-ref/src/features/auth/sign-in/index.tsx +51 -0
  162. package/.shadcn-admin-ref/src/features/auth/sign-in/sign-in-2.tsx +69 -0
  163. package/.shadcn-admin-ref/src/features/auth/sign-up/components/sign-up-form.tsx +143 -0
  164. package/.shadcn-admin-ref/src/features/auth/sign-up/index.tsx +57 -0
  165. package/.shadcn-admin-ref/src/features/chats/components/new-chat.tsx +127 -0
  166. package/.shadcn-admin-ref/src/features/chats/data/chat-types.ts +4 -0
  167. package/.shadcn-admin-ref/src/features/chats/data/convo.json +309 -0
  168. package/.shadcn-admin-ref/src/features/chats/index.tsx +349 -0
  169. package/.shadcn-admin-ref/src/features/dashboard/components/analytics-chart.tsx +77 -0
  170. package/.shadcn-admin-ref/src/features/dashboard/components/analytics.tsx +189 -0
  171. package/.shadcn-admin-ref/src/features/dashboard/components/overview.tsx +82 -0
  172. package/.shadcn-admin-ref/src/features/dashboard/components/recent-sales.tsx +83 -0
  173. package/.shadcn-admin-ref/src/features/dashboard/index.tsx +220 -0
  174. package/.shadcn-admin-ref/src/features/errors/forbidden.tsx +25 -0
  175. package/.shadcn-admin-ref/src/features/errors/general-error.tsx +36 -0
  176. package/.shadcn-admin-ref/src/features/errors/maintenance-error.tsx +19 -0
  177. package/.shadcn-admin-ref/src/features/errors/not-found-error.tsx +25 -0
  178. package/.shadcn-admin-ref/src/features/errors/unauthorized-error.tsx +25 -0
  179. package/.shadcn-admin-ref/src/features/settings/account/account-form.tsx +173 -0
  180. package/.shadcn-admin-ref/src/features/settings/account/index.tsx +14 -0
  181. package/.shadcn-admin-ref/src/features/settings/appearance/appearance-form.tsx +162 -0
  182. package/.shadcn-admin-ref/src/features/settings/appearance/index.tsx +14 -0
  183. package/.shadcn-admin-ref/src/features/settings/components/content-section.tsx +22 -0
  184. package/.shadcn-admin-ref/src/features/settings/components/sidebar-nav.tsx +84 -0
  185. package/.shadcn-admin-ref/src/features/settings/display/display-form.tsx +121 -0
  186. package/.shadcn-admin-ref/src/features/settings/display/index.tsx +13 -0
  187. package/.shadcn-admin-ref/src/features/settings/index.tsx +74 -0
  188. package/.shadcn-admin-ref/src/features/settings/notifications/index.tsx +13 -0
  189. package/.shadcn-admin-ref/src/features/settings/notifications/notifications-form.tsx +220 -0
  190. package/.shadcn-admin-ref/src/features/settings/profile/index.tsx +13 -0
  191. package/.shadcn-admin-ref/src/features/settings/profile/profile-form.tsx +177 -0
  192. package/.shadcn-admin-ref/src/features/tasks/components/data-table-bulk-actions.tsx +193 -0
  193. package/.shadcn-admin-ref/src/features/tasks/components/data-table-row-actions.tsx +83 -0
  194. package/.shadcn-admin-ref/src/features/tasks/components/tasks-columns.tsx +123 -0
  195. package/.shadcn-admin-ref/src/features/tasks/components/tasks-dialogs.tsx +72 -0
  196. package/.shadcn-admin-ref/src/features/tasks/components/tasks-import-dialog.tsx +110 -0
  197. package/.shadcn-admin-ref/src/features/tasks/components/tasks-multi-delete-dialog.tsx +95 -0
  198. package/.shadcn-admin-ref/src/features/tasks/components/tasks-mutate-drawer.tsx +212 -0
  199. package/.shadcn-admin-ref/src/features/tasks/components/tasks-primary-buttons.tsx +21 -0
  200. package/.shadcn-admin-ref/src/features/tasks/components/tasks-provider.tsx +36 -0
  201. package/.shadcn-admin-ref/src/features/tasks/components/tasks-table.tsx +197 -0
  202. package/.shadcn-admin-ref/src/features/tasks/data/data.tsx +77 -0
  203. package/.shadcn-admin-ref/src/features/tasks/data/schema.ts +13 -0
  204. package/.shadcn-admin-ref/src/features/tasks/data/tasks.ts +29 -0
  205. package/.shadcn-admin-ref/src/features/tasks/index.tsx +41 -0
  206. package/.shadcn-admin-ref/src/features/users/components/data-table-bulk-actions.tsx +139 -0
  207. package/.shadcn-admin-ref/src/features/users/components/data-table-row-actions.tsx +63 -0
  208. package/.shadcn-admin-ref/src/features/users/components/users-action-dialog.tsx +326 -0
  209. package/.shadcn-admin-ref/src/features/users/components/users-columns.tsx +138 -0
  210. package/.shadcn-admin-ref/src/features/users/components/users-delete-dialog.tsx +81 -0
  211. package/.shadcn-admin-ref/src/features/users/components/users-dialogs.tsx +51 -0
  212. package/.shadcn-admin-ref/src/features/users/components/users-invite-dialog.tsx +150 -0
  213. package/.shadcn-admin-ref/src/features/users/components/users-multi-delete-dialog.tsx +95 -0
  214. package/.shadcn-admin-ref/src/features/users/components/users-primary-buttons.tsx +21 -0
  215. package/.shadcn-admin-ref/src/features/users/components/users-provider.tsx +36 -0
  216. package/.shadcn-admin-ref/src/features/users/components/users-table.tsx +194 -0
  217. package/.shadcn-admin-ref/src/features/users/data/data.ts +35 -0
  218. package/.shadcn-admin-ref/src/features/users/data/schema.ts +32 -0
  219. package/.shadcn-admin-ref/src/features/users/data/users.ts +33 -0
  220. package/.shadcn-admin-ref/src/features/users/index.tsx +47 -0
  221. package/.shadcn-admin-ref/src/hooks/use-dialog-state.tsx +18 -0
  222. package/.shadcn-admin-ref/src/hooks/use-mobile.tsx +19 -0
  223. package/.shadcn-admin-ref/src/hooks/use-table-url-state.ts +219 -0
  224. package/.shadcn-admin-ref/src/lib/cookies.ts +43 -0
  225. package/.shadcn-admin-ref/src/lib/handle-server-error.ts +24 -0
  226. package/.shadcn-admin-ref/src/lib/show-submitted-data.tsx +15 -0
  227. package/.shadcn-admin-ref/src/lib/utils.ts +60 -0
  228. package/.shadcn-admin-ref/src/main.tsx +107 -0
  229. package/.shadcn-admin-ref/src/routeTree.gen.ts +719 -0
  230. package/.shadcn-admin-ref/src/routes/(auth)/forgot-password.tsx +6 -0
  231. package/.shadcn-admin-ref/src/routes/(auth)/otp.tsx +6 -0
  232. package/.shadcn-admin-ref/src/routes/(auth)/sign-in-2.tsx +6 -0
  233. package/.shadcn-admin-ref/src/routes/(auth)/sign-in.tsx +12 -0
  234. package/.shadcn-admin-ref/src/routes/(auth)/sign-up.tsx +6 -0
  235. package/.shadcn-admin-ref/src/routes/(errors)/401.tsx +6 -0
  236. package/.shadcn-admin-ref/src/routes/(errors)/403.tsx +6 -0
  237. package/.shadcn-admin-ref/src/routes/(errors)/404.tsx +6 -0
  238. package/.shadcn-admin-ref/src/routes/(errors)/500.tsx +6 -0
  239. package/.shadcn-admin-ref/src/routes/(errors)/503.tsx +6 -0
  240. package/.shadcn-admin-ref/src/routes/__root.tsx +30 -0
  241. package/.shadcn-admin-ref/src/routes/_authenticated/apps/index.tsx +17 -0
  242. package/.shadcn-admin-ref/src/routes/_authenticated/chats/index.tsx +6 -0
  243. package/.shadcn-admin-ref/src/routes/_authenticated/errors/$error.tsx +45 -0
  244. package/.shadcn-admin-ref/src/routes/_authenticated/help-center/index.tsx +6 -0
  245. package/.shadcn-admin-ref/src/routes/_authenticated/index.tsx +6 -0
  246. package/.shadcn-admin-ref/src/routes/_authenticated/route.tsx +6 -0
  247. package/.shadcn-admin-ref/src/routes/_authenticated/settings/account.tsx +6 -0
  248. package/.shadcn-admin-ref/src/routes/_authenticated/settings/appearance.tsx +6 -0
  249. package/.shadcn-admin-ref/src/routes/_authenticated/settings/display.tsx +6 -0
  250. package/.shadcn-admin-ref/src/routes/_authenticated/settings/index.tsx +6 -0
  251. package/.shadcn-admin-ref/src/routes/_authenticated/settings/notifications.tsx +6 -0
  252. package/.shadcn-admin-ref/src/routes/_authenticated/settings/route.tsx +6 -0
  253. package/.shadcn-admin-ref/src/routes/_authenticated/tasks/index.tsx +23 -0
  254. package/.shadcn-admin-ref/src/routes/_authenticated/users/index.tsx +32 -0
  255. package/.shadcn-admin-ref/src/routes/clerk/(auth)/route.tsx +60 -0
  256. package/.shadcn-admin-ref/src/routes/clerk/(auth)/sign-in.tsx +14 -0
  257. package/.shadcn-admin-ref/src/routes/clerk/(auth)/sign-up.tsx +9 -0
  258. package/.shadcn-admin-ref/src/routes/clerk/_authenticated/route.tsx +6 -0
  259. package/.shadcn-admin-ref/src/routes/clerk/_authenticated/user-management.tsx +184 -0
  260. package/.shadcn-admin-ref/src/routes/clerk/route.tsx +135 -0
  261. package/.shadcn-admin-ref/src/stores/auth-store.ts +53 -0
  262. package/.shadcn-admin-ref/src/styles/index.css +87 -0
  263. package/.shadcn-admin-ref/src/styles/theme.css +102 -0
  264. package/.shadcn-admin-ref/src/tanstack-table.d.ts +10 -0
  265. package/.shadcn-admin-ref/src/vite-env.d.ts +1 -0
  266. package/.swarm/memory.db +0 -0
  267. package/.swarm/memory.db-shm +0 -0
  268. package/.swarm/memory.db-wal +0 -0
  269. package/.zyflow/cli-settings.json +30 -0
  270. package/.zyflow/db.sqlite +0 -0
  271. package/.zyflow/logs/add-gitdiagram-integration/1633-1765491505852.json +10 -0
  272. package/.zyflow/logs/add-gitdiagram-integration/1633-1765491622627.json +10 -0
  273. package/.zyflow/logs/add-gitdiagram-integration/1633-1765491794652.json +10 -0
  274. package/.zyflow/logs/add-gitdiagram-integration/1633-1765491890392.json +10 -0
  275. package/.zyflow/logs/add-gitdiagram-integration/1633-1765494002879.json +10 -0
  276. package/.zyflow/logs/add-gitdiagram-integration/1633-1765494183887.json +10 -0
  277. package/.zyflow/logs/add-gitdiagram-integration/1633-1765494342052.json +10 -0
  278. package/.zyflow/logs/add-gitdiagram-integration/1633-1765494387244.json +10 -0
  279. package/.zyflow/logs/add-gitdiagram-integration/1633-1765494387245.json +10 -0
  280. package/.zyflow/logs/add-gitdiagram-integration/1633-1765494606176.json +10 -0
  281. package/.zyflow/logs/add-gitdiagram-integration/1633-1765495967542.json +16 -0
  282. package/.zyflow/logs/add-gitdiagram-integration/1633-1765495967629.json +16 -0
  283. package/.zyflow/logs/add-gitdiagram-integration/1633-1765497861143.json +16 -0
  284. package/.zyflow/logs/add-gitdiagram-integration/1633-1765497861870.json +20 -0
  285. package/.zyflow/logs/add-gitdiagram-integration/1633-1765498021377.json +18 -0
  286. package/.zyflow/logs/add-gitdiagram-integration/1633-1765498021660.json +18 -0
  287. package/.zyflow/logs/add-gitdiagram-integration/1633-1765503255525.json +13 -0
  288. package/.zyflow/logs/add-gitdiagram-integration/1633-1765503256018.json +13 -0
  289. package/.zyflow/logs/add-gitdiagram-integration/1633-1765504009102.json +16 -0
  290. package/.zyflow/logs/add-gitdiagram-integration/1633-1765504492051.json +18 -0
  291. package/.zyflow/logs/add-gitdiagram-integration/1633-1765504946437.json +16 -0
  292. package/.zyflow/logs/add-gitdiagram-integration/1633-1765504946640.json +16 -0
  293. package/.zyflow/logs/add-gitdiagram-integration/1634-1765505950215.json +16 -0
  294. package/.zyflow/logs/add-gitdiagram-integration/1634-1765505950948.json +18 -0
  295. package/.zyflow/logs/add-gitdiagram-integration/1635-1765505971712.json +18 -0
  296. package/.zyflow/logs/add-gitdiagram-integration/1635-1765505971976.json +18 -0
  297. package/.zyflow/logs/add-gitdiagram-integration/1636-1765505986208.json +18 -0
  298. package/.zyflow/logs/add-gitdiagram-integration/1636-1765505986620.json +16 -0
  299. package/.zyflow/logs/integrate-claude-flow/3580-1765996816612.json +10 -0
  300. package/.zyflow/logs/integrate-claude-flow/3580-1766014825819.json +10 -0
  301. package/.zyflow/logs/integrate-claude-flow/3580-1766015183794.json +12 -0
  302. package/.zyflow/logs/integrate-claude-flow/3580-1766015474608.json +12 -0
  303. package/.zyflow/logs/integrate-claude-flow/3581-1766016502824.json +63 -0
  304. package/.zyflow/logs/integrate-claude-flow/3581-1766016576008.json +60 -0
  305. package/.zyflow/logs/integrate-claude-flow/3582-1766022737754.json +110 -0
  306. package/.zyflow/logs/integrate-claude-flow/3582-1766022809327.json +135 -0
  307. package/.zyflow/sessions.json +242 -0
  308. package/.zyflow/settings.json +6 -0
  309. package/.zyflow/tasks.db +0 -0
  310. package/.zyflow/tasks.db-shm +0 -0
  311. package/.zyflow/tasks.db-wal +0 -0
  312. package/.zyflow/zyflow.sqlite +0 -0
  313. package/Dockerfile +82 -0
  314. package/LICENSE +21 -0
  315. package/README.md +506 -0
  316. package/claude-flow +34 -0
  317. package/components.json +21 -0
  318. package/config/ports.ts +28 -0
  319. package/docker-compose.yml +52 -0
  320. package/eslint.config.js +34 -0
  321. package/index.html +19 -0
  322. package/logs/mcp-error.log +55 -0
  323. package/logs/mcp-out.log +0 -0
  324. package/logs/pm2-error.log +0 -0
  325. package/logs/pm2-out.log +265 -0
  326. package/logs/py-error.log +22 -0
  327. package/logs/py-out.log +0 -0
  328. package/logs/server-error.log +11000 -0
  329. package/logs/server-out.log +8117 -0
  330. package/logs/vite-error.log +404 -0
  331. package/logs/vite-out.log +311 -0
  332. package/mcp-server/agent-tools.ts +375 -0
  333. package/mcp-server/cli-models.ts +193 -0
  334. package/mcp-server/context.ts +110 -0
  335. package/mcp-server/diagram-tools.ts +341 -0
  336. package/mcp-server/index.ts +2014 -0
  337. package/mcp-server/integration-tools.ts +909 -0
  338. package/mcp-server/moai-spec-tools.ts +416 -0
  339. package/mcp-server/parser.ts +422 -0
  340. package/mcp-server/post-task-runner.ts +253 -0
  341. package/mcp-server/post-task-types.ts +426 -0
  342. package/mcp-server/quarantine-manager.ts +479 -0
  343. package/mcp-server/report-generator.ts +386 -0
  344. package/mcp-server/task-tools.ts +619 -0
  345. package/mcp-server/trigger-config.ts +288 -0
  346. package/mcp-server/trigger-router.ts +305 -0
  347. package/mcp-server/triggers/event-listener.ts +331 -0
  348. package/mcp-server/triggers/git-hooks.ts +283 -0
  349. package/mcp-server/triggers/scheduler.ts +289 -0
  350. package/mcp-server/types.ts +55 -0
  351. package/memory/claude-flow@alpha-data.json +5 -0
  352. package/nginx/zyflow.conf +144 -0
  353. package/openspec/config.yaml +78 -0
  354. package/openspec-backup.tar.gz +0 -0
  355. package/package.json +154 -0
  356. package/packages/gitdiagram-core/.claude-flow/metrics/agent-metrics.json +1 -0
  357. package/packages/gitdiagram-core/.claude-flow/metrics/performance.json +87 -0
  358. package/packages/gitdiagram-core/.claude-flow/metrics/task-metrics.json +10 -0
  359. package/packages/gitdiagram-core/package.json +41 -0
  360. package/packages/gitdiagram-core/src/file-tree.ts +272 -0
  361. package/packages/gitdiagram-core/src/generator.ts +283 -0
  362. package/packages/gitdiagram-core/src/index.ts +78 -0
  363. package/packages/gitdiagram-core/src/llm-adapter.ts +235 -0
  364. package/packages/gitdiagram-core/src/mermaid-utils.ts +304 -0
  365. package/packages/gitdiagram-core/src/prompts.ts +281 -0
  366. package/packages/zyflow-parser/package.json +34 -0
  367. package/packages/zyflow-parser/src/index.ts +26 -0
  368. package/packages/zyflow-parser/src/moai-parser.ts +603 -0
  369. package/packages/zyflow-parser/src/moai-types.ts +110 -0
  370. package/packages/zyflow-remote-plugin/.claude-flow/metrics/agent-metrics.json +1 -0
  371. package/packages/zyflow-remote-plugin/.claude-flow/metrics/performance.json +87 -0
  372. package/packages/zyflow-remote-plugin/.claude-flow/metrics/task-metrics.json +10 -0
  373. package/packages/zyflow-remote-plugin/package.json +31 -0
  374. package/packages/zyflow-remote-plugin/src/index.ts +71 -0
  375. package/packages/zyflow-remote-plugin/src/remote-config.ts +232 -0
  376. package/packages/zyflow-remote-plugin/src/router.ts +535 -0
  377. package/packages/zyflow-remote-plugin/src/ssh-config-parser.ts +123 -0
  378. package/packages/zyflow-remote-plugin/src/ssh-manager.ts +598 -0
  379. package/packages/zyflow-remote-plugin/src/types.ts +149 -0
  380. package/plugin/manifest.json +26 -0
  381. package/plugin/package.json +13 -0
  382. package/public/favicon.svg +4 -0
  383. package/server/adk/agents/error-analyzer.ts +223 -0
  384. package/server/adk/agents/fix-generator.ts +187 -0
  385. package/server/adk/agents/pr-agent.ts +264 -0
  386. package/server/adk/agents/validator.ts +187 -0
  387. package/server/adk/config.ts +43 -0
  388. package/server/adk/index.ts +69 -0
  389. package/server/adk/integration.ts +297 -0
  390. package/server/adk/orchestrator.ts +405 -0
  391. package/server/adk/tools/build-tools.ts +290 -0
  392. package/server/adk/tools/file-tools.ts +351 -0
  393. package/server/adk/tools/git-tools.ts +280 -0
  394. package/server/adk/tools/github-tools.ts +249 -0
  395. package/server/agents/agent-monitor.ts +416 -0
  396. package/server/agents/alert-integration.ts +312 -0
  397. package/server/agents/error-analyzer.ts +472 -0
  398. package/server/agents/error-detector.ts +442 -0
  399. package/server/agents/fix-generator.ts +421 -0
  400. package/server/agents/fix-validator.ts +428 -0
  401. package/server/agents/merge-policy.ts +362 -0
  402. package/server/agents/pr-workflow.ts +476 -0
  403. package/server/agents/prompts/error-analysis.ts +393 -0
  404. package/server/ai/gemini-client.ts +499 -0
  405. package/server/ai/index.ts +317 -0
  406. package/server/ai/types.ts +137 -0
  407. package/server/app.ts +3693 -0
  408. package/server/archive-manager.ts +604 -0
  409. package/server/backlog/index.ts +7 -0
  410. package/server/backlog/migration.ts +331 -0
  411. package/server/backlog/parser.ts +323 -0
  412. package/server/backlog/sync.ts +325 -0
  413. package/server/change-log.ts +868 -0
  414. package/server/claude-flow/index.ts +12 -0
  415. package/server/claude-flow/prompt-builder.ts +407 -0
  416. package/server/claude-flow/types.ts +33 -0
  417. package/server/cli-adapter/index.ts +11 -0
  418. package/server/cli-adapter/process-manager.ts +612 -0
  419. package/server/cli-adapter/profile-manager.ts +286 -0
  420. package/server/cli-adapter/routes.ts +561 -0
  421. package/server/cli-adapter/types.ts +226 -0
  422. package/server/config.d.ts +18 -0
  423. package/server/config.js +79 -0
  424. package/server/config.ts +262 -0
  425. package/server/flow-sync.ts +543 -0
  426. package/server/git/change-workflow.ts +446 -0
  427. package/server/git/commands.ts +370 -0
  428. package/server/git/github.ts +247 -0
  429. package/server/git/index.ts +1202 -0
  430. package/server/git/status.ts +322 -0
  431. package/server/index.ts +136 -0
  432. package/server/integrations/crypto.ts +142 -0
  433. package/server/integrations/db/client.ts +169 -0
  434. package/server/integrations/db/schema.ts +167 -0
  435. package/server/integrations/env-parser.ts +365 -0
  436. package/server/integrations/index.ts +101 -0
  437. package/server/integrations/keychain.ts +239 -0
  438. package/server/integrations/local/file-utils.ts +383 -0
  439. package/server/integrations/local/index.ts +64 -0
  440. package/server/integrations/local/resolver.ts +439 -0
  441. package/server/integrations/local/types.ts +122 -0
  442. package/server/integrations/routes.ts +1100 -0
  443. package/server/integrations/service-patterns.ts +771 -0
  444. package/server/integrations/services/accounts.ts +356 -0
  445. package/server/integrations/services/env-import.ts +279 -0
  446. package/server/integrations/services/projects.ts +552 -0
  447. package/server/integrations/services/system-import.ts +1110 -0
  448. package/server/migrations/ears-generator.ts +491 -0
  449. package/server/migrations/gherkin-generator.ts +605 -0
  450. package/server/migrations/index.ts +73 -0
  451. package/server/migrations/migrate-spec-format.ts +492 -0
  452. package/server/migrations/openspec-parser.ts +542 -0
  453. package/server/migrations/tag-generator.ts +474 -0
  454. package/server/moai-specs.ts +487 -0
  455. package/server/moai-watcher.ts +145 -0
  456. package/server/parser-debug.ts +37 -0
  457. package/server/parser-utils.ts +316 -0
  458. package/server/parser.d.ts +17 -0
  459. package/server/parser.js +221 -0
  460. package/server/parser.ts +342 -0
  461. package/server/remote-watcher.ts +367 -0
  462. package/server/replay-engine.ts +915 -0
  463. package/server/routes/alerts.ts +1028 -0
  464. package/server/routes/changes.ts +812 -0
  465. package/server/routes/docs.ts +898 -0
  466. package/server/routes/flow.ts +2814 -0
  467. package/server/routes/global-chat.ts +162 -0
  468. package/server/routes/leann.ts +327 -0
  469. package/server/routes/projects.ts +1282 -0
  470. package/server/routes/search.ts +266 -0
  471. package/server/routes/specs.ts +482 -0
  472. package/server/routes/webhooks.ts +579 -0
  473. package/server/server/parser.js +265 -0
  474. package/server/services/githubActionsPoller.ts +797 -0
  475. package/server/services/slackNotifier.ts +476 -0
  476. package/server/src/types/index.js +1 -0
  477. package/server/sync-tasks.ts +741 -0
  478. package/server/tasks/cli/commands.ts +269 -0
  479. package/server/tasks/cli/index.ts +152 -0
  480. package/server/tasks/core/search.ts +81 -0
  481. package/server/tasks/core/task.ts +307 -0
  482. package/server/tasks/db/client.ts +1008 -0
  483. package/server/tasks/db/schema.ts +572 -0
  484. package/server/tasks/index.ts +24 -0
  485. package/server/tasks.db +0 -0
  486. package/server/types/archive.ts +136 -0
  487. package/server/types/change-log.ts +643 -0
  488. package/server/types/spec.ts +188 -0
  489. package/server/unified-spec-scanner.ts +753 -0
  490. package/server/utils/crypto.ts +179 -0
  491. package/server/utils/webhook-verify.ts +216 -0
  492. package/server/watcher.ts +132 -0
  493. package/server/websocket.ts +99 -0
  494. package/server-output.log +6 -0
  495. package/sonar-project.properties +18 -0
  496. package/src/App.tsx +386 -0
  497. package/src/api/client.ts +346 -0
  498. package/src/api/error-interceptor.ts +366 -0
  499. package/src/api/errors.ts +123 -0
  500. package/src/api/flow.ts +233 -0
  501. package/src/api/offline-queue.ts +351 -0
  502. package/src/api/retry-logic.ts +233 -0
  503. package/src/components/OfflineModeBanner.tsx +159 -0
  504. package/src/components/SSEStatusIndicator.tsx +194 -0
  505. package/src/components/agent/AgentChat.tsx +243 -0
  506. package/src/components/agent/AgentPage.tsx +182 -0
  507. package/src/components/agent/AgentSidebar.tsx +231 -0
  508. package/src/components/agent/index.ts +7 -0
  509. package/src/components/alerts/AlertCenter.tsx +239 -0
  510. package/src/components/alerts/AlertDashboard.tsx +211 -0
  511. package/src/components/alerts/AlertDetail.tsx +474 -0
  512. package/src/components/alerts/AlertList.tsx +113 -0
  513. package/src/components/alerts/AlertSettings.tsx +336 -0
  514. package/src/components/alerts/index.ts +5 -0
  515. package/src/components/chat/ChatPanel.tsx +642 -0
  516. package/src/components/chat/index.ts +1 -0
  517. package/src/components/cli/AddCustomCLIDialog.tsx +210 -0
  518. package/src/components/cli/CLISelector.tsx +187 -0
  519. package/src/components/cli/index.ts +8 -0
  520. package/src/components/dashboard/ArchivedChangeList.tsx +102 -0
  521. package/src/components/dashboard/ArchivedChangeViewer.tsx +184 -0
  522. package/src/components/dashboard/ArchivedChangesPage.tsx +31 -0
  523. package/src/components/dashboard/ChangeList.tsx +86 -0
  524. package/src/components/dashboard/ThemeToggle.tsx +33 -0
  525. package/src/components/diagram/DiagramViewer.tsx +256 -0
  526. package/src/components/diagram/MermaidRenderer.tsx +163 -0
  527. package/src/components/diagram/ProjectDiagramTab.tsx +161 -0
  528. package/src/components/diagram/index.ts +13 -0
  529. package/src/components/errors/ErrorBoundary.tsx +276 -0
  530. package/src/components/errors/ErrorFallback.tsx +198 -0
  531. package/src/components/errors/ErrorToast.tsx +221 -0
  532. package/src/components/flow/BacklogView.tsx +1142 -0
  533. package/src/components/flow/ChangeDetail.tsx +475 -0
  534. package/src/components/flow/ChangeItem.tsx +230 -0
  535. package/src/components/flow/ChangeList.tsx +92 -0
  536. package/src/components/flow/ExecutionHistoryDialog.tsx +224 -0
  537. package/src/components/flow/FlowContent.tsx +212 -0
  538. package/src/components/flow/FlowPage.tsx +9 -0
  539. package/src/components/flow/PipelineBar.tsx +214 -0
  540. package/src/components/flow/ProjectDashboard.tsx +222 -0
  541. package/src/components/flow/SpecDetail.tsx +138 -0
  542. package/src/components/flow/SpecDetailTabs.tsx +176 -0
  543. package/src/components/flow/SpecItem.tsx +93 -0
  544. package/src/components/flow/SpecProgressBar.tsx +47 -0
  545. package/src/components/flow/StageContent.tsx +620 -0
  546. package/src/components/flow/StandaloneTasks.tsx +960 -0
  547. package/src/components/flow/TaskExecutionDialog.tsx +1204 -0
  548. package/src/components/flow/index.ts +9 -0
  549. package/src/components/flow/task-execution/AgentSlider.tsx +37 -0
  550. package/src/components/flow/task-execution/ConsensusSettings.tsx +129 -0
  551. package/src/components/flow/task-execution/ExecutionOutput.tsx +398 -0
  552. package/src/components/flow/task-execution/ModelSelector.tsx +134 -0
  553. package/src/components/flow/task-execution/ProviderSelector.tsx +137 -0
  554. package/src/components/flow/task-execution/RecommendationBanner.tsx +71 -0
  555. package/src/components/flow/task-execution/StatusBadge.tsx +43 -0
  556. package/src/components/flow/task-execution/StrategySelector.tsx +48 -0
  557. package/src/components/flow/task-execution/SwarmSummary.tsx +55 -0
  558. package/src/components/flow/task-execution/index.ts +14 -0
  559. package/src/components/flow/task-execution/types.ts +56 -0
  560. package/src/components/git/ChangeWorkflowDialog.tsx +582 -0
  561. package/src/components/git/ConflictResolutionDialog.tsx +398 -0
  562. package/src/components/git/GitBranchSelector.tsx +212 -0
  563. package/src/components/git/GitCommitDialog.tsx +254 -0
  564. package/src/components/git/GitStatusBadge.tsx +148 -0
  565. package/src/components/git/GitSyncButton.tsx +128 -0
  566. package/src/components/git/RemoteStatusBanner.tsx +143 -0
  567. package/src/components/git/index.ts +9 -0
  568. package/src/components/integrations/EnvImportDialog.tsx +524 -0
  569. package/src/components/integrations/EnvironmentDialog.tsx +227 -0
  570. package/src/components/integrations/IntegrationBadges.tsx +91 -0
  571. package/src/components/integrations/IntegrationsSettings.tsx +55 -0
  572. package/src/components/integrations/ProjectIntegrations.tsx +481 -0
  573. package/src/components/integrations/ServiceAccountDialog.tsx +422 -0
  574. package/src/components/integrations/ServiceAccountList.tsx +305 -0
  575. package/src/components/integrations/SystemImportDialog.tsx +436 -0
  576. package/src/components/integrations/TestAccountDialog.tsx +162 -0
  577. package/src/components/integrations/index.ts +6 -0
  578. package/src/components/layout/AppSidebar.tsx +284 -0
  579. package/src/components/layout/FlowSidebar.tsx +435 -0
  580. package/src/components/layout/GlobalCommandPalette.tsx +410 -0
  581. package/src/components/layout/MenuBar.tsx +227 -0
  582. package/src/components/layout/StatusBar.tsx +226 -0
  583. package/src/components/monitoring/ErrorDashboard.tsx +274 -0
  584. package/src/components/monitoring/ErrorDetailPanel.tsx +200 -0
  585. package/src/components/monitoring/ErrorFilters.tsx +219 -0
  586. package/src/components/monitoring/ErrorHistoryList.tsx +141 -0
  587. package/src/components/monitoring/ErrorStats.tsx +249 -0
  588. package/src/components/remote/RemoteFileBrowser.tsx +249 -0
  589. package/src/components/remote/RemoteServerDialog.tsx +234 -0
  590. package/src/components/remote/RemoteServerList.tsx +366 -0
  591. package/src/components/remote/index.ts +7 -0
  592. package/src/components/settings/CLISettings.tsx +522 -0
  593. package/src/components/settings/CustomCLIDialog.tsx +548 -0
  594. package/src/components/settings/IntegrationsSettings.tsx +51 -0
  595. package/src/components/settings/ProjectSettings.tsx +441 -0
  596. package/src/components/settings/ProjectsSettings.tsx +541 -0
  597. package/src/components/settings/SearchSettings.tsx +272 -0
  598. package/src/components/settings/SettingsPage.tsx +68 -0
  599. package/src/components/settings/index.ts +5 -0
  600. package/src/components/swarm/ExecutionPanel.tsx +284 -0
  601. package/src/components/swarm/LogViewer.tsx +196 -0
  602. package/src/components/swarm/ProgressIndicator.tsx +111 -0
  603. package/src/components/swarm/index.ts +3 -0
  604. package/src/components/tasks/ArchiveTable.tsx +203 -0
  605. package/src/components/tasks/KanbanBoard.tsx +264 -0
  606. package/src/components/tasks/TaskCard.tsx +138 -0
  607. package/src/components/tasks/TaskColumn.tsx +81 -0
  608. package/src/components/tasks/TaskDialog.tsx +274 -0
  609. package/src/components/tasks/index.ts +5 -0
  610. package/src/components/tasks/types.ts +43 -0
  611. package/src/components/ui/alert-dialog.tsx +154 -0
  612. package/src/components/ui/alert.tsx +65 -0
  613. package/src/components/ui/badge.tsx +45 -0
  614. package/src/components/ui/button.tsx +58 -0
  615. package/src/components/ui/card.tsx +91 -0
  616. package/src/components/ui/checkbox.tsx +29 -0
  617. package/src/components/ui/collapsible.tsx +31 -0
  618. package/src/components/ui/command.tsx +184 -0
  619. package/src/components/ui/confirm-dialog.tsx +55 -0
  620. package/src/components/ui/dialog.tsx +142 -0
  621. package/src/components/ui/dropdown-menu.tsx +254 -0
  622. package/src/components/ui/input.tsx +20 -0
  623. package/src/components/ui/label.tsx +22 -0
  624. package/src/components/ui/markdown.tsx +100 -0
  625. package/src/components/ui/progress.tsx +27 -0
  626. package/src/components/ui/resizable-sidebar.tsx +156 -0
  627. package/src/components/ui/resizable.tsx +54 -0
  628. package/src/components/ui/right-resizable-sidebar.tsx +158 -0
  629. package/src/components/ui/scroll-area.tsx +64 -0
  630. package/src/components/ui/select.tsx +185 -0
  631. package/src/components/ui/separator.tsx +25 -0
  632. package/src/components/ui/sheet.tsx +136 -0
  633. package/src/components/ui/sidebar.tsx +726 -0
  634. package/src/components/ui/skeleton.tsx +13 -0
  635. package/src/components/ui/slider.tsx +56 -0
  636. package/src/components/ui/switch.tsx +29 -0
  637. package/src/components/ui/table.tsx +113 -0
  638. package/src/components/ui/tabs.tsx +63 -0
  639. package/src/components/ui/textarea.tsx +17 -0
  640. package/src/components/ui/tooltip.tsx +60 -0
  641. package/src/config/api.ts +83 -0
  642. package/src/constants/error-codes.ts +255 -0
  643. package/src/constants/stages.ts +27 -0
  644. package/src/context/ErrorContext.tsx +185 -0
  645. package/src/context/theme-provider.tsx +63 -0
  646. package/src/hooks/use-mobile.tsx +19 -0
  647. package/src/hooks/useAI.ts +206 -0
  648. package/src/hooks/useAgentSession.ts +431 -0
  649. package/src/hooks/useAlerts.ts +935 -0
  650. package/src/hooks/useArchivedChanges.ts +39 -0
  651. package/src/hooks/useAsyncError.ts +45 -0
  652. package/src/hooks/useChangeGit.ts +727 -0
  653. package/src/hooks/useChanges.ts +20 -0
  654. package/src/hooks/useClaude.ts +130 -0
  655. package/src/hooks/useDocs.ts +182 -0
  656. package/src/hooks/useErrorDashboard.ts +243 -0
  657. package/src/hooks/useErrorHandler.ts +150 -0
  658. package/src/hooks/useExecutionHistory.ts +55 -0
  659. package/src/hooks/useFlowChanges.ts +850 -0
  660. package/src/hooks/useFlowItems.ts +205 -0
  661. package/src/hooks/useGit.ts +427 -0
  662. package/src/hooks/useHideCompletedSpecs.ts +15 -0
  663. package/src/hooks/useInstance.ts +40 -0
  664. package/src/hooks/useIntegrations.ts +737 -0
  665. package/src/hooks/useLeannStatus.ts +93 -0
  666. package/src/hooks/useNetworkStatus.ts +167 -0
  667. package/src/hooks/useProjects.ts +353 -0
  668. package/src/hooks/useRemoteServers.ts +383 -0
  669. package/src/hooks/useSSEConnection.ts +346 -0
  670. package/src/hooks/useSpecs.ts +39 -0
  671. package/src/hooks/useSwarm.ts +462 -0
  672. package/src/hooks/useTasks.ts +137 -0
  673. package/src/hooks/useURLSync.ts +122 -0
  674. package/src/hooks/useWebSocket.ts +262 -0
  675. package/src/lib/utils.ts +121 -0
  676. package/src/main.tsx +22 -0
  677. package/src/stores/errorStore.ts +301 -0
  678. package/src/stores/offlineStore.ts +266 -0
  679. package/src/stores/sseStore.ts +247 -0
  680. package/src/stores/useHideCompletedStore.ts +21 -0
  681. package/src/styles/index.css +87 -0
  682. package/src/styles/theme.css +102 -0
  683. package/src/types/ai.ts +191 -0
  684. package/src/types/errors.ts +253 -0
  685. package/src/types/flow.ts +382 -0
  686. package/src/types/index.ts +614 -0
  687. package/src/utils/error-logger.ts +399 -0
  688. package/src/utils/error-statistics.ts +305 -0
  689. package/src/utils/logger.ts +280 -0
  690. package/src/utils/task-routing.ts +795 -0
  691. package/src/vite-env.d.ts +1 -0
  692. package/test-results/.last-run.json +4 -0
  693. package/tmp/check-docker-final.ts +48 -0
  694. package/tmp/check-docker-tasks.ts +58 -0
  695. package/tmp/check-docker-tasks2.ts +48 -0
  696. package/tmp/check-docker-tasks3.ts +42 -0
  697. package/tmp/check-mobile-tasks.ts +57 -0
  698. package/tmp/check-zywiki-tasks.ts +49 -0
  699. package/tmp/sync-mobile.ts +11 -0
  700. package/tmp/sync-zywiki.ts +68 -0
  701. package/tmp/test-docker-parser.ts +15 -0
  702. package/tmp/test-mobile-parser.ts +28 -0
  703. package/tmp/test-parser.ts +27 -0
  704. package/tmp/test-unnumbered.ts +35 -0
  705. package/zyflow.db +0 -0
@@ -0,0 +1,1204 @@
1
+ import { useState, useEffect, useRef, useCallback } from 'react'
2
+ import { Play, Square, X, CheckCircle2, XCircle, Loader2, Terminal, History, Zap, Sparkles, Crown, Users, Settings2, AlertCircle, Lightbulb, Handshake, Trophy, Clock, Percent } from 'lucide-react'
3
+ import {
4
+ Dialog,
5
+ DialogContent,
6
+ DialogDescription,
7
+ DialogHeader,
8
+ DialogTitle,
9
+ } from '@/components/ui/dialog'
10
+ import { Button } from '@/components/ui/button'
11
+ import { Badge } from '@/components/ui/badge'
12
+ import { ScrollArea } from '@/components/ui/scroll-area'
13
+ import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
14
+ import { Slider } from '@/components/ui/slider'
15
+ import { useAI, fetchAIProviders, type AIProviderConfig, type AIMessage } from '@/hooks/useAI'
16
+ import { useSwarm, type SwarmStrategy } from '@/hooks/useSwarm'
17
+ import type { ClaudeModel } from '@/hooks/useClaude'
18
+ import { ExecutionHistoryDialog } from './ExecutionHistoryDialog'
19
+ import { cn } from '@/lib/utils'
20
+ import {
21
+ getTaskRecommendation,
22
+ getTaskTypeInfo,
23
+ type TaskRecommendation
24
+ } from '@/utils/task-routing'
25
+ import type { AIProvider, ConsensusStrategy, ConsensusConfig, ProviderResult } from '@/types/ai'
26
+ import { PROVIDER_ICONS } from '@/types/ai'
27
+ import { Switch } from '@/components/ui/switch'
28
+
29
+ // =============================================
30
+ // 타입 및 상수
31
+ // =============================================
32
+
33
+ type ExecutionMode = 'single' | 'swarm'
34
+
35
+ const MODEL_OPTIONS: { value: ClaudeModel; label: string; description: string; icon: typeof Zap }[] = [
36
+ { value: 'haiku', label: 'Haiku', description: '빠르고 저렴 (단순 태스크)', icon: Zap },
37
+ { value: 'sonnet', label: 'Sonnet', description: '균형 잡힌 성능 (권장)', icon: Sparkles },
38
+ { value: 'opus', label: 'Opus', description: '최고 품질 (복잡한 태스크)', icon: Crown },
39
+ ]
40
+
41
+ const STRATEGY_OPTIONS: { value: SwarmStrategy; label: string; description: string }[] = [
42
+ { value: 'development', label: 'Development', description: '코드 구현 중심 (권장)' },
43
+ { value: 'research', label: 'Research', description: '분석 및 조사 중심' },
44
+ { value: 'testing', label: 'Testing', description: '테스트 및 검증 중심' },
45
+ ]
46
+
47
+ const CONSENSUS_STRATEGY_OPTIONS: { value: ConsensusStrategy; label: string; description: string; icon: string }[] = [
48
+ { value: 'majority', label: '다수결', description: '가장 많이 선택된 결과 채택', icon: '🗳️' },
49
+ { value: 'weighted', label: '가중 투표', description: 'Provider별 신뢰도 기반', icon: '⚖️' },
50
+ { value: 'best-of-n', label: 'Best-of-N', description: 'N개 중 최고 품질 선택', icon: '🏆' },
51
+ { value: 'unanimous', label: '만장일치', description: '모든 AI가 동의해야 함', icon: '🤝' },
52
+ ]
53
+
54
+ interface TaskExecutionDialogProps {
55
+ open: boolean
56
+ onOpenChange: (open: boolean) => void
57
+ changeId: string
58
+ taskId: string
59
+ taskTitle: string
60
+ projectPath?: string
61
+ onComplete?: () => void
62
+ }
63
+
64
+ // =============================================
65
+ // 컴포넌트
66
+ // =============================================
67
+
68
+ export function TaskExecutionDialog({
69
+ open,
70
+ onOpenChange,
71
+ changeId,
72
+ taskId,
73
+ taskTitle,
74
+ projectPath,
75
+ onComplete,
76
+ }: TaskExecutionDialogProps) {
77
+ // 실행 모드 상태
78
+ const [executionMode, setExecutionMode] = useState<ExecutionMode>('single')
79
+
80
+ // 단일 실행 상태 (useAI 기반)
81
+ const ai = useAI()
82
+ const [providers, setProviders] = useState<AIProviderConfig[]>([])
83
+ const [selectedProvider, setSelectedProvider] = useState<AIProvider>('claude')
84
+ const [selectedModel, setSelectedModel] = useState<string>('sonnet')
85
+ const [loadingProviders, setLoadingProviders] = useState(false)
86
+
87
+ // Swarm 실행 상태
88
+ const swarm = useSwarm()
89
+ const [strategy, setStrategy] = useState<SwarmStrategy>('development')
90
+ const [maxAgents, setMaxAgents] = useState(5)
91
+ // v2: Swarm용 Provider 선택
92
+ const [swarmProvider, setSwarmProvider] = useState<AIProvider>('claude')
93
+ const [swarmModel, setSwarmModel] = useState<string>('sonnet')
94
+
95
+ // v2: Consensus 설정
96
+ const [consensusEnabled, setConsensusEnabled] = useState(false)
97
+ const [consensusStrategy, setConsensusStrategy] = useState<ConsensusStrategy>('majority')
98
+ const [consensusProviders, setConsensusProviders] = useState<Set<AIProvider>>(new Set())
99
+ const [consensusThreshold, setConsensusThreshold] = useState(0.7)
100
+
101
+ // v2: 자동 추천
102
+ const [recommendation, setRecommendation] = useState<TaskRecommendation | null>(null)
103
+ const [showRecommendation, setShowRecommendation] = useState(true)
104
+
105
+ // 공통 상태
106
+ const [showHistory, setShowHistory] = useState(false)
107
+ const [hasStarted, setHasStarted] = useState(false)
108
+ const scrollRef = useRef<HTMLDivElement>(null)
109
+
110
+ // 현재 실행 상태 (모드에 따라 다름)
111
+ const currentStatus = executionMode === 'single'
112
+ ? ai.execution.status
113
+ : swarm.execution.status
114
+ const isRunning = currentStatus === 'running'
115
+
116
+ // Provider 목록 로드
117
+ useEffect(() => {
118
+ if (open && providers.length === 0) {
119
+ setLoadingProviders(true)
120
+ fetchAIProviders()
121
+ .then((data) => {
122
+ setProviders(data)
123
+ // 첫 번째 사용 가능한 Provider 선택
124
+ const firstAvailable = data.find(p => p.enabled && p.available)
125
+ if (firstAvailable) {
126
+ setSelectedProvider(firstAvailable.id as AIProvider)
127
+ setSelectedModel(firstAvailable.selectedModel || firstAvailable.availableModels[0] || '')
128
+ // Swarm용 Provider도 설정
129
+ setSwarmProvider(firstAvailable.id as AIProvider)
130
+ setSwarmModel(firstAvailable.selectedModel || firstAvailable.availableModels[0] || '')
131
+ }
132
+
133
+ // v2: 자동 추천 계산
134
+ const availableProviderIds = data
135
+ .filter(p => p.enabled && p.available)
136
+ .map(p => p.id) as AIProvider[]
137
+ const rec = getTaskRecommendation(taskTitle, undefined, availableProviderIds)
138
+ setRecommendation(rec)
139
+
140
+ // 추천에 따른 기본값 설정
141
+ if (rec.mode === 'single') {
142
+ setExecutionMode('single')
143
+ setSelectedProvider(rec.provider)
144
+ setSelectedModel(rec.model)
145
+ } else {
146
+ setExecutionMode('swarm')
147
+ setSwarmProvider(rec.provider)
148
+ setSwarmModel(rec.model)
149
+ if (rec.strategy) setStrategy(rec.strategy)
150
+ if (rec.maxAgents) setMaxAgents(rec.maxAgents)
151
+ }
152
+ })
153
+ .finally(() => setLoadingProviders(false))
154
+ }
155
+ }, [open, providers.length, taskTitle])
156
+
157
+ // 다이얼로그 닫힐 때 상태 초기화
158
+ useEffect(() => {
159
+ if (!open) {
160
+ setHasStarted(false)
161
+ if (ai.execution.status === 'running') {
162
+ ai.stop()
163
+ }
164
+ if (swarm.isRunning) {
165
+ swarm.stop()
166
+ }
167
+ ai.reset()
168
+ swarm.reset()
169
+ }
170
+ }, [open])
171
+
172
+ // 자동 스크롤
173
+ useEffect(() => {
174
+ if (scrollRef.current) {
175
+ scrollRef.current.scrollTop = scrollRef.current.scrollHeight
176
+ }
177
+ }, [ai.execution.messages, swarm.logs])
178
+
179
+ // 완료 시 콜백
180
+ const onCompleteRef = useRef(onComplete)
181
+ onCompleteRef.current = onComplete
182
+
183
+ useEffect(() => {
184
+ if ((ai.execution.status === 'completed' || swarm.execution.status === 'completed') && onCompleteRef.current) {
185
+ onCompleteRef.current()
186
+ }
187
+ }, [ai.execution.status, swarm.execution.status])
188
+
189
+ // Provider 선택 시 모델 자동 설정
190
+ const handleProviderSelect = useCallback((providerId: AIProvider) => {
191
+ setSelectedProvider(providerId)
192
+ const provider = providers.find(p => p.id === providerId)
193
+ if (provider) {
194
+ setSelectedModel(provider.selectedModel || provider.availableModels[0] || '')
195
+ }
196
+ }, [providers])
197
+
198
+ // Swarm용 Provider 선택
199
+ const handleSwarmProviderSelect = useCallback((providerId: AIProvider) => {
200
+ setSwarmProvider(providerId)
201
+ const provider = providers.find(p => p.id === providerId)
202
+ if (provider) {
203
+ setSwarmModel(provider.selectedModel || provider.availableModels[0] || '')
204
+ }
205
+ }, [providers])
206
+
207
+ // 자동 추천 적용
208
+ const applyRecommendation = useCallback(() => {
209
+ if (!recommendation) return
210
+
211
+ if (recommendation.mode === 'single') {
212
+ setExecutionMode('single')
213
+ setSelectedProvider(recommendation.provider)
214
+ setSelectedModel(recommendation.model)
215
+ } else {
216
+ setExecutionMode('swarm')
217
+ setSwarmProvider(recommendation.provider)
218
+ setSwarmModel(recommendation.model)
219
+ if (recommendation.strategy) setStrategy(recommendation.strategy)
220
+ if (recommendation.maxAgents) setMaxAgents(recommendation.maxAgents)
221
+ }
222
+ }, [recommendation])
223
+
224
+ // Consensus Provider 토글
225
+ const handleToggleConsensusProvider = useCallback((providerId: AIProvider) => {
226
+ setConsensusProviders(prev => {
227
+ const next = new Set(prev)
228
+ if (next.has(providerId)) {
229
+ next.delete(providerId)
230
+ } else {
231
+ next.add(providerId)
232
+ }
233
+ return next
234
+ })
235
+ }, [])
236
+
237
+ // 실행 핸들러
238
+ const handleStart = async () => {
239
+ setHasStarted(true)
240
+
241
+ if (executionMode === 'single') {
242
+ await ai.execute({
243
+ provider: selectedProvider,
244
+ model: selectedModel,
245
+ changeId,
246
+ taskId,
247
+ taskTitle,
248
+ })
249
+ } else {
250
+ // Consensus 설정 구성
251
+ const consensusConfig: ConsensusConfig | undefined = consensusEnabled && consensusProviders.size >= 2
252
+ ? {
253
+ strategy: consensusStrategy,
254
+ providers: Array.from(consensusProviders) as AIProvider[],
255
+ threshold: consensusThreshold,
256
+ timeout: 5 * 60 * 1000, // 5분
257
+ }
258
+ : undefined
259
+
260
+ await swarm.execute({
261
+ projectPath: projectPath || process.cwd?.() || '',
262
+ changeId,
263
+ taskId,
264
+ mode: 'single',
265
+ strategy,
266
+ maxAgents,
267
+ provider: swarmProvider,
268
+ model: swarmModel,
269
+ consensus: consensusConfig,
270
+ })
271
+ }
272
+ }
273
+
274
+ // 중지 핸들러
275
+ const handleStop = async () => {
276
+ if (executionMode === 'single') {
277
+ await ai.stop()
278
+ } else {
279
+ await swarm.stop()
280
+ }
281
+ }
282
+
283
+ const handleStopAndClose = async () => {
284
+ await handleStop()
285
+ onOpenChange(false)
286
+ }
287
+
288
+ // 재실행 핸들러
289
+ const handleRetry = () => {
290
+ if (executionMode === 'single') {
291
+ ai.reset()
292
+ } else {
293
+ swarm.reset()
294
+ }
295
+ setHasStarted(true)
296
+ handleStart()
297
+ }
298
+
299
+ // 다이얼로그 닫기 제어
300
+ const handleOpenChange = (newOpen: boolean) => {
301
+ if (isRunning && !newOpen) {
302
+ return // 실행 중에는 닫기 방지
303
+ }
304
+ onOpenChange(newOpen)
305
+ }
306
+
307
+ // 메시지 렌더링 (단일 실행)
308
+ const renderAIMessage = (msg: AIMessage, index: number) => {
309
+ if (msg.type === 'start') {
310
+ return (
311
+ <div key={index} className="flex items-center gap-2 text-blue-500 text-sm">
312
+ <Play className="h-3 w-3" />
313
+ <span>실행 시작 ({msg.provider} / {msg.model})</span>
314
+ </div>
315
+ )
316
+ }
317
+
318
+ if (msg.type === 'output' && msg.data) {
319
+ const { data } = msg
320
+
321
+ // Assistant message
322
+ if (data.type === 'assistant' && data.message?.content) {
323
+ const content = data.message.content
324
+ const textContent = Array.isArray(content)
325
+ ? content
326
+ .filter((c: { type: string }) => c.type === 'text')
327
+ .map((c: { text: string }) => c.text)
328
+ .join('\n')
329
+ : typeof content === 'string'
330
+ ? content
331
+ : JSON.stringify(content)
332
+
333
+ if (!textContent) return null
334
+
335
+ return (
336
+ <div key={index} className="bg-muted/50 rounded p-2 text-xs leading-relaxed whitespace-pre-wrap">
337
+ {textContent}
338
+ </div>
339
+ )
340
+ }
341
+
342
+ // Tool use
343
+ if (data.type === 'tool_use') {
344
+ return (
345
+ <div key={index} className="border rounded p-2 text-xs">
346
+ <div className="flex items-center gap-1.5 text-muted-foreground mb-1">
347
+ <Terminal className="h-3 w-3 flex-shrink-0" />
348
+ <span className="font-mono truncate">{data.name}</span>
349
+ </div>
350
+ {data.input && (
351
+ <pre className="text-[10px] bg-muted p-1.5 rounded overflow-x-auto max-h-32">
352
+ {JSON.stringify(data.input, null, 2)}
353
+ </pre>
354
+ )}
355
+ </div>
356
+ )
357
+ }
358
+
359
+ // Tool result
360
+ if (data.type === 'tool_result') {
361
+ return (
362
+ <div key={index} className="border-l-2 border-green-500/50 pl-3 text-xs text-muted-foreground">
363
+ <span>Tool 결과 수신</span>
364
+ </div>
365
+ )
366
+ }
367
+ }
368
+
369
+ if (msg.type === 'text') {
370
+ return null
371
+ }
372
+
373
+ if (msg.type === 'stderr' && msg.content) {
374
+ return (
375
+ <div key={index} className="text-sm text-orange-500 font-mono">
376
+ {msg.content}
377
+ </div>
378
+ )
379
+ }
380
+
381
+ if (msg.type === 'error') {
382
+ return (
383
+ <div key={index} className="flex items-center gap-2 text-red-500 text-sm">
384
+ <XCircle className="h-3 w-3" />
385
+ <span>{msg.message || '오류 발생'}</span>
386
+ </div>
387
+ )
388
+ }
389
+
390
+ if (msg.type === 'complete') {
391
+ return (
392
+ <div
393
+ key={index}
394
+ className={cn(
395
+ 'flex items-center gap-2 text-sm mt-2',
396
+ msg.status === 'completed' ? 'text-green-500' : 'text-red-500'
397
+ )}
398
+ >
399
+ {msg.status === 'completed' ? (
400
+ <>
401
+ <CheckCircle2 className="h-4 w-4" />
402
+ <span>실행 완료</span>
403
+ </>
404
+ ) : (
405
+ <>
406
+ <XCircle className="h-4 w-4" />
407
+ <span>실행 실패 (코드: {msg.exitCode})</span>
408
+ </>
409
+ )}
410
+ </div>
411
+ )
412
+ }
413
+
414
+ return null
415
+ }
416
+
417
+ // 상태 배지
418
+ const getStatusBadge = () => {
419
+ const status = executionMode === 'single' ? ai.execution.status : swarm.execution.status
420
+
421
+ switch (status) {
422
+ case 'running':
423
+ return (
424
+ <Badge variant="default" className="bg-blue-500">
425
+ <Loader2 className="h-3 w-3 mr-1 animate-spin" />
426
+ 실행 중
427
+ </Badge>
428
+ )
429
+ case 'completed':
430
+ return (
431
+ <Badge variant="default" className="bg-green-500">
432
+ <CheckCircle2 className="h-3 w-3 mr-1" />
433
+ 완료
434
+ </Badge>
435
+ )
436
+ case 'error':
437
+ case 'failed':
438
+ return (
439
+ <Badge variant="destructive">
440
+ <XCircle className="h-3 w-3 mr-1" />
441
+ 오류
442
+ </Badge>
443
+ )
444
+ default:
445
+ return null
446
+ }
447
+ }
448
+
449
+ // Provider 카드 렌더링
450
+ const renderProviderCard = (provider: AIProviderConfig) => {
451
+ const isSelected = selectedProvider === provider.id
452
+ const isDisabled = !provider.available || !provider.enabled
453
+
454
+ return (
455
+ <button
456
+ key={provider.id}
457
+ onClick={() => !isDisabled && handleProviderSelect(provider.id)}
458
+ disabled={isDisabled}
459
+ className={cn(
460
+ 'w-full p-3 rounded-lg border-2 text-left transition-all',
461
+ isDisabled && 'opacity-50 cursor-not-allowed',
462
+ isSelected && !isDisabled
463
+ ? 'border-primary bg-primary/5'
464
+ : 'border-muted hover:border-muted-foreground/50'
465
+ )}
466
+ >
467
+ <div className="flex items-center gap-3">
468
+ <span className="text-xl">{provider.icon}</span>
469
+ <div className="flex-1 min-w-0">
470
+ <div className="font-medium flex items-center gap-2">
471
+ {provider.name}
472
+ {!provider.available && (
473
+ <Badge variant="outline" className="text-[10px] py-0">미설치</Badge>
474
+ )}
475
+ </div>
476
+ {provider.availableModels.length > 0 && (
477
+ <div className="text-xs text-muted-foreground truncate">
478
+ {provider.availableModels.slice(0, 3).join(', ')}
479
+ </div>
480
+ )}
481
+ </div>
482
+ {isSelected && provider.available && (
483
+ <CheckCircle2 className="h-5 w-5 text-primary flex-shrink-0" />
484
+ )}
485
+ </div>
486
+ </button>
487
+ )
488
+ }
489
+
490
+ // 모델 선택 렌더링
491
+ const renderModelSelection = () => {
492
+ const provider = providers.find(p => p.id === selectedProvider)
493
+ if (!provider || provider.availableModels.length === 0) return null
494
+
495
+ // Claude의 경우 기존 UI 사용
496
+ if (selectedProvider === 'claude') {
497
+ return (
498
+ <div className="space-y-2 mt-4">
499
+ <label className="text-sm font-medium">모델 선택</label>
500
+ <div className="space-y-2">
501
+ {MODEL_OPTIONS.map((option) => {
502
+ const Icon = option.icon
503
+ const isSelected = selectedModel === option.value
504
+ return (
505
+ <button
506
+ key={option.value}
507
+ onClick={() => setSelectedModel(option.value)}
508
+ className={cn(
509
+ 'w-full p-3 rounded-lg border-2 text-left transition-all',
510
+ isSelected
511
+ ? 'border-primary bg-primary/5'
512
+ : 'border-muted hover:border-muted-foreground/50'
513
+ )}
514
+ >
515
+ <div className="flex items-center gap-3">
516
+ <Icon className={cn('h-4 w-4', isSelected ? 'text-primary' : 'text-muted-foreground')} />
517
+ <div className="flex-1">
518
+ <div className="font-medium text-sm">{option.label}</div>
519
+ <div className="text-xs text-muted-foreground">{option.description}</div>
520
+ </div>
521
+ {isSelected && <CheckCircle2 className="h-4 w-4 text-primary" />}
522
+ </div>
523
+ </button>
524
+ )
525
+ })}
526
+ </div>
527
+ </div>
528
+ )
529
+ }
530
+
531
+ // 다른 Provider의 경우 드롭다운 형식
532
+ return (
533
+ <div className="space-y-2 mt-4">
534
+ <label className="text-sm font-medium">모델 선택</label>
535
+ <div className="space-y-2">
536
+ {provider.availableModels.map((model) => {
537
+ const isSelected = selectedModel === model
538
+ return (
539
+ <button
540
+ key={model}
541
+ onClick={() => setSelectedModel(model)}
542
+ className={cn(
543
+ 'w-full p-2 rounded-lg border text-left transition-all text-sm',
544
+ isSelected
545
+ ? 'border-primary bg-primary/5'
546
+ : 'border-muted hover:border-muted-foreground/50'
547
+ )}
548
+ >
549
+ <div className="flex items-center justify-between">
550
+ <span className="font-mono">{model}</span>
551
+ {isSelected && <CheckCircle2 className="h-4 w-4 text-primary" />}
552
+ </div>
553
+ </button>
554
+ )
555
+ })}
556
+ </div>
557
+ </div>
558
+ )
559
+ }
560
+
561
+ return (
562
+ <Dialog open={open} onOpenChange={handleOpenChange}>
563
+ <DialogContent
564
+ className="max-w-4xl max-h-[85vh] flex flex-col overflow-hidden"
565
+ showCloseButton={!isRunning}
566
+ onEscapeKeyDown={(e) => {
567
+ if (isRunning) e.preventDefault()
568
+ }}
569
+ onPointerDownOutside={(e) => {
570
+ if (isRunning) e.preventDefault()
571
+ }}
572
+ onInteractOutside={(e) => {
573
+ if (isRunning) e.preventDefault()
574
+ }}
575
+ >
576
+ <DialogHeader>
577
+ <div className="flex items-center justify-between">
578
+ <DialogTitle className="flex items-center gap-2">
579
+ <Terminal className="h-5 w-5" />
580
+ 태스크 실행
581
+ </DialogTitle>
582
+ {getStatusBadge()}
583
+ </div>
584
+ <DialogDescription className="text-left">
585
+ <span className="font-mono text-xs">[{taskId}]</span> {taskTitle}
586
+ </DialogDescription>
587
+ </DialogHeader>
588
+
589
+ {/* v2: 자동 추천 배너 */}
590
+ {!hasStarted && currentStatus === 'idle' && recommendation && showRecommendation && (
591
+ <div className="bg-amber-50 dark:bg-amber-950/30 border border-amber-200 dark:border-amber-800 rounded-lg p-3 mb-2">
592
+ <div className="flex items-start gap-2">
593
+ <Lightbulb className="h-4 w-4 text-amber-600 dark:text-amber-400 mt-0.5 flex-shrink-0" />
594
+ <div className="flex-1 min-w-0">
595
+ <div className="flex items-center justify-between gap-2">
596
+ <span className="text-sm font-medium text-amber-800 dark:text-amber-200">
597
+ 자동 추천 ({getTaskTypeInfo(taskTitle).emoji} {getTaskTypeInfo(taskTitle).label})
598
+ </span>
599
+ <button
600
+ onClick={() => setShowRecommendation(false)}
601
+ className="text-amber-600 dark:text-amber-400 hover:text-amber-800 dark:hover:text-amber-200 text-xs"
602
+ >
603
+ 숨기기
604
+ </button>
605
+ </div>
606
+ <p className="text-xs text-amber-700 dark:text-amber-300 mt-1">
607
+ {recommendation.reason}
608
+ </p>
609
+ <div className="flex items-center gap-2 mt-2">
610
+ <Badge variant="outline" className="text-xs border-amber-300 dark:border-amber-700">
611
+ {recommendation.mode === 'single' ? '단일 실행' : 'Swarm 실행'}
612
+ </Badge>
613
+ <Badge variant="outline" className="text-xs border-amber-300 dark:border-amber-700">
614
+ {recommendation.provider} / {recommendation.model || 'default'}
615
+ </Badge>
616
+ {recommendation.strategy && (
617
+ <Badge variant="outline" className="text-xs border-amber-300 dark:border-amber-700">
618
+ {recommendation.strategy}
619
+ </Badge>
620
+ )}
621
+ <Button
622
+ size="sm"
623
+ variant="outline"
624
+ onClick={applyRecommendation}
625
+ className="ml-auto h-6 text-xs border-amber-300 dark:border-amber-700 text-amber-700 dark:text-amber-300 hover:bg-amber-100 dark:hover:bg-amber-900"
626
+ >
627
+ 적용
628
+ </Button>
629
+ </div>
630
+ </div>
631
+ </div>
632
+ </div>
633
+ )}
634
+
635
+ {/* 실행 모드 선택 (실행 전) */}
636
+ {!hasStarted && currentStatus === 'idle' && (
637
+ <Tabs value={executionMode} onValueChange={(v) => setExecutionMode(v as ExecutionMode)} className="flex-1 flex flex-col">
638
+ <TabsList className="grid w-full grid-cols-2">
639
+ <TabsTrigger value="single" className="flex items-center gap-2">
640
+ <Zap className="h-4 w-4" />
641
+ 단일 실행
642
+ </TabsTrigger>
643
+ <TabsTrigger value="swarm" className="flex items-center gap-2">
644
+ <Users className="h-4 w-4" />
645
+ Swarm 실행
646
+ </TabsTrigger>
647
+ </TabsList>
648
+
649
+ {/* 단일 실행 설정 */}
650
+ <TabsContent value="single" className="flex-1 mt-4">
651
+ <ScrollArea className="h-[40vh]">
652
+ <div className="space-y-4 pr-4">
653
+ <div>
654
+ <label className="text-sm font-medium mb-2 block">Provider 선택</label>
655
+ {loadingProviders ? (
656
+ <div className="flex items-center gap-2 text-muted-foreground py-4">
657
+ <Loader2 className="h-4 w-4 animate-spin" />
658
+ <span>Provider 목록 로드 중...</span>
659
+ </div>
660
+ ) : providers.length === 0 ? (
661
+ <div className="flex items-center gap-2 text-muted-foreground py-4">
662
+ <AlertCircle className="h-4 w-4" />
663
+ <span>사용 가능한 Provider가 없습니다</span>
664
+ </div>
665
+ ) : (
666
+ <div className="grid gap-2">
667
+ {providers.filter(p => p.enabled).map(renderProviderCard)}
668
+ </div>
669
+ )}
670
+ </div>
671
+
672
+ {selectedProvider && renderModelSelection()}
673
+ </div>
674
+ </ScrollArea>
675
+ </TabsContent>
676
+
677
+ {/* Swarm 실행 설정 */}
678
+ <TabsContent value="swarm" className="flex-1 mt-4">
679
+ <ScrollArea className="h-[40vh]">
680
+ <div className="space-y-6 pr-4">
681
+ {/* v2: Swarm Provider 선택 */}
682
+ <div>
683
+ <label className="text-sm font-medium mb-2 block">Provider 선택 (v2)</label>
684
+ {loadingProviders ? (
685
+ <div className="flex items-center gap-2 text-muted-foreground py-2">
686
+ <Loader2 className="h-4 w-4 animate-spin" />
687
+ <span>Provider 목록 로드 중...</span>
688
+ </div>
689
+ ) : (
690
+ <div className="grid gap-2">
691
+ {providers.filter(p => p.enabled).map((provider) => {
692
+ const isSelected = swarmProvider === provider.id
693
+ const isDisabled = !provider.available
694
+ return (
695
+ <button
696
+ key={provider.id}
697
+ onClick={() => !isDisabled && handleSwarmProviderSelect(provider.id)}
698
+ disabled={isDisabled}
699
+ className={cn(
700
+ 'w-full p-2 rounded-lg border text-left transition-all',
701
+ isDisabled && 'opacity-50 cursor-not-allowed',
702
+ isSelected && !isDisabled
703
+ ? 'border-primary bg-primary/5'
704
+ : 'border-muted hover:border-muted-foreground/50'
705
+ )}
706
+ >
707
+ <div className="flex items-center gap-2">
708
+ <span>{provider.icon}</span>
709
+ <span className="flex-1 text-sm">{provider.name}</span>
710
+ {!provider.available && (
711
+ <Badge variant="outline" className="text-[10px] py-0">미설치</Badge>
712
+ )}
713
+ {isSelected && provider.available && (
714
+ <CheckCircle2 className="h-4 w-4 text-primary" />
715
+ )}
716
+ </div>
717
+ </button>
718
+ )
719
+ })}
720
+ </div>
721
+ )}
722
+ </div>
723
+
724
+ {/* Swarm용 모델 선택 */}
725
+ {swarmProvider && (() => {
726
+ const provider = providers.find(p => p.id === swarmProvider)
727
+ if (!provider || provider.availableModels.length === 0) return null
728
+ return (
729
+ <div>
730
+ <label className="text-sm font-medium mb-2 block">모델 선택</label>
731
+ <div className="grid gap-1">
732
+ {provider.availableModels.map((model) => {
733
+ const isSelected = swarmModel === model
734
+ return (
735
+ <button
736
+ key={model}
737
+ onClick={() => setSwarmModel(model)}
738
+ className={cn(
739
+ 'w-full p-2 rounded border text-left text-sm transition-all',
740
+ isSelected
741
+ ? 'border-primary bg-primary/5'
742
+ : 'border-muted hover:border-muted-foreground/50'
743
+ )}
744
+ >
745
+ <div className="flex items-center justify-between">
746
+ <span className="font-mono text-xs">{model}</span>
747
+ {isSelected && <CheckCircle2 className="h-3 w-3 text-primary" />}
748
+ </div>
749
+ </button>
750
+ )
751
+ })}
752
+ </div>
753
+ </div>
754
+ )
755
+ })()}
756
+
757
+ <div>
758
+ <label className="text-sm font-medium mb-2 block">Strategy 선택</label>
759
+ <div className="grid gap-2">
760
+ {STRATEGY_OPTIONS.map((option) => {
761
+ const isSelected = strategy === option.value
762
+ return (
763
+ <button
764
+ key={option.value}
765
+ onClick={() => setStrategy(option.value)}
766
+ className={cn(
767
+ 'w-full p-3 rounded-lg border-2 text-left transition-all',
768
+ isSelected
769
+ ? 'border-primary bg-primary/5'
770
+ : 'border-muted hover:border-muted-foreground/50'
771
+ )}
772
+ >
773
+ <div className="flex items-center justify-between">
774
+ <div>
775
+ <div className="font-medium">{option.label}</div>
776
+ <div className="text-xs text-muted-foreground">{option.description}</div>
777
+ </div>
778
+ {isSelected && <CheckCircle2 className="h-5 w-5 text-primary" />}
779
+ </div>
780
+ </button>
781
+ )
782
+ })}
783
+ </div>
784
+ </div>
785
+
786
+ <div>
787
+ <label className="text-sm font-medium mb-2 block flex items-center justify-between">
788
+ <span>최대 에이전트 수</span>
789
+ <span className="text-muted-foreground">{maxAgents}</span>
790
+ </label>
791
+ <Slider
792
+ value={[maxAgents]}
793
+ onValueChange={([value]: number[]) => setMaxAgents(value)}
794
+ min={1}
795
+ max={10}
796
+ step={1}
797
+ className="mt-2"
798
+ />
799
+ <div className="flex justify-between text-xs text-muted-foreground mt-1">
800
+ <span>1 (빠름)</span>
801
+ <span>10 (병렬)</span>
802
+ </div>
803
+ </div>
804
+
805
+ {/* v2: Consensus 설정 섹션 */}
806
+ <div className="border rounded-lg p-4">
807
+ <div className="flex items-center justify-between mb-3">
808
+ <div className="flex items-center gap-2">
809
+ <Handshake className="h-4 w-4 text-muted-foreground" />
810
+ <span className="text-sm font-medium">다중 AI 합의 (Consensus)</span>
811
+ </div>
812
+ <Switch
813
+ checked={consensusEnabled}
814
+ onCheckedChange={setConsensusEnabled}
815
+ />
816
+ </div>
817
+
818
+ {consensusEnabled && (
819
+ <div className="space-y-4 pt-2 border-t">
820
+ {/* Consensus Provider 선택 */}
821
+ <div>
822
+ <label className="text-xs font-medium mb-2 block text-muted-foreground">
823
+ 합의에 참여할 Provider 선택 (최소 2개)
824
+ </label>
825
+ <div className="grid grid-cols-2 gap-2">
826
+ {providers.filter(p => p.enabled && p.available).map((provider) => {
827
+ const isSelected = consensusProviders.has(provider.id)
828
+ return (
829
+ <button
830
+ key={provider.id}
831
+ onClick={() => handleToggleConsensusProvider(provider.id)}
832
+ className={cn(
833
+ 'p-2 rounded border text-left text-xs transition-all',
834
+ isSelected
835
+ ? 'border-purple-500 bg-purple-50 dark:bg-purple-950/30'
836
+ : 'border-muted hover:border-muted-foreground/50'
837
+ )}
838
+ >
839
+ <div className="flex items-center gap-2">
840
+ <span>{provider.icon}</span>
841
+ <span className="flex-1">{provider.name}</span>
842
+ {isSelected && <CheckCircle2 className="h-3 w-3 text-purple-500" />}
843
+ </div>
844
+ </button>
845
+ )
846
+ })}
847
+ </div>
848
+ {consensusProviders.size < 2 && (
849
+ <p className="text-xs text-amber-600 dark:text-amber-400 mt-1">
850
+ Consensus를 사용하려면 최소 2개의 Provider가 필요합니다
851
+ </p>
852
+ )}
853
+ </div>
854
+
855
+ {/* Consensus 전략 */}
856
+ <div>
857
+ <label className="text-xs font-medium mb-2 block text-muted-foreground">합의 전략</label>
858
+ <div className="grid grid-cols-2 gap-2">
859
+ {CONSENSUS_STRATEGY_OPTIONS.map((option) => {
860
+ const isSelected = consensusStrategy === option.value
861
+ return (
862
+ <button
863
+ key={option.value}
864
+ onClick={() => setConsensusStrategy(option.value)}
865
+ className={cn(
866
+ 'p-2 rounded border text-left text-xs transition-all',
867
+ isSelected
868
+ ? 'border-purple-500 bg-purple-50 dark:bg-purple-950/30'
869
+ : 'border-muted hover:border-muted-foreground/50'
870
+ )}
871
+ >
872
+ <div className="flex items-center gap-2">
873
+ <span>{option.icon}</span>
874
+ <div className="flex-1">
875
+ <div className="font-medium">{option.label}</div>
876
+ <div className="text-[10px] text-muted-foreground">{option.description}</div>
877
+ </div>
878
+ {isSelected && <CheckCircle2 className="h-3 w-3 text-purple-500" />}
879
+ </div>
880
+ </button>
881
+ )
882
+ })}
883
+ </div>
884
+ </div>
885
+
886
+ {/* 합의 임계값 */}
887
+ <div>
888
+ <label className="text-xs font-medium mb-2 block flex items-center justify-between text-muted-foreground">
889
+ <span>합의 임계값</span>
890
+ <span className="text-foreground">{Math.round(consensusThreshold * 100)}%</span>
891
+ </label>
892
+ <Slider
893
+ value={[consensusThreshold * 100]}
894
+ onValueChange={([value]) => setConsensusThreshold(value / 100)}
895
+ min={50}
896
+ max={100}
897
+ step={5}
898
+ />
899
+ <div className="flex justify-between text-[10px] text-muted-foreground mt-1">
900
+ <span>50% (낮음)</span>
901
+ <span>100% (엄격)</span>
902
+ </div>
903
+ </div>
904
+ </div>
905
+ )}
906
+ </div>
907
+
908
+ <div className="bg-muted/50 rounded-lg p-3 text-sm">
909
+ <div className="flex items-center gap-2 text-muted-foreground mb-1">
910
+ <Settings2 className="h-4 w-4" />
911
+ <span className="font-medium">Swarm 설정 요약</span>
912
+ </div>
913
+ <ul className="text-xs space-y-1 text-muted-foreground">
914
+ <li>Provider: <span className="text-foreground">{providers.find(p => p.id === swarmProvider)?.name || swarmProvider}</span></li>
915
+ <li>Model: <span className="text-foreground">{swarmModel}</span></li>
916
+ <li>Strategy: <span className="text-foreground">{strategy}</span></li>
917
+ <li>Max Agents: <span className="text-foreground">{maxAgents}</span></li>
918
+ <li>Mode: <span className="text-foreground">single task</span></li>
919
+ {consensusEnabled && consensusProviders.size >= 2 && (
920
+ <li className="text-purple-600 dark:text-purple-400">
921
+ Consensus: <span className="text-foreground">{consensusStrategy} ({consensusProviders.size} providers)</span>
922
+ </li>
923
+ )}
924
+ </ul>
925
+ </div>
926
+ </div>
927
+ </ScrollArea>
928
+ </TabsContent>
929
+ </Tabs>
930
+ )}
931
+
932
+ {/* 실행 로그 화면 (실행 중/후) */}
933
+ {(hasStarted || currentStatus !== 'idle') && (
934
+ <ScrollArea className="flex-1 min-h-0 h-[50vh] rounded-lg border bg-background/50 p-3">
935
+ <div ref={scrollRef} className="space-y-2 pr-4">
936
+ {/* 실행 정보 표시 */}
937
+ <div className="flex items-center gap-2 text-xs text-muted-foreground mb-2 pb-2 border-b">
938
+ {executionMode === 'single' ? (
939
+ <>
940
+ <span className="text-lg">{providers.find(p => p.id === selectedProvider)?.icon || '🤖'}</span>
941
+ <span>
942
+ {providers.find(p => p.id === selectedProvider)?.name || selectedProvider}
943
+ {selectedModel && ` / ${selectedModel}`}
944
+ </span>
945
+ </>
946
+ ) : (
947
+ <>
948
+ <span className="text-lg">{providers.find(p => p.id === swarmProvider)?.icon || '🐝'}</span>
949
+ <span>Swarm ({strategy}) / {providers.find(p => p.id === swarmProvider)?.name || swarmProvider} / {maxAgents} agents</span>
950
+ </>
951
+ )}
952
+ </div>
953
+
954
+ {/* 단일 실행 로그 */}
955
+ {executionMode === 'single' && (
956
+ <>
957
+ {ai.execution.messages.map((msg, i) => renderAIMessage(msg, i))}
958
+
959
+ {ai.execution.status === 'running' && ai.execution.messages.length === 0 && (
960
+ <div className="flex items-center gap-2 text-muted-foreground">
961
+ <Loader2 className="h-4 w-4 animate-spin" />
962
+ <span>AI 실행 준비 중...</span>
963
+ </div>
964
+ )}
965
+
966
+ {ai.execution.error && ai.execution.status === 'error' && (
967
+ <div className="bg-red-500/10 border border-red-500/20 rounded-lg p-3 text-sm text-red-500">
968
+ {ai.execution.error}
969
+ </div>
970
+ )}
971
+ </>
972
+ )}
973
+
974
+ {/* Swarm 실행 로그 */}
975
+ {executionMode === 'swarm' && (
976
+ <>
977
+ {(swarm.logs || []).map((log, i) => (
978
+ <div key={i} className="text-xs">
979
+ <span className="text-muted-foreground">
980
+ [{new Date(log.timestamp).toLocaleTimeString()}]
981
+ </span>{' '}
982
+ <span className={cn(
983
+ log.type === 'error' && 'text-red-500',
984
+ log.type === 'assistant' && 'text-blue-500',
985
+ log.type === 'tool_use' && 'text-yellow-500',
986
+ )}>
987
+ {log.content}
988
+ </span>
989
+ </div>
990
+ ))}
991
+
992
+ {swarm.isRunning && (swarm.logs?.length ?? 0) === 0 && (
993
+ <div className="flex items-center gap-2 text-muted-foreground">
994
+ <Loader2 className="h-4 w-4 animate-spin" />
995
+ <span>Swarm 실행 준비 중...</span>
996
+ </div>
997
+ )}
998
+
999
+ {swarm.execution.progress > 0 && (
1000
+ <div className="mt-2 pt-2 border-t">
1001
+ <div className="flex items-center justify-between text-xs mb-1">
1002
+ <span>진행률</span>
1003
+ <span>{swarm.execution.progress}%</span>
1004
+ </div>
1005
+ <div className="h-2 bg-muted rounded-full overflow-hidden">
1006
+ <div
1007
+ className="h-full bg-primary transition-all duration-300"
1008
+ style={{ width: `${swarm.execution.progress}%` }}
1009
+ />
1010
+ </div>
1011
+ </div>
1012
+ )}
1013
+
1014
+ {swarm.error && swarm.execution.status === 'failed' && (
1015
+ <div className="bg-red-500/10 border border-red-500/20 rounded-lg p-3 text-sm text-red-500">
1016
+ {swarm.error}
1017
+ </div>
1018
+ )}
1019
+
1020
+ {/* Consensus 결과 표시 */}
1021
+ {swarm.execution.consensusResult && (
1022
+ <div className="mt-4 pt-4 border-t space-y-3">
1023
+ <div className="flex items-center gap-2">
1024
+ <Handshake className="h-4 w-4 text-purple-500" />
1025
+ <span className="text-sm font-medium">Consensus 결과</span>
1026
+ <Badge
1027
+ variant={swarm.execution.consensusResult.success ? 'default' : 'destructive'}
1028
+ className={swarm.execution.consensusResult.success ? 'bg-green-500' : ''}
1029
+ >
1030
+ {swarm.execution.consensusResult.success ? '합의 성공' : '합의 실패'}
1031
+ </Badge>
1032
+ </div>
1033
+
1034
+ {/* 합의 요약 */}
1035
+ <div className="grid grid-cols-3 gap-2 text-xs">
1036
+ <div className="bg-muted/50 rounded p-2 text-center">
1037
+ <div className="flex items-center justify-center gap-1 text-muted-foreground mb-1">
1038
+ <Percent className="h-3 w-3" />
1039
+ <span>합의율</span>
1040
+ </div>
1041
+ <span className="font-medium text-foreground">
1042
+ {Math.round(swarm.execution.consensusResult.agreement * 100)}%
1043
+ </span>
1044
+ </div>
1045
+ <div className="bg-muted/50 rounded p-2 text-center">
1046
+ <div className="flex items-center justify-center gap-1 text-muted-foreground mb-1">
1047
+ <Trophy className="h-3 w-3" />
1048
+ <span>신뢰도</span>
1049
+ </div>
1050
+ <span className="font-medium text-foreground">
1051
+ {Math.round(swarm.execution.consensusResult.confidence * 100)}%
1052
+ </span>
1053
+ </div>
1054
+ <div className="bg-muted/50 rounded p-2 text-center">
1055
+ <div className="flex items-center justify-center gap-1 text-muted-foreground mb-1">
1056
+ <Clock className="h-3 w-3" />
1057
+ <span>평균 시간</span>
1058
+ </div>
1059
+ <span className="font-medium text-foreground">
1060
+ {(swarm.execution.consensusResult.metadata.averageDuration / 1000).toFixed(1)}s
1061
+ </span>
1062
+ </div>
1063
+ </div>
1064
+
1065
+ {/* Provider별 결과 */}
1066
+ <div className="space-y-2">
1067
+ <span className="text-xs text-muted-foreground">Provider별 결과</span>
1068
+ {swarm.execution.consensusResult.providerResults.map((result: ProviderResult, i: number) => {
1069
+ const isWinner = result.output === swarm.execution.consensusResult?.finalOutput
1070
+ return (
1071
+ <div
1072
+ key={i}
1073
+ className={cn(
1074
+ 'border rounded-lg p-2 text-xs',
1075
+ isWinner && 'border-purple-500 bg-purple-50 dark:bg-purple-950/30',
1076
+ !result.success && 'border-red-300 bg-red-50 dark:bg-red-950/30'
1077
+ )}
1078
+ >
1079
+ <div className="flex items-center justify-between mb-1">
1080
+ <div className="flex items-center gap-2">
1081
+ <span>{PROVIDER_ICONS[result.provider] || '🤖'}</span>
1082
+ <span className="font-medium">{result.provider}</span>
1083
+ {result.model && (
1084
+ <span className="text-muted-foreground">/ {result.model}</span>
1085
+ )}
1086
+ {isWinner && (
1087
+ <Badge className="bg-purple-500 text-[10px] px-1 py-0">
1088
+ <Trophy className="h-2.5 w-2.5 mr-0.5" />
1089
+ 채택
1090
+ </Badge>
1091
+ )}
1092
+ </div>
1093
+ <div className="flex items-center gap-2">
1094
+ {result.confidence !== undefined && (
1095
+ <span className="text-muted-foreground">
1096
+ {Math.round(result.confidence * 100)}%
1097
+ </span>
1098
+ )}
1099
+ <span className="text-muted-foreground">
1100
+ {(result.duration / 1000).toFixed(1)}s
1101
+ </span>
1102
+ {result.success ? (
1103
+ <CheckCircle2 className="h-3 w-3 text-green-500" />
1104
+ ) : (
1105
+ <XCircle className="h-3 w-3 text-red-500" />
1106
+ )}
1107
+ </div>
1108
+ </div>
1109
+ {result.error && (
1110
+ <div className="text-red-500 text-[10px] mt-1">
1111
+ 오류: {result.error}
1112
+ </div>
1113
+ )}
1114
+ {result.success && result.output && (
1115
+ <div className="mt-1 pt-1 border-t text-[10px] text-muted-foreground max-h-20 overflow-y-auto">
1116
+ <pre className="whitespace-pre-wrap font-mono">
1117
+ {result.output.length > 200
1118
+ ? `${result.output.substring(0, 200)}...`
1119
+ : result.output}
1120
+ </pre>
1121
+ </div>
1122
+ )}
1123
+ </div>
1124
+ )
1125
+ })}
1126
+ </div>
1127
+
1128
+ {/* 전략 정보 */}
1129
+ <div className="text-xs text-muted-foreground">
1130
+ 전략: <span className="text-foreground font-medium">{swarm.execution.consensusResult.strategy}</span>
1131
+ {' | '}
1132
+ 성공: <span className="text-foreground">{swarm.execution.consensusResult.metadata.successfulProviders}/{swarm.execution.consensusResult.metadata.totalProviders}</span>
1133
+ </div>
1134
+ </div>
1135
+ )}
1136
+ </>
1137
+ )}
1138
+ </div>
1139
+ </ScrollArea>
1140
+ )}
1141
+
1142
+ {/* 하단 버튼 영역 */}
1143
+ <div className="flex justify-between gap-2 pt-4 border-t">
1144
+ <Button variant="ghost" size="sm" onClick={() => setShowHistory(true)}>
1145
+ <History className="h-4 w-4 mr-2" />
1146
+ 실행 기록
1147
+ </Button>
1148
+
1149
+ <div className="flex gap-2">
1150
+ {/* 실행 전 */}
1151
+ {!hasStarted && currentStatus === 'idle' && (
1152
+ <>
1153
+ <Button variant="outline" onClick={() => onOpenChange(false)}>
1154
+ 취소
1155
+ </Button>
1156
+ <Button onClick={handleStart} disabled={executionMode === 'single' && !selectedProvider}>
1157
+ <Play className="h-4 w-4 mr-2" />
1158
+ 실행 시작
1159
+ </Button>
1160
+ </>
1161
+ )}
1162
+
1163
+ {/* 실행 중 */}
1164
+ {isRunning && (
1165
+ <>
1166
+ <Button variant="outline" onClick={handleStop}>
1167
+ <Square className="h-4 w-4 mr-2" />
1168
+ 중지
1169
+ </Button>
1170
+ <Button variant="destructive" onClick={handleStopAndClose}>
1171
+ <X className="h-4 w-4 mr-2" />
1172
+ 중지 후 닫기
1173
+ </Button>
1174
+ </>
1175
+ )}
1176
+
1177
+ {/* 완료/실패 후 */}
1178
+ {(currentStatus === 'completed' || currentStatus === 'error' || currentStatus === 'failed' || currentStatus === 'stopped') && (
1179
+ <>
1180
+ <Button variant="outline" onClick={handleRetry}>
1181
+ <Play className="h-4 w-4 mr-2" />
1182
+ 다시 실행
1183
+ </Button>
1184
+ <Button onClick={() => onOpenChange(false)}>
1185
+ <X className="h-4 w-4 mr-2" />
1186
+ 닫기
1187
+ </Button>
1188
+ </>
1189
+ )}
1190
+ </div>
1191
+ </div>
1192
+ </DialogContent>
1193
+
1194
+ {/* History Dialog */}
1195
+ <ExecutionHistoryDialog
1196
+ open={showHistory}
1197
+ onOpenChange={setShowHistory}
1198
+ changeId={changeId}
1199
+ taskId={taskId}
1200
+ taskTitle={taskTitle}
1201
+ />
1202
+ </Dialog>
1203
+ )
1204
+ }