spiracha 2.0.0 → 2.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/README.md +6 -1
- package/apps/ui/README.md +20 -2
- package/apps/ui/package.json +2 -2
- package/apps/ui/src/components/antigravity-conversations-table.tsx +50 -11
- package/apps/ui/src/components/antigravity-workspaces-table.tsx +1 -1
- package/apps/ui/src/components/app-shell.tsx +1 -0
- package/apps/ui/src/components/breadcrumbs.tsx +21 -3
- package/apps/ui/src/components/claude-code-sessions-table.tsx +42 -6
- package/apps/ui/src/components/claude-code-workspaces-table.tsx +3 -1
- package/apps/ui/src/components/cursor-threads-table.tsx +10 -47
- package/apps/ui/src/components/data-table.tsx +7 -5
- package/apps/ui/src/components/export-dialog.tsx +2 -12
- package/apps/ui/src/components/grok-sessions-table.tsx +146 -0
- package/apps/ui/src/components/grok-workspaces-table.tsx +53 -0
- package/apps/ui/src/components/kiro-sessions-table.tsx +40 -4
- package/apps/ui/src/components/opencode-sessions-table.tsx +40 -4
- package/apps/ui/src/components/page-header.tsx +15 -9
- package/apps/ui/src/components/qoder-sessions-table.tsx +23 -2
- package/apps/ui/src/components/qoder-workspaces-table.tsx +5 -1
- package/apps/ui/src/components/selection-actions-toolbar.tsx +80 -0
- package/apps/ui/src/components/threads-table.tsx +9 -46
- package/apps/ui/src/components/transcript-view.tsx +148 -52
- package/apps/ui/src/components/ui/select.tsx +1 -1
- package/apps/ui/src/lib/antigravity-conversation-state.ts +17 -4
- package/apps/ui/src/lib/antigravity-server.ts +152 -7
- package/apps/ui/src/lib/antigravity-transcript-events.ts +11 -3
- package/apps/ui/src/lib/claude-code-queries.ts +8 -0
- package/apps/ui/src/lib/claude-code-server.ts +175 -7
- package/apps/ui/src/lib/claude-code-transcript-events.ts +8 -1
- package/apps/ui/src/lib/codex-queries.ts +19 -3
- package/apps/ui/src/lib/codex-server.ts +135 -53
- package/apps/ui/src/lib/cursor-server.ts +48 -5
- package/apps/ui/src/lib/formatters.ts +3 -5
- package/apps/ui/src/lib/grok-queries.ts +22 -0
- package/apps/ui/src/lib/grok-server.ts +169 -0
- package/apps/ui/src/lib/grok-transcript-events.ts +149 -0
- package/apps/ui/src/lib/kiro-server.ts +85 -7
- package/apps/ui/src/lib/opencode-server.ts +85 -7
- package/apps/ui/src/lib/qoder-server.ts +67 -11
- package/apps/ui/src/lib/route-search.ts +114 -0
- package/apps/ui/src/lib/source-session-export-server.ts +86 -3
- package/apps/ui/src/lib/thread-transcript-load.ts +15 -0
- package/apps/ui/src/lib/workspace-delete-navigation.ts +12 -0
- package/apps/ui/src/routeTree.gen.ts +107 -0
- package/apps/ui/src/routes/antigravity-conversations.$conversationId.tsx +76 -10
- package/apps/ui/src/routes/antigravity.$workspaceKey.tsx +269 -31
- package/apps/ui/src/routes/api.v1.conversations.$source.$id.ts +4 -0
- package/apps/ui/src/routes/api.v1.conversations.delete.ts +12 -0
- package/apps/ui/src/routes/api.v1.conversations.export.ts +12 -0
- package/apps/ui/src/routes/claude-code-sessions.$sessionId.tsx +143 -17
- package/apps/ui/src/routes/claude-code.$workspaceKey.tsx +165 -26
- package/apps/ui/src/routes/cursor-threads.$composerId.tsx +2 -2
- package/apps/ui/src/routes/cursor.$workspaceKey.tsx +11 -1
- package/apps/ui/src/routes/grok-sessions.$sessionId.tsx +388 -0
- package/apps/ui/src/routes/grok.$workspaceKey.tsx +301 -0
- package/apps/ui/src/routes/grok.index.tsx +48 -0
- package/apps/ui/src/routes/kiro-sessions.$sessionId.tsx +66 -15
- package/apps/ui/src/routes/kiro.$workspaceKey.tsx +199 -32
- package/apps/ui/src/routes/opencode-sessions.$sessionId.tsx +105 -19
- package/apps/ui/src/routes/opencode.$workspaceKey.tsx +236 -44
- package/apps/ui/src/routes/opencode.index.tsx +16 -3
- package/apps/ui/src/routes/qoder-sessions.$sessionId.tsx +7 -4
- package/apps/ui/src/routes/qoder.$workspaceKey.tsx +75 -28
- package/apps/ui/src/routes/threads.$threadId.tsx +548 -64
- package/package.json +19 -18
- package/src/client.ts +134 -1
- package/src/lib/antigravity-db.ts +208 -32
- package/src/lib/antigravity-exporter-types.ts +3 -0
- package/src/lib/antigravity-projects.ts +201 -0
- package/src/lib/claude-code-db.ts +498 -32
- package/src/lib/claude-code-exporter-types.ts +5 -0
- package/src/lib/claude-code-transcript-phase.ts +60 -1
- package/src/lib/claude-code-transcript.ts +8 -5
- package/src/lib/codex-browser-export.ts +23 -27
- package/src/lib/codex-thread-cache.ts +41 -13
- package/src/lib/codex-thread-parser.ts +86 -35
- package/src/lib/codex-transcript-filter.ts +31 -0
- package/src/lib/codex-transcript-renderer.ts +39 -19
- package/src/lib/concurrency.ts +41 -0
- package/src/lib/conversation-api.ts +399 -19
- package/src/lib/conversation-data/antigravity-adapter.ts +21 -2
- package/src/lib/conversation-data/claude-code-adapter.ts +37 -6
- package/src/lib/conversation-data/codex-adapter.ts +28 -4
- package/src/lib/conversation-data/cursor-adapter.ts +35 -1
- package/src/lib/conversation-data/grok-adapter.ts +210 -0
- package/src/lib/conversation-data/index.ts +76 -1
- package/src/lib/conversation-data/kiro-adapter.ts +41 -7
- package/src/lib/conversation-data/opencode-adapter.ts +24 -2
- package/src/lib/conversation-data/qoder-adapter.ts +44 -19
- package/src/lib/conversation-data/types.ts +43 -0
- package/src/lib/conversation-zip-export.ts +57 -0
- package/src/lib/cursor-db.ts +34 -5
- package/src/lib/grok-db.ts +1026 -0
- package/src/lib/grok-exporter-types.ts +110 -0
- package/src/lib/grok-transcript-phase.ts +52 -0
- package/src/lib/grok-transcript.ts +154 -0
- package/src/lib/kiro-db.ts +52 -1
- package/src/lib/model-label.ts +11 -3
- package/src/lib/opencode-db.ts +598 -55
- package/src/lib/opencode-transcript.ts +8 -5
- package/src/lib/shared.ts +12 -0
- package/src/lib/transcript-load-limiter.ts +82 -0
- package/src/lib/ui-cache.ts +43 -17
- package/src/lib/ui-export-archive.ts +60 -0
|
@@ -46,9 +46,11 @@ export type AntigravityConversation = {
|
|
|
46
46
|
indexedItemCount: number | null;
|
|
47
47
|
lastUpdatedAtMs: number | null;
|
|
48
48
|
model: string | null;
|
|
49
|
+
projectId: string | null;
|
|
49
50
|
sourceRoot: string | null;
|
|
50
51
|
summaryPath: string | null;
|
|
51
52
|
title: string;
|
|
53
|
+
totalBytes: number;
|
|
52
54
|
transcriptBytes: number;
|
|
53
55
|
transcriptEntryCount: number;
|
|
54
56
|
transcriptPath: string | null;
|
|
@@ -67,5 +69,6 @@ export type AntigravityWorkspaceGroup = {
|
|
|
67
69
|
label: string;
|
|
68
70
|
lastActiveMs: number;
|
|
69
71
|
transcriptCount: number;
|
|
72
|
+
totalBytes: number;
|
|
70
73
|
uri: string | null;
|
|
71
74
|
};
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import os from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { mapWithConcurrency } from './concurrency';
|
|
4
|
+
|
|
5
|
+
type AntigravityDevToolsTarget = {
|
|
6
|
+
type?: string;
|
|
7
|
+
url?: string;
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
type AntigravityProjectConnection = {
|
|
11
|
+
baseUrl: string;
|
|
12
|
+
csrfToken: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
type AntigravityProjectRequest = (
|
|
16
|
+
url: string,
|
|
17
|
+
init: RequestInit & { tls?: { rejectUnauthorized: boolean } },
|
|
18
|
+
) => Promise<Response>;
|
|
19
|
+
|
|
20
|
+
type AntigravityProjectResolverOptions = {
|
|
21
|
+
getConnection?: () => Promise<AntigravityProjectConnection | null>;
|
|
22
|
+
request?: AntigravityProjectRequest;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const ANTIGRAVITY_PROJECT_READ_CONCURRENCY = 8;
|
|
26
|
+
const SAFE_PROJECT_ID_PATTERN = /^[a-z0-9._-]{1,128}$/iu;
|
|
27
|
+
|
|
28
|
+
const encodeGrpcWebJson = (value: unknown): Uint8Array => {
|
|
29
|
+
const payload = Buffer.from(JSON.stringify(value));
|
|
30
|
+
const frame = new Uint8Array(payload.length + 5);
|
|
31
|
+
new DataView(frame.buffer).setUint32(1, payload.length);
|
|
32
|
+
frame.set(payload, 5);
|
|
33
|
+
return frame;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const decodeAntigravityGrpcWebJson = (bytes: Uint8Array): unknown => {
|
|
37
|
+
if (bytes.length < 5 || bytes[0] !== 0) {
|
|
38
|
+
throw new Error('Invalid Antigravity gRPC-Web data frame');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const payloadLength = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(1);
|
|
42
|
+
const payloadEnd = 5 + payloadLength;
|
|
43
|
+
if (payloadEnd > bytes.length) {
|
|
44
|
+
throw new Error('Truncated Antigravity gRPC-Web data frame');
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return JSON.parse(new TextDecoder().decode(bytes.subarray(5, payloadEnd)));
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export const extractAntigravityCsrfToken = (processCommands: string): string | null => {
|
|
51
|
+
for (const command of processCommands.split(/\r?\n/u)) {
|
|
52
|
+
if (!command.includes('language_server') || !command.includes('--app_data_dir antigravity')) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const token = command.match(/--csrf_token(?:=|\s+)([a-z0-9-]{16,128})/iu)?.[1];
|
|
57
|
+
if (token) {
|
|
58
|
+
return token;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return null;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const extractAntigravityProjectServiceUrl = (targets: AntigravityDevToolsTarget[]): string | null => {
|
|
66
|
+
for (const target of targets) {
|
|
67
|
+
if (target.type !== 'page' || !target.url) {
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
const url = new URL(target.url);
|
|
73
|
+
if (url.protocol === 'https:' && url.hostname === '127.0.0.1' && url.port) {
|
|
74
|
+
return url.origin;
|
|
75
|
+
}
|
|
76
|
+
} catch {}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return null;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const getAntigravityDevToolsPortPaths = (): string[] => {
|
|
83
|
+
if (process.platform === 'darwin') {
|
|
84
|
+
return [path.join(os.homedir(), 'Library', 'Application Support', 'Antigravity', 'DevToolsActivePort')];
|
|
85
|
+
}
|
|
86
|
+
if (process.platform === 'win32' && process.env.APPDATA) {
|
|
87
|
+
return [path.join(process.env.APPDATA, 'Antigravity', 'DevToolsActivePort')];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return [
|
|
91
|
+
path.join(
|
|
92
|
+
process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), '.config'),
|
|
93
|
+
'Antigravity',
|
|
94
|
+
'DevToolsActivePort',
|
|
95
|
+
),
|
|
96
|
+
];
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const readDevToolsPort = async (): Promise<number | null> => {
|
|
100
|
+
for (const filePath of getAntigravityDevToolsPortPaths()) {
|
|
101
|
+
try {
|
|
102
|
+
const port = Number.parseInt((await Bun.file(filePath).text()).split(/\r?\n/u)[0] ?? '', 10);
|
|
103
|
+
if (Number.isInteger(port) && port > 0 && port <= 65_535) {
|
|
104
|
+
return port;
|
|
105
|
+
}
|
|
106
|
+
} catch {}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return null;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const readProcessCommands = async (): Promise<string> => {
|
|
113
|
+
if (process.platform === 'win32') {
|
|
114
|
+
return '';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
const processList = Bun.spawn(['ps', '-axo', 'command='], {
|
|
119
|
+
stderr: 'ignore',
|
|
120
|
+
stdout: 'pipe',
|
|
121
|
+
});
|
|
122
|
+
const output = await new Response(processList.stdout).text();
|
|
123
|
+
return (await processList.exited) === 0 ? output : '';
|
|
124
|
+
} catch {
|
|
125
|
+
return '';
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const getRunningAntigravityProjectConnection = async (): Promise<AntigravityProjectConnection | null> => {
|
|
130
|
+
const [devToolsPort, processCommands] = await Promise.all([readDevToolsPort(), readProcessCommands()]);
|
|
131
|
+
const csrfToken = extractAntigravityCsrfToken(processCommands);
|
|
132
|
+
if (!devToolsPort || !csrfToken) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
try {
|
|
137
|
+
const response = await fetch(`http://127.0.0.1:${devToolsPort}/json/list`, {
|
|
138
|
+
signal: AbortSignal.timeout(1_000),
|
|
139
|
+
});
|
|
140
|
+
if (!response.ok) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const targets = (await response.json()) as AntigravityDevToolsTarget[];
|
|
145
|
+
const baseUrl = extractAntigravityProjectServiceUrl(targets);
|
|
146
|
+
return baseUrl ? { baseUrl, csrfToken } : null;
|
|
147
|
+
} catch {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export const resolveAntigravityProjectNames = async (
|
|
153
|
+
projectIds: string[],
|
|
154
|
+
options: AntigravityProjectResolverOptions = {},
|
|
155
|
+
): Promise<Map<string, string>> => {
|
|
156
|
+
const ids = [...new Set(projectIds)].filter((id) => SAFE_PROJECT_ID_PATTERN.test(id));
|
|
157
|
+
if (ids.length === 0) {
|
|
158
|
+
return new Map();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const connection = await (options.getConnection ?? getRunningAntigravityProjectConnection)();
|
|
162
|
+
if (!connection) {
|
|
163
|
+
return new Map();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const request: AntigravityProjectRequest = options.request ?? ((url, init) => fetch(url, init));
|
|
167
|
+
const projects = await mapWithConcurrency(ids, ANTIGRAVITY_PROJECT_READ_CONCURRENCY, async (projectId) => {
|
|
168
|
+
try {
|
|
169
|
+
const response = await request(
|
|
170
|
+
`${connection.baseUrl}/exa.language_server_pb.LanguageServerService/ReadProject`,
|
|
171
|
+
{
|
|
172
|
+
body: encodeGrpcWebJson({ id: projectId }).buffer as ArrayBuffer,
|
|
173
|
+
headers: {
|
|
174
|
+
'content-type': 'application/grpc-web+json',
|
|
175
|
+
'x-codeium-csrf-token': connection.csrfToken,
|
|
176
|
+
'x-grpc-web': '1',
|
|
177
|
+
},
|
|
178
|
+
method: 'POST',
|
|
179
|
+
signal: AbortSignal.timeout(1_500),
|
|
180
|
+
tls: { rejectUnauthorized: false },
|
|
181
|
+
},
|
|
182
|
+
);
|
|
183
|
+
if (!response.ok || response.headers.get('grpc-status') === '16') {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const decoded = decodeAntigravityGrpcWebJson(new Uint8Array(await response.arrayBuffer())) as {
|
|
188
|
+
project?: { id?: unknown; name?: unknown };
|
|
189
|
+
};
|
|
190
|
+
const id = decoded.project?.id;
|
|
191
|
+
const name = decoded.project?.name;
|
|
192
|
+
return id === projectId && typeof name === 'string' && name.trim()
|
|
193
|
+
? ([projectId, name.trim()] as const)
|
|
194
|
+
: null;
|
|
195
|
+
} catch {
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
return new Map(projects.filter((project): project is readonly [string, string] => project !== null));
|
|
201
|
+
};
|