tower-studio 0.1.2 → 0.1.3
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/bin/tower.mjs +5 -15
- package/next.config.ts +1 -8
- package/package.json +10 -11
- package/prisma/dev.db +0 -0
- package/public/vs/_commonjsHelpers-CT9FvmAN.js +1 -0
- package/public/vs/abap-D-t0cyap.js +1 -0
- package/public/vs/apex-CcIm7xu6.js +1 -0
- package/public/vs/assets/css.worker-HnVq6Ewq.js +93 -0
- package/public/vs/assets/editor.worker-Be8ye1pW.js +26 -0
- package/public/vs/assets/html.worker-B51mlPHg.js +470 -0
- package/public/vs/assets/json.worker-DKiEKt88.js +58 -0
- package/public/vs/assets/ts.worker-CMbG-7ft.js +67731 -0
- package/public/vs/azcli-BA0tQDCg.js +1 -0
- package/public/vs/basic-languages/monaco.contribution.js +1 -0
- package/public/vs/bat-C397hTD6.js +1 -0
- package/public/vs/bicep-DF5aW17k.js +2 -0
- package/public/vs/cameligo-plsz8qhj.js +1 -0
- package/public/vs/clojure-Y2auQMzK.js +1 -0
- package/public/vs/coffee-Bu45yuWE.js +1 -0
- package/public/vs/cpp-CkKPQIni.js +1 -0
- package/public/vs/csharp-CX28MZyh.js +1 -0
- package/public/vs/csp-D8uWnyxW.js +1 -0
- package/public/vs/css-CaeNmE3S.js +3 -0
- package/public/vs/cssMode-CjiAH6dQ.js +1 -0
- package/public/vs/cypher-DVThT8BS.js +1 -0
- package/public/vs/dart-CmGfCvrO.js +1 -0
- package/public/vs/dockerfile-CZqqYdch.js +1 -0
- package/public/vs/ecl-30fUercY.js +1 -0
- package/public/vs/editor/editor.main.css +1 -0
- package/public/vs/editor/editor.main.js +5 -0
- package/public/vs/editor.api-CalNCsUg.js +903 -0
- package/public/vs/elixir-xjPaIfzF.js +1 -0
- package/public/vs/flow9-DqtmStfK.js +1 -0
- package/public/vs/freemarker2-Cz_sV6Md.js +3 -0
- package/public/vs/fsharp-BOMdg4U1.js +1 -0
- package/public/vs/go-D_hbi-Jt.js +1 -0
- package/public/vs/graphql-CKUU4kLG.js +1 -0
- package/public/vs/handlebars-OwglfO-1.js +1 -0
- package/public/vs/hcl-DTaboeZW.js +1 -0
- package/public/vs/html-Pa1xEWsY.js +1 -0
- package/public/vs/htmlMode-Bz67EXwp.js +1 -0
- package/public/vs/ini-CsNwO04R.js +1 -0
- package/public/vs/java-CI4ZMsH9.js +1 -0
- package/public/vs/javascript-PczUCGdz.js +1 -0
- package/public/vs/jsonMode-DULH5oaX.js +7 -0
- package/public/vs/julia-BwzEvaQw.js +1 -0
- package/public/vs/kotlin-IUYPiTV8.js +1 -0
- package/public/vs/language/css/monaco.contribution.js +1 -0
- package/public/vs/language/html/monaco.contribution.js +1 -0
- package/public/vs/language/json/monaco.contribution.js +1 -0
- package/public/vs/language/typescript/monaco.contribution.js +1 -0
- package/public/vs/less-C0eDYdqa.js +2 -0
- package/public/vs/lexon-iON-Kj97.js +1 -0
- package/public/vs/liquid-DqKjdPGy.js +1 -0
- package/public/vs/loader.js +1368 -0
- package/public/vs/lspLanguageFeatures-kM9O9rjY.js +4 -0
- package/public/vs/lua-DtygF91M.js +1 -0
- package/public/vs/m3-CsR4AuFi.js +1 -0
- package/public/vs/markdown-C_rD0bIw.js +1 -0
- package/public/vs/mdx-DEWtB1K5.js +1 -0
- package/public/vs/mips-CiYP61RB.js +1 -0
- package/public/vs/monaco.contribution-D2OdxNBt.js +1 -0
- package/public/vs/monaco.contribution-DO3azKX8.js +1 -0
- package/public/vs/monaco.contribution-EcChJV6a.js +1 -0
- package/public/vs/monaco.contribution-qLAYrEOP.js +1 -0
- package/public/vs/msdax-C38-sJlp.js +1 -0
- package/public/vs/mysql-CdtbpvbG.js +1 -0
- package/public/vs/nls.messages-loader.js +1 -0
- package/public/vs/nls.messages.cs.js.js +17 -0
- package/public/vs/nls.messages.de.js.js +17 -0
- package/public/vs/nls.messages.es.js.js +17 -0
- package/public/vs/nls.messages.fr.js.js +15 -0
- package/public/vs/nls.messages.it.js.js +15 -0
- package/public/vs/nls.messages.ja.js.js +17 -0
- package/public/vs/nls.messages.js.js +10 -0
- package/public/vs/nls.messages.ko.js.js +25 -0
- package/public/vs/nls.messages.pl.js.js +17 -0
- package/public/vs/nls.messages.pt-br.js.js +6 -0
- package/public/vs/nls.messages.ru.js.js +17 -0
- package/public/vs/nls.messages.tr.js.js +15 -0
- package/public/vs/nls.messages.zh-cn.js.js +17 -0
- package/public/vs/nls.messages.zh-tw.js.js +15 -0
- package/public/vs/objective-c-CntZFaHX.js +1 -0
- package/public/vs/pascal-r6kuqfl_.js +1 -0
- package/public/vs/pascaligo-BiXoTmXh.js +1 -0
- package/public/vs/perl-DABw_TcH.js +1 -0
- package/public/vs/pgsql-me_jFXeX.js +1 -0
- package/public/vs/php-D_kh-9LK.js +1 -0
- package/public/vs/pla-VfZjczW0.js +1 -0
- package/public/vs/postiats-BBSzz8Pk.js +1 -0
- package/public/vs/powerquery-Dt-g_2cc.js +1 -0
- package/public/vs/powershell-B-7ap1zc.js +1 -0
- package/public/vs/protobuf-BmtuEB1A.js +2 -0
- package/public/vs/pug-BRpRNeEb.js +1 -0
- package/public/vs/python-Cr0UkIbn.js +1 -0
- package/public/vs/qsharp-BzsFaUU9.js +1 -0
- package/public/vs/r-f8dDdrp4.js +1 -0
- package/public/vs/razor-BYAHOTkz.js +1 -0
- package/public/vs/redis-fvZQY4PI.js +1 -0
- package/public/vs/redshift-45Et0LQi.js +1 -0
- package/public/vs/restructuredtext-C7UUFKFD.js +1 -0
- package/public/vs/ruby-CZO8zYTz.js +1 -0
- package/public/vs/rust-Bfetafyc.js +1 -0
- package/public/vs/sb-3GYllVck.js +1 -0
- package/public/vs/scala-foMgrKo1.js +1 -0
- package/public/vs/scheme-CHdMtr7p.js +1 -0
- package/public/vs/scss-C1cmLt9V.js +3 -0
- package/public/vs/shell-ClXCKCEW.js +1 -0
- package/public/vs/solidity-MZ6ExpPy.js +1 -0
- package/public/vs/sophia-DWkuSsPQ.js +1 -0
- package/public/vs/sparql-AUGFYSyk.js +1 -0
- package/public/vs/sql-32GpJSV2.js +1 -0
- package/public/vs/st-CuDFIVZ_.js +1 -0
- package/public/vs/swift-n-2HociN.js +3 -0
- package/public/vs/systemverilog-Ch4vA8Yt.js +1 -0
- package/public/vs/tcl-D74tq1nH.js +1 -0
- package/public/vs/tsMode-CZz1Umrk.js +11 -0
- package/public/vs/twig-C6taOxMV.js +1 -0
- package/public/vs/typescript-DfOrAzoV.js +1 -0
- package/public/vs/typespec-D-PIh9Xw.js +1 -0
- package/public/vs/vb-Dyb2648j.js +1 -0
- package/public/vs/wgsl-BhLXMOR0.js +298 -0
- package/public/vs/workers-DcJshg-q.js +1 -0
- package/public/vs/xml-CdsdnY8S.js +1 -0
- package/public/vs/yaml-DYGvmE88.js +1 -0
- package/src/actions/__tests__/agent-actions-username.test.ts +30 -0
- package/src/actions/__tests__/asset-actions.test.ts +251 -0
- package/src/actions/__tests__/assistant-actions.test.ts +20 -0
- package/src/actions/__tests__/cli-profile-actions.test.ts +243 -0
- package/src/actions/__tests__/label-actions.test.ts +187 -0
- package/src/actions/__tests__/note-actions.test.ts +237 -0
- package/src/actions/__tests__/onboarding-actions.test.ts +265 -0
- package/src/actions/__tests__/project-actions.test.ts +179 -0
- package/src/actions/__tests__/prompt-actions.test.ts +213 -0
- package/src/actions/__tests__/report-actions.test.ts +246 -0
- package/src/actions/__tests__/search-code-actions.test.ts +308 -0
- package/src/actions/__tests__/task-actions-overview.test.ts +58 -0
- package/src/actions/__tests__/task-actions-pin.test.ts +79 -0
- package/src/actions/__tests__/workspace-actions.test.ts +256 -0
- package/src/components/layout/__tests__/top-bar-username.test.tsx +24 -0
- package/src/components/onboarding/__tests__/onboarding-wizard.test.tsx +185 -0
- package/src/hooks/__tests__/sse-event-reducer.test.ts +263 -0
- package/src/hooks/__tests__/use-assistant-chat.test.ts +34 -0
- package/src/hooks/__tests__/use-image-upload.test.ts +443 -0
- package/src/lib/__tests__/assistant-message-converter.test.ts +162 -0
- package/src/lib/__tests__/assistant-sessions.test.ts +253 -0
- package/src/lib/__tests__/build-multimodal-prompt.test.ts +173 -0
- package/src/lib/__tests__/config-reader.test.ts +75 -0
- package/src/lib/__tests__/diff-parser.test.ts +212 -0
- package/src/lib/__tests__/execution-summary.test.ts +237 -0
- package/src/lib/__tests__/file-serve.test.ts +178 -0
- package/src/lib/__tests__/file-utils.test.ts +177 -0
- package/src/lib/__tests__/internal-api-guard.test.ts +151 -0
- package/src/lib/__tests__/logger.test.ts +181 -0
- package/src/lib/__tests__/platform.test.ts +566 -0
- package/src/lib/__tests__/reveal-route-security.test.ts +65 -0
- package/src/lib/__tests__/schemas.test.ts +377 -0
- package/src/lib/__tests__/terminal-link-provider.test.ts +160 -0
- package/src/lib/__tests__/upload-route-security.test.ts +120 -0
- package/src/lib/ai/__tests__/capability-resolver.test.ts +71 -0
- package/src/lib/ai/__tests__/claude-cli-adapter.test.ts +103 -0
- package/src/lib/ai/__tests__/provider-registry.test.ts +74 -0
- package/src/lib/pty/__tests__/ws-server-assistant.test.ts +7 -0
- package/.next/standalone/tower/.claude/rules/process-lifecycle.md +0 -31
- package/.next/standalone/tower/.claude/rules/security.md +0 -29
- package/.next/standalone/tower/.claude/rules/ui.md +0 -105
- package/.next/standalone/tower/AGENTS.md +0 -325
- package/.next/standalone/tower/CHANGELOG.md +0 -63
- package/.next/standalone/tower/CLAUDE.md +0 -33
- package/.next/standalone/tower/LICENSE +0 -21
- package/.next/standalone/tower/README.md +0 -214
- package/.next/standalone/tower/README.zh.md +0 -212
- package/.next/standalone/tower/bin/tower.mjs +0 -180
- package/.next/standalone/tower/docs/README.md +0 -51
- package/.next/standalone/tower/docs/ai/README.md +0 -91
- package/.next/standalone/tower/docs/ai/cli-abstraction-design.md +0 -398
- package/.next/standalone/tower/docs/ai/cli-abstraction-plan.md +0 -1345
- package/.next/standalone/tower/docs/assets-notes/README.md +0 -41
- package/.next/standalone/tower/docs/assistant/README.md +0 -48
- package/.next/standalone/tower/docs/board/README.md +0 -36
- package/.next/standalone/tower/docs/diagrams/tower-ai-architecture-en.html +0 -259
- package/.next/standalone/tower/docs/diagrams/tower-ai-architecture.html +0 -259
- package/.next/standalone/tower/docs/diagrams/tower-data-model-en.html +0 -344
- package/.next/standalone/tower/docs/diagrams/tower-data-model.html +0 -344
- package/.next/standalone/tower/docs/diagrams/tower-module-map-en.html +0 -176
- package/.next/standalone/tower/docs/diagrams/tower-module-map.html +0 -176
- package/.next/standalone/tower/docs/diagrams/tower-system-architecture-en.html +0 -336
- package/.next/standalone/tower/docs/diagrams/tower-system-architecture.html +0 -336
- package/.next/standalone/tower/docs/diagrams/tower-task-lifecycle-en.html +0 -251
- package/.next/standalone/tower/docs/diagrams/tower-task-lifecycle.html +0 -251
- package/.next/standalone/tower/docs/en/guide/architecture.md +0 -79
- package/.next/standalone/tower/docs/en/guide/diagrams.md +0 -24
- package/.next/standalone/tower/docs/en/guide/getting-started.md +0 -80
- package/.next/standalone/tower/docs/en/guide/introduction.md +0 -84
- package/.next/standalone/tower/docs/en/index.md +0 -36
- package/.next/standalone/tower/docs/en/modules/ai.md +0 -110
- package/.next/standalone/tower/docs/en/modules/assets-notes.md +0 -56
- package/.next/standalone/tower/docs/en/modules/assistant.md +0 -63
- package/.next/standalone/tower/docs/en/modules/board.md +0 -44
- package/.next/standalone/tower/docs/en/modules/git.md +0 -55
- package/.next/standalone/tower/docs/en/modules/i18n.md +0 -35
- package/.next/standalone/tower/docs/en/modules/mcp.md +0 -62
- package/.next/standalone/tower/docs/en/modules/missions.md +0 -47
- package/.next/standalone/tower/docs/en/modules/project.md +0 -57
- package/.next/standalone/tower/docs/en/modules/search.md +0 -49
- package/.next/standalone/tower/docs/en/modules/settings.md +0 -63
- package/.next/standalone/tower/docs/en/modules/task.md +0 -82
- package/.next/standalone/tower/docs/en/modules/terminal.md +0 -73
- package/.next/standalone/tower/docs/en/modules/workspace.md +0 -61
- package/.next/standalone/tower/docs/git/README.md +0 -42
- package/.next/standalone/tower/docs/guide/architecture.md +0 -29
- package/.next/standalone/tower/docs/guide/diagrams.md +0 -24
- package/.next/standalone/tower/docs/guide/getting-started.md +0 -80
- package/.next/standalone/tower/docs/guide/introduction.md +0 -84
- package/.next/standalone/tower/docs/i18n/README.md +0 -23
- package/.next/standalone/tower/docs/index.md +0 -36
- package/.next/standalone/tower/docs/mcp/README.md +0 -50
- package/.next/standalone/tower/docs/missions/README.md +0 -40
- package/.next/standalone/tower/docs/modules/ai.md +0 -104
- package/.next/standalone/tower/docs/modules/assets-notes.md +0 -68
- package/.next/standalone/tower/docs/modules/assistant.md +0 -74
- package/.next/standalone/tower/docs/modules/board.md +0 -56
- package/.next/standalone/tower/docs/modules/git.md +0 -61
- package/.next/standalone/tower/docs/modules/i18n.md +0 -38
- package/.next/standalone/tower/docs/modules/mcp.md +0 -68
- package/.next/standalone/tower/docs/modules/missions.md +0 -54
- package/.next/standalone/tower/docs/modules/project.md +0 -65
- package/.next/standalone/tower/docs/modules/search.md +0 -57
- package/.next/standalone/tower/docs/modules/settings.md +0 -72
- package/.next/standalone/tower/docs/modules/task.md +0 -82
- package/.next/standalone/tower/docs/modules/terminal.md +0 -70
- package/.next/standalone/tower/docs/modules/workspace.md +0 -68
- package/.next/standalone/tower/docs/package.json +0 -11
- package/.next/standalone/tower/docs/pnpm-lock.yaml +0 -1620
- package/.next/standalone/tower/docs/postcss.config.mjs +0 -2
- package/.next/standalone/tower/docs/project/README.md +0 -45
- package/.next/standalone/tower/docs/public/banner.png +0 -0
- package/.next/standalone/tower/docs/public/diagrams/tower-ai-architecture-en.html +0 -259
- package/.next/standalone/tower/docs/public/diagrams/tower-ai-architecture.html +0 -259
- package/.next/standalone/tower/docs/public/diagrams/tower-data-model-en.html +0 -344
- package/.next/standalone/tower/docs/public/diagrams/tower-data-model.html +0 -344
- package/.next/standalone/tower/docs/public/diagrams/tower-module-map-en.html +0 -176
- package/.next/standalone/tower/docs/public/diagrams/tower-module-map.html +0 -176
- package/.next/standalone/tower/docs/public/diagrams/tower-system-architecture-en.html +0 -336
- package/.next/standalone/tower/docs/public/diagrams/tower-system-architecture.html +0 -336
- package/.next/standalone/tower/docs/public/diagrams/tower-task-lifecycle-en.html +0 -251
- package/.next/standalone/tower/docs/public/diagrams/tower-task-lifecycle.html +0 -251
- package/.next/standalone/tower/docs/search/README.md +0 -37
- package/.next/standalone/tower/docs/settings/README.md +0 -43
- package/.next/standalone/tower/docs/task/README.md +0 -67
- package/.next/standalone/tower/docs/terminal/README.md +0 -58
- package/.next/standalone/tower/docs/workspace/README.md +0 -50
- package/.next/standalone/tower/docs/zh/guide/architecture.md +0 -29
- package/.next/standalone/tower/docs/zh/guide/diagrams.md +0 -24
- package/.next/standalone/tower/docs/zh/guide/getting-started.md +0 -80
- package/.next/standalone/tower/docs/zh/guide/introduction.md +0 -66
- package/.next/standalone/tower/docs/zh/index.md +0 -23
- package/.next/standalone/tower/docs/zh/modules/ai.md +0 -104
- package/.next/standalone/tower/docs/zh/modules/assets-notes.md +0 -68
- package/.next/standalone/tower/docs/zh/modules/assistant.md +0 -74
- package/.next/standalone/tower/docs/zh/modules/board.md +0 -56
- package/.next/standalone/tower/docs/zh/modules/git.md +0 -61
- package/.next/standalone/tower/docs/zh/modules/i18n.md +0 -38
- package/.next/standalone/tower/docs/zh/modules/mcp.md +0 -68
- package/.next/standalone/tower/docs/zh/modules/missions.md +0 -54
- package/.next/standalone/tower/docs/zh/modules/project.md +0 -65
- package/.next/standalone/tower/docs/zh/modules/search.md +0 -57
- package/.next/standalone/tower/docs/zh/modules/settings.md +0 -72
- package/.next/standalone/tower/docs/zh/modules/task.md +0 -82
- package/.next/standalone/tower/docs/zh/modules/terminal.md +0 -70
- package/.next/standalone/tower/docs/zh/modules/workspace.md +0 -68
- package/.next/standalone/tower/eslint.config.mjs +0 -18
- package/.next/standalone/tower/next.config.ts +0 -15
- package/.next/standalone/tower/package.json +0 -117
- package/.next/standalone/tower/playwright.config.ts +0 -28
- package/.next/standalone/tower/pnpm-lock.yaml +0 -10524
- package/.next/standalone/tower/pnpm-workspace.yaml +0 -6
- package/.next/standalone/tower/prisma/init-fts.ts +0 -23
- package/.next/standalone/tower/prisma/schema.prisma +0 -290
- package/.next/standalone/tower/prompts/backend-developer.md +0 -20
- package/.next/standalone/tower/prompts/code-reviewer.md +0 -19
- package/.next/standalone/tower/prompts/frontend-developer.md +0 -20
- package/.next/standalone/tower/prompts/product-manager.md +0 -16
- package/.next/standalone/tower/public/banner.jpg +0 -0
- package/.next/standalone/tower/public/logo.png +0 -0
- package/.next/standalone/tower/scripts/copy-monaco.js +0 -27
- package/.next/standalone/tower/scripts/init-db.ts +0 -74
- package/.next/standalone/tower/scripts/migrate-data.ts +0 -102
- package/.next/standalone/tower/server.js +0 -38
- package/.next/standalone/tower/src/app/favicon.ico +0 -0
- package/.next/standalone/tower/src/mcp/db.ts +0 -11
- package/.next/standalone/tower/src/mcp/index.ts +0 -15
- package/.next/standalone/tower/src/mcp/server.ts +0 -52
- package/.next/standalone/tower/src/mcp/tools/knowledge-tools.ts +0 -100
- package/.next/standalone/tower/src/mcp/tools/label-tools.ts +0 -70
- package/.next/standalone/tower/src/mcp/tools/note-asset-tools.ts +0 -271
- package/.next/standalone/tower/src/mcp/tools/project-tools.ts +0 -79
- package/.next/standalone/tower/src/mcp/tools/report-tools.ts +0 -214
- package/.next/standalone/tower/src/mcp/tools/search-tools.ts +0 -32
- package/.next/standalone/tower/src/mcp/tools/task-tools.ts +0 -250
- package/.next/standalone/tower/src/mcp/tools/terminal-tools.ts +0 -154
- package/.next/standalone/tower/src/mcp/tools/workspace-tools.ts +0 -73
- package/.next/standalone/tower/tests/e2e/chat-flow.spec.ts +0 -249
- package/.next/standalone/tower/tests/e2e/notes-assets.spec.ts +0 -287
- package/.next/standalone/tower/tests/e2e/search.spec.ts +0 -186
- package/.next/standalone/tower/tests/e2e/settings-flow.spec.ts +0 -250
- package/.next/standalone/tower/tests/e2e/settings.spec.ts +0 -261
- package/.next/standalone/tower/tests/e2e/smoke.spec.ts +0 -317
- package/.next/standalone/tower/tests/e2e/task-flow.spec.ts +0 -287
- package/.next/standalone/tower/tests/e2e/workbench.spec.ts +0 -307
- package/.next/standalone/tower/tests/setup.ts +0 -15
- package/.next/standalone/tower/tests/unit/actions/agent-actions.test.ts +0 -157
- package/.next/standalone/tower/tests/unit/actions/config-actions.test.ts +0 -170
- package/.next/standalone/tower/tests/unit/actions/file-actions.test.ts +0 -283
- package/.next/standalone/tower/tests/unit/actions/git-actions.test.ts +0 -34
- package/.next/standalone/tower/tests/unit/actions/preview-actions.test.ts +0 -177
- package/.next/standalone/tower/tests/unit/actions/search-actions.test.ts +0 -358
- package/.next/standalone/tower/tests/unit/actions/task-actions.test.ts +0 -173
- package/.next/standalone/tower/tests/unit/api/diff-route.test.ts +0 -9
- package/.next/standalone/tower/tests/unit/api/file-serving.test.ts +0 -88
- package/.next/standalone/tower/tests/unit/api/merge-route.test.ts +0 -9
- package/.next/standalone/tower/tests/unit/api/stream-persist-result.test.ts +0 -7
- package/.next/standalone/tower/tests/unit/api/stream-send-back.test.ts +0 -7
- package/.next/standalone/tower/tests/unit/components/asset-item.test.tsx +0 -105
- package/.next/standalone/tower/tests/unit/components/asset-list.test.tsx +0 -51
- package/.next/standalone/tower/tests/unit/components/assets/asset-upload.test.tsx +0 -70
- package/.next/standalone/tower/tests/unit/components/board-stats.test.tsx +0 -32
- package/.next/standalone/tower/tests/unit/components/category-filter.test.tsx +0 -58
- package/.next/standalone/tower/tests/unit/components/cli-adapter-tester.test.tsx +0 -160
- package/.next/standalone/tower/tests/unit/components/create-task-dialog.test.tsx +0 -162
- package/.next/standalone/tower/tests/unit/components/file-tree.test.tsx +0 -172
- package/.next/standalone/tower/tests/unit/components/note-card.test.tsx +0 -71
- package/.next/standalone/tower/tests/unit/components/note-editor.test.tsx +0 -39
- package/.next/standalone/tower/tests/unit/components/prompts-config.test.tsx +0 -200
- package/.next/standalone/tower/tests/unit/components/search-dialog.test.tsx +0 -223
- package/.next/standalone/tower/tests/unit/components/system-config.test.tsx +0 -32
- package/.next/standalone/tower/tests/unit/hooks/hook-registration.test.ts +0 -89
- package/.next/standalone/tower/tests/unit/hooks/stop-hook.test.ts +0 -108
- package/.next/standalone/tower/tests/unit/lib/asset-actions.test.ts +0 -257
- package/.next/standalone/tower/tests/unit/lib/file-utils.test.ts +0 -102
- package/.next/standalone/tower/tests/unit/lib/fs-security.test.ts +0 -34
- package/.next/standalone/tower/tests/unit/lib/fts.test.ts +0 -214
- package/.next/standalone/tower/tests/unit/lib/git-url.test.ts +0 -258
- package/.next/standalone/tower/tests/unit/lib/instrumentation.test.ts +0 -86
- package/.next/standalone/tower/tests/unit/lib/local-path-to-api-url.test.ts +0 -40
- package/.next/standalone/tower/tests/unit/lib/mime-magic.test.ts +0 -95
- package/.next/standalone/tower/tests/unit/lib/note-actions.test.ts +0 -296
- package/.next/standalone/tower/tests/unit/lib/preview-process-manager.test.ts +0 -107
- package/.next/standalone/tower/tests/unit/lib/process-manager.test.ts +0 -10
- package/.next/standalone/tower/tests/unit/lib/pty-session.test.ts +0 -171
- package/.next/standalone/tower/tests/unit/lib/search.test.ts +0 -289
- package/.next/standalone/tower/tests/unit/lib/session-store.test.ts +0 -111
- package/.next/standalone/tower/tests/unit/lib/utils.test.ts +0 -33
- package/.next/standalone/tower/tests/unit/lib/worktree.test.ts +0 -190
- package/.next/standalone/tower/tests/unit/mcp/identify-project.test.ts +0 -217
- package/.next/standalone/tower/tests/unit/mcp/manage-assets.test.ts +0 -199
- package/.next/standalone/tower/tests/unit/mcp/manage-notes.test.ts +0 -304
- package/.next/standalone/tower/tests/unit/mcp/search-tools.test.ts +0 -186
- package/.next/standalone/tower/tests/unit/missions-merge.test.ts +0 -43
- package/.next/standalone/tower/tower-studio-0.1.1.tgz +0 -0
- package/.next/standalone/tower/tsconfig.json +0 -34
- package/.next/standalone/tower/vitest.config.ts +0 -17
- package/.next/static/a6HR9cTK7s4aKfE5dWzjz/_buildManifest.js +0 -11
- package/.next/static/a6HR9cTK7s4aKfE5dWzjz/_clientMiddlewareManifest.js +0 -1
- package/.next/static/a6HR9cTK7s4aKfE5dWzjz/_ssgManifest.js +0 -1
- package/.next/static/chunks/00z-g3x93ngvn.js +0 -1
- package/.next/static/chunks/024pdsc27tjdd.js +0 -5
- package/.next/static/chunks/02dd83gbiv778.js +0 -1
- package/.next/static/chunks/03e.4ymu.j5wl.js +0 -1
- package/.next/static/chunks/03~yq9q893hmn.js +0 -1
- package/.next/static/chunks/05-b9qqm3av9~.js +0 -1
- package/.next/static/chunks/05~v02mkan5z..js +0 -1
- package/.next/static/chunks/0abtpeymj-58i.js +0 -1
- package/.next/static/chunks/0b6us7uq72u-d.js +0 -1
- package/.next/static/chunks/0drgc-oztq6o-.css +0 -1
- package/.next/static/chunks/0eaa2lmymh2fx.js +0 -1
- package/.next/static/chunks/0gb82g.6g90mn.js +0 -1
- package/.next/static/chunks/0gnm22yv~f54b.js +0 -1
- package/.next/static/chunks/0j9qriqni_r1..js +0 -2
- package/.next/static/chunks/0k.u8sxy~e469.js +0 -4
- package/.next/static/chunks/0lnhjf2a~jaco.js +0 -83
- package/.next/static/chunks/0lvd52mjiit6s.js +0 -1
- package/.next/static/chunks/0mq0uqbbbb1~2.js +0 -1
- package/.next/static/chunks/0neevhl_o1ozu.css +0 -2
- package/.next/static/chunks/0omj~p3uxkic-.js +0 -1
- package/.next/static/chunks/0t-gr6j-c65qb.js +0 -1
- package/.next/static/chunks/0t16ai99uv4j3.js +0 -1
- package/.next/static/chunks/0tcl81ybuob5i.js +0 -1
- package/.next/static/chunks/0uqimvsni_op~.js +0 -1
- package/.next/static/chunks/0wt3kws~_yr8z.js +0 -1
- package/.next/static/chunks/0xzdu87n_for1.js +0 -5
- package/.next/static/chunks/0y0tdl.rl6v1u.js +0 -1
- package/.next/static/chunks/0z2bzovqhl2f5.js +0 -1
- package/.next/static/chunks/0z4y0x1ifgy.e.js +0 -1
- package/.next/static/chunks/0z7bwntvfhxzi.js +0 -12
- package/.next/static/chunks/102ijqpvi0z-d.js +0 -1
- package/.next/static/chunks/10n23t.1hpb-1.js +0 -1
- package/.next/static/chunks/11_e3-j5gzbj4.js +0 -1
- package/.next/static/chunks/14.ims4y7osot.js +0 -1
- package/.next/static/chunks/14xzmrt5ly6gq.js +0 -31
- package/.next/static/chunks/151wr~6x8aclx.js +0 -1
- package/.next/static/chunks/169po6_~f3-d5.js +0 -1
- package/.next/static/chunks/16w-ap~msrwpj.js +0 -1
- package/.next/static/chunks/176n7f13ve~a9.js +0 -1
- package/.next/static/chunks/17oc2l.ekcs8b.css +0 -1
- package/.next/static/chunks/turbopack-0wjmrsi.z32s0.js +0 -1
- package/.next/static/media/4fa387ec64143e14-s.0q3udbd2bu5yp.woff2 +0 -0
- package/.next/static/media/7178b3e590c64307-s.11.cyxs5p-0z~.woff2 +0 -0
- package/.next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2 +0 -0
- package/.next/static/media/8a480f0b521d4e75-s.06d3mdzz5bre_.woff2 +0 -0
- package/.next/static/media/apple-icon.16aocl-s-v2qz.png +0 -0
- package/.next/static/media/bbc41e54d2fcbd21-s.0gw~uztddq1df.woff2 +0 -0
- package/.next/static/media/caa3a2e1cccd8315-s.p.16t1db8_9y2o~.woff2 +0 -0
- package/.next/static/media/favicon.0y2d6j9cou~8p.ico +0 -0
- package/.next/static/media/icon0.0a6mkq6meyird.svg +0 -1
- package/.next/static/media/icon1.04ux133882seb.png +0 -0
- /package/{.next/standalone/tower/components.json → components.json} +0 -0
- /package/{.next/standalone/tower/postcss.config.mjs → postcss.config.mjs} +0 -0
- /package/{.next/standalone/tower/prisma → prisma}/prisma/dev.db +0 -0
- /package/{.next/standalone/tower/prisma → prisma}/seed.ts +0 -0
- /package/{.next/standalone/tower/docs/public → public}/banner.jpg +0 -0
- /package/{.next/standalone/tower/docs/public → public}/logo.png +0 -0
- /package/{.next/standalone/tower/public → public}/web-app-manifest-192x192.png +0 -0
- /package/{.next/standalone/tower/public → public}/web-app-manifest-512x512.png +0 -0
- /package/{.next/standalone/tower/scripts → scripts}/init-tower.ts +0 -0
- /package/{.next/standalone/tower/scripts → scripts}/post-tool-hook.js +0 -0
- /package/{.next/standalone/tower/scripts → scripts}/session-start-hook.js +0 -0
- /package/{.next/standalone/tower/scripts → scripts}/stop-hook.js +0 -0
- /package/{.next/standalone/tower/skills → skills}/tower/SKILL.md +0 -0
- /package/{.next/standalone/tower/src → src}/actions/agent-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/agent-config-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/ai-config-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/asset-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/assistant-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/cli-profile-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/config-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/file-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/git-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/label-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/note-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/onboarding-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/preview-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/project-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/prompt-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/report-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/search-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/search-code-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/task-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/actions/workspace-actions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/adapters/test/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/browse-fs/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/files/assets/[projectId]/[filename]/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/git/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/assets/[projectId]/[filename]/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/assets/reveal/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/assistant/chat/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/assistant/images/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/assistant/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/assistant/sessions/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/cache/[...segments]/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/hooks/install/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/hooks/session/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/hooks/stop/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/hooks/upload/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/notifications/pending/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/terminal/[taskId]/buffer/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/terminal/[taskId]/input/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/internal/terminal/[taskId]/start/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/tasks/[taskId]/diff/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/api/tasks/[taskId]/merge/route.ts +0 -0
- /package/{.next/standalone/tower/src → src}/app/apple-icon.png +0 -0
- /package/{.next/standalone/tower/docs/public → src/app}/favicon.ico +0 -0
- /package/{.next/standalone/tower/src → src}/app/globals.css +0 -0
- /package/{.next/standalone/tower/src → src}/app/icon0.svg +0 -0
- /package/{.next/standalone/tower/src → src}/app/icon1.png +0 -0
- /package/{.next/standalone/tower/src → src}/app/layout.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/manifest.json +0 -0
- /package/{.next/standalone/tower/src → src}/app/missions/missions-client.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/missions/page.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/onboarding/page.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/page.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/settings/page.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/archive/archive-page-client.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/archive/page.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/assets/assets-page-client.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/assets/page.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/board-page-client.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/notes/notes-page-client.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/notes/page.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/page.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/projects/[projectId]/page.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/tasks/[taskId]/page.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/tasks/[taskId]/task-page-client.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/app/workspaces/page.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/assets/asset-item.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/assets/asset-list.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/assets/asset-upload.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/assets/image-lightbox.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/assets/text-preview-dialog.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/assistant/assistant-chat-bubble.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/assistant/assistant-chat.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/assistant/assistant-panel.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/assistant/assistant-provider.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/assistant/image-preview-modal.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/assistant/image-thumbnail-strip.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/board/board-column.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/board/board-filters.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/board/board-stats.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/board/column-tasks-dialog.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/board/create-task-dialog.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/board/kanban-board.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/board/project-tabs.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/board/task-card-context-menu.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/board/task-card.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/layout/app-sidebar.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/layout/folder-browser-dialog.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/layout/layout-client.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/layout/search-dialog.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/layout/sub-page-nav.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/layout/top-bar.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/missions/grid-layout-presets.ts +0 -0
- /package/{.next/standalone/tower/src → src}/components/missions/grid-preset-picker.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/missions/merge-missions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/components/missions/mission-card.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/missions/task-picker-dialog.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/notes/category-filter.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/notes/note-card.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/notes/note-editor.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/notes/note-list.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/notifications/notification-permission-banner.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/notifications/use-notification-listener.ts +0 -0
- /package/{.next/standalone/tower/src → src}/components/onboarding/guided-tour.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/onboarding/onboarding-wizard.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/onboarding/wizard-step-cli.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/onboarding/wizard-step-username.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/project/create-project-dialog.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/project/import-project-dialog.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/providers/theme-provider.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/repository/create-branch-dialog.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/repository/git-changes-panel.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/repository/git-log-panel.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/repository/git-stash-panel.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/repository/repo-sidebar.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/settings/cli-adapter-tester.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/settings/settings-page.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/code-editor.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/code-search.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/diff-editor.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/editor-git-panel.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/editor-tabs.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/execution-timeline.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/file-tree-context-menu.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/file-tree-node.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/file-tree.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/preview-panel.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/task-detail-panel.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/task-diff-view.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/task-file-changes.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/task-merge-confirm-dialog.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/task-metadata.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/task-notes-panel.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/task-overview-drawer.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/task-terminal.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/terminal-portal.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/task/types.ts +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/avatar.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/badge.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/button.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/card.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/command.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/dialog.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/dropdown-menu.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/empty-state.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/error-boundary.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/input-group.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/input.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/label.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/popover.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/scroll-area.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/segmented-control.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/select.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/separator.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/sheet.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/sonner.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/switch.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/tabs.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/textarea.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/toast.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/components/ui/tooltip.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/hooks/sse-event-reducer.ts +0 -0
- /package/{.next/standalone/tower/src → src}/hooks/use-assistant-chat.ts +0 -0
- /package/{.next/standalone/tower/src → src}/hooks/use-image-upload.ts +0 -0
- /package/{.next/standalone/tower/src → src}/instrumentation.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/ai/adapters/cli/claude-cli-adapter.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/ai/capability-resolver.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/ai/provider-registry.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/ai/providers/claude.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/ai/providers/index.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/ai/types.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/assistant-constants.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/assistant-message-converter.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/assistant-sessions.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/build-multimodal-prompt.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/claude-session.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/cli-test.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/config-defaults.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/config-reader.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/constants.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/db.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/diff-parser.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/execution-summary.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/file-serve-client.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/file-serve.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/file-utils.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/fs-security.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/fts.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/git-api.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/git-url.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/i18n/en.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/i18n/types.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/i18n/zh.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/i18n.tsx +0 -0
- /package/{.next/standalone/tower/src → src}/lib/init-tower.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/instrumentation-tasks.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/internal-api-guard.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/logger.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/mime-magic.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/platform.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/preview-process.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/pty/pty-session.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/pty/session-store.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/pty/ws-server.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/schemas.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/search.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/terminal-link-provider.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/tower-dir.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/utils.ts +0 -0
- /package/{.next/standalone/tower/src → src}/lib/worktree.ts +0 -0
- /package/{.next/standalone/tower/src → src}/stores/board-store.ts +0 -0
- /package/{.next/standalone/tower/src → src}/stores/task-execution-store.ts +0 -0
- /package/{.next/standalone/tower/src → src}/types/index.ts +0 -0
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { db } from "../db";
|
|
3
|
-
|
|
4
|
-
export const workspaceTools = {
|
|
5
|
-
list_workspaces: {
|
|
6
|
-
description: "List all workspaces ordered by last updated, including project count for each.",
|
|
7
|
-
schema: z.object({}),
|
|
8
|
-
handler: async (_args: Record<string, never>) => {
|
|
9
|
-
const workspaces = await db.workspace.findMany({
|
|
10
|
-
include: {
|
|
11
|
-
projects: {
|
|
12
|
-
select: { id: true },
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
orderBy: { updatedAt: "desc" },
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
return workspaces.map(({ projects, ...rest }) => ({
|
|
19
|
-
...rest,
|
|
20
|
-
projectCount: projects.length,
|
|
21
|
-
}));
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
create_workspace: {
|
|
26
|
-
description: "Create a new workspace with a name and optional description.",
|
|
27
|
-
schema: z.object({
|
|
28
|
-
name: z.string(),
|
|
29
|
-
description: z.string().optional(),
|
|
30
|
-
}),
|
|
31
|
-
handler: async (args: { name: string; description?: string }) => {
|
|
32
|
-
return db.workspace.create({
|
|
33
|
-
data: {
|
|
34
|
-
name: args.name,
|
|
35
|
-
description: args.description,
|
|
36
|
-
},
|
|
37
|
-
});
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
|
|
41
|
-
update_workspace: {
|
|
42
|
-
description: "Update an existing workspace's name and/or description.",
|
|
43
|
-
schema: z.object({
|
|
44
|
-
workspaceId: z.string(),
|
|
45
|
-
name: z.string().optional(),
|
|
46
|
-
description: z.string().optional(),
|
|
47
|
-
}),
|
|
48
|
-
handler: async (args: { workspaceId: string; name?: string; description?: string }) => {
|
|
49
|
-
return db.workspace.update({
|
|
50
|
-
where: { id: args.workspaceId },
|
|
51
|
-
data: {
|
|
52
|
-
name: args.name,
|
|
53
|
-
description: args.description,
|
|
54
|
-
},
|
|
55
|
-
});
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
|
|
59
|
-
delete_workspace: {
|
|
60
|
-
description: "Delete a workspace by ID. Cascade delete is handled by the Prisma schema.",
|
|
61
|
-
schema: z.object({
|
|
62
|
-
workspaceId: z.string(),
|
|
63
|
-
}),
|
|
64
|
-
handler: async (args: { workspaceId: string }) => {
|
|
65
|
-
const count = await db.workspace.count();
|
|
66
|
-
if (count <= 1) {
|
|
67
|
-
throw new Error("Cannot delete the last workspace");
|
|
68
|
-
}
|
|
69
|
-
await db.workspace.delete({ where: { id: args.workspaceId } });
|
|
70
|
-
return { deleted: true, workspaceId: args.workspaceId };
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
};
|
|
@@ -1,249 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E2E-02: Chat Assistant Flow
|
|
3
|
-
*
|
|
4
|
-
* Covers the global chat assistant: open panel → send message → user bubble visible
|
|
5
|
-
* → (response bubble or graceful timeout) → paste image → thumbnail appears.
|
|
6
|
-
*
|
|
7
|
-
* NOTE: The "receive assistant response" test depends on a running Claude SDK backend
|
|
8
|
-
* reachable at /api/internal/assistant/chat. In CI without credentials it will
|
|
9
|
-
* either see an error bubble or a timeout — the test handles both gracefully.
|
|
10
|
-
*/
|
|
11
|
-
import { test, expect } from "@playwright/test";
|
|
12
|
-
|
|
13
|
-
// ---------------------------------------------------------------------------
|
|
14
|
-
// Helper: navigate to settings and switch assistant to chat mode
|
|
15
|
-
// ---------------------------------------------------------------------------
|
|
16
|
-
|
|
17
|
-
async function ensureChatMode(page: import("@playwright/test").Page) {
|
|
18
|
-
await page.goto("/settings");
|
|
19
|
-
await page.locator("nav").waitFor({ state: "visible", timeout: 10000 });
|
|
20
|
-
// Allow React useEffects to hydrate (locale, mounted state, config values)
|
|
21
|
-
await page.waitForTimeout(500);
|
|
22
|
-
|
|
23
|
-
// Find the Communication Mode select — look for "Chat" / "聊天模式" option
|
|
24
|
-
// The select trigger shows the current mode; if already "Chat" / "聊天模式", skip
|
|
25
|
-
const chatOptionText = /Chat|聊天模式/;
|
|
26
|
-
const terminalOptionText = /Terminal|终端模式/;
|
|
27
|
-
|
|
28
|
-
// The select trigger for communication mode appears after mounting
|
|
29
|
-
// We look for a select that currently shows "Terminal" / "终端模式" and switch it to Chat
|
|
30
|
-
const deadline = Date.now() + 8000;
|
|
31
|
-
while (Date.now() < deadline) {
|
|
32
|
-
// Check if any select trigger currently shows terminal mode
|
|
33
|
-
const triggers = page.locator("button[role='combobox']");
|
|
34
|
-
const count = await triggers.count();
|
|
35
|
-
let found = false;
|
|
36
|
-
for (let i = 0; i < count; i++) {
|
|
37
|
-
const text = await triggers.nth(i).textContent();
|
|
38
|
-
if (text && terminalOptionText.test(text)) {
|
|
39
|
-
// Click to open the dropdown
|
|
40
|
-
await triggers.nth(i).click();
|
|
41
|
-
await page.waitForTimeout(200);
|
|
42
|
-
// Click the Chat option
|
|
43
|
-
const chatItem = page.locator("[role='option']").filter({ hasText: chatOptionText });
|
|
44
|
-
if (await chatItem.count() > 0) {
|
|
45
|
-
await chatItem.first().click();
|
|
46
|
-
await page.waitForTimeout(300);
|
|
47
|
-
found = true;
|
|
48
|
-
}
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
if (found) break;
|
|
53
|
-
await page.waitForTimeout(200);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Navigate away and back to /workspaces to ensure fresh config is picked up
|
|
57
|
-
await page.goto("/workspaces");
|
|
58
|
-
await page.waitForLoadState("domcontentloaded");
|
|
59
|
-
await page.waitForTimeout(500);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// ---------------------------------------------------------------------------
|
|
63
|
-
// Helper: open the assistant panel via the top-bar Bot button
|
|
64
|
-
// ---------------------------------------------------------------------------
|
|
65
|
-
|
|
66
|
-
async function openAssistantPanel(page: import("@playwright/test").Page) {
|
|
67
|
-
// Click the Bot icon button in the top-bar
|
|
68
|
-
const assistantBtn = page.locator("button[aria-label='助手'], button[aria-label='Assistant']").first();
|
|
69
|
-
await assistantBtn.waitFor({ state: "visible", timeout: 8000 });
|
|
70
|
-
await assistantBtn.click();
|
|
71
|
-
|
|
72
|
-
// Wait for assistant panel to appear — the panel title bar contains a Bot icon
|
|
73
|
-
// and a title text "助手" / "Assistant". We wait for the close button to appear
|
|
74
|
-
// inside the panel to confirm it opened.
|
|
75
|
-
const closeBtn = page.locator("button[aria-label]").filter({ hasText: "" }).filter({
|
|
76
|
-
has: page.locator("svg"),
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
// More reliable: wait for the chat textarea to appear (confirms panel is open + chat mode)
|
|
80
|
-
await page
|
|
81
|
-
.locator("textarea[placeholder]")
|
|
82
|
-
.waitFor({ state: "visible", timeout: 10000 });
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// ---------------------------------------------------------------------------
|
|
86
|
-
// Test suite
|
|
87
|
-
// ---------------------------------------------------------------------------
|
|
88
|
-
|
|
89
|
-
test.describe.serial("Chat Assistant Flow", () => {
|
|
90
|
-
|
|
91
|
-
// 1. Setup: switch to chat mode
|
|
92
|
-
test("0. Switch assistant to chat mode in settings", async ({ page }) => {
|
|
93
|
-
await ensureChatMode(page);
|
|
94
|
-
// Verify we are back on workspaces page
|
|
95
|
-
await expect(page).toHaveURL(/\/workspaces/, { timeout: 5000 });
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
// 2. Open the assistant panel
|
|
99
|
-
test("1. Open assistant panel", async ({ page }) => {
|
|
100
|
-
// Navigate to workspaces first
|
|
101
|
-
await page.goto("/workspaces");
|
|
102
|
-
await page.waitForLoadState("domcontentloaded");
|
|
103
|
-
await page.waitForTimeout(500);
|
|
104
|
-
|
|
105
|
-
// Click the assistant button (Bot icon in top-bar)
|
|
106
|
-
const assistantBtn = page.locator("button[aria-label='助手'], button[aria-label='Assistant']").first();
|
|
107
|
-
await assistantBtn.waitFor({ state: "visible", timeout: 8000 });
|
|
108
|
-
await assistantBtn.click();
|
|
109
|
-
|
|
110
|
-
// Confirm the assistant panel opened: the chat textarea should be visible
|
|
111
|
-
const chatInput = page.locator("textarea[placeholder]");
|
|
112
|
-
await expect(chatInput).toBeVisible({ timeout: 10000 });
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
// 3. Send a text message and verify user bubble appears
|
|
116
|
-
test("2. Send a text message and verify user bubble appears", async ({ page }) => {
|
|
117
|
-
await page.goto("/workspaces");
|
|
118
|
-
await page.waitForLoadState("domcontentloaded");
|
|
119
|
-
await page.waitForTimeout(500);
|
|
120
|
-
|
|
121
|
-
// Open the assistant panel
|
|
122
|
-
const assistantBtn = page.locator("button[aria-label='助手'], button[aria-label='Assistant']").first();
|
|
123
|
-
await assistantBtn.waitFor({ state: "visible", timeout: 8000 });
|
|
124
|
-
await assistantBtn.click();
|
|
125
|
-
|
|
126
|
-
// Wait for the chat textarea
|
|
127
|
-
const chatInput = page.locator("textarea[placeholder]");
|
|
128
|
-
await chatInput.waitFor({ state: "visible", timeout: 10000 });
|
|
129
|
-
|
|
130
|
-
// Type a message
|
|
131
|
-
const testMessage = "Hello, please respond with just the word OK";
|
|
132
|
-
await chatInput.click();
|
|
133
|
-
await chatInput.fill(testMessage);
|
|
134
|
-
|
|
135
|
-
// Press Enter to send (the AssistantChat keyDown handler sends on Enter without Shift)
|
|
136
|
-
await chatInput.press("Enter");
|
|
137
|
-
|
|
138
|
-
// Verify the user bubble appears — UserBubble has aria-label="You"
|
|
139
|
-
const userBubble = page.locator('[aria-label="You"]').first();
|
|
140
|
-
await expect(userBubble).toBeVisible({ timeout: 8000 });
|
|
141
|
-
|
|
142
|
-
// Verify the message text is in the bubble
|
|
143
|
-
await expect(userBubble).toContainText(testMessage);
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
// 4. Wait for assistant response (Claude-dependent — graceful skip if unavailable)
|
|
147
|
-
//
|
|
148
|
-
// NOTE: This test requires a working Claude Agent SDK connection. In CI or
|
|
149
|
-
// environments without credentials it will see an error message or thinking
|
|
150
|
-
// indicator timeout. The test passes if EITHER a real response OR an error
|
|
151
|
-
// message appears within the timeout.
|
|
152
|
-
test("3. Receive assistant response or error (Claude SDK dependent)", async ({ page }) => {
|
|
153
|
-
test.slow(); // Extends test timeout × 3 (up to 180s with global 60s timeout)
|
|
154
|
-
|
|
155
|
-
await page.goto("/workspaces");
|
|
156
|
-
await page.waitForLoadState("domcontentloaded");
|
|
157
|
-
await page.waitForTimeout(500);
|
|
158
|
-
|
|
159
|
-
// Open assistant panel
|
|
160
|
-
const assistantBtn = page.locator("button[aria-label='助手'], button[aria-label='Assistant']").first();
|
|
161
|
-
await assistantBtn.waitFor({ state: "visible", timeout: 8000 });
|
|
162
|
-
await assistantBtn.click();
|
|
163
|
-
|
|
164
|
-
const chatInput = page.locator("textarea[placeholder]");
|
|
165
|
-
await chatInput.waitFor({ state: "visible", timeout: 10000 });
|
|
166
|
-
|
|
167
|
-
// Send a short message
|
|
168
|
-
await chatInput.click();
|
|
169
|
-
await chatInput.fill("Hi");
|
|
170
|
-
await chatInput.press("Enter");
|
|
171
|
-
|
|
172
|
-
// Wait for user bubble to appear first
|
|
173
|
-
const userBubble = page.locator('[aria-label="You"]').first();
|
|
174
|
-
await expect(userBubble).toBeVisible({ timeout: 8000 });
|
|
175
|
-
|
|
176
|
-
// Now wait for either:
|
|
177
|
-
// a) Assistant response bubble (aria-label="Assistant") — real response
|
|
178
|
-
// b) Error message bubble (contains "Error:" or "Connection error:") — no SDK
|
|
179
|
-
// c) Thinking bubble (role="status") — still waiting
|
|
180
|
-
//
|
|
181
|
-
// We wait up to 120s for any non-user, non-thinking bubble
|
|
182
|
-
const responseOrError = page.locator('[aria-label="Assistant"], [role="status"]');
|
|
183
|
-
await expect(responseOrError.first()).toBeVisible({ timeout: 120_000 });
|
|
184
|
-
|
|
185
|
-
// Test passes regardless of whether it's a real response or thinking indicator
|
|
186
|
-
// This is intentional — the test verifies the UI pipeline works end to end
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
// 5. Paste image and verify thumbnail appears in thumbnail strip
|
|
190
|
-
test("4. Paste image shows thumbnail in thumbnail strip", async ({ page }) => {
|
|
191
|
-
await page.goto("/workspaces");
|
|
192
|
-
await page.waitForLoadState("domcontentloaded");
|
|
193
|
-
await page.waitForTimeout(500);
|
|
194
|
-
|
|
195
|
-
// Open assistant panel
|
|
196
|
-
const assistantBtn = page.locator("button[aria-label='助手'], button[aria-label='Assistant']").first();
|
|
197
|
-
await assistantBtn.waitFor({ state: "visible", timeout: 8000 });
|
|
198
|
-
await assistantBtn.click();
|
|
199
|
-
|
|
200
|
-
const chatInput = page.locator("textarea[placeholder]");
|
|
201
|
-
await chatInput.waitFor({ state: "visible", timeout: 10000 });
|
|
202
|
-
await chatInput.click();
|
|
203
|
-
|
|
204
|
-
// Simulate a clipboard paste event with a 1×1 PNG image
|
|
205
|
-
// The AssistantChat.handlePaste reads clipboardData.items for image/* files
|
|
206
|
-
await page.evaluate(() => {
|
|
207
|
-
const textarea = document.querySelector("textarea");
|
|
208
|
-
if (!textarea) return;
|
|
209
|
-
|
|
210
|
-
// Minimal 1×1 transparent PNG (base64)
|
|
211
|
-
const base64 =
|
|
212
|
-
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
|
|
213
|
-
const binary = atob(base64);
|
|
214
|
-
const bytes = new Uint8Array(binary.length);
|
|
215
|
-
for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
|
|
216
|
-
const file = new File([bytes], "test-image.png", { type: "image/png" });
|
|
217
|
-
|
|
218
|
-
const dt = new DataTransfer();
|
|
219
|
-
dt.items.add(file);
|
|
220
|
-
|
|
221
|
-
const pasteEvent = new ClipboardEvent("paste", {
|
|
222
|
-
clipboardData: dt,
|
|
223
|
-
bubbles: true,
|
|
224
|
-
cancelable: true,
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
textarea.dispatchEvent(pasteEvent);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
// The ImageThumbnailStrip renders a container with thumbnail images.
|
|
231
|
-
// Each thumbnail is an <img> inside a relative h-12 w-12 div.
|
|
232
|
-
// Wait for at least one thumbnail image to appear inside the input area.
|
|
233
|
-
const thumbnail = page.locator("div.border-t").locator("img").first();
|
|
234
|
-
|
|
235
|
-
// Also check for the progress bar (uploading state) — it means paste was handled
|
|
236
|
-
// Use a broader check: any img in the assistant panel area
|
|
237
|
-
const thumbnailStrip = page.locator('[role="progressbar"], div.flex.flex-row.gap-2 img').first();
|
|
238
|
-
|
|
239
|
-
// We wait for either the thumbnail img or the progress bar to appear
|
|
240
|
-
// (upload may be fast or slow depending on network / server state)
|
|
241
|
-
const imgInPanel = page
|
|
242
|
-
.locator("div.border-t")
|
|
243
|
-
.locator("div.flex.flex-row.gap-2 img, img[src^='blob:']")
|
|
244
|
-
.first();
|
|
245
|
-
|
|
246
|
-
await expect(imgInPanel).toBeVisible({ timeout: 10000 });
|
|
247
|
-
});
|
|
248
|
-
|
|
249
|
-
});
|
|
@@ -1,287 +0,0 @@
|
|
|
1
|
-
import { test, expect, type Page } from "@playwright/test";
|
|
2
|
-
|
|
3
|
-
test.describe.serial("Phase 7: Notes & Assets Web UI", () => {
|
|
4
|
-
// Helper: navigate to a workspace that has projects
|
|
5
|
-
async function goToWorkspace(page: Page) {
|
|
6
|
-
await page.goto("/workspaces");
|
|
7
|
-
const sidebar = page.locator("aside");
|
|
8
|
-
// Click first workspace button
|
|
9
|
-
const wsBtn = sidebar.locator("button").filter({ hasText: /测试|Test|E2E/ }).first();
|
|
10
|
-
if (!await wsBtn.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
11
|
-
// Fallback: click any workspace
|
|
12
|
-
const anyWs = sidebar.locator("[data-slot='sidebar-menu-button']").first();
|
|
13
|
-
if (await anyWs.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
14
|
-
await anyWs.click();
|
|
15
|
-
}
|
|
16
|
-
} else {
|
|
17
|
-
await wsBtn.click();
|
|
18
|
-
}
|
|
19
|
-
await page.waitForURL(/\/workspaces\//);
|
|
20
|
-
await page.waitForTimeout(500);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// ─── Notes Page ───
|
|
24
|
-
|
|
25
|
-
test("7.1 侧边栏显示笔记和资源导航链接", async ({ page }) => {
|
|
26
|
-
await goToWorkspace(page);
|
|
27
|
-
const sidebar = page.locator("aside");
|
|
28
|
-
const notesLink = sidebar.locator("a").filter({ hasText: /笔记|Notes/ });
|
|
29
|
-
const assetsLink = sidebar.locator("a").filter({ hasText: /资源|Assets/ });
|
|
30
|
-
await expect(notesLink).toBeVisible({ timeout: 3000 });
|
|
31
|
-
await expect(assetsLink).toBeVisible({ timeout: 3000 });
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test("7.2 点击笔记链接进入笔记页面", async ({ page }) => {
|
|
35
|
-
await goToWorkspace(page);
|
|
36
|
-
const sidebar = page.locator("aside");
|
|
37
|
-
const notesLink = sidebar.locator("a").filter({ hasText: /笔记|Notes/ });
|
|
38
|
-
await notesLink.click();
|
|
39
|
-
await page.waitForURL(/\/notes/);
|
|
40
|
-
// Should see the notes page with a "new note" button
|
|
41
|
-
await expect(
|
|
42
|
-
page.locator("button").filter({ hasText: /新建笔记|New Note/ })
|
|
43
|
-
).toBeVisible({ timeout: 5000 });
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
test("7.3 笔记页面显示分类筛选按钮", async ({ page }) => {
|
|
47
|
-
await goToWorkspace(page);
|
|
48
|
-
const sidebar = page.locator("aside");
|
|
49
|
-
await sidebar.locator("a").filter({ hasText: /笔记|Notes/ }).click();
|
|
50
|
-
await page.waitForURL(/\/notes/);
|
|
51
|
-
await page.waitForTimeout(500);
|
|
52
|
-
// Category filter should show preset categories
|
|
53
|
-
const allBtn = page.locator("button").filter({ hasText: /全部|All/ });
|
|
54
|
-
await expect(allBtn).toBeVisible({ timeout: 3000 });
|
|
55
|
-
// Check at least one preset category is visible
|
|
56
|
-
const categories = ["账号", "环境", "需求", "备忘"];
|
|
57
|
-
let found = false;
|
|
58
|
-
for (const cat of categories) {
|
|
59
|
-
const btn = page.locator("button").filter({ hasText: cat });
|
|
60
|
-
if (await btn.isVisible().catch(() => false)) {
|
|
61
|
-
found = true;
|
|
62
|
-
break;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
expect(found).toBe(true);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test("7.4 新建笔记:填写表单并保存", async ({ page }) => {
|
|
69
|
-
await goToWorkspace(page);
|
|
70
|
-
const sidebar = page.locator("aside");
|
|
71
|
-
await sidebar.locator("a").filter({ hasText: /笔记|Notes/ }).click();
|
|
72
|
-
await page.waitForURL(/\/notes/);
|
|
73
|
-
await page.waitForTimeout(500);
|
|
74
|
-
|
|
75
|
-
// Click new note button
|
|
76
|
-
await page.locator("button").filter({ hasText: /新建笔记|New Note/ }).click();
|
|
77
|
-
await page.waitForTimeout(300);
|
|
78
|
-
|
|
79
|
-
// Fill title
|
|
80
|
-
const titleInput = page.locator("input").filter({ hasNotText: "" }).first();
|
|
81
|
-
await titleInput.fill("E2E测试笔记");
|
|
82
|
-
|
|
83
|
-
// Fill content in textarea
|
|
84
|
-
const textarea = page.locator("textarea");
|
|
85
|
-
await textarea.fill("## 测试内容\n\n这是一条E2E自动化测试创建的笔记。");
|
|
86
|
-
|
|
87
|
-
// Click save
|
|
88
|
-
const saveBtn = page.locator("button").filter({ hasText: /保存|Save/ });
|
|
89
|
-
await saveBtn.click();
|
|
90
|
-
await page.waitForTimeout(1000);
|
|
91
|
-
|
|
92
|
-
// Verify note appears in list
|
|
93
|
-
await expect(page.getByText("E2E测试笔记")).toBeVisible({ timeout: 5000 });
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test("7.5 笔记卡片显示标题和内容预览", async ({ page }) => {
|
|
97
|
-
await goToWorkspace(page);
|
|
98
|
-
const sidebar = page.locator("aside");
|
|
99
|
-
await sidebar.locator("a").filter({ hasText: /笔记|Notes/ }).click();
|
|
100
|
-
await page.waitForURL(/\/notes/);
|
|
101
|
-
await page.waitForTimeout(1000);
|
|
102
|
-
|
|
103
|
-
// The note we created should show title and content preview
|
|
104
|
-
const noteTitle = page.getByText("E2E测试笔记");
|
|
105
|
-
if (!await noteTitle.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
106
|
-
test.skip();
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
await expect(noteTitle).toBeVisible();
|
|
110
|
-
await expect(page.getByText("测试内容")).toBeVisible();
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
test("7.6 编辑笔记", async ({ page }) => {
|
|
114
|
-
await goToWorkspace(page);
|
|
115
|
-
const sidebar = page.locator("aside");
|
|
116
|
-
await sidebar.locator("a").filter({ hasText: /笔记|Notes/ }).click();
|
|
117
|
-
await page.waitForURL(/\/notes/);
|
|
118
|
-
await page.waitForTimeout(1000);
|
|
119
|
-
|
|
120
|
-
const noteTitle = page.getByText("E2E测试笔记");
|
|
121
|
-
if (!await noteTitle.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
122
|
-
test.skip();
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Find and click edit button (pencil icon) - hover to reveal
|
|
127
|
-
const noteCard = noteTitle.locator("xpath=ancestor::div[contains(@class, 'border')]");
|
|
128
|
-
await noteCard.hover();
|
|
129
|
-
await page.waitForTimeout(200);
|
|
130
|
-
const editBtn = noteCard.locator("button[aria-label*='edit'], button:has(svg.lucide-pencil)").first();
|
|
131
|
-
if (await editBtn.isVisible().catch(() => false)) {
|
|
132
|
-
await editBtn.click();
|
|
133
|
-
await page.waitForTimeout(500);
|
|
134
|
-
|
|
135
|
-
// Update title
|
|
136
|
-
const titleInput = page.locator("input").first();
|
|
137
|
-
await titleInput.clear();
|
|
138
|
-
await titleInput.fill("E2E已编辑笔记");
|
|
139
|
-
|
|
140
|
-
// Save
|
|
141
|
-
const saveBtn = page.locator("button").filter({ hasText: /保存|Save/ });
|
|
142
|
-
await saveBtn.click();
|
|
143
|
-
await page.waitForTimeout(1000);
|
|
144
|
-
|
|
145
|
-
await expect(page.getByText("E2E已编辑笔记")).toBeVisible({ timeout: 5000 });
|
|
146
|
-
} else {
|
|
147
|
-
test.skip();
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
test("7.7 分类筛选功能", async ({ page }) => {
|
|
152
|
-
await goToWorkspace(page);
|
|
153
|
-
const sidebar = page.locator("aside");
|
|
154
|
-
await sidebar.locator("a").filter({ hasText: /笔记|Notes/ }).click();
|
|
155
|
-
await page.waitForURL(/\/notes/);
|
|
156
|
-
await page.waitForTimeout(1000);
|
|
157
|
-
|
|
158
|
-
// Click a specific category filter
|
|
159
|
-
const catBtn = page.locator("button").filter({ hasText: "账号" });
|
|
160
|
-
if (await catBtn.isVisible().catch(() => false)) {
|
|
161
|
-
await catBtn.click();
|
|
162
|
-
await page.waitForTimeout(500);
|
|
163
|
-
// The button should be active (amber style)
|
|
164
|
-
await expect(catBtn).toHaveClass(/amber/);
|
|
165
|
-
// Click "All" to reset
|
|
166
|
-
const allBtn = page.locator("button").filter({ hasText: /全部|All/ });
|
|
167
|
-
await allBtn.click();
|
|
168
|
-
await page.waitForTimeout(300);
|
|
169
|
-
} else {
|
|
170
|
-
test.skip();
|
|
171
|
-
}
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
test("7.8 删除笔记", async ({ page }) => {
|
|
175
|
-
await goToWorkspace(page);
|
|
176
|
-
const sidebar = page.locator("aside");
|
|
177
|
-
await sidebar.locator("a").filter({ hasText: /笔记|Notes/ }).click();
|
|
178
|
-
await page.waitForURL(/\/notes/);
|
|
179
|
-
await page.waitForTimeout(1000);
|
|
180
|
-
|
|
181
|
-
const noteTitle = page.getByText(/E2E.*笔记/);
|
|
182
|
-
if (!await noteTitle.isVisible({ timeout: 3000 }).catch(() => false)) {
|
|
183
|
-
test.skip();
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Hover and click delete button
|
|
188
|
-
const noteCard = noteTitle.locator("xpath=ancestor::div[contains(@class, 'border')]");
|
|
189
|
-
await noteCard.hover();
|
|
190
|
-
await page.waitForTimeout(200);
|
|
191
|
-
const deleteBtn = noteCard.locator("button[aria-label*='delete'], button:has(svg.lucide-trash)").first();
|
|
192
|
-
if (await deleteBtn.isVisible().catch(() => false)) {
|
|
193
|
-
await deleteBtn.click();
|
|
194
|
-
await page.waitForTimeout(2000);
|
|
195
|
-
// Note should be gone
|
|
196
|
-
await expect(noteTitle).not.toBeVisible({ timeout: 5000 });
|
|
197
|
-
} else {
|
|
198
|
-
test.skip();
|
|
199
|
-
}
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
test("7.9 返回看板链接可用", async ({ page }) => {
|
|
203
|
-
await goToWorkspace(page);
|
|
204
|
-
const sidebar = page.locator("aside");
|
|
205
|
-
await sidebar.locator("a").filter({ hasText: /笔记|Notes/ }).click();
|
|
206
|
-
await page.waitForURL(/\/notes/);
|
|
207
|
-
await page.waitForTimeout(500);
|
|
208
|
-
|
|
209
|
-
const backLink = page.locator("a").filter({ hasText: /返回看板|Back/ });
|
|
210
|
-
await expect(backLink).toBeVisible({ timeout: 3000 });
|
|
211
|
-
await backLink.click();
|
|
212
|
-
await page.waitForURL(/\/workspaces\/[^/]+$/);
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
// ─── Assets Page ───
|
|
216
|
-
|
|
217
|
-
test("7.10 点击资源链接进入资源页面", async ({ page }) => {
|
|
218
|
-
await goToWorkspace(page);
|
|
219
|
-
const sidebar = page.locator("aside");
|
|
220
|
-
const assetsLink = sidebar.locator("a").filter({ hasText: /资源|Assets/ });
|
|
221
|
-
await assetsLink.click();
|
|
222
|
-
await page.waitForURL(/\/assets/);
|
|
223
|
-
// Should see upload button
|
|
224
|
-
await expect(
|
|
225
|
-
page.locator("button").filter({ hasText: /上传|Upload/ })
|
|
226
|
-
).toBeVisible({ timeout: 5000 });
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
test("7.11 资源页面显示空状态或文件列表", async ({ page }) => {
|
|
230
|
-
await goToWorkspace(page);
|
|
231
|
-
const sidebar = page.locator("aside");
|
|
232
|
-
await sidebar.locator("a").filter({ hasText: /资源|Assets/ }).click();
|
|
233
|
-
await page.waitForURL(/\/assets/);
|
|
234
|
-
await page.waitForTimeout(1000);
|
|
235
|
-
|
|
236
|
-
// Either we see asset items or empty state text
|
|
237
|
-
const hasAssets = await page.locator("a[aria-label*='download']").count() > 0;
|
|
238
|
-
const hasEmpty = await page.getByText(/暂无|No assets|empty/).isVisible().catch(() => false);
|
|
239
|
-
expect(hasAssets || hasEmpty).toBe(true);
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
test("7.12 上传按钮存在且可点击", async ({ page }) => {
|
|
243
|
-
await goToWorkspace(page);
|
|
244
|
-
const sidebar = page.locator("aside");
|
|
245
|
-
await sidebar.locator("a").filter({ hasText: /资源|Assets/ }).click();
|
|
246
|
-
await page.waitForURL(/\/assets/);
|
|
247
|
-
await page.waitForTimeout(500);
|
|
248
|
-
|
|
249
|
-
const uploadBtn = page.locator("button").filter({ hasText: /上传|Upload/ });
|
|
250
|
-
await expect(uploadBtn).toBeVisible();
|
|
251
|
-
await expect(uploadBtn).toBeEnabled();
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
test("7.13 资源页面返回看板", async ({ page }) => {
|
|
255
|
-
await goToWorkspace(page);
|
|
256
|
-
const sidebar = page.locator("aside");
|
|
257
|
-
await sidebar.locator("a").filter({ hasText: /资源|Assets/ }).click();
|
|
258
|
-
await page.waitForURL(/\/assets/);
|
|
259
|
-
await page.waitForTimeout(500);
|
|
260
|
-
|
|
261
|
-
const backLink = page.locator("a").filter({ hasText: /返回看板|Back/ });
|
|
262
|
-
await expect(backLink).toBeVisible({ timeout: 3000 });
|
|
263
|
-
await backLink.click();
|
|
264
|
-
await page.waitForURL(/\/workspaces\/[^/]+$/);
|
|
265
|
-
});
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
// ─── File Serving Security ───
|
|
269
|
-
|
|
270
|
-
test.describe("Phase 6: File Serving Security", () => {
|
|
271
|
-
test("6.1 路径穿越攻击返回400", async ({ page }) => {
|
|
272
|
-
const response = await page.goto("/api/files/assets/../../etc/passwd");
|
|
273
|
-
expect(response?.status()).toBe(400);
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
test("6.2 不存在的文件返回404", async ({ page }) => {
|
|
277
|
-
const response = await page.goto("/api/files/assets/nonexistent-project/nonexistent-file.txt");
|
|
278
|
-
expect(response?.status()).toBe(404);
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
test("6.3 正常asset路径格式正确(即使文件不存在也返回404而非500)", async ({ page }) => {
|
|
282
|
-
const response = await page.goto("/api/files/assets/test-project-id/test.png");
|
|
283
|
-
// Should be 400 (invalid path) or 404 (not found), never 500
|
|
284
|
-
const status = response?.status();
|
|
285
|
-
expect(status === 400 || status === 404).toBe(true);
|
|
286
|
-
});
|
|
287
|
-
});
|