spiracha 1.4.0 → 1.5.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.
Files changed (159) hide show
  1. package/AGENTS.md +48 -5
  2. package/README.md +40 -5
  3. package/apps/ui/AGENTS.md +23 -4
  4. package/apps/ui/README.md +49 -2
  5. package/apps/ui/dist/client/assets/analytics-DOy1b6Sh.js +1 -0
  6. package/apps/ui/dist/client/assets/{antigravity-conversations._conversationId-DmD0sN8X.js → antigravity-conversations._conversationId-DqySVO2K.js} +2 -2
  7. package/apps/ui/dist/client/assets/antigravity-keychain-panel-B77qJz6f.js +1 -0
  8. package/apps/ui/dist/client/assets/antigravity._workspaceKey-B3NM6gRH.js +1 -0
  9. package/apps/ui/dist/client/assets/{antigravity.index-DEEkjlZa.js → antigravity.index-DP9JC2P9.js} +1 -1
  10. package/apps/ui/dist/client/assets/{badge-DfWvPfKF.js → badge-C3i4OKs8.js} +1 -1
  11. package/apps/ui/dist/client/assets/claude-code-sessions._sessionId-8pQ55ci2.js +1 -0
  12. package/apps/ui/dist/client/assets/claude-code-sessions._sessionId-DVz5UmtU.js +1 -0
  13. package/apps/ui/dist/client/assets/claude-code._workspaceKey-BBKskSum.js +1 -0
  14. package/apps/ui/dist/client/assets/claude-code._workspaceKey-OkikMUFs.js +1 -0
  15. package/apps/ui/dist/client/assets/claude-code.index-Cwu76dbb.js +1 -0
  16. package/apps/ui/dist/client/assets/claude-code.index-D6eMd08t.js +1 -0
  17. package/apps/ui/dist/client/assets/createServerFn-B-KkwmHU.js +3 -0
  18. package/apps/ui/dist/client/assets/cursor-threads._composerId-hBWlP1D-.js +1 -0
  19. package/apps/ui/dist/client/assets/cursor._workspaceKey-BFPkIRi-.js +1 -0
  20. package/apps/ui/dist/client/assets/cursor.index-8y4o20kb.js +2 -0
  21. package/apps/ui/dist/client/assets/delete-confirm-dialog-Bxs07u-j.js +7 -0
  22. package/apps/ui/dist/client/assets/dist-BrJhN2A0.js +5 -0
  23. package/apps/ui/dist/client/assets/{dist-BhZOxAPP.js → dist-Cmd3AIfD.js} +1 -1
  24. package/apps/ui/dist/client/assets/dropdown-menu-D5cvPaZt.js +1 -0
  25. package/apps/ui/dist/client/assets/{es2015-BkCWttyM.js → es2015-ad6040dw.js} +1 -1
  26. package/apps/ui/dist/client/assets/export-dialog-Dr8d2MqD.js +1 -0
  27. package/apps/ui/dist/client/assets/{formatters-BM9kB7ed.js → formatters-BtqyrX_c.js} +1 -1
  28. package/apps/ui/dist/client/assets/index-C-STgIH4.js +166 -0
  29. package/apps/ui/dist/client/assets/kiro-sessions._sessionId-CKgfJ7GR.js +1 -0
  30. package/apps/ui/dist/client/assets/kiro-sessions._sessionId-zvIJHtQF.js +1 -0
  31. package/apps/ui/dist/client/assets/kiro._workspaceKey-DhVuJuZB.js +1 -0
  32. package/apps/ui/dist/client/assets/kiro._workspaceKey-QArsjkTY.js +1 -0
  33. package/apps/ui/dist/client/assets/kiro.index-C-fr4m7i.js +1 -0
  34. package/apps/ui/dist/client/assets/kiro.index-OYgAdtZd.js +1 -0
  35. package/apps/ui/dist/client/assets/opencode-sessions._sessionId-DLjiTst-.js +1 -0
  36. package/apps/ui/dist/client/assets/opencode-sessions._sessionId-biBwrRbt.js +8 -0
  37. package/apps/ui/dist/client/assets/opencode._workspaceKey-C7OIzMOJ.js +1 -0
  38. package/apps/ui/dist/client/assets/opencode._workspaceKey-sBakX0oI.js +1 -0
  39. package/apps/ui/dist/client/assets/opencode.index-Bl_kNs9N.js +1 -0
  40. package/apps/ui/dist/client/assets/opencode.index-CN53bVmb.js +1 -0
  41. package/apps/ui/dist/client/assets/preload-helper-B8fFrdxC.js +1 -0
  42. package/apps/ui/dist/client/assets/projects._project-D8WloxQN.js +1 -0
  43. package/apps/ui/dist/client/assets/projects.index-5xRtuJdX.js +3 -0
  44. package/apps/ui/dist/client/assets/routes-DnzF_9CX.js +1 -0
  45. package/apps/ui/dist/client/assets/select-CYF6pF37.js +1 -0
  46. package/apps/ui/dist/client/assets/settings-Dx70jgP_.js +1 -0
  47. package/apps/ui/dist/client/assets/styles-B7Zi9EFA.css +1 -0
  48. package/apps/ui/dist/client/assets/tabs-CmuhkT-c.js +7 -0
  49. package/apps/ui/dist/client/assets/thread-transcript-stats-BUNz6u7F.js +1 -0
  50. package/apps/ui/dist/client/assets/threads._threadId-BMRSFow3.js +1 -0
  51. package/apps/ui/dist/client/assets/useMutation-BSFult2i.js +1 -0
  52. package/apps/ui/dist/client/assets/useQuery-CjINKZf1.js +1 -0
  53. package/apps/ui/dist/client/icon.svg +2 -1
  54. package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-CQ8Jjs3B.js +387 -0
  55. package/apps/ui/dist/server/assets/{antigravity-conversations._conversationId-BtexWY-K.js → antigravity-conversations._conversationId-BKOyL2T6.js} +2 -2
  56. package/apps/ui/dist/server/assets/{antigravity-conversations._conversationId-zMrR6v6R.js → antigravity-conversations._conversationId-eS87Dx7g.js} +1 -1
  57. package/apps/ui/dist/server/assets/claude-code-db-Ik3VStKZ.js +361 -0
  58. package/apps/ui/dist/server/assets/claude-code-queries-Cgzi4K-e.js +37 -0
  59. package/apps/ui/dist/server/assets/claude-code-server-PfraClXS.js +72 -0
  60. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-C55oe6zj.js +18 -0
  61. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-D1RYYi3j.js +473 -0
  62. package/apps/ui/dist/server/assets/claude-code-sessions._sessionId-DSvPLEUL.js +11 -0
  63. package/apps/ui/dist/server/assets/claude-code-transcript-C-bxh3cS.js +139 -0
  64. package/apps/ui/dist/server/assets/claude-code-transcript-phase-DmUMc8VU.js +10 -0
  65. package/apps/ui/dist/server/assets/claude-code._workspaceKey-B5Xg_-tE.js +28 -0
  66. package/apps/ui/dist/server/assets/claude-code._workspaceKey-BPlzyXPa.js +11 -0
  67. package/apps/ui/dist/server/assets/claude-code._workspaceKey-DqDve2wl.js +191 -0
  68. package/apps/ui/dist/server/assets/claude-code.index-B7yYR7dD.js +92 -0
  69. package/apps/ui/dist/server/assets/claude-code.index-BUHThG1W.js +11 -0
  70. package/apps/ui/dist/server/assets/{codex-server-CNXSJuc2.js → codex-server-CGXU4H8-.js} +319 -29
  71. package/apps/ui/dist/server/assets/{cursor-db-cYZEU3WQ.js → cursor-db-CZnYy7aT.js} +3 -3
  72. package/apps/ui/dist/server/assets/{cursor-recovery-nq-kR62j.js → cursor-recovery-CXpO8KcD.js} +2 -2
  73. package/apps/ui/dist/server/assets/{cursor-server-C3q7hrp-.js → cursor-server-DNu52A3K.js} +13 -13
  74. package/apps/ui/dist/server/assets/{cursor-threads._composerId-BkMMTQ3v.js → cursor-threads._composerId-Ckn6ItHI.js} +3 -3
  75. package/apps/ui/dist/server/assets/{cursor-threads._composerId-BPJFWfJj.js → cursor-threads._composerId-p9-ARAzc.js} +1 -1
  76. package/apps/ui/dist/server/assets/{cursor-transcript-2iL3KFSK.js → cursor-transcript-B7tGnqtn.js} +1 -1
  77. package/apps/ui/dist/server/assets/{cursor._workspaceKey-C5PdTaKB.js → cursor._workspaceKey-CZuohIUL.js} +1 -1
  78. package/apps/ui/dist/server/assets/{cursor._workspaceKey-Ckj7apKI.js → cursor._workspaceKey-DPp5JSjy.js} +2 -2
  79. package/apps/ui/dist/server/assets/{export-dialog-BItjWgkZ.js → export-dialog-D88ze9Gy.js} +2 -2
  80. package/apps/ui/dist/server/assets/kiro-db--fXrED_-.js +552 -0
  81. package/apps/ui/dist/server/assets/kiro-queries-CzNlM2ok.js +37 -0
  82. package/apps/ui/dist/server/assets/kiro-server-9WRxg2Au.js +72 -0
  83. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-CRY2c7YO.js +11 -0
  84. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-F1UlwxmR.js +449 -0
  85. package/apps/ui/dist/server/assets/kiro-sessions._sessionId-bvTulT7C.js +18 -0
  86. package/apps/ui/dist/server/assets/kiro-transcript-DoekQBaH.js +112 -0
  87. package/apps/ui/dist/server/assets/kiro-transcript-phase-CJG40nQg.js +27 -0
  88. package/apps/ui/dist/server/assets/kiro._workspaceKey-BDe9sQwo.js +11 -0
  89. package/apps/ui/dist/server/assets/kiro._workspaceKey-CJsjgNwO.js +28 -0
  90. package/apps/ui/dist/server/assets/kiro._workspaceKey-D_-4Qb7y.js +193 -0
  91. package/apps/ui/dist/server/assets/kiro.index-C__-UROk.js +11 -0
  92. package/apps/ui/dist/server/assets/kiro.index-CmTbqeYj.js +93 -0
  93. package/apps/ui/dist/server/assets/opencode-db-BM7KjOzc.js +397 -0
  94. package/apps/ui/dist/server/assets/opencode-queries-BeNYXnQv.js +50 -0
  95. package/apps/ui/dist/server/assets/opencode-server-BpQ_kRze.js +72 -0
  96. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-CGQ-t0vD.js +518 -0
  97. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-D8Q7in_Z.js +18 -0
  98. package/apps/ui/dist/server/assets/opencode-sessions._sessionId-DKOvi0lV.js +11 -0
  99. package/apps/ui/dist/server/assets/opencode-think-tags-CAoD-EcZ.js +87 -0
  100. package/apps/ui/dist/server/assets/opencode-transcript-BNTcGNym.js +141 -0
  101. package/apps/ui/dist/server/assets/opencode-transcript-phase-OqLkiQD0.js +32 -0
  102. package/apps/ui/dist/server/assets/opencode._workspaceKey-BdqcWHw1.js +11 -0
  103. package/apps/ui/dist/server/assets/opencode._workspaceKey-CfH96HTT.js +28 -0
  104. package/apps/ui/dist/server/assets/opencode._workspaceKey-DdbHPDrO.js +207 -0
  105. package/apps/ui/dist/server/assets/opencode.index-BbVzkJXP.js +11 -0
  106. package/apps/ui/dist/server/assets/opencode.index-Vh_Gq_1L.js +93 -0
  107. package/apps/ui/dist/server/assets/{projects._project-Bpbc3C-L.js → projects._project-4io5LO0E.js} +1 -1
  108. package/apps/ui/dist/server/assets/{projects._project-CvZho6EQ.js → projects._project-D6ZoGhJ8.js} +2 -2
  109. package/apps/ui/dist/server/assets/{router-6m-ihwqA.js → router-Sac2DGk6.js} +157 -49
  110. package/apps/ui/dist/server/assets/{shared-CPRNYIql.js → shared-DyhChtHf.js} +4 -1
  111. package/apps/ui/dist/server/assets/source-session-export-server-DNutCawb.js +38 -0
  112. package/apps/ui/dist/server/assets/{start-CI_0bSiY.js → start-B_HFwkkk.js} +1 -1
  113. package/apps/ui/dist/server/assets/{tabs-CGA13IZM.js → tabs-DkaChNVg.js} +0 -1
  114. package/apps/ui/dist/server/assets/thread-transcript-stats-Dh34mt2u.js +45 -0
  115. package/apps/ui/dist/server/assets/{threads._threadId-D2GYkVn6.js → threads._threadId-BeXEc4Lo.js} +15 -6
  116. package/apps/ui/dist/server/assets/{threads._threadId-Bs0yuqO9.js → threads._threadId-Ci0S4mKU.js} +1 -1
  117. package/apps/ui/dist/server/server.js +72 -24
  118. package/package.json +21 -4
  119. package/src/lib/claude-code-db.ts +655 -0
  120. package/src/lib/claude-code-exporter-types.ts +110 -0
  121. package/src/lib/claude-code-transcript-phase.ts +25 -0
  122. package/src/lib/claude-code-transcript.ts +180 -0
  123. package/src/lib/codex-browser-db.ts +490 -31
  124. package/src/lib/codex-browser-export.ts +18 -2
  125. package/src/lib/codex-thread-cache.ts +17 -1
  126. package/src/lib/concurrency.ts +25 -0
  127. package/src/lib/kiro-db.ts +949 -0
  128. package/src/lib/kiro-exporter-types.ts +100 -0
  129. package/src/lib/kiro-transcript-phase.ts +41 -0
  130. package/src/lib/kiro-transcript.ts +115 -0
  131. package/src/lib/opencode-db.ts +610 -0
  132. package/src/lib/opencode-exporter-types.ts +129 -0
  133. package/src/lib/opencode-think-tags.ts +126 -0
  134. package/src/lib/opencode-transcript-phase.ts +50 -0
  135. package/src/lib/opencode-transcript.ts +194 -0
  136. package/src/lib/shared.ts +25 -0
  137. package/src/lib/ui-export-archive.ts +61 -0
  138. package/apps/ui/dist/client/assets/analytics-DK2jdvmI.js +0 -1
  139. package/apps/ui/dist/client/assets/antigravity-keychain-panel-BRHVjFAM.js +0 -1
  140. package/apps/ui/dist/client/assets/antigravity._workspaceKey-CGV7amas.js +0 -1
  141. package/apps/ui/dist/client/assets/createServerFn-CgRRVpBH.js +0 -3
  142. package/apps/ui/dist/client/assets/cursor-threads._composerId-Ti2gTm63.js +0 -1
  143. package/apps/ui/dist/client/assets/cursor._workspaceKey-DzD_c6j9.js +0 -1
  144. package/apps/ui/dist/client/assets/cursor.index-PkCFVcl4.js +0 -2
  145. package/apps/ui/dist/client/assets/delete-confirm-dialog-BHRmyLHr.js +0 -11
  146. package/apps/ui/dist/client/assets/dropdown-menu-Dy5cLzTy.js +0 -1
  147. package/apps/ui/dist/client/assets/export-dialog-C86SYHJn.js +0 -1
  148. package/apps/ui/dist/client/assets/index-CPvAP-jk.js +0 -149
  149. package/apps/ui/dist/client/assets/projects._project-Ckf6muWZ.js +0 -1
  150. package/apps/ui/dist/client/assets/projects.index-V5ibNZII.js +0 -3
  151. package/apps/ui/dist/client/assets/routes-Df2tgpyd.js +0 -1
  152. package/apps/ui/dist/client/assets/select-Bf2GwfPR.js +0 -1
  153. package/apps/ui/dist/client/assets/settings-5VQIzME0.js +0 -1
  154. package/apps/ui/dist/client/assets/styles-BhRkXgwB.css +0 -1
  155. package/apps/ui/dist/client/assets/tabs-OO4VU5KR.js +0 -7
  156. package/apps/ui/dist/client/assets/threads._threadId-BgDhFj2I.js +0 -1
  157. package/apps/ui/dist/client/assets/useMutation-CC_B7uy5.js +0 -1
  158. package/apps/ui/dist/client/assets/useQuery-C5By6WKU.js +0 -1
  159. package/apps/ui/dist/server/assets/_tanstack-start-manifest_v-CRW2kqj0.js +0 -232
@@ -0,0 +1,129 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import type { ExportFormat, JsonValue } from './shared';
4
+
5
+ export const getDefaultOpenCodeDataDir = (env: NodeJS.ProcessEnv = process.env, homeDir = os.homedir()): string => {
6
+ return path.join(env.XDG_DATA_HOME || path.join(homeDir, '.local', 'share'), 'opencode');
7
+ };
8
+
9
+ export const DEFAULT_OPENCODE_DATA_DIR = getDefaultOpenCodeDataDir();
10
+
11
+ export const resolveOpenCodeDataDir = (): string => {
12
+ const configured = process.env.SPIRACHA_OPENCODE_DATA_DIR?.trim() || process.env.SPIRACHA_OPENCODE_DIR?.trim();
13
+ return configured ? configured : DEFAULT_OPENCODE_DATA_DIR;
14
+ };
15
+
16
+ export const resolveOpenCodeDbPath = (): string => {
17
+ const configured = process.env.SPIRACHA_OPENCODE_DB?.trim();
18
+ return configured ? configured : path.join(resolveOpenCodeDataDir(), 'opencode.db');
19
+ };
20
+
21
+ export type OpenCodeWorkspaceGroup = {
22
+ archivedSessionCount: number;
23
+ key: string;
24
+ label: string;
25
+ lastActiveMs: number;
26
+ messageCount: number;
27
+ partCount: number;
28
+ projectId: string;
29
+ sessionCount: number;
30
+ uri: string;
31
+ worktree: string;
32
+ };
33
+
34
+ export type OpenCodeModelInfo = {
35
+ id: string | null;
36
+ providerID: string | null;
37
+ raw: JsonValue | string | null;
38
+ variant: string | null;
39
+ };
40
+
41
+ export type OpenCodeSessionSummary = {
42
+ agent: string | null;
43
+ archivedAtMs: number | null;
44
+ cost: number;
45
+ createdAtMs: number;
46
+ directory: string;
47
+ lastUpdatedAtMs: number;
48
+ messageCount: number;
49
+ model: OpenCodeModelInfo;
50
+ modelLabel: string | null;
51
+ partCount: number;
52
+ path: string | null;
53
+ permission: string | null;
54
+ projectId: string;
55
+ renderablePartCount: number;
56
+ sessionId: string;
57
+ slug: string;
58
+ summaryAdditions: number | null;
59
+ summaryDeletions: number | null;
60
+ summaryFiles: number | null;
61
+ textPartCount: number;
62
+ title: string;
63
+ tokensCacheRead: number;
64
+ tokensCacheWrite: number;
65
+ tokensInput: number;
66
+ tokensOutput: number;
67
+ tokensReasoning: number;
68
+ toolPartCount: number;
69
+ totalTokens: number;
70
+ worktree: string;
71
+ workspaceKey: string;
72
+ workspaceLabel: string;
73
+ };
74
+
75
+ export type OpenCodePartType = 'reasoning' | 'step-finish' | 'step-start' | 'text' | 'tool' | 'unknown';
76
+
77
+ export type OpenCodeStepTokens = {
78
+ cacheRead: number;
79
+ cacheWrite: number;
80
+ input: number;
81
+ output: number;
82
+ reasoning: number;
83
+ total: number;
84
+ };
85
+
86
+ export type OpenCodeTranscriptPart = {
87
+ argumentsText?: string | null;
88
+ callId?: string | null;
89
+ createdAtMs: number;
90
+ endTimeMs?: number | null;
91
+ messageId: string;
92
+ outputText?: string | null;
93
+ partId: string;
94
+ raw: Record<string, JsonValue>;
95
+ reason?: string | null;
96
+ role: string;
97
+ snapshot?: string | null;
98
+ startTimeMs?: number | null;
99
+ status?: string | null;
100
+ text?: string;
101
+ title?: string | null;
102
+ tokens?: OpenCodeStepTokens | null;
103
+ toolName?: string | null;
104
+ type: OpenCodePartType;
105
+ updatedAtMs: number;
106
+ };
107
+
108
+ export type OpenCodeTranscriptMessage = {
109
+ createdAtMs: number;
110
+ messageId: string;
111
+ parts: OpenCodeTranscriptPart[];
112
+ raw: Record<string, JsonValue>;
113
+ role: string;
114
+ updatedAtMs: number;
115
+ };
116
+
117
+ export type OpenCodeSessionTranscript = {
118
+ messages: OpenCodeTranscriptMessage[];
119
+ partCount: number;
120
+ renderablePartCount: number;
121
+ session: OpenCodeSessionSummary;
122
+ };
123
+
124
+ export type OpenCodeExportOptions = {
125
+ includeCommentary: boolean;
126
+ includeMetadata: boolean;
127
+ includeTools: boolean;
128
+ outputFormat: ExportFormat;
129
+ };
@@ -0,0 +1,126 @@
1
+ export type OpenCodeThinkTagText = {
2
+ reasoningBlocks: string[];
3
+ visibleText: string;
4
+ };
5
+
6
+ const THINK_OPEN_PATTERN = /<think\b[^>]*>/iy;
7
+ const THINK_CLOSE_PATTERN = /<\/think>/gi;
8
+ const THINK_CLOSE_TAG_LENGTH = '</think>'.length;
9
+
10
+ const normalizeExtractedText = (text: string): string => {
11
+ return text.replace(/\n{3,}/g, '\n\n').trim();
12
+ };
13
+
14
+ const getBacktickRunLength = (text: string, start: number): number => {
15
+ let end = start;
16
+ while (text[end] === '`') {
17
+ end += 1;
18
+ }
19
+
20
+ return end - start;
21
+ };
22
+
23
+ const findClosingBackticks = (text: string, start: number, runLength: number): number => {
24
+ const marker = '`'.repeat(runLength);
25
+ const index = text.indexOf(marker, start + runLength);
26
+ return index === -1 ? text.length : index + runLength;
27
+ };
28
+
29
+ const findThinkCloseIndex = (text: string, start: number): number => {
30
+ THINK_CLOSE_PATTERN.lastIndex = start;
31
+ const match = THINK_CLOSE_PATTERN.exec(text);
32
+ return match ? match.index : -1;
33
+ };
34
+
35
+ const getLastVisibleChar = (parts: string[]): string => {
36
+ for (let index = parts.length - 1; index >= 0; index -= 1) {
37
+ const part = parts[index];
38
+ if (part) {
39
+ return part.at(-1) ?? '';
40
+ }
41
+ }
42
+
43
+ return '';
44
+ };
45
+
46
+ const getThinkReplacement = (previous: string, next: string): string => {
47
+ if (previous === '\n' || next === '\n') {
48
+ return '\n';
49
+ }
50
+ if ((previous && /\s/u.test(previous)) || (next && /\s/u.test(next))) {
51
+ return '';
52
+ }
53
+
54
+ return ' ';
55
+ };
56
+
57
+ const shouldSkipFollowingSpace = (replacement: string, previous: string, next: string): boolean => {
58
+ return (replacement === ' ' || Boolean(previous && /[^\S\n]/u.test(previous))) && /[^\S\n]/u.test(next);
59
+ };
60
+
61
+ const readThinkBlock = (
62
+ text: string,
63
+ cursor: number,
64
+ visibleParts: string[],
65
+ ): { nextCursor: number; reasoning: string | null; replacement: string } | null => {
66
+ THINK_OPEN_PATTERN.lastIndex = cursor;
67
+ const openMatch = THINK_OPEN_PATTERN.exec(text);
68
+ if (openMatch?.index !== cursor) {
69
+ return null;
70
+ }
71
+
72
+ const reasoningStart = THINK_OPEN_PATTERN.lastIndex;
73
+ const closeIndex = findThinkCloseIndex(text, reasoningStart);
74
+ const reasoningEnd = closeIndex === -1 ? text.length : closeIndex;
75
+ const normalizedReasoning = normalizeExtractedText(text.slice(reasoningStart, reasoningEnd));
76
+ let nextCursor = closeIndex === -1 ? text.length : closeIndex + THINK_CLOSE_TAG_LENGTH;
77
+ const previous = getLastVisibleChar(visibleParts);
78
+ const replacement = getThinkReplacement(previous, text[nextCursor] ?? '');
79
+ if (shouldSkipFollowingSpace(replacement, previous, text[nextCursor] ?? '')) {
80
+ nextCursor += 1;
81
+ }
82
+
83
+ return {
84
+ nextCursor,
85
+ reasoning: normalizedReasoning || null,
86
+ replacement,
87
+ };
88
+ };
89
+
90
+ /**
91
+ * OpenCode can store MiniMax reasoning inline as <think> blocks. Preserve literal
92
+ * examples in Markdown code while extracting model-emitted tags as commentary.
93
+ */
94
+ export const splitOpenCodeThinkTaggedText = (text: string): OpenCodeThinkTagText => {
95
+ const reasoningBlocks: string[] = [];
96
+ const visibleParts: string[] = [];
97
+ let cursor = 0;
98
+
99
+ while (cursor < text.length) {
100
+ if (text[cursor] === '`') {
101
+ const runLength = getBacktickRunLength(text, cursor);
102
+ const end = findClosingBackticks(text, cursor, runLength);
103
+ visibleParts.push(text.slice(cursor, end));
104
+ cursor = end;
105
+ continue;
106
+ }
107
+
108
+ const thinkBlock = readThinkBlock(text, cursor, visibleParts);
109
+ if (thinkBlock) {
110
+ if (thinkBlock.reasoning) {
111
+ reasoningBlocks.push(thinkBlock.reasoning);
112
+ }
113
+ visibleParts.push(thinkBlock.replacement);
114
+ cursor = thinkBlock.nextCursor;
115
+ continue;
116
+ }
117
+
118
+ visibleParts.push(text[cursor]!);
119
+ cursor += 1;
120
+ }
121
+
122
+ return {
123
+ reasoningBlocks,
124
+ visibleText: normalizeExtractedText(visibleParts.join('')),
125
+ };
126
+ };
@@ -0,0 +1,50 @@
1
+ import type { OpenCodeTranscriptPart } from './opencode-exporter-types';
2
+ import { splitOpenCodeThinkTaggedText } from './opencode-think-tags';
3
+
4
+ export type OpenCodeMessagePhase = 'commentary' | 'final_answer' | null;
5
+
6
+ export const getFinalOpenCodeAssistantTextPartIds = (parts: OpenCodeTranscriptPart[]): Set<string> => {
7
+ const finalPartIds = new Set<string>();
8
+ let latestAssistantTextPartId: string | null = null;
9
+
10
+ const flushAssistantRun = () => {
11
+ if (latestAssistantTextPartId) {
12
+ finalPartIds.add(latestAssistantTextPartId);
13
+ latestAssistantTextPartId = null;
14
+ }
15
+ };
16
+
17
+ for (const part of parts) {
18
+ if (part.role === 'user') {
19
+ flushAssistantRun();
20
+ continue;
21
+ }
22
+
23
+ if (part.role !== 'assistant') {
24
+ continue;
25
+ }
26
+
27
+ if (part.type === 'tool') {
28
+ latestAssistantTextPartId = null;
29
+ continue;
30
+ }
31
+
32
+ if (part.type === 'text' && splitOpenCodeThinkTaggedText(part.text ?? '').visibleText.trim()) {
33
+ latestAssistantTextPartId = part.partId;
34
+ }
35
+ }
36
+
37
+ flushAssistantRun();
38
+ return finalPartIds;
39
+ };
40
+
41
+ export const getOpenCodeTextPartPhase = (
42
+ part: OpenCodeTranscriptPart,
43
+ finalAssistantTextPartIds: Set<string>,
44
+ ): OpenCodeMessagePhase => {
45
+ if (part.role !== 'assistant') {
46
+ return null;
47
+ }
48
+
49
+ return finalAssistantTextPartIds.has(part.partId) ? 'final_answer' : 'commentary';
50
+ };
@@ -0,0 +1,194 @@
1
+ import type {
2
+ OpenCodeExportOptions,
3
+ OpenCodeSessionSummary,
4
+ OpenCodeSessionTranscript,
5
+ OpenCodeTranscriptPart,
6
+ } from './opencode-exporter-types';
7
+ import { splitOpenCodeThinkTaggedText } from './opencode-think-tags';
8
+ import { getFinalOpenCodeAssistantTextPartIds, getOpenCodeTextPartPhase } from './opencode-transcript-phase';
9
+ import {
10
+ cleanExtractedText,
11
+ cleanInlineTitle,
12
+ formatInlineLiteral,
13
+ type MetadataEntry,
14
+ renderCodeBlock,
15
+ renderDocumentTitle,
16
+ renderMetadataBlock,
17
+ renderSection,
18
+ } from './shared';
19
+
20
+ const TOOL_OUTPUT_PREVIEW_LIMIT = 4000;
21
+ const MIN_DATE_MS = -8_640_000_000_000_000;
22
+ const MAX_DATE_MS = 8_640_000_000_000_000;
23
+
24
+ const formatUnixMillis = (value: number | null): string | null => {
25
+ if (
26
+ value === null ||
27
+ value === undefined ||
28
+ !Number.isFinite(value) ||
29
+ value < MIN_DATE_MS ||
30
+ value > MAX_DATE_MS
31
+ ) {
32
+ return null;
33
+ }
34
+
35
+ return new Date(value).toISOString();
36
+ };
37
+
38
+ const getSessionTitle = (session: OpenCodeSessionSummary): string => {
39
+ return cleanInlineTitle(session.title || session.sessionId);
40
+ };
41
+
42
+ const buildMetadataEntries = (session: OpenCodeSessionSummary): MetadataEntry[] => [
43
+ { key: 'exported_from', value: 'opencode_sqlite' },
44
+ { key: 'session_id', value: session.sessionId },
45
+ { key: 'title', value: session.title },
46
+ { key: 'slug', value: session.slug },
47
+ { key: 'project_id', value: session.projectId },
48
+ { key: 'worktree', value: session.worktree },
49
+ { key: 'directory', value: session.directory },
50
+ { key: 'agent', value: session.agent },
51
+ { key: 'model', value: session.modelLabel },
52
+ { key: 'created_at_unix_ms', value: session.createdAtMs },
53
+ { key: 'created_at_iso', value: formatUnixMillis(session.createdAtMs) },
54
+ { key: 'last_updated_at_unix_ms', value: session.lastUpdatedAtMs },
55
+ { key: 'last_updated_at_iso', value: formatUnixMillis(session.lastUpdatedAtMs) },
56
+ { key: 'message_count', value: session.messageCount },
57
+ { key: 'part_count', value: session.partCount },
58
+ { key: 'total_tokens', value: session.totalTokens },
59
+ { key: 'cost', value: session.cost },
60
+ ];
61
+
62
+ const roleTitle = (role: string): string => {
63
+ if (role === 'assistant') {
64
+ return 'Assistant';
65
+ }
66
+
67
+ if (role === 'user') {
68
+ return 'User';
69
+ }
70
+
71
+ if (role === 'system') {
72
+ return 'System';
73
+ }
74
+
75
+ return role ? cleanInlineTitle(role) : 'Message';
76
+ };
77
+
78
+ const truncateOutput = (text: string): string => {
79
+ if (text.length <= TOOL_OUTPUT_PREVIEW_LIMIT) {
80
+ return text;
81
+ }
82
+
83
+ return `${text.slice(0, TOOL_OUTPUT_PREVIEW_LIMIT)}\n... (truncated)`;
84
+ };
85
+
86
+ const renderTextPart = (
87
+ part: OpenCodeTranscriptPart,
88
+ options: OpenCodeExportOptions,
89
+ finalAssistantTextPartIds: Set<string>,
90
+ ): string => {
91
+ const { reasoningBlocks, visibleText } =
92
+ part.role === 'assistant'
93
+ ? splitOpenCodeThinkTaggedText(part.text ?? '')
94
+ : { reasoningBlocks: [], visibleText: part.text ?? '' };
95
+ const sections: string[] = [];
96
+
97
+ if (options.includeCommentary) {
98
+ sections.push(
99
+ ...reasoningBlocks
100
+ .map((block) => cleanExtractedText(block).trim())
101
+ .filter(Boolean)
102
+ .map((block) => renderSection('Reasoning', block, options.outputFormat)),
103
+ );
104
+ }
105
+
106
+ const text = cleanExtractedText(visibleText).trim();
107
+ if (
108
+ text &&
109
+ (getOpenCodeTextPartPhase(part, finalAssistantTextPartIds) !== 'commentary' || options.includeCommentary)
110
+ ) {
111
+ sections.push(renderSection(roleTitle(part.role), text, options.outputFormat));
112
+ }
113
+
114
+ return sections.join('\n\n');
115
+ };
116
+
117
+ const renderReasoningPart = (part: OpenCodeTranscriptPart, options: OpenCodeExportOptions): string => {
118
+ if (!options.includeCommentary) {
119
+ return '';
120
+ }
121
+
122
+ const { reasoningBlocks, visibleText } = splitOpenCodeThinkTaggedText(part.text ?? '');
123
+ const text = cleanExtractedText([...reasoningBlocks, visibleText].filter(Boolean).join('\n\n')).trim();
124
+ return text ? renderSection('Reasoning', text, options.outputFormat) : '';
125
+ };
126
+
127
+ const renderToolPart = (part: OpenCodeTranscriptPart, options: OpenCodeExportOptions): string => {
128
+ if (!options.includeTools) {
129
+ return '';
130
+ }
131
+
132
+ const toolName = part.toolName ?? 'unknown';
133
+ const lines = [`Tool: ${formatInlineLiteral(toolName, options.outputFormat)}`];
134
+ if (part.status) {
135
+ lines.push(`Status: ${part.status}`);
136
+ }
137
+ if (part.callId) {
138
+ lines.push(`Call ID: ${part.callId}`);
139
+ }
140
+ if (part.title) {
141
+ lines.push(`Title: ${part.title}`);
142
+ }
143
+ if (part.argumentsText?.trim()) {
144
+ lines.push('', 'Input:', '', renderCodeBlock(part.argumentsText.trim(), options.outputFormat));
145
+ }
146
+ if (part.outputText?.trim()) {
147
+ lines.push('', 'Output:', '', renderCodeBlock(truncateOutput(part.outputText.trim()), options.outputFormat));
148
+ }
149
+
150
+ return renderSection('Tool Call', lines.join('\n'), options.outputFormat);
151
+ };
152
+
153
+ const renderPart = (
154
+ part: OpenCodeTranscriptPart,
155
+ options: OpenCodeExportOptions,
156
+ finalAssistantTextPartIds: Set<string>,
157
+ ): string => {
158
+ if (part.type === 'text') {
159
+ return renderTextPart(part, options, finalAssistantTextPartIds);
160
+ }
161
+
162
+ if (part.type === 'reasoning') {
163
+ return renderReasoningPart(part, options);
164
+ }
165
+
166
+ if (part.type === 'tool') {
167
+ return renderToolPart(part, options);
168
+ }
169
+
170
+ return '';
171
+ };
172
+
173
+ export const renderOpenCodeTranscript = (
174
+ transcript: OpenCodeSessionTranscript,
175
+ options: OpenCodeExportOptions,
176
+ ): string | null => {
177
+ const partsList = transcript.messages.flatMap((message) => message.parts);
178
+ const finalAssistantTextPartIds = getFinalOpenCodeAssistantTextPartIds(partsList);
179
+ const sections = partsList.map((part) => renderPart(part, options, finalAssistantTextPartIds)).filter(Boolean);
180
+ if (sections.length === 0) {
181
+ return null;
182
+ }
183
+
184
+ const parts = [
185
+ renderDocumentTitle(getSessionTitle(transcript.session), options.outputFormat),
186
+ '',
187
+ options.includeMetadata
188
+ ? renderMetadataBlock(buildMetadataEntries(transcript.session), options.outputFormat)
189
+ : '',
190
+ ...sections,
191
+ ].filter(Boolean);
192
+
193
+ return `${parts.join('\n').trimEnd()}\n`;
194
+ };
package/src/lib/shared.ts CHANGED
@@ -42,6 +42,31 @@ export const getPortablePathBasename = (value: string): string => {
42
42
  return path.win32.basename(path.posix.basename(trimmed));
43
43
  };
44
44
 
45
+ export const isWorkspacePathQuery = (value: string): boolean => {
46
+ const raw = value.trim();
47
+ return raw.startsWith('/') || raw.startsWith('~') || raw.includes('/') || raw.includes('\\');
48
+ };
49
+
50
+ export const normalizeWorkspacePathQuery = (value: string): string => {
51
+ return expandHome(value.trim())
52
+ .replace(/[\\/]+$/u, '')
53
+ .replace(/\\/gu, '/');
54
+ };
55
+
56
+ export const workspacePathMatchesQuery = (worktree: string, query: string): boolean => {
57
+ const normalizedQuery = normalizeWorkspacePathQuery(query);
58
+ const normalizedWorktree = normalizeWorkspacePathQuery(worktree);
59
+ if (!normalizedQuery) {
60
+ return false;
61
+ }
62
+ if (normalizedWorktree === normalizedQuery) {
63
+ return true;
64
+ }
65
+
66
+ const suffix = normalizedQuery.replace(/^\/+/u, '');
67
+ return Boolean(suffix) && normalizedWorktree.endsWith(`/${suffix}`);
68
+ };
69
+
45
70
  export const cleanInlineTitle = (value: string): string => {
46
71
  const firstLine =
47
72
  value
@@ -0,0 +1,61 @@
1
+ import type { ExportFormat } from './shared';
2
+
3
+ export const sanitizeExportFileName = (value: string) => {
4
+ return value
5
+ .replace(/[<>:"/\\|?*\u0000-\u001f]/gu, ' ')
6
+ .replace(/\.\.+/gu, ' ')
7
+ .replace(/\s+/gu, ' ')
8
+ .trim();
9
+ };
10
+
11
+ export const getExportMimeType = (outputFormat: ExportFormat) => {
12
+ return outputFormat === 'md' ? 'text/markdown; charset=utf-8' : 'text/plain; charset=utf-8';
13
+ };
14
+
15
+ export const resolveUniqueExportFileBaseName = (baseName: string, usedCounts: Map<string, number>) => {
16
+ const count = (usedCounts.get(baseName) ?? 0) + 1;
17
+ usedCounts.set(baseName, count);
18
+ return count === 1 ? baseName : `${baseName}-${count}`;
19
+ };
20
+
21
+ const readPipeText = async (pipe: ReadableStream<Uint8Array> | number | undefined) => {
22
+ return pipe && typeof pipe !== 'number' ? new Response(pipe).text() : '';
23
+ };
24
+
25
+ const runZip = async (args: string[], options: { cwd?: string } = {}) => {
26
+ let proc: ReturnType<typeof Bun.spawn>;
27
+ try {
28
+ proc = Bun.spawn(['zip', '-9', ...args], {
29
+ cwd: options.cwd,
30
+ stderr: 'pipe',
31
+ stdout: 'pipe',
32
+ });
33
+ } catch (error) {
34
+ throw new Error(
35
+ `zip command failed to start. Install the "zip" executable or choose a non-zip export. ${error instanceof Error ? error.message : String(error)}`,
36
+ );
37
+ }
38
+
39
+ const [stdoutText, stderrText, exitCode] = await Promise.all([
40
+ readPipeText(proc.stdout),
41
+ readPipeText(proc.stderr),
42
+ proc.exited,
43
+ ]);
44
+
45
+ if (exitCode !== 0) {
46
+ const output = (stderrText || stdoutText).trim();
47
+ throw new Error(
48
+ output
49
+ ? `zip command failed (${exitCode}): ${output}`
50
+ : `zip command failed (${exitCode}). Install the "zip" executable or choose a non-zip export.`,
51
+ );
52
+ }
53
+ };
54
+
55
+ export const zipExportFile = async (sourcePath: string, zipPath: string) => {
56
+ await runZip(['-j', zipPath, sourcePath]);
57
+ };
58
+
59
+ export const zipExportDirectory = async (sourceDirectory: string, zipPath: string) => {
60
+ await runZip(['-r', zipPath, '.'], { cwd: sourceDirectory });
61
+ };
@@ -1 +0,0 @@
1
- import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{n}from"./react-dom-DL96Jor4.js";import{c as r,o as i,s as a}from"./formatters-BM9kB7ed.js";import{n as o,t as s}from"./data-table-Br78_dk3.js";import{a as c,i as l,n as u,r as d,t as f}from"./select-Bf2GwfPR.js";import{A as p,F as m,M as h,N as g,R as _,ct as v,j as y}from"./index-CPvAP-jk.js";import{t as b}from"./metric-card-Dplm0ZiM.js";import{t as x}from"./page-header-Cwa3p6Tl.js";var S=e(n()),C=t(),w=o(),T=[w.accessor(`name`,{cell:e=>(0,C.jsx)(`span`,{className:`font-mono text-sm`,children:e.getValue()}),header:`Tool`}),w.accessor(`count`,{cell:e=>(0,C.jsx)(`span`,{className:`font-mono text-sm`,children:i(e.getValue())}),header:`Calls`})],E=o(),D=[E.accessor(`model`,{cell:e=>(0,C.jsx)(`span`,{className:`font-mono text-sm`,children:e.getValue()}),header:`Model`}),E.accessor(`threadCount`,{cell:e=>(0,C.jsx)(`span`,{className:`font-mono text-sm`,children:i(e.getValue())}),header:`Threads`}),E.accessor(`totalTokens`,{cell:e=>(0,C.jsx)(`span`,{className:`font-mono text-sm`,children:a(e.getValue())}),header:`Tokens`})];function O(){let e=v({from:p.fullPath}),t=r(_()).data,n=p.useSearch().project??null,o=r(m(n)).data;return(0,C.jsxs)(`div`,{className:`space-y-6`,children:[(0,C.jsx)(x,{actions:(0,C.jsxs)(f,{value:h(n),onValueChange:t=>{(0,S.startTransition)(()=>{e({replace:!0,search:e=>g(e,y(t))})})},children:[(0,C.jsx)(l,{className:`h-10 w-full rounded-full border-[var(--border)] bg-[var(--panel)] sm:w-[15rem]`,children:(0,C.jsx)(c,{placeholder:`Filter by project`})}),(0,C.jsxs)(u,{children:[(0,C.jsx)(d,{value:`__all__`,children:`All projects`}),t.map(e=>(0,C.jsx)(d,{value:h(e.name),children:e.name},e.name))]})]}),eyebrow:`Analytics`,subtitle:`Inspect token load, tool-call distribution, and project-scoped usage patterns to understand where Codex is spending effort.`,title:`Analytics`}),(0,C.jsxs)(`div`,{className:`grid gap-4 md:grid-cols-2 xl:grid-cols-5`,children:[(0,C.jsx)(b,{label:`Threads`,value:i(o.summary.totalThreads)}),(0,C.jsx)(b,{label:`Projects`,value:i(o.summary.totalProjects)}),(0,C.jsx)(b,{label:`Tokens`,value:a(o.summary.totalTokens)}),(0,C.jsx)(b,{label:`Average per thread`,value:a(Math.round(o.summary.averageTokensPerThread))}),(0,C.jsx)(b,{label:`Web search threads`,value:i(o.summary.threadsWithWebSearch)})]}),(0,C.jsxs)(`div`,{className:`grid gap-4 xl:grid-cols-2`,children:[(0,C.jsxs)(`section`,{className:`space-y-4`,children:[(0,C.jsxs)(`div`,{children:[(0,C.jsx)(`h3`,{className:`font-semibold text-sm`,children:`Most frequent tool calls`}),(0,C.jsx)(`p`,{className:`mt-1 text-[var(--muted-foreground)] text-sm`,children:`Useful for future prompt and tool optimization work.`})]}),(0,C.jsx)(s,{columns:T,data:o.toolUsage,emptyMessage:`No tool calls recorded.`})]}),(0,C.jsxs)(`section`,{className:`space-y-4`,children:[(0,C.jsxs)(`div`,{children:[(0,C.jsx)(`h3`,{className:`font-semibold text-sm`,children:`Model token breakdown`}),(0,C.jsx)(`p`,{className:`mt-1 text-[var(--muted-foreground)] text-sm`,children:`Compare model usage and token concentration within the current project scope.`})]}),(0,C.jsx)(s,{columns:D,data:o.modelsByTokens,emptyMessage:`No model usage recorded.`})]})]})]})}export{O as component};
@@ -1 +0,0 @@
1
- import{t as e}from"./jsx-runtime-DGeXAQPT.js";import{a as t}from"./createServerFn-CgRRVpBH.js";import{t as n}from"./useMutation-CC_B7uy5.js";import{t as r}from"./useQuery-C5By6WKU.js";import{_ as i,h as a}from"./dist-DvMS2965.js";import{J as o,d as s,h as c}from"./index-CPvAP-jk.js";var l=i(`key-round`,[[`path`,{d:`M2.586 17.414A2 2 0 0 0 2 18.828V21a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h1a1 1 0 0 0 1-1v-1a1 1 0 0 1 1-1h.172a2 2 0 0 0 1.414-.586l.814-.814a6.5 6.5 0 1 0-4-4z`,key:`1s6t7t`}],[`circle`,{cx:`16.5`,cy:`7.5`,r:`.5`,fill:`currentColor`,key:`w0ekpg`}]]),u=i(`lock-keyhole`,[[`circle`,{cx:`12`,cy:`16`,r:`1`,key:`1au0dj`}],[`rect`,{x:`3`,y:`10`,width:`18`,height:`12`,rx:`2`,key:`6s8ecr`}],[`path`,{d:`M7 10V7a5 5 0 0 1 10 0v3`,key:`1pqi11`}]]),d=i(`shield-check`,[[`path`,{d:`M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z`,key:`oel41y`}],[`path`,{d:`m9 12 2 2 4-4`,key:`dzmm74`}]]),f=i(`triangle-alert`,[[`path`,{d:`m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3`,key:`wmoenq`}],[`path`,{d:`M12 9v4`,key:`juzpu7`}],[`path`,{d:`M12 17h.01`,key:`p32p05`}]]),p=e();function m(){let e=t(),i=r(s()).data??null,m=n({mutationFn:()=>c(),onSuccess:t=>{e.setQueryData(s().queryKey,t),Promise.all([e.invalidateQueries({queryKey:s().queryKey}),e.invalidateQueries({queryKey:[`antigravity-conversation`]})])}});if(!i||i.status===`unsupported`)return null;let h=i.isUnlocked,g=m.error?.message??i.error;return(0,p.jsxs)(`div`,{className:a(`flex flex-col gap-3 rounded-xl border px-4 py-3 sm:flex-row sm:items-center sm:justify-between`,h?`border-emerald-500/30 bg-emerald-500/10`:`border-[var(--border)] bg-[var(--panel)]`),children:[(0,p.jsxs)(`div`,{className:`flex min-w-0 items-start gap-3`,children:[(0,p.jsx)(`div`,{className:a(`mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-md`,h?`bg-emerald-500/15 text-emerald-600`:`bg-[var(--panel-secondary)]`),children:h?(0,p.jsx)(d,{className:`size-4`}):(0,p.jsx)(u,{className:`size-4`})}),(0,p.jsxs)(`div`,{className:`min-w-0`,children:[(0,p.jsx)(`p`,{className:`font-medium text-sm`,children:h?`Keychain access enabled`:`Unlock Antigravity transcript export`}),(0,p.jsx)(`p`,{className:`mt-1 text-[var(--muted-foreground)] text-xs`,children:h?`The Antigravity key is cached in this server process only. Transcript exports are available for local logs and safe-storage payloads.`:`Spiracha needs one-time access to ${i.keychainService} to decrypt Antigravity transcript data. macOS will ask for approval after you click unlock.`}),g?(0,p.jsxs)(`p`,{className:`mt-2 flex items-center gap-1 text-[var(--destructive)] text-xs`,children:[(0,p.jsx)(f,{className:`size-3`}),g]}):null]})]}),h?null:(0,p.jsxs)(o,{className:`shrink-0`,disabled:!i.canRequestAccess||m.isPending,type:`button`,onClick:()=>m.mutate(),children:[(0,p.jsx)(l,{className:`size-4`}),m.isPending?`Waiting...`:`Unlock`]})]})}export{u as n,m as t};
@@ -1 +0,0 @@
1
- import{r as e,t}from"./jsx-runtime-DGeXAQPT.js";import{n}from"./react-dom-DL96Jor4.js";import{N as r}from"./createServerFn-CgRRVpBH.js";import{c as i,n as a,o,r as s}from"./formatters-BM9kB7ed.js";import{t as c}from"./useMutation-CC_B7uy5.js";import{n as l,t as u}from"./data-table-Br78_dk3.js";import{r as d,t as f}from"./download-Bf0QJKD3.js";import{a as p,i as m,n as h,r as g,t as _}from"./dropdown-menu-Dy5cLzTy.js";import{n as v,t as y}from"./antigravity-keychain-panel-BRHVjFAM.js";import{t as b}from"./scroll-text-fM0sMOB3.js";import{J as x,_ as S,d as C,f as w,g as T,m as E,n as D,p as O,r as k,u as A,v as j,y as M}from"./index-CPvAP-jk.js";import{t as N}from"./page-header-Cwa3p6Tl.js";import{t as P}from"./badge-DfWvPfKF.js";import{n as F,t as I}from"./text-filter-DVAZySUS.js";var L=e(n(),1),R=t(),z=l(),B=(e,t)=>{let n=e.artifactCount>0,r=!!t?.isUnlocked,i=j(e)||S(e),a=T(e,r),o=M(e,r),s=a||o;return{canExportConversation:a,hasArtifacts:n,hasTranscript:i,lockedTranscript:o,showActions:s||n,showConversationAction:s}},V=(e,t)=>t.hasTranscript?`${e.transcriptSource?e.transcriptSource.replace(/-/gu,` `):`transcript`} · ${t.lockedTranscript?`locked`:`available`}`:`Summary only`,H=(e,t,n)=>[z.accessor(`title`,{cell:t=>{let n=B(t.row.original,e);return(0,R.jsxs)(r,{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`,params:{conversationId:t.row.original.conversationId},to:`/antigravity-conversations/$conversationId`,children:[(0,R.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,R.jsx)(`p`,{className:`truncate font-medium underline-offset-2 hover:underline`,children:t.getValue()}),n.hasTranscript?(0,R.jsx)(P,{variant:`secondary`,children:`transcript`}):null,n.hasArtifacts?(0,R.jsx)(P,{variant:`outline`,children:`artifact`}):null]}),(0,R.jsx)(`p`,{className:`truncate text-[var(--muted-foreground)] text-xs`,children:t.row.original.conversationId})]})},header:`Conversation`}),z.accessor(`lastUpdatedAtMs`,{cell:e=>(0,R.jsx)(`span`,{className:`whitespace-nowrap text-sm`,suppressHydrationWarning:!0,children:s(e.getValue())}),header:`Updated`}),z.display({cell:t=>{let n=B(t.row.original,e);return(0,R.jsxs)(`span`,{className:`text-sm`,children:[V(t.row.original,n),t.row.original.transcriptEntryCount>0?` · ${o(t.row.original.transcriptEntryCount)} entries`:``]})},header:`Transcript`,id:`transcript`}),z.accessor(`artifactCount`,{cell:e=>(0,R.jsx)(`span`,{className:`font-mono text-sm`,children:o(e.getValue())}),header:`Artifacts`}),z.accessor(`conversationBytes`,{cell:e=>(0,R.jsx)(`span`,{className:`font-mono text-sm`,children:a(e.getValue())}),header:`Size`}),z.display({cell:r=>{let i=B(r.row.original,e);return i.showActions?(0,R.jsxs)(_,{children:[(0,R.jsx)(m,{asChild:!0,children:(0,R.jsx)(x,{className:`rounded-full`,size:`icon`,type:`button`,variant:`ghost`,onClick:e=>e.stopPropagation(),children:(0,R.jsx)(p,{className:`size-4`})})}),(0,R.jsxs)(h,{align:`end`,children:[i.showConversationAction?(0,R.jsxs)(g,{disabled:!i.canExportConversation,onClick:()=>t(r.row.original),children:[i.lockedTranscript?(0,R.jsx)(v,{className:`mr-2 size-4`}):(0,R.jsx)(d,{className:`mr-2 size-4`}),i.lockedTranscript?`Unlock conversation export first`:`Export conversation`]}):null,i.hasArtifacts?(0,R.jsxs)(g,{onClick:()=>n(r.row.original),children:[(0,R.jsx)(b,{className:`mr-2 size-4`}),`Export artifacts`]}):null]})]}):(0,R.jsx)(`span`,{className:`text-[var(--muted-foreground)] text-sm`,children:`No export`})},header:``,id:`actions`})];function U({conversations:e,decryptionState:t,onExportArtifacts:n,onExportConversation:r}){return(0,R.jsx)(u,{columns:(0,L.useMemo)(()=>H(t,r,n),[t,n,r]),data:e,emptyMessage:`No Antigravity conversations match the current workspace filter.`})}function W(){let e=D.useParams(),t=i(w()).data,n=k(t,e.workspaceKey),r=i(A(n.key)).data,a=i(C()).data??null,[o,s]=(0,L.useState)(``),l=(0,L.useDeferredValue)(o),u=c({mutationFn:e=>E({data:{conversationId:e.conversationId}}),onSuccess:e=>{f(e.filename,e.content,`text/markdown; charset=utf-8`)}}),d=c({mutationFn:e=>O({data:{conversationId:e.conversationId}}),onSuccess:e=>{f(e.filename,e.content,`text/markdown; charset=utf-8`)}}),p=r.filter(e=>I(l,[e.title,e.conversationId,e.transcriptSource,e.workspaceLabel]));return(0,R.jsxs)(`div`,{className:`space-y-6`,children:[(0,R.jsx)(N,{actions:(0,R.jsx)(F,{placeholder:`Search title, id, or transcript source`,value:o,onValueChange:s}),eyebrow:`Antigravity workspace`,subtitle:`Inspect conversation coverage across Antigravity transcripts, raw payloads, and generated artifacts.`,title:n.label}),(0,R.jsx)(y,{}),(0,R.jsx)(U,{conversations:p,decryptionState:a,onExportArtifacts:e=>d.mutate(e),onExportConversation:e=>u.mutate(e)}),u.isError?(0,R.jsx)(`p`,{className:`text-[var(--destructive)] text-sm`,children:u.error instanceof Error?u.error.message:`Conversation export failed`}):null,d.isError?(0,R.jsx)(`p`,{className:`text-[var(--destructive)] text-sm`,children:d.error instanceof Error?d.error.message:`Artifact export failed`}):null]})}export{W as component};