spiracha 1.2.0 → 1.3.0
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/AGENTS.md +49 -12
- package/README.md +117 -64
- package/apps/ui/AGENTS.md +16 -8
- package/apps/ui/README.md +28 -12
- package/apps/ui/dist/client/assets/{analytics-Cv0JMDN2.js → analytics-B_hYz65v.js} +1 -1
- package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-qiyygB7e.js +1 -0
- package/apps/ui/dist/client/assets/antigravity-conversations._conversationId-z1SQC2Kg.js +1 -0
- package/apps/ui/dist/client/assets/antigravity-keychain-panel-dYuRWtCf.js +1 -0
- package/apps/ui/dist/client/assets/antigravity._workspaceKey-CliqUr7o.js +1 -0
- package/apps/ui/dist/client/assets/antigravity._workspaceKey-CnoBzyX6.js +1 -0
- package/apps/ui/dist/client/assets/antigravity.index-CakfZz_E.js +1 -0
- package/apps/ui/dist/client/assets/antigravity.index-DY7M1KhG.js +1 -0
- package/apps/ui/dist/client/assets/badge-aHE9ETVe.js +1 -0
- package/apps/ui/dist/client/assets/checkbox-DN3XnJaA.js +1 -0
- package/apps/ui/dist/client/assets/cursor-threads._composerId-BMQyx8qG.js +1 -0
- package/apps/ui/dist/client/assets/cursor-threads._composerId-BTlaA-tV.js +1 -0
- package/apps/ui/dist/client/assets/cursor._workspaceKey-CrgrfevV.js +1 -0
- package/apps/ui/dist/client/assets/cursor._workspaceKey-bYS2syGL.js +1 -0
- package/apps/ui/dist/client/assets/cursor.index-CTqZMPYU.js +1 -0
- package/apps/ui/dist/client/assets/cursor.index-Clsz4E_e.js +2 -0
- package/apps/ui/dist/client/assets/{data-table-Bgnh7phF.js → data-table-Cj-v-uyB.js} +2 -2
- package/apps/ui/dist/client/assets/delete-confirm-dialog-DTpzBiNK.js +11 -0
- package/apps/ui/dist/client/assets/dist-BNAn99Pu.js +1 -0
- package/apps/ui/dist/client/assets/download-P3Rp23Ad.js +1 -0
- package/apps/ui/dist/client/assets/dropdown-menu-3qB5j9nt.js +1 -0
- package/apps/ui/dist/client/assets/es2015-Dwm_turD.js +41 -0
- package/apps/ui/dist/client/assets/export-dialog-CazdrASq.js +1 -0
- package/apps/ui/dist/client/assets/formatters-BdnWuM1z.js +1 -0
- package/apps/ui/dist/client/assets/index-BVFnfS78.js +22 -0
- package/apps/ui/dist/client/assets/json-panel-DLkS30sQ.js +1 -0
- package/apps/ui/dist/client/assets/metadata-section-jnIkB7dB.js +1 -0
- package/apps/ui/dist/client/assets/{metric-card-BJX5rkHK.js → metric-card-CBZuWLzQ.js} +1 -1
- package/apps/ui/dist/client/assets/page-header-CnD21cPn.js +1 -0
- package/apps/ui/dist/client/assets/projects._project-BLszwvYL.js +1 -0
- package/apps/ui/dist/client/assets/projects._project-DvLxYbvk.js +1 -0
- package/apps/ui/dist/client/assets/projects.index-COn8woBR.js +1 -0
- package/apps/ui/dist/client/assets/projects.index-DYs98skV.js +3 -0
- package/apps/ui/dist/client/assets/refresh-ccw-BDrYXjtD.js +1 -0
- package/apps/ui/dist/client/assets/reload-error-panel-DLAg0AW2.js +1 -0
- package/apps/ui/dist/client/assets/routes-BtF5-coe.js +1 -0
- package/apps/ui/dist/client/assets/scroll-text-CqaFm9by.js +1 -0
- package/apps/ui/dist/client/assets/select-DbnpwqL6.js +1 -0
- package/apps/ui/dist/client/assets/settings-CGX3VleN.js +1 -0
- package/apps/ui/dist/client/assets/styles-Ch0r3kMZ.css +1 -0
- package/apps/ui/dist/client/assets/text-document-panel-DPleOmmq.js +1 -0
- package/apps/ui/dist/client/assets/text-filter-7M6wRo-t.js +2 -0
- package/apps/ui/dist/client/assets/threads._threadId-D5w76IB-.js +7 -0
- package/apps/ui/dist/client/assets/{threads._threadId-CUiCZSwo.js → threads._threadId-Dx85sI9P.js} +1 -1
- package/apps/ui/dist/client/assets/useMutation-MZ3Hr9h9.js +1 -0
- package/apps/ui/dist/client/assets/useQuery-Cb4V0AT0.js +1 -0
- package/apps/ui/dist/client/icon.svg +28 -0
- package/apps/ui/dist/client/manifest.json +6 -16
- package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-CBbkUXw6.js +227 -0
- package/apps/ui/dist/server/assets/{analytics-2QpLKjlG.js → analytics-CBNOYZwJ.js} +2 -2
- package/apps/ui/dist/server/assets/antigravity-conversation-state-HgzS302O.js +16 -0
- package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-B9Rm4EXh.js +212 -0
- package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-BIdYNy68.js +20 -0
- package/apps/ui/dist/server/assets/antigravity-conversations._conversationId-D426O-64.js +11 -0
- package/apps/ui/dist/server/assets/antigravity-db-D9gW1D8G.js +576 -0
- package/apps/ui/dist/server/assets/antigravity-keychain-DOiuHDwK.js +126 -0
- package/apps/ui/dist/server/assets/antigravity-keychain-panel-DcLyBBwd.js +55 -0
- package/apps/ui/dist/server/assets/antigravity-queries-CgQhlQ7J.js +37 -0
- package/apps/ui/dist/server/assets/antigravity-server-DFUx4Khk.js +114 -0
- package/apps/ui/dist/server/assets/antigravity._workspaceKey-3m_MzNFA.js +11 -0
- package/apps/ui/dist/server/assets/antigravity._workspaceKey-D42ixtzp.js +210 -0
- package/apps/ui/dist/server/assets/antigravity._workspaceKey-DnSlSC-C.js +28 -0
- package/apps/ui/dist/server/assets/antigravity.index-DZVT-cac.js +104 -0
- package/apps/ui/dist/server/assets/antigravity.index-DudTB3Tq.js +11 -0
- package/apps/ui/dist/server/assets/badge-EvdhKK_Z.js +26 -0
- package/apps/ui/dist/server/assets/{codex-queries-BH4Cb0v3.js → codex-queries-eOJGfHQj.js} +4 -16
- package/apps/ui/dist/server/assets/{codex-server-DqzruLmg.js → codex-server-nrETIF--.js} +149 -140
- package/apps/ui/dist/server/assets/createServerRpc-BtXIw2iP.js +12 -0
- package/apps/ui/dist/server/assets/createSsrRpc-COf5Zuye.js +16 -0
- package/apps/ui/dist/server/assets/cursor-db-B7agkAvM.js +643 -0
- package/apps/ui/dist/server/assets/cursor-exporter-types-CI3goo-c.js +34 -0
- package/apps/ui/dist/server/assets/cursor-queries-BMhuJeUO.js +65 -0
- package/apps/ui/dist/server/assets/cursor-recovery-9bJLs7vG.js +361 -0
- package/apps/ui/dist/server/assets/cursor-server-BgylIFgn.js +184 -0
- package/apps/ui/dist/server/assets/cursor-threads._composerId-BB0Y_Mao.js +11 -0
- package/apps/ui/dist/server/assets/cursor-threads._composerId-BsxFKzoJ.js +218 -0
- package/apps/ui/dist/server/assets/cursor-threads._composerId-DXffY_CK.js +18 -0
- package/apps/ui/dist/server/assets/cursor-transcript-2iL3KFSK.js +125 -0
- package/apps/ui/dist/server/assets/cursor._workspaceKey-BP2J1x_x.js +28 -0
- package/apps/ui/dist/server/assets/cursor._workspaceKey-BQd0e-Pd.js +399 -0
- package/apps/ui/dist/server/assets/cursor._workspaceKey-nmg3YIOQ.js +11 -0
- package/apps/ui/dist/server/assets/cursor.index-CQVxtCm8.js +189 -0
- package/apps/ui/dist/server/assets/cursor.index-CcsX7DG0.js +11 -0
- package/apps/ui/dist/server/assets/{delete-confirm-dialog-CWqcTXTF.js → delete-confirm-dialog-PCD7S0_M.js} +5 -4
- package/apps/ui/dist/server/assets/download-DMmiy1xf.js +92 -0
- package/apps/ui/dist/server/assets/{input-B4tEzctc.js → dropdown-menu-Dy_9t6TN.js} +1 -11
- package/apps/ui/dist/server/assets/{download-Drctxary.js → export-dialog-DaPlOGFT.js} +1 -92
- package/apps/ui/dist/server/assets/json-panel-RYsxWFae.js +16 -0
- package/apps/ui/dist/server/assets/{loading-panel-DbLdvjtR.js → loading-panel-BGFnWseS.js} +1 -1
- package/apps/ui/dist/server/assets/metadata-section-D6Lbc7D6.js +54 -0
- package/apps/ui/dist/server/assets/page-header-VNSaM3xd.js +29 -0
- package/apps/ui/dist/server/assets/projects._project-Bshqk7JA.js +12 -0
- package/apps/ui/dist/server/assets/{projects._project-gT01HBqH.js → projects._project-DUN3iWfg.js} +4 -4
- package/apps/ui/dist/server/assets/{projects._project-DreIU5b0.js → projects._project-Dim9Y0kD.js} +54 -26
- package/apps/ui/dist/server/assets/projects.index-BLXOx5eL.js +12 -0
- package/apps/ui/dist/server/assets/{projects.index-BYmgSGAj.js → projects.index-DjSQK5dm.js} +23 -27
- package/apps/ui/dist/server/assets/{projects.index-CaplpeMy.js → reload-error-panel-BJMxY3U1.js} +5 -6
- package/apps/ui/dist/server/assets/{router-Qj5Kn7bl.js → router-DrDgc-LD.js} +131 -44
- package/apps/ui/dist/server/assets/{routes-_LbCIjtJ.js → routes-B-GlEe2C.js} +54 -39
- package/apps/ui/dist/server/assets/{routes-BtcXuK0x.js → routes-CNHAUMwo.js} +2 -2
- package/apps/ui/dist/server/assets/{settings-MvWDgc1u.js → settings-OayxIYQQ.js} +1 -1
- package/apps/ui/dist/server/assets/shared-CPRNYIql.js +134 -0
- package/apps/ui/dist/server/assets/text-document-panel-D8JbQWAn.js +23 -0
- package/apps/ui/dist/server/assets/text-filter-CGKxMCKt.js +36 -0
- package/apps/ui/dist/server/assets/{threads._threadId-DcbAJkwf.js → threads._threadId-CJzm4KrZ.js} +3 -3
- package/apps/ui/dist/server/assets/{threads._threadId-D5m6ypGw.js → threads._threadId-DODTYddm.js} +69 -76
- package/apps/ui/dist/server/server.js +77 -13
- package/package.json +19 -9
- package/src/export-cursor.ts +244 -0
- package/src/lib/antigravity-db.ts +936 -0
- package/src/lib/antigravity-exporter-types.ts +70 -0
- package/src/lib/antigravity-keychain.ts +203 -0
- package/src/lib/codex-browser-db.ts +7 -1
- package/src/lib/codex-browser-types.ts +22 -1
- package/src/lib/codex-thread-recovery.ts +202 -0
- package/src/lib/cursor-db.ts +1096 -0
- package/src/lib/cursor-exporter-types.ts +190 -0
- package/src/lib/cursor-exporter.ts +266 -0
- package/src/lib/cursor-recovery.ts +543 -0
- package/src/lib/cursor-transcript.ts +183 -0
- package/src/spiracha.ts +16 -3
- package/src/ui-cli.ts +2 -2
- package/apps/ui/dist/client/assets/checkbox-DjHij7DJ.js +0 -1
- package/apps/ui/dist/client/assets/delete-confirm-dialog-CIZy_LXD.js +0 -11
- package/apps/ui/dist/client/assets/download-DQtfva4z.js +0 -1
- package/apps/ui/dist/client/assets/es2015-DsDKdYCE.js +0 -41
- package/apps/ui/dist/client/assets/formatters-CWFrMKSn.js +0 -1
- package/apps/ui/dist/client/assets/index-C_-e0lDI.js +0 -22
- package/apps/ui/dist/client/assets/input-BbgApiqZ.js +0 -1
- package/apps/ui/dist/client/assets/page-header-ODLuGLAB.js +0 -1
- package/apps/ui/dist/client/assets/projects._project-C2Pys_bB.js +0 -1
- package/apps/ui/dist/client/assets/projects._project-CHvAKvlu.js +0 -1
- package/apps/ui/dist/client/assets/projects.index-BmwtS1x-.js +0 -1
- package/apps/ui/dist/client/assets/projects.index-CuLw73mt.js +0 -1
- package/apps/ui/dist/client/assets/routes-CfnaTOlj.js +0 -1
- package/apps/ui/dist/client/assets/select-B1kH_5lx.js +0 -1
- package/apps/ui/dist/client/assets/settings-mYTB3sso.js +0 -1
- package/apps/ui/dist/client/assets/styles-CMrP9Jb4.css +0 -1
- package/apps/ui/dist/client/assets/threads._threadId-C_47okme.js +0 -7
- package/apps/ui/dist/client/favicon.ico +0 -0
- package/apps/ui/dist/client/logo192.png +0 -0
- package/apps/ui/dist/client/logo512.png +0 -0
- package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-kj_QB_26.js +0 -99
- package/apps/ui/dist/server/assets/page-header-CxdZM86z.js +0 -25
- package/apps/ui/dist/server/assets/projects._project-CLSohrBp.js +0 -26
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
import { t as Button } from "./button-CmTDnzOn.js";
|
|
2
|
+
import { a as deleteCursorWorkspaceFn, c as recoverCursorWorkspaceFn, i as deleteCursorThreadsFn, n as cursorThreadsQueryOptions, o as exportCursorThreadFn, r as cursorWorkspacesQueryOptions, s as exportCursorThreadsFn } from "./cursor-queries-BMhuJeUO.js";
|
|
3
|
+
import { n as findWorkspaceOrThrow, t as Route } from "./cursor._workspaceKey-BP2J1x_x.js";
|
|
4
|
+
import { t as DataTable } from "./data-table-Cdct823O.js";
|
|
5
|
+
import { t as PageHeader } from "./page-header-VNSaM3xd.js";
|
|
6
|
+
import { n as formatBytes, o as formatNumber, r as formatDateTime } from "./formatters-FJaGZgJk.js";
|
|
7
|
+
import { t as downloadTextFile } from "./download-DMmiy1xf.js";
|
|
8
|
+
import { i as DropdownMenuTrigger, n as DropdownMenuContent, r as DropdownMenuItem, t as DropdownMenu } from "./dropdown-menu-Dy_9t6TN.js";
|
|
9
|
+
import { n as ListSearchInput, t as matchesTextQuery } from "./text-filter-CGKxMCKt.js";
|
|
10
|
+
import { t as DeleteConfirmDialog } from "./delete-confirm-dialog-PCD7S0_M.js";
|
|
11
|
+
import { t as ExportDialog } from "./export-dialog-DaPlOGFT.js";
|
|
12
|
+
import { useDeferredValue, useMemo, useState } from "react";
|
|
13
|
+
import { Link, useNavigate } from "@tanstack/react-router";
|
|
14
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
15
|
+
import { useMutation, useQueryClient, useSuspenseQuery } from "@tanstack/react-query";
|
|
16
|
+
import { Download, MoreHorizontal, RefreshCcw, Trash2, X } from "lucide-react";
|
|
17
|
+
import { createColumnHelper } from "@tanstack/react-table";
|
|
18
|
+
//#region src/components/cursor-threads-table.tsx
|
|
19
|
+
var columnHelper = createColumnHelper();
|
|
20
|
+
var defaultSorting = [{
|
|
21
|
+
desc: true,
|
|
22
|
+
id: "updatedAt"
|
|
23
|
+
}];
|
|
24
|
+
var columns = (onDeleteThread, onExportThread) => [
|
|
25
|
+
columnHelper.accessor("name", {
|
|
26
|
+
cell: (info) => /* @__PURE__ */ jsxs(Link, {
|
|
27
|
+
className: "block w-[16rem] max-w-[20rem] space-y-1 rounded-md outline-none transition hover:opacity-80 focus-visible:ring-2 focus-visible:ring-[var(--accent)] lg:w-auto",
|
|
28
|
+
params: { composerId: info.row.original.composerId },
|
|
29
|
+
to: "/cursor-threads/$composerId",
|
|
30
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
31
|
+
className: "truncate font-medium underline-offset-2 hover:underline",
|
|
32
|
+
children: info.getValue()
|
|
33
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
34
|
+
className: "truncate text-[var(--muted-foreground)] text-xs",
|
|
35
|
+
children: [info.row.original.mode ? `${info.row.original.mode} · ` : "", info.row.original.composerId]
|
|
36
|
+
})]
|
|
37
|
+
}),
|
|
38
|
+
header: "Thread"
|
|
39
|
+
}),
|
|
40
|
+
columnHelper.accessor("lastUpdatedAtMs", {
|
|
41
|
+
cell: (info) => /* @__PURE__ */ jsx("span", {
|
|
42
|
+
className: "whitespace-nowrap text-sm",
|
|
43
|
+
suppressHydrationWarning: true,
|
|
44
|
+
children: formatDateTime(info.getValue())
|
|
45
|
+
}),
|
|
46
|
+
header: "Updated",
|
|
47
|
+
id: "updatedAt"
|
|
48
|
+
}),
|
|
49
|
+
columnHelper.accessor("createdAtMs", {
|
|
50
|
+
cell: (info) => /* @__PURE__ */ jsx("span", {
|
|
51
|
+
className: "whitespace-nowrap text-sm",
|
|
52
|
+
suppressHydrationWarning: true,
|
|
53
|
+
children: formatDateTime(info.getValue())
|
|
54
|
+
}),
|
|
55
|
+
header: "Created",
|
|
56
|
+
id: "createdAt"
|
|
57
|
+
}),
|
|
58
|
+
columnHelper.accessor("mode", {
|
|
59
|
+
cell: (info) => /* @__PURE__ */ jsx("span", {
|
|
60
|
+
className: "font-mono text-sm",
|
|
61
|
+
children: info.getValue() ?? "unknown"
|
|
62
|
+
}),
|
|
63
|
+
header: "Mode"
|
|
64
|
+
}),
|
|
65
|
+
columnHelper.accessor("bubbleCount", {
|
|
66
|
+
cell: (info) => /* @__PURE__ */ jsx("span", {
|
|
67
|
+
className: "font-mono text-sm",
|
|
68
|
+
children: formatNumber(info.getValue())
|
|
69
|
+
}),
|
|
70
|
+
header: "Messages"
|
|
71
|
+
}),
|
|
72
|
+
columnHelper.accessor("bubbleBytes", {
|
|
73
|
+
cell: (info) => /* @__PURE__ */ jsx("span", {
|
|
74
|
+
className: "font-mono text-sm",
|
|
75
|
+
children: formatBytes(info.getValue())
|
|
76
|
+
}),
|
|
77
|
+
header: "Size"
|
|
78
|
+
}),
|
|
79
|
+
columnHelper.display({
|
|
80
|
+
cell: (info) => /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
|
|
81
|
+
asChild: true,
|
|
82
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
83
|
+
"aria-label": `Actions for ${info.row.original.name}`,
|
|
84
|
+
className: "rounded-full",
|
|
85
|
+
size: "icon",
|
|
86
|
+
type: "button",
|
|
87
|
+
variant: "ghost",
|
|
88
|
+
onClick: (event) => event.stopPropagation(),
|
|
89
|
+
children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "size-4" })
|
|
90
|
+
})
|
|
91
|
+
}), /* @__PURE__ */ jsxs(DropdownMenuContent, {
|
|
92
|
+
align: "end",
|
|
93
|
+
children: [/* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
94
|
+
disabled: info.row.original.bubbleCount === 0,
|
|
95
|
+
onClick: () => onExportThread(info.row.original),
|
|
96
|
+
children: [/* @__PURE__ */ jsx(Download, { className: "mr-2 size-4" }), "Export thread"]
|
|
97
|
+
}), /* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
98
|
+
className: "text-[var(--destructive)]",
|
|
99
|
+
onClick: () => onDeleteThread(info.row.original),
|
|
100
|
+
children: [/* @__PURE__ */ jsx(Trash2, { className: "mr-2 size-4" }), "Delete thread"]
|
|
101
|
+
})]
|
|
102
|
+
})] }),
|
|
103
|
+
enableSorting: false,
|
|
104
|
+
header: "",
|
|
105
|
+
id: "actions"
|
|
106
|
+
})
|
|
107
|
+
];
|
|
108
|
+
var CursorThreadsTable = ({ onDeleteThread, onDeleteThreads, onExportThread, onExportThreads, threads }) => {
|
|
109
|
+
return /* @__PURE__ */ jsx(DataTable, {
|
|
110
|
+
columns: useMemo(() => columns(onDeleteThread, onExportThread), [onDeleteThread, onExportThread]),
|
|
111
|
+
data: threads,
|
|
112
|
+
emptyMessage: "No Cursor threads match the current workspace filter.",
|
|
113
|
+
enableRowSelection: true,
|
|
114
|
+
getRowId: (row) => row.composerId,
|
|
115
|
+
initialSorting: defaultSorting,
|
|
116
|
+
renderToolbar: ({ clearSelection, selectedRows }) => {
|
|
117
|
+
if (selectedRows.length === 0) return /* @__PURE__ */ jsx("p", {
|
|
118
|
+
className: "text-[var(--muted-foreground)] text-sm",
|
|
119
|
+
children: "Select threads to export or delete them in a batch."
|
|
120
|
+
});
|
|
121
|
+
const selectedComposerIds = selectedRows.map((row) => row.composerId);
|
|
122
|
+
const hasEmptySelection = selectedRows.some((row) => row.bubbleCount === 0);
|
|
123
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
124
|
+
className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",
|
|
125
|
+
children: [/* @__PURE__ */ jsxs("p", {
|
|
126
|
+
className: "text-sm",
|
|
127
|
+
children: [
|
|
128
|
+
selectedRows.length,
|
|
129
|
+
" thread",
|
|
130
|
+
selectedRows.length === 1 ? "" : "s",
|
|
131
|
+
" selected"
|
|
132
|
+
]
|
|
133
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
134
|
+
className: "flex flex-wrap gap-2",
|
|
135
|
+
children: [
|
|
136
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
137
|
+
className: "rounded-full",
|
|
138
|
+
disabled: hasEmptySelection,
|
|
139
|
+
size: "sm",
|
|
140
|
+
type: "button",
|
|
141
|
+
variant: "outline",
|
|
142
|
+
onClick: () => onExportThreads(selectedComposerIds),
|
|
143
|
+
children: [/* @__PURE__ */ jsx(Download, { className: "mr-2 size-4" }), "Export selected threads"]
|
|
144
|
+
}),
|
|
145
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
146
|
+
className: "rounded-full border-[var(--destructive)]/20 text-[var(--destructive)]",
|
|
147
|
+
size: "sm",
|
|
148
|
+
type: "button",
|
|
149
|
+
variant: "outline",
|
|
150
|
+
onClick: () => onDeleteThreads(selectedComposerIds),
|
|
151
|
+
children: [/* @__PURE__ */ jsx(Trash2, { className: "mr-2 size-4" }), "Delete selected threads"]
|
|
152
|
+
}),
|
|
153
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
154
|
+
className: "rounded-full",
|
|
155
|
+
size: "sm",
|
|
156
|
+
type: "button",
|
|
157
|
+
variant: "ghost",
|
|
158
|
+
onClick: clearSelection,
|
|
159
|
+
children: [/* @__PURE__ */ jsx(X, { className: "mr-2 size-4" }), "Clear selection"]
|
|
160
|
+
})
|
|
161
|
+
]
|
|
162
|
+
})]
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
};
|
|
167
|
+
//#endregion
|
|
168
|
+
//#region src/routes/cursor.$workspaceKey.tsx?tsr-split=component
|
|
169
|
+
var getSelectedThreads = (threads, composerIds) => {
|
|
170
|
+
const composerIdSet = new Set(composerIds);
|
|
171
|
+
return threads.filter((thread) => composerIdSet.has(thread.composerId));
|
|
172
|
+
};
|
|
173
|
+
var buildPendingCursorDelete = (threads) => {
|
|
174
|
+
if (threads.length === 0) return null;
|
|
175
|
+
return {
|
|
176
|
+
kind: "threads",
|
|
177
|
+
threads
|
|
178
|
+
};
|
|
179
|
+
};
|
|
180
|
+
var buildPendingCursorExport = (threads) => {
|
|
181
|
+
if (threads.length === 0) return null;
|
|
182
|
+
return {
|
|
183
|
+
composerIds: threads.map((thread) => thread.composerId),
|
|
184
|
+
label: threads.length === 1 ? threads[0].name : `${threads.length} selected threads`
|
|
185
|
+
};
|
|
186
|
+
};
|
|
187
|
+
var getCursorDeleteConfirmLabel = (pendingDelete, pending) => {
|
|
188
|
+
if (pending) return "Deleting...";
|
|
189
|
+
if (pendingDelete?.kind === "workspace") return "Delete workspace";
|
|
190
|
+
return pendingDelete && pendingDelete.threads.length > 1 ? "Delete threads" : "Delete thread";
|
|
191
|
+
};
|
|
192
|
+
var getCursorDeleteDescription = (pendingDelete) => {
|
|
193
|
+
if (!pendingDelete) return "";
|
|
194
|
+
if (pendingDelete.kind === "workspace") return `Permanently delete every thread for "${pendingDelete.workspace.label}" from Cursor's database and remove any on-disk transcript directories. Quit Cursor first. This cannot be undone.`;
|
|
195
|
+
if (pendingDelete.threads.length === 1) return `Permanently delete "${pendingDelete.threads[0].name}" from Cursor's database and remove any on-disk transcript directories. Quit Cursor first. This cannot be undone.`;
|
|
196
|
+
return `Permanently delete ${pendingDelete.threads.length} selected Cursor threads and remove any on-disk transcript directories. Quit Cursor first. This cannot be undone.`;
|
|
197
|
+
};
|
|
198
|
+
var getCursorDeleteTitle = (pendingDelete) => {
|
|
199
|
+
if (pendingDelete?.kind === "workspace") return "Delete Cursor workspace?";
|
|
200
|
+
if (pendingDelete && pendingDelete.threads.length > 1) return `Delete ${pendingDelete.threads.length} Cursor threads?`;
|
|
201
|
+
return "Delete Cursor thread?";
|
|
202
|
+
};
|
|
203
|
+
var getCursorExportMimeType = (outputFormat) => {
|
|
204
|
+
return outputFormat === "md" ? "text/markdown; charset=utf-8" : "text/plain; charset=utf-8";
|
|
205
|
+
};
|
|
206
|
+
var CursorWorkspacePage = () => {
|
|
207
|
+
const navigate = useNavigate();
|
|
208
|
+
const params = Route.useParams();
|
|
209
|
+
const queryClient = useQueryClient();
|
|
210
|
+
const workspaces = useSuspenseQuery(cursorWorkspacesQueryOptions()).data;
|
|
211
|
+
const workspace = findWorkspaceOrThrow(workspaces, params.workspaceKey);
|
|
212
|
+
const threads = useSuspenseQuery(cursorThreadsQueryOptions(workspace.key)).data;
|
|
213
|
+
const [searchInput, setSearchInput] = useState("");
|
|
214
|
+
const [pendingDelete, setPendingDelete] = useState(null);
|
|
215
|
+
const [pendingExport, setPendingExport] = useState(null);
|
|
216
|
+
const deferredSearch = useDeferredValue(searchInput);
|
|
217
|
+
const invalidateWorkspaceQueries = async () => {
|
|
218
|
+
await Promise.all([queryClient.invalidateQueries({ queryKey: ["cursor-workspaces"] }), queryClient.invalidateQueries({ queryKey: ["cursor-threads", workspace.key] })]);
|
|
219
|
+
};
|
|
220
|
+
const recoverWorkspaceMutation = useMutation({
|
|
221
|
+
mutationFn: () => recoverCursorWorkspaceFn({ data: {
|
|
222
|
+
apply: true,
|
|
223
|
+
workspaceKey: workspace.key
|
|
224
|
+
} }),
|
|
225
|
+
onSuccess: invalidateWorkspaceQueries
|
|
226
|
+
});
|
|
227
|
+
const deleteMutation = useMutation({
|
|
228
|
+
mutationFn: (target) => target.kind === "workspace" ? deleteCursorWorkspaceFn({ data: { workspaceKey: target.workspace.key } }) : deleteCursorThreadsFn({ data: { composerIds: target.threads.map((thread) => thread.composerId) } }),
|
|
229
|
+
onSuccess: async (_result, target) => {
|
|
230
|
+
if (target.kind === "workspace") {
|
|
231
|
+
await navigate({ to: "/cursor" });
|
|
232
|
+
await queryClient.invalidateQueries({ queryKey: ["cursor-workspaces"] });
|
|
233
|
+
setPendingDelete(null);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
await invalidateWorkspaceQueries();
|
|
237
|
+
setPendingDelete(null);
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
const exportMutation = useMutation({
|
|
241
|
+
mutationFn: async (options) => {
|
|
242
|
+
if (!pendingExport) throw new Error("No thread selected for export");
|
|
243
|
+
const download = pendingExport.composerIds.length === 1 ? await exportCursorThreadFn({ data: {
|
|
244
|
+
...options,
|
|
245
|
+
composerId: pendingExport.composerIds[0]
|
|
246
|
+
} }) : await exportCursorThreadsFn({ data: {
|
|
247
|
+
...options,
|
|
248
|
+
composerIds: pendingExport.composerIds
|
|
249
|
+
} });
|
|
250
|
+
downloadTextFile(download.filename, download.content, getCursorExportMimeType(options.outputFormat));
|
|
251
|
+
},
|
|
252
|
+
onSuccess: () => {
|
|
253
|
+
setPendingExport(null);
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
const visibleThreads = threads.filter((thread) => matchesTextQuery(deferredSearch, [
|
|
257
|
+
thread.name,
|
|
258
|
+
thread.composerId,
|
|
259
|
+
thread.mode,
|
|
260
|
+
thread.workspaceLabel
|
|
261
|
+
]));
|
|
262
|
+
const openDeleteForSelectedThreads = (composerIds) => {
|
|
263
|
+
const nextPendingDelete = buildPendingCursorDelete(getSelectedThreads(visibleThreads, composerIds));
|
|
264
|
+
if (nextPendingDelete) setPendingDelete(nextPendingDelete);
|
|
265
|
+
};
|
|
266
|
+
const openExportForSelectedThreads = (composerIds) => {
|
|
267
|
+
const nextPendingExport = buildPendingCursorExport(getSelectedThreads(visibleThreads, composerIds));
|
|
268
|
+
if (nextPendingExport) setPendingExport(nextPendingExport);
|
|
269
|
+
};
|
|
270
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
271
|
+
className: "space-y-6",
|
|
272
|
+
children: [
|
|
273
|
+
/* @__PURE__ */ jsx(PageHeader, {
|
|
274
|
+
actions: /* @__PURE__ */ jsx(CursorWorkspaceHeaderActions, {
|
|
275
|
+
deletePending: deleteMutation.isPending,
|
|
276
|
+
recoverPending: recoverWorkspaceMutation.isPending,
|
|
277
|
+
searchInput,
|
|
278
|
+
workspace,
|
|
279
|
+
onDeleteWorkspace: () => setPendingDelete({
|
|
280
|
+
kind: "workspace",
|
|
281
|
+
workspace
|
|
282
|
+
}),
|
|
283
|
+
onRecoverWorkspace: () => recoverWorkspaceMutation.mutate(),
|
|
284
|
+
onSearchInputChange: setSearchInput
|
|
285
|
+
}),
|
|
286
|
+
eyebrow: "Cursor workspace",
|
|
287
|
+
subtitle: "Sort by any column, export thread transcripts, delete stale records, or repair split storage buckets for this workspace.",
|
|
288
|
+
title: workspace.label
|
|
289
|
+
}),
|
|
290
|
+
/* @__PURE__ */ jsx(CursorWorkspaceRecoveryNotice, { workspace }),
|
|
291
|
+
/* @__PURE__ */ jsx(CursorThreadsTable, {
|
|
292
|
+
onDeleteThread: (thread) => setPendingDelete({
|
|
293
|
+
kind: "threads",
|
|
294
|
+
threads: [thread]
|
|
295
|
+
}),
|
|
296
|
+
onDeleteThreads: openDeleteForSelectedThreads,
|
|
297
|
+
onExportThread: (thread) => setPendingExport({
|
|
298
|
+
composerIds: [thread.composerId],
|
|
299
|
+
label: thread.name
|
|
300
|
+
}),
|
|
301
|
+
onExportThreads: openExportForSelectedThreads,
|
|
302
|
+
threads: visibleThreads
|
|
303
|
+
}),
|
|
304
|
+
/* @__PURE__ */ jsx(CursorWorkspaceErrors, {
|
|
305
|
+
deleteError: deleteMutation.isError ? deleteMutation.error : null,
|
|
306
|
+
exportError: exportMutation.isError ? exportMutation.error : null,
|
|
307
|
+
recoverError: recoverWorkspaceMutation.isError ? recoverWorkspaceMutation.error : null
|
|
308
|
+
}),
|
|
309
|
+
/* @__PURE__ */ jsx(CursorWorkspaceDeleteDialog, {
|
|
310
|
+
pending: deleteMutation.isPending,
|
|
311
|
+
pendingDelete,
|
|
312
|
+
onConfirm: () => {
|
|
313
|
+
if (!pendingDelete) return;
|
|
314
|
+
deleteMutation.mutate(pendingDelete);
|
|
315
|
+
},
|
|
316
|
+
onOpenChange: (open) => {
|
|
317
|
+
if (!open) setPendingDelete(null);
|
|
318
|
+
}
|
|
319
|
+
}),
|
|
320
|
+
/* @__PURE__ */ jsx(ExportDialog, {
|
|
321
|
+
open: pendingExport !== null,
|
|
322
|
+
pending: exportMutation.isPending,
|
|
323
|
+
title: pendingExport ? `Export ${pendingExport.label}` : "Export thread",
|
|
324
|
+
onExport: (options) => exportMutation.mutate(options),
|
|
325
|
+
onOpenChange: (open) => {
|
|
326
|
+
if (!open) setPendingExport(null);
|
|
327
|
+
}
|
|
328
|
+
})
|
|
329
|
+
]
|
|
330
|
+
});
|
|
331
|
+
};
|
|
332
|
+
var CursorWorkspaceHeaderActions = ({ deletePending, recoverPending, searchInput, workspace, onDeleteWorkspace, onRecoverWorkspace, onSearchInputChange }) => {
|
|
333
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
334
|
+
className: "flex flex-col gap-2 sm:flex-row",
|
|
335
|
+
children: [
|
|
336
|
+
workspace.needsRecovery ? /* @__PURE__ */ jsxs(Button, {
|
|
337
|
+
className: "rounded-full",
|
|
338
|
+
disabled: recoverPending,
|
|
339
|
+
type: "button",
|
|
340
|
+
variant: "outline",
|
|
341
|
+
onClick: onRecoverWorkspace,
|
|
342
|
+
children: [/* @__PURE__ */ jsx(RefreshCcw, { className: "mr-2 size-4" }), recoverPending ? "Recovering..." : "Recover"]
|
|
343
|
+
}) : null,
|
|
344
|
+
/* @__PURE__ */ jsxs(Button, {
|
|
345
|
+
className: "rounded-full",
|
|
346
|
+
disabled: deletePending,
|
|
347
|
+
type: "button",
|
|
348
|
+
variant: "outline",
|
|
349
|
+
onClick: onDeleteWorkspace,
|
|
350
|
+
children: [/* @__PURE__ */ jsx(Trash2, { className: "mr-2 size-4" }), "Delete workspace"]
|
|
351
|
+
}),
|
|
352
|
+
/* @__PURE__ */ jsx(ListSearchInput, {
|
|
353
|
+
placeholder: "Search thread name, id, or mode",
|
|
354
|
+
value: searchInput,
|
|
355
|
+
onValueChange: onSearchInputChange
|
|
356
|
+
})
|
|
357
|
+
]
|
|
358
|
+
});
|
|
359
|
+
};
|
|
360
|
+
var CursorWorkspaceRecoveryNotice = ({ workspace }) => {
|
|
361
|
+
if (!workspace.needsRecovery) return null;
|
|
362
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
363
|
+
className: "rounded-xl border border-[var(--border)] bg-[var(--panel)] px-4 py-4",
|
|
364
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
365
|
+
className: "font-medium text-sm",
|
|
366
|
+
children: "This workspace has threads in an older storage bucket."
|
|
367
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
368
|
+
className: "mt-1 text-[var(--muted-foreground)] text-xs",
|
|
369
|
+
children: "Recover merges those threads into the active bucket Cursor reads now so they reappear in Chat History. Quit Cursor before running it."
|
|
370
|
+
})]
|
|
371
|
+
});
|
|
372
|
+
};
|
|
373
|
+
var CursorWorkspaceErrors = ({ deleteError, exportError, recoverError }) => {
|
|
374
|
+
const entries = [
|
|
375
|
+
recoverError ? recoverError.message : null,
|
|
376
|
+
deleteError ? deleteError.message : null,
|
|
377
|
+
exportError ? exportError.message : null
|
|
378
|
+
].filter(Boolean);
|
|
379
|
+
if (entries.length === 0) return null;
|
|
380
|
+
return /* @__PURE__ */ jsx("div", {
|
|
381
|
+
className: "space-y-1",
|
|
382
|
+
children: entries.map((message) => /* @__PURE__ */ jsx("p", {
|
|
383
|
+
className: "text-[var(--destructive)] text-sm",
|
|
384
|
+
children: message
|
|
385
|
+
}, message))
|
|
386
|
+
});
|
|
387
|
+
};
|
|
388
|
+
var CursorWorkspaceDeleteDialog = ({ pending, pendingDelete, onConfirm, onOpenChange }) => {
|
|
389
|
+
return /* @__PURE__ */ jsx(DeleteConfirmDialog, {
|
|
390
|
+
confirmLabel: getCursorDeleteConfirmLabel(pendingDelete, pending),
|
|
391
|
+
description: getCursorDeleteDescription(pendingDelete),
|
|
392
|
+
open: pendingDelete !== null,
|
|
393
|
+
title: getCursorDeleteTitle(pendingDelete),
|
|
394
|
+
onConfirm,
|
|
395
|
+
onOpenChange
|
|
396
|
+
});
|
|
397
|
+
};
|
|
398
|
+
//#endregion
|
|
399
|
+
export { CursorWorkspacePage as component };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { t as ReloadErrorPanel } from "./reload-error-panel-BJMxY3U1.js";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/routes/cursor.$workspaceKey.tsx?tsr-split=errorComponent
|
|
4
|
+
var CursorWorkspaceErrorComponent = ({ error }) => {
|
|
5
|
+
return /* @__PURE__ */ jsx(ReloadErrorPanel, {
|
|
6
|
+
description: error.message,
|
|
7
|
+
title: "Failed to load Cursor workspace"
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { CursorWorkspaceErrorComponent as errorComponent };
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { t as Button } from "./button-CmTDnzOn.js";
|
|
2
|
+
import { a as deleteCursorWorkspaceFn, c as recoverCursorWorkspaceFn, r as cursorWorkspacesQueryOptions } from "./cursor-queries-BMhuJeUO.js";
|
|
3
|
+
import { t as DataTable } from "./data-table-Cdct823O.js";
|
|
4
|
+
import { t as PageHeader } from "./page-header-VNSaM3xd.js";
|
|
5
|
+
import { o as formatNumber, r as formatDateTime } from "./formatters-FJaGZgJk.js";
|
|
6
|
+
import { t as Badge } from "./badge-EvdhKK_Z.js";
|
|
7
|
+
import { i as DropdownMenuTrigger, n as DropdownMenuContent, r as DropdownMenuItem, t as DropdownMenu } from "./dropdown-menu-Dy_9t6TN.js";
|
|
8
|
+
import { n as ListSearchInput, t as matchesTextQuery } from "./text-filter-CGKxMCKt.js";
|
|
9
|
+
import { t as DeleteConfirmDialog } from "./delete-confirm-dialog-PCD7S0_M.js";
|
|
10
|
+
import { useDeferredValue, useState } from "react";
|
|
11
|
+
import { Link } from "@tanstack/react-router";
|
|
12
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
|
+
import { useMutation, useQueryClient, useSuspenseQuery } from "@tanstack/react-query";
|
|
14
|
+
import { MoreHorizontal, RefreshCcw, Trash2 } from "lucide-react";
|
|
15
|
+
import { createColumnHelper } from "@tanstack/react-table";
|
|
16
|
+
//#region src/components/cursor-workspaces-table.tsx
|
|
17
|
+
var columnHelper = createColumnHelper();
|
|
18
|
+
var getWorkspaceLocation = (workspace) => workspace.folders[0] ?? workspace.uri;
|
|
19
|
+
var getWorkspaceStorageLabel = (workspace) => {
|
|
20
|
+
if (workspace.buckets.length === 0) return "File history";
|
|
21
|
+
return `${formatNumber(workspace.buckets.length)} bucket${workspace.buckets.length === 1 ? "" : "s"}`;
|
|
22
|
+
};
|
|
23
|
+
var getWorkspaceStateLabel = (workspace) => {
|
|
24
|
+
if (workspace.needsRecovery) return "Recovery available";
|
|
25
|
+
if (workspace.buckets.length === 0) return "Activity only";
|
|
26
|
+
return "Current";
|
|
27
|
+
};
|
|
28
|
+
var columns = (onDeleteWorkspace, onRecoverWorkspace) => [
|
|
29
|
+
columnHelper.accessor("label", {
|
|
30
|
+
cell: (info) => /* @__PURE__ */ jsxs(Link, {
|
|
31
|
+
className: "block w-[16rem] max-w-[22rem] space-y-1 rounded-md outline-none transition hover:opacity-80 focus-visible:ring-2 focus-visible:ring-[var(--accent)] lg:w-auto",
|
|
32
|
+
params: { workspaceKey: info.row.original.key },
|
|
33
|
+
to: "/cursor/$workspaceKey",
|
|
34
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
35
|
+
className: "flex items-center gap-2",
|
|
36
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
37
|
+
className: "truncate font-medium underline-offset-2 hover:underline",
|
|
38
|
+
children: info.getValue()
|
|
39
|
+
}), info.row.original.needsRecovery ? /* @__PURE__ */ jsx(Badge, {
|
|
40
|
+
variant: "outline",
|
|
41
|
+
children: "recover"
|
|
42
|
+
}) : null]
|
|
43
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
44
|
+
className: "truncate text-[var(--muted-foreground)] text-xs",
|
|
45
|
+
children: getWorkspaceLocation(info.row.original)
|
|
46
|
+
})]
|
|
47
|
+
}),
|
|
48
|
+
header: "Workspace"
|
|
49
|
+
}),
|
|
50
|
+
columnHelper.accessor("threadCount", {
|
|
51
|
+
cell: (info) => /* @__PURE__ */ jsx("span", {
|
|
52
|
+
className: "font-mono text-sm",
|
|
53
|
+
children: formatNumber(info.getValue())
|
|
54
|
+
}),
|
|
55
|
+
header: "Threads"
|
|
56
|
+
}),
|
|
57
|
+
columnHelper.display({
|
|
58
|
+
cell: (info) => /* @__PURE__ */ jsx("span", {
|
|
59
|
+
className: "text-sm",
|
|
60
|
+
children: getWorkspaceStorageLabel(info.row.original)
|
|
61
|
+
}),
|
|
62
|
+
header: "Storage",
|
|
63
|
+
id: "storage"
|
|
64
|
+
}),
|
|
65
|
+
columnHelper.display({
|
|
66
|
+
cell: (info) => /* @__PURE__ */ jsx("span", {
|
|
67
|
+
className: "text-sm",
|
|
68
|
+
children: getWorkspaceStateLabel(info.row.original)
|
|
69
|
+
}),
|
|
70
|
+
header: "State",
|
|
71
|
+
id: "state"
|
|
72
|
+
}),
|
|
73
|
+
columnHelper.accessor("lastActiveMs", {
|
|
74
|
+
cell: (info) => /* @__PURE__ */ jsx("span", {
|
|
75
|
+
className: "whitespace-nowrap text-sm",
|
|
76
|
+
suppressHydrationWarning: true,
|
|
77
|
+
children: formatDateTime(info.getValue())
|
|
78
|
+
}),
|
|
79
|
+
header: "Last updated"
|
|
80
|
+
}),
|
|
81
|
+
columnHelper.display({
|
|
82
|
+
cell: (info) => /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
|
|
83
|
+
asChild: true,
|
|
84
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
85
|
+
"aria-label": `Actions for ${info.row.original.label}`,
|
|
86
|
+
className: "rounded-full",
|
|
87
|
+
size: "icon",
|
|
88
|
+
type: "button",
|
|
89
|
+
variant: "ghost",
|
|
90
|
+
onClick: (event) => event.stopPropagation(),
|
|
91
|
+
children: /* @__PURE__ */ jsx(MoreHorizontal, { className: "size-4" })
|
|
92
|
+
})
|
|
93
|
+
}), /* @__PURE__ */ jsxs(DropdownMenuContent, {
|
|
94
|
+
align: "end",
|
|
95
|
+
children: [info.row.original.needsRecovery ? /* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
96
|
+
onClick: () => onRecoverWorkspace(info.row.original),
|
|
97
|
+
children: [/* @__PURE__ */ jsx(RefreshCcw, { className: "mr-2 size-4" }), "Recover workspace"]
|
|
98
|
+
}) : null, /* @__PURE__ */ jsxs(DropdownMenuItem, {
|
|
99
|
+
className: "text-[var(--destructive)]",
|
|
100
|
+
onClick: () => onDeleteWorkspace(info.row.original),
|
|
101
|
+
children: [/* @__PURE__ */ jsx(Trash2, { className: "mr-2 size-4" }), "Delete workspace"]
|
|
102
|
+
})]
|
|
103
|
+
})] }),
|
|
104
|
+
header: "",
|
|
105
|
+
id: "actions"
|
|
106
|
+
})
|
|
107
|
+
];
|
|
108
|
+
var CursorWorkspacesTable = ({ onDeleteWorkspace, onRecoverWorkspace, workspaces }) => {
|
|
109
|
+
return /* @__PURE__ */ jsx(DataTable, {
|
|
110
|
+
columns: columns(onDeleteWorkspace, onRecoverWorkspace),
|
|
111
|
+
data: workspaces,
|
|
112
|
+
emptyMessage: "No Cursor workspaces match the current search."
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/routes/cursor.index.tsx?tsr-split=component
|
|
117
|
+
var CursorPage = () => {
|
|
118
|
+
const queryClient = useQueryClient();
|
|
119
|
+
const workspaces = useSuspenseQuery(cursorWorkspacesQueryOptions()).data;
|
|
120
|
+
const [searchInput, setSearchInput] = useState("");
|
|
121
|
+
const [pendingDelete, setPendingDelete] = useState(null);
|
|
122
|
+
const deferredSearch = useDeferredValue(searchInput);
|
|
123
|
+
const invalidateCursorQueries = async () => {
|
|
124
|
+
await queryClient.invalidateQueries({ queryKey: ["cursor-workspaces"] });
|
|
125
|
+
};
|
|
126
|
+
const recoverWorkspaceMutation = useMutation({
|
|
127
|
+
mutationFn: (workspace) => recoverCursorWorkspaceFn({ data: {
|
|
128
|
+
apply: true,
|
|
129
|
+
workspaceKey: workspace.key
|
|
130
|
+
} }),
|
|
131
|
+
onSuccess: invalidateCursorQueries
|
|
132
|
+
});
|
|
133
|
+
const deleteWorkspaceMutation = useMutation({
|
|
134
|
+
mutationFn: (workspace) => deleteCursorWorkspaceFn({ data: { workspaceKey: workspace.key } }),
|
|
135
|
+
onSuccess: async () => {
|
|
136
|
+
await invalidateCursorQueries();
|
|
137
|
+
setPendingDelete(null);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
const visibleWorkspaces = workspaces.filter((workspace) => matchesTextQuery(deferredSearch, [
|
|
141
|
+
workspace.label,
|
|
142
|
+
workspace.uri,
|
|
143
|
+
workspace.folders.join("\n"),
|
|
144
|
+
workspace.kind
|
|
145
|
+
]));
|
|
146
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
147
|
+
className: "space-y-6",
|
|
148
|
+
children: [
|
|
149
|
+
/* @__PURE__ */ jsx(PageHeader, {
|
|
150
|
+
actions: /* @__PURE__ */ jsx(ListSearchInput, {
|
|
151
|
+
placeholder: "Search workspace name or path",
|
|
152
|
+
value: searchInput,
|
|
153
|
+
onValueChange: setSearchInput
|
|
154
|
+
}),
|
|
155
|
+
eyebrow: "Inventory",
|
|
156
|
+
subtitle: "Workspace groups are derived from Cursor storage buckets and activity metadata. Open a workspace to inspect, export, recover, or delete its threads.",
|
|
157
|
+
title: "Cursor"
|
|
158
|
+
}),
|
|
159
|
+
/* @__PURE__ */ jsx(CursorWorkspacesTable, {
|
|
160
|
+
onDeleteWorkspace: setPendingDelete,
|
|
161
|
+
onRecoverWorkspace: (workspace) => recoverWorkspaceMutation.mutate(workspace),
|
|
162
|
+
workspaces: visibleWorkspaces
|
|
163
|
+
}),
|
|
164
|
+
recoverWorkspaceMutation.isError ? /* @__PURE__ */ jsx("p", {
|
|
165
|
+
className: "text-[var(--destructive)] text-sm",
|
|
166
|
+
children: recoverWorkspaceMutation.error instanceof Error ? recoverWorkspaceMutation.error.message : "Workspace recovery failed"
|
|
167
|
+
}) : null,
|
|
168
|
+
deleteWorkspaceMutation.isError ? /* @__PURE__ */ jsx("p", {
|
|
169
|
+
className: "text-[var(--destructive)] text-sm",
|
|
170
|
+
children: deleteWorkspaceMutation.error instanceof Error ? deleteWorkspaceMutation.error.message : "Workspace deletion failed"
|
|
171
|
+
}) : null,
|
|
172
|
+
/* @__PURE__ */ jsx(DeleteConfirmDialog, {
|
|
173
|
+
confirmLabel: deleteWorkspaceMutation.isPending ? "Deleting..." : "Delete workspace",
|
|
174
|
+
description: pendingDelete ? `Permanently delete every thread for "${pendingDelete.label}" from Cursor's database and remove any on-disk transcript directories. Quit Cursor first. This cannot be undone.` : "",
|
|
175
|
+
open: pendingDelete !== null,
|
|
176
|
+
title: "Delete Cursor workspace?",
|
|
177
|
+
onConfirm: () => {
|
|
178
|
+
if (!pendingDelete) return;
|
|
179
|
+
deleteWorkspaceMutation.mutate(pendingDelete);
|
|
180
|
+
},
|
|
181
|
+
onOpenChange: (open) => {
|
|
182
|
+
if (!open) setPendingDelete(null);
|
|
183
|
+
}
|
|
184
|
+
})
|
|
185
|
+
]
|
|
186
|
+
});
|
|
187
|
+
};
|
|
188
|
+
//#endregion
|
|
189
|
+
export { CursorPage as component };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { t as ReloadErrorPanel } from "./reload-error-panel-BJMxY3U1.js";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
//#region src/routes/cursor.index.tsx?tsr-split=errorComponent
|
|
4
|
+
var CursorErrorComponent = ({ error }) => {
|
|
5
|
+
return /* @__PURE__ */ jsx(ReloadErrorPanel, {
|
|
6
|
+
description: error.message,
|
|
7
|
+
title: "Failed to load Cursor workspaces"
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
//#endregion
|
|
11
|
+
export { CursorErrorComponent as errorComponent };
|
|
@@ -86,13 +86,13 @@ function AlertDialogCancel({ className, variant = "outline", size = "default", .
|
|
|
86
86
|
}
|
|
87
87
|
//#endregion
|
|
88
88
|
//#region src/components/delete-confirm-dialog.tsx
|
|
89
|
-
function DeleteConfirmDialog({ confirmLabel = "Delete", description, open, showDeleteSessionFilesOption = false, title, onConfirm, onOpenChange }) {
|
|
89
|
+
function DeleteConfirmDialog({ confirmLabel = "Delete", defaultDeleteSessionFiles = false, description, open, showDeleteSessionFilesOption = false, title, onConfirm, onOpenChange }) {
|
|
90
90
|
const checkboxId = useId();
|
|
91
91
|
const checkboxDescriptionId = useId();
|
|
92
|
-
const [deleteSessionFiles, setDeleteSessionFiles] = useState(
|
|
92
|
+
const [deleteSessionFiles, setDeleteSessionFiles] = useState(defaultDeleteSessionFiles);
|
|
93
93
|
useEffect(() => {
|
|
94
|
-
if (!open) setDeleteSessionFiles(
|
|
95
|
-
}, [open]);
|
|
94
|
+
if (!open) setDeleteSessionFiles(defaultDeleteSessionFiles);
|
|
95
|
+
}, [defaultDeleteSessionFiles, open]);
|
|
96
96
|
return /* @__PURE__ */ jsx(AlertDialog$1, {
|
|
97
97
|
open,
|
|
98
98
|
onOpenChange,
|
|
@@ -106,6 +106,7 @@ function DeleteConfirmDialog({ confirmLabel = "Delete", description, open, showD
|
|
|
106
106
|
showDeleteSessionFilesOption ? /* @__PURE__ */ jsxs("div", {
|
|
107
107
|
className: "flex items-start gap-3 rounded-xl border border-[var(--border)] bg-[var(--background)]/70 px-4 py-3 text-sm",
|
|
108
108
|
children: [/* @__PURE__ */ jsx(Checkbox$1, {
|
|
109
|
+
"aria-label": "Delete Session files",
|
|
109
110
|
"aria-describedby": checkboxDescriptionId,
|
|
110
111
|
checked: deleteSessionFiles,
|
|
111
112
|
id: checkboxId,
|