spiracha 1.0.0 → 1.1.1
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 +31 -1
- package/README.md +61 -7
- package/apps/ui/AGENTS.md +70 -0
- package/apps/ui/README.md +72 -0
- package/apps/ui/dist/client/assets/_threadId-CAIeH5mq.js +1 -0
- package/apps/ui/dist/client/assets/analytics-CqWZmyV6.js +1 -0
- package/apps/ui/dist/client/assets/checkbox-DXM4lkJq.js +1 -0
- package/apps/ui/dist/client/assets/data-table-DnPYMPCD.js +4 -0
- package/apps/ui/dist/client/assets/delete-confirm-dialog-CcZaRX33.js +11 -0
- package/apps/ui/dist/client/assets/download-DOwxk-cG.js +1 -0
- package/apps/ui/dist/client/assets/es2015-Bm0kEzx2.js +41 -0
- package/apps/ui/dist/client/assets/formatters-C12LmYaa.js +1 -0
- package/apps/ui/dist/client/assets/index-DdJ7ahIt.js +22 -0
- package/apps/ui/dist/client/assets/input-CEsI7EpI.js +1 -0
- package/apps/ui/dist/client/assets/metric-card-9jwBF7rG.js +1 -0
- package/apps/ui/dist/client/assets/page-header-Dr_h1CVv.js +1 -0
- package/apps/ui/dist/client/assets/projects._project-uyNGnpjH.js +1 -0
- package/apps/ui/dist/client/assets/projects._project-zoM8d2nH.js +1 -0
- package/apps/ui/dist/client/assets/projects.index-D1CWVN-O.js +1 -0
- package/apps/ui/dist/client/assets/projects.index-DukMuny6.js +1 -0
- package/apps/ui/dist/client/assets/routes-Gr2Wwh83.js +1 -0
- package/apps/ui/dist/client/assets/select-CFim44gT.js +1 -0
- package/apps/ui/dist/client/assets/settings-DqhyDxo2.js +1 -0
- package/apps/ui/dist/client/assets/styles-CMrP9Jb4.css +1 -0
- package/apps/ui/dist/client/assets/threads._threadId-DT75NiBa.js +1 -0
- package/apps/ui/dist/client/assets/threads._threadId-Df5VXIuZ.js +7 -0
- 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/client/manifest.json +25 -0
- package/apps/ui/dist/client/robots.txt +3 -0
- package/apps/ui/dist/server/assets/__23tanstack-start-plugin-adapters-BzCA6dXo.js +5 -0
- package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-C0V305Nt.js +99 -0
- package/apps/ui/dist/server/assets/_threadId-B6SrBR9E.js +6 -0
- package/apps/ui/dist/server/assets/analytics-BMxW_bZL.js +139 -0
- package/apps/ui/dist/server/assets/button-CmTDnzOn.js +46 -0
- package/apps/ui/dist/server/assets/checkbox-C0hovF41.js +19 -0
- package/apps/ui/dist/server/assets/codex-queries-CAF6HYiG.js +109 -0
- package/apps/ui/dist/server/assets/codex-server-BFZq2Y2O.js +2062 -0
- package/apps/ui/dist/server/assets/data-table-Cdct823O.js +189 -0
- package/apps/ui/dist/server/assets/delete-confirm-dialog-CWqcTXTF.js +139 -0
- package/apps/ui/dist/server/assets/download-C5rkk_Bo.js +289 -0
- package/apps/ui/dist/server/assets/formatters-FJaGZgJk.js +91 -0
- package/apps/ui/dist/server/assets/input-B4tEzctc.js +46 -0
- package/apps/ui/dist/server/assets/loading-panel-DbLdvjtR.js +27 -0
- package/apps/ui/dist/server/assets/metric-card-ByEeLu0r.js +23 -0
- package/apps/ui/dist/server/assets/model-label-B1NWGc65.js +13 -0
- package/apps/ui/dist/server/assets/page-header-CxdZM86z.js +25 -0
- package/apps/ui/dist/server/assets/path-transforms-DL2IwtYd.js +31 -0
- package/apps/ui/dist/server/assets/projects._project-CJ7l0ynC.js +18 -0
- package/apps/ui/dist/server/assets/projects._project-CLSohrBp.js +26 -0
- package/apps/ui/dist/server/assets/projects._project-CcJLp_A8.js +337 -0
- package/apps/ui/dist/server/assets/projects.index-CaplpeMy.js +26 -0
- package/apps/ui/dist/server/assets/projects.index-srtogpuF.js +172 -0
- package/apps/ui/dist/server/assets/router-C_w-haH6.js +307 -0
- package/apps/ui/dist/server/assets/routes-BhbxvJE7.js +34 -0
- package/apps/ui/dist/server/assets/routes-CPe-ppmC.js +169 -0
- package/apps/ui/dist/server/assets/select-GW76p-ld.js +76 -0
- package/apps/ui/dist/server/assets/settings-MvWDgc1u.js +100 -0
- package/apps/ui/dist/server/assets/settings-store-DpEJEQ7M.js +52 -0
- package/apps/ui/dist/server/assets/sqlite-error-LZDrnxdd.js +13 -0
- package/apps/ui/dist/server/assets/start-HeKLHD9b.js +4 -0
- package/apps/ui/dist/server/assets/threads._threadId-BSSK4nkI.js +26 -0
- package/apps/ui/dist/server/assets/threads._threadId-Ba7vv6-K.js +18 -0
- package/apps/ui/dist/server/assets/threads._threadId-euyNckhj.js +1059 -0
- package/apps/ui/dist/server/assets/utils-C_uf36nf.js +8 -0
- package/apps/ui/dist/server/server.js +5678 -0
- package/package.json +53 -7
- package/src/export-chats.ts +4 -18
- package/src/lib/claude-exporter.ts +1 -1
- package/src/lib/codex-analytics.ts +100 -0
- package/src/lib/codex-browser-db.ts +605 -0
- package/src/lib/codex-browser-export.ts +429 -0
- package/src/lib/codex-browser-types.ts +224 -0
- package/src/lib/codex-exporter-cli.ts +6 -1
- package/src/lib/codex-exporter-db.ts +19 -20
- package/src/lib/codex-exporter-transcript.ts +158 -34
- package/src/lib/codex-exporter-types.ts +8 -0
- package/src/lib/codex-thread-cache.ts +58 -0
- package/src/lib/codex-thread-parser.ts +604 -0
- package/src/lib/interactive-cli.ts +10 -25
- package/src/lib/model-label.ts +24 -0
- package/src/lib/native-open.ts +54 -0
- package/src/lib/path-transforms.ts +46 -0
- package/src/lib/shared.ts +15 -1
- package/src/lib/sqlite-error.ts +14 -0
- package/src/lib/sqlite-retry.ts +53 -0
- package/src/lib/ui-cache.ts +96 -0
- package/src/lib/ui-export-files.ts +77 -0
- package/src/mcp-server.ts +1 -0
- package/src/spiracha.ts +16 -4
- package/src/ui-cli.ts +310 -0
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import { t as cn } from "./utils-C_uf36nf.js";
|
|
2
|
+
import { t as Checkbox } from "./checkbox-C0hovF41.js";
|
|
3
|
+
import { useRef, useState } from "react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { ArrowDownUp } from "lucide-react";
|
|
6
|
+
import { flexRender, getCoreRowModel, getFilteredRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
|
|
7
|
+
//#region src/components/ui/table.tsx
|
|
8
|
+
function Table({ className, ...props }) {
|
|
9
|
+
return /* @__PURE__ */ jsx("div", {
|
|
10
|
+
"data-slot": "table-container",
|
|
11
|
+
className: "relative w-full overflow-x-auto",
|
|
12
|
+
children: /* @__PURE__ */ jsx("table", {
|
|
13
|
+
"data-slot": "table",
|
|
14
|
+
className: cn("w-full caption-bottom text-sm", className),
|
|
15
|
+
...props
|
|
16
|
+
})
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function TableHeader({ className, ...props }) {
|
|
20
|
+
return /* @__PURE__ */ jsx("thead", {
|
|
21
|
+
"data-slot": "table-header",
|
|
22
|
+
className: cn("[&_tr]:border-b", className),
|
|
23
|
+
...props
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
function TableBody({ className, ...props }) {
|
|
27
|
+
return /* @__PURE__ */ jsx("tbody", {
|
|
28
|
+
"data-slot": "table-body",
|
|
29
|
+
className: cn("[&_tr:last-child]:border-0", className),
|
|
30
|
+
...props
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
function TableRow({ className, ...props }) {
|
|
34
|
+
return /* @__PURE__ */ jsx("tr", {
|
|
35
|
+
"data-slot": "table-row",
|
|
36
|
+
className: cn("border-b transition-colors hover:bg-muted/50 has-aria-expanded:bg-muted/50 data-[state=selected]:bg-muted", className),
|
|
37
|
+
...props
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function TableHead({ className, ...props }) {
|
|
41
|
+
return /* @__PURE__ */ jsx("th", {
|
|
42
|
+
"data-slot": "table-head",
|
|
43
|
+
className: cn("h-10 whitespace-nowrap px-2 text-left align-middle font-medium text-foreground [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", className),
|
|
44
|
+
...props
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function TableCell({ className, ...props }) {
|
|
48
|
+
return /* @__PURE__ */ jsx("td", {
|
|
49
|
+
"data-slot": "table-cell",
|
|
50
|
+
className: cn("whitespace-nowrap p-2 align-middle [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]", className),
|
|
51
|
+
...props
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/components/data-table.tsx
|
|
56
|
+
var getSortIndicator = (value) => {
|
|
57
|
+
if (value === "asc") return "↑";
|
|
58
|
+
if (value === "desc") return "↓";
|
|
59
|
+
return /* @__PURE__ */ jsx(ArrowDownUp, { className: "size-3" });
|
|
60
|
+
};
|
|
61
|
+
var getRangeRowIds = (visibleRowIds, anchorRowId, targetRowId) => {
|
|
62
|
+
const anchorIndex = visibleRowIds.indexOf(anchorRowId);
|
|
63
|
+
const targetIndex = visibleRowIds.indexOf(targetRowId);
|
|
64
|
+
if (anchorIndex === -1 || targetIndex === -1) return null;
|
|
65
|
+
const [startIndex, endIndex] = anchorIndex <= targetIndex ? [anchorIndex, targetIndex] : [targetIndex, anchorIndex];
|
|
66
|
+
return visibleRowIds.slice(startIndex, endIndex + 1);
|
|
67
|
+
};
|
|
68
|
+
var applySelectionState = (selection, rowIds, checked) => {
|
|
69
|
+
const nextSelection = { ...selection };
|
|
70
|
+
for (const rowId of rowIds) {
|
|
71
|
+
if (checked) {
|
|
72
|
+
nextSelection[rowId] = true;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
delete nextSelection[rowId];
|
|
76
|
+
}
|
|
77
|
+
return nextSelection;
|
|
78
|
+
};
|
|
79
|
+
function DataTable({ className, columns, data, emptyMessage, enableRowSelection = false, getRowId, initialSorting = [], onRowClick, renderToolbar }) {
|
|
80
|
+
const [sorting, setSorting] = useState(initialSorting);
|
|
81
|
+
const [rowSelection, setRowSelection] = useState({});
|
|
82
|
+
const lastSelectedRowIdRef = useRef(null);
|
|
83
|
+
const updateSelectionForRow = (rowId, checked, shiftKey) => {
|
|
84
|
+
const visibleRowIds = table.getRowModel().rows.map((row) => row.id);
|
|
85
|
+
if (shiftKey && lastSelectedRowIdRef.current) {
|
|
86
|
+
const rangeRowIds = getRangeRowIds(visibleRowIds, lastSelectedRowIdRef.current, rowId);
|
|
87
|
+
if (rangeRowIds) {
|
|
88
|
+
setRowSelection(applySelectionState(rowSelection, rangeRowIds, checked));
|
|
89
|
+
lastSelectedRowIdRef.current = rowId;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
setRowSelection(applySelectionState(rowSelection, [rowId], checked));
|
|
94
|
+
lastSelectedRowIdRef.current = rowId;
|
|
95
|
+
};
|
|
96
|
+
const tableColumns = enableRowSelection ? [{
|
|
97
|
+
cell: ({ row }) => /* @__PURE__ */ jsx(Checkbox, {
|
|
98
|
+
"aria-label": `Select row ${row.id}`,
|
|
99
|
+
checked: row.getIsSelected(),
|
|
100
|
+
onClick: (event) => {
|
|
101
|
+
event.stopPropagation();
|
|
102
|
+
event.preventDefault();
|
|
103
|
+
updateSelectionForRow(row.id, !row.getIsSelected(), event.shiftKey);
|
|
104
|
+
},
|
|
105
|
+
onCheckedChange: (checked) => {
|
|
106
|
+
if (typeof checked !== "boolean") return;
|
|
107
|
+
updateSelectionForRow(row.id, checked, false);
|
|
108
|
+
}
|
|
109
|
+
}),
|
|
110
|
+
enableSorting: false,
|
|
111
|
+
header: ({ table }) => /* @__PURE__ */ jsx(Checkbox, {
|
|
112
|
+
"aria-label": "Select all rows",
|
|
113
|
+
checked: table.getIsAllPageRowsSelected() ? true : table.getIsSomePageRowsSelected() ? "indeterminate" : false,
|
|
114
|
+
onCheckedChange: (checked) => table.toggleAllPageRowsSelected(checked === true)
|
|
115
|
+
}),
|
|
116
|
+
id: "select"
|
|
117
|
+
}, ...columns] : [...columns];
|
|
118
|
+
const table = useReactTable({
|
|
119
|
+
autoResetPageIndex: false,
|
|
120
|
+
columns: tableColumns,
|
|
121
|
+
data,
|
|
122
|
+
enableRowSelection,
|
|
123
|
+
enableSortingRemoval: false,
|
|
124
|
+
getCoreRowModel: getCoreRowModel(),
|
|
125
|
+
getFilteredRowModel: getFilteredRowModel(),
|
|
126
|
+
getRowId,
|
|
127
|
+
getSortedRowModel: getSortedRowModel(),
|
|
128
|
+
onRowSelectionChange: setRowSelection,
|
|
129
|
+
onSortingChange: setSorting,
|
|
130
|
+
sortDescFirst: false,
|
|
131
|
+
state: {
|
|
132
|
+
rowSelection,
|
|
133
|
+
sorting
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
const selectedRows = table.getSelectedRowModel().rows.map((row) => row.original);
|
|
137
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
138
|
+
className: cn("w-full overflow-x-auto rounded-[1.5rem] border border-[var(--border)] bg-[var(--panel)]", className),
|
|
139
|
+
children: [renderToolbar ? /* @__PURE__ */ jsx("div", {
|
|
140
|
+
className: "border-[var(--border)] border-b px-4 py-3",
|
|
141
|
+
children: renderToolbar({
|
|
142
|
+
clearSelection: () => setRowSelection({}),
|
|
143
|
+
selectedRows
|
|
144
|
+
})
|
|
145
|
+
}) : null, /* @__PURE__ */ jsxs(Table, {
|
|
146
|
+
className: "min-w-full",
|
|
147
|
+
children: [/* @__PURE__ */ jsx(TableHeader, {
|
|
148
|
+
className: "bg-[var(--panel-secondary)]",
|
|
149
|
+
children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx(TableRow, {
|
|
150
|
+
className: "border-[var(--border)] hover:bg-transparent",
|
|
151
|
+
children: headerGroup.headers.map((header) => /* @__PURE__ */ jsx(TableHead, {
|
|
152
|
+
className: "h-10 whitespace-nowrap px-4 font-semibold text-[11px] text-[var(--muted-foreground)] uppercase tracking-[0.18em]",
|
|
153
|
+
children: header.isPlaceholder ? null : header.column.getCanSort() ? /* @__PURE__ */ jsxs("button", {
|
|
154
|
+
className: "inline-flex items-center gap-1.5 text-left",
|
|
155
|
+
type: "button",
|
|
156
|
+
onClick: header.column.getToggleSortingHandler(),
|
|
157
|
+
children: [/* @__PURE__ */ jsx("span", { children: flexRender(header.column.columnDef.header, header.getContext()) }), /* @__PURE__ */ jsx("span", {
|
|
158
|
+
"aria-hidden": "true",
|
|
159
|
+
className: "text-[10px]",
|
|
160
|
+
children: getSortIndicator(header.column.getIsSorted())
|
|
161
|
+
})]
|
|
162
|
+
}) : flexRender(header.column.columnDef.header, header.getContext())
|
|
163
|
+
}, header.id))
|
|
164
|
+
}, headerGroup.id))
|
|
165
|
+
}), /* @__PURE__ */ jsx(TableBody, { children: table.getRowModel().rows.length === 0 ? /* @__PURE__ */ jsx(TableRow, {
|
|
166
|
+
className: "border-[var(--border)]",
|
|
167
|
+
children: /* @__PURE__ */ jsx(TableCell, {
|
|
168
|
+
className: "px-4 py-10 text-center text-[var(--muted-foreground)] text-sm",
|
|
169
|
+
colSpan: tableColumns.length,
|
|
170
|
+
children: emptyMessage
|
|
171
|
+
})
|
|
172
|
+
}) : table.getRowModel().rows.map((row) => {
|
|
173
|
+
return /* @__PURE__ */ jsx(TableRow, {
|
|
174
|
+
className: cn("border-[var(--border)] hover:bg-[var(--panel-secondary)]/75", Boolean(onRowClick) ? "cursor-pointer" : ""),
|
|
175
|
+
onClick: () => {
|
|
176
|
+
if (!onRowClick) return;
|
|
177
|
+
onRowClick(row.original);
|
|
178
|
+
},
|
|
179
|
+
children: row.getVisibleCells().map((cell) => /* @__PURE__ */ jsx(TableCell, {
|
|
180
|
+
className: "px-4 py-2.5 align-top",
|
|
181
|
+
children: flexRender(cell.column.columnDef.cell, cell.getContext())
|
|
182
|
+
}, cell.id))
|
|
183
|
+
}, row.id);
|
|
184
|
+
}) })]
|
|
185
|
+
})]
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
189
|
+
export { DataTable as t };
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { t as cn } from "./utils-C_uf36nf.js";
|
|
2
|
+
import { t as Button } from "./button-CmTDnzOn.js";
|
|
3
|
+
import { t as Checkbox$1 } from "./checkbox-C0hovF41.js";
|
|
4
|
+
import { useEffect, useId, useState } from "react";
|
|
5
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { AlertDialog } from "radix-ui";
|
|
7
|
+
//#region src/components/ui/alert-dialog.tsx
|
|
8
|
+
function AlertDialog$1({ ...props }) {
|
|
9
|
+
return /* @__PURE__ */ jsx(AlertDialog.Root, {
|
|
10
|
+
"data-slot": "alert-dialog",
|
|
11
|
+
...props
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function AlertDialogPortal({ ...props }) {
|
|
15
|
+
return /* @__PURE__ */ jsx(AlertDialog.Portal, {
|
|
16
|
+
"data-slot": "alert-dialog-portal",
|
|
17
|
+
...props
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function AlertDialogOverlay({ className, ...props }) {
|
|
21
|
+
return /* @__PURE__ */ jsx(AlertDialog.Overlay, {
|
|
22
|
+
"data-slot": "alert-dialog-overlay",
|
|
23
|
+
className: cn("data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=open]:animate-in", className),
|
|
24
|
+
...props
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
function AlertDialogContent({ className, size = "default", ...props }) {
|
|
28
|
+
return /* @__PURE__ */ jsxs(AlertDialogPortal, { children: [/* @__PURE__ */ jsx(AlertDialogOverlay, {}), /* @__PURE__ */ jsx(AlertDialog.Content, {
|
|
29
|
+
"data-slot": "alert-dialog-content",
|
|
30
|
+
"data-size": size,
|
|
31
|
+
className: cn("group/alert-dialog-content data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg duration-200 data-[size=sm]:max-w-xs data-[state=closed]:animate-out data-[state=open]:animate-in data-[size=default]:sm:max-w-lg", className),
|
|
32
|
+
...props
|
|
33
|
+
})] });
|
|
34
|
+
}
|
|
35
|
+
function AlertDialogHeader({ className, ...props }) {
|
|
36
|
+
return /* @__PURE__ */ jsx("div", {
|
|
37
|
+
"data-slot": "alert-dialog-header",
|
|
38
|
+
className: cn("grid grid-rows-[auto_1fr] place-items-center gap-1.5 text-center has-data-[slot=alert-dialog-media]:grid-rows-[auto_auto_1fr] has-data-[slot=alert-dialog-media]:gap-x-6 sm:group-data-[size=default]/alert-dialog-content:place-items-start sm:group-data-[size=default]/alert-dialog-content:text-left sm:group-data-[size=default]/alert-dialog-content:has-data-[slot=alert-dialog-media]:grid-rows-[auto_1fr]", className),
|
|
39
|
+
...props
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function AlertDialogFooter({ className, ...props }) {
|
|
43
|
+
return /* @__PURE__ */ jsx("div", {
|
|
44
|
+
"data-slot": "alert-dialog-footer",
|
|
45
|
+
className: cn("flex flex-col-reverse gap-2 group-data-[size=sm]/alert-dialog-content:grid group-data-[size=sm]/alert-dialog-content:grid-cols-2 sm:flex-row sm:justify-end", className),
|
|
46
|
+
...props
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function AlertDialogTitle({ className, ...props }) {
|
|
50
|
+
return /* @__PURE__ */ jsx(AlertDialog.Title, {
|
|
51
|
+
"data-slot": "alert-dialog-title",
|
|
52
|
+
className: cn("font-semibold text-lg sm:group-data-[size=default]/alert-dialog-content:group-has-data-[slot=alert-dialog-media]/alert-dialog-content:col-start-2", className),
|
|
53
|
+
...props
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function AlertDialogDescription({ className, ...props }) {
|
|
57
|
+
return /* @__PURE__ */ jsx(AlertDialog.Description, {
|
|
58
|
+
"data-slot": "alert-dialog-description",
|
|
59
|
+
className: cn("text-muted-foreground text-sm", className),
|
|
60
|
+
...props
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
function AlertDialogAction({ className, variant = "default", size = "default", ...props }) {
|
|
64
|
+
return /* @__PURE__ */ jsx(Button, {
|
|
65
|
+
variant,
|
|
66
|
+
size,
|
|
67
|
+
asChild: true,
|
|
68
|
+
children: /* @__PURE__ */ jsx(AlertDialog.Action, {
|
|
69
|
+
"data-slot": "alert-dialog-action",
|
|
70
|
+
className: cn(className),
|
|
71
|
+
...props
|
|
72
|
+
})
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function AlertDialogCancel({ className, variant = "outline", size = "default", ...props }) {
|
|
76
|
+
return /* @__PURE__ */ jsx(Button, {
|
|
77
|
+
variant,
|
|
78
|
+
size,
|
|
79
|
+
asChild: true,
|
|
80
|
+
children: /* @__PURE__ */ jsx(AlertDialog.Cancel, {
|
|
81
|
+
"data-slot": "alert-dialog-cancel",
|
|
82
|
+
className: cn(className),
|
|
83
|
+
...props
|
|
84
|
+
})
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
//#region src/components/delete-confirm-dialog.tsx
|
|
89
|
+
function DeleteConfirmDialog({ confirmLabel = "Delete", description, open, showDeleteSessionFilesOption = false, title, onConfirm, onOpenChange }) {
|
|
90
|
+
const checkboxId = useId();
|
|
91
|
+
const checkboxDescriptionId = useId();
|
|
92
|
+
const [deleteSessionFiles, setDeleteSessionFiles] = useState(false);
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
if (!open) setDeleteSessionFiles(false);
|
|
95
|
+
}, [open]);
|
|
96
|
+
return /* @__PURE__ */ jsx(AlertDialog$1, {
|
|
97
|
+
open,
|
|
98
|
+
onOpenChange,
|
|
99
|
+
children: /* @__PURE__ */ jsxs(AlertDialogContent, {
|
|
100
|
+
className: "border-[var(--border)] bg-[var(--panel)] text-[var(--foreground)]",
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ jsxs(AlertDialogHeader, { children: [/* @__PURE__ */ jsx(AlertDialogTitle, { children: title }), /* @__PURE__ */ jsx(AlertDialogDescription, {
|
|
103
|
+
className: "text-[var(--muted-foreground)]",
|
|
104
|
+
children: description
|
|
105
|
+
})] }),
|
|
106
|
+
showDeleteSessionFilesOption ? /* @__PURE__ */ jsxs("div", {
|
|
107
|
+
className: "flex items-start gap-3 rounded-xl border border-[var(--border)] bg-[var(--background)]/70 px-4 py-3 text-sm",
|
|
108
|
+
children: [/* @__PURE__ */ jsx(Checkbox$1, {
|
|
109
|
+
"aria-describedby": checkboxDescriptionId,
|
|
110
|
+
checked: deleteSessionFiles,
|
|
111
|
+
id: checkboxId,
|
|
112
|
+
onCheckedChange: (checked) => setDeleteSessionFiles(checked === true)
|
|
113
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
114
|
+
className: "space-y-1",
|
|
115
|
+
children: [/* @__PURE__ */ jsx("label", {
|
|
116
|
+
className: "block font-medium",
|
|
117
|
+
htmlFor: checkboxId,
|
|
118
|
+
children: "Delete Session files"
|
|
119
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
120
|
+
className: "block text-[var(--muted-foreground)] text-xs",
|
|
121
|
+
id: checkboxDescriptionId,
|
|
122
|
+
children: "Remove the rollout JSONL from disk as well, so Codex cannot backfill this thread later."
|
|
123
|
+
})]
|
|
124
|
+
})]
|
|
125
|
+
}) : null,
|
|
126
|
+
/* @__PURE__ */ jsxs(AlertDialogFooter, { children: [/* @__PURE__ */ jsx(AlertDialogCancel, {
|
|
127
|
+
className: "border-[var(--border)]",
|
|
128
|
+
children: "Cancel"
|
|
129
|
+
}), /* @__PURE__ */ jsx(AlertDialogAction, {
|
|
130
|
+
className: "bg-[var(--destructive)] text-[var(--destructive-foreground)] hover:bg-[var(--destructive)]/90",
|
|
131
|
+
onClick: () => onConfirm({ deleteSessionFiles }),
|
|
132
|
+
children: confirmLabel
|
|
133
|
+
})] })
|
|
134
|
+
]
|
|
135
|
+
})
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
//#endregion
|
|
139
|
+
export { DeleteConfirmDialog as t };
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
import { t as cn } from "./utils-C_uf36nf.js";
|
|
2
|
+
import { t as Button } from "./button-CmTDnzOn.js";
|
|
3
|
+
import { t as Checkbox$1 } from "./checkbox-C0hovF41.js";
|
|
4
|
+
import { a as SelectValue, i as SelectTrigger, n as SelectContent, r as SelectItem, t as Select$1 } from "./select-GW76p-ld.js";
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { XIcon } from "lucide-react";
|
|
8
|
+
import { Dialog } from "radix-ui";
|
|
9
|
+
//#region src/components/ui/dialog.tsx
|
|
10
|
+
function Dialog$1({ ...props }) {
|
|
11
|
+
return /* @__PURE__ */ jsx(Dialog.Root, {
|
|
12
|
+
"data-slot": "dialog",
|
|
13
|
+
...props
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function DialogPortal({ ...props }) {
|
|
17
|
+
return /* @__PURE__ */ jsx(Dialog.Portal, {
|
|
18
|
+
"data-slot": "dialog-portal",
|
|
19
|
+
...props
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function DialogOverlay({ className, ...props }) {
|
|
23
|
+
return /* @__PURE__ */ jsx(Dialog.Overlay, {
|
|
24
|
+
"data-slot": "dialog-overlay",
|
|
25
|
+
className: cn("data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/50 data-[state=closed]:animate-out data-[state=open]:animate-in", className),
|
|
26
|
+
...props
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function DialogContent({ className, children, showCloseButton = true, ...props }) {
|
|
30
|
+
return /* @__PURE__ */ jsxs(DialogPortal, {
|
|
31
|
+
"data-slot": "dialog-portal",
|
|
32
|
+
children: [/* @__PURE__ */ jsx(DialogOverlay, {}), /* @__PURE__ */ jsxs(Dialog.Content, {
|
|
33
|
+
"data-slot": "dialog-content",
|
|
34
|
+
className: cn("data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-4 rounded-lg border bg-background p-6 shadow-lg outline-none duration-200 data-[state=closed]:animate-out data-[state=open]:animate-in sm:max-w-lg", className),
|
|
35
|
+
...props,
|
|
36
|
+
children: [children, showCloseButton && /* @__PURE__ */ jsxs(Dialog.Close, {
|
|
37
|
+
"data-slot": "dialog-close",
|
|
38
|
+
className: "absolute top-4 right-4 rounded-xs opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-hidden focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground [&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
|
|
39
|
+
children: [/* @__PURE__ */ jsx(XIcon, {}), /* @__PURE__ */ jsx("span", {
|
|
40
|
+
className: "sr-only",
|
|
41
|
+
children: "Close"
|
|
42
|
+
})]
|
|
43
|
+
})]
|
|
44
|
+
})]
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
function DialogHeader({ className, ...props }) {
|
|
48
|
+
return /* @__PURE__ */ jsx("div", {
|
|
49
|
+
"data-slot": "dialog-header",
|
|
50
|
+
className: cn("flex flex-col gap-2 text-center sm:text-left", className),
|
|
51
|
+
...props
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
function DialogFooter({ className, showCloseButton = false, children, ...props }) {
|
|
55
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
56
|
+
"data-slot": "dialog-footer",
|
|
57
|
+
className: cn("flex flex-col-reverse gap-2 sm:flex-row sm:justify-end", className),
|
|
58
|
+
...props,
|
|
59
|
+
children: [children, showCloseButton && /* @__PURE__ */ jsx(Dialog.Close, {
|
|
60
|
+
asChild: true,
|
|
61
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
62
|
+
variant: "outline",
|
|
63
|
+
children: "Close"
|
|
64
|
+
})
|
|
65
|
+
})]
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
function DialogTitle({ className, ...props }) {
|
|
69
|
+
return /* @__PURE__ */ jsx(Dialog.Title, {
|
|
70
|
+
"data-slot": "dialog-title",
|
|
71
|
+
className: cn("font-semibold text-lg leading-none", className),
|
|
72
|
+
...props
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
function DialogDescription({ className, ...props }) {
|
|
76
|
+
return /* @__PURE__ */ jsx(Dialog.Description, {
|
|
77
|
+
"data-slot": "dialog-description",
|
|
78
|
+
className: cn("text-muted-foreground text-sm", className),
|
|
79
|
+
...props
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
//#endregion
|
|
83
|
+
//#region src/components/export-dialog.tsx
|
|
84
|
+
function ExportDialog({ open, pending = false, title = "Export thread", onExport, onOpenChange }) {
|
|
85
|
+
const [outputFormat, setOutputFormat] = useState("md");
|
|
86
|
+
const [optimized, setOptimized] = useState(false);
|
|
87
|
+
const [includeCommentary, setIncludeCommentary] = useState(false);
|
|
88
|
+
const [includeTools, setIncludeTools] = useState(true);
|
|
89
|
+
return /* @__PURE__ */ jsx(Dialog$1, {
|
|
90
|
+
open,
|
|
91
|
+
onOpenChange,
|
|
92
|
+
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
93
|
+
className: "border-[var(--border)] bg-[var(--panel)] text-[var(--foreground)]",
|
|
94
|
+
children: [
|
|
95
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [/* @__PURE__ */ jsx(DialogTitle, { children: title }), /* @__PURE__ */ jsx(DialogDescription, {
|
|
96
|
+
className: "text-[var(--muted-foreground)]",
|
|
97
|
+
children: "Choose the transcript format and whether the export includes tool calls."
|
|
98
|
+
})] }),
|
|
99
|
+
/* @__PURE__ */ jsxs("div", {
|
|
100
|
+
className: "space-y-5 py-2",
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ jsxs("div", {
|
|
103
|
+
className: "space-y-2",
|
|
104
|
+
children: [/* @__PURE__ */ jsx("label", {
|
|
105
|
+
className: "font-medium text-sm",
|
|
106
|
+
htmlFor: "output-format",
|
|
107
|
+
children: "Output format"
|
|
108
|
+
}), /* @__PURE__ */ jsxs(Select$1, {
|
|
109
|
+
value: outputFormat,
|
|
110
|
+
onValueChange: (value) => setOutputFormat(value),
|
|
111
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, {
|
|
112
|
+
id: "output-format",
|
|
113
|
+
className: "border-[var(--border)] bg-[var(--panel-secondary)]",
|
|
114
|
+
children: /* @__PURE__ */ jsx(SelectValue, { placeholder: "Choose a format" })
|
|
115
|
+
}), /* @__PURE__ */ jsxs(SelectContent, { children: [/* @__PURE__ */ jsx(SelectItem, {
|
|
116
|
+
value: "md",
|
|
117
|
+
children: "Markdown (.md)"
|
|
118
|
+
}), /* @__PURE__ */ jsx(SelectItem, {
|
|
119
|
+
value: "txt",
|
|
120
|
+
children: "Plain text (.txt)"
|
|
121
|
+
})] })]
|
|
122
|
+
})]
|
|
123
|
+
}),
|
|
124
|
+
/* @__PURE__ */ jsxs("div", {
|
|
125
|
+
className: "flex items-center gap-3 rounded-2xl border border-[var(--border)] bg-[var(--panel-secondary)] p-3",
|
|
126
|
+
children: [/* @__PURE__ */ jsx(Checkbox$1, {
|
|
127
|
+
"aria-label": "Optimized transcript",
|
|
128
|
+
checked: optimized,
|
|
129
|
+
onCheckedChange: (checked) => setOptimized(checked === true)
|
|
130
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
131
|
+
className: "space-y-1",
|
|
132
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
133
|
+
className: "block font-medium text-sm",
|
|
134
|
+
children: "Optimized transcript"
|
|
135
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
136
|
+
className: "block text-[var(--muted-foreground)] text-sm",
|
|
137
|
+
children: "Removes metadata and condenses the transcript for readability and token efficiency."
|
|
138
|
+
})]
|
|
139
|
+
})]
|
|
140
|
+
}),
|
|
141
|
+
/* @__PURE__ */ jsxs("div", {
|
|
142
|
+
className: "flex items-center gap-3 rounded-2xl border border-[var(--border)] bg-[var(--panel-secondary)] p-3",
|
|
143
|
+
children: [/* @__PURE__ */ jsx(Checkbox$1, {
|
|
144
|
+
"aria-label": "Include commentary",
|
|
145
|
+
checked: includeCommentary,
|
|
146
|
+
onCheckedChange: (checked) => setIncludeCommentary(checked === true)
|
|
147
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
148
|
+
className: "space-y-1",
|
|
149
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
150
|
+
className: "block font-medium text-sm",
|
|
151
|
+
children: "Include commentary"
|
|
152
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
153
|
+
className: "block text-[var(--muted-foreground)] text-sm",
|
|
154
|
+
children: "Includes assistant commentary-phase updates in the exported transcript."
|
|
155
|
+
})]
|
|
156
|
+
})]
|
|
157
|
+
}),
|
|
158
|
+
/* @__PURE__ */ jsxs("div", {
|
|
159
|
+
className: "flex items-center gap-3 rounded-2xl border border-[var(--border)] bg-[var(--panel-secondary)] p-3",
|
|
160
|
+
children: [/* @__PURE__ */ jsx(Checkbox$1, {
|
|
161
|
+
"aria-label": "Include tool calls",
|
|
162
|
+
checked: includeTools,
|
|
163
|
+
onCheckedChange: (checked) => setIncludeTools(checked === true)
|
|
164
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
165
|
+
className: "space-y-1",
|
|
166
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
167
|
+
className: "block font-medium text-sm",
|
|
168
|
+
children: "Include tool calls"
|
|
169
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
170
|
+
className: "block text-[var(--muted-foreground)] text-sm",
|
|
171
|
+
children: "Includes tool-call summaries and tool-output summaries in the export."
|
|
172
|
+
})]
|
|
173
|
+
})]
|
|
174
|
+
})
|
|
175
|
+
]
|
|
176
|
+
}),
|
|
177
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button, {
|
|
178
|
+
className: "rounded-full",
|
|
179
|
+
variant: "outline",
|
|
180
|
+
onClick: () => onOpenChange(false),
|
|
181
|
+
children: "Cancel"
|
|
182
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
183
|
+
className: "rounded-full",
|
|
184
|
+
disabled: pending,
|
|
185
|
+
onClick: () => onExport({
|
|
186
|
+
includeCommentary,
|
|
187
|
+
includeTools,
|
|
188
|
+
optimized,
|
|
189
|
+
outputFormat
|
|
190
|
+
}),
|
|
191
|
+
children: pending ? "Exporting..." : "Download export"
|
|
192
|
+
})] })
|
|
193
|
+
]
|
|
194
|
+
})
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
//#endregion
|
|
198
|
+
//#region src/lib/download.ts
|
|
199
|
+
var DEFAULT_DOWNLOAD_ATTEMPTS = 6;
|
|
200
|
+
var DEFAULT_DOWNLOAD_RETRY_DELAY_MS = 250;
|
|
201
|
+
var DEFAULT_INLINE_REVOKE_DELAY_MS = 3e4;
|
|
202
|
+
var logDownloadEvent = (logger, level, event, details) => {
|
|
203
|
+
logger[level](`[spiracha:download] ${event}`, details);
|
|
204
|
+
};
|
|
205
|
+
var delay = (delayMs) => new Promise((resolve) => {
|
|
206
|
+
window.setTimeout(resolve, delayMs);
|
|
207
|
+
});
|
|
208
|
+
var triggerAnchorDownload = (documentRef, href, fileName) => {
|
|
209
|
+
const link = documentRef.createElement("a");
|
|
210
|
+
link.href = href;
|
|
211
|
+
link.download = fileName;
|
|
212
|
+
documentRef.body.append(link);
|
|
213
|
+
link.click();
|
|
214
|
+
link.remove();
|
|
215
|
+
};
|
|
216
|
+
var isReadyStatus = (status) => {
|
|
217
|
+
return status >= 200 && status < 400 || status === 405;
|
|
218
|
+
};
|
|
219
|
+
var waitForDownloadUrlAvailability = async (downloadUrl, fileName, { fetchImpl = fetch, logger = console, maxAttempts = DEFAULT_DOWNLOAD_ATTEMPTS, retryDelayMs = DEFAULT_DOWNLOAD_RETRY_DELAY_MS, sleep = delay } = {}) => {
|
|
220
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
221
|
+
try {
|
|
222
|
+
const response = await fetchImpl(downloadUrl, {
|
|
223
|
+
cache: "no-store",
|
|
224
|
+
method: "HEAD"
|
|
225
|
+
});
|
|
226
|
+
if (isReadyStatus(response.status)) {
|
|
227
|
+
logDownloadEvent(logger, "info", "url_ready", {
|
|
228
|
+
attempt,
|
|
229
|
+
downloadUrl,
|
|
230
|
+
fileName,
|
|
231
|
+
status: response.status
|
|
232
|
+
});
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
logDownloadEvent(logger, "warn", "url_not_ready", {
|
|
236
|
+
attempt,
|
|
237
|
+
downloadUrl,
|
|
238
|
+
fileName,
|
|
239
|
+
status: response.status
|
|
240
|
+
});
|
|
241
|
+
} catch (error) {
|
|
242
|
+
logDownloadEvent(logger, "warn", "url_probe_failed", {
|
|
243
|
+
attempt,
|
|
244
|
+
downloadUrl,
|
|
245
|
+
error: error instanceof Error ? error.message : String(error),
|
|
246
|
+
fileName
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
if (attempt < maxAttempts) await sleep(retryDelayMs);
|
|
250
|
+
}
|
|
251
|
+
throw new Error(`Download file was not available after ${maxAttempts} attempts: ${fileName}`);
|
|
252
|
+
};
|
|
253
|
+
var downloadUrlFile = async (fileName, downloadUrl, { documentRef = document, fetchImpl = fetch, logger = console, maxAttempts = DEFAULT_DOWNLOAD_ATTEMPTS, retryDelayMs = DEFAULT_DOWNLOAD_RETRY_DELAY_MS, sleep = delay } = {}) => {
|
|
254
|
+
logDownloadEvent(logger, "info", "start", {
|
|
255
|
+
downloadUrl,
|
|
256
|
+
fileName
|
|
257
|
+
});
|
|
258
|
+
await waitForDownloadUrlAvailability(downloadUrl, fileName, {
|
|
259
|
+
fetchImpl,
|
|
260
|
+
logger,
|
|
261
|
+
maxAttempts,
|
|
262
|
+
retryDelayMs,
|
|
263
|
+
sleep
|
|
264
|
+
});
|
|
265
|
+
triggerAnchorDownload(documentRef, downloadUrl, fileName);
|
|
266
|
+
logDownloadEvent(logger, "info", "triggered", {
|
|
267
|
+
downloadUrl,
|
|
268
|
+
fileName
|
|
269
|
+
});
|
|
270
|
+
};
|
|
271
|
+
var downloadTextFile = (fileName, content, mimeType, { createObjectUrl = (blob) => URL.createObjectURL(blob), documentRef = document, logger = console, revokeDelayMs = DEFAULT_INLINE_REVOKE_DELAY_MS, revokeObjectUrl = (url) => URL.revokeObjectURL(url), schedule = (callback, delayMs) => {
|
|
272
|
+
window.setTimeout(callback, delayMs);
|
|
273
|
+
} } = {}) => {
|
|
274
|
+
logDownloadEvent(logger, "info", "inline_start", {
|
|
275
|
+
fileName,
|
|
276
|
+
mimeType,
|
|
277
|
+
sizeBytes: content.length
|
|
278
|
+
});
|
|
279
|
+
const url = createObjectUrl(new Blob([content], { type: mimeType }));
|
|
280
|
+
triggerAnchorDownload(documentRef, url, fileName);
|
|
281
|
+
schedule(() => revokeObjectUrl(url), revokeDelayMs);
|
|
282
|
+
logDownloadEvent(logger, "info", "inline_triggered", {
|
|
283
|
+
fileName,
|
|
284
|
+
mimeType,
|
|
285
|
+
sizeBytes: content.length
|
|
286
|
+
});
|
|
287
|
+
};
|
|
288
|
+
//#endregion
|
|
289
|
+
export { downloadUrlFile as n, ExportDialog as r, downloadTextFile as t };
|