@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
package/bun.lock
CHANGED
|
@@ -13,8 +13,12 @@
|
|
|
13
13
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
14
14
|
"@monaco-editor/loader": "^1.5.0",
|
|
15
15
|
"@opencode-ai/sdk": "^1.2.15",
|
|
16
|
-
"@xterm/addon-
|
|
17
|
-
"@xterm/addon-
|
|
16
|
+
"@xterm/addon-clipboard": "^0.2.0",
|
|
17
|
+
"@xterm/addon-fit": "^0.11.0",
|
|
18
|
+
"@xterm/addon-ligatures": "^0.10.0",
|
|
19
|
+
"@xterm/addon-unicode11": "^0.9.0",
|
|
20
|
+
"@xterm/addon-web-links": "^0.12.0",
|
|
21
|
+
"@xterm/xterm": "^6.0.0",
|
|
18
22
|
"bun-pty": "^0.4.2",
|
|
19
23
|
"cloudflared": "^0.7.1",
|
|
20
24
|
"elysia": "^1.4.19",
|
|
@@ -26,7 +30,6 @@
|
|
|
26
30
|
"puppeteer": "^24.33.0",
|
|
27
31
|
"puppeteer-cluster": "^0.25.0",
|
|
28
32
|
"qrcode": "^1.5.4",
|
|
29
|
-
"xterm": "^5.3.0",
|
|
30
33
|
},
|
|
31
34
|
"devDependencies": {
|
|
32
35
|
"@eslint/js": "^9.31.0",
|
|
@@ -35,7 +38,6 @@
|
|
|
35
38
|
"@types/bun": "^1.2.18",
|
|
36
39
|
"@types/node": "^24.0.14",
|
|
37
40
|
"@types/qrcode": "^1.5.6",
|
|
38
|
-
"@types/xterm": "^3.0.0",
|
|
39
41
|
"concurrently": "^9.2.1",
|
|
40
42
|
"eslint": "^9.31.0",
|
|
41
43
|
"eslint-plugin-svelte": "^3.10.1",
|
|
@@ -310,8 +312,6 @@
|
|
|
310
312
|
|
|
311
313
|
"@types/trusted-types": ["@types/trusted-types@2.0.7", "", {}, "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="],
|
|
312
314
|
|
|
313
|
-
"@types/xterm": ["@types/xterm@3.0.0", "", { "dependencies": { "xterm": "*" } }, "sha512-+VaAJQmE7E1d1ebkIh/Zdc2mbXBVwxZGGSgqwzDPpk/HKo0mNT+iX5ZrnswztHSV+CDV+bURl7Yg7PWF7IZfXQ=="],
|
|
314
|
-
|
|
315
315
|
"@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="],
|
|
316
316
|
|
|
317
317
|
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.56.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.56.1", "@typescript-eslint/type-utils": "8.56.1", "@typescript-eslint/utils": "8.56.1", "@typescript-eslint/visitor-keys": "8.56.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.56.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Jz9ZztpB37dNC+HU2HI28Bs9QXpzCz+y/twHOwhyrIRdbuVDxSytJNDl6z/aAKlaRIwC7y8wJdkBv7FxYGgi0A=="],
|
|
@@ -334,11 +334,17 @@
|
|
|
334
334
|
|
|
335
335
|
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.56.1", "", { "dependencies": { "@typescript-eslint/types": "8.56.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw=="],
|
|
336
336
|
|
|
337
|
-
"@xterm/addon-
|
|
337
|
+
"@xterm/addon-clipboard": ["@xterm/addon-clipboard@0.2.0", "", { "dependencies": { "js-base64": "^3.7.5" } }, "sha512-Dl31BCtBhLaUEECUbEiVcCLvLBbaeGYdT7NofB8OJkGTD3MWgBsaLjXvfGAD4tQNHhm6mbKyYkR7XD8kiZsdNg=="],
|
|
338
|
+
|
|
339
|
+
"@xterm/addon-fit": ["@xterm/addon-fit@0.11.0", "", {}, "sha512-jYcgT6xtVYhnhgxh3QgYDnnNMYTcf8ElbxxFzX0IZo+vabQqSPAjC3c1wJrKB5E19VwQei89QCiZZP86DCPF7g=="],
|
|
340
|
+
|
|
341
|
+
"@xterm/addon-ligatures": ["@xterm/addon-ligatures@0.10.0", "", { "dependencies": { "font-finder": "^1.1.0", "font-ligatures": "^1.4.1" } }, "sha512-/Few8ZSHMib7sGjRJoc5l7bCtEB9XJfkNofvPpOcWADxKaUl8og8P172j67OoACSNJAXqeCLIuvj8WFCBkcTxg=="],
|
|
342
|
+
|
|
343
|
+
"@xterm/addon-unicode11": ["@xterm/addon-unicode11@0.9.0", "", {}, "sha512-FxDnYcyuXhNl+XSqGZL/t0U9eiNb/q3EWT5rYkQT/zuig8Gz/VagnQANKHdDWFM2lTMk9ly0EFQxxxtZUoRetw=="],
|
|
338
344
|
|
|
339
|
-
"@xterm/addon-web-links": ["@xterm/addon-web-links@0.
|
|
345
|
+
"@xterm/addon-web-links": ["@xterm/addon-web-links@0.12.0", "", {}, "sha512-4Smom3RPyVp7ZMYOYDoC/9eGJJJqYhnPLGGqJ6wOBfB8VxPViJNSKdgRYb8NpaM6YSelEKbA2SStD7lGyqaobw=="],
|
|
340
346
|
|
|
341
|
-
"@xterm/xterm": ["@xterm/xterm@
|
|
347
|
+
"@xterm/xterm": ["@xterm/xterm@6.0.0", "", {}, "sha512-TQwDdQGtwwDt+2cgKDLn0IRaSxYu1tSUjgKarSDkUM0ZNiSRXFpjxEsvc/Zgc5kq5omJ+V0a8/kIM2WD3sMOYg=="],
|
|
342
348
|
|
|
343
349
|
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
|
|
344
350
|
|
|
@@ -562,6 +568,10 @@
|
|
|
562
568
|
|
|
563
569
|
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
|
|
564
570
|
|
|
571
|
+
"font-finder": ["font-finder@1.1.0", "", { "dependencies": { "get-system-fonts": "^2.0.0", "promise-stream-reader": "^1.0.1" } }, "sha512-wpCL2uIbi6GurJbU7ZlQ3nGd61Ho+dSU6U83/xJT5UPFfN35EeCW/rOtS+5k+IuEZu2SYmHzDIPL9eA5tSYRAw=="],
|
|
572
|
+
|
|
573
|
+
"font-ligatures": ["font-ligatures@1.4.1", "", { "dependencies": { "font-finder": "^1.0.3", "lru-cache": "^6.0.0", "opentype.js": "^0.8.0" } }, "sha512-7W6zlfyhvCqShZ5ReUWqmSd9vBaUudW0Hxis+tqUjtHhsPU+L3Grf8mcZAtCiXHTzorhwdRTId2WeH/88gdFkw=="],
|
|
574
|
+
|
|
565
575
|
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
|
|
566
576
|
|
|
567
577
|
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
|
|
@@ -578,6 +588,8 @@
|
|
|
578
588
|
|
|
579
589
|
"get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="],
|
|
580
590
|
|
|
591
|
+
"get-system-fonts": ["get-system-fonts@2.0.2", "", {}, "sha512-zzlgaYnHMIEgHRrfC7x0Qp0Ylhw/sHpM6MHXeVBTYIsvGf5GpbnClB+Q6rAPdn+0gd2oZZIo6Tj3EaWrt4VhDQ=="],
|
|
592
|
+
|
|
581
593
|
"get-uri": ["get-uri@6.0.5", "", { "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4" } }, "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg=="],
|
|
582
594
|
|
|
583
595
|
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
|
|
@@ -638,6 +650,8 @@
|
|
|
638
650
|
|
|
639
651
|
"jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="],
|
|
640
652
|
|
|
653
|
+
"js-base64": ["js-base64@3.7.8", "", {}, "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow=="],
|
|
654
|
+
|
|
641
655
|
"js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="],
|
|
642
656
|
|
|
643
657
|
"js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="],
|
|
@@ -694,7 +708,7 @@
|
|
|
694
708
|
|
|
695
709
|
"lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="],
|
|
696
710
|
|
|
697
|
-
"lru-cache": ["lru-cache@
|
|
711
|
+
"lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="],
|
|
698
712
|
|
|
699
713
|
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
|
700
714
|
|
|
@@ -742,6 +756,8 @@
|
|
|
742
756
|
|
|
743
757
|
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
|
|
744
758
|
|
|
759
|
+
"opentype.js": ["opentype.js@0.8.0", "", { "dependencies": { "tiny-inflate": "^1.0.2" }, "bin": { "ot": "./bin/ot" } }, "sha512-FQHR4oGP+a0m/f6yHoRpBOIbn/5ZWxKd4D/djHVJu8+KpBTYrJda0b7mLcgDEMWXE9xBCJm+qb0yv6FcvPjukg=="],
|
|
760
|
+
|
|
745
761
|
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
|
746
762
|
|
|
747
763
|
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
|
|
@@ -790,6 +806,8 @@
|
|
|
790
806
|
|
|
791
807
|
"progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="],
|
|
792
808
|
|
|
809
|
+
"promise-stream-reader": ["promise-stream-reader@1.0.1", "", {}, "sha512-Tnxit5trUjBAqqZCGWwjyxhmgMN4hGrtpW3Oc/tRI4bpm/O2+ej72BB08l6JBnGQgVDGCLvHFGjGgQS6vzhwXg=="],
|
|
810
|
+
|
|
793
811
|
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
|
|
794
812
|
|
|
795
813
|
"proxy-agent": ["proxy-agent@6.5.0", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "http-proxy-agent": "^7.0.1", "https-proxy-agent": "^7.0.6", "lru-cache": "^7.14.1", "pac-proxy-agent": "^7.1.0", "proxy-from-env": "^1.1.0", "socks-proxy-agent": "^8.0.5" } }, "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A=="],
|
|
@@ -904,6 +922,8 @@
|
|
|
904
922
|
|
|
905
923
|
"text-extensions": ["text-extensions@3.1.0", "", {}, "sha512-anOjtXr8OT5w4vc/2mP4AYTCE0GWc/21icGmaHtBHnI7pN7o01a/oqG9m06/rGzoAsDm/WNzggBpqptuCmRlZQ=="],
|
|
906
924
|
|
|
925
|
+
"tiny-inflate": ["tiny-inflate@1.0.3", "", {}, "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="],
|
|
926
|
+
|
|
907
927
|
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
|
908
928
|
|
|
909
929
|
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
|
@@ -958,10 +978,10 @@
|
|
|
958
978
|
|
|
959
979
|
"ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="],
|
|
960
980
|
|
|
961
|
-
"xterm": ["xterm@5.3.0", "", {}, "sha512-8QqjlekLUFTrU6x7xck1MsPzPA571K5zNqWm0M0oroYEWVOptZ0+ubQSkQ3uxIEhcIHRujJy6emDWX4A7qyFzg=="],
|
|
962
|
-
|
|
963
981
|
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
|
|
964
982
|
|
|
983
|
+
"yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
|
984
|
+
|
|
965
985
|
"yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="],
|
|
966
986
|
|
|
967
987
|
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
|
|
@@ -1012,6 +1032,8 @@
|
|
|
1012
1032
|
|
|
1013
1033
|
"postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
|
1014
1034
|
|
|
1035
|
+
"proxy-agent/lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="],
|
|
1036
|
+
|
|
1015
1037
|
"qrcode/yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="],
|
|
1016
1038
|
|
|
1017
1039
|
"@modelcontextprotocol/sdk/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
|
@@ -58,9 +58,9 @@
|
|
|
58
58
|
indentGuide: '#21262d',
|
|
59
59
|
indentGuideActive: '#30363d',
|
|
60
60
|
ruler: '#21262d',
|
|
61
|
-
scrollbar: '#
|
|
62
|
-
scrollbarHover: '#
|
|
63
|
-
scrollbarActive: '#
|
|
61
|
+
scrollbar: '#6e768140',
|
|
62
|
+
scrollbarHover: '#6e768180',
|
|
63
|
+
scrollbarActive: '#8b949e'
|
|
64
64
|
},
|
|
65
65
|
tokens: {
|
|
66
66
|
comment: '6A9955',
|
|
@@ -87,9 +87,9 @@
|
|
|
87
87
|
indentGuide: '#e3e3e3',
|
|
88
88
|
indentGuideActive: '#d3d3d3',
|
|
89
89
|
ruler: '#e3e3e3',
|
|
90
|
-
scrollbar: '#
|
|
91
|
-
scrollbarHover: '#
|
|
92
|
-
scrollbarActive: '#
|
|
90
|
+
scrollbar: '#92929240',
|
|
91
|
+
scrollbarHover: '#92929280',
|
|
92
|
+
scrollbarActive: '#555555'
|
|
93
93
|
},
|
|
94
94
|
tokens: {
|
|
95
95
|
comment: '008000',
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
import { settings } from '$frontend/lib/stores/features/settings.svelte';
|
|
15
15
|
|
|
16
16
|
// Import CSS directly - Vite will handle it properly
|
|
17
|
-
import 'xterm/css/xterm.css';
|
|
17
|
+
import '@xterm/xterm/css/xterm.css';
|
|
18
18
|
|
|
19
19
|
// Props
|
|
20
20
|
const {
|
|
@@ -183,127 +183,39 @@
|
|
|
183
183
|
};
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
// Handle right-click copy/paste
|
|
187
|
-
function
|
|
186
|
+
// Handle right-click copy/paste via clipboard addon
|
|
187
|
+
function setupClipboardHandling() {
|
|
188
188
|
if (!terminalContainer || !xtermService.terminal) return;
|
|
189
189
|
|
|
190
|
-
const
|
|
191
|
-
event.preventDefault();
|
|
192
|
-
|
|
193
|
-
// Get selected text from xterm.js
|
|
190
|
+
const handleContextMenu = async (event: MouseEvent) => {
|
|
191
|
+
event.preventDefault();
|
|
192
|
+
|
|
194
193
|
const selectedText = xtermService.getSelectedText();
|
|
195
|
-
|
|
196
|
-
if (selectedText
|
|
194
|
+
|
|
195
|
+
if (selectedText?.trim()) {
|
|
197
196
|
// Copy selected text to clipboard
|
|
198
197
|
try {
|
|
199
198
|
await navigator.clipboard.writeText(selectedText);
|
|
200
|
-
|
|
201
|
-
// Clear selection after copy (like most terminals do)
|
|
202
199
|
xtermService.clearSelection();
|
|
203
|
-
|
|
204
|
-
// Show brief visual feedback
|
|
205
|
-
showCopyFeedback();
|
|
206
|
-
} catch (err) {
|
|
207
|
-
}
|
|
200
|
+
} catch { /* clipboard not available */ }
|
|
208
201
|
} else {
|
|
209
|
-
// No text selected - paste from clipboard
|
|
202
|
+
// No text selected - paste from clipboard
|
|
210
203
|
try {
|
|
211
|
-
const
|
|
212
|
-
if (
|
|
213
|
-
|
|
214
|
-
// Use terminal's built-in paste functionality
|
|
215
|
-
// This simulates typing each character through the input handler
|
|
216
|
-
if ((xtermService as any).inputHandler) {
|
|
217
|
-
// Process each character through the input handler
|
|
218
|
-
for (const char of clipboardText) {
|
|
219
|
-
// Skip newlines - let user decide when to execute
|
|
220
|
-
if (char !== '\n' && char !== '\r') {
|
|
221
|
-
(xtermService as any).inputHandler(char);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Show brief visual feedback
|
|
227
|
-
showPasteFeedback();
|
|
204
|
+
const text = await navigator.clipboard.readText();
|
|
205
|
+
if (text?.trim()) {
|
|
206
|
+
xtermService.pasteText(text);
|
|
228
207
|
}
|
|
229
|
-
} catch {
|
|
230
|
-
// paste not supported
|
|
231
|
-
}
|
|
208
|
+
} catch { /* clipboard not available */ }
|
|
232
209
|
}
|
|
233
210
|
};
|
|
234
211
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
212
|
+
terminalContainer.addEventListener('contextmenu', handleContextMenu);
|
|
213
|
+
|
|
238
214
|
return () => {
|
|
239
|
-
terminalContainer?.removeEventListener('contextmenu',
|
|
215
|
+
terminalContainer?.removeEventListener('contextmenu', handleContextMenu);
|
|
240
216
|
};
|
|
241
217
|
}
|
|
242
218
|
|
|
243
|
-
// Show brief visual feedback for copy action
|
|
244
|
-
function showCopyFeedback() {
|
|
245
|
-
if (!terminalContainer) return;
|
|
246
|
-
|
|
247
|
-
// Create temporary feedback element
|
|
248
|
-
const feedback = document.createElement('div');
|
|
249
|
-
feedback.textContent = 'Copied!';
|
|
250
|
-
feedback.style.cssText = `
|
|
251
|
-
position: absolute;
|
|
252
|
-
top: 10px;
|
|
253
|
-
right: 10px;
|
|
254
|
-
background: rgb(34 197 94 / 0.9);
|
|
255
|
-
color: white;
|
|
256
|
-
padding: 4px 8px;
|
|
257
|
-
border-radius: 4px;
|
|
258
|
-
font-size: 12px;
|
|
259
|
-
font-family: system-ui, sans-serif;
|
|
260
|
-
z-index: 1000;
|
|
261
|
-
pointer-events: none;
|
|
262
|
-
`;
|
|
263
|
-
|
|
264
|
-
terminalContainer.style.position = 'relative';
|
|
265
|
-
terminalContainer.appendChild(feedback);
|
|
266
|
-
|
|
267
|
-
// Remove feedback after 1 second
|
|
268
|
-
setTimeout(() => {
|
|
269
|
-
if (feedback.parentNode) {
|
|
270
|
-
feedback.parentNode.removeChild(feedback);
|
|
271
|
-
}
|
|
272
|
-
}, 1000);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// Show brief visual feedback for paste action
|
|
276
|
-
function showPasteFeedback() {
|
|
277
|
-
if (!terminalContainer) return;
|
|
278
|
-
|
|
279
|
-
// Create temporary feedback element
|
|
280
|
-
const feedback = document.createElement('div');
|
|
281
|
-
feedback.textContent = 'Pasted!';
|
|
282
|
-
feedback.style.cssText = `
|
|
283
|
-
position: absolute;
|
|
284
|
-
top: 10px;
|
|
285
|
-
right: 10px;
|
|
286
|
-
background: rgba(59, 130, 246, 0.9);
|
|
287
|
-
color: white;
|
|
288
|
-
padding: 4px 8px;
|
|
289
|
-
border-radius: 4px;
|
|
290
|
-
font-size: 12px;
|
|
291
|
-
font-family: system-ui, sans-serif;
|
|
292
|
-
z-index: 1000;
|
|
293
|
-
pointer-events: none;
|
|
294
|
-
`;
|
|
295
|
-
|
|
296
|
-
terminalContainer.style.position = 'relative';
|
|
297
|
-
terminalContainer.appendChild(feedback);
|
|
298
|
-
|
|
299
|
-
// Remove feedback after 1 second
|
|
300
|
-
setTimeout(() => {
|
|
301
|
-
if (feedback.parentNode) {
|
|
302
|
-
feedback.parentNode.removeChild(feedback);
|
|
303
|
-
}
|
|
304
|
-
}, 1000);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
219
|
// Handle theme changes
|
|
308
220
|
function setupThemeHandling() {
|
|
309
221
|
xtermService.updateTheme();
|
|
@@ -404,7 +316,9 @@
|
|
|
404
316
|
$effect(() => {
|
|
405
317
|
const size = settings.fontSize;
|
|
406
318
|
if (isInitialized) {
|
|
407
|
-
|
|
319
|
+
const fontSize = Math.round(size * 0.9);
|
|
320
|
+
const lineHeight = Math.round(size * 0.9);
|
|
321
|
+
xtermService.updateFontSize(fontSize, lineHeight, session?.id);
|
|
408
322
|
}
|
|
409
323
|
});
|
|
410
324
|
|
|
@@ -656,12 +570,12 @@
|
|
|
656
570
|
|
|
657
571
|
const cleanupResize = setupResizeHandling();
|
|
658
572
|
const cleanupTheme = setupThemeHandling();
|
|
659
|
-
const
|
|
573
|
+
const cleanupClipboard = setupClipboardHandling();
|
|
660
574
|
|
|
661
575
|
return () => {
|
|
662
576
|
cleanupResize();
|
|
663
577
|
cleanupTheme();
|
|
664
|
-
|
|
578
|
+
cleanupClipboard?.();
|
|
665
579
|
};
|
|
666
580
|
});
|
|
667
581
|
|
|
@@ -711,6 +625,11 @@
|
|
|
711
625
|
export function clearSelection() {
|
|
712
626
|
xtermService.clearSelection();
|
|
713
627
|
}
|
|
628
|
+
|
|
629
|
+
export function pasteText(text: string) {
|
|
630
|
+
xtermService.pasteText(text);
|
|
631
|
+
}
|
|
632
|
+
|
|
714
633
|
</script>
|
|
715
634
|
|
|
716
635
|
<!-- Pure xterm.js terminal container -->
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Centralized xterm.js configuration and utilities
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import type { ITerminalOptions } from 'xterm';
|
|
7
|
+
import type { ITerminalOptions } from '@xterm/xterm';
|
|
8
8
|
|
|
9
9
|
// Terminal theme configuration
|
|
10
10
|
export const terminalConfig: ITerminalOptions = {
|
|
@@ -40,7 +40,7 @@ export const terminalConfig: ITerminalOptions = {
|
|
|
40
40
|
convertEol: true,
|
|
41
41
|
scrollback: 1000,
|
|
42
42
|
tabStopWidth: 4,
|
|
43
|
-
allowProposedApi:
|
|
43
|
+
allowProposedApi: true,
|
|
44
44
|
altClickMovesCursor: true,
|
|
45
45
|
disableStdin: false, // ✅ ENABLED for interactive PTY mode - stdin forwards to backend
|
|
46
46
|
allowTransparency: false
|
|
@@ -6,9 +6,12 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import { browser } from '$frontend/lib/app-environment';
|
|
9
|
-
import type { Terminal } from 'xterm';
|
|
9
|
+
import type { Terminal } from '@xterm/xterm';
|
|
10
10
|
import type { FitAddon } from '@xterm/addon-fit';
|
|
11
11
|
import type { WebLinksAddon } from '@xterm/addon-web-links';
|
|
12
|
+
import type { ClipboardAddon } from '@xterm/addon-clipboard';
|
|
13
|
+
import type { Unicode11Addon } from '@xterm/addon-unicode11';
|
|
14
|
+
import type { LigaturesAddon } from '@xterm/addon-ligatures';
|
|
12
15
|
import type { TerminalLine } from '$shared/types/terminal';
|
|
13
16
|
import { terminalConfig } from './terminal-config';
|
|
14
17
|
import { debug } from '$shared/utils/logger';
|
|
@@ -18,12 +21,16 @@ export class XTermService {
|
|
|
18
21
|
public terminal: Terminal | null = null;
|
|
19
22
|
public fitAddon: FitAddon | null = null;
|
|
20
23
|
public webLinksAddon: WebLinksAddon | null = null;
|
|
24
|
+
public clipboardAddon: ClipboardAddon | null = null;
|
|
25
|
+
private unicode11Addon: Unicode11Addon | null = null;
|
|
26
|
+
private ligaturesAddon: LigaturesAddon | null = null;
|
|
21
27
|
public isInitialized = false;
|
|
22
28
|
public isReady = false;
|
|
23
29
|
|
|
24
30
|
private sessionId: string | null = null;
|
|
25
31
|
private resizeTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
26
32
|
private inputDisposable: any = null;
|
|
33
|
+
private lastSentDims: { cols: number; rows: number } | null = null;
|
|
27
34
|
|
|
28
35
|
constructor() {
|
|
29
36
|
// Service is stateless by design
|
|
@@ -49,27 +56,39 @@ export class XTermService {
|
|
|
49
56
|
this.terminal = null;
|
|
50
57
|
this.fitAddon = null;
|
|
51
58
|
this.webLinksAddon = null;
|
|
59
|
+
this.clipboardAddon = null;
|
|
60
|
+
this.unicode11Addon = null;
|
|
61
|
+
this.ligaturesAddon = null;
|
|
52
62
|
}
|
|
53
63
|
|
|
54
64
|
try {
|
|
55
65
|
debug.log('terminal', '🚀 Initializing XTerm...');
|
|
56
66
|
|
|
57
67
|
// Dynamic import xterm classes
|
|
58
|
-
const [{ Terminal }, { FitAddon }, { WebLinksAddon }] = await Promise.all([
|
|
59
|
-
import('xterm'),
|
|
68
|
+
const [{ Terminal }, { FitAddon }, { WebLinksAddon }, { ClipboardAddon }, { Unicode11Addon }] = await Promise.all([
|
|
69
|
+
import('@xterm/xterm'),
|
|
60
70
|
import('@xterm/addon-fit'),
|
|
61
|
-
import('@xterm/addon-web-links')
|
|
71
|
+
import('@xterm/addon-web-links'),
|
|
72
|
+
import('@xterm/addon-clipboard'),
|
|
73
|
+
import('@xterm/addon-unicode11')
|
|
62
74
|
]);
|
|
63
75
|
|
|
64
76
|
// Create terminal instance
|
|
65
77
|
this.terminal = new Terminal(terminalConfig);
|
|
66
78
|
|
|
67
|
-
// Create and load addons
|
|
79
|
+
// Create and load core addons
|
|
68
80
|
this.fitAddon = new FitAddon();
|
|
69
81
|
this.webLinksAddon = new WebLinksAddon();
|
|
82
|
+
this.clipboardAddon = new ClipboardAddon();
|
|
83
|
+
this.unicode11Addon = new Unicode11Addon();
|
|
70
84
|
|
|
71
85
|
this.terminal.loadAddon(this.fitAddon);
|
|
72
86
|
this.terminal.loadAddon(this.webLinksAddon);
|
|
87
|
+
this.terminal.loadAddon(this.clipboardAddon);
|
|
88
|
+
this.terminal.loadAddon(this.unicode11Addon);
|
|
89
|
+
|
|
90
|
+
// Enable Unicode 11 for better character width support
|
|
91
|
+
this.terminal.unicode.activeVersion = '11';
|
|
73
92
|
|
|
74
93
|
// Open terminal in container
|
|
75
94
|
this.terminal.open(container);
|
|
@@ -82,6 +101,16 @@ export class XTermService {
|
|
|
82
101
|
debug.log('terminal', '⚠️ Initial fit failed (container may have zero dimensions), will retry on resize');
|
|
83
102
|
}
|
|
84
103
|
|
|
104
|
+
// Try ligatures addon for font ligature rendering (non-critical)
|
|
105
|
+
try {
|
|
106
|
+
const { LigaturesAddon } = await import('@xterm/addon-ligatures');
|
|
107
|
+
this.ligaturesAddon = new LigaturesAddon();
|
|
108
|
+
this.terminal.loadAddon(this.ligaturesAddon);
|
|
109
|
+
debug.log('terminal', '🔤 Font ligatures enabled');
|
|
110
|
+
} catch {
|
|
111
|
+
debug.log('terminal', '⚠️ Ligatures addon not available');
|
|
112
|
+
}
|
|
113
|
+
|
|
85
114
|
this.isInitialized = true;
|
|
86
115
|
this.isReady = true;
|
|
87
116
|
|
|
@@ -94,6 +123,9 @@ export class XTermService {
|
|
|
94
123
|
}
|
|
95
124
|
this.fitAddon = null;
|
|
96
125
|
this.webLinksAddon = null;
|
|
126
|
+
this.clipboardAddon = null;
|
|
127
|
+
this.unicode11Addon = null;
|
|
128
|
+
this.ligaturesAddon = null;
|
|
97
129
|
debug.error('terminal', '❌ Failed to initialize XTerm:', error);
|
|
98
130
|
}
|
|
99
131
|
}
|
|
@@ -180,11 +212,12 @@ export class XTermService {
|
|
|
180
212
|
}
|
|
181
213
|
|
|
182
214
|
/**
|
|
183
|
-
* Update terminal font size and refit to container
|
|
215
|
+
* Update terminal font size, line height, and refit to container
|
|
184
216
|
*/
|
|
185
|
-
updateFontSize(size: number, sessionId?: string): void {
|
|
217
|
+
updateFontSize(size: number, lineHeight: number, sessionId?: string): void {
|
|
186
218
|
if (!this.terminal) return;
|
|
187
219
|
this.terminal.options.fontSize = size;
|
|
220
|
+
this.terminal.options.lineHeight = lineHeight / size;
|
|
188
221
|
this.fit(sessionId);
|
|
189
222
|
}
|
|
190
223
|
|
|
@@ -262,6 +295,12 @@ export class XTermService {
|
|
|
262
295
|
const dims = this.fitAddon.proposeDimensions();
|
|
263
296
|
|
|
264
297
|
if (dims && sessionId) {
|
|
298
|
+
// Skip if dimensions haven't changed
|
|
299
|
+
if (this.lastSentDims && this.lastSentDims.cols === dims.cols && this.lastSentDims.rows === dims.rows) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
this.lastSentDims = { cols: dims.cols, rows: dims.rows };
|
|
303
|
+
|
|
265
304
|
// Notify backend of new terminal size via WebSocket HTTP
|
|
266
305
|
debug.log('terminal', `🔧 Syncing terminal size: ${dims.cols}x${dims.rows}`);
|
|
267
306
|
ws.http('terminal:resize', {
|
|
@@ -293,20 +332,11 @@ export class XTermService {
|
|
|
293
332
|
scrollToBottomIfNearEnd(): void {
|
|
294
333
|
if (!this.terminal) return;
|
|
295
334
|
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
this.scrollToBottom();
|
|
299
|
-
return;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
const scrollTop = viewport._viewportElement.scrollTop;
|
|
303
|
-
const scrollHeight = viewport._viewportElement.scrollHeight;
|
|
304
|
-
const clientHeight = viewport._viewportElement.clientHeight;
|
|
335
|
+
const buffer = this.terminal.buffer.active;
|
|
336
|
+
const isNearBottom = buffer.viewportY >= buffer.baseY - 3;
|
|
305
337
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
if (scrollHeight - scrollTop - clientHeight < threshold) {
|
|
309
|
-
this.scrollToBottom();
|
|
338
|
+
if (isNearBottom) {
|
|
339
|
+
this.terminal.scrollToBottom();
|
|
310
340
|
}
|
|
311
341
|
}
|
|
312
342
|
|
|
@@ -361,6 +391,21 @@ export class XTermService {
|
|
|
361
391
|
};
|
|
362
392
|
}
|
|
363
393
|
|
|
394
|
+
/**
|
|
395
|
+
* Paste text by sending to PTY via WebSocket
|
|
396
|
+
*/
|
|
397
|
+
pasteText(text: string): void {
|
|
398
|
+
if (!this.sessionId || !text) return;
|
|
399
|
+
try {
|
|
400
|
+
ws.emit('terminal:input', {
|
|
401
|
+
sessionId: this.sessionId,
|
|
402
|
+
data: text
|
|
403
|
+
});
|
|
404
|
+
} catch (error) {
|
|
405
|
+
debug.error('terminal', '❌ Error pasting text:', error);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
364
409
|
/**
|
|
365
410
|
* Cleanup terminal resources
|
|
366
411
|
*/
|
|
@@ -382,6 +427,10 @@ export class XTermService {
|
|
|
382
427
|
|
|
383
428
|
this.fitAddon = null;
|
|
384
429
|
this.webLinksAddon = null;
|
|
430
|
+
this.clipboardAddon = null;
|
|
431
|
+
this.unicode11Addon = null;
|
|
432
|
+
this.ligaturesAddon = null;
|
|
433
|
+
this.lastSentDims = null;
|
|
385
434
|
this.isInitialized = false;
|
|
386
435
|
this.isReady = false;
|
|
387
436
|
}
|
|
@@ -420,9 +420,9 @@
|
|
|
420
420
|
|
|
421
421
|
<div class="relative flex flex-col h-full overflow-hidden">
|
|
422
422
|
<!-- Modern Header -->
|
|
423
|
-
<div class="px-5 py-
|
|
423
|
+
<div class="px-5 py-2.5 border-b border-slate-200 dark:border-slate-700">
|
|
424
424
|
<div class="flex items-start justify-between gap-2">
|
|
425
|
-
<div class="flex-1 min-w-0">
|
|
425
|
+
<div class="flex-1 min-w-0" title={projectState.currentProject?.path}>
|
|
426
426
|
<h3 class="text-sm font-bold text-slate-900 dark:text-slate-100">
|
|
427
427
|
{projectState.currentProject?.name}
|
|
428
428
|
</h3>
|
|
@@ -466,9 +466,8 @@
|
|
|
466
466
|
<div class="relative flex border-b border-slate-200 dark:border-slate-700">
|
|
467
467
|
<button
|
|
468
468
|
onclick={() => { searchVisible = false; }}
|
|
469
|
-
class="relative flex-1 flex items-center justify-center
|
|
469
|
+
class="relative flex-1 flex items-center justify-center px-3 py-2 text-xs font-medium transition-colors {!searchVisible ? 'text-violet-600 dark:text-violet-400' : 'text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-300'}"
|
|
470
470
|
>
|
|
471
|
-
<Icon name="lucide:folder" class="w-3.5 h-3.5" />
|
|
472
471
|
Explorer
|
|
473
472
|
{#if !searchVisible}
|
|
474
473
|
<span class="absolute bottom-0 inset-x-0 h-px bg-violet-600 dark:bg-violet-400"></span>
|
|
@@ -476,9 +475,8 @@
|
|
|
476
475
|
</button>
|
|
477
476
|
<button
|
|
478
477
|
onclick={switchToSearch}
|
|
479
|
-
class="relative flex-1 flex items-center justify-center
|
|
478
|
+
class="relative flex-1 flex items-center justify-center px-3 py-2 text-xs font-medium transition-colors {searchVisible ? 'text-violet-600 dark:text-violet-400' : 'text-slate-500 dark:text-slate-400 hover:text-slate-700 dark:hover:text-slate-300'}"
|
|
480
479
|
>
|
|
481
|
-
<Icon name="lucide:search" class="w-3.5 h-3.5" />
|
|
482
480
|
Search
|
|
483
481
|
{#if searchVisible}
|
|
484
482
|
<span class="absolute bottom-0 inset-x-0 h-px bg-violet-600 dark:bg-violet-400"></span>
|