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.
Files changed (641) hide show
  1. package/bin/tower.mjs +5 -15
  2. package/next.config.ts +1 -8
  3. package/package.json +10 -11
  4. package/prisma/dev.db +0 -0
  5. package/public/vs/_commonjsHelpers-CT9FvmAN.js +1 -0
  6. package/public/vs/abap-D-t0cyap.js +1 -0
  7. package/public/vs/apex-CcIm7xu6.js +1 -0
  8. package/public/vs/assets/css.worker-HnVq6Ewq.js +93 -0
  9. package/public/vs/assets/editor.worker-Be8ye1pW.js +26 -0
  10. package/public/vs/assets/html.worker-B51mlPHg.js +470 -0
  11. package/public/vs/assets/json.worker-DKiEKt88.js +58 -0
  12. package/public/vs/assets/ts.worker-CMbG-7ft.js +67731 -0
  13. package/public/vs/azcli-BA0tQDCg.js +1 -0
  14. package/public/vs/basic-languages/monaco.contribution.js +1 -0
  15. package/public/vs/bat-C397hTD6.js +1 -0
  16. package/public/vs/bicep-DF5aW17k.js +2 -0
  17. package/public/vs/cameligo-plsz8qhj.js +1 -0
  18. package/public/vs/clojure-Y2auQMzK.js +1 -0
  19. package/public/vs/coffee-Bu45yuWE.js +1 -0
  20. package/public/vs/cpp-CkKPQIni.js +1 -0
  21. package/public/vs/csharp-CX28MZyh.js +1 -0
  22. package/public/vs/csp-D8uWnyxW.js +1 -0
  23. package/public/vs/css-CaeNmE3S.js +3 -0
  24. package/public/vs/cssMode-CjiAH6dQ.js +1 -0
  25. package/public/vs/cypher-DVThT8BS.js +1 -0
  26. package/public/vs/dart-CmGfCvrO.js +1 -0
  27. package/public/vs/dockerfile-CZqqYdch.js +1 -0
  28. package/public/vs/ecl-30fUercY.js +1 -0
  29. package/public/vs/editor/editor.main.css +1 -0
  30. package/public/vs/editor/editor.main.js +5 -0
  31. package/public/vs/editor.api-CalNCsUg.js +903 -0
  32. package/public/vs/elixir-xjPaIfzF.js +1 -0
  33. package/public/vs/flow9-DqtmStfK.js +1 -0
  34. package/public/vs/freemarker2-Cz_sV6Md.js +3 -0
  35. package/public/vs/fsharp-BOMdg4U1.js +1 -0
  36. package/public/vs/go-D_hbi-Jt.js +1 -0
  37. package/public/vs/graphql-CKUU4kLG.js +1 -0
  38. package/public/vs/handlebars-OwglfO-1.js +1 -0
  39. package/public/vs/hcl-DTaboeZW.js +1 -0
  40. package/public/vs/html-Pa1xEWsY.js +1 -0
  41. package/public/vs/htmlMode-Bz67EXwp.js +1 -0
  42. package/public/vs/ini-CsNwO04R.js +1 -0
  43. package/public/vs/java-CI4ZMsH9.js +1 -0
  44. package/public/vs/javascript-PczUCGdz.js +1 -0
  45. package/public/vs/jsonMode-DULH5oaX.js +7 -0
  46. package/public/vs/julia-BwzEvaQw.js +1 -0
  47. package/public/vs/kotlin-IUYPiTV8.js +1 -0
  48. package/public/vs/language/css/monaco.contribution.js +1 -0
  49. package/public/vs/language/html/monaco.contribution.js +1 -0
  50. package/public/vs/language/json/monaco.contribution.js +1 -0
  51. package/public/vs/language/typescript/monaco.contribution.js +1 -0
  52. package/public/vs/less-C0eDYdqa.js +2 -0
  53. package/public/vs/lexon-iON-Kj97.js +1 -0
  54. package/public/vs/liquid-DqKjdPGy.js +1 -0
  55. package/public/vs/loader.js +1368 -0
  56. package/public/vs/lspLanguageFeatures-kM9O9rjY.js +4 -0
  57. package/public/vs/lua-DtygF91M.js +1 -0
  58. package/public/vs/m3-CsR4AuFi.js +1 -0
  59. package/public/vs/markdown-C_rD0bIw.js +1 -0
  60. package/public/vs/mdx-DEWtB1K5.js +1 -0
  61. package/public/vs/mips-CiYP61RB.js +1 -0
  62. package/public/vs/monaco.contribution-D2OdxNBt.js +1 -0
  63. package/public/vs/monaco.contribution-DO3azKX8.js +1 -0
  64. package/public/vs/monaco.contribution-EcChJV6a.js +1 -0
  65. package/public/vs/monaco.contribution-qLAYrEOP.js +1 -0
  66. package/public/vs/msdax-C38-sJlp.js +1 -0
  67. package/public/vs/mysql-CdtbpvbG.js +1 -0
  68. package/public/vs/nls.messages-loader.js +1 -0
  69. package/public/vs/nls.messages.cs.js.js +17 -0
  70. package/public/vs/nls.messages.de.js.js +17 -0
  71. package/public/vs/nls.messages.es.js.js +17 -0
  72. package/public/vs/nls.messages.fr.js.js +15 -0
  73. package/public/vs/nls.messages.it.js.js +15 -0
  74. package/public/vs/nls.messages.ja.js.js +17 -0
  75. package/public/vs/nls.messages.js.js +10 -0
  76. package/public/vs/nls.messages.ko.js.js +25 -0
  77. package/public/vs/nls.messages.pl.js.js +17 -0
  78. package/public/vs/nls.messages.pt-br.js.js +6 -0
  79. package/public/vs/nls.messages.ru.js.js +17 -0
  80. package/public/vs/nls.messages.tr.js.js +15 -0
  81. package/public/vs/nls.messages.zh-cn.js.js +17 -0
  82. package/public/vs/nls.messages.zh-tw.js.js +15 -0
  83. package/public/vs/objective-c-CntZFaHX.js +1 -0
  84. package/public/vs/pascal-r6kuqfl_.js +1 -0
  85. package/public/vs/pascaligo-BiXoTmXh.js +1 -0
  86. package/public/vs/perl-DABw_TcH.js +1 -0
  87. package/public/vs/pgsql-me_jFXeX.js +1 -0
  88. package/public/vs/php-D_kh-9LK.js +1 -0
  89. package/public/vs/pla-VfZjczW0.js +1 -0
  90. package/public/vs/postiats-BBSzz8Pk.js +1 -0
  91. package/public/vs/powerquery-Dt-g_2cc.js +1 -0
  92. package/public/vs/powershell-B-7ap1zc.js +1 -0
  93. package/public/vs/protobuf-BmtuEB1A.js +2 -0
  94. package/public/vs/pug-BRpRNeEb.js +1 -0
  95. package/public/vs/python-Cr0UkIbn.js +1 -0
  96. package/public/vs/qsharp-BzsFaUU9.js +1 -0
  97. package/public/vs/r-f8dDdrp4.js +1 -0
  98. package/public/vs/razor-BYAHOTkz.js +1 -0
  99. package/public/vs/redis-fvZQY4PI.js +1 -0
  100. package/public/vs/redshift-45Et0LQi.js +1 -0
  101. package/public/vs/restructuredtext-C7UUFKFD.js +1 -0
  102. package/public/vs/ruby-CZO8zYTz.js +1 -0
  103. package/public/vs/rust-Bfetafyc.js +1 -0
  104. package/public/vs/sb-3GYllVck.js +1 -0
  105. package/public/vs/scala-foMgrKo1.js +1 -0
  106. package/public/vs/scheme-CHdMtr7p.js +1 -0
  107. package/public/vs/scss-C1cmLt9V.js +3 -0
  108. package/public/vs/shell-ClXCKCEW.js +1 -0
  109. package/public/vs/solidity-MZ6ExpPy.js +1 -0
  110. package/public/vs/sophia-DWkuSsPQ.js +1 -0
  111. package/public/vs/sparql-AUGFYSyk.js +1 -0
  112. package/public/vs/sql-32GpJSV2.js +1 -0
  113. package/public/vs/st-CuDFIVZ_.js +1 -0
  114. package/public/vs/swift-n-2HociN.js +3 -0
  115. package/public/vs/systemverilog-Ch4vA8Yt.js +1 -0
  116. package/public/vs/tcl-D74tq1nH.js +1 -0
  117. package/public/vs/tsMode-CZz1Umrk.js +11 -0
  118. package/public/vs/twig-C6taOxMV.js +1 -0
  119. package/public/vs/typescript-DfOrAzoV.js +1 -0
  120. package/public/vs/typespec-D-PIh9Xw.js +1 -0
  121. package/public/vs/vb-Dyb2648j.js +1 -0
  122. package/public/vs/wgsl-BhLXMOR0.js +298 -0
  123. package/public/vs/workers-DcJshg-q.js +1 -0
  124. package/public/vs/xml-CdsdnY8S.js +1 -0
  125. package/public/vs/yaml-DYGvmE88.js +1 -0
  126. package/src/actions/__tests__/agent-actions-username.test.ts +30 -0
  127. package/src/actions/__tests__/asset-actions.test.ts +251 -0
  128. package/src/actions/__tests__/assistant-actions.test.ts +20 -0
  129. package/src/actions/__tests__/cli-profile-actions.test.ts +243 -0
  130. package/src/actions/__tests__/label-actions.test.ts +187 -0
  131. package/src/actions/__tests__/note-actions.test.ts +237 -0
  132. package/src/actions/__tests__/onboarding-actions.test.ts +265 -0
  133. package/src/actions/__tests__/project-actions.test.ts +179 -0
  134. package/src/actions/__tests__/prompt-actions.test.ts +213 -0
  135. package/src/actions/__tests__/report-actions.test.ts +246 -0
  136. package/src/actions/__tests__/search-code-actions.test.ts +308 -0
  137. package/src/actions/__tests__/task-actions-overview.test.ts +58 -0
  138. package/src/actions/__tests__/task-actions-pin.test.ts +79 -0
  139. package/src/actions/__tests__/workspace-actions.test.ts +256 -0
  140. package/src/components/layout/__tests__/top-bar-username.test.tsx +24 -0
  141. package/src/components/onboarding/__tests__/onboarding-wizard.test.tsx +185 -0
  142. package/src/hooks/__tests__/sse-event-reducer.test.ts +263 -0
  143. package/src/hooks/__tests__/use-assistant-chat.test.ts +34 -0
  144. package/src/hooks/__tests__/use-image-upload.test.ts +443 -0
  145. package/src/lib/__tests__/assistant-message-converter.test.ts +162 -0
  146. package/src/lib/__tests__/assistant-sessions.test.ts +253 -0
  147. package/src/lib/__tests__/build-multimodal-prompt.test.ts +173 -0
  148. package/src/lib/__tests__/config-reader.test.ts +75 -0
  149. package/src/lib/__tests__/diff-parser.test.ts +212 -0
  150. package/src/lib/__tests__/execution-summary.test.ts +237 -0
  151. package/src/lib/__tests__/file-serve.test.ts +178 -0
  152. package/src/lib/__tests__/file-utils.test.ts +177 -0
  153. package/src/lib/__tests__/internal-api-guard.test.ts +151 -0
  154. package/src/lib/__tests__/logger.test.ts +181 -0
  155. package/src/lib/__tests__/platform.test.ts +566 -0
  156. package/src/lib/__tests__/reveal-route-security.test.ts +65 -0
  157. package/src/lib/__tests__/schemas.test.ts +377 -0
  158. package/src/lib/__tests__/terminal-link-provider.test.ts +160 -0
  159. package/src/lib/__tests__/upload-route-security.test.ts +120 -0
  160. package/src/lib/ai/__tests__/capability-resolver.test.ts +71 -0
  161. package/src/lib/ai/__tests__/claude-cli-adapter.test.ts +103 -0
  162. package/src/lib/ai/__tests__/provider-registry.test.ts +74 -0
  163. package/src/lib/pty/__tests__/ws-server-assistant.test.ts +7 -0
  164. package/.next/standalone/tower/.claude/rules/process-lifecycle.md +0 -31
  165. package/.next/standalone/tower/.claude/rules/security.md +0 -29
  166. package/.next/standalone/tower/.claude/rules/ui.md +0 -105
  167. package/.next/standalone/tower/AGENTS.md +0 -325
  168. package/.next/standalone/tower/CHANGELOG.md +0 -63
  169. package/.next/standalone/tower/CLAUDE.md +0 -33
  170. package/.next/standalone/tower/LICENSE +0 -21
  171. package/.next/standalone/tower/README.md +0 -214
  172. package/.next/standalone/tower/README.zh.md +0 -212
  173. package/.next/standalone/tower/bin/tower.mjs +0 -180
  174. package/.next/standalone/tower/docs/README.md +0 -51
  175. package/.next/standalone/tower/docs/ai/README.md +0 -91
  176. package/.next/standalone/tower/docs/ai/cli-abstraction-design.md +0 -398
  177. package/.next/standalone/tower/docs/ai/cli-abstraction-plan.md +0 -1345
  178. package/.next/standalone/tower/docs/assets-notes/README.md +0 -41
  179. package/.next/standalone/tower/docs/assistant/README.md +0 -48
  180. package/.next/standalone/tower/docs/board/README.md +0 -36
  181. package/.next/standalone/tower/docs/diagrams/tower-ai-architecture-en.html +0 -259
  182. package/.next/standalone/tower/docs/diagrams/tower-ai-architecture.html +0 -259
  183. package/.next/standalone/tower/docs/diagrams/tower-data-model-en.html +0 -344
  184. package/.next/standalone/tower/docs/diagrams/tower-data-model.html +0 -344
  185. package/.next/standalone/tower/docs/diagrams/tower-module-map-en.html +0 -176
  186. package/.next/standalone/tower/docs/diagrams/tower-module-map.html +0 -176
  187. package/.next/standalone/tower/docs/diagrams/tower-system-architecture-en.html +0 -336
  188. package/.next/standalone/tower/docs/diagrams/tower-system-architecture.html +0 -336
  189. package/.next/standalone/tower/docs/diagrams/tower-task-lifecycle-en.html +0 -251
  190. package/.next/standalone/tower/docs/diagrams/tower-task-lifecycle.html +0 -251
  191. package/.next/standalone/tower/docs/en/guide/architecture.md +0 -79
  192. package/.next/standalone/tower/docs/en/guide/diagrams.md +0 -24
  193. package/.next/standalone/tower/docs/en/guide/getting-started.md +0 -80
  194. package/.next/standalone/tower/docs/en/guide/introduction.md +0 -84
  195. package/.next/standalone/tower/docs/en/index.md +0 -36
  196. package/.next/standalone/tower/docs/en/modules/ai.md +0 -110
  197. package/.next/standalone/tower/docs/en/modules/assets-notes.md +0 -56
  198. package/.next/standalone/tower/docs/en/modules/assistant.md +0 -63
  199. package/.next/standalone/tower/docs/en/modules/board.md +0 -44
  200. package/.next/standalone/tower/docs/en/modules/git.md +0 -55
  201. package/.next/standalone/tower/docs/en/modules/i18n.md +0 -35
  202. package/.next/standalone/tower/docs/en/modules/mcp.md +0 -62
  203. package/.next/standalone/tower/docs/en/modules/missions.md +0 -47
  204. package/.next/standalone/tower/docs/en/modules/project.md +0 -57
  205. package/.next/standalone/tower/docs/en/modules/search.md +0 -49
  206. package/.next/standalone/tower/docs/en/modules/settings.md +0 -63
  207. package/.next/standalone/tower/docs/en/modules/task.md +0 -82
  208. package/.next/standalone/tower/docs/en/modules/terminal.md +0 -73
  209. package/.next/standalone/tower/docs/en/modules/workspace.md +0 -61
  210. package/.next/standalone/tower/docs/git/README.md +0 -42
  211. package/.next/standalone/tower/docs/guide/architecture.md +0 -29
  212. package/.next/standalone/tower/docs/guide/diagrams.md +0 -24
  213. package/.next/standalone/tower/docs/guide/getting-started.md +0 -80
  214. package/.next/standalone/tower/docs/guide/introduction.md +0 -84
  215. package/.next/standalone/tower/docs/i18n/README.md +0 -23
  216. package/.next/standalone/tower/docs/index.md +0 -36
  217. package/.next/standalone/tower/docs/mcp/README.md +0 -50
  218. package/.next/standalone/tower/docs/missions/README.md +0 -40
  219. package/.next/standalone/tower/docs/modules/ai.md +0 -104
  220. package/.next/standalone/tower/docs/modules/assets-notes.md +0 -68
  221. package/.next/standalone/tower/docs/modules/assistant.md +0 -74
  222. package/.next/standalone/tower/docs/modules/board.md +0 -56
  223. package/.next/standalone/tower/docs/modules/git.md +0 -61
  224. package/.next/standalone/tower/docs/modules/i18n.md +0 -38
  225. package/.next/standalone/tower/docs/modules/mcp.md +0 -68
  226. package/.next/standalone/tower/docs/modules/missions.md +0 -54
  227. package/.next/standalone/tower/docs/modules/project.md +0 -65
  228. package/.next/standalone/tower/docs/modules/search.md +0 -57
  229. package/.next/standalone/tower/docs/modules/settings.md +0 -72
  230. package/.next/standalone/tower/docs/modules/task.md +0 -82
  231. package/.next/standalone/tower/docs/modules/terminal.md +0 -70
  232. package/.next/standalone/tower/docs/modules/workspace.md +0 -68
  233. package/.next/standalone/tower/docs/package.json +0 -11
  234. package/.next/standalone/tower/docs/pnpm-lock.yaml +0 -1620
  235. package/.next/standalone/tower/docs/postcss.config.mjs +0 -2
  236. package/.next/standalone/tower/docs/project/README.md +0 -45
  237. package/.next/standalone/tower/docs/public/banner.png +0 -0
  238. package/.next/standalone/tower/docs/public/diagrams/tower-ai-architecture-en.html +0 -259
  239. package/.next/standalone/tower/docs/public/diagrams/tower-ai-architecture.html +0 -259
  240. package/.next/standalone/tower/docs/public/diagrams/tower-data-model-en.html +0 -344
  241. package/.next/standalone/tower/docs/public/diagrams/tower-data-model.html +0 -344
  242. package/.next/standalone/tower/docs/public/diagrams/tower-module-map-en.html +0 -176
  243. package/.next/standalone/tower/docs/public/diagrams/tower-module-map.html +0 -176
  244. package/.next/standalone/tower/docs/public/diagrams/tower-system-architecture-en.html +0 -336
  245. package/.next/standalone/tower/docs/public/diagrams/tower-system-architecture.html +0 -336
  246. package/.next/standalone/tower/docs/public/diagrams/tower-task-lifecycle-en.html +0 -251
  247. package/.next/standalone/tower/docs/public/diagrams/tower-task-lifecycle.html +0 -251
  248. package/.next/standalone/tower/docs/search/README.md +0 -37
  249. package/.next/standalone/tower/docs/settings/README.md +0 -43
  250. package/.next/standalone/tower/docs/task/README.md +0 -67
  251. package/.next/standalone/tower/docs/terminal/README.md +0 -58
  252. package/.next/standalone/tower/docs/workspace/README.md +0 -50
  253. package/.next/standalone/tower/docs/zh/guide/architecture.md +0 -29
  254. package/.next/standalone/tower/docs/zh/guide/diagrams.md +0 -24
  255. package/.next/standalone/tower/docs/zh/guide/getting-started.md +0 -80
  256. package/.next/standalone/tower/docs/zh/guide/introduction.md +0 -66
  257. package/.next/standalone/tower/docs/zh/index.md +0 -23
  258. package/.next/standalone/tower/docs/zh/modules/ai.md +0 -104
  259. package/.next/standalone/tower/docs/zh/modules/assets-notes.md +0 -68
  260. package/.next/standalone/tower/docs/zh/modules/assistant.md +0 -74
  261. package/.next/standalone/tower/docs/zh/modules/board.md +0 -56
  262. package/.next/standalone/tower/docs/zh/modules/git.md +0 -61
  263. package/.next/standalone/tower/docs/zh/modules/i18n.md +0 -38
  264. package/.next/standalone/tower/docs/zh/modules/mcp.md +0 -68
  265. package/.next/standalone/tower/docs/zh/modules/missions.md +0 -54
  266. package/.next/standalone/tower/docs/zh/modules/project.md +0 -65
  267. package/.next/standalone/tower/docs/zh/modules/search.md +0 -57
  268. package/.next/standalone/tower/docs/zh/modules/settings.md +0 -72
  269. package/.next/standalone/tower/docs/zh/modules/task.md +0 -82
  270. package/.next/standalone/tower/docs/zh/modules/terminal.md +0 -70
  271. package/.next/standalone/tower/docs/zh/modules/workspace.md +0 -68
  272. package/.next/standalone/tower/eslint.config.mjs +0 -18
  273. package/.next/standalone/tower/next.config.ts +0 -15
  274. package/.next/standalone/tower/package.json +0 -117
  275. package/.next/standalone/tower/playwright.config.ts +0 -28
  276. package/.next/standalone/tower/pnpm-lock.yaml +0 -10524
  277. package/.next/standalone/tower/pnpm-workspace.yaml +0 -6
  278. package/.next/standalone/tower/prisma/init-fts.ts +0 -23
  279. package/.next/standalone/tower/prisma/schema.prisma +0 -290
  280. package/.next/standalone/tower/prompts/backend-developer.md +0 -20
  281. package/.next/standalone/tower/prompts/code-reviewer.md +0 -19
  282. package/.next/standalone/tower/prompts/frontend-developer.md +0 -20
  283. package/.next/standalone/tower/prompts/product-manager.md +0 -16
  284. package/.next/standalone/tower/public/banner.jpg +0 -0
  285. package/.next/standalone/tower/public/logo.png +0 -0
  286. package/.next/standalone/tower/scripts/copy-monaco.js +0 -27
  287. package/.next/standalone/tower/scripts/init-db.ts +0 -74
  288. package/.next/standalone/tower/scripts/migrate-data.ts +0 -102
  289. package/.next/standalone/tower/server.js +0 -38
  290. package/.next/standalone/tower/src/app/favicon.ico +0 -0
  291. package/.next/standalone/tower/src/mcp/db.ts +0 -11
  292. package/.next/standalone/tower/src/mcp/index.ts +0 -15
  293. package/.next/standalone/tower/src/mcp/server.ts +0 -52
  294. package/.next/standalone/tower/src/mcp/tools/knowledge-tools.ts +0 -100
  295. package/.next/standalone/tower/src/mcp/tools/label-tools.ts +0 -70
  296. package/.next/standalone/tower/src/mcp/tools/note-asset-tools.ts +0 -271
  297. package/.next/standalone/tower/src/mcp/tools/project-tools.ts +0 -79
  298. package/.next/standalone/tower/src/mcp/tools/report-tools.ts +0 -214
  299. package/.next/standalone/tower/src/mcp/tools/search-tools.ts +0 -32
  300. package/.next/standalone/tower/src/mcp/tools/task-tools.ts +0 -250
  301. package/.next/standalone/tower/src/mcp/tools/terminal-tools.ts +0 -154
  302. package/.next/standalone/tower/src/mcp/tools/workspace-tools.ts +0 -73
  303. package/.next/standalone/tower/tests/e2e/chat-flow.spec.ts +0 -249
  304. package/.next/standalone/tower/tests/e2e/notes-assets.spec.ts +0 -287
  305. package/.next/standalone/tower/tests/e2e/search.spec.ts +0 -186
  306. package/.next/standalone/tower/tests/e2e/settings-flow.spec.ts +0 -250
  307. package/.next/standalone/tower/tests/e2e/settings.spec.ts +0 -261
  308. package/.next/standalone/tower/tests/e2e/smoke.spec.ts +0 -317
  309. package/.next/standalone/tower/tests/e2e/task-flow.spec.ts +0 -287
  310. package/.next/standalone/tower/tests/e2e/workbench.spec.ts +0 -307
  311. package/.next/standalone/tower/tests/setup.ts +0 -15
  312. package/.next/standalone/tower/tests/unit/actions/agent-actions.test.ts +0 -157
  313. package/.next/standalone/tower/tests/unit/actions/config-actions.test.ts +0 -170
  314. package/.next/standalone/tower/tests/unit/actions/file-actions.test.ts +0 -283
  315. package/.next/standalone/tower/tests/unit/actions/git-actions.test.ts +0 -34
  316. package/.next/standalone/tower/tests/unit/actions/preview-actions.test.ts +0 -177
  317. package/.next/standalone/tower/tests/unit/actions/search-actions.test.ts +0 -358
  318. package/.next/standalone/tower/tests/unit/actions/task-actions.test.ts +0 -173
  319. package/.next/standalone/tower/tests/unit/api/diff-route.test.ts +0 -9
  320. package/.next/standalone/tower/tests/unit/api/file-serving.test.ts +0 -88
  321. package/.next/standalone/tower/tests/unit/api/merge-route.test.ts +0 -9
  322. package/.next/standalone/tower/tests/unit/api/stream-persist-result.test.ts +0 -7
  323. package/.next/standalone/tower/tests/unit/api/stream-send-back.test.ts +0 -7
  324. package/.next/standalone/tower/tests/unit/components/asset-item.test.tsx +0 -105
  325. package/.next/standalone/tower/tests/unit/components/asset-list.test.tsx +0 -51
  326. package/.next/standalone/tower/tests/unit/components/assets/asset-upload.test.tsx +0 -70
  327. package/.next/standalone/tower/tests/unit/components/board-stats.test.tsx +0 -32
  328. package/.next/standalone/tower/tests/unit/components/category-filter.test.tsx +0 -58
  329. package/.next/standalone/tower/tests/unit/components/cli-adapter-tester.test.tsx +0 -160
  330. package/.next/standalone/tower/tests/unit/components/create-task-dialog.test.tsx +0 -162
  331. package/.next/standalone/tower/tests/unit/components/file-tree.test.tsx +0 -172
  332. package/.next/standalone/tower/tests/unit/components/note-card.test.tsx +0 -71
  333. package/.next/standalone/tower/tests/unit/components/note-editor.test.tsx +0 -39
  334. package/.next/standalone/tower/tests/unit/components/prompts-config.test.tsx +0 -200
  335. package/.next/standalone/tower/tests/unit/components/search-dialog.test.tsx +0 -223
  336. package/.next/standalone/tower/tests/unit/components/system-config.test.tsx +0 -32
  337. package/.next/standalone/tower/tests/unit/hooks/hook-registration.test.ts +0 -89
  338. package/.next/standalone/tower/tests/unit/hooks/stop-hook.test.ts +0 -108
  339. package/.next/standalone/tower/tests/unit/lib/asset-actions.test.ts +0 -257
  340. package/.next/standalone/tower/tests/unit/lib/file-utils.test.ts +0 -102
  341. package/.next/standalone/tower/tests/unit/lib/fs-security.test.ts +0 -34
  342. package/.next/standalone/tower/tests/unit/lib/fts.test.ts +0 -214
  343. package/.next/standalone/tower/tests/unit/lib/git-url.test.ts +0 -258
  344. package/.next/standalone/tower/tests/unit/lib/instrumentation.test.ts +0 -86
  345. package/.next/standalone/tower/tests/unit/lib/local-path-to-api-url.test.ts +0 -40
  346. package/.next/standalone/tower/tests/unit/lib/mime-magic.test.ts +0 -95
  347. package/.next/standalone/tower/tests/unit/lib/note-actions.test.ts +0 -296
  348. package/.next/standalone/tower/tests/unit/lib/preview-process-manager.test.ts +0 -107
  349. package/.next/standalone/tower/tests/unit/lib/process-manager.test.ts +0 -10
  350. package/.next/standalone/tower/tests/unit/lib/pty-session.test.ts +0 -171
  351. package/.next/standalone/tower/tests/unit/lib/search.test.ts +0 -289
  352. package/.next/standalone/tower/tests/unit/lib/session-store.test.ts +0 -111
  353. package/.next/standalone/tower/tests/unit/lib/utils.test.ts +0 -33
  354. package/.next/standalone/tower/tests/unit/lib/worktree.test.ts +0 -190
  355. package/.next/standalone/tower/tests/unit/mcp/identify-project.test.ts +0 -217
  356. package/.next/standalone/tower/tests/unit/mcp/manage-assets.test.ts +0 -199
  357. package/.next/standalone/tower/tests/unit/mcp/manage-notes.test.ts +0 -304
  358. package/.next/standalone/tower/tests/unit/mcp/search-tools.test.ts +0 -186
  359. package/.next/standalone/tower/tests/unit/missions-merge.test.ts +0 -43
  360. package/.next/standalone/tower/tower-studio-0.1.1.tgz +0 -0
  361. package/.next/standalone/tower/tsconfig.json +0 -34
  362. package/.next/standalone/tower/vitest.config.ts +0 -17
  363. package/.next/static/a6HR9cTK7s4aKfE5dWzjz/_buildManifest.js +0 -11
  364. package/.next/static/a6HR9cTK7s4aKfE5dWzjz/_clientMiddlewareManifest.js +0 -1
  365. package/.next/static/a6HR9cTK7s4aKfE5dWzjz/_ssgManifest.js +0 -1
  366. package/.next/static/chunks/00z-g3x93ngvn.js +0 -1
  367. package/.next/static/chunks/024pdsc27tjdd.js +0 -5
  368. package/.next/static/chunks/02dd83gbiv778.js +0 -1
  369. package/.next/static/chunks/03e.4ymu.j5wl.js +0 -1
  370. package/.next/static/chunks/03~yq9q893hmn.js +0 -1
  371. package/.next/static/chunks/05-b9qqm3av9~.js +0 -1
  372. package/.next/static/chunks/05~v02mkan5z..js +0 -1
  373. package/.next/static/chunks/0abtpeymj-58i.js +0 -1
  374. package/.next/static/chunks/0b6us7uq72u-d.js +0 -1
  375. package/.next/static/chunks/0drgc-oztq6o-.css +0 -1
  376. package/.next/static/chunks/0eaa2lmymh2fx.js +0 -1
  377. package/.next/static/chunks/0gb82g.6g90mn.js +0 -1
  378. package/.next/static/chunks/0gnm22yv~f54b.js +0 -1
  379. package/.next/static/chunks/0j9qriqni_r1..js +0 -2
  380. package/.next/static/chunks/0k.u8sxy~e469.js +0 -4
  381. package/.next/static/chunks/0lnhjf2a~jaco.js +0 -83
  382. package/.next/static/chunks/0lvd52mjiit6s.js +0 -1
  383. package/.next/static/chunks/0mq0uqbbbb1~2.js +0 -1
  384. package/.next/static/chunks/0neevhl_o1ozu.css +0 -2
  385. package/.next/static/chunks/0omj~p3uxkic-.js +0 -1
  386. package/.next/static/chunks/0t-gr6j-c65qb.js +0 -1
  387. package/.next/static/chunks/0t16ai99uv4j3.js +0 -1
  388. package/.next/static/chunks/0tcl81ybuob5i.js +0 -1
  389. package/.next/static/chunks/0uqimvsni_op~.js +0 -1
  390. package/.next/static/chunks/0wt3kws~_yr8z.js +0 -1
  391. package/.next/static/chunks/0xzdu87n_for1.js +0 -5
  392. package/.next/static/chunks/0y0tdl.rl6v1u.js +0 -1
  393. package/.next/static/chunks/0z2bzovqhl2f5.js +0 -1
  394. package/.next/static/chunks/0z4y0x1ifgy.e.js +0 -1
  395. package/.next/static/chunks/0z7bwntvfhxzi.js +0 -12
  396. package/.next/static/chunks/102ijqpvi0z-d.js +0 -1
  397. package/.next/static/chunks/10n23t.1hpb-1.js +0 -1
  398. package/.next/static/chunks/11_e3-j5gzbj4.js +0 -1
  399. package/.next/static/chunks/14.ims4y7osot.js +0 -1
  400. package/.next/static/chunks/14xzmrt5ly6gq.js +0 -31
  401. package/.next/static/chunks/151wr~6x8aclx.js +0 -1
  402. package/.next/static/chunks/169po6_~f3-d5.js +0 -1
  403. package/.next/static/chunks/16w-ap~msrwpj.js +0 -1
  404. package/.next/static/chunks/176n7f13ve~a9.js +0 -1
  405. package/.next/static/chunks/17oc2l.ekcs8b.css +0 -1
  406. package/.next/static/chunks/turbopack-0wjmrsi.z32s0.js +0 -1
  407. package/.next/static/media/4fa387ec64143e14-s.0q3udbd2bu5yp.woff2 +0 -0
  408. package/.next/static/media/7178b3e590c64307-s.11.cyxs5p-0z~.woff2 +0 -0
  409. package/.next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2 +0 -0
  410. package/.next/static/media/8a480f0b521d4e75-s.06d3mdzz5bre_.woff2 +0 -0
  411. package/.next/static/media/apple-icon.16aocl-s-v2qz.png +0 -0
  412. package/.next/static/media/bbc41e54d2fcbd21-s.0gw~uztddq1df.woff2 +0 -0
  413. package/.next/static/media/caa3a2e1cccd8315-s.p.16t1db8_9y2o~.woff2 +0 -0
  414. package/.next/static/media/favicon.0y2d6j9cou~8p.ico +0 -0
  415. package/.next/static/media/icon0.0a6mkq6meyird.svg +0 -1
  416. package/.next/static/media/icon1.04ux133882seb.png +0 -0
  417. /package/{.next/standalone/tower/components.json → components.json} +0 -0
  418. /package/{.next/standalone/tower/postcss.config.mjs → postcss.config.mjs} +0 -0
  419. /package/{.next/standalone/tower/prisma → prisma}/prisma/dev.db +0 -0
  420. /package/{.next/standalone/tower/prisma → prisma}/seed.ts +0 -0
  421. /package/{.next/standalone/tower/docs/public → public}/banner.jpg +0 -0
  422. /package/{.next/standalone/tower/docs/public → public}/logo.png +0 -0
  423. /package/{.next/standalone/tower/public → public}/web-app-manifest-192x192.png +0 -0
  424. /package/{.next/standalone/tower/public → public}/web-app-manifest-512x512.png +0 -0
  425. /package/{.next/standalone/tower/scripts → scripts}/init-tower.ts +0 -0
  426. /package/{.next/standalone/tower/scripts → scripts}/post-tool-hook.js +0 -0
  427. /package/{.next/standalone/tower/scripts → scripts}/session-start-hook.js +0 -0
  428. /package/{.next/standalone/tower/scripts → scripts}/stop-hook.js +0 -0
  429. /package/{.next/standalone/tower/skills → skills}/tower/SKILL.md +0 -0
  430. /package/{.next/standalone/tower/src → src}/actions/agent-actions.ts +0 -0
  431. /package/{.next/standalone/tower/src → src}/actions/agent-config-actions.ts +0 -0
  432. /package/{.next/standalone/tower/src → src}/actions/ai-config-actions.ts +0 -0
  433. /package/{.next/standalone/tower/src → src}/actions/asset-actions.ts +0 -0
  434. /package/{.next/standalone/tower/src → src}/actions/assistant-actions.ts +0 -0
  435. /package/{.next/standalone/tower/src → src}/actions/cli-profile-actions.ts +0 -0
  436. /package/{.next/standalone/tower/src → src}/actions/config-actions.ts +0 -0
  437. /package/{.next/standalone/tower/src → src}/actions/file-actions.ts +0 -0
  438. /package/{.next/standalone/tower/src → src}/actions/git-actions.ts +0 -0
  439. /package/{.next/standalone/tower/src → src}/actions/label-actions.ts +0 -0
  440. /package/{.next/standalone/tower/src → src}/actions/note-actions.ts +0 -0
  441. /package/{.next/standalone/tower/src → src}/actions/onboarding-actions.ts +0 -0
  442. /package/{.next/standalone/tower/src → src}/actions/preview-actions.ts +0 -0
  443. /package/{.next/standalone/tower/src → src}/actions/project-actions.ts +0 -0
  444. /package/{.next/standalone/tower/src → src}/actions/prompt-actions.ts +0 -0
  445. /package/{.next/standalone/tower/src → src}/actions/report-actions.ts +0 -0
  446. /package/{.next/standalone/tower/src → src}/actions/search-actions.ts +0 -0
  447. /package/{.next/standalone/tower/src → src}/actions/search-code-actions.ts +0 -0
  448. /package/{.next/standalone/tower/src → src}/actions/task-actions.ts +0 -0
  449. /package/{.next/standalone/tower/src → src}/actions/workspace-actions.ts +0 -0
  450. /package/{.next/standalone/tower/src → src}/app/api/adapters/test/route.ts +0 -0
  451. /package/{.next/standalone/tower/src → src}/app/api/browse-fs/route.ts +0 -0
  452. /package/{.next/standalone/tower/src → src}/app/api/files/assets/[projectId]/[filename]/route.ts +0 -0
  453. /package/{.next/standalone/tower/src → src}/app/api/git/route.ts +0 -0
  454. /package/{.next/standalone/tower/src → src}/app/api/internal/assets/[projectId]/[filename]/route.ts +0 -0
  455. /package/{.next/standalone/tower/src → src}/app/api/internal/assets/reveal/route.ts +0 -0
  456. /package/{.next/standalone/tower/src → src}/app/api/internal/assistant/chat/route.ts +0 -0
  457. /package/{.next/standalone/tower/src → src}/app/api/internal/assistant/images/route.ts +0 -0
  458. /package/{.next/standalone/tower/src → src}/app/api/internal/assistant/route.ts +0 -0
  459. /package/{.next/standalone/tower/src → src}/app/api/internal/assistant/sessions/route.ts +0 -0
  460. /package/{.next/standalone/tower/src → src}/app/api/internal/cache/[...segments]/route.ts +0 -0
  461. /package/{.next/standalone/tower/src → src}/app/api/internal/hooks/install/route.ts +0 -0
  462. /package/{.next/standalone/tower/src → src}/app/api/internal/hooks/session/route.ts +0 -0
  463. /package/{.next/standalone/tower/src → src}/app/api/internal/hooks/stop/route.ts +0 -0
  464. /package/{.next/standalone/tower/src → src}/app/api/internal/hooks/upload/route.ts +0 -0
  465. /package/{.next/standalone/tower/src → src}/app/api/internal/notifications/pending/route.ts +0 -0
  466. /package/{.next/standalone/tower/src → src}/app/api/internal/terminal/[taskId]/buffer/route.ts +0 -0
  467. /package/{.next/standalone/tower/src → src}/app/api/internal/terminal/[taskId]/input/route.ts +0 -0
  468. /package/{.next/standalone/tower/src → src}/app/api/internal/terminal/[taskId]/start/route.ts +0 -0
  469. /package/{.next/standalone/tower/src → src}/app/api/tasks/[taskId]/diff/route.ts +0 -0
  470. /package/{.next/standalone/tower/src → src}/app/api/tasks/[taskId]/merge/route.ts +0 -0
  471. /package/{.next/standalone/tower/src → src}/app/apple-icon.png +0 -0
  472. /package/{.next/standalone/tower/docs/public → src/app}/favicon.ico +0 -0
  473. /package/{.next/standalone/tower/src → src}/app/globals.css +0 -0
  474. /package/{.next/standalone/tower/src → src}/app/icon0.svg +0 -0
  475. /package/{.next/standalone/tower/src → src}/app/icon1.png +0 -0
  476. /package/{.next/standalone/tower/src → src}/app/layout.tsx +0 -0
  477. /package/{.next/standalone/tower/src → src}/app/manifest.json +0 -0
  478. /package/{.next/standalone/tower/src → src}/app/missions/missions-client.tsx +0 -0
  479. /package/{.next/standalone/tower/src → src}/app/missions/page.tsx +0 -0
  480. /package/{.next/standalone/tower/src → src}/app/onboarding/page.tsx +0 -0
  481. /package/{.next/standalone/tower/src → src}/app/page.tsx +0 -0
  482. /package/{.next/standalone/tower/src → src}/app/settings/page.tsx +0 -0
  483. /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/archive/archive-page-client.tsx +0 -0
  484. /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/archive/page.tsx +0 -0
  485. /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/assets/assets-page-client.tsx +0 -0
  486. /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/assets/page.tsx +0 -0
  487. /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/board-page-client.tsx +0 -0
  488. /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/notes/notes-page-client.tsx +0 -0
  489. /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/notes/page.tsx +0 -0
  490. /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/page.tsx +0 -0
  491. /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/projects/[projectId]/page.tsx +0 -0
  492. /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/tasks/[taskId]/page.tsx +0 -0
  493. /package/{.next/standalone/tower/src → src}/app/workspaces/[workspaceId]/tasks/[taskId]/task-page-client.tsx +0 -0
  494. /package/{.next/standalone/tower/src → src}/app/workspaces/page.tsx +0 -0
  495. /package/{.next/standalone/tower/src → src}/components/assets/asset-item.tsx +0 -0
  496. /package/{.next/standalone/tower/src → src}/components/assets/asset-list.tsx +0 -0
  497. /package/{.next/standalone/tower/src → src}/components/assets/asset-upload.tsx +0 -0
  498. /package/{.next/standalone/tower/src → src}/components/assets/image-lightbox.tsx +0 -0
  499. /package/{.next/standalone/tower/src → src}/components/assets/text-preview-dialog.tsx +0 -0
  500. /package/{.next/standalone/tower/src → src}/components/assistant/assistant-chat-bubble.tsx +0 -0
  501. /package/{.next/standalone/tower/src → src}/components/assistant/assistant-chat.tsx +0 -0
  502. /package/{.next/standalone/tower/src → src}/components/assistant/assistant-panel.tsx +0 -0
  503. /package/{.next/standalone/tower/src → src}/components/assistant/assistant-provider.tsx +0 -0
  504. /package/{.next/standalone/tower/src → src}/components/assistant/image-preview-modal.tsx +0 -0
  505. /package/{.next/standalone/tower/src → src}/components/assistant/image-thumbnail-strip.tsx +0 -0
  506. /package/{.next/standalone/tower/src → src}/components/board/board-column.tsx +0 -0
  507. /package/{.next/standalone/tower/src → src}/components/board/board-filters.tsx +0 -0
  508. /package/{.next/standalone/tower/src → src}/components/board/board-stats.tsx +0 -0
  509. /package/{.next/standalone/tower/src → src}/components/board/column-tasks-dialog.tsx +0 -0
  510. /package/{.next/standalone/tower/src → src}/components/board/create-task-dialog.tsx +0 -0
  511. /package/{.next/standalone/tower/src → src}/components/board/kanban-board.tsx +0 -0
  512. /package/{.next/standalone/tower/src → src}/components/board/project-tabs.tsx +0 -0
  513. /package/{.next/standalone/tower/src → src}/components/board/task-card-context-menu.tsx +0 -0
  514. /package/{.next/standalone/tower/src → src}/components/board/task-card.tsx +0 -0
  515. /package/{.next/standalone/tower/src → src}/components/layout/app-sidebar.tsx +0 -0
  516. /package/{.next/standalone/tower/src → src}/components/layout/folder-browser-dialog.tsx +0 -0
  517. /package/{.next/standalone/tower/src → src}/components/layout/layout-client.tsx +0 -0
  518. /package/{.next/standalone/tower/src → src}/components/layout/search-dialog.tsx +0 -0
  519. /package/{.next/standalone/tower/src → src}/components/layout/sub-page-nav.tsx +0 -0
  520. /package/{.next/standalone/tower/src → src}/components/layout/top-bar.tsx +0 -0
  521. /package/{.next/standalone/tower/src → src}/components/missions/grid-layout-presets.ts +0 -0
  522. /package/{.next/standalone/tower/src → src}/components/missions/grid-preset-picker.tsx +0 -0
  523. /package/{.next/standalone/tower/src → src}/components/missions/merge-missions.ts +0 -0
  524. /package/{.next/standalone/tower/src → src}/components/missions/mission-card.tsx +0 -0
  525. /package/{.next/standalone/tower/src → src}/components/missions/task-picker-dialog.tsx +0 -0
  526. /package/{.next/standalone/tower/src → src}/components/notes/category-filter.tsx +0 -0
  527. /package/{.next/standalone/tower/src → src}/components/notes/note-card.tsx +0 -0
  528. /package/{.next/standalone/tower/src → src}/components/notes/note-editor.tsx +0 -0
  529. /package/{.next/standalone/tower/src → src}/components/notes/note-list.tsx +0 -0
  530. /package/{.next/standalone/tower/src → src}/components/notifications/notification-permission-banner.tsx +0 -0
  531. /package/{.next/standalone/tower/src → src}/components/notifications/use-notification-listener.ts +0 -0
  532. /package/{.next/standalone/tower/src → src}/components/onboarding/guided-tour.tsx +0 -0
  533. /package/{.next/standalone/tower/src → src}/components/onboarding/onboarding-wizard.tsx +0 -0
  534. /package/{.next/standalone/tower/src → src}/components/onboarding/wizard-step-cli.tsx +0 -0
  535. /package/{.next/standalone/tower/src → src}/components/onboarding/wizard-step-username.tsx +0 -0
  536. /package/{.next/standalone/tower/src → src}/components/project/create-project-dialog.tsx +0 -0
  537. /package/{.next/standalone/tower/src → src}/components/project/import-project-dialog.tsx +0 -0
  538. /package/{.next/standalone/tower/src → src}/components/providers/theme-provider.tsx +0 -0
  539. /package/{.next/standalone/tower/src → src}/components/repository/create-branch-dialog.tsx +0 -0
  540. /package/{.next/standalone/tower/src → src}/components/repository/git-changes-panel.tsx +0 -0
  541. /package/{.next/standalone/tower/src → src}/components/repository/git-log-panel.tsx +0 -0
  542. /package/{.next/standalone/tower/src → src}/components/repository/git-stash-panel.tsx +0 -0
  543. /package/{.next/standalone/tower/src → src}/components/repository/repo-sidebar.tsx +0 -0
  544. /package/{.next/standalone/tower/src → src}/components/settings/cli-adapter-tester.tsx +0 -0
  545. /package/{.next/standalone/tower/src → src}/components/settings/settings-page.tsx +0 -0
  546. /package/{.next/standalone/tower/src → src}/components/task/code-editor.tsx +0 -0
  547. /package/{.next/standalone/tower/src → src}/components/task/code-search.tsx +0 -0
  548. /package/{.next/standalone/tower/src → src}/components/task/diff-editor.tsx +0 -0
  549. /package/{.next/standalone/tower/src → src}/components/task/editor-git-panel.tsx +0 -0
  550. /package/{.next/standalone/tower/src → src}/components/task/editor-tabs.tsx +0 -0
  551. /package/{.next/standalone/tower/src → src}/components/task/execution-timeline.tsx +0 -0
  552. /package/{.next/standalone/tower/src → src}/components/task/file-tree-context-menu.tsx +0 -0
  553. /package/{.next/standalone/tower/src → src}/components/task/file-tree-node.tsx +0 -0
  554. /package/{.next/standalone/tower/src → src}/components/task/file-tree.tsx +0 -0
  555. /package/{.next/standalone/tower/src → src}/components/task/preview-panel.tsx +0 -0
  556. /package/{.next/standalone/tower/src → src}/components/task/task-detail-panel.tsx +0 -0
  557. /package/{.next/standalone/tower/src → src}/components/task/task-diff-view.tsx +0 -0
  558. /package/{.next/standalone/tower/src → src}/components/task/task-file-changes.tsx +0 -0
  559. /package/{.next/standalone/tower/src → src}/components/task/task-merge-confirm-dialog.tsx +0 -0
  560. /package/{.next/standalone/tower/src → src}/components/task/task-metadata.tsx +0 -0
  561. /package/{.next/standalone/tower/src → src}/components/task/task-notes-panel.tsx +0 -0
  562. /package/{.next/standalone/tower/src → src}/components/task/task-overview-drawer.tsx +0 -0
  563. /package/{.next/standalone/tower/src → src}/components/task/task-terminal.tsx +0 -0
  564. /package/{.next/standalone/tower/src → src}/components/task/terminal-portal.tsx +0 -0
  565. /package/{.next/standalone/tower/src → src}/components/task/types.ts +0 -0
  566. /package/{.next/standalone/tower/src → src}/components/ui/avatar.tsx +0 -0
  567. /package/{.next/standalone/tower/src → src}/components/ui/badge.tsx +0 -0
  568. /package/{.next/standalone/tower/src → src}/components/ui/button.tsx +0 -0
  569. /package/{.next/standalone/tower/src → src}/components/ui/card.tsx +0 -0
  570. /package/{.next/standalone/tower/src → src}/components/ui/command.tsx +0 -0
  571. /package/{.next/standalone/tower/src → src}/components/ui/dialog.tsx +0 -0
  572. /package/{.next/standalone/tower/src → src}/components/ui/dropdown-menu.tsx +0 -0
  573. /package/{.next/standalone/tower/src → src}/components/ui/empty-state.tsx +0 -0
  574. /package/{.next/standalone/tower/src → src}/components/ui/error-boundary.tsx +0 -0
  575. /package/{.next/standalone/tower/src → src}/components/ui/input-group.tsx +0 -0
  576. /package/{.next/standalone/tower/src → src}/components/ui/input.tsx +0 -0
  577. /package/{.next/standalone/tower/src → src}/components/ui/label.tsx +0 -0
  578. /package/{.next/standalone/tower/src → src}/components/ui/popover.tsx +0 -0
  579. /package/{.next/standalone/tower/src → src}/components/ui/scroll-area.tsx +0 -0
  580. /package/{.next/standalone/tower/src → src}/components/ui/segmented-control.tsx +0 -0
  581. /package/{.next/standalone/tower/src → src}/components/ui/select.tsx +0 -0
  582. /package/{.next/standalone/tower/src → src}/components/ui/separator.tsx +0 -0
  583. /package/{.next/standalone/tower/src → src}/components/ui/sheet.tsx +0 -0
  584. /package/{.next/standalone/tower/src → src}/components/ui/sonner.tsx +0 -0
  585. /package/{.next/standalone/tower/src → src}/components/ui/switch.tsx +0 -0
  586. /package/{.next/standalone/tower/src → src}/components/ui/tabs.tsx +0 -0
  587. /package/{.next/standalone/tower/src → src}/components/ui/textarea.tsx +0 -0
  588. /package/{.next/standalone/tower/src → src}/components/ui/toast.tsx +0 -0
  589. /package/{.next/standalone/tower/src → src}/components/ui/tooltip.tsx +0 -0
  590. /package/{.next/standalone/tower/src → src}/hooks/sse-event-reducer.ts +0 -0
  591. /package/{.next/standalone/tower/src → src}/hooks/use-assistant-chat.ts +0 -0
  592. /package/{.next/standalone/tower/src → src}/hooks/use-image-upload.ts +0 -0
  593. /package/{.next/standalone/tower/src → src}/instrumentation.ts +0 -0
  594. /package/{.next/standalone/tower/src → src}/lib/ai/adapters/cli/claude-cli-adapter.ts +0 -0
  595. /package/{.next/standalone/tower/src → src}/lib/ai/capability-resolver.ts +0 -0
  596. /package/{.next/standalone/tower/src → src}/lib/ai/provider-registry.ts +0 -0
  597. /package/{.next/standalone/tower/src → src}/lib/ai/providers/claude.ts +0 -0
  598. /package/{.next/standalone/tower/src → src}/lib/ai/providers/index.ts +0 -0
  599. /package/{.next/standalone/tower/src → src}/lib/ai/types.ts +0 -0
  600. /package/{.next/standalone/tower/src → src}/lib/assistant-constants.ts +0 -0
  601. /package/{.next/standalone/tower/src → src}/lib/assistant-message-converter.ts +0 -0
  602. /package/{.next/standalone/tower/src → src}/lib/assistant-sessions.ts +0 -0
  603. /package/{.next/standalone/tower/src → src}/lib/build-multimodal-prompt.ts +0 -0
  604. /package/{.next/standalone/tower/src → src}/lib/claude-session.ts +0 -0
  605. /package/{.next/standalone/tower/src → src}/lib/cli-test.ts +0 -0
  606. /package/{.next/standalone/tower/src → src}/lib/config-defaults.ts +0 -0
  607. /package/{.next/standalone/tower/src → src}/lib/config-reader.ts +0 -0
  608. /package/{.next/standalone/tower/src → src}/lib/constants.ts +0 -0
  609. /package/{.next/standalone/tower/src → src}/lib/db.ts +0 -0
  610. /package/{.next/standalone/tower/src → src}/lib/diff-parser.ts +0 -0
  611. /package/{.next/standalone/tower/src → src}/lib/execution-summary.ts +0 -0
  612. /package/{.next/standalone/tower/src → src}/lib/file-serve-client.ts +0 -0
  613. /package/{.next/standalone/tower/src → src}/lib/file-serve.ts +0 -0
  614. /package/{.next/standalone/tower/src → src}/lib/file-utils.ts +0 -0
  615. /package/{.next/standalone/tower/src → src}/lib/fs-security.ts +0 -0
  616. /package/{.next/standalone/tower/src → src}/lib/fts.ts +0 -0
  617. /package/{.next/standalone/tower/src → src}/lib/git-api.ts +0 -0
  618. /package/{.next/standalone/tower/src → src}/lib/git-url.ts +0 -0
  619. /package/{.next/standalone/tower/src → src}/lib/i18n/en.ts +0 -0
  620. /package/{.next/standalone/tower/src → src}/lib/i18n/types.ts +0 -0
  621. /package/{.next/standalone/tower/src → src}/lib/i18n/zh.ts +0 -0
  622. /package/{.next/standalone/tower/src → src}/lib/i18n.tsx +0 -0
  623. /package/{.next/standalone/tower/src → src}/lib/init-tower.ts +0 -0
  624. /package/{.next/standalone/tower/src → src}/lib/instrumentation-tasks.ts +0 -0
  625. /package/{.next/standalone/tower/src → src}/lib/internal-api-guard.ts +0 -0
  626. /package/{.next/standalone/tower/src → src}/lib/logger.ts +0 -0
  627. /package/{.next/standalone/tower/src → src}/lib/mime-magic.ts +0 -0
  628. /package/{.next/standalone/tower/src → src}/lib/platform.ts +0 -0
  629. /package/{.next/standalone/tower/src → src}/lib/preview-process.ts +0 -0
  630. /package/{.next/standalone/tower/src → src}/lib/pty/pty-session.ts +0 -0
  631. /package/{.next/standalone/tower/src → src}/lib/pty/session-store.ts +0 -0
  632. /package/{.next/standalone/tower/src → src}/lib/pty/ws-server.ts +0 -0
  633. /package/{.next/standalone/tower/src → src}/lib/schemas.ts +0 -0
  634. /package/{.next/standalone/tower/src → src}/lib/search.ts +0 -0
  635. /package/{.next/standalone/tower/src → src}/lib/terminal-link-provider.ts +0 -0
  636. /package/{.next/standalone/tower/src → src}/lib/tower-dir.ts +0 -0
  637. /package/{.next/standalone/tower/src → src}/lib/utils.ts +0 -0
  638. /package/{.next/standalone/tower/src → src}/lib/worktree.ts +0 -0
  639. /package/{.next/standalone/tower/src → src}/stores/board-store.ts +0 -0
  640. /package/{.next/standalone/tower/src → src}/stores/task-execution-store.ts +0 -0
  641. /package/{.next/standalone/tower/src → src}/types/index.ts +0 -0
@@ -0,0 +1,212 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { parseDiffOutput } from "../diff-parser";
3
+
4
+ // ── Helpers ──
5
+
6
+ function makeNumstatLine(added: number | string, removed: number | string, filename: string) {
7
+ return `${added}\t${removed}\t${filename}`;
8
+ }
9
+
10
+ function makeUnifiedHeader(filename: string) {
11
+ return `diff --git a/${filename} b/${filename}\nindex abc1234..def5678 100644\n--- a/${filename}\n+++ b/${filename}`;
12
+ }
13
+
14
+ function makeHunk(contextLine: string, addedLine: string, removedLine: string) {
15
+ return `@@ -1,3 +1,3 @@\n ${contextLine}\n+${addedLine}\n-${removedLine}`;
16
+ }
17
+
18
+ // ── Tests ──
19
+
20
+ describe("parseDiffOutput — empty inputs", () => {
21
+ it("returns empty result for empty numstat and unified diff", () => {
22
+ const result = parseDiffOutput("", "");
23
+ expect(result.files).toEqual([]);
24
+ expect(result.totalAdded).toBe(0);
25
+ expect(result.totalRemoved).toBe(0);
26
+ });
27
+
28
+ it("returns empty result for whitespace-only inputs", () => {
29
+ const result = parseDiffOutput(" \n\t ", " \n ");
30
+ expect(result.files).toEqual([]);
31
+ expect(result.totalAdded).toBe(0);
32
+ expect(result.totalRemoved).toBe(0);
33
+ });
34
+ });
35
+
36
+ describe("parseDiffOutput — standard diff (adds and removes)", () => {
37
+ it("parses single file with adds and removes", () => {
38
+ const numstat = makeNumstatLine(10, 5, "src/app.ts");
39
+ const unified =
40
+ makeUnifiedHeader("src/app.ts") +
41
+ "\n" +
42
+ makeHunk("existing line", "new feature line", "old line") +
43
+ "\n";
44
+
45
+ const result = parseDiffOutput(numstat, unified);
46
+
47
+ expect(result.files).toHaveLength(1);
48
+ expect(result.files[0].filename).toBe("src/app.ts");
49
+ expect(result.files[0].added).toBe(10);
50
+ expect(result.files[0].removed).toBe(5);
51
+ expect(result.files[0].isBinary).toBe(false);
52
+ expect(result.files[0].patch).toContain("diff --git a/src/app.ts b/src/app.ts");
53
+ expect(result.totalAdded).toBe(10);
54
+ expect(result.totalRemoved).toBe(5);
55
+ });
56
+
57
+ it("parses multiple files and sums totals correctly", () => {
58
+ const numstat = [
59
+ makeNumstatLine(3, 1, "src/a.ts"),
60
+ makeNumstatLine(7, 2, "src/b.ts"),
61
+ ].join("\n");
62
+
63
+ const unified =
64
+ makeUnifiedHeader("src/a.ts") + "\n" + makeHunk("ctx", "add a", "rm a") + "\n" +
65
+ makeUnifiedHeader("src/b.ts") + "\n" + makeHunk("ctx", "add b", "rm b") + "\n";
66
+
67
+ const result = parseDiffOutput(numstat, unified);
68
+
69
+ expect(result.files).toHaveLength(2);
70
+ expect(result.totalAdded).toBe(10); // 3 + 7
71
+ expect(result.totalRemoved).toBe(3); // 1 + 2
72
+ });
73
+ });
74
+
75
+ describe("parseDiffOutput — added-only hunk", () => {
76
+ it("returns totalRemoved=0 when only lines added", () => {
77
+ const numstat = makeNumstatLine(5, 0, "src/new-file.ts");
78
+ const unified =
79
+ `diff --git a/src/new-file.ts b/src/new-file.ts\nnew file mode 100644\n--- /dev/null\n+++ b/src/new-file.ts\n` +
80
+ `@@ -0,0 +1,5 @@\n+line 1\n+line 2\n+line 3\n+line 4\n+line 5\n`;
81
+
82
+ const result = parseDiffOutput(numstat, unified);
83
+
84
+ expect(result.files).toHaveLength(1);
85
+ expect(result.files[0].added).toBe(5);
86
+ expect(result.files[0].removed).toBe(0);
87
+ expect(result.totalAdded).toBe(5);
88
+ expect(result.totalRemoved).toBe(0);
89
+ });
90
+ });
91
+
92
+ describe("parseDiffOutput — removed-only hunk", () => {
93
+ it("returns totalAdded=0 when only lines removed", () => {
94
+ const numstat = makeNumstatLine(0, 8, "src/old-file.ts");
95
+ const unified =
96
+ makeUnifiedHeader("src/old-file.ts") +
97
+ "\n@@ -1,8 +0,0 @@\n-line 1\n-line 2\n-line 3\n-line 4\n-line 5\n-line 6\n-line 7\n-line 8\n";
98
+
99
+ const result = parseDiffOutput(numstat, unified);
100
+
101
+ expect(result.files).toHaveLength(1);
102
+ expect(result.files[0].added).toBe(0);
103
+ expect(result.files[0].removed).toBe(8);
104
+ expect(result.totalAdded).toBe(0);
105
+ expect(result.totalRemoved).toBe(8);
106
+ });
107
+ });
108
+
109
+ describe("parseDiffOutput — binary files", () => {
110
+ it("marks binary file with isBinary=true and added=removed=0", () => {
111
+ const numstat = makeNumstatLine("-", "-", "assets/logo.png");
112
+ // Binary files typically don't produce unified diff output
113
+ const unified = "";
114
+
115
+ const result = parseDiffOutput(numstat, unified);
116
+
117
+ expect(result.files).toHaveLength(1);
118
+ expect(result.files[0].filename).toBe("assets/logo.png");
119
+ expect(result.files[0].isBinary).toBe(true);
120
+ expect(result.files[0].added).toBe(0);
121
+ expect(result.files[0].removed).toBe(0);
122
+ });
123
+
124
+ it("does not include binary file in totalAdded/totalRemoved", () => {
125
+ const numstat = [
126
+ makeNumstatLine("-", "-", "assets/logo.png"),
127
+ makeNumstatLine(3, 1, "src/code.ts"),
128
+ ].join("\n");
129
+ const unified = makeUnifiedHeader("src/code.ts") + "\n" + makeHunk("ctx", "add", "rm") + "\n";
130
+
131
+ const result = parseDiffOutput(numstat, unified);
132
+
133
+ expect(result.totalAdded).toBe(3);
134
+ expect(result.totalRemoved).toBe(1);
135
+ });
136
+ });
137
+
138
+ describe("parseDiffOutput — numstat with no matching unified diff segment", () => {
139
+ it("returns empty patch string when file not in unified diff", () => {
140
+ const numstat = makeNumstatLine(5, 2, "src/missing.ts");
141
+ const unified = ""; // No unified diff content
142
+
143
+ const result = parseDiffOutput(numstat, unified);
144
+
145
+ expect(result.files).toHaveLength(1);
146
+ expect(result.files[0].patch).toBe("");
147
+ expect(result.files[0].added).toBe(5);
148
+ expect(result.files[0].removed).toBe(2);
149
+ });
150
+ });
151
+
152
+ describe("parseDiffOutput — truncation at >500KB", () => {
153
+ it("truncates patch to 200 lines and appends truncation marker", () => {
154
+ const filename = "src/large-file.ts";
155
+ const numstat = makeNumstatLine(500, 0, filename);
156
+
157
+ // Build a unified diff larger than 500KB
158
+ const headerLines = makeUnifiedHeader(filename);
159
+ const hunkLines = Array.from({ length: 500 }, (_, i) => `+added line ${i}`).join("\n");
160
+ const diffContent = `${headerLines}\n@@ -0,0 +1,500 @@\n${hunkLines}\n`;
161
+
162
+ // Pad to exceed 500KB
163
+ const padding = "// padding\n".repeat(Math.ceil((500 * 1024) / 11));
164
+ const paddedDiff = `${diffContent}${makeUnifiedHeader("src/pad.ts")}\n${padding}`;
165
+
166
+ const paddedNumstat = `${numstat}\n${makeNumstatLine(0, 0, "src/pad.ts")}`;
167
+
168
+ const result = parseDiffOutput(paddedNumstat, paddedDiff);
169
+
170
+ // Large file's patch should be truncated
171
+ const largePatch = result.files.find((f) => f.filename === filename);
172
+ expect(largePatch).toBeDefined();
173
+ const patchLines = largePatch!.patch.split("\n");
174
+ // After truncation: at most 200 lines content + 1 truncation line
175
+ expect(patchLines.length).toBeLessThanOrEqual(201);
176
+ expect(largePatch!.patch).toContain("... (truncated)");
177
+ });
178
+
179
+ it("does NOT truncate patches when total diff is under 500KB", () => {
180
+ const filename = "src/small-file.ts";
181
+ const numstat = makeNumstatLine(3, 1, filename);
182
+ const unified =
183
+ makeUnifiedHeader(filename) +
184
+ "\n" +
185
+ makeHunk("ctx", "add line", "remove line") +
186
+ "\n";
187
+
188
+ const result = parseDiffOutput(numstat, unified);
189
+
190
+ expect(result.files[0].patch).not.toContain("... (truncated)");
191
+ });
192
+ });
193
+
194
+ describe("parseDiffOutput — malformed numstat lines", () => {
195
+ it("skips lines with fewer than 3 tab-separated parts", () => {
196
+ const numstat = "bad line\n5\t3\tsrc/valid.ts";
197
+ const unified = makeUnifiedHeader("src/valid.ts") + "\n" + makeHunk("ctx", "add", "rm") + "\n";
198
+
199
+ const result = parseDiffOutput(numstat, unified);
200
+
201
+ expect(result.files).toHaveLength(1);
202
+ expect(result.files[0].filename).toBe("src/valid.ts");
203
+ });
204
+
205
+ it("treats non-numeric added/removed as 0", () => {
206
+ // "xyz" parsed as parseInt → 0
207
+ const numstat = "xyz\tabc\tsrc/weird.ts";
208
+ const result = parseDiffOutput(numstat, "");
209
+ expect(result.files[0].added).toBe(0);
210
+ expect(result.files[0].removed).toBe(0);
211
+ });
212
+ });
@@ -0,0 +1,237 @@
1
+ // @vitest-environment node
2
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
3
+
4
+ // Mock modules BEFORE imports to ensure correct hoisting
5
+ vi.mock("@/lib/db", () => ({
6
+ db: {
7
+ taskExecution: {
8
+ update: vi.fn().mockResolvedValue({}),
9
+ },
10
+ },
11
+ }));
12
+
13
+ vi.mock("@/lib/claude-session", () => ({
14
+ generateSummaryFromLog: vi.fn().mockResolvedValue(null),
15
+ }));
16
+
17
+ vi.mock("child_process", () => ({
18
+ execFileSync: vi.fn(),
19
+ }));
20
+
21
+ vi.mock("fs", () => ({
22
+ existsSync: vi.fn(),
23
+ }));
24
+
25
+ import { captureExecutionSummary } from "../execution-summary";
26
+ import { db } from "@/lib/db";
27
+ import { generateSummaryFromLog } from "@/lib/claude-session";
28
+ import { execFileSync } from "child_process";
29
+ import { existsSync } from "fs";
30
+
31
+ // Typed mock helpers
32
+ const mockUpdate = vi.mocked(db.taskExecution.update);
33
+ const mockGenerateSummaryFromLog = vi.mocked(generateSummaryFromLog);
34
+ const mockExecFileSync = vi.mocked(execFileSync);
35
+ const mockExistsSync = vi.mocked(existsSync);
36
+
37
+ // Helper: configure execFileSync to return expected git output based on args
38
+ function setupGitMocks(options?: {
39
+ gitDir?: string;
40
+ mergeBase?: string;
41
+ gitLog?: string;
42
+ diffStat?: string;
43
+ }) {
44
+ const opts = {
45
+ gitDir: ".git",
46
+ mergeBase: "abc1234567890",
47
+ gitLog: "abc1234 feat: add feature\ndef5678 fix: bug fix",
48
+ diffStat: " 2 files changed, 47 insertions(+), 12 deletions(-)",
49
+ ...options,
50
+ };
51
+
52
+ mockExecFileSync.mockImplementation((_cmd: unknown, args: unknown) => {
53
+ const gitArgs = args as string[];
54
+ const subcmd = gitArgs[0];
55
+
56
+ if (subcmd === "rev-parse" && gitArgs[1] === "--git-dir") {
57
+ return opts.gitDir as unknown as ReturnType<typeof execFileSync>;
58
+ }
59
+ if (subcmd === "merge-base") {
60
+ return opts.mergeBase as unknown as ReturnType<typeof execFileSync>;
61
+ }
62
+ if (subcmd === "log") {
63
+ return opts.gitLog as unknown as ReturnType<typeof execFileSync>;
64
+ }
65
+ if (subcmd === "diff" && gitArgs[1] === "--stat") {
66
+ return opts.diffStat as unknown as ReturnType<typeof execFileSync>;
67
+ }
68
+ return "" as unknown as ReturnType<typeof execFileSync>;
69
+ });
70
+ }
71
+
72
+ describe("captureExecutionSummary", () => {
73
+ const EXEC_ID = "exec-abc123";
74
+ const TASK_ID = "task-xyz456";
75
+ const WORKTREE = "/some/worktree/path";
76
+
77
+ beforeEach(() => {
78
+ vi.clearAllMocks();
79
+ // Suppress console.error noise from the function's own logging
80
+ vi.spyOn(console, "error").mockImplementation(() => {});
81
+ });
82
+
83
+ afterEach(() => {
84
+ vi.restoreAllMocks();
85
+ });
86
+
87
+ it("updates DB with git data when worktreePath exists and is a git repo", async () => {
88
+ mockExistsSync.mockReturnValue(true);
89
+
90
+ mockGenerateSummaryFromLog.mockResolvedValue("AI summary");
91
+ setupGitMocks();
92
+
93
+ await captureExecutionSummary(EXEC_ID, TASK_ID, 0, "terminal output", WORKTREE);
94
+
95
+ expect(mockUpdate).toHaveBeenCalled();
96
+ const callData = mockUpdate.mock.calls[0][0];
97
+ expect(callData.where).toEqual({ id: EXEC_ID });
98
+ expect(callData.data.exitCode).toBe(0);
99
+ // sessionId is now reported via PostToolUse hook, not captured here
100
+ expect(callData.data.sessionId).toBeUndefined();
101
+ // Git log and stats should be populated
102
+ expect(callData.data.gitLog).toBeTruthy();
103
+ expect(callData.data.gitStats).toBeTruthy();
104
+ // gitStats is JSON string containing commits, filesChanged etc.
105
+ const parsedStats = JSON.parse(callData.data.gitStats as string);
106
+ expect(parsedStats.filesChanged).toBe(2);
107
+ expect(parsedStats.insertions).toBe(47);
108
+ expect(parsedStats.deletions).toBe(12);
109
+ expect(parsedStats.commits).toBeGreaterThanOrEqual(1);
110
+ });
111
+
112
+ it("updates DB without git data when worktreePath is null", async () => {
113
+ await captureExecutionSummary(EXEC_ID, TASK_ID, 1, "some output", null);
114
+
115
+ expect(mockUpdate).toHaveBeenCalled();
116
+ const callData = mockUpdate.mock.calls[0][0];
117
+ expect(callData.data.exitCode).toBe(1);
118
+ expect(callData.data.gitLog).toBeNull();
119
+ expect(callData.data.gitStats).toBeNull();
120
+ });
121
+
122
+ it("updates DB without git data when worktreePath does not exist on filesystem", async () => {
123
+ mockExistsSync.mockReturnValue(false);
124
+
125
+ await captureExecutionSummary(EXEC_ID, TASK_ID, 0, "terminal output", WORKTREE);
126
+
127
+ expect(mockUpdate).toHaveBeenCalled();
128
+ const callData = mockUpdate.mock.calls[0][0];
129
+ expect(callData.data.gitLog).toBeNull();
130
+ expect(callData.data.gitStats).toBeNull();
131
+ });
132
+
133
+ it("strips ANSI escape codes from terminal buffer before storing terminalLog", async () => {
134
+ const ansiBuffer = "\x1b[31mred text\x1b[0m normal text";
135
+
136
+ await captureExecutionSummary(EXEC_ID, TASK_ID, 0, ansiBuffer, null);
137
+
138
+ const callData = mockUpdate.mock.calls[0][0];
139
+ const terminalLog = callData.data.terminalLog as string;
140
+ // ANSI sequences should be stripped
141
+ expect(terminalLog).not.toContain("\x1b");
142
+ expect(terminalLog).toContain("red text");
143
+ expect(terminalLog).toContain("normal text");
144
+ });
145
+
146
+ it("strips OSC sequences from terminal buffer", async () => {
147
+ const oscBuffer = "\x1b]0;title\x07 visible content";
148
+
149
+ await captureExecutionSummary(EXEC_ID, TASK_ID, 0, oscBuffer, null);
150
+
151
+ const callData = mockUpdate.mock.calls[0][0];
152
+ const terminalLog = callData.data.terminalLog as string;
153
+ expect(terminalLog).not.toContain("\x1b]");
154
+ expect(terminalLog).toContain("visible content");
155
+ });
156
+
157
+ it("trims large terminal buffer to 10KB (last 10KB kept)", async () => {
158
+ // Create a 20KB buffer
159
+ const bigBuffer = "x".repeat(20 * 1024);
160
+
161
+ await captureExecutionSummary(EXEC_ID, TASK_ID, 0, bigBuffer, null);
162
+
163
+ const callData = mockUpdate.mock.calls[0][0];
164
+ const terminalLog = callData.data.terminalLog as string;
165
+ // After ANSI strip (no ANSI here), should be <= 10KB
166
+ expect(terminalLog.length).toBeLessThanOrEqual(10 * 1024);
167
+ });
168
+
169
+ it("stores null for terminalLog when buffer is empty", async () => {
170
+ await captureExecutionSummary(EXEC_ID, TASK_ID, 0, "", null);
171
+
172
+ const callData = mockUpdate.mock.calls[0][0];
173
+ expect(callData.data.terminalLog).toBeNull();
174
+ });
175
+
176
+ it("does not throw when DB update fails", async () => {
177
+ mockUpdate.mockRejectedValueOnce(new Error("DB connection failed"));
178
+
179
+ // Should not throw — captureExecutionSummary is designed to never throw
180
+ await expect(
181
+ captureExecutionSummary(EXEC_ID, TASK_ID, 0, "output", null)
182
+ ).resolves.toBeUndefined();
183
+ });
184
+
185
+ it("calls generateSummaryFromLog for background AI summary when terminalLog and worktreePath are present", async () => {
186
+ mockExistsSync.mockReturnValue(true);
187
+ mockGenerateSummaryFromLog.mockResolvedValue("Background AI summary");
188
+ setupGitMocks();
189
+
190
+ await captureExecutionSummary(EXEC_ID, TASK_ID, 0, "terminal output", WORKTREE);
191
+
192
+ // generateSummaryFromLog should have been called with cleaned terminal log and worktree path
193
+ expect(mockGenerateSummaryFromLog).toHaveBeenCalled();
194
+ const [logArg, pathArg] = mockGenerateSummaryFromLog.mock.calls[0];
195
+ expect(pathArg).toBe(WORKTREE);
196
+ expect(logArg).not.toContain("\x1b");
197
+ expect(logArg).toContain("terminal output");
198
+ });
199
+
200
+ it("does not call generateSummaryFromLog when worktreePath is null", async () => {
201
+ await captureExecutionSummary(EXEC_ID, TASK_ID, 0, "terminal output", null);
202
+
203
+ expect(mockGenerateSummaryFromLog).not.toHaveBeenCalled();
204
+ });
205
+
206
+ it("does not call generateSummaryFromLog when terminal buffer is empty", async () => {
207
+ mockExistsSync.mockReturnValue(true);
208
+ setupGitMocks();
209
+
210
+ await captureExecutionSummary(EXEC_ID, TASK_ID, 0, "", WORKTREE);
211
+
212
+ expect(mockGenerateSummaryFromLog).not.toHaveBeenCalled();
213
+ });
214
+
215
+ it("includes correct exitCode in DB update", async () => {
216
+ await captureExecutionSummary(EXEC_ID, TASK_ID, 42, "output", null);
217
+
218
+ const callData = mockUpdate.mock.calls[0][0];
219
+ expect(callData.data.exitCode).toBe(42);
220
+ });
221
+
222
+ it("handles git command failure gracefully — git data is null, does not throw", async () => {
223
+ mockExistsSync.mockReturnValue(true);
224
+ // rev-parse throws — not a git repo
225
+ mockExecFileSync.mockImplementation(() => {
226
+ throw new Error("not a git repository");
227
+ });
228
+
229
+ await expect(
230
+ captureExecutionSummary(EXEC_ID, TASK_ID, 0, "output", WORKTREE)
231
+ ).resolves.toBeUndefined();
232
+
233
+ const callData = mockUpdate.mock.calls[0][0];
234
+ expect(callData.data.gitLog).toBeNull();
235
+ expect(callData.data.gitStats).toBeNull();
236
+ });
237
+ });
@@ -0,0 +1,178 @@
1
+ import { describe, it, expect, vi } from "vitest";
2
+ import * as path from "node:path";
3
+
4
+ // Mock tower-dir to return a predictable path
5
+ vi.mock("../tower-dir", () => ({
6
+ getStorageDir: () => "/mock/tower/storage",
7
+ }));
8
+
9
+ import { resolveAssetPath, MIME_MAP } from "../file-serve";
10
+ import { localPathToApiUrl } from "../file-serve-client";
11
+
12
+ // ── resolveAssetPath ──
13
+
14
+ describe("resolveAssetPath — valid paths", () => {
15
+ it("returns resolved path under storage/assets/{projectId} for a simple filename", () => {
16
+ const { resolved, error } = resolveAssetPath("proj123", "image.png");
17
+ expect(error).toBeNull();
18
+ expect(resolved).not.toBeNull();
19
+ expect(resolved!).toContain(path.join("storage", "assets", "proj123", "image.png"));
20
+ });
21
+
22
+ it("returns resolved path for filename with spaces", () => {
23
+ const { resolved, error } = resolveAssetPath("proj123", "my file.png");
24
+ expect(error).toBeNull();
25
+ expect(resolved!).toContain("my file.png");
26
+ });
27
+
28
+ it("returns resolved path for nested filename without traversal", () => {
29
+ const { resolved, error } = resolveAssetPath("proj123", "subdir/image.png");
30
+ if (error === null) {
31
+ expect(resolved!).toContain(path.join("storage", "assets", "proj123"));
32
+ } else {
33
+ expect(error).toBe("Invalid path");
34
+ }
35
+ });
36
+ });
37
+
38
+ describe("resolveAssetPath — path traversal blocking", () => {
39
+ it("blocks simple directory traversal '../../../etc/passwd'", () => {
40
+ const { resolved, error } = resolveAssetPath("proj123", "../../../etc/passwd");
41
+ expect(resolved).toBeNull();
42
+ expect(error).toBe("Invalid path");
43
+ });
44
+
45
+ it("blocks traversal attempting to escape project directory '../../../etc'", () => {
46
+ const { resolved, error } = resolveAssetPath("proj123", "../../etc");
47
+ expect(resolved).toBeNull();
48
+ expect(error).toBe("Invalid path");
49
+ });
50
+
51
+ it("blocks traversal via nested relative path 'sub/../../../etc/passwd'", () => {
52
+ const { resolved, error } = resolveAssetPath("proj123", "sub/../../../etc/passwd");
53
+ expect(resolved).toBeNull();
54
+ expect(error).toBe("Invalid path");
55
+ });
56
+
57
+ it("allows single level up traversal that stays within storage/assets", () => {
58
+ const { resolved, error } = resolveAssetPath("proj123", "../sibling-proj/secret.txt");
59
+ expect(error).toBeNull();
60
+ expect(resolved).not.toBeNull();
61
+ expect(resolved!).toContain(path.join("storage", "assets", "sibling-proj", "secret.txt"));
62
+ });
63
+
64
+ it("blocks absolute path '/etc/passwd'", () => {
65
+ const { resolved, error } = resolveAssetPath("proj123", "/etc/passwd");
66
+ expect(resolved).toBeNull();
67
+ expect(error).toBe("Invalid path");
68
+ });
69
+ });
70
+
71
+ // ── MIME_MAP ──
72
+
73
+ describe("MIME_MAP", () => {
74
+ it("maps .png to image/png", () => {
75
+ expect(MIME_MAP[".png"]).toBe("image/png");
76
+ });
77
+
78
+ it("maps .jpg to image/jpeg", () => {
79
+ expect(MIME_MAP[".jpg"]).toBe("image/jpeg");
80
+ });
81
+
82
+ it("maps .jpeg to image/jpeg", () => {
83
+ expect(MIME_MAP[".jpeg"]).toBe("image/jpeg");
84
+ });
85
+
86
+ it("maps .svg to image/svg+xml", () => {
87
+ expect(MIME_MAP[".svg"]).toBe("image/svg+xml");
88
+ });
89
+
90
+ it("maps .gif to image/gif", () => {
91
+ expect(MIME_MAP[".gif"]).toBe("image/gif");
92
+ });
93
+
94
+ it("maps .webp to image/webp", () => {
95
+ expect(MIME_MAP[".webp"]).toBe("image/webp");
96
+ });
97
+
98
+ it("maps .pdf to application/pdf", () => {
99
+ expect(MIME_MAP[".pdf"]).toBe("application/pdf");
100
+ });
101
+
102
+ it("maps .json to application/json", () => {
103
+ expect(MIME_MAP[".json"]).toBe("application/json");
104
+ });
105
+
106
+ it("maps .txt to text/plain", () => {
107
+ expect(MIME_MAP[".txt"]).toBe("text/plain");
108
+ });
109
+
110
+ it("maps .md to text/markdown", () => {
111
+ expect(MIME_MAP[".md"]).toBe("text/markdown");
112
+ });
113
+
114
+ it("returns undefined for unknown extension .unknown", () => {
115
+ expect(MIME_MAP[".unknown"]).toBeUndefined();
116
+ });
117
+
118
+ it("returns undefined for .exe (not in map)", () => {
119
+ expect(MIME_MAP[".exe"]).toBeUndefined();
120
+ });
121
+
122
+ it("returns undefined for empty string key", () => {
123
+ expect(MIME_MAP[""]).toBeUndefined();
124
+ });
125
+ });
126
+
127
+ // ── localPathToApiUrl ──
128
+
129
+ describe("localPathToApiUrl", () => {
130
+ it("converts storage/assets path to API URL", () => {
131
+ const result = localPathToApiUrl("/Users/alice/.tower/storage/assets/abc123/file.png");
132
+ expect(result).toBe("/api/files/assets/abc123/file.png");
133
+ });
134
+
135
+ it("converts relative storage/assets path to API URL", () => {
136
+ const result = localPathToApiUrl("storage/assets/abc123/file.png");
137
+ expect(result).toBe("/api/files/assets/abc123/file.png");
138
+ });
139
+
140
+ it("converts legacy data/assets path to API URL (backward compat)", () => {
141
+ const result = localPathToApiUrl("data/assets/abc123/file.png");
142
+ expect(result).toBe("/api/files/assets/abc123/file.png");
143
+ });
144
+
145
+ it("converts path with leading slash /data/assets/... to API URL", () => {
146
+ const result = localPathToApiUrl("/data/assets/abc123/file.png");
147
+ expect(result).toBe("/api/files/assets/abc123/file.png");
148
+ });
149
+
150
+ it("converts absolute path ending in data/assets/... to API URL", () => {
151
+ const result = localPathToApiUrl("/absolute/path/to/data/assets/abc123/file.png");
152
+ expect(result).toBe("/api/files/assets/abc123/file.png");
153
+ });
154
+
155
+ it("returns input unchanged for unrelated path 'unrelated/path.png'", () => {
156
+ const result = localPathToApiUrl("unrelated/path.png");
157
+ expect(result).toBe("unrelated/path.png");
158
+ });
159
+
160
+ it("returns input unchanged for external URL", () => {
161
+ const url = "https://example.com/image.png";
162
+ expect(localPathToApiUrl(url)).toBe(url);
163
+ });
164
+
165
+ it("returns input unchanged for path that doesn't match pattern", () => {
166
+ const p = "cache/abc123/file.png";
167
+ expect(localPathToApiUrl(p)).toBe(p);
168
+ });
169
+
170
+ it("converts path with project ID containing numbers and letters", () => {
171
+ const result = localPathToApiUrl("storage/assets/clh1234567890abcdefghij/screenshot.jpg");
172
+ expect(result).toBe("/api/files/assets/clh1234567890abcdefghij/screenshot.jpg");
173
+ });
174
+
175
+ it("returns input unchanged for empty string", () => {
176
+ expect(localPathToApiUrl("")).toBe("");
177
+ });
178
+ });