@myrialabs/clopen 0.1.7 → 0.1.8
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/lib/git/git-service.ts +1 -0
- package/bun.lock +34 -12
- package/frontend/lib/components/common/MonacoEditor.svelte +6 -6
- package/frontend/lib/components/common/xterm/XTerm.svelte +27 -108
- package/frontend/lib/components/common/xterm/terminal-config.ts +2 -2
- package/frontend/lib/components/common/xterm/types.ts +1 -0
- package/frontend/lib/components/common/xterm/xterm-service.ts +69 -20
- package/frontend/lib/components/files/FileTree.svelte +4 -6
- package/frontend/lib/components/files/FileViewer.svelte +45 -101
- package/frontend/lib/components/git/CommitForm.svelte +1 -1
- package/frontend/lib/components/git/GitLog.svelte +117 -91
- package/frontend/lib/components/settings/engines/AIEnginesSettings.svelte +3 -3
- package/frontend/lib/components/workspace/PanelHeader.svelte +639 -623
- package/frontend/lib/components/workspace/panels/GitPanel.svelte +34 -92
- package/frontend/lib/stores/ui/workspace.svelte.ts +14 -14
- package/package.json +8 -6
|
@@ -67,9 +67,6 @@
|
|
|
67
67
|
let newTagName = $state('');
|
|
68
68
|
let newTagMessage = $state('');
|
|
69
69
|
|
|
70
|
-
// More menu state (for Stash/Tags)
|
|
71
|
-
let showMoreMenu = $state(false);
|
|
72
|
-
|
|
73
70
|
// Tab system (like Files panel)
|
|
74
71
|
interface DiffTab {
|
|
75
72
|
id: string;
|
|
@@ -1053,12 +1050,21 @@
|
|
|
1053
1050
|
gitStatus.staged.length + allChanges.length + gitStatus.conflicted.length
|
|
1054
1051
|
);
|
|
1055
1052
|
|
|
1053
|
+
// View tabs config for tab bar
|
|
1054
|
+
const viewTabs = $derived([
|
|
1055
|
+
{ id: 'changes' as const, label: 'Changes', icon: 'lucide:file-pen' as IconName, badge: totalChanges > 0 ? totalChanges : null },
|
|
1056
|
+
{ id: 'log' as const, label: 'History', icon: 'lucide:history' as IconName, badge: null },
|
|
1057
|
+
{ id: 'stash' as const, label: 'Stash', icon: 'lucide:archive' as IconName, badge: stashEntries.length > 0 ? stashEntries.length : null },
|
|
1058
|
+
{ id: 'tags' as const, label: 'Tags', icon: 'lucide:tag' as IconName, badge: tags.length > 0 ? tags.length : null }
|
|
1059
|
+
]);
|
|
1060
|
+
|
|
1056
1061
|
// Exported panel actions for PanelHeader
|
|
1057
1062
|
export const panelActions = {
|
|
1058
1063
|
push: handlePush,
|
|
1059
1064
|
pull: handlePull,
|
|
1060
1065
|
fetch: handleFetch,
|
|
1061
1066
|
init: handleInit,
|
|
1067
|
+
openBranchManager: () => { showBranchManager = true; },
|
|
1062
1068
|
getBranchInfo: () => branchInfo,
|
|
1063
1069
|
getIsRepo: () => isRepo,
|
|
1064
1070
|
getIsFetching: () => isFetching,
|
|
@@ -1102,97 +1108,32 @@
|
|
|
1102
1108
|
{/if}
|
|
1103
1109
|
{/snippet}
|
|
1104
1110
|
|
|
1105
|
-
<!--
|
|
1106
|
-
{#snippet
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
type="button"
|
|
1111
|
-
class="flex items-center gap-1.5 px-2.5 py-1 text-xs font-medium rounded-md bg-slate-100 dark:bg-slate-800/60 text-slate-700 dark:text-slate-300 hover:bg-violet-500/10 hover:text-violet-600 transition-colors cursor-pointer border-none min-w-0"
|
|
1112
|
-
onclick={() => showBranchManager = true}
|
|
1113
|
-
title="Switch Branch"
|
|
1114
|
-
>
|
|
1115
|
-
<Icon name="lucide:git-branch" class="w-3.5 h-3.5 shrink-0" />
|
|
1116
|
-
<span class="truncate max-w-24">{branchInfo?.current || '...'}</span>
|
|
1117
|
-
</button>
|
|
1118
|
-
|
|
1119
|
-
<div class="flex-1"></div>
|
|
1120
|
-
|
|
1121
|
-
<!-- Primary tabs: Changes & History -->
|
|
1122
|
-
<button
|
|
1123
|
-
type="button"
|
|
1124
|
-
class="px-2 py-1 text-xs font-medium rounded-md transition-colors cursor-pointer border-none
|
|
1125
|
-
{activeView === 'changes'
|
|
1126
|
-
? 'bg-violet-500/10 text-violet-600'
|
|
1127
|
-
: 'bg-transparent text-slate-500 hover:text-slate-700 dark:hover:text-slate-300'}"
|
|
1128
|
-
onclick={() => { switchToView('changes'); showMoreMenu = false; }}
|
|
1129
|
-
>
|
|
1130
|
-
Changes{totalChanges > 0 ? ` (${totalChanges})` : ''}
|
|
1131
|
-
</button>
|
|
1132
|
-
<button
|
|
1133
|
-
type="button"
|
|
1134
|
-
class="px-2 py-1 text-xs font-medium rounded-md transition-colors cursor-pointer border-none
|
|
1135
|
-
{activeView === 'log'
|
|
1136
|
-
? 'bg-violet-500/10 text-violet-600'
|
|
1137
|
-
: 'bg-transparent text-slate-500 hover:text-slate-700 dark:hover:text-slate-300'}"
|
|
1138
|
-
onclick={() => { switchToView('log'); showMoreMenu = false; }}
|
|
1139
|
-
>
|
|
1140
|
-
History
|
|
1141
|
-
</button>
|
|
1142
|
-
|
|
1143
|
-
<!-- More menu (Stash, Tags) -->
|
|
1144
|
-
<div class="relative">
|
|
1111
|
+
<!-- View tabs snippet (always visible, even in single-column diff mode) -->
|
|
1112
|
+
{#snippet viewTabBar()}
|
|
1113
|
+
<div class="relative flex border-b border-slate-200 dark:border-slate-700">
|
|
1114
|
+
{#each viewTabs as tab (tab.id)}
|
|
1115
|
+
{@const isActive = activeView === tab.id}
|
|
1145
1116
|
<button
|
|
1146
1117
|
type="button"
|
|
1147
|
-
class="flex items-center justify-center
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
onclick={() => showMoreMenu = !showMoreMenu}
|
|
1152
|
-
title="More views"
|
|
1118
|
+
class="relative flex-1 flex items-center justify-center gap-1.5 px-3 py-2 text-xs font-medium transition-colors {isActive
|
|
1119
|
+
? 'text-violet-600 dark:text-violet-400'
|
|
1120
|
+
: 'text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-300'}"
|
|
1121
|
+
onclick={() => switchToView(tab.id)}
|
|
1153
1122
|
>
|
|
1154
|
-
|
|
1123
|
+
{tab.label}
|
|
1124
|
+
{#if tab.badge}
|
|
1125
|
+
<span class="min-w-4 h-4 px-1 rounded-full bg-violet-500/15 dark:bg-violet-500/25 text-3xs font-semibold flex items-center justify-center">{tab.badge}</span>
|
|
1126
|
+
{/if}
|
|
1127
|
+
{#if isActive}
|
|
1128
|
+
<span class="absolute bottom-0 inset-x-0 h-px bg-violet-600 dark:bg-violet-400"></span>
|
|
1129
|
+
{/if}
|
|
1155
1130
|
</button>
|
|
1156
|
-
|
|
1157
|
-
{#if showMoreMenu}
|
|
1158
|
-
<div
|
|
1159
|
-
class="fixed inset-0 z-40"
|
|
1160
|
-
onclick={() => showMoreMenu = false}
|
|
1161
|
-
></div>
|
|
1162
|
-
<div class="absolute right-0 top-full mt-1 z-50 bg-white dark:bg-slate-800 border border-slate-200 dark:border-slate-700 rounded-lg shadow-lg py-1 min-w-32">
|
|
1163
|
-
<button
|
|
1164
|
-
type="button"
|
|
1165
|
-
class="flex items-center gap-2 w-full px-3 py-1.5 text-xs font-medium text-left transition-colors cursor-pointer border-none
|
|
1166
|
-
{activeView === 'stash'
|
|
1167
|
-
? 'bg-violet-500/10 text-violet-600'
|
|
1168
|
-
: 'bg-transparent text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700'}"
|
|
1169
|
-
onclick={() => { switchToView('stash'); showMoreMenu = false; }}
|
|
1170
|
-
>
|
|
1171
|
-
<Icon name="lucide:archive" class="w-3.5 h-3.5" />
|
|
1172
|
-
Stash
|
|
1173
|
-
{#if stashEntries.length > 0}
|
|
1174
|
-
<span class="ml-auto text-3xs font-semibold text-slate-400">{stashEntries.length}</span>
|
|
1175
|
-
{/if}
|
|
1176
|
-
</button>
|
|
1177
|
-
<button
|
|
1178
|
-
type="button"
|
|
1179
|
-
class="flex items-center gap-2 w-full px-3 py-1.5 text-xs font-medium text-left transition-colors cursor-pointer border-none
|
|
1180
|
-
{activeView === 'tags'
|
|
1181
|
-
? 'bg-violet-500/10 text-violet-600'
|
|
1182
|
-
: 'bg-transparent text-slate-700 dark:text-slate-300 hover:bg-slate-100 dark:hover:bg-slate-700'}"
|
|
1183
|
-
onclick={() => { switchToView('tags'); showMoreMenu = false; }}
|
|
1184
|
-
>
|
|
1185
|
-
<Icon name="lucide:tag" class="w-3.5 h-3.5" />
|
|
1186
|
-
Tags
|
|
1187
|
-
{#if tags.length > 0}
|
|
1188
|
-
<span class="ml-auto text-3xs font-semibold text-slate-400">{tags.length}</span>
|
|
1189
|
-
{/if}
|
|
1190
|
-
</button>
|
|
1191
|
-
</div>
|
|
1192
|
-
{/if}
|
|
1193
|
-
</div>
|
|
1131
|
+
{/each}
|
|
1194
1132
|
</div>
|
|
1133
|
+
{/snippet}
|
|
1195
1134
|
|
|
1135
|
+
<!-- Changes list snippet -->
|
|
1136
|
+
{#snippet changesList()}
|
|
1196
1137
|
{#if activeView === 'changes'}
|
|
1197
1138
|
<!-- Commit form -->
|
|
1198
1139
|
<CommitForm
|
|
@@ -1253,7 +1194,7 @@
|
|
|
1253
1194
|
/>
|
|
1254
1195
|
{:else if activeView === 'stash'}
|
|
1255
1196
|
<!-- Stash View -->
|
|
1256
|
-
<div class="flex-1 overflow-y-auto">
|
|
1197
|
+
<div class="flex-1 overflow-y-auto pt-2">
|
|
1257
1198
|
<!-- Stash save button/form -->
|
|
1258
1199
|
<div class="px-2 pb-2">
|
|
1259
1200
|
{#if showStashSaveForm}
|
|
@@ -1337,7 +1278,7 @@
|
|
|
1337
1278
|
</div>
|
|
1338
1279
|
{:else if activeView === 'tags'}
|
|
1339
1280
|
<!-- Tags View -->
|
|
1340
|
-
<div class="flex-1 overflow-y-auto">
|
|
1281
|
+
<div class="flex-1 overflow-y-auto pt-2">
|
|
1341
1282
|
<!-- Create tag button/form -->
|
|
1342
1283
|
<div class="px-2 pb-2">
|
|
1343
1284
|
{#if showCreateTagForm}
|
|
@@ -1502,16 +1443,17 @@
|
|
|
1502
1443
|
<div class="flex-1 overflow-hidden">
|
|
1503
1444
|
<!-- Unified layout: always render both panels to preserve state (like Files panel) -->
|
|
1504
1445
|
<div class="h-full flex">
|
|
1505
|
-
<!-- Left panel: Changes list
|
|
1446
|
+
<!-- Left panel: Changes list -->
|
|
1506
1447
|
<div
|
|
1507
1448
|
class={isTwoColumnMode
|
|
1508
1449
|
? 'w-72 flex-shrink-0 h-full overflow-hidden border-r border-slate-200 dark:border-slate-700 flex flex-col'
|
|
1509
1450
|
: (viewMode === 'list' ? 'w-full h-full overflow-hidden flex flex-col' : 'hidden')}
|
|
1510
1451
|
>
|
|
1452
|
+
{@render viewTabBar()}
|
|
1511
1453
|
{@render changesList()}
|
|
1512
1454
|
</div>
|
|
1513
1455
|
|
|
1514
|
-
<!-- Right panel: Diff viewer
|
|
1456
|
+
<!-- Right panel: Diff viewer -->
|
|
1515
1457
|
<div
|
|
1516
1458
|
class={isTwoColumnMode
|
|
1517
1459
|
? 'flex-1 h-full overflow-hidden flex flex-col'
|
|
@@ -459,20 +459,20 @@ const defaultPanels: Record<PanelId, PanelConfig> = {
|
|
|
459
459
|
minimized: false,
|
|
460
460
|
order: 0
|
|
461
461
|
},
|
|
462
|
-
preview: {
|
|
463
|
-
id: 'preview',
|
|
464
|
-
title: 'Preview',
|
|
465
|
-
icon: 'lucide:globe',
|
|
466
|
-
visible: true,
|
|
467
|
-
minimized: false,
|
|
468
|
-
order: 1
|
|
469
|
-
},
|
|
470
462
|
files: {
|
|
471
463
|
id: 'files',
|
|
472
464
|
title: 'Files',
|
|
473
465
|
icon: 'lucide:folder',
|
|
474
466
|
visible: true,
|
|
475
467
|
minimized: false,
|
|
468
|
+
order: 1
|
|
469
|
+
},
|
|
470
|
+
git: {
|
|
471
|
+
id: 'git',
|
|
472
|
+
title: 'Source Control',
|
|
473
|
+
icon: 'lucide:git-branch',
|
|
474
|
+
visible: true,
|
|
475
|
+
minimized: false,
|
|
476
476
|
order: 2
|
|
477
477
|
},
|
|
478
478
|
terminal: {
|
|
@@ -483,10 +483,10 @@ const defaultPanels: Record<PanelId, PanelConfig> = {
|
|
|
483
483
|
minimized: false,
|
|
484
484
|
order: 3
|
|
485
485
|
},
|
|
486
|
-
|
|
487
|
-
id: '
|
|
488
|
-
title: '
|
|
489
|
-
icon: 'lucide:
|
|
486
|
+
preview: {
|
|
487
|
+
id: 'preview',
|
|
488
|
+
title: 'Preview',
|
|
489
|
+
icon: 'lucide:globe',
|
|
490
490
|
visible: true,
|
|
491
491
|
minimized: false,
|
|
492
492
|
order: 4
|
|
@@ -496,9 +496,9 @@ const defaultPanels: Record<PanelId, PanelConfig> = {
|
|
|
496
496
|
export const PANEL_OPTIONS: { id: PanelId; title: string; icon: IconName }[] = [
|
|
497
497
|
{ id: 'chat', title: 'AI Assistant', icon: 'lucide:bot' },
|
|
498
498
|
{ id: 'files', title: 'Files', icon: 'lucide:folder' },
|
|
499
|
-
{ id: '
|
|
499
|
+
{ id: 'git', title: 'Source Control', icon: 'lucide:git-branch' },
|
|
500
500
|
{ id: 'terminal', title: 'Terminal', icon: 'lucide:terminal' },
|
|
501
|
-
{ id: '
|
|
501
|
+
{ id: 'preview', title: 'Preview', icon: 'lucide:globe' }
|
|
502
502
|
];
|
|
503
503
|
|
|
504
504
|
// Default: Main + Stack layout
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@myrialabs/clopen",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
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",
|
|
@@ -62,7 +62,6 @@
|
|
|
62
62
|
"@types/bun": "^1.2.18",
|
|
63
63
|
"@types/node": "^24.0.14",
|
|
64
64
|
"@types/qrcode": "^1.5.6",
|
|
65
|
-
"@types/xterm": "^3.0.0",
|
|
66
65
|
"concurrently": "^9.2.1",
|
|
67
66
|
"eslint": "^9.31.0",
|
|
68
67
|
"eslint-plugin-svelte": "^3.10.1",
|
|
@@ -83,8 +82,12 @@
|
|
|
83
82
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
84
83
|
"@monaco-editor/loader": "^1.5.0",
|
|
85
84
|
"@opencode-ai/sdk": "^1.2.15",
|
|
86
|
-
"@xterm/addon-
|
|
87
|
-
"@xterm/addon-
|
|
85
|
+
"@xterm/addon-clipboard": "^0.2.0",
|
|
86
|
+
"@xterm/addon-fit": "^0.11.0",
|
|
87
|
+
"@xterm/addon-ligatures": "^0.10.0",
|
|
88
|
+
"@xterm/addon-unicode11": "^0.9.0",
|
|
89
|
+
"@xterm/addon-web-links": "^0.12.0",
|
|
90
|
+
"@xterm/xterm": "^6.0.0",
|
|
88
91
|
"bun-pty": "^0.4.2",
|
|
89
92
|
"cloudflared": "^0.7.1",
|
|
90
93
|
"elysia": "^1.4.19",
|
|
@@ -95,8 +98,7 @@
|
|
|
95
98
|
"nanoid": "^5.1.6",
|
|
96
99
|
"puppeteer": "^24.33.0",
|
|
97
100
|
"puppeteer-cluster": "^0.25.0",
|
|
98
|
-
"qrcode": "^1.5.4"
|
|
99
|
-
"xterm": "^5.3.0"
|
|
101
|
+
"qrcode": "^1.5.4"
|
|
100
102
|
},
|
|
101
103
|
"trustedDependencies": [
|
|
102
104
|
"cloudflared",
|