tower-studio 0.2.7 → 0.2.9
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/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/react-loadable-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +47 -47
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +9 -9
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/adapters/test/route.js +3 -2
- package/.next/standalone/.next/server/app/api/adapters/test/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/browse-fs/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/internal/assistant/sessions/route.js +1 -1
- package/.next/standalone/.next/server/app/api/internal/terminal/[taskId]/start/route.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +9 -9
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/missions/page/react-loadable-manifest.json +1 -1
- package/.next/standalone/.next/server/app/missions/page/server-reference-manifest.json +75 -75
- package/.next/standalone/.next/server/app/missions/page.js +5 -5
- package/.next/standalone/.next/server/app/missions/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/missions/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/onboarding/page/react-loadable-manifest.json +1 -1
- package/.next/standalone/.next/server/app/onboarding/page/server-reference-manifest.json +47 -47
- package/.next/standalone/.next/server/app/onboarding/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/onboarding/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/onboarding.html +1 -1
- package/.next/standalone/.next/server/app/onboarding.rsc +16 -16
- package/.next/standalone/.next/server/app/onboarding.segments/_full.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/onboarding.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/onboarding.segments/_index.segment.rsc +9 -9
- package/.next/standalone/.next/server/app/onboarding.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/onboarding.segments/onboarding/__PAGE__.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/onboarding.segments/onboarding.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/page/react-loadable-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +47 -47
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/react-loadable-manifest.json +1 -1
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +60 -60
- package/.next/standalone/.next/server/app/settings/page.js +3 -3
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings.html +1 -1
- package/.next/standalone/.next/server/app/settings.rsc +16 -16
- package/.next/standalone/.next/server/app/settings.segments/_full.segment.rsc +16 -16
- package/.next/standalone/.next/server/app/settings.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/settings.segments/_index.segment.rsc +9 -9
- package/.next/standalone/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/settings.segments/settings.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/archive/page/react-loadable-manifest.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/archive/page/server-reference-manifest.json +98 -98
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/archive/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/archive/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/assets/page/react-loadable-manifest.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/assets/page/server-reference-manifest.json +88 -88
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/assets/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/assets/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/notes/page/react-loadable-manifest.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/notes/page/server-reference-manifest.json +81 -81
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/notes/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/notes/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/page/react-loadable-manifest.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/page/server-reference-manifest.json +76 -76
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/page.js +3 -3
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/page/react-loadable-manifest.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/page/server-reference-manifest.json +47 -47
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/versions/page/react-loadable-manifest.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/versions/page/server-reference-manifest.json +84 -84
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/versions/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/projects/[projectId]/versions/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/tasks/[taskId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/tasks/[taskId]/page/server-reference-manifest.json +90 -90
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/tasks/[taskId]/page.js +5 -5
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/tasks/[taskId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/[workspaceId]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/workspaces/page/react-loadable-manifest.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/page/server-reference-manifest.json +67 -67
- package/.next/standalone/.next/server/app/workspaces/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/workspaces/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/0se9_next_dist_esm_build_templates_app-route_0h5yr8p.js +1 -1
- package/.next/standalone/.next/server/chunks/0se9_next_dist_esm_build_templates_app-route_0hrprmi.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__028ucbo._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__03gi3ue._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__07f7~6u._.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_90467._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0d~z6xs._.js +2 -2
- package/.next/standalone/.next/server/chunks/_0_w835g._.js +4 -0
- package/.next/standalone/.next/server/chunks/src_0bkvm8c._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_lib_0ba0ntr._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_lib_ai_0q-~me1._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_lib_ai_0xx6y51._.js +1 -1
- package/.next/standalone/.next/server/chunks/src_lib_ai_providers_index_ts_0.y.3vp._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/0iu._[workspaceId]_projects_[projectId]_versions_version-timeline-client_tsx_07o_kyi._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0.ukame._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__006_qh0._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__01j8ix6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__02px.0y._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__03ebsif._.js +3 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ca_ueb._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0dsdplu._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0l43.5g._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0n.cuy2._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0nbj.ml._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ojv-d0._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0pm2~fu._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ps55l6._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ribsk4._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0rjue04._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0souuv~._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0tc6uh2._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0v2eslh._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0vwc25l._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0wjg_.n._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0wlmzzq._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0wvyks.._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0u4gc4b._.js → [root-of-the-server]__0z7q-_5._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0zbmoit._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0~03tpv._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0~a-emb._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0zujp5l._.js → [root-of-the-server]__10o9il8._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__13vdw4w._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{_0ysygps._.js → _0-fpxu8._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_0pd0.8f._.js → _03zmko4._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_04b71ua._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0ysyq9g._.js → _0568hf5._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_05h.8a~._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_07k_7zo._.js +7 -0
- package/.next/standalone/.next/server/chunks/ssr/{_0c-jnbs._.js → _0999z~z._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_0_l8.dg._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0cj9a7y._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0ds6nk2._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0gkxdta._.js +7 -0
- package/.next/standalone/.next/server/chunks/ssr/_0i4__mf._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0ihq._v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0f6u19w._.js → _0jxhs~u._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/{_0b0.-sj._.js → _0r8ftmo._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_0r9w-k8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0rbctq7._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0rt8hus._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{_0bw-tx8._.js → _0zcog8w._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_0~80adm._.js +3 -3
- package/.next/standalone/.next/server/chunks/ssr/{_0fob8fc._.js → _11uabrg._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_13b~3az._.js +7 -0
- package/.next/standalone/.next/server/chunks/ssr/src_0eufeyj._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/src_13jha60._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_actions_agent-actions_ts_0~wc.sy._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_actions_file-actions_ts_0gcvqwm._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_app_missions_missions-client_tsx_11429lj._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_app_onboarding_page_tsx_0xf7hpz._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_app_settings_page_tsx_0h9v7dr._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_app_workspaces_[workspaceId]_assets_assets-page-client_tsx_0wyzpam._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_app_workspaces_[workspaceId]_board-page-client_tsx_0gips66._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_app_workspaces_[workspaceId]_tasks_[taskId]_task-page-client_tsx_02t7blt._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +317 -317
- package/.next/standalone/.next/static/chunks/{0v~pz9e87t99b.js → 0-9-c__gfaxpa.js} +1 -1
- package/.next/standalone/.next/static/chunks/{05-ui_o~3irq_.js → 04djo-eed_8rf.js} +2 -2
- package/.next/standalone/.next/static/chunks/{0r1mkt5qs~s6m.js → 05fy_a4boi~ym.js} +1 -1
- package/.next/standalone/.next/static/chunks/05mg~bkdmeovq.js +1 -0
- package/.next/standalone/.next/static/chunks/08o3st.fn2~6x.js +1 -0
- package/.next/standalone/.next/static/chunks/{08~e63d2q~cam.js → 0d5wyd0-zzb94.js} +1 -1
- package/.next/standalone/.next/static/chunks/{00j0mdc41wa44.js → 0e6c~o_iuvycp.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0i55dediewjp5.js → 0h3jzfwt-f9o7.js} +1 -1
- package/.next/standalone/.next/static/chunks/0igfu0uxcf238.js +1 -0
- package/.next/standalone/.next/static/chunks/{0l3mmc866npw4.js → 0jd4uhx~x74ox.js} +2 -2
- package/.next/standalone/.next/static/chunks/{0bw4ahlj4~l~g.js → 0obdotk~5x07o.js} +1 -1
- package/.next/standalone/.next/static/chunks/0o~dk86gtjq-..js +1 -0
- package/.next/standalone/.next/static/chunks/{0ft77ybyq903..js → 0p_vnqgdse218.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0~27mkhc9s5k2.js → 0sbpshsch~ak2.js} +2 -2
- package/.next/standalone/.next/static/chunks/{00.52653v5c~c.js → 0t.7i1ltlf~rt.js} +1 -1
- package/.next/standalone/.next/static/chunks/0v--ko.s9zeij.js +1 -0
- package/.next/standalone/.next/static/chunks/{02edbrlq~2uyx.js → 0v-8_9de2o32z.js} +1 -1
- package/.next/standalone/.next/static/chunks/{05hls.3r4bz.0.js → 0x~sbju1g3fjh.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0fxm-wv..y_a_.js → 0y1m4k4hrzl33.js} +2 -2
- package/.next/standalone/.next/static/chunks/0ztm6whl93nyg.js +1 -0
- package/.next/standalone/.next/static/chunks/136efy8zbqp13.js +1 -0
- package/.next/standalone/package.json +1 -2
- package/dist/mcp-server.cjs +34 -28
- package/package.json +1 -2
- package/scripts/post-tool-hook.js +24 -39
- package/scripts/session-start-hook.js +21 -19
- package/scripts/stop-hook.js +21 -19
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0wbndoc._.js +0 -4
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__04pq37d._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__07_b6c.._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__09kc.q_._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0jo1r7k._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0o8k4pc._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/_02v3fjp._.js +0 -7
- package/.next/standalone/.next/server/chunks/ssr/_07~0_w6._.js +0 -7
- package/.next/standalone/.next/server/chunks/ssr/_08w-r6e._.js +0 -7
- package/.next/standalone/.next/server/chunks/ssr/src_095o8x6._.js +0 -3
- package/.next/standalone/.next/static/chunks/0nno5if2x1mvs.js +0 -1
- package/.next/standalone/.next/static/chunks/0q-u-hhre1uyw.js +0 -1
- package/.next/standalone/.next/static/chunks/0qazzw-pr_sv7.js +0 -1
- package/.next/standalone/.next/static/chunks/0w3jww1m3k77x.js +0 -1
- package/.next/standalone/.next/static/chunks/0z01g02xstbqe.js +0 -1
- package/.next/standalone/.next/static/chunks/117qu902jput3.js +0 -1
- package/.next/standalone/.next/static/chunks/142w-q8.7m3kl.js +0 -1
- package/src/mcp/db.ts +0 -11
- package/src/mcp/index.ts +0 -15
- package/src/mcp/server.ts +0 -52
- package/src/mcp/tools/__tests__/label-tools.test.ts +0 -140
- package/src/mcp/tools/__tests__/project-tools.test.ts +0 -182
- package/src/mcp/tools/__tests__/report-tools.test.ts +0 -212
- package/src/mcp/tools/__tests__/task-tools.test.ts +0 -418
- package/src/mcp/tools/__tests__/terminal-tools.test.ts +0 -318
- package/src/mcp/tools/__tests__/workspace-tools.test.ts +0 -146
- package/src/mcp/tools/knowledge-tools.ts +0 -100
- package/src/mcp/tools/label-tools.ts +0 -70
- package/src/mcp/tools/note-asset-tools.ts +0 -271
- package/src/mcp/tools/project-tools.ts +0 -79
- package/src/mcp/tools/report-tools.ts +0 -220
- package/src/mcp/tools/search-tools.ts +0 -32
- package/src/mcp/tools/task-tools.ts +0 -272
- package/src/mcp/tools/terminal-tools.ts +0 -154
- package/src/mcp/tools/workspace-tools.ts +0 -73
- /package/.next/standalone/.next/static/{om3SyUw4eAwMA0KLhpSGh → 7iWXcI7IK1tpJQ-itTcOk}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{om3SyUw4eAwMA0KLhpSGh → 7iWXcI7IK1tpJQ-itTcOk}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{om3SyUw4eAwMA0KLhpSGh → 7iWXcI7IK1tpJQ-itTcOk}/_ssgManifest.js +0 -0
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { execFileSync } from "child_process";
|
|
3
|
-
import { copyFileSync, existsSync, statSync, mkdirSync } from "fs";
|
|
4
|
-
import { basename, extname, join, resolve } from "path";
|
|
5
|
-
import { db } from "../db";
|
|
6
|
-
import { stripCacheUuidSuffix, isAssistantCachePath } from "@/lib/file-utils";
|
|
7
|
-
|
|
8
|
-
// Derive project root from this file's location (src/mcp/tools/ → ../../..)
|
|
9
|
-
// This avoids depending on process.cwd() which varies when MCP is spawned from .tower/
|
|
10
|
-
const MCP_PROJECT_ROOT = resolve(__dirname, "../../..");
|
|
11
|
-
|
|
12
|
-
const TaskStatus = z.enum(["TODO", "IN_PROGRESS", "IN_REVIEW", "DONE", "CANCELLED"]);
|
|
13
|
-
const Priority = z.enum(["LOW", "MEDIUM", "HIGH", "CRITICAL"]);
|
|
14
|
-
|
|
15
|
-
export const taskTools = {
|
|
16
|
-
list_tasks: {
|
|
17
|
-
description: "List all tasks in a project, optionally filtered by status. Includes labels and is ordered by position then creation date.",
|
|
18
|
-
schema: z.object({
|
|
19
|
-
projectId: z.string(),
|
|
20
|
-
status: TaskStatus.optional(),
|
|
21
|
-
}),
|
|
22
|
-
handler: async (args: { projectId: string; status?: string }) => {
|
|
23
|
-
const tasks = await db.task.findMany({
|
|
24
|
-
where: {
|
|
25
|
-
projectId: args.projectId,
|
|
26
|
-
...(args.status ? { status: args.status as "TODO" | "IN_PROGRESS" | "IN_REVIEW" | "DONE" | "CANCELLED" } : {}),
|
|
27
|
-
// Exclude system tasks tagged with the builtin "Tower" label
|
|
28
|
-
NOT: { labels: { some: { label: { name: "Tower", isBuiltin: true } } } },
|
|
29
|
-
},
|
|
30
|
-
include: {
|
|
31
|
-
labels: { include: { label: true } },
|
|
32
|
-
},
|
|
33
|
-
orderBy: [{ order: "asc" }, { createdAt: "desc" }],
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
return tasks.map((task) => ({
|
|
37
|
-
...task,
|
|
38
|
-
labels: task.labels.map((tl) => tl.label),
|
|
39
|
-
}));
|
|
40
|
-
},
|
|
41
|
-
},
|
|
42
|
-
|
|
43
|
-
create_task: {
|
|
44
|
-
description: "Create a new task in a project. Priority defaults to MEDIUM, status defaults to TODO. Set useWorktree=true for branch isolation. Set autoStart=true (default) to immediately start execution. Pass references as file paths to attach as project assets.",
|
|
45
|
-
schema: z.object({
|
|
46
|
-
projectId: z.string(),
|
|
47
|
-
title: z.string(),
|
|
48
|
-
description: z.string().optional(),
|
|
49
|
-
priority: Priority.optional().default("MEDIUM"),
|
|
50
|
-
status: TaskStatus.optional().default("TODO"),
|
|
51
|
-
labelIds: z.array(z.string()).optional(),
|
|
52
|
-
subPath: z.string().optional(),
|
|
53
|
-
useWorktree: z.boolean().optional().default(false),
|
|
54
|
-
baseBranch: z.string().optional().describe("Base branch for worktree checkout. Only used when useWorktree=true. If omitted, auto-detects the project's current branch."),
|
|
55
|
-
autoStart: z.boolean().optional().default(true),
|
|
56
|
-
references: z.array(z.string()).max(20).optional(),
|
|
57
|
-
}),
|
|
58
|
-
handler: async (args: {
|
|
59
|
-
projectId: string;
|
|
60
|
-
title: string;
|
|
61
|
-
description?: string;
|
|
62
|
-
priority?: string;
|
|
63
|
-
status?: string;
|
|
64
|
-
labelIds?: string[];
|
|
65
|
-
subPath?: string;
|
|
66
|
-
useWorktree?: boolean;
|
|
67
|
-
baseBranch?: string;
|
|
68
|
-
autoStart?: boolean;
|
|
69
|
-
references?: string[];
|
|
70
|
-
}) => {
|
|
71
|
-
// Determine baseBranch: explicit param > auto-detect from project's current git branch
|
|
72
|
-
let baseBranch: string | null = null;
|
|
73
|
-
if (args.useWorktree) {
|
|
74
|
-
if (args.baseBranch) {
|
|
75
|
-
baseBranch = args.baseBranch;
|
|
76
|
-
} else {
|
|
77
|
-
const project = await db.project.findUnique({ where: { id: args.projectId }, select: { localPath: true } });
|
|
78
|
-
if (project?.localPath) {
|
|
79
|
-
try {
|
|
80
|
-
baseBranch = execFileSync("git", ["branch", "--show-current"], {
|
|
81
|
-
cwd: project.localPath, encoding: "utf-8", timeout: 5000,
|
|
82
|
-
}).trim() || null;
|
|
83
|
-
} catch {
|
|
84
|
-
// fallback: no baseBranch, task runs in direct mode
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const task = await db.task.create({
|
|
91
|
-
data: {
|
|
92
|
-
title: args.title,
|
|
93
|
-
description: args.description,
|
|
94
|
-
projectId: args.projectId,
|
|
95
|
-
priority: (args.priority ?? "MEDIUM") as "LOW" | "MEDIUM" | "HIGH" | "CRITICAL",
|
|
96
|
-
status: (args.status ?? "TODO") as "TODO" | "IN_PROGRESS" | "IN_REVIEW" | "DONE" | "CANCELLED",
|
|
97
|
-
baseBranch,
|
|
98
|
-
},
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
if (args.labelIds && args.labelIds.length > 0) {
|
|
102
|
-
await db.taskLabel.createMany({
|
|
103
|
-
data: args.labelIds.map((labelId) => ({ taskId: task.id, labelId })),
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
// Copy reference files to assets and create ProjectAsset records
|
|
108
|
-
const attachedFiles: string[] = [];
|
|
109
|
-
let updatedDesc: string | null = null;
|
|
110
|
-
if (args.references && args.references.length > 0) {
|
|
111
|
-
const assetsDir = join(MCP_PROJECT_ROOT, "data", "assets", args.projectId);
|
|
112
|
-
mkdirSync(assetsDir, { recursive: true });
|
|
113
|
-
|
|
114
|
-
for (const filePath of args.references) {
|
|
115
|
-
try {
|
|
116
|
-
if (!existsSync(filePath)) continue;
|
|
117
|
-
const stat = statSync(filePath);
|
|
118
|
-
if (!stat.isFile()) continue;
|
|
119
|
-
|
|
120
|
-
const isCache = isAssistantCachePath(filePath);
|
|
121
|
-
let filename = isCache
|
|
122
|
-
? stripCacheUuidSuffix(basename(filePath))
|
|
123
|
-
: basename(filePath);
|
|
124
|
-
// Avoid overwriting existing assets
|
|
125
|
-
if (existsSync(join(assetsDir, filename))) {
|
|
126
|
-
const ext = extname(filename);
|
|
127
|
-
const base = basename(filename, ext);
|
|
128
|
-
if (isCache) {
|
|
129
|
-
// Use counter suffix for readable cache asset names: "设计稿 (1).png"
|
|
130
|
-
let counter = 1;
|
|
131
|
-
while (existsSync(join(assetsDir, `${base} (${counter})${ext}`))) {
|
|
132
|
-
counter++;
|
|
133
|
-
}
|
|
134
|
-
filename = `${base} (${counter})${ext}`;
|
|
135
|
-
} else {
|
|
136
|
-
filename = `${base}-${Date.now()}${ext}`;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
const dest = join(assetsDir, filename);
|
|
140
|
-
copyFileSync(filePath, dest);
|
|
141
|
-
|
|
142
|
-
await db.projectAsset.create({
|
|
143
|
-
data: {
|
|
144
|
-
filename,
|
|
145
|
-
path: dest,
|
|
146
|
-
size: stat.size,
|
|
147
|
-
projectId: args.projectId,
|
|
148
|
-
taskId: task.id,
|
|
149
|
-
description: `Reference: ${basename(filePath)}`,
|
|
150
|
-
},
|
|
151
|
-
});
|
|
152
|
-
attachedFiles.push(filename);
|
|
153
|
-
} catch {
|
|
154
|
-
// Skip files that can't be copied
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Append reference info to task description with full absolute paths
|
|
159
|
-
if (attachedFiles.length > 0) {
|
|
160
|
-
const refText = attachedFiles.map((f) => `- ${join(assetsDir, f)}`).join("\n");
|
|
161
|
-
updatedDesc = (task.description ?? "") + `\n\nAttached references:\n${refText}`;
|
|
162
|
-
await db.task.update({ where: { id: task.id }, data: { description: updatedDesc } });
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// Auto-start execution if requested — pass title as prompt since
|
|
167
|
-
// startPtyExecution already injects task description as context.
|
|
168
|
-
//
|
|
169
|
-
// We always surface the outcome on the response so the assistant doesn't
|
|
170
|
-
// claim "Execution started" when the kanban still shows TODO. Common
|
|
171
|
-
// failure modes worth keeping visible:
|
|
172
|
-
// - Next.js server unreachable (wrong port / not running)
|
|
173
|
-
// - Concurrency limit hit (system.maxConcurrentExecutions)
|
|
174
|
-
// - Project missing localPath
|
|
175
|
-
if (args.autoStart) {
|
|
176
|
-
const PORT = process.env.PORT ?? "3000";
|
|
177
|
-
const prompt = args.title;
|
|
178
|
-
try {
|
|
179
|
-
const res = await fetch(`http://localhost:${PORT}/api/internal/terminal/${task.id}/start`, {
|
|
180
|
-
method: "POST",
|
|
181
|
-
headers: { "Content-Type": "application/json" },
|
|
182
|
-
body: JSON.stringify({ prompt }),
|
|
183
|
-
});
|
|
184
|
-
if (res.ok) {
|
|
185
|
-
const execData = await res.json();
|
|
186
|
-
return { ...task, execution: execData };
|
|
187
|
-
}
|
|
188
|
-
let errMsg = `HTTP ${res.status}`;
|
|
189
|
-
try {
|
|
190
|
-
const errBody = (await res.json()) as { error?: string };
|
|
191
|
-
if (errBody?.error) errMsg = errBody.error;
|
|
192
|
-
} catch {
|
|
193
|
-
/* response body wasn't JSON; keep status code */
|
|
194
|
-
}
|
|
195
|
-
return { ...task, execution: null, executionError: errMsg };
|
|
196
|
-
} catch (err) {
|
|
197
|
-
return {
|
|
198
|
-
...task,
|
|
199
|
-
execution: null,
|
|
200
|
-
executionError: err instanceof Error ? err.message : String(err),
|
|
201
|
-
};
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
return task;
|
|
206
|
-
},
|
|
207
|
-
},
|
|
208
|
-
|
|
209
|
-
update_task: {
|
|
210
|
-
description: "Update a task's title, description, priority, labels, and/or subPath. If labelIds is provided, replaces all existing labels.",
|
|
211
|
-
schema: z.object({
|
|
212
|
-
taskId: z.string(),
|
|
213
|
-
title: z.string().optional(),
|
|
214
|
-
description: z.string().optional(),
|
|
215
|
-
priority: Priority.optional(),
|
|
216
|
-
labelIds: z.array(z.string()).optional(),
|
|
217
|
-
subPath: z.string().optional(),
|
|
218
|
-
}),
|
|
219
|
-
handler: async (args: {
|
|
220
|
-
taskId: string;
|
|
221
|
-
title?: string;
|
|
222
|
-
description?: string;
|
|
223
|
-
priority?: string;
|
|
224
|
-
labelIds?: string[];
|
|
225
|
-
subPath?: string;
|
|
226
|
-
}) => {
|
|
227
|
-
const { labelIds, taskId, ...updateData } = args;
|
|
228
|
-
|
|
229
|
-
return db.$transaction(async (tx) => {
|
|
230
|
-
const task = await tx.task.update({
|
|
231
|
-
where: { id: taskId },
|
|
232
|
-
data: updateData as { title?: string; description?: string; priority?: "LOW" | "MEDIUM" | "HIGH" | "CRITICAL"; subPath?: string },
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
if (labelIds !== undefined) {
|
|
236
|
-
await tx.taskLabel.deleteMany({ where: { taskId } });
|
|
237
|
-
if (labelIds.length > 0) {
|
|
238
|
-
await tx.taskLabel.createMany({
|
|
239
|
-
data: labelIds.map((labelId) => ({ taskId, labelId })),
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return task;
|
|
245
|
-
});
|
|
246
|
-
},
|
|
247
|
-
},
|
|
248
|
-
|
|
249
|
-
move_task: {
|
|
250
|
-
description: "Move a task to a different status column (e.g. TODO, IN_PROGRESS, IN_REVIEW, DONE, CANCELLED).",
|
|
251
|
-
schema: z.object({
|
|
252
|
-
taskId: z.string(),
|
|
253
|
-
status: TaskStatus,
|
|
254
|
-
}),
|
|
255
|
-
handler: async (args: { taskId: string; status: string }) => {
|
|
256
|
-
// Delegate to updateTaskStatus to trigger side effects (dreaming on DONE, worktree cleanup on CANCELLED, etc.)
|
|
257
|
-
const { updateTaskStatus } = await import("@/actions/task-actions");
|
|
258
|
-
return updateTaskStatus(args.taskId, args.status as "TODO" | "IN_PROGRESS" | "IN_REVIEW" | "DONE" | "CANCELLED");
|
|
259
|
-
},
|
|
260
|
-
},
|
|
261
|
-
|
|
262
|
-
delete_task: {
|
|
263
|
-
description: "Delete a task by ID.",
|
|
264
|
-
schema: z.object({
|
|
265
|
-
taskId: z.string(),
|
|
266
|
-
}),
|
|
267
|
-
handler: async (args: { taskId: string }) => {
|
|
268
|
-
await db.task.delete({ where: { id: args.taskId } });
|
|
269
|
-
return { deleted: true, taskId: args.taskId };
|
|
270
|
-
},
|
|
271
|
-
},
|
|
272
|
-
};
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { db } from "../db";
|
|
3
|
-
|
|
4
|
-
const PORT = process.env.PORT ?? "3000";
|
|
5
|
-
const BRIDGE_BASE = `http://localhost:${PORT}/api/internal/terminal`;
|
|
6
|
-
const CUID_RE = /^c[a-z0-9]{20,30}$/;
|
|
7
|
-
|
|
8
|
-
async function bridgeFetch(path: string, init?: RequestInit): Promise<Response> {
|
|
9
|
-
return fetch(`${BRIDGE_BASE}${path}`, init);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function validateMcpTaskId(taskId: string): string | null {
|
|
13
|
-
if (!CUID_RE.test(taskId)) return "Invalid taskId format — expected CUID";
|
|
14
|
-
return null;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export const terminalTools = {
|
|
18
|
-
start_task_execution: {
|
|
19
|
-
description:
|
|
20
|
-
"Start a Claude CLI terminal session for a task. The prompt is sent as the initial instruction. The task status will change to IN_PROGRESS. Returns executionId and worktreePath (if worktree mode).",
|
|
21
|
-
schema: z.object({
|
|
22
|
-
taskId: z.string(),
|
|
23
|
-
prompt: z.string().optional(),
|
|
24
|
-
}),
|
|
25
|
-
handler: async (args: { taskId: string; prompt?: string }) => {
|
|
26
|
-
const err = validateMcpTaskId(args.taskId);
|
|
27
|
-
if (err) return { error: err, taskId: args.taskId };
|
|
28
|
-
const tid = encodeURIComponent(args.taskId);
|
|
29
|
-
const response = await bridgeFetch(`/${tid}/start`, {
|
|
30
|
-
method: "POST",
|
|
31
|
-
headers: { "Content-Type": "application/json" },
|
|
32
|
-
body: JSON.stringify({ prompt: args.prompt ?? "" }),
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
if (response.ok) {
|
|
36
|
-
const data = await response.json();
|
|
37
|
-
return { ok: true, ...data };
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const errData = await response.json().catch(() => ({}));
|
|
41
|
-
return { error: (errData as Record<string, unknown>).error ?? "Failed to start execution", status: response.status };
|
|
42
|
-
},
|
|
43
|
-
},
|
|
44
|
-
|
|
45
|
-
get_task_terminal_output: {
|
|
46
|
-
description:
|
|
47
|
-
"Get recent terminal output lines from a running task's PTY session. Returns the last N lines (default 50, max 500).",
|
|
48
|
-
schema: z.object({
|
|
49
|
-
taskId: z.string(),
|
|
50
|
-
lines: z.number().int().min(1).max(500).optional(),
|
|
51
|
-
}),
|
|
52
|
-
handler: async (args: { taskId: string; lines?: number }) => {
|
|
53
|
-
const err = validateMcpTaskId(args.taskId);
|
|
54
|
-
if (err) return { error: err, taskId: args.taskId };
|
|
55
|
-
const tid = encodeURIComponent(args.taskId);
|
|
56
|
-
const response = await bridgeFetch(`/${tid}/buffer?lines=${args.lines ?? 50}`);
|
|
57
|
-
|
|
58
|
-
if (response.status === 404) {
|
|
59
|
-
return { error: "No active terminal session for this task", taskId: args.taskId };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (response.ok) {
|
|
63
|
-
const data = await response.json() as { taskId: string; lines: string[]; total: number; killed: boolean };
|
|
64
|
-
return { taskId: data.taskId, lines: data.lines, total: data.total, killed: data.killed };
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
return { error: "Bridge request failed", status: response.status };
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
|
|
71
|
-
send_task_terminal_input: {
|
|
72
|
-
description:
|
|
73
|
-
"Send text input to a running task's PTY terminal. The text is forwarded directly to the Claude CLI process. Include \\n for Enter key.",
|
|
74
|
-
schema: z.object({
|
|
75
|
-
taskId: z.string(),
|
|
76
|
-
text: z.string().min(1).max(10000),
|
|
77
|
-
}),
|
|
78
|
-
handler: async (args: { taskId: string; text: string }) => {
|
|
79
|
-
const err = validateMcpTaskId(args.taskId);
|
|
80
|
-
if (err) return { error: err, taskId: args.taskId };
|
|
81
|
-
const tid = encodeURIComponent(args.taskId);
|
|
82
|
-
const response = await bridgeFetch(`/${tid}/input`, {
|
|
83
|
-
method: "POST",
|
|
84
|
-
headers: { "Content-Type": "application/json" },
|
|
85
|
-
body: JSON.stringify({ text: args.text }),
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
if (response.status === 404) {
|
|
89
|
-
return { error: "No active terminal session for this task", taskId: args.taskId };
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (response.status === 410) {
|
|
93
|
-
return { error: "Terminal session has exited", taskId: args.taskId };
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (response.ok) {
|
|
97
|
-
return { ok: true, taskId: args.taskId };
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return { error: "Bridge request failed", status: response.status };
|
|
101
|
-
},
|
|
102
|
-
},
|
|
103
|
-
|
|
104
|
-
get_task_execution_status: {
|
|
105
|
-
description:
|
|
106
|
-
"Get the execution status of a task including whether its terminal is running, idle, or exited. Also returns a snippet of recent output.",
|
|
107
|
-
schema: z.object({
|
|
108
|
-
taskId: z.string(),
|
|
109
|
-
}),
|
|
110
|
-
handler: async (args: { taskId: string }) => {
|
|
111
|
-
const err = validateMcpTaskId(args.taskId);
|
|
112
|
-
if (err) return { error: err, taskId: args.taskId };
|
|
113
|
-
|
|
114
|
-
const execution = await db.taskExecution.findFirst({
|
|
115
|
-
where: { taskId: args.taskId },
|
|
116
|
-
orderBy: { createdAt: "desc" },
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
if (!execution) {
|
|
120
|
-
return { error: "No execution found for this task", taskId: args.taskId };
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const tid = encodeURIComponent(args.taskId);
|
|
124
|
-
const bufferResponse = await bridgeFetch(`/${tid}/buffer?lines=10`);
|
|
125
|
-
|
|
126
|
-
let terminalStatus: "running" | "exited" | "not_running";
|
|
127
|
-
let outputSnippet: string | null = null;
|
|
128
|
-
|
|
129
|
-
if (bufferResponse.status === 404) {
|
|
130
|
-
// No active session — check DB status
|
|
131
|
-
const doneStatuses = ["COMPLETED", "FAILED"];
|
|
132
|
-
terminalStatus = doneStatuses.includes(execution.status) ? "exited" : "not_running";
|
|
133
|
-
} else if (bufferResponse.ok) {
|
|
134
|
-
const bufferData = await bufferResponse.json() as { lines: string[]; killed: boolean };
|
|
135
|
-
terminalStatus = bufferData.killed ? "exited" : "running";
|
|
136
|
-
if (bufferData.lines && bufferData.lines.length > 0) {
|
|
137
|
-
outputSnippet = bufferData.lines.slice(-5).join("\n");
|
|
138
|
-
}
|
|
139
|
-
} else {
|
|
140
|
-
terminalStatus = "not_running";
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
return {
|
|
144
|
-
taskId: args.taskId,
|
|
145
|
-
executionId: execution.id,
|
|
146
|
-
executionStatus: execution.status,
|
|
147
|
-
terminalStatus,
|
|
148
|
-
startedAt: execution.startedAt,
|
|
149
|
-
endedAt: execution.endedAt,
|
|
150
|
-
outputSnippet,
|
|
151
|
-
};
|
|
152
|
-
},
|
|
153
|
-
},
|
|
154
|
-
};
|
|
@@ -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
|
-
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|