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.
- package/.claude-flow/metrics/agent-metrics.json +1 -0
- package/.claude-flow/metrics/performance.json +87 -0
- package/.claude-flow/metrics/system-metrics.json +4370 -0
- package/.claude-flow/metrics/task-metrics.json +10 -0
- package/.claude-plugin/marketplace.json +18 -0
- package/.claude-plugin/plugin.json +17 -0
- package/.gitleaks.toml +69 -0
- package/.hive-mind/config/queens.json +59 -0
- package/.hive-mind/config/workers.json +72 -0
- package/.hive-mind/config.json +111 -0
- package/.hive-mind/hive.db +0 -0
- package/.hive-mind/hive.db-shm +0 -0
- package/.hive-mind/hive.db-wal +0 -0
- package/.leann/indexes/zyflow/documents.ids.txt +2078 -0
- package/.leann/indexes/zyflow/documents.index +0 -0
- package/.leann/indexes/zyflow/documents.leann.meta.json +25 -0
- package/.leann/indexes/zyflow/documents.leann.passages.idx +0 -0
- package/.leann/indexes/zyflow/documents.leann.passages.jsonl +2078 -0
- package/.mcp.json +41 -0
- package/.moai-backups/20260126_231508/.mcp.json +11 -0
- package/.moai-backups/20260126_231508/backup_metadata.json +34 -0
- package/.moai-backups/20260129_145438/.mcp.json +41 -0
- package/.moai-backups/20260129_145438/backup_metadata.json +53 -0
- package/.moai-backups/20260129_145504/.mcp.json +41 -0
- package/.moai-backups/20260129_145504/backup_metadata.json +20 -0
- package/.moai-backups/20260201_140004/.mcp.json +41 -0
- package/.moai-backups/20260201_140004/backup_metadata.json +51 -0
- package/.moai-backups/backup/.mcp.json +12 -0
- package/.moai-backups/settings-backup/settings.local.json +61 -0
- package/.pre-commit-config.yaml +74 -0
- package/.prettierignore +3 -0
- package/.prettierrc +7 -0
- package/.scannerwork/.sonar_lock +0 -0
- package/.scannerwork/report-task.txt +6 -0
- package/.serena/project.yml +105 -0
- package/.shadcn-admin-ref/.env.example +1 -0
- package/.shadcn-admin-ref/.prettierignore +18 -0
- package/.shadcn-admin-ref/.prettierrc +50 -0
- package/.shadcn-admin-ref/LICENSE +21 -0
- package/.shadcn-admin-ref/components.json +21 -0
- package/.shadcn-admin-ref/cz.yaml +7 -0
- package/.shadcn-admin-ref/eslint.config.js +59 -0
- package/.shadcn-admin-ref/index.html +80 -0
- package/.shadcn-admin-ref/knip.config.ts +8 -0
- package/.shadcn-admin-ref/netlify.toml +4 -0
- package/.shadcn-admin-ref/package.json +83 -0
- package/.shadcn-admin-ref/public/images/favicon.png +0 -0
- package/.shadcn-admin-ref/public/images/favicon.svg +4 -0
- package/.shadcn-admin-ref/public/images/favicon_light.png +0 -0
- package/.shadcn-admin-ref/public/images/favicon_light.svg +1 -0
- package/.shadcn-admin-ref/public/images/shadcn-admin.png +0 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-discord.tsx +28 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-docker.tsx +33 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-facebook.tsx +25 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-figma.tsx +27 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-github.tsx +25 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-gitlab.tsx +25 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-gmail.tsx +28 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-medium.tsx +30 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-notion.tsx +28 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-skype.tsx +26 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-slack.tsx +28 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-stripe.tsx +25 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-telegram.tsx +25 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-trello.tsx +27 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-whatsapp.tsx +26 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/icon-zoom.tsx +26 -0
- package/.shadcn-admin-ref/src/assets/brand-icons/index.ts +16 -0
- package/.shadcn-admin-ref/src/assets/clerk-full-logo.tsx +41 -0
- package/.shadcn-admin-ref/src/assets/clerk-logo.tsx +23 -0
- package/.shadcn-admin-ref/src/assets/custom/icon-dir.tsx +110 -0
- package/.shadcn-admin-ref/src/assets/custom/icon-layout-compact.tsx +131 -0
- package/.shadcn-admin-ref/src/assets/custom/icon-layout-default.tsx +124 -0
- package/.shadcn-admin-ref/src/assets/custom/icon-layout-full.tsx +100 -0
- package/.shadcn-admin-ref/src/assets/custom/icon-sidebar-floating.tsx +82 -0
- package/.shadcn-admin-ref/src/assets/custom/icon-sidebar-inset.tsx +58 -0
- package/.shadcn-admin-ref/src/assets/custom/icon-sidebar-sidebar.tsx +53 -0
- package/.shadcn-admin-ref/src/assets/custom/icon-theme-dark.tsx +79 -0
- package/.shadcn-admin-ref/src/assets/custom/icon-theme-light.tsx +78 -0
- package/.shadcn-admin-ref/src/assets/custom/icon-theme-system.tsx +116 -0
- package/.shadcn-admin-ref/src/assets/logo.tsx +24 -0
- package/.shadcn-admin-ref/src/components/coming-soon.tsx +16 -0
- package/.shadcn-admin-ref/src/components/command-menu.tsx +91 -0
- package/.shadcn-admin-ref/src/components/config-drawer.tsx +354 -0
- package/.shadcn-admin-ref/src/components/confirm-dialog.tsx +67 -0
- package/.shadcn-admin-ref/src/components/data-table/bulk-actions.tsx +213 -0
- package/.shadcn-admin-ref/src/components/data-table/column-header.tsx +74 -0
- package/.shadcn-admin-ref/src/components/data-table/faceted-filter.tsx +146 -0
- package/.shadcn-admin-ref/src/components/data-table/index.ts +6 -0
- package/.shadcn-admin-ref/src/components/data-table/pagination.tsx +130 -0
- package/.shadcn-admin-ref/src/components/data-table/toolbar.tsx +85 -0
- package/.shadcn-admin-ref/src/components/data-table/view-options.tsx +56 -0
- package/.shadcn-admin-ref/src/components/date-picker.tsx +51 -0
- package/.shadcn-admin-ref/src/components/layout/app-sidebar.tsx +37 -0
- package/.shadcn-admin-ref/src/components/layout/app-title.tsx +64 -0
- package/.shadcn-admin-ref/src/components/layout/authenticated-layout.tsx +42 -0
- package/.shadcn-admin-ref/src/components/layout/data/sidebar-data.ts +205 -0
- package/.shadcn-admin-ref/src/components/layout/header.tsx +50 -0
- package/.shadcn-admin-ref/src/components/layout/main.tsx +27 -0
- package/.shadcn-admin-ref/src/components/layout/nav-group.tsx +185 -0
- package/.shadcn-admin-ref/src/components/layout/nav-user.tsx +124 -0
- package/.shadcn-admin-ref/src/components/layout/team-switcher.tsx +86 -0
- package/.shadcn-admin-ref/src/components/layout/top-nav.tsx +67 -0
- package/.shadcn-admin-ref/src/components/layout/types.ts +44 -0
- package/.shadcn-admin-ref/src/components/learn-more.tsx +44 -0
- package/.shadcn-admin-ref/src/components/long-text.tsx +84 -0
- package/.shadcn-admin-ref/src/components/navigation-progress.tsx +25 -0
- package/.shadcn-admin-ref/src/components/password-input.tsx +42 -0
- package/.shadcn-admin-ref/src/components/profile-dropdown.tsx +75 -0
- package/.shadcn-admin-ref/src/components/search.tsx +37 -0
- package/.shadcn-admin-ref/src/components/select-dropdown.tsx +62 -0
- package/.shadcn-admin-ref/src/components/sign-out-dialog.tsx +38 -0
- package/.shadcn-admin-ref/src/components/skip-to-main.tsx +10 -0
- package/.shadcn-admin-ref/src/components/theme-switch.tsx +58 -0
- package/.shadcn-admin-ref/src/components/ui/alert-dialog.tsx +154 -0
- package/.shadcn-admin-ref/src/components/ui/alert.tsx +65 -0
- package/.shadcn-admin-ref/src/components/ui/avatar.tsx +50 -0
- package/.shadcn-admin-ref/src/components/ui/badge.tsx +45 -0
- package/.shadcn-admin-ref/src/components/ui/button.tsx +58 -0
- package/.shadcn-admin-ref/src/components/ui/calendar.tsx +210 -0
- package/.shadcn-admin-ref/src/components/ui/card.tsx +91 -0
- package/.shadcn-admin-ref/src/components/ui/checkbox.tsx +29 -0
- package/.shadcn-admin-ref/src/components/ui/collapsible.tsx +31 -0
- package/.shadcn-admin-ref/src/components/ui/command.tsx +181 -0
- package/.shadcn-admin-ref/src/components/ui/dialog.tsx +142 -0
- package/.shadcn-admin-ref/src/components/ui/dropdown-menu.tsx +254 -0
- package/.shadcn-admin-ref/src/components/ui/form.tsx +164 -0
- package/.shadcn-admin-ref/src/components/ui/input-otp.tsx +74 -0
- package/.shadcn-admin-ref/src/components/ui/input.tsx +20 -0
- package/.shadcn-admin-ref/src/components/ui/label.tsx +23 -0
- package/.shadcn-admin-ref/src/components/ui/popover.tsx +45 -0
- package/.shadcn-admin-ref/src/components/ui/radio-group.tsx +42 -0
- package/.shadcn-admin-ref/src/components/ui/scroll-area.tsx +65 -0
- package/.shadcn-admin-ref/src/components/ui/select.tsx +182 -0
- package/.shadcn-admin-ref/src/components/ui/separator.tsx +25 -0
- package/.shadcn-admin-ref/src/components/ui/sheet.tsx +136 -0
- package/.shadcn-admin-ref/src/components/ui/sidebar.tsx +728 -0
- package/.shadcn-admin-ref/src/components/ui/skeleton.tsx +13 -0
- package/.shadcn-admin-ref/src/components/ui/sonner.tsx +21 -0
- package/.shadcn-admin-ref/src/components/ui/switch.tsx +28 -0
- package/.shadcn-admin-ref/src/components/ui/table.tsx +113 -0
- package/.shadcn-admin-ref/src/components/ui/tabs.tsx +63 -0
- package/.shadcn-admin-ref/src/components/ui/textarea.tsx +17 -0
- package/.shadcn-admin-ref/src/components/ui/tooltip.tsx +60 -0
- package/.shadcn-admin-ref/src/config/fonts.ts +19 -0
- package/.shadcn-admin-ref/src/context/direction-provider.tsx +61 -0
- package/.shadcn-admin-ref/src/context/font-provider.tsx +58 -0
- package/.shadcn-admin-ref/src/context/layout-provider.tsx +85 -0
- package/.shadcn-admin-ref/src/context/search-provider.tsx +46 -0
- package/.shadcn-admin-ref/src/context/theme-provider.tsx +110 -0
- package/.shadcn-admin-ref/src/features/apps/data/apps.tsx +110 -0
- package/.shadcn-admin-ref/src/features/apps/index.tsx +179 -0
- package/.shadcn-admin-ref/src/features/auth/auth-layout.tsx +19 -0
- package/.shadcn-admin-ref/src/features/auth/forgot-password/components/forgot-password-form.tsx +82 -0
- package/.shadcn-admin-ref/src/features/auth/forgot-password/index.tsx +44 -0
- package/.shadcn-admin-ref/src/features/auth/otp/components/otp-form.tsx +100 -0
- package/.shadcn-admin-ref/src/features/auth/otp/index.tsx +44 -0
- package/.shadcn-admin-ref/src/features/auth/sign-in/assets/dashboard-dark.png +0 -0
- package/.shadcn-admin-ref/src/features/auth/sign-in/assets/dashboard-light.png +0 -0
- package/.shadcn-admin-ref/src/features/auth/sign-in/components/user-auth-form.tsx +150 -0
- package/.shadcn-admin-ref/src/features/auth/sign-in/index.tsx +51 -0
- package/.shadcn-admin-ref/src/features/auth/sign-in/sign-in-2.tsx +69 -0
- package/.shadcn-admin-ref/src/features/auth/sign-up/components/sign-up-form.tsx +143 -0
- package/.shadcn-admin-ref/src/features/auth/sign-up/index.tsx +57 -0
- package/.shadcn-admin-ref/src/features/chats/components/new-chat.tsx +127 -0
- package/.shadcn-admin-ref/src/features/chats/data/chat-types.ts +4 -0
- package/.shadcn-admin-ref/src/features/chats/data/convo.json +309 -0
- package/.shadcn-admin-ref/src/features/chats/index.tsx +349 -0
- package/.shadcn-admin-ref/src/features/dashboard/components/analytics-chart.tsx +77 -0
- package/.shadcn-admin-ref/src/features/dashboard/components/analytics.tsx +189 -0
- package/.shadcn-admin-ref/src/features/dashboard/components/overview.tsx +82 -0
- package/.shadcn-admin-ref/src/features/dashboard/components/recent-sales.tsx +83 -0
- package/.shadcn-admin-ref/src/features/dashboard/index.tsx +220 -0
- package/.shadcn-admin-ref/src/features/errors/forbidden.tsx +25 -0
- package/.shadcn-admin-ref/src/features/errors/general-error.tsx +36 -0
- package/.shadcn-admin-ref/src/features/errors/maintenance-error.tsx +19 -0
- package/.shadcn-admin-ref/src/features/errors/not-found-error.tsx +25 -0
- package/.shadcn-admin-ref/src/features/errors/unauthorized-error.tsx +25 -0
- package/.shadcn-admin-ref/src/features/settings/account/account-form.tsx +173 -0
- package/.shadcn-admin-ref/src/features/settings/account/index.tsx +14 -0
- package/.shadcn-admin-ref/src/features/settings/appearance/appearance-form.tsx +162 -0
- package/.shadcn-admin-ref/src/features/settings/appearance/index.tsx +14 -0
- package/.shadcn-admin-ref/src/features/settings/components/content-section.tsx +22 -0
- package/.shadcn-admin-ref/src/features/settings/components/sidebar-nav.tsx +84 -0
- package/.shadcn-admin-ref/src/features/settings/display/display-form.tsx +121 -0
- package/.shadcn-admin-ref/src/features/settings/display/index.tsx +13 -0
- package/.shadcn-admin-ref/src/features/settings/index.tsx +74 -0
- package/.shadcn-admin-ref/src/features/settings/notifications/index.tsx +13 -0
- package/.shadcn-admin-ref/src/features/settings/notifications/notifications-form.tsx +220 -0
- package/.shadcn-admin-ref/src/features/settings/profile/index.tsx +13 -0
- package/.shadcn-admin-ref/src/features/settings/profile/profile-form.tsx +177 -0
- package/.shadcn-admin-ref/src/features/tasks/components/data-table-bulk-actions.tsx +193 -0
- package/.shadcn-admin-ref/src/features/tasks/components/data-table-row-actions.tsx +83 -0
- package/.shadcn-admin-ref/src/features/tasks/components/tasks-columns.tsx +123 -0
- package/.shadcn-admin-ref/src/features/tasks/components/tasks-dialogs.tsx +72 -0
- package/.shadcn-admin-ref/src/features/tasks/components/tasks-import-dialog.tsx +110 -0
- package/.shadcn-admin-ref/src/features/tasks/components/tasks-multi-delete-dialog.tsx +95 -0
- package/.shadcn-admin-ref/src/features/tasks/components/tasks-mutate-drawer.tsx +212 -0
- package/.shadcn-admin-ref/src/features/tasks/components/tasks-primary-buttons.tsx +21 -0
- package/.shadcn-admin-ref/src/features/tasks/components/tasks-provider.tsx +36 -0
- package/.shadcn-admin-ref/src/features/tasks/components/tasks-table.tsx +197 -0
- package/.shadcn-admin-ref/src/features/tasks/data/data.tsx +77 -0
- package/.shadcn-admin-ref/src/features/tasks/data/schema.ts +13 -0
- package/.shadcn-admin-ref/src/features/tasks/data/tasks.ts +29 -0
- package/.shadcn-admin-ref/src/features/tasks/index.tsx +41 -0
- package/.shadcn-admin-ref/src/features/users/components/data-table-bulk-actions.tsx +139 -0
- package/.shadcn-admin-ref/src/features/users/components/data-table-row-actions.tsx +63 -0
- package/.shadcn-admin-ref/src/features/users/components/users-action-dialog.tsx +326 -0
- package/.shadcn-admin-ref/src/features/users/components/users-columns.tsx +138 -0
- package/.shadcn-admin-ref/src/features/users/components/users-delete-dialog.tsx +81 -0
- package/.shadcn-admin-ref/src/features/users/components/users-dialogs.tsx +51 -0
- package/.shadcn-admin-ref/src/features/users/components/users-invite-dialog.tsx +150 -0
- package/.shadcn-admin-ref/src/features/users/components/users-multi-delete-dialog.tsx +95 -0
- package/.shadcn-admin-ref/src/features/users/components/users-primary-buttons.tsx +21 -0
- package/.shadcn-admin-ref/src/features/users/components/users-provider.tsx +36 -0
- package/.shadcn-admin-ref/src/features/users/components/users-table.tsx +194 -0
- package/.shadcn-admin-ref/src/features/users/data/data.ts +35 -0
- package/.shadcn-admin-ref/src/features/users/data/schema.ts +32 -0
- package/.shadcn-admin-ref/src/features/users/data/users.ts +33 -0
- package/.shadcn-admin-ref/src/features/users/index.tsx +47 -0
- package/.shadcn-admin-ref/src/hooks/use-dialog-state.tsx +18 -0
- package/.shadcn-admin-ref/src/hooks/use-mobile.tsx +19 -0
- package/.shadcn-admin-ref/src/hooks/use-table-url-state.ts +219 -0
- package/.shadcn-admin-ref/src/lib/cookies.ts +43 -0
- package/.shadcn-admin-ref/src/lib/handle-server-error.ts +24 -0
- package/.shadcn-admin-ref/src/lib/show-submitted-data.tsx +15 -0
- package/.shadcn-admin-ref/src/lib/utils.ts +60 -0
- package/.shadcn-admin-ref/src/main.tsx +107 -0
- package/.shadcn-admin-ref/src/routeTree.gen.ts +719 -0
- package/.shadcn-admin-ref/src/routes/(auth)/forgot-password.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/(auth)/otp.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/(auth)/sign-in-2.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/(auth)/sign-in.tsx +12 -0
- package/.shadcn-admin-ref/src/routes/(auth)/sign-up.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/(errors)/401.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/(errors)/403.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/(errors)/404.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/(errors)/500.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/(errors)/503.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/__root.tsx +30 -0
- package/.shadcn-admin-ref/src/routes/_authenticated/apps/index.tsx +17 -0
- package/.shadcn-admin-ref/src/routes/_authenticated/chats/index.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/_authenticated/errors/$error.tsx +45 -0
- package/.shadcn-admin-ref/src/routes/_authenticated/help-center/index.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/_authenticated/index.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/_authenticated/route.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/_authenticated/settings/account.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/_authenticated/settings/appearance.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/_authenticated/settings/display.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/_authenticated/settings/index.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/_authenticated/settings/notifications.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/_authenticated/settings/route.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/_authenticated/tasks/index.tsx +23 -0
- package/.shadcn-admin-ref/src/routes/_authenticated/users/index.tsx +32 -0
- package/.shadcn-admin-ref/src/routes/clerk/(auth)/route.tsx +60 -0
- package/.shadcn-admin-ref/src/routes/clerk/(auth)/sign-in.tsx +14 -0
- package/.shadcn-admin-ref/src/routes/clerk/(auth)/sign-up.tsx +9 -0
- package/.shadcn-admin-ref/src/routes/clerk/_authenticated/route.tsx +6 -0
- package/.shadcn-admin-ref/src/routes/clerk/_authenticated/user-management.tsx +184 -0
- package/.shadcn-admin-ref/src/routes/clerk/route.tsx +135 -0
- package/.shadcn-admin-ref/src/stores/auth-store.ts +53 -0
- package/.shadcn-admin-ref/src/styles/index.css +87 -0
- package/.shadcn-admin-ref/src/styles/theme.css +102 -0
- package/.shadcn-admin-ref/src/tanstack-table.d.ts +10 -0
- package/.shadcn-admin-ref/src/vite-env.d.ts +1 -0
- package/.swarm/memory.db +0 -0
- package/.swarm/memory.db-shm +0 -0
- package/.swarm/memory.db-wal +0 -0
- package/.zyflow/cli-settings.json +30 -0
- package/.zyflow/db.sqlite +0 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765491505852.json +10 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765491622627.json +10 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765491794652.json +10 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765491890392.json +10 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765494002879.json +10 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765494183887.json +10 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765494342052.json +10 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765494387244.json +10 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765494387245.json +10 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765494606176.json +10 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765495967542.json +16 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765495967629.json +16 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765497861143.json +16 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765497861870.json +20 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765498021377.json +18 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765498021660.json +18 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765503255525.json +13 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765503256018.json +13 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765504009102.json +16 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765504492051.json +18 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765504946437.json +16 -0
- package/.zyflow/logs/add-gitdiagram-integration/1633-1765504946640.json +16 -0
- package/.zyflow/logs/add-gitdiagram-integration/1634-1765505950215.json +16 -0
- package/.zyflow/logs/add-gitdiagram-integration/1634-1765505950948.json +18 -0
- package/.zyflow/logs/add-gitdiagram-integration/1635-1765505971712.json +18 -0
- package/.zyflow/logs/add-gitdiagram-integration/1635-1765505971976.json +18 -0
- package/.zyflow/logs/add-gitdiagram-integration/1636-1765505986208.json +18 -0
- package/.zyflow/logs/add-gitdiagram-integration/1636-1765505986620.json +16 -0
- package/.zyflow/logs/integrate-claude-flow/3580-1765996816612.json +10 -0
- package/.zyflow/logs/integrate-claude-flow/3580-1766014825819.json +10 -0
- package/.zyflow/logs/integrate-claude-flow/3580-1766015183794.json +12 -0
- package/.zyflow/logs/integrate-claude-flow/3580-1766015474608.json +12 -0
- package/.zyflow/logs/integrate-claude-flow/3581-1766016502824.json +63 -0
- package/.zyflow/logs/integrate-claude-flow/3581-1766016576008.json +60 -0
- package/.zyflow/logs/integrate-claude-flow/3582-1766022737754.json +110 -0
- package/.zyflow/logs/integrate-claude-flow/3582-1766022809327.json +135 -0
- package/.zyflow/sessions.json +242 -0
- package/.zyflow/settings.json +6 -0
- package/.zyflow/tasks.db +0 -0
- package/.zyflow/tasks.db-shm +0 -0
- package/.zyflow/tasks.db-wal +0 -0
- package/.zyflow/zyflow.sqlite +0 -0
- package/Dockerfile +82 -0
- package/LICENSE +21 -0
- package/README.md +506 -0
- package/claude-flow +34 -0
- package/components.json +21 -0
- package/config/ports.ts +28 -0
- package/docker-compose.yml +52 -0
- package/eslint.config.js +34 -0
- package/index.html +19 -0
- package/logs/mcp-error.log +55 -0
- package/logs/mcp-out.log +0 -0
- package/logs/pm2-error.log +0 -0
- package/logs/pm2-out.log +265 -0
- package/logs/py-error.log +22 -0
- package/logs/py-out.log +0 -0
- package/logs/server-error.log +11000 -0
- package/logs/server-out.log +8117 -0
- package/logs/vite-error.log +404 -0
- package/logs/vite-out.log +311 -0
- package/mcp-server/agent-tools.ts +375 -0
- package/mcp-server/cli-models.ts +193 -0
- package/mcp-server/context.ts +110 -0
- package/mcp-server/diagram-tools.ts +341 -0
- package/mcp-server/index.ts +2014 -0
- package/mcp-server/integration-tools.ts +909 -0
- package/mcp-server/moai-spec-tools.ts +416 -0
- package/mcp-server/parser.ts +422 -0
- package/mcp-server/post-task-runner.ts +253 -0
- package/mcp-server/post-task-types.ts +426 -0
- package/mcp-server/quarantine-manager.ts +479 -0
- package/mcp-server/report-generator.ts +386 -0
- package/mcp-server/task-tools.ts +619 -0
- package/mcp-server/trigger-config.ts +288 -0
- package/mcp-server/trigger-router.ts +305 -0
- package/mcp-server/triggers/event-listener.ts +331 -0
- package/mcp-server/triggers/git-hooks.ts +283 -0
- package/mcp-server/triggers/scheduler.ts +289 -0
- package/mcp-server/types.ts +55 -0
- package/memory/claude-flow@alpha-data.json +5 -0
- package/nginx/zyflow.conf +144 -0
- package/openspec/config.yaml +78 -0
- package/openspec-backup.tar.gz +0 -0
- package/package.json +154 -0
- package/packages/gitdiagram-core/.claude-flow/metrics/agent-metrics.json +1 -0
- package/packages/gitdiagram-core/.claude-flow/metrics/performance.json +87 -0
- package/packages/gitdiagram-core/.claude-flow/metrics/task-metrics.json +10 -0
- package/packages/gitdiagram-core/package.json +41 -0
- package/packages/gitdiagram-core/src/file-tree.ts +272 -0
- package/packages/gitdiagram-core/src/generator.ts +283 -0
- package/packages/gitdiagram-core/src/index.ts +78 -0
- package/packages/gitdiagram-core/src/llm-adapter.ts +235 -0
- package/packages/gitdiagram-core/src/mermaid-utils.ts +304 -0
- package/packages/gitdiagram-core/src/prompts.ts +281 -0
- package/packages/zyflow-parser/package.json +34 -0
- package/packages/zyflow-parser/src/index.ts +26 -0
- package/packages/zyflow-parser/src/moai-parser.ts +603 -0
- package/packages/zyflow-parser/src/moai-types.ts +110 -0
- package/packages/zyflow-remote-plugin/.claude-flow/metrics/agent-metrics.json +1 -0
- package/packages/zyflow-remote-plugin/.claude-flow/metrics/performance.json +87 -0
- package/packages/zyflow-remote-plugin/.claude-flow/metrics/task-metrics.json +10 -0
- package/packages/zyflow-remote-plugin/package.json +31 -0
- package/packages/zyflow-remote-plugin/src/index.ts +71 -0
- package/packages/zyflow-remote-plugin/src/remote-config.ts +232 -0
- package/packages/zyflow-remote-plugin/src/router.ts +535 -0
- package/packages/zyflow-remote-plugin/src/ssh-config-parser.ts +123 -0
- package/packages/zyflow-remote-plugin/src/ssh-manager.ts +598 -0
- package/packages/zyflow-remote-plugin/src/types.ts +149 -0
- package/plugin/manifest.json +26 -0
- package/plugin/package.json +13 -0
- package/public/favicon.svg +4 -0
- package/server/adk/agents/error-analyzer.ts +223 -0
- package/server/adk/agents/fix-generator.ts +187 -0
- package/server/adk/agents/pr-agent.ts +264 -0
- package/server/adk/agents/validator.ts +187 -0
- package/server/adk/config.ts +43 -0
- package/server/adk/index.ts +69 -0
- package/server/adk/integration.ts +297 -0
- package/server/adk/orchestrator.ts +405 -0
- package/server/adk/tools/build-tools.ts +290 -0
- package/server/adk/tools/file-tools.ts +351 -0
- package/server/adk/tools/git-tools.ts +280 -0
- package/server/adk/tools/github-tools.ts +249 -0
- package/server/agents/agent-monitor.ts +416 -0
- package/server/agents/alert-integration.ts +312 -0
- package/server/agents/error-analyzer.ts +472 -0
- package/server/agents/error-detector.ts +442 -0
- package/server/agents/fix-generator.ts +421 -0
- package/server/agents/fix-validator.ts +428 -0
- package/server/agents/merge-policy.ts +362 -0
- package/server/agents/pr-workflow.ts +476 -0
- package/server/agents/prompts/error-analysis.ts +393 -0
- package/server/ai/gemini-client.ts +499 -0
- package/server/ai/index.ts +317 -0
- package/server/ai/types.ts +137 -0
- package/server/app.ts +3693 -0
- package/server/archive-manager.ts +604 -0
- package/server/backlog/index.ts +7 -0
- package/server/backlog/migration.ts +331 -0
- package/server/backlog/parser.ts +323 -0
- package/server/backlog/sync.ts +325 -0
- package/server/change-log.ts +868 -0
- package/server/claude-flow/index.ts +12 -0
- package/server/claude-flow/prompt-builder.ts +407 -0
- package/server/claude-flow/types.ts +33 -0
- package/server/cli-adapter/index.ts +11 -0
- package/server/cli-adapter/process-manager.ts +612 -0
- package/server/cli-adapter/profile-manager.ts +286 -0
- package/server/cli-adapter/routes.ts +561 -0
- package/server/cli-adapter/types.ts +226 -0
- package/server/config.d.ts +18 -0
- package/server/config.js +79 -0
- package/server/config.ts +262 -0
- package/server/flow-sync.ts +543 -0
- package/server/git/change-workflow.ts +446 -0
- package/server/git/commands.ts +370 -0
- package/server/git/github.ts +247 -0
- package/server/git/index.ts +1202 -0
- package/server/git/status.ts +322 -0
- package/server/index.ts +136 -0
- package/server/integrations/crypto.ts +142 -0
- package/server/integrations/db/client.ts +169 -0
- package/server/integrations/db/schema.ts +167 -0
- package/server/integrations/env-parser.ts +365 -0
- package/server/integrations/index.ts +101 -0
- package/server/integrations/keychain.ts +239 -0
- package/server/integrations/local/file-utils.ts +383 -0
- package/server/integrations/local/index.ts +64 -0
- package/server/integrations/local/resolver.ts +439 -0
- package/server/integrations/local/types.ts +122 -0
- package/server/integrations/routes.ts +1100 -0
- package/server/integrations/service-patterns.ts +771 -0
- package/server/integrations/services/accounts.ts +356 -0
- package/server/integrations/services/env-import.ts +279 -0
- package/server/integrations/services/projects.ts +552 -0
- package/server/integrations/services/system-import.ts +1110 -0
- package/server/migrations/ears-generator.ts +491 -0
- package/server/migrations/gherkin-generator.ts +605 -0
- package/server/migrations/index.ts +73 -0
- package/server/migrations/migrate-spec-format.ts +492 -0
- package/server/migrations/openspec-parser.ts +542 -0
- package/server/migrations/tag-generator.ts +474 -0
- package/server/moai-specs.ts +487 -0
- package/server/moai-watcher.ts +145 -0
- package/server/parser-debug.ts +37 -0
- package/server/parser-utils.ts +316 -0
- package/server/parser.d.ts +17 -0
- package/server/parser.js +221 -0
- package/server/parser.ts +342 -0
- package/server/remote-watcher.ts +367 -0
- package/server/replay-engine.ts +915 -0
- package/server/routes/alerts.ts +1028 -0
- package/server/routes/changes.ts +812 -0
- package/server/routes/docs.ts +898 -0
- package/server/routes/flow.ts +2814 -0
- package/server/routes/global-chat.ts +162 -0
- package/server/routes/leann.ts +327 -0
- package/server/routes/projects.ts +1282 -0
- package/server/routes/search.ts +266 -0
- package/server/routes/specs.ts +482 -0
- package/server/routes/webhooks.ts +579 -0
- package/server/server/parser.js +265 -0
- package/server/services/githubActionsPoller.ts +797 -0
- package/server/services/slackNotifier.ts +476 -0
- package/server/src/types/index.js +1 -0
- package/server/sync-tasks.ts +741 -0
- package/server/tasks/cli/commands.ts +269 -0
- package/server/tasks/cli/index.ts +152 -0
- package/server/tasks/core/search.ts +81 -0
- package/server/tasks/core/task.ts +307 -0
- package/server/tasks/db/client.ts +1008 -0
- package/server/tasks/db/schema.ts +572 -0
- package/server/tasks/index.ts +24 -0
- package/server/tasks.db +0 -0
- package/server/types/archive.ts +136 -0
- package/server/types/change-log.ts +643 -0
- package/server/types/spec.ts +188 -0
- package/server/unified-spec-scanner.ts +753 -0
- package/server/utils/crypto.ts +179 -0
- package/server/utils/webhook-verify.ts +216 -0
- package/server/watcher.ts +132 -0
- package/server/websocket.ts +99 -0
- package/server-output.log +6 -0
- package/sonar-project.properties +18 -0
- package/src/App.tsx +386 -0
- package/src/api/client.ts +346 -0
- package/src/api/error-interceptor.ts +366 -0
- package/src/api/errors.ts +123 -0
- package/src/api/flow.ts +233 -0
- package/src/api/offline-queue.ts +351 -0
- package/src/api/retry-logic.ts +233 -0
- package/src/components/OfflineModeBanner.tsx +159 -0
- package/src/components/SSEStatusIndicator.tsx +194 -0
- package/src/components/agent/AgentChat.tsx +243 -0
- package/src/components/agent/AgentPage.tsx +182 -0
- package/src/components/agent/AgentSidebar.tsx +231 -0
- package/src/components/agent/index.ts +7 -0
- package/src/components/alerts/AlertCenter.tsx +239 -0
- package/src/components/alerts/AlertDashboard.tsx +211 -0
- package/src/components/alerts/AlertDetail.tsx +474 -0
- package/src/components/alerts/AlertList.tsx +113 -0
- package/src/components/alerts/AlertSettings.tsx +336 -0
- package/src/components/alerts/index.ts +5 -0
- package/src/components/chat/ChatPanel.tsx +642 -0
- package/src/components/chat/index.ts +1 -0
- package/src/components/cli/AddCustomCLIDialog.tsx +210 -0
- package/src/components/cli/CLISelector.tsx +187 -0
- package/src/components/cli/index.ts +8 -0
- package/src/components/dashboard/ArchivedChangeList.tsx +102 -0
- package/src/components/dashboard/ArchivedChangeViewer.tsx +184 -0
- package/src/components/dashboard/ArchivedChangesPage.tsx +31 -0
- package/src/components/dashboard/ChangeList.tsx +86 -0
- package/src/components/dashboard/ThemeToggle.tsx +33 -0
- package/src/components/diagram/DiagramViewer.tsx +256 -0
- package/src/components/diagram/MermaidRenderer.tsx +163 -0
- package/src/components/diagram/ProjectDiagramTab.tsx +161 -0
- package/src/components/diagram/index.ts +13 -0
- package/src/components/errors/ErrorBoundary.tsx +276 -0
- package/src/components/errors/ErrorFallback.tsx +198 -0
- package/src/components/errors/ErrorToast.tsx +221 -0
- package/src/components/flow/BacklogView.tsx +1142 -0
- package/src/components/flow/ChangeDetail.tsx +475 -0
- package/src/components/flow/ChangeItem.tsx +230 -0
- package/src/components/flow/ChangeList.tsx +92 -0
- package/src/components/flow/ExecutionHistoryDialog.tsx +224 -0
- package/src/components/flow/FlowContent.tsx +212 -0
- package/src/components/flow/FlowPage.tsx +9 -0
- package/src/components/flow/PipelineBar.tsx +214 -0
- package/src/components/flow/ProjectDashboard.tsx +222 -0
- package/src/components/flow/SpecDetail.tsx +138 -0
- package/src/components/flow/SpecDetailTabs.tsx +176 -0
- package/src/components/flow/SpecItem.tsx +93 -0
- package/src/components/flow/SpecProgressBar.tsx +47 -0
- package/src/components/flow/StageContent.tsx +620 -0
- package/src/components/flow/StandaloneTasks.tsx +960 -0
- package/src/components/flow/TaskExecutionDialog.tsx +1204 -0
- package/src/components/flow/index.ts +9 -0
- package/src/components/flow/task-execution/AgentSlider.tsx +37 -0
- package/src/components/flow/task-execution/ConsensusSettings.tsx +129 -0
- package/src/components/flow/task-execution/ExecutionOutput.tsx +398 -0
- package/src/components/flow/task-execution/ModelSelector.tsx +134 -0
- package/src/components/flow/task-execution/ProviderSelector.tsx +137 -0
- package/src/components/flow/task-execution/RecommendationBanner.tsx +71 -0
- package/src/components/flow/task-execution/StatusBadge.tsx +43 -0
- package/src/components/flow/task-execution/StrategySelector.tsx +48 -0
- package/src/components/flow/task-execution/SwarmSummary.tsx +55 -0
- package/src/components/flow/task-execution/index.ts +14 -0
- package/src/components/flow/task-execution/types.ts +56 -0
- package/src/components/git/ChangeWorkflowDialog.tsx +582 -0
- package/src/components/git/ConflictResolutionDialog.tsx +398 -0
- package/src/components/git/GitBranchSelector.tsx +212 -0
- package/src/components/git/GitCommitDialog.tsx +254 -0
- package/src/components/git/GitStatusBadge.tsx +148 -0
- package/src/components/git/GitSyncButton.tsx +128 -0
- package/src/components/git/RemoteStatusBanner.tsx +143 -0
- package/src/components/git/index.ts +9 -0
- package/src/components/integrations/EnvImportDialog.tsx +524 -0
- package/src/components/integrations/EnvironmentDialog.tsx +227 -0
- package/src/components/integrations/IntegrationBadges.tsx +91 -0
- package/src/components/integrations/IntegrationsSettings.tsx +55 -0
- package/src/components/integrations/ProjectIntegrations.tsx +481 -0
- package/src/components/integrations/ServiceAccountDialog.tsx +422 -0
- package/src/components/integrations/ServiceAccountList.tsx +305 -0
- package/src/components/integrations/SystemImportDialog.tsx +436 -0
- package/src/components/integrations/TestAccountDialog.tsx +162 -0
- package/src/components/integrations/index.ts +6 -0
- package/src/components/layout/AppSidebar.tsx +284 -0
- package/src/components/layout/FlowSidebar.tsx +435 -0
- package/src/components/layout/GlobalCommandPalette.tsx +410 -0
- package/src/components/layout/MenuBar.tsx +227 -0
- package/src/components/layout/StatusBar.tsx +226 -0
- package/src/components/monitoring/ErrorDashboard.tsx +274 -0
- package/src/components/monitoring/ErrorDetailPanel.tsx +200 -0
- package/src/components/monitoring/ErrorFilters.tsx +219 -0
- package/src/components/monitoring/ErrorHistoryList.tsx +141 -0
- package/src/components/monitoring/ErrorStats.tsx +249 -0
- package/src/components/remote/RemoteFileBrowser.tsx +249 -0
- package/src/components/remote/RemoteServerDialog.tsx +234 -0
- package/src/components/remote/RemoteServerList.tsx +366 -0
- package/src/components/remote/index.ts +7 -0
- package/src/components/settings/CLISettings.tsx +522 -0
- package/src/components/settings/CustomCLIDialog.tsx +548 -0
- package/src/components/settings/IntegrationsSettings.tsx +51 -0
- package/src/components/settings/ProjectSettings.tsx +441 -0
- package/src/components/settings/ProjectsSettings.tsx +541 -0
- package/src/components/settings/SearchSettings.tsx +272 -0
- package/src/components/settings/SettingsPage.tsx +68 -0
- package/src/components/settings/index.ts +5 -0
- package/src/components/swarm/ExecutionPanel.tsx +284 -0
- package/src/components/swarm/LogViewer.tsx +196 -0
- package/src/components/swarm/ProgressIndicator.tsx +111 -0
- package/src/components/swarm/index.ts +3 -0
- package/src/components/tasks/ArchiveTable.tsx +203 -0
- package/src/components/tasks/KanbanBoard.tsx +264 -0
- package/src/components/tasks/TaskCard.tsx +138 -0
- package/src/components/tasks/TaskColumn.tsx +81 -0
- package/src/components/tasks/TaskDialog.tsx +274 -0
- package/src/components/tasks/index.ts +5 -0
- package/src/components/tasks/types.ts +43 -0
- package/src/components/ui/alert-dialog.tsx +154 -0
- package/src/components/ui/alert.tsx +65 -0
- package/src/components/ui/badge.tsx +45 -0
- package/src/components/ui/button.tsx +58 -0
- package/src/components/ui/card.tsx +91 -0
- package/src/components/ui/checkbox.tsx +29 -0
- package/src/components/ui/collapsible.tsx +31 -0
- package/src/components/ui/command.tsx +184 -0
- package/src/components/ui/confirm-dialog.tsx +55 -0
- package/src/components/ui/dialog.tsx +142 -0
- package/src/components/ui/dropdown-menu.tsx +254 -0
- package/src/components/ui/input.tsx +20 -0
- package/src/components/ui/label.tsx +22 -0
- package/src/components/ui/markdown.tsx +100 -0
- package/src/components/ui/progress.tsx +27 -0
- package/src/components/ui/resizable-sidebar.tsx +156 -0
- package/src/components/ui/resizable.tsx +54 -0
- package/src/components/ui/right-resizable-sidebar.tsx +158 -0
- package/src/components/ui/scroll-area.tsx +64 -0
- package/src/components/ui/select.tsx +185 -0
- package/src/components/ui/separator.tsx +25 -0
- package/src/components/ui/sheet.tsx +136 -0
- package/src/components/ui/sidebar.tsx +726 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/slider.tsx +56 -0
- package/src/components/ui/switch.tsx +29 -0
- package/src/components/ui/table.tsx +113 -0
- package/src/components/ui/tabs.tsx +63 -0
- package/src/components/ui/textarea.tsx +17 -0
- package/src/components/ui/tooltip.tsx +60 -0
- package/src/config/api.ts +83 -0
- package/src/constants/error-codes.ts +255 -0
- package/src/constants/stages.ts +27 -0
- package/src/context/ErrorContext.tsx +185 -0
- package/src/context/theme-provider.tsx +63 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/hooks/useAI.ts +206 -0
- package/src/hooks/useAgentSession.ts +431 -0
- package/src/hooks/useAlerts.ts +935 -0
- package/src/hooks/useArchivedChanges.ts +39 -0
- package/src/hooks/useAsyncError.ts +45 -0
- package/src/hooks/useChangeGit.ts +727 -0
- package/src/hooks/useChanges.ts +20 -0
- package/src/hooks/useClaude.ts +130 -0
- package/src/hooks/useDocs.ts +182 -0
- package/src/hooks/useErrorDashboard.ts +243 -0
- package/src/hooks/useErrorHandler.ts +150 -0
- package/src/hooks/useExecutionHistory.ts +55 -0
- package/src/hooks/useFlowChanges.ts +850 -0
- package/src/hooks/useFlowItems.ts +205 -0
- package/src/hooks/useGit.ts +427 -0
- package/src/hooks/useHideCompletedSpecs.ts +15 -0
- package/src/hooks/useInstance.ts +40 -0
- package/src/hooks/useIntegrations.ts +737 -0
- package/src/hooks/useLeannStatus.ts +93 -0
- package/src/hooks/useNetworkStatus.ts +167 -0
- package/src/hooks/useProjects.ts +353 -0
- package/src/hooks/useRemoteServers.ts +383 -0
- package/src/hooks/useSSEConnection.ts +346 -0
- package/src/hooks/useSpecs.ts +39 -0
- package/src/hooks/useSwarm.ts +462 -0
- package/src/hooks/useTasks.ts +137 -0
- package/src/hooks/useURLSync.ts +122 -0
- package/src/hooks/useWebSocket.ts +262 -0
- package/src/lib/utils.ts +121 -0
- package/src/main.tsx +22 -0
- package/src/stores/errorStore.ts +301 -0
- package/src/stores/offlineStore.ts +266 -0
- package/src/stores/sseStore.ts +247 -0
- package/src/stores/useHideCompletedStore.ts +21 -0
- package/src/styles/index.css +87 -0
- package/src/styles/theme.css +102 -0
- package/src/types/ai.ts +191 -0
- package/src/types/errors.ts +253 -0
- package/src/types/flow.ts +382 -0
- package/src/types/index.ts +614 -0
- package/src/utils/error-logger.ts +399 -0
- package/src/utils/error-statistics.ts +305 -0
- package/src/utils/logger.ts +280 -0
- package/src/utils/task-routing.ts +795 -0
- package/src/vite-env.d.ts +1 -0
- package/test-results/.last-run.json +4 -0
- package/tmp/check-docker-final.ts +48 -0
- package/tmp/check-docker-tasks.ts +58 -0
- package/tmp/check-docker-tasks2.ts +48 -0
- package/tmp/check-docker-tasks3.ts +42 -0
- package/tmp/check-mobile-tasks.ts +57 -0
- package/tmp/check-zywiki-tasks.ts +49 -0
- package/tmp/sync-mobile.ts +11 -0
- package/tmp/sync-zywiki.ts +68 -0
- package/tmp/test-docker-parser.ts +15 -0
- package/tmp/test-mobile-parser.ts +28 -0
- package/tmp/test-parser.ts +27 -0
- package/tmp/test-unnumbered.ts +35 -0
- package/zyflow.db +0 -0
|
@@ -0,0 +1,1100 @@
|
|
|
1
|
+
import { Router, Request, Response } from 'express';
|
|
2
|
+
import {
|
|
3
|
+
createServiceAccount,
|
|
4
|
+
listServiceAccounts,
|
|
5
|
+
getServiceAccount,
|
|
6
|
+
getServiceAccountCredentials,
|
|
7
|
+
updateServiceAccount,
|
|
8
|
+
deleteServiceAccount,
|
|
9
|
+
getAccountsByType,
|
|
10
|
+
} from './services/accounts.js';
|
|
11
|
+
import {
|
|
12
|
+
getProjectIntegration,
|
|
13
|
+
upsertProjectIntegration,
|
|
14
|
+
setProjectService,
|
|
15
|
+
listEnvironments,
|
|
16
|
+
createEnvironment,
|
|
17
|
+
updateEnvironment,
|
|
18
|
+
deleteEnvironment,
|
|
19
|
+
setActiveEnvironment,
|
|
20
|
+
getEnvironmentVariables,
|
|
21
|
+
listTestAccounts,
|
|
22
|
+
createTestAccount,
|
|
23
|
+
updateTestAccount,
|
|
24
|
+
deleteTestAccount,
|
|
25
|
+
getTestAccountPassword,
|
|
26
|
+
getProjectContext,
|
|
27
|
+
} from './services/projects.js';
|
|
28
|
+
import {
|
|
29
|
+
scanAndCacheProjectEnv,
|
|
30
|
+
importServices,
|
|
31
|
+
listEnvFiles,
|
|
32
|
+
type ImportRequest,
|
|
33
|
+
} from './services/env-import.js';
|
|
34
|
+
import {
|
|
35
|
+
scanAndCacheSystemSources,
|
|
36
|
+
importSystemServices,
|
|
37
|
+
type SystemImportRequest,
|
|
38
|
+
} from './services/system-import.js';
|
|
39
|
+
import type { ServiceType, Credentials } from './db/schema.js';
|
|
40
|
+
// Local Settings imports
|
|
41
|
+
import {
|
|
42
|
+
SettingsResolver,
|
|
43
|
+
initLocalZyflow,
|
|
44
|
+
createDefaultLocalSettings,
|
|
45
|
+
saveLocalSettings,
|
|
46
|
+
saveLocalEnvironment,
|
|
47
|
+
saveLocalTestAccounts,
|
|
48
|
+
encryptTestAccountPassword,
|
|
49
|
+
} from './local/index.js';
|
|
50
|
+
|
|
51
|
+
const router = Router();
|
|
52
|
+
|
|
53
|
+
// =============================================
|
|
54
|
+
// 서비스 계정 API
|
|
55
|
+
// =============================================
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* GET /api/integrations/accounts
|
|
59
|
+
* 서비스 계정 목록 조회 (마스킹된 credentials)
|
|
60
|
+
*/
|
|
61
|
+
router.get('/accounts', async (req: Request, res: Response) => {
|
|
62
|
+
try {
|
|
63
|
+
const type = req.query.type as ServiceType | undefined;
|
|
64
|
+
const accounts = await listServiceAccounts(type);
|
|
65
|
+
res.json({ accounts });
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error('Failed to list service accounts:', error);
|
|
68
|
+
res.status(500).json({
|
|
69
|
+
error: 'Failed to list service accounts',
|
|
70
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* POST /api/integrations/accounts
|
|
77
|
+
* 서비스 계정 생성
|
|
78
|
+
*/
|
|
79
|
+
router.post('/accounts', async (req: Request, res: Response) => {
|
|
80
|
+
try {
|
|
81
|
+
const { type, name, credentials, environment, metadata } = req.body;
|
|
82
|
+
|
|
83
|
+
if (!type || !name || !credentials) {
|
|
84
|
+
res.status(400).json({
|
|
85
|
+
error: 'Missing required fields',
|
|
86
|
+
message: 'type, name, and credentials are required',
|
|
87
|
+
});
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const validTypes: ServiceType[] = ['github', 'supabase', 'vercel', 'sentry', 'custom'];
|
|
92
|
+
if (!validTypes.includes(type)) {
|
|
93
|
+
res.status(400).json({
|
|
94
|
+
error: 'Invalid service type',
|
|
95
|
+
message: `type must be one of: ${validTypes.join(', ')}`,
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// environment 검증 (null, 'staging', 'production' 만 허용)
|
|
101
|
+
const validEnvironments = [null, undefined, 'staging', 'production'];
|
|
102
|
+
if (environment !== undefined && !validEnvironments.includes(environment)) {
|
|
103
|
+
res.status(400).json({
|
|
104
|
+
error: 'Invalid environment',
|
|
105
|
+
message: 'environment must be null, "staging", or "production"',
|
|
106
|
+
});
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const account = await createServiceAccount(
|
|
111
|
+
type as ServiceType,
|
|
112
|
+
name,
|
|
113
|
+
credentials as Credentials,
|
|
114
|
+
{
|
|
115
|
+
environment: environment ?? null,
|
|
116
|
+
metadata,
|
|
117
|
+
}
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
res.status(201).json({ account });
|
|
121
|
+
} catch (error) {
|
|
122
|
+
console.error('Failed to create service account:', error);
|
|
123
|
+
res.status(400).json({
|
|
124
|
+
error: 'Failed to create service account',
|
|
125
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* GET /api/integrations/accounts/:id
|
|
132
|
+
* 서비스 계정 단일 조회 (마스킹된 credentials)
|
|
133
|
+
*/
|
|
134
|
+
router.get('/accounts/:id', async (req: Request, res: Response) => {
|
|
135
|
+
try {
|
|
136
|
+
const { id } = req.params;
|
|
137
|
+
const account = await getServiceAccount(id);
|
|
138
|
+
|
|
139
|
+
if (!account) {
|
|
140
|
+
res.status(404).json({
|
|
141
|
+
error: 'Account not found',
|
|
142
|
+
message: `No service account found with id: ${id}`,
|
|
143
|
+
});
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
res.json({ account });
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error('Failed to get service account:', error);
|
|
150
|
+
res.status(500).json({
|
|
151
|
+
error: 'Failed to get service account',
|
|
152
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* GET /api/integrations/accounts/:id/credentials
|
|
159
|
+
* 서비스 계정 credentials 조회 (복호화된 원본 - 복사 기능용)
|
|
160
|
+
*/
|
|
161
|
+
router.get('/accounts/:id/credentials', async (req: Request, res: Response) => {
|
|
162
|
+
try {
|
|
163
|
+
const { id } = req.params;
|
|
164
|
+
const credentials = await getServiceAccountCredentials(id);
|
|
165
|
+
|
|
166
|
+
if (!credentials) {
|
|
167
|
+
res.status(404).json({
|
|
168
|
+
error: 'Account not found',
|
|
169
|
+
message: `No service account found with id: ${id}`,
|
|
170
|
+
});
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
res.json({ credentials });
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error('Failed to get account credentials:', error);
|
|
177
|
+
res.status(500).json({
|
|
178
|
+
error: 'Failed to get account credentials',
|
|
179
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* PUT /api/integrations/accounts/:id
|
|
186
|
+
* 서비스 계정 수정
|
|
187
|
+
*/
|
|
188
|
+
router.put('/accounts/:id', async (req: Request, res: Response) => {
|
|
189
|
+
try {
|
|
190
|
+
const { id } = req.params;
|
|
191
|
+
const { name, environment, credentials, metadata } = req.body;
|
|
192
|
+
|
|
193
|
+
// environment 검증 (null, 'staging', 'production' 만 허용)
|
|
194
|
+
if (environment !== undefined) {
|
|
195
|
+
const validEnvironments = [null, 'staging', 'production'];
|
|
196
|
+
if (!validEnvironments.includes(environment)) {
|
|
197
|
+
res.status(400).json({
|
|
198
|
+
error: 'Invalid environment',
|
|
199
|
+
message: 'environment must be null, "staging", or "production"',
|
|
200
|
+
});
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const account = await updateServiceAccount(id, {
|
|
206
|
+
name,
|
|
207
|
+
environment,
|
|
208
|
+
credentials,
|
|
209
|
+
metadata,
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
if (!account) {
|
|
213
|
+
res.status(404).json({
|
|
214
|
+
error: 'Account not found',
|
|
215
|
+
message: `No service account found with id: ${id}`,
|
|
216
|
+
});
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
res.json({ account });
|
|
221
|
+
} catch (error) {
|
|
222
|
+
console.error('Failed to update service account:', error);
|
|
223
|
+
res.status(400).json({
|
|
224
|
+
error: 'Failed to update service account',
|
|
225
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* DELETE /api/integrations/accounts/:id
|
|
232
|
+
* 서비스 계정 삭제
|
|
233
|
+
*/
|
|
234
|
+
router.delete('/accounts/:id', async (req: Request, res: Response) => {
|
|
235
|
+
try {
|
|
236
|
+
const { id } = req.params;
|
|
237
|
+
const deleted = await deleteServiceAccount(id);
|
|
238
|
+
|
|
239
|
+
if (!deleted) {
|
|
240
|
+
res.status(404).json({
|
|
241
|
+
error: 'Account not found',
|
|
242
|
+
message: `No service account found with id: ${id}`,
|
|
243
|
+
});
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
res.json({ success: true });
|
|
248
|
+
} catch (error) {
|
|
249
|
+
console.error('Failed to delete service account:', error);
|
|
250
|
+
res.status(500).json({
|
|
251
|
+
error: 'Failed to delete service account',
|
|
252
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
/**
|
|
258
|
+
* GET /api/integrations/accounts/type/:type
|
|
259
|
+
* 서비스 타입별 계정 목록 (드롭다운용)
|
|
260
|
+
*/
|
|
261
|
+
router.get('/accounts/type/:type', async (req: Request, res: Response) => {
|
|
262
|
+
try {
|
|
263
|
+
const { type } = req.params;
|
|
264
|
+
const validTypes: ServiceType[] = ['github', 'supabase', 'vercel', 'sentry', 'custom'];
|
|
265
|
+
|
|
266
|
+
if (!validTypes.includes(type as ServiceType)) {
|
|
267
|
+
res.status(400).json({
|
|
268
|
+
error: 'Invalid service type',
|
|
269
|
+
message: `type must be one of: ${validTypes.join(', ')}`,
|
|
270
|
+
});
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
const accounts = await getAccountsByType(type as ServiceType);
|
|
275
|
+
res.json({ accounts });
|
|
276
|
+
} catch (error) {
|
|
277
|
+
console.error('Failed to get accounts by type:', error);
|
|
278
|
+
res.status(500).json({
|
|
279
|
+
error: 'Failed to get accounts by type',
|
|
280
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
// =============================================
|
|
286
|
+
// 프로젝트 연동 API
|
|
287
|
+
// =============================================
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* GET /api/integrations/projects/:projectId
|
|
291
|
+
* 프로젝트 연동 조회
|
|
292
|
+
*/
|
|
293
|
+
router.get('/projects/:projectId', async (req: Request, res: Response) => {
|
|
294
|
+
try {
|
|
295
|
+
const { projectId } = req.params;
|
|
296
|
+
const integration = await getProjectIntegration(projectId);
|
|
297
|
+
|
|
298
|
+
res.json({ integration });
|
|
299
|
+
} catch (error) {
|
|
300
|
+
console.error('Failed to get project integration:', error);
|
|
301
|
+
res.status(500).json({
|
|
302
|
+
error: 'Failed to get project integration',
|
|
303
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* PUT /api/integrations/projects/:projectId
|
|
310
|
+
* 프로젝트 연동 설정
|
|
311
|
+
*/
|
|
312
|
+
router.put('/projects/:projectId', async (req: Request, res: Response) => {
|
|
313
|
+
try {
|
|
314
|
+
const { projectId } = req.params;
|
|
315
|
+
const { integrations, defaultEnvironment } = req.body;
|
|
316
|
+
|
|
317
|
+
const integration = await upsertProjectIntegration(
|
|
318
|
+
projectId,
|
|
319
|
+
integrations || {},
|
|
320
|
+
defaultEnvironment
|
|
321
|
+
);
|
|
322
|
+
|
|
323
|
+
res.json({ integration });
|
|
324
|
+
} catch (error) {
|
|
325
|
+
console.error('Failed to update project integration:', error);
|
|
326
|
+
res.status(500).json({
|
|
327
|
+
error: 'Failed to update project integration',
|
|
328
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* PUT /api/integrations/projects/:projectId/services/:serviceType
|
|
335
|
+
* 프로젝트에 서비스 계정 연결
|
|
336
|
+
*/
|
|
337
|
+
router.put('/projects/:projectId/services/:serviceType', async (req: Request, res: Response) => {
|
|
338
|
+
try {
|
|
339
|
+
const { projectId, serviceType } = req.params;
|
|
340
|
+
const { accountId } = req.body;
|
|
341
|
+
|
|
342
|
+
const validTypes: ServiceType[] = ['github', 'supabase', 'vercel', 'sentry', 'custom'];
|
|
343
|
+
if (!validTypes.includes(serviceType as ServiceType)) {
|
|
344
|
+
res.status(400).json({
|
|
345
|
+
error: 'Invalid service type',
|
|
346
|
+
message: `serviceType must be one of: ${validTypes.join(', ')}`,
|
|
347
|
+
});
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const integration = await setProjectService(
|
|
352
|
+
projectId,
|
|
353
|
+
serviceType as ServiceType,
|
|
354
|
+
accountId || null
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
res.json({ integration });
|
|
358
|
+
} catch (error) {
|
|
359
|
+
console.error('Failed to set project service:', error);
|
|
360
|
+
res.status(500).json({
|
|
361
|
+
error: 'Failed to set project service',
|
|
362
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* GET /api/integrations/projects/:projectId/context
|
|
369
|
+
* 프로젝트 컨텍스트 조회 (AI용, 민감정보 제외)
|
|
370
|
+
* 로컬 설정(.zyflow/)이 있으면 우선 사용
|
|
371
|
+
* @query projectPath - 프로젝트 경로 (로컬 설정 조회용, 선택사항)
|
|
372
|
+
*/
|
|
373
|
+
router.get('/projects/:projectId/context', async (req: Request, res: Response) => {
|
|
374
|
+
try {
|
|
375
|
+
const { projectId } = req.params;
|
|
376
|
+
const projectPath = req.query.projectPath as string | undefined;
|
|
377
|
+
|
|
378
|
+
// 로컬 설정 우선 조회
|
|
379
|
+
if (projectPath) {
|
|
380
|
+
try {
|
|
381
|
+
const resolver = new SettingsResolver(projectPath, projectId);
|
|
382
|
+
const context = await resolver.getContext();
|
|
383
|
+
res.json({
|
|
384
|
+
context,
|
|
385
|
+
source: context.source,
|
|
386
|
+
sources: context.sources,
|
|
387
|
+
});
|
|
388
|
+
return;
|
|
389
|
+
} catch {
|
|
390
|
+
// 로컬 조회 실패 시 전역으로 fallback
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// 전역 DB에서 조회
|
|
395
|
+
const context = await getProjectContext(projectId);
|
|
396
|
+
res.json({
|
|
397
|
+
context,
|
|
398
|
+
source: 'global' as const,
|
|
399
|
+
});
|
|
400
|
+
} catch (error) {
|
|
401
|
+
console.error('Failed to get project context:', error);
|
|
402
|
+
res.status(500).json({
|
|
403
|
+
error: 'Failed to get project context',
|
|
404
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// =============================================
|
|
410
|
+
// 환경 설정 API
|
|
411
|
+
// =============================================
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* GET /api/integrations/projects/:projectId/environments
|
|
415
|
+
* 프로젝트 환경 목록 조회 (로컬 우선, 전역 fallback)
|
|
416
|
+
* Query params:
|
|
417
|
+
* - projectPath: 프로젝트 경로 (로컬 설정 조회 시 필요)
|
|
418
|
+
*/
|
|
419
|
+
router.get('/projects/:projectId/environments', async (req: Request, res: Response) => {
|
|
420
|
+
try {
|
|
421
|
+
const { projectId } = req.params;
|
|
422
|
+
const projectPath = req.query.projectPath as string | undefined;
|
|
423
|
+
|
|
424
|
+
// 로컬 설정이 있으면 로컬 우선
|
|
425
|
+
if (projectPath) {
|
|
426
|
+
const resolver = new SettingsResolver(projectPath, projectId);
|
|
427
|
+
const envList = await resolver.listEnvironments();
|
|
428
|
+
|
|
429
|
+
// ResolvedEnvironment[] 형식으로 변환
|
|
430
|
+
const environments = await Promise.all(
|
|
431
|
+
envList.map(async (env) => {
|
|
432
|
+
const resolved = await resolver.getEnvironment(env.name);
|
|
433
|
+
return {
|
|
434
|
+
id: `local-${env.name}`,
|
|
435
|
+
name: env.name,
|
|
436
|
+
isActive: env.isActive,
|
|
437
|
+
source: env.source,
|
|
438
|
+
hasVariables: resolved ? Object.keys(resolved.variables).length > 0 : false,
|
|
439
|
+
};
|
|
440
|
+
})
|
|
441
|
+
);
|
|
442
|
+
|
|
443
|
+
res.json({ environments, source: 'hybrid' as const });
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// 전역 DB에서 조회
|
|
448
|
+
const environments = await listEnvironments(projectId);
|
|
449
|
+
res.json({
|
|
450
|
+
environments: environments.map((e) => ({ ...e, source: 'global' as const })),
|
|
451
|
+
source: 'global' as const,
|
|
452
|
+
});
|
|
453
|
+
} catch (error) {
|
|
454
|
+
console.error('Failed to list environments:', error);
|
|
455
|
+
res.status(500).json({
|
|
456
|
+
error: 'Failed to list environments',
|
|
457
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
/**
|
|
463
|
+
* POST /api/integrations/projects/:projectId/environments
|
|
464
|
+
* 환경 생성
|
|
465
|
+
*/
|
|
466
|
+
router.post('/projects/:projectId/environments', async (req: Request, res: Response) => {
|
|
467
|
+
try {
|
|
468
|
+
const { projectId } = req.params;
|
|
469
|
+
const { name, variables, serverUrl, databaseUrl, description, isActive } = req.body;
|
|
470
|
+
|
|
471
|
+
if (!name || !variables) {
|
|
472
|
+
res.status(400).json({
|
|
473
|
+
error: 'Missing required fields',
|
|
474
|
+
message: 'name and variables are required',
|
|
475
|
+
});
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
const environment = await createEnvironment(projectId, name, variables, {
|
|
480
|
+
serverUrl,
|
|
481
|
+
databaseUrl,
|
|
482
|
+
description,
|
|
483
|
+
isActive,
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
res.status(201).json({ environment });
|
|
487
|
+
} catch (error) {
|
|
488
|
+
console.error('Failed to create environment:', error);
|
|
489
|
+
res.status(400).json({
|
|
490
|
+
error: 'Failed to create environment',
|
|
491
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* PUT /api/integrations/projects/:projectId/environments/:envId
|
|
498
|
+
* 환경 수정
|
|
499
|
+
*/
|
|
500
|
+
router.put('/projects/:projectId/environments/:envId', async (req: Request, res: Response) => {
|
|
501
|
+
try {
|
|
502
|
+
const { envId } = req.params;
|
|
503
|
+
const { name, variables, serverUrl, databaseUrl, description } = req.body;
|
|
504
|
+
|
|
505
|
+
const environment = await updateEnvironment(envId, {
|
|
506
|
+
name,
|
|
507
|
+
variables,
|
|
508
|
+
serverUrl,
|
|
509
|
+
databaseUrl,
|
|
510
|
+
description,
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
if (!environment) {
|
|
514
|
+
res.status(404).json({
|
|
515
|
+
error: 'Environment not found',
|
|
516
|
+
message: `No environment found with id: ${envId}`,
|
|
517
|
+
});
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
res.json({ environment });
|
|
522
|
+
} catch (error) {
|
|
523
|
+
console.error('Failed to update environment:', error);
|
|
524
|
+
res.status(400).json({
|
|
525
|
+
error: 'Failed to update environment',
|
|
526
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
527
|
+
});
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* DELETE /api/integrations/projects/:projectId/environments/:envId
|
|
533
|
+
* 환경 삭제
|
|
534
|
+
*/
|
|
535
|
+
router.delete('/projects/:projectId/environments/:envId', async (req: Request, res: Response) => {
|
|
536
|
+
try {
|
|
537
|
+
const { envId } = req.params;
|
|
538
|
+
const deleted = await deleteEnvironment(envId);
|
|
539
|
+
|
|
540
|
+
if (!deleted) {
|
|
541
|
+
res.status(404).json({
|
|
542
|
+
error: 'Environment not found',
|
|
543
|
+
message: `No environment found with id: ${envId}`,
|
|
544
|
+
});
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
res.json({ success: true });
|
|
549
|
+
} catch (error) {
|
|
550
|
+
console.error('Failed to delete environment:', error);
|
|
551
|
+
res.status(500).json({
|
|
552
|
+
error: 'Failed to delete environment',
|
|
553
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* PUT /api/integrations/projects/:projectId/environments/:envId/activate
|
|
560
|
+
* 환경 활성화
|
|
561
|
+
*/
|
|
562
|
+
router.put('/projects/:projectId/environments/:envId/activate', async (req: Request, res: Response) => {
|
|
563
|
+
try {
|
|
564
|
+
const { projectId, envId } = req.params;
|
|
565
|
+
await setActiveEnvironment(projectId, envId);
|
|
566
|
+
|
|
567
|
+
res.json({ success: true });
|
|
568
|
+
} catch (error) {
|
|
569
|
+
console.error('Failed to activate environment:', error);
|
|
570
|
+
res.status(500).json({
|
|
571
|
+
error: 'Failed to activate environment',
|
|
572
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* GET /api/integrations/projects/:projectId/environments/:envId/variables
|
|
579
|
+
* 환경 변수 조회 (복호화된 원본)
|
|
580
|
+
*/
|
|
581
|
+
router.get('/projects/:projectId/environments/:envId/variables', async (req: Request, res: Response) => {
|
|
582
|
+
try {
|
|
583
|
+
const { envId } = req.params;
|
|
584
|
+
const variables = await getEnvironmentVariables(envId);
|
|
585
|
+
|
|
586
|
+
if (variables === null) {
|
|
587
|
+
res.status(404).json({
|
|
588
|
+
error: 'Environment not found',
|
|
589
|
+
message: `No environment found with id: ${envId}`,
|
|
590
|
+
});
|
|
591
|
+
return;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
res.json({ variables });
|
|
595
|
+
} catch (error) {
|
|
596
|
+
console.error('Failed to get environment variables:', error);
|
|
597
|
+
res.status(500).json({
|
|
598
|
+
error: 'Failed to get environment variables',
|
|
599
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
// =============================================
|
|
605
|
+
// 테스트 계정 API
|
|
606
|
+
// =============================================
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* GET /api/integrations/projects/:projectId/test-accounts
|
|
610
|
+
* 프로젝트 테스트 계정 목록 조회 (로컬 우선, 전역 fallback)
|
|
611
|
+
* Query params:
|
|
612
|
+
* - projectPath: 프로젝트 경로 (로컬 설정 조회 시 필요)
|
|
613
|
+
* - role: 역할 필터 (선택)
|
|
614
|
+
*/
|
|
615
|
+
router.get('/projects/:projectId/test-accounts', async (req: Request, res: Response) => {
|
|
616
|
+
try {
|
|
617
|
+
const { projectId } = req.params;
|
|
618
|
+
const projectPath = req.query.projectPath as string | undefined;
|
|
619
|
+
const role = req.query.role as string | undefined;
|
|
620
|
+
|
|
621
|
+
// 로컬 설정이 있으면 로컬 우선
|
|
622
|
+
if (projectPath) {
|
|
623
|
+
const resolver = new SettingsResolver(projectPath, projectId);
|
|
624
|
+
const resolvedAccounts = await resolver.getTestAccounts(role);
|
|
625
|
+
|
|
626
|
+
// 비밀번호 제외하고 반환 (보안)
|
|
627
|
+
const accounts = resolvedAccounts.map((a) => ({
|
|
628
|
+
id: a.id,
|
|
629
|
+
role: a.role,
|
|
630
|
+
email: a.email,
|
|
631
|
+
description: a.description,
|
|
632
|
+
source: a.source,
|
|
633
|
+
}));
|
|
634
|
+
|
|
635
|
+
res.json({
|
|
636
|
+
accounts,
|
|
637
|
+
source: accounts.length > 0 ? accounts[0].source : 'global',
|
|
638
|
+
});
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
// 전역 DB에서 조회
|
|
643
|
+
let accounts = await listTestAccounts(projectId);
|
|
644
|
+
if (role) {
|
|
645
|
+
accounts = accounts.filter((a) => a.role.toLowerCase().includes(role.toLowerCase()));
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
res.json({
|
|
649
|
+
accounts: accounts.map((a) => ({ ...a, source: 'global' as const })),
|
|
650
|
+
source: 'global' as const,
|
|
651
|
+
});
|
|
652
|
+
} catch (error) {
|
|
653
|
+
console.error('Failed to list test accounts:', error);
|
|
654
|
+
res.status(500).json({
|
|
655
|
+
error: 'Failed to list test accounts',
|
|
656
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* POST /api/integrations/projects/:projectId/test-accounts
|
|
663
|
+
* 테스트 계정 생성
|
|
664
|
+
*/
|
|
665
|
+
router.post('/projects/:projectId/test-accounts', async (req: Request, res: Response) => {
|
|
666
|
+
try {
|
|
667
|
+
const { projectId } = req.params;
|
|
668
|
+
const { role, email, password, description } = req.body;
|
|
669
|
+
|
|
670
|
+
if (!role || !email || !password) {
|
|
671
|
+
res.status(400).json({
|
|
672
|
+
error: 'Missing required fields',
|
|
673
|
+
message: 'role, email, and password are required',
|
|
674
|
+
});
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
const account = await createTestAccount(projectId, role, email, password, description);
|
|
679
|
+
|
|
680
|
+
res.status(201).json({ account });
|
|
681
|
+
} catch (error) {
|
|
682
|
+
console.error('Failed to create test account:', error);
|
|
683
|
+
res.status(400).json({
|
|
684
|
+
error: 'Failed to create test account',
|
|
685
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
});
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* PUT /api/integrations/projects/:projectId/test-accounts/:id
|
|
692
|
+
* 테스트 계정 수정
|
|
693
|
+
*/
|
|
694
|
+
router.put('/projects/:projectId/test-accounts/:id', async (req: Request, res: Response) => {
|
|
695
|
+
try {
|
|
696
|
+
const { id } = req.params;
|
|
697
|
+
const { role, email, password, description } = req.body;
|
|
698
|
+
|
|
699
|
+
const account = await updateTestAccount(id, {
|
|
700
|
+
role,
|
|
701
|
+
email,
|
|
702
|
+
password,
|
|
703
|
+
description,
|
|
704
|
+
});
|
|
705
|
+
|
|
706
|
+
if (!account) {
|
|
707
|
+
res.status(404).json({
|
|
708
|
+
error: 'Test account not found',
|
|
709
|
+
message: `No test account found with id: ${id}`,
|
|
710
|
+
});
|
|
711
|
+
return;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
res.json({ account });
|
|
715
|
+
} catch (error) {
|
|
716
|
+
console.error('Failed to update test account:', error);
|
|
717
|
+
res.status(400).json({
|
|
718
|
+
error: 'Failed to update test account',
|
|
719
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* DELETE /api/integrations/projects/:projectId/test-accounts/:id
|
|
726
|
+
* 테스트 계정 삭제
|
|
727
|
+
*/
|
|
728
|
+
router.delete('/projects/:projectId/test-accounts/:id', async (req: Request, res: Response) => {
|
|
729
|
+
try {
|
|
730
|
+
const { id } = req.params;
|
|
731
|
+
const deleted = await deleteTestAccount(id);
|
|
732
|
+
|
|
733
|
+
if (!deleted) {
|
|
734
|
+
res.status(404).json({
|
|
735
|
+
error: 'Test account not found',
|
|
736
|
+
message: `No test account found with id: ${id}`,
|
|
737
|
+
});
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
res.json({ success: true });
|
|
742
|
+
} catch (error) {
|
|
743
|
+
console.error('Failed to delete test account:', error);
|
|
744
|
+
res.status(500).json({
|
|
745
|
+
error: 'Failed to delete test account',
|
|
746
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
/**
|
|
752
|
+
* GET /api/integrations/projects/:projectId/test-accounts/:id/password
|
|
753
|
+
* 테스트 계정 비밀번호 조회 (복호화된 원본 - 복사 기능용)
|
|
754
|
+
*/
|
|
755
|
+
router.get('/projects/:projectId/test-accounts/:id/password', async (req: Request, res: Response) => {
|
|
756
|
+
try {
|
|
757
|
+
const { id } = req.params;
|
|
758
|
+
const password = await getTestAccountPassword(id);
|
|
759
|
+
|
|
760
|
+
if (password === null) {
|
|
761
|
+
res.status(404).json({
|
|
762
|
+
error: 'Test account not found',
|
|
763
|
+
message: `No test account found with id: ${id}`,
|
|
764
|
+
});
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
res.json({ password });
|
|
769
|
+
} catch (error) {
|
|
770
|
+
console.error('Failed to get test account password:', error);
|
|
771
|
+
res.status(500).json({
|
|
772
|
+
error: 'Failed to get test account password',
|
|
773
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
// =============================================
|
|
779
|
+
// 환경변수 임포트 API
|
|
780
|
+
// =============================================
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* GET /api/integrations/env/files
|
|
784
|
+
* 프로젝트의 .env 파일 목록 조회
|
|
785
|
+
*/
|
|
786
|
+
router.get('/env/files', async (req: Request, res: Response) => {
|
|
787
|
+
try {
|
|
788
|
+
const projectPath = req.query.projectPath as string;
|
|
789
|
+
|
|
790
|
+
if (!projectPath) {
|
|
791
|
+
res.status(400).json({
|
|
792
|
+
error: 'Missing required parameter',
|
|
793
|
+
message: 'projectPath query parameter is required',
|
|
794
|
+
});
|
|
795
|
+
return;
|
|
796
|
+
}
|
|
797
|
+
|
|
798
|
+
const files = await listEnvFiles(projectPath);
|
|
799
|
+
res.json({ files });
|
|
800
|
+
} catch (error) {
|
|
801
|
+
console.error('Failed to list env files:', error);
|
|
802
|
+
res.status(500).json({
|
|
803
|
+
error: 'Failed to list env files',
|
|
804
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* GET /api/integrations/env/scan
|
|
811
|
+
* 프로젝트의 .env 파일 스캔 및 서비스 감지
|
|
812
|
+
* @query projectPath - 프로젝트 경로 (필수)
|
|
813
|
+
* @query files - 스캔할 파일 목록 (쉼표 구분, 선택사항 - 미지정시 모든 파일)
|
|
814
|
+
*/
|
|
815
|
+
router.get('/env/scan', async (req: Request, res: Response) => {
|
|
816
|
+
try {
|
|
817
|
+
const projectPath = req.query.projectPath as string;
|
|
818
|
+
const filesParam = req.query.files as string | undefined;
|
|
819
|
+
|
|
820
|
+
if (!projectPath) {
|
|
821
|
+
res.status(400).json({
|
|
822
|
+
error: 'Missing required parameter',
|
|
823
|
+
message: 'projectPath query parameter is required',
|
|
824
|
+
});
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// 파일 목록 파싱 (쉼표 구분)
|
|
829
|
+
const selectedFiles = filesParam
|
|
830
|
+
? filesParam.split(',').map(f => f.trim()).filter(Boolean)
|
|
831
|
+
: undefined;
|
|
832
|
+
|
|
833
|
+
const result = await scanAndCacheProjectEnv(projectPath, selectedFiles);
|
|
834
|
+
res.json(result);
|
|
835
|
+
} catch (error) {
|
|
836
|
+
console.error('Failed to scan env files:', error);
|
|
837
|
+
res.status(500).json({
|
|
838
|
+
error: 'Failed to scan env files',
|
|
839
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
840
|
+
});
|
|
841
|
+
}
|
|
842
|
+
});
|
|
843
|
+
|
|
844
|
+
/**
|
|
845
|
+
* POST /api/integrations/env/import
|
|
846
|
+
* 선택한 서비스를 Integration Hub에 등록
|
|
847
|
+
*/
|
|
848
|
+
router.post('/env/import', async (req: Request, res: Response) => {
|
|
849
|
+
try {
|
|
850
|
+
const { projectPath, services } = req.body as {
|
|
851
|
+
projectPath: string;
|
|
852
|
+
services: ImportRequest['services'];
|
|
853
|
+
};
|
|
854
|
+
|
|
855
|
+
if (!projectPath || !services || !Array.isArray(services)) {
|
|
856
|
+
res.status(400).json({
|
|
857
|
+
error: 'Missing required fields',
|
|
858
|
+
message: 'projectPath and services array are required',
|
|
859
|
+
});
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
if (services.length === 0) {
|
|
864
|
+
res.status(400).json({
|
|
865
|
+
error: 'No services selected',
|
|
866
|
+
message: 'At least one service must be selected for import',
|
|
867
|
+
});
|
|
868
|
+
return;
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
const result = await importServices(projectPath, { services });
|
|
872
|
+
res.json(result);
|
|
873
|
+
} catch (error) {
|
|
874
|
+
console.error('Failed to import services:', error);
|
|
875
|
+
res.status(500).json({
|
|
876
|
+
error: 'Failed to import services',
|
|
877
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
});
|
|
881
|
+
|
|
882
|
+
// =============================================
|
|
883
|
+
// 시스템 설정 Import API
|
|
884
|
+
// =============================================
|
|
885
|
+
|
|
886
|
+
/**
|
|
887
|
+
* GET /api/integrations/system/scan
|
|
888
|
+
* 시스템 설정에서 사용 가능한 서비스 스캔
|
|
889
|
+
* (Git Config, gh CLI, AWS credentials, GCloud, Azure CLI 등)
|
|
890
|
+
* @query projectPath - 프로젝트 경로 (로컬 git config 조회 시 필요, 선택사항)
|
|
891
|
+
*/
|
|
892
|
+
router.get('/system/scan', async (req: Request, res: Response) => {
|
|
893
|
+
try {
|
|
894
|
+
const projectPath = req.query.projectPath as string | undefined;
|
|
895
|
+
const result = await scanAndCacheSystemSources(projectPath);
|
|
896
|
+
res.json(result);
|
|
897
|
+
} catch (error) {
|
|
898
|
+
console.error('Failed to scan system sources:', error);
|
|
899
|
+
res.status(500).json({
|
|
900
|
+
error: 'Failed to scan system sources',
|
|
901
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
});
|
|
905
|
+
|
|
906
|
+
/**
|
|
907
|
+
* POST /api/integrations/system/import
|
|
908
|
+
* 시스템 설정에서 선택한 서비스를 Integration Hub에 등록
|
|
909
|
+
*/
|
|
910
|
+
router.post('/system/import', async (req: Request, res: Response) => {
|
|
911
|
+
try {
|
|
912
|
+
const { projectPath, services } = req.body as {
|
|
913
|
+
projectPath?: string;
|
|
914
|
+
services: SystemImportRequest['services'];
|
|
915
|
+
};
|
|
916
|
+
|
|
917
|
+
if (!services || !Array.isArray(services)) {
|
|
918
|
+
res.status(400).json({
|
|
919
|
+
error: 'Missing required fields',
|
|
920
|
+
message: 'services array is required',
|
|
921
|
+
});
|
|
922
|
+
return;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
if (services.length === 0) {
|
|
926
|
+
res.status(400).json({
|
|
927
|
+
error: 'No services selected',
|
|
928
|
+
message: 'At least one service must be selected for import',
|
|
929
|
+
});
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
const result = await importSystemServices({ services }, projectPath);
|
|
934
|
+
res.json(result);
|
|
935
|
+
} catch (error) {
|
|
936
|
+
console.error('Failed to import system services:', error);
|
|
937
|
+
res.status(500).json({
|
|
938
|
+
error: 'Failed to import system services',
|
|
939
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
940
|
+
});
|
|
941
|
+
}
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
// =============================================
|
|
945
|
+
// 로컬 설정 API
|
|
946
|
+
// =============================================
|
|
947
|
+
|
|
948
|
+
/**
|
|
949
|
+
* POST /api/integrations/local/init
|
|
950
|
+
* 프로젝트에 .zyflow 디렉토리 초기화
|
|
951
|
+
*/
|
|
952
|
+
router.post('/local/init', async (req: Request, res: Response) => {
|
|
953
|
+
try {
|
|
954
|
+
const { projectPath } = req.body;
|
|
955
|
+
|
|
956
|
+
if (!projectPath) {
|
|
957
|
+
res.status(400).json({
|
|
958
|
+
error: 'Missing required field',
|
|
959
|
+
message: 'projectPath is required',
|
|
960
|
+
});
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
const result = await initLocalZyflow(projectPath);
|
|
965
|
+
res.json({
|
|
966
|
+
success: true,
|
|
967
|
+
data: result,
|
|
968
|
+
});
|
|
969
|
+
} catch (error) {
|
|
970
|
+
console.error('Failed to initialize local settings:', error);
|
|
971
|
+
res.status(500).json({
|
|
972
|
+
error: 'Failed to initialize local settings',
|
|
973
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
974
|
+
});
|
|
975
|
+
}
|
|
976
|
+
});
|
|
977
|
+
|
|
978
|
+
/**
|
|
979
|
+
* GET /api/integrations/local/status
|
|
980
|
+
* 프로젝트의 로컬 설정 상태 조회
|
|
981
|
+
*/
|
|
982
|
+
router.get('/local/status', async (req: Request, res: Response) => {
|
|
983
|
+
try {
|
|
984
|
+
const projectPath = req.query.projectPath as string;
|
|
985
|
+
|
|
986
|
+
if (!projectPath) {
|
|
987
|
+
res.status(400).json({
|
|
988
|
+
error: 'Missing required parameter',
|
|
989
|
+
message: 'projectPath query parameter is required',
|
|
990
|
+
});
|
|
991
|
+
return;
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
const resolver = new SettingsResolver(projectPath);
|
|
995
|
+
const sources = await resolver.getSettingsSources();
|
|
996
|
+
|
|
997
|
+
res.json({
|
|
998
|
+
success: true,
|
|
999
|
+
data: {
|
|
1000
|
+
projectPath,
|
|
1001
|
+
status: sources,
|
|
1002
|
+
},
|
|
1003
|
+
});
|
|
1004
|
+
} catch (error) {
|
|
1005
|
+
console.error('Failed to check local settings status:', error);
|
|
1006
|
+
res.status(500).json({
|
|
1007
|
+
error: 'Failed to check local settings status',
|
|
1008
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
1009
|
+
});
|
|
1010
|
+
}
|
|
1011
|
+
});
|
|
1012
|
+
|
|
1013
|
+
/**
|
|
1014
|
+
* POST /api/integrations/projects/:projectId/export-to-local
|
|
1015
|
+
* 전역 DB 설정을 프로젝트 로컬(.zyflow/)로 내보내기
|
|
1016
|
+
*/
|
|
1017
|
+
router.post('/projects/:projectId/export-to-local', async (req: Request, res: Response) => {
|
|
1018
|
+
try {
|
|
1019
|
+
const { projectId } = req.params;
|
|
1020
|
+
const { projectPath } = req.body;
|
|
1021
|
+
|
|
1022
|
+
if (!projectPath) {
|
|
1023
|
+
res.status(400).json({
|
|
1024
|
+
error: 'Missing required field',
|
|
1025
|
+
message: 'projectPath is required in request body',
|
|
1026
|
+
});
|
|
1027
|
+
return;
|
|
1028
|
+
}
|
|
1029
|
+
|
|
1030
|
+
// 1. 전역 DB에서 프로젝트 설정 조회
|
|
1031
|
+
const integration = await getProjectIntegration(projectId);
|
|
1032
|
+
const envList = await listEnvironments(projectId);
|
|
1033
|
+
const testAccountList = await listTestAccounts(projectId);
|
|
1034
|
+
|
|
1035
|
+
// 2. .zyflow 디렉토리 초기화 (없으면 생성)
|
|
1036
|
+
const initResult = await initLocalZyflow(projectPath);
|
|
1037
|
+
|
|
1038
|
+
// 3. settings.json 저장 (계정 매핑)
|
|
1039
|
+
if (integration?.integrations) {
|
|
1040
|
+
const localSettings = createDefaultLocalSettings();
|
|
1041
|
+
localSettings.integrations = integration.integrations as {
|
|
1042
|
+
github?: string;
|
|
1043
|
+
supabase?: string;
|
|
1044
|
+
vercel?: string;
|
|
1045
|
+
sentry?: string;
|
|
1046
|
+
custom?: Record<string, string>;
|
|
1047
|
+
};
|
|
1048
|
+
if (envList.length > 0) {
|
|
1049
|
+
const activeEnv = envList.find((e) => e.isActive);
|
|
1050
|
+
localSettings.defaultEnvironment = activeEnv?.name || envList[0].name;
|
|
1051
|
+
}
|
|
1052
|
+
await saveLocalSettings(projectPath, localSettings);
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
// 4. 환경 변수 파일 저장
|
|
1056
|
+
const exportedFiles: string[] = [...initResult.created];
|
|
1057
|
+
for (const env of envList) {
|
|
1058
|
+
const variables = await getEnvironmentVariables(env.id);
|
|
1059
|
+
if (variables && Object.keys(variables).length > 0) {
|
|
1060
|
+
await saveLocalEnvironment(projectPath, env.name, variables);
|
|
1061
|
+
exportedFiles.push(`environments/${env.name}.env`);
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
// 5. 테스트 계정 저장
|
|
1066
|
+
if (testAccountList.length > 0) {
|
|
1067
|
+
const localAccounts = await Promise.all(
|
|
1068
|
+
testAccountList.map(async (account) => {
|
|
1069
|
+
const password = await getTestAccountPassword(account.id);
|
|
1070
|
+
return {
|
|
1071
|
+
id: account.id,
|
|
1072
|
+
role: account.role,
|
|
1073
|
+
email: account.email,
|
|
1074
|
+
password: await encryptTestAccountPassword(password || ''),
|
|
1075
|
+
description: account.description ?? undefined,
|
|
1076
|
+
};
|
|
1077
|
+
})
|
|
1078
|
+
);
|
|
1079
|
+
await saveLocalTestAccounts(projectPath, localAccounts);
|
|
1080
|
+
exportedFiles.push('test-accounts.json');
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
res.json({
|
|
1084
|
+
success: true,
|
|
1085
|
+
data: {
|
|
1086
|
+
success: true,
|
|
1087
|
+
zyflowPath: initResult.zyflowPath,
|
|
1088
|
+
exported: exportedFiles,
|
|
1089
|
+
},
|
|
1090
|
+
});
|
|
1091
|
+
} catch (error) {
|
|
1092
|
+
console.error('Failed to export to local:', error);
|
|
1093
|
+
res.status(500).json({
|
|
1094
|
+
error: 'Failed to export to local',
|
|
1095
|
+
message: error instanceof Error ? error.message : 'Unknown error',
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
});
|
|
1099
|
+
|
|
1100
|
+
export default router;
|