@myrialabs/clopen 0.0.8 → 0.1.1

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 (49) hide show
  1. package/backend/index.ts +9 -0
  2. package/backend/lib/chat/stream-manager.ts +130 -10
  3. package/backend/lib/database/queries/message-queries.ts +47 -0
  4. package/backend/lib/engine/adapters/claude/stream.ts +65 -1
  5. package/backend/lib/engine/adapters/opencode/message-converter.ts +35 -77
  6. package/backend/lib/engine/types.ts +6 -0
  7. package/backend/lib/files/file-operations.ts +2 -2
  8. package/backend/lib/files/file-reading.ts +2 -2
  9. package/backend/lib/files/path-browsing.ts +2 -2
  10. package/backend/lib/terminal/pty-session-manager.ts +1 -1
  11. package/backend/lib/terminal/shell-utils.ts +4 -4
  12. package/backend/ws/chat/background.ts +3 -0
  13. package/backend/ws/chat/stream.ts +43 -1
  14. package/bin/clopen.ts +10 -0
  15. package/bun.lock +259 -381
  16. package/frontend/lib/components/chat/ChatInterface.svelte +8 -1
  17. package/frontend/lib/components/chat/formatters/MessageFormatter.svelte +20 -0
  18. package/frontend/lib/components/chat/formatters/TextMessage.svelte +3 -15
  19. package/frontend/lib/components/chat/formatters/Tools.svelte +15 -8
  20. package/frontend/lib/components/chat/input/ChatInput.svelte +70 -21
  21. package/frontend/lib/components/chat/input/components/LoadingIndicator.svelte +23 -11
  22. package/frontend/lib/components/chat/input/composables/use-chat-actions.svelte.ts +1 -1
  23. package/frontend/lib/components/chat/message/ChatMessage.svelte +13 -1
  24. package/frontend/lib/components/chat/message/ChatMessages.svelte +2 -2
  25. package/frontend/lib/components/chat/message/DateSeparator.svelte +1 -1
  26. package/frontend/lib/components/chat/message/MessageBubble.svelte +2 -2
  27. package/frontend/lib/components/chat/message/MessageHeader.svelte +14 -12
  28. package/frontend/lib/components/chat/tools/AgentTool.svelte +95 -0
  29. package/frontend/lib/components/chat/tools/AskUserQuestionTool.svelte +396 -0
  30. package/frontend/lib/components/chat/tools/BashTool.svelte +9 -4
  31. package/frontend/lib/components/chat/tools/EnterPlanModeTool.svelte +24 -0
  32. package/frontend/lib/components/chat/tools/ExitPlanModeTool.svelte +4 -7
  33. package/frontend/lib/components/chat/tools/{KillShellTool.svelte → TaskStopTool.svelte} +6 -6
  34. package/frontend/lib/components/chat/tools/index.ts +5 -2
  35. package/frontend/lib/components/checkpoint/TimelineModal.svelte +7 -2
  36. package/frontend/lib/components/history/HistoryModal.svelte +13 -5
  37. package/frontend/lib/components/workspace/DesktopNavigator.svelte +2 -1
  38. package/frontend/lib/components/workspace/MobileNavigator.svelte +2 -1
  39. package/frontend/lib/services/chat/chat.service.ts +146 -12
  40. package/frontend/lib/stores/core/app.svelte.ts +77 -0
  41. package/frontend/lib/utils/chat/message-grouper.ts +94 -12
  42. package/frontend/lib/utils/chat/message-processor.ts +37 -4
  43. package/frontend/lib/utils/chat/tool-handler.ts +96 -5
  44. package/package.json +4 -4
  45. package/shared/constants/engines.ts +1 -1
  46. package/shared/types/database/schema.ts +1 -0
  47. package/shared/types/messaging/index.ts +15 -13
  48. package/shared/types/messaging/tool.ts +185 -361
  49. package/shared/utils/message-formatter.ts +1 -0
@@ -7,31 +7,44 @@ import type {
7
7
  ToolGroup,
8
8
  BackgroundBashData
9
9
  } from './message-grouper';
10
+ import type { SDKMessageFormatter } from '$shared/types/database/schema';
11
+ import type { SubAgentActivity } from '$shared/types/messaging';
10
12
 
11
- // Extended ToolUse with embedded result
13
+ // Extended ToolUse with embedded result and metadata
12
14
  export interface ToolUseWithResult {
13
15
  type: 'tool_use';
14
16
  id: string;
15
17
  name: string;
16
18
  input: any;
17
19
  $result?: any;
20
+ $subMessages?: SubAgentActivity[];
21
+ metadata?: Record<string, unknown>;
18
22
  }
19
23
 
20
24
  // Process a tool message with embedded results
21
25
  export function processToolMessage(
22
26
  message: ProcessedMessage,
23
27
  toolUseMap: Map<string, ToolGroup>,
24
- backgroundBashMap: Map<string, BackgroundBashData>
28
+ backgroundBashMap: Map<string, BackgroundBashData>,
29
+ subAgentMap: Map<string, SDKMessageFormatter[]>
25
30
  ): ProcessedMessage {
26
31
  const messageAny = message as any;
27
32
  const content = messageAny.message?.content ?
28
33
  (Array.isArray(messageAny.message.content) ? messageAny.message.content : [messageAny.message.content]) : [];
29
34
 
35
+ // Check if parent message is marked as interrupted
36
+ const isInterrupted = !!(messageAny.metadata?.interrupted);
37
+
30
38
  // Create modified content with embedded tool_result in tool_use objects
31
39
  const modifiedContent = content
32
40
  .map((item: any): any => {
33
41
  if (typeof item === 'object' && item && 'type' in item && item.type === 'tool_use') {
34
- return processToolUse(item, toolUseMap, backgroundBashMap);
42
+ const processed = processToolUse(item, toolUseMap, backgroundBashMap, subAgentMap);
43
+ // Propagate message-level interrupted flag to ALL tool_use blocks
44
+ if (processed && isInterrupted) {
45
+ return { ...processed, metadata: { ...processed.metadata, interrupted: true } };
46
+ }
47
+ return processed;
35
48
  }
36
49
  return item;
37
50
  })
@@ -51,7 +64,8 @@ export function processToolMessage(
51
64
  function processToolUse(
52
65
  item: any,
53
66
  toolUseMap: Map<string, ToolGroup>,
54
- backgroundBashMap: Map<string, BackgroundBashData>
67
+ backgroundBashMap: Map<string, BackgroundBashData>,
68
+ subAgentMap: Map<string, SDKMessageFormatter[]>
55
69
  ): ToolUseWithResult | null {
56
70
  // Hide certain tools completely
57
71
  if (shouldHideTool(item.name)) {
@@ -66,6 +80,11 @@ function processToolUse(
66
80
  return handleBackgroundBash(item, toolUseMap, backgroundBashMap);
67
81
  }
68
82
 
83
+ // Special handling for Agent tool — embed sub-agent activities
84
+ if (item.name === 'Agent' && item.id && subAgentMap.has(item.id)) {
85
+ return handleAgentTool(item, toolUseMap, subAgentMap);
86
+ }
87
+
69
88
  // Regular tool handling
70
89
  if (item.id && item.name && shouldEmbedResult(item.name) && toolUseMap.has(item.id)) {
71
90
  return handleRegularTool(item, toolUseMap);
@@ -74,6 +93,78 @@ function processToolUse(
74
93
  return item;
75
94
  }
76
95
 
96
+ // Handle Agent tool — process sub-agent messages into activities
97
+ function handleAgentTool(
98
+ item: any,
99
+ toolUseMap: Map<string, ToolGroup>,
100
+ subAgentMap: Map<string, SDKMessageFormatter[]>
101
+ ): ToolUseWithResult {
102
+ const subMessages = subAgentMap.get(item.id) || [];
103
+ const activities = processSubAgentMessages(subMessages);
104
+
105
+ // Also embed the $result if available
106
+ let result: any = undefined;
107
+ if (item.id && toolUseMap.has(item.id)) {
108
+ const group = toolUseMap.get(item.id);
109
+ if (group?.toolResultMessage) {
110
+ const resultMessage = group.toolResultMessage as any;
111
+ const resultContent = resultMessage.message ?
112
+ (Array.isArray(resultMessage.message.content) ? resultMessage.message.content : [resultMessage.message.content]) : [];
113
+ result = findToolResult(resultContent, item.id);
114
+ }
115
+ }
116
+
117
+ return {
118
+ ...item,
119
+ ...(result ? { $result: result } : {}),
120
+ ...(activities.length > 0 ? { $subMessages: activities } : {})
121
+ } as ToolUseWithResult;
122
+ }
123
+
124
+ // Process sub-agent messages into a flat activity list
125
+ function processSubAgentMessages(messages: SDKMessageFormatter[]): SubAgentActivity[] {
126
+ const activities: SubAgentActivity[] = [];
127
+ const toolResultMap = new Map<string, any>();
128
+
129
+ // First pass: collect all tool_results from user messages
130
+ for (const msg of messages) {
131
+ if (msg.type === 'user' && 'message' in msg && msg.message?.content) {
132
+ const content = Array.isArray(msg.message.content) ? msg.message.content : [msg.message.content];
133
+ for (const item of content) {
134
+ if (typeof item === 'object' && item && item.type === 'tool_result' && item.tool_use_id) {
135
+ toolResultMap.set(item.tool_use_id, item);
136
+ }
137
+ }
138
+ }
139
+ }
140
+
141
+ // Second pass: build activity list from assistant messages
142
+ for (const msg of messages) {
143
+ if (msg.type === 'assistant' && 'message' in msg && msg.message?.content) {
144
+ const content = Array.isArray(msg.message.content) ? msg.message.content : [msg.message.content];
145
+ for (const item of content) {
146
+ if (typeof item === 'object' && item) {
147
+ if (item.type === 'tool_use') {
148
+ activities.push({
149
+ type: 'tool_use',
150
+ toolName: item.name,
151
+ toolInput: item.input,
152
+ toolResult: toolResultMap.get(item.id) || undefined
153
+ });
154
+ } else if (item.type === 'text' && item.text?.trim()) {
155
+ activities.push({
156
+ type: 'text',
157
+ text: item.text
158
+ });
159
+ }
160
+ }
161
+ }
162
+ }
163
+ }
164
+
165
+ return activities;
166
+ }
167
+
77
168
  // Handle background bash commands
78
169
  function handleBackgroundBash(
79
170
  item: any,
@@ -158,4 +249,4 @@ function findToolResult(
158
249
  'tool_use_id' in resultItem &&
159
250
  resultItem.tool_use_id === toolUseId
160
251
  );
161
- }
252
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@myrialabs/clopen",
3
- "version": "0.0.8",
3
+ "version": "0.1.1",
4
4
  "description": "All-in-one web workspace for Claude Code & OpenCode — chat, terminal, git, browser preview, checkpoints, and real-time collaboration",
5
5
  "author": "Myria Labs",
6
6
  "license": "MIT",
@@ -74,14 +74,14 @@
74
74
  "vite": "^7.0.4"
75
75
  },
76
76
  "dependencies": {
77
- "@anthropic-ai/claude-agent-sdk": "^0.2.7",
78
- "@anthropic-ai/sdk": "^0.62.0",
77
+ "@anthropic-ai/claude-agent-sdk": "^0.2.63",
78
+ "@anthropic-ai/sdk": "^0.78.0",
79
79
  "@elysiajs/cors": "^1.4.0",
80
80
  "@iconify-json/lucide": "^1.2.57",
81
81
  "@iconify-json/material-icon-theme": "^1.2.16",
82
82
  "@modelcontextprotocol/sdk": "^1.26.0",
83
83
  "@monaco-editor/loader": "^1.5.0",
84
- "@opencode-ai/sdk": "^1.2.4",
84
+ "@opencode-ai/sdk": "^1.2.15",
85
85
  "@tailwindcss/typography": "^0.5.16",
86
86
  "@types/marked": "^5.0.2",
87
87
  "@types/node": "^24.0.14",
@@ -52,7 +52,7 @@ export const CLAUDE_CODE_MODELS: EngineModel[] = [
52
52
  id: 'claude-code:sonnet',
53
53
  engine: 'claude-code',
54
54
  modelId: 'sonnet',
55
- name: 'Sonnet 4.5',
55
+ name: 'Sonnet 4.6',
56
56
  provider: 'anthropic',
57
57
  description: 'High-performance model with excellent coding capabilities and extended thinking',
58
58
  capabilities: ['Reasoning', 'Attachments'],
@@ -69,6 +69,7 @@ export type SDKMessageFormatter = EngineSDKMessage & {
69
69
  parent_message_id?: string | null; // Git-like parent pointer
70
70
  engine?: string; // Engine type that produced this message (claude-code, opencode)
71
71
  reasoning?: boolean; // Whether this message is a reasoning/thinking message
72
+ interrupted?: boolean; // Whether the stream ended before all tools got results
72
73
  };
73
74
  };
74
75
 
@@ -65,6 +65,7 @@ import type { SDKUserMessage as _SDKUserMessage } from '@anthropic-ai/claude-age
65
65
  export type EngineSDKMessage = SDKMessage & {
66
66
  metadata?: {
67
67
  reasoning?: boolean;
68
+ interrupted?: boolean;
68
69
  };
69
70
  };
70
71
 
@@ -113,7 +114,7 @@ export type {
113
114
  ExitPlanModeToolInput,
114
115
  GlobToolInput,
115
116
  GrepToolInput,
116
- KillShellToolInput,
117
+ TaskStopToolInput,
117
118
  ListMcpResourcesToolInput,
118
119
  NotebookEditToolInput,
119
120
  ReadMcpResourceToolInput,
@@ -123,30 +124,31 @@ export type {
123
124
  WebFetchToolInput,
124
125
  WebSearchToolInput,
125
126
  WriteToolInput,
127
+ AskUserQuestionToolInput,
128
+ ConfigToolInput,
129
+ EnterWorktreeToolInput,
130
+ AgentToolInput,
131
+ EnterPlanModeToolInput,
132
+ SubAgentActivity,
126
133
  ToolInput,
127
134
 
128
- // Tool output types
135
+ // Tool output types (from SDK)
129
136
  TaskOutput,
137
+ AskUserQuestionOutput,
130
138
  BashOutput,
131
- BashOutputToolOutput,
139
+ ConfigOutput,
140
+ EnterWorktreeOutput,
132
141
  EditOutput,
133
- TextFileOutput,
134
- ImageFileOutput,
135
- PDFFileOutput,
136
- NotebookFileOutput,
142
+ ExitPlanModeOutput,
137
143
  ReadOutput,
144
+ WriteOutput,
138
145
  GlobOutput,
139
146
  GrepOutput,
140
- GrepContentOutput,
141
- GrepFilesOutput,
142
- GrepCountOutput,
143
147
  WebFetchOutput,
144
148
  WebSearchOutput,
145
- WriteOutput,
146
149
  NotebookEditOutput,
147
150
  TodoWriteOutput,
148
- ExitPlanModeOutput,
149
- KillShellOutput,
151
+ TaskStopOutput,
150
152
  ListMcpResourcesOutput,
151
153
  ReadMcpResourceOutput,
152
154
  ToolOutput,