trident-git 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -0
- package/.next/app-path-routes-manifest.json +23 -0
- package/.next/build-manifest.json +20 -0
- package/.next/export-marker.json +6 -0
- package/.next/images-manifest.json +73 -0
- package/.next/next-minimal-server.js.nft.json +1 -0
- package/.next/next-server.js.nft.json +1 -0
- package/.next/package.json +1 -0
- package/.next/prerender-manifest.json +282 -0
- package/.next/react-loadable-manifest.json +1 -0
- package/.next/required-server-files.js +330 -0
- package/.next/required-server-files.json +330 -0
- package/.next/routes-manifest.json +170 -0
- package/.next/server/app/_global-error/page.js +3 -0
- package/.next/server/app/_global-error/page.js.nft.json +1 -0
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -0
- package/.next/server/app/_global-error.html +2 -0
- package/.next/server/app/_global-error.meta +16 -0
- package/.next/server/app/_global-error.rsc +12 -0
- package/.next/server/app/_global-error.segments/_full.segment.rsc +12 -0
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +5 -0
- package/.next/server/app/_global-error.segments/_global-error.segment.rsc +4 -0
- package/.next/server/app/_global-error.segments/_head.segment.rsc +5 -0
- package/.next/server/app/_global-error.segments/_index.segment.rsc +4 -0
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
- package/.next/server/app/_not-found/page.js +2 -0
- package/.next/server/app/_not-found/page.js.nft.json +1 -0
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/.next/server/app/_not-found.html +1 -0
- package/.next/server/app/_not-found.meta +16 -0
- package/.next/server/app/_not-found.rsc +19 -0
- package/.next/server/app/_not-found.segments/_full.segment.rsc +19 -0
- package/.next/server/app/_not-found.segments/_head.segment.rsc +6 -0
- package/.next/server/app/_not-found.segments/_index.segment.rsc +8 -0
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +5 -0
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +4 -0
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +6 -0
- package/.next/server/app/api/credentials/route.js +1 -0
- package/.next/server/app/api/credentials/route.js.nft.json +1 -0
- package/.next/server/app/api/credentials/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/custom-scripts/route.js +3 -0
- package/.next/server/app/api/custom-scripts/route.js.nft.json +1 -0
- package/.next/server/app/api/custom-scripts/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/fs/route.js +1 -0
- package/.next/server/app/api/fs/route.js.nft.json +1 -0
- package/.next/server/app/api/fs/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/git/action/route.js +1 -0
- package/.next/server/app/api/git/action/route.js.nft.json +1 -0
- package/.next/server/app/api/git/action/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/git/branches/route.js +1 -0
- package/.next/server/app/api/git/branches/route.js.nft.json +1 -0
- package/.next/server/app/api/git/branches/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/git/diff/route.js +1 -0
- package/.next/server/app/api/git/diff/route.js.nft.json +1 -0
- package/.next/server/app/api/git/diff/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/git/log/route.js +1 -0
- package/.next/server/app/api/git/log/route.js.nft.json +1 -0
- package/.next/server/app/api/git/log/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/git/status/route.js +1 -0
- package/.next/server/app/api/git/status/route.js.nft.json +1 -0
- package/.next/server/app/api/git/status/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/repos/route.js +1 -0
- package/.next/server/app/api/repos/route.js.nft.json +1 -0
- package/.next/server/app/api/repos/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/settings/route.js +1 -0
- package/.next/server/app/api/settings/route.js.nft.json +1 -0
- package/.next/server/app/api/settings/route_client-reference-manifest.js +1 -0
- package/.next/server/app/credentials/page.js +4 -0
- package/.next/server/app/credentials/page.js.nft.json +1 -0
- package/.next/server/app/credentials/page_client-reference-manifest.js +1 -0
- package/.next/server/app/credentials.html +1 -0
- package/.next/server/app/credentials.meta +15 -0
- package/.next/server/app/credentials.rsc +23 -0
- package/.next/server/app/credentials.segments/_full.segment.rsc +23 -0
- package/.next/server/app/credentials.segments/_head.segment.rsc +6 -0
- package/.next/server/app/credentials.segments/_index.segment.rsc +8 -0
- package/.next/server/app/credentials.segments/_tree.segment.rsc +6 -0
- package/.next/server/app/credentials.segments/credentials/__PAGE__.segment.rsc +9 -0
- package/.next/server/app/credentials.segments/credentials.segment.rsc +4 -0
- package/.next/server/app/icon.png/route.js +1 -0
- package/.next/server/app/icon.png/route.js.nft.json +1 -0
- package/.next/server/app/icon.png.meta +1 -0
- package/.next/server/app/index.html +1 -0
- package/.next/server/app/index.meta +14 -0
- package/.next/server/app/index.rsc +20 -0
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +6 -0
- package/.next/server/app/index.segments/_full.segment.rsc +20 -0
- package/.next/server/app/index.segments/_head.segment.rsc +6 -0
- package/.next/server/app/index.segments/_index.segment.rsc +8 -0
- package/.next/server/app/index.segments/_tree.segment.rsc +6 -0
- package/.next/server/app/page.js +2 -0
- package/.next/server/app/page.js.nft.json +1 -0
- package/.next/server/app/page_client-reference-manifest.js +1 -0
- package/.next/server/app/workspace/changes/page.js +4 -0
- package/.next/server/app/workspace/changes/page.js.nft.json +1 -0
- package/.next/server/app/workspace/changes/page_client-reference-manifest.js +1 -0
- package/.next/server/app/workspace/changes.html +1 -0
- package/.next/server/app/workspace/changes.meta +16 -0
- package/.next/server/app/workspace/changes.rsc +26 -0
- package/.next/server/app/workspace/changes.segments/_full.segment.rsc +26 -0
- package/.next/server/app/workspace/changes.segments/_head.segment.rsc +6 -0
- package/.next/server/app/workspace/changes.segments/_index.segment.rsc +8 -0
- package/.next/server/app/workspace/changes.segments/_tree.segment.rsc +7 -0
- package/.next/server/app/workspace/changes.segments/workspace/changes/__PAGE__.segment.rsc +10 -0
- package/.next/server/app/workspace/changes.segments/workspace/changes.segment.rsc +4 -0
- package/.next/server/app/workspace/changes.segments/workspace.segment.rsc +7 -0
- package/.next/server/app/workspace/custom-scripts/page.js +2 -0
- package/.next/server/app/workspace/custom-scripts/page.js.nft.json +1 -0
- package/.next/server/app/workspace/custom-scripts/page_client-reference-manifest.js +1 -0
- package/.next/server/app/workspace/custom-scripts.html +1 -0
- package/.next/server/app/workspace/custom-scripts.meta +16 -0
- package/.next/server/app/workspace/custom-scripts.rsc +25 -0
- package/.next/server/app/workspace/custom-scripts.segments/_full.segment.rsc +25 -0
- package/.next/server/app/workspace/custom-scripts.segments/_head.segment.rsc +6 -0
- package/.next/server/app/workspace/custom-scripts.segments/_index.segment.rsc +8 -0
- package/.next/server/app/workspace/custom-scripts.segments/_tree.segment.rsc +6 -0
- package/.next/server/app/workspace/custom-scripts.segments/workspace/custom-scripts/__PAGE__.segment.rsc +9 -0
- package/.next/server/app/workspace/custom-scripts.segments/workspace/custom-scripts.segment.rsc +4 -0
- package/.next/server/app/workspace/custom-scripts.segments/workspace.segment.rsc +7 -0
- package/.next/server/app/workspace/history/page.js +2 -0
- package/.next/server/app/workspace/history/page.js.nft.json +1 -0
- package/.next/server/app/workspace/history/page_client-reference-manifest.js +1 -0
- package/.next/server/app/workspace/history.html +1 -0
- package/.next/server/app/workspace/history.meta +16 -0
- package/.next/server/app/workspace/history.rsc +26 -0
- package/.next/server/app/workspace/history.segments/_full.segment.rsc +26 -0
- package/.next/server/app/workspace/history.segments/_head.segment.rsc +6 -0
- package/.next/server/app/workspace/history.segments/_index.segment.rsc +8 -0
- package/.next/server/app/workspace/history.segments/_tree.segment.rsc +7 -0
- package/.next/server/app/workspace/history.segments/workspace/history/__PAGE__.segment.rsc +10 -0
- package/.next/server/app/workspace/history.segments/workspace/history.segment.rsc +4 -0
- package/.next/server/app/workspace/history.segments/workspace.segment.rsc +7 -0
- package/.next/server/app/workspace/page.js +2 -0
- package/.next/server/app/workspace/page.js.nft.json +1 -0
- package/.next/server/app/workspace/page_client-reference-manifest.js +1 -0
- package/.next/server/app/workspace/settings/page.js +2 -0
- package/.next/server/app/workspace/settings/page.js.nft.json +1 -0
- package/.next/server/app/workspace/settings/page_client-reference-manifest.js +1 -0
- package/.next/server/app/workspace/settings.html +1 -0
- package/.next/server/app/workspace/settings.meta +16 -0
- package/.next/server/app/workspace/settings.rsc +25 -0
- package/.next/server/app/workspace/settings.segments/_full.segment.rsc +25 -0
- package/.next/server/app/workspace/settings.segments/_head.segment.rsc +6 -0
- package/.next/server/app/workspace/settings.segments/_index.segment.rsc +8 -0
- package/.next/server/app/workspace/settings.segments/_tree.segment.rsc +6 -0
- package/.next/server/app/workspace/settings.segments/workspace/settings/__PAGE__.segment.rsc +9 -0
- package/.next/server/app/workspace/settings.segments/workspace/settings.segment.rsc +4 -0
- package/.next/server/app/workspace/settings.segments/workspace.segment.rsc +7 -0
- package/.next/server/app/workspace/stashes/page.js +2 -0
- package/.next/server/app/workspace/stashes/page.js.nft.json +1 -0
- package/.next/server/app/workspace/stashes/page_client-reference-manifest.js +1 -0
- package/.next/server/app/workspace/stashes.html +1 -0
- package/.next/server/app/workspace/stashes.meta +16 -0
- package/.next/server/app/workspace/stashes.rsc +26 -0
- package/.next/server/app/workspace/stashes.segments/_full.segment.rsc +26 -0
- package/.next/server/app/workspace/stashes.segments/_head.segment.rsc +6 -0
- package/.next/server/app/workspace/stashes.segments/_index.segment.rsc +8 -0
- package/.next/server/app/workspace/stashes.segments/_tree.segment.rsc +7 -0
- package/.next/server/app/workspace/stashes.segments/workspace/stashes/__PAGE__.segment.rsc +10 -0
- package/.next/server/app/workspace/stashes.segments/workspace/stashes.segment.rsc +4 -0
- package/.next/server/app/workspace/stashes.segments/workspace.segment.rsc +7 -0
- package/.next/server/app/workspace.html +1 -0
- package/.next/server/app/workspace.meta +15 -0
- package/.next/server/app/workspace.rsc +26 -0
- package/.next/server/app/workspace.segments/_full.segment.rsc +26 -0
- package/.next/server/app/workspace.segments/_head.segment.rsc +6 -0
- package/.next/server/app/workspace.segments/_index.segment.rsc +8 -0
- package/.next/server/app/workspace.segments/_tree.segment.rsc +7 -0
- package/.next/server/app/workspace.segments/workspace/__PAGE__.segment.rsc +10 -0
- package/.next/server/app/workspace.segments/workspace.segment.rsc +7 -0
- package/.next/server/app-paths-manifest.json +23 -0
- package/.next/server/chunks/116.js +1 -0
- package/.next/server/chunks/170.js +1 -0
- package/.next/server/chunks/309.js +6 -0
- package/.next/server/chunks/356.js +1 -0
- package/.next/server/chunks/392.js +1 -0
- package/.next/server/chunks/443.js +37 -0
- package/.next/server/chunks/445.js +22 -0
- package/.next/server/chunks/471.js +13 -0
- package/.next/server/chunks/557.js +5 -0
- package/.next/server/chunks/680.js +1 -0
- package/.next/server/chunks/739.js +5 -0
- package/.next/server/chunks/781.js +1 -0
- package/.next/server/chunks/813.js +1 -0
- package/.next/server/chunks/816.js +13 -0
- package/.next/server/functions-config-manifest.json +6 -0
- package/.next/server/interception-route-rewrite-manifest.js +1 -0
- package/.next/server/middleware-build-manifest.js +1 -0
- package/.next/server/middleware-manifest.json +6 -0
- package/.next/server/middleware-react-loadable-manifest.js +1 -0
- package/.next/server/next-font-manifest.js +1 -0
- package/.next/server/next-font-manifest.json +1 -0
- package/.next/server/pages/404.html +1 -0
- package/.next/server/pages/500.html +2 -0
- package/.next/server/pages-manifest.json +4 -0
- package/.next/server/server-reference-manifest.js +1 -0
- package/.next/server/server-reference-manifest.json +1 -0
- package/.next/server/webpack-runtime.js +1 -0
- package/.next/static/VTWJwhFJd5VcC6GP5bbli/_buildManifest.js +1 -0
- package/.next/static/VTWJwhFJd5VcC6GP5bbli/_ssgManifest.js +1 -0
- package/.next/static/chunks/131-6237c77d708182b1.js +1 -0
- package/.next/static/chunks/147-d4cb3e03218d75df.js +6 -0
- package/.next/static/chunks/176-b068120641913226.js +1 -0
- package/.next/static/chunks/200-3664e65687e716a2.js +1 -0
- package/.next/static/chunks/26-d93e82c9c09ff972.js +1 -0
- package/.next/static/chunks/4bd1b696-096d35a2bd1da3af.js +1 -0
- package/.next/static/chunks/500-5d45efbf86b8d36e.js +1 -0
- package/.next/static/chunks/772-b39107b40c31b6b6.js +3 -0
- package/.next/static/chunks/785-e6d755147ff87934.js +1 -0
- package/.next/static/chunks/790-3e8fa6e595d97940.js +6 -0
- package/.next/static/chunks/794-37dad9bbc14b04b8.js +2 -0
- package/.next/static/chunks/841-4d865378216d36eb.js +13 -0
- package/.next/static/chunks/app/_global-error/page-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/app/_not-found/page-5bea07380837254f.js +1 -0
- package/.next/static/chunks/app/api/credentials/route-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/app/api/custom-scripts/route-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/app/api/fs/route-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/app/api/git/action/route-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/app/api/git/branches/route-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/app/api/git/diff/route-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/app/api/git/log/route-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/app/api/git/status/route-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/app/api/repos/route-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/app/api/settings/route-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/app/credentials/page-23c1807ad9f68a40.js +1 -0
- package/.next/static/chunks/app/layout-a06241c385e50ae0.js +1 -0
- package/.next/static/chunks/app/page-c8404790f5191fd7.js +1 -0
- package/.next/static/chunks/app/workspace/changes/page-8cca17f80e66f534.js +3 -0
- package/.next/static/chunks/app/workspace/custom-scripts/page-ee24b9dd7779244f.js +1 -0
- package/.next/static/chunks/app/workspace/history/page-b7017fea285c804c.js +1 -0
- package/.next/static/chunks/app/workspace/layout-cb86c00fdcd8db08.js +1 -0
- package/.next/static/chunks/app/workspace/page-21211acc90c08509.js +1 -0
- package/.next/static/chunks/app/workspace/settings/page-7ccb58ece31492e9.js +1 -0
- package/.next/static/chunks/app/workspace/stashes/page-0e1b8304c4b0f4f3.js +1 -0
- package/.next/static/chunks/framework-75892d61b920805f.js +1 -0
- package/.next/static/chunks/main-app-221e1b945693a142.js +1 -0
- package/.next/static/chunks/main-f1d55fffd3cc9809.js +5 -0
- package/.next/static/chunks/next/dist/client/components/builtin/app-error-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/forbidden-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/global-error-f2a2c324f3740ed8.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/not-found-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-9eb8a19109bbd711.js +1 -0
- package/.next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/.next/static/chunks/webpack-7dec27dc3bfe207a.js +1 -0
- package/.next/static/css/36968b90b2339533.css +1 -0
- package/.next/static/css/c56c0e57397a3a60.css +1 -0
- package/.next/static/css/de70bee13400563f.css +1 -0
- package/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- package/README.md +2 -0
- package/bin/trident-git.mjs +9 -11
- package/{next.config.ts → next.config.mjs} +7 -8
- package/package.json +8 -6
- package/eslint.config.mjs +0 -18
- package/postcss.config.mjs +0 -7
- package/src/app/api/credentials/route.ts +0 -113
- package/src/app/api/custom-scripts/route.ts +0 -203
- package/src/app/api/fs/route.ts +0 -75
- package/src/app/api/git/action/route.ts +0 -383
- package/src/app/api/git/branches/route.ts +0 -20
- package/src/app/api/git/diff/route.ts +0 -104
- package/src/app/api/git/log/route.ts +0 -28
- package/src/app/api/git/status/route.ts +0 -28
- package/src/app/api/repos/route.ts +0 -84
- package/src/app/api/settings/route.ts +0 -37
- package/src/app/credentials/page.tsx +0 -408
- package/src/app/globals.css +0 -109
- package/src/app/layout.tsx +0 -38
- package/src/app/page.tsx +0 -10
- package/src/app/providers.tsx +0 -21
- package/src/app/workspace/changes/page.tsx +0 -27
- package/src/app/workspace/custom-scripts/page.tsx +0 -247
- package/src/app/workspace/history/page.tsx +0 -27
- package/src/app/workspace/layout.tsx +0 -26
- package/src/app/workspace/page.tsx +0 -27
- package/src/app/workspace/settings/page.tsx +0 -233
- package/src/app/workspace/stashes/page.tsx +0 -395
- package/src/components/command-palette.tsx +0 -178
- package/src/components/context-menu.tsx +0 -200
- package/src/components/fs-browser.tsx +0 -154
- package/src/components/git/diff-view.tsx +0 -137
- package/src/components/git/git-graph.tsx +0 -489
- package/src/components/git/grouped-diff-viewer.tsx +0 -332
- package/src/components/git/history-view.tsx +0 -4862
- package/src/components/git/image-diff-view.tsx +0 -342
- package/src/components/git/status-view.tsx +0 -597
- package/src/components/home-settings-modal.tsx +0 -192
- package/src/components/layout/sidebar.tsx +0 -256
- package/src/components/repo-list.tsx +0 -206
- package/src/components/theme-toggle.tsx +0 -37
- package/src/components/toaster.tsx +0 -36
- package/src/components/workspace-repo-open-tracker.tsx +0 -39
- package/src/hooks/use-credentials.ts +0 -123
- package/src/hooks/use-escape-dismiss.ts +0 -72
- package/src/hooks/use-git.ts +0 -448
- package/src/hooks/use-toast.ts +0 -280
- package/src/hooks/use-workspace-title.ts +0 -23
- package/src/lib/api-utils.ts +0 -24
- package/src/lib/branch-colors.ts +0 -98
- package/src/lib/credentials.ts +0 -404
- package/src/lib/git.ts +0 -1510
- package/src/lib/graph-utils.ts +0 -253
- package/src/lib/store.ts +0 -145
- package/src/lib/types.ts +0 -95
- package/src/lib/utils.ts +0 -266
- package/tsconfig.json +0 -34
- /package/{src/app/icon.png → .next/server/app/icon.png.body} +0 -0
|
@@ -1,383 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from 'next/server';
|
|
2
|
-
import { GitService } from '@/lib/git';
|
|
3
|
-
import { getRepositories } from '@/lib/store';
|
|
4
|
-
import { getCredentialById, getCredentialToken, findCredentialForRemote } from '@/lib/credentials';
|
|
5
|
-
import { getImageMimeType, isImageFile } from '@/lib/utils';
|
|
6
|
-
import { handleGitError } from '@/lib/api-utils';
|
|
7
|
-
import { z } from 'zod';
|
|
8
|
-
import fs from 'node:fs';
|
|
9
|
-
|
|
10
|
-
const actionSchema = z.object({
|
|
11
|
-
repoPath: z.string(),
|
|
12
|
-
action: z.enum(['commit', 'push', 'pull', 'stage', 'unstage', 'fetch', 'checkout', 'checkout-to-local', 'branch', 'create-tag', 'delete-branch', 'delete-remote-branch', 'delete-remote', 'delete-tag', 'delete-remote-tag', 'rename-branch', 'rename-remote-branch', 'rename-remote', 'add-remote', 'reset', 'revert', 'cherry-pick', 'cherry-pick-multiple', 'cherry-pick-abort', 'rebase', 'merge', 'check-merge-conflicts', 'check-rebase-conflicts', 'get-remotes', 'get-remote-branches', 'get-tracking-branch', 'get-latest-commit-message', 'push-to-remote', 'pull-from-remote', 'stash', 'stash-list', 'stash-apply', 'stash-drop', 'stash-pop', 'stash-files', 'stash-file-diff', 'reword', 'discard', 'cleanup-lock-file']),
|
|
13
|
-
data: z.any().optional(), // Payload depends on action
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
async function resolveCredentials(repoPath: string, git: GitService, remoteName?: string) {
|
|
17
|
-
const repos = getRepositories();
|
|
18
|
-
const repoConfig = repos.find(r => r.path === repoPath);
|
|
19
|
-
|
|
20
|
-
// 1. Check for explicitly associated credential
|
|
21
|
-
if (repoConfig?.credentialId) {
|
|
22
|
-
const cred = await getCredentialById(repoConfig.credentialId);
|
|
23
|
-
if (cred) {
|
|
24
|
-
const token = await getCredentialToken(cred.id);
|
|
25
|
-
if (token) {
|
|
26
|
-
return { username: cred.username, token };
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// 2. Fallback: try to find matching credential by URL
|
|
32
|
-
if (remoteName) {
|
|
33
|
-
const remoteUrl = await git.getRemoteUrl(remoteName);
|
|
34
|
-
if (remoteUrl) {
|
|
35
|
-
const result = await findCredentialForRemote(remoteUrl);
|
|
36
|
-
if (result) {
|
|
37
|
-
return { username: result.credential.username, token: result.token };
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return undefined;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function toImageSide(buffer: Buffer | null, mimeType: string) {
|
|
46
|
-
if (!buffer) return null;
|
|
47
|
-
return {
|
|
48
|
-
mimeType,
|
|
49
|
-
base64: buffer.toString('base64'),
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export async function POST(request: Request) {
|
|
54
|
-
try {
|
|
55
|
-
const body = await request.json();
|
|
56
|
-
const { repoPath, action, data } = actionSchema.parse(body);
|
|
57
|
-
|
|
58
|
-
// Check if path exists
|
|
59
|
-
if (!fs.existsSync(repoPath)) {
|
|
60
|
-
return NextResponse.json({ error: `Path not found: ${repoPath}` }, { status: 404 });
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const git = new GitService(repoPath);
|
|
64
|
-
|
|
65
|
-
switch (action) {
|
|
66
|
-
case 'commit':
|
|
67
|
-
if (!data?.message) throw new Error('Commit message is required');
|
|
68
|
-
await git.commit(data.message, data.files);
|
|
69
|
-
break;
|
|
70
|
-
case 'push':
|
|
71
|
-
// Try to resolve credentials
|
|
72
|
-
let pushCredentials = await resolveCredentials(repoPath, git, undefined);
|
|
73
|
-
|
|
74
|
-
if (!pushCredentials) {
|
|
75
|
-
// If no associated credential, try to infer from upstream
|
|
76
|
-
try {
|
|
77
|
-
const status = await git.getBranches();
|
|
78
|
-
const current = status.current;
|
|
79
|
-
const tracking = status.trackingInfo[current];
|
|
80
|
-
if (tracking && tracking.upstream) {
|
|
81
|
-
const slashIndex = tracking.upstream.indexOf('/');
|
|
82
|
-
if (slashIndex > 0) {
|
|
83
|
-
const remoteName = tracking.upstream.slice(0, slashIndex);
|
|
84
|
-
pushCredentials = await resolveCredentials(repoPath, git, remoteName);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
} catch (e) {
|
|
88
|
-
// Ignore errors finding upstream, just proceed without creds
|
|
89
|
-
console.warn('[API] Failed to resolve upstream for push credentials:', e);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
await git.push({ credentials: pushCredentials });
|
|
94
|
-
break;
|
|
95
|
-
case 'pull':
|
|
96
|
-
await git.pull();
|
|
97
|
-
break;
|
|
98
|
-
case 'fetch':
|
|
99
|
-
if (data?.allRemotes) {
|
|
100
|
-
await git.fetchAllRemotes();
|
|
101
|
-
} else if (data?.remote) {
|
|
102
|
-
await git.fetchRemote(data.remote);
|
|
103
|
-
} else {
|
|
104
|
-
await git.fetch();
|
|
105
|
-
}
|
|
106
|
-
break;
|
|
107
|
-
case 'stage':
|
|
108
|
-
if (!data?.files) throw new Error('Files are required for staging');
|
|
109
|
-
await git.stage(data.files);
|
|
110
|
-
break;
|
|
111
|
-
case 'unstage':
|
|
112
|
-
if (!data?.files) throw new Error('Files are required for unstaging');
|
|
113
|
-
await git.unstage(data.files);
|
|
114
|
-
break;
|
|
115
|
-
case 'discard':
|
|
116
|
-
await git.discardUnstagedChanges({
|
|
117
|
-
includeUntracked: data?.includeUntracked ?? true,
|
|
118
|
-
});
|
|
119
|
-
break;
|
|
120
|
-
case 'checkout':
|
|
121
|
-
if (!data?.branch) throw new Error('Branch name is required for checkout');
|
|
122
|
-
await git.checkout(data.branch);
|
|
123
|
-
break;
|
|
124
|
-
case 'checkout-to-local':
|
|
125
|
-
if (!data?.remoteBranch) throw new Error('Remote branch is required for checkout-to-local');
|
|
126
|
-
if (!data?.localBranch) throw new Error('Local branch name is required for checkout-to-local');
|
|
127
|
-
await git.checkoutRemoteToLocal(data.remoteBranch, data.localBranch);
|
|
128
|
-
break;
|
|
129
|
-
case 'branch':
|
|
130
|
-
if (!data?.branch) throw new Error('Branch name is required to create branch');
|
|
131
|
-
await git.createBranch(data.branch, data?.fromRef);
|
|
132
|
-
break;
|
|
133
|
-
case 'create-tag':
|
|
134
|
-
if (!data?.tagName) throw new Error('Tag name is required to create tag');
|
|
135
|
-
if (!data?.commitHash) throw new Error('Commit hash is required to create tag');
|
|
136
|
-
if (data?.pushToRemote) {
|
|
137
|
-
let remoteForTag = typeof data?.remote === 'string' && data.remote.trim() ? data.remote.trim() : undefined;
|
|
138
|
-
if (!remoteForTag) {
|
|
139
|
-
const branches = await git.getBranches();
|
|
140
|
-
const current = branches.current;
|
|
141
|
-
const trackingUpstream = current ? branches.trackingInfo?.[current]?.upstream : undefined;
|
|
142
|
-
if (trackingUpstream) {
|
|
143
|
-
const slashIndex = trackingUpstream.indexOf('/');
|
|
144
|
-
if (slashIndex > 0) {
|
|
145
|
-
remoteForTag = trackingUpstream.slice(0, slashIndex);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
if (!remoteForTag) {
|
|
150
|
-
const remotes = await git.getRemotes();
|
|
151
|
-
if (remotes.includes('origin')) {
|
|
152
|
-
remoteForTag = 'origin';
|
|
153
|
-
} else {
|
|
154
|
-
remoteForTag = remotes[0];
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const tagCreds = remoteForTag ? await resolveCredentials(repoPath, git, remoteForTag) : undefined;
|
|
159
|
-
await git.createTag(data.tagName, data.commitHash, {
|
|
160
|
-
pushToRemote: true,
|
|
161
|
-
remote: remoteForTag ?? undefined,
|
|
162
|
-
credentials: tagCreds,
|
|
163
|
-
});
|
|
164
|
-
} else {
|
|
165
|
-
await git.createTag(data.tagName, data.commitHash, { pushToRemote: false });
|
|
166
|
-
}
|
|
167
|
-
break;
|
|
168
|
-
case 'delete-branch':
|
|
169
|
-
if (!data?.branch) throw new Error('Branch name is required to delete branch');
|
|
170
|
-
await git.deleteBranch(data.branch);
|
|
171
|
-
break;
|
|
172
|
-
case 'delete-remote-branch':
|
|
173
|
-
if (!data?.remote) throw new Error('Remote name is required to delete remote branch');
|
|
174
|
-
if (!data?.branch) throw new Error('Branch name is required to delete remote branch');
|
|
175
|
-
|
|
176
|
-
const deleteCreds = await resolveCredentials(repoPath, git, data.remote);
|
|
177
|
-
await git.deleteRemoteBranch(data.remote, data.branch, deleteCreds);
|
|
178
|
-
break;
|
|
179
|
-
case 'delete-remote':
|
|
180
|
-
if (!data?.name) throw new Error('Remote name is required to delete remote');
|
|
181
|
-
await git.deleteRemote(data.name);
|
|
182
|
-
break;
|
|
183
|
-
case 'delete-tag':
|
|
184
|
-
if (!data?.tag) throw new Error('Tag name is required to delete tag');
|
|
185
|
-
await git.deleteTag(data.tag);
|
|
186
|
-
break;
|
|
187
|
-
case 'delete-remote-tag':
|
|
188
|
-
if (!data?.remote) throw new Error('Remote name is required to delete remote tag');
|
|
189
|
-
if (!data?.tag) throw new Error('Tag name is required to delete remote tag');
|
|
190
|
-
|
|
191
|
-
const deleteTagCreds = await resolveCredentials(repoPath, git, data.remote);
|
|
192
|
-
await git.deleteRemoteTag(data.remote, data.tag, deleteTagCreds);
|
|
193
|
-
break;
|
|
194
|
-
case 'rename-branch':
|
|
195
|
-
if (!data?.oldName) throw new Error('Old branch name is required to rename branch');
|
|
196
|
-
if (!data?.newName) throw new Error('New branch name is required to rename branch');
|
|
197
|
-
if (data?.renameTrackingRemote) {
|
|
198
|
-
const tracking = await git.getTrackingBranch(data.oldName);
|
|
199
|
-
const renameTrackingCreds = tracking
|
|
200
|
-
? await resolveCredentials(repoPath, git, tracking.remote)
|
|
201
|
-
: undefined;
|
|
202
|
-
await git.renameBranch(data.oldName, data.newName, {
|
|
203
|
-
renameTrackingRemote: true,
|
|
204
|
-
credentials: renameTrackingCreds,
|
|
205
|
-
});
|
|
206
|
-
} else {
|
|
207
|
-
await git.renameBranch(data.oldName, data.newName);
|
|
208
|
-
}
|
|
209
|
-
break;
|
|
210
|
-
case 'rename-remote-branch':
|
|
211
|
-
if (!data?.remote) throw new Error('Remote name is required to rename remote branch');
|
|
212
|
-
if (!data?.oldName) throw new Error('Old branch name is required to rename remote branch');
|
|
213
|
-
if (!data?.newName) throw new Error('New branch name is required to rename remote branch');
|
|
214
|
-
|
|
215
|
-
const renameCreds = await resolveCredentials(repoPath, git, data.remote);
|
|
216
|
-
await git.renameRemoteBranch(data.remote, data.oldName, data.newName, renameCreds);
|
|
217
|
-
break;
|
|
218
|
-
case 'rename-remote':
|
|
219
|
-
if (!data?.oldName) throw new Error('Old remote name is required to rename remote');
|
|
220
|
-
if (!data?.newName) throw new Error('New remote name is required to rename remote');
|
|
221
|
-
await git.renameRemote(data.oldName, data.newName);
|
|
222
|
-
break;
|
|
223
|
-
case 'add-remote':
|
|
224
|
-
if (!data?.name) throw new Error('Remote name is required to add remote');
|
|
225
|
-
if (!data?.url) throw new Error('Remote URL is required to add remote');
|
|
226
|
-
await git.addRemote(data.name, data.url);
|
|
227
|
-
break;
|
|
228
|
-
case 'reset':
|
|
229
|
-
if (!data?.commitHash) throw new Error('Commit hash is required for reset');
|
|
230
|
-
await git.reset(data.commitHash, data.mode ?? 'hard');
|
|
231
|
-
break;
|
|
232
|
-
case 'revert':
|
|
233
|
-
if (!data?.commitHash) throw new Error('Commit hash is required for revert');
|
|
234
|
-
await git.revert(data.commitHash);
|
|
235
|
-
break;
|
|
236
|
-
case 'cherry-pick':
|
|
237
|
-
if (!data?.commitHash) throw new Error('Commit hash is required for cherry-pick');
|
|
238
|
-
await git.cherryPick(data.commitHash);
|
|
239
|
-
break;
|
|
240
|
-
case 'cherry-pick-multiple':
|
|
241
|
-
if (!Array.isArray(data?.commitHashes) || data.commitHashes.length === 0) {
|
|
242
|
-
throw new Error('Commit hashes are required for multi cherry-pick');
|
|
243
|
-
}
|
|
244
|
-
if (!data.commitHashes.every((hash: unknown) => typeof hash === 'string' && hash.trim().length > 0)) {
|
|
245
|
-
throw new Error('All commit hashes must be non-empty strings');
|
|
246
|
-
}
|
|
247
|
-
await git.cherryPickMultiple(data.commitHashes);
|
|
248
|
-
break;
|
|
249
|
-
case 'cherry-pick-abort':
|
|
250
|
-
await git.abortCherryPick();
|
|
251
|
-
break;
|
|
252
|
-
case 'rebase':
|
|
253
|
-
if (!data?.ontoBranch) throw new Error('Target branch is required for rebase');
|
|
254
|
-
await git.rebase(data.ontoBranch, data.stashChanges ?? true);
|
|
255
|
-
break;
|
|
256
|
-
case 'reword':
|
|
257
|
-
if (!data?.commitHash) throw new Error('Commit hash is required for reword');
|
|
258
|
-
if (!data?.message) throw new Error('New message is required for reword');
|
|
259
|
-
await git.reword(data.commitHash, data.message, data.branch);
|
|
260
|
-
break;
|
|
261
|
-
case 'merge':
|
|
262
|
-
if (!data?.targetBranch) throw new Error('Target branch is required for merge');
|
|
263
|
-
await git.merge(data.targetBranch, {
|
|
264
|
-
rebaseBeforeMerge: data.rebaseBeforeMerge ?? false,
|
|
265
|
-
squash: data.squash ?? false,
|
|
266
|
-
fastForward: data.fastForward ?? false,
|
|
267
|
-
squashMessage: data.squashMessage,
|
|
268
|
-
});
|
|
269
|
-
break;
|
|
270
|
-
case 'check-merge-conflicts':
|
|
271
|
-
if (!data?.sourceBranch) throw new Error('Source branch is required for merge conflict check');
|
|
272
|
-
const hasConflicts = await git.willMergeHaveConflicts(data.sourceBranch, data.targetBranch);
|
|
273
|
-
return NextResponse.json({ success: true, hasConflicts });
|
|
274
|
-
case 'check-rebase-conflicts':
|
|
275
|
-
if (!data?.ontoBranch) throw new Error('Target branch is required for rebase conflict check');
|
|
276
|
-
if (!data?.sourceBranch) throw new Error('Source branch is required for rebase conflict check');
|
|
277
|
-
const hasRebaseConflicts = await git.willRebaseHaveConflicts(data.ontoBranch, data.sourceBranch);
|
|
278
|
-
return NextResponse.json({ success: true, hasConflicts: hasRebaseConflicts });
|
|
279
|
-
case 'get-remotes':
|
|
280
|
-
const remotes = await git.getRemotes();
|
|
281
|
-
return NextResponse.json({ success: true, remotes });
|
|
282
|
-
case 'get-remote-branches':
|
|
283
|
-
if (!data?.remote) throw new Error('Remote name is required');
|
|
284
|
-
const remoteBranches = await git.getRemoteBranches(data.remote);
|
|
285
|
-
return NextResponse.json({ success: true, branches: remoteBranches });
|
|
286
|
-
case 'get-tracking-branch':
|
|
287
|
-
if (!data?.branch) throw new Error('Branch name is required');
|
|
288
|
-
const tracking = await git.getTrackingBranch(data.branch);
|
|
289
|
-
return NextResponse.json({ success: true, tracking });
|
|
290
|
-
case 'get-latest-commit-message':
|
|
291
|
-
if (!data?.branch) throw new Error('Branch name is required');
|
|
292
|
-
const message = await git.getLatestCommitMessage(data.branch);
|
|
293
|
-
return NextResponse.json({ success: true, message });
|
|
294
|
-
case 'push-to-remote':
|
|
295
|
-
console.log('[API] push-to-remote action received:', data);
|
|
296
|
-
if (!data?.localBranch) throw new Error('Local branch is required');
|
|
297
|
-
if (!data?.remote) throw new Error('Remote is required');
|
|
298
|
-
if (!data?.remoteBranch) throw new Error('Remote branch is required');
|
|
299
|
-
|
|
300
|
-
const creds = await resolveCredentials(repoPath, git, data.remote);
|
|
301
|
-
|
|
302
|
-
console.log('[API] Calling git.pushToRemote...');
|
|
303
|
-
await git.pushToRemote(data.localBranch, data.remote, data.remoteBranch, {
|
|
304
|
-
rebaseFirst: data.rebaseFirst ?? !(data.forcePush ?? false),
|
|
305
|
-
forcePush: data.forcePush ?? false,
|
|
306
|
-
pushLocalOnlyTags: data.pushLocalOnlyTags ?? true,
|
|
307
|
-
setUpstream: data.setUpstream ?? false,
|
|
308
|
-
squash: data.squash ?? false,
|
|
309
|
-
squashMessage: data.squashMessage,
|
|
310
|
-
credentials: creds,
|
|
311
|
-
});
|
|
312
|
-
console.log('[API] git.pushToRemote completed');
|
|
313
|
-
break;
|
|
314
|
-
case 'pull-from-remote':
|
|
315
|
-
console.log('[API] pull-from-remote action received:', data);
|
|
316
|
-
if (!data?.localBranch) throw new Error('Local branch is required');
|
|
317
|
-
if (!data?.remote) throw new Error('Remote is required');
|
|
318
|
-
if (!data?.remoteBranch) throw new Error('Remote branch is required');
|
|
319
|
-
console.log('[API] Calling git.pullFromRemote...');
|
|
320
|
-
await git.pullFromRemote(data.localBranch, data.remote, data.remoteBranch, {
|
|
321
|
-
rebase: data.rebase ?? true,
|
|
322
|
-
});
|
|
323
|
-
console.log('[API] git.pullFromRemote completed');
|
|
324
|
-
break;
|
|
325
|
-
case 'stash':
|
|
326
|
-
await git.stash(data?.message);
|
|
327
|
-
break;
|
|
328
|
-
case 'stash-list':
|
|
329
|
-
const stashes = await git.getStashes();
|
|
330
|
-
return NextResponse.json({ success: true, stashes });
|
|
331
|
-
case 'stash-apply':
|
|
332
|
-
if (data?.index === undefined) throw new Error('Stash index is required');
|
|
333
|
-
await git.applyStash(data.index);
|
|
334
|
-
break;
|
|
335
|
-
case 'stash-drop':
|
|
336
|
-
if (data?.index === undefined) throw new Error('Stash index is required');
|
|
337
|
-
await git.dropStash(data.index);
|
|
338
|
-
break;
|
|
339
|
-
case 'stash-pop':
|
|
340
|
-
if (data?.index === undefined) throw new Error('Stash index is required');
|
|
341
|
-
await git.popStash(data.index);
|
|
342
|
-
break;
|
|
343
|
-
case 'stash-files':
|
|
344
|
-
if (data?.index === undefined) throw new Error('Stash index is required');
|
|
345
|
-
const stashFiles = await git.getStashFiles(data.index);
|
|
346
|
-
return NextResponse.json({ success: true, files: stashFiles });
|
|
347
|
-
case 'stash-file-diff':
|
|
348
|
-
if (data?.index === undefined) throw new Error('Stash index is required');
|
|
349
|
-
if (!data?.file) throw new Error('File path is required');
|
|
350
|
-
if (isImageFile(data.file)) {
|
|
351
|
-
const mimeType = getImageMimeType(data.file);
|
|
352
|
-
const [leftBuffer, rightBuffer, diff] = await Promise.all([
|
|
353
|
-
git.getFileContentBuffer(data.file, `stash@{${data.index}}^1`),
|
|
354
|
-
git.getFileContentBuffer(data.file, `stash@{${data.index}}`),
|
|
355
|
-
git.getStashFilePatch(data.index, data.file),
|
|
356
|
-
]);
|
|
357
|
-
|
|
358
|
-
return NextResponse.json({
|
|
359
|
-
success: true,
|
|
360
|
-
left: '',
|
|
361
|
-
right: '',
|
|
362
|
-
diff,
|
|
363
|
-
imageDiff: {
|
|
364
|
-
left: toImageSide(leftBuffer, mimeType),
|
|
365
|
-
right: toImageSide(rightBuffer, mimeType),
|
|
366
|
-
},
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
const stashFileDiff = await git.getStashFileDiff(data.index, data.file);
|
|
371
|
-
return NextResponse.json({ success: true, ...stashFileDiff });
|
|
372
|
-
case 'cleanup-lock-file':
|
|
373
|
-
const cleaned = await git.cleanupLockFile();
|
|
374
|
-
return NextResponse.json({ success: true, cleaned });
|
|
375
|
-
default:
|
|
376
|
-
return NextResponse.json({ error: 'Invalid action' }, { status: 400 });
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
return NextResponse.json({ success: true });
|
|
380
|
-
} catch (error) {
|
|
381
|
-
return handleGitError(error);
|
|
382
|
-
}
|
|
383
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from 'next/server';
|
|
2
|
-
import { GitService } from '@/lib/git';
|
|
3
|
-
import { handleGitError } from '@/lib/api-utils';
|
|
4
|
-
|
|
5
|
-
export async function GET(req: Request) {
|
|
6
|
-
const { searchParams } = new URL(req.url);
|
|
7
|
-
const path = searchParams.get('path');
|
|
8
|
-
|
|
9
|
-
if (!path) {
|
|
10
|
-
return NextResponse.json({ error: 'Path is required' }, { status: 400 });
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
try {
|
|
14
|
-
const git = new GitService(path);
|
|
15
|
-
const branches = await git.getBranches();
|
|
16
|
-
return NextResponse.json(branches);
|
|
17
|
-
} catch (err) {
|
|
18
|
-
return handleGitError(err);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from 'next/server';
|
|
2
|
-
import { GitService } from '@/lib/git';
|
|
3
|
-
import { getImageMimeType, isImageFile } from '@/lib/utils';
|
|
4
|
-
import { handleGitError } from '@/lib/api-utils';
|
|
5
|
-
import fs from 'node:fs';
|
|
6
|
-
import pathLib from 'path';
|
|
7
|
-
|
|
8
|
-
function toImageSide(buffer: Buffer | null, mimeType: string) {
|
|
9
|
-
if (!buffer) return null;
|
|
10
|
-
return {
|
|
11
|
-
mimeType,
|
|
12
|
-
base64: buffer.toString('base64'),
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export async function GET(request: Request) {
|
|
17
|
-
const { searchParams } = new URL(request.url);
|
|
18
|
-
const repoPath = searchParams.get('path');
|
|
19
|
-
const filePath = searchParams.get('file');
|
|
20
|
-
const commitHash = searchParams.get('commit');
|
|
21
|
-
|
|
22
|
-
if (!repoPath) {
|
|
23
|
-
return NextResponse.json({ error: 'Repo path is required' }, { status: 400 });
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Check if path exists
|
|
27
|
-
if (!fs.existsSync(repoPath)) {
|
|
28
|
-
return NextResponse.json({ error: `Path not found: ${repoPath}` }, { status: 404 });
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
const git = new GitService(repoPath);
|
|
33
|
-
|
|
34
|
-
// If commit hash is provided, get commit diff
|
|
35
|
-
if (commitHash) {
|
|
36
|
-
// If file path is also provided, get diff for that specific file in the commit
|
|
37
|
-
if (filePath) {
|
|
38
|
-
if (isImageFile(filePath)) {
|
|
39
|
-
const mimeType = getImageMimeType(filePath);
|
|
40
|
-
const [beforeBuffer, afterBuffer, diff] = await Promise.all([
|
|
41
|
-
git.getFileContentBuffer(filePath, `${commitHash}^`),
|
|
42
|
-
git.getFileContentBuffer(filePath, commitHash),
|
|
43
|
-
git.getCommitFilePatch(commitHash, filePath),
|
|
44
|
-
]);
|
|
45
|
-
|
|
46
|
-
return NextResponse.json({
|
|
47
|
-
left: '',
|
|
48
|
-
right: '',
|
|
49
|
-
diff,
|
|
50
|
-
imageDiff: {
|
|
51
|
-
left: toImageSide(beforeBuffer, mimeType),
|
|
52
|
-
right: toImageSide(afterBuffer, mimeType),
|
|
53
|
-
},
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const { before, after, diff } = await git.getCommitFileDiff(commitHash, filePath);
|
|
58
|
-
return NextResponse.json({ left: before, right: after, diff });
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Otherwise, get the list of files changed in the commit
|
|
62
|
-
const { files, diff } = await git.getCommitDiff(commitHash);
|
|
63
|
-
return NextResponse.json({ files, diff });
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Original behavior: diff against working directory
|
|
67
|
-
if (!filePath) {
|
|
68
|
-
return NextResponse.json({ error: 'File path is required' }, { status: 400 });
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const diff = await git.getDiff(filePath);
|
|
72
|
-
|
|
73
|
-
if (isImageFile(filePath)) {
|
|
74
|
-
const mimeType = getImageMimeType(filePath);
|
|
75
|
-
const fullPath = pathLib.join(repoPath, filePath);
|
|
76
|
-
const [leftBuffer, rightBuffer] = await Promise.all([
|
|
77
|
-
git.getFileContentBuffer(filePath, 'HEAD'),
|
|
78
|
-
fs.existsSync(fullPath) ? fs.promises.readFile(fullPath) : Promise.resolve(null),
|
|
79
|
-
]);
|
|
80
|
-
|
|
81
|
-
return NextResponse.json({
|
|
82
|
-
diff,
|
|
83
|
-
left: '',
|
|
84
|
-
right: '',
|
|
85
|
-
imageDiff: {
|
|
86
|
-
left: toImageSide(leftBuffer, mimeType),
|
|
87
|
-
right: toImageSide(rightBuffer, mimeType),
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Get content for Diff Viewer
|
|
93
|
-
const left = await git.getFileContent(filePath, 'HEAD');
|
|
94
|
-
let right = '';
|
|
95
|
-
const fullPath = pathLib.join(repoPath, filePath);
|
|
96
|
-
if (fs.existsSync(fullPath)) {
|
|
97
|
-
right = await fs.promises.readFile(fullPath, 'utf-8');
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return NextResponse.json({ diff, left, right });
|
|
101
|
-
} catch (error) {
|
|
102
|
-
return handleGitError(error);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { NextResponse } from 'next/server';
|
|
3
|
-
import { GitService } from '@/lib/git';
|
|
4
|
-
import { handleGitError } from '@/lib/api-utils';
|
|
5
|
-
import fs from 'node:fs';
|
|
6
|
-
|
|
7
|
-
export async function GET(request: Request) {
|
|
8
|
-
const { searchParams } = new URL(request.url);
|
|
9
|
-
const path = searchParams.get('path');
|
|
10
|
-
const limit = searchParams.get('limit');
|
|
11
|
-
|
|
12
|
-
if (!path) {
|
|
13
|
-
return NextResponse.json({ error: 'Repo path is required' }, { status: 400 });
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// Check if path exists
|
|
17
|
-
if (!fs.existsSync(path)) {
|
|
18
|
-
return NextResponse.json({ error: `Path not found: ${path}` }, { status: 404 });
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
const git = new GitService(path);
|
|
23
|
-
const log = await git.getLog(limit ? parseInt(limit) : 50);
|
|
24
|
-
return NextResponse.json(log);
|
|
25
|
-
} catch (error) {
|
|
26
|
-
return handleGitError(error);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { NextResponse } from 'next/server';
|
|
2
|
-
import { GitService } from '@/lib/git';
|
|
3
|
-
import { handleGitError } from '@/lib/api-utils';
|
|
4
|
-
import fs from 'node:fs/promises';
|
|
5
|
-
|
|
6
|
-
export async function GET(request: Request) {
|
|
7
|
-
const { searchParams } = new URL(request.url);
|
|
8
|
-
const path = searchParams.get('path');
|
|
9
|
-
|
|
10
|
-
if (!path) {
|
|
11
|
-
return NextResponse.json({ error: 'Repo path is required' }, { status: 400 });
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
// Check if path exists
|
|
15
|
-
try {
|
|
16
|
-
await fs.access(path);
|
|
17
|
-
} catch {
|
|
18
|
-
return NextResponse.json({ error: `Path not found: ${path}` }, { status: 404 });
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
const git = new GitService(path);
|
|
23
|
-
const status = await git.getStatus();
|
|
24
|
-
return NextResponse.json(status);
|
|
25
|
-
} catch (error) {
|
|
26
|
-
return handleGitError(error);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { NextResponse } from 'next/server';
|
|
3
|
-
import { getRepositories, addRepository, updateRepository, removeRepository } from '@/lib/store';
|
|
4
|
-
import { z } from 'zod';
|
|
5
|
-
|
|
6
|
-
const customScriptSchema = z.object({
|
|
7
|
-
id: z.string().min(1),
|
|
8
|
-
name: z.string().min(1),
|
|
9
|
-
target: z.literal('branch'),
|
|
10
|
-
action: z.literal('run-bash-script'),
|
|
11
|
-
content: z.string(),
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
export async function GET() {
|
|
15
|
-
const repos = getRepositories();
|
|
16
|
-
return NextResponse.json(repos);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const addRepoSchema = z.object({
|
|
20
|
-
path: z.string().min(1),
|
|
21
|
-
name: z.string().optional(),
|
|
22
|
-
displayName: z.string().nullable().optional(),
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
const updateRepoSchema = z.object({
|
|
26
|
-
path: z.string().min(1),
|
|
27
|
-
updates: z.object({
|
|
28
|
-
name: z.string().optional(),
|
|
29
|
-
displayName: z.string().nullable().optional(),
|
|
30
|
-
lastOpenedAt: z.string().optional(),
|
|
31
|
-
credentialId: z.string().optional().nullable(),
|
|
32
|
-
customScripts: z.array(customScriptSchema).optional(),
|
|
33
|
-
expandedFolders: z.array(z.string()).optional(),
|
|
34
|
-
visibilityMap: z.record(z.string(), z.enum(['visible', 'hidden'])).optional(),
|
|
35
|
-
localGroupExpanded: z.boolean().optional(),
|
|
36
|
-
remotesGroupExpanded: z.boolean().optional(),
|
|
37
|
-
}),
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
export async function POST(request: Request) {
|
|
41
|
-
try {
|
|
42
|
-
const body = await request.json();
|
|
43
|
-
const { path, name, displayName } = addRepoSchema.parse(body);
|
|
44
|
-
const repo = addRepository(path, name, displayName);
|
|
45
|
-
return NextResponse.json(repo);
|
|
46
|
-
} catch (error) {
|
|
47
|
-
if (error instanceof z.ZodError) {
|
|
48
|
-
return NextResponse.json({ error: error.issues }, { status: 400 });
|
|
49
|
-
}
|
|
50
|
-
return NextResponse.json({ error: (error as Error).message }, { status: 500 });
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export async function PUT(request: Request) {
|
|
55
|
-
try {
|
|
56
|
-
const body = await request.json();
|
|
57
|
-
const { path, updates } = updateRepoSchema.parse(body);
|
|
58
|
-
const repo = updateRepository(path, updates);
|
|
59
|
-
return NextResponse.json(repo);
|
|
60
|
-
} catch (error) {
|
|
61
|
-
if (error instanceof z.ZodError) {
|
|
62
|
-
return NextResponse.json({ error: error.issues }, { status: 400 });
|
|
63
|
-
}
|
|
64
|
-
return NextResponse.json({ error: (error as Error).message }, { status: 500 });
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const deleteRepoSchema = z.object({
|
|
69
|
-
path: z.string().min(1),
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
export async function DELETE(request: Request) {
|
|
73
|
-
try {
|
|
74
|
-
const body = await request.json();
|
|
75
|
-
const { path } = deleteRepoSchema.parse(body);
|
|
76
|
-
removeRepository(path);
|
|
77
|
-
return NextResponse.json({ success: true });
|
|
78
|
-
} catch (error) {
|
|
79
|
-
if (error instanceof z.ZodError) {
|
|
80
|
-
return NextResponse.json({ error: error.issues }, { status: 400 });
|
|
81
|
-
}
|
|
82
|
-
return NextResponse.json({ error: (error as Error).message }, { status: 500 });
|
|
83
|
-
}
|
|
84
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
import { NextResponse } from 'next/server';
|
|
3
|
-
import { getSettings, updateSettings, getDefaultRootFolder } from '@/lib/store';
|
|
4
|
-
import { z } from 'zod';
|
|
5
|
-
|
|
6
|
-
export async function GET() {
|
|
7
|
-
const settings = getSettings();
|
|
8
|
-
const resolvedDefaultFolder = getDefaultRootFolder();
|
|
9
|
-
return NextResponse.json({
|
|
10
|
-
...settings,
|
|
11
|
-
resolvedDefaultFolder, // The actual folder that will be used (after fallback logic)
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const updateSettingsSchema = z.object({
|
|
16
|
-
defaultRootFolder: z.string().nullable().optional(),
|
|
17
|
-
sidebarCollapsed: z.boolean().optional(),
|
|
18
|
-
historyPanelHeight: z.number().optional(),
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
export async function PUT(request: Request) {
|
|
22
|
-
try {
|
|
23
|
-
const body = await request.json();
|
|
24
|
-
const updates = updateSettingsSchema.parse(body);
|
|
25
|
-
const settings = updateSettings(updates);
|
|
26
|
-
const resolvedDefaultFolder = getDefaultRootFolder();
|
|
27
|
-
return NextResponse.json({
|
|
28
|
-
...settings,
|
|
29
|
-
resolvedDefaultFolder,
|
|
30
|
-
});
|
|
31
|
-
} catch (error) {
|
|
32
|
-
if (error instanceof z.ZodError) {
|
|
33
|
-
return NextResponse.json({ error: error.issues }, { status: 400 });
|
|
34
|
-
}
|
|
35
|
-
return NextResponse.json({ error: (error as Error).message }, { status: 500 });
|
|
36
|
-
}
|
|
37
|
-
}
|