@myrialabs/clopen 0.1.1 → 0.1.3
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/backend/index.ts +4 -1
- package/backend/lib/engine/adapters/opencode/message-converter.ts +53 -2
- package/backend/lib/engine/adapters/opencode/stream.ts +89 -5
- package/backend/lib/project/status-manager.ts +221 -181
- package/frontend/lib/components/chat/message/ChatMessages.svelte +16 -4
- package/frontend/lib/components/chat/tools/AgentTool.svelte +12 -11
- package/frontend/lib/components/chat/tools/BashOutputTool.svelte +3 -3
- package/frontend/lib/components/chat/tools/BashTool.svelte +4 -4
- package/frontend/lib/components/chat/tools/CustomMcpTool.svelte +3 -1
- package/frontend/lib/components/chat/tools/EditTool.svelte +6 -6
- package/frontend/lib/components/chat/tools/ExitPlanModeTool.svelte +1 -1
- package/frontend/lib/components/chat/tools/GlobTool.svelte +12 -12
- package/frontend/lib/components/chat/tools/GrepTool.svelte +5 -5
- package/frontend/lib/components/chat/tools/ListMcpResourcesTool.svelte +1 -1
- package/frontend/lib/components/chat/tools/NotebookEditTool.svelte +6 -6
- package/frontend/lib/components/chat/tools/ReadMcpResourceTool.svelte +2 -2
- package/frontend/lib/components/chat/tools/ReadTool.svelte +4 -4
- package/frontend/lib/components/chat/tools/TaskStopTool.svelte +1 -1
- package/frontend/lib/components/chat/tools/TaskTool.svelte +1 -1
- package/frontend/lib/components/chat/tools/TodoWriteTool.svelte +4 -4
- package/frontend/lib/components/chat/tools/WebSearchTool.svelte +1 -1
- package/frontend/lib/components/chat/tools/WriteTool.svelte +3 -3
- package/frontend/lib/components/chat/tools/components/CodeBlock.svelte +3 -3
- package/frontend/lib/components/chat/tools/components/DiffBlock.svelte +2 -2
- package/frontend/lib/components/chat/tools/components/FileHeader.svelte +1 -1
- package/frontend/lib/components/chat/tools/components/InfoLine.svelte +2 -2
- package/frontend/lib/components/chat/tools/components/StatsBadges.svelte +1 -1
- package/frontend/lib/components/chat/tools/components/TerminalCommand.svelte +5 -5
- package/frontend/lib/components/common/Button.svelte +1 -1
- package/frontend/lib/components/common/Card.svelte +3 -3
- package/frontend/lib/components/common/Input.svelte +3 -3
- package/frontend/lib/components/common/LoadingSpinner.svelte +1 -1
- package/frontend/lib/components/common/Select.svelte +6 -6
- package/frontend/lib/components/common/Textarea.svelte +3 -3
- package/frontend/lib/components/files/FileViewer.svelte +1 -1
- package/frontend/lib/components/git/ChangesSection.svelte +2 -4
- package/frontend/lib/components/preview/browser/BrowserPreview.svelte +9 -29
- package/frontend/lib/components/preview/browser/components/Container.svelte +17 -0
- package/frontend/lib/components/preview/browser/components/VirtualCursor.svelte +2 -2
- package/frontend/lib/components/settings/appearance/AppearanceSettings.svelte +0 -6
- package/frontend/lib/components/settings/appearance/LayoutPresetSettings.svelte +15 -15
- package/frontend/lib/components/settings/appearance/LayoutPreview.svelte +2 -2
- package/frontend/lib/components/workspace/DesktopNavigator.svelte +380 -383
- package/frontend/lib/components/workspace/MobileNavigator.svelte +391 -395
- package/frontend/lib/components/workspace/PanelHeader.svelte +115 -4
- package/frontend/lib/components/workspace/ViewMenu.svelte +9 -25
- package/frontend/lib/components/workspace/layout/split-pane/Layout.svelte +29 -4
- package/frontend/lib/services/notification/global-stream-monitor.ts +77 -86
- package/frontend/lib/services/project/status.service.ts +160 -159
- package/frontend/lib/stores/ui/workspace.svelte.ts +326 -283
- package/package.json +1 -1
|
@@ -1,159 +1,160 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Project Status Service
|
|
3
|
-
* Tracks active streams and user presence for projects via WebSocket
|
|
4
|
-
* Fully realtime - no cache, no polling
|
|
5
|
-
*
|
|
6
|
-
* Single event: `projects:presence-updated` contains full state
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { getOrCreateAnonymousUser, type AnonymousUser } from '$shared/utils/anonymous-user';
|
|
10
|
-
import ws from '$frontend/lib/utils/ws';
|
|
11
|
-
import { debug } from '$shared/utils/logger';
|
|
12
|
-
|
|
13
|
-
export interface ProjectStatus {
|
|
14
|
-
projectId: string;
|
|
15
|
-
hasActiveStreams: boolean;
|
|
16
|
-
activeStreamCount: number;
|
|
17
|
-
activeUsers: { userId: string; userName: string }[];
|
|
18
|
-
streams: {
|
|
19
|
-
streamId: string;
|
|
20
|
-
chatSessionId: string;
|
|
21
|
-
status: string;
|
|
22
|
-
startedAt: string;
|
|
23
|
-
messagesCount: number;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
private
|
|
32
|
-
private
|
|
33
|
-
private
|
|
34
|
-
private
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
*
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
*
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
this.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
ws.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
this.unsubscribe
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
this.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Project Status Service
|
|
3
|
+
* Tracks active streams and user presence for projects via WebSocket
|
|
4
|
+
* Fully realtime - no cache, no polling
|
|
5
|
+
*
|
|
6
|
+
* Single event: `projects:presence-updated` contains full state
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { getOrCreateAnonymousUser, type AnonymousUser } from '$shared/utils/anonymous-user';
|
|
10
|
+
import ws from '$frontend/lib/utils/ws';
|
|
11
|
+
import { debug } from '$shared/utils/logger';
|
|
12
|
+
|
|
13
|
+
export interface ProjectStatus {
|
|
14
|
+
projectId: string;
|
|
15
|
+
hasActiveStreams: boolean;
|
|
16
|
+
activeStreamCount: number;
|
|
17
|
+
activeUsers: { userId: string; userName: string }[];
|
|
18
|
+
streams: {
|
|
19
|
+
streamId: string;
|
|
20
|
+
chatSessionId: string;
|
|
21
|
+
status: string;
|
|
22
|
+
startedAt: string;
|
|
23
|
+
messagesCount: number;
|
|
24
|
+
isWaitingInput?: boolean;
|
|
25
|
+
}[];
|
|
26
|
+
/** Per-chat-session user presence: { chatSessionId → users[] } */
|
|
27
|
+
chatSessionUsers?: Record<string, { userId: string; userName: string }[]>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
class ProjectStatusService {
|
|
31
|
+
private currentUser: AnonymousUser | null = null;
|
|
32
|
+
private currentProjectId: string | null = null;
|
|
33
|
+
private initialized = false;
|
|
34
|
+
private statusUpdateCallbacks: Set<(statuses: ProjectStatus[]) => void> = new Set();
|
|
35
|
+
private unsubscribe: (() => void) | null = null;
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Initialize the service - sets up WS listener
|
|
39
|
+
* Called automatically on first use
|
|
40
|
+
*/
|
|
41
|
+
async initialize(): Promise<void> {
|
|
42
|
+
if (typeof window === 'undefined' || this.initialized) return;
|
|
43
|
+
|
|
44
|
+
this.currentUser = await getOrCreateAnonymousUser();
|
|
45
|
+
debug.log('project', 'Initialized with user:', this.currentUser?.name);
|
|
46
|
+
|
|
47
|
+
this.unsubscribe = ws.on('projects:presence-updated', (data) => {
|
|
48
|
+
try {
|
|
49
|
+
if (data.type === 'presence-updated' && data.data) {
|
|
50
|
+
const statuses = Array.isArray(data.data) ? data.data : [data.data];
|
|
51
|
+
this.statusUpdateCallbacks.forEach(callback => {
|
|
52
|
+
try {
|
|
53
|
+
callback(statuses);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
debug.error('project', 'Error in status callback:', error);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
debug.error('project', 'Error handling presence update:', error);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
this.initialized = true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private async ensureInitialized(): Promise<void> {
|
|
68
|
+
if (!this.initialized) {
|
|
69
|
+
await this.initialize();
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Subscribe to real-time presence updates
|
|
75
|
+
* Auto-initializes WS listener if not done yet
|
|
76
|
+
*/
|
|
77
|
+
onStatusUpdate(callback: (statuses: ProjectStatus[]) => void): () => void {
|
|
78
|
+
this.statusUpdateCallbacks.add(callback);
|
|
79
|
+
this.ensureInitialized();
|
|
80
|
+
|
|
81
|
+
return () => {
|
|
82
|
+
this.statusUpdateCallbacks.delete(callback);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Join a project - start presence tracking
|
|
88
|
+
*/
|
|
89
|
+
async startTracking(projectId: string): Promise<void> {
|
|
90
|
+
if (typeof window === 'undefined') return;
|
|
91
|
+
|
|
92
|
+
await this.ensureInitialized();
|
|
93
|
+
|
|
94
|
+
if (this.currentProjectId && this.currentProjectId !== projectId) {
|
|
95
|
+
await this.stopTracking();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
this.currentProjectId = projectId;
|
|
99
|
+
|
|
100
|
+
if (this.currentUser) {
|
|
101
|
+
ws.emit('projects:join', {
|
|
102
|
+
userName: this.currentUser.name
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
document.addEventListener('visibilitychange', this.handleVisibilityChange);
|
|
107
|
+
window.addEventListener('beforeunload', this.handleBeforeUnload);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Leave a project - stop presence tracking
|
|
112
|
+
*/
|
|
113
|
+
async stopTracking(): Promise<void> {
|
|
114
|
+
if (this.currentProjectId && this.currentUser) {
|
|
115
|
+
// Send projectId explicitly because ws.setProject() may have already changed context
|
|
116
|
+
ws.emit('projects:leave', {
|
|
117
|
+
projectId: this.currentProjectId
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (typeof window !== 'undefined') {
|
|
122
|
+
document.removeEventListener('visibilitychange', this.handleVisibilityChange);
|
|
123
|
+
window.removeEventListener('beforeunload', this.handleBeforeUnload);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
this.currentProjectId = null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
cleanup(): void {
|
|
130
|
+
if (this.unsubscribe) {
|
|
131
|
+
this.unsubscribe();
|
|
132
|
+
this.unsubscribe = null;
|
|
133
|
+
}
|
|
134
|
+
this.statusUpdateCallbacks.clear();
|
|
135
|
+
this.initialized = false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private handleVisibilityChange = () => {
|
|
139
|
+
if (!document.hidden && this.currentProjectId && this.currentUser) {
|
|
140
|
+
ws.http('projects:update-presence', {
|
|
141
|
+
userName: this.currentUser.name,
|
|
142
|
+
action: 'update'
|
|
143
|
+
}).catch(() => {});
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
private handleBeforeUnload = () => {
|
|
148
|
+
if (this.currentProjectId && this.currentUser) {
|
|
149
|
+
ws.emit('projects:leave', {
|
|
150
|
+
projectId: this.currentProjectId
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
getCurrentUser(): AnonymousUser | null {
|
|
156
|
+
return this.currentUser;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export const projectStatusService = new ProjectStatusService();
|