@comergehq/studio 0.1.26 → 0.1.28
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/dist/index.d.mts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1576 -601
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1292 -317
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
- package/src/components/chat/AgentProgressCard.tsx +82 -0
- package/src/components/chat/BundleProgressCard.tsx +75 -0
- package/src/components/chat/ChatMessageBubble.tsx +48 -4
- package/src/components/chat/ChatMessageList.tsx +56 -36
- package/src/components/comments/useAppComments.ts +12 -0
- package/src/data/agent-progress/repository.ts +179 -0
- package/src/data/agent-progress/types.ts +67 -0
- package/src/studio/ComergeStudio.tsx +23 -2
- package/src/studio/analytics/client.ts +103 -0
- package/src/studio/analytics/events.ts +98 -0
- package/src/studio/analytics/track.ts +237 -0
- package/src/studio/bootstrap/StudioBootstrap.tsx +8 -2
- package/src/studio/bootstrap/useStudioBootstrap.ts +18 -2
- package/src/studio/hooks/useAgentRunProgress.ts +357 -0
- package/src/studio/hooks/useAppStats.ts +14 -2
- package/src/studio/hooks/useBundleManager.ts +43 -5
- package/src/studio/hooks/useMergeRequests.ts +63 -14
- package/src/studio/hooks/useStudioActions.ts +34 -1
- package/src/studio/ui/ChatPanel.tsx +13 -2
- package/src/studio/ui/PreviewPanel.tsx +10 -0
- package/src/studio/ui/RuntimeRenderer.tsx +6 -1
- package/src/studio/ui/StudioOverlay.tsx +3 -0
- package/src/studio/ui/preview-panel/usePreviewPanelData.ts +1 -0
|
@@ -4,6 +4,7 @@ import type { App } from '../../data/apps/types';
|
|
|
4
4
|
import { appsRepository } from '../../data/apps/repository';
|
|
5
5
|
import { agentRepository } from '../../data/agent/repository';
|
|
6
6
|
import type { AttachmentMeta } from '../../data/attachment/types';
|
|
7
|
+
import { trackEditApp, trackRemixApp } from '../analytics/track';
|
|
7
8
|
|
|
8
9
|
function sleep(ms: number): Promise<void> {
|
|
9
10
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -104,14 +105,22 @@ export function useStudioActions({
|
|
|
104
105
|
|
|
105
106
|
setSending(true);
|
|
106
107
|
setError(null);
|
|
108
|
+
let forkSucceeded = false;
|
|
107
109
|
try {
|
|
108
110
|
let targetApp = app;
|
|
111
|
+
const sourceAppId = app.id;
|
|
109
112
|
|
|
110
113
|
if (shouldForkOnEdit) {
|
|
111
114
|
setForking(true);
|
|
112
|
-
const sourceAppId = app.id;
|
|
113
115
|
const forked = await appsRepository.fork(app.id, {});
|
|
114
116
|
targetApp = forked;
|
|
117
|
+
await trackRemixApp({
|
|
118
|
+
appId: forked.id,
|
|
119
|
+
sourceAppId,
|
|
120
|
+
threadId: forked.threadId ?? undefined,
|
|
121
|
+
success: true,
|
|
122
|
+
});
|
|
123
|
+
forkSucceeded = true;
|
|
115
124
|
// For fork+edit, keep rendering the original app until the edit completes on the fork.
|
|
116
125
|
onForkedApp?.(forked.id, { keepRenderingAppId: sourceAppId });
|
|
117
126
|
}
|
|
@@ -143,9 +152,33 @@ export function useStudioActions({
|
|
|
143
152
|
queueItemId: editResult.queueItemId ?? null,
|
|
144
153
|
queuePosition: editResult.queuePosition ?? null,
|
|
145
154
|
});
|
|
155
|
+
await trackEditApp({
|
|
156
|
+
appId: targetApp.id,
|
|
157
|
+
threadId,
|
|
158
|
+
promptLength: prompt.trim().length,
|
|
159
|
+
success: true,
|
|
160
|
+
});
|
|
146
161
|
} catch (e) {
|
|
147
162
|
const err = e instanceof Error ? e : new Error(String(e));
|
|
148
163
|
setError(err);
|
|
164
|
+
if (shouldForkOnEdit && !forkSucceeded && app?.id) {
|
|
165
|
+
await trackRemixApp({
|
|
166
|
+
appId: app.id,
|
|
167
|
+
sourceAppId: app.id,
|
|
168
|
+
threadId: app.threadId ?? undefined,
|
|
169
|
+
success: false,
|
|
170
|
+
error: err,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
if (app?.id && app.threadId) {
|
|
174
|
+
await trackEditApp({
|
|
175
|
+
appId: app.id,
|
|
176
|
+
threadId: app.threadId,
|
|
177
|
+
promptLength: prompt.trim().length,
|
|
178
|
+
success: false,
|
|
179
|
+
error: err,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
149
182
|
throw err;
|
|
150
183
|
} finally {
|
|
151
184
|
setForking(false);
|
|
@@ -12,6 +12,10 @@ import { Text } from '../../components/primitives/Text';
|
|
|
12
12
|
import type { ChatMessage } from '../../components/models/types';
|
|
13
13
|
import type { EditQueueItem } from '../../data/apps/edit-queue/types';
|
|
14
14
|
import { ChatQueue } from '../../components/chat/ChatQueue';
|
|
15
|
+
import { AgentProgressCard } from '../../components/chat/AgentProgressCard';
|
|
16
|
+
import { BundleProgressCard } from '../../components/chat/BundleProgressCard';
|
|
17
|
+
import type { AgentRunProgressView } from '../hooks/useAgentRunProgress';
|
|
18
|
+
import { useTheme } from '../../theme';
|
|
15
19
|
|
|
16
20
|
export type ChatPanelProps = {
|
|
17
21
|
title?: string;
|
|
@@ -34,6 +38,7 @@ export type ChatPanelProps = {
|
|
|
34
38
|
isRetryingMessage?: (messageId: string) => boolean;
|
|
35
39
|
queueItems?: EditQueueItem[];
|
|
36
40
|
onRemoveQueueItem?: (id: string) => void;
|
|
41
|
+
progress?: AgentRunProgressView | null;
|
|
37
42
|
};
|
|
38
43
|
|
|
39
44
|
export function ChatPanel({
|
|
@@ -57,7 +62,9 @@ export function ChatPanel({
|
|
|
57
62
|
isRetryingMessage,
|
|
58
63
|
queueItems = [],
|
|
59
64
|
onRemoveQueueItem,
|
|
65
|
+
progress = null,
|
|
60
66
|
}: ChatPanelProps) {
|
|
67
|
+
const theme = useTheme();
|
|
61
68
|
const listRef = React.useRef<ChatMessageListRef | null>(null);
|
|
62
69
|
const [nearBottom, setNearBottom] = React.useState(true);
|
|
63
70
|
|
|
@@ -131,8 +138,12 @@ export function ChatPanel({
|
|
|
131
138
|
);
|
|
132
139
|
}
|
|
133
140
|
|
|
134
|
-
const
|
|
135
|
-
|
|
141
|
+
const bundleProgress = progress?.bundle ?? null;
|
|
142
|
+
const queueTop = progress || queueItems.length > 0 ? (
|
|
143
|
+
<View style={{ gap: theme.spacing.sm }}>
|
|
144
|
+
{progress ? (bundleProgress ? <BundleProgressCard progress={bundleProgress} /> : <AgentProgressCard progress={progress} />) : null}
|
|
145
|
+
{queueItems.length > 0 ? <ChatQueue items={queueItems} onRemove={onRemoveQueueItem} /> : null}
|
|
146
|
+
</View>
|
|
136
147
|
) : null;
|
|
137
148
|
|
|
138
149
|
return (
|
|
@@ -12,6 +12,7 @@ import { PreviewMetaSection } from './preview-panel/PreviewMetaSection';
|
|
|
12
12
|
import { PreviewCustomizeSection } from './preview-panel/PreviewCustomizeSection';
|
|
13
13
|
import { PreviewCollaborateSection } from './preview-panel/PreviewCollaborateSection';
|
|
14
14
|
import { usePreviewPanelData } from './preview-panel/usePreviewPanelData';
|
|
15
|
+
import { trackShareApp } from '../analytics/track';
|
|
15
16
|
|
|
16
17
|
export type PreviewPanelProps = {
|
|
17
18
|
app: App | null;
|
|
@@ -84,8 +85,17 @@ export function PreviewPanel({
|
|
|
84
85
|
url: shareUrl,
|
|
85
86
|
};
|
|
86
87
|
await Share.share(payload);
|
|
88
|
+
await trackShareApp({
|
|
89
|
+
appId: app.id,
|
|
90
|
+
success: true,
|
|
91
|
+
});
|
|
87
92
|
} catch (error) {
|
|
88
93
|
log.warn('PreviewPanel share failed', error);
|
|
94
|
+
await trackShareApp({
|
|
95
|
+
appId: app.id,
|
|
96
|
+
success: false,
|
|
97
|
+
error,
|
|
98
|
+
});
|
|
89
99
|
}
|
|
90
100
|
}, [app]);
|
|
91
101
|
|
|
@@ -8,6 +8,10 @@ import { Text } from '../../components/primitives/Text';
|
|
|
8
8
|
export type RuntimeRendererProps = {
|
|
9
9
|
appKey: string;
|
|
10
10
|
bundlePath: string | null;
|
|
11
|
+
/**
|
|
12
|
+
* Loading text shown while runtime cannot render a bundle yet.
|
|
13
|
+
*/
|
|
14
|
+
preparingText?: string;
|
|
11
15
|
/**
|
|
12
16
|
* When true, show the "Preparing app…" UI even if a previous bundle is available.
|
|
13
17
|
* Used to avoid briefly rendering an outdated bundle during post-edit base refresh.
|
|
@@ -28,6 +32,7 @@ export type RuntimeRendererProps = {
|
|
|
28
32
|
export function RuntimeRenderer({
|
|
29
33
|
appKey,
|
|
30
34
|
bundlePath,
|
|
35
|
+
preparingText,
|
|
31
36
|
forcePreparing,
|
|
32
37
|
renderToken,
|
|
33
38
|
style,
|
|
@@ -48,7 +53,7 @@ export function RuntimeRenderer({
|
|
|
48
53
|
|
|
49
54
|
return (
|
|
50
55
|
<View style={[{ flex: 1, justifyContent: 'center', alignItems: 'center', padding: 24 }, style]}>
|
|
51
|
-
<Text variant="bodyMuted">Preparing app
|
|
56
|
+
<Text variant="bodyMuted">{preparingText ?? 'Preparing app…'}</Text>
|
|
52
57
|
</View>
|
|
53
58
|
);
|
|
54
59
|
}
|
|
@@ -64,6 +64,7 @@ export type StudioOverlayProps = {
|
|
|
64
64
|
onSendChat: (text: string, attachments?: string[]) => void | Promise<void>;
|
|
65
65
|
chatQueueItems?: import('../../data/apps/edit-queue/types').EditQueueItem[];
|
|
66
66
|
onRemoveQueueItem?: (id: string) => void;
|
|
67
|
+
chatProgress?: import('../hooks/useAgentRunProgress').AgentRunProgressView | null;
|
|
67
68
|
|
|
68
69
|
// Navigation callbacks
|
|
69
70
|
onNavigateHome?: () => void;
|
|
@@ -105,6 +106,7 @@ export function StudioOverlay({
|
|
|
105
106
|
onSendChat,
|
|
106
107
|
chatQueueItems,
|
|
107
108
|
onRemoveQueueItem,
|
|
109
|
+
chatProgress,
|
|
108
110
|
onNavigateHome,
|
|
109
111
|
showBubble,
|
|
110
112
|
studioControlOptions,
|
|
@@ -287,6 +289,7 @@ export function StudioOverlay({
|
|
|
287
289
|
isRetryingMessage={optimistic.isRetrying}
|
|
288
290
|
queueItems={queueItemsForChat}
|
|
289
291
|
onRemoveQueueItem={onRemoveQueueItem}
|
|
292
|
+
progress={chatProgress}
|
|
290
293
|
/>
|
|
291
294
|
}
|
|
292
295
|
/>
|
|
@@ -104,6 +104,7 @@ export function usePreviewPanelData(params: {
|
|
|
104
104
|
initialComments: commentCountOverride ?? insights.comments,
|
|
105
105
|
initialIsLiked: Boolean(app?.isLiked),
|
|
106
106
|
onOpenComments,
|
|
107
|
+
interactionSource: 'preview_panel',
|
|
107
108
|
});
|
|
108
109
|
|
|
109
110
|
const canSubmitMergeRequest = React.useMemo(() => {
|