spiracha 1.0.0 → 1.1.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 +28 -1
- package/README.md +47 -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-BjYaHqXk.js +1 -0
- package/apps/ui/dist/client/assets/checkbox-wPoGG3of.js +1 -0
- package/apps/ui/dist/client/assets/data-table-6yDgAdtf.js +4 -0
- package/apps/ui/dist/client/assets/delete-confirm-dialog-DJUAk7ha.js +11 -0
- package/apps/ui/dist/client/assets/download-BhWd-Pm5.js +1 -0
- package/apps/ui/dist/client/assets/es2015-BlyMI4CF.js +41 -0
- package/apps/ui/dist/client/assets/formatters-BxjZwWSE.js +1 -0
- package/apps/ui/dist/client/assets/index-T01rPkb4.js +22 -0
- package/apps/ui/dist/client/assets/input-B3YN8gzg.js +1 -0
- package/apps/ui/dist/client/assets/metric-card-BWW7TWER.js +1 -0
- package/apps/ui/dist/client/assets/page-header-BZ8Gnxgs.js +1 -0
- package/apps/ui/dist/client/assets/projects._project-B7XcpoLt.js +1 -0
- package/apps/ui/dist/client/assets/projects._project-EfBhCHPY.js +1 -0
- package/apps/ui/dist/client/assets/projects.index-4vfIwLjw.js +1 -0
- package/apps/ui/dist/client/assets/projects.index-DzEZ4pAJ.js +1 -0
- package/apps/ui/dist/client/assets/routes-CWCCZykE.js +1 -0
- package/apps/ui/dist/client/assets/select-DLXGsyZ4.js +1 -0
- package/apps/ui/dist/client/assets/settings-b0Xthfae.js +1 -0
- package/apps/ui/dist/client/assets/styles-8Wtc8YJw.css +1 -0
- package/apps/ui/dist/client/assets/threads._threadId-CgtoCqTb.js +1 -0
- package/apps/ui/dist/client/assets/threads._threadId-DBiDb38K.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-BjsXNYgm.js +99 -0
- package/apps/ui/dist/server/assets/_threadId-B6SrBR9E.js +6 -0
- package/apps/ui/dist/server/assets/analytics-Br_fZB6a.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-Cqh0hb93.js +1995 -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-CzHmFWGk.js +286 -0
- package/apps/ui/dist/server/assets/formatters-B6o5pTY9.js +72 -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/page-header-CxdZM86z.js +25 -0
- package/apps/ui/dist/server/assets/path-transforms-DD1e7rhY.js +31 -0
- package/apps/ui/dist/server/assets/projects._project-Bwf6iJC-.js +335 -0
- package/apps/ui/dist/server/assets/projects._project-CLSohrBp.js +26 -0
- package/apps/ui/dist/server/assets/projects._project-DdVSdfPe.js +18 -0
- package/apps/ui/dist/server/assets/projects.index-CaplpeMy.js +26 -0
- package/apps/ui/dist/server/assets/projects.index-DKeVeqUZ.js +171 -0
- package/apps/ui/dist/server/assets/router-ve2Hrl2Y.js +307 -0
- package/apps/ui/dist/server/assets/routes-BJyx5OmO.js +34 -0
- package/apps/ui/dist/server/assets/routes-pkOwjjYc.js +168 -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-BAvbjjfs.js +4 -0
- package/apps/ui/dist/server/assets/threads._threadId-BSSK4nkI.js +26 -0
- package/apps/ui/dist/server/assets/threads._threadId-D3PYZIwl.js +18 -0
- package/apps/ui/dist/server/assets/threads._threadId-D3xaWM86.js +1037 -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 +47 -7
- package/src/export-chats.ts +1 -14
- package/src/lib/codex-analytics.ts +100 -0
- package/src/lib/codex-browser-db.ts +518 -0
- package/src/lib/codex-browser-export.ts +418 -0
- package/src/lib/codex-browser-types.ts +224 -0
- package/src/lib/codex-exporter-cli.ts +5 -0
- package/src/lib/codex-exporter-transcript.ts +143 -32
- 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 +5 -13
- package/src/lib/native-open.ts +54 -0
- package/src/lib/path-transforms.ts +45 -0
- package/src/lib/shared.ts +37 -1
- package/src/lib/sqlite-error.ts +14 -0
- package/src/lib/sqlite-retry.ts +39 -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 +14 -1
- 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,286 @@
|
|
|
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
|
+
checked: optimized,
|
|
128
|
+
onCheckedChange: (checked) => setOptimized(checked === true)
|
|
129
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
130
|
+
className: "space-y-1",
|
|
131
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
132
|
+
className: "block font-medium text-sm",
|
|
133
|
+
children: "Optimized transcript"
|
|
134
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
135
|
+
className: "block text-[var(--muted-foreground)] text-sm",
|
|
136
|
+
children: "Removes metadata and condenses the transcript for readability and token efficiency."
|
|
137
|
+
})]
|
|
138
|
+
})]
|
|
139
|
+
}),
|
|
140
|
+
/* @__PURE__ */ jsxs("div", {
|
|
141
|
+
className: "flex items-center gap-3 rounded-2xl border border-[var(--border)] bg-[var(--panel-secondary)] p-3",
|
|
142
|
+
children: [/* @__PURE__ */ jsx(Checkbox$1, {
|
|
143
|
+
checked: includeCommentary,
|
|
144
|
+
onCheckedChange: (checked) => setIncludeCommentary(checked === true)
|
|
145
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
146
|
+
className: "space-y-1",
|
|
147
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
148
|
+
className: "block font-medium text-sm",
|
|
149
|
+
children: "Include commentary"
|
|
150
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
151
|
+
className: "block text-[var(--muted-foreground)] text-sm",
|
|
152
|
+
children: "Includes assistant commentary-phase updates in the exported transcript."
|
|
153
|
+
})]
|
|
154
|
+
})]
|
|
155
|
+
}),
|
|
156
|
+
/* @__PURE__ */ jsxs("div", {
|
|
157
|
+
className: "flex items-center gap-3 rounded-2xl border border-[var(--border)] bg-[var(--panel-secondary)] p-3",
|
|
158
|
+
children: [/* @__PURE__ */ jsx(Checkbox$1, {
|
|
159
|
+
checked: includeTools,
|
|
160
|
+
onCheckedChange: (checked) => setIncludeTools(checked === true)
|
|
161
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
162
|
+
className: "space-y-1",
|
|
163
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
164
|
+
className: "block font-medium text-sm",
|
|
165
|
+
children: "Include tool calls"
|
|
166
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
167
|
+
className: "block text-[var(--muted-foreground)] text-sm",
|
|
168
|
+
children: "Includes tool-call summaries and tool-output summaries in the export."
|
|
169
|
+
})]
|
|
170
|
+
})]
|
|
171
|
+
})
|
|
172
|
+
]
|
|
173
|
+
}),
|
|
174
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [/* @__PURE__ */ jsx(Button, {
|
|
175
|
+
className: "rounded-full",
|
|
176
|
+
variant: "outline",
|
|
177
|
+
onClick: () => onOpenChange(false),
|
|
178
|
+
children: "Cancel"
|
|
179
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
180
|
+
className: "rounded-full",
|
|
181
|
+
disabled: pending,
|
|
182
|
+
onClick: () => onExport({
|
|
183
|
+
includeCommentary,
|
|
184
|
+
includeTools,
|
|
185
|
+
optimized,
|
|
186
|
+
outputFormat
|
|
187
|
+
}),
|
|
188
|
+
children: pending ? "Exporting..." : "Download export"
|
|
189
|
+
})] })
|
|
190
|
+
]
|
|
191
|
+
})
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
//#endregion
|
|
195
|
+
//#region src/lib/download.ts
|
|
196
|
+
var DEFAULT_DOWNLOAD_ATTEMPTS = 6;
|
|
197
|
+
var DEFAULT_DOWNLOAD_RETRY_DELAY_MS = 250;
|
|
198
|
+
var DEFAULT_INLINE_REVOKE_DELAY_MS = 3e4;
|
|
199
|
+
var logDownloadEvent = (logger, level, event, details) => {
|
|
200
|
+
logger[level](`[spiracha:download] ${event}`, details);
|
|
201
|
+
};
|
|
202
|
+
var delay = (delayMs) => new Promise((resolve) => {
|
|
203
|
+
window.setTimeout(resolve, delayMs);
|
|
204
|
+
});
|
|
205
|
+
var triggerAnchorDownload = (documentRef, href, fileName) => {
|
|
206
|
+
const link = documentRef.createElement("a");
|
|
207
|
+
link.href = href;
|
|
208
|
+
link.download = fileName;
|
|
209
|
+
documentRef.body.append(link);
|
|
210
|
+
link.click();
|
|
211
|
+
link.remove();
|
|
212
|
+
};
|
|
213
|
+
var isReadyStatus = (status) => {
|
|
214
|
+
return status >= 200 && status < 400 || status === 405;
|
|
215
|
+
};
|
|
216
|
+
var waitForDownloadUrlAvailability = async (downloadUrl, fileName, { fetchImpl = fetch, logger = console, maxAttempts = DEFAULT_DOWNLOAD_ATTEMPTS, retryDelayMs = DEFAULT_DOWNLOAD_RETRY_DELAY_MS, sleep = delay } = {}) => {
|
|
217
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
218
|
+
try {
|
|
219
|
+
const response = await fetchImpl(downloadUrl, {
|
|
220
|
+
cache: "no-store",
|
|
221
|
+
method: "HEAD"
|
|
222
|
+
});
|
|
223
|
+
if (isReadyStatus(response.status)) {
|
|
224
|
+
logDownloadEvent(logger, "info", "url_ready", {
|
|
225
|
+
attempt,
|
|
226
|
+
downloadUrl,
|
|
227
|
+
fileName,
|
|
228
|
+
status: response.status
|
|
229
|
+
});
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
logDownloadEvent(logger, "warn", "url_not_ready", {
|
|
233
|
+
attempt,
|
|
234
|
+
downloadUrl,
|
|
235
|
+
fileName,
|
|
236
|
+
status: response.status
|
|
237
|
+
});
|
|
238
|
+
} catch (error) {
|
|
239
|
+
logDownloadEvent(logger, "warn", "url_probe_failed", {
|
|
240
|
+
attempt,
|
|
241
|
+
downloadUrl,
|
|
242
|
+
error: error instanceof Error ? error.message : String(error),
|
|
243
|
+
fileName
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
if (attempt < maxAttempts) await sleep(retryDelayMs);
|
|
247
|
+
}
|
|
248
|
+
throw new Error(`Download file was not available after ${maxAttempts} attempts: ${fileName}`);
|
|
249
|
+
};
|
|
250
|
+
var downloadUrlFile = async (fileName, downloadUrl, { documentRef = document, fetchImpl = fetch, logger = console, maxAttempts = DEFAULT_DOWNLOAD_ATTEMPTS, retryDelayMs = DEFAULT_DOWNLOAD_RETRY_DELAY_MS, sleep = delay } = {}) => {
|
|
251
|
+
logDownloadEvent(logger, "info", "start", {
|
|
252
|
+
downloadUrl,
|
|
253
|
+
fileName
|
|
254
|
+
});
|
|
255
|
+
await waitForDownloadUrlAvailability(downloadUrl, fileName, {
|
|
256
|
+
fetchImpl,
|
|
257
|
+
logger,
|
|
258
|
+
maxAttempts,
|
|
259
|
+
retryDelayMs,
|
|
260
|
+
sleep
|
|
261
|
+
});
|
|
262
|
+
triggerAnchorDownload(documentRef, downloadUrl, fileName);
|
|
263
|
+
logDownloadEvent(logger, "info", "triggered", {
|
|
264
|
+
downloadUrl,
|
|
265
|
+
fileName
|
|
266
|
+
});
|
|
267
|
+
};
|
|
268
|
+
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) => {
|
|
269
|
+
window.setTimeout(callback, delayMs);
|
|
270
|
+
} } = {}) => {
|
|
271
|
+
logDownloadEvent(logger, "info", "inline_start", {
|
|
272
|
+
fileName,
|
|
273
|
+
mimeType,
|
|
274
|
+
sizeBytes: content.length
|
|
275
|
+
});
|
|
276
|
+
const url = createObjectUrl(new Blob([content], { type: mimeType }));
|
|
277
|
+
triggerAnchorDownload(documentRef, url, fileName);
|
|
278
|
+
schedule(() => revokeObjectUrl(url), revokeDelayMs);
|
|
279
|
+
logDownloadEvent(logger, "info", "inline_triggered", {
|
|
280
|
+
fileName,
|
|
281
|
+
mimeType,
|
|
282
|
+
sizeBytes: content.length
|
|
283
|
+
});
|
|
284
|
+
};
|
|
285
|
+
//#endregion
|
|
286
|
+
export { downloadUrlFile as n, ExportDialog as r, downloadTextFile as t };
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
//#region src/lib/formatters.ts
|
|
2
|
+
var MONTHS = [
|
|
3
|
+
"Jan",
|
|
4
|
+
"Feb",
|
|
5
|
+
"Mar",
|
|
6
|
+
"Apr",
|
|
7
|
+
"May",
|
|
8
|
+
"Jun",
|
|
9
|
+
"Jul",
|
|
10
|
+
"Aug",
|
|
11
|
+
"Sep",
|
|
12
|
+
"Oct",
|
|
13
|
+
"Nov",
|
|
14
|
+
"Dec"
|
|
15
|
+
];
|
|
16
|
+
var formatNumber = (value) => {
|
|
17
|
+
return new Intl.NumberFormat("en-US").format(value);
|
|
18
|
+
};
|
|
19
|
+
var formatTokens = (value) => {
|
|
20
|
+
return `${formatNumber(value)} tokens`;
|
|
21
|
+
};
|
|
22
|
+
var formatBytes = (value) => {
|
|
23
|
+
if (!value || value <= 0) return "0 B";
|
|
24
|
+
const units = [
|
|
25
|
+
"B",
|
|
26
|
+
"KB",
|
|
27
|
+
"MB",
|
|
28
|
+
"GB",
|
|
29
|
+
"TB"
|
|
30
|
+
];
|
|
31
|
+
let size = value;
|
|
32
|
+
let unitIndex = 0;
|
|
33
|
+
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
34
|
+
size /= 1024;
|
|
35
|
+
unitIndex += 1;
|
|
36
|
+
}
|
|
37
|
+
const fractionDigits = size >= 100 || unitIndex === 0 ? 0 : 1;
|
|
38
|
+
return `${size.toFixed(fractionDigits)} ${units[unitIndex]}`;
|
|
39
|
+
};
|
|
40
|
+
var formatDateTime = (value) => {
|
|
41
|
+
if (value === null || value === void 0 || value === "") return "n/a";
|
|
42
|
+
const date = typeof value === "number" ? new Date(value) : new Date(value);
|
|
43
|
+
if (Number.isNaN(date.getTime())) return "n/a";
|
|
44
|
+
const today = /* @__PURE__ */ new Date();
|
|
45
|
+
const isToday = date.getUTCDate() === today.getUTCDate() && date.getUTCMonth() === today.getUTCMonth() && date.getUTCFullYear() === today.getUTCFullYear();
|
|
46
|
+
const month = MONTHS[date.getUTCMonth()];
|
|
47
|
+
const day = date.getUTCDate();
|
|
48
|
+
const hours12 = date.getUTCHours() % 12 || 12;
|
|
49
|
+
const minutes = String(date.getUTCMinutes()).padStart(2, "0");
|
|
50
|
+
const ampm = date.getUTCHours() >= 12 ? "PM" : "AM";
|
|
51
|
+
if (isToday) return `${hours12}:${minutes} ${ampm}`;
|
|
52
|
+
return `${month} ${day} · ${hours12}:${minutes} ${ampm}`;
|
|
53
|
+
};
|
|
54
|
+
var formatList = (values) => {
|
|
55
|
+
if (values.length === 0) return "n/a";
|
|
56
|
+
return values.join(", ");
|
|
57
|
+
};
|
|
58
|
+
var formatBooleanLabel = (value) => {
|
|
59
|
+
return value ? "Yes" : "No";
|
|
60
|
+
};
|
|
61
|
+
var formatModelLabel = (value) => {
|
|
62
|
+
if (!value) return "Assistant";
|
|
63
|
+
return value.split(/[-_\s]+/u).filter(Boolean).map((part) => {
|
|
64
|
+
const lower = part.toLowerCase();
|
|
65
|
+
if (lower === "gpt") return "GPT";
|
|
66
|
+
if (/^[a-z]\d$/u.test(lower)) return lower.toUpperCase();
|
|
67
|
+
if (/^\d+(\.\d+)*$/u.test(part)) return part;
|
|
68
|
+
return `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`;
|
|
69
|
+
}).join(" ");
|
|
70
|
+
};
|
|
71
|
+
//#endregion
|
|
72
|
+
export { formatModelLabel as a, formatList as i, formatBytes as n, formatNumber as o, formatDateTime as r, formatTokens as s, formatBooleanLabel as t };
|