@dyyz1993/create-agent 2.1.1 → 2.1.2
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/package.json +5 -4
- package/src/__tests__/cli.test.ts +2 -0
- package/src/__tests__/copy.test.ts +110 -122
- package/src/__tests__/create-args.test.ts +113 -0
- package/src/__tests__/templates.test.ts +29 -3
- package/src/__tests__/update.test.ts +129 -0
- package/src/cli.ts +30 -32
- package/src/commands/create.ts +83 -24
- package/src/commands/update.ts +174 -0
- package/src/commands/workspace.ts +26 -6
- package/src/lib/copy.ts +127 -91
- package/src/lib/templates.ts +12 -0
- package/templates/agent/.husky/commit-msg +4 -0
- package/templates/agent/.husky/pre-commit +11 -0
- package/templates/agent/.husky/pre-push +6 -0
- package/templates/agent/CHANGELOG.md +15 -0
- package/templates/agent/package.json +3 -3
- package/templates/agent/src/gateway/__tests__/ws-handler-token.test.ts +53 -39
- package/templates/agent/src/mainview/App.tsx +14 -12
- package/templates/agent/src/mainview/__tests__/hooks/use-rpc-init.test.ts +194 -190
- package/templates/agent/src/mainview/components/bash/BashPanel.tsx +210 -189
- package/templates/agent/src/mainview/components/chat/ChatPanel.tsx +45 -20
- package/templates/agent/src/mainview/components/common/ThemeToggle.tsx +41 -21
- package/templates/agent/src/mainview/components/debug/DebugPanel.tsx +181 -114
- package/templates/agent/src/mainview/components/debug/__tests__/DebugPanel.test.tsx +80 -80
- package/templates/agent/src/mainview/components/diff/__tests__/DiffViewerPanel.test.tsx +61 -58
- package/templates/agent/src/mainview/components/feed/FeedPanel.tsx +43 -41
- package/templates/agent/src/mainview/components/file-preview/FilePreviewOverlay.tsx +69 -50
- package/templates/agent/src/mainview/components/file-preview/VirtualizedCodeView.tsx +31 -18
- package/templates/agent/src/mainview/components/git/GitPanel.tsx +731 -490
- package/templates/agent/src/mainview/components/git/__tests__/GitPanel.test.tsx +157 -139
- package/templates/agent/src/mainview/components/layout/AppLayout.tsx +210 -161
- package/templates/agent/src/mainview/components/layout/__tests__/AppLayout.test.tsx +130 -122
- package/templates/agent/src/mainview/components/rules/RulesPanel.tsx +119 -109
- package/templates/agent/src/mainview/components/search/SearchPanel.tsx +123 -117
- package/templates/agent/src/mainview/components/search/__tests__/SearchPanel.test.tsx +64 -44
- package/templates/agent/src/mainview/components/sidebar/__tests__/PinButton.test.tsx +38 -38
- package/templates/agent/src/mainview/components/todo/TodoPanel.tsx +40 -38
- package/templates/agent/src/mainview/components/todo/__tests__/TodoPanel.test.tsx +72 -72
- package/templates/agent/src/mainview/lib/i18n/locales/en.json +175 -155
- package/templates/agent/src/mainview/lib/i18n/locales/zh.json +173 -155
- package/templates/agent/src/mainview/stores/use-app-store.ts +96 -86
- package/templates/agent/src/mainview/stores/use-explorer-store.ts +292 -275
- package/templates/agent/src/mainview/types/index.ts +23 -22
- package/templates/agent/src/mainview/utils/file-icon.tsx +17 -21
- package/templates/agent/src/shared/handlers/chat.ts +53 -53
- package/templates/agent/src/shared/handlers/debug.ts +13 -3
- package/templates/browser-agent/.env.example +19 -0
- package/templates/browser-agent/.husky/commit-msg +4 -0
- package/templates/browser-agent/.husky/pre-commit +11 -0
- package/templates/browser-agent/.husky/pre-push +6 -0
- package/templates/browser-agent/.prettierignore +6 -0
- package/templates/browser-agent/.prettierrc +9 -0
- package/templates/browser-agent/AGENTS.md +396 -0
- package/templates/browser-agent/CHANGELOG.md +15 -0
- package/templates/browser-agent/LICENSE +21 -0
- package/templates/browser-agent/README.md +103 -0
- package/templates/browser-agent/commitlint.config.js +8 -0
- package/templates/browser-agent/electrobun.config.ts +27 -0
- package/templates/browser-agent/electron/main.js +46 -0
- package/templates/browser-agent/electron/preload.js +5 -0
- package/templates/browser-agent/electron-builder.json +40 -0
- package/templates/browser-agent/eslint.config.mjs +79 -0
- package/templates/browser-agent/llms.txt +24 -0
- package/templates/browser-agent/package.json +140 -0
- package/templates/browser-agent/postcss.config.js +6 -0
- package/templates/browser-agent/scripts/dev.ts +138 -0
- package/templates/browser-agent/src/__tests__/hybrid-mode.test.ts +126 -0
- package/templates/browser-agent/src/__tests__/server-config-security.test.ts +55 -0
- package/templates/browser-agent/src/__tests__/server-config.test.ts +59 -0
- package/templates/browser-agent/src/bun/index.ts +130 -0
- package/templates/browser-agent/src/bun/three.d.ts +1 -0
- package/templates/browser-agent/src/gateway/http-routes.ts +1 -0
- package/templates/browser-agent/src/gateway/ipc-transport.ts +68 -0
- package/templates/browser-agent/src/gateway/sse-transport.ts +221 -0
- package/templates/browser-agent/src/mainview/App.tsx +45 -0
- package/templates/browser-agent/src/mainview/__tests__/hooks/use-rpc-init.test.ts +202 -0
- package/templates/browser-agent/src/mainview/__tests__/hooks/use-sidebar-resize.test.ts +127 -0
- package/templates/browser-agent/src/mainview/__tests__/i18n/i18n.test.ts +49 -0
- package/templates/browser-agent/src/mainview/__tests__/setup.ts +40 -0
- package/templates/browser-agent/src/mainview/__tests__/stores/use-chat-store.test.ts +73 -0
- package/templates/browser-agent/src/mainview/__tests__/stores/use-sidebar-store.test.ts +61 -0
- package/templates/browser-agent/src/mainview/__tests__/theme-variables.test.ts +36 -0
- package/templates/browser-agent/src/mainview/components/assets/AssetsPanel.tsx +139 -0
- package/templates/browser-agent/src/mainview/components/chat/ChatPanel.tsx +219 -0
- package/templates/browser-agent/src/mainview/components/chat/CommandBar.tsx +184 -0
- package/templates/browser-agent/src/mainview/components/chat/MessageBubble.tsx +249 -0
- package/templates/browser-agent/src/mainview/components/chat/ToolPicker.tsx +115 -0
- package/templates/browser-agent/src/mainview/components/common/ErrorBoundary.tsx +1 -0
- package/templates/browser-agent/src/mainview/components/common/LanguageSwitcher.tsx +15 -0
- package/templates/browser-agent/src/mainview/components/common/ThemeToggle.tsx +45 -0
- package/templates/browser-agent/src/mainview/components/common/__tests__/ErrorBoundary.test.tsx +74 -0
- package/templates/browser-agent/src/mainview/components/common/__tests__/LanguageSwitcher.test.tsx +44 -0
- package/templates/browser-agent/src/mainview/components/common/__tests__/ThemeToggle.test.tsx +41 -0
- package/templates/browser-agent/src/mainview/components/dev/NetworkPanel.tsx +155 -0
- package/templates/browser-agent/src/mainview/components/layout/AppLayout.tsx +311 -0
- package/templates/browser-agent/src/mainview/components/onboarding/SetupWizard.tsx +310 -0
- package/templates/browser-agent/src/mainview/components/process/ProcessPanel.tsx +329 -0
- package/templates/browser-agent/src/mainview/components/sidebar/SessionSidebar.tsx +122 -0
- package/templates/browser-agent/src/mainview/components/sidebar/SkillSidebar.tsx +115 -0
- package/templates/browser-agent/src/mainview/components/topbar/TopBar.tsx +350 -0
- package/templates/browser-agent/src/mainview/global.d.ts +13 -0
- package/templates/browser-agent/src/mainview/hooks/__tests__/use-breakpoint.test.ts +151 -0
- package/templates/browser-agent/src/mainview/hooks/use-agent-chat.ts +157 -0
- package/templates/browser-agent/src/mainview/hooks/use-breakpoint.ts +68 -0
- package/templates/browser-agent/src/mainview/hooks/use-rpc-init.ts +71 -0
- package/templates/browser-agent/src/mainview/hooks/use-sidebar-resize.ts +40 -0
- package/templates/browser-agent/src/mainview/index.css +71 -0
- package/templates/browser-agent/src/mainview/index.html +12 -0
- package/templates/browser-agent/src/mainview/lib/api-client.ts +397 -0
- package/templates/browser-agent/src/mainview/lib/i18n/index.ts +30 -0
- package/templates/browser-agent/src/mainview/lib/i18n/locales/en.json +130 -0
- package/templates/browser-agent/src/mainview/lib/i18n/locales/zh.json +128 -0
- package/templates/browser-agent/src/mainview/lib/network-bus.ts +92 -0
- package/templates/browser-agent/src/mainview/lib/rpc-cache.ts +94 -0
- package/templates/browser-agent/src/mainview/main.tsx +18 -0
- package/templates/browser-agent/src/mainview/stores/__tests__/use-connection-store.test.ts +26 -0
- package/templates/browser-agent/src/mainview/stores/__tests__/use-locale-store.test.ts +32 -0
- package/templates/browser-agent/src/mainview/stores/__tests__/use-log-store.test.ts +28 -0
- package/templates/browser-agent/src/mainview/stores/__tests__/use-theme-store.test.ts +59 -0
- package/templates/browser-agent/src/mainview/stores/message-batcher.ts +25 -0
- package/templates/browser-agent/src/mainview/stores/use-asset-store.ts +65 -0
- package/templates/browser-agent/src/mainview/stores/use-chat-store.ts +200 -0
- package/templates/browser-agent/src/mainview/stores/use-connection-store.ts +173 -0
- package/templates/browser-agent/src/mainview/stores/use-locale-store.ts +27 -0
- package/templates/browser-agent/src/mainview/stores/use-log-store.ts +16 -0
- package/templates/browser-agent/src/mainview/stores/use-network-panel-store.ts +18 -0
- package/templates/browser-agent/src/mainview/stores/use-record-store.ts +147 -0
- package/templates/browser-agent/src/mainview/stores/use-session-store.ts +151 -0
- package/templates/browser-agent/src/mainview/stores/use-sidebar-store.ts +161 -0
- package/templates/browser-agent/src/mainview/stores/use-theme-store.ts +46 -0
- package/templates/browser-agent/src/mainview/stores/use-view-store.ts +20 -0
- package/templates/browser-agent/src/mainview/types/index.ts +6 -0
- package/templates/browser-agent/src/server-config.ts +45 -0
- package/templates/browser-agent/src/server.ts +78 -0
- package/templates/browser-agent/src/shared/handlers/__tests__/chat-concurrency.test.ts +127 -0
- package/templates/browser-agent/src/shared/handlers/__tests__/chat-handler.test.ts +77 -0
- package/templates/browser-agent/src/shared/handlers/__tests__/file-handler.test.ts +100 -0
- package/templates/browser-agent/src/shared/handlers/__tests__/system-handler.test.ts +55 -0
- package/templates/browser-agent/src/shared/handlers/__tests__/timer-handler.test.ts +77 -0
- package/templates/browser-agent/src/shared/handlers/browser.ts +596 -0
- package/templates/browser-agent/src/shared/handlers/chat.ts +213 -0
- package/templates/browser-agent/src/shared/handlers/file.ts +99 -0
- package/templates/browser-agent/src/shared/handlers/index.ts +7 -0
- package/templates/browser-agent/src/shared/handlers/session.ts +167 -0
- package/templates/browser-agent/src/shared/handlers/system.ts +27 -0
- package/templates/browser-agent/src/shared/handlers/timer.ts +34 -0
- package/templates/browser-agent/src/shared/http-routes.ts +437 -0
- package/templates/browser-agent/src/shared/lib/__tests__/logger.test.ts +92 -0
- package/templates/browser-agent/src/shared/lib/__tests__/path-security.test.ts +77 -0
- package/templates/browser-agent/src/shared/lib/__tests__/web-server.test.ts +203 -0
- package/templates/browser-agent/src/shared/lib/agent.ts +384 -0
- package/templates/browser-agent/src/shared/lib/cdp.ts +448 -0
- package/templates/browser-agent/src/shared/lib/generate.ts +111 -0
- package/templates/browser-agent/src/shared/lib/logger.ts +152 -0
- package/templates/browser-agent/src/shared/lib/mock-stream.ts +147 -0
- package/templates/browser-agent/src/shared/lib/path-security.ts +38 -0
- package/templates/browser-agent/src/shared/lib/port-registry.ts +103 -0
- package/templates/browser-agent/src/shared/lib/web-server.ts +127 -0
- package/templates/browser-agent/src/shared/lib/xhs-extract.ts +71 -0
- package/templates/browser-agent/src/shared/modules/browser.ts +86 -0
- package/templates/browser-agent/src/shared/modules/chat.ts +20 -0
- package/templates/browser-agent/src/shared/modules/file.ts +40 -0
- package/templates/browser-agent/src/shared/modules/session.ts +55 -0
- package/templates/browser-agent/src/shared/modules/system.ts +8 -0
- package/templates/browser-agent/src/shared/modules/timer.ts +11 -0
- package/templates/browser-agent/src/shared/register-all-handlers.ts +36 -0
- package/templates/browser-agent/src/shared/rpc-schema.ts +34 -0
- package/templates/browser-agent/tailwind.config.js +15 -0
- package/templates/browser-agent/tsconfig.ipc.json +14 -0
- package/templates/browser-agent/tsconfig.json +36 -0
- package/templates/browser-agent/vite.config.ts +3 -0
- package/templates/browser-agent/vitest.config.ts +3 -0
- package/templates/chat/.husky/commit-msg +4 -0
- package/templates/chat/.husky/pre-commit +11 -0
- package/templates/chat/.husky/pre-push +6 -0
- package/templates/chat/CHANGELOG.md +15 -0
- package/templates/chat/commitlint.config.js +8 -0
- package/templates/chat/package.json +19 -4
- package/templates/chat/src/mainview/__tests__/hooks/use-input-history.test.ts +125 -0
- package/templates/chat/src/mainview/__tests__/setup.ts +32 -29
- package/templates/chat/src/mainview/components/chat/ChatPanel.tsx +80 -55
- package/templates/chat/src/mainview/components/common/ThemeToggle.tsx +40 -20
- package/templates/chat/src/mainview/lib/i18n/locales/en.json +175 -155
- package/templates/chat/src/mainview/lib/i18n/locales/zh.json +173 -155
- package/templates/chat/src/shared/handlers/chat.ts +17 -19
- package/templates/chat/src/shared/handlers/debug.ts +12 -2
- package/templates/cowork/.env.example +8 -0
- package/templates/cowork/.prettierignore +6 -0
- package/templates/cowork/.prettierrc +9 -0
- package/templates/cowork/AGENTS.md +236 -0
- package/templates/cowork/CHANGELOG.md +15 -0
- package/templates/cowork/LICENSE +21 -0
- package/templates/cowork/README.md +103 -0
- package/templates/cowork/commitlint.config.js +8 -0
- package/templates/cowork/docs/CODE-VIEW-PLAN.md +637 -0
- package/templates/cowork/docs/CODE-VIEW-V2.md +196 -0
- package/templates/cowork/docs/CODE-VIEW-V4.md +150 -0
- package/templates/cowork/electrobun.config.ts +27 -0
- package/templates/cowork/eslint.config.mjs +79 -0
- package/templates/cowork/llms.txt +24 -0
- package/templates/cowork/package.json +87 -0
- package/templates/cowork/postcss.config.js +6 -0
- package/templates/cowork/scripts/dev.ts +138 -0
- package/templates/cowork/src/__tests__/hybrid-mode.test.ts +126 -0
- package/templates/cowork/src/__tests__/server-config-security.test.ts +55 -0
- package/templates/cowork/src/__tests__/server-config.test.ts +59 -0
- package/templates/cowork/src/bun/index.ts +130 -0
- package/templates/cowork/src/bun/three.d.ts +1 -0
- package/templates/cowork/src/gateway/http-routes.ts +1 -0
- package/templates/cowork/src/gateway/ipc-transport.ts +68 -0
- package/templates/cowork/src/gateway/sse-transport.ts +231 -0
- package/templates/cowork/src/mainview/App.tsx +45 -0
- package/templates/cowork/src/mainview/__tests__/hooks/use-rpc-init.test.ts +202 -0
- package/templates/cowork/src/mainview/__tests__/hooks/use-sidebar-resize.test.ts +127 -0
- package/templates/cowork/src/mainview/__tests__/i18n/i18n.test.ts +49 -0
- package/templates/cowork/src/mainview/__tests__/setup.ts +40 -0
- package/templates/cowork/src/mainview/__tests__/stores/use-chat-store.test.ts +73 -0
- package/templates/cowork/src/mainview/__tests__/stores/use-sidebar-store.test.ts +61 -0
- package/templates/cowork/src/mainview/__tests__/theme-variables.test.ts +36 -0
- package/templates/cowork/src/mainview/components/chat/TaskChat.tsx +311 -0
- package/templates/cowork/src/mainview/components/chat/__tests__/localhost-links.test.ts +76 -0
- package/templates/cowork/src/mainview/components/common/ErrorBoundary.tsx +1 -0
- package/templates/cowork/src/mainview/components/common/LanguageSwitcher.tsx +15 -0
- package/templates/cowork/src/mainview/components/common/ThemeToggle.tsx +45 -0
- package/templates/cowork/src/mainview/components/common/__tests__/ErrorBoundary.test.tsx +74 -0
- package/templates/cowork/src/mainview/components/common/__tests__/LanguageSwitcher.test.tsx +44 -0
- package/templates/cowork/src/mainview/components/common/__tests__/ThemeToggle.test.tsx +41 -0
- package/templates/cowork/src/mainview/components/dev/NetworkPanel.tsx +155 -0
- package/templates/cowork/src/mainview/components/layout/AppLayout.tsx +216 -0
- package/templates/cowork/src/mainview/components/right/ArtifactsPanel.tsx +54 -0
- package/templates/cowork/src/mainview/components/right/ContextPanel.tsx +133 -0
- package/templates/cowork/src/mainview/components/right/ElementPicker.tsx +206 -0
- package/templates/cowork/src/mainview/components/right/PreviewBlock.tsx +155 -0
- package/templates/cowork/src/mainview/components/right/ProgressPanel.tsx +85 -0
- package/templates/cowork/src/mainview/components/sidebar/TaskSidebar.tsx +211 -0
- package/templates/cowork/src/mainview/components/topbar/TopBar.tsx +86 -0
- package/templates/cowork/src/mainview/global.d.ts +13 -0
- package/templates/cowork/src/mainview/hooks/__tests__/use-breakpoint.test.ts +123 -0
- package/templates/cowork/src/mainview/hooks/use-breakpoint.ts +53 -0
- package/templates/cowork/src/mainview/hooks/use-rpc-init.ts +26 -0
- package/templates/cowork/src/mainview/hooks/use-sidebar-resize.ts +40 -0
- package/templates/cowork/src/mainview/index.css +89 -0
- package/templates/cowork/src/mainview/index.html +12 -0
- package/templates/cowork/src/mainview/lib/api-client.ts +404 -0
- package/templates/cowork/src/mainview/lib/i18n/index.ts +30 -0
- package/templates/cowork/src/mainview/lib/i18n/locales/en.json +130 -0
- package/templates/cowork/src/mainview/lib/i18n/locales/zh.json +128 -0
- package/templates/cowork/src/mainview/lib/network-bus.ts +92 -0
- package/templates/cowork/src/mainview/lib/rpc-cache.ts +94 -0
- package/templates/cowork/src/mainview/main.tsx +18 -0
- package/templates/cowork/src/mainview/stores/__tests__/use-connection-store.test.ts +26 -0
- package/templates/cowork/src/mainview/stores/__tests__/use-locale-store.test.ts +32 -0
- package/templates/cowork/src/mainview/stores/__tests__/use-log-store.test.ts +28 -0
- package/templates/cowork/src/mainview/stores/__tests__/use-preview-store.test.ts +193 -0
- package/templates/cowork/src/mainview/stores/__tests__/use-sidebar-store.test.ts +81 -0
- package/templates/cowork/src/mainview/stores/__tests__/use-theme-store.test.ts +59 -0
- package/templates/cowork/src/mainview/stores/message-batcher.ts +25 -0
- package/templates/cowork/src/mainview/stores/use-chat-store.ts +198 -0
- package/templates/cowork/src/mainview/stores/use-connection-store.ts +168 -0
- package/templates/cowork/src/mainview/stores/use-context-store.ts +68 -0
- package/templates/cowork/src/mainview/stores/use-locale-store.ts +27 -0
- package/templates/cowork/src/mainview/stores/use-log-store.ts +16 -0
- package/templates/cowork/src/mainview/stores/use-network-panel-store.ts +18 -0
- package/templates/cowork/src/mainview/stores/use-output-store.ts +47 -0
- package/templates/cowork/src/mainview/stores/use-preview-store.ts +97 -0
- package/templates/cowork/src/mainview/stores/use-sidebar-store.ts +272 -0
- package/templates/cowork/src/mainview/stores/use-task-store.ts +86 -0
- package/templates/cowork/src/mainview/stores/use-theme-store.ts +46 -0
- package/templates/cowork/src/mainview/stores/use-view-store.ts +29 -0
- package/templates/cowork/src/mainview/types/index.ts +6 -0
- package/templates/cowork/src/server-config.ts +44 -0
- package/templates/cowork/src/server.ts +78 -0
- package/templates/cowork/src/shared/handlers/__tests__/chat-concurrency.test.ts +127 -0
- package/templates/cowork/src/shared/handlers/__tests__/chat-handler.test.ts +77 -0
- package/templates/cowork/src/shared/handlers/__tests__/file-handler.test.ts +100 -0
- package/templates/cowork/src/shared/handlers/__tests__/preview-handler.test.ts +172 -0
- package/templates/cowork/src/shared/handlers/__tests__/system-handler.test.ts +55 -0
- package/templates/cowork/src/shared/handlers/__tests__/timer-handler.test.ts +77 -0
- package/templates/cowork/src/shared/handlers/chat.ts +213 -0
- package/templates/cowork/src/shared/handlers/context.ts +72 -0
- package/templates/cowork/src/shared/handlers/file.ts +99 -0
- package/templates/cowork/src/shared/handlers/index.ts +9 -0
- package/templates/cowork/src/shared/handlers/output.ts +59 -0
- package/templates/cowork/src/shared/handlers/preview.ts +81 -0
- package/templates/cowork/src/shared/handlers/system.ts +27 -0
- package/templates/cowork/src/shared/handlers/task.ts +101 -0
- package/templates/cowork/src/shared/handlers/timer.ts +34 -0
- package/templates/cowork/src/shared/http-routes.ts +444 -0
- package/templates/cowork/src/shared/lib/__tests__/logger.test.ts +92 -0
- package/templates/cowork/src/shared/lib/__tests__/path-security.test.ts +77 -0
- package/templates/cowork/src/shared/lib/__tests__/web-server.test.ts +203 -0
- package/templates/cowork/src/shared/lib/logger.ts +152 -0
- package/templates/cowork/src/shared/lib/path-security.ts +38 -0
- package/templates/cowork/src/shared/lib/port-registry.ts +103 -0
- package/templates/cowork/src/shared/lib/web-server.ts +127 -0
- package/templates/cowork/src/shared/modules/chat.ts +20 -0
- package/templates/cowork/src/shared/modules/context.ts +32 -0
- package/templates/cowork/src/shared/modules/file.ts +40 -0
- package/templates/cowork/src/shared/modules/output.ts +20 -0
- package/templates/cowork/src/shared/modules/preview.ts +44 -0
- package/templates/cowork/src/shared/modules/system.ts +8 -0
- package/templates/cowork/src/shared/modules/task.ts +31 -0
- package/templates/cowork/src/shared/modules/timer.ts +11 -0
- package/templates/cowork/src/shared/register-all-handlers.ts +36 -0
- package/templates/cowork/src/shared/rpc-schema.ts +38 -0
- package/templates/cowork/tailwind.config.js +15 -0
- package/templates/cowork/test-upload.txt +0 -0
- package/templates/cowork/tsconfig.ipc.json +14 -0
- package/templates/cowork/tsconfig.json +36 -0
- package/templates/cowork/vite.config.ts +3 -0
- package/templates/cowork/vitest.config.ts +3 -0
- package/templates/general/.husky/commit-msg +4 -0
- package/templates/general/.husky/pre-commit +11 -0
- package/templates/general/.husky/pre-push +6 -0
- package/templates/general/CHANGELOG.md +15 -0
- package/templates/general/commitlint.config.js +8 -0
- package/templates/general/package.json +19 -4
- package/templates/general/src/mainview/__tests__/hooks/use-input-history.test.ts +125 -0
- package/templates/general/src/mainview/__tests__/setup.ts +32 -29
- package/templates/general/src/mainview/components/chat/ChatPanel.tsx +80 -55
- package/templates/general/src/mainview/components/common/ThemeToggle.tsx +40 -20
- package/templates/general/src/mainview/components/debug/DebugPanel.tsx +170 -156
- package/templates/general/src/mainview/components/debug/__tests__/DebugPanel.test.tsx +169 -0
- package/templates/general/src/mainview/components/explorer/ConfirmDialog.tsx +42 -42
- package/templates/general/src/mainview/components/explorer/ContextMenu.tsx +72 -67
- package/templates/general/src/mainview/components/feed/FeedPanel.tsx +7 -5
- package/templates/general/src/mainview/components/file-preview/FilePreviewOverlay.tsx +64 -45
- package/templates/general/src/mainview/components/file-preview/VirtualizedCodeView.tsx +24 -7
- package/templates/general/src/mainview/components/git/GitPanel.tsx +700 -473
- package/templates/general/src/mainview/components/layout/AppLayout.tsx +123 -114
- package/templates/general/src/mainview/components/search/SearchPanel.tsx +15 -19
- package/templates/general/src/mainview/lib/i18n/locales/en.json +175 -155
- package/templates/general/src/mainview/lib/i18n/locales/zh.json +173 -155
- package/templates/general/src/mainview/stores/__tests__/use-explorer-store.test.ts +259 -0
- package/templates/general/src/mainview/stores/__tests__/use-feed-store.test.ts +160 -0
- package/templates/general/src/mainview/stores/__tests__/use-git-store.test.ts +313 -0
- package/templates/general/src/mainview/stores/__tests__/use-notification-store.test.ts +115 -0
- package/templates/general/src/mainview/stores/__tests__/use-sidebar-store.test.ts +120 -0
- package/templates/general/src/mainview/stores/use-explorer-store.ts +277 -260
- package/templates/general/src/mainview/types/index.ts +21 -20
- package/templates/general/src/shared/handlers/chat.ts +1 -1
- package/templates/general/src/shared/handlers/debug.ts +12 -2
- package/templates/shared/components/ErrorBoundary.tsx +0 -1
- package/templates/shared/vite-base.config.ts +8 -7
- /package/templates/{shared → browser-agent}/test-upload.txt +0 -0
package/src/lib/copy.ts
CHANGED
|
@@ -7,11 +7,46 @@ import {
|
|
|
7
7
|
unlinkSync,
|
|
8
8
|
chmodSync,
|
|
9
9
|
} from "fs";
|
|
10
|
-
import { join, resolve } from "path";
|
|
11
|
-
import {
|
|
10
|
+
import { join, resolve, extname } from "path";
|
|
11
|
+
import { homedir } from "os";
|
|
12
|
+
import { execFileSync } from "child_process";
|
|
13
|
+
import { getRootDir } from "./templates.js";
|
|
12
14
|
|
|
13
15
|
const SKIP_DIRS = new Set(["node_modules", "build", "dist", ".git", ".husky", ".trae"]);
|
|
14
|
-
const SKIP_FILES = new Set(["bun.lock"
|
|
16
|
+
const SKIP_FILES = new Set(["bun.lock"]);
|
|
17
|
+
|
|
18
|
+
const BINARY_EXTENSIONS = new Set([
|
|
19
|
+
".png",
|
|
20
|
+
".jpg",
|
|
21
|
+
".jpeg",
|
|
22
|
+
".gif",
|
|
23
|
+
".webp",
|
|
24
|
+
".ico",
|
|
25
|
+
".icns",
|
|
26
|
+
".ttf",
|
|
27
|
+
".otf",
|
|
28
|
+
".woff",
|
|
29
|
+
".woff2",
|
|
30
|
+
".mp3",
|
|
31
|
+
".mp4",
|
|
32
|
+
".wav",
|
|
33
|
+
".pdf",
|
|
34
|
+
".zip",
|
|
35
|
+
".gz",
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
export function expandTilde(targetPath: string): string {
|
|
39
|
+
if (targetPath === "~") return homedir();
|
|
40
|
+
if (targetPath.startsWith("~/")) return join(homedir(), targetPath.slice(2));
|
|
41
|
+
return targetPath;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function isBinaryFile(filePath: string, buffer: Buffer): boolean {
|
|
45
|
+
if (BINARY_EXTENSIONS.has(extname(filePath).toLowerCase())) return true;
|
|
46
|
+
// A NUL byte in the first 8KB almost certainly means binary content;
|
|
47
|
+
// reading such a file as utf-8 would silently corrupt it.
|
|
48
|
+
return buffer.subarray(0, 8192).includes(0);
|
|
49
|
+
}
|
|
15
50
|
|
|
16
51
|
export interface CopyOptions {
|
|
17
52
|
projectName: string;
|
|
@@ -43,14 +78,20 @@ export function copyAndReplace(srcDir: string, destDir: string, projectName: str
|
|
|
43
78
|
} else {
|
|
44
79
|
if (SKIP_FILES.has(entry.name)) continue;
|
|
45
80
|
|
|
46
|
-
|
|
81
|
+
const raw = readFileSync(srcPath);
|
|
82
|
+
|
|
83
|
+
if (isBinaryFile(entry.name, raw)) {
|
|
84
|
+
writeFileSync(destPath, raw);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let content = raw.toString("utf-8");
|
|
47
89
|
|
|
48
90
|
content = content.replace(/pi-agent-template/g, projectName);
|
|
49
91
|
content = content.replace(/Pi Agent Template/g, pascalName);
|
|
50
92
|
content = content.replace(/Pi Agent/g, pascalName);
|
|
51
93
|
content = content.replace(/com\.piagent\.template/g, identifier);
|
|
52
94
|
content = content.replace(/com\.piagent/g, shortId);
|
|
53
|
-
content = content.replace(/@pi-agent\//g, `@${projectName}/`);
|
|
54
95
|
|
|
55
96
|
writeFileSync(destPath, content);
|
|
56
97
|
}
|
|
@@ -74,8 +115,8 @@ function copyTraeRules(monorepoRoot: string, targetDir: string, projectName: str
|
|
|
74
115
|
}
|
|
75
116
|
}
|
|
76
117
|
|
|
77
|
-
function copySharedModules(
|
|
78
|
-
const sharedDir = resolve(
|
|
118
|
+
function copySharedModules(sourceRoot: string, targetDir: string, projectName: string): void {
|
|
119
|
+
const sharedDir = resolve(sourceRoot, "templates", "shared");
|
|
79
120
|
if (!existsSync(sharedDir)) return;
|
|
80
121
|
|
|
81
122
|
const destSharedDir = join(targetDir, "shared");
|
|
@@ -145,76 +186,83 @@ function cleanSharedViteConfig(sharedDir: string): void {
|
|
|
145
186
|
}
|
|
146
187
|
}
|
|
147
188
|
|
|
148
|
-
function resolvePackageVersion(packageName: string): string {
|
|
189
|
+
function resolvePackageVersion(packageName: string, fallbackRange?: string): string {
|
|
149
190
|
try {
|
|
150
|
-
|
|
191
|
+
const version = execFileSync("npm", ["view", packageName, "version"], {
|
|
192
|
+
encoding: "utf-8",
|
|
193
|
+
}).trim();
|
|
194
|
+
return `^${version}`;
|
|
151
195
|
} catch {
|
|
152
|
-
|
|
196
|
+
// Offline / registry failure: keep a usable range instead of silently
|
|
197
|
+
// downgrading the project to an ancient version.
|
|
198
|
+
if (fallbackRange && fallbackRange !== "workspace:*") {
|
|
199
|
+
console.warn(`(Could not look up latest ${packageName}; keeping ${fallbackRange})`);
|
|
200
|
+
return fallbackRange;
|
|
201
|
+
}
|
|
202
|
+
const fallback = NPM_FALLBACK_VERSIONS[packageName];
|
|
203
|
+
if (fallback) {
|
|
204
|
+
console.warn(`(Could not look up latest ${packageName}; falling back to ${fallback})`);
|
|
205
|
+
return fallback;
|
|
206
|
+
}
|
|
207
|
+
console.warn(`(Could not look up latest ${packageName}; keeping ${String(fallbackRange)})`);
|
|
208
|
+
return fallbackRange ?? "*";
|
|
153
209
|
}
|
|
154
210
|
}
|
|
155
211
|
|
|
212
|
+
// Only used when the registry is unreachable AND no usable range is present;
|
|
213
|
+
// bundled templates carry pinned versions via post-sync-templates.mjs.
|
|
214
|
+
const NPM_FALLBACK_VERSIONS: Record<string, string> = {
|
|
215
|
+
"@dyyz1993/rpc-core": "^2.2.0",
|
|
216
|
+
"@dyyz1993/eslint-plugin-rpc": "^1.1.0",
|
|
217
|
+
};
|
|
218
|
+
|
|
156
219
|
const WORKSPACE_PACKAGES = ["@dyyz1993/rpc-core", "@dyyz1993/eslint-plugin-rpc"];
|
|
157
220
|
|
|
158
|
-
function updatePackageJson(targetDir: string,
|
|
221
|
+
function updatePackageJson(targetDir: string, projectName: string): void {
|
|
159
222
|
const rootPkgPath = join(targetDir, "package.json");
|
|
160
223
|
if (!existsSync(rootPkgPath)) return;
|
|
161
224
|
|
|
162
225
|
const rootPkg = JSON.parse(readFileSync(rootPkgPath, "utf-8"));
|
|
163
226
|
|
|
164
227
|
delete rootPkg.workspaces;
|
|
228
|
+
rootPkg.name = projectName;
|
|
165
229
|
|
|
166
230
|
for (const depKey of ["dependencies", "devDependencies"] as const) {
|
|
167
231
|
if (!rootPkg[depKey]) continue;
|
|
168
232
|
for (const pkgName of WORKSPACE_PACKAGES) {
|
|
169
233
|
if (!rootPkg[depKey][pkgName]) continue;
|
|
170
|
-
|
|
171
|
-
const version = resolvePackageVersion(pkgName);
|
|
172
|
-
rootPkg[depKey][pkgName] = `^${version}`;
|
|
173
|
-
} else {
|
|
174
|
-
delete rootPkg[depKey][pkgName];
|
|
175
|
-
}
|
|
234
|
+
rootPkg[depKey][pkgName] = resolvePackageVersion(pkgName, rootPkg[depKey][pkgName]);
|
|
176
235
|
}
|
|
177
236
|
}
|
|
178
237
|
|
|
179
238
|
writeFileSync(rootPkgPath, JSON.stringify(rootPkg, null, "\t") + "\n");
|
|
239
|
+
}
|
|
180
240
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
if (line.includes("import rpcPlugin") && line.includes("@dyyz1993/eslint-plugin-rpc")) {
|
|
192
|
-
continue;
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (line.includes("RPC") && line.includes("规范规则")) {
|
|
196
|
-
inRpcSection = true;
|
|
197
|
-
continue;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (inRpcSection) {
|
|
201
|
-
if (line.trim().startsWith("'rpc/") || line.trim().startsWith('"rpc/')) {
|
|
202
|
-
continue;
|
|
203
|
-
}
|
|
204
|
-
inRpcSection = false;
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
if (line.includes("rpc: rpcPlugin")) {
|
|
208
|
-
continue;
|
|
209
|
-
}
|
|
241
|
+
/**
|
|
242
|
+
* Shared post-processing after raw template files land in the target project.
|
|
243
|
+
* Used by both `create` and `update --force`; skipping it used to leave
|
|
244
|
+
* `workspace:*` deps and `../shared` imports in user projects.
|
|
245
|
+
*/
|
|
246
|
+
export function postProcessTemplate(targetDir: string, projectName: string): void {
|
|
247
|
+
copySharedModules(getRootDir(), targetDir, projectName);
|
|
248
|
+
cleanViteConfig(targetDir);
|
|
249
|
+
updatePackageJson(targetDir, projectName);
|
|
250
|
+
}
|
|
210
251
|
|
|
211
|
-
|
|
252
|
+
function precheckExternalTools(): void {
|
|
253
|
+
const missing: string[] = [];
|
|
254
|
+
for (const tool of ["git", "bun"]) {
|
|
255
|
+
try {
|
|
256
|
+
execFileSync(tool, ["--version"], { stdio: "pipe" });
|
|
257
|
+
} catch {
|
|
258
|
+
missing.push(tool);
|
|
212
259
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
260
|
+
}
|
|
261
|
+
if (missing.length > 0) {
|
|
262
|
+
throw new Error(
|
|
263
|
+
`Required tools not found: ${missing.join(", ")}. ` +
|
|
264
|
+
`Install them before creating a project (bun: https://bun.sh).`
|
|
265
|
+
);
|
|
218
266
|
}
|
|
219
267
|
}
|
|
220
268
|
|
|
@@ -227,6 +275,8 @@ export async function copyTemplate(options: CopyOptions): Promise<void> {
|
|
|
227
275
|
throw new Error(`Directory "${targetDir}" already exists.`);
|
|
228
276
|
}
|
|
229
277
|
|
|
278
|
+
precheckExternalTools();
|
|
279
|
+
|
|
230
280
|
const { identifier } = deriveNames(projectName);
|
|
231
281
|
|
|
232
282
|
console.log(`Creating project: ${projectName}`);
|
|
@@ -237,37 +287,18 @@ export async function copyTemplate(options: CopyOptions): Promise<void> {
|
|
|
237
287
|
copyAndReplace(templateDir, targetDir, projectName);
|
|
238
288
|
if (isMonorepo) {
|
|
239
289
|
copyTraeRules(localRoot, targetDir, projectName);
|
|
240
|
-
copySharedModules(localRoot, targetDir, projectName);
|
|
241
|
-
} else {
|
|
242
|
-
const publishedShared = resolve(import.meta.dir, "..", "..", "templates", "shared");
|
|
243
|
-
if (existsSync(publishedShared)) {
|
|
244
|
-
copyAndReplace(publishedShared, join(targetDir, "shared"), projectName);
|
|
245
|
-
for (const f of ["http-routes.ts", "logger.ts"]) {
|
|
246
|
-
const p = join(targetDir, "shared", f);
|
|
247
|
-
if (existsSync(p)) unlinkSync(p);
|
|
248
|
-
}
|
|
249
|
-
const tsconfigPath = join(targetDir, "tsconfig.json");
|
|
250
|
-
if (existsSync(tsconfigPath)) {
|
|
251
|
-
let tsconfig = readFileSync(tsconfigPath, "utf-8");
|
|
252
|
-
tsconfig = tsconfig.replace(/"\.\.\/shared\/\*"/g, '"./shared/*"');
|
|
253
|
-
tsconfig = tsconfig.replace(/"\.\.\/shared"/g, '"./shared"');
|
|
254
|
-
writeFileSync(tsconfigPath, tsconfig);
|
|
255
|
-
}
|
|
256
|
-
cleanSharedViteConfig(join(targetDir, "shared"));
|
|
257
|
-
}
|
|
258
290
|
}
|
|
259
|
-
|
|
260
|
-
updatePackageJson(targetDir, projectName);
|
|
291
|
+
postProcessTemplate(targetDir, projectName);
|
|
261
292
|
|
|
262
293
|
console.log("Initializing git...");
|
|
263
|
-
|
|
294
|
+
execFileSync("git", ["init"], { cwd: targetDir, stdio: "pipe" });
|
|
264
295
|
|
|
265
296
|
console.log("Installing dependencies...");
|
|
266
|
-
|
|
297
|
+
execFileSync("bun", ["install"], { cwd: targetDir, stdio: "inherit" });
|
|
267
298
|
|
|
268
299
|
console.log("Building browser bundle...");
|
|
269
300
|
try {
|
|
270
|
-
|
|
301
|
+
execFileSync("bun", ["run", "build:browser"], { cwd: targetDir, stdio: "pipe" });
|
|
271
302
|
} catch {
|
|
272
303
|
console.log("(build:browser skipped - script not found)");
|
|
273
304
|
}
|
|
@@ -284,7 +315,7 @@ export async function copyTemplate(options: CopyOptions): Promise<void> {
|
|
|
284
315
|
hook(
|
|
285
316
|
"pre-commit",
|
|
286
317
|
`#!/bin/sh
|
|
287
|
-
|
|
318
|
+
bunx lint-staged
|
|
288
319
|
|
|
289
320
|
STAGED_TS=$(git diff --cached --name-only --diff-filter=ACMR | grep -c '\\.tsx\\?$' || true)
|
|
290
321
|
|
|
@@ -300,7 +331,7 @@ echo "✅ Pre-commit checks passed"
|
|
|
300
331
|
hook(
|
|
301
332
|
"commit-msg",
|
|
302
333
|
`#!/bin/sh
|
|
303
|
-
|
|
334
|
+
bunx commitlint --edit "$1"
|
|
304
335
|
`
|
|
305
336
|
);
|
|
306
337
|
|
|
@@ -311,7 +342,7 @@ echo "⏳ Linting..."
|
|
|
311
342
|
bun run lint || { echo "❌ Lint failed."; exit 1; }
|
|
312
343
|
|
|
313
344
|
echo "⏳ Checking lockfile sync..."
|
|
314
|
-
git diff --name-only HEAD --
|
|
345
|
+
git diff --name-only HEAD -- bun.lock | grep -q . && { echo "⚠️ bun.lock has uncommitted changes."; exit 1; }
|
|
315
346
|
|
|
316
347
|
echo "✅ Pre-push checks passed (full tests run in CI). Pushing..."
|
|
317
348
|
`
|
|
@@ -356,9 +387,9 @@ fi
|
|
|
356
387
|
echo "⏳ Checking for dependency changes..."
|
|
357
388
|
CHANGED=$(git diff HEAD@{1} --name-only HEAD)
|
|
358
389
|
|
|
359
|
-
if echo "$CHANGED" | grep -q "
|
|
360
|
-
echo "📦 Dependencies changed, running
|
|
361
|
-
|
|
390
|
+
if echo "$CHANGED" | grep -q "bun.lock\\|package.json"; then
|
|
391
|
+
echo "📦 Dependencies changed, running bun install..."
|
|
392
|
+
bun install
|
|
362
393
|
fi
|
|
363
394
|
`
|
|
364
395
|
);
|
|
@@ -372,26 +403,31 @@ IS_BRANCH="$3"
|
|
|
372
403
|
|
|
373
404
|
if [ "$IS_BRANCH" = "1" ]; then
|
|
374
405
|
CHANGED=$(git diff --name-only "$PREV_HEAD" "$NEW_HEAD" 2>/dev/null)
|
|
375
|
-
if echo "$CHANGED" | grep -q "
|
|
376
|
-
echo "📦 Dependencies changed between branches, running
|
|
377
|
-
|
|
406
|
+
if echo "$CHANGED" | grep -q "bun.lock\\|package.json"; then
|
|
407
|
+
echo "📦 Dependencies changed between branches, running bun install..."
|
|
408
|
+
bun install
|
|
378
409
|
fi
|
|
379
410
|
fi
|
|
380
411
|
`
|
|
381
412
|
);
|
|
382
413
|
|
|
383
414
|
console.log("Initializing husky...");
|
|
384
|
-
|
|
415
|
+
try {
|
|
416
|
+
execFileSync("bun", ["run", "prepare"], { cwd: targetDir, stdio: "pipe" });
|
|
417
|
+
} catch {
|
|
418
|
+
console.warn("(husky init skipped - prepare script failed; git hooks not installed)");
|
|
419
|
+
}
|
|
385
420
|
|
|
386
|
-
|
|
421
|
+
execFileSync("git", ["add", "-A"], { cwd: targetDir, stdio: "pipe" });
|
|
387
422
|
|
|
388
423
|
try {
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
424
|
+
execFileSync(
|
|
425
|
+
"git",
|
|
426
|
+
["commit", "--no-verify", "-m", `feat: init ${projectName} from pi-agent-template`],
|
|
427
|
+
{ cwd: targetDir, stdio: "pipe" }
|
|
428
|
+
);
|
|
393
429
|
} catch {
|
|
394
|
-
console.log("(git commit skipped -
|
|
430
|
+
console.log("(git commit skipped - check git user.name / user.email config)");
|
|
395
431
|
}
|
|
396
432
|
|
|
397
433
|
console.log("");
|
package/src/lib/templates.ts
CHANGED
|
@@ -27,6 +27,18 @@ const TEMPLATES: TemplateInfo[] = [
|
|
|
27
27
|
available: true,
|
|
28
28
|
dir: 'templates/agent',
|
|
29
29
|
},
|
|
30
|
+
{
|
|
31
|
+
type: 'browser-agent',
|
|
32
|
+
description: 'Browser automation agent (AI-powered browser control + xbrowser + Desktop/Web)',
|
|
33
|
+
available: true,
|
|
34
|
+
dir: 'templates/browser-agent',
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
type: 'cowork',
|
|
38
|
+
description: 'Cowork task collaboration agent (Task orchestration + Progress tracking + Artifacts + Context management)',
|
|
39
|
+
available: true,
|
|
40
|
+
dir: 'templates/cowork',
|
|
41
|
+
},
|
|
30
42
|
];
|
|
31
43
|
|
|
32
44
|
export function getTemplateInfo(type: string): TemplateInfo | undefined {
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
. "$(dirname -- "$0")/_/husky.sh"
|
|
3
|
+
|
|
4
|
+
# Secret detection
|
|
5
|
+
if git diff --cached --name-only --diff-filter=ACM -z | xargs -0 grep -ilE '(password|secret|api.key|private.key|token|credential).*=.*[A-Za-z0-9]{16,}' 2>/dev/null; then
|
|
6
|
+
echo "⚠️ Potential secrets detected in staged files!"
|
|
7
|
+
echo "Please review and remove any sensitive data before committing."
|
|
8
|
+
exit 1
|
|
9
|
+
fi
|
|
10
|
+
|
|
11
|
+
npx lint-staged
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# pi-agent-app
|
|
2
|
+
|
|
3
|
+
## 1.0.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [[`29d2171`](https://github.com/dyyz1993/pi-agent-template/commit/29d217148f6e0b496cc06716e11847b3e522e266)]:
|
|
8
|
+
- @dyyz1993/rpc-core@2.2.1
|
|
9
|
+
|
|
10
|
+
## 1.0.1
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- Updated dependencies [[`29d2171`](https://github.com/dyyz1993/pi-agent-template/commit/29d217148f6e0b496cc06716e11847b3e522e266), [`724470a`](https://github.com/dyyz1993/pi-agent-template/commit/724470a784b48a66591e06299fab8ad72f023962)]:
|
|
15
|
+
- @dyyz1993/rpc-core@3.0.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-agent-app",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "Coding agent template with Bash, Rules, and Todo management",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "xuyingzhou",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"prepare": "husky"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@dyyz1993/rpc-core": "^
|
|
78
|
+
"@dyyz1993/rpc-core": "^2.2.1",
|
|
79
79
|
"@tanstack/react-virtual": "^3.13.24",
|
|
80
80
|
"electrobun": "1.18.1",
|
|
81
81
|
"lucide-react": "^1.9.0",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"zustand": "^5.0.12"
|
|
92
92
|
},
|
|
93
93
|
"devDependencies": {
|
|
94
|
-
"@dyyz1993/eslint-plugin-rpc": "
|
|
94
|
+
"@dyyz1993/eslint-plugin-rpc": "^1.1.0",
|
|
95
95
|
"@eslint/js": "^9.0.0",
|
|
96
96
|
"@testing-library/jest-dom": "^6.9.1",
|
|
97
97
|
"@testing-library/react": "^16.3.2",
|
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from
|
|
2
|
-
import { EventEmitter } from
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import type { Server } from 'http';
|
|
4
|
+
import type { WebSocketServer } from 'ws';
|
|
3
5
|
|
|
4
|
-
vi.mock(
|
|
6
|
+
vi.mock('../../shared/register-all-handlers', () => ({
|
|
5
7
|
registerAllHandlers: vi.fn(),
|
|
6
8
|
}));
|
|
7
9
|
|
|
8
|
-
vi.mock(
|
|
10
|
+
vi.mock('../../shared/lib/logger', () => ({
|
|
9
11
|
createLogger: () => ({
|
|
10
12
|
info: vi.fn(),
|
|
11
13
|
error: vi.fn(),
|
|
@@ -14,14 +16,22 @@ vi.mock("../../shared/lib/logger", () => ({
|
|
|
14
16
|
}),
|
|
15
17
|
}));
|
|
16
18
|
|
|
17
|
-
const MOCK_AUTH_TOKEN =
|
|
19
|
+
const MOCK_AUTH_TOKEN = 'test-secure-token-123456';
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
interface MockWs extends EventEmitter {
|
|
22
|
+
readyState: number;
|
|
23
|
+
close: ReturnType<typeof vi.fn>;
|
|
24
|
+
send: ReturnType<typeof vi.fn>;
|
|
25
|
+
ping: ReturnType<typeof vi.fn>;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function createMockWs(): MockWs {
|
|
29
|
+
const ws = Object.assign(new EventEmitter(), {
|
|
30
|
+
readyState: 1,
|
|
31
|
+
close: vi.fn(),
|
|
32
|
+
send: vi.fn(),
|
|
33
|
+
ping: vi.fn(),
|
|
34
|
+
}) as MockWs;
|
|
25
35
|
return ws;
|
|
26
36
|
}
|
|
27
37
|
|
|
@@ -29,19 +39,19 @@ function createMockReq(url: string, headers: Record<string, string> = {}) {
|
|
|
29
39
|
return { url, headers };
|
|
30
40
|
}
|
|
31
41
|
|
|
32
|
-
describe(
|
|
33
|
-
let _wssInstance: EventEmitter & { clients: Set<
|
|
42
|
+
describe('WS Handler Token 安全', () => {
|
|
43
|
+
let _wssInstance: EventEmitter & { clients: Set<unknown> };
|
|
34
44
|
|
|
35
45
|
beforeEach(async () => {
|
|
36
46
|
vi.resetModules();
|
|
37
47
|
|
|
38
|
-
const { WebSocketServer } = await import(
|
|
48
|
+
const { WebSocketServer } = await import('ws');
|
|
39
49
|
const _originalWSS = WebSocketServer;
|
|
40
50
|
|
|
41
|
-
vi.doMock(
|
|
51
|
+
vi.doMock('ws', () => {
|
|
42
52
|
class MockWSS extends EventEmitter {
|
|
43
|
-
clients = new Set();
|
|
44
|
-
constructor(_opts:
|
|
53
|
+
clients = new Set<unknown>();
|
|
54
|
+
constructor(_opts: unknown) {
|
|
45
55
|
super();
|
|
46
56
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
47
57
|
_wssInstance = this;
|
|
@@ -52,67 +62,71 @@ describe("WS Handler Token 安全", () => {
|
|
|
52
62
|
});
|
|
53
63
|
|
|
54
64
|
async function setupTest() {
|
|
55
|
-
const { createWsHandler } = await import(
|
|
65
|
+
const { createWsHandler } = await import('../ws-handler');
|
|
56
66
|
const httpServer = new EventEmitter();
|
|
57
|
-
const wss = createWsHandler(httpServer as
|
|
67
|
+
const wss = createWsHandler(httpServer as unknown as Server, {
|
|
58
68
|
config: { port: 3100, authToken: MOCK_AUTH_TOKEN, maxUploadSize: 50 * 1024 * 1024 },
|
|
59
69
|
});
|
|
60
70
|
return wss;
|
|
61
71
|
}
|
|
62
72
|
|
|
63
|
-
function emitConnection(
|
|
64
|
-
wss
|
|
73
|
+
function emitConnection(
|
|
74
|
+
wss: WebSocketServer,
|
|
75
|
+
ws: MockWs,
|
|
76
|
+
req: { url: string; headers: Record<string, string> },
|
|
77
|
+
) {
|
|
78
|
+
wss.emit('connection', ws, req);
|
|
65
79
|
}
|
|
66
80
|
|
|
67
|
-
it(
|
|
81
|
+
it('无 token 应被拒绝 (4001)', async () => {
|
|
68
82
|
const wss = await setupTest();
|
|
69
83
|
const ws = createMockWs();
|
|
70
|
-
const req = createMockReq(
|
|
84
|
+
const req = createMockReq('/ws');
|
|
71
85
|
emitConnection(wss, ws, req);
|
|
72
|
-
expect(
|
|
86
|
+
expect(ws.close).toHaveBeenCalledWith(4001, 'Unauthorized');
|
|
73
87
|
});
|
|
74
88
|
|
|
75
|
-
it(
|
|
89
|
+
it('错误 token 应被拒绝 (4001)', async () => {
|
|
76
90
|
const wss = await setupTest();
|
|
77
91
|
const ws = createMockWs();
|
|
78
|
-
const req = createMockReq(
|
|
92
|
+
const req = createMockReq('/ws?token=wrong-token');
|
|
79
93
|
emitConnection(wss, ws, req);
|
|
80
|
-
expect(
|
|
94
|
+
expect(ws.close).toHaveBeenCalledWith(4001, 'Unauthorized');
|
|
81
95
|
});
|
|
82
96
|
|
|
83
|
-
it(
|
|
97
|
+
it('正确 token 通过 URL query 应被接受', async () => {
|
|
84
98
|
const wss = await setupTest();
|
|
85
99
|
const ws = createMockWs();
|
|
86
100
|
const req = createMockReq(`/ws?token=${MOCK_AUTH_TOKEN}`);
|
|
87
101
|
emitConnection(wss, ws, req);
|
|
88
|
-
expect(
|
|
102
|
+
expect(ws.close).not.toHaveBeenCalled();
|
|
89
103
|
});
|
|
90
104
|
|
|
91
|
-
it(
|
|
105
|
+
it('正确 token 通过 Sec-WebSocket-Protocol header 应被接受', async () => {
|
|
92
106
|
const wss = await setupTest();
|
|
93
107
|
const ws = createMockWs();
|
|
94
|
-
const req = createMockReq(
|
|
95
|
-
|
|
108
|
+
const req = createMockReq('/ws', {
|
|
109
|
+
'sec-websocket-protocol': MOCK_AUTH_TOKEN,
|
|
96
110
|
});
|
|
97
111
|
emitConnection(wss, ws, req);
|
|
98
|
-
expect(
|
|
112
|
+
expect(ws.close).not.toHaveBeenCalled();
|
|
99
113
|
});
|
|
100
114
|
|
|
101
|
-
it(
|
|
115
|
+
it('header 方式优先于 query 方式 (header 正确, query 错误)', async () => {
|
|
102
116
|
const wss = await setupTest();
|
|
103
117
|
const ws = createMockWs();
|
|
104
|
-
const req = createMockReq(
|
|
105
|
-
|
|
118
|
+
const req = createMockReq('/ws?token=wrong-token', {
|
|
119
|
+
'sec-websocket-protocol': MOCK_AUTH_TOKEN,
|
|
106
120
|
});
|
|
107
121
|
emitConnection(wss, ws, req);
|
|
108
|
-
expect(
|
|
122
|
+
expect(ws.close).not.toHaveBeenCalled();
|
|
109
123
|
});
|
|
110
124
|
|
|
111
|
-
it(
|
|
125
|
+
it('token 验证使用 timingSafeEqual(长度不等返回 false)', async () => {
|
|
112
126
|
const wss = await setupTest();
|
|
113
127
|
const ws = createMockWs();
|
|
114
128
|
const req = createMockReq(`/ws?token=short`);
|
|
115
129
|
emitConnection(wss, ws, req);
|
|
116
|
-
expect(
|
|
130
|
+
expect(ws.close).toHaveBeenCalledWith(4001, 'Unauthorized');
|
|
117
131
|
});
|
|
118
132
|
});
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import type { ReactNode } from
|
|
2
|
-
import { useState } from
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import { useTranslation } from 'react-i18next';
|
|
4
|
+
import { useConnectionStore } from './stores/use-connection-store';
|
|
5
|
+
import { useBreakpointSync } from './hooks/use-breakpoint';
|
|
6
|
+
import { useRpcInit } from './hooks/use-rpc-init';
|
|
7
|
+
import { useSidebarResize } from './hooks/use-sidebar-resize';
|
|
8
|
+
import { AppLayout, type CenterTab } from './components/layout/AppLayout';
|
|
9
|
+
import { ErrorBoundary as _EB } from './components/common/ErrorBoundary';
|
|
9
10
|
|
|
10
11
|
const ErrorBoundary = _EB as unknown as React.FC<{ children: ReactNode }>;
|
|
11
12
|
|
|
12
13
|
function App() {
|
|
14
|
+
const { t } = useTranslation();
|
|
13
15
|
const ready = useConnectionStore((s) => s.ready);
|
|
14
|
-
const [centerTab, setCenterTab] = useState<CenterTab>(
|
|
16
|
+
const [centerTab, setCenterTab] = useState<CenterTab>('chat');
|
|
15
17
|
|
|
16
18
|
useBreakpointSync();
|
|
17
19
|
useRpcInit();
|
|
@@ -20,10 +22,10 @@ function App() {
|
|
|
20
22
|
|
|
21
23
|
if (!ready) {
|
|
22
24
|
return (
|
|
23
|
-
<div className="h-screen bg-
|
|
25
|
+
<div className="h-screen bg-[var(--color-bg-primary)] flex items-center justify-center">
|
|
24
26
|
<div className="text-center">
|
|
25
|
-
<div className="inline-block w-8 h-8 border-2 border-
|
|
26
|
-
<div className="text-
|
|
27
|
+
<div className="inline-block w-8 h-8 border-2 border-[var(--color-text-accent)] border-t-transparent rounded-full animate-spin mb-4" />
|
|
28
|
+
<div className="text-[var(--color-text-tertiary)] text-sm">{t('app.connecting')}</div>
|
|
27
29
|
</div>
|
|
28
30
|
</div>
|
|
29
31
|
);
|